优化混炼示方,新增种类配置
This commit is contained in:
@@ -18,7 +18,10 @@ export const getExportUrl = Api.exportXls;
|
||||
export const getImportUrl = Api.importExcel;
|
||||
export const list = (params) => defHttp.get({ url: Api.list, params });
|
||||
export const queryById = (params) => defHttp.get({ url: Api.queryById, params });
|
||||
export const saveOrUpdate = (params, isUpdate) => defHttp.post({ url: isUpdate ? Api.edit : Api.save, params });
|
||||
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A45】混炼示方主子表保存延长超时避免误报失败-----------
|
||||
export const saveOrUpdate = (params, isUpdate) =>
|
||||
defHttp.post({ url: isUpdate ? Api.edit : Api.save, params, timeout: 60 * 1000 });
|
||||
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A45】混炼示方主子表保存延长超时避免误报失败-----------
|
||||
export const queryIssueNumberOptions = (params) => defHttp.get({ url: Api.queryIssueNumberOptions, params });
|
||||
export const queryPurposeOptions = (params) => defHttp.get({ url: Api.queryPurposeOptions, params });
|
||||
|
||||
|
||||
@@ -91,10 +91,27 @@ export const materialColumns: JVxeColumn[] = [
|
||||
{ title: '物料大类', key: 'materialMajor', type: JVxeTypes.input, width: 100, minWidth: MIXING_MATERIAL_MIN_COLUMN_WIDTH },
|
||||
{ title: '物料小类', key: 'materialMinor', type: JVxeTypes.input, width: 120, minWidth: MIXING_MATERIAL_MIN_COLUMN_WIDTH },
|
||||
{ title: '种类', key: 'materialKind', type: JVxeTypes.input, width: 80, minWidth: MIXING_MATERIAL_MIN_COLUMN_WIDTH },
|
||||
{ title: '密炼物料名称', key: 'mixerMaterialName', type: JVxeTypes.input, width: 160, minWidth: MIXING_MATERIAL_MIN_COLUMN_WIDTH },
|
||||
{
|
||||
title: '密炼物料名称',
|
||||
key: 'mixerMaterialName',
|
||||
type: JVxeTypes.slot,
|
||||
slotName: 'mixerMaterialNameSlot',
|
||||
width: 160,
|
||||
minWidth: MIXING_MATERIAL_MIN_COLUMN_WIDTH,
|
||||
},
|
||||
{ title: '密炼物料描述', key: 'mixerMaterialDesc', type: JVxeTypes.input, width: 220, minWidth: MIXING_MATERIAL_MIN_COLUMN_WIDTH },
|
||||
{ title: '单重', key: 'unitWeight', type: JVxeTypes.inputNumber, width: 72, minWidth: MIXING_MATERIAL_MIN_COLUMN_WIDTH, align: 'center' },
|
||||
{ title: '累计', key: 'accumWeight', type: JVxeTypes.inputNumber, width: 72, minWidth: MIXING_MATERIAL_MIN_COLUMN_WIDTH, align: 'center' },
|
||||
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A41】累计列按种类分组合计只读展示-----------
|
||||
{
|
||||
title: '累计',
|
||||
key: 'accumWeight',
|
||||
type: JVxeTypes.inputNumber,
|
||||
width: 72,
|
||||
minWidth: MIXING_MATERIAL_MIN_COLUMN_WIDTH,
|
||||
align: 'center',
|
||||
disabled: true,
|
||||
},
|
||||
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A41】累计列按种类分组合计只读展示-----------
|
||||
{ title: '顺序', key: 'seqNo', type: JVxeTypes.inputNumber, width: 64, minWidth: MIXING_MATERIAL_MIN_COLUMN_WIDTH, align: 'center' },
|
||||
];
|
||||
|
||||
@@ -196,6 +213,280 @@ export function calcMixingMaterialTableWidth(columns: JVxeColumn[], widthMap: Re
|
||||
}
|
||||
//update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A17】橡胶及配合剂明细列展示设置-----------
|
||||
|
||||
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A41】橡胶及配合剂明细累计按种类分组合计-----------
|
||||
/** 是否为有效明细行(参与种类分组) */
|
||||
function isMixingMaterialDataRow(row: Recordable): boolean {
|
||||
if (!row) {
|
||||
return false;
|
||||
}
|
||||
return !!(row.mixerMaterialName || row.materialKind || row.unitWeight != null && row.unitWeight !== '');
|
||||
}
|
||||
|
||||
/** 规范化种类字段,用于连续行分组 */
|
||||
function normalizeMixingMaterialKind(row: Recordable): string {
|
||||
const kind = row?.materialKind;
|
||||
return kind != null && String(kind).trim() !== '' ? String(kind).trim() : '';
|
||||
}
|
||||
|
||||
/** 按种类连续分组,累计写入每组最后一行 */
|
||||
export function fillMixingMaterialAccumWeight(rows: Recordable[] = []): Recordable[] {
|
||||
if (!rows?.length) {
|
||||
return rows;
|
||||
}
|
||||
let index = 0;
|
||||
while (index < rows.length) {
|
||||
const current = rows[index];
|
||||
if (!isMixingMaterialDataRow(current)) {
|
||||
current.accumWeight = null;
|
||||
index++;
|
||||
continue;
|
||||
}
|
||||
const kind = normalizeMixingMaterialKind(current);
|
||||
let groupEnd = index;
|
||||
let sum = 0;
|
||||
while (groupEnd < rows.length) {
|
||||
const row = rows[groupEnd];
|
||||
if (!isMixingMaterialDataRow(row) || normalizeMixingMaterialKind(row) !== kind) {
|
||||
break;
|
||||
}
|
||||
const weight = toMixingMaterialNumber(row.unitWeight);
|
||||
if (weight != null) {
|
||||
sum += weight;
|
||||
}
|
||||
groupEnd++;
|
||||
}
|
||||
for (let rowIndex = index; rowIndex < groupEnd; rowIndex++) {
|
||||
rows[rowIndex].accumWeight =
|
||||
rowIndex === groupEnd - 1 && sum !== 0 ? roundMixingMaterialNumber(sum) : null;
|
||||
}
|
||||
index = groupEnd;
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
/** 安全解析明细数值,避免字符串拼接 */
|
||||
function toMixingMaterialNumber(value: unknown): number | null {
|
||||
if (value == null || value === '') {
|
||||
return null;
|
||||
}
|
||||
const num = Number(value);
|
||||
return Number.isFinite(num) ? num : null;
|
||||
}
|
||||
|
||||
/** 混炼示方重量小数位(与后端 BigDecimal 精度一致) */
|
||||
const MIXING_MATERIAL_WEIGHT_SCALE = 6;
|
||||
|
||||
/** 重量四舍五入,消除浮点累加误差 */
|
||||
function roundMixingMaterialNumber(value: number): number {
|
||||
return Number(value.toFixed(MIXING_MATERIAL_WEIGHT_SCALE));
|
||||
}
|
||||
|
||||
/** 格式化重量展示文本 */
|
||||
function formatMixingMaterialWeight(value: unknown): string {
|
||||
const num = toMixingMaterialNumber(value);
|
||||
if (num == null) {
|
||||
return '';
|
||||
}
|
||||
return String(roundMixingMaterialNumber(num));
|
||||
}
|
||||
|
||||
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A43】换算系数联动明细单重实时计算-----------
|
||||
/** 规范化换算系数,空值或非正数按 1 处理 */
|
||||
export function normalizeMixingConvertFactor(factor: unknown): number {
|
||||
const num = toMixingMaterialNumber(factor);
|
||||
if (num == null || num <= 0) {
|
||||
return 1;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
/** 基准单重 × 换算系数 */
|
||||
export function calcMixingMaterialConvertedWeight(base: unknown, factor: unknown): number | null {
|
||||
const baseNum = toMixingMaterialNumber(base);
|
||||
if (baseNum == null) {
|
||||
return null;
|
||||
}
|
||||
return Number((baseNum * normalizeMixingConvertFactor(factor)).toFixed(MIXING_MATERIAL_WEIGHT_SCALE));
|
||||
}
|
||||
|
||||
/** 从当前显示单重反推基准单重 */
|
||||
export function syncMaterialBaseUnitWeightFromDisplay(row: Recordable, factor: unknown) {
|
||||
if (!row) {
|
||||
return;
|
||||
}
|
||||
const unit = toMixingMaterialNumber(row.unitWeight);
|
||||
if (unit == null) {
|
||||
row.baseUnitWeight = null;
|
||||
return;
|
||||
}
|
||||
row.baseUnitWeight = Number((unit / normalizeMixingConvertFactor(factor)).toFixed(MIXING_MATERIAL_WEIGHT_SCALE));
|
||||
}
|
||||
|
||||
/** 初始化明细行基准单重(编辑加载时由已保存单重反推) */
|
||||
export function initMaterialBaseUnitWeight(row: Recordable, factor: unknown, force = false) {
|
||||
if (!isMixingMaterialDataRow(row)) {
|
||||
row.baseUnitWeight = null;
|
||||
return;
|
||||
}
|
||||
if (!force && toMixingMaterialNumber(row.baseUnitWeight) != null) {
|
||||
return;
|
||||
}
|
||||
syncMaterialBaseUnitWeightFromDisplay(row, factor);
|
||||
}
|
||||
|
||||
/** 批量初始化基准单重 */
|
||||
export function initMaterialBaseUnitWeights(rows: Recordable[] = [], factor: unknown, force = false) {
|
||||
for (const row of rows) {
|
||||
initMaterialBaseUnitWeight(row, factor, force);
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
/** 按换算系数重算所有明细单重 */
|
||||
export function applyConvertFactorToMaterialRows(
|
||||
rows: Recordable[] = [],
|
||||
factor: unknown,
|
||||
prevFactor?: unknown,
|
||||
): Recordable[] {
|
||||
const nextFactor = normalizeMixingConvertFactor(factor);
|
||||
const oldFactor = prevFactor != null ? normalizeMixingConvertFactor(prevFactor) : nextFactor;
|
||||
for (const row of rows) {
|
||||
if (!isMixingMaterialDataRow(row)) {
|
||||
continue;
|
||||
}
|
||||
let base = toMixingMaterialNumber(row.baseUnitWeight);
|
||||
if (base == null) {
|
||||
const unit = toMixingMaterialNumber(row.unitWeight);
|
||||
if (unit == null) {
|
||||
continue;
|
||||
}
|
||||
base = roundMixingMaterialNumber(unit / oldFactor);
|
||||
row.baseUnitWeight = base;
|
||||
}
|
||||
row.unitWeight = calcMixingMaterialConvertedWeight(base, nextFactor);
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A43】换算系数联动明细单重实时计算-----------
|
||||
|
||||
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A46】填充体积按单重/比重/机台有效体积自动计算-----------
|
||||
/** 解析设备有效体积(支持纯数字或带单位字符串) */
|
||||
export function parseMixingEffectiveVolume(raw: unknown): number | null {
|
||||
if (raw == null || raw === '') {
|
||||
return null;
|
||||
}
|
||||
const text = String(raw).trim();
|
||||
if (!text) {
|
||||
return null;
|
||||
}
|
||||
const direct = toMixingMaterialNumber(text);
|
||||
if (direct != null && direct > 0) {
|
||||
return direct;
|
||||
}
|
||||
const matched = text.match(/([0-9]+(?:\.[0-9]+)?)/);
|
||||
if (!matched) {
|
||||
return null;
|
||||
}
|
||||
const parsed = Number(matched[1]);
|
||||
return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
|
||||
}
|
||||
|
||||
/** 按段数与比重字段选择本段计算用比重 */
|
||||
export function resolveMixingSpecificGravity(form: Recordable = {}): number | null {
|
||||
const motherSg = toMixingMaterialNumber(form.motherRubberSg);
|
||||
const finalSg = toMixingMaterialNumber(form.finalRubberSg);
|
||||
const stageCount = String(form.stageCount || '').trim();
|
||||
const stageMatch = stageCount.match(/^(\d+)\/(\d+)$/);
|
||||
const isFinalStage = stageMatch ? stageMatch[1] === stageMatch[2] : false;
|
||||
if (isFinalStage && finalSg != null && finalSg > 0) {
|
||||
return finalSg;
|
||||
}
|
||||
if (motherSg != null && motherSg > 0) {
|
||||
return motherSg;
|
||||
}
|
||||
if (finalSg != null && finalSg > 0) {
|
||||
return finalSg;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 填充体积(%) = 单重合计 ÷ 比重 ÷ 机台有效体积(L) × 100
|
||||
* 单重合计已含换算系数,此处不再重复乘换算系数
|
||||
*/
|
||||
export function calcMixingFillVolume(totalWeight: unknown, specificGravity: unknown, effectiveVolume: unknown): number | null {
|
||||
const weight = toMixingMaterialNumber(totalWeight);
|
||||
const sg = toMixingMaterialNumber(specificGravity);
|
||||
const volume = parseMixingEffectiveVolume(effectiveVolume);
|
||||
if (weight == null || weight <= 0 || sg == null || sg <= 0 || volume == null || volume <= 0) {
|
||||
return null;
|
||||
}
|
||||
const materialVolume = weight / sg;
|
||||
return Number(((materialVolume / volume) * 100).toFixed(6));
|
||||
}
|
||||
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A46】填充体积按单重/比重/机台有效体积自动计算-----------
|
||||
|
||||
/** 汇总有效明细行的单重合计 */
|
||||
export function calcMixingMaterialUnitWeightTotal(rows: Recordable[] = []): number | null {
|
||||
let sum = 0;
|
||||
let hasAny = false;
|
||||
for (const row of rows) {
|
||||
if (!isMixingMaterialDataRow(row)) {
|
||||
continue;
|
||||
}
|
||||
const weight = toMixingMaterialNumber(row.unitWeight);
|
||||
if (weight != null) {
|
||||
sum += weight;
|
||||
hasAny = true;
|
||||
}
|
||||
}
|
||||
return hasAny ? roundMixingMaterialNumber(sum) : null;
|
||||
}
|
||||
|
||||
/** 汇总有效明细行的累计合计(与单重合计一致) */
|
||||
export function calcMixingMaterialAccumWeightTotal(rows: Recordable[] = []): number | null {
|
||||
return calcMixingMaterialUnitWeightTotal(rows);
|
||||
}
|
||||
|
||||
export interface MixingMaterialFooterCell {
|
||||
key: string;
|
||||
width: number;
|
||||
text: string;
|
||||
align?: 'left' | 'center' | 'right';
|
||||
isLabel?: boolean;
|
||||
isTotal?: boolean;
|
||||
}
|
||||
|
||||
/** 构建橡胶及配合剂明细底部合计行单元格(列宽与明细表同步) */
|
||||
export function buildMixingMaterialFooterCells(
|
||||
columns: JVxeColumn[],
|
||||
widthMap: Record<string, number>,
|
||||
totals: { unitWeight?: number | null; accumWeight?: number | null },
|
||||
): MixingMaterialFooterCell[] {
|
||||
const unitWeightIndex = columns.findIndex((col) => String(col.key) === 'unitWeight');
|
||||
const formatTotal = (value: number | null | undefined) => formatMixingMaterialWeight(value);
|
||||
|
||||
return columns.map((col, index) => {
|
||||
const key = String(col.key);
|
||||
const width = widthMap[key] ?? Number(col.width) ?? 80;
|
||||
if (key === 'unitWeight') {
|
||||
return { key, width, text: formatTotal(totals.unitWeight), align: 'center', isTotal: true };
|
||||
}
|
||||
if (key === 'accumWeight') {
|
||||
return { key, width, text: formatTotal(totals.accumWeight), align: 'center', isTotal: true };
|
||||
}
|
||||
const isLabelCol = unitWeightIndex > 0 && index === unitWeightIndex - 1;
|
||||
return {
|
||||
key,
|
||||
width,
|
||||
text: isLabelCol ? '合计' : '',
|
||||
align: 'center',
|
||||
isLabel: isLabelCol,
|
||||
};
|
||||
});
|
||||
}
|
||||
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A41】橡胶及配合剂明细累计按种类分组合计-----------
|
||||
|
||||
//update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A20】明细表默认列宽对齐参考图-----------
|
||||
/** 混合步骤/下密炼机明细列可缩小到的最小宽度 */
|
||||
export const MIXING_STEP_MIN_COLUMN_WIDTH = 48;
|
||||
@@ -412,6 +703,9 @@ export const MIXING_VXE_MINI_HEADER_HEIGHT = 36;
|
||||
/** vxe mini 行高 */
|
||||
export const MIXING_VXE_MINI_ROW_HEIGHT = 32;
|
||||
|
||||
/** 橡胶及配合剂明细合计行高度(含边框) */
|
||||
export const MIXING_MATERIAL_FOOTER_ROW_HEIGHT = MIXING_VXE_MINI_ROW_HEIGHT + 1;
|
||||
|
||||
//update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A29】胶料/混合步骤表格高度按行数完整展示-----------
|
||||
/** 计算橡胶及配合剂明细表格展示高度 */
|
||||
export function calcMixingMaterialTableHeight(rowCount = MIXING_MATERIAL_VISIBLE_ROW_COUNT) {
|
||||
@@ -637,3 +931,99 @@ export function ensureMixingDetailRows(rows: Recordable[] = [], defaultCount: nu
|
||||
}
|
||||
//update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A39】编辑页明细补齐默认空行与新增一致-----------
|
||||
//update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A22】明细表默认空行数-----------
|
||||
|
||||
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A50】混炼示方密炼物料选料弹窗与种类解析-----------
|
||||
/** 混炼示方选料弹窗:隐藏的小类 ID 偏好 localStorage 键 */
|
||||
export const MIXING_MATERIAL_PICKER_HIDDEN_CATEGORY_CACHE_KEY = 'mes_xsl_mixing_spec_material_picker_hidden_categories';
|
||||
|
||||
export interface MixingMaterialPickerCategoryItem {
|
||||
id: string;
|
||||
name: string;
|
||||
majorId: string;
|
||||
majorName: string;
|
||||
label: string;
|
||||
}
|
||||
|
||||
const mixingMaterialPickerStorage = createLocalStorage();
|
||||
|
||||
export function loadMixingMaterialPickerHiddenCategoryIds(): string[] {
|
||||
const raw = mixingMaterialPickerStorage.get(MIXING_MATERIAL_PICKER_HIDDEN_CATEGORY_CACHE_KEY);
|
||||
return Array.isArray(raw) ? raw.map(String) : [];
|
||||
}
|
||||
|
||||
export function saveMixingMaterialPickerHiddenCategoryIds(ids: string[]) {
|
||||
mixingMaterialPickerStorage.set(MIXING_MATERIAL_PICKER_HIDDEN_CATEGORY_CACHE_KEY, ids || []);
|
||||
}
|
||||
|
||||
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A50】选料弹窗小类树为空时重置隐藏配置-----------
|
||||
/** 过滤无效隐藏项;若全部小类被隐藏则自动重置,避免左侧树只剩「全部小类」 */
|
||||
export function sanitizeMixingMaterialPickerHiddenCategoryIds(allMinorIds: string[], hidden: string[]) {
|
||||
const allSet = new Set((allMinorIds || []).map(String));
|
||||
const filtered = (hidden || []).map(String).filter((id) => allSet.has(id));
|
||||
if (allSet.size > 0 && filtered.length >= allSet.size) {
|
||||
return [];
|
||||
}
|
||||
return filtered;
|
||||
}
|
||||
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A50】选料弹窗小类树为空时重置隐藏配置-----------
|
||||
|
||||
/** 解析混炼示方明细种类:小类勾选胶料则显示「胶料」,否则显示小类名 */
|
||||
export function resolveMixingMaterialKindFromCategory(isRubber?: unknown, minorName?: string) {
|
||||
if (isRubber === '1' || isRubber === 1 || isRubber === true) {
|
||||
return '胶料';
|
||||
}
|
||||
return minorName != null && String(minorName).trim() !== '' ? String(minorName).trim() : '';
|
||||
}
|
||||
|
||||
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A50】选料弹窗自动/人工称量列与种类映射-----------
|
||||
/** 与配合示方「自动/人工」列相同字典 */
|
||||
export const MIXING_MATERIAL_PICKER_WEIGH_MODE_DICT = 'xslmes_formula_spec_weigh_mode';
|
||||
|
||||
/** 选料弹窗表格列(隐藏 ERP 编号,新增仅本次有效的自动/人工称量) */
|
||||
export const mixingMaterialPickerTableColumns: BasicColumn[] = [
|
||||
{ title: '物料编码', align: 'center', width: 120, dataIndex: 'materialCode' },
|
||||
{ title: '物料名称', align: 'center', width: 160, dataIndex: 'materialName' },
|
||||
{ title: '自动/人工称量', align: 'center', width: 132, dataIndex: 'pickerWeighMode' },
|
||||
{ title: '物料大类', align: 'center', width: 120, dataIndex: 'majorCategoryId_dictText' },
|
||||
{ title: '物料小类', align: 'center', width: 120, dataIndex: 'minorCategoryId_dictText' },
|
||||
{ title: '物料描述', align: 'center', width: 180, ellipsis: true, dataIndex: 'materialDesc' },
|
||||
];
|
||||
|
||||
/** 配合示方称量方式 -> 混炼示方种类(与后端 resolveWeighModeMaterialKind 一致) */
|
||||
export function resolveMixingMaterialKindFromWeighMode(weighMode?: string) {
|
||||
if (weighMode == null || String(weighMode).trim() === '') {
|
||||
return '';
|
||||
}
|
||||
const normalized = String(weighMode).trim();
|
||||
const lower = normalized.toLowerCase();
|
||||
if (lower.startsWith('auto') || normalized.includes('自动')) {
|
||||
return '自动';
|
||||
}
|
||||
if (lower === 'manual' || normalized.includes('人工')) {
|
||||
return '人工';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/** 选料确认时种类:称量方式优先,否则按小类胶料/小类名 */
|
||||
export function resolveMixingMaterialKindForPicker(weighMode: string | undefined, isRubber?: unknown, minorName?: string) {
|
||||
const fromWeighMode = resolveMixingMaterialKindFromWeighMode(weighMode);
|
||||
if (fromWeighMode) {
|
||||
return fromWeighMode;
|
||||
}
|
||||
return resolveMixingMaterialKindFromCategory(isRubber, minorName);
|
||||
}
|
||||
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A50】选料弹窗自动/人工称量列与种类映射-----------
|
||||
|
||||
/** 选择密炼物料后回填混炼示方橡胶及配合剂明细行 */
|
||||
export function applyMixingMaterialFromSelection(row: Recordable, material: Recordable, materialKind: string) {
|
||||
if (!row || !material) {
|
||||
return;
|
||||
}
|
||||
row.mixerMaterialName = material.materialName || material.materialCode || '';
|
||||
row.mixerMaterialDesc = material.materialDesc || material.materialName || material.materialCode || '';
|
||||
row.materialMajor = material.majorCategoryId_dictText || '';
|
||||
row.materialMinor = material.minorCategoryId_dictText || '';
|
||||
row.materialKind = materialKind || row.materialMinor || '';
|
||||
}
|
||||
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A50】混炼示方密炼物料选料弹窗与种类解析-----------
|
||||
|
||||
@@ -0,0 +1,221 @@
|
||||
<template>
|
||||
<Popover
|
||||
v-model:open="popoverOpen"
|
||||
trigger="click"
|
||||
placement="bottomRight"
|
||||
:overlayClassName="`${prefixCls}__popover`"
|
||||
@open-change="handleOpenChange"
|
||||
>
|
||||
<template #title>
|
||||
<div :class="`${prefixCls}__title`">
|
||||
<Checkbox :indeterminate="indeterminate" :checked="checkAll" :disabled="loading || !allCategoryIds.length" @change="onCheckAllChange">
|
||||
小类展示
|
||||
</Checkbox>
|
||||
</div>
|
||||
</template>
|
||||
<template #content>
|
||||
<Spin :spinning="loading">
|
||||
<div v-if="!loading && !groupedCategories.length" :class="`${prefixCls}__empty`">
|
||||
暂无物料小类,请确认分类字典 XSLMES_MATERIAL 已配置
|
||||
</div>
|
||||
<div v-else :class="`${prefixCls}__list`">
|
||||
<div v-for="group in groupedCategories" :key="group.majorId" :class="`${prefixCls}__group`">
|
||||
<div :class="`${prefixCls}__group-title`">{{ group.majorName }}</div>
|
||||
<div :class="`${prefixCls}__group-options`">
|
||||
<Checkbox
|
||||
v-for="opt in group.options"
|
||||
:key="opt.value"
|
||||
:checked="isMinorVisible(opt.value)"
|
||||
@change="(e) => onMinorVisibleChange(opt.value, e.target.checked)"
|
||||
>
|
||||
{{ opt.label }}
|
||||
</Checkbox>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Spin>
|
||||
<div :class="`${prefixCls}__footer`">
|
||||
<a-button size="small" :disabled="loading || !allCategoryIds.length" @click="handleReset">重置</a-button>
|
||||
<a-button size="small" type="primary" :disabled="loading || !allCategoryIds.length" @click="handleSave">保存</a-button>
|
||||
</div>
|
||||
</template>
|
||||
<a-tooltip title="小类展示设置">
|
||||
<a-button size="small" class="mixing-material-category-setting-btn" :disabled="loading" @click.stop>
|
||||
<Icon icon="ant-design:setting-outlined" />
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
</Popover>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref, watch, type PropType } from 'vue';
|
||||
import { Popover, Checkbox, Spin } from 'ant-design-vue';
|
||||
import type { CheckboxChangeEvent } from 'ant-design-vue/lib/checkbox/interface';
|
||||
import { Icon } from '/@/components/Icon';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import { saveMixingMaterialPickerHiddenCategoryIds, type MixingMaterialPickerCategoryItem } from '../MesXslMixingSpec.data';
|
||||
|
||||
const prefixCls = 'mixing-material-category-setting';
|
||||
const { createMessage } = useMessage();
|
||||
|
||||
const props = defineProps({
|
||||
categories: {
|
||||
type: Array as PropType<MixingMaterialPickerCategoryItem[]>,
|
||||
default: () => [],
|
||||
},
|
||||
hiddenCategoryIds: {
|
||||
type: Array as PropType<string[]>,
|
||||
default: () => [],
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['update:hiddenCategoryIds', 'change']);
|
||||
|
||||
const popoverOpen = ref(false);
|
||||
const draftVisibleIds = ref<string[]>([]);
|
||||
|
||||
const allCategoryIds = computed(() => (props.categories || []).map((item) => item.id));
|
||||
|
||||
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A50】选料弹窗小类设置按大类分组展示-----------
|
||||
const groupedCategories = computed(() => {
|
||||
const groupMap = new Map<string, { majorId: string; majorName: string; options: { label: string; value: string }[] }>();
|
||||
(props.categories || []).forEach((item) => {
|
||||
const majorId = item.majorId || 'unknown';
|
||||
const majorName = item.majorName || '其他';
|
||||
const group = groupMap.get(majorId) || { majorId, majorName, options: [] };
|
||||
group.options.push({
|
||||
label: item.name,
|
||||
value: item.id,
|
||||
});
|
||||
groupMap.set(majorId, group);
|
||||
});
|
||||
return Array.from(groupMap.values());
|
||||
});
|
||||
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A50】选料弹窗小类设置按大类分组展示-----------
|
||||
|
||||
const checkAll = computed(() => {
|
||||
const all = allCategoryIds.value;
|
||||
if (!all.length) {
|
||||
return false;
|
||||
}
|
||||
return draftVisibleIds.value.length === all.length;
|
||||
});
|
||||
|
||||
const indeterminate = computed(() => {
|
||||
const total = allCategoryIds.value.length;
|
||||
const checked = draftVisibleIds.value.length;
|
||||
return checked > 0 && checked < total;
|
||||
});
|
||||
|
||||
watch(
|
||||
() => [props.hiddenCategoryIds, props.categories],
|
||||
() => {
|
||||
syncDraftFromHidden();
|
||||
},
|
||||
{ deep: true, immediate: true },
|
||||
);
|
||||
|
||||
function syncDraftFromHidden() {
|
||||
const hidden = new Set((props.hiddenCategoryIds || []).map(String));
|
||||
draftVisibleIds.value = allCategoryIds.value.filter((id) => !hidden.has(String(id)));
|
||||
}
|
||||
|
||||
function handleOpenChange(open: boolean) {
|
||||
popoverOpen.value = open;
|
||||
if (open) {
|
||||
syncDraftFromHidden();
|
||||
}
|
||||
}
|
||||
|
||||
function onCheckAllChange(e: CheckboxChangeEvent) {
|
||||
draftVisibleIds.value = e.target.checked ? [...allCategoryIds.value] : [];
|
||||
}
|
||||
|
||||
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A50】小类展示分组勾选互不覆盖-----------
|
||||
function isMinorVisible(id: string) {
|
||||
return draftVisibleIds.value.map(String).includes(String(id));
|
||||
}
|
||||
|
||||
function onMinorVisibleChange(id: string, checked: boolean) {
|
||||
const visibleSet = new Set(draftVisibleIds.value.map(String));
|
||||
const key = String(id);
|
||||
if (checked) {
|
||||
visibleSet.add(key);
|
||||
} else {
|
||||
visibleSet.delete(key);
|
||||
}
|
||||
draftVisibleIds.value = allCategoryIds.value.filter((itemId) => visibleSet.has(String(itemId)));
|
||||
}
|
||||
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A50】小类展示分组勾选互不覆盖-----------
|
||||
|
||||
function handleReset() {
|
||||
draftVisibleIds.value = [...allCategoryIds.value];
|
||||
}
|
||||
|
||||
function handleSave() {
|
||||
const visibleSet = new Set(draftVisibleIds.value.map(String));
|
||||
const hidden = allCategoryIds.value.filter((id) => !visibleSet.has(String(id)));
|
||||
saveMixingMaterialPickerHiddenCategoryIds(hidden);
|
||||
emit('update:hiddenCategoryIds', hidden);
|
||||
emit('change', hidden);
|
||||
popoverOpen.value = false;
|
||||
createMessage.success('小类展示设置已保存');
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.mixing-material-category-setting-btn {
|
||||
padding-inline: 8px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="less">
|
||||
.mixing-material-category-setting__popover {
|
||||
.ant-popover-inner-content {
|
||||
width: 320px;
|
||||
max-width: 80vw;
|
||||
}
|
||||
}
|
||||
|
||||
.mixing-material-category-setting__empty {
|
||||
padding: 12px 0;
|
||||
color: var(--text-color-secondary, rgba(0, 0, 0, 0.45));
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.mixing-material-category-setting__list {
|
||||
max-height: 320px;
|
||||
overflow: auto;
|
||||
padding: 4px 0 8px;
|
||||
}
|
||||
|
||||
.mixing-material-category-setting__group + .mixing-material-category-setting__group {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.mixing-material-category-setting__group-title {
|
||||
font-weight: 600;
|
||||
margin-bottom: 6px;
|
||||
color: var(--text-color, rgba(0, 0, 0, 0.88));
|
||||
}
|
||||
|
||||
.mixing-material-category-setting__group {
|
||||
.mixing-material-category-setting__group-options {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.mixing-material-category-setting__footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
padding-top: 8px;
|
||||
border-top: 1px solid var(--border-color-base, #f0f0f0);
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,406 @@
|
||||
<template>
|
||||
<BasicModal
|
||||
v-bind="$attrs"
|
||||
title="选择密炼物料"
|
||||
:width="1180"
|
||||
:getContainer="getModalContainer"
|
||||
@register="registerModal"
|
||||
@ok="handleOk"
|
||||
>
|
||||
<div class="mixing-material-picker">
|
||||
<div class="mixing-material-picker-toolbar">
|
||||
<a-input
|
||||
v-model:value="keyword"
|
||||
allow-clear
|
||||
placeholder="关键字(物料编码/名称/描述)"
|
||||
style="width: 280px"
|
||||
@pressEnter="reloadTable"
|
||||
/>
|
||||
<a-button type="primary" @click="reloadTable">搜索</a-button>
|
||||
<MesXslMixingMaterialCategorySetting
|
||||
v-model:hiddenCategoryIds="hiddenCategoryIds"
|
||||
:categories="allMinorCategories"
|
||||
:loading="treeLoading"
|
||||
@change="handleCategoryVisibilityChange"
|
||||
/>
|
||||
</div>
|
||||
<div class="mixing-material-picker-body">
|
||||
<aside class="mixing-material-picker-sider">
|
||||
<div class="mixing-material-picker-sider-title">物料小类</div>
|
||||
<Spin :spinning="treeLoading">
|
||||
<BasicTree
|
||||
:treeData="visibleCategoryTree"
|
||||
:selectedKeys="selectedCategoryKeys"
|
||||
:expandedKeys="expandedCategoryKeys"
|
||||
defaultExpandLevel="2"
|
||||
@update:selectedKeys="onCategorySelect"
|
||||
@update:expandedKeys="onExpandedKeysChange"
|
||||
/>
|
||||
</Spin>
|
||||
</aside>
|
||||
<div class="mixing-material-picker-main">
|
||||
<BasicTable @register="registerTable">
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.dataIndex === 'pickerWeighMode'">
|
||||
<div class="mixing-material-picker-weigh-mode" @click.stop>
|
||||
<JDictSelectTag
|
||||
:value="getPickerWeighMode(record.id)"
|
||||
:dictCode="MIXING_MATERIAL_PICKER_WEIGH_MODE_DICT"
|
||||
:getPopupContainer="getSelectPopupContainer"
|
||||
:showChooseOption="false"
|
||||
placeholder="请选择"
|
||||
popupClassName="mixing-material-picker-weigh-mode-dropdown"
|
||||
style="width: 100%"
|
||||
@change="(val) => setPickerWeighMode(record.id, val)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</BasicTable>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</BasicModal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, onMounted, ref, watch } from 'vue';
|
||||
import { Spin } from 'ant-design-vue';
|
||||
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||
import { BasicTable, useTable } from '/@/components/Table';
|
||||
import { BasicTree } from '/@/components/Tree';
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
import { loadMesMaterialCategoryTreeData } from '/@/views/system/category/category.constants';
|
||||
import { list as mixerList, queryById as queryMixerById } from '/@/views/mes/material/MesMixerMaterial.api';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import JDictSelectTag from '/@/components/Form/src/jeecg/components/JDictSelectTag.vue';
|
||||
import MesXslMixingMaterialCategorySetting from './MesXslMixingMaterialCategorySetting.vue';
|
||||
import {
|
||||
applyMixingMaterialFromSelection,
|
||||
loadMixingMaterialPickerHiddenCategoryIds,
|
||||
MIXING_MATERIAL_PICKER_WEIGH_MODE_DICT,
|
||||
mixingMaterialPickerTableColumns,
|
||||
resolveMixingMaterialKindForPicker,
|
||||
sanitizeMixingMaterialPickerHiddenCategoryIds,
|
||||
saveMixingMaterialPickerHiddenCategoryIds,
|
||||
type MixingMaterialPickerCategoryItem,
|
||||
} from '../MesXslMixingSpec.data';
|
||||
import type { KeyType } from '/@/components/Tree/src/types/tree';
|
||||
|
||||
const TREE_ALL = 'ALL';
|
||||
const emit = defineEmits(['register', 'select']);
|
||||
const { createMessage } = useMessage();
|
||||
|
||||
const keyword = ref('');
|
||||
const treeLoading = ref(false);
|
||||
const rawCategoryTree = ref<Recordable[]>([]);
|
||||
const allMajorCategories = ref<Array<{ id: string; name: string; minors: MixingMaterialPickerCategoryItem[] }>>([]);
|
||||
const allMinorCategories = ref<MixingMaterialPickerCategoryItem[]>([]);
|
||||
const hiddenCategoryIds = ref<string[]>(loadMixingMaterialPickerHiddenCategoryIds());
|
||||
const selectedCategoryKeys = ref<KeyType[]>([TREE_ALL]);
|
||||
const expandedCategoryKeys = ref<KeyType[]>([TREE_ALL]);
|
||||
const selectedRow = ref<Recordable | null>(null);
|
||||
const categoryRubberMap = ref<Record<string, boolean>>({});
|
||||
const pickerWeighModeMap = ref<Record<string, string>>({});
|
||||
|
||||
const hiddenCategoryIdSet = computed(() => new Set(hiddenCategoryIds.value.map(String)));
|
||||
|
||||
function getModalContainer() {
|
||||
return document.body;
|
||||
}
|
||||
|
||||
function getSelectPopupContainer() {
|
||||
return document.body;
|
||||
}
|
||||
|
||||
function filterHiddenCategoryTree(nodes: Recordable[], hidden: Set<string>): Recordable[] {
|
||||
return (nodes || [])
|
||||
.map((major) => {
|
||||
const children = (major.children || [])
|
||||
.filter((minor) => !hidden.has(String(minor.key)))
|
||||
.map((minor) => ({
|
||||
key: minor.key,
|
||||
title: minor.title,
|
||||
}));
|
||||
if (!children.length) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
key: major.key,
|
||||
title: major.title,
|
||||
children,
|
||||
};
|
||||
})
|
||||
.filter(Boolean) as Recordable[];
|
||||
}
|
||||
|
||||
const visibleCategoryTree = computed(() => [
|
||||
{
|
||||
key: TREE_ALL,
|
||||
title: '全部小类',
|
||||
children: filterHiddenCategoryTree(rawCategoryTree.value, hiddenCategoryIdSet.value),
|
||||
},
|
||||
]);
|
||||
|
||||
function syncExpandedCategoryKeys() {
|
||||
const keys: KeyType[] = [TREE_ALL];
|
||||
for (const major of visibleCategoryTree.value[0]?.children || []) {
|
||||
keys.push(major.key);
|
||||
}
|
||||
expandedCategoryKeys.value = keys;
|
||||
}
|
||||
|
||||
watch(
|
||||
visibleCategoryTree,
|
||||
() => {
|
||||
syncExpandedCategoryKeys();
|
||||
},
|
||||
{ deep: true },
|
||||
);
|
||||
|
||||
const selectedCategoryFilter = computed(() => {
|
||||
const key = selectedCategoryKeys.value[0];
|
||||
if (!key || key === TREE_ALL) {
|
||||
return {};
|
||||
}
|
||||
const keyStr = String(key);
|
||||
const major = allMajorCategories.value.find((item) => item.id === keyStr);
|
||||
if (major) {
|
||||
return { majorCategoryId: major.id };
|
||||
}
|
||||
return { minorCategoryId: keyStr };
|
||||
});
|
||||
|
||||
const [registerTable, { reload, getSelectRowKeys, getSelectRows, clearSelectedRowKeys }] = useTable({
|
||||
api: mixerList,
|
||||
columns: mixingMaterialPickerTableColumns,
|
||||
rowKey: 'id',
|
||||
useSearchForm: false,
|
||||
pagination: { pageSize: 10 },
|
||||
canResize: false,
|
||||
showIndexColumn: true,
|
||||
immediate: true,
|
||||
beforeFetch: (params) => {
|
||||
const next = { ...params, ...selectedCategoryFilter.value };
|
||||
const kw = keyword.value?.trim();
|
||||
if (kw) {
|
||||
next.materialName = `*${kw}*`;
|
||||
}
|
||||
return next;
|
||||
},
|
||||
rowSelection: {
|
||||
type: 'radio',
|
||||
columnWidth: 48,
|
||||
onChange: (_keys, rows) => {
|
||||
selectedRow.value = rows?.[0] ?? null;
|
||||
},
|
||||
},
|
||||
clickToRowSelect: true,
|
||||
});
|
||||
|
||||
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A50】选料弹窗打开时初始化(对齐其他SelectModal)-----------
|
||||
const [registerModal, { setModalProps, closeModal }] = useModalInner(async () => {
|
||||
await initPickerModal();
|
||||
});
|
||||
|
||||
async function initPickerModal() {
|
||||
selectedRow.value = null;
|
||||
keyword.value = '';
|
||||
pickerWeighModeMap.value = {};
|
||||
clearSelectedRowKeys?.();
|
||||
hiddenCategoryIds.value = loadMixingMaterialPickerHiddenCategoryIds();
|
||||
selectedCategoryKeys.value = [TREE_ALL];
|
||||
setModalProps({ confirmLoading: false });
|
||||
await loadMaterialCategoryTree();
|
||||
reloadTable();
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadMaterialCategoryTree();
|
||||
});
|
||||
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A50】选料弹窗打开时初始化(对齐其他SelectModal)-----------
|
||||
|
||||
async function loadMaterialCategoryTree() {
|
||||
treeLoading.value = true;
|
||||
try {
|
||||
const { majors, minors, treeNodes } = await loadMesMaterialCategoryTreeData();
|
||||
rawCategoryTree.value = treeNodes;
|
||||
allMajorCategories.value = majors;
|
||||
allMinorCategories.value = minors;
|
||||
|
||||
const sanitizedHidden = sanitizeMixingMaterialPickerHiddenCategoryIds(
|
||||
minors.map((item) => item.id),
|
||||
hiddenCategoryIds.value,
|
||||
);
|
||||
if (sanitizedHidden.length !== hiddenCategoryIds.value.length) {
|
||||
hiddenCategoryIds.value = sanitizedHidden;
|
||||
saveMixingMaterialPickerHiddenCategoryIds(sanitizedHidden);
|
||||
}
|
||||
|
||||
categoryRubberMap.value = {};
|
||||
syncExpandedCategoryKeys();
|
||||
|
||||
if (!minors.length) {
|
||||
createMessage.warning('未加载到物料小类,请确认分类字典根编码 XSLMES_MATERIAL 及其下级分类已配置。');
|
||||
}
|
||||
} catch {
|
||||
rawCategoryTree.value = [];
|
||||
allMajorCategories.value = [];
|
||||
allMinorCategories.value = [];
|
||||
createMessage.warning('加载物料分类树失败,请检查分类根编码 XSLMES_MATERIAL 是否存在。');
|
||||
} finally {
|
||||
treeLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function reloadTable() {
|
||||
reload();
|
||||
}
|
||||
|
||||
function getPickerWeighMode(materialId?: string) {
|
||||
if (!materialId) {
|
||||
return undefined;
|
||||
}
|
||||
return pickerWeighModeMap.value[String(materialId)];
|
||||
}
|
||||
|
||||
function setPickerWeighMode(materialId: string | undefined, value?: string) {
|
||||
if (!materialId) {
|
||||
return;
|
||||
}
|
||||
const key = String(materialId);
|
||||
const next = { ...pickerWeighModeMap.value };
|
||||
if (value == null || value === '') {
|
||||
delete next[key];
|
||||
} else {
|
||||
next[key] = String(value);
|
||||
}
|
||||
pickerWeighModeMap.value = next;
|
||||
}
|
||||
|
||||
function onCategorySelect(keys: KeyType[]) {
|
||||
selectedCategoryKeys.value = keys?.length ? keys : [TREE_ALL];
|
||||
reloadTable();
|
||||
}
|
||||
|
||||
function onExpandedKeysChange(keys: KeyType[]) {
|
||||
expandedCategoryKeys.value = keys?.length ? keys : [TREE_ALL];
|
||||
}
|
||||
|
||||
function handleCategoryVisibilityChange() {
|
||||
const key = selectedCategoryKeys.value[0];
|
||||
if (!key || key === TREE_ALL) {
|
||||
syncExpandedCategoryKeys();
|
||||
reloadTable();
|
||||
return;
|
||||
}
|
||||
const keyStr = String(key);
|
||||
const hidden = hiddenCategoryIdSet.value;
|
||||
const major = allMajorCategories.value.find((item) => item.id === keyStr);
|
||||
if (major) {
|
||||
const hasVisibleMinor = major.minors.some((minor) => !hidden.has(String(minor.id)));
|
||||
if (!hasVisibleMinor) {
|
||||
selectedCategoryKeys.value = [TREE_ALL];
|
||||
}
|
||||
} else if (hidden.has(keyStr)) {
|
||||
selectedCategoryKeys.value = [TREE_ALL];
|
||||
}
|
||||
syncExpandedCategoryKeys();
|
||||
reloadTable();
|
||||
}
|
||||
|
||||
async function resolveKindForMaterial(material: Recordable, weighMode?: string) {
|
||||
const minorId = material?.minorCategoryId ? String(material.minorCategoryId) : '';
|
||||
const minorName = material?.minorCategoryId_dictText || '';
|
||||
if (!minorId) {
|
||||
return resolveMixingMaterialKindForPicker(weighMode, false, minorName);
|
||||
}
|
||||
if (categoryRubberMap.value[minorId] === undefined) {
|
||||
try {
|
||||
const cat = await defHttp.get<Recordable>({ url: '/sys/category/queryById', params: { id: minorId } });
|
||||
categoryRubberMap.value[minorId] = cat?.isRubber === '1' || cat?.isRubber === 1;
|
||||
} catch {
|
||||
categoryRubberMap.value[minorId] = false;
|
||||
}
|
||||
}
|
||||
return resolveMixingMaterialKindForPicker(
|
||||
weighMode,
|
||||
categoryRubberMap.value[minorId] ? '1' : '0',
|
||||
minorName,
|
||||
);
|
||||
}
|
||||
|
||||
async function handleOk() {
|
||||
const keys = (getSelectRowKeys?.() || []) as string[];
|
||||
let row = selectedRow.value || ((getSelectRows?.() || []) as Recordable[])[0];
|
||||
if (!row && keys.length) {
|
||||
try {
|
||||
const raw = await queryMixerById({ id: keys[0] });
|
||||
row = (raw as any)?.id != null ? raw : (raw as any)?.result;
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
if (!row?.id) {
|
||||
createMessage.warning('请选择一条密炼物料');
|
||||
return;
|
||||
}
|
||||
const weighMode = getPickerWeighMode(row.id);
|
||||
const payload: Recordable = { ...row, pickerWeighMode: weighMode };
|
||||
const materialKind = await resolveKindForMaterial(row, weighMode);
|
||||
applyMixingMaterialFromSelection(payload, row, materialKind);
|
||||
emit('select', payload);
|
||||
closeModal();
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.mixing-material-picker {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
min-height: 520px;
|
||||
}
|
||||
|
||||
.mixing-material-picker-toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.mixing-material-picker-body {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
min-height: 480px;
|
||||
}
|
||||
|
||||
.mixing-material-picker-sider {
|
||||
width: 240px;
|
||||
flex-shrink: 0;
|
||||
border: 1px solid var(--border-color-base, #f0f0f0);
|
||||
border-radius: 4px;
|
||||
padding: 8px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.mixing-material-picker-sider-title {
|
||||
font-weight: 600;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.mixing-material-picker-main {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.mixing-material-picker-weigh-mode {
|
||||
min-width: 108px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="less">
|
||||
/* 下拉挂到 body,避免表格 overflow 裁剪;层级高于 Modal */
|
||||
.mixing-material-picker-weigh-mode-dropdown {
|
||||
z-index: 2100 !important;
|
||||
}
|
||||
</style>
|
||||
@@ -55,7 +55,15 @@
|
||||
<tr>
|
||||
<th class="formTitle" colspan="1">换算系数</th>
|
||||
<td class="formValue" colspan="2">
|
||||
<a-input-number v-model:value="sheetForm.convertFactor" :disabled="!showFooter" :precision="6" :bordered="false" class="form-input" style="width: 100%" />
|
||||
<a-input-number
|
||||
v-model:value="sheetForm.convertFactor"
|
||||
:disabled="!showFooter"
|
||||
:precision="6"
|
||||
:bordered="false"
|
||||
class="form-input"
|
||||
style="width: 100%"
|
||||
@update:value="handleConvertFactorChange"
|
||||
/>
|
||||
</td>
|
||||
<th class="formTitle" colspan="1">填充体积</th>
|
||||
<td class="formValue" colspan="1">
|
||||
@@ -80,7 +88,7 @@
|
||||
</td>
|
||||
<th class="formTitle" colspan="1">母胶比重</th>
|
||||
<td class="formValue">
|
||||
<a-input-number v-model:value="sheetForm.motherRubberSg" :disabled="!showFooter" :precision="6" :bordered="false" class="form-input" style="width: 100%" />
|
||||
<a-input-number v-model:value="sheetForm.motherRubberSg" :disabled="!showFooter" :precision="6" :bordered="false" class="form-input" style="width: 100%" @update:value="recalcFillVolume" />
|
||||
</td>
|
||||
<th class="formTitle">段数</th>
|
||||
<td class="formValue" colspan="2">
|
||||
@@ -104,7 +112,7 @@
|
||||
<tr>
|
||||
<th class="formTitle" colspan="1">终炼胶比重</th>
|
||||
<td class="formValue">
|
||||
<a-input-number v-model:value="sheetForm.finalRubberSg" :disabled="!showFooter" :precision="6" :bordered="false" class="form-input" style="width: 100%" />
|
||||
<a-input-number v-model:value="sheetForm.finalRubberSg" :disabled="!showFooter" :precision="6" :bordered="false" class="form-input" style="width: 100%" @update:value="recalcFillVolume" />
|
||||
</td>
|
||||
<th class="formTitle" colspan="1">适用工厂</th>
|
||||
<td class="formValue" colspan="2">
|
||||
@@ -181,25 +189,60 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="material-table-wrap" :style="{ height: `${materialMainTableHeight}px` }">
|
||||
<JVxeTable
|
||||
:key="materialTableLayoutKey"
|
||||
ref="materialRef"
|
||||
row-number
|
||||
keep-source
|
||||
bordered
|
||||
:fit="false"
|
||||
:column-config="{ resizable: true }"
|
||||
:row-config="materialRowConfig"
|
||||
size="mini"
|
||||
:height="materialMainTableHeight"
|
||||
:scroll-x="{ enabled: false }"
|
||||
:scroll-y="{ enabled: true }"
|
||||
:columns="visibleMaterialColumns"
|
||||
:dataSource="materialData"
|
||||
:disabled="!showFooter"
|
||||
@resizable-change="handleMaterialColumnResize"
|
||||
@column-resizable-change="handleMaterialColumnResize"
|
||||
/>
|
||||
<!--update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A42】橡胶及配合剂明细底部固定合计行----------- -->
|
||||
<div class="material-table-stack" :style="{ width: `${materialTableWidth}px` }">
|
||||
<div class="material-table-body" :style="{ height: `${materialBodyTableHeight}px` }">
|
||||
<JVxeTable
|
||||
:key="materialTableLayoutKey"
|
||||
ref="materialRef"
|
||||
row-number
|
||||
keep-source
|
||||
bordered
|
||||
:fit="false"
|
||||
:column-config="{ resizable: true }"
|
||||
:row-config="materialRowConfig"
|
||||
size="mini"
|
||||
:height="materialBodyTableHeight"
|
||||
:scroll-x="{ enabled: false }"
|
||||
:scroll-y="{ enabled: true }"
|
||||
:columns="visibleMaterialColumns"
|
||||
:dataSource="materialData"
|
||||
:disabled="!showFooter"
|
||||
@value-change="handleMaterialValueChange"
|
||||
@resizable-change="handleMaterialColumnResize"
|
||||
@column-resizable-change="handleMaterialColumnResize"
|
||||
>
|
||||
<template #mixerMaterialNameSlot="{ row }">
|
||||
<div
|
||||
class="mixing-material-name-cell"
|
||||
:class="{ 'is-disabled': !showFooter }"
|
||||
:style="{ minHeight: `${materialHeightPref.rowHeight}px` }"
|
||||
@click.stop="openMixingMaterialPicker(row)"
|
||||
>
|
||||
<span v-if="row.mixerMaterialName" class="mixing-material-name-text">{{ row.mixerMaterialName }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</JVxeTable>
|
||||
</div>
|
||||
<div class="material-table-footer">
|
||||
<div class="material-table-footer-row">
|
||||
<div
|
||||
class="material-footer-seq"
|
||||
:style="{ width: `${MIXING_MATERIAL_ROW_NUMBER_WIDTH}px`, height: `${materialHeightPref.rowHeight}px` }"
|
||||
></div>
|
||||
<div
|
||||
v-for="cell in materialFooterCells"
|
||||
:key="cell.key"
|
||||
class="material-footer-cell"
|
||||
:class="{ 'is-label': cell.isLabel, 'is-total': cell.isTotal }"
|
||||
:style="{ width: `${cell.width}px`, height: `${materialHeightPref.rowHeight}px` }"
|
||||
>
|
||||
{{ cell.text }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A42】橡胶及配合剂明细底部固定合计行----------- -->
|
||||
</div>
|
||||
<!--update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A18】TCU温度条件表移至橡胶及配合剂下方----------- -->
|
||||
<div class="left-panel-section left-panel-section-tcu">
|
||||
@@ -368,11 +411,11 @@
|
||||
</div>
|
||||
|
||||
<BasicForm v-show="false" @register="registerForm" />
|
||||
|
||||
<MesXslEquipmentLedgerSelectModal @register="registerMachineModal" @select="onMachineSelect" />
|
||||
<MesXslMixerPsCompileSelectModal @register="registerIssueNumberModal" @select="onIssueNumberSelect" />
|
||||
</div>
|
||||
</BasicModal>
|
||||
<MesXslEquipmentLedgerSelectModal @register="registerMachineModal" @select="onMachineSelect" />
|
||||
<MesXslMixerPsCompileSelectModal @register="registerIssueNumberModal" @select="onIssueNumberSelect" />
|
||||
<MesXslMixingMaterialSelectModal @register="registerMixingMaterialModal" @select="onMixingMaterialSelect" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
@@ -411,6 +454,19 @@ import {
|
||||
DEFAULT_MIXING_STEP_ROW_COUNT,
|
||||
DEFAULT_MIXING_DOWN_STEP_ROW_COUNT,
|
||||
buildDefaultMixingTcuRows,
|
||||
applyMixingMaterialFromSelection,
|
||||
fillMixingMaterialAccumWeight,
|
||||
calcMixingMaterialUnitWeightTotal,
|
||||
calcMixingMaterialAccumWeightTotal,
|
||||
buildMixingMaterialFooterCells,
|
||||
normalizeMixingConvertFactor,
|
||||
initMaterialBaseUnitWeights,
|
||||
applyConvertFactorToMaterialRows,
|
||||
syncMaterialBaseUnitWeightFromDisplay,
|
||||
calcMixingFillVolume,
|
||||
resolveMixingSpecificGravity,
|
||||
MIXING_MATERIAL_ROW_NUMBER_WIDTH,
|
||||
MIXING_MATERIAL_FOOTER_ROW_HEIGHT,
|
||||
MIXING_MATERIAL_MIN_COLUMN_WIDTH,
|
||||
MIXING_TCU_MIN_COLUMN_WIDTH,
|
||||
MIXING_STEP_MIN_COLUMN_WIDTH,
|
||||
@@ -422,7 +478,9 @@ import MesXslMixingStepSelectCell from './MesXslMixingStepSelectCell.vue';
|
||||
import { list as mixerActionList } from '/@/views/xslmes/mesXslMixerAction/MesXslMixerAction.api';
|
||||
import { list as mixerConditionList } from '/@/views/xslmes/mesXslMixerCondition/MesXslMixerCondition.api';
|
||||
import MesXslEquipmentLedgerSelectModal from '/@/views/xslmes/mesXslEquipInspectConfig/components/MesXslEquipmentLedgerSelectModal.vue';
|
||||
import { queryById as queryEquipmentById } from '/@/views/xslmes/mesXslEquipmentLedger/MesXslEquipmentLedger.api';
|
||||
import MesXslMixerPsCompileSelectModal from '/@/views/xslmes/mesXslMixerPsCompile/components/MesXslMixerPsCompileSelectModal.vue';
|
||||
import MesXslMixingMaterialSelectModal from './MesXslMixingMaterialSelectModal.vue';
|
||||
|
||||
const emit = defineEmits(['register', 'success']);
|
||||
const { createMessage } = useMessage();
|
||||
@@ -437,6 +495,7 @@ const mixerConditionOptions = ref<{ title: string; value: string }[]>([]);
|
||||
//update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A34】混合步骤动作/组合下拉选项-----------
|
||||
|
||||
const materialRef = ref();
|
||||
const materialPickerRow = ref<Recordable | null>(null);
|
||||
const stepRef = ref();
|
||||
const downStepRef = ref();
|
||||
const tcuRef = ref();
|
||||
@@ -465,6 +524,22 @@ const stepHeightPref = ref(loadMixingTableHeightPreference('step'));
|
||||
const downStepHeightPref = ref(loadMixingTableHeightPreference('downStep'));
|
||||
|
||||
const materialMainTableHeight = computed(() => calcMixingDetailTableViewportHeight('material', materialHeightPref.value));
|
||||
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A42】橡胶及配合剂明细底部固定合计行-----------
|
||||
const materialBodyTableHeight = computed(() =>
|
||||
Math.max(materialMainTableHeight.value - MIXING_MATERIAL_FOOTER_ROW_HEIGHT, 80),
|
||||
);
|
||||
const materialUnitWeightTotal = ref<number | null>(null);
|
||||
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A46】换算系数/单重/机台有效体积联动填充体积-----------
|
||||
const machineEffectiveVolume = ref('');
|
||||
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A46】换算系数/单重/机台有效体积联动填充体积-----------
|
||||
const materialAccumWeightTotal = ref<number | null>(null);
|
||||
const materialFooterCells = computed(() =>
|
||||
buildMixingMaterialFooterCells(visibleMaterialColumns.value, materialColumnWidths.value, {
|
||||
unitWeight: materialUnitWeightTotal.value,
|
||||
accumWeight: materialAccumWeightTotal.value,
|
||||
}),
|
||||
);
|
||||
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A42】橡胶及配合剂明细底部固定合计行-----------
|
||||
const stepMainTableHeight = computed(() => calcMixingDetailTableViewportHeight('step', stepHeightPref.value));
|
||||
const tcuTableHeight = computed(() => calcMixingDetailTableViewportHeight('tcu', tcuHeightPref.value));
|
||||
const downStepTableHeight = computed(() => calcMixingDetailTableViewportHeight('downStep', downStepHeightPref.value));
|
||||
@@ -509,6 +584,105 @@ function handleMaterialColumnResize(params: Recordable) {
|
||||
};
|
||||
saveMixingMaterialColumnWidths(materialColumnWidths.value);
|
||||
}
|
||||
|
||||
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A41】橡胶及配合剂明细累计按种类分组合计-----------
|
||||
/** JVxe getTableData 为浅拷贝,批量改值需用 fullData 原行并强制 refresh */
|
||||
function resolveMaterialTableRawRows(): Recordable[] {
|
||||
const fullData = materialRef.value?.getXTable?.()?.getTableData?.()?.fullData as Recordable[] | undefined;
|
||||
if (Array.isArray(fullData) && fullData.length) {
|
||||
return fullData;
|
||||
}
|
||||
return (materialRef.value?.getTableData?.() || materialData.value || []) as Recordable[];
|
||||
}
|
||||
|
||||
function refreshMaterialTableView() {
|
||||
materialRef.value?.getXTable?.()?.updateData?.();
|
||||
}
|
||||
|
||||
function applyMaterialAccumWeight(rows?: Recordable[]) {
|
||||
const targetRows = rows || resolveMaterialTableRawRows();
|
||||
fillMixingMaterialAccumWeight(targetRows);
|
||||
materialUnitWeightTotal.value = calcMixingMaterialUnitWeightTotal(targetRows);
|
||||
materialAccumWeightTotal.value = calcMixingMaterialAccumWeightTotal(targetRows);
|
||||
refreshMaterialTableView();
|
||||
recalcFillVolume();
|
||||
}
|
||||
|
||||
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A46】换算系数/单重/机台有效体积联动填充体积-----------
|
||||
async function loadMachineEffectiveVolume(machineId?: string) {
|
||||
const id = machineId || sheetForm.machineId;
|
||||
if (!id) {
|
||||
machineEffectiveVolume.value = '';
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const raw = await queryEquipmentById({ id });
|
||||
const row = (raw as Recordable)?.id != null ? raw : (raw as Recordable)?.result;
|
||||
machineEffectiveVolume.value = row?.effectiveVolume || '';
|
||||
} catch {
|
||||
machineEffectiveVolume.value = '';
|
||||
}
|
||||
}
|
||||
|
||||
function recalcFillVolume() {
|
||||
if (!showFooter.value) {
|
||||
return;
|
||||
}
|
||||
const totalWeight =
|
||||
materialUnitWeightTotal.value ?? calcMixingMaterialUnitWeightTotal(resolveMaterialTableRawRows());
|
||||
const specificGravity = resolveMixingSpecificGravity(sheetForm);
|
||||
const next = calcMixingFillVolume(totalWeight, specificGravity, machineEffectiveVolume.value);
|
||||
if (next != null) {
|
||||
sheetForm.fillVolume = next;
|
||||
}
|
||||
}
|
||||
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A46】换算系数/单重/机台有效体积联动填充体积-----------
|
||||
|
||||
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A43】换算系数联动明细单重实时计算-----------
|
||||
const lastConvertFactor = ref<number>(1);
|
||||
const convertFactorApplying = ref(false);
|
||||
|
||||
function applyConvertFactorToMaterials(factor: unknown) {
|
||||
const rows = resolveMaterialTableRawRows();
|
||||
applyConvertFactorToMaterialRows(rows, factor, lastConvertFactor.value);
|
||||
lastConvertFactor.value = normalizeMixingConvertFactor(factor);
|
||||
applyMaterialAccumWeight(rows);
|
||||
}
|
||||
|
||||
function handleConvertFactorChange(value: unknown) {
|
||||
if (!showFooter.value || convertFactorApplying.value) {
|
||||
return;
|
||||
}
|
||||
applyConvertFactorToMaterials(value);
|
||||
recalcFillVolume();
|
||||
}
|
||||
|
||||
function stripMaterialRowForSave(row: Recordable) {
|
||||
if (!row) {
|
||||
return row;
|
||||
}
|
||||
const { baseUnitWeight: _baseUnitWeight, ...rest } = row;
|
||||
return rest;
|
||||
}
|
||||
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A43】换算系数联动明细单重实时计算-----------
|
||||
|
||||
function recalcMaterialAccumWeight() {
|
||||
applyMaterialAccumWeight();
|
||||
}
|
||||
|
||||
function handleMaterialValueChange(event) {
|
||||
const key = event?.column?.key;
|
||||
const row = event?.row;
|
||||
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A43】换算系数联动明细单重实时计算-----------
|
||||
if (key === 'unitWeight' && row) {
|
||||
syncMaterialBaseUnitWeightFromDisplay(row, sheetForm.convertFactor);
|
||||
}
|
||||
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A43】换算系数联动明细单重实时计算-----------
|
||||
if (key === 'unitWeight' || key === 'materialKind') {
|
||||
recalcMaterialAccumWeight();
|
||||
}
|
||||
}
|
||||
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A41】橡胶及配合剂明细累计按种类分组合计-----------
|
||||
//update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A17】橡胶及配合剂明细列展示设置-----------
|
||||
|
||||
//update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A19】TCU温度条件表列宽可调且表头换行-----------
|
||||
@@ -710,6 +884,7 @@ const [registerForm, { resetFields, setFieldsValue, validate, setProps }] = useF
|
||||
//update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A33】混炼示方主表选择弹窗-----------
|
||||
const [registerMachineModal, { openModal: openMachineModalInner }] = useModal();
|
||||
const [registerIssueNumberModal, { openModal: openIssueNumberModalInner }] = useModal();
|
||||
const [registerMixingMaterialModal, { openModal: openMixingMaterialModalInner }] = useModal();
|
||||
|
||||
function openMachinePicker() {
|
||||
if (!showFooter.value) {
|
||||
@@ -721,6 +896,11 @@ function openMachinePicker() {
|
||||
async function onMachineSelect(payload: Recordable | null) {
|
||||
sheetForm.machineId = payload?.equipmentLedgerId || '';
|
||||
sheetForm.machineName = payload?.equipmentName || '';
|
||||
machineEffectiveVolume.value = payload?.effectiveVolume || '';
|
||||
if (sheetForm.machineId && !machineEffectiveVolume.value) {
|
||||
await loadMachineEffectiveVolume(sheetForm.machineId);
|
||||
}
|
||||
recalcFillVolume();
|
||||
await loadMixerStepOptions(sheetForm.machineId);
|
||||
}
|
||||
|
||||
@@ -738,6 +918,27 @@ function onIssueNumberSelect(payload: Recordable | null) {
|
||||
mixerPsCompilePickerId.value = payload.psCompileId || '';
|
||||
sheetForm.issueNumber = payload.psCode || '';
|
||||
}
|
||||
|
||||
function openMixingMaterialPicker(row: Recordable) {
|
||||
if (!showFooter.value || !row) {
|
||||
return;
|
||||
}
|
||||
materialPickerRow.value = row;
|
||||
openMixingMaterialModalInner(true, { picker: true, ts: Date.now() });
|
||||
}
|
||||
|
||||
function onMixingMaterialSelect(payload: Recordable | null) {
|
||||
if (!payload || !materialPickerRow.value) {
|
||||
return;
|
||||
}
|
||||
applyMixingMaterialFromSelection(
|
||||
materialPickerRow.value,
|
||||
payload,
|
||||
payload.materialKind || payload.materialMinor || '',
|
||||
);
|
||||
recalcMaterialAccumWeight();
|
||||
materialPickerRow.value = null;
|
||||
}
|
||||
//update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A33】混炼示方主表选择弹窗-----------
|
||||
|
||||
function ensureTcuDefaultRows(rows: Recordable[] = []) {
|
||||
@@ -783,6 +984,7 @@ function resetSheetForm() {
|
||||
sheetForm.approveTime = '';
|
||||
sheetForm.changeDate = '';
|
||||
mixerPsCompilePickerId.value = '';
|
||||
machineEffectiveVolume.value = '';
|
||||
refreshSignDisplay({});
|
||||
}
|
||||
|
||||
@@ -806,6 +1008,9 @@ const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data
|
||||
await resetFields();
|
||||
resetSheetForm();
|
||||
materialData.value = [];
|
||||
materialUnitWeightTotal.value = null;
|
||||
materialAccumWeightTotal.value = null;
|
||||
lastConvertFactor.value = 1;
|
||||
stepData.value = [];
|
||||
downStepData.value = [];
|
||||
tcuData.value = ensureTcuDefaultRows([]);
|
||||
@@ -819,10 +1024,16 @@ const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data
|
||||
const row = raw?.result || raw;
|
||||
Object.assign(sheetForm, row || {});
|
||||
refreshSignDisplay(row || {});
|
||||
await loadMachineEffectiveVolume(sheetForm.machineId);
|
||||
await loadMixerStepOptions(sheetForm.machineId);
|
||||
await syncSheetToForm();
|
||||
//update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A39】编辑页明细补齐默认空行与新增一致-----------
|
||||
materialData.value = ensureMixingDetailRows(row?.materialList || [], DEFAULT_MIXING_MATERIAL_ROW_COUNT);
|
||||
convertFactorApplying.value = true;
|
||||
initMaterialBaseUnitWeights(materialData.value, sheetForm.convertFactor, true);
|
||||
lastConvertFactor.value = normalizeMixingConvertFactor(sheetForm.convertFactor);
|
||||
applyMaterialAccumWeight(materialData.value);
|
||||
convertFactorApplying.value = false;
|
||||
stepData.value = ensureMixingDetailRows(row?.stepList || [], DEFAULT_MIXING_STEP_ROW_COUNT);
|
||||
downStepData.value = ensureMixingDetailRows(row?.downStepList || [], DEFAULT_MIXING_DOWN_STEP_ROW_COUNT);
|
||||
//update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A39】编辑页明细补齐默认空行与新增一致-----------
|
||||
@@ -838,6 +1049,7 @@ const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data
|
||||
});
|
||||
//update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A22】明细表默认空行数-----------
|
||||
materialData.value = createEmptyMaterialRows();
|
||||
lastConvertFactor.value = normalizeMixingConvertFactor(sheetForm.convertFactor);
|
||||
stepData.value = createEmptyStepRows();
|
||||
downStepData.value = createEmptyDownStepRows();
|
||||
//update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A22】明细表默认空行数-----------
|
||||
@@ -850,14 +1062,15 @@ const title = computed(() => (!showFooter.value && unref(isUpdate) ? '混炼示
|
||||
async function handleSubmit() {
|
||||
await syncSheetToForm();
|
||||
const formValues = await validate();
|
||||
const materialList = materialRef.value?.getTableData?.() || materialData.value;
|
||||
const materialList = resolveMaterialTableRawRows();
|
||||
applyMaterialAccumWeight(materialList);
|
||||
const stepList = stepRef.value?.getTableData?.() || stepData.value;
|
||||
const downStepList = downStepRef.value?.getTableData?.() || downStepData.value;
|
||||
const tcuList = ensureTcuDefaultRows((tcuRef.value?.getTableData?.() || tcuData.value) as Recordable[]);
|
||||
const cleanRows = (rows: Recordable[]) => (rows || []).filter((row) => Object.values(row || {}).some((v) => v != null && v !== ''));
|
||||
const payload = {
|
||||
...formValues,
|
||||
materialList: cleanRows(materialList),
|
||||
materialList: cleanRows(materialList).map(stripMaterialRowForSave),
|
||||
stepList: cleanRows(stepList),
|
||||
downStepList: cleanRows(downStepList),
|
||||
tcuList: tcuList.map((row) => ({
|
||||
@@ -1008,6 +1221,25 @@ async function handleSubmit() {
|
||||
color: #262626;
|
||||
}
|
||||
|
||||
:deep(.mixing-material-name-cell) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
padding: 2px 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
:deep(.mixing-material-name-cell.is-disabled) {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.65;
|
||||
}
|
||||
|
||||
:deep(.mixing-material-name-text) {
|
||||
color: #262626;
|
||||
}
|
||||
|
||||
}
|
||||
//update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A17】顶部施工表对齐旧系统13列表格-----------
|
||||
|
||||
@@ -1027,6 +1259,9 @@ async function handleSubmit() {
|
||||
|
||||
.material-table-wrap {
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
:deep(.jeecg-j-vxe-table),
|
||||
:deep(.j-vxe-table-box),
|
||||
@@ -1040,6 +1275,76 @@ async function handleSubmit() {
|
||||
}
|
||||
}
|
||||
|
||||
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A42】橡胶及配合剂明细底部固定合计行-----------
|
||||
.material-table-stack {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-shrink: 0;
|
||||
min-width: min-content;
|
||||
}
|
||||
|
||||
.material-table-body {
|
||||
flex: 0 0 auto;
|
||||
overflow: hidden;
|
||||
|
||||
:deep(.vxe-table--footer-wrapper) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
:deep(.col--mixerMaterialName .vxe-cell) {
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
:deep(.col--mixerMaterialName .vxe-cell > div) {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.material-table-footer {
|
||||
flex-shrink: 0;
|
||||
border: 1px solid #e8e8e8;
|
||||
border-top: none;
|
||||
background: #fafafa;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.material-table-footer-row {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
box-sizing: border-box;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.material-footer-seq,
|
||||
.material-footer-cell {
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-right: 1px solid #e8e8e8;
|
||||
box-sizing: border-box;
|
||||
padding: 0 2px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
&:last-child {
|
||||
border-right: none;
|
||||
}
|
||||
}
|
||||
|
||||
.material-footer-seq {
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
.material-footer-cell.is-label,
|
||||
.material-footer-cell.is-total {
|
||||
font-weight: 600;
|
||||
color: #262626;
|
||||
}
|
||||
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A42】橡胶及配合剂明细底部固定合计行-----------
|
||||
|
||||
//update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A26】TCU紧凑两行且胶料表向下扩展-----------
|
||||
.material-table-wrap--fill {
|
||||
flex: 1;
|
||||
|
||||
Reference in New Issue
Block a user