更新物料大类和小类的字典表引用,优化前端表单组件,改用API选择器加载分类数据,增强用户体验。调整物料信息模态框,支持动态加载大类和小类选项。
This commit is contained in:
@@ -33,12 +33,12 @@ public class MesMixerMaterial implements Serializable {
|
||||
@Excel(name = "ERP编号", width = 15)
|
||||
private String erpCode;
|
||||
|
||||
@Excel(name = "物料大类", width = 15, dictTable = "mes_material_category", dicText = "category_name", dicCode = "id")
|
||||
@Dict(dictTable = "mes_material_category", dicText = "category_name", dicCode = "id")
|
||||
@Excel(name = "物料大类", width = 15, dictTable = "sys_category", dicText = "name", dicCode = "id")
|
||||
@Dict(dictTable = "sys_category", dicText = "name", dicCode = "id")
|
||||
private String majorCategoryId;
|
||||
|
||||
@Excel(name = "物料小类", width = 15, dictTable = "mes_material_category", dicText = "category_name", dicCode = "id")
|
||||
@Dict(dictTable = "mes_material_category", dicText = "category_name", dicCode = "id")
|
||||
@Excel(name = "物料小类", width = 15, dictTable = "sys_category", dicText = "name", dicCode = "id")
|
||||
@Dict(dictTable = "sys_category", dicText = "name", dicCode = "id")
|
||||
private String minorCategoryId;
|
||||
|
||||
@Excel(name = "物料描述", width = 25)
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
-- MES 物料分类:新增分类字典(sys_category)根节点与子节点
|
||||
-- 根编码:XSLMES_MATERIAL
|
||||
-- 子类:物料大类、物料小类
|
||||
|
||||
-- 根节点:物料分类
|
||||
INSERT INTO `sys_category` (`id`, `pid`, `name`, `code`, `has_child`, `create_by`, `create_time`)
|
||||
SELECT '1993000000000000001', '0', '物料分类', 'XSLMES_MATERIAL', '1', 'admin', NOW()
|
||||
FROM DUAL
|
||||
WHERE NOT EXISTS (SELECT 1 FROM `sys_category` WHERE `code` = 'XSLMES_MATERIAL');
|
||||
|
||||
-- 子节点:物料大类
|
||||
INSERT INTO `sys_category` (`id`, `pid`, `name`, `code`, `has_child`, `create_by`, `create_time`)
|
||||
SELECT '1993000000000000002', p.`id`, '物料大类', 'XSLMES_MATERIAL_MAJOR', '0', 'admin', NOW()
|
||||
FROM `sys_category` p
|
||||
WHERE p.`code` = 'XSLMES_MATERIAL'
|
||||
AND NOT EXISTS (SELECT 1 FROM `sys_category` WHERE `code` = 'XSLMES_MATERIAL_MAJOR');
|
||||
|
||||
-- 子节点:物料小类
|
||||
INSERT INTO `sys_category` (`id`, `pid`, `name`, `code`, `has_child`, `create_by`, `create_time`)
|
||||
SELECT '1993000000000000003', p.`id`, '物料小类', 'XSLMES_MATERIAL_MINOR', '0', 'admin', NOW()
|
||||
FROM `sys_category` p
|
||||
WHERE p.`code` = 'XSLMES_MATERIAL'
|
||||
AND NOT EXISTS (SELECT 1 FROM `sys_category` WHERE `code` = 'XSLMES_MATERIAL_MINOR');
|
||||
|
||||
-- 确保根节点有子节点标记
|
||||
UPDATE `sys_category`
|
||||
SET `has_child` = '1'
|
||||
WHERE `code` = 'XSLMES_MATERIAL';
|
||||
@@ -0,0 +1,169 @@
|
||||
-- MES 物料分类树:根节点 -> 物料大类 -> 物料小类
|
||||
-- 兼容处理:清理上一版占位节点(物料大类/物料小类),避免出现在下拉中
|
||||
|
||||
-- 清理占位节点(若存在)
|
||||
DELETE FROM `sys_category` WHERE `code` IN ('XSLMES_MATERIAL_MAJOR', 'XSLMES_MATERIAL_MINOR');
|
||||
|
||||
-- 确保根节点存在
|
||||
INSERT INTO `sys_category` (`id`, `pid`, `name`, `code`, `has_child`, `create_by`, `create_time`)
|
||||
SELECT '1993000000000000001', '0', '物料分类', 'XSLMES_MATERIAL', '1', 'admin', NOW()
|
||||
FROM DUAL
|
||||
WHERE NOT EXISTS (SELECT 1 FROM `sys_category` WHERE `code` = 'XSLMES_MATERIAL');
|
||||
|
||||
-- 物料大类
|
||||
INSERT INTO `sys_category` (`id`, `pid`, `name`, `code`, `has_child`, `create_by`, `create_time`)
|
||||
SELECT '1993000000000000101', root.`id`, '原辅材料', 'XSLMES_MATERIAL_RAW_AUX', '1', 'admin', NOW()
|
||||
FROM `sys_category` root
|
||||
WHERE root.`code` = 'XSLMES_MATERIAL'
|
||||
AND NOT EXISTS (SELECT 1 FROM `sys_category` WHERE `code` = 'XSLMES_MATERIAL_RAW_AUX');
|
||||
|
||||
INSERT INTO `sys_category` (`id`, `pid`, `name`, `code`, `has_child`, `create_by`, `create_time`)
|
||||
SELECT '1993000000000000102', root.`id`, '小料', 'XSLMES_MATERIAL_SMALL', '1', 'admin', NOW()
|
||||
FROM `sys_category` root
|
||||
WHERE root.`code` = 'XSLMES_MATERIAL'
|
||||
AND NOT EXISTS (SELECT 1 FROM `sys_category` WHERE `code` = 'XSLMES_MATERIAL_SMALL');
|
||||
|
||||
INSERT INTO `sys_category` (`id`, `pid`, `name`, `code`, `has_child`, `create_by`, `create_time`)
|
||||
SELECT '1993000000000000103', root.`id`, '塑炼胶', 'XSLMES_MATERIAL_PLASTIC', '1', 'admin', NOW()
|
||||
FROM `sys_category` root
|
||||
WHERE root.`code` = 'XSLMES_MATERIAL'
|
||||
AND NOT EXISTS (SELECT 1 FROM `sys_category` WHERE `code` = 'XSLMES_MATERIAL_PLASTIC');
|
||||
|
||||
INSERT INTO `sys_category` (`id`, `pid`, `name`, `code`, `has_child`, `create_by`, `create_time`)
|
||||
SELECT '1993000000000000104', root.`id`, '母炼胶', 'XSLMES_MATERIAL_MASTER', '1', 'admin', NOW()
|
||||
FROM `sys_category` root
|
||||
WHERE root.`code` = 'XSLMES_MATERIAL'
|
||||
AND NOT EXISTS (SELECT 1 FROM `sys_category` WHERE `code` = 'XSLMES_MATERIAL_MASTER');
|
||||
|
||||
INSERT INTO `sys_category` (`id`, `pid`, `name`, `code`, `has_child`, `create_by`, `create_time`)
|
||||
SELECT '1993000000000000105', root.`id`, '终炼胶', 'XSLMES_MATERIAL_FINAL', '1', 'admin', NOW()
|
||||
FROM `sys_category` root
|
||||
WHERE root.`code` = 'XSLMES_MATERIAL'
|
||||
AND NOT EXISTS (SELECT 1 FROM `sys_category` WHERE `code` = 'XSLMES_MATERIAL_FINAL');
|
||||
|
||||
-- 原辅材料 -> 小类
|
||||
INSERT INTO `sys_category` (`id`, `pid`, `name`, `code`, `has_child`, `create_by`, `create_time`)
|
||||
SELECT '1993000000000000201', p.`id`, '炭黑', 'XSLMES_MATERIAL_RAW_AUX_TH', '0', 'admin', NOW()
|
||||
FROM `sys_category` p
|
||||
WHERE p.`code` = 'XSLMES_MATERIAL_RAW_AUX'
|
||||
AND NOT EXISTS (SELECT 1 FROM `sys_category` WHERE `code` = 'XSLMES_MATERIAL_RAW_AUX_TH');
|
||||
|
||||
INSERT INTO `sys_category` (`id`, `pid`, `name`, `code`, `has_child`, `create_by`, `create_time`)
|
||||
SELECT '1993000000000000202', p.`id`, '油料', 'XSLMES_MATERIAL_RAW_AUX_YL', '0', 'admin', NOW()
|
||||
FROM `sys_category` p
|
||||
WHERE p.`code` = 'XSLMES_MATERIAL_RAW_AUX'
|
||||
AND NOT EXISTS (SELECT 1 FROM `sys_category` WHERE `code` = 'XSLMES_MATERIAL_RAW_AUX_YL');
|
||||
|
||||
INSERT INTO `sys_category` (`id`, `pid`, `name`, `code`, `has_child`, `create_by`, `create_time`)
|
||||
SELECT '1993000000000000203', p.`id`, '粉料', 'XSLMES_MATERIAL_RAW_AUX_FL', '0', 'admin', NOW()
|
||||
FROM `sys_category` p
|
||||
WHERE p.`code` = 'XSLMES_MATERIAL_RAW_AUX'
|
||||
AND NOT EXISTS (SELECT 1 FROM `sys_category` WHERE `code` = 'XSLMES_MATERIAL_RAW_AUX_FL');
|
||||
|
||||
INSERT INTO `sys_category` (`id`, `pid`, `name`, `code`, `has_child`, `create_by`, `create_time`)
|
||||
SELECT '1993000000000000204', p.`id`, '钢丝', 'XSLMES_MATERIAL_RAW_AUX_GS', '0', 'admin', NOW()
|
||||
FROM `sys_category` p
|
||||
WHERE p.`code` = 'XSLMES_MATERIAL_RAW_AUX'
|
||||
AND NOT EXISTS (SELECT 1 FROM `sys_category` WHERE `code` = 'XSLMES_MATERIAL_RAW_AUX_GS');
|
||||
|
||||
INSERT INTO `sys_category` (`id`, `pid`, `name`, `code`, `has_child`, `create_by`, `create_time`)
|
||||
SELECT '1993000000000000205', p.`id`, '帘线', 'XSLMES_MATERIAL_RAW_AUX_LX', '0', 'admin', NOW()
|
||||
FROM `sys_category` p
|
||||
WHERE p.`code` = 'XSLMES_MATERIAL_RAW_AUX'
|
||||
AND NOT EXISTS (SELECT 1 FROM `sys_category` WHERE `code` = 'XSLMES_MATERIAL_RAW_AUX_LX');
|
||||
|
||||
INSERT INTO `sys_category` (`id`, `pid`, `name`, `code`, `has_child`, `create_by`, `create_time`)
|
||||
SELECT '1993000000000000206', p.`id`, '天然胶', 'XSLMES_MATERIAL_RAW_AUX_TRJ', '0', 'admin', NOW()
|
||||
FROM `sys_category` p
|
||||
WHERE p.`code` = 'XSLMES_MATERIAL_RAW_AUX'
|
||||
AND NOT EXISTS (SELECT 1 FROM `sys_category` WHERE `code` = 'XSLMES_MATERIAL_RAW_AUX_TRJ');
|
||||
|
||||
INSERT INTO `sys_category` (`id`, `pid`, `name`, `code`, `has_child`, `create_by`, `create_time`)
|
||||
SELECT '1993000000000000207', p.`id`, '合成胶', 'XSLMES_MATERIAL_RAW_AUX_HCJ', '0', 'admin', NOW()
|
||||
FROM `sys_category` p
|
||||
WHERE p.`code` = 'XSLMES_MATERIAL_RAW_AUX'
|
||||
AND NOT EXISTS (SELECT 1 FROM `sys_category` WHERE `code` = 'XSLMES_MATERIAL_RAW_AUX_HCJ');
|
||||
|
||||
INSERT INTO `sys_category` (`id`, `pid`, `name`, `code`, `has_child`, `create_by`, `create_time`)
|
||||
SELECT '1993000000000000208', p.`id`, '再生胶', 'XSLMES_MATERIAL_RAW_AUX_ZSJ', '0', 'admin', NOW()
|
||||
FROM `sys_category` p
|
||||
WHERE p.`code` = 'XSLMES_MATERIAL_RAW_AUX'
|
||||
AND NOT EXISTS (SELECT 1 FROM `sys_category` WHERE `code` = 'XSLMES_MATERIAL_RAW_AUX_ZSJ');
|
||||
|
||||
INSERT INTO `sys_category` (`id`, `pid`, `name`, `code`, `has_child`, `create_by`, `create_time`)
|
||||
SELECT '1993000000000000209', p.`id`, '硅烷', 'XSLMES_MATERIAL_RAW_AUX_GW', '0', 'admin', NOW()
|
||||
FROM `sys_category` p
|
||||
WHERE p.`code` = 'XSLMES_MATERIAL_RAW_AUX'
|
||||
AND NOT EXISTS (SELECT 1 FROM `sys_category` WHERE `code` = 'XSLMES_MATERIAL_RAW_AUX_GW');
|
||||
|
||||
INSERT INTO `sys_category` (`id`, `pid`, `name`, `code`, `has_child`, `create_by`, `create_time`)
|
||||
SELECT '1993000000000000210', p.`id`, '大粉料', 'XSLMES_MATERIAL_RAW_AUX_DFL', '0', 'admin', NOW()
|
||||
FROM `sys_category` p
|
||||
WHERE p.`code` = 'XSLMES_MATERIAL_RAW_AUX'
|
||||
AND NOT EXISTS (SELECT 1 FROM `sys_category` WHERE `code` = 'XSLMES_MATERIAL_RAW_AUX_DFL');
|
||||
|
||||
INSERT INTO `sys_category` (`id`, `pid`, `name`, `code`, `has_child`, `create_by`, `create_time`)
|
||||
SELECT '1993000000000000211', p.`id`, '白炭黑', 'XSLMES_MATERIAL_RAW_AUX_BTH', '0', 'admin', NOW()
|
||||
FROM `sys_category` p
|
||||
WHERE p.`code` = 'XSLMES_MATERIAL_RAW_AUX'
|
||||
AND NOT EXISTS (SELECT 1 FROM `sys_category` WHERE `code` = 'XSLMES_MATERIAL_RAW_AUX_BTH');
|
||||
|
||||
-- 小料 -> 小类
|
||||
INSERT INTO `sys_category` (`id`, `pid`, `name`, `code`, `has_child`, `create_by`, `create_time`)
|
||||
SELECT '1993000000000000301', p.`id`, '人工', 'XSLMES_MATERIAL_SMALL_RG', '0', 'admin', NOW()
|
||||
FROM `sys_category` p
|
||||
WHERE p.`code` = 'XSLMES_MATERIAL_SMALL'
|
||||
AND NOT EXISTS (SELECT 1 FROM `sys_category` WHERE `code` = 'XSLMES_MATERIAL_SMALL_RG');
|
||||
|
||||
INSERT INTO `sys_category` (`id`, `pid`, `name`, `code`, `has_child`, `create_by`, `create_time`)
|
||||
SELECT '1993000000000000302', p.`id`, '自动', 'XSLMES_MATERIAL_SMALL_ZD', '0', 'admin', NOW()
|
||||
FROM `sys_category` p
|
||||
WHERE p.`code` = 'XSLMES_MATERIAL_SMALL'
|
||||
AND NOT EXISTS (SELECT 1 FROM `sys_category` WHERE `code` = 'XSLMES_MATERIAL_SMALL_ZD');
|
||||
|
||||
-- 塑炼胶 -> 小类
|
||||
INSERT INTO `sys_category` (`id`, `pid`, `name`, `code`, `has_child`, `create_by`, `create_time`)
|
||||
SELECT '1993000000000000401', p.`id`, 'J0段胶', 'XSLMES_MATERIAL_PLASTIC_J0', '0', 'admin', NOW()
|
||||
FROM `sys_category` p
|
||||
WHERE p.`code` = 'XSLMES_MATERIAL_PLASTIC'
|
||||
AND NOT EXISTS (SELECT 1 FROM `sys_category` WHERE `code` = 'XSLMES_MATERIAL_PLASTIC_J0');
|
||||
|
||||
-- 母炼胶 -> 小类
|
||||
INSERT INTO `sys_category` (`id`, `pid`, `name`, `code`, `has_child`, `create_by`, `create_time`)
|
||||
SELECT '1993000000000000501', p.`id`, 'A胶', 'XSLMES_MATERIAL_MASTER_A', '0', 'admin', NOW()
|
||||
FROM `sys_category` p
|
||||
WHERE p.`code` = 'XSLMES_MATERIAL_MASTER'
|
||||
AND NOT EXISTS (SELECT 1 FROM `sys_category` WHERE `code` = 'XSLMES_MATERIAL_MASTER_A');
|
||||
|
||||
-- 终炼胶 -> 小类
|
||||
INSERT INTO `sys_category` (`id`, `pid`, `name`, `code`, `has_child`, `create_by`, `create_time`)
|
||||
SELECT '1993000000000000601', p.`id`, 'Q胶', 'XSLMES_MATERIAL_FINAL_Q', '0', 'admin', NOW()
|
||||
FROM `sys_category` p
|
||||
WHERE p.`code` = 'XSLMES_MATERIAL_FINAL'
|
||||
AND NOT EXISTS (SELECT 1 FROM `sys_category` WHERE `code` = 'XSLMES_MATERIAL_FINAL_Q');
|
||||
|
||||
INSERT INTO `sys_category` (`id`, `pid`, `name`, `code`, `has_child`, `create_by`, `create_time`)
|
||||
SELECT '1993000000000000602', p.`id`, '返回胶', 'XSLMES_MATERIAL_FINAL_FHJ', '0', 'admin', NOW()
|
||||
FROM `sys_category` p
|
||||
WHERE p.`code` = 'XSLMES_MATERIAL_FINAL'
|
||||
AND NOT EXISTS (SELECT 1 FROM `sys_category` WHERE `code` = 'XSLMES_MATERIAL_FINAL_FHJ');
|
||||
|
||||
-- 统一修正 has_child 标记(仅针对物料分类树,避免 MySQL 1093)
|
||||
-- 先将物料分类树节点全部置 0
|
||||
UPDATE `sys_category`
|
||||
SET `has_child` = '0'
|
||||
WHERE `code` = 'XSLMES_MATERIAL'
|
||||
OR `code` LIKE 'XSLMES_MATERIAL_%';
|
||||
|
||||
-- 再把有子节点的节点置 1(通过派生表规避同表更新限制)
|
||||
UPDATE `sys_category` p
|
||||
JOIN (
|
||||
SELECT DISTINCT c.`pid` AS parent_id
|
||||
FROM `sys_category` c
|
||||
WHERE c.`code` LIKE 'XSLMES_MATERIAL_%'
|
||||
AND c.`pid` IS NOT NULL
|
||||
AND c.`pid` <> '0'
|
||||
) t ON t.parent_id = p.`id`
|
||||
SET p.`has_child` = '1'
|
||||
WHERE p.`code` = 'XSLMES_MATERIAL'
|
||||
OR p.`code` LIKE 'XSLMES_MATERIAL_%';
|
||||
@@ -1,4 +1,5 @@
|
||||
import { BasicColumn, FormSchema } from '/@/components/Table';
|
||||
import { loadTreeData } from '/@/api/common/api';
|
||||
|
||||
function feedManageStatusText(v: unknown) {
|
||||
if (v === 1) return '在投管';
|
||||
@@ -49,8 +50,33 @@ export const searchFormSchema: FormSchema[] = [
|
||||
{
|
||||
label: '物料大类',
|
||||
field: 'majorCategoryId',
|
||||
component: 'JDictSelectTag',
|
||||
componentProps: { dictCode: 'mes_material_category,category_name,id' },
|
||||
component: 'ApiSelect',
|
||||
componentProps: {
|
||||
api: loadTreeData,
|
||||
params: { pcode: 'XSLMES_MATERIAL' },
|
||||
resultField: '',
|
||||
labelField: 'title',
|
||||
valueField: 'key',
|
||||
placeholder: '请选择物料大类',
|
||||
},
|
||||
colProps: { span: 6 },
|
||||
},
|
||||
{
|
||||
label: '物料小类',
|
||||
field: 'minorCategoryId',
|
||||
component: 'ApiSelect',
|
||||
componentProps: ({ formModel }) => {
|
||||
const majorCategoryId = formModel?.majorCategoryId ? String(formModel.majorCategoryId) : '';
|
||||
return {
|
||||
api: loadTreeData,
|
||||
params: majorCategoryId ? { pid: majorCategoryId } : { pid: '-1' },
|
||||
resultField: '',
|
||||
labelField: 'title',
|
||||
valueField: 'key',
|
||||
placeholder: majorCategoryId ? '请选择物料小类' : '请先选择物料大类',
|
||||
disabled: !majorCategoryId,
|
||||
};
|
||||
},
|
||||
colProps: { span: 6 },
|
||||
},
|
||||
];
|
||||
@@ -73,14 +99,16 @@ export const formSchema: FormSchema[] = [
|
||||
{
|
||||
label: '物料大类',
|
||||
field: 'majorCategoryId',
|
||||
component: 'JDictSelectTag',
|
||||
componentProps: { dictCode: 'mes_material_category,category_name,id' },
|
||||
required: true,
|
||||
component: 'Input',
|
||||
slot: 'majorCategoryIdField',
|
||||
},
|
||||
{
|
||||
label: '物料小类',
|
||||
field: 'minorCategoryId',
|
||||
component: 'JDictSelectTag',
|
||||
componentProps: { dictCode: 'mes_material_category,category_name,id' },
|
||||
required: true,
|
||||
component: 'Input',
|
||||
slot: 'minorCategoryIdField',
|
||||
},
|
||||
{ label: '物料描述', field: 'materialDesc', component: 'InputTextArea' },
|
||||
{ label: '物料别名', field: 'aliasName', component: 'Input' },
|
||||
|
||||
@@ -1,36 +1,114 @@
|
||||
<template>
|
||||
<div>
|
||||
<BasicTable @register="registerTable" :rowSelection="rowSelection">
|
||||
<template #tableTitle>
|
||||
<a-button type="primary" v-auth="'mes:mes_mixer_material:add'" @click="handleAdd" preIcon="ant-design:plus-outlined">新增</a-button>
|
||||
<a-button type="primary" v-auth="'mes:mes_mixer_material:exportXls'" preIcon="ant-design:export-outlined" @click="onExportXls">导出</a-button>
|
||||
<j-upload-button type="primary" v-auth="'mes:mes_mixer_material:importExcel'" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button>
|
||||
<a-dropdown v-if="selectedRowKeys.length > 0">
|
||||
<template #overlay>
|
||||
<a-menu>
|
||||
<a-menu-item key="1" @click="batchHandleDelete"><Icon icon="ant-design:delete-outlined" />删除</a-menu-item>
|
||||
</a-menu>
|
||||
<div class="mes-mixer-material-page">
|
||||
<div class="mes-mixer-material-layout">
|
||||
<div class="mes-mixer-material-sider-col">
|
||||
<aside
|
||||
:class="['mes-mixer-material-sider', { 'is-collapsed': siderCollapsed, 'is-dragging': siderDragging }]"
|
||||
:style="siderAsideStyle"
|
||||
>
|
||||
<Card class="mes-mixer-material-sider-card" size="small" title="物料分类" :bordered="true">
|
||||
<template #extra>
|
||||
<a-space v-show="!siderCollapsed" size="small">
|
||||
<a-button type="link" size="small" @click="handleAddCategory">新增</a-button>
|
||||
<a-button type="link" size="small" :disabled="!categorySelectedId" @click="handleEditCategory">编辑</a-button>
|
||||
<a-button type="link" size="small" danger :disabled="!categorySelectedId" @click="handleDeleteCategory">删除</a-button>
|
||||
</a-space>
|
||||
</template>
|
||||
<Spin :spinning="treeLoading">
|
||||
<BasicTree :treeData="categoryTreeData" :selectedKeys="selectedKeys" defaultExpandLevel="2" @update:selectedKeys="onTreeSelect" />
|
||||
</Spin>
|
||||
</Card>
|
||||
</aside>
|
||||
<div
|
||||
class="mes-mixer-material-resizer"
|
||||
:class="{ 'is-dragging': siderDragging }"
|
||||
role="separator"
|
||||
aria-orientation="vertical"
|
||||
:aria-valuenow="siderCollapsed ? 0 : siderWidth"
|
||||
:aria-valuemin="SIDER_MIN"
|
||||
:aria-valuemax="SIDER_MAX"
|
||||
tabindex="0"
|
||||
@pointerdown="onSiderResizerPointerDown"
|
||||
@keydown.left.prevent="nudgeSiderWidth(-16)"
|
||||
@keydown.right.prevent="nudgeSiderWidth(16)"
|
||||
>
|
||||
<a-tooltip :title="siderCollapsed ? '展开(可向右拖拽)' : '收起(点击)或左右拖拽调整宽度'">
|
||||
<span class="mes-mixer-material-resizer-knob" aria-hidden="true">
|
||||
<span class="mes-mixer-material-tri" :class="{ 'mes-mixer-material-tri--collapsed': siderCollapsed }" />
|
||||
</span>
|
||||
</a-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mes-mixer-material-main">
|
||||
<BasicTable @register="registerTable" :rowSelection="rowSelection">
|
||||
<template #tableTitle>
|
||||
<a-button type="primary" v-auth="'mes:mes_mixer_material:add'" @click="handleAdd" preIcon="ant-design:plus-outlined">新增</a-button>
|
||||
<a-button type="primary" v-auth="'mes:mes_mixer_material:exportXls'" preIcon="ant-design:export-outlined" @click="onExportXls">导出</a-button>
|
||||
<j-upload-button type="primary" v-auth="'mes:mes_mixer_material:importExcel'" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button>
|
||||
<a-dropdown v-if="selectedRowKeys.length > 0">
|
||||
<template #overlay>
|
||||
<a-menu>
|
||||
<a-menu-item key="1" @click="batchHandleDelete"><Icon icon="ant-design:delete-outlined" />删除</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
<a-button>批量操作<Icon icon="mdi:chevron-down" /></a-button>
|
||||
</a-dropdown>
|
||||
</template>
|
||||
<a-button>批量操作<Icon icon="mdi:chevron-down" /></a-button>
|
||||
</a-dropdown>
|
||||
</template>
|
||||
<template #action="{ record }">
|
||||
<TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)" />
|
||||
</template>
|
||||
</BasicTable>
|
||||
<template #action="{ record }">
|
||||
<TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)" />
|
||||
</template>
|
||||
</BasicTable>
|
||||
</div>
|
||||
</div>
|
||||
<MesMixerMaterialModal @register="registerModal" @success="handleSuccess" />
|
||||
<MesMixerMaterialSysCategoryModal @register="registerCategoryModal" @success="onCategorySuccess" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, onMounted, onUnmounted, reactive, ref } from 'vue';
|
||||
import { Card, Spin } from 'ant-design-vue';
|
||||
import { BasicTable, TableAction } from '/@/components/Table';
|
||||
import { BasicTree } from '/@/components/Tree';
|
||||
import { useModal } from '/@/components/Modal';
|
||||
import { useListPage } from '/@/hooks/system/useListPage';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import MesMixerMaterialModal from './modules/MesMixerMaterialModal.vue';
|
||||
import MesMixerMaterialSysCategoryModal from './modules/MesMixerMaterialSysCategoryModal.vue';
|
||||
import { columns, searchFormSchema } from './MesMixerMaterial.data';
|
||||
import { batchDelete, deleteOne, getExportUrl, getImportUrl, list } from './MesMixerMaterial.api';
|
||||
import { loadTreeData as loadCategoryTreeRoot } from '/@/views/system/category/category.api';
|
||||
import type { KeyType } from '/@/components/Tree/src/types/tree';
|
||||
import { deleteMaterialSysCategory, fetchMaterialCategoryRoot } from './MesMixerMaterialSysCategory.api';
|
||||
|
||||
const { createMessage, createConfirm } = useMessage();
|
||||
const TREE_ALL = 'ALL';
|
||||
const treeLoading = ref(false);
|
||||
const rawCategoryTree = ref<Recordable[]>([]);
|
||||
const selectedKeys = ref<KeyType[]>([TREE_ALL]);
|
||||
const queryParam = reactive<Recordable>({});
|
||||
const materialCategoryRootId = ref('');
|
||||
const SIDER_MIN = 200;
|
||||
const SIDER_MAX = 560;
|
||||
const SIDER_DEFAULT = 260;
|
||||
const SIDER_DRAG_THRESHOLD = 5;
|
||||
const SIDER_EXPAND_DRAG = 12;
|
||||
const siderCollapsed = ref(false);
|
||||
const siderWidth = ref(SIDER_DEFAULT);
|
||||
const siderDragging = ref(false);
|
||||
const siderAsideStyle = computed(() => ({
|
||||
width: siderCollapsed.value ? '0px' : `${siderWidth.value}px`,
|
||||
}));
|
||||
|
||||
let siderDragStartX = 0;
|
||||
let siderDragStartW = 0;
|
||||
let siderDragMaxDelta = 0;
|
||||
let siderDragCollapsedStart = false;
|
||||
let siderDragPointerId: number | null = null;
|
||||
let siderDragEl: HTMLElement | null = null;
|
||||
|
||||
const [registerModal, { openModal }] = useModal();
|
||||
const [registerCategoryModal, { openModal: openCategoryModal }] = useModal();
|
||||
const { tableContext, onExportXls, onImportXls } = useListPage({
|
||||
tableProps: {
|
||||
title: '密炼物料信息',
|
||||
@@ -39,12 +117,224 @@ const { tableContext, onExportXls, onImportXls } = useListPage({
|
||||
canResize: true,
|
||||
formConfig: { labelWidth: 120, schemas: searchFormSchema, autoSubmitOnEnter: true, showAdvancedButton: true },
|
||||
actionColumn: { width: 120 },
|
||||
beforeFetch: (params) => Object.assign(params, queryParam),
|
||||
},
|
||||
exportConfig: { name: '密炼物料信息', url: getExportUrl },
|
||||
exportConfig: { name: '密炼物料信息', url: getExportUrl, params: queryParam },
|
||||
importConfig: { url: getImportUrl, success: handleSuccess },
|
||||
});
|
||||
const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext;
|
||||
|
||||
function toggleSider() {
|
||||
siderCollapsed.value = !siderCollapsed.value;
|
||||
}
|
||||
|
||||
function clampSiderW(w: number) {
|
||||
return Math.min(SIDER_MAX, Math.max(SIDER_MIN, w));
|
||||
}
|
||||
|
||||
function nudgeSiderWidth(delta: number) {
|
||||
if (siderCollapsed.value) {
|
||||
if (delta > 0) siderCollapsed.value = false;
|
||||
else return;
|
||||
}
|
||||
siderWidth.value = clampSiderW(siderWidth.value + delta);
|
||||
}
|
||||
|
||||
function onSiderResizerPointerMove(e: PointerEvent) {
|
||||
if (siderDragPointerId == null || e.pointerId !== siderDragPointerId) return;
|
||||
const dx = e.clientX - siderDragStartX;
|
||||
siderDragMaxDelta = Math.max(siderDragMaxDelta, Math.abs(dx));
|
||||
|
||||
if (siderDragCollapsedStart) {
|
||||
if (dx >= SIDER_EXPAND_DRAG) {
|
||||
siderCollapsed.value = false;
|
||||
siderWidth.value = clampSiderW(dx);
|
||||
siderDragStartX = e.clientX;
|
||||
siderDragStartW = siderWidth.value;
|
||||
siderDragCollapsedStart = false;
|
||||
}
|
||||
} else {
|
||||
siderWidth.value = clampSiderW(siderDragStartW + dx);
|
||||
}
|
||||
}
|
||||
|
||||
function endSiderDrag(e: PointerEvent) {
|
||||
if (siderDragPointerId == null || e.pointerId !== siderDragPointerId) return;
|
||||
if (siderDragEl) {
|
||||
try {
|
||||
siderDragEl.releasePointerCapture(siderDragPointerId);
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
document.removeEventListener('pointermove', onSiderResizerPointerMove);
|
||||
document.removeEventListener('pointerup', endSiderDrag);
|
||||
document.removeEventListener('pointercancel', endSiderDrag);
|
||||
document.body.style.cursor = '';
|
||||
document.body.style.userSelect = '';
|
||||
siderDragging.value = false;
|
||||
siderDragPointerId = null;
|
||||
siderDragEl = null;
|
||||
if (siderDragMaxDelta < SIDER_DRAG_THRESHOLD) toggleSider();
|
||||
}
|
||||
|
||||
function onSiderResizerPointerDown(e: PointerEvent) {
|
||||
if (e.button !== 0) return;
|
||||
e.preventDefault();
|
||||
siderDragEl = e.currentTarget as HTMLElement;
|
||||
siderDragPointerId = e.pointerId;
|
||||
siderDragStartX = e.clientX;
|
||||
siderDragStartW = siderCollapsed.value ? 0 : siderWidth.value;
|
||||
siderDragMaxDelta = 0;
|
||||
siderDragCollapsedStart = siderCollapsed.value;
|
||||
siderDragging.value = true;
|
||||
document.body.style.cursor = 'col-resize';
|
||||
document.body.style.userSelect = 'none';
|
||||
try {
|
||||
siderDragEl.setPointerCapture(e.pointerId);
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
document.addEventListener('pointermove', onSiderResizerPointerMove);
|
||||
document.addEventListener('pointerup', endSiderDrag);
|
||||
document.addEventListener('pointercancel', endSiderDrag);
|
||||
}
|
||||
|
||||
function mapCategoryTreeNodes(nodes: Recordable[]): Recordable[] {
|
||||
return (nodes || []).map((n) => ({
|
||||
key: n.key,
|
||||
title: n.title,
|
||||
children: n.children?.length ? mapCategoryTreeNodes(n.children as Recordable[]) : undefined,
|
||||
}));
|
||||
}
|
||||
|
||||
const categoryTreeData = computed(() => [
|
||||
{ key: TREE_ALL, title: '全部分类', children: mapCategoryTreeNodes(rawCategoryTree.value || []) },
|
||||
]);
|
||||
|
||||
function findNodeByKey(nodes: Recordable[], key: string): Recordable | null {
|
||||
for (const n of nodes) {
|
||||
if (String(n.key) === key) return n;
|
||||
const nested = n.children as Recordable[] | undefined;
|
||||
if (nested?.length) {
|
||||
const found = findNodeByKey(nested, key);
|
||||
if (found) return found;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
async function loadCategoryTree() {
|
||||
treeLoading.value = true;
|
||||
try {
|
||||
const root = await fetchMaterialCategoryRoot();
|
||||
materialCategoryRootId.value = root?.id != null ? String(root.id) : '';
|
||||
const res = await loadCategoryTreeRoot({ async: false, pcode: 'XSLMES_MATERIAL' });
|
||||
rawCategoryTree.value = Array.isArray(res) ? res : [];
|
||||
if (!materialCategoryRootId.value || !rawCategoryTree.value.length) {
|
||||
createMessage.warning('未加载到物料分类树,请确认分类字典根编码 XSLMES_MATERIAL 已存在。');
|
||||
}
|
||||
} catch {
|
||||
materialCategoryRootId.value = '';
|
||||
rawCategoryTree.value = [];
|
||||
createMessage.warning('加载物料分类树失败,请检查分类根编码 XSLMES_MATERIAL 是否存在。');
|
||||
} finally {
|
||||
treeLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
const categorySelectedId = computed(() => {
|
||||
const k = selectedKeys.value[0];
|
||||
if (!k || k === TREE_ALL) return '';
|
||||
return String(k);
|
||||
});
|
||||
|
||||
function handleAddCategory() {
|
||||
const rootId = materialCategoryRootId.value;
|
||||
if (!rootId) {
|
||||
createMessage.warning('未找到物料分类根节点,请确认分类字典中存在编码「XSLMES_MATERIAL」');
|
||||
return;
|
||||
}
|
||||
const sel = categorySelectedId.value;
|
||||
const parentId = sel || rootId;
|
||||
openCategoryModal(true, { isUpdate: false, parentId });
|
||||
}
|
||||
|
||||
function handleEditCategory() {
|
||||
const id = categorySelectedId.value;
|
||||
if (!id) {
|
||||
createMessage.warning('请先选择左侧分类');
|
||||
return;
|
||||
}
|
||||
openCategoryModal(true, { isUpdate: true, record: { id } });
|
||||
}
|
||||
|
||||
async function handleDeleteCategory() {
|
||||
const id = categorySelectedId.value;
|
||||
if (!id) {
|
||||
createMessage.warning('请先选择要删除的分类');
|
||||
return;
|
||||
}
|
||||
if (id === materialCategoryRootId.value) {
|
||||
createMessage.warning('根分类不可删除');
|
||||
return;
|
||||
}
|
||||
createConfirm({
|
||||
iconType: 'warning',
|
||||
title: '确认删除',
|
||||
content: '将删除该节点及其下级分类,请确认无业务影响。',
|
||||
onOk: async () => {
|
||||
await deleteMaterialSysCategory(id);
|
||||
await loadCategoryTree();
|
||||
selectedKeys.value = [TREE_ALL];
|
||||
delete queryParam.majorCategoryId;
|
||||
delete queryParam.minorCategoryId;
|
||||
reload();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function onCategorySuccess() {
|
||||
loadCategoryTree();
|
||||
reload();
|
||||
}
|
||||
|
||||
function onTreeSelect(keys: KeyType[]) {
|
||||
selectedKeys.value = keys;
|
||||
delete queryParam.majorCategoryId;
|
||||
delete queryParam.minorCategoryId;
|
||||
|
||||
const k = keys[0];
|
||||
if (!k || k === TREE_ALL) {
|
||||
reload();
|
||||
return;
|
||||
}
|
||||
const node = findNodeByKey(rawCategoryTree.value, String(k));
|
||||
if (!node) {
|
||||
reload();
|
||||
return;
|
||||
}
|
||||
if (node.children?.length) {
|
||||
queryParam.majorCategoryId = String(k);
|
||||
} else {
|
||||
queryParam.minorCategoryId = String(k);
|
||||
}
|
||||
reload();
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await loadCategoryTree();
|
||||
reload();
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
document.removeEventListener('pointermove', onSiderResizerPointerMove);
|
||||
document.removeEventListener('pointerup', endSiderDrag);
|
||||
document.removeEventListener('pointercancel', endSiderDrag);
|
||||
document.body.style.cursor = '';
|
||||
document.body.style.userSelect = '';
|
||||
});
|
||||
|
||||
function handleAdd() {
|
||||
openModal(true, { isUpdate: false, showFooter: true });
|
||||
}
|
||||
@@ -77,3 +367,104 @@ function getDropDownAction(record) {
|
||||
];
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.mes-mixer-material-page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: calc(100vh - 160px);
|
||||
}
|
||||
.mes-mixer-material-layout {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
align-items: stretch;
|
||||
min-height: 0;
|
||||
}
|
||||
.mes-mixer-material-sider-col {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: stretch;
|
||||
flex: 0 0 auto;
|
||||
min-height: 0;
|
||||
}
|
||||
.mes-mixer-material-sider {
|
||||
flex: 0 0 auto;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
transition: width 0.2s ease;
|
||||
&.is-dragging {
|
||||
transition: none;
|
||||
}
|
||||
&.is-collapsed {
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
.mes-mixer-material-sider-card {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
:deep(.ant-card-body) {
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
min-height: 0;
|
||||
padding: 8px 12px;
|
||||
}
|
||||
}
|
||||
.mes-mixer-material-resizer {
|
||||
flex: 0 0 8px;
|
||||
width: 8px;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
cursor: col-resize;
|
||||
touch-action: none;
|
||||
user-select: none;
|
||||
background: #fafafa;
|
||||
margin-right: 2px;
|
||||
&:hover,
|
||||
&:focus-visible {
|
||||
background: #f0f0f0;
|
||||
}
|
||||
&.is-dragging {
|
||||
background: #e6f4ff;
|
||||
}
|
||||
}
|
||||
.mes-mixer-material-resizer-knob {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 10px;
|
||||
height: 44px;
|
||||
pointer-events: none;
|
||||
background: #fff;
|
||||
border: 1px solid #e8e8e8;
|
||||
border-radius: 2px;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
.mes-mixer-material-tri {
|
||||
display: block;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-style: solid;
|
||||
border-width: 5px 6px 5px 0;
|
||||
border-color: transparent #595959 transparent transparent;
|
||||
margin-left: -1px;
|
||||
}
|
||||
.mes-mixer-material-tri--collapsed {
|
||||
border-width: 5px 0 5px 6px;
|
||||
border-color: transparent transparent transparent #595959;
|
||||
margin-left: 0;
|
||||
margin-right: -1px;
|
||||
}
|
||||
.mes-mixer-material-main {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
import type { Recordable } from '/@/types/global';
|
||||
|
||||
export const MATERIAL_CATEGORY_ROOT_CODE = 'XSLMES_MATERIAL';
|
||||
|
||||
export function fetchMaterialCategoryRoot() {
|
||||
return defHttp.get<Recordable>({
|
||||
url: '/sys/category/loadOne',
|
||||
params: { field: 'code', val: MATERIAL_CATEGORY_ROOT_CODE },
|
||||
});
|
||||
}
|
||||
|
||||
export function saveMaterialSysCategory(data: Recordable) {
|
||||
return defHttp.post({ url: '/sys/category/add', data });
|
||||
}
|
||||
|
||||
export function editMaterialSysCategory(data: Recordable) {
|
||||
return defHttp.post({ url: '/sys/category/edit', data });
|
||||
}
|
||||
|
||||
export function deleteMaterialSysCategory(id: string) {
|
||||
return defHttp.delete({ url: '/sys/category/delete', params: { id } }, { joinParamsToUrl: true });
|
||||
}
|
||||
|
||||
@@ -1,6 +1,27 @@
|
||||
<template>
|
||||
<BasicModal @register="registerModal" :title="title" width="720px" v-bind="$attrs" @ok="handleSubmit">
|
||||
<BasicForm @register="registerForm" />
|
||||
<BasicForm @register="registerForm">
|
||||
<template #majorCategoryIdField="{ model, field }">
|
||||
<a-select
|
||||
v-model:value="model[field]"
|
||||
placeholder="请选择物料大类"
|
||||
:options="majorCategoryOptions"
|
||||
allowClear
|
||||
@change="(v) => onMajorCategoryChange(model, v)"
|
||||
>
|
||||
</a-select>
|
||||
</template>
|
||||
<template #minorCategoryIdField="{ model, field }">
|
||||
<a-select
|
||||
v-model:value="model[field]"
|
||||
placeholder="请选择物料小类"
|
||||
:options="minorCategoryOptions"
|
||||
:disabled="!model.majorCategoryId"
|
||||
allowClear
|
||||
>
|
||||
</a-select>
|
||||
</template>
|
||||
</BasicForm>
|
||||
</BasicModal>
|
||||
</template>
|
||||
|
||||
@@ -10,9 +31,12 @@ import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||
import { BasicForm, useForm } from '/@/components/Form/index';
|
||||
import { formSchema } from '../MesMixerMaterial.data';
|
||||
import { saveOrUpdate } from '../MesMixerMaterial.api';
|
||||
import { loadTreeData } from '/@/api/common/api';
|
||||
|
||||
const emit = defineEmits(['register', 'success']);
|
||||
const isUpdate = ref(true);
|
||||
const majorCategoryOptions = ref<{ label: string; value: string }[]>([]);
|
||||
const minorCategoryOptions = ref<{ label: string; value: string }[]>([]);
|
||||
|
||||
const [registerForm, { resetFields, setFieldsValue, validate, setProps }] = useForm({
|
||||
labelWidth: 140,
|
||||
@@ -24,14 +48,54 @@ const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data
|
||||
await resetFields();
|
||||
setModalProps({ confirmLoading: false, showCancelBtn: data?.showFooter, showOkBtn: data?.showFooter });
|
||||
isUpdate.value = !!data?.isUpdate;
|
||||
await loadMajorCategories();
|
||||
if (unref(isUpdate)) {
|
||||
await setFieldsValue({ ...data.record });
|
||||
await loadMinorCategoriesByMajor(data?.record?.majorCategoryId);
|
||||
}
|
||||
if (!unref(isUpdate)) {
|
||||
minorCategoryOptions.value = [];
|
||||
}
|
||||
setProps({ disabled: !data?.showFooter });
|
||||
});
|
||||
|
||||
const title = computed(() => (!unref(isUpdate) ? '新增密炼物料' : '编辑密炼物料'));
|
||||
|
||||
async function onMajorCategoryChange(model: Recordable, majorCategoryId: unknown) {
|
||||
const majorId = majorCategoryId == null ? '' : String(majorCategoryId);
|
||||
if (!majorId) {
|
||||
model.minorCategoryId = '';
|
||||
minorCategoryOptions.value = [];
|
||||
return;
|
||||
}
|
||||
// 大类切换后清空原小类,避免提交不匹配数据
|
||||
model.minorCategoryId = '';
|
||||
await loadMinorCategoriesByMajor(majorId);
|
||||
}
|
||||
|
||||
async function loadMajorCategories() {
|
||||
const rows = await loadTreeData({ pcode: 'XSLMES_MATERIAL' });
|
||||
const list = Array.isArray(rows) ? rows : [];
|
||||
majorCategoryOptions.value = list.map((item: any) => ({
|
||||
label: item?.title ?? item?.name ?? '',
|
||||
value: String(item?.key ?? item?.id ?? ''),
|
||||
}));
|
||||
}
|
||||
|
||||
async function loadMinorCategoriesByMajor(majorCategoryId?: string) {
|
||||
const majorId = majorCategoryId == null ? '' : String(majorCategoryId);
|
||||
if (!majorId) {
|
||||
minorCategoryOptions.value = [];
|
||||
return;
|
||||
}
|
||||
const rows = await loadTreeData({ pid: majorId });
|
||||
const list = Array.isArray(rows) ? rows : [];
|
||||
minorCategoryOptions.value = list.map((item: any) => ({
|
||||
label: item?.title ?? item?.name ?? '',
|
||||
value: String(item?.key ?? item?.id ?? ''),
|
||||
}));
|
||||
}
|
||||
|
||||
async function handleSubmit() {
|
||||
try {
|
||||
const values = await validate();
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
<template>
|
||||
<BasicModal v-bind="$attrs" @register="registerModal" destroyOnClose :title="title" :width="560" @ok="handleSubmit">
|
||||
<BasicForm @register="registerForm" />
|
||||
</BasicModal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref, unref } from 'vue';
|
||||
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||
import { BasicForm, useForm } from '/@/components/Form';
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
import { loadTreeData } from '/@/views/system/category/category.api';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import type { FormSchema } from '/@/components/Form';
|
||||
import type { Recordable } from '/@/types/global';
|
||||
import { editMaterialSysCategory, fetchMaterialCategoryRoot, saveMaterialSysCategory } from '../MesMixerMaterialSysCategory.api';
|
||||
|
||||
const { createMessage } = useMessage();
|
||||
const emit = defineEmits(['register', 'success']);
|
||||
const isUpdate = ref(false);
|
||||
|
||||
const schemas: FormSchema[] = [
|
||||
{ field: 'id', label: 'ID', component: 'Input', show: false },
|
||||
{
|
||||
field: 'pid',
|
||||
label: '上级分类',
|
||||
component: 'TreeSelect',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
field: 'name',
|
||||
label: '分类名称',
|
||||
component: 'Input',
|
||||
required: true,
|
||||
componentProps: { maxlength: 50, placeholder: '请输入分类名称' },
|
||||
},
|
||||
];
|
||||
|
||||
const [registerForm, { resetFields, setFieldsValue, validate, updateSchema, scrollToField }] = useForm({
|
||||
labelWidth: 100,
|
||||
schemas,
|
||||
showActionButtonGroup: false,
|
||||
baseColProps: { span: 24 },
|
||||
});
|
||||
|
||||
function mapTreeNodes(nodes: Recordable[]): Recordable[] {
|
||||
return (nodes || []).map((n) => ({
|
||||
key: n.key,
|
||||
title: n.title,
|
||||
children: n.children?.length ? mapTreeNodes(n.children as Recordable[]) : undefined,
|
||||
}));
|
||||
}
|
||||
|
||||
async function buildPidTree(): Promise<Recordable[]> {
|
||||
const root = await fetchMaterialCategoryRoot();
|
||||
if (!root?.id) return [];
|
||||
const children = await loadTreeData({ async: false, pcode: 'XSLMES_MATERIAL' });
|
||||
return [
|
||||
{
|
||||
key: root.id,
|
||||
title: root.name || '物料分类',
|
||||
children: mapTreeNodes(Array.isArray(children) ? children : []),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
|
||||
await resetFields();
|
||||
setModalProps({ confirmLoading: false });
|
||||
isUpdate.value = !!data?.isUpdate;
|
||||
const tree = await buildPidTree();
|
||||
if (!tree.length) {
|
||||
createMessage.warning('未加载到物料分类树,请确认分类字典根编码 XSLMES_MATERIAL 已存在');
|
||||
}
|
||||
await updateSchema([
|
||||
{
|
||||
field: 'pid',
|
||||
componentProps: {
|
||||
treeData: tree,
|
||||
fieldNames: { label: 'title', value: 'key' },
|
||||
showSearch: true,
|
||||
allowClear: false,
|
||||
treeDefaultExpandAll: true,
|
||||
dropdownStyle: { maxHeight: '50vh' },
|
||||
getPopupContainer: () => document.body,
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
if (unref(isUpdate) && data?.record?.id) {
|
||||
const cat = await defHttp.get<Recordable>({ url: '/sys/category/queryById', params: { id: data.record.id } });
|
||||
await setFieldsValue({ id: cat.id, pid: cat.pid, name: cat.name });
|
||||
} else {
|
||||
const pid = data?.parentId != null && data.parentId !== '' ? String(data.parentId) : '';
|
||||
await setFieldsValue({ pid: pid || undefined, name: '' });
|
||||
}
|
||||
});
|
||||
|
||||
const title = computed(() => (unref(isUpdate) ? '编辑物料分类' : '新增物料分类'));
|
||||
|
||||
async function handleSubmit() {
|
||||
try {
|
||||
const values = await validate();
|
||||
setModalProps({ confirmLoading: true });
|
||||
if (unref(isUpdate)) {
|
||||
const full = await defHttp.get<Recordable>({ url: '/sys/category/queryById', params: { id: values.id } });
|
||||
await editMaterialSysCategory({ ...full, pid: values.pid, name: values.name });
|
||||
} else {
|
||||
await saveMaterialSysCategory({ pid: values.pid, name: values.name });
|
||||
}
|
||||
closeModal();
|
||||
emit('success');
|
||||
} catch (e: any) {
|
||||
if (e?.errorFields) {
|
||||
const firstField = e.errorFields[0];
|
||||
if (firstField) {
|
||||
scrollToField(firstField.name, { behavior: 'smooth', block: 'center' });
|
||||
}
|
||||
}
|
||||
return Promise.reject(e);
|
||||
} finally {
|
||||
setModalProps({ confirmLoading: false });
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user