Merge remote-tracking branch 'origin/main'

This commit is contained in:
caozehui
2026-05-18 13:19:45 +08:00
11 changed files with 187 additions and 179 deletions

View File

@@ -3,7 +3,7 @@ import { computed, onMounted, reactive, ref } from 'vue';
import type { Component } from 'vue';
import { ElButton, ElTag } from 'element-plus';
import dayjs from 'dayjs';
import { CircleCheckFilled, DeleteFilled, FolderOpened, VideoPause } from '@element-plus/icons-vue';
import { Box, DeleteFilled, VideoPause, VideoPlay } from '@element-plus/icons-vue';
import { RDMS_OBJECT_DIRECTION_DICT_CODE } from '@/constants/dict';
import { OBJECT_CONTEXT_QUERY_KEY } from '@/constants/object-context';
import { fetchGetProductOverviewSummary, fetchGetProductPage, fetchGetUserSimpleList } from '@/service/api';
@@ -76,14 +76,14 @@ const statusNavMetas: StatusNavMeta[] = [
label: '启用产品',
description: '当前正常服务中的产品',
tone: 'teal',
icon: CircleCheckFilled
icon: VideoPlay
},
{
key: 'archived',
label: '归档产品',
description: '已完成阶段目标的产品',
tone: 'slate',
icon: FolderOpened
icon: Box
},
{
key: 'paused',
@@ -109,7 +109,7 @@ const operateVisible = ref(false);
const editingRow = ref<Api.Product.Product | null>(null);
const { routerPush } = useRouterPush();
const { dictData: directionOptions, getLabel: getDirectionDictLabel } = useDict(RDMS_OBJECT_DIRECTION_DICT_CODE);
const { getLabel: getDirectionDictLabel } = useDict(RDMS_OBJECT_DIRECTION_DICT_CODE);
const statusCounts = ref<Record<string, number>>({
active: 0,
@@ -129,29 +129,6 @@ const statusItems = computed(() =>
}))
);
const overviewMetrics = computed(() => [
{
label: '可见产品',
value: Object.values(statusCounts.value).reduce((sum, count) => sum + count, 0),
hint: '当前接口可查询到的产品总量'
},
{
label: '当前启用',
value: statusCounts.value.active ?? 0,
hint: '正在持续服务和维护的产品'
},
{
label: '产品方向',
value: directionOptions.value.length,
hint: '已加载的方向字典项数量'
},
{
label: '废弃产品',
value: statusCounts.value.abandoned ?? 0,
hint: '已明确停止建设的产品'
}
]);
function getDirectionLabel(directionCode?: string | null) {
return getDirectionDictLabel(directionCode, '--');
}
@@ -288,7 +265,7 @@ async function handleResetSearch() {
async function handleStatusChange(status: Api.Product.ProductStatusCode) {
selectedStatus.value = status;
await reloadProductTable(1);
await Promise.all([loadOverviewData(), reloadProductTable(1)]);
}
function openCreate() {
@@ -326,14 +303,6 @@ onMounted(async () => {
>
<div class="flex-col-stretch gap-16px xl:min-h-0">
<ElCard class="product-overview-card card-wrapper">
<div class="product-overview-card__stats">
<div v-for="item in overviewMetrics" :key="item.label" class="product-overview-card__stat">
<span class="product-overview-card__stat-label">{{ item.label }}</span>
<strong class="product-overview-card__stat-value">{{ item.value }}</strong>
<small class="product-overview-card__stat-hint">{{ item.hint }}</small>
</div>
</div>
<div class="product-status-panel__list">
<button
v-for="item in statusItems"
@@ -441,45 +410,10 @@ onMounted(async () => {
linear-gradient(180deg, rgb(255 255 255 / 99%), rgb(248 250 252 / 97%));
}
.product-overview-card__stats {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 12px;
}
.product-overview-card__stat {
display: flex;
flex-direction: column;
gap: 6px;
padding: 14px 16px;
border: 1px solid rgb(226 232 240 / 88%);
border-radius: 18px;
background-color: rgb(255 255 255 / 84%);
}
.product-overview-card__stat-label {
color: rgb(100 116 139 / 90%);
font-size: 13px;
}
.product-overview-card__stat-value {
color: rgb(15 23 42 / 94%);
font-size: 24px;
font-weight: 700;
line-height: 1.1;
}
.product-overview-card__stat-hint {
color: rgb(100 116 139 / 90%);
font-size: 12px;
line-height: 1.5;
}
.product-status-panel__list {
display: flex;
flex-direction: column;
gap: 12px;
margin-top: 16px;
}
.product-status-item {
@@ -594,10 +528,4 @@ onMounted(async () => {
flex-direction: column;
}
}
@media (width <= 640px) {
.product-overview-card__stats {
grid-template-columns: 1fr;
}
}
</style>

View File

@@ -71,7 +71,7 @@ const operateVisible = ref(false);
const editingRow = ref<Api.Project.Project | null>(null);
const { routerPush } = useRouterPush();
const { dictData: directionOptions, getLabel: getDirectionDictLabel } = useDict(RDMS_OBJECT_DIRECTION_DICT_CODE);
const { getLabel: getDirectionDictLabel } = useDict(RDMS_OBJECT_DIRECTION_DICT_CODE);
const { getLabel: getProjectTypeLabel } = useDict(RDMS_PROJECT_TYPE_DICT_CODE);
const statusCounts = ref<Record<string, number>>({
@@ -243,7 +243,7 @@ async function handleResetSearch() {
async function handleStatusChange(status: Api.Project.ProjectStatusCode) {
selectedStatus.value = status;
await reloadProjectTable(1);
await Promise.all([loadOverviewData(), reloadProjectTable(1)]);
}
function openCreate() {
@@ -282,7 +282,6 @@ onMounted(async () => {
<div class="flex-col-stretch gap-16px xl:min-h-0">
<ProjectOverviewCard
:status-counts="statusCounts"
:direction-count="directionOptions.length"
:selected-status="selectedStatus"
@status-change="handleStatusChange"
/>

View File

@@ -1,7 +1,7 @@
<script setup lang="ts">
import { computed } from 'vue';
import type { Component } from 'vue';
import { CircleCheckFilled, DeleteFilled, DocumentAdd, FolderOpened, VideoPause } from '@element-plus/icons-vue';
import { Box, CircleCheckFilled, DeleteFilled, DocumentAdd, VideoPause, VideoPlay } from '@element-plus/icons-vue';
defineOptions({ name: 'ProjectOverviewCard' });
@@ -15,7 +15,6 @@ interface StatusNavMeta {
interface Props {
statusCounts: Record<string, number>;
directionCount: number;
selectedStatus: Api.Project.ProjectStatusCode;
}
@@ -40,7 +39,7 @@ const statusNavMetas: StatusNavMeta[] = [
label: '进行中',
description: '正在执行的项目',
tone: 'teal',
icon: CircleCheckFilled
icon: VideoPlay
},
{
key: 'paused',
@@ -54,7 +53,7 @@ const statusNavMetas: StatusNavMeta[] = [
label: '已完成',
description: '达成目标的项目',
tone: 'teal',
icon: FolderOpened
icon: CircleCheckFilled
},
{
key: 'cancelled',
@@ -68,7 +67,7 @@ const statusNavMetas: StatusNavMeta[] = [
label: '归档项目',
description: '已收口归档的历史项目',
tone: 'slate',
icon: FolderOpened
icon: Box
}
];
@@ -79,29 +78,6 @@ const statusItems = computed(() =>
}))
);
const overviewMetrics = computed(() => [
{
label: '总项目数',
value: Object.values(props.statusCounts).reduce((sum, count) => sum + count, 0),
hint: '当前接口可查询到的项目总量'
},
{
label: '进行中',
value: props.statusCounts.active ?? 0,
hint: '正在执行的项目'
},
{
label: '待开始',
value: props.statusCounts.pending ?? 0,
hint: '等待启动的项目'
},
{
label: '作废项目',
value: props.statusCounts.cancelled ?? 0,
hint: '已终止或取消推进的项目'
}
]);
function handleStatusClick(status: Api.Project.ProjectStatusCode) {
emit('status-change', status);
}
@@ -109,14 +85,6 @@ function handleStatusClick(status: Api.Project.ProjectStatusCode) {
<template>
<ElCard class="project-overview-card card-wrapper">
<div class="project-overview-card__stats">
<div v-for="item in overviewMetrics" :key="item.label" class="project-overview-card__stat">
<span class="project-overview-card__stat-label">{{ item.label }}</span>
<strong class="project-overview-card__stat-value">{{ item.value }}</strong>
<small class="project-overview-card__stat-hint">{{ item.hint }}</small>
</div>
</div>
<div class="project-status-panel__list">
<button
v-for="item in statusItems"
@@ -153,45 +121,10 @@ function handleStatusClick(status: Api.Project.ProjectStatusCode) {
linear-gradient(180deg, rgb(255 255 255 / 99%), rgb(248 250 252 / 97%));
}
.project-overview-card__stats {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 12px;
}
.project-overview-card__stat {
display: flex;
flex-direction: column;
gap: 6px;
padding: 14px 16px;
border: 1px solid rgb(226 232 240 / 88%);
border-radius: 18px;
background-color: rgb(255 255 255 / 84%);
}
.project-overview-card__stat-label {
color: rgb(100 116 139 / 90%);
font-size: 13px;
}
.project-overview-card__stat-value {
color: rgb(15 23 42 / 94%);
font-size: 24px;
font-weight: 700;
line-height: 1.1;
}
.project-overview-card__stat-hint {
color: rgb(100 116 139 / 90%);
font-size: 12px;
line-height: 1.5;
}
.project-status-panel__list {
display: flex;
flex-direction: column;
gap: 12px;
margin-top: 16px;
}
.project-status-item {
@@ -293,10 +226,4 @@ function handleStatusClick(status: Api.Project.ProjectStatusCode) {
flex-direction: column;
}
}
@media (width <= 640px) {
.project-overview-card__stats {
grid-template-columns: 1fr;
}
}
</style>