Vue实现可移动水平时间轴


Posted in Javascript onJune 29, 2020

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

里程碑时间轴具体实现

效果图

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">序 号</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组件学习教程进行学习。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
Jquery Ajax学习实例3 向WebService发出请求,调用方法返回数据
Mar 16 Javascript
javaScript知识点总结(必看篇)
Jun 10 Javascript
全面解析JavaScript中“&amp;&amp;”和“||”操作符(总结篇)
Jul 18 Javascript
教你JS中的运算符乘方、开方及变量格式转换
Aug 09 Javascript
jQuery事件对象总结
Oct 17 Javascript
jquery.validate[.unobtrusive]和Bootstrap实现tooltip错误提示问题分析
Oct 30 Javascript
js仿拉勾网首页穿墙广告效果
Mar 08 Javascript
前端开发之CSS原理详解
Mar 11 Javascript
详解最新vue-cli 2.9.1的webpack存在问题
Dec 16 Javascript
从零使用TypeScript开发项目打包发布到npm
Feb 14 Javascript
Vue3配置axios跨域实现过程解析
Nov 25 Vue.js
JS实现页面侧边栏效果探究
Jan 08 Javascript
uniapp与webview之间的相互传值的实现
Jun 29 #Javascript
基于Element封装一个表格组件tableList的使用方法
Jun 29 #Javascript
iview实现图片上传功能
Jun 29 #Javascript
vue+animation实现翻页动画
Jun 29 #Javascript
vue+element实现图片上传及裁剪功能
Jun 29 #Javascript
vue实现匀速轮播效果
Jun 29 #Javascript
vant实现购物车功能
Jun 29 #Javascript
You might like
收音机发烧友应当熟知的100条知识
2021/03/02 无线电
用IE远程创建Mysql数据库的简易程序
2006/10/09 PHP
wordpress之wp-settings.php
2007/08/17 PHP
php 团购折扣计算公式
2011/11/24 PHP
PHP hebrev()函数用法讲解
2019/02/21 PHP
用javascript来实现动画导航效果的代码
2007/12/16 Javascript
jquery异步调用页面后台方法&amp;#8207;(asp.net)
2011/03/01 Javascript
根据IP的地址,区分不同的地区,查看不同的网站页面的js代码
2013/02/26 Javascript
jQuery对于显示和隐藏等常用状态的判断方法
2014/12/13 Javascript
jquery实现tab键进行选择后enter键触发click行为
2017/03/29 jQuery
Vue.js鼠标悬浮更换图片功能
2017/05/17 Javascript
EasyUI的TreeGrid的过滤功能的解决思路
2017/08/08 Javascript
原生js实现淘宝放大镜效果
2020/10/28 Javascript
vue实现Excel文件的上传与下载功能的两种方式
2019/06/28 Javascript
基于ssm框架实现layui分页效果
2019/07/27 Javascript
浅谈JS中this在各个场景下的指向
2019/08/14 Javascript
js实现随机抽奖
2020/03/19 Javascript
python实现识别相似图片小结
2016/02/22 Python
PyQt5每天必学之带有标签的复选框
2018/04/19 Python
Python中property函数用法实例分析
2018/06/04 Python
Python延时操作实现方法示例
2018/08/14 Python
Python实现九宫格式的朋友圈功能内附“马云”朋友圈
2019/05/07 Python
Python3如何在Windows和Linux上打包
2020/02/25 Python
pyqt5 QlistView列表显示的实现示例
2020/03/24 Python
Shoes For Crews法国官网:美国领先的防滑鞋设计和制造商
2018/01/01 全球购物
几道PHP面试题
2013/04/14 面试题
体育教育毕业生自荐信
2013/11/21 职场文书
cf收人广告词大全
2014/03/14 职场文书
室内设计专业毕业生求职信
2014/05/02 职场文书
我的中国梦演讲稿1000字
2014/08/19 职场文书
2014年文艺部工作总结
2014/11/17 职场文书
周年庆典答谢词
2015/01/20 职场文书
环境卫生标语
2015/08/03 职场文书
担保公司2015年终工作总结
2015/10/14 职场文书
创业计划书之酒厂
2019/10/14 职场文书
python 判断字符串当中是否包含字符(str.contain)
2022/06/01 Python