cm-wisdom-cube/frontend/src/components/developer/DeveloperList.vue
2025-03-14 16:57:26 +08:00

238 lines
6.3 KiB
Vue

<script setup>
import {NInput, NSpace, NButton, NPagination, NModal, NSelect, NSpin, NPopconfirm, NEmpty, useMessage} from 'naive-ui'
import {onMounted, ref} from "vue";
import DeveloperEdit from "./DeveloperEdit.vue";
import {useRouter} from 'vue-router';
import {request, errorHandler} from '../../utils/request.js'
const message = useMessage()
const router = useRouter();
const isLoadingData = ref(false);
const showDeveloperEditModal = ref(false)
const developerListRef = ref(null)
const filterSectionRef = ref(null);
const paginationRef = ref(null)
const cardContainerRef = ref(null)
const filterName = ref(null)
const page = ref(1)
const pageSize = ref(18)
const developerList = ref([])
const editId = ref(null)
/**
* 计算高度
*/
const calculateCardHeight = () => {
const requirementListHeight = parseInt(developerListRef.value.getBoundingClientRect().height);
const filterSectionHeight = parseInt(filterSectionRef.value.getBoundingClientRect().height);
const paginationHeight = parseInt(paginationRef.value.getBoundingClientRect().height);
cardContainerRef.value.style.maxHeight = `${requirementListHeight - filterSectionHeight - paginationHeight - 55}px`;
}
const listpage = () => {
isLoadingData.value = true;
request.get('/developer/listpage', {
params: {
name: filterName.value,
page: page.value,
page_size: pageSize.value
}
}).then(res => {
developerList.value = res.data.data_list
}).catch(error => {
errorHandler(error, message, router)
}).finally(() => {
isLoadingData.value = false;
})
}
const del = (id) => {
isLoadingData.value = true;
request.delete(`/developer/delete`, {
params: {
ids: id
}
}).then(res => {
message.success('删除成功')
listpage()
}).catch(error => {
errorHandler(error, message, router)
}).finally(() => {
isLoadingData.value = false;
})
}
onMounted(() => {
setTimeout(() => {
calculateCardHeight();
listpage()
}, 500)
})
</script>
<template>
<div class="developer-list" ref="developerListRef">
<n-spin :show="isLoadingData">
<div class="filter-section" ref="filterSectionRef">
<div class="filter-form">
<n-space>
<n-space class="filter-item" align="center">
<label>姓名</label>
<n-input v-model:value="filterName"
:clearable="true"
type="text"
style="width: 120px"
placeholder="输入姓名"/>
</n-space>
</n-space>
</div>
<div class="filter-actions">
<n-space justify="space-between">
<n-button type="primary" @click="() => {
listpage()
}">搜索
</n-button>
<n-button type="info" @click="() => {
editId = null
showDeveloperEditModal = true
}">
<i class="fas fa-plus"></i>
</n-button>
</n-space>
</div>
</div>
<!-- 项目列表 -->
<div class="card-container" ref="cardContainerRef" v-show="developerList.length > 0">
<div class="card-item" v-for="developer in developerList">
<div class="name">{{ developer.name }}</div>
<div class="profile" :title="developer.profile">{{ developer.profile }}</div>
<div class="actions">
<n-space justify="space-between">
<n-space>{{ developer.post }}</n-space>
<n-space justify="end" :size="5">
<i class="fas fa-edit" @click="() => {
editId = developer.id
showDeveloperEditModal = true
}"></i>
<n-popconfirm
@positive-click="() => {
del(developer.id)
}"
positive-text="确定"
negative-text="取消"
>
<template #trigger>
<i class="fas fa-trash"></i>
</template>
确定删除吗?删除后数据无法恢复!
</n-popconfirm>
</n-space>
</n-space>
</div>
</div>
</div>
<!-- 分页 -->
<div class="pagination" ref="paginationRef" v-show="developerList.length > 0">
<n-pagination v-model:page="page"
:page-size="pageSize"
:on-update-page="(currentPage) => {
page = currentPage
listpage()
}"/>
</div>
<div class="empty-container" v-show="developerList.length === 0">
<n-empty description="暂无数据"/>
</div>
</n-spin>
<n-modal v-model:show="showDeveloperEditModal"
preset="card"
:style="{width: '600px'}"
title="需求编辑"
:bordered="false">
<DeveloperEdit :developer-id="editId"
@on-data-edited="() => {
showDeveloperEditModal = false
listpage()
}"/>
</n-modal>
</div>
</template>
<style scoped>
.developer-list {
height: 100%;
}
.filter-section {
display: flex;
padding: 10px;
border-bottom: 1px solid var(--border-color);
margin-bottom: 10px;
.filter-actions {
flex: 1;
margin-left: 10px;
}
}
.card-container {
display: grid;
grid-template-columns: repeat(3, 1fr);
column-gap: 10px;
row-gap: 10px;
overflow-y: scroll;
height: 100%;
.card-item {
border: 1px solid var(--border-color);
padding: 10px;
border-radius: 2px;
height: 140px;
min-width: 0; /** 防止grid子元素扩展 **/
.name {
font-weight: bold;
}
.profile {
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
line-height: 24px;
height: 72px;
word-break: break-all;
}
.actions {
margin-top: 5px;
.fas {
cursor: pointer;
}
.fa-edit:hover {
color: var(--primary-color);
}
.fa-trash:hover {
color: var(--danger-color);
}
}
}
}
.pagination {
border-top: 1px solid var(--border-color);
margin-top: 10px;
padding: 10px;
display: flex;
justify-content: center;
}
</style>