From ec226b03fbd26bc178137ad20d7bd030ef2c5c8b Mon Sep 17 00:00:00 2001
From: liding <756868258@qq.com>
Date: 星期三, 24 六月 2026 15:01:40 +0800
Subject: [PATCH] Merge branch 'refs/heads/dev_NEW_pro' into dev_宁夏_铭远环保
---
src/views/productionManagement/productStructure/DetailNew/MaterialCard.vue | 236 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 236 insertions(+), 0 deletions(-)
diff --git a/src/views/productionManagement/productStructure/DetailNew/MaterialCard.vue b/src/views/productionManagement/productStructure/DetailNew/MaterialCard.vue
new file mode 100644
index 0000000..f0ac5a6
--- /dev/null
+++ b/src/views/productionManagement/productStructure/DetailNew/MaterialCard.vue
@@ -0,0 +1,236 @@
+<template>
+ <div class="material-node">
+ <!-- 褰撳墠鑺傜偣鍗$墖 -->
+ <div :class="['node-card', isRoot ? 'root-card' : (row.nodeType === 'semiFinished' ? 'semi-finished-card' : 'child-card')]">
+ <div class="node-header">
+ <div class="node-label">
+ <el-tag :type="isRoot ? '' : (row.nodeType === 'semiFinished' ? 'warning' : 'success')" size="small" effect="dark">
+ {{ isRoot ? '鎴愬搧' : (row.nodeType === 'semiFinished' ? '鍗婃垚鍝�' : '鍘熸枡') }}
+ </el-tag>
+ <span class="node-title">{{ row.productName || '鏈�夋嫨浜у搧' }}</span>
+ <span v-if="row.model" class="node-sub">瑙勬牸: {{ row.model }}</span>
+ <span v-if="row.unit" class="node-sub">鍗曚綅: {{ row.unit }}</span>
+ </div>
+ <div class="node-actions">
+ <template v-if="editable && (isRoot || row.nodeType === 'semiFinished')">
+ <el-button type="primary"
+ text
+ size="small"
+ @click="handleAdd('semiFinished')">
+ + 娣诲姞鍗婃垚鍝�
+ </el-button>
+ <el-button type="primary"
+ text
+ size="small"
+ @click="handleAdd('rawMaterial')">
+ + 娣诲姞鍘熸枡
+ </el-button>
+ </template>
+ <el-button v-if="editable"
+ type="danger"
+ text
+ size="small"
+ @click="$emit('remove', row.tempId)">
+ 鍒犻櫎
+ </el-button>
+ </div>
+ </div>
+
+ <!-- 缂栬緫妯″紡涓嬬殑琛ㄥ崟 -->
+ <div v-if="editable" class="node-body">
+ <el-row :gutter="12">
+ <el-col :span="7">
+ <el-form-item label="浜у搧" :rules="[{ required: true, message: '璇烽�夋嫨浜у搧' }]" style="margin:0">
+ <el-input :model-value="row.productName || ''"
+ readonly
+ placeholder="鐐瑰嚮閫夋嫨浜у搧"
+ @click="openSelect"
+ style="width:100%">
+ <template #suffix>
+ <el-icon><component :is="SearchIcon" /></el-icon>
+ </template>
+ </el-input>
+ </el-form-item>
+ </el-col>
+ <el-col :span="5">
+ <el-form-item label="瑙勬牸" style="margin:0">
+ <el-select v-model="row.model"
+ placeholder="璇烽�夋嫨瑙勬牸"
+ clearable
+ style="width:100%"
+ @visible-change="(v:boolean) => { if (v) openSelect() }">
+ <el-option v-if="row.model" :label="row.model" :value="row.model" />
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col v-if="!isRoot" :span="5">
+ <el-form-item label="宸ュ簭" :rules="[{ required: true, message: '璇烽�夋嫨宸ュ簭' }]" style="margin:0">
+ <el-select v-model="row.processId"
+ placeholder="璇烽�夋嫨"
+ filterable
+ clearable
+ style="width:100%"
+ @change="(v:any) => $emit('processChange', row, v)">
+ <el-option v-for="item in processOptions"
+ :key="item.id"
+ :label="item.name"
+ :value="item.id" />
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :span="4">
+ <el-form-item label="鏁伴噺" :rules="[{ required: true, message: '璇峰~鍐欐暟閲�' }]" style="margin:0">
+ <el-input-number v-model="row.unitQuantity"
+ :min="0"
+ :precision="2"
+ :step="1"
+ controls-position="right"
+ style="width:100%"
+ @change="$emit('quantityChange')" />
+ </el-form-item>
+ </el-col>
+ <el-col :span="3">
+ <el-form-item label="鍗曚綅" style="margin:0">
+ <el-input v-model="row.unit" placeholder="鍗曚綅" clearable style="width:100%" />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ </div>
+
+ <!-- 闈炵紪杈戞ā寮忥細绠�娲佹樉绀� -->
+ <div v-else class="node-view">
+ <span v-if="!isRoot && row.processName">宸ュ簭: {{ row.processName }} | </span>
+ <span>鏁伴噺: {{ row.unitQuantity || '-' }}</span>
+ </div>
+ </div>
+
+ <!-- 閫掑綊娓叉煋瀛愯妭鐐� -->
+ <div v-if="row.children && row.children.length > 0" class="node-children">
+ <MaterialCard
+ v-for="child in row.children"
+ :key="child.tempId"
+ :row="child"
+ :depth="depth + 1"
+ :editable="editable"
+ :process-options="processOptions"
+ @remove="(id:string) => $emit('remove', id)"
+ @add="(id:string, nodeType:string) => $emit('add', id, nodeType)"
+ @select-product="(tempId: string, data: any) => $emit('selectProduct', tempId, data)"
+ @process-change="(row: any, v: any) => $emit('processChange', row, v)"
+ @quantity-change="$emit('quantityChange')"
+ />
+ </div>
+ </div>
+</template>
+
+<script setup lang="ts">
+import { computed } from 'vue'
+import { Search } from '@element-plus/icons-vue'
+
+const SearchIcon = Search
+
+const props = defineProps<{
+ row: any
+ depth: number
+ editable: boolean
+ processOptions: any[]
+}>()
+
+const emit = defineEmits<{
+ remove: [tempId: string]
+ add: [tempId: string, nodeType: string]
+ selectProduct: [tempId: string, data: any]
+ processChange: [row: any, value: any]
+ quantityChange: []
+}>()
+
+const isRoot = computed(() => props.depth === 0)
+
+const openSelect = () => {
+ emit('selectProduct', props.row.tempId, null)
+}
+
+const handleAdd = (nodeType: string) => {
+ emit('add', props.row.tempId, nodeType)
+}
+</script>
+
+<script lang="ts">
+export default { name: 'MaterialCard' }
+</script>
+
+<style scoped>
+.material-node {
+ margin: 4px 0;
+}
+
+.node-card {
+ border: 1px solid #e4e7ed;
+ border-radius: 8px;
+ overflow: hidden;
+}
+
+.root-card {
+ border-color: #409eff;
+ border-left: 4px solid #409eff;
+ background-color: #f0f5ff;
+}
+
+.child-card {
+ border-left: 4px solid #67c23a;
+ background-color: #f0f9eb;
+}
+
+.semi-finished-card {
+ border-left: 4px solid #e6a23c;
+ background-color: #fdf6ec;
+}
+
+.node-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 8px 12px;
+ background-color: rgba(0,0,0,0.03);
+ flex-wrap: wrap;
+ gap: 4px;
+}
+
+.node-label {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ flex-wrap: wrap;
+}
+
+.node-title {
+ font-weight: 600;
+ color: #303133;
+}
+
+.node-sub {
+ font-size: 12px;
+ color: #909399;
+}
+
+.node-actions {
+ display: flex;
+ gap: 4px;
+}
+
+.node-body {
+ padding: 10px 12px;
+}
+
+.node-view {
+ padding: 6px 12px;
+ font-size: 13px;
+ color: #606266;
+}
+
+.node-children {
+ margin-left: 36px;
+ padding-left: 16px;
+ border-left: 2px dashed #dcdfe6;
+}
+</style>
--
Gitblit v1.9.3