huang
2025-05-20 2c2413760b6467bf62402dba7338bd3bbcbd7341
添加产量报表功能页面
8个文件已修改
1个文件已添加
1479 ■■■■ 已修改文件
JiuMuMesParent/moduleService/DeviceInteractionModule/src/main/java/com/mes/md/controller/TaskingLogController.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
JiuMuMesParent/moduleService/DeviceInteractionModule/src/main/java/com/mes/md/service/TaskingLogService.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
JiuMuMesParent/moduleService/DeviceInteractionModule/src/main/java/com/mes/md/service/impl/TaskingLogServiceImpl.java 149 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
UI-Project/src/lang/zh.js 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
UI-Project/src/main.js 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
UI-Project/src/router/index.js 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
UI-Project/src/views/KanbanData/kanbanData.vue 206 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
UI-Project/src/views/KanbanDisplay2/kanbanDisplay2.vue 739 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
UI-Project/src/views/MechanicalReport/mechanicalReport.vue 314 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
JiuMuMesParent/moduleService/DeviceInteractionModule/src/main/java/com/mes/md/controller/TaskingLogController.java
@@ -1,12 +1,14 @@
package com.mes.md.controller;
import com.mes.md.service.TaskingLogService;
import com.mes.utils.Result;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.bind.annotation.*;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
@@ -23,6 +25,31 @@
    @Autowired
    TaskingLogService taskingLogService;
    @ApiOperation("查询报表")
    @PostMapping("/mechanicalReport")
    @ResponseBody
    public Result mechanicalReport(
            @RequestParam(required = false) Integer dayCount,
            @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date startDate,
            @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date endDate,
            @RequestParam(required = false) String taskType,
            @RequestParam(required = false) String operationRecord,
            @RequestParam(required = false) String lineType) {
        try {
            List<Map> result = taskingLogService.selectMechanicalReport(
                dayCount,
                startDate,
                endDate,
                taskType,
                operationRecord,
                lineType
            );
            return Result.build(200, "查询成功", result);
        } catch (Exception e) {
            return Result.build(199, "查询异常", null);
        }
    }
    @ApiOperation("提交日志以及报工数据到九牧数据库")
    @PostMapping("/reportTaskingLog")
@@ -59,6 +86,5 @@
            return Result.build(199,"提交异常",map);
        }
    }
}
JiuMuMesParent/moduleService/DeviceInteractionModule/src/main/java/com/mes/md/service/TaskingLogService.java
@@ -4,6 +4,7 @@
import com.mes.md.entity.TaskLog;
import com.mes.md.entity.TaskingLog;
import java.util.Date;
import java.util.List;
import java.util.Map;
@@ -21,6 +22,19 @@
     * 查询完工数量-分线路
     */
    List<Map> selectTaskingLog(int dayCount);
    /**
     * 查询产量
     * @param dayCount 天数
     * @param startDate 开始日期
     * @param endDate 结束日期
     * @param taskType 任务类型
     * @param operationRecord 设备
     * @param lineType 生产线(1:一线,2:二线)
     * @return 产量数据列表
     */
    List<Map> selectMechanicalReport(int dayCount, Date startDate, Date endDate, String taskType, String operationRecord, String lineType);
    /**
     * 回传报工数据+ 设备玻璃过片记录给 九牧
     */
JiuMuMesParent/moduleService/DeviceInteractionModule/src/main/java/com/mes/md/service/impl/TaskingLogServiceImpl.java
@@ -35,6 +35,60 @@
    @Autowired
    KBBTJPDrawingBPMapper kBBTJPDrawingBPMapper;
    @Override
    public List<Map> selectMechanicalReport(int dayCount, Date startDate, Date endDate, String taskType, String operationRecord, String lineType) {
        try {
            // 构建查询条件
            QueryWrapper<TaskingLog> taskingWrapper = new QueryWrapper<>();
            // 添加完工状态过滤
            taskingWrapper.eq("work_state", "完工");
            // 时间范围处理
            if (startDate != null && endDate != null) {
                taskingWrapper.ge("operation_record_time", startDate)
                        .le("operation_record_time", endDate);
            } else if (dayCount > 0) {
                // 如果没有时间范围,使用默认的dayCount
                Calendar cal = Calendar.getInstance();
                cal.setTime(new Date());
                cal.set(Calendar.HOUR_OF_DAY, 0);
                cal.set(Calendar.MINUTE, 0);
                cal.set(Calendar.SECOND, 0);
                cal.set(Calendar.MILLISECOND, 0);
                cal.add(Calendar.DATE, 1 - dayCount);
                Date defaultStartDate = cal.getTime();
                Date defaultEndDate = new Date();
                taskingWrapper.ge("operation_record_time", defaultStartDate)
                        .le("operation_record_time", defaultEndDate);
            }
            // 添加可选条件
            if (taskType != null && !taskType.isEmpty()) {
                taskingWrapper.eq("task_type", taskType);
            }
            if (operationRecord != null && !operationRecord.isEmpty()) {
                taskingWrapper.like("operation_record", operationRecord);
            }
            if (lineType != null && !lineType.isEmpty()) {
                taskingWrapper.apply("operation_record REGEXP '.*[^0-9]" + lineType + "$'");
            }
            // 按时间排序
            taskingWrapper.orderByDesc("operation_record_time");
            // 执行查询
            List<Map<String, Object>> taskingList = baseMapper.selectMaps(taskingWrapper);
            // 直接返回查询结果
            return new ArrayList<>(taskingList);
        } catch (Exception e) {
            log.error("查询异常", e);
            throw e;
        }
    }
    public List<TaskingLog> findTaskingLog(){
        return new ArrayList<TaskingLog>();
    }
@@ -61,19 +115,78 @@
        List<Map> list=kBBTJPDrawingBPMapper.selectMaps((QueryWrapper)queryWrapper);
        List<Map<String, Object>> listTasking1 = baseMapper.selectMaps(new QueryWrapper<TaskingLog>()
                .select("operation_record,operation_mode,DATE_FORMAT(operation_record_time, '%Y-%m-%d') as operation_record_time,count(1) as count")
                .select("task_type, operation_record, operation_mode, DATE_FORMAT(operation_record_time, '%Y-%m-%d') as operation_record_time, count(*) as count")
                .eq("task_type", "定制")
                .eq("operation_record", "旋转1")
                .eq("operation_mode", "结束")
                .gt("operation_record_time", startDate)
                .groupBy("operation_record", "operation_mode", "DATE_FORMAT(operation_record_time, '%Y-%m-%d')")
                .groupBy("task_type", "operation_record", "operation_mode", "DATE_FORMAT(operation_record_time, '%Y-%m-%d')")
                .orderByAsc("DATE_FORMAT(operation_record_time, '%Y-%m-%d')"));
        List<Map<String, Object>> listTasking2 = baseMapper.selectMaps(new QueryWrapper<TaskingLog>()
                .select("operation_record,operation_mode,DATE_FORMAT(operation_record_time, '%Y-%m-%d') as operation_record_time,count(1) as count")
                .select("task_type,operation_record,operation_mode,DATE_FORMAT(operation_record_time, '%Y-%m-%d') as operation_record_time,count(1) as count")
                .eq("task_type", "定制")
                .eq("operation_record", "旋转2")
                .eq("operation_mode", "结束")
                .gt("operation_record_time", startDate)
                .groupBy("operation_record", "operation_mode", "DATE_FORMAT(operation_record_time, '%Y-%m-%d')")
                .groupBy("task_type", "operation_record", "operation_mode", "DATE_FORMAT(operation_record_time, '%Y-%m-%d')")
                .orderByAsc("DATE_FORMAT(operation_record_time, '%Y-%m-%d')"));
        //标准上片记录
        List<Map<String, Object>> loadTaskingList1 = baseMapper.selectMaps(new QueryWrapper<TaskingLog>()
                .select("task_type, operation_record, operation_mode, DATE_FORMAT(operation_record_time, '%Y-%m-%d') as operation_record_time, count(*) as count")
                .eq("task_type", "标准")
                .eq("operation_record", "上片1")
                .eq("operation_mode", "结束")
                .gt("operation_record_time", startDate)
                .groupBy("task_type", "operation_record", "operation_mode", "DATE_FORMAT(operation_record_time, '%Y-%m-%d')")
                .orderByAsc("DATE_FORMAT(operation_record_time, '%Y-%m-%d')"));
        List<Map<String, Object>> loadTaskingList2 = baseMapper.selectMaps(new QueryWrapper<TaskingLog>()
                .select("task_type, operation_record, operation_mode, DATE_FORMAT(operation_record_time, '%Y-%m-%d') as operation_record_time, count(*) as count")
                .eq("task_type", "标准")
                .eq("operation_record", "上片2")
                .eq("operation_mode", "结束")
                .gt("operation_record_time", startDate)
                .groupBy("task_type", "operation_record", "operation_mode", "DATE_FORMAT(operation_record_time, '%Y-%m-%d')")
                .orderByAsc("DATE_FORMAT(operation_record_time, '%Y-%m-%d')"));
        // 存储每条线路的数据
        Map<String, Map<String, Integer>> lineDataMap = new HashMap<>();
        lineDataMap.put("line1", new HashMap<>());
        lineDataMap.put("line2", new HashMap<>());
        // 处理第一条线路数据
        // 处理旋转1结束记录
        for (Map<String, Object> map : listTasking1) {
            String date = map.get("operation_record_time").toString();
            int count = Integer.parseInt(map.get("count").toString());
            Map<String, Integer> line1Map = lineDataMap.get("line1");
            line1Map.put(date, line1Map.getOrDefault(date, 0) + count);
        }
        // 处理线路1上片记录
        for (Map<String, Object> map : loadTaskingList1) {
            String date = map.get("operation_record_time").toString();
            int count = Integer.parseInt(map.get("count").toString());
            Map<String, Integer> line1Map = lineDataMap.get("line1");
            line1Map.put(date, line1Map.getOrDefault(date, 0) + count);
        }
        // 处理第二条线路数据
        // 处理旋转2结束记录
        for (Map<String, Object> map : listTasking2) {
            String date = map.get("operation_record_time").toString();
            int count = Integer.parseInt(map.get("count").toString());
            Map<String, Integer> line2Map = lineDataMap.get("line2");
            line2Map.put(date, line2Map.getOrDefault(date, 0) + count);
        }
        // 处理线路2上片记录
        for (Map<String, Object> map : loadTaskingList2) {
            String date = map.get("operation_record_time").toString();
            int count = Integer.parseInt(map.get("count").toString());
            Map<String, Integer> line2Map = lineDataMap.get("line2");
            line2Map.put(date, line2Map.getOrDefault(date, 0) + count);
        }
        //log.info("客户表计划量:{},{},{}",list,listTasking1,listTasking2);
        List<Map> Result=new ArrayList<>();
        for (int i=0;i<dayCount;i++){
@@ -84,28 +197,14 @@
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            String dateString = sdf.format(thisdate);
            thisMap.put("date",dateString);
            if (listTasking1.size()>0&&listTasking1.get(0).get("operation_record_time").toString().equals(dateString)){
            // 获取一线数据
            thisMap.put("line1", lineDataMap.get("line1").getOrDefault(dateString, 0));
            // 获取二线数据
            thisMap.put("line2", lineDataMap.get("line2").getOrDefault(dateString, 0));
                thisMap.put("line1",listTasking1.get(0).get("count"));
                listTasking1.remove(0);
            }else{
                thisMap.put("line1",0);
            }
            if (listTasking2.size()>0&&listTasking2.get(0).get("operation_record_time").toString().equals(dateString)){
                thisMap.put("line2",listTasking2.get(0).get("count"));
                listTasking2.remove(0);
            }else{
                thisMap.put("line2",0);
            }
//            if(list.size()>0){
//                log.info("对比:{},{},{}",
//                        list.get(0).get("CreateDate"),
//                        dateString,
//                        list.get(0).get("CreateDate").toString().equals(dateString));
//            }
            if (list.size()>0&&list.get(0).get("CreateDate").toString().equals(dateString)){
            if (list.size()>0 && list.get(0).get("CreateDate").toString().equals(dateString)){
                thisMap.put("plan",list.get(0).get("task_quantity_sum"));
                list.remove(0);
            }else{
UI-Project/src/lang/zh.js
@@ -150,7 +150,8 @@
        sendContent: '发送内容',
        warehouse:'仓库',
        notCompleteCount:'未完成量',
        notCompleteArea:'未完成面积'
        notCompleteArea:'未完成面积',
        OrderNo:'订单号'
    },
    machine: {
        mechanicalArm:'自动上片机',
UI-Project/src/main.js
@@ -8,7 +8,9 @@
import 'element-plus/dist/index.css'
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
import VXETable from 'vxe-table'
import { VxeButton, VxeLoading, VxeTooltip } from 'vxe-pc-ui'
import 'vxe-table/lib/style.css'
import 'vxe-pc-ui/lib/style.css'
import i18n from '@/lang'
import Echarts from "vue-echarts"
import * as echarts from "echarts";
@@ -22,16 +24,19 @@
const app = createApp(App)
app.component('v-chart', echarts)
//app.config.globalProperties.$echarts = echarts
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
  app.component(key, component)
}
const pinia = createPinia()
pinia.use(piniaPluginPersistedstate )
app.use(VXETable)
app.use(pinia)
app.use(router)
app.use(VxeButton)
app.use(VxeLoading)
app.use(VxeTooltip)
// app.use(ElementPlus)
app.use(ElementPlus,{
    locale: zhCn,
UI-Project/src/router/index.js
@@ -93,11 +93,13 @@
          path: 'KanbanDisplay2/kanbanDisplay2',
          name: 'kanbanDisplay2',
          component: () => import('../views/KanbanDisplay2/kanbanDisplay2.vue'),
          props: true,
          children: [
            {
              path: '/KanbanDisplay2/kanbanDisplay2',
              name: 'kanbanDisplay2',
              component: () => import('../views/KanbanDisplay2/kanbanDisplay2.vue'),
              props: true
            }
          ]
        },
@@ -115,6 +117,19 @@
          ]
        },
        {
          /*----------- 报表 ----------------*/
          path: 'MechanicalReport/mechanicalReport',
          name: 'mechanicalReport',
          component: () => import('../views/MechanicalReport/mechanicalReport.vue'),
          children: [
            {
              path: '/MechanicalReport/mechanicalReport',
              name: 'mechanicalReport',
              component: () => import('../views/MechanicalReport/mechanicalReport.vue'),
            }
          ]
        },
        {
          /*----------- 设备状态 ----------------*/
          path: 'MechanicalMonitor/mechanicalMonitor',
          name: 'mechanicalMonitor',
UI-Project/src/views/KanbanData/kanbanData.vue
@@ -2,9 +2,25 @@
import { ref, onMounted, onBeforeUnmount } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import request from '@/utils/request'
import { useRoute, useRouter } from 'vue-router'
const router = useRouter()
const route = useRoute()
// 加载初始数据
onMounted(() => {
  // 从localStorage获取存储的目标值
  yieldTargetValue1.value = localStorage.getItem('yieldTarget1') ? Number(localStorage.getItem('yieldTarget1')) : 0
  yieldTargetValue2.value = localStorage.getItem('yieldTarget2') ? Number(localStorage.getItem('yieldTarget2')) : 0
  utilizationTargetValue1.value = localStorage.getItem('utilizationTarget1') ? Number(localStorage.getItem('utilizationTarget1')) : 0
  utilizationTargetValue2.value = localStorage.getItem('utilizationTarget2') ? Number(localStorage.getItem('utilizationTarget2')) : 0
  quantityTargetValue1.value = localStorage.getItem('quantityTarget1') ? Number(localStorage.getItem('quantityTarget1')) : 0
  quantityTargetValue2.value = localStorage.getItem('quantityTarget2') ? Number(localStorage.getItem('quantityTarget2')) : 0
  quantityTargetValue3.value = localStorage.getItem('quantityTarget3') ? Number(localStorage.getItem('quantityTarget3')) : 0
  // 加载其他数据
  loadYieldData()
  loadUtilizationData()
  loadQuantityData()
@@ -54,6 +70,8 @@
  lineNo: '',
  yieldvalue: null
})
const yieldTargetValue1 = ref() // 一线目标值
const yieldTargetValue2 = ref() // 二线目标值
const yieldData = ref([])
const yieldLoading = ref(false)
@@ -63,6 +81,8 @@
  lineNo: '',
  utilizationRate: null
})
const utilizationTargetValue1 = ref() // 标准线目标值
const utilizationTargetValue2 = ref() // 定制线目标值
const utilizationData = ref([])
const utilizationLoading = ref(false)
@@ -79,6 +99,9 @@
  locationCode: '',
  quantity: null
})
const quantityTargetValue1 = ref(4000) // 半成品目标值
const quantityTargetValue2 = ref(4000) // 7014目标值
const quantityTargetValue3 = ref(4000) // 7016目标值
const quantityData = ref([])
const quantityLoading = ref(false)
@@ -235,9 +258,9 @@
  }
  try {
    const recordTimeStr = `${yieldFormData.value.recordDate} 00:00:00`;
    const recordTimeStr = `${yieldFormData.value.recordDate} 00:00:00`
    
    await request({
    const res = await request({
      url: '/deviceInteraction/yield/addYield',
      method: 'post',
      data: {
@@ -245,9 +268,14 @@
        recordTime: recordTimeStr
      }
    })
    ElMessage.success('添加成功')
    resetYieldForm()
    loadYieldData() // 刷新数据
    if (res.code === 200) {
      ElMessage.success('添加成功')
      resetYieldForm()
      loadYieldData() // 刷新数据
    } else {
      ElMessage.error(res.message || '添加失败')
    }
  } catch (error) {
    ElMessage.error('添加失败')
    console.error(error)
@@ -266,9 +294,9 @@
  }
  try {
    const recordTimeStr = `${utilizationFormData.value.recordDate} 00:00:00`;
    const recordTimeStr = `${utilizationFormData.value.recordDate} 00:00:00`
    
    await request({
    const res = await request({
      url: '/deviceInteraction/utilization/addUtilization',
      method: 'post',
      data: {
@@ -276,9 +304,14 @@
        recordTime: recordTimeStr
      }
    })
    ElMessage.success('添加成功')
    resetUtilizationForm()
    loadUtilizationData() // 刷新数据
    if (res.code === 200) {
      ElMessage.success('添加成功')
      resetUtilizationForm()
      loadUtilizationData() // 刷新数据
    } else {
      ElMessage.error(res.message || '添加失败')
    }
  } catch (error) {
    ElMessage.error('添加失败')
    console.error(error)
@@ -297,14 +330,9 @@
  }
  try {
    // 拼接日期时间字符串,确保是当天的00:00:00
    const dateStr = quantityFormData.value.recordDate;
    const recordTimeStr = `${dateStr} 00:00:00`;
    const recordTimeStr = `${quantityFormData.value.recordDate} 00:00:00`
    
    const locationCode = quantityFormData.value.locationCode;
    await request({
    const res = await request({
      url: '/deviceInteraction/quantity/addQuantity',
      method: 'post',
      data: {
@@ -312,9 +340,14 @@
        recordTime: recordTimeStr
      }
    })
    ElMessage.success('添加成功')
    resetQuantityForm()
    loadQuantityData() // 刷新数据
    if (res.code === 200) {
      ElMessage.success('添加成功')
      resetQuantityForm()
      loadQuantityData() // 刷新数据
    } else {
      ElMessage.error(res.message || '添加失败')
    }
  } catch (error) {
    ElMessage.error('添加失败')
    console.error(error)
@@ -358,7 +391,7 @@
// 重置表单
const resetYieldForm = () => {
  yieldFormData.value = {
    recordDate: yieldFormData.value.recordDate, // 保持当前选择的日期
    recordDate: yieldFormData.value.recordDate,
    lineNo: '',
    yieldvalue: null
  }
@@ -366,7 +399,7 @@
const resetUtilizationForm = () => {
  utilizationFormData.value = {
    recordDate: utilizationFormData.value.recordDate, // 保持当前选择的日期
    recordDate: utilizationFormData.value.recordDate,
    lineNo: '',
    utilizationRate: null
  }
@@ -374,7 +407,7 @@
const resetQuantityForm = () => {
  quantityFormData.value = {
    recordDate: quantityFormData.value.recordDate, // 保持当前选择的日期
    recordDate: quantityFormData.value.recordDate,
    locationCode: '',
    quantity: null
  }
@@ -621,6 +654,30 @@
    }
  }
}
// 修改设置目标值的方法
const setYieldTarget = () => {
  // 更新产量目标值并保存到localStorage
  localStorage.setItem('yieldTarget1', yieldTargetValue1.value.toString())
  localStorage.setItem('yieldTarget2', yieldTargetValue2.value.toString())
  ElMessage.success('目标值设置成功')
}
const setUtilizationTarget = () => {
  // 更新利用率目标值并保存到localStorage
  localStorage.setItem('utilizationTarget1', utilizationTargetValue1.value.toString())
  localStorage.setItem('utilizationTarget2', utilizationTargetValue2.value.toString())
  ElMessage.success('目标值设置成功')
}
const setQuantityTarget = () => {
  // 更新在制量目标值并保存到localStorage
  localStorage.setItem('quantityTarget1', quantityTargetValue1.value.toString())
  localStorage.setItem('quantityTarget2', quantityTargetValue2.value.toString())
  localStorage.setItem('quantityTarget3', quantityTargetValue3.value.toString())
  ElMessage.success('目标值设置成功')
}
</script>
<template>
@@ -629,6 +686,34 @@
      <el-tabs v-model="activeTab">
        <!-- 单小时产量标签页 -->
        <el-tab-pane label="单小时产量" name="yield">
          <!-- 添加目标值设置部分 -->
          <div class="target-setting">
            <el-form :inline="true" label-width="100px">
              <el-form-item label="一线目标值">
                <el-input-number
                  v-model="yieldTargetValue1"
                  :precision="0"
                  :step="100"
                  :min="0"
                  controls-position="right"
                  style="width: 180px"
                />
              </el-form-item>
              <el-form-item label="二线目标值">
                <el-input-number
                  v-model="yieldTargetValue2"
                  :precision="0"
                  :step="100"
                  :min="0"
                  controls-position="right"
                  style="width: 180px"
                />
              </el-form-item>
              <el-form-item>
                <el-button type="primary" @click="setYieldTarget">设置目标值</el-button>
              </el-form-item>
            </el-form>
          </div>
          <el-form :inline="true" :model="yieldFormData" label-width="100px" class="form-container">
            <el-form-item label="日期">
              <el-date-picker
@@ -732,6 +817,36 @@
        <!-- 利用率标签页 -->
        <el-tab-pane label="利用率" name="utilization">
          <!-- 添加目标值设置部分 -->
          <div class="target-setting">
            <el-form :inline="true" label-width="100px">
              <el-form-item label="标准线目标值">
                <el-input-number
                  v-model="utilizationTargetValue1"
                  :precision="2"
                  :step="0.1"
                  :min="0"
                  :max="100"
                  controls-position="right"
                  style="width: 180px"
                />
              </el-form-item>
              <el-form-item label="定制线目标值">
                <el-input-number
                  v-model="utilizationTargetValue2"
                  :precision="2"
                  :step="0.1"
                  :min="0"
                  :max="100"
                  controls-position="right"
                  style="width: 180px"
                />
              </el-form-item>
              <el-form-item>
                <el-button type="primary" @click="setUtilizationTarget">设置目标值</el-button>
              </el-form-item>
            </el-form>
          </div>
          <el-form :inline="true" :model="utilizationFormData" label-width="100px" class="form-container">
            <el-form-item label="日期">
              <el-date-picker
@@ -835,6 +950,44 @@
        <!-- 在制量标签页 -->
        <el-tab-pane label="在制量" name="quantity">
          <!-- 添加目标值设置部分 -->
          <div class="target-setting">
            <el-form :inline="true" label-width="100px">
              <el-form-item label="半成品目标值">
                <el-input-number
                  v-model="quantityTargetValue1"
                  :precision="0"
                  :step="100"
                  :min="0"
                  controls-position="right"
                  style="width: 180px"
                />
              </el-form-item>
              <el-form-item label="7014目标值">
                <el-input-number
                  v-model="quantityTargetValue2"
                  :precision="0"
                  :step="100"
                  :min="0"
                  controls-position="right"
                  style="width: 180px"
                />
              </el-form-item>
              <el-form-item label="7016目标值">
                <el-input-number
                  v-model="quantityTargetValue3"
                  :precision="0"
                  :step="100"
                  :min="0"
                  controls-position="right"
                  style="width: 180px"
                />
              </el-form-item>
              <el-form-item>
                <el-button type="primary" @click="setQuantityTarget">设置目标值</el-button>
              </el-form-item>
            </el-form>
          </div>
          <el-form :inline="true" :model="quantityFormData" label-width="100px" class="form-container">
            <el-form-item label="日期">
              <el-date-picker
@@ -1047,6 +1200,13 @@
</template>
<style scoped>
.target-setting {
  margin-bottom: 20px;
  background-color: #f5f7fa;
  padding: 20px;
  border-radius: 4px;
}
.form-container {
  margin-bottom: 20px;
  background-color: #f5f7fa;
UI-Project/src/views/KanbanDisplay2/kanbanDisplay2.vue
@@ -1,12 +1,61 @@
<script setup>
import { ref, onMounted, onUnmounted, nextTick } from 'vue'
import { ref, onMounted, onUnmounted, nextTick, watch } from 'vue'
import * as echarts from 'echarts'
import request from '@/utils/request'
import { useRoute } from 'vue-router'
const route = useRoute()
const dashboardRef = ref(null)
const standardWidth = 2220 // 设计稿标准宽度
const standardHeight = 1224 // 设计稿标准高度,
const standardHeight = 1224 // 设计稿标准高度
// 从路由参数中获取目标值
const yieldTarget1 = ref(Number(localStorage.getItem('yieldTarget1')) || Number(route.query.yieldTarget1) || 0)
const yieldTarget2 = ref(Number(localStorage.getItem('yieldTarget2')) || Number(route.query.yieldTarget2) || 0)
const utilizationTarget1 = ref(Number(localStorage.getItem('utilizationTarget1')) || Number(route.query.utilizationTarget1) || 0)
const utilizationTarget2 = ref(Number(localStorage.getItem('utilizationTarget2')) || Number(route.query.utilizationTarget2) || 0)
const quantityTarget1 = ref(Number(localStorage.getItem('quantityTarget1')) || Number(route.query.quantityTarget1) || 0)
const quantityTarget2 = ref(Number(localStorage.getItem('quantityTarget2')) || Number(route.query.quantityTarget2) || 0)
const quantityTarget3 = ref(Number(localStorage.getItem('quantityTarget3')) || Number(route.query.quantityTarget3) || 0)
// 监听路由参数变化
watch(() => route.query, (newQuery) => {
  if (newQuery.yieldTarget1) {
    yieldTarget1.value = Number(newQuery.yieldTarget1)
    localStorage.setItem('yieldTarget1', newQuery.yieldTarget1)
    updateOptionYield(yieldTarget1.value, yieldTarget2.value)
  }
  if (newQuery.yieldTarget2) {
    yieldTarget2.value = Number(newQuery.yieldTarget2)
    localStorage.setItem('yieldTarget2', newQuery.yieldTarget2)
    updateOptionYield(yieldTarget1.value, yieldTarget2.value)
  }
  if (newQuery.utilizationTarget1) {
    utilizationTarget1.value = Number(newQuery.utilizationTarget1)
    localStorage.setItem('utilizationTarget1', newQuery.utilizationTarget1)
    updateOptionUtilization(utilizationTarget1.value, utilizationTarget2.value)
  }
  if (newQuery.utilizationTarget2) {
    utilizationTarget2.value = Number(newQuery.utilizationTarget2)
    localStorage.setItem('utilizationTarget2', newQuery.utilizationTarget2)
    updateOptionUtilization(utilizationTarget1.value, utilizationTarget2.value)
  }
  if (newQuery.quantityTarget1) {
    quantityTarget1.value = Number(newQuery.quantityTarget1)
    localStorage.setItem('quantityTarget1', newQuery.quantityTarget1)
    updateOptionQuantity(quantityTarget1.value, quantityTarget2.value, quantityTarget3.value)
  }
  if (newQuery.quantityTarget2) {
    quantityTarget2.value = Number(newQuery.quantityTarget2)
    localStorage.setItem('quantityTarget2', newQuery.quantityTarget2)
    updateOptionQuantity(quantityTarget1.value, quantityTarget2.value, quantityTarget3.value)
  }
  if (newQuery.quantityTarget3) {
    quantityTarget3.value = Number(newQuery.quantityTarget3)
    localStorage.setItem('quantityTarget3', newQuery.quantityTarget3)
    updateOptionQuantity(quantityTarget1.value, quantityTarget2.value, quantityTarget3.value)
  }
}, { deep: true })
// 计算缩放比例并应用
const setScale = () => {
@@ -70,7 +119,7 @@
    });
    if (res.code === 200) {
      yieldData.value = res.data;
      updateOptionYield();
      updateOptionYield(yieldTarget1.value, yieldTarget2.value);
    }
  } catch (error) {
    console.error('获取单小时产量数据失败:', error);
@@ -85,7 +134,7 @@
    });
    if (res.code === 200) {
      utilizationData.value = res.data;
      updateOptionUtilization();
      updateOptionUtilization(utilizationTarget1.value, utilizationTarget2.value);
    }
  } catch (error) {
    console.error('获取利用率数据失败:', error);
@@ -100,7 +149,7 @@
    });
    if (res.code === 200) {
      quantityData.value = res.data;
      updateOptionQuantity();
      updateOptionQuantity(quantityTarget1.value, quantityTarget2.value, quantityTarget3.value);
    }
  } catch (error) {
    console.error('获取在制量数据失败:', error);
@@ -405,7 +454,7 @@
  draw('drawLineChart_day51', OptionDayMode)
}
const updateOptionYield = () => {
const updateOptionYield = (targetValue1, targetValue2) => {
  // 按日期排序并处理数据
  const sortedData = [...yieldData.value].sort((a, b) =>
    new Date(a.recordTime) - new Date(b.recordTime)
@@ -434,14 +483,32 @@
  // 单小时产量的配置 - 分上下两个子图表
  const OptionYield = {
    title: {
      text: '单小时产量',
      textStyle: {
        fontSize: 20,
        fontWeight: 'bold',
        color: 'white'
      }
    },
    title: [
      {
        text: '单小时产量',
        textStyle: {
          fontSize: 20,
          fontWeight: 'bold',
          color: 'white'
        }
      },
      {
        text: '目标' + targetValue1,
        bottom: 140, //
        textStyle: {
          color: 'white',
          fontSize: 17
        },
      },
      {
        text: '目标' + targetValue2,
        bottom: 35, //
        textStyle: {
          color: 'white',
          fontSize: 17
        },
      },
    ],
    tooltip: {
      trigger: 'axis',
      axisPointer: {
@@ -454,10 +521,11 @@
      x: 'left',
      y: 'center',
      orient: 'vertical',
      itemGap: 90,
      textStyle: {
        fontSize: 20,
        fontWeight: 'bold',
        color: 'white',
        color: 'white'
      }
    },
    grid: [{
@@ -558,6 +626,20 @@
        areaStyle: {
          color: '#000000',
          opacity: 0.3
        },
        markLine: {
          data: [
            {
              yAxis: targetValue1,
              name: 'Line',
              label: {
                formatter: '',
              },
              lineStyle: {
                width: 2,
              }
            }
          ]
        }
      },
      {
@@ -584,6 +666,20 @@
        areaStyle: {
          color: 'white',
          opacity: 0.3
        },
        markLine: {
          data: [
            {
              yAxis: targetValue2,
              name: 'Line',
              label: {
                formatter: '',
              },
              lineStyle: {
                width: 2,
              }
            }
          ]
        }
      }
    ]
@@ -598,7 +694,7 @@
  draw('drawLineChart_yield', OptionYield)
}
const updateOptionUtilization = () => {
const updateOptionUtilization = (targetValue1, targetValue2) => {
  // 按日期排序并处理数据
  const sortedData = [...utilizationData.value].sort((a, b) =>
    new Date(a.recordTime || a.recordDate) - new Date(b.recordTime || b.recordDate)
@@ -627,14 +723,32 @@
  // 利用率的配置 - 分上下两个子图表
  const OptionUtilization = {
    title: {
      text: '利用率',
      textStyle: {
        fontSize: 20,
        fontWeight: 'bold',
        color: 'white'
      }
    },
    title: [
      {
        text: '利用率',
        textStyle: {
          fontSize: 20,
          fontWeight: 'bold',
          color: 'white'
        }
      },
      {
        text: '目标' + targetValue1 + '%',
        bottom: 140, //
        textStyle: {
          color: 'white',
          fontSize: 17
        },
      },
      {
        text: '目标' + targetValue2 + '%',
        bottom: 35, //
        textStyle: {
          color: 'white',
          fontSize: 17
        },
      },
    ],
    tooltip: {
      trigger: 'axis',
      axisPointer: {
@@ -647,6 +761,7 @@
      x: 'left',
      y: 'center',
      orient: 'vertical',
      itemGap: 90,
      textStyle: {
        fontSize: 20,
        fontWeight: 'bold',
@@ -774,6 +889,20 @@
        areaStyle: {
          color: '#000000',
          opacity: 0.3
        },
        markLine: {
          data: [
            {
              yAxis: targetValue1,
              name: 'Line',
              label: {
                formatter: '',
              },
              lineStyle: {
                width: 2,
              }
            }
          ]
        }
      },
      {
@@ -801,6 +930,20 @@
        areaStyle: {
          color: 'white',
          opacity: 0.3
        },
        markLine: {
          data: [
            {
              yAxis: targetValue2,
              name: "line",
              label: {
                formatter: '',
              },
              lineStyle: {
                width: 2,
              }
            }
          ]
        }
      }
    ]
@@ -812,12 +955,13 @@
  //   chart.setOption(OptionUtilization);
  //   charts.push(chart);
  // }
  draw('drawLineChart_utilization',OptionUtilization);
  draw('drawLineChart_utilization', OptionUtilization);
}
const updateOptionQuantity = () => {
const updateOptionQuantity = (targetValue1, targetValue2, targetValue3) => {
  // 按日期排序并处理数据
  const sortedData = [...quantityData.value].sort((a, b) =>
    new Date(a.recordTime || a.recordDate) - new Date(b.recordTime || b.recordDate)
  );
@@ -848,7 +992,7 @@
  // 在制量的配置 - 上中下三层布局
  const OptionQuantity = {
    title: {
    title: [{
      text: '在制量',
      textStyle: {
        fontSize: 20,
@@ -856,6 +1000,31 @@
        color: 'white'
      }
    },
    {
      text: '目标' + targetValue1,
      bottom: 160, //
      textStyle: {
        color: 'white',
        fontSize: 17
      },
    },
    {
      text: '目标' + targetValue2,
      bottom: 95, //
      textStyle: {
        color: 'white',
        fontSize: 17
      },
    },
    {
      text: '目标' + targetValue3,
      bottom: 20, //
      textStyle: {
        color: 'white',
        fontSize: 17
      },
    },
    ],
    tooltip: {
      trigger: 'axis',
      axisPointer: {
@@ -868,6 +1037,7 @@
      x: 'left',
      y: 'center',
      orient: 'vertical',
      itemGap: 50,
      textStyle: {
        fontSize: 20,
        fontWeight: 'bold',
@@ -1014,6 +1184,20 @@
        areaStyle: {
          color: '#91cc75',
          opacity: 0.3
        },
        markLine: {
          data: [
            {
              yAxis: targetValue1,
              name: 'Line',
              label: {
                formatter: '',
              },
              lineStyle: {
                width: 2,
              }
            }
          ]
        }
      },
      {
@@ -1040,6 +1224,20 @@
        areaStyle: {
          color: '#000000',
          opacity: 0.3
        },
        markLine: {
          data: [
            {
              yAxis: targetValue2,
              name: 'Line',
              label: {
                formatter: '',
              },
              lineStyle: {
                width: 2,
              }
            }
          ]
        }
      },
      {
@@ -1066,6 +1264,20 @@
        areaStyle: {
          color: 'white',
          opacity: 0.3
        },
        markLine: {
          data: [
            {
              yAxis: targetValue3,
              name: 'Line',
              label: {
                formatter: '',
              },
              lineStyle: {
                width: 2,
              }
            }
          ]
        }
      }
    ]
@@ -1077,7 +1289,7 @@
  //   chart.setOption(OptionQuantity);
  //   charts.push(chart);
  // }
  draw('drawLineChart_quantity',OptionQuantity);
  draw('drawLineChart_quantity', OptionQuantity);
}
@@ -1086,33 +1298,87 @@
  window.addEventListener('resize', handleResize)
  // 确保DOM加载完成后再初始化图表
  nextTick(() => {
    loadNotCompleteData();
    loadYieldData();
    loadUtilizationData();
    loadInventoryData();
    loadPlannedData();
  });
  nextTick(async () => {
    try {
      // 从localStorage中获取目标值,如果没有则从路由参数获取,都没有则使用默认值0
      yieldTarget1.value = Number(localStorage.getItem('yieldTarget1')) || Number(route.query.yieldTarget1) || 0
      yieldTarget2.value = Number(localStorage.getItem('yieldTarget2')) || Number(route.query.yieldTarget2) || 0
      utilizationTarget1.value = Number(localStorage.getItem('utilizationTarget1')) || Number(route.query.utilizationTarget1) || 0
      utilizationTarget2.value = Number(localStorage.getItem('utilizationTarget2')) || Number(route.query.utilizationTarget2) || 0
      quantityTarget1.value = Number(localStorage.getItem('quantityTarget1')) || Number(route.query.quantityTarget1) || 0
      quantityTarget2.value = Number(localStorage.getItem('quantityTarget2')) || Number(route.query.quantityTarget2) || 0
      quantityTarget3.value = Number(localStorage.getItem('quantityTarget3')) || Number(route.query.quantityTarget3) || 0
  // 设置定时刷新
  const refreshInterval = setInterval(() => {
    loadYieldData();
    loadUtilizationData();
    loadInventoryData();
    loadPlannedData();
    console.log('数据已刷新');
  }, 30000); // 每分钟刷新一次
      // 按顺序加载数据
      await loadNotCompleteData()
      await loadYieldData()
      await loadUtilizationData()
      await loadInventoryData()
      await loadPlannedData()
  onUnmounted(() => {
    clearInterval(refreshInterval);
  });
      // 设置定时刷新数据
      const refreshInterval = setInterval(async () => {
        try {
          await loadYieldData()
          await loadUtilizationData()
          await loadInventoryData()
          await loadPlannedData()
          console.log('数据已刷新')
        } catch (error) {
          console.error('数据刷新失败:', error)
        }
      }, 15000) // 每15秒刷新一次
      // 添加监听localStorage变化的定时器
      const checkTargetsInterval = setInterval(() => {
        const newYieldTarget1 = Number(localStorage.getItem('yieldTarget1'))
        const newYieldTarget2 = Number(localStorage.getItem('yieldTarget2'))
        const newUtilizationTarget1 = Number(localStorage.getItem('utilizationTarget1'))
        const newUtilizationTarget2 = Number(localStorage.getItem('utilizationTarget2'))
        const newQuantityTarget1 = Number(localStorage.getItem('quantityTarget1'))
        const newQuantityTarget2 = Number(localStorage.getItem('quantityTarget2'))
        const newQuantityTarget3 = Number(localStorage.getItem('quantityTarget3'))
        // 检查目标值是否有变化
        if (newYieldTarget1 !== yieldTarget1.value || newYieldTarget2 !== yieldTarget2.value) {
          yieldTarget1.value = newYieldTarget1
          yieldTarget2.value = newYieldTarget2
          updateOptionYield(newYieldTarget1, newYieldTarget2)
        }
        if (newUtilizationTarget1 !== utilizationTarget1.value || newUtilizationTarget2 !== utilizationTarget2.value) {
          utilizationTarget1.value = newUtilizationTarget1
          utilizationTarget2.value = newUtilizationTarget2
          updateOptionUtilization(newUtilizationTarget1, newUtilizationTarget2)
        }
        if (newQuantityTarget1 !== quantityTarget1.value ||
            newQuantityTarget2 !== quantityTarget2.value ||
            newQuantityTarget3 !== quantityTarget3.value) {
          quantityTarget1.value = newQuantityTarget1
          quantityTarget2.value = newQuantityTarget2
          quantityTarget3.value = newQuantityTarget3
          updateOptionQuantity(newQuantityTarget1, newQuantityTarget2, newQuantityTarget3)
        }
      }, 1000) // 每秒检查一次
      onUnmounted(() => {
        clearInterval(refreshInterval)
        clearInterval(checkTargetsInterval)
      })
    } catch (error) {
      console.error('初始化数据失败:', error)
    }
  })
})
onUnmounted(() => {
  window.removeEventListener('resize', handleResize)
  // 清理所有图表实例
  charts.forEach(chart => {
    chart.dispose()
    if (chart && !chart.isDisposed()) {
      chart.dispose()
    }
  })
  charts.length = 0
})
</script>
@@ -1139,8 +1405,8 @@
                总计划量-片数、平方</div>
              <div id="textDay" style="font-size: 20px;height: 30px;margin-left: 20px;margin-top: 20px;">日期:</div>
              <br>
              <div id="textprice" style="font-size: 20px;height: 30px;margin-left: 20px;margin-top: 20px;">片数:</div>
              <div id="textarea" style="font-size: 20px;height: 30px;margin-left: 20px;margin-top: 20px;">平方数:</div>
              <div id="textprice" style="font-size: 20px;height: 30px;margin-left: 20px;margin-top: 20px;">片数:</div>
            </div>
          </div>
@@ -1167,206 +1433,148 @@
<script>
export default {
  mounted() {
    const OptionYear = {
      tooltip: {
        trigger: 'axis',
        axisPointer: {
          type: 'shadow',
          label: {
            fontSize: 16,
            color: 'white' // 设置提示框文字颜色为白色
  data() {
    return {
      timer: null,
      OptionYear: {
        tooltip: {
          trigger: 'axis',
          axisPointer: {
            type: 'shadow',
            label: {
              fontSize: 16,
              color: 'white' // 设置提示框文字颜色为白色
            }
          }
        }
      },
      legend: {
        data: ['计划量', '一线', '二线'],
        icon: 'roundRect',
        itemGap: 50,
        y:'bottom',
        textStyle: {
          fontSize: 20,
          fontWeight: 'bold',
          color: 'white'
        }
      },
      // toolbox: {
      //   show: true,
      //   feature: {
      //     dataZoom: {
      //       yAxisIndex: 'none'
      //     },
      //     dataView: { readOnly: false },
      //     magicType: { type: ['line', 'bar'] },
      //     restore: {},
      //     saveAsImage: {}
      //   },
      //   iconStyle: {
      //     color: 'white' // 设置工具框图标颜色为白色
      //   }
      // },
      grid: {
        left: '3%',
        right: '4%',
        bottom: '20%',
        top: '10%',
        containLabel: true
      },
      xAxis: [
        {
          type: 'category',
          axisTick: { alignWithLabel: true },
          boundaryGap: true,
          axisLabel: {
        },
        title: {
          text: '已完成                    已完成',
          left: '48%',
          bottom: 0, //
          textStyle: {
            color: 'white',
            fontSize: 16
          },
        },
        legend: {
          data: ['计划量', '一线', '二线'],
          icon: 'roundRect',
          itemGap: 90,
          y: '80%',
          textStyle: {
            fontSize: 20,
            interval: 'auto',
            margin: 15,
            formatter: (value, index) => {
              // 如果是日期格式
              if (value.includes('-')) {
                // 对第一个日期显示完整年月日
                if (index === 0) {
                  return value;  // 返回完整日期 (例如: 2024-03-21)
            fontWeight: 'bold',
            color: 'white'
          }
        },
        grid: {
          left: '3%',
          right: '4%',
          bottom: '20%',
          top: '10%',
          containLabel: true
        },
        xAxis: [
          {
            type: 'category',
            axisTick: { alignWithLabel: true },
            boundaryGap: true,
            axisLabel: {
              fontSize: 20,
              interval: 'auto',
              formatter: (value, index) => {
                // 如果是日期格式
                if (value.includes('-')) {
                  // 对第一个日期显示完整年月日
                  if (index === 0) {
                    return value;  // 返回完整日期 (例如: 2024-03-21)
                  }
                  // 其他日期只显示月-日
                  return value.split('-').slice(1).join('-');  // (例如: 03-21)
                }
                // 其他日期只显示月-日
                return value.split('-').slice(1).join('-');  // (例如: 03-21)
              }
              return value;
                return value;
              },
              color: 'white' // 设置 x 轴标签颜色为白色
            },
            color: 'white' // 设置 x 轴标签颜色为白色
          },
          nameTextStyle: {
            fontSize: 20,
            color: 'white' // 设置 x 轴名称颜色为白色
          },
          position: 'top'
        }
      ],
      yAxis: [
        {
          type: 'value',
          axisLabel: {
            fontSize: 20,
            color: 'white' // 设置 y 轴标签颜色为白色
          },
          nameTextStyle: {
            fontSize: 20,
            color: 'white' // 设置 y 轴名称颜色为白色
            nameTextStyle: {
              fontSize: 20,
              color: 'white' // 设置 x 轴名称颜色为白色
            },
            position: 'top',
            offset: 15 // 调整 x 轴标签的位置
          }
        }
      ],
      series: [
        {
          name: '计划量',
          type: 'bar',
          barWidth: '30%',
          barGap: '10%',
          label: {
            show: true,
            fontSize: 16,
            formatter: (params) => params.value,
            color: 'white',
            position: 'top'
        ],
        yAxis: [
          {
            type: 'value',
            axisLabel: {
              fontSize: 20,
              color: 'white' // 设置 y 轴标签颜色为白色
            },
            nameTextStyle: {
              fontSize: 20,
              color: 'white' // 设置 y 轴名称颜色为白色
            }
          }
        },
        {
          name: '一线',
          type: 'bar',
          barWidth: '30%',
          barGap: '10%',
          label: {
            show: true,
            fontSize: 16,
            formatter: (params) => params.value,
            color: 'white',
            position: 'top'
        ],
        series: [
          {
            name: '计划量',
            type: 'bar',
            barWidth: '30%',
            barGap: '10%',
            label: {
              show: true,
              fontSize: 16,
              formatter: (params) => params.value,
              color: 'white',
              position: 'top'
            }
          },
        },
        {
          name: '二线',
          type: 'bar',
          barWidth: '30%',
          barGap: '10%',
          itemStyle: {
            color: '#4a86e8'
          {
            name: '一线',
            type: 'bar',
            barWidth: '30%',
            barGap: '10%',
            label: {
              show: true,
              fontSize: 16,
              formatter: (params) => params.value,
              color: 'white',
              position: 'top'
            }
          },
          label: {
            show: true,
            fontSize: 16,
            formatter: (params) => params.value,
            color: 'white',
            position: 'top'
          },
        }
      ]
          {
            name: '二线',
            type: 'bar',
            barWidth: '30%',
            barGap: '10%',
            itemStyle: {
              color: '#4a86e8'
            },
            label: {
              show: true,
              fontSize: 16,
              formatter: (params) => params.value,
              color: 'white',
              position: 'top'
            }
          }
        ]
      }
    };
    // 请求当日产量
    // request.post('/deviceInteraction/primitiveTask/findDailyOutput',
    //   {
    //     "dayCount": 1
    //   }).then((res) => {
    //     if (res.code == 200) {
    //       const modeOptions = res.data;
    //       console.log("获取当日产量",modeOptions);
    //       this.drawDay('drawLineChart_day11', OptionYear, modeOptions);
    //       // this.drawDay('drawLineChart_day31', OptionYear, modeOptions);
    //       // this.drawYear('drawLineChart_day51', OptionDayMode, modeOptions);
    //     } else {
    //       console.error('请求当日产量数据失败:', error);
    //     }
    //   });
    //请求日产量-月
    request.post('/deviceInteraction/primitiveTask/findDailyOutput',
      {
        "dayCount": 30
      }).then((res) => {
        if (res.code == 200) {
          const modeOptions = res.data;
          const modeOptions2 = [res.data[res.data.length - 1]];
          // this.drawDay('drawLineChart_day11', OptionYear, modeOptions);
          //this.drawDay('drawLineChart_day31', OptionYear, modeOptions);
          // this.drawYear('drawLineChart_day51', OptionDayMode, modeOptions);
          this.drawDay('drawLineChart_day11', OptionYear, modeOptions2);
        } else {
          console.error('请求日产量-月数据失败:', error);
        }
      });
    //请求计划量
    // request.post('/deviceInteraction/primitiveTask/findPlannedQuantity',
    //   {
    //     "dayCount": 30
    //   }).then((res) => {
    //     if (res.code == 200) {
    //       const modeOptions = res.data;
    //       this.drawYear('drawLineChart_day51', OptionDayMode, modeOptions);
    //       let textDay = document.getElementById('textDay');
    //       let textprice = document.getElementById('textprice');
    //       let textarea = document.getElementById('textarea');
    //       let y_pingfang = res.data.map(v => { return v.area_sum });
    //       let y_pianshu = res.data.map(v => { return v.task_quantity_sum });
    //       let y_pingfang_sum = 0;
    //       let y_pianshu_sum = 0;
    //       for (let i = 0; i < y_pingfang.length; i++) {
    //         y_pingfang_sum += y_pingfang[i];
    //       }
    //       for (let i = 0; i < y_pianshu.length; i++) {
    //         y_pianshu_sum += y_pianshu[i];
    //       }
    //       textDay.innerHTML = "日期:" + "<br>" + res.data[0].CreateDate + " - " + res.data[res.data.length - 1].CreateDate;
    //       textprice.innerHTML = "片数:" + y_pianshu_sum;
    //       textarea.innerHTML = "平方数:" + Number(y_pingfang_sum).toFixed(2);
    //       // this.drawYear('drawLineChart_day51', OptionDayMode, modeOptions);
    //     } else {
    //       console.error('请求计划量-月数据失败:', error);
    //     }
    //   });
  },
  mounted() {
    this.fetchData();
    // 每半分钟刷新一次数据
    this.timer = setInterval(() => {
      this.fetchData();
    }, 30000);
  },
  beforeDestroy() {
    if (this.timer) {
      clearInterval(this.timer);
    }
  },
  methods: {
    draw(name, Option) {
@@ -1374,9 +1582,6 @@
      myChart.setOption(Option);
    },
    drawDay(name, Option, data) {
      // console.log(data);
      //Option.title.text="日看板";
      //日看板- 计划量,一线完成,二线完成(片数)
      let x_data = data.map(v => { return v.date });
      let y_jihua = data.map(v => { return v.plan });
      let y_one = data.map(v => { return v.line1 });
@@ -1388,7 +1593,6 @@
      this.draw(name, Option);
    },
    drawYear(name, Option, data) {
      //计划量- 平方,片数
      let x_data = data.map(v => { return v.CreateDate });
      let y_pingfang = data.map(v => { return v.area_sum });
      let y_pianshu = data.map(v => { return v.task_quantity_sum });
@@ -1398,37 +1602,24 @@
      Option.series[1].data = y_pianshu;
      this.draw(name, Option);
    },
    requsstData() {
    },
    // // 渲染单小时产量图表
    // drawYieldChart(data) {
    //   const option = { ...OptionYield };
    //   option.xAxis.data = data.map(v => v.date);
    //   option.series[0].data = data.map(v => v.line1_yield);
    //   option.series[1].data = data.map(v => v.line2_yield);
    //   this.draw('drawLineChart_yield', option);
    // },
    // // 渲染利用率图表
    // drawUtilizationChart(data) {
    //   const option = { ...OptionUtilization };
    //   option.xAxis.data = data.map(v => v.date);
    //   option.series[0].data = data.map(v => v.line1_utilization);
    //   option.series[1].data = data.map(v => v.line2_utilization);
    //   this.draw('drawLineChart_utilization', option);
    // },
    // // 渲染在制量图表
    // drawQuantityChart(data) {
    //   const option = { ...OptionQuantity };
    //   option.xAxis.data = data.map(v => v.date);
    //   option.series[0].data = data.map(v => v.semi_finished);
    //   option.series[1].data = data.map(v => v.location_7014);
    //   option.series[2].data = data.map(v => v.location_7016);
    //   this.draw('drawLineChart_quantity', option);
    // },
    fetchData() {
      // 请求日产量-月
      request.post('/deviceInteraction/primitiveTask/findDailyOutput', {
        "dayCount": 30
      }).then((res) => {
        if (res.code == 200) {
          const modeOptions = res.data;
          const modeOptions2 = [res.data[res.data.length - 1]];
          this.drawDay('drawLineChart_day11', this.OptionYear, modeOptions2);
        } else {
          console.error('请求日产量-月数据失败:', res);
        }
      }).catch((error) => {
        console.error('请求数据时发生错误:', error);
      });
    }
  }
}
};
</script>
<style scoped>
UI-Project/src/views/MechanicalReport/mechanicalReport.vue
New file
@@ -0,0 +1,314 @@
<script setup>
import { ref, onMounted, reactive, onUnmounted } from 'vue'
import { ElMessage } from 'element-plus'
import request from '@/utils/request'
const timer = ref(null)
const xGrid = ref()
const tableData = ref([])
const loading = ref(false)
// 筛选条件
const filterForm = ref({
  startDate: null,
  endDate: null,
  taskType: '',
  operationRecord: '',
  lineType: ''
})
// 获取本月第一天和最后一天
const getCurrentMonthRange = () => {
  const now = new Date()
  const firstDay = new Date(now.getFullYear(), now.getMonth(), 1)
  const lastDay = new Date(now.getFullYear(), now.getMonth() + 1, 0)
  return {
    startDate: formatDate(firstDay),
    endDate: formatDate(lastDay)
  }
}
// 格式化日期为 yyyy-MM-dd HH:mm:ss
const formatDate = (date, isEndDate = false) => {
  const year = date.getFullYear()
  const month = String(date.getMonth() + 1).padStart(2, '0')
  const day = String(date.getDate()).padStart(2, '0')
  const time = isEndDate ? '23:59:59' : '00:00:00'
  return `${year}-${month}-${day} ${time}`
}
// 格式化表格中的时间显示
const formatTableDateTime = ({ cellValue }) => {
  if (!cellValue) return ''
  try {
    // 处理ISO格式的时间字符串
    const date = new Date(cellValue)
    if (isNaN(date.getTime())) return cellValue
    const year = date.getFullYear()
    const month = String(date.getMonth() + 1).padStart(2, '0')
    const day = String(date.getDate()).padStart(2, '0')
    const hours = String(date.getHours()).padStart(2, '0')
    const minutes = String(date.getMinutes()).padStart(2, '0')
    const seconds = String(date.getSeconds()).padStart(2, '0')
    return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
  } catch (error) {
    console.error('日期格式化错误:', error)
    return cellValue
  }
}
// 添加日期选择的限制逻辑
const validateDateRange = (startDate, endDate) => {
  if (!startDate || !endDate) return true
  const start = new Date(startDate)
  const end = new Date(endDate)
  // 计算两个日期之间的毫秒差
  const diffTime = Math.abs(end - start)
  // 转换为天数
  const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24))
  // 检查是否超过31天
  return diffDays <= 31
}
const gridOptions = reactive({
  border: true,
  height: '500px',
  showOverflow: true,
  loading: loading,
  exportConfig: {},
  columnConfig: {
    resizable: true
  },
  toolbarConfig:
  {
    print: true,
    export: true,
    custom: true,
    zoom: true
  },
  columns: [
    { type: 'seq', width: 60, title: '序号' },
    { field: 'glass_id', title: '玻璃ID', width: 120 },
    { field: 'batch_number', title: '批次号', width: 120 },
    { field: 'scan_id', title: '扫描ID', width: 120 },
    { field: 'operation_record_time', title: '操作时间', width: 180, formatter: formatTableDateTime },
    { field: 'task_type', title: '类型', width: 100 },
    { field: 'operation_record', title: '设备名称', width: 120 },
    { field: 'operation_mode', title: '操作模式', width: 100 },
    { field: 'drawing_marking', title: '图纸标记', width: 120 },
    { field: 'state', title: '状态', width: 100 },
    { field: 'work_state', title: '工作状态', width: 100 },
    { field: 'glass_state', title: '玻璃状态', width: 100 },
    { field: 'line_configuration_id', title: '产线ID', width: 100 },
    { field: 'is_marking', title: '是否标记', width: 100 },
    { field: 'is_send', title: '发送状态', width: 100 },
    { field: 'is_silk_screen', title: '是否丝印', width: 100 },
    { field: 'length', title: '长度', width: 100 },
    { field: 'width', title: '宽度', width: 100 },
    { field: 'thickness', title: '厚度', width: 100 },
    { field: 'program_id', title: '程序ID', width: 120 },
    { field: 'silk_screen_x', title: '丝印X', width: 100 },
    { field: 'silk_screen_y', title: '丝印Y', width: 100 },
    { field: 'task_quantity', title: '任务数量', width: 100 },
    { field: 'task_sequence', title: '任务序列', width: 100 }
  ],
  data: tableData
})
// 获取数据
const fetchData = async () => {
  loading.value = true
  try {
    if (!filterForm.value.startDate || !filterForm.value.endDate) {
      ElMessage.warning('请选择时间范围')
      loading.value = false
      return
    }
    // 验证日期范围
    if (!validateDateRange(filterForm.value.startDate, filterForm.value.endDate)) {
      ElMessage.warning('时间范围不能超过一个月')
      loading.value = false
      return
    }
    const startDate = formatDate(new Date(filterForm.value.startDate), false)  // 开始日期使用 00:00:00
    const endDate = formatDate(new Date(filterForm.value.endDate), true)      // 结束日期使用 23:59:59
    const params = {
      dayCount: 0,
      startDate: startDate,
      endDate: endDate,
      taskType: filterForm.value.taskType || null,
      operationRecord: filterForm.value.operationRecord || null,
      lineType: filterForm.value.lineType || null
    }
    const response = await request({
      url: '/deviceInteraction/taskingLog/mechanicalReport',
      method: 'post',
      params: params
    })
    if (response && response.code === 200) {
      if (Array.isArray(response.data)) {
        //console.log('设置表格数据:', response.data)
        gridOptions.data = response.data
      } else {
        gridOptions.data = []
        ElMessage.warning('暂无数据')
      }
    } else {
      gridOptions.data = []
      ElMessage.error(response?.message || '查询失败')
    }
  } catch (error) {
    console.error('获取数据失败:', error)
    ElMessage.error('获取数据失败:' + (error.message || '未知错误'))
    gridOptions.data = []
  } finally {
    loading.value = false
  }
}
// 重置筛选条件
const resetFilter = () => {
  const today = new Date()
  const firstDayOfMonth = new Date(today.getFullYear(), today.getMonth(), 1)
  filterForm.value = {
    startDate: formatDate(firstDayOfMonth),
    endDate: formatDate(today),
    taskType: '',
    operationRecord: '',
    lineType: ''
  }
  fetchData()
}
// 限制结束日期不能超过开始日期一个月
const disabledEndDate = (time) => {
  if (!filterForm.value.startDate) {
    return false
  }
  const startDate = new Date(filterForm.value.startDate)
  const oneMonthLater = new Date(startDate)
  oneMonthLater.setMonth(oneMonthLater.getMonth() + 1)
  return time.getTime() > oneMonthLater.getTime()
}
// 限制开始日期不能离结束日期超过一个月
const disabledStartDate = (time) => {
  if (!filterForm.value.endDate) {
    return false
  }
  const endDate = new Date(filterForm.value.endDate)
  const oneMonthEarlier = new Date(endDate)
  oneMonthEarlier.setMonth(oneMonthEarlier.getMonth() - 1)
  return time.getTime() < oneMonthEarlier.getTime()
}
// 页面加载时获取数据
onMounted(() => {
  resetFilter()
  // 每分钟刷新一次数据
  timer.value = setInterval(fetchData, 60000)
})
// 页面卸载时清除定时器
onUnmounted(() => {
  if (timer.value) {
    clearInterval(timer.value)
  }
})
</script>
<template>
  <div class="mechanical-report">
    <!-- 筛选条件 -->
    <el-card class="filter-card">
      <el-form :inline="true" :model="filterForm" class="filter-form">
        <el-form-item label="开始日期" required>
          <el-date-picker v-model="filterForm.startDate" type="date" placeholder="选择开始日期" format="YYYY-MM-DD"
            value-format="YYYY-MM-DD" :disabledDate="disabledStartDate" />
        </el-form-item>
        <el-form-item label="结束日期" required>
          <el-date-picker v-model="filterForm.endDate" type="date" placeholder="选择结束日期" format="YYYY-MM-DD"
            value-format="YYYY-MM-DD" :disabledDate="disabledEndDate" />
        </el-form-item>
        <el-form-item label="类型">
          <el-select v-model="filterForm.taskType" placeholder="请选择类型" style="width: 100px;" clearable>
            <el-option label="全部" value="" />
            <el-option label="定制" value="定制" />
            <el-option label="标准" value="标准" />
          </el-select>
        </el-form-item>
        <el-form-item label="设备名称">
          <el-select v-model="filterForm.operationRecord" placeholder="请选择设备" style="width: 100px;" clearable>
            <el-option label="全部" value="" />
            <el-option label="上片" value="上片" />
            <el-option label="磨边" value="磨边" />
            <el-option label="翻片" value="翻片" />
            <el-option label="打标" value="打标" />
            <el-option label="丝印" value="丝印" />
            <el-option label="旋转" value="旋转" />
          </el-select>
        </el-form-item>
        <el-form-item label="生产线">
          <el-select v-model="filterForm.lineType" placeholder="请选择生产线" style="width: 100px;" clearable>
            <el-option label="全部" value="" />
            <el-option label="一线" value="1" />
            <el-option label="二线" value="2" />
          </el-select>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="fetchData">查询</el-button>
          <el-button @click="resetFilter">重置</el-button>
        </el-form-item>
      </el-form>
    </el-card>
    <!-- 数据表格 -->
    <el-card class="table-card">
      <vxe-grid v-bind="gridOptions"></vxe-grid>
      <div class="total-info">
        <el-tag type="info" style="font-size: 22px; padding: 8px 16px;">总数量: {{ gridOptions.data.length }}</el-tag>
      </div>
    </el-card>
  </div>
</template>
<style scoped>
.mechanical-report {
  padding: 20px;
}
.filter-card {
  margin-bottom: 20px;
}
.filter-form {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}
.table-card {
  margin-top: 20px;
}
.total-info {
  margin-top: 2px;
  display: left;
  padding-right: 20px;
  font-weight: bold;
}
</style>