<template>
|
<div class="app-container">
|
<div class="search_form mb20">
|
<div class="search-row">
|
<div class="search-item">
|
<span class="search_title">工单编号:</span>
|
<el-input v-model="searchForm.workOrderNo"
|
style="width: 240px"
|
placeholder="请输入"
|
@change="handleQuery"
|
clearable
|
prefix-icon="Search" />
|
</div>
|
<div class="search-item">
|
<span class="search_title">生产订单号:</span>
|
<el-input v-model="searchForm.npsNo"
|
style="width: 240px"
|
placeholder="请输入"
|
@change="handleQuery"
|
clearable
|
prefix-icon="Search" />
|
</div>
|
<div class="search-item">
|
<el-button type="primary"
|
@click="handleQuery">搜索</el-button>
|
</div>
|
<div class="search-item">
|
<el-switch v-model="filterMine"
|
active-text="仅看我的"
|
@change="handleQuery" />
|
</div>
|
</div>
|
</div>
|
<div class="table_list">
|
<PIMTable rowKey="id"
|
:column="tableColumn"
|
:tableData="tableData"
|
:page="page"
|
:tableLoading="tableLoading"
|
@pagination="pagination">
|
<template #completionStatus="{ row }">
|
<el-progress :percentage="toProgressPercentage(row?.completionStatus)"
|
:color="progressColor(toProgressPercentage(row?.completionStatus))"
|
:status="toProgressPercentage(row?.completionStatus) >= 100 ? 'success' : ''" />
|
</template>
|
</PIMTable>
|
</div>
|
<!-- 流转卡弹窗 -->
|
<el-dialog v-model="transferCardVisible"
|
title="流转卡"
|
width="1000px">
|
<div class="transfer-card-title">工单流转卡</div>
|
<div class="transfer-card-container">
|
<div class="transfer-card-info">
|
<div class="info-group">
|
<div class="info-item">
|
<span class="info-label">工单编号</span>
|
<span class="info-value">{{ transferCardRowData.workOrderNo }}</span>
|
</div>
|
<div class="info-item">
|
<span class="info-label">产品名称</span>
|
<span class="info-value">{{ transferCardRowData.productName }}</span>
|
</div>
|
<div class="info-item">
|
<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.planStartTime }}</span>
|
</div>
|
<div class="info-item">
|
<span class="info-label">计划结束时间</span>
|
<span class="info-value">{{ transferCardRowData.planEndTime }}</span>
|
</div>
|
<div class="info-item">
|
<span class="info-label">备注</span>
|
<span class="info-value">{{ transferCardRowData.remark }}</span>
|
</div>
|
</div>
|
<div class="info-group">
|
<div class="info-item">
|
<span class="info-label">需求数量</span>
|
<span class="info-value">{{ transferCardRowData.planQuantity }}</span>
|
</div>
|
<div class="info-item">
|
<span class="info-value">{{ transferCardRowData.completeQuantity }}</span>
|
</div>
|
<div class="info-item">
|
<span class="info-label">良品数量</span>
|
<span class="info-value">0</span>
|
</div>
|
<div class="info-item">
|
<span class="info-label">不良品数</span>
|
<span class="info-value">0</span>
|
</div>
|
<div class="info-item">
|
<span class="info-label">实际开始时间</span>
|
<span class="info-value">{{ transferCardRowData.actualStartTime }}</span>
|
</div>
|
<div class="info-item">
|
<span class="info-label">实际结束时间</span>
|
<span class="info-value">{{ transferCardRowData.actualEndTime }}</span>
|
</div>
|
</div>
|
</div>
|
<div class="transfer-card-qr">
|
<div class="qr-container">
|
<img :src="transferCardQrUrl"
|
alt="流转卡二维码"
|
style="width: 200px; height: 200px;" />
|
</div>
|
</div>
|
</div>
|
<div class="print-button-container"
|
style=" text-align: center;
|
margin-bottom: 40px;">
|
<el-button type="primary"
|
style="margin-top: 20px;"
|
@click="printTransferCard">打印流转卡</el-button>
|
</div>
|
</el-dialog>
|
<!-- 报工弹窗(结束报工用) -->
|
<el-dialog v-model="reportDialogVisible"
|
title="结束报工"
|
width="500px">
|
<el-form ref="reportFormRef"
|
:model="reportForm"
|
:rules="reportFormRules"
|
label-width="120px">
|
<el-form-item label="待生产数量">
|
<el-input v-model="reportForm.planQuantity"
|
readonly
|
style="width: 300px" />
|
</el-form-item>
|
<el-form-item label="生产合格数量"
|
prop="quantity">
|
<el-input v-model.number="reportForm.quantity"
|
type="number"
|
min="0"
|
step="1"
|
style="width: 300px"
|
placeholder="请输入生产合格数量"
|
@input="handleQuantityInput" />
|
</el-form-item>
|
<el-form-item label="报废数量"
|
prop="scrapQty">
|
<el-input v-model.number="reportForm.scrapQty"
|
type="number"
|
min="0"
|
step="1"
|
style="width: 300px"
|
placeholder="请输入报废数量"
|
@input="handleScrapQtyInput" />
|
</el-form-item>
|
<el-form-item label="班组信息">
|
<el-select v-model="reportForm.userId"
|
style="width: 300px"
|
placeholder="请选择班组信息"
|
clearable
|
filterable
|
@change="handleUserChange">
|
<el-option v-for="user in userOptions"
|
:key="user.userId"
|
:label="user.nickName"
|
:value="user.userId" />
|
</el-select>
|
</el-form-item>
|
<el-form-item label="工时"
|
v-if="currentReportRowData?.type == 0"
|
prop="workHour">
|
<el-input v-model.number="reportForm.workHour"
|
type="number"
|
min="0"
|
style="width: 280px"
|
placeholder="请输入工时" /><span style="margin-left:10px"
|
class="param-unit">h</span>
|
</el-form-item>
|
<div v-if="params.length > 0"
|
class="param-grid"
|
v-loading="paramLoading">
|
<el-form-item v-for="param in params"
|
:key="param.id"
|
:label="param.paramName"
|
:label-width="120"
|
class="param-item">
|
<template v-if="param.paramType == '1'">
|
<div class="param-input-group">
|
<el-input-number v-model="reportForm.paramGroups[param.id]"
|
controls-position="right"
|
:key="param.id"
|
style="width: 250px"
|
class="param-input" />
|
<span v-if="param.unit && param.unit != '/'"
|
class="param-unit">{{ param.unit }}</span>
|
</div>
|
</template>
|
<template v-else-if="param.paramType == '2'">
|
<div class="param-input-group">
|
<el-input v-model="reportForm.paramGroups[param.id]"
|
:key="param.id"
|
style="width: 250px"
|
class="param-input" />
|
<span v-if="param.unit && param.unit != '/'"
|
class="param-unit">{{ param.unit }}</span>
|
</div>
|
</template>
|
<template v-else-if="param.paramType == '3'">
|
<div class="param-input-group">
|
<el-select v-model="reportForm.paramGroups[param.id]"
|
placeholder="请选择"
|
:key="param.id"
|
class="param-select"
|
style="width: 250px">
|
<el-option v-for="option in dictOptions[param.paramFormat] || []"
|
:key="option.dictLabel"
|
:label="option.dictLabel"
|
:value="option.dictLabel" />
|
</el-select>
|
<span v-if="param.unit && param.unit != '/'"
|
class="param-unit">{{ param.unit }}</span>
|
</div>
|
</template>
|
<template v-else-if="param.paramType == '4'">
|
<div class="param-input-group">
|
<el-date-picker :value-format="param.paramFormat.replace('yyyy', 'YYYY').replace('dd', 'DD')"
|
:format="param.paramFormat.replace('yyyy', 'YYYY').replace('dd', 'DD')"
|
:key="param.id"
|
:type="param.paramFormat=='yyyy-MM-dd'?'date':'datetime'"
|
v-model="reportForm.paramGroups[param.id]"
|
class="param-input"
|
style="width: 250px" />
|
<span v-if="param.unit && param.unit != '/'"
|
class="param-unit">{{ param.unit }}</span>
|
</div>
|
</template>
|
<template v-else>
|
<div class="param-input-group">
|
<el-input v-model="reportForm.paramGroups[param.id]"
|
:key="param.id"
|
class="param-input" />
|
<span v-if="param.unit && param.unit != '/'"
|
class="param-unit">{{ param.unit }}</span>
|
</div>
|
</template>
|
</el-form-item>
|
</div>
|
</el-form>
|
<template #footer>
|
<span class="dialog-footer">
|
<el-button type="primary"
|
@click="handleFinishWork">确定</el-button>
|
<el-button @click="reportDialogVisible = false">取消</el-button>
|
</span>
|
</template>
|
</el-dialog>
|
<MaterialDialog v-model="materialDialogVisible"
|
:row-data="currentMaterialOrderRow"
|
@refresh="getList" />
|
<FileList v-if="fileDialogVisible"
|
v-model:visible="fileDialogVisible"
|
:editable="!currentWorkOrderRow?.endOrder"
|
:record-type="'production_operation_task'"
|
:record-id="currentWorkOrderId" />
|
</div>
|
</template>
|
|
<script setup>
|
import { onMounted, ref, nextTick } from "vue";
|
import { ElMessageBox } from "element-plus";
|
import dayjs from "dayjs";
|
import {
|
productWorkOrderPage,
|
addProductMain,
|
startWork,
|
downProductWorkOrder,
|
} from "@/api/productionManagement/workOrder.js";
|
import { findProcessParamListOrder } from "@/api/productionManagement/productProcessRoute.js";
|
import { getUserProfile, userListNoPageByTenantId } from "@/api/system/user.js";
|
import { getDicts } from "@/api/system/dict/data";
|
import QRCode from "qrcode";
|
import { getCurrentInstance, reactive, toRefs } from "vue";
|
import MaterialDialog from "./components/MaterialDialog.vue";
|
const FileList = defineAsyncComponent(() =>
|
import("@/components/Dialog/FileList.vue")
|
);
|
|
import useUserStore from "@/store/modules/user";
|
const { proxy } = getCurrentInstance();
|
const userStore = useUserStore();
|
|
const isCompleted = row => {
|
const status = Number(row?.completionStatus);
|
return Number.isFinite(status) && status >= 100;
|
};
|
|
const canOperate = row => !row.endOrder && !isCompleted(row);
|
|
const tableColumn = ref([
|
{ label: "工单类型", prop: "workOrderType", width: "80" },
|
{ label: "工单编号", prop: "workOrderNo", width: "140" },
|
{ label: "生产订单号", prop: "npsNo", width: "140" },
|
{ label: "产品名称", prop: "productName", width: "140" },
|
{ label: "规格", prop: "model" },
|
{ label: "单位", prop: "unit" },
|
{ label: "工序名称", prop: "operationName", width: "100" },
|
{ label: "需求数量", prop: "planQuantity", width: "140" },
|
{ label: "完成数量", prop: "completeQuantity", width: "140" },
|
{ label: "完成进度", prop: "completionStatus", dataType: "slot", slot: "completionStatus", width: "140" },
|
{ label: "计划开始时间", prop: "planStartTime", width: "140" },
|
{ label: "计划结束时间", prop: "planEndTime", width: "140" },
|
{ label: "实际开始时间", prop: "actualStartTime", width: "140" },
|
{ label: "实际结束时间", prop: "actualEndTime", width: "140" },
|
{
|
label: "操作", width: "260", align: "center", dataType: "action", fixed: "right",
|
operation: [
|
{
|
name: "流转卡",
|
clickFun: row => { downloadAndPrintWorkOrder(row); },
|
},
|
{
|
name: "附件",
|
clickFun: row => { openWorkOrderFiles(row); },
|
},
|
{
|
name: "开始报工",
|
showHide: row => canOperate(row) && !row.actualStartTime,
|
disabled: row => {
|
if (row.planQuantity <= 0) return true;
|
if (!row.userIds) return false;
|
try {
|
const userIds = typeof row.userIds === "string" ? JSON.parse(row.userIds) : row.userIds;
|
if (Array.isArray(userIds)) {
|
return !userIds.some(id => String(id) === String(userStore.id));
|
}
|
return true;
|
} catch (e) { return true; }
|
},
|
clickFun: row => { handleStartWork(row); },
|
},
|
{
|
name: "结束报工",
|
showHide: row => canOperate(row) && !!row.actualStartTime,
|
clickFun: row => { showReportDialog(row); },
|
},
|
],
|
},
|
]);
|
const tableData = ref([]);
|
const tableLoading = ref(false);
|
const transferCardVisible = ref(false);
|
const transferCardRowData = ref(null);
|
const reportDialogVisible = ref(false);
|
const fileDialogVisible = ref(false);
|
const currentWorkOrderId = ref(null);
|
const reportFormRef = ref(null);
|
const userOptions = ref([]);
|
const reportForm = reactive({
|
planQuantity: 0,
|
quantity: null,
|
scrapQty: null,
|
userName: "",
|
workOrderId: "",
|
reportWork: "",
|
productProcessRouteItemId: "",
|
userId: "",
|
productMainId: null,
|
productionOrderRoutingOperationId: "",
|
productionOrderId: "",
|
workHour: 0,
|
paramGroups: {},
|
});
|
|
const params = ref({});
|
const dictOptions = ref({});
|
const paramLoading = ref(false);
|
|
const validateQuantity = (rule, value, callback) => {
|
if (value === null || value === undefined || value === "") {
|
callback(new Error("请输入生产合格数量"));
|
return;
|
}
|
const num = Number(value);
|
if (isNaN(num) || !Number.isInteger(num) || num < 0) {
|
callback(new Error("生产合格数量必须大于等于0"));
|
return;
|
}
|
callback();
|
};
|
const validateScrapQty = (rule, value, callback) => {
|
if (value === null || value === undefined || value === "") {
|
callback();
|
return;
|
}
|
const num = Number(value);
|
if (isNaN(num) || !Number.isInteger(num) || num < 0) {
|
callback(new Error("报废数量必须大于等于0"));
|
return;
|
}
|
callback();
|
};
|
const reportFormRules = {
|
quantity: [{ required: true, validator: validateQuantity, trigger: "blur" }],
|
scrapQty: [{ validator: validateScrapQty, trigger: "blur" }],
|
};
|
|
const handleQuantityInput = value => {
|
if (value === "" || value === null || value === undefined) { reportForm.quantity = null; return; }
|
const num = Number(value);
|
if (isNaN(num)) return;
|
if (num < 0) { reportForm.quantity = null; return; }
|
if (!Number.isInteger(num)) {
|
const intValue = Math.floor(num);
|
if (intValue < 0) { reportForm.quantity = null; return; }
|
reportForm.quantity = intValue;
|
return;
|
}
|
reportForm.quantity = num;
|
};
|
|
const handleScrapQtyInput = value => {
|
if (value === "" || value === null || value === undefined) { reportForm.scrapQty = null; return; }
|
const num = Number(value);
|
if (isNaN(num)) return;
|
if (num < 0) { reportForm.scrapQty = null; return; }
|
if (!Number.isInteger(num)) { reportForm.scrapQty = Math.floor(num); return; }
|
reportForm.scrapQty = num;
|
};
|
|
const filterMine = ref(false);
|
const currentReportRowData = ref(null);
|
const materialDialogVisible = ref(false);
|
const currentMaterialOrderRow = ref(null);
|
const page = reactive({ current: 1, size: 100, total: 0 });
|
|
const data = reactive({
|
searchForm: { workOrderNo: "", npsNo: "" },
|
});
|
const { searchForm } = toRefs(data);
|
|
const toProgressPercentage = val => {
|
const n = Number(val);
|
if (!Number.isFinite(n)) return 0;
|
if (n <= 0) return 0;
|
if (n >= 100) return 100;
|
return parseFloat(n.toFixed(2));
|
};
|
const progressColor = percentage => {
|
const p = toProgressPercentage(percentage);
|
if (p < 30) return "#f56c6c";
|
if (p < 50) return "#e6a23c";
|
if (p < 80) return "#409eff";
|
return "#67c23a";
|
};
|
|
const handleQuery = () => { page.current = 1; getList(); };
|
const pagination = obj => { page.current = obj.page; page.size = obj.limit; getList(); };
|
|
const getList = () => {
|
tableLoading.value = true;
|
const params = { ...searchForm.value, ...page };
|
if (filterMine.value) { params.filterMine = true; }
|
productWorkOrderPage(params)
|
.then(res => {
|
tableLoading.value = false;
|
tableData.value = res.data.records;
|
page.total = res.data.total;
|
})
|
.catch(() => { tableLoading.value = false; });
|
};
|
|
const downloadAndPrintWorkOrder = async row => {
|
if (!row || !row.id) {
|
proxy.$modal.msgError("缺少工单ID,无法下载流转卡");
|
return;
|
}
|
try {
|
const blob = await downProductWorkOrder(row.id);
|
if (!blob) { proxy.$modal.msgError("未获取到流转卡文件"); return; }
|
const fileBlob = blob instanceof Blob ? blob : new Blob([blob], { type: blob.type || "application/octet-stream" });
|
const url = window.URL.createObjectURL(fileBlob);
|
const iframe = document.createElement("iframe");
|
iframe.style.position = "fixed";
|
iframe.style.right = "0"; iframe.style.bottom = "0";
|
iframe.style.width = "0"; iframe.style.height = "0"; iframe.style.border = "0";
|
iframe.src = url;
|
document.body.appendChild(iframe);
|
iframe.onload = () => {
|
try { iframe.contentWindow?.focus(); iframe.contentWindow?.print(); }
|
catch (e) { window.open(url); }
|
};
|
} catch (e) {
|
console.error("下载工单流转卡失败", e);
|
proxy.$modal.msgError("下载工单流转卡失败");
|
}
|
};
|
|
const printTransferCard = () => { window.print(); };
|
const currentWorkOrderRow = ref(null);
|
|
const openWorkOrderFiles = row => {
|
currentWorkOrderId.value = row.id;
|
currentWorkOrderRow.value = row;
|
fileDialogVisible.value = true;
|
};
|
|
const handleStartWork = row => {
|
proxy.$modal
|
.confirm("确认开始报工?", "提示", { type: "info" })
|
.then(async () => {
|
try {
|
await startWork({
|
productionOperationTaskId: row.id,
|
userId: userStore.id,
|
});
|
proxy.$modal.msgSuccess("开始报工成功");
|
getList();
|
} catch (e) {
|
proxy.$modal.msgError("开始报工失败");
|
}
|
})
|
.catch(() => {});
|
};
|
|
const showReportDialog = async row => {
|
currentReportRowData.value = row;
|
const planQuantity = Number(row.planQuantity || 0);
|
const completeQuantity = Number(row.completeQuantity || 0);
|
const remainingQuantity = Math.max(0, planQuantity - completeQuantity);
|
reportForm.planQuantity = remainingQuantity;
|
reportForm.quantity = row.quantity !== undefined && row.quantity !== null ? row.quantity : null;
|
reportForm.productProcessRouteItemId = row.productProcessRouteItemId;
|
reportForm.workOrderId = row.id;
|
reportForm.reportWork = row.reportWork;
|
reportForm.productMainId = row.productMainId;
|
reportForm.scrapQty = row.scrapQty !== undefined && row.scrapQty !== null ? row.scrapQty : null;
|
reportForm.productionOrderRoutingOperationId = row.productionOrderRoutingOperationId;
|
reportForm.productionOrderId = row.productionOrderId;
|
reportForm.workHour = row.type == 0 ? (row.workHour || 0) : 0;
|
nextTick(() => {
|
reportFormRef.value?.clearValidate();
|
if (row.productionOrderRoutingOperationId && row.productionOrderId) {
|
loadParams(row.productionOrderRoutingOperationId, row.productionOrderId);
|
}
|
});
|
if (userStore.id) {
|
reportForm.userId = userStore.id;
|
reportForm.userName = userStore.name || userStore.nickName || "";
|
}
|
getUserProfile()
|
.then(res => {
|
if (res.code === 200 && res.data) {
|
reportForm.userId = res.data.userId;
|
reportForm.userName = res.data.nickName || res.data.userName || "";
|
}
|
})
|
.catch(err => { console.error("获取用户信息失败", err); });
|
|
reportDialogVisible.value = true;
|
};
|
|
const openMaterialDialog = row => {
|
currentMaterialOrderRow.value = row;
|
materialDialogVisible.value = true;
|
};
|
|
const handleFinishWork = () => {
|
reportFormRef.value?.validate(valid => {
|
if (!valid) return;
|
|
if (reportForm.planQuantity <= 0) {
|
ElMessageBox.alert("待生产数量为0,无法报工", "提示", { confirmButtonText: "确定" });
|
return;
|
}
|
if (reportForm.quantity === null || reportForm.quantity === undefined || reportForm.quantity === "") {
|
ElMessageBox.alert("请输入生产合格数量", "提示", { confirmButtonText: "确定" });
|
return;
|
}
|
const quantity = Number(reportForm.quantity);
|
if (isNaN(quantity) || quantity < 0) {
|
ElMessageBox.alert("生产合格数量必须大于等于0", "提示", { confirmButtonText: "确定" });
|
return;
|
}
|
const scrapQty = Number(reportForm.scrapQty);
|
if (!isNaN(scrapQty) && scrapQty < 0) {
|
ElMessageBox.alert("报废数量不能小于0", "提示", { confirmButtonText: "确定" });
|
return;
|
}
|
|
const productionOperationParamList = params.value.map(param => ({
|
...param,
|
inputValue: reportForm.paramGroups[param.id] ?? "",
|
}));
|
|
addProductMain({
|
quantity,
|
scrapQty: isNaN(scrapQty) ? 0 : scrapQty,
|
userId: reportForm.userId,
|
userName: reportForm.userName,
|
productionOperationTaskId: reportForm.workOrderId,
|
productProcessRouteItemId: reportForm.productProcessRouteItemId,
|
reportWork: reportForm.reportWork,
|
productMainId: reportForm.productMainId,
|
productionOrderRoutingOperationId: reportForm.productionOrderRoutingOperationId,
|
productionOrderId: reportForm.productionOrderId,
|
workHour: reportForm.workHour,
|
productionOperationParamList: productionOperationParamList,
|
})
|
.then(() => {
|
proxy.$modal.msgSuccess("结束报工成功");
|
reportDialogVisible.value = false;
|
getList();
|
})
|
.catch(() => {
|
ElMessageBox.alert("结束报工失败", "提示", { confirmButtonText: "确定" });
|
});
|
});
|
};
|
|
const handleUserChange = val => {
|
const user = userOptions.value.find(item => item.userId === val);
|
reportForm.userName = user ? user.nickName : "";
|
};
|
|
const getDictOptions = async dictType => {
|
if (!dictType) return [];
|
if (dictOptions.value[dictType]) return dictOptions.value[dictType];
|
try {
|
const res = await getDicts(dictType);
|
if (res.code === 200) { dictOptions.value[dictType] = res.data; return res.data; }
|
return [];
|
} catch (error) { console.error("获取字典数据失败:", error); return []; }
|
};
|
|
const loadParams = (productionOrderRoutingOperationId, productionOrderId) => {
|
paramLoading.value = true;
|
findProcessParamListOrder({ productionOrderRoutingOperationId, productionOrderId })
|
.then(res => {
|
if (res.code === 200) {
|
const paramList = res.data || [];
|
params.value = paramList;
|
reportForm.paramGroups = {};
|
paramList.forEach(param => {
|
if (!reportForm.paramGroups[param.id]) { reportForm.paramGroups[param.id] = ""; }
|
if (param.paramType == "3" && param.paramFormat) { getDictOptions(param.paramFormat); }
|
});
|
}
|
})
|
.catch(err => { console.error("获取工序参数失败:", err); })
|
.finally(() => { paramLoading.value = false; });
|
};
|
|
onMounted(() => {
|
userStore.getInfo();
|
getList();
|
userListNoPageByTenantId().then(res => {
|
if (res.code === 200) { userOptions.value = res.data; }
|
});
|
});
|
</script>
|
|
<style scoped lang="scss">
|
.search-row { display: flex; align-items: center; gap: 12px; }
|
.search-item { display: flex; align-items: center; }
|
.search_title { margin-right: 8px; font-size: 14px; color: #606266; }
|
.transfer-card-title { text-align: center; font-size: 24px; font-weight: bold; margin-bottom: 20px; color: #303133; }
|
.transfer-card-container { display: flex; justify-content: space-between; padding: 20px; }
|
.transfer-card-info { flex: 1; margin-right: 20px; }
|
.info-group { margin-bottom: 20px; }
|
.info-item { display: flex; margin-bottom: 10px; }
|
.info-label { width: 100px; font-weight: bold; color: #606266; }
|
.info-value { flex: 1; color: #303133; }
|
.transfer-card-qr { display: flex; flex-direction: column; align-items: center; }
|
.qr-container { text-align: center; }
|
.print-button-container { text-align: center; margin-top: 20px; }
|
.param-grid { margin-top: 10px; border-top: 1px solid #ebe9f3; padding-top: 10px; }
|
.param-item { margin-bottom: 12px; }
|
.param-input-group { display: flex; align-items: center; gap: 8px; }
|
.param-input { flex: 1; }
|
.param-select { flex: 1; }
|
.param-unit { color: #909399; font-size: 12px; min-width: 30px; }
|
</style>
|
|
<style lang="scss">
|
@media print {
|
@page { size: landscape; }
|
body * { visibility: hidden; }
|
.el-dialog__wrapper, .el-dialog, .el-dialog__body,
|
.transfer-card-title, .transfer-card-container, .transfer-card-container *,
|
.info-item, .info-label, .info-value { visibility: visible; }
|
.print-button-container { visibility: hidden; }
|
.el-dialog__wrapper { position: absolute; top: 0; left: 0; right: 0; margin: 0; }
|
.el-dialog { width: 100% !important; max-width: 800px; margin: 0 auto !important; }
|
.el-dialog__header, .el-dialog__footer { display: none; }
|
.el-dialog__body { padding: 20px; }
|
.transfer-card-container { height: auto; display: flex; gap: 20px; }
|
.transfer-card-info {
|
.info-group { width: 100%; float: none; margin-bottom: 20px; }
|
.info-item { display: flex; margin-bottom: 10px;
|
.info-label { width: 100px; font-weight: bold; margin-right: 15px; white-space: nowrap; }
|
.info-value { flex: 1; word-break: break-word; }
|
}
|
}
|
.transfer-card-qr { width: 160px; display: flex; flex-direction: column; align-items: center; justify-content: flex-start; }
|
.qr-container img { width: 140px !important; height: 140px !important; }
|
}
|
</style>
|