shaogen1995 9 月之前
父節點
當前提交
f5f3766820

+ 4 - 2
src/components/ZupTypes/index.tsx

@@ -35,6 +35,7 @@ type Props = {
   fileCheck: boolean //有没有点击过确定
   dirCode: string //文件的code码
   myUrl: string //请求地址
+  isEdit: boolean //是否是编辑
   isLook?: boolean //是不是查看
   modelSize?: number //模型文件大小限制
   imgSize?: number //图片大小限制
@@ -55,6 +56,7 @@ function ZupTypes(
     fileCheck,
     dirCode,
     myUrl,
+    isEdit,
     isLook = false,
     modelSize = 500,
     imgSize = 5,
@@ -83,13 +85,13 @@ function ZupTypes(
     ]
 
     const arrRes = arr.filter(v => selecFlag.includes(v.label))
-    if (isTypeShow) {
+    if (isTypeShow && !isEdit) {
       setTypeCheck([arrRes[0].value])
       // 默认就选中
     }
 
     return arrRes
-  }, [isTypeShow, selecFlag])
+  }, [isEdit, isTypeShow, selecFlag])
 
   // 上传附件的信息
   const [fileList, setFileList] = useState({

+ 1 - 0
src/pages/A1goods/A1add/index.tsx

@@ -189,6 +189,7 @@ function A1add({ editInfo, closeFu, addTableFu, editTableFu }: Props) {
                 fileCheck={fileCheck}
                 dirCode={'A1goodsType'}
                 myUrl='cms/goods/upload'
+                isEdit={editInfo.id > 0}
                 isLook={editInfo.txt === '查看'}
                 isOneType={true}
                 isTypeShow={true}

+ 5 - 4
src/pages/A1goods/A1sort/index.tsx

@@ -18,7 +18,8 @@ type Props = {
 function A1sort({ closeFu, type }: Props) {
   const dispatch = useDispatch()
 
-  const { sortList } = useSelector((state: RootState) => state.A1goods)
+  const { sortList: sortList1 } = useSelector((state: RootState) => state.A1goods)
+  const { sortList: sortList2 } = useSelector((state: RootState) => state.A2expert)
 
   const delTableFu = useCallback(
     async (id: number) => {
@@ -76,7 +77,7 @@ function A1sort({ closeFu, type }: Props) {
       <div className='A1Stop'>
         <div>
           <h1>类别管理</h1>
-          <Button type='primary' onClick={() => setEditInfo({ id: -1 } as A1sortType)}>
+          <Button type='primary' onClick={() => setEditInfo({ id: -1, sort: 999 } as A1sortType)}>
             新增
           </Button>
         </div>
@@ -88,7 +89,7 @@ function A1sort({ closeFu, type }: Props) {
         <MyTable
           classKey='A1StableBox'
           yHeight={560}
-          list={sortList}
+          list={type === 'goods' ? sortList1 : sortList2}
           columnsTemp={A1sortTableC}
           lastBtn={tableLastBtn}
           pagingInfo={false}
@@ -115,7 +116,7 @@ function A1sort({ closeFu, type }: Props) {
                 maxLength={20}
                 showCount
                 value={editInfo.name}
-                onChange={e => setEditInfo({ ...editInfo, name: e.target.value })}
+                onChange={e => setEditInfo({ ...editInfo, name: e.target.value.trim() })}
               />
             </div>
           </div>

+ 98 - 0
src/pages/A2expert/A2add/index.module.scss

@@ -0,0 +1,98 @@
+.A2add {
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  z-index: 12;
+  background-color: #fff;
+  border-radius: 10px;
+  padding: 24px;
+
+  :global {
+    .A2aMain {
+      width: 100%;
+      height: 100%;
+      overflow-y: auto;
+
+      textarea {
+        min-height: 150px !important;
+      }
+
+      .A2fromRow {
+        position: relative;
+        width: 800px;
+
+        .A2_6Frow {
+          position: absolute;
+          left: 200px;
+          top: 5px;
+          color: #999;
+          font-size: 12px;
+        }
+      }
+
+      .ant-form {
+        width: 800px;
+
+        // .ant-input-affix-wrapper{
+        //   width: 800px;
+        // }
+        .formRow {
+          display: flex;
+
+          .formLeft {
+            position: relative;
+            top: 3px;
+            width: 100px;
+            text-align: right;
+
+            & > span {
+              color: #ff4d4f;
+            }
+          }
+
+          .formRight {
+            width: calc(100% - 100px);
+          }
+        }
+
+        .A2abtn {
+          position: absolute;
+          z-index: 10;
+          left: 1200px;
+          top: 50%;
+          transform: translateY(-50%);
+        }
+      }
+    }
+
+    // 从查看进入
+    .A2aMainLook {
+      // 左边的 label 也不让选中
+      label {
+        pointer-events: none;
+      }
+
+      .ant-picker {
+        pointer-events: none;
+      }
+
+      .ant-checkbox-wrapper {
+        pointer-events: none;
+      }
+
+      .ant-input-number {
+        pointer-events: none;
+      }
+
+      .ant-select {
+        pointer-events: none;
+      }
+
+      .ant-radio-wrapper {
+        pointer-events: none;
+      }
+    }
+  }
+}

+ 259 - 0
src/pages/A2expert/A2add/index.tsx

@@ -0,0 +1,259 @@
+import React, { useCallback, useEffect, useRef, useState } from 'react'
+import styles from './index.module.scss'
+import classNames from 'classnames'
+import { Button, Form, FormInstance, Input, InputNumber, Select } from 'antd'
+import { MessageFu } from '@/utils/message'
+import ZupOne from '@/components/ZupOne'
+import TextArea from 'antd/es/input/TextArea'
+import MyPopconfirm from '@/components/MyPopconfirm'
+import { useSelector } from 'react-redux'
+import { RootState } from '@/store'
+import ZupTypes from '@/components/ZupTypes'
+import { A1EditInfoType } from '@/pages/A1goods/data'
+import { A2_APIgetInfo, A2_APIsave } from '@/store/action/A2expert'
+
+type Props = {
+  editInfo: A1EditInfoType
+  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)
+
+  // 多张图片的ref
+  const ZupImgsRef = useRef<any>(null)
+
+  // 编辑/查看 进入页面 获取信息
+  const getInfoFu = useCallback(async (id: number) => {
+    const res = await A2_APIgetInfo(id)
+    if (res.code === 0) {
+      const info = res.data.entity
+
+      const obj = {
+        ...info,
+        dictId: Number(info.dictId)
+      }
+
+      FormBoxRef.current?.setFieldsValue(obj)
+
+      // 设置肖像
+      ZupThumbRef.current?.setFileComFileFu({
+        fileName: '',
+        thumb: info.thumb,
+        filePath: info.thumbPc
+      })
+
+      // 设置文件
+      const file = res.data.file || []
+
+      // 传给 附件 组件的
+      const sonInfo = {
+        type: info.fileType,
+        fileList: file
+      }
+      ZupImgsRef.current?.setFileComFileFu(sonInfo)
+    }
+  }, [])
+
+  // 附件 是否 已经点击过确定
+  const [fileCheck, setFileCheck] = useState(false)
+
+  useEffect(() => {
+    if (editInfo.id > 0) {
+      getInfoFu(editInfo.id)
+    } else {
+      FormBoxRef.current?.setFieldsValue({
+        sort: 999
+      })
+    }
+  }, [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('请上传肖像!')
+
+      const { sonFileIds, sonIsOk, sonType } = ZupImgsRef.current?.fileComFileResFu()
+      if (sonIsOk) return
+
+      const obj = {
+        ...values,
+        id: editInfo.id > 0 ? editInfo.id : null,
+        thumb: coverUrl1.thumb,
+        thumbPc: coverUrl1.filePath,
+        fileIds: sonFileIds ? sonFileIds.join(',') : null,
+        fileType: sonType ? sonType.join(',') : null
+      }
+
+      // if (obj) {
+      //   console.log(123, obj);
+      //   return;
+      // }
+
+      const res = await A2_APIsave(obj)
+
+      if (res.code === 0) {
+        MessageFu.success(`${editInfo.txt}成功!`)
+        editInfo.id > 0 ? editTableFu() : addTableFu()
+        closeFu()
+      }
+    },
+    [addTableFu, closeFu, editInfo.id, editInfo.txt, editTableFu]
+  )
+
+  const { sortList } = useSelector((state: RootState) => state.A2expert)
+
+  return (
+    <div className={styles.A2add}>
+      <div className={classNames('A2aMain', editInfo.txt === '查看' ? 'A2aMainLook' : '')}>
+        <Form
+          ref={FormBoxRef}
+          name='basic'
+          labelCol={{ span: 3 }}
+          onFinish={onFinish}
+          onFinishFailed={onFinishFailed}
+          autoComplete='off'
+          scrollToFirstError
+        >
+          <Form.Item
+            label='姓名'
+            name='name'
+            rules={[{ required: true, message: '请输入姓名!' }]}
+            getValueFromEvent={e => e.target.value.trim()}
+          >
+            <Input
+              readOnly={editInfo.txt === '查看'}
+              placeholder='请输入内容'
+              maxLength={20}
+              showCount
+            />
+          </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={'A2expert'}
+                myUrl='cms/expert/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='dictId'
+            rules={[{ required: true, message: '请选择类别!' }]}
+          >
+            <Select
+              placeholder='请选择'
+              style={{ width: 200 }}
+              fieldNames={{ label: 'name', value: 'id' }}
+              options={sortList}
+            />
+          </Form.Item>
+
+          {/* 文件类型 */}
+          <div className='formRow'>
+            <div className='formLeft'>
+              <span>* </span>
+              文件类型:
+            </div>
+            <div className='formRight'>
+              <ZupTypes
+                ref={ZupImgsRef}
+                selecFlag='图片/视频'
+                fileCheck={fileCheck}
+                dirCode={'A2expertType'}
+                myUrl='cms/expert/upload'
+                isEdit={editInfo.id > 0}
+                isLook={editInfo.txt === '查看'}
+                isTypeShow={true}
+              />
+            </div>
+          </div>
+          {editInfo.txt === '查看' ? <br /> : null}
+
+          <Form.Item label='简介' name='intro' getValueFromEvent={e => e.target.value.trim()}>
+            <Input
+              readOnly={editInfo.txt === '查看'}
+              placeholder='请输入内容'
+              maxLength={20}
+              showCount
+            />
+          </Form.Item>
+
+          <Form.Item label='介绍' name='remark'>
+            <TextArea
+              readOnly={editInfo.txt === '查看'}
+              maxLength={800}
+              showCount
+              placeholder='请输入内容'
+            />
+          </Form.Item>
+
+          <div className='A2fromRow'>
+            <Form.Item
+              label='排序值'
+              name='sort'
+              rules={[{ required: true, message: '请输入排序值!' }]}
+            >
+              <InputNumber min={1} max={999} precision={0} placeholder='请输入' />
+            </Form.Item>
+            <div className='A2_6Frow' hidden={editInfo.txt === '查看'}>
+              请输入1~999的数字。数字越小,排序越靠前。数字相同时,更新发布的内容排在前面
+            </div>
+          </div>
+
+          {/* 确定和取消按钮 */}
+          <Form.Item className='A2abtn'>
+            {editInfo.txt === '查看' ? (
+              <Button onClick={closeFu}>返回</Button>
+            ) : (
+              <>
+                <Button type='primary' htmlType='submit'>
+                  提交
+                </Button>
+                <br />
+                <br />
+                <MyPopconfirm txtK='取消' onConfirm={closeFu} />
+              </>
+            )}
+          </Form.Item>
+        </Form>
+      </div>
+    </div>
+  )
+}
+
+const MemoA2add = React.memo(A2add)
+
+export default MemoA2add

+ 37 - 0
src/pages/A2expert/index.module.scss

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

+ 175 - 2
src/pages/A2expert/index.tsx

@@ -1,9 +1,182 @@
-import React from 'react'
+import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
 import styles from './index.module.scss'
+import { useDispatch, useSelector } from 'react-redux'
+import { RootState } from '@/store'
+import { MessageFu } from '@/utils/message'
+import { A1tableType } from '@/types'
+import { Button, Input, Select } from 'antd'
+import MyPopconfirm from '@/components/MyPopconfirm'
+import MyTable from '@/components/MyTable'
+import { A2tableC } from '@/utils/tableData'
+import { A1EditInfoType, A1FromDataType } from '../A1goods/data'
+import A1sort from '../A1goods/A1sort'
+import { A2_APIdel, A2_APIgetList } from '@/store/action/A2expert'
+import { A1_APIgetDictList } from '@/store/action/A1goods'
+import A2add from './A2add'
+
+const fromDataBase: A1FromDataType = {
+  searchKey: '',
+  dictId: null,
+
+  pageNum: 1,
+  pageSize: 10
+}
+
 function A2expert() {
+  const dispatch = useDispatch()
+
+  // 获取类别数组
+
+  useEffect(() => {
+    dispatch(A1_APIgetDictList('expert'))
+  }, [dispatch])
+
+  const [fromData, setFromData] = useState(fromDataBase)
+
+  const getListFu = useCallback(() => {
+    dispatch(A2_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, sortList } = useSelector((state: RootState) => state.A2expert)
+
+  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: A1tableType) => (
+          <>
+            <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 [sortShow, setSortShow] = useState(false)
+
   return (
     <div className={styles.A2expert}>
-      <h1>A2expert</h1>
+      <div className='pageTitle'>专家风采 {editInfo.id ? ` - ${editInfo.txt}` : ''}</div>
+
+      {/* 顶部筛选 */}
+      <div className='A2top'>
+        <div>
+          <div className='A2TopRow'>
+            <span>类别:</span>
+            <Select
+              allowClear
+              placeholder='全部'
+              style={{ width: 200 }}
+              value={fromData.dictId}
+              onChange={e => setFromData({ ...fromData, pageNum: 1, dictId: e })}
+              fieldNames={{ label: 'name', value: 'id' }}
+              options={sortList}
+            />
+          </div>
+
+          <div className='A2TopRow'>
+            <span>搜索:</span>
+            <Input
+              key={inputKey}
+              maxLength={50}
+              style={{ width: 200 }}
+              placeholder='请输入名称'
+              allowClear
+              onChange={e => txtChangeFu(e, 'searchKey')}
+            />
+          </div>
+        </div>
+        <div>
+          <Button onClick={resetSelectFu}>重置</Button>&emsp;
+          <Button type='primary' onClick={() => setEditInfo({ id: -1, txt: '新增' })}>
+            新增
+          </Button>
+          &emsp;
+          <Button type='primary' onClick={() => setSortShow(true)}>
+            类别管理
+          </Button>
+        </div>
+      </div>
+
+      {/* 表格主体 */}
+      <div className='A2tableBox'>
+        <MyTable
+          yHeight={625}
+          list={tableInfo.list}
+          columnsTemp={A2tableC}
+          lastBtn={tableLastBtn}
+          pageNum={fromData.pageNum}
+          pageSize={fromData.pageSize}
+          total={tableInfo.total}
+          onChange={(pageNum, pageSize) => setFromData({ ...fromData, pageNum, pageSize })}
+        />
+      </div>
+
+      {/* 类别管理 */}
+      {sortShow ? (
+        <div className='A2sortBox'>
+          <A1sort closeFu={() => setSortShow(false)} type='expert' />
+        </div>
+      ) : null}
+
+      {editInfo.id ? (
+        <A2add
+          editInfo={editInfo}
+          closeFu={() => setEditInfo({} as A1EditInfoType)}
+          addTableFu={resetSelectFu}
+          editTableFu={getListFu}
+        />
+      ) : null}
     </div>
   )
 }

+ 1 - 1
src/store/action/A1goods.ts

@@ -47,7 +47,7 @@ export const A1_APIgetDictList = (type: 'goods' | 'expert'): any => {
   return async (dispatch: AppDispatch) => {
     const res = await http.get(`cms/dict/getList?type=${type}`)
     if (res.code === 0) {
-      dispatch({ type: 'A1/getSortList', payload: res.data })
+      dispatch({ type: type === 'goods' ? 'A1/getSortList' : 'A2/getSortList', payload: res.data })
     }
   }
 }

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

@@ -0,0 +1,39 @@
+import http from '@/utils/http'
+import { AppDispatch } from '..'
+
+/**
+ *馆藏文物-列表
+ */
+
+export const A2_APIgetList = (data: any): any => {
+  return async (dispatch: AppDispatch) => {
+    const res = await http.post('cms/expert/pageList', data)
+    if (res.code === 0) {
+      const obj = {
+        list: res.data.records,
+        total: res.data.total
+      }
+      dispatch({ type: 'A2/getList', payload: obj })
+    }
+  }
+}
+/**
+ * 馆藏文物-删除
+ */
+export const A2_APIdel = (id: number) => {
+  return http.get(`cms/expert/remove/${id}`)
+}
+
+/**
+ * 馆藏文物-获取详情
+ */
+export const A2_APIgetInfo = (id: number) => {
+  return http.get(`cms/expert/detail/${id}`)
+}
+
+/**
+ * 馆藏文物-新增、编辑
+ */
+export const A2_APIsave = (data: any) => {
+  return http.post('cms/expert/save', data)
+}

+ 39 - 0
src/store/reducer/A2expert.ts

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

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

@@ -4,6 +4,7 @@ import { combineReducers } from 'redux'
 // 导入 登录 模块的 reducer
 import A0Layout from './layout'
 import A1goods from './A1goods'
+import A2expert from './A2expert'
 import Z1user from './Z1user'
 import Z2log from './Z2log'
 
@@ -11,6 +12,7 @@ import Z2log from './Z2log'
 const rootReducer = combineReducers({
   A0Layout,
   A1goods,
+  A2expert,
   Z1user,
   Z2log
 })

+ 9 - 0
src/utils/tableData.ts

@@ -22,6 +22,15 @@ export const A1tableC = [
   ['txt', '排序值', 'sort']
 ]
 
+export const A2tableC = [
+  ['txt', '类别', 'dictName'],
+  ['txt', '姓名', 'name'],
+  ['img', '照片', 'thumb'],
+  ['text', '简介', 'intro', 50],
+  ['text', '介绍', 'remark', 50],
+  ['txt', '排序值', 'sort']
+]
+
 export const A1sortTableC = [
   ['txt', '类型名称', 'name'],
   ['txt', '排序值', 'sort']