Files
Situation-Awareness-Platfor…/src/views/User/components/stars-repos.vue

266 lines
6.7 KiB
Vue
Raw Normal View History

2025-03-12 18:41:20 +08:00
<template>
<custom-header v-if="false" class="stars-repos-left-header" title="Starred 项目" :count="starredTotal"></custom-header>
<DataPanel :empty="!starredRepoList?.length" skeleton :loading="starredRepoList?.length ? false : loading">
<div v-loading="loading" :view="{ top: '300px', left: '50%' }" class="stars-repos-content" v-if="starredRepoList?.length">
<template v-for="(item, index) in starredRepoList" :key="item.id">
<repo-item
:iconHandleList="item.iconHandleList"
:id="item.id"
:imgSrc="item.imgSrc"
:title="item.title"
:tag-list="item.tagList"
:desc="item.desc"
:isStar="item.isStar"
:web_url="item.web_url"
:hide-star="!isSelf"
:topic-names="item.topicNames"
:class="{ 'is-last': index === starredRepoList.length - 1 }"
@handle-star="({isStar}) => item.isStar = isStar"
/>
</template>
</div>
</DataPanel>
<teleport v-if="tel" :to="tel">
<div class="stars-repos-filters">
<div class="stars-repos-filter-item filter-item-input">
<d-input
v-model="search"
clearable
placeholder="搜索项目"
class="stars-repos-filter-form-item"
style="width: 100%"
maxlength="100"
@change="onSearch" @clear="onSearch">
<template #prefix>
<Icon name="gt-search" color="#B3B4B5" style="font-size: inherit;" />
</template>
</d-input>
</div>
<div class="stars-repos-filter-item filter-item-selects">
<div class="stars-repos-filter-item">
<d-select
class="stars-repos-filter-select"
v-model="filter.type"
:options="types"
allow-clear
placeholder="类型"
>
</d-select>
</div>
<div class="stars-repos-filter-item">
<d-select
class="stars-repos-filter-select"
v-model="filter.lang"
:options="langList"
allow-clear
placeholder="语言"
>
</d-select>
</div>
<div class="stars-repos-filter-item is-last">
<d-select
class="stars-repos-filter-select last-select"
style="max-width: 120px;"
v-model="filter.sort"
:options="sorts"
allow-clear
placeholder="排序"
>
</d-select>
</div>
</div>
</div>
</teleport>
<div v-show="pager.total > pager.pageSize" class="stars-repos-pagination">
<d-pagination
:total="pager.total"
v-model:pageSize="pager.pageSize"
v-model:pageIndex="pager.pageIndex"
:can-view-total="true"
:can-change-page-size="true"
:max-items="5"
/>
</div>
</template>
<script lang="ts">
export default {
name: 'stars-repos'
};
</script>
<script setup lang="ts">
import { ref, watch } from 'vue';
import RepoItem from '@/components/RepoItem/index.vue';
import { useRepoList } from '@/views/User/hooks/useRepoList';
import { useUserInfo } from '@/views/User/hooks/useUserInfo';
import { REPO_TYPES, SORT_TYPES } from '@/views/User/constant/const';
import CustomHeader from '@/components/CustomHeader/index.vue';
import { useUserLang } from '@/views/User/hooks/useUserLang';
withDefaults(defineProps<{
tel: any;
}>(), {
tel: 'body'
});
const filter = ref({
type: null,
lang: null,
sort: null
});
const types = ref(REPO_TYPES);
const sorts = ref(SORT_TYPES);
const pager = ref({
total: 0,
pageSize: 10,
pageIndex: 1
});
const { isSelf, namespace } = useUserInfo();
const { langList } = useUserLang('starred');
const search = ref('');
const getQueryParams = () => {
return {
starred: {
params: {
user_name: namespace,
page: pager.value.pageIndex,
per_page: pager.value.pageSize,
order_by: filter.value?.sort?.split(':')[0] || '',
sort: filter.value?.sort?.split(':')[1] || '',
search: search.value || null,
visibility: isSelf ? filter.value.type : 'public',
with_programming_language: filter.value.lang || null
}
},
auto: true
};
};
const { starredRepoList, starredTotal, loading, toggleRepoStar, init } = useRepoList(getQueryParams(), getQueryParams);
watch(() => starredTotal.value, (val) => {
pager.value.total = val || 0;
});
watch(() => pager.value.pageIndex, () => {
init(getQueryParams());
}, { deep: true, flush: 'post' });
watch(() => pager.value.pageSize, (val) => {
if (val > 1) {
pager.value.pageIndex = 1;
} else {
init(getQueryParams());
}
}, { deep: true, flush: 'post' });
watch(() => filter.value, () => {
init(getQueryParams());
}, { deep: true, flush: 'post' });
const onSearch = () => {
init(getQueryParams());
};
</script>
<style scoped lang="scss">
$stars-repos-border-color: #808080;
$stars-repos-border-color-second: #E6E7E8;
$stars-repos-border-radius: 4px;
$stars-repos-stars-color: #000000;
.stars-repos {
&-left-header {
display: flex;
align-items: center;
margin-bottom: 24px;
&-title {
display: flex;
align-items: center;
font-size: 20px;
color: $stars-repos-stars-color;
font-weight: 500;
margin-right: 8px;
}
}
&-content {
overflow: hidden;
.is-last {
:deep(.g-repo-item) {
border-bottom: none;
}
}
:deep(.g-repo-item) {
border-top: none;
border-left: none;
border-right: none;
border-radius: 0;
box-shadow: none;
}
}
&-pagination {
padding-top: 20px;
padding-bottom: 20px;
display: flex;
justify-content: center;
}
&-filters {
display: flex;
align-items: center;
flex: 1;
}
&-filter-form-item {
:deep(.devui-input__wrapper) {
border-color: $stars-repos-border-color-second;
}
}
&-filter-item {
margin-right: 0;
&.filter-item-input {
margin-right: 8px;
flex: 1;
overflow: hidden;
}
&.filter-item-selects {
display: flex;
align-items: center;
border: 1px solid $stars-repos-border-color-second;
border-radius: $stars-repos-border-radius;
overflow: hidden;
}
}
&-filter-select {
max-width: 100px;
position: relative;
&::after {
content: '';
height: 14px;
width: 1px;
background-color: $stars-repos-border-color-second;
display: block;
position: absolute;
top: 50%;
right: 0;
z-index: 20;
transform: translateY(-50%);
}
&.last-select {
&::after {
display: none;
}
}
:deep(.devui-select__selection) {
border: none;
border-radius: 0;
}
:deep(.devui-select__input) {
padding-left: 16px;
}
}
}
</style>