This commit is contained in:
geht
2026-07-30 17:02:10 +08:00
352 changed files with 43647 additions and 385 deletions

View File

@@ -1,13 +1,18 @@
import { BasicColumn, FormSchema } from '/@/components/Table';
export const baseColumns: BasicColumn[] = [
{ title: '日期', align: 'center', dataIndex: 'statDate', width: 140 },
{ title: '原材料名称', align: 'center', dataIndex: 'rawMaterialName', width: 260, ellipsis: true },
{ title: '需求重量(KG)', align: 'center', dataIndex: 'demandWeight', width: 180 },
];
export const machineColumns: BasicColumn[] = [{ title: '机台', align: 'center', dataIndex: 'machineName', width: 180 }, ...baseColumns];
export const machineColumns: BasicColumn[] = [
baseColumns[0],
{ title: '机台', align: 'center', dataIndex: 'machineName', width: 180 },
...baseColumns.slice(1),
];
export const searchFormSchema: FormSchema[] = [
export const baseSearchFormSchema: FormSchema[] = [
{
label: '日期',
field: 'statDate',
@@ -18,6 +23,12 @@ export const searchFormSchema: FormSchema[] = [
{ label: '原材料名称', field: 'rawMaterialName', component: 'JInput', colProps: { span: 6 } },
];
export const machineSearchFormSchema: FormSchema[] = [
baseSearchFormSchema[0],
{ label: '机台', field: 'machineName', component: 'JInput', colProps: { span: 6 } },
...baseSearchFormSchema.slice(1),
];
export const superQuerySchema = {
machineName: { title: '机台', order: 0, view: 'text' },
statDate: { title: '日期', order: 1, view: 'date' },

View File

@@ -25,7 +25,8 @@
import {
baseColumns,
machineColumns,
searchFormSchema,
baseSearchFormSchema,
machineSearchFormSchema,
superQuerySchema,
} from './MesXslAutoSmallMaterialDemandPlan.data';
import { list, getExportUrl } from './MesXslAutoSmallMaterialDemandPlan.api';
@@ -40,7 +41,7 @@
columns: baseColumns,
canResize: true,
formConfig: {
schemas: searchFormSchema,
schemas: baseSearchFormSchema,
autoSubmitOnEnter: true,
showAdvancedButton: true,
},
@@ -57,20 +58,33 @@
},
});
const [registerTable, { reload, setColumns }] = tableContext;
const [registerTable, { reload, setColumns, setProps }] = tableContext;
const superQueryConfig = reactive(superQuerySchema);
onMounted(() => {
applyColumns();
applySearchSchemas();
});
function applyColumns() {
setColumns(groupByMachine.value ? machineColumns : baseColumns);
}
function applySearchSchemas() {
setProps({
formConfig: {
schemas: groupByMachine.value ? machineSearchFormSchema : baseSearchFormSchema,
},
});
}
function onGroupByMachineChange() {
queryParam.groupByMachine = groupByMachine.value ? 1 : 0;
if (!groupByMachine.value) {
delete queryParam.machineName;
}
applyColumns();
applySearchSchemas();
reload();
}

View File

@@ -4,7 +4,7 @@ import { checkEquipmentCode, checkEquipmentName } from './MesXslEquipmentLedger.
const colHalf = { span: 12 };
export const columns: BasicColumn[] = [
{ title: '系统编号', align: 'center', dataIndex: 'ledgerNo', width: 100 },
{ title: '系统编号', align: 'center', dataIndex: 'ledgerNo', width: 100, defaultHidden: true },
{ title: '设备编号', align: 'center', dataIndex: 'equipmentCode', width: 130 },
{ title: '设备名称', align: 'center', dataIndex: 'equipmentName', width: 160 },
{ title: '工序', align: 'center', dataIndex: 'processOperationName', width: 120 },
@@ -12,6 +12,8 @@ export const columns: BasicColumn[] = [
{ title: '设备类型', align: 'center', dataIndex: 'equipmentTypeName', width: 110 },
{ title: '设备厂家', align: 'center', dataIndex: 'manufacturerName', width: 120 },
{ title: '所属工厂', align: 'center', dataIndex: 'factoryName', width: 120 },
{ title: '设备描述', align: 'left', dataIndex: 'equipmentDesc', width: 200, ellipsis: true },
{ title: '受控PDA', align: 'center', dataIndex: 'controlledPda', width: 120 },
{ title: '设备状态', align: 'center', dataIndex: 'equipmentStatus_dictText', width: 90 },
{ title: '是否启用', align: 'center', dataIndex: 'enabledFlag_dictText', width: 90 },
{ title: '设备型号', align: 'center', dataIndex: 'equipmentModel', width: 110, defaultHidden: true },
@@ -85,14 +87,6 @@ export const formSchema: FormSchema[] = [
{ label: '', field: 'equipmentCategoryId', component: 'Input', show: false, dynamicRules: () => [{ required: true, message: '请选择设备类别' }] },
{ label: '', field: 'equipmentTypeId', component: 'Input', show: false, dynamicRules: () => [{ required: true, message: '请选择设备类型' }] },
{ label: '', field: 'factoryId', component: 'Input', show: false },
{
label: '所属工序',
field: 'processOperationName',
component: 'Input',
slot: 'processOperationPicker',
colProps: colHalf,
dynamicRules: () => [{ required: true, message: '请选择所属工序' }],
},
{
label: '系统编号',
field: 'ledgerNo',
@@ -100,6 +94,30 @@ export const formSchema: FormSchema[] = [
colProps: colHalf,
componentProps: { readonly: true, placeholder: '保存时从001起自动生成' },
},
{
label: '设备类型',
field: 'equipmentTypeName',
component: 'Input',
slot: 'equipmentTypePicker',
colProps: colHalf,
dynamicRules: () => [{ required: true, message: '请选择设备类型' }],
},
{
label: '所属工序',
field: 'processOperationName',
component: 'Input',
colProps: colHalf,
componentProps: { readonly: true, placeholder: '选择设备类型后自动带出' },
dynamicRules: () => [{ required: true, message: '请先选择设备类型' }],
},
{
label: '设备类别',
field: 'equipmentCategoryName',
component: 'Input',
colProps: colHalf,
componentProps: { readonly: true, placeholder: '选择设备类型后自动带出' },
dynamicRules: () => [{ required: true, message: '请先选择设备类型' }],
},
{
label: '设备编号',
field: 'equipmentCode',
@@ -153,22 +171,6 @@ export const formSchema: FormSchema[] = [
slot: 'manufacturerPicker',
colProps: colHalf,
},
{
label: '设备类别',
field: 'equipmentCategoryName',
component: 'Input',
slot: 'equipmentCategoryPicker',
colProps: colHalf,
dynamicRules: () => [{ required: true, message: '请选择设备类别' }],
},
{
label: '设备类型',
field: 'equipmentTypeName',
component: 'Input',
slot: 'equipmentTypePicker',
colProps: colHalf,
dynamicRules: () => [{ required: true, message: '请选择设备类型' }],
},
{
label: '所属工厂',
field: 'factoryName',

View File

@@ -10,13 +10,6 @@
@ok="handleSubmit"
>
<BasicForm @register="registerForm">
<template #processOperationPicker="{ model, field }">
<a-input-group compact style="display: flex; width: 100%">
<a-input v-model:value="model[field]" read-only placeholder="请选择工序" style="flex: 1" />
<a-button type="primary" :disabled="isDetail" @click="openProcessSelect">选择</a-button>
<a-button v-if="model.processOperationId && !isDetail" @click="clearProcess(model)">清除</a-button>
</a-input-group>
</template>
<template #manufacturerPicker="{ model, field }">
<a-input-group compact style="display: flex; width: 100%">
<a-input v-model:value="model[field]" read-only placeholder="请选择设备厂家" style="flex: 1" />
@@ -24,13 +17,6 @@
<a-button v-if="model.manufacturerId && !isDetail" @click="clearManufacturer(model)">清除</a-button>
</a-input-group>
</template>
<template #equipmentCategoryPicker="{ model, field }">
<a-input-group compact style="display: flex; width: 100%">
<a-input v-model:value="model[field]" read-only placeholder="请选择设备类别" style="flex: 1" />
<a-button type="primary" :disabled="isDetail" @click="openCategorySelect">选择</a-button>
<a-button v-if="model.equipmentCategoryId && !isDetail" @click="clearCategory(model)">清除</a-button>
</a-input-group>
</template>
<template #equipmentTypePicker="{ model, field }">
<a-input-group compact style="display: flex; width: 100%">
<a-input v-model:value="model[field]" read-only placeholder="请选择设备类型" style="flex: 1" />
@@ -46,13 +32,11 @@
</a-input-group>
</template>
</BasicForm>
<MesXslProcessOperationSelectModal @register="registerProcessModal" @select="onProcessSelect" />
<MesXslManufacturerSelectModal
@register="registerManufacturerModal"
:modal-title="manufacturerModalTitle"
@select="onManufacturerSelect"
/>
<MesXslEquipmentCategorySelectModal @register="registerCategoryModal" @select="onCategorySelect" />
<MesXslEquipmentTypeSelectModal @register="registerTypeModal" @select="onTypeSelect" />
</BasicModal>
</template>
@@ -61,14 +45,14 @@
import { computed, ref, unref, onMounted } from 'vue';
import { BasicModal, useModalInner, useModal } from '/@/components/Modal';
import { BasicForm, useForm } from '/@/components/Form/index';
import { useMessage } from '/@/hooks/web/useMessage';
import { formSchema } from '../MesXslEquipmentLedger.data';
import { fetchNextLedgerNo, saveOrUpdate } from '../MesXslEquipmentLedger.api';
import MesXslProcessOperationSelectModal from '/@/views/xslmes/mesXslEquipmentCategory/components/MesXslProcessOperationSelectModal.vue';
import MesXslManufacturerSelectModal from './MesXslManufacturerSelectModal.vue';
import MesXslEquipmentCategorySelectModal from '/@/views/xslmes/mesXslEquipmentType/components/MesXslEquipmentCategorySelectModal.vue';
import MesXslEquipmentTypeSelectModal from './MesXslEquipmentTypeSelectModal.vue';
const emit = defineEmits(['register', 'success']);
const { createMessage } = useMessage();
const isUpdate = ref(true);
const isDetail = ref(false);
@@ -89,9 +73,7 @@
manufacturerPickTarget.value === 'factory' ? '选择所属工厂' : '选择设备厂家',
);
const [registerProcessModal, { openModal: openProcessModal }] = useModal();
const [registerManufacturerModal, { openModal: openManufacturerModal }] = useModal();
const [registerCategoryModal, { openModal: openCategoryModal }] = useModal();
const [registerTypeModal, { openModal: openTypeModal }] = useModal();
const [registerForm, { resetFields, setFieldsValue, validate, setProps, getFieldsValue }] = useForm({
@@ -127,11 +109,6 @@
!unref(isUpdate) ? '新增设备台账' : unref(isDetail) ? '设备台账详情' : '编辑设备台账',
);
function openProcessSelect() {
const v = getFieldsValue();
openProcessModal(true, { processOperationId: v?.processOperationId });
}
function openManufacturerSelect(target: 'manufacturer' | 'factory') {
manufacturerPickTarget.value = target;
const v = getFieldsValue();
@@ -140,23 +117,11 @@
});
}
function openCategorySelect() {
const v = getFieldsValue();
openCategoryModal(true, { equipmentCategoryId: v?.equipmentCategoryId });
}
function openTypeSelect() {
const v = getFieldsValue();
openTypeModal(true, { equipmentTypeId: v?.equipmentTypeId });
}
function onProcessSelect(payload: Recordable) {
setFieldsValue({
processOperationId: payload.processOperationId,
processOperationName: payload.processOperationName,
});
}
function onManufacturerSelect(payload: Recordable) {
if (manufacturerPickTarget.value === 'factory') {
setFieldsValue({
@@ -171,27 +136,17 @@
}
}
function onCategorySelect(payload: Recordable) {
setFieldsValue({
equipmentCategoryId: payload.equipmentCategoryId,
equipmentCategoryName: payload.equipmentCategoryName,
});
}
function onTypeSelect(payload: Recordable) {
setFieldsValue({
equipmentTypeId: payload.equipmentTypeId,
equipmentTypeName: payload.equipmentTypeName,
equipmentCategoryId: payload.equipmentCategoryId || getFieldsValue()?.equipmentCategoryId,
equipmentCategoryName: payload.equipmentCategoryName || getFieldsValue()?.equipmentCategoryName,
equipmentTypeId: payload.equipmentTypeId || '',
equipmentTypeName: payload.equipmentTypeName || '',
equipmentCategoryId: payload.equipmentCategoryId || '',
equipmentCategoryName: payload.equipmentCategoryName || '',
processOperationId: payload.processOperationId || '',
processOperationName: payload.processOperationName || '',
});
}
function clearProcess(model: Recordable) {
model.processOperationId = '';
model.processOperationName = '';
}
function clearManufacturer(model: Recordable) {
model.manufacturerId = '';
model.manufacturerName = '';
@@ -202,26 +157,38 @@
model.factoryName = '';
}
function clearCategory(model: Recordable) {
model.equipmentCategoryId = '';
model.equipmentCategoryName = '';
}
function clearType(model: Recordable) {
model.equipmentTypeId = '';
model.equipmentTypeName = '';
model.equipmentCategoryId = '';
model.equipmentCategoryName = '';
model.processOperationId = '';
model.processOperationName = '';
}
async function handleSubmit() {
try {
const values = await validate();
// validate 结果可能不含隐藏字段最新值,与 getFieldsValue 合并
const values = { ...(getFieldsValue() || {}), ...(await validate()) };
if (!values.equipmentTypeId) {
createMessage.warning('请选择设备类型');
return;
}
if (!values.processOperationId) {
createMessage.warning('所选设备类型未绑定工序,请先维护设备类型');
return;
}
if (!values.equipmentCategoryId) {
createMessage.warning('所选设备类型未绑定设备类别,请先维护设备类型');
return;
}
setModalProps({ confirmLoading: true });
await saveOrUpdate(values, isUpdate.value);
closeModal();
emit('success');
} catch (e) {
// 表单校验失败时 ant-design 会标红;此处避免未捕获异常导致“点保存无反应”
console.warn('[设备台账] 保存校验未通过', e);
} finally {
setModalProps({ confirmLoading: false });
}

View File

@@ -79,6 +79,8 @@
equipmentTypeName: '',
equipmentCategoryId: '',
equipmentCategoryName: '',
processOperationId: '',
processOperationName: '',
});
closeModal();
return;
@@ -88,6 +90,8 @@
equipmentTypeName: row.typeName || '',
equipmentCategoryId: row.equipmentCategoryId || '',
equipmentCategoryName: row.equipmentCategoryName || '',
processOperationId: row.processOperationId || '',
processOperationName: row.processOperationName || '',
});
closeModal();
}

View File

@@ -42,7 +42,10 @@ export const batchDelete = (params, handleSuccess) => {
});
};
export const saveOrUpdate = (params, isUpdate) => defHttp.post({ url: isUpdate ? Api.edit : Api.save, params });
export const saveOrUpdate = (params, isUpdate) =>
//update-begin---author:jiangxh ---date:20260729 for【配合示方】保存延长超时避免远程库慢导致误报超时-----------
defHttp.post({ url: isUpdate ? Api.edit : Api.save, params, timeout: 120 * 1000 });
//update-end---author:jiangxh ---date:20260729 for【配合示方】保存延长超时避免远程库慢导致误报超时-----------
//update-begin---author:cursor ---date:20260522 for【XSLMES-20260522-A38】配合示方生成混炼示方-----------
export const buildMixingGeneratePreview = (params) =>

View File

@@ -111,7 +111,7 @@ export function applyWeightPercentToLines(lines: Recordable[]): void {
row.weightPercent = null;
return;
}
row.weightPercent = Number(((phr / totalPhr) * 100).toFixed(1));
row.weightPercent = Number(((phr / totalPhr) * 100).toFixed(3));
});
}
@@ -429,9 +429,25 @@ export function createEmptyLineRows(count = DEFAULT_LINE_ROW_COUNT): Recordable[
return Array.from({ length: count }, () => ({ id: buildUUID() }));
}
/** 明细数值保留三位小数 */
export function roundFormulaLineDecimal3(value: unknown): number | null {
if (value == null || value === '') {
return null;
}
const n = Number(value);
return Number.isFinite(n) ? Number(n.toFixed(3)) : null;
}
/** 确保每行有唯一 idJVxeTable rowKey 依赖 id否则单元格无法渲染 */
export function normalizeLineRows(rows: Recordable[]): Recordable[] {
return (rows || []).map((r) => ({ ...r, id: r?.id || buildUUID() }));
//update-begin---author:jiangxh ---date:20260729 for【配合示方】明细重量%/体积保留三位小数-----------
return (rows || []).map((r) => ({
...r,
id: r?.id || buildUUID(),
weightPercent: roundFormulaLineDecimal3(r?.weightPercent),
volume: roundFormulaLineDecimal3(r?.volume),
}));
//update-end---author:jiangxh ---date:20260729 for【配合示方】明细重量%/体积保留三位小数-----------
}
function sectionTitle(label: string, field: string): FormSchema {
@@ -931,6 +947,7 @@ export function buildLineJVxeColumns(mixingStages?: number | null, tableDisabled
type: JVxeTypes.inputNumber,
minWidth: 90,
align: 'center',
props: { precision: 3 },
},
{
title: '体积',
@@ -939,6 +956,7 @@ export function buildLineJVxeColumns(mixingStages?: number | null, tableDisabled
minWidth: 90,
align: 'center',
placeholder: '自动计算',
props: { precision: 3 },
},
{
title: '备注',

View File

@@ -92,6 +92,7 @@
}
loading.value = true;
try {
//update-begin---author:jiangxh ---date:20260730 for【混炼示方生成】打开预览即匹配胶料失败则关闭弹窗-----------
const preview = await buildMixingGeneratePreview({ formulaSpecId: formulaSpecId.value });
rubberName.value = preview?.rubberName || '';
mixingStages.value = preview?.mixingStages || 0;
@@ -106,9 +107,13 @@
if (!tableRows.value.length) {
createMessage.warning('无可生成的混炼段,请检查混合段数');
}
} catch (_e) {
// 预览阶段胶料匹配失败等错误由全局提示,关闭弹窗避免空表继续操作
closeModal();
} finally {
loading.value = false;
}
//update-end---author:jiangxh ---date:20260730 for【混炼示方生成】打开预览即匹配胶料失败则关闭弹窗-----------
});
function formatMachineNames(machines: Recordable[] = []) {

View File

@@ -441,6 +441,7 @@
createEmptyLineRows,
getActiveStageCount,
normalizeLineRows,
roundFormulaLineDecimal3,
stageTotalNumberProps,
SUMMARY_FOOTER_FIELD_KEYS,
SUMMARY_METRICS_FIELD_KEYS,
@@ -1464,7 +1465,7 @@
const material = (raw as Recordable)?.id != null ? raw : (raw as Recordable)?.result;
const sg = Number(material?.specificGravity);
if (sg > 0) {
row.volume = Number((Number(row.phr) / sg).toFixed(6));
row.volume = Number((Number(row.phr) / sg).toFixed(3));
} else {
row.volume = null;
}
@@ -1505,6 +1506,10 @@
.filter((r) => r && (r.mixerMaterialId || r.phr != null))
.map((r, index) => ({
...stripFormulaLineDisplayFields(r),
//update-begin---author:jiangxh ---date:20260729 for【配合示方】明细重量%/体积提交保留三位小数-----------
weightPercent: roundFormulaLineDecimal3(r.weightPercent),
volume: roundFormulaLineDecimal3(r.volume),
//update-end---author:jiangxh ---date:20260729 for【配合示方】明细重量%/体积提交保留三位小数-----------
sortNo: index,
}));

View File

@@ -1,13 +1,18 @@
import { BasicColumn, FormSchema } from '/@/components/Table';
export const baseColumns: BasicColumn[] = [
{ title: '日期', align: 'center', dataIndex: 'statDate', width: 140 },
{ title: '原材料名称', align: 'center', dataIndex: 'rawMaterialName', width: 260, ellipsis: true },
{ title: '需求重量(KG)', align: 'center', dataIndex: 'demandWeight', width: 180 },
];
export const machineColumns: BasicColumn[] = [{ title: '机台', align: 'center', dataIndex: 'machineName', width: 180 }, ...baseColumns];
export const machineColumns: BasicColumn[] = [
baseColumns[0],
{ title: '机台', align: 'center', dataIndex: 'machineName', width: 180 },
...baseColumns.slice(1),
];
export const searchFormSchema: FormSchema[] = [
export const baseSearchFormSchema: FormSchema[] = [
{
label: '日期',
field: 'statDate',
@@ -18,6 +23,12 @@ export const searchFormSchema: FormSchema[] = [
{ label: '原材料名称', field: 'rawMaterialName', component: 'JInput', colProps: { span: 6 } },
];
export const machineSearchFormSchema: FormSchema[] = [
baseSearchFormSchema[0],
{ label: '机台', field: 'machineName', component: 'JInput', colProps: { span: 6 } },
...baseSearchFormSchema.slice(1),
];
export const superQuerySchema = {
machineName: { title: '机台', order: 0, view: 'text' },
statDate: { title: '日期', order: 1, view: 'date' },

View File

@@ -25,7 +25,8 @@
import {
baseColumns,
machineColumns,
searchFormSchema,
baseSearchFormSchema,
machineSearchFormSchema,
superQuerySchema,
} from './MesXslManualSmallMaterialDemandPlan.data';
import { list, getExportUrl } from './MesXslManualSmallMaterialDemandPlan.api';
@@ -40,7 +41,7 @@
columns: baseColumns,
canResize: true,
formConfig: {
schemas: searchFormSchema,
schemas: baseSearchFormSchema,
autoSubmitOnEnter: true,
showAdvancedButton: true,
},
@@ -57,20 +58,33 @@
},
});
const [registerTable, { reload, setColumns }] = tableContext;
const [registerTable, { reload, setColumns, setProps }] = tableContext;
const superQueryConfig = reactive(superQuerySchema);
onMounted(() => {
applyColumns();
applySearchSchemas();
});
function applyColumns() {
setColumns(groupByMachine.value ? machineColumns : baseColumns);
}
function applySearchSchemas() {
setProps({
formConfig: {
schemas: groupByMachine.value ? machineSearchFormSchema : baseSearchFormSchema,
},
});
}
function onGroupByMachineChange() {
queryParam.groupByMachine = groupByMachine.value ? 1 : 0;
if (!groupByMachine.value) {
delete queryParam.machineName;
}
applyColumns();
applySearchSchemas();
reload();
}

View File

@@ -0,0 +1,13 @@
import { defHttp } from '/@/utils/http/axios';
enum Api {
list = '/xslmes/mesXslMillAction/list',
queryById = '/xslmes/mesXslMillAction/queryById',
exportXls = '/xslmes/mesXslMillAction/exportXls',
}
export const getExportUrl = Api.exportXls;
export const list = (params) => defHttp.get({ url: Api.list, params });
export const queryById = (params) => defHttp.get({ url: Api.queryById, params });

View File

@@ -0,0 +1,33 @@
import { BasicColumn, FormSchema } from '/@/components/Table';
export const columns: BasicColumn[] = [
{ title: 'GUID', align: 'center', dataIndex: 'guid', width: 280 },
{ title: '动作地址', align: 'center', dataIndex: 'actAddr', width: 100 },
{ title: '动作名称', align: 'center', dataIndex: 'actName', width: 140 },
{ title: '动作名称(英)', align: 'center', dataIndex: 'actNameEn', width: 140 },
{ title: '动作备注', align: 'center', dataIndex: 'actMemo', width: 120 },
{ title: '关联地址', align: 'center', dataIndex: 'actRepaddr', width: 100 },
{ title: '写入时间', align: 'center', dataIndex: 'writeTime', width: 170 },
{ title: '读写标识', align: 'center', dataIndex: 'rwFlag', width: 90 },
{ title: '更新时间', align: 'center', dataIndex: 'updateTime', width: 170 },
];
export const searchFormSchema: FormSchema[] = [
{ label: '动作名称', field: 'actName', component: 'Input', colProps: { span: 6 } },
{ label: '动作地址', field: 'actAddr', component: 'InputNumber', colProps: { span: 6 } },
{ label: 'GUID', field: 'guid', component: 'Input', colProps: { span: 6 } },
];
export const formSchema: FormSchema[] = [
{ label: '', field: 'id', component: 'Input', show: false },
{ label: 'GUID', field: 'guid', component: 'Input', componentProps: { disabled: true }, colProps: { span: 24 } },
{ label: '动作地址', field: 'actAddr', component: 'InputNumber', componentProps: { disabled: true }, colProps: { span: 12 } },
{ label: '关联地址', field: 'actRepaddr', component: 'InputNumber', componentProps: { disabled: true }, colProps: { span: 12 } },
{ label: '动作名称', field: 'actName', component: 'Input', componentProps: { disabled: true }, colProps: { span: 12 } },
{ label: '动作名称(英)', field: 'actNameEn', component: 'Input', componentProps: { disabled: true }, colProps: { span: 12 } },
{ label: '动作备注', field: 'actMemo', component: 'Input', componentProps: { disabled: true }, colProps: { span: 24 } },
{ label: '写入时间', field: 'writeTime', component: 'Input', componentProps: { disabled: true }, colProps: { span: 12 } },
{ label: '读取时间', field: 'readTime', component: 'Input', componentProps: { disabled: true }, colProps: { span: 12 } },
{ label: '读写标识', field: 'rwFlag', component: 'InputNumber', componentProps: { disabled: true }, colProps: { span: 12 } },
{ label: '更新时间', field: 'updateTime', component: 'Input', componentProps: { disabled: true }, colProps: { span: 12 } },
];

View File

@@ -0,0 +1,81 @@
<template>
<div class="mes-xsl-mill-action-page">
<BasicTable @register="registerTable">
<template #tableTitle>
<a-button type="primary" v-auth="'xslmes:mcsSyncConfig:setting'" preIcon="ant-design:sync-outlined" @click="openCollect"> 采集操作 </a-button>
<a-button type="link" v-auth="'xslmes:mes_xsl_mill_action:exportXls'" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button>
</template>
<template #action="{ record }">
<TableAction :actions="getTableAction(record)" />
</template>
</BasicTable>
<MesXslMillActionModal @register="registerModal" />
<CollectModal @register="registerCollectModal" @success="reload" />
</div>
</template>
<script lang="ts" name="xslmes-mesXslMillAction" setup>
import { BasicTable, TableAction } from '/@/components/Table';
import { useModal } from '/@/components/Modal';
import { useListPage } from '/@/hooks/system/useListPage';
import MesXslMillActionModal from './components/MesXslMillActionModal.vue';
import CollectModal from '/@/views/xslmesMcs/mcsSyncConfig/components/CollectModal.vue';
import { columns, searchFormSchema } from './MesXslMillAction.data';
import { list, getExportUrl } from './MesXslMillAction.api';
const [registerModal, { openModal }] = useModal();
const [registerCollectModal, { openModal: openCollectModal }] = useModal();
const { tableContext, onExportXls } = useListPage({
tableProps: {
title: '开炼机动作接收',
api: list,
columns,
canResize: true,
formConfig: { labelWidth: 100, schemas: searchFormSchema, autoSubmitOnEnter: true },
actionColumn: { width: 80, fixed: 'right' },
},
exportConfig: { name: '开炼机动作接收', url: getExportUrl },
});
const [registerTable, { reload }] = tableContext;
function openCollect() {
openCollectModal(true, { bizType: 'MILL_ACT' });
}
function handleDetail(record: Recordable) {
openModal(true, { record, isUpdate: true, showFooter: false });
}
function getTableAction(record) {
return [{ label: '详情', onClick: handleDetail.bind(null, record) }];
}
</script>
<style lang="less" scoped>
/* 空数据时 BasicTable canResize 不计算高度,用视口高度把表格区域铺满 */
.mes-xsl-mill-action-page {
min-height: calc(100vh - 120px);
:deep(.jeecg-basic-table-form-container) {
min-height: inherit;
}
:deep(.ant-table-wrapper),
:deep(.ant-spin-nested-loading),
:deep(.ant-spin-container),
:deep(.ant-table),
:deep(.ant-table-container) {
min-height: calc(100vh - 280px);
}
:deep(.ant-table-body) {
min-height: calc(100vh - 360px) !important;
}
:deep(.ant-table-tbody > tr.ant-table-placeholder > td) {
height: calc(100vh - 360px);
}
}
</style>

View File

@@ -0,0 +1,30 @@
<template>
<BasicModal v-bind="$attrs" @register="registerModal" destroyOnClose title="开炼机动作接收" :width="900">
<BasicForm @register="registerForm" />
</BasicModal>
</template>
<script lang="ts" setup>
import { BasicModal, useModalInner } from '/@/components/Modal';
import { BasicForm, useForm } from '/@/components/Form/index';
import { formSchema } from '../MesXslMillAction.data';
defineEmits(['register']);
const [registerForm, { resetFields, setFieldsValue, setProps }] = useForm({
labelWidth: 120,
schemas: formSchema,
showActionButtonGroup: false,
baseColProps: { span: 12 },
disabled: true,
});
const [registerModal, { setModalProps }] = useModalInner(async (data) => {
await resetFields();
setModalProps({ confirmLoading: false, showOkBtn: false, showCancelBtn: true, cancelText: '关闭' });
if (data?.record) {
await setFieldsValue({ ...data.record });
}
setProps({ disabled: true });
});
</script>

View File

@@ -14,10 +14,10 @@ enum Api {
export const list = (params) => defHttp.get({ url: Api.list, params });
export const checkConditionName = (params: { conditionName: string; dataId?: string }) =>
export const checkConditionName = (params: { conditionName: string; equipmentId?: string; dataId?: string }) =>
defHttp.get({ url: Api.checkConditionName, params }, { successMessageMode: 'none', errorMessageMode: 'none' });
export const checkConditionCode = (params: { conditionCode: string; dataId?: string }) =>
export const checkConditionCode = (params: { conditionCode: string; equipmentId?: string; dataId?: string }) =>
defHttp.get({ url: Api.checkConditionCode, params }, { successMessageMode: 'none', errorMessageMode: 'none' });
export const deleteOne = (params, handleSuccess) =>

View File

@@ -42,11 +42,13 @@ export const formSchema: FormSchema[] = [
validator: async (_rule, value) => {
const v = value == null ? '' : String(value).trim();
if (!v) return Promise.resolve();
// 未选设备时不做跨设备校验,保存时仍会强制校验
if (!model?.equipmentId) return Promise.resolve();
try {
await checkConditionName({ conditionName: v, dataId: model?.id });
await checkConditionName({ conditionName: v, equipmentId: model.equipmentId, dataId: model?.id });
return Promise.resolve();
} catch (e: any) {
return Promise.reject(e?.response?.data?.message || e?.message || '条件名称不能重复');
return Promise.reject(e?.response?.data?.message || e?.message || '同一设备下条件名称不能重复');
}
},
trigger: 'blur',
@@ -64,11 +66,12 @@ export const formSchema: FormSchema[] = [
validator: async (_rule, value) => {
const v = value == null ? '' : String(value).trim();
if (!v) return Promise.resolve();
if (!model?.equipmentId) return Promise.resolve();
try {
await checkConditionCode({ conditionCode: v, dataId: model?.id });
await checkConditionCode({ conditionCode: v, equipmentId: model.equipmentId, dataId: model?.id });
return Promise.resolve();
} catch (e: any) {
return Promise.reject(e?.response?.data?.message || e?.message || '条件代码不能重复');
return Promise.reject(e?.response?.data?.message || e?.message || '同一设备下条件代码不能重复');
}
},
trigger: 'blur',

View File

@@ -79,11 +79,11 @@ export const mainSchema: FormSchema[] = [
rules: [{ required: true, message: '请选择发行编号' }],
},
//update-end---author:cursor ---date:20260522 for【XSLMES-20260522-A33】混炼示方基本信息字段优化-----------
{ label: '换算系数', field: 'convertFactor', component: 'InputNumber', colProps: { span: 8 }, componentProps: { precision: 2, style: { width: '100%' } } },
{ label: '填充体积', field: 'fillVolume', component: 'InputNumber', colProps: { span: 8 }, componentProps: { precision: 6, style: { width: '100%' } } },
{ label: '换算系数', field: 'convertFactor', component: 'InputNumber', colProps: { span: 8 }, componentProps: { precision: 3, style: { width: '100%' } } },
{ label: '填充体积', field: 'fillVolume', component: 'InputNumber', colProps: { span: 8 }, componentProps: { precision: 2, style: { width: '100%' } } },
{ label: '回收炭黑(秒)', field: 'recycleCarbonSec', component: 'InputNumber', colProps: { span: 8 }, componentProps: { precision: 0, style: { width: '100%' } } },
{ label: '母胶比重', field: 'motherRubberSg', component: 'InputNumber', colProps: { span: 8 }, componentProps: { precision: 6, style: { width: '100%' } } },
{ label: '终炼胶比重', field: 'finalRubberSg', component: 'InputNumber', colProps: { span: 8 }, componentProps: { precision: 6, style: { width: '100%' } } },
{ label: '母胶比重', field: 'motherRubberSg', component: 'InputNumber', colProps: { span: 8 }, componentProps: { precision: 3, style: { width: '100%' } } },
{ label: '终炼胶比重', field: 'finalRubberSg', component: 'InputNumber', colProps: { span: 8 }, componentProps: { precision: 3, style: { width: '100%' } } },
{ label: '适用工厂', field: 'applyFactory', component: 'Input', colProps: { span: 8 } },
{ label: '段数', field: 'stageCount', component: 'Input', colProps: { span: 8 }, componentProps: { placeholder: '如 2/3' } },
{ label: '纯混炼时间(秒)', field: 'pureMixSec', component: 'InputNumber', colProps: { span: 8 }, componentProps: { precision: 0, style: { width: '100%' } } },
@@ -319,7 +319,13 @@ const MIXING_MATERIAL_WEIGHT_SCALE = 6;
//update-begin---author:cursor ---date:20260526 for【XSLMES-20260526-A60】换算系数/配方参数数值展示优化-----------
/** 换算系数展示小数位 */
export const MIXING_CONVERT_FACTOR_SCALE = 2;
export const MIXING_CONVERT_FACTOR_SCALE = 3;
/** 母胶比重展示小数位 */
export const MIXING_MOTHER_RUBBER_SG_SCALE = 3;
/** 填充体积展示小数位 */
export const MIXING_FILL_VOLUME_SCALE = 2;
/** 配方参数设定允许的小数精度 */
export const MIXING_RECIPE_PARAM_DECIMAL_SCALE = 6;
@@ -333,7 +339,7 @@ export const MIXING_RECIPE_PARAM_DECIMAL_FIELDS = [
'maxFeedTemp',
] as const;
/** 换算系数展示:固定保留位小数 */
/** 换算系数展示:固定保留位小数 */
export function formatMixingConvertFactorDisplay(value: unknown): string {
if (value === null || value === undefined || value === '') {
return '';
@@ -536,7 +542,7 @@ export function calcMixingFillVolume(totalWeight: unknown, specificGravity: unkn
return null;
}
const materialVolume = weight / sg;
return Number(((materialVolume / volume) * 100).toFixed(6));
return Number(((materialVolume / volume) * 100).toFixed(MIXING_FILL_VOLUME_SCALE));
}
//update-end---author:cursor ---date:20260525 for【XSLMES-20260525-A46】填充体积按单重/比重/机台有效体积自动计算-----------
@@ -1311,8 +1317,9 @@ export function applyMixingMaterialFromSelection(row: Recordable, material: Reco
//update-begin---author:cursor ---date:20260601 for【XSLMES-20260601-A62】选料弹窗新增胶料页签查询胶料信息-----------
/** 选料弹窗「胶料」页签表格列(数据源为胶料信息 mes_material */
export const mixingRubberPickerTableColumns: BasicColumn[] = [
{ title: '胶料编码', align: 'center', width: 140, dataIndex: 'materialCode' },
//update-begin---author:jiangxh ---date:20260729 for【选料弹窗】胶料页签去掉胶料编码-----------
{ title: '胶料名称', align: 'center', width: 180, dataIndex: 'materialName' },
//update-end---author:jiangxh ---date:20260729 for【选料弹窗】胶料页签去掉胶料编码-----------
//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】胶料页签补齐自动/人工称量列-----------

View File

@@ -13,7 +13,7 @@
<a-input
v-model:value="keyword"
allow-clear
placeholder="关键字(编码/名称/描述)"
:placeholder="keywordPlaceholder"
style="width: 280px"
@pressEnter="reloadTable"
/>
@@ -105,6 +105,11 @@
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 {
buildOrLikeSuperQuery,
MIXER_MATERIAL_LIKE_FIELDS,
RUBBER_MATERIAL_LIKE_FIELDS,
} from '/@/views/mes/material/materialQuery.util';
import { useMessage } from '/@/hooks/web/useMessage';
import JDictSelectTag from '/@/components/Form/src/jeecg/components/JDictSelectTag.vue';
import MesXslMixingMaterialCategorySetting from './MesXslMixingMaterialCategorySetting.vue';
@@ -133,6 +138,11 @@
const RUBBER_TREE_ALL = 'ALL';
const RUBBER_CATEGORY_PCODE = 'XSLMES_RUBBER';
const pickerType = ref<'mixer' | 'rubber'>('mixer');
//update-begin---author:jiangxh ---date:20260729 for【选料弹窗】胶料页签关键字提示去掉编码-----------
const keywordPlaceholder = computed(() =>
pickerType.value === 'rubber' ? '关键字(名称/别名/ERP' : '关键字(编码/名称/描述)',
);
//update-end---author:jiangxh ---date:20260729 for【选料弹窗】胶料页签关键字提示去掉编码-----------
const rubberTreeLoading = ref(false);
const rubberCategoryTree = ref<Recordable[]>([]);
/** 胶料类别 id -> { code, title },用于按种类配置编码匹配 */
@@ -256,14 +266,20 @@
const kw = keyword.value?.trim();
if (pickerType.value === 'rubber') {
const rubberParams = { ...params, ...selectedRubberCategoryFilter.value };
if (kw) {
rubberParams.materialName = `*${kw}*`;
//update-begin---author:jiangxh ---date:20260729 for【选料弹窗】胶料关键字按名称/ERP/别名模糊查询-----------
// 关键字按名称/ERP/别名模糊 OR 查询(不含编码)
const orQuery = buildOrLikeSuperQuery(RUBBER_MATERIAL_LIKE_FIELDS, kw || '');
//update-end---author:jiangxh ---date:20260729 for【选料弹窗】胶料关键字按名称/ERP/别名模糊查询-----------
if (orQuery) {
Object.assign(rubberParams, orQuery);
}
return rubberParams;
}
const next = { ...params, ...selectedCategoryFilter.value };
if (kw) {
next.materialName = `*${kw}*`;
// 关键字按编码/名称/描述/ERP/别名模糊 OR 查询
const orQuery = buildOrLikeSuperQuery(MIXER_MATERIAL_LIKE_FIELDS, kw || '');
if (orQuery) {
Object.assign(next, orQuery);
}
return next;
},

View File

@@ -67,7 +67,7 @@
<a-input-number
v-model:value="sheetForm.convertFactor"
:disabled="!showFooter"
:precision="2"
:precision="3"
:formatter="formatConvertFactorInput"
:parser="parseConvertFactorInput"
:bordered="false"
@@ -78,7 +78,7 @@
</td>
<th class="formTitle" colspan="1">填充体积</th>
<td class="formValue" colspan="1">
<a-input-number v-model:value="sheetForm.fillVolume" :disabled="!showFooter" :precision="6" :bordered="false" class="form-input" style="width: 100%" />
<a-input-number v-model:value="sheetForm.fillVolume" :disabled="!showFooter" :precision="2" :bordered="false" class="form-input" style="width: 100%" />
</td>
<th class="formTitle" colspan="1">回收炭黑()</th>
<td class="formValue">
@@ -99,7 +99,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%" @update:value="recalcFillVolume" />
<a-input-number v-model:value="sheetForm.motherRubberSg" :disabled="!showFooter" :precision="3" :bordered="false" class="form-input" style="width: 100%" @update:value="recalcFillVolume" />
</td>
<th class="formTitle">段数</th>
<td class="formValue" colspan="2">
@@ -123,7 +123,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%" @update:value="recalcFillVolume" />
<a-input-number v-model:value="sheetForm.finalRubberSg" :disabled="!showFooter" :precision="3" :bordered="false" class="form-input" style="width: 100%" @update:value="recalcFillVolume" />
</td>
<th class="formTitle" colspan="1">适用工厂</th>
<td class="formValue" colspan="2">

View File

@@ -10,16 +10,23 @@ export const baseColumns: BasicColumn[] = [
];
export const machineColumns: BasicColumn[] = [
baseColumns[0],
{ title: '机台', align: 'center', dataIndex: 'machineName', width: 160 },
...baseColumns,
...baseColumns.slice(1),
];
export const searchFormSchema: FormSchema[] = [
export const baseSearchFormSchema: FormSchema[] = [
{ label: '计划日期', field: 'planDate', component: 'DatePicker', colProps: { span: 6 } },
{ label: 'ERP编号', field: 'erpCode', component: 'JInput', colProps: { span: 6 } },
{ label: '原材料名称', field: 'rawMaterialName', component: 'JInput', colProps: { span: 6 } },
];
export const machineSearchFormSchema: FormSchema[] = [
baseSearchFormSchema[0],
{ label: '机台', field: 'machineName', component: 'JInput', colProps: { span: 6 } },
...baseSearchFormSchema.slice(1),
];
export const superQuerySchema = {
planDate: { title: '计划日期', order: 0, view: 'date' },
machineName: { title: '机台', order: 1, view: 'text' },

View File

@@ -25,7 +25,8 @@
import {
baseColumns,
machineColumns,
searchFormSchema,
baseSearchFormSchema,
machineSearchFormSchema,
superQuerySchema,
} from './MesXslRawMaterialDemandPlan.data';
import { list, getExportUrl } from './MesXslRawMaterialDemandPlan.api';
@@ -40,7 +41,7 @@
columns: baseColumns,
canResize: true,
formConfig: {
schemas: searchFormSchema,
schemas: baseSearchFormSchema,
autoSubmitOnEnter: true,
showAdvancedButton: true,
},
@@ -57,20 +58,33 @@
},
});
const [registerTable, { reload, setColumns }] = tableContext;
const [registerTable, { reload, setColumns, setProps }] = tableContext;
const superQueryConfig = reactive(superQuerySchema);
onMounted(() => {
applyColumns();
applySearchSchemas();
});
function applyColumns() {
setColumns(groupByMachine.value ? machineColumns : baseColumns);
}
function applySearchSchemas() {
setProps({
formConfig: {
schemas: groupByMachine.value ? machineSearchFormSchema : baseSearchFormSchema,
},
});
}
function onGroupByMachineChange() {
queryParam.groupByMachine = groupByMachine.value ? 1 : 0;
if (!groupByMachine.value) {
delete queryParam.machineName;
}
applyColumns();
applySearchSchemas();
reload();
}