index.vue 7.98 KB
<template>
  <div class="go-items-list">
    <!-- 搜索区域 -->
    <n-form ref="formRef" label-placement="left" label-width="auto" :model="formValue" :size="formSize">
      <n-grid :cols="24" :x-gap="24">
        <n-grid-item :span="6" label="Input" path="name">
          <n-form-item label="名称" path="name">
            <n-input v-model:value="formValue.name" placeholder="输入名称" />
          </n-form-item>
        </n-grid-item>
        <n-grid-item :span="6" label="Select" path="state">
          <n-form-item label="状态" path="state">
            <n-select v-model:value="formValue.state" placeholder="选择状态" :options="statusOptions" />
          </n-form-item>
        </n-grid-item>
        <n-grid-item :span="8">
          <n-button type="primary" @click="handleSearchClick">
            <template #icon>
              <n-icon>
                <SearchIcon />
              </n-icon>
            </template>
            查询
          </n-button>
          <n-button style="margin-left: 20px" @click="handleResetClick">
            <template #icon>
              <n-icon>
                <ReloadSearch />
              </n-icon>
            </template>
            重置
          </n-button>
        </n-grid-item>
      </n-grid>
    </n-form>
    <div v-show="loading">
      <go-loading></go-loading>
    </div>
    <div v-show="!loading">
      <div style="display: flex; flex-direction: row-reverse">
        <n-space>
          <n-button type="primary" @click="handleOpenThreeEditor"> 新增 </n-button>
          <n-button v-if="list.length" @click="handleSelectAll" type="info">
            {{ selectAllTextFlag ? '全选' : '反选' }}
          </n-button>
          <n-dropdown
            v-if="list.length"
            :disabled="isBulkOperationFlag"
            trigger="hover"
            :options="operationOptions"
            @select="handleOperationSelect"
          >
            <n-button :disabled="isBulkOperationFlag"> 批量操作 </n-button>
          </n-dropdown>
        </n-space>
      </div>
      <n-grid style="margin-top: 16px" :x-gap="20" :y-gap="20" cols="2 s:2 m:3 l:4 xl:4 xxl:4" responsive="screen">
        <n-grid-item v-for="(item, index) in list" :key="item.id">
          <div style="display: none">{{ index }}</div>
          <project-items-card
            :cardData="item"
            :operationKey="operationKey"
            @resize="resizeHandle"
            @delete="deleteHandle(item)"
            @release="releaseHandle(item)"
            @edit="editHandle"
            @inputUpdateCard="inputUpdateHandle"
          ></project-items-card>
        </n-grid-item>
      </n-grid>
    </div>
    <div class="list-pagination">
      <n-pagination
        :page="pagination.page"
        :page-size="pagination.pageSize"
        :item-count="pagination.count"
        :page-sizes="[8, 16, 24, 32]"
        @update:page="changePage"
        @update:page-size="changeSize"
        show-size-picker
      >
        <template #prefix> 共 {{ pagination.count }} 条 </template>
      </n-pagination>
    </div>
  </div>
  <project-items-modal-card
    v-if="modalData"
    :modalShow="modalShow"
    :cardData="modalData"
    @close="closeModal"
    @edit="editHandle"
  ></project-items-modal-card>
</template>

<script setup lang="ts">
import { ProjectItemsCard } from '../ProjectItemsCard/index'
import { ProjectItemsModalCard } from '../ProjectItemsModalCard/index'
import { useModalDataInit } from './hooks/useModal.hook'
import { useDataListInit } from './hooks/useData.hook'
import { ref } from 'vue'
import type { FormInst } from 'naive-ui'
import { icon } from '@/plugins'
import { generateUUIDv4 } from '@/utils/utils'
import { threeJsDeleteApi, putReleaseThreeJsModel } from '@/api/external/contentSave/content'
import { ChartType } from '../..'
import { DialogEnum } from '@/enums/pluginEnum'
import { goDialog } from '@/utils'

const { SearchIcon, ReloadSearch } = icon.ionicons5

const { modalData, modalShow, closeModal, resizeHandle, editHandle } = useModalDataInit()

const formRef = ref<FormInst | null>(null)

const formSize = ref('medium')

const formValue = ref({
  name: '',
  state: null
})

const statusOptions = ref([
  {
    label: '已发布',
    value: 'yes'
  },
  {
    label: '未发布',
    value: 'no'
  }
])

const operationKey = ref('')

const operationOptions = [
  {
    label: '批量删除',
    key: 'Bulk delete'
  },
  {
    label: '批量发布',
    key: 'Bulk release'
  },
  {
    label: '批量取消发布',
    key: 'Bulk un release'
  }
]

const resetSelect = (list: ChartType[], flag: boolean) => {
  list.forEach(item => {
    item.checkedValue = flag
  })
}

const releaseGoDialog = (message: string, state: number, messageText: string) => {
  goDialog({
    type: DialogEnum.DELETE,
    promise: true,
    message,
    // eslint-disable-next-line @typescript-eslint/no-empty-function
    onPositiveCallback: () => {},
    promiseResCallback: async () => {
      // eslint-disable-next-line no-case-declarations
      const bulkDeleteIds = list.value
        ?.filter((item: ChartType) => item.checkedValue)
        ?.map((item: ChartType) => item.id)
      await putReleaseThreeJsModel(state, bulkDeleteIds as unknown as string[])
      window['$message'].success(window['$t'](messageText))
      setTimeout(() => {
        handleSearchClick()
      }, 500)
      isBulkOperationFlag.value = true
      selectAllTextFlag.value = true
      operationKey.value = ''
      resetSelect(list.value, false)
    }
  })
}

const handleOperationSelect = async (key: string) => {
  operationKey.value = key
  switch (key) {
    case 'Bulk delete':
      goDialog({
        type: DialogEnum.DELETE,
        promise: true,
        message: '是否批量删除所选数据?',
        // eslint-disable-next-line @typescript-eslint/no-empty-function
        onPositiveCallback: () => {},
        promiseResCallback: async () => {
          // eslint-disable-next-line no-case-declarations
          const bulkDeleteIds = list.value
            ?.filter((item: ChartType) => item.checkedValue)
            ?.map((item: ChartType) => item.id)
          await threeJsDeleteApi([bulkDeleteIds] as unknown as string[])
          window['$message'].success(window['$t']('common.deleteSuccessText'))
          setTimeout(() => {
            handleSearchClick()
          }, 500)
          isBulkOperationFlag.value = true
          selectAllTextFlag.value = true
          operationKey.value = ''
          resetSelect(list.value, false)
        }
      })
      break
    case 'Bulk release':
      releaseGoDialog('是否批量发布所选数据?', 1, 'common.releaseSuccessText')
      break
    case 'Bulk un release':
      releaseGoDialog('是否批量取消发布所选数据?', 0, 'common.cancelReleaseSuccessText')
      break
  }
}

const {
  loading,
  pagination,
  list,
  changeSize,
  changePage,
  deleteHandle,
  releaseHandle,
  inputUpdateHandle,
  handleSearchClick
} = useDataListInit(formValue.value)

const isBulkOperationFlag = ref(true)

const selectAllTextFlag = ref(true)

const handleSelectAll = () => {
  selectAllTextFlag.value = !selectAllTextFlag.value
  if (!selectAllTextFlag.value) {
    resetSelect(list.value, true)
    isBulkOperationFlag.value = false
    operationKey.value = 'Bulk delete'
  } else {
    resetSelect(list.value, false)
    isBulkOperationFlag.value = true
    operationKey.value = ''
  }
}

const handleResetClick = () => {
  formValue.value.name = ''
  formValue.value.state = null
  handleSearchClick()
}

const handleOpenThreeEditor = () => {
  const { host, protocol, pathname } = location
  const randomId = generateUUIDv4()
  window.open(`${protocol}//${host}${pathname}editor/?three_file_uuid=${randomId}&action_type=create`)
}
</script>

<style lang="scss" scoped>
$contentHeight: 250px;
@include go('items-list') {
  display: flex;
  flex-direction: column;
  min-height: calc(100vh - #{$--header-height} * 2 - 2px);
  .list-content {
    position: relative;
    height: $contentHeight;
  }
  .list-pagination {
    position: fixed;
    bottom: 10px;
    right: 30px;
  }
}
</style>