25个文件已修改
4个文件已添加
2个文件已删除
2010 ■■■■■ 已修改文件
rsf-admin/src/i18n/zh.js 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/basicInfo/deviceSite/DeviceSiteList.jsx 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/basicInfo/deviceSite/InitModal.jsx 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/basicInfo/loc/LocEdit.jsx 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/locItem/LocItemCreate.jsx 236 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/locItem/LocItemEdit.jsx 282 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/locItem/LocItemList.jsx 266 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/locItem/LocItemPanel.jsx 165 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/locItem/LocListAside.jsx 133 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/locItem/LocQueryList.jsx 214 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/delivery/DeliveryList.jsx 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/stock/OrderItemList.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/task/TaskList.jsx 21 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/work/checkOutBound/CheckOutBoundList.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/work/outBound/OutBoundList.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/work/stockTransfer/stockTransferList.jsx 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/api/service/WcsService.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/WcsServiceImpl.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/api/utils/LocUtils.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/common/constant/Constants.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/CompanysController.java 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/DeliveryController.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/LocItemController.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/TaskController.java 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/params/LocToTaskParams.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/excel/DeliveryTemplate.java 118 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/schedules/TaskSchedules.java 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/LocItemService.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/DeviceSiteServiceImpl.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/LocItemServiceImpl.java 173 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/TaskServiceImpl.java 113 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/i18n/zh.js
@@ -208,7 +208,8 @@
        basContainer: '容器管理',
        outBound: '出库作业',
        checkOutBound: '盘点出库',
        stockTransfer: '库存转移',
        stockTransfer: '库位转移',
    },
    table: {        
        field: {
rsf-admin/src/page/basicInfo/deviceSite/DeviceSiteList.jsx
@@ -136,8 +136,7 @@
                actions={(
                    <TopToolbar>
                        <FilterButton />
                        <InitButton />
                        <MyCreateButton onClick={() => { setCreateDialog(true) }} />
                        <InitButton />
                        <SelectColumnsButton preferenceKey='deviceSite' />
                        <MyExportButton />
                    </TopToolbar>
rsf-admin/src/page/basicInfo/deviceSite/InitModal.jsx
@@ -128,22 +128,29 @@
                                />
                            </Grid>
                            <Grid item xs={4}>
                                <TextInput
                                    label={translate("table.field.deviceSite.deviceSite")}
                                    name="deviceSites"
                                    placeholder={translate('common.action.inputPlaceholder')}
                                    size="small"
                                // type="number"
                            <ReferenceInput
                                source="deviceSites"
                                reference="basStation"
                            >
                                <SelectInput
                                    label="table.field.deviceSite.deviceSite"
                                    optionText="stationName"
                                    optionValue="stationName"
                                />
                            </ReferenceInput>
                            </Grid>
                            <Grid item xs={4}>
                                <TextInput
                                    label={translate("table.field.deviceSite.site")}
                                    name="site"
                                    placeholder={translate('common.action.inputPlaceholder')}
                                    size="small"
                                // type="number"
                            <ReferenceInput
                                source="site"
                                reference="basStation"
                            >
                                <SelectInput
                                    label="table.field.deviceSite.site"
                                    optionText="stationName"
                                    optionValue="stationName"
                                />
                            </ReferenceInput>
                            </Grid>
                            <Grid item xs={4}>
                                <TextInput
rsf-admin/src/page/basicInfo/loc/LocEdit.jsx
@@ -111,24 +111,21 @@
                                    <NumberInput
                                        label="table.field.loc.length"
                                        source="length"
                                        validate={required()}
                                    />
                                    <NumberInput
                                        label="table.field.loc.width"
                                        source="width"
                                        validate={required()}
                                    />
                                    <NumberInput
                                        label="table.field.loc.height"
                                        source="height"
                                        validate={required()}
                                    />
                                </Grid>
                                <Grid item display="flex" gap={1}>
                                    <ReferenceArrayInput source="typeIds" reference="locType" >
                                        <SelectArrayInput label="table.field.loc.type" validate={[required()]} />
                                        <SelectArrayInput label="table.field.loc.type" />
                                    </ReferenceArrayInput>
                                    <TextInput
                                        label="table.field.loc.unit"
rsf-admin/src/page/locItem/LocItemCreate.jsx
File was deleted
rsf-admin/src/page/locItem/LocItemEdit.jsx
@@ -10,6 +10,7 @@
    DateInput,
    SelectInput,
    ReferenceInput,
    SelectArrayInput,
    ReferenceArrayInput,
    AutocompleteInput,
    SaveButton,
@@ -19,6 +20,7 @@
    required,
    useRecordContext,
    DeleteButton,
    useNotify,
} from 'react-admin';
import { useWatch, useFormContext } from "react-hook-form";
import { Stack, Grid, Box, Typography } from '@mui/material';
@@ -28,153 +30,175 @@
import CustomerTopToolBar from "../components/EditTopToolBar";
import MemoInput from "../components/MemoInput";
import StatusSelectInput from "../components/StatusSelectInput";
import request from '@/utils/request';
import DictionarySelect from "../components/DictionarySelect";
import LocQueryList from "./LocQueryList";
const FormToolbar = () => {
    const { getValues } = useFormContext();
    return (
        <Toolbar sx={{ justifyContent: 'end' }}>
            <SaveButton />
            {/* <DeleteButton mutationMode="optimistic" /> */}
        </Toolbar>
    )
}
const LocItemEdit = () => {
    const translate = useTranslate();
    const dicts = JSON.parse(localStorage.getItem('sys_dicts'))?.filter(dict => (dict.dictTypeCode == 'sys_loc_type')) || [];
    const [warehouseId, setWrehouseId] = useState();
    const warehouseChange = (val) => {
        setWrehouseId(val)
    }
    return (
        <Edit
            redirect="list"
            mutationMode={EDIT_MODE}
            actions={<CustomerTopToolBar />}
            aside={<EditBaseAside />}
        >
            <SimpleForm
                shouldUnregister
                warnWhenUnsavedChanges
                toolbar={<FormToolbar />}
                mode="onTouched"
                defaultValues={{}}
            // validate={(values) => { }}
        <>
            <Edit
                redirect="list"
                mutationMode={EDIT_MODE}
                actions={<CustomerTopToolBar />}
                aside={<EditBaseAside />}
                title={"menu.loc"}
            >
                <Grid container width={{ xs: '100%', xl: '100%' }} rowSpacing={3} columnSpacing={3}>
                    <Grid item xs={14} md={10}>
                        <Typography variant="h6" gutterBottom>
                            {translate('common.edit.title.main')}
                        </Typography>
                        <Stack direction='row' gap={2}>
                            <NumberInput
                                label="table.field.locItem.locId"
                                source="locId"
                                autoFocus
                            />
                            <TextInput
                                label="table.field.locItem.locCode"
                                source="locCode"
                                parse={v => v}
                            />
                            <NumberInput
                                label="table.field.locItem.orderId"
                                source="orderId"
                            />
                            <TextInput
                                label="table.field.locItem.type"
                                source="type$"
                                parse={v => v}
                            />
                        </Stack>
                        <Stack direction='row' gap={2}>
                            <NumberInput
                                label="table.field.locItem.orderItemId"
                                source="orderItemId"
                            />
                            <NumberInput
                                label="table.field.locItem.wkType"
                                source="wkType"
                            />
                            <NumberInput
                                label="table.field.locItem.matnrId"
                                source="matnrId"
                            />
                        </Stack>
                        <Stack direction='row' gap={2}>
                            <TextInput
                                label="table.field.locItem.maktx"
                                source="maktx"
                                parse={v => v}
                            />
                <SimpleForm
                    shouldUnregister
                    warnWhenUnsavedChanges
                    toolbar={false}
                    mode="onTouched"
                    defaultValues={{}}
                // validate={(values) => { }}
                >
                    <Grid container width={{ xs: '100%', xl: '90%' }} rowSpacing={3} columnSpacing={3}
                        sx={{
                            "& .MuiFormLabel-root.MuiInputLabel-root.Mui-disabled": {
                                bgcolor: 'white',
                                WebkitTextFillColor: "rgba(0, 0, 0)"
                            },
                            <TextInput
                                label="table.field.locItem.matnrCode"
                                source="matnrCode"
                                parse={v => v}
                            />
                            <TextInput
                                label="table.field.locItem.trackCode"
                                source="trackCode"
                                parse={v => v}
                            />
                            <TextInput
                                label="table.field.locItem.unit"
                                source="unit"
                                parse={v => v}
                            />
                        </Stack>
                        <Stack direction='row' gap={2}>
                            <NumberInput
                                label="table.field.locItem.anfme"
                                source="anfme"
                            />
                            <NumberInput
                                label="table.field.locItem.qty"
                                source="qty"
                            />
                            <NumberInput
                                label="table.field.locItem.workQty"
                                source="workQty"
                            />
                            <TextInput
                                label="table.field.locItem.batch"
                                source="batch"
                                parse={v => v}
                            />
                        </Stack>
                        <Stack direction='row' gap={2}>
                            <TextInput
                                label="table.field.locItem.splrBatch"
                                source="splrBatch"
                                parse={v => v}
                            />
                            <TextInput
                                label="table.field.locItem.spec"
                                source="spec"
                                parse={v => v}
                            />
                            <TextInput
                                label="table.field.locItem.model"
                                source="model"
                                parse={v => v}
                            />
                            <TextInput
                                label="table.field.locItem.fieldsIndex"
                                source="fieldsIndex"
                                parse={v => v}
                            />
                        </Stack>
                            "& .MuiInputBase-input.MuiFilledInput-input.Mui-disabled": {
                                bgcolor: 'white',
                                WebkitTextFillColor: "rgba(0, 0, 0)"
                            },
                            "& .MuiFilledInput-root.MuiInputBase-sizeSmall": {
                                bgcolor: 'white',
                            }
                        }}
                    >
                        <Grid item xs={12} md={10}>
                            <Typography variant="h6" gutterBottom>
                                {translate('common.edit.title.main')}
                            </Typography>
                            <Grid container rowSpacing={2} columnSpacing={2}>
                                <Grid item display="flex" gap={2}>
                                    <ReferenceInput
                                        source="warehouseId"
                                        reference="warehouse"
                                    >
                                        <AutocompleteInput
                                            label="table.field.loc.warehouseId"
                                            optionText="name"
                                            readOnly
                                            validate={[required()]}
                                            onChange={warehouseChange}
                                            filterToQuery={(val) => ({ name: val })}
                                        />
                                    </ReferenceInput>
                                    <ReferenceInput
                                        source="areaId"
                                        reference="warehouseAreas"
                                        filter={{ warehouseId }}
                                    >
                                        <AutocompleteInput
                                            label="table.field.loc.areaId"
                                            optionText="name"
                                            readOnly
                                            validate={[required()]}
                                            filterToQuery={(val) => ({ name: val })}
                                        />
                                    </ReferenceInput>
                                    <TextInput
                                        label="table.field.loc.code"
                                        source="code"
                                        parse={v => v}
                                        readOnly
                                        validate={required()}
                                    />
                                    <NumberInput
                                        label="table.field.loc.length"
                                        source="length"
                                        readOnly
                                        validate={required()}
                                    />
                                    <NumberInput
                                        label="table.field.loc.width"
                                        source="width"
                                        readOnly
                                        validate={required()}
                                    />
                                    <NumberInput
                                        label="table.field.loc.height"
                                        source="height"
                                        readOnly
                                        validate={required()}
                                    />
                                </Grid>
                                <Grid item display="flex" gap={1}>
                                    <ReferenceArrayInput source="typeIds" reference="locType" >
                                        <SelectArrayInput label="table.field.loc.type" readOnly validate={[required()]} />
                                    </ReferenceArrayInput>
                                    <TextInput
                                        label="table.field.loc.unit"
                                        source="unit"
                                        readOnly
                                        parse={v => v}
                                    />
                                    <DictionarySelect
                                        label={translate("table.field.loc.useStatus")}
                                        name="useStatus"
                                        validate={[required()]}
                                        readOnly
                                        size="small"
                                        dictTypeCode="sys_loc_use_stas"
                                    />
                                    <NumberInput
                                        label="table.field.loc.row"
                                        source="row"
                                        readOnly
                                        validate={required()}
                                    />
                                    <NumberInput
                                        label="table.field.loc.col"
                                        source="col"
                                        readOnly
                                        validate={required()}
                                    />
                                    <NumberInput
                                        label="table.field.loc.lev"
                                        source="lev"
                                        readOnly
                                        validate={required()}
                                    />
                                </Grid>
                            </Grid>
                        </Grid>
                        <Grid item xs={12} md={2}>
                            <Typography variant="h6" gutterBottom>
                                {translate('common.edit.title.common')}
                            </Typography>
                            <StatusSelectInput readOnly />
                            <Box mt="2em" />
                            <MemoInput />
                        </Grid>
                    </Grid>
                    <Grid item xs={10} md={2}>
                        <Typography variant="h6" gutterBottom>
                            {translate('common.edit.title.common')}
                        </Typography>
                        <StatusSelectInput />
                        <Box mt="2em" />
                        <MemoInput />
                    </Grid>
                </Grid>
            </SimpleForm>
        </Edit >
                </SimpleForm>
            </Edit >
            <LocQueryList />
        </>
    )
}
rsf-admin/src/page/locItem/LocItemList.jsx
@@ -29,22 +29,18 @@
    NumberInput,
    ReferenceInput,
    ReferenceArrayInput,
    useRefresh,
    AutocompleteInput,
    DeleteButton,
    useRefresh,
    Button,
    useList,
} from 'react-admin';
import { Box, Typography, Card, Stack, LinearProgress } from '@mui/material';
import { Box, Typography, Card, Stack } from '@mui/material';
import { styled } from '@mui/material/styles';
import LocItemCreate from "./LocItemCreate";
import LocItemPanel from "./LocItemPanel";
import EmptyData from "../components/EmptyData";
import MyCreateButton from "../components/MyCreateButton";
import MyExportButton from '../components/MyExportButton';
import PageDrawer from "../components/PageDrawer";
import MyField from "../components/MyField";
import { PAGE_DRAWER_WIDTH, OPERATE_MODE, DEFAULT_PAGE_SIZE } from '@/config/setting';
import * as Common from '@/utils/common';
import request from '@/utils/request';
import LocListAside from "./LocListAside";
const StyledDatagrid = styled(DatagridConfigurable)(({ theme }) => ({
    '& .css-1vooibu-MuiSvgIcon-root': {
@@ -56,49 +52,98 @@
    '& .column-name': {
    },
    '& .opt': {
        width: 100
        width: 180
    },
    '& .type .MuiTypography-root': {
        whiteSpace: 'nowrap',
        overflow: 'hidden',
        textOverflow: 'ellipsis',
        display: 'block',
        width: 'auto',
    },
}));
const filters = [
    <SearchInput source="condition" alwaysOn />,
    <DateInput label='common.time.after' source="timeStart" />,
    <DateInput label='common.time.before' source="timeEnd" />,
    <NumberInput source="locId" label="table.field.locItem.locId" />,
    <TextInput source="locCode" label="table.field.locItem.locCode" />,
    <NumberInput source="orderId" label="table.field.locItem.orderId" />,
    <TextInput source="type" label="table.field.locItem.type" />,
    <NumberInput source="orderItemId" label="table.field.locItem.orderItemId" />,
    <NumberInput source="wkType" label="table.field.locItem.wkType" />,
    <NumberInput source="matnrId" label="table.field.locItem.matnrId" />,
    <TextInput source="maktx" label="table.field.locItem.maktx" />,
    <TextInput source="matnrCode" label="table.field.locItem.matnrCode" />,
    <TextInput source="trackCode" label="table.field.locItem.trackCode" />,
    <TextInput source="unit" label="table.field.locItem.unit" />,
    <NumberInput source="anfme" label="table.field.locItem.anfme" />,
    <NumberInput source="qty" label="table.field.locItem.qty" />,
    <NumberInput source="workQty" label="table.field.locItem.workQty" />,
    <TextInput source="batch" label="table.field.locItem.batch" />,
    <TextInput source="splrBatch" label="table.field.locItem.splrBatch" />,
    <TextInput source="spec" label="table.field.locItem.spec" />,
    <TextInput source="model" label="table.field.locItem.model" />,
    <TextInput source="fieldsIndex" label="table.field.locItem.fieldsIndex" />,
    <TextInput label="common.field.memo" source="memo" />,
    <SelectInput
        label="common.field.status"
        source="status"
        choices={[
            { id: '1', name: 'common.enums.statusTrue' },
            { id: '0', name: 'common.enums.statusFalse' },
        ]}
        resettable
    />,
]
const LocItemList = () => {
    const translate = useTranslate();
    const notify = useNotify();
    const refresh = useRefresh();
    const [createDialog, setCreateDialog] = useState(false);
    const [drawerVal, setDrawerVal] = useState(false);
    const [initDialog, setInitDialog] = useState(false);
    const dicts = JSON.parse(localStorage.getItem('sys_dicts'))?.filter(dict => (dict.dictTypeCode == 'sys_loc_use_stas')) || [];
    const locType = JSON.parse(localStorage.getItem('sys_dicts'))?.filter(dict => (dict.dictTypeCode == 'sys_loc_type')) || [];
    const filters = [
        <SearchInput source="condition" alwaysOn />,
        <ReferenceInput
            source="warehouseId"
            label="table.field.loc.warehouseId"
            reference="warehouse"
        >
            <AutocompleteInput
                label="table.field.loc.warehouseId"
                optionText="name"
                filterToQuery={(val) => ({ name: val })}
            />
        </ReferenceInput>,
        <ReferenceInput
            source="areaId"
            label="table.field.loc.areaId"
            reference="warehouseAreas"
        >
            <AutocompleteInput
                label="table.field.loc.areaId"
                optionText="name"
                filterToQuery={(val) => ({ name: val })}
            />
        </ReferenceInput>,
        <AutocompleteInput
            choices={dicts}
            optionText="label"
            label="table.field.loc.useStatus"
            source="useStatus"
            optionValue="value"
            parse={v => v}
            alwaysOn
        />,
        <TextInput source="code" label="table.field.loc.code" />,
        <AutocompleteInput
            choices={locType}
            optionText="label"
            label="table.field.loc.type"
            source="type"
            optionValue="value"
            parse={v => v}
        />, <TextInput source="name" label="table.field.loc.name" />,
        <NumberInput source="flagLogic" label="table.field.loc.flagLogic" />,
        <TextInput source="fucAtrrs" label="table.field.loc.fucAtrrs" />,
        <TextInput source="barcode" label="table.field.loc.barcode" />,
        <TextInput source="unit" label="table.field.loc.unit" />,
        <TextInput source="size" label="table.field.loc.size" />,
        <NumberInput source="row" label="table.field.loc.row" />,
        <NumberInput source="col" label="table.field.loc.col" />,
        <NumberInput source="lev" label="table.field.loc.lev" />,
        <NumberInput source="channel" label="table.field.loc.channel" />,
        <NumberInput source="maxParts" label="table.field.loc.maxParts" />,
        <NumberInput source="maxPack" label="table.field.loc.maxPack" />,
        <NumberInput source="flagLabelMange" label="table.field.loc.flagLabelMange" />,
        <TextInput source="locAttrs" label="table.field.loc.locAttrs" />,
        <TextInput label="common.field.memo" source="memo" />,
        <SelectInput
            label="common.field.status"
            source="status"
            choices={[
                { id: '1', name: 'common.enums.statusTrue' },
                { id: '0', name: 'common.enums.statusFalse' },
            ]}
            resettable
        />,
    ]
    return (
        <Box display="flex">
@@ -109,8 +154,10 @@
                        theme.transitions.create(['all'], {
                            duration: theme.transitions.duration.enteringScreen,
                        }),
                    marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                }}
                storeKey="locItem"
                resource="loc"
                title={"menu.locItem"}
                empty={false}
                filters={filters}
@@ -118,107 +165,46 @@
                actions={(
                    <TopToolbar>
                        <FilterButton />
                        {/* <MyCreateButton onClick={() => { setCreateDialog(true) }} /> */}
                        <SelectColumnsButton preferenceKey='locItem' />
                        {/* <MyExportButton /> */}
                        <SelectColumnsButton preferenceKey='loc' />
                    </TopToolbar>
                )}
                perPage={DEFAULT_PAGE_SIZE}
                aside={<LocListAside />}
            >
                <DynamicFields />
                <StyledDatagrid
                    preferenceKey='locItem'
                    align="left"
                    bulkActionButtons={false}
                    rowClick={() => false}
                    omit={['id', 'createTime', 'createBy', 'memo', 'updateTime', 'updateBy']}
                >
                    <NumberField source="id" />
                    <NumberField source="warehouseId$" label="table.field.loc.warehouseId" />
                    <NumberField source="areaId$" label="table.field.loc.areaId" />
                    <TextField source="code" label="table.field.loc.code" />
                    <TextField source="typeIds$" label="table.field.loc.type" cellClassName="type" />
                    <TextField source="barcode" label="table.field.loc.barcode" />
                    <TextField source="length" label="table.field.loc.length" />
                    <TextField source="width" label="table.field.loc.width" />
                    <TextField source="height" label="table.field.loc.height" />
                    <NumberField source="row" label="table.field.loc.row" />
                    <NumberField source="col" label="table.field.loc.col" />
                    <NumberField source="lev" label="table.field.loc.lev" />
                    <NumberField source="channel" label="table.field.loc.channel" />
                    <TextField source="useStatus$" label="table.field.loc.useStatus" />
                    <TextField source="updateBy$" label="common.field.updateBy" />
                    <DateField source="updateTime" label="common.field.updateTime" showTime align="left" />
                    <TextField source="createBy$" label="common.field.createBy" />
                    <DateField source="createTime" label="common.field.createTime" showTime align="left" />
                    <BooleanField source="statusBool" label="common.field.status" sortable={false} align="left" />
                    <TextField source="memo" label="common.field.memo" sortable={false} />
                    <WrapperField cellClassName="opt" label="common.field.opt">
                        <EditButton sx={{ padding: '1px', fontSize: '.75rem' }} resource="locItem" label="toolbar.detail" />
                    </WrapperField>
                </StyledDatagrid>
            </List>
            <LocItemCreate
                open={createDialog}
                setOpen={setCreateDialog}
            />
            <PageDrawer
                title='LocItem Detail'
                drawerVal={drawerVal}
                setDrawerVal={setDrawerVal}
            >
            </PageDrawer>
        </Box>
    )
}
export default LocItemList;
const DynamicFields = (props) => {
    const translate = useTranslate();
    const notify = useNotify();
    const [columns, setColumns] = useState([]);
    const { isLoading } = useListContext();
    const refresh = useRefresh();
    useEffect(() => {
        getDynamicFields();
    }, []);
    const getDynamicFields = async () => {
        const { data: { code, data, msg }, } = await request.get("/fields/enable/list");
        if (code == 200) {
            const arr = [
                <NumberField source="id" />,
                <NumberField source="locId" label="table.field.locItem.locId" />,
                <TextField source="wareArea" label="table.field.locItem.wareArea" />,
                <TextField source="locCode" label="table.field.locItem.locCode" />,
                <NumberField source="orderId" label="table.field.locItem.orderId" />,
                <TextField source="type$" label="table.field.locItem.type" />,
                <NumberField source="orderItemId" label="table.field.locItem.orderItemId" />,
                <NumberField source="wkType$" label="table.field.locItem.wkType" />,
                <NumberField source="matnrId" label="table.field.locItem.matnrId" />,
                <TextField source="matnrCode" label="table.field.locItem.matnrCode" />,
                <TextField source="maktx" label="table.field.locItem.maktx" />,
                <TextField source="spec" label="table.field.locItem.spec" />,
                <TextField source="model" label="table.field.locItem.model" />,
                <TextField source="batch" label="table.field.locItem.batch" />,
                <TextField source="trackCode" label="table.field.locItem.trackCode" />,
                <TextField source="unit" label="table.field.locItem.unit" />,
                <NumberField source="anfme" label="table.field.locItem.anfme" />,
                <NumberField source="workQty" label="table.field.locItem.workQty" />,
                <NumberField source="qty" label="table.field.locItem.qty" />,
                <TextField source="splrBatch" label="table.field.locItem.splrBatch" />,
                <TextField source="fieldsIndex" label="table.field.locItem.fieldsIndex" />,
            ]
            const fields = data.map(el => <TextField key={el.fields} source={`extendFields.[${el.fields}]`} label={el.fieldsAlise} />)
            const lastArr = [
                <TextField source="updateBy$" label="common.field.updateBy" />,
                <DateField source="updateTime" label="common.field.updateTime" showTime />,
                <TextField source="createBy$" label="common.field.createBy" />,
                <DateField source="createTime" label="common.field.createTime" showTime />,
                <BooleanField source="statusBool" label="common.field.status" sortable={false} />,
                <TextField source="memo" label="common.field.memo" sortable={false} />,
            ]
            setColumns([...arr, ...fields, ...lastArr]);
        } else {
            notify(msg);
        }
    }
    return (
        <Box sx={{ position: 'relative', minHeight: "60vh", }}>
            {isLoading && (
                <LinearProgress
                    sx={{
                        height: "2px",
                        position: 'absolute',
                        top: 0,
                        left: 0,
                        right: 0,
                    }}
                />
            )}
            {columns.length > 0 &&
                <StyledDatagrid
                    preferenceKey='locItem'
                    bulkActionButtons={false}
                    rowClick={false}
                    expand={false}
                    expandSingle={true}
                    omit={['id', 'createTime','spec', 'model', 'locId', 'orderId', 'trackCode', 'orderItemId', 'matnrId', 'splrBatch','createBy', 'memo', 'fieldsIndex']}
                >
                    {columns.map((column) => column)}
                </StyledDatagrid>}
        </Box>
    )
}
export default LocItemList;
rsf-admin/src/page/locItem/LocItemPanel.jsx
File was deleted
rsf-admin/src/page/locItem/LocListAside.jsx
New file
@@ -0,0 +1,133 @@
import React, { useState, useRef, useEffect, useMemo, useCallback } from "react";
import request from '@/utils/request';
import {
    SavedQueriesList,
    FilterLiveSearch,
    useNotify,
    useListContext,
    SearchInput
} from 'react-admin';
import BookmarkIcon from '@mui/icons-material/BookmarkBorder';
import { Box, Typography, Card, CardContent, useTheme, Input } from '@mui/material';
import { RichTreeView } from "@mui/x-tree-view/RichTreeView";
import { TreeItem2 } from "@mui/x-tree-view/TreeItem2";
import { useTreeViewApiRef } from '@mui/x-tree-view/hooks';
const LocListAside = () => {
    const theme = useTheme();
    const notify = useNotify();
    const { setFilters } = useListContext(); // 获取列表上下文
    const [selectedOption, setSelectedOption] = useState(null);
    const [treeData, setTreeData] = useState([]);
    const [defaultIds, setDefaultIds] = useState([]);
    const [condition, setCondition] = useState('');
    const haveChildren = (item) => {
        if (Array.isArray(item)) {
            return item.map((k) => haveChildren(k));
        }
        if (item && typeof item === 'object') {
            if (item.index !== undefined) {
                item.index = item.index.toString();
            }
            if (item.children && Array.isArray(item.children)) {
                item.children = haveChildren(item.children);
            }
        }
        return item;
    };
    useEffect(() => {
        http()
    }, [condition]);
    const http = () => {
        request.post('/warehouse/areas', { condition })
            .then(res => {
                if (res?.data?.code === 200) {
                    let data = res.data.data;
                    let items = haveChildren(data)
                    setTreeData(items)
                    // setDefaultIds([items.at(0).id])
                } else {
                    notify(res.data.msg);
                }
            })
            .catch(error => {
                notify('Error fetching tree data');
            });
    }
    const handleNodeSelect = (event, nodeId) => {
        const row = apiRef.current.getItem(nodeId);
        if (row.flagWare === 1) {
            setFilters({ warehouseId: row.id, areaId: '' });
        } else if (row.flagWare === 0) {
            setFilters({ areaId: row.id, warehouseId: row.warehouseId });
        }
    };
    const handleSearch = (e) => {
        setCondition(e.target.value)
    };
    const apiRef = useTreeViewApiRef();
    const CustomCheckbox = React.forwardRef(function CustomCheckbox(props, ref) {
        return <input type="checkbox" ref={ref} {...props} />;
    });
    const CustomTreeItem = React.forwardRef(function CustomTreeItem(props, ref) {
        return (
            <TreeItem2
                {...props}
                ref={ref}
                slots={{
                    checkbox: CustomCheckbox,
                }}
            />
        );
    });
    return (
        <Card
            sx={{
                order: -1,
                mr: 2,
                mt: 8,
                alignSelf: 'flex-start',
                border: theme.palette.mode === 'light' && '1px solid #e0e0e3',
                width: 250,
                minWidth: 150,
                height: `100%`,
            }}
        >
            <CardContent>
                {/* <Input
                    placeholder="搜索库位"
                    sx={{ '--Input-focused': 1, marginBottom: '10px' }}
                    onChange={handleSearch}
                /> */}
                <RichTreeView
                    defaultExpandedItems={defaultIds}
                    expansionTrigger="iconContainer"
                    items={treeData}
                    slots={CustomTreeItem}
                    apiRef={apiRef}
                    getItemId={(item) => item.index}
                    getItemLabel={(item) => item.name}
                    onItemClick={handleNodeSelect} // 监听节点点击事件
                />
            </CardContent>
        </Card>
    )
}
export default LocListAside;
rsf-admin/src/page/locItem/LocQueryList.jsx
New file
@@ -0,0 +1,214 @@
import React, { useState, useRef, useEffect, useMemo, useCallback } from "react";
import { useNavigate } from 'react-router-dom';
import {
    List,
    DatagridConfigurable,
    SearchInput,
    TopToolbar,
    SelectColumnsButton,
    EditButton,
    FilterButton,
    CreateButton,
    ExportButton,
    BulkDeleteButton,
    WrapperField,
    useRecordContext,
    useTranslate,
    useNotify,
    useListContext,
    FunctionField,
    TextField,
    NumberField,
    DateField,
    BooleanField,
    ReferenceField,
    TextInput,
    DateTimeInput,
    DateInput,
    SelectInput,
    NumberInput,
    ReferenceInput,
    ReferenceArrayInput,
    useRefresh,
    AutocompleteInput,
    DeleteButton,
    useGetRecordId,
} from 'react-admin';
import { Box, Typography, Card, Stack, LinearProgress } from '@mui/material';
import { styled } from '@mui/material/styles';
import PageDrawer from "../components/PageDrawer";
import { PAGE_DRAWER_WIDTH, OPERATE_MODE, DEFAULT_PAGE_SIZE } from '@/config/setting';
import request from '@/utils/request';
const StyledDatagrid = styled(DatagridConfigurable)(({ theme }) => ({
    '& .css-1vooibu-MuiSvgIcon-root': {
        height: '.9em'
    },
    '& .RaDatagrid-row': {
        cursor: 'auto'
    },
    '& .column-name': {
    },
    '& .opt': {
        width: 100
    },
}));
const filters = [
    <SearchInput source="condition" alwaysOn />,
    <DateInput label='common.time.after' source="timeStart" />,
    <DateInput label='common.time.before' source="timeEnd" />,
    <NumberInput source="locId" label="table.field.locItem.locId" />,
    <TextInput source="locCode" label="table.field.locItem.locCode" />,
    <NumberInput source="orderId" label="table.field.locItem.orderId" />,
    <TextInput source="type" label="table.field.locItem.type" />,
    <NumberInput source="orderItemId" label="table.field.locItem.orderItemId" />,
    <NumberInput source="wkType" label="table.field.locItem.wkType" />,
    <NumberInput source="matnrId" label="table.field.locItem.matnrId" />,
    <TextInput source="maktx" label="table.field.locItem.maktx" />,
    <TextInput source="matnrCode" label="table.field.locItem.matnrCode" />,
    <TextInput source="trackCode" label="table.field.locItem.trackCode" />,
    <TextInput source="unit" label="table.field.locItem.unit" />,
    <NumberInput source="anfme" label="table.field.locItem.anfme" />,
    <NumberInput source="qty" label="table.field.locItem.qty" />,
    <NumberInput source="workQty" label="table.field.locItem.workQty" />,
    <TextInput source="batch" label="table.field.locItem.batch" />,
    <TextInput source="splrBatch" label="table.field.locItem.splrBatch" />,
    <TextInput source="spec" label="table.field.locItem.spec" />,
    <TextInput source="model" label="table.field.locItem.model" />,
    <TextInput source="fieldsIndex" label="table.field.locItem.fieldsIndex" />,
    <TextInput label="common.field.memo" source="memo" />,
    <SelectInput
        label="common.field.status"
        source="status"
        choices={[
            { id: '1', name: 'common.enums.statusTrue' },
            { id: '0', name: 'common.enums.statusFalse' },
        ]}
        resettable
    />,
]
const LocItemList = () => {
    const translate = useTranslate();
    const [createDialog, setCreateDialog] = useState(false);
    const [drawerVal, setDrawerVal] = useState(false);
    const locId = useGetRecordId();
    return (
        <Box display="flex">
            <List
                sx={{
                    flexGrow: 1,
                    transition: (theme) =>
                        theme.transitions.create(['all'], {
                            duration: theme.transitions.duration.enteringScreen,
                        }),
                    marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                }}
                title={"menu.locItem"}
                empty={false}
                filter={{locId: locId}}
                filters={filters}
                sort={{ field: "create_time", order: "desc" }}
                actions={(
                    <TopToolbar>
                        <FilterButton />
                        <SelectColumnsButton preferenceKey='locItem' />
                    </TopToolbar>
                )}
                perPage={DEFAULT_PAGE_SIZE}
            >
                <DynamicFields />
            </List>
            <PageDrawer
                title='LocItem Detail'
                drawerVal={drawerVal}
                setDrawerVal={setDrawerVal}
            >
            </PageDrawer>
        </Box>
    )
}
export default LocItemList;
const DynamicFields = (props) => {
    const translate = useTranslate();
    const notify = useNotify();
    const [columns, setColumns] = useState([]);
    const { isLoading } = useListContext();
    const refresh = useRefresh();
    useEffect(() => {
        getDynamicFields();
    }, []);
    const getDynamicFields = async () => {
        const { data: { code, data, msg }, } = await request.get("/fields/enable/list");
        if (code == 200) {
            const arr = [
                <NumberField source="id" />,
                <NumberField source="locId" label="table.field.locItem.locId" />,
                <TextField source="wareArea" label="table.field.locItem.wareArea" />,
                <TextField source="locCode" label="table.field.locItem.locCode" />,
                <NumberField source="orderId" label="table.field.locItem.orderId" />,
                <TextField source="type$" label="table.field.locItem.type" />,
                <NumberField source="orderItemId" label="table.field.locItem.orderItemId" />,
                <NumberField source="wkType$" label="table.field.locItem.wkType" />,
                <NumberField source="matnrId" label="table.field.locItem.matnrId" />,
                <TextField source="matnrCode" label="table.field.locItem.matnrCode" />,
                <TextField source="maktx" label="table.field.locItem.maktx" />,
                <TextField source="spec" label="table.field.locItem.spec" />,
                <TextField source="model" label="table.field.locItem.model" />,
                <TextField source="batch" label="table.field.locItem.batch" />,
                <TextField source="trackCode" label="table.field.locItem.trackCode" />,
                <TextField source="unit" label="table.field.locItem.unit" />,
                <NumberField source="anfme" label="table.field.locItem.anfme" />,
                <NumberField source="workQty" label="table.field.locItem.workQty" />,
                <NumberField source="qty" label="table.field.locItem.qty" />,
                <TextField source="splrBatch" label="table.field.locItem.splrBatch" />,
                <TextField source="fieldsIndex" label="table.field.locItem.fieldsIndex" />,
            ]
            const fields = data.map(el => <TextField key={el.fields} source={`extendFields.[${el.fields}]`} label={el.fieldsAlise} />)
            const lastArr = [
                <TextField source="updateBy$" label="common.field.updateBy" />,
                <DateField source="updateTime" label="common.field.updateTime" showTime />,
                <TextField source="createBy$" label="common.field.createBy" />,
                <DateField source="createTime" label="common.field.createTime" showTime />,
                <BooleanField source="statusBool" label="common.field.status" sortable={false} />,
                <TextField source="memo" label="common.field.memo" sortable={false} />,
            ]
            setColumns([...arr, ...fields, ...lastArr]);
        } else {
            notify(msg);
        }
    }
    return (
        <Box sx={{ position: 'relative', minHeight: "60vh", }}>
            {isLoading && (
                <LinearProgress
                    sx={{
                        height: "2px",
                        position: 'absolute',
                        top: 0,
                        left: 0,
                        right: 0,
                    }}
                />
            )}
            {columns.length > 0 &&
                <StyledDatagrid
                    preferenceKey='locItem'
                    bulkActionButtons={false}
                    rowClick={false}
                    expand={false}
                    expandSingle={true}
                    omit={['id', 'createTime','spec', 'model', 'locId', 'orderId', 'trackCode', 'orderItemId', 'matnrId', 'splrBatch','createBy', 'memo', 'fieldsIndex']}
                >
                    {columns.map((column) => column)}
                </StyledDatagrid>}
        </Box>
    )
}
rsf-admin/src/page/orders/delivery/DeliveryList.jsx
@@ -39,6 +39,7 @@
import EmptyData from "../../components/EmptyData";
import MyCreateButton from "../../components/MyCreateButton";
import MyExportButton from '../../components/MyExportButton';
import ImportButton from "../../components/ImportButton";
import PageDrawer from "../../components/PageDrawer";
import MyField from "../../components/MyField";
import { PAGE_DRAWER_WIDTH, OPERATE_MODE, DEFAULT_PAGE_SIZE } from '@/config/setting';
@@ -60,8 +61,8 @@
const filters = [
    <SearchInput source="condition" alwaysOn />,
    <DateInput label='common.time.after' source="timeStart"  />,
    <DateInput label='common.time.before' source="timeEnd"  />,
    <DateInput label='common.time.after' source="timeStart" />,
    <DateInput label='common.time.before' source="timeEnd" />,
    <TextInput source="code" label="table.field.delivery.code" />,
    <TextInput source="platId" label="table.field.delivery.platId" />,
    <TextInput source="type" label="table.field.delivery.type" />,
@@ -110,7 +111,8 @@
                        <FilterButton />
                        <MyCreateButton onClick={() => { setCreateDialog(true) }} />
                        <SelectColumnsButton preferenceKey='delivery' />
                        <MyExportButton />
                        <ImportButton value={'delivery'} />
                        {/* <MyExportButton /> */}
                    </TopToolbar>
                )}
                perPage={DEFAULT_PAGE_SIZE}
@@ -121,7 +123,7 @@
                    rowClick={(id, resource, record) => false}
                    expand={false}
                    expandSingle={true}
                    omit={['id', 'createTime', 'createBy','platId', 'memo', 'workQty', 'startTime', 'endTime', 'updateBy','createTime']}
                    omit={['id', 'createTime', 'createBy', 'platId', 'memo', 'workQty', 'startTime', 'endTime', 'updateBy', 'createTime']}
                >
                    <NumberField source="id" />
                    <TextField source="code" label="table.field.delivery.code" />
@@ -135,7 +137,7 @@
                    <TextField source="platCode" label="table.field.delivery.platCode" />
                    <DateField source="startTime" label="table.field.delivery.startTime" showTime />
                    <DateField source="endTime" label="table.field.delivery.endTime" showTime />
                    <TextField source="updateBy$" label="common.field.updateBy"  />
                    <TextField source="updateBy$" label="common.field.updateBy" />
                    <DateField source="updateTime" label="common.field.updateTime" showTime />
                    <TextField source="createBy$" label="common.field.createBy" />
                    <DateField source="createTime" label="common.field.createTime" showTime />
rsf-admin/src/page/orders/stock/OrderItemList.jsx
@@ -68,8 +68,6 @@
    <TextInput source="matnrId" label="table.field.stockItem.matnrId" />,
    <TextInput source="matnrCode" label="table.field.stockItem.matnrCode" />,
    <TextInput source="maktx" label="table.field.stockItem.maktx" />,
    <TextInput source="locCode" label="table.field.loc.code" />,
    <TextInput source="barcode" label="table.field.task.barcode" />,
    <NumberInput source="anfme" label="table.field.stockItem.anfme" />,
    <TextInput source="stockUnit" label="table.field.stockItem.stockUnit" />,
    <NumberInput source="workQty" label="table.field.stockItem.workQty" />,
rsf-admin/src/page/task/TaskList.jsx
@@ -63,8 +63,17 @@
const TaskList = (props) => {
    const translate = useTranslate();
    const refresh = useRefresh();
    const [drawerVal, setDrawerVal] = useState(false);
    const dict = JSON.parse(localStorage.getItem('sys_dicts'))?.filter(dict => (dict.dictTypeCode == 'sys_warehouse_type')) || [];
    // useEffect(() => {
    //     const interval = setInterval(() => {
    //         refresh();
    //     }, 5000); // 每5秒刷新一次
    //     return () => clearInterval(interval); // 清除定时器
    // }, [refresh])
    const filters = [
        <SearchInput source="condition" alwaysOn />,
@@ -103,6 +112,7 @@
    return (
        <Box display="flex">
            <List
                queryOptions={{ refetchInterval: 5000 }}
                sx={{
                    flexGrow: 1,
                    transition: (theme) =>
@@ -179,7 +189,10 @@
export default TaskList;
/**
 * 盘点
 * @returns te
 */
const CheckButton = () => {
    const record = useRecordContext();
    const notify = useNotify();
@@ -195,7 +208,7 @@
        }
    }
    return (record?.taskStatus == 198 && record?.taskType == 107 ? <ConfirmButton label={"toolbar.check"} startIcon={<GradingOutlinedIcon />} onConfirm={checkClick} /> : <></>)
    return (record?.taskStatus == 199 && record?.taskType == 107 ? <ConfirmButton label={"toolbar.check"} startIcon={<GradingOutlinedIcon />} onConfirm={checkClick} /> : <></>)
}
/**
@@ -245,7 +258,7 @@
        }
    }
    return (
        ((record?.taskStatus < 98) || (record?.taskType >= 101 && record?.taskStatus < 199)) ? (<ConfirmButton label={"toolbar.complete"} color="secondary" startIcon={<TaskAltIcon />} onConfirm={clickComplete} />) : (<></>)
        ((record?.taskStatus < 98) || (record?.taskType >= 101 && record?.taskStatus < 198)) ? (<ConfirmButton label={"toolbar.complete"} color="secondary" startIcon={<TaskAltIcon />} onConfirm={clickComplete} />) : (<></>)
    )
}
@@ -273,7 +286,7 @@
        }
    }
    return (
        record.taskStatus === 1 ?
        (record.taskStatus == 1 || record.taskStatus == 101) && (record.taskType == 1 || record.taskType == 101 || record.taskType == 10 || record.taskType == 104) ?
            <Button
                onClick={clickCancel}
                label="toolbar.cancel">
rsf-admin/src/page/work/checkOutBound/CheckOutBoundList.jsx
@@ -182,7 +182,7 @@
        http(sta, data);
    }
    const http = async (sta, items) => {
        const { data: { code, data, msg } } = await request.post(`/locItem/generate/task`, { siteNo: sta, items: items, type: 'check' });
        const { data: { code, data, msg } } = await request.post(`/locItem/check/task`, { siteNo: sta, items: items });
        if (code === 200) {
            notify(msg);
            refresh()
rsf-admin/src/page/work/outBound/OutBoundList.jsx
@@ -189,7 +189,7 @@
            notify(translate('toolbar.request.error.out_stock_qty'))
            return
        }
        const { data: { code, data, msg } } = await request.post(`/locItem/check/task`, { siteNo: sta, items: items });
        const { data: { code, data, msg } } = await request.post(`/locItem/generate/task`, { siteNo: sta, items: items });
        if (code === 200) {
            notify(msg);
            refresh()
rsf-admin/src/page/work/stockTransfer/stockTransferList.jsx
@@ -221,10 +221,10 @@
            notify("请输入源库位");
            return;
        }
        if (tarLoc === "" || tarLoc === undefined || tarLoc === null) {
            notify("请输入目标库位");
            return;
        }
        // if (tarLoc === "" || tarLoc === undefined || tarLoc === null) {
        //     notify("请输入目标库位");
        //     return;
        // }
        if (tabelData.length === 0) {
            notify("源库位明细无,请检查库位状态");
            return;
rsf-server/src/main/java/com/vincent/rsf/server/api/service/WcsService.java
@@ -8,5 +8,5 @@
    void agvTaskPickUpComplete(TaskInParam param);
    InTaskMsgDto getLocNo(TaskInParam param);
    InTaskMsgDto getLocNo(TaskInParam param) throws Exception;
}
rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/WcsServiceImpl.java
@@ -95,7 +95,12 @@
        String ruleCode = generateTaskCode();
        // 获取库位号
        InTaskMsgDto locNo = getLocNo(param);
        InTaskMsgDto locNo = null;
        try {
            locNo = getLocNo(param);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        // 创建并保存任务
        Task task = createTask(ruleCode, locNo.getLocNo(), waitPakin.getBarcode(),
@@ -329,7 +334,7 @@
//        return locNo;
//    }
    @Override
    public InTaskMsgDto getLocNo(TaskInParam param) {
    public InTaskMsgDto getLocNo(TaskInParam param) throws Exception{
        String matnr = null;
        String batch = null;
        List<WaitPakin> waitPakins = waitPakinService.list(new LambdaQueryWrapper<WaitPakin>().eq(WaitPakin::getBarcode, param.getBarcode()));
@@ -380,7 +385,7 @@
            batch = "";
        }
        // 初始化参数
        int deviceNo = 0;      //堆垛机号
        int channel = 0;      //堆垛机号
        int nearRow = 0;    //最浅库位排
        int curRow = 0;     //最深库位排
        int rowCount = 0;   //轮询轮次
@@ -400,7 +405,7 @@
        for (int i = times; i <= deviceQty * 2; i++) {
            int[] locNecessaryParameters = LocUtils.LocNecessaryParameters(deviceBind, curRow, deviceQty);
            curRow = locNecessaryParameters[1];
            deviceNo = locNecessaryParameters[2];
            channel = locNecessaryParameters[2];
            rowCount = locNecessaryParameters[0];
            nearRow = locNecessaryParameters[3];
            break;
@@ -423,7 +428,7 @@
                    if (shallowLoc != null && shallowLoc.getUseStatus().equals(LocStsType.LOC_STS_TYPE_O.type)) {
                        if (LocUtils.locMoveCheckLocTypeComplete(shallowLoc, locTypeDto)) {
                            loc = shallowLoc;
                            deviceNo = shallowLoc.getDeviceNo();
                            channel = shallowLoc.getChannel();
                            break;
                        }
@@ -460,10 +465,10 @@
        DeviceSite deviceSite = deviceSiteService.getOne(new LambdaQueryWrapper<DeviceSite>()
                .eq(DeviceSite::getType, ioType)
                .eq(DeviceSite::getSite, sourceStaNo)
                .eq(DeviceSite::getDeviceCode, deviceNo)
                .eq(DeviceSite::getChannel, channel)
        );
        if (Cools.isEmpty(deviceSite)) {
            deviceNo = 0;
            channel = 0;
        } else {
            inTaskMsgDto.setStaNo(Integer.parseInt(deviceSite.getDeviceSite()));
        }
@@ -475,7 +480,7 @@
        // 开始查找库位 ==============================>>
        // 1.按规则查找库位
        if (Cools.isEmpty(loc) && deviceNo != 0) {
        if (Cools.isEmpty(loc) && channel != 0) {
            List<Loc> locMasts = null;
            locMasts = locService.list(new LambdaQueryWrapper<Loc>()
                    .eq(Loc::getRow, nearRow)
@@ -562,7 +567,7 @@
        //查询当前库位类型空库位 小于5个则locmast = null
        List<Loc> locTypeLocMasts = locService.list(new LambdaQueryWrapper<Loc>()
                .eq(Loc::getUseStatus, LocStsType.LOC_STS_TYPE_O.type)
                .eq(Loc::getChannel, deviceNo)
                .eq(Loc::getChannel, channel)
                .eq(Loc::getType, locTypeDto.getLocType1())
                .eq(Loc::getAreaId, area)
        );
@@ -588,7 +593,7 @@
        String locNo = loc.getCode();
        // 返回dto
        inTaskMsgDto.setDeviceNo(deviceNo);
        inTaskMsgDto.setDeviceNo(channel);
        inTaskMsgDto.setSourceStaNo(sourceStaNo);
//        inTaskMsgDto.setStaNo();
        inTaskMsgDto.setLocNo(locNo);
rsf-server/src/main/java/com/vincent/rsf/server/api/utils/LocUtils.java
@@ -5,13 +5,19 @@
import com.vincent.rsf.framework.common.Cools;
import com.vincent.rsf.framework.common.SpringUtils;
import com.vincent.rsf.framework.exception.CoolException;
import com.vincent.rsf.server.api.controller.params.TaskInParam;
import com.vincent.rsf.server.api.entity.dto.InTaskMsgDto;
import com.vincent.rsf.server.api.entity.dto.LocTypeDto;
import com.vincent.rsf.server.manager.entity.DeviceBind;
import com.vincent.rsf.server.manager.entity.Loc;
import com.vincent.rsf.server.manager.service.DeviceBindService;
import com.vincent.rsf.server.manager.service.LocService;
import com.vincent.rsf.server.manager.entity.*;
import com.vincent.rsf.server.manager.enums.LocStsType;
import com.vincent.rsf.server.manager.enums.TaskType;
import com.vincent.rsf.server.manager.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.RegEx;
import javax.annotation.Resource;
import java.util.List;
public class LocUtils {
@@ -49,7 +55,12 @@
    public static String getShallowLoc(SlaveProperties slaveProperties, String deepLoc) {
        LocService locService = SpringUtils.getBean(LocService.class);
        Loc depLoc = locService.getOne(new LambdaQueryWrapper<Loc>().eq(Loc::getCode, deepLoc));
        int row = depLoc.getRow()-1;
        int row;
        if (depLoc.getRow() != 1) {
            row = depLoc.getRow()-1;
        } else {
            row = depLoc.getRow();
        }
        boolean contains = slaveProperties.getDoubleLocs().contains(row);
        Loc shallowLoc = null;
        if (!contains) {
@@ -99,10 +110,7 @@
    //库位排号分配
    public static int[] LocNecessaryParameters(DeviceBind deviceBind, Integer curRow, Integer crnNumber) {
      return LocNecessaryParametersDoubleExtension(curRow, crnNumber); //已完善
    }
    //经典双伸库位
rsf-server/src/main/java/com/vincent/rsf/server/common/constant/Constants.java
@@ -90,4 +90,19 @@
     */
    public static final String TOKEN_TYPE = "Bearer";
    /**
     * 库存出库
     */
    public static final String TASK_TYPE_OUT_STOCK = "outStock";
    /**
     * 库存盘点出库
     */
    public static final String TASK_TYPE_OUT_CHECK = "check";
    /**
     * 拣料出库
     */
    public static final String TASK_TYPE_OUT_PICK = "pick";
}
rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/CompanysController.java
@@ -105,7 +105,6 @@
    @OperationLog("Update 字典数据集")
    @PostMapping("/companys/update")
    public R update(@RequestBody Companys companys) {
        companys.setUpdateBy(getLoginUserId());
        if (Objects.isNull(companys.getName())) {
            throw new CoolException("名称不能为空!!");
        }
@@ -115,21 +114,8 @@
        if (Objects.isNull(companys.getType())) {
            throw new CoolException("类型不能为空!!");
        }
//        Companys companys1 = companysService.getById(companys.getId());
        List<Companys> warehouses = companysService.list(new LambdaQueryWrapper<Companys>()
                .eq(Companys::getName, companys.getName())
                .eq(Companys::getType, companys.getType())
                .eq(Companys::getBreifCode, companys.getBreifCode()));
        if (!warehouses.isEmpty()) {
            throw new CoolException("企业已存在!!");
        }
        if (!companysService.list(new LambdaQueryWrapper<Companys>()
                .eq(Companys::getType, companys.getType())
                .eq(Companys::getName, companys.getName())
                .eq(Companys::getCode, companys.getBreifCode())).isEmpty()) {
            throw new CoolException("企业编码重复!!");
        }
        companys.setUpdateTime(null);
        companys.setUpdateBy(getLoginUserId());
        if (!companysService.updateById(companys)) {
            return R.error("Update Fail");
        }
rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/DeliveryController.java
@@ -124,4 +124,4 @@
        ExcelUtil.build(ExcelUtil.create(deliveryService.list(), Delivery.class), response);
    }
}
}
rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/LocItemController.java
@@ -5,14 +5,17 @@
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.vincent.rsf.framework.common.Cools;
import com.vincent.rsf.framework.common.R;
import com.vincent.rsf.server.common.constant.Constants;
import com.vincent.rsf.server.common.utils.ExcelUtil;
import com.vincent.rsf.server.common.annotation.OperationLog;
import com.vincent.rsf.server.common.domain.BaseParam;
import com.vincent.rsf.server.common.domain.KeyValVo;
import com.vincent.rsf.server.common.domain.PageParam;
import com.vincent.rsf.server.common.utils.FieldsUtils;
import com.vincent.rsf.server.manager.controller.params.LocToTaskParams;
import com.vincent.rsf.server.manager.entity.LocItem;
import com.vincent.rsf.server.manager.service.LocItemService;
import com.vincent.rsf.server.manager.service.LocService;
import com.vincent.rsf.server.system.controller.BaseController;
import com.vincent.rsf.server.manager.enums.LocStsType;
import io.swagger.annotations.ApiOperation;
@@ -28,6 +31,8 @@
    @Autowired
    private LocItemService locItemService;
    @Autowired
    private LocService locService;
    @PreAuthorize("hasAuthority('manager:locItem:list')")
    @PostMapping("/locItem/page")
@@ -79,17 +84,19 @@
    /**
     * 生成库存出库任务
     * @param map
     * @param param
     * @return
     */
    @PreAuthorize("hasAuthority('manager:locItem:list')")
    @ApiOperation("生成库存出库任务")
    @PostMapping("/locItem/generate/task")
    public R generateTask(@RequestBody Map<String, Object> map) {
        if (Objects.isNull(map)) {
    public R generateTask(@RequestBody LocToTaskParams param) {
        if (Objects.isNull(param)) {
            return R.error("参数不能为空!!");
        }
        return locItemService.generateTask(map);
        param.setType(Constants.TASK_TYPE_OUT_STOCK);
        return locItemService.generateTask(param);
    }
    /**
@@ -100,11 +107,11 @@
    @PreAuthorize("hasAuthority('manager:locItem:list')")
    @ApiOperation("生成移库任务")
    @PostMapping("/locItem/move/task")
    public R genMoveTask(@RequestBody Map<String, Object> map) {
    public R genMoveTask(@RequestBody LocToTaskParams map) {
        if (Objects.isNull(map)) {
            return R.error("参数不能为空!!");
        }
        return locItemService.genMoveTask(map);
        return R.ok("任务生成成功").add(locItemService.genMoveTask(map));
    }
    /**
@@ -115,11 +122,12 @@
    @PreAuthorize("hasAuthority('manager:locItem:list')")
    @ApiOperation("生成盘点出库任务")
    @PostMapping("/locItem/check/task")
    public R genStatisticalTask(@RequestBody Map<String, Object> map) {
    public R genStatisticalTask(@RequestBody LocToTaskParams map) {
        if (Objects.isNull(map)) {
            return R.error("参数不能为空!!");
        }
        return locItemService.generateTask(map);
        map.setType(Constants.TASK_TYPE_OUT_CHECK);
        return R.ok("任务生成成功").add(locItemService.generateTask(map));
    }
@@ -138,7 +146,7 @@
    @PreAuthorize("hasAuthority('manager:locItem:list')")
    @GetMapping("/locItem/{id}")
    public R get(@PathVariable("id") Long id) {
        return R.ok().add(locItemService.getById(id));
        return R.ok().add(locService.getById(id));
    }
    @PreAuthorize("hasAuthority('manager:locItem:save')")
rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/TaskController.java
@@ -6,6 +6,7 @@
import com.vincent.rsf.framework.common.Cools;
import com.vincent.rsf.framework.common.R;
import com.vincent.rsf.framework.exception.CoolException;
import com.vincent.rsf.server.common.constant.Constants;
import com.vincent.rsf.server.manager.entity.*;
import com.vincent.rsf.server.manager.enums.*;
import com.vincent.rsf.server.common.utils.ExcelUtil;
@@ -17,6 +18,7 @@
import com.vincent.rsf.server.system.controller.BaseController;
import com.vincent.rsf.server.system.service.impl.ConfigServiceImpl;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.transaction.annotation.Transactional;
@@ -137,8 +139,15 @@
                .in(Task::getTaskStatus, longs));
        for (Task task : tasks) {
            if (StringUtils.isNotBlank(task.getParentId() + "")) {
                Task task1 = taskService.getById(task.getParentId());
                if (!Objects.isNull(task1)) {
                    throw new CoolException("父任务:" + task1.getTaskCode() + "未执行完成!");
                }
            }
            task.setTaskStatus(task.getTaskType() < 100 ? TaskStsType.COMPLETE_IN.id : TaskStsType.COMPLETE_OUT.id);
        }
        if (!taskService.updateBatchById(tasks)) {
            return R.error("完成任务失败");
        }
@@ -158,7 +167,7 @@
            throw new CoolException("能数不能为空!!");
        }
        try {
            return R.ok(taskService.pickOrCheckTask(id, "pick"));
            return R.ok("出库完成").add(taskService.pickOrCheckTask(id, Constants.TASK_TYPE_OUT_PICK));
        } catch (Exception e) {
            throw new CoolException(e.getMessage());
        }
@@ -177,7 +186,7 @@
            throw new CoolException("能数不能为空!!");
        }
        try {
            return R.ok(taskService.pickOrCheckTask(id, "check"));
            return R.ok(taskService.pickOrCheckTask(id, Constants.TASK_TYPE_OUT_CHECK));
        } catch (Exception e) {
            throw new CoolException(e.getMessage());
        }
rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/params/LocToTaskParams.java
New file
@@ -0,0 +1,32 @@
package com.vincent.rsf.server.manager.controller.params;
import com.vincent.rsf.server.manager.entity.LocItem;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.List;
@Data
@Accessors(chain = true)
@ApiModel(value = "LocToTaskParams", description = "库存出库参数")
public class LocToTaskParams {
    @ApiModelProperty("类型: check:盘点出库, outStock: 库存出库")
    private String type;
    @ApiModelProperty("目标站点")
    private String siteNo;
    @ApiModelProperty("库位明细列表")
    private List<LocItem> items;
    @ApiModelProperty("源库位")
    private String orgLoc;
    @ApiModelProperty("目标库位")
    private String tarLoc;
}
rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/excel/DeliveryTemplate.java
New file
@@ -0,0 +1,118 @@
package com.vincent.rsf.server.manager.entity.excel;
import cn.afterturn.easypoi.excel.annotation.Excel;
import com.vincent.rsf.server.manager.entity.excel.annotation.ExcelAutoColumnSize;
import com.vincent.rsf.server.manager.entity.excel.annotation.ExcelComment;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
@Data
@ExcelAutoColumnSize
@Accessors(chain = true)
public class DeliveryTemplate implements Serializable {
    private static final long serialVersionUID = 1L;
    @Excel(name = "*DO单号")
    @ApiModelProperty(value= "*PO单号")
    @ExcelComment(value = "poCode", example = "PO25413975")
    private String poCode;
    @Excel(name = "*行号")
    @ApiModelProperty(value= "*行号")
    @ExcelComment(value = "platItemId", example = "100068541001")
    private String platItemId;
    @Excel(name = "单据类型")
    @ApiModelProperty(value= "单据类型")
    @ExcelComment(value = "type", example = "入库单")
    private String type;
    @Excel(name = "单据来源")
    @ApiModelProperty(value= "单据来源")
    @ExcelComment(value = "source", example = "ERP同步")
    private String source;
    @Excel(name = "客单号")
    @ApiModelProperty(value= "客单号")
    @ExcelComment(value = "platOrderCode", example = "2052146822")
    private String platOrderCode;
    @Excel(name = "工单号")
    @ApiModelProperty(value= "工单号")
    @ExcelComment(value = "platWorkCode", example = "64875413")
    private String platWorkCode;
    @Excel(name = "项目号")
    @ApiModelProperty(value= "项目号")
    @ExcelComment(value = "projectCode", example = "65413")
    private String projectCode;
    @Excel(name = "业务类型")
    @ApiModelProperty(value= "业务类型")
    @ExcelComment(value = "wkType", example = "采购入库单")
    private String wkType;
    @Excel(name = "项目名称")
    @ApiModelProperty(value= "项目名称")
    @ExcelComment(value = "project", example = "京东电商立库")
    private String project;
    /**
     * 物料编码
     */
    @Excel(name = "*物料编码")
    @ApiModelProperty(value= "*物料编码")
    @ExcelComment(value = "matnrCode", example = "101000000002")
    private String matnrCode;
    /**
     *
     */
    @Excel(name = "物料名称")
    @ApiModelProperty(value= "物料名称")
    @ExcelComment(value = "matnrName", example = "TC-03128寸连体内上托")
    private String matnrName;
    /**
     * 数量
     */
    @Excel(name = "数量")
    @ApiModelProperty(value= "数量")
    @ExcelComment(value = "anfme", example = "75")
    private Double anfme;
    /**
     * 供应商编码
     */
    @Excel(name = "*供应商编码")
    @ApiModelProperty(value= "*供应商编码")
    @ExcelComment(value = "splrCode", example = "685947")
    private String splrCode;
    /**
     * 供应商批次
     */
    @Excel(name = "供应商批次")
    @ApiModelProperty(value= "供应商批次")
    @ExcelComment(value = "splrBatch", example = "20250401")
    private String splrBatch;
    @Excel(name = "预计送达时间")
    @ApiModelProperty("预计送达时间")
    @ExcelComment(value = "arrTime", example = "2025-05-21")
    private String arrTime;
    @Excel(name = "备注")
    @ApiModelProperty("备注")
    @ExcelComment(value = "memo", example = "注:易碎品,轻拿放")
    private String memo;
}
rsf-server/src/main/java/com/vincent/rsf/server/manager/schedules/TaskSchedules.java
@@ -58,7 +58,6 @@
     * @time 2025/4/2 12:37
     */
    @Scheduled(cron = "0/3 * * * * ?")
//    @Transactional(rollbackFor = Exception.class)
    public void completeInStock() throws Exception {
        List<Task> tasks = taskService.list(new LambdaQueryWrapper<Task>().eq(Task::getTaskStatus, TaskStsType.COMPLETE_IN.id));
        if (tasks.isEmpty()) {
@@ -73,8 +72,7 @@
     * @description: 完成出库任务,更新库存
     * @version 1.0
     */
    @Scheduled(cron = "0/30 * * * * ?  ")
    @Transactional(rollbackFor = Exception.class)
    @Scheduled(cron = "0/5 * * * * ?  ")
    public void complateOutStock() throws Exception {
        List<Task> tasks = taskService.list(new LambdaQueryWrapper<Task>().eq(Task::getTaskStatus, TaskStsType.COMPLETE_OUT.id));
        if (tasks.isEmpty()) {
@@ -90,7 +88,7 @@
     * @description 已完成任务加入历史档
     * @time 2025/4/3 12:54
     */
    @Scheduled(cron = "0 0/05 * * * ?  ")
    @Scheduled(cron = "0 0/01 * * * ?  ")
    @Transactional(rollbackFor = Exception.class)
    public void taskLogUpdate() {
        LambdaQueryWrapper<Task> queryWrapper = new LambdaQueryWrapper<Task>();
@@ -109,14 +107,6 @@
            return;
        }
        List<Long> list = tasks.stream().map(Task::getId).collect(Collectors.toList());
        List<TaskItem> taskItems = taskItemService.list(new LambdaQueryWrapper<TaskItem>().in(TaskItem::getTaskId, list));
        if (taskItems.isEmpty()) {
            return;
        }
        Map<Long, List<TaskItem>> listMap = taskItems.stream().collect(Collectors.groupingBy(TaskItem::getTaskId));
        tasks.forEach(task -> {
            TaskLog taskLog = new TaskLog();
            BeanUtils.copyProperties(task, taskLog);
@@ -125,9 +115,9 @@
            if (!taskLogService.save(taskLog)) {
                throw new CoolException("任务历史档保存失败!!");
            }
            List<TaskItem> taskItems = taskItemService.list(new LambdaQueryWrapper<TaskItem>().eq(TaskItem::getTaskId, task.getId()));
            List<TaskItemLog> itemLogs = new ArrayList<>();
            for (TaskItem item : listMap.get(task.getId())) {
            for (TaskItem item : taskItems) {
                TaskItemLog itemLog = new TaskItemLog();
                BeanUtils.copyProperties(item, itemLog);
                itemLog.setId(null)
@@ -137,19 +127,19 @@
                itemLogs.add(itemLog);
            }
            if (!taskItemLogService.saveBatch(itemLogs)) {
                throw new CoolException("任务明细历史档保存失败!!");
            if (!taskService.removeById(task.getId())) {
                throw new CoolException("原始任务删除失败!!");
            }
            if (!taskItems.isEmpty()) {
                if (!taskItemLogService.saveBatch(itemLogs)) {
                    throw new CoolException("任务明细历史档保存失败!!");
                }
                if (!taskItemService.remove(new LambdaQueryWrapper<TaskItem>().eq(TaskItem::getTaskId, task.getId()))) {
                    throw new CoolException("原始任务明细删除失败!!");
                }
            }
        });
        if (!taskService.removeByIds(list)) {
            throw new CoolException("原始任务删除失败!!");
        }
        List<Long> itemIds = taskItems.stream().map(TaskItem::getId).collect(Collectors.toList());
        if (!taskItemService.removeByIds(itemIds)) {
            throw new CoolException("原始任务明细删除失败!!");
        }
    }
}
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/LocItemService.java
@@ -2,14 +2,16 @@
import com.baomidou.mybatisplus.extension.service.IService;
import com.vincent.rsf.framework.common.R;
import com.vincent.rsf.server.manager.controller.params.LocToTaskParams;
import com.vincent.rsf.server.manager.entity.LocItem;
import com.vincent.rsf.server.manager.entity.Task;
import java.util.Map;
public interface LocItemService extends IService<LocItem> {
    R generateTask(Map<String, Object> map);
    R generateTask(LocToTaskParams map);
    R genMoveTask(Map<String, Object> map);
    Task genMoveTask(LocToTaskParams map);
}
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/DeviceSiteServiceImpl.java
@@ -4,11 +4,15 @@
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.vincent.rsf.framework.exception.CoolException;
import com.vincent.rsf.server.manager.controller.params.DeviceSiteParame;
import com.vincent.rsf.server.manager.entity.BasDevice;
import com.vincent.rsf.server.manager.entity.BasStation;
import com.vincent.rsf.server.manager.mapper.DeviceSiteMapper;
import com.vincent.rsf.server.manager.entity.DeviceSite;
import com.vincent.rsf.server.manager.service.BasStationService;
import com.vincent.rsf.server.manager.service.DeviceSiteService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
@@ -18,6 +22,10 @@
@Service("deviceSiteService")
public class DeviceSiteServiceImpl extends ServiceImpl<DeviceSiteMapper, DeviceSite> implements DeviceSiteService {
    @Autowired
    private BasStationService basStationService;
    /**
     * 初始化站点
@@ -51,7 +59,15 @@
        List<String> targets = Arrays.asList(StringUtils.split(param.getTarget(), ","));
        List<DeviceSite> deviceSites =  new ArrayList<>();
        for (String site : sites) {
            BasStation basStation = basStationService.getOne(new LambdaQueryWrapper<BasStation>().eq(BasStation::getStationName, site));
            if (null == basStation) {
                throw new CoolException("初始化失败: 站点未找到!!");
            }
            for (String deviceSite : dvSites) {
                BasStation basStation2 = basStationService.getOne(new LambdaQueryWrapper<BasStation>().eq(BasStation::getStationName, deviceSite));
                if (null == basStation2) {
                    throw new CoolException("初始化失败: 作业站点未找到!!");
                }
                for (Long id : param.getTypeIds()) {
                    for (String target : targets) {
                        DeviceSite site1 = new DeviceSite();
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/LocItemServiceImpl.java
@@ -5,17 +5,19 @@
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.vincent.rsf.framework.common.R;
import com.vincent.rsf.framework.exception.CoolException;
import com.vincent.rsf.server.manager.entity.Loc;
import com.vincent.rsf.server.manager.entity.Task;
import com.vincent.rsf.server.manager.entity.TaskItem;
import com.vincent.rsf.server.api.controller.params.TaskInParam;
import com.vincent.rsf.server.api.entity.dto.InTaskMsgDto;
import com.vincent.rsf.server.api.service.WcsService;
import com.vincent.rsf.server.api.utils.LocUtils;
import com.vincent.rsf.server.api.utils.SlaveProperties;
import com.vincent.rsf.server.common.constant.Constants;
import com.vincent.rsf.server.manager.controller.params.LocToTaskParams;
import com.vincent.rsf.server.manager.entity.*;
import com.vincent.rsf.server.manager.enums.*;
import com.vincent.rsf.server.manager.enums.LocType;
import com.vincent.rsf.server.manager.mapper.LocItemMapper;
import com.vincent.rsf.server.manager.entity.LocItem;
import com.vincent.rsf.server.manager.service.LocItemService;
import com.vincent.rsf.server.manager.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.vincent.rsf.server.manager.service.LocService;
import com.vincent.rsf.server.manager.service.TaskItemService;
import com.vincent.rsf.server.manager.service.TaskService;
import com.vincent.rsf.server.system.constant.SerialRuleCode;
import com.vincent.rsf.server.system.utils.SerialRuleUtils;
import lombok.Synchronized;
@@ -25,10 +27,8 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.lang.reflect.Array;
import java.util.*;
import java.util.stream.Collectors;
@Service("locItemService")
@@ -42,6 +42,12 @@
    private TaskItemService taskItemService;
    @Autowired
    private LocItemService locItemService;
    @Autowired
    private DeviceSiteService deviceSiteService;
    @Autowired
    private SlaveProperties slaveProperties;
    @Autowired
    private WcsService wcsService;
    /**
@@ -54,21 +60,16 @@
    @Override
    @Synchronized
    @Transactional(rollbackFor = Exception.class)
    public R generateTask(Map<String, Object> map) {
        String type;
        if (!Objects.isNull(map.get("type")) && StringUtils.isNotBlank(map.get("type").toString())) {
            type = map.get("type").toString();
        } else {
            type = "stock";
        }
        if (Objects.isNull(map.get("siteNo"))) {
    public R generateTask(LocToTaskParams map) {
        if (Objects.isNull(map.getSiteNo())) {
            throw new CoolException("站点不能为空!");
        }
        if (Objects.isNull(map.get("items"))) {
        if (Objects.isNull(map.getItems()) || map.getItems().isEmpty()) {
            throw new CoolException("明细不能为空!");
        }
        String siteNo = map.get("siteNo").toString();
        List<LocItem> items = JSONArray.parseArray(JSONArray.toJSONString(map.get("items")), LocItem.class);
        String siteNo = map.getSiteNo();
        List<LocItem> items = map.getItems();
        Map<Long, List<LocItem>> listMap = items.stream().collect(Collectors.groupingBy(LocItem::getLocId));
        listMap.keySet().forEach(key -> {
            Task task = new Task();
@@ -82,9 +83,25 @@
                throw new CoolException("库位状态更新失败!!");
            }
            Task moveTask = new Task();
            if (!LocUtils.isShallowLoc(slaveProperties, loc.getCode())) {
                //获取深库位对应浅库位
                String shallowLoc = LocUtils.getShallowLoc(slaveProperties, loc.getCode());
                Loc one = locService.getOne(new LambdaQueryWrapper<Loc>().eq(Loc::getCode, shallowLoc));
                if (Objects.isNull(one)) {
                    throw new CoolException("对应库位不存在!!");
                }
                map.setOrgLoc(one.getCode());
                //优先生成移库任务
                if (!one.getUseStatus().equals(LocStsType.LOC_STS_TYPE_O.type)) {
                    moveTask = genMoveTask(map);
                }
            }
            String ruleCode = SerialRuleUtils.generateRuleCode(SerialRuleCode.SYS_TASK_CODE, null);
            task.setOrgLoc(loc.getCode())
                    .setTaskCode(ruleCode)
                    .setParentId(moveTask.getId())
                    .setTargSite(siteNo)
                    .setTaskStatus(TaskStsType.GENERATE_OUT.id)
                    .setBarcode(loc.getBarcode());
@@ -104,20 +121,41 @@
                throw new CoolException("托盘任务执行中,不能重复创建!");
            }
            if (type.equals("stock")) {
                Double useQty  = Math.round((outQty + workQty) * 10000) / 10000.0;
            if (map.getType().equals(Constants.TASK_TYPE_OUT_STOCK)) {
                Double useQty = Math.round((outQty + workQty) * 10000) / 10000.0;
                if (orgQty.compareTo(useQty) > 0) {
                    //拣料出库
                    task.setTaskType(TaskType.TASK_TYPE_PICK_AGAIN_OUT.type);
                    DeviceSite deviceSite = deviceSiteService.getOne(new LambdaQueryWrapper<DeviceSite>()
                            .eq(DeviceSite::getSite, siteNo)
                            .eq(DeviceSite::getChannel, loc.getChannel())
                            .eq(DeviceSite::getType, TaskType.TASK_TYPE_PICK_AGAIN_OUT.type));
                    if (Objects.isNull(deviceSite)) {
                        throw new CoolException("站点不支持拣料出库!!");
                    }
                } else {
                    //全板出库
                    task.setTaskType(TaskType.TASK_TYPE_OUT.type);
                    DeviceSite deviceSite = deviceSiteService.getOne(new LambdaQueryWrapper<DeviceSite>()
                            .eq(DeviceSite::getChannel, loc.getChannel())
                            .eq(DeviceSite::getSite, siteNo).eq(DeviceSite::getType, TaskType.TASK_TYPE_OUT.type));
                    if (Objects.isNull(deviceSite)) {
                        throw new CoolException("站点不支持全板出库!!");
                    }
                }
            } else if (type.equals("check")) {
            } else if (map.getType().equals(Constants.TASK_TYPE_OUT_CHECK)) {
                //盘点出库
                task.setTaskType(TaskType.TASK_TYPE_CHECK_OUT.type);
                DeviceSite deviceSite = deviceSiteService.getOne(new LambdaQueryWrapper<DeviceSite>()
                        .eq(DeviceSite::getChannel, loc.getChannel())
                        .eq(DeviceSite::getSite, siteNo)
                        .eq(DeviceSite::getType, TaskType.TASK_TYPE_CHECK_OUT.type));
                if (Objects.isNull(deviceSite)) {
                    throw new CoolException("当前站点不支持盘点出库!!");
                }
            }
            if (!taskService.save(task)) {
                throw new CoolException("任务创建失败!!");
            }
@@ -138,7 +176,7 @@
                    throw new CoolException("库存信息不存在!");
                }
                if (locItem.getOutQty().compareTo(0.0) < 0) {
                if (item.getOutQty().compareTo(0.0) < 0) {
                    throw new CoolException("出库数里不能小于0!!");
                }
@@ -163,32 +201,59 @@
    /**
     * 生成移库任务
     *
     * @param map
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R genMoveTask(Map<String, Object> map) {
        if (Objects.isNull(map.get("tarLoc")) || StringUtils.isBlank(map.get("tarLoc").toString())) {
            throw new CoolException("目标库位不能为空!");
        }
        if (Objects.isNull(map.get("orgLoc")) || StringUtils.isBlank(map.get("orgLoc").toString())) {
    public Task genMoveTask(LocToTaskParams map) {
        if (Objects.isNull(map.getOrgLoc()) || StringUtils.isBlank(map.getOrgLoc())) {
            throw new CoolException("源库位不能为空!");
        }
        Loc orgLoc = locService.getOne(new LambdaQueryWrapper<Loc>().eq(Loc::getCode, map.get("orgLoc")));
        Loc orgLoc = locService.getOne(new LambdaQueryWrapper<Loc>().eq(Loc::getCode, map.getOrgLoc()));
        if (Objects.isNull(orgLoc)) {
            throw new CoolException("源库位不存在!!");
        }
        if (orgLoc.getUseStatus().equals(LocStsType.LOC_STS_TYPE_R.type)
                || orgLoc.getUseStatus().equals(LocStsType.LOC_STS_TYPE_S.type)
                || orgLoc.getUseStatus().equals(LocStsType.LOC_STS_TYPE_X.type ) ) {
            throw new CoolException("源库位有任务正在执行中...");
        }
        orgLoc.setUseStatus(LocStsType.LOC_STS_TYPE_R.type);
        if (!locService.updateById(orgLoc)) {
            throw new CoolException("目标库位预约失败!!");
            throw new CoolException("出库预约失败!!");
        }
        Loc targetLoc = new Loc();
        if (Objects.isNull(map.getTarLoc()) || StringUtils.isBlank(map.getTarLoc())) {
            //目标库位为空,自动获取新库位
            DeviceSite deviceSite = deviceSiteService.getOne(new LambdaQueryWrapper<DeviceSite>()
                            .eq(DeviceSite::getType, TaskType.TASK_TYPE_LOC_MOVE.type)
                    .eq(DeviceSite::getChannel, orgLoc.getChannel()), false);
            if (Objects.isNull(deviceSite)) {
                throw new CoolException("站点信息不存在!!");
            }
            TaskInParam param = new TaskInParam();
            param.setIoType(TaskType.TASK_TYPE_OUT.type)
                    .setSourceStaNo(Integer.parseInt(deviceSite.getSite()))
                    .setLocType1(Integer.parseInt(orgLoc.getType()));
            InTaskMsgDto locNo = null;
            try {
                locNo = wcsService.getLocNo(param);
            } catch (Exception e) {
                log.error("<UNK>", e);
                throw new CoolException(e.getMessage());
            }
            targetLoc = locService.getOne(new LambdaQueryWrapper<Loc>().eq(Loc::getCode, locNo.getLocNo()));
        } else {
            targetLoc = locService.getOne(new LambdaQueryWrapper<Loc>().eq(Loc::getCode, map.getTarLoc()));
        }
        Loc targetLoc = locService.getOne(new LambdaQueryWrapper<Loc>().eq(Loc::getCode, map.get("tarLoc").toString()));
        if (Objects.isNull(targetLoc)) {
            throw new CoolException("目标库位不存在!!");
        }
@@ -213,26 +278,22 @@
        }
        List<LocItem> locItems = locItemService.list(new LambdaQueryWrapper<LocItem>().eq(LocItem::getLocId, orgLoc.getId()));
        if (locItems.isEmpty()) {
            throw new CoolException("库位明细不存在!!");
        if (!locItems.isEmpty()) {
            List<TaskItem> taskItems = new ArrayList<>();
            for (LocItem item : locItems) {
                TaskItem taskItem = new TaskItem();
                BeanUtils.copyProperties(item, taskItem);
                taskItem.setTaskId(task.getId())
                        .setAnfme(item.getAnfme())
                        .setBatch(item.getBatch())
                        .setOrderType(OrderType.ORDER_IN.type)
                        .setWkType(Short.parseShort(OrderWorkType.ORDER_WORK_TYPE_OTHER_IN.type));
                taskItems.add(taskItem);
            }
            if (!taskItemService.saveBatch(taskItems)) {
                throw new CoolException("任务明细生成失败!!");
            }
        }
        List<TaskItem> taskItems = new ArrayList<>();
        for (LocItem item : locItems) {
            TaskItem taskItem = new TaskItem();
            BeanUtils.copyProperties(item, taskItem);
            taskItem.setTaskId(task.getId())
                    .setAnfme(item.getAnfme())
                    .setBatch(item.getBatch())
                    .setOrderType(OrderType.ORDER_IN.type)
                    .setWkType(Short.parseShort(OrderWorkType.ORDER_WORK_TYPE_OTHER_IN.type));
            taskItems.add(taskItem);
        }
        if (!taskItemService.saveBatch(taskItems)) {
            throw new CoolException("任务明细生成失败!!");
        }
        return R.ok(task);
        return task;
    }
}
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/TaskServiceImpl.java
@@ -6,6 +6,7 @@
import com.vincent.rsf.server.api.controller.params.TaskInParam;
import com.vincent.rsf.server.api.entity.dto.InTaskMsgDto;
import com.vincent.rsf.server.api.service.WcsService;
import com.vincent.rsf.server.common.constant.Constants;
import com.vincent.rsf.server.manager.enums.*;
import com.vincent.rsf.framework.common.R;
import com.vincent.rsf.framework.exception.CoolException;
@@ -167,7 +168,6 @@
            throw new CoolException("参数不能为空!!");
        }
        /**获取组拖*/
//        List<Long> ids = pakins.stream().map(WaitPakin::getId).collect(Collectors.toList());
        List<WaitPakin> waitPakins = waitPakinService.list(new LambdaQueryWrapper<WaitPakin>()
                .in(WaitPakin::getId, pakins.getId())
                .eq(WaitPakin::getIoStatus, Short.parseShort(PakinIOStatus.PAKIN_IO_STATUS_DONE.val)));
@@ -414,7 +414,7 @@
        Loc orgLoc = locService.getOne(new LambdaQueryWrapper<Loc>().eq(Loc::getCode, task.getOrgLoc()));
        if (Objects.isNull(orgLoc)) {
            throw new CoolException("目标库位不存在!");
            throw new CoolException("源库位不存在!");
        }
        if (!loc.getUseStatus().equals(LocStsType.LOC_STS_TYPE_S.type)) {
@@ -426,31 +426,36 @@
        }
        List<TaskItem> taskItems = taskItemService.list(new LambdaQueryWrapper<TaskItem>().eq(TaskItem::getTaskId, task.getId()));
        if (taskItems.isEmpty()) {
            throw new CoolException("任务明细不存在!!");
        if (!taskItems.isEmpty()) {
            //移库有可能是空板
            try {
                //更新库位明细
                saveLocItem(taskItems, task.getId());
            } catch (Exception e) {
                throw new CoolException("库位明细更新失败!!");
            }
            if (!locItemService.remove(new LambdaQueryWrapper<LocItem>().eq(LocItem::getLocCode, task.getOrgLoc()))) {
                throw new CoolException("源库位明细删除失败!");
            }
        }
        try {
            //更新库位明细
            saveLocItem(taskItems, task.getId());
        } catch (Exception e) {
            throw new CoolException("库位明细更新失败!!");
        }
//        /**对任务明细按组拖明细进行分组*/
//        try {
//            //保存库存明细
//            saveStockItems(taskItems, null, null, pakinItem.getWkType(), pakinItem.getType());
//        } catch (Exception e) {
//            log.error("<UNK>", e);
//            throw new CoolException(e.getMessage());
//        }
        /**修改库位状态为F.在库*/
        if (!locService.update(new LambdaUpdateWrapper<Loc>().set(Loc::getUseStatus, LocStsType.LOC_STS_TYPE_F.type).eq(Loc::getCode, task.getTargLoc()))) {
        if (!locService.update(new LambdaUpdateWrapper<Loc>()
                        .set(Loc::getBarcode, task.getBarcode())
                .set(Loc::getUseStatus, LocStsType.LOC_STS_TYPE_F.type)
                .eq(Loc::getCode, task.getTargLoc()))) {
            throw new CoolException("库位状态修改失败!!");
        }
        if (!locService.update(new LambdaUpdateWrapper<Loc>().set(Loc::getUseStatus, LocStsType.LOC_STS_TYPE_O.type).eq(Loc::getCode, task.getOrgLoc()))) {
        if (!locService.update(new LambdaUpdateWrapper<Loc>()
                        .set(Loc::getBarcode, null)
                .set(Loc::getUseStatus, LocStsType.LOC_STS_TYPE_O.type).eq(Loc::getCode, task.getOrgLoc()))) {
            throw new CoolException("库位状态修改失败!!");
        }
        if (!this.update(new LambdaUpdateWrapper<Task>().eq(Task::getId, task.getId()).set(Task::getTaskStatus, TaskStsType.UPDATED_IN.id))) {
            throw new CoolException("任务状态修改失败!!");
@@ -524,18 +529,10 @@
                throw new CoolException("数据错误,作业中库存数据丢失!!");
            }
            if (task.getTaskType().equals(TaskType.TASK_TYPE_CHECK_IN.type)) {
                locWorking.setWorkQty(0.0);
                locWorking.setAnfme(taskItem.getAnfme());
            } else {
                if (locWorking.getAnfme().compareTo(taskItem.getAnfme()) >= 0) {
                    locWorking.setWorkQty(0.0);
                    locWorking.setAnfme(Math.round((locWorking.getAnfme() - taskItem.getAnfme()) * 10000) / 10000.0);
                } else {
                    continue;
                }
            }
            BeanUtils.copyProperties(locWorking, locItem);
            locItem.setLocCode(loc.getCode()).setLocId(loc.getId()).setId(null);
            locItem.setWorkQty(0.0).setLocCode(loc.getCode()).setLocId(loc.getId()).setId(null);
            items.add(locItem);
        }
@@ -547,13 +544,11 @@
        //保存入出库流水
        saveStockItems(taskItems, task, null, null, taskItem.getWkType(), taskItem.getOrderType());
        if (!locItemWorkingService.remove(new LambdaQueryWrapper<LocItemWorking>().eq(LocItemWorking::getTaskId, task.getId()))) {
            throw new CoolException("作业中库存删除失败!!");
        }
        task.setTaskStatus(TaskStsType.UPDATED_IN.id);
        task.setTaskStatus(TaskStsType.UPDATED_IN.id).setUpdateTime(null);
        if (!taskService.updateById(task)) {
            throw new CoolException("任务状态修改失败!!");
        }
@@ -567,9 +562,13 @@
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R removeTask(Long[] ids) {
        List<Integer> longs = Arrays.asList(TaskStsType.GENERATE_IN.id, TaskStsType.GENERATE_OUT.id);
        List<Task> tasks = this.list(new LambdaQueryWrapper<Task>().in(Task::getId, ids).in(Task::getTaskStatus, longs));
        List<Integer> list = Arrays.asList(TaskType.TASK_TYPE_IN.type, TaskType.TASK_TYPE_OUT.type, TaskType.TASK_TYPE_EMPITY_IN.type, TaskType.TASK_TYPE_EMPITY_OUT.type, TaskType.TASK_TYPE_MERGE_OUT.type);
        List<Task> tasks = this.list(new LambdaQueryWrapper<Task>()
                .in(Task::getTaskType, list)
                .in(Task::getId, ids).in(Task::getTaskStatus, longs));
        if (tasks.isEmpty()) {
            throw new CoolException("任务已处执行状态不可取消!!");
        }
@@ -642,17 +641,15 @@
            throw new CoolException("当前任务不存在!!");
        }
        Integer type;
        if (oType.equals("check")) {
        if (oType.equals(Constants.TASK_TYPE_OUT_CHECK)) {
            //盘点入库
            type = TaskType.TASK_TYPE_CHECK_IN.type;
            if (!task.getTaskType().equals(TaskType.TASK_TYPE_CHECK_OUT.type)) {
                throw new CoolException("非盘点出库 ,不可执行此操作!!");
            }
        } else {
            //拣料入库
            type = TaskType.TASK_TYPE_PICK_IN.type;
            if (!task.getTaskType().equals(TaskType.TASK_TYPE_PICK_AGAIN_OUT.type)) {
                throw new CoolException("非拣料出库 ,不可执行此操作!!");
            }
@@ -671,11 +668,11 @@
                .setBarcode(task.getBarcode())
                .setTaskStatus(TaskStsType.GENERATE_IN.id);
        //TODO 根据物料的库位类型生成新的库位
        TaskInParam param = new TaskInParam();
        param.setSourceStaNo(Integer.parseInt(task.getTargSite()))
                .setIoType(type)
                .setLocType1(Integer.parseInt(loc.getType()));
        //获取新库位
        InTaskMsgDto locInfo = wcsService.getLocNo(param);
        if (Objects.isNull(locInfo)) {
@@ -685,6 +682,38 @@
        if (!this.updateById(task)) {
            throw new CoolException("任务状态更新失败!!");
        }
        List<TaskItem> taskItems = taskItemService.list(new LambdaQueryWrapper<TaskItem>().eq(TaskItem::getTaskId, task.getId()));
        for (int i = 0; i < taskItems.size(); i++) {
            TaskItem taskItem = taskItems.get(i);
            LocItemWorking locWorking = locItemWorkingService.getOne(new LambdaQueryWrapper<LocItemWorking>()
                    .eq(LocItemWorking::getTaskId, taskItem.getTaskId())
                    .eq(StringUtils.isNotBlank(taskItem.getBatch()), LocItemWorking::getBatch, taskItem.getBatch())
                    .eq(StringUtils.isNotBlank(taskItem.getFieldsIndex()), LocItemWorking::getFieldsIndex, taskItem.getFieldsIndex())
                    .eq(LocItemWorking::getMatnrId, taskItem.getMatnrId()));
            if (Objects.isNull(locWorking)) {
                throw new CoolException("数据错误,作业中库存数据丢失!!");
            }
            if (task.getTaskType().equals(TaskType.TASK_TYPE_CHECK_IN.type)) {
                locWorking.setWorkQty(0.0);
                locWorking.setAnfme(taskItem.getAnfme());
            } else {
                if (locWorking.getAnfme().compareTo(taskItem.getAnfme()) >= 0) {
                    locWorking.setWorkQty(0.0);
                    locWorking.setAnfme(Math.round((locWorking.getAnfme() - taskItem.getAnfme()) * 10000) / 10000.0);
                } else {
                    continue;
                }
            }
            if (!locItemWorkingService.updateById(locWorking)) {
                throw new CoolException("临时库存更新失败!!");
            }
            taskItems.get(i).setAnfme(locWorking.getAnfme());
        }
        if (!taskItemService.updateBatchById(taskItems)) {
            throw new CoolException("任务明细更新失败!!");
        }
        Loc one = locService.getOne(new LambdaQueryWrapper<Loc>().eq(Loc::getCode, task.getTargLoc()));
@@ -711,6 +740,7 @@
        if (Objects.isNull(task)) {
            throw new CoolException("参数不能为空!!");
        }
        Loc loc = locService.getOne(new LambdaQueryWrapper<Loc>().eq(Loc::getCode, task.getOrgLoc()));
        if (Objects.isNull(loc)) {
            throw new CoolException("库位不存在!!");
@@ -796,6 +826,11 @@
                    .eq(Task::getId, task.getId())
                    .set(Task::getTaskStatus, TaskStsType.UPDATED_OUT.id))) {
                throw new CoolException("库存状态更新失败!!");
            }
            //全板出库,删除临时库存
            if (!locItemWorkingService.remove(new LambdaQueryWrapper<LocItemWorking>().eq(LocItemWorking::getTaskId, task.getId()))) {
                throw new CoolException("临时库存清除失败!!");
            }
        }
@@ -901,7 +936,7 @@
            List<TaskItem> items = orderMap.get(key);
            try {
                //保存库存明细
                saveStockItems(items, task,  pakinItem.getId(), pakinItem.getAsnCode(), pakinItem.getWkType(), pakinItem.getType());
                saveStockItems(items, task, pakinItem.getId(), pakinItem.getAsnCode(), pakinItem.getWkType(), pakinItem.getType());
                //移出收货区库存, 修改组托状态
                removeReceiptStock(pakinItem);
            } catch (Exception e) {
@@ -1008,7 +1043,7 @@
                task.getTaskType().equals(TaskType.TASK_TYPE_MERGE_IN.type) ||
                task.getTaskType().equals(TaskType.TASK_TYPE_LOC_MOVE.type) ||
                task.getTaskType().equals(TaskType.TASK_TYPE_EMPITY_IN.type) ||
                task.getTaskType().equals(TaskType.TASK_TYPE_CHECK_IN.type) ) {
                task.getTaskType().equals(TaskType.TASK_TYPE_CHECK_IN.type)) {
            stock.setLocCode(task.getTargLoc());
        } else {
            stock.setLocCode(task.getOrgLoc());