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>

/

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值