多维表格
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

136 lines
4.4 KiB

<script lang="ts" setup>
import { Modal } from 'ant-design-vue'
import type { ProjectType } from 'nocodb-sdk'
import { useToast } from 'vue-toastification'
import { computed, onMounted } from '#imports'
import { extractSdkResponseErrorMsg } from '~/utils/errorUtils'
import MdiDeleteOutline from '~icons/mdi/delete-outline'
import MdiEditOutline from '~icons/mdi/edit-outline'
import MdiRefresh from '~icons/mdi/refresh'
import MdiMenuDown from '~icons/mdi/menu-down'
import MdiPlus from '~icons/mdi/plus'
import MdiDatabaseOutline from '~icons/mdi/database-outline'
const { $api } = useNuxtApp()
const toast = useToast()
const filterQuery = ref('')
const loading = ref(true)
const projects = ref()
const loadProjects = async () => {
loading.value = true
const response = await $api.project.list({})
projects.value = response.list
loading.value = false
}
const filteredProjects = computed(() => {
return projects.value.filter(
(project) => !filterQuery.value || project.title?.toLowerCase?.().includes(filterQuery.value.toLowerCase()),
)
})
const deleteProject = (project: ProjectType) => {
Modal.confirm({
title: 'Do you want to delete the project?',
content: 'Some descriptions',
okText: 'Yes',
okType: 'danger',
cancelText: 'No',
async onOk() {
try {
await $api.project.delete(project.id as string)
projects.splice(projects.indexOf(project), 1)
} catch (e) {
toast.error(await extractSdkResponseErrorMsg(e))
}
},
})
}
onMounted(() => {
loadProjects()
})
</script>
<template>
<NuxtLayout>
<a-card class="mx-auto mt-5 !max-w-[600px] shadow-lg">
<h1 class="text-center text-4xl pa-2 nc-project-page-title flex align-center justify-center gap-2">
<!-- My Projects -->
<b>{{ $t('title.myProject') }}</b>
<MdiRefresh class="text-sm text-gray-500 hover:text-primary mt-1 cursor-pointer" @click="loadProjects"></MdiRefresh>
</h1>
<div class="flex mb-6">
<a-input-search
v-model:value="filterQuery"
class="max-w-[200px] nc-project-page-search"
:placeholder="$t('activity.searchProject')"
></a-input-search>
<div class="flex-grow"></div>
<a-dropdown @click.stop>
<a-button
>
<div class="flex align-center" >{{ $t('title.newProj') }}
<MdiMenuDown class="menu-icon" />
</div>
</a-button>
<template #overlay>
<a-menu>
<div
class="grid grid-cols-12 cursor-pointer hover:bg-gray-200 flex items-center p-2"
@click="navigateTo('/project/create')"
>
<MdiPlus class="col-span-2 mr-1 mt-[1px] text-primary text-lg" />
<div class="col-span-10 text-sm xl:text-md">{{ $t('activity.createProject') }}</div>
</div>
<div
class="grid grid-cols-12 cursor-pointer hover:bg-gray-200 flex items-center p-2"
@click="navigateTo('/project/create-external')"
>
<MdiDatabaseOutline class="col-span-2 mr-1 mt-[1px] text-green-500 text-lg" />
<div class="col-span-10 text-sm xl:text-md" v-html="$t('activity.createProjectExtended.extDB')" />
</div>
</a-menu>
</template>
</a-dropdown>
</div>
<div v-if="loading">
<a-skeleton />
</div>
<a-table v-else :data-source="filteredProjects" :pagination="{ position: ['bottomCenter'] }">
<a-table-column key="title" title="Title" data-index="title">
<template #default="{ text }">
<div class="capitalize !w-[400px] overflow-hidden overflow-ellipsis whitespace-nowrap" :title="text">{{ text }}</div>
</template>
</a-table-column>
<a-table-column key="id" title="Actions" data-index="id">
<template #default="{ text }">
<div class="flex align-center">
<MdiEditOutline class="nc-action-btn" @click.stop="navigateTo(`/project/${text}`)" />
<MdiDeleteOutline class="nc-action-btn" @click.stop="deleteProject(text)" />
</div>
</template>
</a-table-column>
</a-table>
</a-card>
</NuxtLayout>
</template>
<style scoped>
.nc-action-btn {
@apply text-gray-500 hover:text-primary mr-2 cursor-pointer p-2 w-[30px] h-[30px] hover:bg-gray-300/50 rounded-full;
}
:deep(.ant-table-cell) {
@apply py-1;
}
</style>