优化登录页UI、新增占满布局类
This commit is contained in:
@@ -18,6 +18,7 @@ const session = useSessionStore();
|
||||
<style scoped>
|
||||
.app-shell {
|
||||
min-height: 100vh;
|
||||
min-height: 100dvh;
|
||||
}
|
||||
|
||||
.app-locked {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<el-card class="panel">
|
||||
<div class="panel unified-shell">
|
||||
<div class="header">
|
||||
<span>{{ TEXT.common.labels.category }}</span>
|
||||
<div v-if="canMaintain">
|
||||
@@ -23,7 +23,7 @@
|
||||
</el-menu-item>
|
||||
</el-menu>
|
||||
<FaqCategoryForm v-model="showForm" :category="editing" :is-admin="isAdmin" @success="emit('refresh')" />
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
@@ -94,18 +94,24 @@ const onDelete = async (cat: FaqCategory) => {
|
||||
|
||||
<style scoped>
|
||||
.panel {
|
||||
padding: 0;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 12px;
|
||||
padding: 0 0 12px;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
}
|
||||
|
||||
.menu {
|
||||
max-height: calc(100vh - 240px);
|
||||
overflow: auto;
|
||||
border-right: 0;
|
||||
}
|
||||
.actions {
|
||||
margin-left: auto;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<el-table :data="items" v-loading="loading" style="width: 100%" @row-click="onRowClick">
|
||||
<el-table :data="items" v-loading="loading" style="width: 100%" class="faq-table" @row-click="onRowClick">
|
||||
<el-table-column prop="question" :label="TEXT.common.fields.question" min-width="200">
|
||||
<template #default="scope">
|
||||
<el-link type="primary" :underline="false" class="question-link">
|
||||
@@ -131,6 +131,10 @@ const remove = async (row: FaqItem) => {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.faq-table :deep(.el-table__inner-wrapper::before) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.danger {
|
||||
color: #f56c6c;
|
||||
}
|
||||
|
||||
@@ -195,8 +195,8 @@
|
||||
<div class="content-wrapper">
|
||||
<router-view v-slot="{ Component }">
|
||||
<transition name="fade-transform" mode="out-in">
|
||||
<div class="ctms-route-shell">
|
||||
<component :is="Component" />
|
||||
<div :key="route.fullPath" class="ctms-route-shell">
|
||||
<component :is="Component" :key="route.fullPath" />
|
||||
</div>
|
||||
</transition>
|
||||
</router-view>
|
||||
@@ -435,6 +435,9 @@ const onCommand = (cmd: string) => {
|
||||
<style scoped>
|
||||
.layout-container {
|
||||
height: 100vh;
|
||||
height: 100dvh;
|
||||
min-height: 100vh;
|
||||
min-height: 100dvh;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
@@ -703,6 +706,7 @@ const onCommand = (cmd: string) => {
|
||||
.content-wrapper {
|
||||
padding: 6px 8px;
|
||||
min-height: calc(100vh - 52px);
|
||||
min-height: calc(100dvh - 52px);
|
||||
background: #f7f8fb;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,19 +1,21 @@
|
||||
<template>
|
||||
<div class="module-page">
|
||||
<div class="module-header">
|
||||
<div>
|
||||
<h1 class="module-title">{{ title }}</h1>
|
||||
<p v-if="subtitle" class="module-subtitle">{{ subtitle }}</p>
|
||||
</div>
|
||||
<slot name="actions" />
|
||||
</div>
|
||||
<div class="module-content">
|
||||
<div class="module-list">
|
||||
<div class="module-list-header">
|
||||
<span class="list-title">{{ listTitle }}</span>
|
||||
<span class="list-note">{{ TEXT.common.empty.listPlaceholder }}</span>
|
||||
<div class="module-page ctms-page-shell page--flush">
|
||||
<div class="unified-shell">
|
||||
<div class="module-header unified-action-bar bar--flush">
|
||||
<div>
|
||||
<h1 class="module-title">{{ title }}</h1>
|
||||
<p v-if="subtitle" class="module-subtitle">{{ subtitle }}</p>
|
||||
</div>
|
||||
<slot name="actions" />
|
||||
</div>
|
||||
<div class="module-content unified-section section--flush">
|
||||
<div class="module-list">
|
||||
<div class="module-list-header">
|
||||
<span class="list-title">{{ listTitle }}</span>
|
||||
<span class="list-note">{{ TEXT.common.empty.listPlaceholder }}</span>
|
||||
</div>
|
||||
<StateEmpty :title="emptyTitle" :description="emptyDescription" />
|
||||
</div>
|
||||
<StateEmpty :title="emptyTitle" :description="emptyDescription" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -44,13 +46,7 @@ withDefaults(
|
||||
.module-page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.module-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: baseline;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.module-title {
|
||||
@@ -68,9 +64,9 @@ withDefaults(
|
||||
|
||||
.module-list {
|
||||
background-color: #fff;
|
||||
border: 1px solid var(--ctms-border-color);
|
||||
border-radius: var(--ctms-radius);
|
||||
padding: 20px;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.module-list-header {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<el-card>
|
||||
<div class="attachment-list-panel unified-shell">
|
||||
<div class="header">
|
||||
<span>{{ headerTitle }}</span>
|
||||
<AttachmentUploader
|
||||
@@ -10,7 +10,7 @@
|
||||
@uploaded="load"
|
||||
/>
|
||||
</div>
|
||||
<el-table :data="attachments" v-loading="loading" style="width: 100%">
|
||||
<el-table :data="attachments" v-loading="loading" style="width: 100%" class="attachment-table">
|
||||
<el-table-column prop="filename" :label="TEXT.common.labels.filename" min-width="200" />
|
||||
<el-table-column :label="TEXT.common.labels.size" width="120">
|
||||
<template #default="scope">{{ formatFileSize(scope.row.file_size ?? scope.row.size) }}</template>
|
||||
@@ -43,7 +43,7 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
<el-dialog append-to=".layout-main .content-wrapper" v-model="previewVisible" :title="previewTitle" width="720px" :close-on-click-modal="false">
|
||||
<div v-if="previewError" class="preview-error">
|
||||
@@ -236,11 +236,23 @@ watch(previewVisible, (visible) => {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.attachment-list-panel {
|
||||
background: #ffffff;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 8px;
|
||||
padding: 10px 16px;
|
||||
border-bottom: 1px solid #eaf0f8;
|
||||
}
|
||||
|
||||
.attachment-table :deep(.el-table__inner-wrapper::before) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.preview-frame {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="fee-attachments">
|
||||
<el-card v-for="group in groups" :key="group.key" class="group-card">
|
||||
<div v-for="group in groups" :key="group.key" class="group-card unified-shell">
|
||||
<div class="group-header">
|
||||
<div>
|
||||
<div class="group-title">{{ group.label }}</div>
|
||||
@@ -28,7 +28,7 @@
|
||||
<div v-if="(grouped[group.key] || []).length === 0" class="group-empty">
|
||||
<StateEmpty :description="group.emptyText" />
|
||||
</div>
|
||||
<el-table v-else :data="grouped[group.key]" style="width: 100%">
|
||||
<el-table v-else :data="grouped[group.key]" style="width: 100%" class="group-table">
|
||||
<el-table-column prop="filename" :label="TEXT.common.labels.filename" min-width="160" />
|
||||
<el-table-column :label="TEXT.common.labels.size" width="110">
|
||||
<template #default="scope">{{ formatFileSize(scope.row.size || scope.row.file_size) }}</template>
|
||||
@@ -59,7 +59,7 @@
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</template>
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-dialog append-to=".layout-main .content-wrapper" v-model="previewVisible" :title="previewTitle" width="720px" :close-on-click-modal="false">
|
||||
@@ -315,14 +315,21 @@ watch(previewVisible, (visible) => {
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
|
||||
.group-card {
|
||||
background: #ffffff;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.group-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 8px;
|
||||
gap: 8px;
|
||||
padding: 10px 16px;
|
||||
border-bottom: 1px solid #eaf0f8;
|
||||
}
|
||||
|
||||
.group-title {
|
||||
@@ -338,7 +345,11 @@ watch(previewVisible, (visible) => {
|
||||
}
|
||||
|
||||
.group-empty {
|
||||
padding: 0;
|
||||
padding: 12px 16px 0;
|
||||
}
|
||||
|
||||
.group-table :deep(.el-table__inner-wrapper::before) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Compact Empty State Override */
|
||||
|
||||
@@ -90,6 +90,12 @@
|
||||
}
|
||||
|
||||
/* 全局重置 */
|
||||
html,
|
||||
body,
|
||||
#app {
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: "Manrope", "Segoe UI", sans-serif;
|
||||
@@ -345,15 +351,15 @@ body {
|
||||
.ctms-filter-row {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
gap: 20px;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.ctms-filter-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
min-width: 160px;
|
||||
gap: 4px;
|
||||
min-width: 144px;
|
||||
}
|
||||
|
||||
.ctms-filter-label {
|
||||
@@ -368,6 +374,14 @@ body {
|
||||
|
||||
.ctms-table-card {
|
||||
margin-bottom: 0;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
box-shadow: none !important;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.ctms-table-card > .el-card__body {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.ctms-table .el-table__row {
|
||||
@@ -375,7 +389,7 @@ body {
|
||||
}
|
||||
|
||||
.ctms-pagination {
|
||||
margin-top: 16px;
|
||||
margin-top: 10px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
--unified-shell-border: #d8e2ef;
|
||||
--unified-shell-divider: #eaf0f8;
|
||||
--unified-shell-radius: 16px;
|
||||
--unified-shell-padding-x: 20px;
|
||||
--unified-shell-padding-y: 14px;
|
||||
--unified-shell-padding-x: 16px;
|
||||
--unified-shell-padding-y: 10px;
|
||||
--unified-title-color: #0f2345;
|
||||
--unified-muted-color: #6f84a8;
|
||||
}
|
||||
@@ -13,6 +13,11 @@
|
||||
padding: 16px 20px 20px;
|
||||
}
|
||||
|
||||
.ctms-page-shell.page--flush,
|
||||
.page.page--flush {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.ctms-page-header-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
@@ -33,6 +38,23 @@
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.page--flush > .unified-shell,
|
||||
.page--flush > .main-content-flat.unified-shell,
|
||||
.page--flush .page-body > .unified-shell,
|
||||
.page--flush .page-body > .main-content-flat.unified-shell {
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.main-content-flat {
|
||||
background: transparent;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.el-card.unified-shell {
|
||||
margin-bottom: 0;
|
||||
border: 0 !important;
|
||||
@@ -54,6 +76,11 @@
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.unified-action-bar.bar--flush {
|
||||
padding-left: 0 !important;
|
||||
padding-right: 0 !important;
|
||||
}
|
||||
|
||||
.ctms-page > .ctms-page-header.unified-action-bar,
|
||||
.page > .page-header.unified-action-bar {
|
||||
border: 0;
|
||||
@@ -67,6 +94,23 @@
|
||||
border-bottom: 1px solid var(--unified-shell-divider);
|
||||
}
|
||||
|
||||
.unified-section.section--flush-x {
|
||||
padding-left: 0 !important;
|
||||
padding-right: 0 !important;
|
||||
}
|
||||
|
||||
.unified-section.section--flush-top {
|
||||
padding-top: 0 !important;
|
||||
}
|
||||
|
||||
.unified-section.section--flush-bottom {
|
||||
padding-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.unified-section.section--flush {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.unified-section:last-child {
|
||||
border-bottom: 0;
|
||||
}
|
||||
@@ -112,16 +156,16 @@
|
||||
}
|
||||
|
||||
.unified-shell .el-table th.el-table__cell {
|
||||
background-color: #f8fbff;
|
||||
color: #35527d;
|
||||
background-color: #f7f9fc;
|
||||
color: #34506f;
|
||||
font-weight: 600;
|
||||
height: 42px;
|
||||
height: 40px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.unified-shell .el-table td.el-table__cell {
|
||||
border-bottom-color: #edf2f8;
|
||||
padding: 8px 0;
|
||||
padding: 7px 0;
|
||||
}
|
||||
|
||||
.unified-shell .el-button,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="page">
|
||||
<div class="page ctms-page-shell page--flush">
|
||||
<el-row :gutter="12">
|
||||
<el-col :span="5">
|
||||
<FaqCategoryPanel
|
||||
@@ -154,25 +154,25 @@ onMounted(async () => {
|
||||
|
||||
<style scoped>
|
||||
.page {
|
||||
padding: 16px;
|
||||
padding: 0;
|
||||
}
|
||||
.faq-main {
|
||||
background: #fff;
|
||||
border: 1px solid var(--ctms-border-color);
|
||||
border-radius: 10px;
|
||||
padding: 16px;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
.filters {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.spacer {
|
||||
flex: 1;
|
||||
}
|
||||
.pagination-wrap {
|
||||
margin-top: 14px;
|
||||
padding: 10px 16px 0;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="page">
|
||||
<el-card shadow="never" class="main-content-card unified-shell">
|
||||
<div class="main-content-flat unified-shell">
|
||||
<div class="filter-container unified-action-bar">
|
||||
<div class="filter-form">
|
||||
<el-tag type="info" effect="plain" class="filter-label-tag">{{ TEXT.common.fields.status }}</el-tag>
|
||||
@@ -14,7 +14,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="unified-section approval-table-section">
|
||||
<el-table :data="users" v-loading="loading" style="width: 100%">
|
||||
<el-table :data="users" v-loading="loading" class="approval-table" style="width: 100%">
|
||||
<el-table-column prop="email" :label="TEXT.common.fields.email" min-width="200" />
|
||||
<el-table-column prop="full_name" :label="TEXT.common.fields.name" min-width="140" />
|
||||
<el-table-column prop="role" :label="TEXT.common.labels.role" width="120">
|
||||
@@ -54,7 +54,7 @@
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -124,12 +124,26 @@ onMounted(() => {
|
||||
.page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.main-content-flat {
|
||||
width: 100%;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.main-content-flat :deep(.el-card__body) {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.filter-form {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
gap: 12px;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
@@ -146,7 +160,10 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
.approval-table-section {
|
||||
padding-top: 12px;
|
||||
padding-bottom: 12px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.approval-table :deep(.el-table__inner-wrapper::before) {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="page">
|
||||
<el-card shadow="never" class="main-content-card unified-shell">
|
||||
<div class="main-content-flat unified-shell">
|
||||
<div class="audit-toolbar">
|
||||
<el-form :inline="true" :model="filters" class="filter-form">
|
||||
<el-form-item label="" class="filter-item-form">
|
||||
@@ -60,7 +60,7 @@
|
||||
</el-form>
|
||||
</div>
|
||||
<div class="unified-section table-section">
|
||||
<el-table :data="logs" v-loading="loading" style="width: 100%" stripe>
|
||||
<el-table :data="logs" v-loading="loading" class="audit-table" style="width: 100%" stripe>
|
||||
<el-table-column prop="timestamp" :label="TEXT.modules.adminAuditLogs.columns.time" width="180" align="center">
|
||||
<template #default="scope">
|
||||
<span class="text-gray-500">{{ displayDateTime(scope.row.timestamp) }}</span>
|
||||
@@ -115,7 +115,7 @@
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
<el-drawer
|
||||
v-model="detailVisible"
|
||||
@@ -425,21 +425,35 @@ onMounted(async () => {
|
||||
.page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.main-content-flat {
|
||||
width: 100%;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.main-content-flat :deep(.el-card__body) {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.table-section {
|
||||
padding-top: 12px;
|
||||
padding-bottom: 12px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.audit-toolbar {
|
||||
padding: 12px 16px;
|
||||
padding: 10px 16px;
|
||||
border-bottom: 1px solid var(--unified-shell-divider);
|
||||
}
|
||||
|
||||
.filter-form {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
gap: 10px;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
@@ -451,15 +465,15 @@ onMounted(async () => {
|
||||
}
|
||||
|
||||
.filter-select-comp {
|
||||
width: 140px;
|
||||
width: 132px;
|
||||
}
|
||||
|
||||
.filter-select-result {
|
||||
width: 100px;
|
||||
width: 96px;
|
||||
}
|
||||
|
||||
.date-range-picker-comp {
|
||||
width: 260px !important;
|
||||
width: 248px !important;
|
||||
}
|
||||
|
||||
.filter-spacer {
|
||||
@@ -509,9 +523,14 @@ onMounted(async () => {
|
||||
}
|
||||
|
||||
.pagination-wrap {
|
||||
margin-top: 14px;
|
||||
margin-top: 10px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
padding: 0 0 6px;
|
||||
}
|
||||
|
||||
.audit-table :deep(.el-table__inner-wrapper::before) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.drawer-header {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="ctms-page setup-page ctms-page-shell">
|
||||
<div class="ctms-page setup-page ctms-page-shell page--flush">
|
||||
<div class="setup-shell unified-shell">
|
||||
<div class="setup-header unified-action-bar">
|
||||
<div class="setup-flow">
|
||||
@@ -537,7 +537,7 @@
|
||||
<StateLoading v-else :rows="4" />
|
||||
</section>
|
||||
|
||||
<section v-show="activeStep === 1" class="setup-section">
|
||||
<section v-show="activeStep === 1" class="setup-section setup-section--table">
|
||||
<el-table :data="currentSetupDraft.projectMilestones" class="ctms-table setup-milestone-table">
|
||||
<el-table-column label="里程碑" min-width="180">
|
||||
<template #default="scope">
|
||||
@@ -668,7 +668,7 @@
|
||||
</el-table>
|
||||
</section>
|
||||
|
||||
<section v-show="activeStep === 2" class="setup-section enrollment-plan-section">
|
||||
<section v-show="activeStep === 2" class="setup-section setup-section--table enrollment-plan-section">
|
||||
<div class="enrollment-plan-toolbar">
|
||||
<div class="enrollment-inline-group">
|
||||
<span class="enrollment-inline-label required">计划入组日期</span>
|
||||
@@ -886,7 +886,7 @@
|
||||
</el-table>
|
||||
</section>
|
||||
|
||||
<section v-show="activeStep === 3" class="setup-section">
|
||||
<section v-show="activeStep === 3" class="setup-section setup-section--table">
|
||||
<el-table :data="currentSetupDraft.siteMilestones" class="ctms-table">
|
||||
<el-table-column label="里程碑" min-width="220">
|
||||
<template #default="scope">
|
||||
@@ -979,7 +979,7 @@
|
||||
</el-table>
|
||||
</section>
|
||||
|
||||
<section v-show="activeStep === 4" class="setup-section enrollment-plan-section">
|
||||
<section v-show="activeStep === 4" class="setup-section setup-section--table enrollment-plan-section">
|
||||
<div class="enrollment-plan-toolbar">
|
||||
<div class="site-plan-selector">
|
||||
<span class="enrollment-inline-label">中心</span>
|
||||
@@ -1226,7 +1226,7 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section v-show="activeStep === 5" class="setup-section">
|
||||
<section v-show="activeStep === 5" class="setup-section setup-section--table">
|
||||
<el-table :data="currentSetupDraft.monitoringStrategies" class="ctms-table">
|
||||
<el-table-column label="监查类型" min-width="180">
|
||||
<template #default="scope">
|
||||
@@ -1303,7 +1303,7 @@
|
||||
</el-table>
|
||||
</section>
|
||||
|
||||
<section v-show="activeStep === 6" class="setup-section">
|
||||
<section v-show="activeStep === 6" class="setup-section setup-section--table">
|
||||
<el-table :data="centerConfirmDisplayRows" class="ctms-table">
|
||||
<el-table-column label="中心" min-width="180">
|
||||
<template #default="scope">
|
||||
@@ -6045,11 +6045,10 @@ onBeforeUnmount(() => {
|
||||
}
|
||||
|
||||
.setup-shell {
|
||||
border: 1px solid #d8e2ef;
|
||||
border-radius: 16px;
|
||||
border: 0;
|
||||
background: #ffffff;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 6px 20px rgba(17, 42, 88, 0.05);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.setup-header {
|
||||
@@ -6977,6 +6976,12 @@ onBeforeUnmount(() => {
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.setup-section--table {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.enrollment-plan-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -7207,13 +7212,16 @@ onBeforeUnmount(() => {
|
||||
|
||||
.setup-content {
|
||||
position: relative;
|
||||
padding-left: 0 !important;
|
||||
padding-right: 0 !important;
|
||||
padding-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.setup-content-step-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 10px 12px;
|
||||
padding: 9px 12px;
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: #162f57;
|
||||
@@ -7473,6 +7481,12 @@ onBeforeUnmount(() => {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.setup-section--table .setup-section-header {
|
||||
margin-bottom: 0;
|
||||
padding-left: 12px;
|
||||
padding-right: 12px;
|
||||
}
|
||||
|
||||
.setup-content.setup-content-drawer .setup-section-header {
|
||||
padding-bottom: 0;
|
||||
margin-bottom: 0;
|
||||
@@ -7698,9 +7712,10 @@ onBeforeUnmount(() => {
|
||||
}
|
||||
|
||||
.setup-section :deep(.el-table th.el-table__cell) {
|
||||
background: #f8fafc !important;
|
||||
color: #64748b !important;
|
||||
font-weight: 500 !important;
|
||||
background: #f7f9fc !important;
|
||||
color: #34506f !important;
|
||||
font-weight: 600 !important;
|
||||
height: 40px;
|
||||
border-bottom: 1px solid #e2e8f0 !important;
|
||||
border-right: none !important;
|
||||
border-left: none !important;
|
||||
@@ -7711,6 +7726,8 @@ onBeforeUnmount(() => {
|
||||
border-right: none !important;
|
||||
border-left: none !important;
|
||||
background: transparent !important;
|
||||
padding-top: 7px;
|
||||
padding-bottom: 7px;
|
||||
}
|
||||
|
||||
/* 覆盖悬停状态颜色,保持极简高级 */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="page">
|
||||
<el-card shadow="never" class="main-content-card unified-shell">
|
||||
<div class="main-content-flat unified-shell">
|
||||
<div class="unified-action-bar actions-only-bar">
|
||||
<div class="filter-spacer"></div>
|
||||
<el-button type="primary" @click="openAdd">
|
||||
@@ -8,7 +8,7 @@
|
||||
</el-button>
|
||||
</div>
|
||||
<div class="unified-section member-table-section">
|
||||
<el-table :data="memberRows" v-loading="loading" stripe>
|
||||
<el-table :data="memberRows" v-loading="loading" stripe class="member-table">
|
||||
<el-table-column prop="full_name" :label="TEXT.modules.adminProjectMembers.username" min-width="160" />
|
||||
<el-table-column prop="role_in_study" :label="TEXT.modules.adminProjectMembers.projectRole" min-width="140">
|
||||
<template #default="scope">
|
||||
@@ -62,7 +62,7 @@
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
<el-dialog append-to=".layout-main .content-wrapper" :title="TEXT.modules.adminProjectMembers.newTitle" width="520px" v-model="addVisible" :close-on-click-modal="false">
|
||||
<el-form :model="newMember" label-width="120px" ref="addFormRef" :rules="addRules">
|
||||
@@ -301,6 +301,20 @@ onMounted(async () => {
|
||||
.page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.main-content-flat {
|
||||
width: 100%;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.main-content-flat :deep(.el-card__body) {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.actions-only-bar {
|
||||
@@ -310,8 +324,11 @@ onMounted(async () => {
|
||||
}
|
||||
|
||||
.member-table-section {
|
||||
padding-top: 12px;
|
||||
padding-bottom: 12px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.member-table :deep(.el-table__inner-wrapper::before) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.hint {
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
<template>
|
||||
<div class="page">
|
||||
<el-card shadow="never" class="main-content-card unified-shell">
|
||||
<div class="main-content-flat unified-shell">
|
||||
<div class="unified-action-bar actions-only-bar">
|
||||
<div class="filter-spacer"></div>
|
||||
<el-button type="primary" @click="openCreate">
|
||||
{{ TEXT.common.actions.add }}{{ TEXT.modules.adminProjects.projectLabel }}
|
||||
</el-button>
|
||||
</div>
|
||||
<div class="unified-section">
|
||||
<el-table :data="projects" v-loading="loading" stripe>
|
||||
<div class="unified-section project-table-section">
|
||||
<el-table :data="projects" v-loading="loading" stripe class="project-table">
|
||||
<el-table-column prop="name" :label="TEXT.common.fields.projectName" min-width="300">
|
||||
<template #default="scope">
|
||||
<el-link type="primary" @click="goDetail(scope.row)" class="font-medium">{{ scope.row.name }}</el-link>
|
||||
@@ -57,7 +57,7 @@
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
<ProjectForm v-model:visible="formVisible" :project="editingProject" @saved="loadProjects" />
|
||||
</div>
|
||||
</template>
|
||||
@@ -219,6 +219,20 @@ onMounted(() => {
|
||||
.page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.main-content-flat {
|
||||
width: 100%;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.main-content-flat :deep(.el-card__body) {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.actions-only-bar {
|
||||
@@ -227,9 +241,12 @@ onMounted(() => {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.unified-section {
|
||||
padding-top: 12px;
|
||||
padding-bottom: 12px;
|
||||
.project-table-section {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.project-table :deep(.el-table__inner-wrapper::before) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.action-btn {
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
<template>
|
||||
<div class="page">
|
||||
<el-card shadow="never" class="main-content-card unified-shell">
|
||||
<div class="page page--flush">
|
||||
<div class="main-content-flat unified-shell">
|
||||
<div class="unified-action-bar actions-only-bar">
|
||||
<div class="filter-spacer"></div>
|
||||
<el-button type="primary" @click="openCreate">
|
||||
{{ TEXT.common.actions.add }}{{ TEXT.modules.adminSites.siteLabel }}
|
||||
</el-button>
|
||||
</div>
|
||||
<div class="unified-section site-table-section">
|
||||
<el-table :data="displaySites" v-loading="loading" stripe :row-class-name="siteRowClass" style="width: 100%">
|
||||
<div class="unified-section site-table-section section--flush-x section--flush-top section--flush-bottom">
|
||||
<el-table :data="displaySites" v-loading="loading" stripe :row-class-name="siteRowClass" style="width: 100%" class="site-table">
|
||||
<el-table-column prop="name" :label="TEXT.common.fields.siteName" min-width="220">
|
||||
<template #default="scope">
|
||||
<div class="site-name-cell">
|
||||
@@ -61,7 +61,7 @@
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
<SiteForm
|
||||
v-if="projectId"
|
||||
v-model:visible="formVisible"
|
||||
@@ -278,9 +278,8 @@ onMounted(async () => {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.site-table-section {
|
||||
padding-top: 12px;
|
||||
padding-bottom: 12px;
|
||||
.site-table :deep(.el-table__inner-wrapper::before) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.site-name-cell {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="page">
|
||||
<el-card shadow="never" class="main-content-card unified-shell">
|
||||
<div class="main-content-flat unified-shell">
|
||||
<div class="filter-container unified-action-bar">
|
||||
<div class="filter-form">
|
||||
<el-form-item label="" class="filter-item-form">
|
||||
@@ -28,7 +28,7 @@
|
||||
</div>
|
||||
|
||||
<div class="unified-section user-table-section">
|
||||
<el-table :data="users" stripe v-loading="loading" style="width: 100%">
|
||||
<el-table :data="users" stripe v-loading="loading" class="user-table" style="width: 100%">
|
||||
<el-table-column prop="email" :label="TEXT.common.fields.email" min-width="200" />
|
||||
<el-table-column prop="full_name" :label="TEXT.common.fields.name" min-width="140" />
|
||||
<el-table-column prop="department" :label="TEXT.common.fields.department" min-width="140" />
|
||||
@@ -84,7 +84,7 @@
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
<UserForm v-model:visible="formVisible" :user="editingUser" :admin-count="activeAdminCount" @saved="loadUsers" />
|
||||
<UserResetPassword v-model:visible="resetVisible" :user="resetUser" @reset="loadUsers" />
|
||||
</div>
|
||||
@@ -291,12 +291,26 @@ onMounted(() => {
|
||||
.page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.main-content-flat {
|
||||
width: 100%;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.main-content-flat :deep(.el-card__body) {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.filter-form {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
gap: 12px;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
@@ -306,7 +320,7 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
.filter-input-comp {
|
||||
width: 200px;
|
||||
width: 190px;
|
||||
}
|
||||
|
||||
.filter-spacer {
|
||||
@@ -314,13 +328,31 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
.user-table-section {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.user-table {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.user-table :deep(.el-table__inner-wrapper::before) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.user-table :deep(th.el-table__cell) {
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.user-table :deep(td.el-table__cell) {
|
||||
padding-top: 12px;
|
||||
padding-bottom: 12px;
|
||||
}
|
||||
|
||||
.pagination-wrap {
|
||||
margin-top: 14px;
|
||||
margin-top: 10px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
padding: 0 0 6px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="page">
|
||||
<div class="page ctms-page-shell page--flush">
|
||||
<div class="unified-shell">
|
||||
<section class="unified-section" v-loading="loading">
|
||||
<section class="unified-section section--flush-x" v-loading="loading">
|
||||
<div class="unified-section-header">
|
||||
<div>
|
||||
<div class="ctms-section-title">
|
||||
@@ -37,7 +37,7 @@
|
||||
</el-descriptions>
|
||||
</section>
|
||||
|
||||
<section class="unified-section">
|
||||
<section class="unified-section section--flush-x section--flush-bottom">
|
||||
<el-tabs v-model="activeTab" @tab-change="handleTabChange" class="ctms-tabs">
|
||||
<el-tab-pane :label="TEXT.modules.fileVersionManagement.tabs.versions" name="versions">
|
||||
<div class="ctms-section-header">
|
||||
@@ -49,7 +49,7 @@
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<el-card class="ctms-table-card unified-shell">
|
||||
<div class="ctms-table-panel">
|
||||
<el-table :data="detail.version_timeline" v-loading="versionLoading" class="ctms-table">
|
||||
<el-table-column prop="version_no" :label="TEXT.modules.fileVersionManagement.fields.versionNo" width="120">
|
||||
<template #default="{ row }">
|
||||
@@ -94,7 +94,7 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane :label="TEXT.modules.fileVersionManagement.tabs.distributions" name="distributions">
|
||||
@@ -107,7 +107,7 @@
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<el-card class="ctms-table-card unified-shell">
|
||||
<div class="ctms-table-panel">
|
||||
<el-table :data="distributions" v-loading="distributionLoading" class="ctms-table">
|
||||
<el-table-column :label="TEXT.modules.fileVersionManagement.fields.targetType" width="120">
|
||||
<template #default="{ row }">
|
||||
@@ -125,7 +125,7 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
|
||||
</el-tabs>
|
||||
@@ -680,6 +680,18 @@ watch(
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.ctms-table-panel {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.ctms-section-header {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.ctms-table-panel :deep(.el-table__inner-wrapper::before) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.doc-meta-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="page">
|
||||
<el-card shadow="never" class="main-content-card unified-shell">
|
||||
<div class="filter-container unified-action-bar">
|
||||
<div class="page ctms-page-shell page--flush">
|
||||
<div class="main-content-flat unified-shell">
|
||||
<div class="filter-container unified-action-bar bar--flush">
|
||||
<el-form :inline="true" :model="filters" class="filter-form">
|
||||
<el-form-item label="" class="filter-item-form">
|
||||
<el-select v-model="filters.scope_type" :placeholder="TEXT.modules.fileVersionManagement.filters.scope" clearable class="filter-select-comp">
|
||||
@@ -28,7 +28,7 @@
|
||||
</el-button>
|
||||
</el-form>
|
||||
</div>
|
||||
<section class="unified-section">
|
||||
<section class="unified-section document-table-section section--flush-x section--flush-top section--flush-bottom">
|
||||
<el-table
|
||||
:data="sortedItems"
|
||||
v-loading="loading"
|
||||
@@ -84,7 +84,7 @@
|
||||
</template>
|
||||
</el-table>
|
||||
</section>
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
<el-dialog append-to=".layout-main .content-wrapper" v-model="createVisible" :title="TEXT.modules.fileVersionManagement.dialog.createTitle" width="520px" destroy-on-close class="ctms-dialog">
|
||||
<el-form ref="createFormRef" :model="createForm" :rules="createRules" label-width="100px" class="ctms-form">
|
||||
@@ -346,18 +346,10 @@ watch(
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.main-content-card :deep(.el-card__body) {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.filter-container {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.filter-form {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
gap: 12px;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
@@ -370,6 +362,10 @@ watch(
|
||||
width: 132px;
|
||||
}
|
||||
|
||||
.ctms-table :deep(.el-table__inner-wrapper::before) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.filter-spacer {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
<el-descriptions-item :label="TEXT.common.fields.remark" :span="2">{{ detail.remark || TEXT.common.fallback }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</section>
|
||||
<section class="unified-section">
|
||||
<section class="unified-section attachment-section">
|
||||
<AttachmentList
|
||||
v-if="shipmentId"
|
||||
:study-id="studyId"
|
||||
@@ -109,6 +109,10 @@ onMounted(load);
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.attachment-section {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.section-title-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
@@ -251,6 +251,10 @@ onMounted(async () => {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.section-card :deep(.el-card__body) {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@
|
||||
</el-row>
|
||||
</el-card>
|
||||
|
||||
<el-card class="form-card section-margin unified-shell" shadow="never">
|
||||
<el-card class="form-card section-margin attachment-card unified-shell" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header actions-header">
|
||||
<span class="header-title">{{ TEXT.modules.feeContracts.paymentTitle }}</span>
|
||||
@@ -517,6 +517,10 @@ onMounted(async () => {
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
.attachment-card :deep(.el-card__body) {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="page ctms-page-shell">
|
||||
<div class="page ctms-page-shell page--flush">
|
||||
<div class="overview">
|
||||
<el-row :gutter="20">
|
||||
<el-col :xs="24" :sm="12" :md="6">
|
||||
@@ -53,7 +53,7 @@
|
||||
|
||||
<StateLoading v-else-if="loading" :rows="6" />
|
||||
|
||||
<el-card shadow="never" class="main-content-card unified-shell" v-else>
|
||||
<div class="main-content-flat unified-shell" v-else>
|
||||
<div class="filter-container unified-action-bar">
|
||||
<el-form :inline="true" :model="filters" class="filter-form">
|
||||
<el-form-item label="" class="filter-item">
|
||||
@@ -86,13 +86,13 @@
|
||||
</el-button>
|
||||
</el-form>
|
||||
</div>
|
||||
<section class="unified-section">
|
||||
<section class="unified-section contract-table-section section--flush-x section--flush-top section--flush-bottom">
|
||||
<el-table
|
||||
:data="sortedContracts"
|
||||
style="width: 100%"
|
||||
@row-click="onRowClick"
|
||||
:row-class-name="contractRowClass"
|
||||
:header-cell-style="{ background: '#f8f9fb' }"
|
||||
class="contract-table"
|
||||
>
|
||||
<el-table-column prop="center_name" :label="TEXT.common.fields.site" min-width="160">
|
||||
<template #default="scope">
|
||||
@@ -167,7 +167,7 @@
|
||||
</el-table>
|
||||
<StateEmpty v-if="sortedContracts.length === 0" :description="TEXT.modules.feeContracts.empty" />
|
||||
</section>
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -350,18 +350,14 @@ onMounted(async () => {
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.main-content-card :deep(.el-card__body) {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.filter-container {
|
||||
margin-bottom: 0;
|
||||
.overview {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.filter-form {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
gap: 12px;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
@@ -383,10 +379,8 @@ onMounted(async () => {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.table-card {
|
||||
border-radius: 12px;
|
||||
border: 1px solid var(--ctms-border-color);
|
||||
overflow: hidden;
|
||||
.contract-table :deep(.el-table__inner-wrapper::before) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.site-cell {
|
||||
|
||||
@@ -233,6 +233,10 @@ onMounted(async () => {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.section-card :deep(.el-card__body) {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
</el-row>
|
||||
</el-card>
|
||||
|
||||
<el-card class="form-card section-margin unified-shell" shadow="never">
|
||||
<el-card class="form-card section-margin attachment-card unified-shell" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="header-title">{{ TEXT.common.fields.status }}</span>
|
||||
@@ -394,6 +394,10 @@ onMounted(async () => {
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
.attachment-card :deep(.el-card__body) {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="page ctms-page-shell">
|
||||
<div class="page ctms-page-shell page--flush">
|
||||
<div class="overview">
|
||||
<el-row :gutter="20">
|
||||
<el-col :xs="24" :sm="12" :md="6">
|
||||
@@ -52,7 +52,7 @@
|
||||
|
||||
<StateLoading v-else-if="loading" :rows="6" />
|
||||
|
||||
<el-card shadow="never" class="main-content-card unified-shell" v-else>
|
||||
<div class="main-content-flat unified-shell" v-else>
|
||||
<div class="filter-container unified-action-bar">
|
||||
<el-form :inline="true" :model="filters" class="filter-form">
|
||||
<el-form-item label="" class="filter-item">
|
||||
@@ -97,13 +97,13 @@
|
||||
</el-button>
|
||||
</el-form>
|
||||
</div>
|
||||
<section class="unified-section">
|
||||
<section class="unified-section special-expense-table-section section--flush-x section--flush-top section--flush-bottom">
|
||||
<el-table
|
||||
:data="sortedExpenses"
|
||||
style="width: 100%"
|
||||
@row-click="onRowClick"
|
||||
:header-cell-style="{ background: '#f8f9fb' }"
|
||||
:row-class-name="expenseRowClass"
|
||||
class="special-expense-table"
|
||||
>
|
||||
<el-table-column :label="TEXT.common.fields.occurDate" width="140">
|
||||
<template #default="scope">
|
||||
@@ -166,7 +166,7 @@
|
||||
</el-table>
|
||||
<StateEmpty v-if="sortedExpenses.length === 0" :description="TEXT.modules.feeSpecials.empty" />
|
||||
</section>
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -355,18 +355,14 @@ onMounted(async () => {
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.main-content-card :deep(.el-card__body) {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.filter-container {
|
||||
margin-bottom: 0;
|
||||
.overview {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.filter-form {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
gap: 12px;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
@@ -391,10 +387,8 @@ onMounted(async () => {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.table-card {
|
||||
border-radius: 12px;
|
||||
border: 1px solid var(--ctms-border-color);
|
||||
overflow: hidden;
|
||||
.special-expense-table :deep(.el-table__inner-wrapper::before) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.date-text {
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
<el-descriptions-item :label="TEXT.common.fields.remark" :span="2">{{ detail.remark || TEXT.common.fallback }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</section>
|
||||
<section class="unified-section">
|
||||
<section class="unified-section attachment-section">
|
||||
<AttachmentList
|
||||
v-if="contractId"
|
||||
:study-id="studyId"
|
||||
@@ -113,4 +113,8 @@ onMounted(async () => {
|
||||
flex-direction: column;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.attachment-section {
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<el-descriptions-item :label="TEXT.common.fields.remark" :span="2">{{ detail.remark || TEXT.common.fallback }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</section>
|
||||
<section class="unified-section">
|
||||
<section class="unified-section attachment-section">
|
||||
<AttachmentList
|
||||
v-if="specialId"
|
||||
:study-id="studyId"
|
||||
@@ -112,4 +112,8 @@ onMounted(async () => {
|
||||
flex-direction: column;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.attachment-section {
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="page">
|
||||
<div class="page page--flush">
|
||||
|
||||
<el-card shadow="never" class="main-content-card unified-shell">
|
||||
<div class="main-content-flat unified-shell">
|
||||
<div class="filter-container unified-action-bar">
|
||||
<el-form :inline="true" :model="filters" class="filter-form">
|
||||
<el-form-item label="" class="filter-item">
|
||||
@@ -48,11 +48,12 @@
|
||||
</el-button>
|
||||
</el-form>
|
||||
</div>
|
||||
<div class="unified-section table-section">
|
||||
<div class="unified-section table-section section--flush-x section--flush-top section--flush-bottom">
|
||||
<el-table
|
||||
:data="sortedItems"
|
||||
v-loading="loading"
|
||||
style="width: 100%"
|
||||
class="shipment-table"
|
||||
:row-class-name="shipmentRowClass"
|
||||
@row-click="onRowClick"
|
||||
>
|
||||
@@ -104,7 +105,7 @@
|
||||
</el-table>
|
||||
<StateEmpty v-if="!loading && sortedItems.length === 0" :description="TEXT.modules.drugShipments.empty" />
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -252,7 +253,7 @@ onMounted(async () => {
|
||||
.filter-form {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
gap: 12px;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
@@ -271,10 +272,10 @@ onMounted(async () => {
|
||||
}
|
||||
|
||||
.filter-actions :deep(.el-button) {
|
||||
height: 36px;
|
||||
line-height: 36px;
|
||||
padding: 0 18px;
|
||||
border-radius: 8px;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
padding: 0 12px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.filter-select {
|
||||
@@ -285,9 +286,8 @@ onMounted(async () => {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.table-section {
|
||||
padding-top: 12px;
|
||||
padding-bottom: 12px;
|
||||
.shipment-table :deep(.el-table__inner-wrapper::before) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.type-tag {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<div class="redirecting ctms-page-shell">
|
||||
<section class="unified-action-bar">
|
||||
<div class="redirecting ctms-page-shell page--flush">
|
||||
<section class="unified-action-bar bar--flush">
|
||||
<div class="redirecting-title">{{ TEXT.menu.fileVersionManagement }}</div>
|
||||
</section>
|
||||
<section class="unified-shell">
|
||||
<section class="unified-section">
|
||||
<section class="unified-section section--flush">
|
||||
<el-empty :description="`${TEXT.common.loading}...`" />
|
||||
</section>
|
||||
</section>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="page">
|
||||
<el-card shadow="never" class="main-content-card unified-shell">
|
||||
<div class="main-content-flat unified-shell">
|
||||
<div class="filter-container unified-action-bar">
|
||||
<el-form :inline="true" :model="filters" class="filter-form">
|
||||
<el-form-item label="" class="filter-item-form">
|
||||
@@ -70,7 +70,7 @@
|
||||
</el-table>
|
||||
<StateEmpty v-if="!loading && sortedItems.length === 0" :description="TEXT.modules.financeContracts.empty" />
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -185,10 +185,18 @@ onMounted(async () => {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.main-content-flat {
|
||||
background: transparent;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.filter-form {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
gap: 12px;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
@@ -206,8 +214,12 @@ onMounted(async () => {
|
||||
}
|
||||
|
||||
.table-section {
|
||||
padding-top: 12px;
|
||||
padding-bottom: 12px;
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.ctms-table :deep(.el-table__inner-wrapper::before) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="page">
|
||||
<el-card shadow="never" class="main-content-card unified-shell">
|
||||
<div class="main-content-flat unified-shell">
|
||||
<div class="filter-container unified-action-bar">
|
||||
<el-form :inline="true" :model="filters" class="filter-form">
|
||||
<el-form-item label="" class="filter-item-form">
|
||||
@@ -80,7 +80,7 @@
|
||||
</el-table>
|
||||
<StateEmpty v-if="!loading && sortedItems.length === 0" :description="TEXT.modules.financeSpecials.empty" />
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -194,10 +194,18 @@ onMounted(async () => {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.main-content-flat {
|
||||
background: transparent;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.filter-form {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
gap: 12px;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
@@ -219,8 +227,12 @@ onMounted(async () => {
|
||||
}
|
||||
|
||||
.table-section {
|
||||
padding-top: 12px;
|
||||
padding-bottom: 12px;
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
:deep(.ctms-table .el-table__inner-wrapper::before) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<div class="page">
|
||||
<div class="page ctms-page-shell page--flush">
|
||||
|
||||
<el-card shadow="never" class="main-content-card unified-shell">
|
||||
<div class="filter-container unified-action-bar">
|
||||
<div class="main-content-flat unified-shell">
|
||||
<div class="filter-container unified-action-bar bar--flush">
|
||||
<el-form :inline="true" :model="filters" class="filter-form">
|
||||
<el-form-item label="" class="filter-item-form">
|
||||
<el-input
|
||||
@@ -29,7 +29,7 @@
|
||||
</el-button>
|
||||
</el-form>
|
||||
</div>
|
||||
<div class="unified-section table-section">
|
||||
<div class="unified-section table-section section--flush-x section--flush-top section--flush-bottom">
|
||||
<el-table
|
||||
:data="sortedItems"
|
||||
v-loading="loading"
|
||||
@@ -60,7 +60,7 @@
|
||||
</el-table>
|
||||
<StateEmpty v-if="!loading && sortedItems.length === 0" :description="TEXT.modules.knowledgeNotes.empty" />
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -178,7 +178,7 @@ onMounted(async () => {
|
||||
.filter-form {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
gap: 12px;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
@@ -195,9 +195,8 @@ onMounted(async () => {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.table-section {
|
||||
padding-top: 12px;
|
||||
padding-bottom: 12px;
|
||||
:deep(.ctms-table .el-table__inner-wrapper::before) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="page">
|
||||
<div class="page page--flush">
|
||||
<div v-if="study.currentStudy" class="unified-shell">
|
||||
<section class="unified-section equipment-section">
|
||||
<section class="unified-section section--flush">
|
||||
<div class="filter-row">
|
||||
<el-form :inline="true" :model="filters">
|
||||
<el-form-item label="设备名称">
|
||||
@@ -15,7 +15,7 @@
|
||||
<el-button type="primary" @click="openCreate">新建</el-button>
|
||||
</div>
|
||||
|
||||
<el-table v-loading="loading" :data="rows" class="ctms-table" style="width: 100%" table-layout="fixed">
|
||||
<el-table v-loading="loading" :data="rows" class="ctms-table equipment-table" style="width: 100%" table-layout="fixed">
|
||||
<el-table-column prop="name" label="设备名称" />
|
||||
<el-table-column prop="specModel" label="规格型号" />
|
||||
<el-table-column prop="unit" label="单位" />
|
||||
@@ -391,11 +391,6 @@ watch(
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.equipment-section {
|
||||
padding-top: 14px;
|
||||
padding-bottom: 12px;
|
||||
}
|
||||
|
||||
.filter-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -593,9 +588,13 @@ watch(
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
|
||||
.equipment-table :deep(.el-table__inner-wrapper::before) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* ========== 表格居中 ========== */
|
||||
:deep(.ctms-table th.el-table__cell .cell),
|
||||
:deep(.ctms-table td.el-table__cell .cell) {
|
||||
.equipment-table :deep(th.el-table__cell .cell),
|
||||
.equipment-table :deep(td.el-table__cell .cell) {
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="page ctms-page-shell">
|
||||
<div class="page ctms-page-shell page--flush">
|
||||
<div v-if="study.currentStudy" class="unified-shell ctms-table-card">
|
||||
<section class="unified-action-bar">
|
||||
<section class="unified-action-bar bar--flush">
|
||||
<div class="card-header ctms-page-header-row">
|
||||
<div>
|
||||
<div class="card-title">{{ TEXT.modules.projectMilestones.listTitle }}</div>
|
||||
@@ -22,7 +22,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="unified-section ctms-page-content-grid">
|
||||
<section class="unified-section ctms-page-content-grid section--flush-x section--flush-top section--flush-bottom">
|
||||
<el-table :data="rows" v-loading="loading" class="ctms-table" style="width: 100%">
|
||||
<el-table-column prop="name" :label="TEXT.modules.projectMilestones.columns.name" min-width="140" />
|
||||
<el-table-column prop="planDate" :label="TEXT.modules.projectMilestones.columns.planDate" min-width="170">
|
||||
@@ -450,12 +450,16 @@ watch(
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.ctms-page-content-grid {
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
margin-bottom: 12px;
|
||||
margin-bottom: 0;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
@@ -657,12 +661,7 @@ watch(
|
||||
background: #94a3b8;
|
||||
}
|
||||
|
||||
:deep(.ctms-table th.el-table__cell .cell),
|
||||
:deep(.ctms-table td.el-table__cell .cell) {
|
||||
font-size: 11px;
|
||||
padding-top: 4px;
|
||||
padding-bottom: 4px;
|
||||
padding-left: 6px;
|
||||
padding-right: 6px;
|
||||
.ctms-table :deep(.el-table__inner-wrapper::before) {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,21 +1,7 @@
|
||||
<template>
|
||||
<div class="page ctms-page-shell">
|
||||
<div class="page ctms-page-shell page--flush">
|
||||
<div v-if="study.currentStudy" class="page-body">
|
||||
<div class="unified-shell ctms-table-card">
|
||||
<section class="unified-section">
|
||||
<div class="kpi-grid">
|
||||
<KpiCard
|
||||
v-for="item in kpiItems"
|
||||
:key="item.key"
|
||||
class="kpi"
|
||||
:title="item.title"
|
||||
:value="item.value"
|
||||
:subtext="item.subtext"
|
||||
:type="item.type"
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="unified-section">
|
||||
<div class="overview-meta-inline">
|
||||
<el-tag v-if="usingDemo" effect="plain" type="info" class="demo-tag">示例数据</el-tag>
|
||||
@@ -83,7 +69,6 @@ import { fetchProjectOverview } from "../../api/overview";
|
||||
import { fetchSites } from "../../api/sites";
|
||||
import StateEmpty from "../../components/StateEmpty.vue";
|
||||
import StateLoading from "../../components/StateLoading.vue";
|
||||
import KpiCard from "../../components/KpiCard.vue";
|
||||
import CenterProgressRow from "./project-overview/CenterProgressRow.vue";
|
||||
import EnrollmentBarChart, { type EnrollmentBarItem } from "./project-overview/EnrollmentBarChart.vue";
|
||||
import { adaptProjectOverview, type CenterOverview, type ProjectOverviewViewModel } from "./project-overview/overview.adapter";
|
||||
@@ -99,35 +84,6 @@ const updatedAtLabel = ref(displayDateTime(new Date()));
|
||||
const preferApi = String(import.meta.env.VITE_USE_OVERVIEW_API || "").toLowerCase() === "true";
|
||||
|
||||
const centers = computed(() => overview.value?.centers || []);
|
||||
const kpiItems = computed(() => {
|
||||
const summary = overview.value?.summary;
|
||||
const totalTarget = summary?.total_target ?? 0;
|
||||
const totalActual = summary?.total_actual ?? 0;
|
||||
const activeCenters = centers.value.filter((item) => item.is_active !== false).length;
|
||||
return [
|
||||
{
|
||||
key: "target",
|
||||
title: "总入组目标",
|
||||
value: totalTarget,
|
||||
subtext: "项目整体计划",
|
||||
type: "primary" as const,
|
||||
},
|
||||
{
|
||||
key: "actual",
|
||||
title: "当前入组",
|
||||
value: totalActual,
|
||||
subtext: `达成率 ${totalTarget > 0 ? Math.round((totalActual / totalTarget) * 100) : 0}%`,
|
||||
type: "success" as const,
|
||||
},
|
||||
{
|
||||
key: "centers",
|
||||
title: "活跃中心",
|
||||
value: activeCenters,
|
||||
subtext: `中心总数 ${centers.value.length}`,
|
||||
type: "info" as const,
|
||||
},
|
||||
];
|
||||
});
|
||||
|
||||
const buildFallbackCentersFromSites = (siteList: any[]): CenterOverview[] =>
|
||||
siteList.map((site: any) => ({
|
||||
@@ -252,12 +208,6 @@ watch(
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.kpi-grid {
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
||||
}
|
||||
|
||||
.demo-tag {
|
||||
border-color: var(--ctms-border-color);
|
||||
color: var(--ctms-text-secondary);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<div class="page ctms-page-shell">
|
||||
<div class="page ctms-page-shell page--flush">
|
||||
<template v-if="study.currentStudy">
|
||||
<el-card shadow="never" class="main-content-card unified-shell ctms-table-card">
|
||||
<div class="filter-container unified-action-bar">
|
||||
<div class="main-content-flat unified-shell">
|
||||
<div class="filter-container unified-action-bar bar--flush">
|
||||
<div class="filter-left">
|
||||
<el-form :inline="true" :model="filters" class="filter-form">
|
||||
<el-form-item label="问题分类" class="filter-item">
|
||||
@@ -47,7 +47,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="unified-section table-section">
|
||||
<div class="unified-section table-section section--flush">
|
||||
<el-table
|
||||
class="issue-table"
|
||||
:data="tableRows"
|
||||
@@ -113,7 +113,7 @@
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
<el-drawer
|
||||
v-model="formDialogVisible"
|
||||
@@ -723,7 +723,6 @@ watch(
|
||||
justify-content: space-between;
|
||||
gap: 16px;
|
||||
flex-wrap: wrap;
|
||||
padding: 16px 16px 0;
|
||||
}
|
||||
|
||||
.filter-left {
|
||||
@@ -734,7 +733,7 @@ watch(
|
||||
.filter-form {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
gap: 12px;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
@@ -764,10 +763,6 @@ watch(
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.table-section {
|
||||
padding: 12px 0;
|
||||
}
|
||||
|
||||
.issue-no {
|
||||
font-weight: 600;
|
||||
color: #24324a;
|
||||
@@ -823,11 +818,15 @@ watch(
|
||||
}
|
||||
|
||||
.pagination-wrap {
|
||||
margin: 14px 16px 0;
|
||||
margin: 10px 0 0;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.issue-table :deep(.el-table__inner-wrapper::before) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.dialog-select {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="page ctms-page-shell">
|
||||
<el-card shadow="never" class="main-content-card unified-shell ctms-table-card">
|
||||
<div class="filter-container unified-action-bar">
|
||||
<div class="page ctms-page-shell page--flush">
|
||||
<div class="main-content-flat unified-shell">
|
||||
<div class="filter-container unified-action-bar bar--flush">
|
||||
<el-form :inline="true" class="filter-form">
|
||||
<el-form-item class="filter-item-form">
|
||||
<el-input v-model="filters.keyword" :placeholder="TEXT.common.fields.keyword" clearable class="filter-input-comp">
|
||||
@@ -33,8 +33,8 @@
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<div class="unified-section table-section">
|
||||
<el-table :data="filteredItems" v-loading="loading" style="width: 100%" table-layout="fixed">
|
||||
<div class="unified-section table-section section--flush-x section--flush-top section--flush-bottom">
|
||||
<el-table :data="filteredItems" v-loading="loading" style="width: 100%" table-layout="fixed" class="risk-table">
|
||||
<el-table-column prop="pd_no" :label="TEXT.common.fields.pdNo" min-width="160" show-overflow-tooltip />
|
||||
<el-table-column prop="subject_no" :label="TEXT.modules.subjectManagement.screeningNo" min-width="160" show-overflow-tooltip />
|
||||
<el-table-column :label="TEXT.common.fields.site" min-width="160" show-overflow-tooltip>
|
||||
@@ -54,7 +54,7 @@
|
||||
</el-table>
|
||||
<StateEmpty v-if="!loading && filteredItems.length === 0" :description="TEXT.modules.riskIssuePd.emptyDescription" />
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -162,21 +162,16 @@ onMounted(load);
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.table-section {
|
||||
padding-top: 12px;
|
||||
padding-bottom: 12px;
|
||||
}
|
||||
|
||||
.filter-form {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
flex-wrap: wrap;
|
||||
gap: 0;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.filter-item-form {
|
||||
margin-bottom: 0;
|
||||
margin-right: 12px;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.filter-input-comp {
|
||||
@@ -191,4 +186,8 @@ onMounted(load);
|
||||
margin-bottom: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.risk-table :deep(.el-table__inner-wrapper::before) {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="page ctms-page-shell">
|
||||
<el-card shadow="never" class="main-content-card unified-shell ctms-table-card">
|
||||
<div class="filter-container unified-action-bar">
|
||||
<div class="page ctms-page-shell page--flush">
|
||||
<div class="main-content-flat unified-shell">
|
||||
<div class="filter-container unified-action-bar bar--flush">
|
||||
<el-form :inline="true" class="filter-form">
|
||||
<el-form-item class="filter-item-form">
|
||||
<el-input v-model="filters.keyword" :placeholder="TEXT.common.fields.keyword" clearable class="filter-input-comp">
|
||||
@@ -51,8 +51,8 @@
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<div class="unified-section table-section">
|
||||
<el-table :data="filteredItems" v-loading="loading" style="width: 100%">
|
||||
<div class="unified-section table-section section--flush-x section--flush-top section--flush-bottom">
|
||||
<el-table :data="filteredItems" v-loading="loading" style="width: 100%" class="risk-table">
|
||||
<el-table-column prop="onset_date" :label="TEXT.common.fields.occurDate" width="140">
|
||||
<template #default="scope">{{ displayDate(scope.row.onset_date) }}</template>
|
||||
</el-table-column>
|
||||
@@ -82,7 +82,7 @@
|
||||
</el-table>
|
||||
<StateEmpty v-if="!loading && filteredItems.length === 0" :description="TEXT.modules.riskIssueSae.emptyDescription" />
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -219,21 +219,16 @@ onMounted(load);
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.table-section {
|
||||
padding-top: 12px;
|
||||
padding-bottom: 12px;
|
||||
}
|
||||
|
||||
.filter-form {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
flex-wrap: wrap;
|
||||
gap: 0;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.filter-item-form {
|
||||
margin-bottom: 0;
|
||||
margin-right: 12px;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.filter-input-comp {
|
||||
@@ -248,4 +243,8 @@ onMounted(load);
|
||||
margin-bottom: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.risk-table :deep(.el-table__inner-wrapper::before) {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<div class="page">
|
||||
<el-card shadow="never" class="main-content-card unified-shell">
|
||||
<div class="page ctms-page-shell page--flush">
|
||||
<div class="main-content-flat unified-shell">
|
||||
<el-tabs v-model="activeTab" class="ctms-tabs">
|
||||
<el-tab-pane :label="TEXT.modules.startupFeasibilityEthics.feasibilityTab" name="feasibility">
|
||||
<div class="ctms-tab-content">
|
||||
<div class="ctms-tab-content unified-section section--flush">
|
||||
<div class="ctms-section-header">
|
||||
<div class="ctms-section-title">{{ TEXT.modules.startupFeasibilityEthics.feasibilityTab }}</div>
|
||||
<div class="ctms-section-actions">
|
||||
@@ -63,7 +63,7 @@
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="TEXT.modules.startupFeasibilityEthics.ethicsTab" name="ethics">
|
||||
<div class="ctms-tab-content">
|
||||
<div class="ctms-tab-content unified-section section--flush">
|
||||
<div class="ctms-section-header">
|
||||
<div class="ctms-section-title">{{ TEXT.modules.startupFeasibilityEthics.ethicsTab }}</div>
|
||||
<div class="ctms-section-actions">
|
||||
@@ -126,7 +126,7 @@
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -312,7 +312,15 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
.ctms-tab-content {
|
||||
padding: 12px;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.ctms-tab-content .ctms-section-header {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.ctms-table :deep(.el-table__inner-wrapper::before) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<template>
|
||||
<div class="page">
|
||||
<div class="page ctms-page-shell page--flush">
|
||||
<div class="unified-shell">
|
||||
<section class="unified-section">
|
||||
<section class="unified-section kickoff-table-section section--flush">
|
||||
<el-table
|
||||
:data="kickoffRows"
|
||||
v-loading="loading"
|
||||
style="width: 100%"
|
||||
class="ctms-table"
|
||||
class="ctms-table kickoff-table"
|
||||
:row-class-name="kickoffRowClass"
|
||||
@row-click="onKickoffRowClick"
|
||||
>
|
||||
@@ -166,6 +166,10 @@ onMounted(() => {
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.kickoff-table :deep(.el-table__inner-wrapper::before) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<style>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="page ctms-page-shell">
|
||||
<el-card shadow="never" class="main-content-card unified-shell ctms-table-card">
|
||||
<div class="filter-container unified-action-bar">
|
||||
<div class="page ctms-page-shell page--flush">
|
||||
<div class="main-content-flat unified-shell">
|
||||
<div class="filter-container unified-action-bar bar--flush">
|
||||
<el-form :inline="true" :model="filters" class="filter-form">
|
||||
<el-form-item label="" class="filter-item-form">
|
||||
<el-input
|
||||
@@ -54,7 +54,7 @@
|
||||
</el-button>
|
||||
</el-form>
|
||||
</div>
|
||||
<div class="unified-section table-section">
|
||||
<div class="unified-section table-section section--flush-x section--flush-top section--flush-bottom">
|
||||
<el-table
|
||||
:data="pagedItems"
|
||||
v-loading="loading"
|
||||
@@ -118,7 +118,7 @@
|
||||
</div>
|
||||
<StateEmpty v-if="!loading && sortedItems.length === 0" :description="TEXT.modules.subjectManagement.empty" />
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -281,7 +281,7 @@ onMounted(async () => {
|
||||
.filter-form {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
gap: 12px;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
@@ -300,9 +300,13 @@ onMounted(async () => {
|
||||
}
|
||||
|
||||
.header-action-btn {
|
||||
height: 36px;
|
||||
padding: 0 20px;
|
||||
border-radius: 8px;
|
||||
height: 32px;
|
||||
padding: 0 12px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
:deep(.ctms-table .el-table__inner-wrapper::before) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.subject-info-cell {
|
||||
@@ -358,7 +362,7 @@ onMounted(async () => {
|
||||
.pagination-wrap {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-top: 14px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</section>
|
||||
<section class="unified-section">
|
||||
<section class="unified-section attachment-section">
|
||||
<AttachmentList
|
||||
v-if="recordId"
|
||||
:study-id="studyId"
|
||||
@@ -156,6 +156,18 @@ onMounted(() => {
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.attachment-section {
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style scoped>
|
||||
.page {
|
||||
display: flex;
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</section>
|
||||
<section class="unified-section">
|
||||
<section class="unified-section attachment-section">
|
||||
<AttachmentList
|
||||
v-if="recordId"
|
||||
:study-id="studyId"
|
||||
@@ -154,6 +154,18 @@ onMounted(() => {
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.attachment-section {
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style scoped>
|
||||
.page {
|
||||
display: flex;
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
</el-descriptions>
|
||||
</section>
|
||||
|
||||
<section class="unified-section">
|
||||
<section class="unified-section training-section">
|
||||
<div class="training-header">
|
||||
<div class="training-title">{{ TEXT.modules.startupMeetingAuth.trainingTab }}</div>
|
||||
</div>
|
||||
@@ -126,7 +126,7 @@
|
||||
/>
|
||||
</section>
|
||||
|
||||
<section v-if="meetingId" class="unified-section">
|
||||
<section v-if="meetingId" class="unified-section attachment-section">
|
||||
<div class="attachment-grid">
|
||||
<AttachmentList
|
||||
v-for="group in kickoffAttachmentGroups"
|
||||
@@ -448,6 +448,16 @@ onMounted(async () => {
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.training-section,
|
||||
.attachment-section {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
.training-section {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.training-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="page">
|
||||
<div class="page-header unified-action-bar">
|
||||
<div class="page ctms-page-shell page--flush">
|
||||
<div class="page-header unified-action-bar bar--flush">
|
||||
<div>
|
||||
<h1 class="page-title">{{ detail.subject_no || TEXT.modules.subjectManagement.screeningNo }}</h1>
|
||||
<p class="page-subtitle">{{ TEXT.modules.subjectManagement.screeningNo }}</p>
|
||||
@@ -25,7 +25,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-card class="unified-shell" v-loading="loading">
|
||||
<el-card class="unified-shell subject-shell" v-loading="loading">
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item :label="TEXT.modules.subjectManagement.screeningNo">{{ detail.subject_no || TEXT.common.fallback }}</el-descriptions-item>
|
||||
<el-descriptions-item :label="TEXT.common.fields.site">{{ siteMap[detail.site_id] || TEXT.common.fallback }}</el-descriptions-item>
|
||||
@@ -76,7 +76,7 @@
|
||||
</el-descriptions>
|
||||
</el-card>
|
||||
|
||||
<el-card class="unified-shell">
|
||||
<el-card class="unified-shell subject-shell">
|
||||
<el-tabs v-model="activeTab">
|
||||
<el-tab-pane :label="TEXT.modules.subjectDetail.tabs.history" name="history">
|
||||
<div class="tab-actions">
|
||||
@@ -84,7 +84,7 @@
|
||||
{{ TEXT.common.actions.newHistory }}
|
||||
</el-button>
|
||||
</div>
|
||||
<el-table :data="historyItems" v-loading="loadingHistory" style="width: 100%">
|
||||
<el-table :data="historyItems" v-loading="loadingHistory" style="width: 100%" class="subject-detail-table">
|
||||
<el-table-column prop="record_date" :label="TEXT.common.fields.recordDate" width="140">
|
||||
<template #default="scope">{{ displayDate(scope.row.record_date) }}</template>
|
||||
</el-table-column>
|
||||
@@ -121,7 +121,7 @@
|
||||
{{ TEXT.common.actions.newVisit }}
|
||||
</el-button>
|
||||
</div>
|
||||
<el-table :data="visitItems" v-loading="loadingVisits" style="width: 100%">
|
||||
<el-table :data="visitItems" v-loading="loadingVisits" style="width: 100%" class="subject-detail-table">
|
||||
<el-table-column prop="visit_code" :label="TEXT.common.fields.visitCode" width="120" />
|
||||
<el-table-column prop="planned_date" :label="TEXT.common.fields.plannedDate" min-width="180">
|
||||
<template #default="scope">{{ displayDate(scope.row.planned_date) }}</template>
|
||||
@@ -202,7 +202,7 @@
|
||||
{{ TEXT.common.actions.newAe }}
|
||||
</el-button>
|
||||
</div>
|
||||
<el-table :data="aeItems" v-loading="loadingAes" style="width: 100%">
|
||||
<el-table :data="aeItems" v-loading="loadingAes" style="width: 100%" class="subject-detail-table">
|
||||
<el-table-column prop="onset_date" :label="TEXT.common.fields.occurDate" width="140">
|
||||
<template #default="scope">{{ displayDate(scope.row.onset_date) }}</template>
|
||||
</el-table-column>
|
||||
@@ -258,7 +258,7 @@
|
||||
{{ TEXT.modules.subjectDetail.newPd }}
|
||||
</el-button>
|
||||
</div>
|
||||
<el-table :data="pdItems" v-loading="loadingPds" style="width: 100%">
|
||||
<el-table :data="pdItems" v-loading="loadingPds" style="width: 100%" class="subject-detail-table">
|
||||
<el-table-column prop="pd_no" :label="TEXT.common.fields.pdNo" width="130" />
|
||||
<el-table-column prop="pd_type" :label="TEXT.common.fields.pdType" min-width="140" />
|
||||
<el-table-column prop="pd_level" :label="TEXT.common.fields.pdLevel" min-width="120">
|
||||
@@ -1097,7 +1097,7 @@ onMounted(async () => {
|
||||
.page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
@@ -1106,6 +1106,16 @@ onMounted(async () => {
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.subject-shell {
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.subject-shell :deep(.el-card__body) {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.page-title {
|
||||
margin: 0;
|
||||
font-size: 22px;
|
||||
@@ -1126,7 +1136,11 @@ onMounted(async () => {
|
||||
.tab-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-bottom: 12px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.subject-detail-table :deep(.el-table__inner-wrapper::before) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.ae-type-tag {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
style="width: 100%"
|
||||
v-loading="loading"
|
||||
empty-text="暂无数据"
|
||||
class="custom-table"
|
||||
class="custom-table center-summary-table"
|
||||
>
|
||||
<el-table-column prop="name" label="管理中心" min-width="180">
|
||||
<template #default="{ row }">
|
||||
@@ -65,6 +65,29 @@ const getStageType = (status?: string) => {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.summary-table-container {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.center-summary-table :deep(.el-table__inner-wrapper::before) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.summary-table-container :deep(.el-table th.el-table__cell) {
|
||||
background: #f7f9fc;
|
||||
}
|
||||
|
||||
.summary-table-container :deep(.el-table td.el-table__cell),
|
||||
.summary-table-container :deep(.el-table th.el-table__cell) {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
.summary-table-container :deep(.el-table td.el-table__cell) {
|
||||
padding-top: 7px;
|
||||
padding-bottom: 7px;
|
||||
}
|
||||
|
||||
.box-header {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user