fix(portal): 修复组织架构图连接线及子公司详情页空白问题

- 架构图横线改用 border-top 方式,连线准确对齐
- 后端 OrganizationPublicViewSet 支持按 ID 查询任意组织(不限顶级)
- CompanyDetailView 添加 try-catch 防止 Promise.all 失败导致空白

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
TianyangZhang 2026-03-26 13:48:39 +08:00
parent f820499376
commit 819ad3e7f1
3 changed files with 29 additions and 30 deletions

View File

@ -7,8 +7,14 @@ from apps.accounts.permissions import IsSuperAdmin
class OrganizationPublicViewSet(viewsets.ReadOnlyModelViewSet):
"""公开只读:门户展示用,返回顶级组织(集团)及其子公司树"""
queryset = Organization.objects.filter(is_active=True, parent__isnull=True)
queryset = Organization.objects.filter(is_active=True)
serializer_class = OrganizationTreeSerializer
def get_queryset(self):
# 列表只返回顶级,详情可查任意
if self.action == 'list':
return Organization.objects.filter(is_active=True, parent__isnull=True)
return Organization.objects.filter(is_active=True)
permission_classes = [AllowAny]

View File

@ -21,11 +21,15 @@ const route = useRoute()
const org = ref(null)
const jobs = ref([])
onMounted(async () => {
const [orgRes, jobRes] = await Promise.all([
getOrganization(route.params.id),
getJobs({ organization: route.params.id })
])
org.value = orgRes.data
jobs.value = jobRes.data.results
try {
const [orgRes, jobRes] = await Promise.all([
getOrganization(route.params.id),
getJobs({ organization: route.params.id })
])
org.value = orgRes.data
jobs.value = jobRes.data.results ?? []
} catch (e) {
console.error('加载公司详情失败', e)
}
})
</script>

View File

@ -47,13 +47,10 @@
<div class="node-name">{{ group.name }}</div>
<div class="node-sub">集团总院</div>
</div>
<!-- 根节点下的竖线 -->
<div class="root-v-line"></div>
</div>
<!-- 连接线 -->
<div class="org-connector">
<div class="v-line"></div>
<div class="h-line"></div>
</div>
<!-- 子节点 -->
<!-- 子节点区域横线用 before 伪元素覆盖 -->
<div class="org-children">
<div
v-for="child in group.children"
@ -266,9 +263,15 @@ onMounted(async () => {
}
.org-root {
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
margin-bottom: 0;
}
.root-v-line {
width: 2px;
height: 24px;
background: #d0d0d0;
}
.org-node {
border-radius: 8px;
padding: 10px 16px;
@ -293,27 +296,13 @@ onMounted(async () => {
color: #c9a84c;
margin-top: 4px;
}
.org-connector {
display: flex;
flex-direction: column;
align-items: center;
}
.v-line {
width: 2px;
height: 24px;
background: #d0d0d0;
}
.h-line {
width: calc(100% - 40px);
height: 2px;
background: #d0d0d0;
min-width: 600px;
}
/* 子节点行 */
.org-children {
display: flex;
justify-content: space-between;
gap: 8px;
min-width: 900px;
border-top: 2px solid #d0d0d0;
}
.org-child-wrap {
display: flex;