Merge branch '20260519-3.9.2版本-葛昊天分支'

This commit is contained in:
geht
2026-06-01 11:30:44 +08:00
7 changed files with 438 additions and 187 deletions

View File

@@ -17,8 +17,10 @@ export const MIXING_MATERIAL_ROW_NUMBER_WIDTH = 60;
/** 橡胶及配合剂明细列可缩小到的最小宽度 */
export const MIXING_MATERIAL_MIN_COLUMN_WIDTH = 40;
/** 默认隐藏的明细列 */
export const MIXING_MATERIAL_DEFAULT_HIDDEN_COLUMN_KEYS = ['materialMajor', 'materialKind'];
//update-begin---author:cursor ---date:20260601 for【XSLMES-20260601-A62】橡胶及配合剂明细默认展示种类列-----------
/** 默认隐藏的明细列(种类列默认展示,物料小类默认隐藏) */
export const MIXING_MATERIAL_DEFAULT_HIDDEN_COLUMN_KEYS = ['materialMajor', 'materialMinor'];
//update-end---author:cursor ---date:20260601 for【XSLMES-20260601-A62】橡胶及配合剂明细默认展示种类列-----------
/** 不允许隐藏的明细列 */
export const MIXING_MATERIAL_LOCKED_COLUMN_KEYS = ['mixerMaterialName'];
@@ -92,8 +94,17 @@ export const materialColumns: JVxeColumn[] = [
{ title: '密炼物料ID', key: 'mixerMaterialId', type: JVxeTypes.hidden },
//update-end---author:cursor ---date:20260525 for【XSLMES-20260525-A55】混炼示方明细关联密炼物料ID-----------
{ title: '物料大类', key: 'materialMajor', type: JVxeTypes.input, width: 100, minWidth: MIXING_MATERIAL_MIN_COLUMN_WIDTH },
//update-begin---author:cursor ---date:20260601 for【XSLMES-20260601-A62】种类列置于首列展示且只读-----------
{
title: '种类',
key: 'materialKind',
type: JVxeTypes.input,
width: 100,
minWidth: MIXING_MATERIAL_MIN_COLUMN_WIDTH,
disabled: true,
},
{ 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 },
//update-end---author:cursor ---date:20260601 for【XSLMES-20260601-A62】种类列置于首列展示且只读-----------
{
title: '密炼物料名称',
key: 'mixerMaterialName',
@@ -134,9 +145,16 @@ export function loadMixingMaterialHiddenColumnKeys(): string[] {
if (!Array.isArray(saved)) {
return MIXING_MATERIAL_DEFAULT_HIDDEN_COLUMN_KEYS.filter((key) => validKeys.has(key));
}
return saved.filter(
//update-begin---author:cursor ---date:20260601 for【XSLMES-20260601-A62】迁移列显示偏好原隐藏种类改为隐藏物料小类-----------
let keys = saved.filter(
(key) => typeof key === 'string' && !MIXING_MATERIAL_LOCKED_COLUMN_KEYS.includes(key) && validKeys.has(key),
);
if (keys.includes('materialKind') && !keys.includes('materialMinor')) {
keys = keys.filter((key) => key !== 'materialKind');
keys.push('materialMinor');
}
return keys;
//update-end---author:cursor ---date:20260601 for【XSLMES-20260601-A62】迁移列显示偏好原隐藏种类改为隐藏物料小类-----------
}
/** 保存已隐藏的橡胶及配合剂明细列 key */
@@ -1047,12 +1065,16 @@ export function sanitizeMixingMaterialPickerHiddenCategoryIds(allMinorIds: strin
export interface MixerMaterialKindLookup {
byRefId: Record<string, string>;
byRefCode: Record<string, string>;
//update-begin---author:cursor ---date:20260601 for【XSLMES-20260601-A62】种类查找表支持胶料类别名称-----------
byRefName?: Record<string, string>;
//update-end---author:cursor ---date:20260601 for【XSLMES-20260601-A62】种类查找表支持胶料类别名称-----------
rubberKindName?: string;
}
export const EMPTY_MIXER_MATERIAL_KIND_LOOKUP: MixerMaterialKindLookup = {
byRefId: {},
byRefCode: {},
byRefName: {},
rubberKindName: '胶料',
};
@@ -1074,6 +1096,9 @@ export async function loadMixingMaterialKindLookup(forceReload = false): Promise
const lookup: MixerMaterialKindLookup = {
byRefId: raw?.byRefId || {},
byRefCode: raw?.byRefCode || {},
//update-begin---author:cursor ---date:20260601 for【XSLMES-20260601-A62】加载种类配置含类别名称映射-----------
byRefName: raw?.byRefName || {},
//update-end---author:cursor ---date:20260601 for【XSLMES-20260601-A62】加载种类配置含类别名称映射-----------
rubberKindName: raw?.rubberKindName || '胶料',
};
mixingMaterialKindLookupCache = lookup;
@@ -1116,12 +1141,12 @@ function matchKindFromLookup(lookup: MixerMaterialKindLookup | null | undefined,
return '';
}
/** 解析混炼示方明细种类:称量方式优先,其次物料小类 ID未命中返回空,由配置表维护 */
/** 解析混炼示方明细种类:称量方式优先,其次类 ID,再按分类名称(未命中返回空) */
export function resolveMixingMaterialKindFromLookup(
lookup: MixerMaterialKindLookup | null | undefined,
weighMode?: string,
minorCategoryId?: string,
_minorCategoryName?: string,
minorCategoryName?: string,
) {
const fromWeighMode = matchKindFromLookup(lookup, weighMode);
if (fromWeighMode) {
@@ -1131,9 +1156,35 @@ export function resolveMixingMaterialKindFromLookup(
if (fromMinorId) {
return fromMinorId;
}
//update-begin---author:cursor ---date:20260601 for【XSLMES-20260601-A62】按胶料类别名称匹配种类配置-----------
if (minorCategoryName != null && String(minorCategoryName).trim() !== '') {
const refName = String(minorCategoryName).trim();
if (lookup?.byRefName?.[refName]) {
return lookup.byRefName[refName];
}
}
//update-end---author:cursor ---date:20260601 for【XSLMES-20260601-A62】按胶料类别名称匹配种类配置-----------
return '';
}
/** 胶料页签解析种类:配置匹配后可用 rubberKindName如「胶料」兜底 */
export function resolveMixingRubberKindForPicker(
lookup: MixerMaterialKindLookup | null | undefined,
weighMode?: string,
categoryId?: string,
categoryName?: string,
categoryCode?: string,
) {
let kind = resolveMixingMaterialKindFromLookup(lookup, weighMode, categoryId, categoryName);
if (!kind && categoryCode) {
kind = matchKindFromLookup(lookup, categoryCode);
}
if (!kind && lookup?.rubberKindName) {
kind = lookup.rubberKindName;
}
return kind;
}
/** @deprecated 保留兼容,请改用 resolveMixingMaterialKindFromLookup */
export function resolveMixingMaterialKindFromCategory(_isRubber?: unknown, minorName?: string) {
return minorName != null && String(minorName).trim() !== '' ? String(minorName).trim() : '';
@@ -1189,6 +1240,33 @@ export function applyMixingMaterialFromSelection(row: Recordable, material: Reco
}
//update-end---author:cursor ---date:20260525 for【XSLMES-20260525-A50】混炼示方密炼物料选料弹窗与种类解析-----------
//update-begin---author:cursor ---date:20260601 for【XSLMES-20260601-A62】选料弹窗新增胶料页签查询胶料信息-----------
/** 选料弹窗「胶料」页签表格列(数据源为胶料信息 mes_material */
export const mixingRubberPickerTableColumns: BasicColumn[] = [
{ title: '胶料编码', align: 'center', width: 140, dataIndex: 'materialCode' },
{ title: '胶料名称', align: 'center', width: 180, dataIndex: 'materialName' },
//update-begin---author:cursor ---date:20260601 for【XSLMES-20260601-A62】胶料页签补齐自动/人工称量列-----------
{ title: '自动/人工称量', align: 'center', width: 132, dataIndex: 'pickerWeighMode' },
//update-end---author:cursor ---date:20260601 for【XSLMES-20260601-A62】胶料页签补齐自动/人工称量列-----------
{ title: '种类', align: 'center', width: 100, dataIndex: 'pickerMaterialKind' },
{ title: '胶料类别', align: 'center', width: 140, dataIndex: 'categoryId_dictText' },
{ title: '胶料别名', align: 'center', width: 140, dataIndex: 'aliasName' },
];
/** 选择胶料信息后回填混炼示方橡胶及配合剂明细行(复用 mixerMaterialId 存 mes_material.id */
export function applyMixingRubberFromSelection(row: Recordable, material: Recordable, materialKind: string) {
if (!row || !material) {
return;
}
row.mixerMaterialId = material.id || '';
row.mixerMaterialName = material.materialName || material.materialCode || '';
row.mixerMaterialDesc = material.materialName || material.materialCode || '';
row.materialMajor = '';
row.materialMinor = material.categoryId_dictText || '';
row.materialKind = materialKind != null && String(materialKind).trim() !== '' ? String(materialKind).trim() : '';
}
//update-end---author:cursor ---date:20260601 for【XSLMES-20260601-A62】选料弹窗新增胶料页签查询胶料信息-----------
//update-begin---author:cursor ---date:20260526 for【XSLMES-20260526-A58】参照历史混合步骤选择弹窗-----------
/** 混合步骤可复制的业务字段 */
export const MIXING_STEP_COPY_FIELD_KEYS = [

View File

@@ -1,7 +1,7 @@
<template>
<BasicModal
v-bind="$attrs"
title="选择密炼物料"
title="选择物料"
:width="1280"
:zIndex="1500"
wrapClassName="mixing-material-picker-modal-wrap"
@@ -13,12 +13,14 @@
<a-input
v-model:value="keyword"
allow-clear
placeholder="关键字(物料编码/名称/描述)"
placeholder="关键字(编码/名称/描述)"
style="width: 280px"
@pressEnter="reloadTable"
/>
<a-button type="primary" @click="reloadTable">搜索</a-button>
<!--update-begin---author:cursor ---date:20260601 forXSLMES-20260601-A62仅密炼物料页签展示小类设置------------->
<MesXslMixingMaterialCategorySetting
v-if="pickerType === 'mixer'"
v-model:hiddenCategoryIds="hiddenCategoryIds"
:categories="allMinorCategories"
:loading="treeLoading"
@@ -26,20 +28,42 @@
@change="handleCategoryVisibilityChange"
@refresh="handleRefreshCategoryTree"
/>
<!--update-end---author:cursor ---date:20260601 forXSLMES-20260601-A62仅密炼物料页签展示小类设置------------->
</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>
<!--update-begin---author:cursor ---date:20260601 forXSLMES-20260601-A62选料弹窗左侧密炼物料/胶料页签------------->
<a-radio-group v-model:value="pickerType" button-style="solid" size="small" class="mixing-material-picker-tabs" @change="handleSwitchPickerType">
<a-radio-button value="mixer">密炼物料</a-radio-button>
<a-radio-button value="rubber">胶料</a-radio-button>
</a-radio-group>
<template v-if="pickerType === 'mixer'">
<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>
</template>
<template v-else>
<div class="mixing-material-picker-sider-title">胶料类别</div>
<Spin :spinning="rubberTreeLoading">
<BasicTree
:treeData="visibleRubberTree"
:selectedKeys="selectedRubberCategoryKeys"
:expandedKeys="expandedRubberCategoryKeys"
defaultExpandLevel="2"
@update:selectedKeys="onRubberCategorySelect"
@update:expandedKeys="onRubberExpandedKeysChange"
/>
</Spin>
</template>
<!--update-end---author:cursor ---date:20260601 forXSLMES-20260601-A62选料弹窗左侧密炼物料/胶料页签------------->
</aside>
<div class="mixing-material-picker-main">
<BasicTable @register="registerTable">
@@ -77,11 +101,20 @@
import { BasicTree } from '/@/components/Tree';
import { loadMesMaterialCategoryTreeData, hasMesMaterialCategoryTreeCache } from '/@/views/system/category/category.constants';
import { list as mixerList, queryById as queryMixerById } from '/@/views/mes/material/MesMixerMaterial.api';
//update-begin---author:cursor ---date:20260601 for【XSLMES-20260601-A62】胶料页签查询胶料信息(mes_material)------------->
import { list as rubberList, queryById as queryRubberById } from '/@/views/mes/material/MesMaterial.api';
import { loadTreeData } from '/@/api/common/api';
//update-end---author:cursor ---date:20260601 for【XSLMES-20260601-A62】胶料页签查询胶料信息(mes_material)------------->
import { useMessage } from '/@/hooks/web/useMessage';
import JDictSelectTag from '/@/components/Form/src/jeecg/components/JDictSelectTag.vue';
import MesXslMixingMaterialCategorySetting from './MesXslMixingMaterialCategorySetting.vue';
import {
applyMixingMaterialFromSelection,
//update-begin---author:cursor ---date:20260601 for【XSLMES-20260601-A62】引入胶料页签列与回填------------->
applyMixingRubberFromSelection,
mixingRubberPickerTableColumns,
resolveMixingRubberKindForPicker,
//update-end---author:cursor ---date:20260601 for【XSLMES-20260601-A62】引入胶料页签列与回填------------->
EMPTY_MIXER_MATERIAL_KIND_LOOKUP,
loadMixingMaterialKindLookup,
loadMixingMaterialPickerHiddenCategoryIds,
@@ -96,6 +129,34 @@
import type { KeyType } from '/@/components/Tree/src/types/tree';
const TREE_ALL = 'ALL';
//update-begin---author:cursor ---date:20260601 for【XSLMES-20260601-A62】选料弹窗数据源类型与胶料类别树------------->
const RUBBER_TREE_ALL = 'ALL';
const RUBBER_CATEGORY_PCODE = 'XSLMES_RUBBER';
const pickerType = ref<'mixer' | 'rubber'>('mixer');
const rubberTreeLoading = ref(false);
const rubberCategoryTree = ref<Recordable[]>([]);
/** 胶料类别 id -> { code, title },用于按种类配置编码匹配 */
const rubberCategoryMetaMap = ref<Map<string, { code?: string; title?: string }>>(new Map());
const selectedRubberCategoryKeys = ref<KeyType[]>([RUBBER_TREE_ALL]);
const expandedRubberCategoryKeys = ref<KeyType[]>([RUBBER_TREE_ALL]);
const visibleRubberTree = computed(() => [
{
key: RUBBER_TREE_ALL,
title: '全部胶料类别',
children: rubberCategoryTree.value || [],
},
]);
const selectedRubberCategoryFilter = computed(() => {
const key = selectedRubberCategoryKeys.value[0];
if (!key || key === RUBBER_TREE_ALL) {
return {};
}
return { categoryId: String(key) };
});
//update-end---author:cursor ---date:20260601 for【XSLMES-20260601-A62】选料弹窗数据源类型与胶料类别树------------->
const emit = defineEmits(['register', 'select']);
const { createMessage } = useMessage();
@@ -177,8 +238,13 @@
return { minorCategoryId: keyStr };
});
const [registerTable, { reload, getSelectRowKeys, getSelectRows, clearSelectedRowKeys }] = useTable({
api: mixerList,
//update-begin---author:cursor ---date:20260601 for【XSLMES-20260601-A62】右侧列表按页签切换数据源------------->
function pickerListApi(params: Recordable) {
return pickerType.value === 'rubber' ? rubberList(params) : mixerList(params);
}
const [registerTable, { reload, getSelectRowKeys, getSelectRows, clearSelectedRowKeys, setColumns }] = useTable({
api: pickerListApi,
columns: mixingMaterialPickerTableColumns,
rowKey: 'id',
useSearchForm: false,
@@ -187,13 +253,22 @@
showIndexColumn: true,
immediate: false,
beforeFetch: (params) => {
const next = { ...params, ...selectedCategoryFilter.value };
const kw = keyword.value?.trim();
if (pickerType.value === 'rubber') {
const rubberParams = { ...params, ...selectedRubberCategoryFilter.value };
if (kw) {
rubberParams.materialName = `*${kw}*`;
}
return rubberParams;
}
const next = { ...params, ...selectedCategoryFilter.value };
if (kw) {
next.materialName = `*${kw}*`;
}
return next;
},
//update-end---author:cursor ---date:20260601 for【XSLMES-20260601-A62】右侧列表按页签切换数据源------------->
rowSelection: {
type: 'radio',
columnWidth: 48,
@@ -218,11 +293,18 @@
clearSelectedRowKeys?.();
hiddenCategoryIds.value = loadMixingMaterialPickerHiddenCategoryIds();
selectedCategoryKeys.value = [TREE_ALL];
//update-begin---author:cursor ---date:20260601 for【XSLMES-20260601-A62】每次打开默认密炼物料页签------------->
pickerType.value = 'mixer';
selectedRubberCategoryKeys.value = [RUBBER_TREE_ALL];
setColumns(mixingMaterialPickerTableColumns);
//update-end---author:cursor ---date:20260601 for【XSLMES-20260601-A62】每次打开默认密炼物料页签------------->
setModalProps({ confirmLoading: false });
//update-begin---author:cursor ---date:20260525 for【XSLMES-20260525-A52】选料弹窗先加载左侧树再查右侧列表-----------
try {
await loadMaterialCategoryTree();
kindLookup.value = await loadMixingMaterialKindLookup(false);
//update-begin---author:cursor ---date:20260601 for【XSLMES-20260601-A62】打开弹窗刷新种类配置避免缓存旧数据-----------
kindLookup.value = await loadMixingMaterialKindLookup(true);
//update-end---author:cursor ---date:20260601 for【XSLMES-20260601-A62】打开弹窗刷新种类配置避免缓存旧数据-----------
reloadTable();
} finally {
pickerInitializing.value = false;
@@ -231,6 +313,64 @@
}
//update-end---author:cursor ---date:20260525 for【XSLMES-20260525-A50】选料弹窗打开时初始化对齐其他SelectModal-----------
//update-begin---author:cursor ---date:20260601 for【XSLMES-20260601-A62】页签切换 + 胶料类别树加载/选择------------->
async function handleSwitchPickerType() {
selectedRow.value = null;
clearSelectedRowKeys?.();
setColumns(pickerType.value === 'rubber' ? mixingRubberPickerTableColumns : mixingMaterialPickerTableColumns);
if (pickerType.value === 'rubber' && !rubberCategoryTree.value.length) {
await loadRubberCategoryTree();
}
reloadTable();
}
function flattenRubberCategoryTree(nodes: Recordable[], map: Map<string, { code?: string; title?: string }>) {
for (const node of nodes || []) {
const key = node?.key != null ? String(node.key) : '';
if (key) {
map.set(key, {
code: node.code != null ? String(node.code) : undefined,
title: node.title != null ? String(node.title) : undefined,
});
}
if (node?.children?.length) {
flattenRubberCategoryTree(node.children, map);
}
}
}
async function loadRubberCategoryTree() {
rubberTreeLoading.value = true;
try {
const res: any = await loadTreeData({ pcode: RUBBER_CATEGORY_PCODE });
const treeNodes = Array.isArray(res) ? res : res?.result || [];
rubberCategoryTree.value = treeNodes;
const metaMap = new Map<string, { code?: string; title?: string }>();
flattenRubberCategoryTree(treeNodes, metaMap);
rubberCategoryMetaMap.value = metaMap;
} catch {
rubberCategoryTree.value = [];
rubberCategoryMetaMap.value = new Map();
createMessage.warning('加载胶料类别失败,请检查分类根编码 XSLMES_RUBBER 是否存在。');
} finally {
rubberTreeLoading.value = false;
}
}
function onRubberCategorySelect(keys: KeyType[]) {
selectedRubberCategoryKeys.value = keys?.length ? keys : [RUBBER_TREE_ALL];
if (pickerInitializing.value) {
return;
}
reloadTable();
}
function onRubberExpandedKeysChange(keys: KeyType[]) {
expandedRubberCategoryKeys.value = keys?.length ? keys : [RUBBER_TREE_ALL];
}
//update-end---author:cursor ---date:20260601 for【XSLMES-20260601-A62】页签切换 + 胶料类别树加载/选择------------->
async function loadMaterialCategoryTree(forceReload = false) {
const hasCachedTree = !forceReload && (hasMesMaterialCategoryTreeCache() || rawCategoryTree.value.length > 0);
if (forceReload || !hasCachedTree) {
@@ -363,6 +503,15 @@
}
function resolvePickerMaterialKind(material: Recordable) {
//update-begin---author:cursor ---date:20260601 for【XSLMES-20260601-A62】胶料页签种类/自动人工称量解析------------->
if (pickerType.value === 'rubber') {
const weighMode = getPickerWeighMode(material?.id);
const catId = material?.categoryId ? String(material.categoryId) : '';
const catName = material?.categoryId_dictText || '';
const catCode = rubberCategoryMetaMap.value.get(catId)?.code || '';
return resolveMixingRubberKindForPicker(kindLookup.value, weighMode, catId, catName, catCode);
}
//update-end---author:cursor ---date:20260601 for【XSLMES-20260601-A62】胶料页签种类/自动人工称量解析------------->
const weighMode = getPickerWeighMode(material?.id);
const minorId = material?.minorCategoryId ? String(material.minorCategoryId) : '';
const minorName = material?.minorCategoryId_dictText || '';
@@ -380,12 +529,37 @@
let row = selectedRow.value || ((getSelectRows?.() || []) as Recordable[])[0];
if (!row && keys.length) {
try {
const raw = await queryMixerById({ id: keys[0] });
//update-begin---author:cursor ---date:20260601 for【XSLMES-20260601-A62】按页签查询选中行详情------------->
const queryById = pickerType.value === 'rubber' ? queryRubberById : queryMixerById;
const raw = await queryById({ id: keys[0] });
//update-end---author:cursor ---date:20260601 for【XSLMES-20260601-A62】按页签查询选中行详情------------->
row = (raw as any)?.id != null ? raw : (raw as any)?.result;
} catch {
// ignore
}
}
//update-begin---author:cursor ---date:20260601 for【XSLMES-20260601-A62】胶料页签选中回填明细------------->
if (pickerType.value === 'rubber') {
if (!row?.id) {
createMessage.warning('请选择一条胶料');
return;
}
const weighMode = getPickerWeighMode(row.id);
const catId = row.categoryId ? String(row.categoryId) : '';
const catName = row.categoryId_dictText || '';
const catCode = rubberCategoryMetaMap.value.get(catId)?.code || '';
const rubberKind = resolveMixingRubberKindForPicker(kindLookup.value, weighMode, catId, catName, catCode);
if (!rubberKind) {
createMessage.warning('未匹配到种类,请检查种类配置(胶料类别或「胶料」兜底种类)');
return;
}
const rubberPayload: Recordable = { ...row, pickerWeighMode: weighMode };
applyMixingRubberFromSelection(rubberPayload, row, rubberKind);
emit('select', rubberPayload);
closeModal();
return;
}
//update-end---author:cursor ---date:20260601 for【XSLMES-20260601-A62】胶料页签选中回填明细------------->
if (!row?.id) {
createMessage.warning('请选择一条密炼物料');
return;
@@ -439,6 +613,17 @@
margin-bottom: 8px;
}
/* 选料弹窗左侧密炼物料/胶料页签 */
.mixing-material-picker-tabs {
display: flex;
margin-bottom: 10px;
}
.mixing-material-picker-tabs :deep(.ant-radio-button-wrapper) {
flex: 1;
text-align: center;
}
.mixing-material-picker-main {
flex: 1;
min-width: 0;