From 27b40d8451a39191dfbe4576415419ce2ed9cb2f Mon Sep 17 00:00:00 2001
From: skyouc
Date: 星期日, 27 四月 2025 18:28:03 +0800
Subject: [PATCH] Merge branch 'devlop' of http://47.97.1.152:5880/r/wms-master into devlop

---
 rsf-server/src/main/java/com/vincent/rsf/server/manager/mapper/BasDeviceMapper.java            |   12 
 rsf-server/src/main/resources/mapper/manager/BasDeviceMapper.xml                               |    5 
 rsf-server/src/main/java/com/vincent/rsf/server/api/entity/dto/LocTypeDto.java                 |   21 
 rsf-server/src/main/java/com/vincent/rsf/server/api/utils/SlaveProperties.java                 |   28 
 rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/BasDeviceServiceImpl.java |   12 
 rsf-server/src/main/java/com/vincent/rsf/server/api/entity/dto/InTaskMsgDto.java               |   16 
 rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/DeviceBind.java                 |    1 
 rsf-server/src/main/java/com/vincent/rsf/server/api/utils/LocUtils.java                        |  166 +++++
 rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/BasDevice.java                  |  154 +++++
 rsf-admin/src/page/basDevice/BasDeviceList.jsx                                                 |  158 +++++
 rsf-server/src/main/java/com/vincent/rsf/server/manager/service/BasDeviceService.java          |    8 
 rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/Loc.java                        |    7 
 rsf-server/src/main/java/com/vincent/rsf/server/api/controller/params/TaskInParam.java         |   15 
 rsf-server/src/main/java/com/vincent/rsf/server/common/security/SecurityConfig.java            |    3 
 rsf-server/src/main/resources/application.yml                                                  |   13 
 rsf-admin/src/page/basDevice/BasDeviceEdit.jsx                                                 |  110 +++
 rsf-server/src/main/java/com/vincent/rsf/server/api/service/PdaOutStockService.java            |    9 
 rsf-admin/src/page/basDevice/BasDevicePanel.jsx                                                |   75 ++
 rsf-server/src/main/java/com/vincent/rsf/server/api/controller/pda/pdaOutStockController.java  |   28 
 rsf-server/src/main/java/com/vincent/rsf/server/api/service/WcsService.java                    |    8 
 rsf-server/src/main/java/com/vincent/rsf/server/api/controller/WcsController.java              |   47 +
 rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/WcsServiceImpl.java           |  561 ++++++++++++++++++
 rsf-server/src/main/java/com/vincent/rsf/server/api/controller/pda/MobileController.java       |    2 
 rsf-admin/src/page/basDevice/index.jsx                                                         |   18 
 rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/PdaOutStockServiceImpl.java   |   45 +
 rsf-admin/src/page/basDevice/BasDeviceCreate.jsx                                               |  138 ++++
 rsf-server/src/main/java/basDevice.sql                                                         |   25 
 rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/BasDeviceController.java    |  110 +++
 28 files changed, 1,792 insertions(+), 3 deletions(-)

diff --git a/rsf-admin/src/page/basDevice/BasDeviceCreate.jsx b/rsf-admin/src/page/basDevice/BasDeviceCreate.jsx
new file mode 100644
index 0000000..e446295
--- /dev/null
+++ b/rsf-admin/src/page/basDevice/BasDeviceCreate.jsx
@@ -0,0 +1,138 @@
+import React, { useState, useRef, useEffect, useMemo } from "react";
+import {
+    CreateBase,
+    useTranslate,
+    TextInput,
+    NumberInput,
+    BooleanInput,
+    DateInput,
+    SaveButton,
+    SelectInput,
+    ReferenceInput,
+    ReferenceArrayInput,
+    AutocompleteInput,
+    Toolbar,
+    required,
+    useDataProvider,
+    useNotify,
+    Form,
+    useCreateController,
+} from 'react-admin';
+import {
+    Dialog,
+    DialogActions,
+    DialogContent,
+    DialogTitle,
+    Stack,
+    Grid,
+    Box,
+} from '@mui/material';
+import DialogCloseButton from "../components/DialogCloseButton";
+import StatusSelectInput from "../components/StatusSelectInput";
+import MemoInput from "../components/MemoInput";
+
+const BasDeviceCreate = (props) => {
+    const { open, setOpen } = props;
+
+    const translate = useTranslate();
+    const notify = useNotify();
+
+    const handleClose = (event, reason) => {
+        if (reason !== "backdropClick") {
+            setOpen(false);
+        }
+    };
+
+    const handleSuccess = async (data) => {
+        setOpen(false);
+        notify('common.response.success');
+    };
+
+    const handleError = async (error) => {
+        notify(error.message || 'common.response.fail', { type: 'error', messageArgs: { _: error.message } });
+    };
+
+    return (
+        <>
+            <CreateBase
+                record={{}}
+                transform={(data) => {
+                    return data;
+                }}
+                mutationOptions={{ onSuccess: handleSuccess, onError: handleError }}
+            >
+                <Dialog
+                    open={open}
+                    onClose={handleClose}
+                    aria-labelledby="form-dialog-title"
+                    fullWidth
+                    disableRestoreFocus
+                    maxWidth="md"   // 'xs' | 'sm' | 'md' | 'lg' | 'xl'
+                >
+                    <Form>
+                        <DialogTitle id="form-dialog-title" sx={{
+                            position: 'sticky',
+                            top: 0,
+                            backgroundColor: 'background.paper',
+                            zIndex: 1000
+                        }}
+                        >
+                            {translate('create.title')}
+                            <Box sx={{ position: 'absolute', top: 8, right: 8, zIndex: 1001 }}>
+                                <DialogCloseButton onClose={handleClose} />
+                            </Box>
+                        </DialogTitle>
+                        <DialogContent sx={{ mt: 2 }}>
+                            <Grid container rowSpacing={2} columnSpacing={2}>
+                                <Grid item xs={6} display="flex" gap={1}>
+                                    <NumberInput
+                                        label="table.field.basDevice.deviceNo"
+                                        source="deviceNo"
+                                        autoFocus
+                                    />
+                                </Grid>
+                                <Grid item xs={6} display="flex" gap={1}>
+                                    <TextInput
+                                        label="table.field.basDevice.inEnable"
+                                        source="inEnable"
+                                        parse={v => v}
+                                    />
+                                </Grid>
+                                <Grid item xs={6} display="flex" gap={1}>
+                                    <TextInput
+                                        label="table.field.basDevice.outEnable"
+                                        source="outEnable"
+                                        parse={v => v}
+                                    />
+                                </Grid>
+                                <Grid item xs={6} display="flex" gap={1}>
+                                    <TextInput
+                                        label="table.field.basDevice.origin"
+                                        source="origin"
+                                        parse={v => v}
+                                    />
+                                </Grid>
+
+                                <Grid item xs={6} display="flex" gap={1}>
+                                    <StatusSelectInput />
+                                </Grid>
+                                <Grid item xs={12} display="flex" gap={1}>
+                                    <Stack direction="column" spacing={1} width={'100%'}>
+                                        <MemoInput />
+                                    </Stack>
+                                </Grid>
+                            </Grid>
+                        </DialogContent>
+                        <DialogActions sx={{ position: 'sticky', bottom: 0, backgroundColor: 'background.paper', zIndex: 1000 }}>
+                            <Toolbar sx={{ width: '100%', justifyContent: 'space-between' }}  >
+                                <SaveButton />
+                            </Toolbar>
+                        </DialogActions>
+                    </Form>
+                </Dialog>
+            </CreateBase>
+        </>
+    )
+}
+
+export default BasDeviceCreate;
diff --git a/rsf-admin/src/page/basDevice/BasDeviceEdit.jsx b/rsf-admin/src/page/basDevice/BasDeviceEdit.jsx
new file mode 100644
index 0000000..488b7d5
--- /dev/null
+++ b/rsf-admin/src/page/basDevice/BasDeviceEdit.jsx
@@ -0,0 +1,110 @@
+import React, { useState, useRef, useEffect, useMemo } from "react";
+import {
+    Edit,
+    SimpleForm,
+    FormDataConsumer,
+    useTranslate,
+    TextInput,
+    NumberInput,
+    BooleanInput,
+    DateInput,
+    SelectInput,
+    ReferenceInput,
+    ReferenceArrayInput,
+    AutocompleteInput,
+    SaveButton,
+    Toolbar,
+    Labeled,
+    NumberField,
+    required,
+    useRecordContext,
+    DeleteButton,
+} from 'react-admin';
+import { useWatch, useFormContext } from "react-hook-form";
+import { Stack, Grid, Box, Typography } from '@mui/material';
+import * as Common from '@/utils/common';
+import { EDIT_MODE, REFERENCE_INPUT_PAGESIZE } from '@/config/setting';
+import EditBaseAside from "../components/EditBaseAside";
+import CustomerTopToolBar from "../components/EditTopToolBar";
+import MemoInput from "../components/MemoInput";
+import StatusSelectInput from "../components/StatusSelectInput";
+
+const FormToolbar = () => {
+    const { getValues } = useFormContext();
+
+    return (
+        <Toolbar sx={{ justifyContent: 'space-between' }}>
+            <SaveButton />
+            <DeleteButton mutationMode="optimistic" />
+        </Toolbar>
+    )
+}
+
+const BasDeviceEdit = () => {
+    const translate = useTranslate();
+
+    return (
+        <Edit
+            redirect="list"
+            mutationMode={EDIT_MODE}
+            actions={<CustomerTopToolBar />}
+            aside={<EditBaseAside />}
+        >
+            <SimpleForm
+                shouldUnregister
+                warnWhenUnsavedChanges
+                toolbar={<FormToolbar />}
+                mode="onTouched"
+                defaultValues={{}}
+            // validate={(values) => { }}
+            >
+                <Grid container width={{ xs: '100%', xl: '80%' }} rowSpacing={3} columnSpacing={3}>
+                    <Grid item xs={12} md={8}>
+                        <Typography variant="h6" gutterBottom>
+                            {translate('common.edit.title.main')}
+                        </Typography>
+                        <Stack direction='row' gap={2}>
+                            <NumberInput
+                                label="table.field.basDevice.deviceNo"
+                                source="deviceNo"
+                                autoFocus
+                            />
+                        </Stack>
+                        <Stack direction='row' gap={2}>
+                            <TextInput
+                                label="table.field.basDevice.inEnable"
+                                source="inEnable"
+                                parse={v => v}
+                            />
+                        </Stack>
+                        <Stack direction='row' gap={2}>
+                            <TextInput
+                                label="table.field.basDevice.outEnable"
+                                source="outEnable"
+                                parse={v => v}
+                            />
+                        </Stack>
+                        <Stack direction='row' gap={2}>
+                            <TextInput
+                                label="table.field.basDevice.origin"
+                                source="origin"
+                                parse={v => v}
+                            />
+                        </Stack>
+
+                    </Grid>
+                    <Grid item xs={12} md={4}>
+                        <Typography variant="h6" gutterBottom>
+                            {translate('common.edit.title.common')}
+                        </Typography>
+                        <StatusSelectInput />
+                        <Box mt="2em" />
+                        <MemoInput />
+                    </Grid>
+                </Grid>
+            </SimpleForm>
+        </Edit >
+    )
+}
+
+export default BasDeviceEdit;
diff --git a/rsf-admin/src/page/basDevice/BasDeviceList.jsx b/rsf-admin/src/page/basDevice/BasDeviceList.jsx
new file mode 100644
index 0000000..b85be95
--- /dev/null
+++ b/rsf-admin/src/page/basDevice/BasDeviceList.jsx
@@ -0,0 +1,158 @@
+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,
+    AutocompleteInput,
+    DeleteButton,
+} from 'react-admin';
+import { Box, Typography, Card, Stack } from '@mui/material';
+import { styled } from '@mui/material/styles';
+import BasDeviceCreate from "./BasDeviceCreate";
+import BasDevicePanel from "./BasDevicePanel";
+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';
+
+const StyledDatagrid = styled(DatagridConfigurable)(({ theme }) => ({
+    '& .css-1vooibu-MuiSvgIcon-root': {
+        height: '.9em'
+    },
+    '& .RaDatagrid-row': {
+        cursor: 'auto'
+    },
+    '& .column-name': {
+    },
+    '& .opt': {
+        width: 200
+    },
+}));
+
+const filters = [
+    <SearchInput source="condition" alwaysOn />,
+    <DateInput label='common.time.after' source="timeStart" alwaysOn />,
+    <DateInput label='common.time.before' source="timeEnd" alwaysOn />,
+
+    <NumberInput source="deviceNo" label="table.field.basDevice.deviceNo" />,
+    <TextInput source="inEnable" label="table.field.basDevice.inEnable" />,
+    <TextInput source="outEnable" label="table.field.basDevice.outEnable" />,
+    <TextInput source="origin" label="table.field.basDevice.origin" />,
+
+    <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 BasDeviceList = () => {
+    const translate = useTranslate();
+
+    const [createDialog, setCreateDialog] = useState(false);
+    const [drawerVal, setDrawerVal] = useState(false);
+
+    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.basDevice"}
+                empty={<EmptyData onClick={() => { setCreateDialog(true) }} />}
+                filters={filters}
+                sort={{ field: "create_time", order: "desc" }}
+                actions={(
+                    <TopToolbar>
+                        <FilterButton />
+                        <MyCreateButton onClick={() => { setCreateDialog(true) }} />
+                        <SelectColumnsButton preferenceKey='basDevice' />
+                        <MyExportButton />
+                    </TopToolbar>
+                )}
+                perPage={DEFAULT_PAGE_SIZE}
+            >
+                <StyledDatagrid
+                    preferenceKey='basDevice'
+                    bulkActionButtons={() => <BulkDeleteButton mutationMode={OPERATE_MODE} />}
+                    rowClick={(id, resource, record) => false}
+                    expand={() => <BasDevicePanel />}
+                    expandSingle={true}
+                    omit={['id', 'createTime', 'createBy', 'memo']}
+                >
+                    <NumberField source="id" />
+                    <NumberField source="deviceNo" label="table.field.basDevice.deviceNo" />
+                    <TextField source="inEnable" label="table.field.basDevice.inEnable" />
+                    <TextField source="outEnable" label="table.field.basDevice.outEnable" />
+                    <TextField source="origin" label="table.field.basDevice.origin" />
+
+                    <ReferenceField source="updateBy" label="common.field.updateBy" reference="user" link={false} sortable={false}>
+                        <TextField source="nickname" />
+                    </ReferenceField>
+                    <DateField source="updateTime" label="common.field.updateTime" showTime />
+                    <ReferenceField source="createBy" label="common.field.createBy" reference="user" link={false} sortable={false}>
+                        <TextField source="nickname" />
+                    </ReferenceField>
+                    <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} />
+                    <WrapperField cellClassName="opt" label="common.field.opt">
+                        <EditButton sx={{ padding: '1px', fontSize: '.75rem' }} />
+                        <DeleteButton sx={{ padding: '1px', fontSize: '.75rem' }} mutationMode={OPERATE_MODE} />
+                    </WrapperField>
+                </StyledDatagrid>
+            </List>
+            <BasDeviceCreate
+                open={createDialog}
+                setOpen={setCreateDialog}
+            />
+            <PageDrawer
+                title='BasDevice Detail'
+                drawerVal={drawerVal}
+                setDrawerVal={setDrawerVal}
+            >
+            </PageDrawer>
+        </Box>
+    )
+}
+
+export default BasDeviceList;
diff --git a/rsf-admin/src/page/basDevice/BasDevicePanel.jsx b/rsf-admin/src/page/basDevice/BasDevicePanel.jsx
new file mode 100644
index 0000000..2cc3f0e
--- /dev/null
+++ b/rsf-admin/src/page/basDevice/BasDevicePanel.jsx
@@ -0,0 +1,75 @@
+import React, { useState, useRef, useEffect, useMemo } from "react";
+import { Box, Card, CardContent, Grid, Typography, Tooltip } from '@mui/material';
+import {
+    useTranslate,
+    useRecordContext,
+} from 'react-admin';
+import PanelTypography from "../components/PanelTypography";
+import * as Common from '@/utils/common'
+
+const BasDevicePanel = () => {
+    const record = useRecordContext();
+    if (!record) return null;
+    const translate = useTranslate();
+    return (
+        <>
+            <Card sx={{ width: { xs: 300, sm: 500, md: 600, lg: 800 }, margin: 'auto' }}>
+                <CardContent>
+                    <Grid container spacing={2}>
+                        <Grid item xs={12} sx={{ display: 'flex', justifyContent: 'space-between' }}>
+                            <Typography variant="h6" gutterBottom align="left" sx={{
+                                maxWidth: { xs: '100px', sm: '180px', md: '260px', lg: '360px' },
+                                whiteSpace: 'nowrap',
+                                overflow: 'hidden',
+                                textOverflow: 'ellipsis',
+                            }}>
+                                {Common.camelToPascalWithSpaces(translate('table.field.basDevice.id'))}: {record.id}
+                            </Typography>
+                            {/*  inherit, primary, secondary, textPrimary, textSecondary, error */}
+                            <Typography variant="h6" gutterBottom align="right" >
+                                ID: {record.id}
+                            </Typography>
+                        </Grid>
+                    </Grid>
+                    <Grid container spacing={2}>
+                        <Grid item xs={12} container alignContent="flex-end">
+                            <Typography variant="caption" color="textSecondary" sx={{ wordWrap: 'break-word', wordBreak: 'break-all' }}>
+                                {Common.camelToPascalWithSpaces(translate('common.field.memo'))}:{record.memo}
+                            </Typography>
+                        </Grid>
+                    </Grid>
+                    <Box height={20}>&nbsp;</Box>
+                    <Grid container spacing={2}>
+                        <Grid item xs={6}>
+                            <PanelTypography
+                                title="table.field.basDevice.deviceNo" 
+                                property={record.deviceNo}
+                            />
+                        </Grid>
+                        <Grid item xs={6}>
+                            <PanelTypography
+                                title="table.field.basDevice.inEnable" 
+                                property={record.inEnable}
+                            />
+                        </Grid>
+                        <Grid item xs={6}>
+                            <PanelTypography
+                                title="table.field.basDevice.outEnable" 
+                                property={record.outEnable}
+                            />
+                        </Grid>
+                        <Grid item xs={6}>
+                            <PanelTypography
+                                title="table.field.basDevice.origin" 
+                                property={record.origin}
+                            />
+                        </Grid>
+
+                    </Grid>
+                </CardContent>
+            </Card >
+        </>
+    );
+};
+
+export default BasDevicePanel;
diff --git a/rsf-admin/src/page/basDevice/index.jsx b/rsf-admin/src/page/basDevice/index.jsx
new file mode 100644
index 0000000..4e0325a
--- /dev/null
+++ b/rsf-admin/src/page/basDevice/index.jsx
@@ -0,0 +1,18 @@
+import React, { useState, useRef, useEffect, useMemo } from "react";
+import {
+    ListGuesser,
+    EditGuesser,
+    ShowGuesser,
+} from "react-admin";
+
+import BasDeviceList from "./BasDeviceList";
+import BasDeviceEdit from "./BasDeviceEdit";
+
+export default {
+    list: BasDeviceList,
+    edit: BasDeviceEdit,
+    show: ShowGuesser,
+    recordRepresentation: (record) => {
+        return `${record.id}`
+    }
+};
diff --git a/rsf-server/src/main/java/basDevice.sql b/rsf-server/src/main/java/basDevice.sql
new file mode 100644
index 0000000..1c107e3
--- /dev/null
+++ b/rsf-server/src/main/java/basDevice.sql
@@ -0,0 +1,25 @@
+-- save basDevice record
+-- mysql
+insert into `sys_menu` ( `name`, `parent_id`, `route`, `component`, `type`, `sort`, `tenant_id`, `status`) values ( 'menu.basDevice', '0', '/manager/basDevice', 'basDevice', '0' , '0', '1' , '1');
+
+insert into `sys_menu` ( `name`, `parent_id`, `type`, `authority`, `sort`, `tenant_id`, `status`) values ( 'Query 鍩虹璁惧琛�', '', '1', 'manager:basDevice:list', '0', '1', '1');
+insert into `sys_menu` ( `name`, `parent_id`, `type`, `authority`, `sort`, `tenant_id`, `status`) values ( 'Create 鍩虹璁惧琛�', '', '1', 'manager:basDevice:save', '1', '1', '1');
+insert into `sys_menu` ( `name`, `parent_id`, `type`, `authority`, `sort`, `tenant_id`, `status`) values ( 'Update 鍩虹璁惧琛�', '', '1', 'manager:basDevice:update', '2', '1', '1');
+insert into `sys_menu` ( `name`, `parent_id`, `type`, `authority`, `sort`, `tenant_id`, `status`) values ( 'Delete 鍩虹璁惧琛�', '', '1', 'manager:basDevice:remove', '3', '1', '1');
+
+-- locale menu name
+basDevice: 'BasDevice',
+
+-- locale field
+basDevice: {
+    deviceNo: "deviceNo",
+    inEnable: "inEnable",
+    outEnable: "outEnable",
+    origin: "origin",
+},
+
+-- ResourceContent
+import basDevice from './basDevice';
+
+case 'basDevice':
+    return basDevice;
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/WcsController.java b/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/WcsController.java
new file mode 100644
index 0000000..2e10cc7
--- /dev/null
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/WcsController.java
@@ -0,0 +1,47 @@
+package com.vincent.rsf.server.api.controller;
+
+import com.vincent.rsf.framework.common.Cools;
+import com.vincent.rsf.framework.common.R;
+import com.vincent.rsf.server.api.entity.dto.InTaskMsgDto;
+import com.vincent.rsf.server.api.controller.params.TaskInParam;
+import com.vincent.rsf.server.api.entity.enums.TaskType;
+import com.vincent.rsf.server.api.service.WcsService;
+import com.vincent.rsf.server.system.controller.BaseController;
+import io.swagger.annotations.Api;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/wcs")
+@Api(tags = "wcs鎺ュ彛瀵规帴")
+public class WcsController extends BaseController {
+
+    @Autowired
+    private WcsService wcsService;
+
+//    @ApiOperation(value = "wcs鐢熸垚鍏ュ簱浠诲姟鎺ュ彛")
+    @PostMapping("/create/in/task")
+    public R createInTask(@RequestBody TaskInParam param) {
+        if (Cools.isEmpty(param.getIoType())) {
+            return R.error("鍏ュ嚭搴撶被鍨嬩笉鑳戒负绌�");
+        }
+        if (Cools.isEmpty(param.getSourceStaNo())) {
+            return R.error("婧愮珯缂栧彿涓嶈兘涓虹┖");
+        }
+        if (Cools.isEmpty(param.getBarcode()) && param.getIoType().equals(TaskType.TASK_TYPE_IN.type)) {
+            return R.error("鏉$爜涓嶈兘涓虹┖");
+        }
+        if (Cools.isEmpty(param.getLocType1())){
+            return R.error("楂樹綆妫�娴嬩俊鍙蜂笉鑳戒负绌�");
+        }
+        InTaskMsgDto msgDto = wcsService.createInTask(param,getLoginUserId());
+        return R.ok(msgDto);
+
+
+    }
+
+
+}
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/params/TaskInParam.java b/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/params/TaskInParam.java
new file mode 100644
index 0000000..ecb50ac
--- /dev/null
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/params/TaskInParam.java
@@ -0,0 +1,15 @@
+package com.vincent.rsf.server.api.controller.params;
+
+import lombok.Data;
+
+@Data
+public class TaskInParam {
+
+    private Integer ioType;  //浣滀笟绫诲瀷
+    private Integer sourceStaNo; //浣滀笟绔欑偣 or 鏉ユ簮绔欑偣
+    private String barcode; //瀹瑰櫒鏉$爜
+    private Integer locType1; //搴撲綅绫诲瀷
+    private Integer area;
+//    private Integer locType2; //搴撲綅绫诲瀷
+//    private Integer locType3; //搴撲綅绫诲瀷
+}
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/MobileController.java b/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/pda/MobileController.java
similarity index 99%
rename from rsf-server/src/main/java/com/vincent/rsf/server/api/controller/MobileController.java
rename to rsf-server/src/main/java/com/vincent/rsf/server/api/controller/pda/MobileController.java
index 7471043..eed0ce4 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/MobileController.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/pda/MobileController.java
@@ -1,4 +1,4 @@
-package com.vincent.rsf.server.api.controller;
+package com.vincent.rsf.server.api.controller.pda;
 
 import com.vincent.rsf.framework.common.R;
 import com.vincent.rsf.framework.exception.CoolException;
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/pda/pdaOutStockController.java b/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/pda/pdaOutStockController.java
new file mode 100644
index 0000000..8d42824
--- /dev/null
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/pda/pdaOutStockController.java
@@ -0,0 +1,28 @@
+package com.vincent.rsf.server.api.controller.pda;
+
+import com.vincent.rsf.framework.common.R;
+import com.vincent.rsf.server.api.service.PdaOutStockService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Map;
+
+@Api(tags = "PDA鍑哄簱鎿嶄綔鎺ュ彛")
+@RequestMapping("/pda")
+@RestController
+public class pdaOutStockController {
+
+    @Autowired
+    private PdaOutStockService pdaOutStockService;
+
+    @PreAuthorize("hasAuthority('manager:task:list')")
+    @GetMapping("/outStockTaskItem/{barcode}")
+    @ApiOperation("蹇�熸嫞璐ф煡璇�")
+    public R getOutStockTaskItem(@PathVariable String barcode) {
+
+        return pdaOutStockService.getOutStockTaskItem(barcode);
+    }
+}
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/api/entity/dto/InTaskMsgDto.java b/rsf-server/src/main/java/com/vincent/rsf/server/api/entity/dto/InTaskMsgDto.java
new file mode 100644
index 0000000..c4ba4e6
--- /dev/null
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/api/entity/dto/InTaskMsgDto.java
@@ -0,0 +1,16 @@
+package com.vincent.rsf.server.api.entity.dto;
+
+import lombok.Data;
+
+@Data
+public class InTaskMsgDto {
+    private Integer sourceStaNo;
+
+    private Integer staNo;
+
+    private Integer deviceNo;
+
+    private String locNo;
+
+    private String workNo;
+}
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/api/entity/dto/LocTypeDto.java b/rsf-server/src/main/java/com/vincent/rsf/server/api/entity/dto/LocTypeDto.java
new file mode 100644
index 0000000..38565a6
--- /dev/null
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/api/entity/dto/LocTypeDto.java
@@ -0,0 +1,21 @@
+package com.vincent.rsf.server.api.entity.dto;
+
+import com.vincent.rsf.server.api.controller.params.TaskInParam;
+import lombok.Data;
+
+@Data
+public class LocTypeDto {
+    // 楂樹綆绫诲瀷{0:鏈煡,1:浣庡簱浣�,2:楂樺簱浣峿
+    private Integer locType1;
+
+    // 瀹界獎绫诲瀷{0:鏈煡,1:绐勫簱浣�,2:瀹藉簱浣峿
+    private Integer locType2;
+
+    // 杞婚噸绫诲瀷{0:鏈煡,1:杞诲簱浣�,2:閲嶅簱浣峿
+    private Integer locType3;
+
+    public LocTypeDto(TaskInParam param) {
+         this.locType1 = param.getLocType1(); // 楂樺簱浣�
+
+    }
+}
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/api/service/PdaOutStockService.java b/rsf-server/src/main/java/com/vincent/rsf/server/api/service/PdaOutStockService.java
new file mode 100644
index 0000000..068d155
--- /dev/null
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/api/service/PdaOutStockService.java
@@ -0,0 +1,9 @@
+package com.vincent.rsf.server.api.service;
+
+import com.vincent.rsf.framework.common.R;
+
+import java.util.Map;
+
+public interface PdaOutStockService {
+    R getOutStockTaskItem(String barcode);
+}
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/api/service/WcsService.java b/rsf-server/src/main/java/com/vincent/rsf/server/api/service/WcsService.java
new file mode 100644
index 0000000..433194a
--- /dev/null
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/api/service/WcsService.java
@@ -0,0 +1,8 @@
+package com.vincent.rsf.server.api.service;
+
+import com.vincent.rsf.server.api.entity.dto.InTaskMsgDto;
+import com.vincent.rsf.server.api.controller.params.TaskInParam;
+
+public interface WcsService {
+    InTaskMsgDto createInTask(TaskInParam param, Long loginUserId);
+}
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/PdaOutStockServiceImpl.java b/rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/PdaOutStockServiceImpl.java
new file mode 100644
index 0000000..80f0f4d
--- /dev/null
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/PdaOutStockServiceImpl.java
@@ -0,0 +1,45 @@
+package com.vincent.rsf.server.api.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.vincent.rsf.framework.common.R;
+import com.vincent.rsf.server.api.service.PdaOutStockService;
+import com.vincent.rsf.server.manager.entity.AsnOrder;
+import com.vincent.rsf.server.manager.entity.Task;
+import com.vincent.rsf.server.manager.entity.TaskItem;
+import com.vincent.rsf.server.manager.service.AsnOrderService;
+import com.vincent.rsf.server.manager.service.OutStockService;
+import com.vincent.rsf.server.manager.service.TaskItemService;
+import com.vincent.rsf.server.manager.service.TaskService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+@Service
+public class PdaOutStockServiceImpl implements PdaOutStockService {
+
+    @Resource
+    private TaskService taskService;
+    @Resource
+    private TaskItemService taskItemService;
+
+    @Override
+    public R getOutStockTaskItem(String barcode) {
+        LambdaQueryWrapper<Task> lambdaQueryWrapper = new LambdaQueryWrapper<>();
+        lambdaQueryWrapper.eq(Task::getBarcode, barcode);
+        Task task = taskService.getOne(lambdaQueryWrapper);
+        if (null == task){
+            return R.error("鏈煡璇㈠埌鐩稿叧浠诲姟");
+        }
+        List<TaskItem> taskItems = taskItemService.list(new LambdaQueryWrapper<TaskItem>().eq(TaskItem::getTaskId, task.getId()));
+        if (null == taskItems || taskItems.size() <= 0){
+            return R.error("浠诲姟鍑洪敊锛屾湭鏌ヨ鍒扮浉鍏充换鍔℃槑缁�");
+        }
+
+
+        return R.ok(taskItems);
+    }
+}
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/WcsServiceImpl.java b/rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/WcsServiceImpl.java
new file mode 100644
index 0000000..b2e2d4f
--- /dev/null
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/WcsServiceImpl.java
@@ -0,0 +1,561 @@
+package com.vincent.rsf.server.api.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.vincent.rsf.framework.common.Cools;
+import com.vincent.rsf.framework.exception.CoolException;
+import com.vincent.rsf.server.api.entity.dto.InTaskMsgDto;
+import com.vincent.rsf.server.api.entity.dto.LocTypeDto;
+import com.vincent.rsf.server.api.controller.params.TaskInParam;
+import com.vincent.rsf.server.api.entity.enums.OrderType;
+import com.vincent.rsf.server.api.entity.enums.TaskStsType;
+import com.vincent.rsf.server.api.entity.enums.TaskType;
+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.manager.entity.*;
+import com.vincent.rsf.server.manager.enums.PakinIOStatus;
+import com.vincent.rsf.server.manager.service.*;
+import com.vincent.rsf.server.manager.service.impl.LocServiceImpl;
+import com.vincent.rsf.server.manager.utils.LocManageUtil;
+import com.vincent.rsf.server.system.constant.SerialRuleCode;
+import com.vincent.rsf.server.system.enums.LocStsType;
+import com.vincent.rsf.server.system.utils.SerialRuleUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+@Service
+public class WcsServiceImpl implements WcsService {
+    @Autowired
+    private DeviceSiteService deviceSiteService;
+    @Autowired
+    private WaitPakinService waitPakinService;
+    @Autowired
+    private DeviceBindService deviceBindService;
+    @Autowired
+    private LocServiceImpl locService;
+    @Autowired
+    private LocItemService locItemService;
+    @Autowired
+    private SlaveProperties slaveProperties;
+    @Autowired
+    private WarehouseAreasService warehouseAreasService;
+    @Autowired
+    private TaskService taskService;
+    @Autowired
+    private TaskItemService taskItemService;
+    @Autowired
+    private WaitPakinItemService waitPakinItemService;
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public InTaskMsgDto createInTask(TaskInParam param, Long loginUserId) {
+        // 鑾峰彇搴撲綅鍙�
+        InTaskMsgDto locNo = getLocNo(param);
+
+        // 楠岃瘉璁惧绔欑偣
+        DeviceSite deviceSite = validateDeviceSite(param);
+
+        // 楠岃瘉缁勬嫋鐘舵��
+        WaitPakin waitPakin = validateWaitPakin(param.getBarcode());
+
+        // 鐢熸垚浠诲姟缂栫爜
+        String ruleCode = generateTaskCode();
+
+        // 鍒涘缓骞朵繚瀛樹换鍔�
+        Task task = createTask(ruleCode, locNo.getLocNo(), waitPakin.getBarcode(),
+                deviceSite.getDeviceSite(), param.getSourceStaNo().toString(), loginUserId);
+
+        // 鏇存柊搴撲綅鐘舵��
+        updateLocStatus(task.getTargLoc(), waitPakin.getBarcode());
+
+        // 鑾峰彇骞堕獙璇佺粍鎷栨槑缁�
+        List<WaitPakinItem> waitPakinItems = getWaitPakinItems(waitPakin.getId());
+
+        // 鍒涘缓骞朵繚瀛樹换鍔℃槑缁�
+        saveTaskItems(task.getId(), waitPakinItems, loginUserId);
+
+        // 鏇存柊缁勬墭鐘舵��
+        updateWaitPakinStatus(param.getBarcode(), loginUserId);
+
+        // 璁剧疆宸ヤ綔鍗曞彿骞惰繑鍥�
+        locNo.setWorkNo(ruleCode);
+        return locNo;
+    }
+
+    /**
+     * 楠岃瘉璁惧绔欑偣
+     */
+    private DeviceSite validateDeviceSite(TaskInParam param) {
+        DeviceSite deviceSite = deviceSiteService.getOne(new LambdaQueryWrapper<DeviceSite>()
+                .eq(DeviceSite::getSite, param.getSourceStaNo())
+                .eq(DeviceSite::getType, param.getIoType()));
+
+        if (Objects.isNull(deviceSite)) {
+            throw new CoolException("绔欑偣涓嶅瓨鍦紒锛�");
+        }
+        return deviceSite;
+    }
+
+    /**
+     * 楠岃瘉缁勬嫋鐘舵��
+     */
+    private WaitPakin validateWaitPakin(String barcode) {
+        WaitPakin waitPakin = waitPakinService.getOne(new LambdaQueryWrapper<WaitPakin>()
+                .eq(WaitPakin::getBarcode, barcode)
+                .eq(WaitPakin::getIoStatus, Short.parseShort(PakinIOStatus.PAKIN_IO_STATUS_DONE.val)));
+
+        if (Cools.isEmpty(waitPakin)) {
+            throw new CoolException("璇锋鏌ョ粍鎷栫姸鎬佹槸鍚﹀畬鎴愶紒锛�");
+        }
+        return waitPakin;
+    }
+
+    /**
+     * 鐢熸垚浠诲姟缂栫爜
+     */
+    private String generateTaskCode() {
+        String ruleCode = SerialRuleUtils.generateRuleCode(SerialRuleCode.SYS_TASK_CODE, null);
+        if (StringUtils.isBlank(ruleCode)) {
+            throw new CoolException("缂栫爜閿欒锛氳纭缂栫爜銆孲YS_TASK_CODE銆嶆槸鍚﹀凡鐢熸垚!!");
+        }
+        return ruleCode;
+    }
+
+    /**
+     * 鍒涘缓骞朵繚瀛樹换鍔�
+     */
+    private Task createTask(String ruleCode, String targetLoc, String barcode,
+                            String targetSite, String sourceSiteNo, Long loginUserId) {
+        Task task = new Task();
+        task.setTaskCode(ruleCode)
+                .setTaskStatus(TaskStsType.GENERATE_IN.id.shortValue())
+                .setTaskType(TaskType.TASK_TYPE_IN.type.shortValue())
+                .setTargLoc(targetLoc)
+                .setBarcode(barcode)
+                .setTargSite(targetSite)
+                .setCreateBy(loginUserId)
+                .setUpdateBy(loginUserId)
+                .setOrgSite(sourceSiteNo);
+
+        if (!taskService.save(task)) {
+            throw new CoolException("浠诲姟淇濆瓨澶辫触锛侊紒");
+        }
+        return task;
+    }
+
+    /**
+     * 鏇存柊搴撲綅鐘舵��
+     */
+    private void updateLocStatus(String locCode, String barcode) {
+        boolean updated = locService.update(new LambdaUpdateWrapper<Loc>()
+                .eq(Loc::getCode, locCode)
+                .set(Loc::getUseStatus, LocStsType.LOC_STS_TYPE_S.type)
+                .set(Loc::getBarcode, barcode));
+
+        if (!updated) {
+            throw new CoolException("搴撲綅棰勭害澶辫触锛侊紒");
+        }
+    }
+
+    /**
+     * 鑾峰彇骞堕獙璇佺粍鎷栨槑缁�
+     */
+    private List<WaitPakinItem> getWaitPakinItems(Long pakinId) {
+        List<WaitPakinItem> waitPakinItems = waitPakinItemService.list(
+                new LambdaQueryWrapper<WaitPakinItem>().eq(WaitPakinItem::getPakinId, pakinId));
+
+        if (waitPakinItems.isEmpty()) {
+            throw new CoolException("鏁版嵁閿欒锛氱粍鎷栨槑缁嗕笉瀛樺湪");
+        }
+        return waitPakinItems;
+    }
+
+    /**
+     * 鍒涘缓骞朵繚瀛樹换鍔℃槑缁�
+     */
+    private void saveTaskItems(Long taskId, List<WaitPakinItem> waitPakinItems, Long loginUserId) {
+        List<TaskItem> taskItems = waitPakinItems.stream().map(item -> {
+            TaskItem taskItem = new TaskItem();
+            BeanUtils.copyProperties(item, taskItem);
+
+            return taskItem.setTaskId(taskId)
+                    .setOrderType(OrderType.ORDER_RECEIPT.type)
+                    .setSource(item.getId())
+                    .setTrackCode(item.getTrackCode())
+                    .setCreateBy(loginUserId)
+                    .setUpdateBy(loginUserId)
+                    .setOrderId(item.getAsnId())
+                    .setOrderItemId(item.getAsnItemId());
+        }).collect(Collectors.toList());
+
+        if (!taskItemService.saveBatch(taskItems)) {
+            throw new CoolException("浠诲姟鏄庣粏淇濆瓨澶辫触锛侊紒");
+        }
+    }
+
+    /**
+     * 鏇存柊缁勬墭鐘舵��
+     */
+    private void updateWaitPakinStatus(String barcode, Long loginUserId) {
+        boolean updated = waitPakinService.update(new LambdaUpdateWrapper<WaitPakin>()
+                .eq(WaitPakin::getBarcode, barcode)
+                .set(WaitPakin::getUpdateBy, loginUserId)
+                .set(WaitPakin::getCreateBy, loginUserId)
+                .set(WaitPakin::getIoStatus, PakinIOStatus.PAKIN_IO_STATUS_TASK_EXCE.val));
+
+        if (!updated) {
+            throw new CoolException("缁勬墭鐘舵�佷慨鏀瑰け璐ワ紒锛�");
+        }
+    }
+
+//    @Override
+//    public InTaskMsgDto createInTask(TaskInParam param, Long loginUserId) {
+//        InTaskMsgDto locNo = getLocNo(param);
+//        DeviceSite deviceSite = deviceSiteService.getOne(new LambdaQueryWrapper<DeviceSite>()
+//                .eq(DeviceSite::getSite, param.getSourceStaNo())
+//                .eq(DeviceSite::getType,param.getIoType())
+//        );
+//        if (Objects.isNull(deviceSite)) {
+//            throw new CoolException("绔欑偣涓嶅瓨鍦紒锛�");
+//        }
+//
+//        WaitPakin waitPakin = waitPakinService.getOne(new LambdaQueryWrapper<WaitPakin>()
+//                .eq(WaitPakin::getBarcode, param.getBarcode())
+//                .eq(WaitPakin::getIoStatus, Short.parseShort(PakinIOStatus.PAKIN_IO_STATUS_DONE.val)));
+//        if (Cools.isEmpty(waitPakin)) {
+//            throw new CoolException("璇锋鏌ョ粍鎷栫姸鎬佹槸鍚﹀畬鎴愶紒锛�");
+//        }
+//
+//            List<TaskItem> taskItems = new ArrayList<>();
+//            String ruleCode = SerialRuleUtils.generateRuleCode(SerialRuleCode.SYS_TASK_CODE, null);
+//            if (StringUtils.isBlank(ruleCode)) {
+//                throw new CoolException("缂栫爜閿欒锛氳纭缂栫爜銆孲YS_TASK_CODE銆嶆槸鍚﹀凡鐢熸垚!!");
+//            }
+//            Task task = new Task();
+//            task.setTaskCode(ruleCode)
+//                    .setTaskStatus(TaskStsType.GENERATE_IN.id.shortValue())
+//                    .setTaskType(TaskType.TASK_TYPE_IN.type.shortValue())
+//                    .setTargLoc(locNo.getLocNo())
+//                    .setBarcode(waitPakin.getBarcode())
+//                    .setTargSite(deviceSite.getDeviceSite())
+//                    .setCreateBy(loginUserId)
+//                    .setUpdateBy(loginUserId)
+//                    .setOrgSite(param.getSourceStaNo().toString());
+//
+//
+//
+//
+//            if (!taskService.save(task)) {
+//                throw new CoolException("浠诲姟淇濆瓨澶辫触锛侊紒");
+//            }
+//            if (!locService.update(new LambdaUpdateWrapper<Loc>().eq(Loc::getCode, task.getTargLoc())
+//                    .set(Loc::getUseStatus, LocStsType.LOC_STS_TYPE_S.type).set(Loc::getBarcode, waitPakin.getBarcode()))) {
+//                throw new CoolException("搴撲綅棰勭害澶辫触锛侊紒");
+//            }
+//            /**鑾峰彇缁勬嫋鏄庣粏**/
+//            List<WaitPakinItem> waitPakinItems = waitPakinItemService.list(new LambdaQueryWrapper<WaitPakinItem>().eq(WaitPakinItem::getPakinId, waitPakin.getId()));
+//            if (waitPakinItems.isEmpty()) {
+//                throw new CoolException("鏁版嵁閿欒锛氱粍鎷栨槑缁嗕笉瀛樺湪");
+//            }
+//            waitPakinItems.forEach(item -> {
+//                TaskItem taskItem = new TaskItem();
+//                BeanUtils.copyProperties(item, taskItem);
+////                AsnOrder order = asnOrderService.getOne(new LambdaQueryWrapper<AsnOrder>().eq(AsnOrder::getId, item.getAsnId()));
+////                if (Objects.isNull(order)) {
+////                    throw new CoolException("鏁版嵁閿欒: 鍗曟嵁涓嶅瓨鍦紒锛�");
+////                }
+//                taskItem.setTaskId(task.getId())
+//                        .setOrderType(OrderType.ORDER_RECEIPT.type)
+//                        .setSource(item.getId())
+//                        .setTrackCode(item.getTrackCode())
+//                        .setCreateBy(loginUserId)
+//                        .setUpdateBy(loginUserId)
+//                        .setOrderId(item.getAsnId())
+//                        .setOrderItemId(item.getAsnItemId());
+//                taskItems.add(taskItem);
+//            });
+//            if (!taskItemService.saveBatch(taskItems)) {
+//                throw new CoolException("浠诲姟鏄庣粏淇濆瓨澶辫触锛侊紒");
+//            }
+//
+//
+//        if (!waitPakinService.update(new LambdaUpdateWrapper<WaitPakin>()
+//                .eq(WaitPakin::getBarcode, param.getBarcode())
+//                .set(WaitPakin::getUpdateBy, loginUserId)
+//                .set(WaitPakin::getCreateBy, loginUserId)
+//                .set(WaitPakin::getIoStatus, PakinIOStatus.PAKIN_IO_STATUS_TASK_EXCE.val))) {
+//            throw new CoolException("缁勬墭鐘舵�佷慨鏀瑰け璐ワ紒锛�");
+//        }
+//        locNo.setWorkNo(ruleCode);
+//        return locNo;
+//    }
+
+    public InTaskMsgDto getLocNo(TaskInParam param) {
+        String matnr = null; String batch = null;
+        List<WaitPakin> waitPakins = waitPakinService.list(new LambdaQueryWrapper<WaitPakin>().eq(WaitPakin::getBarcode, param.getBarcode()));
+        if (Cools.isEmpty(waitPakins) && param.getIoType().equals(TaskType.TASK_TYPE_IN.type)) {
+            throw new CoolException("鏈壘鍒扮粍鎵樹俊鎭紝璇风粍鎵�");
+        }else if (!Cools.isEmpty(waitPakins)) {
+            matnr = waitPakins.get(0).getCode();
+            batch = waitPakins.get(0).getCode();
+        }
+        List<DeviceSite> deviceSites = deviceSiteService.list(new LambdaQueryWrapper<DeviceSite>()
+                .eq(DeviceSite::getSite, param.getSourceStaNo())
+                .eq(DeviceSite::getType,param.getIoType())
+        );
+        if (Cools.isEmpty(deviceSites)) {
+            throw new CoolException("鏈壘鍒扮珯鐐硅矾寰勪俊鎭�");
+        }
+        WarehouseAreas warehouseArea = warehouseAreasService.getById(param.getArea());
+        if (Cools.isEmpty(warehouseArea)) {
+            throw new CoolException("鏈壘鍒版墍灞炲簱鍖轰俊鎭�");
+        }
+        LocTypeDto locTypeDto = new LocTypeDto(param);
+        InTaskMsgDto dto = null;
+        switch (warehouseArea.getType()) {
+            case "CRN": //鍫嗗灈鏈�
+                dto = getLocNoCrn(param.getArea(), param.getSourceStaNo(), matnr,batch, locTypeDto, 0, param.getIoType());
+                break;
+            case "SXC": //鍥涘悜搴�
+                break;
+            case "CTU": //鍥涘悜搴�
+                break;
+        }
+        return dto;
+    }
+
+    private InTaskMsgDto getLocNoCrn(Integer area,Integer sourceStaNo, String matnr, String batch,LocTypeDto locTypeDto, int times,Integer ioType){
+        if (Cools.isEmpty(matnr)) {  //鐗╂枡鍙�
+            matnr = "";
+        }
+        if (Cools.isEmpty(batch)) {  //鎵规
+            batch = "";
+        }
+        // 鍒濆鍖栧弬鏁�
+        int deviceNo = 0;      //鍫嗗灈鏈哄彿
+        int nearRow = 0;    //鏈�娴呭簱浣嶆帓
+        int curRow = 0;     //鏈�娣卞簱浣嶆帓
+        int rowCount = 0;   //杞杞
+        Loc loc = null;     // 鐩爣搴撲綅
+
+        InTaskMsgDto inTaskMsgDto = new InTaskMsgDto();
+        DeviceBind deviceBind = deviceBindService.getById(LocUtils.getAreaType(sourceStaNo));
+        if (Cools.isEmpty(deviceBind)) {
+            throw new CoolException("鏁版嵁寮傚父锛岃鑱旂郴绠$悊鍛�===>搴撲綅瑙勫垯鏈煡");
+        }
+        int sRow = deviceBind.getStartRow();
+        int eRow = deviceBind.getEndRow();
+        int deviceQty = deviceBind.getDeviceQty();
+
+
+        // ===============>>>> 寮�濮嬫墽琛�
+        curRow = deviceBind.getCurrentRow();
+
+        //姝ょ▼搴忕敤浜庝紭鍖栧爢鍨涙満寮傚父鏃剁殑杩愯鏃堕棿
+        for (int i = times; i <= deviceQty * 2; i++) {
+            int[] locNecessaryParameters = LocUtils.LocNecessaryParameters(deviceBind, curRow, deviceQty);
+            curRow = locNecessaryParameters[1];
+            deviceNo = locNecessaryParameters[2];
+            rowCount = locNecessaryParameters[0];
+            nearRow = locNecessaryParameters[3];
+            break;
+        }
+        if (nearRow == 0) {
+            throw new CoolException("鏃犲彲鐢ㄥ爢鍨涙満");
+        }
+        //鍏ュ簱闈犺繎鎽嗘斁
+        if (ioType== 1 && deviceBind.getBeSimilar().equals("1") && !Cools.isEmpty(matnr)) {
+            if (nearRow != curRow) {
+                List<LocItem> locItems = locItemService.list(new LambdaQueryWrapper<LocItem>().eq(LocItem::getMatnrCode, matnr));
+                for (LocItem locItem : locItems) {
+                    Loc loc1 = locService.getById(locItem.getLocId());
+                    if (LocUtils.isShallowLoc(slaveProperties, loc1.getCode())) {
+                        continue;
+                    }
+                    String shallowLocNo = LocUtils.getShallowLoc(slaveProperties, loc1.getCode());
+                    // 妫�娴嬬洰鏍囧簱浣嶆槸鍚︿负绌哄簱浣�
+                    Loc shallowLoc = locService.getOne(new LambdaQueryWrapper<Loc>().eq(Loc::getCode,shallowLocNo));
+                    if (shallowLoc != null && shallowLoc.getUseStatus().equals("O")) {
+                        if (LocUtils.locMoveCheckLocTypeComplete(shallowLoc, locTypeDto)) {
+                                loc = shallowLoc;
+                                deviceNo = shallowLoc.getDeviceNo();
+                                break;
+
+                        }
+                    }
+                }
+            }
+        }
+
+//        // 闈犺繎鎽嗘斁瑙勫垯 --- 绌烘墭 //浜掗�氱増
+//        if (ioType == 10 && deviceBind.getEmptySimilar().equals("1")) {
+//            List<LocMast> locMasts = locMastService.selectList(new EntityWrapper<LocMast>()
+//                    .eq("loc_sts", "D").ge("row1", sRow).le("row1", eRow).eq("whs_type", rowLastnoType.getType().longValue()));
+//            if (!locMasts.isEmpty()) {
+//                for (LocMast loc : locMasts) {
+//                    if (Utils.isShallowLoc(slaveProperties, loc.getLocNo())) {
+//                        continue;
+//                    }
+//                    String shallowLocNo = Utils.getShallowLoc(slaveProperties, loc.getLocNo());
+//                    // 妫�娴嬬洰鏍囧簱浣嶆槸鍚︿负绌哄簱浣�
+//                    LocMast shallowLoc = locMastService.selectById(shallowLocNo);
+//                    if (shallowLoc != null && shallowLoc.getLocSts().equals("O")) {
+//                        if (VersionUtils.locMoveCheckLocTypeComplete(shallowLoc, locTypeDto)) {
+//                            if (basCrnpService.checkSiteError(shallowLoc.getCrnNo(), true)) {
+//                                locMast = shallowLoc;
+//                                crnNo = locMast.getCrnNo();
+//                                break;
+//                            }
+//                        }
+//                    }
+//                }
+//            }
+//        }
+        //鏌ユ壘璺緞
+        DeviceSite deviceSite = deviceSiteService.getOne(new LambdaQueryWrapper<DeviceSite>()
+                .eq(DeviceSite::getType, ioType)
+                .eq(DeviceSite::getSite, sourceStaNo)
+                .eq(DeviceSite::getDeviceCode, deviceNo)
+        );
+        if (Cools.isEmpty(deviceSite)){
+            deviceNo = 0;
+        }else {
+            inTaskMsgDto.setStaNo(Integer.parseInt(deviceSite.getDeviceSite()));
+        }
+
+        //鏇存柊褰撳墠鎺�
+        deviceBind.setCurrentRow(curRow);
+        deviceBindService.updateById(deviceBind);
+
+        // 寮�濮嬫煡鎵惧簱浣� ==============================>>
+
+        // 1.鎸夎鍒欐煡鎵惧簱浣�
+        if (Cools.isEmpty(loc) && deviceNo != 0) {
+            List<Loc> locMasts = null;
+            locMasts = locService.list(new LambdaQueryWrapper<Loc>()
+                    .eq(Loc::getRow, nearRow)
+                    .eq(Loc::getUseStatus, "O")
+                    .eq(Loc::getType, locTypeDto.getLocType1())
+                    .eq(Loc::getAreaId,area)
+                    .orderByAsc(Loc::getLev)
+                    .orderByAsc(Loc::getCol)
+            );
+            for (Loc locMast1 : locMasts) {
+                if (!LocUtils.locMoveCheckLocTypeComplete(locMast1, locTypeDto)) {
+                    continue;
+                }
+                String shallowLoc = LocUtils.getDeepLoc(slaveProperties, locMast1.getCode());
+                if ((ioType== 1 && deviceBind.getBeSimilar().equals("1"))) {
+                    //鐩镐技鐗╂枡鎵撳紑锛屽垽鏂繁搴撲綅鏈夋病鏈夎揣锛屾病璐у氨鏀炬繁搴撲綅锛屾湁璐у氨涓嶆搷浣�
+                    Loc locMast2 = locService.getOne(new LambdaQueryWrapper<Loc>()
+                            .eq(Loc::getRow, shallowLoc)
+                            .eq(Loc::getUseStatus, "O")
+                            .eq(Loc::getAreaId,area)
+                    );
+                    if (!Cools.isEmpty(locMast2)) {
+                        loc = locMast2;
+                        break;
+                    }
+                } else {
+                    //鐩镐技鐗╂枡鍏抽棴锛屽垽鏂繁搴撲綅鏈夋病鏈夎揣锛屾湁璐у氨鏀炬祬搴撲綅锛屾棤璐у氨涓嶆搷浣�
+                    Loc locMast2 = locService.getOne(new LambdaQueryWrapper<Loc>()
+                            .eq(Loc::getCode, shallowLoc)
+                            .in(Loc::getUseStatus, "D","F")
+                            .eq(Loc::getAreaId,area)
+                    );
+                    if (!Cools.isEmpty(locMast2)) {
+                        loc = locMast1;
+                        break;
+                    }else{
+                        locMast2 = locService.getOne(new LambdaQueryWrapper<Loc>()
+                                .eq(Loc::getCode, shallowLoc)
+                                .eq(Loc::getUseStatus, "O")
+                                .eq(Loc::getAreaId,area)
+                        );
+                        if (!Cools.isEmpty(locMast2)) {
+                            loc = locMast2;
+                            break;
+                        }
+                    }
+                }
+            }
+            if (Cools.isEmpty(loc) && deviceBind.getBeSimilar().equals("1")) {
+                for (Loc locMast1 : locMasts) {
+                    if (!LocUtils.locMoveCheckLocTypeComplete(locMast1, locTypeDto)) {
+                        continue;
+                    }
+                    if (deviceBind.getBeSimilar().equals("1")) {
+                        String shallowLoc = LocUtils.getDeepLoc(slaveProperties, locMast1.getCode());
+                        Loc locMast2 = locService.getOne(new LambdaQueryWrapper<Loc>()
+                                .eq(Loc::getCode, shallowLoc)
+                                .eq(Loc::getUseStatus, "O")
+                                .eq(Loc::getAreaId,area)
+                        );
+                        if (!Cools.isEmpty(locMast2)) {
+                            loc = locMast2;
+                            break;
+                        } else {
+                            locMast2 = locService.getOne(new LambdaQueryWrapper<Loc>()
+                                    .eq(Loc::getCode, shallowLoc)
+                                    .in(Loc::getUseStatus, "D","F")
+                                    .eq(Loc::getAreaId,area)
+                            );
+                            if (!Cools.isEmpty(locMast2)) {
+                                loc = locMast1;
+                                break;
+                            }
+                        }
+                    } else {
+                        if (!Cools.isEmpty(locMast1)) {
+                            loc = locMast1;
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+        //鏌ヨ褰撳墠搴撲綅绫诲瀷绌哄簱浣� 灏忎簬5涓垯locmast = null
+        List<Loc> locTypeLocMasts = locService.list(new LambdaQueryWrapper<Loc>()
+                .eq(Loc::getUseStatus, "O")
+                .eq(Loc::getDeviceNo, deviceNo)
+                .eq(Loc::getType, locTypeDto.getLocType1())
+                .eq(Loc::getAreaId,area)
+        );
+        if (null !=locTypeLocMasts && locTypeLocMasts.size()<=5){
+            loc = null;
+        }
+        // 閫掑綊鏌ヨ
+        if (Cools.isEmpty(loc) || !loc.getUseStatus().equals("O")) {
+            // 褰撳墠宸烽亾鏃犵┖搴撲綅鏃讹紝閫掑綊璋冩暣鑷充笅涓�宸烽亾锛屾绱㈠叏閮ㄥ贩閬撴棤鏋滃悗锛岃烦鍑洪�掑綊
+            if (times < rowCount * 2) {
+                times = times + 1;
+                return getLocNoCrn(area,sourceStaNo,matnr,batch,locTypeDto,times, ioType);
+
+            }
+            // 2.搴撲綅褰撳墠鎵�灞炲昂瀵告棤绌哄簱浣嶆椂锛岃皟鏁村昂瀵稿弬鏁帮紝鍚戜笂鍏煎妫�绱㈠簱浣�
+            if (locTypeDto.getLocType1() < 3) {
+                int i = locTypeDto.getLocType1() + 1;
+                locTypeDto.setLocType1(i);
+                return getLocNoCrn(area,sourceStaNo,matnr,batch,locTypeDto,0, ioType);
+            }
+            throw new CoolException("娌℃湁绌哄簱浣�");
+        }
+        String locNo = loc.getCode();
+
+        // 杩斿洖dto
+        inTaskMsgDto.setDeviceNo(deviceNo);
+        inTaskMsgDto.setSourceStaNo(sourceStaNo);
+//        inTaskMsgDto.setStaNo();
+        inTaskMsgDto.setLocNo(locNo);
+        return inTaskMsgDto;
+    }
+}
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/api/utils/LocUtils.java b/rsf-server/src/main/java/com/vincent/rsf/server/api/utils/LocUtils.java
new file mode 100644
index 0000000..dc5064e
--- /dev/null
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/api/utils/LocUtils.java
@@ -0,0 +1,166 @@
+package com.vincent.rsf.server.api.utils;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.vincent.rsf.framework.common.Arith;
+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.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 java.util.List;
+
+public class LocUtils {
+
+    /**
+     * 鑾峰彇 娴呭簱浣嶅搴旂殑娣卞簱浣嶅彿
+     */
+    public static String getDeepLoc(SlaveProperties slaveProperties, String shallowLoc) {
+        int row = getRow(shallowLoc);
+        int remainder = (int) Arith.remainder(row, slaveProperties.getGroupCount());
+        int targetRow;
+        if (remainder == 2) {
+            targetRow = row - 1;
+        } else if (remainder == 3) {
+            targetRow = row + 1;
+        } else {
+            throw new CoolException(shallowLoc + "涓嶆槸娴呭簱浣嶏紝绯荤粺绻佸繖");
+        }
+        return zerofill(String.valueOf(targetRow), 2) + shallowLoc.substring(2);
+    }
+
+    /**
+     * 鑾峰彇 娣卞簱浣嶅搴旂殑娴呭簱浣嶅彿
+     */
+    public static String getShallowLoc(SlaveProperties slaveProperties, String deepLoc) {
+        int row = getRow(deepLoc);
+        int remainder = (int) Arith.remainder(row, slaveProperties.getGroupCount());
+        int shallowRow = remainder == 1 ? (row + 1) : (row - 1);
+        return zerofill(String.valueOf(shallowRow), 2) + deepLoc.substring(2);
+    }
+
+    /**
+     * 鍒ゆ柇鏄惁涓烘祬搴撲綅
+     */
+    public static boolean isShallowLoc(SlaveProperties slaveProperties, String locNo) {
+        if (slaveProperties.isDoubleDeep()) {
+            int row = getRow(locNo);
+            return !slaveProperties.getDoubleLocs().contains(row);
+        } else {
+            return false;
+        }
+    }
+
+    //鑾峰彇绔欑偣瀵瑰簲鐨勫簱绫诲瀷
+    public static Long getAreaType(Integer sourceStaNo) {
+        DeviceBindService rowLastnoService = SpringUtils.getBean(DeviceBindService.class);
+        List<DeviceBind> deviceBinds = rowLastnoService.list(new LambdaQueryWrapper<DeviceBind>());
+        for (DeviceBind deviceBind : deviceBinds) {
+            String[] staNoList = deviceBind.getStaList().split(";");
+            for (String staNo : staNoList) {
+                if (staNo.equals(sourceStaNo.toString())) {
+                    return deviceBind.getId();
+                }
+            }
+        }
+        return 0L;
+    }
+
+    //搴撲綅鎺掑彿鍒嗛厤
+    public static int[] LocNecessaryParameters(DeviceBind deviceBind, Integer curRow, Integer crnNumber) {
+
+      return LocNecessaryParametersDoubleExtension(curRow, crnNumber); //宸插畬鍠�
+
+
+    }
+
+    //缁忓吀鍙屼几搴撲綅
+    public static int[] LocNecessaryParametersDoubleExtension( Integer curRow, Integer crnNumber) {
+        int[] necessaryParameters = new int[]{0, 0, 0, 0};
+
+        necessaryParameters[0] = crnNumber; // 杞娆℃暟
+        //婊℃澘姝e父鍏ュ簱
+        if (curRow.equals(crnNumber * 4)) {
+            necessaryParameters[1] = 1;    //curRow   鏈�娣卞簱浣嶆帓
+            necessaryParameters[2] = 1;     //crnNo     鍫嗗灈鏈哄彿
+            necessaryParameters[3] = 2;    //nearRow  鏈�娴呭簱浣嶆帓
+        } else if (curRow.equals(crnNumber * 4 - 3)) {
+            necessaryParameters[1] = 4;    //curRow   鏈�娣卞簱浣嶆帓
+            necessaryParameters[2] = 1;     //crnNo     鍫嗗灈鏈哄彿
+            necessaryParameters[3] = 3;    //nearRow  鏈�娴呭簱浣嶆帓
+        } else {
+            curRow = curRow + 4;
+            if (curRow < 1 || curRow > (crnNumber * 4)) {
+                throw new CoolException("搴撲綅鎺掑彿寮傚父锛氭帓鍙凤細" + curRow);
+            }
+            if ((curRow - 1) % 4 == 0) {
+                necessaryParameters[1] = curRow;    //curRow   鏈�娣卞簱浣嶆帓
+                necessaryParameters[2] = (curRow + 3) / 4;     //crnNo     鍫嗗灈鏈哄彿
+                necessaryParameters[3] = curRow + 1;    //nearRow  鏈�娴呭簱浣嶆帓
+            } else if (curRow % 4 == 0) {
+                necessaryParameters[1] = curRow;    //curRow   鏈�娣卞簱浣嶆帓
+                necessaryParameters[2] = curRow / 4;     //crnNo     鍫嗗灈鏈哄彿
+                necessaryParameters[3] = curRow - 1;    //nearRow  鏈�娴呭簱浣嶆帓
+            } else {
+                throw new CoolException("搴撲綅鎺掑彿寮傚父锛氭帓鍙凤細" + curRow);
+            }
+        }
+
+        return necessaryParameters;
+    }
+
+    /**
+     * 閫氳繃搴撲綅鍙疯幏鍙� 鎺�
+     */
+    public static int getRow(String locNo) {
+        if (!Cools.isEmpty(locNo)) {
+            return Integer.parseInt(locNo.substring(0, 2));
+        }
+        throw new RuntimeException("搴撲綅瑙f瀽寮傚父");
+    }
+
+    /**
+     * 閫氳繃搴撲綅鍙疯幏鍙� 鍒�
+     */
+    public static int getBay(String locNo) {
+        if (!Cools.isEmpty(locNo)) {
+            return Integer.parseInt(locNo.substring(2, 5));
+        }
+        throw new RuntimeException("搴撲綅瑙f瀽寮傚父");
+    }
+
+    /**
+     * 閫氳繃搴撲綅鍙疯幏鍙� 灞�
+     */
+    public static int getLev(String locNo) {
+        if (!Cools.isEmpty(locNo)) {
+            return Integer.parseInt(locNo.substring(5, 7));
+        }
+        throw new RuntimeException("搴撲綅瑙f瀽寮傚父");
+    }
+
+    /**
+     * 绫诲瀷妫�娴�
+     * 瀹屽叏妫�娴�
+     **/
+    public static boolean locMoveCheckLocTypeComplete(Loc loc, LocTypeDto dto) {
+        // 濡傛灉婧愬簱浣嶆槸楂樺簱浣嶏紝鐩爣搴撲綅鏄綆搴撲綅
+        return dto.getLocType1().equals(Integer.parseInt(loc.getType()));
+    }
+    public static String zerofill(String msg, Integer count) {
+        if (msg.length() == count) {
+            return msg;
+        } else if (msg.length() > count) {
+            return msg.substring(0, 16);
+        } else {
+            StringBuilder msgBuilder = new StringBuilder(msg);
+            for (int i = 0; i < count - msg.length(); i++) {
+                msgBuilder.insert(0, "0");
+            }
+            return msgBuilder.toString();
+        }
+    }
+}
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/api/utils/SlaveProperties.java b/rsf-server/src/main/java/com/vincent/rsf/server/api/utils/SlaveProperties.java
new file mode 100644
index 0000000..386ce11
--- /dev/null
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/api/utils/SlaveProperties.java
@@ -0,0 +1,28 @@
+package com.vincent.rsf.server.api.utils;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by vincent on 2020/8/4
+ */
+@Data
+@Configuration
+@ConfigurationProperties(prefix = "wcs-slave")
+public class SlaveProperties {
+
+    private boolean doubleDeep;
+    // 鍙屾繁搴撲綅鎺掑彿
+    private List<Integer> doubleLocs = new ArrayList<>();
+    // 宸︽繁搴撲綅鎺掑彿
+    private List<Integer> doubleLocsLeft = new ArrayList<>();
+    // 鍙虫繁搴撲綅鎺掑彿
+    private List<Integer> doubleLocsRight = new ArrayList<>();
+
+    private int groupCount;
+
+}
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/common/security/SecurityConfig.java b/rsf-server/src/main/java/com/vincent/rsf/server/common/security/SecurityConfig.java
index 3ba527a..e68c14c 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/common/security/SecurityConfig.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/common/security/SecurityConfig.java
@@ -51,7 +51,8 @@
             "/v2/api-docs/**",
             "/v3/api-docs/**",
             "/swagger-ui/**",
-            "/ws/**"
+            "/ws/**",
+            "/wcs/**"
     };
 
     @Resource
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/BasDeviceController.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/BasDeviceController.java
new file mode 100644
index 0000000..75b2717
--- /dev/null
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/BasDeviceController.java
@@ -0,0 +1,110 @@
+package com.vincent.rsf.server.manager.controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+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.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.manager.entity.BasDevice;
+import com.vincent.rsf.server.manager.service.BasDeviceService;
+import com.vincent.rsf.server.system.controller.BaseController;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletResponse;
+import java.util.*;
+
+@RestController
+public class BasDeviceController extends BaseController {
+
+    @Autowired
+    private BasDeviceService basDeviceService;
+
+    @PreAuthorize("hasAuthority('manager:basDevice:list')")
+    @PostMapping("/basDevice/page")
+    public R page(@RequestBody Map<String, Object> map) {
+        BaseParam baseParam = buildParam(map, BaseParam.class);
+        PageParam<BasDevice, BaseParam> pageParam = new PageParam<>(baseParam, BasDevice.class);
+        return R.ok().add(basDeviceService.page(pageParam, pageParam.buildWrapper(true)));
+    }
+
+    @PreAuthorize("hasAuthority('manager:basDevice:list')")
+    @PostMapping("/basDevice/list")
+    public R list(@RequestBody Map<String, Object> map) {
+        return R.ok().add(basDeviceService.list());
+    }
+
+    @PreAuthorize("hasAuthority('manager:basDevice:list')")
+    @PostMapping({"/basDevice/many/{ids}", "/basDevices/many/{ids}"})
+    public R many(@PathVariable Long[] ids) {
+        return R.ok().add(basDeviceService.listByIds(Arrays.asList(ids)));
+    }
+
+    @PreAuthorize("hasAuthority('manager:basDevice:list')")
+    @GetMapping("/basDevice/{id}")
+    public R get(@PathVariable("id") Long id) {
+        return R.ok().add(basDeviceService.getById(id));
+    }
+
+    @PreAuthorize("hasAuthority('manager:basDevice:save')")
+    @OperationLog("Create 鍩虹璁惧琛�")
+    @PostMapping("/basDevice/save")
+    public R save(@RequestBody BasDevice basDevice) {
+        basDevice.setCreateBy(getLoginUserId());
+        basDevice.setCreateTime(new Date());
+        basDevice.setUpdateBy(getLoginUserId());
+        basDevice.setUpdateTime(new Date());
+        if (!basDeviceService.save(basDevice)) {
+            return R.error("Save Fail");
+        }
+        return R.ok("Save Success").add(basDevice);
+    }
+
+    @PreAuthorize("hasAuthority('manager:basDevice:update')")
+    @OperationLog("Update 鍩虹璁惧琛�")
+    @PostMapping("/basDevice/update")
+    public R update(@RequestBody BasDevice basDevice) {
+        basDevice.setUpdateBy(getLoginUserId());
+        basDevice.setUpdateTime(new Date());
+        if (!basDeviceService.updateById(basDevice)) {
+            return R.error("Update Fail");
+        }
+        return R.ok("Update Success").add(basDevice);
+    }
+
+    @PreAuthorize("hasAuthority('manager:basDevice:remove')")
+    @OperationLog("Delete 鍩虹璁惧琛�")
+    @PostMapping("/basDevice/remove/{ids}")
+    public R remove(@PathVariable Long[] ids) {
+        if (!basDeviceService.removeByIds(Arrays.asList(ids))) {
+            return R.error("Delete Fail");
+        }
+        return R.ok("Delete Success").add(ids);
+    }
+
+    @PreAuthorize("hasAuthority('manager:basDevice:list')")
+    @PostMapping("/basDevice/query")
+    public R query(@RequestParam(required = false) String condition) {
+        List<KeyValVo> vos = new ArrayList<>();
+        LambdaQueryWrapper<BasDevice> wrapper = new LambdaQueryWrapper<>();
+        if (!Cools.isEmpty(condition)) {
+            wrapper.like(BasDevice::getId, condition);
+        }
+        basDeviceService.page(new Page<>(1, 30), wrapper).getRecords().forEach(
+                item -> vos.add(new KeyValVo(item.getId(), item.getId()))
+        );
+        return R.ok().add(vos);
+    }
+
+    @PreAuthorize("hasAuthority('manager:basDevice:list')")
+    @PostMapping("/basDevice/export")
+    public void export(@RequestBody Map<String, Object> map, HttpServletResponse response) throws Exception {
+        ExcelUtil.build(ExcelUtil.create(basDeviceService.list(), BasDevice.class), response);
+    }
+
+}
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/BasDevice.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/BasDevice.java
new file mode 100644
index 0000000..9dc0d7e
--- /dev/null
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/BasDevice.java
@@ -0,0 +1,154 @@
+package com.vincent.rsf.server.manager.entity;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import com.vincent.rsf.framework.common.Cools;
+import com.vincent.rsf.framework.common.SpringUtils;
+import com.vincent.rsf.server.system.service.UserService;
+import com.vincent.rsf.server.system.entity.User;
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+@TableName("man_bas_device")
+public class BasDevice implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * id
+     */
+    @ApiModelProperty(value= "id")
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * 璁惧鍙�
+     */
+    @ApiModelProperty(value= "璁惧鍙�")
+    private Long deviceNo;
+
+    /**
+     * 鍙叆
+     */
+    @ApiModelProperty(value= "鍙叆")
+    private String inEnable;
+
+    /**
+     * 鍙嚭
+     */
+    @ApiModelProperty(value= "鍙嚭")
+    private String outEnable;
+
+    /**
+     * 鐘舵��
+     */
+    @ApiModelProperty(value= "鐘舵��")
+    private String status;
+
+    /**
+     * 婧愭暟鎹�
+     */
+    @ApiModelProperty(value= "婧愭暟鎹�")
+    private String origin;
+
+    /**
+     * 鍒涘缓浜�
+     */
+    @ApiModelProperty(value= "鍒涘缓浜�")
+    private Long createBy;
+
+    /**
+     * 鍒涘缓鏃堕棿
+     */
+    @ApiModelProperty(value= "鍒涘缓鏃堕棿")
+    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+    private Date createTime;
+
+    /**
+     * 鏇存柊浜�
+     */
+    @ApiModelProperty(value= "鏇存柊浜�")
+    private Long updateBy;
+
+    /**
+     * 鏇存柊鏃堕棿
+     */
+    @ApiModelProperty(value= "鏇存柊鏃堕棿")
+    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+    private Date updateTime;
+
+    /**
+     * 澶囨敞
+     */
+    @ApiModelProperty(value= "澶囨敞")
+    private String memo;
+
+    public BasDevice() {}
+
+    public BasDevice(Long deviceNo,String inEnable,String outEnable,String status,String origin,Long createBy,Date createTime,Long updateBy,Date updateTime,String memo) {
+        this.deviceNo = deviceNo;
+        this.inEnable = inEnable;
+        this.outEnable = outEnable;
+        this.status = status;
+        this.origin = origin;
+        this.createBy = createBy;
+        this.createTime = createTime;
+        this.updateBy = updateBy;
+        this.updateTime = updateTime;
+        this.memo = memo;
+    }
+
+//    BasDevice basDevice = new BasDevice(
+//            null,    // 璁惧鍙�
+//            null,    // 鍙叆
+//            null,    // 鍙嚭
+//            null,    // 鐘舵��
+//            null,    // 婧愭暟鎹�
+//            null,    // 鍒涘缓浜�
+//            null,    // 鍒涘缓鏃堕棿
+//            null,    // 鏇存柊浜�
+//            null,    // 鏇存柊鏃堕棿
+//            null    // 澶囨敞
+//    );
+
+    public String getCreateTime$(){
+        if (Cools.isEmpty(this.createTime)){
+            return "";
+        }
+        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(this.createTime);
+    }
+
+    public String getUpdateTime$(){
+        if (Cools.isEmpty(this.updateTime)){
+            return "";
+        }
+        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(this.updateTime);
+    }
+
+
+
+//    public Boolean getStatusBool(){
+//        if (null == this.status){ return null; }
+//        switch (this.status){
+//            case "1":
+//                return true;
+//            case "0":
+//                return false;
+//            default:
+//                return null;
+//        }
+//    }
+
+}
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/DeviceBind.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/DeviceBind.java
index f65d4de..e10aae7 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/DeviceBind.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/DeviceBind.java
@@ -130,4 +130,5 @@
 //        }
 //    }
 
+
 }
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/Loc.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/Loc.java
index 8593a26..5b1f707 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/Loc.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/Loc.java
@@ -107,7 +107,6 @@
      */
     @ApiModelProperty(value= "瀹�")
     private Double width;
-
     /**
      * 鎺�
      */
@@ -116,6 +115,12 @@
     private Integer row;
 
     /**
+     * 璁惧鍙�
+     */
+    @ApiModelProperty(value= "璁惧鍙�")
+    private Integer deviceNo;
+
+    /**
      * 鍒�
      */
     @ApiModelProperty(value= "鍒�")
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/mapper/BasDeviceMapper.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/mapper/BasDeviceMapper.java
new file mode 100644
index 0000000..79395c5
--- /dev/null
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/mapper/BasDeviceMapper.java
@@ -0,0 +1,12 @@
+package com.vincent.rsf.server.manager.mapper;
+
+import com.vincent.rsf.server.manager.entity.BasDevice;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.springframework.stereotype.Repository;
+
+@Mapper
+@Repository
+public interface BasDeviceMapper extends BaseMapper<BasDevice> {
+
+}
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/BasDeviceService.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/BasDeviceService.java
new file mode 100644
index 0000000..8779389
--- /dev/null
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/BasDeviceService.java
@@ -0,0 +1,8 @@
+package com.vincent.rsf.server.manager.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.vincent.rsf.server.manager.entity.BasDevice;
+
+public interface BasDeviceService extends IService<BasDevice> {
+
+}
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/BasDeviceServiceImpl.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/BasDeviceServiceImpl.java
new file mode 100644
index 0000000..b4efdd1
--- /dev/null
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/BasDeviceServiceImpl.java
@@ -0,0 +1,12 @@
+package com.vincent.rsf.server.manager.service.impl;
+
+import com.vincent.rsf.server.manager.mapper.BasDeviceMapper;
+import com.vincent.rsf.server.manager.entity.BasDevice;
+import com.vincent.rsf.server.manager.service.BasDeviceService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+@Service("basDeviceService")
+public class BasDeviceServiceImpl extends ServiceImpl<BasDeviceMapper, BasDevice> implements BasDeviceService {
+
+}
diff --git a/rsf-server/src/main/resources/application.yml b/rsf-server/src/main/resources/application.yml
index 4a03079..a5eb904 100644
--- a/rsf-server/src/main/resources/application.yml
+++ b/rsf-server/src/main/resources/application.yml
@@ -40,3 +40,16 @@
 logging:
   file:
     path: logs/@pom.artifactId@
+
+# 涓嬩綅鏈洪厤缃�
+wcs-slave:
+  # 鍙屾繁
+  doubleDeep: true
+  # 鍙屾繁搴撲綅鎺掑彿
+  doubleLocs: 1,4,5,8
+  # 涓�涓爢鍨涙満璐熻矗鐨勮揣鏋舵帓鏁�
+  groupCount: 4
+  # 宸︽繁搴撲綅鎺掑彿
+  doubleLocsLeft: 1,5,9,13
+  # 鍙虫繁搴撲綅鎺掑彿
+  doubleLocsRight: 4,8,12,16
diff --git a/rsf-server/src/main/resources/mapper/manager/BasDeviceMapper.xml b/rsf-server/src/main/resources/mapper/manager/BasDeviceMapper.xml
new file mode 100644
index 0000000..7ac5f0d
--- /dev/null
+++ b/rsf-server/src/main/resources/mapper/manager/BasDeviceMapper.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.vincent.rsf.server.manager.mapper.BasDeviceMapper">
+
+</mapper>

--
Gitblit v1.9.1