feat 搭建架构骨架
This commit is contained in:
186
src/views/project/cpns/ProjectMilestones.vue
Normal file
186
src/views/project/cpns/ProjectMilestones.vue
Normal file
@@ -0,0 +1,186 @@
|
||||
<script setup lang="ts">
|
||||
import type { Milestone } from '@/types/business/project'
|
||||
|
||||
interface Props {
|
||||
progress: number
|
||||
milestones: Milestone[]
|
||||
startTime?: string
|
||||
endTime?: string
|
||||
}
|
||||
|
||||
defineProps<Props>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="project-milestones">
|
||||
<div class="project-milestones__head">
|
||||
<h2 class="project-milestones__title">
|
||||
总体进度
|
||||
</h2>
|
||||
<span class="project-milestones__percent">{{ progress }}%</span>
|
||||
</div>
|
||||
<div class="project-milestones__track">
|
||||
<div
|
||||
class="project-milestones__bar"
|
||||
:style="{ width: `${progress}%` }"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<ol class="project-milestones__timeline">
|
||||
<li
|
||||
v-for="node in milestones"
|
||||
:key="node.name"
|
||||
class="project-milestones__node"
|
||||
:class="`is-${node.status === '已完成' ? 'done' : node.status === '进行中' ? 'active' : 'pending'}`"
|
||||
>
|
||||
<span class="project-milestones__dot" />
|
||||
<div class="project-milestones__body">
|
||||
<div class="project-milestones__row">
|
||||
<span class="project-milestones__name">{{ node.name }}</span>
|
||||
<span class="project-milestones__status">{{ node.status }}</span>
|
||||
</div>
|
||||
<span v-if="node.time" class="project-milestones__time text-secondary">{{ node.time }}</span>
|
||||
</div>
|
||||
</li>
|
||||
<li v-if="milestones.length === 0" class="project-milestones__empty text-secondary">
|
||||
暂无里程碑数据
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<div class="project-milestones__range">
|
||||
<span v-if="startTime" class="text-secondary">开始时间:{{ startTime }}</span>
|
||||
<span v-if="endTime" class="text-secondary">结束时间:{{ endTime }}</span>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.project-milestones {
|
||||
padding: @spacing-lg @spacing-xl;
|
||||
border-radius: @radius-lg;
|
||||
background: @white;
|
||||
box-shadow: @shadow-base;
|
||||
|
||||
&__head {
|
||||
.flex(row, space-between, center);
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-size: @font-size-lg;
|
||||
font-weight: 600;
|
||||
color: @heading-color;
|
||||
}
|
||||
|
||||
&__percent {
|
||||
font-size: @font-size-xl;
|
||||
font-weight: 600;
|
||||
color: @primary-color;
|
||||
}
|
||||
|
||||
&__track {
|
||||
height: 8px;
|
||||
margin-top: @spacing-base;
|
||||
border-radius: @radius-round;
|
||||
background: @bg-color;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
&__bar {
|
||||
height: 100%;
|
||||
border-radius: @radius-round;
|
||||
background: @primary-color;
|
||||
transition: width 0.3s;
|
||||
}
|
||||
|
||||
&__timeline {
|
||||
margin-top: @spacing-lg;
|
||||
padding-left: @spacing-xs;
|
||||
}
|
||||
|
||||
&__node {
|
||||
position: relative;
|
||||
padding: 0 0 @spacing-base @spacing-lg;
|
||||
border-left: 2px solid @border-color;
|
||||
|
||||
&:last-of-type {
|
||||
border-left-color: transparent;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
&.is-done {
|
||||
border-left-color: @success-color;
|
||||
}
|
||||
|
||||
&.is-active {
|
||||
border-left-color: @primary-color;
|
||||
}
|
||||
}
|
||||
|
||||
&__dot {
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
left: -7px;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border: 2px solid @border-color-dark;
|
||||
border-radius: @radius-round;
|
||||
background: @white;
|
||||
|
||||
.is-done & {
|
||||
border-color: @success-color;
|
||||
background: @success-color;
|
||||
}
|
||||
|
||||
.is-active & {
|
||||
border-color: @primary-color;
|
||||
background: @primary-color;
|
||||
}
|
||||
}
|
||||
|
||||
&__body {
|
||||
.flex(column, flex-start);
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
&__row {
|
||||
.flex(row, center);
|
||||
gap: @spacing-sm;
|
||||
}
|
||||
|
||||
&__name {
|
||||
font-size: @font-size-base;
|
||||
color: @heading-color;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
&__status {
|
||||
font-size: @font-size-sm;
|
||||
color: @text-color-secondary;
|
||||
|
||||
.is-done & {
|
||||
color: @success-color;
|
||||
}
|
||||
|
||||
.is-active & {
|
||||
color: @primary-color;
|
||||
}
|
||||
}
|
||||
|
||||
&__time {
|
||||
font-size: @font-size-sm;
|
||||
}
|
||||
|
||||
&__empty {
|
||||
font-size: @font-size-base;
|
||||
}
|
||||
|
||||
&__range {
|
||||
.flex(row, flex-start, center);
|
||||
gap: @spacing-lg;
|
||||
margin-top: @spacing-base;
|
||||
padding-top: @spacing-base;
|
||||
border-top: 1px solid @border-color;
|
||||
font-size: @font-size-sm;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user