Browse Source

修复文件上传和下载的BUG;更新文件上传后的反馈提示,现在可以对具体的事件和选项进行反馈;

fxs 7 months ago
parent
commit
93a1205fab

+ 7 - 2
src/components/form/FileUpload.vue

@@ -43,7 +43,7 @@ const beforeUpload = (file: UploadRawFile) => {
   reader.onload = function () {
     try {
       const finnalResult = reader.result as string
-      //   console.log(JSON.parse(finnalResult))
+
       emits('uploadSuccess', JSON.parse(finnalResult))
       state = true
     } catch {
@@ -185,6 +185,9 @@ defineExpose({
           <br />
           <p>
             <b>请确保上传的选项对应的均是同一游戏的选项,否则可能会上传失败</b>
+            <br />
+            <br />
+            <b>提供其他额外的字段可能会被直接忽略</b>
           </p>
           <pre>
                     <code>
@@ -202,7 +205,7 @@ defineExpose({
       // 新增
         {
             "gid": "1200",
-            "actionId": "123",
+            "actionId": "456",
             "actionName": "第二关过关",
             "status": 0,
             "remark": "t"
@@ -215,6 +218,7 @@ defineExpose({
         "123": [
             {
                 "id": 1,  // 更新需要传入id
+                "actionId": 123,
                 "optionId": "test",
                 "optionName": "test",
                 "optionType": "string",
@@ -225,6 +229,7 @@ defineExpose({
         // 如果不存在这个actionid则视为新增
         "888":[
             {
+              "actionId": 456,
                 "optionId": "ba",
                 "optionName": "bgbb",
                 "optionType": "int",

+ 7 - 2
src/types/res.ts

@@ -1,8 +1,13 @@
 export interface ResponseInfo {
   code: number
   msg: string
-  data: any
-  count: number
+  data?: any
+  count?: number
+}
+
+export interface ErrorResInfo {
+  code: number
+  msg: string
 }
 
 export enum MessageType {

+ 13 - 3
src/utils/axios/axiosInstance.ts

@@ -2,7 +2,7 @@
  * @Author: fxs bjnsfxs@163.com
  * @Date: 2024-08-20 17:18:52
  * @LastEditors: fxs bjnsfxs@163.com
- * @LastEditTime: 2024-10-10 18:31:00
+ * @LastEditTime: 2024-10-12 12:15:23
  * @FilePath: \Game-Backstage-Management-System\src\utils\axios\axiosInstance.ts
  * @Description:
  *
@@ -18,6 +18,12 @@ import { setLoginState } from '../localStorage/localStorage'
 
 const { baseURL } = useRequest()
 
+const errorCodeMsg: {
+  [key: number]: string
+} = {
+  422: '请求缺少参数,请检查后重试'
+}
+
 // 创建axios实例
 const axiosInstance = axios.create({
   baseURL,
@@ -93,13 +99,17 @@ axiosInstance.interceptors.response.use(
     return response.data
   },
   function (error) {
+    let code = error.response.data.code
+    let msg = errorCodeMsg[code] ?? '服务器错误,请稍后再试'
+
     // 对响应错误做点什么
     ElMessage({
       type: MessageType.Error,
-      message: '服务器错误,请稍后再试',
+      message: msg,
       duration: 1500
     })
-    setLoginState(false)
+    // console.log(error)
+    // setLoginState(false)
     // router.push('/login')
     return Promise.reject(error)
   }

+ 246 - 147
src/views/AppManage/EventManageView.vue

@@ -2,12 +2,14 @@
  * @Author: fxs bjnsfxs@163.com
  * @Date: 2024-09-02 17:57:15
  * @LastEditors: fxs bjnsfxs@163.com
- * @LastEditTime: 2024-10-11 17:56:04
+ * @LastEditTime: 2024-10-12 16:45:15
  * @FilePath: \Game-Backstage-Management-System\src\views\AppManage\EventManageView.vue
  * @Description: 
  * 
 -->
 <script setup lang="ts">
+import type { ResponseInfo } from '@/types/res'
+
 import HeaderCard from '@/components/dataAnalysis/HeaderCard.vue'
 import { shouldListenToEvent } from '@/utils/table/table'
 import { ref, reactive, computed } from 'vue'
@@ -23,6 +25,57 @@ import { downLoadData } from '@/utils/table/table'
 import { resetTimeToMidnight } from '@/utils/common'
 import router from '@/router'
 
+interface uploadEvent {
+  id?: number // 更新需要传入id
+  gid: string
+  actionId: string
+  actionName: string
+  status: number
+  remark?: string
+}
+
+interface UploadOption {
+  id?: number // 更新需要传入id
+  optionId: string
+  optionName: string
+  optionType: string
+  actionId: number
+  status: number
+}
+
+interface DownLoadEvent {
+  actionId: string
+  actionName: string
+  createdAt: string
+  gid: string
+  id: number
+  remark: string
+  status: number
+  updatedAt: string
+}
+
+interface DownLoadOption {
+  actionId: number
+  createdAt: string
+  id: number
+  optionId: string
+  optionName: string
+  optionType: string
+  status: number
+  updatedAt: string
+}
+
+type GetTableReturn<T> = T extends 'all'
+  ? {
+      allEventTable: Array<DownLoadEvent>
+      allOptionsInfo: { [key: string]: Array<DownLoadOption> }
+    }
+  : T extends 'event'
+    ? { allEventTable: Array<DownLoadEvent> }
+    : T extends 'option'
+      ? { allOptionsInfo: { [key: string]: Array<DownLoadOption> } }
+      : never
+
 const { selectInfo } = useCommonStore()
 
 const { AllApi } = useRequest()
@@ -56,47 +109,57 @@ const headerAddPath = (info: any) => {
 }
 
 /**
+ * @description:  展示上传之后的反馈信息
+ * @param {*} state 这个状态只表示是否全部成功,其余情况皆为false
+ * @param {*} name 区分是事件还是选项
+ * @return {*}
+ */
+const showUploadMsg = (failedCount: number, totalCount: number, name: string): boolean => {
+  if (failedCount < 0) throw new Error('Error!FailedCount < 0')
+
+  let state = true
+  let duration = 3000
+  let title = '上传成功'
+  let position: 'top-left' | 'top-right' = 'top-left'
+  let message: string = `${name}全部上传成功`
+  let type: 'success' | 'warning' | 'error' = 'success'
+
+  // 有上传失败的情况下
+  if (failedCount > 0) {
+    state = false
+    position = 'top-right'
+    duration = 8000
+    if (failedCount === totalCount) {
+      message = `${name}全部上传失败`
+      type = 'error'
+    } else {
+      message = `${name}部分上传失败`
+      type = 'warning'
+    }
+  }
+  ElNotification({
+    type,
+    title,
+    message,
+    duration,
+    position
+  })
+
+  return state
+}
+
+/**
  * @description:  提交所有新上传的事件及选项请求
  * @param {*} reqList 请求列表
  * @param {*} msg 提示信息,用于展示上传之后返回的消息
  * @return {*}
  */
-const submitUpload = async (reqList: Array<Promise<boolean>>, msg?: string): Promise<boolean> => {
+const submitUpload = async (reqList: Array<Promise<boolean>>, msg: string): Promise<boolean> => {
   const result = await Promise.allSettled(reqList).then((res) => {
     const failedList = res.filter((item: any) => item.value === false)
     const failedCount = failedList.length
     const totalCount = res.length
-    let state = true
-
-    if (failedCount === 0) {
-      // 全部成功
-      ElNotification({
-        type: 'success',
-        title: '上传完成',
-        message: `${msg}全部上传成功`,
-        position: 'top-left',
-        duration: 3000
-      })
-    } else if (failedCount === totalCount) {
-      // 全部失败
-      ElNotification({
-        type: 'error',
-        title: '上传完成',
-        message: `${msg}全部上传失败,请检查参数`,
-        duration: 5000,
-        position: 'top-left'
-      })
-      state = false
-    } else {
-      // 部分失败
-      ElNotification({
-        type: 'warning',
-        title: '上传完成',
-        message: `${msg}部分上传成功`,
-        position: 'top-left',
-        duration: 5000
-      })
-    }
+    let state = showUploadMsg(failedCount, totalCount, msg)
     return state
   })
 
@@ -126,21 +189,14 @@ const getTableData = async (
       ...otherInfo
     })
     .then(async (res) => {
-      let resultData: any = []
       let resData = JSON.parse(JSON.stringify(res))
       let result = []
-      // if (!resData.data) return []
-      // // nowOptionList.push(...resData.data)
-      // if (resData.count > total) {
-      //   result = await getTableData(url, otherInfo, total, limit)
-      // }
-      if (resData.data && resData.count > total) {
+      if (!resData.data) return []
+
+      if (resData.count > total) {
         result = await getTableData(url, otherInfo, total, limit)
-        resultData = [...resData.data, ...result]
       }
-
-      return resultData
-      // return [...resData.data, ...result]
+      return [...resData.data, ...result]
     })
     .catch((err) => {
       console.log(err)
@@ -159,19 +215,19 @@ const getTableData = async (
 const batReqOptionsData = async (
   url: string,
   reqParams: Array<any>,
-  eventTable: Array<any>
-): Promise<Object> => {
+  eventTable: Array<DownLoadEvent>
+): Promise<{ [key: string]: Array<DownLoadOption> }> => {
   let reqList: Array<Promise<any>> = []
   let finalResult: {
-    [key: string]: Array<any>
+    [key: string]: Array<DownLoadOption>
   } = {}
 
   reqParams.map((item) => {
     reqList.push(
       getTableData(url, item)
         .then((res) => {
-          let actionId = eventTable.find((i) => i.id === item.actionId).actionId
-          finalResult[actionId] = res
+          let actionId = eventTable.find((i) => i.id === item.actionId)?.actionId
+          if (actionId) finalResult[actionId] = res
         })
         .catch((err) => {
           console.log(err)
@@ -182,24 +238,26 @@ const batReqOptionsData = async (
   return finalResult
 }
 
-type GetTableReturn<T> = T extends 'all'
-  ? { allEventTable: Array<any>; allOptionsInfo: any }
-  : T extends 'event'
-    ? { allEventTable: Array<any> }
-    : T extends 'option'
-      ? { allOptionsInfo: any }
-      : never
-
 /**
  * @description: 拿到事件数据和选项数据,首先需要拿到所有的事件列表,然后将他们的actionId抽出来形成一个列表,这个列表去作为optin的查询参数批量查询
  * @return {*} 返回事件数据和选项数据
  */
 const getAllTable = async <T extends 'all' | 'event' | 'option' = 'all'>(
-  table?: T
+  table: T = 'all' as any
 ): Promise<GetTableReturn<T>> => {
-  let allEventTable: Array<any> = [],
-    allOptionsInfo: any = null
+  let allEventTable: Array<DownLoadEvent> = [],
+    allOptionsInfo: { [key: string]: Array<DownLoadOption> } = {}
+
   allEventTable = await getTableData(AllApi.gameActionList, { gid: selectInfo.gid })
+
+  let optionReqList = allEventTable.map((item) => {
+    return { actionId: item.id }
+  })
+  allOptionsInfo = await batReqOptionsData(
+    AllApi.gameActionOptionList,
+    optionReqList,
+    allEventTable
+  )
   // 只需要事件列表在这里就返回
   if (table === 'event') {
     return { allEventTable } as GetTableReturn<T>
@@ -207,14 +265,6 @@ const getAllTable = async <T extends 'all' | 'event' | 'option' = 'all'>(
 
   // 只需要选项在这里就只返回选项
   if (table === 'option') {
-    let optionReqList = allEventTable.map((item) => {
-      return { actionId: parseInt(item.id) }
-    })
-    allOptionsInfo = await batReqOptionsData(
-      AllApi.gameActionOptionList,
-      optionReqList,
-      allEventTable
-    )
     return { allOptionsInfo } as GetTableReturn<T>
   }
 
@@ -243,6 +293,124 @@ const startDownload = async () => {
   })
 }
 
+/**
+ * @description: 创建一个上传请求函数
+ * @param {*} url 请求地址
+ * @param {*} reqParams 请求参数
+ * @param {*} name 上传的是事件还是选项
+ * @return {*}
+ */
+const createUploadReqFunc = async (url: string, reqParams: any, name: string): Promise<boolean> => {
+  let result: boolean = false
+  try {
+    const res: ResponseInfo = await axiosInstance.post<string, ResponseInfo>(url, reqParams)
+
+    if (res.code !== 0) {
+      ElNotification({
+        type: 'warning',
+        title: '事件上传失败',
+        dangerouslyUseHTMLString: true,
+        message: `${name}上传失败.<br/>${res.msg}`,
+        position: 'top-left',
+        duration: 8000
+      })
+    }
+
+    result = res.code === 0
+  } catch (err: any) {
+    ElNotification({
+      type: 'error',
+      title: '上传失败',
+      message: `${name}上传失败,请检查参数`,
+      position: 'top-right',
+      duration: 5000
+    })
+    console.log(err)
+  }
+  return result
+}
+
+/**
+ * @description: 上传所有事件
+ * @param {*} uploadEventTable 上传的事件列表
+ * @param {*} allEventTable 获取的事件列表
+ * @return {Promise<boolean>} 返回是否上传成功
+ */
+const uploadEvent = async (
+  uploadEventTable: Array<uploadEvent>,
+  allEventTable: Array<DownLoadEvent>
+): Promise<boolean> => {
+  let eventReqUrl = AllApi.setGameAction
+  let eventReqList: Array<Promise<boolean>> = []
+  uploadEventTable.map((item: uploadEvent) => {
+    let { id, ...otherInfo } = item
+    if (allEventTable.some((i: DownLoadEvent) => i.actionId === item.actionId)) {
+      eventReqUrl = AllApi.updateGameAction
+    }
+    let eventReq = createUploadReqFunc(eventReqUrl, otherInfo, item.actionName)
+    eventReqList.push(eventReq) // 统一放入请求列表中
+  })
+  return await submitUpload(eventReqList, '事件') // 等待所有的事件请求完成
+}
+
+/**
+ * @description: 上传所有选项
+ * @param {*} uploadOptionsInfo 上传的选项列表
+ * @return {*}
+ */
+const uploadOpiton = async (uploadOptionsInfo: { [key: string]: Array<UploadOption> }) => {
+  const { allEventTable, allOptionsInfo } = await getAllTable() // 重新获取所有事件列表和选项列表
+  let optionsReqList: Array<Promise<boolean>> = []
+  if (Object.keys(uploadOptionsInfo).length) {
+    // 开始上传选项
+    allEventTable.map((item) => {
+      // 在上传的事件列表中,找到有对应的事件的actionid的那一组数据
+      let uploadOptionItem = uploadOptionsInfo[item.actionId]
+      // 在现有的事件列表中,找到对应事件的actionid的那一组数据
+      let nowOptionItem = allOptionsInfo[item.actionId] // 找到所有在已有事件列表中的选项列表
+
+      // 如果有已存在的事件,并且上传的选项列表中也有对应的actionid,则开始上传
+      if (uploadOptionItem) {
+        // 对找到的那一组数据进行循环,区分出来哪些是已有的,哪些是新上传的
+        // 新上传的需要给他加上actionid,然后上传,这个actionid其实是事件列表的id字段
+        uploadOptionItem.map((i) => {
+          const { id, actionId: originalActionId, ...otherInfo } = i // 上传参数拆分出来
+          const isUpdate = nowOptionItem.some((k) => k.id === id) // 判断是否是更新选项
+
+          // 设置请求 URL 和参数
+          const optionReqUrl = isUpdate ? AllApi.updateGameActionOption : AllApi.addGameActionOption
+          const reqParams = isUpdate
+            ? { id, ...otherInfo } // 更新选项
+            : { actionId: item.id, ...otherInfo } // 新增选项
+
+          let eventReq = createUploadReqFunc(optionReqUrl, reqParams, item.actionName)
+          optionsReqList.push(eventReq) // 统一放入请求列表中
+        })
+      } else {
+        setTimeout(() => {
+          ElNotification({
+            type: 'warning',
+            title: `没有对应事件`,
+            message: `没有${item.actionName}事件,为事件添加的选项无效`,
+            position: 'top-right',
+            duration: 8000
+          })
+        }, 0)
+      }
+    })
+
+    await submitUpload(optionsReqList, '选项') // 等待所有选项上传完成
+  } else {
+    ElNotification({
+      type: 'warning',
+      title: '没有选项被上传',
+      message: `上传选项为空`,
+      position: 'top-right',
+      duration: 8000
+    })
+  }
+}
+
 // 上传选项的时候,选项的键要设置为actionid
 // 需要先上传事件,然后上传完了,用上传的选项中的第一个(如果有)的actionid去找到对应的事件的ID(不是actionid),然后作为选项上传的id
 /**
@@ -254,96 +422,27 @@ const startDownload = async () => {
  * @param {*} data 上传的文件数据,里面包含allEventTable:所有的事件列表,allOptionsInfo:所有选项列表
  * @return {*}
  */
-const uploadSuccess = async (data: any) => {
+const uploadSuccess = async (data: {
+  allEventTable: Array<uploadEvent>
+  allOptionsInfo: { [key: string]: Array<UploadOption> }
+}) => {
   let uploadEventTable = data.allEventTable
   let uploadOptionsInfo = data.allOptionsInfo
-  let allEventTable: Array<any> = [],
-    allOptionsInfo: { [key: string]: any } = {}
+
+  let allEventTable: Array<DownLoadEvent> = []
+
   // 上传的事件列表有值,则开始上传
   ;({ allEventTable } = await getAllTable('event')) // 获取所有事件列表和选项列表
 
-  // 开始上传事件
-  let eventReqList: Array<Promise<boolean>> = []
-  let eventReqUrl = AllApi.setGameAction
   let eventUploadResult = false
 
-  if (Array.isArray(uploadEventTable) && uploadEventTable.length) {
+  if (Array.isArray(uploadEventTable) && uploadEventTable.length > 0) {
     // 将新事件和旧事件区分,对于新事件走新增,对于旧事件走更新
-    uploadEventTable.map((item) => {
-      let { id, createdAt, updatedAt, ...otherInfo } = item
-      if (allEventTable.some((i) => i.actionId === item.actionId)) {
-        eventReqUrl = AllApi.updateGameAction
-      } else {
-        eventReqUrl = AllApi.setGameAction
-      }
-      let eventReq = axiosInstance
-        .post(eventReqUrl, otherInfo)
-        .then((res: any) => {
-          return res.code === 0
-        })
-        .catch((err) => {
-          console.log(err)
-          return false
-        })
-      eventReqList.push(eventReq) // 统一放入请求列表中
-    })
 
-    eventUploadResult = await submitUpload(eventReqList, '事件') // 等待所有的事件请求完成
+    eventUploadResult = await uploadEvent(uploadEventTable, allEventTable)
     // 如果事件上传全部失败,那么就不要再上传选项了
     if (eventUploadResult) {
-      ;({ allEventTable, allOptionsInfo } = await getAllTable()) // 重新获取所有事件列表和选项列表
-      let optionsReqList: Array<Promise<boolean>> = []
-      if (uploadOptionsInfo) {
-        // 开始上传选项
-        allEventTable.map((item) => {
-          // 在上传的事件列表中,找到有对应的事件的actionid的那一组数据
-          let uploadOptionItem = uploadOptionsInfo[item.actionId] as Array<any>
-          // 在现有的事件列表中,找到对应事件的actionid的那一组数据
-          let nowOptionItem = allOptionsInfo[item.actionId] as Array<any> // 找到所有在已有事件列表中的选项列表
-
-          // 如果有已存在的事件,并且上传的选项列表中也有对应的actionid,则开始上传
-          if (uploadOptionItem) {
-            // 对找到的那一组数据进行循环,区分出来哪些是已有的,哪些是新上传的
-            // 新上传的需要给他加上actionid,然后上传,这个actionid其实是事件列表的id字段
-            uploadOptionItem.map((i) => {
-              let optionReqUrl = AllApi.addGameActionOption // 选项上传的url
-              let { id, actionId, createdAt, updatedAt, ...otherInfo } = i // 上传参数拆分出来
-              let reqParams = {}
-              // 分出来哪些是新增加的选项,哪些是需要更新的选项
-              // 新增的选项需要加入的是事件列表的主键,而更新中需要加入的是option的id
-              if (nowOptionItem.some((k) => k.id === i.id)) {
-                reqParams = { id, ...otherInfo }
-
-                optionReqUrl = AllApi.updateGameActionOption
-              } else {
-                actionId = item.id
-                reqParams = { actionId, ...otherInfo }
-                optionReqUrl = AllApi.addGameActionOption
-              }
-              let optionReq = axiosInstance
-                .post(optionReqUrl, reqParams)
-                .then((res: any) => {
-                  if (res.code === 0) return true
-                  return false
-                })
-                .catch((err) => {
-                  console.log(err)
-                  return false
-                })
-              optionsReqList.push(optionReq)
-            })
-          }
-        })
-        await submitUpload(optionsReqList, '选项') // 等待所有选项上传完成
-      } else {
-        ElNotification({
-          type: 'warning',
-          title: '没有选项参数',
-          message: `上传选项为空`,
-          position: 'top-left',
-          duration: 5000
-        })
-      }
+      uploadOpiton(uploadOptionsInfo)
     }
   } else {
     ElNotification({