Vue实现可移动水平时间轴

软件发布|下载排行|最新软件

当前位置:首页IT学院IT技术

Vue实现可移动水平时间轴

frieryumao   2020-06-29 我要评论

本文着重为大家仔细讲解了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">序 号</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/imageshttps://img.qb5200.com/download-x/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组件学习教程进行学习。

Copyright 2022 版权所有 软件发布 访问手机版

声明:所有软件和文章来自软件开发商或者作者 如有异议 请与本站联系 联系我们