| | |
| | | </div> |
| | | |
| | | <el-form :model="form" label-width="120px" :rules="rules" ref="formRef"> |
| | | <div style="width: 350px; margin-bottom: 12px; margin-left: 120px;"> |
| | | <el-select |
| | | v-model="selectedEngineeringId" |
| | | placeholder="选择工程号(选择后自动填充玻璃ID)" |
| | | clearable |
| | | filterable |
| | | :disabled="!group" |
| | | :loading="engineeringListLoading" |
| | | @change="handleEngineeringChange" |
| | | style="width: 100%" |
| | | > |
| | | <el-option |
| | | v-for="item in engineeringList" |
| | | :key="item.engineeringId" |
| | | :label="item.engineeringId" |
| | | :value="item.engineeringId" |
| | | > |
| | | <div style="display: flex; justify-content: space-between; align-items: center; width: 100%;"> |
| | | <div style="flex: 1;"> |
| | | <span>{{ item.engineeringId }}</span> |
| | | <span style="margin-left: 8px; color: #8492a6; font-size: 12px"> |
| | | {{ item.date ? new Date(item.date).toLocaleDateString() : '' }} |
| | | </span> |
| | | </div> |
| | | <el-button |
| | | type="danger" |
| | | link |
| | | size="small" |
| | | :loading="deletingEngineeringId === item.engineeringId" |
| | | @click.stop="handleDeleteEngineering(item.engineeringId)" |
| | | style="margin-left: 8px; padding: 0 4px;" |
| | | > |
| | | <el-icon><Delete /></el-icon> |
| | | </el-button> |
| | | </div> |
| | | </el-option> |
| | | </el-select> |
| | | </div> |
| | | |
| | | <el-form-item label="玻璃ID列表" prop="glassIds"> |
| | | <el-input |
| | | v-model="glassIdsInput" |
| | | type="textarea" |
| | | :rows="4" |
| | | placeholder="可选:输入玻璃ID,将使用输入的ID进行测试" |
| | | placeholder="可选:输入玻璃ID,将使用输入的ID进行测试(或通过上方选择工程号自动填充)" |
| | | show-word-limit |
| | | :maxlength="5000" |
| | | /> |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { computed, reactive, ref, watch } from 'vue' |
| | | import { ElMessage } from 'element-plus' |
| | | import { computed, reactive, ref, watch, onMounted } from 'vue' |
| | | import { ElMessage, ElMessageBox } from 'element-plus' |
| | | import { Delete, Promotion, Upload } from '@element-plus/icons-vue' |
| | | import * as XLSX from 'xlsx' |
| | | import { multiDeviceTaskApi } from '@/api/device/multiDeviceTask' |
| | |
| | | const loadDeviceLoading = ref(false) |
| | | const fileInputRef = ref(null) |
| | | |
| | | // 工程号相关 |
| | | const selectedEngineeringId = ref('') |
| | | const engineeringList = ref([]) |
| | | const engineeringListLoading = ref(false) |
| | | const glassIdsLoading = ref(false) |
| | | const deletingEngineeringId = ref('') |
| | | |
| | | watch( |
| | | () => props.group, |
| | | () => { |
| | | glassIdsInput.value = '' |
| | | selectedEngineeringId.value = '' |
| | | fetchLoadDevice() |
| | | fetchEngineeringList() |
| | | } |
| | | ) |
| | | |
| | | // 组件挂载时加载工程号列表 |
| | | onMounted(() => { |
| | | fetchEngineeringList() |
| | | }) |
| | | |
| | | const glassIds = computed(() => { |
| | | if (!glassIdsInput.value) return [] |
| | |
| | | .map((item) => item.trim()) |
| | | .filter((item) => item.length > 0) |
| | | }) |
| | | |
| | | // 获取工程号列表 |
| | | const fetchEngineeringList = async () => { |
| | | try { |
| | | engineeringListLoading.value = true |
| | | const response = await engineeringApi.getEngineeringList() |
| | | |
| | | if (Array.isArray(response)) { |
| | | engineeringList.value = response |
| | | } else if (Array.isArray(response?.data)) { |
| | | engineeringList.value = response.data |
| | | } else { |
| | | engineeringList.value = [] |
| | | } |
| | | // 按日期倒序排列 |
| | | engineeringList.value.sort((a, b) => { |
| | | const dateA = a.date ? new Date(a.date).getTime() : 0 |
| | | const dateB = b.date ? new Date(b.date).getTime() : 0 |
| | | return dateB - dateA |
| | | }) |
| | | } catch (error) { |
| | | console.error('获取工程号列表失败:', error) |
| | | ElMessage.error(error?.message || '获取工程号列表失败') |
| | | engineeringList.value = [] |
| | | } finally { |
| | | engineeringListLoading.value = false |
| | | } |
| | | } |
| | | |
| | | // 处理工程号选择变化 |
| | | const handleEngineeringChange = async (engineeringId) => { |
| | | if (!engineeringId) { |
| | | // 清空选择时,不清空已输入的玻璃ID,让用户保留 |
| | | return |
| | | } |
| | | |
| | | try { |
| | | glassIdsLoading.value = true |
| | | const response = await engineeringApi.getGlassIdsByEngineeringId(engineeringId) |
| | | |
| | | const glassIds = response?.glassIds || response?.data?.glassIds || [] |
| | | |
| | | if (glassIds.length > 0) { |
| | | glassIdsInput.value = glassIds.join('\n') |
| | | ElMessage.success(`已加载工程号 ${engineeringId} 的 ${glassIds.length} 个玻璃ID`) |
| | | } else { |
| | | ElMessage.warning(`工程号 ${engineeringId} 下没有找到玻璃ID`) |
| | | } |
| | | } catch (error) { |
| | | console.error('获取玻璃ID列表失败:', error) |
| | | ElMessage.error(error?.message || '获取玻璃ID列表失败') |
| | | } finally { |
| | | glassIdsLoading.value = false |
| | | } |
| | | } |
| | | |
| | | // 处理删除工程号 |
| | | const handleDeleteEngineering = async (engineeringId) => { |
| | | if (!engineeringId) { |
| | | return |
| | | } |
| | | |
| | | try { |
| | | await ElMessageBox.confirm( |
| | | `确定要删除工程号 "${engineeringId}" 及其关联的所有玻璃信息吗?此操作不可恢复!`, |
| | | '确认删除', |
| | | { |
| | | confirmButtonText: '确定删除', |
| | | cancelButtonText: '取消', |
| | | type: 'warning', |
| | | dangerouslyUseHTMLString: false |
| | | } |
| | | ) |
| | | |
| | | deletingEngineeringId.value = engineeringId |
| | | const response = await engineeringApi.deleteEngineering(engineeringId) |
| | | |
| | | const result = response?.data || response |
| | | if (result?.success !== false) { |
| | | const deletedCount = result?.deletedGlassCount || 0 |
| | | ElMessage.success(`已删除工程号 ${engineeringId},共删除 ${deletedCount} 条玻璃信息`) |
| | | |
| | | // 如果删除的是当前选中的工程号,清空选择 |
| | | if (selectedEngineeringId.value === engineeringId) { |
| | | selectedEngineeringId.value = '' |
| | | glassIdsInput.value = '' |
| | | } |
| | | |
| | | // 刷新工程号列表 |
| | | await fetchEngineeringList() |
| | | } else { |
| | | throw new Error(result?.message || '删除失败') |
| | | } |
| | | } catch (error) { |
| | | if (error !== 'cancel') { |
| | | console.error('删除工程号失败:', error) |
| | | ElMessage.error(error?.message || '删除工程号失败') |
| | | } |
| | | } finally { |
| | | deletingEngineeringId.value = '' |
| | | } |
| | | } |
| | | |
| | | const normalizeType = (type) => (type || '').trim().toUpperCase() |
| | | |
| | |
| | | const qty = parseInt(quantity) || 1 |
| | | for (let j = 0; j < qty; j++) { |
| | | // 如果数量大于1,为每条记录生成唯一的玻璃ID(追加序号) |
| | | const finalGlassId = qty > 1 ? `${glassId}_${j + 1}` : glassId |
| | | const finalGlassId = qty > 1 ? `${glassId}${j + 1}` : glassId |
| | | |
| | | result.push({ |
| | | glassId: finalGlassId, |
| | |
| | | : `成功导入 ${glassDataList.length} 条玻璃数据` |
| | | ElMessage.success(successMsg) |
| | | |
| | | // 将导入的玻璃ID填充到输入框,方便用户查看和编辑 |
| | | const glassIds = glassDataList.map(item => item.glassId).filter(id => id) |
| | | if (glassIds.length > 0) { |
| | | glassIdsInput.value = glassIds.join('\n') |
| | | // 成功后刷新工程号下拉列表,并选中最新工程号 |
| | | try { |
| | | await fetchEngineeringList() |
| | | if (engineerId) { |
| | | selectedEngineeringId.value = engineerId |
| | | // 刷新并回填后端保存的 glassId(带工程号前缀),避免使用前端原始值 |
| | | await handleEngineeringChange(engineerId) |
| | | } |
| | | } catch (refreshErr) { |
| | | console.error('刷新工程号列表失败:', refreshErr) |
| | | } |
| | | } else { |
| | | // MES 接口返回失败 |