首页 > 其他分享 >实现dhtmlx甘特图

实现dhtmlx甘特图

时间:2023-04-07 14:33:31浏览次数:59  
标签:实现 config dhtmlx 甘特图 item gantt date data id

Vue2使用DHTMLX Gantt

甘特图

成品展示

gantt安装与使用

vue2版---部分功能收费

  1. 安装gantt

    npm install dhtmlx-gantt -save
    
  2. 引入---组件

    `引入`
    <template>
    		<div ref="gantt" class="container" />
    </template>
    <script>
      import { gantt } from 'dhtmlx-gantt'
    </script>
    
  3. 使用

    使用需要很多配置项,在原生版进行详情介绍,vue版只做基本使用

    功能(收费) 文档链接 简要说明
    动态加载 Dynamic loading 能通过接口更新甘特数据,gantt支持的接口方法
    时间刻度隐藏 Ability to hide time units on the time scale 右边视图刻度可以不显示某时间内容
    工作时间精度 Assigning Calendar to Project 精确工作时间到小时或小数点天数
    自动调度 Auto scheduling 使甘特图能够根据任务之间的关系自动安排任务,自动调度时间
    页面多个甘特图 Enterprise and Ultimate licenses) 单个页面创建多个甘特图
    关键任务计算 Critical path calculation 关键任务不可延迟,项目标红,计算项目可预算时间
    水平拖拽多个任务 Decimal units for tasks durations 可以同时修改多个任务的时间
    项目,里程碑,任务类型 Projects and Milestones task types 区别显示图标,里程碑(菱形图案)---原生版可用
    将项目拆分子任务 Projects and Milestones task types 项目收缩显示子任务 -----原生版可用
    分组任务 Tasks grouping 细化数据分类,不做汇总分区基本用不上

    以上内容只是部分收费内容,并非全部收费内容

原生版---推荐使用

引入

`页面部分` ----#节点高度要给,gantt不根据内容撑开
<div style="min-height:calc(78vh - 50px - 5px );width: 100%;overflow: hidden;" ref="gantt">
 </div>

`引入部分`
import {
  gantt
} from '@/assets/js/dhtmlx';
import "@/assets/css/dhtmlxgantt.css";
  1. css文件地址 examples/dhtmlx_gantt/dhtmlxgantt.css · 残星落影/博客 - 码云 - 开源中国 (gitee.com)
  2. js文件地址 examples/dhtmlx_gantt/dhtmlx · 残星落影/博客 - 码云 - 开源中国 (gitee.com)

使用

gantt加载数据格式
`定义数据格式` 
data(){
	return {
    tasks: {
            data: [],//数据
            links: [],//关联项目数据
          },
    }
}
`甘特数据载入`
 gantt.parse(this.tasks);//parse方法加载数据
 gantt.render();//建议每一次修改配置项调用一次render方法

tasks.data数据格式

data=[
  { 
    id: 1,//必填
    text: "标题",//必填 
    type: "task",// 项目类型 task任务 project项目  milestone里程碑  
    start_date: "2023/3/15",
    duration: 5,//任务持续时间
    parent: 11,//存在这个属性说明此数据为子任务数据,父任务id为11
    progress: 0.3,//项目任务滑块的进度
    open: true,//是否展开显示
  	....
  },
  { 
    id: 2,
    text: "标题2", 
    start_date: "2023/3/15",
    duration: 5,
    progress: 0,
    open: true
  	....
  },
]
# data中有些数据可以直接被读取,其余数据都可以定义在左侧表格columns数据显示
`甘特可直接读取属性
		type  parent  progress open ...
`

tasks.links数据格式

links=[
  {
		id:'111',//数据id
    source:'1'
    target:'2'
    type:'0'
  },//
  {
    id:'222'
    source:'2'
    target:'1'
    type:'1'
  },//数据说明 滑块任务2 的头部 指向滑块任务1的头部
]
#字段解释
格式 id:数据id   
		source:开始链接的项目id  ----为tasks.data中数据的id
    target:要链接项目的id  ----为tasks.data中数据的id
		type: 0--进行-开始  `尾部链接头部`  
					1--开始-开始	`头部链接头部`
					2--进行-进行	`尾部链接尾部`
					3--开始-进行	`头部链接尾部`

图例

配置项
  • 基础config

     gantt.config.branch_loading = true; // 启用动态加载
     gantt.config.xml_date = "%Y-%m-%d"; //日期格式化
     gantt.config.order_branch = true;
     gantt.config.order_branch_free = true;
     gantt.config.autofit = true;//左侧是否自适应
     gantt.config.drag_links = true;//连线
     gantt.config.readonly = false;  //只读
     gantt.config.smart_scales = true;
     gantt.config.date_scale = "%m月%d日"; //右侧显示列名
     gantt.config.layout = {//拖拽布局
            css: "gantt_container",
            rows: [
              {
                cols: [
                  { view: "grid", id: "grid", scrollX: "scrollHor", scrollY: "scrollVer" },
                  { resizer: true, width: 1 },
                  { view: "timeline", id: "timeline", scrollX: "scrollHor", scrollY: "scrollVer" },
                  { view: "scrollbar", scroll: "y", id: "scrollVer" }
                ]
              },
              { view: "scrollbar", scroll: "x", id: "scrollHor", height: 20 }
            ]
          };
    gantt.config.start_on_monday = true;//是否从周一显示起始时间---右侧条形图
    gantt.config.work_time = true;//显示工作时间
    gantt.config.fit_tasks = true;   //自动调整图表坐标轴区间用于适配task的长度
    
  • local---本地汉化

    说明

    (1)直接引入dhtmlx甘特实现的图表操作描述全是英文的,所以要对现有的属性数据显示要进行汉化文字代替

    (2)汉化分三种

    日期汉化 属性汉化 自定义属性汉化
    gantt.locale.date gantt.locale.labels gantt.locale.labels
     //汉化
          gantt.locale = {
            date: {
              month_full: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"],
              month_short: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"],
              day_full: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"],
              day_short: ["日", "一", "二", "三", "四", "五", "六"]
            },
            labels: {
              dhx_cal_today_button: "今天",
              day_tab: "日",
              week_tab: "周",
              month_tab: "月",
              new_event: "新建日程",
              icon_save: "保存",
              icon_cancel: "关闭",
              icon_details: "详细",
              icon_edit: "编辑",
              icon_delete: "删除",
              confirm_closing: "请确认是否撤销修改!", //Your changes will be lost, are your sure?
              confirm_deleting: "是否删除计划?",
              section_description: "描述:",
              section_time: "时间范围:",
              section_type: "类型:",
              section_text: "计划名称:",
              section_test: "测试:",
              #自定义属性汉化----->
              section_projectClass: "项目类型:",
              taskProjectType_0: "项目任务",
              taskProjectType_1: "普通任务",
              section_head: "负责人:",
              section_priority: '优先级:',
              taskProgress: '任务状态',
              taskProgress_0: "未开始",
              taskProgress_1: "进行中",
              taskProgress_2: "已完成",
              taskProgress_3: "已延期",
              taskProgress_4: "搁置中",
              #<-----自定义属性汉化结束
              section_template: 'Details',
              /* grid columns */
              column_text: "计划名称",
              column_start_date: "开始时间",
              column_duration: "持续时间",
              column_add: "",
              column_priority: "难度",
              /* link confirmation */
              link: "关联",
              confirm_link_deleting: "将被删除",
              link_start: " (开始)",
              link_end: " (结束)",
              type_task: "任务",
              type_project: "项目",
              type_milestone: "里程碑",
    
              minutes: "分钟",
              hours: "小时",
              days: "天",
              weeks: "周",
              months: "月",
              years: "年"
            }
          }
    

    (4)图例注释

  • 表格(左)配置

    属性 说明
    name 在tasks.data中定义的属性数据,add为例外,add为新增数据项触发gantt新增弹窗,显示为一个加号
    label 标记描述
    align 文字格式
    resize 布尔值,可以拉伸内容宽度
    width 宽度,可写max _width min_width
    height 高度, 可写max _height min_height
    editor 将表格内容设置为可编辑状态,[官网描述](columns Gantt Docs (dhtmlx.com))
    template 自定义渲染内容
      //左侧显示列名
          gantt.config.columns = [
            //{ name: "add", width: 44 }
            { name: "text", min_width:100,max_width:200, label:"任务", align: "left",resize: true,  tree: true, editor: { type: 'text', map_to: 'text' } },
            { name: "id", label: "", hide: true },
            { name: "start_date", label: "开始时间", width: 120, resize: true, align: "left" },
            {
              name: "head", width: 110, height: 40, label: "负责人",resize: true, align: "left",
              // editor: {
              //   map_to: "head_id", type: "select", options: gantt.serverList("staff"),
              // },
              #这里的template渲染的是任务头像跟名称,this.genttDealById 是在methods定义的方法根据id获取名称,gantt.serverList()是甘特图获取数据集分发
              template: (item) => {
                if (this.ganttDealById(gantt.serverList('staff'), item.head_id)) {
                  return `<span class='userIcon' style='background-color:${item.color ? item.color : "#6666"}'>${this.ganttDealById(gantt.serverList('staff'), item.head_id).slice(0, 1)}</span>${this.ganttDealById(gantt.serverList('staff'), item.head_id)}`
                }
              }
            },
            // { name: "end_date", label: "结束时间", align: "center" },
            {
              name: "taskProgress", label: "任务状态", align: "center", width: 130,editor: {
                type: "select", map_to: "taskProgress", options: [
                  #这里的labels.taskProgress_0属性是自定义汉化属性描述
                  { key: "0", label: gantt.locale.labels.taskProgress_0 },
                  { key: "1", label: gantt.locale.labels.taskProgress_1 },
                  { key: "2", label: gantt.locale.labels.taskProgress_2 },
                  { key: "3", label: gantt.locale.labels.taskProgress_3 },
                  { key: "4", label: gantt.locale.labels.taskProgress_4 },
                ],
              },
                #obj形参是单个的tasks.data中的数据
              template: function (obj) {
                let re = '';
                switch (obj.taskProgress) {
                  case "0":
                    #这里的样式类名只能通过css读取,写在less scss无法读取
                    re = `<div class='taskProgress color_bg_1' >未开始</div>`
                    break;
                  case "1":
                    re = `<div class='taskProgress color_bg_2' >进行中</div>`
                    break;
                  case "2":
                    re = `<div class='taskProgress color_bg_3'  >已完成</div>`
                    break;
                  case "3":
                    re = `<div  class='taskProgress color_bg_4'>已延期</div>`
                    break;
                  case "4":
                    re = `<div  class='taskProgress color_bg_5' >搁置中</div>`
                    break;
                }
                return re
              }
            },
    
          ];
    
  • 弹窗表单----见汉化图例

      //弹出层
          gantt.config.lightbox.sections = [
            { name: "text", height: 70, map_to: "text", type: "textarea", focus: true, width: "*" },
            {
              name: "time", height: 40, map_to: "auto", type: "duration",
              time_format: ["%Y", "%m", "%d"],
            },
            {
              name: "projectClass", height: 30, map_to: "proTemplate", type: "template",
             
            },
            {
              name: "head", height: 22, map_to: "head_id", type: "select", options: gantt.serverList('staff',[]),
            },
            { name: "description", height: 70, map_to: "description", type: "textarea" },
            {
              name: "priority", height: 40, map_to: "priority", type: "radio", options: gantt.serverList("priority")
            },
    
          ];
    
  • gantt功能插件挂载

     gantt.plugins({
            click_drag: true,
            drag_timeline: true,// 拖动图
            marker: true,// 时间标记
            fullscreen: true,// 全屏
            tooltip: true,// 鼠标经过时信息
            undo: true // 允许撤销
          })
    

    收费的甘特图功能一般在这放开

常用事件
事件 参数 说明 (参数:id:数据id,item:当个数据对象,mode:拖拽模式,e:事件event)
onGanttReady 在 dhtmlx甘特图初始化完成后触发,但甘特图尚未在页面上呈现
onBeforeLightbox id 打开弹窗之前修改
onAfterTaskAdd id, item 在用户将任务添加到甘特图后触发
onAfterTaskUpdate id, item 在用户将修改甘特图任务后触发
onAfterTaskDelete id, item 在用户删除甘特图任务后触发
onAfterTaskDrag id, mode, e 在用户完成拖动并释放鼠标按钮后触发,移动滑块
onAfterLinkDelete id, item 删除连接任务的联系
onAfterLinkUpdate id, item 修改连接项目关系
onBeforeLinkAdd id, item 新增连接项目关系
onLightboxSave id, item 弹窗新增修改

甘特图常用API方法

方法 用例 说明
gantt.serverList(‘数据集名称’,'数据集') gantt,serverList("数据集名称") 返回的数据集 在甘特实例定义数据集,方便在甘特配置修改是调用
gantt.updateCollection('数据集名称',更新数据) gantt.updateCollection("staff", staffArr); 更新数据集数据
gantt.render() 更新gantt配置
gantt.clearAll() 清空gantt配置
gantt.detachEvent(’事件名) 重点 因为切换页面甘特不会销毁,调用销毁后阻止事件反复调用
gantt.scrollTo(x,y) 定位今日线功能需要,定位到某个位置
gantt.init() gantt.init(this.$refs.gantt); gantt初始化挂载节点
gantt.parse() gantt.parse({ data: [],links: [] }) gantt挂载数据
gantt.getTask() gantt.getTask(id) gantt获取单个数据

甘特图功能

今日线与定位

  // 今日线
 createTodayLine() {
      var dateToStr = gantt.date.date_to_str("%Y年%M%d日");
      var markerId = gantt.addMarker({
        id: 'markerLine',
        start_date: new Date(),
        css: "today",
        text: "今日",
        title: dateToStr(new Date()) 
      });
      gantt.updateMarker(markerId);
    }
//定位到今日线
 changeToday() {
      this.$nextTick(() => {
        let ganTT = document.getElementsByClassName('gantt_marker today')
        gantt.scrollTo(ganTT[0].offsetLeft-300, null);
      })
 },

全屏(类F11)

// 是否全屏
changeFull() {
   gantt.ext.fullscreen.toggle();
 },

搜索功能

//
<a-input allowClear v-model="searchTitle" placeholder="请输入任务名称"></a-input>
<a-button icon="search" type="primary" @click="searchDataClick">搜索</a-button>
 //点击按钮搜索
#methods
// 搜索判断数据
    hasSubstr(parentId,type){
      let task = gantt.getTask(parentId);
      if(type=='tilte'){
        if(task.text.toLowerCase().indexOf(this.searchTitle) !== -1)
          return true;
      }
      // }  
    },
    searchDataClick(){
      if(this.searchTitle  ){
        this.ganttEvent.onBeforeTaskDisplay=gantt.attachEvent("onBeforeTaskDisplay", (id, task)=>{
          if (this.hasSubstr(id,'tilte') ){ return true;}
            return false;
          });
          gantt.refreshData()
          gantt.render()
      }else{
        this.ganttEvent.onBeforeTaskDisplay=gantt.attachEvent("onBeforeTaskDisplay", (id, task)=>{
         return true
        })
        gantt.refreshData()
        gantt.render()
      }
    },

日期切换

 // 切换 年 季 月 周 日视图 
    ganttChangeDateView(type) {
      switch (type) {
        case 'y':
          gantt.config.scale_unit = "year";
          gantt.config.step = 1;
          gantt.config.subscales = null;
          gantt.config.date_scale = "%Y年";
          gantt.templates.date_scale = null;
          break;

        case 'm':
          gantt.config.scale_unit = 'month';
          gantt.config.step = 1;
          gantt.config.date_scale = "%m月";
          gantt.templates.date_scale = null;
        
          break;
        case 'w':
          gantt.config.scale_unit = 'week';
          gantt.config.step = 1;
          gantt.config.date_scale = "第%w周";
          gantt.templates.date_scale = null;
       
          break;
        case 'd':
          gantt.config.scale_unit = 'day';
          gantt.config.step = 1;
          gantt.config.date_scale = "%m月%d日";
          gantt.templates.date_scale = null;
          gantt.config.subscales = null;
          
          break;
      }
      gantt.render();
    },

图例

feature

完整代码

<template>
  <div style="height: 100%; width: 100%">
    <a-layout>
      <div class="content">
        <div style="margin: -5px 0px 5px;display: flex;justify-content: space-between;">
            <a-input allowClear v-model="searchTitle" placeholder="请输入任务名称"></a-input>
            <a-button icon="search" type="primary" @click="searchDataClick">搜索</a-button>
        </div>
        <!-- 中间 内容 -->
        <div class="centerContent">
          <!-- 甘特图 -->
          <div class="selectDate">
            <a-button @click="changeToday">今</a-button>
            <!-- 日期切换 -->
            <a-select  default-value="d" style="width: 55px;margin-left: 5px;" @change="ganttChangeDateView">
              <a-select-option value="y">年</a-select-option>
              <a-select-option value="m">月</a-select-option>
              <a-select-option value="w">周</a-select-option>
              <a-select-option value="d">日</a-select-option>
            </a-select>
            <a-button style="margin-left: 5px;" @click="changeFull"><a-icon type="fullscreen" /></a-button>
          </div>
          <div class="rightGatt" style="min-height:calc(78vh - 50px - 5px );width: 100%;overflow: hidden;" ref="gantt">
          </div>
        </div>
      </div>
    </a-layout>
  </div>
</template>
<script>

import {
  gantt
} from '@/assets/js/dhtmlx';
import "@/assets/css/dhtmlxgantt.css";
import { util } from "@/components/utils/util.js"
import moment from 'moment'

export default {
  name: "ganttChart",
  data() {
    return {
      moment,
      timer: null,//定时
      item: {},//单行数据
      searchTitle: "",//搜索标题
      tasks: {
        data: [],//数据
        links: [],//关联项目数据
      },
      savetasks: {
        data: [],
        links: []
      },//暂存空数据
      ganttServerStaff:[],//设置gantt成员数据
      selectStaff: [],//下拉成员
      staff: [],//成员
      ganttEvent: {//销毁事件
      },
      urls: {
        staff: "",//项目成员
        tasklinks: '',//gantt数据
        linksEdit: '',//修改和新增连接
        linksDelete: '',//删除连接
        addTask: '',//新增项目PUT
        editTask: '',//编辑项目put请求 tid 
        deleteTask: '',//删除项目delete tid
      }
    }
  },
  watch: {
    searchTitle(newVal,oldVal){
      this.searchTitle = newVal;
    }
  },
  mounted() {
    this.axios.get(this.urls.staff, {
        params: { projectId:  this.$store.state.project_data.id },
      }).then(res => {
        let staffArr = [];
        res.data.code = 200 && res.data.result.forEach((item, index) => {
          staffArr[index] = {};
          staffArr[index].key = item.id;
          staffArr[index].label = item.realname;
        })
        this.selectStaff = res.data.result;
        // 补充gantt数据
        this.ganttServerStaff=staffArr;
       
      })
    this.$nextTick(()=>{
      this.ganttChangeEvent();//交互事件
      this.initGantt();//初始化
      
      this.createTodayLine();//今日线
      this.ganttServerList();//服务数据
    })
    this.onQuery();//查询数据
    this.ganttChangeDateView("d");//默认日格式
  },
  methods: {
    /*
      甘特图 
     */
    // 初始化gantt
    initGantt() {
      // 清空之前的配置
      // gantt.clearAll();
   
      // 启用动态加载
      gantt.config.branch_loading = true
      //日期格式化
      gantt.config.xml_date = "%Y-%m-%d";
      gantt.config.order_branch = true;
      gantt.config.order_branch_free = true;
      //左侧是否自适应
      gantt.config.autofit = true;
      gantt.config.drag_links = true;//连线
      gantt.config.readonly = false;  //只读
      gantt.config.date_scale = "%m月%d日"; //右侧显示列名
      gantt.config.layout = {//拖拽布局
        css: "gantt_container",
        rows: [
          {
            cols: [
              { view: "grid", id: "grid", scrollX: "scrollHor", scrollY: "scrollVer" },
              { resizer: true, width: 1 },
              { view: "timeline", id: "timeline", scrollX: "scrollHor", scrollY: "scrollVer" },
              { view: "scrollbar", scroll: "y", id: "scrollVer" }
            ]
          },
          { view: "scrollbar", scroll: "x", id: "scrollHor", height: 20 }
        ]
      };
      gantt.config.start_on_monday = true;
      gantt.config.work_time = true;
      gantt.config.fit_tasks = true;   //自动调整图表坐标轴区间用于适配task的长度
    

      //汉化
      gantt.locale = {
        date: {
          month_full: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"],
          month_short: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"],
          day_full: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"],
          day_short: ["日", "一", "二", "三", "四", "五", "六"]
        },
        labels: {
          dhx_cal_today_button: "今天",
          day_tab: "日",
          week_tab: "周",
          month_tab: "月",
          new_event: "新建日程",
          icon_save: "保存",
          icon_cancel: "关闭",
          icon_details: "详细",
          icon_edit: "编辑",
          icon_delete: "删除",
          confirm_closing: "请确认是否撤销修改!", //Your changes will be lost, are your sure?
          confirm_deleting: "是否删除计划?",
          section_description: "描述:",
          section_time: "时间范围:",
          section_type: "类型:",
          section_text: "计划名称:",
          section_test: "测试:",
          section_projectClass: "项目类型:",
          taskProjectType_0: "项目任务",
          taskProjectType_1: "普通任务",
          section_head: "负责人:",
          section_priority: '优先级:',
          taskProgress: '任务状态',
          taskProgress_0: "未开始",
          taskProgress_1: "进行中",
          taskProgress_2: "已完成",
          taskProgress_3: "已延期",
          taskProgress_4: "搁置中",
          section_template: 'Details',
          /* grid columns */
          column_text: "计划名称",
          column_start_date: "开始时间",
          column_duration: "持续时间",
          column_add: "",
          column_priority: "难度",
          /* link confirmation */
          link: "关联",
          confirm_link_deleting: "将被删除",
          message_ok:'确定',
          message_cancel:'取消',
          link_start: " (开始)",
          link_end: " (结束)",

          type_task: "任务",
          type_project: "项目",
          type_milestone: "里程碑",

          minutes: "分钟",
          hours: "小时",
          days: "天",
          weeks: "周",
          months: "月",
          years: "年"
        }
      }
      gantt.serverList("priority", [
        { key: 0, label: "最高" },
        { key: 1, label: "较高" },
        { key: 2, label: "普通" },
        { key: 3, label: "较低" },
        { key: 4, label: "最低" },
      ]);
      //左侧显示列名
      gantt.config.columns = [
        { name: "text", min_width:100,max_width:200, label:"任务", align: "left",resize: true,  tree: true, editor: { type: 'text', map_to: 'text' } },
        { name: "id", label: "", hide: true },
        { name: "start_date", label: "开始时间", width: 120, resize: true, align: "left" },
        {
          name: "head", min_width: 100, height: 40, label: "负责人",resize: true, align: "left",
          // editor: {
          //   map_to: "head_id", type: "select", options: gantt.serverList("staff"),
          // },
          template: (item) => {
            if (this.ganttDealById(gantt.serverList('staff'), item.head_id)) {
              return `<span class='userIcon' style='background-color:${item.color ? item.color : "#6666"}'>${this.ganttDealById(gantt.serverList('staff'), item.head_id).slice(0, 1)}</span>${this.ganttDealById(gantt.serverList('staff'), item.head_id)}`
            }
          }
        },
        // { name: "end_date", label: "结束时间", align: "center" },
        {
          name: "taskProgress", label: "任务状态", align: "center", min_width: 110,editor: {
            type: "select", map_to: "taskProgress", options: [
              { key: "0", label: gantt.locale.labels.taskProgress_0 },
              { key: "1", label: gantt.locale.labels.taskProgress_1 },
              { key: "2", label: gantt.locale.labels.taskProgress_2 },
              { key: "3", label: gantt.locale.labels.taskProgress_3 },
              { key: "4", label: gantt.locale.labels.taskProgress_4 },
            ],
          },
          template: function (obj) {
            let re = '';
            switch (obj.taskProgress) {
              case "0":
                re = `<div class='taskProgress color_bg_1' >未开始</div>`
                break;
              case "1":
                re = `<div class='taskProgress color_bg_2' >进行中</div>`
                break;
              case "2":
                re = `<div class='taskProgress color_bg_3'  >已完成</div>`
                break;
              case "3":
                re = `<div  class='taskProgress color_bg_4'>已延期</div>`
                break;
              case "4":
                re = `<div  class='taskProgress color_bg_5' >搁置中</div>`
                break;
            }
            return re

          }
        },

      ];

      //弹出层
      gantt.config.lightbox.sections = [
        { name: "text", height: 70, map_to: "text", type: "textarea", focus: true, width: "*" },
        {
          name: "time", height: 40, map_to: "auto", type: "duration",
          time_format: ["%Y", "%m", "%d"],
        },
        {
          name: "projectClass", height: 30, map_to: "proTemplate", type: "template",
         
        },
        {
          name: "head", height: 22, map_to: "head_id", type: "select", options: gantt.serverList('staff',[]),
        },
        { name: "description", height: 70, map_to: "description", type: "textarea" },
        {
          name: "priority", height: 40, map_to: "priority", type: "radio", options: gantt.serverList("priority")
        },

      ];

      gantt.config.smart_scales = true;
      gantt.plugins({
        click_drag: true,
        drag_timeline: true,// 拖动图
        marker: true,// 时间标记
        fullscreen: true,// 全屏
        tooltip: true,// 鼠标经过时信息
        undo: true // 允许撤销
      })
      gantt.init(this.$refs.gantt);
     
    },
  
  
    // gantt数据服务列表
    ganttServerList() {
      this.getProjectStaff();//获取项目成员
      // 项目难度
      gantt.serverList("priority", [
        { key: 0, label: "最高" },
        { key: 1, label: "较高" },
        { key: 2, label: "普通" },
        { key: 3, label: "较低" },
        { key: 4, label: "最低" },
      ]);
   
    },
    // gantt交互事件注册
    ganttChangeEvent() {
      // gantt渲染
      this.ganttEvent.onGanttReady= gantt.attachEvent("onGanttReady", ()=>{
         
          //弹窗标题 日期范围
          gantt.templates.task_time = function (start, end, task) {
            return "周期:" + moment(start).format('YYYY-MM-DD') + " 至 " + moment(end).format('YYYY-MM-DD');
          };
          // 浮窗
          gantt.templates.tooltip_text = (start, end, task) => {
            return "<b>项目名称:</b> " + task.text + "<br><b>负责人:</b>" + task.head + "<br/><b>开始时间:</b> "
              + moment(start).format('YYYY-MM-DD')
              + "<br/><b>结束时间:</b> "
              + moment(new Date(end).valueOf() - 1000*60*60*24 ).format('YYYY-MM-DD');
          }
          //弹窗标题 计划名称
          gantt.templates.task_text = function (start, end, task) {
            return task.text;
          };
          gantt.templates.timeline_cell_class = function (task, date) {
            if (!gantt.isWorkTime({ task: task, date: date })) {
              return "weekend";
            } else {
              return 'weekday'
            }
          };
          gantt.templates.task_end_date = (date)=>{
            return gantt.templates.task_date(this.moment(new Date(date.valueOf() - 1000*60*60*24)).format("YYYY-MM-DD")); 
          };
          gantt.templates.grid_date_format = (date, column)=>{
            if(column === "end_date"){
                return this.moment(new Date(date.valueOf() - 1000*60*60*24)).format("YYYY-MM-DD"); 
            }else{
                return this.moment(date).format("YYYY-MM-DD"); 
            }
          }
      });
      // 修改默认弹窗
      gantt.attachEvent("onBeforeLightbox",  (id)=> {
        var task = gantt.getTask(id);
        task.proTemplate = `${gantt.locale.labels.taskProjectType_0}`
        return true;
      });

      //添加后触发
      this.ganttEvent.onAfterTaskAdd = gantt.attachEvent("onAfterTaskAdd", (id, item) => {
        clearTimeout(this.timer)
        this.timer = setTimeout(() => {
          this.dealProject("add",item)
        }, 500)

      });
      // 修改任务
      this.ganttEvent.onAfterTaskUpdate = gantt.attachEvent("onAfterTaskUpdate", (id, data) => {
        clearTimeout(this.timer)
        this.timer = setTimeout(() => {
          this.dealProject("edit", data);
          gantt.render()
        }, 500)

      });
      // 删除项目
      this.ganttEvent.onAfterTaskDelete = gantt.attachEvent("onAfterTaskDelete", (id, data) => {
        clearTimeout(this.timer)
        this.timer = setTimeout(() => {
  
          this.dealProject("delete", data);
          gantt.render();
        }, 500)
      });
      // 移动项目
      this.ganttEvent.onAfterTaskDrag = gantt.attachEvent("onAfterTaskDrag", (id, mode, e) => {
        clearTimeout(this.timer)
        this.timer = setTimeout(() => {
          var task = gantt.getTask(id);
          this.dealProject("edit", task);
          gantt.render()
        }, 500)
      });
      // 用户完成拖动并释放鼠标
      this.ganttEvent.onAfterTaskChanged = gantt.attachEvent("onAfterTaskChanged", (id, mode, task) => {
        clearTimeout(this.timer)
        this.timer = setTimeout(() => {
          gantt.render();
        }, 500)
      });

      // 删除连接项目关系
      this.ganttEvent.onAfterLinkDelete = gantt.attachEvent("onAfterLinkDelete", (id, item) => {
        clearTimeout(this.timer)
        this.timer = setTimeout(() => {
      
          let param = Object.assign({}, { projectId:this.$store.state.project_data.id }, item)
          this.axios.$delete(this.urls.linksDelete, param).then(res => {
            res.code == 200 && this.$message.success("解除成功!")
            res.code != 200 && this.$message.error("解除失败!")
          })
          gantt.render();
        }, 500)
      });
      // 修改连接项目关系
      this.ganttEvent.onAfterLinkUpdate = gantt.attachEvent("onAfterLinkUpdate", (id, item) => {
        clearTimeout(this.timer)
        this.timer = setTimeout(() => {

          let param = Object.assign({}, { projectId:this.$store.state.project_data.id }, item)
          this.axios.$put(this.urls.linksEdit, param).then(res => {
            res.code == 200 && this.$message.success("关联成功!")
            res.code != 200 && this.$message.error("关联失败!")

          })
          gantt.render()
        }, 500)
      });
      // 新增连接项目关系
      this.ganttEvent.onBeforeLinkAdd = gantt.attachEvent("onBeforeLinkAdd", (id, item) => {
        this.timer = setTimeout(() => {
          clearTimeout(this.timer)
          let param = Object.assign({}, { projectId: this.$store.state.project_data.id }, item)
          this.axios.$put(this.urls.linksEdit, param).then(res => {
            res.code == 200 && this.$message.success("关联成功!");
            res.code != 200 && this.$message.error("关联失败!");
           
          })
          gantt.render()
        }, 20)

      });
      // 保存新增
      this.ganttEvent.onLightboxSave = gantt.attachEvent("onLightboxSave", (id, item) => {
        if (!item.text) {
          this.$message.error("请填写计划名称!");
          return false;
        }
        return true;
      });

    },
    // 处理id 对应名称label
    ganttDealById(list, id) {
      for (let i = 0; i < list.length; i++) {
        if (list[i].key == id)
          return list[i].label ;
      }
      return "";
    },
    // 切换 年 季 月 周 日视图 
    ganttChangeDateView(type) {
      switch (type) {
        case 'y':
          gantt.config.scale_unit = "year";
          gantt.config.step = 1;
          gantt.config.subscales = null;
          gantt.config.date_scale = "%Y年";
          gantt.templates.date_scale = null;
          break;

        case 'm':
          gantt.config.scale_unit = 'month';
          gantt.config.step = 1;
          gantt.config.date_scale = "%m月";
          gantt.templates.date_scale = null;
        
          break;
        case 'w':
          gantt.config.scale_unit = 'week';
          gantt.config.step = 1;
          gantt.config.date_scale = "第%w周";
          gantt.templates.date_scale = null;
       
          break;
        case 'd':
          gantt.config.scale_unit = 'day';
          gantt.config.step = 1;
          gantt.config.date_scale = "%m月%d日";
          gantt.templates.date_scale = null;
          gantt.config.subscales = null;
          
          break;
      }
      gantt.render();
    },
    // 今日线
    createTodayLine() {
      var dateToStr = gantt.date.date_to_str("%Y年%M%d日");
      var markerId = gantt.addMarker({
        id: 'markerLine',
        start_date: new Date(),
        css: "today",
        text: "今日",
        title: dateToStr(new Date()) 
      });
      gantt.updateMarker(markerId);
    },
    // 是否全屏
    changeFull() {
      gantt.ext.fullscreen.toggle();
    },
    // 定位到今日线
    changeToday() {
      this.$nextTick(() => {
        let ganTT = document.getElementsByClassName('gantt_marker today')
        gantt.scrollTo(ganTT[0].offsetLeft-300, null);
      })
    },
    /* 
    操作 
    */
    //  获取项目成员
    getProjectStaff(projectID) {
      this.axios.get(this.urls.staff, {
        params: { projectId: projectID ? projectID : this.$store.state.project_data.id },
      }).then(res => {
        let staffArr = [];
        res.data.code = 200 && res.data.result.forEach((item, index) => {
          staffArr[index] = {};
          staffArr[index].key = item.id;
          staffArr[index].label = item.realname;
        })
        this.selectStaff = res.data.result;
        // 补充gantt数据
        this.ganttServerStaff=staffArr;
        gantt.updateCollection("staff", staffArr);
        gantt.render()
      })
    },
    //计算进度
    evalProgess(start,end,update) {
      if (start && end && update) {
        let start_date = this.moment(start).format("YYYY-MM-DD");
        let end_date = this.moment(end).format("YYYY-MM-DD");
        let update_date = this.moment(update).format("YYYY-MM-DD");
        
        if((new Date(end_date) - new Date(update_date)>0)){
          let process= (new Date(update_date) - new Date(start_date)) / (new Date(end_date) - new Date(start_date));
          return process.toFixed(2)
        }else {
          return 0
        }
      }

      return 0
    },
    // 获取数据
    onQuery(param) {
      gantt.clearAll();
      gantt.parse(this.savetasks);
      gantt.render();
      param = Object.assign({}, { projectId: 
        this.$store.state.project_data.id ? this.$store.state.project_data.id :'1'
      }, param)
      this.axios.get(this.urls.tasklinks, {
        params: param
      }).then(res => {
        let result = res.data.result["taskList"];
        let pushArr = [];
        this.tasks.links = res.data.result["ganttchartList"];//连接项目
        this.tasks.data = [];
        result.forEach((item, index) => {
          this.tasks.data[index] = {};
          this.tasks.data[index].id = item.tid ? item.tid : '';//项目id
          this.tasks.data[index].text = item.title ? item.title : '空标题';//标题
          this.tasks.data[index].start_date = item.startTime;//开始时间
          // 负责人--成员
          this.tasks.data[index].head_id = item.headRole?.id?item.headRole?.id:'';//负责人id
          this.tasks.data[index].head = item.headRole?.realname ? item.headRole?.realname : '';//负责人
          this.tasks.data[index].progress = this.evalProgess(item.startTime,item.endTime,item.updateTime)//项目进展
          // 后台时间加一天 显示减一天 处理条形图时间左闭右开
          this.tasks.data[index].end_date = this.moment(new Date(item.endTime).valueOf() + 1000*60*60*24).format("YYYY-MM-DD");//结束时间
          // this.tasks.data[index].end_date = item.endTime;//结束时间
          this.tasks.data[index].priority = item.priority ? item.priority : '';//任务优先级
          this.tasks.data[index].projectClass = item.type ? item.type : '';//类型 0项目任务 1 普通任务

          this.tasks.data[index].taskProgress = item.taskStatus.toString();//任务状态
          this.tasks.data[index].description = item.describe ? item.describe : '';//描述
          this.tasks.data[index].color = item.stateDictionary.color ? item.stateDictionary.color : '';//颜色
          if (item.taskList && item.taskList.length != 0) {
            this.tasks.data[index].render = "split";//显示在单行
            this.tasks.data[index].open = true;//展开
            item.taskList.forEach((_item) => {
              pushArr.push(
                {
                  id: _item.tid,
                  text: _item.title ? _item.title : '空标题',
                  start_date: _item.startTime,
                  end_date: _item.endTime,
                  head_id: _item.headId,
                  head: _item.head,
                  priority: _item.priority,
                  projectClass: _item.type,
                  taskProgress: _item.taskStatus.toString(),
                  description: _item.describe,
                  parent: _item.mainTaskId,
                }
              );
            })
          }
        });
        this.tasks.data = this.tasks.data.concat(pushArr)
       
        this.$nextTick(() => {
          gantt.parse(this.tasks);
          gantt.render();
          gantt.refreshData();
        })

      })
    },

    // 项目新增 修改tid  删除tid
    dealProject(type, data) {
      let param = {};
      if (type != 'add') {
        param.tid = data.id;
        param.title = data.text;
        param.startTime = this.moment(data.start_date).format("YYYY-MM-DD");
        param.endTime = this.moment(data.end_date).format("YYYY-MM-DD");
      
        param.describe = data.description;
        param.priority = data.priority;
      
        param.head = data.head_id;
        param.taskStatus = data.taskProgress;
        param.projectId = this.$store.state.project_data.id;
      } else {
       
        param.title = data.text;
        param.startTime = this.moment(data.start_date).format("YYYY-MM-DD");
        param.endTime = this.moment(data.end_date).format("YYYY-MM-DD");
        
        param.describe = data.description;
        param.priority = data.priority;
      
        param.head = data.head_id;
        param.taskStatus = data.taskProgress;
        param.projectId = this.$store.state.project_data.id;
      }
      let formdata=new FormData();
      for(let i in param){
        formdata.append(i,param[i])
      }
      switch (type) {
        case "add"://新增
          this.axios.put(this.urls.addTask, formdata).then(res => {
           
            res.data.code == 200 && this.$message.success("新增成功!")
            res.data.code != 200 && this.$message.error("新增失败!")
          }).catch(err => {
            this.$message.error("请求失败!")
          })
          break;
        case "edit":
          this.axios.put(this.urls.editTask, formdata).then(res => {
            res.data.code == 200 && this.$message.success("修改成功!")
            res.data.code != 200 && this.$message.error("修改失败!")
          }).catch(err => {
            this.$message.error("请求失败!")
          })
          break;
        case "delete":
          this.axios.delete(this.urls.deleteTask, formdata).then(res => {
            res.data.code == 200 && this.$message.success("删除成功!")
            res.data.code != 200 && this.$message.error("删除失败!")
          }).catch(err => {
            this.$message.error("请求失败!")
          })
          break;

      }
    },
    selecthead(val){
      
      this.searchHead=val;//id
    },
    // 搜索判断数据
    hasSubstr(parentId,type){
      let task = gantt.getTask(parentId);
      if(type=='tilte'){
        if(task.text.toLowerCase().indexOf(this.searchTitle) !== -1)
          return true;
      }
      // }  
    },
    //点击按钮搜索
    searchDataClick(){
  
      if(this.searchTitle  ){
        this.ganttEvent.onBeforeTaskDisplay=gantt.attachEvent("onBeforeTaskDisplay", (id, task)=>{
          if (this.hasSubstr(id,'tilte') ){ return true;}
            return false;
          });
          gantt.refreshData()
          gantt.render()
      }else{
        this.ganttEvent.onBeforeTaskDisplay=gantt.attachEvent("onBeforeTaskDisplay", (id, task)=>{
         return true
        })
        gantt.refreshData()
        gantt.render()
      }
    },
    // 提交弹框
    handleOk() {

      if (this.modalTitle === 1) {
        this.editForm.validateFields((err, values) => {
          if (!err) {
            Array.isArray(values.participants) && (values.participants = values.participants.join());
            values = util.transformFields(values);
            let formdata = new FormData();
            for (let key in values) {
              formdata.append(key, values[key] ? values[key] : '');
            }
            this.axios.put(this.urls.addTask, formdata).then((res) => {
              if (res.data.code === 200) {
                this.visible = false;
                let msg = res.data.message
                this.$message.success(msg)
                this.editForm.resetFields()
                this.onQuery();
              }
            })
          }
        })
      }
    },
  },

  destroyed() {
    // 销毁gantt事件
    for (let i in this.ganttEvent) {
      gantt.detachEvent(this.ganttEvent[i])
    }
   gantt.ext.tooltips.tooltip.hide();
  }
}
</script>
<style scoped lang="less">
@import url(./gantt.css);
.ant-layout {
  background: #f8f9f9;
}

.ant-layout-header {
  background: #fdffff;
  color: rgb(29, 28, 28);
  border: 1px solid #dee0e0;
}

.header {
  // position: fixed;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.content {
  background: #fdffff;
  height: 99vh;
}

// 中间
.centerContent {
  position: relative;
  background: #fdffff;
  width: 100%;
  overflow-y: auto;
  display: flex;
  justify-content: space-between;
  .selectDate {
    width: 100px;
    position: fixed;
    top: 18%;
    right: 9%;
    z-index: 99;
    display: flex;
    justify-content: space-between;
  }
}
</style>

自定义修改gantt样式文件

.weekend {
  background: #fafafa !important;
}
.weekday{
  background: #fff;
}
.gantt_resource_task .gantt_task_content {
  color: inherit;
}

.gantt_resource_task .gantt_task_progress {
  background-color: rgba(33, 33, 33, 0.3);
}
.gantt_tree_content{
  color: #808080;
}
.gantt_cell:nth-child(1) .gantt_tree_content {
  border-radius: 16px;
  width: 100%;
  height: 80%;
  margin: 5% 0;
  line-height: 230%;
}
/* 今日线 */
.gantt_marker.today{
  background: #ffb121;
}
.gantt_cell,.gantt_grid_head_cell,.gantt_grid_data,.gantt_data_area,.gantt_scale_cell{
  background-color:#fff ;
}
/* 滑块 */
.gantt_task_content{
  color: #fff;
  font-size: 13px;
  font-weight: bold;
  outline: none;
}
/* 右边单元格 */
.gantt_task_line,.gantt_task_inline_color{
  border-radius: 10px;
  box-sizing: border-box;
  border-color: #fff !important;
}
.gantt_task_scale .gantt_scale_line{
  /* border-bottom: 1px solid #e6ebf2; */
}
.gantt_row, .gantt_task_row{
  /* border-bottom: none; */
}
/* 覆盖进度条 */
.gantt_task_line.gantt_task_inline_color .gantt_task_progress{
  opacity: none;
  /* background: repeating-linear-gradient(70deg, #666 0px, #666 10px, #fff 0px,#fff 20px); */
  /* animation: ani 1.5s ease-in-out 6; */
}
@keyframes ani {
    0%{
      background: repeating-linear-gradient(70deg, #666 0px, #666 10px, #fff 0px,#fff 20px);
    }
    100%{
      background: repeating-linear-gradient(70deg, #fff 0px, #fff 10px, #666 0px,#666 20px);
    }
}
.taskProgress{
  margin: 0 auto;
  margin-top: 5px;
  height: 24px;
  width: 65px;
  font-size: 12px;
  line-height: 24px;
  font-weight: bold;
  color: #f7fbfe;
  border-radius: 20px;
}
.color_bg_1{
  background-color:#60a3bc ;
}
.color_bg_2{
  background-color:#079992 ;
}
.color_bg_3{
  background-color:#78e08f ;
}
.color_bg_4{
  background-color:#e55039 ;
}
.color_bg_5{
  background-color:#f6b93b ;
}
.gantt_task_row .gantt_task_cell,.weekday{
  outline: none;
}
.gantt_grid_scale{
  background-color: #f7fbfe !important;
}
.gantt_task_row .gantt_selected .gantt_task_cell{
  background-color: none;
  border-right-color:none;
}
.gantt_grid_scale .gantt_grid_head_cell{
  font-weight: bold;
  font-size: 14px;
  border: none;
  color:#506270;
}
/* 滑动栏 */
/* 项目icon标 */
.gantt_tree_icon{
  width: 14px;
  margin-right: 2px;
  margin-left: -8px;
}
.gantt_tree_icon.gantt_file {
  /* 文件icon */
  background-image: url(../../assets/img/file.png);
}

.gantt_tree_icon.gantt_folder_open{
  /* 文件夹icon */
  background-image: none;
}

.gantt_tree_icon.gantt_open{
  /* 加号 */
  background-image: url(../../assets//img/project.png);
}

.gantt_tree_icon.gantt_close{
  /* 减号 */
  background-image: none;
}

.userIcon{
  display: inline-block;
  width: 25px;
  height: 25px;
  margin-right: 5px;
  text-align: center;
  line-height: 25px;
  color: #fafafa;
  border-radius: 50%;
}
#search{
  margin-left: 10px;
  outline: none;
  border: none;
  font-size: 12px;
  color: #666666;
}
/*定义滚动条宽高及背景,宽高分别对应横竖滚动条的尺寸*/
*::-webkit-scrollbar {
  width: 10px;
  height: 10px;
  background-color: rgba(255, 255, 255, 0);
}

/*定义滚动条的轨道,内阴影及圆角*/
*::-webkit-scrollbar-track {
  border-radius: 10px;
  background-color: rgba(230, 230, 230, 0.05);
}

*:hover::-webkit-scrollbar-track {
  background-color: rgba(230, 230, 230, 0.5);
}

/*定义滑块,内阴影及圆角*/

*::-webkit-scrollbar-thumb {
  height: 20px;
  border-radius: 10px;
  -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0);
  background-color: rgba(216, 216, 216, 0.4);
  transition: background-color 1s;
}

*:hover::-webkit-scrollbar-thumb {
  background-color: rgba(216, 216, 216, 1);
}

*::-webkit-scrollbar-thumb:hover {
  background-color: rgba(190, 190, 190, 1);
}

*::-webkit-scrollbar-thumb:active {
  background-color: rgba(160, 160, 160, 1);
}

标签:实现,config,dhtmlx,甘特图,item,gantt,date,data,id
From: https://www.cnblogs.com/lht1132950411/p/17296046.html

相关文章

  • 直播app开发,使用koa和MongoDB实现分页和模糊查询
    直播app开发,使用koa和MongoDB实现分页和模糊查询1.分页per_page:一页多少条数据page:第几页 //index.jsconstKoa=require('koa')constapp=newKoa()constRouter=require('koa-router')constusersRouter=newRouter({prefix:'/users'})//MongoDB数据库Us......
  • Chrome 发布首个 WebGPU 实现
    Chrome团队宣布,经过多年的开发,他们终于发布了WebGPU实现,目前已在Chrome113Beta中默认启用。WebGPU可用于在Web上进行高性能3D图形和数据并行计算。WebGPU初始版本可以在ChromeOS、macOS和Windows上使用,对其他平台的支持将于今年晚些时候推出。WebGPU是由......
  • 【Spring AOP基础使用:认识AOP,AOP作用,核心概念,AOP实现】
    本文纲要一、了解AOP1、认识AOP2、AOP作用3、AOP核心概念二、AOP快速入门1、基础准备2、AOP实现3、总结三、AOP获取通知数据1、JoinPoint2、ProceedingJoinPoint3、获取通知数据的使用场景进入正文:一、了解AOP1、认识AOPAOP(AspectOrientedProgramming)面向切面编程,一种......
  • AgileSecu 案例分享 | Bot Manger 为欧洲跨境电商实现网络安全与用户体验的双赢
    01客户概述客户是欧洲一家大型的跨境电商,每年的客流量超过1000万,业务遍布全球200多个国家和地区,每年的收入同比增长50%以上。此外,为了提高用户留存率和企业口碑,客户自身还制定了用户忠诚度奖励计划,并定期举办慈善活动。 02客户挑战在与客户初步沟通中,我们了解到客户希望使......
  • BF算法的实现:病毒感染检测
    一、问题引入BF(Brute-Force)算法介绍了BF算法的具体实现,但并未结合具体案例。本随笔就是结合案例(病毒感染检测)对BF算法进行结合分析。案例4.1:病毒感染检测医学研究者最近发现了某些新病毒,通过对这些病毒的分析,得知它们的DNA序列都是环状的。现在研究者巳收集了大量的病毒......
  • 改进蚁群算法 Dijkstra算法 遗传算法 人工势场法实现二维 三维空间路径规划
    【蚁群算法】改进蚁群算法Dijkstra算法遗传算法人工势场法实现二维三维空间路径规划本程序为蚁群算法+Dijkstra算法+MAKLINK图理论实现的二维空间路径规划算法实现:1)基于MAKLINK图理论生成地图,并对可行点进行划分;2)用Dijkstra算法实现次优路径的寻找;3)在Dijkstra算法的基......
  • canvas实现图片镜像翻转的2种方式
    canvas实现图片镜像翻转的2种方式原文引用:https://www.qetool.com/scripts/view/23387.html1.通过canvas自带的画布方法进行翻转varimg=newImage();//这个就是img标签的dom对象img.src='./sy.png';img.onload=function(){//图片加载完成后,执行此方......
  • Handler与Message类,实现n秒后无操作自动消失功能
    实现功能:某控件不操作10秒后,自动消失。如照相机变焦条出现后,无操作10秒自动隐藏。所用知识:handler  message//定义变量privateEffectInVisiableHandlermtimeHandler;privatefinalintMOBILE_QUERY=1;//程序启动时,初始化并发送消......
  • (C#)Random实现随机点名
    namespaceWindowsFormsApp3{publicpartialclassForm1:Form{//实例化字符串,设置字符串长度与内容string[]student=newstring[7]{"张三","李四","王五","赵六","hello","world","helloworl......
  • 怎么样用css样式实现一个三角形?
    <!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metahttp-equiv="X-UA-Compatible"content="IE=edge"><metaname="viewport"content="width=device-......