Просмотр исходного кода

百岗MES看板调整:增加项目阶段

xiaost 3 месяцев назад
Родитель
Сommit
884b53f79f

+ 135 - 0
src/assets/scss/indexprjphase.scss

@@ -0,0 +1,135 @@
+#index {
+  color: #d3d6dd;
+  width: 1920px;
+  height: 1080px;
+  position: absolute;
+  top: 50%;
+  left: 50%;
+  transform: translate(-50%, -50%);
+  transform-origin: left top;
+  overflow: hidden;
+
+  .bg {
+    width: 100%;
+    height: 100%;
+    padding: 16px 16px 0 16px;
+    background-image: url("../../assets/pageBg.png");
+    background-size: cover;
+    background-position: center center;
+  }
+
+  .host-body {
+    .dv-dec-10,
+    .dv-dec-10-s {
+      width: 33.3%;
+      height: 5px;
+    }
+    .dv-dec-10-s {
+      transform: rotateY(180deg);
+    }
+    .dv-dec-8 {
+      width: 200px;
+      height: 50px;
+    }
+    .title {
+      position: relative;
+      width: 500px;
+      text-align: center;
+      background-size: cover;
+      background-repeat: no-repeat;
+
+      .title-text {
+        font-size: 26px;
+        position: absolute;
+        bottom: 0;
+        left: 50%;
+        transform: translate(-50%);
+      }
+
+      .dv-dec-6 {
+        position: absolute;
+        bottom: -30px;
+        left: 50%;
+        width: 250px;
+        height: 8px;
+        transform: translate(-50%);
+      }
+    }
+
+    // 第二行
+    .aside-width {
+      width: 40%;
+    }
+    .react-r-s,
+    .react-l-s {
+      background-color: #1a5cd7;
+    }
+
+    // 平行四边形
+    .react-right {
+      &.react-l-s {
+        text-align: right;
+        width: 500px;
+      }
+      font-size: 18px;
+      width: 300px;
+      line-height: 50px;
+      text-align: center;
+      transform: skewX(-45deg);
+
+      .react-after {
+        position: absolute;
+        right: -25px;
+        top: 0;
+        height: 50px;
+        width: 50px;
+        background-color: #1a5cd7;
+        transform: skewX(45deg);
+      }
+
+      .text {
+        display: inline-block;
+        transform: skewX(45deg);
+      }
+    }
+
+    .react-left {
+      &.react-l-s {
+        width: 500px;
+        text-align: left;
+      }
+      font-size: 20px;
+      width: 300px;
+      height: 50px;
+      line-height: 50px;
+      text-align: center;
+      transform: skewX(45deg);
+      background-color: #0f1325;
+
+      .react-left {
+        position: absolute;
+        left: -25px;
+        top: 0;
+        height: 50px;
+        width: 50px;
+        background-color: #1a5cd7;
+        transform: skewX(-45deg);
+      }
+
+      .text {
+        display: inline-block;
+        transform: skewX(-45deg);
+      }
+    }
+
+    .body-box {
+      margin-top: 1px;
+      display: flex;
+      flex-direction: column;
+      .content-box {
+        display: grid;
+        grid-template-columns: 1fr;
+      }
+    }
+  }
+}

+ 8 - 0
src/router/index.js

@@ -82,6 +82,14 @@ const routes = [{
     title: "制线",
     requireAuth: true // 标识该路由是否需要登录
   }
+},{
+  path: '/PRJPHASE',
+  name: 'PRJPHASE',
+  component: () => import('../views/./PRJPHASE/index.vue'),
+  meta: {
+    title: "项目阶段 ",
+    requireAuth: true // 标识该路由是否需要登录
+  }
 }]
 const router = new VueRouter({
   routes

+ 1 - 0
src/views/DIP/index.vue

@@ -52,6 +52,7 @@
                   <el-dropdown-item class="dropdownitem"><router-link to="SMT">SMT</router-link></el-dropdown-item>
                   <el-dropdown-item class="dropdownitem"><router-link to="ZZ">组装</router-link></el-dropdown-item>
                   <el-dropdown-item class="dropdownitem"><router-link to="WIRE">制线</router-link></el-dropdown-item>
+                  <el-dropdown-item class="dropdownitem"><router-link to="PRJPHASE">项目阶段</router-link></el-dropdown-item>
                 </el-dropdown-menu>
               </el-dropdown>
               <span class="text">&nbsp;&nbsp;&nbsp;&nbsp;</span>

+ 1 - 0
src/views/FQC/index.vue

@@ -52,6 +52,7 @@
                   <el-dropdown-item class="dropdownitem"><router-link to="DIP">插件</router-link></el-dropdown-item>
                   <el-dropdown-item class="dropdownitem"><router-link to="ZZ">组装</router-link></el-dropdown-item>
                   <el-dropdown-item class="dropdownitem"><router-link to="WIRE">制线</router-link></el-dropdown-item>
+                  <el-dropdown-item class="dropdownitem"><router-link to="PRJPHASE">项目阶段</router-link></el-dropdown-item>
                 </el-dropdown-menu>
               </el-dropdown>
               <span class="text">&nbsp;&nbsp;&nbsp;&nbsp;</span>

+ 1 - 0
src/views/IQC/index.vue

@@ -52,6 +52,7 @@
                   <el-dropdown-item class="dropdownitem"><router-link to="DIP">插件</router-link></el-dropdown-item>
                   <el-dropdown-item class="dropdownitem"><router-link to="ZZ">组装</router-link></el-dropdown-item>
                   <el-dropdown-item class="dropdownitem"><router-link to="WIRE">制线</router-link></el-dropdown-item>
+                  <el-dropdown-item class="dropdownitem"><router-link to="PRJPHASE">项目阶段</router-link></el-dropdown-item>
                 </el-dropdown-menu>
               </el-dropdown>
               <span class="text">&nbsp;&nbsp;&nbsp;&nbsp;</span>

+ 1 - 0
src/views/LAB/index.vue

@@ -52,6 +52,7 @@
                   <el-dropdown-item class="dropdownitem"><router-link to="DIP">插件</router-link></el-dropdown-item>
                   <el-dropdown-item class="dropdownitem"><router-link to="ZZ">组装</router-link></el-dropdown-item>
                   <el-dropdown-item class="dropdownitem"><router-link to="WIRE">制线</router-link></el-dropdown-item>
+                  <el-dropdown-item class="dropdownitem"><router-link to="PRJPHASE">项目阶段</router-link></el-dropdown-item>
                 </el-dropdown-menu>
               </el-dropdown>
               <span class="text">&nbsp;&nbsp;&nbsp;&nbsp;</span>

+ 1 - 0
src/views/PRJ/index.vue

@@ -52,6 +52,7 @@
                   <el-dropdown-item class="dropdownitem"><router-link to="DIP">插件</router-link></el-dropdown-item>
                   <el-dropdown-item class="dropdownitem"><router-link to="ZZ">组装</router-link></el-dropdown-item>
                   <el-dropdown-item class="dropdownitem"><router-link to="WIRE">制线</router-link></el-dropdown-item>
+                  <el-dropdown-item class="dropdownitem"><router-link to="PRJPHASE">项目阶段</router-link></el-dropdown-item>
                 </el-dropdown-menu>
               </el-dropdown>
               <span class="text">&nbsp;&nbsp;&nbsp;&nbsp;</span>

+ 194 - 0
src/views/PRJPHASE/index.vue

@@ -0,0 +1,194 @@
+<template>
+  <div id="index" ref="appRef">
+    <div class="bg">
+      <dv-loading v-if="loading">Loading...</dv-loading>
+      <div v-else class="host-body">
+        <div class="d-flex jc-center">
+          <dv-decoration-10 class="dv-dec-10" />
+          <div class="d-flex jc-center">
+            <dv-decoration-8 class="dv-dec-8" />
+            <div class="title">
+              <span class="title-text">百岗-MES可视化平台</span>
+              <dv-decoration-6
+                class="dv-dec-6"
+                :reverse="true"
+                :color="['#50e3c2', '#67a1e5']"
+              />
+            </div>
+            <dv-decoration-8
+              class="dv-dec-8"
+              :reverse="true"
+              :color="decorationColor"
+            />
+          </div>
+          <dv-decoration-10 class="dv-dec-10-s" />
+        </div>
+
+        <!-- 第二行 -->
+        <div class="d-flex jc-between px-2">
+          <div class="d-flex aside-width">
+            <div class="react-left ml-4 react-l-s bg-color-blue">
+              <span class="react-left"></span>
+              <span class="text fw-b" style="font-size:24px;">项目阶段看板</span>
+            </div>
+          </div>
+          <div class="d-flex aside-width">
+            <div class="react-right bg-color-r mr-3">
+              <el-button type="text" class="text" style="width:50% ;font-size: 22px;" @click="fullScreen" ref="fullScreen"
+                         v-show=!isFullScreen >全屏</el-button>
+              <el-button type="text" class="text" style="width:50% ;font-size: 22px;" @click="exitFullScreen" ref="exitFullScreen" v-show=isFullScreen>退出全屏</el-button>
+            </div>
+            <div class="react-right mr-4 react-l-s" style="width: 900px">
+              <span class="react-after"></span>
+              <el-dropdown class="dropdown">
+                <span class="el-dropdown-link" ref="echarType">
+                  项目阶段<i class="el-icon-arrow-down el-icon--right"></i>&nbsp;&nbsp;&nbsp;&nbsp;
+                </span>
+                <el-dropdown-menu slot="dropdown">
+                  <el-dropdown-item class="dropdownitem"><router-link to="IQC">IQC</router-link></el-dropdown-item>
+                  <el-dropdown-item class="dropdownitem"><router-link to="FQC">FQC</router-link></el-dropdown-item>
+                  <el-dropdown-item class="dropdownitem"><router-link to="PRJ">项目</router-link></el-dropdown-item>
+                  <el-dropdown-item class="dropdownitem"><router-link to="LAB">实验室</router-link></el-dropdown-item>
+                  <el-dropdown-item class="dropdownitem"><router-link to="SMT">SMT</router-link></el-dropdown-item>
+                  <el-dropdown-item class="dropdownitem"><router-link to="DIP">插件</router-link></el-dropdown-item>
+                  <el-dropdown-item class="dropdownitem"><router-link to="ZZ">组装</router-link></el-dropdown-item>
+                  <el-dropdown-item class="dropdownitem"><router-link to="WIRE">制线</router-link></el-dropdown-item>
+                </el-dropdown-menu>
+              </el-dropdown>
+              <span class="text">&nbsp;&nbsp;&nbsp;&nbsp;</span>
+              <span class="text">{{ dateYear }} {{ dateWeek }} {{ dateDay }}</span>
+            </div>
+          </div>
+        </div>
+
+        <div class="body-box">
+        <!--上面 -->
+          <div class="content-box">
+              <div>
+                <up/>
+              </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import drawMixin from "../../utils/drawMixin";
+import  common  from '../../utils/common';
+import {formatTime} from '../../utils/index.js'
+import up from './up.vue'
+import {mapMutations, mapState} from "vuex"
+
+export default {
+  mixins: [ drawMixin,common ],
+  computed: {
+    ...mapState(['user','factoryoptions','factory']),
+  },
+  data() {
+    return {
+      timing: null,
+      timing2: null,
+      timing3: null,
+      loading: true,
+      dateDay: null,
+      dateYear: null,
+      dateWeek: null,
+      weekday: ['周日', '周一', '周二', '周三', '周四', '周五', '周六'],
+      decorationColor: ['#568aea', '#000000'],
+    }
+  },
+  components: {
+    up
+  },
+  created() {
+     this.isFullScreen = document.fullscreenElement;
+  },
+  mounted() {
+    this.timeFn();
+    this.cancelLoading();
+   // this.autoFullScreen();
+  },
+  beforeDestroy () {
+    clearInterval(this.timing);
+    clearInterval(this.timing2);
+  },
+  methods: {
+    ...mapMutations(['setFactory']),
+    timeFn() {
+      this.timing = setInterval(() => {
+        this.dateDay = formatTime(new Date(), 'HH: mm: ss')
+        this.dateYear = formatTime(new Date(), 'yyyy-MM-dd')
+        this.dateWeek = this.weekday[new Date().getDay()]
+      }, 1000);
+    },
+    cancelLoading() {
+      setTimeout(() => {
+        this.loading = false
+      }, 1000)
+    },
+    autoFullScreen(){
+      if (!this.isFullScreen) {
+        setTimeout(() => {
+          this.$showMsgBox({
+            caption: "提示",
+            msg: '是否全屏展示?',
+            callback: (data) => {
+              if (data == "yes") {
+                this.fullScreen();
+              }
+            }
+          })
+        }, 3000)
+      }
+    },
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import '../../assets/scss/indexprjphase.scss';
+.dropdown{
+  font-size: 22px;
+  font-weight: bold;
+  color: #f6f7fa;
+  transform: skewX(45deg);
+  ::v-deep .el-select-dropdown {
+    /* // 若不将下拉框的背景颜色设置为:transparent,那么做不出来半透明的效果;
+    // 因为其最终的显示为:下拉框有一个背景颜色且下拉框的字体有一个背景颜色,重叠后的效果展示; */
+    border: 1px solid #0f1325;
+    background: #04308D !important;
+  }
+
+  ::v-deep .el-input__inner {
+    background-color: #1a5cd7;
+    color: #fff;
+    border: 1px solid #1a5cd7;
+    font-size: 22px;
+  }
+
+  .el-select-dropdown__item {
+    color: #fff;
+    background-color: #0f1325;
+  }
+  ::v-deep .el-select-dropdown {
+    background-color: transparent;
+    border: 1px solid #0f1325;
+  }
+  ::v-deep.el-select-dropdown__list {
+    padding: 0;
+  }
+  ::v-deep.el-popper[x-placement^="bottom"] {
+    margin-top: 0px;
+  }
+  ::v-deep.el-popper .popper__arrow,
+  ::v-deep.el-popper .popper__arrow::after {
+    display: none;
+  }
+  .el-select-dropdown__item:hover {
+    background-color: rgba(0, 225, 219, 0.690196078431373);
+  }
+}
+
+</style>

+ 157 - 0
src/views/PRJPHASE/up.vue

@@ -0,0 +1,157 @@
+<template>
+  <div id="prjp-up">
+    <div class="bg-color-black">
+      <!--      <div class="d-flex">
+              <span>
+                <icon name="align-left" class="text-icon"></icon>
+              </span>
+              <span class="fs-xxl mx-2 fw-b">项目阶段</span>
+            </div>-->
+      <div class="body-box pt-2">
+        <dv-scroll-board :config="config" ref="scroll-board" />
+      </div>
+    </div>
+  </div>
+</template>
+
+
+<script>
+export default {
+  data() {
+    return {
+      timing: null,
+      config: {
+        header: [],
+        data: [],
+        rowNum: 20, //表格行数
+        headerHeight: 40,
+        headerBGC: 'rgba(15,19,37,0.1)', //表头
+        oddRowBGC: 'rgba(15,19,37,0.1)', //奇数行
+        evenRowBGC: 'rgba(23,28,51,0.1)', //偶数行
+        columnWidth: [],
+        align: [],
+        carousel: 'page',
+        hoverPause: true,
+        waitTime :3500
+      },
+    }
+  },
+  components: {},
+  mounted() {
+    this.refreshdata();
+  },
+  beforeDestroy () {
+    clearInterval(this.timing)
+  },
+  methods: {
+    refreshdata() {
+      this.getdata(); //获取数据
+      this.timing = setInterval(() => {
+        this.getdata(); //获取-主题词
+      }, 300000);
+    },
+
+    async getdata() {
+      var caller = 'KB!PRJPHASE!DATA';
+      try {
+        const result = await this.$http.get("kanban/datalist.action?caller=" + caller + "&_noc=1&page=1&pageSize=100", {
+          params: { condition: "1=1" }
+        });
+        let columns = result.data.columns;
+        let headers = new Array();
+        let columnWidths = new Array();
+        let fieldnames = new Array();
+        let aligns = new Array();
+        for (let index = 0; index < columns.length; index++) {
+          const element = columns[index];
+          if(element.width>0) {
+            headers.push(element.text);
+            columnWidths.push(element.width);
+            fieldnames.push(element.dataIndex);
+            aligns.push('center');
+          }
+        }
+
+        this.config.header = headers;
+        this.config.columnWidth = columnWidths;
+        this.config.align = aligns;
+        let dataList = JSON.parse(result.data.data);
+        let resultList = new Array();
+        for (let index = 0; index < dataList.length; index++) {
+          const element = dataList[index];
+          let item = new Array();
+          fieldnames.forEach(function (ele) {
+            // 遍历数组,对每个元素进行操作
+            if(ele == "prj_name" ){
+               if(index%2 ==0) {
+                 item.push("<span  class='colorGrass fs-xl'>" + element[ele] + "</span>");
+               }else{
+                 item.push("<span  class='colorGrass fs-xl'>" + element[ele] + "</span>");
+               }
+            }else{
+              item.push("<span  class='colorGrass fs-xl'>" + element[ele] + "</span>");
+            }
+          });
+          resultList.push(item);
+        }
+        this.config.data = resultList;
+        this.config = { ...this.config };
+      } catch (error) {
+        console.error(error);
+      }
+    },
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+$box-height: 950px;
+$box-width: 100%;
+#prjp-up {
+  // padding: 13px;
+  // padding: 5px;
+  height: $box-height;
+  width: $box-width;
+  border-radius: 5px;
+  .bg-color-black {
+    padding: 5px;
+    height: $box-height - 25px;
+    //  width: width - 5px;
+    border-radius: 10px;
+  }
+
+  .text {
+    color: #c3cbde;
+    font-size: 25px;
+  }
+
+  .body-box {
+    width: $box-width;
+    overflow: hidden;
+
+    .dv-scroll-board {
+      height: $box-height - 65px;
+    }
+    ::v-deep  .dv-scroll-board {
+      .header {
+        font-size: 23px;
+        .header-item{
+          border: 1px solid #efebeb;
+        }
+      }
+      .rows {
+        .row-item {
+          font-size: 20px !important;
+        }
+        .ceil {
+          border: 1px solid #f8eeee;
+        }
+        .hidden-cell {
+          display: none;
+        }
+      }
+    }
+  }
+
+}
+</style>

+ 385 - 0
src/views/PRJPHASE/up1.vue

@@ -0,0 +1,385 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
+  <style>
+    body {
+      font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
+      padding: 20px;
+      background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
+      min-height: 100vh;
+    }
+
+    #app {
+      max-width: 1200px;
+      margin: 0 auto;
+      background-color: white;
+      border-radius: 12px;
+      box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
+      padding: 25px;
+      overflow: hidden;
+    }
+
+    h1 {
+      text-align: center;
+      color: #2c3e50;
+      margin-bottom: 5px;
+    }
+
+    .description {
+      text-align: center;
+      color: #7f8c8d;
+      margin-bottom: 25px;
+      font-size: 0.95em;
+    }
+
+    .controls {
+      display: flex;
+      justify-content: center;
+      gap: 15px;
+      margin-bottom: 20px;
+      flex-wrap: wrap;
+    }
+
+    button {
+      padding: 10px 20px;
+      background-color: #4CAF50;
+      color: white;
+      border: none;
+      border-radius: 6px;
+      cursor: pointer;
+      font-weight: 600;
+      transition: all 0.3s ease;
+    }
+
+    button:hover {
+      background-color: #3d8b40;
+      transform: translateY(-2px);
+    }
+
+    button:active {
+      transform: translateY(0);
+    }
+
+    button.pause {
+      background-color: #f39c12;
+    }
+
+    button.pause:hover {
+      background-color: #d68910;
+    }
+
+    button.reset {
+      background-color: #e74c3c;
+    }
+
+    button.reset:hover {
+      background-color: #c0392b;
+    }
+
+    .table-container {
+      max-height: 600px;
+      overflow: hidden;
+      position: relative;
+      border-radius: 8px;
+      border: 1px solid #ddd;
+    }
+
+    .scroll-message {
+      position: absolute;
+      top: 10px;
+      right: 10px;
+      background-color: #4CAF50;
+      color: white;
+      padding: 5px 10px;
+      border-radius: 20px;
+      font-size: 0.8em;
+      z-index: 10;
+      animation: pulse 2s infinite;
+    }
+
+    @keyframes pulse {
+      0% { opacity: 1; }
+      50% { opacity: 0.7; }
+      100% { opacity: 1; }
+    }
+
+    .table-wrapper {
+      overflow: hidden;
+    }
+
+    .scrolling-table {
+      animation: scrollUp 50s linear infinite;
+      animation-play-state: running;
+    }
+
+    .scrolling-table.paused {
+      animation-play-state: paused;
+    }
+
+    @keyframes scrollUp {
+      0% {
+        transform: translateY(0);
+      }
+      100% {
+        transform: translateY(calc(-100% + 600px));
+      }
+    }
+
+    table {
+      border-collapse: collapse;
+      width: 100%;
+      font-size: 0.95em;
+    }
+
+    th, td {
+      border: 1px solid #e0e0e0;
+      padding: 12px 15px;
+      text-align: left;
+    }
+
+    th {
+      background: #4CAF50;
+      color: white;
+      font-weight: 600;
+      position: sticky;
+      top: 0;
+      z-index: 5;
+    }
+
+    .dept {
+      background: #f0f8ff;
+      font-weight: bold;
+      color: #2c3e50;
+    }
+
+    tr:nth-child(even) {
+      background-color: #f9f9f9;
+    }
+
+    tr:hover {
+      background-color: #f1f8ff;
+    }
+
+    .footer {
+      text-align: center;
+      margin-top: 20px;
+      color: #7f8c8d;
+      font-size: 0.9em;
+    }
+
+    .counter {
+      display: inline-block;
+      background-color: #ecf0f1;
+      padding: 5px 10px;
+      border-radius: 4px;
+      font-weight: bold;
+      color: #2c3e50;
+    }
+  </style>
+</head>
+<body>
+<div id="app">
+  <h1>部门员工信息表</h1>
+  <p class="description">当数据超过15条时,表格会自动向上滚动。使用下方按钮控制滚动行为。</p>
+
+  <div class="controls">
+    <button @click="toggleScroll" :class="{pause: isPaused}">
+      {{ isPaused ? '继续滚动' : '暂停滚动' }}
+    </button>
+    <button @click="resetScroll" class="reset">重置到顶部</button>
+    <button @click="toggleSpeed">{{ speedLabel }}</button>
+    <div class="counter">当前数据: {{ data.length }} 条</div>
+  </div>
+
+  <div class="table-container">
+    <div v-if="shouldScroll" class="scroll-message">自动滚动中</div>
+    <div class="table-wrapper">
+      <table :class="['scrolling-table', {paused: isPaused}]" ref="table">
+        <thead>
+        <tr>
+          <th>部门编号</th>
+          <th>部门</th>
+          <th>姓名</th>
+          <th>职位</th>
+          <th>薪资</th>
+        </tr>
+        </thead>
+        <tbody>
+        <template v-for="dept in data" :key="dept.id">
+          <tr>
+            <td class="dept" rowspan="2">{{dept.id}}</td>
+            <td class="dept" rowspan="2">{{dept.name}}</td>
+            <td>{{dept.emp1.name}}</td>
+            <td>{{dept.emp1.position}}</td>
+            <td>¥{{dept.emp1.salary.toLocaleString()}}</td>
+          </tr>
+          <tr>
+            <td>{{dept.emp2.name}}</td>
+            <td>{{dept.emp2.position}}</td>
+            <td>¥{{dept.emp2.salary.toLocaleString()}}</td>
+          </tr>
+        </template>
+        <!-- 添加重复数据以实现无缝滚动效果 -->
+        <template v-if="shouldScroll" v-for="dept in data" :key="`repeat-${dept.id}`">
+          <tr>
+            <td class="dept" rowspan="2">{{dept.id}}</td>
+            <td class="dept" rowspan="2">{{dept.name}}</td>
+            <td>{{dept.emp1.name}}</td>
+            <td>{{dept.emp1.position}}</td>
+            <td>¥{{dept.emp1.salary.toLocaleString()}}</td>
+          </tr>
+          <tr>
+            <td>{{dept.emp2.name}}</td>
+            <td>{{dept.emp2.position}}</td>
+            <td>¥{{dept.emp2.salary.toLocaleString()}}</td>
+          </tr>
+        </template>
+        </tbody>
+      </table>
+    </div>
+  </div>
+
+  <div class="footer">
+    <p>每行显示一个部门的两名员工信息 | 数据条数超过15条时自动滚动</p>
+  </div>
+</div>
+
+<script>
+  Vue.createApp({
+    setup() {
+      // 生成更多数据(超过15条)
+      const generateData = () => {
+        const departments = [
+          {id:'D001', name:'技术部'},
+          {id:'D002', name:'市场部'},
+          {id:'D003', name:'人力资源部'},
+          {id:'D004', name:'财务部'},
+          {id:'D005', name:'销售部'},
+          {id:'D006', name:'产品部'},
+          {id:'D007', name:'设计部'},
+          {id:'D008', name:'客服部'},
+          {id:'D009', name:'研发部'},
+          {id:'D010', name:'运营部'},
+          {id:'D011', name:'质量部'},
+          {id:'D012', name:'采购部'},
+          {id:'D013', name:'行政部'},
+          {id:'D014', name:'法务部'},
+          {id:'D015', name:'公关部'},
+          {id:'D016', name:'物流部'},
+          {id:'D017', name:'工程部'},
+          {id:'D018', name:'信息部'},
+          {id:'D019', name:'培训部'},
+          {id:'D020', name:'战略部'}
+        ];
+
+        const positions = [
+          {title:'工程师', salaryRange:[8000, 15000]},
+          {title:'高级工程师', salaryRange:[12000, 25000]},
+          {title:'经理', salaryRange:[15000, 30000]},
+          {title:'专员', salaryRange:[6000, 10000]},
+          {title:'主管', salaryRange:[10000, 18000]},
+          {title:'总监', salaryRange:[20000, 40000]},
+          {title:'助理', salaryRange:[5000, 8000]},
+          {title:'分析师', salaryRange:[9000, 16000]}
+        ];
+
+        const firstNames = ['张', '李', '王', '赵', '刘', '陈', '杨', '黄', '周', '吴', '郑', '孙', '马', '朱', '胡', '林', '郭', '何', '高', '罗'];
+        const lastNames = ['伟', '芳', '娜', '敏', '静', '磊', '洋', '艳', '勇', '军', '霞', '强', '秀英', '文', '明', '华', '建国', '桂英', '亮', '玲'];
+
+        const getRandomName = () => {
+          const firstName = firstNames[Math.floor(Math.random() * firstNames.length)];
+          const lastName = lastNames[Math.floor(Math.random() * lastNames.length)];
+          return firstName + lastName;
+        };
+
+        const getRandomPosition = () => {
+          return positions[Math.floor(Math.random() * positions.length)];
+        };
+
+        return departments.map(dept => {
+          const pos1 = getRandomPosition();
+          const pos2 = getRandomPosition();
+
+          return {
+            id: dept.id,
+            name: dept.name,
+            emp1: {
+              name: getRandomName(),
+              position: pos1.title,
+              salary: Math.floor(Math.random() * (pos1.salaryRange[1] - pos1.salaryRange[0])) + pos1.salaryRange[0]
+            },
+            emp2: {
+              name: getRandomName(),
+              position: pos2.title,
+              salary: Math.floor(Math.random() * (pos2.salaryRange[1] - pos2.salaryRange[0])) + pos2.salaryRange[0]
+            }
+          };
+        });
+      };
+
+      const data = generateData();
+      const shouldScroll = Vue.ref(data.length > 15);
+      const isPaused = Vue.ref(false);
+      const scrollSpeed = Vue.ref(50); // 动画时长,值越大滚动越慢
+
+      const speedLabel = Vue.computed(() => {
+        if (scrollSpeed.value === 30) return '快速滚动';
+        if (scrollSpeed.value === 70) return '慢速滚动';
+        return '中速滚动';
+      });
+
+      const toggleScroll = () => {
+        isPaused.value = !isPaused.value;
+      };
+
+      const resetScroll = () => {
+        const table = document.querySelector('.scrolling-table');
+        if (table) {
+          table.style.animation = 'none';
+          setTimeout(() => {
+            table.style.animation = `scrollUp ${scrollSpeed.value}s linear infinite`;
+            table.style.animationPlayState = isPaused.value ? 'paused' : 'running';
+          }, 10);
+        }
+        isPaused.value = false;
+      };
+
+      const toggleSpeed = () => {
+        if (scrollSpeed.value === 50) {
+          scrollSpeed.value = 30; // 快速
+        } else if (scrollSpeed.value === 30) {
+          scrollSpeed.value = 70; // 慢速
+        } else {
+          scrollSpeed.value = 50; // 中速
+        }
+
+        // 应用新的速度
+        const table = document.querySelector('.scrolling-table');
+        if (table) {
+          table.style.animationDuration = `${scrollSpeed.value}s`;
+        }
+      };
+
+      // 动态更新动画时长
+      Vue.onMounted(() => {
+        const table = document.querySelector('.scrolling-table');
+        if (table && shouldScroll.value) {
+          table.style.animationDuration = `${scrollSpeed.value}s`;
+        }
+      });
+
+      return {
+        data,
+        shouldScroll,
+        isPaused,
+        speedLabel,
+        toggleScroll,
+        resetScroll,
+        toggleSpeed
+      };
+    }
+  }).mount('#app');
+</script>
+</body>
+</html>

+ 147 - 0
src/views/PRJPHASE/up2.vue

@@ -0,0 +1,147 @@
+<template>
+  <div id="prjp-up">
+    <div class="bg-color-black">
+<!--      <div class="d-flex">
+        <span>
+          <icon name="align-left" class="text-icon"></icon>
+        </span>
+        <span class="fs-xxl mx-2 fw-b">项目阶段</span>
+      </div>-->
+      <div class="body-box pt-2">
+        <dv-scroll-board :config="config" ref="scroll-board" />
+      </div>
+    </div>
+  </div>
+</template>
+
+
+<script>
+export default {
+  data() {
+    return {
+      timing: null,
+      config: {
+        header: [],
+        //'项目','项目经理','评审','硬件','软件','样机','DQA','送样','试产','型式试验','结案'
+        data: [],
+        rowNum: 23, //表格行数
+        headerHeight: 40,
+        headerBGC: 'rgba(15,19,37,0.1)', //表头
+        oddRowBGC: 'rgba(15,19,37,0.1)', //奇数行
+        evenRowBGC: 'rgba(23,28,51,0.1)', //偶数行
+        columnWidth: [],
+        align: [],
+        carousel: 'page',
+        hoverPause: true,
+        waitTime :3000
+      },
+    }
+  },
+  components: {},
+  mounted() {
+    this.refreshdata();
+  },
+  beforeDestroy () {
+    clearInterval(this.timing)
+  },
+  methods: {
+    refreshdata() {
+      this.getdata(); //获取数据
+      this.timing = setInterval(() => {
+        this.getdata(); //获取-主题词
+      }, 300000);
+    },
+
+    async getdata() {
+      var caller = 'KB!PRJPHASE!DATA';
+      try {
+        const result = await this.$http.get("kanban/datalist.action?caller=" + caller + "&_noc=1&page=1&pageSize=100", {
+          params: { condition: "1=1" }
+        });
+        let columns = result.data.columns;
+        let headers = new Array();
+        let columnWidths = new Array();
+        let fieldnames = new Array();
+        let aligns = new Array();
+        for (let index = 0; index < columns.length; index++) {
+          const element = columns[index];
+          if(element.width>0) {
+            headers.push(element.text);
+            columnWidths.push(element.width);
+            fieldnames.push(element.dataIndex);
+            aligns.push('center');
+          }
+        }
+
+        this.config.header = headers;
+        this.config.columnWidth = columnWidths;
+        this.config.align = aligns;
+        let dataList = JSON.parse(result.data.data);
+        let resultList = new Array();
+        for (let index = 0; index < dataList.length; index++) {
+          const element = dataList[index];
+          let item = new Array();
+          fieldnames.forEach(function (ele) {
+            // 遍历数组,对每个元素进行操作
+            item.push("<span  class='colorGrass fs-xl'>" + element[ele] + "</span>");
+          });
+          resultList.push(item);
+        }
+        this.config.data = resultList;
+        this.config = { ...this.config };
+      } catch (error) {
+        console.error(error);
+      }
+    },
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+$box-height: 950px;
+$box-width: 100%;
+#prjp-up {
+  padding: 13px;
+  // padding: 5px;
+  height: $box-height;
+  width: $box-width;
+  border-radius: 5px;
+  .bg-color-black {
+    padding: 5px;
+    height: $box-height - 25px;
+    //  width: width - 5px;
+    border-radius: 10px;
+  }
+
+  .text {
+    color: #c3cbde;
+    font-size: 25px;
+  }
+
+  .body-box {
+    width: $box-width;
+    overflow: hidden;
+
+    .dv-scroll-board {
+      height: $box-height - 65px;
+    }
+    ::v-deep  .dv-scroll-board {
+      .header {
+        font-size: 23px;
+        .header-item{
+          border: 1px solid #efebeb;
+        }
+      }
+      .rows {
+        .row-item {
+          font-size: 20px !important;
+        }
+        .ceil {
+          border: 1px solid #f8eeee;
+        }
+      }
+    }
+  }
+
+}
+</style>

+ 1 - 0
src/views/SMT/index.vue

@@ -52,6 +52,7 @@
                   <el-dropdown-item class="dropdownitem"><router-link to="DIP">插件</router-link></el-dropdown-item>
                   <el-dropdown-item class="dropdownitem"><router-link to="ZZ">组装</router-link></el-dropdown-item>
                   <el-dropdown-item class="dropdownitem"><router-link to="WIRE">制线</router-link></el-dropdown-item>
+                  <el-dropdown-item class="dropdownitem"><router-link to="PRJPHASE">项目阶段</router-link></el-dropdown-item>
                 </el-dropdown-menu>
               </el-dropdown>
               <el-select v-model="licode" class="dropdown" @change ="handleBlur" style="width: 150px">

+ 1 - 0
src/views/WIRE/index.vue

@@ -52,6 +52,7 @@
                   <el-dropdown-item class="dropdownitem"><router-link to="SMT">SMT</router-link></el-dropdown-item>
                   <el-dropdown-item class="dropdownitem"><router-link to="DIP">DIP</router-link></el-dropdown-item>
                   <el-dropdown-item class="dropdownitem"><router-link to="ZZ">组装</router-link></el-dropdown-item>
+                  <el-dropdown-item class="dropdownitem"><router-link to="PRJPHASE">项目阶段</router-link></el-dropdown-item>
                 </el-dropdown-menu>
               </el-dropdown>
               <span class="text">&nbsp;&nbsp;&nbsp;&nbsp;</span>

+ 1 - 0
src/views/ZZ/index.vue

@@ -52,6 +52,7 @@
                   <el-dropdown-item class="dropdownitem"><router-link to="SMT">SMT</router-link></el-dropdown-item>
                   <el-dropdown-item class="dropdownitem"><router-link to="DIP">插件</router-link></el-dropdown-item>
                   <el-dropdown-item class="dropdownitem"><router-link to="WIRE">制线</router-link></el-dropdown-item>
+                  <el-dropdown-item class="dropdownitem"><router-link to="PRJPHASE">项目阶段</router-link></el-dropdown-item>
                 </el-dropdown-menu>
               </el-dropdown>
               <span class="text">&nbsp;&nbsp;&nbsp;&nbsp;</span>

+ 4 - 1
src/views/login.vue

@@ -69,6 +69,7 @@
                     {label: '插件', value: 'DIP'},
                     {label: '组装', value: 'ZZ'},
                     {label: '制线', value: 'WIRE'},
+                    {label: '项目阶段', value: 'PRJPHASE'},
                 ],
             }
         },
@@ -136,7 +137,9 @@
                                      this.$router.push({path: this.redirect || '/ZZ'});
                                     }else if(this.loginForm.type == 'WIRE') {
                                      this.$router.push({path: this.redirect || '/WIRE'});
-                                   }
+                                    }else if(this.loginForm.type == 'PRJPHASE') {
+                                     this.$router.push({path: this.redirect || '/PRJPHASE'});
+                                    }
                                 }else{
                                     this.$message.error(res.reason);
                                 }