浏览代码

chore: 半成品领料单和出库单增加库位选择

xyh 2 年之前
父节点
当前提交
a2de764678

+ 7 - 1
packages/app/src/apis/semiManufactures.ts

@@ -17,11 +17,15 @@ const BASE_URL = '/warehousing',
   BASE_URL2 = '/askGoods';
 
 /** 报工单列表 */
-export function getNoticeList(data: GetNoticeListParams): BaseListResult<NoticeListData> {
+export function getNoticeList(
+  data: GetNoticeListParams,
+  signal?: AbortSignal,
+): BaseListResult<NoticeListData> {
   return request({
     method: 'GET',
     url: `${BASE_URL}/getNotice`,
     data,
+    signal,
   });
 }
 
@@ -85,11 +89,13 @@ export function exportSemiManufacturesInStream(data: GetWarehousingFlowingListPa
 /** 半成品出库物料列表 */
 export function getSemiManufacturesDrawList(
   data: GetSemiManufacturesDrawList,
+  signal?: AbortSignal,
 ): BaseListResult<SemiDrawListData> {
   return request({
     method: 'GET',
     url: `${BASE_URL2}/getGoodsHalf`,
     data,
+    signal,
   });
 }
 

+ 1 - 1
packages/app/src/components/table/index.tsx

@@ -36,7 +36,7 @@ function Table<T extends Record<string, any>>(props: Props<T>): ReactElement {
       return [
         {
           title: '序号',
-          width: 62,
+          width: 64,
           render(_: any, __: any, idx: number) {
             return idx + 1;
           },

+ 2 - 2
packages/app/src/hooks/use-options/index.ts

@@ -80,10 +80,10 @@ export function useDictionaryOptions(
 
       if (data.msg === '200') {
         const list = data.data.map(function (value) {
-          return {label: value.name, value: findValue(value)};
+          return {label: value.name, value: findValue(value), type: value.warehouseType};
         });
 
-        if (addAll) list.unshift({label: '全部', value: ''});
+        if (addAll) list.unshift({label: '全部', value: '', type: ''});
 
         return list;
       }

+ 1 - 1
packages/app/src/hooks/use-query-list/index.ts

@@ -54,7 +54,7 @@ export function useQueryTableList<
     isFetching,
     refetch,
   } = useQuery<T>({
-    queryKey: [queryFn.name, page, pageSize, formatResultFn, ...Object.values(params)],
+    queryKey: [queryFn.name, page, pageSize, ...Object.values(params)],
     async queryFn({signal}) {
       /**
        * 当参数发生改变说明请求内容发生变化

+ 1 - 1
packages/app/src/models/request/container.ts

@@ -66,5 +66,5 @@ export type ScrapContainerLogParams = {
   /** 容器id */
   containerName: string;
   /** 用户名称 */
-  useName: string;
+  operationName: string;
 } & ListParams;

+ 4 - 0
packages/app/src/models/request/semiManufactures.ts

@@ -37,6 +37,8 @@ export type SemiManufacturesAddParams = {
    */
   wllbClass: string;
   wllbCode: string;
+  /** 所属库位id */
+  storageLocationCode: string;
 };
 
 /** 半成品出库 */
@@ -57,6 +59,8 @@ export type SemiManufacturesOutParams = {
   companyNumber: string;
   /** wbs编号 */
   wbs: string;
+  /** 所属库位id */
+  storageLocationCode: string;
 };
 
 /** 产成品/半成品出库物料列表 */

+ 1 - 1
packages/app/src/models/response/semiManufactures.ts

@@ -41,7 +41,7 @@ export type NoticeListData = {
   /**
    * 入库数量
    */
-  warehousingNum?: string;
+  warehousingNum: string;
   /**
    * wbs
    */

+ 1 - 1
packages/app/src/pages/container-scrap/context.ts

@@ -11,6 +11,6 @@ export const contextState: OriginalListParams<ScrapContainerLogParams> = {
   startTime: '',
   endTime: '',
   containerName: '',
-  useName: '',
+  operationName: '',
 };
 export const context = createTableSearchContext(contextState);

+ 4 - 4
packages/app/src/pages/container-scrap/filter/index.tsx

@@ -7,7 +7,7 @@ import {context, searchContext} from '../context';
 const Filter: FC = function () {
   const [{dates, start, end}, setDates] = useRangeDate();
   const {isSearching} = useContextSection(searchContext, state => state[0]);
-  const [fields, {onChange, resetState}] = useFilterField({userName: ''}, true);
+  const [fields, {onChange, resetState}] = useFilterField({operationName: ''}, true);
   const [, {onSearch, onReset}] = useTableSearchToolEvents(
     context,
     {...fields, startTime: start, endTime: end},
@@ -19,9 +19,9 @@ const Filter: FC = function () {
       <FilterFieldWrapper onSearch={onSearch}>
         <FilterField
           label='用户名称'
-          name='containerDate'
-          value={fields.userName}
-          onChange={onChange('userName')}
+          name='operationName'
+          value={fields.operationName}
+          onChange={onChange('operationName')}
         />
         <FilterDatePicker label='日期选择' name='containerDate' value={dates} onChange={setDates} />
         <FilterButtonGroup

+ 9 - 9
packages/app/src/pages/product-draw/table/modal/hooks.ts

@@ -76,15 +76,15 @@ export function useFormState({
     if (!info) message.error('未获取到信息');
     else {
       const {materialId, askGoodsId, materialCode, companyNumber, wbs} = info;
-      mutate({
-        materialId,
-        askGoodsId,
-        userId,
-        warehousingNum: String(semiDrawNum),
-        wllbCode: materialCode,
-        companyNumber,
-        wbs,
-      });
+      // mutate({
+      //   materialId,
+      //   askGoodsId,
+      //   userId,
+      //   warehousingNum: String(semiDrawNum),
+      //   wllbCode: materialCode,
+      //   companyNumber,
+      //   wbs,
+      // });
     }
   });
 

+ 10 - 62
packages/app/src/pages/semi-draw/table/hooks.tsx

@@ -1,13 +1,9 @@
-import {delProductionRequisition, semiManufacturesOut} from '@apis';
+import {delProductionRequisition} from '@apis';
 import {ColumnsType} from 'antd/es/table';
 import {SemiDrawListData} from '@models';
-import {useState} from 'react';
-import {Button, Modal, message} from 'antd';
+import {Button} from 'antd';
 import {DOUBLE_BTN_WIDTH, MIDDLE_TABLE_WIDTH, NORMAL_TABLE_WIDTH, SMALL_TABLE_WIDTH} from '@utils';
-import {useMutation} from '@tanstack/react-query';
-import {useStore} from 'zustand';
-import {userStore} from '@stores';
-import {useSupertube, useTableDeleteEvent} from '@hooks';
+import {useSupertube, useTableDeleteEvent, useTableModalEvent} from '@hooks';
 
 const tableColumns: ColumnsType<SemiDrawListData> = [
   {title: '要货单编号', dataIndex: 'askGoodsId', key: 'askGoodsId', width: NORMAL_TABLE_WIDTH},
@@ -32,53 +28,11 @@ const tableColumns: ColumnsType<SemiDrawListData> = [
   },
 ];
 
-function usePutInQuery(refetch: () => void) {
-  const [pendingId, setPendingId] = useState('');
-  const userId = useStore(userStore, state => String(state.id));
-
-  const {mutate} = useMutation({
-    mutationFn: semiManufacturesOut,
-    onSuccess({msg}) {
-      if (msg === '200') {
-        refetch();
-        setPendingId('');
-        message.success('出库成功');
-      }
-    },
-  });
-
-  function putInQuery(data: SemiDrawListData) {
-    const {companyNumber, wbs, materialId, askGoodsId, num, id, materialCode} = data;
-    setPendingId(id);
-    mutate({
-      companyNumber,
-      wbs,
-      materialId,
-      warehousingNum: num,
-      userId,
-      askGoodsId,
-      wllbCode: materialCode,
-    });
-  }
-
-  function onClick(data: SemiDrawListData) {
-    return function () {
-      Modal.confirm({
-        title: '出库',
-        content: `你确定要对${data.askGoodsId}出库吗?`,
-        onOk: () => putInQuery(data),
-      });
-    };
-  }
-
-  return [pendingId, onClick] as const;
-}
-
 export function useHandle(refetch: () => void) {
-  const [pendingId, onClick] = usePutInQuery(refetch);
-  const [editId, onDelete] = useTableDeleteEvent(delProductionRequisition, refetch, {
+  const [deleteId, onDelete] = useTableDeleteEvent(delProductionRequisition, refetch, {
     label: '半成品领料单',
   });
+  const [{visible, editId: putOutId}, {onClose, onEdit}] = useTableModalEvent();
 
   const isSuper = useSupertube();
   const columns: ColumnsType<SemiDrawListData> = [
@@ -89,20 +43,14 @@ export function useHandle(refetch: () => void) {
       key: 'id',
       fixed: 'right',
       width: DOUBLE_BTN_WIDTH,
-      render(_, data) {
-        const {id} = data;
+      render(_, {id, type}) {
         return (
           <>
-            <Button
-              type='link'
-              disabled={data.type !== '0'}
-              onClick={onClick(data)}
-              loading={pendingId === data.id}
-            >
-              {data.type === '0' ? '出库' : '已出库'}
+            <Button type='link' disabled={type !== '0' || deleteId === id} onClick={onEdit(id)}>
+              {type === '0' ? '出库' : '已出库'}
             </Button>
             {isSuper && (
-              <Button type='text' danger loading={editId === id} onClick={onDelete(id)}>
+              <Button type='text' danger loading={deleteId === id} onClick={onDelete(id)}>
                 删除
               </Button>
             )}
@@ -112,5 +60,5 @@ export function useHandle(refetch: () => void) {
     },
   ];
 
-  return [{columns}] as const;
+  return [{columns, visible, putOutId}, {onClose}] as const;
 }

+ 10 - 3
packages/app/src/pages/semi-draw/table/index.tsx

@@ -7,6 +7,7 @@ import {getSemiManufacturesDrawList} from '@apis';
 import {useContextSection, useQueryTableList, useSupertube} from '@hooks';
 import {useBoolean} from 'ahooks';
 import AddModal from './modal';
+import PutOutModal from './put-out-modal';
 
 const TableList: FC = function () {
   const params = useContextSection(context, function ([{code, type}]) {
@@ -18,20 +19,25 @@ const TableList: FC = function () {
     };
   });
 
-  const [{data, count}, {refetch}] = useQueryTableList({
+  const [{data, count, isFetching}, {refetch}] = useQueryTableList({
     queryFn: getSemiManufacturesDrawList,
     params,
     pageContext,
     searchContext,
   });
-  const [{columns}] = useHandle(refetch);
+  const [{columns, visible: putOutVisible, putOutId}, {onClose}] = useHandle(refetch);
   const [visible, {setTrue, setFalse}] = useBoolean();
   const isSuper = useSupertube();
 
   return (
     <>
       <Card className='table-wrapper'>
-        {isSuper && <TableTools onClick={setTrue} />}
+        <TableTools
+          onAdd={isSuper ? setTrue : void 0}
+          onRefresh={refetch}
+          isRefreshing={isFetching}
+        />
+
         <Table
           data-testid='semi_draw_table'
           data={data}
@@ -43,6 +49,7 @@ const TableList: FC = function () {
       </Card>
 
       {isSuper && <AddModal visible={visible} onClose={setFalse} onFetch={refetch} />}
+      <PutOutModal visible={putOutVisible} id={putOutId} onClose={onClose} onFetch={refetch} />
     </>
   );
 };

+ 101 - 0
packages/app/src/pages/semi-draw/table/put-out-modal/hooks.ts

@@ -0,0 +1,101 @@
+import {getSemiManufacturesDrawList, semiManufacturesOut} from '@apis';
+import {yupResolver} from '@hookform/resolvers/yup';
+import {SemiDrawListData} from '@models';
+import {userStore} from '@stores';
+import {useMutation, useQueryClient} from '@tanstack/react-query';
+import {message} from 'antd';
+import {useEffect, useMemo} from 'react';
+import {useForm} from 'react-hook-form';
+import {object, string} from 'yup';
+import {useStore} from 'zustand';
+
+type FormState = {
+  /** 仓库id */
+  warehouse: string;
+  /** 库位id */
+  location: string;
+};
+
+const validate = object({
+  warehouse: string().required('请选择仓库'),
+  location: string().required('请选择库位'),
+});
+
+function useData(id: string) {
+  const client = useQueryClient();
+
+  return useMemo(
+    function () {
+      const data = client.getQueryData<SemiDrawListData[]>([getSemiManufacturesDrawList.name], {
+        exact: false,
+      });
+      if (!data) return void 0;
+
+      return data.find(val => val.id === id);
+    },
+    [client, id],
+  );
+}
+
+export function useFormState({
+  visible,
+  onClose,
+  onFetch,
+  id,
+}: {
+  id: string;
+  visible: boolean;
+  onClose: () => void;
+  onFetch: () => void;
+}) {
+  const {control, handleSubmit, reset, clearErrors, watch} = useForm<FormState>({
+    resolver: yupResolver(validate),
+    defaultValues: {warehouse: '', location: ''},
+  });
+
+  useEffect(
+    function () {
+      if (visible) {
+        clearErrors();
+        reset();
+      }
+    },
+    [clearErrors, reset, visible],
+  );
+
+  const data = useData(id);
+
+  const {isLoading, mutate} = useMutation({
+    mutationFn: semiManufacturesOut,
+    onSuccess({msg}) {
+      if (msg === '200') {
+        onClose();
+        onFetch();
+        message.success('出库完成');
+      }
+    },
+  });
+
+  const userId = useStore(userStore, state => String(state.id));
+
+  const onSubmit = handleSubmit(function ({location}) {
+    if (!data) return message.error('未获取到领料单信息');
+    const {companyNumber, wbs, materialId, askGoodsId, num, materialCode} = data;
+
+    mutate({
+      companyNumber,
+      wbs,
+      materialId,
+      warehousingNum: num,
+      askGoodsId,
+      wllbCode: materialCode,
+      storageLocationCode: location,
+      userId,
+    });
+  });
+
+  return [
+    {control, isLoading},
+    {onSubmit, watch},
+  ] as const;
+}

+ 35 - 0
packages/app/src/pages/semi-draw/table/put-out-modal/index.tsx

@@ -0,0 +1,35 @@
+import {Modal, ModalSelect} from '@components';
+import {FC, useMemo} from 'react';
+import {useFormState} from './hooks';
+import {useDictionaryOptions, useStorageOptions} from '@hooks';
+
+type Props = {
+  visible: boolean;
+  onClose: () => void;
+  onFetch: () => void;
+  id: string;
+};
+
+const PutOutModal: FC<Props> = function (props) {
+  const [{control, isLoading}, {onSubmit, watch}] = useFormState(props);
+  const warehouse = useDictionaryOptions('仓库');
+  const warehouseOptions = useMemo(
+    function () {
+      return warehouse.filter(val => val?.type === '1');
+    },
+    [warehouse],
+  );
+  const warehouseId = watch('warehouse');
+  const storageOptions = useStorageOptions(false, state => state.storageLocationCode, {
+    id: warehouseId,
+  });
+
+  return (
+    <Modal {...props} title='选择库位信息' onSubmit={onSubmit} isLoading={isLoading}>
+      <ModalSelect data={warehouseOptions} control={control} label='所属仓库' name='warehouse' />
+      <ModalSelect data={storageOptions} control={control} label='所属库位' name='location' />
+    </Modal>
+  );
+};
+
+export default PutOutModal;

+ 10 - 63
packages/app/src/pages/semi-report/table/hooks.tsx

@@ -1,8 +1,7 @@
-import {deleNotice, semiManufacturesAdd} from '@apis';
-import {Button, Modal, message} from 'antd';
+import {deleNotice} from '@apis';
+import {Button} from 'antd';
 import {ColumnsType} from 'antd/es/table';
 import {NoticeListData} from '@models';
-import {useState} from 'react';
 import {
   DOUBLE_BTN_WIDTH,
   HUGE_TABLE_WIDTH,
@@ -10,10 +9,7 @@ import {
   NORMAL_TABLE_WIDTH,
   SMALL_TABLE_WIDTH,
 } from '@utils';
-import {useMutation} from '@tanstack/react-query';
-import {useStore} from 'zustand';
-import {userStore} from '@stores';
-import {useSupertube, useTableDeleteEvent} from '@hooks';
+import {useSupertube, useTableDeleteEvent, useTableModalEvent} from '@hooks';
 
 const tableColumns: ColumnsType<NoticeListData> = [
   {title: '报工单号', dataIndex: 'noticeId', key: 'noticeId', width: MIDDLE_TABLE_WIDTH},
@@ -38,52 +34,10 @@ const tableColumns: ColumnsType<NoticeListData> = [
   },
 ];
 
-function usePutInStorage(refetch: () => void) {
-  const [pendingId, setPendingId] = useState('');
-  const userId = useStore(userStore, state => String(state.id));
-
-  const {mutate} = useMutation({
-    mutationFn: semiManufacturesAdd,
-    onSuccess({msg}) {
-      if (msg === '200') {
-        refetch();
-        setPendingId('');
-        message.success('入库成功');
-      }
-    },
-  });
-
-  function putInQuery(data: NoticeListData) {
-    const {wllbClass, companyNumber, wbs, materialId, noticeId, wllbCode, num, id} = data;
-    setPendingId(id);
-    mutate({
-      wllbClass,
-      companyNumber,
-      wbs,
-      materialId,
-      noticeId,
-      wllbCode,
-      warehousingNum: num,
-      userId,
-    });
-  }
-
-  function onClick(data: NoticeListData) {
-    return function () {
-      Modal.confirm({
-        title: '入库',
-        content: `你确定要对${data.noticeId}入库吗?`,
-        onOk: () => putInQuery(data),
-      });
-    };
-  }
-
-  return [pendingId, onClick] as const;
-}
-
 export function useHandle(refetch: () => void) {
-  const [pendingId, onClick] = usePutInStorage(refetch);
   const [deleteId, onDelete] = useTableDeleteEvent(deleNotice, refetch, {label: '半成品报工单'});
+  const [{visible, editId}, {onClose, onEdit}] = useTableModalEvent();
+
   const isSuper = useSupertube();
   const columns: ColumnsType<NoticeListData> = [
     ...tableColumns,
@@ -93,21 +47,14 @@ export function useHandle(refetch: () => void) {
       key: 'id',
       width: isSuper ? DOUBLE_BTN_WIDTH : SMALL_TABLE_WIDTH,
       fixed: 'right',
-      render(_, data) {
-        const {id} = data;
-        const disabled = pendingId === id || deleteId === id;
+      render(_, {id, type}) {
         return (
           <>
-            <Button
-              type='link'
-              disabled={data.type !== '0'}
-              onClick={onClick(data)}
-              loading={pendingId === data.id}
-            >
-              {data.type === '0' ? '入库' : '已入库'}
+            <Button type='link' disabled={type !== '0' || deleteId === id} onClick={onEdit(id)}>
+              {type === '0' ? '入库' : '已入库'}
             </Button>
             {isSuper && (
-              <Button type='text' danger loading={disabled} onClick={onDelete(id)}>
+              <Button type='text' danger loading={deleteId === id} onClick={onDelete(id)}>
                 删除
               </Button>
             )}
@@ -117,5 +64,5 @@ export function useHandle(refetch: () => void) {
     },
   ];
 
-  return [{columns}] as const;
+  return [{columns, visible, editId}, {onClose}] as const;
 }

+ 9 - 3
packages/app/src/pages/semi-report/table/index.tsx

@@ -7,23 +7,28 @@ import {getNoticeList} from '@apis';
 import {useContextSection, useQueryTableList, useSupertube} from '@hooks';
 import {useBoolean} from 'ahooks';
 import AddModal from './modal';
+import PutInModal from './put-in-modal';
 
 const TableList: FC = function () {
   const params = useContextSection(context, contextStateSelector);
-  const [{data, count}, {refetch}] = useQueryTableList({
+  const [{data, count, isFetching}, {refetch}] = useQueryTableList({
     queryFn: getNoticeList,
     params,
     pageContext,
     searchContext,
   });
-  const [{columns}] = useHandle(refetch);
+  const [{columns, visible: putInVisible, editId: putInId}, {onClose}] = useHandle(refetch);
   const [visible, {setTrue, setFalse}] = useBoolean();
   const isSuper = useSupertube();
 
   return (
     <>
       <Card className='table-wrapper'>
-        {isSuper && <TableTools onClick={setTrue} />}
+        <TableTools
+          onAdd={isSuper ? setTrue : void 0}
+          onRefresh={refetch}
+          isRefreshing={isFetching}
+        />
 
         <Table
           data-testid='semi_report_table'
@@ -36,6 +41,7 @@ const TableList: FC = function () {
       </Card>
 
       {isSuper && <AddModal visible={visible} onClose={setFalse} onFetch={refetch} />}
+      <PutInModal visible={putInVisible} onClose={onClose} id={putInId} onFetch={refetch} />
     </>
   );
 };

+ 85 - 0
packages/app/src/pages/semi-report/table/put-in-modal/hooks.ts

@@ -0,0 +1,85 @@
+import {getNoticeList, semiManufacturesAdd} from '@apis';
+import {yupResolver} from '@hookform/resolvers/yup';
+import {NoticeListData} from '@models';
+import {userStore} from '@stores';
+import {useMutation, useQueryClient} from '@tanstack/react-query';
+import {message} from 'antd';
+import {useEffect, useMemo} from 'react';
+import {useForm} from 'react-hook-form';
+import {object, string} from 'yup';
+import {useStore} from 'zustand';
+
+type FormState = {
+  /** 仓库id */
+  warehouse: string;
+  /** 库位id */
+  location: string;
+};
+
+const validate = object({
+  warehouse: string().required('请选择仓库'),
+  location: string().required('请选择库位'),
+});
+
+function useData(id: string) {
+  const client = useQueryClient();
+
+  return useMemo(
+    function () {
+      const data = client.getQueryData<NoticeListData[]>([getNoticeList.name], {exact: false});
+      if (!data) return void 0;
+
+      return data.find(val => val.id === id);
+    },
+    [client, id],
+  );
+}
+
+export function useFormState({
+  visible,
+  onClose,
+  onFetch,
+  id,
+}: {
+  id: string;
+  visible: boolean;
+  onClose: () => void;
+  onFetch: () => void;
+}) {
+  const {control, handleSubmit, reset, clearErrors, watch} = useForm<FormState>({
+    resolver: yupResolver(validate),
+    defaultValues: {warehouse: '', location: ''},
+  });
+
+  useEffect(
+    function () {
+      if (visible) {
+        clearErrors();
+        reset();
+      }
+    },
+    [clearErrors, reset, visible],
+  );
+
+  const data = useData(id);
+
+  const {isLoading, mutate} = useMutation({
+    mutationFn: semiManufacturesAdd,
+    onSuccess({msg}) {
+      if (msg === '200') {
+        onClose();
+        onFetch();
+        message.success('入库完成');
+      }
+    },
+  });
+
+  const userId = useStore(userStore, state => String(state.id));
+
+  const onSubmit = handleSubmit(function ({location}) {
+    if (!data) return message.error('未获取到报工单信息');
+    mutate({...data, storageLocationCode: location, userId});
+  });
+
+  return [{control}, {onSubmit, watch}] as const;
+}

+ 35 - 0
packages/app/src/pages/semi-report/table/put-in-modal/index.tsx

@@ -0,0 +1,35 @@
+import {Modal, ModalSelect} from '@components';
+import {FC, useMemo} from 'react';
+import {useFormState} from './hooks';
+import {useDictionaryOptions, useStorageOptions} from '@hooks';
+
+type Props = {
+  visible: boolean;
+  onClose: () => void;
+  onFetch: () => void;
+  id: string;
+};
+
+const PutInModal: FC<Props> = function (props) {
+  const [{control}, {onSubmit, watch}] = useFormState(props);
+  const warehouse = useDictionaryOptions('仓库');
+  const warehouseOptions = useMemo(
+    function () {
+      return warehouse.filter(val => val?.type === '1');
+    },
+    [warehouse],
+  );
+  const warehouseId = watch('warehouse');
+  const storageOptions = useStorageOptions(false, state => state.storageLocationCode, {
+    id: warehouseId,
+  });
+
+  return (
+    <Modal {...props} title='选择库位信息' onSubmit={onSubmit}>
+      <ModalSelect data={warehouseOptions} control={control} label='所属仓库' name='warehouse' />
+      <ModalSelect data={storageOptions} control={control} label='所属库位' name='location' />
+    </Modal>
+  );
+};
+
+export default PutInModal;