feat: 成果发布列表评审未完成时禁用发布成果入口
Made-with: Cursor
This commit is contained in:
parent
6c3b2f4a1d
commit
ea40131084
@ -8,12 +8,8 @@
|
||||
|
||||
<!-- 统计卡片 -->
|
||||
<div class="stats-row">
|
||||
<div
|
||||
v-for="item in statsItems"
|
||||
:key="item.key"
|
||||
:class="['stat-card', { active: activeFilter === item.key }]"
|
||||
@click="handleStatClick(item.key)"
|
||||
>
|
||||
<div v-for="item in statsItems" :key="item.key" :class="['stat-card', { active: activeFilter === item.key }]"
|
||||
@click="handleStatClick(item.key)">
|
||||
<div class="stat-icon" :style="{ background: item.bgColor }">
|
||||
<component :is="item.icon" :style="{ color: item.color }" />
|
||||
</div>
|
||||
@ -28,46 +24,31 @@
|
||||
<div class="filter-bar">
|
||||
<a-form layout="inline" :model="superSearch" @finish="handleSuperSearch">
|
||||
<a-form-item label="所属活动">
|
||||
<a-select
|
||||
v-model:value="superSearch.contestId"
|
||||
placeholder="全部活动"
|
||||
allow-clear
|
||||
show-search
|
||||
:filter-option="filterContestOption"
|
||||
style="width: 200px"
|
||||
:options="contestOptions"
|
||||
/>
|
||||
<a-select v-model:value="superSearch.contestId" placeholder="全部活动" allow-clear show-search
|
||||
:filter-option="filterContestOption" style="width: 200px" :options="contestOptions" />
|
||||
</a-form-item>
|
||||
<a-form-item label="发布状态">
|
||||
<a-select
|
||||
v-model:value="superSearch.resultState"
|
||||
placeholder="全部"
|
||||
allow-clear
|
||||
style="width: 110px"
|
||||
>
|
||||
<a-select v-model:value="superSearch.resultState" placeholder="全部" allow-clear style="width: 110px">
|
||||
<a-select-option value="published">已发布</a-select-option>
|
||||
<a-select-option value="unpublished">未发布</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="主办机构">
|
||||
<a-select
|
||||
v-model:value="superSearch.creatorTenantId"
|
||||
placeholder="全部机构"
|
||||
allow-clear
|
||||
show-search
|
||||
:filter-option="filterTenantOption"
|
||||
style="width: 160px"
|
||||
:options="tenantOptions"
|
||||
/>
|
||||
<a-select v-model:value="superSearch.creatorTenantId" placeholder="全部机构" allow-clear show-search
|
||||
:filter-option="filterTenantOption" style="width: 160px" :options="tenantOptions" />
|
||||
</a-form-item>
|
||||
<a-form-item>
|
||||
<a-space>
|
||||
<a-button type="primary" html-type="submit">
|
||||
<template #icon><SearchOutlined /></template>
|
||||
<template #icon>
|
||||
<SearchOutlined />
|
||||
</template>
|
||||
搜索
|
||||
</a-button>
|
||||
<a-button @click="handleSuperReset">
|
||||
<template #icon><ReloadOutlined /></template>
|
||||
<template #icon>
|
||||
<ReloadOutlined />
|
||||
</template>
|
||||
重置
|
||||
</a-button>
|
||||
</a-space>
|
||||
@ -76,26 +57,15 @@
|
||||
</div>
|
||||
|
||||
<!-- 表格 -->
|
||||
<a-table
|
||||
:columns="superColumns"
|
||||
:data-source="superDataSource"
|
||||
:loading="superLoading"
|
||||
:pagination="superPagination"
|
||||
row-key="id"
|
||||
@change="handleSuperTableChange"
|
||||
class="data-table"
|
||||
>
|
||||
<a-table :columns="superColumns" :data-source="superDataSource" :loading="superLoading"
|
||||
:pagination="superPagination" row-key="id" @change="handleSuperTableChange" class="data-table">
|
||||
<template #bodyCell="{ column, record, index }">
|
||||
<template v-if="column.key === 'index'">
|
||||
{{ (superPagination.current - 1) * superPagination.pageSize + index + 1 }}
|
||||
</template>
|
||||
<template v-else-if="column.key === 'contestName'">
|
||||
<a-button
|
||||
type="link"
|
||||
size="small"
|
||||
class="contest-link"
|
||||
@click="router.push(`/${tenantCode}/contests/${record.id}/overview`)"
|
||||
>
|
||||
<a-button type="link" size="small" class="contest-link"
|
||||
@click="router.push(`/${tenantCode}/contests/${record.id}/overview`)">
|
||||
{{ record.contestName }}
|
||||
</a-button>
|
||||
</template>
|
||||
@ -137,7 +107,8 @@
|
||||
|
||||
<!-- 统计概览 -->
|
||||
<div class="stats-row">
|
||||
<div v-for="item in orgStatsItems" :key="item.key" :class="['stat-card', { active: orgActiveFilter === item.key }]" @click="handleOrgStatClick(item.key)">
|
||||
<div v-for="item in orgStatsItems" :key="item.key"
|
||||
:class="['stat-card', { active: orgActiveFilter === item.key }]" @click="handleOrgStatClick(item.key)">
|
||||
<div class="stat-icon" :style="{ background: item.bgColor }">
|
||||
<component :is="item.icon" :style="{ color: item.color }" />
|
||||
</div>
|
||||
@ -155,25 +126,33 @@
|
||||
<a-input v-model:value="searchParams.contestName" placeholder="请输入活动名称" allow-clear style="width: 200px" />
|
||||
</a-form-item>
|
||||
<a-form-item label="活动类型">
|
||||
<a-select v-model:value="searchParams.contestType" placeholder="全部" allow-clear style="width: 120px" @change="handleSearch">
|
||||
<a-select v-model:value="searchParams.contestType" placeholder="全部" allow-clear style="width: 120px"
|
||||
@change="handleSearch">
|
||||
<a-select-option value="individual">个人参与</a-select-option>
|
||||
<a-select-option value="team">团队参与</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="发布状态">
|
||||
<a-select v-model:value="orgResultState" placeholder="全部" allow-clear style="width: 110px" @change="handleSearch">
|
||||
<a-select v-model:value="orgResultState" placeholder="全部" allow-clear style="width: 110px"
|
||||
@change="handleSearch">
|
||||
<a-select-option value="published">已发布</a-select-option>
|
||||
<a-select-option value="unpublished">未发布</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item>
|
||||
<a-button type="primary" html-type="submit"><template #icon><SearchOutlined /></template> 搜索</a-button>
|
||||
<a-button style="margin-left: 8px" @click="handleReset"><template #icon><ReloadOutlined /></template> 重置</a-button>
|
||||
<a-button type="primary" html-type="submit"><template #icon>
|
||||
<SearchOutlined />
|
||||
</template> 搜索</a-button>
|
||||
<a-button style="margin-left: 8px" @click="handleReset"><template #icon>
|
||||
<ReloadOutlined />
|
||||
</template>
|
||||
重置</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</div>
|
||||
|
||||
<a-table :columns="orgColumns" :data-source="dataSource" :loading="loading" :pagination="pagination" row-key="id" @change="handleTableChange" class="data-table">
|
||||
<a-table :columns="orgColumns" :data-source="dataSource" :loading="loading" :pagination="pagination" row-key="id"
|
||||
@change="handleTableChange" class="data-table">
|
||||
<template #bodyCell="{ column, record, index }">
|
||||
<template v-if="column.key === 'index'">
|
||||
{{ (pagination.current - 1) * pagination.pageSize + index + 1 }}
|
||||
@ -182,7 +161,8 @@
|
||||
<a @click="handleViewDetail(record)">{{ record.contestName }}</a>
|
||||
</template>
|
||||
<template v-else-if="column.key === 'contestType'">
|
||||
<a-tag :color="record.contestType === 'individual' ? 'blue' : 'green'">{{ record.contestType === 'individual' ? '个人' : '团队' }}</a-tag>
|
||||
<a-tag :color="record.contestType === 'individual' ? 'blue' : 'green'">{{ record.contestType ===
|
||||
'individual' ? '个人' : '团队' }}</a-tag>
|
||||
</template>
|
||||
<template v-else-if="column.key === 'registrationCount'">
|
||||
{{ record._count?.registrations || 0 }}
|
||||
@ -195,8 +175,17 @@
|
||||
<a-tag v-else color="default">未发布</a-tag>
|
||||
</template>
|
||||
<template v-else-if="column.key === 'action'">
|
||||
<a-button v-if="record.resultState === 'published'" type="link" size="small" @click="handleViewDetail(record)">查看成果</a-button>
|
||||
<a-button v-else type="link" size="small" style="color: #10b981" @click="handleViewDetail(record)">发布成果</a-button>
|
||||
<a-button v-if="record.resultState === 'published'" type="link" size="small"
|
||||
@click="handleViewDetail(record)">查看成果</a-button>
|
||||
<template v-else-if="canPublishResults(record)">
|
||||
<a-button type="link" size="small" style="color: #10b981"
|
||||
@click="handleViewDetail(record)">发布成果</a-button>
|
||||
</template>
|
||||
<a-tooltip v-else placement="top" title="评审未完成,请待全部作品完成评审后再发布成果">
|
||||
<span class="publish-results-btn-wrap">
|
||||
<a-button type="link" size="small" style="color: #777" disabled>发布成果</a-button>
|
||||
</span>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
</template>
|
||||
</a-table>
|
||||
@ -232,6 +221,16 @@ const isSuperAdmin = computed(() => authStore.hasAnyRole(['super_admin']))
|
||||
|
||||
const formatDate = (d?: string) => d ? dayjs(d).format("YYYY-MM-DD HH:mm") : "-"
|
||||
|
||||
/**
|
||||
* 是否允许进入成果发布详情(发布成果入口)。
|
||||
* 与活动列表接口的 reviewedCount / totalWorksCount 一致:有作品且已完成评审的作品数 ≥ 作品总数。
|
||||
*/
|
||||
function canPublishResults(record: Contest): boolean {
|
||||
const totalWorks = Number(record.totalWorksCount ?? record._count?.works ?? 0)
|
||||
const reviewed = Number(record.reviewedCount ?? 0)
|
||||
return totalWorks > 0 && reviewed >= totalWorks
|
||||
}
|
||||
|
||||
// =============================================
|
||||
// 超管端逻辑
|
||||
// =============================================
|
||||
@ -455,11 +454,26 @@ $primary: #6366f1;
|
||||
border: none;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
|
||||
:deep(.ant-card-head) { border-bottom: none; .ant-card-head-title { font-size: 18px; font-weight: 600; } }
|
||||
:deep(.ant-card-body) { padding: 0; }
|
||||
|
||||
:deep(.ant-card-head) {
|
||||
border-bottom: none;
|
||||
|
||||
.ant-card-head-title {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.ant-card-body) {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.stats-row { display: flex; gap: 12px; margin-bottom: 16px; }
|
||||
.stats-row {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
flex: 1;
|
||||
@ -473,10 +487,43 @@ $primary: #6366f1;
|
||||
cursor: pointer;
|
||||
border: 2px solid transparent;
|
||||
transition: all 0.2s;
|
||||
&:hover { box-shadow: 0 4px 16px rgba($primary, 0.12); }
|
||||
&.active { border-color: $primary; background: rgba($primary, 0.02); }
|
||||
.stat-icon { width: 36px; height: 36px; border-radius: 8px; display: flex; align-items: center; justify-content: center; font-size: 16px; flex-shrink: 0; }
|
||||
.stat-info { display: flex; flex-direction: column; .stat-count { font-size: 18px; font-weight: 700; color: #1e1b4b; line-height: 1.2; } .stat-label { font-size: 12px; color: #9ca3af; } }
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 4px 16px rgba($primary, 0.12);
|
||||
}
|
||||
|
||||
&.active {
|
||||
border-color: $primary;
|
||||
background: rgba($primary, 0.02);
|
||||
}
|
||||
|
||||
.stat-icon {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 16px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.stat-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.stat-count {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: #1e1b4b;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 12px;
|
||||
color: #9ca3af;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.filter-bar {
|
||||
@ -493,13 +540,35 @@ $primary: #6366f1;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
|
||||
overflow: hidden;
|
||||
.ant-table-thead > tr > th { background: #fafafa; font-weight: 600; }
|
||||
.ant-table-tbody > tr:hover > td { background: rgba($primary, 0.03); }
|
||||
.ant-table-pagination { padding: 16px; margin: 0; }
|
||||
|
||||
.ant-table-thead>tr>th {
|
||||
background: #fafafa;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.ant-table-tbody>tr:hover>td {
|
||||
background: rgba($primary, 0.03);
|
||||
}
|
||||
|
||||
.ant-table-pagination {
|
||||
padding: 16px;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.contest-link { padding: 0; text-align: left; }
|
||||
.text-muted { color: #d1d5db; }
|
||||
.contest-link {
|
||||
padding: 0;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.text-muted {
|
||||
color: #d1d5db;
|
||||
}
|
||||
|
||||
/* 包裹禁用链接按钮,便于 Tooltip 触发且布局不塌缩 */
|
||||
.publish-results-btn-wrap {
|
||||
display: inline-block;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
</style>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user