项目中心
This commit is contained in:
108
src/views/project/cpns/ProjectProgress.vue
Normal file
108
src/views/project/cpns/ProjectProgress.vue
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
interface Props {
|
||||||
|
/** 总体进度百分比(后端 `projectStage.developmentProgress`;未立项为 0) */
|
||||||
|
progress: number
|
||||||
|
startTime?: string
|
||||||
|
endTime?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<Props>()
|
||||||
|
|
||||||
|
/** 进度条填充宽度(夹到 0~100,避免脏数据把条撑出容器) */
|
||||||
|
function clampPercent(value: number): number {
|
||||||
|
if (!Number.isFinite(value)) return 0
|
||||||
|
return Math.min(100, Math.max(0, Math.round(value)))
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<section class="project-progress">
|
||||||
|
<h2 class="project-progress__title">
|
||||||
|
开发进度
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<div class="project-progress__head">
|
||||||
|
<span class="project-progress__label text-secondary">总体进度</span>
|
||||||
|
<span class="project-progress__percent">{{ clampPercent(props.progress) }}%</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 设计稿:轨道通栏,蓝色填充,末端一个白底蓝环圆点(进度为 0 时不画圆点) -->
|
||||||
|
<div class="project-progress__track">
|
||||||
|
<div class="project-progress__fill" :style="{ width: `${clampPercent(props.progress)}%` }" />
|
||||||
|
<span
|
||||||
|
v-if="clampPercent(props.progress) > 0"
|
||||||
|
class="project-progress__knob"
|
||||||
|
:style="{ left: `${clampPercent(props.progress)}%` }"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="project-progress__range">
|
||||||
|
<span class="text-secondary">开始时间:{{ props.startTime || '—' }}</span>
|
||||||
|
<span class="text-secondary">结束时间:{{ props.endTime || '—' }}</span>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.project-progress {
|
||||||
|
.flex(column, flex-start, stretch);
|
||||||
|
padding: @spacing-lg;
|
||||||
|
border-radius: @radius-lg;
|
||||||
|
background: @white;
|
||||||
|
box-shadow: @shadow-base;
|
||||||
|
|
||||||
|
&__title {
|
||||||
|
.section-title();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设计稿:正文块相对标题再右缩进一级(设计 27 设计px × 0.77 ≈ 21px)
|
||||||
|
&__head {
|
||||||
|
.flex(row, space-between, center);
|
||||||
|
margin-top: @spacing-base;
|
||||||
|
padding-left: 21px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__label {
|
||||||
|
font-size: @font-size-sm;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__percent {
|
||||||
|
font-size: @font-size-title;
|
||||||
|
font-weight: 600;
|
||||||
|
color: @project-accent;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__track {
|
||||||
|
position: relative;
|
||||||
|
height: 5px;
|
||||||
|
margin: @spacing-base 0 0 21px;
|
||||||
|
border-radius: @radius-round;
|
||||||
|
background: @project-track;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__fill {
|
||||||
|
height: 100%;
|
||||||
|
border-radius: @radius-round;
|
||||||
|
background: @project-accent;
|
||||||
|
transition: width 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__knob {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
border: 2px solid @project-accent;
|
||||||
|
border-radius: @radius-round;
|
||||||
|
background: @white;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__range {
|
||||||
|
.flex(row, space-between, center);
|
||||||
|
margin-top: @spacing-lg;
|
||||||
|
font-size: @font-size-sm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user