Merge branch 'master' of http://10.153.19.25:10105/r/ERP_override
| | |
| | | <div style="display: flex; height: 90vh;">
|
| | | <!-- Sidebar -->
|
| | | <div class="sidebar" style="width: 200px; background: #f4f4f4; padding: 10px; height: 93%; overflow-y: auto; max-height: 90vh; border-radius: 8px;">
|
| | | <div
|
| | | v-for="(layout, layoutIndex) in layouts"
|
| | | :key="layoutIndex"
|
| | | class="sidebar-item"
|
| | | @click="selectLayout(layoutIndex)"
|
| | | :class="{ 'selected': selectedLayoutIndex === layoutIndex }" style="margin-bottom: 5px;"
|
| | | >
|
| | | {{ layout.realWidth }} × {{ layout.realHeight }} × {{ layout.quantity }}
|
| | | <div class="folder">
|
| | | <div
|
| | | class="folder-header" style="padding: 8px; background: #e0e0e0; margin-bottom: 5px; border-radius: 4px; user-select: none; display: flex; justify-content: space-between; align-items: center;"
|
| | | >
|
| | | <span @click="toggleFolder('pending')" style="flex: 1; cursor: pointer;">待切割原片</span>
|
| | | <button
|
| | | @click="toggleFolder('pending')" style="background: none; border: none; cursor: pointer; font-size: 14px; padding: 2px 5px; border-radius: 3px;"
|
| | | :title="openFolders.pending ? '收起' : '展开'"
|
| | | >
|
| | | <el-icon v-if="openFolders.pending"><ArrowUp /></el-icon>
|
| | | <el-icon v-else><ArrowDown /></el-icon>
|
| | | </button>
|
| | | </div>
|
| | | <div v-show="openFolders.pending" class="folder-content" style="padding-left: 15px;">
|
| | | <div
|
| | | v-for="(layout, layoutIndex) in layouts"
|
| | | :key="layoutIndex"
|
| | | class="sidebar-item"
|
| | | @click="selectLayout(layoutIndex)"
|
| | | :class="{ 'selected': selectedLayoutIndex === layoutIndex }" style="margin-bottom: 5px;"
|
| | | >
|
| | | {{ layout.realWidth }} × {{ layout.realHeight }} × {{ layout.quantity }}
|
| | | </div>
|
| | | </div>
|
| | | </div>
|
| | |
|
| | | <!-- 待补片队列文件夹 -->
|
| | | <div class="folder">
|
| | | <div
|
| | | class="folder-header" style="padding: 8px; background: #e0e0e0; margin-bottom: 5px; border-radius: 4px; user-select: none; display: flex; justify-content: space-between; align-items: center;"
|
| | | >
|
| | | <span @click="toggleFolder('patchQueue')" style="flex: 1; cursor: pointer;">待补片队列</span>
|
| | | <button
|
| | | @click="toggleFolder('patchQueue')" style="background: none; border: none; cursor: pointer; font-size: 14px; padding: 2px 5px; border-radius: 3px;"
|
| | | :title="openFolders.patchQueue ? '收起' : '展开'"
|
| | | >
|
| | | <el-icon v-if="openFolders.patchQueue"><ArrowUp /></el-icon>
|
| | | <el-icon v-else><ArrowDown /></el-icon>
|
| | | </button>
|
| | | </div>
|
| | | <div v-show="openFolders.patchQueue" class="folder-content" style="padding-left: 15px;">
|
| | | <div style="padding: 10px; color: #666; font-style: italic;">
|
| | | 暂无补片任务
|
| | | </div>
|
| | | </div>
|
| | | </div>
|
| | |
|
| | | <!-- 添加自定义尺寸文件夹 -->
|
| | | <div class="folder">
|
| | | <div
|
| | | class="folder-header" style="padding: 8px; background: #e0e0e0; margin-bottom: 5px; border-radius: 4px; user-select: none; display: flex; justify-content: space-between; align-items: center;"
|
| | | >
|
| | | <span @click="toggleFolder('customSize')" style="flex: 1; cursor: pointer;">添加自定义尺寸</span>
|
| | | <button
|
| | | @click="toggleFolder('customSize')" style="background: none; border: none; cursor: pointer; font-size: 14px; padding: 2px 5px; border-radius: 3px;"
|
| | | :title="openFolders.customSize ? '收起' : '展开'"
|
| | | >
|
| | | <el-icon v-if="openFolders.customSize"><ArrowUp /></el-icon>
|
| | | <el-icon v-else><ArrowDown /></el-icon>
|
| | | </button>
|
| | | </div>
|
| | | <div v-show="openFolders.customSize" class="folder-content" style="padding-left: 15px;">
|
| | | <div style="padding: 10px;">
|
| | | <button
|
| | | @click="showAddCustomSizeDialog" style="width: 100%; padding: 8px; background: #409eff; color: white; border: none; border-radius: 4px; cursor: pointer;"
|
| | | >
|
| | | + 添加自定义尺寸
|
| | | </button>
|
| | | </div>
|
| | | </div>
|
| | | </div>
|
| | |
|
| | |
|
| | | </div>
|
| | |
|
| | | <!-- Main Layout Panel -->
|
| | |
| | | <script setup>
|
| | | import { ref, reactive, onMounted, onUnmounted } from 'vue';
|
| | | import { useRouter } from 'vue-router';
|
| | | import { ArrowUp, ArrowDown } from '@element-plus/icons-vue'
|
| | | import request from "@/utils/request";
|
| | | const router = useRouter();
|
| | | import { useI18n } from "vue-i18n";
|
| | |
| | | ElMessage.warning(res.msg);
|
| | | }
|
| | | });
|
| | | };
|
| | |
|
| | | const openFolders = ref({
|
| | | pending: true, // 默认展开"待切割原片"文件夹
|
| | | patchQueue: false, // 默认收起"待补片队列"文件夹
|
| | | customSize: false // 默认收起"添加自定义尺寸"文件夹
|
| | | });
|
| | |
|
| | | // 切换文件夹展开/收起状态
|
| | | const toggleFolder = (folderName) => {
|
| | | openFolders.value[folderName] = !openFolders.value[folderName];
|
| | | };
|
| | |
|
| | |
|
| | |
|
| | | const showAddCustomSizeDialog = () => {
|
| | | // 检查是否选择了版图
|
| | | if (selectedLayoutIndex.value === null || layouts.value.length === 0) {
|
| | | ElMessage.warning('请先选择一个版图');
|
| | | return;
|
| | | }
|
| | |
|
| | | // 使用现有的添加成品逻辑,传入当前选中的版图索引
|
| | | showAddDialog(selectedLayoutIndex.value);
|
| | | };
|
| | |
|
| | | //查询设置的基础信息架号,矩形颜色,订单序号等
|
| | |
| | | .context-menu div:hover {
|
| | | background-color: #f0f0f0;
|
| | | }
|
| | |
|
| | | .folder-header {
|
| | | font-weight: bold;
|
| | | }
|
| | |
|
| | | .folder-header:hover {
|
| | | background-color: #d0d0d0 !important;
|
| | | }
|
| | |
|
| | | .folder-content {
|
| | | border-left: 2px solid #ccc;
|
| | | margin-left: 5px;
|
| | | }
|
| | | </style>
|
| | |
| | | selectOrderList() |
| | | } |
| | | |
| | | //总价 |
| | | const totalPriceSum = ref() |
| | | |
| | | //页面跳转更新或者删除订单 |
| | | const getTableRow = (row,type) => { |
| | | switch (type) { |
| | |
| | | orderBomDetails.value=res.data.data |
| | | orderBomData.value.productName.forEach((product, i) => { |
| | | const details = orderBomDetails.value[i]?.data || [] |
| | | const perimeter = Number(product.perimeter || 0) |
| | | |
| | | // hollow:重算 consume、materialPric |
| | | details.forEach(d => { |
| | | if (d.detail_type === 'hollow') { |
| | | const glueDepth = Number(d.glueDepth || 0) |
| | | const thickness = Number(d.thickness || 0) |
| | | const price = Number(d.price || 0) |
| | | |
| | | // consume 保持为数字 |
| | | const consume = (glueDepth / 100) * (thickness / 100) * perimeter |
| | | d.consume = Number(consume.toFixed(2)) // 需要保留2位就转回 number |
| | | |
| | | // materialPric 也保持为数字 |
| | | d.materialPric = Number((d.consume * price).toFixed(2)) |
| | | } |
| | | }) |
| | | |
| | | // 生成 parts |
| | | const parts = product.product_name.split(/[*+]/) |
| | | parts.push("其它") |
| | | |
| | | product.product_parts = parts.map((p, idx) => { |
| | | // 找出所有 product_layer == idx+1 的 detail |
| | | const assignedDetails = details.filter(d => d.product_layer === idx + 1) |
| | | |
| | | return { |
| | | name: p, |
| | | details: assignedDetails |
| | | } |
| | | const assignedDetails = details.filter(d => Number(d.product_layer) === idx + 1) |
| | | return { name: p, details: assignedDetails } |
| | | }) |
| | | // 计算总价 |
| | | product.totalPrice = details.reduce((sum, d) => sum + (d.materialPric || 0) , 0) |
| | | |
| | | // 每个 product 的总价(保证数字相加) |
| | | product.totalPrice = details.reduce( |
| | | (sum, d) => sum + Number(d.materialPric || 0), |
| | | 0 |
| | | ) |
| | | }) |
| | | |
| | | // 成品合计:从 details 汇总 |
| | | const totalMap = new Map() |
| | | |
| | | orderBomDetails.value.forEach(block => { |
| | | const details = block?.data || [] |
| | | details.forEach(d => { |
| | | const consume = Number(d.consume || 0) |
| | | const price = Number(d.price || 0) |
| | | const key = `${Number(d.material_id)}|${String(d.detail_type || '')}|${price}` |
| | | |
| | | if (!totalMap.has(key)) { |
| | | totalMap.set(key, { |
| | | material_id: d.material_id, |
| | | material: d.material, |
| | | detail_type: d.detail_type, |
| | | price, |
| | | unit: d.unit, |
| | | type: d.type, |
| | | consume: 0, |
| | | materialPrice: 0 |
| | | }) |
| | | } |
| | | |
| | | const row = totalMap.get(key) |
| | | row.consume += consume |
| | | }) |
| | | }) |
| | | |
| | | const totalSumDatilsData = Array.from(totalMap.values()).map(r => ({ |
| | | ...r, |
| | | consume: Number(r.consume.toFixed(2)), |
| | | materialPrice: Number(r.materialPrice.toFixed(2)) |
| | | })) |
| | | |
| | | bomSum.value.sumDatilsData = totalSumDatilsData |
| | | |
| | | // 汇总总金额 |
| | | totalPriceSum.value = orderBomData.value.productName.reduce( |
| | | (sum, p) => sum + Number(p.totalPrice || 0), |
| | | 0 |
| | | ) |
| | | |
| | | dialogTableVisible.value = true |
| | | } |
| | | }) |
| | |
| | | } |
| | | } |
| | | |
| | | //总价 |
| | | const totalPrice = computed(() => { |
| | | return bomSum.value.sumDatilsData.reduce((sum, d) => sum + d.materialPrice, 0) |
| | | }) |
| | | |
| | | </script> |
| | | |
| | | <template> |
| | |
| | | |
| | | <!-- footer --> |
| | | <template #footer> |
| | | 合计 ¥{{ totalPrice }} |
| | | 合计 ¥{{ totalPriceSum }} |
| | | </template> |
| | | </el-card> |
| | | |
| | |
| | | import java.nio.file.Path; |
| | | import java.nio.file.Paths; |
| | | import java.sql.Date; |
| | | import java.util.HashMap; |
| | | import java.util.Map; |
| | | |
| | | @RestController |
| | |
| | | } |
| | | |
| | | |
| | | @PostMapping("/calculate") |
| | | public ResponseEntity<Map<String, Object>> receiveOptimizeRequest( |
| | | @RequestBody Map<String, Object> requestData) { |
| | | |
| | | Map<String, Object> response = new HashMap<>(); |
| | | |
| | | try { |
| | | // 立即返回接收成功的响应 |
| | | response.put("code", "200"); |
| | | response.put("msg", "success"); |
| | | response.put("data", ""); |
| | | |
| | | // 异步处理计算任务 |
| | | // glassOptimizeService.processExternalOptimizeRequest(requestData); |
| | | System.out.println(requestData); |
| | | |
| | | return ResponseEntity.ok(response); |
| | | } catch (Exception e) { |
| | | response.put("code", 201); |
| | | response.put("msg", "false: " + e.getMessage()); |
| | | response.put("data", ""); |
| | | return ResponseEntity.status(500).body(response); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | |
| | | Object produceId = row.get("produceId"); |
| | | Object tabId = row.get("tabId"); |
| | | Object layer = row.get("layer"); |
| | | if (tabId!=null){ |
| | | bomDataMapper.saveProductBOMMp(produceId,tabId,layer); |
| | | } |
| | | |
| | | bomDataMapper.saveProductBOMMp(produceId,tabId,layer); |
| | | } |
| | | } |
| | | } |
| | |
| | | </select> |
| | | |
| | | <select id="getBOMDetails"> |
| | | select bp.*,bb.*,(consume*price) as materialPric,od.quantity from sd.bom_product as bp |
| | | select bp.*,bb.*,(consume*price) as materialPric,od.quantity,pdd.detail_type, |
| | | IFNULL(JSON_UNQUOTE(JSON_EXTRACT(pdd.separation, '$.GlueDepth')),0) as glueDepth, |
| | | CAST(SUBSTRING_INDEX(IFNULL(JSON_UNQUOTE(JSON_EXTRACT(pdd.separation, '$.thickness')), '0mm'), 'mm', 1) AS DECIMAL(10, 2)) AS thickness |
| | | from sd.bom_product as bp |
| | | left join sd.bom_base as bb on bb.id=bp.base_id |
| | | left join ( select order_id,product_id,SUM(quantity) as quantity from sd.order_detail GROUP BY order_id,product_id |
| | | ) as od on od.product_id = bp.product_id |
| | | left join sd.product_detail as pdd on pdd.prod_id = bp.product_id and pdd.sort_num = bp.product_layer |
| | | where bp.product_id = #{productId} and od.order_id = #{orderId} ORDER BY product_layer |
| | | </select> |
| | | |
| | |
| | | sum(bb.consume) as consume, |
| | | sum(bb.price) as price, |
| | | sum(bb.consume * bb.price) AS materialPrice, |
| | | od.quantity |
| | | od.quantity, |
| | | pdd.detail_type, |
| | | IFNULL( JSON_UNQUOTE( JSON_EXTRACT( pdd.separation, '$.GlueDepth' )), 0 ) AS glueDepth, |
| | | CAST( |
| | | SUBSTRING_INDEX( IFNULL( JSON_UNQUOTE( JSON_EXTRACT( pdd.separation, '$.thickness' )), '0mm' ), 'mm', 1 ) AS DECIMAL ( 10, 2 )) AS thickness |
| | | FROM |
| | | sd.bom_product AS bp |
| | | LEFT JOIN sd.bom_base AS bb ON bb.id = bp.base_id |
| | | LEFT JOIN ( |
| | | select order_id,product_id,SUM(quantity) as quantity from sd.order_detail GROUP BY order_id,product_id |
| | | ) as od on od.product_id = bp.product_id |
| | | |
| | | LEFT JOIN sd.product_detail AS pdd ON pdd.prod_id = bp.product_id AND pdd.sort_num = bp.product_layer |
| | | WHERE od.order_id=#{orderId} |
| | | GROUP BY bb.material_id |
| | | ORDER BY bp.product_layer |