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

主页的样式修改和盘具逻辑判断的修改

695593266@qq.com 15 часов назад
Родитель
Сommit
14c5e66265

+ 205 - 38
src/views/home/data.js

@@ -116,56 +116,175 @@ export const columns = [
 ];
 
 export const barOption = (series, itemStyle = {}) => {
+  const axisLabel = {
+    color: 'rgba(224, 242, 254, 0.72)',
+    fontSize: Math.max(11, window.innerHeight * 0.011),
+    hideOverlap: true
+  };
+  const formatAxisValue = (value) => {
+    if (Math.abs(value) >= 10000) {
+      return (value / 10000).toFixed(value % 10000 === 0 ? 0 : 1) + '万';
+    }
+    return value;
+  };
+  const defaultXAxis = {
+    type: 'category',
+    data: [
+      '一月',
+      '二月',
+      '三月',
+      '四月',
+      '五月',
+      '六月',
+      '七月',
+      '八月',
+      '九月',
+      '十月',
+      '十一月',
+      '十二月'
+    ],
+    axisLabel,
+    axisLine: {
+      lineStyle: {
+        color: 'rgba(125, 211, 252, 0.35)'
+      }
+    },
+    axisTick: {
+      lineStyle: {
+        color: 'rgba(125, 211, 252, 0.35)'
+      }
+    }
+  };
+  const xAxis = {
+    ...defaultXAxis,
+    ...(itemStyle.xAxis || {}),
+    axisLabel: {
+      ...defaultXAxis.axisLabel,
+      ...((itemStyle.xAxis && itemStyle.xAxis.axisLabel) || {})
+    },
+    axisLine: {
+      ...defaultXAxis.axisLine,
+      ...((itemStyle.xAxis && itemStyle.xAxis.axisLine) || {})
+    },
+    axisTick: {
+      ...defaultXAxis.axisTick,
+      ...((itemStyle.xAxis && itemStyle.xAxis.axisTick) || {})
+    }
+  };
   return {
+    backgroundColor: 'transparent',
     tooltip: {
       formatter: (item) => {
         return item.name + ':' + item.seriesName + ' ' + item.value + '个';
       },
-      trigger: 'item'
+      trigger: 'item',
+      borderWidth: 1,
+      borderColor: 'rgba(56, 189, 248, 0.35)',
+      backgroundColor: 'rgba(8, 18, 33, 0.92)',
+      textStyle: {
+        color: '#e0faff'
+      }
     },
     legend: {
       // bottom: '2%',
       itemGap: window.innerHeight * 0.014,
 
       textStyle: {
-        fontSize: window.innerHeight * 0.013
-      }
+        color: 'rgba(224, 242, 254, 0.82)',
+        fontSize: Math.max(12, window.innerHeight * 0.013)
+      },
+      icon: 'roundRect'
     },
-    color: ['#1890ff'],
-    xAxis: {
-      type: 'category',
-      data: [
-        '一月',
-        '二月',
-        '三月',
-        '四月',
-        '五月',
-        '六月',
-        '七月',
-        '八月',
-        '九月',
-        '十月',
-        '十一月',
-        '十二月'
-      ],
-      axisLabel: {
-        fontSize: window.innerHeight * 0.012
-      }
+    grid: {
+      top: 48,
+      left: 36,
+      right: 24,
+      bottom: 24,
+      containLabel: true
     },
+    color: [
+      {
+        type: 'linear',
+        x: 0,
+        y: 0,
+        x2: 0,
+        y2: 1,
+        colorStops: [
+          { offset: 0, color: '#67e8f9' },
+          { offset: 1, color: '#0284c7' }
+        ]
+      },
+      '#facc15'
+    ],
+    xAxis,
     yAxis: [
       {
         type: 'value',
         name: '(个)',
+        splitNumber: 4,
+        minInterval: 1,
         nameTextStyle: {
           align: 'center',
-          color: '#333',
-          fontSize: window.innerHeight * 0.012,
-          padding: [0, 20, -3, 0]
+          color: 'rgba(224, 242, 254, 0.72)',
+          fontSize: Math.max(11, window.innerHeight * 0.011),
+          padding: [0, 12, -3, 0]
+        },
+        axisLabel: {
+          ...axisLabel,
+          margin: 12,
+          formatter: formatAxisValue
+        },
+        splitLine: {
+          lineStyle: {
+            color: 'rgba(125, 211, 252, 0.14)',
+            type: 'dashed'
+          }
+        },
+        axisLine: {
+          show: true,
+          lineStyle: {
+            color: 'rgba(125, 211, 252, 0.3)'
+          }
         }
       }
     ],
     ...itemStyle,
-    series
+    xAxis,
+    series: series.map((item) => {
+      if (item.type === 'bar') {
+        return {
+          ...item,
+          barMaxWidth: 28,
+          showBackground: true,
+          backgroundStyle: {
+            color: 'rgba(56, 189, 248, 0.055)',
+            borderRadius: [6, 6, 0, 0]
+          },
+          itemStyle: {
+            borderRadius: [6, 6, 0, 0],
+            shadowBlur: 12,
+            shadowColor: 'rgba(56, 189, 248, 0.32)',
+            ...(item.itemStyle || {})
+          }
+        };
+      }
+      return {
+        ...item,
+        lineStyle: {
+          width: 3,
+          color: '#facc15',
+          shadowBlur: 10,
+          shadowColor: 'rgba(250, 204, 21, 0.5)',
+          ...(item.lineStyle || {})
+        },
+        itemStyle: {
+          color: '#facc15',
+          borderColor: '#fff7ad',
+          borderWidth: 2,
+          ...(item.itemStyle || {})
+        }
+      };
+    })
   };
 };
 
@@ -216,13 +335,20 @@ export const pieOption = (data) => {
 
 export const pieOptions = (data) => {
   return {
-    color: ['#398f4e', '#458ef7', '#fdc537', '#fe6869', '#975fe6'],
+    backgroundColor: 'transparent',
+    color: ['#20d47a', '#38c7ff', '#ffd23f', '#ff738a', '#a877e8', '#30d6c4'],
     tooltip: {
       // formatter: '{b}:{c}' + '%',
       formatter: function (params) {
         return `${params.name}<br/>数量: ${params.value}<br/>占比: ${params.percent}%`;
       },
-      trigger: 'item'
+      trigger: 'item',
+      borderWidth: 1,
+      borderColor: 'rgba(56, 189, 248, 0.35)',
+      backgroundColor: 'rgba(8, 18, 33, 0.92)',
+      textStyle: {
+        color: '#e0faff'
+      }
     },
     // legend: {
     //   orient: 'horizontal',
@@ -236,25 +362,66 @@ export const pieOptions = (data) => {
     // },
     series: [
       {
-        center: ['50%', '50%'],
+        center: ['52%', '52%'],
         label: {
           position: 'outside',
           show: true,
           formatter: (item) => {
-            return item.name + ':' + item.value;
+            return `{name|${item.name}}  {value|${item.value}}`;
           },
-          fontSize: 12
-          // color:"#fff"
+          color: 'rgba(224, 242, 254, 0.82)',
+          width: 120,
+          overflow: 'break',
+          lineHeight: 18,
+          rich: {
+            name: {
+              color: 'rgba(148, 178, 195, 0.9)',
+              fontSize: 12,
+              fontWeight: 600,
+              lineHeight: 18,
+              textShadowBlur: 8,
+              textShadowColor: 'rgba(56, 189, 248, 0.18)'
+            },
+            value: {
+              color: '#ffe88a',
+              fontSize: 14,
+              fontWeight: 700,
+              lineHeight: 18,
+              textBorderColor: 'rgba(7, 18, 31, 0.68)',
+              textBorderWidth: 2,
+              textShadowBlur: 12,
+              textShadowColor: 'rgba(250, 204, 21, 0.62)'
+            }
+          }
         },
         labelLine: {
-          show: true
+          show: true,
+          length: 14,
+          length2: 20,
+          smooth: true,
+          lineStyle: {
+            width: 1.5,
+            color: 'rgba(125, 211, 252, 0.62)'
+          }
         },
         type: 'pie',
-        radius: '60%',
+        radius: ['42%', '64%'],
+        startAngle: 120,
+        minAngle: 4,
+        avoidLabelOverlap: true,
         itemStyle: {
-          borderWidth: 0,
-          shadowBlur: 10,
-          shadowColor: 'rgba(0, 0, 0, 0.5)'
+          borderRadius: 8,
+          borderWidth: 2,
+          borderColor: '#081421',
+          shadowBlur: 18,
+          shadowColor: 'rgba(34, 211, 238, 0.24)'
+        },
+        emphasis: {
+          scaleSize: 8,
+          itemStyle: {
+            shadowBlur: 24,
+            shadowColor: 'rgba(103, 232, 249, 0.45)'
+          }
         },
         data
       }

+ 890 - 145
src/views/home/index.vue

@@ -1,100 +1,111 @@
 <template>
-  <div class="ele-body">
-    <el-row :gutter="15">
-      <el-col :span="16" style="height: calc(57% - 51px)">
-        <div
-          class=""
-          style="
-            display: flex;
-            align-items: center;
-            justify-content: space-between;
-          "
-        >
-          <el-radio-group v-model="form.timeType" @change="timeTypeChange">
+  <div class="ele-body mes-screen">
+    <div class="screen-shell">
+      <div class="screen-toolbar">
+        <div class="screen-title">
+          <span>MES生产运营驾驶舱</span>
+          <em>Manufacturing Execution Dashboard</em>
+        </div>
+        <div class="screen-filters">
+          <el-radio-group
+            v-model="form.timeType"
+            class="mode-tabs"
+            @change="timeTypeChange"
+          >
             <el-radio-button label="1">企业</el-radio-button>
             <el-radio-button label="2">工厂</el-radio-button>
             <!-- <el-radio-button label="3">班组</el-radio-button>
           <el-radio-button label="4">产线</el-radio-button> -->
           </el-radio-group>
-          <div>
-            <el-select
-              v-if="form.timeType === '2'"
-              v-model="params.factoryId"
-              filterable
-              placeholder="请选择工厂"
-              size="mini"
-              style="margin-right: 20px"
-            >
-              <el-option
-                v-for="item in factoryList"
-                :key="item.id"
-                :label="item.name"
-                :value="item.id"
-              >
-              </el-option>
-            </el-select>
-            <el-date-picker
-              v-model="params.date"
-              type="monthrange"
-              range-separator="至"
-              start-placeholder="开始月份"
-              end-placeholder="结束月份"
-              size="mini"
-              :picker-options="pickerOptions"
+          <el-select
+            v-if="form.timeType === '2'"
+            v-model="params.factoryId"
+            class="factory-select"
+            filterable
+            placeholder="请选择工厂"
+            size="mini"
+          >
+            <el-option
+              v-for="item in factoryList"
+              :key="item.id"
+              :label="item.name"
+              :value="item.id"
             >
-            </el-date-picker>
-          </div>
-        </div>
-        <div style="height: 20%" class="item">
-          <div
-            v-for="(item, index) in arr"
-            :key="index"
-            :style="{ color: item.color }"
+            </el-option>
+          </el-select>
+          <el-date-picker
+            v-model="params.date"
+            class="date-range"
+            type="monthrange"
+            range-separator="至"
+            start-placeholder="开始月份"
+            end-placeholder="结束月份"
+            size="mini"
+            :picker-options="pickerOptions"
           >
-            <img :src="item.imgUrl" />
-            <div>
-              <span>
-                {{ item.name }}
-              </span>
-              <span>
-                {{ item.num }}
-                <span>{{ item.unit }}</span>
-              </span>
-            </div>
-          </div>
+          </el-date-picker>
         </div>
-        <el-card class="box-card" style="height: calc(80% - 15px)">
-          <div slot="header" class="clearfix">
-            <span>工单完成统计</span>
-          </div>
-          <v-chart ref="barRef" style="height: 100%" :option="barOption" />
-        </el-card>
-      </el-col>
-      <el-col :span="8" style="height: 57%">
-        <el-card class="box-card">
-          <div slot="header" class="clearfix">
-            <span>不良品分布图</span>
-          </div>
-          <v-chart ref="pieRef" style="height: 100%" :option="pieOptions" />
-        </el-card>
-      </el-col>
-      <el-col :span="24" style="height: 43%; margin-top: 15px">
-        <el-card class="box-card">
-          <div slot="header" class="clearfix">
-            <span>工单进度执行跟踪</span>
+      </div>
+
+      <el-row :gutter="16" class="screen-grid">
+        <el-col :xs="24" :sm="24" :md="16" :lg="16" :xl="17" class="main-col">
+          <div class="item metrics-grid">
+            <div
+              v-for="(item, index) in arr"
+              :key="index"
+              class="metric-card"
+              :class="'metric-card-' + index"
+              :style="{ color: item.color }"
+            >
+              <div class="metric-content">
+                <span class="metric-label">
+                  {{ item.name }}
+                </span>
+                <div class="metric-main">
+                  <div class="metric-icon">
+                    <img :src="item.imgUrl" />
+                  </div>
+                  <span class="metric-value">
+                    {{ item.num }}
+                    <span>{{ item.unit }}</span>
+                  </span>
+                </div>
+              </div>
+            </div>
           </div>
-          <ele-pro-table
-            ref="table"
-            height="calc(100%)"
-            :columns="columns"
-            :datasource="datasource"
-            :toolbar="false"
-            :needPage="false"
-          >
-          </ele-pro-table>
-        </el-card>
-      </el-col>
-    </el-row>
+          <el-card class="box-card screen-panel chart-panel">
+            <div slot="header" class="clearfix panel-header">
+              <span>工单完成统计</span>
+            </div>
+            <v-chart ref="barRef" class="screen-chart" :option="barOption" />
+          </el-card>
+        </el-col>
+        <el-col :xs="24" :sm="24" :md="8" :lg="8" :xl="7" class="side-col">
+          <el-card class="box-card screen-panel pie-panel">
+            <div slot="header" class="clearfix panel-header">
+              <span>不良品分布图</span>
+            </div>
+            <v-chart ref="pieRef" class="screen-chart" :option="pieOptions" />
+          </el-card>
+        </el-col>
+        <el-col :span="24" class="table-col">
+          <el-card class="box-card screen-panel table-panel">
+            <div slot="header" class="clearfix panel-header">
+              <span>工单进度执行跟踪</span>
+            </div>
+            <ele-pro-table
+              ref="table"
+              height="calc(100%)"
+              :columns="columns"
+              :datasource="datasource"
+              :toolbar="false"
+              :needPage="false"
+            >
+            </ele-pro-table>
+          </el-card>
+        </el-col>
+      </el-row>
+    </div>
   </div>
 </template>
 <script>
@@ -390,76 +401,810 @@
   };
 </script>
 <style lang="scss" scoped>
-  .clearfix {
-    font-size: 0.7vw;
+  .mes-screen {
+    height: calc(100vh - 92px);
+    min-height: 680px;
+    box-sizing: border-box;
+    overflow: hidden;
+    color: #d9f7ff;
+    background:
+      linear-gradient(115deg, rgba(34, 211, 238, 0.08) 0%, transparent 26%),
+      linear-gradient(245deg, rgba(16, 185, 129, 0.06) 0%, transparent 30%),
+      linear-gradient(180deg, #071524 0%, #06111f 52%, #050c17 100%);
+    position: relative;
+    box-shadow: 0 0 0 100vmax #050c17;
+    clip-path: inset(0 -100vmax -100vmax -100vmax);
 
-    > span {
-      font-weight: bold;
+    &::before {
+      content: '';
+      position: absolute;
+      inset: 0;
+      pointer-events: none;
+      background-image:
+        linear-gradient(rgba(103, 232, 249, 0.06) 1px, transparent 1px),
+        linear-gradient(90deg, rgba(103, 232, 249, 0.06) 1px, transparent 1px);
+      background-size: 32px 32px;
+      mask-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.9), transparent 90%);
     }
-    :deep(.el-radio-button__inner) {
-      font-size: 0.7vw;
+
+    &::after {
+      content: '';
+      position: absolute;
+      inset: 0;
+      pointer-events: none;
+      background: repeating-linear-gradient(
+        180deg,
+        rgba(255, 255, 255, 0.025) 0,
+        rgba(255, 255, 255, 0.025) 1px,
+        transparent 1px,
+        transparent 5px
+      );
+      opacity: 0.25;
     }
   }
-  .ele-body {
-    height: calc(100vh - 111px);
-    > .el-row {
-      height: 100%;
+
+  .screen-shell {
+    position: relative;
+    z-index: 1;
+    height: 100%;
+    min-height: 0;
+    padding: 16px 20px 18px;
+    display: flex;
+    flex-direction: column;
+    gap: 14px;
+
+    &::before,
+    &::after {
+      content: '';
+      position: absolute;
+      left: 20px;
+      right: 20px;
+      height: 1px;
+      pointer-events: none;
+      background: linear-gradient(90deg, transparent, rgba(103, 232, 249, 0.42), transparent);
+    }
+
+    &::before {
+      top: 8px;
+    }
+
+    &::after {
+      bottom: 8px;
+    }
+  }
+
+  .screen-toolbar {
+    position: relative;
+    overflow: hidden;
+    min-height: 58px;
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    gap: 18px;
+    padding: 12px 18px;
+    border: 1px solid rgba(56, 189, 248, 0.34);
+    border-radius: 8px;
+    background:
+      linear-gradient(90deg, rgba(9, 45, 69, 0.92), rgba(8, 22, 39, 0.78)),
+      linear-gradient(180deg, rgba(103, 232, 249, 0.08), transparent);
+    box-shadow:
+      inset 0 1px 0 rgba(165, 243, 252, 0.16),
+      inset 0 0 28px rgba(14, 165, 233, 0.12),
+      0 14px 34px rgba(0, 0, 0, 0.28);
+
+    &::before {
+      content: '';
+      position: absolute;
+      left: 18px;
+      right: 18px;
+      bottom: 0;
+      height: 1px;
+      background: linear-gradient(90deg, transparent, rgba(103, 232, 249, 0.85), transparent);
+      opacity: 0.65;
     }
-    .el-card {
+
+    &::after {
+      content: '';
+      position: absolute;
+      left: 0;
+      top: 0;
+      width: 180px;
       height: 100%;
-      :deep(.el-card__body) {
-        padding: 0.3vw;
-      }
-      :deep(.el-card__header) {
-        padding: 0.8vw;
-      }
-      :deep(.el-card__body) {
-        height: calc(100% - 1.6vw - 39px);
-      }
-      :deep(.ele-pro-table) {
-        height: 99%;
-      }
-      :deep(.el-table) {
-        font-size: 0.65vw;
-      }
+      background: linear-gradient(100deg, rgba(103, 232, 249, 0.12), transparent 72%);
+      pointer-events: none;
     }
   }
-  .item {
-    width: 100%;
+
+  .screen-title {
+    position: relative;
+    z-index: 1;
     display: flex;
-    margin-bottom: 15px;
-    margin-top: 15px;
-    > div {
-      border-radius: 4px;
-      flex: 1;
-      margin-left: 15px;
-      background: url(../../assets/item_frame.png) no-repeat;
-      background-size: 100% 100%;
+    flex-direction: column;
+    min-width: 260px;
+
+    span {
       display: flex;
       align-items: center;
-      padding: 12px;
-      img {
-        width: 2.3vw;
-        // height:1.7vw;
+      gap: 10px;
+      font-size: 23px;
+      line-height: 1.2;
+      font-weight: 700;
+      letter-spacing: 0;
+      color: #f0fdff;
+      text-shadow: 0 0 18px rgba(34, 211, 238, 0.5);
+
+      &::before {
+        content: '';
+        width: 7px;
+        height: 26px;
+        border-radius: 2px;
+        background: linear-gradient(180deg, #67e8f9, #0ea5e9);
+        box-shadow: 0 0 14px rgba(34, 211, 238, 0.75);
       }
-      > div {
-        display: flex;
-        flex-direction: column;
-        // margin-left: 0.8vw;
-        justify-content: center;
-        align-items: center;
-        width: 80%;
-        span:nth-of-type(1) {
-          font-size: 0.75vw;
-        }
-        span:nth-of-type(2) {
-          font-weight: bold;
-          font-size: 1.2vw;
-          margin-top: 0.8vw;
-          span {
-            font-size: 0.7vw;
-          }
-        }
+    }
+
+    em {
+      margin-top: 4px;
+      font-style: normal;
+      font-size: 12px;
+      color: rgba(165, 243, 252, 0.72);
+      text-transform: uppercase;
+    }
+  }
+
+  .screen-filters {
+    position: relative;
+    z-index: 1;
+    display: flex;
+    align-items: center;
+    justify-content: flex-end;
+    flex-wrap: wrap;
+    gap: 10px;
+    padding: 4px;
+    border: 1px solid rgba(56, 189, 248, 0.18);
+    border-radius: 8px;
+    background: rgba(3, 12, 24, 0.28);
+    box-shadow:
+      inset 0 0 16px rgba(14, 165, 233, 0.08),
+      0 0 18px rgba(14, 165, 233, 0.08);
+  }
+
+  .mode-tabs {
+    :deep(.el-radio-button__inner) {
+      min-width: 72px;
+      height: 32px;
+      line-height: 30px;
+      padding: 0 18px;
+      border-color: rgba(56, 189, 248, 0.36);
+      color: rgba(224, 242, 254, 0.82);
+      background: rgba(8, 20, 35, 0.75);
+      box-shadow: none;
+    }
+
+    :deep(.el-radio-button__orig-radio:checked + .el-radio-button__inner) {
+      color: #06131f;
+      border-color: #22d3ee;
+      background: linear-gradient(135deg, #67e8f9, #38bdf8);
+      box-shadow: 0 0 18px rgba(56, 189, 248, 0.4);
+    }
+  }
+
+  .factory-select {
+    width: 180px;
+  }
+
+  .date-range {
+    width: 310px;
+  }
+
+  :deep(.el-input__inner) {
+    height: 32px;
+    color: #e0f7ff;
+    border-color: rgba(56, 189, 248, 0.34);
+    background: rgba(6, 18, 32, 0.82);
+  }
+
+  :deep(.el-input__inner::placeholder) {
+    color: rgba(191, 219, 254, 0.55);
+  }
+
+  :deep(.el-range-input) {
+    color: #e0f7ff;
+    background: transparent;
+  }
+
+  :deep(.el-range-separator),
+  :deep(.el-input__icon) {
+    color: rgba(125, 211, 252, 0.8);
+  }
+
+  .screen-grid {
+    flex: 1;
+    min-height: 0;
+  }
+
+  .main-col,
+  .side-col {
+    height: 58%;
+  }
+
+  .main-col {
+    display: flex;
+    flex-direction: column;
+    gap: 14px;
+  }
+
+  .table-col {
+    height: calc(42% - 14px);
+    margin-top: 14px;
+  }
+
+  .metrics-grid {
+    width: 100%;
+    min-height: 112px;
+    display: grid;
+    grid-template-columns: repeat(5, minmax(0, 1fr));
+    gap: 16px;
+  }
+
+  .metric-card {
+    position: relative;
+    overflow: hidden;
+    min-width: 0;
+    min-height: 112px;
+    padding: 16px 12px 14px;
+    display: flex;
+    flex-direction: column;
+    justify-content: space-between;
+    gap: 0;
+    border: 1px solid rgba(56, 189, 248, 0.38);
+    border-radius: 8px;
+    color: #7dd3fc;
+    background:
+      linear-gradient(135deg, rgba(14, 116, 144, 0.38), rgba(15, 23, 42, 0.88)),
+      linear-gradient(90deg, rgba(34, 211, 238, 0.1), transparent 55%),
+      repeating-linear-gradient(
+        90deg,
+        rgba(125, 211, 252, 0.035) 0,
+        rgba(125, 211, 252, 0.035) 1px,
+        transparent 1px,
+        transparent 28px
+      );
+    box-shadow:
+      inset 0 1px 0 rgba(165, 243, 252, 0.12),
+      inset 0 0 30px rgba(34, 211, 238, 0.09),
+      0 14px 28px rgba(0, 0, 0, 0.24);
+    transition: border-color 0.2s ease, box-shadow 0.2s ease, transform 0.2s ease;
+
+    &::before,
+    &::after {
+      content: '';
+      position: absolute;
+      pointer-events: none;
+    }
+
+    &::before {
+      inset: 0;
+      border-top: 3px solid rgba(103, 232, 249, 0.82);
+      border-left: 1px solid rgba(103, 232, 249, 0.12);
+      opacity: 0.75;
+    }
+
+    &::after {
+      width: 54px;
+      height: 54px;
+      right: -20px;
+      bottom: -18px;
+      border: 1px solid rgba(125, 211, 252, 0.24);
+      transform: rotate(45deg);
+      background: rgba(14, 165, 233, 0.1);
+    }
+  }
+
+  .metric-card:hover {
+    border-color: rgba(103, 232, 249, 0.6);
+    box-shadow:
+      inset 0 1px 0 rgba(165, 243, 252, 0.16),
+      inset 0 0 34px rgba(34, 211, 238, 0.13),
+      0 16px 32px rgba(0, 0, 0, 0.3),
+      0 0 18px rgba(14, 165, 233, 0.14);
+    transform: translateY(-1px);
+  }
+
+  .metric-card-3 {
+    color: #fb7185 !important;
+    border-color: rgba(251, 113, 133, 0.42);
+    background:
+      linear-gradient(135deg, rgba(190, 18, 60, 0.32), rgba(15, 23, 42, 0.88)),
+      linear-gradient(90deg, rgba(251, 113, 133, 0.12), transparent 55%);
+
+    &::before {
+      border-top-color: rgba(251, 113, 133, 0.72);
+    }
+  }
+
+  .metric-card-3 .metric-value {
+    color: #ff7890;
+    text-shadow:
+      0 0 10px rgba(251, 113, 133, 0.85),
+      0 0 22px rgba(251, 113, 133, 0.38);
+  }
+
+  .metric-icon {
+    flex: 0 0 40px;
+    width: 40px;
+    height: 40px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    border: 1px solid rgba(125, 211, 252, 0.12);
+    border-radius: 6px;
+    background: linear-gradient(135deg, rgba(8, 20, 35, 0.82), rgba(14, 116, 144, 0.18));
+    box-shadow:
+      inset 0 0 18px rgba(103, 232, 249, 0.14),
+      0 0 18px rgba(14, 165, 233, 0.14);
+
+    img {
+      width: 30px;
+      max-height: 30px;
+      object-fit: contain;
+      filter: drop-shadow(0 0 10px rgba(56, 189, 248, 0.55));
+    }
+  }
+
+  .metric-content {
+    position: relative;
+    z-index: 1;
+    min-width: 0;
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    justify-content: space-between;
+    gap: 14px;
+  }
+
+  .metric-label {
+    position: relative;
+    padding-left: 12px;
+    font-size: clamp(12px, 0.72vw, 14px);
+    line-height: 1.25;
+    color: rgba(224, 242, 254, 0.78);
+    white-space: nowrap;
+    overflow: hidden;
+    text-overflow: ellipsis;
+
+    &::before {
+      content: '';
+      position: absolute;
+      left: 0;
+      top: 50%;
+      width: 5px;
+      height: 5px;
+      border-radius: 50%;
+      background: #67e8f9;
+      box-shadow: 0 0 9px rgba(103, 232, 249, 0.9);
+      transform: translateY(-50%);
+    }
+  }
+
+  .metric-main {
+    min-width: 0;
+    display: grid;
+    grid-template-columns: 42px minmax(0, 1fr);
+    align-items: center;
+    gap: 10px;
+  }
+
+  .metric-value {
+    display: block;
+    width: 100%;
+    min-width: 0;
+    font-size: clamp(18px, 1.08vw, 24px);
+    line-height: 1;
+    font-weight: 700;
+    color: #8fe3ff;
+    white-space: nowrap;
+    overflow: visible;
+    text-overflow: clip;
+    font-variant-numeric: tabular-nums;
+    text-shadow:
+      0 0 10px rgba(56, 189, 248, 0.85),
+      0 0 22px rgba(56, 189, 248, 0.35);
+
+    span {
+      font-size: 10px;
+      color: rgba(224, 242, 254, 0.78);
+      text-shadow: none;
+    }
+  }
+
+  .screen-panel {
+    position: relative;
+    overflow: hidden;
+    height: 100%;
+    border: 1px solid rgba(56, 189, 248, 0.34);
+    border-radius: 8px;
+    color: #d9f7ff;
+    background:
+      linear-gradient(180deg, rgba(14, 36, 61, 0.92), rgba(6, 16, 30, 0.9)),
+      linear-gradient(135deg, rgba(34, 211, 238, 0.11), transparent 48%);
+    box-shadow:
+      inset 0 1px 0 rgba(165, 243, 252, 0.1),
+      inset 0 0 26px rgba(14, 165, 233, 0.1),
+      0 16px 34px rgba(0, 0, 0, 0.28);
+
+    &::before {
+      content: '';
+      position: absolute;
+      inset: 0;
+      pointer-events: none;
+      border-radius: inherit;
+      background:
+        linear-gradient(90deg, rgba(103, 232, 249, 0.6), transparent 72px) left top / 120px 1px no-repeat,
+        linear-gradient(180deg, rgba(103, 232, 249, 0.5), transparent 56px) left top / 1px 90px no-repeat,
+        linear-gradient(270deg, rgba(103, 232, 249, 0.42), transparent 72px) right bottom / 120px 1px no-repeat,
+        linear-gradient(0deg, rgba(103, 232, 249, 0.36), transparent 56px) right bottom / 1px 90px no-repeat;
+      opacity: 0.85;
+    }
+
+    &::after {
+      content: '';
+      position: absolute;
+      left: 16px;
+      right: 16px;
+      bottom: 0;
+      height: 1px;
+      pointer-events: none;
+      background: linear-gradient(90deg, transparent, rgba(34, 211, 238, 0.62), transparent);
+      opacity: 0.6;
+    }
+
+    :deep(.el-card__header) {
+      position: relative;
+      z-index: 1;
+      padding: 12px 16px;
+      border-bottom: 1px solid rgba(56, 189, 248, 0.2);
+      background: linear-gradient(90deg, rgba(8, 47, 73, 0.48), transparent);
+    }
+
+    :deep(.el-card__body) {
+      position: relative;
+      z-index: 1;
+      height: calc(100% - 48px);
+      padding: 10px 12px 12px;
+      background:
+        linear-gradient(rgba(125, 211, 252, 0.026) 1px, transparent 1px),
+        linear-gradient(90deg, rgba(125, 211, 252, 0.026) 1px, transparent 1px);
+      background-size: 28px 28px;
+    }
+  }
+
+  .panel-header {
+    display: flex;
+    align-items: center;
+    min-height: 24px;
+    justify-content: space-between;
+
+    > span {
+      position: relative;
+      padding-left: 12px;
+      font-size: 15px;
+      line-height: 1.3;
+      font-weight: 700;
+      color: #e0faff;
+      text-shadow: 0 0 12px rgba(34, 211, 238, 0.45);
+
+      &::before {
+        content: '';
+        position: absolute;
+        left: 0;
+        top: 50%;
+        width: 4px;
+        height: 16px;
+        border-radius: 2px;
+        background: linear-gradient(180deg, #67e8f9, #38bdf8);
+        transform: translateY(-50%);
+        box-shadow: 0 0 12px rgba(34, 211, 238, 0.8);
+      }
+    }
+
+    &::after {
+      content: '';
+      width: 72px;
+      height: 1px;
+      background: linear-gradient(90deg, rgba(103, 232, 249, 0.8), transparent);
+      opacity: 0.6;
+    }
+  }
+
+  .chart-panel {
+    flex: 1;
+    min-height: 0;
+  }
+
+  .screen-chart {
+    width: 100%;
+    height: 100%;
+  }
+
+  .chart-panel {
+    :deep(.el-card__body) {
+      background:
+        radial-gradient(circle at 28% 38%, rgba(34, 211, 238, 0.06), transparent 34%),
+        linear-gradient(rgba(125, 211, 252, 0.026) 1px, transparent 1px),
+        linear-gradient(90deg, rgba(125, 211, 252, 0.026) 1px, transparent 1px);
+      background-size: auto, 28px 28px, 28px 28px;
+    }
+  }
+
+  .pie-panel {
+    :deep(.el-card__body) {
+      background:
+        radial-gradient(circle at 52% 52%, rgba(56, 189, 248, 0.13), transparent 30%),
+        radial-gradient(circle at 52% 52%, rgba(15, 23, 42, 0.72), transparent 48%),
+        linear-gradient(rgba(125, 211, 252, 0.026) 1px, transparent 1px),
+        linear-gradient(90deg, rgba(125, 211, 252, 0.026) 1px, transparent 1px);
+      background-size: auto, auto, 28px 28px, 28px 28px;
+    }
+  }
+
+  .table-panel {
+    :deep(.el-card__body) {
+      padding: 10px 12px 12px;
+      background:
+        linear-gradient(180deg, rgba(5, 16, 30, 0.12), rgba(5, 16, 30, 0.34)),
+        repeating-linear-gradient(
+          90deg,
+          rgba(56, 189, 248, 0.02) 0,
+          rgba(56, 189, 248, 0.02) 1px,
+          transparent 1px,
+          transparent 72px
+        );
+    }
+
+    :deep(.ele-pro-table) {
+      height: 100%;
+      color: #dbeafe;
+      background:
+        linear-gradient(180deg, rgba(6, 20, 36, 0.86), rgba(3, 11, 22, 0.92)),
+        linear-gradient(90deg, rgba(56, 189, 248, 0.04), transparent);
+    }
+
+    :deep(.ele-pro-table-body),
+    :deep(.ele-pro-table-main),
+    :deep(.ele-table-tool-default),
+    :deep(.el-table__body-wrapper),
+    :deep(.el-table__fixed),
+    :deep(.el-table__fixed-right) {
+      background: rgba(3, 12, 24, 0.92) !important;
+    }
+
+    :deep(.el-table) {
+      overflow: hidden;
+      font-size: 12px;
+      color: #dbeafe;
+      background:
+        linear-gradient(180deg, rgba(6, 20, 36, 0.88), rgba(3, 11, 22, 0.94)),
+        repeating-linear-gradient(
+          90deg,
+          rgba(56, 189, 248, 0.022) 0,
+          rgba(56, 189, 248, 0.022) 1px,
+          transparent 1px,
+          transparent 72px
+        );
+      border: 1px solid rgba(125, 211, 252, 0.28);
+      box-shadow:
+        inset 0 0 18px rgba(14, 165, 233, 0.08),
+        0 0 18px rgba(14, 165, 233, 0.1);
+    }
+
+    :deep(.el-table .cell) {
+      line-height: 18px;
+      font-weight: 500;
+      letter-spacing: 0;
+    }
+
+    :deep(.el-table__header-wrapper) {
+      background: linear-gradient(180deg, rgba(13, 80, 105, 0.78), rgba(8, 47, 73, 0.72));
+    }
+
+    :deep(.el-table__empty-block) {
+      min-height: 214px;
+      background:
+        radial-gradient(circle at 50% 42%, rgba(34, 211, 238, 0.12), transparent 30%),
+        linear-gradient(180deg, rgba(6, 20, 36, 0.88), rgba(3, 11, 22, 0.96)) !important;
+    }
+
+    :deep(.el-table__empty-text) {
+      color: rgba(224, 242, 254, 0.72);
+      text-shadow: 0 0 12px rgba(56, 189, 248, 0.38);
+    }
+
+    :deep(.el-table__empty-text .el-empty__image) {
+      opacity: 0.74;
+      filter: drop-shadow(0 0 14px rgba(56, 189, 248, 0.3));
+    }
+
+    :deep(.el-loading-mask) {
+      background:
+        radial-gradient(circle at 50% 42%, rgba(34, 211, 238, 0.16), transparent 28%),
+        linear-gradient(180deg, rgba(5, 17, 31, 0.94), rgba(2, 8, 17, 0.96)) !important;
+      backdrop-filter: blur(1px);
+    }
+
+    :deep(.el-loading-spinner .path) {
+      stroke: #67e8f9;
+    }
+
+    :deep(.el-loading-spinner .el-loading-text) {
+      color: #c7fbff;
+    }
+
+    :deep(.el-table::before),
+    :deep(.el-table--border::after),
+    :deep(.el-table--group::after) {
+      background-color: rgba(56, 189, 248, 0.12);
+    }
+
+    :deep(.el-table th),
+    :deep(.el-table tr),
+    :deep(.el-table td) {
+      background: transparent !important;
+    }
+
+    :deep(.el-table th) {
+      height: 34px;
+      color: #c7fbff;
+      background: linear-gradient(180deg, rgba(14, 116, 144, 0.5), rgba(8, 47, 73, 0.72)) !important;
+      border-color: rgba(56, 189, 248, 0.22);
+      text-shadow: 0 0 10px rgba(103, 232, 249, 0.34);
+    }
+
+    :deep(.el-table td) {
+      height: 32px;
+      color: rgba(226, 232, 240, 0.78);
+      border-color: rgba(56, 189, 248, 0.1);
+    }
+
+    :deep(.el-table__body tr:nth-child(odd) > td) {
+      background: rgba(8, 30, 52, 0.26) !important;
+    }
+
+    :deep(.el-table__body tr:nth-child(even) > td) {
+      background: rgba(3, 14, 27, 0.16) !important;
+    }
+
+    :deep(.el-table__body tr:hover),
+    :deep(.el-table__body tr.hover-row),
+    :deep(.el-table__body tr.current-row) {
+      background: transparent !important;
+    }
+
+    :deep(.el-table--enable-row-hover .el-table__body tr:hover > td),
+    :deep(.el-table--enable-row-hover .el-table__body tr:hover > td.el-table__cell),
+    :deep(.el-table__body tr.hover-row > td),
+    :deep(.el-table__body tr.hover-row > td.el-table__cell),
+    :deep(.el-table__body tr.current-row > td),
+    :deep(.el-table__body tr.current-row > td.el-table__cell) {
+      color: #f8fafc !important;
+      background: linear-gradient(90deg, rgba(34, 211, 238, 0.2), rgba(14, 165, 233, 0.14)) !important;
+      box-shadow: inset 0 1px 0 rgba(125, 211, 252, 0.2), inset 0 -1px 0 rgba(125, 211, 252, 0.16);
+    }
+
+    :deep(.el-table__body tr:hover > td .cell),
+    :deep(.el-table__body tr.hover-row > td .cell),
+    :deep(.el-table__body tr.current-row > td .cell) {
+      color: #f8fafc !important;
+    }
+
+    :deep(.el-table__body-wrapper::-webkit-scrollbar) {
+      width: 8px;
+      height: 8px;
+    }
+
+    :deep(.el-table__body-wrapper::-webkit-scrollbar-thumb) {
+      border-radius: 8px;
+      background: rgba(56, 189, 248, 0.48);
+    }
+
+    :deep(.el-table__body-wrapper::-webkit-scrollbar-track) {
+      background: rgba(8, 20, 35, 0.72);
+    }
+  }
+
+  @media (max-width: 1400px) {
+    .metrics-grid {
+      grid-template-columns: repeat(3, minmax(0, 1fr));
+    }
+
+    .metric-card {
+      min-height: 108px;
+    }
+
+    .metric-value {
+      font-size: 22px;
+    }
+  }
+
+  @media (max-width: 992px) {
+    .mes-screen {
+      height: auto;
+      min-height: calc(100vh - 92px);
+      overflow: auto;
+    }
+
+    .screen-shell {
+      min-height: 0;
+    }
+
+    .screen-toolbar {
+      align-items: flex-start;
+      flex-direction: column;
+    }
+
+    .screen-filters {
+      width: 100%;
+      justify-content: flex-start;
+    }
+
+    .main-col,
+    .side-col,
+    .table-col {
+      height: auto;
+    }
+
+    .side-col,
+    .table-col {
+      margin-top: 14px;
+    }
+
+    .chart-panel,
+    .pie-panel {
+      height: 360px;
+    }
+
+    .table-panel {
+      height: 420px;
+    }
+  }
+
+  @media (max-width: 768px) {
+    .screen-shell {
+      padding: 10px;
+    }
+
+    .screen-title span {
+      font-size: 20px;
+    }
+
+    .metrics-grid {
+      grid-template-columns: repeat(2, minmax(0, 1fr));
+    }
+
+    .factory-select,
+    .date-range {
+      width: 100%;
+    }
+
+    .metric-value {
+      font-size: 24px;
+    }
+  }
+
+  @media (max-width: 520px) {
+    .metrics-grid {
+      grid-template-columns: 1fr;
+    }
+
+    .mode-tabs {
+      width: 100%;
+
+      :deep(.el-radio-button) {
+        width: 50%;
+      }
+
+      :deep(.el-radio-button__inner) {
+        width: 100%;
       }
     }
   }

+ 30 - 1
src/views/produce/components/feeding/components/batchProductsBom.vue

@@ -50,6 +50,12 @@
         >
       </template>
 
+      <template v-slot:reelSpecification="{ row, $index }">
+        <span>{{
+          row.extInfo.reelSpecification ? row.extInfo.reelSpecification : ''
+        }}</span>
+      </template>
+
       <template v-slot:newWeight="{ row, $index }">
         <el-input
           size="mini"
@@ -130,6 +136,7 @@
   import tabMixins from '@/mixins/tableColumnsMixin';
   import { splitBatch } from '@/api/produce/feeding';
   import EncodingDialog from '../../encodingDialog/index.vue';
+  import { parameterGetByCode } from '@/api/system/dictionary-data';
   export default {
     name: 'productsBom',
     mixins: [tabMixins],
@@ -167,7 +174,8 @@
         clientEnvironmentId: '',
         scanBuffer: '',
         lastScanTime: 0,
-        selection: []
+        selection: [],
+        isReelSpecification: false
       };
     },
 
@@ -189,6 +197,7 @@
       }
 
       this.autoAssignEngrave();
+      this.getReelSpecification();
 
       this._barcodeScanHandler = this.handleBarcodeScan.bind(this);
       document.addEventListener('keydown', this._barcodeScanHandler);
@@ -293,6 +302,18 @@
             slot: 'engrave',
             align: 'center'
           },
+          ...(this.isReelSpecification
+            ? [
+                {
+                  width: 150,
+                  prop: 'extInfo.reelSpecification',
+                  label: '盘具',
+                  slot: 'reelSpecification',
+                  align: 'center',
+                  showOverflowTooltip: true
+                }
+              ]
+            : []),
           {
             minWidth: 120,
             prop: 'extInfo',
@@ -373,6 +394,14 @@
           });
         }
       },
+
+      async getReelSpecification() {
+        await parameterGetByCode({
+          code: 'dishware_specifications'
+        }).then((res) => {
+          this.isReelSpecification = res.value == '1' ? true : false;
+        });
+      },
       handleBarcodePaste(e) {
         const text = (e.clipboardData || window.clipboardData)
           .getData('text')

+ 10 - 6
src/views/produce/components/jobBooking/components/batchPackagingGrouping.vue

@@ -141,7 +141,7 @@
                   </div>
 
                   <div class="rx ww55" v-if="isReelSpecification">
-                    <div class="lable lable200 rx-cc">盘具规格:</div>
+                    <div class="lable lable200 rx-cc">盘具:</div>
                     <div class="content content_num">
                       <el-input
                         class="uni-el-input"
@@ -359,7 +359,7 @@
               class="rx ww55"
               v-if="isReelSpecification && item.titel == '最小包装'"
             >
-              <div class="lable lable200 rx-cc">盘具规格</div>
+              <div class="lable lable200 rx-cc">盘具</div>
               <div class="content content_num">
                 <el-input
                   class="uni-el-input"
@@ -1714,7 +1714,8 @@
             };
           } else {
             packInfo = {
-              isUnpack: this.objData.isUnpack
+              isUnpack: this.objData.isUnpack,
+              reelSpecification: this.reelSpecification
             };
           }
         } else {
@@ -1739,7 +1740,8 @@
             } else {
               packInfo = {
                 tier: 1,
-                isUnpack: this.objData.isUnpack
+                isUnpack: this.objData.isUnpack,
+                reelSpecification: this.reelSpecification
               };
             }
           } else if (this.warehouseId == 3) {
@@ -1760,7 +1762,8 @@
               };
             } else {
               packInfo = {
-                isUnpack: this.objData.isUnpack
+                isUnpack: this.objData.isUnpack,
+                reelSpecification: this.reelSpecification
               };
             }
           } else if (this.warehouseId == 4) {
@@ -1782,7 +1785,8 @@
             } else {
               packInfo = {
                 tier: 1,
-                isUnpack: this.objData.isUnpack
+                isUnpack: this.objData.isUnpack,
+                reelSpecification: this.reelSpecification
               };
             }
           }

+ 27 - 0
src/views/produce/components/jobBooking/components/batchSemiProductJobBom.vue

@@ -100,6 +100,11 @@
           :disabled="isDetails || clientEnvironmentId == 9"
         />
       </template>
+      <template v-slot:reelSpecification="{ row }">
+        <span>{{
+          row.extInfo.reelSpecification ? row.extInfo.reelSpecification : ''
+        }}</span>
+      </template>
 
       <template v-slot:materielCode="{ row, $index }">
         <span v-if="isDetails">{{ row.extInfo.materielCode }}</span>
@@ -1142,6 +1147,18 @@
             align: 'center',
             showOverflowTooltip: true
           },
+          ...(this.isReelSpecification
+            ? [
+                {
+                  width: 150,
+                  prop: 'extInfo.reelSpecification',
+                  label: '盘具',
+                  slot: 'reelSpecification',
+                  align: 'center',
+                  showOverflowTooltip: true
+                }
+              ]
+            : []),
           {
             width: 150,
             prop: 'brandNum',
@@ -1252,6 +1269,7 @@
         clientEnvironmentId: '',
         scanBuffer: '',
         lastScanTime: 0,
+        isReelSpecification: false,
 
         resultObj: {},
         resultIdx: 0,
@@ -1371,6 +1389,14 @@
     },
 
     methods: {
+      async getReelSpecification() {
+        await parameterGetByCode({
+          code: 'dishware_specifications'
+        }).then((res) => {
+          this.isReelSpecification = res.value == '1' ? true : false;
+        });
+      },
+
       autoAssignEngrave() {
         if (this.clientEnvironmentId == 9) {
           this.list.forEach((item, index) => {
@@ -2192,6 +2218,7 @@
     created() {
       this.getTaskFn();
       this.getCompute();
+      this.getReelSpecification();
     }
   };
 </script>

+ 2 - 2
src/views/produce/components/jobBooking/components/detailPackagingGrouping.vue

@@ -119,7 +119,7 @@
                 </div>
 
                 <div class="rx ww55" v-if="isReelSpecification">
-                  <div class="lable lable200 rx-cc">盘具规格:</div>
+                  <div class="lable lable200 rx-cc">盘具:</div>
                   <div class="content content_num">
                     <el-input
                       class="uni-el-input"
@@ -244,7 +244,7 @@
             </div>
 
             <div class="rx ww55" v-if="isReelSpecification">
-              <div class="lable lable200 rx-cc">盘具规格:</div>
+              <div class="lable lable200 rx-cc">盘具:</div>
               <div class="content content_num">
                 <el-input
                   class="uni-el-input"

+ 34 - 0
src/views/produce/components/jobBooking/components/jobBom.vue

@@ -119,6 +119,19 @@
             </div>
           </div>
 
+          <div class="rx ww43" v-if="isReelSpecification && !isDetails">
+            <div class="lable lable100 rx-cc">盘具</div>
+            <div class="content content_num rx-sc">
+              <el-input
+                size="mini"
+                :disabled="isDetails"
+                v-model="item.workReportInfo.reelSpecification"
+                placeholder="请输入盘具"
+              >
+              </el-input>
+            </div>
+          </div>
+
           <div class="rx ww43" v-if="clientEnvironmentId == 2">
             <div class="lable lable100 rx-cc">批次号</div>
             <div class="content content_num rx-sc">
@@ -206,6 +219,7 @@
     createInProductBatchTG,
     createInProductBatch
   } from '@/api/produce/workOrder';
+  import { parameterGetByCode } from '@/api/system/dictionary-data';
 
   export default {
     props: {
@@ -305,6 +319,7 @@
     data() {
       return {
         notFormedList: [],
+        isReelSpecification: false,
 
         form: {
           warehouseId: null
@@ -324,6 +339,7 @@
           };
         });
       }
+      this.getReelSpecification();
     },
 
     mounted() {
@@ -331,6 +347,24 @@
     },
 
     methods: {
+      async getReelSpecification() {
+        await parameterGetByCode({
+          code: 'dishware_specifications'
+        }).then((res) => {
+          this.isReelSpecification = res.value == '1' ? true : false;
+          if (
+            this.isReelSpecification &&
+            this.item.workReportInfo &&
+            !Object.prototype.hasOwnProperty.call(
+              this.item.workReportInfo,
+              'reelSpecification'
+            )
+          ) {
+            this.$set(this.item.workReportInfo, 'reelSpecification', '');
+          }
+        });
+      },
+
       penalize() {
         this.visible = true;
       },

+ 33 - 0
src/views/produce/components/jobBooking/components/jobDdBom.vue

@@ -121,6 +121,18 @@
             </div>
           </div>
 
+          <div class="rx ww43" v-if="isReelSpecification && !isDetails">
+            <div class="lable lable100 rx-cc">盘具</div>
+            <div class="content content_num rx-sc">
+              <el-input
+                size="mini"
+                v-model="item.workReportInfo.reelSpecification"
+                placeholder="请输入盘具"
+              >
+              </el-input>
+            </div>
+          </div>
+
           <div class="rx ww43" v-if="clientEnvironmentId == 2">
             <div class="lable lable100 rx-cc">批次号</div>
             <div class="content content_num rx-sc">
@@ -155,6 +167,7 @@
 </template>
 <script>
   import { createInProduct } from '@/api/produce/workOrder';
+  import { parameterGetByCode } from '@/api/system/dictionary-data';
 
   import checkbox from './checkbox.vue';
   export default {
@@ -251,6 +264,7 @@
       return {
         list: [],
         notFormedList: [],
+        isReelSpecification: false,
 
         form: {
           warehouseId: null
@@ -270,9 +284,28 @@
           };
         });
       }
+      this.getReelSpecification();
     },
 
     methods: {
+      async getReelSpecification() {
+        await parameterGetByCode({
+          code: 'dishware_specifications'
+        }).then((res) => {
+          this.isReelSpecification = res.value == '1' ? true : false;
+          if (
+            this.isReelSpecification &&
+            this.item.workReportInfo &&
+            !Object.prototype.hasOwnProperty.call(
+              this.item.workReportInfo,
+              'reelSpecification'
+            )
+          ) {
+            this.$set(this.item.workReportInfo, 'reelSpecification', '');
+          }
+        });
+      },
+
       getSemiProductList(newVal) {
         console.log(newVal);
         if (newVal.semiProductList.length) {

+ 27 - 0
src/views/produce/components/jobBooking/components/semiProductJobBom.vue

@@ -115,6 +115,11 @@
           :disabled="isDetails || clientEnvironmentId == 9"
         />
       </template>
+      <template v-slot:reelSpecification="{ row }">
+        <span>{{
+          row.extInfo.reelSpecification ? row.extInfo.reelSpecification : ''
+        }}</span>
+      </template>
 
       <template v-slot:materielCode="{ row, $index }">
         <span v-if="isDetails">{{ row.extInfo.materielCode }}</span>
@@ -727,6 +732,7 @@
         printData: {},
         printStyle: '',
         dialogWeight: false,
+        isReelSpecification: false,
         weightForm: {
           weight: ''
         }
@@ -1014,6 +1020,18 @@
             align: 'center',
             showOverflowTooltip: true
           },
+          ...(this.isReelSpecification
+            ? [
+                {
+                  width: 150,
+                  prop: 'extInfo.reelSpecification',
+                  label: '盘具',
+                  slot: 'reelSpecification',
+                  align: 'center',
+                  showOverflowTooltip: true
+                }
+              ]
+            : []),
           {
             width: 150,
             prop: 'brandNum',
@@ -1088,6 +1106,14 @@
     // item
 
     methods: {
+      async getReelSpecification() {
+        await parameterGetByCode({
+          code: 'dishware_specifications'
+        }).then((res) => {
+          this.isReelSpecification = res.value == '1' ? true : false;
+        });
+      },
+
       autoAssignEngrave() {
         if (this.clientEnvironmentId == 9) {
           this.list.forEach((item, index) => {
@@ -1758,6 +1784,7 @@
       console.log(this.item, '列表数据123');
       this.getTaskFn();
       this.getCompute();
+      this.getReelSpecification();
     }
   };
 </script>

+ 34 - 0
src/views/produce/components/warehousing/components/jobBom.vue

@@ -169,6 +169,19 @@
             </div>
           </div>
 
+          <div class="rx ww43" v-if="isReelSpecification && !isDetails">
+            <div class="lable lable100 rx-cc">盘具</div>
+            <div class="content content_num rx-sc">
+              <el-input
+                size="mini"
+                :disabled="isDetails"
+                v-model="item.workReportInfo.reelSpecification"
+                placeholder="请输入盘具"
+              >
+              </el-input>
+            </div>
+          </div>
+
           <div class="rx ww43" v-if="clientEnvironmentId == 2">
             <div class="lable lable100 rx-cc">批次号</div>
             <div class="content content_num rx-sc">
@@ -225,6 +238,7 @@
     createInProductBatchTG,
     createInProductBatch
   } from '@/api/produce/workOrder';
+  import { parameterGetByCode } from '@/api/system/dictionary-data';
 
   export default {
     props: {
@@ -325,6 +339,7 @@
     data() {
       return {
         notFormedList: [],
+        isReelSpecification: false,
 
         form: {
           warehouseId: null
@@ -344,6 +359,7 @@
           };
         });
       }
+      this.getReelSpecification();
       // if(item.semiProductList){
       //   let allReportWeight=0
       //    item.semiProductList.map(sitem=>{
@@ -362,6 +378,24 @@
     },
 
     methods: {
+      async getReelSpecification() {
+        await parameterGetByCode({
+          code: 'dishware_specifications'
+        }).then((res) => {
+          this.isReelSpecification = res.value == '1' ? true : false;
+          if (
+            this.isReelSpecification &&
+            this.item.workReportInfo &&
+            !Object.prototype.hasOwnProperty.call(
+              this.item.workReportInfo,
+              'reelSpecification'
+            )
+          ) {
+            this.$set(this.item.workReportInfo, 'reelSpecification', '');
+          }
+        });
+      },
+
       penalize() {
         this.visible = true;
       },

+ 33 - 0
src/views/produce/components/warehousing/components/jobDdBom.vue

@@ -126,6 +126,18 @@
             </div>
           </div>
 
+          <div class="rx ww43" v-if="isReelSpecification && !isDetails">
+            <div class="lable lable100 rx-cc">盘具</div>
+            <div class="content content_num rx-sc">
+              <el-input
+                size="mini"
+                v-model="item.workReportInfo.reelSpecification"
+                placeholder="请输入盘具"
+              >
+              </el-input>
+            </div>
+          </div>
+
           <div class="rx ww43" v-if="clientEnvironmentId == 2">
             <div class="lable lable100 rx-cc">批次号</div>
             <div class="content content_num rx-sc">
@@ -194,6 +206,7 @@
 </template>
 <script>
   import { createInProduct, getWarehouseList } from '@/api/produce/workOrder';
+  import { parameterGetByCode } from '@/api/system/dictionary-data';
 
   export default {
     props: {
@@ -297,6 +310,7 @@
         warehouseDataList: [],
 
         visible: false,
+        isReelSpecification: false,
         warehouseId: '',
         inWarehouseSpecType: '',
         WarehouseSpecTypeList: [
@@ -334,6 +348,7 @@
 
       console.log(this.item, 'item');
       console.log(this.notFormedList, 'notFormedList');
+      this.getReelSpecification();
     },
 
     // async mounted() {
@@ -341,6 +356,24 @@
     // },
 
     methods: {
+      async getReelSpecification() {
+        await parameterGetByCode({
+          code: 'dishware_specifications'
+        }).then((res) => {
+          this.isReelSpecification = res.value == '1' ? true : false;
+          if (
+            this.isReelSpecification &&
+            this.item.workReportInfo &&
+            !Object.prototype.hasOwnProperty.call(
+              this.item.workReportInfo,
+              'reelSpecification'
+            )
+          ) {
+            this.$set(this.item.workReportInfo, 'reelSpecification', '');
+          }
+        });
+      },
+
       getSemiProductList(newVal) {
         console.log(newVal);
         if (newVal.semiProductList.length) {

+ 33 - 0
src/views/produce/components/warehousing/components/newJobDdBom.vue

@@ -126,6 +126,18 @@
             </div>
           </div>
 
+          <div class="rx ww43" v-if="isReelSpecification && !isDetails">
+            <div class="lable lable100 rx-cc">盘具</div>
+            <div class="content content_num rx-sc">
+              <el-input
+                size="mini"
+                v-model="item.workReportInfo.reelSpecification"
+                placeholder="请输入盘具"
+              >
+              </el-input>
+            </div>
+          </div>
+
           <div class="rx ww43" v-if="clientEnvironmentId == 2">
             <div class="lable lable100 rx-cc">批次号</div>
             <div class="content content_num rx-sc">
@@ -194,6 +206,7 @@
 </template>
 <script>
   import { createInProduct, getWarehouseList } from '@/api/produce/workOrder';
+  import { parameterGetByCode } from '@/api/system/dictionary-data';
 
   export default {
     props: {
@@ -378,6 +391,7 @@
         warehouseDataList: [],
 
         visible: false,
+        isReelSpecification: false,
         warehouseId: '',
         inWarehouseSpecType: '',
         WarehouseSpecTypeList: [
@@ -415,6 +429,7 @@
 
       console.log(this.item, 'item');
       console.log(this.notFormedList, 'notFormedList');
+      this.getReelSpecification();
     },
 
     async mounted() {
@@ -422,6 +437,24 @@
     },
 
     methods: {
+      async getReelSpecification() {
+        await parameterGetByCode({
+          code: 'dishware_specifications'
+        }).then((res) => {
+          this.isReelSpecification = res.value == '1' ? true : false;
+          if (
+            this.isReelSpecification &&
+            this.item.workReportInfo &&
+            !Object.prototype.hasOwnProperty.call(
+              this.item.workReportInfo,
+              'reelSpecification'
+            )
+          ) {
+            this.$set(this.item.workReportInfo, 'reelSpecification', '');
+          }
+        });
+      },
+
       getSemiProductList(newVal) {
         console.log(newVal);
         if (newVal.semiProductList.length) {

+ 73 - 1
src/views/warehousing/components/tgDetails.vue

@@ -85,6 +85,14 @@
       <template v-slot:engrave="{ row }">
         {{ row.extInfo.engrave }}
       </template>
+
+      <template v-slot:reelSpecification="{ row }">
+        {{
+          row.extInfo && row.extInfo.reelSpecification
+            ? row.extInfo.reelSpecification
+            : ''
+        }}
+      </template>
     </ele-pro-table>
 
     <ele-pro-table
@@ -98,6 +106,14 @@
       <template v-slot:quantity="{ row }">
         {{ row.quantity }}
       </template>
+
+      <template v-slot:reelSpecification="{ row }">
+        {{
+          row.extInfo && row.extInfo.reelSpecification
+            ? row.extInfo.reelSpecification
+            : ''
+        }}
+      </template>
     </ele-pro-table>
 
     <ele-pro-table
@@ -123,6 +139,14 @@
       <template v-slot:engrave="{ row }">
         {{ row.extInfo.engrave }}
       </template>
+
+      <template v-slot:reelSpecification="{ row }">
+        {{
+          row.extInfo && row.extInfo.reelSpecification
+            ? row.extInfo.reelSpecification
+            : ''
+        }}
+      </template>
     </ele-pro-table>
 
     <ele-pro-table
@@ -152,11 +176,21 @@
       <template v-slot:engrave="{ row }">
         {{ row.extInfo.engrave }}
       </template>
+
+      <template v-slot:reelSpecification="{ row }">
+        {{
+          row.extInfo && row.extInfo.reelSpecification
+            ? row.extInfo.reelSpecification
+            : ''
+        }}
+      </template>
     </ele-pro-table>
   </ele-modal>
 </template>
 
 <script>
+  import { parameterGetByCode } from '@/api/system/dictionary-data';
+
   export default {
     computed: {
       clientEnvironmentId() {
@@ -168,6 +202,7 @@
         visible: false,
         tableList: [],
         row: {},
+        isReelSpecification: false,
         columns: [
           {
             label: '序号',
@@ -346,8 +381,45 @@
         ]
       };
     },
-    created() {},
+    created() {
+      this.getReelSpecification();
+    },
     methods: {
+      async getReelSpecification() {
+        await parameterGetByCode({
+          code: 'dishware_specifications'
+        }).then((res) => {
+          this.isReelSpecification = res.value == '1' ? true : false;
+          this.setReelSpecificationColumn();
+        });
+      },
+
+      setReelSpecificationColumn() {
+        const column = {
+          label: '盘具',
+          slot: 'reelSpecification',
+          prop: 'extInfo.reelSpecification',
+          showOverflowTooltip: true
+        };
+        const insertColumn = (columns) => {
+          const hasColumn = columns.some((item) => item.prop === column.prop);
+          if (this.isReelSpecification && !hasColumn) {
+            const index = columns.findIndex(
+              (item) => item.slot === 'materielCode'
+            );
+            columns.splice(index === -1 ? columns.length : index, 0, column);
+          }
+          if (!this.isReelSpecification && hasColumn) {
+            columns.splice(
+              columns.findIndex((item) => item.prop === column.prop),
+              1
+            );
+          }
+        };
+        insertColumn(this.columns);
+        insertColumn(this.columns2);
+      },
+
       open(row) {
         console.log(row, 'row++++++++++');