Vue实现可移动水平时间轴

本文实例为大家分享了Vue实现可移动水平时间轴的具体代码,供大家参考,具体内容如下

里程碑时间轴具体实现

效果图

编辑里程碑效果图

<template>

<div class="state_grade">

<!-- <mile-stone :projectId="projectData.proId" :projectName="projectData.proName" :proNum="projectData.proNum"></mile-stone>-->

<div class="timeLine" style="overflow: hidden;">

<div style="width: 10%; display: inline-block; margin-left: 5px;">

<el-button @click="mileStoUpdateVisible = true" type="primary">编辑里程碑</el-button>

</div>

<div style="width: 70%;display: inline-block" align="center">

<div style="width: 20%;display: inline-block; font-size: 14px;">里程碑状态:</div>

<div style="width: 100px;display: inline-block; font-size: 14px; ">开始 <img class="node_picture" src="../../assets/images/timeLineA.png"></div>

<div style="width: 100px;display: inline-block; font-size: 14px;">超期 <img class="node_picture" src="../../assets/images/timeLineB.png"> </div>

<div style="width: 100px;display: inline-block; font-size: 14px;">关闭 <img class="node_picture" src="../../assets/images/timeLineC.png"> </div>

</div>

<div class="my_timeline_prev" @click="moveLeft">

<img src="../../assets/arrow_left_blue.png" class="my_timeline_node"/>

<!-- <div class="my_timeline_item_line" style="margin-top: -18px;"></div>-->

<!-- <div class="my_timeline_item_content" style="color: rgba(0,0,0,0);">上</div>-->

</div>

<div v-if="destroyIncomeStatistics" class="ul_box">

<ul class="my_timeline" ref="mytimeline" style="margin-left: 10px;">

<li class="my_timeline_item" v-for="(item,index) in timeLineList" :key="index">

<el-tooltip placement="top" effect="light">

<div slot="content" class="tooltip">

<el-row>

<el-col :span="24">{{'阶段名称:'+item.stageName}}</el-col>

</el-row>

<el-row>

<el-col :span="24">{{'阶段目标:'+item.stageTarget}}</el-col>

</el-row>

<el-row>

<el-col :span="24">{{'开始时间:'+item.startTime}}</el-col>

</el-row>

<el-row>

<el-col :span="24">{{'结束时间:'+item.endTime}}</el-col>

</el-row>

<el-row>

<el-col :span="24">{{'验收标准:'+item.acceptStar}}</el-col>

</el-row>

<el-row>

<el-col :span="24">

<span v-if="item.milepostState==='1'">里程碑状态:打开</span>

<span v-if="item.milepostState==='2'">里程碑状态:超期</span>

<span v-if="item.milepostState==='3'">里程碑状态:关闭</span>

</el-col>

</el-row>

</div>

<!--圈圈节点-->

<!-- <div class="my_timeline_node" style="backgroundColor: #999; width: 28px;height: 28px;" @click="changeActive(index)" :class="{active: index == timeIndex}"></div>-->

<div class="my_timeline_node">

<div style="background-color: #FCFCFC">

<img class="my_timeline_picture" v-if="item.milepostState==='1'"

src="../../assets/images/timeLineA.png">

<img class="my_timeline_picture" v-if="item.milepostState==='2'"

src="../../assets/images/timeLineB.png">

<img class="my_timeline_picture" v-if="item.milepostState==='3'"

src="../../assets/images/timeLineC.png">

</div>

</div>

</el-tooltip>

<!--线-->

<div

:class="[timeLineList.length==index+1?my_timeline_item_line_last:my_timeline_item_line_not_last]"></div>

<!--标注-->

<div class="my_timeline_item_content">

<div>{{item.endTime}}</div>

<el-tooltip placement="top" effect="light">

<div slot="content">{{item.endTime}}<br/>{{item.stageName}}</div>

<div class="detail_info">{{item.stageName}}</div>

</el-tooltip>

</div>

</li>

</ul>

</div>

<div class="my_timeline_next" @click="moveRight">

<img src="../../assets/arrow_right_blue.png" class="my_timeline_node"/>

<div class="my_timeline_item_content" style="color: rgba(0,0,0,0);">下</div>

</div>

</div>

<el-dialog :title="titleMessage" center :visible="mileStoUpdateVisible" width="50%"

@open="onMileStoUpdateVisibleOpen()" @close="closeMileStone()">

<stone-detail :projectId="this.projectId" :proNum="this.projectData.proNum" @closeMileStone="closeMileStone()" ref="stone-detail"

@refreshMileStoneData="searchMileStone()"></stone-detail>

</el-dialog>

</div>

</div>

</template>

<script>

import API from '../../api/api_project';

import StoneDetail from "../../components/project-info/stonedetail"

import MemberDetail from "../../components/project-info/memberdetail.vue"

export default {

name: 'project-detail',

components:{

MemberDetail,

StoneDetail,

},

data() {

return {

destroyIncomeStatistics:true,

loading: false,

titleMessage: '',

mileStoUpdateVisible: false,

my_timeline_item_line_last: "my_timeline_item_line_last",

my_timeline_item_line_not_last: "my_timeline_item_line_not_last",

menuTree:[],

timeLineList: [],

page:{

total:0,

pageNum: 0,

pageSize: 10,

},

model: {

select: "",

searchConent: "",

projectId: "",

proName:"",

},

projectData:{

proId: '',

proNum: '',

proName: '',

hwDept: '',

hwPo: '',

busineMode: '1',

buildProDate: '',

startDate: '',

expEndDate: '',

hwPoDate: '',

hwPoEndDate:'',

realEndDate: '',

proManageId:'',

proQa:'',

hwPm:'',

proEstNum: '0',

proState:'1'

},

proPeoId:'',

projectId:'',

proPeoUpdateVisible:false,

projectMember: [],

}

},

mounted(){

this.projectId=this.$route.params.projectId

this.searchMileStone()

this.sortDataArray(this.timeLineList)

//到数据库获取projectId对应的信息列表存入projectData

API.getProjectInfo(this.projectId).then((data)=>{

this.projectData=data.data;

this.projectData.busineMode = this.projectData.busineMode.toString();

this.projectData.proState = this.projectData.proState.toString();

})

this.search();

},

methods: {

searchMileStone() {

console.log('项目id:'+this.projectId)

let params={

proId:this.projectId,

};

API.getMileStoneList(params).then(data => {

let result = data.data

if (result && result.list) {

if(this.timeLineList.length>0){

this.timeLineList.splice(0,this.timeLineList.length);

}

for(var i=0;i<result.list.length;i++){

this.timeLineList.splice(i, 1, result.list[i])

}

this.sortDataArray(this.timeLineList)

}

},({msg})=>{

this.$message.error(msg);

});

console.log('刷新里程碑列表')

console.log(this.timeLineList)

},

closeMileStone() {

this.mileStoUpdateVisible = false;

// this.projectId = '';

},

onMileStoUpdateVisibleOpen() {

this.titleMessage = this.projectData.proNum + '项目里程碑';

this.$nextTick(() => {

let form = this.$refs["stone-detail"];

form.initPage();

});

},

changeActive(index) {

this.timeIndex = index;

},

moveLeft() {

let marginLeft = parseInt(this.$refs.mytimeline.style.marginLeft);

let listNum = 0;

if (Math.abs(marginLeft) > 10) {

this.$refs.mytimeline.style.marginLeft = marginLeft + 120 + 'px';

}

},

moveRight() {

let marginLeft = parseInt(this.$refs.mytimeline.style.marginLeft);

if (marginLeft <= 10 && (marginLeft >= -(this.timeLineList.length * 120))) {

this.$refs.mytimeline.style.marginLeft = marginLeft - 120 + 'px';

}

},

//对数组根据日期进行排序

sortDataArray(dataArray) {

return dataArray.sort(function (a, b) {

return Date.parse(a.endTime.replace(/-/g, "/")) - Date.parse(b.endTime.replace(/-/g, "/"));

})

},

sortByKey(array,key){

return array.sort(function(a,b){

var y = a[key];

var x = b[key];

return((x<y)?-1:((x>y)?1:0));

})

},

handleCurrentChange(val) {

this.page.pageNum = val ;

this.search();

},

handleSizeChange(val) {

this.page.pageSize = val;

this.search();

},

handleSearch(){

this.page.pageNum= 0;

this.search();

},

}

</script>

.content {

height: 100px;

}

.my_timeline_next {

float: left;

display: inline-block;

background-color: #FCFCFC;

cursor: pointer;

}

.my_timeline_prev {

width: 50px;

float: left;

margin-top: 110px;

}

.my_timeline_next {

width: 34px;

margin-top: 80px;

}

.el-col-24 {

margin-left: 10px;

padding-bottom: 5px;

}

.el-col-12 {

margin-left: 10px;

}

.tooltip {

}

.ul_box {

width: 80%;

height: 120px;

display: inline-block;

float: left;

margin-top: 50px;

overflow: hidden;

}

.my_timeline_item {

display: inline-block;

width: 150px;

}

.my_timeline_node {

background-color: #FCFCFC;

box-sizing: border-box;

border-radius: 50%;

cursor: pointer;

width: 40px;

height: 40px;

}

.node_picture {

//margin-top: 20px;

height: 25px;

width: 25px;

margin-left: 5px;

margin-bottom: -7px;

}

.my_timeline_picture {

margin-top: 13px;

height: 25px;

width: 25px;

}

.my_timeline_node.active {

background-color: #fff !important;

border: 6px solid #f68720;

}

.my_timeline_item_line_last {

width: 100%;

height: 10px;

margin: -14px 0 0 28px;

border-left: none;

}

.my_timeline_item_line_not_last {

width: 100%;

height: 10px;

margin: -14px 0 0 25px;

border-top: 2px solid #E4E7ED;

border-left: none;

}

.my_timeline_item_content {

margin: 10px 0 0 -10px;

width: 90%; /*根据自己项目进行定义宽度*/

font-size: 14px;

}

.detail_info {

width: 80%;

height: 250px;

padding-bottom: 50px;

overflow: hidden; /*设置超出的部分进行影藏*/

text-overflow: ellipsis; /*设置超出部分使用省略号*/

white-space: nowrap; /*设置为单行*/

font-size: 14px;

}

.state_grade.process_wrap{

border-color: #e4ebf0;

margin-top: 150px;

border-radius: 2px;

padding-bottom: 10px;

}

.fall-back {

float:right;

margin-right: 20px;

margin-bottom:50px;

}

.state_grade{

border: 1px solid #e6e6e6;

background: #FCFCFC;

padding: 10px;

//position: relative;

/*height: 90px;*/

height: 250px;

margin-bottom: 15px;

/*margin-top: 15px;*/

}

.title_top{

height: 33px;

}

.obj_tit_wrap{

border-bottom: 1px solid #e6e6e6;

padding-bottom: 3px;

font-size: 14px;

}

.obj_tit_mile{

width: 150px;

height: 35px;

}

.tit_deco{

color: #9a9a9a;

font-size: 14px;

}

.add_contain{

display:inline-block;

padding-bottom: 10px;

padding-top: 20px;

}

.project_content_warp{

background: #fdfdfd;

margin-bottom: 15px;

}

.project_job_add{

padding-left: 30px;

background: #FCFCFC;

border-bottom: 1px solid #E5E5E5;

line-height: 10px;

margin-bottom: 15px;

font-size: 14px;

}

.project_info_span{

display:inline-block;

padding-left: 10px;

}

.el-col-8{

height: 50px;

}

</style>

编辑里程碑

stonedetail.vue

<template>

<div>

<el-row>

<el-col :span="23">

<div style="margin-top: 10px">

<el-tag effect="dark" style="font-size: 16px;width: 110px;text-align: center">里程碑</el-tag>

</div>

</el-col>

<el-col :span="1">

<img src="../../assets/images/add.png" style="width: 30px;height: 30px;margin-top: 10px" @click="addItems()"/>

</el-col>

</el-row>

<hr/>

<el-row style="text-align: center">

<el-col :span="3">

<el-tag style="width: 100%;font-size: 14px">序&#12288;号</el-tag>

</el-col>

<el-col :span="8">

<el-tag style="width: 100%;font-size: 14px">阶段名称</el-tag>

</el-col>

<el-col :span="7">

<el-tag style="width: 100%;font-size: 14px">起始时间</el-tag>

</el-col>

<el-col :span="5">

<el-tag style="width: 100%;font-size: 14px">结束时间</el-tag>

</el-col>

</el-row>

<el-form label-width="100px" align="left" ref="form" style="text-align: left;" :model="model">

<div v-for="(item, index) in model.timeLineList" :key="index">

<el-row>

<el-col :span="3">

<input style="text-align: center" class="el-input__inner" type="text" v-model="index" disabled="true">

</el-col>

<el-col :span="8">

<input placeholder="请输入阶段名称" style="text-align: center" class="el-input__inner" type="text"

v-model="item.stageName">

</el-col>

<el-col :span="6">

<el-date-picker

style="width: 100%"

type="date"

:editable="false"

v-model="item.startTime"

placeholder="请选择起始时间"

format="yyyy-MM-dd"

value-format="yyyy-MM-dd"

>

</el-date-picker>

</el-col>

<el-col :span="6">

<el-date-picker

style="width: 100%"

type="date"

:editable="false"

v-model="item.endTime"

placeholder="请选择结束时间"

format="yyyy-MM-dd"

value-format="yyyy-MM-dd"

>

</el-date-picker>

</el-col>

</el-row>

<el-row>

<el-col :span="3">

<input placeholder="阶段目标" style="text-align: center;" class="el-input__inner" type="text" disabled="true">

</el-col>

<el-col :span="20">

<el-input v-model="item.stageTarget" placeholder="请输入阶段目标"></el-input>

<!-- <textarea placeholder="请输入阶段目标" v-model="item.stageTarget" style="height: 30px;" class="el-input__inner" type="text"></textarea>-->

</el-col>

</el-row>

<el-row>

<el-col :span="3">

<input placeholder="验收标准" style="text-align: center;" class="el-input__inner" type="text" disabled="true">

</el-col>

<el-col :span="20">

<el-input v-model="item.acceptStar" placeholder="请输入验收标准"></el-input>

</el-col>

</el-row>

<el-row>

<el-col :span="3">

<input placeholder="里程碑状态" style="text-align: center;" class="el-input__inner" type="text" disabled="true">

</el-col>

<el-col :span="20">

<template>

<el-select v-model="item.milepostState" placeholder="请选择">

<el-option

v-for="item in milepostStateList"

:key="item.ref_id"

:label="item.ref_value"

:value="item.ref_id">

</el-option>

</el-select>

</template>

</el-col>

<el-col :span="1">

<img src="../../assets/images/delete.png" style="width: 30px;height: 30px" @click="deleteItems(index)"/>

</el-col>

</el-row>

</div>

</el-form>

<div style="text-align: center;margin-top: 30px">

<el-button type="primary" @click="submit()">确认修改</el-button>

</div>

</div>

</template>

<script>

import API from '../../api/api_project';

export default {

name: "stoneDetail",

props: ['projectId', 'proNum'],

watch: {

'proId': {

// projectId,所以每次都能监听到变化

immediate: true,

handler: function (val) {

if (!val) return;

this.onProjectIdChange(val);

}

}

},

data() {

return {

proId:'',

milepostStateList: [{

ref_id: "1",

ref_value: '打开',

ref_key: '1'

}, {

ref_id: "2",

ref_value: '超期',

ref_key: '2'

}, {

ref_id: "3",

ref_value: '关闭',

ref_key: '3'

}],

deleteList: [],

model: {

timeLineList: [],

},

}

},

methods: {

/**

* 提交修改的信息

*/

submit: function () {

this.$refs.form.validate((valid) => {

if (!valid) {

this.$message.error('请填写正确信息');

return;

}

console.log('编辑里程碑结果:')

console.log(this.model.timeLineList)

let proMileposts = this.model.timeLineList

API.updatetMileStone(proMileposts).then(data => {

if (data.code == 200) {

this.$message.success("修改成功");

this.refreshMileStoneData();

this.close();

} else {

this.$message.error(data.msg);

// this.close();

}

})

});

},

close() {

this.$emit("closeMileStone");

this.proId=''

this.model.timeLineList.splice(0,this.model.timeLineList.length)

},

refreshMileStoneData() {

this.$emit("refreshMileStoneData");

},

addItems() {

this.model.timeLineList.push({

milepostId:'',

proId: this.proId,

stageName: '',

startTime: this.addDate(),

endTime: this.addDate(),

stageTarget: '',

acceptStar: '',

deliverableName: '',

milepostState: '1',

});

},

addDate() {

var date = new Date();

var seperator1 = "-";

var year = date.getFullYear();

var month = date.getMonth() + 1;

var strDate = date.getDate();

if (month >= 1 && month <= 9) {

month = "0" + month;

}

if (strDate >= 0 && strDate <= 9) {

strDate = "0" + strDate;

}

var currentdate = year + seperator1 + month + seperator1 + strDate;

return currentdate;

},

deleteItems(index) {

this.$confirm('确认删除该记录吗?', '提示', {

confirmButtonClass: 'el-button--warning'

}).then(() => {

if(this.model.timeLineList[index].milepostId)

{

API.deleteMileStone(this.model.timeLineList[index].milepostId).then(data=>{

if(data.code===200)

{

this.$message.success("删除成功");

this.model.timeLineList.splice(index, 1);

this.refreshMileStoneData();

}else {

this.$message.error(data.msg);

}

})

}

else{

this.model.timeLineList.splice(index, 1);

}

}).catch(() => {});

},

onProjectIdChange(id) {

this.model.timeLineList.splice(0,this.model.timeLineList.length)

// if (id) {

let params={

proId:id,

};

API.getMileStoneList(params).then(data => {

let result = data.data

if (result && result.list) {

for(var i=0;i<result.list.length;i++){

this.model.timeLineList.splice(i, 1, result.list[i])

}

}

}, ({msg}) => {

this.$message.error(msg);

});

// }

console.log('dailog打开里程碑列表')

console.log(this.model.timeLineList)

},

initPage() {

this.proId=this.projectId;

if (this.proId) {

this.onProjectIdChange(this.proId);

}

}

},

}

</script>

<style scoped>

</style>

关于vue.js组件的教程,请大家点击专题vue.js组件学习教程进行学习。

以上是 Vue实现可移动水平时间轴 的全部内容, 来源链接: utcz.com/z/332185.html

回到顶部