Files
Situation-Awareness-Platfor…/src/views/User/index.vue

277 lines
7.7 KiB
Vue
Raw Normal View History

2025-03-12 18:41:20 +08:00
<template>
<div class="page-user">
<d-skeleton :loading="loadingStatus.bgImageLoading" :rows="4">
<header class="page-user-header">
<img v-if="banner" class="page-user-banner" :src="banner || defaultBanner" />
<img v-else class="page-user-banner" src="@/assets/imgs/user-banner.png" />
<!--上传banner-->
<div class="page-user-header-actions" v-if="isSelf && false">
<d-upload class="page-user-header-button" accept=".png,.jpg,.gif,.jpeg" :before-upload="beforeUpload"
@file-select="onBannerUpload">
<Icon class="page-user-header-button-icon" name="gt-upload-cover" size="16px" color="#7E7E80" />
</d-upload>
</div>
<!--选择banner-->
<div class="page-user-header-actions" v-if="isSelf">
<div class="page-user-header-button">
<banner-choose @update="onChooseBanner" />
</div>
</div>
</header>
</d-skeleton>
<section class="page-user-wrapper">
<div class="page-user-info">
<user-info @update-banner="onUpdateBanner" @update-info="onUpdateInfo" />
<my-organs class="page-user-organizations" />
</div>
<div class="page-user-content">
<div class="page-user-intro mt-24 mb-24">
<div class="page-user-intro-md">
<md-intro />
</div>
</div>
<div class="page-user-repos">
<panel :blank="false" class="overflow-hidden">
<template #header>
<div class="page-user-repos-header">
<Icon name="gt-folder-c" size="16px" />
<span class="page-user-repos-title">精选项目</span>
</div>
</template>
<template #headerRight>
<repo-select-modal v-if="isSelf" @update="onUpdate" />
</template>
<DataPanel :empty="!repoList?.length" :loading="repoList?.length ? false : loading" skeleton>
<div class="page-user-repos-content" v-loading="loading">
<template v-for="(item, index) in repoList.slice(0, 6)" :key="item.id">
<repo-item class="page-user-repos-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" :topicNames="item.topicNames"
:class="{ 'is-last': index === repoList.length - 1 }" @handle-star="({isStar}) => item.isStar = isStar" />
</template>
</div>
</DataPanel>
</panel>
</div>
<div class="page-user-activities">
<activity-contributes />
</div>
</div>
</section>
</div>
</template>
<script lang="ts">
export default {
name: 'User'
};
</script>
<script lang="ts" setup>
import { ref, watch, reactive } from 'vue';
import UserInfo from '@/views/User/components/UserInfo.vue';
import MyOrgans from '@/views/User/components/my-organs.vue';
import MdIntro from '@/views/User/components/md-intro.vue';
import ActivityContributes from '@/views/User/components/activity-contributes.vue';
import Panel from '@/components/Panel/index.vue';
import RepoItem from '@/components/RepoItem/index.vue';
import RepoSelectModal from '@/views/User/components/repo-select-modal.vue';
import BannerChoose from '@/views/User/components/banner-choose.vue';
import { useUserInfo } from '@/views/User/hooks/useUserInfo';
import { useRepoList } from '@/views/User/hooks/useRepoList';
import { Message } from 'vue-devui/message';
import { uploadFile, updateUserProfile } from '@/api/user';
import { useRoute, useRouter } from 'vue-router';
import { otherAccountStore } from '@/stores/user';
import { usePageTitle } from '@/utils/hooks/useTitle';
const router = useRouter();
const route = useRoute();
// 精选项目
const { namespace, isSelf } = useUserInfo();
const { repoList, loading, init } = useRepoList({
profile: { params: { username: namespace }},
auto: true
});
const banner = ref('');
const defaultBanner = ref('https://cdn-img.gitcode.com/user-profile/skin-wave.jpg');
const loadingStatus = reactive({
// 加载状态
profileLoading: true,
bgImageLoading: true,
eventsLoading: true,
contributorLoading: true,
releasesLoading: true
});
const onUpdateBanner = (img: string) => {
banner.value = img;
loadingStatus.profileLoading = false;
loadingStatus.bgImageLoading = false;
};
const beforeUpload = (file: any) => {
return false;
};
const infoData = ref<any>(null);
const onUpdateInfo = (data: any) => {
infoData.value = data;
};
const onBannerUpload = async(fileInfo: any) => {
if (fileInfo.length > 0 && fileInfo[0].size > 500 * 1024) {
return Message({
type: 'warning',
message: '图片大小不超过500kb!'
});
}
const resImg: any = await uploadFile(fileInfo, false, fileInfo[0].type);
if (!resImg || resImg.includes('Error')) return false;
if (!infoData.value || !infoData.value.profile) return false;
banner.value = resImg + '?time' + new Date().getTime();
infoData.value.profile.bg_image = resImg;
updateUserProfile(infoData.value);
};
const onChooseBanner = (item: { img: string; title: string }) => {
const resImg = item.img;
banner.value = resImg + '?time' + new Date().getTime();
infoData.value.profile.bg_image = resImg;
updateUserProfile(infoData.value);
};
const onUpdate = () => {
init();
};
watch(
() => route,
(val) => {
if (val.params.namespace !== namespace) {
// 如果从其他用户切换过来导致路由不刷新强制刷新页面
router.go(0);
}
},
{
deep: true
}
);
const user = otherAccountStore();
const userPathInfo = user.accountInfo;
watch(() => userPathInfo, () => {
usePageTitle(userPathInfo.name ? `${userPathInfo.name}(@${userPathInfo.username})` : '个人主页');
}, { deep: true, immediate: true });
</script>
<style scoped lang="scss">
$g-page-user-border-color: #808080;
$g-page-user-border-color-second: #e6e6e8;
$g-page-user-border-radius: 4px;
$g-page-user-border-radius-large: 12px;
$g-page-user-bg-color: #d3d3d3;
$g-page-user-color: #000000;
$g-page-user-color-second: #2d2d2e;
$g-page-user-color-third: #7e7e80;
.page-user {
position: relative;
max-width: 1376px;
margin: 0 auto;
padding-top: 24px;
&-header {
position: relative;
&-button {
position: absolute;
bottom: 10px;
right: 10px;
line-height: 1;
&-icon {
color: $g-page-user-color;
cursor: pointer;
line-height: 1;
}
:deep(.button-content) {
line-height: 1;
}
&:hover {
opacity: 0.9;
}
}
}
&-banner {
object-fit: cover;
width: 100%;
height: 110px;
display: block;
border-top-left-radius: $g-page-user-border-radius-large;
border-top-right-radius: $g-page-user-border-radius-large;
}
&-wrapper {
display: flex;
position: relative;
z-index: 1;
}
&-info {
margin-top: -30px;
}
&-content {
position: relative;
flex: 1;
// overflow: hidden;
// padding-top: 24px;
padding-left: 32px;
}
&-repos {
&-header {
display: flex;
align-items: center;
}
&-title {
font-size: 14px;
font-weight: 500;
color: $g-page-user-color-second;
margin-left: 20px;
}
&-content {
.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;
}
}
&-item {
:deep(.repo-title):hover {
color: $devui-link;
}
}
}
&-activities {
margin-top: 24px;
}
}
</style>