UI-Project/src/lang/zh.js
@@ -559,7 +559,6 @@ hollownumber: '中空总数量', hollowEngineer: '中空工程', hollowarea: '中空总面积', hollowtotal: '中空总时间', engineerId: '工程号', totalnumber: '总数量', tatalarea: '总面积', @@ -990,5 +989,38 @@ pwidth: '请输入宽度', pheight: '请输入高度', upnumber: '上片数量', }, scheduling:{ cuttingCount: '切割', edgingCount: '磨边', temperingCount: '钢化', insulatingCount: '中空', completed:"已排产", completedCount: '完成数量', unfinished:'待排产', serial: '序号', projectNo: '工程ID', thickness: '厚度(mm)', glassType: '玻璃类型', coatingType: '膜系', layerCount: '层数', height: '长(mm)', width: '宽(mm)', state: '状态', glassCount: '数量', operate: '操作', totalCount: '总片数', totalArea: '总面积(㎡)', remove: '去除', top: '置顶', order: '出片顺序', flowCardId: '流程卡号', add: '添加', cancelled: '已取消', saveFailed: '保存排产信息失败', retryLater: '请稍后重试', saveSuccess: '保存成功', totalFireCount: '总炉数', fullFireCount: '满炉数', } } 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
@@ -16,29 +16,51 @@ projectName: string } // 所有可选数据(左侧) 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 '已排产' // 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[]>([]) // 已选数据(右侧表格) 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'; @@ -46,17 +68,17 @@ 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 } }) 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 || '未知错误'}`) } @@ -66,40 +88,38 @@ } } // 获取右侧已选数据 // 获取右侧已选数据 - 直接填充右侧表格 const fetchTargetKeys = async () => { try { // 根据当前标签页确定type参数 let type = 1; // 默认切割一线 let type = 1; let response; if (activeTab.value === 'cutting2') { type = 2; // 切割二线 type = 2; response = await request.post('/loadGlass/optimizeProject/engineerScheduling', {type}) } else if (activeTab.value === 'tempered') { type = 3; // 钢化 type = 3; response = await request.post('/cacheVerticalGlass/bigStorageCageDetails/queryTemperingOrder') } else { response = await request.post('/loadGlass/optimizeProject/engineerScheduling', {type}) } const response = await request.post('/loadGlass/optimizeProject/engineerScheduling', { type: type }) 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 = { // 右侧表格数据 rightDataSource.value = response.data.map((item: any) => ({ key: item.projectNo, label: `${item.projectNo}-${item.projectName || 'null'}`, projectNo: item.projectNo, projectName: item.projectName || '' } dataSource.value.push(newItem) } }) projectName: item.projectName || '', state: item.state, type: item.type, glassThickness: item.glassThickness || '', glassType: item.glassType || '', glassTotal: item.glassTotal || 0, glassTotalArea: item.glassTotalArea || 0 })) // 从左侧数据源移除右侧已选数据 dataSource.value = dataSource.value.filter( item => !rightDataSource.value.some(rightItem => rightItem.key === item.key) ) } else { ElMessage.error(`获取数据失败: ${response.message || '未知错误'}`) } @@ -109,30 +129,50 @@ } } // 保存排产信息 // 修改:支持单行数据移动到右侧表格末尾 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; // 钢化 } 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 { @@ -148,7 +188,7 @@ const resetScheduling = async () => { await fetchDataSource() await fetchTargetKeys() ElMessage.info(t('已取消')) ElMessage.info(t('scheduling.cancelled')) } // 监听标签页切换,根据不同标签页加载对应的数据 @@ -167,6 +207,128 @@ 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; }; // 判断上方是否有进行中的行(修复:使用正确的状态值1) const hasInProgressAbove = (row: TransferDataItem) => { const index = rightDataSource.value.findIndex(item => item.key === row.key); // 查找当前行上方是否有进行中的任务 return rightDataSource.value.some((item, i) => i < index && item.state === 1); }; // 向上移动一行 const moveUp = (row: TransferDataItem) => { const index = rightDataSource.value.findIndex(item => item.key === row.key); if (index > 0) { // 检查是否会超过进行中的任务 const prevItem = rightDataSource.value[index - 1]; if (prevItem.state === 1) { // 直接上方是进行中任务,提示用户不可超过 ElMessage.warning('操作不可超过进行中的任务'); return; } // 交换位置 [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 canMoveToTop = (row: TransferDataItem) => { // 进行中任务不能置顶 if (row.state === 1) return false; const index = rightDataSource.value.findIndex(item => item.key === row.key); // 已经是第一行的不能置顶 if (index === 0) return false; // 查找第一个非进行中任务的位置 const firstNonProgressIndex = rightDataSource.value.findIndex(item => item.state !== 1); // 如果当前行已经在第一个非进行中任务的位置或之前,则不能置顶 return index > firstNonProgressIndex; }; // ... existing code (moveUp和moveDown函数保持不变) // 置顶(移动到所有非进行中任务的最前面) 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 nonProgressIndices = newList .map((item, i) => ({ item, index: i })) .filter(item => item.item.state !== 1) .map(item => item.index); if (nonProgressIndices.length > 0) { // 有非进行中任务,添加到第一个非进行中任务的位置 newList.splice(nonProgressIndices[0], 0, row); } else { // 全部都是进行中任务,添加到开头 newList.unshift(row); } // 更新数据源 rightDataSource.value = newList; } }; // 创建计算属性,根据标签页返回不同的表头配置 const tableHeaders = computed(() => { const baseHeaders = { serial: t('scheduling.serial'), projectNo: t('scheduling.projectNo'), thickness: t('scheduling.thickness'), glassType: t('scheduling.glassType'), totalCount: t('scheduling.totalCount'), totalArea: t('scheduling.totalArea'), operate: t('scheduling.operate') }; // 根据不同标签页返回不同的表头配置 if (activeTab.value === 'tempered') { return { ...baseHeaders, // 更改钢化标签页的特定表头 totalCount: t('scheduling.totalFireCount'), totalArea: t('scheduling.fullFireCount') }; } return baseHeaders; }); // 状态格式化函数 const stateFormatter = (row: any) => { return row.state === 1 ? '进行中' : '未开始'; }; </script> <template> @@ -177,15 +339,106 @@ <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" /> <!-- 表格布局容器 --> <div class="table-container"> <!-- 左侧表格:待排产 --> <div class="table-wrapper" v-if="activeTab !== 'tempered'"> <h3 class="table-title">{{ t('scheduling.unfinished') }} ({{ dataSource.length }})</h3> <el-table :data="dataSource" border class="custom-table" height="400" row-key="key" > <el-table-column type="index" :label="$t('scheduling.serial')" width="55"/> <el-table-column prop="projectNo" :label="$t('scheduling.projectNo')" width="150"/> <el-table-column prop="glassThickness" :label="$t('scheduling.thickness')" width="120"/> <el-table-column prop="glassType" :label="$t('scheduling.glassType')" width="120"/> <el-table-column prop="glassTotal" :label="$t('scheduling.totalCount')" width="90"/> <el-table-column prop="glassTotalArea" :label="$t('scheduling.totalArea')" width="100"/> <el-table-column :label="$t('scheduling.operate')" width="90" align="center"> <template #default="{ row }"> <el-button type="primary" @click="moveToRight(row)"> {{ t('scheduling.add') }} </el-button> </template> </el-transfer> </el-table-column> </el-table> </div> <!-- 右侧表格:已排产 --> <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="tableHeaders.serial" width="55"/> <el-table-column prop="projectNo" :label="tableHeaders.projectNo" width="120"/> <el-table-column prop="glassThickness" :label="tableHeaders.thickness" width="120"/> <el-table-column prop="glassType" :label="tableHeaders.glassType" width="120"/> <el-table-column prop="glassTotal" :label="tableHeaders.totalCount" width="90"/> <el-table-column prop="glassTotalArea" :label="tableHeaders.totalArea" width="120"/> <el-table-column prop="state" :label="t('scheduling.state')" width="90" :formatter="stateFormatter" /> <el-table-column :label="t('scheduling.operate')" :width="activeTab === 'tempered' ? 200 : 300" :align="center"> <template #default="{ row }"> <div style="display: flex; gap: 5px; align-items: center;"> <el-button v-if="activeTab !== 'tempered'" type="default" size="small" @click="moveToLeft(row)" :disabled="row.state === 1" style="background: #ff4d4f; color: white; border-radius: 8px; min-width: 60px; display: inline-flex; justify-content: center; align-items: center;" > {{ t('scheduling.remove') }} </el-button> <el-button type="default" size="small" @click="moveUp(row)" :disabled="row.state === 1 || isFirstRow(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="default" size="small" @click="moveDown(row)" :disabled="row.state === 1 || 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 size="small" @click="moveToTop(row)" :disabled="row.state === 1 || isFirstRow(row) || !canMoveToTop(row)" style="background: #E6F4FF; color: #1890FF; border-radius: 8px; min-width: 60px; display: inline-flex; justify-content: center; align-items: center;" > {{ t('scheduling.top') }} </el-button> </div> </template> </el-table-column> </el-table> </div> </div> <!-- 保存和重置按钮 --> <div class="transfer-save"> <el-button type="primary" @click="saveScheduling"> {{ t('searchOrder.makesure') }} @@ -195,10 +448,101 @@ </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="$t('scheduling.projectNo')" width="120"/> <el-table-column prop="flowCardId" :label="$t('scheduling.flowCardId')" width="150"/> <el-table-column prop="layer" :label="$t('scheduling.layerCount')" width="80"/> <el-table-column prop="glassType" :label="$t('scheduling.serial')" width="80"/> <el-table-column prop="thickness" :label="$t('scheduling.thickness')" width="100"/> <el-table-column prop="filmsid" :label="$t('scheduling.coatingType')" width="120"/> <el-table-column prop="width" :label="$t('scheduling.width')" width="90"/> <el-table-column prop="height" :label="$t('scheduling.height')" width="90"/> <el-table-column prop="glassIdCount" :label="$t('scheduling.glassCount')" width="80"/> <el-table-column prop="cuttingCount" :label="$t('scheduling.cuttingCount')" width="80"/> <el-table-column prop="edgingCount" :label="$t('scheduling.edgingCount')" width="80"/> <el-table-column prop="temperingCount" :label="$t('scheduling.temperingCount')" width="80"/> <el-table-column prop="insulatingCount" :label="$t('scheduling.insulatingCount')" 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; hangzhoumesParent/common/servicebase/src/main/java/com/mes/engineerScheduling/controller/EngineerSchedulingController.java
New file @@ -0,0 +1,21 @@ package com.mes.engineerScheduling.controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * <p> * 前端控制器 * </p> * * @author wf * @since 2025-10-27 */ @RestController @RequestMapping("/engineerScheduling/engineer-scheduling") public class EngineerSchedulingController { } hangzhoumesParent/common/servicebase/src/main/java/com/mes/engineerScheduling/entity/EngineerScheduling.java
New file @@ -0,0 +1,50 @@ package com.mes.engineerScheduling.entity; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import java.io.Serializable; import lombok.Data; import lombok.EqualsAndHashCode; /** * <p> * * </p> * * @author wf * @since 2025-10-27 */ @Data @EqualsAndHashCode(callSuper = false) public class EngineerScheduling implements Serializable { private static final long serialVersionUID = 1L; /** * 工程排产id */ @TableId(value = "id", type = IdType.AUTO) private Long id; /** * 工程编号 */ private String projectNo; /** * 工程项目名 */ private String projectName; /** * 类型 */ private Integer type; /** * 状态 */ private Integer state; } hangzhoumesParent/common/servicebase/src/main/java/com/mes/engineerScheduling/mapper/EngineerSchedulingMapper.java
New file @@ -0,0 +1,16 @@ package com.mes.engineerScheduling.mapper; import com.mes.engineerScheduling.entity.EngineerScheduling; import com.baomidou.mybatisplus.core.mapper.BaseMapper; /** * <p> * Mapper 接口 * </p> * * @author wf * @since 2025-10-27 */ public interface EngineerSchedulingMapper extends BaseMapper<EngineerScheduling> { } hangzhoumesParent/common/servicebase/src/main/java/com/mes/engineerScheduling/mapper/xml/EngineerSchedulingMapper.xml
New file @@ -0,0 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.mes.engineerScheduling.mapper.EngineerSchedulingMapper"> </mapper> hangzhoumesParent/common/servicebase/src/main/java/com/mes/engineerScheduling/service/EngineerSchedulingService.java
New file @@ -0,0 +1,16 @@ package com.mes.engineerScheduling.service; import com.mes.engineerScheduling.entity.EngineerScheduling; import com.baomidou.mybatisplus.extension.service.IService; /** * <p> * 服务类 * </p> * * @author wf * @since 2025-10-27 */ public interface EngineerSchedulingService extends IService<EngineerScheduling> { } hangzhoumesParent/common/servicebase/src/main/java/com/mes/engineerScheduling/service/impl/EngineerSchedulingServiceImpl.java
New file @@ -0,0 +1,20 @@ package com.mes.engineerScheduling.service.impl; import com.mes.engineerScheduling.entity.EngineerScheduling; import com.mes.engineerScheduling.mapper.EngineerSchedulingMapper; import com.mes.engineerScheduling.service.EngineerSchedulingService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.springframework.stereotype.Service; /** * <p> * 服务实现类 * </p> * * @author wf * @since 2025-10-27 */ @Service public class EngineerSchedulingServiceImpl extends ServiceImpl<EngineerSchedulingMapper, EngineerScheduling> implements EngineerSchedulingService { } 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,27 +52,36 @@ <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 and p.project_no not in (select es.project_no from north_glass_mes.engineer_scheduling es where es.project_no is not null ) 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, IFNULL(e.state,0) as state from north_glass_mes.engineer_scheduling es left join pp.optimize_project p on es.project_no=p.project_no left join north_glass_mes.engineering e on es.project_no=e.engineer_id where es.state = 100 <if test="type != null and type != ''"> and es.type = #{type} </if> order by es.id order by case when IFNULL(e.state, 0) = 1 then 0 else 1 end, es.id </select> <!-- 根据类型删除engineer_scheduling表中的数据 --> @@ -93,5 +118,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/java/com/mes/bigstorage/controller/BigStorageCageDetailsController.java
@@ -203,5 +203,13 @@ List<BigStorageCageDetails> result = bigStorageCageDetailsService.queryEngineer(); return Result.build(200, "", result); } @ApiOperation("查询钢化排产顺序") @PostMapping("/queryTemperingOrder") //显示工程排产信息 @ResponseBody public Result<List<OptimizeProject>> queryTemperingOrder() { List<OptimizeProject> result = bigStorageCageDetailsService.queryTemperingOrder(); return Result.build(200, "", result); } } hangzhoumesParent/moduleService/CacheVerticalGlassModule/src/main/java/com/mes/bigstorage/mapper/BigStorageCageDetailsMapper.java
@@ -71,4 +71,6 @@ BigStorageSlotDTO queryNeedDispatchSlotBySequence(); List<TemperingGlassCountDTO> queryTemperingGlassCountSummary(int isTempering); } hangzhoumesParent/moduleService/CacheVerticalGlassModule/src/main/java/com/mes/bigstorage/service/BigStorageCageDetailsService.java
@@ -150,4 +150,9 @@ List<BigStorageCageDetails> queryNeedDispatch(); BigStorageSlotDTO queryNeedDispatchSlotBySequence(); /** * 查询钢化排产顺序 * @return OptimizeProject 钢化排产顺序 */ List<OptimizeProject> queryTemperingOrder(); } hangzhoumesParent/moduleService/CacheVerticalGlassModule/src/main/java/com/mes/bigstorage/service/impl/BigStorageCageDetailsServiceImpl.java
@@ -29,6 +29,8 @@ import com.mes.glassinfo.entity.GlassInfo; import com.mes.glassinfo.mapper.GlassInfoMapper; import com.mes.glassinfo.service.GlassInfoService; import com.mes.pp.entity.OptimizeProject; import com.mes.pp.service.OptimizeProjectService; import com.mes.sysconfig.entity.SysConfig; import com.mes.sysconfig.service.SysConfigService; import com.mes.temperingglass.entity.TemperingGlassInfo; @@ -41,6 +43,7 @@ import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.util.*; import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -69,6 +72,8 @@ private BigStorageCageService bigStorageCageService; @Resource private GlassInfoMapper glassInfoMapper; @Resource private OptimizeProjectService optimizeProjectService; @Resource private GlassInfoService glassInfoService; @@ -587,4 +592,32 @@ public BigStorageSlotDTO queryNeedDispatchSlotBySequence() { return baseMapper.queryNeedDispatchSlotBySequence(); } @Override public List<OptimizeProject> queryTemperingOrder() { String temperingengineerId = redisUtil.getCacheObject("temperingEngineerId"); List<TemperingGlassCountDTO> temperingGlassCountDTOS = baseMapper.queryTemperingGlassCountSummary(1); List<OptimizeProject> projectList = optimizeProjectService.engineerScheduling(new OptimizeProject() {{ setType(3); }}); Set<String> projectNoSet = projectList.stream() .map(OptimizeProject::getProjectNo) .collect(Collectors.toSet()); List<OptimizeProject> resultList= new ArrayList<>(); for (TemperingGlassCountDTO dto : temperingGlassCountDTOS) { if (projectNoSet.contains(dto.getEngineerId())) { OptimizeProject project = new OptimizeProject(); if (Objects.equals(dto.getEngineerId(), temperingengineerId)) { project.setState(1); } project.setProjectNo(dto.getEngineerId()); project.setGlassType(dto.getFilmsId()); project.setGlassThickness(dto.getThickness().intValue()); project.setGlassTotal(dto.getTotalCount()); project.setGlassTotalArea(dto.getRealCount()); resultList.add(project); } } return resultList; } } hangzhoumesParent/moduleService/CacheVerticalGlassModule/src/main/resources/application.yml
@@ -3,7 +3,7 @@ spring: profiles: active: yw active: dev application: name: cacheVerticalGlass liquibase: hangzhoumesParent/moduleService/CacheVerticalGlassModule/src/main/resources/mapper/BigStorageCageDetailsMapper.xml
@@ -326,4 +326,60 @@ t1.tempering_feed_sequence -1 )select * from result limit 1 </select> <select id="queryTemperingGlassCountSummary" resultMap="temperingGlassCount"> with glass_info_temp as ( select engineer_id, tempering_layout_id, count(*) as total_count from glass_info group by engineer_id, tempering_layout_id ), big_details_temp as ( select engineer_id, tempering_layout_id, count(*) as real_count, films_id, thickness from big_storage_cage_details where state = 100 <if test="isTempering == 0"> and tempering_layout_id = 0 </if> <if test="isTempering == 1"> and tempering_layout_id != 0 </if> group by engineer_id, tempering_layout_id, films_id, thickness ), damage_temp as ( select engineer_id, tempering_layout_id, count(*) as damage_count from damage where type in(8,9) and STATUS = 1 group by engineer_id, tempering_layout_id ), result as ( select t.engineer_id, t.tempering_layout_id, t.films_id, t.thickness, total_count, real_count, ifnull(damage_count, 0) as damage_count, case when total_count - real_count - ifnull(damage_count, 0) < 0 then 0 else total_count - real_count - ifnull(damage_count, 0) end as lack_count from big_details_temp t inner join glass_info_temp t1 on t.engineer_id = t1.engineer_id and t.tempering_layout_id = t1.tempering_layout_id left join damage_temp t2 on t.engineer_id = t2.engineer_id and t.tempering_layout_id = t2.tempering_layout_id ), -- 二次汇总层 secondary_summary as ( select engineer_id, films_id, thickness, count(distinct tempering_layout_id) as total_count, -- 计算totalCount的累计数(去重计数) sum(total_count) as real_count -- 计算realCount的总和 from result group by engineer_id, films_id, thickness ) select * from secondary_summary order by engineer_id, films_id, thickness </select> </mapper> hangzhoumesParent/moduleService/LoadGlassModule/src/main/resources/application.yml
@@ -2,7 +2,7 @@ port: 10015 spring: profiles: active: yw active: dev application: name: loadGlass liquibase: