lsc 1 year ago
parent
commit
8257f980fd

+ 64 - 0
package-lock.json

@@ -10,9 +10,11 @@
       "dependencies": {
         "axios": "^0.21.3",
         "big.js": "^6.2.1",
+        "dayjs": "^1.11.7",
         "echarts": "^5.2.2",
         "element-ui": "^2.15.6",
         "file-saver": "^2.0.5",
+        "gantt-elastic": "^1.0.12",
         "hevue-img-preview": "^5.0.3",
         "html-docx-js": "^0.3.1",
         "html2canvas": "^1.4.1",
@@ -24,6 +26,7 @@
         "pdfvuer": "^1.7.5",
         "qrcodejs2": "^0.0.2",
         "recordrtc": "^5.6.2",
+        "relation-graph": "^2.0.26",
         "vue": "^2.5.2",
         "vue-cookies": "^1.7.4",
         "vue-jsmind": "^1.5.0",
@@ -10045,6 +10048,11 @@
       "integrity": "sha1-dxY+qcINhkG0cH6PGKvfmnjzSDU=",
       "dev": true
     },
+    "node_modules/dayjs": {
+      "version": "1.11.7",
+      "resolved": "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.7.tgz",
+      "integrity": "sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ=="
+    },
     "node_modules/de-indent": {
       "version": "1.0.2",
       "resolved": "https://registry.nlark.com/de-indent/download/de-indent-1.0.2.tgz",
@@ -11883,6 +11891,16 @@
       "resolved": "https://registry.npm.taobao.org/function-bind/download/function-bind-1.1.1.tgz",
       "integrity": "sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0="
     },
+    "node_modules/gantt-elastic": {
+      "version": "1.0.12",
+      "resolved": "https://registry.npmmirror.com/gantt-elastic/-/gantt-elastic-1.0.12.tgz",
+      "integrity": "sha512-PZHbADMGlVcTHKVqtvLNg8bvUGqeeSmDMVCQscyVBxNKd4Wwmvht4eNiTlasLW2ceufLN7BKziGZ9AJP28nJiw==",
+      "dependencies": {
+        "dayjs": "^1.8.16",
+        "resize-observer-polyfill": "^1.5.1",
+        "vue": "^2.6.10"
+      }
+    },
     "node_modules/gensync": {
       "version": "1.0.0-beta.2",
       "resolved": "https://registry.npmmirror.com/gensync/-/gensync-1.0.0-beta.2.tgz",
@@ -19770,6 +19788,15 @@
         "node": ">= 0.10"
       }
     },
+    "node_modules/relation-graph": {
+      "version": "2.0.26",
+      "resolved": "https://registry.npmmirror.com/relation-graph/-/relation-graph-2.0.26.tgz",
+      "integrity": "sha512-GaxXF430Z3vN5RU2wem2Zi9gfzAUPoxsLIStQi0vfqVOos7p0zz7RGw8eVX7K+hLvfp3PJCH3/Jeg0r6PLVuXQ==",
+      "dependencies": {
+        "html2canvas": "^1.4.1",
+        "screenfull": "^5.1.0"
+      }
+    },
     "node_modules/remove-trailing-separator": {
       "version": "1.1.0",
       "resolved": "https://registry.npm.taobao.org/remove-trailing-separator/download/remove-trailing-separator-1.1.0.tgz",
@@ -20073,6 +20100,14 @@
       "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=",
       "dev": true
     },
+    "node_modules/screenfull": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmmirror.com/screenfull/-/screenfull-5.2.0.tgz",
+      "integrity": "sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
     "node_modules/select-hose": {
       "version": "2.0.0",
       "resolved": "https://registry.npm.taobao.org/select-hose/download/select-hose-2.0.0.tgz",
@@ -32306,6 +32341,11 @@
       "integrity": "sha1-dxY+qcINhkG0cH6PGKvfmnjzSDU=",
       "dev": true
     },
+    "dayjs": {
+      "version": "1.11.7",
+      "resolved": "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.7.tgz",
+      "integrity": "sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ=="
+    },
     "de-indent": {
       "version": "1.0.2",
       "resolved": "https://registry.nlark.com/de-indent/download/de-indent-1.0.2.tgz",
@@ -33819,6 +33859,16 @@
       "resolved": "https://registry.npm.taobao.org/function-bind/download/function-bind-1.1.1.tgz",
       "integrity": "sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0="
     },
+    "gantt-elastic": {
+      "version": "1.0.12",
+      "resolved": "https://registry.npmmirror.com/gantt-elastic/-/gantt-elastic-1.0.12.tgz",
+      "integrity": "sha512-PZHbADMGlVcTHKVqtvLNg8bvUGqeeSmDMVCQscyVBxNKd4Wwmvht4eNiTlasLW2ceufLN7BKziGZ9AJP28nJiw==",
+      "requires": {
+        "dayjs": "^1.8.16",
+        "resize-observer-polyfill": "^1.5.1",
+        "vue": "^2.6.10"
+      }
+    },
     "gensync": {
       "version": "1.0.0-beta.2",
       "resolved": "https://registry.npmmirror.com/gensync/-/gensync-1.0.0-beta.2.tgz",
@@ -40336,6 +40386,15 @@
       "resolved": "https://registry.npm.taobao.org/relateurl/download/relateurl-0.2.7.tgz",
       "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk="
     },
+    "relation-graph": {
+      "version": "2.0.26",
+      "resolved": "https://registry.npmmirror.com/relation-graph/-/relation-graph-2.0.26.tgz",
+      "integrity": "sha512-GaxXF430Z3vN5RU2wem2Zi9gfzAUPoxsLIStQi0vfqVOos7p0zz7RGw8eVX7K+hLvfp3PJCH3/Jeg0r6PLVuXQ==",
+      "requires": {
+        "html2canvas": "^1.4.1",
+        "screenfull": "^5.1.0"
+      }
+    },
     "remove-trailing-separator": {
       "version": "1.1.0",
       "resolved": "https://registry.npm.taobao.org/remove-trailing-separator/download/remove-trailing-separator-1.1.0.tgz",
@@ -40594,6 +40653,11 @@
         }
       }
     },
+    "screenfull": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmmirror.com/screenfull/-/screenfull-5.2.0.tgz",
+      "integrity": "sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA=="
+    },
     "select-hose": {
       "version": "2.0.0",
       "resolved": "https://registry.npm.taobao.org/select-hose/download/select-hose-2.0.0.tgz",

+ 3 - 0
package.json

@@ -14,9 +14,11 @@
   "dependencies": {
     "axios": "^0.21.3",
     "big.js": "^6.2.1",
+    "dayjs": "^1.11.7",
     "echarts": "^5.2.2",
     "element-ui": "^2.15.6",
     "file-saver": "^2.0.5",
+    "gantt-elastic": "^1.0.12",
     "hevue-img-preview": "^5.0.3",
     "html-docx-js": "^0.3.1",
     "html2canvas": "^1.4.1",
@@ -28,6 +30,7 @@
     "pdfvuer": "^1.7.5",
     "qrcodejs2": "^0.0.2",
     "recordrtc": "^5.6.2",
+    "relation-graph": "^2.0.26",
     "vue": "^2.5.2",
     "vue-cookies": "^1.7.4",
     "vue-jsmind": "^1.5.0",

BIN
src/assets/icon/allTime.png


BIN
src/assets/icon/endTime.png


BIN
src/assets/icon/proMan.png


BIN
src/assets/icon/startTime.png


BIN
src/assets/icon/task copy.png


BIN
src/assets/icon/tupu.png


+ 384 - 0
src/components/components/ganChart.vue

@@ -0,0 +1,384 @@
+<template>
+  <div class="ganCss">
+    <!-- v-show="showGantt" -->
+    <gantt-elastic :options="options" :tasks="tasks" @tasks-changed="tasksUpdates" @options-changed="optionsUpdate"
+      @dynamic-style-changed="styleUpdate">
+    </gantt-elastic>
+
+    <!-- -->
+  </div>
+</template>
+
+<style>
+
+</style>
+<script>
+import GanttElastic from "gantt-elastic";
+import dayjs from "dayjs";
+// import GanttHeader from "gantt-elastic-header";
+
+//tasks是数据 真实的项目需要接口赋值数据
+let that;
+let options = {
+  taskMapping: {
+    progress: "percent",
+  },
+  maxRows: 10,
+  maxHeight: 500,
+  // title: {
+  //   label: "Your project title as html (link or whatever...)",
+  //   html: false
+  // },
+  row: {
+    height: 30, //设置行高
+  },
+  times: {
+    timeScale: 60 * 1000,
+    timeZoom: 20,
+  },
+
+  chart: {
+    grid: {
+      horizontal: {
+        gap: 6, //*
+      },
+    },
+    text: {
+      offset: 4, //*
+      xPadding: 10, //*
+      display: true, //*
+    },
+
+    expander: {
+      type: "chart",
+      display: true, //*
+      displayIfTaskListHidden: true, //*
+      offset: 4, //*
+      size: 18,
+    },
+  },
+
+  taskList: {
+    // expander: {
+    //   straight: true,
+    // },
+    columns: [
+      {
+        id: 2,
+        label: "任务描述",
+        value: "label2",
+        width: 300,
+        expander: true,
+        html: true,
+        events: {
+          click({ data, column }) {
+            if (that.flags != "1") {
+              that.showDialog(data);
+            }
+          },
+        },
+      },
+      {
+        id: 4,
+        label: "开始时间",
+        value: 'start',
+        width: 78,
+      },
+      {
+        id: 5,
+        label: "结束时间",
+        value: 'end',
+        width: 78,
+      },
+    ],
+  },
+
+  calendar: {
+    workingDays: [1, 2, 3, 4, 5, 6], //*
+    gap: 0,
+    strokeWidth: 5,
+    hour: {
+      display: false,
+    },
+  },
+
+  locale: {
+    weekdays: ["周日", "周一", "周二", "周三", "周四", "周五", "周六"],
+    months: [
+      "一月",
+      "二月",
+      "三月",
+      "四月",
+      "五月",
+      "六月",
+      "七月",
+      "八月",
+      "九月",
+      "十月",
+      "十一月",
+      "十二月",
+    ],
+  },
+};
+export default {
+  props: ['Json'],
+  //   name: "Gantt",
+  components: {
+    GanttElastic,
+    // GanttHeader
+  },
+  // props: {
+  //   gantData: {},
+  //   flags: {
+  //     type: String,
+  //   },
+  // },
+  data() {
+    return {
+      showGantt: false,
+      dialogVisible: false,
+      orderModal: false,
+      TaskData: [],
+      sontaskData: "",
+      tasks: [
+        // {
+        //   id: 1,
+        //   label: "项目一",
+        //   start: this.getTody(new Date(), 4),
+        //   end: this.getTody(new Date(), -30),
+        //   duration: 30 * 24 * 60 * 60 * 1000,
+        //   percent: 85,
+        //   type: "task",
+        //   style: {
+        //     base: {
+        //       fill: "#4a83d0",
+        //       stroke: "#4a83d0",
+        //     },
+        //   },
+        // },
+        // {
+        //   id: 2,
+        //   label: "项目二",
+        //   start: this.getTody(new Date(), 10),
+        //   end: this.getTody(new Date(), -50),
+        //   duration: 30 * 24 * 60 * 60 * 1000,
+        //   percent: 85,
+        //   type: "task",
+        //   style: {
+        //     base: {
+        //       fill: "#4a83d0",
+        //       stroke: "#4a83d0",
+        //     },
+        //   },
+        // },
+        // {
+        //   id: 3,
+        //   label: "项目三",
+        //   start: this.getTody(new Date(), 15),
+        //   end: this.getTody(new Date(), -80),
+        //   duration: 30 * 24 * 60 * 60 * 1000,
+        //   percent: 85,
+        //   type: "task",
+        //   style: {
+        //     base: {
+        //       fill: "#4a83d0",
+        //       stroke: "#4a83d0",
+        //     },
+        //   },
+        // },
+        // {
+        //   id: 4,
+        //   label: "项目四",
+        //   start: this.getTody(new Date(), 7),
+        //   end: this.getTody(new Date(), -15),
+        //   duration: 30 * 24 * 60 * 60 * 1000,
+        //   percent: 85,
+        //   type: "task",
+        //   style: {
+        //     base: {
+        //       fill: "#4a83d0",
+        //       stroke: "#4a83d0",
+        //     },
+        //   },
+        // },
+        // {
+        //   id: 5,
+        //   label: "项目五",
+        //   start: this.getTody(new Date(), 3),
+        //   end: this.getTody(new Date(), -40),
+        //   duration: 30 * 24 * 60 * 60 * 1000,
+        //   percent: 85,
+        //   type: "task",
+        //   style: {
+        //     base: {
+        //       fill: "#4a83d0",
+        //       stroke: "#4a83d0",
+        //     },
+        //   },
+        // },
+      ],
+      options,
+      dynamicStyle: {},
+      successStyle: {
+        base: {
+          fill: "#4a83d0",
+          stroke: "#4a83d0",
+          height: 20,
+        },
+      },
+      unfinishedStyle: {
+        base: {
+          fill: "#4a83d0",
+          stroke: "#4a83d0",
+        },
+      },
+      comName: "newSelectProdct",
+      titles: "新品选品",
+      flag: true,
+    };
+  },
+  created() { },
+  mounted() {
+    this.getTaskList();
+  },
+  computed: {},
+  watch: {
+    Json: {
+      immediate: true,
+      deep: true,
+      handler(newValue, oldValue) {
+        var unitJson = this.Json
+        this.tasks = []
+        for (var i = 0; i < unitJson.length; i++) {
+          let task = unitJson[i].chapterInfo[0].taskJson
+          this.tasks.push({
+              id: i ,
+              label2: '第' + (i + 1) + '阶段',
+              label: this.datedifference('', ''),
+              start: '',
+              end: '',
+              percent: 85,
+              type: "task",
+              style: {
+                base: {
+                  fill: "#4a83d0",
+                  stroke: "#4a83d0",
+                },
+              },
+            })
+          for (var j = 0; j < task.length; j++) {
+            this.tasks.push({
+              id: i + '-' + j,
+              label2: '任务' + (j + 1) + '-' + task[j].task,
+              label: this.datedifference(task[j].time ? task[j].time[0] : '', task[j].time ? task[j].time[1] : ''),
+              start: this.getTody(task[j].time ? task[j].time[0] : ''),
+              end: this.getTody(task[j].time ? task[j].time[1] : ''),
+              parentId:i,
+              percent: 85,
+              type: "task",
+              style: {
+                base: {
+                  fill: "#4a83d0",
+                  stroke: "#4a83d0",
+                },
+              },
+            })
+          }
+        }
+      }
+    }
+  },
+  methods: {
+    handleClose() {
+      this.dialogVisible = false;
+    },
+    getTody(n, ds = 0, ys = 0) {
+      var now = new Date(n);
+      var time = now - 24 * 60 * 60 * 1000 * ds; //获取前N天
+      var d = new Date(time);
+      var year = d.getFullYear() - ys; //获取前N年的时间
+      var mon = d.getMonth() + 1;
+      var day = d.getDate();
+      var week = d.getDay();
+      var hour = d.getHours();
+      var secd = d.getMinutes();
+      var week = d.getDay();
+      var times = "";
+      if (mon == 0) {
+        times = 12 + "-" + (day < 10 ? "0" + day : day);
+      } else if (mon < 10) {
+        times =
+          (mon < 10 ? "0" + mon : mon) + "-" + (day < 10 ? "0" + day : day);
+      } else {
+        times = mon + "-" + (day < 10 ? "0" + day : day);
+      }
+      var today = year + "-" + times;
+
+      return year ? today : '无';
+    },
+    //计算时间差
+    datedifference(date1, date2) {
+      //sDate1和sDate2是2006-12-18格式
+      var dateSpan, tempDate, iDays;
+      var sDate1 = this.getTody(date1);
+      sDate1 = Date.parse(sDate1);
+      var sDate2 = this.getTody(date2);
+      sDate2 = Date.parse(sDate2);
+      dateSpan = sDate2 - sDate1;
+      dateSpan = Math.abs(dateSpan);
+      iDays = Math.floor(dateSpan / (24 * 3600 * 1000));
+      return iDays ? iDays + '天' : "";
+    },
+    //获取数据-----------------------------------------------------
+    getTaskList() {
+      var unitJson = this.Json
+      this.tasks = []
+      for (var i = 0; i < unitJson.length; i++) {
+        let task = unitJson[i].chapterInfo[0].taskJson
+        for (var j = 0; j < task.length; j++) {
+          this.tasks.push({
+            id: i + '-' + j,
+            label2: '第' + (i + 1) + '阶段-' + '任务' + (j + 1) + '-' + task[j].task,
+            label: this.datedifference(task[j].time ? task[j].time[0] : '', task[j].time ? task[j].time[1] : ''),
+            start: this.getTody(task[j].time ? task[j].time[0] : ''),
+            end: this.getTody(task[j].time ? task[j].time[1] : ''),
+            percent: 85,
+            type: "task",
+            style: {
+              base: {
+                fill: "#4a83d0",
+                stroke: "#4a83d0",
+              },
+            },
+          })
+        }
+      }
+    },
+    //点击弹出-----------------------------------------------------
+    showDialog(data) { },
+
+    tasksUpdates(tasks, num) {
+      if (num == 2) {
+        // this.tasks = [];
+        this.tasks = tasks;
+      } else {
+        return;
+      }
+    },
+    optionsUpdate(options, num) {
+      if (num == 2) {
+        this.options = options;
+      }
+    },
+    styleUpdate(style) {
+      this.dynamicStyle = style;
+    },
+  },
+};
+</script>
+<style scoped>
+.ganCss >>> .gantt-elastic__task-list-header{
+  min-height: 40px;
+}
+</style>
+

+ 62 - 0
src/components/components/graph.vue

@@ -0,0 +1,62 @@
+<template>
+    <div style="width: 100%; max-height: 600px; overflow: auto;padding-bottom: 10px;" class="content">
+        <div style="height:600px;position: relative;">
+            <RelationGraph ref="seeksRelationGraph" :options="graphOptions" :on-node-click="onNodeClick"
+                :on-line-click="onLineClick" />
+        </div>
+    </div>
+</template>
+
+<script>
+import RelationGraph from 'relation-graph'
+
+export default {
+    props: ['Json'],
+    components: {
+        RelationGraph,
+    },
+    data() {
+        return {
+            graphOptions: {
+                allowSwitchLineShape: true,
+                zoomToFitWhenRefresh: true,
+                moveToCenterWhenRefresh: true,
+                // allowSwitchJunctionPoint: true,
+                defaultJunctionPoint: 'border'
+                // 这里可以参考"Graph 图谱"中的参数进行设置
+            }
+        }
+    },
+    mounted() {
+        this.showSeeksGraph()
+    },
+    watch: {
+        Json: {
+            immediate: true,
+            deep: true,
+            handler(newValue, oldValue) {
+                this.Json = newValue
+                this.showSeeksGraph()
+            }
+        }
+    },
+    methods: {
+        showSeeksGraph() {
+            const __graph_json_data = this.Json
+            // 以上数据中的node和link可以参考"Node节点"和"Link关系"中的参数进行配置 
+            this.$refs.seeksRelationGraph.setJsonData(__graph_json_data, (seeksRGGraph) => {
+                // Called when the relation-graph is completed 
+            })
+        },
+        onNodeClick(nodeObject, $event) {
+            console.log('onNodeClick:', nodeObject)
+        },
+        onLineClick(lineObject, $event) {
+            console.log('onLineClick:', lineObject)
+        }
+    }
+}
+
+</script>
+
+<style></style>

+ 246 - 0
src/components/components/proMan.vue

@@ -0,0 +1,246 @@
+<template>
+  <div style="width: 100%; max-height: 600px; overflow: auto;padding-bottom: 10px;" class="content">
+    <div v-for="(item, index) in Json" :key="index" class="bigBox">
+      <div v-for="(item2, index2) in item.chapterInfo[0].taskJson" :key="index + '-' + index2" class="taskBox">
+        <div class="rwBox">
+          <div class="rwTop">
+            <div class="rwTouImg"></div>
+            <div>{{ getMan(item2.people) }}</div>
+          </div>
+          <div class="rwTop" v-if="item2.tcMember && item2.tcMember.length">
+            <div class="rwTouImg" style="background:#ff9219"></div>
+            <!-- <div class="xtBox"><span class="tcMember" v-for="(mam, mIndex) in item2.tcMember" :key="mIndex">{{ getMan(mam) }}</span>
+            </div> -->
+            <el-tooltip :content="getMen(item2.tcMember)" placement="top" effect="dark">
+              <div class="xtBox"><span class="tcMember" v-for="(mam, mIndex) in getMan2(item2.tcMember)" :key="mIndex">{{
+                mam
+              }}</span>
+              </div>
+            </el-tooltip>
+          </div>
+          <div class="rwTop" v-else>
+            <div class="rwTouImg" style="background:#ff9219"></div>
+            <div><span class="tcMember">无</span></div>
+          </div>
+          <div class="rwMidBox">
+            <div>{{ item2.task }}</div>
+            <div class="rwMessage">
+              <div class="rwBoxMessage">
+                <div class="rwIcon">
+                  <img src="../../assets/icon/startTime.png" alt="" />
+                </div>
+                <div>开始时间:{{ timeB(item2.time ? item2.time[0] : '') }} </div>
+              </div>
+              <div class="rwBoxMessage">
+                <div class="rwIcon">
+                  <img src="../../assets/icon/endTime.png" alt="" />
+                </div>
+                <div>完成时间:{{ timeB(item2.time ? item2.time[1] : '') }} </div>
+              </div>
+              <div class="rwBoxMessage">
+                <div class="rwIcon">
+                  <img src="../../assets/icon/allTime.png" alt="" />
+                </div>
+                <div>所需时长:{{ timeA(item2.time ? item2.time[0] : '', item2.time ? item2.time[1] : '') }}天</div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  props: ['Json', 'ManAarray'],
+  data() {
+    return {
+      ManAarray2: []
+    };
+  },
+  computed: {
+    timeA() { //此处不需要携带参数
+      return function (startTime, endTime) {
+        var day =
+          new Date(endTime).getTime() - new Date(startTime).getTime(); //日期转时间戳
+        var time = Math.floor(day / 86400000);
+        return time ? time : '0'
+      }
+    },
+    timeB() {
+      return function (timeA) {
+        var time = new Date(timeA);
+        time.setTime(time.getTime());
+        var s2 = time.getFullYear() + "-" + ((time.getMonth() + 1) < 10 ? '0' + (time.getMonth() + 1) : (time.getMonth() + 1)) + "-"
+          + ((time.getDate()) < 10 ? '0' + (time.getDate()) : (time.getDate()));
+        return time.getFullYear() ? s2 : '无'
+      }
+    },
+    getMen() {
+      return function (people) {
+        let _people = people
+        let kp = []
+        if (this.ManAarray.length) {
+          for (var k = 0; k < _people.length; k++) {
+            let person = _people[k]
+            for (var i = 0; i < this.ManAarray.length; i++) {
+              if (this.ManAarray[i].userid == person) {
+                // _people = this.ManAarray[i].name;
+                kp.push(this.ManAarray[i].name)
+                break;
+              }
+            }
+          }
+        }
+        return this.ManAarray.length ? (kp.length ? kp.join('、') : '') : ''
+      }
+    },
+    getMan() {
+      return function (people) {
+        let _people = ''
+        if (this.ManAarray2.length) {
+          for (var i = 0; i < this.ManAarray2.length; i++) {
+            if (this.ManAarray2[i].userid == people) {
+              _people = this.ManAarray2[i].name;
+              break;
+            }
+          }
+        }
+        return _people ? _people : '无'
+      }
+    },
+    getMan2() {
+      return function (people) {
+        let _people = people
+        let kp = []
+        if (this.ManAarray.length) {
+          for (var k = 0; k < _people.length; k++) {
+            let person = _people[k]
+            for (var i = 0; i < this.ManAarray.length; i++) {
+              if (this.ManAarray[i].userid == person) {
+                // _people = this.ManAarray[i].name;
+                kp.push(this.ManAarray[i].name)
+                break;
+              }
+            }
+          }
+        }
+        return kp.length ? kp : ['无']
+      }
+    },
+  },
+  watch: {
+    ManAarray: {
+      immediate: true,
+      deep: true,
+      handler(newValue, oldValue) {
+        this.ManAarray2 = newValue
+      }
+    }
+  },
+  methods: {
+  },
+  created() {
+  },
+};
+</script>
+
+<style scoped>
+.content {
+  display: flex;
+}
+
+.bigBox {
+  padding-bottom: 11px;
+  height: 100%;
+}
+
+.bigBox+.bigBox {
+  margin-left: 10px;
+}
+
+.taskBox+.taskBox {
+  margin-top: 10px;
+}
+
+.rwBox {
+  width: 280px;
+  background: #fff;
+}
+
+.rwTop {
+  display: flex;
+  flex-direction: row;
+  flex-wrap: nowrap;
+  align-items: top;
+}
+
+.rwTop+.rwTop {
+  margin-top: 5px;
+}
+
+.rwTouImg {
+  min-width: 13px;
+  height: 13px;
+  background: #0258f1 100%;
+  border-radius: 50%;
+  margin: 5px 10px 0;
+}
+
+.rwMidBox {
+  border: 2px solid #e3e6e8;
+  width: 270px;
+  margin-top: 10px;
+  border-radius: 15px;
+  background: #f6f6f640;
+}
+
+.rwMidBox>div:nth-child(1) {
+  font-weight: bold;
+  margin: 15px 0 0 0;
+  padding: 0 10px;
+}
+
+.rwMessage {
+  margin-top: 5px;
+  padding: 0 10px 10px 10px;
+}
+
+.rwBoxMessage {
+  display: flex;
+  flex-direction: row;
+  flex-wrap: nowrap;
+  align-items: center;
+  padding: 10px 0;
+}
+
+.rwIcon {
+  width: 20px;
+  height: 20px;
+  /* background: #000;
+  border-radius: 50%; */
+  margin-right: 5px;
+}
+
+.rwIcon>img {
+  width: 100%;
+  height: 100%;
+  object-fit: cover;
+}
+
+.rwBoxMessage>div:nth-child(2) {
+  font-size: 12px;
+}
+
+.tcMember+.tcMember::before {
+  content: '、';
+}
+
+.xtBox {
+  max-width: 100%;
+  overflow: hidden;
+  white-space: nowrap;
+  text-overflow: ellipsis;
+}
+</style>

+ 17 - 2
src/components/noTerminal/studyStudent.vue

@@ -1718,7 +1718,7 @@
                                                             " v-for="(w, wIndex) in worksTeacher[toolIndex]"
                       :key="wIndex" :class="w.type == 1 ? 'isTypeOne' : ''">
                       <div class="workImg">
-                        <img :src="word" @click="openTable(w)" alt />
+                        <img :src="word" @click="openWord(w)" alt />
                         <!-- @click="openFile(w.works)" -->
                         <div class="answerScore" v-if="w.score" @click.stop="openScore(w)" :class="{
                             rightW:
@@ -3203,7 +3203,7 @@
                                                               : worksStudent2[toolIndex].slice(0, 6)" :key="wIndex"
                       :class="w.type == 1 ? 'isTypeOne' : ''">
                       <div class="workImg">
-                        <img :src="word" @click="openTable(w)" alt />
+                        <img :src="word" @click="openWord(w)" alt />
                         <!-- @click="openFile(w.works)" -->
                         <div class="answerScore" v-if="w.score" @click.stop="openScore(w)" :class="{
                             rightW:
@@ -4636,6 +4636,15 @@
         <el-button @click="dialogVisibleTable2 = false">关 闭</el-button>
       </span>
     </el-dialog>
+    <el-dialog title="文档" :visible.sync="dialogVisibleTable3" :append-to-body="true" width="95%"
+      :before-close="handleClose" class="dialog_diy">
+      <el-form>
+        <div class="cont" v-html="tableJson.text"></div>
+      </el-form>
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="dialogVisibleTable3 = false">关 闭</el-button>
+      </span>
+    </el-dialog>
     <el-dialog title="分组设置" :visible.sync="dialogVisibleGroup" :append-to-body="true" width="95%"
       :before-close="handleClose" class="dialog_diy">
       <div v-if="dialogVisibleGroup">
@@ -5176,6 +5185,7 @@ export default {
       dialogVisibleWord: false,
       dialogVisibleWordTeacher: false,
       dialogVisibleTable2: false,
+      dialogVisibleTable3: false,
       dialogVisibleGroupWork: false,
       dialogVisibleUpdateGroup: false,
       dialogVisibleDeleteGroup: false,
@@ -9118,6 +9128,11 @@ export default {
       this.$forceUpdate();
       this.dialogVisibleTable2 = true;
     },
+    openWord(f) {
+      this.tableJson = JSON.parse(f.works);
+      this.$forceUpdate();
+      this.dialogVisibleTable3 = true;
+    },
     doUrl(url, i) {
       this.isClickNav = "";
       this.pptImgUrl1 = "";

+ 55 - 100
src/components/student/courseDetail.vue

@@ -20,19 +20,18 @@
               '&screenType=' +
               screenType
             )
-          ">
+            ">
             返回
           </div>
           <div class="box_course">
             <div class="wheel">
-              <img style="object-fit: cover" :src="
-                this.courseDetail.cover != null &&
+              <img style="object-fit: cover" :src="this.courseDetail.cover != null &&
                   this.courseDetail.cover != ''
                   ? JSON.parse(this.courseDetail.cover).length > 0
                     ? JSON.parse(this.courseDetail.cover)[0].url
                     : mr
                   : mr
-              " alt />
+                " alt />
             </div>
             <div class="right_box">
               <div class="rightT">
@@ -50,22 +49,24 @@
               <div class="cType" style="font-size: 18px; color: #6c6c6c">
                 <div style="min-width:150px">
                   创建者:<span style="color: #000">{{
-                      courseDetail.username
+                    courseDetail.username
                   }}</span>
                 </div>
                 <div class="Tname" v-if="Tname.length > 0" @click="TnameCheck = !TnameCheck">
-                  协同人员:<span v-for="(tname, tIndex) in  TnameCheck ? Tname : Tname.slice(0,6)" :key="tIndex" style="margin: 0 5px; color: #000">{{ tname
-                  }}</span><span style="margin: 0 5px; color: #b2b2b2" v-if="!TnameCheck && Tname.length > 6">更多....</span>
+                  协同人员:<span v-for="(tname, tIndex) in  TnameCheck ? Tname : Tname.slice(0, 6)" :key="tIndex"
+                    style="margin: 0 5px; color: #000">{{ tname
+                    }}</span><span style="margin: 0 5px; color: #b2b2b2"
+                    v-if="!TnameCheck && Tname.length > 6">更多....</span>
                 </div>
               </div>
               <div class="cType" style="font-size: 18px; color: #6c6c6c">
               </div>
-              <div class="btnBox">
+              <div class="btnBox" v-if="false">
                 <div class="now_study" @click="dialogVisible = true">
                   预览
                 </div>
                 <div class="now_study" @click="goToCongress">进展</div>
-            </div>
+              </div>
             </div>
           </div>
         </div>
@@ -75,13 +76,20 @@
             <div class="courseTd">{{ courseDetail.brief }}</div>
           </div>
           <div :class="courseDetail.brief != '' ? 'rightTd' : 'noBRight'">
-            <div :class="courseDetail.brief != '' ? 'rightTd' : 'noBRight'">
+            <div class="checkBox">
+              <span :class="{ active: type == 1 }" @click="type = 1">阶段选择</span>
+              <span :class="{ active: type == 2 }" @click="type = 2">项目进展</span>
+            </div>
+            <div :class="courseDetail.brief != '' ? 'rightTd' : 'noBRight'" v-show="type == 1">
               <div class="blue_box_one" v-for="(item, index) in chapInfo" :key="index" @click="addUserRate(index)">
                 <div>第{{ index + 1 }}阶段</div>
                 <div :title="item.dyName">{{ item.dyName }}</div>
                 <div>{{ item.chapterInfo[0].taskJson.length }}个任务</div>
               </div>
             </div>
+            <div :class="courseDetail.brief != '' ? 'rightTd' : 'noBRight'" v-show="type == 2">
+              <courseProgress :cid="id" :userid="userid" :oid="oid" :org="org"></courseProgress>
+            </div>
           </div>
         </div>
 
@@ -108,9 +116,12 @@
 
 <script>
 import Heatmap from '../tools/heatmap.vue'
+import courseProgress from './courseProgress.vue'
+
 export default {
   components: {
     Heatmap,
+    courseProgress
   },
   data() {
     return {
@@ -129,7 +140,7 @@ export default {
       chapInfo: [],
       courseType: [],
       Tname: [],
-      TnameCheck:false,
+      TnameCheck: false,
       courseTypeJson: {},
       userinfo: [],
       mr: "https://ccrb.s3.cn-northwest-1.amazonaws.com.cn/noBanner1656409780264.jpg",
@@ -145,15 +156,15 @@ export default {
     goTo(path) {
       this.$router.push(path);
     },
-    goToCongress(){
-      window.location.href='https://pbl.cocorobo.cn/pbl-teacher-table/dist/#/courseProgress?cid=' +
-                      this.id +
-                      '&userid=' +
-                      this.userid +
-                      '&oid=' +
-                      this.oid +
-                      '&org=' +
-                      this.org
+    goToCongress() {
+      window.location.href = 'https://pbl.cocorobo.cn/pbl-teacher-table/dist/#/courseProgress?cid=' +
+        this.id +
+        '&userid=' +
+        this.userid +
+        '&oid=' +
+        this.oid +
+        '&org=' +
+        this.org
     },
     addUserRate(i) {
       // var suid = this.userid;
@@ -273,83 +284,6 @@ export default {
           }
 
 
-          let _chapters = JSON.parse(a[0].chapters)
-          let _works = res.data[3];
-          let _sCont = res.data[4];
-          let _comment = res.data[5];
-
-          let _chaptersJson = {
-            chapterState: _chapters,
-            state: {
-              stage: _chapters.length,
-              finish: 0,
-              learing: 0,
-            },
-            tool: [],
-            chapter: [],
-            time: {},
-            startTime: _works.length ? _works[0].time : '',
-            work: [],
-            studentCount: _sCont[0].usercount
-          }
-          let timeAarry = []
-          for (var j = 0; j < _works.length; j++) {
-            timeAarry.push(_works[j].vtime)
-          }
-          timeAarry.forEach(item => {
-            _chaptersJson.time[item] = (_chaptersJson.time[item] + 1) || 1
-          })
-          for (var i = 0; i < _chapters.length; i++) {
-            _chaptersJson.chapterState[i].isFinsh = false;
-            _chaptersJson.tool[i] = []
-            _chaptersJson.chapter[i] = []
-            _chaptersJson.work[i] = { name: _chapters[i].dyName, chapter: [] }
-            for (var j = 0; j < _works.length; j++) {
-              if (i == _works[j].stage) {
-                _chaptersJson.chapterState[i].isFinsh = true;
-                _chaptersJson.state.finish++
-                break;
-              }
-            }
-            let el = _chapters[i].chapterInfo[0].taskJson;
-            for (var z = 0; z < el.length; z++) {
-              _chaptersJson.tool[i][z] = []
-              _chaptersJson.chapter[i][z] = []
-              _chaptersJson.work[i].chapter[z] = { name: el[z].task, task: [] }
-              _chaptersJson.work[i].is = false;
-              let tools = el[z].toolChoose
-              for (var k = 0; k < tools.length; k++) {
-                _chaptersJson.work[i].chapter[z].task[k] = { tool: tools[k].tool[0], works: [], likeCount: 0, commentCount: 0, score: 0, isScore: 0 }
-                for (var j = 0; j < _works.length; j++) {
-                  if (i == _works[j].stage && z == _works[j].task && k == _works[j].tool) {
-                    _chaptersJson.work[i].chapter[z].task[k].works.push(_works[j])
-                    if (_works[j].score) {
-                      _chaptersJson.work[i].chapter[z].task[k].score += JSON.parse(_works[j].score).wScore
-                      _chaptersJson.work[i].chapter[z].task[k].isScore++
-                    }
-                  }
-                }
-                for (var j = 0; j < _comment.length; j++) {
-                  if (i == _comment[j].stage && z == _comment[j].task && k == _comment[j].tool) {
-                    if (_comment[j].cType == 1) {
-                      _chaptersJson.work[i].chapter[z].task[k].likeCount++
-                    }
-
-                    if (_comment[j].cType == 2) {
-                      _chaptersJson.work[i].chapter[z].task[k].commentCount++
-                    }
-                  }
-                }
-                // if (_chaptersJson.chapter[i][z].indexOf(tools[k].tool[0]) == -1) {
-                //   _chaptersJson.tool[i][z].push(tools[k].tool[0])
-                // }
-                _chaptersJson.chapter[i][z][k] = { tool: tools[k].tool[0] }
-                _chaptersJson.tool[i][z][k] = { tool: tools[k].tool[0] }
-              }
-            }
-          }
-          _chaptersJson.state.learing = _chaptersJson.state.stage - _chaptersJson.state.finish
-          this.chaptersJson = _chaptersJson
           // debugger
         })
         .catch((err) => {
@@ -476,7 +410,7 @@ export default {
   margin-top: 30px;
 }
 
-.now_study + .now_study{
+.now_study+.now_study {
   margin-left: 10px;
 }
 
@@ -779,7 +713,7 @@ export default {
   cursor: pointer;
   margin-left: 40px;
   word-break: break-all;
-  width:auto;
+  width: auto;
   /* overflow: hidden;
   white-space: nowrap;
   text-overflow: ellipsis; */
@@ -1165,8 +1099,29 @@ export default {
   transform: rotate(90deg);
 }
 
-.btnBox{
+.btnBox {
+  display: flex;
+}
+
+.checkBox {
   display: flex;
+  padding: 20px 0 0 20px;
+  box-sizing: border-box;
+  width: 100%;
+}
+
+.checkBox span {
+  padding: 0 10px 5px;
+  cursor: pointer;
+  font-size: 18px;
+}
+
+.checkBox span+span {
+  margin-left: 20px;
 }
 
+.checkBox .active {
+  border-bottom: 2px solid rgb(75, 151, 229);
+  cursor: pointer;
+}
 </style>

+ 235 - 0
src/components/student/courseProgress.vue

@@ -0,0 +1,235 @@
+<template>
+    <div v-loading="loading" class="box">
+        <!-- <el-button type="primary" size="small" class="returnBtn" @click="retrunA()">返回</el-button> -->
+        <!-- <div v-if="cPan == 2" class="noneClass">项目数据不完善,无法显示数据,请前去完善</div> -->
+        <div class="proMan" v-if="cPan == 1">
+            <div class="title"><img src="../../assets/icon/task.png" alt />任务进展甘特图</div>
+            <ganChart :Json="unitJson"></ganChart>
+        </div>
+        <div class="proMan">
+            <div class="title"><img src="../../assets/icon/tupu.png" alt />图谱</div>
+            <graph :Json="graphJson"></graph>
+        </div>
+        <div class="proMan" v-if="cPan == 1">
+            <div class="title"><img src="../../assets/icon/proMan.png" alt />负责人看板</div>
+            <proMan :Json="unitJson" :ManAarray="ManAarray"></proMan>
+        </div>
+    </div>
+</template>
+
+<script>
+import proMan from "../components/proMan.vue"
+import ganChart from "../components/ganChart.vue"
+import graph from "../components/graph.vue"
+export default {
+    components: { proMan, ganChart, graph },
+    props:['cid','userid','oid','org'],
+    data() {
+        return {
+            loading: false,
+            unitJson: {},
+            cPan: 1,
+            teacherJuri2: [],
+            ManAarray: [],
+            checkboxList3: [],
+            courseUserid: "",
+            graphJson: {}
+        }
+    },
+    methods: {
+        retrunA() {
+            this.$router.go(-1)
+        },
+        getCourse() {
+            let params = {
+                cid: this.cid,
+            };
+            this.ajax
+                .get(this.$store.state.api + "select_student_course_detail", params)
+                .then((res) => {
+                    this.unitJson = JSON.parse(res.data[0][0].chapters);
+                    this.courseUserid = res.data[0][0].userid;
+                    this.checkboxList3 = res.data[0][0].course_teacher
+                        ? res.data[0][0].course_teacher.split(",")
+                        : [];
+                    this.cPan = 1;
+                    for (var i = 0; i < this.unitJson.length; i++) {
+                        for (
+                            var j = 0;
+                            j < this.unitJson[i].chapterInfo[0].taskJson.length;
+                            j++
+                        ) {
+                            // if (
+                            //     !this.unitJson[i].chapterInfo[0].taskJson[j].task
+                            // ) {
+                            //     // this.$message.error("请填写任务名称");
+                            //     this.cPan = 2
+                            //     break;
+                            // }
+                            // if (
+                            //     !this.unitJson[i].chapterInfo[0].taskJson[j].people
+                            // ) {
+                            //     // this.$message.error("请填写负责人");
+                            //     this.cPan = 2
+                            //     break;
+                            // }
+                            // if (
+                            //     !this.unitJson[i].chapterInfo[0].taskJson[j].time
+                            // ) {
+                            //     // this.$message.error("请填写任务完成时间");
+                            //     this.cPan = 2
+                            //     break;
+                            // }
+                            if (this.unitJson[i].chapterInfo[0].taskJson[j].eList) {
+                                this.unitJson[i].chapterInfo[0].taskJson[j].eList = this.unitJson[
+                                    i
+                                ].chapterInfo[0].taskJson[j].eList.filter((ele) => {
+                                    return ele.value != "";
+                                });
+                            }
+                        }
+                    }
+                    this.getTeacher(res.data[0][0]);
+                })
+                .catch((err) => {
+                    console.error(err);
+                });
+        },
+        setGraphJson(json) {
+            let chapters = JSON.parse(json.chapters)
+            let gjson = {
+                rootId: 'pid',
+                nodes: [
+                    { id: 'pid', text: '', borderWidth: -1, color: '#128cff' },
+                ],
+                lines: [
+                ]
+            }
+            gjson.nodes[0].text = json.title
+            for (var i = 0; i < chapters.length; i++) {
+                let _chapter = chapters[i]
+                gjson.nodes.push({ id: 'chap' + i, text: '阶段' + (i + 1) + '-' + _chapter.dyName, borderWidth: -1, color: '#0672e1' })
+                gjson.lines.push({ from: 'pid', to: 'chap' + i })
+                let tasks = _chapter.chapterInfo[0].taskJson
+                for (var j = 0; j < tasks.length; j++) {
+                    let _task = tasks[j]
+                    gjson.nodes.push({ id: 'task' + i + '-' + j, text: '任务' + (j + 1) + '-' + _task.task, borderWidth: -1, color: '#3c59da' })
+                    gjson.lines.push({ from: 'chap' + i, to: 'task' + i + '-' + j })
+                    if (_task.people) {
+                        let _people = '负责人-' + this.getGMan(_task.people)
+                        gjson.nodes.push({ id: 'people' + i + '-' + j, text: _people, borderWidth: -1, color: '#004d9b' })
+                        gjson.lines.push({ from: 'task' + i + '-' + j, to: 'people' + i + '-' + j })
+                        if (_task.tcMember && _task.tcMember.length) {
+                            for (var tc = 0; tc < _task.tcMember.length; tc++) {
+                                let _tc = this.getGMan(_task.tcMember[tc])
+                                if (_tc) {
+                                    gjson.nodes.push({ id: 'tc' + i + '-' + j + '-' + tc, text: _tc, borderWidth: -1, color: '#53c5fb' })
+                                    gjson.lines.push({ from: 'people' + i + '-' + j, to: 'tc' + i + '-' + j + '-' + tc })
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            this.graphJson = gjson
+        },
+        getGMan(people) {
+            let _people = ''
+            if (this.ManAarray.length) {
+                for (var i = 0; i < this.ManAarray.length; i++) {
+                    if (this.ManAarray[i].userid == people) {
+                        _people = this.ManAarray[i].name;
+                        break;
+                    }
+                }
+            }
+            return _people ? _people : '无'
+        },
+        getTeacher(sss) {
+            this.ManAarray = []
+            if (this.checkboxList3.indexOf(this.courseUserid) == -1) {
+                this.checkboxList3.push(this.courseUserid)
+            }
+            let params = {
+                uid: this.checkboxList3.join(","),
+            };
+            this.ajax
+                .get(
+                    this.$store.state.api + "getAllUserById",
+                    params
+                )
+                .then((res) => {
+                    let teacherJuri = res.data[0];
+                    this.ManAarray = teacherJuri;
+                    this.setGraphJson(sss)
+                    this.setMan();
+                })
+                .catch((err) => {
+                    console.error(err);
+                });
+        },
+        setMan() {
+            // let teacherJuri = this.teacherJuri2;
+            // debugger
+            // this.ManAarray = []
+            // for (var i = 0; i < teacherJuri.length; i++) {
+            //     if (teacherJuri[i].userid == this.userid) {
+            //         this.ManAarray.push(teacherJuri[i])
+            //     } else if (this.checkboxList3.indexOf(teacherJuri[i].userid) != -1) {
+            //         this.ManAarray.push(teacherJuri[i])
+            //     }
+            // }
+            this.loading = false;
+
+        },
+    },
+    mounted() {
+        this.loading = true;
+        this.getCourse();
+
+    },
+}
+</script>
+
+<style scoped>
+.returnBtn {
+    position: fixed;
+    right: 20px;
+    top: 15px;
+    z-index: 99999;
+}
+
+.noneClass {
+    margin-top: 10px;
+    display: flex;
+    justify-content: center;
+    font-size: 20px;
+    font-weight: 700;
+}
+
+.box {
+    background: #fff;
+    height: 100%;
+    width: 100%;
+    overflow: auto;
+}
+
+.proMan {
+    width: 95%;
+    margin: 0 auto;
+    padding: 20px 0 20px;
+    /* margin-top: 20px; */
+}
+
+.proMan .title {
+    margin-bottom: 10px;
+    display: flex;
+    align-items: center;
+}
+
+.proMan .title img {
+    margin-right: 5px;
+    height: 17px;
+    width: 17px;
+}
+</style>

+ 20 - 3
src/components/student/studyStudent.vue

@@ -65,7 +65,9 @@
           <div class="btnAll">
             <div class="returnBtn" @click="nextOrpreSteps(0)">上一步</div>
             <div class="returnBtn" @click="nextOrpreSteps(1)">下一步</div>
-            <div v-if="tType != 5" class="returnBtn" @click="allScrell">全屏</div>
+            <div class="returnBtn" @click="refreshCourse">刷新</div>
+            <div class="returnBtn" @click="setPz" v-if="tType == 1" >评论</div>
+            <!-- <div v-if="tType != 5" class="returnBtn" @click="allScrell">全屏</div> -->
             <!-- <div class="returnBtn" @click="startRecording" v-if="(!videoStart && (tType == 1 || tType == 4))">开始录制</div>
             <div class="returnBtn" @click="stopRecording" v-else-if="(tType == 1 || tType == 4)"
               style="background:#ee5255">下载录制</div>
@@ -627,7 +629,7 @@
         </div>
       </div>
     </div>
-    <div class="pButton" @click="(pzDialog = true), selectPz(), setVHeight()" v-if="tType == 4">
+    <div class="pButton" @click="(pzDialog = true), selectPz(), setVHeight()" v-if="tType == 4 || ispzType == 4">
       <!-- 批 -->
       <img src="../../assets/pzBtn2.png" style="width: 25px" alt="" />
     </div>
@@ -1124,6 +1126,7 @@ export default {
       answerList: [],
       navList: [],
       addPzDialog: false,
+      ispzType:0,
       pzConText: "",
       worksStudent: [],
       workStudent: [],
@@ -1427,6 +1430,20 @@ export default {
     allScrell() {
       window.parent.postMessage({ allScreen: this.screenType + "s" }, "*");
     },
+    refreshCourse(){
+      this.navList = [];
+      this.getCourseDetail(1)
+    },
+    setPz(){
+      if(this.ispzType == 4){
+        this.ispzType = 0
+        this.pzDialog = false
+        return;
+      }
+      this.ispzType = 4
+      this.pzDialog = true
+      this.selectPz();
+    },
     nextOrpreSteps(t) {
       var b = this.chapInfoList.length - 1;
       if (t == 0) {
@@ -1965,7 +1982,7 @@ export default {
             clearInterval(_this.timer);
             _this.timer = null;
           }
-          if (_this.tType == 4) {
+          if (_this.tType == 4 || _this.ispzType == 4) {
             _this.selectPz();
           }
           _this.timer = setInterval(function () {

+ 13 - 3
src/components/studio/courseDetail.vue

@@ -60,9 +60,9 @@
               </div>
               <div class="cType" style="font-size: 18px; color: #6c6c6c">
               </div>
-              <div class="btnBox">
+              <!-- <div class="btnBox">
                 <div class="now_study" @click="goToCongress">工作进展</div>
-            </div>
+            </div> -->
             </div>
           </div>
         </div>
@@ -72,13 +72,20 @@
             <div class="courseTd">{{ courseDetail.brief }}</div>
           </div>
           <div :class="courseDetail.brief != '' ? 'rightTd' : 'noBRight'">
-            <div :class="courseDetail.brief != '' ? 'rightTd' : 'noBRight'">
+            <div class="checkBox">
+              <span :class="{ active: type == 1 }" @click="type = 1">阶段选择</span>
+              <span :class="{ active: type == 2 }" @click="type = 2">项目进展</span>
+            </div>
+            <div :class="courseDetail.brief != '' ? 'rightTd' : 'noBRight'" v-show="type == 1">
               <div class="blue_box_one" v-for="(item, index) in chapInfo" :key="index" @click="addUserRate(index)">
                 <div>第{{ index + 1 }}阶段</div>
                 <div :title="item.dyName">{{ item.dyName }}</div>
                 <div>{{ item.chapterInfo[0].taskJson.length }}个任务</div>
               </div>
             </div>
+            <div :class="courseDetail.brief != '' ? 'rightTd' : 'noBRight'" v-show="type == 2">
+              <courseProgress :cid="id" :userid="userid" :oid="oid" :org="org"></courseProgress>
+            </div>
           </div>
         </div>
 
@@ -105,9 +112,12 @@
 
 <script>
 import Heatmap from '../tools/heatmap.vue'
+import courseProgress from './courseProgress.vue'
+
 export default {
   components: {
     Heatmap,
+    courseProgress
   },
   data() {
     return {

+ 235 - 0
src/components/studio/courseProgress.vue

@@ -0,0 +1,235 @@
+<template>
+    <div v-loading="loading" class="box">
+        <!-- <el-button type="primary" size="small" class="returnBtn" @click="retrunA()">返回</el-button> -->
+        <!-- <div v-if="cPan == 2" class="noneClass">项目数据不完善,无法显示数据,请前去完善</div> -->
+        <div class="proMan" v-if="cPan == 1">
+            <div class="title"><img src="../../assets/icon/task.png" alt />任务进展甘特图</div>
+            <ganChart :Json="unitJson"></ganChart>
+        </div>
+        <div class="proMan">
+            <div class="title"><img src="../../assets/icon/tupu.png" alt />图谱</div>
+            <graph :Json="graphJson"></graph>
+        </div>
+        <div class="proMan" v-if="cPan == 1">
+            <div class="title"><img src="../../assets/icon/proMan.png" alt />负责人看板</div>
+            <proMan :Json="unitJson" :ManAarray="ManAarray"></proMan>
+        </div>
+    </div>
+</template>
+
+<script>
+import proMan from "../components/proMan.vue"
+import ganChart from "../components/ganChart.vue"
+import graph from "../components/graph.vue"
+export default {
+    components: { proMan, ganChart, graph },
+    props:['cid','userid','oid','org'],
+    data() {
+        return {
+            loading: false,
+            unitJson: {},
+            cPan: 1,
+            teacherJuri2: [],
+            ManAarray: [],
+            checkboxList3: [],
+            courseUserid: "",
+            graphJson: {}
+        }
+    },
+    methods: {
+        retrunA() {
+            this.$router.go(-1)
+        },
+        getCourse() {
+            let params = {
+                cid: this.cid,
+            };
+            this.ajax
+                .get(this.$store.state.api + "select_studio_course_detail", params)
+                .then((res) => {
+                    this.unitJson = JSON.parse(res.data[0][0].chapters);
+                    this.courseUserid = res.data[0][0].userid;
+                    this.checkboxList3 = res.data[0][0].course_teacher
+                        ? res.data[0][0].course_teacher.split(",")
+                        : [];
+                    this.cPan = 1;
+                    for (var i = 0; i < this.unitJson.length; i++) {
+                        for (
+                            var j = 0;
+                            j < this.unitJson[i].chapterInfo[0].taskJson.length;
+                            j++
+                        ) {
+                            // if (
+                            //     !this.unitJson[i].chapterInfo[0].taskJson[j].task
+                            // ) {
+                            //     // this.$message.error("请填写任务名称");
+                            //     this.cPan = 2
+                            //     break;
+                            // }
+                            // if (
+                            //     !this.unitJson[i].chapterInfo[0].taskJson[j].people
+                            // ) {
+                            //     // this.$message.error("请填写负责人");
+                            //     this.cPan = 2
+                            //     break;
+                            // }
+                            // if (
+                            //     !this.unitJson[i].chapterInfo[0].taskJson[j].time
+                            // ) {
+                            //     // this.$message.error("请填写任务完成时间");
+                            //     this.cPan = 2
+                            //     break;
+                            // }
+                            if (this.unitJson[i].chapterInfo[0].taskJson[j].eList) {
+                                this.unitJson[i].chapterInfo[0].taskJson[j].eList = this.unitJson[
+                                    i
+                                ].chapterInfo[0].taskJson[j].eList.filter((ele) => {
+                                    return ele.value != "";
+                                });
+                            }
+                        }
+                    }
+                    this.getTeacher(res.data[0][0]);
+                })
+                .catch((err) => {
+                    console.error(err);
+                });
+        },
+        setGraphJson(json) {
+            let chapters = JSON.parse(json.chapters)
+            let gjson = {
+                rootId: 'pid',
+                nodes: [
+                    { id: 'pid', text: '', borderWidth: -1, color: '#128cff' },
+                ],
+                lines: [
+                ]
+            }
+            gjson.nodes[0].text = json.title
+            for (var i = 0; i < chapters.length; i++) {
+                let _chapter = chapters[i]
+                gjson.nodes.push({ id: 'chap' + i, text: '阶段' + (i + 1) + '-' + _chapter.dyName, borderWidth: -1, color: '#0672e1' })
+                gjson.lines.push({ from: 'pid', to: 'chap' + i })
+                let tasks = _chapter.chapterInfo[0].taskJson
+                for (var j = 0; j < tasks.length; j++) {
+                    let _task = tasks[j]
+                    gjson.nodes.push({ id: 'task' + i + '-' + j, text: '任务' + (j + 1) + '-' + _task.task, borderWidth: -1, color: '#3c59da' })
+                    gjson.lines.push({ from: 'chap' + i, to: 'task' + i + '-' + j })
+                    if (_task.people) {
+                        let _people = '负责人-' + this.getGMan(_task.people)
+                        gjson.nodes.push({ id: 'people' + i + '-' + j, text: _people, borderWidth: -1, color: '#004d9b' })
+                        gjson.lines.push({ from: 'task' + i + '-' + j, to: 'people' + i + '-' + j })
+                        if (_task.tcMember && _task.tcMember.length) {
+                            for (var tc = 0; tc < _task.tcMember.length; tc++) {
+                                let _tc = this.getGMan(_task.tcMember[tc])
+                                if (_tc) {
+                                    gjson.nodes.push({ id: 'tc' + i + '-' + j + '-' + tc, text: _tc, borderWidth: -1, color: '#53c5fb' })
+                                    gjson.lines.push({ from: 'people' + i + '-' + j, to: 'tc' + i + '-' + j + '-' + tc })
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            this.graphJson = gjson
+        },
+        getGMan(people) {
+            let _people = ''
+            if (this.ManAarray.length) {
+                for (var i = 0; i < this.ManAarray.length; i++) {
+                    if (this.ManAarray[i].userid == people) {
+                        _people = this.ManAarray[i].name;
+                        break;
+                    }
+                }
+            }
+            return _people ? _people : '无'
+        },
+        getTeacher(sss) {
+            this.ManAarray = []
+            if (this.checkboxList3.indexOf(this.courseUserid) == -1) {
+                this.checkboxList3.push(this.courseUserid)
+            }
+            let params = {
+                uid: this.checkboxList3.join(","),
+            };
+            this.ajax
+                .get(
+                    this.$store.state.api + "getAllUserById",
+                    params
+                )
+                .then((res) => {
+                    let teacherJuri = res.data[0];
+                    this.ManAarray = teacherJuri;
+                    this.setGraphJson(sss)
+                    this.setMan();
+                })
+                .catch((err) => {
+                    console.error(err);
+                });
+        },
+        setMan() {
+            // let teacherJuri = this.teacherJuri2;
+            // debugger
+            // this.ManAarray = []
+            // for (var i = 0; i < teacherJuri.length; i++) {
+            //     if (teacherJuri[i].userid == this.userid) {
+            //         this.ManAarray.push(teacherJuri[i])
+            //     } else if (this.checkboxList3.indexOf(teacherJuri[i].userid) != -1) {
+            //         this.ManAarray.push(teacherJuri[i])
+            //     }
+            // }
+            this.loading = false;
+
+        },
+    },
+    mounted() {
+        this.loading = true;
+        this.getCourse();
+
+    },
+}
+</script>
+
+<style scoped>
+.returnBtn {
+    position: fixed;
+    right: 20px;
+    top: 15px;
+    z-index: 99999;
+}
+
+.noneClass {
+    margin-top: 10px;
+    display: flex;
+    justify-content: center;
+    font-size: 20px;
+    font-weight: 700;
+}
+
+.box {
+    background: #fff;
+    height: 100%;
+    width: 100%;
+    overflow: auto;
+}
+
+.proMan {
+    width: 95%;
+    margin: 0 auto;
+    padding: 20px 0 20px;
+    /* margin-top: 20px; */
+}
+
+.proMan .title {
+    margin-bottom: 10px;
+    display: flex;
+    align-items: center;
+}
+
+.proMan .title img {
+    margin-right: 5px;
+    height: 17px;
+    width: 17px;
+}
+</style>

+ 20 - 3
src/components/studio/studyStudent.vue

@@ -65,7 +65,9 @@
           <div class="btnAll">
             <div class="returnBtn" @click="nextOrpreSteps(0)">上一步</div>
             <div class="returnBtn" @click="nextOrpreSteps(1)">下一步</div>
-            <div v-if="tType != 5" class="returnBtn" @click="allScrell">全屏</div>
+            <!-- <div v-if="tType != 5" class="returnBtn" @click="allScrell">全屏</div> -->
+            <div class="returnBtn" @click="refreshCourse">刷新</div>
+            <div class="returnBtn" @click="setPz" v-if="tType == 1" >评论</div>
             <!-- <div class="returnBtn" @click="startRecording" v-if="(!videoStart && (tType == 1 || tType == 4))">开始录制</div>
             <div class="returnBtn" @click="stopRecording" v-else-if="(tType == 1 || tType == 4)"
               style="background:#ee5255">下载录制</div>
@@ -630,7 +632,7 @@
         </div>
       </div>
     </div>
-    <div class="pButton" @click="(pzDialog = true), selectPz(), setVHeight()" v-if="tType == 4">
+    <div class="pButton" @click="(pzDialog = true), selectPz(), setVHeight()" v-if="tType == 4 || ispzType == 4">
       <!-- 批 -->
       <img src="../../assets/pzBtn2.png" style="width: 25px" alt="" />
     </div>
@@ -1127,6 +1129,7 @@ export default {
       answerList: [],
       navList: [],
       addPzDialog: false,
+      ispzType:0,
       pzConText: "",
       worksStudent: [],
       workStudent: [],
@@ -1430,6 +1433,20 @@ export default {
     allScrell() {
       window.parent.postMessage({ allScreen: this.screenType+"studio" }, "*");
     },
+    refreshCourse(){
+      this.navList = [];
+      this.getCourseDetail(1)
+    },
+    setPz(){
+      if(this.ispzType == 4){
+        this.ispzType = 0
+        this.pzDialog = false
+        return;
+      }
+      this.ispzType = 4
+      this.pzDialog = true
+      this.selectPz();
+    },
     nextOrpreSteps(t) {
       var b = this.chapInfoList.length - 1;
       if (t == 0) {
@@ -1968,7 +1985,7 @@ export default {
             clearInterval(_this.timer);
             _this.timer = null;
           }
-          if (_this.tType == 4) {
+          if (_this.tType == 4 || _this.ispzType == 4) {
             _this.selectPz();
           }
           _this.timer = setInterval(function () {

+ 24 - 4
src/components/studyStudent.vue

@@ -167,7 +167,7 @@
               @click="startRecording"
               v-if="!videoStart && (tType == 1 || tType == 4)"
             >
-              开始录制
+              录制
             </div>
             <div
               class="returnBtn"
@@ -175,7 +175,7 @@
               v-else-if="tType == 1 || tType == 4"
               style="background: #ee5255"
             >
-              下载录制
+              下载
             </div>
             <div
               class="returnBtn"
@@ -5659,7 +5659,7 @@
                         :class="w.type == 1 ? 'isTypeOne' : ''"
                       >
                         <div class="workImg">
-                          <img :src="word" @click="openTable(w)" alt />
+                          <img :src="word" @click="openWord(w)" alt />
                           <!-- @click="openFile(w.works)" -->
                           <div
                             class="answerScore"
@@ -5779,7 +5779,7 @@
                         :key="wIndex"
                       >
                         <div class="workImg">
-                          <img :src="word" @click="openTable(w)" alt />
+                          <img :src="word" @click="openWord(w)" alt />
                           <div
                             class="answerScore"
                             v-if="w.score"
@@ -8591,6 +8591,21 @@
         <el-button @click="dialogVisibleTable2 = false">关 闭</el-button>
       </span>
     </el-dialog>
+    <el-dialog
+      title="文档"
+      :visible.sync="dialogVisibleTable3"
+      :append-to-body="true"
+      width="95%"
+      :before-close="handleClose"
+      class="dialog_diy"
+    >
+      <el-form>
+        <div class="cont" v-html="tableJson.text"></div>
+      </el-form>
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="dialogVisibleTable3 = false">关 闭</el-button>
+      </span>
+    </el-dialog>
     <el-dialog
       title="分组设置"
       :visible.sync="dialogVisibleGroup"
@@ -9358,6 +9373,7 @@ export default {
       dialogVisibleWord: false,
       dialogVisibleWordTeacher: false,
       dialogVisibleTable2: false,
+      dialogVisibleTable3:false,
       dialogVisibleGroupWork: false,
       dialogVisibleUpdateGroup: false,
       dialogVisibleDeleteGroup: false,
@@ -13769,6 +13785,10 @@ export default {
       this.tableJson = JSON.parse(f.works);
       this.dialogVisibleTable2 = true;
     },
+    openWord(f) {
+      this.tableJson = JSON.parse(f.works);
+      this.dialogVisibleTable3 = true;
+    },
     doUrl(url, i) {
       this.isClickNav = "";
       this.pptImgUrl1 = "";

+ 75 - 3
src/components/tools/wangEnduit.vue

@@ -1,5 +1,5 @@
 <template lang="html">
-  <div class="editor">
+  <div class="editor cont">
     <div ref="toolbar" class="toolbar">
     </div>
     <div ref="editor" class="text">
@@ -168,7 +168,7 @@ export default {
 };
 </script>  
   
-<style lang="css">
+<style lang="css" scoped>
 .editor {
   width: 100%;
   margin: 10px auto;
@@ -182,8 +182,80 @@ export default {
 
 .text {
   border: 1px solid #ccc;
-  height: 350px;
+  height: 400px;
   overflow: auto;
+
+}
+
+.editor >>> .w-e-toolbar .w-e-menu{
+  display: flex;
+  width: auto;
+  align-items: center;
+  margin-left: 10px;
+  padding: 0 10px;
 }
 
+.editor >>> .w-e-toolbar {
+  background: #f1f1f1;
+}
+
+.editor >>> .w-e-icon-table2::after {
+  content: '插入表格';
+  margin-left: 5px;
+}
+
+
+/* table 样式 */
+.cont>>>table {
+  border-top: 1px solid #ccc;
+  border-left: 1px solid #ccc;
+}
+
+.cont>>>table td,
+.cont>>>table th {
+  border-bottom: 1px solid #ccc;
+  border-right: 1px solid #ccc;
+  /* padding: 20px 5px; */
+  padding: 5px 10px;
+  max-width: 0px;
+  height: 30px;
+  vertical-align: baseline;
+}
+
+.cont>>>table th {
+  border-bottom: 2px solid #ccc;
+  text-align: center;
+}
+
+/* blockquote 样式 */
+.cont>>>blockquote {
+  display: block;
+  border-left: 8px solid #d0e5f2;
+  padding: 5px 10px;
+  margin: 10px 0;
+  line-height: 1.4;
+  font-size: 100%;
+  background-color: #f1f1f1;
+}
+
+/* code 样式 */
+.cont>>>code {
+  display: inline-block;
+  *display: inline;
+  *zoom: 1;
+  background-color: #f1f1f1;
+  border-radius: 3px;
+  padding: 3px 5px;
+  margin: 0 3px;
+}
+
+.cont>>>pre code {
+  display: block;
+}
+
+/* ul ol 样式 */
+.cont>>>ul,
+ol {
+  margin: 10px 0 10px 20px;
+}
 </style>