Files
Situation-Awareness-Platfor…/src/components/Repo/RepoHeaderInfo/index.vue
2025-03-12 18:41:20 +08:00

243 lines
7.7 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="repo-info">
<d-row :gutter="64">
<d-col flex="1" class="min-w-0">
<div class="flex items-end flex-wrap gap-x-4 gap-y-1">
<div class="text-[20px]">
<span v-for="(path, index) in breadcrumb" :key="index">
<GLink :href="path.href" >
<span class="font-color-t1 font-semibold" :class="!index ? 'max-w-[200px] whitespace-nowrap table-cell overflow-ellipsis overflow-hidden' : 'break-all'">{{ path.label }}</span>
</GLink>
<span v-if="index !== breadcrumb.length - 1" class="breadcrumb-splitter font-color-t1"> / </span>
</span>
</div>
<template v-for="(item, index) in topicData.officialTopicList" :key="index">
<div class="official-topic mb-0.5">
<GIcon name="gt-plane-officialCertification" />
<span class="ml-1">{{ item.name }}</span>
</div>
</template>
<div v-if="repoInfo.visibility === 'private'" class="repo-visible font-color-t2 inline-flex items-center justify-center text-xs">
私有
</div>
</div>
<div class="mt-4 flex items-center flex-wrap gap-x-4 gap-y-1" v-if="repoInfo?.forked_from_project">
<span class="font-color-t2 cursor-pointer" :class="{'cursor-pointer': repoInfo.value?.forked_from_project?.web_url}" @click="toForkRepo">
fork {{ repoInfo?.forked_from_project?.name_with_namespace }}
</span>
<div v-if="isAdminOperate" class="fork-btn" @click="handleSync()">
<GIcon name="gt-plane-synchronous" class="mr-1" />
同步源项目
<GIcon size="14" name="gt-line-right" class="ml-1" />
</div>
</div>
<template v-if="isPhone">
<RepoData class="mt-4" :widthType="widthType" @update-star="handleUpdateStarNumber" />
<RepoTopic :tagList="tagList" />
<RepoAction class="mt-3" />
<!-- 只在项目首页展示 -->
<DownloadChart v-if="route?.name === 'repoDashboard'" :repoId="repoId" class="mt-8" />
</template>
<template v-else>
<RepoTopic :tagList="tagList" />
</template>
</d-col>
<d-col v-if="!isPhone">
<RepoData :widthType="widthType" @update-star="handleUpdateStarNumber" />
</d-col>
</d-row>
<d-row align="middle" class="mt-32">
<d-col flex="1">
<NewNavTabs />
</d-col>
<d-col v-if="!isPhone">
<RepoAction />
</d-col>
</d-row>
<SyncFork ref="syncFork" :repoId="repoId" :repoInfo="repoInfo" />
</div>
</template>
<script lang="ts" setup>
import { ref, onUnmounted, watch, computed } from 'vue';
import RepoData from './RepoData.vue';
import RepoAction from './RepoAction.vue';
import DownloadChart from '@/components/Repo/DownloadChart.vue';
import NewNavTabs from '@/components/NavTabs/NewNavTabs.vue';
import RepoTopic from './RepoTopic.vue';
import SyncFork from './SyncFork.vue';
import { addEventListener, offEvent } from '@/utils/eventBus';
import { reqCatch } from '@/utils/catch';
import { storeToRefs } from 'pinia';
import { useRouter, useRoute } from 'vue-router';
import * as types from '@/api/org/types';
import { getCommunityInfo } from '@/api/org/index';
import { getOrgInfo } from '@/views/Org/hooks/orgInfo';
import { orgInfoStore } from '@/stores/Org/index';
import { useRepoHeaderInit } from '@/utils/hooks/useRepoHeaderInit';
import { useRepoId } from '@/utils/hooks/useRepoId';
import { useAccountStore } from '@/stores/user';
import { getSettingsValues } from '@/api/repo';
import { repoInfoStore } from '@/stores/Repo';
import { useOrgId } from '@/utils/hooks/useOrgId';
import setting from '@/setting';
const props = withDefaults(
defineProps<{
widthType: string;
}>(),
{
widthType: 'md'
}
);
const { isLogin } = useAccountStore();
const { repoId } = useRepoId();
const { orgId } = useOrgId('/');
const route = useRoute();
const { access_level, repoInfo, isAdminOperate } = storeToRefs(repoInfoStore()); // pinia直接解构会失去响应式
const { setRepoInfo } = repoInfoStore();
// 获取组织namespace
const { namespace } = getOrgInfo();
const { initRepoDashboard, validLinks, topicData } = useRepoHeaderInit(isLogin);
initRepoDashboard();
const tagList = ref(validLinks.value);
const isPhone = computed(() => ['lg', 'sm'].includes(props.widthType));
const visiMap = new Map([
['public', '公开'],
['private', '私有'],
['internal', '内部']
]);
const toForkRepo = () => {
if (repoInfo.value?.forked_from_project?.web_url) {
location.href = repoInfo.value?.forked_from_project?.web_url;
}
};
const router = useRouter();
const breadcrumb = computed(() => {
const pathStrList = repoInfo.value.name_with_namespace?.split('/');
const pathList = pathStrList.map((item) => ({
label: item
}));
// 第一个路由带链接
if (pathList.length === 2) {
pathList[0].href = router.resolve({
name: 'homepage',
params: { namespace: orgId.value }
}).path;
pathList[1].href = router.resolve({
name: 'repoDashboard'
}).path;
}
return pathList;
});
// 获取仓库
const orgStore = orgInfoStore();
// 社区基本信息
const getCommunityInfoFun = async() => {
const params: types.commonGroupReqType = {
orgId: namespace.value
};
const { data, error } = await reqCatch(getCommunityInfo, params);
if (!error && data) {
orgStore.setCommunityUrl({
communityUrl: `https://${data.data.custom_domain}`,
communityactivityUrl: `https://${data.data.custom_domain}/activelist`
});
orgStore.setCommunityInfo(data.data);
}
};
async function getModuleState() {
const res = await getSettingsValues({
repoId: repoId.value,
group_id: namespace.value
});
if (res.data) {
const { modules } = res.data.data;
modules.forEach(({ key, value }) => {
if (key === 'COMMUNITY' && value === '1') {
getCommunityInfoFun();
}
});
}
}
const handleUpdateStarNumber = (params:Record<string, any>) => {
setRepoInfo(params);
};
const syncFork = ref(null);
const handleSync = () => {
syncFork.value.handleOpen();
};
// @TODO 此处只用于repo切换时读取项目模块配置信息。是否直接从repo详情获取
watch(repoId, () => getModuleState(), { flush: 'post', immediate: true });
addEventListener('updateNaviBar', getModuleState);
onUnmounted(() => offEvent('updateNaviBar', getModuleState));
watch(() => topicData.userTopicList, val => {
if (val && val.length) {
tagList.value = validLinks.value.concat(topicData.userTopicList);
}
});
watch(() => validLinks.value, val => {
if (val && val.length) {
tagList.value = validLinks.value.concat(topicData.userTopicList);
}
}, { deep: true });
</script>
<style scoped lang="scss">
.repo-info {
.repo-visible {
border-radius: 14px;
border: 1px solid var(--devui-btn-common-border-color);
padding: 7px;
line-height: 16px;
height: 24px;
}
.official-topic {
background: rgba(#2951E0, 0.12);
border-radius: 4px;
padding: 0 8px;
height: 22px;
color: #2951E0;
font-weight: 600;
}
.status-btn-tag {
height: 24px;
border-radius: 12px;
border: 1px solid #e3e3ee;
padding: 0 8px;
font-size: 12px;
&:hover {
background: #f1f1f8;
color: #000 !important;
}
&:not(:last-of-type) {
margin-right: 4px;
}
}
.fork-btn {
border-radius: 4px;
border: 1px solid #E3E3EE;
background: #fff;
padding: 2px 8px;
cursor: pointer;
display: flex;
align-items: center;
&:hover {
background: linear-gradient(0deg, rgba(188, 188, 208, 0.1) 0%, rgba(188, 188, 208, 0.1) 100%), var(--White, #fff);
}
}
}
</style>