欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

基于vue3和element plus實(shí)現(xiàn)甘特圖

 更新時(shí)間:2024年06月02日 10:27:05   作者:Emma?M  
甘特圖是一種重要的項(xiàng)目管理工具,它可以通過(guò)圖形化的方式展示項(xiàng)目的進(jìn)度和時(shí)間表,甘特圖通常由一個(gè)橫軸和一個(gè)縱軸組成,甘特圖對(duì)于項(xiàng)目管理非常重要,所以本文給大家介紹了如何基于vue3和element plus實(shí)現(xiàn)甘特圖,需要的朋友可以參考下

vue3 + element plus實(shí)現(xiàn)甘特圖

效果展示

實(shí)現(xiàn)思路

甘特圖,個(gè)人理解就是表格的一種展現(xiàn)形式。左側(cè)填充數(shù)據(jù),右側(cè)用圖例填充表示時(shí)間、工期、進(jìn)度等信息。

技術(shù)選型

常用的ui框架有很多,以前用vue2的時(shí)候多搭配element ui,最近在看vue3的內(nèi)容,所以選擇了element plus。所以本文示例使用vue3+element plus實(shí)現(xiàn)甘特圖??催^(guò)原理之后改用其他技術(shù)方案也很簡(jiǎn)單。

代碼實(shí)現(xiàn)

新建項(xiàng)目 vue3 + element plus

自己搜索吧,有很多,這里不是重點(diǎn)。

封裝組件

這里說(shuō)下為什么要封裝成組件,因?yàn)轫?xiàng)目里可能多處用到類(lèi)似的功能,總不能每次都拷貝,然后修改。一次封裝,多次引用。
上代碼:我存放的路徑 /src/components/gantt/index.vue

<template>
	<div class="gantt">
		<div class="legend">
			<!-- 渲染圖例 -->
			<i class="plan"></i>
			<label>計(jì)劃</label>
			<i class="actuality"></i>
			<label>實(shí)際</label>
		</div>
		<el-table :data="data">
			<!-- 渲染表格 -->
			<el-table-column 
				v-for="(column, index) in columnsConfig" 
				:key="index"
				v-bind="column"
			></el-table-column>
			<el-table-column
				v-for="monthItem in monthData"
				:key="monthItem.month"
				align="center"
				min-width="80"
				:prop="monthItem.month"
				:label="monthItem.month"
			>
				<template #header>
					<span>{{ monthItem.month.substring(5) + '月' }}</span>
				</template>
				<el-table-column
					v-for="day in monthItem.dayArray"
					:key="day"
					align="center"
					:width="50"
					:prop="day"
				>
					<template #header>
						<span>{{ day.substring(8) }}</span>
					</template>
					<template #default="scope">
						<i class="plan" v-if="showPlan(scope)"></i>
						<i class="empty" v-else></i>
						<i class="actuality" v-if="showActuality(scope)"></i>
						<i class="empty" v-else></i>
					</template>
				</el-table-column>
			</el-table-column>
		</el-table>
	</div>
</template>

<script setup>
import { ref } from 'vue';

const props = defineProps({
	data: {
		type: Array,
		default: []
	},
	columnsConfig: {
		type: Array,
		default: []
	},
	ganttConfig: {
		type: Object,
		default: {
			planBeginColumn: 'planBegin',
			planEndColumn: 'planEnd',
			actualityBeginColumn: 'actualityBegin',
			actualityEndColumn: 'actualityEnd'
		}
	}
})

const monthData = ref({})

const init = () => {
	let minDate = undefined
	let maxDate = undefined
	
	props.data.forEach((row, index) => {
		let current = new Date(row[props.ganttConfig.planBeginColumn])
		if (minDate) {
			minDate = minDate.getTime() < current.getTime() ? minDate : current
		} else {
			minDate = current
		}
		current = new Date(row[props.ganttConfig.planEndColumn])
		if (maxDate) {
			maxDate = maxDate.getTime() > current.getTime() ? maxDate : current
		} else {
			maxDate = current
		}
		current = props.ganttConfig.actualityBeginColumn || row[props.ganttConfig.actualityBeginColumn] ? new Date(row[props.ganttConfig.actualityBeginColumn]) : undefined
		if (current) {
			minDate = minDate.getTime() < current.getTime() ? minDate : current
		}
		current = props.ganttConfig.actualityEndColumn || row[props.ganttConfig.actualityEndColumn] ? new Date(row[props.ganttConfig.actualityEndColumn]) : undefined
		if (current) {
			maxDate = maxDate.getTime() > current.getTime() ? maxDate : current
		}
	})
	
	// 甘特圖前后各放寬2天
	minDate = new Date(minDate.getTime() - 2 * 24 * 60 * 60 * 1000)
	maxDate = new Date(maxDate.getTime() + 2 * 24 * 60 * 60 * 1000)
	let current = new Date(format(minDate))
	while(!isAfter(current, maxDate)) {
		const month = formatYearMonth(current)
		const day = format(current)
		if (monthData.value[month]) {
			monthData.value[month].dayArray.push(day)
		} else {
			monthData.value[month] = {
				month: month,
				dayArray: [day]
			}
		}
		// 加一天
		current = after(current)
	}
}
/**
 * 格式化 YYYY-MM-DD
 */
const format = (date) => {
	const day = String(date.getDate()).padStart(2, '0')
	return formatYearMonth(date) + '-' + day
}
/**
 * 格式化 YYYY-MM
 */
const formatYearMonth = (date) => {
	const year = date.getFullYear()
	const month = String(date.getMonth() + 1).padStart(2, '0')
	return year + '-' + month
}
/**
 * 加一天
 */
const after = (date) => {
	return new Date(date.getTime() + 24 * 60 * 60 * 1000)
}
/**
 * date1是否大于等于date2
 */
const isAfter = (date1, date2) => {
	return date1.getTime() >= date2.getTime()
}
/**
 * 顯示計(jì)劃進(jìn)度
 */
const showPlan = ({row, column}) => {
	const currentDay = new Date(column.property)
	const begin = new Date(row[props.ganttConfig.planBeginColumn])
	const end = new Date(row[props.ganttConfig.planEndColumn])
	return currentDay.getTime() >= begin.getTime() && currentDay.getTime() <= end.getTime()
}
/**
 * 顯示實(shí)際進(jìn)度
 */
const showActuality = ({row, column}) => {
	const currentDay = new Date(column.property)
	const begin = props.ganttConfig.actualityBeginColumn || row[props.ganttConfig.actualityBeginColumn] ? new Date(row[props.ganttConfig.actualityBeginColumn]) : undefined
	const end = props.ganttConfig.actualityEndColumn || row[props.ganttConfig.actualityEndColumn] ? new Date(row[props.ganttConfig.actualityEndColumn]) : undefined
	return begin && end && currentDay.getTime() >= begin.getTime() && currentDay.getTime() <= end.getTime()
}
init()
</script>

<style scoped>
	.plan {
		display: flex;
		width: calc(100% + 24px);
		height: 16px;
		background-color: limegreen;
		margin: 0 -12px;
	}
	.actuality {
		display: flex;
		width: calc(100% + 24px);
		height: 16px;
		background-color: yellow;
		margin: 0 -12px;
	}
	.empty {
		display: flex;
		width: calc(100% + 24px);
		height: 16px;
		margin: 0 -12px;
	}
	.legend {
		display: flex;
		line-height: 40px;
		flex-direction: row;
		justify-content: right;
		align-items: center;
		padding: 0 20px;
		
		* {
			margin: 0 5px;
		}
		
		i {
			width: 32px;
			height: 16px;
		}
	}
</style>

引用組件

app.vue中引用上面的組件

<script setup>
	import Gantt from '@/components/gantt/index.vue'
	const data = ref([
		{
			title: '第一階段',
			planBegin: '2022-01-01',
			planEnd: '2022-01-09',
			actualityBegin: '2022-01-02',
			actualityEnd: '2022-01-10'
		},
		{
			title: '第二階段',
			planBegin: '2022-01-09',
			planEnd: '2022-01-15',
			actualityBegin: '2022-01-09',
			actualityEnd: '2022-01-18'
		}
	])
	const columnsConfig = ref([
		{
			label: '事項(xiàng)',
			prop: 'title',
			fixed: 'left',
			align: 'center',
			'min-width': 120
		},
		{
			label: '開(kāi)始',
			prop: 'planBegin',
			fixed: 'left',
			align: 'center',
			'min-width': 120
		},
		{
			label: '結(jié)束',
			prop: 'planEnd',
			fixed: 'left',
			align: 'center',
			'min-width': 120
		}
	])
</script>

<template>
	<div>
		<Gantt 
			:data="data" 
			:columnsConfig="columnsConfig" 
			:ganttConfig ="{
				planBeginColumn: 'planBegin',
				planEndColumn: 'planEnd',
				actualityBeginColumn: 'actualityBegin',
				actualityEndColumn: 'actualityEnd'
			}"
		/>
	</div>
</template>

<style scoped>
</style>

到此這篇關(guān)于基于vue3和element plus實(shí)現(xiàn)甘特圖的文章就介紹到這了,更多相關(guān)vue3 element plus甘特圖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 使用Bootrap和Vue實(shí)現(xiàn)仿百度搜索功能

    使用Bootrap和Vue實(shí)現(xiàn)仿百度搜索功能

    這篇文章主要介紹了使用Bootrap和Vue實(shí)現(xiàn)仿百度搜索功能,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2017-10-10
  • 前端必知必會(huì)之Vue?$emit()方法詳解

    前端必知必會(huì)之Vue?$emit()方法詳解

    這篇文章主要介紹了前端必知必會(huì)之Vue?$emit()方法的相關(guān)資料,Vue.js中的$emit()方法用于在子組件中創(chuàng)建自定義事件,并在父組件中捕獲這些事件,這在需要從子組件向父組件傳遞信息的大型項(xiàng)目中非常有用,需要的朋友可以參考下
    2025-02-02
  • vue-cli中vue本地實(shí)現(xiàn)跨域調(diào)試接口

    vue-cli中vue本地實(shí)現(xiàn)跨域調(diào)試接口

    這篇文章主要介紹了vue-cli中vue本地實(shí)現(xiàn)跨域調(diào)試接口,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2019-01-01
  • vue2.0父子組件間通信的實(shí)現(xiàn)方法

    vue2.0父子組件間通信的實(shí)現(xiàn)方法

    本篇文章主要介紹了vue2.0父子組件間通信的實(shí)現(xiàn)方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。
    2017-04-04
  • Vue3中ref和reactive的使用場(chǎng)景詳解

    Vue3中ref和reactive的使用場(chǎng)景詳解

    這篇文章主要介紹了Vue3中ref和reactive的使用場(chǎng)景,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-04-04
  • vue引用BootStrap以及引用bootStrap-vue.js問(wèn)題

    vue引用BootStrap以及引用bootStrap-vue.js問(wèn)題

    這篇文章主要介紹了vue引用BootStrap以及引用bootStrap-vue.js問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-10-10
  • vue中axios的二次封裝實(shí)例講解

    vue中axios的二次封裝實(shí)例講解

    在本篇文章里小編給大家整理了關(guān)于vue中axios的二次封裝實(shí)例以及相關(guān)知識(shí)點(diǎn)總結(jié),需要的朋友們可以學(xué)習(xí)下。
    2019-10-10
  • 詳解Nuxt.js Vue服務(wù)端渲染摸索

    詳解Nuxt.js Vue服務(wù)端渲染摸索

    本篇文章主要介紹了詳解Nuxt.js Vue服務(wù)端渲染摸索,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-02-02
  • Vue Autocomplete 自動(dòng)完成功能簡(jiǎn)單示例

    Vue Autocomplete 自動(dòng)完成功能簡(jiǎn)單示例

    這篇文章主要介紹了Vue Autocomplete 自動(dòng)完成功能,結(jié)合簡(jiǎn)單示例形式分析了Vue使用el-autocomplete組件實(shí)現(xiàn)自動(dòng)完成功能相關(guān)操作技巧,需要的朋友可以參考下
    2019-05-05
  • vue實(shí)現(xiàn)折疊展開(kāi)收縮動(dòng)畫(huà)效果

    vue實(shí)現(xiàn)折疊展開(kāi)收縮動(dòng)畫(huà)效果

    這篇文章主要介紹了vue實(shí)現(xiàn)折疊展開(kāi)收縮動(dòng)畫(huà),通過(guò)scrollHeight實(shí)現(xiàn),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友一起看看吧
    2023-11-11

最新評(píng)論