guhongwei 3 年之前
父節點
當前提交
538afc48e2
共有 99 個文件被更改,包括 12834 次插入44 次删除
  1. 560 0
      public/home copy.html
  2. 10 10
      public/home.html
  3. 1 0
      src/main.js
  4. 1 1
      src/plugins/components.js
  5. 137 31
      src/router/index.js
  6. 13 1
      src/store/index.js
  7. 154 0
      src/views/twoweb/achieveLive/apply.vue
  8. 130 0
      src/views/twoweb/achieveLive/before.vue
  9. 188 0
      src/views/twoweb/achieveLive/detail.vue
  10. 207 0
      src/views/twoweb/achieveLive/detail/chatData.vue
  11. 152 0
      src/views/twoweb/achieveLive/detail/expertData.vue
  12. 233 0
      src/views/twoweb/achieveLive/detail/imgtextData.vue
  13. 130 0
      src/views/twoweb/achieveLive/detail/jiabinData.vue
  14. 229 0
      src/views/twoweb/achieveLive/detail/productData.vue
  15. 163 0
      src/views/twoweb/achieveLive/detail/top.vue
  16. 178 0
      src/views/twoweb/achieveLive/detail/videoData.vue
  17. 132 0
      src/views/twoweb/achieveLive/detail/xiangmuData.vue
  18. 86 0
      src/views/twoweb/achieveLive/expert/detail.vue
  19. 111 0
      src/views/twoweb/achieveLive/expert/index.vue
  20. 44 0
      src/views/twoweb/achieveLive/model/data-detail.vue
  21. 45 0
      src/views/twoweb/achieveLive/model/data-index.vue
  22. 71 0
      src/views/twoweb/achieveLive/model/data-slot.vue
  23. 164 0
      src/views/twoweb/achieveLive/news/index.vue
  24. 92 0
      src/views/twoweb/achieveLive/product/detail.vue
  25. 117 0
      src/views/twoweb/achieveLive/product/index.vue
  26. 247 0
      src/views/twoweb/channelLive/index.vue
  27. 127 0
      src/views/twoweb/interflow/index.vue
  28. 97 0
      src/views/twoweb/interflow/index/cooperation.vue
  29. 97 0
      src/views/twoweb/interflow/index/dynamic.vue
  30. 97 0
      src/views/twoweb/interflow/index/industry.vue
  31. 97 0
      src/views/twoweb/interflow/index/learning.vue
  32. 77 0
      src/views/twoweb/interflow/index/top.vue
  33. 122 0
      src/views/twoweb/interflow/list.vue
  34. 106 0
      src/views/twoweb/interflow/list/cooperation.vue
  35. 112 0
      src/views/twoweb/interflow/list/detail-model/news-model.vue
  36. 106 0
      src/views/twoweb/interflow/list/dynamic.vue
  37. 106 0
      src/views/twoweb/interflow/list/industry.vue
  38. 106 0
      src/views/twoweb/interflow/list/learning.vue
  39. 139 0
      src/views/twoweb/live/achieve/list.vue
  40. 65 0
      src/views/twoweb/live/index.vue
  41. 80 0
      src/views/twoweb/live/parts/achieveLive.vue
  42. 80 0
      src/views/twoweb/live/parts/personalLive.vue
  43. 146 0
      src/views/twoweb/live/parts/scienceLive.vue
  44. 183 0
      src/views/twoweb/live/parts/trainLive.vue
  45. 90 0
      src/views/twoweb/live/personal/list.vue
  46. 116 0
      src/views/twoweb/market/index.vue
  47. 133 0
      src/views/twoweb/market/index/achieve.vue
  48. 123 0
      src/views/twoweb/market/index/expert.vue
  49. 97 0
      src/views/twoweb/market/index/patent.vue
  50. 114 0
      src/views/twoweb/market/index/roadshow.vue
  51. 77 0
      src/views/twoweb/market/index/top.vue
  52. 125 0
      src/views/twoweb/market/list.vue
  53. 125 0
      src/views/twoweb/market/list/achieve.vue
  54. 46 0
      src/views/twoweb/market/list/detail-model/model-1.vue
  55. 217 0
      src/views/twoweb/market/list/detail-model/model-2.vue
  56. 46 0
      src/views/twoweb/market/list/detail-model/model-3.vue
  57. 44 0
      src/views/twoweb/market/list/detail-model/model-4.vue
  58. 46 0
      src/views/twoweb/market/list/detail-model/model-5.vue
  59. 105 0
      src/views/twoweb/market/list/detail-model/model-6.vue
  60. 120 0
      src/views/twoweb/market/list/expert.vue
  61. 95 0
      src/views/twoweb/market/list/patent.vue
  62. 96 0
      src/views/twoweb/market/list/roadshow.vue
  63. 476 0
      src/views/twoweb/personalLive/index.vue
  64. 50 0
      src/views/twoweb/personalLive/js/sxList.js
  65. 26 0
      src/views/twoweb/personalLive/js/zpxxList.js
  66. 66 0
      src/views/twoweb/personalLive/js/zsgwList.js
  67. 211 0
      src/views/twoweb/service/index.vue
  68. 203 0
      src/views/twoweb/service/order/index.vue
  69. 176 0
      src/views/twoweb/service/parts/info.vue
  70. 106 0
      src/views/twoweb/service/parts/list.vue
  71. 71 0
      src/views/twoweb/service/parts/top.vue
  72. 269 0
      src/views/twoweb/service/policy/index.vue
  73. 344 0
      src/views/twoweb/service/product/achieve.vue
  74. 221 0
      src/views/twoweb/service/product/business.vue
  75. 86 0
      src/views/twoweb/service/product/index.vue
  76. 285 0
      src/views/twoweb/service/product/techol.vue
  77. 114 0
      src/views/twoweb/service/project/index.vue
  78. 442 0
      src/views/twoweb/service/project/parts/projectForm.vue
  79. 95 0
      src/views/twoweb/service/project/parts/questionInfo.vue
  80. 227 0
      src/views/twoweb/service/question/detail.vue
  81. 136 0
      src/views/twoweb/service/question/index.vue
  82. 147 0
      src/views/twoweb/trainLive/index.vue
  83. 217 0
      src/views/twoweb/trainLive/parts/chat.vue
  84. 46 0
      src/views/twoweb/trainLive/parts/imgTxt.vue
  85. 66 0
      src/views/twoweb/trainLive/parts/message.vue
  86. 158 0
      src/views/twoweb/trainLive/parts/videoSwiper.vue
  87. 119 0
      src/views/twoweb/universal/index.vue
  88. 97 0
      src/views/twoweb/universal/index/experience.vue
  89. 97 0
      src/views/twoweb/universal/index/read.vue
  90. 97 0
      src/views/twoweb/universal/index/science.vue
  91. 77 0
      src/views/twoweb/universal/index/top.vue
  92. 97 0
      src/views/twoweb/universal/index/venues.vue
  93. 122 0
      src/views/twoweb/universal/list.vue
  94. 112 0
      src/views/twoweb/universal/list/detail-model/news-model.vue
  95. 106 0
      src/views/twoweb/universal/list/experience.vue
  96. 106 0
      src/views/twoweb/universal/list/read.vue
  97. 106 0
      src/views/twoweb/universal/list/science.vue
  98. 106 0
      src/views/twoweb/universal/list/venues.vue
  99. 1 1
      vue.config.js

+ 560 - 0
public/home copy.html

@@ -0,0 +1,560 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+  <meta charset="utf-8">
+  <title>中科在线(长春)</title>
+  <!-- layui -->
+  <link rel="stylesheet" href="static/home/lib/layui/css/layui.css">
+  <link rel="stylesheet" href="static/home/css/lib.css">
+  <link rel="stylesheet" href="static/home/css/road.css">
+  <link rel="stylesheet" href="static/home/css/index.css">
+  <script src="https://cdn.jsdelivr.net/npm/vue@2.6.12"></script>
+  <script src="https://cdn.staticfile.org/vue-resource/1.5.1/vue-resource.min.js"></script>
+  <style>
+    .canvas-stats {
+      display: none;
+    }
+    #a{
+      position: absolute;
+      bottom: -20px;
+      color: #fff;
+      right: 0;
+    }
+    #a:hover{
+      cursor: pointer;
+    }
+    .floating{
+      width: 350px;
+      height: 170px;
+      background-image: url(./static/images/fuchuang.jpg);
+      background-repeat: no-repeat;
+      background-size: 100% 100%;
+    }
+    .floating p:nth-child(1){
+      text-align: center;
+      font-size: 20px;
+      font-family: cursive;
+      font-weight: bold;
+      /* -webkit-text-stroke: 1px #ffffff; */
+      padding: 10px 0;
+      color: #ffffff;
+    }
+    .floating p:nth-child(2){
+      text-align: center;
+      font-size: 32px;
+      font-family: cursive;
+      font-weight: bold;
+      -webkit-text-stroke: 1px #ffc900;
+      padding: 0px 20px 10px 20px;
+      color: #409eff;
+    }
+    .floating p:nth-child(3){
+      text-align: center;
+    }
+    .floating p:nth-child(3) button{
+      border: none;
+      padding: 5px 10px;
+      border-radius: 25px;
+      color: #fff;
+      background: #409eff;
+    }
+    .floating p:nth-child(3) button:hover{
+      cursor: pointer;
+    }
+  </style>
+</head>
+
+<body>
+  <div class="header">
+   <div class='left'>
+      <img class='image' src="static/images/logo.png" alt="">
+      <p class='title'>中科在线(长春)</p>
+   </div>
+   <div class='right'>
+      <button onclick="window.open('http://broadcast.waityou24.cn/platlive/login')">平台登录</button>
+      <button onclick="window.open('http://broadcast.waityou24.cn/liveadmin/login')">管理登录</button>
+   </div>
+  </div>
+  <img class="sci-wheel" src="static/home/images/sci.gif" alt="">
+  <!-- 导航 -->
+  <div class="center">
+    <a class="list fn_1 moveUpDownFla1"  href="/platlive/market/index">
+      <p>科技超市</p>
+    </a>
+    <a class="list fn_2 moveUpDownFla2"  href="/platlive/live/index">
+      <p>直播大厅</p>
+    </a>
+    <a class="list fn_3 moveUpDownFla1"  href="/platlive/dynamic/index">
+      <p>数据动态</p>
+    </a>
+    <a class="list fn_4 moveUpDownFla2"  href="/platlive/news/index">
+      <p>新闻资讯</p>
+    </a>
+    <a class="list fn_5 moveUpDownFla2"  href="/platlive/techolchat/index">
+      <p>技术交流</p>
+    </a>
+  </div>
+  <!-- 浮窗 -->
+  <div id="floatingDiv" style="position:absolute;left:50px;top:60px;z-index: 9999;">
+    <div id="a" onClick="javascript:this.parentNode.style.display='none';">关闭窗口</div>
+    <div id="app" class='floating'>
+      <p>科技引领新发展 校地合作赢未来</p>
+      <p>{{info.title}}</p>
+      <p><button v-on:click="noticeBtn">展会入口</button></p>
+    </div>
+  </div>
+  <!--流星-->
+  <div class="liuxing liuxing1 liuxingFla"></div>
+  <div class="liuxing liuxing2 liuxingFla2"></div>
+  <div class="liuxing liuxing3 liuxingFla3"></div>
+  <div class="liuxing liuxing4 liuxingFla4"></div>
+  <div id="canvas-container-1" class="canvas-container">
+    <canvas id="canvas-1"></canvas>
+  </div>
+  <script src="static/home/js/stats.min.js"></script>
+  <script src="static/home/js/three.min.js"></script>
+  <script src="static/js/jquery-1.8.3.min.js"></script>
+  <script type="text/javascript">
+    new Vue({
+      el: '#app',
+      data: {
+        info:{}
+      },
+      created() {
+        this.search();
+      },
+      computed: {},
+      methods: {
+        search(){
+          $.ajax({
+            url: '/api/live/v0/dock/dock',
+            type: "GET",
+            contentType: 'application/json',
+            success:  (res)=> {
+              if (res.errcode == '0') {
+                let data=res.data.find(i=>i.room_id=='1008');
+                if (data) {
+                  this.$set(this, `info`, data);
+                }
+              }
+            },
+            error: function (e) {
+              console.error(e)
+            }
+          })
+        },
+        noticeBtn(){
+          if (this.info.status=='1') {
+            window.location.href = `/platlive/achieveLive/detail?dock_id=${this.info.id}`
+          }else{
+            alert(`展会尚未开启,展会开始时间:${this.info.start_time}!`)
+          }
+          
+        }
+      },
+    })
+</script>
+<script>
+  function ThreeJSCanvas(CANVAS_ID) {
+    var SCREEN_HEIGHT = Math.min(window.innerWidth, window.innerHeight);
+    var SCREEN_WIDTH = SCREEN_HEIGHT;
+    var SCREEN_ASPECT_RATIO = SCREEN_WIDTH / SCREEN_HEIGHT;
+    var canvas, container;
+
+    var container, loader, stats;
+    var renderer, camera, scene;
+    var raycaster, controls;
+
+    var ANIMATION_FRAME_LENGTH = 30,
+      INTERACT_DISTANCE = 2.5;
+    var objetArray = [],
+      animationQueue = [];
+
+    var color1 = [0 / 255, 110 / 255, 255 / 255],
+      color2 = [0 / 255, 255 / 255, 140 / 255];
+
+    var bitmap = [];
+    var BITMAP_SKIP = 1;
+
+    var fov = 90;
+    var cameraPos = [0, 0, 30];
+    var cameraLookAt = [0, 0, 0];
+    var viewHeight = 2 * Math.tan(THREE.Math.degToRad(fov / 2)) * cameraPos[2],
+      viewWidth = viewHeight * SCREEN_ASPECT_RATIO;
+    var mouse = new THREE.Vector3(10000, 10000, -1),
+      mouseScaled = new THREE.Vector3(10000, 10000, -1);
+
+    var frame = 0;
+
+    function init() {
+
+      // Global Variables
+      container = document.getElementById("canvas-container-" + CANVAS_ID);
+      canvas = document.getElementById("canvas-" + CANVAS_ID);
+      canvas.addEventListener('mousemove', onDocumentMouseMove, false);
+
+      loader = new THREE.JSONLoader();
+      stats = new Stats();
+      stats.domElement.classList.add("canvas-stats");
+      stats.domElement.id = "canvas-stats-" + CANVAS_ID;
+
+      /* If you are familiar with python and opencv
+          you can use this python script to generate custom bitmaps 
+          --------------------
+          https://git.io/vdBAu 
+          --------------------
+      */
+      var data = '#000000000000000000011110000000000000000000' +
+        '#000000000000000011111111110000000000000000' +
+        '#000000000000001111111111111100000000000000' +
+        '#000000000000011111111111111110000000000000' +
+        '#000000000000111111111111111111000000000000' +
+        '#000000000001111111111111111111100000000000' +
+        '#000000000011111111111111111111110000000000' +
+        '#000000000011111111111111111111110000000000' +
+        '#000000000111111111111111111111111000000000' +
+        '#000000000111111111111111111111111000000000' +
+        '#000000001111111111111111111111111100000000' +
+        '#000000001111111111111111111111111100000000' +
+        '#000000001111111111111111111111111100000000' +
+        '#000000001111111111111111111111111100000000' +
+        '#000000001111111111111111111111111100000000' +
+        '#000000000111111111111111111111111000000000' +
+        '#000000000111111111111111111111111000000000' +
+        '#000000000111111111111111111111111000000000' +
+        '#000000000011111111111111111111110000000000' +
+        '#000000000011111111111111111111110000000000' +
+        '#000000000001111111111111111111100000000000' +
+        '#000000000001111111111111111111100000000000' +
+        '#000000000000111111111111111111000000000000' +
+        '#000000000000111111111111111110000000000000' +
+        '#000000000000011111111111111110000000000000' +
+        '#000000000000001111111111111100000000000000' +
+        '#000000000000001111111111111100000000000000' +
+        '#000000000000001111111111111000000000000000' +
+        '#000000000000000111111111111000000000000000' +
+        '#000000000000000111111111111000000000000000' +
+        '#000000000000000111111111111000000000000000' +
+        '#000000000000000111111111111000000000000000' +
+        '#000000000000000011111111110000000000000000' +
+        '#000000000000000010000000010000000000000000' +
+        '#000000000000000011111111110000000000000000' +
+        '#000000000000000010000000010000000000000000' +
+        '#000000000000000011111111110000000000000000' +
+        '#000000000000000010000000010000000000000000' +
+        '#000000000000000011111111110000000000000000' +
+        '#000000000000000000100001000000000000000000' +
+        '#000000000000000000110011000000000000000000' +
+        '#000000000000000000011110000000000000000000';
+
+      for (var i = 0; i < data.length; i++) {
+        if (data[i] == '#') {
+          bitmap.push([]);
+        } else {
+          bitmap[bitmap.length - 1].push(data[i] - '0');
+        }
+      }
+
+      container.appendChild(stats.domElement);
+
+      // Renderer
+      renderer = new THREE.WebGLRenderer({
+        alpha: true,
+        antialias: true,
+        canvas: canvas,
+      });
+      renderer.setClearColor(0x212121, 0);
+      renderer.setPixelRatio(window.devicePixelRatio);
+      renderer.shadowMap.enabled = true;
+      renderer.shadowMap.type = THREE.PCFSoftShadowMap;
+      renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
+
+      // Camera and Controls
+      camera = new THREE.PerspectiveCamera(fov, SCREEN_ASPECT_RATIO, 0.1, 1000);
+      // camera = new THREE.OrthographicCamera(-viewWidth, viewWidth, viewHeight, -viewHeight, 1, 300);
+      camera.position.set(cameraPos[0], cameraPos[1], cameraPos[2]);
+      camera.lookAt(new THREE.Vector3(cameraLookAt[0], cameraLookAt[1], cameraLookAt[2]));
+      raycaster = new THREE.Raycaster();
+
+      // controls = new THREE.OrbitControls(camera);
+      // controls.rotateSpeed = 2.0;
+      // controls.zoomSpeed = 2.0;
+      // controls.enableZoom = true;
+      // controls.enablePan = true;
+      // controls.dampingFactor = 0.2;
+      // controls.addEventListener('change', render);
+
+      //Scene
+      scene = new THREE.Scene();
+
+
+      //Lights
+
+      // Making Object Array
+      var xOffset = -bitmap[0].length / (BITMAP_SKIP * 2);
+      var yOffset = bitmap.length / (BITMAP_SKIP * 2);
+      for (var i = 0; i < bitmap.length; i += BITMAP_SKIP) {
+        for (var j = 0; j < bitmap[i].length; j += BITMAP_SKIP) {
+          if (bitmap[i][j] == 1) {
+            planeGeometry = new THREE.PlaneGeometry(1, 1);
+            var circleGeometry = new THREE.CircleGeometry(1, 5);
+            var frac = i / bitmap.length;
+            // Materials
+            planeMaterial = new THREE.MeshBasicMaterial({
+              color: new THREE.Color(
+                color1[0] * frac + color2[0] * (1 - frac),
+                color1[1] * frac + color2[1] * (1 - frac),
+                color1[2] * frac + color2[2] * (1 - frac)
+              ),
+              transparent: true,
+              opacity: THREE.Math.randFloat(0.4, 0.6),
+              side: THREE.DoubleSide
+            });
+
+            var circleMaterial = new THREE.MeshBasicMaterial({
+              color: new THREE.Color(1, 1, 1),
+              transparent: true,
+              opacity: THREE.Math.randFloat(0.8, 1),
+              side: THREE.DoubleSide
+            });
+
+            // Mesh
+            planeMesh = new THREE.Mesh(planeGeometry, planeMaterial);
+            planeMesh.position.set(xOffset + j / BITMAP_SKIP, yOffset - i / BITMAP_SKIP, 0);
+            var randWidth = THREE.Math.randFloat(0.6, 1.2);
+            var randHeight = randWidth
+            planeMesh.scale.set(randWidth, randHeight, 1);
+            scene.add(planeMesh);
+            objetArray.push([planeMesh, false]);
+
+
+            circleMesh = new THREE.Mesh(circleGeometry, circleMaterial);
+            circleMesh.position.set(xOffset + j / BITMAP_SKIP + THREE.Math.randFloat(-0.5, 0.5), yOffset - i / BITMAP_SKIP + THREE.Math.randFloat(-0.5, 0.5), 0.1);
+            var randRadius = THREE.Math.randFloat(0.05, 0.1);
+            circleMesh.scale.set(randRadius, randRadius, 1);
+            scene.add(circleMesh);
+            objetArray.push([circleMesh, false]);
+          }
+
+        }
+      }
+
+
+      //Geometry 
+
+      // Materials
+
+
+      // Mesh
+
+
+      // Helpers
+
+      //Add Stuff to Scene
+
+
+    }
+
+    function animate() {
+
+      requestAnimationFrame(animate);
+      render();
+      stats.update();
+      // controls.update();
+      frame++;
+    }
+
+    function render() {
+
+      while (animationQueue.length > 0) {
+        var obj_index = animationQueue[0][0];
+        var ani_frame = animationQueue[0][1];
+        if (ani_frame > ANIMATION_FRAME_LENGTH) {
+          objetArray[obj_index][1] = false;
+          animationQueue.shift();
+        } else {
+          break;
+        }
+      }
+
+      for (var i = 0; i < objetArray.length; i++) {
+        var obj = objetArray[i][0];
+        var isAnimating = objetArray[i][1];
+        if (isAnimating == false) {
+          var px = obj.position.x;
+          var py = obj.position.y;
+          var dist = Math.sqrt(Math.pow(px - mouseScaled.x, 2) + Math.pow(py - mouseScaled.y, 2));
+          if (dist < INTERACT_DISTANCE) {
+            var startPosVector = obj.position.clone();
+            var mouseRepelVector = new THREE.Vector3().subVectors(startPosVector, mouseScaled).multiplyScalar(THREE.Math.randFloat(INTERACT_DISTANCE + 0.5, INTERACT_DISTANCE + 2) - dist);
+            var endPosVector = new THREE.Vector3().addVectors(startPosVector, mouseRepelVector);
+            animationQueue.push([i, 0, startPosVector, endPosVector]);
+            objetArray[i][1] = true;
+          }
+        }
+      }
+
+      for (var i = 0; i < animationQueue.length; i++) {
+        var obj = objetArray[animationQueue[i][0]][0];
+        var ani_frame = animationQueue[i][1];
+        var startPosVector = animationQueue[i][2];
+        var endPosVector = animationQueue[i][3];
+        var curPosVector = new THREE.Vector3();
+        var frac = 1 - Math.abs(ani_frame - (ANIMATION_FRAME_LENGTH / 2)) / (ANIMATION_FRAME_LENGTH / 2);
+        frac = easeOutQuad(frac);
+        curPosVector.lerpVectors(startPosVector, endPosVector, frac);
+
+        obj.position.x = curPosVector.x;
+        obj.position.y = curPosVector.y;
+        obj.position.z = curPosVector.z;
+        animationQueue[i][1] += 1;
+      }
+
+      mouse = new THREE.Vector3(10000, 10000, -2);
+      mouseScaled = new THREE.Vector3(10000, 10000, -2);
+
+      renderer.render(scene, camera);
+    }
+
+    function onWindowResize() {
+      SCREEN_HEIGHT = Math.min(window.innerWidth, window.innerHeight);
+      SCREEN_WIDTH = SCREEN_HEIGHT;
+      SCREEN_ASPECT_RATIO = SCREEN_WIDTH / SCREEN_HEIGHT;
+      camera.aspect = SCREEN_ASPECT_RATIO;
+      camera.updateProjectionMatrix();
+      renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
+      console.log(SCREEN_WIDTH + "x" + SCREEN_HEIGHT)
+    }
+
+    function onDocumentMouseMove(event) {
+
+      var rect = canvas.getBoundingClientRect();
+
+      mouse.x = event.clientX - rect.left;
+      mouse.y = event.clientY - rect.top;
+
+      mouseScaled.x = mouse.x * viewWidth / SCREEN_WIDTH - viewWidth / 2;
+      mouseScaled.y = -mouse.y * viewHeight / SCREEN_HEIGHT + viewHeight / 2;
+
+    }
+
+    function sigmoid(t) {
+      return 1 / (1 + Math.pow(Math.E, -t));
+    }
+
+    // no easing, no acceleration
+    function linear(t) {
+      return t;
+    }
+    // accelerating from zero velocity
+    function easeInQuad(t) {
+      return t * t;
+    }
+    // decelerating to zero velocity
+    function easeOutQuad(t) {
+      return t * (2 - t);
+    }
+    // acceleration until halfway, then deceleration
+    function easeInOutQuad(t) {
+      return t < .5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
+    }
+    // accelerating from zero velocity 
+    function easeInCubic(t) {
+      return t * t * t;
+    }
+    // decelerating to zero velocity 
+    function easeOutCubic(t) {
+      return (--t) * t * t + 1;
+    }
+    // acceleration until halfway, then deceleration 
+    function easeInOutCubic(t) {
+      return t < .5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1;
+    }
+    // accelerating from zero velocity 
+    function easeInQuart(t) {
+      return t * t * t * t;
+    }
+    // decelerating to zero velocity 
+    function easeOutQuart(t) {
+      return 1 - (--t) * t * t * t;
+    }
+    // acceleration until halfway, then deceleration
+    function easeInOutQuart(t) {
+      return t < .5 ? 8 * t * t * t * t : 1 - 8 * (--t) * t * t * t;
+    }
+    // accelerating from zero velocity
+    function easeInQuint(t) {
+      return t * t * t * t * t;
+    }
+    // decelerating to zero velocity
+    function easeOutQuint(t) {
+      return 1 + (--t) * t * t * t * t;
+    }
+    // acceleration until halfway, then deceleration 
+    function easeInOutQuint(t) {
+      return t < .5 ? 16 * t * t * t * t * t : 1 + 16 * (--t) * t * t * t * t;
+    }
+
+    //Event Handlers
+    window.addEventListener("resize", onWindowResize);
+
+
+    init();
+    animate();
+
+  }
+  ThreeJSCanvas(1);
+</script>
+<script>
+  var xin = true,
+      yin = true;
+    var step = 2;
+    var delay = 10;
+    var $obj;
+    $(function () {
+      $obj = $('#floatingDiv');
+      var time = window.setInterval('move()', delay);
+      $obj.mouseover(function () {
+        clearInterval(time);
+      });
+      $obj.mouseout(function () {
+        time = window.setInterval('move()', delay);
+      });
+    });
+
+    function move() {
+      var left = $obj.offset().left;
+      // console.log(left);
+      var top = $obj.offset().top;
+      var L = (T = 0); //左边界和顶部边界
+      var R = $(window).width() - $obj.width(); // 右边界
+      var B = $(window).height() - $obj.height(); //下边界
+
+      //难点:怎样判断广告的4个边框有没有超出可视化范围!
+      if (left < L) {
+        xin = true; // 水平向右移动
+      }
+      if (left > R) {
+        xin = false;
+      }
+      if (top < T) {
+        yin = true;
+      }
+      if (top > B) {
+        yin = false;
+      }
+      //根据有没有超出范围来确定广告的移动方向
+      left += step * (xin == true ? 1 : -1);
+      top += step * (yin == true ? 1 : -1);
+      // 给div 元素重新定位
+      $obj.offset({
+        top: top,
+        left: left,
+      });
+    }
+
+</script>
+</body>
+<script type="text/javascript" src="static/home/lib/layui/layui.all.js"></script>
+</html>

+ 10 - 10
public/home.html

@@ -79,20 +79,20 @@
   <img class="sci-wheel" src="static/home/images/sci.gif" alt="">
   <!-- 导航 -->
   <div class="center">
-    <a class="list fn_1 moveUpDownFla1"  href="/platlive/market/index">
-      <p>科技超市</p>
-    </a>
-    <a class="list fn_2 moveUpDownFla2"  href="/platlive/live/index">
+    <a class="list fn_1 moveUpDownFla1"  href="/platlive/twoweb/live/index">
       <p>直播大厅</p>
     </a>
-    <a class="list fn_3 moveUpDownFla1"  href="/platlive/dynamic/index">
-      <p>数据动态</p>
+    <a class="list fn_2 moveUpDownFla2"  href="/platlive/twoweb/market/index">
+      <p>科技超市</p>
+    </a>
+    <a class="list fn_3 moveUpDownFla1"  href="/platlive/twoweb/interflow/index">
+      <p>交流合作</p>
     </a>
-    <a class="list fn_4 moveUpDownFla2"  href="/platlive/news/index">
-      <p>新闻资讯</p>
+    <a class="list fn_4 moveUpDownFla2"  href="/platlive/twoweb/service/index">
+      <p>创新服务</p>
     </a>
-    <a class="list fn_5 moveUpDownFla2"  href="/platlive/techolchat/index">
-      <p>技术交流</p>
+    <a class="list fn_5 moveUpDownFla2"  href="/platlive/twoweb/universal/index">
+      <p>科学普及</p>
     </a>
   </div>
   <!-- 浮窗 -->

+ 1 - 0
src/main.js

@@ -12,6 +12,7 @@ import '@/plugins/var';
 import '@/plugins/methods';
 import '@/plugins/setting';
 import '@/plugins/components';
+import '@common/src/assets/icon/iconfont.css';
 import InitStomp from '@/plugins/stomp';
 Vue.config.productionTip = false;
 new Vue({

+ 1 - 1
src/plugins/components.js

@@ -1,7 +1,7 @@
 import Vue from 'vue';
 import dataTable from '@common/src/components/frame/filter-page-table.vue';
 import dataForm from '@common/src/components/frame/form.vue';
-import eUpload from '@common/src/components/frame/upload.vue';
+import eUpload from '@common/src/components/frame/e-upload.vue';
 const Plugin = vue => {
   vue.prototype.$dev_mode = process.env.NODE_ENV === 'development';
   vue.component('data-table', dataTable);

+ 137 - 31
src/router/index.js

@@ -46,6 +46,99 @@ const admin = [
     component: () => import('../views/admin/live/achieve.vue'),
   },
 ];
+const twoweb = [
+  // 直播大厅
+  {
+    path: '/twoweb/live/index',
+    name: 'twoweb_live_index',
+    meta: { title: '直播大厅' },
+    component: () => import('../views/twoweb/live/index.vue'),
+  },
+  {
+    path: '/twoweb/achieveLive/apply',
+    name: 'twoweb_achieveLive_apply',
+    meta: { title: '直播大厅-申请参展', subSite: true },
+    component: () => import('../views/twoweb/achieveLive/apply.vue'),
+  },
+  {
+    path: '/twoweb/market/index',
+    name: 'twoweb_market_index',
+    meta: { title: '科技超市' },
+    component: () => import('../views/twoweb/market/index.vue'),
+  },
+  {
+    path: '/twoweb/market/list',
+    name: 'twoweb_market_list',
+    meta: { title: '科技超市' },
+    component: () => import('../views/twoweb/market/list.vue'),
+  },
+  {
+    path: '/twoweb/interflow/index',
+    name: 'twoweb_interflow_index',
+    meta: { title: '交流合作' },
+    component: () => import('../views/twoweb/interflow/index.vue'),
+  },
+  {
+    path: '/twoweb/interflow/list',
+    name: 'twoweb_interflow_list',
+    meta: { title: '交流合作' },
+    component: () => import('../views/twoweb/interflow/list.vue'),
+  },
+  {
+    path: '/twoweb/service/index',
+    name: 'twoweb_service_index',
+    meta: { title: '创新服务' },
+    component: () => import('../views/twoweb/service/index.vue'),
+  },
+  {
+    path: '/twoweb/service/project',
+    name: 'twoweb_service_project_index',
+    meta: { title: '项目征集' },
+    component: () => import('../views/twoweb/service/project/index.vue'),
+  },
+  {
+    path: '/twoweb/service/question',
+    name: 'twoweb_service_question_index',
+    meta: { title: '调查问卷' },
+    component: () => import('../views/twoweb/service/question/index.vue'),
+  },
+  {
+    path: '/twoweb/service/question/detail',
+    name: 'twoweb_service_question_detail',
+    meta: { title: '调查问卷' },
+    component: () => import('../views/twoweb/service/question/detail.vue'),
+  },
+  {
+    path: '/twoweb/service/product',
+    name: 'twoweb_service_product_index',
+    meta: { title: '信息发布' },
+    component: () => import('../views/twoweb/service/product/index.vue'),
+  },
+  {
+    path: '/twoweb/service/policy',
+    name: 'twoweb_service_policy_index',
+    meta: { title: '高企申报' },
+    component: () => import('../views/twoweb/service/policy/index.vue'),
+  },
+  {
+    path: '/twoweb/service/order',
+    name: 'twoweb_service_order_index',
+    meta: { title: '预约服务' },
+    component: () => import('../views/twoweb/service/order/index.vue'),
+  },
+  {
+    path: '/twoweb/universal/index',
+    name: 'twoweb_universal_index',
+    meta: { title: '科学普及' },
+    component: () => import('../views/twoweb/universal/index.vue'),
+  },
+  {
+    path: '/twoweb/universal/list',
+    name: 'twoweb_universal_list',
+    meta: { title: '科学普及' },
+    component: () => import('../views/twoweb/universal/list.vue'),
+  },
+];
 Vue.use(VueRouter);
 const live = [
   {
@@ -114,37 +207,49 @@ const live = [
     meta: { title: '直播大厅-数据详情', subSite: true },
     component: () => import('../views/achieveLive/model/data-detail.vue'),
   },
-
-  // {
-  //   path: '/achieveLive/expert/index',
-  //   name: 'achieveLive_expert',
-  //   meta: { title: '直播大厅-参展专家', subSite: true },
-  //   component: () => import('../views/achieveLive/expert/index.vue'),
-  // },
-  // {
-  //   path: '/achieveLive/expert/detail',
-  //   name: 'achieveLive_detail',
-  //   meta: { title: '直播大厅-专家详情', subSite: true },
-  //   component: () => import('../views/achieveLive/expert/detail.vue'),
-  // },
-  // {
-  //   path: '/achieveLive/product/index',
-  //   name: 'achieveLive_product',
-  //   meta: { title: '直播大厅-参展项目', subSite: true },
-  //   component: () => import('../views/achieveLive/product/index.vue'),
-  // },
-  // {
-  //   path: '/achieveLive/product/detail',
-  //   name: 'achieveLive_detail',
-  //   meta: { title: '直播大厅-对接项目', subSite: true },
-  //   component: () => import('../views/achieveLive/product/detail.vue'),
-  // },
-  // {
-  //   path: '/achieveLive/news/detail',
-  //   name: 'achieveLive_news_detail',
-  //   meta: { title: '直播大厅-嘉宾访谈,项目路演', subSite: true },
-  //   component: () => import('../views/achieveLive/news/detail.vue'),
-  // },
+  // 2021-06-07-twoweb
+  {
+    path: '/twoweb/achieveLive/before',
+    name: 'twoweb_personalLive_before',
+    meta: { title: '直播大厅-展会活动页', subSite: true },
+    component: () => import('../views/twoweb/achieveLive/before.vue'),
+  },
+  {
+    path: '/twoweb/achieveLive/detail',
+    name: 'twoweb_personalLive_detail',
+    meta: { title: '直播大厅-展会详情', subSite: true },
+    component: () => import('../views/twoweb/achieveLive/detail.vue'),
+  },
+  {
+    path: '/twoweb/achieveLive/model/dataIndex',
+    name: 'twoweb_personalLive_model_dataIndex',
+    meta: { title: '直播大厅-数据列表', subSite: true },
+    component: () => import('../views/twoweb/achieveLive/model/data-index.vue'),
+  },
+  {
+    path: '/twoweb/achieveLive/model/dataDetail',
+    name: 'twoweb_personalLive_model_dataDetail',
+    meta: { title: '直播大厅-数据详情', subSite: true },
+    component: () => import('../views/twoweb/achieveLive/model/data-detail.vue'),
+  },
+  {
+    path: '/twoweb/personalLive/index',
+    name: 'twoweb_personalLive_index',
+    meta: { title: '直播大厅-人才对接', subSite: true },
+    component: () => import('../views/twoweb/personalLive/index.vue'),
+  },
+  {
+    path: '/twoweb/trainLive/index',
+    name: 'twoweb_trainLive_index',
+    meta: { title: '直播大厅-培训问诊', subSite: true },
+    component: () => import('../views/twoweb/trainLive/index.vue'),
+  },
+  {
+    path: '/twoweb/channelLive/index',
+    name: 'twoweb_channelLive_index',
+    meta: { title: '直播大厅-科技频道', subSite: true },
+    component: () => import('../views/twoweb/channelLive/index.vue'),
+  },
   {
     path: '/website',
     name: 'website',
@@ -226,6 +331,7 @@ const live = [
         meta: { title: '科技创新能力评价' },
         component: () => import('../views/newTeck/index.vue'),
       },
+      ...twoweb,
     ],
   },
 ];

+ 13 - 1
src/store/index.js

@@ -40,6 +40,7 @@ import interview from '@common/src/store/interview';
 // 技术新闻
 import column from '@common/src/store/column';
 import news from '@common/src/store/news';
+import universal from '@common/src/store/universal';
 // 调研调查
 import question from '@common/src/store/question';
 import projectsolic from '@common/src/store/projectsolic';
@@ -60,7 +61,12 @@ import questionnaire from '@common/src/store/question/questionnaire';
 import answer from '@common/src/store/question/answer';
 // 科技创新能力评价申请
 import apply from '@common/src/store/newteck/apply';
-
+// 高企申报
+import declare from '@common/src/store/declare';
+import mechanism from '@common/src/store/mechanism';
+// 科教之旅
+import Medium from '@common/src/store/kjzl/Medium';
+import Order from '@common/src/store/kjzl/Order';
 Vue.use(Vuex);
 
 export default new Vuex.Store({
@@ -89,6 +95,7 @@ export default new Vuex.Store({
     interview,
     column,
     news,
+    universal,
     question,
     projectsolic,
     category,
@@ -101,5 +108,10 @@ export default new Vuex.Store({
     questionnaire,
     answer,
     apply,
+    declare,
+    mechanism,
+    // 科教之旅
+    Medium,
+    Order,
   },
 });

+ 154 - 0
src/views/twoweb/achieveLive/apply.vue

@@ -0,0 +1,154 @@
+<template>
+  <div id="apply">
+    <el-row>
+      <el-col :span="24" class="main">
+        <div class="w_1200">
+          <el-col :span="24" class="one">
+            <el-col :span="3">
+              <el-image :src="img_path" style="width:105px;height:105px;"></el-image>
+            </el-col>
+            <el-col :span="20">
+              <p>温馨提示:</p>
+              <p>1、为了保证您的信息能顺利通过我们的审核,请将信息的真实情况尽可能全面的发布出来!</p>
+              <p>2、根据我们的长期跟踪统计,信息完整度越高,越容易获得目标客户的关注!</p>
+              <p>3、信息完整度越高,将在我们的平台搜索结果排序靠前、获得推荐机会,以及享受增值服务试用机会!</p>
+            </el-col>
+          </el-col>
+          <el-col :span="24" class="two">
+            <el-form :model="form" :rules="rules" ref="form" label-width="100px">
+              <el-form-item label="用户名称" prop="name">
+                <el-input v-model="form.name"></el-input>
+              </el-form-item>
+              <el-form-item label="联系电话" prop="phone">
+                <el-input v-model="form.phone"></el-input>
+              </el-form-item>
+              <el-form-item label="申请时间" prop="create_time">
+                <el-date-picker v-model="form.create_time" placeholder="请选择" value-format="yyyy-MM-dd" format="yyyy-MM-dd" type="date"> </el-date-picker>
+              </el-form-item>
+              <el-form-item label="参展项目" prop="productList">
+                <el-select v-model="form.productList" value-key="id" clearable filterable multiple collapse-tags placeholder="请选择选择产品">
+                  <el-option v-for="(item, index) in goodsList" :key="index" :label="`${item.name}(${getType(item.type)})`" :value="item"> </el-option>
+                </el-select>
+              </el-form-item>
+              <el-col :span="24" class="btn">
+                <el-button type="danger" size="mini" @click="resetBtn">取消申请</el-button>
+                <el-button type="success" size="mini" @click="onSubmit('form')">提交申请</el-button>
+              </el-col>
+            </el-form>
+          </el-col>
+        </div>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: product } = createNamespacedHelpers('product');
+const { mapActions: dockUser } = createNamespacedHelpers('dockUser');
+
+export default {
+  name: 'apply',
+  props: {},
+  components: {},
+  data: function() {
+    return {
+      img_path: require('@common/src/assets/product.png'),
+      form: {},
+      rules: {
+        productList: [],
+      },
+      // 企业成果
+      goodsList: [],
+    };
+  },
+  created() {
+    if (this.user) this.search();
+  },
+  methods: {
+    ...product(['query']),
+    ...dockUser(['create']),
+    async search() {
+      let data = { name: this.user.name, phone: this.user.phone, user_id: this.user.id, dock_id: this.dock_id };
+      this.$set(this, `form`, data);
+      let res = await this.query({ user_id: this.user.id, status: '2' });
+      if (this.$checkRes(res)) {
+        this.$set(this, `goodsList`, res.data);
+      }
+    },
+
+    // 提交申请
+    onSubmit(formName) {
+      this.$refs[formName].validate(async valid => {
+        if (valid) {
+          let data = this.form;
+          let res = await this.create(data);
+          if (this.$checkRes(res)) {
+            this.$message({
+              message: '申请参展成功!',
+              type: 'success',
+            });
+            this.resetBtn();
+          }
+        } else {
+          console.log('error submit!!');
+          return false;
+        }
+      });
+    },
+    // 整理类型
+    getType(type) {
+      if (type == '0') return '科技需求';
+      else if (type == '1') return '技术成果';
+      else if (type == '2') return '商务服务';
+    },
+    // 取消申请
+    resetBtn() {
+      this.$router.push({ path: '/twoweb/live/index' });
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+    dock_id() {
+      return this.$route.query.id;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  min-height: 557px;
+  padding: 15px 0;
+  .one {
+    background: #f3faff;
+    padding: 15px;
+    border: 1px solid #ccc;
+    margin: 0 0 15px 0;
+    p {
+      font-size: 16px;
+    }
+  }
+  .two {
+    .el-date-editor {
+      width: 100%;
+    }
+    .el-select {
+      width: 100%;
+    }
+    .btn {
+      text-align: center;
+    }
+  }
+}
+</style>

+ 130 - 0
src/views/twoweb/achieveLive/before.vue

@@ -0,0 +1,130 @@
+<template>
+  <div id="before">
+    <el-row>
+      <el-col :span="24" class="style">
+        <el-col :span="24" class="top">
+          <el-col :span="24" class="left">
+            中科在线(长春)
+          </el-col>
+          <el-col :span="24" class="right">
+            直播大厅
+          </el-col>
+        </el-col>
+        <el-col :span="24" class="main">
+          <div class="w_1200">
+            <el-col :span="24" class="title">{{ dockInfo.title }}</el-col>
+            <el-col :span="24" class="txt">主办方:{{ dockInfo.sponsor }}</el-col>
+            <el-col :span="24" class="txt">承办方:{{ dockInfo.organizer }}</el-col>
+            <el-col :span="24" class="txt">技术支持:长春市福瑞科技有限公司</el-col>
+            <el-col :span="24" class="btn">
+              <el-button @click="dockBtn(dockInfo)">进入活动现场<i class="iconfont icon-bofang"></i></el-button>
+            </el-col>
+          </div>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: dock } = createNamespacedHelpers('dock');
+export default {
+  name: 'before',
+  props: {},
+  components: {},
+  data: function() {
+    return {
+      dockInfo: {},
+    };
+  },
+  created() {
+    this.search();
+  },
+  methods: {
+    ...dock(['fetch']),
+    async search() {
+      let res = await this.fetch(this.id);
+      if (this.$checkRes(res)) {
+        this.$set(this, `dockInfo`, res.data);
+      }
+    },
+    dockBtn(data) {
+      if (data.room_id == '1007') {
+        // this.$router.push({ path: '/halltwo/directTwo', query: { dock_id: data.id } });
+        this.$router.push({ path: '/twoweb/achieveLive/detail', query: { dock_id: data.id } });
+      } else {
+        this.$router.push({ path: '/twoweb/achieveLive/detail', query: { dock_id: data.id } });
+      }
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+    id() {
+      return this.$route.query.id;
+    },
+    pageTitle() {
+      return `${this.$route.meta.title}`;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.w_1200 {
+  width: 1200px;
+  margin: 0 auto;
+}
+.style {
+  background-image: url('~@common/src/assets/directBack.png');
+  height: 100vh;
+  background-size: 100% 100%;
+  background-repeat: no-repeat;
+  .top {
+    .left {
+      height: 40px;
+      line-height: 40px;
+      padding: 0 15px;
+      font-size: 20px;
+      color: #fffa93;
+    }
+    .right {
+      text-align: center;
+      color: #fffa93;
+      font-size: 50px;
+      text-shadow: 2px 2px 5px #000;
+    }
+  }
+  .main {
+    text-align: center;
+    margin: 100px 0 0 0;
+    .title {
+      font-size: 40px;
+      color: #fffa93;
+      font-weight: bold;
+      font-family: monospace;
+      padding: 0 0 20px 0;
+      height: 100px;
+    }
+    .txt {
+      font-size: 25px;
+      color: #fffa93;
+      padding: 0 0 10px 0;
+    }
+    /deep/.btn {
+      margin: 50px 0 0 0;
+      .el-button {
+        background: linear-gradient(to bottom, #ffbd00 0%, #fd5a00 100%);
+        color: #fff;
+        border: none;
+        border-radius: 25px;
+        padding: 15px 40px;
+        font-size: 20px;
+      }
+    }
+  }
+}
+</style>

+ 188 - 0
src/views/twoweb/achieveLive/detail.vue

@@ -0,0 +1,188 @@
+<template>
+  <div id="detail">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one">
+          <top :info="info"></top>
+        </el-col>
+        <el-col :span="24" class="two">
+          <div class="w_1200">
+            <el-col :span="24" class="two_1">
+              <el-col :span="12" class="left">
+                <video-data :info="info"></video-data>
+              </el-col>
+              <el-col :span="12" class="right">
+                <imgtext-data></imgtext-data>
+              </el-col>
+            </el-col>
+            <el-col :span="24" class="two_2">
+              <product-data></product-data>
+            </el-col>
+            <el-col :span="24" class="two_3">
+              <expert-data></expert-data>
+            </el-col>
+            <!-- <el-col :span="24" class="two_4">
+              <el-image :src="fourImg"> </el-image>
+            </el-col> -->
+            <el-col :span="24" class="two_5">
+              <el-col :span="8" class="left">
+                <jiabin-data></jiabin-data>
+              </el-col>
+              <el-col :span="8" class="center">
+                <xiangmu-data></xiangmu-data>
+              </el-col>
+              <el-col :span="8" class="right">
+                <chat-data></chat-data>
+              </el-col>
+            </el-col>
+          </div>
+        </el-col>
+        <el-col :span="24" class="foot">
+          <foot></foot>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import foot from '@common/src/components/common/foot.vue';
+import top from './detail/top.vue';
+import videoData from './detail/videoData.vue';
+import imgtextData from './detail/imgtextData.vue';
+import productData from './detail/productData.vue';
+import expertData from './detail/expertData.vue';
+import jiabinData from './detail/jiabinData.vue';
+import xiangmuData from './detail/xiangmuData.vue';
+import chatData from './detail/chatData.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: dock } = createNamespacedHelpers('dock');
+export default {
+  name: 'detail',
+  props: {},
+  components: {
+    foot,
+    top,
+    videoData,
+    imgtextData,
+    productData,
+    expertData,
+    jiabinData,
+    xiangmuData,
+    chatData,
+  },
+  data: function() {
+    return {
+      fourImg: require('@common/src/assets/live/top_bg.png'),
+      info: {},
+    };
+  },
+  created() {
+    if (this.dock_id) this.search();
+  },
+  methods: {
+    ...dock(['fetch']),
+    async search() {
+      let res = await this.fetch(this.dock_id);
+      if (this.$checkRes(res)) {
+        this.$set(this, `info`, res.data);
+      }
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+    dock_id() {
+      return this.$route.query.dock_id;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  .two {
+    .two_1 {
+      height: 480px;
+      background-color: #fff;
+      margin: 0 0 15px 0;
+      .left {
+        width: 49%;
+        height: 480px;
+        margin: 0 15px 0 0;
+        // border: 4px solid #000;
+        box-shadow: 0 0 5px #ccc;
+        border-radius: 5px;
+      }
+      .right {
+        width: 49.5%;
+        height: 480px;
+        box-shadow: 0 0 5px #ccc;
+        border-radius: 5px;
+      }
+    }
+    .two_2 {
+      height: 620px;
+      background-color: #fff;
+      box-shadow: 0 0 5px #ccc;
+      border-radius: 5px;
+      margin: 0 0 15px 0;
+    }
+    .two_3 {
+      height: 560px;
+      background-color: #fff;
+      box-shadow: 0 0 5px #ccc;
+      border-radius: 5px;
+      margin: 0 0 15px 0;
+    }
+    .two_4 {
+      height: 120px;
+      box-shadow: 0 0 5px #ccc;
+      border-radius: 5px;
+      margin: 0 0 15px 0;
+      .el-image {
+        height: 120px;
+        overflow: hidden;
+        border-radius: 5px;
+      }
+    }
+    .two_5 {
+      height: 510px;
+      background-color: #fff;
+      margin: 0 0 15px 0;
+      .left {
+        width: 33%;
+        height: 510px;
+        overflow: hidden;
+        box-shadow: 0 0 5px #ccc;
+        border-radius: 5px;
+        margin: 0 10px 0 0;
+      }
+      .center {
+        width: 33%;
+        height: 510px;
+        overflow: hidden;
+        box-shadow: 0 0 5px #ccc;
+        border-radius: 5px;
+        margin: 0 10px 0 0;
+      }
+      .right {
+        width: 32.3%;
+        height: 510px;
+        overflow: hidden;
+        box-shadow: 0 0 5px #ccc;
+        border-radius: 5px;
+      }
+    }
+  }
+}
+</style>

+ 207 - 0
src/views/twoweb/achieveLive/detail/chatData.vue

@@ -0,0 +1,207 @@
+<template>
+  <div id="chatData">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one">
+          <el-tabs v-model="active" type="card">
+            <el-tab-pane label="公共聊天" name="first">
+              <el-col :span="24" class="first">
+                <el-col :span="24" class="first_1">
+                  <el-col :span="24" class="list" v-for="(item, index) in list" :key="index">
+                    <el-col :span="24" class="name">
+                      <span>[{{ item.send_time }}]</span>
+                      <span>{{ item.sender_name }}</span>
+                    </el-col>
+                    <el-col :span="24" class="content">
+                      {{ item.content }}
+                    </el-col>
+                  </el-col>
+                </el-col>
+                <el-col :span="24" class="first_2">
+                  <el-col :span="14" class="text">
+                    <el-input v-model="text"></el-input>
+                  </el-col>
+                  <el-col :span="10" class="btn">
+                    <el-col :span="10" class="btn_1">
+                      <el-button type="primary" size="mini" @click="send">发送</el-button>
+                    </el-col>
+                    <el-col :span="14" class="btn_1">
+                      <el-popover placement="top" trigger="click">
+                        <el-col :span="24">
+                          <p class="textList" v-for="(item, index) in textList" :key="index" @click="textBtn(item.name)">{{ item.name }}</p>
+                        </el-col>
+                        <el-button slot="reference" type="primary" size="mini">快捷发言</el-button>
+                      </el-popover>
+                    </el-col>
+                  </el-col>
+                </el-col>
+              </el-col>
+            </el-tab-pane>
+          </el-tabs>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: dockChat } = createNamespacedHelpers('dockChat');
+var moment = require('moment');
+export default {
+  name: 'chatData',
+  props: {},
+  components: {},
+  data: function() {
+    return {
+      active: 'first',
+      list: [
+        {
+          send_time: '2021-01-01 10:00:00',
+          sender_name: '发言人',
+          content: '发言内容发言内容发言内容发言内容发言内容',
+        },
+      ],
+      // 发言内容
+      text: '',
+      textList: [{ name: '欢迎欢迎' }, { name: '科技创新' }, { name: '大咖云集' }],
+    };
+  },
+  created() {
+    if (this.dock_id) this.search();
+  },
+  mounted() {
+    this.scrollToBottom();
+  },
+  //每次页面渲染完之后滚动条在最底部
+  updated() {
+    this.scrollToBottom();
+  },
+  methods: {
+    ...dockChat(['query', 'create']),
+    async search() {
+      let res = await this.query({ dock_id: this.dock_id });
+      if (this.$checkRes(res)) {
+        this.$set(this, `list`, res.data);
+      }
+    },
+    async send() {
+      let data = {
+        dock_id: this.dock_id,
+        content: this.text,
+        sender_id: this.user ? this.user.id : this.getData(),
+        sender_name: this.user ? this.user.name : this.getData() + '游客',
+        send_time: moment().format('yyyy-MM-DD HH:mm:ss'),
+      };
+      if (data.content != '') {
+        const res = await this.create(data);
+        this.$checkRes(res, null, '发言成功' || '发言失败');
+        this.$set(this, 'text', '');
+        this.search();
+      } else this.$message.error('请输入信息后发送');
+    },
+    textBtn(text) {
+      this.$set(this, `text`, text);
+      this.send();
+    },
+    // 获取时间戳
+    getData() {
+      let date = moment(new Date()).valueOf();
+      if (date) return date;
+    },
+    // 整理滚动条
+    scrollToBottom: function() {
+      this.$nextTick(() => {
+        var container = this.$el.querySelector('.first_1');
+        container.scrollTop = container.scrollHeight;
+      });
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+    dock_id() {
+      return this.$route.query.dock_id;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  .one {
+    .first {
+      padding: 0 5px;
+      height: 460px;
+      overflow-y: auto;
+      .first_1 {
+        height: 410px;
+        overflow-y: auto;
+        padding: 0 10px 0 0;
+        .list {
+          margin: 0 0 10px 0;
+          .name {
+            margin: 0 0 5px 0;
+            span {
+              font-size: 14px;
+            }
+            span:nth-child(1) {
+              color: #666;
+            }
+            span:nth-child(2) {
+              font-weight: bold;
+              padding: 0 0 0 5px;
+            }
+          }
+          .content {
+            background-color: #f1f1f1;
+            padding: 10px 5px;
+            border-radius: 5px;
+          }
+        }
+      }
+      .first_2 {
+        height: 40px;
+        box-shadow: 0 0 5px #ccc;
+        padding: 5px;
+        border-radius: 5px;
+        .text {
+          /deep/.el-input__inner {
+            height: 30px;
+            line-height: 30px;
+            padding: 0 5px;
+          }
+        }
+        .btn {
+          .btn_1 {
+            height: 40px;
+            line-height: 24px;
+            text-align: center;
+          }
+        }
+      }
+    }
+    /deep/.el-tabs__header {
+      margin: 0 0 10px 0;
+    }
+  }
+}
+.textList {
+  text-align: center;
+  padding: 5px 0;
+  border-bottom: 1px dashed #ccc;
+}
+.textList:hover {
+  cursor: pointer;
+  color: #409eff;
+}
+</style>

+ 152 - 0
src/views/twoweb/achieveLive/detail/expertData.vue

@@ -0,0 +1,152 @@
+<template>
+  <div id="expertData">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one">
+          <el-tabs v-model="active" type="card">
+            <el-tab-pane label="专家智库" name="first">
+              <el-col :span="24" class="first">
+                <el-col :span="8" class="list" v-for="(item, index) in expertList" :key="index">
+                  <el-col :span="6" class="image">
+                    <el-image :src="item.img_path">
+                      <div slot="error" class="image-slot">
+                        <el-image :src="img_url"></el-image>
+                      </div>
+                    </el-image>
+                  </el-col>
+                  <el-col :span="18" class="text">
+                    <p class="textOver">{{ item.name }}</p>
+                    <p class="textOver">{{ item.zwzc }}</p>
+                    <p class="textOver">{{ item.company }}</p>
+                    <p>
+                      <el-button type="primary" size="mini" @click="detail(item)">详情</el-button>
+                      <el-button type="success" size="mini" @click="trans(item)">对接</el-button>
+                    </p>
+                  </el-col>
+                </el-col>
+              </el-col>
+              <el-col :span="24" class="btn">
+                <el-button type="primary" size="mini" @click="moreBtn">查看更多专家</el-button>
+              </el-col>
+            </el-tab-pane>
+          </el-tabs>
+        </el-col>
+      </el-col>
+    </el-row>
+    <el-dialog title="专家信息" :visible.sync="dialog" width="50%" :before-close="close">
+      <expertInfo :form="info" :showBtn="false"></expertInfo>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+import expertInfo from '@c/detail-model/expertInfo.vue';
+const { mapActions: expert } = createNamespacedHelpers('expert');
+export default {
+  name: 'expertData',
+  props: {},
+  components: { expertInfo },
+  data: function() {
+    return {
+      active: 'first',
+      img_url: require('@common/src/assets/live/d10_fbb1.png'),
+      expertList: [],
+      // 专家详情
+      dialog: false,
+      info: {},
+    };
+  },
+  created() {
+    if (this.dock_id) this.search();
+  },
+  methods: {
+    ...expert(['query']),
+    async search({ skip = 0, limit = 9, ...info } = {}) {
+      let res = await this.query({ skip, limit, ...info });
+      if (this.$checkRes(res)) {
+        this.$set(this, `expertList`, res.data);
+      }
+    },
+    // 查看详情
+    detail(data) {
+      this.$set(this, `info`, data);
+      this.dialog = true;
+    },
+    // 关闭详情
+    close() {
+      this.dialog = false;
+    },
+    // 对接
+    trans(data) {
+      this.$router.push({ path: '/twoweb/achieveLive/model/dataDetail', query: { dock_id: this.dock_id, id: data.user_id, viewType: 'expert' } });
+    },
+    // 查看更多项目
+    moreBtn() {
+      this.$router.push({ path: '/twoweb/achieveLive/model/dataIndex', query: { dock_id: this.dock_id, viewType: 'expert' } });
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+    dock_id() {
+      return this.$route.query.dock_id;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  .one {
+    .first {
+      height: 465px;
+      overflow: hidden;
+      padding: 0 10px;
+      .list {
+        width: 32.6%;
+        height: 140px;
+        box-shadow: 0 0 5px #ccc;
+        border-radius: 5px;
+        margin: 5px 10px 10px 0;
+        padding: 10px;
+        .image {
+          height: 120px;
+          overflow: hidden;
+          border: 1px dashed #ccc;
+          .el-image {
+            height: 120px;
+            overflow: hidden;
+          }
+        }
+        .text {
+          padding: 0 0 0 10px;
+          p {
+            font-size: 16px;
+            margin: 0 0 8px 0;
+          }
+          p:nth-child(1) {
+            font-size: 18px;
+            font-weight: bold;
+          }
+        }
+      }
+      .list:nth-child(3n) {
+        margin: 5px 0 10px 0;
+      }
+    }
+    .btn {
+      text-align: center;
+    }
+  }
+}
+</style>

+ 233 - 0
src/views/twoweb/achieveLive/detail/imgtextData.vue

@@ -0,0 +1,233 @@
+<template>
+  <div id="imgtextData">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one">
+          <el-tabs v-model="activeName" type="card">
+            <el-tab-pane label="图文直播" name="first">
+              <el-col :span="24" class="first">
+                <el-col :span="24" class="imgList" v-for="(item, index) in imgList" :key="index">
+                  <el-col :span="24" class="user">
+                    <span>[{{ getDate(item.meta) }}]</span>
+                    <span>展会负责人</span>
+                    <span>
+                      <el-link v-if="item.file_url" :href="item.file_url" target="_blank" :underline="false" class="videoPlay">视频播放</el-link>
+                    </span>
+                  </el-col>
+                  <el-col :span="24" class="content">
+                    {{ item.content }}
+                  </el-col>
+                  <el-col :span="24" class="image">
+                    <!-- <el-image :src="tag.img_url" v-for="(tag, tagindex) in item.url" :key="tagindex"></el-image> -->
+                    <el-image :src="item.img_url">
+                      <div slot="error" class="image-slot">
+                        <i class="el-icon-picture-outline"></i>
+                      </div>
+                    </el-image>
+                  </el-col>
+                </el-col>
+              </el-col>
+            </el-tab-pane>
+            <el-tab-pane label="洽谈合作" name="second">
+              <el-col :span="24" class="second">
+                <el-col :span="24" class="secondList" v-for="(item, index) in secondList" :key="index">
+                  <span>[{{ getDate(item.meta) }}]</span>
+                  <span class="textOver">{{ item.d_name }}</span>
+                  <span>与</span>
+                  <span class="textOver">{{ item.s_name }}</span>
+                  <span>{{ getStatus(item.status) }}</span>
+                </el-col>
+              </el-col>
+            </el-tab-pane>
+            <el-tab-pane label="达成意向" name="third">
+              <el-col :span="24" class="second">
+                <el-col :span="24" class="secondList" v-for="(item, index) in thirdList" :key="index">
+                  <span>[{{ getDate(item.meta) }}]</span>
+                  <span class="textOver">{{ item.d_name }}</span>
+                  <span>与</span>
+                  <span class="textOver">{{ item.s_name }}</span>
+                  <span>{{ getStatus(item.status) }}</span>
+                </el-col>
+              </el-col>
+            </el-tab-pane>
+            <el-tab-pane label="交易完成" name="fourth">
+              <el-col :span="24" class="second">
+                <el-col :span="24" class="secondList" v-for="(item, index) in fourthList" :key="index">
+                  <span>[{{ getDate(item.meta) }}]</span>
+                  <span class="textOver">{{ item.d_name }}</span>
+                  <span>与</span>
+                  <span class="textOver">{{ item.s_name }}</span>
+                  <span>{{ getStatus(item.status) }}</span>
+                </el-col>
+              </el-col>
+            </el-tab-pane>
+          </el-tabs>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: dockImgtxt } = createNamespacedHelpers('dockImgtxt');
+const { mapActions: dockTranscation } = createNamespacedHelpers('dockTranscation');
+var moment = require('moment');
+export default {
+  name: 'imgtextData',
+  props: {},
+  components: {},
+  data: function() {
+    return {
+      activeName: 'first',
+      // 图文列表
+      imgList: [],
+      // 正在洽谈
+      secondList: [],
+      // 达成意向
+      thirdList: [],
+      // 交易完成
+      fourthList: [],
+    };
+  },
+  created() {
+    if (this.dock_id) this.search();
+  },
+  mounted() {
+    this.scrollToBottom();
+  },
+  //每次页面渲染完之后滚动条在最底部
+  updated() {
+    this.scrollToBottom();
+  },
+  methods: {
+    ...dockImgtxt(['query']),
+    ...dockTranscation({ transQuery: 'query' }),
+    async search() {
+      // 查询图文
+      let res = await this.query({ dock_id: this.dock_id });
+      if (this.$checkRes(res)) {
+        this.$set(this, `imgList`, res.data);
+      }
+      res = await this.transQuery({ dock_id: this.dock_id });
+      if (this.$checkRes(res)) {
+        let second = res.data.filter(i => i.status == '0');
+        if (second) this.$set(this, `secondList`, second);
+        let third = res.data.filter(i => i.status == '1');
+        if (third) this.$set(this, `thirdList`, third);
+        let fourth = res.data.filter(i => i.status == '3');
+        if (fourth) this.$set(this, `fourthList`, fourth);
+      }
+    },
+    getDate(val) {
+      let newDate = moment(val.createdAt).format('hh:mm:ss');
+      if (newDate) return newDate;
+    },
+    getStatus(val) {
+      if (val == '0') return '正在洽谈';
+      else if (val == '1') return '达成意向';
+      else if (val == '2') return '交易备案';
+      else if (val == '3') return '交易完成';
+      else if (val == '4') return '交易失败';
+    },
+    // 整理滚动条
+    scrollToBottom: function() {
+      this.$nextTick(() => {
+        var container = this.$el.querySelector('.first');
+        container.scrollTop = container.scrollHeight;
+      });
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+    dock_id() {
+      return this.$route.query.dock_id;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  .one {
+    /deep/.el-tabs__header {
+      margin: 0 0 10px 0;
+    }
+    .first {
+      padding: 0 10px;
+      height: 415px;
+      overflow-y: auto;
+      .imgList {
+        padding: 10px 0 0 0;
+        border-bottom: 1px dashed #ff0000;
+        .user {
+          margin: 0 0 5px 0;
+          span {
+            font-size: 16px;
+          }
+          span:nth-child(2) {
+            padding: 0 0 0 10px;
+            font-weight: bold;
+          }
+          span:nth-child(3) {
+            padding: 0 0 0 20px;
+            .el-link {
+              font-weight: bold;
+              font-size: 16px;
+              top: -3px;
+            }
+          }
+        }
+        .content {
+          padding: 0 0 10px 0;
+          text-indent: 2rem;
+        }
+        .image {
+          .el-image {
+            width: 100%;
+            height: 250px;
+            margin: 0 0 10px 0;
+          }
+        }
+      }
+    }
+    .second {
+      padding: 0 10px;
+      height: 415px;
+      overflow-y: auto;
+      .secondList {
+        border-bottom: 1px dashed #ff0000;
+        padding: 10px 0;
+        span {
+          float: left;
+          font-weight: bold;
+          font-size: 16px;
+        }
+        span:nth-child(1) {
+          color: #ff0000;
+        }
+        span:nth-child(2n) {
+          width: 32%;
+          margin: 0 10px 0 10px;
+        }
+        span:nth-child(3) {
+          color: #666;
+        }
+        span:nth-child(5) {
+          float: right;
+        }
+      }
+    }
+  }
+}
+</style>

+ 130 - 0
src/views/twoweb/achieveLive/detail/jiabinData.vue

@@ -0,0 +1,130 @@
+<template>
+  <div id="jiabinData">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one">
+          <el-tabs v-model="active" type="card">
+            <el-tab-pane label="嘉宾访谈" name="first">
+              <el-col :span="24" class="first">
+                <el-col :span="24" class="list" v-for="(item, index) in list" :key="index" @click.native="detail(item)">
+                  <el-col :span="6" class="image">
+                    <el-image :src="item.picture">
+                      <div slot="error" class="image-slot">
+                        <p>暂无图片</p>
+                      </div>
+                    </el-image>
+                  </el-col>
+                  <el-col :span="18" class="text">
+                    <p class="textOver">{{ item.title }}</p>
+                    <p class="textOver">更新时间:{{ item.publish_time }}</p>
+                    <p class="textOver">信息来源:{{ item.origin }}</p>
+                  </el-col>
+                </el-col>
+              </el-col>
+            </el-tab-pane>
+          </el-tabs>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: interview } = createNamespacedHelpers('interview');
+export default {
+  name: 'jiabinData',
+  props: {},
+  components: {},
+  data: function() {
+    return {
+      active: 'first',
+      list: [],
+    };
+  },
+  created() {
+    if (this.dock_id) this.search();
+  },
+  methods: {
+    ...interview(['query']),
+    async search({ skip = 0, limit = 10, ...info } = {}) {
+      let res = await this.query({ skip, dock_id: this.dock_id, ...info });
+      if (this.$checkRes(res)) this.$set(this, `list`, res.data);
+    },
+    // 详情
+    detail(data) {
+      this.$router.push({ path: '/twoweb/achieveLive/model/dataIndex', query: { dock_id: this.dock_id, id: data.id, type: '0', viewType: 'news' } });
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+    dock_id() {
+      return this.$route.query.dock_id;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  .one {
+    .first {
+      padding: 0 10px;
+      height: 450px;
+      overflow-y: auto;
+      .list {
+        border: 1px solid #ccc;
+        border-radius: 5px;
+        margin: 0 0 10px 0;
+        padding: 10px;
+        .image {
+          height: 80px;
+          overflow: hidden;
+          border: 1px dashed #ccc;
+          text-align: center;
+          .el-image {
+            height: 80px;
+          }
+          p {
+            line-height: 80px;
+          }
+        }
+        .text {
+          padding: 0 0 0 10px;
+          p {
+            font-size: 14px;
+            margin: 0 0 5px 0;
+          }
+          p:nth-child(1) {
+            font-size: 16px;
+            font-weight: bold;
+            padding: 3px 0;
+          }
+        }
+      }
+      .list:hover {
+        cursor: pointer;
+        border: 1px solid #409eff;
+        .text {
+          p:nth-child(1) {
+            color: #409eff;
+          }
+        }
+      }
+    }
+    /deep/.el-tabs__header {
+      margin: 0 0 10px 0;
+    }
+  }
+}
+</style>

+ 229 - 0
src/views/twoweb/achieveLive/detail/productData.vue

@@ -0,0 +1,229 @@
+<template>
+  <div id="productData">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one">
+          <el-tabs v-model="activeName" type="card">
+            <el-tab-pane label="技术成果" name="first">
+              <el-col :span="24" class="first">
+                <el-col :span="5" class="achieveList" v-for="(item, index) in achieveList" :key="index">
+                  <el-col :span="24" class="top">
+                    <p class="textOver">{{ item.name || '暂无' }}</p>
+                    <p>{{ item.achievebrief || '暂无' }}</p>
+                    <p class="textOver">领域:{{ item.field || '暂无' }}</p>
+                    <p class="textOver">联系人{{ item.contacts || '暂无' }}</p>
+                  </el-col>
+                  <el-col :span="24" class="down">
+                    <el-button size="mini" type="primary" @click="detail(item, '1')">详情</el-button>
+                    <el-button size="mini" type="success" @click="trans(item, '1')">对接</el-button>
+                  </el-col>
+                </el-col>
+              </el-col>
+              <el-col :span="24" class="btn">
+                <el-button type="primary" size="mini" @click="moreBtn('1')">查看更多项目</el-button>
+              </el-col>
+            </el-tab-pane>
+            <el-tab-pane label="科技需求" name="second">
+              <el-col :span="24" class="second">
+                <el-col :span="5" class="techolList" v-for="(item, index) in techolList" :key="index">
+                  <el-col :span="24" class="top">
+                    <p>{{ item.name || '暂无' }}</p>
+                    <p class="textOver">领域:{{ item.field || '暂无' }}</p>
+                  </el-col>
+                  <el-col :span="24" class="down">
+                    <el-button size="mini" type="primary" @click="detail(item, '0')">详情</el-button>
+                    <el-button size="mini" type="success" @click="trans(item, '0')">对接</el-button>
+                  </el-col>
+                </el-col>
+              </el-col>
+              <el-col :span="24" class="btn">
+                <el-button type="primary" size="mini" @click="moreBtn('0')">查看更多项目</el-button>
+              </el-col>
+            </el-tab-pane>
+          </el-tabs>
+        </el-col>
+      </el-col>
+    </el-row>
+    <el-dialog title="项目详情" :visible.sync="dialog" width="50%" :before-close="close">
+      <techolInfo :form="info" :showBtn="false" v-if="info.type == '0'"></techolInfo>
+      <achieveInfo :form="info" :showBtn="false" v-else-if="info.type == '1'"></achieveInfo>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import techolInfo from '@c/detail-model/techolInfo.vue';
+import achieveInfo from '@c/detail-model/achieveInfo.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: statistics } = createNamespacedHelpers('statistics');
+export default {
+  name: 'productData',
+  props: {},
+  components: {
+    techolInfo,
+    achieveInfo,
+  },
+  data: function() {
+    return {
+      activeName: 'first',
+      achieveList: [],
+      techolList: [],
+      // 项目详情
+      dialog: false,
+      info: {},
+    };
+  },
+  created() {
+    if (this.dock_id) this.search();
+  },
+  methods: {
+    ...statistics(['dockProduct']),
+    async search({ skip = 0, limit = 10, ...info } = {}) {
+      info.dock_id = this.dock_id;
+      let res = await this.dockProduct({ skip, limit, type: '0', ...info });
+      if (this.$checkRes(res)) {
+        this.$set(this, `techolList`, res.data);
+      }
+      res = await this.dockProduct({ skip, limit, type: '1', ...info });
+      if (this.$checkRes(res)) {
+        this.$set(this, `achieveList`, res.data);
+      }
+    },
+    // 查看详情
+    detail(data, type) {
+      this.$set(this, `info`, data);
+      this.dialog = true;
+    },
+    // 关闭详情
+    close() {
+      this.dialog = false;
+    },
+    // 对接
+    trans(data, type) {
+      this.$router.push({ path: '/twoweb/achieveLive/model/dataDetail', query: { dock_id: this.dock_id, id: data.id, type: type, viewType: 'product' } });
+    },
+    // 查看更多项目
+    moreBtn(type) {
+      this.$router.push({ path: '/twoweb/achieveLive/model/dataIndex', query: { dock_id: this.dock_id, type: type, viewType: 'product' } });
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+    dock_id() {
+      return this.$route.query.dock_id;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  .one {
+    .btn {
+      text-align: center;
+    }
+    .first {
+      padding: 0 10px;
+      height: 530px;
+      overflow: hidden;
+      .achieveList {
+        width: 18.9%;
+        height: 250px;
+        background: url('~@common/src/assets/achieve.png');
+        background-size: 100% 100%;
+        background-repeat: no-repeat;
+        margin: 0 15px 15px 0;
+        padding: 22px 22px 8px 22px;
+        border-radius: 5px;
+        .top {
+          height: 190px;
+          overflow: hidden;
+          p:nth-child(1) {
+            font-size: 18px;
+            font-weight: bold;
+            padding: 5px 0;
+          }
+          p:nth-child(2) {
+            font-size: 12px;
+            overflow: hidden;
+            text-overflow: ellipsis;
+            -webkit-line-clamp: 6;
+            word-break: break-all;
+            display: -webkit-box;
+            -webkit-box-orient: vertical;
+            padding: 0 5px;
+            height: 105px;
+            line-height: 17px;
+          }
+          p:nth-child(3) {
+            font-size: 14px;
+            padding: 4px 0 0 0;
+          }
+          p:nth-child(4) {
+            font-size: 14px;
+            padding: 4px 0 0 0;
+          }
+        }
+        .down {
+          text-align: center;
+        }
+      }
+      .achieveList:nth-child(5n) {
+        margin: 0 0 15px 0;
+      }
+    }
+    .second {
+      padding: 0 10px;
+      height: 530px;
+      overflow: hidden;
+      .techolList {
+        width: 18.9%;
+        height: 250px;
+        border: 1px solid #ccc;
+        border-radius: 5px;
+        margin: 0 15px 15px 0;
+        padding: 22px 22px 8px 22px;
+        .top {
+          height: 190px;
+          overflow: hidden;
+          p:nth-child(1) {
+            height: 145px;
+            text-align: center;
+            font-size: 18px;
+            margin: 0 0 10px 0;
+            overflow: hidden;
+            text-overflow: ellipsis;
+            -webkit-line-clamp: 6;
+            word-break: break-all;
+            display: -webkit-box;
+            -webkit-box-orient: vertical;
+          }
+          p:nth-child(2) {
+            text-align: center;
+            font-size: 16px;
+          }
+        }
+        .down {
+          text-align: center;
+        }
+      }
+      .techolList:nth-child(5n) {
+        margin: 0 0 15px 0;
+      }
+    }
+    /deep/.el-tabs__header {
+      margin: 0 0 10px 0;
+    }
+  }
+}
+</style>

+ 163 - 0
src/views/twoweb/achieveLive/detail/top.vue

@@ -0,0 +1,163 @@
+<template>
+  <div id="top">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one">
+          <div class="w_1200">
+            <el-col :span="24" class="one_1">
+              {{ info.title }}
+            </el-col>
+            <el-col :span="24" class="one_2">
+              主办方:<span>{{ info.sponsor }}</span>
+            </el-col>
+            <el-col :span="24" class="one_3">
+              <p v-for="(item, index) in list" :key="index">
+                <span>{{ item.name }}</span>
+                <span>{{ item.num || 0 }}{{ item.unit }}</span>
+              </p>
+            </el-col>
+          </div>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: statistics } = createNamespacedHelpers('statistics');
+export default {
+  name: 'top',
+  props: {
+    info: { type: Object },
+  },
+  components: {},
+  data: function() {
+    return {
+      list: [
+        {
+          name: '同时在线',
+          num: '252',
+          unit: '人',
+        },
+        {
+          name: '特邀嘉宾',
+          num: 198,
+          unit: '人',
+        },
+        {
+          name: '洽谈合作',
+          num: 0,
+          unit: '项',
+        },
+        {
+          name: '达成意向',
+          num: 0,
+          unit: '项',
+        },
+        {
+          name: '交易完成',
+          num: 0,
+          unit: '项',
+        },
+        {
+          name: '参展项目',
+          num: 13,
+          unit: '项',
+        },
+      ],
+    };
+  },
+  created() {
+    if (this.dock_id) this.search();
+  },
+  methods: {
+    ...statistics(['dockQuery']),
+    async search() {
+      let res = await this.dockQuery({ dock_id: this.dock_id });
+      if (this.$checkRes(res)) {
+        console.log(res);
+        this.$set(this, `list`, res.data);
+      }
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+    dock_id() {
+      return this.$route.query.dock_id;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  .one {
+    background: url('~@common/src/assets/live/dock_top.png');
+    height: 430px;
+    background-repeat: no-repeat;
+    background-size: 100% 100%;
+    .one_1 {
+      text-align: center;
+      font-size: 40px;
+      color: #fff;
+      padding: 6% 8% 0 10%;
+      height: 185px;
+      margin: 0 0 40px 0;
+      overflow: hidden;
+      text-overflow: ellipsis;
+      -webkit-line-clamp: 2;
+      word-break: break-all;
+      display: -webkit-box;
+      -webkit-box-orient: vertical;
+    }
+    .one_2 {
+      text-align: center;
+      font-size: 30px;
+      color: #fff;
+      margin: 0 0 50px 0;
+    }
+    .one_3 {
+      p {
+        float: left;
+        width: 15%;
+        background: #fff;
+        margin: 0 10px 0 10px !important;
+        color: #000;
+        height: 50px;
+        line-height: 50px;
+        border-radius: 30px;
+        span:first-child {
+          display: inline-block;
+          width: 56%;
+          text-align: center;
+          height: 50px;
+          line-height: 50px;
+          font-size: 16px;
+          background: red;
+          border-radius: 30px;
+          color: #fff;
+          font-weight: 700;
+        }
+        span:last-child {
+          display: inline-block;
+          width: 42%;
+          text-align: center;
+          font-size: 15px;
+          font-weight: 700;
+        }
+      }
+    }
+  }
+}
+</style>

+ 178 - 0
src/views/twoweb/achieveLive/detail/videoData.vue

@@ -0,0 +1,178 @@
+<template>
+  <div id="videoData">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="top">
+          <el-col :span="4" class="txt">
+            <span style="color:#FF8400;">视频</span>
+            <span>直播</span>
+          </el-col>
+          <el-col :span="20" class="title textOver">
+            {{ info.title }}
+          </el-col>
+        </el-col>
+        <el-col :span="24" class="video">
+          <video :src="videoPath" controls autoplay loop v-if="videoList != ''">
+            <source src="movie.mp4" type="video/mp4" />
+            <source src="movie.ogg" type="video/ogg" />
+          </video>
+          <div class="videointro" v-else>
+            <p>{{ info.title }}</p>
+          </div>
+        </el-col>
+        <el-col :span="24" class="list">
+          <swiper :list="videoList" :options="options">
+            <template v-slot="{ index, item }">
+              <p :class="`${menuIndex == index ? 'indexClass' : 'videodata'}`" @click="changeMenu(index, item)">{{ item.brief }}</p>
+            </template>
+          </swiper>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import swiper from '@c/frame/swiper-frame.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: dockVideo } = createNamespacedHelpers('dockVideo');
+export default {
+  name: 'videoData',
+  props: {
+    info: { type: Object },
+  },
+  components: {
+    swiper,
+  },
+  data: function() {
+    return {
+      // 视频路径
+      videoPath: '',
+      // 视频列表
+      videoList: [],
+      menuIndex: '0',
+      options: {
+        slidesPerView: 5,
+        spaceBetween: 10,
+        // 分页
+        navigation: {
+          nextEl: '.swiper-button-next',
+          prevEl: '.swiper-button-prev',
+        },
+      },
+    };
+  },
+  async created() {
+    if (this.dock_id) this.search();
+  },
+  methods: {
+    ...dockVideo(['query']),
+    async search() {
+      let res = await this.query({ dock_id: this.dock_id });
+      if (this.$checkRes(res)) {
+        this.$set(this, `videoList`, res.data);
+        this.changeMenu('0', this.videoList[0]);
+      }
+    },
+    changeMenu(index, item) {
+      if (item) {
+        this.menuIndex = index;
+        this.$set(this, `videoPath`, item.file_url);
+      }
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+    dock_id() {
+      return this.$route.query.dock_id;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  .top {
+    height: 60px;
+    overflow: hidden;
+    .txt {
+      height: 60px;
+      line-height: 40px;
+      font-size: 20px;
+      font-weight: 700;
+      text-align: center;
+    }
+    .title {
+      height: 60px;
+      line-height: 65px;
+      font-weight: bolder;
+      -webkit-text-stroke: 1px #6e042c;
+      -webkit-text-fill-color: #fff;
+      letter-spacing: 3px;
+      font-size: 20px;
+    }
+  }
+  .video {
+    height: 370px;
+    overflow: hidden;
+    video {
+      width: 100%;
+      height: 370px;
+      background: #000;
+      object-fit: fill;
+    }
+    .videointro {
+      height: 370px;
+      text-align: center;
+      background-image: url('~@common/src/assets/directBack.png');
+      background-size: 100% 100%;
+      background-repeat: no-repeat;
+      p {
+        text-align: center;
+        font-size: 30px;
+        padding: 60px 15px;
+        color: #fff;
+      }
+    }
+  }
+  .list {
+    height: 45px;
+    overflow: hidden;
+    padding: 5px;
+    .videodata {
+      border-radius: 10px;
+      background: #cccccc8f;
+      height: 39px;
+      line-height: 39px;
+      text-align: center;
+      margin: 2px 0 0 0;
+      font-weight: bold;
+    }
+    .videodata:hover {
+      cursor: pointer;
+      color: #fff;
+      background: #409eff;
+    }
+    .indexClass {
+      border-radius: 10px;
+      height: 39px;
+      line-height: 39px;
+      text-align: center;
+      margin: 2px 0 0 0;
+      font-weight: bold;
+      color: #fff;
+      background: #409eff;
+    }
+  }
+}
+</style>

+ 132 - 0
src/views/twoweb/achieveLive/detail/xiangmuData.vue

@@ -0,0 +1,132 @@
+<template>
+  <div id="xiangmuData">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one">
+          <el-tabs v-model="active" type="card">
+            <el-tab-pane label="项目路演" name="first">
+              <el-col :span="24" class="first">
+                <el-col :span="24" class="list" v-for="(item, index) in list" :key="index" @click.native="detail(item)">
+                  <el-col :span="24" class="title textOver">
+                    {{ item.title }}
+                  </el-col>
+                  <el-col :span="24" class="other">
+                    <el-col :span="24" class="other_info">
+                      更新时间:<span> {{ item.publish_time || '暂无' }}</span>
+                    </el-col>
+                    <el-col :span="24" class="other_info">
+                      信息来源:<span> {{ item.origin || '暂无' }}</span>
+                    </el-col>
+                  </el-col>
+                  <el-col :span="24" class="brief">
+                    {{ item.brief }}
+                  </el-col>
+                </el-col>
+              </el-col>
+            </el-tab-pane>
+          </el-tabs>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: roadShow } = createNamespacedHelpers('roadShow');
+export default {
+  name: 'xiangmuData',
+  props: {},
+  components: {},
+  data: function() {
+    return {
+      active: 'first',
+      list: [],
+    };
+  },
+  created() {
+    if (this.dock_id) this.search();
+  },
+  methods: {
+    ...roadShow(['query']),
+    async search({ skip = 0, limit = 10, ...info } = {}) {
+      let res = await this.query({ skip, dock_id: this.dock_id, ...info });
+      if (this.$checkRes(res)) this.$set(this, `list`, res.data);
+    },
+    // 查看详情
+    // 详情
+    detail(data) {
+      this.$router.push({ path: '/twoweb/achieveLive/model/dataIndex', query: { dock_id: this.dock_id, id: data.id, type: '1', viewType: 'news' } });
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+    dock_id() {
+      return this.$route.query.dock_id;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  .one {
+    .first {
+      padding: 0 10px;
+      height: 450px;
+      overflow-y: auto;
+      .list {
+        border: 1px solid #ccc;
+        padding: 8px;
+        border-radius: 5px;
+        margin: 0 0 10px 0;
+        .title {
+          font-size: 16px;
+          margin: 0 0 3px 0;
+          font-weight: bold;
+        }
+        .other {
+          .other_info {
+            font-size: 14px;
+            margin: 0 0 2px 0;
+            font-size: 14px;
+            color: #666;
+            span {
+              color: #000;
+            }
+          }
+        }
+        .brief {
+          overflow: hidden;
+          text-overflow: ellipsis;
+          -webkit-line-clamp: 1;
+          word-break: break-all;
+          display: -webkit-box;
+          -webkit-box-orient: vertical;
+          font-size: 14px;
+        }
+      }
+      .list:hover {
+        cursor: pointer;
+        border: 1px solid #409eff;
+        .title {
+          color: #409eff;
+        }
+      }
+    }
+    /deep/.el-tabs__header {
+      margin: 0 0 10px 0;
+    }
+  }
+}
+</style>

+ 86 - 0
src/views/twoweb/achieveLive/expert/detail.vue

@@ -0,0 +1,86 @@
+<template>
+  <div id="detail">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one">
+          <el-col :span="24" class="right">
+            <el-button type="primary" size="mini" @click="back">返回活动首页</el-button>
+          </el-col>
+        </el-col>
+        <el-col :span="24" class="two">
+          <expertInfo :form="info"></expertInfo>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import expertInfo from '@c/detail-model/expertInfo.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: expert } = createNamespacedHelpers('expert');
+export default {
+  name: 'detail',
+  props: {},
+  components: {
+    expertInfo,
+  },
+  data: function() {
+    return {
+      info: {},
+    };
+  },
+  created() {
+    if (this.id) this.search();
+  },
+  methods: {
+    ...expert(['fetch']),
+    async search() {
+      let res = await this.fetch(this.id);
+      if (this.$checkRes(res)) {
+        this.$set(this, `info`, res.data);
+      }
+    },
+    back() {
+      this.$router.push({ path: '/twoweb/achieveLive/detail', query: { dock_id: this.dock_id } });
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+    dock_id() {
+      return this.$route.query.dock_id;
+    },
+    id() {
+      return this.$route.query.id;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  min-height: 505px;
+  box-shadow: 0 0 5px #ccc;
+  background-color: #fff;
+  padding: 20px;
+  .one {
+    margin: 0 0 10px 0;
+    height: 40px;
+    overflow: hidden;
+    border-bottom: 2px solid #666;
+    .right {
+      text-align: right;
+    }
+  }
+}
+</style>

+ 111 - 0
src/views/twoweb/achieveLive/expert/index.vue

@@ -0,0 +1,111 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one">
+          <el-col :span="12" class="left">
+            <span>专家总数:{{ total }}人</span>
+          </el-col>
+          <el-col :span="12" class="right">
+            <el-button type="primary" size="mini" @click="back">返回活动首页</el-button>
+          </el-col>
+        </el-col>
+        <el-col :span="24" class="two">
+          <data-table :fields="fields" :opera="opera" :data="list" :total="total" @query="search" @check="toCheck"></data-table>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import dataTable from '@common/src/components/frame/filter-page-table.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: expert } = createNamespacedHelpers('expert');
+export default {
+  name: 'index',
+  props: {},
+  components: { dataTable },
+  data: function() {
+    return {
+      opera: [{ label: '对接', method: 'check' }],
+      fields: [
+        { label: '姓名', prop: 'name' },
+        { label: 'QQ微信', prop: 'qqwx' },
+        { label: '电子邮箱', prop: 'email' },
+        { label: '文化程度', prop: 'education' },
+        { label: '毕业院校', prop: 'school' },
+        { label: '工作单位', prop: 'company' },
+        { label: '职务职称', prop: 'zwzc' },
+      ],
+      list: [],
+      total: 0,
+    };
+  },
+  created() {
+    if (this.dock_id) this.search();
+  },
+  methods: {
+    ...expert(['query']),
+    async search({ skip = 0, limit = 10, ...info } = {}) {
+      let res = await this.query({ skip, limit, ...info });
+      if (this.$checkRes(res)) {
+        this.$set(this, `list`, res.data);
+        this.$set(this, `total`, res.total);
+      }
+    },
+    // 对接
+    toCheck({ data }) {
+      this.$router.push({ path: '/twoweb/achieveLive/model/dataDetail', query: { dock_id: this.dock_id, id: data.user_id, viewType: 'expert' } });
+    },
+    back() {
+      this.$router.push({ path: '/twoweb/achieveLive/detail', query: { dock_id: this.dock_id } });
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+    dock_id() {
+      return this.$route.query.dock_id;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  min-height: 505px;
+  box-shadow: 0 0 5px #ccc;
+  background-color: #fff;
+  padding: 20px;
+  .one {
+    margin: 0 0 10px 0;
+    height: 40px;
+    overflow: hidden;
+    border-bottom: 2px solid #666;
+    .left {
+      span {
+        display: inline-block;
+        background: #ff0000;
+        color: #fff;
+        height: 40px;
+        line-height: 40px;
+        padding: 0px 10px;
+        font-weight: bold;
+      }
+    }
+    .right {
+      text-align: right;
+    }
+  }
+}
+</style>

+ 44 - 0
src/views/twoweb/achieveLive/model/data-detail.vue

@@ -0,0 +1,44 @@
+<template>
+  <div id="data-detail">
+    <data-slot>
+      <component :is="model"></component>
+    </data-slot>
+  </div>
+</template>
+
+<script>
+import dataSlot from './data-slot.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'data-detail',
+  props: {},
+  components: {
+    dataSlot,
+    modelexpert: () => import('../expert/detail.vue'),
+    modelproduct: () => import('../product/detail.vue'),
+  },
+  data: function() {
+    return {};
+  },
+  created() {},
+  methods: {},
+  computed: {
+    ...mapState(['user']),
+    model() {
+      return `model${this.$route.query.viewType}`;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 45 - 0
src/views/twoweb/achieveLive/model/data-index.vue

@@ -0,0 +1,45 @@
+<template>
+  <div id="data-index">
+    <data-slot>
+      <component :is="model"></component>
+    </data-slot>
+  </div>
+</template>
+
+<script>
+import dataSlot from './data-slot.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'data-index',
+  props: {},
+  components: {
+    dataSlot,
+    modelexpert: () => import('../expert/index.vue'),
+    modelproduct: () => import('../product/index.vue'),
+    modelnews: () => import('../news/index.vue'),
+  },
+  data: function() {
+    return {};
+  },
+  created() {},
+  methods: {},
+  computed: {
+    ...mapState(['user']),
+    model() {
+      return `model${this.$route.query.viewType}`;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 71 - 0
src/views/twoweb/achieveLive/model/data-slot.vue

@@ -0,0 +1,71 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one">
+          <top :info="info"></top>
+        </el-col>
+        <el-col :span="24" class="two">
+          <div class="w_1200">
+            <slot></slot>
+          </div>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import top from '../detail/top.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: dock } = createNamespacedHelpers('dock');
+export default {
+  name: 'index',
+  props: {},
+  components: {
+    top,
+  },
+  data: function() {
+    return {
+      info: {},
+    };
+  },
+  created() {
+    if (this.dock_id) this.search();
+  },
+  methods: {
+    ...dock(['fetch']),
+    async search() {
+      let res = await this.fetch(this.dock_id);
+      if (this.$checkRes(res)) {
+        this.$set(this, `info`, res.data);
+      }
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+    dock_id() {
+      return this.$route.query.dock_id;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  .two {
+    position: relative;
+    top: -15px;
+  }
+}
+</style>

+ 164 - 0
src/views/twoweb/achieveLive/news/index.vue

@@ -0,0 +1,164 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one">
+          <el-col :span="12" class="left">
+            <span>{{ type == '0' ? '嘉宾访谈' : '项目路演' }}</span>
+          </el-col>
+          <el-col :span="12" class="right">
+            <el-button type="primary" size="mini" @click="back">返回活动首页</el-button>
+          </el-col>
+        </el-col>
+        <el-col :span="24" class="two">
+          <el-col :span="24" class="title">
+            {{ detailInfo.title }}
+          </el-col>
+          <el-col :span="24" class="other">
+            <span>发布时间:{{ detailInfo.publish_time || '暂无' }}</span>
+            <span>信息来源:{{ detailInfo.origin || '暂无' }}</span>
+          </el-col>
+          <el-col :span="24" class="image" v-if="detailInfo.picture">
+            <el-image :src="detailInfo.picture"></el-image>
+          </el-col>
+          <el-col :span="24" class="video" v-if="detailInfo.filepath">
+            <video :src="detailInfo.filepath" controls="controls">
+              您的浏览器不支持 video 标签。
+            </video>
+          </el-col>
+          <el-col :span="24" class="content">
+            <p v-html="detailInfo.content"></p>
+          </el-col>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: interview } = createNamespacedHelpers('interview');
+const { mapActions: roadShow } = createNamespacedHelpers('roadShow');
+export default {
+  name: 'index',
+  props: {},
+  components: {},
+  data: function() {
+    return {
+      detailInfo: {},
+    };
+  },
+  created() {
+    if (this.id) this.search();
+  },
+  methods: {
+    ...interview({ interviewFetch: 'fetch' }),
+    ...roadShow({ roadShowFetch: 'fetch' }),
+    async search() {
+      if (this.type == '0') {
+        let res = await this.interviewFetch(this.id);
+        if (this.$checkRes(res)) {
+          this.$set(this, `detailInfo`, res.data);
+        }
+      } else if (this.type == '1') {
+        let res = await this.roadShowFetch(this.id);
+        if (this.$checkRes(res)) {
+          this.$set(this, `detailInfo`, res.data);
+        }
+      }
+    },
+    back() {
+      this.$router.push({ path: '/twoweb/achieveLive/detail', query: { dock_id: this.dock_id } });
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+    dock_id() {
+      return this.$route.query.dock_id;
+    },
+    id() {
+      return this.$route.query.id;
+    },
+    type() {
+      return this.$route.query.type;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  min-height: 505px;
+  box-shadow: 0 0 5px #ccc;
+  background-color: #fff;
+  padding: 20px;
+  .one {
+    margin: 0 0 10px 0;
+    height: 40px;
+    overflow: hidden;
+    border-bottom: 2px solid #666;
+    .left {
+      span {
+        display: inline-block;
+        background: #ff0000;
+        color: #fff;
+        height: 40px;
+        line-height: 40px;
+        padding: 0px 10px;
+        font-weight: bold;
+      }
+    }
+    .right {
+      text-align: right;
+    }
+  }
+  .two {
+    .title {
+      text-align: center;
+      font-size: 30px;
+      font-weight: bold;
+      padding: 15px 0;
+    }
+    .other {
+      text-align: center;
+      font-size: 14px;
+      color: #666;
+      padding: 0 0 15px 0;
+      span {
+        padding: 0 0 0 10px;
+      }
+    }
+    .image {
+      text-align: center;
+      height: 300px;
+      overflow: hidden;
+      margin: 0 0 15px 0;
+      .el-image {
+        width: 50%;
+        height: 300px;
+      }
+    }
+    .video {
+      text-align: center;
+      margin: 0 0 15px 0;
+      height: 300px;
+      overflow: hidden;
+      video {
+        width: 50%;
+        height: 300px;
+        background-color: #000000;
+      }
+    }
+  }
+}
+</style>

+ 92 - 0
src/views/twoweb/achieveLive/product/detail.vue

@@ -0,0 +1,92 @@
+<template>
+  <div id="detail">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one">
+          <el-col :span="24" class="right">
+            <el-button type="primary" size="mini" @click="back">返回活动首页</el-button>
+          </el-col>
+        </el-col>
+        <el-col :span="24" class="two">
+          <techolInfo :form="info" v-if="type == '0'"></techolInfo>
+          <achieveInfo :form="info" v-else-if="type == '1'"></achieveInfo>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import techolInfo from '@c/detail-model/techolInfo.vue';
+import achieveInfo from '@c/detail-model/achieveInfo.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: product } = createNamespacedHelpers('product');
+export default {
+  name: 'detail',
+  props: {},
+  components: {
+    techolInfo,
+    achieveInfo,
+  },
+  data: function() {
+    return {
+      info: {},
+    };
+  },
+  created() {
+    if (this.id) this.search();
+  },
+  methods: {
+    ...product(['fetch']),
+    async search() {
+      let res = await this.fetch(this.id);
+      if (this.$checkRes(res)) {
+        this.$set(this, `info`, res.data);
+      }
+    },
+    back() {
+      this.$router.push({ path: '/twoweb/achieveLive/detail', query: { dock_id: this.dock_id } });
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+    dock_id() {
+      return this.$route.query.dock_id;
+    },
+    id() {
+      return this.$route.query.id;
+    },
+    type() {
+      return this.$route.query.type;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  min-height: 505px;
+  box-shadow: 0 0 5px #ccc;
+  background-color: #fff;
+  padding: 20px;
+  .one {
+    margin: 0 0 10px 0;
+    height: 40px;
+    overflow: hidden;
+    border-bottom: 2px solid #666;
+    .right {
+      text-align: right;
+    }
+  }
+}
+</style>

+ 117 - 0
src/views/twoweb/achieveLive/product/index.vue

@@ -0,0 +1,117 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one">
+          <el-col :span="12" class="left">
+            <span>项目成果:{{ total }}项</span>
+          </el-col>
+          <el-col :span="12" class="right">
+            <el-button type="primary" size="mini" @click="back">返回活动首页</el-button>
+          </el-col>
+        </el-col>
+        <el-col :span="24" class="two">
+          <data-table :fields="fields" :opera="opera" :data="list" :total="total" @query="search" @check="toCheck"></data-table>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import dataTable from '@common/src/components/frame/filter-page-table.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: statistics } = createNamespacedHelpers('statistics');
+export default {
+  name: 'index',
+  props: {},
+  components: { dataTable },
+  data: function() {
+    return {
+      opera: [{ label: '对接', method: 'check' }],
+      fields: [
+        { label: '产品类型', prop: 'type', format: i => (i == '0' ? '科技需求' : i == '1' ? '技术成果' : i == '2' ? '商务服务' : '未识别') },
+        { label: '产品名称', prop: 'name' },
+        { label: '所属领域', prop: 'field' },
+        { label: '合作方式', prop: 'cooperation' },
+        { label: '企业名称', prop: 'company' },
+        { label: '联系人', prop: 'contacts' },
+        { label: '联系电话', prop: 'phone' },
+        { label: '电子邮箱', prop: 'email' },
+      ],
+      list: [],
+      total: 0,
+    };
+  },
+  created() {
+    if (this.dock_id) this.search();
+  },
+  methods: {
+    ...statistics(['dockProduct']),
+    async search({ skip = 0, limit = 10, ...info } = {}) {
+      info.dock_id = this.dock_id;
+      info.type = this.type;
+      let res = await this.dockProduct({ skip, limit, ...info });
+      if (this.$checkRes(res)) {
+        this.$set(this, `list`, res.data);
+        this.$set(this, `total`, res.total);
+      }
+    },
+    // 对接
+    toCheck({ data }) {
+      this.$router.push({ path: '/twoweb/achieveLive/model/dataDetail', query: { dock_id: this.dock_id, id: data.id, type: data.type, viewType: 'product' } });
+    },
+    back() {
+      this.$router.push({ path: '/twoweb/achieveLive/detail', query: { dock_id: this.dock_id } });
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+    dock_id() {
+      return this.$route.query.dock_id;
+    },
+    type() {
+      return this.$route.query.type;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  min-height: 505px;
+  box-shadow: 0 0 5px #ccc;
+  background-color: #fff;
+  padding: 20px;
+  .one {
+    margin: 0 0 10px 0;
+    height: 40px;
+    overflow: hidden;
+    border-bottom: 2px solid #666;
+    .left {
+      span {
+        display: inline-block;
+        background: #ff0000;
+        color: #fff;
+        height: 40px;
+        line-height: 40px;
+        padding: 0px 10px;
+        font-weight: bold;
+      }
+    }
+    .right {
+      text-align: right;
+    }
+  }
+}
+</style>

+ 247 - 0
src/views/twoweb/channelLive/index.vue

@@ -0,0 +1,247 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main">
+        <div class="w_1200">
+          <el-col :span="24" class="top">
+            科技频道
+          </el-col>
+          <el-col :span="24" class="info">
+            <el-col :span="24" class="one">
+              <el-button type="primary" size="mini" @click="$router.push({ path: '/twoweb/live/index' })">返回</el-button>
+            </el-col>
+            <el-col :span="24" class="two">
+              <el-col :span="24" class="title">
+                {{ info.title }}
+              </el-col>
+              <el-col :span="24" class="twoVideo">
+                <el-col :span="18" class="left">
+                  <video :src="video_url" controls="" controlsList="nodownload">
+                    您的浏览器不支持 video 标签。
+                  </video>
+                </el-col>
+                <el-col :span="6" class="right">
+                  <h1>视频列表</h1>
+                  <el-col :span="24" class="list">
+                    <el-col :span="24" class="videoList" v-for="(item, index) in videoList" :key="index" @click.native="show(item, index)">
+                      <el-col :span="12" class="file">
+                        <video :src="item.file_path" controlsList="nodownload">
+                          您的浏览器不支持 video 标签。
+                        </video>
+                      </el-col>
+                      <el-col :span="12" class="videoInfo">
+                        <p :style="`color:${menuIndex == index ? menuColor : ''}`">{{ item.title }}</p>
+                        <p class="textOver">{{ item.start_time }}</p>
+                        <p class="textOver">{{ item.end_time }}</p>
+                      </el-col>
+                    </el-col>
+                  </el-col>
+                </el-col>
+              </el-col>
+            </el-col>
+            <el-col :span="24" class="thr">
+              <el-tabs type="border-card">
+                <el-tab-pane label="视频简介">
+                  <p class="textOver"><span>来源:</span>{{ info.origin || '暂无' }}</p>
+                  <p class="textOver"><span>更新时间:</span>{{ info.create_time || '暂无' }}</p>
+                  <p class="textOver"><span>视频简介:</span>{{ info.desc || '暂无' }}</p>
+                </el-tab-pane>
+              </el-tabs>
+            </el-col>
+          </el-col>
+        </div>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: channel } = createNamespacedHelpers('channel');
+const { mapActions: channelVideo } = createNamespacedHelpers('channelVideo');
+
+var moment = require('moment');
+export default {
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  name: 'index',
+  props: {},
+  components: {},
+  data: function() {
+    return {
+      info: {},
+      // 视频
+      video_url: '',
+      videoList: [],
+      menuIndex: '',
+      menuColor: 'rgb(64,158,255)',
+    };
+  },
+  async created() {
+    await this.search();
+  },
+  methods: {
+    ...channel(['fetch']),
+    ...channelVideo(['query']),
+    async search() {
+      let res = await this.fetch(this.id);
+      if (this.$checkRes(res)) {
+        this.$set(this, `info`, res.data);
+      }
+      res = await this.query({ channel_id: this.id });
+      if (this.$checkRes(res)) {
+        // this.$set(this, `videoList`, _.orderBy(res.data, ['start_time'], ['asc']));
+        this.$set(this, `videoList`, res.data);
+      }
+    },
+    show(data, index) {
+      if (data) {
+        this.menuIndex = index;
+        this.$set(this, `video_url`, data.file_path);
+      }
+    },
+    searchvideo() {
+      let data = this.videoList;
+      let adate = moment().format('YYYY-MM-DD HH:mm');
+      let arr = data.find(i => i.start_time <= adate && i.end_time >= adate);
+      let index = data.findIndex(i => i.start_time <= adate && i.end_time >= adate);
+      if (arr && index) {
+        this.show(arr, index);
+      } else {
+        this.show(data[0], '0');
+      }
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+    id() {
+      return this.$route.query.id;
+    },
+  },
+  watch: {
+    videoList: {
+      immediate: true,
+      deep: true,
+      handler(val) {
+        if (val) {
+          this.searchvideo();
+        }
+      },
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  background: url('~@common/src/assets/kjpd.png');
+  background-repeat: no-repeat;
+  background-size: 100% 100%;
+  height: 100vh;
+  .top {
+    font-size: 50px;
+    color: #ffffff;
+    font-family: '楷体';
+    height: 130px;
+    line-height: 130px;
+  }
+  .info {
+    min-height: 700px;
+    background: #ffffff5f;
+    border-radius: 10px;
+    padding: 20px;
+    .one {
+      text-align: right;
+      margin: 0 0 10px 0;
+    }
+    .two {
+      margin: 0 0 10px 0;
+      .title {
+        font-size: 35px;
+        font-weight: bold;
+        text-align: center;
+        font-family: cursive;
+        margin: 0 0 10px 0;
+      }
+      .twoVideo {
+        height: 430px;
+        background: #000;
+        .left {
+          video {
+            width: 100%;
+            height: 430px;
+          }
+        }
+        .right {
+          height: 430px;
+          background: #000;
+          h1 {
+            height: 40px;
+            line-height: 40px;
+            text-align: center;
+            color: #fff;
+            font-size: 16px;
+            background: #409eff;
+            margin: 0;
+          }
+          .list {
+            height: 390px;
+            overflow: auto;
+            padding: 0px 10px;
+            .videoList {
+              border-radius: 10px;
+              border: 1px solid #fff;
+              color: #fff;
+              margin: 10px 0 0 0;
+              height: 120px;
+              .file {
+                video {
+                  width: 100%;
+                  height: 120px;
+                  overflow: hidden;
+                }
+              }
+              .videoInfo {
+                padding: 10px 5px;
+                p {
+                  font-size: 12px;
+                  margin: 0 0 5px 0;
+                }
+                p:nth-child(1) {
+                  font-size: 16px;
+                  overflow: hidden;
+                  text-overflow: ellipsis;
+                  -webkit-line-clamp: 2;
+                  word-break: break-all;
+                  display: -webkit-box;
+                  -webkit-box-orient: vertical;
+                }
+              }
+            }
+            .videoList:hover {
+              cursor: pointer;
+              .videoInfo {
+                p:nth-child(1) {
+                  color: #409eff;
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+    .thr {
+      /deep/.el-tabs--border-card {
+        background: transparent;
+      }
+      p {
+        border-bottom: 1px dashed #ccc;
+        color: #000000;
+        font-weight: bold;
+        padding: 10px 0;
+      }
+    }
+  }
+}
+</style>

+ 127 - 0
src/views/twoweb/interflow/index.vue

@@ -0,0 +1,127 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main">
+        <div class="w_1200">
+          <el-col :span="24" class="one">
+            <el-col :span="12" class="left">
+              <dynamic :list="kydtList"></dynamic>
+            </el-col>
+            <el-col :span="12" class="right">
+              <learning :list="xsjlList"></learning>
+            </el-col>
+          </el-col>
+          <el-col :span="24" class="two">
+            <el-image :src="imgUrl"></el-image>
+          </el-col>
+          <el-col :span="24" class="one">
+            <el-col :span="12" class="left">
+              <cooperation :list="ydhzList"></cooperation>
+            </el-col>
+            <el-col :span="12" class="right">
+              <industry :list="hyyjList"></industry>
+            </el-col>
+          </el-col>
+        </div>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import dynamic from './index/dynamic.vue';
+import learning from './index/learning.vue';
+import cooperation from './index/cooperation.vue';
+import industry from './index/industry.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: column } = createNamespacedHelpers('column');
+const { mapActions: news } = createNamespacedHelpers('news');
+export default {
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  name: 'index',
+  props: {},
+  components: {
+    dynamic,
+    learning,
+    cooperation,
+    industry,
+  },
+  data: function() {
+    return {
+      imgUrl: require('@common/src/assets/center/jlhz.png'),
+      kydtList: [],
+      xsjlList: [],
+      ydhzList: [],
+      hyyjList: [],
+    };
+  },
+  async created() {
+    await this.search();
+  },
+  methods: {
+    ...column({ columnQuery: 'query' }),
+    ...news(['query']),
+    async search({ skip = 0, limit = 11, ...info } = {}) {
+      let res = await this.columnQuery();
+      if (this.$checkRes(res)) {
+        // 科研动态
+        let kydt = res.data.find(i => i.site == 'kydt');
+        let arr = await this.query({ skip, limit, column_id: kydt.id, ...info });
+        if (this.$checkRes(arr)) this.$set(this, `${kydt.site}List`, arr.data);
+        // 学术交流
+        let xsjl = res.data.find(i => i.site == 'xsjl');
+        arr = await this.query({ skip, limit, column_id: xsjl.id, ...info });
+        if (this.$checkRes(arr)) this.$set(this, `${xsjl.site}List`, arr.data);
+        // 院地合作
+        let ydhz = res.data.find(i => i.site == 'ydhz');
+        arr = await this.query({ skip, limit, column_id: ydhz.id, ...info });
+        if (this.$checkRes(arr)) this.$set(this, `${ydhz.site}List`, arr.data);
+        // 行业研究
+        let hyyj = res.data.find(i => i.site == 'hyyj');
+        arr = await this.query({ skip, limit, column_id: hyyj.id, ...info });
+        if (this.$checkRes(arr)) this.$set(this, `${hyyj.site}List`, arr.data);
+      }
+      console.log(res);
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  watch: {},
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  background-image: linear-gradient(#ffffff, #a3d5f6, #ffffff);
+  min-height: 557px;
+  padding: 10px 0;
+  .one {
+    margin: 0 0 10px 0;
+    .left {
+      width: 49%;
+      min-height: 530px;
+      background: #ffffff;
+      padding: 15px;
+      border-radius: 20px;
+      margin: 0 24px 0 0;
+      box-shadow: 0 0 5px #409eff;
+    }
+    .right {
+      width: 49%;
+      min-height: 530px;
+      background: #ffffff;
+      border-radius: 20px;
+      padding: 15px;
+      box-shadow: 0 0 5px #409eff;
+    }
+  }
+  .two {
+    height: 140px;
+    overflow: hidden;
+    margin: 0 0 10px 0;
+  }
+}
+</style>

+ 97 - 0
src/views/twoweb/interflow/index/cooperation.vue

@@ -0,0 +1,97 @@
+<template>
+  <div id="cooperation">
+    <el-row>
+      <el-col :span="24" class="style">
+        <el-col :span="24" class="top">
+          <top :topInfo="topInfo" @moreBtn="moreBtn"></top>
+        </el-col>
+        <el-col :span="24" class="down">
+          <el-col :span="24" class="list" v-for="(item, index) in list" :key="index" @click.native="toDetail(item._id)">
+            <el-col :span="24" class="name">
+              <el-col :span="20" class="title textOver">
+                {{ item.title }}
+              </el-col>
+              <el-col :span="4" class="date textOver">
+                {{ item.publish_time || '暂无' }}
+              </el-col>
+            </el-col>
+          </el-col>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import top from './top.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'cooperation',
+  props: {
+    list: { type: Array },
+  },
+  components: {
+    top,
+  },
+  data: function() {
+    return {
+      topInfo: {
+        title: '院地合作',
+        engTitle: 'cooperation',
+      },
+    };
+  },
+  created() {},
+  methods: {
+    // 查看更多
+    moreBtn() {
+      this.$router.push({ path: '/twoweb/interflow/list', query: { index: 2 } });
+    },
+    toDetail(id) {
+      this.$router.push({ path: '/twoweb/interflow/list', query: { index: 2, id: id } });
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  watch: {},
+};
+</script>
+
+<style lang="less" scoped>
+.style {
+  .top {
+    height: 50px;
+    overflow: hidden;
+  }
+  .down {
+    height: 450px;
+    overflow: hidden;
+    position: relative;
+    .list {
+      border-bottom: 1px dashed #ccc;
+      padding: 9px 0;
+      .name {
+        .title {
+          font-size: 16px;
+          font-weight: bold;
+        }
+        .date {
+          text-align: right;
+        }
+      }
+    }
+    .list:last-child {
+      border-bottom: none;
+    }
+    .list:hover {
+      cursor: pointer;
+      .name {
+        .title {
+          color: #409eff;
+        }
+      }
+    }
+  }
+}
+</style>

+ 97 - 0
src/views/twoweb/interflow/index/dynamic.vue

@@ -0,0 +1,97 @@
+<template>
+  <div id="dynamic">
+    <el-row>
+      <el-col :span="24" class="style">
+        <el-col :span="24" class="top">
+          <top :topInfo="topInfo" @moreBtn="moreBtn"></top>
+        </el-col>
+        <el-col :span="24" class="down">
+          <el-col :span="24" class="list" v-for="(item, index) in list" :key="index" @click.native="toDetail(item._id)">
+            <el-col :span="24" class="name">
+              <el-col :span="20" class="title textOver">
+                {{ item.title }}
+              </el-col>
+              <el-col :span="4" class="date textOver">
+                {{ item.publish_time || '暂无' }}
+              </el-col>
+            </el-col>
+          </el-col>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import top from './top.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'dynamic',
+  props: {
+    list: { type: Array },
+  },
+  components: {
+    top,
+  },
+  data: function() {
+    return {
+      topInfo: {
+        title: '科研动态',
+        engTitle: 'dynamic',
+      },
+    };
+  },
+  created() {},
+  methods: {
+    // 查看更多
+    moreBtn() {
+      this.$router.push({ path: '/twoweb/interflow/list', query: { index: 0 } });
+    },
+    toDetail(id) {
+      this.$router.push({ path: '/twoweb/interflow/list', query: { index: 0, id: id } });
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  watch: {},
+};
+</script>
+
+<style lang="less" scoped>
+.style {
+  .top {
+    height: 50px;
+    overflow: hidden;
+  }
+  .down {
+    height: 450px;
+    overflow: hidden;
+    position: relative;
+    .list {
+      border-bottom: 1px dashed #ccc;
+      padding: 9px 0;
+      .name {
+        .title {
+          font-size: 16px;
+          font-weight: bold;
+        }
+        .date {
+          text-align: right;
+        }
+      }
+    }
+    .list:last-child {
+      border-bottom: none;
+    }
+    .list:hover {
+      cursor: pointer;
+      .name {
+        .title {
+          color: #409eff;
+        }
+      }
+    }
+  }
+}
+</style>

+ 97 - 0
src/views/twoweb/interflow/index/industry.vue

@@ -0,0 +1,97 @@
+<template>
+  <div id="industry">
+    <el-row>
+      <el-col :span="24" class="style">
+        <el-col :span="24" class="top">
+          <top :topInfo="topInfo" @moreBtn="moreBtn"></top>
+        </el-col>
+        <el-col :span="24" class="down">
+          <el-col :span="24" class="list" v-for="(item, index) in list" :key="index" @click.native="toDetail(item._id)">
+            <el-col :span="24" class="name">
+              <el-col :span="20" class="title textOver">
+                {{ item.title }}
+              </el-col>
+              <el-col :span="4" class="date textOver">
+                {{ item.publish_time || '暂无' }}
+              </el-col>
+            </el-col>
+          </el-col>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import top from './top.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'industry',
+  props: {
+    list: { type: Array },
+  },
+  components: {
+    top,
+  },
+  data: function() {
+    return {
+      topInfo: {
+        title: '行业研究',
+        engTitle: 'industry',
+      },
+    };
+  },
+  created() {},
+  methods: {
+    // 查看更多
+    moreBtn() {
+      this.$router.push({ path: '/twoweb/interflow/list', query: { index: 3 } });
+    },
+    toDetail(id) {
+      this.$router.push({ path: '/twoweb/interflow/list', query: { index: 3, id: id } });
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  watch: {},
+};
+</script>
+
+<style lang="less" scoped>
+.style {
+  .top {
+    height: 50px;
+    overflow: hidden;
+  }
+  .down {
+    height: 450px;
+    overflow: hidden;
+    position: relative;
+    .list {
+      border-bottom: 1px dashed #ccc;
+      padding: 9px 0;
+      .name {
+        .title {
+          font-size: 16px;
+          font-weight: bold;
+        }
+        .date {
+          text-align: right;
+        }
+      }
+    }
+    .list:last-child {
+      border-bottom: none;
+    }
+    .list:hover {
+      cursor: pointer;
+      .name {
+        .title {
+          color: #409eff;
+        }
+      }
+    }
+  }
+}
+</style>

+ 97 - 0
src/views/twoweb/interflow/index/learning.vue

@@ -0,0 +1,97 @@
+<template>
+  <div id="learning">
+    <el-row>
+      <el-col :span="24" class="style">
+        <el-col :span="24" class="top">
+          <top :topInfo="topInfo" @moreBtn="moreBtn"></top>
+        </el-col>
+        <el-col :span="24" class="down">
+          <el-col :span="24" class="list" v-for="(item, index) in list" :key="index" @click.native="toDetail(item._id)">
+            <el-col :span="24" class="name">
+              <el-col :span="20" class="title textOver">
+                {{ item.title }}
+              </el-col>
+              <el-col :span="4" class="date textOver">
+                {{ item.publish_time || '暂无' }}
+              </el-col>
+            </el-col>
+          </el-col>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import top from './top.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'industry',
+  props: {
+    list: { type: Array },
+  },
+  components: {
+    top,
+  },
+  data: function() {
+    return {
+      topInfo: {
+        title: '学术交流',
+        engTitle: 'learning',
+      },
+    };
+  },
+  created() {},
+  methods: {
+    // 查看更多
+    moreBtn() {
+      this.$router.push({ path: '/twoweb/interflow/list', query: { index: 1 } });
+    },
+    toDetail(id) {
+      this.$router.push({ path: '/twoweb/interflow/list', query: { index: 1, id: id } });
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  watch: {},
+};
+</script>
+
+<style lang="less" scoped>
+.style {
+  .top {
+    height: 50px;
+    overflow: hidden;
+  }
+  .down {
+    height: 450px;
+    overflow: hidden;
+    position: relative;
+    .list {
+      border-bottom: 1px dashed #ccc;
+      padding: 9px 0;
+      .name {
+        .title {
+          font-size: 16px;
+          font-weight: bold;
+        }
+        .date {
+          text-align: right;
+        }
+      }
+    }
+    .list:last-child {
+      border-bottom: none;
+    }
+    .list:hover {
+      cursor: pointer;
+      .name {
+        .title {
+          color: #409eff;
+        }
+      }
+    }
+  }
+}
+</style>

+ 77 - 0
src/views/twoweb/interflow/index/top.vue

@@ -0,0 +1,77 @@
+<template>
+  <div id="topInfo">
+    <el-row>
+      <el-col :span="24" class="top">
+        <el-col :span="2" class="topImg">
+          <el-image :src="iconImage"></el-image>
+        </el-col>
+        <el-col :span="22" class="topTxt">
+          <span>{{ topInfo.title }}</span>
+          <span>{{ topInfo.engTitle }}</span>
+          <span @click="moreBtn">更多</span>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  name: 'topInfo',
+  props: {
+    topInfo: { typs: Object },
+  },
+  components: {},
+  data: function() {
+    return {
+      iconImage: require('@common/src/assets/square_big.png'),
+    };
+  },
+  created() {},
+  methods: {
+    moreBtn() {
+      this.$emit('moreBtn');
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  watch: {},
+};
+</script>
+
+<style lang="less" scoped>
+.top {
+  height: 50px;
+  .topTxt {
+    height: 45px;
+    border-bottom: 3px solid #044b79;
+    line-height: 45px;
+    padding: 0 5px;
+    span:nth-child(1) {
+      font-size: 24px;
+      font-weight: 700;
+    }
+    span:nth-child(2) {
+      padding: 0 10px;
+      text-transform: Capitalize;
+      font-size: 18px;
+      color: #92959a;
+      font-weight: 700;
+    }
+    span:nth-child(3) {
+      float: right;
+      font-size: 16px;
+      font-weight: bold;
+    }
+    span:nth-child(3):hover {
+      cursor: pointer;
+      color: #409eff;
+    }
+  }
+}
+</style>

+ 122 - 0
src/views/twoweb/interflow/list.vue

@@ -0,0 +1,122 @@
+<template>
+  <div id="list">
+    <el-row>
+      <el-col :span="24" class="main">
+        <div class="w_1200">
+          <el-col :span="5" class="menu">
+            <el-image :src="squareImage"></el-image>
+            <span class="menuTitle">Menu</span>
+            <el-col :span="24" class="menuList" v-for="(item, index) in menuList" :key="index">
+              <p @click="changeMenu(item.component, index)" :style="`color:${menuIndex == index ? menuColor : ''}`">{{ item.name }}</p>
+            </el-col>
+          </el-col>
+          <el-col :span="19" class="listInfo">
+            <component :is="component" v-bind="params"></component>
+          </el-col>
+        </div>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+const _ = require('lodash');
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'list',
+  props: {},
+  components: {
+    dynamic: () => import('./list/dynamic.vue'),
+    learning: () => import('./list/learning.vue'),
+    cooperation: () => import('./list/cooperation.vue'),
+    industry: () => import('./list/industry.vue'),
+  },
+  data: function() {
+    return {
+      component: '',
+      menuList: [
+        { name: '科研动态', component: 'dynamic', options: { useTab: true, listModel: 0 } },
+        { name: '学术交流', component: 'learning', options: { useTab: false, listModel: 1 } },
+        { name: '院地合作', component: 'cooperation', options: { useTab: false, listModel: 2 } },
+        { name: '行业研究', component: 'industry', options: { useTab: true, listModel: 3 } },
+      ],
+      squareImage: require('@p/live/square_big.png'),
+      column_name: '',
+      params: {},
+      menuColor: 'rgb(254, 149, 14)',
+    };
+  },
+  created() {},
+  methods: {
+    changeMenu(component, index) {
+      if (index !== this.menuIndex) this.$router.push({ path: './list', query: { index } });
+      this.component = component;
+    },
+  },
+  computed: {
+    ...mapState(['user', 'menuParams']),
+    pageTitle() {
+      return `${this.$route.meta.title}`;
+    },
+    menuIndex() {
+      const index = this.$route.query.index || 0;
+      const obj = this.menuList[index];
+      const params = {
+        title: _.get(obj, 'name'),
+        ..._.get(obj, 'options'),
+      };
+      this.$set(this, 'component', _.get(obj, 'component', 'dynamic'));
+      this.$set(this, 'params', params);
+      return index;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  min-height: 500px;
+  padding: 10px 0;
+  .menu {
+    height: 600px;
+    overflow: hidden;
+    padding: 15px 10px;
+    background: no-repeat 100% 100%;
+    background-image: url('~@p/live/menu_back.jpg');
+    box-sizing: border-box;
+    box-shadow: 0 0 10px #bbbaba;
+    .menuTitle {
+      font-size: 24px;
+      color: #92959a;
+      font-weight: bold;
+      position: relative;
+      top: -10px;
+      left: 10px;
+    }
+    .menuList {
+      height: 60px;
+      line-height: 60px;
+      border-bottom: 1px solid #2d64b3;
+      p {
+        font-weight: bold;
+        font-size: 18px;
+        color: #044b79;
+      }
+    }
+    .menuList:hover {
+      cursor: pointer;
+    }
+  }
+  .listInfo {
+    float: right;
+    width: 78%;
+    min-height: 600px;
+    overflow: hidden;
+    box-shadow: 0 0 10px #2d64b3;
+    padding: 10px;
+  }
+}
+</style>

+ 106 - 0
src/views/twoweb/interflow/list/cooperation.vue

@@ -0,0 +1,106 @@
+<template>
+  <div id="cooperation">
+    <list-page v-bind="$attrs" :total="total" v-if="!id" @toSearch="search" :pageSize="pageSize" :useTab="false" searchModel="title">
+      <component :is="model" :list="list"></component>
+    </list-page>
+    <template v-else>
+      <dmodel :displayBtn="true" :data="detail" v-if="detail">
+        <el-button size="mini" type="primary" @click="$router.push({ path: './list', query: { index: $route.query.index } })"> 返回</el-button>
+      </dmodel>
+    </template>
+  </div>
+</template>
+
+<script>
+import listPage from '@c/list/list-page.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: column } = createNamespacedHelpers('column');
+const { mapActions: news } = createNamespacedHelpers('news');
+export default {
+  name: 'cooperation',
+  props: ['listModel'],
+  components: {
+    listPage,
+    model2: () => import('@c/list/list-model/model-6.vue'),
+    dmodel: () => import('./detail-model/news-model.vue'),
+  },
+  data: function() {
+    return {
+      list: [],
+      total: 0,
+      detail: {},
+      // 栏目信息
+      column: {},
+      pageSize: 10,
+    };
+  },
+  async created() {
+    await this.searchOther();
+    await this.search();
+  },
+  methods: {
+    ...column({ columnQuery: 'query' }),
+    ...news(['query', 'fetch']),
+    async search({ skip = 0, limit = this.pageSize, ...info } = {}) {
+      // TODO: 查询
+      let res = await this.query({ skip, limit, column_id: this.column.id, ...info });
+      if (this.$checkRes(res)) {
+        this.$set(this, `list`, res.data);
+        this.$set(this, `total`, res.total);
+        // 最后结果处理方式,将显示的信息转换成固定的字段去显示
+        this.$set(this, 'list', this.translate(this.list));
+      }
+    },
+    translate(data) {
+      const list = data.map(i => {
+        const obj = { id: i.id || i._id };
+        obj.p1 = _.get(i, 'title');
+        obj.p2 = _.get(i, 'publish_time');
+        return obj;
+      });
+      return list;
+    },
+    // 查询详情
+    async searchInfo() {
+      let res = await this.fetch(this.id);
+      if (this.$checkRes(res)) {
+        this.$set(this, `detail`, res.data);
+      }
+    },
+    // 查询其他
+    async searchOther() {
+      let res = await this.columnQuery();
+      if (this.$checkRes(res)) {
+        let column = res.data.find(i => i.site == 'ydhz');
+        if (column) this.$set(this, `column`, column);
+      }
+    },
+  },
+  computed: {
+    ...mapState(['user', 'menuParams']),
+    pageTitle() {
+      return `${this.$route.meta.title}`;
+    },
+    model() {
+      const moduleNumber = this.listModel || 0;
+      return `model${moduleNumber}`;
+    },
+    id() {
+      return this.$route.query.id;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    id: {
+      handler(ne) {
+        if (ne) this.searchInfo();
+      },
+      immediate: true,
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 112 - 0
src/views/twoweb/interflow/list/detail-model/news-model.vue

@@ -0,0 +1,112 @@
+<template>
+  <div id="news-model">
+    <el-row type="flex" justify="end">
+      <el-col :span="2">
+        <slot></slot>
+      </el-col>
+    </el-row>
+    <el-row>
+      <el-col :span="24" class="detail">
+        <el-col :span="24" class="one">
+          <p>{{ data.title }}</p>
+          <p>
+            <span>信息来源:{{ data.origin || '暂无' }}</span>
+            <span>发布时间:{{ data.publish_time || '暂无' }}</span>
+          </p>
+        </el-col>
+        <el-col :span="24" class="two" v-if="data.picture != null || undefined">
+          <el-image :src="data.picture"></el-image>
+        </el-col>
+        <el-col :span="24" class="three">
+          <p v-html="data.content"></p>
+        </el-col>
+        <el-col :span="24" class="four" v-if="data.filepath">
+          <h4>附件:</h4>
+          <el-link :href="data.filepath" :underline="false">{{ data.filepathname || '附件下载' }}</el-link>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'news-model',
+  props: {
+    data: { type: Object, default: () => {} },
+  },
+  components: {},
+  data: function() {
+    return {};
+  },
+  created() {},
+  methods: {},
+  computed: {
+    ...mapState(['user', 'menuParams']),
+    pageTitle() {
+      return `${this.$route.meta.title}`;
+    },
+  },
+  metadata() {
+    return { title: this.$route.meta.title };
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.detail {
+  .one {
+    border-bottom: 1px dashed #ccc;
+    margin: 0 0 15px 0;
+    p:nth-child(1) {
+      font-size: 20px;
+      font-weight: bold;
+      color: #044b79;
+      padding: 25px 0;
+      text-align: center;
+    }
+    p:nth-child(2) {
+      padding: 0 0 20px 0;
+      span {
+        display: inline-block;
+        width: 46%;
+        font-size: 16px;
+        color: #666;
+        padding: 0 15px;
+      }
+      span:nth-child(1) {
+        text-align: right;
+      }
+    }
+  }
+  .two {
+    text-align: center;
+    margin: 0 0 15px 0;
+    .el-image {
+      width: 60%;
+    }
+  }
+  .three {
+    margin: 0 0 15px 0;
+    /deep/p {
+      font-size: 16px;
+      font-family: 微软雅黑;
+      color: #444;
+      // img {
+      //   padding: 10px 140px !important;
+      // }
+    }
+  }
+  .four {
+    h4 {
+      color: #400eff;
+      font-weight: bold;
+      margin: 0;
+    }
+    .el-link {
+      padding: 10px 0 0 10px;
+    }
+  }
+}
+</style>

+ 106 - 0
src/views/twoweb/interflow/list/dynamic.vue

@@ -0,0 +1,106 @@
+<template>
+  <div id="dynamic">
+    <list-page v-bind="$attrs" :total="total" v-if="!id" @toSearch="search" :pageSize="pageSize" :useTab="false" searchModel="title">
+      <component :is="model" :list="list"></component>
+    </list-page>
+    <template v-else>
+      <dmodel :displayBtn="true" :data="detail" v-if="detail">
+        <el-button size="mini" type="primary" @click="$router.push({ path: './list', query: { index: $route.query.index } })"> 返回</el-button>
+      </dmodel>
+    </template>
+  </div>
+</template>
+
+<script>
+import listPage from '@c/list/list-page.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: column } = createNamespacedHelpers('column');
+const { mapActions: news } = createNamespacedHelpers('news');
+export default {
+  name: 'dynamic',
+  props: ['listModel'],
+  components: {
+    listPage,
+    model0: () => import('@c/list/list-model/model-6.vue'),
+    dmodel: () => import('./detail-model/news-model.vue'),
+  },
+  data: function() {
+    return {
+      list: [],
+      total: 0,
+      detail: {},
+      // 栏目信息
+      column: {},
+      pageSize: 10,
+    };
+  },
+  async created() {
+    await this.searchOther();
+    await this.search();
+  },
+  methods: {
+    ...column({ columnQuery: 'query' }),
+    ...news(['query', 'fetch']),
+    async search({ skip = 0, limit = this.pageSize, ...info } = {}) {
+      // TODO: 查询
+      let res = await this.query({ skip, limit, column_id: this.column.id, ...info });
+      if (this.$checkRes(res)) {
+        this.$set(this, `list`, res.data);
+        this.$set(this, `total`, res.total);
+        // 最后结果处理方式,将显示的信息转换成固定的字段去显示
+        this.$set(this, 'list', this.translate(this.list));
+      }
+    },
+    translate(data) {
+      const list = data.map(i => {
+        const obj = { id: i.id || i._id };
+        obj.p1 = _.get(i, 'title');
+        obj.p2 = _.get(i, 'publish_time');
+        return obj;
+      });
+      return list;
+    },
+    // 查询详情
+    async searchInfo() {
+      let res = await this.fetch(this.id);
+      if (this.$checkRes(res)) {
+        this.$set(this, `detail`, res.data);
+      }
+    },
+    // 查询其他
+    async searchOther() {
+      let res = await this.columnQuery();
+      if (this.$checkRes(res)) {
+        let column = res.data.find(i => i.site == 'kydt');
+        if (column) this.$set(this, `column`, column);
+      }
+    },
+  },
+  computed: {
+    ...mapState(['user', 'menuParams']),
+    pageTitle() {
+      return `${this.$route.meta.title}`;
+    },
+    model() {
+      const moduleNumber = this.listModel || 0;
+      return `model${moduleNumber}`;
+    },
+    id() {
+      return this.$route.query.id;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    id: {
+      handler(ne) {
+        if (ne) this.searchInfo();
+      },
+      immediate: true,
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 106 - 0
src/views/twoweb/interflow/list/industry.vue

@@ -0,0 +1,106 @@
+<template>
+  <div id="industry">
+    <list-page v-bind="$attrs" :total="total" v-if="!id" @toSearch="search" :pageSize="pageSize" :useTab="false" searchModel="title">
+      <component :is="model" :list="list"></component>
+    </list-page>
+    <template v-else>
+      <dmodel :displayBtn="true" :data="detail" v-if="detail">
+        <el-button size="mini" type="primary" @click="$router.push({ path: './list', query: { index: $route.query.index } })"> 返回</el-button>
+      </dmodel>
+    </template>
+  </div>
+</template>
+
+<script>
+import listPage from '@c/list/list-page.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: column } = createNamespacedHelpers('column');
+const { mapActions: news } = createNamespacedHelpers('news');
+export default {
+  name: 'industry',
+  props: ['listModel'],
+  components: {
+    listPage,
+    model3: () => import('@c/list/list-model/model-6.vue'),
+    dmodel: () => import('./detail-model/news-model.vue'),
+  },
+  data: function() {
+    return {
+      list: [],
+      total: 0,
+      detail: {},
+      // 栏目信息
+      column: {},
+      pageSize: 10,
+    };
+  },
+  async created() {
+    await this.searchOther();
+    await this.search();
+  },
+  methods: {
+    ...column({ columnQuery: 'query' }),
+    ...news(['query', 'fetch']),
+    async search({ skip = 0, limit = this.pageSize, ...info } = {}) {
+      // TODO: 查询
+      let res = await this.query({ skip, limit, column_id: this.column.id, ...info });
+      if (this.$checkRes(res)) {
+        this.$set(this, `list`, res.data);
+        this.$set(this, `total`, res.total);
+        // 最后结果处理方式,将显示的信息转换成固定的字段去显示
+        this.$set(this, 'list', this.translate(this.list));
+      }
+    },
+    translate(data) {
+      const list = data.map(i => {
+        const obj = { id: i.id || i._id };
+        obj.p1 = _.get(i, 'title');
+        obj.p2 = _.get(i, 'publish_time');
+        return obj;
+      });
+      return list;
+    },
+    // 查询详情
+    async searchInfo() {
+      let res = await this.fetch(this.id);
+      if (this.$checkRes(res)) {
+        this.$set(this, `detail`, res.data);
+      }
+    },
+    // 查询其他
+    async searchOther() {
+      let res = await this.columnQuery();
+      if (this.$checkRes(res)) {
+        let column = res.data.find(i => i.site == 'hyyj');
+        if (column) this.$set(this, `column`, column);
+      }
+    },
+  },
+  computed: {
+    ...mapState(['user', 'menuParams']),
+    pageTitle() {
+      return `${this.$route.meta.title}`;
+    },
+    model() {
+      const moduleNumber = this.listModel || 0;
+      return `model${moduleNumber}`;
+    },
+    id() {
+      return this.$route.query.id;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    id: {
+      handler(ne) {
+        if (ne) this.searchInfo();
+      },
+      immediate: true,
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 106 - 0
src/views/twoweb/interflow/list/learning.vue

@@ -0,0 +1,106 @@
+<template>
+  <div id="dynamic">
+    <list-page v-bind="$attrs" :total="total" v-if="!id" @toSearch="search" :pageSize="pageSize" :useTab="false" searchModel="title">
+      <component :is="model" :list="list"></component>
+    </list-page>
+    <template v-else>
+      <dmodel :displayBtn="true" :data="detail" v-if="detail">
+        <el-button size="mini" type="primary" @click="$router.push({ path: './list', query: { index: $route.query.index } })"> 返回</el-button>
+      </dmodel>
+    </template>
+  </div>
+</template>
+
+<script>
+import listPage from '@c/list/list-page.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: column } = createNamespacedHelpers('column');
+const { mapActions: news } = createNamespacedHelpers('news');
+export default {
+  name: 'dynamic',
+  props: ['listModel'],
+  components: {
+    listPage,
+    model1: () => import('@c/list/list-model/model-6.vue'),
+    dmodel: () => import('./detail-model/news-model.vue'),
+  },
+  data: function() {
+    return {
+      list: [],
+      total: 0,
+      detail: {},
+      // 栏目信息
+      column: {},
+      pageSize: 10,
+    };
+  },
+  async created() {
+    await this.searchOther();
+    await this.search();
+  },
+  methods: {
+    ...column({ columnQuery: 'query' }),
+    ...news(['query', 'fetch']),
+    async search({ skip = 0, limit = this.pageSize, ...info } = {}) {
+      // TODO: 查询
+      let res = await this.query({ skip, limit, column_id: this.column.id, ...info });
+      if (this.$checkRes(res)) {
+        this.$set(this, `list`, res.data);
+        this.$set(this, `total`, res.total);
+        // 最后结果处理方式,将显示的信息转换成固定的字段去显示
+        this.$set(this, 'list', this.translate(this.list));
+      }
+    },
+    translate(data) {
+      const list = data.map(i => {
+        const obj = { id: i.id || i._id };
+        obj.p1 = _.get(i, 'title');
+        obj.p2 = _.get(i, 'publish_time');
+        return obj;
+      });
+      return list;
+    },
+    // 查询详情
+    async searchInfo() {
+      let res = await this.fetch(this.id);
+      if (this.$checkRes(res)) {
+        this.$set(this, `detail`, res.data);
+      }
+    },
+    // 查询其他
+    async searchOther() {
+      let res = await this.columnQuery();
+      if (this.$checkRes(res)) {
+        let column = res.data.find(i => i.site == 'xsjl');
+        if (column) this.$set(this, `column`, column);
+      }
+    },
+  },
+  computed: {
+    ...mapState(['user', 'menuParams']),
+    pageTitle() {
+      return `${this.$route.meta.title}`;
+    },
+    model() {
+      const moduleNumber = this.listModel || 0;
+      return `model${moduleNumber}`;
+    },
+    id() {
+      return this.$route.query.id;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    id: {
+      handler(ne) {
+        if (ne) this.searchInfo();
+      },
+      immediate: true,
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 139 - 0
src/views/twoweb/live/achieve/list.vue

@@ -0,0 +1,139 @@
+<template>
+  <div id="list">
+    <el-row>
+      <el-col :span="24">
+        <el-col :span="8" class="list" v-for="(item, index) in achieveList" :key="index">
+          <el-col :span="24" class="image">
+            <el-image :src="imgUrl"></el-image>
+          </el-col>
+          <el-col :span="24" class="info">
+            <el-col :span="24" class="title textOver">
+              <span>[{{ item.room_id }}]</span>
+              <span>{{ item.title }}</span>
+            </el-col>
+            <el-col :span="24" class="other">
+              <el-col :span="10" class="textOver"><i class="el-icon-location-outline"></i>{{ item.province }}-{{ item.city }} </el-col>
+              <el-col :span="14" class="textOver"><i class="el-icon-time"></i>{{ item.start_time }}-{{ item.end_time }} </el-col>
+            </el-col>
+            <el-col :span="24" class="btn">
+              <el-button type="primary" size="mini" @click="toAdmin(item.room_id)">管理进入</el-button>
+              <el-button type="primary" size="mini" v-if="item.status == '1'" @click="liveBtn(item)">进入对接会</el-button>
+              <el-button type="primary" size="mini" v-else-if="item.status == '0'" @click="applyBtn(item)">申请对接会</el-button>
+              <el-button type="primary" size="mini" v-else-if="item.status == '2'">查看成果</el-button>
+            </el-col>
+          </el-col>
+        </el-col>
+      </el-col>
+    </el-row>
+    <el-dialog title="登陆" width="40%" :visible.sync="adminDialog" @closed="handleClose" :destroy-on-close="true">
+      <data-form :data="loginForm" :fields="loginFields" :rules="rules" @save="toSave" submitText="登陆"> </data-form>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+const _ = require('lodash');
+import dataForm from '@common/src/components/frame/form.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: dock } = createNamespacedHelpers('dock');
+export default {
+  name: 'list',
+  props: {
+    achieveList: { type: Array },
+  },
+  components: { dataForm },
+  data: function() {
+    return {
+      adminDialog: false,
+      imgUrl: require('@common/src/assets/hall.jpg'),
+      loginForm: {},
+      loginFields: [
+        { label: '房间号', model: 'room_id', type: 'text' },
+        { label: '登录密码', model: 'password', required: true, type: 'password' },
+      ],
+      rules: {
+        room_phone: [{ required: true, trigger: 'blur', message: '请填写房间号' }],
+        password: [{ required: true, trigger: 'blur', message: '请填写密码' }],
+      },
+    };
+  },
+  created() {},
+  methods: {
+    ...dock(['login']),
+    toAdmin(room_id) {
+      if (_.isEqual(_.get(this.user, 'room_id'), room_id)) this.$router.push({ path: '/admin/live/achieve' });
+      this.adminDialog = true;
+      this.loginForm.room_id = room_id;
+    },
+    handleClose() {
+      this.loginForm = {};
+      this.adminDialog = false;
+    },
+    async toSave() {
+      const res = await this.login(_.cloneDeep(this.loginForm));
+      if (res.errcode != '0') {
+        this.$message.error(res.errmsg);
+      } else {
+        this.$router.push({ path: '/admin/live/achieve' });
+      }
+    },
+    // 申请展会
+    applyBtn(data) {
+      if (this.user) {
+        this.$router.push({ path: '/achieveLive/apply', query: { id: data.id } });
+      } else {
+        this.$message({
+          message: '请先登录,再申请参展!',
+          type: 'warning',
+        });
+      }
+    },
+    // 进入展会
+    liveBtn(data) {
+      this.$router.push({ path: '/twoweb/achieveLive/before', query: { id: data.id } });
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  watch: {},
+};
+</script>
+
+<style lang="less" scoped>
+.list {
+  width: 379px;
+  border: 1px solid #ccc;
+  margin: 0 15px 10px 0;
+  border-radius: 10px;
+  .image {
+    height: 260px;
+    .el-image {
+      height: 260px;
+      border-top-left-radius: 10px;
+      border-top-right-radius: 10px;
+    }
+  }
+  .info {
+    padding: 5px 10px 10px 10px;
+    .title {
+      font-size: 16px;
+      font-weight: bold;
+      padding: 0 0 5px 0;
+      span:nth-child(1) {
+        color: #ff0000;
+      }
+    }
+    .other {
+      font-size: 14px;
+      padding: 0 0 5px 0;
+    }
+    .btn {
+      text-align: center;
+    }
+  }
+}
+.list:nth-child(3n) {
+  margin: 0 0 10px 0;
+}
+</style>

+ 65 - 0
src/views/twoweb/live/index.vue

@@ -0,0 +1,65 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main">
+        <div class="w_1200">
+          <el-tabs type="border-card" class="tab">
+            <el-tab-pane label="科技成果在线">
+              <achieveLive></achieveLive>
+            </el-tab-pane>
+            <el-tab-pane label="人才对接在线">
+              <personalLive></personalLive>
+            </el-tab-pane>
+            <el-tab-pane label="培训问诊在线">
+              <trainLive></trainLive>
+            </el-tab-pane>
+            <el-tab-pane label="科技频道在线">
+              <scienceLive></scienceLive>
+            </el-tab-pane>
+          </el-tabs>
+        </div>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import achieveLive from './parts/achieveLive.vue';
+import personalLive from './parts/personalLive.vue';
+import trainLive from './parts/trainLive.vue';
+import scienceLive from './parts/scienceLive.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  name: 'index',
+  props: {},
+  components: { achieveLive, personalLive, trainLive, scienceLive },
+  data: function() {
+    return {};
+  },
+  created() {},
+  methods: {},
+  computed: {
+    ...mapState(['user']),
+  },
+  watch: {},
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  min-height: 557px;
+  padding: 10px 0;
+  .tab {
+    min-height: 530px;
+    /deep/.el-tabs__item {
+      font-size: 18px;
+      font-weight: bold;
+      height: 50px;
+      line-height: 50px;
+    }
+  }
+}
+</style>

+ 80 - 0
src/views/twoweb/live/parts/achieveLive.vue

@@ -0,0 +1,80 @@
+<template>
+  <div id="achieveLive">
+    <el-row>
+      <el-col :span="24" class="achieve">
+        <el-collapse v-model="active" accordion>
+          <el-collapse-item title="正在直播" name="1">
+            <list :achieveList="oneList"></list>
+          </el-collapse-item>
+          <el-collapse-item title="下期预告" name="2">
+            <list :achieveList="twoList"></list>
+          </el-collapse-item>
+          <el-collapse-item title="已往直播" name="3">
+            <list :achieveList="thrList"></list>
+          </el-collapse-item>
+        </el-collapse>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import list from '../achieve/list.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: dock } = createNamespacedHelpers('dock');
+const { mapActions: place } = createNamespacedHelpers('place');
+export default {
+  name: 'achieveLive',
+  props: {},
+  components: {
+    list,
+  },
+  data: function() {
+    return {
+      active: '1',
+      // 正在直播
+      oneList: [],
+      // 下期预告
+      twoList: [],
+      // 已往直播
+      thrList: [],
+    };
+  },
+  async created() {
+    await this.searchOther();
+  },
+  methods: {
+    ...dock(['query']),
+    ...place({ queryName: 'queryName' }),
+    async searchOther({ skip = 0, limit = 10, ...info } = {}) {
+      let one = await this.query({ skip, status: '1', ...info });
+      let two = await this.query({ skip, status: '0', ...info });
+      let thr = await this.query({ skip, status: '-1', ...info });
+      if (this.$checkRes(one) || this.$checkRes(two) || this.$checkRes(thr)) {
+        for (const val of one.data) this.searchPlace(val);
+        this.$set(this, `oneList`, one.data);
+        for (const val of two.data) this.searchPlace(val);
+        this.$set(this, `twoList`, two.data);
+        for (const val of thr.data) this.searchPlace(val);
+        this.$set(this, `thrList`, thr.data);
+      }
+    },
+    // 查询省市
+    async searchPlace(data) {
+      let nameData = { code: [data.province, data.city] };
+      let res = await this.queryName(nameData);
+      if (this.$checkRes(res)) {
+        data.province = res.data.find(i => i.code == data.province).name;
+        data.city = res.data.find(i => i.code == data.city).name;
+        return data;
+      }
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  watch: {},
+};
+</script>
+
+<style lang="less" scoped></style>

+ 80 - 0
src/views/twoweb/live/parts/personalLive.vue

@@ -0,0 +1,80 @@
+<template>
+  <div id="personalLive">
+    <el-row>
+      <el-col :span="24" class="personal">
+        <el-collapse v-model="active" accordion>
+          <el-collapse-item title="正在直播" name="1">
+            <list :personalList="oneList"></list>
+          </el-collapse-item>
+          <el-collapse-item title="下期预告" name="2">
+            <list :personalList="twoList"></list>
+          </el-collapse-item>
+          <el-collapse-item title="已往直播" name="3">
+            <list :personalList="thrList"></list>
+          </el-collapse-item>
+        </el-collapse>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import list from '../personal/list.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  name: 'personalLive',
+  props: {},
+  components: {
+    list,
+  },
+  data: function() {
+    return {
+      active: '1',
+      oneList: [
+        {
+          room_id: '1001',
+          end_time: '2020-10-23 00:00',
+          place: '吉林省',
+          province: '长春市',
+          start_time: '2020-10-16 10:00',
+          status: '1',
+          title: '人才招聘会模板',
+        },
+      ],
+      twoList: [
+        {
+          room_id: '1001',
+          end_time: '2020-10-23 00:00',
+          place: '吉林省',
+          province: '长春市',
+          start_time: '2020-10-16 10:00',
+          status: '0',
+          title: '人才招聘会模板',
+        },
+      ],
+      thrList: [
+        {
+          room_id: '1001',
+          end_time: '2020-10-23 00:00',
+          place: '吉林省',
+          province: '长春市',
+          start_time: '2020-10-16 10:00',
+          status: '2',
+          title: '人才招聘会模板',
+        },
+      ],
+    };
+  },
+  created() {},
+  methods: {},
+  computed: {
+    ...mapState(['user']),
+  },
+  watch: {},
+};
+</script>
+
+<style lang="less" scoped></style>

+ 146 - 0
src/views/twoweb/live/parts/scienceLive.vue

@@ -0,0 +1,146 @@
+<template>
+  <div id="scienceLive">
+    <el-row>
+      <el-col :span="24">
+        <el-col :span="8" class="list" v-for="(item, index) in list" :key="index">
+          <el-col :span="24" class="image">
+            <el-image :src="imgUrl"></el-image>
+          </el-col>
+          <el-col :span="24" class="info">
+            <el-col :span="24" class="title textOver">
+              <span>[{{ item.room_id }}]</span>
+              <span>{{ item.type }}-{{ item.title }}</span>
+            </el-col>
+            <el-col :span="24" class="other">
+              <el-col :span="12" class="textOver">信息来源:{{ item.origin }} </el-col>
+              <el-col :span="12" class="textOver">更新时间:{{ item.create_time }} </el-col>
+            </el-col>
+            <el-col :span="24" class="btn">
+              <el-button type="warning" size="mini" @click="toAdmin(item.room_id)">管理进入</el-button>
+              <el-button type="primary" size="mini" @click="inChannel(item)">进入频道</el-button>
+            </el-col>
+          </el-col>
+        </el-col>
+      </el-col>
+    </el-row>
+    <el-dialog title="登陆" width="40%" :visible.sync="adminDialog" @closed="handleClose" :destroy-on-close="true">
+      <data-form :data="loginForm" :fields="loginFields" :rules="rules" @save="toSave" submitText="登陆"> </data-form>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+const _ = require('lodash');
+import dataForm from '@common/src/components/frame/form.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: channel } = createNamespacedHelpers('channel');
+const { mapActions: code } = createNamespacedHelpers('code');
+export default {
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  name: 'scienceLive',
+  props: {},
+  components: { dataForm },
+  data: function() {
+    return {
+      adminDialog: false,
+      imgUrl: require('@common/src/assets/kjzx.jpg'),
+      list: [],
+      loginForm: {},
+      loginFields: [
+        { label: '房间号', model: 'room_id', type: 'text' },
+        { label: '登录密码', model: 'passwd', required: true, type: 'password' },
+      ],
+      rules: {
+        room_id: [{ required: true, trigger: 'blur', message: '请填写房间号' }],
+        passwd: [{ required: true, trigger: 'blur', message: '请填写密码' }],
+      },
+    };
+  },
+  async created() {
+    await this.search();
+  },
+  methods: {
+    ...code({ codeQuery: 'query' }),
+    ...channel(['query', 'login']),
+    async search() {
+      let res = await this.query();
+      if (this.$checkRes(res)) {
+        for (const val of res.data) this.searchOther(val);
+      }
+      this.$set(this, `list`, res.data);
+    },
+    async searchOther(val) {
+      let res = await this.codeQuery({ category: '04' });
+      if (this.$checkRes(res)) {
+        val.type = res.data.find(i => i.id == val.type).name;
+        return;
+      }
+    },
+    toAdmin(room_id) {
+      if (_.isEqual(_.get(this.user, 'room_id'), room_id)) this.$router.push({ path: '/admin/live/science' });
+      this.adminDialog = true;
+      this.loginForm.room_id = room_id;
+    },
+    handleClose() {
+      this.loginForm = {};
+      this.adminDialog = false;
+    },
+    async toSave() {
+      const res = await this.login(_.cloneDeep(this.loginForm));
+      if (res.errcode != '0') {
+        this.$message.error(res.errmsg);
+      } else {
+        this.$router.push({ path: '/admin/live/science' });
+      }
+    },
+    // 进入频道
+    inChannel(data) {
+      this.$router.push({ path: '/twoweb/channelLive/index', query: { id: data.id } });
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  watch: {},
+};
+</script>
+
+<style lang="less" scoped>
+.list {
+  width: 379px;
+  border: 1px solid #ccc;
+  margin: 0 15px 10px 0;
+  border-radius: 10px;
+  .image {
+    height: 260px;
+    .el-image {
+      height: 260px;
+      border-top-left-radius: 10px;
+      border-top-right-radius: 10px;
+    }
+  }
+  .info {
+    padding: 5px 10px 10px 10px;
+    .title {
+      font-size: 16px;
+      font-weight: bold;
+      padding: 0 0 5px 0;
+      span:nth-child(1) {
+        color: #ff0000;
+      }
+    }
+    .other {
+      font-size: 14px;
+      padding: 0 0 5px 0;
+    }
+    .btn {
+      text-align: center;
+    }
+  }
+}
+.list:nth-child(3n) {
+  margin: 0 0 10px 0;
+}
+</style>

+ 183 - 0
src/views/twoweb/live/parts/trainLive.vue

@@ -0,0 +1,183 @@
+<template>
+  <div id="trainLive">
+    <el-row>
+      <el-col :span="24">
+        <el-col :span="8" class="list" v-for="(item, index) in list" :key="index">
+          <el-col :span="24" class="image">
+            <el-image :src="imgUrl"></el-image>
+          </el-col>
+          <el-col :span="24" class="info">
+            <el-col :span="24" class="title textOver">
+              <span>[{{ item.room_id }}]</span>
+              <span>{{ item.title }}</span>
+            </el-col>
+            <el-col :span="24" class="other">
+              <el-col :span="12" class="textOver"><i class="el-icon-location-outline"></i>{{ item.province }}-{{ item.place }} </el-col>
+              <el-col :span="12" class="textOver"><i class="el-icon-time"></i>{{ item.start_date }} </el-col>
+            </el-col>
+            <el-col :span="24" class="btn">
+              <el-button type="warning" size="mini" @click="toAdmin(item.room_id)">管理进入</el-button>
+              <el-button type="primary" size="mini" @click="inChannel(item)">进入频道</el-button>
+              <!-- <el-button type="primary" size="mini" @click="logout">退出登录</el-button> -->
+            </el-col>
+          </el-col>
+        </el-col>
+      </el-col>
+    </el-row>
+    <el-dialog title="登陆" width="40%" :visible.sync="adminDialog" @closed="handleClose" :destroy-on-close="true">
+      <data-form :data="loginForm" :fields="loginFields" :rules="rules" @save="toSave" submitText="登陆"> </data-form>
+    </el-dialog>
+    <el-dialog title="用户登录" width="30%" :visible.sync="userDialog" @closed="handleClose" :destroy-on-close="true">
+      <data-form :data="userForm" :fields="userFields" :rules="{}" @save="userToSave"> </data-form>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+const _ = require('lodash');
+import dataForm from '@common/src/components/frame/form.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: mapTrainLive } = createNamespacedHelpers('trainLive');
+const { mapActions: place } = createNamespacedHelpers('place');
+export default {
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  name: 'trainLive',
+  props: {},
+  components: { dataForm },
+  data: function() {
+    return {
+      adminDialog: false,
+      imgUrl: require('@common/src/assets/train.jpg'),
+      list: [],
+      loginForm: {},
+      loginFields: [
+        { label: '房间号', model: 'room_id', type: 'text' },
+        { label: '登录密码', model: 'password', required: true, type: 'password' },
+      ],
+      rules: {
+        room_id: [{ required: true, trigger: 'blur', message: '请填写房间号' }],
+        password: [{ required: true, trigger: 'blur', message: '请填写密码' }],
+      },
+      // 用户登录
+      userDialog: false,
+      userForm: {},
+      userFields: [
+        { label: '账号', model: 'user_phone' },
+        { label: '密码', model: 'user_password', required: true, type: 'password' },
+      ],
+    };
+  },
+  async created() {
+    await this.search();
+  },
+  methods: {
+    ...mapTrainLive(['query', 'login', 'userLogin', 'userLogout']),
+    ...place({ queryName: 'queryName' }),
+    // 查询列表
+    async search() {
+      let res = await this.query();
+      if (this.$checkRes(res)) {
+        for (const val of res.data) this.searchPlace(val);
+        this.$set(this, `list`, res.data);
+      }
+    },
+    // 查询省市
+    async searchPlace(data) {
+      let nameData = { code: [data.province, data.place] };
+      let res = await this.queryName(nameData);
+      if (this.$checkRes(res)) {
+        data.province = res.data.find(i => i.code == data.province).name;
+        data.place = res.data.find(i => i.code == data.place).name;
+        return data;
+      }
+    },
+    // 管理进入
+    toAdmin(room_id) {
+      if (_.isEqual(_.get(this.user, 'room_id'), room_id)) this.$router.push({ path: '/admin/live/train' });
+      this.adminDialog = true;
+      this.loginForm.room_id = room_id;
+    },
+    async toSave() {
+      const res = await this.login(_.cloneDeep(this.loginForm));
+      if (res.errcode != '0') {
+        this.$message.error(res.errmsg);
+      } else {
+        this.$router.push({ path: '/admin/live/train' });
+      }
+    },
+    // 进入频道
+    inChannel(data) {
+      this.$set(this.userForm, `id`, data.id);
+      let user = this.user;
+      this.userDialog = true;
+      // if (user & user._id) {
+      //   this.$router.push({ path: '/trainLive/index', query: { id: data.id } });
+      // } else {
+      //   this.userDialog = true;
+      // }
+    },
+    // 用户登录提交
+    async userToSave({ data }) {
+      let res = await this.userLogin(data);
+      if (this.$checkRes(res)) {
+        this.$router.push({ path: '/twoweb/trainLive/index', query: { id: data.id } });
+      }
+    },
+    // 退出登录
+    async logout() {
+      let res = await this.userLogout('6018c378d08f0821b7648d0c');
+    },
+    // 取消
+    handleClose() {
+      this.loginForm = {};
+      this.adminDialog = false;
+      this.userForm = {};
+      this.userDialog = false;
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  watch: {},
+};
+</script>
+
+<style lang="less" scoped>
+.list {
+  width: 379px;
+  border: 1px solid #ccc;
+  margin: 0 15px 10px 0;
+  border-radius: 10px;
+  .image {
+    height: 260px;
+    .el-image {
+      height: 260px;
+      border-top-left-radius: 10px;
+      border-top-right-radius: 10px;
+    }
+  }
+  .info {
+    padding: 5px 10px 10px 10px;
+    .title {
+      font-size: 16px;
+      font-weight: bold;
+      padding: 0 0 5px 0;
+      span:nth-child(1) {
+        color: #ff0000;
+      }
+    }
+    .other {
+      font-size: 14px;
+      padding: 0 0 5px 0;
+    }
+    .btn {
+      text-align: center;
+    }
+  }
+}
+.list:nth-child(3n) {
+  margin: 0 0 10px 0;
+}
+</style>

+ 90 - 0
src/views/twoweb/live/personal/list.vue

@@ -0,0 +1,90 @@
+<template>
+  <div id="list">
+    <el-row>
+      <el-col :span="24">
+        <el-col :span="8" class="list" v-for="(item, index) in personalList" :key="index">
+          <el-col :span="24" class="image">
+            <el-image :src="imgUrl"></el-image>
+          </el-col>
+          <el-col :span="24" class="info">
+            <el-col :span="24" class="title textOver">
+              <span>[{{ item.room_id }}]</span>
+              <span>{{ item.title }}</span>
+            </el-col>
+            <el-col :span="24" class="other">
+              <el-col :span="10" class="textOver"><i class="el-icon-location-outline"></i>{{ item.province }}-{{ item.place }} </el-col>
+              <el-col :span="14" class="textOver"><i class="el-icon-time"></i>{{ item.start_time }}-{{ item.end_time }} </el-col>
+            </el-col>
+            <el-col :span="24" class="btn">
+              <el-button type="primary" size="mini" @click="inPersonal">进入对接会</el-button>
+            </el-col>
+          </el-col>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'list',
+  props: {
+    personalList: { type: Array },
+  },
+  components: {},
+  data: function() {
+    return {
+      imgUrl: require('@common/src/assets/personal.jpg'),
+    };
+  },
+  created() {},
+  methods: {
+    inPersonal() {
+      this.$router.push({ path: '/twoweb/personalLive/index' });
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  watch: {},
+};
+</script>
+
+<style lang="less" scoped>
+.list {
+  width: 379px;
+  border: 1px solid #ccc;
+  margin: 0 15px 10px 0;
+  border-radius: 10px;
+  .image {
+    height: 260px;
+    .el-image {
+      border-top-left-radius: 10px;
+      border-top-right-radius: 10px;
+      height: 260px;
+    }
+  }
+  .info {
+    padding: 5px 10px 10px 10px;
+    .title {
+      font-size: 16px;
+      font-weight: bold;
+      padding: 0 0 5px 0;
+      span:nth-child(1) {
+        color: #ff0000;
+      }
+    }
+    .other {
+      font-size: 14px;
+      padding: 0 0 5px 0;
+    }
+    .btn {
+      text-align: center;
+    }
+  }
+}
+.list:nth-child(3n) {
+  margin: 0 0 10px 0;
+}
+</style>

+ 116 - 0
src/views/twoweb/market/index.vue

@@ -0,0 +1,116 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main">
+        <div class="w_1200">
+          <el-col :span="24" class="one">
+            <el-col :span="12" class="left">
+              <achieve :list="achieveList"></achieve>
+            </el-col>
+            <el-col :span="12" class="right">
+              <patent :list="patentList"></patent>
+            </el-col>
+          </el-col>
+          <el-col :span="24" class="two">
+            <el-image :src="imgUrl"></el-image>
+          </el-col>
+          <el-col :span="24" class="one">
+            <el-col :span="12" class="left">
+              <roadshow :list="roadshowList"></roadshow>
+            </el-col>
+            <el-col :span="12" class="right">
+              <expert :list="expertList"></expert>
+            </el-col>
+          </el-col>
+        </div>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import achieve from './index/achieve.vue';
+import patent from './index/patent.vue';
+import roadshow from './index/roadshow.vue';
+import expert from './index/expert.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: productIndex } = createNamespacedHelpers('productIndex');
+export default {
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  name: 'index',
+  props: {},
+  components: {
+    achieve,
+    patent,
+    roadshow,
+    expert,
+  },
+  data: function() {
+    return {
+      imgUrl: require('@common/src/assets/center/gqxx.png'),
+      // 技术成果
+      achieveList: [],
+      // e专利
+      patentList: [],
+      // 项目路演
+      roadshowList: [],
+      // 专家智库
+      expertList: [],
+    };
+  },
+  async created() {
+    await this.search();
+  },
+  methods: {
+    ...productIndex(['query']),
+    async search({ skip = 0, limit = 10, ...info } = {}) {
+      let res = await this.query({ ...info });
+      if (this.$checkRes(res)) {
+        this.$set(this, `achieveList`, res.data.achieve);
+        this.$set(this, `patentList`, res.data.patent);
+        this.$set(this, `roadshowList`, res.data.roadShow);
+        this.$set(this, `expertList`, res.data.expert);
+      }
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  watch: {},
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  background-image: linear-gradient(#ffffff, #a3d5f6, #ffffff);
+  min-height: 557px;
+  padding: 10px 0;
+  .one {
+    margin: 0 0 10px 0;
+    .left {
+      width: 49%;
+      min-height: 530px;
+      background: #ffffff;
+      padding: 15px;
+      border-radius: 20px;
+      margin: 0 24px 0 0;
+      box-shadow: 0 0 5px #409eff;
+    }
+    .right {
+      width: 49%;
+      min-height: 530px;
+      background: #ffffff;
+      border-radius: 20px;
+      padding: 15px;
+      box-shadow: 0 0 5px #409eff;
+    }
+  }
+  .two {
+    height: 140px;
+    overflow: hidden;
+    margin: 0 0 10px 0;
+  }
+}
+</style>

+ 133 - 0
src/views/twoweb/market/index/achieve.vue

@@ -0,0 +1,133 @@
+<template>
+  <div id="achieve">
+    <el-row>
+      <el-col :span="24" class="style">
+        <el-col :span="24" class="top">
+          <top :topInfo="topInfo" @moreBtn="moreBtn"></top>
+        </el-col>
+        <el-col :span="24" class="down">
+          <el-col :span="8" class="list" v-for="(item, index) in list" :key="index" @click.native="toDetail(item._id)">
+            <el-col :span="24" class="text">
+              <p class="name textOver">{{ item.name }}</p>
+              <p class="brief">{{ item.achievebrief }}</p>
+              <p class="other">
+                <span class="textOver">领域:{{ item.field }}</span>
+                <span class="textOver">联系人:{{ item.contacts }}</span>
+              </p>
+            </el-col>
+          </el-col>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import top from './top.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'achieve',
+  props: {
+    list: { type: Array },
+  },
+  components: {
+    top,
+  },
+  data: function() {
+    return {
+      topInfo: {
+        title: '技术成果',
+        engTitle: 'achieve',
+      },
+    };
+  },
+  created() {},
+  methods: {
+    // 查看更多
+    moreBtn() {
+      this.$router.push({ path: '/twoweb/market/list', query: { index: 0 } });
+    },
+    toDetail(id) {
+      this.$router.push({ path: '/twoweb/market/list', query: { index: 0, id: id } });
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  watch: {},
+};
+</script>
+
+<style lang="less" scoped>
+.style {
+  .top {
+    height: 50px;
+    overflow: hidden;
+  }
+  .down {
+    height: 450px;
+    position: relative;
+    .list {
+      position: relative;
+      overflow: hidden;
+      height: 220px;
+      margin: 0 10px 10px 0;
+      width: 32%;
+      .image {
+        height: 220px;
+        overflow: hidden;
+        .el-image {
+          width: 100%;
+          height: 220px;
+        }
+      }
+      .text {
+        width: 100%;
+        height: 220px;
+        background: url('~@common/src/assets/achieve.png');
+        background-size: 100% 100%;
+        background-repeat: no-repeat;
+        padding: 25px 19px;
+        .name {
+          font-size: 16px;
+          font-weight: bold;
+          margin: 0 0 5px 0;
+        }
+        .brief {
+          font-size: 12px;
+          overflow: hidden;
+          text-overflow: ellipsis;
+          -webkit-line-clamp: 7;
+          word-break: break-all;
+          display: -webkit-box;
+          -webkit-box-orient: vertical;
+          padding: 0 5px;
+        }
+        .other {
+          padding: 5px 0 0 0;
+          position: absolute;
+          bottom: 10px;
+          width: 83%;
+          span {
+            padding: 3px 0 0 0;
+            float: left;
+            width: 100%;
+            font-size: 12px;
+          }
+        }
+      }
+    }
+    .list:nth-child(3n) {
+      margin: 0 0 10px 0;
+    }
+    .list:hover {
+      cursor: pointer;
+      .text {
+        .name {
+          color: #409eff;
+        }
+      }
+    }
+  }
+}
+</style>

+ 123 - 0
src/views/twoweb/market/index/expert.vue

@@ -0,0 +1,123 @@
+<template>
+  <div id="expert">
+    <el-row>
+      <el-col :span="24" class="style">
+        <el-col :span="24" class="top">
+          <top :topInfo="topInfo" @moreBtn="moreBtn"></top>
+        </el-col>
+        <el-col :span="24" class="down">
+          <el-col :span="12" class="list" v-for="(item, index) in list" :key="index" @click.native="toDetail(item.user_id)">
+            <el-col :span="8" class="expertimage">
+              <el-image :src="item.img_path">
+                <div slot="error" class="image-slot">
+                  <el-image :src="imgUrl"></el-image>
+                </div>
+              </el-image>
+            </el-col>
+            <el-col :span="16" class="rightInfo">
+              <el-col :span="24" class="name textOver">
+                {{ item.name }}
+              </el-col>
+              <el-col :span="24" class="school textOver"> {{ item.zwzc }} </el-col>
+              <el-col :span="24" class="company textOver">{{ item.company }} </el-col>
+            </el-col>
+          </el-col>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import top from './top.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'expert',
+  props: {
+    list: { type: Array },
+  },
+  components: {
+    top,
+  },
+  data: function() {
+    return {
+      topInfo: {
+        title: '专家智库',
+        engTitle: 'expert',
+      },
+      imgUrl: require('@common/src/assets/expert.png'),
+    };
+  },
+  created() {},
+  methods: {
+    // 查看更多
+    moreBtn() {
+      this.$router.push({ path: '/twoweb/market/list', query: { index: 3 } });
+    },
+    toDetail(id) {
+      this.$router.push({ path: '/twoweb/market/list', query: { index: 3, id } });
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  watch: {},
+};
+</script>
+
+<style lang="less" scoped>
+.style {
+  .top {
+    height: 50px;
+    overflow: hidden;
+  }
+  .down {
+    height: 450px;
+    position: relative;
+    .list {
+      padding: 10px 0;
+      border-bottom: 1px dashed #044b79;
+      .expertimage {
+        .el-image {
+          width: 90px;
+          height: 90px;
+          border-radius: 90px;
+        }
+      }
+      .rightInfo {
+        padding: 0 10px;
+        .name {
+          font-size: 18px;
+          padding: 7px 0 0 0;
+          font-weight: bold;
+        }
+        .school {
+          font-size: 16px;
+          padding: 7px 0 0 0;
+        }
+        .edu {
+          font-size: 16px;
+          padding: 7px 0 0 0;
+        }
+        .company {
+          font-size: 16px;
+          padding: 7px 0 0 0;
+        }
+      }
+    }
+    .list:nth-child(7) {
+      border-bottom: none;
+    }
+    .list:nth-child(8) {
+      border-bottom: none;
+    }
+    .list:hover {
+      cursor: pointer;
+      .name {
+        color: #0085d2;
+        font-weight: bold;
+      }
+    }
+  }
+}
+</style>

+ 97 - 0
src/views/twoweb/market/index/patent.vue

@@ -0,0 +1,97 @@
+<template>
+  <div id="patent">
+    <el-row>
+      <el-col :span="24" class="style">
+        <el-col :span="24" class="top">
+          <top :topInfo="topInfo" @moreBtn="moreBtn"></top>
+        </el-col>
+        <el-col :span="24" class="down">
+          <el-col :span="8" class="list" v-for="(item, index) in list" :key="index" @click.native="toDetail(item._id)">
+            <el-image :src="item.img_url">
+              <template #error>
+                <el-image :src="imgUrl"></el-image>
+              </template>
+            </el-image>
+            <p class="textOver">{{ item.name }}</p>
+          </el-col>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import top from './top.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'patent',
+  props: {
+    list: { type: Array },
+  },
+  components: {
+    top,
+  },
+  data: function() {
+    return {
+      topInfo: {
+        title: 'e专利',
+        engTitle: 'patent',
+      },
+      imgUrl: require('@common/src/assets/fmzl1.jpg'),
+    };
+  },
+  created() {},
+  methods: {
+    // 查看更多
+    moreBtn() {
+      this.$router.push({ path: '/twoweb/market/list', query: { index: 1 } });
+    },
+    toDetail(id) {
+      this.$router.push({ path: '/twoweb/market/list', query: { index: 1, id } });
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  watch: {},
+};
+</script>
+
+<style lang="less" scoped>
+.style {
+  .top {
+    height: 50px;
+    overflow: hidden;
+  }
+  .down {
+    height: 450px;
+    position: relative;
+    .list {
+      width: 32%;
+      height: 220px;
+      margin: 0 10px 10px 0;
+      box-shadow: 0 0 5px #ccc;
+      border-radius: 5px;
+      padding: 5px;
+      .el-image {
+        width: 100%;
+        height: 185px;
+      }
+      p {
+        font-size: 16px;
+        font-weight: bold;
+        text-align: center;
+      }
+    }
+    .list:nth-child(3n) {
+      margin: 0 0 10px 0;
+    }
+    .list:hover {
+      cursor: pointer;
+      p {
+        color: #409eff;
+      }
+    }
+  }
+}
+</style>

+ 114 - 0
src/views/twoweb/market/index/roadshow.vue

@@ -0,0 +1,114 @@
+<template>
+  <div id="roadshow">
+    <el-row>
+      <el-col :span="24" class="style">
+        <el-col :span="24" class="top">
+          <top :topInfo="topInfo" @moreBtn="moreBtn"></top>
+        </el-col>
+        <el-col :span="24" class="down">
+          <el-col :span="24" class="list" v-for="(item, index) in list" :key="index" @click.native="toDetail(item._id)">
+            <el-col :span="4" class="date">
+              <span>{{ item.publish_time || '暂无' }}</span>
+            </el-col>
+            <el-col :span="20" class="title textOver">
+              {{ item.title }}
+            </el-col>
+            <el-col :span="24" class="brief">
+              {{ item.titlejj || '暂无' }}
+            </el-col>
+          </el-col>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import top from './top.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'roadshow',
+  props: {
+    list: { type: Array },
+  },
+  components: {
+    top,
+  },
+  data: function() {
+    return {
+      topInfo: {
+        title: '项目路演',
+        engTitle: 'roadshow',
+      },
+    };
+  },
+  created() {},
+  methods: {
+    // 查看更多
+    moreBtn() {
+      this.$router.push({ path: '/twoweb/market/list', query: { index: 2 } });
+    },
+    toDetail(id) {
+      this.$router.push({ path: '/twoweb/market/list', query: { index: 2, id } });
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  watch: {},
+};
+</script>
+
+<style lang="less" scoped>
+.style {
+  .top {
+    height: 50px;
+    overflow: hidden;
+  }
+  .down {
+    height: 450px;
+    position: relative;
+    .list {
+      border-bottom: 1px dashed #000;
+      border-bottom: 1px dashed #000;
+      padding: 12px 0;
+      .date {
+        text-align: center;
+        span {
+          background: #044b79;
+          padding: 2px 5px 4px 5px;
+          font-size: 14px;
+          border-radius: 5px;
+          font-weight: bold;
+          color: #fff;
+        }
+      }
+      .title {
+        font-size: 16px;
+        font-weight: bold;
+        padding: 0 0 0 5px;
+      }
+      .brief {
+        font-size: 14px;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        -webkit-line-clamp: 2;
+        word-break: break-all;
+        display: -webkit-box;
+        -webkit-box-orient: vertical;
+        padding: 5px 0 0 0;
+        height: 43px;
+      }
+    }
+    .list:last-child {
+      border-bottom: none;
+    }
+    .list:hover {
+      cursor: pointer;
+      .title {
+        color: #409eff;
+      }
+    }
+  }
+}
+</style>

+ 77 - 0
src/views/twoweb/market/index/top.vue

@@ -0,0 +1,77 @@
+<template>
+  <div id="topInfo">
+    <el-row>
+      <el-col :span="24" class="top">
+        <el-col :span="2" class="topImg">
+          <el-image :src="iconImage"></el-image>
+        </el-col>
+        <el-col :span="22" class="topTxt">
+          <span>{{ topInfo.title }}</span>
+          <span>{{ topInfo.engTitle }}</span>
+          <span @click="moreBtn">更多</span>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  name: 'topInfo',
+  props: {
+    topInfo: { typs: Object },
+  },
+  components: {},
+  data: function() {
+    return {
+      iconImage: require('@common/src/assets/square_big.png'),
+    };
+  },
+  created() {},
+  methods: {
+    moreBtn() {
+      this.$emit('moreBtn');
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  watch: {},
+};
+</script>
+
+<style lang="less" scoped>
+.top {
+  height: 50px;
+  .topTxt {
+    height: 45px;
+    border-bottom: 3px solid #044b79;
+    line-height: 45px;
+    padding: 0 5px;
+    span:nth-child(1) {
+      font-size: 24px;
+      font-weight: 700;
+    }
+    span:nth-child(2) {
+      padding: 0 10px;
+      text-transform: Capitalize;
+      font-size: 18px;
+      color: #92959a;
+      font-weight: 700;
+    }
+    span:nth-child(3) {
+      float: right;
+      font-size: 16px;
+      font-weight: bold;
+    }
+    span:nth-child(3):hover {
+      cursor: pointer;
+      color: #409eff;
+    }
+  }
+}
+</style>

+ 125 - 0
src/views/twoweb/market/list.vue

@@ -0,0 +1,125 @@
+<template>
+  <div id="list">
+    <el-row>
+      <el-col :span="24" class="main">
+        <div class="w_1200">
+          <el-col :span="5" class="menu">
+            <el-image :src="squareImage"></el-image>
+            <span class="menuTitle">Menu</span>
+            <el-col :span="24" class="menuList" v-for="(item, index) in menuList" :key="index">
+              <p @click="changeMenu(item.component, index)" :style="`color:${menuIndex == index ? menuColor : ''}`">{{ item.name }}</p>
+            </el-col>
+          </el-col>
+          <el-col :span="19" class="listInfo">
+            <component :is="component" v-bind="params"></component>
+            <!-- <keep-alive>
+              <component :is="component" v-bind="params"></component>
+            </keep-alive> -->
+          </el-col>
+        </div>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+const _ = require('lodash');
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'list',
+  props: {},
+  components: {
+    achieve: () => import('./list/achieve.vue'),
+    patent: () => import('./list/patent.vue'),
+    roadshow: () => import('./list/roadshow.vue'),
+    expert: () => import('./list/expert.vue'),
+  },
+  data: function() {
+    return {
+      component: '',
+      menuList: [
+        { name: '技术成果', component: 'achieve', options: { useTab: true, listModel: 1 } },
+        { name: 'e专利', component: 'patent', options: { useTab: false, listModel: 2 } },
+        { name: '项目路演', component: 'roadshow', options: { useTab: false, listModel: 5 } },
+        { name: '专家智库', component: 'expert', options: { useTab: true, listModel: 4 } },
+      ],
+      squareImage: require('@p/live/square_big.png'),
+      column_name: '',
+      params: {},
+      menuColor: 'rgb(254, 149, 14)',
+    };
+  },
+  created() {},
+  methods: {
+    changeMenu(component, index) {
+      if (index !== this.menuIndex) this.$router.push({ path: './list', query: { index } });
+      this.component = component;
+    },
+  },
+  computed: {
+    ...mapState(['user', 'menuParams']),
+    pageTitle() {
+      return `${this.$route.meta.title}`;
+    },
+    menuIndex() {
+      const index = this.$route.query.index || 0;
+      const obj = this.menuList[index];
+      const params = {
+        title: _.get(obj, 'name'),
+        ..._.get(obj, 'options'),
+      };
+      this.$set(this, 'component', _.get(obj, 'component', 'achieve'));
+      this.$set(this, 'params', params);
+      return index;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  min-height: 500px;
+  padding: 10px 0;
+  .menu {
+    height: 600px;
+    overflow: hidden;
+    padding: 15px 10px;
+    background: no-repeat 100% 100%;
+    background-image: url('~@p/live/menu_back.jpg');
+    box-sizing: border-box;
+    box-shadow: 0 0 10px #bbbaba;
+    .menuTitle {
+      font-size: 24px;
+      color: #92959a;
+      font-weight: bold;
+      position: relative;
+      top: -10px;
+      left: 10px;
+    }
+    .menuList {
+      height: 60px;
+      line-height: 60px;
+      border-bottom: 1px solid #2d64b3;
+      p {
+        font-weight: bold;
+        font-size: 18px;
+        color: #044b79;
+      }
+    }
+    .menuList:hover {
+      cursor: pointer;
+    }
+  }
+  .listInfo {
+    float: right;
+    width: 78%;
+    min-height: 600px;
+    overflow: hidden;
+    box-shadow: 0 0 10px #2d64b3;
+    padding: 10px;
+  }
+}
+</style>

+ 125 - 0
src/views/twoweb/market/list/achieve.vue

@@ -0,0 +1,125 @@
+<template>
+  <div id="achieve">
+    <list-page :displayList="firDroplist" :dropList="dropList" v-bind="$attrs" :total="total" v-if="!id" @toSearch="search" @toChangeTab="search">
+      <component :is="model" :list="list"></component>
+    </list-page>
+    <template v-else>
+      <dmodel :displayBtn="true" :data="detail" v-if="detail">
+        <el-button size="mini" type="primary" @click="$router.push({ path: './list', query: { index: $route.query.index } })"> 返回</el-button>
+      </dmodel>
+    </template>
+  </div>
+</template>
+
+<script>
+const _ = require('lodash');
+import listPage from '@c/list/list-page.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: product } = createNamespacedHelpers('product');
+const { mapActions: code } = createNamespacedHelpers('code');
+export default {
+  name: 'achieve',
+  props: ['listModel'],
+  components: {
+    listPage,
+    model1: () => import('@c/list/list-model/model-1.vue'),
+    dmodel: () => import('./detail-model/model-1.vue'),
+  },
+  data: function() {
+    return {
+      list: [],
+      firDroplist: [{ name: '中科系' }, { name: '吉林大学' }, { name: '长春工业大学' }],
+      dropList: [],
+      total: 0,
+      detail: {},
+      // 成果单位
+      company: '',
+    };
+  },
+  created() {
+    this.searchOther();
+    this.search();
+  },
+  methods: {
+    ...product(['query', 'fetch']),
+    ...code({ codeQuery: 'query' }),
+    // 查询相关
+    async search({ skip = 0, limit = 5, ...info } = {}) {
+      console.log(info);
+      let res = await this.query({ skip, limit, status: '2', type: '1', ...info });
+      if (this.$checkRes(res)) {
+        this.$set(this, `list`, res.data);
+        this.$set(this, `total`, res.total);
+        // 最后结果处理方式,将显示的信息转换成固定的字段去显示
+        this.$set(this, 'list', this.translate(this.list));
+      }
+    },
+    // change(data) {
+    //   if (data === '中科系') {
+    //     this.$set(this, `company`, data);
+    //     // TODO:原逻辑:将数据过滤出中科系;我觉得:应该是查有关中科系的信息
+    //   } else if (data === '其他') {
+    //     this.$set(this, `company`, data);
+    //     // TODO:原逻辑:是过滤某些单位; 应该去查这些单位的数据
+    //   } else {
+    //     this.$set(this, `company`, data);
+    //     // TODO:原逻辑:过滤含有这些内容的数据;应该去查
+    //   }
+    //   this.search();
+    // },
+    // 查询详情
+    async searchInfo() {
+      let res = await this.fetch(this.id);
+      if (this.$checkRes(res)) {
+        this.$set(this, `detail`, res.data);
+      }
+    },
+    // 显示相关
+    translate(data) {
+      const list = data.map(i => {
+        const obj = { id: i.id || i._id };
+        obj.p1 = _.get(i, 'name');
+        obj.p2 = _.get(i, 'create_time');
+        obj.p3 = _.get(i, 'achievebrief');
+        return obj;
+      });
+      return list;
+    },
+    // 查询其他信息
+    async searchOther() {
+      let res = await this.codeQuery({ category: '05' });
+      if (this.$checkRes(res)) {
+        let newRes = res.data;
+        newRes.push({ name: '其他' });
+        this.$set(this, `dropList`, newRes);
+      }
+    },
+  },
+  computed: {
+    ...mapState(['user', 'menuParams']),
+    pageTitle() {
+      return `${this.$route.meta.title}`;
+    },
+    model() {
+      const moduleNumber = this.listModel || 1;
+      return `model${moduleNumber}`;
+    },
+    id() {
+      return this.$route.query.id;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    id: {
+      handler(ne) {
+        if (ne) this.searchInfo();
+      },
+      immediate: true,
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 46 - 0
src/views/twoweb/market/list/detail-model/model-1.vue

@@ -0,0 +1,46 @@
+<template>
+  <div id="model-1">
+    <el-row type="flex" justify="end">
+      <el-col :span="2">
+        <slot></slot>
+      </el-col>
+    </el-row>
+    <el-col :span="24" class="two">
+      <achieveInfo :form="data"></achieveInfo>
+    </el-col>
+  </div>
+</template>
+
+<script>
+import achieveInfo from '@c/detail-model/achieveInfo.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'model-1',
+  props: {
+    data: { type: Object, default: () => {} },
+  },
+  components: {
+    achieveInfo,
+  },
+  data: function() {
+    return {};
+  },
+  created() {},
+  methods: {},
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 217 - 0
src/views/twoweb/market/list/detail-model/model-2.vue

@@ -0,0 +1,217 @@
+<template>
+  <div id="model-2">
+    <el-row type="flex" justify="end">
+      <el-col :span="2">
+        <slot></slot>
+      </el-col>
+    </el-row>
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="top">
+          <el-col :span="7" class="left">
+            <el-col :span="24" class="noImage">
+              <p>专利有效性</p>
+              <p>{{ data.term }}</p>
+            </el-col>
+          </el-col>
+          <el-col :span="17" class="right">
+            <el-col :span="24" class="name textOver">
+              {{ data.name }}
+            </el-col>
+            <el-col :span="12">
+              <el-col :span="8" class="otherInfo textOver">
+                申请号
+              </el-col>
+              <el-col :span="16" class="otherInfo textOver">
+                {{ data.create_number || '暂无' }}
+              </el-col>
+            </el-col>
+            <el-col :span="12">
+              <el-col :span="8" class="otherInfo textOver">
+                申请日
+              </el-col>
+              <el-col :span="16" class="otherInfo textOver">
+                {{ data.create_date || '暂无' }}
+              </el-col>
+            </el-col>
+            <el-col :span="12">
+              <el-col :span="8" class="otherInfo textOver">
+                公开(公告)号
+              </el-col>
+              <el-col :span="16" class="otherInfo textOver">
+                {{ data.success_number || '暂无' }}
+              </el-col>
+            </el-col>
+            <el-col :span="12">
+              <el-col :span="8" class="otherInfo textOver">
+                公开(公告)日
+              </el-col>
+              <el-col :span="16" class="otherInfo textOver">
+                {{ data.success_date || '暂无' }}
+              </el-col>
+            </el-col>
+            <el-col :span="12">
+              <el-col :span="8" class="otherInfo textOver">
+                申请人
+              </el-col>
+              <el-col :span="16" class="otherInfo textOver">
+                {{ data.apply_personal || '暂无' }}
+              </el-col>
+            </el-col>
+            <el-col :span="12">
+              <el-col :span="8" class="otherInfo textOver">
+                专利类型
+              </el-col>
+              <el-col :span="16" class="otherInfo textOver">
+                {{ data.type || '暂无' }}
+              </el-col>
+            </el-col>
+            <el-col :span="24">
+              <el-col :span="4" class="otherInfo textOver">
+                发明人
+              </el-col>
+              <el-col :span="20" class="otherInfo textOver">
+                {{ data.inventor || '暂无' }}
+              </el-col>
+            </el-col>
+
+            <el-col :span="24">
+              <el-col :span="4" class="otherInfo textOver">
+                代理人
+              </el-col>
+              <el-col :span="20" class="otherInfo textOver">
+                {{ data.agent_personal || '暂无' }}
+              </el-col>
+            </el-col>
+            <el-col :span="24">
+              <el-col :span="4" class="otherInfo textOver">
+                代理机构
+              </el-col>
+              <el-col :span="20" class="otherInfo textOver">
+                {{ data.agent || '暂无' }}
+              </el-col>
+            </el-col>
+            <el-col :span="24">
+              <el-col :span="4" class="otherInfo textOver">
+                地址
+              </el-col>
+              <el-col :span="20" class="otherInfo textOver">
+                {{ data.address || '暂无' }}
+              </el-col>
+            </el-col>
+          </el-col>
+        </el-col>
+        <el-col :span="24" class="down">
+          <el-col :span="24" class="downInfo">
+            <h1>摘要</h1>
+            <p>{{ data.abstract || '暂无' }}</p>
+          </el-col>
+          <el-col :span="24" class="downInfo" v-if="data.img_url">
+            <h1>专利图鉴</h1>
+            <el-image :src="data.img_url"></el-image>
+          </el-col>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'model-2',
+  props: {
+    data: { type: Object, default: () => {} },
+  },
+  components: {},
+  data: function() {
+    return {};
+  },
+  created() {},
+  methods: {},
+  computed: {
+    ...mapState(['user', 'menuParams']),
+    pageTitle() {
+      return `${this.$route.meta.title}`;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  margin: 15px 0 0 0;
+  .top {
+    margin: 0 0 10px 0;
+    .left {
+      margin: 0 10px 0 0;
+      border: 1px solid #ccc;
+      .el-image {
+        width: 100%;
+        height: 320px;
+      }
+      .noImage {
+        height: 320px;
+        p:nth-child(1) {
+          font-size: 25px;
+          text-align: left;
+          padding: 10px;
+        }
+        p:nth-child(2) {
+          text-align: center;
+          padding: 30% 0;
+          font-size: 35px;
+          font-weight: bold;
+          color: #ff0000;
+        }
+      }
+    }
+    .right {
+      width: 638px;
+      border: 1px solid #ccc;
+      .name {
+        height: 40px;
+        line-height: 40px;
+        padding: 0 10px;
+        border-bottom: 1px solid #ccc;
+        font-size: 18px;
+        font-weight: bold;
+        text-align: center;
+      }
+      .otherInfo {
+        height: 40px;
+        line-height: 40px;
+        padding: 0 0 0 10px;
+        border-right: 1px solid #ccc;
+        border-bottom: 1px solid #ccc;
+        font-size: 16px;
+        .tooltip {
+          float: left;
+          width: 98%;
+        }
+      }
+    }
+  }
+  .down {
+    border: 1px solid #cccccc;
+    padding: 10px;
+    .downInfo {
+      margin: 0 0 15px 0;
+      border-bottom: 1px dashed #ccc;
+      p {
+        font-size: 18px;
+        line-height: 38px;
+        text-indent: 2rem;
+      }
+      h1 {
+        font-weight: 400;
+        font-size: 24px;
+        margin: 0 0 10px 0;
+      }
+    }
+  }
+}
+</style>

+ 46 - 0
src/views/twoweb/market/list/detail-model/model-3.vue

@@ -0,0 +1,46 @@
+<template>
+  <div id="model-3">
+    <el-row type="flex" justify="end">
+      <el-col :span="2">
+        <slot></slot>
+      </el-col>
+    </el-row>
+    <el-col :span="24" class="two">
+      <businessInfo :form="data"></businessInfo>
+    </el-col>
+  </div>
+</template>
+
+<script>
+import businessInfo from '@c/detail-model/businessInfo.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'model-3',
+  props: {
+    data: { type: Object, default: () => {} },
+  },
+  components: {
+    businessInfo,
+  },
+  data: function() {
+    return {};
+  },
+  created() {},
+  methods: {},
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 44 - 0
src/views/twoweb/market/list/detail-model/model-4.vue

@@ -0,0 +1,44 @@
+<template>
+  <div id="model-4">
+    <el-row type="flex" justify="end">
+      <el-col :span="2">
+        <slot></slot>
+      </el-col>
+    </el-row>
+    <el-col :span="24" class="two">
+      <expertInfo :form="data"></expertInfo>
+    </el-col>
+  </div>
+</template>
+
+<script>
+import expertInfo from '@c/detail-model/expertInfo.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'model-4',
+  props: { data: { type: Object, default: () => {} } },
+  components: {
+    expertInfo,
+  },
+  data: function() {
+    return {};
+  },
+  created() {},
+  methods: {},
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 46 - 0
src/views/twoweb/market/list/detail-model/model-5.vue

@@ -0,0 +1,46 @@
+<template>
+  <div id="model-5">
+    <el-row type="flex" justify="end">
+      <el-col :span="2">
+        <slot></slot>
+      </el-col>
+    </el-row>
+    <el-col :span="24" class="two">
+      <techolInfo :form="data"></techolInfo>
+    </el-col>
+  </div>
+</template>
+
+<script>
+import techolInfo from '@c/detail-model/techolInfo.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'model-5',
+  props: {
+    data: { type: Object, default: () => {} },
+  },
+  components: {
+    techolInfo,
+  },
+  data: function() {
+    return {};
+  },
+  created() {},
+  methods: {},
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 105 - 0
src/views/twoweb/market/list/detail-model/model-6.vue

@@ -0,0 +1,105 @@
+<template>
+  <div id="model-6">
+    <el-row type="flex" justify="end">
+      <el-col :span="2">
+        <slot></slot>
+      </el-col>
+    </el-row>
+    <el-row>
+      <el-col :span="24" class="main">
+        <div class="detailtop">
+          <span>{{ data.title }}</span>
+        </div>
+        <div class="detailtopleft">
+          <span>时间:{{ data.publish_time }}&nbsp;&nbsp;&nbsp;&nbsp;来源:{{ data.orgin }}</span>
+        </div>
+        <div class="detailimage" v-if="data.picture">
+          <img :src="data.picture" class="detailimg" />
+        </div>
+        <div class="detailVideo">
+          <video :src="data.filepath" controls="controls">
+            您的浏览器不支持 video 标签。
+          </video>
+        </div>
+        <div class="detailcontext">
+          <p v-html="data.content"></p>
+        </div>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'model-6',
+  props: {
+    displayBtn: { type: Boolean },
+    data: { type: Object, default: () => {} },
+  },
+  components: {},
+  data: function() {
+    return {};
+  },
+  created() {},
+  methods: {},
+  computed: {
+    ...mapState(['user', 'menuParams']),
+    pageTitle() {
+      return `${this.$route.meta.title}`;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  .detailtop {
+    padding: 20px 0px;
+    font-size: 18px;
+    line-height: 40px;
+    font-weight: normal;
+    text-align: left;
+    margin: 0;
+    text-align: center;
+    color: #005293;
+  }
+
+  .detailtopleft {
+    text-align: center;
+    padding: 0 0 10px 0;
+    border-bottom: 1px solid #ccc;
+    font-size: 16px;
+    color: #666666;
+  }
+
+  .detailimage {
+    text-align: center;
+    padding: 20px 0 0 0;
+  }
+  .detailVideo {
+    float: left;
+    width: 100%;
+    text-align: center;
+    height: 260px;
+    overflow: hidden;
+    margin: 20px 0;
+  }
+  .detailVideo video {
+    height: 260px;
+    width: 50%;
+  }
+
+  .detailimg {
+    width: 500px;
+    height: 300px;
+  }
+
+  .detailcontext {
+    padding: 20px 0;
+  }
+}
+</style>

+ 120 - 0
src/views/twoweb/market/list/expert.vue

@@ -0,0 +1,120 @@
+<template>
+  <div id="expert">
+    <list-page
+      :displayList="firDroplist"
+      :dropList="dropList"
+      v-bind="$attrs"
+      :total="total"
+      v-if="!id"
+      @toSearch="search"
+      :pageSize="pageSize"
+      @toChangeTab="search"
+    >
+      <component :is="model" :list="list"></component>
+    </list-page>
+    <template v-else>
+      <dmodel :displayBtn="true" :data="detail" v-if="detail">
+        <el-button size="mini" type="primary" @click="$router.push({ path: './list', query: { index: $route.query.index } })"> 返回</el-button>
+      </dmodel>
+    </template>
+  </div>
+</template>
+
+<script>
+import listPage from '@c/list/list-page.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: expert } = createNamespacedHelpers('expert');
+const { mapActions: code } = createNamespacedHelpers('code');
+export default {
+  name: 'expert',
+  props: ['listModel'],
+  components: {
+    listPage,
+    model4: () => import('@c/list/list-model/model-4.vue'),
+    dmodel: () => import('./detail-model/model-4.vue'),
+  },
+  data: function() {
+    return {
+      list: [],
+      firDroplist: [{ name: '中科系' }, { name: '吉林大学' }, { name: '长春工业大学' }],
+      dropList: [],
+      total: 0,
+      detail: {},
+      pageSize: 8,
+    };
+  },
+  created() {
+    this.searchOther();
+    this.search();
+  },
+  methods: {
+    ...expert(['query', 'fetch']),
+    ...code({ codeQuery: 'query' }),
+    // 查询相关
+    async search({ skip = 0, limit = this.pageSize, ...info } = {}) {
+      console.log(info);
+      // TODO: 查询
+      let res = await this.query({ skip, limit, ...info });
+      if (this.$checkRes(res)) {
+        this.$set(this, `list`, res.data);
+        this.$set(this, `total`, res.total);
+        // 最后结果处理方式,将显示的信息转换成固定的字段去显示
+        this.$set(this, 'list', this.translate(this.list));
+      }
+    },
+    translate(data) {
+      const list = data.map(i => {
+        const obj = { id: i.id || i.user_id };
+        obj.p1 = _.get(i, 'img_path');
+        obj.p2 = _.get(i, 'name');
+        obj.p3 = _.get(i, 'company');
+        obj.p4 = _.get(i, 'expertise');
+        return obj;
+      });
+      return list;
+    },
+    // 查询详情
+    async searchInfo() {
+      let res = await this.fetch(this.id);
+      if (this.$checkRes(res)) {
+        this.$set(this, `detail`, res.data);
+      }
+    },
+    // 查询其他信息
+    async searchOther() {
+      let res = await this.codeQuery({ category: '06' });
+      if (this.$checkRes(res)) {
+        let newRes = res.data;
+        newRes.push({ name: '其他' });
+        this.$set(this, `dropList`, newRes);
+      }
+    },
+  },
+  computed: {
+    ...mapState(['user', 'menuParams']),
+    pageTitle() {
+      return `${this.$route.meta.title}`;
+    },
+    model() {
+      const moduleNumber = this.listModel || 1;
+      return `model${moduleNumber}`;
+    },
+    id() {
+      return this.$route.query.id;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    id: {
+      handler(ne) {
+        if (ne) this.searchInfo();
+      },
+      immediate: true,
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 95 - 0
src/views/twoweb/market/list/patent.vue

@@ -0,0 +1,95 @@
+<template>
+  <div id="patent">
+    <list-page v-bind="$attrs" :total="total" v-if="!id" @toSearch="search">
+      <component :is="model" :list="list"></component>
+    </list-page>
+    <template v-else>
+      <dmodel :displayBtn="true" :data="detail" v-if="detail">
+        <el-button size="mini" type="primary" @click="$router.push({ path: './list', query: { index: $route.query.index } })"> 返回</el-button>
+      </dmodel>
+    </template>
+  </div>
+</template>
+
+<script>
+import listPage from '@c/list/list-page.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: mapPatent } = createNamespacedHelpers('patent');
+export default {
+  name: 'patent',
+  props: ['listModel'],
+  components: {
+    listPage,
+    model2: () => import('@c/list/list-model/model-2.vue'),
+    dmodel: () => import('./detail-model/model-2.vue'),
+  },
+  data: function() {
+    return {
+      list: [],
+      total: 0,
+      detail: {},
+    };
+  },
+  created() {
+    this.search();
+  },
+  methods: {
+    ...mapPatent(['query', 'fetch']),
+    // 查询相关
+    async search({ skip = 0, limit = 5, ...info } = {}) {
+      // TODO: 查询
+      let res = await this.query({ skip, limit, ...info });
+      if (this.$checkRes(res)) {
+        this.$set(this, `list`, res.data);
+        this.$set(this, `total`, res.total);
+        // 最后结果处理方式,将显示的信息转换成固定的字段去显示
+        this.$set(this, 'list', this.translate(this.list));
+      }
+    },
+    translate(data) {
+      const list = data.map(i => {
+        const obj = { id: i.id || i._id };
+        obj.p1 = _.get(i, 'name');
+        obj.p2 = _.get(i, 'term');
+        obj.p3 = _.get(i, 'success_date');
+        obj.p4 = _.get(i, 'abstract');
+        return obj;
+      });
+      return list;
+    },
+    // 查询详情
+    async searchInfo() {
+      let res = await this.fetch(this.id);
+      if (this.$checkRes(res)) {
+        this.$set(this, `detail`, res.data);
+      }
+    },
+  },
+  computed: {
+    ...mapState(['user', 'menuParams']),
+    pageTitle() {
+      return `${this.$route.meta.title}`;
+    },
+    model() {
+      const moduleNumber = this.listModel || 1;
+      return `model${moduleNumber}`;
+    },
+    id() {
+      return this.$route.query.id;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    id: {
+      handler(ne) {
+        if (ne) this.searchInfo();
+      },
+      immediate: true,
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 96 - 0
src/views/twoweb/market/list/roadshow.vue

@@ -0,0 +1,96 @@
+<template>
+  <div id="roadshow">
+    <list-page v-bind="$attrs" :total="total" v-if="!id" @toSearch="search" :pageSize="pageSize" searchModel="title">
+      <component :is="model" :list="list"></component>
+    </list-page>
+    <template v-else>
+      <dmodel :displayBtn="true" :data="detail" v-if="detail">
+        <el-button size="mini" type="primary" @click="$router.push({ path: './list', query: { index: $route.query.index } })"> 返回</el-button>
+      </dmodel>
+    </template>
+  </div>
+</template>
+
+<script>
+import listPage from '@c/list/list-page.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: mapRoadShow } = createNamespacedHelpers('roadShow');
+export default {
+  name: 'roadshow',
+  props: ['listModel'],
+  components: {
+    listPage,
+    model5: () => import('@c/list/list-model/model-5.vue'),
+    dmodel: () => import('./detail-model/model-6.vue'),
+  },
+  data: function() {
+    return {
+      list: [],
+      total: 0,
+      detail: {},
+      pageSize: 5,
+    };
+  },
+  created() {
+    this.search();
+  },
+  methods: {
+    ...mapRoadShow(['query', 'fetch']),
+    // 查询相关
+    async search({ skip = 0, limit = this.pageSize, ...info } = {}) {
+      // TODO: 查询
+      let res = await this.query({ skip, limit, ...info });
+      if (this.$checkRes(res)) {
+        this.$set(this, `list`, res.data);
+        this.$set(this, `total`, res.total);
+        // 最后结果处理方式,将显示的信息转换成固定的字段去显示
+        this.$set(this, 'list', this.translate(this.list));
+      }
+    },
+    translate(data) {
+      const list = data.map(i => {
+        const obj = { id: i.id || i._id };
+        obj.p1 = _.get(i, 'title');
+        obj.p2 = _.get(i, 'publish_time');
+        obj.p3 = _.get(i, 'titlejj');
+        return obj;
+      });
+      return list;
+    },
+    // 查询详情
+    async searchInfo() {
+      console.log(this.id);
+      let res = await this.fetch(this.id);
+      if (this.$checkRes(res)) {
+        this.$set(this, `detail`, res.data);
+      }
+    },
+  },
+  computed: {
+    ...mapState(['user', 'menuParams']),
+    pageTitle() {
+      return `${this.$route.meta.title}`;
+    },
+    model() {
+      const moduleNumber = this.listModel || 1;
+      return `model${moduleNumber}`;
+    },
+    id() {
+      return this.$route.query.id;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    id: {
+      handler(ne) {
+        if (ne) this.searchInfo();
+      },
+      immediate: true,
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 476 - 0
src/views/twoweb/personalLive/index.vue

@@ -0,0 +1,476 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main">
+        <div class="w_1200">
+          <el-col :span="24" class="one">
+            <el-col :span="24" class="top">
+              <p>人才招聘展会模板</p>
+              <p>主办方:吉林省计算中心</p>
+            </el-col>
+            <el-col :span="24" class="down">
+              <p v-for="(item, index) in numList" :key="index">
+                <span>{{ item.name }}</span>
+                <span>{{ item.num }}人</span>
+              </p>
+            </el-col>
+          </el-col>
+          <el-col :span="24" class="two">
+            <el-col :span="12" class="left">
+              <el-col :span="24" class="top">
+                <span style="color:#409eff">人才视频</span>
+                <span>直播</span>
+              </el-col>
+              <el-col :span="24" class="down">
+                视频播放框
+              </el-col>
+            </el-col>
+            <el-col :span="12" class="right">
+              <el-col :span="24" class="top">
+                公共聊天
+              </el-col>
+              <el-col :span="24" class="down">
+                <el-col :span="24" class="list">
+                  <el-col :span="24" class="chatList" v-for="(item, index) in chatList" :key="index">
+                    <el-col :span="2" class="image">
+                      <el-image :src="touxiang" style="width:30px;height:30px"></el-image>
+                    </el-col>
+                    <el-col :span="22" class="other">
+                      <el-col :span="24" class="otherone">
+                        <span>{{ item.name }}</span>
+                        <span>{{ item.date }}</span>
+                      </el-col>
+                      <el-col :span="24" class="othertwo">
+                        <p class="remark">{{ item.content }}</p>
+                      </el-col>
+                    </el-col>
+                  </el-col>
+                </el-col>
+                <el-col :span="24" class="chat">
+                  <el-col :span="21" class="input">
+                    <el-input v-model="text" placeholder="请输入聊天内容"></el-input>
+                  </el-col>
+                  <el-col :span="3" class="btn">
+                    <el-button type="primary" size="mini">发送</el-button>
+                  </el-col>
+                </el-col>
+              </el-col>
+            </el-col>
+          </el-col>
+          <el-col :span="24" class="three">
+            <el-image :src="per"></el-image>
+          </el-col>
+          <el-col :span="24" class="four">
+            <el-tabs type="border-card">
+              <el-tab-pane label="招聘信息">
+                <el-col :span="24" class="fourone">
+                  <el-col :span="24" class="zpxxList" v-for="(item, index) in zpxxList" :key="index">
+                    <el-col :span="16" class="name textOver">
+                      {{ item.name }}
+                    </el-col>
+                    <el-col :span="4" class="type textOver"> 类型:{{ item.type }} </el-col>
+                    <el-col :span="4" class="date textOver">
+                      {{ item.date }}
+                    </el-col>
+                    <el-col :span="24" class="content">
+                      {{ item.content }}
+                    </el-col>
+                  </el-col>
+                </el-col>
+              </el-tab-pane>
+              <el-tab-pane label="正式岗位">
+                <el-col :span="24" class="fourtwo">
+                  <el-col :span="12" class="zsgwList" v-for="(item, index) in zsgwList" :key="index">
+                    <el-col :span="20" class="name textOver">
+                      {{ item.name }}
+                    </el-col>
+                    <el-col :span="4" class="date textOver">
+                      {{ item.date }}
+                    </el-col>
+                    <el-col :span="24" class="other">
+                      <span class="textOver">需求人数:{{ item.num }}</span>
+                      <span class="textOver" style="color:#ff0000;">薪资:{{ item.xz }}</span>
+                    </el-col>
+                    <el-col :span="24" class="other">
+                      <span class="textOver">福利待遇:{{ item.fldy }}</span>
+                      <span class="textOver">职位诱惑:{{ item.zwyh }}</span>
+                    </el-col>
+                  </el-col>
+                </el-col>
+              </el-tab-pane>
+              <el-tab-pane label="实习岗位">
+                <el-col :span="24" class="fourthree">
+                  <el-col :span="6" class="sxList" v-for="(item, index) in sxList" :key="index">
+                    <el-image :src="sx" class="image"></el-image>
+                    <el-col :span="24" class="name textOver">
+                      {{ item.name }}
+                    </el-col>
+                    <el-col :span="24" class="other">
+                      <span class="textOver"><i class="el-icon-coin"></i>{{ item.xz }}</span>
+                      <span class="textOver"><i class="el-icon-location"></i>{{ item.address }}</span>
+                    </el-col>
+                    <el-col :span="24" class="fldy textOver">
+                      <span>福利待遇:{{ item.fldy }}</span>
+                    </el-col>
+                  </el-col>
+                </el-col>
+              </el-tab-pane>
+            </el-tabs>
+          </el-col>
+        </div>
+        <div class="pz_down">
+          <foot></foot>
+        </div>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import foot from '@common/src/components/common/foot.vue';
+import { zpxx } from './js/zpxxList.js';
+import { zsgw } from './js/zsgwList.js';
+import { sx } from './js/sxList.js';
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'index',
+  props: {},
+  components: {
+    foot,
+  },
+  data: function() {
+    return {
+      numList: [
+        { name: '同时在线', num: 1000 },
+        { name: '特邀嘉宾', num: 1000 },
+        { name: '洽谈合作', num: 1000 },
+        { name: '达成意向', num: 1000 },
+        { name: '对接成功', num: 1000 },
+        { name: '参展职位', num: 1000 },
+      ],
+      // 聊天列表
+      chatList: [
+        { name: '顾红伟', date: '10:00', content: '信息内容' },
+        { name: '顾红伟', date: '10:00', content: '信息内容' },
+      ],
+      touxiang: require('@common/src/assets/emotion/touxiang.png'),
+      // 发言内容
+      text: '',
+      per: require('@common/src/assets/personalLive.jpg'),
+      // 招聘信息
+      zpxxList: zpxx,
+      // 正式岗位
+      zsgwList: zsgw,
+      // 实习岗位
+      sx: require('@common/src/assets/sx.png'),
+      sxList: sx,
+    };
+  },
+  created() {},
+  methods: {},
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  background: url('~@common/src/assets/bg1.jpg');
+  background-repeat: no-repeat;
+  background-size: 100%;
+  .one {
+    .top {
+      margin: 50px 0;
+      text-align: center;
+      p:nth-child(1) {
+        font-size: 70px;
+        font-family: cursive;
+        transform: scale(0.8);
+        font-weight: bolder;
+        -webkit-text-stroke: 1px #fff;
+        -webkit-text-fill-color: #191970;
+        letter-spacing: 3px;
+      }
+      p:nth-child(2) {
+        font-size: 30px;
+        padding: 20px 0;
+        font-family: cursive;
+        color: #fff;
+      }
+    }
+    .down {
+      margin: 0 0 15px 0;
+      p {
+        float: left;
+        width: 16%;
+        background: #ffffff5f;
+        color: #000;
+        height: 50px;
+        line-height: 50px;
+        border-radius: 30px;
+        margin: 0 7px 0 0;
+        span:first-child {
+          display: inline-block;
+          width: 56%;
+          text-align: center;
+          height: 50px;
+          line-height: 50px;
+          font-size: 16px;
+          background: #76bdfe;
+          border-radius: 30px;
+          color: #fff;
+          font-weight: 700;
+        }
+        span:last-child {
+          display: inline-block;
+          width: 42%;
+          text-align: center;
+          font-size: 15px;
+          font-weight: 700;
+        }
+      }
+    }
+  }
+  .two {
+    height: 450px;
+    margin: 0 0 15px 0;
+    .left {
+      height: 450px;
+      overflow: hidden;
+      border: 5px solid #000;
+      background: #fff;
+      border-radius: 5px;
+      padding: 10px;
+      margin: 0 15px 0 0;
+      .top {
+        height: 30px;
+        line-height: 30px;
+        font-weight: bold;
+        font-size: 20px;
+        margin: 0 0 5px 0;
+      }
+      .down {
+        height: 385px;
+        background-color: #000;
+        color: #fff;
+      }
+    }
+    .right {
+      width: 48%;
+      height: 450px;
+      overflow: hidden;
+      background: #f0ffff5f;
+      box-shadow: 0 0 5px #409eff;
+      border-radius: 5px;
+      .top {
+        height: 40px;
+        line-height: 40px;
+        padding: 0 10px;
+        font-weight: bold;
+        font-size: 18px;
+        color: #fff;
+        background-color: #409eff;
+      }
+      .down {
+        height: 410px;
+        overflow: hidden;
+        padding: 0 0 0 10px;
+        .list {
+          height: 370px;
+          overflow-y: auto;
+          .chatList {
+            padding: 10px 0;
+            border-bottom: 1px dashed #409eff;
+            .image {
+              text-align: center;
+            }
+            .other {
+              .otherone {
+                span:nth-child(1) {
+                  color: #000;
+                  font-size: 16px;
+                  font-weight: bold;
+                }
+                span:nth-child(2) {
+                  display: inline-block;
+                  margin: 0 0 0 15px;
+                  color: #ccc;
+                }
+              }
+              .othertwo {
+                margin: 5px 0 0 0;
+                color: #000;
+                .remark {
+                  min-height: 20px;
+                  font-size: 15px;
+                  padding: 5px;
+                  border-radius: 5px;
+                  background: #cccccc5f;
+                }
+              }
+            }
+          }
+        }
+        .chat {
+          height: 40px;
+          .input {
+            /deep/.el-input__inner {
+              height: 35px;
+              line-height: 35px;
+            }
+          }
+          .btn {
+            /deep/.el-button--mini,
+            .el-button--mini.is-round {
+              padding: 10px 15px;
+              width: 100%;
+            }
+          }
+        }
+      }
+    }
+  }
+  .three {
+    height: 120px;
+    margin: 10px 0 15px 0;
+    .el-image {
+      width: 100%;
+      height: 120px;
+      border: 1px solid #f1f1f1;
+      box-shadow: 0 0 10px #f1f1f1;
+    }
+  }
+  .four {
+    height: 494px;
+    overflow: hidden;
+    .el-tabs {
+      height: 480px;
+      overflow: hidden;
+    }
+    .el-tabs--border-card {
+      background-color: #ffffff9f;
+    }
+    .fourone {
+      height: 430px;
+      overflow: hidden;
+      .zpxxList {
+        border-bottom: 1px dashed #ccc;
+        margin: 0 0 10px 0;
+        height: 100px;
+        .name {
+          font-size: 18px;
+          font-weight: bold;
+          padding: 0 0 5px 0;
+        }
+        .type {
+          font-size: 16px;
+          padding: 0 0 5px 0;
+          text-align: left;
+        }
+        .date {
+          font-size: 16px;
+          padding: 0 0 5px 0;
+          text-align: right;
+        }
+        .content {
+          font-size: 16px;
+          overflow: hidden;
+          text-overflow: ellipsis;
+          -webkit-line-clamp: 2;
+          word-break: break-all;
+          display: -webkit-box;
+          -webkit-box-orient: vertical;
+          margin: 10px 0 0 0;
+        }
+      }
+      .zpxxList:hover {
+        cursor: pointer;
+        .name {
+          color: #409eff;
+        }
+      }
+    }
+    .fourtwo {
+      height: 430px;
+      overflow: hidden;
+      .zsgwList {
+        border: 1px solid #ccc;
+        padding: 10px;
+        margin: 0 0 5px 0;
+        height: 100px;
+        .name {
+          font-size: 18px;
+          font-weight: bold;
+        }
+        .date {
+          text-align: right;
+          font-size: 16px;
+        }
+        .other {
+          padding: 2px 0 1px 0;
+          font-size: 16px;
+          span {
+            display: inline-block;
+            width: 50%;
+          }
+        }
+      }
+      .zsgwList:hover {
+        cursor: pointer;
+        .name {
+          color: #409eff;
+        }
+      }
+    }
+    .fourthree {
+      .sxList {
+        padding: 15px;
+        margin: 0 15px 10px 0;
+        height: 205px;
+        width: 24%;
+        border-radius: 10px;
+        box-shadow: 0 0px 5px #3333334f;
+        .image {
+          height: 100px;
+          padding: 0 60px;
+        }
+        .name {
+          font-size: 18px;
+          text-align: center;
+          font-weight: bold;
+          padding: 5px 0 0 0;
+        }
+        .other {
+          font-size: 16px;
+          text-align: center;
+          padding: 5px 0;
+          span {
+            display: inline-block;
+            margin: 0 10px;
+          }
+          span:nth-child(1) {
+            color: #ff0000;
+          }
+        }
+        .fldy {
+          font-size: 16px;
+          text-align: center;
+        }
+      }
+      .sxList:nth-child(4n) {
+        margin: 0 0 10px 0;
+      }
+      .sxList:hover {
+        cursor: pointer;
+        .name {
+          color: #409eff;
+        }
+      }
+    }
+  }
+}
+</style>

+ 50 - 0
src/views/twoweb/personalLive/js/sxList.js

@@ -0,0 +1,50 @@
+export const sx = [
+  {
+    name: '前端开发工程师',
+    xz: '3k-6k/月',
+    address: '长春市',
+    fldy: '五险一金',
+  },
+  {
+    name: '前端开发工程师',
+    xz: '3k-6k/月',
+    address: '长春市',
+    fldy: '五险一金',
+  },
+  {
+    name: '前端开发工程师',
+    xz: '3k-6k/月',
+    address: '长春市',
+    fldy: '五险一金',
+  },
+  {
+    name: '前端开发工程师',
+    xz: '3k-6k/月',
+    address: '长春市',
+    fldy: '五险一金',
+  },
+  {
+    name: '前端开发工程师',
+    xz: '3k-6k/月',
+    address: '长春市',
+    fldy: '五险一金',
+  },
+  {
+    name: '前端开发工程师',
+    xz: '3k-6k/月',
+    address: '长春市',
+    fldy: '五险一金',
+  },
+  {
+    name: '前端开发工程师',
+    xz: '3k-6k/月',
+    address: '长春市',
+    fldy: '五险一金',
+  },
+  {
+    name: '前端开发工程师',
+    xz: '3k-6k/月',
+    address: '长春市',
+    fldy: '五险一金',
+  },
+];

+ 26 - 0
src/views/twoweb/personalLive/js/zpxxList.js

@@ -0,0 +1,26 @@
+export const zpxx = [
+  {
+    name: '长春市福瑞科技有限公司',
+    date: '2020-10-16',
+    type: '全职',
+    content: '长春市福瑞科技有限公司长春市福瑞科技有限公司长春市福瑞科技有限公司长春市福瑞科技有限公司',
+  },
+  {
+    name: '长春市福瑞科技有限公司',
+    date: '2020-10-16',
+    type: '全职',
+    content: '长春市福瑞科技有限公司长春市福瑞科技有限公司长春市福瑞科技有限公司长春市福瑞科技有限公司',
+  },
+  {
+    name: '长春市福瑞科技有限公司',
+    date: '2020-10-16',
+    type: '全职',
+    content: '长春市福瑞科技有限公司长春市福瑞科技有限公司长春市福瑞科技有限公司长春市福瑞科技有限公司',
+  },
+  {
+    name: '长春市福瑞科技有限公司',
+    date: '2020-10-16',
+    type: '全职',
+    content: '长春市福瑞科技有限公司长春市福瑞科技有限公司长春市福瑞科技有限公司长春市福瑞科技有限公司',
+  },
+];

+ 66 - 0
src/views/twoweb/personalLive/js/zsgwList.js

@@ -0,0 +1,66 @@
+export const zsgw = [
+  {
+    name: '应届管培生',
+    date: '2020-10-16',
+    xz: '3k-6k/月',
+    fldy: '五险一金',
+    num: '10',
+    zwyh: '扁平管理,节日礼物,岗前培训,岗位晋升',
+  },
+  {
+    name: '应届管培生',
+    date: '2020-10-16',
+    xz: '3k-6k/月',
+    fldy: '五险一金',
+    num: '10',
+    zwyh: '扁平管理,节日礼物,岗前培训,岗位晋升',
+  },
+  {
+    name: '应届管培生',
+    date: '2020-10-16',
+    xz: '3k-6k/月',
+    fldy: '五险一金',
+    num: '10',
+    zwyh: '扁平管理,节日礼物,岗前培训,岗位晋升',
+  },
+  {
+    name: '应届管培生',
+    date: '2020-10-16',
+    xz: '3k-6k/月',
+    fldy: '五险一金',
+    num: '10',
+    zwyh: '扁平管理,节日礼物,岗前培训,岗位晋升',
+  },
+  {
+    name: '应届管培生',
+    date: '2020-10-16',
+    xz: '3k-6k/月',
+    fldy: '五险一金',
+    num: '10',
+    zwyh: '扁平管理,节日礼物,岗前培训,岗位晋升',
+  },
+  {
+    name: '应届管培生',
+    date: '2020-10-16',
+    xz: '3k-6k/月',
+    fldy: '五险一金',
+    num: '10',
+    zwyh: '扁平管理,节日礼物,岗前培训,岗位晋升',
+  },
+  {
+    name: '应届管培生',
+    date: '2020-10-16',
+    xz: '3k-6k/月',
+    fldy: '五险一金',
+    num: '10',
+    zwyh: '扁平管理,节日礼物,岗前培训,岗位晋升',
+  },
+  {
+    name: '应届管培生',
+    date: '2020-10-16',
+    xz: '3k-6k/月',
+    fldy: '五险一金',
+    num: '10',
+    zwyh: '扁平管理,节日礼物,岗前培训,岗位晋升',
+  },
+];

+ 211 - 0
src/views/twoweb/service/index.vue

@@ -0,0 +1,211 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main">
+        <div class="w_1200">
+          <el-col :span="24" class="one">
+            <el-col :span="4" class="list" v-for="(item, index) in list" :key="index" @click.native="btn(item)">
+              <el-col :span="24" class="name">
+                <i class="iconfont" :class="item.icon"></i>
+                <p>{{ item.name }}</p>
+              </el-col>
+            </el-col>
+          </el-col>
+          <el-col :span="24" class="two">
+            <el-col :span="24" class="two_1">
+              <top topText="项目征集" :userMore="false"></top>
+              <list type="1" :list="twoList" @detail="detail"></list>
+            </el-col>
+            <el-col :span="24" class="two_1">
+              <top topText="问卷调查" :userMore="false"></top>
+              <list type="1" :list="twoList" @detail="detail"></list>
+            </el-col>
+            <el-col :span="24" class="two_1">
+              <top topText="成果评价" :userMore="false"></top>
+              <list type="1" :list="twoList" @detail="detail"></list>
+            </el-col>
+            <el-col :span="24" class="two_1">
+              <top topText="信息发布" :userMore="false"></top>
+              <list type="1" :list="twoList" @detail="detail"></list>
+            </el-col>
+            <el-col :span="24" class="two_1">
+              <top topText="高企申报" :userMore="false"></top>
+              <list type="1" :list="twoList" @detail="detail"></list>
+            </el-col>
+            <el-col :span="24" class="two_1">
+              <top topText="预约服务" :userMore="false"></top>
+              <list type="1" :list="twoList" @detail="detail"></list>
+            </el-col>
+          </el-col>
+        </div>
+      </el-col>
+    </el-row>
+    <el-dialog :title="dialogInfo.name" class="dialog" :visible.sync="dialog" width="70%" :before-close="close">
+      <info :type="dialogInfo.type"></info>
+      <el-col :span="24" class="two" v-if="dialogInfo.type == '5'">
+        <el-form :model="form2" :rules="rulesForm2" ref="form2" label-width="80px">
+          <el-form-item label="用户账号" prop="institution_code">
+            <el-input v-model="form2.institution_code" placeholder="请输入用户账号" maxlength="18"></el-input>
+          </el-form-item>
+          <el-form-item label="登录密码" prop="passwd">
+            <el-input v-model="form2.password" placeholder="请输入登录密码" type="password" show-password></el-input>
+          </el-form-item>
+          <el-col :span="24" class="btn">
+            <el-button type="primary" @click="onSubmit2('form2')">提交登录</el-button>
+          </el-col>
+        </el-form>
+      </el-col>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import info from './parts/info.vue';
+import top from './parts/top.vue';
+import list from './parts/list.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: organization } = createNamespacedHelpers('organization');
+export default {
+  name: 'index',
+  props: {},
+  components: {
+    info,
+    top,
+    list,
+  },
+  data: function() {
+    return {
+      list: [
+        { icon: 'iconzhengji', name: '项目征集', type: '1' },
+        { icon: 'iconwenjuan', name: '问卷调查', type: '2' },
+        { icon: 'iconchengguo', name: '成果评价', type: '3' },
+        { icon: 'iconinformation-delivery', name: '信息发布', type: '4' },
+        { icon: 'iconshenbao', name: '高企申报', type: '5' },
+        { icon: 'iconyuyuefuwu', name: '预约服务', type: '6' },
+      ],
+      dialogInfo: {},
+      dialog: false,
+      form2: {},
+      rulesForm2: {},
+      // 公共信息
+      twoList: [],
+    };
+  },
+  created() {},
+  methods: {
+    ...organization(['orgLogin', 'fetch']),
+    // 打开弹框
+    btn(data) {
+      if (data.type == '1') {
+        this.$router.push({ path: '/twoweb/service/project' });
+      } else if (data.type == '2') {
+        this.$router.push({ path: '/twoweb/service/question' });
+      } else if (data.type == '4') {
+        this.$router.push({ path: '/twoweb/service/product' });
+      } else if (data.type == '6') {
+        this.$router.push({ path: '/twoweb/service/order' });
+      } else {
+        this.$set(this, `dialogInfo`, data);
+        this.dialog = true;
+      }
+    },
+    // 关闭弹框
+    close() {
+      this.dialog = false;
+    },
+    // 提交登录
+    onSubmit2(formName) {
+      this.$refs[formName].validate(async valid => {
+        if (valid) {
+          let data = this.form2;
+          const res = await this.orgLogin({ user: data });
+          if (this.$checkRes(res)) {
+            if (this.dialogInfo.type === '5') this.$router.push({ path: '/twoweb/service/policy' });
+          }
+        } else {
+          console.log('error submit!!');
+          return false;
+        }
+      });
+    },
+    // 查看详情
+    detail() {},
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  padding: 10px 0;
+  .one {
+    margin: 0 0 20px 0;
+    .list {
+      width: 15.9%;
+      height: 140px;
+      margin: 0 10px 0px 0;
+      text-align: center;
+      padding: 30px 0;
+      border-radius: 5px;
+      box-shadow: 0 0 5px #409eff;
+      .name {
+        .iconfont {
+          font-size: 40px;
+        }
+        p {
+          font-size: 16px;
+          font-weight: bold;
+          margin: 10px 0 0 0;
+        }
+      }
+    }
+    .list:last-child {
+      margin: 0 0 0 0;
+    }
+    .list:hover {
+      cursor: pointer;
+      .name {
+        p {
+          color: #6495ed;
+        }
+      }
+    }
+  }
+  .two {
+    .two_1 {
+      min-height: 90px;
+      overflow: hidden;
+      box-shadow: 0 0 4px #409eff;
+      border-radius: 10px;
+      margin: 0 10px 10px 0;
+      padding: 10px;
+    }
+  }
+}
+.dialog {
+  .two {
+    height: 200px;
+    background: #fff;
+    padding: 10px 20%;
+    .btn {
+      text-align: center;
+      padding: 10px 0;
+    }
+  }
+  /deep/.el-dialog__body {
+    padding: 0;
+  }
+}
+</style>

+ 203 - 0
src/views/twoweb/service/order/index.vue

@@ -0,0 +1,203 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main">
+        <div class="w_1200">
+          <el-col :span="24" class="one">
+            <el-col :span="24" class="btn">
+              <!-- <el-button type="primary" size="mini" @click="back">返回</el-button> -->
+            </el-col>
+            <el-col :span="24" class="text">预约服务</el-col>
+            <el-col :span="24" class="dwon">
+              <el-form :model="form" :rules="rules" ref="form" label-width="80px">
+                <el-form-item label="服务类型" prop="type">
+                  <el-radio-group v-model="form.type">
+                    <el-radio label="0">服务</el-radio>
+                    <el-radio label="1">设备</el-radio>
+                  </el-radio-group>
+                </el-form-item>
+                <el-form-item label="选取机构" prop="medium_id">
+                  <el-select v-model="form.medium_id" clearable filterable placeholder="请选择" @change="changeMed">
+                    <el-option v-for="item in mediumList" :key="item.id" :label="item.name" :value="item.id"> </el-option>
+                  </el-select>
+                </el-form-item>
+                <el-form-item label="服务名称" prop="project" v-if="form.type == '0'">
+                  <el-select v-model="form.project" clearable filterable placeholder="请选择">
+                    <el-option v-for="item in projectList" :key="item.id" :label="item.name" :value="item"> </el-option>
+                  </el-select>
+                </el-form-item>
+                <el-form-item label="设备名称" prop="project" v-if="form.type == '1'">
+                  <el-select v-model="form.project" clearable filterable placeholder="请选择">
+                    <el-option v-for="item in equipmentList" :key="item.id" :label="item.name" :value="item"> </el-option>
+                  </el-select>
+                </el-form-item>
+                <el-form-item label="联系人" prop="contact">
+                  <el-input v-model="form.contact" placeholder="请输入联系人"></el-input>
+                </el-form-item>
+                <el-form-item label="联系电话" prop="phone">
+                  <el-input v-model="form.phone" placeholder="请输入联系电话"></el-input>
+                </el-form-item>
+                <el-form-item label="邮件" prop="email">
+                  <el-input v-model="form.email" placeholder="请输入邮件"></el-input>
+                </el-form-item>
+                <el-form-item label="服务时间" prop="server_time">
+                  <el-date-picker v-model="form.server_time" placeholder="请选择" value-format="yyyy-MM-dd" format="yyyy-MM-dd" type="date"> </el-date-picker>
+                </el-form-item>
+                <el-form-item label="预约备注" prop="remark">
+                  <el-input
+                    v-model="form.remark"
+                    type="textarea"
+                    maxlength="200"
+                    :autosize="{ minRows: 4, maxRows: 6 }"
+                    show-word-limit
+                    placeholder="请输入预约备注"
+                  ></el-input>
+                </el-form-item>
+                <el-form-item label="开具发票" prop="invoice">
+                  <el-radio-group v-model="form.invoice">
+                    <el-radio label="0">否</el-radio>
+                    <el-radio label="1">是</el-radio>
+                  </el-radio-group>
+                </el-form-item>
+                <el-form-item label="单位名称" prop="company" v-if="form.invoice == '1'">
+                  <el-input v-model="form.company" placeholder="请输入单位名称"></el-input>
+                </el-form-item>
+                <el-form-item label="税号" prop="number" v-if="form.invoice == '1'">
+                  <el-input v-model="form.number" placeholder="请输入纳税人识别号"></el-input>
+                </el-form-item>
+                <el-col :span="24" class="formBtn">
+                  <el-button type="danger" size="mini" @click="back">取消预约</el-button>
+                  <el-button type="primary" size="mini" @click="onSubmit('form')">提交预约</el-button>
+                </el-col>
+              </el-form>
+            </el-col>
+          </el-col>
+        </div>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: Medium } = createNamespacedHelpers('Medium');
+const { mapActions: Order } = createNamespacedHelpers('Order');
+export default {
+  name: 'index',
+  props: {},
+  components: {},
+  data: function() {
+    return {
+      form: {
+        type: '0',
+      },
+      rules: {
+        medium_id: [{ required: true, message: '请选取机构', trigger: 'change' }],
+        type: [{ required: true, message: '请选取服务类型', trigger: 'change' }],
+        project: [{ required: true, message: '请选取服务', trigger: 'change' }],
+        contact: [{ required: true, message: '请输入联系人', trigger: 'blur' }],
+        phone: [{ required: true, message: '请输入联系电话', trigger: 'blur' }],
+        email: [{ required: true, message: '请输入邮件', trigger: 'blur' }],
+        server_time: [{ required: true, message: '请输入服务时间', trigger: 'blur' }],
+        remark: [{ required: true, message: '请输入预约备注', trigger: 'blur' }],
+      },
+      // 机构
+      mediumList: [],
+      // 服务
+      projectList: [],
+      // 设备
+      equipmentList: [],
+    };
+  },
+  created() {
+    this.search();
+  },
+  methods: {
+    ...Medium(['query']),
+    ...Order(['create']),
+    async search() {
+      let res = await this.query();
+      if (this.$checkRes(res)) {
+        this.$set(this, `mediumList`, res.data);
+      }
+    },
+    // 选择机构
+    changeMed(id) {
+      let data = this.mediumList.find(i => i.id == id);
+      if (data) {
+        this.$set(this, `projectList`, data.project);
+        this.$set(this, `equipmentList`, data.equipment);
+      }
+    },
+    onSubmit(formName) {
+      this.$refs[formName].validate(async valid => {
+        if (valid) {
+          let data = form;
+          data.openid = 'ooHQc5vSXiM5PxfpLSdgGURhbPKI';
+          let res = await this.create(data);
+          if (this.$checkRes(res, '预约成功', res.errmsg || '预约失败')) {
+            this.back();
+          }
+        } else {
+          console.log('error submit!!');
+          return false;
+        }
+      });
+    },
+    // 取消
+    back() {
+      this.$router.push({ path: '/twoweb/service/index' });
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  min-height: 500px;
+  margin: 10px 0;
+  .one {
+    min-height: 500px;
+    border-radius: 5px;
+    border: 1px solid #ccc;
+    padding: 0 10px;
+    .btn {
+      padding: 10px;
+      text-align: right;
+    }
+    .text {
+      font-size: 30px;
+      text-align: center;
+      margin: 0 0 10px 0;
+    }
+    .dwon {
+      padding: 10px;
+      border: 1px dashed #ccc;
+      border-radius: 5px;
+      .formBtn {
+        margin-top: 10px;
+        text-align: center;
+      }
+    }
+  }
+}
+.el-date-editor {
+  width: 100%;
+}
+.el-select {
+  width: 100%;
+}
+</style>

+ 176 - 0
src/views/twoweb/service/parts/info.vue

@@ -0,0 +1,176 @@
+<template>
+  <div id="info">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one" v-if="type == '3'">
+          <el-col :span="4" class="describe">服务描述:</el-col>
+          <el-col :span="24" class="text1">
+            <p>
+              这是科研成果管理的一项重要内容。这是一项政策性和技术性很强的工作。它直接关系到科研的发展方向和科研人员的积极性以及经济建设的发展。
+            </p>
+          </el-col>
+          <el-col :span="4" class="process">服务流程:</el-col>
+          <el-col :span="24" class="text1">
+            <el-col :span="24" class="con">
+              <el-col :span="3" class="login">基本信息</el-col>
+              <el-col :span="1" class="arrow"><i class="el-icon-right"></i></el-col>
+              <el-col :span="3" class="login">内容简介</el-col>
+              <el-col :span="1" class="arrow"><i class="el-icon-right"></i></el-col>
+              <el-col :span="5" class="login">委托方提供资料清单</el-col>
+              <el-col :span="1" class="arrow"><i class="el-icon-right"></i></el-col>
+              <el-col :span="3" class="login">发行证书</el-col>
+            </el-col>
+          </el-col>
+          <el-col :span="24" class="btn">
+            <el-button type="primary" size="" @click="addBtn">成果评价申报</el-button>
+            <el-button type="primary" size="" @click="loginBtn">成果评价系统登录</el-button>
+          </el-col>
+        </el-col>
+        <el-col :span="24" class="two" v-else-if="type == '5'">
+          <el-col :span="24" class="title"><span>服务描述</span></el-col>
+          <el-col :span="24" class="info">
+            在平台当中高企可在此根据企业自身条件以及经营情况,进行创新券的领取申报。创新券是政府为了帮助小微企业、优秀创业团队购买创新资源、科研服务而打造的服务系统。创新券由政府发放,小微企业和创业团队在开展创新创业活动过程中用创新券向高校院所购买科研服务,收取创新券的单位持创新券到指定部门兑现。
+          </el-col>
+          <el-col :span="24" class="title"><span>申报流程</span></el-col>
+          <el-col :span="24" class="btn">
+            <el-steps :active="6" align-center>
+              <el-step title="企业注册" description="如您尚未成为平台用户,请先注册成为平台用户"></el-step>
+              <el-step title="登录" description="企业需使用统一社会信用代码+登录密码,方可登录"></el-step>
+              <el-step title="企业信息材料上传" description="企业可根据提示,进行信息材料准备,并进行填写,信息会由您选择的中介机构机型审核"></el-step>
+              <el-step title="合同上传" description="当中介机构审核企业信息通过后,企业可把所签署的合同上传,方便服务机构进行查看"></el-step>
+              <el-step title="高企申报成功" description="当服务机构终审企业资料后,企业方可高企申报成功"></el-step>
+            </el-steps>
+          </el-col>
+        </el-col>
+        <el-col :span="24" class="thr" v-else-if="type == '6'">
+          <el-col :span="24" class="title"><span>服务描述</span></el-col>
+          <el-col :span="24" class="info">
+            用户可根据自身资质条件,进行服务和设备预约服务,目前提供机构有中科在线,吉科在线机构
+          </el-col>
+          <el-col :span="24" class="title"><span>申报流程</span></el-col>
+          <el-col :span="24" class="btn">
+            <el-steps :active="6" align-center>
+              <el-step title="企业注册" description="如您尚未成为平台用户,请先注册成为平台用户"></el-step>
+              <el-step title="登录" description="企业需使用统一社会信用代码+登录密码,方可登录"></el-step>
+            </el-steps>
+          </el-col>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'info',
+  props: {
+    type: { type: String },
+  },
+  components: {},
+  data: function() {
+    return {};
+  },
+  created() {},
+  methods: {
+    addBtn() {
+      window.location.href = 'http://broadcast.waityou24.cn/liveAchieve/userDeclare';
+    },
+    loginBtn() {
+      window.location.href = 'http://broadcast.waityou24.cn/liveAchieve';
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  padding: 0 10px;
+  .one {
+    margin: 10px 0;
+    .describe,
+    .process {
+      background-color: #22529a;
+      height: 45px;
+      border-radius: 10px;
+      line-height: 45px;
+      text-align: center;
+      font-size: 20px;
+      color: #fff;
+      font-weight: bolder;
+    }
+    .text1 {
+      height: 100px;
+      border: 1px solid #22529a;
+      border-radius: 5px;
+      margin-top: 15px;
+      padding: 20px 10px 0px 10px;
+      font-size: 16px;
+      .con {
+        padding-left: 10px;
+        .login {
+          border: 1px solid rgb(221, 219, 219);
+          height: 40px;
+          font-size: 15px;
+          color: #666;
+          line-height: 40px;
+          text-align: center;
+        }
+        .arrow {
+          text-align: center;
+          height: 40px;
+          line-height: 40px;
+        }
+      }
+    }
+    .process {
+      margin-top: 40px;
+    }
+    .btn {
+      text-align: center;
+      padding: 30px 0 0 0;
+    }
+  }
+  .two {
+    .title {
+      font-size: 18px;
+      font-weight: bold;
+      margin: 0 0 10px 0;
+      span {
+        display: inline-block;
+        background-color: #22529a;
+        color: #fff;
+        padding: 10px 20px;
+        border-radius: 8px;
+      }
+    }
+    .info {
+      font-size: 16px;
+      text-indent: 2rem;
+      margin: 0 0 10px 0;
+      padding: 0 0 10px 0;
+      border-bottom: 1px dashed #ccc;
+      color: #000;
+      font-weight: bold;
+      line-height: 30px;
+    }
+    .btn {
+      padding: 0 0 10px 0;
+      border-bottom: 1px dashed #ccc;
+    }
+  }
+}
+</style>

+ 106 - 0
src/views/twoweb/service/parts/list.vue

@@ -0,0 +1,106 @@
+<template>
+  <div id="list">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one" v-if="type == '1'">
+          <el-col :span="24" class="oneList" v-for="(item, index) in list" :key="index" @click.native="detail(item)">
+            <el-col :span="24" class="title textOver">
+              {{ item.title }}
+            </el-col>
+            <el-col :span="24" class="other">
+              <el-col :span="12" class="text">
+                信息来源:<span>{{ item.origin }}</span>
+              </el-col>
+              <el-col :span="12" class="text">
+                发布时间:<span> {{ getDate(item.release_time) }}</span>
+              </el-col>
+            </el-col>
+          </el-col>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+const moment = require('moment');
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'list',
+  props: {
+    type: {
+      type: String,
+    },
+    list: {
+      type: Array,
+    },
+  },
+  components: {},
+  data: function() {
+    return {};
+  },
+  created() {},
+  methods: {
+    getDate(date) {
+      if (date) {
+        let newDate = moment(date).format('YYYY-MM-DD');
+        if (newDate) return newDate;
+      }
+    },
+    detail(data) {
+      this.$emit('detail', data);
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  padding: 5px;
+  .one {
+    min-height: 70px;
+    max-height: 430px;
+    overflow: hidden;
+    .oneList {
+      padding: 12px 0;
+      border-bottom: 1px dashed #ccc;
+      .title {
+        font-size: 16px;
+        margin: 0 0 5px 0;
+      }
+      .other {
+        .text {
+          font-size: 14px;
+          color: #666;
+          span {
+            color: #000;
+          }
+        }
+      }
+    }
+    .oneList:last-child {
+      border-bottom: none;
+    }
+    .oneList:hover {
+      cursor: pointer;
+      .title {
+        font-weight: bold;
+        color: #409eff;
+      }
+    }
+  }
+}
+</style>

+ 71 - 0
src/views/twoweb/service/parts/top.vue

@@ -0,0 +1,71 @@
+<template>
+  <div id="top">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one">
+          <el-col :span="20" class="left">
+            {{ topText }}
+          </el-col>
+          <el-col :span="4" class="right" v-if="userMore">
+            <el-link :underline="false" @click="more">MORE</el-link>
+          </el-col>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'top',
+  props: {
+    topText: { type: String },
+    userMore: { type: Boolean, default: true },
+  },
+  components: {},
+  data: function() {
+    return {};
+  },
+  created() {},
+  methods: {
+    more() {
+      this.$emit('more');
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  .one {
+    height: 40px;
+    line-height: 40px;
+    overflow: hidden;
+    border-bottom: 1px solid #ccc;
+    .left {
+      font-weight: bold;
+      font-size: 16px;
+    }
+    .right {
+      text-align: right;
+      .el-link {
+        font-weight: bold;
+      }
+    }
+  }
+}
+</style>

+ 269 - 0
src/views/twoweb/service/policy/index.vue

@@ -0,0 +1,269 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main">
+        <div class="w_1200">
+          <el-col :span="24" class="one">
+            <el-col :span="24" class="btn">
+              <!-- <el-button type="primary" size="mini" @click="back">返回</el-button> -->
+            </el-col>
+            <el-col :span="24" class="text">高企申报服务</el-col>
+            <el-col :span="24" class="dwon">
+              <el-form :model="form" :rules="rules" ref="form" label-width="100px">
+                <el-row>
+                  <el-col :span="24" class="title"> 资质资料 </el-col>
+                  <el-col :span="24" class="info">
+                    <el-form-item label="申请单位" prop="company">
+                      <el-input v-model="form.company" placeholder="" disabled></el-input>
+                    </el-form-item>
+                    <el-form-item label="申请人" prop="apply_personal">
+                      <el-input v-model="form.apply_personal" placeholder=""></el-input>
+                    </el-form-item>
+                    <el-form-item label="联系电话" prop="phone">
+                      <el-input v-model="form.phone" placeholder=""></el-input>
+                    </el-form-item>
+                    <el-form-item label="法人复印件" prop="qyfr">
+                      <e-upload url="/files/cysci/qyfr_file/upload" :limit="1" v-model="form.qyfr" type="text"></e-upload>
+                    </el-form-item>
+                    <el-form-item label="企业营业执照" prop="yyzz">
+                      <e-upload url="/files/cysci/yyzz_file/upload" :limit="1" v-model="form.yyzz" type="text"></e-upload>
+                    </el-form-item>
+                    <el-form-item label="企业利润表" prop="qylr">
+                      <e-upload url="/files/cysci/qylr_file/upload" :limit="1" v-model="form.qylr" type="text"></e-upload>
+                    </el-form-item>
+                  </el-col>
+                </el-row>
+                <el-row>
+                  <el-col :span="24" class="title">信息资料</el-col>
+                  <el-col :span="24" class="info">
+                    <el-form-item label="中介机构" prop="mechanism_id">
+                      <el-select v-model="form.mechanism_id" placeholder="请选择中介机构">
+                        <el-option v-for="(i, index) in mechanismList" :key="`mechanism${index}`" :value="i._id" :label="i.name"></el-option>
+                      </el-select>
+                    </el-form-item>
+                    <el-form-item label="法人复印件" prop="mqyfr">
+                      <e-upload url="/files/cysci/qyfr_file/upload" :limit="1" v-model="form.mqyfr" type="text"></e-upload>
+                    </el-form-item>
+                    <el-form-item label="企业营业执照" prop="myyzz">
+                      <e-upload url="/files/cysci/yyzz_file/upload" :limit="1" v-model="form.myyzz" type="text"></e-upload>
+                    </el-form-item>
+                    <el-form-item label="企业利润表" prop="mqylr">
+                      <e-upload url="/files/cysci/qylr_file/upload" :limit="1" v-model="form.mqylr" type="text"></e-upload>
+                    </el-form-item>
+                  </el-col>
+                </el-row>
+                <el-col :span="24" class="formBtn">
+                  <el-button type="danger" size="mini" @click="back">取消申请</el-button>
+                  <el-button type="primary" size="mini" @click="onSubmit('form')">提交申请</el-button>
+                </el-col>
+              </el-form>
+            </el-col>
+          </el-col>
+        </div>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+const _ = require('lodash');
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: declare } = createNamespacedHelpers('declare');
+const { mapActions: mechanism } = createNamespacedHelpers('mechanism');
+const { mapActions: organization } = createNamespacedHelpers('organization');
+export default {
+  name: 'index',
+  props: {},
+  components: {},
+  data: function() {
+    return {
+      form: {},
+      rules: {},
+      mechanismList: [],
+    };
+  },
+  created() {
+    this.getOtherList();
+  },
+  methods: {
+    ...declare(['fetch', 'create', 'update']),
+    ...mechanism(['query']),
+    ...organization({ orgFetch: 'fetch' }),
+    async getOtherList() {
+      const res = await this.query();
+      if (this.$checkRes(res)) {
+        this.$set(this, 'mechanismList', res.data);
+      }
+      if (this.user.id) {
+        const res = await this.orgFetch(this.user.id);
+        if (this.$checkRes(res)) {
+          let data = {
+            user_id: res.data.id,
+            company: res.data.name,
+            apply_personal: res.data.companyperson,
+            phone: res.data.phone,
+            qyfr: [],
+            yyzz: [],
+            qylr: [],
+            mqyfr: [],
+            myyzz: [],
+            mqylr: [],
+          };
+          this.$set(this, `form`, data);
+        }
+      }
+    },
+    async onSubmit(formName) {
+      this.$refs[formName].validate(async valid => {
+        if (valid) {
+          let data = this.form;
+          data.material = this.oneMap();
+          data.medium_material = this.twoMap();
+          if (this.id) {
+            data.status = this.searchStatus(data.status);
+            let res = await this.update(data);
+            if (this.$checkRes(res)) {
+              this.$message({
+                message: '高企申报服务重申成功,请耐心等待结果',
+                type: 'success',
+              });
+              this.back();
+            }
+          } else {
+            let res = await this.create(data);
+            if (this.$checkRes(res)) {
+              this.$message({
+                message: '高企申报服务申报成功,请耐心等待结果',
+                type: 'success',
+              });
+              this.back();
+            }
+          }
+        } else {
+          console.log('error submit!!');
+          return false;
+        }
+      });
+    },
+    // 企业资质资料重组
+    oneMap() {
+      let data = _.cloneDeep(this.form);
+      const arr = ['qyfr', 'yyzz', 'qylr'];
+      const res = [];
+      for (const key of arr) {
+        const e = data[key];
+        if (e.length <= 0) continue;
+        const head = _.head(e);
+        res.push(head);
+      }
+      return res;
+    },
+    // 企业信息资料
+    twoMap() {
+      let data = _.cloneDeep(this.form);
+      const arr = ['qyfr1', 'yyzz1', 'qylr1'];
+      const res = [];
+      for (const key of arr) {
+        const e = data[key];
+        if (e.length <= 0) continue;
+        const head = _.head(e);
+        res.push(head);
+      }
+      return res;
+    },
+    // 资质信息处理,订单
+    searchMaterial(data) {
+      if (data.material.length > 0) {
+        data.qyfr = [data.material[0]];
+        data.yyzz = [data.material[1]];
+        data.qylr = [data.material[2]];
+      } else {
+        data.qyfr = [];
+        data.yyzz = [];
+        data.qylr = [];
+      }
+      if (data.medium_material.length > 0) {
+        data.qyfr1 = [data.medium_material[0]];
+        data.yyzz1 = [data.medium_material[1]];
+        data.qylr1 = [data.medium_material[2]];
+      } else {
+        data.qyfr1 = [];
+        data.yyzz1 = [];
+        data.qylr1 = [];
+      }
+      return data;
+    },
+    // 处理状态
+    searchStatus(data) {
+      if (data == '0') return '0';
+      else if (data == '-1') return '0';
+      else if (data == '1') return '2';
+      else if (data == '2') return '2';
+    },
+    back() {
+      this.$router.push({ path: '/twoweb/service/index' });
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+    id() {
+      return this.$route.query.id;
+    },
+    status() {
+      return this.$route.query.status;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  min-height: 500px;
+  margin: 10px 0;
+  .one {
+    min-height: 500px;
+    border-radius: 5px;
+    border: 1px solid #ccc;
+    padding: 0 10px;
+    .btn {
+      padding: 10px;
+      text-align: right;
+    }
+    .text {
+      font-size: 30px;
+      text-align: center;
+      margin: 0 0 10px 0;
+    }
+    .dwon {
+      padding: 10px;
+      border: 1px dashed #ccc;
+      border-radius: 5px;
+      .formBtn {
+        margin-top: 10px;
+        text-align: center;
+      }
+    }
+  }
+}
+.title {
+  font-weight: bold;
+  border-bottom: 1px dashed;
+  padding: 10px 0;
+  margin-bottom: 10px;
+}
+.info {
+  border: 1px solid #000;
+  border-radius: 5px;
+  padding: 10px;
+}
+</style>

+ 344 - 0
src/views/twoweb/service/product/achieve.vue

@@ -0,0 +1,344 @@
+<template>
+  <div id="achieve">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="top">
+          技术成果
+        </el-col>
+        <el-col :span="24" class="info">
+          <el-col :span="24" class="txt">
+            <el-col :span="2" class="left">
+              企业名称:
+            </el-col>
+            <el-col :span="22" class="right">
+              <el-input v-model="form.company" placeholder="请输入企业名称" disabled></el-input>
+            </el-col>
+          </el-col>
+          <el-col :span="12" class="txt">
+            <el-col :span="4" class="left">
+              联系电话:
+            </el-col>
+            <el-col :span="20" class="right">
+              <el-input v-model="form.phone" placeholder="请输入联系电话" disabled></el-input>
+            </el-col>
+          </el-col>
+          <el-col :span="12" class="txt">
+            <el-col :span="4" class="left">
+              电子邮箱:
+            </el-col>
+            <el-col :span="20" class="right">
+              <el-input v-model="form.email" placeholder="请输入电子邮箱" disabled></el-input>
+            </el-col>
+          </el-col>
+          <el-col :span="12" class="txt">
+            <el-col :span="4" class="left">
+              联系人:
+            </el-col>
+            <el-col :span="20" class="right">
+              <el-input v-model="form.contacts" placeholder="请输入联系人"></el-input>
+            </el-col>
+          </el-col>
+          <el-col :span="12" class="txt">
+            <el-col :span="4" class="left">
+              QQ/微信
+            </el-col>
+            <el-col :span="20" class="right">
+              <el-input v-model="form.qqwx" placeholder="请输入QQ/微信"></el-input>
+            </el-col>
+          </el-col>
+          <el-col :span="24" class="txt">
+            <el-col :span="2" class="left">
+              成果名称:
+            </el-col>
+            <el-col :span="22" class="right">
+              <el-input v-model="form.name" placeholder="请输入成果名称"></el-input>
+            </el-col>
+          </el-col>
+          <el-col :span="12" class="txt">
+            <el-col :span="4" class="left">
+              所属领域:
+            </el-col>
+            <el-col :span="20" class="right">
+              <el-select v-model="form.field" filterable clearable>
+                <el-option v-for="(item, index) in fieldList" :key="index" :value="item.name" :label="item.name"></el-option>
+              </el-select>
+            </el-col>
+          </el-col>
+          <el-col :span="12" class="txt">
+            <el-col :span="4" class="left">
+              合作方式:
+            </el-col>
+            <el-col :span="20" class="right">
+              <el-select v-model="form.cooperation" filterable clearable>
+                <el-option v-for="(item, index) in cooperationList" :key="index" :value="item.name" :label="item.name"></el-option>
+              </el-select>
+            </el-col>
+          </el-col>
+          <el-col :span="12" class="txt">
+            <el-col :span="4" class="left">
+              成果状态:
+            </el-col>
+            <el-col :span="20" class="right">
+              <el-select v-model="form.achievestatus" filterable>
+                <el-option v-for="(item, index) in achievestatusList" :key="index" :value="item.name" :label="item.name"></el-option>
+              </el-select>
+            </el-col>
+          </el-col>
+          <el-col :span="12" class="txt">
+            <el-col :span="4" class="left">
+              成果权属:
+            </el-col>
+            <el-col :span="20" class="right">
+              <el-input v-model="form.achieveown" placeholder="请输入QQ/微信"></el-input>
+            </el-col>
+          </el-col>
+          <el-col :span="12" class="txt">
+            <el-col :span="4" class="left">
+              成果来源:
+            </el-col>
+            <el-col :span="20" class="right">
+              <el-select v-model="form.achievesource" placeholder="请选择成果来源">
+                <el-option label="国家项目" value="国家项目"></el-option>
+                <el-option label="省级项目" value="省级项目"></el-option>
+                <el-option label="市级项目" value="市级项目"></el-option>
+                <el-option label="自选项目" value="自选项目"></el-option>
+              </el-select>
+            </el-col>
+          </el-col>
+          <el-col :span="12" class="txt">
+            <el-col :span="4" class="left">
+              意向价格:
+            </el-col>
+            <el-col :span="20" class="right">
+              <el-input v-model="form.intentionprice" placeholder="请输入意向价格"></el-input>
+            </el-col>
+          </el-col>
+          <el-col :span="24" class="txt">
+            <el-col :span="2" class="left">
+              项目路演:
+            </el-col>
+            <el-col :span="22" class="right">
+              <upload
+                :limit="1"
+                :data="form.roadshow"
+                listType=""
+                type="roadshow"
+                :url="'/files/roadshow/upload'"
+                @upload="roadshowSuccess"
+                @delete="roadshowDelete"
+              ></upload>
+            </el-col>
+          </el-col>
+          <el-col :span="24" class="txtTwo">
+            <p>成果简介:</p>
+            <el-input
+              v-model="form.achievebrief"
+              type="textarea"
+              maxlength="500"
+              show-word-limit
+              :autosize="{ minRows: 4, maxRows: 5 }"
+              placeholder="请输入成果简介"
+            ></el-input>
+          </el-col>
+          <el-col :span="24" class="txtTwo">
+            <p>技术特点:</p>
+            <el-input
+              v-model="form.features"
+              type="textarea"
+              maxlength="500"
+              show-word-limit
+              :autosize="{ minRows: 4, maxRows: 5 }"
+              placeholder="请输入技术特点"
+            ></el-input>
+          </el-col>
+          <el-col :span="24" class="txtTwo">
+            <p>技术团队:</p>
+            <el-input
+              v-model="form.team"
+              type="textarea"
+              maxlength="500"
+              show-word-limit
+              :autosize="{ minRows: 4, maxRows: 5 }"
+              placeholder="请输入技术团队"
+            ></el-input>
+          </el-col>
+          <el-col :span="24" class="txtTwo">
+            <p>商业预期:</p>
+            <el-input
+              v-model="form.expect"
+              type="textarea"
+              maxlength="500"
+              show-word-limit
+              :autosize="{ minRows: 4, maxRows: 5 }"
+              placeholder="请输入商业预期"
+            ></el-input>
+          </el-col>
+          <el-col :span="24" class="txtTwo">
+            <p>合作条件及要求:</p>
+            <el-input
+              v-model="form.condition"
+              type="textarea"
+              maxlength="500"
+              show-word-limit
+              :autosize="{ minRows: 4, maxRows: 5 }"
+              placeholder="请输入合作条件及要求"
+            ></el-input>
+          </el-col>
+          <el-col :span="24" class="txtTwo">
+            <p>图片(6):</p>
+            <uploadArray
+              :limit="6"
+              :data="form.image"
+              :uploadBtn="true"
+              type="image"
+              :url="`/files/image/upload`"
+              @upload="uploadSuccess"
+              @delete="uploadDelete"
+            ></uploadArray>
+          </el-col>
+          <el-col :span="24" class="btn">
+            <el-button type="primary" size="mini" @click="onSubmit">提交保存</el-button>
+          </el-col>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import upload from '@common/src/components/frame/upload.vue';
+import uploadArray from '@common/src/components/upload/uploadArray.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: product } = createNamespacedHelpers('product');
+const { mapActions: code } = createNamespacedHelpers('code');
+export default {
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  name: 'achieve',
+  props: {},
+  components: { upload, uploadArray },
+  data: function() {
+    return {
+      form: {},
+      fieldList: [],
+      cooperationList: [],
+      achievestatusList: [],
+    };
+  },
+  async created() {
+    await this.searchOther();
+    await this.searchUser();
+  },
+  methods: {
+    ...product(['create']),
+    ...code({ codeQuery: 'query' }),
+    // 查询用户信息
+    searchUser() {
+      let data = {
+        company: this.user.name,
+        phone: this.user.phone,
+        email: this.user.email,
+        user_id: this.user.id,
+      };
+      this.$set(this, `form`, data);
+    },
+    // 提交保存
+    async onSubmit() {
+      let data = this.form;
+      data.type = '1';
+      data.status = '1';
+      let res = await this.create(data);
+      if (this.$checkRes(res)) {
+        this.$message({
+          message: '信息发布成功,需等待审核',
+          type: 'success',
+        });
+        this.form = {};
+      }
+    },
+    // 图片
+    uploadSuccess({ type, data }) {
+      let arr = _.get(this.form, type);
+      if (_.isArray(arr)) {
+        let datas = { name: data.name, url: data.uri };
+        this.form[type].push({ name: data.name, url: data.uri });
+      } else {
+        let newArr = [{ name: data.name, url: data.uri }];
+        this.$set(this.form, `${type}`, newArr);
+      }
+    },
+    // 删除图片
+    uploadDelete(index) {
+      this.form.image.splice(index, 1);
+    },
+    // 项目路演文件上传
+    roadshowSuccess({ type, data }) {
+      this.$set(this.form, `${type}`, data.uri);
+    },
+    // 项目路演文件删除
+    roadshowDelete(data) {
+      this.$set(this.form, `${data.type}`, null);
+    },
+    // 查询字典表
+    async searchOther() {
+      // 所属领域;
+      let res = await this.codeQuery({ category: '01' });
+      if (this.$checkRes(res)) {
+        this.$set(this, `fieldList`, res.data);
+      }
+      // 合作方式;
+      res = await this.codeQuery({ category: '03' });
+      if (this.$checkRes(res)) {
+        this.$set(this, `cooperationList`, res.data);
+      }
+      // 成果状态
+      res = await this.codeQuery({ category: '02' });
+      if (this.$checkRes(res)) {
+        this.$set(this, `achievestatusList`, res.data);
+      }
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  watch: {},
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  padding: 10px;
+  border: 1px solid #ccc;
+  .top {
+    border-bottom: 1px solid #ff0000;
+    height: 50px;
+    line-height: 50px;
+    font-size: 20px;
+    padding: 0 10px;
+  }
+  .info {
+    .txt {
+      margin: 0 0 5px 0;
+      border-bottom: 1px dashed #ccc;
+      padding: 10px 0;
+      .left {
+        text-align: center;
+        height: 40px;
+        line-height: 40px;
+        font-size: 15px;
+      }
+    }
+    .txtTwo {
+      p {
+        font-size: 15px;
+        padding: 10px;
+      }
+    }
+    .btn {
+      text-align: center;
+      padding: 15px 0;
+    }
+  }
+}
+</style>

+ 221 - 0
src/views/twoweb/service/product/business.vue

@@ -0,0 +1,221 @@
+<template>
+  <div id="business">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="top">
+          商务服务
+        </el-col>
+        <el-col class="info">
+          <el-col :span="24" class="txt">
+            <el-col :span="2" class="left">
+              企业名称:
+            </el-col>
+            <el-col :span="22" class="right">
+              <el-input v-model="form.company" placeholder="请输入企业名称" disabled></el-input>
+            </el-col>
+          </el-col>
+          <el-col :span="12" class="txt">
+            <el-col :span="4" class="left">
+              联系电话:
+            </el-col>
+            <el-col :span="20" class="right">
+              <el-input v-model="form.phone" placeholder="请输入联系电话" disabled></el-input>
+            </el-col>
+          </el-col>
+          <el-col :span="12" class="txt">
+            <el-col :span="4" class="left">
+              电子邮箱:
+            </el-col>
+            <el-col :span="20" class="right">
+              <el-input v-model="form.email" placeholder="请输入电子邮箱" disabled></el-input>
+            </el-col>
+          </el-col>
+          <el-col :span="12" class="txt">
+            <el-col :span="4" class="left">
+              联系人:
+            </el-col>
+            <el-col :span="20" class="right">
+              <el-input v-model="form.contacts" placeholder="请输入联系人"></el-input>
+            </el-col>
+          </el-col>
+          <el-col :span="12" class="txt">
+            <el-col :span="4" class="left">
+              QQ/微信
+            </el-col>
+            <el-col :span="20" class="right">
+              <el-input v-model="form.qqwx" placeholder="请输入QQ/微信"></el-input>
+            </el-col>
+          </el-col>
+          <el-col :span="24" class="txt">
+            <el-col :span="2" class="left">
+              信息名称:
+            </el-col>
+            <el-col :span="22" class="right">
+              <el-input v-model="form.name" placeholder="请输入成果名称"></el-input>
+            </el-col>
+          </el-col>
+          <el-col :span="12" class="txt">
+            <el-col :span="4" class="left">
+              信息属性
+            </el-col>
+            <el-col :span="20" class="right">
+              <el-radio-group v-model="form.messattribute">
+                <el-radio label="提供方"></el-radio>
+                <el-radio label="需求方"></el-radio>
+              </el-radio-group>
+            </el-col>
+          </el-col>
+          <el-col :span="12" class="txt">
+            <el-col :span="4" class="left">
+              需求程度
+            </el-col>
+            <el-col :span="20" class="right">
+              <el-radio-group v-model="form.demand">
+                <el-radio label="特急"></el-radio>
+                <el-radio label="一般"></el-radio>
+                <el-radio label="长期"></el-radio>
+              </el-radio-group>
+            </el-col>
+          </el-col>
+          <el-col :span="24" class="txtTwo">
+            <p>信息描述:</p>
+            <el-input
+              v-model="form.informationdesc"
+              type="textarea"
+              maxlength="500"
+              show-word-limit
+              :autosize="{ minRows: 4, maxRows: 5 }"
+              placeholder="请输入信息描述"
+            ></el-input>
+          </el-col>
+          <el-col :span="24" class="txtTwo">
+            <p>核心要素:</p>
+            <el-input
+              v-model="form.coreelements"
+              type="textarea"
+              maxlength="500"
+              show-word-limit
+              :autosize="{ minRows: 4, maxRows: 5 }"
+              placeholder="请输入核心要素"
+            ></el-input>
+          </el-col>
+          <el-col :span="24" class="txtTwo">
+            <p>价格信息:</p>
+            <el-input
+              v-model="form.priceinfo"
+              type="textarea"
+              maxlength="500"
+              show-word-limit
+              :autosize="{ minRows: 4, maxRows: 5 }"
+              placeholder="请输入价格信息"
+            ></el-input>
+          </el-col>
+          <el-col :span="24" class="txtTwo">
+            <p>商务预期:</p>
+            <el-input
+              v-model="form.expect"
+              type="textarea"
+              maxlength="500"
+              show-word-limit
+              :autosize="{ minRows: 4, maxRows: 5 }"
+              placeholder="请输入商务预期"
+            ></el-input>
+          </el-col>
+          <el-col :span="24" class="btn">
+            <el-button type="primary" size="mini" @click="onSubmit">提交保存</el-button>
+          </el-col>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: product } = createNamespacedHelpers('product');
+export default {
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  name: 'business',
+  props: {},
+  components: {},
+  data: function() {
+    return { form: {} };
+  },
+  async created() {
+    await this.searchUser();
+  },
+  methods: {
+    ...product(['create']),
+    // 查询用户信息
+    searchUser() {
+      let data = {
+        company: this.user.name,
+        phone: this.user.phone,
+        email: this.user.email,
+        user_id: this.user.id,
+      };
+      this.$set(this, `form`, data);
+    },
+    // 提交保存
+    async onSubmit() {
+      let data = this.form;
+      data.type = '2';
+      data.status = '1';
+      let res = await this.create(data);
+      if (this.$checkRes(res)) {
+        this.$message({
+          message: '信息发布成功,需等待审核',
+          type: 'success',
+        });
+        this.form = {};
+      }
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  watch: {},
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  padding: 10px;
+  border: 1px solid #ccc;
+  .top {
+    border-bottom: 1px solid #ff0000;
+    height: 50px;
+    line-height: 50px;
+    font-size: 20px;
+    padding: 0 10px;
+  }
+  .info {
+    .txt {
+      margin: 0 0 5px 0;
+      border-bottom: 1px dashed #ccc;
+      padding: 10px 0;
+      .left {
+        text-align: center;
+        height: 40px;
+        line-height: 40px;
+        font-size: 15px;
+      }
+      .right {
+        padding: 10px 0;
+      }
+    }
+    .txtTwo {
+      p {
+        font-size: 15px;
+        padding: 10px;
+      }
+    }
+    .btn {
+      text-align: center;
+      padding: 15px 0;
+    }
+  }
+}
+</style>

+ 86 - 0
src/views/twoweb/service/product/index.vue

@@ -0,0 +1,86 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main">
+        <div class="w_1200">
+          <el-col :span="24" class="one">
+            <el-col :span="24" class="top">
+              <el-col :span="3">
+                <el-image :src="img_path" style="width:105px;height:105px;"></el-image>
+              </el-col>
+              <el-col :span="20">
+                <p>温馨提示:</p>
+                <p>1、为了保证您的信息能顺利通过我们的审核,请将信息的真实情况尽可能全面的发布出来!</p>
+                <p>2、根据我们的长期跟踪统计,信息完整度越高,越容易获得目标客户的关注!</p>
+                <p>3、信息完整度越高,将在我们的平台搜索结果排序靠前、获得推荐机会,以及享受增值服务试用机会!</p>
+                <p>4、发布信息,需用户进行登录,如是尚未注册用户,请先注册为平台用户,待审核通过后,放可发布信息!</p>
+              </el-col>
+            </el-col>
+            <el-col :span="24" class="down">
+              <el-tabs v-model="active" type="card">
+                <el-tab-pane label="科技需求" name="first">
+                  <techol></techol>
+                </el-tab-pane>
+                <el-tab-pane label="技术成果" name="second">
+                  <achieve></achieve>
+                </el-tab-pane>
+                <el-tab-pane label="商务服务" name="third">
+                  <business></business>
+                </el-tab-pane>
+              </el-tabs>
+            </el-col>
+          </el-col>
+        </div>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import techol from './techol.vue';
+import achieve from './achieve.vue';
+import business from './business.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'index',
+  props: {},
+  components: { techol, achieve, business },
+  data: function() {
+    return {
+      img_path: require('@common/src/assets/product.png'),
+      active: 'first',
+    };
+  },
+  created() {},
+  methods: {},
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  min-height: 557px;
+  padding: 15px 0;
+  .top {
+    background: #f3faff;
+    padding: 15px;
+    border: 1px solid #ccc;
+    margin: 0 0 15px 0;
+    p {
+      font-size: 16px;
+    }
+  }
+}
+</style>

+ 285 - 0
src/views/twoweb/service/product/techol.vue

@@ -0,0 +1,285 @@
+<template>
+  <div id="techol">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="top">
+          科技需求
+        </el-col>
+        <el-col :span="24" class="info">
+          <el-col :span="24" class="txt">
+            <el-col :span="2" class="left">
+              企业名称:
+            </el-col>
+            <el-col :span="22" class="right">
+              <el-input v-model="form.company" placeholder="请输入企业名称" disabled></el-input>
+            </el-col>
+          </el-col>
+          <el-col :span="12" class="txt">
+            <el-col :span="4" class="left">
+              联系电话:
+            </el-col>
+            <el-col :span="20" class="right">
+              <el-input v-model="form.phone" placeholder="请输入联系电话" disabled></el-input>
+            </el-col>
+          </el-col>
+          <el-col :span="12" class="txt">
+            <el-col :span="4" class="left">
+              电子邮箱:
+            </el-col>
+            <el-col :span="20" class="right">
+              <el-input v-model="form.email" placeholder="请输入电子邮箱" disabled></el-input>
+            </el-col>
+          </el-col>
+          <el-col :span="12" class="txt">
+            <el-col :span="4" class="left">
+              联系人:
+            </el-col>
+            <el-col :span="20" class="right">
+              <el-input v-model="form.contacts" placeholder="请输入联系人"></el-input>
+            </el-col>
+          </el-col>
+          <el-col :span="12" class="txt">
+            <el-col :span="4" class="left">
+              QQ/微信
+            </el-col>
+            <el-col :span="20" class="right">
+              <el-input v-model="form.qqwx" placeholder="请输入QQ/微信"></el-input>
+            </el-col>
+          </el-col>
+          <el-col :span="24" class="txt">
+            <el-col :span="2" class="left">
+              需求名称:
+            </el-col>
+            <el-col :span="22" class="right">
+              <el-input v-model="form.name" placeholder="请输入需求名称"></el-input>
+            </el-col>
+          </el-col>
+          <el-col :span="12" class="txt">
+            <el-col :span="4" class="left">
+              紧急程度:
+            </el-col>
+            <el-col :span="20" class="right">
+              <el-select v-model="form.demand" placeholder="请选择需求紧急程度" clearable>
+                <el-option label="特急" value="特急"></el-option>
+                <el-option label="一般" value="一般"></el-option>
+                <el-option label="长期" value="长期"></el-option>
+              </el-select>
+            </el-col>
+          </el-col>
+          <el-col :span="12" class="txt">
+            <el-col :span="4" class="left">
+              所属领域:
+            </el-col>
+            <el-col :span="20" class="right">
+              <el-select v-model="form.field" filterable clearable>
+                <el-option v-for="(item, index) in fieldList" :key="index" :value="item.name" :label="item.name"></el-option>
+              </el-select>
+            </el-col>
+          </el-col>
+          <el-col :span="12" class="txt">
+            <el-col :span="4" class="left">
+              投资预算:
+            </el-col>
+            <el-col :span="20" class="right">
+              <el-input v-model="form.budget" placeholder="请输入投资预算"></el-input>
+            </el-col>
+          </el-col>
+          <el-col :span="12" class="txt">
+            <el-col :span="4" class="left">
+              合作方式:
+            </el-col>
+            <el-col :span="20" class="right">
+              <el-select v-model="form.cooperation" filterable clearable>
+                <el-option v-for="(item, index) in cooperationList" :key="index" :value="item.name" :label="item.name"></el-option>
+              </el-select>
+            </el-col>
+          </el-col>
+          <el-col :span="24" class="txtTwo">
+            <p>技术说明:</p>
+            <el-input
+              v-model="form.requirementdesc"
+              type="textarea"
+              maxlength="500"
+              show-word-limit
+              :autosize="{ minRows: 4, maxRows: 5 }"
+              placeholder="请输入技术说明"
+            ></el-input>
+          </el-col>
+          <el-col :span="24" class="txtTwo">
+            <p>预期目标:</p>
+            <el-input
+              v-model="form.expect"
+              type="textarea"
+              maxlength="500"
+              show-word-limit
+              :autosize="{ minRows: 4, maxRows: 5 }"
+              placeholder="请输入预期目标"
+            ></el-input>
+          </el-col>
+          <el-col :span="24" class="txtTwo">
+            <p>需求现状:</p>
+            <el-input
+              v-model="form.present"
+              type="textarea"
+              maxlength="500"
+              show-word-limit
+              :autosize="{ minRows: 4, maxRows: 5 }"
+              placeholder="请输入需求现状"
+            ></el-input>
+          </el-col>
+          <el-col :span="24" class="txtTwo">
+            <p>合作条件及要求:</p>
+            <el-input
+              v-model="form.condition"
+              type="textarea"
+              maxlength="500"
+              show-word-limit
+              :autosize="{ minRows: 4, maxRows: 5 }"
+              placeholder="请输入合作条件及要求"
+            ></el-input>
+          </el-col>
+          <el-col :span="24" class="txtTwo">
+            <p>图片(6):</p>
+            <uploadArray
+              :limit="6"
+              :data="form.image"
+              :uploadBtn="true"
+              type="image"
+              :url="`/files/image/upload`"
+              @upload="uploadSuccess"
+              @delete="uploadDelete"
+            ></uploadArray>
+          </el-col>
+          <el-col :span="24" class="btn">
+            <el-button type="primary" size="mini" @click="onSubmit">提交保存</el-button>
+          </el-col>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import uploadArray from '@common/src/components/upload/uploadArray.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: product } = createNamespacedHelpers('product');
+const { mapActions: code } = createNamespacedHelpers('code');
+export default {
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  name: 'techol',
+  props: {},
+  components: { uploadArray },
+  data: function() {
+    return {
+      form: {},
+      // 所属领域
+      fieldList: [],
+      // 合作方式
+      cooperationList: [],
+    };
+  },
+  async created() {
+    await this.searchOther();
+    await this.searchUser();
+  },
+  methods: {
+    ...product(['create']),
+    ...code({ codeQuery: 'query' }),
+    // 查询用户信息
+    searchUser() {
+      let data = {
+        company: this.user.name,
+        phone: this.user.phone,
+        email: this.user.email,
+        user_id: this.user.id,
+      };
+      this.$set(this, `form`, data);
+    },
+    // 提交保存
+    async onSubmit() {
+      let data = this.form;
+      data.type = '0';
+      data.status = '1';
+      let res = await this.create(data);
+      if (this.$checkRes(res)) {
+        this.$message({
+          message: '信息发布成功,需等待审核',
+          type: 'success',
+        });
+        this.form = {};
+      }
+    },
+    // 图片
+    uploadSuccess({ type, data }) {
+      let arr = _.get(this.form, type);
+      if (_.isArray(arr)) {
+        let datas = { name: data.name, url: data.uri };
+        this.form[type].push({ name: data.name, url: data.uri });
+      } else {
+        let newArr = [{ name: data.name, url: data.uri }];
+        this.$set(this.form, `${type}`, newArr);
+      }
+    },
+    // 删除图片
+    uploadDelete(index) {
+      this.form.image.splice(index, 1);
+    },
+    // 查询字典表
+    async searchOther() {
+      // 所属领域;
+      let res = await this.codeQuery({ category: '01' });
+      if (this.$checkRes(res)) {
+        this.$set(this, `fieldList`, res.data);
+      }
+      // 合作方式;
+      res = await this.codeQuery({ category: '03' });
+      if (this.$checkRes(res)) {
+        this.$set(this, `cooperationList`, res.data);
+      }
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  watch: {},
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  padding: 10px;
+  border: 1px solid #ccc;
+  .top {
+    border-bottom: 1px solid #ff0000;
+    height: 50px;
+    line-height: 50px;
+    font-size: 20px;
+    padding: 0 10px;
+  }
+  .info {
+    .txt {
+      margin: 0 0 5px 0;
+      border-bottom: 1px dashed #ccc;
+      padding: 10px 0;
+      .left {
+        text-align: center;
+        height: 40px;
+        line-height: 40px;
+        font-size: 15px;
+      }
+    }
+    .txtTwo {
+      p {
+        font-size: 15px;
+        padding: 10px;
+      }
+    }
+    .btn {
+      text-align: center;
+      padding: 15px 0;
+    }
+  }
+}
+</style>

+ 114 - 0
src/views/twoweb/service/project/index.vue

@@ -0,0 +1,114 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main">
+        <div class="w_1200">
+          <el-col :span="24" class="one">
+            <el-col :span="24" class="one_1">
+              2022年度吉林省科技发展计划高新技术领域项目建议书
+            </el-col>
+            <el-col :span="24" class="one_2">
+              <el-tabs v-model="active" type="card">
+                <el-tab-pane label="通知正文" name="first">
+                  <questionInfo :info="info"></questionInfo>
+                </el-tab-pane>
+                <el-tab-pane label="信息填报" name="second">
+                  <projectForm :form="form" @reset="reset" @onSubmit="onSubmit"></projectForm>
+                </el-tab-pane>
+              </el-tabs>
+            </el-col>
+          </el-col>
+        </div>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import questionInfo from './parts/questionInfo.vue';
+import projectForm from './parts/projectForm.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: mapQuestion } = createNamespacedHelpers('question');
+const { mapActions: questionnaire } = createNamespacedHelpers('questionnaire');
+const { mapActions: projectsolic } = createNamespacedHelpers('projectsolic');
+export default {
+  name: 'index',
+  props: {},
+  components: { questionInfo, projectForm },
+  data: function() {
+    return {
+      active: 'first',
+      info: {},
+      form: {},
+    };
+  },
+  created() {
+    this.search();
+    if (this.id) {
+      this.searchInfo();
+    }
+  },
+  methods: {
+    ...mapQuestion(['query']),
+    ...projectsolic(['create']),
+    ...questionnaire(['fetch']),
+    async search() {
+      let res = await this.query();
+      if (this.$checkRes(res)) {
+        this.$set(this, `info`, res.data[0]);
+      }
+    },
+    async searchInfo() {
+      let res = await this.fetch(this.id);
+      if (this.$checkRes(res)) {
+        this.$set(this, `info`, res.data);
+      }
+    },
+    async onSubmit({ data }) {
+      data.question_id = this.info._id;
+      let res = await this.create(data);
+      if (this.$checkRes(res)) {
+        this.$message({
+          message: '数据添加成功',
+          type: 'success',
+        });
+        this.reset();
+      }
+    },
+    // 取消
+    reset() {
+      this.form = {};
+      this.$router.push({ path: '/twoweb/service/index' });
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+    id() {
+      return this.$route.query.id;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    id: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  padding: 10px 0;
+  .one {
+    .one_1 {
+      text-align: center;
+      font-size: 30px;
+      padding: 30px 0 15px 0;
+    }
+  }
+}
+</style>

+ 442 - 0
src/views/twoweb/service/project/parts/projectForm.vue

@@ -0,0 +1,442 @@
+<template>
+  <div id="projectForm">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-form :model="form" :rules="rules" ref="form" label-width="125px">
+          <el-col :span="24" class="one">
+            <el-col :span="24" class="txt">
+              <span> 项目基本信息</span>
+            </el-col>
+            <el-col :span="24" class="info">
+              <el-col :span="24">
+                <el-form-item prop="name">
+                  <el-col :span="21" slot="label">
+                    项目名称:
+                  </el-col>
+                  <el-col :span="24">
+                    <el-input v-model="form.name" placeholder="请输入项目名称"></el-input>
+                  </el-col>
+                </el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item prop="pro_user">
+                  <el-col :span="21" slot="label">
+                    项目负责人:
+                  </el-col>
+                  <el-col :span="24">
+                    <el-input v-model="form.pro_user" placeholder="请输入项目负责人"></el-input>
+                  </el-col>
+                </el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item prop="pro_phone">
+                  <el-col :span="21" slot="label">
+                    联系电话:
+                  </el-col>
+                  <el-col :span="24">
+                    <el-input v-model="form.pro_phone" placeholder="请输入联系电话"></el-input>
+                  </el-col>
+                </el-form-item>
+              </el-col>
+              <el-col :span="12" class="langSelect">
+                <el-form-item prop="techol_stage">
+                  <el-col :span="21" slot="label">
+                    技术阶段:
+                  </el-col>
+                  <el-col :span="24">
+                    <el-select v-model="form.techol_stage" filterable>
+                      <el-option v-for="(item, index) in techolstageList" :key="index" :value="item.name" :label="item.name"></el-option>
+                    </el-select>
+                  </el-col>
+                </el-form-item>
+              </el-col>
+              <el-col :span="12" class="langSelect">
+                <el-form-item prop="techol_level">
+                  <el-col :span="21" slot="label">
+                    技术水平:
+                  </el-col>
+                  <el-col :span="24">
+                    <el-select v-model="form.techol_level" filterable>
+                      <el-option v-for="(item, index) in techollevelList" :key="index" :value="item.name" :label="item.name"></el-option>
+                    </el-select>
+                  </el-col>
+                </el-form-item>
+              </el-col>
+              <el-col :span="12" class="langSelect">
+                <el-form-item prop="field">
+                  <el-col :span="21" slot="label">
+                    领域分类:
+                  </el-col>
+                  <el-col :span="24">
+                    <el-select v-model="form.field" filterable>
+                      <el-option v-for="(item, index) in fieldList" :key="index" :value="item.name" :label="item.name"></el-option>
+                    </el-select>
+                  </el-col>
+                </el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item prop="scale">
+                  <el-col :span="21" slot="label">
+                    市场预估:
+                  </el-col>
+                  <el-col :span="24">
+                    <p>关键技术所支撑的产品市场规模<el-input v-model.number="form.scale" class="scale"></el-input>(亿元/年)</p>
+                  </el-col>
+                </el-form-item>
+              </el-col>
+            </el-col>
+          </el-col>
+          <el-col :span="24" class="one">
+            <el-col :span="24" class="txt">
+              <span>项目建议单位</span>
+            </el-col>
+            <el-col :span="24" class="info">
+              <el-col :span="24">
+                <el-form-item prop="proposal_company">
+                  <el-col :span="21" slot="label">
+                    建议单位名称:
+                  </el-col>
+                  <el-col :span="24">
+                    <el-input v-model="form.proposal_company" placeholder="请输入建议单位名称"></el-input>
+                  </el-col>
+                </el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item prop="proposal_user">
+                  <el-col :span="21" slot="label">
+                    联系人:
+                  </el-col>
+                  <el-col :span="24">
+                    <el-input v-model="form.proposal_user" placeholder="请输入联系人"></el-input>
+                  </el-col>
+                </el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item prop="proposal_phone">
+                  <el-col :span="21" slot="label">
+                    联系电话:
+                  </el-col>
+                  <el-col :span="24">
+                    <el-input v-model="form.proposal_phone" placeholder="请输入联系电话"></el-input>
+                  </el-col>
+                </el-form-item>
+              </el-col>
+            </el-col>
+          </el-col>
+          <el-col :span="24" class="one">
+            <el-col :span="24" class="txt">
+              <span>主要合作单位</span>
+            </el-col>
+            <el-col :span="24" class="info">
+              <el-col :span="24">
+                <el-form-item prop="coopera_company">
+                  <el-col :span="21" slot="label">
+                    合作单位名称:
+                  </el-col>
+                  <el-col :span="24">
+                    <el-input v-model="form.coopera_company" placeholder="请输入合作单位名称"></el-input>
+                  </el-col>
+                </el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item prop="coopera_user">
+                  <el-col :span="21" slot="label">
+                    联系人:
+                  </el-col>
+                  <el-col :span="24">
+                    <el-input v-model="form.coopera_user" placeholder="请输入联系人"></el-input>
+                  </el-col>
+                </el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item prop="coopera_phone">
+                  <el-col :span="21" slot="label">
+                    联系电话:
+                  </el-col>
+                  <el-col :span="24">
+                    <el-input v-model="form.coopera_phone" placeholder="请输入联系电话"></el-input>
+                  </el-col>
+                </el-form-item>
+              </el-col>
+            </el-col>
+          </el-col>
+          <el-col :span="24" class="one">
+            <el-col :span="24" class="txt">
+              <span>项目内容简介</span>
+            </el-col>
+            <el-col :span="24" class="info">
+              <el-col :span="24" class="langInfo">
+                <el-col :span="24" class="title">
+                  <span><sup style="color:#ff0000">*</sup>立项背景</span>(含解决“卡脖子”技术问题及在行业中所处的地位和作用):</el-col
+                >
+                <el-col :span="24" class="textarea">
+                  <el-form-item prop="sign">
+                    <el-input
+                      v-model="form.sign"
+                      type="textarea"
+                      maxlength="500"
+                      show-word-limit
+                      :autosize="{ minRows: 5, maxRows: 5 }"
+                      placeholder="请输入立项背景(含解决“卡脖子”技术问题及在行业中所处的地位和作用)"
+                    ></el-input>
+                  </el-form-item>
+                </el-col>
+              </el-col>
+              <el-col :span="24" class="langInfo">
+                <el-col :span="24" class="title">
+                  <span><sup style="color:#ff0000">*</sup>前期基础</span>(含知识产权状况):</el-col
+                >
+                <el-col :span="24" class="textarea">
+                  <el-form-item prop="work_basics">
+                    <el-input
+                      v-model="form.work_basics"
+                      type="textarea"
+                      maxlength="500"
+                      show-word-limit
+                      :autosize="{ minRows: 5, maxRows: 5 }"
+                      placeholder="请输入前期基础(含知识产权状况)"
+                    ></el-input>
+                  </el-form-item>
+                </el-col>
+              </el-col>
+              <el-col :span="24" class="langInfo">
+                <el-col :span="24" class="title">
+                  <span><sup style="color:#ff0000">*</sup>研究内容</span>(含项目创新点):</el-col
+                >
+                <el-col :span="24" class="textarea">
+                  <el-form-item prop="content">
+                    <el-input
+                      v-model="form.content"
+                      type="textarea"
+                      maxlength="500"
+                      show-word-limit
+                      :autosize="{ minRows: 5, maxRows: 5 }"
+                      placeholder="请输入研究内容(含项目创新点)"
+                    ></el-input>
+                  </el-form-item>
+                </el-col>
+              </el-col>
+              <el-col :span="24" class="langInfo">
+                <el-col :span="24" class="title">
+                  <span><sup style="color:#ff0000">*</sup>技术路线</span>(含拟解决关键技术):</el-col
+                >
+                <el-col :span="24" class="textarea">
+                  <el-form-item prop="route">
+                    <el-input
+                      v-model="form.route"
+                      type="textarea"
+                      maxlength="500"
+                      show-word-limit
+                      :autosize="{ minRows: 5, maxRows: 5 }"
+                      placeholder="请输入技术路线(含拟解决关键技术)"
+                    ></el-input>
+                  </el-form-item>
+                </el-col>
+              </el-col>
+              <el-col :span="24" class="langInfo">
+                <el-col :span="24" class="title">
+                  <span><sup style="color:#ff0000">*</sup>核心指标</span>(要求可量化、可考核、可检测):</el-col
+                >
+                <el-col :span="24" class="textarea">
+                  <el-form-item prop="quota">
+                    <el-input
+                      v-model="form.quota"
+                      type="textarea"
+                      maxlength="500"
+                      show-word-limit
+                      :autosize="{ minRows: 5, maxRows: 5 }"
+                      placeholder="请输入核心指标(要求可量化、可考核、可检测)"
+                    ></el-input>
+                  </el-form-item>
+                </el-col>
+              </el-col>
+              <el-col :span="24" class="langInfo">
+                <el-col :span="24" class="title">
+                  <span><sup style="color:#ff0000">*</sup>经济效益</span>(含市场分析和产业化预期):</el-col
+                >
+                <el-col :span="24" class="textarea">
+                  <el-form-item prop="influence">
+                    <el-input
+                      v-model="form.influence"
+                      type="textarea"
+                      maxlength="500"
+                      show-word-limit
+                      :autosize="{ minRows: 5, maxRows: 5 }"
+                      placeholder="请输入经济效益(含市场分析和产业化预期)"
+                    ></el-input>
+                  </el-form-item>
+                </el-col>
+              </el-col>
+            </el-col>
+          </el-col>
+          <el-col :span="24" class="btn">
+            <el-button type="danger" size="mini" @click="reset">取消</el-button>
+            <el-button type="primary" size="mini" @click="onSresert('form')">保存</el-button>
+            <el-button type="success" size="mini" @click="onSubmit('form')">提交</el-button>
+          </el-col>
+        </el-form>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'projectForm',
+  props: {
+    form: { type: Object },
+  },
+  components: {},
+  data: function() {
+    return {
+      rules: {
+        name: [{ required: true, message: '请输入项目名称', trigger: 'blur' }],
+        pro_user: [{ required: true, message: '请输入项目负责人', trigger: 'blur' }],
+        pro_phone: [{ required: true, message: '请输入联系电话', trigger: 'blur' }],
+        techol_stage: [{ required: true, message: '请输入技术阶段', trigger: 'change' }],
+        techol_level: [{ required: true, message: '请输入技术水平', trigger: 'change' }],
+        field: [{ required: true, message: '请输入领域分类', trigger: 'change' }],
+        scale: [{ required: true, message: '请输入市场预估', trigger: 'blur' }],
+        proposal_company: [{ required: true, message: '请输入建议单位名称', trigger: 'blur' }],
+        proposal_user: [{ required: true, message: '请输入联系人', trigger: 'blur' }],
+        proposal_phone: [{ required: true, message: '请输入联系电话', trigger: 'blur' }],
+        sign: [{ required: true, message: '请输入立项背景(含解决“卡脖子”技术问题及在行业中所处的地位和作用)', trigger: 'blur' }],
+        work_basics: [{ required: true, message: '请输入前期基础(含知识产权状况)', trigger: 'blur' }],
+        content: [{ required: true, message: '请输入研究内容(含项目创新点)', trigger: 'blur' }],
+        route: [{ required: true, message: '请输入技术路线(含拟解决关键技术)', trigger: 'blur' }],
+        quota: [{ required: true, message: '请输入核心指标(要求可量化、可考核、可检测)', trigger: 'blur' }],
+        influence: [{ required: true, message: '请输入经济效益(含市场分析和产业化预期)', trigger: 'blur' }],
+        // coopera_company: [{ required: false, message: '请输入合作单位名称', trigger: 'blur' }],
+        // coopera_user: [{ required: false, message: '请输入联系人', trigger: 'blur' }],
+        // coopera_phone: [{ required: false, message: '请输入联系电话', trigger: 'blur' }],
+      },
+      // 领域分类
+      fieldList: [{ name: '新材料' }, { name: '先进制造' }, { name: '光电子' }, { name: '新一代信息技术' }, { name: '先进技术' }],
+      techolstageList: [{ name: '理论研究' }, { name: '小试' }, { name: '中试' }, { name: '规模化试制' }, { name: '其他' }],
+      // 项目技术水平
+      techollevelList: [{ name: '国际领先' }, { name: '国际先进' }, { name: '国内领先' }, { name: '国内先进' }],
+    };
+  },
+  created() {},
+  methods: {
+    reset() {
+      this.$emit('reset');
+    },
+    onSresert(formName) {
+      this.$refs[formName].validate(valid => {
+        if (valid) {
+          let data = this.form;
+          data.status = '0';
+          this.$alert(
+            '<strong><p>1:用户</p><p>当您进行项目征集时,系统会自动提取项目负责人和联系电话进行平台用户注册,您可用【联系电话】和【初始密码(111111)】进行登录。</p><p>2:保存按钮</p><p>保存按钮,是您填写的信息处于草稿状态,您可到个人中心查看并进行修改与提交。</p></strong>',
+            '信息提示',
+            {
+              dangerouslyUseHTMLString: true,
+              showConfirmButton: true,
+              showCancelButton: true,
+              confirmButtonText: '确定',
+              cancelButtonText: '取消',
+            }
+          )
+            .then(() => {
+              this.$emit('onSubmit', { data });
+            })
+            .catch(() => {});
+        } else {
+          console.log('error submit!!');
+          return false;
+        }
+      });
+    },
+    onSubmit(formName) {
+      this.$refs[formName].validate(valid => {
+        if (valid) {
+          let data = this.form;
+          data.status = '1';
+          this.$alert(
+            '<strong><p>1:用户</p><p>当您进行项目征集时,系统会自动提取项目负责人和联系电话进行平台用户注册,您可用【联系电话】和【初始密码(111111)】进行登录。</p><p>2:保存按钮</p><p>保存按钮,是您填写的信息处于草稿状态,您可到个人中心查看并进行修改与提交。</p></strong>',
+            '信息提示',
+            {
+              dangerouslyUseHTMLString: true,
+              showConfirmButton: true,
+              showCancelButton: true,
+              confirmButtonText: '确定',
+              cancelButtonText: '取消',
+            }
+          )
+            .then(() => {
+              this.$emit('onSubmit', { data });
+            })
+            .catch(() => {});
+        } else {
+          console.log('error submit!!');
+          return false;
+        }
+      });
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  watch: {},
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  margin: 15px 0 0 0;
+  .one {
+    position: relative;
+    border: 1px solid #41719c;
+    margin: 0 0 35px 0;
+    min-height: 150px;
+    .txt {
+      position: absolute;
+      top: -22px;
+      text-align: center;
+      span {
+        height: 40px;
+        line-height: 40px;
+        display: inline-block;
+        padding: 0 35px;
+        background: #fff;
+        font-weight: bold;
+        font-size: 18px;
+      }
+    }
+    .info {
+      padding: 20px 10px 10px 10px;
+      /deep/.langSelect .el-select {
+        width: 100%;
+      }
+      .scale {
+        width: 18%;
+        margin: 0 5px;
+        /deep/.el-input__inner {
+          padding: 0 5px;
+        }
+      }
+      .langInfo {
+        margin: 0 0 10px 0;
+        .title {
+          font-size: 14px;
+          color: #606266;
+          padding: 10px 0;
+          span {
+            font-size: 18px;
+            font-weight: bold;
+          }
+        }
+        /deep/.el-form-item__content {
+          margin-left: 0px !important;
+        }
+      }
+    }
+  }
+  .btn {
+    text-align: center;
+    padding: 10px 0;
+  }
+}
+</style>

+ 95 - 0
src/views/twoweb/service/project/parts/questionInfo.vue

@@ -0,0 +1,95 @@
+<template>
+  <div id="questionInfo">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="title textOver">
+          {{ info.title }}
+        </el-col>
+        <el-col :span="24" class="other">
+          <span>发布时间:{{ getDate(info.create_date) || '暂无' }}</span>
+          <span>信息来源:{{ info.origin || '暂无' }}</span>
+        </el-col>
+        <el-col :span="24" class="image" v-if="info.img_path">
+          <el-image :src="info.img_path">
+            <div slot="error" class="image-slot">
+              <i class="el-icon-picture-outline"></i></div
+          ></el-image>
+        </el-col>
+        <el-col :span="24" class="content">
+          <p v-html="info.content"></p>
+        </el-col>
+        <el-col :span="24" class="link" v-if="info.file_path">
+          <el-link :href="info.file_path" :underline="false">附件:2022年度吉林省科技发展计划高新技术领域项目建议书编写提纲。</el-link>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+var moment = require('moment');
+export default {
+  name: 'questionInfo',
+  props: {
+    info: { type: Object },
+  },
+  components: {},
+  data: function() {
+    return {};
+  },
+  created() {},
+  methods: {
+    // 整理时间
+    getDate(date) {
+      let newsDate = moment(date).format('YYYY-MM-DD');
+      if (newsDate) return newsDate;
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  watch: {},
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  .title {
+    font-size: 25px;
+    padding: 15px 0;
+    text-align: center;
+    color: #005293;
+  }
+  .other {
+    text-align: center;
+    font-size: 18px;
+    margin: 0 0 15px 0;
+    span {
+      padding: 0 10px;
+    }
+  }
+  .image {
+    text-align: center;
+    height: 300px;
+    margin: 0 0 15px 0;
+    .el-image {
+      width: 50%;
+      height: 300px;
+      overflow: hidden;
+    }
+  }
+  .content {
+    margin: 0 0 15px 0;
+    p {
+      font-size: 18px;
+    }
+  }
+  .link {
+    margin: 0 0 15px 0;
+    .el-link {
+      font-size: 16px;
+    }
+  }
+}
+</style>

+ 227 - 0
src/views/twoweb/service/question/detail.vue

@@ -0,0 +1,227 @@
+<template>
+  <div id="detail">
+    <el-row>
+      <el-col :span="24" class="main">
+        <div class="w_1200">
+          <el-col :span="24" class="one">
+            <el-col :span="24" class="info">
+              <el-col :span="24" class="title">
+                {{ data.title }}
+              </el-col>
+              <el-col :span="24" class="brief">
+                {{ data.brief }}
+              </el-col>
+            </el-col>
+            <el-col :span="24" class="form">
+              <el-form :model="answer" label-position="top" ref="form">
+                <el-form-item v-if="!user || !user.id" label="您是否注册成为平台用户">
+                  <el-radio-group v-model="userForm.user">
+                    <el-radio :label="true">是</el-radio>
+                    <el-radio :label="false">否</el-radio>
+                  </el-radio-group>
+                </el-form-item>
+                <el-form-item v-if="userForm.user" label="手机号">
+                  <el-input v-model="userForm.phone" placeholder="请填写手机号"></el-input>
+                </el-form-item>
+                <!-- 0单选,1多选,2简答 -->
+                <template v-for="(i, index) in data.questions">
+                  <el-form-item
+                    v-if="i.type === '0'"
+                    :prop="`${index}`"
+                    :key="`question${index}`"
+                    :label="`${index + 1}.${i.title}`"
+                    :rules="[{ required: true, message: '请选择一个选项', trigger: 'blur' }]"
+                  >
+                    <el-radio-group v-model="answer[index]" :disabled="disabled">
+                      <el-radio v-for="(s, si) in i.selects" :key="`s_${index}_${si}`" :label="s.name">{{ s.num }}.{{ s.name }}</el-radio>
+                    </el-radio-group>
+                  </el-form-item>
+                  <el-form-item
+                    v-else-if="i.type === '1'"
+                    :prop="`${index}`"
+                    :key="`question${index}`"
+                    :label="`${index + 1}.${i.title}`"
+                    :rules="[{ required: true, message: '请至少选择一个选项', trigger: 'blur' }]"
+                  >
+                    <el-checkbox-group :value="answer[index]" @input="data => toCheck(data, index)" :disabled="disabled">
+                      <el-checkbox v-for="(s, si) in i.selects" :key="`c_${index}_${si}`" :label="s.name">{{ s.num }}.{{ s.name }}</el-checkbox>
+                    </el-checkbox-group>
+                  </el-form-item>
+                  <el-form-item v-else :key="`question${index}`" :label="`${index + 1}.${i.title}`">
+                    <el-input v-model="answer[index]" type="textarea" :autosize="{ minRows: 4, maxRows: 6 }" :readonly="disabled"></el-input>
+                  </el-form-item>
+                </template>
+              </el-form>
+            </el-col>
+            <el-col :span="24" style="text-align:center">
+              <el-button type="primary" @click="toSubmit" v-if="!disabled">提交</el-button>
+            </el-col>
+          </el-col>
+        </div>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: questionnaire } = createNamespacedHelpers('questionnaire');
+const { mapActions: answer } = createNamespacedHelpers('answer');
+const _ = require('lodash');
+export default {
+  name: 'detail',
+  props: {},
+  components: {},
+  data: function() {
+    return {
+      data: {},
+      answer: {},
+      disabled: false,
+      userForm: {},
+    };
+  },
+  async created() {
+    if (this.id) await this.search();
+    await this.init();
+  },
+  methods: {
+    ...questionnaire(['fetch']),
+    ...answer(['create', 'findAnswer']),
+    async search() {
+      let res = await this.fetch(this.id);
+      if (this.$checkRes(res)) {
+        this.$set(this, `data`, res.data);
+      }
+    },
+    async init() {
+      console.log('in function:');
+      const { questions } = this.data;
+      if (!(_.isArray(questions) && questions.length > 0)) return;
+      for (let i = 0; i < questions.length; i++) {
+        const e = questions[i];
+        const { type } = e;
+        if (type === '1') {
+          this.answer[i] = [];
+        }
+      }
+      this.getAnswer();
+    },
+    async getAnswer() {
+      if (!this.user || !this.user.id) return;
+      const res = await this.findAnswer({ user_id: this.user.id, questionnaire_id: this.id });
+      if (this.$checkRes(res)) {
+        if (res.data) {
+          this.disabled = true;
+          // 还原数据
+          const { answer } = res.data;
+          const questions = this.data.questions;
+          const reply = {};
+          for (const i of answer) {
+            const { answer: a, quest } = i;
+            const r = questions.findIndex(f => f.title === quest);
+            if (r > -1) reply[r] = a;
+          }
+          this.$set(this, 'answer', reply);
+        }
+      }
+    },
+    // 因为层级过深(只要不是在this下,就属于过深),所以需要手动更新视图
+    toCheck(data, model) {
+      this.answer[model] = data;
+      this.$forceUpdate();
+    },
+    async toSubmit() {
+      this.$refs.form.validate(valid => {
+        if (valid) {
+          this.submit();
+        } else {
+          console.log('error submit!!');
+          return false;
+        }
+      });
+    },
+    async submit() {
+      let dup = _.cloneDeep(this.answer);
+      const keys = Object.keys(dup);
+      const questions = this.data.questions;
+      const answer = [];
+      for (const i of keys) {
+        const a = dup[i];
+        const quest = questions[i];
+        if (a && quest) {
+          const obj = { answer: a, quest: quest.title };
+          answer.push(obj);
+        }
+      }
+      const data = {
+        questionnaire_id: this.id,
+        answer,
+      };
+      if (this.user && this.user.id) {
+        data.user_id = this.user.id;
+      } else {
+        const userForm = this.userForm;
+        if (userForm.user) data.phone = userForm.phone;
+      }
+      const res = await this.create(data);
+      if (this.$checkRes(res, '提交成功', '提交失败')) {
+        // 返回列表
+        // this.$router.push('/questionnaire/index');
+        // TODO返回
+        this.$router.push({ path: './list', query: { index: this.$route.query.index } });
+      }
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+    id() {
+      return this.$route.query.id;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  padding: 10px 0;
+  .one {
+    margin: 0 0 10px 0;
+    .info {
+      border-bottom: 1px dashed #ccc;
+      padding: 0 20px;
+      .title {
+        font-size: 30px;
+        font-weight: bold;
+        margin: 20px 0;
+        text-align: center;
+      }
+      .brief {
+        font-size: 16px;
+        padding: 0 0 20px 0;
+      }
+    }
+    .form {
+      padding: 20px 0;
+      /deep/.el-form-item {
+        margin-bottom: 5px;
+      }
+      /deep/.el-form-item__label {
+        padding: 0 0;
+        font-weight: bold;
+        color: #000;
+        font-size: 16px;
+      }
+    }
+  }
+}
+</style>

+ 136 - 0
src/views/twoweb/service/question/index.vue

@@ -0,0 +1,136 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main">
+        <div class="w_1200">
+          <el-col :span="24" class="one">
+            <el-col :span="24" class="list" v-for="(item, index) in list" :key="index">
+              <el-col :span="24" class="title">
+                {{ item.title }}
+                <el-button type="primary" size="mini" @click="btn(item)">答卷</el-button>
+              </el-col>
+              <el-col :span="24" class="other">
+                <el-col :span="24" class="otherInfo">
+                  发布时间:<span>{{ item.create_time || '暂无' }}</span>
+                </el-col>
+              </el-col>
+              <el-col :span="24" class="brief">
+                {{ item.brief }}
+              </el-col>
+            </el-col>
+          </el-col>
+          <el-col :span="24" class="two">
+            <el-pagination
+              @current-change="searchPage"
+              :current-page="currentPage"
+              layout="total, prev, pager, next, jumper"
+              :total="total"
+              :page-size="pageSize"
+            >
+            </el-pagination>
+          </el-col>
+        </div>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: questionnaire } = createNamespacedHelpers('questionnaire');
+export default {
+  name: 'index',
+  props: {},
+  components: {},
+  data: function() {
+    return {
+      list: [],
+      total: 0,
+      currentPage: 1,
+      pageSize: 5,
+    };
+  },
+  created() {
+    this.search();
+  },
+  methods: {
+    ...questionnaire(['query']),
+    async search({ skip = 0, limit = 5, ...info } = {}) {
+      let res = await this.query({ skip, limit, ...info });
+      if (this.$checkRes(res)) {
+        this.$set(this, `list`, res.data);
+        this.$set(this, `total`, res.total);
+      }
+    },
+    searchPage(page = 1) {
+      this.currentPage = page;
+      const skip = (this.currentPage - 1) * this.pageSize;
+      let condition = { skip, limit: this.pageSize };
+      this.search(condition);
+    },
+    // 答卷
+    btn(data) {
+      if (data.column == '定制问卷') {
+        this.$router.push({ path: '/twoweb/service/project', query: { id: data.id } });
+      } else {
+        this.$router.push({ path: '/twoweb/service/question/detail', query: { id: data.id } });
+      }
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  padding: 10px 0;
+  .one {
+    height: 600px;
+    overflow: hidden;
+    .list {
+      padding: 10px 0;
+      border-bottom: 1px dashed #ccc;
+      .title {
+        font-size: 16px;
+        font-weight: bold;
+        margin: 0 0 5px 0;
+      }
+      .other {
+        margin: 0 0 5px 0;
+        .otherInfo {
+          font-size: 14px;
+          color: #666;
+          span {
+            color: #000;
+          }
+        }
+      }
+      .brief {
+        overflow: hidden;
+        text-overflow: ellipsis;
+        -webkit-line-clamp: 2;
+        word-break: break-all;
+        display: -webkit-box;
+        -webkit-box-orient: vertical;
+        font-size: 14px;
+      }
+    }
+  }
+  .two {
+    text-align: center;
+    margin: 10px 0;
+  }
+}
+</style>

+ 147 - 0
src/views/twoweb/trainLive/index.vue

@@ -0,0 +1,147 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main">
+        <div class="w_1200">
+          <el-col :span="24" class="one">
+            <el-col :span="24" class="title">{{ info.title }} </el-col>
+            <el-col :span="24" class="other">
+              <span>主办方:{{ info.sponsor }}</span>
+              <span>办展城市:{{ info.province }}-{{ info.place }}</span>
+            </el-col>
+          </el-col>
+          <el-col :span="24" class="two">
+            <el-col :span="12" class="left">
+              <videoSwiper :liveInfo="info" :videoData="videoData"></videoSwiper>
+            </el-col>
+            <el-col :span="12" class="right">
+              <imgTxt :liveInfo="info"></imgTxt>
+            </el-col>
+          </el-col>
+        </div>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import videoSwiper from './parts/videoSwiper.vue';
+import imgTxt from './parts/imgTxt.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: mapTrainLive } = createNamespacedHelpers('trainLive');
+const { mapActions: place } = createNamespacedHelpers('place');
+export default {
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  name: 'index',
+  props: {},
+  components: { videoSwiper, imgTxt },
+  data: function() {
+    return {
+      info: {},
+      videoData: [],
+      times: 1800,
+    };
+  },
+  async created() {
+    await this.search();
+  },
+  methods: {
+    ...mapTrainLive(['fetch', 'sessionLonger']),
+    ...place({ queryName: 'queryName' }),
+    async search() {
+      let res = await this.fetch(this.id);
+      if (this.$checkRes(res)) {
+        this.searchPlace(res.data);
+        this.$set(this, `info`, res.data);
+        this.$set(this, `videoData`, res.data.video_data);
+      }
+    },
+    // 查询省市
+    async searchPlace(data) {
+      let nameData = { code: [data.province, data.place] };
+      let res = await this.queryName(nameData);
+      if (this.$checkRes(res)) {
+        data.province = res.data.find(i => i.code == data.province).name;
+        data.place = res.data.find(i => i.code == data.place).name;
+        return data;
+      }
+    },
+    setDate() {
+      this.timer = setInterval(async () => {
+        this.times--;
+        if (this.times === 0) {
+          let res = await this.sessionLonger({ id: this.user._id });
+          this.times = 1800;
+          clearInterval(this.timer);
+        }
+      }, 1000);
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+    id() {
+      return this.$route.query.id;
+    },
+  },
+  watch: {
+    times: {
+      handler(val) {
+        if (val == 1800) {
+          this.setDate();
+        }
+      },
+      immediate: true,
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  background: url('~@common/src/assets/2.jpg');
+  background-repeat: no-repeat;
+  background-size: 100% 100%;
+  height: 100vh;
+  .one {
+    text-align: center;
+    margin: 5% 0 0% 0;
+    .title {
+      font-size: 50px;
+      font-family: cursive;
+      font-weight: bolder;
+      -webkit-text-stroke: 1px #fff;
+      -webkit-text-fill-color: #191970;
+      letter-spacing: 3px;
+    }
+    .other {
+      color: #ffffff;
+      font-size: 25px;
+      font-family: cursive;
+      font-weight: bold;
+      padding: 5% 4%;
+      span {
+        padding: 0 10px;
+      }
+    }
+  }
+  .two {
+    .left {
+      width: 49%;
+      height: 550px;
+      margin: 0 15px 0 0;
+      border: 2px solid #409eff;
+      background: #ffffff5f;
+      border-radius: 5px;
+    }
+    .right {
+      width: 49%;
+      height: 550px;
+      border: 2px solid #409eff;
+      background: #ffffff5f;
+      border-radius: 5px;
+    }
+  }
+}
+</style>

+ 217 - 0
src/views/twoweb/trainLive/parts/chat.vue

@@ -0,0 +1,217 @@
+<template>
+  <div id="chat">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="list">
+          <el-col :span="24" class="chatlist" v-for="(i, index) in list" :key="index">
+            <span v-if="!isEmotion(i.content)">
+              <el-col :span="24" class="one">
+                [<span>{{ i.send_time | getTime }}</span
+                >]
+                <span>{{ i.sender_name }}</span>
+              </el-col>
+              <el-col :span="24" class="two">
+                <span> {{ i.content }}</span>
+              </el-col>
+            </span>
+            <span v-else>
+              <el-col :span="24" class="thr">
+                <span class="textOver">{{ i.sender_name }}</span>
+                <span>送出一朵/个</span>
+                <span v-html="i.content"></span>
+              </el-col>
+            </span>
+          </el-col>
+        </el-col>
+        <el-col :span="24" class="send">
+          <el-col :span="17" class="text">
+            <el-input v-model="text"></el-input>
+          </el-col>
+          <el-col :span="7" class="btn">
+            <el-popover placement="top" width="200" trigger="click">
+              <p>
+                <span class="kjfyList" v-for="(i, index) in kjfyList" :key="index" @click="changekjfy(i.name)">{{ i.name }}</span>
+              </p>
+              <el-button type="primary" size="mini" slot="reference">快捷发言</el-button>
+            </el-popover>
+            <el-button type="primary" size="mini" @click="send">发送</el-button>
+          </el-col>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: trainchat } = createNamespacedHelpers('trainchat');
+var moment = require('moment');
+import _ from 'lodash';
+export default {
+  name: 'chat',
+  props: {
+    liveInfo: { type: Object },
+  },
+  components: {},
+  data: function() {
+    return {
+      list: [],
+      text: '',
+      kjfyList: [{ name: '欢迎欢迎' }, { name: '科技创新' }, { name: '大咖云集' }],
+    };
+  },
+  async created() {
+    this.search();
+  },
+  async mounted() {
+    this.channel();
+  },
+  methods: {
+    ...trainchat(['query', 'create']),
+    async search() {
+      const res = await this.query({ skip: 0, unit_id: this.liveInfo.id });
+      if (this.$checkRes(res)) this.$set(this, `list`, res.data);
+    },
+    isEmotion(word) {
+      return word.startsWith('<img');
+    },
+    channel() {
+      this.$stomp({
+        [`/exchange/train_live/${this.liveInfo.id}`]: this.onMessage,
+      });
+    },
+    onMessage(message) {
+      let body = _.get(message, 'body');
+      if (body) {
+        body = JSON.parse(body);
+        this.list.push(body);
+        this.text = '';
+      }
+      this.search();
+    },
+    async send() {
+      if (this.text != '') {
+        let object = { sender_name: this.user.user_title, content: this.text, unit_id: this.liveInfo.id };
+        if (this.user._id) {
+          object.sender_id = this.user._id;
+        }
+        let res = await this.create(object);
+        this.text = '';
+        this.show = false;
+        this.$checkRes(res, null, res.errmsg || '发言失败');
+      } else this.$message.error('请输入信息后发送');
+    },
+    // 选择快捷发言
+    changekjfy(data) {
+      this.$set(this, `text`, data);
+      this.send();
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  filters: {
+    getTime(date) {
+      if (!date) return '很久以前';
+      let today = moment().format('YYYY-MM-DD');
+      let dd = moment(date).format('YYYY-MM-DD');
+      let time;
+      if (today == dd) time = moment(date).format('HH:mm');
+      else time = moment(date).format('YYYY-MM-DD');
+      return time;
+    },
+  },
+  watch: {},
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  .list {
+    height: 429px;
+    overflow-y: auto;
+    border: 1px solid red;
+    padding: 0 0 10px 0;
+    .chatlist {
+      padding: 0 10px;
+      .one {
+        padding: 10px 0;
+        span:nth-child(1) {
+          color: #ff0000;
+        }
+        span:nth-child(2) {
+          font-size: 16px;
+          color: #999;
+        }
+      }
+      .two {
+        min-height: 30px;
+        span {
+          font-size: 15px;
+          background: #f1f1f1;
+          padding: 5px;
+          border-radius: 5px;
+          min-width: 30%;
+          display: inline-block;
+        }
+      }
+      .thr {
+        text-align: center;
+        background: #f1f1f1;
+        border-radius: 25px;
+        width: 80%;
+        margin: 0 10%;
+        padding: 5px 0;
+        span:nth-child(1) {
+          color: #db7093;
+          font-weight: bold;
+          position: relative;
+          top: -3px;
+          font-size: 15px;
+          display: inline-block;
+          width: 45%;
+        }
+        span:nth-child(2) {
+          color: #000000;
+          position: relative;
+          top: -7px;
+          font-size: 15px;
+        }
+        span:nth-child(3) {
+          position: relative;
+          top: 2px;
+          left: 5px;
+        }
+      }
+    }
+  }
+  .send {
+    height: 40px;
+    border: 1px solid #000;
+    margin: 10px 0 0 0;
+    border-radius: 5px;
+    .text {
+      /deep/.el-input__inner {
+        height: 38px;
+        line-height: 38px;
+      }
+    }
+    .btn {
+      text-align: center;
+      padding: 5px 0;
+      .el-button {
+        margin: 0 0 0 5px;
+      }
+    }
+  }
+}
+.kjfyList {
+  display: inline-block;
+  margin: 0 10px 0 0;
+}
+.kjfyList:hover {
+  cursor: pointer;
+  color: #409eff;
+  font-weight: bold;
+}
+</style>

+ 46 - 0
src/views/twoweb/trainLive/parts/imgTxt.vue

@@ -0,0 +1,46 @@
+<template>
+  <div id="imgTxt">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-tabs class="tabs" type="border-card">
+          <el-tab-pane label="公共聊天"><chat :liveInfo="liveInfo"></chat></el-tab-pane>
+          <el-tab-pane label="展会信息"><message :liveInfo="liveInfo"></message></el-tab-pane>
+        </el-tabs>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import chat from './chat.vue';
+import message from './message.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'imgTxt',
+  props: {
+    liveInfo: { type: Object },
+  },
+  components: {
+    chat,
+    message,
+  },
+  data: function() {
+    return {};
+  },
+  created() {},
+  methods: {},
+  computed: {
+    ...mapState(['user']),
+  },
+  watch: {},
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  .tabs {
+    height: 548px;
+    overflow-y: auto;
+  }
+}
+</style>

+ 66 - 0
src/views/twoweb/trainLive/parts/message.vue

@@ -0,0 +1,66 @@
+<template>
+  <div id="message">
+    <el-row>
+      <el-col :span="24" class="main">
+        <p>
+          标题:<span>{{ liveInfo.title }}</span>
+        </p>
+        <p>
+          开始时间:<span>{{ liveInfo.start_date }}</span>
+        </p>
+        <p>
+          办展城市:<span>{{ liveInfo.province }}-{{ liveInfo.place }}</span>
+        </p>
+        <p>
+          主办方:<span>{{ liveInfo.sponsor }}</span>
+        </p>
+        <p>
+          负责人:<span>{{ liveInfo.user }}</span>
+        </p>
+        <p>
+          联系电话:<span>{{ liveInfo.phone }}</span>
+        </p>
+        <p>信息简介:{{ liveInfo.brief || '暂无' }}</p>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'message',
+  props: {
+    liveInfo: { type: Object },
+  },
+  components: {},
+  data: function() {
+    return {};
+  },
+  created() {},
+  methods: {},
+  computed: {
+    ...mapState(['user']),
+  },
+  watch: {},
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  p {
+    font-size: 18px;
+    padding: 10px 0;
+    border-bottom: 1px dashed #ccc;
+    color: #666;
+    span {
+      color: #000;
+    }
+  }
+  p:last-child {
+    border-bottom: none;
+    line-height: 10px;
+    line-height: 30px;
+  }
+}
+</style>

+ 158 - 0
src/views/twoweb/trainLive/parts/videoSwiper.vue

@@ -0,0 +1,158 @@
+<template>
+  <div id="videoSwiper">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one">
+          <el-col :span="4" class="txt">
+            <span style="color: rgb(255, 132, 0);">视频</span>
+            <span>直播</span>
+          </el-col>
+          <el-col :span="20" class="title textOver">
+            {{ liveInfo.title }}
+          </el-col>
+        </el-col>
+        <el-col :span="24" class="two">
+          <video :src="videoPath" controls autoplay loop v-if="videoData.length > 0" controlsList="nodownload">
+            <source src="movie.mp4" type="video/mp4" />
+            <source src="movie.ogg" type="video/ogg" />
+          </video>
+          <div class="videointro" v-else>
+            <p>{{ liveInfo.title }}</p>
+          </div>
+        </el-col>
+        <el-col :span="24" class="thr">
+          <swiper :list="videoData" :options="options">
+            <template v-slot="{ index, item }">
+              <p :class="`${menuIndex == index ? 'indexClass' : 'videodata'}`" @click="changeMenu(index, item)">{{ item.video_title }}</p>
+            </template>
+          </swiper>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+import swiper from '@c/frame/swiper-frame.vue';
+export default {
+  name: 'videoSwiper',
+  props: {
+    liveInfo: { type: Object },
+    videoData: { type: Array },
+  },
+  components: {
+    swiper,
+  },
+  data: function() {
+    return {
+      videoPath: '',
+      menuIndex: '0',
+      options: {
+        slidesPerView: 5,
+        spaceBetween: 10,
+        // 分页
+        navigation: {
+          nextEl: '.swiper-button-next',
+          prevEl: '.swiper-button-prev',
+        },
+      },
+    };
+  },
+  created() {},
+  methods: {
+    changeMenu(index, item) {
+      if (item) {
+        this.menuIndex = index;
+        this.$set(this, `videoPath`, item.video_url);
+      }
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+    id() {
+      return this.$route.query.id;
+    },
+  },
+  watch: {
+    videoData: {
+      immediate: true,
+      handler(val) {
+        this.changeMenu('0', this.videoData[0]);
+      },
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  .one {
+    height: 60px;
+    .txt {
+      height: 60px;
+      line-height: 40px;
+      font-size: 20px;
+      font-weight: 700;
+      text-align: center;
+    }
+    .title {
+      height: 60px;
+      line-height: 65px;
+      font-weight: bolder;
+      -webkit-text-stroke: 1px #191970;
+      -webkit-text-fill-color: #fff;
+      letter-spacing: 3px;
+      font-size: 20px;
+    }
+  }
+  .two {
+    height: 440px;
+    video {
+      width: 100%;
+      height: 440px;
+      background-color: #000;
+    }
+    .videointro {
+      height: 440px;
+      text-align: center;
+      background-image: url('~@common/src/assets/directBack.png');
+      background-size: 100% 100%;
+      background-repeat: no-repeat;
+      p {
+        text-align: center;
+        font-size: 30px;
+        padding: 60px 15px;
+        color: #fff;
+      }
+    }
+  }
+  .thr {
+    height: 50px;
+    .videodata {
+      border-radius: 10px;
+      background: #cccccc8f;
+      height: 39px;
+      line-height: 39px;
+      text-align: center;
+      margin: 2px 0 0 0;
+      font-weight: bold;
+    }
+    .videodata:hover {
+      cursor: pointer;
+      color: #fff;
+      background: #409eff;
+    }
+    .indexClass {
+      border-radius: 10px;
+      height: 39px;
+      line-height: 39px;
+      text-align: center;
+      margin: 2px 0 0 0;
+      font-weight: bold;
+      color: #fff;
+      background: #409eff;
+    }
+  }
+}
+</style>

+ 119 - 0
src/views/twoweb/universal/index.vue

@@ -0,0 +1,119 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main">
+        <div class="w_1200">
+          <el-col :span="24" class="one">
+            <el-col :span="12" class="left">
+              <venues :list="kydtList"></venues>
+            </el-col>
+            <el-col :span="12" class="right">
+              <experience :list="xsjlList"></experience>
+            </el-col>
+          </el-col>
+          <el-col :span="24" class="two">
+            <el-image :src="imgUrl"></el-image>
+          </el-col>
+          <el-col :span="24" class="one">
+            <el-col :span="12" class="left">
+              <read :list="ydhzList"></read>
+            </el-col>
+            <el-col :span="12" class="right">
+              <science :list="hyyjList"></science>
+            </el-col>
+          </el-col>
+        </div>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import venues from './index/venues.vue';
+import experience from './index/experience.vue';
+import read from './index/read.vue';
+import science from './index/science.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: column } = createNamespacedHelpers('column');
+const { mapActions: news } = createNamespacedHelpers('news');
+export default {
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  name: 'index',
+  props: {},
+  components: {
+    venues,
+    experience,
+    read,
+    science,
+  },
+  data: function() {
+    return {
+      imgUrl: require('@common/src/assets/center/kxpj.png'),
+      kydtList: [],
+      xsjlList: [],
+      ydhzList: [],
+      hyyjList: [],
+    };
+  },
+  async created() {
+    await this.search();
+  },
+  methods: {
+    ...column({ columnQuery: 'query' }),
+    ...news(['query']),
+    async search({ skip = 0, limit = 11, ...info } = {}) {
+      let res = await this.columnQuery();
+      if (this.$checkRes(res)) {
+        for (const val of res.data) {
+          let arr = await this.query({ skip, limit, column_id: val.id, ...info });
+          if (this.$checkRes(arr)) {
+            if (this[`${val.site}List`]) {
+              this.$set(this, `${val.site}List`, arr.data);
+            }
+          }
+        }
+      }
+      console.log(res);
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  watch: {},
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  background-image: linear-gradient(#ffffff, #a3d5f6, #ffffff);
+  min-height: 557px;
+  padding: 10px 0;
+  .one {
+    margin: 0 0 10px 0;
+    .left {
+      width: 49%;
+      min-height: 530px;
+      background: #ffffff;
+      padding: 15px;
+      border-radius: 20px;
+      margin: 0 24px 0 0;
+      box-shadow: 0 0 5px #409eff;
+    }
+    .right {
+      width: 49%;
+      min-height: 530px;
+      background: #ffffff;
+      border-radius: 20px;
+      padding: 15px;
+      box-shadow: 0 0 5px #409eff;
+    }
+  }
+  .two {
+    height: 140px;
+    overflow: hidden;
+    margin: 0 0 10px 0;
+  }
+}
+</style>

+ 97 - 0
src/views/twoweb/universal/index/experience.vue

@@ -0,0 +1,97 @@
+<template>
+  <div id="experience">
+    <el-row>
+      <el-col :span="24" class="style">
+        <el-col :span="24" class="top">
+          <top :topInfo="topInfo" @moreBtn="moreBtn"></top>
+        </el-col>
+        <el-col :span="24" class="down">
+          <el-col :span="24" class="list" v-for="(item, index) in list" :key="index" @click.native="toDetail(item._id)">
+            <el-col :span="24" class="name">
+              <el-col :span="20" class="title textOver">
+                {{ item.title }}
+              </el-col>
+              <el-col :span="4" class="date textOver">
+                {{ item.publish_time || '暂无' }}
+              </el-col>
+            </el-col>
+          </el-col>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import top from './top.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'experience',
+  props: {
+    list: { type: Array },
+  },
+  components: {
+    top,
+  },
+  data: function() {
+    return {
+      topInfo: {
+        title: '科普体验',
+        engTitle: 'experience',
+      },
+    };
+  },
+  created() {},
+  methods: {
+    // 查看更多
+    moreBtn() {
+      this.$router.push({ path: '/twoweb/universal/list', query: { index: 1 } });
+    },
+    toDetail(id) {
+      this.$router.push({ path: '/twoweb/universal/list', query: { index: 1, id: id } });
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  watch: {},
+};
+</script>
+
+<style lang="less" scoped>
+.style {
+  .top {
+    height: 50px;
+    overflow: hidden;
+  }
+  .down {
+    height: 450px;
+    overflow: hidden;
+    position: relative;
+    .list {
+      border-bottom: 1px dashed #ccc;
+      padding: 9px 0;
+      .name {
+        .title {
+          font-size: 16px;
+          font-weight: bold;
+        }
+        .date {
+          text-align: right;
+        }
+      }
+    }
+    .list:last-child {
+      border-bottom: none;
+    }
+    .list:hover {
+      cursor: pointer;
+      .name {
+        .title {
+          color: #409eff;
+        }
+      }
+    }
+  }
+}
+</style>

+ 97 - 0
src/views/twoweb/universal/index/read.vue

@@ -0,0 +1,97 @@
+<template>
+  <div id="read">
+    <el-row>
+      <el-col :span="24" class="style">
+        <el-col :span="24" class="top">
+          <top :topInfo="topInfo" @moreBtn="moreBtn"></top>
+        </el-col>
+        <el-col :span="24" class="down">
+          <el-col :span="24" class="list" v-for="(item, index) in list" :key="index" @click.native="toDetail(item._id)">
+            <el-col :span="24" class="name">
+              <el-col :span="20" class="title textOver">
+                {{ item.title }}
+              </el-col>
+              <el-col :span="4" class="date textOver">
+                {{ item.publish_time || '暂无' }}
+              </el-col>
+            </el-col>
+          </el-col>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import top from './top.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'read',
+  props: {
+    list: { type: Array },
+  },
+  components: {
+    top,
+  },
+  data: function() {
+    return {
+      topInfo: {
+        title: '科学解读',
+        engTitle: 'read',
+      },
+    };
+  },
+  created() {},
+  methods: {
+    // 查看更多
+    moreBtn() {
+      this.$router.push({ path: '/twoweb/universal/list', query: { index: 2 } });
+    },
+    toDetail(id) {
+      this.$router.push({ path: '/twoweb/universal/list', query: { index: 2, id: id } });
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  watch: {},
+};
+</script>
+
+<style lang="less" scoped>
+.style {
+  .top {
+    height: 50px;
+    overflow: hidden;
+  }
+  .down {
+    height: 450px;
+    overflow: hidden;
+    position: relative;
+    .list {
+      border-bottom: 1px dashed #ccc;
+      padding: 9px 0;
+      .name {
+        .title {
+          font-size: 16px;
+          font-weight: bold;
+        }
+        .date {
+          text-align: right;
+        }
+      }
+    }
+    .list:last-child {
+      border-bottom: none;
+    }
+    .list:hover {
+      cursor: pointer;
+      .name {
+        .title {
+          color: #409eff;
+        }
+      }
+    }
+  }
+}
+</style>

+ 97 - 0
src/views/twoweb/universal/index/science.vue

@@ -0,0 +1,97 @@
+<template>
+  <div id="science">
+    <el-row>
+      <el-col :span="24" class="style">
+        <el-col :span="24" class="top">
+          <top :topInfo="topInfo" @moreBtn="moreBtn"></top>
+        </el-col>
+        <el-col :span="24" class="down">
+          <el-col :span="24" class="list" v-for="(item, index) in list" :key="index" @click.native="toDetail(item._id)">
+            <el-col :span="24" class="name">
+              <el-col :span="20" class="title textOver">
+                {{ item.title }}
+              </el-col>
+              <el-col :span="4" class="date textOver">
+                {{ item.publish_time || '暂无' }}
+              </el-col>
+            </el-col>
+          </el-col>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import top from './top.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'science',
+  props: {
+    list: { type: Array },
+  },
+  components: {
+    top,
+  },
+  data: function() {
+    return {
+      topInfo: {
+        title: '黑科技',
+        engTitle: 'science',
+      },
+    };
+  },
+  created() {},
+  methods: {
+    // 查看更多
+    moreBtn() {
+      this.$router.push({ path: '/twoweb/universal/list', query: { index: 3 } });
+    },
+    toDetail(id) {
+      this.$router.push({ path: '/twoweb/universal/list', query: { index: 3, id: id } });
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  watch: {},
+};
+</script>
+
+<style lang="less" scoped>
+.style {
+  .top {
+    height: 50px;
+    overflow: hidden;
+  }
+  .down {
+    height: 450px;
+    overflow: hidden;
+    position: relative;
+    .list {
+      border-bottom: 1px dashed #ccc;
+      padding: 9px 0;
+      .name {
+        .title {
+          font-size: 16px;
+          font-weight: bold;
+        }
+        .date {
+          text-align: right;
+        }
+      }
+    }
+    .list:last-child {
+      border-bottom: none;
+    }
+    .list:hover {
+      cursor: pointer;
+      .name {
+        .title {
+          color: #409eff;
+        }
+      }
+    }
+  }
+}
+</style>

+ 77 - 0
src/views/twoweb/universal/index/top.vue

@@ -0,0 +1,77 @@
+<template>
+  <div id="topInfo">
+    <el-row>
+      <el-col :span="24" class="top">
+        <el-col :span="2" class="topImg">
+          <el-image :src="iconImage"></el-image>
+        </el-col>
+        <el-col :span="22" class="topTxt">
+          <span>{{ topInfo.title }}</span>
+          <span>{{ topInfo.engTitle }}</span>
+          <span @click="moreBtn">更多</span>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  name: 'topInfo',
+  props: {
+    topInfo: { typs: Object },
+  },
+  components: {},
+  data: function() {
+    return {
+      iconImage: require('@common/src/assets/square_big.png'),
+    };
+  },
+  created() {},
+  methods: {
+    moreBtn() {
+      this.$emit('moreBtn');
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  watch: {},
+};
+</script>
+
+<style lang="less" scoped>
+.top {
+  height: 50px;
+  .topTxt {
+    height: 45px;
+    border-bottom: 3px solid #044b79;
+    line-height: 45px;
+    padding: 0 5px;
+    span:nth-child(1) {
+      font-size: 24px;
+      font-weight: 700;
+    }
+    span:nth-child(2) {
+      padding: 0 10px;
+      text-transform: Capitalize;
+      font-size: 18px;
+      color: #92959a;
+      font-weight: 700;
+    }
+    span:nth-child(3) {
+      float: right;
+      font-size: 16px;
+      font-weight: bold;
+    }
+    span:nth-child(3):hover {
+      cursor: pointer;
+      color: #409eff;
+    }
+  }
+}
+</style>

+ 97 - 0
src/views/twoweb/universal/index/venues.vue

@@ -0,0 +1,97 @@
+<template>
+  <div id="venues">
+    <el-row>
+      <el-col :span="24" class="style">
+        <el-col :span="24" class="top">
+          <top :topInfo="topInfo" @moreBtn="moreBtn"></top>
+        </el-col>
+        <el-col :span="24" class="down">
+          <el-col :span="24" class="list" v-for="(item, index) in list" :key="index" @click.native="toDetail(item._id)">
+            <el-col :span="24" class="name">
+              <el-col :span="20" class="title textOver">
+                {{ item.title }}
+              </el-col>
+              <el-col :span="4" class="date textOver">
+                {{ item.publish_time || '暂无' }}
+              </el-col>
+            </el-col>
+          </el-col>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import top from './top.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'venues',
+  props: {
+    list: { type: Array },
+  },
+  components: {
+    top,
+  },
+  data: function() {
+    return {
+      topInfo: {
+        title: '科普场馆',
+        engTitle: 'venues',
+      },
+    };
+  },
+  created() {},
+  methods: {
+    // 查看更多
+    moreBtn() {
+      this.$router.push({ path: '/twoweb/universal/list', query: { index: 0 } });
+    },
+    toDetail(id) {
+      this.$router.push({ path: '/twoweb/universal/list', query: { index: 0, id: id } });
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  watch: {},
+};
+</script>
+
+<style lang="less" scoped>
+.style {
+  .top {
+    height: 50px;
+    overflow: hidden;
+  }
+  .down {
+    height: 450px;
+    overflow: hidden;
+    position: relative;
+    .list {
+      border-bottom: 1px dashed #ccc;
+      padding: 9px 0;
+      .name {
+        .title {
+          font-size: 16px;
+          font-weight: bold;
+        }
+        .date {
+          text-align: right;
+        }
+      }
+    }
+    .list:last-child {
+      border-bottom: none;
+    }
+    .list:hover {
+      cursor: pointer;
+      .name {
+        .title {
+          color: #409eff;
+        }
+      }
+    }
+  }
+}
+</style>

+ 122 - 0
src/views/twoweb/universal/list.vue

@@ -0,0 +1,122 @@
+<template>
+  <div id="list">
+    <el-row>
+      <el-col :span="24" class="main">
+        <div class="w_1200">
+          <el-col :span="5" class="menu">
+            <el-image :src="squareImage"></el-image>
+            <span class="menuTitle">Menu</span>
+            <el-col :span="24" class="menuList" v-for="(item, index) in menuList" :key="index">
+              <p @click="changeMenu(item.component, index)" :style="`color:${menuIndex == index ? menuColor : ''}`">{{ item.name }}</p>
+            </el-col>
+          </el-col>
+          <el-col :span="19" class="listInfo">
+            <component :is="component" v-bind="params"></component>
+          </el-col>
+        </div>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+const _ = require('lodash');
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'list',
+  props: {},
+  components: {
+    venues: () => import('./list/venues.vue'),
+    experience: () => import('./list/experience.vue'),
+    read: () => import('./list/read.vue'),
+    science: () => import('./list/science.vue'),
+  },
+  data: function() {
+    return {
+      component: '',
+      menuList: [
+        { name: '科普场馆', component: 'venues', options: { useTab: true, listModel: 0 } },
+        { name: '科普体验', component: 'experience', options: { useTab: false, listModel: 1 } },
+        { name: '科学解读', component: 'read', options: { useTab: false, listModel: 2 } },
+        { name: '黑科技', component: 'science', options: { useTab: true, listModel: 3 } },
+      ],
+      squareImage: require('@p/live/square_big.png'),
+      column_name: '',
+      params: {},
+      menuColor: 'rgb(254, 149, 14)',
+    };
+  },
+  created() {},
+  methods: {
+    changeMenu(component, index) {
+      if (index !== this.menuIndex) this.$router.push({ path: './list', query: { index } });
+      this.component = component;
+    },
+  },
+  computed: {
+    ...mapState(['user', 'menuParams']),
+    pageTitle() {
+      return `${this.$route.meta.title}`;
+    },
+    menuIndex() {
+      const index = this.$route.query.index || 0;
+      const obj = this.menuList[index];
+      const params = {
+        title: _.get(obj, 'name'),
+        ..._.get(obj, 'options'),
+      };
+      this.$set(this, 'component', _.get(obj, 'component', 'venues'));
+      this.$set(this, 'params', params);
+      return index;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  min-height: 500px;
+  padding: 10px 0;
+  .menu {
+    height: 600px;
+    overflow: hidden;
+    padding: 15px 10px;
+    background: no-repeat 100% 100%;
+    background-image: url('~@p/live/menu_back.jpg');
+    box-sizing: border-box;
+    box-shadow: 0 0 10px #bbbaba;
+    .menuTitle {
+      font-size: 24px;
+      color: #92959a;
+      font-weight: bold;
+      position: relative;
+      top: -10px;
+      left: 10px;
+    }
+    .menuList {
+      height: 60px;
+      line-height: 60px;
+      border-bottom: 1px solid #2d64b3;
+      p {
+        font-weight: bold;
+        font-size: 18px;
+        color: #044b79;
+      }
+    }
+    .menuList:hover {
+      cursor: pointer;
+    }
+  }
+  .listInfo {
+    float: right;
+    width: 78%;
+    min-height: 600px;
+    overflow: hidden;
+    box-shadow: 0 0 10px #2d64b3;
+    padding: 10px;
+  }
+}
+</style>

+ 112 - 0
src/views/twoweb/universal/list/detail-model/news-model.vue

@@ -0,0 +1,112 @@
+<template>
+  <div id="news-model">
+    <el-row type="flex" justify="end">
+      <el-col :span="2">
+        <slot></slot>
+      </el-col>
+    </el-row>
+    <el-row>
+      <el-col :span="24" class="detail">
+        <el-col :span="24" class="one">
+          <p>{{ data.title }}</p>
+          <p>
+            <span>信息来源:{{ data.origin || '暂无' }}</span>
+            <span>发布时间:{{ data.publish_time || '暂无' }}</span>
+          </p>
+        </el-col>
+        <el-col :span="24" class="two" v-if="data.picture != null || undefined">
+          <el-image :src="data.picture"></el-image>
+        </el-col>
+        <el-col :span="24" class="three">
+          <p v-html="data.content"></p>
+        </el-col>
+        <el-col :span="24" class="four" v-if="data.filepath">
+          <h4>附件:</h4>
+          <el-link :href="data.filepath" :underline="false">{{ data.filepathname || '附件下载' }}</el-link>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'news-model',
+  props: {
+    data: { type: Object, default: () => {} },
+  },
+  components: {},
+  data: function() {
+    return {};
+  },
+  created() {},
+  methods: {},
+  computed: {
+    ...mapState(['user', 'menuParams']),
+    pageTitle() {
+      return `${this.$route.meta.title}`;
+    },
+  },
+  metadata() {
+    return { title: this.$route.meta.title };
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.detail {
+  .one {
+    border-bottom: 1px dashed #ccc;
+    margin: 0 0 15px 0;
+    p:nth-child(1) {
+      font-size: 20px;
+      font-weight: bold;
+      color: #044b79;
+      padding: 25px 0;
+      text-align: center;
+    }
+    p:nth-child(2) {
+      padding: 0 0 20px 0;
+      span {
+        display: inline-block;
+        width: 46%;
+        font-size: 16px;
+        color: #666;
+        padding: 0 15px;
+      }
+      span:nth-child(1) {
+        text-align: right;
+      }
+    }
+  }
+  .two {
+    text-align: center;
+    margin: 0 0 15px 0;
+    .el-image {
+      width: 60%;
+    }
+  }
+  .three {
+    margin: 0 0 15px 0;
+    /deep/p {
+      font-size: 16px;
+      font-family: 微软雅黑;
+      color: #444;
+      // img {
+      //   padding: 10px 140px !important;
+      // }
+    }
+  }
+  .four {
+    h4 {
+      color: #400eff;
+      font-weight: bold;
+      margin: 0;
+    }
+    .el-link {
+      padding: 10px 0 0 10px;
+    }
+  }
+}
+</style>

+ 106 - 0
src/views/twoweb/universal/list/experience.vue

@@ -0,0 +1,106 @@
+<template>
+  <div id="dynamic">
+    <list-page v-bind="$attrs" :total="total" v-if="!id" @toSearch="search" :pageSize="pageSize" :useTab="false" searchModel="title">
+      <component :is="model" :list="list"></component>
+    </list-page>
+    <template v-else>
+      <dmodel :displayBtn="true" :data="detail" v-if="detail">
+        <el-button size="mini" type="primary" @click="$router.push({ path: './list', query: { index: $route.query.index } })"> 返回</el-button>
+      </dmodel>
+    </template>
+  </div>
+</template>
+
+<script>
+import listPage from '@c/list/list-page.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: column } = createNamespacedHelpers('column');
+const { mapActions: news } = createNamespacedHelpers('news');
+export default {
+  name: 'dynamic',
+  props: ['listModel'],
+  components: {
+    listPage,
+    model1: () => import('@c/list/list-model/model-6.vue'),
+    dmodel: () => import('./detail-model/news-model.vue'),
+  },
+  data: function() {
+    return {
+      list: [],
+      total: 0,
+      detail: {},
+      // 栏目信息
+      column: {},
+      pageSize: 10,
+    };
+  },
+  async created() {
+    await this.searchOther();
+    await this.search();
+  },
+  methods: {
+    ...column({ columnQuery: 'query' }),
+    ...news(['query', 'fetch']),
+    async search({ skip = 0, limit = this.pageSize, ...info } = {}) {
+      // TODO: 查询
+      let res = await this.query({ skip, limit, column_id: this.column.id, ...info });
+      if (this.$checkRes(res)) {
+        this.$set(this, `list`, res.data);
+        this.$set(this, `total`, res.total);
+        // 最后结果处理方式,将显示的信息转换成固定的字段去显示
+        this.$set(this, 'list', this.translate(this.list));
+      }
+    },
+    translate(data) {
+      const list = data.map(i => {
+        const obj = { id: i.id || i._id };
+        obj.p1 = _.get(i, 'title');
+        obj.p2 = _.get(i, 'publish_time');
+        return obj;
+      });
+      return list;
+    },
+    // 查询详情
+    async searchInfo() {
+      let res = await this.fetch(this.id);
+      if (this.$checkRes(res)) {
+        this.$set(this, `detail`, res.data);
+      }
+    },
+    // 查询其他
+    async searchOther() {
+      let res = await this.columnQuery();
+      if (this.$checkRes(res)) {
+        let column = res.data.find(i => i.site == 'xsjl');
+        if (column) this.$set(this, `column`, column);
+      }
+    },
+  },
+  computed: {
+    ...mapState(['user', 'menuParams']),
+    pageTitle() {
+      return `${this.$route.meta.title}`;
+    },
+    model() {
+      const moduleNumber = this.listModel || 0;
+      return `model${moduleNumber}`;
+    },
+    id() {
+      return this.$route.query.id;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    id: {
+      handler(ne) {
+        if (ne) this.searchInfo();
+      },
+      immediate: true,
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 106 - 0
src/views/twoweb/universal/list/read.vue

@@ -0,0 +1,106 @@
+<template>
+  <div id="cooperation">
+    <list-page v-bind="$attrs" :total="total" v-if="!id" @toSearch="search" :pageSize="pageSize" :useTab="false" searchModel="title">
+      <component :is="model" :list="list"></component>
+    </list-page>
+    <template v-else>
+      <dmodel :displayBtn="true" :data="detail" v-if="detail">
+        <el-button size="mini" type="primary" @click="$router.push({ path: './list', query: { index: $route.query.index } })"> 返回</el-button>
+      </dmodel>
+    </template>
+  </div>
+</template>
+
+<script>
+import listPage from '@c/list/list-page.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: column } = createNamespacedHelpers('column');
+const { mapActions: news } = createNamespacedHelpers('news');
+export default {
+  name: 'cooperation',
+  props: ['listModel'],
+  components: {
+    listPage,
+    model2: () => import('@c/list/list-model/model-6.vue'),
+    dmodel: () => import('./detail-model/news-model.vue'),
+  },
+  data: function() {
+    return {
+      list: [],
+      total: 0,
+      detail: {},
+      // 栏目信息
+      column: {},
+      pageSize: 10,
+    };
+  },
+  async created() {
+    await this.searchOther();
+    await this.search();
+  },
+  methods: {
+    ...column({ columnQuery: 'query' }),
+    ...news(['query', 'fetch']),
+    async search({ skip = 0, limit = this.pageSize, ...info } = {}) {
+      // TODO: 查询
+      let res = await this.query({ skip, limit, column_id: this.column.id, ...info });
+      if (this.$checkRes(res)) {
+        this.$set(this, `list`, res.data);
+        this.$set(this, `total`, res.total);
+        // 最后结果处理方式,将显示的信息转换成固定的字段去显示
+        this.$set(this, 'list', this.translate(this.list));
+      }
+    },
+    translate(data) {
+      const list = data.map(i => {
+        const obj = { id: i.id || i._id };
+        obj.p1 = _.get(i, 'title');
+        obj.p2 = _.get(i, 'publish_time');
+        return obj;
+      });
+      return list;
+    },
+    // 查询详情
+    async searchInfo() {
+      let res = await this.fetch(this.id);
+      if (this.$checkRes(res)) {
+        this.$set(this, `detail`, res.data);
+      }
+    },
+    // 查询其他
+    async searchOther() {
+      let res = await this.columnQuery();
+      if (this.$checkRes(res)) {
+        let column = res.data.find(i => i.site == 'ydhz');
+        if (column) this.$set(this, `column`, column);
+      }
+    },
+  },
+  computed: {
+    ...mapState(['user', 'menuParams']),
+    pageTitle() {
+      return `${this.$route.meta.title}`;
+    },
+    model() {
+      const moduleNumber = this.listModel || 0;
+      return `model${moduleNumber}`;
+    },
+    id() {
+      return this.$route.query.id;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    id: {
+      handler(ne) {
+        if (ne) this.searchInfo();
+      },
+      immediate: true,
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 106 - 0
src/views/twoweb/universal/list/science.vue

@@ -0,0 +1,106 @@
+<template>
+  <div id="industry">
+    <list-page v-bind="$attrs" :total="total" v-if="!id" @toSearch="search" :pageSize="pageSize" :useTab="false" searchModel="title">
+      <component :is="model" :list="list"></component>
+    </list-page>
+    <template v-else>
+      <dmodel :displayBtn="true" :data="detail" v-if="detail">
+        <el-button size="mini" type="primary" @click="$router.push({ path: './list', query: { index: $route.query.index } })"> 返回</el-button>
+      </dmodel>
+    </template>
+  </div>
+</template>
+
+<script>
+import listPage from '@c/list/list-page.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: column } = createNamespacedHelpers('column');
+const { mapActions: news } = createNamespacedHelpers('news');
+export default {
+  name: 'industry',
+  props: ['listModel'],
+  components: {
+    listPage,
+    model3: () => import('@c/list/list-model/model-6.vue'),
+    dmodel: () => import('./detail-model/news-model.vue'),
+  },
+  data: function() {
+    return {
+      list: [],
+      total: 0,
+      detail: {},
+      // 栏目信息
+      column: {},
+      pageSize: 10,
+    };
+  },
+  async created() {
+    await this.searchOther();
+    await this.search();
+  },
+  methods: {
+    ...column({ columnQuery: 'query' }),
+    ...news(['query', 'fetch']),
+    async search({ skip = 0, limit = this.pageSize, ...info } = {}) {
+      // TODO: 查询
+      let res = await this.query({ skip, limit, column_id: this.column.id, ...info });
+      if (this.$checkRes(res)) {
+        this.$set(this, `list`, res.data);
+        this.$set(this, `total`, res.total);
+        // 最后结果处理方式,将显示的信息转换成固定的字段去显示
+        this.$set(this, 'list', this.translate(this.list));
+      }
+    },
+    translate(data) {
+      const list = data.map(i => {
+        const obj = { id: i.id || i._id };
+        obj.p1 = _.get(i, 'title');
+        obj.p2 = _.get(i, 'publish_time');
+        return obj;
+      });
+      return list;
+    },
+    // 查询详情
+    async searchInfo() {
+      let res = await this.fetch(this.id);
+      if (this.$checkRes(res)) {
+        this.$set(this, `detail`, res.data);
+      }
+    },
+    // 查询其他
+    async searchOther() {
+      let res = await this.columnQuery();
+      if (this.$checkRes(res)) {
+        let column = res.data.find(i => i.site == 'hyyj');
+        if (column) this.$set(this, `column`, column);
+      }
+    },
+  },
+  computed: {
+    ...mapState(['user', 'menuParams']),
+    pageTitle() {
+      return `${this.$route.meta.title}`;
+    },
+    model() {
+      const moduleNumber = this.listModel || 0;
+      return `model${moduleNumber}`;
+    },
+    id() {
+      return this.$route.query.id;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    id: {
+      handler(ne) {
+        if (ne) this.searchInfo();
+      },
+      immediate: true,
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 106 - 0
src/views/twoweb/universal/list/venues.vue

@@ -0,0 +1,106 @@
+<template>
+  <div id="dynamic">
+    <list-page v-bind="$attrs" :total="total" v-if="!id" @toSearch="search" :pageSize="pageSize" :useTab="false" searchModel="title">
+      <component :is="model" :list="list"></component>
+    </list-page>
+    <template v-else>
+      <dmodel :displayBtn="true" :data="detail" v-if="detail">
+        <el-button size="mini" type="primary" @click="$router.push({ path: './list', query: { index: $route.query.index } })"> 返回</el-button>
+      </dmodel>
+    </template>
+  </div>
+</template>
+
+<script>
+import listPage from '@c/list/list-page.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: column } = createNamespacedHelpers('column');
+const { mapActions: news } = createNamespacedHelpers('news');
+export default {
+  name: 'dynamic',
+  props: ['listModel'],
+  components: {
+    listPage,
+    model0: () => import('@c/list/list-model/model-6.vue'),
+    dmodel: () => import('./detail-model/news-model.vue'),
+  },
+  data: function() {
+    return {
+      list: [],
+      total: 0,
+      detail: {},
+      // 栏目信息
+      column: {},
+      pageSize: 10,
+    };
+  },
+  async created() {
+    await this.searchOther();
+    await this.search();
+  },
+  methods: {
+    ...column({ columnQuery: 'query' }),
+    ...news(['query', 'fetch']),
+    async search({ skip = 0, limit = this.pageSize, ...info } = {}) {
+      // TODO: 查询
+      let res = await this.query({ skip, limit, column_id: this.column.id, ...info });
+      if (this.$checkRes(res)) {
+        this.$set(this, `list`, res.data);
+        this.$set(this, `total`, res.total);
+        // 最后结果处理方式,将显示的信息转换成固定的字段去显示
+        this.$set(this, 'list', this.translate(this.list));
+      }
+    },
+    translate(data) {
+      const list = data.map(i => {
+        const obj = { id: i.id || i._id };
+        obj.p1 = _.get(i, 'title');
+        obj.p2 = _.get(i, 'publish_time');
+        return obj;
+      });
+      return list;
+    },
+    // 查询详情
+    async searchInfo() {
+      let res = await this.fetch(this.id);
+      if (this.$checkRes(res)) {
+        this.$set(this, `detail`, res.data);
+      }
+    },
+    // 查询其他
+    async searchOther() {
+      let res = await this.columnQuery();
+      if (this.$checkRes(res)) {
+        let column = res.data.find(i => i.site == 'kydt');
+        if (column) this.$set(this, `column`, column);
+      }
+    },
+  },
+  computed: {
+    ...mapState(['user', 'menuParams']),
+    pageTitle() {
+      return `${this.$route.meta.title}`;
+    },
+    model() {
+      const moduleNumber = this.listModel || 0;
+      return `model${moduleNumber}`;
+    },
+    id() {
+      return this.$route.query.id;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    id: {
+      handler(ne) {
+        if (ne) this.searchInfo();
+      },
+      immediate: true,
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 1 - 1
vue.config.js

@@ -38,7 +38,7 @@ module.exports = {
         ws: false,
       },
       '/api': {
-        target: 'http://192.168.1.19:9101', //http://192.168.1.19:9101
+        target: 'http://broadcast.waityou24.cn', //http://192.168.1.19:9101
         changeOrigin: true,
         ws: false,
       },