| | |
| | | <div class="panel-title-row"> |
| | | <div class="panel-title">生产订单进度</div> |
| | | <el-radio-group v-model="orderFilter" size="small"> |
| | | <el-radio-button label="all">全部({{ orderProgressMeta.total }})</el-radio-button> |
| | | <el-radio-button label="waiting">待开始({{ orderProgressMeta.waitingCount }})</el-radio-button> |
| | | <el-radio-button label="inProgress">进行中({{ orderProgressMeta.inProgressCount }})</el-radio-button> |
| | | <el-radio-button label="completed">已完成({{ orderProgressMeta.completedCount }})</el-radio-button> |
| | | <el-radio-button label="paused">已暂停({{ orderProgressMeta.pausedCount }})</el-radio-button> |
| | | <el-radio-button :value="'all'">全部({{ orderProgressMeta.total }})</el-radio-button> |
| | | <el-radio-button :value="'waiting'">待开始({{ orderProgressMeta.waitingCount }})</el-radio-button> |
| | | <el-radio-button :value="'inProgress'">进行中({{ orderProgressMeta.inProgressCount }})</el-radio-button> |
| | | <el-radio-button :value="'completed'">已完成({{ orderProgressMeta.completedCount }})</el-radio-button> |
| | | <el-radio-button :value="'paused'">已暂停({{ orderProgressMeta.pausedCount }})</el-radio-button> |
| | | </el-radio-group> |
| | | </div> |
| | | <el-table :data="filteredOrders" stripe> |
| | |
| | | <div v-if="visiblePanels.todo" class="cockpit-panel todo-panel"> |
| | | <div class="panel-title-row"> |
| | | <div class="panel-title">待办事项</div> |
| | | <span class="panel-more">更多</span> |
| | | <span class="panel-more" @click="goToApprovalProcess">更多</span> |
| | | </div> |
| | | <ul class="todo-list" v-if="todoList.length > 0"> |
| | | <li v-for="item in todoList" :key="item.id" class="todo-item"> |
| | |
| | | <div v-if="visiblePanels.realtime" class="cockpit-panel realtime-panel"> |
| | | <div class="panel-title-row"> |
| | | <div class="panel-title">生产实时看板</div> |
| | | <span class="panel-more">更多</span> |
| | | <span class="panel-more" @click="goToProductionOrder">更多</span> |
| | | </div> |
| | | <div class="realtime-grid"> |
| | | <div class="realtime-item" v-for="item in realtimeBoard" :key="item.key"> |
| | |
| | | <div v-if="visiblePanels.plan" class="cockpit-panel plan-panel"> |
| | | <div class="panel-title-row"> |
| | | <div class="panel-title">今日生产计划</div> |
| | | <span class="panel-more">{{ todayPlanTotal }}项</span> |
| | | <span class="panel-more" @click="goToProductionPlan">{{ todayPlanTotal }}项</span> |
| | | </div> |
| | | <ul class="plan-list"> |
| | | <li v-for="item in todayPlanList" :key="item.orderNo" class="plan-item"> |
| | |
| | | <div class="process-selection-wrapper"> |
| | | <el-checkbox-group v-model="tempProcessIds"> |
| | | <div class="process-grid"> |
| | | <el-checkbox v-for="item in processOptions" :key="item.id" :label="item.id" border> |
| | | <el-checkbox v-for="item in processOptions" :key="item.id" :value="item.id" border> |
| | | {{ item.name }} |
| | | </el-checkbox> |
| | | </div> |
| | |
| | | }); |
| | | |
| | | const realtimeBoardData = ref({ |
| | | deviceOee: { value: 0, compareYesterday: 0 }, |
| | | orderAchievementRate: { value: 0, compareYesterday: 0 }, |
| | | defectRate: { value: 0, compareYesterday: 0 }, |
| | | }); |
| | |
| | | }; |
| | | |
| | | const realtimeBoard = computed(() => { |
| | | const oee = Number(realtimeBoardData.value.deviceOee?.value || 0); |
| | | const orderAchievement = Number(realtimeBoardData.value.orderAchievementRate?.value || 0); |
| | | const defectRate = Number(realtimeBoardData.value.defectRate?.value || 0); |
| | | const oeeCompare = Number(realtimeBoardData.value.deviceOee?.compareYesterday || 0); |
| | | const orderCompare = Number(realtimeBoardData.value.orderAchievementRate?.compareYesterday || 0); |
| | | const defectCompare = Number(realtimeBoardData.value.defectRate?.compareYesterday || 0); |
| | | return [ |
| | | { |
| | | key: "oee", |
| | | label: "设备 OEE", |
| | | percent: clampPercent(oee), |
| | | display: `${oee.toFixed(2)}%`, |
| | | delta: getCompareText(oeeCompare), |
| | | trend: getCompareTrend(oeeCompare), |
| | | color: "#2d8cff", |
| | | }, |
| | | { |
| | | key: "order", |
| | | label: "订单达成率", |
| | |
| | | display: `${orderAchievement.toFixed(2)}%`, |
| | | delta: getCompareText(orderCompare), |
| | | trend: getCompareTrend(orderCompare), |
| | | color: "#31d2ff", |
| | | color: "#2d8cff", |
| | | }, |
| | | { |
| | | key: "defect", |
| | |
| | | const res = await productionRealtimeBoard(); |
| | | const data = res?.data || {}; |
| | | realtimeBoardData.value = { |
| | | deviceOee: { |
| | | value: Number(data.deviceOee?.value || 0), |
| | | compareYesterday: Number(data.deviceOee?.compareYesterday || 0), |
| | | }, |
| | | orderAchievementRate: { |
| | | value: Number(data.orderAchievementRate?.value || 0), |
| | | compareYesterday: Number(data.orderAchievementRate?.compareYesterday || 0), |
| | |
| | | }; |
| | | } catch { |
| | | realtimeBoardData.value = { |
| | | deviceOee: { value: 0, compareYesterday: 0 }, |
| | | orderAchievementRate: { value: 0, compareYesterday: 0 }, |
| | | defectRate: { value: 0, compareYesterday: 0 }, |
| | | }; |
| | |
| | | |
| | | const statisticsReceivable = async () => { |
| | | const res = await statisticsReceivablePayable({ type: 1 }); |
| | | const data = res?.data || {}; |
| | | const payableMoney = Number(data.payableMoney ?? 0); |
| | | const receivableMoney = Number(data.receivableMoney ?? 0); |
| | | barSeries.value[0].data = [ |
| | | { value: res.data.payableMoney, itemStyle: { color: barColors2[0] } }, |
| | | { value: res.data.receivableMoney, itemStyle: { color: barColors2[1] } }, |
| | | { value: payableMoney, itemStyle: { color: barColors2[0] } }, |
| | | { value: receivableMoney, itemStyle: { color: barColors2[1] } }, |
| | | ]; |
| | | }; |
| | | |
| | |
| | | barSeries1.value[0].data = []; |
| | | barSeries1.value[1].data = []; |
| | | barSeries1.value[2].data = []; |
| | | (res.data.item || []).forEach((item) => { |
| | | const data = res.data || {}; |
| | | (data.item || []).forEach((item) => { |
| | | xAxis1.value[0].data.push(item.date); |
| | | barSeries1.value[0].data.push(item.supplierNum); |
| | | barSeries1.value[1].data.push(item.processNum); |
| | | barSeries1.value[2].data.push(item.factoryNum); |
| | | }); |
| | | qualityStatisticsObject.value.supplierNum = res.data.supplierNum; |
| | | qualityStatisticsObject.value.processNum = res.data.processNum; |
| | | qualityStatisticsObject.value.factoryNum = res.data.factoryNum; |
| | | qualityStatisticsObject.value.supplierNum = data.supplierNum || 0; |
| | | qualityStatisticsObject.value.processNum = data.processNum || 0; |
| | | qualityStatisticsObject.value.factoryNum = data.factoryNum || 0; |
| | | }; |
| | | |
| | | const getAmountHalfYearNum = async () => { |
| | |
| | | const goToQuick = (path) => { |
| | | if (!path) return; |
| | | router.push(path).catch(() => {}); |
| | | }; |
| | | |
| | | const goToProductionOrder = () => { |
| | | router.push('/productionManagement/productionOrder').catch(() => {}); |
| | | }; |
| | | |
| | | const goToApprovalProcess = () => { |
| | | router.push('/collaborativeApproval/approvalProcess').catch(() => {}); |
| | | }; |
| | | |
| | | const goToProductionPlan = () => { |
| | | router.push('/productionManagement/productionPlan').catch(() => {}); |
| | | }; |
| | | |
| | | watch(orderFilter, () => { |
| | |
| | | .realtime-grid { |
| | | margin-top: 10px; |
| | | display: grid; |
| | | grid-template-columns: repeat(3, minmax(0, 1fr)); |
| | | grid-template-columns: repeat(2, minmax(0, 1fr)); |
| | | gap: 10px; |
| | | } |
| | | |
| | |
| | | border: 1px solid rgba(148, 163, 184, 0.2); |
| | | border-radius: 12px; |
| | | background: #f8fbff; |
| | | padding: 10px 8px; |
| | | padding: 16px 12px; |
| | | text-align: center; |
| | | } |
| | | |
| | | .realtime-value { |
| | | font-size: 26px; |
| | | font-size: 32px; |
| | | color: #0f172a; |
| | | font-weight: 700; |
| | | } |
| | |
| | | } |
| | | |
| | | .realtime-grid { |
| | | grid-template-columns: repeat(3, minmax(0, 1fr)); |
| | | grid-template-columns: repeat(2, minmax(0, 1fr)); |
| | | } |
| | | |
| | | .quality-cards { |