release(main): 同步 dev 最新候选改动
Storage Persistence Guard / storage-persistence-audit (push) Has been cancelled
Client Quality Gates / Shared client and Web (push) Has been cancelled
Client Quality Gates / macOS Desktop (push) Has been cancelled
Client Quality Gates / Shared client and Web (pull_request) Has been cancelled
Client Quality Gates / macOS Desktop (pull_request) Has been cancelled
Storage Persistence Guard / storage-persistence-audit (pull_request) Has been cancelled

This commit is contained in:
Cheng Zhou
2026-07-16 17:15:50 +08:00
parent 32167fba02
commit d5279b124f
393 changed files with 51630 additions and 9711 deletions
+45 -41
View File
@@ -1,16 +1,9 @@
<template>
<div class="page ctms-page-shell page--flush">
<div v-if="study.currentStudy" class="unified-shell ctms-table-card">
<section class="unified-action-bar bar--flush">
<section class="unified-action-bar milestone-action-bar">
<div class="card-header ctms-page-header-row">
<div>
<div class="card-title">{{ TEXT.modules.projectMilestones.listTitle }}</div>
<div class="card-subtitle">
{{ TEXT.modules.projectMilestones.sourceLabel }}{{ dataSourceLabel }}
<span class="dot-sep">·</span>
{{ TEXT.common.labels.updatedAt }}{{ updatedAtLabel }}
</div>
</div>
<div class="card-title">{{ TEXT.modules.projectMilestones.listTitle }}</div>
<div class="header-actions">
<el-tag size="small" effect="plain">
{{ TEXT.modules.projectMilestones.statTotal }}{{ rows.length }}
@@ -200,7 +193,6 @@ import { useStudyStore } from "../../store/study";
import { listProjectMilestones, updateProjectMilestone } from "../../api/projectMilestones";
import { TEXT } from "../../locales";
import StateEmpty from "../../components/StateEmpty.vue";
import { displayDateTime } from "../../utils/display";
import { usePermission } from "../../utils/permission";
import { useDrawerDirtyGuard } from "../../utils/drawerDirtyGuard";
@@ -237,8 +229,6 @@ const study = useStudyStore();
const { can } = usePermission();
const rows = ref<MilestoneRow[]>([]);
const loading = ref(false);
const dataSourceLabel = ref<string>(TEXT.modules.projectMilestones.sourcePublished);
const updatedAtLabel = ref<string>(TEXT.common.fallback);
const editorVisible = ref(false);
const editingRowId = ref("");
const editorForm = reactive<MilestoneLocalEdit>({
@@ -309,15 +299,8 @@ const loadMilestones = async () => {
const { data } = (await listProjectMilestones(studyId)) as any;
const list = Array.isArray(data) ? data : data?.items || [];
rows.value = list.map(normalizeRow);
const updatedAt = list
.map((item: any) => String(item?.updated_at || ""))
.filter(Boolean)
.sort()
.pop();
updatedAtLabel.value = updatedAt ? displayDateTime(updatedAt) : TEXT.common.fallback;
} catch (error: any) {
rows.value = [];
updatedAtLabel.value = TEXT.common.fallback;
ElMessage.error(error?.response?.data?.detail || TEXT.common.messages.loadFailed);
} finally {
loading.value = false;
@@ -452,7 +435,6 @@ watch(
() => study.currentStudy?.id,
() => {
rows.value = [];
updatedAtLabel.value = TEXT.common.fallback;
loadMilestones();
}
);
@@ -462,6 +444,32 @@ watch(
.page {
display: flex;
flex-direction: column;
/* 撑满父容器(desktop-route-shell 已经是 height: 100%*/
height: 100%;
min-height: 0;
}
/* 让白色卡片壳撑满 .page 的剩余高度,并去掉圆角 */
.page > .unified-shell {
flex: 1;
display: flex;
flex-direction: column;
min-height: 0;
border-radius: 0;
}
/* 让表格 section 撑满卡片壳的剩余高度 */
.page > .unified-shell > .unified-section {
flex: 1;
display: flex;
flex-direction: column;
min-height: 0;
}
/* el-table 本身填满 section */
.page > .unified-shell > .unified-section :deep(.el-table),
.page > .unified-shell > .unified-section :deep(.el-table__inner-wrapper) {
height: 100%;
}
.ctms-page-content-grid {
@@ -477,20 +485,15 @@ watch(
flex-wrap: wrap;
}
.milestone-action-bar {
min-height: 56px;
box-sizing: border-box;
}
.card-title {
font-size: 15px;
font-weight: 700;
color: #0f2345;
}
.card-subtitle {
margin-top: 4px;
font-size: 12px;
color: var(--ctms-text-secondary);
}
.dot-sep {
margin: 0 8px;
color: var(--unified-title-color);
}
.header-actions {
@@ -520,11 +523,11 @@ watch(
border-radius: 50%;
border: 3px solid #2f84c6;
box-sizing: border-box;
background: #ffffff;
background: var(--ctms-bg-card);
}
.plan-time-label {
color: #4b5563;
color: var(--ctms-text-secondary);
font-size: 11px;
}
@@ -546,10 +549,10 @@ watch(
}
.time-editor-group {
border: 1px solid #e8eef6;
border: 1px solid var(--ctms-border-color);
border-radius: 10px;
padding: 14px 16px 10px;
background: #fbfcfe;
background: var(--ctms-bg-muted);
}
.time-editor-group + .time-editor-group {
@@ -566,7 +569,7 @@ watch(
font-size: 14px;
font-weight: 700;
margin-bottom: 12px;
color: #1a3560;
color: var(--ctms-text-main);
display: flex;
align-items: center;
gap: 8px;
@@ -600,14 +603,14 @@ watch(
.duration-label {
font-size: 13px;
color: #6b7280;
color: var(--ctms-text-secondary);
font-weight: 500;
}
.duration-value {
font-size: 14px;
font-weight: 700;
color: #1a3560;
color: var(--ctms-text-main);
}
.time-editor-footer {
@@ -628,7 +631,7 @@ watch(
.time-editor-form :deep(.el-form-item__label) {
font-size: 13px;
font-weight: 600;
color: #4a6283;
color: var(--ctms-text-regular);
padding-bottom: 4px;
}
@@ -655,7 +658,7 @@ watch(
.status-detail {
padding-left: 14px;
color: #6b7280;
color: var(--ctms-text-secondary);
font-size: 11px;
}
@@ -684,9 +687,10 @@ watch(
display: flex;
align-items: center;
justify-content: center;
color: #8a97ab;
color: var(--ctms-text-secondary);
font-size: 14px;
font-weight: 500;
letter-spacing: 0.02em;
}
</style>