wu
2025-10-23 27550ee46778905ab194844ab5247b116f70659e
切割排产重写,增加详情查询接口,增加查询类,部分中文翻译
11个文件已修改
1个文件已添加
775 ■■■■ 已修改文件
UI-Project/src/lang/zh.js 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
UI-Project/src/utils/constants.js 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
UI-Project/src/views/EngineerScheduling/engineerScheduling.vue 603 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hangzhoumesParent/common/servicebase/src/main/java/com/mes/pp/controller/OptimizeProjectController.java 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hangzhoumesParent/common/servicebase/src/main/java/com/mes/pp/entity/OptimizeProject.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hangzhoumesParent/common/servicebase/src/main/java/com/mes/pp/entity/dto/ProgressDTO.java 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hangzhoumesParent/common/servicebase/src/main/java/com/mes/pp/mapper/OptimizeProjectMapper.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hangzhoumesParent/common/servicebase/src/main/java/com/mes/pp/service/OptimizeProjectService.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hangzhoumesParent/common/servicebase/src/main/java/com/mes/pp/service/impl/OptimizeProjectServiceImpl.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hangzhoumesParent/common/servicebase/src/main/resources/mapper/OptimizeProjectMapper.xml 75 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
hangzhoumesParent/moduleService/CacheVerticalGlassModule/src/main/resources/application.yml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
hangzhoumesParent/moduleService/LoadGlassModule/src/main/resources/application.yml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
UI-Project/src/lang/zh.js
@@ -559,7 +559,6 @@
        hollownumber: '中空总数量',
        hollowEngineer: '中空工程',
        hollowarea: '中空总面积',
        hollowtotal: '中空总时间',
        engineerId: '工程号',
        totalnumber: '总数量',
        tatalarea: '总面积',
@@ -990,5 +989,18 @@
        pwidth: '请输入宽度',
        pheight: '请输入高度',
        upnumber: '上片数量',
    }
    },
    scheduling:{
        cuttingCount: '切割',
        edgingCount: '磨边',
        temperingCount: '钢化',
        insulatingCount: '中空',
        completed:"已排产",
        completedCount: '完成数量',
        unfinished:'待排产',
        serial: '序号',
        projectNo: '工程ID',
        thickness: '玻璃厚度(mm)',
        glassType: '玻璃类型',
    }
}
UI-Project/src/utils/constants.js
@@ -1,10 +1,10 @@
//  export const WebSocketHost = "192.168.2.100";
 export const WebSocketHost = "10.153.19.179";
//  export const WebSocketHost = "10.153.19.179";
// export const WebSocketHost = "192.168.0.39";
// export const WebSocketHost = "10.153.19.150";
// export const WebSocketHost = "10.153.19.218";
// export const WebSocketHost = "10.153.19.162";
// export const WebSocketHost = "127.0.0.1";
export const WebSocketHost = "127.0.0.1";
export const host = "88";
export const ErpIp = "10.153.19.179";
export const ErpHost = "8086";
UI-Project/src/views/EngineerScheduling/engineerScheduling.vue
@@ -1,161 +1,195 @@
<script lang="ts" setup>
import { ref, computed, watch, onMounted } from 'vue'
import { useI18n } from 'vue-i18n'
import { ElMessage, ElTransfer, ElTabs, ElTabPane, ElButton } from 'element-plus'
import {ref, computed, watch, onMounted} from 'vue'
import {useI18n} from 'vue-i18n'
import {ElMessage, ElTransfer, ElTabs, ElTabPane, ElButton} from 'element-plus'
import request from '@/utils/request'
const { t } = useI18n()
const {t} = useI18n()
const activeTab = ref('cutting1')
// Transfer组件所需的数据格式
interface TransferDataItem {
    key: string
    label: string
    projectNo: string
    projectName: string
  key: string
  label: string
  projectNo: string
  projectName: string
}
// 所有可选数据(左侧)
// Transfer组件所需的数据格式 - 完善字段定义
interface TransferDataItem {
  key: string
  projectNo: string
  projectName: string
  state?: number
  type?: number
  glassThickness?: string  // 玻璃厚度
  glassType?: string       // 玻璃类型
  glassTotal?: number      // 玻璃总数
  glassTotalArea?: number  // 玻璃总面积
}
// 所有可选数据(左侧表格)
const dataSource = ref<TransferDataItem[]>([])
// 已选数据的keys(右侧)
const targetKeys = ref<string[]>([])
// 根据当前标签页获取右侧列表标题
const getRightListTitle = computed(() => {
    switch (activeTab.value) {
        case 'cutting1':
            return t('large.countOutOne')
        case 'cutting2':
            return t('large.countOutTwo')
        case 'tempered':
            return t('large.temp')
        default:
            return '已排产'
// 已选数据(右侧表格)
const rightDataSource = ref<TransferDataItem[]>([])
// 左侧表格选中项
const selectedLeft = ref<TransferDataItem[]>([])
// 右侧表格选中项
const selectedRight = ref<TransferDataItem[]>([])
// 详情数据状态(改为数组类型,适应列表返回)
const detailData = ref<any[]>([]);
const showDetail = ref(false);
// 获取项目详情接口(更新为实际接口)
const fetchProjectDetail = async (projectNo: string) => {
  try {
    const response = await request.post('/loadGlass/optimizeProject/selectProgress', {
      projectNo: projectNo  // 传入工程ID(projectNo)
    });
    if (response.code === 200) {
      detailData.value = response.data;  // 假设返回数组
      showDetail.value = true;
    } else {
      ElMessage.error(`获取详情失败: ${response.message || '未知错误'}`);
    }
})
  } catch (error) {
    console.error('获取项目详情失败:', error);
    ElMessage.error('获取详情失败,请稍后重试');
  }
};
// 获取左侧数据源
// 获取左侧数据源 - 更新映射逻辑(包含所有字段)
const fetchDataSource = async () => {
    try {
        // 根据当前标签页选择不同的接口
        const apiUrl = activeTab.value === 'tempered'
            ? '/cacheVerticalGlass/bigStorageCageDetails/queryEngineer'
            : '/loadGlass/optimizeProject/queryEngineer';
  try {
    const apiUrl = activeTab.value === 'tempered'
        ? '/cacheVerticalGlass/bigStorageCageDetails/queryEngineer'
        : '/loadGlass/optimizeProject/queryEngineer';
        const response = await request.post(apiUrl)
    const response = await request.post(apiUrl)
        if (response.code === 200) {
            dataSource.value = response.data.map((item: any) => {
                const projectNo = activeTab.value === 'tempered' ? item.engineerId : item.projectNo
                const name = activeTab.value === 'tempered' ? item.engineerId : (item.projectNo + "-" + item.projectName)
                return {
                    key: projectNo,
                    label: name,
                    projectNo: projectNo,
                    projectName: activeTab.value === 'tempered' ? '' : item.projectName
                }
            })
        } else {
            ElMessage.error(`获取数据失败: ${response.message || '未知错误'}`)
        }
    } catch (error) {
        console.error('获取左侧数据失败:', error)
        ElMessage.error('请稍后重试')
    if (response.code === 200) {
      dataSource.value = response.data.map((item: any) => ({
        key: activeTab.value === 'tempered' ? item.engineerId : item.projectNo,
        projectNo: activeTab.value === 'tempered' ? item.engineerId : item.projectNo,
        projectName: item.projectName || '',
        state: item.state,
        type: item.type,
        glassThickness: item.glassThickness || '',
        glassType: item.glassType || '',
        glassTotal: item.glassTotal || 0,
        glassTotalArea: item.glassTotalArea || 0
      }))
    } else {
      ElMessage.error(`获取数据失败: ${response.message || '未知错误'}`)
    }
  } catch (error) {
    console.error('获取左侧数据失败:', error)
    ElMessage.error('请稍后重试')
  }
}
// 获取右侧已选数据
// 获取右侧已选数据 - 直接填充右侧表格
const fetchTargetKeys = async () => {
    try {
        // 根据当前标签页确定type参数
        let type = 1; // 默认切割一线
        if (activeTab.value === 'cutting2') {
            type = 2; // 切割二线
        } else if (activeTab.value === 'tempered') {
            type = 3; // 钢化
        }
  try {
    let type = 1;
    if (activeTab.value === 'cutting2') type = 2;
    else if (activeTab.value === 'tempered') type = 3;
        const response = await request.post('/loadGlass/optimizeProject/engineerScheduling', {
            type: type
        })
    const response = await request.post('/loadGlass/optimizeProject/engineerScheduling', {type})
    if (response.code === 200) {
      // 右侧表格数据
      rightDataSource.value = response.data.map((item: any) => ({
        key: item.projectNo,
        projectNo: item.projectNo,
        projectName: item.projectName || '',
        state: item.state,
        type: item.type,
        glassThickness: item.glassThickness || '',
        glassType: item.glassType || '',
        glassTotal: item.glassTotal || 0,
        glassTotalArea: item.glassTotalArea || 0
      }))
        if (response.code === 200) {
            // 对于所有标签页,使用projectNo作为key
            targetKeys.value = response.data.map((item: any) => item.projectNo)
            // 将右侧数据添加到dataSource中,确保Transfer组件能找到对应的项
            response.data.forEach((item: any) => {
                // 检查dataSource中是否已存在该项
                const exists = dataSource.value.some(dataItem => dataItem.key === item.projectNo)
                if (!exists) {
                    // 如果不存在,添加到dataSource中
                    const newItem: TransferDataItem = {
                        key: item.projectNo,
                        label: `${item.projectNo}-${item.projectName || 'null'}`,
                        projectNo: item.projectNo,
                        projectName: item.projectName || ''
                    }
                    dataSource.value.push(newItem)
                }
            })
        } else {
            ElMessage.error(`获取数据失败: ${response.message || '未知错误'}`)
        }
    } catch (error) {
        console.error('获取右侧数据失败:', error)
        ElMessage.error('请稍后重试')
      // 从左侧数据源移除右侧已选数据
      dataSource.value = dataSource.value.filter(
          item => !rightDataSource.value.some(rightItem => rightItem.key === item.key)
      )
    } else {
      ElMessage.error(`获取数据失败: ${response.message || '未知错误'}`)
    }
  } catch (error) {
    console.error('获取右侧数据失败:', error)
    ElMessage.error('请稍后重试')
  }
}
// 保存排产信息
// 修改:支持单行数据移动到右侧表格末尾
const moveToRight = (row: TransferDataItem) => {
  if (!row) return;
  // 从左侧表格移除当前行
  dataSource.value = dataSource.value.filter(item => item.key !== row.key);
  // 添加到右侧表格末尾
  rightDataSource.value.push(row);
  ElMessage.success(`已添加项目 ${row.projectNo}`);
}
// 修改:支持单行数据从右侧表格移回左侧表格
const moveToLeft = (row: TransferDataItem) => {
  if (!row) return;
  // 从右侧表格移除当前行
  rightDataSource.value = rightDataSource.value.filter(item => item.key !== row.key);
  // 添加到左侧表格
  dataSource.value.push(row);
  ElMessage.success(`已移除项目 ${row.projectNo}`);
}
// 更新保存逻辑 - 使用右侧表格数据
const saveScheduling = async () => {
    try {
        // 根据当前标签页确定type参数
        let type = 1; // 默认切割一线
        if (activeTab.value === 'cutting2') {
            type = 2; // 切割二线
        } else if (activeTab.value === 'tempered') {
            type = 3; // 钢化
        }
  try {
    let type = 1;
    if (activeTab.value === 'cutting2') type = 2;
    else if (activeTab.value === 'tempered') type = 3;
        const engineerList = targetKeys.value.map(projectNo => {
            const dataItem = dataSource.value.find(item => item.key === projectNo)
            return {
                projectNo: projectNo,
                projectName: dataItem ? dataItem.projectName : ''
            }
        })
    // 右侧表格数据即为需要保存的排产数据
    const engineerList = rightDataSource.value.map(item => ({
      projectNo: item.projectNo,
      projectName: item.projectName
    }))
        const response = await request.post(`/loadGlass/optimizeProject/updateEngineerScheduling?type=${type}`, engineerList)
    const response = await request.post(
        `/loadGlass/optimizeProject/updateEngineerScheduling?type=${type}`,
        engineerList
    )
        if (response.code === 200) {
            ElMessage.success('保存成功')
            // 重新加载数据
            await fetchDataSource()
            await fetchTargetKeys()
        } else {
            ElMessage.error(`保存失败: ${response.message || '未知错误'}`)
        }
    } catch (error) {
        console.error('保存排产信息失败:', error)
        ElMessage.error('请稍后重试')
    if (response.code === 200) {
      ElMessage.success('保存成功')
      await fetchDataSource()
      await fetchTargetKeys()
    } else {
      ElMessage.error(`保存失败: ${response.message || '未知错误'}`)
    }
  } catch (error) {
    console.error('保存排产信息失败:', error)
    ElMessage.error('请稍后重试')
  }
}
// 重置排产信息
const resetScheduling = async () => {
    await fetchDataSource()
    await fetchTargetKeys()
    ElMessage.info(t('已取消'))
  await fetchDataSource()
  await fetchTargetKeys()
  ElMessage.info(t('已取消'))
}
// 监听标签页切换,根据不同标签页加载对应的数据
watch(activeTab, async (newTab) => {
    // 重新获取数据
    await fetchDataSource()
    await fetchTargetKeys()
  // 重新获取数据
  await fetchDataSource()
  await fetchTargetKeys()
})
@@ -164,85 +198,332 @@
// 组件挂载时获取数据
onMounted(async () => {
    await fetchDataSource()
    await fetchTargetKeys()
  await fetchDataSource()
  await fetchTargetKeys()
})
// 判断是否为第一行
const isFirstRow = (row: TransferDataItem) => {
  const index = rightDataSource.value.findIndex(item => item.key === row.key);
  return index === 0;
};
// 判断是否为最后一行
const isLastRow = (row: TransferDataItem) => {
  const index = rightDataSource.value.findIndex(item => item.key === row.key);
  return index === rightDataSource.value.length - 1;
};
// 判断上方是否有进行中的行(state=100表示进行中,根据实际状态值调整)
const hasInProgressAbove = (row: TransferDataItem) => {
  const index = rightDataSource.value.findIndex(item => item.key === row.key);
  // 查找当前行上方是否有进行中的任务
  return rightDataSource.value.some((item, i) => i < index && item.state === 100);
};
// 向上移动一行
const moveUp = (row: TransferDataItem) => {
  const index = rightDataSource.value.findIndex(item => item.key === row.key);
  if (index > 0) {
    // 交换位置
    [rightDataSource.value[index], rightDataSource.value[index - 1]] =
        [rightDataSource.value[index - 1], rightDataSource.value[index]];
    // 触发响应式更新
    rightDataSource.value = [...rightDataSource.value];
  }
};
// 向下移动一行
const moveDown = (row: TransferDataItem) => {
  const index = rightDataSource.value.findIndex(item => item.key === row.key);
  if (index < rightDataSource.value.length - 1) {
    // 交换位置
    [rightDataSource.value[index], rightDataSource.value[index + 1]] =
        [rightDataSource.value[index + 1], rightDataSource.value[index]];
    // 触发响应式更新
    rightDataSource.value = [...rightDataSource.value];
  }
};
// 置顶(移动到第一个非进行中任务上方)
const moveToTop = (row: TransferDataItem) => {
  const index = rightDataSource.value.findIndex(item => item.key === row.key);
  if (index > 0) {
    // 移除当前行
    const newList = rightDataSource.value.filter(item => item.key !== row.key);
    // 查找第一个进行中任务的位置
    const firstInProgressIndex = newList.findIndex(item => item.state === 100);
    if (firstInProgressIndex === -1) {
      // 无进行中任务,直接添加到开头
      newList.unshift(row);
    } else {
      // 有进行中任务,添加到第一个进行中任务后面
      newList.splice(firstInProgressIndex + 1, 0, row);
    }
    // 更新数据源
    rightDataSource.value = newList;
  }
};
</script>
<template>
    <div class="engineer-scheduling-container">
        <el-tabs v-model="activeTab" class="custom-tabs">
            <el-tab-pane :label="t('large.countOutOne')" name="cutting1" />
            <el-tab-pane :label="t('large.countOutTwo')" name="cutting2" />
            <el-tab-pane :label="t('large.temp')" name="tempered" />
        </el-tabs>
  <div class="engineer-scheduling-container">
    <el-tabs v-model="activeTab" class="custom-tabs">
      <el-tab-pane :label="t('large.countOutOne')" name="cutting1"/>
      <el-tab-pane :label="t('large.countOutTwo')" name="cutting2"/>
      <el-tab-pane :label="t('large.temp')" name="tempered"/>
    </el-tabs>
        <div class="transfer-wrapper">
            <el-transfer v-model="targetKeys" class="custom-transfer" filterable :data="dataSource"
                :titles="['待排产', getRightListTitle]" :button-texts="['', '']">
                <template #right-empty>
                    <el-empty :image-size="80" description="No data" />
                </template>
            </el-transfer>
    <!-- 表格布局容器 -->
    <div class="table-container">
      <!-- 左侧表格:待排产 -->
      <div class="table-wrapper">
        <h3 class="table-title">{{ '待排产' }} ({{ dataSource.length }})</h3>
        <el-table
            :data="dataSource"
            border
            class="custom-table"
            height="400"
            row-key="key"
        >
          <el-table-column type="index" label="序号" width="55"/>
          <el-table-column prop="projectNo" label="工程ID" width="180"/>
          <el-table-column prop="glassThickness" label="玻璃厚度(mm)" width="120"/>
          <el-table-column prop="glassType" label="玻璃类型" width="120"/>
          <el-table-column prop="glassTotal" label="总片数" width="90"/>
          <el-table-column prop="glassTotalArea" label="总面积(㎡)" width="120"/>
          <el-table-column label="操作" width="120" align="center">
            <template #default="{ row }">
              <el-button type="primary" @click="moveToRight(row)">
                {{ t('添加') }}
              </el-button>
            </template>
          </el-table-column>
        </el-table>
      </div>
            <div class="transfer-save">
                <el-button type="primary" @click="saveScheduling">
                    {{ t('searchOrder.makesure') }}
      <!-- 右侧表格:已排产 -->
      <div class="table-wrapper">
        <h3 class="table-title">{{ t('scheduling.completed') }} ({{ rightDataSource.length }})</h3>
        <el-table
            :data="rightDataSource"
            border
            class="custom-table"
            height="400"
            row-key="key"
            @row-click="(row) => fetchProjectDetail(row.key)"
            highlight-current-row
        >
          <el-table-column type="index" label="序号" width="55"/>
          <el-table-column prop="projectNo" label="工程ID" width="120"/>
          <el-table-column prop="glassThickness" label="玻璃厚度(mm)" width="120"/>
          <el-table-column prop="glassType" label="玻璃类型" width="120"/>
          <el-table-column prop="glassTotal" label="总片数" width="90"/>
          <el-table-column prop="glassTotalArea" label="总面积(㎡)" width="120"/>
          <el-table-column label="操作" width="300" align="center">
            <template #default="{ row }">
              <div style="display: flex; gap: 5px; align-items: center;">
                <el-button
                    type="default"
                    size="small"
                    @click="moveToLeft(row)"
                    style="background: #ff4d4f; color: white; border-radius: 8px; min-width: 60px; display: inline-flex; justify-content: center; align-items: center;"
                >
                  去除
                </el-button>
                <el-button type="primary" @click="resetScheduling">
                    {{ t('delivery.cancel') }}
                <!-- 向上按钮 -->
                <el-button
                    type="default"
                    size="small"
                    @click="moveUp(row)"
                    :disabled="isFirstRow(row) || hasInProgressAbove(row)"
                    style="background: #E6F4FF; color: #1890FF; border-radius: 8px; min-width: 40px; display: inline-flex; justify-content: center; align-items: center;"
                >
                  ↑
                </el-button>
            </div>
        </div>
                <!-- 向下按钮 -->
                <el-button
                    type="default"
                    size="small"
                    @click="moveDown(row)"
                    :disabled="isLastRow(row)"
                    style="background: #E6F4FF; color: #1890FF; border-radius: 8px; min-width: 40px; display: inline-flex; justify-content: center; align-items: center;"
                >
                  ↓
                </el-button>
                <!-- 置顶按钮 -->
                <el-button
                    type="primary"
                    size="small"
                    @click="moveToTop(row)"
                    :disabled="isFirstRow(row) || hasInProgressAbove(row)"
                    style="background: #E6F4FF; color: #1890FF; border-radius: 8px; min-width: 60px; display: inline-flex; justify-content: center; align-items: center;"
                >
                  置顶
                </el-button>
              </div>
            </template>
          </el-table-column>
        </el-table>
      </div>
    </div>
    <!-- 保存和重置按钮 -->
    <div class="transfer-save">
      <el-button type="primary" @click="saveScheduling">
        {{ t('searchOrder.makesure') }}
      </el-button>
      <el-button type="primary" @click="resetScheduling">
        {{ t('delivery.cancel') }}
      </el-button>
    </div>
  </div>
  <!-- 详情展示区域(改为表格展示列表数据) -->
  <div v-if="showDetail" class="project-detail">
    <!--    <h3 class="detail-title">工程详情列表 ({{ detailData.length }})</h3>-->
    <el-table
        :data="detailData"
        border
        class="detail-table"
        height="230"
    >
      <el-table-column prop="engineerId" label="工程号" width="120"/>
      <el-table-column prop="flowCardId" label="流程卡号" width="150"/>
      <el-table-column prop="layer" label="层号" width="80"/>
      <el-table-column prop="glassType" label="订序" width="80"/>
      <el-table-column prop="thickness" label="厚度(mm)" width="100"/>
      <el-table-column prop="filmsid" label="膜系" width="120"/>
      <el-table-column prop="width" label="宽(mm)" width="90"/>
      <el-table-column prop="height" label="高(mm)" width="90"/>
      <el-table-column prop="glassIdCount" label="数量" width="80"/>
      <el-table-column prop="cuttingCount" label="切割" width="80"/>
      <el-table-column prop="edgingCount" label="磨边" width="80"/>
      <el-table-column prop="temperingCount" label="钢化" width="80"/>
      <el-table-column prop="insulatingCount" label="中空" width="80"/>
    </el-table>
  </div>
</template>
<style scoped>
/* 表格布局容器 */
.table-container {
  display: flex;
  align-items: center;
  gap: 20px;
  margin-bottom: 20px;
}
/* 详情表格样式 */
.project-detail {
  margin-top: 0px;
  padding: 15px;
  border: 1px solid #dcdfe6;
  border-radius: 4px;
  width: 100%;
  box-sizing: border-box;
  height: auto; /* 确保容器高度自适应 */
}
.detail-title {
  margin-bottom: 15px;
  font-size: 16px;
  font-weight: bold;
  color: #303133;
}
.detail-table {
  width: 100%;
  font-size: 14px;
}
/* 强制表格内容区域滚动 */
::v-deep(.detail-table .el-table__body-wrapper) {
  overflow-y: auto !important; /* 优先确保垂直滚动 */
  max-height: calc(230px - 50px); /* 适配表格高度(需与el-table height匹配) */
}
.table-wrapper {
  flex: 1;
}
.table-title {
  margin-bottom: 10px;
  font-size: 18px;
  font-weight: bold;
  color: #303133;
}
.custom-table {
  width: 100%;
  font-size: 14px;
}
/* 转移按钮样式 */
.transfer-buttons {
  display: flex;
  flex-direction: column;
}
/* 调整按钮区域位置 */
.transfer-save {
  display: flex;
  justify-content: center;
  gap: 10px;
  margin-top: 20px;
}
.engineer-scheduling-container {
    padding: 20px;
    border: 1px solid #dcdfe6;
    border-radius: 4px;
    background-color: #fff;
  padding: 20px;
  border: 1px solid #dcdfe6;
  border-radius: 4px;
  background-color: #fff;
}
.custom-tabs {
    margin-bottom: 20px;
  margin-bottom: 20px;
}
::v-deep(.custom-tabs .el-tabs__item) {
    font-size: 20px;
  font-size: 20px;
}
.transfer-wrapper {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 20px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 20px;
}
.transfer-save {
    display: flex;
    gap: 10px;
  display: flex;
  gap: 10px;
}
/* 自定义Transfer组件的样式 */
::v-deep(.el-transfer-panel) {
    font-size: 16px;
    width: 350px;
    height: 440px;
  font-size: 16px;
  width: 350px;
  height: 440px;
}
.custom-transfer {
    --el-transfer-panel-body-height: 400px;
  --el-transfer-panel-body-height: 400px;
}
::v-deep(.el-transfer-panel__header) {
    font-weight: bold;
    font-size: 18px;
  font-weight: bold;
  font-size: 18px;
}
::v-deep(.el-checkbox__label) {
    font-size: 16px;
  font-size: 16px;
}
</style>
hangzhoumesParent/common/servicebase/src/main/java/com/mes/pp/controller/OptimizeProjectController.java
@@ -1,14 +1,13 @@
package com.mes.pp.controller;
import com.baomidou.mybatisplus.extension.api.R;
import com.mes.pp.entity.OptimizeProject;
import com.mes.pp.entity.dto.ProgressDTO;
import com.mes.pp.entity.request.OptimizeRequest;
import com.mes.pp.service.OptimizeProjectService;
import com.mes.utils.Result;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import liquibase.pro.packaged.O;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@@ -66,6 +65,13 @@
        List<OptimizeProject> resultList = optimizeProjectService.updateEngineerScheduling(type, engineerList);
        return Result.build(200, "更新成功", resultList);
    }
    @ApiOperation("查询工程进度")
    @PostMapping("/selectProgress") //更新工程排产信息 engineerScheduling表
    @ResponseBody
    public Result<List<ProgressDTO>> selectProgress(@RequestBody OptimizeRequest optimizeRequest) {
        List<ProgressDTO> resultList = optimizeProjectService.selectProgress(optimizeRequest.getProjectNo());
        return Result.build(200, "更新成功", resultList);
    }
//    @ApiOperation("保存工程信息")
//    @PostMapping("/saveProject") //显示工程选择信息
hangzhoumesParent/common/servicebase/src/main/java/com/mes/pp/entity/OptimizeProject.java
@@ -1,6 +1,5 @@
package com.mes.pp.entity;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
@@ -50,7 +49,7 @@
    /**
     * 玻璃厚度
     */
    private String glassThickness;
    private Integer  glassThickness;
    /**
     * 工程种类
hangzhoumesParent/common/servicebase/src/main/java/com/mes/pp/entity/dto/ProgressDTO.java
New file
@@ -0,0 +1,39 @@
package com.mes.pp.entity.dto;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
/**
 * <p>
 *
 * </p>
 *
 * @author wu
 * @since 2024-07-25
 */
@Data
@EqualsAndHashCode(callSuper = false)
public class ProgressDTO implements Serializable {
    // 玻璃信息相关
    private String engineerId;         // 工程号(对应 glass_info.engineer_id)
    private String flowCardId;         // 流程卡号(对应 glass_info.flow_card_id)
    private Integer layer;             // 层号(对应 glass_info.layer)
    private Integer glassType;         // 玻璃类型(对应 glass_info.glass_type)
    private Double thickness;      // 厚度(对应 glass_info.thickness)
    private String filmsid;            // 膜系(对应 glass_info.filmsid)
    private Double width;          // 宽(对应 glass_info.width)
    private Double height;         // 高(对应 glass_info.height)
    // 数量统计相关
    private Integer glassIdCount;      // 玻璃总数(对应 COUNT(a.glass_id))
    // 报工统计相关(各工序报工数)
    private Integer cuttingCount;      // 切割报工数(对应切割工序 SUM(...))
    private Integer edgingCount;       // 磨边报工数(对应磨边工序 SUM(...))
    private Integer temperingCount;    // 钢化报工数(对应钢化工序 SUM(...))
    private Integer insulatingCount;   // 中空报工数(对应中空工序 SUM(...))
}
hangzhoumesParent/common/servicebase/src/main/java/com/mes/pp/mapper/OptimizeProjectMapper.java
@@ -3,6 +3,7 @@
import com.baomidou.dynamic.datasource.annotation.DS;
import com.github.yulichang.base.MPJBaseMapper;
import com.mes.pp.entity.OptimizeProject;
import com.mes.pp.entity.dto.ProgressDTO;
import com.mes.pp.entity.request.OptimizeRequest;
import liquibase.pro.packaged.L;
import org.apache.ibatis.annotations.Param;
@@ -57,4 +58,11 @@
     * @param types
     */
    void deleteByScheduling(@Param("engineerId") String engineerId,@Param("types") List<Integer> types);
    /**
     * 查询工程进度
     *
     * @param engineerId
     */
    List<ProgressDTO> selectProgress(@Param("engineerId") String engineerId);
}
hangzhoumesParent/common/servicebase/src/main/java/com/mes/pp/service/OptimizeProjectService.java
@@ -2,6 +2,7 @@
import com.github.yulichang.base.MPJBaseService;
import com.mes.pp.entity.OptimizeProject;
import com.mes.pp.entity.dto.ProgressDTO;
import com.mes.pp.entity.request.OptimizeRequest;
import com.mes.uppattenusage.entity.UpPattenUsage;
import io.swagger.models.auth.In;
@@ -71,4 +72,10 @@
     * @return
     */
    void deleteengineerSchedulingByid(String engineerId, List<Integer> types);
    /**
     * 查询工程进度
     *
     * @return ProgressDTO
     */
     List<ProgressDTO> selectProgress(String engineerId);
}
hangzhoumesParent/common/servicebase/src/main/java/com/mes/pp/service/impl/OptimizeProjectServiceImpl.java
@@ -9,6 +9,7 @@
import com.mes.engineering.entity.Engineering;
import com.mes.engineering.service.EngineeringService;
import com.mes.pp.entity.OptimizeProject;
import com.mes.pp.entity.dto.ProgressDTO;
import com.mes.pp.entity.request.OptimizeRequest;
import com.mes.pp.mapper.OptimizeProjectMapper;
import com.mes.pp.service.OptimizeProjectService;
@@ -127,4 +128,9 @@
    public void deleteengineerSchedulingByid(String engineerId, List<Integer> types) {
        baseMapper.deleteByScheduling(engineerId, types);
    }
    @Override
    public List<ProgressDTO> selectProgress(String engineerId) {
        return baseMapper.selectProgress(engineerId);
    }
}
hangzhoumesParent/common/servicebase/src/main/resources/mapper/OptimizeProjectMapper.xml
@@ -10,7 +10,6 @@
        <result property="thickness" column="glass_thickness"/>
        <result property="layoutSequence" column="heat_layout_sort"/>
        <result property="state" column="state"/>
    </resultMap>
    <resultMap id="resultMap" type="com.mes.pp.entity.OptimizeProject">
@@ -19,8 +18,25 @@
        <result property="projectName" column="project_name"/>
        <result property="state" column="state"/>
        <result property="type" column="type"/>
        <result property="glassThickness" column="glass_thickness"/>
        <result property="glassType" column="glass_type"/>
        <result property="glassTotal" column="glass_total"/>
        <result property="glassTotalArea" column="glass_total_area"/>
    </resultMap>
    <resultMap id="progressResultMap" type="com.mes.pp.entity.dto.ProgressDTO">
        <!-- 玻璃信息表(a)字段映射 -->
        <result property="engineerId" column="engineer_id"/>    <!-- 玻璃No → a.engineer_id -->
        <result property="flowCardId" column="flow_card_id"/>     <!-- 流程卡号 → a.flow_card_id -->
        <result property="layer" column="layer"/>     <!-- 层号 → a.layer -->
        <result property="glassType" column="glass_type"/>      <!-- 玻璃名称 → a.glass_type -->
        <result property="width" column="width"/>                <!-- 宽 → a.width -->
        <result property="height" column="height"/>              <!-- 高 → a.height -->
        <result property="glassIdCount" column="glassIdCount"/>      <!-- 订单数量 → 统计的 glassIdCount -->
        <result property="cuttingCount" column="cuttingCount"/>       <!-- 切割报工数 → cuttingCount -->
        <result property="edgingCount" column="edgingCount"/>   <!-- 磨边报工数 → edgingCount -->
         <result property="temperingCount" column="temperingCount"/>
         <result property="insulatingCount" column="insulatingCount"/>
    </resultMap>
    <select id="saveProject" parameterType="com.mes.pp.entity.request.OptimizeRequest" resultMap="sequenceMap">
        select a.project_no,
               1                                            as glass_type,
@@ -36,22 +52,29 @@
    <select id="queryEngineer" parameterType="com.mes.pp.entity.OptimizeProject" resultMap="resultMap">
        select p.project_no,
               p.project_name
               p.project_name,
               p.glass_thickness,
               p.glass_type,
               p.glass_total,
               p.glass_total_area
        from pp.optimize_project p
        where p.state = 100
          and p.project_no not in (
            select es.project_no
            from north_glass_mes.engineer_scheduling es
            where es.project_no is not null
        )
          and p.project_no not in (select es.project_no
                                   from north_glass_mes.engineer_scheduling es
                                   where es.project_no is not null)
        order by p.id
    </select>
    <select id="engineerScheduling" parameterType="com.mes.pp.entity.request.OptimizeRequest" resultMap="resultMap">
        select es.project_no,
        es.project_name,
        es.type
        es.type,
        p.glass_thickness,
        p.glass_type,
        p.glass_total,
        p.glass_total_area
        from north_glass_mes.engineer_scheduling es
        left join pp.optimize_project p on es.project_no=p.project_no
        where es.state = 100
        <if test="type != null and type != ''">
            and es.type = #{type}
@@ -93,5 +116,37 @@
            )
        </foreach>
    </insert>
    <select id="selectProgress" parameterType="com.mes.glassinfo.entity.GlassInfo" resultMap="progressResultMap">
        SELECT
        a.engineer_id,
        a.flow_card_id,
        a.layer,
        a.glass_type,
        a.thickness,
        a.filmsid,
        a.width,
        a.height,
        COUNT(a.glass_id) as glassIdCount,
        SUM(CASE WHEN d.working_procedure = '切割' AND d.type = 1 THEN 1 ELSE 0 END) as cuttingCount,
        SUM(CASE WHEN d.working_procedure = '磨边' AND d.type = 1 THEN 1 ELSE 0 END) as edgingCount,
        SUM(CASE WHEN d.working_procedure = '钢化' AND d.type = 1 THEN 1 ELSE 0 END) as temperingCount,
        SUM(CASE WHEN d.working_procedure = '中空' AND d.type = 1 THEN 1 ELSE 0 END) as insulatingCount
        FROM
        north_glass_mes.glass_info a
        LEFT JOIN
        north_glass_mes.damage d
        ON a.glass_id = d.glass_id
        AND a.engineer_id = d.engineer_id
        WHERE
        a.engineer_id = #{engineerId}
        GROUP BY
        a.engineer_id,
        a.flow_card_id,
        a.layer,
        a.glass_type,
        a.thickness,
        a.filmsid,
        a.width,
        a.height
    </select>
</mapper>
hangzhoumesParent/moduleService/CacheVerticalGlassModule/src/main/resources/application.yml
@@ -3,7 +3,7 @@
spring:
  profiles:
    active: yw
    active: dev
  application:
    name: cacheVerticalGlass
  liquibase:
hangzhoumesParent/moduleService/LoadGlassModule/src/main/resources/application.yml
@@ -2,7 +2,7 @@
  port: 10015
spring:
  profiles:
    active: yw
    active: dev
  application:
    name: loadGlass
  liquibase: