Files
klp-oa/klp-ui/src/views/mes/qc/certificate/physics.vue

952 lines
32 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="100px">
<el-form-item label="入场钢卷号" prop="coilNo">
<el-input
v-model="queryParams.coilNo"
placeholder="请输入入场钢卷号"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="屈服强度(MPa)" prop="yieldStrength">
<el-input
v-model="queryParams.yieldStrength"
placeholder="请输入拉伸试验-屈服强度(MPa)"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="抗拉强度(MPa)" prop="tensileStrength">
<el-input
v-model="queryParams.tensileStrength"
placeholder="请输入拉伸试验-抗拉强度(MPa)"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="伸长率(%)" prop="elongation">
<el-input
v-model="queryParams.elongation"
placeholder="请输入拉伸试验-伸长率(%)"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="硬度实验(HRB)" prop="hardness">
<el-input
v-model="queryParams.hardness"
placeholder="请输入硬度实验(HRB)"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="弯曲试验" prop="bendingTest">
<el-input
v-model="queryParams.bendingTest"
placeholder="请输入弯曲试验"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="表面质量" prop="surfaceQuality">
<el-input
v-model="queryParams.surfaceQuality"
placeholder="请输入表面质量"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="表面结构" prop="surfaceStructure">
<el-input
v-model="queryParams.surfaceStructure"
placeholder="请输入表面结构"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="镀层表面结构" prop="coatingSurfaceStructure">
<el-input
v-model="queryParams.coatingSurfaceStructure"
placeholder="请输入镀层表面结构"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="el-icon-plus"
size="mini"
@click="handleAdd"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<coil-selector :use-trigger="true" multiple @confirm="handleBatchAdd"
:filters="{ selectType: 'product', status: 0 }">
<el-button type="primary" plain icon="el-icon-plus" size="mini">批量新增</el-button>
</coil-selector>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="el-icon-upload2"
size="mini"
@click="openImportDialog"
>导入</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="el-icon-edit"
size="mini"
:disabled="single"
@click="handleUpdate"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="el-icon-delete"
size="mini"
:disabled="multiple"
@click="handleDelete"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="el-icon-download"
size="mini"
@click="handleExport"
>导出</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="physicalItemList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="物理性能ID" align="center" prop="physicalId" v-if="false"/>
<el-table-column label="入场钢卷号" align="center" prop="coilNo" />
<el-table-column label="屈服强度(MPa)" align="center" prop="yieldStrength" />
<el-table-column label="抗拉强度(MPa)" align="center" prop="tensileStrength" />
<el-table-column label="伸长率(%)" align="center" prop="elongation" />
<el-table-column label="规定塑性延伸强度(MPa)" align="center" prop="plasticExtensionStrength" />
<el-table-column label="硬度实验(HRB)" align="center" prop="hardness" />
<el-table-column label="镀层重量(g/m²)" align="center" prop="coatingMass" />
<el-table-column label="弯曲试验" align="center" prop="bendingTest" />
<el-table-column label="表面质量" align="center" prop="surfaceQuality" />
<el-table-column label="表面结构" align="center" prop="surfaceStructure" />
<el-table-column label="镀层表面结构" align="center" prop="coatingSurfaceStructure" />
<el-table-column label="边缘状态" align="center" prop="edgeStatus" />
<el-table-column label="备注" align="center" prop="remark" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="handleUpdate(scope.row)"
>修改</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
>删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total>0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
<!-- 添加或修改物理性能明细对话框 -->
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
<el-form-item label="入场钢卷号" prop="coilNo">
<el-autocomplete
v-model="form.coilNo"
:fetch-suggestions="queryCoilNo"
placeholder="请输入入场钢卷号输入2个字符以上自动搜索"
:loading="coilNoLoading"
:trigger-on-focus="false"
clearable
/>
</el-form-item>
<el-form-item label="屈服强度(MPa)" prop="yieldStrength">
<el-input v-model="form.yieldStrength" placeholder="请输入屈服强度(MPa)" />
</el-form-item>
<el-form-item label="抗拉强度(MPa)" prop="tensileStrength">
<el-input v-model="form.tensileStrength" placeholder="请输入抗拉强度(MPa)" />
</el-form-item>
<el-form-item label="伸长率(%)" prop="elongation">
<el-input v-model="form.elongation" placeholder="请输入伸长率(%)" />
</el-form-item>
<el-form-item label="规定塑性延伸强度(MPa)" prop="plasticExtensionStrength">
<el-input v-model="form.plasticExtensionStrength" placeholder="请输入规定塑性延伸强度(MPa)" />
</el-form-item>
<el-form-item label="硬度实验(HRB)" prop="hardness">
<el-input v-model="form.hardness" placeholder="请输入硬度实验(HRB)" />
</el-form-item>
<el-form-item label="镀层重量(g/m²)" prop="coatingMass">
<el-input v-model="form.coatingMass" placeholder="请输入镀层重量(g/m²)" />
</el-form-item>
<el-form-item label="弯曲试验" prop="bendingTest">
<el-input v-model="form.bendingTest" placeholder="请输入弯曲试验" />
</el-form-item>
<el-form-item label="表面质量" prop="surfaceQuality">
<el-input v-model="form.surfaceQuality" placeholder="请输入表面质量" />
</el-form-item>
<el-form-item label="表面结构" prop="surfaceStructure">
<el-input v-model="form.surfaceStructure" placeholder="请输入表面结构" />
</el-form-item>
<el-form-item label="镀层表面结构" prop="coatingSurfaceStructure">
<el-input v-model="form.coatingSurfaceStructure" placeholder="请输入镀层表面结构" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" placeholder="请输入备注" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
<!-- 导入对话框 -->
<el-dialog title="导入物理性能" :visible.sync="importDialogVisible" width="1100px" top="5vh" append-to-body>
<div class="import-container">
<!-- 步骤条 -->
<div class="import-steps">
<div class="step" :class="{ active: true, done: importStatus !== 'idle' && importStatus !== 'validated' }">
<div class="step-badge">1</div>
<div class="step-label">下载模板</div>
</div>
<div class="step-connector" :class="{ done: importStatus !== 'idle' }" />
<div class="step" :class="{ active: importStatus === 'validated' || importStatus === 'processing' || importStatus === 'finished', done: importStatus !== 'idle' && importStatus !== 'validated' }">
<div class="step-badge">2</div>
<div class="step-label">上传文件</div>
</div>
<div class="step-connector" :class="{ done: importStatus === 'processing' || importStatus === 'finished' }" />
<div class="step" :class="{ active: importStatus === 'validated' || importStatus === 'processing' || importStatus === 'finished', done: importStatus === 'processing' || importStatus === 'finished' }">
<div class="step-badge">3</div>
<div class="step-label">校验数据</div>
</div>
<div class="step-connector" :class="{ done: importStatus === 'processing' || importStatus === 'finished' }" />
<div class="step" :class="{ active: importStatus === 'processing' || importStatus === 'finished', done: importStatus === 'finished' }">
<div class="step-badge step-badge-success">4</div>
<div class="step-label">批量导入</div>
</div>
</div>
<!-- 工具栏 -->
<div class="import-toolbar">
<div class="toolbar-left">
<el-upload ref="importUpload" action="" :auto-upload="false" :show-file-list="false"
:on-change="importHandleFileChange" accept=".xlsx,.xls"
:disabled="importStatus !== 'idle' && importStatus !== 'validated'">
<el-button :type="importFile ? 'default' : 'primary'" :icon="importFile ? 'el-icon-document' : 'el-icon-upload2'">
{{ importFile ? importFile.name : '选择Excel文件' }}
</el-button>
</el-upload>
<el-button type="success" plain icon="el-icon-check" @click="importHandleValidate"
:disabled="!importFile || importValidateLoading || importStatus !== 'idle'" :loading="importValidateLoading">校验数据</el-button>
</div>
<div class="toolbar-right">
<el-button v-if="importStatus === 'validated'" type="primary" icon="el-icon-upload-success" @click="importStartImport" :loading="importLoading">开始导入</el-button>
<el-button plain icon="el-icon-download" @click="importDownloadTemplate">下载模板</el-button>
<el-button plain icon="el-icon-refresh" @click="importReset">重置</el-button>
</div>
</div>
<!-- 数据预览表格 -->
<div v-if="importTableData.length > 0" class="data-preview">
<el-table ref="importTable" :data="importTableData" border size="small" max-height="340" stripe
:row-class-name="importTableRowClassName">
<el-table-column label="#" width="48" type="index" align="center" />
<el-table-column prop="coilNo" label="入场钢卷号" width="140" />
<el-table-column prop="yieldStrength" label="屈服强度(MPa)" width="110" align="center" />
<el-table-column prop="tensileStrength" label="抗拉强度(MPa)" width="110" align="center" />
<el-table-column prop="elongation" label="伸长率(%)" width="80" align="center" />
<el-table-column prop="plasticExtensionStrength" label="规定塑性延伸强度(MPa)" width="120" align="center" />
<el-table-column prop="hardness" label="硬度(HRB)" width="80" align="center" />
<el-table-column prop="coatingMass" label="镀层重量(g/m²)" width="100" align="center" />
<el-table-column prop="bendingTest" label="弯曲试验" width="80" align="center" />
<el-table-column prop="surfaceQuality" label="表面质量" width="80" align="center" />
<el-table-column prop="surfaceStructure" label="表面结构" width="80" align="center" />
<el-table-column prop="coatingSurfaceStructure" label="镀层表面结构" width="90" align="center" />
<el-table-column prop="edgeStatus" label="边缘状态" width="80" align="center" />
</el-table>
</div>
<!-- 导入进度 -->
<div v-if="importStatus === 'processing'" class="import-progress">
<div class="progress-header">
<i class="el-icon-loading" />
<span>正在批量导入数据请稍候...</span>
</div>
<el-progress :percentage="importProgress" :stroke-width="8" />
</div>
<!-- 完成提示 -->
<div v-if="importStatus === 'finished'" class="result-panel result-success">
<div class="result-icon"><i class="el-icon-circle-check" /></div>
<div class="result-body">
<div class="result-title">导入完成</div>
<div class="result-desc">共成功导入 <b>{{ importImportedCount }}</b> 条物理性能数据</div>
</div>
</div>
<!-- 错误提示 -->
<div v-if="importStatus === 'error'" class="result-panel result-error">
<div class="result-icon"><i class="el-icon-circle-close" /></div>
<div class="result-body">
<div class="result-title">导入失败</div>
<div class="result-desc">{{ importErrorMsg }}</div>
</div>
</div>
</div>
</el-dialog>
</div>
</template>
<script>
import * as XLSX from 'xlsx';
import { listPhysicalItem, getPhysicalItem, delPhysicalItem, addPhysicalItem, updatePhysicalItem, batchAddPhysicalItem } from "@/api/mes/qc/physicalItem";
import CoilSelector from "@/components/CoilSelector";
import { listMaterialCoil } from "@/api/wms/coil";
const PHYS_TEMPLATE_HEADERS = [
'当前钢卷号', '屈服强度(MPa)', '抗拉强度(MPa)', '伸长率(%)', '规定塑性延伸强度(MPa)', '硬度(HRB)',
'镀层重量(g/m²)', '弯曲试验', '表面质量', '表面结构', '镀层表面结构', '边缘状态'
];
const PHYS_HEADER_MAP = {
'当前钢卷号': 'coilNo',
'屈服强度(MPa)': 'yieldStrength',
'抗拉强度(MPa)': 'tensileStrength',
'伸长率(%)': 'elongation',
'规定塑性延伸强度(MPa)': 'plasticExtensionStrength',
'硬度(HRB)': 'hardness',
'镀层重量(g/m²)': 'coatingMass',
'弯曲试验': 'bendingTest',
'表面质量': 'surfaceQuality',
'表面结构': 'surfaceStructure',
'镀层表面结构': 'coatingSurfaceStructure',
'边缘状态': 'edgeStatus'
};
export default {
name: "PhysicalItem",
components: {
CoilSelector
},
computed: {},
data() {
return {
// 按钮loading
buttonLoading: false,
// 遮罩层
loading: true,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 物理性能明细表格数据
physicalItemList: [],
// 弹出层标题
title: "",
// 是否显示弹出层
open: false,
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
coilNo: undefined,
yieldStrength: undefined,
tensileStrength: undefined,
elongation: undefined,
plasticExtensionStrength: undefined,
hardness: undefined,
coatingMass: undefined,
bendingTest: undefined,
surfaceQuality: undefined,
surfaceStructure: undefined,
coatingSurfaceStructure: undefined,
edgeStatus: undefined,
},
// 表单参数
form: {},
// 表单校验
rules: {
coilNo: [
{ required: true, message: "入场钢卷号不能为空", trigger: "blur" }
],
},
importDialogVisible: false,
importFile: null,
importRawData: [],
importTableData: [],
importErrorList: [],
importProgress: 0,
importImportedCount: 0,
importTotalCount: 0,
importStatus: 'idle', // idle | validated | matched | processing | finished | error
importErrorMsg: '',
importValidateLoading: false,
importLoading: false,
coilNoOptions: [],
coilNoLoading: false,
};
},
created() {
this.getList();
},
methods: {
/** 查询物理性能明细列表 */
getList() {
this.loading = true;
listPhysicalItem(this.queryParams).then(response => {
this.physicalItemList = response.rows;
this.total = response.total;
this.loading = false;
});
},
// 取消按钮
cancel() {
this.open = false;
this.reset();
},
// 表单重置
reset() {
this.form = {
physicalId: undefined,
certificateId: undefined,
coilNo: undefined,
yieldStrength: undefined,
tensileStrength: undefined,
elongation: undefined,
plasticExtensionStrength: undefined,
hardness: undefined,
coatingMass: undefined,
bendingTest: undefined,
surfaceQuality: undefined,
surfaceStructure: undefined,
coatingSurfaceStructure: undefined,
edgeStatus: undefined,
remark: undefined,
delFlag: undefined,
createTime: undefined,
createBy: undefined,
updateTime: undefined,
updateBy: undefined
};
this.resetForm("form");
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
// 多选框选中数据
handleSelectionChange(selection) {
this.ids = selection.map(item => item.physicalId)
this.single = selection.length!==1
this.multiple = !selection.length
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = "添加物理性能明细";
},
handleSelect(coil) {
this.form.coilNo = coil.enterCoilNo;
},
queryCoilNo(queryString, cb) {
if (!queryString || queryString.length < 2) {
cb([]);
return;
}
this.coilNoLoading = true;
listMaterialCoil({
enterCoilNo: queryString,
pageNum: 1,
pageSize: 20
}).then(response => {
const options = (response.rows || []).map(item => ({
value: item.enterCoilNo,
label: item.enterCoilNo
}));
cb(options);
}).finally(() => {
this.coilNoLoading = false;
});
},
handleBatchAdd(rows) {
this.loading = true;
this.buttonLoading = true;
const payload = rows.map(coil => ({
coilNo: coil.coilNo,
}))
batchAddPhysicalItem(payload).then(response => {
this.$modal.msgSuccess("新增成功");
this.getList();
}).finally(() => {
this.buttonLoading = false;
this.loading = false;
});
},
openImportDialog() {
this.importDialogVisible = true;
},
importHandleFileChange(file) {
if (this.importValidateLoading || this.importLoading) return;
this.importFile = file.raw;
this.importErrorList = [];
this.importStatus = 'idle';
this.importReadExcel();
},
async importReadExcel() {
if (!this.importFile) return;
try {
const reader = new FileReader();
reader.readAsArrayBuffer(this.importFile);
reader.onload = async (e) => {
try {
const data = new Uint8Array(e.target.result);
const wb = XLSX.read(data, { type: 'array' });
const ws = wb.Sheets[wb.SheetNames[0]];
const json = XLSX.utils.sheet_to_json(ws, { header: 1 });
this.importValidateHeaders(json[0]);
this.importRawData = json.slice(1).filter(r => r.some(c => c != null && c !== ''));
this.importFormatExcel();
this.$message.success(`成功解析Excel共读取到 ${this.importRawData.length} 条数据`);
} catch (err) { this.importHandleError('解析Excel失败' + err.message); }
};
} catch (err) { this.importHandleError('读取文件失败:' + err.message); }
},
importValidateHeaders(headers) {
this.importErrorList = [];
if (!headers || headers.length < PHYS_TEMPLATE_HEADERS.length) {
this.importErrorList.push({ rowNum: 1, errorMsg: `表头数量不匹配,要求至少${PHYS_TEMPLATE_HEADERS.length}` });
return;
}
PHYS_TEMPLATE_HEADERS.forEach((h, i) => {
if (headers[i] !== h) this.importErrorList.push({ rowNum: 1, errorMsg: `${i+1}列表头错误,要求:"${h}",实际:"${headers[i]||''}"` });
});
if (this.importErrorList.length > 0) this.$message.error('Excel表头格式不符合要求请检查');
},
importFormatExcel() {
this.importTableData = [];
if (!this.importRawData.length) return;
this.importRawData.forEach((row, i) => {
const obj = {};
PHYS_TEMPLATE_HEADERS.forEach((h, j) => { obj[PHYS_HEADER_MAP[h]] = row[j] != null ? String(row[j]).trim() : ''; });
obj.rowNum = i + 2;
obj._status = 'pending';
this.importTableData.push(obj);
});
},
async importHandleValidate() {
if (!this.importFile || !this.importRawData.length) { this.$message.warning('暂无数据可校验'); return; }
this.importValidateLoading = true;
this.importErrorList = [];
for (let i = 0; i < this.importRawData.length; i++) {
const rowNum = i + 2;
let coilNo = '';
PHYS_TEMPLATE_HEADERS.forEach((h, j) => { if (PHYS_HEADER_MAP[h] === 'coilNo') coilNo = this.importRawData[i][j]; });
if (!coilNo || !String(coilNo).trim()) this.importErrorList.push({ rowNum, errorMsg: '当前钢卷号不能为空' });
}
if (this.importErrorList.length > 0) {
this.$message.error(`数据校验失败,共发现${this.importErrorList.length}条错误`);
} else {
this.importTableData.forEach(row => { row._status = 'valid'; });
this.$message.success('数据校验通过');
this.importStatus = 'validated';
}
this.importValidateLoading = false;
},
async importStartImport() {
const rows = this.importTableData.filter(r => r._status === 'valid');
if (!rows.length) { this.$message.warning('没有可导入的数据'); return; }
const ok = await this.$confirm(`确认导入 ${rows.length} 条数据?`, '导入确认', { confirmButtonText: '确认导入', cancelButtonText: '取消', type: 'warning' }).catch(() => false);
if (!ok) return;
this.importLoading = true;
this.importStatus = 'processing';
this.importProgress = 0;
this.importTotalCount = rows.length;
this.importErrorMsg = '';
try {
const payload = rows.map(row => {
const item = { coilId: null, coilNo: row.coilNo };
['yieldStrength','tensileStrength','elongation','plasticExtensionStrength','hardness','coatingMass','bendingTest','surfaceQuality','surfaceStructure','coatingSurfaceStructure','edgeStatus'].forEach(f => { if (row[f]) item[f] = row[f]; });
return item;
});
const addRes = await batchAddPhysicalItem(payload);
if (addRes.code !== 200) throw new Error(addRes.msg || '批量导入失败');
this.importStatus = 'finished';
this.importImportedCount = payload.length;
this.importProgress = 100;
this.$message.success(`导入完成!共成功导入${payload.length}条数据`);
this.getList();
} catch (err) {
this.importHandleError(err.message);
} finally {
this.importLoading = false;
}
},
importReset() {
if (this.importValidateLoading || this.importLoading || this.importStatus === 'processing') { this.$message.warning('当前有操作正在进行中'); return; }
this.importFile = null;
this.importRawData = [];
this.importTableData = [];
this.importErrorList = [];
this.importProgress = 0;
this.importImportedCount = 0;
this.importTotalCount = 0;
this.importStatus = 'idle';
this.importErrorMsg = '';
this.$refs.importUpload?.clearFiles();
},
importDownloadTemplate() {
const data = [PHYS_TEMPLATE_HEADERS, ['示例卷号', '300', '420', '35', '260', '85', '275', '合格', '良好', '光面', '无锌花', '良好']];
const wb = XLSX.utils.book_new();
const ws = XLSX.utils.aoa_to_sheet(data);
ws['!cols'] = [{ wch: 16 }, { wch: 16 }, { wch: 16 }, { wch: 10 }, { wch: 20 }, { wch: 10 }, { wch: 16 }, { wch: 10 }, { wch: 10 }, { wch: 10 }, { wch: 12 }, { wch: 10 }];
XLSX.utils.book_append_sheet(wb, ws, '导入模板');
XLSX.writeFile(wb, '物理性能导入模板.xlsx');
},
importHandleError(msg) {
this.$message.error(msg);
this.importStatus = 'error';
this.importErrorMsg = msg;
this.importValidateLoading = false;
this.importLoading = false;
},
importTableRowClassName() {
return '';
},
/** 修改按钮操作 */
handleUpdate(row) {
this.loading = true;
this.reset();
const physicalId = row.physicalId || this.ids
getPhysicalItem(physicalId).then(response => {
this.loading = false;
this.form = response.data;
this.open = true;
this.title = "修改物理性能明细";
});
},
/** 提交按钮 */
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
this.buttonLoading = true;
if (this.form.physicalId != null) {
updatePhysicalItem(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
}).finally(() => {
this.buttonLoading = false;
});
} else {
addPhysicalItem(this.form).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
}).finally(() => {
this.buttonLoading = false;
});
}
}
});
},
/** 删除按钮操作 */
handleDelete(row) {
const physicalIds = row.physicalId || this.ids;
this.$modal.confirm('是否确认删除物理性能明细编号为"' + physicalIds + '"的数据项?').then(() => {
this.loading = true;
return delPhysicalItem(physicalIds);
}).then(() => {
this.loading = false;
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {
}).finally(() => {
this.loading = false;
});
},
/** 导出按钮操作 */
handleExport() {
this.download('qc/physicalItem/export', {
...this.queryParams
}, `physicalItem_${new Date().getTime()}.xlsx`)
}
}
};
</script>
<style scoped>
.import-container {
padding: 0 4px;
}
.import-steps {
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 24px;
padding: 20px 0 16px;
border-bottom: 1px solid #f0f0f0;
}
.step {
display: flex;
flex-direction: column;
align-items: center;
gap: 6px;
opacity: 0.45;
transition: all 0.3s;
}
.step.active { opacity: 1; }
.step.done { opacity: 0.65; }
.step-badge {
width: 32px;
height: 32px;
border-radius: 50%;
background: #dcdfe6;
color: #fff;
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
font-weight: 600;
transition: all 0.3s;
}
.step.active .step-badge {
background: #409eff;
box-shadow: 0 2px 8px rgba(64,158,255,0.35);
}
.step.done .step-badge {
background: #67c23a;
}
.step-badge-warn { background: #e6a23c !important; }
.step.active .step-badge-warn { background: #e6a23c !important; box-shadow: 0 2px 8px rgba(230,162,60,0.35) !important; }
.step-badge-success { background: #67c23a !important; }
.step.active .step-badge-success { background: #67c23a !important; box-shadow: 0 2px 8px rgba(103,194,58,0.35) !important; }
.step-label {
font-size: 12px;
color: #606266;
white-space: nowrap;
}
.step.active .step-label { color: #303133; font-weight: 600; }
.step-connector {
width: 48px;
height: 2px;
background: #dcdfe6;
margin: 0 4px;
margin-bottom: 24px;
transition: all 0.3s;
}
.step-connector.done { background: #67c23a; }
.import-toolbar {
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 8px;
margin-bottom: 16px;
padding: 12px 16px;
background: #fafafa;
border-radius: 8px;
border: 1px solid #eee;
}
.toolbar-left, .toolbar-right {
display: flex;
align-items: center;
gap: 8px;
flex-wrap: wrap;
}
.match-summary {
display: flex;
gap: 12px;
margin-bottom: 16px;
}
.summary-item {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
padding: 14px 8px;
border-radius: 8px;
background: #fafafa;
border: 1px solid #eee;
gap: 4px;
}
.summary-matched { border-color: #b7eb8f; background: #f6ffed; }
.summary-ambiguous { border-color: #ffe58f; background: #fffbe6; }
.summary-notfound { border-color: #ffa39e; background: #fff2f0; }
.summary-total { border-color: #d9d9d9; background: #fafafa; }
.summary-num {
font-size: 22px;
font-weight: 700;
line-height: 1;
}
.summary-matched .summary-num { color: #52c41a; }
.summary-ambiguous .summary-num { color: #faad14; }
.summary-notfound .summary-num { color: #ff4d4f; }
.summary-total .summary-num { color: #409eff; }
.summary-label {
font-size: 12px;
color: #606266;
}
.data-preview {
margin-bottom: 12px;
}
::v-deep .tag-clickable {
cursor: pointer;
}
::v-deep .tag-clickable:hover {
opacity: 0.8;
}
.import-progress {
padding: 24px;
background: #f6ffed;
border-radius: 8px;
border: 1px solid #b7eb8f;
margin-bottom: 12px;
}
.progress-header {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 12px;
font-size: 14px;
color: #52c41a;
font-weight: 500;
}
.result-panel {
display: flex;
align-items: center;
gap: 16px;
padding: 20px 24px;
border-radius: 8px;
margin-bottom: 12px;
}
.result-success {
background: #f6ffed;
border: 1px solid #b7eb8f;
}
.result-error {
background: #fff2f0;
border: 1px solid #ffa39e;
}
.result-icon {
font-size: 36px;
line-height: 1;
}
.result-success .result-icon { color: #52c41a; }
.result-error .result-icon { color: #ff4d4f; }
.result-title {
font-size: 16px;
font-weight: 600;
margin-bottom: 4px;
}
.result-success .result-title { color: #389e0d; }
.result-error .result-title { color: #cf1322; }
.result-desc {
font-size: 13px;
color: #606266;
}
.candidate-hint {
margin-bottom: 12px;
padding: 10px 14px;
background: #fffbe6;
border: 1px solid #ffe58f;
border-radius: 6px;
font-size: 13px;
color: #ad6800;
display: flex;
align-items: center;
gap: 6px;
}
.candidate-footer {
margin-top: 10px;
text-align: center;
font-size: 12px;
color: #999;
}
</style>