feat:仓库、库区、仓位基础功能
This commit is contained in:
@@ -80,3 +80,10 @@ export function deleteBsrealStorAttrList(ids: string[]) {
|
||||
export function exportBsrealStorAttr(params: any) {
|
||||
return requestClient.download('/wms/bsreal-stor-attr/export-excel', { params });
|
||||
}
|
||||
|
||||
/** 获得启用的实物库属性精简列表 */
|
||||
export function getBsrealStorAttrSimpleList() {
|
||||
return requestClient.get<{ storId: string; storName: string }[]>(
|
||||
'/wms/bsreal-stor-attr/simple-list',
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
import type { PageParam, PageResult } from '@vben/request';
|
||||
|
||||
import { requestClient } from '#/api/request';
|
||||
|
||||
export namespace WmsSectAttrApi {
|
||||
/** 库区属性信息 */
|
||||
export interface SectAttr {
|
||||
sectId: string; // 库区标识
|
||||
sectCode?: string; // 库区编码
|
||||
sectName?: string; // 库区名称
|
||||
simpleName: string; // 库区简称
|
||||
sectTypeAttr?: string; // 库区类型
|
||||
storId?: string; // 仓库标识
|
||||
storType: string; // 仓库类型
|
||||
capacity: number; // 容量
|
||||
width: number; // 宽度
|
||||
height: number; // 高度
|
||||
zdepth: number; // 深度
|
||||
xqty: number; // 起始X坐标
|
||||
yqty: number; // 起始Y坐标
|
||||
zqty: number; // 起始Z坐标
|
||||
sectManagerName: string; // 负责人
|
||||
mobileNo: string; // 负责人电话
|
||||
remark: string; // 备注
|
||||
backGroundColor: string; // 背景色
|
||||
frontGroundColor: string; // 前景色
|
||||
backGroundPic: string; // 背景图片
|
||||
fontDirectionScode: string; // 字体显示方向
|
||||
floorNo: number; // 所在楼层
|
||||
isUsed?: string; // 是否启用
|
||||
extId: string; // 外部标识
|
||||
}
|
||||
}
|
||||
|
||||
/** 查询库区属性分页 */
|
||||
export function getSectAttrPage(params: PageParam) {
|
||||
return requestClient.get<PageResult<WmsSectAttrApi.SectAttr>>(
|
||||
'/wms/sect-attr/page',
|
||||
{ params },
|
||||
);
|
||||
}
|
||||
|
||||
/** 查询库区属性详情 */
|
||||
export function getSectAttr(id: string) {
|
||||
return requestClient.get<WmsSectAttrApi.SectAttr>(
|
||||
`/wms/sect-attr/get?id=${id}`,
|
||||
);
|
||||
}
|
||||
|
||||
/** 新增库区属性 */
|
||||
export function createSectAttr(data: WmsSectAttrApi.SectAttr) {
|
||||
return requestClient.post('/wms/sect-attr/create', data);
|
||||
}
|
||||
|
||||
/** 修改库区属性 */
|
||||
export function updateSectAttr(data: WmsSectAttrApi.SectAttr) {
|
||||
return requestClient.put('/wms/sect-attr/update', data);
|
||||
}
|
||||
|
||||
/** 删除库区属性 */
|
||||
export function deleteSectAttr(id: string) {
|
||||
return requestClient.delete(`/wms/sect-attr/delete?id=${id}`);
|
||||
}
|
||||
|
||||
/** 批量删除库区属性 */
|
||||
export function deleteSectAttrList(ids: string[]) {
|
||||
return requestClient.delete(
|
||||
`/wms/sect-attr/delete-list?ids=${ids.join(',')}`,
|
||||
);
|
||||
}
|
||||
|
||||
/** 导出库区属性 */
|
||||
export function exportSectAttr(params: any) {
|
||||
return requestClient.download('/wms/sect-attr/export-excel', { params });
|
||||
}
|
||||
|
||||
/** 获得启用的库区属性精简列表(可按仓库筛选) */
|
||||
export function getSectAttrSimpleList(storId?: string) {
|
||||
return requestClient.get<{ sectId: string; sectName: string; storId: string }[]>(
|
||||
'/wms/sect-attr/simple-list',
|
||||
{ params: storId ? { storId } : {} },
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
import type { PageParam, PageResult } from '@vben/request';
|
||||
|
||||
import { requestClient } from '#/api/request';
|
||||
|
||||
export namespace WmsStrucAttrApi {
|
||||
/** 仓位属性信息 */
|
||||
export interface StrucAttr {
|
||||
structId: string; // 仓位标识
|
||||
structCode?: string; // 仓位编码
|
||||
structName?: string; // 仓位名称
|
||||
simpleName: string; // 仓位简称
|
||||
sectId?: string; // 库区标识
|
||||
sectCode?: string; // 库区编码
|
||||
sectName?: string; // 库区名称
|
||||
storId?: string; // 仓库标识
|
||||
storCode?: string; // 仓库编码
|
||||
storName?: string; // 仓库名称
|
||||
storType: string; // 仓库类型
|
||||
capacity: number; // 容量
|
||||
width: number; // 宽度
|
||||
height: number; // 高度
|
||||
zdepth: number; // 深度
|
||||
weight: number; // 承受重量
|
||||
xqty: number; // 起始X坐标
|
||||
yqty: number; // 起始Y坐标
|
||||
zqty: number; // 起始Z坐标
|
||||
isTempstruct?: string; // 是否临时仓位
|
||||
rowNum: number; // 排
|
||||
colNum: number; // 列
|
||||
layerNum: number; // 层
|
||||
blockNum: number; // 块
|
||||
placementType: string; // 放置类型
|
||||
isUsed?: boolean; // 是否启用
|
||||
isZdepth: string; // 是否判断高度
|
||||
storagevehicleCode: string; // 存储载具号
|
||||
storagevehicleType: string; // 载具类型
|
||||
storagevehicleQty: number; // 载具数量
|
||||
lockType?: string; // 锁定类型
|
||||
taskCode: string; // 锁定任务编码
|
||||
invType: string; // 锁定单据类型
|
||||
invId: string; // 锁定单据标识
|
||||
invCode: string; // 锁定单据编码
|
||||
extId: string; // 外部标识
|
||||
remark: string; // 备注
|
||||
}
|
||||
}
|
||||
|
||||
/** 查询仓位属性分页 */
|
||||
export function getStrucAttrPage(params: PageParam) {
|
||||
return requestClient.get<PageResult<WmsStrucAttrApi.StrucAttr>>(
|
||||
'/wms/struc-attr/page',
|
||||
{ params },
|
||||
);
|
||||
}
|
||||
|
||||
/** 查询仓位属性详情 */
|
||||
export function getStrucAttr(id: number) {
|
||||
return requestClient.get<WmsStrucAttrApi.StrucAttr>(
|
||||
`/wms/struc-attr/get?id=${id}`,
|
||||
);
|
||||
}
|
||||
|
||||
/** 新增仓位属性 */
|
||||
export function createStrucAttr(data: WmsStrucAttrApi.StrucAttr) {
|
||||
return requestClient.post('/wms/struc-attr/create', data);
|
||||
}
|
||||
|
||||
/** 修改仓位属性 */
|
||||
export function updateStrucAttr(data: WmsStrucAttrApi.StrucAttr) {
|
||||
return requestClient.put('/wms/struc-attr/update', data);
|
||||
}
|
||||
|
||||
/** 删除仓位属性 */
|
||||
export function deleteStrucAttr(id: number) {
|
||||
return requestClient.delete(`/wms/struc-attr/delete?id=${id}`);
|
||||
}
|
||||
|
||||
/** 批量删除仓位属性 */
|
||||
export function deleteStrucAttrList(ids: number[]) {
|
||||
return requestClient.delete(
|
||||
`/wms/struc-attr/delete-list?ids=${ids.join(',')}`,
|
||||
);
|
||||
}
|
||||
|
||||
/** 导出仓位属性 */
|
||||
export function exportStrucAttr(params: any) {
|
||||
return requestClient.download('/wms/struc-attr/export-excel', { params });
|
||||
}
|
||||
@@ -0,0 +1,377 @@
|
||||
import type { VbenFormSchema } from '#/adapter/form';
|
||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||
import type { WmsSectAttrApi } from '#/api/wms/sectattr';
|
||||
|
||||
import { getBsrealStorAttrSimpleList } from '#/api/wms/bsrealstorattr';
|
||||
import { getRangePickerDefaultProps } from '#/utils';
|
||||
|
||||
/** 是/否 选项 */
|
||||
const BOOLEAN_OPTIONS = [
|
||||
{ label: '是', value: '1' },
|
||||
{ label: '否', value: '0' },
|
||||
];
|
||||
|
||||
// ========== 仓库名称映射表(storId → storName) ==========
|
||||
const warehouseNameMap: Record<string, string> = {};
|
||||
|
||||
// ========== 启用的仓库下拉 ==========
|
||||
async function loadWarehouseList() {
|
||||
const data = await getBsrealStorAttrSimpleList();
|
||||
// 填充映射表
|
||||
if (data) {
|
||||
data.forEach((item) => {
|
||||
warehouseNameMap[item.storId] = item.storName;
|
||||
});
|
||||
}
|
||||
return data || [];
|
||||
}
|
||||
|
||||
/** 仓库标识 → 仓库名称 格式化 */
|
||||
function warehouseFormatter({ cellValue }: { cellValue: string }) {
|
||||
return warehouseNameMap[cellValue] || cellValue;
|
||||
}
|
||||
|
||||
/** 是/否 格式化('1' → '是','0' → '否') */
|
||||
function boolFormatter({ cellValue }: { cellValue: string }) {
|
||||
return cellValue === '1' ? '是' : '否';
|
||||
}
|
||||
|
||||
/** 新增/修改的表单 */
|
||||
export function useFormSchema(): VbenFormSchema[] {
|
||||
return [
|
||||
{
|
||||
fieldName: 'sectId',
|
||||
component: 'Input',
|
||||
dependencies: {
|
||||
triggerFields: [''],
|
||||
show: () => false,
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'sectCode',
|
||||
label: '库区编码',
|
||||
rules: 'required',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
placeholder: '请输入库区编码',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'sectName',
|
||||
label: '库区名称',
|
||||
rules: 'required',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
placeholder: '请输入库区名称',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'simpleName',
|
||||
label: '库区简称',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
placeholder: '请输入库区简称',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'sectTypeAttr',
|
||||
label: '库区类型',
|
||||
rules: 'required',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
placeholder: '请输入库区类型',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'storId',
|
||||
label: '仓库标识',
|
||||
rules: 'required',
|
||||
component: 'ApiSelect',
|
||||
componentProps: {
|
||||
api: loadWarehouseList,
|
||||
labelField: 'storName',
|
||||
valueField: 'storId',
|
||||
placeholder: '请选择仓库',
|
||||
allowClear: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'storType',
|
||||
label: '仓库类型',
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
options: [],
|
||||
placeholder: '请选择仓库类型',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'capacity',
|
||||
label: '容量',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
placeholder: '请输入容量',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'width',
|
||||
label: '宽度',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
placeholder: '请输入宽度',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'height',
|
||||
label: '高度',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
placeholder: '请输入高度',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'zdepth',
|
||||
label: '深度',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
placeholder: '请输入深度',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'xqty',
|
||||
label: '起始X坐标',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
placeholder: '请输入起始X坐标',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'yqty',
|
||||
label: '起始Y坐标',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
placeholder: '请输入起始Y坐标',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'zqty',
|
||||
label: '起始Z坐标',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
placeholder: '请输入起始Z坐标',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'sectManagerName',
|
||||
label: '负责人',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
placeholder: '请输入负责人',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'mobileNo',
|
||||
label: '负责人电话',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
placeholder: '请输入负责人电话',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'remark',
|
||||
label: '备注',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
placeholder: '请输入备注',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'backGroundColor',
|
||||
label: '背景色',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
placeholder: '请输入背景色',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'frontGroundColor',
|
||||
label: '前景色',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
placeholder: '请输入前景色',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'backGroundPic',
|
||||
label: '背景图片',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
placeholder: '请输入背景图片',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'fontDirectionScode',
|
||||
label: '字体显示方向',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
placeholder: '请输入字体显示方向',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'floorNo',
|
||||
label: '所在楼层',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
placeholder: '请输入所在楼层',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'isUsed',
|
||||
label: '是否启用',
|
||||
rules: 'required',
|
||||
component: 'RadioGroup',
|
||||
componentProps: {
|
||||
options: BOOLEAN_OPTIONS,
|
||||
buttonStyle: 'solid',
|
||||
optionType: 'button',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'extId',
|
||||
label: '外部标识',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
placeholder: '请输入外部标识',
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/** 列表的搜索表单 */
|
||||
export function useGridFormSchema(): VbenFormSchema[] {
|
||||
return [
|
||||
{
|
||||
fieldName: 'sectCode',
|
||||
label: '库区编码',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
placeholder: '请输入库区编码',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'sectName',
|
||||
label: '库区名称',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
placeholder: '请输入库区名称',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'sectTypeAttr',
|
||||
label: '库区类型',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
placeholder: '请输入库区类型',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'storId',
|
||||
label: '仓库标识',
|
||||
component: 'ApiSelect',
|
||||
componentProps: {
|
||||
api: loadWarehouseList,
|
||||
labelField: 'storName',
|
||||
valueField: 'storId',
|
||||
placeholder: '请选择仓库',
|
||||
allowClear: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'createTime',
|
||||
label: '创建时间',
|
||||
component: 'RangePicker',
|
||||
componentProps: {
|
||||
...getRangePickerDefaultProps(),
|
||||
allowClear: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'isUsed',
|
||||
label: '是否启用',
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
options: BOOLEAN_OPTIONS,
|
||||
placeholder: '请选择是否启用',
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/** 列表的字段 */
|
||||
export function useGridColumns(): VxeTableGridOptions<WmsSectAttrApi.SectAttr>['columns'] {
|
||||
return [
|
||||
{ type: 'checkbox', width: 40 },
|
||||
{
|
||||
field: 'sectId',
|
||||
title: '库区标识',
|
||||
visible: false,
|
||||
},
|
||||
{
|
||||
field: 'sectCode',
|
||||
title: '库区编码',
|
||||
minWidth: 120,
|
||||
},
|
||||
{
|
||||
field: 'sectName',
|
||||
title: '库区名称',
|
||||
minWidth: 120,
|
||||
},
|
||||
{
|
||||
field: 'simpleName',
|
||||
title: '库区简称',
|
||||
minWidth: 120,
|
||||
},
|
||||
{
|
||||
field: 'sectTypeAttr',
|
||||
title: '库区类型',
|
||||
minWidth: 120,
|
||||
},
|
||||
{
|
||||
field: 'storId',
|
||||
title: '仓库名称',
|
||||
minWidth: 120,
|
||||
formatter: warehouseFormatter,
|
||||
},
|
||||
{
|
||||
field: 'remark',
|
||||
title: '备注',
|
||||
minWidth: 120,
|
||||
},
|
||||
{
|
||||
field: 'createTime',
|
||||
title: '创建时间',
|
||||
minWidth: 120,
|
||||
formatter: 'formatDateTime',
|
||||
},
|
||||
{
|
||||
field: 'isUsed',
|
||||
title: '是否启用',
|
||||
minWidth: 120,
|
||||
formatter: boolFormatter,
|
||||
},
|
||||
{
|
||||
field: 'extId',
|
||||
title: '外部标识',
|
||||
minWidth: 120,
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
width: 200,
|
||||
fixed: 'right',
|
||||
slots: { default: 'actions' },
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
<script lang="ts" setup>
|
||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||
import type { WmsSectAttrApi } from '#/api/wms/sectattr';
|
||||
|
||||
import { ref } from 'vue';
|
||||
|
||||
import { confirm, Page, useVbenModal } from '@vben/common-ui';
|
||||
import { downloadFileFromBlobPart, isEmpty } from '@vben/utils';
|
||||
|
||||
import { message } from 'antdv-next';
|
||||
|
||||
import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||
import {
|
||||
deleteSectAttr,
|
||||
deleteSectAttrList,
|
||||
exportSectAttr,
|
||||
getSectAttrPage,
|
||||
} from '#/api/wms/sectattr';
|
||||
import { $t } from '#/locales';
|
||||
|
||||
import { useGridColumns, useGridFormSchema } from './data';
|
||||
import Form from './modules/form.vue';
|
||||
|
||||
const [FormModal, formModalApi] = useVbenModal({
|
||||
connectedComponent: Form,
|
||||
destroyOnClose: true,
|
||||
});
|
||||
|
||||
/** 刷新表格 */
|
||||
function handleRefresh() {
|
||||
gridApi.query();
|
||||
}
|
||||
|
||||
/** 创建库区属性 */
|
||||
function handleCreate() {
|
||||
formModalApi.setData(null).open();
|
||||
}
|
||||
|
||||
/** 编辑库区属性 */
|
||||
function handleEdit(row: WmsSectAttrApi.SectAttr) {
|
||||
formModalApi.setData(row).open();
|
||||
}
|
||||
|
||||
/** 删除库区属性 */
|
||||
async function handleDelete(row: WmsSectAttrApi.SectAttr) {
|
||||
const hideLoading = message.loading({
|
||||
content: $t('ui.actionMessage.deleting', [row.sectId]),
|
||||
duration: 0,
|
||||
});
|
||||
try {
|
||||
await deleteSectAttr(row.sectId!);
|
||||
message.success($t('ui.actionMessage.deleteSuccess', [row.sectId]));
|
||||
handleRefresh();
|
||||
} finally {
|
||||
hideLoading();
|
||||
}
|
||||
}
|
||||
|
||||
/** 批量删除库区属性 */
|
||||
async function handleDeleteBatch() {
|
||||
await confirm($t('ui.actionMessage.deleteBatchConfirm'));
|
||||
const hideLoading = message.loading({
|
||||
content: $t('ui.actionMessage.deletingBatch'),
|
||||
duration: 0,
|
||||
});
|
||||
try {
|
||||
await deleteSectAttrList(checkedIds.value);
|
||||
checkedIds.value = [];
|
||||
message.success($t('ui.actionMessage.deleteSuccess'));
|
||||
handleRefresh();
|
||||
} finally {
|
||||
hideLoading();
|
||||
}
|
||||
}
|
||||
|
||||
const checkedIds = ref<string[]>([]);
|
||||
function handleRowCheckboxChange({
|
||||
records,
|
||||
}: {
|
||||
records: WmsSectAttrApi.SectAttr[];
|
||||
}) {
|
||||
checkedIds.value = records.map((item) => item.sectId! as string);
|
||||
}
|
||||
|
||||
/** 导出表格 */
|
||||
async function handleExport() {
|
||||
const data = await exportSectAttr(await gridApi.formApi.getValues());
|
||||
downloadFileFromBlobPart({ fileName: '库区属性.xls', source: data });
|
||||
}
|
||||
|
||||
|
||||
const [Grid, gridApi] = useVbenVxeGrid({
|
||||
formOptions: {
|
||||
schema: useGridFormSchema(),
|
||||
},
|
||||
gridOptions: {
|
||||
columns: useGridColumns(),
|
||||
height: 'auto',
|
||||
keepSource: true,
|
||||
proxyConfig: {
|
||||
ajax: {
|
||||
query: async ({ page }, formValues) => {
|
||||
return await getSectAttrPage({
|
||||
pageNo: page.currentPage,
|
||||
pageSize: page.pageSize,
|
||||
...formValues,
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
rowConfig: {
|
||||
keyField: 'sectId',
|
||||
isHover: true,
|
||||
},
|
||||
toolbarConfig: {
|
||||
refresh: true,
|
||||
search: true,
|
||||
},
|
||||
} as VxeTableGridOptions<WmsSectAttrApi.SectAttr>,
|
||||
gridEvents: {
|
||||
checkboxAll: handleRowCheckboxChange,
|
||||
checkboxChange: handleRowCheckboxChange,
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Page auto-content-height>
|
||||
<FormModal @success="handleRefresh" />
|
||||
<Grid table-title="库区属性列表">
|
||||
<template #toolbar-tools>
|
||||
<TableAction
|
||||
:actions="[
|
||||
{
|
||||
label: $t('ui.actionTitle.create', ['库区属性']),
|
||||
type: 'primary',
|
||||
icon: ACTION_ICON.ADD,
|
||||
auth: ['wms:sect-attr:create'],
|
||||
onClick: handleCreate,
|
||||
},
|
||||
{
|
||||
label: $t('ui.actionTitle.export'),
|
||||
type: 'primary',
|
||||
icon: ACTION_ICON.DOWNLOAD,
|
||||
auth: ['wms:sect-attr:export'],
|
||||
onClick: handleExport,
|
||||
},
|
||||
{
|
||||
label: $t('ui.actionTitle.deleteBatch'),
|
||||
type: 'primary',
|
||||
danger: true,
|
||||
icon: ACTION_ICON.DELETE,
|
||||
auth: ['wms:sect-attr:delete'],
|
||||
disabled: isEmpty(checkedIds),
|
||||
onClick: handleDeleteBatch,
|
||||
},
|
||||
]"
|
||||
/>
|
||||
</template>
|
||||
<template #actions="{ row }">
|
||||
<TableAction
|
||||
:actions="[
|
||||
{
|
||||
label: $t('common.edit'),
|
||||
type: 'link',
|
||||
icon: ACTION_ICON.EDIT,
|
||||
auth: ['wms:sect-attr:update'],
|
||||
onClick: handleEdit.bind(null, row),
|
||||
},
|
||||
{
|
||||
label: $t('common.delete'),
|
||||
type: 'link',
|
||||
danger: true,
|
||||
icon: ACTION_ICON.DELETE,
|
||||
auth: ['wms:sect-attr:delete'],
|
||||
popConfirm: {
|
||||
title: $t('ui.actionMessage.deleteConfirm', [row.sectId]),
|
||||
confirm: handleDelete.bind(null, row),
|
||||
},
|
||||
},
|
||||
]"
|
||||
/>
|
||||
</template>
|
||||
</Grid>
|
||||
</Page>
|
||||
</template>
|
||||
@@ -0,0 +1,82 @@
|
||||
<script lang="ts" setup>
|
||||
import type { WmsSectAttrApi } from '#/api/wms/sectattr';
|
||||
|
||||
import { computed, ref } from 'vue';
|
||||
|
||||
import { useVbenModal } from '@vben/common-ui';
|
||||
|
||||
import { message } from 'antdv-next';
|
||||
|
||||
import { useVbenForm } from '#/adapter/form';
|
||||
import { createSectAttr, getSectAttr, updateSectAttr } from '#/api/wms/sectattr';
|
||||
import { $t } from '#/locales';
|
||||
|
||||
import { useFormSchema } from '../data';
|
||||
|
||||
const emit = defineEmits(['success']);
|
||||
const formData = ref<WmsSectAttrApi.SectAttr>();
|
||||
const getTitle = computed(() => {
|
||||
return formData.value?.sectId
|
||||
? $t('ui.actionTitle.edit', ['库区属性'])
|
||||
: $t('ui.actionTitle.create', ['库区属性']);
|
||||
});
|
||||
|
||||
const [Form, formApi] = useVbenForm({
|
||||
commonConfig: {
|
||||
componentProps: {
|
||||
class: 'w-full',
|
||||
},
|
||||
formItemClass: 'col-span-2',
|
||||
labelWidth: 80,
|
||||
},
|
||||
layout: 'horizontal',
|
||||
schema: useFormSchema(),
|
||||
showDefaultActions: false,
|
||||
});
|
||||
|
||||
const [Modal, modalApi] = useVbenModal({
|
||||
async onConfirm() {
|
||||
const { valid } = await formApi.validate();
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
modalApi.lock();
|
||||
// 提交表单
|
||||
const data = (await formApi.getValues()) as WmsSectAttrApi.SectAttr;
|
||||
try {
|
||||
await (formData.value?.sectId ? updateSectAttr(data) : createSectAttr(data));
|
||||
// 关闭并提示
|
||||
await modalApi.close();
|
||||
emit('success');
|
||||
message.success($t('ui.actionMessage.operationSuccess'));
|
||||
} finally {
|
||||
modalApi.unlock();
|
||||
}
|
||||
},
|
||||
async onOpenChange(isOpen: boolean) {
|
||||
if (!isOpen) {
|
||||
formData.value = undefined;
|
||||
return;
|
||||
}
|
||||
// 加载数据
|
||||
const data = modalApi.getData<WmsSectAttrApi.SectAttr>();
|
||||
if (!data || !data.sectId) {
|
||||
return;
|
||||
}
|
||||
modalApi.lock();
|
||||
try {
|
||||
formData.value = await getSectAttr(data.sectId);
|
||||
// 设置到 values
|
||||
await formApi.setValues(formData.value);
|
||||
} finally {
|
||||
modalApi.unlock();
|
||||
}
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Modal :title="getTitle">
|
||||
<Form class="mx-4" />
|
||||
</Modal>
|
||||
</template>
|
||||
@@ -0,0 +1,401 @@
|
||||
import type { VbenFormSchema } from '#/adapter/form';
|
||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||
import type { WmsStrucAttrApi } from '#/api/wms/structAttr';
|
||||
|
||||
import { ref } from 'vue';
|
||||
|
||||
import { DICT_TYPE } from '@vben/constants';
|
||||
import { getDictOptions } from '@vben/hooks';
|
||||
|
||||
import { getBsrealStorAttrSimpleList } from '#/api/wms/bsrealstorattr';
|
||||
import { getSectAttrSimpleList } from '#/api/wms/sectattr';
|
||||
import { getRangePickerDefaultProps } from '#/utils';
|
||||
|
||||
/** 是/否 选项 */
|
||||
const BOOLEAN_OPTIONS = [
|
||||
{ label: '是', value: '1' },
|
||||
{ label: '否', value: '0' },
|
||||
];
|
||||
const BOOLEAN_TRUE_FALSE_OPTIONS = [
|
||||
{ label: '是', value: true },
|
||||
{ label: '否', value: false },
|
||||
];
|
||||
function boolFormatter({ cellValue }: { cellValue: boolean | string }) {
|
||||
if (cellValue === true || cellValue === 'true' || cellValue === '1') return '是';
|
||||
return '否';
|
||||
}
|
||||
|
||||
// ========== 名称映射表 ==========
|
||||
const warehouseNameMap: Record<string, string> = {};
|
||||
const warehouseCodeMap: Record<string, string> = {};
|
||||
const sectNameMap: Record<string, string> = {};
|
||||
const sectCodeMap: Record<string, string> = {};
|
||||
|
||||
function warehouseFormatter({ cellValue }: { cellValue: string }) {
|
||||
return warehouseNameMap[cellValue] || cellValue;
|
||||
}
|
||||
function sectFormatter({ cellValue }: { cellValue: string }) {
|
||||
return sectNameMap[cellValue] || cellValue;
|
||||
}
|
||||
|
||||
// ========== 仓库-库区级联树 ==========
|
||||
const warehouseSectTree = ref<any[]>([]);
|
||||
|
||||
export async function loadWarehouseSectTree() {
|
||||
if (warehouseSectTree.value.length > 0) return;
|
||||
const warehouses = await getBsrealStorAttrSimpleList();
|
||||
if (!warehouses) return;
|
||||
|
||||
const tree = await Promise.all(
|
||||
warehouses.map(async (w: any) => {
|
||||
warehouseNameMap[w.storId] = w.storName;
|
||||
warehouseCodeMap[w.storId] = w.storCode || '';
|
||||
const sects = await getSectAttrSimpleList(w.storId);
|
||||
return {
|
||||
label: w.storName,
|
||||
value: w.storId,
|
||||
children: (sects || []).map((s: any) => {
|
||||
sectNameMap[s.sectId] = s.sectName;
|
||||
sectCodeMap[s.sectId] = s.sectCode || '';
|
||||
return { label: s.sectName, value: s.sectId };
|
||||
}),
|
||||
};
|
||||
}),
|
||||
);
|
||||
warehouseSectTree.value = tree;
|
||||
}
|
||||
|
||||
/** 导出映射,供 form.vue 使用 */
|
||||
export function getWarehouseCode(id: string) { return warehouseCodeMap[id] || ''; }
|
||||
export function getWarehouseName(id: string) { return warehouseNameMap[id] || ''; }
|
||||
export function getSectCode(id: string) { return sectCodeMap[id] || ''; }
|
||||
export function getSectName(id: string) { return sectNameMap[id] || ''; }
|
||||
|
||||
// 立即预加载
|
||||
loadWarehouseSectTree();
|
||||
|
||||
/** 新增/修改的表单 */
|
||||
export function useFormSchema(): VbenFormSchema[] {
|
||||
return [
|
||||
{
|
||||
fieldName: 'structId',
|
||||
component: 'Input',
|
||||
dependencies: { triggerFields: [''], show: () => false },
|
||||
},
|
||||
{
|
||||
fieldName: 'structCode',
|
||||
label: '仓位编码',
|
||||
rules: 'required',
|
||||
component: 'Input',
|
||||
componentProps: { placeholder: '请输入仓位编码' },
|
||||
},
|
||||
{
|
||||
fieldName: 'structName',
|
||||
label: '仓位名称',
|
||||
rules: 'required',
|
||||
component: 'Input',
|
||||
componentProps: { placeholder: '请输入仓位名称' },
|
||||
},
|
||||
{
|
||||
fieldName: 'simpleName',
|
||||
label: '仓位简称',
|
||||
component: 'Input',
|
||||
componentProps: { placeholder: '请输入仓位简称' },
|
||||
},
|
||||
{
|
||||
fieldName: 'warehouseSect',
|
||||
label: '仓库 / 库区',
|
||||
rules: 'required',
|
||||
component: 'Cascader',
|
||||
componentProps: {
|
||||
options: warehouseSectTree,
|
||||
placeholder: '请选择仓库和库区',
|
||||
allowClear: true,
|
||||
changeOnSelect: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'storType',
|
||||
label: '仓库类型',
|
||||
component: 'Select',
|
||||
componentProps: { options: [], placeholder: '请选择仓库类型' },
|
||||
},
|
||||
{
|
||||
fieldName: 'capacity',
|
||||
label: '容量',
|
||||
component: 'Input',
|
||||
componentProps: { placeholder: '请输入容量' },
|
||||
},
|
||||
{
|
||||
fieldName: 'width',
|
||||
label: '宽度',
|
||||
component: 'Input',
|
||||
componentProps: { placeholder: '请输入宽度' },
|
||||
},
|
||||
{
|
||||
fieldName: 'height',
|
||||
label: '高度',
|
||||
component: 'Input',
|
||||
componentProps: { placeholder: '请输入高度' },
|
||||
},
|
||||
{
|
||||
fieldName: 'zdepth',
|
||||
label: '深度',
|
||||
component: 'Input',
|
||||
componentProps: { placeholder: '请输入深度' },
|
||||
},
|
||||
{
|
||||
fieldName: 'weight',
|
||||
label: '承受重量',
|
||||
component: 'Input',
|
||||
componentProps: { placeholder: '请输入承受重量' },
|
||||
},
|
||||
{
|
||||
fieldName: 'xqty',
|
||||
label: '起始X坐标',
|
||||
component: 'Input',
|
||||
componentProps: { placeholder: '请输入起始X坐标' },
|
||||
},
|
||||
{
|
||||
fieldName: 'yqty',
|
||||
label: '起始Y坐标',
|
||||
component: 'Input',
|
||||
componentProps: { placeholder: '请输入起始Y坐标' },
|
||||
},
|
||||
{
|
||||
fieldName: 'zqty',
|
||||
label: '起始Z坐标',
|
||||
component: 'Input',
|
||||
componentProps: { placeholder: '请输入起始Z坐标' },
|
||||
},
|
||||
{
|
||||
fieldName: 'isTempstruct',
|
||||
label: '是否临时仓位',
|
||||
rules: 'required',
|
||||
component: 'RadioGroup',
|
||||
componentProps: {
|
||||
options: BOOLEAN_OPTIONS,
|
||||
buttonStyle: 'solid',
|
||||
optionType: 'button',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'rowNum',
|
||||
label: '排',
|
||||
component: 'Input',
|
||||
componentProps: { placeholder: '请输入排' },
|
||||
},
|
||||
{
|
||||
fieldName: 'colNum',
|
||||
label: '列',
|
||||
component: 'Input',
|
||||
componentProps: { placeholder: '请输入列' },
|
||||
},
|
||||
{
|
||||
fieldName: 'layerNum',
|
||||
label: '层',
|
||||
component: 'Input',
|
||||
componentProps: { placeholder: '请输入层' },
|
||||
},
|
||||
{
|
||||
fieldName: 'blockNum',
|
||||
label: '块',
|
||||
component: 'Input',
|
||||
componentProps: { placeholder: '请输入块' },
|
||||
},
|
||||
{
|
||||
fieldName: 'placementType',
|
||||
label: '放置类型',
|
||||
component: 'Select',
|
||||
componentProps: { options: [], placeholder: '请选择放置类型' },
|
||||
},
|
||||
{
|
||||
fieldName: 'isUsed',
|
||||
label: '是否启用',
|
||||
rules: 'required',
|
||||
component: 'RadioGroup',
|
||||
componentProps: {
|
||||
options: BOOLEAN_TRUE_FALSE_OPTIONS,
|
||||
buttonStyle: 'solid',
|
||||
optionType: 'button',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'isZdepth',
|
||||
label: '是否判断高度',
|
||||
component: 'RadioGroup',
|
||||
componentProps: {
|
||||
options: BOOLEAN_OPTIONS,
|
||||
buttonStyle: 'solid',
|
||||
optionType: 'button',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'storagevehicleCode',
|
||||
label: '存储载具号',
|
||||
component: 'Input',
|
||||
componentProps: { placeholder: '请输入存储载具号' },
|
||||
},
|
||||
{
|
||||
fieldName: 'storagevehicleType',
|
||||
label: '载具类型',
|
||||
component: 'Select',
|
||||
componentProps: { options: [], placeholder: '请选择载具类型' },
|
||||
},
|
||||
{
|
||||
fieldName: 'storagevehicleQty',
|
||||
label: '载具数量',
|
||||
component: 'Input',
|
||||
componentProps: { placeholder: '请输入载具数量' },
|
||||
},
|
||||
{
|
||||
fieldName: 'lockType',
|
||||
label: '锁定类型',
|
||||
rules: 'required',
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
options: getDictOptions(DICT_TYPE.WMS_LOCK_TYPE, 'string'),
|
||||
placeholder: '请选择锁定类型',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'taskCode',
|
||||
label: '锁定任务编码',
|
||||
component: 'Input',
|
||||
componentProps: { placeholder: '请输入锁定任务编码' },
|
||||
},
|
||||
{
|
||||
fieldName: 'invType',
|
||||
label: '锁定单据类型',
|
||||
component: 'Select',
|
||||
componentProps: { options: [], placeholder: '请选择锁定单据类型' },
|
||||
},
|
||||
{
|
||||
fieldName: 'invId',
|
||||
label: '锁定单据标识',
|
||||
component: 'Input',
|
||||
componentProps: { placeholder: '请输入锁定单据标识' },
|
||||
},
|
||||
{
|
||||
fieldName: 'invCode',
|
||||
label: '锁定单据编码',
|
||||
component: 'Input',
|
||||
componentProps: { placeholder: '请输入锁定单据编码' },
|
||||
},
|
||||
{
|
||||
fieldName: 'extId',
|
||||
label: '外部标识',
|
||||
component: 'Input',
|
||||
componentProps: { placeholder: '请输入外部标识' },
|
||||
},
|
||||
{
|
||||
fieldName: 'remark',
|
||||
label: '备注',
|
||||
component: 'Input',
|
||||
componentProps: { placeholder: '请输入备注' },
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/** 列表的搜索表单 */
|
||||
export function useGridFormSchema(): VbenFormSchema[] {
|
||||
return [
|
||||
{
|
||||
fieldName: 'structCode',
|
||||
label: '仓位编码',
|
||||
component: 'Input',
|
||||
componentProps: { allowClear: true, placeholder: '请输入仓位编码' },
|
||||
},
|
||||
{
|
||||
fieldName: 'structName',
|
||||
label: '仓位名称',
|
||||
component: 'Input',
|
||||
componentProps: { allowClear: true, placeholder: '请输入仓位名称' },
|
||||
},
|
||||
{
|
||||
fieldName: 'warehouseSect',
|
||||
label: '仓库 / 库区',
|
||||
component: 'Cascader',
|
||||
componentProps: {
|
||||
options: warehouseSectTree,
|
||||
placeholder: '请选择仓库和库区',
|
||||
allowClear: true,
|
||||
changeOnSelect: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'createTime',
|
||||
label: '创建时间',
|
||||
component: 'RangePicker',
|
||||
componentProps: { ...getRangePickerDefaultProps(), allowClear: true },
|
||||
},
|
||||
{
|
||||
fieldName: 'isUsed',
|
||||
label: '是否启用',
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
options: BOOLEAN_TRUE_FALSE_OPTIONS,
|
||||
placeholder: '请选择是否启用',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'storagevehicleCode',
|
||||
label: '存储载具号',
|
||||
component: 'Input',
|
||||
componentProps: { allowClear: true, placeholder: '请输入存储载具号' },
|
||||
},
|
||||
{
|
||||
fieldName: 'lockType',
|
||||
label: '锁定类型',
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
options: getDictOptions(DICT_TYPE.WMS_LOCK_TYPE, 'string'),
|
||||
placeholder: '请选择锁定类型',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'taskCode',
|
||||
label: '锁定任务编码',
|
||||
component: 'Input',
|
||||
componentProps: { allowClear: true, placeholder: '请输入锁定任务编码' },
|
||||
},
|
||||
{
|
||||
fieldName: 'invCode',
|
||||
label: '锁定单据编码',
|
||||
component: 'Input',
|
||||
componentProps: { allowClear: true, placeholder: '请输入锁定单据编码' },
|
||||
},
|
||||
{
|
||||
fieldName: 'extId',
|
||||
label: '外部标识',
|
||||
component: 'Input',
|
||||
componentProps: { allowClear: true, placeholder: '请输入外部标识' },
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/** 列表的字段 */
|
||||
export function useGridColumns(): VxeTableGridOptions<WmsStrucAttrApi.StrucAttr>['columns'] {
|
||||
return [
|
||||
{ type: 'checkbox', width: 40 },
|
||||
{ field: 'structId', title: '仓位标识', minWidth: 120 },
|
||||
{ field: 'structCode', title: '仓位编码', minWidth: 120 },
|
||||
{ field: 'structName', title: '仓位名称', minWidth: 120 },
|
||||
{ field: 'simpleName', title: '仓位简称', minWidth: 120 },
|
||||
{ field: 'storId', title: '仓库名称', minWidth: 120, formatter: warehouseFormatter },
|
||||
{ field: 'sectId', title: '库区名称', minWidth: 120, formatter: sectFormatter },
|
||||
{ field: 'height', title: '高度', minWidth: 120 },
|
||||
{ field: 'rowNum', title: '排', minWidth: 120 },
|
||||
{ field: 'colNum', title: '列', minWidth: 120 },
|
||||
{ field: 'layerNum', title: '层', minWidth: 120 },
|
||||
{ field: 'blockNum', title: '块', minWidth: 120 },
|
||||
{ field: 'isTempstruct', title: '是否临时仓位', minWidth: 120, formatter: boolFormatter },
|
||||
{ field: 'isUsed', title: '是否启用', minWidth: 120, formatter: boolFormatter },
|
||||
{ field: 'isZdepth', title: '是否判断高度', minWidth: 120, formatter: boolFormatter },
|
||||
{ field: 'createTime', title: '创建时间', minWidth: 120, formatter: 'formatDateTime' },
|
||||
{ field: 'remark', title: '备注', minWidth: 120 },
|
||||
{ title: '操作', width: 200, fixed: 'right', slots: { default: 'actions' } },
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
<script lang="ts" setup>
|
||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||
import type { WmsStrucAttrApi } from '#/api/wms/structAttr';
|
||||
|
||||
import { ref } from 'vue';
|
||||
|
||||
import { confirm, Page, useVbenModal } from '@vben/common-ui';
|
||||
import { downloadFileFromBlobPart, isEmpty } from '@vben/utils';
|
||||
|
||||
import { message } from 'antdv-next';
|
||||
|
||||
import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||
import {
|
||||
deleteStrucAttr,
|
||||
deleteStrucAttrList,
|
||||
exportStrucAttr,
|
||||
getStrucAttrPage,
|
||||
} from '#/api/wms/structAttr';
|
||||
import { $t } from '#/locales';
|
||||
|
||||
import { useGridColumns, useGridFormSchema } from './data';
|
||||
import Form from './modules/form.vue';
|
||||
|
||||
const [FormModal, formModalApi] = useVbenModal({
|
||||
connectedComponent: Form,
|
||||
destroyOnClose: true,
|
||||
});
|
||||
|
||||
/** 刷新表格 */
|
||||
function handleRefresh() {
|
||||
gridApi.query();
|
||||
}
|
||||
|
||||
/** 创建仓位属性 */
|
||||
function handleCreate() {
|
||||
formModalApi.setData(null).open();
|
||||
}
|
||||
|
||||
/** 编辑仓位属性 */
|
||||
function handleEdit(row: WmsStrucAttrApi.StrucAttr) {
|
||||
formModalApi.setData(row).open();
|
||||
}
|
||||
|
||||
/** 删除仓位属性 */
|
||||
async function handleDelete(row: WmsStrucAttrApi.StrucAttr) {
|
||||
const hideLoading = message.loading({
|
||||
content: $t('ui.actionMessage.deleting', [row.structId]),
|
||||
duration: 0,
|
||||
});
|
||||
try {
|
||||
await deleteStrucAttr(row.structId!);
|
||||
message.success($t('ui.actionMessage.deleteSuccess', [row.structId]));
|
||||
handleRefresh();
|
||||
} finally {
|
||||
hideLoading();
|
||||
}
|
||||
}
|
||||
|
||||
/** 批量删除仓位属性 */
|
||||
async function handleDeleteBatch() {
|
||||
await confirm($t('ui.actionMessage.deleteBatchConfirm'));
|
||||
const hideLoading = message.loading({
|
||||
content: $t('ui.actionMessage.deletingBatch'),
|
||||
duration: 0,
|
||||
});
|
||||
try {
|
||||
await deleteStrucAttrList(checkedIds.value);
|
||||
checkedIds.value = [];
|
||||
message.success($t('ui.actionMessage.deleteSuccess'));
|
||||
handleRefresh();
|
||||
} finally {
|
||||
hideLoading();
|
||||
}
|
||||
}
|
||||
|
||||
const checkedIds = ref<number[]>([]);
|
||||
function handleRowCheckboxChange({
|
||||
records,
|
||||
}: {
|
||||
records: WmsStrucAttrApi.StrucAttr[];
|
||||
}) {
|
||||
checkedIds.value = records.map((item) => item.structId!);
|
||||
}
|
||||
|
||||
/** 导出表格 */
|
||||
async function handleExport() {
|
||||
const data = await exportStrucAttr(await gridApi.formApi.getValues());
|
||||
downloadFileFromBlobPart({ fileName: '仓位属性.xls', source: data });
|
||||
}
|
||||
|
||||
|
||||
const [Grid, gridApi] = useVbenVxeGrid({
|
||||
formOptions: {
|
||||
schema: useGridFormSchema(),
|
||||
},
|
||||
gridOptions: {
|
||||
columns: useGridColumns(),
|
||||
height: 'auto',
|
||||
keepSource: true,
|
||||
proxyConfig: {
|
||||
ajax: {
|
||||
query: async ({ page }, formValues) => {
|
||||
// Cascader 值映射:warehouseSect[0]=storId, warehouseSect[1]=sectId
|
||||
const { warehouseSect, ...rest } = formValues as any;
|
||||
if (warehouseSect?.length >= 1) rest.storId = warehouseSect[0];
|
||||
if (warehouseSect?.length >= 2) rest.sectId = warehouseSect[1];
|
||||
return await getStrucAttrPage({
|
||||
pageNo: page.currentPage,
|
||||
pageSize: page.pageSize,
|
||||
...rest,
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
rowConfig: {
|
||||
keyField: 'structId',
|
||||
isHover: true,
|
||||
},
|
||||
toolbarConfig: {
|
||||
refresh: true,
|
||||
search: true,
|
||||
},
|
||||
} as VxeTableGridOptions<WmsStrucAttrApi.StrucAttr>,
|
||||
gridEvents: {
|
||||
checkboxAll: handleRowCheckboxChange,
|
||||
checkboxChange: handleRowCheckboxChange,
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Page auto-content-height>
|
||||
<FormModal @success="handleRefresh" />
|
||||
<Grid table-title="仓位属性列表">
|
||||
<template #toolbar-tools>
|
||||
<TableAction
|
||||
:actions="[
|
||||
{
|
||||
label: $t('ui.actionTitle.create', ['仓位属性']),
|
||||
type: 'primary',
|
||||
icon: ACTION_ICON.ADD,
|
||||
auth: ['wms:struc-attr:create'],
|
||||
onClick: handleCreate,
|
||||
},
|
||||
{
|
||||
label: $t('ui.actionTitle.export'),
|
||||
type: 'primary',
|
||||
icon: ACTION_ICON.DOWNLOAD,
|
||||
auth: ['wms:struc-attr:export'],
|
||||
onClick: handleExport,
|
||||
},
|
||||
{
|
||||
label: $t('ui.actionTitle.deleteBatch'),
|
||||
type: 'primary',
|
||||
danger: true,
|
||||
icon: ACTION_ICON.DELETE,
|
||||
auth: ['wms:struc-attr:delete'],
|
||||
disabled: isEmpty(checkedIds),
|
||||
onClick: handleDeleteBatch,
|
||||
},
|
||||
]"
|
||||
/>
|
||||
</template>
|
||||
<template #actions="{ row }">
|
||||
<TableAction
|
||||
:actions="[
|
||||
{
|
||||
label: $t('common.edit'),
|
||||
type: 'link',
|
||||
icon: ACTION_ICON.EDIT,
|
||||
auth: ['wms:struc-attr:update'],
|
||||
onClick: handleEdit.bind(null, row),
|
||||
},
|
||||
{
|
||||
label: $t('common.delete'),
|
||||
type: 'link',
|
||||
danger: true,
|
||||
icon: ACTION_ICON.DELETE,
|
||||
auth: ['wms:struc-attr:delete'],
|
||||
popConfirm: {
|
||||
title: $t('ui.actionMessage.deleteConfirm', [row.structId]),
|
||||
confirm: handleDelete.bind(null, row),
|
||||
},
|
||||
},
|
||||
]"
|
||||
/>
|
||||
</template>
|
||||
</Grid>
|
||||
</Page>
|
||||
</template>
|
||||
@@ -0,0 +1,108 @@
|
||||
<script lang="ts" setup>
|
||||
import type { WmsStrucAttrApi } from '#/api/wms/structAttr';
|
||||
|
||||
import { computed, ref } from 'vue';
|
||||
|
||||
import { useVbenModal } from '@vben/common-ui';
|
||||
|
||||
import { message } from 'antdv-next';
|
||||
|
||||
import { useVbenForm } from '#/adapter/form';
|
||||
import { createStrucAttr, getStrucAttr, updateStrucAttr } from '#/api/wms/structAttr';
|
||||
import { $t } from '#/locales';
|
||||
|
||||
import {
|
||||
getSectCode,
|
||||
getSectName,
|
||||
getWarehouseCode,
|
||||
getWarehouseName,
|
||||
loadWarehouseSectTree,
|
||||
useFormSchema,
|
||||
} from '../data';
|
||||
|
||||
const emit = defineEmits(['success']);
|
||||
const formData = ref<WmsStrucAttrApi.StrucAttr>();
|
||||
const getTitle = computed(() => {
|
||||
return formData.value?.structId
|
||||
? $t('ui.actionTitle.edit', ['仓位属性'])
|
||||
: $t('ui.actionTitle.create', ['仓位属性']);
|
||||
});
|
||||
|
||||
const [Form, formApi] = useVbenForm({
|
||||
commonConfig: {
|
||||
componentProps: { class: 'w-full' },
|
||||
formItemClass: 'col-span-2',
|
||||
labelWidth: 80,
|
||||
},
|
||||
layout: 'horizontal',
|
||||
schema: useFormSchema(),
|
||||
showDefaultActions: false,
|
||||
});
|
||||
|
||||
const [Modal, modalApi] = useVbenModal({
|
||||
async onConfirm() {
|
||||
const { valid } = await formApi.validate();
|
||||
if (!valid) return;
|
||||
|
||||
modalApi.lock();
|
||||
const data = (await formApi.getValues()) as WmsStrucAttrApi.StrucAttr & {
|
||||
warehouseSect?: string[];
|
||||
};
|
||||
|
||||
// Cascader 值映射:warehouseSect[0]=storId, warehouseSect[1]=sectId
|
||||
if (data.warehouseSect) {
|
||||
const storId = data.warehouseSect[0];
|
||||
const sectId = data.warehouseSect[1] || '';
|
||||
data.storId = storId;
|
||||
data.sectId = sectId;
|
||||
data.storCode = getWarehouseCode(storId);
|
||||
data.storName = getWarehouseName(storId);
|
||||
data.sectCode = getSectCode(sectId);
|
||||
data.sectName = getSectName(sectId);
|
||||
delete data.warehouseSect;
|
||||
}
|
||||
|
||||
try {
|
||||
await (formData.value?.structId ? updateStrucAttr(data) : createStrucAttr(data));
|
||||
await modalApi.close();
|
||||
emit('success');
|
||||
message.success($t('ui.actionMessage.operationSuccess'));
|
||||
} finally {
|
||||
modalApi.unlock();
|
||||
}
|
||||
},
|
||||
async onOpenChange(isOpen: boolean) {
|
||||
if (!isOpen) {
|
||||
formData.value = undefined;
|
||||
return;
|
||||
}
|
||||
const data = modalApi.getData<WmsStrucAttrApi.StrucAttr>();
|
||||
if (!data || !data.structId) return;
|
||||
|
||||
modalApi.lock();
|
||||
try {
|
||||
// 预加载级联树
|
||||
await loadWarehouseSectTree();
|
||||
|
||||
formData.value = await getStrucAttr(data.structId);
|
||||
|
||||
// 将 storId + sectId 合并为 Cascader 值
|
||||
const cascadeValue = [formData.value.storId];
|
||||
if (formData.value.sectId) {
|
||||
cascadeValue.push(formData.value.sectId);
|
||||
}
|
||||
formData.value = { ...formData.value, warehouseSect: cascadeValue } as any;
|
||||
|
||||
await formApi.setValues(formData.value);
|
||||
} finally {
|
||||
modalApi.unlock();
|
||||
}
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Modal :title="getTitle">
|
||||
<Form class="mx-4" />
|
||||
</Modal>
|
||||
</template>
|
||||
@@ -279,6 +279,7 @@ const WMS_DICT = {
|
||||
WMS_ORDER_STATUS: 'wms_order_status', // WMS 单据状态
|
||||
WMS_RECEIPT_ORDER_TYPE: 'wms_receipt_order_type', // WMS 入库单类型
|
||||
WMS_SHIPMENT_ORDER_TYPE: 'wms_shipment_order_type', // WMS 出库单类型
|
||||
WMS_LOCK_TYPE: 'wms_lock_type', // WMS 锁定类型
|
||||
} as const;
|
||||
|
||||
/** ========== TASK - 任务管理模块 ========== */
|
||||
|
||||
Reference in New Issue
Block a user