| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357 |
- <template>
- <div class="main-wrap flex flex-col gap-y-2 p-4">
- <NCard>
- <div class="mb-2 flex gap-x-4">
- <NForm ref="formRef" :model="form" inline label-placement="left">
- <NFormItem label="站点" path="sn">
- <NInput v-model:value="form.sn" style="width: 250px" clearable />
- </NFormItem>
- <NFormItem label="进度" path="progress">
- <NSelect v-model:value="form.progress" :options="progressOptions" style="width: 120px" clearable />
- </NFormItem>
- </NForm>
- <div class="flex gap-2">
- <NButton type="success" @click="createBatchDownload">
- <template #icon>
- <span class="i-ph:plus-circle" />
- </template>
- 创建任务
- </NButton>
- <NButton type="info" @click="handleQueryClick" :loading="isRequestLoading" :disabled="isRequestLoading">
- <template #icon>
- <span class="i-ph:magnifying-glass" />
- </template>
- 查询
- </NButton>
- <NButton type="warning" @click="resetForm">
- <template #icon>
- <span class="i-ph:arrow-clockwise" />
- </template>
- 重置
- </NButton>
- </div>
- </div>
- <div>
- <NDataTable ref="dataTableRef" v-model:checked-row-keys="checkedRowKeys" :remote="true" :min-height="166.6"
- :max-height="maxHeight" size="small" :columns="tableColumns" :data="tableData" :row-key="tableRowKey"
- :loading="isRequestLoading" striped :single-line="false" :row-props="rowProps" />
- <div class="mt-3 flex items-end justify-between">
- <div class="flex items-center gap-x-3">
- <span>已选择 {{ checkedRowKeys.length }} 条</span>
- <NButtonGroup size="small" :ghost="true">
- <NButton :disabled="isSelectMultiple" @click="handleDownloadClick" secondary type="info">
- 下载
- </NButton>
- <NButton :disabled="isSelectMultiple" @click="handleDeleteClick" secondary type="info">
- 删除
- </NButton>
- </NButtonGroup>
- </div>
- <NPagination v-bind="tablePagination" :prefix="paginationPrefix" />
- </div>
- </div>
- </NCard>
- <NDropdown placement="bottom-start" trigger="manual" v-bind="dropdownOptions" :show="showDropdown" />
- </div>
- </template>
- <script setup lang="tsx">
- import { useRouter } from 'vue-router'
- import { NButton, NDataTable, NForm, NNumberAnimation, NInput, NEllipsis } from 'naive-ui'
- import type { DataTableColumns, PaginationProps, DropdownProps } from 'naive-ui'
- import { useDataTable } from '@/composable/comp/useDataTable'
- import { useResettableReactive } from '@/composable/useResettable'
- import { getBatchDownloadList, createBatchDownload as createBatchDownloadTask } from '@/service/batchDownload'
- import type { BatchDownloadFilter, BatchDownloadInfo, BatchDownloadConfig } from '@/service/batchDownload/interface'
- import ModalData from './ModalData.vue'
- defineOptions({
- name: 'BatchDownload',
- })
- const router = useRouter()
- const message = useMessage()
- const modal = useModal()
- const dialog = useDialog()
- const formRef = useTemplateRef<InstanceType<typeof NForm>>('formRef')
- const dataTableRef = useTemplateRef<InstanceType<typeof NDataTable>>('dataTableRef')
- const { maxHeight } = useDataTable(dataTableRef)
- const isRequestLoading = ref(false)
- const showDropdown = ref(false)
- const checkedRowKeys = ref<Array<number | string>>([])
- const contextmenu = ref<BatchDownloadInfo | undefined>(undefined)
- const isSelectMultiple = ref(false)
- type FilterForm = BatchDownloadFilter
- const [form, , resetForm] = useResettableReactive<FilterForm>({
- sn: undefined,
- })
- const progressOptions = [
- { label: 'pending', value: 'pending' },
- { label: 'running', value: 'running' },
- { label: 'error', value: 'error' },
- { label: 'failed', value: 'failed' }
- { label: 'complete', value: 'complete' },
- ]
- const handleQueryClick = () => {
- // 请求查询数据
- handleListQuery()
- }
- const prevUserListTotal = ref(0)
- const paginationPrefix: PaginationProps['prefix'] = (info) => {
- const { itemCount } = info
- return (
- itemCount && (
- <div>
- <span>总 & nbsp; </span>
- < NNumberAnimation
- from={prevUserListTotal.value}
- to={itemCount}
- onFinish={() => {
- prevUserListTotal.value = itemCount
- }}
- />
- <span> & nbsp; 条 </span>
- </div>
- )
- )
- }
- const dropdownOptions = reactive<DropdownProps>({
- x: 0,
- y: 0,
- options: [
- {
- label: () => <span class='text-green-500'> 下载 </span>,
- key: 'download',
- disabled: true,
- },
- {
- label: () => <span class='text-red-500'> 删除 </span>,
- key: 'delete',
- disabled: true,
- },
- ],
- onClickoutside: () => {
- showDropdown.value = false
- },
- onSelect: (key: string) => {
- showDropdown.value = false
- if (contextmenu.value === undefined) return
- if (key === 'download') {
- itemDownload(contextmenu.value.id)
- } else if (key === 'delete') {
- itemDelete(contextmenu.value.id)
- }
- },
- })
- function createBatchDownload() {
- const title = '新增数据批量下载'
- const handleSubmitClick = async (data: BatchDownloadConfig) => {
- let promise: Promise<void> | undefined
- promise = createBatchDownloadTask(data)
- const result = await promise?.then(async () => {
- handleListQuery()
- message.success('创建成功')
- return true
- }).catch((err) => {
- message.error(`请求失败。\n${err}`)
- return false
- })
- if (!result) return
- m.destroy()
- }
- function handleCancelClick() {
- m.destroy()
- }
- const m = modal.create({
- title,
- preset: 'card',
- draggable: true,
- style: {
- width: '500px',
- },
- content: () => (
- <ModalData
- onSubmit={handleSubmitClick}
- onCancel={handleCancelClick}
- />
- ),
- })
- }
- const tableRowKey = (rowData: BatchDownloadInfo) => {
- return rowData.id
- }
- function createColumns(): DataTableColumns<BatchDownloadInfo> {
- return [
- {
- type: 'selection',
- fixed: 'left'
- },
- {
- title: 'SN',
- key: 'sn',
- width: 200,
- fixed: 'left',
- render(rowData, rowIndex) {
- return h(NEllipsis, {
- lineClamp: 3,
- tooltip: {
- placement: "right-start", // ⬅️ Tooltip 显示在右侧
- style: {
- maxHeight: "200px", // ⬅️ 多行时滚动
- overflowY: "auto",
- whiteSpace: "pre-line" // ⬅️ \n 正常换行
- }
- }
- },
- {
- default: () =>
- h("span", { style: { whiteSpace: "pre-line" } }, rowData.sn.join("\n"))
- })
- },
- },
- {
- title: '时间范围',
- key: 'timeRange',
- width: 100,
- },
- {
- title: '进度',
- key: 'progress',
- },
- {
- title: '任务结果',
- key: 'result'
- },
- {
- title: '操作',
- key: 'operate',
- width: 200,
- fixed: 'right',
- render(row) {
- return h('div', { class: 'flex justify-center gap-4 p-x-4' }, [
- h(NButton, {
- type: "success",
- strong: true,
- size: 'small',
- disabled: row.progress === "pending" || row.progress === "running",
- onClick: () => itemDownload(row.id)
- }, {
- default: () => '下载'
- }),
- h(NButton, {
- type: "error",
- strong: true,
- size: 'small',
- disabled: row.progress === "pending" || row.progress === "running",
- onClick: () => itemDelete(row.id)
- }, {
- default: () => '删除'
- })
- ])
- }
- }
- ]
- }
- // 表格右键菜单
- function rowProps(row: BatchDownloadInfo) {
- return {
- onContextmenu: (e: MouseEvent) => {
- e.preventDefault()
- showDropdown.value = false
- nextTick().then(() => {
- contextmenu.value = row
- showDropdown.value = true
- dropdownOptions.x = e.clientX
- dropdownOptions.y = e.clientY
- })
- },
- }
- }
- const tableData = ref<BatchDownloadInfo[]>([])
- const tableColumns = createColumns()
- const tablePagination = reactive<PaginationProps>({
- page: 1,
- pageSize: 10,
- showSizePicker: true,
- pageSizes: [10, 20, 50, 100],
- itemCount: 0,
- showQuickJumper: true,
- showQuickJumpDropdown: true,
- onUpdatePage: (page: number) => {
- tablePagination.page = page
- handleListQuery()
- },
- onUpdatePageSize: (pageSize: number) => {
- tablePagination.pageSize = pageSize
- tablePagination.page = 1
- handleListQuery()
- },
- })
- const itemDownload = (id: string) => {
- // TODO
- }
- const itemDelete = (id: string) => {
- // TODO
- }
- // 批量下载
- const handleDownloadClick = () => {
- }
- // 批量删除
- const handleDeleteClick = () => {
- }
- const queryBatchDownloadList = async (pageSize: number, pageNum: number, filter?: BatchDownloadFilter) => {
- const responseList = await getBatchDownloadList(pageSize, pageNum, filter)
- if (responseList.data != null) {
- tableData.value = responseList.data
- } else {
- tableData.value = []
- }
- tablePagination.itemCount = responseList.total
- }
- const handleListQuery = async () => {
- const pageSize = tablePagination.pageSize ?? 10
- const page = tablePagination.page ?? 1
- // 处理过滤条件
- const filter: FilterForm = {
- sn: form.sn,
- progress: form.progress,
- }
- await queryBatchDownloadList(pageSize, page, filter)
- }
- onMounted(async () => {
- // 请求查询数据
- await handleListQuery()
- })
- </script>
|