lanxin 10 часов назад
Родитель
Сommit
aa2a1939de
99 измененных файлов с 2337 добавлено и 5915 удалено
  1. 3 0
      package.json
  2. 1 1
      public/index.html
  3. 26 27
      src/App.tsx
  4. BIN
      src/assets/img/eye.png
  5. BIN
      src/assets/img/eyex.png
  6. BIN
      src/assets/img/inputBg.png
  7. BIN
      src/assets/img/loginBac.png
  8. BIN
      src/assets/img/loginBtnBg.png
  9. BIN
      src/assets/img/logo.png
  10. BIN
      src/assets/img/logo2.png
  11. BIN
      src/assets/img/logo3.png
  12. 30 0
      src/components/DragTable/index.module.scss
  13. 198 0
      src/components/DragTable/index.tsx
  14. 7 0
      src/components/MyTable/index.module.scss
  15. 38 22
      src/components/MyTable/index.tsx
  16. 3 4
      src/components/UpXlsx.tsx
  17. 28 37
      src/components/ZupOne/index.tsx
  18. 0 94
      src/pages/A1manage/A1Import/index.module.scss
  19. 0 179
      src/pages/A1manage/A1Import/index.tsx
  20. 0 402
      src/pages/A1manage/A1add/index.tsx
  21. 0 225
      src/pages/A1manage/A1ying/A1Yadd.tsx
  22. 0 104
      src/pages/A1manage/A1ying/index.module.scss
  23. 0 176
      src/pages/A1manage/A1ying/index.tsx
  24. 0 19
      src/pages/A1manage/data.ts
  25. 0 271
      src/pages/A1manage/index.tsx
  26. 33 5
      src/pages/A1manage/A1add/index.module.scss
  27. 263 0
      src/pages/A1scene/A1add/index.tsx
  28. 213 0
      src/pages/A1scene/A1imgUp/index.module.scss
  29. 341 0
      src/pages/A1scene/A1imgUp/index.tsx
  30. 7 0
      src/pages/A1scene/data.ts
  31. 11 7
      src/pages/A1manage/index.module.scss
  32. 175 0
      src/pages/A1scene/index.tsx
  33. 0 202
      src/pages/A2classify/A2add.tsx
  34. 0 113
      src/pages/A2classify/A2add2.tsx
  35. 0 18
      src/pages/A2classify/data.ts
  36. 0 123
      src/pages/A2classify/index.module.scss
  37. 0 337
      src/pages/A2classify/index.tsx
  38. 37 9
      src/pages/A7notice/A7add/index.module.scss
  39. 255 0
      src/pages/A2line/A2add/index.tsx
  40. 7 0
      src/pages/A2line/data.ts
  41. 13 9
      src/pages/A5bookAudit/index.module.scss
  42. 147 0
      src/pages/A2line/index.tsx
  43. 0 163
      src/pages/A3recommend/A3add.tsx
  44. 0 7
      src/pages/A3recommend/data.ts
  45. 0 78
      src/pages/A3recommend/index.module.scss
  46. 0 181
      src/pages/A3recommend/index.tsx
  47. 0 76
      src/pages/A4iosUser/A4ip/index.module.scss
  48. 0 158
      src/pages/A4iosUser/A4ip/index.tsx
  49. 0 21
      src/pages/A4iosUser/data.ts
  50. 0 30
      src/pages/A4iosUser/index.module.scss
  51. 0 144
      src/pages/A4iosUser/index.tsx
  52. 0 125
      src/pages/A5bookAudit/A5look/index.module.scss
  53. 0 318
      src/pages/A5bookAudit/A5look/index.tsx
  54. 0 25
      src/pages/A5bookAudit/data.ts
  55. 0 161
      src/pages/A5bookAudit/index.tsx
  56. 0 108
      src/pages/A6remarkAudit/A6audit.tsx
  57. 0 79
      src/pages/A6remarkAudit/index.module.scss
  58. 0 121
      src/pages/A6remarkAudit/index.tsx
  59. 0 182
      src/pages/A7notice/A7add/index.tsx
  60. 0 63
      src/pages/A7notice/A7type/index.module.scss
  61. 0 171
      src/pages/A7notice/A7type/index.tsx
  62. 0 6
      src/pages/A7notice/data.ts
  63. 0 45
      src/pages/A7notice/index.module.scss
  64. 0 192
      src/pages/A7notice/index.tsx
  65. 7 37
      src/pages/Layout/data.ts
  66. 20 14
      src/pages/Layout/index.module.scss
  67. 18 14
      src/pages/Layout/index.tsx
  68. 29 25
      src/pages/Login/index.module.scss
  69. 94 93
      src/pages/Login/index.tsx
  70. 74 104
      src/pages/Z1user/index.tsx
  71. 0 76
      src/store/action/A1manage.ts
  72. 39 0
      src/store/action/A1scene.ts
  73. 17 15
      src/store/action/A2classify.ts
  74. 0 44
      src/store/action/A3recommend.ts
  75. 0 53
      src/store/action/A4iosUser.ts
  76. 0 40
      src/store/action/A5bookAudit.ts
  77. 0 39
      src/store/action/A6remarkAudit.ts
  78. 0 66
      src/store/action/A7notice.ts
  79. 0 0
      src/store/reducer/A1scene.ts
  80. 1 12
      src/store/reducer/A2classify.ts
  81. 0 25
      src/store/reducer/A3recommend.ts
  82. 0 38
      src/store/reducer/A4iosUser.ts
  83. 0 28
      src/store/reducer/A5bookAudit.ts
  84. 0 28
      src/store/reducer/A6remarkAudit.ts
  85. 0 38
      src/store/reducer/A7notice.ts
  86. 4 14
      src/store/reducer/index.ts
  87. 0 41
      src/types/api/A1manage.d.ts
  88. 73 0
      src/types/api/A1scene.d.ts
  89. 0 24
      src/types/api/A2classify.d.ts
  90. 60 0
      src/types/api/A2line.d.ts
  91. 0 23
      src/types/api/A3recommend.ts
  92. 0 20
      src/types/api/A4iosUser.ts
  93. 0 28
      src/types/api/A5bookAudit.ts
  94. 0 13
      src/types/api/A6remarkAudit.ts
  95. 0 14
      src/types/api/A7notice.ts
  96. 2 7
      src/types/index.d.ts
  97. 10 6
      src/utils/http.ts
  98. 9 98
      src/utils/tableData.ts
  99. 44 0
      yarn.lock

+ 3 - 0
package.json

@@ -4,6 +4,9 @@
   "private": true,
   "dependencies": {
     "@ant-design/cssinjs": "^1.5.6",
+    "@dnd-kit/core": "^6.3.1",
+    "@dnd-kit/modifiers": "^9.0.0",
+    "@dnd-kit/sortable": "^10.0.0",
     "@testing-library/jest-dom": "^5.16.5",
     "@testing-library/react": "^13.4.0",
     "@testing-library/user-event": "^13.5.0",

+ 1 - 1
public/index.html

@@ -21,7 +21,7 @@
       work correctly both with client-side routing and a non-root public URL.
       Learn how to configure a non-root public URL by running `npm run build`.
     -->
-    <title>刘少奇同志纪念馆数字图书馆-管理后台</title>
+    <title>云上岳阳-管理后台</title>
   </head>
   <body>
     <noscript>You need to enable JavaScript to run this app.</noscript>

+ 26 - 27
src/App.tsx

@@ -1,25 +1,24 @@
-import "@/assets/styles/base.css";
+import '@/assets/styles/base.css'
 // 关于路由
-import React from "react";
-import { Router, Route, Switch } from "react-router-dom";
-import history from "./utils/history";
-import AuthRoute from "./components/AuthRoute";
-import SpinLoding from "./components/SpinLoding";
-import AsyncSpinLoding from "./components/AsyncSpinLoding";
-import { Image } from "antd";
-import { useSelector } from "react-redux";
-import store, { RootState } from "./store";
-import UpAsyncLoding from "./components/UpAsyncLoding";
-import MessageCom from "./components/Message";
-import LookDom from "./components/LookDom";
-const Layout = React.lazy(() => import("./pages/Layout"));
-const Login = React.lazy(() => import("./pages/Login"));
+import React from 'react'
+import { Router, Route, Switch } from 'react-router-dom'
+import history from './utils/history'
+import AuthRoute from './components/AuthRoute'
+import SpinLoding from './components/SpinLoding'
+import AsyncSpinLoding from './components/AsyncSpinLoding'
+import { Image } from 'antd'
+import { baseURL } from './utils/http'
+import { useSelector } from 'react-redux'
+import store, { RootState } from './store'
+import UpAsyncLoding from './components/UpAsyncLoding'
+import MessageCom from './components/Message'
+import LookDom from './components/LookDom'
+const Layout = React.lazy(() => import('./pages/Layout'))
+const Login = React.lazy(() => import('./pages/Login'))
 
 export default function App() {
   // 从仓库中获取查看图片的信息
-  const lookBigImg = useSelector(
-    (state: RootState) => state.A0Layout.lookBigImg
-  );
+  const lookBigImg = useSelector((state: RootState) => state.A0Layout.lookBigImg)
 
   return (
     <>
@@ -28,8 +27,8 @@ export default function App() {
         <React.Suspense fallback={<SpinLoding />}>
           <Switch>
             {/* 测试页面 */}
-            <Route path="/login" component={Login} />
-            <AuthRoute path="/" component={Layout} />
+            <Route path='/login' component={Login} />
+            <AuthRoute path='/' component={Layout} />
           </Switch>
         </React.Suspense>
       </Router>
@@ -41,14 +40,14 @@ export default function App() {
       <Image
         preview={{
           visible: lookBigImg.show,
-          src: lookBigImg.url,
-          onVisibleChange: (value) => {
+          src: baseURL + lookBigImg.url,
+          onVisibleChange: value => {
             // 清除仓库信息
             store.dispatch({
-              type: "layout/lookBigImg",
-              payload: { url: "", show: false },
-            });
-          },
+              type: 'layout/lookBigImg',
+              payload: { url: '', show: false }
+            })
+          }
         }}
       />
 
@@ -61,5 +60,5 @@ export default function App() {
       {/* antd 轻提示 ---兼容360浏览器 */}
       <MessageCom />
     </>
-  );
+  )
 }

BIN
src/assets/img/eye.png


BIN
src/assets/img/eyex.png


BIN
src/assets/img/inputBg.png


BIN
src/assets/img/loginBac.png


BIN
src/assets/img/loginBtnBg.png


BIN
src/assets/img/logo.png


BIN
src/assets/img/logo2.png


BIN
src/assets/img/logo3.png


+ 30 - 0
src/components/DragTable/index.module.scss

@@ -0,0 +1,30 @@
+.dragTable {
+  display: flex;
+  flex-direction: column;
+  gap: 20px;
+  :global {
+    .ant-btn {
+      width: 82px;
+    }
+  }
+}
+
+.modal {
+  :global {
+    .ant-modal-content {
+      width: 400px;
+      height: 180px;
+      display: flex;
+      flex-direction: column;
+      justify-content: center;
+      .ant-modal-footer {
+        display: flex;
+        justify-content: center;
+        gap: 20px;
+        .ant-btn {
+          width: 82px;
+        }
+      }
+    }
+  }
+}

+ 198 - 0
src/components/DragTable/index.tsx

@@ -0,0 +1,198 @@
+import React, { useState, useCallback, useEffect } from 'react'
+import type { DragEndEvent } from '@dnd-kit/core'
+import { DndContext, PointerSensor, useSensor, useSensors } from '@dnd-kit/core'
+import { restrictToVerticalAxis } from '@dnd-kit/modifiers'
+import {
+  arrayMove,
+  SortableContext,
+  useSortable,
+  verticalListSortingStrategy
+} from '@dnd-kit/sortable'
+import { CSS } from '@dnd-kit/utilities'
+import styles from './index.module.scss'
+import { Table, Button, Modal, Form, AutoComplete, Input } from 'antd'
+import { useDispatch, useSelector } from 'react-redux'
+import { A1_APIgetList } from '@/store/action/A1scene'
+import { RootState } from '@/store'
+import type { TableColumnsType } from 'antd'
+
+export interface DataType {
+  id: number
+  name: string
+}
+
+interface RowProps extends React.HTMLAttributes<HTMLTableRowElement> {
+  'data-row-key': string
+}
+
+const Row: React.FC<Readonly<RowProps>> = props => {
+  const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
+    id: props['data-row-key']
+  })
+
+  const style: React.CSSProperties = {
+    ...props.style,
+    transform: CSS.Translate.toString(transform),
+    transition,
+    cursor: 'move',
+    ...(isDragging ? { position: 'relative', zIndex: 9999 } : {})
+  }
+
+  return <tr {...props} ref={setNodeRef} style={style} {...attributes} {...listeners} />
+}
+
+type DragTableProps = {
+  columns: TableColumnsType<DataType>
+  dataSource: DataType[]
+  setDataSource: (value: DataType[] | ((prev: DataType[]) => DataType[])) => void
+}
+
+const DragTable: React.FC<DragTableProps> = ({ columns, dataSource, setDataSource }) => {
+  const dispatch = useDispatch()
+
+  const sensors = useSensors(
+    useSensor(PointerSensor, {
+      activationConstraint: {
+        distance: 1
+      }
+    })
+  )
+
+  const [title, setTitle] = useState('')
+  // 搜索景点
+  const getListFu = useCallback(() => {
+    dispatch(A1_APIgetList({ pageNum: 1, pageSize: 10, searchKey: title }))
+  }, [dispatch, title])
+  // 新增景点列表
+  const sceneList = useSelector((state: RootState) => state.A1scene.tableInfo)
+
+  const onDragEnd = ({ active, over }: DragEndEvent) => {
+    if (active.id !== over?.id) {
+      setDataSource(prev => {
+        const activeId = Number(active.id)
+        const overId = Number(over?.id)
+        const activeIndex = prev.findIndex(i => i.id === activeId)
+        const overIndex = prev.findIndex(i => i.id === overId)
+        return arrayMove(prev, activeIndex, overIndex)
+      })
+    }
+  }
+
+  const [isModalVisible, setIsModalVisible] = useState(false)
+  const [form] = Form.useForm()
+
+  useEffect(() => {
+    if (isModalVisible) {
+      getListFu()
+    } else {
+      setTitle('')
+    }
+  }, [getListFu, isModalVisible])
+
+  // 新增景点提交逻辑
+  const handleAddSubmit = async () => {
+    try {
+      const values = await form.validateFields()
+      // 检查是否已存在相同的景点名称
+      const exists = dataSource.some(item => item.id === values.id)
+      if (exists) {
+        form.setFields([
+          {
+            name: 'sceneName',
+            errors: ['景点已存在']
+          }
+        ])
+        return
+      }
+      setDataSource(prev => [
+        ...prev,
+        {
+          id: values.id,
+          name: values.sceneName
+        }
+      ])
+      setIsModalVisible(false)
+      form.resetFields()
+    } catch (error) {
+      console.log('Validation failed:', error)
+    }
+  }
+
+  return (
+    <div className={styles.dragTable}>
+      <Button type='primary' onClick={() => setIsModalVisible(true)}>
+        新增
+      </Button>
+
+      {/* 修改后的模态框 */}
+      <Modal
+        className={styles.modal}
+        visible={isModalVisible}
+        onCancel={() => {
+          // 取消按钮逻辑保持不变
+          setIsModalVisible(false)
+          form.resetFields()
+        }}
+        closable={false}
+        footer={[
+          <Button key='ok' type='primary' onClick={handleAddSubmit}>
+            提交
+          </Button>,
+          <Button
+            key='cancel'
+            onClick={() => {
+              setIsModalVisible(false)
+              form.resetFields()
+            }}
+          >
+            取消
+          </Button>
+        ]}
+        title={null}
+        centered
+      >
+        <Form form={form} layout='vertical' requiredMark='optional'>
+          <Form.Item name='sceneName' rules={[{ required: true, message: '请输入景点名称!' }]}>
+            <AutoComplete
+              onChange={v => setTitle(v)}
+              onSelect={(value, option) => {
+                form.setFieldsValue({
+                  name: value,
+                  id: option.id
+                })
+              }}
+              size='large'
+              placeholder='请输入或选择景点名称'
+              options={sceneList.list.map(item => ({
+                value: item.name,
+                label: item.name,
+                id: item.id
+              }))}
+              style={{ width: '100%' }}
+            />
+          </Form.Item>
+          {/* 新增隐藏的id字段用于存储选中项的id */}
+          <Form.Item style={{ display: 'none' }} name='id'>
+            <Input type='hidden' />
+          </Form.Item>
+        </Form>
+      </Modal>
+
+      <DndContext sensors={sensors} modifiers={[restrictToVerticalAxis]} onDragEnd={onDragEnd}>
+        <SortableContext
+          items={dataSource.map(i => i.id.toString())}
+          strategy={verticalListSortingStrategy}
+        >
+          <Table<DataType>
+            components={{ body: { row: Row } }}
+            rowKey={record => record.id.toString()}
+            columns={columns}
+            dataSource={dataSource}
+          />
+        </SortableContext>
+      </DndContext>
+    </div>
+  )
+}
+
+export default DragTable

+ 7 - 0
src/components/MyTable/index.module.scss

@@ -11,6 +11,13 @@
           a {
             color: var(--themeColor) !important;
           }
+
+          .ant-btn {
+            background-color: transparent;
+            span:hover {
+              color: var(--themeColor) !important;
+            }
+          }
         }
       }
       .tabx {

+ 38 - 22
src/components/MyTable/index.tsx

@@ -2,8 +2,8 @@ import React, { useCallback, useEffect, useMemo } from 'react'
 import styles from './index.module.scss'
 import { Table } from 'antd'
 import ImageLazy from '../ImageLazy'
-
 type Props = {
+  myKey?: string //表格的key
   yHeight?: number //设置表格的高度
   list: any //表格数据
   columnsTemp: any[][] //表格展示
@@ -51,7 +51,8 @@ function MyTable({
   classKey = '',
   merge,
   myTitle,
-  isNull = '(空)'
+  isNull = '(空)',
+  myKey
 }: Props) {
   useEffect(() => {
     const dom = document.querySelector(`.MyTable${classKey} .ant-table-body`) as HTMLDivElement
@@ -73,34 +74,40 @@ function MyTable({
     (v: any) => {
       /**
        * index:序号
-       * txt:正常数据
+       * txtNormal:正常数据
+       * txt:判断显示不同字段
        * img:图片
        * txtChange:判断显示不同字段
        * text:文字比较多的情况
+       * sort:排序
+       * link:链接
        */
 
       const obj = {
         index: (_: any, __: any, index: number) => index + 1 + (pageNum - 1) * pageSize,
-        txt: (item: any) =>
-          v[3] && !item[v[2]] ? (
-            <div dangerouslySetInnerHTML={{ __html: v[3] }}></div>
-          ) : (
-            item[v[2]] || isNull
-          ),
-        img: (item: any) =>
-          v[3] && !item[v[2]] ? (
-            <div dangerouslySetInnerHTML={{ __html: v[3] }}></div>
-          ) : (
+        txtNormal: (item: any) => item[v[2]] || isNull,
+        txt: (item: any) => {
+          return item.status === 0 ? item[v[3]] || isNull : item[v[2]] || isNull
+        },
+        img: (item: any) => {
+          console.log(item[v[2]], v[2], v, 'txt')
+          return (
             <div className='tableImgAuto'>
-              <ImageLazy
-                width={60}
-                height={60}
-                srcBig={item.thumbPc}
-                src={item[v[2]] || item.thumb}
-                offline={(item[v[2]] || item.thumb || '').includes('http')}
-              />
+              {item[v[2]] ? (
+                <ImageLazy
+                  width={60}
+                  height={60}
+                  srcBig={item[v[2]]}
+                  src={item[v[2]]}
+                  offline={item[v[2]].includes('http')}
+                />
+              ) : (
+                isNull
+              )}
             </div>
-          ),
+          )
+        },
+        scenes: (item: any) => item.siteIds?.split(',').length || 0,
         txtChange: (item: any) => Reflect.get(v[3], item[v[2]]) || v[4] || isNull,
         text: (item: any) => {
           let tempCom: any = item[v[2]] || isNull
@@ -120,6 +127,15 @@ function MyTable({
           }
 
           return tempCom
+        },
+        link: (item: any) => {
+          return item[v[2]] ? (
+            <a href={item[v[2]]} target='_blank' title={item[v[2]]} rel='noreferrer'>
+              {item[v[2]]}
+            </a>
+          ) : (
+            isNull
+          )
         }
       }
 
@@ -150,7 +166,7 @@ function MyTable({
       scroll={{ y: yHeight ? yHeight : '' }}
       dataSource={list}
       columns={[...columns, ...lastBtn]}
-      rowKey='id'
+      rowKey={myKey ? myKey : 'id'}
       pagination={
         pagingInfo
           ? {

+ 3 - 4
src/components/UpXlsx.tsx

@@ -1,5 +1,4 @@
 import { API_upFile } from '@/store/action/layout'
-import { A1tableType } from '@/types'
 import { fileDomInitialFu } from '@/utils/domShow'
 import { MessageFu } from '@/utils/message'
 import { notification } from 'antd'
@@ -8,7 +7,7 @@ import { forwardRef, useImperativeHandle } from 'react'
 
 type Props = {
   url: string
-  xlsxResInfoFu: (arr: A1tableType[]) => void
+  xlsxResInfoFu: (arr: any[]) => void
   ref: any //当前自己的ref,给父组件调用
   dirCode: string
   ISBNArr: string[] //ISBN编号集合,用来过滤表格
@@ -64,7 +63,7 @@ function UpXlsx({ url, xlsxResInfoFu, dirCode, ISBNArr }: Props, ref: any) {
             //   placement: 'topLeft'
             // })
 
-            const arrTemp: A1tableType[] = res.data || []
+            const arrTemp: any[] = res.data || []
 
             const moreTit: number[] = []
 
@@ -93,7 +92,7 @@ function UpXlsx({ url, xlsxResInfoFu, dirCode, ISBNArr }: Props, ref: any) {
             }
 
             const temp: string[] = []
-            const arrRes: A1tableType[] = []
+            const arrRes: any[] = []
 
             arr.forEach((v: any, i: number) => {
               v.id = Date.now() + i

+ 28 - 37
src/components/ZupOne/index.tsx

@@ -9,7 +9,6 @@ import {
   UploadOutlined
 } from '@ant-design/icons'
 import store from '@/store'
-import { baseURL } from '@/utils/http'
 import classNames from 'classnames'
 import { Button } from 'antd'
 import { MessageFu } from '@/utils/message'
@@ -54,9 +53,9 @@ function ZupOne(
   ref: any
 ) {
   const [fileUrl, setFileUrl] = useState({
-    fileName: '',
-    filePath: '',
-    thumb: '' //压缩图
+    filename: '',
+    url: '',
+    thUrl: '' //压缩图
   })
 
   const myInput = useRef<HTMLInputElement>(null)
@@ -120,7 +119,11 @@ function ZupOne(
           const res = await API_upFile(fd, myUrl)
           if (res.code === 0) {
             MessageFu.success('上传成功!')
-            setFileUrl(res.data)
+            setFileUrl({
+              filename: res.data.fileName,
+              url: res.data.filePath,
+              thUrl: res.data.filePath
+            })
           }
           fileDomInitialFu()
         } catch (error) {
@@ -133,7 +136,7 @@ function ZupOne(
 
   // 让父组件调用的 回显 附件 地址
   const setFileComFileFu = useCallback(
-    (valObj: { fileName: string; filePath: string; thumb: string }) => {
+    (valObj: { filename: string; url: string; thUrl: string }) => {
       setFileUrl(valObj)
     },
     []
@@ -160,16 +163,18 @@ function ZupOne(
     return accept
   }, [myType])
 
+  console.log(fileUrl, 'fileUrl')
+
   // 点击 预览(除了图片)
   const lookFileNoImgFu = useCallback(
     (type: MyTypeType) => {
       if (type === 'pdf' || type === 'thumb') {
         // 新窗口打开
-        window.open(baseURL + fileUrl.filePath)
+        window.open(fileUrl.url)
       } else if (type !== 'epub') {
         store.dispatch({
           type: 'layout/lookDom',
-          payload: { src: fileUrl.filePath, type }
+          payload: { src: fileUrl.url, type }
         })
       }
 
@@ -177,7 +182,7 @@ function ZupOne(
       // } else {
       // }
     },
-    [fileUrl.filePath]
+    [fileUrl.url]
   )
 
   return (
@@ -191,7 +196,7 @@ function ZupOne(
       />
       {myType === 'thumb' ? (
         <div
-          hidden={fileUrl.filePath !== ''}
+          hidden={fileUrl.url !== ''}
           className='file_upIcon'
           onClick={() => myInput.current?.click()}
         >
@@ -199,7 +204,7 @@ function ZupOne(
         </div>
       ) : (
         <Button
-          hidden={fileUrl.filePath !== ''}
+          hidden={fileUrl.url !== ''}
           onClick={() => myInput.current?.click()}
           icon={<UploadOutlined rev={undefined} />}
         >
@@ -209,22 +214,16 @@ function ZupOne(
 
       {/* 为图片的情况-------------- */}
       {myType === 'thumb' ? (
-        <div className='file_img' hidden={fileUrl.filePath === ''}>
+        <div className='file_img' hidden={fileUrl.url === ''}>
           {fileUrl ? (
-            <ImageLazy
-              width={100}
-              height={100}
-              srcBig={fileUrl.filePath}
-              src={fileUrl.thumb}
-              noLook
-            />
+            <ImageLazy width={100} height={100} srcBig={fileUrl.url} src={fileUrl.thUrl} noLook />
           ) : null}
 
           {/* 删除 */}
           <div className='file_closeBox' hidden={isLook}>
             <MyPopconfirm
               txtK='删除'
-              onConfirm={() => setFileUrl({ fileName: '', filePath: '', thumb: '' })}
+              onConfirm={() => setFileUrl({ filename: '', url: '', thUrl: '' })}
               Dom={<CloseOutlined rev={undefined} />}
             />
           </div>
@@ -235,35 +234,29 @@ function ZupOne(
               onClick={() =>
                 store.dispatch({
                   type: 'layout/lookBigImg',
-                  payload: { url: baseURL + fileUrl.filePath, show: true }
+                  payload: { url: fileUrl.url, show: true }
                 })
               }
               rev={undefined}
             />
-            <a href={baseURL + fileUrl.filePath} download target='_blank' rel='noreferrer'>
+            <a href={fileUrl.url} download target='_blank' rel='noreferrer'>
               <DownloadOutlined rev={undefined} />
             </a>
           </div>
         </div>
-      ) : fileUrl.filePath ? (
+      ) : fileUrl.url ? (
         <div className='fileInfo'>
-          <div className='upSuccTxt'>{fileUrl.fileName}</div>
+          <div className='upSuccTxt'>{fileUrl.filename}</div>
           {/* 视频预览 */}
           <div
             className='clearCover'
-            hidden={!fileUrl.filePath || myType === 'epub'}
+            hidden={!fileUrl.url || myType === 'epub'}
             onClick={() => lookFileNoImgFu(myType)}
           >
             <EyeOutlined rev={undefined} />
           </div>
           {/* 视频下载 */}
-          <a
-            href={baseURL + fileUrl.filePath}
-            download
-            target='_blank'
-            className='clearCover'
-            rel='noreferrer'
-          >
+          <a href={fileUrl.url} download target='_blank' className='clearCover' rel='noreferrer'>
             <DownloadOutlined rev={undefined} />
           </a>
           {/* 视频删除 */}
@@ -271,7 +264,7 @@ function ZupOne(
           {isLook ? null : (
             <MyPopconfirm
               txtK='删除'
-              onConfirm={() => setFileUrl({ fileName: '', filePath: '', thumb: '' })}
+              onConfirm={() => setFileUrl({ filename: '', url: '', thUrl: '' })}
               Dom={<CloseOutlined className='clearCover' rev={undefined} />}
             />
           )}
@@ -279,11 +272,9 @@ function ZupOne(
       ) : null}
 
       <div className='fileBoxRow_r_tit' hidden={isLook}>
-        格式要求:支持{formatTxt}格式;最大支持{size}M。{upTxt}
+        {upTxt},支持{formatTxt}格式,不超过{size}M。
         <br />
-        <div
-          className={classNames('noUpThumb', !fileUrl.filePath && fileCheck ? 'noUpThumbAc' : '')}
-        >
+        <div className={classNames('noUpThumb', !fileUrl.url && fileCheck ? 'noUpThumbAc' : '')}>
           {checkTxt}
         </div>
       </div>

+ 0 - 94
src/pages/A1manage/A1Import/index.module.scss

@@ -1,94 +0,0 @@
-.A1Import {
-  position: absolute;
-  top: 0;
-  left: 0;
-  width: 100%;
-  height: 100%;
-  z-index: 10;
-  background-color: #ecedf1;
-
-  :global {
-    .A1top {
-      .anticon-arrow-left {
-        cursor: pointer;
-        font-size: 30px;
-        margin-right: 24px;
-      }
-      h1 {
-        line-height: 30px;
-        font-size: 16px;
-      }
-      & > div {
-        display: flex;
-        align-items: center;
-        .A1iInco {
-          width: 24px;
-          height: 24px;
-          border-radius: 50%;
-          cursor: pointer;
-          display: flex;
-          justify-content: center;
-          align-items: center;
-          border: 1px solid #ccc;
-        }
-      }
-    }
-    .A1tableBox {
-      position: relative;
-      // height: calc(100% - 180px);
-      .ant-table-tbody .ant-table-cell {
-        padding: 4px !important;
-      }
-      .A1Ibtn {
-        position: absolute;
-        bottom: 10px;
-        left: 50%;
-        transform: translateX(-50%);
-        & > span {
-          width: 500px;
-          position: absolute;
-          top: -8px;
-          left: 80px;
-          opacity: 0;
-          pointer-events: none;
-          transition: all 0.3s;
-          color: #ff4d4d;
-        }
-        .A1IbtnTit {
-          top: 8px;
-          opacity: 1;
-        }
-      }
-    }
-
-    .A1Iedit {
-      position: absolute;
-      top: 0;
-      left: 0;
-      z-index: 10;
-      width: 100%;
-      height: 100%;
-      background-color: rgba(0, 0, 0, 0.6);
-      border-radius: 10px;
-      padding: 50px 100px;
-      & > div {
-        width: 100%;
-        height: 100%;
-        position: relative;
-      }
-    }
-  }
-}
-
-.A1Imo {
-  :global {
-    .ant-modal-body {
-      padding-top: 20px !important;
-      border-top: 1px solid #ccc;
-    }
-    .A1ImoRow {
-      margin-bottom: 20px;
-      font-size: 16px;
-    }
-  }
-}

+ 0 - 179
src/pages/A1manage/A1Import/index.tsx

@@ -1,179 +0,0 @@
-import React, { useCallback, useMemo, useRef, useState } from 'react'
-import styles from './index.module.scss'
-import { ArrowLeftOutlined, QuestionOutlined } from '@ant-design/icons'
-import MyPopconfirm from '@/components/MyPopconfirm'
-import { Button, Modal } from 'antd'
-import MyTable from '@/components/MyTable'
-import { A1tableType, A2tableType, A2TreeType } from '@/types'
-import { A1tableCimp } from '@/utils/tableData'
-import UpXlsx from '@/components/UpXlsx'
-import { baseURL } from '@/utils/http'
-import classNames from 'classnames'
-import A1add from '../A1add'
-import { A1_APIimport } from '@/store/action/A1manage'
-import { MessageFu } from '@/utils/message'
-
-type Props = {
-  closeFu: () => void
-  addTableFu: () => void
-  storageArr: A2TreeType[]
-  exhibitTypeArr: A2tableType[]
-}
-
-function A1Import({ closeFu, addTableFu, storageArr, exhibitTypeArr }: Props) {
-  const [list, setList] = useState<A1tableType[]>([])
-
-  const [tit, setTit] = useState(false)
-
-  const tableLastBtn = useMemo(() => {
-    return [
-      {
-        title: '操作',
-        render: (item: A1tableType) => (
-          <>
-            <Button size='small' type='text' onClick={() => setEditInfo(item)}>
-              编辑
-            </Button>
-
-            <MyPopconfirm
-              txtK='删除'
-              onConfirm={() => setList(list.filter(v => v.id !== item.id))}
-            />
-          </>
-        )
-      }
-    ]
-  }, [list])
-
-  // 编辑
-  const [editInfo, setEditInfo] = useState({} as A1tableType)
-
-  // 上传xlsx 的ref
-  const upXlsxRef = useRef<any>(null)
-
-  // 信息录入不完整的消息提示
-  const titShow = useMemo(() => {
-    return list.some(v => !v.thumb || !v.storageId || !v.exhibitTypeId || !v.filePath)
-  }, [list])
-
-  // 编辑完返回的信息
-  const editFu = useCallback(
-    (info: A1tableType) => {
-      const index = list.findIndex(v => v.id === info.id)
-      const arr = [...list]
-      arr[index] = info
-      setList(arr)
-    },
-    [list]
-  )
-
-  // 点击导入
-  const impFu = useCallback(async () => {
-    const res = await A1_APIimport(list.map(v => ({ ...v, id: null })))
-    if (res.code === 0) {
-      MessageFu.success('导入成功!')
-      addTableFu()
-      closeFu()
-    }
-
-    // else if(res.code===-2){
-    //   MessageFu.warning()
-    // }
-  }, [addTableFu, closeFu, list])
-
-  return (
-    <div className={styles.A1Import}>
-      <div className='A1top'>
-        <div>
-          <ArrowLeftOutlined onClick={closeFu} />
-          <h1>图书批量导入</h1>
-        </div>
-        <div>
-          关于导入规则&nbsp;
-          <span className='A1iInco' onClick={() => setTit(true)}>
-            <QuestionOutlined />
-          </span>
-          &emsp;
-          <MyPopconfirm txtK='清空' onConfirm={() => setList([])} Dom={<Button>清空</Button>} />
-          &emsp;
-          <a href={baseURL + '/baseData/tp_book.xlsx'} download>
-            <Button>下载模板</Button>
-          </a>
-          &emsp;
-          <UpXlsx
-            url='cms/book/upload/excel'
-            ref={upXlsxRef}
-            xlsxResInfoFu={arr => setList([...arr, ...list])}
-            dirCode='cameraXlsx'
-            ISBNArr={list.map(v => v.num)}
-          />
-          {/* 上传xlsx */}
-          <Button type='primary' onClick={() => upXlsxRef.current?.myInputClickFu()}>
-            上传
-          </Button>
-        </div>
-      </div>
-
-      {/* 表格主体 */}
-      <div className='A1tableBox'>
-        <MyTable
-          classKey='A1Itable'
-          yHeight={610}
-          list={list}
-          columnsTemp={A1tableCimp}
-          lastBtn={tableLastBtn}
-          pagingInfo={false}
-        />
-
-        {/* 底部导入按钮 */}
-        <div className='A1Ibtn'>
-          <Button disabled={list.length === 0 || titShow} type='primary' onClick={impFu}>
-            导入
-          </Button>
-          <span className={classNames(list.length && titShow ? 'A1IbtnTit' : '')}>
-            请先完善代填入字段
-          </span>
-        </div>
-      </div>
-
-      {/* 复用编辑 */}
-      {editInfo.id ? (
-        <div className='A1Iedit'>
-          <div>
-            <A1add
-              editInfo={{ id: editInfo.id, txt: '编辑', info: editInfo }}
-              closeFu={() => setEditInfo({} as A1tableType)}
-              addTableFu={() => {}}
-              editTableFu={() => {}}
-              storageArr={storageArr}
-              exhibitTypeArr={exhibitTypeArr}
-              isImportFu={info => editFu(info)}
-              ISBNArr={list.filter(v => v.id !== editInfo.id).map(v => v.num)}
-            />
-          </div>
-        </div>
-      ) : null}
-
-      {/* 导入规则 */}
-      <Modal
-        wrapClassName={styles.A1Imo}
-        open={tit}
-        title='导入规则'
-        onCancel={() => setTit(false)}
-        footer={
-          [] // 设置footer为空,去掉 取消 确定默认按钮
-        }
-      >
-        <div className='A1ImoRow'>1:下载模板</div>
-        <div className='A1ImoRow'>2:在模板中填入内容,注意必填项和填入要求</div>
-        <div className='A1ImoRow'>3:上传已填写的模板文件</div>
-        <div className='A1ImoRow'>4:在当前列表中,完善图书信息,包括上传封面,附件等</div>
-        <div className='A1ImoRow'>5:导入内容</div>
-      </Modal>
-    </div>
-  )
-}
-
-const MemoA1Import = React.memo(A1Import)
-
-export default MemoA1Import

+ 0 - 402
src/pages/A1manage/A1add/index.tsx

@@ -1,402 +0,0 @@
-import React, { useCallback, useEffect, useRef, useState } from 'react'
-import styles from './index.module.scss'
-import classNames from 'classnames'
-import { A1EditInfoType } from '../data'
-import { Button, Cascader, Form, FormInstance, Input, InputNumber, Select } from 'antd'
-import { A1_APIgetInfo, A1_APIsave } from '@/store/action/A1manage'
-import { MessageFu } from '@/utils/message'
-import ZupOne from '@/components/ZupOne'
-import TextArea from 'antd/es/input/TextArea'
-import dayjs from 'dayjs'
-import { A1tableType, A2tableType, A2TreeType } from '@/types'
-import MyPopconfirm from '@/components/MyPopconfirm'
-import { A5_APIgetInfo } from '@/store/action/A5bookAudit'
-import { treeResIdFu } from '@/pages/A2classify/data'
-
-type Props = {
-  editInfo: A1EditInfoType
-  closeFu: () => void
-  addTableFu: () => void
-  editTableFu: () => void
-  storageArr: A2TreeType[]
-  exhibitTypeArr: A2tableType[]
-  isAudit?: boolean //从图书审核页面进来
-  isImportFu?: (info: A1tableType) => void // 从批量导入里面进来
-  ISBNArr?: string[] //ISBN编号集合,用来判断当前填写的ISBN是否已经存在了(外层表格中)
-}
-
-function A1add({
-  editInfo,
-  closeFu,
-  addTableFu,
-  editTableFu,
-  storageArr,
-  exhibitTypeArr,
-  isAudit,
-  isImportFu,
-  ISBNArr
-}: Props) {
-  // 表单的ref
-  const FormBoxRef = useRef<FormInstance>(null)
-
-  // 封面图的ref
-  const ZupThumbRef = useRef<any>(null)
-
-  // txt的ref
-  const ZupTxtRef = useRef<any>(null)
-
-  // 回显数据的方法调用
-  const dataShow = useCallback((info: A1tableType) => {
-    let storageIds: any[] = []
-    if (info.ancestor) storageIds = info.ancestor.split(',').map((v: string) => Number(v))
-
-    if (info.storageId) storageIds.push(Number(info.storageId))
-
-    const obj = {
-      ...info,
-      storageIds,
-      exhibitTypeId: info.exhibitTypeId ? Number(info.exhibitTypeId) : null,
-      year: info.year ? info.year : null
-    }
-
-    FormBoxRef.current?.setFieldsValue(obj)
-
-    // 设置封面图
-    ZupThumbRef.current?.setFileComFileFu({
-      fileName: '',
-      thumb: info.thumb,
-      filePath: info.thumbPc
-    })
-
-    // 设置附件
-    ZupTxtRef.current?.setFileComFileFu({
-      fileName: info.fileName,
-      filePath: info.filePath
-    })
-  }, [])
-
-  // 编辑/查看 进入页面 获取信息
-  const getInfoFu = useCallback(
-    async (id: number) => {
-      if (isImportFu && editInfo.info) dataShow(editInfo.info)
-      else {
-        const res = isAudit ? await A5_APIgetInfo(id) : await A1_APIgetInfo(id)
-        if (res.code === 0) {
-          dataShow(res.data)
-        }
-      }
-    },
-    [dataShow, editInfo.info, isAudit, isImportFu]
-  )
-
-  // 附件 是否 已经点击过确定
-  const [fileCheck, setFileCheck] = useState(false)
-
-  useEffect(() => {
-    if (editInfo.id > 0) {
-      getInfoFu(editInfo.id)
-    } else {
-      FormBoxRef.current?.setFieldsValue({
-        sort: 999,
-        year: dayjs().get('year')
-      })
-    }
-  }, [editInfo.id, getInfoFu])
-
-  // 没有通过校验
-  const onFinishFailed = useCallback(() => {
-    setFileCheck(true)
-  }, [])
-
-  //  通过校验点击确定
-  const onFinish = useCallback(
-    async (values: any) => {
-      setFileCheck(true)
-
-      const coverUrl1 = ZupThumbRef.current?.fileComFileResFu()
-      // 没有传 封面图
-      if (!coverUrl1.filePath) return MessageFu.warning('请上传封面图!')
-
-      let fileName = ''
-      let filePath = ''
-      // txt附件
-      const ZupTxtRefObj = ZupTxtRef.current?.fileComFileResFu()
-      fileName = ZupTxtRefObj.fileName
-      filePath = ZupTxtRefObj.filePath
-      if (!filePath) return MessageFu.warning('请上传epub附件!')
-
-      if (ISBNArr && ISBNArr.includes(values.num) && values.num !== '')
-        return MessageFu.warning(`ISBN编号 ${values.num} 重复!`)
-
-      let storageId: null | number = null
-
-      if (values.storageIds && values.storageIds.length) {
-        storageId = values.storageIds[values.storageIds.length - 1]
-      }
-
-      const obj = {
-        ...values,
-        id: isAudit ? null : editInfo.id > 0 ? editInfo.id : null,
-        thumb: coverUrl1.thumb,
-        thumbPc: coverUrl1.filePath,
-        storageId,
-        fileName,
-        filePath
-      }
-
-      // if (obj) {
-      //   console.log(123, obj);
-      //   return;
-      // }
-
-      if (isImportFu && editInfo.info) {
-        const info = editInfo.info
-
-        // 多级筛选的 映射字段回显
-        let ancestor = ''
-        let storageName = ''
-
-        const storageArrAc = treeResIdFu(storageArr, storageId!)
-        if (storageArrAc) {
-          ancestor = storageArrAc.ancestor
-          storageName = storageArrAc.name
-        }
-
-        // 下拉框 映射字段回显
-        let exhibitTypeName = ''
-
-        const exhibitTypeArrAc = exhibitTypeArr.find(v => v.id === values.exhibitTypeId)
-
-        if (exhibitTypeArrAc) exhibitTypeName = exhibitTypeArrAc.name
-        const ImpObj = {
-          ...obj,
-          id: info.id,
-          ancestor,
-          storageName,
-          exhibitTypeName
-        }
-
-        isImportFu(ImpObj)
-        MessageFu.success('编辑成功!')
-        closeFu()
-      } else {
-        const res = await A1_APIsave(obj)
-
-        if (res.code === 0) {
-          MessageFu.success(isAudit ? '创建成功!' : `${editInfo.txt}成功!`)
-          editInfo.id > 0 ? editTableFu() : addTableFu()
-          closeFu()
-        }
-      }
-    },
-    [
-      ISBNArr,
-      addTableFu,
-      closeFu,
-      editInfo.id,
-      editInfo.info,
-      editInfo.txt,
-      editTableFu,
-      exhibitTypeArr,
-      isAudit,
-      isImportFu,
-      storageArr
-    ]
-  )
-
-  // 年份
-  const [ageSelect, setAgeSelect] = useState<{ value: string; label: string }[]>([])
-
-  useEffect(() => {
-    const arr: { value: string; label: string }[] = []
-    const nowYear = dayjs().get('year')
-    const num = nowYear - 1900
-    for (let i = 0; i <= num; i++) {
-      const temp = nowYear - i + ''
-      arr.push({
-        value: temp,
-        label: temp
-      })
-    }
-
-    setAgeSelect(arr)
-  }, [])
-
-  return (
-    <div className={styles.A1add}>
-      <div className={classNames('A1aMain', editInfo.txt === '查看' ? 'A1aMainLook' : '')}>
-        <Form
-          ref={FormBoxRef}
-          name='basic'
-          labelCol={{ span: 3 }}
-          onFinish={onFinish}
-          onFinishFailed={onFinishFailed}
-          autoComplete='off'
-          scrollToFirstError
-        >
-          <Form.Item label='书名' name='name' rules={[{ required: true, message: '请输入书名!' }]}>
-            <Input
-              readOnly={editInfo.txt === '查看'}
-              placeholder='请输入内容'
-              maxLength={50}
-              showCount
-            />
-          </Form.Item>
-
-          <Form.Item label='简介' name='description'>
-            <TextArea
-              readOnly={editInfo.txt === '查看'}
-              maxLength={200}
-              showCount
-              placeholder='请输入内容'
-            />
-          </Form.Item>
-
-          <Form.Item label='作者' name='author'>
-            <Input
-              readOnly={editInfo.txt === '查看'}
-              placeholder='请输入内容'
-              maxLength={20}
-              showCount
-            />
-          </Form.Item>
-
-          <Form.Item label='出版社' name='press'>
-            <Input
-              readOnly={editInfo.txt === '查看'}
-              placeholder='请输入内容'
-              maxLength={20}
-              showCount
-            />
-          </Form.Item>
-
-          <Form.Item label='出版年份' name='year'>
-            <Select
-              allowClear
-              placeholder='请选择年份'
-              style={{ width: 200 }}
-              options={ageSelect}
-            />
-          </Form.Item>
-
-          {/* 封面 */}
-          <div className='formRow'>
-            <div className='formLeft'>
-              <span>* </span>
-              封面:
-            </div>
-            <div className='formRight'>
-              <ZupOne
-                ref={ZupThumbRef}
-                isLook={editInfo.txt === '查看'}
-                fileCheck={fileCheck}
-                size={5}
-                dirCode={'A1manage'}
-                myUrl='cms/book/upload'
-                format={['image/jpeg', 'image/png']}
-                formatTxt='png、jpg和jpeg'
-                checkTxt='请上传封面图!'
-                upTxt='最多1张'
-                myType='thumb'
-              />
-            </div>
-          </div>
-          {editInfo.txt === '查看' ? <br /> : null}
-
-          <Form.Item
-            label='中图法分类'
-            name='storageIds'
-            rules={[{ required: true, message: '请选择中图法分类!' }]}
-          >
-            <Cascader
-              allowClear={false}
-              changeOnSelect
-              style={{ width: 300 }}
-              options={storageArr}
-              fieldNames={{ label: 'name', value: 'id', children: 'children' }}
-              placeholder='请选择'
-            />
-          </Form.Item>
-
-          <Form.Item
-            label='展示分类'
-            name='exhibitTypeId'
-            rules={[{ required: true, message: '请选择展示分类!' }]}
-          >
-            <Select
-              placeholder='请选择'
-              style={{ width: 200 }}
-              fieldNames={{ label: 'name', value: 'id' }}
-              options={exhibitTypeArr}
-            />
-          </Form.Item>
-
-          <Form.Item label='ISBN编号' name='num'>
-            <Input
-              readOnly={editInfo.txt === '查看'}
-              placeholder='请输入内容'
-              maxLength={20}
-              showCount
-            />
-          </Form.Item>
-          {/* 附件 */}
-          <div className='formRow'>
-            <div className='formLeft'>
-              <span>* </span>
-              附件:
-            </div>
-            <div className='formRight'>
-              <ZupOne
-                ref={ZupTxtRef}
-                isLook={editInfo.txt === '查看'}
-                fileCheck={fileCheck}
-                size={500}
-                dirCode='A1manage'
-                myUrl='cms/book/upload'
-                format={['']}
-                formatTxt='epub'
-                checkTxt='请上传epub附件!'
-                upTxt='最多1个'
-                myType='epub'
-              />
-            </div>
-          </div>
-          {editInfo.txt === '查看' ? <br /> : null}
-
-          <div className='A1fromRow'>
-            <Form.Item
-              label='排序值'
-              name='sort'
-              rules={[{ required: true, message: '请输入排序值!' }]}
-            >
-              <InputNumber min={1} max={999} precision={0} placeholder='请输入' />
-            </Form.Item>
-            <div className='A1_6Frow' hidden={editInfo.txt === '查看'}>
-              请输入1~999的数字。数字越小,排序越靠前。数字相同时,更新发布的内容排在前面
-            </div>
-          </div>
-
-          {/* 确定和取消按钮 */}
-          <Form.Item className='A1abtn'>
-            {editInfo.txt === '查看' ? (
-              <Button onClick={closeFu}>返回</Button>
-            ) : (
-              <>
-                <Button type='primary' htmlType='submit'>
-                  提交
-                </Button>
-                <br />
-                <br />
-                <MyPopconfirm txtK='取消' onConfirm={closeFu} />
-              </>
-            )}
-          </Form.Item>
-        </Form>
-      </div>
-    </div>
-  )
-}
-
-const MemoA1add = React.memo(A1add)
-
-export default MemoA1add

+ 0 - 225
src/pages/A1manage/A1ying/A1Yadd.tsx

@@ -1,225 +0,0 @@
-import React, { useCallback, useEffect, useRef, useState } from 'react'
-import styles from './index.module.scss'
-import { Button, Form, FormInstance, Input, InputNumber, Modal } from 'antd'
-import { A1_APIgetInfoById, A1_APIsaveById } from '@/store/action/A1manage'
-import { MessageFu } from '@/utils/message'
-import ZupOne from '@/components/ZupOne'
-import MyPopconfirm from '@/components/MyPopconfirm'
-import TextArea from 'antd/es/input/TextArea'
-
-type Props = {
-  type: 'img' | 'video'
-  id: number
-  bookId: number
-  closeFu: () => void
-  addTableFu: () => void
-  editTableFu: () => void
-}
-
-function A1Yadd({ type, id, closeFu, addTableFu, editTableFu, bookId }: Props) {
-  // 表单的ref
-  const FormBoxRef = useRef<FormInstance>(null)
-
-  // 封面图的ref
-  const ZupThumbRef = useRef<any>(null)
-
-  // 附件的ref
-  const ZupFileRef = useRef<any>(null)
-
-  // 编辑/查看 进入页面 获取信息
-  const getInfoFu = useCallback(async (id: number) => {
-    const res = await A1_APIgetInfoById(id)
-    if (res.code === 0) {
-      const data = res.data
-      FormBoxRef.current?.setFieldsValue(data)
-
-      // 设置封面图
-      ZupThumbRef.current?.setFileComFileFu({
-        fileName: '',
-        thumb: data.thumb,
-        filePath: data.thumbPc
-      })
-
-      // 设置附件
-      ZupFileRef.current?.setFileComFileFu({
-        fileName: data.fileName,
-        filePath: data.filePath
-      })
-    }
-  }, [])
-
-  // 附件 是否 已经点击过确定
-  const [fileCheck, setFileCheck] = useState(false)
-
-  useEffect(() => {
-    if (id > 0) {
-      getInfoFu(id)
-    } else {
-      FormBoxRef.current?.setFieldsValue({
-        sort: 999
-      })
-    }
-  }, [id, getInfoFu])
-
-  // 没有通过校验
-  const onFinishFailed = useCallback(() => {
-    setFileCheck(true)
-  }, [])
-
-  //  通过校验点击确定
-  const onFinish = useCallback(
-    async (values: any) => {
-      setFileCheck(true)
-
-      const coverUrl1 = ZupThumbRef.current?.fileComFileResFu()
-      // 没有传 封面图
-      if (!coverUrl1.filePath)
-        return MessageFu.warning(`请上传!${type === 'img' ? '图片' : '封面图'}!`)
-
-      let fileName = ''
-      let filePath = ''
-      // 附件
-      if (type === 'video') {
-        const ZupTxtRefObj = ZupFileRef.current?.fileComFileResFu()
-        fileName = ZupTxtRefObj.fileName
-        filePath = ZupTxtRefObj.filePath
-        if (!filePath) return MessageFu.warning('请上传附件!')
-      }
-
-      const obj = {
-        ...values,
-        id: id > 0 ? id : null,
-        thumb: coverUrl1.thumb,
-        thumbPc: coverUrl1.filePath,
-        fileName,
-        filePath,
-        type,
-        bookId
-      }
-
-      // if (obj) {
-      //   console.log(123, obj)
-      //   return
-      // }
-
-      const res = await A1_APIsaveById(obj)
-
-      if (res.code === 0) {
-        MessageFu.success(`${id > 0 ? '编辑' : '新增'}成功!`)
-        id > 0 ? editTableFu() : addTableFu()
-        closeFu()
-      }
-    },
-    [addTableFu, bookId, closeFu, editTableFu, id, type]
-  )
-
-  return (
-    <Modal
-      wrapClassName={styles.A1Yadd}
-      open={true}
-      title={id > 0 ? '编辑' : '新增'}
-      footer={
-        [] // 设置footer为空,去掉 取消 确定默认按钮
-      }
-    >
-      <div className='A1Ymain'>
-        <Form
-          ref={FormBoxRef}
-          name='basic'
-          labelCol={{ span: 2 }}
-          onFinish={onFinish}
-          onFinishFailed={onFinishFailed}
-          autoComplete='off'
-          scrollToFirstError
-        >
-          {type === 'video' ? (
-            <Form.Item
-              label='标题'
-              name='name'
-              rules={[{ required: true, message: '请输入标题!' }]}
-            >
-              <Input placeholder='请输入内容' maxLength={20} showCount />
-            </Form.Item>
-          ) : null}
-
-          {/* 封面 */}
-          <div className='formRow'>
-            <div className='formLeft'>
-              <span>* </span>
-              {type === 'img' ? '图片' : '封面'}:
-            </div>
-            <div className='formRight'>
-              <ZupOne
-                ref={ZupThumbRef}
-                fileCheck={fileCheck}
-                size={5}
-                dirCode={'A1manageY'}
-                myUrl='cms/video/upload'
-                format={['image/jpeg', 'image/png']}
-                formatTxt='png、jpg和jpeg'
-                checkTxt={`请上传${type === 'img' ? '图片' : '封面图'}!`}
-                upTxt='最多1张'
-                myType='thumb'
-              />
-            </div>
-          </div>
-
-          <Form.Item label={type === 'img' ? '正文' : '简介'} name='description'>
-            <TextArea maxLength={type === 'img' ? 1000 : 200} showCount placeholder='请输入内容' />
-          </Form.Item>
-
-          {/* 附件 */}
-          {type === 'video' ? (
-            <div className='formRow'>
-              <div className='formLeft'>
-                <span>* </span>
-                附件:
-              </div>
-              <div className='formRight'>
-                <ZupOne
-                  ref={ZupFileRef}
-                  fileCheck={fileCheck}
-                  size={2000}
-                  dirCode='A1manageY'
-                  myUrl='cms/video/upload'
-                  format={['video/mp4']}
-                  formatTxt='video'
-                  checkTxt='请上传video附件!'
-                  upTxt='最多1个'
-                  myType='video'
-                />
-              </div>
-            </div>
-          ) : null}
-
-          <div className='A1fromRow'>
-            <Form.Item
-              label='排序值'
-              name='sort'
-              rules={[{ required: true, message: '请输入排序值!' }]}
-            >
-              <InputNumber min={1} max={999} precision={0} placeholder='请输入' />
-            </Form.Item>
-            <div className='A1_6Frow'>
-              请输入1~999的数字。数字越小,排序越靠前。数字相同时,更新发布的内容排在前面
-            </div>
-          </div>
-
-          {/* 确定和取消按钮 */}
-          <Form.Item className='A1Ybtn'>
-            <Button type='primary' htmlType='submit'>
-              提交
-            </Button>
-            <br />
-            <br />
-            <MyPopconfirm txtK='取消' onConfirm={closeFu} />
-          </Form.Item>
-        </Form>
-      </div>
-    </Modal>
-  )
-}
-
-const MemoA1Yadd = React.memo(A1Yadd)
-
-export default MemoA1Yadd

+ 0 - 104
src/pages/A1manage/A1ying/index.module.scss

@@ -1,104 +0,0 @@
-.A1ying {
-  position: absolute;
-  top: 0;
-  left: 0;
-  width: 100%;
-  height: 100%;
-  z-index: 12;
-  background-color: #fff;
-  border-radius: 10px;
-  :global {
-    .A1Ytop {
-      border-radius: 10px;
-      background-color: #fff;
-      padding: 15px 24px;
-      display: flex;
-      justify-content: space-between;
-      .A1YtopRow {
-        display: flex;
-        align-items: center;
-        .anticon-arrow-left {
-          cursor: pointer;
-          font-size: 30px;
-          margin-right: 24px;
-        }
-        .A1YtopBack {
-          color: var(--themeColor);
-          font-size: 18px;
-          font-weight: 700;
-          margin-right: 24px;
-        }
-      }
-    }
-  }
-}
-
-// 新增 、编辑弹窗
-.A1Yadd {
-  :global {
-    .ant-modal-close {
-      display: none;
-    }
-    .ant-modal {
-      width: 1000px !important;
-    }
-    .ant-modal-body {
-      border-top: 1px solid #ccc;
-      padding-top: 15px !important;
-    }
-
-    .A1Ymain {
-      width: 100%;
-      height: 100%;
-      overflow-y: auto;
-      position: relative;
-
-      textarea {
-        min-height: 150px !important;
-      }
-
-      .A1fromRow {
-        position: relative;
-        width: 800px;
-
-        .A1_6Frow {
-          position: absolute;
-          left: 180px;
-          top: 5px;
-          color: #999;
-          font-size: 12px;
-        }
-      }
-
-      .ant-form {
-        width: 800px;
-        .formRow {
-          display: flex;
-
-          .formLeft {
-            position: relative;
-            top: 3px;
-            width: 67px;
-            text-align: right;
-
-            & > span {
-              color: #ff4d4f;
-            }
-          }
-
-          .formRight {
-            width: calc(100% - 67px);
-          }
-        }
-
-        .A1Ybtn {
-          position: absolute;
-          z-index: 10;
-          right: 20px;
-          top: 50%;
-          transform: translateY(-50%);
-        }
-      }
-    }
-  }
-}

+ 0 - 176
src/pages/A1manage/A1ying/index.tsx

@@ -1,176 +0,0 @@
-import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
-import styles from './index.module.scss'
-import { A1_APIdelById, A1_APIgetListById } from '@/store/action/A1manage'
-import { ArrowLeftOutlined } from '@ant-design/icons'
-import { Button, Input } from 'antd'
-import MyTable from '@/components/MyTable'
-import { A1YType } from '@/types'
-import MyPopconfirm from '@/components/MyPopconfirm'
-import { MessageFu } from '@/utils/message'
-import { A2tableY1, A2tableY2 } from '@/utils/tableData'
-import A1Yadd from './A1Yadd'
-
-type FromDataType = {
-  searchKey: string
-  pageNum: number
-  pageSize: number
-  bookId: number
-  type: 'img' | 'video'
-}
-
-type Props = {
-  bookId: number
-  type: 'img' | 'video'
-  name: string
-  closeFu: () => void
-}
-
-function A1ying({ bookId, type, closeFu, name }: Props) {
-  const [fromData, setFromData] = useState({} as FromDataType)
-
-  useEffect(() => {
-    setFromData({
-      searchKey: '',
-      pageNum: 1,
-      pageSize: 10,
-      bookId,
-      type
-    })
-  }, [bookId, type])
-
-  const getListFu = useCallback(async () => {
-    if (fromData.bookId) {
-      const res = await A1_APIgetListById(fromData)
-
-      if (res.code === 0) {
-        const obj = {
-          list: res.data.records,
-          total: res.data.total
-        }
-        setTableInfo(obj)
-      }
-    }
-  }, [fromData])
-
-  useEffect(() => {
-    getListFu()
-  }, [getListFu])
-
-  // 输入框的输入
-  const [inputKey, setInputKey] = useState(1)
-  const timeRef = useRef(-1)
-  const txtChangeFu = useCallback(
-    (e: React.ChangeEvent<HTMLInputElement>, key: 'searchKey') => {
-      clearTimeout(timeRef.current)
-      timeRef.current = window.setTimeout(() => {
-        setFromData({ ...fromData, [key]: e.target.value.replaceAll("'", ''), pageNum: 1 })
-      }, 500)
-    },
-    [fromData]
-  )
-
-  // 点击重置
-  const resetSelectFu = useCallback(() => {
-    setInputKey(Date.now())
-    setFromData({
-      searchKey: '',
-      pageNum: 1,
-      pageSize: 10,
-      bookId,
-      type
-    })
-  }, [bookId, type])
-
-  // 表格数据
-  const [tableInfo, setTableInfo] = useState({
-    list: [] as A1YType[],
-    total: 0
-  })
-
-  const delTableFu = useCallback(
-    async (id: number) => {
-      const res = await A1_APIdelById(id)
-      if (res.code === 0) {
-        MessageFu.success('删除成功!')
-        getListFu()
-      }
-    },
-    [getListFu]
-  )
-
-  const tableLastBtn = useMemo(() => {
-    return [
-      {
-        title: '操作',
-        render: (item: A1YType) => (
-          <>
-            <Button size='small' type='text' onClick={() => setAddId(item.id)}>
-              编辑
-            </Button>
-            <MyPopconfirm txtK='删除' onConfirm={() => delTableFu(item.id)} />
-          </>
-        )
-      }
-    ]
-  }, [delTableFu])
-
-  // 新增和编辑
-  const [addId, setAddId] = useState(0)
-
-  return (
-    <div className={styles.A1ying}>
-      <div className='A1Ytop'>
-        <div className='A1YtopRow'>
-          <ArrowLeftOutlined onClick={closeFu} />
-          <div className='A1YtopBack'>
-            {name} - {type === 'img' ? '影印资料' : '视频资料'}
-          </div>
-          <span>搜索:</span>
-          <Input
-            key={inputKey}
-            maxLength={20}
-            style={{ width: 300 }}
-            placeholder={type === 'img' ? '请输入正文' : '请输入标题或简介'}
-            allowClear
-            onChange={e => txtChangeFu(e, 'searchKey')}
-          />
-        </div>
-        <div className='A1YtopRow'>
-          <Button onClick={resetSelectFu}>重置</Button>&emsp;
-          <Button type='primary' onClick={() => setAddId(-1)}>
-            新增
-          </Button>
-        </div>
-      </div>
-
-      <div className='A1tableBox'>
-        <MyTable
-          classKey='A1y'
-          yHeight={625}
-          list={tableInfo.list}
-          columnsTemp={type === 'img' ? A2tableY1 : A2tableY2}
-          lastBtn={tableLastBtn}
-          pageNum={fromData.pageNum}
-          pageSize={fromData.pageSize}
-          total={tableInfo.total}
-          onChange={(pageNum, pageSize) => setFromData({ ...fromData, pageNum, pageSize })}
-        />
-      </div>
-
-      {addId ? (
-        <A1Yadd
-          type={type}
-          bookId={bookId}
-          id={addId}
-          closeFu={() => setAddId(0)}
-          addTableFu={resetSelectFu}
-          editTableFu={getListFu}
-        />
-      ) : null}
-    </div>
-  )
-}
-
-const MemoA1ying = React.memo(A1ying)
-
-export default MemoA1ying

+ 0 - 19
src/pages/A1manage/data.ts

@@ -1,19 +0,0 @@
-import { A1tableType } from '@/types'
-
-export type A1FromDataType = {
-  searchKey: string
-  num: string
-
-  storageArr: number[] | undefined
-  storageId: number | null
-  exhibitTypeId: number | null
-
-  pageNum: number
-  pageSize: number
-}
-
-export type A1EditInfoType = {
-  id: number
-  txt: '新增' | '编辑' | '查看' | ''
-  info?: A1tableType
-}

+ 0 - 271
src/pages/A1manage/index.tsx

@@ -1,271 +0,0 @@
-import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
-import styles from './index.module.scss'
-import { Button, Cascader, Input, Select } from 'antd'
-import { useDispatch, useSelector } from 'react-redux'
-import { A1EditInfoType, A1FromDataType } from './data'
-import { A1_APIdel, A1_APIgetList } from '@/store/action/A1manage'
-import { RootState } from '@/store'
-import { MessageFu } from '@/utils/message'
-import { A1tableType } from '@/types'
-import MyPopconfirm from '@/components/MyPopconfirm'
-import { A2_APIgetList1, A2_APIgetList2 } from '@/store/action/A2classify'
-import MyTable from '@/components/MyTable'
-import { A1tableC } from '@/utils/tableData'
-import A1add from './A1add'
-import A1ying from './A1ying'
-import A1Import from './A1Import'
-
-const fromDataBase: A1FromDataType = {
-  searchKey: '',
-  num: '',
-
-  storageArr: undefined,
-  storageId: null,
-  exhibitTypeId: null,
-  pageNum: 1,
-  pageSize: 10
-}
-
-function A1manage() {
-  const dispatch = useDispatch()
-
-  // 获取中图法分类 和 展示分类
-
-  useEffect(() => {
-    dispatch(A2_APIgetList1())
-    dispatch(A2_APIgetList2({ pageNum: 1, pageSize: 9999, searchKey: '' }))
-  }, [dispatch])
-
-  const { treeData: storageArr, tableInfo: exhibitTypeObj } = useSelector(
-    (state: RootState) => state.A2classify
-  )
-
-  const [fromData, setFromData] = useState(fromDataBase)
-
-  const getListFu = useCallback(() => {
-    const obj: A1FromDataType = {
-      ...fromData,
-      storageId: null
-    }
-    if (fromData.storageArr && fromData.storageArr.length)
-      obj.storageId = fromData.storageArr[fromData.storageArr.length - 1]
-
-    dispatch(A1_APIgetList(obj))
-  }, [dispatch, fromData])
-
-  useEffect(() => {
-    getListFu()
-  }, [getListFu])
-
-  const [inputKey, setInputKey] = useState(1)
-
-  // 输入框的输入
-  const timeRef = useRef(-1)
-  const txtChangeFu = useCallback(
-    (e: React.ChangeEvent<HTMLInputElement>, key: 'searchKey' | 'num') => {
-      clearTimeout(timeRef.current)
-      timeRef.current = window.setTimeout(() => {
-        setFromData({ ...fromData, [key]: e.target.value.replaceAll("'", ''), pageNum: 1 })
-      }, 500)
-    },
-    [fromData]
-  )
-
-  // 点击重置
-  const resetSelectFu = useCallback(() => {
-    setInputKey(Date.now())
-    setFromData({ ...fromDataBase })
-  }, [])
-
-  const tableInfo = useSelector((state: RootState) => state.A1manage.tableInfo)
-
-  const delTableFu = useCallback(
-    async (id: number) => {
-      const res = await A1_APIdel(id)
-      if (res.code === 0) {
-        MessageFu.success('删除成功!')
-        getListFu()
-      }
-    },
-    [getListFu]
-  )
-
-  const tableLastBtn = useMemo(() => {
-    return [
-      {
-        title: '操作',
-        render: (item: A1tableType) => (
-          <>
-            <Button
-              size='small'
-              type='text'
-              onClick={() => setEditInfo({ id: item.id, txt: '查看' })}
-            >
-              查看
-            </Button>
-            <Button
-              size='small'
-              type='text'
-              onClick={() => setEditInfo({ id: item.id, txt: '编辑' })}
-            >
-              编辑
-            </Button>
-            <Button
-              size='small'
-              type='text'
-              onClick={() => setBookYing({ bookId: item.id, type: 'img', name: item.name })}
-            >
-              影印
-            </Button>
-            <Button
-              size='small'
-              type='text'
-              onClick={() => setBookYing({ bookId: item.id, type: 'video', name: item.name })}
-            >
-              视频
-            </Button>
-
-            <MyPopconfirm txtK='删除' onConfirm={() => delTableFu(item.id)} />
-          </>
-        )
-      }
-    ]
-  }, [delTableFu])
-
-  //查看、新增、编辑
-  const [editInfo, setEditInfo] = useState<A1EditInfoType>({
-    id: 0,
-    txt: ''
-  })
-
-  // 影印和视频
-  const [bookYing, setBookYing] = useState<{ bookId: number; type: 'img' | 'video'; name: string }>(
-    {
-      bookId: 0,
-      type: 'img',
-      name: ''
-    }
-  )
-
-  // 批量导入
-  const [imp, setImp] = useState(false)
-
-  return (
-    <div className={styles.A1manage}>
-      <div className='pageTitle'>图书管理 {editInfo.id ? ` - ${editInfo.txt}` : ''}</div>
-
-      {/* 顶部筛选 */}
-      <div className='A1top'>
-        <div>
-          <div className='A1TopRow'>
-            <span>搜索:</span>
-            <Input
-              key={inputKey}
-              maxLength={20}
-              style={{ width: 192 }}
-              placeholder='请输入书名/作者/出版社'
-              allowClear
-              onChange={e => txtChangeFu(e, 'searchKey')}
-            />
-            &nbsp;
-            <Input
-              key={inputKey + 1}
-              maxLength={20}
-              style={{ width: 192 }}
-              placeholder='请输入完整ISBN编号'
-              allowClear
-              onChange={e => txtChangeFu(e, 'num')}
-            />
-          </div>
-
-          <div className='A1TopRow'>
-            <span>中图法分类:</span>
-            <Cascader
-              changeOnSelect
-              style={{ width: 250 }}
-              options={storageArr}
-              fieldNames={{ label: 'name', value: 'id', children: 'children' }}
-              value={fromData.storageArr}
-              placeholder='全部'
-              onChange={e =>
-                setFromData({
-                  ...fromData,
-                  storageArr: e as number[]
-                })
-              }
-            />
-          </div>
-          <div className='A1TopRow'>
-            <span>展示分类:</span>
-            <Select
-              allowClear
-              placeholder='全部'
-              style={{ width: 180 }}
-              value={fromData.exhibitTypeId}
-              fieldNames={{ label: 'name', value: 'id' }}
-              onChange={e => setFromData({ ...fromData, pageNum: 1, exhibitTypeId: e })}
-              options={exhibitTypeObj.list}
-            />
-          </div>
-        </div>
-        <div>
-          <Button onClick={() => setImp(true)}>批量导入</Button>&emsp;
-          <Button onClick={resetSelectFu}>重置</Button>&emsp;
-          <Button type='primary' onClick={() => setEditInfo({ id: -1, txt: '新增' })}>
-            新增
-          </Button>
-        </div>
-      </div>
-
-      {/* 表格主体 */}
-      <div className='A1tableBox'>
-        <MyTable
-          yHeight={625}
-          list={tableInfo.list}
-          columnsTemp={A1tableC}
-          lastBtn={tableLastBtn}
-          pageNum={fromData.pageNum}
-          pageSize={fromData.pageSize}
-          total={tableInfo.total}
-          onChange={(pageNum, pageSize) => setFromData({ ...fromData, pageNum, pageSize })}
-        />
-      </div>
-
-      {/* 新增 / 编辑 / 查看 */}
-      {editInfo.id ? (
-        <A1add
-          editInfo={editInfo}
-          closeFu={() => setEditInfo({ id: 0, txt: '新增' })}
-          addTableFu={resetSelectFu}
-          editTableFu={getListFu}
-          storageArr={storageArr}
-          exhibitTypeArr={exhibitTypeObj.list}
-        ></A1add>
-      ) : null}
-
-      {/* 影印和视频 */}
-      {bookYing.bookId ? (
-        <A1ying
-          bookId={bookYing.bookId}
-          type={bookYing.type}
-          name={bookYing.name}
-          closeFu={() => setBookYing({ bookId: 0, type: 'img', name: '' })}
-        />
-      ) : null}
-
-      {/* 批量导入 */}
-      {imp ? (
-        <A1Import
-          storageArr={storageArr}
-          exhibitTypeArr={exhibitTypeObj.list}
-          closeFu={() => setImp(false)}
-          addTableFu={resetSelectFu}
-        />
-      ) : null}
-    </div>
-  )
-}
-
-const MemoA1manage = React.memo(A1manage)
-
-export default MemoA1manage

+ 33 - 5
src/pages/A1manage/A1add/index.module.scss

@@ -12,7 +12,7 @@
   :global {
     .A1aMain {
       width: 100%;
-      height: 100%;
+      height: calc(100% - 80px);
       overflow-y: auto;
 
       textarea {
@@ -34,10 +34,29 @@
 
       .ant-form {
         width: 800px;
+        display: flex;
+        flex-direction: column;
+        gap: 30px;
 
         // .ant-input-affix-wrapper{
         //   width: 800px;
         // }
+
+        .tude {
+          margin-left: 46px;
+          display: flex;
+          gap: 10px;
+          .ant-form-item {
+            width: 50%;
+            .ant-row {
+              justify-content: space-between;
+              .ant-form-item-control {
+                max-width: 320px;
+              }
+            }
+          }
+        }
+
         .formRow {
           display: flex;
 
@@ -58,11 +77,20 @@
         }
 
         .A1abtn {
-          position: absolute;
+          display: flex;
+          align-items: center;
+          width: 100%;
+          height: 80px;
+          position: fixed;
+          bottom: 0;
+          background: #fff;
           z-index: 10;
-          left: 1200px;
-          top: 50%;
-          transform: translateY(-50%);
+
+          .A1abtnBox {
+            display: flex;
+            gap: 20px;
+            padding-left: 100px;
+          }
         }
       }
     }

+ 263 - 0
src/pages/A1scene/A1add/index.tsx

@@ -0,0 +1,263 @@
+import React, { useCallback, useEffect, useRef, useState } from 'react'
+import styles from './index.module.scss'
+import classNames from 'classnames'
+import { A1EditInfoType } from '../data'
+import { Button, Form, FormInstance, Input, Select } from 'antd'
+import { A1_APIgetInfo, A1_APIsave } from '@/store/action/A1scene'
+import { MessageFu } from '@/utils/message'
+import ZupOne from '@/components/ZupOne'
+import ImgUp from '../A1imgUp'
+import { A1AddType, A1tbType } from '@/types'
+import MyPopconfirm from '@/components/MyPopconfirm'
+
+type Props = {
+  editInfo: A1EditInfoType
+  closeFu: () => void
+  addTableFu: () => void
+  editTableFu: () => void
+}
+
+function A1add({ editInfo, closeFu, addTableFu, editTableFu }: Props) {
+  // 表单的ref
+  const FormBoxRef = useRef<FormInstance>(null)
+
+  // 音频的ref
+  const ZupAudioRef = useRef<any>(null)
+  const ZupTypesRef = useRef<any>(null)
+
+  // 回显数据的方法调用
+  const dataShow = useCallback((info: A1tbType) => {
+    FormBoxRef.current?.setFieldsValue({ ...info })
+    // 设置图片组
+    const imgFileList = info.files
+      ? info.files.map((v: any) => ({
+          fileName: v.fileName,
+          filePath: v.filePath,
+          id: v.id,
+          type: 'img'
+        }))
+      : []
+    ZupTypesRef.current?.setFileComFileFu({
+      fileList: [...imgFileList],
+      type: ['img']
+    })
+
+    // 设置音频
+    ZupAudioRef.current?.setFileComFileFu({
+      filename: info.audioName,
+      thUrl: info.audioPath,
+      url: info.audioPath
+    })
+  }, [])
+
+  // 编辑 进入页面 获取信息
+  const getInfoFu = useCallback(
+    async (id: number) => {
+      if (editInfo.info) dataShow(editInfo.info)
+      else {
+        const res = await A1_APIgetInfo(id)
+        if (res.code === 0) {
+          dataShow(res.data)
+        }
+      }
+    },
+    [dataShow, editInfo.info]
+  )
+
+  // 附件 是否 已经点击过确定
+  const [fileCheck, setFileCheck] = useState(false)
+
+  // 编辑填入数据
+  useEffect(() => {
+    if (editInfo.id > 0) {
+      getInfoFu(editInfo.id)
+    }
+  }, [editInfo.id, getInfoFu])
+
+  // 没有通过校验
+  const onFinishFailed = useCallback(() => {
+    setFileCheck(true)
+  }, [])
+
+  //  通过校验点击确定
+  const onFinish = useCallback(
+    async (values: any) => {
+      setFileCheck(true)
+      const { filename, url } = ZupAudioRef.current?.fileComFileResFu()
+      const { fileList, sonIsOk } = ZupTypesRef.current?.fileComFileResFu()
+      if (sonIsOk) return MessageFu.warning('请上传图片!')
+
+      // 提交参数
+      const param: A1AddType = {
+        ...values,
+        audioName: filename || '',
+        audioPath: url || '',
+        fileIds: fileList.img.map((v: any) => v.id).join(','),
+        thumb: fileList.img[0].filePath
+      }
+
+      const res: any =
+        editInfo.txt === '新增'
+          ? await A1_APIsave(param)
+          : await A1_APIsave({ ...param, id: editInfo.id })
+
+      if (res.msg === '名称不能重复') {
+        return FormBoxRef.current?.setFields([{ name: 'name', errors: ['已存在相同名称的景点'] }])
+      }
+
+      if (res.code === 0) {
+        MessageFu.success(`${editInfo.txt}成功!`)
+        editInfo.id > 0 ? editTableFu() : addTableFu()
+        closeFu()
+      }
+    },
+    [addTableFu, closeFu, editInfo.id, editInfo.txt, editTableFu]
+  )
+
+  return (
+    <div className={styles.A1add}>
+      <div className={classNames('A1aMain')}>
+        <Form
+          ref={FormBoxRef}
+          name='basic'
+          labelCol={{ span: 3 }}
+          onFinish={onFinish}
+          onFinishFailed={onFinishFailed}
+          autoComplete='off'
+          scrollToFirstError
+        >
+          <Form.Item label='名称' name='name' rules={[{ required: true, message: '请输入名称!' }]}>
+            <Input
+              readOnly={editInfo.txt === '查看'}
+              placeholder='请输入内容,不超过10个字'
+              maxLength={10}
+              showCount
+            />
+          </Form.Item>
+
+          <Form.Item label='类型' name='type' rules={[{ required: true, message: '请选择类型!' }]}>
+            <Select
+              disabled={editInfo.txt === '查看'}
+              placeholder='请选择景点类型'
+              options={[
+                { label: '历史文化', value: '历史文化' },
+                { label: '自然探索', value: '自然探索' },
+                { label: '亲子休闲', value: '亲子休闲' },
+                { label: '城市烟火', value: '城市烟火' },
+                { label: '交通住宿', value: '交通住宿' },
+                { label: '政府驻地', value: '政府驻地' }
+              ]}
+            />
+          </Form.Item>
+
+          <Form.Item label='地址' name='address'>
+            <Input
+              readOnly={editInfo.txt === '查看'}
+              placeholder='请输入内容,不超过50个字'
+              maxLength={50}
+              showCount
+            />
+          </Form.Item>
+
+          <Form.Item label='简介' name='intro'>
+            <Input.TextArea
+              readOnly={editInfo.txt === '查看'}
+              placeholder='请输入内容,不超过500个字'
+              maxLength={500}
+              showCount
+            />
+          </Form.Item>
+
+          <Form.Item
+            label={
+              <>
+                <span style={{ color: 'red' }}>*&nbsp;</span> 图片
+              </>
+            }
+            name='files'
+          >
+            <ImgUp
+              ref={ZupTypesRef}
+              imgLength={20}
+              isLook={editInfo.txt === '查看'}
+              fileCheck={fileCheck}
+              dirCode={'A1scene'}
+              myUrl='cms/site/upload'
+            />
+          </Form.Item>
+
+          <Form.Item label='音频' name='audioPath'>
+            <ZupOne
+              ref={ZupAudioRef}
+              fileCheck={fileCheck}
+              size={5}
+              isLook={editInfo.txt === '查看'}
+              dirCode={'A1scene'}
+              myUrl='cms/site/upload'
+              format={['audio/mpeg', 'audio/mp3']}
+              formatTxt='mp3/wav'
+              checkTxt=''
+              upTxt='最多可上传1个音频文件'
+              myType='audio'
+            />
+          </Form.Item>
+
+          <Form.Item label='VR全景' name='vrUrl'>
+            <Input
+              readOnly={editInfo.txt === '查看'}
+              placeholder='请输入链接,不超过100个字'
+              maxLength={100}
+              showCount
+            />
+          </Form.Item>
+
+          <Form.Item label='模型' name='modelUrl'>
+            <Input
+              readOnly={editInfo.txt === '查看'}
+              placeholder='请输入链接,不超过100个字'
+              maxLength={100}
+              showCount
+            />
+          </Form.Item>
+          <div className='tude'>
+            <Form.Item label='经度' name='lon' rules={[{ required: true, message: '请输入经度!' }]}>
+              <Input readOnly={editInfo.txt === '查看'} placeholder='请输入数字' type='number' />
+            </Form.Item>
+
+            <Form.Item label='纬度' name='lat' rules={[{ required: true, message: '请输入纬度!' }]}>
+              <Input readOnly={editInfo.txt === '查看'} placeholder='请输入数字' type='number' />
+            </Form.Item>
+          </div>
+
+          <Form.Item
+            label='权重'
+            name='weight'
+            rules={[{ required: true, message: '请输入权重!' }]}
+          >
+            <Input
+              type='number'
+              readOnly={editInfo.txt === '查看'}
+              placeholder='请输入1-999的数字,数字越大,缩放地图时的排序越靠前。'
+              max={999}
+              min={1}
+            />
+          </Form.Item>
+
+          {/* 确定和取消按钮 */}
+          <Form.Item className='A1abtn'>
+            <div className='A1abtnBox'>
+              <Button type='primary' htmlType='submit'>
+                提交
+              </Button>
+              <MyPopconfirm txtK='取消' onConfirm={closeFu} />
+            </div>
+          </Form.Item>
+        </Form>
+      </div>
+    </div>
+  )
+}
+
+const MemoA1add = React.memo(A1add)
+
+export default MemoA1add

+ 213 - 0
src/pages/A1scene/A1imgUp/index.module.scss

@@ -0,0 +1,213 @@
+.ZupTypes {
+  padding-top: 3px;
+
+  :global {
+    .ZTboxTit {
+      margin-left: 10px;
+      font-size: 14px;
+      color: rgb(126, 124, 124);
+      position: relative;
+      top: 4px;
+    }
+
+    .ZTbox {
+      margin-top: 20px;
+      display: flex;
+
+      .ZTbox1 {
+        position: relative;
+        top: 3px;
+        width: 60px;
+
+        & > span {
+          color: #ff4d4f;
+        }
+      }
+
+      .ZTbox2 {
+        width: calc(100% - 60px);
+        margin-left: 5px;
+        display: flex;
+        font-size: 16px;
+        align-items: center;
+
+        .ZTbox2Look {
+          margin-left: 20px;
+          cursor: pointer;
+        }
+
+        .ZTbox2Down {
+          margin-left: 15px;
+          color: black;
+        }
+
+        .ZTbox2X {
+          cursor: pointer;
+          margin-left: 15px;
+        }
+      }
+    }
+
+    // 图片
+    .ZTboxImgMain {
+      .ZTboxImgBox {
+        display: flex;
+
+        .ZTbox1 {
+          position: relative;
+          top: 3px;
+          width: 60px;
+
+          & > span {
+            color: #ff4d4f;
+          }
+        }
+
+        .ZTbox1Img {
+          width: calc(100% - 60px);
+          display: flex;
+          flex-wrap: wrap;
+
+          .ZTbox1ImgIcon {
+            margin-right: 20px;
+            color: #a6a6a6;
+            border-radius: 3px;
+            cursor: pointer;
+            font-size: 30px;
+            width: 100px;
+            height: 100px;
+            border: 1px dashed #797979;
+            display: flex;
+            justify-content: center;
+            align-items: center;
+          }
+
+          .ZTbox1ImgRow {
+            // content-visibility:auto;
+            margin-right: 20px;
+            width: 100px;
+            height: 125px;
+            position: relative;
+            margin-bottom: 20px;
+            cursor: move;
+            position: relative;
+
+            // 第一张作为封面
+            .ZTbox1ImgRowCover {
+              font-size: 12px;
+              line-height: 22px;
+              position: absolute;
+              left: 0;
+              top: 0;
+              width: 100%;
+              height: 24px;
+              background-color: rgba(0, 0, 0, 0.8);
+              color: #fff;
+              text-align: center;
+              pointer-events: none;
+            }
+
+            // 修改图片名字
+            .ZTbox1ImgRowName {
+              font-size: 12px;
+              line-height: 22px;
+              position: absolute;
+              left: 0;
+              bottom: 25px;
+              width: 100%;
+              cursor: pointer;
+              height: 24px;
+              padding: 0 3px;
+              background-color: rgba(0, 0, 0, 0.8);
+              color: #fff;
+              text-align: center;
+              overflow: hidden;
+              text-overflow: ellipsis;
+              white-space: nowrap;
+
+              &:hover {
+                color: var(--themeColor);
+              }
+            }
+
+            .ZTbox1ImgRowIcon {
+              width: 100%;
+              background-color: rgba(0, 0, 0, 0.6);
+              color: #fff;
+              display: flex;
+              justify-content: space-around;
+              font-size: 16px;
+
+              a {
+                color: #fff !important;
+              }
+            }
+
+            .ZTbox1ImgRowX {
+              cursor: pointer;
+              position: absolute;
+              right: -10px;
+              top: -10px;
+              z-index: 99;
+              background-color: rgba(0, 0, 0, 0.8);
+              width: 20px;
+              height: 20px;
+              border-radius: 50%;
+              font-size: 16px;
+              color: #fff;
+              display: flex;
+              justify-content: center;
+              align-items: center;
+            }
+          }
+        }
+      }
+    }
+
+    .ZcheckTxt {
+      position: relative;
+      overflow: hidden;
+      opacity: 0;
+      transition: top 0.2s;
+      color: #ff4d4f;
+      top: -10px;
+    }
+
+    .ZcheckTxtAc {
+      top: 2px;
+      opacity: 1;
+    }
+  }
+}
+
+// 查看情况
+.ZupTypesLook {
+  :global {
+    .ZTbox1ImgRowName {
+      cursor: default !important;
+      color: #fff !important;
+    }
+
+    .ZTbox1ImgRow {
+      cursor: default !important;
+    }
+
+    .ZTbox1ImgRowX {
+      display: none !important;
+    }
+  }
+}
+
+// 修改图片名字的弹窗
+.ZupTypesMo {
+  :global {
+    .ant-modal-close {
+      display: none;
+    }
+
+    .ZupTypesMoBtn {
+      margin-top: 24px;
+      text-align: center;
+    }
+  }
+}

+ 341 - 0
src/pages/A1scene/A1imgUp/index.tsx

@@ -0,0 +1,341 @@
+import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
+import styles from './index.module.scss'
+import { forwardRef, useImperativeHandle } from 'react'
+import { PlusOutlined, CloseOutlined, DownloadOutlined, EyeOutlined } from '@ant-design/icons'
+import { MessageFu } from '@/utils/message'
+import { API_upFile } from '@/store/action/layout'
+import { fileDomInitialFu } from '@/utils/domShow'
+import store from '@/store'
+import ImageLazy from '@/components/ImageLazy'
+import classNames from 'classnames'
+// import { A2_APIchangeImgName } from "@/store/action/A2exhibition";
+import MyPopconfirm from '@/components/MyPopconfirm'
+
+export type FileListType = {
+  fileName: string
+  thumb?: string
+  filePath: string
+  id: number
+  type: 'model' | 'img' | 'audio' | 'video'
+  imgName: string
+}
+
+type Props = {
+  ref: any //当前自己的ref,给父组件调用
+  fileCheck: boolean //有没有点击过确定
+  dirCode: string //文件的code码
+  myUrl: string //请求地址
+  isLook?: boolean //是不是查看
+  modelSize?: number //模型文件大小限制
+  imgSize?: number //图片大小限制
+  imgLength?: number //图片数量限制
+  audioSize?: number //音频大小限制
+  videoSize?: number //视频大小限制
+  videoTit?: string //视频上传的提示语
+  isTypeShow?: boolean //默认就选中(只有一个类型的时候)
+  isUpName?: boolean //是否能修改图片名字
+  lastImgTxt?: string //加载最后面的上传提示
+  oneIsCover?: boolean //是否将第一张作为封面
+}
+
+function ImgUp(
+  {
+    fileCheck,
+    dirCode,
+    myUrl,
+    isLook = false,
+    modelSize = 500,
+    imgSize = 5,
+    imgLength = 9,
+    audioSize = 10,
+    videoSize = 500,
+    videoTit = '',
+    isTypeShow = false,
+    isUpName = false,
+    lastImgTxt = '',
+    oneIsCover = false
+  }: Props,
+  ref: any
+) {
+  // 筛选
+  const [typeCheck, setTypeCheck] = useState<string[]>(['img'])
+
+  // 上传附件的信息
+  const [fileList, setFileList] = useState({
+    img: [] as FileListType[]
+  })
+
+  // 附件信息的校验,不满足返回 true
+  const fileCheckFu = useMemo(() => {
+    let flag = false
+    if (typeCheck.length === 0) flag = true
+    if (typeCheck.includes('img') && fileList.img.length === 0) flag = true
+    return flag
+  }, [fileList, typeCheck])
+
+  // 点击上传附件按钮
+  const myInput = useRef<HTMLInputElement>(null)
+
+  const [fileOneType, setFileOneType] = useState('')
+
+  useEffect(() => {
+    if (fileOneType) myInput.current?.click()
+  }, [fileOneType])
+
+  const upFileFu = useCallback((type: string) => {
+    setFileOneType('')
+    window.setTimeout(() => {
+      setFileOneType(type)
+    }, 100)
+  }, [])
+
+  // 上传附件的处理函数
+  const handeUpPhoto2 = useCallback(
+    async (e: React.ChangeEvent<HTMLInputElement>) => {
+      if (e.target.files) {
+        // 拿到files信息
+        const filesInfo = e.target.files[0]
+
+        let anType = ['image/jpeg', 'image/png']
+        let anTit1 = '只支持png、jpg格式!'
+        let anTit2 = `最大支持${imgSize}M!`
+        let anSize = imgSize * 1024 * 1024
+
+        // 校验格式
+        if (!anType.includes(filesInfo.type)) {
+          e.target.value = ''
+          return MessageFu.warning(anTit1)
+        }
+
+        // 校验大小
+        if (filesInfo.size > anSize) {
+          e.target.value = ''
+          return MessageFu.warning(anTit2)
+        }
+        // 创建FormData对象
+        const fd = new FormData()
+        // 把files添加进FormData对象(‘photo’为后端需要的字段)
+        fd.append('type', fileOneType)
+        fd.append('dirCode', dirCode)
+        fd.append('isDb', 'true')
+
+        //初始图片 fileName为:未命名
+        if (isUpName) {
+          fd.append('isDefaultName', 'false')
+        }
+
+        fd.append('file', filesInfo)
+
+        if (fileOneType === 'img' && filesInfo.size > 1 * 1024 * 1024) {
+          // 开启压缩图片
+          fd.append('isCompress', 'true')
+        }
+
+        e.target.value = ''
+
+        const res = await API_upFile(fd, myUrl)
+
+        try {
+          if (res.code === 0) {
+            MessageFu.success('上传成功!')
+            console.log(res.data, fileList)
+            if (fileOneType === 'img')
+              setFileList({
+                ...fileList,
+                img: [
+                  ...fileList.img,
+                  {
+                    fileName: res.data.fileName,
+                    filePath: res.data.filePath,
+                    id: res.data.id,
+                    type: 'img',
+                    imgName: '未命名'
+                  }
+                ]
+              })
+          }
+
+          fileDomInitialFu()
+        } catch (error) {
+          fileDomInitialFu()
+        }
+      }
+    },
+    [dirCode, fileList, fileOneType, imgSize, isUpName, myUrl]
+  )
+
+  // 附件图片的拖动
+  const [dragImg, setDragImg] = useState<any>(null)
+
+  const handleDragOver = useCallback(
+    (e: React.DragEvent<HTMLDivElement>, item: FileListType) => {
+      if (isLook) return
+      e.dataTransfer.dropEffect = 'move'
+    },
+    [isLook]
+  )
+
+  const handleDragEnter = useCallback(
+    (e: React.DragEvent<HTMLDivElement>, item: FileListType) => {
+      if (isLook) return
+
+      e.dataTransfer.effectAllowed = 'move'
+      if (item === dragImg) return
+      const newItems = [...fileList.img] //拷贝一份数据进行交换操作。
+      const src = newItems.indexOf(dragImg) //获取数组下标
+      const dst = newItems.indexOf(item)
+      newItems.splice(dst, 0, ...newItems.splice(src, 1)) //交换位置
+      setFileList({ ...fileList, img: newItems })
+    },
+    [dragImg, fileList, isLook]
+  )
+
+  // 删除某一张图片
+  const delImgListFu = useCallback(
+    (id: number) => {
+      const newItems = fileList.img.filter(v => v.id !== id)
+      setFileList({ ...fileList, img: newItems })
+    },
+    [fileList]
+  )
+
+  // ------------让父组件调用的 回显
+  const setFileComFileFu = useCallback((info: any) => {
+    if (info.type) setTypeCheck(info.type)
+
+    if (info.fileList && info.fileList.length) {
+      const data: FileListType[] = info.fileList
+      console.log('-xsxxas', data)
+      const obj = {
+        model: {} as FileListType,
+        img: [] as FileListType[],
+        audio: {} as FileListType,
+        video: {} as FileListType
+      }
+
+      data.forEach(v => {
+        if (v.type === 'img') {
+          obj.img.push({ ...v, imgName: v.fileName })
+        } else obj[v.type!] = v
+      })
+      setFileList(obj)
+    }
+  }, [])
+
+  // --------------让父组件调用的返回 附件 信息
+  const fileComFileResFu = useCallback(() => {
+    let coverUrl = ''
+    const fileIds: number[] = []
+    if (typeCheck.includes('img')) {
+      fileList.img.forEach((v, i) => {
+        if (v.id) {
+          fileIds.push(v.id)
+          if (oneIsCover && i === 0) {
+            // 返回 第一张图的url 作为封面
+            coverUrl = v.thumb || v.filePath
+          }
+        }
+      })
+    }
+    return {
+      sonType: typeCheck,
+      sonFileIds: fileIds,
+      sonIsOk: fileCheckFu,
+      fileList,
+      coverUrl
+    }
+  }, [fileCheckFu, fileList, oneIsCover, typeCheck])
+
+  // 可以让父组件调用子组件的方法
+  useImperativeHandle(ref, () => ({
+    setFileComFileFu,
+    fileComFileResFu
+  }))
+
+  return (
+    <div className={classNames(styles.ZupTypes)}>
+      <input
+        id='upInput'
+        type='file'
+        accept={'.png,.jpg,.jpeg'}
+        ref={myInput}
+        onChange={e => handeUpPhoto2(e)}
+      />
+      {/* -----------图片 */}
+      <div className='ZTboxImgMain' hidden={!typeCheck.includes('img')}>
+        <div className='ZTboxImgBox'>
+          <div className='ZTbox1Img' style={{ width: isTypeShow ? '100%' : '' }}>
+            <div
+              hidden={(!!fileList.img.length && fileList.img.length >= imgLength) || isLook}
+              className='ZTbox1ImgIcon'
+              onClick={() => upFileFu('img')}
+            >
+              <PlusOutlined rev={undefined} />
+            </div>
+            {fileList.img.map((v, i) => (
+              <div
+                className='ZTbox1ImgRow'
+                key={v.id}
+                draggable='true'
+                onDragStart={() => setDragImg(v)}
+                onDragOver={e => handleDragOver(e, v)}
+                onDragEnter={e => handleDragEnter(e, v)}
+                onDragEnd={() => setDragImg(null)}
+              >
+                {v.thumb || v.filePath ? (
+                  <ImageLazy noLook={true} width={100} height={100} src={v.thumb || v.filePath} />
+                ) : null}
+
+                {oneIsCover && i === 0 ? <div className='ZTbox1ImgRowCover'>封面</div> : null}
+
+                <div className='ZTbox1ImgRowIcon'>
+                  <EyeOutlined
+                    onClick={() =>
+                      store.dispatch({
+                        type: 'layout/lookBigImg',
+                        payload: {
+                          url: v.filePath,
+                          show: true
+                        }
+                      })
+                    }
+                    rev={undefined}
+                  />
+                  <a href={v.filePath} download target='_blank' rel='noreferrer'>
+                    <DownloadOutlined rev={undefined} />
+                  </a>
+                </div>
+
+                {!isLook && (
+                  <MyPopconfirm
+                    txtK='删除'
+                    onConfirm={() => delImgListFu(v.id!)}
+                    Dom={<CloseOutlined className='ZTbox1ImgRowX' rev={undefined} />}
+                  />
+                )}
+              </div>
+            ))}
+          </div>
+        </div>
+
+        <div className='ZTboxTit' hidden={isLook}>
+          {fileList.img.length && fileList.img.length >= 2 ? (
+            <>
+              按住鼠标可拖动图片调整顺序。
+              <br />
+            </>
+          ) : null}
+          最多可上传{imgLength}张图片,第一张作为封面。支持jpg/jpeg/png格式,不超过5M
+          {lastImgTxt}
+        </div>
+      </div>
+
+      {/* 最后的提示 */}
+      <div className={classNames('ZcheckTxt', fileCheck && fileCheckFu ? 'ZcheckTxtAc' : '')}>
+        请最少上传一张图片!
+      </div>
+    </div>
+  )
+}
+
+export default forwardRef(ImgUp)

+ 7 - 0
src/pages/A1scene/data.ts

@@ -0,0 +1,7 @@
+import { A1tbType } from '@/types'
+
+export type A1EditInfoType = {
+  id: number
+  txt: '新增' | '编辑' | '查看' | ''
+  info?: A1tbType
+}

+ 11 - 7
src/pages/A1manage/index.module.scss

@@ -1,4 +1,4 @@
-.A1manage {
+.A1banner {
   position: relative;
   :global {
     .A1top {
@@ -7,17 +7,21 @@
       padding: 15px 24px;
       display: flex;
       justify-content: space-between;
-      & > div {
+      gap: 20px;
+      .A1topLeft {
         display: flex;
-        .A1TopRow {
+        .rowItem {
+          margin-left: 20px;
+          width: 200px;
           display: flex;
           align-items: center;
-          margin-right: 20px;
-          .ant-select-selection-placeholder {
-            color: black;
-          }
+          gap: 10px;
         }
       }
+      .A1topRight {
+        display: flex;
+        gap: 20px;
+      }
     }
     .A1tableBox {
       border-radius: 10px;

+ 175 - 0
src/pages/A1scene/index.tsx

@@ -0,0 +1,175 @@
+import React, { useCallback, useEffect, useMemo, useState } from 'react'
+import styles from './index.module.scss'
+import { Button, Select, Input } from 'antd'
+import { useDispatch, useSelector } from 'react-redux'
+import { A1EditInfoType } from './data'
+import { A1_APIdel, A1_APIgetList } from '@/store/action/A1scene'
+import { RootState } from '@/store'
+import { MessageFu } from '@/utils/message'
+import { A1tbType } from '@/types'
+import MyPopconfirm from '@/components/MyPopconfirm'
+import MyTable from '@/components/MyTable'
+import { A1tableC } from '@/utils/tableData'
+import A1add from './A1add'
+
+const pageDataBase = {
+  pageNum: 1,
+  pageSize: 10
+}
+
+function A1scene() {
+  const dispatch = useDispatch()
+
+  const [pageData, setPageData] = useState(pageDataBase)
+  const [title, setTitle] = useState('')
+  const [type, setType] = useState('')
+
+  const getListFu = useCallback(() => {
+    dispatch(A1_APIgetList({ ...pageData, searchKey: title, type }))
+  }, [dispatch, pageData, title, type])
+
+  useEffect(() => {
+    getListFu()
+  }, [getListFu])
+
+  // 点击重置
+  const resetSelectFu = useCallback(() => {
+    setPageData({ ...pageDataBase })
+  }, [])
+
+  const tableInfo = useSelector((state: RootState) => state.A1scene.tableInfo)
+
+  const delTableFu = useCallback(
+    async (id: number) => {
+      const res = await A1_APIdel(id)
+      if (res.code === 0) {
+        MessageFu.success('删除成功!')
+        getListFu()
+      }
+    },
+    [getListFu]
+  )
+
+  const tableLastBtn = useMemo(() => {
+    return [
+      {
+        title: '操作',
+        render: (item: A1tbType) => (
+          <>
+            <Button
+              size='small'
+              type='text'
+              onClick={() => setEditInfo({ id: item.id, txt: '查看' })}
+            >
+              查看
+            </Button>
+            <Button
+              size='small'
+              type='text'
+              onClick={() => setEditInfo({ id: item.id, txt: '编辑' })}
+            >
+              编辑
+            </Button>
+            <MyPopconfirm txtK='删除' onConfirm={() => delTableFu(item.id)} />
+          </>
+        )
+      }
+    ]
+  }, [delTableFu])
+
+  //新增、编辑
+  const [editInfo, setEditInfo] = useState<A1EditInfoType>({
+    id: 0,
+    txt: ''
+  })
+
+  return (
+    <>
+      <div className={styles.A1banner}>
+        <div className='pageTitle'>景点设置 {editInfo.id ? ` - ${editInfo.txt}` : ''}</div>
+
+        {/* 顶部筛选 */}
+        <div className='A1top'>
+          <div className='A1topLeft'>
+            <Input
+              style={{ width: 200 }}
+              placeholder='请输入景点名称或简介'
+              onChange={e => setTitle(e.target.value)}
+              value={title}
+              maxLength={10}
+            />
+            <div className='rowItem'>
+              <Select
+                style={{ width: 150 }}
+                placeholder='请选择景点类型'
+                options={[
+                  { label: '全部', value: '' },
+                  { label: '历史文化', value: '历史文化' },
+                  { label: '自然探索', value: '自然探索' },
+                  { label: '亲子休闲', value: '亲子休闲' },
+                  { label: '城市烟火', value: '城市烟火' },
+                  { label: '交通住宿', value: '交通住宿' },
+                  { label: '政府驻地', value: '政府驻地' }
+                ]}
+                value={type}
+                onChange={value => setType(value)}
+              />
+            </div>
+          </div>
+          <div className='A1topRight'>
+            <Button
+              onClick={() => {
+                resetSelectFu()
+                setTitle('')
+                setType('')
+              }}
+            >
+              重置
+            </Button>
+            <Button
+              type='primary'
+              onClick={() => {
+                if (tableInfo.total >= 200) {
+                  MessageFu.error('最多200个景点')
+                  return
+                }
+                setEditInfo({ id: -1, txt: '新增' })
+              }}
+            >
+              新增
+            </Button>
+          </div>
+        </div>
+
+        {/* 表格主体 */}
+        <div className='A1tableBox'>
+          <MyTable
+            myKey='id'
+            yHeight={625}
+            list={tableInfo.list}
+            columnsTemp={A1tableC}
+            lastBtn={tableLastBtn}
+            pageNum={pageData.pageNum}
+            pageSize={pageData.pageSize}
+            total={tableInfo.total}
+            onChange={(pageNum, pageSize) => setPageData({ ...pageData, pageNum, pageSize })}
+          />
+        </div>
+
+        {/* 新增 / 编辑 */}
+        {editInfo.id ? (
+          <A1add
+            editInfo={editInfo}
+            closeFu={() => setEditInfo({ id: 0, txt: '新增' })}
+            addTableFu={resetSelectFu}
+            editTableFu={getListFu}
+          ></A1add>
+        ) : null}
+      </div>
+    </>
+  )
+}
+
+const MemoA1scene = React.memo(A1scene)
+
+export default MemoA1scene

+ 0 - 202
src/pages/A2classify/A2add.tsx

@@ -1,202 +0,0 @@
-import React, { useCallback, useEffect, useRef, useState } from 'react'
-import styles from './index.module.scss'
-import { Button, Cascader, Form, FormInstance, Input, InputNumber, Modal } from 'antd'
-import MyPopconfirm from '@/components/MyPopconfirm'
-import { useSelector } from 'react-redux'
-import { RootState } from '@/store'
-import { A2_APIgetInfo1, A2_APIsave1 } from '@/store/action/A2classify'
-import { MessageFu } from '@/utils/message'
-import { A2TreeType } from '@/types'
-
-export type A2AddInfoType = {
-  id: number
-  txt: '新增' | '编辑'
-  acInfo: A2TreeType
-}
-
-type Props = {
-  addInfo: A2AddInfoType
-  addFu: () => void
-  closeFu: () => void
-}
-
-function A2add({ addInfo, addFu, closeFu }: Props) {
-  const treeData = useSelector((state: RootState) => state.A2classify.treeData)
-
-  // 级联选择器改变的时候 筛选当前级联的 信息出来
-  const [acCardInfo, setAcCardInfo] = useState({} as A2TreeType)
-  const [parentIdArr, setParentIdArr] = useState<number[] | null>(null)
-
-  // useEffect(() => {
-  //   console.log(acCardInfo, parentIdArr)
-  // }, [acCardInfo, parentIdArr])
-
-  useEffect(() => {
-    setAcCardInfo(addInfo.acInfo)
-
-    let ids: number[] | null = addInfo.acInfo.id ? [addInfo.acInfo.id] : null
-    if (addInfo.acInfo.ancestor)
-      ids = [...addInfo.acInfo.ancestor.split(',').map(v => Number(v)), addInfo.acInfo.id]
-
-    const idsRes = ids
-    if (ids && ids.length >= 1 && addInfo.txt === '编辑') {
-      ids.pop()
-    }
-
-    setParentIdArr(idsRes)
-  }, [addInfo.acInfo, addInfo.txt])
-
-  const cardChange = useCallback((aa: any, bb: any) => {
-    setParentIdArr(aa)
-
-    if (bb && bb.length) setAcCardInfo(bb[bb.length - 1])
-    else setAcCardInfo({} as A2TreeType)
-  }, [])
-
-  const getInfoFu = useCallback(async (id: number) => {
-    const res = await A2_APIgetInfo1(id)
-    if (res.code === 0) {
-      FormBoxRef.current?.setFieldsValue({
-        ...res.data
-      })
-    }
-  }, [])
-  useEffect(() => {
-    if (addInfo.txt === '编辑') getInfoFu(addInfo.id)
-    else {
-      FormBoxRef.current?.setFieldsValue({
-        sort: 999
-      })
-    }
-  }, [addInfo.id, addInfo.txt, getInfoFu])
-
-  // 设置表单初始数据(区分编辑和新增)
-  const FormBoxRef = useRef<FormInstance>(null)
-
-  // 没有通过校验
-  const onFinishFailed = useCallback(() => {
-    // return MessageFu.warning("有表单不符号规则!");
-  }, [])
-
-  // 通过校验点击确定
-  const onFinish = useCallback(
-    async (values: any) => {
-      let ancestor = ''
-      let parentId: number | null = null
-
-      if (parentIdArr && parentIdArr.length >= 5 && addInfo.txt === '新增')
-        return MessageFu.warning('最多支持五级!')
-
-      if (acCardInfo) parentId = addInfo.txt === '编辑' ? acCardInfo.parentId : acCardInfo.id
-      if (parentIdArr && parentId) ancestor = parentIdArr.filter(v => v !== addInfo.id).join(',')
-
-      let level = 1
-      if (parentIdArr) {
-        level = addInfo.txt === '新增' ? acCardInfo.level + 1 : acCardInfo.level
-      }
-      const obj = {
-        ...values,
-        id: addInfo.id > 0 ? addInfo.id : null,
-        ancestor,
-        level,
-        parentId
-      }
-      // console.log(123, obj)
-      // if (1 + 1 === 2) {
-      //   return
-      // }
-
-      const res = await A2_APIsave1(obj)
-
-      if (res.code === 0) {
-        MessageFu.success(addInfo.txt + '成功!')
-        addFu()
-        closeFu()
-      }
-    },
-    [acCardInfo, addFu, addInfo.id, addInfo.txt, closeFu, parentIdArr]
-  )
-  return (
-    <Modal
-      wrapClassName={styles.A2add}
-      open={true}
-      title={`${addInfo.txt} - 中图法分类`}
-      footer={
-        [] // 设置footer为空,去掉 取消 确定默认按钮
-      }
-    >
-      <div className='A2aMain'>
-        <Form
-          scrollToFirstError={true}
-          ref={FormBoxRef}
-          name='basic'
-          labelCol={{ span: 3 }}
-          onFinish={onFinish}
-          onFinishFailed={onFinishFailed}
-          autoComplete='off'
-        >
-          <div className='fromRow'>
-            <div className='fromRowll'>父级分类:</div>
-            <div className='fromRowrr'>
-              <Cascader
-                style={{ width: 658 }}
-                disabled={addInfo.txt === '编辑'}
-                changeOnSelect
-                fieldNames={{ label: 'name', value: 'id', children: 'children' }}
-                options={treeData}
-                placeholder={addInfo.txt === '编辑' ? '空' : '请选择'}
-                value={parentIdArr ? [...parentIdArr] : []}
-                onChange={cardChange}
-              />
-            </div>
-          </div>
-
-          <Form.Item
-            label='分类编号'
-            name='num'
-            rules={[{ required: true, message: '请输入分类编号!' }]}
-            getValueFromEvent={e => e.target.value.replace(/\s+/g, '')}
-          >
-            <Input maxLength={20} showCount placeholder='请输入内容' />
-          </Form.Item>
-
-          <Form.Item
-            label='分类名称'
-            name='name'
-            rules={[{ required: true, message: '请输入分类名称!' }]}
-            getValueFromEvent={e => e.target.value.replace(/\s+/g, '')}
-          >
-            <Input maxLength={20} showCount placeholder='请输入内容' />
-          </Form.Item>
-
-          <div className='fromRow2'>
-            <Form.Item
-              label='排序值'
-              name='sort'
-              rules={[{ required: true, message: '请输入排序值!' }]}
-            >
-              <InputNumber min={1} max={999} precision={0} placeholder='请输入' />
-            </Form.Item>
-            <div className='fromRowTit'>
-              请输入1~999的数字。数字越小,排序越靠前。数字相同时,更新发布的内容排在前面
-            </div>
-          </div>
-
-          {/* 确定和取消按钮 */}
-          <br />
-          <Form.Item wrapperCol={{ offset: 9, span: 16 }}>
-            <Button type='primary' htmlType='submit'>
-              提交
-            </Button>
-            &emsp;
-            <MyPopconfirm txtK='取消' onConfirm={closeFu} />
-          </Form.Item>
-        </Form>
-      </div>
-    </Modal>
-  )
-}
-
-const MemoA2add = React.memo(A2add)
-
-export default MemoA2add

+ 0 - 113
src/pages/A2classify/A2add2.tsx

@@ -1,113 +0,0 @@
-import React, { useCallback, useEffect, useRef } from 'react'
-import styles from './index.module.scss'
-import { Button, Form, FormInstance, Input, InputNumber, Modal } from 'antd'
-import MyPopconfirm from '@/components/MyPopconfirm'
-import { A2_APIgetInfo2, A2_APIsave2 } from '@/store/action/A2classify'
-import { MessageFu } from '@/utils/message'
-
-type Props = {
-  tab2Id: number
-  addFu: (flag: boolean) => void
-  closeFu: () => void
-}
-
-function A2add2({ tab2Id, addFu, closeFu }: Props) {
-  // 设置表单初始数据(区分编辑和新增)
-  const FormBoxRef = useRef<FormInstance>(null)
-
-  const getInfoFu = useCallback(async (id: number) => {
-    const res = await A2_APIgetInfo2(id)
-    if (res.code === 0) {
-      FormBoxRef.current?.setFieldsValue({
-        ...res.data
-      })
-    }
-  }, [])
-  useEffect(() => {
-    if (tab2Id > 0) getInfoFu(tab2Id)
-    else {
-      FormBoxRef.current?.setFieldsValue({
-        sort: 999
-      })
-    }
-  }, [getInfoFu, tab2Id])
-
-  // 没有通过校验
-  const onFinishFailed = useCallback(() => {
-    // return MessageFu.warning("有表单不符号规则!");
-  }, [])
-
-  // 通过校验点击确定
-  const onFinish = useCallback(
-    async (values: any) => {
-      const res = await A2_APIsave2({
-        ...values,
-        id: tab2Id > 0 ? tab2Id : null
-      })
-      if (res.code === 0) {
-        MessageFu.success(tab2Id > 0 ? '编辑成功!' : '新增成功!')
-        addFu(tab2Id > 0 ? true : false)
-        closeFu()
-      }
-    },
-    [addFu, closeFu, tab2Id]
-  )
-  return (
-    <Modal
-      wrapClassName={styles.A2add}
-      open={true}
-      title={`${tab2Id > 0 ? '编辑' : '新增'} - 展示分类`}
-      footer={
-        [] // 设置footer为空,去掉 取消 确定默认按钮
-      }
-    >
-      <div className='A2aMain'>
-        <Form
-          scrollToFirstError={true}
-          ref={FormBoxRef}
-          name='basic'
-          labelCol={{ span: 3 }}
-          onFinish={onFinish}
-          onFinishFailed={onFinishFailed}
-          autoComplete='off'
-        >
-          <Form.Item
-            label='分类名称'
-            name='name'
-            rules={[{ required: true, message: '请输入分类名称!' }]}
-            getValueFromEvent={e => e.target.value.replace(/\s+/g, '')}
-          >
-            <Input maxLength={20} showCount placeholder='请输入内容' />
-          </Form.Item>
-
-          <div className='fromRow2'>
-            <Form.Item
-              label='排序值'
-              name='sort'
-              rules={[{ required: true, message: '请输入排序值!' }]}
-            >
-              <InputNumber min={1} max={999} precision={0} placeholder='请输入' />
-            </Form.Item>
-            <div className='fromRowTit'>
-              请输入1~999的数字。数字越小,排序越靠前。数字相同时,更新发布的内容排在前面
-            </div>
-          </div>
-
-          {/* 确定和取消按钮 */}
-          <br />
-          <Form.Item wrapperCol={{ offset: 9, span: 16 }}>
-            <Button type='primary' htmlType='submit'>
-              提交
-            </Button>
-            &emsp;
-            <MyPopconfirm txtK='取消' onConfirm={closeFu} />
-          </Form.Item>
-        </Form>
-      </div>
-    </Modal>
-  )
-}
-
-const MemoA2add2 = React.memo(A2add2)
-
-export default MemoA2add2

+ 0 - 18
src/pages/A2classify/data.ts

@@ -1,18 +0,0 @@
-export const treeResIdFu = (list: any, id: number) => {
-  // 每次进来使用find遍历一次
-  let res = list.find((item: any) => item.id === id)
-
-  if (res) {
-    return res
-  } else {
-    for (let i = 0; i < list.length; i++) {
-      if (list[i].children instanceof Array && list[i].children.length > 0) {
-        res = treeResIdFu(list[i].children, id)
-
-        if (res) return res
-      }
-    }
-
-    return null
-  }
-}

+ 0 - 123
src/pages/A2classify/index.module.scss

@@ -1,123 +0,0 @@
-.A2classify {
-  background-color: #fff;
-  border-radius: 10px;
-  padding: 20px 24px;
-  position: relative;
-  :global {
-    .A2top {
-      display: flex;
-      justify-content: space-between;
-      height: 40px;
-      align-items: center;
-      .A2top1 {
-        display: flex;
-        align-items: center;
-      }
-    }
-    .A2main {
-      margin-top: 15px;
-      height: calc(100% - 50px);
-      & > div {
-        height: 100%;
-      }
-      .A2Null {
-        width: 100%;
-        height: 300px;
-        font-size: 24px;
-        display: flex;
-        justify-content: center;
-        align-items: center;
-      }
-      .A2m1 {
-        display: flex;
-        justify-content: space-between;
-        .A2m1ll {
-          width: 40%;
-          background-color: #e8e8e8;
-          padding: 20px;
-          overflow-y: auto;
-          .site-tree-search-value {
-            color: red;
-            font-weight: 700;
-          }
-          .ant-tree {
-            min-height: 100%;
-            padding: 10px;
-          }
-        }
-        .A2m1rr {
-          width: calc(60% - 24px);
-          border: 1px solid #ccc;
-          padding: 20px;
-          .A2mr1 {
-            font-weight: 700;
-            color: var(--themeColor);
-            font-size: 24px;
-          }
-          .A2mr2 {
-            margin: 20px 0 40px;
-          }
-
-          .A2mr3 {
-            display: flex;
-            font-size: 20px;
-            margin-bottom: 30px;
-            .A2mr3ll {
-              width: 100px;
-              text-align: right;
-              font-weight: 700;
-            }
-            .A2mr3rr {
-              width: calc(100% - 100px);
-            }
-          }
-        }
-      }
-    }
-  }
-}
-
-// 新增弹窗页面
-.A2add {
-  :global {
-    .ant-modal-close {
-      display: none;
-    }
-
-    .ant-modal {
-      width: 800px !important;
-    }
-
-    .ant-modal-body {
-      border-top: 1px solid #ccc;
-    }
-
-    .A2aMain {
-      padding-top: 15px;
-      .fromRow2 {
-        position: relative;
-
-        .fromRowTit {
-          position: absolute;
-          left: 200px;
-          top: 5px;
-          color: #999;
-          font-size: 12px;
-        }
-      }
-      .fromRow {
-        display: flex;
-        align-items: center;
-        margin-bottom: 24px;
-        .fromRowll {
-          width: 94px;
-          text-align: right;
-          position: relative;
-        }
-        .fromRowrr {
-          width: calc(100% - 94px);
-        }
-      }
-    }
-  }
-}

+ 0 - 337
src/pages/A2classify/index.tsx

@@ -1,337 +0,0 @@
-import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
-import styles from './index.module.scss'
-import { Button, Input, Tree, TreeDataNode } from 'antd'
-import { treeResIdFu } from './data'
-import { useDispatch, useSelector } from 'react-redux'
-import { RootState } from '@/store'
-import { A2_APIdel1, A2_APIdel2, A2_APIgetList1, A2_APIgetList2 } from '@/store/action/A2classify'
-import MyPopconfirm from '@/components/MyPopconfirm'
-import { MessageFu } from '@/utils/message'
-import A2add, { A2AddInfoType } from './A2add'
-import { A2tableType, A2TreeType } from '@/types'
-import MyTable from '@/components/MyTable'
-import { A2tableC } from '@/utils/tableData'
-import A2add2 from './A2add2'
-
-export type TopLeftArrType = '中图法分类' | '展示分类'
-
-const topLeftArr: TopLeftArrType[] = ['中图法分类', '展示分类']
-
-function A2classify() {
-  const { treeData: treeDataTemp, treeFlag } = useSelector((state: RootState) => state.A2classify)
-  const dispatch = useDispatch()
-
-  const [topType, setTopType] = useState<TopLeftArrType>('中图法分类')
-
-  const getList1 = useCallback(() => {
-    dispatch(A2_APIgetList1())
-  }, [dispatch])
-
-  const getList2 = useCallback(
-    async (val: string) => {
-      dispatch(A2_APIgetList2({ pageNum: 1, pageSize: 9999, searchKey: val }))
-    },
-    [dispatch]
-  )
-
-  useEffect(() => {
-    getList1()
-  }, [getList1])
-
-  // 点击重置
-  const resetSelectFu = useCallback(
-    (flag?: boolean) => {
-      setValue('')
-      if (topType === '展示分类') getList2('')
-      if (flag) getList1()
-    },
-    [getList1, getList2, topType]
-  )
-
-  // 顶部切换tab
-  const cutTop = useCallback(
-    (item: TopLeftArrType) => {
-      setValue('')
-      setTopType(item)
-      item === '中图法分类' ? getList1() : getList2('')
-    },
-    [getList1, getList2]
-  )
-
-  const [value, setValue] = useState('')
-
-  const time = useRef(-1)
-  const valueChange = useCallback(
-    (val: string) => {
-      setValue(val)
-      clearInterval(time.current)
-      time.current = window.setTimeout(() => {
-        if (topType === '展示分类') getList2(val)
-        // topType === '中图法分类' ? getList1(val) : getList2(val)
-      }, 500)
-    },
-    [getList2, topType]
-  )
-
-  // 有关树------------------------
-  const tab1Flag = useRef(true)
-  useEffect(() => {
-    if (treeDataTemp && treeDataTemp.length && tab1Flag.current) {
-      tab1Flag.current = false
-      setAcShu(treeDataTemp[0].id as number)
-    }
-  }, [treeDataTemp])
-
-  // 当前选中的树节点ID
-  const [acShu, setAcShu] = useState(0)
-
-  // 点击树节点
-  const onSelect = (id: any) => {
-    if (id[0]) setAcShu(id[0])
-  }
-
-  // 搜索高亮
-  const treeData = useMemo(() => {
-    const loop = (dataTemp: any[]): TreeDataNode[] => {
-      const data = dataTemp || []
-
-      return data.map(item => {
-        const strTitle = ((item.num ? item.num + ' ' : '') + item.name) as string
-
-        const index = strTitle.indexOf(value)
-
-        const beforeStr = strTitle.substring(0, index)
-        const afterStr = strTitle.slice(index + value.length)
-        const title =
-          index > -1 ? (
-            <span key={item.id}>
-              {beforeStr}
-              <span className='site-tree-search-value'>{value}</span>
-              {afterStr}
-            </span>
-          ) : (
-            <span key={item.id}>{strTitle}</span>
-          )
-        if (item.children) {
-          return { title, key: item.id, children: loop(item.children) }
-        }
-        return {
-          title,
-          key: item.id
-        }
-      })
-    }
-
-    return loop(treeDataTemp)
-  }, [treeDataTemp, value])
-
-  // 右侧信息
-  const rightData = useMemo(() => {
-    let obj = {} as A2TreeType
-
-    obj = treeResIdFu(treeDataTemp, acShu)
-
-    return obj || {}
-  }, [acShu, treeDataTemp])
-
-  // 点击删除
-  const delTree = useCallback(
-    async (id: number) => {
-      const res = await A2_APIdel1(id)
-      if (res.code === 0) {
-        MessageFu.success('删除成功!')
-        tab1Flag.current = true
-        getList1()
-      }
-    },
-    [getList1]
-  )
-
-  // 点击新增和编辑
-  const [addInfo, setAddInfo] = useState({} as A2AddInfoType)
-
-  const addSonFu = useCallback(
-    (id: number) => {
-      setAddInfo({
-        id,
-        txt: id > 0 ? '编辑' : '新增',
-        acInfo: rightData
-      })
-    },
-    [rightData]
-  )
-
-  // -----------------展示分类
-  const tableInfo = useSelector((state: RootState) => state.A2classify.tableInfo)
-
-  const delTableFu = useCallback(
-    async (id: number) => {
-      const res = await A2_APIdel2(id)
-      if (res.code === 0) {
-        MessageFu.success('删除成功!')
-        getList2(value)
-      }
-    },
-    [getList2, value]
-  )
-  const tableLastBtn = useMemo(() => {
-    return [
-      {
-        title: '操作',
-        render: (item: A2tableType) => (
-          <>
-            <Button size='small' type='text' onClick={() => setTab2Id(item.id)}>
-              编辑
-            </Button>
-            <MyPopconfirm txtK='删除' onConfirm={() => delTableFu(item.id)} />
-          </>
-        )
-      }
-    ]
-  }, [delTableFu])
-
-  // tab新增/编辑
-  const [tab2Id, setTab2Id] = useState(0)
-
-  return (
-    <div className={styles.A2classify}>
-      <div className='pageTitle'>图书分类</div>
-      {/* 顶部 */}
-      <div className='A2top'>
-        <div className='A2top1'>
-          {topLeftArr.map(item => (
-            <Button
-              onClick={() => cutTop(item)}
-              key={item}
-              type={topType === item ? 'primary' : 'default'}
-            >
-              {item}
-            </Button>
-          ))}
-        </div>
-        <div className='A2top1'>
-          <Input
-            style={{ width: 240 }}
-            placeholder={topType === '中图法分类' ? '请输入分类名称/编号' : '请输入标题'}
-            value={value}
-            onChange={e => valueChange(e.target.value)}
-          />
-          &emsp;
-          <Button onClick={() => resetSelectFu()}>重置</Button>&emsp;
-          <Button
-            type='primary'
-            onClick={() =>
-              topType === '展示分类'
-                ? setTab2Id(-1)
-                : setAddInfo({ id: -1, txt: '新增', acInfo: rightData })
-            }
-          >
-            新增
-          </Button>
-        </div>
-      </div>
-
-      {/* 主体 */}
-      <div className='A2main'>
-        <div className='A2m1' hidden={topType !== '中图法分类'}>
-          <div className='A2m1ll'>
-            {treeDataTemp && treeDataTemp.length ? (
-              <Tree
-                // 默认全部展开
-                defaultExpandAll={true}
-                // 数据
-                treeData={treeData}
-                // 自定义字段
-                // fieldNames={{ title: 'title', key: 'key', children: 'children' }}
-                // 选中
-                selectedKeys={[acShu]}
-                // 点击
-                onSelect={onSelect}
-              />
-            ) : treeFlag ? (
-              <div className='A2Null'>暂无数据</div>
-            ) : null}
-          </div>
-          <div className='A2m1rr'>
-            <div className='A2mr1'>分类详情</div>
-
-            {rightData.id ? (
-              <>
-                <div className='A2mr2'>
-                  <Button type='text' onClick={() => addSonFu(rightData.id)}>
-                    编辑
-                  </Button>
-                  &emsp;
-                  <MyPopconfirm txtK='删除' onConfirm={() => delTree(rightData.id)} />
-                </div>
-
-                <div className='A2mr3'>
-                  <div className='A2mr3ll'>分类编号:</div>
-                  <div className='A2mr3rr'>{rightData.num}</div>
-                </div>
-
-                <div className='A2mr3'>
-                  <div className='A2mr3ll'>分类名称:</div>
-                  <div className='A2mr3rr'>{rightData.name}</div>
-                </div>
-
-                <div className='A2mr3'>
-                  <div className='A2mr3ll'>层级:</div>
-                  <div className='A2mr3rr'>{rightData.level}</div>
-                </div>
-
-                <div className='A2mr3'>
-                  <div className='A2mr3ll'>排序值:</div>
-                  <div className='A2mr3rr'>{rightData.sort}</div>
-                </div>
-
-                <div className='A2mr3'>
-                  <div className='A2mr3ll'>编辑时间:</div>
-                  <div className='A2mr3rr'>{rightData.updateTime}</div>
-                </div>
-
-                <div className='A2mr3'>
-                  <div className='A2mr3ll'>编辑人:</div>
-                  <div className='A2mr3rr'>{rightData.creatorName}</div>
-                </div>
-              </>
-            ) : treeFlag ? (
-              <div className='A2Null'>暂无数据</div>
-            ) : null}
-          </div>
-        </div>
-        <div className='A2m2' hidden={topType !== '展示分类'}>
-          <MyTable
-            yHeight={678}
-            list={tableInfo.list}
-            columnsTemp={A2tableC}
-            lastBtn={tableLastBtn}
-            pagingInfo={false}
-          />
-        </div>
-      </div>
-
-      {/* 新增/编辑页面 中图法分类 */}
-      {addInfo.id ? (
-        <A2add
-          addInfo={addInfo}
-          addFu={() => resetSelectFu(true)}
-          closeFu={() => setAddInfo({} as A2AddInfoType)}
-        />
-      ) : null}
-
-      {/* 新增/编辑 展示分类 */}
-      {tab2Id ? (
-        <A2add2
-          tab2Id={tab2Id}
-          addFu={flag => (flag ? getList2(value) : resetSelectFu())}
-          closeFu={() => setTab2Id(0)}
-        />
-      ) : null}
-    </div>
-  )
-}
-
-const MemoA2classify = React.memo(A2classify)
-
-export default MemoA2classify

+ 37 - 9
src/pages/A7notice/A7add/index.module.scss

@@ -1,4 +1,4 @@
-.A7add {
+.A1add {
   position: absolute;
   top: 0;
   left: 0;
@@ -10,9 +10,9 @@
   padding: 24px;
 
   :global {
-    .A7aMain {
+    .A1aMain {
       width: 100%;
-      height: 100%;
+      height: calc(100% - 80px);
       overflow-y: auto;
 
       textarea {
@@ -34,10 +34,29 @@
 
       .ant-form {
         width: 800px;
+        display: flex;
+        flex-direction: column;
+        gap: 30px;
 
         // .ant-input-affix-wrapper{
         //   width: 800px;
         // }
+
+        .tude {
+          margin-left: 46px;
+          display: flex;
+          gap: 10px;
+          .ant-form-item {
+            width: 50%;
+            .ant-row {
+              justify-content: space-between;
+              .ant-form-item-control {
+                max-width: 320px;
+              }
+            }
+          }
+        }
+
         .formRow {
           display: flex;
 
@@ -57,18 +76,27 @@
           }
         }
 
-        .A7abtn {
-          position: absolute;
+        .A1abtn {
+          display: flex;
+          align-items: center;
+          width: 100%;
+          height: 80px;
+          position: fixed;
+          bottom: 0;
+          background: #fff;
           z-index: 10;
-          left: 1200px;
-          top: 50%;
-          transform: translateY(-50%);
+
+          .A1abtnBox {
+            display: flex;
+            gap: 20px;
+            padding-left: 100px;
+          }
         }
       }
     }
 
     // 从查看进入
-    .A7aMainLook {
+    .A1aMainLook {
       // 左边的 label 也不让选中
       label {
         pointer-events: none;

+ 255 - 0
src/pages/A2line/A2add/index.tsx

@@ -0,0 +1,255 @@
+import React, { useCallback, useEffect, useRef, useState } from 'react'
+import styles from './index.module.scss'
+import classNames from 'classnames'
+import { A2EditInfoType } from '../data'
+import { Button, Form, FormInstance, Input, Space, TableColumnsType } from 'antd'
+import { DragOutlined } from '@ant-design/icons'
+import { A2_APIgetInfo, A2_APIsave } from '@/store/action/A2line'
+import { MessageFu } from '@/utils/message'
+import ZupOne from '@/components/ZupOne'
+import { A2AddType, A2tbType } from '@/types'
+import DragTable, { DataType } from '@/components/DragTable'
+import MyPopconfirm from '@/components/MyPopconfirm'
+
+type Props = {
+  editInfo: A2EditInfoType
+  closeFu: () => void
+  addTableFu: () => void
+  editTableFu: () => void
+}
+
+function A2add({ editInfo, closeFu, addTableFu, editTableFu }: Props) {
+  // 表单的ref
+  const FormBoxRef = useRef<FormInstance>(null)
+
+  // 封面图ref
+  const ZupThumbRef = useRef<any>(null)
+
+  // 列表数据
+  const [dataSource, setDataSource] = useState<DataType[]>([])
+
+  // 回显数据的方法调用
+  const dataShow = useCallback((info: A2tbType) => {
+    FormBoxRef.current?.setFieldsValue({ ...info })
+    // 设置封面图
+    ZupThumbRef.current?.setFileComFileFu({
+      filename: '',
+      thUrl: info.thumb,
+      url: info.thumb
+    })
+    // 设置列表数据
+    setDataSource(
+      info.sites.map(item => ({
+        id: item.id,
+        name: item.name
+      }))
+    )
+  }, [])
+
+  // 编辑 进入页面 获取信息
+  const getInfoFu = useCallback(
+    async (id: number) => {
+      if (editInfo.info) dataShow(editInfo.info)
+      else {
+        const res = await A2_APIgetInfo(id)
+        if (res.code === 0) {
+          dataShow(res.data)
+        }
+      }
+    },
+    [dataShow, editInfo.info]
+  )
+
+  // 附件 是否 已经点击过确定
+  const [fileCheck, setFileCheck] = useState(false)
+
+  // 编辑填入数据
+  useEffect(() => {
+    if (editInfo.id > 0) {
+      getInfoFu(editInfo.id)
+    }
+  }, [editInfo.id, getInfoFu])
+
+  // 没有通过校验
+  const onFinishFailed = useCallback(() => {
+    setFileCheck(true)
+  }, [])
+
+  //  通过校验点击确定
+  const onFinish = useCallback(
+    async (values: any) => {
+      setFileCheck(true)
+
+      const coverUrl = ZupThumbRef.current?.fileComFileResFu()
+      // 没有传 封面图
+      if (!coverUrl.url) return MessageFu.warning('请上传封面图!')
+      if (dataSource.length === 0) return MessageFu.warning('请上传路线清单!')
+
+      // 发布
+      const obj1: A2AddType = {
+        ...values,
+        siteIds: dataSource.map(item => item.id).join(','),
+        thumb: coverUrl.url
+      }
+
+      const res: any =
+        editInfo.txt === '新增'
+          ? await A2_APIsave(obj1)
+          : await A2_APIsave({ ...obj1, id: editInfo.id })
+
+      if (res.msg === '名称不能重复') {
+        return FormBoxRef.current?.setFields([{ name: 'name', errors: ['已存在相同名称的景点'] }])
+      }
+
+      if (res.code === 0) {
+        MessageFu.success(`${editInfo.txt}成功!`)
+        editInfo.id > 0 ? editTableFu() : addTableFu()
+        closeFu()
+      }
+    },
+    [addTableFu, closeFu, dataSource, editInfo.id, editInfo.txt, editTableFu]
+  )
+
+  const formOkBtnRef = useRef<any>(null)
+
+  const columns: TableColumnsType<DataType> = [
+    {
+      title: '排序',
+      dataIndex: 'sort',
+      render: (_, record) => (
+        <span style={{ cursor: 'move' }} data-row-key={record.id}>
+          <DragOutlined />
+        </span>
+      )
+    },
+    {
+      title: '景点名称',
+      dataIndex: 'name'
+    },
+    {
+      title: '操作',
+      dataIndex: 'action',
+      render: (_, record) => (
+        <Space>
+          <Button
+            onClick={() => {
+              setDataSource(prev => prev.filter(item => item.id !== record.id))
+            }}
+          >
+            删除
+          </Button>
+        </Space>
+      )
+    }
+  ]
+  return (
+    <div className={styles.A1add}>
+      <div className={classNames('A1aMain')}>
+        <Form
+          ref={FormBoxRef}
+          name='basic'
+          labelCol={{ span: 3 }}
+          onFinish={onFinish}
+          onFinishFailed={onFinishFailed}
+          autoComplete='off'
+          scrollToFirstError
+        >
+          <Form.Item label='名称' name='name' rules={[{ required: true, message: '请输入名称!' }]}>
+            <Input
+              readOnly={editInfo.txt === '查看'}
+              placeholder='请输入内容,不超过10个字'
+              maxLength={10}
+              showCount
+            />
+          </Form.Item>
+
+          <Form.Item label='标签' name='tag' rules={[{ required: true, message: '请输入标签!' }]}>
+            <Input
+              readOnly={editInfo.txt === '查看'}
+              placeholder='请输入内容,不超过10个字'
+              maxLength={10}
+              showCount
+            />
+          </Form.Item>
+
+          <Form.Item
+            label='预计用时'
+            name='expect'
+            rules={[{ required: true, message: '请输入预计时间!' }]}
+          >
+            <Input
+              readOnly={editInfo.txt === '查看'}
+              placeholder='请输入内容,不超过10个字,如4日'
+              maxLength={10}
+              showCount
+            />
+          </Form.Item>
+
+          <Form.Item
+            label={
+              <>
+                <span style={{ color: 'red' }}>* </span> 封面
+              </>
+            }
+            name='thumb'
+          >
+            <ZupOne
+              ref={ZupThumbRef}
+              fileCheck={fileCheck}
+              size={5}
+              isLook={editInfo.txt === '查看'}
+              dirCode={'A2line'}
+              myUrl='cms/site/upload'
+              format={['image/jpeg', 'image/png']}
+              formatTxt='jpg/jpeg/png'
+              checkTxt='请上传图片!'
+              upTxt='最多可上传1张图片'
+              myType='thumb'
+            />
+          </Form.Item>
+
+          <Form.Item
+            label='排序值'
+            name='sort'
+            rules={[{ required: true, message: '请输入1-999的数字!' }]}
+          >
+            <Input
+              readOnly={editInfo.txt === '查看'}
+              placeholder='请输入1-999的数字,数字越大,排序越靠前。'
+              type='number'
+            />
+          </Form.Item>
+
+          <Form.Item
+            label={
+              <>
+                <span style={{ color: 'red' }}>* </span> 路线清单
+              </>
+            }
+            name='sites'
+          >
+            <DragTable columns={columns} dataSource={dataSource} setDataSource={setDataSource} />
+          </Form.Item>
+
+          {/* 确定和取消按钮 */}
+          <Form.Item className='A1abtn'>
+            <div className='A1abtnBox'>
+              <Button
+                type='primary'
+                htmlType='submit'
+                onClick={() => formOkBtnRef.current?.click()}
+              >
+                提交
+              </Button>
+              <MyPopconfirm txtK='取消' onConfirm={closeFu} />
+            </div>
+          </Form.Item>
+        </Form>
+      </div>
+    </div>
+  )
+}
+
+const MemoA2add = React.memo(A2add)
+
+export default MemoA2add

+ 7 - 0
src/pages/A2line/data.ts

@@ -0,0 +1,7 @@
+import { A2tbType } from '@/types'
+
+export type A2EditInfoType = {
+  id: number
+  txt: '新增' | '编辑' | '查看' | ''
+  info?: A2tbType
+}

+ 13 - 9
src/pages/A5bookAudit/index.module.scss

@@ -1,25 +1,29 @@
-.A5bookAudit {
+.A2lineOpt {
   position: relative;
   :global {
-    .A5top {
+    .A2top {
       border-radius: 10px;
       background-color: #fff;
       padding: 15px 24px;
       display: flex;
       justify-content: space-between;
-      & > div {
+      gap: 20px;
+      .A2topLeft {
         display: flex;
-        .A5TopRow {
+        .rowItem {
+          margin-left: 20px;
+          width: 200px;
           display: flex;
           align-items: center;
-          margin-right: 20px;
-          .ant-select-selection-placeholder {
-            color: black;
-          }
+          gap: 10px;
         }
       }
+      .A2topRight {
+        display: flex;
+        gap: 20px;
+      }
     }
-    .A5tableBox {
+    .A1tableBox {
       border-radius: 10px;
       overflow: hidden;
       margin-top: 15px;

+ 147 - 0
src/pages/A2line/index.tsx

@@ -0,0 +1,147 @@
+import React, { useCallback, useEffect, useMemo, useState } from 'react'
+import styles from './index.module.scss'
+import { Button, Input } from 'antd'
+import { useDispatch, useSelector } from 'react-redux'
+import { A2EditInfoType } from './data'
+import { A2_APIdel, A2_APIgetList } from '@/store/action/A2line'
+import { RootState } from '@/store'
+import { MessageFu } from '@/utils/message'
+import { A1tbType } from '@/types'
+import MyPopconfirm from '@/components/MyPopconfirm'
+import MyTable from '@/components/MyTable'
+import { A2tableC } from '@/utils/tableData'
+import A2add from './A2add'
+
+const pageDataBase = {
+  pageNum: 1,
+  pageSize: 10
+}
+
+function A2line() {
+  const dispatch = useDispatch()
+
+  const [pageData, setPageData] = useState(pageDataBase)
+  const [title, setTitle] = useState('')
+
+  const getListFu = useCallback(() => {
+    dispatch(A2_APIgetList({ ...pageData, searchKey: title }))
+  }, [dispatch, pageData, title])
+
+  useEffect(() => {
+    getListFu()
+  }, [getListFu])
+
+  // 点击重置
+  const resetSelectFu = useCallback(() => {
+    setPageData({ ...pageDataBase })
+  }, [])
+
+  const tableInfo = useSelector((state: RootState) => state.A2line.tableInfo)
+
+  const delTableFu = useCallback(
+    async (id: number) => {
+      const res = await A2_APIdel(id)
+      if (res.code === 0) {
+        MessageFu.success('删除成功!')
+        getListFu()
+      }
+    },
+    [getListFu]
+  )
+
+  const tableLastBtn = useMemo(() => {
+    return [
+      {
+        title: '操作',
+        render: (item: A1tbType) => (
+          <>
+            <Button
+              size='small'
+              type='text'
+              onClick={() => setEditInfo({ id: item.id, txt: '查看' })}
+            >
+              查看
+            </Button>
+            <Button
+              size='small'
+              type='text'
+              onClick={() => setEditInfo({ id: item.id, txt: '编辑' })}
+            >
+              编辑
+            </Button>
+            <MyPopconfirm txtK='删除' onConfirm={() => delTableFu(item.id)} />
+          </>
+        )
+      }
+    ]
+  }, [delTableFu])
+
+  //新增、编辑
+  const [editInfo, setEditInfo] = useState<A2EditInfoType>({
+    id: 0,
+    txt: ''
+  })
+
+  return (
+    <>
+      <div className={styles.A2lineOpt}>
+        <div className='pageTitle'>路线设置 {editInfo.id ? ` - ${editInfo.txt}` : ''}</div>
+
+        {/* 顶部筛选 */}
+        <div className='A2top'>
+          <div className='A2topLeft'>
+            <Input
+              style={{ width: 200 }}
+              placeholder='请输入景点名称或简介'
+              onChange={e => setTitle(e.target.value)}
+              value={title}
+              maxLength={10}
+            />
+          </div>
+          <div className='A2topRight'>
+            <Button
+              onClick={() => {
+                resetSelectFu()
+                setTitle('')
+              }}
+            >
+              重置
+            </Button>
+            <Button type='primary' onClick={() => setEditInfo({ id: -1, txt: '新增' })}>
+              新增
+            </Button>
+          </div>
+        </div>
+
+        {/* 表格主体 */}
+        <div className='A1tableBox'>
+          <MyTable
+            myKey='id'
+            yHeight={625}
+            list={tableInfo.list}
+            columnsTemp={A2tableC}
+            lastBtn={tableLastBtn}
+            pageNum={pageData.pageNum}
+            pageSize={pageData.pageSize}
+            total={tableInfo.total}
+            onChange={(pageNum, pageSize) => setPageData({ ...pageData, pageNum, pageSize })}
+          />
+        </div>
+
+        {/* 新增 / 编辑 */}
+        {editInfo.id ? (
+          <A2add
+            editInfo={editInfo}
+            closeFu={() => setEditInfo({ id: 0, txt: '新增' })}
+            addTableFu={resetSelectFu}
+            editTableFu={getListFu}
+          />
+        ) : null}
+      </div>
+    </>
+  )
+}
+
+const MemoA2line = React.memo(A2line)
+
+export default MemoA2line

+ 0 - 163
src/pages/A3recommend/A3add.tsx

@@ -1,163 +0,0 @@
-import React, { useCallback, useEffect, useState } from 'react'
-import styles from './index.module.scss'
-import { Button, InputNumber, Modal, Select } from 'antd'
-import MyPopconfirm from '@/components/MyPopconfirm'
-import { A1_APIgetSelect, A3_APIgetInfo, A3_APIsave } from '@/store/action/A3recommend'
-import { MessageFu } from '@/utils/message'
-
-type Props = {
-  type: 'index' | 'rank'
-  id: number
-  closeFu: () => void
-  addTableFu: () => void
-}
-
-function A3add({ type, id, closeFu, addTableFu }: Props) {
-  const getSelect = useCallback(async () => {
-    const res = await A1_APIgetSelect()
-    if (res.code === 0) {
-      setSelectArr(res.data.records.map((v: any) => ({ value: v.id, name: v.name, num: v.num })))
-    }
-  }, [])
-
-  useEffect(() => {
-    getSelect()
-  }, [getSelect])
-
-  const getInfo = useCallback(async (id: number) => {
-    const res = await A3_APIgetInfo(id)
-    if (res.code === 0) {
-      setName(res.data.bookId)
-      if (res.data.num) setNum(res.data.bookId)
-
-      setSort(res.data.sort)
-    }
-  }, [])
-
-  useEffect(() => {
-    if (id > 0) getInfo(id)
-  }, [getInfo, id])
-
-  const [selectArr, setSelectArr] = useState<{ value: number; name: string; num: string }[]>([])
-
-  const [name, setName] = useState<number | null>(null)
-  const [num, setNum] = useState<number | null>(null)
-
-  const [sort, setSort] = useState<number>(999)
-
-  const onChange = useCallback(
-    (value: number) => {
-      setName(value)
-
-      const obj = selectArr.find(v => v.value === value)!
-
-      if (obj.num) setNum(value)
-      else setNum(null)
-    },
-    [selectArr]
-  )
-
-  // 拿来占位,不然会报错
-  const onSearch = useCallback((value: string) => {
-    // console.log(`search ${value}`)
-  }, [])
-
-  const btnOk = useCallback(async () => {
-    if (!Number(name)) return MessageFu.warning('请输入书名!')
-    if (!sort) return MessageFu.warning('请输入排序值!')
-
-    const obj = {
-      id: id > 0 ? id : null,
-      type,
-      bookId: Number(name),
-      sort
-    }
-
-    const res = await A3_APIsave(obj)
-    if (res.code === 0) {
-      MessageFu.success(id > 0 ? '编辑成功!' : '新增成功!')
-      addTableFu()
-      closeFu()
-    }
-  }, [addTableFu, closeFu, id, name, sort, type])
-
-  return (
-    <Modal
-      wrapClassName={styles.A3add}
-      open={true}
-      title={id > 0 ? '编辑' : '新增'}
-      footer={
-        [] // 设置footer为空,去掉 取消 确定默认按钮
-      }
-    >
-      <div className='formRow'>
-        <div className='formLeft'>
-          <span>*</span>书名:
-        </div>
-        <div className='formRight'>
-          <Select
-            showSearch
-            value={name}
-            maxLength={20}
-            placeholder={'请输入内容模糊搜索'}
-            style={{ width: 400 }}
-            onChange={onChange}
-            onSearch={onSearch}
-            fieldNames={{ label: 'name', value: 'value' }}
-            optionFilterProp='name'
-            options={selectArr}
-          />
-        </div>
-      </div>
-
-      <div className='formRow'>
-        <div className='formLeft'>ISBN编号:</div>
-        <div className='formRight'>
-          <Select
-            showSearch
-            value={num}
-            maxLength={20}
-            placeholder={'请输入内容模糊搜索'}
-            style={{ width: 400 }}
-            onChange={onChange}
-            onSearch={onSearch}
-            fieldNames={{ label: 'num', value: 'value' }}
-            optionFilterProp='num'
-            options={selectArr.filter(v => v.num)}
-          />
-        </div>
-      </div>
-
-      <div className='formRow'>
-        <div className='formLeft'>
-          <span>*</span>排序值:
-        </div>
-        <div className='formRight'>
-          <InputNumber
-            value={sort}
-            onChange={e => setSort(e ? e : 1)}
-            min={1}
-            max={999}
-            precision={0}
-            placeholder='请输入'
-          />
-          <div className='formRightTit'>
-            请输入1~999的数字。数字越小,排序越靠前。数字相同时,更新发布的内容排在前面
-          </div>
-        </div>
-      </div>
-
-      <div className='A3abtn'>
-        <Button type='primary' onClick={btnOk}>
-          提交
-        </Button>
-        &emsp;
-        <MyPopconfirm txtK='取消' onConfirm={closeFu} />
-      </div>
-    </Modal>
-  )
-}
-
-const MemoA3add = React.memo(A3add)
-
-export default MemoA3add

+ 0 - 7
src/pages/A3recommend/data.ts

@@ -1,7 +0,0 @@
-export type A3FromDataType = {
-  type: 'index' | 'rank'
-  searchKey: string
-  num: string
-  pageNum: number
-  pageSize: number
-}

+ 0 - 78
src/pages/A3recommend/index.module.scss

@@ -1,78 +0,0 @@
-.A3recommend {
-  position: relative;
-  :global {
-    .A3top {
-      border-radius: 10px;
-      background-color: #fff;
-      padding: 15px 24px;
-      display: flex;
-      justify-content: space-between;
-      & > div {
-        display: flex;
-        .A3TopRow {
-          display: flex;
-          align-items: center;
-          margin-right: 20px;
-          .ant-select-selection-placeholder {
-            color: black;
-          }
-        }
-      }
-    }
-    .A3tableBox {
-      border-radius: 10px;
-      overflow: hidden;
-      margin-top: 15px;
-      height: calc(100% - 77px);
-      background-color: #fff;
-    }
-  }
-}
-
-// 新增 、编辑弹窗
-.A3add {
-  :global {
-    .ant-modal-close {
-      display: none;
-    }
-    .ant-modal {
-      width: 800px !important;
-    }
-    .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;
-        }
-      }
-
-      .formRight {
-        width: calc(100% - 80px);
-        position: relative;
-        .formRightTit {
-          position: absolute;
-          left: 110px;
-          top: 5px;
-          color: #999;
-          font-size: 12px;
-        }
-      }
-    }
-
-    .A3abtn {
-      text-align: center;
-      margin-top: 30px;
-    }
-  }
-}

+ 0 - 181
src/pages/A3recommend/index.tsx

@@ -1,181 +0,0 @@
-import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
-import styles from './index.module.scss'
-import { Button, Input } from 'antd'
-import { useDispatch, useSelector } from 'react-redux'
-import { A3FromDataType } from './data'
-import { A3_APIdel, A3_APIgetList } from '@/store/action/A3recommend'
-import { RootState } from '@/store'
-import { MessageFu } from '@/utils/message'
-import { A3tableType } from '@/types'
-import MyPopconfirm from '@/components/MyPopconfirm'
-import MyTable from '@/components/MyTable'
-import { A3tableC } from '@/utils/tableData'
-import A3add from './A3add'
-
-const fromDataBase: A3FromDataType = {
-  type: 'index',
-  searchKey: '',
-  num: '',
-  pageNum: 1,
-  pageSize: 9999
-}
-
-const topTypeArr: { name: string; key: 'index' | 'rank' }[] = [
-  {
-    name: '首页推荐',
-    key: 'index'
-  },
-  {
-    name: '排行榜推荐',
-    key: 'rank'
-  }
-]
-
-function A3recommend() {
-  const dispatch = useDispatch()
-
-  const [fromData, setFromData] = useState(fromDataBase)
-
-  const getListFu = useCallback(() => {
-    dispatch(A3_APIgetList(fromData))
-  }, [dispatch, fromData])
-
-  useEffect(() => {
-    getListFu()
-  }, [getListFu])
-
-  const [inputKey, setInputKey] = useState(1)
-
-  // 输入框的输入
-  const timeRef = useRef(-1)
-  const txtChangeFu = useCallback(
-    (e: React.ChangeEvent<HTMLInputElement>, key: 'searchKey' | 'num') => {
-      clearTimeout(timeRef.current)
-      timeRef.current = window.setTimeout(() => {
-        setFromData({ ...fromData, [key]: e.target.value.replaceAll("'", ''), pageNum: 1 })
-      }, 500)
-    },
-    [fromData]
-  )
-
-  // 点击重置
-  const resetSelectFu = useCallback(() => {
-    setInputKey(Date.now())
-    setFromData({ ...fromDataBase, type: fromData.type })
-  }, [fromData.type])
-
-  const tableList = useSelector((state: RootState) => state.A3recommend.tableList)
-
-  const delTableFu = useCallback(
-    async (id: number) => {
-      const res = await A3_APIdel(id)
-      if (res.code === 0) {
-        MessageFu.success('删除成功!')
-        getListFu()
-      }
-    },
-    [getListFu]
-  )
-
-  const tableLastBtn = useMemo(() => {
-    return [
-      {
-        title: '操作',
-        render: (item: A3tableType) => (
-          <>
-            <Button size='small' type='text' onClick={() => setEditId(item.id)}>
-              编辑
-            </Button>
-
-            <MyPopconfirm txtK='删除' onConfirm={() => delTableFu(item.id)} />
-          </>
-        )
-      }
-    ]
-  }, [delTableFu])
-
-  // 点击编辑和新增
-  const [editId, setEditId] = useState(0)
-
-  return (
-    <div className={styles.A3recommend}>
-      <div className='pageTitle'>图书推荐</div>
-      {/* 顶部筛选 */}
-      <div className='A3top'>
-        <div>
-          <div className='A3TopRow'>
-            {topTypeArr.map(v => (
-              <Button
-                type={v.key === fromData.type ? 'primary' : 'default'}
-                key={v.key}
-                onClick={() => setFromData({ ...fromData, type: v.key, pageNum: 1 })}
-              >
-                {v.name}
-              </Button>
-            ))}
-          </div>
-
-          <div className='A3TopRow'>
-            <span>搜索:</span>
-            <Input
-              key={inputKey}
-              maxLength={20}
-              style={{ width: 192 }}
-              placeholder='请输入书名/作者/出版社'
-              allowClear
-              onChange={e => txtChangeFu(e, 'searchKey')}
-            />
-            &nbsp;
-            <Input
-              key={inputKey + 1}
-              maxLength={20}
-              style={{ width: 192 }}
-              placeholder='请输入完整ISBN编号'
-              allowClear
-              onChange={e => txtChangeFu(e, 'num')}
-            />
-          </div>
-        </div>
-        <div>
-          <Button onClick={resetSelectFu}>重置</Button>&emsp;
-          <Button
-            type='primary'
-            onClick={() => {
-              if (fromData.type === 'index' && tableList.length >= 50)
-                return MessageFu.warning('最多支持50本!')
-              if (fromData.type === 'rank' && tableList.length >= 10)
-                return MessageFu.warning('最多支持10本!')
-              setEditId(-1)
-            }}
-          >
-            新增
-          </Button>
-        </div>
-      </div>
-
-      {/* 表格主体 */}
-      <div className='A3tableBox'>
-        <MyTable
-          yHeight={678}
-          list={tableList}
-          columnsTemp={A3tableC}
-          lastBtn={tableLastBtn}
-          pagingInfo={false}
-        />
-      </div>
-
-      {editId ? (
-        <A3add
-          id={editId}
-          type={fromData.type}
-          closeFu={() => setEditId(0)}
-          addTableFu={resetSelectFu}
-        />
-      ) : null}
-    </div>
-  )
-}
-
-const MemoA3recommend = React.memo(A3recommend)
-
-export default MemoA3recommend

+ 0 - 76
src/pages/A4iosUser/A4ip/index.module.scss

@@ -1,76 +0,0 @@
-.A4ip {
-  position: absolute;
-  top: 0;
-  left: 0;
-  width: 100%;
-  height: 100%;
-  background-color: rgba(0, 0, 0, 0.6);
-  border-radius: 10px;
-  padding: 50px 100px;
-  :global {
-    .A4iBox {
-      width: 100%;
-      height: 100%;
-      border-radius: 10px;
-      background-color: #fff;
-      padding: 20px;
-      .A4iTop {
-        display: flex;
-        align-items: center;
-        justify-content: space-between;
-        & > div {
-          display: flex;
-          align-items: center;
-        }
-      }
-      .ant-table-wrapper {
-        margin-top: 20px;
-        .ant-table-cell {
-          padding: 6px;
-        }
-      }
-    }
-  }
-}
-
-// 新增 /编辑
-.A4ipAdd {
-  :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;
-        }
-      }
-
-      .formRight {
-        width: calc(100% - 80px);
-        position: relative;
-      }
-    }
-
-    .A4ibtn {
-      text-align: center;
-      margin-top: 50px;
-    }
-  }
-}

+ 0 - 158
src/pages/A4iosUser/A4ip/index.tsx

@@ -1,158 +0,0 @@
-import React, { useCallback, useEffect, useMemo, useState } from 'react'
-import styles from './index.module.scss'
-import { Button, Input, Modal } from 'antd'
-import { A4_APIipDel, A4_APIipList, A4_APIipSave } from '@/store/action/A4iosUser'
-import { useDispatch, useSelector } from 'react-redux'
-import { RootState } from '@/store'
-import MyTable from '@/components/MyTable'
-import { MessageFu } from '@/utils/message'
-import { A4IpType } from '@/types'
-import MyPopconfirm from '@/components/MyPopconfirm'
-
-type Props = {
-  closeFu: () => void
-}
-
-function A4ip({ closeFu }: Props) {
-  const dispatch = useDispatch()
-
-  const getListFu = useCallback(async () => {
-    dispatch(A4_APIipList())
-  }, [dispatch])
-
-  useEffect(() => {
-    getListFu()
-  }, [getListFu])
-
-  const ipList = useSelector((state: RootState) => state.A4iosUser.ipList)
-
-  const delTableFu = useCallback(
-    async (id: number) => {
-      const res = await A4_APIipDel(id)
-      if (res.code === 0) {
-        MessageFu.success('删除成功!')
-        getListFu()
-      }
-    },
-    [getListFu]
-  )
-
-  const [opId, setOpId] = useState(0)
-  const [ip, setIp] = useState('')
-
-  const tableLastBtn = useMemo(() => {
-    return [
-      {
-        title: '操作',
-        render: (item: A4IpType) => (
-          <>
-            <Button
-              size='small'
-              type='text'
-              onClick={() => {
-                setOpId(item.id)
-                setIp(item.ip)
-              }}
-            >
-              编辑
-            </Button>
-
-            <MyPopconfirm txtK='删除' onConfirm={() => delTableFu(item.id)} />
-          </>
-        )
-      }
-    ]
-  }, [delTableFu])
-
-  const btnOk = useCallback(async () => {
-    if (ip === '') return MessageFu.warning('请输入IP地址!')
-
-    const res = await A4_APIipSave({
-      id: opId > 0 ? opId : null,
-      ip
-    })
-
-    if (res.code === 0) {
-      MessageFu.success(opId > 0 ? '编辑成功!' : '新增成功!')
-      setOpId(0)
-      setIp('')
-      getListFu()
-    }
-  }, [getListFu, ip, opId])
-
-  return (
-    <div className={styles.A4ip}>
-      <div className='A4iBox'>
-        <div className='A4iTop'>
-          <h1>IP黑名单</h1>
-          <div>
-            <Button
-              type='primary'
-              onClick={() => {
-                setOpId(-1)
-                setIp('')
-              }}
-            >
-              新增
-            </Button>
-            &emsp; <Button onClick={closeFu}>关闭</Button>
-          </div>
-        </div>
-
-        <MyTable
-          classKey='A4ipTable'
-          yHeight={595}
-          list={ipList}
-          columnsTemp={[['txt', 'IP地址', 'ip']]}
-          lastBtn={tableLastBtn}
-          pagingInfo={false}
-        />
-      </div>
-
-      {opId ? (
-        <Modal
-          wrapClassName={styles.A4ipAdd}
-          open={true}
-          title={opId > 0 ? '编辑' : '新增'}
-          footer={
-            [] // 设置footer为空,去掉 取消 确定默认按钮
-          }
-        >
-          <br />
-          <div className='formRow'>
-            <div className='formLeft'>
-              <span>*</span>IP地址:
-            </div>
-            <div className='formRight'>
-              <Input
-                placeholder='请输入内容'
-                maxLength={20}
-                showCount
-                value={ip}
-                onChange={e => setIp(e.target.value.replace(/[^\d.]/g, ''))}
-              />
-            </div>
-          </div>
-
-          <div className='A4ibtn'>
-            <Button type='primary' onClick={btnOk}>
-              提交
-            </Button>
-            &emsp;
-            <MyPopconfirm
-              txtK='取消'
-              onConfirm={() => {
-                setOpId(0)
-                setIp('')
-              }}
-            />
-          </div>
-        </Modal>
-      ) : null}
-    </div>
-  )
-}
-
-const MemoA4ip = React.memo(A4ip)
-
-export default MemoA4ip

+ 0 - 21
src/pages/A4iosUser/data.ts

@@ -1,21 +0,0 @@
-export type A4FromDataType = {
-  searchKey: string
-  pageNum: number
-  pageSize: number
-  isEnabled: 0 | 1 | ''
-}
-
-export const A4selArr1 = [
-  {
-    value: '',
-    label: '全部'
-  },
-  {
-    value: 0,
-    label: '禁用'
-  },
-  {
-    value: 1,
-    label: '启用'
-  }
-]

+ 0 - 30
src/pages/A4iosUser/index.module.scss

@@ -1,30 +0,0 @@
-.A4iosUser {
-  position: relative;
-  :global {
-    .A4top {
-      border-radius: 10px;
-      background-color: #fff;
-      padding: 15px 24px;
-      display: flex;
-      justify-content: space-between;
-      & > div {
-        display: flex;
-        .A4TopRow {
-          display: flex;
-          align-items: center;
-          margin-right: 20px;
-          .ant-select-selection-placeholder {
-            color: black;
-          }
-        }
-      }
-    }
-    .A4tableBox {
-      border-radius: 10px;
-      overflow: hidden;
-      margin-top: 15px;
-      height: calc(100% - 77px);
-      background-color: #fff;
-    }
-  }
-}

+ 0 - 144
src/pages/A4iosUser/index.tsx

@@ -1,144 +0,0 @@
-import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
-import styles from './index.module.scss'
-import { Button, Input, Select, Switch } from 'antd'
-import { A4FromDataType, A4selArr1 } from './data'
-import { useDispatch, useSelector } from 'react-redux'
-import { A4_APIgetList, A4_APIisEnabled } from '@/store/action/A4iosUser'
-import { RootState } from '@/store'
-import { A4tableType } from '@/types'
-import MyTable from '@/components/MyTable'
-import { A4tableC } from '@/utils/tableData'
-import { MessageFu } from '@/utils/message'
-import A4ip from './A4ip'
-
-const fromDataBase: A4FromDataType = {
-  searchKey: '',
-  pageNum: 1,
-  pageSize: 10,
-  isEnabled: ''
-}
-
-function A4iosUser() {
-  const dispatch = useDispatch()
-
-  const [fromData, setFromData] = useState(fromDataBase)
-
-  const getListFu = useCallback(() => {
-    dispatch(A4_APIgetList(fromData))
-  }, [dispatch, fromData])
-
-  useEffect(() => {
-    getListFu()
-  }, [getListFu])
-
-  const [inputKey, setInputKey] = useState(1)
-
-  // 输入框的输入
-  const timeRef = useRef(-1)
-  const txtChangeFu = useCallback(
-    (e: React.ChangeEvent<HTMLInputElement>, key: 'searchKey') => {
-      clearTimeout(timeRef.current)
-      timeRef.current = window.setTimeout(() => {
-        setFromData({ ...fromData, [key]: e.target.value.replaceAll("'", ''), pageNum: 1 })
-      }, 500)
-    },
-    [fromData]
-  )
-
-  // 点击重置
-  const resetSelectFu = useCallback(() => {
-    setInputKey(Date.now())
-    setFromData({ ...fromDataBase })
-  }, [])
-
-  const tableInfo = useSelector((state: RootState) => state.A4iosUser.tableInfo)
-
-  // 用户状态切换
-  const cutIsEnabled = useCallback(
-    async (id: number, val: 0 | 1) => {
-      const res = await A4_APIisEnabled(id, val ? 0 : 1)
-      if (res.code === 0) {
-        MessageFu.success('操作成功!')
-        getListFu()
-      }
-    },
-    [getListFu]
-  )
-
-  const tableLastBtn = useMemo(() => {
-    return [
-      {
-        title: '用户状态',
-        render: (item: A4tableType) => (
-          <Switch
-            checked={!!item.isEnabled}
-            onChange={() => cutIsEnabled(item.id, item.isEnabled)}
-            checkedChildren='启用'
-            unCheckedChildren='禁用'
-          />
-        )
-      }
-    ]
-  }, [cutIsEnabled])
-
-  const [ipShow, setIpShow] = useState(false)
-
-  return (
-    <div className={styles.A4iosUser}>
-      <div className='pageTitle'>平台用户</div>
-
-      {/* 顶部筛选 */}
-      <div className='A4top'>
-        <div>
-          <div className='A4TopRow'>
-            <span>搜索:</span>
-            <Input
-              key={inputKey}
-              maxLength={20}
-              style={{ width: 192 }}
-              placeholder='请输入用户昵称'
-              allowClear
-              onChange={e => txtChangeFu(e, 'searchKey')}
-            />
-          </div>
-
-          <div className='A4TopRow'>
-            <span>用户状态:</span>
-            <Select
-              style={{ width: 180 }}
-              value={fromData.isEnabled}
-              onChange={e => setFromData({ ...fromData, pageNum: 1, isEnabled: e })}
-              options={A4selArr1}
-            />
-          </div>
-        </div>
-        <div>
-          <Button onClick={resetSelectFu}>重置</Button>&emsp;
-          <Button type='primary' onClick={() => setIpShow(true)}>
-            IP黑名单
-          </Button>
-        </div>
-      </div>
-
-      {/* 表格主体 */}
-      <div className='A4tableBox'>
-        <MyTable
-          yHeight={625}
-          list={tableInfo.list}
-          columnsTemp={A4tableC}
-          lastBtn={tableLastBtn}
-          pageNum={fromData.pageNum}
-          pageSize={fromData.pageSize}
-          total={tableInfo.total}
-          onChange={(pageNum, pageSize) => setFromData({ ...fromData, pageNum, pageSize })}
-        />
-      </div>
-
-      {ipShow ? <A4ip closeFu={() => setIpShow(false)} /> : null}
-    </div>
-  )
-}
-
-const MemoA4iosUser = React.memo(A4iosUser)
-
-export default MemoA4iosUser

+ 0 - 125
src/pages/A5bookAudit/A5look/index.module.scss

@@ -1,125 +0,0 @@
-.A5look {
-  position: absolute;
-  top: 0;
-  left: 0;
-  width: 100%;
-  height: 100%;
-  background-color: #fff;
-  border-radius: 10px;
-  padding: 24px;
-  :global {
-    .A5lMain {
-      padding-right: 400px;
-      width: 100%;
-      height: 100%;
-      overflow: auto;
-    }
-
-    .A5lBtn {
-      font-size: 16px;
-      position: absolute;
-      right: 200px;
-      top: 50%;
-      transform: translateY(-50%);
-      text-align: center;
-    }
-
-    .A5lRow {
-      display: flex;
-      margin-bottom: 20px;
-      font-size: 16px;
-      .A5lLeft {
-        font-weight: 700;
-        width: 120px;
-        text-align: right;
-      }
-      .A5lLeft2 {
-        position: relative;
-        top: 6px;
-      }
-      .A5lRight {
-        width: calc(100% - 120px);
-        .ant-select {
-          pointer-events: none;
-          .ant-select-selector {
-            font-size: 16px;
-            border: none;
-            padding: 0;
-          }
-          .ant-select-arrow {
-            display: none;
-          }
-        }
-      }
-    }
-    .A5lRow2 {
-      margin-bottom: 15px;
-    }
-
-    .A5Ladd {
-      position: absolute;
-      top: 0;
-      left: 0;
-      width: 100%;
-      height: 100%;
-      z-index: 10;
-      padding: 50px 100px;
-      background-color: rgba(0, 0, 0, 0.6);
-      border-radius: 10px;
-      & > div {
-        width: 100%;
-        height: 100%;
-        position: relative;
-      }
-    }
-  }
-}
-
-// 审核
-.A5lAduit {
-  :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;
-        }
-      }
-    }
-
-    .A5lAduitBtn {
-      text-align: center;
-      margin-top: 50px;
-    }
-  }
-}

+ 0 - 318
src/pages/A5bookAudit/A5look/index.tsx

@@ -1,318 +0,0 @@
-import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
-import styles from './index.module.scss'
-import { A5tableType } from '@/types'
-import ZupOne from '@/components/ZupOne'
-import { Button, Cascader, Input, Modal } from 'antd'
-import { A2_APIgetList1, A2_APIgetList2 } from '@/store/action/A2classify'
-import { useDispatch, useSelector } from 'react-redux'
-import { RootState } from '@/store'
-import { A5selArr1 } from '../data'
-import MyPopconfirm from '@/components/MyPopconfirm'
-import { A5_APIaudit, A5_APIgetInfo } from '@/store/action/A5bookAudit'
-import { MessageFu } from '@/utils/message'
-import A1add from '@/pages/A1manage/A1add'
-const { TextArea } = Input
-
-type Props = {
-  info: A5tableType
-  closeFuOne: () => void
-  editTableFu: () => void
-}
-
-function A5look({ info, closeFuOne, editTableFu }: Props) {
-  const dispatch = useDispatch()
-  // 占位ref
-  const imgRef = useRef<any>(null)
-  const ZupTxtRef = useRef<any>(null)
-
-  // 获取中图法分类 和 展示分类
-  useEffect(() => {
-    dispatch(A2_APIgetList1())
-    dispatch(A2_APIgetList2({ pageNum: 1, pageSize: 9999, searchKey: '' }))
-  }, [dispatch])
-
-  const { treeData: storageArr, tableInfo: exhibitTypeObj } = useSelector(
-    (state: RootState) => state.A2classify
-  )
-
-  const [storageIds, setStorageIds] = useState<any>([])
-
-  // 审核状态外面页面
-  const [auditStatus, setAuditStatus] = useState<'' | 0 | 1 | 2>('')
-
-  const auditStatusTxt = useMemo(() => {
-    let txt = ''
-    let obj = A5selArr1.find(v => v.value === auditStatus)
-    if (obj) txt = obj.label
-    return txt
-  }, [auditStatus])
-
-  // 审核状态-里面
-  const [auditStatus2, setAuditStatus2] = useState<'' | 0 | 1 | 2>('')
-
-  // 审核人
-  const [auditBy, setAuditBy] = useState('')
-
-  // 审核时间
-  const [auditTime, setAuditTime] = useState('')
-
-  // 审核备注
-  const [auditDesc, setAuditDesc] = useState('')
-
-  useEffect(() => {
-    // 设置封面图
-    imgRef.current?.setFileComFileFu({
-      fileName: '',
-      filePath: info.thumb
-    })
-
-    // 设置附件
-    ZupTxtRef.current?.setFileComFileFu({
-      fileName: info.fileName,
-      filePath: info.filePath
-    })
-
-    let storageIds: number[] = []
-    if (info.ancestor) storageIds = info.ancestor.split(',').map((v: string) => Number(v))
-    storageIds.push(Number(info.storageId))
-
-    setStorageIds(storageIds)
-
-    // 设置审核状态
-    setAuditStatus(info.auditStatus)
-
-    setAuditBy(info.creatorName)
-    setAuditTime(info.auditTime)
-    setAuditDesc(info.auditDesc)
-  }, [info])
-
-  // 审核页面
-  const [aduitShow, setAduitShow] = useState(false)
-
-  useEffect(() => {
-    if (aduitShow) setAuditStatus2(auditStatus)
-    else setAuditStatus2('')
-  }, [aduitShow, auditStatus, info.auditStatus])
-
-  // 审核点击确定
-  const btnOk = useCallback(async () => {
-    const obj = {
-      id: info.id,
-      auditDesc,
-      auditStatus: auditStatus2
-    }
-    const res = await A5_APIaudit(obj)
-    if (res.code === 0) {
-      MessageFu.success('审核成功!')
-      const res2 = await A5_APIgetInfo(info.id)
-      if (res2.code === 0) {
-        const data: A5tableType = res2.data
-
-        setAuditStatus(data.auditStatus)
-        setAuditBy(data.creatorName)
-        setAuditTime(data.auditTime)
-        setAuditDesc(data.auditDesc)
-        setAduitShow(false)
-
-        editTableFu()
-      }
-    }
-  }, [auditDesc, auditStatus2, editTableFu, info.id])
-
-  // 点击创建图书
-  const [creatorShow, setCreatorShow] = useState(false)
-
-  return (
-    <div className={styles.A5look}>
-      <div className='A5lMain'>
-        <div className='A5lRow'>
-          <div className='A5lLeft'>书名:</div>
-          <div className='A5lRight'>{info.name || '(空)'}</div>
-        </div>
-        <div className='A5lRow'>
-          <div className='A5lLeft'>简介:</div>
-          <div className='A5lRight'>{info.description || '(空)'}</div>
-        </div>
-        <div className='A5lRow'>
-          <div className='A5lLeft'>作者:</div>
-          <div className='A5lRight'>{info.author || '(空)'}</div>
-        </div>
-        <div className='A5lRow'>
-          <div className='A5lLeft'>出版社:</div>
-          <div className='A5lRight'>{info.press || '(空)'}</div>
-        </div>
-        <div className='A5lRow A5lRow2'>
-          <div className='A5lLeft'>出版年份:</div>
-          <div className='A5lRight'>{info.year || '(空)'}</div>
-        </div>
-        <div className='A5lRow'>
-          <div className='A5lLeft A5lLeft2'>封面:</div>
-          <div className='A5lRight'>
-            <ZupOne
-              ref={imgRef}
-              isLook={true}
-              fileCheck={false}
-              size={5}
-              dirCode={'A1manage'}
-              myUrl='cms/book/upload'
-              format={['image/jpeg', 'image/png']}
-              formatTxt='png、jpg和jpeg'
-              checkTxt='请上传封面图!'
-              upTxt='最多1张'
-              myType='thumb'
-            />
-          </div>
-        </div>
-        <div className='A5lRow'>
-          <div className='A5lLeft A5lLeft2'>中图法分类:</div>
-          <div className='A5lRight'>
-            <Cascader
-              allowClear={false}
-              changeOnSelect
-              style={{ width: 300 }}
-              options={storageArr}
-              fieldNames={{ label: 'name', value: 'id', children: 'children' }}
-              placeholder='请选择'
-              value={storageIds}
-            />
-          </div>
-        </div>
-        <div className='A5lRow'>
-          <div className='A5lLeft'>展示分类:</div>
-          <div className='A5lRight'>{info.exhibitTypeName || '(空)'}</div>
-        </div>
-        <div className='A5lRow'>
-          <div className='A5lLeft'>ISBN编号:</div>
-          <div className='A5lRight'>{info.num || '(空)'}</div>
-        </div>
-        <div className='A5lRow'>
-          <div className='A5lLeft'>附件:</div>
-          <div className='A5lRight'>
-            <ZupOne
-              ref={ZupTxtRef}
-              isLook={true}
-              fileCheck={false}
-              size={30}
-              dirCode='A1manage'
-              myUrl='cms/book/upload'
-              format={['']}
-              formatTxt='epub'
-              checkTxt='请上传epub附件!'
-              upTxt='最多1个'
-              myType='epub'
-            />
-          </div>
-        </div>
-        <div className='A5lRow'>
-          <div className='A5lLeft'>提交人:</div>
-          <div className='A5lRight'>{info.wxUserName || '(空)'}</div>
-        </div>
-        <div className='A5lRow'>
-          <div className='A5lLeft'>提交时间:</div>
-          <div className='A5lRight'>{info.createTime || '(空)'}</div>
-        </div>
-      </div>
-
-      {/* 右侧按钮 */}
-      <div className='A5lBtn'>
-        审核状态:{auditStatusTxt}
-        <br /> <br />
-        <Button type='primary' onClick={() => setAduitShow(true)}>
-          审核
-        </Button>
-        <br /> <br />
-        <Button type='primary' onClick={() => setCreatorShow(true)}>
-          创建图书
-        </Button>
-        <br /> <br />
-        <Button onClick={closeFuOne}>返回</Button>
-      </div>
-
-      {/* 审核出来的页面 */}
-      {aduitShow ? (
-        <Modal
-          wrapClassName={styles.A5lAduit}
-          open={true}
-          title='审核'
-          footer={
-            [] // 设置footer为空,去掉 取消 确定默认按钮
-          }
-        >
-          <div className='formRow'>
-            <div className='formLeft formLeft2'>审核状态:</div>
-            <div className='formRight'>
-              {A5selArr1.filter(v => v.label !== '全部').map(v => (
-                <Button
-                  onClick={() => setAuditStatus2(v.value as 0)}
-                  type={v.value === auditStatus2 ? 'primary' : 'default'}
-                  key={v.value}
-                >
-                  {v.label}
-                </Button>
-              ))}
-            </div>
-          </div>
-
-          <div className='formRow'>
-            <div className='formLeft'>
-              <span></span>审核人:
-            </div>
-            <div className='formRight'>{auditBy || '(空)'}</div>
-          </div>
-
-          <div className='formRow'>
-            <div className='formLeft'>
-              <span></span>审核时间:
-            </div>
-            <div className='formRight'>{auditTime || '(空)'}</div>
-          </div>
-
-          <div className='formRow'>
-            <div className='formLeft'>
-              <span></span>审核备注:
-            </div>
-            <div className='formRight'>
-              <TextArea
-                value={auditDesc}
-                onChange={e => setAuditDesc(e.target.value)}
-                rows={6}
-                placeholder='请输入内容'
-                maxLength={200}
-                showCount
-              />
-            </div>
-          </div>
-
-          <div className='A5lAduitBtn'>
-            <Button type='primary' onClick={btnOk}>
-              提交
-            </Button>
-            &emsp;
-            <MyPopconfirm txtK='取消' onConfirm={() => setAduitShow(false)} />
-          </div>
-        </Modal>
-      ) : null}
-
-      {/* 点击创建图书 */}
-      {creatorShow ? (
-        <div className='A5Ladd'>
-          <div>
-            <A1add
-              editInfo={{ id: info.id, txt: '编辑' }}
-              closeFu={() => setCreatorShow(false)}
-              addTableFu={() => {}}
-              editTableFu={() => {}}
-              storageArr={storageArr}
-              exhibitTypeArr={exhibitTypeObj.list}
-              isAudit={true}
-            />
-          </div>
-        </div>
-      ) : null}
-    </div>
-  )
-}
-
-const MemoA5look = React.memo(A5look)
-
-export default MemoA5look

+ 0 - 25
src/pages/A5bookAudit/data.ts

@@ -1,25 +0,0 @@
-export type A5FromDataType = {
-  auditStatus: '' | 0 | 1 | 2
-  searchKey: string
-  num: string
-  pageNum: number
-  pageSize: number
-}
-export const A5selArr1 = [
-  {
-    value: '',
-    label: '全部'
-  },
-  {
-    value: 0,
-    label: '待审核'
-  },
-  {
-    value: 1,
-    label: '审核通过'
-  },
-  {
-    value: 2,
-    label: '审核驳回'
-  }
-]

+ 0 - 161
src/pages/A5bookAudit/index.tsx

@@ -1,161 +0,0 @@
-import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
-import styles from './index.module.scss'
-import { A5FromDataType, A5selArr1 } from './data'
-import { useDispatch, useSelector } from 'react-redux'
-import { A5_APIdel, A5_APIgetList } from '@/store/action/A5bookAudit'
-import { RootState } from '@/store'
-import { MessageFu } from '@/utils/message'
-import { A5tableType } from '@/types'
-import { Button, Input, Select } from 'antd'
-import MyPopconfirm from '@/components/MyPopconfirm'
-import MyTable from '@/components/MyTable'
-import { A5tableC } from '@/utils/tableData'
-import A5look from './A5look'
-
-const fromDataBase: A5FromDataType = {
-  auditStatus: '',
-  searchKey: '',
-  num: '',
-  pageNum: 1,
-  pageSize: 10
-}
-
-function A5bookAudit() {
-  const dispatch = useDispatch()
-
-  const [fromData, setFromData] = useState(fromDataBase)
-
-  const getListFu = useCallback(() => {
-    dispatch(A5_APIgetList(fromData))
-  }, [dispatch, fromData])
-
-  useEffect(() => {
-    getListFu()
-  }, [getListFu])
-
-  const [inputKey, setInputKey] = useState(1)
-
-  // 输入框的输入
-  const timeRef = useRef(-1)
-  const txtChangeFu = useCallback(
-    (e: React.ChangeEvent<HTMLInputElement>, key: 'searchKey' | 'num') => {
-      clearTimeout(timeRef.current)
-      timeRef.current = window.setTimeout(() => {
-        setFromData({ ...fromData, [key]: e.target.value.replaceAll("'", ''), pageNum: 1 })
-      }, 500)
-    },
-    [fromData]
-  )
-
-  // 点击重置
-  const resetSelectFu = useCallback(() => {
-    setInputKey(Date.now())
-    setFromData({ ...fromDataBase })
-  }, [])
-
-  const tableInfo = useSelector((state: RootState) => state.A5bookAudit.tableInfo)
-
-  const delTableFu = useCallback(
-    async (id: number) => {
-      const res = await A5_APIdel(id)
-      if (res.code === 0) {
-        MessageFu.success('删除成功!')
-        getListFu()
-      }
-    },
-    [getListFu]
-  )
-
-  const tableLastBtn = useMemo(() => {
-    return [
-      {
-        title: '操作',
-        render: (item: A5tableType) => (
-          <>
-            <Button size='small' type='text' onClick={() => setLookInfo(item)}>
-              查看
-            </Button>
-
-            <MyPopconfirm txtK='删除' onConfirm={() => delTableFu(item.id)} />
-          </>
-        )
-      }
-    ]
-  }, [delTableFu])
-
-  // 点击查看
-  const [lookInfo, setLookInfo] = useState({} as A5tableType)
-
-  return (
-    <div className={styles.A5bookAudit}>
-      <div className='pageTitle'>图书审核{lookInfo.id ? ' - 查看' : ''}</div>
-
-      {/* 顶部筛选 */}
-      <div className='A5top'>
-        <div>
-          <div className='A5TopRow'>
-            <span>搜索:</span>
-            <Input
-              key={inputKey}
-              maxLength={20}
-              style={{ width: 200 }}
-              placeholder='请输入书名/作者/出版社'
-              allowClear
-              onChange={e => txtChangeFu(e, 'searchKey')}
-            />
-            &nbsp;
-            <Input
-              key={inputKey + 1}
-              maxLength={20}
-              style={{ width: 200 }}
-              placeholder='请输入完整ISBN编号'
-              allowClear
-              onChange={e => txtChangeFu(e, 'num')}
-            />
-          </div>
-
-          <div className='A5TopRow'>
-            <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='A5tableBox'>
-        <MyTable
-          yHeight={625}
-          list={tableInfo.list}
-          columnsTemp={A5tableC}
-          lastBtn={tableLastBtn}
-          pageNum={fromData.pageNum}
-          pageSize={fromData.pageSize}
-          total={tableInfo.total}
-          onChange={(pageNum, pageSize) => setFromData({ ...fromData, pageNum, pageSize })}
-        />
-      </div>
-
-      {/* 点击查看 */}
-      {lookInfo.id ? (
-        <A5look
-          info={lookInfo}
-          closeFuOne={() => setLookInfo({} as A5tableType)}
-          editTableFu={getListFu}
-        />
-      ) : null}
-    </div>
-  )
-}
-
-const MemoA5bookAudit = React.memo(A5bookAudit)
-
-export default MemoA5bookAudit

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

@@ -1,108 +0,0 @@
-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

+ 0 - 79
src/pages/A6remarkAudit/index.module.scss

@@ -1,79 +0,0 @@
-.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;
-    }
-  }
-}

+ 0 - 121
src/pages/A6remarkAudit/index.tsx

@@ -1,121 +0,0 @@
-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}>
-      <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)
-
-export default MemoA6remarkAudit

+ 0 - 182
src/pages/A7notice/A7add/index.tsx

@@ -1,182 +0,0 @@
-import React, { useCallback, useEffect, useRef, useState } from 'react'
-import styles from './index.module.scss'
-import { A1EditInfoType } from '@/pages/A1manage/data'
-import { Button, Form, FormInstance, Input, InputNumber, Select } from 'antd'
-import classNames from 'classnames'
-import { A7_APIgetInfo, A7_APIsave } from '@/store/action/A7notice'
-import { MessageFu } from '@/utils/message'
-import { useSelector } from 'react-redux'
-import { RootState } from '@/store'
-import MyPopconfirm from '@/components/MyPopconfirm'
-import ZRichTexts from '@/components/ZRichTexts'
-
-type Props = {
-  editInfo: A1EditInfoType
-  closeFu: () => void
-  addTableFu: () => void
-  editTableFu: () => void
-}
-
-function A7add({ editInfo, closeFu, addTableFu, editTableFu }: Props) {
-  const { typeList } = useSelector((state: RootState) => state.A7notice)
-
-  // 表单的ref
-  const FormBoxRef = useRef<FormInstance>(null)
-
-  // 富文本的ref
-  const ZRichTextRef = useRef<any>(null)
-
-  // 编辑/查看 进入页面 获取信息
-  const getInfoFu = useCallback(async (id: number) => {
-    const res = await A7_APIgetInfo(id)
-    if (res.code === 0) {
-      const data = res.data
-
-      // 设置富文本
-      ZRichTextRef.current?.ritxtShowFu(JSON.parse(data.description || '{}'))
-
-      FormBoxRef.current?.setFieldsValue(data)
-    }
-  }, [])
-
-  useEffect(() => {
-    if (editInfo.id > 0) {
-      getInfoFu(editInfo.id)
-    } else {
-      FormBoxRef.current?.setFieldsValue({
-        sort: 999
-      })
-    }
-  }, [editInfo.id, getInfoFu])
-
-  // 附件 是否 已经点击过确定
-  const [fileCheck, setFileCheck] = useState(false)
-
-  // 没有通过校验
-  const onFinishFailed = useCallback(() => {
-    setFileCheck(true)
-  }, [])
-
-  //  通过校验点击确定
-  const onFinish = useCallback(
-    async (values: any) => {
-      setFileCheck(true)
-
-      // 富文本校验不通过
-      const rtf = ZRichTextRef.current?.fatherBtnOkFu() || { flag: true }
-
-      if (rtf.flag) return MessageFu.warning('请输入完整正文!')
-
-      const obj = {
-        ...values,
-        id: editInfo.id > 0 ? editInfo.id : null,
-        description: JSON.stringify(rtf.val || '')
-      }
-
-      // if (obj) {
-      //   console.log(123, obj);
-      //   return;
-      // }
-
-      const res = await A7_APIsave(obj)
-
-      if (res.code === 0) {
-        MessageFu.success(`${editInfo.txt}成功!`)
-        editInfo.id > 0 ? editTableFu() : addTableFu()
-        closeFu()
-      }
-    },
-    [addTableFu, closeFu, editInfo.id, editInfo.txt, editTableFu]
-  )
-
-  return (
-    <div className={styles.A7add}>
-      <div className={classNames('A7aMain', editInfo.txt === '查看' ? 'A7aMainLook' : '')}>
-        <Form
-          ref={FormBoxRef}
-          name='basic'
-          labelCol={{ span: 3 }}
-          onFinish={onFinish}
-          onFinishFailed={onFinishFailed}
-          autoComplete='off'
-          scrollToFirstError
-        >
-          <Form.Item label='标题' name='name' rules={[{ required: true, message: '请输入标题!' }]}>
-            <Input
-              readOnly={editInfo.txt === '查看'}
-              placeholder='请输入内容'
-              maxLength={20}
-              showCount
-            />
-          </Form.Item>
-
-          <Form.Item
-            label='公告类型'
-            name='dictId'
-            rules={[{ required: true, message: '请选择公告类型!' }]}
-          >
-            <Select
-              placeholder='请选择'
-              fieldNames={{ label: 'name', value: 'id' }}
-              style={{ width: 200 }}
-              options={typeList}
-            />
-          </Form.Item>
-
-          {/* 封面 */}
-          <div className='formRow'>
-            <div className='formLeft'>
-              <span>* </span>
-              正文:
-            </div>
-            <div className='formRight'>
-              <ZRichTexts
-                check={fileCheck}
-                dirCode={'A7notice'}
-                isLook={editInfo.txt === '查看'}
-                ref={ZRichTextRef}
-                myUrl='cms/notice/upload'
-                isOne={true}
-                upAudioBtnNone={true}
-              />
-            </div>
-          </div>
-          {/* {editInfo.txt === '查看' ? <br /> : null} */}
-
-          <div className='A1fromRow'>
-            <Form.Item
-              label='排序值'
-              name='sort'
-              rules={[{ required: true, message: '请输入排序值!' }]}
-            >
-              <InputNumber min={1} max={999} precision={0} placeholder='请输入' />
-            </Form.Item>
-            <div className='A1_6Frow' hidden={editInfo.txt === '查看'}>
-              请输入1~999的数字。数字越小,排序越靠前。数字相同时,更新发布的内容排在前面
-            </div>
-          </div>
-
-          {/* 确定和取消按钮 */}
-          <Form.Item className='A7abtn'>
-            {editInfo.txt === '查看' ? (
-              <Button onClick={closeFu}>返回</Button>
-            ) : (
-              <>
-                <Button type='primary' htmlType='submit'>
-                  提交
-                </Button>
-                <br />
-                <br />
-                <MyPopconfirm txtK='取消' onConfirm={closeFu} />
-              </>
-            )}
-          </Form.Item>
-        </Form>
-      </div>
-    </div>
-  )
-}
-
-const MemoA7add = React.memo(A7add)
-
-export default MemoA7add

+ 0 - 63
src/pages/A7notice/A7type/index.module.scss

@@ -1,63 +0,0 @@
-.A7type {
-  width: 100%;
-  height: 100%;
-  padding: 24px;
-  background-color: #fff;
-  border-radius: 10px;
-
-  :global {
-    .A7tTitle {
-      display: flex;
-      justify-content: space-between;
-    }
-    .A7tTable {
-      border-radius: 10px;
-      overflow: hidden;
-      margin-top: 15px;
-      height: calc(100% - 77px);
-    }
-  }
-}
-
-// 新增 、编辑弹窗
-.A7tAdd {
-  :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;
-    }
-
-    .A7tMain {
-      width: 100%;
-      height: 100%;
-      overflow-y: auto;
-      position: relative;
-
-      .A7tFromRow {
-        position: relative;
-
-        .A7tFrowTit {
-          position: absolute;
-          left: 180px;
-          top: 5px;
-          color: #999;
-          font-size: 12px;
-        }
-      }
-
-      .ant-form {
-        .A7tBtn {
-          text-align: center;
-          margin-top: 30px;
-        }
-      }
-    }
-  }
-}

+ 0 - 171
src/pages/A7notice/A7type/index.tsx

@@ -1,171 +0,0 @@
-import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
-import styles from './index.module.scss'
-import { Button, Form, FormInstance, Input, InputNumber, Modal } from 'antd'
-import { useDispatch, useSelector } from 'react-redux'
-import { RootState } from '@/store'
-import { A7_APIdel2, A7_APIgetList2, A7_APIsave2 } from '@/store/action/A7notice'
-import MyTable from '@/components/MyTable'
-import { MessageFu } from '@/utils/message'
-import { A7tableType, A7typeType } from '@/types'
-import MyPopconfirm from '@/components/MyPopconfirm'
-import { A7tableCtype } from '@/utils/tableData'
-
-type Props = {
-  closeFu: () => void
-}
-
-function A7type({ closeFu }: Props) {
-  const dispatch = useDispatch()
-
-  useEffect(() => {
-    dispatch(A7_APIgetList2())
-  }, [dispatch])
-
-  const { typeList } = useSelector((state: RootState) => state.A7notice)
-
-  const delTableFu = useCallback(
-    async (id: number) => {
-      const res = await A7_APIdel2(id)
-      if (res.code === 0) {
-        MessageFu.success('删除成功!')
-        dispatch(A7_APIgetList2())
-      }
-    },
-    [dispatch]
-  )
-
-  const tableLastBtn = useMemo(() => {
-    return [
-      {
-        title: '操作',
-        render: (item: A7typeType) =>
-          item.id === 5 ? (
-            ' - '
-          ) : (
-            <>
-              <Button size='small' type='text' onClick={() => setEditInfo(item)}>
-                编辑
-              </Button>
-              <MyPopconfirm txtK='删除' onConfirm={() => delTableFu(item.id)} />
-            </>
-          )
-      }
-    ]
-  }, [delTableFu])
-
-  // 新增和编辑
-  const [editInfo, setEditInfo] = useState({} as A7typeType)
-
-  useEffect(() => {
-    FormBoxRef.current?.setFieldsValue(editInfo)
-  }, [editInfo])
-
-  // 表单的ref
-  const FormBoxRef = useRef<FormInstance>(null)
-
-  // 没有通过校验
-  const onFinishFailed = useCallback(() => {}, [])
-
-  //  通过校验点击确定
-  const onFinish = useCallback(
-    async (values: any) => {
-      const res = await A7_APIsave2({
-        id: editInfo.id > 0 ? editInfo.id : null,
-        name: values.name,
-        sort: values.sort,
-        type: 'notice',
-        display: 1
-      })
-      if (res.code === 0) {
-        MessageFu.success(editInfo.id > 0 ? '编辑成功!' : '新增成功!')
-        setEditInfo({} as A7typeType)
-        dispatch(A7_APIgetList2())
-      }
-    },
-    [dispatch, editInfo.id]
-  )
-
-  return (
-    <div className={styles.A7type}>
-      <div className='A7tTitle'>
-        <h1>公告类型</h1>
-        <div>
-          <Button type='primary' onClick={() => setEditInfo({ id: -1, name: '', sort: 999 })}>
-            新增
-          </Button>
-          &emsp;
-          <Button onClick={closeFu}>关闭</Button>
-        </div>
-      </div>
-
-      <div className='A7tTable'>
-        <MyTable
-          classKey='A7tTable'
-          yHeight={580}
-          list={typeList}
-          columnsTemp={A7tableCtype}
-          lastBtn={tableLastBtn}
-          pagingInfo={false}
-        />
-      </div>
-
-      {/* 新增/编辑 */}
-      {editInfo.id ? (
-        <Modal
-          wrapClassName={styles.A7tAdd}
-          open={true}
-          title={editInfo.id > 0 ? '编辑' : '新增'}
-          footer={
-            [] // 设置footer为空,去掉 取消 确定默认按钮
-          }
-        >
-          <div className='A7tMain'>
-            <Form
-              ref={FormBoxRef}
-              name='basic'
-              labelCol={{ span: 2 }}
-              onFinish={onFinish}
-              onFinishFailed={onFinishFailed}
-              autoComplete='off'
-              scrollToFirstError
-            >
-              <Form.Item
-                label='标题'
-                name='name'
-                rules={[{ required: true, message: '请输入标题!' }]}
-              >
-                <Input placeholder='请输入内容' maxLength={20} showCount />
-              </Form.Item>
-
-              <div className='A7tFromRow'>
-                <Form.Item
-                  label='排序值'
-                  name='sort'
-                  rules={[{ required: true, message: '请输入排序值!' }]}
-                >
-                  <InputNumber min={1} max={999} precision={0} placeholder='请输入' />
-                </Form.Item>
-                <div className='A7tFrowTit'>
-                  请输入1~999的数字。数字越小,排序越靠前。数字相同时,更新发布的内容排在前面
-                </div>
-              </div>
-
-              {/* 确定和取消按钮 */}
-              <Form.Item className='A7tBtn'>
-                <Button type='primary' htmlType='submit'>
-                  提交
-                </Button>
-                &emsp;
-                <MyPopconfirm txtK='取消' onConfirm={() => setEditInfo({} as A7tableType)} />
-              </Form.Item>
-            </Form>
-          </div>
-        </Modal>
-      ) : null}
-    </div>
-  )
-}
-
-const MemoA7type = React.memo(A7type)
-
-export default MemoA7type

+ 0 - 6
src/pages/A7notice/data.ts

@@ -1,6 +0,0 @@
-export type A7FromDataType = {
-  searchKey: string
-  dictId: number | null
-  pageNum: number
-  pageSize: number
-}

+ 0 - 45
src/pages/A7notice/index.module.scss

@@ -1,45 +0,0 @@
-.A7notice {
-  position: relative;
-  :global {
-    .A7top {
-      border-radius: 10px;
-      background-color: #fff;
-      padding: 15px 24px;
-      display: flex;
-      justify-content: space-between;
-      & > div {
-        display: flex;
-        .A7TopRow {
-          display: flex;
-          align-items: center;
-          margin-right: 20px;
-          .ant-select-selection-placeholder {
-            color: black;
-          }
-        }
-      }
-    }
-    .A7tableBox {
-      border-radius: 10px;
-      overflow: hidden;
-      margin-top: 15px;
-      height: calc(100% - 77px);
-      background-color: #fff;
-    }
-
-    .A7type {
-      position: absolute;
-      top: 0;
-      left: 0;
-      width: 100%;
-      height: 100%;
-      border-radius: 10px;
-      padding: 50px 100px;
-      background-color: rgba(0, 0, 0, 0.6);
-      & > div {
-        width: 100%;
-        height: 100%;
-      }
-    }
-  }
-}

+ 0 - 192
src/pages/A7notice/index.tsx

@@ -1,192 +0,0 @@
-import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
-import styles from './index.module.scss'
-import { A7FromDataType } from './data'
-import { useDispatch, useSelector } from 'react-redux'
-import { A7_APIdel, A7_APIgetList, A7_APIgetList2 } from '@/store/action/A7notice'
-import { RootState } from '@/store'
-import { MessageFu } from '@/utils/message'
-import { A7tableType } from '@/types'
-import { Button, Input, Select } from 'antd'
-import MyPopconfirm from '@/components/MyPopconfirm'
-import { A1EditInfoType } from '../A1manage/data'
-import MyTable from '@/components/MyTable'
-import { A7tableC } from '@/utils/tableData'
-import A7type from './A7type'
-import A7add from './A7add'
-
-const fromDataBase: A7FromDataType = {
-  dictId: null,
-  searchKey: '',
-  pageNum: 1,
-  pageSize: 10
-}
-
-function A7notice() {
-  const dispatch = useDispatch()
-
-  useEffect(() => {
-    dispatch(A7_APIgetList2())
-  }, [dispatch])
-
-  const [fromData, setFromData] = useState(fromDataBase)
-
-  const getListFu = useCallback(() => {
-    dispatch(A7_APIgetList(fromData))
-  }, [dispatch, fromData])
-
-  useEffect(() => {
-    getListFu()
-  }, [getListFu])
-
-  const [inputKey, setInputKey] = useState(1)
-
-  // 输入框的输入
-  const timeRef = useRef(-1)
-  const txtChangeFu = useCallback(
-    (e: React.ChangeEvent<HTMLInputElement>, key: 'searchKey') => {
-      clearTimeout(timeRef.current)
-      timeRef.current = window.setTimeout(() => {
-        setFromData({ ...fromData, [key]: e.target.value.replaceAll("'", ''), pageNum: 1 })
-      }, 500)
-    },
-    [fromData]
-  )
-
-  // 点击重置
-  const resetSelectFu = useCallback(() => {
-    setInputKey(Date.now())
-    setFromData({ ...fromDataBase })
-  }, [])
-
-  const { tableInfo, typeList } = useSelector((state: RootState) => state.A7notice)
-
-  const delTableFu = useCallback(
-    async (id: number) => {
-      const res = await A7_APIdel(id)
-      if (res.code === 0) {
-        MessageFu.success('删除成功!')
-        getListFu()
-      }
-    },
-    [getListFu]
-  )
-
-  const tableLastBtn = useMemo(() => {
-    return [
-      {
-        title: '操作',
-        render: (item: A7tableType) => (
-          <>
-            <Button
-              size='small'
-              type='text'
-              onClick={() => setEditInfo({ id: item.id, txt: '查看' })}
-            >
-              查看
-            </Button>
-            <Button
-              size='small'
-              type='text'
-              onClick={() => setEditInfo({ id: item.id, txt: '编辑' })}
-            >
-              编辑
-            </Button>
-            <MyPopconfirm txtK='删除' onConfirm={() => delTableFu(item.id)} />
-          </>
-        )
-      }
-    ]
-  }, [delTableFu])
-
-  //查看、新增、编辑
-  const [editInfo, setEditInfo] = useState<A1EditInfoType>({
-    id: 0,
-    txt: ''
-  })
-
-  // 公告类型显示隐藏
-  const [typeShow, setTypeShow] = useState(false)
-
-  return (
-    <div className={styles.A7notice}>
-      <div className='pageTitle'>公告管理 {editInfo.id ? ` - ${editInfo.txt}` : ''}</div>
-
-      {/* 顶部筛选 */}
-      <div className='A7top'>
-        <div>
-          <div className='A7TopRow'>
-            <span>搜索:</span>
-            <Input
-              key={inputKey}
-              maxLength={20}
-              style={{ width: 200 }}
-              placeholder='请输入公告标题'
-              allowClear
-              onChange={e => txtChangeFu(e, 'searchKey')}
-            />
-          </div>
-
-          <div className='A7TopRow'>
-            <span>展示分类:</span>
-            <Select
-              allowClear
-              placeholder='全部'
-              style={{ width: 200 }}
-              value={fromData.dictId}
-              fieldNames={{ label: 'name', value: 'id' }}
-              onChange={e => setFromData({ ...fromData, pageNum: 1, dictId: e })}
-              options={typeList}
-            />
-          </div>
-        </div>
-        <div>
-          <Button onClick={resetSelectFu}>重置</Button>&emsp;
-          <Button type='primary' onClick={() => setTypeShow(true)}>
-            公告类型
-          </Button>
-          &emsp;
-          <Button type='primary' onClick={() => setEditInfo({ id: -1, txt: '新增' })}>
-            新增
-          </Button>
-        </div>
-      </div>
-
-      {/* 表格主体 */}
-      <div className='A7tableBox'>
-        <MyTable
-          yHeight={625}
-          list={tableInfo.list}
-          columnsTemp={A7tableC}
-          lastBtn={tableLastBtn}
-          pageNum={fromData.pageNum}
-          pageSize={fromData.pageSize}
-          total={tableInfo.total}
-          onChange={(pageNum, pageSize) => setFromData({ ...fromData, pageNum, pageSize })}
-        />
-      </div>
-
-      {/* 公告类型 */}
-      {typeShow ? (
-        <div className='A7type'>
-          <div>
-            <A7type closeFu={() => setTypeShow(false)} />
-          </div>
-        </div>
-      ) : null}
-
-      {/* 新增/编辑 */}
-      {editInfo.id ? (
-        <A7add
-          editInfo={editInfo}
-          closeFu={() => setEditInfo({ id: 0, txt: '新增' })}
-          addTableFu={resetSelectFu}
-          editTableFu={getListFu}
-        />
-      ) : null}
-    </div>
-  )
-}
-
-const MemoA7notice = React.memo(A7notice)
-
-export default MemoA7notice

+ 7 - 37
src/pages/Layout/data.ts

@@ -4,49 +4,19 @@ import React from 'react'
 const tabLeftArr: RouterType = [
   {
     id: 1,
-    name: '内容发布',
+    name: '智行岳阳',
     son: [
       {
         id: 200,
-        name: '图书管理',
+        name: '景点设置',
         path: '/',
-        Com: React.lazy(() => import('../A1manage'))
+        Com: React.lazy(() => import('../A1scene'))
       },
       {
         id: 300,
-        name: '图书分类',
-        path: '/classify',
-        Com: React.lazy(() => import('../A2classify'))
-      },
-      {
-        id: 400,
-        name: '图书推荐',
-        path: '/recommend',
-        Com: React.lazy(() => import('../A3recommend'))
-      },
-      {
-        id: 500,
-        name: '平台用户',
-        path: '/iosUser',
-        Com: React.lazy(() => import('../A4iosUser'))
-      },
-      {
-        id: 600,
-        name: '图书审核',
-        path: '/bookAudit',
-        Com: React.lazy(() => import('../A5bookAudit'))
-      },
-      {
-        id: 700,
-        name: '评论审核',
-        path: '/remarkAudit',
-        Com: React.lazy(() => import('../A6remarkAudit'))
-      },
-      {
-        id: 800,
-        name: '公告管理',
-        path: '/notice',
-        Com: React.lazy(() => import('../A7notice'))
+        name: '路线设置',
+        path: '/line',
+        Com: React.lazy(() => import('../A2line'))
       }
     ]
   },
@@ -57,7 +27,7 @@ const tabLeftArr: RouterType = [
     son: [
       {
         id: 2100,
-        name: '后台用户',
+        name: '用户管理',
         path: '/user',
         Com: React.lazy(() => import('../Z1user'))
       },

+ 20 - 14
src/pages/Layout/index.module.scss

@@ -6,13 +6,14 @@
   :global {
     .layoutLeft {
       position: relative;
-      width: 220px;
+      width: 285px;
       height: 100%;
       background-color: var(--themeColor2);
 
       .layoutLeftTop {
+        height: 140px;
         text-align: center;
-        padding: 20px;
+        padding: 12px 30px;
 
         & > img {
           width: 208px;
@@ -20,24 +21,32 @@
       }
 
       .layoutLeftMain {
+        height: calc(100% - 140px);
+        overflow-y: auto;
         padding-top: 10px;
 
+        &::-webkit-scrollbar {
+          // display: none;
+          width: 2px;
+        }
+
+        &::-webkit-scrollbar-thumb {
+          background-color: #d4d4d4;
+        }
+
         .layoutLRowBox {
           .layoutLRowBoxTxt {
             font-size: 18px;
             font-weight: 700;
             height: 50px;
             line-height: 50px;
-            padding-left: 40px;
-            color: #fff;
-            display: none;
-            // opacity: .8;
+            padding-left: 55px;
+            color: #b1967b;
           }
 
           .layoutLRowBoxRow {
-            opacity: 0.6;
-            color: #fff;
-            text-align: center;
+            color: #b1967b;
+            padding-left: 85px;
             cursor: pointer;
 
             font-size: 16px;
@@ -46,15 +55,12 @@
             margin-bottom: 15px;
 
             &:hover {
-              background-color: var(--themeColor);
-              opacity: 1;
+              color: #efdbac;
             }
           }
 
           .active {
-            opacity: 1;
-            pointer-events: none;
-            background-color: var(--themeColor);
+            color: #efdbac;
           }
         }
       }

+ 18 - 14
src/pages/Layout/index.tsx

@@ -18,7 +18,7 @@ import NotFound from '@/components/NotFound'
 import { RouterType, RouterTypeRow } from '@/types'
 import tabLeftArr from './data'
 import MyPopconfirm from '@/components/MyPopconfirm'
-import { Z1_APIgetAuthByUserId } from '@/store/action/Z1user'
+// import { Z1_APIgetAuthByUserId } from '@/store/action/Z1user'
 import { UserListType } from '../Z1user/Z1auth'
 
 function Layout() {
@@ -38,27 +38,31 @@ function Layout() {
   const getUserAuthFu = useCallback(async () => {
     const userInfo = getTokenInfo().user
 
-    const res = await Z1_APIgetAuthByUserId(userInfo.id)
+    // 该项目无权限控制
+    // const res = await Z1_APIgetAuthByUserId(userInfo.id)
+    const isOkIdArr: number[] = [200, 300, 2100, 2200]
+    const res = {
+      code: 0,
+      data: []
+    }
     if (res.code === 0) {
       // 这里后台返回的一层的数据。懒得改逻辑,手动修改成2级的数据
-      res.data = [
-        {
-          id: Date.now(),
-          name: '',
-          children: res.data
-        }
-      ]
-
-      const isOkIdArr: number[] = [
-        // 101, 102, 103, 104, 105, 106, 107, 108
-      ]
+      // res.data = [
+      //   {
+      //     id: Date.now(),
+      //     name: '',
+      //     children: res.data
+      //   }
+      // ]
       const tempList: UserListType[] = res.data || []
       // console.log(123, tempList);
       tempList.forEach(v => {
         if (v.children) {
           v.children.forEach(c => {
-            if (c.authority) isOkIdArr.push(c.id)
+            isOkIdArr.push(c.id)
           })
+        } else {
+          isOkIdArr.push(v.id)
         }
       })
       // 是管理员

+ 29 - 25
src/pages/Login/index.module.scss

@@ -1,7 +1,7 @@
 .Login {
   width: 100%;
   height: 100%;
-  background-image: url('../../assets/img/loginBac.jpg');
+  background-image: url('../../assets/img/loginBac.png');
   background-size: 100% 100%;
 
   :global {
@@ -10,15 +10,12 @@
       left: 50%;
       top: 50%;
       transform: translate(-50%, -50%);
-      width: 530px;
-      background-color: rgba(255, 255, 255, 0.7);
-      backdrop-filter: blur(6px);
+      width: 580px;
+      height: 740px;
       display: flex;
       flex-direction: column;
-      justify-content: center;
       align-items: center;
-      padding: 50px 0;
-      border-radius: 6px;
+      gap: 20px;
 
       .LogoImg {
         & > img {
@@ -27,36 +24,36 @@
       }
 
       .inputBox {
-        margin: 10px 0 30px;
         width: 100%;
 
         input::-webkit-input-placeholder {
           /* WebKit browsers */
-          color: rgba(0, 0, 0, 0.4);
+          color: rgba(217, 217, 217, 0.8);
         }
 
         input:-moz-placeholder {
           /* Mozilla Firefox 4 to 18 */
-          color: rgba(0, 0, 0, 0.4);
+          color: rgba(217, 217, 217, 0.8);
         }
 
         input::-moz-placeholder {
           /* Mozilla Firefox 19+ */
-          color: rgba(0, 0, 0, 0.4);
+          color: rgba(217, 217, 217, 0.8);
         }
 
         input:-ms-input-placeholder {
           /* Internet Explorer 10+ */
-          color: rgba(0, 0, 0, 0.4);
+          color: rgba(217, 217, 217, 0.8);
         }
 
         .inputBoxRow {
           width: 370px;
-          margin: 30px auto;
+          margin: 12px auto;
 
           .ant-input-suffix .ant-input-password-icon {
-            color: rgba(0, 0, 0, 0.4);
-            font-size: 22px;
+            color: rgba(217, 217, 217, 0.8);
+            font-size: 20px;
+            margin-right: 20px;
           }
         }
 
@@ -68,13 +65,13 @@
             cursor: pointer;
             position: absolute;
             top: 50%;
-            right: 0;
+            right: 8px;
             transform: translateY(-50%);
           }
         }
 
         .ant-input-prefix {
-          margin-right: 10px;
+          margin-right: 20px;
 
           .anticon {
             padding-right: 10px;
@@ -98,7 +95,7 @@
 
         input:-webkit-autofill {
           font-size: 18px !important;
-          -webkit-text-fill-color: black !important;
+          -webkit-text-fill-color: rgb(255, 255, 255) !important;
           background-image: none;
           -webkit-box-shadow: 0 0 0px 1000px transparent inset !important; //填充阴影,可以用来遮住背景色
           background-color: transparent;
@@ -106,20 +103,20 @@
         }
 
         .ant-input-affix-wrapper {
-          background-color: transparent;
-          padding: 0 11px;
+          background: url('../../assets/img/inputBg.png');
+          background-size: 100% 100%;
+          padding: 0;
           width: 100%;
           height: 60px;
           border: none;
-          border-bottom: 1px solid black;
-          border-radius: 0;
+          border-radius: 5px;
           color: var(--themeColor);
 
           .ant-input {
             background-color: transparent;
             width: 100%;
             height: 60px;
-            color: black;
+            color: rgb(255, 255, 255);
           }
         }
 
@@ -131,11 +128,18 @@
       .loginBtn {
         .ant-btn {
           color: #fff;
-          background-color: var(--themeColor);
-          border-radius: 25px;
+          background: url('../../assets/img/loginBtnBg.png') no-repeat;
+          background-size: cover;
+          border-radius: 5px;
           font-size: 18px;
           width: 375px;
           height: 50px;
+          &:hover {
+            color: #fff;
+            opacity: 0.8;
+            background: url('../../assets/img/loginBtnBg.png') no-repeat;
+            background-size: cover;
+          }
         }
       }
     }

+ 94 - 93
src/pages/Login/index.tsx

@@ -1,134 +1,135 @@
-import styles from "./index.module.scss";
+import styles from './index.module.scss'
 
-import { Input, Button } from "antd";
-import { UserOutlined, LockOutlined, NumberOutlined } from "@ant-design/icons";
-import { useCallback, useEffect, useState } from "react";
-import { Base64 } from "js-base64";
-import encodeStr from "@/utils/pass";
-import { setTokenInfo } from "@/utils/storage";
-import history from "@/utils/history";
-import { MessageFu } from "@/utils/message";
-import { API_LoginGetCode, userLoginAPI } from "@/store/action/layout";
-import LogoImg from "@/assets/img/logo.png";
+import { Input, Button } from 'antd'
+import { UserOutlined, LockOutlined, NumberOutlined } from '@ant-design/icons'
+import { useCallback, useEffect, useState } from 'react'
+import { Base64 } from 'js-base64'
+import encodeStr from '@/utils/pass'
+import { setTokenInfo } from '@/utils/storage'
+import history from '@/utils/history'
+import { MessageFu } from '@/utils/message'
+import { API_LoginGetCode, userLoginAPI } from '@/store/action/layout'
 
 export default function Login() {
   // 获取验证码
   const LoginGetCodeFu = useCallback(async () => {
-    const res: any = await API_LoginGetCode();
-    const reader = new FileReader();
-    reader.readAsDataURL(res);
+    const res: any = await API_LoginGetCode()
+    const reader = new FileReader()
+    reader.readAsDataURL(res)
     reader.onload = () => {
-      setCodeImg(reader.result);
-    };
-  }, []);
+      setCodeImg(reader.result)
+    }
+  }, [])
 
   useEffect(() => {
-    LoginGetCodeFu();
-  }, [LoginGetCodeFu]);
+    LoginGetCodeFu()
+  }, [LoginGetCodeFu])
 
   // 账号密码 - 验证码
-  const [userName, setUserName] = useState("");
-  const [passWord, setPassWord] = useState("");
-  const [code, setCode] = useState<any>("");
-  const [codeImg, setCodeImg] = useState<any>("");
+  const [userName, setUserName] = useState('')
+  const [passWord, setPassWord] = useState('')
+  const [code, setCode] = useState<any>('')
+  const [codeImg, setCodeImg] = useState<any>('')
+  const images = {
+    logo: require('@/assets/img/logo.png'),
+    eye: require('@/assets/img/eye.png'),
+    eyex: require('@/assets/img/eyex.png')
+  }
 
   useEffect(() => {
     //进入登录页 重置 权限信息为空
-  }, []);
+  }, [])
 
   // 键盘按下回车事件
   const keyUpEntFu = (e: React.KeyboardEvent<HTMLInputElement>) => {
-    if (e.key === "Enter") loginClickFu();
-  };
+    if (e.key === 'Enter') loginClickFu()
+  }
   // 点击登录
   const loginClickFu = useCallback(async () => {
     // 非空判断
-    if (userName === "") return MessageFu.warning("请输入账号!");
-    else if (passWord === "") return MessageFu.warning("请输入密码!");
+    if (userName === '') return MessageFu.warning('请输入账号!')
+    else if (passWord === '') return MessageFu.warning('请输入密码!')
     const obj = {
       userName,
       passWord: encodeStr(Base64.encode(passWord)),
-      randCode: code,
-    };
-    const res: any = await userLoginAPI(obj);
+      randCode: code
+    }
+    const res: any = await userLoginAPI(obj)
     if (res.code === 0) {
-      MessageFu.success("登录成功");
+      MessageFu.success('登录成功')
 
       // 检查密码是不是默认密码,是的话给提示
-      if (passWord === "123456") {
+      if (passWord === '123456') {
         window.setTimeout(() => {
-          MessageFu.warning("您的密码还是默认密码,请尽快修改!");
-        }, 1000);
+          MessageFu.warning('您的密码还是默认密码,请尽快修改!')
+        }, 1000)
       }
 
       // 用户信息存到本地
-      setTokenInfo(res.data);
-      history.push("/");
+      setTokenInfo(res.data)
+      history.push('/')
     } else if (res.code === 3014) {
-      MessageFu.warning("账号不存在或密码错误,请联系管理员!");
-    } else if (res.code === -1 && res.msg === "验证码有误") {
-      LoginGetCodeFu();
+      MessageFu.warning('账号不存在或密码错误,请联系管理员!')
+    } else if (res.code === -1 && res.msg === '验证码有误') {
+      LoginGetCodeFu()
     }
-  }, [LoginGetCodeFu, code, passWord, userName]);
+  }, [LoginGetCodeFu, code, passWord, userName])
 
   return (
     <div className={styles.Login}>
-      <div className="mainRight">
-
-        {/* logg */}
-        <div className="LogoImg">
-        <img src={LogoImg}  alt="" />
+      <div className='mainRight'>
+        {/* logo */}
+        <div className='LogoImg'>
+          <img src={images.logo} alt='' />
         </div>
 
-          {/* 账号密码输入框 */}
-          <div className="inputBox">
-            <div className="inputBoxRow">
-              <Input
-                onKeyUp={(e) => keyUpEntFu(e)}
-                value={userName}
-                onChange={(e) => setUserName(e.target.value.trim())}
-                prefix={<UserOutlined rev={undefined} />}
-                placeholder="请输入账号"
-                maxLength={15}
-              />
-            </div>
-            <div className="inputBoxRow">
-              <Input.Password
-                onKeyUp={(e) => keyUpEntFu(e)}
-                value={passWord}
-                onChange={(e) => setPassWord(e.target.value.trim())}
-                prefix={<LockOutlined rev={undefined} />}
-                placeholder="请输入密码"
-                maxLength={20}
-              />
-            </div>
-            <div className="inputBoxRow inputBoxRow2">
-              <Input
-                onKeyUp={(e) => keyUpEntFu(e)}
-                value={code}
-                onChange={(e) => setCode(e.target.value.trim())}
-                prefix={<NumberOutlined rev={undefined} />}
-                placeholder="请输入验证码"
-                maxLength={5}
-              />
-              {codeImg ? (
-                <img
-                  onClick={LoginGetCodeFu}
-                  className="loginCode"
-                  src={codeImg}
-                  alt=""
-                />
-              ) : null}
-            </div>
+        {/* 账号密码输入框 */}
+        <div className='inputBox'>
+          <div className='inputBoxRow'>
+            <Input
+              onKeyUp={e => keyUpEntFu(e)}
+              value={userName}
+              onChange={e => setUserName(e.target.value.trim())}
+              prefix={<span />}
+              placeholder='请输入账号'
+              maxLength={15}
+            />
           </div>
-
-          {/* 登录按钮 */}
-          <div className="loginBtn">
-            <Button type="primary" size="large" onClick={loginClickFu}>
-              登 录
-            </Button>
+          <div className='inputBoxRow'>
+            <Input.Password
+              onKeyUp={e => keyUpEntFu(e)}
+              value={passWord}
+              onChange={e => setPassWord(e.target.value.trim())}
+              prefix={<span />} // 占位
+              placeholder='请输入密码'
+              iconRender={visible =>
+                visible ? <img src={images.eye} alt='' /> : <img src={images.eyex} alt='' />
+              }
+              maxLength={20}
+            />
           </div>
+          <div className='inputBoxRow inputBoxRow2'>
+            <Input
+              onKeyUp={e => keyUpEntFu(e)}
+              value={code}
+              onChange={e => setCode(e.target.value.trim())}
+              prefix={<span />}
+              placeholder='请输入验证码'
+              maxLength={5}
+            />
+            {codeImg ? (
+              <img onClick={LoginGetCodeFu} className='loginCode' src={codeImg} alt='' />
+            ) : null}
+          </div>
+        </div>
+
+        {/* 登录按钮 */}
+        <div className='loginBtn'>
+          <Button type='primary' size='large' onClick={loginClickFu}>
+            登 录
+          </Button>
+        </div>
       </div>
     </div>
-  );
+  )
 }

+ 74 - 104
src/pages/Z1user/index.tsx

@@ -1,183 +1,158 @@
-import { RootState } from "@/store";
-import {
-  getUserListAPI,
-  userPassResetAPI,
-  userRemoveAPI,
-} from "@/store/action/Z1user";
-import { UserTableAPIType, UserTableListType } from "@/types";
-import { MessageFu } from "@/utils/message";
-import { Input, Button } from "antd";
-import React, {
-  useCallback,
-  useEffect,
-  useMemo,
-  useRef,
-  useState,
-} from "react";
-import { useDispatch, useSelector } from "react-redux";
-import styles from "./index.module.scss";
-import UserAdd from "./UserAdd";
-import MyTable from "@/components/MyTable";
-import { Z1tableC } from "@/utils/tableData";
-import MyPopconfirm from "@/components/MyPopconfirm";
-import Z1auth from "./Z1auth";
+import { RootState } from '@/store'
+import { getUserListAPI, userPassResetAPI, userRemoveAPI } from '@/store/action/Z1user'
+import { UserTableAPIType, UserTableListType } from '@/types'
+import { MessageFu } from '@/utils/message'
+import { Input, Button } from 'antd'
+import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
+import { useDispatch, useSelector } from 'react-redux'
+import styles from './index.module.scss'
+import UserAdd from './UserAdd'
+import MyTable from '@/components/MyTable'
+import { Z1tableC } from '@/utils/tableData'
+import MyPopconfirm from '@/components/MyPopconfirm'
+import Z1auth from './Z1auth'
 
 function Z1user() {
-  const dispatch = useDispatch();
+  const dispatch = useDispatch()
 
   // 顶部筛选
   const [fromData, setFromData] = useState<UserTableAPIType>({
     pageNum: 1,
     pageSize: 10,
-    searchKey: "",
-  });
+    searchKey: ''
+  })
 
   // 封装发送请求的函数
 
   const getList = useCallback(async () => {
-    dispatch(getUserListAPI(fromData));
-  }, [dispatch, fromData]);
+    dispatch(getUserListAPI(fromData))
+  }, [dispatch, fromData])
 
   useEffect(() => {
-    getList();
-  }, [getList]);
+    getList()
+  }, [getList])
 
-  const timeRef = useRef(-1);
+  const timeRef = useRef(-1)
   // 用户名
   const txtChangeFu = useCallback(
-    (e: React.ChangeEvent<HTMLInputElement>, key: "searchKey") => {
-      clearTimeout(timeRef.current);
+    (e: React.ChangeEvent<HTMLInputElement>, key: 'searchKey') => {
+      clearTimeout(timeRef.current)
       timeRef.current = window.setTimeout(() => {
         setFromData({
           ...fromData,
           [key]: e.target.value,
-          pageNum: 1,
-        });
-      }, 500);
+          pageNum: 1
+        })
+      }, 500)
     },
     [fromData]
-  );
+  )
 
   // 点击重置
-  const [inputKey, setInputKey] = useState(1);
+  const [inputKey, setInputKey] = useState(1)
   const resetSelectFu = useCallback(() => {
     // 把2个输入框和时间选择器清空
-    setInputKey(Date.now());
+    setInputKey(Date.now())
     setFromData({
       pageNum: 1,
       pageSize: 10,
-      searchKey: "",
-    });
-  }, []);
+      searchKey: ''
+    })
+  }, [])
 
   // 从仓库中获取表格数据
-  const tableInfo = useSelector((state: RootState) => state.Z1user.tableInfo);
+  const tableInfo = useSelector((state: RootState) => state.Z1user.tableInfo)
 
   // 点击删除
   const delTableFu = useCallback(
     async (id: number) => {
-      const res: any = await userRemoveAPI(id);
+      const res: any = await userRemoveAPI(id)
       if (res.code === 0) {
-        MessageFu.success("删除成功!");
-        getList();
+        MessageFu.success('删除成功!')
+        getList()
       }
     },
     [getList]
-  );
+  )
 
   // 点击重置密码
   const resetPassFu = useCallback(async (id: number) => {
-    const res: any = await userPassResetAPI(id);
-    if (res.code === 0) MessageFu.success("重置成功!");
-  }, []);
+    const res: any = await userPassResetAPI(id)
+    if (res.code === 0) MessageFu.success('重置成功!')
+  }, [])
 
   // 0------------点击新增或者编辑出来的页面
-  const [editPageShow, setEditPageShow] = useState(false);
-  const editId = useRef(0);
+  const [editPageShow, setEditPageShow] = useState(false)
+  const editId = useRef(0)
 
   const openEditPageFu = useCallback(
     (id: number) => {
-      if (id === 0 && tableInfo.list.length >= 20)
-        return MessageFu.warning("最多支持20个用户!");
+      if (id === 0 && tableInfo.list.length >= 20) return MessageFu.warning('最多支持20个用户!')
 
-      editId.current = id;
-      setEditPageShow(true);
+      editId.current = id
+      setEditPageShow(true)
     },
     [tableInfo.list.length]
-  );
+  )
 
   const tableLastBtn = useMemo(() => {
     return [
       {
-        title: "操作",
+        title: '操作',
         render: (item: UserTableListType) => {
           return item.isAdmin === 1 ? (
-            "-"
+            '-'
           ) : (
             <>
               <MyPopconfirm
-                txtK="重置密码"
+                txtK='重置密码'
                 onConfirm={() => resetPassFu(item.id)}
                 Dom={
-                  <Button size="small" type="text">
+                  <Button size='small' type='text'>
                     重置密码
                   </Button>
                 }
               />
-              <Button
-                size="small"
-                type="text"
-                onClick={() =>
-                  setAuthInfo({ id: item.id, name: item.userName })
-                }
-              >
-                权限管理
-              </Button>
-              <Button
-                size="small"
-                type="text"
-                onClick={() => openEditPageFu(item.id)}
-              >
+              <Button size='small' type='text' onClick={() => openEditPageFu(item.id)}>
                 编辑
               </Button>
-              <MyPopconfirm txtK="删除" onConfirm={() => delTableFu(item.id)} />
+              <MyPopconfirm txtK='删除' onConfirm={() => delTableFu(item.id)} />
             </>
-          );
-        },
-      },
-    ];
-  }, [delTableFu, openEditPageFu, resetPassFu]);
+          )
+        }
+      }
+    ]
+  }, [delTableFu, openEditPageFu, resetPassFu])
 
   // 授权管理
-  const [authInfo, setAuthInfo] = useState({ id: 0, name: "" });
+  const [authInfo, setAuthInfo] = useState({ id: 0, name: '' })
 
   return (
     <div className={styles.Z1user}>
-      <div className="pageTitle">用户管理</div>
-      <div className="userTop">
-        <div className="selectBox">
-          <div className="selectBoxRow">
+      <div className='pageTitle'>用户管理</div>
+      <div className='userTop'>
+        <div className='selectBox'>
+          <div className='selectBoxRow'>
             <span>搜索项:</span>
             <Input
               key={inputKey}
               maxLength={10}
               showCount
               style={{ width: 300 }}
-              placeholder="请输入用户名"
+              placeholder='请输入用户名'
               allowClear
-              onChange={(e) => txtChangeFu(e, "searchKey")}
+              onChange={e => txtChangeFu(e, 'searchKey')}
             />
           </div>
 
-          <div className="selectBoxRow">
+          <div className='selectBoxRow'>
             &emsp;&emsp;<Button onClick={resetSelectFu}>重置</Button>
             &emsp;&emsp;
             <Button
-              type="primary"
+              type='primary'
               onClick={() => {
-                if (tableInfo.total >= 30)
-                  return MessageFu.warning("最多30个账号!");
-                openEditPageFu(0);
+                if (tableInfo.total >= 30) return MessageFu.warning('最多30个账号!')
+                openEditPageFu(0)
               }}
             >
               新增
@@ -186,7 +161,7 @@ function Z1user() {
         </div>
       </div>
       {/* 表格主体 */}
-      <div className="tableBox">
+      <div className='tableBox'>
         <MyTable
           yHeight={630}
           list={tableInfo.list}
@@ -195,9 +170,7 @@ function Z1user() {
           pageNum={fromData.pageNum}
           pageSize={fromData.pageSize}
           total={tableInfo.total}
-          onChange={(pageNum, pageSize) =>
-            setFromData({ ...fromData, pageNum, pageSize })
-          }
+          onChange={(pageNum, pageSize) => setFromData({ ...fromData, pageNum, pageSize })}
         />
       </div>
 
@@ -213,15 +186,12 @@ function Z1user() {
 
       {/* 点击授权 */}
       {authInfo.id ? (
-        <Z1auth
-          authInfo={authInfo}
-          closeFu={() => setAuthInfo({ id: 0, name: "" })}
-        />
+        <Z1auth authInfo={authInfo} closeFu={() => setAuthInfo({ id: 0, name: '' })} />
       ) : null}
     </div>
-  );
+  )
 }
 
-const MemoZ1user = React.memo(Z1user);
+const MemoZ1user = React.memo(Z1user)
 
-export default MemoZ1user;
+export default MemoZ1user

+ 0 - 76
src/store/action/A1manage.ts

@@ -1,76 +0,0 @@
-import http from '@/utils/http'
-import { AppDispatch } from '..'
-
-/**
- *图书管理-列表
- */
-
-export const A1_APIgetList = (data: any): any => {
-  return async (dispatch: AppDispatch) => {
-    const res = await http.post('cms/book/pageList', data)
-    if (res.code === 0) {
-      const obj = {
-        list: res.data.records,
-        total: res.data.total
-      }
-      dispatch({ type: 'A1/getList', payload: obj })
-    }
-  }
-}
-/**
- * 图书管理-删除
- */
-export const A1_APIdel = (id: number) => {
-  return http.get(`cms/book/remove/${id}`)
-}
-
-/**
- * 图书管理-获取详情
- */
-export const A1_APIgetInfo = (id: number) => {
-  return http.get(`cms/book/detail/${id}`)
-}
-
-/**
- * 图书管理-新增、编辑
- */
-export const A1_APIsave = (data: any) => {
-  return http.post('cms/book/save', data)
-}
-
-// ----------------------影印/视频资料-------------------
-
-/**
- * 图书管理-影印/视频资料 列表
- */
-export const A1_APIgetListById = (data: any) => {
-  return http.post('cms/video/pageList', data)
-}
-
-/**
- * 图书管理-影印/视频资料-删除
- */
-export const A1_APIdelById = (id: number) => {
-  return http.get(`cms/video/remove/${id}`)
-}
-
-/**
- * 图书管理-影印/视频资料-获取详情
- */
-export const A1_APIgetInfoById = (id: number) => {
-  return http.get(`cms/video/detail/${id}`)
-}
-
-/**
- * 图书管理-影印/视频资料-新增、编辑
- */
-export const A1_APIsaveById = (data: any) => {
-  return http.post('cms/video/save', data)
-}
-
-/**
- * 导入------------
- */
-export const A1_APIimport = (data: any) => {
-  return http.post('cms/book/import', data)
-}

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

@@ -0,0 +1,39 @@
+import http from '@/utils/http'
+import { AppDispatch } from '..'
+
+/**
+ *列表
+ */
+
+export const A1_APIgetList = (data: any): any => {
+  return async (dispatch: AppDispatch) => {
+    const res = await http.post('cms/site/page', data)
+    if (res.code === 0) {
+      const obj = {
+        list: res.data.records,
+        total: res.data.total
+      }
+      dispatch({ type: 'A1/getList', payload: obj })
+    }
+  }
+}
+/**
+ * 删除
+ */
+export const A1_APIdel = (id: number) => {
+  return http.get(`cms/site/remove/${id}`)
+}
+
+/**
+ * 获取详情
+ */
+export const A1_APIgetInfo = (id: number) => {
+  return http.get(`cms/site/detail/${id}`)
+}
+
+/**
+ * 新增、编辑
+ */
+export const A1_APIsave = (data: any) => {
+  return http.post('cms/site/save', data)
+}

+ 17 - 15
src/store/action/A2classify.ts

@@ -2,38 +2,40 @@ import http from '@/utils/http'
 import { AppDispatch } from '..'
 
 /**
- *图书分类-树
+ *列表
  */
 
-export const A2_APIgetList1 = (): any => {
+export const A2_APIgetList = (data: any): any => {
   return async (dispatch: AppDispatch) => {
-    const res = await http.get('cms/storage/getTree')
+    const res = await http.post('cms/way/page', data)
     if (res.code === 0) {
-      dispatch({ type: 'A2/getTree', payload: res.data })
-      dispatch({ type: 'A2/treeFlag', payload: true })
-      // console.log(123, res)
+      const obj = {
+        list: res.data.records,
+        total: res.data.total
+      }
+      dispatch({ type: 'A2/getList', payload: obj })
     }
   }
 }
 /**
- * 图书分类-删除
+ * 删除
  */
-export const A2_APIdel1 = (id: number) => {
-  return http.get(`cms/storage/remove/${id}`)
+export const A2_APIdel = (id: number) => {
+  return http.get(`cms/way/remove/${id}`)
 }
 
 /**
- * 图书分类-获取详情
+ * 获取详情
  */
-export const A2_APIgetInfo1 = (id: number) => {
-  return http.get(`cms/storage/detail/${id}`)
+export const A2_APIgetInfo = (id: number) => {
+  return http.get(`cms/way/detail/${id}`)
 }
 
 /**
- * 图书分类-新增、编辑
+ * 图书管理-新增、编辑
  */
-export const A2_APIsave1 = (data: any) => {
-  return http.post('cms/storage/save', data)
+export const A2_APIsave = (data: any) => {
+  return http.post('cms/way/save', data)
 }
 
 // -------------------展示分类--------------------

+ 0 - 44
src/store/action/A3recommend.ts

@@ -1,44 +0,0 @@
-import http from '@/utils/http'
-import { AppDispatch } from '..'
-
-/**
- *图书推荐-列表
- */
-
-export const A3_APIgetList = (data: any): any => {
-  return async (dispatch: AppDispatch) => {
-    const res = await http.post('cms/rank/getList', data)
-    if (res.code === 0) {
-      dispatch({ type: 'A3/getList', payload: res.data })
-    }
-  }
-}
-
-// 获取新增 、编辑 里面的 书名/ISBN编号的下拉框数据
-export const A1_APIgetSelect = (): any => {
-  return http.post('cms/book/pageList', {
-    pageNum: 1,
-    pageSize: 99999
-  })
-}
-
-/**
- * 图书推荐-删除
- */
-export const A3_APIdel = (id: number) => {
-  return http.get(`cms/rank/remove/${id}`)
-}
-
-/**
- * 图书推荐-获取详情
- */
-export const A3_APIgetInfo = (id: number) => {
-  return http.get(`cms/rank/detail/${id}`)
-}
-
-/**
- * 图书推荐-新增、编辑
- */
-export const A3_APIsave = (data: any) => {
-  return http.post('cms/rank/save', data)
-}

+ 0 - 53
src/store/action/A4iosUser.ts

@@ -1,53 +0,0 @@
-import http from '@/utils/http'
-import { AppDispatch } from '..'
-
-/**
- *平台用户-列表
- */
-
-export const A4_APIgetList = (data: any): any => {
-  return async (dispatch: AppDispatch) => {
-    const res = await http.post('cms/wxUser/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_APIisEnabled = (id: number, val: 0 | 1) => {
-  return http.get(`cms/wxUser/editStatus/${id}/${val}`)
-}
-
-// ip白名单列表
-export const A4_APIipList = (): any => {
-  return async (dispatch: AppDispatch) => {
-    const res = await http.post('sys/ip/pageList', {
-      pageNum: 1,
-      pageSize: 99999
-    })
-    if (res.code === 0) {
-      dispatch({ type: 'A3/getIpList', payload: res.data.records })
-    }
-  }
-}
-
-/**
- * ip白名单-删除
- */
-export const A4_APIipDel = (id: number) => {
-  return http.get(`sys/ip/remove/${id}`)
-}
-
-/**
- * ip白名单-新增、编辑
- */
-export const A4_APIipSave = (data: any) => {
-  return http.post('sys/ip/save', data)
-}

+ 0 - 40
src/store/action/A5bookAudit.ts

@@ -1,40 +0,0 @@
-import http from '@/utils/http'
-import { AppDispatch } from '..'
-
-/**
- *图书审核-列表
- */
-
-export const A5_APIgetList = (data: any): any => {
-  return async (dispatch: AppDispatch) => {
-    const res = await http.post('cms/audit/pageList', data)
-    if (res.code === 0) {
-      const obj = {
-        list: res.data.records,
-        total: res.data.total
-      }
-      dispatch({ type: 'A5/getList', payload: obj })
-    }
-  }
-}
-
-/**
- * 图书审核-删除
- */
-export const A5_APIdel = (id: number) => {
-  return http.get(`cms/audit/remove/${id}`)
-}
-
-/**
- * 图书审核-审核
- */
-export const A5_APIaudit = (data: any) => {
-  return http.post('cms/audit/audit', data)
-}
-
-/**
- * 图书推荐-获取详情
- */
-export const A5_APIgetInfo = (id: number) => {
-  return http.get(`cms/audit/detail/${id}`)
-}

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

@@ -1,39 +0,0 @@
-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)
-}

+ 0 - 66
src/store/action/A7notice.ts

@@ -1,66 +0,0 @@
-import http from '@/utils/http'
-import { AppDispatch } from '..'
-
-/**
- *公告管理-列表
- */
-
-export const A7_APIgetList = (data: any): any => {
-  return async (dispatch: AppDispatch) => {
-    const res = await http.post('cms/notice/pageList', data)
-    if (res.code === 0) {
-      const obj = {
-        list: res.data.records,
-        total: res.data.total
-      }
-      dispatch({ type: 'A7/getList', payload: obj })
-    }
-  }
-}
-/**
- * 公告管理-删除
- */
-export const A7_APIdel = (id: number) => {
-  return http.get(`cms/notice/remove/${id}`)
-}
-
-/**
- * 公告管理-获取详情
- */
-export const A7_APIgetInfo = (id: number) => {
-  return http.get(`cms/notice/detail/${id}`)
-}
-
-/**
- * 公告管理-新增/编辑
- */
-export const A7_APIsave = (data: any) => {
-  return http.post('cms/notice/save', data)
-}
-
-// --------------------公告类型--------------------
-/**
- *公告类型-列表
- */
-
-export const A7_APIgetList2 = (): any => {
-  return async (dispatch: AppDispatch) => {
-    const res = await http.get('cms/dict/getList')
-    if (res.code === 0) {
-      dispatch({ type: 'A7/getTypeList', payload: res.data })
-    }
-  }
-}
-/**
- * 公告类型-删除
- */
-export const A7_APIdel2 = (id: number) => {
-  return http.get(`cms/dict/removes/${id}`)
-}
-
-/**
- * 公告类型-新增/编辑
- */
-export const A7_APIsave2 = (data: any) => {
-  return http.post('cms/dict/save', data)
-}

src/store/reducer/A1manage.ts → src/store/reducer/A1scene.ts


+ 1 - 12
src/store/reducer/A2classify.ts

@@ -1,11 +1,7 @@
-import { A2tableType, A2TreeType } from '@/types'
+import { A2tableType } from '@/types'
 
 // 初始化状态
 const initState = {
-  // 树数据
-  treeData: [] as A2TreeType[],
-  treeFlag: false,
-
   // 列表数据
   tableInfo: {
     list: [] as A2tableType[],
@@ -16,10 +12,6 @@ const initState = {
 // 定义 action 类型
 type Props =
   | {
-      type: 'A2/getTree'
-      payload: A2TreeType[]
-    }
-  | {
       type: 'A2/treeFlag'
       payload: boolean
     }
@@ -31,9 +23,6 @@ type Props =
 // reducer
 export default function Reducer(state = initState, action: Props) {
   switch (action.type) {
-    // 获取树数据
-    case 'A2/getTree':
-      return { ...state, treeData: action.payload }
     // 获取列表数据
     case 'A2/getList':
       return { ...state, tableInfo: action.payload }

+ 0 - 25
src/store/reducer/A3recommend.ts

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

+ 0 - 38
src/store/reducer/A4iosUser.ts

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

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

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

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

@@ -1,28 +0,0 @@
-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
-  }
-}

+ 0 - 38
src/store/reducer/A7notice.ts

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

+ 4 - 14
src/store/reducer/index.ts

@@ -3,26 +3,16 @@ import { combineReducers } from 'redux'
 
 // 导入 登录 模块的 reducer
 import A0Layout from './layout'
-import A1manage from './A1manage'
-import A2classify from './A2classify'
-import A3recommend from './A3recommend'
-import A4iosUser from './A4iosUser'
-import A5bookAudit from './A5bookAudit'
-import A6remarkAudit from './A6remarkAudit'
-import A7notice from './A7notice'
+import A1scene from './A1scene'
+import A2line from './A2line'
 import Z1user from './Z1user'
 import Z2log from './Z2log'
 
 // 合并 reducer
 const rootReducer = combineReducers({
   A0Layout,
-  A1manage,
-  A2classify,
-  A3recommend,
-  A4iosUser,
-  A5bookAudit,
-  A6remarkAudit,
-  A7notice,
+  A1scene,
+  A2line,
   Z1user,
   Z2log
 })

+ 0 - 41
src/types/api/A1manage.d.ts

@@ -1,41 +0,0 @@
-export type A1tableType = {
-  ancestor: string
-  auditDesc: string
-  author: string
-  createTime: string
-  creatorId: number
-  creatorName: string
-  description: string
-  display: number
-  exhibitTypeId: string
-  exhibitTypeName: string
-  fileName: string
-  filePath: string
-  id: number
-  input: string
-  name: string
-  num: string
-  press: string
-  sort: number
-  storageId: string
-  storageName: string
-  thumb: string
-  thumbPc: string
-  updateTime: string
-  year: string
-}
-export type A1YType = {
-  bookId: number
-  createTime: string
-  creatorId: number
-  creatorName: string
-  description: string
-  fileName: string
-  filePath: string
-  id: number
-  name: string
-  sort: number
-  thumb: string
-  type: string
-  updateTime: string
-}

+ 73 - 0
src/types/api/A1scene.d.ts

@@ -0,0 +1,73 @@
+export type A1tableType = {
+  address: string
+  audioPath: string
+  createTime: string
+  creatorId: number
+  creatorName: string
+  fileIds: string
+  files: any // You may want to replace 'any' with a more specific type if available
+  id: number
+  intro: string
+  lat: number
+  lon: number
+  modelUrl: string
+  name: string
+  thumb: string
+  type: string
+  updateTime: string
+  vrUrl: string
+  weight: number
+}
+
+export type A1tbFileType = {
+  createTime: string | null
+  creatorId: number | null
+  creatorName: string
+  description: string
+  fileName: string
+  filePath: string
+  id: number
+  moduleName: string
+  parentId: number | null
+  thumb: string
+  type: string
+  updateTime: string | null
+}
+
+export type A1tbType = {
+  address: string
+  audioName: string
+  audioPath: string
+  createTime: string
+  creatorId: number
+  creatorName: string
+  fileIds: string
+  files: A1tbFileType[]
+  id: number
+  intro: string
+  lat: number
+  lon: number
+  modelUrl: string
+  name: string
+  type: string
+  updateTime: string
+  vrUrl: string
+  weight: number
+}
+
+export type A1AddType = {
+  address: string
+  audioName: string
+  audioPath: string
+  fileIds: string
+  id: number
+  intro: string
+  lat: number
+  lon: number
+  modelUrl: string
+  name: string
+  thumb: string
+  type: string
+  vrUrl: string
+  weight: number
+}

+ 0 - 24
src/types/api/A2classify.d.ts

@@ -1,24 +0,0 @@
-export type A2TreeType = {
-  ancestor: string
-  children: A2TreeType[] | null
-  createTime: string
-  description: string
-  id: number
-  level: number
-  name: string
-  num: string
-  parentId: number | null
-  updateTime: string
-  sort: number
-  creatorName: string
-}
-
-export type A2tableType = {
-  createTime: string
-  creatorId: number
-  creatorName: string
-  id: number
-  name: string
-  sort: number
-  updateTime: string
-}

+ 60 - 0
src/types/api/A2line.d.ts

@@ -0,0 +1,60 @@
+export type A2tbType = {
+  createTime: string
+  creatorId: number
+  creatorName: string
+  expect: string
+  id: number
+  name: string
+  siteIds: string
+  sites: A2tbSitesType[]
+  sort: number
+  tag: string
+  thumb: string
+  updateTime: string
+}
+
+export type A2tbSitesType = {
+  address: string
+  audioPath: string
+  createTime: string
+  creatorId: number
+  creatorName: string
+  fileIds: string
+  files: any
+  id: number
+  intro: string
+  lat: number
+  lon: number
+  modelUrl: string
+  name: string
+  thumb: string
+  type: string
+  updateTime: string
+  vrUrl: string
+  weight: number
+}
+
+export type A2tableType = {
+  createTime: string
+  creatorId: number
+  creatorName: string
+  expect: string
+  id: number
+  name: string
+  siteIds: string
+  sites: A2tbSitesType[] | null
+  sort: number
+  tag: string
+  thumb: string
+  updateTime: string
+}
+
+export type A2AddType = {
+  expect: string
+  id: number
+  name: string
+  siteIds: string
+  sort: number
+  tag: string
+  thumb: string
+}

+ 0 - 23
src/types/api/A3recommend.ts

@@ -1,23 +0,0 @@
-export type A3tableType = {
-  ancestor: string
-  author: string
-  createTime: string
-  creatorId: number
-  creatorName: string
-  description: string
-  exhibitTypeId: string
-  exhibitTypeName: string
-  fileName: string
-  filePath: string
-  id: number
-  name: string
-  num: string
-  pcsVisit: number
-  press: string
-  sort: number
-  storageId: string
-  storageName: string
-  thumb: string
-  updateTime: string
-  year: string
-}

+ 0 - 20
src/types/api/A4iosUser.ts

@@ -1,20 +0,0 @@
-export type A4tableType = {
-  avatarUrl: string
-  city: string
-  country: string
-  createTime: string
-  creatorName: string
-  gender: string
-  id: number
-  isEnabled: 0 | 1
-  lastIp: string
-  nickName: string
-  openId: string
-  phone: string
-  province: string
-  type: string
-  unionId: string
-  updateTime: string
-}
-
-export type A4IpType = any

+ 0 - 28
src/types/api/A5bookAudit.ts

@@ -1,28 +0,0 @@
-export type A5tableType = {
-  ancestor: string
-  auditDesc: string
-  author: string
-  createTime: string
-  creatorId: number
-  creatorName: string
-  description: string
-  display: number
-  exhibitTypeId: string
-  exhibitTypeName: string
-  fileName: string
-  filePath: string
-  id: number
-  name: string
-  num: string
-  press: string
-  sort: number
-  storageId: string
-  storageName: string
-  thumb: string
-  updateTime: string
-  year: string
-  wxUserName: string
-  auditStatus: 0 | 1 | 2
-  auditBy: string
-  auditTime: string
-}

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

@@ -1,13 +0,0 @@
-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
-}

+ 0 - 14
src/types/api/A7notice.ts

@@ -1,14 +0,0 @@
-export type A7tableType = {
-  creatorName: string
-  id: number
-  name: string
-  rtf: string
-  sort: number
-  type: string
-}
-
-export type A7typeType = {
-  id: number
-  name: string
-  sort: number
-}

+ 2 - 7
src/types/index.d.ts

@@ -1,10 +1,5 @@
 export * from './api/layot'
-export * from './api/A1manage'
-export * from './api/A2classify'
-export * from './api/A3recommend'
-export * from './api/A4iosUser'
-export * from './api/A5bookAudit'
-export * from './api/A6remarkAudit'
-export * from './api/A7notice'
+export * from './api/A1scene'
+export * from './api/A2line'
 export * from './api/Z1user'
 export * from './api/Z2log'

+ 10 - 6
src/utils/http.ts

@@ -5,15 +5,15 @@ import store from '@/store'
 import { MessageFu } from './message'
 import { domShowFu } from './domShow'
 
-const envFlag = process.env.NODE_ENV === 'development'
+// const envFlag = process.env.NODE_ENV === 'development'
 
-const baseUrlTemp = 'https://sit-liushaoqibwg.4dage.com' // 测试环境
-// const baseUrlTemp = 'http://192.168.20.61:8072' // 线下环境
+const baseUrlTemp = 'https://sit-yueyangbwg.4dage.com' // 测试环境
+// const baseUrlTemp = 'http://192.168.20.61:8099' // 线下环境
 
-const baseFlag = baseUrlTemp.includes('https://')
+// const baseFlag = baseUrlTemp.includes('https://')
 
 // 请求基地址
-export const baseURL = envFlag ? `${baseUrlTemp}${baseFlag ? '' : '/api/'}` : ''
+// export const baseURL = envFlag ? `${baseUrlTemp}${baseFlag ? '' : '/api/'}` : ''
 
 // 处理  类型“AxiosResponse<any, any>”上不存在属性“code”
 declare module 'axios' {
@@ -26,10 +26,12 @@ declare module 'axios' {
 
 // 创建 axios 实例
 const http = axios.create({
-  baseURL: `${baseURL}${baseFlag ? '/api/' : ''}`,
+  baseURL: `${baseUrlTemp}/api/`,
   timeout: 10000
 })
 
+export const baseURL = `${baseUrlTemp}`
+
 let axajInd = 0
 
 // 请求拦截器
@@ -68,6 +70,8 @@ http.interceptors.response.use(
       }, 200)
     } else if (response.data.code === 0) {
       // MessageFu.success(response.data.msg);
+    } else if (response.data.msg === '名称不能重复') {
+      // MessageFu.success(response.data.msg);
     } else if (response.data.code !== 3014) MessageFu.warning(response.data.msg)
 
     return response.data

+ 9 - 98
src/utils/tableData.ts

@@ -14,109 +14,20 @@
 //     ["text", "创建日期",'description', 50,A],
 //   ];
 
-const A1tableCTemp = [
-  ['txt', '书名', 'name'],
+export const A1tableC = [
+  ['txtNormal', '名称', 'name'],
+  ['txtNormal', '类型', 'type'],
   ['img', '封面', 'thumb'],
-  ['txt', '作者', 'author'],
-  ['txt', '出版社', 'press'],
-  ['txt', '中图法分类', 'storageName'],
-  ['txt', '展示分类', 'exhibitTypeName'],
-  ['txt', 'ISBN编号', 'num'],
-  ['txt', '排序值', 'sort'],
-  ['txt', '编辑人', 'creatorName'],
-  ['txt', '编辑时间', 'updateTime']
-]
-
-export const A1tableC = isBookIdShow ? [['txt', 'bookId', 'id'], ...A1tableCTemp] : A1tableCTemp
-
-export const A1tableCimp = [
-  ['txt', '书名', 'name'],
-  ['img', '封面(png、jpg)', 'thumb', `<span class='tabx'>(待填入)</span>`],
-  ['txt', '作者', 'author'],
-  ['txt', '出版社', 'press'],
-  ['txt', '出版年份', 'year'],
-  ['txt', '中图法分类', 'storageName', `<span class='tabx'>(待填入)</span>`],
-  ['txt', '展示分类', 'exhibitTypeName', `<span class='tabx'>(待填入)</span>`],
-  ['txt', 'ISBN编号', 'num'],
-  ['txt', '排序值', 'sort'],
-  ['txt', '附件(equb格式)', 'fileName', `<span class='tabx'>(待填入)</span>`]
-]
-
-export const A2tableY1 = [
-  ['img', '封面', 'thumb'],
-  ['text', '正文', 'description', 50],
-  ['txt', '排序值', 'sort'],
-  ['txt', '编辑人', 'creatorName'],
-  ['txt', '编辑时间', 'updateTime']
-]
-
-export const A2tableY2 = [
-  ['txt', '标题', 'name'],
-  ['img', '视频封面', 'thumb'],
-  ['text', '简介', 'description', 50],
-  ['txt', '附件', 'fileName'],
-  ['txt', '排序值', 'sort'],
-  ['txt', '编辑人', 'creatorName'],
-  ['txt', '编辑时间', 'updateTime']
+  ['txtNormal', '简介', 'intro'],
+  ['link', 'VR全景', 'vrUrl'],
+  ['link', '模型', 'modelUrl']
 ]
 
 export const A2tableC = [
-  ['txt', '分类名称', 'name'],
-  ['txt', '排序值', 'sort'],
-  ['txt', '编辑人', 'creatorName'],
-  ['txt', '编辑时间', 'updateTime']
-]
-
-export const A3tableC = [
-  ['txt', '书名', 'name'],
+  ['txtNormal', '名称', 'name'],
+  ['txtNormal', '标签', 'tag'],
   ['img', '封面', 'thumb'],
-  ['txt', '作者', 'author'],
-  ['txt', '出版社', 'press'],
-  ['txt', 'ISBN编号', 'num'],
-  ['txt', '排序值', 'sort'],
-  ['txt', '编辑人', 'creatorName'],
-  ['txt', '编辑时间', 'updateTime']
-]
-
-export const A4tableC = [
-  ['txt', '用户ID', 'openId'],
-  ['txt', '用户昵称', 'nickName'],
-  ['img', '用户头像', 'avatarUrl'],
-  ['txt', '注册时间', 'createTime'],
-  ['txt', '最近登录时间', 'lastLoginTime'],
-  ['txt', '最近登录IP', 'lastIp']
-]
-
-export const A5tableC = [
-  ['txt', '书名', 'name'],
-  ['img', '封面', 'thumb'],
-  ['txt', '作者', 'author'],
-  ['txt', '出版社', 'press'],
-  ['txt', 'ISBN编号', 'num'],
-  ['txt', '提交人', 'wxUserName'],
-  ['txt', '提交时间', 'createTime'],
-  ['txtChange', '审核状态', 'auditStatus', { 0: '待审核', 1: '审核通过', 2: '审核驳回' }],
-  ['text', '审核备注', 'auditDesc', 50]
-]
-
-export const A6tableC = [
-  ['txt', '书名', 'bookName'],
-  ['text', '评论内容', 'content', 50],
-  ['txtChange', '审核状态', 'auditStatus', { 0: '待审核', 1: '审核通过', 2: '审核驳回' }],
-  ['txt', '提交人', 'createBy'],
-  ['txt', '提交时间', 'createTime']
-]
-
-export const A7tableC = [
-  ['txt', '标题', 'name'],
-  ['txt', '公告类型', 'dictName'],
-  ['txt', '排序值', 'sort'],
-  ['txt', '编辑人', 'creatorName']
-]
-
-export const A7tableCtype = [
-  ['txt', '类型名称', 'name'],
-  ['txt', '排序值', 'sort']
+  ['scenes', '景点数量', 'siteIds']
 ]
 
 export const Z1tableC = [

+ 44 - 0
yarn.lock

@@ -1321,6 +1321,45 @@
   resolved "https://registry.npmmirror.com/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz#b6c75a56a1947cc916ea058772d666a2c8932f31"
   integrity sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==
 
+"@dnd-kit/accessibility@^3.1.1":
+  version "3.1.1"
+  resolved "https://registry.npmmirror.com/@dnd-kit/accessibility/-/accessibility-3.1.1.tgz#3b4202bd6bb370a0730f6734867785919beac6af"
+  integrity sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==
+  dependencies:
+    tslib "^2.0.0"
+
+"@dnd-kit/core@^6.3.1":
+  version "6.3.1"
+  resolved "https://registry.npmmirror.com/@dnd-kit/core/-/core-6.3.1.tgz#4c36406a62c7baac499726f899935f93f0e6d003"
+  integrity sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==
+  dependencies:
+    "@dnd-kit/accessibility" "^3.1.1"
+    "@dnd-kit/utilities" "^3.2.2"
+    tslib "^2.0.0"
+
+"@dnd-kit/modifiers@^9.0.0":
+  version "9.0.0"
+  resolved "https://registry.npmmirror.com/@dnd-kit/modifiers/-/modifiers-9.0.0.tgz#96a0280c77b10c716ef79d9792ce7ad04370771d"
+  integrity sha512-ybiLc66qRGuZoC20wdSSG6pDXFikui/dCNGthxv4Ndy8ylErY0N3KVxY2bgo7AWwIbxDmXDg3ylAFmnrjcbVvw==
+  dependencies:
+    "@dnd-kit/utilities" "^3.2.2"
+    tslib "^2.0.0"
+
+"@dnd-kit/sortable@^10.0.0":
+  version "10.0.0"
+  resolved "https://registry.npmmirror.com/@dnd-kit/sortable/-/sortable-10.0.0.tgz#1f9382b90d835cd5c65d92824fa9dafb78c4c3e8"
+  integrity sha512-+xqhmIIzvAYMGfBYYnbKuNicfSsk4RksY2XdmJhT+HAC01nix6fHCztU68jooFiMUB01Ky3F0FyOvhG/BZrWkg==
+  dependencies:
+    "@dnd-kit/utilities" "^3.2.2"
+    tslib "^2.0.0"
+
+"@dnd-kit/utilities@^3.2.2":
+  version "3.2.2"
+  resolved "https://registry.npmmirror.com/@dnd-kit/utilities/-/utilities-3.2.2.tgz#5a32b6af356dc5f74d61b37d6f7129a4040ced7b"
+  integrity sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg==
+  dependencies:
+    tslib "^2.0.0"
+
 "@emotion/hash@^0.8.0":
   version "0.8.0"
   resolved "https://registry.npmmirror.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413"
@@ -10192,6 +10231,11 @@ tslib@^1.8.1:
   resolved "https://registry.npmmirror.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
   integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
 
+tslib@^2.0.0:
+  version "2.8.1"
+  resolved "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f"
+  integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==
+
 tslib@^2.0.3, tslib@^2.4.1, tslib@^2.5.0:
   version "2.6.2"
   resolved "https://registry.npmmirror.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae"