|
|
@@ -1,3340 +1,3341 @@
|
|
|
-<template>
|
|
|
- <div>
|
|
|
- <layout>
|
|
|
- <layout-content >
|
|
|
- <div class="gva-table-box">
|
|
|
- <div style="display: flex; align-items: baseline; margin-bottom: 10px;">
|
|
|
- <h1 style="margin: 0; margin-bottom: 10px;">{{_code}}工分报工</h1>
|
|
|
- </div>
|
|
|
- <div class="gongfen-toolbar-row">
|
|
|
- <el-input
|
|
|
- v-model="add_searchInfo"
|
|
|
- placeholder="请扫描订单二维码"
|
|
|
- @keyup.enter="add_onSubmit"
|
|
|
- id="searchInput"
|
|
|
- class="gongfen-order-search-input"
|
|
|
- :disabled="workScoreDialogVisible"/>
|
|
|
- <el-button type="primary" icon="search" class="gongfen-search-btn" :disabled="workScoreDialogVisible" @click="add_onSubmit">查询</el-button>
|
|
|
- <span class="gongfen-toolbar-label">机台号</span>
|
|
|
- <el-input v-model="add_formData['机台号']" readonly class="gongfen-toolbar-field" />
|
|
|
- <span class="gongfen-toolbar-label">工序</span>
|
|
|
- <el-input v-model="add_formData['工序']" readonly class="gongfen-toolbar-field" />
|
|
|
- <span class="gongfen-toolbar-label">组别</span>
|
|
|
- <el-input v-model="add_formData['组别']" readonly class="gongfen-toolbar-field" />
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 订单信息显示区域 -->
|
|
|
- <div style="margin-top: 20px; margin-bottom: 20px; display: flex; justify-content: space-between; align-items: flex-start;">
|
|
|
- <div style="flex: 1;">
|
|
|
- <el-table :data="orderInfoList" style="width: 100%">
|
|
|
- <el-table-column prop="订单编号" label="订单编号" width="110" />
|
|
|
- <el-table-column prop="生产款号" label="生产款号" width="300" />
|
|
|
- <el-table-column prop="款式" label="款式" width="220" />
|
|
|
- <el-table-column prop="订单数量" label="订单数量" width="110" />
|
|
|
-
|
|
|
- </el-table>
|
|
|
- </div>
|
|
|
- <div class="gongfen-order-actions">
|
|
|
- <el-button type="success" icon="document" class="gongfen-work-score-btn" :disabled="!currentOrderNo" :loading="loadingProcess && !workScoreDialogVisible" @click="openWorkScoreDialog">工分报工</el-button>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="gongfen-report-tabs">
|
|
|
- <!-- 表格数据 -->
|
|
|
- <el-tabs v-model="activeName" @tab-click="onGongfenTabClick">
|
|
|
- <el-tab-pane label="当天报工记录" name="first">
|
|
|
- <el-table
|
|
|
- ref="gongfenHistoryTableRef"
|
|
|
- class="gongfen-history-table"
|
|
|
- style="width: 100%; height: 52vh"
|
|
|
- tooltip-effect="dark"
|
|
|
- :row-style="{ height: '38px' }"
|
|
|
- :header-cell-style="gongfenHistoryHeaderCellStyle"
|
|
|
- :cell-style="gongfenHistoryCellStyle"
|
|
|
- :footer-cell-style="gongfenHistoryFooterCellStyle"
|
|
|
- :header-row-style="{ height: '34px' }"
|
|
|
- :data="filteredGongfenHistoryData"
|
|
|
- border
|
|
|
- row-key="ID"
|
|
|
- size="small"
|
|
|
- show-summary
|
|
|
- scrollbar-always-on
|
|
|
- :summary-method="getGongfenHistorySummaries"
|
|
|
- highlight-current-row
|
|
|
- show-overflow-tooltip
|
|
|
- @row-click="tableRowClick"
|
|
|
- >
|
|
|
- <el-table-column align="center" label="小组" prop="sys_id" :width="90" show-overflow-tooltip />
|
|
|
- <el-table-column align="center" label="订单编号" prop="work_order" :width="100" />
|
|
|
- <el-table-column align="center" label="工序号" prop="process_code" :width="90" />
|
|
|
- <el-table-column align="left" label="工序名称" prop="process_name" min-width="200" show-overflow-tooltip />
|
|
|
- <el-table-column align="center" label="员工姓名" prop="staff_name" :width="120">
|
|
|
- <template #header>
|
|
|
- <div class="gongfen-col-header">
|
|
|
- <span>员工姓名</span>
|
|
|
- <el-popover trigger="click" placement="bottom-start" :width="180" :teleported="true" :z-index="10050" append-to-body popper-class="gy-detail-filter-popper">
|
|
|
- <template #reference>
|
|
|
- <span class="gy-detail-filter-btn" :class="{ 'is-active': isStaffNameFilterActive }" @click.stop>
|
|
|
- <svg viewBox="0 0 1024 1024" width="14" height="14" aria-hidden="true"><path fill="currentColor" d="M880.1 154H143.9c-24.5 0-39.9 26.7-27.6 48L349 597.4V838c0 17.7 14.2 32 31.8 32h262.4c17.6 0 31.8-14.3 31.8-32V597.4L907.7 202c12.2-21.3-3.1-48-27.6-48z"/></svg>
|
|
|
- </span>
|
|
|
- </template>
|
|
|
- <div class="gy-detail-filter-panel">
|
|
|
- <div class="gy-detail-filter-options">
|
|
|
- <el-checkbox-group v-model="staffNameFilter">
|
|
|
- <el-checkbox v-for="item in staffNameFilterOptions" :key="item.value" :label="item.value">{{ item.text }}</el-checkbox>
|
|
|
- </el-checkbox-group>
|
|
|
- </div>
|
|
|
- <div class="gy-detail-filter-actions">
|
|
|
- <span class="gy-detail-filter-link" @click.stop="clearStaffNameFilter">取消全选</span>
|
|
|
- <span class="gy-detail-filter-link" @click.stop="selectAllStaffNameFilter">全选</span>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </el-popover>
|
|
|
- </div>
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
- <el-table-column align="center" label="数量" prop="number" :width="90" />
|
|
|
- <el-table-column align="center" label="报工时间" prop="sys_rq" :width="180" show-overflow-tooltip />
|
|
|
- <el-table-column align="center" label="操作" :width="160" fixed="right">
|
|
|
- <template #default="scope">
|
|
|
- <el-button type="primary" size="small" @click.stop="openEditReportingQty(scope.row)">修改</el-button>
|
|
|
- <el-button type="danger" size="small" @click.stop="deleteReportingWork(scope.row)">删除</el-button>
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
- </el-table>
|
|
|
- </el-tab-pane>
|
|
|
-
|
|
|
- <el-tab-pane label="工序产量核查" name="processProduction" lazy>
|
|
|
- <ProcessProduction
|
|
|
- ref="processProductionRef"
|
|
|
- :key="`${currentOrderNo || 'empty'}-${processProductionRefreshKey}`"
|
|
|
- :initial-workorder="currentOrderNo"
|
|
|
- :initial-process="add_formData['工序']"
|
|
|
- :initial-sys-id="add_formData['组别']"
|
|
|
- embedded-in-tab
|
|
|
- hide-amount-columns
|
|
|
- />
|
|
|
- </el-tab-pane>
|
|
|
-
|
|
|
- <el-tab-pane label="订单资料附件" name="third">
|
|
|
- <el-table ref="multipleTable"
|
|
|
- :row-style="{ height: '30px' }"
|
|
|
- :cell-style="{ padding: '0px' }" :header-row-style="{ height: '30px' }"
|
|
|
- :header-cell-style="{ padding: '0px' }"
|
|
|
- :show-overflow-tooltip="true"
|
|
|
- :cell-class-name="planUsageCellClass"
|
|
|
- highlight-current-row="true"
|
|
|
- @row-dblclick="gdbomupdateCompanyFunc"
|
|
|
- style="width: 100%;height: 36vh" border tooltip-effect="dark" :data="ddtableData" row-key="ID"
|
|
|
- @selection-change="fjSelectionChange">
|
|
|
- <el-table-column align="left" label="关联编号" prop="关联编号" width="115"/>
|
|
|
- <el-table-column align="left" label="备注" prop="附件备注" width="110"/>
|
|
|
- <el-table-column align="left" label="文件类型" prop="附件类型" width="100"/>
|
|
|
- <el-table-column align="left" label="建档时间" prop="sys_rq" width="160"/>
|
|
|
- <el-table-column align="left" label="建档用户" prop="sys_id" width="200"/>
|
|
|
- <el-table-column align="left" label="操作"width="100"fixed="right">
|
|
|
- <template #default="scope">
|
|
|
- <el-button type="success" size="small" :data="ddtableData" @click="showPdf(scope.row)" >PDF预览</el-button>
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
- </el-table>
|
|
|
- </el-tab-pane>
|
|
|
-
|
|
|
-
|
|
|
- <el-tab-pane label="技术附件" name="fourth">
|
|
|
- <el-table ref="multipleTable"
|
|
|
- :row-style="{ height: '30px' }"
|
|
|
- :cell-style="{ padding: '0px' }" :header-row-style="{ height: '30px' }"
|
|
|
- :header-cell-style="{ padding: '0px' }"
|
|
|
- :show-overflow-tooltip="true"
|
|
|
- :cell-class-name="planUsageCellClass"
|
|
|
- highlight-current-row="true"
|
|
|
- @row-dblclick="ExcelShow"
|
|
|
- style="width: 100%;height: 36vh" border tooltip-effect="dark" :data="jstableData" row-key="ID"
|
|
|
- @selection-change="fjSelectionChange">
|
|
|
- <el-table-column align="left" label="关联编号" prop="关联编号" width="115"/>
|
|
|
- <el-table-column align="left" label="备注" prop="附件备注" width="110"/>
|
|
|
- <el-table-column align="left" label="文件类型" prop="附件类型" width="100"/>
|
|
|
- <el-table-column align="left" label="建档时间" prop="sys_rq" width="160"/>
|
|
|
- <el-table-column align="left" label="建档用户" prop="sys_id" width="200"/>
|
|
|
- <el-table-column align="left" label="操作"width="100"fixed="right">
|
|
|
- <template #default="scope">
|
|
|
- <el-button type="success" size="small" :data="ddtableData" @click="showPdf(scope.row)" >PDF预览</el-button>
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
- </el-table>
|
|
|
- </el-tab-pane>
|
|
|
- </el-tabs>
|
|
|
-
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 是否订单尾包确认弹窗 -->
|
|
|
- <el-dialog v-model="DialogVisible" title="是否订单尾包" destroy-on-close width="30%" style="top: 20%;">
|
|
|
- <h3>请再次确认是否该订单产品已全部报工,该批为订单尾包?</h3>
|
|
|
- <div class="dialog-footer" style="text-align: right;">
|
|
|
- <el-button @click="confirmDialogVisible">取消</el-button>
|
|
|
- <el-button type="primary" @click="handleConfirm">确认</el-button>
|
|
|
- </div>
|
|
|
- </el-dialog>
|
|
|
-
|
|
|
- <!-- 工分报工对话框 -->
|
|
|
- <el-dialog
|
|
|
- v-model="workScoreDialogVisible"
|
|
|
- class="work-score-dialog"
|
|
|
- width="100vw"
|
|
|
- height="100vh"
|
|
|
- :show-close="false"
|
|
|
- :modal="false"
|
|
|
- :close-on-click-modal="false"
|
|
|
- style="padding: 0; margin: 0; overflow: hidden; background: white;"
|
|
|
- >
|
|
|
- <div class="work-score-dialog-inner">
|
|
|
- <!-- 订单信息 + 关闭 -->
|
|
|
- <div class="work-score-order-header">
|
|
|
- <div v-if="orderInfoList.length > 0" class="work-score-order-bar">
|
|
|
- <p><strong>组别:</strong> {{ add_formData['组别'] }}</p>
|
|
|
- <p><strong>订单编号:</strong> {{ orderInfoList[0]['订单编号'] }}</p>
|
|
|
- <p><strong>生产款号:</strong> {{ orderInfoList[0]['生产款号'] }}</p>
|
|
|
- <p><strong>款式:</strong> {{ orderInfoList[0]['款式'] }}</p>
|
|
|
- <p><strong>订单数量:</strong> {{ orderInfoList[0]['订单数量'] }}</p>
|
|
|
- </div>
|
|
|
- <el-button type="danger" class="work-score-close-btn" @click="workScoreDialogVisible = false">关闭</el-button>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 下方:左右分栏 -->
|
|
|
- <div class="work-score-main-body">
|
|
|
- <!-- 左侧:部件列表(所有工序统一) -->
|
|
|
- <div v-if="processParts.length > 0" class="work-score-sidebar">
|
|
|
- <div class="work-score-content-header">
|
|
|
- <h3 class="work-score-section-title">部件</h3>
|
|
|
- </div>
|
|
|
- <div class="part-list work-score-part-list">
|
|
|
- <div
|
|
|
- v-for="(part, index) in processParts"
|
|
|
- :key="part['部件编号']"
|
|
|
- class="part-item"
|
|
|
- :class="{ selected: selectedPartIndex === index }"
|
|
|
- @click="selectPart(index)"
|
|
|
- >
|
|
|
- <div class="part-info">
|
|
|
- <div class="part-name">{{ part['部件编号'] }}-{{ part['部件名称'] }}</div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 右侧:上报人员 + 工艺列表 -->
|
|
|
- <div class="work-score-right-panel">
|
|
|
- <!-- 上报人员选择 -->
|
|
|
- <div class="work-score-employee-section">
|
|
|
- <div class="work-score-content-header work-score-step-header">
|
|
|
- <p class="work-score-step-text">第一步:请先选择<strong>人员</strong></p>
|
|
|
- </div>
|
|
|
- <div class="employee-grid work-score-employee-grid">
|
|
|
- <div
|
|
|
- v-for="employee in employees"
|
|
|
- :key="employee['员工编号']"
|
|
|
- class="employee-card"
|
|
|
- :class="{ selected: selectedEmployee === employee['员工编号'] }"
|
|
|
- @click="selectEmployee(employee)"
|
|
|
- draggable="true"
|
|
|
- @dragstart="onDragStart($event, employee)"
|
|
|
- >
|
|
|
- <div class="employee-avatar" :style="{ backgroundColor: getAvatarColor(employee['员工编号']) }">
|
|
|
- {{ employee['员工姓名'].charAt(0) }}
|
|
|
- </div>
|
|
|
- <div class="employee-name">{{ employee['员工姓名'] }}</div>
|
|
|
- <div class="employee-id">{{ employee['员工编号'] }}</div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 工艺列表 -->
|
|
|
- <div class="work-score-process-area">
|
|
|
- <div v-if="selectedPartIndex !== -1 && partProcesses[selectedPartIndex] && partProcesses[selectedPartIndex].length > 0" class="work-score-process-block">
|
|
|
- <div class="work-score-process-toolbar work-score-process-toolbar--simple">
|
|
|
- <div class="work-score-toolbar-guide">
|
|
|
- <div class="work-score-quick-row work-score-step-row">
|
|
|
- <span class="work-score-step-text">第二步:找到工序名称,填<strong>完工数量</strong></span>
|
|
|
- <!-- <el-input
|
|
|
- v-model.number="batchQuantity"
|
|
|
- type="number"
|
|
|
- :placeholder="selectedEmployee ? '如 20' : '先选人'"
|
|
|
- class="work-score-batch-qty-input"
|
|
|
- :disabled="!selectedEmployee"
|
|
|
- /> -->
|
|
|
- <el-button type="primary" class="work-score-submit-btn" @click="submitWorkScore">提交报工</el-button>
|
|
|
- </div>
|
|
|
-
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div ref="processTableWrapRef" class="work-score-process-table-wrap">
|
|
|
- <el-table
|
|
|
- ref="processTableRef"
|
|
|
- :data="partProcesses[selectedPartIndex]"
|
|
|
- :height="processTableHeight"
|
|
|
- scrollbar-always-on
|
|
|
- highlight-current-row
|
|
|
- :row-class-name="processTableRowClassName"
|
|
|
- class="work-score-process-table"
|
|
|
- style="width: 100%;"
|
|
|
- @row-click="onProcessTableRowClick"
|
|
|
- >
|
|
|
- <el-table-column prop="工艺编号" label="工序号" width="72" align="center" />
|
|
|
- <el-table-column prop="工艺名称" label="工序名称" min-width="240" />
|
|
|
- <el-table-column prop="本组完成数" label="本组完成数" min-width="88" align="center" />
|
|
|
- <el-table-column prop="累计完成数" label="累计完成数" min-width="70" align="center" />
|
|
|
- <el-table-column prop="未完成数" label="未完成数" min-width="60" align="center" />
|
|
|
- <el-table-column label="完工人员" width="120">
|
|
|
- <template #default="scope">
|
|
|
- <div v-if="getReportingData(selectedPartIndex, scope.$index).staffList">
|
|
|
- <div v-for="(staff, staffIndex) in getReportingData(selectedPartIndex, scope.$index).staffList" :key="staffIndex" class="work-score-staff-row">
|
|
|
- <el-input
|
|
|
- v-model="staff.staff_name"
|
|
|
- class="work-score-staff-input"
|
|
|
- readonly
|
|
|
- :disabled="isReportingFillDisabled(selectedPartIndex, scope.$index, staffIndex)"
|
|
|
- @focus="highlightProcessRow(scope.row)"
|
|
|
- @click="fillSelectedEmployee(staff, selectedPartIndex, scope.$index, staffIndex); highlightProcessRow(scope.row)"
|
|
|
- @drop="onDrop($event, selectedPartIndex, scope.$index, staffIndex)"
|
|
|
- @dragover="onDragOver($event)"
|
|
|
- />
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <el-input
|
|
|
- v-else
|
|
|
- v-model="getReportingData(selectedPartIndex, scope.$index).staff_name"
|
|
|
- class="work-score-staff-input"
|
|
|
- readonly
|
|
|
- :disabled="isReportingFillDisabled(selectedPartIndex, scope.$index)"
|
|
|
- @focus="highlightProcessRow(scope.row)"
|
|
|
- @click="fillSelectedEmployee(getReportingData(selectedPartIndex, scope.$index), selectedPartIndex, scope.$index); highlightProcessRow(scope.row)"
|
|
|
- @drop="onDrop($event, selectedPartIndex, scope.$index)"
|
|
|
- @dragover="onDragOver($event)"
|
|
|
- />
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
- <el-table-column label="完工数量" width="110">
|
|
|
- <template #default="scope">
|
|
|
- <div v-if="getReportingData(selectedPartIndex, scope.$index).staffList">
|
|
|
- <div v-for="(staff, staffIndex) in getReportingData(selectedPartIndex, scope.$index).staffList" :key="staffIndex" class="work-score-staff-row">
|
|
|
- <el-input
|
|
|
- :model-value="staff.number"
|
|
|
- inputmode="numeric"
|
|
|
- class="work-score-qty-input"
|
|
|
- :class="{ 'work-score-qty-over': isQtyOverUnfinished(selectedPartIndex, scope.$index) }"
|
|
|
- :disabled="isReportingFillDisabled(selectedPartIndex, scope.$index, staffIndex)"
|
|
|
- @focus="highlightProcessRow(scope.row)"
|
|
|
- @click="highlightProcessRow(scope.row)"
|
|
|
- @update:model-value="(v) => onQtyInput(selectedPartIndex, scope.$index, staffIndex, v)"
|
|
|
- />
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <el-input
|
|
|
- v-else
|
|
|
- :model-value="getReportingData(selectedPartIndex, scope.$index).number"
|
|
|
- inputmode="numeric"
|
|
|
- class="work-score-qty-input"
|
|
|
- :class="{ 'work-score-qty-over': isQtyOverUnfinished(selectedPartIndex, scope.$index) }"
|
|
|
- :disabled="isReportingFillDisabled(selectedPartIndex, scope.$index)"
|
|
|
- @focus="highlightProcessRow(scope.row)"
|
|
|
- @click="highlightProcessRow(scope.row)"
|
|
|
- @update:model-value="(v) => onQtyInput(selectedPartIndex, scope.$index, null, v)"
|
|
|
- />
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
- <el-table-column label="操作" width="110" align="center">
|
|
|
- <template #default="scope">
|
|
|
- <div class="work-score-row-actions">
|
|
|
- <!-- <el-button
|
|
|
- type="primary"
|
|
|
- size="small"
|
|
|
- class="work-score-fill-row-btn"
|
|
|
- :disabled="!selectedEmployee || batchQuantity === '' || batchQuantity == null"
|
|
|
- @click="fillRowPerson(selectedPartIndex, scope.$index)"
|
|
|
- >填入</el-button> -->
|
|
|
- <el-button size="small" plain class="work-score-add-person-btn" @click="addPerson(selectedPartIndex, scope.$index)">加一人</el-button>
|
|
|
- </div>
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
- </el-table>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div v-else-if="loadingProcess" class="work-score-process-empty">
|
|
|
- <p style="margin-top: 10px;">加载中...</p>
|
|
|
- </div>
|
|
|
- <div v-else class="work-score-process-empty work-score-process-empty--muted">
|
|
|
- <p style="font-size: 24px;">暂无数据</p>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </el-dialog>
|
|
|
-
|
|
|
- <!-- 工分报工确认弹窗 -->
|
|
|
- <el-dialog
|
|
|
- v-model="workScoreConfirmVisible"
|
|
|
- title="确认报工"
|
|
|
- width="1040px"
|
|
|
- top="8vh"
|
|
|
- append-to-body
|
|
|
- destroy-on-close
|
|
|
- class="work-score-confirm-dialog"
|
|
|
- :close-on-click-modal="false"
|
|
|
- >
|
|
|
- <p class="work-score-confirm-tip">请核对以下报工数据,确认无误后再提交</p>
|
|
|
- <el-table
|
|
|
- :data="workScoreConfirmRows"
|
|
|
- border
|
|
|
- stripe
|
|
|
- height="512"
|
|
|
- :span-method="workScoreConfirmSpanMethod"
|
|
|
- :cell-class-name="workScoreConfirmCellClass"
|
|
|
- class="work-score-confirm-table"
|
|
|
- style="width: 100%"
|
|
|
- >
|
|
|
- <el-table-column label="部件" prop="部件" width="88" align="center" show-overflow-tooltip />
|
|
|
- <el-table-column label="工序号" prop="工序编号" width="68" align="center" />
|
|
|
- <el-table-column label="工序名称" prop="工序名称" min-width="150" align="left" show-overflow-tooltip />
|
|
|
- <el-table-column label="本组完成数" prop="本组完成数" width="96" align="center" />
|
|
|
- <el-table-column label="累计完成数" prop="累计完成数" width="96" align="center" />
|
|
|
- <el-table-column label="未完成数" prop="未完成数量" width="88" align="center" />
|
|
|
- <el-table-column label="完工人员" prop="员工姓名" width="88" align="center" />
|
|
|
- <el-table-column label="完工数量" prop="完工数量" width="88" align="center" />
|
|
|
- <el-table-column label="超出数量" prop="超出数量" width="88" align="center" />
|
|
|
- </el-table>
|
|
|
- <template #footer>
|
|
|
- <el-button @click="workScoreConfirmVisible = false">返回修改</el-button>
|
|
|
- <el-button type="primary" :loading="workScoreSubmitting" @click="confirmSubmitWorkScore">确认报工</el-button>
|
|
|
- </template>
|
|
|
- </el-dialog>
|
|
|
-
|
|
|
- <!-- 当天报工记录:修改数量 -->
|
|
|
- <el-dialog
|
|
|
- v-model="editReportingQtyVisible"
|
|
|
- title="修改数量"
|
|
|
- width="420px"
|
|
|
- top="32vh"
|
|
|
- append-to-body
|
|
|
- destroy-on-close
|
|
|
- :close-on-click-modal="false"
|
|
|
- class="edit-reporting-qty-dialog"
|
|
|
- @opened="focusEditReportingQtyInput"
|
|
|
- >
|
|
|
- <el-form label-width="88px">
|
|
|
- <el-form-item label="工序号">
|
|
|
- <el-input :model-value="editReportingQtyForm.process_code" disabled />
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="工序名称">
|
|
|
- <el-input :model-value="editReportingQtyForm.process_name" disabled />
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="未完成数">
|
|
|
- <el-input :model-value="editReportingQtyForm.unfinished" disabled />
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="数量" required>
|
|
|
- <el-input
|
|
|
- ref="editReportingQtyInputRef"
|
|
|
- :model-value="editReportingQtyForm.number"
|
|
|
- inputmode="numeric"
|
|
|
- maxlength="5"
|
|
|
- placeholder="请输入修正后的数量"
|
|
|
- :class="{ 'edit-reporting-qty-over': isEditReportingQtyOver }"
|
|
|
- @update:model-value="(v) => { editReportingQtyForm.number = filterQtyDigits(v) }"
|
|
|
- @keyup.enter="submitEditReportingQty"
|
|
|
- />
|
|
|
- </el-form-item>
|
|
|
- </el-form>
|
|
|
- <template #footer>
|
|
|
- <el-button @click="editReportingQtyVisible = false">取消</el-button>
|
|
|
- <el-button type="primary" :loading="editReportingQtyLoading" @click="submitEditReportingQty">确定</el-button>
|
|
|
- </template>
|
|
|
- </el-dialog>
|
|
|
- </layout-content>
|
|
|
- </layout>
|
|
|
- <SubOrderPage ref="SubOrderPageRef" />
|
|
|
- <!-- 子订单详情页 -->
|
|
|
- <luckyexcelPage ref="luckyexcelPageRef" />
|
|
|
- </div>
|
|
|
- </template>
|
|
|
-<script>
|
|
|
-export default {
|
|
|
- data() {
|
|
|
- return {
|
|
|
- currentTable: '', // 当前展示的表格
|
|
|
- activeName: 'first',
|
|
|
- dialogFormVisible: false,
|
|
|
- formDataTest: {
|
|
|
- imageUrl: '' // 添加一个字段来保存上传的图片路径
|
|
|
- },
|
|
|
- rule: {} // 初始化rule对象
|
|
|
- };
|
|
|
- },
|
|
|
- methods: {
|
|
|
- handleKeyDown(event, prevId, currentId, nextId) {
|
|
|
- const currentElement = document.getElementById(currentId);
|
|
|
- const isEmpty = currentElement.value === '';
|
|
|
- const atStart = currentElement.selectionStart === 0;
|
|
|
- const atEnd = currentElement.selectionStart === currentElement.value.length;
|
|
|
- switch (event.keyCode) {
|
|
|
- case 13: // Enter
|
|
|
- case 40: // 向下箭头
|
|
|
- if (nextId) {
|
|
|
- document.getElementById(nextId).focus();
|
|
|
- }
|
|
|
- break;
|
|
|
- case 38: // 向上箭头
|
|
|
- if (prevId) {
|
|
|
- document.getElementById(prevId).focus();
|
|
|
- }
|
|
|
- break;
|
|
|
- case 8: // 删除键
|
|
|
- if (prevId && (isEmpty || atStart)) {
|
|
|
- document.getElementById(prevId).focus();
|
|
|
- }
|
|
|
- break;
|
|
|
- case 37: // 向左箭头
|
|
|
- if (prevId && atStart) {
|
|
|
- document.getElementById(prevId).focus();
|
|
|
- }
|
|
|
- break;
|
|
|
- case 39: // 向右箭头
|
|
|
- if (nextId && atEnd) {
|
|
|
- document.getElementById(nextId).focus();
|
|
|
- }
|
|
|
- break;
|
|
|
- default:
|
|
|
- break;
|
|
|
- }
|
|
|
- },
|
|
|
- },
|
|
|
-};
|
|
|
-</script>
|
|
|
-<script setup>
|
|
|
-// 全量引入格式化工具 请按需保留
|
|
|
-import $script from 'scriptjs'
|
|
|
-import $ from 'jquery';
|
|
|
-import LuckyExcel from 'luckyexcel';
|
|
|
-import { Layout, LayoutSider, LayoutContent } from '@arco-design/web-vue';
|
|
|
-import {ref, reactive, computed, watch, nextTick, onUnmounted} from 'vue';
|
|
|
-import {getSpotList,getInfo,OrderAttachments,WorkOrderList,DeleteReportingWork,UpdateReportingWork} from '@/api/mes/job';
|
|
|
-import {getMac,getMajorprocessAndPerson,GetOrderProcess,GetCarProcess,ReportingWork,GetReportingWorkRecord} from '@/api/jixiaoguanli/baogong'
|
|
|
-import {getMachineMac} from '@/api/jixiaoguanli/jitairibaobiao'
|
|
|
-import {ElMessage,ElMessageBox} from "element-plus";
|
|
|
-import luckyexcelPage from '@/view/yunyin/shengchanguanli/components/luckyexcel.vue';
|
|
|
-import SubOrderPage from '@/view/yunyin/shengchanguanli/components/SubOrder.vue';
|
|
|
-import ProcessProduction from '@/view/SalaryManage/ProcessProduction.vue';
|
|
|
-import { useUserStore } from '@/pinia/modules/user';
|
|
|
-defineOptions({name: 'Company'})
|
|
|
-const path = `${import.meta.env.VITE_BASE_PATH}:${import.meta.env.VITE_UPLOADS_PORT}`
|
|
|
-console.log(path)
|
|
|
-//定义跳转页面
|
|
|
-const SubOrderPageRef = ref()//子订单详情页
|
|
|
-const printPageRef = ref()//打印预览
|
|
|
-const luckyexcelPageRef = ref()//pdf预览
|
|
|
-//获取登录用户信息
|
|
|
-const userStore = useUserStore()
|
|
|
-const _username = ref('')
|
|
|
-_username.value = userStore.userInfo.userName + '/' + userStore.userInfo.nickName
|
|
|
-console.log('获取用户名称',_username.value)
|
|
|
-//全局获取当前日期
|
|
|
-const today = new Date();
|
|
|
-const year = today.getFullYear();
|
|
|
-const month = String(today.getMonth() + 1).padStart(2, '0'); // 月份从 0 开始,需要补零
|
|
|
-const day = String(today.getDate()).padStart(2, '0');
|
|
|
-const hours = String(today.getHours()).padStart(2, '0');
|
|
|
-const minutes = String(today.getMinutes()).padStart(2, '0');
|
|
|
-const seconds = String(today.getSeconds()).padStart(2, '0');
|
|
|
-const currentDate = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
|
|
-const currentDates = `${year}-${month}-${day}`;
|
|
|
-const add_searchInfo = ref('')
|
|
|
-const gongfenHistoryData = ref([])
|
|
|
-const gongfenHistoryTableRef = ref()
|
|
|
-const staffNameFilter = ref([])
|
|
|
-const currentOrderNo = ref('')
|
|
|
-
|
|
|
-/** 当天报工记录:仅当前查询订单 */
|
|
|
-const orderScopedGongfenHistoryData = computed(() => {
|
|
|
- const list = gongfenHistoryData.value || []
|
|
|
- const orderNo = String(currentOrderNo.value || '').trim()
|
|
|
- if (!orderNo) return []
|
|
|
- return list.filter((row) => {
|
|
|
- const rowOrder = String(row.work_order ?? row['订单编号'] ?? '').trim()
|
|
|
- return rowOrder === orderNo
|
|
|
- })
|
|
|
-})
|
|
|
-
|
|
|
-const staffNameFilterOptions = computed(() => {
|
|
|
- const names = [...new Set(
|
|
|
- (orderScopedGongfenHistoryData.value || [])
|
|
|
- .map(item => String(item.staff_name || '').trim())
|
|
|
- .filter(Boolean)
|
|
|
- )]
|
|
|
- return names.map(name => ({ text: name, value: name }))
|
|
|
-})
|
|
|
-
|
|
|
-const isStaffNameFilterActive = computed(() => {
|
|
|
- const allValues = staffNameFilterOptions.value.map(item => item.value)
|
|
|
- const selected = staffNameFilter.value
|
|
|
- if (!allValues.length) return false
|
|
|
- return selected.length < allValues.length
|
|
|
-})
|
|
|
-
|
|
|
-const selectAllStaffNameFilter = () => {
|
|
|
- staffNameFilter.value = staffNameFilterOptions.value.map(item => item.value)
|
|
|
-}
|
|
|
-
|
|
|
-const clearStaffNameFilter = () => {
|
|
|
- staffNameFilter.value = []
|
|
|
-}
|
|
|
-
|
|
|
-const syncStaffNameFilterAfterDataChange = () => {
|
|
|
- const allValues = staffNameFilterOptions.value.map(item => item.value)
|
|
|
- const selected = staffNameFilter.value
|
|
|
- if (!selected.length) {
|
|
|
- staffNameFilter.value = [...allValues]
|
|
|
- return
|
|
|
- }
|
|
|
- const wasAllSelected = allValues.length > 0 && allValues.every(v => selected.includes(v))
|
|
|
- if (wasAllSelected) {
|
|
|
- staffNameFilter.value = [...allValues]
|
|
|
- return
|
|
|
- }
|
|
|
- staffNameFilter.value = selected.filter(v => allValues.includes(v))
|
|
|
-}
|
|
|
-
|
|
|
-const filteredGongfenHistoryData = computed(() => {
|
|
|
- const list = orderScopedGongfenHistoryData.value || []
|
|
|
- const options = staffNameFilterOptions.value
|
|
|
- const selected = staffNameFilter.value
|
|
|
- if (!selected.length) return []
|
|
|
- if (!options.length || selected.length >= options.length) return list
|
|
|
- const set = new Set(selected)
|
|
|
- return list.filter(row => set.has(String(row.staff_name || '').trim()))
|
|
|
-})
|
|
|
-
|
|
|
-watch(
|
|
|
- () => [gongfenHistoryData.value, currentOrderNo.value],
|
|
|
- () => {
|
|
|
- syncStaffNameFilterAfterDataChange()
|
|
|
- },
|
|
|
- { deep: true }
|
|
|
-)
|
|
|
-
|
|
|
-const relayoutGongfenHistoryTable = () => {
|
|
|
- nextTick(() => {
|
|
|
- gongfenHistoryTableRef.value?.doLayout?.()
|
|
|
- })
|
|
|
-}
|
|
|
-
|
|
|
-watch(filteredGongfenHistoryData, relayoutGongfenHistoryTable)
|
|
|
-watch(staffNameFilter, relayoutGongfenHistoryTable)
|
|
|
-
|
|
|
-const gongfenHistoryHeaderCellStyle = ({ column }) => ({
|
|
|
- padding: '6px 0',
|
|
|
- fontSize: '16px',
|
|
|
- textAlign: column?.property === 'process_name' ? 'left' : 'center',
|
|
|
-})
|
|
|
-
|
|
|
-const gongfenHistoryCellStyle = ({ column }) => ({
|
|
|
- padding: '6px 0',
|
|
|
- fontSize: '16px',
|
|
|
- textAlign: column.property === 'process_name' ? 'left' : 'center',
|
|
|
-})
|
|
|
-
|
|
|
-const gongfenHistoryFooterCellStyle = ({ column }) => ({
|
|
|
- padding: '6px 0',
|
|
|
- fontSize: '16px',
|
|
|
- fontWeight: '600',
|
|
|
- background: '#fafafa',
|
|
|
- textAlign: column?.property === 'process_name' ? 'left' : 'center',
|
|
|
-})
|
|
|
-
|
|
|
-const getGongfenHistorySummaries = ({ columns, data }) => {
|
|
|
- const sums = []
|
|
|
- columns.forEach((column, index) => {
|
|
|
- if (column.property === 'process_code') {
|
|
|
- sums[index] = '合计'
|
|
|
- return
|
|
|
- }
|
|
|
- if (column.property === 'number') {
|
|
|
- sums[index] = data.reduce((total, row) => {
|
|
|
- const val = Number(row.number)
|
|
|
- return total + (Number.isNaN(val) ? 0 : val)
|
|
|
- }, 0)
|
|
|
- return
|
|
|
- }
|
|
|
- sums[index] = ''
|
|
|
- })
|
|
|
- return sums
|
|
|
-}
|
|
|
-
|
|
|
-//全局获取code,接口接收code
|
|
|
-const _code = ref('裁剪')
|
|
|
-//全局接口接受的物理地址
|
|
|
-const Machine = ref('')
|
|
|
-/** 机台 MAC 映射是否就绪;失败时禁止报工,避免静默落入测试机台 */
|
|
|
-const machineReady = ref(false)
|
|
|
-//全局获取UniqId
|
|
|
-const UniqId = ref('')
|
|
|
-
|
|
|
-// 员工数据
|
|
|
-const employees = ref([])
|
|
|
-const selectedEmployee = ref('')
|
|
|
-
|
|
|
-//物理地址获取机台编号
|
|
|
-const getMachineMacdata = async () => {
|
|
|
- try {
|
|
|
- const data = await getMachineMac({ sys_sbID: Machine.value })
|
|
|
- if (data.data === null) {
|
|
|
- machineReady.value = false
|
|
|
- add_formData['机台号'] = ''
|
|
|
- add_formData['工序'] = ''
|
|
|
- add_formData['组别'] = ''
|
|
|
- add_formData['人员'] = ''
|
|
|
- employees.value = []
|
|
|
- return
|
|
|
- }
|
|
|
- add_formData['机台号'] = data.data['机台号']
|
|
|
- add_formData['工序'] = data.data['生产工序']
|
|
|
- add_formData['组别'] = data.data['组别']
|
|
|
- add_formData['人员'] = data.data['组长']
|
|
|
- _code.value = data.data['生产工序']
|
|
|
- machineReady.value = true
|
|
|
- getEmployeeData(data.data['机台号'])
|
|
|
- setTimeout(() => {
|
|
|
- const inputElement = document.getElementById('searchInput')
|
|
|
- if (inputElement) {
|
|
|
- inputElement.focus()
|
|
|
- }
|
|
|
- }, 100)
|
|
|
- } catch (error) {
|
|
|
- console.error(error)
|
|
|
- machineReady.value = false
|
|
|
- add_formData['机台号'] = ''
|
|
|
- add_formData['工序'] = ''
|
|
|
- add_formData['组别'] = ''
|
|
|
- add_formData['人员'] = ''
|
|
|
- employees.value = []
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// 获取员工数据
|
|
|
-const getEmployeeData = async (machineId) => {
|
|
|
- try {
|
|
|
- const data = await getMajorprocessAndPerson({ machine: machineId || 'CF01' })
|
|
|
- if (data.code === 0 && data.data) {
|
|
|
- employees.value = data.data.person || []
|
|
|
- // 不默认选中人员,工艺表「报工人员」列为空,由用户点击上方人员或拖入填写
|
|
|
- selectedEmployee.value = ''
|
|
|
- }
|
|
|
- } catch (error) {
|
|
|
- console.error('获取员工数据失败:', error)
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// 选择员工
|
|
|
-const selectEmployee = (employee) => {
|
|
|
- selectedEmployee.value = employee.员工编号
|
|
|
- add_formData['人员'] = employee.员工姓名
|
|
|
-}
|
|
|
-
|
|
|
-const createEmptyReportingItem = () => ({
|
|
|
- staff_name: '',
|
|
|
- staff_no: '',
|
|
|
- number: '',
|
|
|
-})
|
|
|
-
|
|
|
-const extractListFromResponse = (data) => {
|
|
|
- if (!data) return []
|
|
|
- if (Array.isArray(data)) return data
|
|
|
- if (typeof data === 'object') {
|
|
|
- for (const key of ['list', 'process_list', 'processes', 'rows', 'data']) {
|
|
|
- if (Array.isArray(data[key])) return data[key]
|
|
|
- }
|
|
|
- }
|
|
|
- return []
|
|
|
-}
|
|
|
-
|
|
|
-const isPartRow = (row) => {
|
|
|
- if (!row || typeof row !== 'object') return false
|
|
|
- const hasPart = !!(row['部件编号'] || row.part_code || row['部件名称'] || row.part_name)
|
|
|
- const hasProcess = !!(row['工艺编号'] || row['工序编号'] || row.process_code || row.gy_code || row['工艺名称'] || row['工序名称'] || row.process_name || row.gy_name)
|
|
|
- return hasPart && !hasProcess
|
|
|
-}
|
|
|
-
|
|
|
-const getRowMajorProcess = (row) => String(
|
|
|
- row?.['大工序'] ?? row?.['生产工序'] ?? row?.big_process ?? row?.['大工艺'] ?? ''
|
|
|
-).trim()
|
|
|
-
|
|
|
-const normalizeWorkScoreProcessRow = (row) => {
|
|
|
- if (!row || typeof row !== 'object') return null
|
|
|
- if (isPartRow(row)) return null
|
|
|
-
|
|
|
- const 工艺编号 = row['工艺编号'] ?? row['工序编号'] ?? row.process_code ?? row.gy_code ?? row.gy_sort ?? ''
|
|
|
- const 工艺名称 = row['工艺名称'] ?? row['工序名称'] ?? row.process_name ?? row.gy_name ?? ''
|
|
|
- if (!String(工艺编号).trim() && !String(工艺名称).trim()) return null
|
|
|
-
|
|
|
- return {
|
|
|
- ...row,
|
|
|
- 工艺编号,
|
|
|
- 工艺名称,
|
|
|
- 本组完成数: row['本组完成数'] ?? row.group_complete ?? row['本组完成'] ?? '',
|
|
|
- 累计完成数: row['累计完成数'] ?? row.total_complete ?? '',
|
|
|
- 未完成数: row['未完成数'] ?? row.unfinished ?? '',
|
|
|
- 标准分钟: row['标准分钟'] ?? row.standard_minutes ?? row['标准工时'] ?? row.standard_hour ?? '',
|
|
|
- 标准工时: row['标准工时'] ?? row.standard_hour ?? row['标准分钟'] ?? row.standard_minutes ?? '',
|
|
|
- 标准工分: row['标准工分'] ?? row.standard_score ?? row['标准公分'] ?? '',
|
|
|
- 金额: row['金额'] ?? row.money ?? '',
|
|
|
- 系数: row['系数'] ?? row.coefficient ?? row.difficulty_coef ?? row['难度系数'] ?? '',
|
|
|
- 大工序: getRowMajorProcess(row),
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-const normalizeWorkScoreProcessList = (list) => {
|
|
|
- return extractListFromResponse(list)
|
|
|
- .map(normalizeWorkScoreProcessRow)
|
|
|
- .filter(Boolean)
|
|
|
-}
|
|
|
-
|
|
|
-const resolvePartCode = (part) => String(part?.['部件编号'] ?? part?.part_code ?? '').trim()
|
|
|
-
|
|
|
-const setPartProcessData = (index, processList) => {
|
|
|
- const nextPartProcesses = partProcesses.value.slice()
|
|
|
- nextPartProcesses[index] = processList
|
|
|
- partProcesses.value = nextPartProcesses
|
|
|
-
|
|
|
- const nextReportingData = reportingData.value.slice()
|
|
|
- nextReportingData[index] = processList.map(() => createEmptyReportingItem())
|
|
|
- reportingData.value = nextReportingData
|
|
|
-}
|
|
|
-
|
|
|
-const refreshProcessTableLayout = () => {
|
|
|
- nextTick(() => {
|
|
|
- updateProcessTableHeight()
|
|
|
- attachProcessTableResizeObserver()
|
|
|
- })
|
|
|
-}
|
|
|
-
|
|
|
-//工分报工对话框
|
|
|
-const workScoreDialogVisible = ref(false);
|
|
|
-const workScoreConfirmVisible = ref(false);
|
|
|
-const workScoreConfirmRows = ref([]);
|
|
|
-const pendingReportData = ref([]);
|
|
|
-const workScoreSubmitting = ref(false);
|
|
|
-const processTableWrapRef = ref(null);
|
|
|
-const processTableRef = ref(null);
|
|
|
-const processTableHeight = ref(320);
|
|
|
-/** 当前点选的工艺行(用于整行粉色 + 输入框同色) */
|
|
|
-const activeProcessRow = ref(null);
|
|
|
-const batchQuantity = ref('');
|
|
|
-let processTableResizeObserver = null;
|
|
|
-
|
|
|
-const updateProcessTableHeight = () => {
|
|
|
- nextTick(() => {
|
|
|
- requestAnimationFrame(() => {
|
|
|
- const height = processTableWrapRef.value?.clientHeight || 0
|
|
|
- if (height > 120) {
|
|
|
- const nextHeight = Math.floor(height) - 14
|
|
|
- if (Math.abs(nextHeight - processTableHeight.value) > 2) {
|
|
|
- processTableHeight.value = nextHeight
|
|
|
- }
|
|
|
- }
|
|
|
- })
|
|
|
- })
|
|
|
-}
|
|
|
-
|
|
|
-const attachProcessTableResizeObserver = () => {
|
|
|
- processTableResizeObserver?.disconnect()
|
|
|
- const el = processTableWrapRef.value
|
|
|
- if (!el || typeof ResizeObserver === 'undefined') return
|
|
|
- processTableResizeObserver = new ResizeObserver(() => {
|
|
|
- updateProcessTableHeight()
|
|
|
- })
|
|
|
- processTableResizeObserver.observe(el)
|
|
|
-}
|
|
|
-
|
|
|
-watch(workScoreDialogVisible, (visible) => {
|
|
|
- if (visible) {
|
|
|
- nextTick(() => {
|
|
|
- updateProcessTableHeight()
|
|
|
- attachProcessTableResizeObserver()
|
|
|
- })
|
|
|
- window.addEventListener('resize', updateProcessTableHeight)
|
|
|
- } else {
|
|
|
- window.removeEventListener('resize', updateProcessTableHeight)
|
|
|
- processTableResizeObserver?.disconnect()
|
|
|
- processTableResizeObserver = null
|
|
|
- resetWorkScoreDialogState()
|
|
|
- }
|
|
|
-})
|
|
|
-
|
|
|
-onUnmounted(() => {
|
|
|
- window.removeEventListener('resize', updateProcessTableHeight)
|
|
|
- processTableResizeObserver?.disconnect()
|
|
|
-})
|
|
|
-
|
|
|
-const selectedEmployeeName = computed(() => {
|
|
|
- const emp = employees.value.find(item => item['员工编号'] === selectedEmployee.value)
|
|
|
- return emp?.['员工姓名'] || ''
|
|
|
-})
|
|
|
-
|
|
|
-//工艺部件数据
|
|
|
-const processParts = ref([]);
|
|
|
-
|
|
|
-//工艺数据
|
|
|
-const partProcesses = ref([]);
|
|
|
-
|
|
|
-//部件数量
|
|
|
-const partQuantities = ref([]);
|
|
|
-
|
|
|
-//选中的部件索引
|
|
|
-const selectedPartIndex = ref(-1);
|
|
|
-
|
|
|
-//报工数据
|
|
|
-const reportingData = ref([]);
|
|
|
-
|
|
|
-//加载状态
|
|
|
-const loadingProcess = ref(false);
|
|
|
-
|
|
|
-const resetWorkScoreDialogState = () => {
|
|
|
- selectedEmployee.value = ''
|
|
|
- batchQuantity.value = ''
|
|
|
- selectedPartIndex.value = -1
|
|
|
- processParts.value = []
|
|
|
- partProcesses.value = []
|
|
|
- partQuantities.value = []
|
|
|
- reportingData.value = []
|
|
|
- loadingProcess.value = false
|
|
|
- workScoreConfirmVisible.value = false
|
|
|
- workScoreConfirmRows.value = []
|
|
|
- pendingReportData.value = []
|
|
|
- workScoreSubmitting.value = false
|
|
|
-}
|
|
|
-
|
|
|
-watch(selectedPartIndex, () => {
|
|
|
- if (workScoreDialogVisible.value) {
|
|
|
- updateProcessTableHeight()
|
|
|
- }
|
|
|
-})
|
|
|
-
|
|
|
-watch(loadingProcess, (loading) => {
|
|
|
- if (!loading && workScoreDialogVisible.value) {
|
|
|
- updateProcessTableHeight()
|
|
|
- }
|
|
|
-})
|
|
|
-
|
|
|
-const openWorkScoreDialog = async () => {
|
|
|
- if (!getActiveOrderNo() || orderInfoList.length === 0) {
|
|
|
- warningres('请先查询订单信息');
|
|
|
- return;
|
|
|
- }
|
|
|
- const machineNo = String(add_formData['机台号'] || '').trim()
|
|
|
- if (!machineReady.value || !machineNo) {
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- resetWorkScoreDialogState()
|
|
|
- const hasData = await loadProcessParts()
|
|
|
- if (!hasData) return
|
|
|
-
|
|
|
- workScoreDialogVisible.value = true
|
|
|
- refreshProcessTableLayout()
|
|
|
-};
|
|
|
-
|
|
|
-const loadOrderAttachments = async (orderNo) => {
|
|
|
- const seq = ++attachmentQuerySeq
|
|
|
- try {
|
|
|
- const jsOrderAttachments = await OrderAttachments({ order: orderNo, desc: '技术附件' })
|
|
|
- const ddOrderAttachments = await OrderAttachments({ order: orderNo, desc: '订单资料附件' })
|
|
|
- if (seq !== attachmentQuerySeq) return
|
|
|
- const jsList = jsOrderAttachments?.data?.list || []
|
|
|
- const ddList = ddOrderAttachments?.data?.list || []
|
|
|
- jstableData.splice(0, jstableData.length, ...jsList)
|
|
|
- ddtableData.splice(0, ddtableData.length, ...ddList)
|
|
|
- } catch (error) {
|
|
|
- if (seq !== attachmentQuerySeq) return
|
|
|
- console.error('获取附件失败:', error)
|
|
|
- jstableData.length = 0
|
|
|
- ddtableData.length = 0
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-//加载工艺部件数据;有数据返回 true,无数据或失败返回 false(仅提示,不弹窗)
|
|
|
-const loadProcessParts = async () => {
|
|
|
- loadingProcess.value = true;
|
|
|
- try {
|
|
|
- const response = await GetOrderProcess({
|
|
|
- workorder: getActiveOrderNo(),
|
|
|
- majorprocess: add_formData['工序']
|
|
|
- });
|
|
|
-
|
|
|
- if (response.code === 0) {
|
|
|
- const parts = extractListFromResponse(response.data)
|
|
|
- if (!parts.length) {
|
|
|
- warningres('技术部未上传工序明细资料数据')
|
|
|
- return false
|
|
|
- }
|
|
|
- processParts.value = parts
|
|
|
- partQuantities.value = new Array(parts.length).fill('')
|
|
|
- partProcesses.value = Array.from({ length: parts.length }, () => [])
|
|
|
- reportingData.value = Array.from({ length: parts.length }, () => [])
|
|
|
- await selectPart(0)
|
|
|
- return true
|
|
|
- }
|
|
|
- warningres('获取工艺部件失败')
|
|
|
- return false
|
|
|
- } catch (error) {
|
|
|
- console.error('获取工艺部件失败:', error);
|
|
|
- warningres('网络错误,请稍后重试');
|
|
|
- return false
|
|
|
- } finally {
|
|
|
- loadingProcess.value = false;
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-//加载部件工艺数据
|
|
|
-const loadPartProcesses = async (index, partCode) => {
|
|
|
- const code = String(partCode || '').trim()
|
|
|
- if (!code) {
|
|
|
- setPartProcessData(index, [])
|
|
|
- return
|
|
|
- }
|
|
|
- try {
|
|
|
- const carParams = {
|
|
|
- workorder: getActiveOrderNo(),
|
|
|
- part_code: code,
|
|
|
- majorprocess: add_formData['工序'],
|
|
|
- }
|
|
|
- // 本组完成数由后端在 GetCarProcess 中按组别返回
|
|
|
- const sysId = String(add_formData['组别'] || '').trim()
|
|
|
- if (sysId) carParams.sys_id = sysId
|
|
|
-
|
|
|
- const response = await GetCarProcess(carParams)
|
|
|
-
|
|
|
- if (response.code === 0 && response.data) {
|
|
|
- const processList = normalizeWorkScoreProcessList(response.data)
|
|
|
- setPartProcessData(index, processList)
|
|
|
- } else {
|
|
|
- setPartProcessData(index, [])
|
|
|
- }
|
|
|
- } catch (error) {
|
|
|
- console.error('获取部件工艺失败:', error);
|
|
|
- setPartProcessData(index, [])
|
|
|
- } finally {
|
|
|
- if (index === selectedPartIndex.value) {
|
|
|
- refreshProcessTableLayout()
|
|
|
- }
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-//获取报工数据
|
|
|
-const getReportingData = (partIndex, processIndex) => {
|
|
|
- if (!reportingData.value[partIndex]) {
|
|
|
- reportingData.value[partIndex] = [];
|
|
|
- }
|
|
|
- if (!reportingData.value[partIndex][processIndex]) {
|
|
|
- reportingData.value[partIndex][processIndex] = createEmptyReportingItem()
|
|
|
- }
|
|
|
- return reportingData.value[partIndex][processIndex];
|
|
|
-};
|
|
|
-
|
|
|
-/** 同一工序行内已选人员(排除当前正在编辑的格) */
|
|
|
-const isStaffDuplicateInProcessRow = (partIndex, processIndex, staffNo, staffName, excludeStaffIndex = null) => {
|
|
|
- const item = getReportingData(partIndex, processIndex)
|
|
|
- const n = String(staffNo || '').trim()
|
|
|
- const nm = String(staffName || '').trim()
|
|
|
- const checkOne = (no, name, idx) => {
|
|
|
- if (excludeStaffIndex !== null && idx === excludeStaffIndex) return false
|
|
|
- const o = String(no || '').trim()
|
|
|
- const on = String(name || '').trim()
|
|
|
- if (n && o && n === o) return true
|
|
|
- if (nm && on && nm === on) return true
|
|
|
- return false
|
|
|
- }
|
|
|
- if (item.staffList?.length) {
|
|
|
- return item.staffList.some((s, idx) => checkOne(s.staff_no, s.staff_name, idx))
|
|
|
- }
|
|
|
- return checkOne(item.staff_no, item.staff_name, null)
|
|
|
-}
|
|
|
-
|
|
|
-const assignStaffToReportingRow = (partIndex, processIndex, employee, staffIndex = null) => {
|
|
|
- if (!employee) return false
|
|
|
- const no = employee.员工编号
|
|
|
- const name = employee.员工姓名
|
|
|
- if (isStaffDuplicateInProcessRow(partIndex, processIndex, no, name, staffIndex)) {
|
|
|
- warningres([
|
|
|
- `「${name}」`,
|
|
|
- '已在该工序中选择',
|
|
|
- '请勿重复添加',
|
|
|
- ])
|
|
|
- return false
|
|
|
- }
|
|
|
- const reportingDataItem = getReportingData(partIndex, processIndex)
|
|
|
- if (staffIndex !== null && reportingDataItem.staffList) {
|
|
|
- reportingDataItem.staffList[staffIndex].staff_name = name
|
|
|
- reportingDataItem.staffList[staffIndex].staff_no = no
|
|
|
- } else if (reportingDataItem.staffList) {
|
|
|
- reportingDataItem.staffList.push({
|
|
|
- staff_name: name,
|
|
|
- staff_no: no,
|
|
|
- number: '',
|
|
|
- })
|
|
|
- } else {
|
|
|
- reportingDataItem.staff_name = name
|
|
|
- reportingDataItem.staff_no = no
|
|
|
- }
|
|
|
- return true
|
|
|
-}
|
|
|
-
|
|
|
-// 将上方选中的员工填入当前工序格(同一工序行内不可重复)
|
|
|
-const fillSelectedEmployee = (row, partIndex, processIndex, staffIndex = null) => {
|
|
|
- if (isReportingFillDisabled(partIndex, processIndex, staffIndex)) {
|
|
|
- warningres('请先在上方选择人员')
|
|
|
- return
|
|
|
- }
|
|
|
- const emp = employees.value.find(emp => emp['员工编号'] === selectedEmployee.value)
|
|
|
- if (!emp) return
|
|
|
- assignStaffToReportingRow(partIndex, processIndex, emp, staffIndex)
|
|
|
-}
|
|
|
-
|
|
|
-// 表格内输入完工数量时,若上方已选人员且本格人员为空,则自动填入
|
|
|
-const filterQtyDigits = (val) => String(val ?? '').replace(/[^\d]/g, '').slice(0, 5)
|
|
|
-
|
|
|
-const highlightProcessRow = (row) => {
|
|
|
- activeProcessRow.value = row
|
|
|
- processTableRef.value?.setCurrentRow?.(row)
|
|
|
-}
|
|
|
-
|
|
|
-const onProcessTableRowClick = (row) => {
|
|
|
- highlightProcessRow(row)
|
|
|
-}
|
|
|
-
|
|
|
-const processTableRowClassName = ({ row }) =>
|
|
|
- row === activeProcessRow.value ? 'work-score-process-row-active' : ''
|
|
|
-
|
|
|
-const onQtyInput = (partIndex, processIndex, staffIndex, val) => {
|
|
|
- const digits = filterQtyDigits(val)
|
|
|
- const item = getReportingData(partIndex, processIndex)
|
|
|
- if (item.staffList?.length) {
|
|
|
- const idx = staffIndex !== null && staffIndex !== undefined ? staffIndex : 0
|
|
|
- if (item.staffList[idx]) item.staffList[idx].number = digits
|
|
|
- } else {
|
|
|
- item.number = digits
|
|
|
- }
|
|
|
- autoFillStaffOnQuantityInput(partIndex, processIndex, staffIndex)
|
|
|
-}
|
|
|
-
|
|
|
-/** 本工序已填完工合计是否超出未完成数 */
|
|
|
-const isQtyOverUnfinished = (partIndex, processIndex) => {
|
|
|
- const process = partProcesses.value?.[partIndex]?.[processIndex]
|
|
|
- const unfinished = Number(process?.未完成数)
|
|
|
- if (!Number.isFinite(unfinished)) return false
|
|
|
- const item = getReportingData(partIndex, processIndex)
|
|
|
- let sum = 0
|
|
|
- if (item.staffList?.length) {
|
|
|
- sum = item.staffList.reduce((s, st) => s + (Number(st.number) || 0), 0)
|
|
|
- } else {
|
|
|
- sum = Number(item.number) || 0
|
|
|
- }
|
|
|
- return sum > unfinished
|
|
|
-}
|
|
|
-
|
|
|
-const isReportingStaffEmpty = (partIndex, processIndex, staffIndex = null) => {
|
|
|
- const item = getReportingData(partIndex, processIndex)
|
|
|
- if (item.staffList?.length) {
|
|
|
- const idx = staffIndex !== null ? staffIndex : 0
|
|
|
- const staff = item.staffList[idx]
|
|
|
- return !String(staff?.staff_name || '').trim()
|
|
|
- }
|
|
|
- return !String(item.staff_name || '').trim()
|
|
|
-}
|
|
|
-
|
|
|
-const isReportingFillDisabled = (partIndex, processIndex, staffIndex = null) => {
|
|
|
- return isReportingStaffEmpty(partIndex, processIndex, staffIndex) && !selectedEmployee.value
|
|
|
-}
|
|
|
-
|
|
|
-const clearReportingQuantity = (partIndex, processIndex, staffIndex = null) => {
|
|
|
- const item = getReportingData(partIndex, processIndex)
|
|
|
- if (item.staffList?.length) {
|
|
|
- const idx = staffIndex !== null ? staffIndex : 0
|
|
|
- if (item.staffList[idx]) {
|
|
|
- item.staffList[idx].number = ''
|
|
|
- }
|
|
|
- } else {
|
|
|
- item.number = ''
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-const autoFillStaffOnQuantityInput = (partIndex, processIndex, staffIndex = null) => {
|
|
|
- const item = getReportingData(partIndex, processIndex)
|
|
|
- let hasQty = false
|
|
|
- let staffEmpty = false
|
|
|
- let targetStaffIndex = staffIndex
|
|
|
-
|
|
|
- if (item.staffList?.length) {
|
|
|
- const idx = staffIndex !== null ? staffIndex : 0
|
|
|
- const staff = item.staffList[idx]
|
|
|
- if (!staff) return
|
|
|
- hasQty = staff.number !== '' && staff.number != null
|
|
|
- staffEmpty = !String(staff.staff_name || '').trim()
|
|
|
- targetStaffIndex = idx
|
|
|
- } else {
|
|
|
- hasQty = item.number !== '' && item.number != null
|
|
|
- staffEmpty = !String(item.staff_name || '').trim()
|
|
|
- targetStaffIndex = null
|
|
|
- }
|
|
|
-
|
|
|
- if (!hasQty) return
|
|
|
-
|
|
|
- if (staffEmpty) {
|
|
|
- if (!selectedEmployee.value) {
|
|
|
- warningres('请先在上方选择人员')
|
|
|
- clearReportingQuantity(partIndex, processIndex, staffIndex)
|
|
|
- return
|
|
|
- }
|
|
|
- const emp = employees.value.find(item => item['员工编号'] === selectedEmployee.value)
|
|
|
- if (!emp) {
|
|
|
- clearReportingQuantity(partIndex, processIndex, staffIndex)
|
|
|
- return
|
|
|
- }
|
|
|
- assignStaffToReportingRow(partIndex, processIndex, emp, targetStaffIndex)
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-//选择部件
|
|
|
-const selectPart = async (index) => {
|
|
|
- if (index < 0 || index >= processParts.value.length) return
|
|
|
- selectedPartIndex.value = index
|
|
|
- activeProcessRow.value = null
|
|
|
- if (partProcesses.value[index]?.length > 0) {
|
|
|
- refreshProcessTableLayout()
|
|
|
- return
|
|
|
- }
|
|
|
- const partCode = resolvePartCode(processParts.value[index])
|
|
|
- await loadPartProcesses(index, partCode)
|
|
|
-};
|
|
|
-
|
|
|
-// 拖拽相关函数
|
|
|
-let draggedEmployee = null;
|
|
|
-
|
|
|
-// 开始拖拽
|
|
|
-const onDragStart = (event, employee) => {
|
|
|
- draggedEmployee = employee;
|
|
|
- console.log('拖拽的员工:', employee);
|
|
|
- event.dataTransfer.effectAllowed = 'copy';
|
|
|
-};
|
|
|
-
|
|
|
-// 拖拽经过
|
|
|
-const onDragOver = (event) => {
|
|
|
- event.preventDefault();
|
|
|
- event.dataTransfer.dropEffect = 'copy';
|
|
|
-};
|
|
|
-
|
|
|
-// 放置
|
|
|
-const onDrop = (event, partIndex, processIndex, staffIndex = null) => {
|
|
|
- event.preventDefault();
|
|
|
- if (draggedEmployee) {
|
|
|
- assignStaffToReportingRow(partIndex, processIndex, draggedEmployee, staffIndex)
|
|
|
- draggedEmployee = null;
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-// 把上方选中的工人和完工数量填入本行
|
|
|
-const fillRowPerson = (partIndex, processIndex) => {
|
|
|
- if (!selectedEmployee.value) {
|
|
|
- warningres('请先点下面选一个工人')
|
|
|
- return
|
|
|
- }
|
|
|
- const emp = employees.value.find(item => item['员工编号'] === selectedEmployee.value)
|
|
|
- if (!emp) return
|
|
|
-
|
|
|
- const qty = resolveBatchQuantity()
|
|
|
- if (qty === null) {
|
|
|
- warningres('请先输入完工数量')
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- const item = getReportingData(partIndex, processIndex)
|
|
|
- let staffIndex = null
|
|
|
- if (item.staffList?.length) {
|
|
|
- const emptyIndex = item.staffList.findIndex(staff => !String(staff.staff_name || '').trim())
|
|
|
- if (emptyIndex >= 0) {
|
|
|
- staffIndex = emptyIndex
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (!assignStaffToReportingRow(partIndex, processIndex, emp, staffIndex)) {
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- const updated = getReportingData(partIndex, processIndex)
|
|
|
- if (updated.staffList?.length) {
|
|
|
- if (staffIndex !== null) {
|
|
|
- updated.staffList[staffIndex].number = qty
|
|
|
- } else {
|
|
|
- const idx = updated.staffList.findIndex(staff => staff.staff_no === emp['员工编号'])
|
|
|
- if (idx >= 0) {
|
|
|
- updated.staffList[idx].number = qty
|
|
|
- }
|
|
|
- }
|
|
|
- } else {
|
|
|
- updated.number = qty
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// 添加人员
|
|
|
-const addPerson = (partIndex, processIndex) => {
|
|
|
- const reportingDataItem = getReportingData(partIndex, processIndex);
|
|
|
- if (!reportingDataItem.staffList) {
|
|
|
- // 首次添加:先把当前单行数据迁入列表,再追加新行
|
|
|
- reportingDataItem.staffList = [{
|
|
|
- staff_name: reportingDataItem.staff_name || '',
|
|
|
- staff_no: reportingDataItem.staff_no || '',
|
|
|
- number: reportingDataItem.number ?? '',
|
|
|
- }];
|
|
|
- }
|
|
|
- reportingDataItem.staffList.push({
|
|
|
- staff_name: '',
|
|
|
- staff_no: '',
|
|
|
- number: '',
|
|
|
- });
|
|
|
-};
|
|
|
-
|
|
|
-const resolveBatchQuantity = () => {
|
|
|
- if (batchQuantity.value !== '' && batchQuantity.value != null) {
|
|
|
- return batchQuantity.value
|
|
|
- }
|
|
|
- return null
|
|
|
-}
|
|
|
-
|
|
|
-const resolveStaffNoByName = (staffName) => {
|
|
|
- const name = String(staffName || '').trim()
|
|
|
- if (!name) return ''
|
|
|
- return employees.value.find(emp => emp['员工姓名'] === name)?.['员工编号'] || ''
|
|
|
-}
|
|
|
-
|
|
|
-//提交工分报工
|
|
|
-const buildProcessReportFields = (process) => ({
|
|
|
- process_code: process['工艺编号'],
|
|
|
- process_name: process['工艺名称'],
|
|
|
- standard_hour: process['标准工时'],
|
|
|
- standard_score: process['标准工分'],
|
|
|
- standard_minutes: process['标准分钟'],
|
|
|
- money: process['金额'],
|
|
|
- coefficient: process['系数'],
|
|
|
-})
|
|
|
-
|
|
|
-const buildWorkScoreReportData = () => {
|
|
|
- const reportData = []
|
|
|
-
|
|
|
- for (let i = 0; i < processParts.value.length; i++) {
|
|
|
- if (reportingData.value[i] && reportingData.value[i].length > 0) {
|
|
|
- const part = processParts.value[i]
|
|
|
- for (let j = 0; j < reportingData.value[i].length; j++) {
|
|
|
- const reportItem = reportingData.value[i][j]
|
|
|
- const process = partProcesses.value[i][j]
|
|
|
- if (!process) continue
|
|
|
-
|
|
|
- if (reportItem.staffList) {
|
|
|
- for (const staff of reportItem.staffList) {
|
|
|
- if (staff.number) {
|
|
|
- if (!String(staff.staff_name || '').trim()) {
|
|
|
- warningres('请填写报工人员')
|
|
|
- return null
|
|
|
- }
|
|
|
- const staffNo = staff.staff_no || resolveStaffNoByName(staff.staff_name)
|
|
|
- if (!staffNo) {
|
|
|
- warningres(`未找到报工人员「${staff.staff_name}」对应的员工编号`)
|
|
|
- return null
|
|
|
- }
|
|
|
- reportData.push({
|
|
|
- staff_no: staffNo,
|
|
|
- staff_name: staff.staff_name,
|
|
|
- work_order: getActiveOrderNo(),
|
|
|
- majorprocess: add_formData['工序'],
|
|
|
- part_code: part['部件编号'],
|
|
|
- ...buildProcessReportFields(process),
|
|
|
- number: staff.number,
|
|
|
- machine: add_formData['机台号'],
|
|
|
- sys_id: add_formData['组别'],
|
|
|
- date: currentDates
|
|
|
- })
|
|
|
- }
|
|
|
- }
|
|
|
- } else if (reportItem.number) {
|
|
|
- if (!String(reportItem.staff_name || '').trim()) {
|
|
|
- warningres('请填写报工人员')
|
|
|
- return null
|
|
|
- }
|
|
|
- const staffNo = reportItem.staff_no || resolveStaffNoByName(reportItem.staff_name)
|
|
|
- if (!staffNo) {
|
|
|
- warningres(`未找到报工人员「${reportItem.staff_name}」对应的员工编号`)
|
|
|
- return null
|
|
|
- }
|
|
|
- reportData.push({
|
|
|
- staff_no: staffNo,
|
|
|
- staff_name: reportItem.staff_name,
|
|
|
- work_order: getActiveOrderNo(),
|
|
|
- majorprocess: add_formData['工序'],
|
|
|
- part_code: part['部件编号'],
|
|
|
- ...buildProcessReportFields(process),
|
|
|
- number: reportItem.number,
|
|
|
- machine: add_formData['机台号'],
|
|
|
- sys_id: add_formData['组别'],
|
|
|
- date: currentDates
|
|
|
- })
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (reportData.length === 0) {
|
|
|
- warningres('请选择人员后,再填写完工数量')
|
|
|
- return null
|
|
|
- }
|
|
|
-
|
|
|
- return reportData
|
|
|
-}
|
|
|
-
|
|
|
-const recomputeWorkScoreConfirmRowSpan = (rows) => {
|
|
|
- const result = []
|
|
|
- let i = 0
|
|
|
- while (i < rows.length) {
|
|
|
- const partLabel = rows[i].部件
|
|
|
- const processCode = rows[i].工序编号
|
|
|
- const processName = rows[i].工序名称
|
|
|
- let j = i
|
|
|
- while (
|
|
|
- j < rows.length &&
|
|
|
- rows[j].部件 === partLabel &&
|
|
|
- rows[j].工序编号 === processCode &&
|
|
|
- rows[j].工序名称 === processName
|
|
|
- ) {
|
|
|
- j++
|
|
|
- }
|
|
|
- const group = rows.slice(i, j)
|
|
|
- group.forEach((row, idx) => {
|
|
|
- result.push({ ...row, _processRowSpan: idx === 0 ? group.length : 0 })
|
|
|
- })
|
|
|
- i = j
|
|
|
- }
|
|
|
- return result
|
|
|
-}
|
|
|
-
|
|
|
-/** 左侧部件展示文案:编号-名称 */
|
|
|
-const resolvePartLabel = (partCode) => {
|
|
|
- const code = String(partCode ?? '').trim()
|
|
|
- const part = (processParts.value || []).find((p) => String(p?.['部件编号'] ?? '').trim() === code)
|
|
|
- if (!part) return code
|
|
|
- const name = String(part['部件名称'] ?? '').trim()
|
|
|
- return name ? `${code}-${name}` : code
|
|
|
-}
|
|
|
-
|
|
|
-/** 从当前已加载工艺行取未完成数等 */
|
|
|
-const findProcessProgressByCode = (processCode, processName) => {
|
|
|
- const code = String(processCode ?? '').trim()
|
|
|
- const name = String(processName ?? '').trim()
|
|
|
- for (const list of partProcesses.value || []) {
|
|
|
- for (const p of list || []) {
|
|
|
- const pCode = String(p?.工艺编号 ?? '').trim()
|
|
|
- const pName = String(p?.工艺名称 ?? '').trim()
|
|
|
- if (code && pCode === code && (!name || pName === name)) {
|
|
|
- return {
|
|
|
- unfinished: Number(p?.未完成数),
|
|
|
- totalComplete: Number(p?.累计完成数),
|
|
|
- groupComplete: Number(p?.本组完成数),
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- return { unfinished: NaN, totalComplete: NaN, groupComplete: NaN }
|
|
|
-}
|
|
|
-
|
|
|
-const buildWorkScoreConfirmRows = (reportData) => {
|
|
|
- // 同一部件+工序多人报工时,按合计完工数再算超出
|
|
|
- const processQtySum = {}
|
|
|
- for (const item of reportData) {
|
|
|
- const key = `${item.part_code}||${item.process_code}||${item.process_name}`
|
|
|
- processQtySum[key] = (processQtySum[key] || 0) + (Number(item.number) || 0)
|
|
|
- }
|
|
|
-
|
|
|
- const rows = reportData.map((item) => {
|
|
|
- const key = `${item.part_code}||${item.process_code}||${item.process_name}`
|
|
|
- const progress = findProcessProgressByCode(item.process_code, item.process_name)
|
|
|
- const unfinished = progress.unfinished
|
|
|
- const groupComplete = progress.groupComplete
|
|
|
- const totalComplete = progress.totalComplete
|
|
|
- const hasUnfinished = Number.isFinite(unfinished)
|
|
|
- const hasGroupComplete = Number.isFinite(groupComplete)
|
|
|
- const hasTotalComplete = Number.isFinite(totalComplete)
|
|
|
- const sumQty = processQtySum[key] || 0
|
|
|
- const excess = hasUnfinished ? Math.max(0, sumQty - unfinished) : 0
|
|
|
- return {
|
|
|
- 部件: resolvePartLabel(item.part_code),
|
|
|
- 工序编号: item.process_code,
|
|
|
- 工序名称: item.process_name,
|
|
|
- 本组完成数: hasGroupComplete ? groupComplete : '',
|
|
|
- 累计完成数: hasTotalComplete ? totalComplete : '',
|
|
|
- 未完成数量: hasUnfinished ? unfinished : '',
|
|
|
- 员工姓名: item.staff_name,
|
|
|
- 完工数量: item.number,
|
|
|
- 超出数量: excess > 0 ? excess : '',
|
|
|
- _isOver: excess > 0,
|
|
|
- }
|
|
|
- })
|
|
|
- return recomputeWorkScoreConfirmRowSpan(rows)
|
|
|
-}
|
|
|
-
|
|
|
-const workScoreConfirmSpanMethod = ({ row, column }) => {
|
|
|
- const mergeProps = ['部件', '工序编号', '工序名称', '本组完成数', '累计完成数', '未完成数量', '超出数量']
|
|
|
- if (!mergeProps.includes(column.property)) {
|
|
|
- return { rowspan: 1, colspan: 1 }
|
|
|
- }
|
|
|
- const rowspan = row._processRowSpan || 0
|
|
|
- if (rowspan > 0) {
|
|
|
- return { rowspan, colspan: 1 }
|
|
|
- }
|
|
|
- return { rowspan: 0, colspan: 0 }
|
|
|
-}
|
|
|
-
|
|
|
-const workScoreConfirmCellClass = ({ row, column }) => {
|
|
|
- if (column.property === '超出数量' && row._isOver) return 'work-score-confirm-over-cell'
|
|
|
- if (column.property === '完工数量' && row._isOver) return 'work-score-confirm-over-cell'
|
|
|
- return ''
|
|
|
-}
|
|
|
-
|
|
|
-const submitWorkScore = () => {
|
|
|
- const reportData = buildWorkScoreReportData()
|
|
|
- if (!reportData) return
|
|
|
- pendingReportData.value = reportData
|
|
|
- workScoreConfirmRows.value = buildWorkScoreConfirmRows(reportData)
|
|
|
- workScoreConfirmVisible.value = true
|
|
|
-}
|
|
|
-
|
|
|
-const confirmSubmitWorkScore = async () => {
|
|
|
- if (!pendingReportData.value.length || workScoreSubmitting.value) return
|
|
|
- workScoreSubmitting.value = true
|
|
|
- try {
|
|
|
- const response = await ReportingWork(pendingReportData.value)
|
|
|
-
|
|
|
- if (response.code === 0) {
|
|
|
- yellowTopTip('提交成功')
|
|
|
- workScoreConfirmVisible.value = false
|
|
|
- workScoreDialogVisible.value = false
|
|
|
- await getGongfenHistory()
|
|
|
- await refreshProcessProduction()
|
|
|
- } else {
|
|
|
- warningres(response.msg || '提交失败')
|
|
|
- }
|
|
|
- } catch (error) {
|
|
|
- console.error('提交工分报工失败:', error)
|
|
|
- warningres('网络错误,请稍后重试')
|
|
|
- } finally {
|
|
|
- workScoreSubmitting.value = false
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// 生成头像颜色
|
|
|
-const getAvatarColor = (index) => {
|
|
|
- const colors = [
|
|
|
- '#667eea', '#764ba2', '#f093fb', '#f5576c',
|
|
|
- '#4facfe', '#00f2fe', '#43e97b', '#38f9d7',
|
|
|
- '#fa709a', '#ffa751', '#6a11cb', '#11998e',
|
|
|
- '#eb3349', '#56ab2f', '#614385',
|
|
|
- ]
|
|
|
- return colors[index % colors.length]
|
|
|
-}
|
|
|
-//自动获取物理地址
|
|
|
-const GetAddr = () => {
|
|
|
- var xmlhttp = null;
|
|
|
- var res;
|
|
|
- if (window.XMLHttpRequest) {
|
|
|
- xmlhttp = new XMLHttpRequest();
|
|
|
- } else if (window.ActiveXObject) {
|
|
|
- xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
|
|
|
- }
|
|
|
- // 2. 设置回调函数
|
|
|
- xmlhttp.onreadystatechange = function() {
|
|
|
- if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
|
|
|
- res = eval('('+xmlhttp.response+')');
|
|
|
- let result = ''
|
|
|
- for (let i = 0; i < res.macAddress.length; i++) {
|
|
|
- if (i % 2 === 0 && i !== 0) {
|
|
|
- result += '-' // 根据实际需求修改分隔符
|
|
|
- }
|
|
|
- result += res.macAddress[i]
|
|
|
- }
|
|
|
- Machine.value = result
|
|
|
- getMachineMacdata(Machine.value)
|
|
|
- } else if (xmlhttp.readyState == 4) {
|
|
|
- machineReady.value = false
|
|
|
- }
|
|
|
- }
|
|
|
- xmlhttp.onerror = function() {
|
|
|
- machineReady.value = false
|
|
|
- }
|
|
|
- // 3. 打开一个连接
|
|
|
- xmlhttp.open("get", "http://127.0.0.1:8090/init")
|
|
|
- // 5. 发送
|
|
|
- xmlhttp.send();
|
|
|
-}
|
|
|
-// getMachineMacdata();
|
|
|
-GetAddr()
|
|
|
-// PDF预览
|
|
|
-const showPdf = async (row) => {
|
|
|
- if (!luckyexcelPageRef.value?.open) {
|
|
|
- warningres('预览组件未加载,请刷新页面重试')
|
|
|
- return
|
|
|
- }
|
|
|
- luckyexcelPageRef.value.open(row)
|
|
|
-}
|
|
|
-
|
|
|
-const add_formData = reactive({
|
|
|
- 机台号: '',
|
|
|
- 工序: '',
|
|
|
- 组别: '',
|
|
|
- 人员: '',
|
|
|
- 尺码: '',
|
|
|
- 数量: '',
|
|
|
- 是否订单尾包: '',
|
|
|
-});
|
|
|
-//清空对象的属性值
|
|
|
-const gd_clearFormData = () => {
|
|
|
- Object.keys(add_formData).forEach(key => {
|
|
|
- add_formData[key] = '';
|
|
|
- });
|
|
|
-};
|
|
|
-
|
|
|
-//进度汇总表格数据
|
|
|
-const add_tableData = reactive([]);
|
|
|
-const jdhz_tableData = reactive([]);
|
|
|
-const bgjdhz_tableData = reactive([]);
|
|
|
-const _order = ref('');
|
|
|
-const _UniqId = ref('');
|
|
|
-//尺寸列表
|
|
|
-const sizeDatas = reactive([])
|
|
|
-//技术附件
|
|
|
-const jstableData = reactive([])
|
|
|
-const ddtableData = reactive([])
|
|
|
-const _list = ref('');
|
|
|
-
|
|
|
-//订单信息数据
|
|
|
-const orderInfoList = reactive([]);
|
|
|
-/** 当前已加载订单编号(红框订单信息区,与搜索 input 解耦) */
|
|
|
-const processProductionRef = ref(null)
|
|
|
-const processProductionRefreshKey = ref(0)
|
|
|
-
|
|
|
-const getActiveOrderNo = () => {
|
|
|
- const no = String(currentOrderNo.value || orderInfoList[0]?.['订单编号'] || '').trim()
|
|
|
- return no
|
|
|
-}
|
|
|
-
|
|
|
-const refreshProcessProduction = async () => {
|
|
|
- const orderNo = getActiveOrderNo()
|
|
|
- if (!orderNo) return
|
|
|
- await nextTick()
|
|
|
- if (processProductionRef.value?.loadByWorkorder) {
|
|
|
- await processProductionRef.value.loadByWorkorder(orderNo, add_formData['工序'])
|
|
|
- } else {
|
|
|
- processProductionRefreshKey.value += 1
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-/** 点击「当天报工记录 / 工序产量核查」时重新拉取最新数据(含再次点击当前 Tab) */
|
|
|
-const onGongfenTabClick = async (pane) => {
|
|
|
- const name = pane?.paneName ?? pane?.props?.name
|
|
|
- if (name === 'first') {
|
|
|
- await getGongfenHistory()
|
|
|
- return
|
|
|
- }
|
|
|
- if (name === 'processProduction') {
|
|
|
- await refreshProcessProduction()
|
|
|
- }
|
|
|
- relayoutGongfenHistoryTable()
|
|
|
-}
|
|
|
-
|
|
|
-// 查询请求序号:丢弃过期响应,避免连扫串单
|
|
|
-let orderQuerySeq = 0
|
|
|
-let historyQuerySeq = 0
|
|
|
-let attachmentQuerySeq = 0
|
|
|
-
|
|
|
-// 查询
|
|
|
-/** 子订单号如 DC2605017-0800 转为订单号 DC2605017 再查询 */
|
|
|
-const normalizeOrderSearchInput = (val) => {
|
|
|
- const s = String(val ?? '').trim()
|
|
|
- if (!s) return ''
|
|
|
- const idx = s.indexOf('-')
|
|
|
- return idx >= 0 ? s.slice(0, idx).trim() : s
|
|
|
-}
|
|
|
-
|
|
|
-const add_onSubmit = async ()=>{
|
|
|
- if (workScoreDialogVisible.value) {
|
|
|
- warningres('请先关闭工分报工窗口后再查询其他订单,避免报错单')
|
|
|
- return
|
|
|
- }
|
|
|
- const machineNo = String(add_formData['机台号'] || '').trim()
|
|
|
- if (!machineReady.value || !machineNo || machineNo === '测试机台') {
|
|
|
- machineTip()
|
|
|
- return
|
|
|
- }
|
|
|
- const searchKey = normalizeOrderSearchInput(add_searchInfo.value)
|
|
|
- if (!searchKey) {
|
|
|
- warningres('请扫描订单二维码')
|
|
|
- return;
|
|
|
- }
|
|
|
- add_searchInfo.value = searchKey
|
|
|
- const seq = ++orderQuerySeq
|
|
|
-
|
|
|
- try {
|
|
|
- const response = await WorkOrderList({
|
|
|
- search: searchKey,
|
|
|
- page: 1,
|
|
|
- limit: 10,
|
|
|
- });
|
|
|
- if (seq !== orderQuerySeq) return
|
|
|
- const list = response.data?.data || []
|
|
|
- const total = response.data?.total ?? list.length
|
|
|
- if (response.code === 0 && response.data) {
|
|
|
- if (total === 0 || !list.length) {
|
|
|
- warningres('暂无该订单编号');
|
|
|
- orderInfoList.length = 0;
|
|
|
- currentOrderNo.value = '';
|
|
|
- } else {
|
|
|
- // 清空并更新订单信息列表
|
|
|
- orderInfoList.length = 0;
|
|
|
- orderInfoList.splice(0, list.length, ...list);
|
|
|
- // 锁定当前订单编号(红框区域),后续业务不再依赖搜索框
|
|
|
- currentOrderNo.value = String(orderInfoList[0]?.['订单编号'] || searchKey).trim();
|
|
|
-
|
|
|
- // 获取工分报工历史记录
|
|
|
- await getGongfenHistory();
|
|
|
- if (seq !== orderQuerySeq) return
|
|
|
-
|
|
|
- const searchValue = getActiveOrderNo();
|
|
|
-
|
|
|
- // 附件加载失败不影响查询结果
|
|
|
- await loadOrderAttachments(searchValue);
|
|
|
- if (seq !== orderQuerySeq) return
|
|
|
-
|
|
|
- // 查询成功后清空搜索框,便于继续扫描下一单
|
|
|
- add_searchInfo.value = '';
|
|
|
- _searchInput();
|
|
|
- }
|
|
|
- } else {
|
|
|
- warningres(response.msg || '查询失败');
|
|
|
- orderInfoList.length = 0;
|
|
|
- currentOrderNo.value = '';
|
|
|
- }
|
|
|
- } catch (error) {
|
|
|
- if (seq !== orderQuerySeq) return
|
|
|
- console.error('查询订单失败:', error);
|
|
|
- warningres('网络错误,请稍后重试');
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-// 获取工分报工历史记录
|
|
|
-const getGongfenHistory = async () => {
|
|
|
- const seq = ++historyQuerySeq
|
|
|
- try {
|
|
|
- const response = await GetReportingWorkRecord({
|
|
|
- date: currentDates,
|
|
|
- machine: add_formData['机台号']
|
|
|
- });
|
|
|
- if (seq !== historyQuerySeq) return
|
|
|
- if (response.code === 0 && response.data) {
|
|
|
- gongfenHistoryData.value = response.data || [];
|
|
|
- } else {
|
|
|
- gongfenHistoryData.value = [];
|
|
|
- }
|
|
|
- relayoutGongfenHistoryTable()
|
|
|
- } catch (error) {
|
|
|
- if (seq !== historyQuerySeq) return
|
|
|
- console.error('获取工分报工历史记录失败:', error);
|
|
|
- gongfenHistoryData.value = [];
|
|
|
- relayoutGongfenHistoryTable()
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-const deleteReportingWork = async (row) => {
|
|
|
- try {
|
|
|
- const escapeHtml = (val) => String(val ?? '')
|
|
|
- .replace(/&/g, '&')
|
|
|
- .replace(/</g, '<')
|
|
|
- .replace(/>/g, '>')
|
|
|
- .replace(/"/g, '"')
|
|
|
- const processCode = escapeHtml(row?.process_code) || '-'
|
|
|
- const processName = escapeHtml(row?.process_name) || '-'
|
|
|
- const staffName = escapeHtml(row?.staff_name) || '-'
|
|
|
- const number = escapeHtml(row?.number) || '-'
|
|
|
- await ElMessageBox.confirm(
|
|
|
- `<div class="gongfen-delete-msg">
|
|
|
- <div>确定要删除这条报工记录吗?</div>
|
|
|
- <div class="gongfen-delete-msg__row">工序号:<strong>${processCode}</strong></div>
|
|
|
- <div class="gongfen-delete-msg__row">工序名称:<strong>${processName}</strong></div>
|
|
|
- <div class="gongfen-delete-msg__row">员工姓名:<strong>${staffName}</strong></div>
|
|
|
- <div class="gongfen-delete-msg__row">数量:<strong>${number}</strong></div>
|
|
|
- </div>`,
|
|
|
- '提示',
|
|
|
- {
|
|
|
- confirmButtonText: '确定',
|
|
|
- cancelButtonText: '取消',
|
|
|
- type: 'warning',
|
|
|
- dangerouslyUseHTMLString: true,
|
|
|
- customClass: 'gongfen-delete-confirm',
|
|
|
- }
|
|
|
- );
|
|
|
-
|
|
|
- const deleteId = row?.id ?? row?.ID
|
|
|
- if (deleteId === undefined || deleteId === null || deleteId === '') {
|
|
|
- warningres('缺少报工记录ID,无法删除')
|
|
|
- return
|
|
|
- }
|
|
|
- const response = await DeleteReportingWork({
|
|
|
- id: deleteId
|
|
|
- });
|
|
|
-
|
|
|
- if (response.code === 0) {
|
|
|
- yellowTopTip('删除成功')
|
|
|
- await getGongfenHistory();
|
|
|
- await refreshProcessProduction();
|
|
|
- } else {
|
|
|
- errorres(response.msg || '删除失败');
|
|
|
- }
|
|
|
- } catch (error) {
|
|
|
- if (error !== 'cancel') {
|
|
|
- console.error('删除报工记录失败:', error);
|
|
|
- errorres('删除失败');
|
|
|
- }
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-const editReportingQtyVisible = ref(false)
|
|
|
-const editReportingQtyLoading = ref(false)
|
|
|
-const editReportingQtyInputRef = ref(null)
|
|
|
-const editReportingQtyForm = ref({
|
|
|
- id: '',
|
|
|
- number: '',
|
|
|
- original_number: '',
|
|
|
- process_code: '',
|
|
|
- process_name: '',
|
|
|
- part_code: '',
|
|
|
- unfinished: '',
|
|
|
- standard_hour: '',
|
|
|
- standard_score: '',
|
|
|
- production_hour: '',
|
|
|
- production_score: '',
|
|
|
-})
|
|
|
-
|
|
|
-const isEditReportingQtyOver = computed(() => {
|
|
|
- const unfinished = Number(editReportingQtyForm.value.unfinished)
|
|
|
- const original = Number(editReportingQtyForm.value.original_number) || 0
|
|
|
- const qty = Number(editReportingQtyForm.value.number)
|
|
|
- if (!Number.isFinite(unfinished) || !Number.isFinite(qty) || !qty) return false
|
|
|
- // 未完成数已扣除本条原数量,可改上限 = 未完成数 + 原数量
|
|
|
- return qty > unfinished + original
|
|
|
-})
|
|
|
-
|
|
|
-const focusEditReportingQtyInput = () => {
|
|
|
- nextTick(() => {
|
|
|
- const comp = editReportingQtyInputRef.value
|
|
|
- const el = comp?.input || comp?.textarea || comp?.$el?.querySelector?.('input')
|
|
|
- if (el && typeof el.focus === 'function') {
|
|
|
- el.focus()
|
|
|
- const len = String(el.value ?? '').length
|
|
|
- try {
|
|
|
- el.setSelectionRange(len, len)
|
|
|
- } catch (_) { /* ignore */ }
|
|
|
- return
|
|
|
- }
|
|
|
- comp?.focus?.()
|
|
|
- })
|
|
|
-}
|
|
|
-
|
|
|
-const resolveUnfinishedForEditRow = async (row) => {
|
|
|
- const processCode = String(row.process_code ?? row['工序编号'] ?? row['工序号'] ?? '').trim()
|
|
|
- const processName = String(row.process_name ?? row['工序名称'] ?? '').trim()
|
|
|
- const fromRow = Number(row.未完成数 ?? row.unfinished ?? row['未完成数量'])
|
|
|
- if (Number.isFinite(fromRow)) return fromRow
|
|
|
-
|
|
|
- const loaded = findProcessProgressByCode(processCode, processName)
|
|
|
- if (Number.isFinite(loaded.unfinished)) return loaded.unfinished
|
|
|
-
|
|
|
- const partCode = String(row.part_code ?? row['部件编号'] ?? '').trim()
|
|
|
- if (!partCode || !getActiveOrderNo()) return ''
|
|
|
-
|
|
|
- try {
|
|
|
- const carParams = {
|
|
|
- workorder: getActiveOrderNo(),
|
|
|
- part_code: partCode,
|
|
|
- majorprocess: add_formData['工序'],
|
|
|
- }
|
|
|
- const sysId = String(add_formData['组别'] || '').trim()
|
|
|
- if (sysId) carParams.sys_id = sysId
|
|
|
- const response = await GetCarProcess(carParams)
|
|
|
- if (response.code !== 0 || !response.data) return ''
|
|
|
- const processList = normalizeWorkScoreProcessList(response.data)
|
|
|
- const hit = (processList || []).find((p) => {
|
|
|
- const pCode = String(p?.['工艺编号'] ?? '').trim()
|
|
|
- const pName = String(p?.['工艺名称'] ?? '').trim()
|
|
|
- return processCode && pCode === processCode && (!processName || pName === processName)
|
|
|
- })
|
|
|
- const unfinished = Number(hit?.['未完成数'])
|
|
|
- return Number.isFinite(unfinished) ? unfinished : ''
|
|
|
- } catch (e) {
|
|
|
- console.error('获取未完成数失败:', e)
|
|
|
- return ''
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-const openEditReportingQty = async (row) => {
|
|
|
- const id = row?.id ?? row?.ID
|
|
|
- if (id === undefined || id === null || id === '') {
|
|
|
- warningres('缺少报工记录ID,无法修改')
|
|
|
- return
|
|
|
- }
|
|
|
- const number = filterQtyDigits(String(row.number ?? row['数量'] ?? ''))
|
|
|
- editReportingQtyForm.value = {
|
|
|
- id,
|
|
|
- number,
|
|
|
- original_number: number,
|
|
|
- process_code: String(row.process_code ?? row['工序编号'] ?? row['工序号'] ?? ''),
|
|
|
- process_name: String(row.process_name ?? row['工序名称'] ?? ''),
|
|
|
- part_code: String(row.part_code ?? row['部件编号'] ?? ''),
|
|
|
- unfinished: '',
|
|
|
- standard_hour: row.standard_hour ?? row['标准工时'] ?? '',
|
|
|
- standard_score: row.standard_score ?? row['标准工分'] ?? row['标准分数'] ?? '',
|
|
|
- production_hour: row.production_hour ?? row['生产工时'] ?? '',
|
|
|
- production_score: row.production_score ?? row['生产分数'] ?? row['生产工分'] ?? '',
|
|
|
- }
|
|
|
- editReportingQtyVisible.value = true
|
|
|
- const unfinished = await resolveUnfinishedForEditRow(row)
|
|
|
- if (editReportingQtyForm.value.id === id) {
|
|
|
- editReportingQtyForm.value.unfinished = unfinished === '' ? '' : String(unfinished)
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-const submitEditReportingQty = async () => {
|
|
|
- const numberStr = String(editReportingQtyForm.value.number ?? '').trim()
|
|
|
- const qty = Number(numberStr)
|
|
|
- if (!numberStr || Number.isNaN(qty) || qty <= 0) {
|
|
|
- warningres('请输入大于 0 的数量')
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- const stdHour = Number(editReportingQtyForm.value.standard_hour)
|
|
|
- const stdScore = Number(editReportingQtyForm.value.standard_score)
|
|
|
- let production_hour = String(editReportingQtyForm.value.production_hour ?? '')
|
|
|
- let production_score = String(editReportingQtyForm.value.production_score ?? '')
|
|
|
- if (Number.isFinite(stdHour) && stdHour > 0) {
|
|
|
- production_hour = (qty * stdHour).toFixed(2)
|
|
|
- }
|
|
|
- if (Number.isFinite(stdScore) && stdScore > 0) {
|
|
|
- production_score = (qty * stdScore).toFixed(2)
|
|
|
- }
|
|
|
-
|
|
|
- const mod_id = userStore.userInfo?.nickName || userStore.userInfo?.userName || ''
|
|
|
-
|
|
|
- editReportingQtyLoading.value = true
|
|
|
- try {
|
|
|
- const res = await UpdateReportingWork({
|
|
|
- id: editReportingQtyForm.value.id,
|
|
|
- number: String(qty),
|
|
|
- production_hour,
|
|
|
- production_score,
|
|
|
- mod_id,
|
|
|
- })
|
|
|
- if (res?.code === 0) {
|
|
|
- yellowTopTip(res.msg || '修改成功')
|
|
|
- editReportingQtyVisible.value = false
|
|
|
- await getGongfenHistory()
|
|
|
- await refreshProcessProduction()
|
|
|
- } else {
|
|
|
- errorres(res?.msg || '修改失败')
|
|
|
- }
|
|
|
- } catch (e) {
|
|
|
- console.error(e)
|
|
|
- errorres(e?.response?.data?.msg || e?.message || '修改失败')
|
|
|
- } finally {
|
|
|
- editReportingQtyLoading.value = false
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// 复选框选择
|
|
|
-const fjSelectionChange = (selection) => {
|
|
|
- console.log('选中的附件:', selection);
|
|
|
-};
|
|
|
-
|
|
|
- //总数量合计
|
|
|
- const getSummaries = (param) => {
|
|
|
- const { columns, data } = param;
|
|
|
- const sums = {};
|
|
|
- const summableLabels = [...sizeDatas, "实裁总数"];
|
|
|
- columns.forEach((column, index) => {
|
|
|
- if (index === 1) {
|
|
|
- sums[index] = '总数量合计';
|
|
|
- return;
|
|
|
- }
|
|
|
- if (summableLabels.includes(column.label)) {
|
|
|
- const values = data.map(item => Number(item[column.property]));
|
|
|
- // 检查数组中是否所有值都是 NaN
|
|
|
- if (!values.every(value => isNaN(value))) {
|
|
|
- sums[index] = values.reduce((prev, curr) => {
|
|
|
- const value = Number(curr);
|
|
|
- if (!isNaN(value)) {
|
|
|
- return prev + value;
|
|
|
- }
|
|
|
- return prev;
|
|
|
- }, 0);
|
|
|
- // 如果需要,可以在这里添加单位
|
|
|
- // sums[index] += ' 件';
|
|
|
- } else {
|
|
|
- sums[index] = '';
|
|
|
- }
|
|
|
- }
|
|
|
- });
|
|
|
- return sums;
|
|
|
-};
|
|
|
-
|
|
|
-
|
|
|
-//表格行点击(子订单编号单独保存,不写入搜索框)
|
|
|
-const tableRowClick = async (row)=>{
|
|
|
- _order.value = row.子订单编号 || ''
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-const _searchInput = async ()=>{
|
|
|
- setTimeout(() => {
|
|
|
- const inputElement = document.getElementById('searchInput');
|
|
|
- if (inputElement) {
|
|
|
- inputElement.focus();
|
|
|
- }
|
|
|
- }, 100);
|
|
|
-}
|
|
|
-
|
|
|
-//子订单详情页
|
|
|
-const cp_gdprintonClick = async () => {
|
|
|
- if(!_order.value){
|
|
|
- warningres('请先点击报工记录选择子订单后再查看')
|
|
|
- return false;
|
|
|
- }
|
|
|
- SubOrderPageRef.value.open(_order.value,add_formData['工序'])
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-const gd_yulan = () => {
|
|
|
- const order = getActiveOrderNo()
|
|
|
- if(!order){
|
|
|
- warningres('请先查询订单后再操作此功能')
|
|
|
- return false;
|
|
|
- }
|
|
|
- printPageRef.value.open(order)
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-const _orderid = ref('')//订单子编号
|
|
|
-const _kh = ref('')//生产款号
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-// =========== 分页 ===========
|
|
|
-// 分页相关的响应式变量
|
|
|
-const page = ref(1)
|
|
|
-const total = ref(0)
|
|
|
-const pageSize = ref(10)
|
|
|
-// 分页
|
|
|
-const handleCurrentChange = (val) => {
|
|
|
- page.value = val;
|
|
|
- _getStaffList();
|
|
|
-};
|
|
|
-
|
|
|
-// 修改页面容量 点击多少条/页
|
|
|
-const handleSizeChange = (val) => {
|
|
|
- page.value = 10;//默认显示
|
|
|
- pageSize.value = val;
|
|
|
- _getStaffList();
|
|
|
-};
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-// 统一提示:顶部居中、固定宽度(与扫描框一带)
|
|
|
-const TIP_OFFSET = 90
|
|
|
-const TIP_WIDTH = 520
|
|
|
-const TIP_CLASS = 'custom-warning-message gongfen-unified-tip'
|
|
|
-
|
|
|
-const buildTipHtml = (content, bgColor, textColor = '#000') => {
|
|
|
- const lines = Array.isArray(content) ? content : [String(content || '')]
|
|
|
- const linesHtml = lines.map((line) => (
|
|
|
- `<div style="font-size:32px;line-height:1.35;font-weight:700;color:${textColor};word-break:break-word;white-space:normal;">${line}</div>`
|
|
|
- )).join('')
|
|
|
- return `<div style="background-color:${bgColor};padding:16px 24px;text-align:center;display:block;width:${TIP_WIDTH}px;box-sizing:border-box;border-radius:4px;">${linesHtml}</div>`
|
|
|
-}
|
|
|
-
|
|
|
-const showUnifiedTip = (content, { bg = '#f5ff2f', color = '#000', duration = 3000 } = {}) => {
|
|
|
- ElMessage.closeAll()
|
|
|
- ElMessage({
|
|
|
- type: '',
|
|
|
- dangerouslyUseHTMLString: true,
|
|
|
- duration,
|
|
|
- offset: TIP_OFFSET,
|
|
|
- message: buildTipHtml(content, bg, color),
|
|
|
- customClass: TIP_CLASS,
|
|
|
- })
|
|
|
-}
|
|
|
-
|
|
|
-const successres = (arr) => showUnifiedTip(arr, { bg: '#80FA80' })
|
|
|
-const errorres = (arr) => showUnifiedTip(arr, { bg: 'red', color: '#fff' })
|
|
|
-const warningres = (arr) => showUnifiedTip(arr, { bg: '#f5ff2f' })
|
|
|
-
|
|
|
-/** 机台相关:同位置黄色提示 */
|
|
|
-const machineTip = (text) => {
|
|
|
- showUnifiedTip(
|
|
|
- text || '未获取到机台编号,重启电脑或重新打开系统尝试',
|
|
|
- { duration: 4000 }
|
|
|
- )
|
|
|
-}
|
|
|
-
|
|
|
-/** 提交/修改/删除成功:同位置黄色提示 */
|
|
|
-const yellowTopTip = (text) => {
|
|
|
- showUnifiedTip(String(text || '').trim() || '操作成功')
|
|
|
-}
|
|
|
-</script>
|
|
|
-
|
|
|
-<style scoped>
|
|
|
-.form-container {
|
|
|
- display: flex;
|
|
|
- flex-wrap: wrap;
|
|
|
-}
|
|
|
-
|
|
|
-.form-column {
|
|
|
- /*flex: 1;*/
|
|
|
- margin-right: 15px; /* 调整列之间的间距 */
|
|
|
-}
|
|
|
-
|
|
|
-/* 左侧输入框宽度调整 */
|
|
|
-.form-column .el-form-item .el-input {
|
|
|
- width: 150px; /* 调整左侧输入框的宽度 */
|
|
|
-}
|
|
|
-
|
|
|
-/* 媒体查询,根据需要调整断点 */
|
|
|
-@media screen and (max-width: 768px) {
|
|
|
- .form-column {
|
|
|
- flex: 1 0 100%; /* 在小屏幕下变成单列布局 */
|
|
|
- margin-right: 0;
|
|
|
- }
|
|
|
-}
|
|
|
-/*:deep(.el-table td .cell) {*/
|
|
|
-/* line-height: 30px !important;*/
|
|
|
-/*}*/
|
|
|
-.JKWTree-container {
|
|
|
- display: flex;
|
|
|
-}
|
|
|
-.JKWTree-tree {
|
|
|
- /*width: 300px;*/
|
|
|
- background-color: #fff;
|
|
|
- padding: 10px;
|
|
|
- margin-right: 20px;
|
|
|
-}
|
|
|
-.JKWTree-tree h3 {
|
|
|
- font-size: 15px;
|
|
|
- font-weight: 700;
|
|
|
- margin: 10px 0;
|
|
|
-}
|
|
|
-.JKWTree-content {
|
|
|
- flex: 1;
|
|
|
-}
|
|
|
-/* 图片上传 */
|
|
|
-.upload-box {
|
|
|
- width: 200px;
|
|
|
- height: 200px;
|
|
|
- border: 2px dashed #e2e2e2;
|
|
|
- display: flex;
|
|
|
- justify-content: center;
|
|
|
- align-items: center;
|
|
|
- position: relative;
|
|
|
- cursor: pointer;
|
|
|
-}
|
|
|
-.uploaded-image {
|
|
|
- width: 100%;
|
|
|
- height: 100%;
|
|
|
- object-fit: cover;
|
|
|
-}
|
|
|
-.upload-icon {
|
|
|
- font-size: 40px;
|
|
|
- color: #c0c4cc;
|
|
|
-}
|
|
|
-.file-input {
|
|
|
- display: none;
|
|
|
-}
|
|
|
-.el-table .warning-row {
|
|
|
- background: oldlace;
|
|
|
-}
|
|
|
-
|
|
|
-/*bom参数背景*/
|
|
|
-:deep(.el-table__body .background-plan-usage-low div div div) {
|
|
|
- background: #80FA80 !important;
|
|
|
-}
|
|
|
-/* 选中某行时的背景色 */
|
|
|
-:deep(.el-table__body tr.current-row) > td {
|
|
|
- background: #ff80ff !important;
|
|
|
-}
|
|
|
-/* 鼠标悬停时的背景色(工序产量核查表关闭悬停高亮) */
|
|
|
-:deep(.el-table__body tr:hover) > td {
|
|
|
- background: #ff80ff !important;
|
|
|
-}
|
|
|
-:deep(.process-production-table-wrap .el-table__body tr:hover > td) {
|
|
|
- background-color: var(--el-table-tr-bg-color, #fff) !important;
|
|
|
-}
|
|
|
-:deep(.process-production-table-wrap .el-table__body tr.el-table__row--striped:hover > td) {
|
|
|
- background-color: var(--el-fill-color-lighter, #fafafa) !important;
|
|
|
-}
|
|
|
-:deep(.process-production-table-wrap .el-table__body tr.process-production-row-active > td) {
|
|
|
- background-color: #ff80ff !important;
|
|
|
- background: #ff80ff !important;
|
|
|
-}
|
|
|
-
|
|
|
-/* 员工选择区域样式 */
|
|
|
-.employee-grid {
|
|
|
- display: grid;
|
|
|
- grid-template-columns: repeat(8, 1fr);
|
|
|
- gap: 15px;
|
|
|
- margin-top: 10px;
|
|
|
-}
|
|
|
-
|
|
|
-.employee-card {
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- align-items: center;
|
|
|
- padding: 15px;
|
|
|
- border-radius: 8px;
|
|
|
- background-color: #f5f7fa;
|
|
|
- cursor: pointer;
|
|
|
- transition: all 0.3s ease;
|
|
|
- border: 2px solid transparent;
|
|
|
-}
|
|
|
-
|
|
|
-.employee-card:hover {
|
|
|
- transform: translateY(-3px);
|
|
|
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
|
-}
|
|
|
-
|
|
|
-.employee-card.selected {
|
|
|
- border-color: #667eea;
|
|
|
- background-color: #e6e8ff;
|
|
|
-}
|
|
|
-
|
|
|
-.employee-avatar {
|
|
|
- width: 60px;
|
|
|
- height: 60px;
|
|
|
- border-radius: 50%;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
- color: white;
|
|
|
- font-size: 24px;
|
|
|
- font-weight: bold;
|
|
|
- margin-bottom: 10px;
|
|
|
-}
|
|
|
-
|
|
|
-.employee-name {
|
|
|
- font-size: 16px;
|
|
|
- font-weight: bold;
|
|
|
- margin-bottom: 5px;
|
|
|
- text-align: center;
|
|
|
-}
|
|
|
-
|
|
|
-.employee-id {
|
|
|
- font-size: 14px;
|
|
|
- font-weight: bold;
|
|
|
- color: #666;
|
|
|
- text-align: center;
|
|
|
-}
|
|
|
-</style>
|
|
|
-<style scoped>
|
|
|
-:deep(.el-table td .cell) {
|
|
|
- line-height: 20px !important;
|
|
|
-}
|
|
|
-:deep(.el-tabs__header){
|
|
|
- margin-bottom: 0;
|
|
|
-}
|
|
|
-.search{
|
|
|
- margin-left: 0px !important;
|
|
|
- margin-right: 10px !important;
|
|
|
-}
|
|
|
-.bt{
|
|
|
- margin-left: 2px !important;
|
|
|
- padding: 3px !important;
|
|
|
- font-size: 12px;
|
|
|
-}
|
|
|
-.el-tabs__header{
|
|
|
- margin: 0px !important;
|
|
|
-}
|
|
|
-.gva-table-box{
|
|
|
- padding: 0px !important;
|
|
|
- margin-left: -10px !important;
|
|
|
- min-height: 600px;
|
|
|
-}
|
|
|
-.gongfen-report-tabs {
|
|
|
- padding: 0;
|
|
|
-}
|
|
|
-.gongfen-toolbar-row {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- flex-wrap: wrap;
|
|
|
- gap: 10px;
|
|
|
- margin-bottom: 20px;
|
|
|
-}
|
|
|
-.gongfen-order-search-input {
|
|
|
- width: 200px;
|
|
|
- flex-shrink: 0;
|
|
|
-}
|
|
|
-.gongfen-order-search-input :deep(.el-input__wrapper) {
|
|
|
- height: 50px;
|
|
|
-}
|
|
|
-.gongfen-search-btn {
|
|
|
- height: 50px;
|
|
|
- width: 80px;
|
|
|
- flex-shrink: 0;
|
|
|
- margin: 0;
|
|
|
-}
|
|
|
-.gongfen-toolbar-label {
|
|
|
- font-size: 30px;
|
|
|
- line-height: 1;
|
|
|
- white-space: nowrap;
|
|
|
-}
|
|
|
-.gongfen-toolbar-field {
|
|
|
- width: 120px;
|
|
|
- flex-shrink: 0;
|
|
|
-}
|
|
|
-.gongfen-toolbar-field :deep(.el-input__wrapper) {
|
|
|
- height: 40px;
|
|
|
-}
|
|
|
-.gongfen-order-actions {
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- gap: 8px;
|
|
|
- margin-left: 20px;
|
|
|
- margin-right: 24px;
|
|
|
- flex-shrink: 0;
|
|
|
-}
|
|
|
-.gongfen-work-score-btn {
|
|
|
- height: 64px;
|
|
|
- width: 120px;
|
|
|
- font-size: 18px;
|
|
|
-}
|
|
|
-.work-score-order-header {
|
|
|
- flex-shrink: 0;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: space-between;
|
|
|
- gap: 16px;
|
|
|
- padding: 8px 16px;
|
|
|
- background-color: #333;
|
|
|
- color: white;
|
|
|
-}
|
|
|
-.work-score-order-bar {
|
|
|
- flex: 1;
|
|
|
- min-width: 0;
|
|
|
- display: flex;
|
|
|
- flex-wrap: wrap;
|
|
|
- gap: 24px;
|
|
|
-}
|
|
|
-.work-score-order-bar p {
|
|
|
- margin: 5px 0;
|
|
|
- font-size: 16px;
|
|
|
- font-weight: bold;
|
|
|
-}
|
|
|
-.work-score-close-btn {
|
|
|
- flex-shrink: 0;
|
|
|
- min-width: 80px;
|
|
|
- height: 36px;
|
|
|
- font-size: 15px;
|
|
|
- font-weight: 600;
|
|
|
-}
|
|
|
-:deep(.work-score-dialog) {
|
|
|
- padding: 0;
|
|
|
- margin: 0;
|
|
|
-}
|
|
|
-:deep(.work-score-dialog .el-dialog__header) {
|
|
|
- display: none;
|
|
|
- padding: 0;
|
|
|
- margin: 0;
|
|
|
-}
|
|
|
-:deep(.work-score-dialog .el-dialog__body) {
|
|
|
- padding: 0;
|
|
|
-}
|
|
|
-.work-score-dialog-inner {
|
|
|
- height: 100vh;
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- overflow: hidden;
|
|
|
- position: fixed;
|
|
|
- top: 0;
|
|
|
- left: 0;
|
|
|
- right: 0;
|
|
|
- bottom: 0;
|
|
|
- background: white;
|
|
|
-}
|
|
|
-.work-score-main-body {
|
|
|
- flex: 1;
|
|
|
- display: flex;
|
|
|
- min-height: 0;
|
|
|
- overflow: hidden;
|
|
|
-}
|
|
|
-.work-score-sidebar {
|
|
|
- width: 170px;
|
|
|
- border-right: 1px solid #e0e0e0;
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- overflow: hidden;
|
|
|
- flex-shrink: 0;
|
|
|
-}
|
|
|
-.work-score-right-panel {
|
|
|
- flex: 1;
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- min-height: 0;
|
|
|
- overflow: hidden;
|
|
|
-}
|
|
|
-.work-score-content-header {
|
|
|
- flex-shrink: 0;
|
|
|
- padding: 6px 10px;
|
|
|
- border-bottom: 1px solid #e0e0e0;
|
|
|
- background-color: #f5f5f5;
|
|
|
-}
|
|
|
-.work-score-section-title {
|
|
|
- margin: 0;
|
|
|
- font-size: 15px;
|
|
|
- font-weight: 600;
|
|
|
- line-height: 1.2;
|
|
|
-}
|
|
|
-.work-score-sidebar .part-list.work-score-part-list {
|
|
|
- flex: 1;
|
|
|
- min-height: 0;
|
|
|
- overflow-y: auto !important;
|
|
|
- overflow-x: hidden;
|
|
|
- padding-bottom: 12px;
|
|
|
- border: none;
|
|
|
- border-radius: 0;
|
|
|
-}
|
|
|
-.work-score-sidebar .part-item {
|
|
|
- padding: 10px 12px;
|
|
|
-}
|
|
|
-.work-score-employee-section {
|
|
|
- flex-shrink: 0;
|
|
|
- border-bottom: 1px solid #e0e0e0;
|
|
|
- background-color: #fafafa;
|
|
|
-}
|
|
|
-.work-score-employee-section .employee-grid {
|
|
|
- margin-top: 0;
|
|
|
-}
|
|
|
-.work-score-step-header {
|
|
|
- flex-shrink: 0;
|
|
|
- padding: 4px 12px;
|
|
|
- min-height: 28px;
|
|
|
- box-sizing: border-box;
|
|
|
- background: #fafafa;
|
|
|
-}
|
|
|
-.work-score-step-text {
|
|
|
- margin: 0;
|
|
|
- font-size: 17px;
|
|
|
- line-height: 1.5;
|
|
|
- color: #303133;
|
|
|
- white-space: nowrap;
|
|
|
-}
|
|
|
-.work-score-step-text strong {
|
|
|
- color: #303133;
|
|
|
- font-weight: 700;
|
|
|
-}
|
|
|
-.work-score-step-row {
|
|
|
- gap: 12px;
|
|
|
- flex-wrap: wrap;
|
|
|
-}
|
|
|
-.work-score-toolbar-guide {
|
|
|
- width: 100%;
|
|
|
-}
|
|
|
-.work-score-batch-label {
|
|
|
- flex-shrink: 0;
|
|
|
- font-size: 15px;
|
|
|
- font-weight: 600;
|
|
|
- color: #606266;
|
|
|
-}
|
|
|
-.work-score-step-hint {
|
|
|
- margin: 6px 0 0;
|
|
|
- font-size: 14px;
|
|
|
- line-height: 1.5;
|
|
|
- color: #909399;
|
|
|
-}
|
|
|
-.work-score-selected-name {
|
|
|
- color: #2563eb;
|
|
|
- font-weight: 600;
|
|
|
-}
|
|
|
-.work-score-selected-name.is-empty {
|
|
|
- color: #e6a23c;
|
|
|
-}
|
|
|
-.work-score-step-hint-divider {
|
|
|
- margin: 0 8px;
|
|
|
- color: #dcdfe6;
|
|
|
-}
|
|
|
-.work-score-steps {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- flex-wrap: nowrap;
|
|
|
- gap: 8px;
|
|
|
- width: 100%;
|
|
|
-}
|
|
|
-.work-score-step {
|
|
|
- font-size: 16px;
|
|
|
- font-weight: 600;
|
|
|
- color: #606266;
|
|
|
- white-space: nowrap;
|
|
|
-}
|
|
|
-.work-score-step.is-active {
|
|
|
- color: #2563eb;
|
|
|
- font-weight: 700;
|
|
|
-}
|
|
|
-.work-score-step-arrow {
|
|
|
- font-size: 16px;
|
|
|
- color: #909399;
|
|
|
- flex-shrink: 0;
|
|
|
-}
|
|
|
-.work-score-employee-grid {
|
|
|
- display: flex;
|
|
|
- flex-wrap: nowrap;
|
|
|
- gap: 6px;
|
|
|
- padding: 4px 10px 4px;
|
|
|
- min-height: 0;
|
|
|
- box-sizing: border-box;
|
|
|
-}
|
|
|
-.work-score-employee-section .employee-card {
|
|
|
- flex: 1 1 0;
|
|
|
- min-width: 0;
|
|
|
- padding: 6px 4px;
|
|
|
- min-height: auto;
|
|
|
- border-radius: 6px;
|
|
|
- border: 2px solid transparent;
|
|
|
- box-sizing: border-box;
|
|
|
-}
|
|
|
-.work-score-employee-section .employee-card:hover {
|
|
|
- transform: none;
|
|
|
- box-shadow: none;
|
|
|
-}
|
|
|
-.work-score-employee-section .employee-avatar {
|
|
|
- width: 30px;
|
|
|
- height: 30px;
|
|
|
- font-size: 18px;
|
|
|
- margin-bottom: 4px;
|
|
|
-}
|
|
|
-.work-score-employee-section .employee-name {
|
|
|
- font-size: 18px;
|
|
|
- font-weight: 600;
|
|
|
- line-height: 1.2;
|
|
|
- margin-bottom: 2px;
|
|
|
- white-space: nowrap;
|
|
|
- overflow: hidden;
|
|
|
- text-overflow: ellipsis;
|
|
|
- width: 100%;
|
|
|
- text-align: center;
|
|
|
-}
|
|
|
-.work-score-employee-section .employee-id {
|
|
|
- font-size: 14px;
|
|
|
- line-height: 1.2;
|
|
|
- white-space: nowrap;
|
|
|
- overflow: hidden;
|
|
|
- text-overflow: ellipsis;
|
|
|
- width: 100%;
|
|
|
- text-align: center;
|
|
|
-}
|
|
|
-.work-score-employee-section .employee-card.selected {
|
|
|
- border-color: #10b981;
|
|
|
- border-width: 2px;
|
|
|
- background: #ecfdf5;
|
|
|
-}
|
|
|
-.work-score-process-area {
|
|
|
- flex: 1;
|
|
|
- min-height: 0;
|
|
|
- overflow: hidden;
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- padding: 2px 10px 4px;
|
|
|
-}
|
|
|
-.work-score-process-block {
|
|
|
- flex: 1;
|
|
|
- min-height: 0;
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- overflow: hidden;
|
|
|
-}
|
|
|
-.work-score-process-toolbar {
|
|
|
- flex-shrink: 0;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: space-between;
|
|
|
- flex-wrap: wrap;
|
|
|
- gap: 8px;
|
|
|
- margin-bottom: 2px;
|
|
|
- padding-bottom: 2px;
|
|
|
- background: #fff;
|
|
|
- border-bottom: 1px solid #ebeef5;
|
|
|
- z-index: 2;
|
|
|
-}
|
|
|
-.work-score-process-toolbar h4 {
|
|
|
- margin: 0;
|
|
|
- font-size: 14px;
|
|
|
- flex-shrink: 0;
|
|
|
-}
|
|
|
-.work-score-process-toolbar--simple {
|
|
|
- flex-shrink: 0;
|
|
|
- padding: 4px 12px;
|
|
|
- background: #fafafa;
|
|
|
- border-bottom: 1px solid #ebeef5;
|
|
|
- border-radius: 0;
|
|
|
-}
|
|
|
-.work-score-quick-row {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- flex-wrap: nowrap;
|
|
|
- gap: 12px;
|
|
|
- width: 100%;
|
|
|
- min-height: 40px;
|
|
|
-}
|
|
|
-.work-score-batch-qty-input {
|
|
|
- width: 72px;
|
|
|
- flex-shrink: 0;
|
|
|
-}
|
|
|
-.work-score-batch-qty-input :deep(.el-input__inner) {
|
|
|
- height: 34px;
|
|
|
- font-size: 16px;
|
|
|
- font-weight: 600;
|
|
|
- text-align: center;
|
|
|
- color: #303133;
|
|
|
-}
|
|
|
-.work-score-batch-qty-input :deep(.el-input__inner::placeholder) {
|
|
|
- font-size: 13px;
|
|
|
- font-weight: 400;
|
|
|
- color: #a8abb2;
|
|
|
-}
|
|
|
-.work-score-batch-qty-input :deep(input[type='number']) {
|
|
|
- -moz-appearance: textfield;
|
|
|
- appearance: textfield;
|
|
|
-}
|
|
|
-.work-score-batch-qty-input :deep(input[type='number']::-webkit-outer-spin-button),
|
|
|
-.work-score-batch-qty-input :deep(input[type='number']::-webkit-inner-spin-button) {
|
|
|
- -webkit-appearance: none;
|
|
|
- margin: 0;
|
|
|
-}
|
|
|
-.work-score-submit-btn {
|
|
|
- flex-shrink: 0;
|
|
|
- min-width: 88px;
|
|
|
- height: 32px;
|
|
|
- font-size: 14px;
|
|
|
- font-weight: 600;
|
|
|
- padding: 0 12px;
|
|
|
- margin-left: auto;
|
|
|
-}
|
|
|
-.work-score-confirm-tip {
|
|
|
- margin: 0 0 12px;
|
|
|
- font-size: 15px;
|
|
|
- color: #606266;
|
|
|
-}
|
|
|
-:deep(.work-score-confirm-over-cell) {
|
|
|
- color: #f56c6c !important;
|
|
|
- font-weight: 600;
|
|
|
-}
|
|
|
-.work-score-process-table-wrap :deep(.work-score-process-table .el-input__inner) {
|
|
|
- height: 30px;
|
|
|
- font-size: 14px;
|
|
|
-}
|
|
|
-.work-score-process-table-wrap :deep(.work-score-qty-input .el-input__inner) {
|
|
|
- height: 30px;
|
|
|
- font-size: 18px;
|
|
|
- font-weight: 600;
|
|
|
- text-align: center;
|
|
|
- color: #303133;
|
|
|
-}
|
|
|
-/* 选中行:只高亮整行粉色,输入框保持白底 */
|
|
|
-.work-score-process-table-wrap :deep(.el-table__body tr.work-score-process-row-active > td.el-table__cell),
|
|
|
-.work-score-process-table-wrap :deep(.el-table__body tr.current-row > td.el-table__cell) {
|
|
|
- background-color: #ff80ff !important;
|
|
|
- background: #ff80ff !important;
|
|
|
-}
|
|
|
-.work-score-process-table-wrap :deep(.work-score-qty-over .el-input__inner) {
|
|
|
- color: #f56c6c !important;
|
|
|
-}
|
|
|
-.work-score-process-table-wrap :deep(.work-score-staff-input .el-input__inner) {
|
|
|
- height: 30px;
|
|
|
- font-size: 14px;
|
|
|
- text-align: center;
|
|
|
-}
|
|
|
-.work-score-process-table-wrap :deep(.work-score-process-table .cell) {
|
|
|
- font-size: 15px;
|
|
|
- line-height: 1.4;
|
|
|
- padding-top: 0px;
|
|
|
- padding-bottom: 0px;
|
|
|
-}
|
|
|
-.work-score-row-actions {
|
|
|
- display: flex;
|
|
|
- flex-direction: row;
|
|
|
- flex-wrap: nowrap;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
- gap: 6px;
|
|
|
-}
|
|
|
-.work-score-fill-row-btn,
|
|
|
-.work-score-add-person-btn {
|
|
|
- margin: 0;
|
|
|
- min-width: 52px;
|
|
|
- height: 30px;
|
|
|
- padding: 0 10px;
|
|
|
- font-size: 13px;
|
|
|
- font-weight: 600;
|
|
|
- border-radius: 4px;
|
|
|
-}
|
|
|
-.work-score-add-person-btn {
|
|
|
- color: #409eff;
|
|
|
- border-color: #b3d8ff;
|
|
|
- background: #fff;
|
|
|
-}
|
|
|
-.work-score-add-person-btn:hover:not(:disabled) {
|
|
|
- color: #fff;
|
|
|
- border-color: #409eff;
|
|
|
- background: #409eff;
|
|
|
-}
|
|
|
-.work-score-fill-row-btn:disabled {
|
|
|
- opacity: 0.45;
|
|
|
-}
|
|
|
-.work-score-staff-row {
|
|
|
- margin-bottom: 2px;
|
|
|
-}
|
|
|
-.work-score-staff-row:last-child {
|
|
|
- margin-bottom: 0;
|
|
|
-}
|
|
|
-.work-score-process-table-wrap :deep(.work-score-process-table td.el-table__cell) {
|
|
|
- padding: 3px 0;
|
|
|
-}
|
|
|
-.work-score-process-table-wrap :deep(.work-score-process-table th.el-table__cell) {
|
|
|
- padding: 8px 0;
|
|
|
- font-size: 14px;
|
|
|
- background: #f5f7fa;
|
|
|
-}
|
|
|
-.work-score-process-table-wrap :deep(.work-score-process-table .el-table__body-wrapper) {
|
|
|
- overflow-y: auto;
|
|
|
-}
|
|
|
-.work-score-process-table-wrap :deep(.work-score-process-table .el-scrollbar__wrap) {
|
|
|
- padding-bottom: 6px;
|
|
|
- box-sizing: border-box;
|
|
|
-}
|
|
|
-.work-score-process-table-wrap :deep(.work-score-process-table .el-scrollbar__bar.is-vertical) {
|
|
|
- width: 8px;
|
|
|
- right: 2px;
|
|
|
-}
|
|
|
-.work-score-process-table-wrap {
|
|
|
- flex: 1;
|
|
|
- min-height: 0;
|
|
|
- height: 0;
|
|
|
- overflow: hidden;
|
|
|
- padding-bottom: 4px;
|
|
|
- box-sizing: border-box;
|
|
|
-}
|
|
|
-.work-score-process-table-wrap :deep(input[type='number']) {
|
|
|
- -moz-appearance: textfield;
|
|
|
- appearance: textfield;
|
|
|
-}
|
|
|
-.work-score-process-table-wrap :deep(input[type='number']::-webkit-outer-spin-button),
|
|
|
-.work-score-process-table-wrap :deep(input[type='number']::-webkit-inner-spin-button) {
|
|
|
- -webkit-appearance: none;
|
|
|
- margin: 0;
|
|
|
-}
|
|
|
-.work-score-process-empty {
|
|
|
- flex: 1;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
- text-align: center;
|
|
|
- padding: 50px;
|
|
|
-}
|
|
|
-.work-score-process-empty--muted {
|
|
|
- color: #999;
|
|
|
-}
|
|
|
-.gongfen-col-header {
|
|
|
- display: inline-flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
- gap: 4px;
|
|
|
- width: 100%;
|
|
|
-}
|
|
|
-
|
|
|
-.gongfen-history-table :deep(.el-table__header .cell),
|
|
|
-.gongfen-history-table :deep(.el-table__body .cell),
|
|
|
-.gongfen-history-table :deep(.el-table__footer .cell) {
|
|
|
- padding-left: 8px;
|
|
|
- padding-right: 8px;
|
|
|
- line-height: 24px;
|
|
|
- box-sizing: border-box;
|
|
|
-}
|
|
|
-
|
|
|
-.gongfen-history-table :deep(.el-table__header th),
|
|
|
-.gongfen-history-table :deep(.el-table__body td),
|
|
|
-.gongfen-history-table :deep(.el-table__footer td) {
|
|
|
- padding-top: 4px !important;
|
|
|
- padding-bottom: 4px !important;
|
|
|
-}
|
|
|
-
|
|
|
-.gongfen-history-table :deep(.el-table__footer-wrapper td) {
|
|
|
- font-weight: 600;
|
|
|
- background: #fafafa;
|
|
|
-}
|
|
|
-.gy-detail-filter-btn {
|
|
|
- display: inline-flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
- width: 22px;
|
|
|
- height: 22px;
|
|
|
- cursor: pointer;
|
|
|
- color: #909399;
|
|
|
- border-radius: 2px;
|
|
|
-}
|
|
|
-.gy-detail-filter-btn:hover,
|
|
|
-.gy-detail-filter-btn.is-active {
|
|
|
- color: var(--el-color-primary);
|
|
|
- background: #ecf5ff;
|
|
|
-}
|
|
|
-.gy-detail-filter-options {
|
|
|
- max-height: 220px;
|
|
|
- overflow-x: hidden;
|
|
|
- overflow-y: auto;
|
|
|
- margin-bottom: 4px;
|
|
|
-}
|
|
|
-.gy-detail-filter-panel :deep(.el-checkbox) {
|
|
|
- display: flex;
|
|
|
- margin-right: 0;
|
|
|
- margin-bottom: 6px;
|
|
|
-}
|
|
|
-.gy-detail-filter-actions {
|
|
|
- display: flex;
|
|
|
- justify-content: space-between;
|
|
|
- align-items: center;
|
|
|
- margin-top: 4px;
|
|
|
- padding-top: 8px;
|
|
|
- border-top: 1px solid #ebeef5;
|
|
|
-}
|
|
|
-.gy-detail-filter-link {
|
|
|
- color: var(--el-color-primary);
|
|
|
- font-size: 12px;
|
|
|
- line-height: 1;
|
|
|
- cursor: pointer;
|
|
|
- user-select: none;
|
|
|
- padding: 4px 2px;
|
|
|
-}
|
|
|
-.gy-detail-filter-link:hover {
|
|
|
- opacity: 0.85;
|
|
|
-}
|
|
|
-.mab{
|
|
|
- margin-bottom: 5px;
|
|
|
-}
|
|
|
-
|
|
|
-/* 搜索样式 */
|
|
|
-::v-deep .el-input__wrapper #searchInput {
|
|
|
- font-size: 16px;
|
|
|
-}
|
|
|
-::v-deep .el-input__wrapper #jitaihao {
|
|
|
- font-size: 18px;
|
|
|
-}
|
|
|
-::v-deep .el-input__wrapper #gongxu {
|
|
|
- font-size: 18px;
|
|
|
-}
|
|
|
-::v-deep .el-input__wrapper #zubie {
|
|
|
- font-size: 18px;
|
|
|
-}
|
|
|
-::v-deep .el-input__wrapper #renyuan {
|
|
|
- font-size: 18px;
|
|
|
-}
|
|
|
-::v-deep .el-input__wrapper #shuliang {
|
|
|
- font-size: 18px;
|
|
|
- color: red;
|
|
|
-}
|
|
|
-::v-deep .el-input__wrapper #chima {
|
|
|
- font-size: 18px;
|
|
|
-}
|
|
|
-
|
|
|
-/* 尺码/制单数合计样式 */
|
|
|
-::v-deep .el-input__wrapper #cm1{
|
|
|
- font-size: 20px;
|
|
|
-}
|
|
|
-::v-deep .el-input__wrapper #cm2{
|
|
|
- font-size: 20px;
|
|
|
-}
|
|
|
-::v-deep .el-input__wrapper #cm3{
|
|
|
- font-size: 20px;
|
|
|
-}
|
|
|
-::v-deep .el-input__wrapper #cm4{
|
|
|
- font-size: 20px;
|
|
|
-}
|
|
|
-::v-deep .el-input__wrapper #cm5{
|
|
|
- font-size: 20px;
|
|
|
-}
|
|
|
-::v-deep .el-input__wrapper #cm6{
|
|
|
- font-size: 20px;
|
|
|
-}
|
|
|
-::v-deep .el-input__wrapper #cm7{
|
|
|
- font-size: 20px;
|
|
|
-}
|
|
|
-::v-deep .el-input__wrapper #cm8{
|
|
|
- font-size: 20px;
|
|
|
-}
|
|
|
-::v-deep .el-input__wrapper #cm9{
|
|
|
- font-size: 20px;
|
|
|
-}
|
|
|
-::v-deep .el-input__wrapper #cm10{
|
|
|
- font-size: 20px;
|
|
|
-}
|
|
|
-::v-deep .el-input__wrapper #cm11{
|
|
|
- font-size: 20px;
|
|
|
-}
|
|
|
-::v-deep .el-input__wrapper #cm12{
|
|
|
- font-size: 20px;
|
|
|
-}
|
|
|
-::v-deep .el-input__wrapper #cm13{
|
|
|
- font-size: 20px;
|
|
|
-}
|
|
|
-::v-deep .el-input__wrapper #cm14{
|
|
|
- font-size: 20px;
|
|
|
-}
|
|
|
-::v-deep .el-input__wrapper #cmtotal{
|
|
|
- font-size: 20px;
|
|
|
-}
|
|
|
-/* 本次实裁新增样式 */
|
|
|
-::v-deep .el-input__wrapper #cmsl1{
|
|
|
- font-size: 20px;
|
|
|
- color: red !important;
|
|
|
-}
|
|
|
-::v-deep .el-input__wrapper #cmsl2{
|
|
|
- font-size: 20px;
|
|
|
- color: red !important;
|
|
|
-}
|
|
|
-::v-deep .el-input__wrapper #cmsl3{
|
|
|
- font-size: 20px;
|
|
|
- color: red !important;
|
|
|
-}
|
|
|
-::v-deep .el-input__wrapper #cmsl4{
|
|
|
- font-size: 20px;
|
|
|
- color: red !important;
|
|
|
-}
|
|
|
-::v-deep .el-input__wrapper #cmsl5{
|
|
|
- font-size: 20px;
|
|
|
- color: red !important;
|
|
|
-}
|
|
|
-::v-deep .el-input__wrapper #cmsl6{
|
|
|
- font-size: 20px;
|
|
|
- color: red !important;
|
|
|
-}
|
|
|
-::v-deep .el-input__wrapper #cmsl7{
|
|
|
- font-size: 20px;
|
|
|
- color: red !important;
|
|
|
-}
|
|
|
-::v-deep .el-input__wrapper #cmsl8{
|
|
|
- font-size: 20px;
|
|
|
- color: red !important;
|
|
|
-}
|
|
|
-::v-deep .el-input__wrapper #cmsl9{
|
|
|
- font-size: 20px;
|
|
|
- color: red !important;
|
|
|
-}
|
|
|
-::v-deep .el-input__wrapper #cmsl10{
|
|
|
- font-size: 20px;
|
|
|
- color: red !important;
|
|
|
-}
|
|
|
-::v-deep .el-input__wrapper #cmsl11{
|
|
|
- font-size: 20px;
|
|
|
- color: red !important;
|
|
|
-}
|
|
|
-::v-deep .el-input__wrapper #cmsl12{
|
|
|
- font-size: 20px;
|
|
|
- color: red !important;
|
|
|
-}
|
|
|
-::v-deep .el-input__wrapper #cmsl13{
|
|
|
- font-size: 20px;
|
|
|
- color: red !important;
|
|
|
-}
|
|
|
-::v-deep .el-input__wrapper #cmsl14{
|
|
|
- font-size: 20px;
|
|
|
- color: red !important;
|
|
|
-}
|
|
|
-::v-deep .el-input__wrapper #zdtotal{
|
|
|
- font-size: 20px;
|
|
|
- color: red !important;
|
|
|
-}
|
|
|
-::v-deep .el-input__wrapper #scs1{
|
|
|
- font-size: 18px;
|
|
|
-}
|
|
|
-::v-deep .el-input__wrapper #scs2{
|
|
|
- font-size: 18px;
|
|
|
-}
|
|
|
-::v-deep .el-input__wrapper #scs3{
|
|
|
- font-size: 18px;
|
|
|
-}
|
|
|
-::v-deep .el-input__wrapper #scs4{
|
|
|
- font-size: 18px;
|
|
|
-}
|
|
|
-::v-deep .el-input__wrapper #scs5{
|
|
|
- font-size: 18px;
|
|
|
-}
|
|
|
-::v-deep .el-input__wrapper #scs6{
|
|
|
- font-size: 18px;
|
|
|
-}
|
|
|
-::v-deep .el-input__wrapper #scs7{
|
|
|
- font-size: 18px;
|
|
|
-}
|
|
|
-::v-deep .el-input__wrapper #scs8{
|
|
|
- font-size: 18px;
|
|
|
-}
|
|
|
-::v-deep .el-input__wrapper #scs9{
|
|
|
- font-size: 18px;
|
|
|
-}
|
|
|
-::v-deep .el-input__wrapper #scs10{
|
|
|
- font-size: 18px;
|
|
|
-}
|
|
|
-::v-deep .el-input__wrapper #scs11{
|
|
|
- font-size: 18px;
|
|
|
-}
|
|
|
-::v-deep .el-input__wrapper #scs12{
|
|
|
- font-size: 18px;
|
|
|
-}
|
|
|
-::v-deep .el-input__wrapper #scs13{
|
|
|
- font-size: 18px;
|
|
|
-}
|
|
|
-::v-deep .el-input__wrapper #scs14{
|
|
|
- font-size: 18px;
|
|
|
-}
|
|
|
-::v-deep .el-input__wrapper #sctotal{
|
|
|
- font-size: 18px;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/* 表格复选框大小调整 */
|
|
|
-:deep(.el-checkbox.el-checkbox--small .el-checkbox__inner) {
|
|
|
- width: 30px;
|
|
|
- /* 复选框宽度 */
|
|
|
- height: 20px;
|
|
|
- /* 复选框高度 */
|
|
|
-}
|
|
|
-:deep(.el-checkbox.el-checkbox--small.is-checked .el-checkbox__inner::after) {
|
|
|
- transform: scale(1.2) rotate(45deg);
|
|
|
- /* 调整选中后的对勾大小 */
|
|
|
- top: 5%;
|
|
|
- /* 调整对勾位置 */
|
|
|
- left: 40%;
|
|
|
- /* 调整对勾位置 */
|
|
|
- width: 5px;
|
|
|
- /* 调整对勾宽度 */
|
|
|
- height: 9px;
|
|
|
- /* 调整对勾高度 */
|
|
|
-}
|
|
|
-
|
|
|
-/* 部件列表样式 */
|
|
|
-.part-list {
|
|
|
- border: 1px solid #e0e0e0;
|
|
|
- border-radius: 4px;
|
|
|
- overflow: hidden;
|
|
|
-}
|
|
|
-
|
|
|
-.part-item {
|
|
|
- padding: 15px;
|
|
|
- border-bottom: 1px solid #f0f0f0;
|
|
|
- cursor: pointer;
|
|
|
- transition: all 0.3s ease;
|
|
|
-}
|
|
|
-
|
|
|
-.part-item:last-child {
|
|
|
- border-bottom: none;
|
|
|
-}
|
|
|
-
|
|
|
-.part-item:hover {
|
|
|
- background-color: #f5f7fa;
|
|
|
-}
|
|
|
-
|
|
|
-.part-item.selected {
|
|
|
- background-color: #ecf5ff;
|
|
|
- border-left: 4px solid #409EFF;
|
|
|
-}
|
|
|
-
|
|
|
-.part-info {
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
-}
|
|
|
-
|
|
|
-.part-number {
|
|
|
- font-size: 14px;
|
|
|
- color: #999;
|
|
|
- margin-bottom: 5px;
|
|
|
-}
|
|
|
-
|
|
|
-.part-name {
|
|
|
- font-size: 16px;
|
|
|
- font-weight: 500;
|
|
|
-}
|
|
|
-
|
|
|
-/* 员工网格样式 */
|
|
|
-.employee-grid {
|
|
|
- display: grid;
|
|
|
- grid-template-columns: repeat(12, 1fr);
|
|
|
- gap: 8px;
|
|
|
-}
|
|
|
-
|
|
|
-.employee-card {
|
|
|
- border: 1px solid #e0e0e0;
|
|
|
- border-radius: 12px;
|
|
|
- padding: 10px;
|
|
|
- text-align: center;
|
|
|
- cursor: pointer;
|
|
|
- transition: all 0.3s ease;
|
|
|
-}
|
|
|
-
|
|
|
-.employee-card:hover {
|
|
|
- border-color: #409EFF;
|
|
|
- box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
|
|
-}
|
|
|
-
|
|
|
-.employee-card.selected {
|
|
|
- border-color: #67C23A;
|
|
|
- background-color: #F0F9EB;
|
|
|
-}
|
|
|
-
|
|
|
-.employee-avatar {
|
|
|
- width: 30px;
|
|
|
- height: 30px;
|
|
|
- border-radius: 50%;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
- margin: 0 auto 8px;
|
|
|
- font-size: 20px;
|
|
|
- font-weight: bold;
|
|
|
- color: white;
|
|
|
-}
|
|
|
-
|
|
|
-.employee-name {
|
|
|
- font-size: 20px;
|
|
|
- font-weight: 500;
|
|
|
- margin-bottom: 3px;
|
|
|
-}
|
|
|
-
|
|
|
-.employee-id {
|
|
|
- font-size: 16px;
|
|
|
- color: #999;
|
|
|
-}
|
|
|
-
|
|
|
-</style>
|
|
|
-
|
|
|
-<style>
|
|
|
-/* 工分报工工艺表:选中/悬停整行粉色;完工人员、完工数量输入框保持白底 */
|
|
|
-.work-score-process-table .el-table__body tr.work-score-process-row-active > td.el-table__cell,
|
|
|
-.work-score-process-table .el-table__body tr.current-row > td.el-table__cell,
|
|
|
-.work-score-process-table .el-table__body tr:hover > td.el-table__cell {
|
|
|
- background-color: #ff80ff !important;
|
|
|
- background: #ff80ff !important;
|
|
|
-}
|
|
|
-.work-score-process-table .el-table__body tr.work-score-process-row-active .work-score-qty-input,
|
|
|
-.work-score-process-table .el-table__body tr.current-row .work-score-qty-input,
|
|
|
-.work-score-process-table .el-table__body tr:hover .work-score-qty-input,
|
|
|
-.work-score-process-table .el-table__body tr.work-score-process-row-active .work-score-staff-input,
|
|
|
-.work-score-process-table .el-table__body tr.current-row .work-score-staff-input,
|
|
|
-.work-score-process-table .el-table__body tr:hover .work-score-staff-input {
|
|
|
- --el-input-bg-color: #ffffff;
|
|
|
- --el-fill-color-blank: #ffffff;
|
|
|
-}
|
|
|
-.work-score-process-table .el-table__body tr.work-score-process-row-active .work-score-qty-input .el-input__wrapper,
|
|
|
-.work-score-process-table .el-table__body tr.current-row .work-score-qty-input .el-input__wrapper,
|
|
|
-.work-score-process-table .el-table__body tr:hover .work-score-qty-input .el-input__wrapper,
|
|
|
-.work-score-process-table .el-table__body tr.work-score-process-row-active .work-score-staff-input .el-input__wrapper,
|
|
|
-.work-score-process-table .el-table__body tr.current-row .work-score-staff-input .el-input__wrapper,
|
|
|
-.work-score-process-table .el-table__body tr:hover .work-score-staff-input .el-input__wrapper,
|
|
|
-.work-score-process-table .el-table__body tr.work-score-process-row-active .work-score-qty-input .el-input__wrapper.is-focus,
|
|
|
-.work-score-process-table .el-table__body tr.current-row .work-score-qty-input .el-input__wrapper.is-focus,
|
|
|
-.work-score-process-table .el-table__body tr:hover .work-score-qty-input .el-input__wrapper.is-focus,
|
|
|
-.work-score-process-table .el-table__body tr.work-score-process-row-active .work-score-staff-input .el-input__wrapper.is-focus,
|
|
|
-.work-score-process-table .el-table__body tr.current-row .work-score-staff-input .el-input__wrapper.is-focus,
|
|
|
-.work-score-process-table .el-table__body tr:hover .work-score-staff-input .el-input__wrapper.is-focus {
|
|
|
- background-color: #ffffff !important;
|
|
|
- background: #ffffff !important;
|
|
|
-}
|
|
|
-
|
|
|
-/* 确认报工弹窗:固定尺寸 + 内容居中放大(append-to-body 用全局样式) */
|
|
|
-.work-score-confirm-dialog.el-dialog,
|
|
|
-.work-score-confirm-dialog {
|
|
|
- width: 1040px !important;
|
|
|
- margin-top: 8vh !important;
|
|
|
-}
|
|
|
-.work-score-confirm-dialog .el-dialog__header {
|
|
|
- padding: 12px 12px 6px;
|
|
|
-}
|
|
|
-.work-score-confirm-dialog .el-dialog__title {
|
|
|
- font-size: 20px;
|
|
|
- font-weight: 600;
|
|
|
-}
|
|
|
-.work-score-confirm-dialog .el-dialog__body {
|
|
|
- padding: 4px 12px 4px;
|
|
|
- height: 556px;
|
|
|
- box-sizing: border-box;
|
|
|
- overflow: hidden;
|
|
|
-}
|
|
|
-.work-score-confirm-dialog .work-score-confirm-tip {
|
|
|
- margin: 0 0 6px;
|
|
|
- text-align: center;
|
|
|
- font-size: 18px;
|
|
|
- font-weight: 600;
|
|
|
- color: #303133;
|
|
|
- line-height: 1.3;
|
|
|
-}
|
|
|
-.work-score-confirm-dialog .work-score-confirm-table {
|
|
|
- font-size: 15px;
|
|
|
- width: 100% !important;
|
|
|
-}
|
|
|
-.work-score-confirm-dialog .work-score-confirm-table .el-table__inner-wrapper::before {
|
|
|
- display: none;
|
|
|
-}
|
|
|
-.work-score-confirm-dialog .work-score-confirm-table .el-table__header-wrapper,
|
|
|
-.work-score-confirm-dialog .work-score-confirm-table .el-table__body-wrapper {
|
|
|
- overflow-x: hidden !important;
|
|
|
-}
|
|
|
-.work-score-confirm-dialog .work-score-confirm-table .el-scrollbar__bar.is-horizontal {
|
|
|
- display: none !important;
|
|
|
-}
|
|
|
-.work-score-confirm-dialog .work-score-confirm-table .el-table__header th {
|
|
|
- color: #000 !important;
|
|
|
- font-weight: 600;
|
|
|
- font-size: 15px;
|
|
|
- padding: 4px 0 !important;
|
|
|
- height: 32px !important;
|
|
|
-}
|
|
|
-.work-score-confirm-dialog .work-score-confirm-table .el-table__header th .cell {
|
|
|
- color: #000 !important;
|
|
|
- font-weight: 600;
|
|
|
- line-height: 22px;
|
|
|
- padding: 0 6px !important;
|
|
|
-}
|
|
|
-.work-score-confirm-dialog .work-score-confirm-table .el-table__body td {
|
|
|
- font-size: 15px;
|
|
|
- padding: 2px 0 !important;
|
|
|
- height: 32px !important;
|
|
|
-}
|
|
|
-.work-score-confirm-dialog .work-score-confirm-table .cell {
|
|
|
- line-height: 22px;
|
|
|
- padding: 0 6px !important;
|
|
|
-}
|
|
|
-.work-score-confirm-dialog .work-score-confirm-table .el-table__header th.is-center,
|
|
|
-.work-score-confirm-dialog .work-score-confirm-table .el-table__body td.is-center {
|
|
|
- text-align: center !important;
|
|
|
-}
|
|
|
-.work-score-confirm-dialog .work-score-confirm-table .el-table__header th.is-center .cell,
|
|
|
-.work-score-confirm-dialog .work-score-confirm-table .el-table__body td.is-center .cell {
|
|
|
- text-align: center !important;
|
|
|
- justify-content: center;
|
|
|
-}
|
|
|
-.work-score-confirm-dialog .work-score-confirm-table .el-table__header th.is-left,
|
|
|
-.work-score-confirm-dialog .work-score-confirm-table .el-table__body td.is-left {
|
|
|
- text-align: left !important;
|
|
|
-}
|
|
|
-.work-score-confirm-dialog .work-score-confirm-table .el-table__header th.is-left .cell,
|
|
|
-.work-score-confirm-dialog .work-score-confirm-table .el-table__body td.is-left .cell {
|
|
|
- text-align: left !important;
|
|
|
- justify-content: flex-start;
|
|
|
-}
|
|
|
-.work-score-confirm-dialog .work-score-confirm-over-cell {
|
|
|
- color: #f56c6c !important;
|
|
|
- font-weight: 600;
|
|
|
- font-size: 17px !important;
|
|
|
-}
|
|
|
-.work-score-confirm-dialog .el-dialog__footer {
|
|
|
- padding: 8px 12px 12px;
|
|
|
-}
|
|
|
-.work-score-confirm-dialog .el-dialog__footer .el-button {
|
|
|
- min-width: 100px;
|
|
|
- font-size: 15px;
|
|
|
-}
|
|
|
-.work-score-confirm-dialog .el-table__body tr:hover > td {
|
|
|
- background-color: var(--el-table-tr-bg-color, #fff) !important;
|
|
|
-}
|
|
|
-.work-score-confirm-dialog .el-table__body tr.el-table__row--striped:hover > td {
|
|
|
- background-color: var(--el-fill-color-lighter, #fafafa) !important;
|
|
|
-}
|
|
|
-
|
|
|
-/* 修改数量弹窗:超出未完成数时数量变红 */
|
|
|
-.edit-reporting-qty-dialog .edit-reporting-qty-over .el-input__inner,
|
|
|
-.edit-reporting-qty-dialog .edit-reporting-qty-over .el-input__wrapper input {
|
|
|
- color: #f56c6c !important;
|
|
|
- font-weight: 600;
|
|
|
-}
|
|
|
-
|
|
|
-.custom-warning-message {
|
|
|
- background: transparent !important;
|
|
|
- border: none !important;
|
|
|
- box-shadow: none !important;
|
|
|
- padding: 0 !important;
|
|
|
-}
|
|
|
-
|
|
|
-.custom-warning-message .el-message__content {
|
|
|
- padding: 0 !important;
|
|
|
- line-height: 1 !important;
|
|
|
-}
|
|
|
-
|
|
|
-.custom-warning-message .el-message__icon {
|
|
|
- display: none !important;
|
|
|
-}
|
|
|
-
|
|
|
-.custom-warning-message .el-message__closeBtn {
|
|
|
- display: none !important;
|
|
|
-}
|
|
|
-.gongfen-unified-tip.el-message {
|
|
|
- left: 50% !important;
|
|
|
- transform: translateX(-50%) !important;
|
|
|
- width: 520px !important;
|
|
|
- min-width: 520px !important;
|
|
|
- max-width: 520px !important;
|
|
|
-}
|
|
|
-
|
|
|
-.gy-detail-filter-popper {
|
|
|
- z-index: 10050 !important;
|
|
|
- pointer-events: auto;
|
|
|
- padding: 8px 10px !important;
|
|
|
-}
|
|
|
-
|
|
|
-.gy-detail-filter-popper .gy-detail-filter-panel {
|
|
|
- pointer-events: auto;
|
|
|
-}
|
|
|
-
|
|
|
-.gy-detail-filter-popper .gy-detail-filter-panel .el-checkbox {
|
|
|
- display: flex;
|
|
|
- margin-right: 0;
|
|
|
- margin-bottom: 6px;
|
|
|
-}
|
|
|
-
|
|
|
-/* 工分报工删除确认:图标顶对齐,工序信息左对齐 */
|
|
|
-.gongfen-delete-confirm .el-message-box__container {
|
|
|
- align-items: flex-start;
|
|
|
-}
|
|
|
-.gongfen-delete-confirm .el-message-box__status {
|
|
|
- top: 2px;
|
|
|
-}
|
|
|
-.gongfen-delete-confirm .el-message-box__message {
|
|
|
- padding-left: 0;
|
|
|
- text-align: left;
|
|
|
-}
|
|
|
-.gongfen-delete-confirm .gongfen-delete-msg {
|
|
|
- text-align: left;
|
|
|
- line-height: 1.7;
|
|
|
-}
|
|
|
-.gongfen-delete-confirm .gongfen-delete-msg__row {
|
|
|
- margin-top: 6px;
|
|
|
-}
|
|
|
-.gongfen-delete-confirm .gongfen-delete-msg__row strong {
|
|
|
- color: #f56c6c;
|
|
|
- font-weight: 600;
|
|
|
-}
|
|
|
-</style>
|
|
|
+<template>
|
|
|
+ <div>
|
|
|
+ <layout>
|
|
|
+ <layout-content >
|
|
|
+ <div class="gva-table-box">
|
|
|
+ <div style="display: flex; align-items: baseline; margin-bottom: 10px;">
|
|
|
+ <h1 style="margin: 0; margin-bottom: 10px;">{{_code}}工分报工</h1>
|
|
|
+ </div>
|
|
|
+ <div class="gongfen-toolbar-row">
|
|
|
+ <el-input
|
|
|
+ v-model="add_searchInfo"
|
|
|
+ placeholder="请扫描订单二维码"
|
|
|
+ @keyup.enter="add_onSubmit"
|
|
|
+ id="searchInput"
|
|
|
+ class="gongfen-order-search-input"
|
|
|
+ :disabled="workScoreDialogVisible"
|
|
|
+ />
|
|
|
+ <el-button type="primary" icon="search" class="gongfen-search-btn" :disabled="workScoreDialogVisible" @click="add_onSubmit">查询</el-button>
|
|
|
+ <span class="gongfen-toolbar-label">机台号</span>
|
|
|
+ <el-input v-model="add_formData['机台号']" readonly class="gongfen-toolbar-field" />
|
|
|
+ <span class="gongfen-toolbar-label">工序</span>
|
|
|
+ <el-input v-model="add_formData['工序']" readonly class="gongfen-toolbar-field" />
|
|
|
+ <span class="gongfen-toolbar-label">组别</span>
|
|
|
+ <el-input v-model="add_formData['组别']" readonly class="gongfen-toolbar-field" />
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 订单信息显示区域 -->
|
|
|
+ <div style="margin-top: 20px; margin-bottom: 20px; display: flex; justify-content: space-between; align-items: flex-start;">
|
|
|
+ <div style="flex: 1;">
|
|
|
+ <el-table :data="orderInfoList" style="width: 100%">
|
|
|
+ <el-table-column prop="订单编号" label="订单编号" width="110" />
|
|
|
+ <el-table-column prop="生产款号" label="生产款号" width="300" />
|
|
|
+ <el-table-column prop="款式" label="款式" width="220" />
|
|
|
+ <el-table-column prop="订单数量" label="订单数量" width="110" />
|
|
|
+
|
|
|
+ </el-table>
|
|
|
+ </div>
|
|
|
+ <div class="gongfen-order-actions">
|
|
|
+ <el-button type="success" icon="document" class="gongfen-work-score-btn" :disabled="!currentOrderNo" :loading="loadingProcess && !workScoreDialogVisible" @click="openWorkScoreDialog">工分报工</el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="gongfen-report-tabs">
|
|
|
+ <!-- 表格数据 -->
|
|
|
+ <el-tabs v-model="activeName" @tab-click="onGongfenTabClick">
|
|
|
+ <el-tab-pane label="当天报工记录" name="first">
|
|
|
+ <el-table
|
|
|
+ ref="gongfenHistoryTableRef"
|
|
|
+ class="gongfen-history-table"
|
|
|
+ style="width: 100%; height: 52vh"
|
|
|
+ tooltip-effect="dark"
|
|
|
+ :row-style="{ height: '38px' }"
|
|
|
+ :header-cell-style="gongfenHistoryHeaderCellStyle"
|
|
|
+ :cell-style="gongfenHistoryCellStyle"
|
|
|
+ :footer-cell-style="gongfenHistoryFooterCellStyle"
|
|
|
+ :header-row-style="{ height: '34px' }"
|
|
|
+ :data="filteredGongfenHistoryData"
|
|
|
+ border
|
|
|
+ row-key="ID"
|
|
|
+ size="small"
|
|
|
+ show-summary
|
|
|
+ scrollbar-always-on
|
|
|
+ :summary-method="getGongfenHistorySummaries"
|
|
|
+ highlight-current-row
|
|
|
+ show-overflow-tooltip
|
|
|
+ @row-click="tableRowClick"
|
|
|
+ >
|
|
|
+ <el-table-column align="center" label="小组" prop="sys_id" :width="90" show-overflow-tooltip />
|
|
|
+ <el-table-column align="center" label="订单编号" prop="work_order" :width="100" />
|
|
|
+ <el-table-column align="center" label="工序号" prop="process_code" :width="90" />
|
|
|
+ <el-table-column align="left" label="工序名称" prop="process_name" min-width="200" show-overflow-tooltip />
|
|
|
+ <el-table-column align="center" label="员工姓名" prop="staff_name" :width="120">
|
|
|
+ <template #header>
|
|
|
+ <div class="gongfen-col-header">
|
|
|
+ <span>员工姓名</span>
|
|
|
+ <el-popover trigger="click" placement="bottom-start" :width="180" :teleported="true" :z-index="10050" append-to-body popper-class="gy-detail-filter-popper">
|
|
|
+ <template #reference>
|
|
|
+ <span class="gy-detail-filter-btn" :class="{ 'is-active': isStaffNameFilterActive }" @click.stop>
|
|
|
+ <svg viewBox="0 0 1024 1024" width="14" height="14" aria-hidden="true"><path fill="currentColor" d="M880.1 154H143.9c-24.5 0-39.9 26.7-27.6 48L349 597.4V838c0 17.7 14.2 32 31.8 32h262.4c17.6 0 31.8-14.3 31.8-32V597.4L907.7 202c12.2-21.3-3.1-48-27.6-48z"/></svg>
|
|
|
+ </span>
|
|
|
+ </template>
|
|
|
+ <div class="gy-detail-filter-panel">
|
|
|
+ <div class="gy-detail-filter-options">
|
|
|
+ <el-checkbox-group v-model="staffNameFilter">
|
|
|
+ <el-checkbox v-for="item in staffNameFilterOptions" :key="item.value" :label="item.value">{{ item.text }}</el-checkbox>
|
|
|
+ </el-checkbox-group>
|
|
|
+ </div>
|
|
|
+ <div class="gy-detail-filter-actions">
|
|
|
+ <span class="gy-detail-filter-link" @click.stop="clearStaffNameFilter">取消全选</span>
|
|
|
+ <span class="gy-detail-filter-link" @click.stop="selectAllStaffNameFilter">全选</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-popover>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column align="center" label="数量" prop="number" :width="90" />
|
|
|
+ <el-table-column align="center" label="报工时间" prop="sys_rq" :width="180" show-overflow-tooltip />
|
|
|
+ <el-table-column align="center" label="操作" :width="160" fixed="right">
|
|
|
+ <template #default="scope">
|
|
|
+ <el-button type="primary" size="small" @click.stop="openEditReportingQty(scope.row)">修改</el-button>
|
|
|
+ <el-button type="danger" size="small" @click.stop="deleteReportingWork(scope.row)">删除</el-button>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+ </el-tab-pane>
|
|
|
+
|
|
|
+ <el-tab-pane label="工序产量核查" name="processProduction" lazy>
|
|
|
+ <ProcessProduction
|
|
|
+ ref="processProductionRef"
|
|
|
+ :key="`${currentOrderNo || 'empty'}-${processProductionRefreshKey}`"
|
|
|
+ :initial-workorder="currentOrderNo"
|
|
|
+ :initial-process="add_formData['工序']"
|
|
|
+ :initial-sys-id="add_formData['组别']"
|
|
|
+ embedded-in-tab
|
|
|
+ hide-amount-columns
|
|
|
+ />
|
|
|
+ </el-tab-pane>
|
|
|
+
|
|
|
+ <el-tab-pane label="订单资料附件" name="third">
|
|
|
+ <el-table ref="multipleTable"
|
|
|
+ :row-style="{ height: '30px' }"
|
|
|
+ :cell-style="{ padding: '0px' }" :header-row-style="{ height: '30px' }"
|
|
|
+ :header-cell-style="{ padding: '0px' }"
|
|
|
+ :show-overflow-tooltip="true"
|
|
|
+ :cell-class-name="planUsageCellClass"
|
|
|
+ highlight-current-row="true"
|
|
|
+ @row-dblclick="gdbomupdateCompanyFunc"
|
|
|
+ style="width: 100%;height: 36vh" border tooltip-effect="dark" :data="ddtableData" row-key="ID"
|
|
|
+ @selection-change="fjSelectionChange">
|
|
|
+ <el-table-column align="left" label="关联编号" prop="关联编号" width="115"/>
|
|
|
+ <el-table-column align="left" label="备注" prop="附件备注" width="110"/>
|
|
|
+ <el-table-column align="left" label="文件类型" prop="附件类型" width="100"/>
|
|
|
+ <el-table-column align="left" label="建档时间" prop="sys_rq" width="160"/>
|
|
|
+ <el-table-column align="left" label="建档用户" prop="sys_id" width="200"/>
|
|
|
+ <el-table-column align="left" label="操作"width="100"fixed="right">
|
|
|
+ <template #default="scope">
|
|
|
+ <el-button type="success" size="small" :data="ddtableData" @click="showPdf(scope.row)" >PDF预览</el-button>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+ </el-tab-pane>
|
|
|
+
|
|
|
+
|
|
|
+ <el-tab-pane label="技术附件" name="fourth">
|
|
|
+ <el-table ref="multipleTable"
|
|
|
+ :row-style="{ height: '30px' }"
|
|
|
+ :cell-style="{ padding: '0px' }" :header-row-style="{ height: '30px' }"
|
|
|
+ :header-cell-style="{ padding: '0px' }"
|
|
|
+ :show-overflow-tooltip="true"
|
|
|
+ :cell-class-name="planUsageCellClass"
|
|
|
+ highlight-current-row="true"
|
|
|
+ @row-dblclick="ExcelShow"
|
|
|
+ style="width: 100%;height: 36vh" border tooltip-effect="dark" :data="jstableData" row-key="ID"
|
|
|
+ @selection-change="fjSelectionChange">
|
|
|
+ <el-table-column align="left" label="关联编号" prop="关联编号" width="115"/>
|
|
|
+ <el-table-column align="left" label="备注" prop="附件备注" width="110"/>
|
|
|
+ <el-table-column align="left" label="文件类型" prop="附件类型" width="100"/>
|
|
|
+ <el-table-column align="left" label="建档时间" prop="sys_rq" width="160"/>
|
|
|
+ <el-table-column align="left" label="建档用户" prop="sys_id" width="200"/>
|
|
|
+ <el-table-column align="left" label="操作"width="100"fixed="right">
|
|
|
+ <template #default="scope">
|
|
|
+ <el-button type="success" size="small" :data="ddtableData" @click="showPdf(scope.row)" >PDF预览</el-button>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+ </el-tab-pane>
|
|
|
+ </el-tabs>
|
|
|
+
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 是否订单尾包确认弹窗 -->
|
|
|
+ <el-dialog v-model="DialogVisible" title="是否订单尾包" destroy-on-close width="30%" style="top: 20%;">
|
|
|
+ <h3>请再次确认是否该订单产品已全部报工,该批为订单尾包?</h3>
|
|
|
+ <div class="dialog-footer" style="text-align: right;">
|
|
|
+ <el-button @click="confirmDialogVisible">取消</el-button>
|
|
|
+ <el-button type="primary" @click="handleConfirm">确认</el-button>
|
|
|
+ </div>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
+ <!-- 工分报工对话框 -->
|
|
|
+ <el-dialog
|
|
|
+ v-model="workScoreDialogVisible"
|
|
|
+ class="work-score-dialog"
|
|
|
+ width="100vw"
|
|
|
+ height="100vh"
|
|
|
+ :show-close="false"
|
|
|
+ :modal="false"
|
|
|
+ :close-on-click-modal="false"
|
|
|
+ style="padding: 0; margin: 0; overflow: hidden; background: white;"
|
|
|
+ >
|
|
|
+ <div class="work-score-dialog-inner">
|
|
|
+ <!-- 订单信息 + 关闭 -->
|
|
|
+ <div class="work-score-order-header">
|
|
|
+ <div v-if="orderInfoList.length > 0" class="work-score-order-bar">
|
|
|
+ <p><strong>组别:</strong> {{ add_formData['组别'] }}</p>
|
|
|
+ <p><strong>订单编号:</strong> {{ orderInfoList[0]['订单编号'] }}</p>
|
|
|
+ <p><strong>生产款号:</strong> {{ orderInfoList[0]['生产款号'] }}</p>
|
|
|
+ <p><strong>款式:</strong> {{ orderInfoList[0]['款式'] }}</p>
|
|
|
+ <p><strong>订单数量:</strong> {{ orderInfoList[0]['订单数量'] }}</p>
|
|
|
+ </div>
|
|
|
+ <el-button type="danger" class="work-score-close-btn" @click="workScoreDialogVisible = false">关闭</el-button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 下方:左右分栏 -->
|
|
|
+ <div class="work-score-main-body">
|
|
|
+ <!-- 左侧:部件列表(所有工序统一) -->
|
|
|
+ <div v-if="processParts.length > 0" class="work-score-sidebar">
|
|
|
+ <div class="work-score-content-header">
|
|
|
+ <h3 class="work-score-section-title">部件</h3>
|
|
|
+ </div>
|
|
|
+ <div class="part-list work-score-part-list">
|
|
|
+ <div
|
|
|
+ v-for="(part, index) in processParts"
|
|
|
+ :key="part['部件编号']"
|
|
|
+ class="part-item"
|
|
|
+ :class="{ selected: selectedPartIndex === index }"
|
|
|
+ @click="selectPart(index)"
|
|
|
+ >
|
|
|
+ <div class="part-info">
|
|
|
+ <div class="part-name">{{ part['部件编号'] }}-{{ part['部件名称'] }}</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 右侧:上报人员 + 工艺列表 -->
|
|
|
+ <div class="work-score-right-panel">
|
|
|
+ <!-- 上报人员选择 -->
|
|
|
+ <div class="work-score-employee-section">
|
|
|
+ <div class="work-score-content-header work-score-step-header">
|
|
|
+ <p class="work-score-step-text">第一步:请先选择<strong>人员</strong></p>
|
|
|
+ </div>
|
|
|
+ <div class="employee-grid work-score-employee-grid">
|
|
|
+ <div
|
|
|
+ v-for="employee in employees"
|
|
|
+ :key="employee['员工编号']"
|
|
|
+ class="employee-card"
|
|
|
+ :class="{ selected: selectedEmployee === employee['员工编号'] }"
|
|
|
+ @click="selectEmployee(employee)"
|
|
|
+ draggable="true"
|
|
|
+ @dragstart="onDragStart($event, employee)"
|
|
|
+ >
|
|
|
+ <div class="employee-avatar" :style="{ backgroundColor: getAvatarColor(employee['员工编号']) }">
|
|
|
+ {{ employee['员工姓名'].charAt(0) }}
|
|
|
+ </div>
|
|
|
+ <div class="employee-name">{{ employee['员工姓名'] }}</div>
|
|
|
+ <div class="employee-id">{{ employee['员工编号'] }}</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 工艺列表 -->
|
|
|
+ <div class="work-score-process-area">
|
|
|
+ <div v-if="selectedPartIndex !== -1 && partProcesses[selectedPartIndex] && partProcesses[selectedPartIndex].length > 0" class="work-score-process-block">
|
|
|
+ <div class="work-score-process-toolbar work-score-process-toolbar--simple">
|
|
|
+ <div class="work-score-toolbar-guide">
|
|
|
+ <div class="work-score-quick-row work-score-step-row">
|
|
|
+ <span class="work-score-step-text">第二步:找到工序名称,填<strong>完工数量</strong></span>
|
|
|
+ <!-- <el-input
|
|
|
+ v-model.number="batchQuantity"
|
|
|
+ type="number"
|
|
|
+ :placeholder="selectedEmployee ? '如 20' : '先选人'"
|
|
|
+ class="work-score-batch-qty-input"
|
|
|
+ :disabled="!selectedEmployee"
|
|
|
+ /> -->
|
|
|
+ <el-button type="primary" class="work-score-submit-btn" @click="submitWorkScore">提交报工</el-button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div ref="processTableWrapRef" class="work-score-process-table-wrap">
|
|
|
+ <el-table
|
|
|
+ ref="processTableRef"
|
|
|
+ :data="partProcesses[selectedPartIndex]"
|
|
|
+ :height="processTableHeight"
|
|
|
+ scrollbar-always-on
|
|
|
+ highlight-current-row
|
|
|
+ :row-class-name="processTableRowClassName"
|
|
|
+ class="work-score-process-table"
|
|
|
+ style="width: 100%;"
|
|
|
+ @row-click="onProcessTableRowClick"
|
|
|
+ >
|
|
|
+ <el-table-column prop="工艺编号" label="工序号" width="72" align="center" />
|
|
|
+ <el-table-column prop="工艺名称" label="工序名称" min-width="240" />
|
|
|
+ <el-table-column prop="本组完成数" label="本组完成数" min-width="88" align="center" />
|
|
|
+ <el-table-column prop="累计完成数" label="累计完成数" min-width="70" align="center" />
|
|
|
+ <el-table-column prop="未完成数" label="未完成数" min-width="60" align="center" />
|
|
|
+ <el-table-column label="完工人员" width="120">
|
|
|
+ <template #default="scope">
|
|
|
+ <div v-if="getReportingData(selectedPartIndex, scope.$index).staffList">
|
|
|
+ <div v-for="(staff, staffIndex) in getReportingData(selectedPartIndex, scope.$index).staffList" :key="staffIndex" class="work-score-staff-row">
|
|
|
+ <el-input
|
|
|
+ v-model="staff.staff_name"
|
|
|
+ class="work-score-staff-input"
|
|
|
+ readonly
|
|
|
+ :disabled="isReportingFillDisabled(selectedPartIndex, scope.$index, staffIndex)"
|
|
|
+ @focus="highlightProcessRow(scope.row)"
|
|
|
+ @click="fillSelectedEmployee(staff, selectedPartIndex, scope.$index, staffIndex); highlightProcessRow(scope.row)"
|
|
|
+ @drop="onDrop($event, selectedPartIndex, scope.$index, staffIndex)"
|
|
|
+ @dragover="onDragOver($event)"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <el-input
|
|
|
+ v-else
|
|
|
+ v-model="getReportingData(selectedPartIndex, scope.$index).staff_name"
|
|
|
+ class="work-score-staff-input"
|
|
|
+ readonly
|
|
|
+ :disabled="isReportingFillDisabled(selectedPartIndex, scope.$index)"
|
|
|
+ @focus="highlightProcessRow(scope.row)"
|
|
|
+ @click="fillSelectedEmployee(getReportingData(selectedPartIndex, scope.$index), selectedPartIndex, scope.$index); highlightProcessRow(scope.row)"
|
|
|
+ @drop="onDrop($event, selectedPartIndex, scope.$index)"
|
|
|
+ @dragover="onDragOver($event)"
|
|
|
+ />
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="完工数量" width="110">
|
|
|
+ <template #default="scope">
|
|
|
+ <div v-if="getReportingData(selectedPartIndex, scope.$index).staffList">
|
|
|
+ <div v-for="(staff, staffIndex) in getReportingData(selectedPartIndex, scope.$index).staffList" :key="staffIndex" class="work-score-staff-row">
|
|
|
+ <el-input
|
|
|
+ :model-value="staff.number"
|
|
|
+ inputmode="numeric"
|
|
|
+ class="work-score-qty-input"
|
|
|
+ :class="{ 'work-score-qty-over': isQtyOverUnfinished(selectedPartIndex, scope.$index) }"
|
|
|
+ :disabled="isReportingFillDisabled(selectedPartIndex, scope.$index, staffIndex)"
|
|
|
+ @focus="highlightProcessRow(scope.row)"
|
|
|
+ @click="highlightProcessRow(scope.row)"
|
|
|
+ @update:model-value="(v) => onQtyInput(selectedPartIndex, scope.$index, staffIndex, v)"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <el-input
|
|
|
+ v-else
|
|
|
+ :model-value="getReportingData(selectedPartIndex, scope.$index).number"
|
|
|
+ inputmode="numeric"
|
|
|
+ class="work-score-qty-input"
|
|
|
+ :class="{ 'work-score-qty-over': isQtyOverUnfinished(selectedPartIndex, scope.$index) }"
|
|
|
+ :disabled="isReportingFillDisabled(selectedPartIndex, scope.$index)"
|
|
|
+ @focus="highlightProcessRow(scope.row)"
|
|
|
+ @click="highlightProcessRow(scope.row)"
|
|
|
+ @update:model-value="(v) => onQtyInput(selectedPartIndex, scope.$index, null, v)"
|
|
|
+ />
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="操作" width="110" align="center">
|
|
|
+ <template #default="scope">
|
|
|
+ <div class="work-score-row-actions">
|
|
|
+ <!-- <el-button
|
|
|
+ type="primary"
|
|
|
+ size="small"
|
|
|
+ class="work-score-fill-row-btn"
|
|
|
+ :disabled="!selectedEmployee || batchQuantity === '' || batchQuantity == null"
|
|
|
+ @click="fillRowPerson(selectedPartIndex, scope.$index)"
|
|
|
+ >填入</el-button> -->
|
|
|
+ <el-button size="small" plain class="work-score-add-person-btn" @click="addPerson(selectedPartIndex, scope.$index)">加一人</el-button>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div v-else-if="loadingProcess" class="work-score-process-empty">
|
|
|
+ <p style="margin-top: 10px;">加载中...</p>
|
|
|
+ </div>
|
|
|
+ <div v-else class="work-score-process-empty work-score-process-empty--muted">
|
|
|
+ <p style="font-size: 24px;">暂无数据</p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
+ <!-- 工分报工确认弹窗 -->
|
|
|
+ <el-dialog
|
|
|
+ v-model="workScoreConfirmVisible"
|
|
|
+ title="确认报工"
|
|
|
+ width="1040px"
|
|
|
+ top="8vh"
|
|
|
+ append-to-body
|
|
|
+ destroy-on-close
|
|
|
+ class="work-score-confirm-dialog"
|
|
|
+ :close-on-click-modal="false"
|
|
|
+ >
|
|
|
+ <p class="work-score-confirm-tip">请核对以下报工数据,确认无误后再提交</p>
|
|
|
+ <el-table
|
|
|
+ :data="workScoreConfirmRows"
|
|
|
+ border
|
|
|
+ stripe
|
|
|
+ height="512"
|
|
|
+ :span-method="workScoreConfirmSpanMethod"
|
|
|
+ :cell-class-name="workScoreConfirmCellClass"
|
|
|
+ class="work-score-confirm-table"
|
|
|
+ style="width: 100%"
|
|
|
+ >
|
|
|
+ <el-table-column label="部件" prop="部件" width="88" align="center" show-overflow-tooltip />
|
|
|
+ <el-table-column label="工序号" prop="工序编号" width="68" align="center" />
|
|
|
+ <el-table-column label="工序名称" prop="工序名称" min-width="150" align="left" show-overflow-tooltip />
|
|
|
+ <el-table-column label="本组完成数" prop="本组完成数" width="96" align="center" />
|
|
|
+ <el-table-column label="累计完成数" prop="累计完成数" width="96" align="center" />
|
|
|
+ <el-table-column label="未完成数" prop="未完成数量" width="88" align="center" />
|
|
|
+ <el-table-column label="完工人员" prop="员工姓名" width="88" align="center" />
|
|
|
+ <el-table-column label="完工数量" prop="完工数量" width="88" align="center" />
|
|
|
+ <el-table-column label="超出数量" prop="超出数量" width="88" align="center" />
|
|
|
+ </el-table>
|
|
|
+ <template #footer>
|
|
|
+ <el-button @click="workScoreConfirmVisible = false">返回修改</el-button>
|
|
|
+ <el-button type="primary" :loading="workScoreSubmitting" @click="confirmSubmitWorkScore">确认报工</el-button>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
+ <!-- 当天报工记录:修改数量 -->
|
|
|
+ <el-dialog
|
|
|
+ v-model="editReportingQtyVisible"
|
|
|
+ title="修改数量"
|
|
|
+ width="420px"
|
|
|
+ top="32vh"
|
|
|
+ append-to-body
|
|
|
+ destroy-on-close
|
|
|
+ :close-on-click-modal="false"
|
|
|
+ class="edit-reporting-qty-dialog"
|
|
|
+ @opened="focusEditReportingQtyInput"
|
|
|
+ >
|
|
|
+ <el-form label-width="88px">
|
|
|
+ <el-form-item label="工序号">
|
|
|
+ <el-input :model-value="editReportingQtyForm.process_code" disabled />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="工序名称">
|
|
|
+ <el-input :model-value="editReportingQtyForm.process_name" disabled />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="未完成数">
|
|
|
+ <el-input :model-value="editReportingQtyForm.unfinished" disabled />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="数量" required>
|
|
|
+ <el-input
|
|
|
+ ref="editReportingQtyInputRef"
|
|
|
+ :model-value="editReportingQtyForm.number"
|
|
|
+ inputmode="numeric"
|
|
|
+ maxlength="5"
|
|
|
+ placeholder="请输入修正后的数量"
|
|
|
+ :class="{ 'edit-reporting-qty-over': isEditReportingQtyOver }"
|
|
|
+ @update:model-value="(v) => { editReportingQtyForm.number = filterQtyDigits(v) }"
|
|
|
+ @keyup.enter="submitEditReportingQty"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ <template #footer>
|
|
|
+ <el-button @click="editReportingQtyVisible = false">取消</el-button>
|
|
|
+ <el-button type="primary" :loading="editReportingQtyLoading" @click="submitEditReportingQty">确定</el-button>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
+ </layout-content>
|
|
|
+ </layout>
|
|
|
+ <SubOrderPage ref="SubOrderPageRef" />
|
|
|
+ <!-- 子订单详情页 -->
|
|
|
+ <luckyexcelPage ref="luckyexcelPageRef" />
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+<script>
|
|
|
+export default {
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ currentTable: '', // 当前展示的表格
|
|
|
+ activeName: 'first',
|
|
|
+ dialogFormVisible: false,
|
|
|
+ formDataTest: {
|
|
|
+ imageUrl: '' // 添加一个字段来保存上传的图片路径
|
|
|
+ },
|
|
|
+ rule: {} // 初始化rule对象
|
|
|
+ };
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ handleKeyDown(event, prevId, currentId, nextId) {
|
|
|
+ const currentElement = document.getElementById(currentId);
|
|
|
+ const isEmpty = currentElement.value === '';
|
|
|
+ const atStart = currentElement.selectionStart === 0;
|
|
|
+ const atEnd = currentElement.selectionStart === currentElement.value.length;
|
|
|
+ switch (event.keyCode) {
|
|
|
+ case 13: // Enter
|
|
|
+ case 40: // 向下箭头
|
|
|
+ if (nextId) {
|
|
|
+ document.getElementById(nextId).focus();
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 38: // 向上箭头
|
|
|
+ if (prevId) {
|
|
|
+ document.getElementById(prevId).focus();
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 8: // 删除键
|
|
|
+ if (prevId && (isEmpty || atStart)) {
|
|
|
+ document.getElementById(prevId).focus();
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 37: // 向左箭头
|
|
|
+ if (prevId && atStart) {
|
|
|
+ document.getElementById(prevId).focus();
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 39: // 向右箭头
|
|
|
+ if (nextId && atEnd) {
|
|
|
+ document.getElementById(nextId).focus();
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ },
|
|
|
+};
|
|
|
+</script>
|
|
|
+<script setup>
|
|
|
+// 全量引入格式化工具 请按需保留
|
|
|
+import $script from 'scriptjs'
|
|
|
+import $ from 'jquery';
|
|
|
+import LuckyExcel from 'luckyexcel';
|
|
|
+import { Layout, LayoutSider, LayoutContent } from '@arco-design/web-vue';
|
|
|
+import {ref, reactive, computed, watch, nextTick, onUnmounted} from 'vue';
|
|
|
+import {getSpotList,getInfo,OrderAttachments,WorkOrderList,DeleteReportingWork,UpdateReportingWork} from '@/api/mes/job';
|
|
|
+import {getMac,getMajorprocessAndPerson,GetOrderProcess,GetCarProcess,ReportingWork,GetReportingWorkRecord} from '@/api/jixiaoguanli/baogong'
|
|
|
+import {getMachineMac} from '@/api/jixiaoguanli/jitairibaobiao'
|
|
|
+import {ElMessage,ElMessageBox} from "element-plus";
|
|
|
+import luckyexcelPage from '@/view/yunyin/shengchanguanli/components/luckyexcel.vue';
|
|
|
+import SubOrderPage from '@/view/yunyin/shengchanguanli/components/SubOrder.vue';
|
|
|
+import ProcessProduction from '@/view/SalaryManage/ProcessProduction.vue';
|
|
|
+import { useUserStore } from '@/pinia/modules/user';
|
|
|
+defineOptions({name: 'Company'})
|
|
|
+const path = `${import.meta.env.VITE_BASE_PATH}:${import.meta.env.VITE_UPLOADS_PORT}`
|
|
|
+console.log(path)
|
|
|
+//定义跳转页面
|
|
|
+const SubOrderPageRef = ref()//子订单详情页
|
|
|
+const printPageRef = ref()//打印预览
|
|
|
+const luckyexcelPageRef = ref()//pdf预览
|
|
|
+//获取登录用户信息
|
|
|
+const userStore = useUserStore()
|
|
|
+const _username = ref('')
|
|
|
+_username.value = userStore.userInfo.userName + '/' + userStore.userInfo.nickName
|
|
|
+console.log('获取用户名称',_username.value)
|
|
|
+//全局获取当前日期
|
|
|
+const today = new Date();
|
|
|
+const year = today.getFullYear();
|
|
|
+const month = String(today.getMonth() + 1).padStart(2, '0'); // 月份从 0 开始,需要补零
|
|
|
+const day = String(today.getDate()).padStart(2, '0');
|
|
|
+const hours = String(today.getHours()).padStart(2, '0');
|
|
|
+const minutes = String(today.getMinutes()).padStart(2, '0');
|
|
|
+const seconds = String(today.getSeconds()).padStart(2, '0');
|
|
|
+const currentDate = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
|
|
+const currentDates = `${year}-${month}-${day}`;
|
|
|
+const add_searchInfo = ref('')
|
|
|
+const gongfenHistoryData = ref([])
|
|
|
+const gongfenHistoryTableRef = ref()
|
|
|
+const staffNameFilter = ref([])
|
|
|
+const currentOrderNo = ref('')
|
|
|
+
|
|
|
+/** 当天报工记录:仅当前查询订单 */
|
|
|
+const orderScopedGongfenHistoryData = computed(() => {
|
|
|
+ const list = gongfenHistoryData.value || []
|
|
|
+ const orderNo = String(currentOrderNo.value || '').trim()
|
|
|
+ if (!orderNo) return []
|
|
|
+ return list.filter((row) => {
|
|
|
+ const rowOrder = String(row.work_order ?? row['订单编号'] ?? '').trim()
|
|
|
+ return rowOrder === orderNo
|
|
|
+ })
|
|
|
+})
|
|
|
+
|
|
|
+const staffNameFilterOptions = computed(() => {
|
|
|
+ const names = [...new Set(
|
|
|
+ (orderScopedGongfenHistoryData.value || [])
|
|
|
+ .map(item => String(item.staff_name || '').trim())
|
|
|
+ .filter(Boolean)
|
|
|
+ )]
|
|
|
+ return names.map(name => ({ text: name, value: name }))
|
|
|
+})
|
|
|
+
|
|
|
+const isStaffNameFilterActive = computed(() => {
|
|
|
+ const allValues = staffNameFilterOptions.value.map(item => item.value)
|
|
|
+ const selected = staffNameFilter.value
|
|
|
+ if (!allValues.length) return false
|
|
|
+ return selected.length < allValues.length
|
|
|
+})
|
|
|
+
|
|
|
+const selectAllStaffNameFilter = () => {
|
|
|
+ staffNameFilter.value = staffNameFilterOptions.value.map(item => item.value)
|
|
|
+}
|
|
|
+
|
|
|
+const clearStaffNameFilter = () => {
|
|
|
+ staffNameFilter.value = []
|
|
|
+}
|
|
|
+
|
|
|
+const syncStaffNameFilterAfterDataChange = () => {
|
|
|
+ const allValues = staffNameFilterOptions.value.map(item => item.value)
|
|
|
+ const selected = staffNameFilter.value
|
|
|
+ if (!selected.length) {
|
|
|
+ staffNameFilter.value = [...allValues]
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const wasAllSelected = allValues.length > 0 && allValues.every(v => selected.includes(v))
|
|
|
+ if (wasAllSelected) {
|
|
|
+ staffNameFilter.value = [...allValues]
|
|
|
+ return
|
|
|
+ }
|
|
|
+ staffNameFilter.value = selected.filter(v => allValues.includes(v))
|
|
|
+}
|
|
|
+
|
|
|
+const filteredGongfenHistoryData = computed(() => {
|
|
|
+ const list = orderScopedGongfenHistoryData.value || []
|
|
|
+ const options = staffNameFilterOptions.value
|
|
|
+ const selected = staffNameFilter.value
|
|
|
+ if (!selected.length) return []
|
|
|
+ if (!options.length || selected.length >= options.length) return list
|
|
|
+ const set = new Set(selected)
|
|
|
+ return list.filter(row => set.has(String(row.staff_name || '').trim()))
|
|
|
+})
|
|
|
+
|
|
|
+watch(
|
|
|
+ () => [gongfenHistoryData.value, currentOrderNo.value],
|
|
|
+ () => {
|
|
|
+ syncStaffNameFilterAfterDataChange()
|
|
|
+ },
|
|
|
+ { deep: true }
|
|
|
+)
|
|
|
+
|
|
|
+const relayoutGongfenHistoryTable = () => {
|
|
|
+ nextTick(() => {
|
|
|
+ gongfenHistoryTableRef.value?.doLayout?.()
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+watch(filteredGongfenHistoryData, relayoutGongfenHistoryTable)
|
|
|
+watch(staffNameFilter, relayoutGongfenHistoryTable)
|
|
|
+
|
|
|
+const gongfenHistoryHeaderCellStyle = ({ column }) => ({
|
|
|
+ padding: '6px 0',
|
|
|
+ fontSize: '16px',
|
|
|
+ textAlign: column?.property === 'process_name' ? 'left' : 'center',
|
|
|
+})
|
|
|
+
|
|
|
+const gongfenHistoryCellStyle = ({ column }) => ({
|
|
|
+ padding: '6px 0',
|
|
|
+ fontSize: '16px',
|
|
|
+ textAlign: column.property === 'process_name' ? 'left' : 'center',
|
|
|
+})
|
|
|
+
|
|
|
+const gongfenHistoryFooterCellStyle = ({ column }) => ({
|
|
|
+ padding: '6px 0',
|
|
|
+ fontSize: '16px',
|
|
|
+ fontWeight: '600',
|
|
|
+ background: '#fafafa',
|
|
|
+ textAlign: column?.property === 'process_name' ? 'left' : 'center',
|
|
|
+})
|
|
|
+
|
|
|
+const getGongfenHistorySummaries = ({ columns, data }) => {
|
|
|
+ const sums = []
|
|
|
+ columns.forEach((column, index) => {
|
|
|
+ if (column.property === 'process_code') {
|
|
|
+ sums[index] = '合计'
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (column.property === 'number') {
|
|
|
+ sums[index] = data.reduce((total, row) => {
|
|
|
+ const val = Number(row.number)
|
|
|
+ return total + (Number.isNaN(val) ? 0 : val)
|
|
|
+ }, 0)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ sums[index] = ''
|
|
|
+ })
|
|
|
+ return sums
|
|
|
+}
|
|
|
+
|
|
|
+//全局获取code,接口接收code
|
|
|
+const _code = ref('裁剪')
|
|
|
+//全局接口接受的物理地址
|
|
|
+const Machine = ref('')
|
|
|
+/** 机台 MAC 映射是否就绪;失败时禁止报工,避免静默落入测试机台 */
|
|
|
+const machineReady = ref(false)
|
|
|
+//全局获取UniqId
|
|
|
+const UniqId = ref('')
|
|
|
+
|
|
|
+// 员工数据
|
|
|
+const employees = ref([])
|
|
|
+const selectedEmployee = ref('')
|
|
|
+
|
|
|
+//物理地址获取机台编号
|
|
|
+const getMachineMacdata = async () => {
|
|
|
+ try {
|
|
|
+ const data = await getMachineMac({ sys_sbID: Machine.value })
|
|
|
+ if (data.data === null) {
|
|
|
+ machineReady.value = false
|
|
|
+ add_formData['机台号'] = ''
|
|
|
+ add_formData['工序'] = ''
|
|
|
+ add_formData['组别'] = ''
|
|
|
+ add_formData['人员'] = ''
|
|
|
+ employees.value = []
|
|
|
+ return
|
|
|
+ }
|
|
|
+ add_formData['机台号'] = data.data['机台号']
|
|
|
+ add_formData['工序'] = data.data['生产工序']
|
|
|
+ add_formData['组别'] = data.data['组别']
|
|
|
+ add_formData['人员'] = data.data['组长']
|
|
|
+ _code.value = data.data['生产工序']
|
|
|
+ machineReady.value = true
|
|
|
+ getEmployeeData(data.data['机台号'])
|
|
|
+ setTimeout(() => {
|
|
|
+ const inputElement = document.getElementById('searchInput')
|
|
|
+ if (inputElement) {
|
|
|
+ inputElement.focus()
|
|
|
+ }
|
|
|
+ }, 100)
|
|
|
+ } catch (error) {
|
|
|
+ console.error(error)
|
|
|
+ machineReady.value = false
|
|
|
+ add_formData['机台号'] = ''
|
|
|
+ add_formData['工序'] = ''
|
|
|
+ add_formData['组别'] = ''
|
|
|
+ add_formData['人员'] = ''
|
|
|
+ employees.value = []
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 获取员工数据
|
|
|
+const getEmployeeData = async (machineId) => {
|
|
|
+ try {
|
|
|
+ const data = await getMajorprocessAndPerson({ machine: machineId || 'CF01' })
|
|
|
+ if (data.code === 0 && data.data) {
|
|
|
+ employees.value = data.data.person || []
|
|
|
+ // 不默认选中人员,工艺表「报工人员」列为空,由用户点击上方人员或拖入填写
|
|
|
+ selectedEmployee.value = ''
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('获取员工数据失败:', error)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 选择员工
|
|
|
+const selectEmployee = (employee) => {
|
|
|
+ selectedEmployee.value = employee.员工编号
|
|
|
+ add_formData['人员'] = employee.员工姓名
|
|
|
+}
|
|
|
+
|
|
|
+const createEmptyReportingItem = () => ({
|
|
|
+ staff_name: '',
|
|
|
+ staff_no: '',
|
|
|
+ number: '',
|
|
|
+})
|
|
|
+
|
|
|
+const extractListFromResponse = (data) => {
|
|
|
+ if (!data) return []
|
|
|
+ if (Array.isArray(data)) return data
|
|
|
+ if (typeof data === 'object') {
|
|
|
+ for (const key of ['list', 'process_list', 'processes', 'rows', 'data']) {
|
|
|
+ if (Array.isArray(data[key])) return data[key]
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return []
|
|
|
+}
|
|
|
+
|
|
|
+const isPartRow = (row) => {
|
|
|
+ if (!row || typeof row !== 'object') return false
|
|
|
+ const hasPart = !!(row['部件编号'] || row.part_code || row['部件名称'] || row.part_name)
|
|
|
+ const hasProcess = !!(row['工艺编号'] || row['工序编号'] || row.process_code || row.gy_code || row['工艺名称'] || row['工序名称'] || row.process_name || row.gy_name)
|
|
|
+ return hasPart && !hasProcess
|
|
|
+}
|
|
|
+
|
|
|
+const getRowMajorProcess = (row) => String(
|
|
|
+ row?.['大工序'] ?? row?.['生产工序'] ?? row?.big_process ?? row?.['大工艺'] ?? ''
|
|
|
+).trim()
|
|
|
+
|
|
|
+const normalizeWorkScoreProcessRow = (row) => {
|
|
|
+ if (!row || typeof row !== 'object') return null
|
|
|
+ if (isPartRow(row)) return null
|
|
|
+
|
|
|
+ const 工艺编号 = row['工艺编号'] ?? row['工序编号'] ?? row.process_code ?? row.gy_code ?? row.gy_sort ?? ''
|
|
|
+ const 工艺名称 = row['工艺名称'] ?? row['工序名称'] ?? row.process_name ?? row.gy_name ?? ''
|
|
|
+ if (!String(工艺编号).trim() && !String(工艺名称).trim()) return null
|
|
|
+
|
|
|
+ return {
|
|
|
+ ...row,
|
|
|
+ 工艺编号,
|
|
|
+ 工艺名称,
|
|
|
+ 本组完成数: row['本组完成数'] ?? row.group_complete ?? row['本组完成'] ?? '',
|
|
|
+ 累计完成数: row['累计完成数'] ?? row.total_complete ?? '',
|
|
|
+ 未完成数: row['未完成数'] ?? row.unfinished ?? '',
|
|
|
+ 标准分钟: row['标准分钟'] ?? row.standard_minutes ?? row['标准工时'] ?? row.standard_hour ?? '',
|
|
|
+ 标准工时: row['标准工时'] ?? row.standard_hour ?? row['标准分钟'] ?? row.standard_minutes ?? '',
|
|
|
+ 标准工分: row['标准工分'] ?? row.standard_score ?? row['标准公分'] ?? '',
|
|
|
+ 金额: row['金额'] ?? row.money ?? '',
|
|
|
+ 系数: row['系数'] ?? row.coefficient ?? row.difficulty_coef ?? row['难度系数'] ?? '',
|
|
|
+ 大工序: getRowMajorProcess(row),
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const normalizeWorkScoreProcessList = (list) => {
|
|
|
+ return extractListFromResponse(list)
|
|
|
+ .map(normalizeWorkScoreProcessRow)
|
|
|
+ .filter(Boolean)
|
|
|
+}
|
|
|
+
|
|
|
+const resolvePartCode = (part) => String(part?.['部件编号'] ?? part?.part_code ?? '').trim()
|
|
|
+
|
|
|
+const setPartProcessData = (index, processList) => {
|
|
|
+ const nextPartProcesses = partProcesses.value.slice()
|
|
|
+ nextPartProcesses[index] = processList
|
|
|
+ partProcesses.value = nextPartProcesses
|
|
|
+
|
|
|
+ const nextReportingData = reportingData.value.slice()
|
|
|
+ nextReportingData[index] = processList.map(() => createEmptyReportingItem())
|
|
|
+ reportingData.value = nextReportingData
|
|
|
+}
|
|
|
+
|
|
|
+const refreshProcessTableLayout = () => {
|
|
|
+ nextTick(() => {
|
|
|
+ updateProcessTableHeight()
|
|
|
+ attachProcessTableResizeObserver()
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+//工分报工对话框
|
|
|
+const workScoreDialogVisible = ref(false);
|
|
|
+const workScoreConfirmVisible = ref(false);
|
|
|
+const workScoreConfirmRows = ref([]);
|
|
|
+const pendingReportData = ref([]);
|
|
|
+const workScoreSubmitting = ref(false);
|
|
|
+const processTableWrapRef = ref(null);
|
|
|
+const processTableRef = ref(null);
|
|
|
+const processTableHeight = ref(320);
|
|
|
+/** 当前点选的工艺行(用于整行粉色 + 输入框同色) */
|
|
|
+const activeProcessRow = ref(null);
|
|
|
+const batchQuantity = ref('');
|
|
|
+let processTableResizeObserver = null;
|
|
|
+
|
|
|
+const updateProcessTableHeight = () => {
|
|
|
+ nextTick(() => {
|
|
|
+ requestAnimationFrame(() => {
|
|
|
+ const height = processTableWrapRef.value?.clientHeight || 0
|
|
|
+ if (height > 120) {
|
|
|
+ const nextHeight = Math.floor(height) - 14
|
|
|
+ if (Math.abs(nextHeight - processTableHeight.value) > 2) {
|
|
|
+ processTableHeight.value = nextHeight
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+const attachProcessTableResizeObserver = () => {
|
|
|
+ processTableResizeObserver?.disconnect()
|
|
|
+ const el = processTableWrapRef.value
|
|
|
+ if (!el || typeof ResizeObserver === 'undefined') return
|
|
|
+ processTableResizeObserver = new ResizeObserver(() => {
|
|
|
+ updateProcessTableHeight()
|
|
|
+ })
|
|
|
+ processTableResizeObserver.observe(el)
|
|
|
+}
|
|
|
+
|
|
|
+watch(workScoreDialogVisible, (visible) => {
|
|
|
+ if (visible) {
|
|
|
+ nextTick(() => {
|
|
|
+ updateProcessTableHeight()
|
|
|
+ attachProcessTableResizeObserver()
|
|
|
+ })
|
|
|
+ window.addEventListener('resize', updateProcessTableHeight)
|
|
|
+ } else {
|
|
|
+ window.removeEventListener('resize', updateProcessTableHeight)
|
|
|
+ processTableResizeObserver?.disconnect()
|
|
|
+ processTableResizeObserver = null
|
|
|
+ resetWorkScoreDialogState()
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
+onUnmounted(() => {
|
|
|
+ window.removeEventListener('resize', updateProcessTableHeight)
|
|
|
+ processTableResizeObserver?.disconnect()
|
|
|
+})
|
|
|
+
|
|
|
+const selectedEmployeeName = computed(() => {
|
|
|
+ const emp = employees.value.find(item => item['员工编号'] === selectedEmployee.value)
|
|
|
+ return emp?.['员工姓名'] || ''
|
|
|
+})
|
|
|
+
|
|
|
+//工艺部件数据
|
|
|
+const processParts = ref([]);
|
|
|
+
|
|
|
+//工艺数据
|
|
|
+const partProcesses = ref([]);
|
|
|
+
|
|
|
+//部件数量
|
|
|
+const partQuantities = ref([]);
|
|
|
+
|
|
|
+//选中的部件索引
|
|
|
+const selectedPartIndex = ref(-1);
|
|
|
+
|
|
|
+//报工数据
|
|
|
+const reportingData = ref([]);
|
|
|
+
|
|
|
+//加载状态
|
|
|
+const loadingProcess = ref(false);
|
|
|
+
|
|
|
+const resetWorkScoreDialogState = () => {
|
|
|
+ selectedEmployee.value = ''
|
|
|
+ batchQuantity.value = ''
|
|
|
+ selectedPartIndex.value = -1
|
|
|
+ processParts.value = []
|
|
|
+ partProcesses.value = []
|
|
|
+ partQuantities.value = []
|
|
|
+ reportingData.value = []
|
|
|
+ loadingProcess.value = false
|
|
|
+ workScoreConfirmVisible.value = false
|
|
|
+ workScoreConfirmRows.value = []
|
|
|
+ pendingReportData.value = []
|
|
|
+ workScoreSubmitting.value = false
|
|
|
+}
|
|
|
+
|
|
|
+watch(selectedPartIndex, () => {
|
|
|
+ if (workScoreDialogVisible.value) {
|
|
|
+ updateProcessTableHeight()
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
+watch(loadingProcess, (loading) => {
|
|
|
+ if (!loading && workScoreDialogVisible.value) {
|
|
|
+ updateProcessTableHeight()
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
+const openWorkScoreDialog = async () => {
|
|
|
+ if (!getActiveOrderNo() || orderInfoList.length === 0) {
|
|
|
+ warningres('请先查询订单信息');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const machineNo = String(add_formData['机台号'] || '').trim()
|
|
|
+ if (!machineReady.value || !machineNo) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ resetWorkScoreDialogState()
|
|
|
+ const hasData = await loadProcessParts()
|
|
|
+ if (!hasData) return
|
|
|
+
|
|
|
+ workScoreDialogVisible.value = true
|
|
|
+ refreshProcessTableLayout()
|
|
|
+};
|
|
|
+
|
|
|
+const loadOrderAttachments = async (orderNo) => {
|
|
|
+ const seq = ++attachmentQuerySeq
|
|
|
+ try {
|
|
|
+ const jsOrderAttachments = await OrderAttachments({ order: orderNo, desc: '技术附件' })
|
|
|
+ const ddOrderAttachments = await OrderAttachments({ order: orderNo, desc: '订单资料附件' })
|
|
|
+ if (seq !== attachmentQuerySeq) return
|
|
|
+ const jsList = jsOrderAttachments?.data?.list || []
|
|
|
+ const ddList = ddOrderAttachments?.data?.list || []
|
|
|
+ jstableData.splice(0, jstableData.length, ...jsList)
|
|
|
+ ddtableData.splice(0, ddtableData.length, ...ddList)
|
|
|
+ } catch (error) {
|
|
|
+ if (seq !== attachmentQuerySeq) return
|
|
|
+ console.error('获取附件失败:', error)
|
|
|
+ jstableData.length = 0
|
|
|
+ ddtableData.length = 0
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+//加载工艺部件数据;有数据返回 true,无数据或失败返回 false(仅提示,不弹窗)
|
|
|
+const loadProcessParts = async () => {
|
|
|
+ loadingProcess.value = true;
|
|
|
+ try {
|
|
|
+ const response = await GetOrderProcess({
|
|
|
+ workorder: getActiveOrderNo(),
|
|
|
+ majorprocess: add_formData['工序']
|
|
|
+ });
|
|
|
+
|
|
|
+ if (response.code === 0) {
|
|
|
+ const parts = extractListFromResponse(response.data)
|
|
|
+ if (!parts.length) {
|
|
|
+ warningres('技术部未上传工序明细资料数据')
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ processParts.value = parts
|
|
|
+ partQuantities.value = new Array(parts.length).fill('')
|
|
|
+ partProcesses.value = Array.from({ length: parts.length }, () => [])
|
|
|
+ reportingData.value = Array.from({ length: parts.length }, () => [])
|
|
|
+ await selectPart(0)
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ warningres('获取工艺部件失败')
|
|
|
+ return false
|
|
|
+ } catch (error) {
|
|
|
+ console.error('获取工艺部件失败:', error);
|
|
|
+ warningres('网络错误,请稍后重试');
|
|
|
+ return false
|
|
|
+ } finally {
|
|
|
+ loadingProcess.value = false;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+//加载部件工艺数据
|
|
|
+const loadPartProcesses = async (index, partCode) => {
|
|
|
+ const code = String(partCode || '').trim()
|
|
|
+ if (!code) {
|
|
|
+ setPartProcessData(index, [])
|
|
|
+ return
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ const carParams = {
|
|
|
+ workorder: getActiveOrderNo(),
|
|
|
+ part_code: code,
|
|
|
+ majorprocess: add_formData['工序'],
|
|
|
+ }
|
|
|
+ // 本组完成数由后端在 GetCarProcess 中按组别返回
|
|
|
+ const sysId = String(add_formData['组别'] || '').trim()
|
|
|
+ if (sysId) carParams.sys_id = sysId
|
|
|
+
|
|
|
+ const response = await GetCarProcess(carParams)
|
|
|
+
|
|
|
+ if (response.code === 0 && response.data) {
|
|
|
+ const processList = normalizeWorkScoreProcessList(response.data)
|
|
|
+ setPartProcessData(index, processList)
|
|
|
+ } else {
|
|
|
+ setPartProcessData(index, [])
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('获取部件工艺失败:', error);
|
|
|
+ setPartProcessData(index, [])
|
|
|
+ } finally {
|
|
|
+ if (index === selectedPartIndex.value) {
|
|
|
+ refreshProcessTableLayout()
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+//获取报工数据
|
|
|
+const getReportingData = (partIndex, processIndex) => {
|
|
|
+ if (!reportingData.value[partIndex]) {
|
|
|
+ reportingData.value[partIndex] = [];
|
|
|
+ }
|
|
|
+ if (!reportingData.value[partIndex][processIndex]) {
|
|
|
+ reportingData.value[partIndex][processIndex] = createEmptyReportingItem()
|
|
|
+ }
|
|
|
+ return reportingData.value[partIndex][processIndex];
|
|
|
+};
|
|
|
+
|
|
|
+/** 同一工序行内已选人员(排除当前正在编辑的格) */
|
|
|
+const isStaffDuplicateInProcessRow = (partIndex, processIndex, staffNo, staffName, excludeStaffIndex = null) => {
|
|
|
+ const item = getReportingData(partIndex, processIndex)
|
|
|
+ const n = String(staffNo || '').trim()
|
|
|
+ const nm = String(staffName || '').trim()
|
|
|
+ const checkOne = (no, name, idx) => {
|
|
|
+ if (excludeStaffIndex !== null && idx === excludeStaffIndex) return false
|
|
|
+ const o = String(no || '').trim()
|
|
|
+ const on = String(name || '').trim()
|
|
|
+ if (n && o && n === o) return true
|
|
|
+ if (nm && on && nm === on) return true
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ if (item.staffList?.length) {
|
|
|
+ return item.staffList.some((s, idx) => checkOne(s.staff_no, s.staff_name, idx))
|
|
|
+ }
|
|
|
+ return checkOne(item.staff_no, item.staff_name, null)
|
|
|
+}
|
|
|
+
|
|
|
+const assignStaffToReportingRow = (partIndex, processIndex, employee, staffIndex = null) => {
|
|
|
+ if (!employee) return false
|
|
|
+ const no = employee.员工编号
|
|
|
+ const name = employee.员工姓名
|
|
|
+ if (isStaffDuplicateInProcessRow(partIndex, processIndex, no, name, staffIndex)) {
|
|
|
+ warningres([
|
|
|
+ `「${name}」`,
|
|
|
+ '已在该工序中选择',
|
|
|
+ '请勿重复添加',
|
|
|
+ ])
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ const reportingDataItem = getReportingData(partIndex, processIndex)
|
|
|
+ if (staffIndex !== null && reportingDataItem.staffList) {
|
|
|
+ reportingDataItem.staffList[staffIndex].staff_name = name
|
|
|
+ reportingDataItem.staffList[staffIndex].staff_no = no
|
|
|
+ } else if (reportingDataItem.staffList) {
|
|
|
+ reportingDataItem.staffList.push({
|
|
|
+ staff_name: name,
|
|
|
+ staff_no: no,
|
|
|
+ number: '',
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ reportingDataItem.staff_name = name
|
|
|
+ reportingDataItem.staff_no = no
|
|
|
+ }
|
|
|
+ return true
|
|
|
+}
|
|
|
+
|
|
|
+// 将上方选中的员工填入当前工序格(同一工序行内不可重复)
|
|
|
+const fillSelectedEmployee = (row, partIndex, processIndex, staffIndex = null) => {
|
|
|
+ if (isReportingFillDisabled(partIndex, processIndex, staffIndex)) {
|
|
|
+ warningres('请先在上方选择人员')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const emp = employees.value.find(emp => emp['员工编号'] === selectedEmployee.value)
|
|
|
+ if (!emp) return
|
|
|
+ assignStaffToReportingRow(partIndex, processIndex, emp, staffIndex)
|
|
|
+}
|
|
|
+
|
|
|
+// 表格内输入完工数量时,若上方已选人员且本格人员为空,则自动填入
|
|
|
+const filterQtyDigits = (val) => String(val ?? '').replace(/[^\d]/g, '').slice(0, 5)
|
|
|
+
|
|
|
+const highlightProcessRow = (row) => {
|
|
|
+ activeProcessRow.value = row
|
|
|
+ processTableRef.value?.setCurrentRow?.(row)
|
|
|
+}
|
|
|
+
|
|
|
+const onProcessTableRowClick = (row) => {
|
|
|
+ highlightProcessRow(row)
|
|
|
+}
|
|
|
+
|
|
|
+const processTableRowClassName = ({ row }) =>
|
|
|
+ row === activeProcessRow.value ? 'work-score-process-row-active' : ''
|
|
|
+
|
|
|
+const onQtyInput = (partIndex, processIndex, staffIndex, val) => {
|
|
|
+ const digits = filterQtyDigits(val)
|
|
|
+ const item = getReportingData(partIndex, processIndex)
|
|
|
+ if (item.staffList?.length) {
|
|
|
+ const idx = staffIndex !== null && staffIndex !== undefined ? staffIndex : 0
|
|
|
+ if (item.staffList[idx]) item.staffList[idx].number = digits
|
|
|
+ } else {
|
|
|
+ item.number = digits
|
|
|
+ }
|
|
|
+ autoFillStaffOnQuantityInput(partIndex, processIndex, staffIndex)
|
|
|
+}
|
|
|
+
|
|
|
+/** 本工序已填完工合计是否超出未完成数 */
|
|
|
+const isQtyOverUnfinished = (partIndex, processIndex) => {
|
|
|
+ const process = partProcesses.value?.[partIndex]?.[processIndex]
|
|
|
+ const unfinished = Number(process?.未完成数)
|
|
|
+ if (!Number.isFinite(unfinished)) return false
|
|
|
+ const item = getReportingData(partIndex, processIndex)
|
|
|
+ let sum = 0
|
|
|
+ if (item.staffList?.length) {
|
|
|
+ sum = item.staffList.reduce((s, st) => s + (Number(st.number) || 0), 0)
|
|
|
+ } else {
|
|
|
+ sum = Number(item.number) || 0
|
|
|
+ }
|
|
|
+ return sum > unfinished
|
|
|
+}
|
|
|
+
|
|
|
+const isReportingStaffEmpty = (partIndex, processIndex, staffIndex = null) => {
|
|
|
+ const item = getReportingData(partIndex, processIndex)
|
|
|
+ if (item.staffList?.length) {
|
|
|
+ const idx = staffIndex !== null ? staffIndex : 0
|
|
|
+ const staff = item.staffList[idx]
|
|
|
+ return !String(staff?.staff_name || '').trim()
|
|
|
+ }
|
|
|
+ return !String(item.staff_name || '').trim()
|
|
|
+}
|
|
|
+
|
|
|
+const isReportingFillDisabled = (partIndex, processIndex, staffIndex = null) => {
|
|
|
+ return isReportingStaffEmpty(partIndex, processIndex, staffIndex) && !selectedEmployee.value
|
|
|
+}
|
|
|
+
|
|
|
+const clearReportingQuantity = (partIndex, processIndex, staffIndex = null) => {
|
|
|
+ const item = getReportingData(partIndex, processIndex)
|
|
|
+ if (item.staffList?.length) {
|
|
|
+ const idx = staffIndex !== null ? staffIndex : 0
|
|
|
+ if (item.staffList[idx]) {
|
|
|
+ item.staffList[idx].number = ''
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ item.number = ''
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const autoFillStaffOnQuantityInput = (partIndex, processIndex, staffIndex = null) => {
|
|
|
+ const item = getReportingData(partIndex, processIndex)
|
|
|
+ let hasQty = false
|
|
|
+ let staffEmpty = false
|
|
|
+ let targetStaffIndex = staffIndex
|
|
|
+
|
|
|
+ if (item.staffList?.length) {
|
|
|
+ const idx = staffIndex !== null ? staffIndex : 0
|
|
|
+ const staff = item.staffList[idx]
|
|
|
+ if (!staff) return
|
|
|
+ hasQty = staff.number !== '' && staff.number != null
|
|
|
+ staffEmpty = !String(staff.staff_name || '').trim()
|
|
|
+ targetStaffIndex = idx
|
|
|
+ } else {
|
|
|
+ hasQty = item.number !== '' && item.number != null
|
|
|
+ staffEmpty = !String(item.staff_name || '').trim()
|
|
|
+ targetStaffIndex = null
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!hasQty) return
|
|
|
+
|
|
|
+ if (staffEmpty) {
|
|
|
+ if (!selectedEmployee.value) {
|
|
|
+ warningres('请先在上方选择人员')
|
|
|
+ clearReportingQuantity(partIndex, processIndex, staffIndex)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const emp = employees.value.find(item => item['员工编号'] === selectedEmployee.value)
|
|
|
+ if (!emp) {
|
|
|
+ clearReportingQuantity(partIndex, processIndex, staffIndex)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ assignStaffToReportingRow(partIndex, processIndex, emp, targetStaffIndex)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+//选择部件
|
|
|
+const selectPart = async (index) => {
|
|
|
+ if (index < 0 || index >= processParts.value.length) return
|
|
|
+ selectedPartIndex.value = index
|
|
|
+ activeProcessRow.value = null
|
|
|
+ if (partProcesses.value[index]?.length > 0) {
|
|
|
+ refreshProcessTableLayout()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const partCode = resolvePartCode(processParts.value[index])
|
|
|
+ await loadPartProcesses(index, partCode)
|
|
|
+};
|
|
|
+
|
|
|
+// 拖拽相关函数
|
|
|
+let draggedEmployee = null;
|
|
|
+
|
|
|
+// 开始拖拽
|
|
|
+const onDragStart = (event, employee) => {
|
|
|
+ draggedEmployee = employee;
|
|
|
+ console.log('拖拽的员工:', employee);
|
|
|
+ event.dataTransfer.effectAllowed = 'copy';
|
|
|
+};
|
|
|
+
|
|
|
+// 拖拽经过
|
|
|
+const onDragOver = (event) => {
|
|
|
+ event.preventDefault();
|
|
|
+ event.dataTransfer.dropEffect = 'copy';
|
|
|
+};
|
|
|
+
|
|
|
+// 放置
|
|
|
+const onDrop = (event, partIndex, processIndex, staffIndex = null) => {
|
|
|
+ event.preventDefault();
|
|
|
+ if (draggedEmployee) {
|
|
|
+ assignStaffToReportingRow(partIndex, processIndex, draggedEmployee, staffIndex)
|
|
|
+ draggedEmployee = null;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 把上方选中的工人和完工数量填入本行
|
|
|
+const fillRowPerson = (partIndex, processIndex) => {
|
|
|
+ if (!selectedEmployee.value) {
|
|
|
+ warningres('请先点下面选一个工人')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const emp = employees.value.find(item => item['员工编号'] === selectedEmployee.value)
|
|
|
+ if (!emp) return
|
|
|
+
|
|
|
+ const qty = resolveBatchQuantity()
|
|
|
+ if (qty === null) {
|
|
|
+ warningres('请先输入完工数量')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ const item = getReportingData(partIndex, processIndex)
|
|
|
+ let staffIndex = null
|
|
|
+ if (item.staffList?.length) {
|
|
|
+ const emptyIndex = item.staffList.findIndex(staff => !String(staff.staff_name || '').trim())
|
|
|
+ if (emptyIndex >= 0) {
|
|
|
+ staffIndex = emptyIndex
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!assignStaffToReportingRow(partIndex, processIndex, emp, staffIndex)) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ const updated = getReportingData(partIndex, processIndex)
|
|
|
+ if (updated.staffList?.length) {
|
|
|
+ if (staffIndex !== null) {
|
|
|
+ updated.staffList[staffIndex].number = qty
|
|
|
+ } else {
|
|
|
+ const idx = updated.staffList.findIndex(staff => staff.staff_no === emp['员工编号'])
|
|
|
+ if (idx >= 0) {
|
|
|
+ updated.staffList[idx].number = qty
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ updated.number = qty
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 添加人员
|
|
|
+const addPerson = (partIndex, processIndex) => {
|
|
|
+ const reportingDataItem = getReportingData(partIndex, processIndex);
|
|
|
+ if (!reportingDataItem.staffList) {
|
|
|
+ // 首次添加:先把当前单行数据迁入列表,再追加新行
|
|
|
+ reportingDataItem.staffList = [{
|
|
|
+ staff_name: reportingDataItem.staff_name || '',
|
|
|
+ staff_no: reportingDataItem.staff_no || '',
|
|
|
+ number: reportingDataItem.number ?? '',
|
|
|
+ }];
|
|
|
+ }
|
|
|
+ reportingDataItem.staffList.push({
|
|
|
+ staff_name: '',
|
|
|
+ staff_no: '',
|
|
|
+ number: '',
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+const resolveBatchQuantity = () => {
|
|
|
+ if (batchQuantity.value !== '' && batchQuantity.value != null) {
|
|
|
+ return batchQuantity.value
|
|
|
+ }
|
|
|
+ return null
|
|
|
+}
|
|
|
+
|
|
|
+const resolveStaffNoByName = (staffName) => {
|
|
|
+ const name = String(staffName || '').trim()
|
|
|
+ if (!name) return ''
|
|
|
+ return employees.value.find(emp => emp['员工姓名'] === name)?.['员工编号'] || ''
|
|
|
+}
|
|
|
+
|
|
|
+//提交工分报工
|
|
|
+const buildProcessReportFields = (process) => ({
|
|
|
+ process_code: process['工艺编号'],
|
|
|
+ process_name: process['工艺名称'],
|
|
|
+ standard_hour: process['标准工时'],
|
|
|
+ standard_score: process['标准工分'],
|
|
|
+ standard_minutes: process['标准分钟'],
|
|
|
+ money: process['金额'],
|
|
|
+ coefficient: process['系数'],
|
|
|
+})
|
|
|
+
|
|
|
+const buildWorkScoreReportData = () => {
|
|
|
+ const reportData = []
|
|
|
+
|
|
|
+ for (let i = 0; i < processParts.value.length; i++) {
|
|
|
+ if (reportingData.value[i] && reportingData.value[i].length > 0) {
|
|
|
+ const part = processParts.value[i]
|
|
|
+ for (let j = 0; j < reportingData.value[i].length; j++) {
|
|
|
+ const reportItem = reportingData.value[i][j]
|
|
|
+ const process = partProcesses.value[i][j]
|
|
|
+ if (!process) continue
|
|
|
+
|
|
|
+ if (reportItem.staffList) {
|
|
|
+ for (const staff of reportItem.staffList) {
|
|
|
+ if (staff.number) {
|
|
|
+ if (!String(staff.staff_name || '').trim()) {
|
|
|
+ warningres('请填写报工人员')
|
|
|
+ return null
|
|
|
+ }
|
|
|
+ const staffNo = staff.staff_no || resolveStaffNoByName(staff.staff_name)
|
|
|
+ if (!staffNo) {
|
|
|
+ warningres(`未找到报工人员「${staff.staff_name}」对应的员工编号`)
|
|
|
+ return null
|
|
|
+ }
|
|
|
+ reportData.push({
|
|
|
+ staff_no: staffNo,
|
|
|
+ staff_name: staff.staff_name,
|
|
|
+ work_order: getActiveOrderNo(),
|
|
|
+ majorprocess: add_formData['工序'],
|
|
|
+ part_code: part['部件编号'],
|
|
|
+ ...buildProcessReportFields(process),
|
|
|
+ number: staff.number,
|
|
|
+ machine: add_formData['机台号'],
|
|
|
+ sys_id: add_formData['组别'],
|
|
|
+ date: currentDates
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else if (reportItem.number) {
|
|
|
+ if (!String(reportItem.staff_name || '').trim()) {
|
|
|
+ warningres('请填写报工人员')
|
|
|
+ return null
|
|
|
+ }
|
|
|
+ const staffNo = reportItem.staff_no || resolveStaffNoByName(reportItem.staff_name)
|
|
|
+ if (!staffNo) {
|
|
|
+ warningres(`未找到报工人员「${reportItem.staff_name}」对应的员工编号`)
|
|
|
+ return null
|
|
|
+ }
|
|
|
+ reportData.push({
|
|
|
+ staff_no: staffNo,
|
|
|
+ staff_name: reportItem.staff_name,
|
|
|
+ work_order: getActiveOrderNo(),
|
|
|
+ majorprocess: add_formData['工序'],
|
|
|
+ part_code: part['部件编号'],
|
|
|
+ ...buildProcessReportFields(process),
|
|
|
+ number: reportItem.number,
|
|
|
+ machine: add_formData['机台号'],
|
|
|
+ sys_id: add_formData['组别'],
|
|
|
+ date: currentDates
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (reportData.length === 0) {
|
|
|
+ warningres('请选择人员后,再填写完工数量')
|
|
|
+ return null
|
|
|
+ }
|
|
|
+
|
|
|
+ return reportData
|
|
|
+}
|
|
|
+
|
|
|
+const recomputeWorkScoreConfirmRowSpan = (rows) => {
|
|
|
+ const result = []
|
|
|
+ let i = 0
|
|
|
+ while (i < rows.length) {
|
|
|
+ const partLabel = rows[i].部件
|
|
|
+ const processCode = rows[i].工序编号
|
|
|
+ const processName = rows[i].工序名称
|
|
|
+ let j = i
|
|
|
+ while (
|
|
|
+ j < rows.length &&
|
|
|
+ rows[j].部件 === partLabel &&
|
|
|
+ rows[j].工序编号 === processCode &&
|
|
|
+ rows[j].工序名称 === processName
|
|
|
+ ) {
|
|
|
+ j++
|
|
|
+ }
|
|
|
+ const group = rows.slice(i, j)
|
|
|
+ group.forEach((row, idx) => {
|
|
|
+ result.push({ ...row, _processRowSpan: idx === 0 ? group.length : 0 })
|
|
|
+ })
|
|
|
+ i = j
|
|
|
+ }
|
|
|
+ return result
|
|
|
+}
|
|
|
+
|
|
|
+/** 左侧部件展示文案:编号-名称 */
|
|
|
+const resolvePartLabel = (partCode) => {
|
|
|
+ const code = String(partCode ?? '').trim()
|
|
|
+ const part = (processParts.value || []).find((p) => String(p?.['部件编号'] ?? '').trim() === code)
|
|
|
+ if (!part) return code
|
|
|
+ const name = String(part['部件名称'] ?? '').trim()
|
|
|
+ return name ? `${code}-${name}` : code
|
|
|
+}
|
|
|
+
|
|
|
+/** 从当前已加载工艺行取未完成数等 */
|
|
|
+const findProcessProgressByCode = (processCode, processName) => {
|
|
|
+ const code = String(processCode ?? '').trim()
|
|
|
+ const name = String(processName ?? '').trim()
|
|
|
+ for (const list of partProcesses.value || []) {
|
|
|
+ for (const p of list || []) {
|
|
|
+ const pCode = String(p?.工艺编号 ?? '').trim()
|
|
|
+ const pName = String(p?.工艺名称 ?? '').trim()
|
|
|
+ if (code && pCode === code && (!name || pName === name)) {
|
|
|
+ return {
|
|
|
+ unfinished: Number(p?.未完成数),
|
|
|
+ totalComplete: Number(p?.累计完成数),
|
|
|
+ groupComplete: Number(p?.本组完成数),
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return { unfinished: NaN, totalComplete: NaN, groupComplete: NaN }
|
|
|
+}
|
|
|
+
|
|
|
+const buildWorkScoreConfirmRows = (reportData) => {
|
|
|
+ // 同一部件+工序多人报工时,按合计完工数再算超出
|
|
|
+ const processQtySum = {}
|
|
|
+ for (const item of reportData) {
|
|
|
+ const key = `${item.part_code}||${item.process_code}||${item.process_name}`
|
|
|
+ processQtySum[key] = (processQtySum[key] || 0) + (Number(item.number) || 0)
|
|
|
+ }
|
|
|
+
|
|
|
+ const rows = reportData.map((item) => {
|
|
|
+ const key = `${item.part_code}||${item.process_code}||${item.process_name}`
|
|
|
+ const progress = findProcessProgressByCode(item.process_code, item.process_name)
|
|
|
+ const unfinished = progress.unfinished
|
|
|
+ const groupComplete = progress.groupComplete
|
|
|
+ const totalComplete = progress.totalComplete
|
|
|
+ const hasUnfinished = Number.isFinite(unfinished)
|
|
|
+ const hasGroupComplete = Number.isFinite(groupComplete)
|
|
|
+ const hasTotalComplete = Number.isFinite(totalComplete)
|
|
|
+ const sumQty = processQtySum[key] || 0
|
|
|
+ const excess = hasUnfinished ? Math.max(0, sumQty - unfinished) : 0
|
|
|
+ return {
|
|
|
+ 部件: resolvePartLabel(item.part_code),
|
|
|
+ 工序编号: item.process_code,
|
|
|
+ 工序名称: item.process_name,
|
|
|
+ 本组完成数: hasGroupComplete ? groupComplete : '',
|
|
|
+ 累计完成数: hasTotalComplete ? totalComplete : '',
|
|
|
+ 未完成数量: hasUnfinished ? unfinished : '',
|
|
|
+ 员工姓名: item.staff_name,
|
|
|
+ 完工数量: item.number,
|
|
|
+ 超出数量: excess > 0 ? excess : '',
|
|
|
+ _isOver: excess > 0,
|
|
|
+ }
|
|
|
+ })
|
|
|
+ return recomputeWorkScoreConfirmRowSpan(rows)
|
|
|
+}
|
|
|
+
|
|
|
+const workScoreConfirmSpanMethod = ({ row, column }) => {
|
|
|
+ const mergeProps = ['部件', '工序编号', '工序名称', '本组完成数', '累计完成数', '未完成数量', '超出数量']
|
|
|
+ if (!mergeProps.includes(column.property)) {
|
|
|
+ return { rowspan: 1, colspan: 1 }
|
|
|
+ }
|
|
|
+ const rowspan = row._processRowSpan || 0
|
|
|
+ if (rowspan > 0) {
|
|
|
+ return { rowspan, colspan: 1 }
|
|
|
+ }
|
|
|
+ return { rowspan: 0, colspan: 0 }
|
|
|
+}
|
|
|
+
|
|
|
+const workScoreConfirmCellClass = ({ row, column }) => {
|
|
|
+ if (column.property === '超出数量' && row._isOver) return 'work-score-confirm-over-cell'
|
|
|
+ if (column.property === '完工数量' && row._isOver) return 'work-score-confirm-over-cell'
|
|
|
+ return ''
|
|
|
+}
|
|
|
+
|
|
|
+const submitWorkScore = () => {
|
|
|
+ const reportData = buildWorkScoreReportData()
|
|
|
+ if (!reportData) return
|
|
|
+ pendingReportData.value = reportData
|
|
|
+ workScoreConfirmRows.value = buildWorkScoreConfirmRows(reportData)
|
|
|
+ workScoreConfirmVisible.value = true
|
|
|
+}
|
|
|
+
|
|
|
+const confirmSubmitWorkScore = async () => {
|
|
|
+ if (!pendingReportData.value.length || workScoreSubmitting.value) return
|
|
|
+ workScoreSubmitting.value = true
|
|
|
+ try {
|
|
|
+ const response = await ReportingWork(pendingReportData.value)
|
|
|
+
|
|
|
+ if (response.code === 0) {
|
|
|
+ yellowTopTip('提交成功')
|
|
|
+ workScoreConfirmVisible.value = false
|
|
|
+ workScoreDialogVisible.value = false
|
|
|
+ await getGongfenHistory()
|
|
|
+ await refreshProcessProduction()
|
|
|
+ } else {
|
|
|
+ warningres(response.msg || '提交失败')
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('提交工分报工失败:', error)
|
|
|
+ warningres('网络错误,请稍后重试')
|
|
|
+ } finally {
|
|
|
+ workScoreSubmitting.value = false
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 生成头像颜色
|
|
|
+const getAvatarColor = (index) => {
|
|
|
+ const colors = [
|
|
|
+ '#667eea', '#764ba2', '#f093fb', '#f5576c',
|
|
|
+ '#4facfe', '#00f2fe', '#43e97b', '#38f9d7',
|
|
|
+ '#fa709a', '#ffa751', '#6a11cb', '#11998e',
|
|
|
+ '#eb3349', '#56ab2f', '#614385',
|
|
|
+ ]
|
|
|
+ return colors[index % colors.length]
|
|
|
+}
|
|
|
+//自动获取物理地址
|
|
|
+const GetAddr = () => {
|
|
|
+ var xmlhttp = null;
|
|
|
+ var res;
|
|
|
+ if (window.XMLHttpRequest) {
|
|
|
+ xmlhttp = new XMLHttpRequest();
|
|
|
+ } else if (window.ActiveXObject) {
|
|
|
+ xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
|
|
|
+ }
|
|
|
+ // 2. 设置回调函数
|
|
|
+ xmlhttp.onreadystatechange = function() {
|
|
|
+ if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
|
|
|
+ res = eval('('+xmlhttp.response+')');
|
|
|
+ let result = ''
|
|
|
+ for (let i = 0; i < res.macAddress.length; i++) {
|
|
|
+ if (i % 2 === 0 && i !== 0) {
|
|
|
+ result += '-' // 根据实际需求修改分隔符
|
|
|
+ }
|
|
|
+ result += res.macAddress[i]
|
|
|
+ }
|
|
|
+ Machine.value = result
|
|
|
+ getMachineMacdata(Machine.value)
|
|
|
+ } else if (xmlhttp.readyState == 4) {
|
|
|
+ machineReady.value = false
|
|
|
+ }
|
|
|
+ }
|
|
|
+ xmlhttp.onerror = function() {
|
|
|
+ machineReady.value = false
|
|
|
+ }
|
|
|
+ // 3. 打开一个连接
|
|
|
+ xmlhttp.open("get", "http://127.0.0.1:8090/init")
|
|
|
+ // 5. 发送
|
|
|
+ xmlhttp.send();
|
|
|
+}
|
|
|
+// getMachineMacdata();
|
|
|
+GetAddr()
|
|
|
+// PDF预览
|
|
|
+const showPdf = async (row) => {
|
|
|
+ if (!luckyexcelPageRef.value?.open) {
|
|
|
+ warningres('预览组件未加载,请刷新页面重试')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ luckyexcelPageRef.value.open(row)
|
|
|
+}
|
|
|
+
|
|
|
+const add_formData = reactive({
|
|
|
+ 机台号: '',
|
|
|
+ 工序: '',
|
|
|
+ 组别: '',
|
|
|
+ 人员: '',
|
|
|
+ 尺码: '',
|
|
|
+ 数量: '',
|
|
|
+ 是否订单尾包: '',
|
|
|
+});
|
|
|
+//清空对象的属性值
|
|
|
+const gd_clearFormData = () => {
|
|
|
+ Object.keys(add_formData).forEach(key => {
|
|
|
+ add_formData[key] = '';
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+//进度汇总表格数据
|
|
|
+const add_tableData = reactive([]);
|
|
|
+const jdhz_tableData = reactive([]);
|
|
|
+const bgjdhz_tableData = reactive([]);
|
|
|
+const _order = ref('');
|
|
|
+const _UniqId = ref('');
|
|
|
+//尺寸列表
|
|
|
+const sizeDatas = reactive([])
|
|
|
+//技术附件
|
|
|
+const jstableData = reactive([])
|
|
|
+const ddtableData = reactive([])
|
|
|
+const _list = ref('');
|
|
|
+
|
|
|
+//订单信息数据
|
|
|
+const orderInfoList = reactive([]);
|
|
|
+/** 当前已加载订单编号(红框订单信息区,与搜索 input 解耦) */
|
|
|
+const processProductionRef = ref(null)
|
|
|
+const processProductionRefreshKey = ref(0)
|
|
|
+
|
|
|
+const getActiveOrderNo = () => {
|
|
|
+ const no = String(currentOrderNo.value || orderInfoList[0]?.['订单编号'] || '').trim()
|
|
|
+ return no
|
|
|
+}
|
|
|
+
|
|
|
+const refreshProcessProduction = async () => {
|
|
|
+ const orderNo = getActiveOrderNo()
|
|
|
+ if (!orderNo) return
|
|
|
+ await nextTick()
|
|
|
+ if (processProductionRef.value?.loadByWorkorder) {
|
|
|
+ await processProductionRef.value.loadByWorkorder(orderNo, add_formData['工序'])
|
|
|
+ } else {
|
|
|
+ processProductionRefreshKey.value += 1
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/** 点击「当天报工记录 / 工序产量核查」时重新拉取最新数据(含再次点击当前 Tab) */
|
|
|
+const onGongfenTabClick = async (pane) => {
|
|
|
+ const name = pane?.paneName ?? pane?.props?.name
|
|
|
+ if (name === 'first') {
|
|
|
+ await getGongfenHistory()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (name === 'processProduction') {
|
|
|
+ await refreshProcessProduction()
|
|
|
+ }
|
|
|
+ relayoutGongfenHistoryTable()
|
|
|
+}
|
|
|
+
|
|
|
+// 查询请求序号:丢弃过期响应,避免连扫串单
|
|
|
+let orderQuerySeq = 0
|
|
|
+let historyQuerySeq = 0
|
|
|
+let attachmentQuerySeq = 0
|
|
|
+
|
|
|
+// 查询
|
|
|
+/** 子订单号如 DC2605017-0800 转为订单号 DC2605017 再查询 */
|
|
|
+const normalizeOrderSearchInput = (val) => {
|
|
|
+ const s = String(val ?? '').trim()
|
|
|
+ if (!s) return ''
|
|
|
+ const idx = s.indexOf('-')
|
|
|
+ return idx >= 0 ? s.slice(0, idx).trim() : s
|
|
|
+}
|
|
|
+
|
|
|
+const add_onSubmit = async ()=>{
|
|
|
+ if (workScoreDialogVisible.value) {
|
|
|
+ warningres('请先关闭工分报工窗口后再查询其他订单,避免报错单')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const machineNo = String(add_formData['机台号'] || '').trim()
|
|
|
+ if (!machineReady.value || !machineNo || machineNo === '测试机台') {
|
|
|
+ machineTip()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const searchKey = normalizeOrderSearchInput(add_searchInfo.value)
|
|
|
+ if (!searchKey) {
|
|
|
+ warningres('请扫描订单二维码')
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ add_searchInfo.value = searchKey
|
|
|
+ const seq = ++orderQuerySeq
|
|
|
+
|
|
|
+ try {
|
|
|
+ const response = await WorkOrderList({
|
|
|
+ search: searchKey,
|
|
|
+ page: 1,
|
|
|
+ limit: 10,
|
|
|
+ });
|
|
|
+ if (seq !== orderQuerySeq) return
|
|
|
+ const list = response.data?.data || []
|
|
|
+ const total = response.data?.total ?? list.length
|
|
|
+ if (response.code === 0 && response.data) {
|
|
|
+ if (total === 0 || !list.length) {
|
|
|
+ warningres('暂无该订单编号');
|
|
|
+ orderInfoList.length = 0;
|
|
|
+ currentOrderNo.value = '';
|
|
|
+ } else {
|
|
|
+ // 清空并更新订单信息列表
|
|
|
+ orderInfoList.length = 0;
|
|
|
+ orderInfoList.splice(0, list.length, ...list);
|
|
|
+ // 锁定当前订单编号(红框区域),后续业务不再依赖搜索框
|
|
|
+ currentOrderNo.value = String(orderInfoList[0]?.['订单编号'] || searchKey).trim();
|
|
|
+
|
|
|
+ // 获取工分报工历史记录
|
|
|
+ await getGongfenHistory();
|
|
|
+ if (seq !== orderQuerySeq) return
|
|
|
+
|
|
|
+ const searchValue = getActiveOrderNo();
|
|
|
+
|
|
|
+ // 附件加载失败不影响查询结果
|
|
|
+ await loadOrderAttachments(searchValue);
|
|
|
+ if (seq !== orderQuerySeq) return
|
|
|
+
|
|
|
+ // 查询成功后清空搜索框,便于继续扫描下一单
|
|
|
+ add_searchInfo.value = '';
|
|
|
+ _searchInput();
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ warningres(response.msg || '查询失败');
|
|
|
+ orderInfoList.length = 0;
|
|
|
+ currentOrderNo.value = '';
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ if (seq !== orderQuerySeq) return
|
|
|
+ console.error('查询订单失败:', error);
|
|
|
+ warningres('网络错误,请稍后重试');
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 获取工分报工历史记录
|
|
|
+const getGongfenHistory = async () => {
|
|
|
+ const seq = ++historyQuerySeq
|
|
|
+ try {
|
|
|
+ const response = await GetReportingWorkRecord({
|
|
|
+ date: currentDates,
|
|
|
+ machine: add_formData['机台号']
|
|
|
+ });
|
|
|
+ if (seq !== historyQuerySeq) return
|
|
|
+ if (response.code === 0 && response.data) {
|
|
|
+ gongfenHistoryData.value = response.data || [];
|
|
|
+ } else {
|
|
|
+ gongfenHistoryData.value = [];
|
|
|
+ }
|
|
|
+ relayoutGongfenHistoryTable()
|
|
|
+ } catch (error) {
|
|
|
+ if (seq !== historyQuerySeq) return
|
|
|
+ console.error('获取工分报工历史记录失败:', error);
|
|
|
+ gongfenHistoryData.value = [];
|
|
|
+ relayoutGongfenHistoryTable()
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+const deleteReportingWork = async (row) => {
|
|
|
+ try {
|
|
|
+ const escapeHtml = (val) => String(val ?? '')
|
|
|
+ .replace(/&/g, '&')
|
|
|
+ .replace(/</g, '<')
|
|
|
+ .replace(/>/g, '>')
|
|
|
+ .replace(/"/g, '"')
|
|
|
+ const processCode = escapeHtml(row?.process_code) || '-'
|
|
|
+ const processName = escapeHtml(row?.process_name) || '-'
|
|
|
+ const staffName = escapeHtml(row?.staff_name) || '-'
|
|
|
+ const number = escapeHtml(row?.number) || '-'
|
|
|
+ await ElMessageBox.confirm(
|
|
|
+ `<div class="gongfen-delete-msg">
|
|
|
+ <div>确定要删除这条报工记录吗?</div>
|
|
|
+ <div class="gongfen-delete-msg__row">工序号:<strong>${processCode}</strong></div>
|
|
|
+ <div class="gongfen-delete-msg__row">工序名称:<strong>${processName}</strong></div>
|
|
|
+ <div class="gongfen-delete-msg__row">员工姓名:<strong>${staffName}</strong></div>
|
|
|
+ <div class="gongfen-delete-msg__row">数量:<strong>${number}</strong></div>
|
|
|
+ </div>`,
|
|
|
+ '提示',
|
|
|
+ {
|
|
|
+ confirmButtonText: '确定',
|
|
|
+ cancelButtonText: '取消',
|
|
|
+ type: 'warning',
|
|
|
+ dangerouslyUseHTMLString: true,
|
|
|
+ customClass: 'gongfen-delete-confirm',
|
|
|
+ }
|
|
|
+ );
|
|
|
+
|
|
|
+ const deleteId = row?.id ?? row?.ID
|
|
|
+ if (deleteId === undefined || deleteId === null || deleteId === '') {
|
|
|
+ warningres('缺少报工记录ID,无法删除')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const response = await DeleteReportingWork({
|
|
|
+ id: deleteId
|
|
|
+ });
|
|
|
+
|
|
|
+ if (response.code === 0) {
|
|
|
+ yellowTopTip('删除成功')
|
|
|
+ await getGongfenHistory();
|
|
|
+ await refreshProcessProduction();
|
|
|
+ } else {
|
|
|
+ errorres(response.msg || '删除失败');
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ if (error !== 'cancel') {
|
|
|
+ console.error('删除报工记录失败:', error);
|
|
|
+ errorres('删除失败');
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+const editReportingQtyVisible = ref(false)
|
|
|
+const editReportingQtyLoading = ref(false)
|
|
|
+const editReportingQtyInputRef = ref(null)
|
|
|
+const editReportingQtyForm = ref({
|
|
|
+ id: '',
|
|
|
+ number: '',
|
|
|
+ original_number: '',
|
|
|
+ process_code: '',
|
|
|
+ process_name: '',
|
|
|
+ part_code: '',
|
|
|
+ unfinished: '',
|
|
|
+ standard_hour: '',
|
|
|
+ standard_score: '',
|
|
|
+ production_hour: '',
|
|
|
+ production_score: '',
|
|
|
+})
|
|
|
+
|
|
|
+const isEditReportingQtyOver = computed(() => {
|
|
|
+ const unfinished = Number(editReportingQtyForm.value.unfinished)
|
|
|
+ const original = Number(editReportingQtyForm.value.original_number) || 0
|
|
|
+ const qty = Number(editReportingQtyForm.value.number)
|
|
|
+ if (!Number.isFinite(unfinished) || !Number.isFinite(qty) || !qty) return false
|
|
|
+ // 未完成数已扣除本条原数量,可改上限 = 未完成数 + 原数量
|
|
|
+ return qty > unfinished + original
|
|
|
+})
|
|
|
+
|
|
|
+const focusEditReportingQtyInput = () => {
|
|
|
+ nextTick(() => {
|
|
|
+ const comp = editReportingQtyInputRef.value
|
|
|
+ const el = comp?.input || comp?.textarea || comp?.$el?.querySelector?.('input')
|
|
|
+ if (el && typeof el.focus === 'function') {
|
|
|
+ el.focus()
|
|
|
+ const len = String(el.value ?? '').length
|
|
|
+ try {
|
|
|
+ el.setSelectionRange(len, len)
|
|
|
+ } catch (_) { /* ignore */ }
|
|
|
+ return
|
|
|
+ }
|
|
|
+ comp?.focus?.()
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+const resolveUnfinishedForEditRow = async (row) => {
|
|
|
+ const processCode = String(row.process_code ?? row['工序编号'] ?? row['工序号'] ?? '').trim()
|
|
|
+ const processName = String(row.process_name ?? row['工序名称'] ?? '').trim()
|
|
|
+ const fromRow = Number(row.未完成数 ?? row.unfinished ?? row['未完成数量'])
|
|
|
+ if (Number.isFinite(fromRow)) return fromRow
|
|
|
+
|
|
|
+ const loaded = findProcessProgressByCode(processCode, processName)
|
|
|
+ if (Number.isFinite(loaded.unfinished)) return loaded.unfinished
|
|
|
+
|
|
|
+ const partCode = String(row.part_code ?? row['部件编号'] ?? '').trim()
|
|
|
+ if (!partCode || !getActiveOrderNo()) return ''
|
|
|
+
|
|
|
+ try {
|
|
|
+ const carParams = {
|
|
|
+ workorder: getActiveOrderNo(),
|
|
|
+ part_code: partCode,
|
|
|
+ majorprocess: add_formData['工序'],
|
|
|
+ }
|
|
|
+ const sysId = String(add_formData['组别'] || '').trim()
|
|
|
+ if (sysId) carParams.sys_id = sysId
|
|
|
+ const response = await GetCarProcess(carParams)
|
|
|
+ if (response.code !== 0 || !response.data) return ''
|
|
|
+ const processList = normalizeWorkScoreProcessList(response.data)
|
|
|
+ const hit = (processList || []).find((p) => {
|
|
|
+ const pCode = String(p?.['工艺编号'] ?? '').trim()
|
|
|
+ const pName = String(p?.['工艺名称'] ?? '').trim()
|
|
|
+ return processCode && pCode === processCode && (!processName || pName === processName)
|
|
|
+ })
|
|
|
+ const unfinished = Number(hit?.['未完成数'])
|
|
|
+ return Number.isFinite(unfinished) ? unfinished : ''
|
|
|
+ } catch (e) {
|
|
|
+ console.error('获取未完成数失败:', e)
|
|
|
+ return ''
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const openEditReportingQty = async (row) => {
|
|
|
+ const id = row?.id ?? row?.ID
|
|
|
+ if (id === undefined || id === null || id === '') {
|
|
|
+ warningres('缺少报工记录ID,无法修改')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const number = filterQtyDigits(String(row.number ?? row['数量'] ?? ''))
|
|
|
+ editReportingQtyForm.value = {
|
|
|
+ id,
|
|
|
+ number,
|
|
|
+ original_number: number,
|
|
|
+ process_code: String(row.process_code ?? row['工序编号'] ?? row['工序号'] ?? ''),
|
|
|
+ process_name: String(row.process_name ?? row['工序名称'] ?? ''),
|
|
|
+ part_code: String(row.part_code ?? row['部件编号'] ?? ''),
|
|
|
+ unfinished: '',
|
|
|
+ standard_hour: row.standard_hour ?? row['标准工时'] ?? '',
|
|
|
+ standard_score: row.standard_score ?? row['标准工分'] ?? row['标准分数'] ?? '',
|
|
|
+ production_hour: row.production_hour ?? row['生产工时'] ?? '',
|
|
|
+ production_score: row.production_score ?? row['生产分数'] ?? row['生产工分'] ?? '',
|
|
|
+ }
|
|
|
+ editReportingQtyVisible.value = true
|
|
|
+ const unfinished = await resolveUnfinishedForEditRow(row)
|
|
|
+ if (editReportingQtyForm.value.id === id) {
|
|
|
+ editReportingQtyForm.value.unfinished = unfinished === '' ? '' : String(unfinished)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const submitEditReportingQty = async () => {
|
|
|
+ const numberStr = String(editReportingQtyForm.value.number ?? '').trim()
|
|
|
+ const qty = Number(numberStr)
|
|
|
+ if (!numberStr || Number.isNaN(qty) || qty <= 0) {
|
|
|
+ warningres('请输入大于 0 的数量')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ const stdHour = Number(editReportingQtyForm.value.standard_hour)
|
|
|
+ const stdScore = Number(editReportingQtyForm.value.standard_score)
|
|
|
+ let production_hour = String(editReportingQtyForm.value.production_hour ?? '')
|
|
|
+ let production_score = String(editReportingQtyForm.value.production_score ?? '')
|
|
|
+ if (Number.isFinite(stdHour) && stdHour > 0) {
|
|
|
+ production_hour = (qty * stdHour).toFixed(2)
|
|
|
+ }
|
|
|
+ if (Number.isFinite(stdScore) && stdScore > 0) {
|
|
|
+ production_score = (qty * stdScore).toFixed(2)
|
|
|
+ }
|
|
|
+
|
|
|
+ const mod_id = userStore.userInfo?.nickName || userStore.userInfo?.userName || ''
|
|
|
+
|
|
|
+ editReportingQtyLoading.value = true
|
|
|
+ try {
|
|
|
+ const res = await UpdateReportingWork({
|
|
|
+ id: editReportingQtyForm.value.id,
|
|
|
+ number: String(qty),
|
|
|
+ production_hour,
|
|
|
+ production_score,
|
|
|
+ mod_id,
|
|
|
+ })
|
|
|
+ if (res?.code === 0) {
|
|
|
+ yellowTopTip(res.msg || '修改成功')
|
|
|
+ editReportingQtyVisible.value = false
|
|
|
+ await getGongfenHistory()
|
|
|
+ await refreshProcessProduction()
|
|
|
+ } else {
|
|
|
+ errorres(res?.msg || '修改失败')
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ console.error(e)
|
|
|
+ errorres(e?.response?.data?.msg || e?.message || '修改失败')
|
|
|
+ } finally {
|
|
|
+ editReportingQtyLoading.value = false
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 复选框选择
|
|
|
+const fjSelectionChange = (selection) => {
|
|
|
+ console.log('选中的附件:', selection);
|
|
|
+};
|
|
|
+
|
|
|
+ //总数量合计
|
|
|
+ const getSummaries = (param) => {
|
|
|
+ const { columns, data } = param;
|
|
|
+ const sums = {};
|
|
|
+ const summableLabels = [...sizeDatas, "实裁总数"];
|
|
|
+ columns.forEach((column, index) => {
|
|
|
+ if (index === 1) {
|
|
|
+ sums[index] = '总数量合计';
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (summableLabels.includes(column.label)) {
|
|
|
+ const values = data.map(item => Number(item[column.property]));
|
|
|
+ // 检查数组中是否所有值都是 NaN
|
|
|
+ if (!values.every(value => isNaN(value))) {
|
|
|
+ sums[index] = values.reduce((prev, curr) => {
|
|
|
+ const value = Number(curr);
|
|
|
+ if (!isNaN(value)) {
|
|
|
+ return prev + value;
|
|
|
+ }
|
|
|
+ return prev;
|
|
|
+ }, 0);
|
|
|
+ // 如果需要,可以在这里添加单位
|
|
|
+ // sums[index] += ' 件';
|
|
|
+ } else {
|
|
|
+ sums[index] = '';
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ return sums;
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
+//表格行点击(子订单编号单独保存,不写入搜索框)
|
|
|
+const tableRowClick = async (row)=>{
|
|
|
+ _order.value = row.子订单编号 || ''
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+const _searchInput = async ()=>{
|
|
|
+ setTimeout(() => {
|
|
|
+ const inputElement = document.getElementById('searchInput');
|
|
|
+ if (inputElement) {
|
|
|
+ inputElement.focus();
|
|
|
+ }
|
|
|
+ }, 100);
|
|
|
+}
|
|
|
+
|
|
|
+//子订单详情页
|
|
|
+const cp_gdprintonClick = async () => {
|
|
|
+ if(!_order.value){
|
|
|
+ warningres('请先点击报工记录选择子订单后再查看')
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ SubOrderPageRef.value.open(_order.value,add_formData['工序'])
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+const gd_yulan = () => {
|
|
|
+ const order = getActiveOrderNo()
|
|
|
+ if(!order){
|
|
|
+ warningres('请先查询订单后再操作此功能')
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ printPageRef.value.open(order)
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+const _orderid = ref('')//订单子编号
|
|
|
+const _kh = ref('')//生产款号
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+// =========== 分页 ===========
|
|
|
+// 分页相关的响应式变量
|
|
|
+const page = ref(1)
|
|
|
+const total = ref(0)
|
|
|
+const pageSize = ref(10)
|
|
|
+// 分页
|
|
|
+const handleCurrentChange = (val) => {
|
|
|
+ page.value = val;
|
|
|
+ _getStaffList();
|
|
|
+};
|
|
|
+
|
|
|
+// 修改页面容量 点击多少条/页
|
|
|
+const handleSizeChange = (val) => {
|
|
|
+ page.value = 10;//默认显示
|
|
|
+ pageSize.value = val;
|
|
|
+ _getStaffList();
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+// 统一提示:顶部居中、固定宽度(与扫描框一带)
|
|
|
+const TIP_OFFSET = 90
|
|
|
+const TIP_WIDTH = 520
|
|
|
+const TIP_CLASS = 'custom-warning-message gongfen-unified-tip'
|
|
|
+
|
|
|
+const buildTipHtml = (content, bgColor, textColor = '#000') => {
|
|
|
+ const lines = Array.isArray(content) ? content : [String(content || '')]
|
|
|
+ const linesHtml = lines.map((line) => (
|
|
|
+ `<div style="font-size:32px;line-height:1.35;font-weight:700;color:${textColor};word-break:break-word;white-space:normal;">${line}</div>`
|
|
|
+ )).join('')
|
|
|
+ return `<div style="background-color:${bgColor};padding:16px 24px;text-align:center;display:block;width:${TIP_WIDTH}px;box-sizing:border-box;border-radius:4px;">${linesHtml}</div>`
|
|
|
+}
|
|
|
+
|
|
|
+const showUnifiedTip = (content, { bg = '#f5ff2f', color = '#000', duration = 3000 } = {}) => {
|
|
|
+ ElMessage.closeAll()
|
|
|
+ ElMessage({
|
|
|
+ type: '',
|
|
|
+ dangerouslyUseHTMLString: true,
|
|
|
+ duration,
|
|
|
+ offset: TIP_OFFSET,
|
|
|
+ message: buildTipHtml(content, bg, color),
|
|
|
+ customClass: TIP_CLASS,
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+const successres = (arr) => showUnifiedTip(arr, { bg: '#80FA80' })
|
|
|
+const errorres = (arr) => showUnifiedTip(arr, { bg: 'red', color: '#fff' })
|
|
|
+const warningres = (arr) => showUnifiedTip(arr, { bg: '#f5ff2f' })
|
|
|
+
|
|
|
+/** 机台相关:同位置黄色提示 */
|
|
|
+const machineTip = (text) => {
|
|
|
+ showUnifiedTip(
|
|
|
+ text || '未获取到机台编号,重启电脑或重新打开系统尝试',
|
|
|
+ { duration: 4000 }
|
|
|
+ )
|
|
|
+}
|
|
|
+
|
|
|
+/** 提交/修改/删除成功:同位置黄色提示 */
|
|
|
+const yellowTopTip = (text) => {
|
|
|
+ showUnifiedTip(String(text || '').trim() || '操作成功')
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.form-container {
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: wrap;
|
|
|
+}
|
|
|
+
|
|
|
+.form-column {
|
|
|
+ /*flex: 1;*/
|
|
|
+ margin-right: 15px; /* 调整列之间的间距 */
|
|
|
+}
|
|
|
+
|
|
|
+/* 左侧输入框宽度调整 */
|
|
|
+.form-column .el-form-item .el-input {
|
|
|
+ width: 150px; /* 调整左侧输入框的宽度 */
|
|
|
+}
|
|
|
+
|
|
|
+/* 媒体查询,根据需要调整断点 */
|
|
|
+@media screen and (max-width: 768px) {
|
|
|
+ .form-column {
|
|
|
+ flex: 1 0 100%; /* 在小屏幕下变成单列布局 */
|
|
|
+ margin-right: 0;
|
|
|
+ }
|
|
|
+}
|
|
|
+/*:deep(.el-table td .cell) {*/
|
|
|
+/* line-height: 30px !important;*/
|
|
|
+/*}*/
|
|
|
+.JKWTree-container {
|
|
|
+ display: flex;
|
|
|
+}
|
|
|
+.JKWTree-tree {
|
|
|
+ /*width: 300px;*/
|
|
|
+ background-color: #fff;
|
|
|
+ padding: 10px;
|
|
|
+ margin-right: 20px;
|
|
|
+}
|
|
|
+.JKWTree-tree h3 {
|
|
|
+ font-size: 15px;
|
|
|
+ font-weight: 700;
|
|
|
+ margin: 10px 0;
|
|
|
+}
|
|
|
+.JKWTree-content {
|
|
|
+ flex: 1;
|
|
|
+}
|
|
|
+/* 图片上传 */
|
|
|
+.upload-box {
|
|
|
+ width: 200px;
|
|
|
+ height: 200px;
|
|
|
+ border: 2px dashed #e2e2e2;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ position: relative;
|
|
|
+ cursor: pointer;
|
|
|
+}
|
|
|
+.uploaded-image {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ object-fit: cover;
|
|
|
+}
|
|
|
+.upload-icon {
|
|
|
+ font-size: 40px;
|
|
|
+ color: #c0c4cc;
|
|
|
+}
|
|
|
+.file-input {
|
|
|
+ display: none;
|
|
|
+}
|
|
|
+.el-table .warning-row {
|
|
|
+ background: oldlace;
|
|
|
+}
|
|
|
+
|
|
|
+/*bom参数背景*/
|
|
|
+:deep(.el-table__body .background-plan-usage-low div div div) {
|
|
|
+ background: #80FA80 !important;
|
|
|
+}
|
|
|
+/* 选中某行时的背景色 */
|
|
|
+:deep(.el-table__body tr.current-row) > td {
|
|
|
+ background: #ff80ff !important;
|
|
|
+}
|
|
|
+/* 鼠标悬停时的背景色(工序产量核查表关闭悬停高亮) */
|
|
|
+:deep(.el-table__body tr:hover) > td {
|
|
|
+ background: #ff80ff !important;
|
|
|
+}
|
|
|
+:deep(.process-production-table-wrap .el-table__body tr:hover > td) {
|
|
|
+ background-color: var(--el-table-tr-bg-color, #fff) !important;
|
|
|
+}
|
|
|
+:deep(.process-production-table-wrap .el-table__body tr.el-table__row--striped:hover > td) {
|
|
|
+ background-color: var(--el-fill-color-lighter, #fafafa) !important;
|
|
|
+}
|
|
|
+:deep(.process-production-table-wrap .el-table__body tr.process-production-row-active > td) {
|
|
|
+ background-color: #ff80ff !important;
|
|
|
+ background: #ff80ff !important;
|
|
|
+}
|
|
|
+
|
|
|
+/* 员工选择区域样式 */
|
|
|
+.employee-grid {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: repeat(8, 1fr);
|
|
|
+ gap: 15px;
|
|
|
+ margin-top: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.employee-card {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ padding: 15px;
|
|
|
+ border-radius: 8px;
|
|
|
+ background-color: #f5f7fa;
|
|
|
+ cursor: pointer;
|
|
|
+ transition: all 0.3s ease;
|
|
|
+ border: 2px solid transparent;
|
|
|
+}
|
|
|
+
|
|
|
+.employee-card:hover {
|
|
|
+ transform: translateY(-3px);
|
|
|
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
|
+}
|
|
|
+
|
|
|
+.employee-card.selected {
|
|
|
+ border-color: #667eea;
|
|
|
+ background-color: #e6e8ff;
|
|
|
+}
|
|
|
+
|
|
|
+.employee-avatar {
|
|
|
+ width: 60px;
|
|
|
+ height: 60px;
|
|
|
+ border-radius: 50%;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ color: white;
|
|
|
+ font-size: 24px;
|
|
|
+ font-weight: bold;
|
|
|
+ margin-bottom: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.employee-name {
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: bold;
|
|
|
+ margin-bottom: 5px;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+
|
|
|
+.employee-id {
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #666;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+</style>
|
|
|
+<style scoped>
|
|
|
+:deep(.el-table td .cell) {
|
|
|
+ line-height: 20px !important;
|
|
|
+}
|
|
|
+:deep(.el-tabs__header){
|
|
|
+ margin-bottom: 0;
|
|
|
+}
|
|
|
+.search{
|
|
|
+ margin-left: 0px !important;
|
|
|
+ margin-right: 10px !important;
|
|
|
+}
|
|
|
+.bt{
|
|
|
+ margin-left: 2px !important;
|
|
|
+ padding: 3px !important;
|
|
|
+ font-size: 12px;
|
|
|
+}
|
|
|
+.el-tabs__header{
|
|
|
+ margin: 0px !important;
|
|
|
+}
|
|
|
+.gva-table-box{
|
|
|
+ padding: 0px !important;
|
|
|
+ margin-left: -10px !important;
|
|
|
+ min-height: 600px;
|
|
|
+}
|
|
|
+.gongfen-report-tabs {
|
|
|
+ padding: 0;
|
|
|
+}
|
|
|
+.gongfen-toolbar-row {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ gap: 10px;
|
|
|
+ margin-bottom: 20px;
|
|
|
+}
|
|
|
+.gongfen-order-search-input {
|
|
|
+ width: 200px;
|
|
|
+ flex-shrink: 0;
|
|
|
+}
|
|
|
+.gongfen-order-search-input :deep(.el-input__wrapper) {
|
|
|
+ height: 50px;
|
|
|
+}
|
|
|
+.gongfen-search-btn {
|
|
|
+ height: 50px;
|
|
|
+ width: 80px;
|
|
|
+ flex-shrink: 0;
|
|
|
+ margin: 0;
|
|
|
+}
|
|
|
+.gongfen-toolbar-label {
|
|
|
+ font-size: 30px;
|
|
|
+ line-height: 1;
|
|
|
+ white-space: nowrap;
|
|
|
+}
|
|
|
+.gongfen-toolbar-field {
|
|
|
+ width: 120px;
|
|
|
+ flex-shrink: 0;
|
|
|
+}
|
|
|
+.gongfen-toolbar-field :deep(.el-input__wrapper) {
|
|
|
+ height: 40px;
|
|
|
+}
|
|
|
+.gongfen-order-actions {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 8px;
|
|
|
+ margin-left: 20px;
|
|
|
+ margin-right: 24px;
|
|
|
+ flex-shrink: 0;
|
|
|
+}
|
|
|
+.gongfen-work-score-btn {
|
|
|
+ height: 64px;
|
|
|
+ width: 120px;
|
|
|
+ font-size: 18px;
|
|
|
+}
|
|
|
+.work-score-order-header {
|
|
|
+ flex-shrink: 0;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ gap: 16px;
|
|
|
+ padding: 8px 16px;
|
|
|
+ background-color: #333;
|
|
|
+ color: white;
|
|
|
+}
|
|
|
+.work-score-order-bar {
|
|
|
+ flex: 1;
|
|
|
+ min-width: 0;
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ gap: 24px;
|
|
|
+}
|
|
|
+.work-score-order-bar p {
|
|
|
+ margin: 5px 0;
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: bold;
|
|
|
+}
|
|
|
+.work-score-close-btn {
|
|
|
+ flex-shrink: 0;
|
|
|
+ min-width: 80px;
|
|
|
+ height: 36px;
|
|
|
+ font-size: 15px;
|
|
|
+ font-weight: 600;
|
|
|
+}
|
|
|
+:deep(.work-score-dialog) {
|
|
|
+ padding: 0;
|
|
|
+ margin: 0;
|
|
|
+}
|
|
|
+:deep(.work-score-dialog .el-dialog__header) {
|
|
|
+ display: none;
|
|
|
+ padding: 0;
|
|
|
+ margin: 0;
|
|
|
+}
|
|
|
+:deep(.work-score-dialog .el-dialog__body) {
|
|
|
+ padding: 0;
|
|
|
+}
|
|
|
+.work-score-dialog-inner {
|
|
|
+ height: 100vh;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ overflow: hidden;
|
|
|
+ position: fixed;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ right: 0;
|
|
|
+ bottom: 0;
|
|
|
+ background: white;
|
|
|
+}
|
|
|
+.work-score-main-body {
|
|
|
+ flex: 1;
|
|
|
+ display: flex;
|
|
|
+ min-height: 0;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+.work-score-sidebar {
|
|
|
+ width: 170px;
|
|
|
+ border-right: 1px solid #e0e0e0;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ overflow: hidden;
|
|
|
+ flex-shrink: 0;
|
|
|
+}
|
|
|
+.work-score-right-panel {
|
|
|
+ flex: 1;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ min-height: 0;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+.work-score-content-header {
|
|
|
+ flex-shrink: 0;
|
|
|
+ padding: 6px 10px;
|
|
|
+ border-bottom: 1px solid #e0e0e0;
|
|
|
+ background-color: #f5f5f5;
|
|
|
+}
|
|
|
+.work-score-section-title {
|
|
|
+ margin: 0;
|
|
|
+ font-size: 15px;
|
|
|
+ font-weight: 600;
|
|
|
+ line-height: 1.2;
|
|
|
+}
|
|
|
+.work-score-sidebar .part-list.work-score-part-list {
|
|
|
+ flex: 1;
|
|
|
+ min-height: 0;
|
|
|
+ overflow-y: auto !important;
|
|
|
+ overflow-x: hidden;
|
|
|
+ padding-bottom: 12px;
|
|
|
+ border: none;
|
|
|
+ border-radius: 0;
|
|
|
+}
|
|
|
+.work-score-sidebar .part-item {
|
|
|
+ padding: 10px 12px;
|
|
|
+}
|
|
|
+.work-score-employee-section {
|
|
|
+ flex-shrink: 0;
|
|
|
+ border-bottom: 1px solid #e0e0e0;
|
|
|
+ background-color: #fafafa;
|
|
|
+}
|
|
|
+.work-score-employee-section .employee-grid {
|
|
|
+ margin-top: 0;
|
|
|
+}
|
|
|
+.work-score-step-header {
|
|
|
+ flex-shrink: 0;
|
|
|
+ padding: 4px 12px;
|
|
|
+ min-height: 28px;
|
|
|
+ box-sizing: border-box;
|
|
|
+ background: #fafafa;
|
|
|
+}
|
|
|
+.work-score-step-text {
|
|
|
+ margin: 0;
|
|
|
+ font-size: 17px;
|
|
|
+ line-height: 1.5;
|
|
|
+ color: #303133;
|
|
|
+ white-space: nowrap;
|
|
|
+}
|
|
|
+.work-score-step-text strong {
|
|
|
+ color: #303133;
|
|
|
+ font-weight: 700;
|
|
|
+}
|
|
|
+.work-score-step-row {
|
|
|
+ gap: 12px;
|
|
|
+ flex-wrap: wrap;
|
|
|
+}
|
|
|
+.work-score-toolbar-guide {
|
|
|
+ width: 100%;
|
|
|
+}
|
|
|
+.work-score-batch-label {
|
|
|
+ flex-shrink: 0;
|
|
|
+ font-size: 15px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #606266;
|
|
|
+}
|
|
|
+.work-score-step-hint {
|
|
|
+ margin: 6px 0 0;
|
|
|
+ font-size: 14px;
|
|
|
+ line-height: 1.5;
|
|
|
+ color: #909399;
|
|
|
+}
|
|
|
+.work-score-selected-name {
|
|
|
+ color: #2563eb;
|
|
|
+ font-weight: 600;
|
|
|
+}
|
|
|
+.work-score-selected-name.is-empty {
|
|
|
+ color: #e6a23c;
|
|
|
+}
|
|
|
+.work-score-step-hint-divider {
|
|
|
+ margin: 0 8px;
|
|
|
+ color: #dcdfe6;
|
|
|
+}
|
|
|
+.work-score-steps {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ flex-wrap: nowrap;
|
|
|
+ gap: 8px;
|
|
|
+ width: 100%;
|
|
|
+}
|
|
|
+.work-score-step {
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #606266;
|
|
|
+ white-space: nowrap;
|
|
|
+}
|
|
|
+.work-score-step.is-active {
|
|
|
+ color: #2563eb;
|
|
|
+ font-weight: 700;
|
|
|
+}
|
|
|
+.work-score-step-arrow {
|
|
|
+ font-size: 16px;
|
|
|
+ color: #909399;
|
|
|
+ flex-shrink: 0;
|
|
|
+}
|
|
|
+.work-score-employee-grid {
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: nowrap;
|
|
|
+ gap: 6px;
|
|
|
+ padding: 4px 10px 4px;
|
|
|
+ min-height: 0;
|
|
|
+ box-sizing: border-box;
|
|
|
+}
|
|
|
+.work-score-employee-section .employee-card {
|
|
|
+ flex: 1 1 0;
|
|
|
+ min-width: 0;
|
|
|
+ padding: 6px 4px;
|
|
|
+ min-height: auto;
|
|
|
+ border-radius: 6px;
|
|
|
+ border: 2px solid transparent;
|
|
|
+ box-sizing: border-box;
|
|
|
+}
|
|
|
+.work-score-employee-section .employee-card:hover {
|
|
|
+ transform: none;
|
|
|
+ box-shadow: none;
|
|
|
+}
|
|
|
+.work-score-employee-section .employee-avatar {
|
|
|
+ width: 30px;
|
|
|
+ height: 30px;
|
|
|
+ font-size: 18px;
|
|
|
+ margin-bottom: 4px;
|
|
|
+}
|
|
|
+.work-score-employee-section .employee-name {
|
|
|
+ font-size: 18px;
|
|
|
+ font-weight: 600;
|
|
|
+ line-height: 1.2;
|
|
|
+ margin-bottom: 2px;
|
|
|
+ white-space: nowrap;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ width: 100%;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+.work-score-employee-section .employee-id {
|
|
|
+ font-size: 14px;
|
|
|
+ line-height: 1.2;
|
|
|
+ white-space: nowrap;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ width: 100%;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+.work-score-employee-section .employee-card.selected {
|
|
|
+ border-color: #10b981;
|
|
|
+ border-width: 2px;
|
|
|
+ background: #ecfdf5;
|
|
|
+}
|
|
|
+.work-score-process-area {
|
|
|
+ flex: 1;
|
|
|
+ min-height: 0;
|
|
|
+ overflow: hidden;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ padding: 2px 10px 4px;
|
|
|
+}
|
|
|
+.work-score-process-block {
|
|
|
+ flex: 1;
|
|
|
+ min-height: 0;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+.work-score-process-toolbar {
|
|
|
+ flex-shrink: 0;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ gap: 8px;
|
|
|
+ margin-bottom: 2px;
|
|
|
+ padding-bottom: 2px;
|
|
|
+ background: #fff;
|
|
|
+ border-bottom: 1px solid #ebeef5;
|
|
|
+ z-index: 2;
|
|
|
+}
|
|
|
+.work-score-process-toolbar h4 {
|
|
|
+ margin: 0;
|
|
|
+ font-size: 14px;
|
|
|
+ flex-shrink: 0;
|
|
|
+}
|
|
|
+.work-score-process-toolbar--simple {
|
|
|
+ flex-shrink: 0;
|
|
|
+ padding: 4px 12px;
|
|
|
+ background: #fafafa;
|
|
|
+ border-bottom: 1px solid #ebeef5;
|
|
|
+ border-radius: 0;
|
|
|
+}
|
|
|
+.work-score-quick-row {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ flex-wrap: nowrap;
|
|
|
+ gap: 12px;
|
|
|
+ width: 100%;
|
|
|
+ min-height: 40px;
|
|
|
+}
|
|
|
+.work-score-batch-qty-input {
|
|
|
+ width: 72px;
|
|
|
+ flex-shrink: 0;
|
|
|
+}
|
|
|
+.work-score-batch-qty-input :deep(.el-input__inner) {
|
|
|
+ height: 34px;
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 600;
|
|
|
+ text-align: center;
|
|
|
+ color: #303133;
|
|
|
+}
|
|
|
+.work-score-batch-qty-input :deep(.el-input__inner::placeholder) {
|
|
|
+ font-size: 13px;
|
|
|
+ font-weight: 400;
|
|
|
+ color: #a8abb2;
|
|
|
+}
|
|
|
+.work-score-batch-qty-input :deep(input[type='number']) {
|
|
|
+ -moz-appearance: textfield;
|
|
|
+ appearance: textfield;
|
|
|
+}
|
|
|
+.work-score-batch-qty-input :deep(input[type='number']::-webkit-outer-spin-button),
|
|
|
+.work-score-batch-qty-input :deep(input[type='number']::-webkit-inner-spin-button) {
|
|
|
+ -webkit-appearance: none;
|
|
|
+ margin: 0;
|
|
|
+}
|
|
|
+.work-score-submit-btn {
|
|
|
+ flex-shrink: 0;
|
|
|
+ min-width: 88px;
|
|
|
+ height: 32px;
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: 600;
|
|
|
+ padding: 0 12px;
|
|
|
+ margin-left: auto;
|
|
|
+}
|
|
|
+.work-score-confirm-tip {
|
|
|
+ margin: 0 0 12px;
|
|
|
+ font-size: 15px;
|
|
|
+ color: #606266;
|
|
|
+}
|
|
|
+:deep(.work-score-confirm-over-cell) {
|
|
|
+ color: #f56c6c !important;
|
|
|
+ font-weight: 600;
|
|
|
+}
|
|
|
+.work-score-process-table-wrap :deep(.work-score-process-table .el-input__inner) {
|
|
|
+ height: 30px;
|
|
|
+ font-size: 14px;
|
|
|
+}
|
|
|
+.work-score-process-table-wrap :deep(.work-score-qty-input .el-input__inner) {
|
|
|
+ height: 30px;
|
|
|
+ font-size: 18px;
|
|
|
+ font-weight: 600;
|
|
|
+ text-align: center;
|
|
|
+ color: #303133;
|
|
|
+}
|
|
|
+/* 选中行:只高亮整行粉色,输入框保持白底 */
|
|
|
+.work-score-process-table-wrap :deep(.el-table__body tr.work-score-process-row-active > td.el-table__cell),
|
|
|
+.work-score-process-table-wrap :deep(.el-table__body tr.current-row > td.el-table__cell) {
|
|
|
+ background-color: #ff80ff !important;
|
|
|
+ background: #ff80ff !important;
|
|
|
+}
|
|
|
+.work-score-process-table-wrap :deep(.work-score-qty-over .el-input__inner) {
|
|
|
+ color: #f56c6c !important;
|
|
|
+}
|
|
|
+.work-score-process-table-wrap :deep(.work-score-staff-input .el-input__inner) {
|
|
|
+ height: 30px;
|
|
|
+ font-size: 14px;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+.work-score-process-table-wrap :deep(.work-score-process-table .cell) {
|
|
|
+ font-size: 15px;
|
|
|
+ line-height: 1.4;
|
|
|
+ padding-top: 0px;
|
|
|
+ padding-bottom: 0px;
|
|
|
+}
|
|
|
+.work-score-row-actions {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: row;
|
|
|
+ flex-wrap: nowrap;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ gap: 6px;
|
|
|
+}
|
|
|
+.work-score-fill-row-btn,
|
|
|
+.work-score-add-person-btn {
|
|
|
+ margin: 0;
|
|
|
+ min-width: 52px;
|
|
|
+ height: 30px;
|
|
|
+ padding: 0 10px;
|
|
|
+ font-size: 13px;
|
|
|
+ font-weight: 600;
|
|
|
+ border-radius: 4px;
|
|
|
+}
|
|
|
+.work-score-add-person-btn {
|
|
|
+ color: #409eff;
|
|
|
+ border-color: #b3d8ff;
|
|
|
+ background: #fff;
|
|
|
+}
|
|
|
+.work-score-add-person-btn:hover:not(:disabled) {
|
|
|
+ color: #fff;
|
|
|
+ border-color: #409eff;
|
|
|
+ background: #409eff;
|
|
|
+}
|
|
|
+.work-score-fill-row-btn:disabled {
|
|
|
+ opacity: 0.45;
|
|
|
+}
|
|
|
+.work-score-staff-row {
|
|
|
+ margin-bottom: 2px;
|
|
|
+}
|
|
|
+.work-score-staff-row:last-child {
|
|
|
+ margin-bottom: 0;
|
|
|
+}
|
|
|
+.work-score-process-table-wrap :deep(.work-score-process-table td.el-table__cell) {
|
|
|
+ padding: 3px 0;
|
|
|
+}
|
|
|
+.work-score-process-table-wrap :deep(.work-score-process-table th.el-table__cell) {
|
|
|
+ padding: 8px 0;
|
|
|
+ font-size: 14px;
|
|
|
+ background: #f5f7fa;
|
|
|
+}
|
|
|
+.work-score-process-table-wrap :deep(.work-score-process-table .el-table__body-wrapper) {
|
|
|
+ overflow-y: auto;
|
|
|
+}
|
|
|
+.work-score-process-table-wrap :deep(.work-score-process-table .el-scrollbar__wrap) {
|
|
|
+ padding-bottom: 6px;
|
|
|
+ box-sizing: border-box;
|
|
|
+}
|
|
|
+.work-score-process-table-wrap :deep(.work-score-process-table .el-scrollbar__bar.is-vertical) {
|
|
|
+ width: 8px;
|
|
|
+ right: 2px;
|
|
|
+}
|
|
|
+.work-score-process-table-wrap {
|
|
|
+ flex: 1;
|
|
|
+ min-height: 0;
|
|
|
+ height: 0;
|
|
|
+ overflow: hidden;
|
|
|
+ padding-bottom: 4px;
|
|
|
+ box-sizing: border-box;
|
|
|
+}
|
|
|
+.work-score-process-table-wrap :deep(input[type='number']) {
|
|
|
+ -moz-appearance: textfield;
|
|
|
+ appearance: textfield;
|
|
|
+}
|
|
|
+.work-score-process-table-wrap :deep(input[type='number']::-webkit-outer-spin-button),
|
|
|
+.work-score-process-table-wrap :deep(input[type='number']::-webkit-inner-spin-button) {
|
|
|
+ -webkit-appearance: none;
|
|
|
+ margin: 0;
|
|
|
+}
|
|
|
+.work-score-process-empty {
|
|
|
+ flex: 1;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ text-align: center;
|
|
|
+ padding: 50px;
|
|
|
+}
|
|
|
+.work-score-process-empty--muted {
|
|
|
+ color: #999;
|
|
|
+}
|
|
|
+.gongfen-col-header {
|
|
|
+ display: inline-flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ gap: 4px;
|
|
|
+ width: 100%;
|
|
|
+}
|
|
|
+
|
|
|
+.gongfen-history-table :deep(.el-table__header .cell),
|
|
|
+.gongfen-history-table :deep(.el-table__body .cell),
|
|
|
+.gongfen-history-table :deep(.el-table__footer .cell) {
|
|
|
+ padding-left: 8px;
|
|
|
+ padding-right: 8px;
|
|
|
+ line-height: 24px;
|
|
|
+ box-sizing: border-box;
|
|
|
+}
|
|
|
+
|
|
|
+.gongfen-history-table :deep(.el-table__header th),
|
|
|
+.gongfen-history-table :deep(.el-table__body td),
|
|
|
+.gongfen-history-table :deep(.el-table__footer td) {
|
|
|
+ padding-top: 4px !important;
|
|
|
+ padding-bottom: 4px !important;
|
|
|
+}
|
|
|
+
|
|
|
+.gongfen-history-table :deep(.el-table__footer-wrapper td) {
|
|
|
+ font-weight: 600;
|
|
|
+ background: #fafafa;
|
|
|
+}
|
|
|
+.gy-detail-filter-btn {
|
|
|
+ display: inline-flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ width: 22px;
|
|
|
+ height: 22px;
|
|
|
+ cursor: pointer;
|
|
|
+ color: #909399;
|
|
|
+ border-radius: 2px;
|
|
|
+}
|
|
|
+.gy-detail-filter-btn:hover,
|
|
|
+.gy-detail-filter-btn.is-active {
|
|
|
+ color: var(--el-color-primary);
|
|
|
+ background: #ecf5ff;
|
|
|
+}
|
|
|
+.gy-detail-filter-options {
|
|
|
+ max-height: 220px;
|
|
|
+ overflow-x: hidden;
|
|
|
+ overflow-y: auto;
|
|
|
+ margin-bottom: 4px;
|
|
|
+}
|
|
|
+.gy-detail-filter-panel :deep(.el-checkbox) {
|
|
|
+ display: flex;
|
|
|
+ margin-right: 0;
|
|
|
+ margin-bottom: 6px;
|
|
|
+}
|
|
|
+.gy-detail-filter-actions {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ margin-top: 4px;
|
|
|
+ padding-top: 8px;
|
|
|
+ border-top: 1px solid #ebeef5;
|
|
|
+}
|
|
|
+.gy-detail-filter-link {
|
|
|
+ color: var(--el-color-primary);
|
|
|
+ font-size: 12px;
|
|
|
+ line-height: 1;
|
|
|
+ cursor: pointer;
|
|
|
+ user-select: none;
|
|
|
+ padding: 4px 2px;
|
|
|
+}
|
|
|
+.gy-detail-filter-link:hover {
|
|
|
+ opacity: 0.85;
|
|
|
+}
|
|
|
+.mab{
|
|
|
+ margin-bottom: 5px;
|
|
|
+}
|
|
|
+
|
|
|
+/* 搜索样式 */
|
|
|
+::v-deep .el-input__wrapper #searchInput {
|
|
|
+ font-size: 16px;
|
|
|
+}
|
|
|
+::v-deep .el-input__wrapper #jitaihao {
|
|
|
+ font-size: 18px;
|
|
|
+}
|
|
|
+::v-deep .el-input__wrapper #gongxu {
|
|
|
+ font-size: 18px;
|
|
|
+}
|
|
|
+::v-deep .el-input__wrapper #zubie {
|
|
|
+ font-size: 18px;
|
|
|
+}
|
|
|
+::v-deep .el-input__wrapper #renyuan {
|
|
|
+ font-size: 18px;
|
|
|
+}
|
|
|
+::v-deep .el-input__wrapper #shuliang {
|
|
|
+ font-size: 18px;
|
|
|
+ color: red;
|
|
|
+}
|
|
|
+::v-deep .el-input__wrapper #chima {
|
|
|
+ font-size: 18px;
|
|
|
+}
|
|
|
+
|
|
|
+/* 尺码/制单数合计样式 */
|
|
|
+::v-deep .el-input__wrapper #cm1{
|
|
|
+ font-size: 20px;
|
|
|
+}
|
|
|
+::v-deep .el-input__wrapper #cm2{
|
|
|
+ font-size: 20px;
|
|
|
+}
|
|
|
+::v-deep .el-input__wrapper #cm3{
|
|
|
+ font-size: 20px;
|
|
|
+}
|
|
|
+::v-deep .el-input__wrapper #cm4{
|
|
|
+ font-size: 20px;
|
|
|
+}
|
|
|
+::v-deep .el-input__wrapper #cm5{
|
|
|
+ font-size: 20px;
|
|
|
+}
|
|
|
+::v-deep .el-input__wrapper #cm6{
|
|
|
+ font-size: 20px;
|
|
|
+}
|
|
|
+::v-deep .el-input__wrapper #cm7{
|
|
|
+ font-size: 20px;
|
|
|
+}
|
|
|
+::v-deep .el-input__wrapper #cm8{
|
|
|
+ font-size: 20px;
|
|
|
+}
|
|
|
+::v-deep .el-input__wrapper #cm9{
|
|
|
+ font-size: 20px;
|
|
|
+}
|
|
|
+::v-deep .el-input__wrapper #cm10{
|
|
|
+ font-size: 20px;
|
|
|
+}
|
|
|
+::v-deep .el-input__wrapper #cm11{
|
|
|
+ font-size: 20px;
|
|
|
+}
|
|
|
+::v-deep .el-input__wrapper #cm12{
|
|
|
+ font-size: 20px;
|
|
|
+}
|
|
|
+::v-deep .el-input__wrapper #cm13{
|
|
|
+ font-size: 20px;
|
|
|
+}
|
|
|
+::v-deep .el-input__wrapper #cm14{
|
|
|
+ font-size: 20px;
|
|
|
+}
|
|
|
+::v-deep .el-input__wrapper #cmtotal{
|
|
|
+ font-size: 20px;
|
|
|
+}
|
|
|
+/* 本次实裁新增样式 */
|
|
|
+::v-deep .el-input__wrapper #cmsl1{
|
|
|
+ font-size: 20px;
|
|
|
+ color: red !important;
|
|
|
+}
|
|
|
+::v-deep .el-input__wrapper #cmsl2{
|
|
|
+ font-size: 20px;
|
|
|
+ color: red !important;
|
|
|
+}
|
|
|
+::v-deep .el-input__wrapper #cmsl3{
|
|
|
+ font-size: 20px;
|
|
|
+ color: red !important;
|
|
|
+}
|
|
|
+::v-deep .el-input__wrapper #cmsl4{
|
|
|
+ font-size: 20px;
|
|
|
+ color: red !important;
|
|
|
+}
|
|
|
+::v-deep .el-input__wrapper #cmsl5{
|
|
|
+ font-size: 20px;
|
|
|
+ color: red !important;
|
|
|
+}
|
|
|
+::v-deep .el-input__wrapper #cmsl6{
|
|
|
+ font-size: 20px;
|
|
|
+ color: red !important;
|
|
|
+}
|
|
|
+::v-deep .el-input__wrapper #cmsl7{
|
|
|
+ font-size: 20px;
|
|
|
+ color: red !important;
|
|
|
+}
|
|
|
+::v-deep .el-input__wrapper #cmsl8{
|
|
|
+ font-size: 20px;
|
|
|
+ color: red !important;
|
|
|
+}
|
|
|
+::v-deep .el-input__wrapper #cmsl9{
|
|
|
+ font-size: 20px;
|
|
|
+ color: red !important;
|
|
|
+}
|
|
|
+::v-deep .el-input__wrapper #cmsl10{
|
|
|
+ font-size: 20px;
|
|
|
+ color: red !important;
|
|
|
+}
|
|
|
+::v-deep .el-input__wrapper #cmsl11{
|
|
|
+ font-size: 20px;
|
|
|
+ color: red !important;
|
|
|
+}
|
|
|
+::v-deep .el-input__wrapper #cmsl12{
|
|
|
+ font-size: 20px;
|
|
|
+ color: red !important;
|
|
|
+}
|
|
|
+::v-deep .el-input__wrapper #cmsl13{
|
|
|
+ font-size: 20px;
|
|
|
+ color: red !important;
|
|
|
+}
|
|
|
+::v-deep .el-input__wrapper #cmsl14{
|
|
|
+ font-size: 20px;
|
|
|
+ color: red !important;
|
|
|
+}
|
|
|
+::v-deep .el-input__wrapper #zdtotal{
|
|
|
+ font-size: 20px;
|
|
|
+ color: red !important;
|
|
|
+}
|
|
|
+::v-deep .el-input__wrapper #scs1{
|
|
|
+ font-size: 18px;
|
|
|
+}
|
|
|
+::v-deep .el-input__wrapper #scs2{
|
|
|
+ font-size: 18px;
|
|
|
+}
|
|
|
+::v-deep .el-input__wrapper #scs3{
|
|
|
+ font-size: 18px;
|
|
|
+}
|
|
|
+::v-deep .el-input__wrapper #scs4{
|
|
|
+ font-size: 18px;
|
|
|
+}
|
|
|
+::v-deep .el-input__wrapper #scs5{
|
|
|
+ font-size: 18px;
|
|
|
+}
|
|
|
+::v-deep .el-input__wrapper #scs6{
|
|
|
+ font-size: 18px;
|
|
|
+}
|
|
|
+::v-deep .el-input__wrapper #scs7{
|
|
|
+ font-size: 18px;
|
|
|
+}
|
|
|
+::v-deep .el-input__wrapper #scs8{
|
|
|
+ font-size: 18px;
|
|
|
+}
|
|
|
+::v-deep .el-input__wrapper #scs9{
|
|
|
+ font-size: 18px;
|
|
|
+}
|
|
|
+::v-deep .el-input__wrapper #scs10{
|
|
|
+ font-size: 18px;
|
|
|
+}
|
|
|
+::v-deep .el-input__wrapper #scs11{
|
|
|
+ font-size: 18px;
|
|
|
+}
|
|
|
+::v-deep .el-input__wrapper #scs12{
|
|
|
+ font-size: 18px;
|
|
|
+}
|
|
|
+::v-deep .el-input__wrapper #scs13{
|
|
|
+ font-size: 18px;
|
|
|
+}
|
|
|
+::v-deep .el-input__wrapper #scs14{
|
|
|
+ font-size: 18px;
|
|
|
+}
|
|
|
+::v-deep .el-input__wrapper #sctotal{
|
|
|
+ font-size: 18px;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/* 表格复选框大小调整 */
|
|
|
+:deep(.el-checkbox.el-checkbox--small .el-checkbox__inner) {
|
|
|
+ width: 30px;
|
|
|
+ /* 复选框宽度 */
|
|
|
+ height: 20px;
|
|
|
+ /* 复选框高度 */
|
|
|
+}
|
|
|
+:deep(.el-checkbox.el-checkbox--small.is-checked .el-checkbox__inner::after) {
|
|
|
+ transform: scale(1.2) rotate(45deg);
|
|
|
+ /* 调整选中后的对勾大小 */
|
|
|
+ top: 5%;
|
|
|
+ /* 调整对勾位置 */
|
|
|
+ left: 40%;
|
|
|
+ /* 调整对勾位置 */
|
|
|
+ width: 5px;
|
|
|
+ /* 调整对勾宽度 */
|
|
|
+ height: 9px;
|
|
|
+ /* 调整对勾高度 */
|
|
|
+}
|
|
|
+
|
|
|
+/* 部件列表样式 */
|
|
|
+.part-list {
|
|
|
+ border: 1px solid #e0e0e0;
|
|
|
+ border-radius: 4px;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+
|
|
|
+.part-item {
|
|
|
+ padding: 15px;
|
|
|
+ border-bottom: 1px solid #f0f0f0;
|
|
|
+ cursor: pointer;
|
|
|
+ transition: all 0.3s ease;
|
|
|
+}
|
|
|
+
|
|
|
+.part-item:last-child {
|
|
|
+ border-bottom: none;
|
|
|
+}
|
|
|
+
|
|
|
+.part-item:hover {
|
|
|
+ background-color: #f5f7fa;
|
|
|
+}
|
|
|
+
|
|
|
+.part-item.selected {
|
|
|
+ background-color: #ecf5ff;
|
|
|
+ border-left: 4px solid #409EFF;
|
|
|
+}
|
|
|
+
|
|
|
+.part-info {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+}
|
|
|
+
|
|
|
+.part-number {
|
|
|
+ font-size: 14px;
|
|
|
+ color: #999;
|
|
|
+ margin-bottom: 5px;
|
|
|
+}
|
|
|
+
|
|
|
+.part-name {
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 500;
|
|
|
+}
|
|
|
+
|
|
|
+/* 员工网格样式 */
|
|
|
+.employee-grid {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: repeat(12, 1fr);
|
|
|
+ gap: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.employee-card {
|
|
|
+ border: 1px solid #e0e0e0;
|
|
|
+ border-radius: 12px;
|
|
|
+ padding: 10px;
|
|
|
+ text-align: center;
|
|
|
+ cursor: pointer;
|
|
|
+ transition: all 0.3s ease;
|
|
|
+}
|
|
|
+
|
|
|
+.employee-card:hover {
|
|
|
+ border-color: #409EFF;
|
|
|
+ box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
|
|
+}
|
|
|
+
|
|
|
+.employee-card.selected {
|
|
|
+ border-color: #67C23A;
|
|
|
+ background-color: #F0F9EB;
|
|
|
+}
|
|
|
+
|
|
|
+.employee-avatar {
|
|
|
+ width: 30px;
|
|
|
+ height: 30px;
|
|
|
+ border-radius: 50%;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ margin: 0 auto 8px;
|
|
|
+ font-size: 20px;
|
|
|
+ font-weight: bold;
|
|
|
+ color: white;
|
|
|
+}
|
|
|
+
|
|
|
+.employee-name {
|
|
|
+ font-size: 20px;
|
|
|
+ font-weight: 500;
|
|
|
+ margin-bottom: 3px;
|
|
|
+}
|
|
|
+
|
|
|
+.employee-id {
|
|
|
+ font-size: 16px;
|
|
|
+ color: #999;
|
|
|
+}
|
|
|
+
|
|
|
+</style>
|
|
|
+
|
|
|
+<style>
|
|
|
+/* 工分报工工艺表:选中/悬停整行粉色;完工人员、完工数量输入框保持白底 */
|
|
|
+.work-score-process-table .el-table__body tr.work-score-process-row-active > td.el-table__cell,
|
|
|
+.work-score-process-table .el-table__body tr.current-row > td.el-table__cell,
|
|
|
+.work-score-process-table .el-table__body tr:hover > td.el-table__cell {
|
|
|
+ background-color: #ff80ff !important;
|
|
|
+ background: #ff80ff !important;
|
|
|
+}
|
|
|
+.work-score-process-table .el-table__body tr.work-score-process-row-active .work-score-qty-input,
|
|
|
+.work-score-process-table .el-table__body tr.current-row .work-score-qty-input,
|
|
|
+.work-score-process-table .el-table__body tr:hover .work-score-qty-input,
|
|
|
+.work-score-process-table .el-table__body tr.work-score-process-row-active .work-score-staff-input,
|
|
|
+.work-score-process-table .el-table__body tr.current-row .work-score-staff-input,
|
|
|
+.work-score-process-table .el-table__body tr:hover .work-score-staff-input {
|
|
|
+ --el-input-bg-color: #ffffff;
|
|
|
+ --el-fill-color-blank: #ffffff;
|
|
|
+}
|
|
|
+.work-score-process-table .el-table__body tr.work-score-process-row-active .work-score-qty-input .el-input__wrapper,
|
|
|
+.work-score-process-table .el-table__body tr.current-row .work-score-qty-input .el-input__wrapper,
|
|
|
+.work-score-process-table .el-table__body tr:hover .work-score-qty-input .el-input__wrapper,
|
|
|
+.work-score-process-table .el-table__body tr.work-score-process-row-active .work-score-staff-input .el-input__wrapper,
|
|
|
+.work-score-process-table .el-table__body tr.current-row .work-score-staff-input .el-input__wrapper,
|
|
|
+.work-score-process-table .el-table__body tr:hover .work-score-staff-input .el-input__wrapper,
|
|
|
+.work-score-process-table .el-table__body tr.work-score-process-row-active .work-score-qty-input .el-input__wrapper.is-focus,
|
|
|
+.work-score-process-table .el-table__body tr.current-row .work-score-qty-input .el-input__wrapper.is-focus,
|
|
|
+.work-score-process-table .el-table__body tr:hover .work-score-qty-input .el-input__wrapper.is-focus,
|
|
|
+.work-score-process-table .el-table__body tr.work-score-process-row-active .work-score-staff-input .el-input__wrapper.is-focus,
|
|
|
+.work-score-process-table .el-table__body tr.current-row .work-score-staff-input .el-input__wrapper.is-focus,
|
|
|
+.work-score-process-table .el-table__body tr:hover .work-score-staff-input .el-input__wrapper.is-focus {
|
|
|
+ background-color: #ffffff !important;
|
|
|
+ background: #ffffff !important;
|
|
|
+}
|
|
|
+
|
|
|
+/* 确认报工弹窗:固定尺寸 + 内容居中放大(append-to-body 用全局样式) */
|
|
|
+.work-score-confirm-dialog.el-dialog,
|
|
|
+.work-score-confirm-dialog {
|
|
|
+ width: 1040px !important;
|
|
|
+ margin-top: 8vh !important;
|
|
|
+}
|
|
|
+.work-score-confirm-dialog .el-dialog__header {
|
|
|
+ padding: 12px 12px 6px;
|
|
|
+}
|
|
|
+.work-score-confirm-dialog .el-dialog__title {
|
|
|
+ font-size: 20px;
|
|
|
+ font-weight: 600;
|
|
|
+}
|
|
|
+.work-score-confirm-dialog .el-dialog__body {
|
|
|
+ padding: 4px 12px 4px;
|
|
|
+ height: 556px;
|
|
|
+ box-sizing: border-box;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+.work-score-confirm-dialog .work-score-confirm-tip {
|
|
|
+ margin: 0 0 6px;
|
|
|
+ text-align: center;
|
|
|
+ font-size: 18px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #303133;
|
|
|
+ line-height: 1.3;
|
|
|
+}
|
|
|
+.work-score-confirm-dialog .work-score-confirm-table {
|
|
|
+ font-size: 15px;
|
|
|
+ width: 100% !important;
|
|
|
+}
|
|
|
+.work-score-confirm-dialog .work-score-confirm-table .el-table__inner-wrapper::before {
|
|
|
+ display: none;
|
|
|
+}
|
|
|
+.work-score-confirm-dialog .work-score-confirm-table .el-table__header-wrapper,
|
|
|
+.work-score-confirm-dialog .work-score-confirm-table .el-table__body-wrapper {
|
|
|
+ overflow-x: hidden !important;
|
|
|
+}
|
|
|
+.work-score-confirm-dialog .work-score-confirm-table .el-scrollbar__bar.is-horizontal {
|
|
|
+ display: none !important;
|
|
|
+}
|
|
|
+.work-score-confirm-dialog .work-score-confirm-table .el-table__header th {
|
|
|
+ color: #000 !important;
|
|
|
+ font-weight: 600;
|
|
|
+ font-size: 15px;
|
|
|
+ padding: 4px 0 !important;
|
|
|
+ height: 32px !important;
|
|
|
+}
|
|
|
+.work-score-confirm-dialog .work-score-confirm-table .el-table__header th .cell {
|
|
|
+ color: #000 !important;
|
|
|
+ font-weight: 600;
|
|
|
+ line-height: 22px;
|
|
|
+ padding: 0 6px !important;
|
|
|
+}
|
|
|
+.work-score-confirm-dialog .work-score-confirm-table .el-table__body td {
|
|
|
+ font-size: 15px;
|
|
|
+ padding: 2px 0 !important;
|
|
|
+ height: 32px !important;
|
|
|
+}
|
|
|
+.work-score-confirm-dialog .work-score-confirm-table .cell {
|
|
|
+ line-height: 22px;
|
|
|
+ padding: 0 6px !important;
|
|
|
+}
|
|
|
+.work-score-confirm-dialog .work-score-confirm-table .el-table__header th.is-center,
|
|
|
+.work-score-confirm-dialog .work-score-confirm-table .el-table__body td.is-center {
|
|
|
+ text-align: center !important;
|
|
|
+}
|
|
|
+.work-score-confirm-dialog .work-score-confirm-table .el-table__header th.is-center .cell,
|
|
|
+.work-score-confirm-dialog .work-score-confirm-table .el-table__body td.is-center .cell {
|
|
|
+ text-align: center !important;
|
|
|
+ justify-content: center;
|
|
|
+}
|
|
|
+.work-score-confirm-dialog .work-score-confirm-table .el-table__header th.is-left,
|
|
|
+.work-score-confirm-dialog .work-score-confirm-table .el-table__body td.is-left {
|
|
|
+ text-align: left !important;
|
|
|
+}
|
|
|
+.work-score-confirm-dialog .work-score-confirm-table .el-table__header th.is-left .cell,
|
|
|
+.work-score-confirm-dialog .work-score-confirm-table .el-table__body td.is-left .cell {
|
|
|
+ text-align: left !important;
|
|
|
+ justify-content: flex-start;
|
|
|
+}
|
|
|
+.work-score-confirm-dialog .work-score-confirm-over-cell {
|
|
|
+ color: #f56c6c !important;
|
|
|
+ font-weight: 600;
|
|
|
+ font-size: 17px !important;
|
|
|
+}
|
|
|
+.work-score-confirm-dialog .el-dialog__footer {
|
|
|
+ padding: 8px 12px 12px;
|
|
|
+}
|
|
|
+.work-score-confirm-dialog .el-dialog__footer .el-button {
|
|
|
+ min-width: 100px;
|
|
|
+ font-size: 15px;
|
|
|
+}
|
|
|
+.work-score-confirm-dialog .el-table__body tr:hover > td {
|
|
|
+ background-color: var(--el-table-tr-bg-color, #fff) !important;
|
|
|
+}
|
|
|
+.work-score-confirm-dialog .el-table__body tr.el-table__row--striped:hover > td {
|
|
|
+ background-color: var(--el-fill-color-lighter, #fafafa) !important;
|
|
|
+}
|
|
|
+
|
|
|
+/* 修改数量弹窗:超出未完成数时数量变红 */
|
|
|
+.edit-reporting-qty-dialog .edit-reporting-qty-over .el-input__inner,
|
|
|
+.edit-reporting-qty-dialog .edit-reporting-qty-over .el-input__wrapper input {
|
|
|
+ color: #f56c6c !important;
|
|
|
+ font-weight: 600;
|
|
|
+}
|
|
|
+
|
|
|
+.custom-warning-message {
|
|
|
+ background: transparent !important;
|
|
|
+ border: none !important;
|
|
|
+ box-shadow: none !important;
|
|
|
+ padding: 0 !important;
|
|
|
+}
|
|
|
+
|
|
|
+.custom-warning-message .el-message__content {
|
|
|
+ padding: 0 !important;
|
|
|
+ line-height: 1 !important;
|
|
|
+}
|
|
|
+
|
|
|
+.custom-warning-message .el-message__icon {
|
|
|
+ display: none !important;
|
|
|
+}
|
|
|
+
|
|
|
+.custom-warning-message .el-message__closeBtn {
|
|
|
+ display: none !important;
|
|
|
+}
|
|
|
+.gongfen-unified-tip.el-message {
|
|
|
+ left: 50% !important;
|
|
|
+ transform: translateX(-50%) !important;
|
|
|
+ width: 520px !important;
|
|
|
+ min-width: 520px !important;
|
|
|
+ max-width: 520px !important;
|
|
|
+}
|
|
|
+
|
|
|
+.gy-detail-filter-popper {
|
|
|
+ z-index: 10050 !important;
|
|
|
+ pointer-events: auto;
|
|
|
+ padding: 8px 10px !important;
|
|
|
+}
|
|
|
+
|
|
|
+.gy-detail-filter-popper .gy-detail-filter-panel {
|
|
|
+ pointer-events: auto;
|
|
|
+}
|
|
|
+
|
|
|
+.gy-detail-filter-popper .gy-detail-filter-panel .el-checkbox {
|
|
|
+ display: flex;
|
|
|
+ margin-right: 0;
|
|
|
+ margin-bottom: 6px;
|
|
|
+}
|
|
|
+
|
|
|
+/* 工分报工删除确认:图标顶对齐,工序信息左对齐 */
|
|
|
+.gongfen-delete-confirm .el-message-box__container {
|
|
|
+ align-items: flex-start;
|
|
|
+}
|
|
|
+.gongfen-delete-confirm .el-message-box__status {
|
|
|
+ top: 2px;
|
|
|
+}
|
|
|
+.gongfen-delete-confirm .el-message-box__message {
|
|
|
+ padding-left: 0;
|
|
|
+ text-align: left;
|
|
|
+}
|
|
|
+.gongfen-delete-confirm .gongfen-delete-msg {
|
|
|
+ text-align: left;
|
|
|
+ line-height: 1.7;
|
|
|
+}
|
|
|
+.gongfen-delete-confirm .gongfen-delete-msg__row {
|
|
|
+ margin-top: 6px;
|
|
|
+}
|
|
|
+.gongfen-delete-confirm .gongfen-delete-msg__row strong {
|
|
|
+ color: #f56c6c;
|
|
|
+ font-weight: 600;
|
|
|
+}
|
|
|
+</style>
|