| | |
| | | <el-table-column prop="productName" label="产å大类" min-width="160" /> |
| | | <el-table-column prop="model" label="åå·åç§°" min-width="200" /> |
| | | <el-table-column prop="unit" label="åä½" min-width="160" /> |
| | | <el-table-column prop="materialCode" label="æå·" min-width="100" /> |
| | | </el-table> |
| | | |
| | | <div class="mt-3 flex justify-end"> |
| | |
| | | prop="model" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | | label="æå·" |
| | | prop="materialCode" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | | label="åä½" |
| | | prop="unit" |
| | |
| | | <tr> |
| | | <th>产ååç§°</th> |
| | | <th>è§æ ¼åå·</th> |
| | | <th>æå·</th> |
| | | <th>åä½</th> |
| | | <th>åä»·</th> |
| | | <th>é¶å®æ°é</th> |
| | |
| | | <tr> |
| | | <td>${item.productName || 'ç ç°ç '}</td> |
| | | <td>${item.model || 'æ å'}</td> |
| | | <td>${item.materialCode || ''}</td> |
| | | <td>${item.unit || 'å'}</td> |
| | | <td>${item.taxInclusiveUnitPrice || '0'}</td> |
| | | <td>${item.inboundNum || '2000'}</td> |
| | |
| | | <el-table-column label="è§æ ¼åå·" |
| | | prop="model" |
| | | show-overflow-tooltip/> |
| | | <el-table-column label="æå·" |
| | | prop="materialCode" |
| | | show-overflow-tooltip/> |
| | | <el-table-column label="åä½" |
| | | prop="unit" |
| | | show-overflow-tooltip/> |
| | |
| | | <el-table-column align="center" label="åºå·" type="index" width="60" /> |
| | | <el-table-column label="产å大类" prop="productName" show-overflow-tooltip /> |
| | | <el-table-column label="è§æ ¼åå·" prop="model" show-overflow-tooltip /> |
| | | <el-table-column label="æå·" prop="materialCode" show-overflow-tooltip /> |
| | | <el-table-column label="åä½" prop="unit" show-overflow-tooltip /> |
| | | <el-table-column label="åºåæ°é" prop="qualitity" show-overflow-tooltip /> |
| | | <el-table-column label="å»ç»æ°é" prop="lockedQuantity" show-overflow-tooltip /> |
| | |
| | | <el-table-column align="center" label="åºå·" type="index" width="60" /> |
| | | <el-table-column label="产å大类" prop="productName" show-overflow-tooltip /> |
| | | <el-table-column label="è§æ ¼åå·" prop="model" show-overflow-tooltip /> |
| | | <el-table-column label="æå·" prop="materialCode" show-overflow-tooltip /> |
| | | <el-table-column label="åä½" prop="unit" show-overflow-tooltip /> |
| | | <el-table-column label="åºåæ°é" prop="qualitity" show-overflow-tooltip /> |
| | | <el-table-column label="å»ç»æ°é" prop="lockedQuantity" show-overflow-tooltip /> |
| | |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | | label="æå·" |
| | | prop="materialCode" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | | label="åä½" |
| | | prop="unit" |
| | | show-overflow-tooltip |
| | |
| | | prop="specificationModel" /> |
| | | <el-table-column label="åä½" |
| | | prop="unit" /> |
| | | <el-table-column label="æå·" |
| | | prop="materialCode" /> |
| | | <el-table-column label="æ°é" |
| | | prop="quantity" /> |
| | | <el-table-column label="ç¨ç(%)" |
| | |
| | | prop="productCategory" /> |
| | | <el-table-column label="è§æ ¼åå·" |
| | | prop="specificationModel" /> |
| | | <el-table-column label="æå·" |
| | | prop="materialCode" /> |
| | | <el-table-column label="åä½" |
| | | prop="unit" |
| | | width="70" /> |
| | |
| | | :label="item.model" |
| | | :value="item.id" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | |
| | | <el-col :span="24"> |
| | | <el-form-item label="æå·ï¼" |
| | | prop="materialCode"> |
| | | <el-input v-model="productForm.materialCode" |
| | | placeholder="请è¾å
¥" |
| | | disabled /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | |
| | | productCategory: "", |
| | | productModelId: "", |
| | | specificationModel: "", |
| | | materialCode: "", |
| | | unit: "", |
| | | quantity: "", |
| | | taxInclusiveUnitPrice: "", |
| | |
| | | if (index !== -1) { |
| | | productForm.value.specificationModel = modelOptions.value[index].model; |
| | | productForm.value.unit = modelOptions.value[index].unit; |
| | | productForm.value.materialCode = modelOptions.value[index].materialCode; |
| | | } else { |
| | | productForm.value.specificationModel = null; |
| | | productForm.value.unit = null; |
| | | productForm.value.materialCode = null; |
| | | } |
| | | }; |
| | | const findNodeById = (nodes, productId) => { |
| | |
| | | prop: 'specificationModel', |
| | | }, |
| | | { |
| | | label: 'æå·', |
| | | prop: 'materialCode', |
| | | }, |
| | | { |
| | | label: 'éè´æ°é', |
| | | prop: 'purchaseNum', |
| | | width: 120, |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="large-screen"> |
| | | <div class="top-kpi-row"> |
| | | <div class="group-card group-card--wide"> |
| | | <div class="group-left"> |
| | | <div class="group-icon group-icon--order"></div> |
| | | </div> |
| | | <div class="group-right"> |
| | | <div class="group-metrics"> |
| | | <div class="metric metric--plain"> |
| | | <div class="metric-title">工忻æ°</div> |
| | | <div class="metric-value">{{ kpi.workOrderTotal }}<span class="unit">æ¡</span></div> |
| | | </div> |
| | | <div class="metric metric--plain"> |
| | | <div class="metric-title">è¿è¡ä¸å·¥å</div> |
| | | <div class="metric-value">{{ kpi.workOrderDoing }}<span class="unit">æ¡</span></div> |
| | | </div> |
| | | <div class="metric metric--plain"> |
| | | <div class="metric-title">宿工å</div> |
| | | <div class="metric-value">{{ kpi.workOrderDone }}<span class="unit">æ¡</span></div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="group-card group-card--wide"> |
| | | <div class="group-left"> |
| | | <div class="group-icon group-icon--quality"></div> |
| | | </div> |
| | | <div class="group-right"> |
| | | <div class="group-metrics"> |
| | | <div class="metric metric--plain"> |
| | | <div class="metric-title">åæ ¼ç</div> |
| | | <div class="metric-value">{{ kpi.passRate }}<span class="unit">%</span></div> |
| | | </div> |
| | | <div class="metric metric--plain"> |
| | | <div class="metric-title">ä¸è¯ç</div> |
| | | <div class="metric-value">{{ kpi.ngRate }}<span class="unit">%</span></div> |
| | | </div> |
| | | <div class="metric metric--plain"> |
| | | <div class="metric-title">æ»æ¥åºæ°</div> |
| | | <div class="metric-value">{{ kpi.scrapTotal }}<span class="unit">æ¡</span></div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="top-stat-row"> |
| | | <div class="stat-card stat-card--primary"> |
| | | <div class="stat-main"> |
| | | <div class="stat-value">{{ formatMoney(kpi.productionAmount) }}<span class="unit1">å¨</span></div> |
| | | <div class="stat-title">æ»ç产æ»é</div> |
| | | <div class="stat-sub"> |
| | | <span>è¾ä¸æè¶å¿ï¼</span> |
| | | <span class="trend" :class="kpi.productionAmountTrend >= 0 ? 'up' : 'down'"> |
| | | {{ kpi.productionAmountTrend >= 0 ? '+' : '' }}{{ kpi.productionAmountTrend }}% |
| | | </span> |
| | | <svg |
| | | class="trend-arrow-svg" |
| | | :class="[ |
| | | kpi.productionAmountTrend >= 0 ? '' : 'trend-arrow-svg--up', |
| | | kpi.productionAmountTrend >= 0 ? 'is-up' : 'is-down' |
| | | ]" |
| | | viewBox="0 0 16 10" |
| | | aria-hidden="true" |
| | | > |
| | | <path d="M1 2 L6 7 L10 3 L15 3" /> |
| | | <path d="M13 1 L15 3 L13 5" /> |
| | | </svg> |
| | | </div> |
| | | </div> |
| | | <div class="stat-primary-decor"></div> |
| | | </div> |
| | | |
| | | <div class="stat-card"> |
| | | <div class="stat-main"> |
| | | <div class="stat-value">{{ formatMoney(kpi.productionCost) }}<span class="unit">å¨</span></div> |
| | | <div class="stat-title">çäº§æ»æ¶è</div> |
| | | <div class="stat-sub"> |
| | | <span>è¾ä¸æè¶å¿ï¼</span> |
| | | <span class="trend" :class="kpi.productionCostTrend >= 0 ? 'up' : 'down'"> |
| | | {{ kpi.productionCostTrend >= 0 ? '+' : '' }}{{ kpi.productionCostTrend }}% |
| | | </span> |
| | | <svg |
| | | class="trend-arrow-svg" |
| | | :class="[ |
| | | kpi.productionCostTrend >= 0 ? '' : 'trend-arrow-svg--up', |
| | | kpi.productionCostTrend >= 0 ? 'is-up' : 'is-down' |
| | | ]" |
| | | viewBox="0 0 16 10" |
| | | aria-hidden="true" |
| | | > |
| | | <path d="M1 2 L6 7 L10 3 L15 3" /> |
| | | <path d="M13 1 L15 3 L13 5" /> |
| | | </svg> |
| | | </div> |
| | | </div> |
| | | <div class="stat-icon stat-icon--cost"></div> |
| | | </div> |
| | | |
| | | <div class="stat-card"> |
| | | <div class="stat-main"> |
| | | <div class="stat-value">{{ kpi.supplierCount }}<span class="unit">å®¶</span></div> |
| | | <div class="stat-title">äº§åæ»ä¾åºå
¬å¸</div> |
| | | <div class="stat-sub"> |
| | | <span>è¾ä¸æè¶å¿ï¼</span> |
| | | <span class="trend" :class="kpi.supplierCountTrend >= 0 ? 'up' : 'down'"> |
| | | {{ kpi.supplierCountTrend >= 0 ? '+' : '' }}{{ kpi.supplierCountTrend }}% |
| | | </span> |
| | | <svg |
| | | class="trend-arrow-svg" |
| | | :class="[ |
| | | kpi.supplierCountTrend >= 0 ? '' : 'trend-arrow-svg--up', |
| | | kpi.supplierCountTrend >= 0 ? 'is-up' : 'is-down' |
| | | ]" |
| | | viewBox="0 0 16 10" |
| | | aria-hidden="true" |
| | | > |
| | | <path d="M1 2 L6 7 L10 3 L15 3" /> |
| | | <path d="M13 1 L15 3 L13 5" /> |
| | | </svg> |
| | | </div> |
| | | </div> |
| | | <div class="stat-icon stat-icon--supplier"></div> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="mid-row"> |
| | | <div class="panel panel--rect"> |
| | | <div class="panel-header"> |
| | | <div class="panel-title">产å产åºåæ</div> |
| | | </div> |
| | | <div class="panel-body"> |
| | | <div class="product-pie-wrapper"> |
| | | <Echarts |
| | | :chartStyle="chartStyle" |
| | | :legend="categoryPieLegend" |
| | | :tooltip="categoryPieTooltip" |
| | | :series="categoryPieSeries" |
| | | :xAxis="[]" |
| | | :yAxis="[]" |
| | | :color="categoryPieColors" |
| | | :options="transparentOptions" |
| | | style="height: 100%" |
| | | /> |
| | | </div> |
| | | <div class="category-cards"> |
| | | <div v-for="(it, idx) in categoryPieData" :key="it.name" class="category-card"> |
| | | <div class="category-name">产å大类{{ idx + 1 }}</div> |
| | | <div class="category-val">{{ it.value }}</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="panel panel--rect"> |
| | | <div class="panel-header"> |
| | | <div class="panel-title">ä¸è¯åå ç»è®¡åæ</div> |
| | | </div> |
| | | <div class="panel-body"> |
| | | <div class="ng-layout"> |
| | | <div class="ng-list"> |
| | | <div class="ng-list-head"> |
| | | <div class="ng-col ng-col--name">ä¸è¯åå </div> |
| | | <div class="ng-col ng-col--pct">å æ¯</div> |
| | | <div class="ng-col ng-col--val">æ°é</div> |
| | | </div> |
| | | <div class="ng-list-body"> |
| | | <div v-for="(row, idx) in ngRows" :key="row.name" class="ng-row"> |
| | | <div class="ng-col ng-col--name"> |
| | | <span class="ng-dot" :style="{ backgroundColor: ngColors[idx % ngColors.length] }"></span> |
| | | <span class="ng-name">{{ row.name }}</span> |
| | | </div> |
| | | <div class="ng-col ng-col--pct">{{ row.percent }}%</div> |
| | | <div class="ng-col ng-col--val">{{ row.value }}</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="ng-chart"> |
| | | <div class="donut-wrap"> |
| | | <Echarts |
| | | :chartStyle="chartStyle" |
| | | :legend="{ show: false }" |
| | | :tooltip="pieTooltip" |
| | | :series="pieSeries" |
| | | :color="ngColors" |
| | | :xAxis="[]" |
| | | :yAxis="[]" |
| | | :options="transparentOptions" |
| | | style="height: 100%" |
| | | /> |
| | | <div class="donut-center"> |
| | | <div class="donut-label">ä¸è¯åå </div> |
| | | <div class="donut-value">{{ formatMoney(ngTotal) }}</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="bottom-row"> |
| | | <div class="panel panel-full"> |
| | | <div class="panel-header"> |
| | | <div class="panel-title">å·¥åºä¸è¯åå åæ</div> |
| | | <div class="panel-actions"> |
| | | <div class="panel-action">年份</div> |
| | | <el-date-picker |
| | | v-model="currentYear" |
| | | type="year" |
| | | format="YYYYå¹´" |
| | | value-format="YYYY" |
| | | :clearable="false" |
| | | class="panel-year-picker" |
| | | size="small" |
| | | /> |
| | | </div> |
| | | </div> |
| | | <div class="panel-body"> |
| | | <div class="bottom-chart-wrap"> |
| | | <div class="chart-unit">åä½ï¼%</div> |
| | | <Echarts |
| | | :chartStyle="{ width: '100%', height: '260px' }" |
| | | :grid="lineGrid" |
| | | :legend="lineLegend" |
| | | :tooltip="axisTooltip" |
| | | :xAxis="lineXAxis" |
| | | :yAxis="lineYAxis" |
| | | :series="lineSeries" |
| | | :options="transparentOptions" |
| | | style="height: 100%" |
| | | /> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { computed, ref } from 'vue' |
| | | import * as echarts from 'echarts' |
| | | import Echarts from '@/components/Echarts/echarts.vue' |
| | | import { ElSelect, ElOption, ElDatePicker } from 'element-plus' |
| | | |
| | | const chartStyle = { width: '100%', height: '100%' } |
| | | const transparentOptions = { |
| | | backgroundColor: 'transparent', |
| | | textStyle: { color: '#3a3a3a' }, |
| | | } |
| | | |
| | | const kpi = ref({ |
| | | workOrderTotal: 378, |
| | | workOrderDoing: 108, |
| | | workOrderDone: 238, |
| | | passRate: 98, |
| | | ngRate: 8, |
| | | scrapTotal: 38, |
| | | productionAmount: 989878, |
| | | productionAmountTrend: 16, |
| | | productionQty: 19878, |
| | | productionQtyTrend: 16, |
| | | productionCost: 69878, |
| | | productionCostTrend: -16, |
| | | supplierCount: 48, |
| | | supplierCountTrend: 16, |
| | | totalOutput: 1000, |
| | | }) |
| | | |
| | | const currentYear = ref('2025') |
| | | |
| | | function formatMoney(n) { |
| | | const num = Number(n || 0) |
| | | return num.toLocaleString('zh-CN', { maximumFractionDigits: 0 }) |
| | | } |
| | | |
| | | const axisTooltip = { |
| | | trigger: 'axis', |
| | | axisPointer: { type: 'shadow' }, |
| | | formatter: (params) => { |
| | | const first = params?.[0] |
| | | const x = first?.axisValueLabel || '' |
| | | const lines = [`${x}`] |
| | | params.forEach((p) => { |
| | | if (!p) return |
| | | const name = p.seriesName |
| | | const v = p.data |
| | | lines.push(`${name}: ${v}`) |
| | | }) |
| | | return lines.join('<br/>') |
| | | }, |
| | | } |
| | | |
| | | // ä¸é¨å·¦ä¾§ï¼é¥¼ç¶å¾ï¼æäº§å大类ç»è®¡äº§åºæ°éï¼ |
| | | const categoryPieColors = ['#2D5BFF', '#4E8AFF', '#00A4ED', '#26C6DA', '#7C3AED', '#F59E0B', '#EF4444', '#10B981'] |
| | | const categoryPieData = ref([ |
| | | { name: '产å大类1', value: 600 }, |
| | | { name: '产å大类2', value: 200 }, |
| | | { name: '产å大类3', value: 200 }, |
| | | { name: '产å大类4', value: 200 }, |
| | | { name: '产å大类5', value: 200 }, |
| | | ]) |
| | | |
| | | const categoryPieLegend = computed(() => { |
| | | // 设计å¾ä¸é¥¼å¾æ¬èº«æ¾ç¤ºå æ¯æ ç¾ï¼ä¸é¢å¤å±ç¤ºå¾ä¾ |
| | | return { |
| | | show: false, |
| | | data: categoryPieData.value.map((d) => d.name), |
| | | } |
| | | }) |
| | | |
| | | const categoryPieTooltip = { |
| | | trigger: 'item', |
| | | formatter: (p) => `${p.marker} ${p.name}<br/>äº§åºæ°éï¼${p.value}<br/>å æ¯ï¼${p.percent}%`, |
| | | } |
| | | |
| | | const categoryPieSeries = computed(() => [ |
| | | { |
| | | name: 'äº§åºæ°é', |
| | | type: 'pie', |
| | | radius: ['40%', '68%'], |
| | | center: ['50%', '45%'], |
| | | avoidLabelOverlap: false, |
| | | label: { |
| | | show: true, |
| | | formatter: (p) => `${p.name} ${p.percent}%`, |
| | | color: '#6b7280', |
| | | fontSize: 12, |
| | | }, |
| | | labelLine: { |
| | | show: true, |
| | | lineStyle: { color: '#e5e7eb' }, |
| | | length: 16, |
| | | length2: 20, |
| | | }, |
| | | data: categoryPieData.value, |
| | | emphasis: { |
| | | scale: true, |
| | | scaleSize: 8, |
| | | }, |
| | | }, |
| | | ]) |
| | | |
| | | // ä¸é¨å³ä¾§ï¼ç¯å½¢é¥¼å¾ |
| | | const ngColors = ['#2D5BFF', '#26C6DA', '#F59E0B', '#7C3AED', '#60A5FA', '#10B981'] |
| | | |
| | | const ngReasonData = ref([ |
| | | { name: 'ä¸è¯åå 1', value: 300 }, |
| | | { name: 'ä¸è¯åå 3', value: 200 }, |
| | | { name: 'ä¸è¯åå 4', value: 100 }, |
| | | { name: 'ä¸è¯åå 5', value: 100 }, |
| | | { name: 'ä¸è¯åå 6', value: 100 }, |
| | | ]) |
| | | |
| | | const ngTotal = computed(() => ngReasonData.value.reduce((s, it) => s + Number(it.value || 0), 0)) |
| | | const ngRows = computed(() => { |
| | | const total = ngTotal.value || 0 |
| | | return ngReasonData.value.map((it) => { |
| | | const v = Number(it.value || 0) |
| | | const p = total ? Math.round((v / total) * 100) : 0 |
| | | return { name: it.name, value: v, percent: p } |
| | | }) |
| | | }) |
| | | |
| | | const pieTooltip = { |
| | | trigger: 'item', |
| | | formatter: (p) => `${p.marker} ${p.name}ï¼${p.value}ï¼${p.percent}%ï¼`, |
| | | } |
| | | const pieSeries = computed(() => [ |
| | | { |
| | | name: 'ä¸è¯åå ', |
| | | type: 'pie', |
| | | radius: ['52%', '76%'], |
| | | center: ['50%', '50%'], |
| | | avoidLabelOverlap: true, |
| | | label: { show: false }, |
| | | labelLine: { show: false }, |
| | | data: ngReasonData.value, |
| | | }, |
| | | ]) |
| | | |
| | | // åºé¨ï¼æçº¿å¾ï¼å¹´ä»½èå¨çæ¯ä¸ªå·¥åºä¸è¯çï¼ |
| | | const lineGrid = { left: '4%', right: '4%', top: 60, bottom: 30, containLabel: true } |
| | | const lineLegend = computed(() => { |
| | | return { |
| | | show: true, |
| | | top: 8, |
| | | textStyle: { color: '#666' }, |
| | | data: ['å¹³åä¸è¯ç', 'å·¥åºA', 'å·¥åºB', 'å·¥åºC'], |
| | | } |
| | | }) |
| | | |
| | | const chartDataByYear = { |
| | | '2023': { |
| | | x: ['2023/02/21', '2023/03/02', '2023/03/13', '2023/03/24', '2023/04/04', '2023/04/15', '2023/04/28'], |
| | | bar: [30, 32, 35, 40, 38, 42, 39], |
| | | lineA: [45, 48, 52, 60, 55, 62, 58], |
| | | lineB: [30, 32, 38, 45, 40, 48, 42], |
| | | lineC: [20, 24, 30, 35, 32, 38, 33], |
| | | }, |
| | | '2024': { |
| | | x: ['2024/02/21', '2024/03/02', '2024/03/13', '2024/03/24', '2024/04/04', '2024/04/15', '2024/04/28'], |
| | | bar: [28, 30, 33, 37, 35, 39, 36], |
| | | lineA: [42, 46, 50, 58, 53, 60, 56], |
| | | lineB: [28, 31, 36, 43, 38, 46, 40], |
| | | lineC: [18, 21, 27, 33, 29, 35, 30], |
| | | }, |
| | | '2025': { |
| | | x: ['2025/02/21', '2025/03/02', '2025/03/13', '2025/03/24', '2025/04/04', '2025/04/15', '2025/04/28'], |
| | | bar: [32, 34, 37, 42, 40, 45, 41], |
| | | lineA: [45, 49, 54, 61, 57, 64, 60], |
| | | lineB: [31, 33, 39, 47, 41, 50, 44], |
| | | lineC: [21, 25, 31, 37, 34, 40, 35], |
| | | }, |
| | | } |
| | | |
| | | const chartData = computed(() => { |
| | | return chartDataByYear[currentYear.value] || chartDataByYear['2025'] |
| | | }) |
| | | |
| | | const lineXAxis = computed(() => { |
| | | return [ |
| | | { |
| | | type: 'category', |
| | | data: chartData.value.x, |
| | | axisTick: { show: false }, |
| | | axisLabel: { color: '#666' }, |
| | | }, |
| | | ] |
| | | }) |
| | | |
| | | const lineYAxis = computed(() => { |
| | | return [ |
| | | { |
| | | type: 'value', |
| | | axisLabel: { color: '#666' }, |
| | | splitLine: { lineStyle: { color: 'rgba(0,0,0,0.06)' } }, |
| | | name: 'ä¸è¯ç(%)', |
| | | }, |
| | | ] |
| | | }) |
| | | |
| | | const lineSeries = computed(() => [ |
| | | { |
| | | name: 'å¹³åä¸è¯ç', |
| | | type: 'bar', |
| | | barWidth: 18, |
| | | data: chartData.value.bar, |
| | | itemStyle: { |
| | | color: 'rgba(59, 130, 246, 0.15)', |
| | | borderRadius: [4, 4, 0, 0], |
| | | }, |
| | | }, |
| | | { |
| | | name: 'å·¥åºA', |
| | | type: 'line', |
| | | smooth: true, |
| | | data: chartData.value.lineA, |
| | | symbol: 'circle', |
| | | symbolSize: 6, |
| | | lineStyle: { width: 2, color: '#3b82f6' }, |
| | | itemStyle: { color: '#3b82f6' }, |
| | | }, |
| | | { |
| | | name: 'å·¥åºB', |
| | | type: 'line', |
| | | smooth: true, |
| | | data: chartData.value.lineB, |
| | | symbol: 'circle', |
| | | symbolSize: 6, |
| | | lineStyle: { width: 2, color: '#f59e0b' }, |
| | | itemStyle: { color: '#f59e0b' }, |
| | | }, |
| | | { |
| | | name: 'å·¥åºC', |
| | | type: 'line', |
| | | smooth: true, |
| | | data: chartData.value.lineC, |
| | | symbol: 'circle', |
| | | symbolSize: 6, |
| | | lineStyle: { width: 2, color: '#10b981' }, |
| | | itemStyle: { color: '#10b981' }, |
| | | }, |
| | | ]) |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .large-screen { |
| | | padding: 18px 20px; |
| | | background: #f5f7fb; |
| | | } |
| | | |
| | | .top-kpi-row { |
| | | display: grid; |
| | | grid-template-columns: 1fr 1fr; |
| | | gap: 12px; |
| | | } |
| | | |
| | | .top-stat-row { |
| | | margin-top: 12px; |
| | | display: grid; |
| | | grid-template-columns: 1fr 1fr 1fr; |
| | | gap: 12px; |
| | | } |
| | | |
| | | .group-card { |
| | | background: #fff; |
| | | border-radius: 8px; |
| | | padding: 14px 16px; |
| | | box-shadow: 0 6px 22px rgba(16, 24, 40, 0.08); |
| | | border: 1px solid rgba(2, 6, 23, 0.06); |
| | | display: grid; |
| | | grid-template-columns: 120px 1fr; |
| | | min-height: 112px; |
| | | } |
| | | |
| | | .group-card--wide { |
| | | grid-column: span 1; |
| | | } |
| | | |
| | | .group-left { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | |
| | | .group-icon { |
| | | width: 110px; |
| | | height: 110px; |
| | | border-radius: 18px; |
| | | background: transparent; |
| | | border: 0; |
| | | position: relative; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .group-icon::before { |
| | | content: none; |
| | | } |
| | | |
| | | .group-icon::after { |
| | | content: ''; |
| | | position: absolute; |
| | | inset: 0; |
| | | border-radius: 999px; |
| | | background-size: contain; |
| | | background-position: center; |
| | | background-repeat: no-repeat; |
| | | } |
| | | |
| | | .group-icon--order::after { |
| | | background-image: url('@/assets/BI/kpiIcons/kpi-dataBoard.png'); |
| | | } |
| | | |
| | | .group-icon--quality::after { |
| | | background-image: url('@/assets/BI/kpiIcons/kpi-shield.png'); |
| | | } |
| | | |
| | | .group-right { |
| | | display: flex; |
| | | align-items: center; |
| | | padding-left: 60px; |
| | | } |
| | | |
| | | .group-metrics { |
| | | display: grid; |
| | | grid-template-columns: repeat(3, 1fr); |
| | | gap: 18px; |
| | | width: 100%; |
| | | } |
| | | |
| | | .metric { |
| | | background: transparent; |
| | | border: 0; |
| | | border-radius: 0; |
| | | padding: 0; |
| | | } |
| | | |
| | | .metric--plain .metric-title { |
| | | font-weight: 400; |
| | | font-size: 16px; |
| | | color: #111827; |
| | | line-height: 1.1; |
| | | } |
| | | |
| | | .metric-value { |
| | | margin-top: 10px; |
| | | font-size: 30px; |
| | | font-weight: 400; |
| | | color: #111827; |
| | | line-height: 1; |
| | | letter-spacing: 0.5px; |
| | | } |
| | | |
| | | .metric-sub { |
| | | margin-top: 10px; |
| | | font-size: 12px; |
| | | color: rgba(2, 6, 23, 0.58); |
| | | } |
| | | |
| | | .unit { |
| | | margin-left: 4px; |
| | | font-size: 12px; |
| | | font-weight: 600; |
| | | color: rgba(2, 6, 23, 0.55); |
| | | } |
| | | .unit1 { |
| | | margin-left: 4px; |
| | | font-size: 12px; |
| | | font-weight: 600; |
| | | color: #fff; |
| | | } |
| | | |
| | | .stat-card { |
| | | background: #fff; |
| | | border-radius: 8px; |
| | | padding: 14px 18px; |
| | | box-shadow: 0 6px 22px rgba(16, 24, 40, 0.08); |
| | | border: 1px solid rgba(2, 6, 23, 0.06); |
| | | display: grid; |
| | | grid-template-columns: 1fr 58px; |
| | | column-gap: 12px; |
| | | align-items: center; |
| | | min-height: 116px; |
| | | } |
| | | |
| | | .stat-card--primary { |
| | | background: linear-gradient(135deg, #2f6bff 0%, #3a87ff 100%); |
| | | border-color: rgba(47, 107, 255, 0.18); |
| | | color: #fff; |
| | | grid-template-columns: 1fr 1fr; |
| | | position: relative; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .stat-card--primary .stat-title, |
| | | .stat-card--primary .stat-sub, |
| | | .stat-card--primary .stat-value, |
| | | .stat-card--primary .trend { |
| | | color: #fff; |
| | | } |
| | | |
| | | .stat-card--primary .trend.up, |
| | | .stat-card--primary .trend.down { |
| | | color: #fff; |
| | | } |
| | | |
| | | .stat-card--primary .trend-arrow-svg.is-up { |
| | | color: #fff; |
| | | } |
| | | |
| | | .stat-card--primary .trend-arrow-svg.is-down { |
| | | color: #fff; |
| | | } |
| | | |
| | | .stat-primary-decor { |
| | | width: 100%; |
| | | height: 100%; |
| | | border-radius: 12px; |
| | | position: relative; |
| | | } |
| | | |
| | | .stat-primary-decor::after { |
| | | content: none; |
| | | } |
| | | |
| | | .stat-card--primary::after { |
| | | content: ''; |
| | | position: absolute; |
| | | right: -12px; |
| | | bottom: -22px; |
| | | width: 120px; |
| | | height: 120px; |
| | | background-image: url('@/assets/BI/kpiIcons/kpi-cartCutout.png'); |
| | | background-repeat: no-repeat; |
| | | background-position: right bottom; |
| | | background-size: contain; |
| | | opacity: 0.95; |
| | | pointer-events: none; |
| | | } |
| | | |
| | | .stat-main { |
| | | display: flex; |
| | | flex-direction: column; |
| | | } |
| | | |
| | | .stat-title { |
| | | margin-top: 8px; |
| | | font-size: 13px; |
| | | color: rgba(17, 24, 39, 0.86); |
| | | } |
| | | |
| | | .stat-value { |
| | | font-size: 38px; |
| | | font-weight: 400; |
| | | color: #111827; |
| | | line-height: 1; |
| | | letter-spacing: 0.2px; |
| | | } |
| | | |
| | | .currency-sign { |
| | | font-size: 0.58em; |
| | | margin-right: 2px; |
| | | vertical-align: 8%; |
| | | } |
| | | |
| | | .stat-sub { |
| | | margin-top: 10px; |
| | | font-size: 12px; |
| | | color: rgba(17, 24, 39, 0.75); |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 4px; |
| | | } |
| | | |
| | | .trend { |
| | | font-size: 20px; |
| | | font-weight: 400; |
| | | color: #16a34a; |
| | | } |
| | | .trend.up { |
| | | color: #16a34a; |
| | | } |
| | | .trend.down { |
| | | color: #dc2626; |
| | | } |
| | | |
| | | .trend-arrow-svg { |
| | | width: 17px; |
| | | height: 11px; |
| | | margin-left: 3px; |
| | | stroke: currentColor; |
| | | fill: none; |
| | | stroke-width: 1.8; |
| | | stroke-linecap: round; |
| | | stroke-linejoin: round; |
| | | } |
| | | |
| | | .trend-arrow-svg--up { |
| | | transform: scaleY(-1); |
| | | transform-origin: center; |
| | | } |
| | | |
| | | .trend-arrow-svg.is-up { |
| | | color: #16a34a; |
| | | } |
| | | |
| | | .trend-arrow-svg.is-down { |
| | | color: #dc2626; |
| | | } |
| | | |
| | | |
| | | .stat-icon { |
| | | width: 54px; |
| | | height: 54px; |
| | | border-radius: 999px; |
| | | border: 1px solid rgba(2, 6, 23, 0.04); |
| | | box-shadow: 0 4px 10px rgba(2, 6, 23, 0.08), inset 0 2px 10px rgba(255, 255, 255, 0.55); |
| | | } |
| | | |
| | | .stat-card--blue .stat-icon { |
| | | background: rgba(255, 255, 255, 0.22); |
| | | border-color: rgba(255, 255, 255, 0.25); |
| | | } |
| | | |
| | | .stat-icon--money { |
| | | background: radial-gradient(circle at 30% 30%, rgba(255, 255, 255, 0.85), rgba(255, 255, 255, 0.12) 45%), |
| | | linear-gradient(135deg, rgba(255, 183, 77, 0.22), rgba(255, 171, 64, 0.4)); |
| | | } |
| | | .stat-icon--qty { |
| | | background: transparent; |
| | | border: 0; |
| | | box-shadow: none; |
| | | background-image: url('@/assets/BI/kpiIcons/kpi-dataBoard.png'); |
| | | background-size: contain; |
| | | background-position: center; |
| | | background-repeat: no-repeat; |
| | | } |
| | | .stat-icon--cost { |
| | | background: transparent; |
| | | border: 0; |
| | | box-shadow: none; |
| | | background-image: url('@/assets/BI/kpiIcons/kpi-dbIcon.png'); |
| | | background-size: contain; |
| | | background-position: center; |
| | | background-repeat: no-repeat; |
| | | } |
| | | .stat-icon--supplier { |
| | | background: transparent; |
| | | border: 0; |
| | | box-shadow: none; |
| | | background-image: url('@/assets/BI/kpiIcons/kpi-cloud.png'); |
| | | background-size: contain; |
| | | background-position: center; |
| | | background-repeat: no-repeat; |
| | | } |
| | | |
| | | .mid-row { |
| | | margin-top: 14px; |
| | | display: grid; |
| | | grid-template-columns: 1fr 1fr; |
| | | gap: 14px; |
| | | align-items: stretch; |
| | | } |
| | | |
| | | .bottom-row { |
| | | margin-top: 14px; |
| | | } |
| | | |
| | | .panel { |
| | | background: #fff; |
| | | border-radius: 10px; |
| | | box-shadow: 0 4px 18px rgba(20, 28, 47, 0.06); |
| | | border: 1px solid rgba(20, 28, 47, 0.06); |
| | | overflow: hidden; |
| | | display: flex; |
| | | flex-direction: column; |
| | | min-height: 360px; |
| | | } |
| | | |
| | | .panel--rect { |
| | | border-radius: 0; |
| | | } |
| | | |
| | | .panel-full { |
| | | min-height: 320px; |
| | | } |
| | | |
| | | .panel-header { |
| | | padding: 12px 14px; |
| | | border-bottom: 1px solid rgba(2, 6, 23, 0.06); |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | } |
| | | |
| | | .panel-actions { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 8px; |
| | | font-size: 12px; |
| | | color: rgba(2, 6, 23, 0.6); |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | .panel-select { |
| | | min-width: 88px; |
| | | } |
| | | |
| | | :deep(.panel-select .el-select__wrapper) { |
| | | width: 88px; |
| | | } |
| | | |
| | | :deep(.panel-select .el-select__selected-text) { |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | .panel-title { |
| | | font-weight: 800; |
| | | color: #030303; |
| | | font-size: 14px; |
| | | letter-spacing: 1px; |
| | | position: relative; |
| | | padding-left: 10px; |
| | | } |
| | | |
| | | .panel-title::before { |
| | | content: ''; |
| | | position: absolute; |
| | | left: 0; |
| | | top: 50%; |
| | | transform: translateY(-50%); |
| | | width: 3px; |
| | | height: 14px; |
| | | border-radius: 999px; |
| | | background: #0047ff; |
| | | } |
| | | |
| | | .panel-subtitle { |
| | | margin-top: 6px; |
| | | font-size: 13px; |
| | | color: rgba(2, 6, 23, 0.58); |
| | | } |
| | | |
| | | .panel-body { |
| | | padding: 12px 14px 14px; |
| | | flex: 1; |
| | | min-height: 280px; |
| | | position: relative; |
| | | display: flex; |
| | | flex-direction: column; |
| | | } |
| | | |
| | | .bottom-chart-wrap { |
| | | width: 90%; |
| | | margin: 0 auto; |
| | | } |
| | | |
| | | .product-pie-wrapper { |
| | | flex: 0 0 260px; |
| | | } |
| | | |
| | | .chart-unit { |
| | | font-size: 12px; |
| | | color: rgba(107, 114, 128, 1); |
| | | margin-bottom: 4px; |
| | | } |
| | | .category-cards { |
| | | margin-top: 18px; |
| | | display: grid; |
| | | grid-template-columns: repeat(5, 1fr); |
| | | gap: 12px; |
| | | } |
| | | |
| | | .category-card { |
| | | height: 64px; |
| | | background: #f9fafb; |
| | | border-radius: 6px; |
| | | padding: 10px 14px; |
| | | display: flex; |
| | | flex-direction: column; |
| | | justify-content: center; |
| | | } |
| | | |
| | | .category-name { |
| | | font-size: 13px; |
| | | color: rgba(17, 24, 39, 0.7); |
| | | } |
| | | |
| | | .category-val { |
| | | margin-top: 6px; |
| | | font-size: 14px; |
| | | color: rgba(17, 24, 39, 0.9); |
| | | } |
| | | |
| | | .donut-wrap { |
| | | position: relative; |
| | | height: 100%; |
| | | } |
| | | |
| | | .donut-center { |
| | | position: absolute; |
| | | left: 50%; |
| | | top: 50%; |
| | | transform: translate(-50%, -50%); |
| | | text-align: center; |
| | | pointer-events: none; |
| | | } |
| | | |
| | | .donut-label { |
| | | font-size: 12px; |
| | | color: rgba(2, 6, 23, 0.58); |
| | | } |
| | | |
| | | .donut-value { |
| | | margin-top: 6px; |
| | | font-size: 28px; |
| | | font-weight: 900; |
| | | color: #111827; |
| | | } |
| | | |
| | | .ng-layout { |
| | | display: grid; |
| | | grid-template-columns: 1.15fr 0.85fr; |
| | | gap: 14px; |
| | | height: 100%; |
| | | } |
| | | |
| | | .ng-list { |
| | | padding: 8px 10px; |
| | | background: #f7f8fb; |
| | | border-radius: 6px; |
| | | } |
| | | |
| | | .ng-list-title { |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | | color: rgba(2, 6, 23, 0.75); |
| | | margin: 4px 0 10px; |
| | | } |
| | | |
| | | .ng-list-head { |
| | | display: grid; |
| | | grid-template-columns: 1fr 64px 64px; |
| | | gap: 6px; |
| | | padding: 10px 8px 8px; |
| | | border-radius: 0; |
| | | background: transparent; |
| | | color: rgba(2, 6, 23, 0.6); |
| | | font-size: 13px; |
| | | font-weight: 400; |
| | | border-bottom: 1px solid rgba(2, 6, 23, 0.08); |
| | | } |
| | | |
| | | .ng-list-body { |
| | | margin-top: 2px; |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 0; |
| | | } |
| | | |
| | | .ng-row { |
| | | display: grid; |
| | | grid-template-columns: 1fr 64px 64px; |
| | | gap: 6px; |
| | | padding: 12px 8px; |
| | | border-radius: 0; |
| | | border: 0; |
| | | border-bottom: 1px dashed rgba(2, 6, 23, 0.14); |
| | | background: transparent; |
| | | } |
| | | |
| | | .ng-col { |
| | | display: flex; |
| | | align-items: center; |
| | | font-size: 18px; |
| | | color: rgba(2, 6, 23, 0.72); |
| | | } |
| | | |
| | | .ng-col--pct, |
| | | .ng-col--val { |
| | | justify-content: flex-end; |
| | | font-variant-numeric: tabular-nums; |
| | | } |
| | | |
| | | .ng-col--val { |
| | | font-weight: 400; |
| | | color: rgba(2, 6, 23, 0.86); |
| | | } |
| | | |
| | | .ng-dot { |
| | | width: 7px; |
| | | height: 7px; |
| | | border-radius: 999px; |
| | | margin-right: 8px; |
| | | } |
| | | |
| | | .ng-name { |
| | | font-weight: 400; |
| | | color: rgba(2, 6, 23, 0.78); |
| | | } |
| | | |
| | | .ng-col--pct, |
| | | .ng-col--val { |
| | | font-size: 20px; |
| | | color: rgba(2, 6, 23, 0.82); |
| | | } |
| | | |
| | | .ng-chart { |
| | | height: 100%; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | |
| | | .ng-chart .donut-wrap { |
| | | width: 100%; |
| | | max-width: 360px; |
| | | height: 320px; |
| | | } |
| | | |
| | | @media (max-width: 1100px) { |
| | | .ng-layout { |
| | | grid-template-columns: 1fr; |
| | | } |
| | | .donut-wrap :deep(canvas) { |
| | | margin: 0 auto; |
| | | } |
| | | } |
| | | |
| | | @media (max-width: 1600px) { |
| | | /* ä¿®å¤æ§å¸å±æ®çï¼é¿å
å¼ºè¡ span å¯¼è´ top-kpi/top-stat ç½æ ¼éä½ */ |
| | | .top-stat-row { |
| | | grid-template-columns: 1fr 1fr 1fr; |
| | | } |
| | | .top-kpi-row { |
| | | grid-template-columns: 1fr 1fr; |
| | | } |
| | | } |
| | | |
| | | @media (max-width: 1100px) { |
| | | .mid-row { |
| | | grid-template-columns: 1fr; |
| | | } |
| | | } |
| | | </style> |
| | |
| | | prop: "model", |
| | | }, |
| | | { |
| | | label: "æå·", |
| | | prop: "materialCode", |
| | | }, |
| | | { |
| | | label: "BOMç¼å·", |
| | | prop: "bomNo", |
| | | }, |
| | |
| | | processRouteCode: row.processRouteCode || '', |
| | | productName: row.productName || '', |
| | | model: row.model || '', |
| | | materialCode: row.materialCode || '', |
| | | bomNo: row.bomNo || '', |
| | | description: row.description || '', |
| | | type: 'route', |
| | |
| | | </div> |
| | | <div class="info-item"> |
| | | <div class="info-label-wrapper"> |
| | | <span class="info-label">æå·</span> |
| | | </div> |
| | | <div class="info-value-wrapper"> |
| | | <span class="info-value">{{ routeInfo.materialCode || '-' }}</span> |
| | | </div> |
| | | </div> |
| | | <div class="info-item"> |
| | | <div class="info-label-wrapper"> |
| | | <span class="info-label">BOMç¼å·</span> |
| | | </div> |
| | | <div class="info-value-wrapper"> |
| | |
| | | </el-table-column> |
| | | <el-table-column label="产ååç§°" prop="productName" min-width="160" /> |
| | | <el-table-column label="è§æ ¼åç§°" prop="model" min-width="140" /> |
| | | <el-table-column label="æå·" prop="materialCode" min-width="140" /> |
| | | <el-table-column label="åä½" prop="unit" width="100" /> |
| | | <el-table-column label="æ¯å¦è´¨æ£" prop="isQuality" width="100"> |
| | | <template #default="scope"> |
| | |
| | | processRouteCode: '', |
| | | productName: '', |
| | | model: '', |
| | | materialCode: '', |
| | | bomNo: '', |
| | | description: '' |
| | | }); |
| | |
| | | processRouteCode: route.query.processRouteCode || '', |
| | | productName: route.query.productName || '', |
| | | model: route.query.model || '', |
| | | materialCode: route.query.materialCode || '', |
| | | bomNo: route.query.bomNo || '', |
| | | description: route.query.description || '' |
| | | }; |
| | |
| | | </el-form-item> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="materialCode" |
| | | label="æå·" /> |
| | | <el-table-column prop="processName" |
| | | label="æ¶èå·¥åº"> |
| | | <template #default="{ row, $index }"> |
| | |
| | | prop="productName" /> |
| | | <el-table-column label="è§æ ¼åå·" |
| | | prop="model" /> |
| | | <el-table-column label="æå·" |
| | | prop="materialCode" /> |
| | | </el-table> |
| | | <product-select-dialog v-if="dataValue.showProductDialog" |
| | | v-model:model-value="dataValue.showProductDialog" |
| | |
| | | const routeProductModelName = computed( |
| | | () => route.query.productModelName || "" |
| | | ); |
| | | const routeMaterialCode = computed(() => route.query.materialCode || ""); |
| | | const routeOrderId = computed(() => route.query.orderId); |
| | | const pageType = computed(() => route.query.type); |
| | | const isOrderPage = computed( |
| | |
| | | { |
| | | productName: "", |
| | | model: "", |
| | | materialCode: "", |
| | | bomNo: "", |
| | | }, |
| | | ]); |
| | |
| | | if (isTopLevel) { |
| | | if ( |
| | | productData.productName === tableData[0].productName && |
| | | productData.model === tableData[0].model |
| | | productData.model === tableData[0].model && |
| | | productData.materialCode === tableData[0].materialCode |
| | | ) { |
| | | // æ¥æ¾æ¯å¦å·²ç»æå
¶ä»é¡¶å±è¡å·²ç»æ¯è¿ä¸ªäº§å |
| | | const hasOther = dataValue.dataList.some( |
| | |
| | | if (item.tempId === dataValue.currentRowName) { |
| | | item.productName = productData.productName; |
| | | item.model = productData.model; |
| | | item.materialCode = productData.materialCode; |
| | | item.productModelId = productData.id; |
| | | item.unit = productData.unit || ""; |
| | | return; |
| | |
| | | if (item.tempId === tempId) { |
| | | item.productName = productData.productName; |
| | | item.model = productData.model; |
| | | item.materialCode = productData.materialCode; |
| | | item.productModelId = productData.id; |
| | | item.unit = productData.unit || ""; |
| | | return true; |
| | |
| | | // ä»è·¯ç±åæ°åæ¾æ°æ® |
| | | tableData[0].productName = routeProductName.value as string; |
| | | tableData[0].model = routeProductModelName.value as string; |
| | | tableData[0].materialCode = routeMaterialCode.value as string; |
| | | tableData[0].bomNo = routeBomNo.value as string; |
| | | |
| | | // 订åæ
åµä¸ç¦ç¨ç¼è¾ |
| | |
| | | minWidth: 140 |
| | | }, |
| | | { |
| | | label: "æå·", |
| | | prop: "materialCode", |
| | | minWidth: 100 |
| | | }, |
| | | { |
| | | label: "çæ¬å·", |
| | | prop: "version", |
| | | width: 100 |
| | |
| | | id: row.id, |
| | | bomNo: row.bomNo || '', |
| | | productName: row.productName || '', |
| | | materialCode: row.materialCode || '', |
| | | productModelName: row.productModelName || '' |
| | | } |
| | | }); |
| | |
| | | prop: "productModelName", |
| | | minWidth: 100, |
| | | }, |
| | | { |
| | | label: "æå·", |
| | | prop: "materialCode", |
| | | minWidth: 100, |
| | | }, |
| | | { |
| | | label: "åä½", |
| | | prop: "unit", |
| | |
| | | <span class="mr12">ç产æ¹å·ï¼{{ header.lotNo || "-" }}</span> |
| | | <span class="mr12">产ååç§°ï¼{{ header.productCategory || "-" }}</span> |
| | | <span class="mr12">è§æ ¼ï¼{{ header.specificationModel || "-" }}</span> |
| | | <span class="mr12">æå·ï¼{{ header.materialCode || "-" }}</span> |
| | | </div> |
| | | </div> |
| | | </el-card> |
| | |
| | | lotNo: route.query.lotNo, |
| | | productCategory: route.query.productCategory, |
| | | specificationModel: route.query.specificationModel, |
| | | materialCode: route.query.materialCode, |
| | | })); |
| | | |
| | | // å·¥åºæ°æ®ï¼æ¥å£æ¿æ¢ï¼ |
| | |
| | | </el-form-item> |
| | | |
| | | <el-form-item |
| | | label="æå·" |
| | | prop="materialCode" |
| | | > |
| | | <el-input v-model="formState.materialCode" disabled /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item |
| | | label="åä½" |
| | | prop="unit" |
| | | > |
| | |
| | | routeId: undefined, |
| | | productName: "", |
| | | productModelName: "", |
| | | materialCode: "", |
| | | unit: "", |
| | | priority: undefined, |
| | | quantity: 0, |
| | |
| | | productName: "", |
| | | productModelName: "", |
| | | unit: "", |
| | | materialCode: "", |
| | | priority: priority_type.value && priority_type.value.length > 0 ? priority_type.value[2].value : undefined, |
| | | quantity: '', |
| | | lotNo: "", |
| | |
| | | formState.value.productModelName = product.model; |
| | | formState.value.productModelId = product.id; |
| | | formState.value.unit = product.unit; |
| | | formState.value.materialCode = product.materialCode || ""; |
| | | showProductSelectDialog.value = false; |
| | | fetchRouteOptions( product.id); |
| | | // 触å表åéªè¯æ´æ° |
| | |
| | | width: '120px', |
| | | }, |
| | | { |
| | | label: "æå·", |
| | | prop: "materialCode", |
| | | width: '120px', |
| | | }, |
| | | { |
| | | label: "å·¥èºè·¯çº¿ç¼å·", |
| | | prop: "processRouteCode", |
| | | width: '200px', |
| | |
| | | processRouteCode: data.processRouteCode || "", |
| | | productName: data.productName || "", |
| | | model: data.model || "", |
| | | materialCode: data.materialCode || "", |
| | | bomNo: data.bomNo || "", |
| | | description: data.description || "", |
| | | orderId, |
| | |
| | | bomNo: row.bomNo || "", |
| | | productName: row.productCategory || "", |
| | | productModelName: row.specificationModel || "", |
| | | materialCode: row.materialCode || "", |
| | | orderId: row.id, |
| | | type: "order", |
| | | }, |
| | |
| | | lotNo: row.lotNo || "", |
| | | productCategory: row.productCategory || "", |
| | | specificationModel: row.specificationModel || "", |
| | | materialCode: row.materialCode || "", |
| | | }, |
| | | }); |
| | | }; |
| | |
| | | prop: 'model', |
| | | }, |
| | | { |
| | | label: 'æå
¥æå·', |
| | | prop: 'materialCode', |
| | | }, |
| | | { |
| | | label: 'æå
¥æ°é', |
| | | prop: 'quantity', |
| | | }, |
| | |
| | | <el-descriptions-item label="å·¥åç¼å·">{{ row.workOrderNo || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="产ååç§°">{{ row.productName || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="产åè§æ ¼åå·">{{ row.productModelName || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="æå·">{{ row.materialCode || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="äº§åºæ°é">{{ row.quantity || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="æ¥åºæ°é">{{ row.scrapQty || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="åä½">{{ row.unit || '-' }}</el-descriptions-item> |
| | |
| | | width: 120, |
| | | }, |
| | | { |
| | | label: "æå·", |
| | | prop: "materialCode", |
| | | width: 120, |
| | | }, |
| | | { |
| | | label: "äº§åºæ°é", |
| | | prop: "quantity", |
| | | width: 120, |
| | |
| | | <span class="info-label">产åè§æ ¼</span> |
| | | <span class="info-value">{{ transferCardRowData.model }}</span> |
| | | </div> |
| | | <div class="info-item"> |
| | | <span class="info-label">æå·</span> |
| | | <span class="info-value">{{ transferCardRowData.materialCode }}</span> |
| | | </div> |
| | | <!-- <div class="info-item"> |
| | | <span class="info-label">å·¥åç¶æ</span> |
| | | <span class="info-value">{{ |
| | |
| | | prop: "model", |
| | | }, |
| | | { |
| | | label: "æå·", |
| | | prop: "materialCode", |
| | | }, |
| | | { |
| | | label: "åä½", |
| | | prop: "unit", |
| | | }, |
| | |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="åä½ï¼" prop="unit"> |
| | | <el-input v-model="form.unit" placeholder="请è¾å
¥" disabled/> |
| | | <el-form-item label="æå·ï¼" prop="materialCode"> |
| | | <el-input v-model="form.materialCode" placeholder="请è¾å
¥" disabled/> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ä¸è¯æ°éï¼" prop="defectiveQuantity"> |
| | | <el-input v-model="form.defectiveQuantity" placeholder="请è¾å
¥" clearable/> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="åä½ï¼" prop="unit"> |
| | | <el-input v-model="form.unit" placeholder="请è¾å
¥" disabled/> |
| | | </el-form-item> |
| | | </el-col> |
| | | |
| | | <el-col :span="12"> |
| | | <el-form-item label="åæ ¼æ°éï¼" prop="qualifiedQuantity"> |
| | | <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="form.qualifiedQuantity" placeholder="请è¾å
¥" clearable :precision="2" disabled/> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | |
| | | </el-col> |
| | | |
| | | <el-col :span="12"> |
| | | <el-form-item label="åæ ¼æ°éï¼" prop="qualifiedQuantity"> |
| | | <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="form.qualifiedQuantity" placeholder="请è¾å
¥" clearable :precision="2" disabled/> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ£æµåä½ï¼" prop="checkCompany"> |
| | | <el-input v-model="form.checkCompany" placeholder="请è¾å
¥" clearable/> |
| | | </el-form-item> |
| | |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ£éªåï¼" prop="checkName"> |
| | | <el-select v-model="form.checkName" placeholder="è¯·éæ©" clearable> |
| | | <el-option v-for="item in userList" :key="item.nickName" :label="item.nickName" |
| | | :value="item.nickName"/> |
| | | </el-select> |
| | | <el-select v-model="form.checkName" placeholder="è¯·éæ©" clearable> |
| | | <el-option v-for="item in userList" :key="item.nickName" :label="item.nickName" |
| | | :value="item.nickName"/> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | |
| | | testStandardId: "", |
| | | defectiveReason: undefined, |
| | | unit: "", |
| | | materialCode: "", |
| | | qualifiedQuantity: "", |
| | | quantity: "", |
| | | checkCompany: "", |
| | |
| | | if (selectedModel) { |
| | | form.value.model = selectedModel.model || ''; |
| | | form.value.unit = selectedModel.unit || ''; |
| | | form.value.materialCode = selectedModel.materialCode || ''; |
| | | } |
| | | } |
| | | |
| | |
| | | const getModels = (value) => { |
| | | form.value.productModelId = undefined; |
| | | form.value.unit = undefined; |
| | | form.value.materialCode = undefined; |
| | | modelOptions.value = []; |
| | | currentProductId.value = value |
| | | form.value.productName = findNodeById(productOptions.value, value); |
| | |
| | | const handleChangeModel = (value) => { |
| | | form.value.model = modelOptions.value.find(item => item.id == value)?.model || ''; |
| | | form.value.unit = modelOptions.value.find(item => item.id == value)?.unit || ''; |
| | | form.value.materialCode = modelOptions.value.find(item => item.id == value)?.materialCode || ''; |
| | | } |
| | | |
| | | const findNodeById = (nodes, productId) => { |
| | |
| | | prop: "model", |
| | | }, |
| | | { |
| | | label: "æå·", |
| | | prop: "materialCode", |
| | | }, |
| | | { |
| | | label: "åä½", |
| | | prop: "unit", |
| | | }, |
| | |
| | | <el-col :span="12"> |
| | | <el-form-item label="ææ éæ©ï¼" prop="testStandardId"> |
| | | <el-select |
| | | v-model="form.testStandardId" |
| | | placeholder="è¯·éæ©ææ " |
| | | clearable |
| | | @change="handleTestStandardChange" |
| | | style="width: 100%" |
| | | v-model="form.testStandardId" |
| | | placeholder="è¯·éæ©ææ " |
| | | clearable |
| | | @change="handleTestStandardChange" |
| | | style="width: 100%" |
| | | > |
| | | <el-option |
| | | v-for="item in testStandardOptions" |
| | | :key="item.id" |
| | | :label="item.standardName || item.standardNo" |
| | | :value="item.id" |
| | | v-for="item in testStandardOptions" |
| | | :key="item.id" |
| | | :label="item.standardName || item.standardNo" |
| | | :value="item.id" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="åä½ï¼" prop="unit"> |
| | | <el-input v-model="form.unit" placeholder="请è¾å
¥" disabled/> |
| | | <el-form-item label="æå·ï¼" prop="materialCode"> |
| | | <el-input v-model="form.materialCode" placeholder="请è¾å
¥" disabled/> |
| | | </el-form-item> |
| | | </el-col> |
| | | |
| | | <el-col :span="12"> |
| | | <el-form-item label="ä¸è¯æ°éï¼" prop="defectiveQuantity"> |
| | | <el-input-number |
| | |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | |
| | | <el-col :span="12"> |
| | | <el-form-item label="åä½ï¼" prop="unit"> |
| | | <el-input v-model="form.unit" placeholder="请è¾å
¥" disabled/> |
| | | </el-form-item> |
| | | </el-col> |
| | | |
| | | <el-col :span="12"> |
| | | <el-form-item label="åæ ¼æ°éï¼" prop="qualifiedQuantity"> |
| | | <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="form.qualifiedQuantity" placeholder="请è¾å
¥" clearable :precision="2" disabled/> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ°éï¼" prop="quantity"> |
| | | <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="form.quantity" placeholder="请è¾å
¥" clearable :precision="2" :disabled="operationType !== 'add'"/> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | |
| | | <el-col :span="12"> |
| | | <el-form-item label="ä¸è¯åå ï¼" prop="defectiveReason"> |
| | | <el-select v-model="form.defectiveReason" placeholder="è¯·éæ©" clearable style="width: 100%"> |
| | |
| | | </el-form-item> |
| | | |
| | | </el-col> |
| | | |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ°éï¼" prop="quantity"> |
| | | <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="form.quantity" placeholder="请è¾å
¥" clearable :precision="2" :disabled="operationType !== 'add'"/> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ£æµåä½ï¼" prop="checkCompany"> |
| | | <el-input v-model="form.checkCompany" placeholder="请è¾å
¥" clearable/> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ£éªåï¼" prop="checkName"> |
| | | <el-select v-model="form.checkName" placeholder="è¯·éæ©" clearable> |
| | |
| | | :value="item.nickName"/> |
| | | </el-select> |
| | | </el-form-item> |
| | | |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ£æµç»æï¼" prop="checkResult"> |
| | | <el-select v-model="form.checkResult"> |
| | | <el-option label="åæ ¼" value="åæ ¼" /> |
| | | <el-option label="ä¸åæ ¼" value="ä¸åæ ¼" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ£æµæ¥æï¼" prop="checkTime"> |
| | |
| | | model: "", |
| | | testStandardId: "", |
| | | unit: "", |
| | | materialCode: "", |
| | | quantity: "", |
| | | defectiveQuantity: "", |
| | | defectiveReason: "", |
| | |
| | | model: "", |
| | | testStandardId: "", |
| | | unit: "", |
| | | materialCode: "", |
| | | quantity: "", |
| | | checkCompany: "", |
| | | checkResult: "", |
| | |
| | | const getModels = (value) => { |
| | | form.value.productModelId = undefined; |
| | | form.value.unit = undefined; |
| | | form.value.materialCode = undefined; |
| | | modelOptions.value = []; |
| | | currentProductId.value = value |
| | | form.value.productName = findNodeById(productOptions.value, value); |
| | |
| | | const handleChangeModel = (value) => { |
| | | form.value.model = modelOptions.value.find(item => item.id == value)?.model || ''; |
| | | form.value.unit = modelOptions.value.find(item => item.id == value)?.unit || ''; |
| | | form.value.materialCode = modelOptions.value.find(item => item.id == value)?.materialCode || ''; |
| | | } |
| | | |
| | | const findNodeById = (nodes, productId) => { |
| | |
| | | prop: "model", |
| | | }, |
| | | { |
| | | label: "æå·", |
| | | prop: "materialCode", |
| | | }, |
| | | { |
| | | label: "åä½", |
| | | prop: "unit", |
| | | }, |
| | |
| | | <el-table-column label="产å大类" prop="productCategory" /> |
| | | <el-table-column label="è§æ ¼åå·" prop="specificationModel" /> |
| | | <el-table-column label="åä½" prop="unit" /> |
| | | <el-table-column label="æå·" prop="materialCode" /> |
| | | <el-table-column label="产åç¶æ" |
| | | width="100px" |
| | | align="center"> |
| | |
| | | <el-table-column label="产å大类" prop="productCategory" /> |
| | | <el-table-column label="è§æ ¼åå·" prop="specificationModel" /> |
| | | <el-table-column label="åä½" prop="unit" /> |
| | | <el-table-column label="æå·" prop="materialCode" /> |
| | | <el-table-column label="æ°é" prop="quantity" /> |
| | | <el-table-column label="ç¨ç(%)" prop="taxRate" /> |
| | | <el-table-column label="å«ç¨åä»·(å
)" prop="taxInclusiveUnitPrice" :formatter="formattedNumber" /> |
| | |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="24"> |
| | | <el-form-item label="æå·ï¼" |
| | | prop="materialCode"> |
| | | <el-input v-model="productForm.materialCode" |
| | | placeholder="请è¾å
¥" |
| | | disabled /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | |
| | | <thead> |
| | | <tr> |
| | | <th>åºå·</th> |
| | | <th>ç©æç¼å·</th> |
| | | <th>æå·</th> |
| | | <th>åå/è§æ ¼</th> |
| | | <th>åä½</th> |
| | | <th>æ°é</th> |
| | |
| | | productForm: { |
| | | productCategory: "", |
| | | specificationModel: "", |
| | | materialCode: "", |
| | | unit: "", |
| | | quantity: "", |
| | | taxInclusiveUnitPrice: "", |
| | |
| | | if (index !== -1) { |
| | | productForm.value.specificationModel = modelOptions.value[index].model; |
| | | productForm.value.unit = modelOptions.value[index].unit; |
| | | productForm.value.materialCode = modelOptions.value[index].materialCode; |
| | | } else { |
| | | productForm.value.specificationModel = null; |
| | | productForm.value.unit = null; |
| | | productForm.value.materialCode = null; |
| | | } |
| | | }; |
| | | const findNodeById = (nodes, productId) => { |
| | |
| | | <thead> |
| | | <tr> |
| | | <th>åºå·</th> |
| | | <th>ç©æç¼å·</th> |
| | | <th>æå·</th> |
| | | <th>åå/è§æ ¼</th> |
| | | <th>åä½</th> |
| | | <th>æ°é</th> |