Преглед на файлове

Merge branch 'alert-question-zjc' into 'all'

feat: 简单闭环问题/中建材版本--报警问题管理对齐复杂闭环

See merge request skyeye/skyeye_frontend/skyeye-admin!175
楼航飞 преди 1 година
родител
ревизия
0c8f719266

+ 219 - 94
src/views/datamanager/alertformdata/components/common/AlertTableSimple.vue

@@ -1,17 +1,36 @@
 <template>
   <div class="alert-table-box">
-    <el-table ref="multipleTableRef" :data="tableData" style="width: 100%" height="100%" stripe
-      :cell-style="colorOfState" @selection-change="handleSelectionChange">
+    <el-table
+      ref="multipleTableRef"
+      :data="tableData"
+      style="width: 100%"
+      height="100%"
+      :cell-style="colorOfState"
+      :row-class-name="colorOfRow"
+      @select="handleShiftSelect"
+      @selection-change="handleSelectionChange"
+      @row-click="handleRowClick"
+      @sort-change="handleTimeSort"
+      :default-sort="{ prop: 'createdAt', order: 'descending' }"
+    >
       <el-table-column type="selection" width="55"></el-table-column>
-      <el-table-column label="类型" prop="issueType" width="150">
+      <el-table-column label="类型" prop="issueType" width="180">
         <template #default="{ row }">
           {{ getNameByType(row.source, row.issueType) }}
         </template>
       </el-table-column>
-      <el-table-column label="问题描述" prop="description" width="400" show-overflow-tooltip>
+      <el-table-column label="问题描述" prop="description" width="280" show-overflow-tooltip>
         <template #default="{ row }">
           <span>{{ getSplicedDes(row.description) }}</span>
-          <span class="detail-text" @click="handleDetailClick(row)"> 详情</span>
+          <span
+            class="detail-text"
+            @click="
+              handleDetailClick(row);
+              $event.stopPropagation();
+            "
+          >
+            详情</span
+          >
         </template>
       </el-table-column>
       <el-table-column label="地点" prop="workspaceId" width="300">
@@ -19,7 +38,12 @@
           {{ getNameByWorkid(row.workshopId, row.workspaceId, locationOptions) }}
         </template>
       </el-table-column>
-      <el-table-column label="时间" prop="createdAt" width="180"></el-table-column>
+      <el-table-column
+        label="时间"
+        prop="createdAt"
+        width="180"
+        sortable="custom"
+      ></el-table-column>
       <el-table-column label="负责人" prop="personNameInCharge" width="100"></el-table-column>
       <el-table-column label="处理状态" prop="issueState">
         <template #default="{ row }">
@@ -28,7 +52,16 @@
       </el-table-column>
       <el-table-column label="操作" width="60" fixed="right">
         <template #default="{ row }">
-          <img src="/src/assets/images/alert/delete.png" alt="" title="点击删除问题数据" @click="handleDelete(row)">
+          <el-tooltip effect="dark" content="点击删除问题数据" placement="top">
+            <img
+              src="/src/assets/images/alert/delete.png"
+              alt=""
+              @click="
+                handleDelete(row);
+                $event.stopPropagation();
+              "
+            />
+          </el-tooltip>
         </template>
       </el-table-column>
     </el-table>
@@ -36,105 +69,197 @@
 </template>
 
 <script setup lang="ts">
-import { ElTable } from 'element-plus';
-import { onBeforeMount, ref } from 'vue';
-import { getNameByStateZJC } from './constant.question';
-import { useIssueType } from '../../hooks/useIssueType';
-import { useWorkLocation } from '../../hooks/useWorkLocation';
-
-const { getAIOptions, getManualOptions, getNameByType } = useIssueType();
-const { locationOptions, getLocationOptions, getNameByWorkid } = useWorkLocation();
-
-const multipleTableRef = ref<InstanceType<typeof ElTable>>();
-
-interface DataSourceItem {
-  source: Number,         // 问题单来源:1-AI检测、2-人工上报
-  issueType: Number,      // 问题单类型
-  description: String,    // 问题描述
-  workspaceId: Number[],  // 工位id(地点=车间+工位?)
-  createdAt: String,
-  personNameInCharge: String,
-  issueState: Number,     // 问题单状态:1-待审核、2-待处理、3-待复核、4-已退回、5-已处理
-};
-
-interface Props {
-  tableData: Array<DataSourceItem>;
-  onDetail: (row: DataSourceItem) => unknown; // 详情事件
-  onDelete: (row: DataSourceItem) => unknown; // 删除按钮事件
-};
-
-const props = defineProps<Props>();
-
-const emits = defineEmits(['update:selection'])
-const handleSelectionChange = (selection: any[]) => {
-  emits("update:selection", selection);
-};
-
-const handleDetailClick = (row) => {
-  props.onDetail(row);
-};
-const handleDelete = (row) => {
-  props.onDelete(row);
-};
-
-const getSplicedDes = (val) => {
-  if (val.length < 20) return val;
-  else {
-    const temp = val.substring(0, 20);
-    return temp + '…';
+  import { ElTable } from 'element-plus';
+  import { onBeforeMount, onMounted, ref } from 'vue';
+  import { getNameByStateZJC } from './constant.question';
+  import { useIssueType } from '../../hooks/useIssueType';
+  import { useWorkLocation } from '../../hooks/useWorkLocation';
+
+  const { getAIOptions, getManualOptions, getNameByType } = useIssueType();
+  const { locationOptions, getLocationOptions, getNameByWorkid } = useWorkLocation();
+
+  const multipleTableRef = ref<InstanceType<typeof ElTable>>();
+
+  export interface DataSourceItem {
+    index: Number;
+    id: Number;
+    source: Number; // 问题单来源:1-AI检测、2-人工上报
+    issueType: Number; // 问题单类型
+    description: String; // 问题描述
+    workspaceId: Number[]; // 工位id(地点=车间+工位?)
+    createdAt: String;
+    personNameInCharge: String;
+    issueState: Number; // 问题单状态:1-待审核、2-待处理、3-待复核、4-已退回、5-已处理
   }
-};
 
-const colorOfState = ({ row, columnIndex }) => {
-  if (columnIndex === 6) {
-    if (row.issueState === 7 || row.issueState === 8) return { color: "#52C41A " };
-    else return { color: "#FF4D4F" };
-  };
-  if (row.isHide) {
-    return { color: "#A8ABB2" };
+  interface Props {
+    tableData: Array<DataSourceItem>;
+    onDetail: (row: DataSourceItem) => unknown; // 详情事件
+    onDelete: (row: DataSourceItem) => unknown; // 删除按钮事件
   }
-};
 
-const clearAll = () => {
-  multipleTableRef.value!.clearSelection();
-};
+  const props = defineProps<Props>();
+
+  const emits = defineEmits(['update:selection', 'update:timeSort']);
+
+  const startPoint = ref<number | undefined>();
+  const endPoint = ref<number | undefined>();
+  const shiftKeyBoard = ref(false); // shift按钮按住/松开
+
+  const selections = ref<DataSourceItem[]>([]);
+  const handleSelectionChange = (selection: any[]) => {
+    selections.value = selection;
+    emits('update:selection', selection);
+  };
+
+  const handleShiftSelect = (_, row) => {
+    props.tableData.forEach((item, index) => {
+      item.index = index;
+    });
+    // 按住shift
+    if (shiftKeyBoard.value) {
+      // 有起点startPoint
+      if (startPoint.value !== undefined) {
+        endPoint.value = row.index as number;
+        if (startPoint.value > endPoint.value) {
+          let temp = startPoint.value;
+          startPoint.value = endPoint.value;
+          endPoint.value = temp;
+        }
+        setTimeout(() => {
+          for (let i = startPoint.value as number; i < (endPoint.value as number); i++) {
+            multipleTableRef.value!.toggleRowSelection(props.tableData[i], true);
+          }
+        }, 100);
+      }
+      // 没有起点startPoint
+      else {
+        startPoint.value = row.index;
+        endPoint.value = undefined;
+      }
+    }
+    // 没按住shift
+    else {
+      startPoint.value = row.index;
+      endPoint.value = undefined;
+    }
+  };
+
+  const rowClickSelections = ref<DataSourceItem[]>([]);
+  const handleRowClick = (row) => {
+    if (rowClickSelections.value.find((item) => item.id === row.id)) {
+      let index = rowClickSelections.value.findIndex((item) => item.id === row.id);
+      rowClickSelections.value.splice(index, 1);
+      multipleTableRef.value!.toggleRowSelection(row, false);
+    } else {
+      rowClickSelections.value.push(row);
+      multipleTableRef.value!.toggleRowSelection(row, true);
+    }
+  };
+
+  const handleDetailClick = (row) => {
+    props.onDetail(row);
+  };
+  const handleDelete = (row) => {
+    props.onDelete(row);
+  };
+
+  const handleTimeSort = (column) => {
+    let curTimeSort = '';
+    if (column.order === 'ascending') curTimeSort = 'asc';
+    if (column.order === 'descending') curTimeSort = 'desc';
+    emits('update:timeSort', curTimeSort);
+  };
+
+  const getSplicedDes = (val) => {
+    if (val.length < 15) return val;
+    else {
+      const temp = val.substring(0, 14);
+      return temp + '…';
+    }
+  };
+
+  const colorOfState = ({ row, columnIndex }) => {
+    if (columnIndex === 6) {
+      if (row.issueState === 7 || row.issueState === 8) return { color: '#52C41A ' };
+      else return { color: '#FF4D4F' };
+    }
+    if (row.isHide) {
+      return { color: '#A8ABB2' };
+    }
+  };
+
+  const colorOfRow = ({ row }) => {
+    if (selections.value.includes(row)) {
+      return 'selected-row';
+    }
+    return '';
+  };
+
+  const clearAll = () => {
+    multipleTableRef.value!.clearSelection();
+  };
+
+  // 改变当前打开详情的表格行的选中状态
+  const updateCurRowChosen = (row, status: boolean) => {
+    multipleTableRef.value!.toggleRowSelection(row, status);
+  };
+
+  defineExpose({ clearAll, updateCurRowChosen });
 
-defineExpose({ clearAll })
+  onBeforeMount(() => {
+    getAIOptions();
+    getManualOptions();
+    getLocationOptions();
+  });
 
-onBeforeMount(() => {
-  getAIOptions();
-  getManualOptions();
-  getLocationOptions();
-});
+  onMounted(() => {
+    window.addEventListener('keydown', (code) => {
+      if (code.shiftKey) {
+        shiftKeyBoard.value = true;
+      }
+    });
+    window.addEventListener('keyup', (code) => {
+      if (!code.shiftKey) {
+        shiftKeyBoard.value = false;
+        startPoint.value = -1;
+        endPoint.value = -1;
+      }
+    });
+  });
 </script>
 
-<style scoped lang="scss">
-.alert-table-box {
-  display: flex;
-  flex-direction: column;
-  height: calc(100vh - 290px);
-}
-
-.detail-text {
-  color: #1890FF;
-  font-weight: 500;
-  cursor: pointer;
-}
-
-:deep(.el-table-fixed-column--right) {
-  .cell {
+<style scoped lang="less">
+  .alert-table-box {
     display: flex;
+    flex-direction: column;
+    height: calc(100vh - 290px);
   }
 
-  img {
-    margin-right: 20px;
+  .detail-text {
+    color: #1890ff;
+    font-weight: 500;
     cursor: pointer;
   }
-}
 
-:deep(.el-table) {
-  ::before {
-    height: 0px;
+  :deep(.el-table-fixed-column--right) {
+    .cell {
+      display: flex;
+    }
+
+    img {
+      margin-right: 20px;
+      cursor: pointer;
+    }
+  }
+
+  :deep(.el-table) {
+    ::before {
+      height: 0px;
+    }
+
+    .selected-row {
+      background: #f3f8ff;
+    }
   }
-}
-</style>
+</style>

+ 151 - 114
src/views/datamanager/alertformdata/components/common/QueryFormSimple.vue

@@ -2,24 +2,51 @@
   <div>
     <el-form :model="queryForm" label-width="auto" :inline="true" ref="formRef">
       <div class="select-group">
-        <el-form-item label="类型:" prop="issueType">
-          <el-select v-model="queryForm.issueType" placeholder="全部" clearable>
-            <el-option v-for="item in props.aiOptions" :label="item.name" :value="item.id" />
-          </el-select>
+        <el-form-item label="类型:" prop="issueTypeList">
+          <el-cascader
+            v-model="issueTypeValue"
+            :options="props.aiOptions"
+            :props="issueMainTypeProp"
+            clearable
+            collapse-tags
+            :show-all-levels="false"
+            @change="handleIssueMainTypeChange"
+          />
         </el-form-item>
         <el-form-item label="地点:" prop="workspaceId">
-          <el-cascader v-model="workLocation" :options="props.locationOptions" :props="location" clearable
-            @change="handleCascaderChange" />
+          <el-cascader
+            v-model="workLocation"
+            :options="props.locationOptions"
+            :props="locationProp"
+            clearable
+            collapse-tags
+            :show-all-levels="false"
+            @change="handleCascaderChange"
+          />
         </el-form-item>
-        <el-form-item label="状态:" prop="issueState">
+        <el-form-item label="处理状态:" prop="issueState">
           <el-select v-model="tempState" clearable @change="handleIssueStateChange">
-            <el-option v-for="item in issueStateOptionsZJC" :key="item.value" :label="item.label" :value="item.value" />
+            <el-option
+              v-for="item in issueStateOptionsZJC"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            />
           </el-select>
         </el-form-item>
         <el-form-item label="日期:">
-          <el-date-picker v-model="dateRange" type="daterange" range-separator="~" start-placeholder="开始时间"
-            end-placeholder="结束时间" clearable unlink-panels value-format="YYYY-MM-DD HH:mm:ss.SSS"
-            :default-time="defaultTime" @change="handleDateChange" />
+          <el-date-picker
+            v-model="dateRange"
+            type="daterange"
+            range-separator="~"
+            start-placeholder="开始时间"
+            end-placeholder="结束时间"
+            clearable
+            unlink-panels
+            value-format="YYYY-MM-DD HH:mm:ss"
+            :default-time="defaultTime"
+            @change="handleDateChange"
+          />
         </el-form-item>
       </div>
       <div class="btn-group">
@@ -33,117 +60,127 @@
 </template>
 
 <script setup lang="ts">
-import type { FormInstance } from 'element-plus';
-import { reactive, ref } from 'vue';
-import { issueStateOptionsZJC } from './constant.question';
-
-interface Props {
-  aiOptions: Array<any>
-  locationOptions: Array<any>
-};
-const props = defineProps<Props>();
-const emits = defineEmits(['onSearch', 'onReset']);
-
-interface QueryModel {
-  pageNumber: number,
-  pageSize: number,
-  source?: number,         // 来源
-  issueType?: number,      // 类型
-  workspaceId?: number[],  // 地点=工位id
-  issueState?: number[],   // 状态
-  startTime?: string,      // 开始时间(默认)
-  endTime?: string,        // 结束时间(默认)
-};
-
-const formRef = ref<FormInstance>();
-const queryForm = reactive<QueryModel>({
-  pageNumber: 1,
-  pageSize: 10,
-});
-
-const location = { multiple: true };  // 级联选择器(打开多选)
-const workLocation = ref([]);   // 级联选择器,为二维数组(提取workspaceId)
-const tempState = ref('');  // 状态,字符串转number[]
-const dateRange = ref([]);  // 时间段,拆分成startTime/endTime
-const defaultTime = ref<[Date, Date]>([
-  new Date(2000, 1, 1, 0, 0, 0),
-  new Date(2000, 2, 1, 23, 59, 59),
-])
-
-const handleSearch = () => {
-  emits('onSearch', queryForm);
-};
-
-const handleReset = () => {
-  workLocation.value = [];
-  tempState.value = '';
-  dateRange.value = [];
-  Reflect.deleteProperty(queryForm, "source");
-  Reflect.deleteProperty(queryForm, "startTime");
-  Reflect.deleteProperty(queryForm, "endTime");
-  formRef.value?.resetFields();
-  emits('onReset', queryForm);
-};
-
-const handleCascaderChange = () => {
-  const arr = [];
-  workLocation.value.forEach((item) => {
-    arr.push(item[1]);
+  import type { FormInstance } from 'element-plus';
+  import { reactive, ref } from 'vue';
+  import { issueStateOptionsZJC } from './constant.question';
+  import { TableQueryForm } from '@/api/datamanagement/alert-default';
+
+  const props = defineProps({
+    aiOptions: Array<any>,
+    locationOptions: Array<any>,
   });
-  queryForm.workspaceId = arr;
-};
-
-const handleIssueStateChange = () => {
-  if (tempState.value === undefined)
-    queryForm.issueState = [];
-  if (tempState.value)
-    queryForm.issueState = JSON.parse(tempState.value);
-};
-
-const handleDateChange = () => {
-  if (dateRange.value != null) {
-    queryForm.startTime = dateRange.value[0];
-    queryForm.endTime = dateRange.value[1];
-  } else {
-    Reflect.deleteProperty(queryForm, "startTime");
-    Reflect.deleteProperty(queryForm, "endTime");
-  }
-};
-</script>
+  const emits = defineEmits(['onSearch', 'onReset']);
 
-<style scoped lang="scss">
-.el-form {
-  display: flex;
-  justify-content: space-between;
-}
+  const formRef = ref<FormInstance>();
+  const queryForm = reactive<TableQueryForm>({
+    pageNumber: 1,
+    pageSize: 10,
+  });
 
-:deep(.el-form-item__label) {
-  padding: 0;
-}
+  const issueTypeValue = ref([]);
+  const issueMainTypeProp = { multiple: true, expandTrigger: 'hover' as const };
+  const workLocation = ref([]); // 级联选择器,为二维数组(提取workspaceId)
+  const locationProp = { multiple: true, expandTrigger: 'hover' as const }; // 级联选择器(打开多选)
+  const tempState = ref(''); // 状态,字符串转number[]
+  const dateRange = ref([]); // 时间段,拆分成startTime/endTime
+  const defaultTime = ref<[Date, Date]>([
+    new Date(2000, 1, 1, 0, 0, 0),
+    new Date(2000, 2, 1, 23, 59, 59),
+  ]);
+
+  const handleSearch = () => {
+    emits('onSearch', queryForm);
+  };
+
+  const handleReset = () => {
+    issueTypeValue.value = [];
+    workLocation.value = [];
+    tempState.value = '';
+    dateRange.value = [];
+    Reflect.deleteProperty(queryForm, 'startTime');
+    Reflect.deleteProperty(queryForm, 'endTime');
+    Reflect.deleteProperty(queryForm, 'issueMainTypeList');
+    Reflect.deleteProperty(queryForm, 'issueTypeList');
+    formRef.value?.resetFields();
+    emits('onReset', queryForm);
+  };
+
+  const handleIssueMainTypeChange = () => {
+    if (issueTypeValue.value.length !== 0) {
+      const arrMain = [];
+      const arrSub = [];
+      issueTypeValue.value.forEach((item) => {
+        arrMain.push(item[0]);
+        arrSub.push(item[1]);
+      });
+      queryForm.issueMainTypeList = [...new Set(arrMain)];
+      queryForm.issueTypeList = arrSub;
+    } else {
+      Reflect.deleteProperty(queryForm, 'issueMainTypeList');
+      Reflect.deleteProperty(queryForm, 'issueTypeList');
+    }
+  };
+
+  const handleCascaderChange = () => {
+    if (workLocation.value.length !== 0) {
+      const arr = [];
+      workLocation.value.forEach((item) => {
+        arr.push(item[1]);
+      });
+      queryForm.workspaceId = arr;
+    } else {
+      Reflect.deleteProperty(queryForm, 'workspaceId');
+    }
+  };
+
+  const handleIssueStateChange = () => {
+    if (tempState.value) queryForm.issueState = JSON.parse(tempState.value);
+    else Reflect.deleteProperty(queryForm, 'issueState');
+  };
+
+  const handleDateChange = () => {
+    if (dateRange.value != null) {
+      queryForm.startTime = dateRange.value[0];
+      queryForm.endTime = dateRange.value[1];
+    } else {
+      Reflect.deleteProperty(queryForm, 'startTime');
+      Reflect.deleteProperty(queryForm, 'endTime');
+    }
+  };
+</script>
 
-.select-group {
-  flex: 1;
-}
+<style scoped lang="less">
+  .el-form {
+    display: flex;
+    justify-content: space-between;
+  }
 
-.btn-group {
+  :deep(.el-form-item__label) {
+    padding: 0;
+  }
 
-  .search-btn {
-    width: 65px;
-    height: 32px;
-    background: #1890FF;
-    border-radius: 2px;
+  .select-group {
+    flex: 1;
   }
 
-  .reset-btn {
-    width: 65px;
-    height: 32px;
-    border-radius: 2px;
-    border: 1px solid #1890FF;
-    color: #1890FF;
+  .btn-group {
+    .search-btn {
+      width: 65px;
+      height: 32px;
+      background: #1890ff;
+      border-radius: 2px;
+    }
+
+    .reset-btn {
+      width: 65px;
+      height: 32px;
+      border-radius: 2px;
+      border: 1px solid #1890ff;
+      color: #1890ff;
+    }
   }
-}
 
-.el-select {
-  --el-select-width: 215px;
-}
+  .el-select {
+    --el-select-width: 215px;
+  }
 </style>

+ 69 - 14
src/views/datamanager/alertformdata/components/default-simple/Default.vue

@@ -3,9 +3,7 @@
     <Prequalification />
     <div class="search-form">
       <QueryFormSimple
-        :is-show-tab="false"
-        :ai-options="aiOptions"
-        :manual-options="manualOptions"
+        :ai-options="aiMainOptions"
         :location-options="locationOptions"
         @on-search="handleSearch"
         @on-reset="handleReset"
@@ -26,6 +24,7 @@
         :on-detail="handleDetail"
         :on-delete="handleDelete"
         @update:selection="handlePop"
+        @update:time-sort="handleChangeTimeSort"
       />
     </div>
     <div class="pagination-box">
@@ -39,10 +38,16 @@
     </div>
     <DetailDialog
       v-if="isDetailDialogShow"
+      :has-been-chosen="detailRowChosen"
       :description="detailDescription"
       :image-paths="detailPictures"
       :video-paths="detailVideos"
+      :has-previous="hasPreviousRow"
+      :has-next="hasNextRow"
       @close="closeDetailDialog"
+      @update:previous="handleChangePrevious"
+      @update:next="handleChangeNext"
+      @update:choose="handleChangeChoose"
     />
   </div>
 </template>
@@ -51,32 +56,46 @@
   import { ref, onMounted, onBeforeMount } from 'vue';
   import { ElMessage, ElMessageBox } from 'element-plus';
   import QueryFormSimple from '../common/QueryFormSimple.vue';
-  import AlertTableSimple from '../common/AlertTableSimple.vue';
+  import AlertTableSimple, { DataSourceItem } from '../common/AlertTableSimple.vue';
   import DetailDialog from '../common/DetailDialog.vue';
   import Pagination from '../common/Pagination.vue';
-  import { useIssueType } from '../../hooks/useIssueType';
+  // import { useIssueType } from '../../hooks/useIssueType';
   import { useWorkLocation } from '../../hooks/useWorkLocation';
+  import { useIssueMainType } from '../../hooks/useIssueMainType';
   import Prequalification from '../common/Prequalification.vue';
-  import { getDefaultTableData, deleteDefaultTableData } from '@/api/datamanagement/alert-default';
+  import {
+    TableQueryForm,
+    getDefaultTableData,
+    deleteDefaultTableData,
+  } from '@/api/datamanagement/alert-default';
 
-  const { aiOptions, manualOptions, getAIOptions, getManualOptions } = useIssueType();
+  // const { aiOptions, manualOptions, getAIOptions, getManualOptions } = useIssueType();
   const { locationOptions, getLocationOptions } = useWorkLocation();
+  const { aiMainOptions, getAIMainOptions } = useIssueMainType();
 
   const alertTableRef = ref<typeof AlertTableSimple>();
-  const tableData = ref([]);
+  const tableData = ref<DataSourceItem[]>([]);
   const showActionBar = ref(false);
   const chooseNum = ref(0);
+  const chooseRow = ref<DataSourceItem[]>([]); // 被选中的数据行
   const chooseId = ref<number[]>([]);
   const isActiveDelete = ref(false);
   // 详情
   const isDetailDialogShow = ref(false);
+  const detailRowChosen = ref(false); // 当前行是否被选中
+  const detailRow = ref(); // 当前行
+  const detailCurRowIndex = ref(0); // 当前行index
+  const detailPreviousRow = ref(); // 上一行
+  const detailNextRow = ref(); // 下一行
+  const hasPreviousRow = ref(false); // 是否有上一行
+  const hasNextRow = ref(false); // 是否有下一行
   const detailDescription = ref('');
   const detailPictures = ref<string[]>([]);
   const detailVideos = ref<string[]>([]);
   // 分页
   const total = ref(0);
 
-  const query = ref({
+  const query = ref<TableQueryForm>({
     pageNumber: 1,
     pageSize: 10,
   });
@@ -91,8 +110,15 @@
     getTableData();
   };
 
+  // 表格排序切换
+  const handleChangeTimeSort = (curTimeSort) => {
+    query.value.order = curTimeSort;
+    getTableData();
+  };
+
   // 多选
   const handlePop = (selection) => {
+    chooseRow.value = selection;
     chooseId.value = [];
     selection.forEach((item) => {
       if (chooseId.value.indexOf(item.id) === -1) chooseId.value.push(item.id);
@@ -107,6 +133,11 @@
     alertTableRef.value?.clearAll();
     showActionBar.value = false;
   };
+  // 改变该行的选中状态
+  const handleChangeChoose = (status) => {
+    alertTableRef.value?.updateCurRowChosen(detailRow.value, !status);
+    updateDetailDialog(detailRow.value);
+  };
 
   // 批量删除
   const handleDeleteAll = () => {
@@ -142,11 +173,36 @@
   const closeDetailDialog = () => {
     isDetailDialogShow.value = false;
   };
+  // 更新detailCurRowIndex、detailPreviousRow、detailNextRow、hasPreviousRow、hasNextRow
+  const updateDetailDialog = (curRow) => {
+    detailDescription.value = curRow.description;
+    detailPictures.value = curRow.pictures;
+    detailVideos.value = curRow.videos;
+    detailCurRowIndex.value = tableData.value.findIndex((item) => item.id === curRow.id);
+    detailPreviousRow.value = tableData.value[detailCurRowIndex.value - 1];
+    detailNextRow.value = tableData.value[detailCurRowIndex.value + 1];
+    if (detailPreviousRow.value) hasPreviousRow.value = true;
+    else hasPreviousRow.value = false;
+    if (detailNextRow.value) hasNextRow.value = true;
+    else hasNextRow.value = false;
+    if (chooseRow.value.findIndex((item) => item.id === curRow.id) !== -1)
+      detailRowChosen.value = true;
+    else detailRowChosen.value = false;
+  };
   const handleDetail = (row) => {
     isDetailDialogShow.value = true;
-    detailDescription.value = row.description;
-    detailPictures.value = row.pictures;
-    detailVideos.value = row.videos;
+    detailRow.value = row;
+    updateDetailDialog(detailRow.value);
+  };
+  // 上一个
+  const handleChangePrevious = () => {
+    detailRow.value = detailPreviousRow.value;
+    updateDetailDialog(detailRow.value);
+  };
+  // 下一个
+  const handleChangeNext = () => {
+    detailRow.value = detailNextRow.value;
+    updateDetailDialog(detailRow.value);
   };
 
   // 删除
@@ -198,8 +254,7 @@
   });
 
   onBeforeMount(() => {
-    getAIOptions();
-    getManualOptions();
+    getAIMainOptions();
     getLocationOptions();
   });
 </script>