Ver código fonte

添加盘点出入库

yangg 11 meses atrás
pai
commit
f90b9c87c6

+ 1 - 1
.env

@@ -1 +1 @@
-VITE_API_URL=http://192.168.8.101:9998
+VITE_API_URL=http://192.168.8.104:9998

+ 3 - 3
src/api/basicSetting.js

@@ -270,15 +270,15 @@ export function deleteWarehouse(id) {
 }
 
 /**
- * 所有仓库
+ * 所有仓库params
  * @param params
  */
-export function getWarehouseListAll(params) {
+export function getWarehouseListAll() {
   return request({
     url: 'admin/erp/warehouse/list-all',
     method: 'get',
     loading: false,
-    params
+    /* params */
   })
 }
 

+ 3 - 3
src/api/goodsExchange.js

@@ -181,11 +181,11 @@ export function warehouseOut(parmas) {
   })
 }
 
-// 获取商品档案/admin/erp/goods
+// 出入库获取商品
 
-export function getGoodsInfo(params,id) {
+export function getGoodsInfo(params,id,type) {
   return request({
-    url: `/admin/erp/goods/getSkuByWarehouse/${id}`,
+    url: `/admin/erp/warehouseOut/getGoodByWarehouse/${id}/${type}`,
     method: 'get',
     loaidng: false,
     params

+ 183 - 0
src/api/goodsInventory.js

@@ -0,0 +1,183 @@
+/**
+ * 商品换货相关API
+ */
+
+import request from '@/utils/request'
+
+/**
+ * 查询产品借出数量信息
+ * @param params
+ */
+export function getlistProductLendNum(params) {
+  return request({
+    url: 'admin/lend/form/list-product-lend-num',
+    method: 'post',
+    loaidng: false,
+    headers: { 'Content-Type': 'application/json' },
+    data: params
+  })
+}
+
+/**
+ * 归还商品换货
+ * @param id
+ * @param parmas
+ */
+export function returnGoodsInventory(id, parmas) {
+  return request({
+    url: `admin/stock/inventory/return/${id}`,
+    method: 'post',
+    headers: { 'Content-Type': 'application/json' },
+    data: parmas
+  })
+}
+
+/**
+ * 批量确认商品换货单
+ * @param id
+ */
+export function inventoryFormConfirm(ids) {
+  return request({
+    url: `admin/stock/inventory/confirm/${ids}`,
+    method: 'post'
+  })
+}
+
+/**
+ * 修改商品换货
+ * @param id
+ * @param parmas
+ */
+export function editgoodsInventoryAdd(id, parmas) {
+  return request({
+    url: `admin/stock/inventory/${id}`,
+    method: 'post',
+    headers: { 'Content-Type': 'application/json' },
+    data: parmas
+  })
+}
+
+/**
+ * 添加商品换货
+ * @param params
+ */
+export function addgoodsInventoryAdd(params) {
+  return request({
+    url: 'admin/stock/inventory',
+    method: 'post',
+    headers: { 'Content-Type': 'application/json' },
+    data: params
+  })
+}
+
+/**
+ * 提交审核商品换货单
+ * @param ids
+ */
+export function submitAuditGoodsInventory(ids) {
+  return request({
+    url: `admin/stock/inventory/submit/${ids}`,
+    method: 'post'
+  })
+}
+
+/**
+ * 撤回商品换货
+ * @param ids
+ */
+export function cancelGoodsInventory(ids) {
+  return request({
+    url: `admin/stock/inventory/cancel/${ids}`,
+    method: 'post'
+  })
+}
+
+/**
+ * 审核商品换货
+ * @param params
+ */
+export function auditGoodsInventory(ids, parmas) {
+  return request({
+    url: `admin/stock/inventory/audit/${ids}`,
+    method: 'post',
+    data: parmas
+  })
+}
+
+/**
+ * 获取商品换货详情
+ * @param params
+ */
+export function getGoodsInventoryInfo(id) {
+  return request({
+    url: `admin/stock/inventory/${id}`,
+    method: 'get',
+    loaidng: false
+  })
+}
+
+/**
+ * 获取商品换货列表
+ * @param params
+ */
+export function getGoodsInventoryList(params) {
+  return request({
+    url: 'admin/stock/inventory',
+    method: 'get',
+    loaidng: false,
+    params
+  })
+}
+
+/**
+ * 更新商品换货
+ * @param id
+ * @param parmas
+ */
+export function editGoodsInventory(id, parmas) {
+  return request({
+    url: `admin/stock/inventory/${id}`,
+    method: 'put',
+    headers: { 'Content-Type': 'application/json' },
+    data: parmas
+  })
+}
+
+/**
+ * 删除商品换货
+ * @param id
+ */
+export function deleteGoodsInventory(ids) {
+  return request({
+    url: `admin/stock/inventory/${ids}`,
+    method: 'delete'
+  })
+}
+
+/* 同步库存  /admin/stock/inventory/syncStock/{id*/
+export function getSyncStock(id) {
+  return request({
+    url: `/admin/stock/inventory/syncStock/${id}`,
+    method: 'get',
+    loaidng: false
+  })
+}
+
+/* /admin/erp/warehouseOut/getGoodByWarehouse */
+
+export function getGoodByWarehouseInventory(params,id) {
+  return request({
+    url: `/admin/erp/warehouseOut/getGoodByWarehouseInventory/${id}`,
+    method: 'get',
+    loaidng: false,
+    params
+  })
+}
+/* 审核人列表 */
+export function getUserByCompany() {
+  return request({
+    url: `/admin/systems/manager/admin-users/getUserByCompany`,
+    method: 'get',
+    loaidng: false,
+  })
+}

+ 4 - 0
src/components/layout/Sidebar.vue

@@ -220,6 +220,10 @@
                   <li>
                     <router-link to="/stock/goodsOutBound" @click="toggleMobileMenu">{{ $t('goodsOutBound') }}</router-link>
                   </li>
+                  <!-- goodsInventory -->
+                  <li>
+                    <router-link to="/stock/goodsInventory" @click="toggleMobileMenu">{{ $t('goodsInventory') }}</router-link>
+                  </li>
                 </ul>
               </vue-collapsible>
             </li>

+ 2 - 0
src/locales/zh.json

@@ -5,6 +5,7 @@
     "goodsTransfer":"库存列表",
     "goodsExchange":"入库管理",
     "goodsOutBound":"出库管理",
+    "goodsInventory":"库存盘点",
        
     "setting":"系统管理",
     "companyList":"公司列表",
@@ -28,6 +29,7 @@
     "goods":"商品管理",
     "SKUList":"商品列表",
     "warehouseLocation":"库位区域",
+    "addInventory":"新增入库",
 
     "sales": "销售量",
     "analytics": "分析",

+ 5 - 0
src/router/index.ts

@@ -36,6 +36,11 @@ const asyncRouterMap: RouteRecordRaw[] = [
             { path: 'goodsExchange', component: () => import('@/views/stock/warehousing.vue'), name: 'goodsExchange', meta: { title: 'goodsExchange' } },
             { path: 'goodsOutBound', component: () => import('@/views/stock/outbound.vue'), name: 'goodsOutBound', meta: { title: 'goodsOutBound' } },
             { path: 'warehouseLocation', component: () => import('@/views/stock/warehouseLocation.vue'), name: 'warehouseLocation', meta: { title: 'warehouseLocation' ,layout: 'app'} },
+            /* addOutbound */
+            { path: 'addInventory', component: () => import('@/views/stock/addInventory.vue'), name: 'addInventory', meta: { title: 'addInventory' ,layout: 'app'} },
+            { path: 'addOutbound', component: () => import('@/views/stock/addOutbound.vue'), name: 'addOutbound', meta: { title: 'addOutbound' ,layout: 'app'} },
+            { path: 'goodsInventory', component: () => import('@/views/stock/goodsInventory.vue'), name: 'goodsInventory', meta: { title: 'goodsInventory' ,layout: 'app'} },
+            { path: 'goodsInventoryAdd', component: () => import('@/views/stock/goodsInventoryAdd.vue'), name: 'goodsInventoryAdd', meta: { title: 'goodsInventoryAdd' ,layout: 'app'} },
         ]
     },
     {

+ 13 - 14
src/views/setting/dicData.vue

@@ -12,8 +12,7 @@
               <div class="toolbar-search"></div>
             </div>
           </template>
-
-          <template #default>
+          <template #table-columns>
             <el-table-column prop="id" label="字典编号" />
             <el-table-column prop="name" label="字典名称" />
             <el-table-column prop="type" label="字典类型" />
@@ -54,7 +53,7 @@
             </div>
           </template>
 
-          <template #default>
+          <template #table-columns>
             <el-table-column prop="id" label="字典编码" />
             <el-table-column prop="label" label="字典标签" />
             <el-table-column prop="value" label="字典键值" />
@@ -141,7 +140,7 @@
   </div>
 </template>
   
-  <script setup>
+  <script lang="ts" setup>
 import { ref, onMounted, reactive } from 'vue';
 import { ElMessage, ElMessageBox } from 'element-plus';
 import * as API_Setting from '@/api/setting';
@@ -163,8 +162,8 @@ const paramsType = reactive({
 });
 
 // 列表数据
-const tableData = ref({});
-const tableDataType = ref({});
+const tableData = ref<any>([]);
+const tableDataType = ref<any>([]);
 
 // 字典表单
 const dictDataForm = ref({});
@@ -229,13 +228,9 @@ const dictDataRules = {
 const dialogVisible = ref(false);
 const dialogTypeVisible = ref(false);
 
-const dictTypeFormRef = ref(null);
-const dictDataFormRef = ref(null);
+const dictTypeFormRef = ref();
+const dictDataFormRef = ref();
 
-onMounted(() => {
-  GET_DictDataList();
-  GET_DictTypeList();
-});
 
 const tableClick = (row) => {
   params.dict_type = row.type;
@@ -310,7 +305,6 @@ const handleDeleteData = (index, row) => {
     })
     .catch(() => {});
 };
-
 const submitTypeForm = () => {
   dictTypeFormRef.value.validate((valid) => {
     if (valid) {
@@ -368,8 +362,8 @@ const GET_DictTypeList = () => {
   API_Setting.getDictTypeList(paramsType)
     .then((response) => {
       loading.value = false;
-      console.log(response);
       tableDataType.value = response;
+      console.log(tableDataType.value);
     })
     .catch(() => {
       loading.value = false;
@@ -392,6 +386,11 @@ const checkPermission = (permissions) => {
   // 实现权限检查逻辑
   return true;
 };
+onMounted(() => {
+  GET_DictDataList();
+  GET_DictTypeList();
+});
+
 </script>
   
   <style scoped>

+ 723 - 0
src/views/stock/addInventory.vue

@@ -0,0 +1,723 @@
+<template>
+  <div class="bg-in-stock">
+    <el-form ref="goodsExchangeAddFormRef" :model="goodsExchangeAddForm" :rules="goodsExchangeAddFormRule" label-width="160px" inline class="change-form">
+      <el-form-item
+        label="订单编号:"
+        prop="order_id"
+        class="change-form-item"
+        v-if="goodsExchangeAddForm.sn && (goodsExchangeAddForm.type == 'SALE_AFTER' || goodsExchangeAddForm.type == 'HAIL_ENTRY')"
+      >
+        {{ goodsExchangeAddForm.sn }}
+      </el-form-item>
+      <el-form-item prop="warehouse_id" label="入库仓库:" class="change-form-item">
+        <el-select v-model="goodsExchangeAddForm.warehouse_id" clearable :disabled="type === 'view'">
+          <el-option v-for="item in warehouseList" :key="item.id" :label="item.name" :value="item.id" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="类型:" prop="type" class="change-form-item">
+        <el-select
+          v-model="goodsExchangeAddForm.type"
+          filterable
+          allow-create
+          clearable
+          default-first-option
+          :disabled="type === 'view' || orderType || goodsExchangeAddForm.type == 'SALE_AFTER' || goodsExchangeAddForm.type == 'HAIL_ENTRY'"
+        >
+          <el-option
+            v-for="item in typeList"
+            :key="item.id"
+            :label="item.label"
+            :value="item.value"
+            :disabled="item.value == 'TRANSFER_ENTRY' || item.value == 'HAIL_ENTRY' || item.value == 'SALE_AFTER'"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="备注:" prop="change_desc" class="change-form-item" style="width: 61%">
+        <el-input
+          style="flex: 1"
+          v-model="goodsExchangeAddForm.memo"
+          type="textarea"
+          :disabled="type === 'view' || type === 'audit'"
+          :autosize="{ minRows: 3, maxRows: 4 }"
+          placeholder="请输入"
+        ></el-input>
+      </el-form-item>
+      <div class="mx">
+        <h3>商品明细:</h3>
+        <el-button class="button" size="mini" type="primary" v-if="type !== 'view' && type !== 'audit'" @click="scanCode">扫码入库</el-button>
+        <el-button
+          class="button"
+          size="mini"
+          type="primary"
+          v-if="
+            type !== 'view' &&
+            type !== 'audit' &&
+            goodsExchangeAddForm.type !== 'TRANSFER_ENTRY' &&
+            goodsExchangeAddForm.type !== 'HAIL_ENTRY' &&
+            goodsExchangeAddForm.type !== 'SALE_AFTER'
+          "
+          @click="handleSelectWarehouseEntryBatch"
+          >选择</el-button
+        >
+      </div>
+      <div style="width: 100%; display: block">
+        <el-form-item style="width: 100%">
+          <el-table
+            :data="goodsExchangeAddForm.product_list"
+            border
+            :cell-style="{ textAlign: 'center' }"
+            :header-cell-style="{ textAlign: 'center' }"
+            style="width: 100%; margin-top: 20px"
+          >
+            <el-table-column label="库位号">
+              <template #default="scope">
+                <el-popover placement="right" trigger="click" v-if="scope.row.area_stock_list">
+                  <div>
+                    <p v-for="item in scope.row.area_stock_list" :key="item.id">{{ item.warehouse_area_name }}</p>
+                  </div>
+                  <span slot="reference" v-if="scope.row.area_stock_list.length !== 0">{{ scope.row.area_stock_list[0].warehouse_area_name }}</span>
+                </el-popover>
+              </template>
+            </el-table-column>
+            <!-- <el-table-column label="商品编号">
+              <template #default="scope">
+                {{ scope.row.goods_vo.sn }}
+              </template>
+            </el-table-column> -->
+            <el-table-column label="商品名称">
+              <template #default="scope">
+                {{ scope.row.product_vo.name }}
+              </template>
+            </el-table-column>
+            <el-table-column label="sku">
+              <template #default="scope">
+                {{ scope.row.product_vo.sku }}
+                <!-- <span v-if="id">{{ scope.row.product_vo.sku }}</span>
+                <span v-else>{{ scope.row.product_vo.sku }}</span> -->
+              </template>
+            </el-table-column>
+            <!-- <el-table-column label="序列号">
+              <template #default="scope">
+                <div class="sn-code-container">
+                  <span v-for="item in scope.row.sn_code_list" :key="item.id">
+                    <p>{{ item.sn_code }}</p>
+                  </span>
+                </div>
+              </template>
+            </el-table-column> -->
+            <!-- <el-table-column prop="product_vo.spec_name" label="规格型号" v-if="id"> </el-table-column>
+            <el-table-column prop="product_vo.spec_name" label="规格型号" v-else> </el-table-column> -->
+            <el-table-column label="单位">
+              <template #default="scope">
+                {{ scope.row.product_vo.unit }}
+                <!--    <span v-if="id">{{ scope.row.product_vo.unit }}</span>
+                <span v-else>{{ scope.row.product_vo.unit }}</span> -->
+              </template>
+            </el-table-column>
+            <el-table-column label="入库数量">
+              <template #default="scope">
+                <el-input-number
+                  v-model="scope.row.num"
+                  type="number"
+                  :min="0"
+                  :maxlength="20"
+                  :disabled="
+                    type === 'view' ||
+                    type === 'audit' ||
+                    goodsExchangeAddForm.type == 'TRANSFER_ENTRY' ||
+                    goodsExchangeAddForm.type == 'HAIL_ENTRY' ||
+                    goodsExchangeAddForm.type == 'SALE_AFTER'
+                  "
+                ></el-input-number>
+              </template>
+            </el-table-column>
+            <el-table-column
+              prop="entry_num"
+              label="已入库数量"
+              v-if="goodsExchangeAddForm.type == 'TRANSFER_ENTRY' || goodsExchangeAddForm.type == 'HAIL_ENTRY' || goodsExchangeAddForm.type == 'SALE_AFTER'"
+            >
+              <template #default="scope">
+                {{ scope.row.entry_num }}
+              </template>
+            </el-table-column>
+            <el-table-column
+              prop="not_entry_num"
+              label="未入库数量"
+              v-if="goodsExchangeAddForm.type == 'TRANSFER_ENTRY' || goodsExchangeAddForm.type == 'HAIL_ENTRY' || goodsExchangeAddForm.type == 'SALE_AFTER'"
+            >
+              <template #default="scope">
+                {{ scope.row.not_entry_num }}
+              </template>
+            </el-table-column>
+            <el-table-column
+              label="订单数量"
+              v-if="goodsExchangeAddForm.type == 'HAIL_ENTRY' || goodsExchangeAddForm.type == 'SALE_AFTER' || goodsExchangeAddForm.type == 'TRANSFER_ENTRY'"
+            >
+              <template #default="scope">
+                {{ scope.row.order_num }}
+              </template>
+            </el-table-column>
+            <el-table-column label="退货数量" v-if="goodsExchangeAddForm.type == 'SALE_AFTER'">
+              <template #default="scope">
+                {{ scope.row.return_num }}
+              </template>
+            </el-table-column>
+            <el-table-column label="在途库存" v-if="TO_BE_RETURN == 'TO_BE_RETURN'">
+              <template #default="scope">
+                {{ scope.row.stock_num }}
+              </template>
+            </el-table-column>
+            <el-table-column label="差异" v-if="id">
+              <template #default="scope">
+                <span v-if="scope.row.order_num">{{ scope.row.num - scope.row.order_num || 0 }}</span>
+              </template>
+            </el-table-column>
+            <el-table-column
+              label="操作"
+              v-if="
+                type !== 'view' &&
+                type !== 'audit' &&
+                goodsExchangeAddForm.type !== 'TRANSFER_ENTRY' &&
+                goodsExchangeAddForm.type !== 'HAIL_ENTRY' &&
+                goodsExchangeAddForm.type !== 'SALE_AFTER'
+              "
+            >
+              <template #default="scope">
+                <el-button size="mini" type="danger" @click="goodsExchangeAddForm.product_list.splice(scope.$index, 1)">删除</el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+        </el-form-item>
+      </div>
+    </el-form>
+    <div class="footer">
+      <el-button
+        v-if="
+          type !== 'view' &&
+          type !== 'detail' &&
+          checkPermission(['warehouseEntry2:add']) &&
+          goodsExchangeAddForm.type !== 'TRANSFER_ENTRY' &&
+          goodsExchangeAddForm.type !== 'HAIL_ENTRY' &&
+          goodsExchangeAddForm.type !== 'SALE_AFTER'
+        "
+        type="primary"
+        @click="savegoodsExchangeAddForm"
+        >保存
+      </el-button>
+      <el-button v-if="type !== 'view' && type !== 'detail' && checkPermission(['warehouseEntry:update'])" type="primary" @click="submitgoodsExchangeAddForm"
+        >入库
+      </el-button>
+      <el-button @click="printIng" v-if="type == 'audit'">打印</el-button>
+      <el-button @click="toBack()">返回</el-button>
+    </div>
+    <el-dialog title="提示" v-model="dialogVisible" width="30%">
+      <el-form :model="goodsExchangeAddForm" label-width="120px" inline style="width: 900px">
+        <el-form-item label="驳回原因" prop="reject_reason">
+          <el-input v-model="goodsExchangeAddForm.reject_reason" type="textarea" :minlength="0" :maxlength="100"></el-input>
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <el-button @click="dialogVisible = false">取 消</el-button>
+        <el-button type="primary" @click="handleRejectGoodsExchange()">确 定</el-button>
+      </template>
+    </el-dialog>
+    <el-dialog title="扫码入库" v-model="scanDialogVisible" width="30%" :close-on-click-modal="false">
+      <el-form ref="scanGoodsFormRef" :model="scanGoodsForm" label-width="120px" inline>
+        <el-form-item label="sku" prop="bar_code">
+          <el-input v-model="scanGoodsForm.bar_code" ref="inputRef" @keyup.enter="toSearch()" :minlength="0" :maxlength="100"></el-input>
+        </el-form-item>
+        <el-form-item label="序列号" prop="sn_code">
+          <el-input ref="sn_input" v-model="sn_code" @keyup.enter="toSnCode()" :minlength="0" :maxlength="100"></el-input>
+        </el-form-item>
+      </el-form>
+    </el-dialog>
+    <el-dialog title="入库商品" v-model="goodsVisible" width="1000px" @close="closeGoosData">
+      <div style="display: flex; align-items: center; justify-content: flex-end; padding: 10px 0">
+        <span>搜索商品:</span><el-input v-model="params.keyWord" style="width: 200px; margin-right: 5px"></el-input>
+        <el-button @click="searchGoodEvent"> 搜索 </el-button>
+      </div>
+      <el-table :data="goodsData.records" border style="width: 100%" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" />
+        <el-table-column prop="product_vo.name" label="商品名称"></el-table-column>
+        <el-table-column prop="product_vo.sku" label="sku"> </el-table-column>
+        <el-table-column prop="" label="品牌">
+          <template #default="scope">
+            {{ scope.row.product_vo.brand }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="product_vo.weight" label="重量"> </el-table-column>
+        <el-table-column prop="product_vo.unit" label="单位"> </el-table-column>
+      </el-table>
+      <el-pagination
+        @size-change="goodsPageSizeChange"
+        @current-change="goodsPageCurrentChange"
+        :current-page="goodsData.current"
+        :page-sizes="[10, 20, 50, 100]"
+        :page-size="goodsData.size"
+        layout="total, sizes, prev, pager, next, jumper"
+        :total="goodsData.total"
+      >
+      </el-pagination>
+      <template #footer>
+        <el-button @click="closeGoosData">取 消</el-button>
+        <el-button type="primary" @click="submitGoosData()">确 定</el-button>
+      </template>
+    </el-dialog>
+    <el-dialog title="订单列表" v-model="orderVisible" width="1000px" @close="closeGoosData">
+      <el-table :data="orderList.data" border style="width: 100%" ref="tables" @selection-change="handleSelOrderChange">
+        <el-table-column type="selection" width="55" />
+        <el-table-column prop="" label="订单编号">
+          <template #default="scope">
+            {{ scope.row.sn }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="order_time" label="下单时间">
+          <template #default="scope">{{ scope.row.order_time }}</template>
+        </el-table-column>
+        <el-table-column prop="" label="仓库名称">
+          <template #default="scope">
+            {{ warehouseName(scope.row.warehouse_id) }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="" label="配送方式">
+          <template #default="scope">{{ deliveryType(scope.row.send_type) }}</template>
+        </el-table-column>
+        <el-table-column prop="" label="实付金额">
+          <template #default="scope">{{ '¥' + scope.row.pay_price }}</template>
+        </el-table-column>
+      </el-table>
+      <el-pagination
+        @size-change="handlePageSizeChange"
+        @current-change="handlePageCurrentChange"
+        :current-page="orderList.page_no"
+        :page-sizes="[10, 20, 50, 100]"
+        :page-size="orderList.page_size"
+        layout="total, sizes, prev, pager, next, jumper"
+        :total="orderList.data_total"
+      >
+      </el-pagination>
+      <template #footer>
+        <el-button @click="closeOrder">取 消</el-button>
+        <el-button @click="searchOrderAdd" type="primary">确 定</el-button>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+  
+  <script setup>
+import { ref, reactive, computed, onMounted, watch, nextTick } from 'vue';
+import { useStore } from 'vuex';
+import { useRoute, useRouter } from 'vue-router';
+import { ElMessageBox, ElMessage } from 'element-plus';
+import * as API_GoodsExchange from '@/api/goodsExchange';
+import * as API_Setting from '@/api/setting';
+import * as API_BasicSetting from '@/api/basicSetting';
+/*   import * as API_Erp from '@/api/erp'; 
+  import * as API_Auth from '@/api/auth';
+  import * as API_order from '@/api/order';
+  import * as API_Goods from '@/api/goods';
+  import * as API_CollectingAccount from '@/api/collectingAccount'; */
+
+const store = useStore();
+const route = useRoute();
+const router = useRouter();
+
+const dialogVisible = ref(false);
+const scanDialogVisible = ref(false);
+const goodsVisible = ref(false);
+const orderVisible = ref(false);
+const snCodeVisible = ref(false);
+
+const goodsExchangeAddFormRef = ref();
+let goodsExchangeAddForm = reactive({
+  contract_product_list: [],
+  product_list: [],
+  warehouse_id: '',
+  type: '',
+  memo: '',
+  sn: '',
+  reject_reason: '',
+  order_id: '',
+});
+
+const goodsExchangeAddFormRule = {
+  warehouse_id: [{ required: true, message: '请选择入库仓库', trigger: 'change' }],
+  type: [{ required: true, message: '请选择入库类型', trigger: 'change' }],
+};
+
+const params = reactive({
+  page_no: 1,
+  page_size: 10,
+  keyWord: '',
+});
+
+const warehouseList = ref([]);
+const typeList = ref([]);
+const goodsData = ref([]);
+const orderList = ref([]);
+const sn_code = ref('');
+const scanGoodsForm = reactive({
+  bar_code: '',
+});
+const scanGoodsFormRef = ref();
+
+const type = ref('');
+const id = ref('');
+const orderType = ref(false);
+const TO_BE_RETURN = ref('');
+
+const checkPermission = (permissions) => {
+  // Implement your permission check logic here
+  return true;
+};
+
+const searchGoodEvent = () => {
+  API_GoodsExchange.getGoodsInfo(params, goodsExchangeAddForm.warehouse_id).then((res) => {
+    goodsData.value = res;
+  });
+};
+
+const handleSelOrderChange = (val) => {
+  if (val.length > 1) {
+    const lastSelected = val[val.length - 1];
+    orderList.value = [lastSelected];
+  }
+};
+
+const toBack = () => {
+  router.push({ name: 'goodsExchange', params: { type: 'second' } });
+};
+
+const toSnCode = async () => {
+  if (scanGoodsForm.bar_code === '') return;
+  const res = await API_GoodsExchange.getSnCode('in', scanGoodsForm.bar_code, sn_code.value.replace(/\s+/g, ''));
+  sn_code.value = '';
+  const exists = goodsExchangeAddForm.product_list.find((item) => item.sn_code === res.sn_code && item.sku === res.sku);
+  if (!exists) {
+    goodsExchangeAddForm.product_list.push(res);
+  }
+  if (TO_BE_RETURN.value === 'TO_BE_RETURN') {
+    if (goodsExchangeAddForm.product_list.length >= goodsExchangeAddForm.stock_num) {
+      return;
+    }
+  }
+  if (goodsExchangeAddForm.type === 'TRANSFER_ENTRY' || goodsExchangeAddForm.type === 'HAIL_ENTRY' || goodsExchangeAddForm.type === 'SALE_AFTER') {
+    if (goodsExchangeAddForm.product_list.length >= goodsExchangeAddForm.not_entry_num) {
+      return;
+    }
+  }
+  goodsExchangeAddForm.product_list.length = goodsExchangeAddForm.product_list.length;
+  scanGoodsForm.bar_code = '';
+};
+
+const addSnCode = (row, index) => {
+  scanGoodsForm.bar_code = row.product_vo.sku;
+  snCodeVisible.value = true;
+};
+
+const orderBtn = () => {
+  params.status = 'TO_BE_RETURN';
+  API_order.getOrderList(params).then((res) => {
+    orderList.value = res;
+    orderVisible.value = true;
+  });
+};
+
+const closeOrder = () => {
+  orderVisible.value = false;
+};
+
+const goodsPageSizeChange = (size) => {
+  params.page_size = size;
+  searchGoodEvent();
+};
+
+const goodsPageCurrentChange = (page) => {
+  params.page_no = page;
+  searchGoodEvent();
+};
+
+const handlePageSizeChange = (size) => {
+  params.page_size = size;
+  API_order.getOrderList(params).then((res) => {
+    orderList.value = res;
+  });
+};
+
+const handlePageCurrentChange = (page) => {
+  params.page_no = page;
+  API_order.getOrderList(params).then((res) => {
+    orderList.value = res;
+  });
+};
+
+const searchOrderAdd = () => {
+  if (orderList.value.length >= 1) {
+    API_GoodsExchange.getOneBySn(orderList.value[0].sn).then((res) => {
+      orderType.value = true;
+      goodsExchangeAddForm.type = res.scan_order_type === 'saleAfter' ? 'SALE_AFTER' : 'HAIL_ENTRY';
+      TO_BE_RETURN.value = res.status;
+      goodsExchangeAddForm.warehouse_id = res.return_warehouse_id;
+      goodsExchangeAddForm.scan_order_sn = orderList.value[0].sn;
+      goodsExchangeAddForm.scan_order_type = res.type;
+      goodsExchangeAddForm.order_id = res.id;
+      goodsExchangeAddForm.product_list = res.item_list
+        .filter((el) => el.stock_num > 0)
+        .map((el) => {
+          el.scan_order_item_id = el.id;
+          el.scan_order_id = res.id;
+          el.num = res.scan_order_type === 'saleAfter' ? el.return_num : 0;
+          el.order_num = res.scan_order_type === 'saleAfter' ? el.order_item_num : el.num;
+          el.sn_code_list = [];
+          return el;
+        });
+      orderVisible.value = false;
+    });
+  } else {
+    ElMessage.error('请选择订单');
+  }
+};
+
+const blurUsername = () => {
+  if (goodsExchangeAddForm.sn !== undefined) {
+    API_GoodsExchange.getOneBySn(goodsExchangeAddForm.sn).then((res) => {
+      orderType.value = true;
+      goodsExchangeAddForm.type = res.scan_order_type === 'saleAfter' ? 'SALE_AFTER' : 'HAIL_ENTRY';
+      goodsExchangeAddForm.warehouse_id = res.return_warehouse_id;
+      goodsExchangeAddForm.scan_order_sn = goodsExchangeAddForm.sn;
+      goodsExchangeAddForm.scan_order_type = res.type;
+      goodsExchangeAddForm.order_id = res.id;
+      res.item_list.forEach((el) => {
+        el.scan_order_item_id = el.id;
+        el.scan_order_id = res.id;
+        el.num = res.scan_order_type === 'saleAfter' ? el.return_num : 0;
+        el.order_num = res.scan_order_type === 'saleAfter' ? el.num : el.num;
+        el.sn_code_list = [];
+      });
+      goodsExchangeAddForm.product_list = res.item_list;
+    });
+  } else {
+    ElMessage.error('请填写订单编号');
+  }
+};
+/* 选中的商品列表 */
+const goodsList = ref([]);
+const handleSelectionChange = (val) => {
+  goodsList.value = val.map((el) => {
+    /* el.product_id = el.id;
+    el.goods_id = el.id;
+    el.sn_code_list = []; */
+    return el;
+  });
+};
+
+const submitGoosData = () => {
+  if (goodsList.value.length >= 1) {
+    goodsExchangeAddForm.product_list = goodsList.value.map((el) => {
+      /* el.sn_code_list = []; */
+      return el;
+    });
+    goodsVisible.value = false;
+  } else {
+    ElMessage.error('请选择商品信息');
+  }
+};
+
+const closeGoosData = () => {
+  goodsVisible.value = false;
+};
+
+const inputRef = ref();
+const scanCode = () => {
+  if (!goodsExchangeAddForm.warehouse_id) {
+    ElMessage.error('请先选择仓库!');
+    return;
+  }
+  scanDialogVisible.value = true;
+  nextTick(() => {
+    inputRef.value.focus();
+  });
+};
+
+const handleSelectWarehouseEntryBatch = () => {
+  if (!goodsExchangeAddForm.warehouse_id) {
+    ElMessage.error('请先选择仓库!');
+    return;
+  }
+  API_GoodsExchange.getGoodsInfo(params, goodsExchangeAddForm.warehouse_id, 'le').then((res) => {
+    goodsData.value = res;
+    goodsVisible.value = true;
+  });
+};
+
+const savegoodsExchangeAddForm = () => {
+  goodsExchangeAddFormRef.value.validate((valid) => {
+    if (valid) {
+      const params = { ...goodsExchangeAddForm };
+      params.save_or_submit = 'save';
+      if (!params.product_list.length) {
+        ElMessage.error('请选择商品!');
+        return;
+      }
+      params.product_list.forEach((el) => {
+        el.product_stock_id = el.id;
+        el.product_id = el.product_vo.id;
+        el.id = '';
+      });
+      if (type.value == 'edit') {
+        API_GoodsExchange.editWarehouseEntry(route.query.id, params).then((response) => {
+          ElMessage.success('修改成功!');
+          router.push({ name: 'goodsExchange' });
+        });
+      } else {
+        API_GoodsExchange.warehouseEntry(params).then(() => {
+          ElMessage.success('保存成功!');
+          router.push({ name: 'goodsExchange' });
+        });
+      }
+    }
+  });
+};
+
+const submitgoodsExchangeAddForm = () => {
+  goodsExchangeAddFormRef.value.validate((valid) => {
+    if (valid) {
+      const params = { ...goodsExchangeAddForm };
+      params.save_or_submit = 'submit';
+      if (!params.product_list.length) {
+        ElMessage.error('请选择商品!');
+        return;
+      }
+      params.product_list.forEach((el) => {
+        el.product_stock_id = el.id;
+        el.product_id = el.product_vo.id;
+        el.id = '';
+      });
+      if (type.value == 'edit') {
+        API_GoodsExchange.editWarehouseEntry(route.query.id, params).then((response) => {
+          ElMessage.success('修改成功!');
+          router.push({ name: 'goodsExchange' });
+        });
+      } else {
+        API_GoodsExchange.warehouseEntry(params).then(() => {
+          ElMessage.success('保存成功!');
+          router.push({ name: 'goodsExchange' });
+        });
+      }
+    }
+  });
+};
+/* 获取当前入库单详情 */
+const GET_WarehousInfo = () => {
+  API_GoodsExchange.getGoodsExchangeInfo(route.query.id).then((response) => {
+    API_Setting.getPage({ dictType: 'warehouse_entry_type' }).then((res) => {
+      Object.assign(typeList, res.data);
+    });
+    Object.assign(goodsExchangeAddForm, response);
+  });
+};
+
+onMounted(() => {
+  if (route.query.type == 'view') {
+    type.value = 'view';
+    GET_WarehousInfo();
+  } else if (route.query.type == 'edit') {
+    type.value = 'edit';
+    GET_WarehousInfo();
+  }
+  API_BasicSetting.getWarehouseListAll().then((response) => {
+    warehouseList.value = response;
+  });
+  API_Setting.getPage({ dictType: 'warehouse_entry_type' }).then((res) => {
+    typeList.value = res.data;
+  });
+});
+</script>
+
+<style scoped>
+/* 底部步骤 */
+.footer {
+  width: 100%;
+  padding: 10px;
+  bottom: 0px;
+  text-align: center;
+  z-index: 999;
+}
+
+.mx {
+  display: flex;
+  align-items: center;
+  width: 100%;
+}
+
+.mx .button {
+  margin-left: 10px;
+}
+
+.change-form {
+  display: flex;
+  justify-content: flex-start;
+  align-items: flex-start;
+  flex-wrap: wrap;
+  min-width: 900px;
+}
+
+.change-form .change-form-item {
+  width: 30%;
+  margin: 0 10px 20px 0;
+  display: flex;
+  flex-direction: row;
+  flex-wrap: nowrap;
+}
+
+.change-form .el-form-item__content {
+  flex: 1;
+  width: 100%;
+}
+
+.change-form .el-date-editor,
+.change-form .el-cascader,
+.change-form .el-select {
+  width: 100%;
+}
+
+.bg-in-stock {
+  background-color: #fff;
+  margin: 10px;
+  padding: 25px;
+}
+
+.goods-info {
+  display: flex;
+}
+
+.goods-info .goods-name-box {
+  text-align: left;
+}
+
+.goods-info .goods-name-box .goods-name {
+  text-overflow: ellipsis;
+  display: -webkit-box;
+  -webkit-line-clamp: 2;
+  -webkit-box-orient: vertical;
+  overflow: hidden;
+  line-height: 16px;
+}
+
+.goods-info .goods-name-box .specs {
+  color: #999999;
+}
+
+.sn-code-container {
+  max-height: 100px;
+  overflow-y: auto;
+}
+
+.el-input--suffix .el-input__inner {
+  padding-right: 10px;
+}
+
+.error-input .el-input__inner {
+  border: 1px solid red;
+}
+</style>

+ 731 - 0
src/views/stock/addOutbound.vue

@@ -0,0 +1,731 @@
+<template>
+  <div class="bg-in-stock">
+    <el-form ref="goodsExchangeAddFormRef" :model="goodsExchangeAddForm" :rules="goodsExchangeAddFormRule" label-width="160px" inline class="change-form">
+      <el-form-item prop="warehouse_id" label="出库仓库" class="change-form-item">
+        <el-select v-model="goodsExchangeAddForm.warehouse_id" :disabled="type === 'view' || type === 'audit'">
+          <el-option v-for="item in warehouseList" :key="item.id" :label="item.name" :value="item.id" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="类型" prop="type" class="change-form-item">
+        <el-select v-model="goodsExchangeAddForm.type" filterable allow-create clearable default-first-option :disabled="type === 'view' || type === 'audit'">
+          <el-option
+            v-for="item in typeList"
+            :key="item.value"
+            :label="item.label"
+            :value="item.value"
+            :disabled="item.value == 'SALE_OUT' || item.value == 'HAIL_OUT' || item.value == 'DAMAGE_OUT' || item.value == 'TRANSFER_OUT'"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="备注" prop="notes" class="change-form-item" style="width: 61%">
+        <el-input
+          style="flex: 1"
+          v-model="goodsExchangeAddForm.notes"
+          type="textarea"
+          :disabled="type === 'view' || type === 'audit'"
+          maxlength="250"
+          :autosize="{ minRows: 3, maxRows: 4 }"
+          placeholder="请输入"
+        ></el-input>
+      </el-form-item>
+      <div class="mx">
+        <h3>商品明细</h3>
+        <el-button class="button" size="mini" type="primary" v-if="type !== 'view' && type !== 'audit'" @click="scanCode">扫码出库</el-button>
+        <el-button class="button" size="mini" type="primary" v-if="type !== 'view' && type !== 'audit'" @click="handleSelectWarehouseEntryBatch"
+          >选择</el-button
+        >
+      </div>
+      <div style="width: 100%; display: block">
+        <el-form-item style="width: 100%">
+          <el-table
+            :data="goodsExchangeAddForm.product_list"
+            border
+            :cell-style="{ textAlign: 'center' }"
+            :header-cell-style="{ textAlign: 'center' }"
+            style="width: 100%; margin-top: 20px"
+          >
+            <el-table-column label="库位号">
+              <template #default="scope">
+                <el-popover placement="right" trigger="click" v-if="scope.row.area_stock_list">
+                  <div>
+                    <p v-for="item in scope.row.area_stock_list" :key="item.id">{{ item.warehouse_area_name }}</p>
+                  </div>
+                  <span slot="reference" v-if="scope.row.area_stock_list.length !== 0">{{ scope.row.area_stock_list[0].warehouse_area_name }}</span>
+                </el-popover>
+              </template>
+            </el-table-column>
+            <!-- <el-table-column label="商品编号">
+              <template #default="scope">
+                <span v-if="id">{{ scope.row.goods_vo.sn }}</span>
+                <span v-else>{{ scope.row.goods_vo.sn }}</span>
+              </template>
+            </el-table-column> -->
+            <el-table-column label="商品名称">
+              <template #default="scope">
+                <span v-if="id">{{ scope.row.product_vo.name }}</span>
+                <span v-else>{{ scope.row.product_vo.name }}</span>
+              </template>
+            </el-table-column>
+            <el-table-column label="sku">
+              <template #default="scope">
+                <span v-if="id">{{ scope.row.product_vo.sku }}</span>
+                <span v-else>{{ scope.row.product_vo.sku }}</span>
+              </template>
+            </el-table-column>
+            <!-- <el-table-column label="序列号" v-if="sn_code_list">
+              <template #default="scope">
+                <div class="sn-code-container">
+                  <span v-for="item in scope.row.sn_code_list" :key="item.id">
+                    <p>{{ item.sn_code }}</p>
+                  </span>
+                </div>
+              </template>
+            </el-table-column> 
+            <el-table-column prop="product_vo.spec_name" label="规格型号" v-if="id"> </el-table-column>
+            <el-table-column prop="product_vo.spec_name" label="规格型号" v-else> </el-table-column>-->
+            <el-table-column label="单位">
+              <template #default="scope">
+                {{ scope.row.product_vo.unit }}
+                <!--  <span v-if="id">{{ scope.row.product_vo.unit }}</span>
+                <span v-else>{{ scope.row.product_vo.unit }}</span> -->
+              </template>
+            </el-table-column>
+            <el-table-column label="出库数量">
+              <template #default="scope">
+                <el-input v-model="scope.row.out_num" type="number" :min="0" :maxlength="20" :disabled="type === 'view' || type === 'audit'"></el-input>
+              </template>
+            </el-table-column>
+            <!-- <el-table-column label="订单数量">
+              <template #default="scope">
+                {{ scope.row.order_num }}
+              </template>
+            </el-table-column> -->
+            <el-table-column label="可用库存">
+              <template #default="scope">
+                {{ scope.row.usable_stock }}
+              </template>
+            </el-table-column>
+            <el-table-column label="实际库存">
+              <template #default="scope">
+                {{ scope.row.actual_stock }}
+              </template>
+            </el-table-column>
+            <el-table-column width="200" label="操作" v-if="type !== 'view' && type !== 'audit'">
+              <template #default="scope">
+                <el-button size="mini" type="danger" @click="goodsExchangeAddForm.product_list.splice(scope.$index, 1)">删除</el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+        </el-form-item>
+      </div>
+    </el-form>
+    <div class="footer">
+      <el-button v-if="type !== 'audit' && type !== 'view' && checkPermission(['warehouseOut2:add'])" type="primary" @click="saveGoodsExchangeAddForm"
+        >保存
+      </el-button>
+      <el-button v-if="type !== 'audit' && type !== 'view' && checkPermission(['warehouseOut:update'])" type="primary" @click="submitGoodsExchangeAddForm"
+        >出库
+      </el-button>
+      <el-button @click="printIng" v-if="type == 'audit'">打印</el-button>
+      <el-button @click="toBack()">返回</el-button>
+    </div>
+
+    <el-dialog title="提示" v-model:visible="dialogVisible" width="30%">
+      <el-form ref="goodsExchangeAddForm" :model="goodsExchangeAddForm" label-width="120px" inline style="width: 900px">
+        <el-form-item label="驳回原因" prop="reject_reason">
+          <el-input v-model="goodsExchangeAddForm.reject_reason" type="textarea" :minlength="0" :maxlength="100"></el-input>
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <el-button @click="dialogVisible = false">取 消</el-button>
+        <el-button type="primary" @click="handleRejectGoodsExchange()">确 定</el-button>
+      </template>
+    </el-dialog>
+    <el-dialog title="扫码出库" v-model:visible="scanDialogVisible" width="30%" :close-on-click-modal="false">
+      <el-form ref="scanGoodsForm" :model="scanGoodsForm" label-width="120px" inline>
+        <el-form-item label="sku" prop="bar_code">
+          <el-input v-model="scanGoodsForm.bar_code" ref="input" @keyup.enter="toSearch()" :minlength="0" :maxlength="100"></el-input>
+        </el-form-item>
+        <el-form-item label="序列号" prop="sn_code">
+          <el-input v-model="sn_code" ref="sn_input" @keyup.enter="toSnCode()" :minlength="0" :maxlength="100"></el-input>
+        </el-form-item>
+      </el-form>
+    </el-dialog>
+    <el-dialog title="出库商品" v-model="goodsVisible" width="1000px" @close="closeGoosData">
+      <div style="display: flex; align-items: center; justify-content: flex-end; padding: 10px 0">
+        <span>搜索商品:</span><el-input v-model="params.keyWord" style="width: 200px; margin-right: 5px"></el-input>
+        <el-button @click="searchGoodEvent"> 搜索 </el-button>
+      </div>
+      <el-table :data="goodsData.records" border style="width: 100%" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" />
+        <el-table-column prop="product_vo.name" label="商品名称"></el-table-column>
+        <el-table-column prop="product_vo.sku" label="sku"> </el-table-column>
+        <el-table-column prop="" label="品牌">
+          <template #default="scope">
+            {{ scope.row.product_vo.brand }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="product_vo.weight" label="重量"> </el-table-column>
+        <el-table-column prop="product_vo.unit" label="单位"> </el-table-column>
+      </el-table>
+      <el-pagination
+        @size-change="goodsPageSizeChange"
+        @current-change="goodsPageCurrentChange"
+        :current-page="goodsData.current"
+        :page-sizes="[10, 20, 50, 100]"
+        :page-size="goodsData.size"
+        layout="total, sizes, prev, pager, next, jumper"
+        :total="goodsData.total"
+      >
+      </el-pagination>
+      <template #footer>
+        <el-button @click="closeGoosData">取 消</el-button>
+        <el-button type="primary" @click="submitGoosData()">确 定</el-button>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+  
+  <script setup>
+import { ref, onMounted, computed, watch, reactive,nextTick } from 'vue';
+import { useStore, mapGetters } from 'vuex';
+import * as API_GoodsExchange from '@/api/goodsExchange';
+import * as API_Setting from '@/api/setting';
+import * as API_BasicSetting from '@/api/basicSetting';
+import { useRoute, useRouter } from 'vue-router';
+import { ElMessageBox, ElMessage } from 'element-plus';
+
+const route = useRoute();
+const router = useRouter();
+/* import * as API_Erp from '@/api/erp';
+import * as API_Auth from '@/api/auth'; */
+
+const store = useStore();
+const goodsExchangeAddForm = ref({
+  /*   order_list: [
+    {
+      order_id: '1752156400898293761',
+      order_item_list: [
+        {
+          batch_list: [
+            {
+              batch_id: 0,
+              batch_sn: '',
+              out_num: 0,
+              remain_num: 0,
+              warehouse_entry_sn: '',
+            },
+          ],
+          num: 0,
+          order_item_id: 0,
+          product_id: 0,
+          product_name: 'string',
+          product_sn: 'string',
+          product_specification: 'string',
+          product_unit: 'string',
+        },
+      ],
+      order_sn: '',
+    },
+  ], */
+  product_list: [],
+  type: '',
+});
+const goodsExchangeAddFormRule = ref({
+  warehouse_id: [{ required: true, message: '请选择出库仓库', trigger: 'change' }],
+  type: [{ required: true, message: '请选择出库类型', trigger: 'change' }],
+});
+const typeList = ref([]);
+const adminList = ref([]);
+const dialogVisible = ref(false);
+const warehouseList = ref([]);
+const deptList = ref([]);
+const deptListAll = ref([]);
+const orderList = ref([]);
+const id = ref('');
+const type = ref('');
+const warehouseProduct = ref(null);
+const scanDialogVisible = ref(false);
+const scanGoodsForm = ref({});
+const routeName = ref('');
+const sttorageType = ref('');
+const goodsVisible = ref(false);
+const goodsData = ref([]);
+const snCodeVisible = ref(false);
+const sn_code = ref('');
+const sku = ref('');
+const sn_code_list = ref([]);
+const index = ref('');
+
+const user = computed(() => store.getters.user);
+
+const checkPrice = (rule, value, callback) => {
+  if (!value && value !== 0) {
+    return callback(new Error('换货金额不能为空'));
+  } else if (!RegExp.money.test(value)) {
+    callback(new Error('请输入正整数或者两位小数'));
+  } else if (parseFloat(value) > 99999999) {
+    callback(new Error('换货金额设置超过上限值'));
+  } else {
+    callback();
+  }
+};
+
+const toBack = () => {
+  router.push({
+    name: 'goodsOutBound',
+  });
+};
+/* 扫描sku */
+const toSnCode = async () => {
+  if (sku.value == '') return ElMessage.error('请录入正确的sku');
+  await API_GoodsExchange.getSnCode('out', sku.value, sn_code.value.replace(/\s+/g, '')).then(async (res) => {
+    sn_code.value = '';
+    let exists = goodsExchangeAddForm.value.product_list[index.value].sn_code_list.find((item) => item.sn_code === res.sn_code && item.sku === res.sku);
+    if (!exists) {
+      if (id.value) {
+        await API_GoodsExchange.skuRedis({
+          send_order_id: id.value,
+          item_id: goodsExchangeAddForm.value.product_list[index.value].id,
+          sku: res,
+        }).then((response) => {
+          goodsExchangeAddForm.value.product_list[index.value].sn_code_list.push(res);
+        });
+      } else {
+        goodsExchangeAddForm.value.product_list[index.value].sn_code_list.push(res);
+      }
+    }
+    goodsExchangeAddForm.value.product_list[index.value].out_num = goodsExchangeAddForm.value.product_list[index.value].sn_code_list.length;
+    scanGoodsForm.value.bar_code = '';
+    nextTick(() => {
+      refs.input.focus();
+    });
+  });
+};
+
+const addSnCode = (row, index) => {
+  sku.value = row.product_vo.sku;
+  index.value = index;
+  snCodeVisible.value = true;
+};
+
+const outType = () => {
+  API_Setting.getPage({ dictType: 'out_warehouse_type' }).then((res) => {
+    typeList.value = res.data;
+  });
+};
+
+const printIng = () => {};
+/* 扫描序列号 */
+const toSearch = () => {
+  API_GoodsExchange.getProduct(goodsExchangeAddForm.value.warehouse_id, scanGoodsForm.value.bar_code.replace(/\s+/g, '')).then((res) => {
+    res.sn_code_list = [];
+    sku.value = res.product_vo.sku;
+    const indexs = goodsExchangeAddForm.value.product_list.findIndex((el) => {
+      return el.goods_id === res.goods_id && el.product_id === res.product_id && el.product_vo.sku === res.product_vo.sku;
+    });
+    if (indexs === -1) {
+      index.value = goodsExchangeAddForm.value.product_list.length;
+      goodsExchangeAddForm.value.product_list.push(res);
+    } else {
+      index.value = indexs;
+    }
+    if (res.product_vo.have_sn) {
+      nextTick(() => {
+        refs.sn_input.focus();
+      });
+    } else {
+      goodsExchangeAddForm.value.product_list[index.value].num += 1;
+    }
+  });
+};
+
+const scanCode = () => {
+  if (!goodsExchangeAddForm.value.warehouse_id) {
+    ElMessage.error('请先选择仓库!');
+    return;
+  }
+  scanDialogVisible.value = true;
+  nextTick(() => {
+    refs.input.focus();
+  });
+};
+
+const GET_AdministratorList = () => {
+  API_Auth.getAdministratorList({
+    page_no: 1,
+    page_size: 9999,
+    user_state: 0,
+  }).then((response) => {
+    adminList.value = response.data;
+  });
+};
+
+const GET_WarehouseList = (e) => {
+  API_BasicSetting.getWarehouseListAll().then((response) => {
+    warehouseList.value = response;
+  });
+};
+
+const goodsExchangeAddFormRef = ref();
+const saveGoodsExchangeAddForm = () => {
+  console.log(112);
+  goodsExchangeAddFormRef.value.validate((valid) => {
+    if (valid) {
+      const { id } = goodsExchangeAddForm.value;
+      const params = { ...goodsExchangeAddForm.value };
+      params.save_or_submit = 'save';
+      params.warehouse_consignee_id = deptListAll.value.id;
+      params.out_time = Date.parse(new Date());
+      params.staff_name = goodsExchangeAddForm.value.distribution_name;
+      if (params.warehouse_id) {
+        params.warehouse_name = warehouseList.value.find((ware) => ware.id === params.warehouse_id).name;
+      }
+      if (params.handled_by_id) {
+        params.handled_by = adminList.value.find((admin) => admin.id === params.handled_by_id).real_name;
+      }
+      params.change_time = Math.floor(params.change_time / 1000);
+
+      if (!goodsExchangeAddForm.value.product_list.length) {
+        return;
+      }
+      if (params.type == 'OTHER_OUT' || params.type == 'BORROW_OUT') {
+        const isStockSufficient = params.product_list.map((el) => {
+          if (el.out_num > el.usable_stock) {
+            ElMessage.error('该商品库存不足!');
+            return false;
+          }
+          return true;
+        });
+        if (!isStockSufficient) {
+          return;
+        }
+      }
+      if (type.value == 'edit') {
+        API_GoodsExchange.editWarehouseOut(id, params).then((response) => {
+          ElMessage.success('修改成功!');
+          /* const { callback } = this.$route.params;
+          if (typeof callback === 'function') callback();
+          store.dispatch('delCurrentViews', {
+            view: this.$route,
+            $router: this.$router,
+          }); */
+          router.push({ name: 'goodsOutBound' });
+        });
+      } else {
+        console.log(params);
+        params.product_list.map((el) => {
+          el.product_stock_id = el.id;
+          el.id = '';
+        });
+        API_GoodsExchange.warehouseOut(params).then(() => {
+          ElMessage.success('添加成功!');
+          /* const { callback } = this.$route.params;
+          if (typeof callback === 'function') callback();
+          store.dispatch('delCurrentViews', {
+            view: this.$route,
+            $router: this.$router,
+          }); */
+          router.push({ name: 'goodsOutBound' });
+        });
+      }
+    }
+  });
+};
+
+const submitGoodsExchangeAddForm = () => {
+  goodsExchangeAddFormRef.value.validate((valid) => {
+    if (valid) {
+      const { id } = goodsExchangeAddForm.value;
+      const params = { ...goodsExchangeAddForm.value };
+      params.save_or_submit = 'submit';
+      params.warehouse_consignee_id = deptListAll.value.id;
+      params.out_time = Date.parse(new Date());
+      params.staff_name = goodsExchangeAddForm.value.distribution_name;
+      if (params.warehouse_id) {
+        params.warehouse_name = warehouseList.value.find((ware) => ware.id === params.warehouse_id).name;
+      }
+      if (params.handled_by_id) {
+        params.handled_by = adminList.value.find((admin) => admin.id === params.handled_by_id).real_name;
+      }
+      params.change_time = Math.floor(params.change_time / 1000);
+      if (!goodsExchangeAddForm.value.product_list.length) {
+        ElMessage.error('请选择商品!');
+        return;
+      }
+      if (params.type == 'OTHER_OUT' || params.type == 'BORROW_OUT') {
+        const isStockSufficient = params.product_list.map((el) => {
+          if (el.out_num > el.usable_stock) {
+            ElMessage.error('该商品库存不足!');
+            return false;
+          }
+          return true;
+        });
+        if (!isStockSufficient) {
+          return;
+        }
+      }
+      if (type.value == 'edit') {
+        API_GoodsExchange.editWarehouseOut(id, params).then((response) => {
+          ElMessage.success('修改成功!');
+          /* const { callback } = this.$route.params;
+          if (typeof callback === 'function') callback();
+          store.dispatch('delCurrentViews', {
+            view: this.$route,
+            $router: this.$router,
+          }); */
+         router.push({ name: 'goodsOutBound' });
+        });
+      } else {
+        params.product_list.map((el) => {
+          el.product_stock_id = el.id;
+          el.id = '';
+        });
+        API_GoodsExchange.warehouseOut(params).then(() => {
+          ElMessage.success('添加成功!');
+          /* const { callback } = this.$route.params;
+          if (typeof callback === 'function') callback();
+          store.dispatch('delCurrentViews', {
+            view: this.$route,
+            $router: this.$router,
+          }); */
+          router.push({ name: 'goodsOutBound' });
+        });
+      }
+    }
+  });
+};
+
+/* 关闭入库窗口 */
+const closeGoosData = () => {
+  goodsVisible.value = false;
+};
+
+/* 打开商品弹窗 */
+const params = reactive({
+  page_no: 1,
+  page_size: 10,
+  keyWord: '',
+});
+const handleSelectWarehouseEntryBatch = async () => {
+  if (!goodsExchangeAddForm.value.warehouse_id) {
+    ElMessage.error('请先选择仓库!');
+    return;
+  }
+  API_GoodsExchange.getGoodsInfo(params, goodsExchangeAddForm.value.warehouse_id, 'gt').then((res) => {
+    goodsData.value = res;
+    goodsVisible.value = true;
+  });
+};
+/* 选中的商品列表 */
+const goodsList = ref([]);
+const handleSelectionChange = (val) => {
+  goodsList.value = val.map((el) => {
+    return el;
+  });
+};
+const submitGoosData = () => {
+  if (goodsList.value.length >= 1) {
+    goodsExchangeAddForm.value.product_list = goodsList.value.map((el) => {
+      return el;
+    });
+    goodsVisible.value = false;
+  } else {
+    ElMessage.error('请选择商品信息');
+  }
+};
+const goodsPageSizeChange = (size) => {
+  params.page_size = size;
+  searchGoodEvent();
+};
+
+const goodsPageCurrentChange = (page) => {
+  params.page_no = page;
+  searchGoodEvent();
+};
+
+const handleSelectOrderSn = async () => {
+  const orders = await this.$EnPickerOrder({
+    orderApi: 'admin/erp/order',
+    selectedIds: [goodsExchangeAddForm.value.order_sn],
+    limit: 1,
+  });
+  this.$set(goodsExchangeAddForm.value, 'distribution_name', orders[0].distribution_name);
+  const orderIds = orders.map((v) => v.sn);
+  this.$set(goodsExchangeAddForm.value, 'order_sn', orderIds.join(','));
+  GET_WarehouseOutProduct();
+};
+
+const GET_WarehouseOutProduct = async () => {
+  const res = await API_Erp.getWarehouseOutProduct({
+    order_sn: goodsExchangeAddForm.value.order_sn,
+  });
+  goodsExchangeAddForm.value.return_list = res.data.map((item) => {
+    item.amount = item.product_price;
+    item.product_sn = item.product_sn;
+    item.product_name = item.product_name;
+    item.specification = item.product_specification;
+    item.product_id = item.product_id;
+    item.unit = item.product_unit;
+    item.out_num = item.return_num;
+    item.stock_sn = item.warehouse_entry_sn;
+    item.cost_price = item.product_cost_price;
+    return item;
+  });
+};
+
+const GET_DeptList = () => {
+  API_GoodsExchange.getInfo().then((response) => {
+    deptListAll.value = response;
+    deptListAll.value.password = '';
+  });
+};
+
+const handleChangeWareHouse = (val) => {
+  // this.goodsExchangeAddForm.product_list = []change_list
+};
+
+const GET_goodsExchangeAddDetail = () => {
+  nextTick(() => {
+    API_GoodsExchange.getGoodsWarehouseOut(route.query.id).then((response) => {
+      goodsExchangeAddForm.value = response;
+      GET_WarehouseList({ dept_id: response.warehouse_id });
+      goodsExchangeAddForm.value.change_time = Math.floor(goodsExchangeAddForm.value.change_time * 1000);
+      /* response.product_list.map((el) => {
+        el.order_num = el.out_num;
+        el.out_num = 0;
+        if (!el.sn_code_list) {
+          el.sn_code_list = [];
+        } else {
+          el.out_num = el.sn_code_list;
+        }
+      }); */
+      goodsExchangeAddForm.value.distribution_name = response.staff_name;
+      goodsExchangeAddForm.value.product_list = response.product_list;
+    });
+  });
+};
+
+onMounted(() => {
+  if (route.query.type == 'view') {
+    type.value = 'view';
+    GET_goodsExchangeAddDetail();
+  } else if (route.query.type == 'edit') {
+    type.value = 'edit';
+    GET_goodsExchangeAddDetail();
+  }
+  routeName.value = route.name;
+  sttorageType.value = route.params.type;
+  GET_WarehouseList();
+  GET_DeptList();
+  outType();
+});
+
+/* watch(() => route, {
+  immediate: true,
+  handler(newVal) {
+    if (route.name === 'goodsExchangeEdit') {
+      type.value = 'edit';
+    } else if (route.name === 'goodsExchangeAudit') {
+      type.value = 'audit';
+    } else if (route.name === 'goodsExchangeReturn') {
+      type.value = 'return';
+    } else if (route.name === 'goodsExchangeAdd') {
+      type.value = 'add';
+      GET_WarehouseList({ dept_id: user.value.dept_id });
+      set(goodsExchangeAddForm.value, 'change_time', new Date().getTime());
+    } else if (route.name === 'goodsExchangeDetail') {
+      type.value = 'detail';
+    }
+    if (route.params.id) {
+      id.value = route.params.id;
+      GET_goodsExchangeAddDetail();
+    }
+    GET_AdministratorList();
+  },
+}); */
+</script>
+
+<style scoped>
+.footer {
+  width: 100%;
+  padding: 10px;
+  bottom: 0px;
+  text-align: center;
+  z-index: 999;
+}
+
+.mx {
+  display: flex;
+  align-items: center;
+  width: 100%;
+}
+
+.mx .button {
+  margin-left: 10px;
+}
+
+.change-form {
+  display: flex;
+  justify-content: flex-start;
+  align-items: flex-start;
+  flex-wrap: wrap;
+  min-width: 900px;
+}
+
+.change-form .change-form-item {
+  width: 30%;
+  margin: 0 10px 20px 0;
+  display: flex;
+  flex-direction: row;
+  flex-wrap: nowrap;
+}
+
+.change-form .el-form-item__content,
+.change-form .el-date-editor,
+.change-form .el-cascader,
+.change-form .el-select {
+  flex: 1;
+  width: 100%;
+}
+
+.bg-in-stock {
+  background-color: #fff;
+  margin: 10px;
+  padding: 25px;
+}
+
+.goods-info {
+  display: flex;
+}
+
+.goods-info .goods-name-box {
+  text-align: left;
+}
+
+.goods-info .goods-name-box .goods-name {
+  text-overflow: ellipsis;
+  display: -webkit-box;
+  -webkit-line-clamp: 2;
+  -webkit-box-orient: vertical;
+  overflow: hidden;
+  line-height: 16px;
+}
+
+.goods-info .goods-name-box .specs {
+  color: #999999;
+}
+
+.sn-code-container {
+  max-height: 100px;
+  overflow-y: auto;
+}
+
+.el-input--suffix .el-input__inner {
+  padding-right: 10px;
+}
+
+.error-input .el-input__inner {
+  border: 1px solid red;
+}
+</style>

+ 416 - 0
src/views/stock/goodsInventory.vue

@@ -0,0 +1,416 @@
+<template>
+  <div>
+    <div class="search bg-white p-3">
+      <el-form ref="advancedForm" :model="advancedForm" label-width="160px">
+        <el-row>
+          <el-col :span="6">
+            <el-form-item label="盘点日期">
+              <el-date-picker
+                v-model="searchTime"
+                type="daterange"
+                align="center"
+                :editable="false"
+                unlink-panels
+                :clearable="true"
+                :default-time="['00:00:00', '23:59:59']"
+                range-separator="-"
+                start-placeholder="开始日期"
+                end-placeholder="结束日期"
+                value-format="yyyy-MM-dd hh:mm:ss"
+              >
+              </el-date-picker>
+            </el-form-item>
+          </el-col>
+          <el-col :span="6">
+            <el-form-item label="仓库">
+              <el-select v-model="advancedForm.warehouse_id" clearable>
+                <el-option v-for="item in warehouseList" :key="item.id" :label="item.name" :value="item.id" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="6">
+            <el-form-item label="盘点人">
+              <el-select v-model="advancedForm.inventory_person_id" clearable>
+                <el-option v-for="item in adminList" :key="item.id" :label="item.real_name" :value="item.id" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <div class="flex justify-end">
+        <el-button @click="advancedSearchEvent"> 搜索 </el-button>
+      </div>
+    </div>
+    <en-table-layout :tableData="tableData.data" :loading="loading" @selection-change="handleSelectionChange">
+      <template #toolbar>
+        <div class="inner-toolbar">
+          <div class="toolbar-btns">
+            <!-- v-if="checkPermission(['goodsInventory:add'])" type="primary" -->
+            <el-button size="mini" @click="handleAddGoodsInventory">新增</el-button>
+          </div>
+        </div>
+      </template>
+
+      <template #table-columns>
+        <el-table-column type="selection" width="55" />
+        <el-table-column prop="sn" label="盘点单编号">
+          <template #default="scope">
+            <span>{{ scope.row.sn }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="inventory_time" label="盘点日期">
+          <template #default="scope">{{ scope.row.inventory_time }}</template>
+        </el-table-column>
+        <el-table-column prop="warehouse_name" label="仓库">
+          <template #default="scope">{{ warehouseName(scope.row.warehouse_id) }}</template>
+        </el-table-column>
+        <el-table-column prop="status" label="状态">
+          <template #default="scope">{{ statusFilter(scope.row.status) }}</template>
+        </el-table-column>
+        <el-table-column label="操作" width="450">
+          <template #default="scope">
+            <!-- v-if="checkPermission(['goodsInventoryCheck'])" -->
+            <el-button size="mini" @click="handleCheckGoodsInventory(scope.row)">查看</el-button>
+            <!--  && checkPermission(['goodsInventoryEdit']) -->
+            <el-button v-if="scope.row.status == 'NOT_HANDLE'" size="mini" @click="handleEditGoodsInventory(scope.row)">编辑</el-button>
+            <!--  && checkPermission(['goodsInventory:sync']) -->
+            <el-button type="mini" size="mini" v-if="scope.row.status == 'NOT_HANDLE'" @click="handleSubmitGoodsInventory(scope.row)">同步</el-button>
+          </template>
+        </el-table-column>
+      </template>
+
+      <el-pagination
+        v-if="tableData"
+        @size-change="handlePageSizeChange"
+        @current-change="handlePageCurrentChange"
+        :current-page="tableData.page_no"
+        :page-sizes="[10, 20, 50, 100]"
+        :page-size="tableData.page_size"
+        layout="total, sizes, prev, pager, next, jumper"
+        :total="tableData.data_total"
+      >
+      </el-pagination>
+    </en-table-layout>
+
+    <el-dialog v-model="dialogVisible" width="940px" center>
+      <div style="width: 900px">
+        <el-button size="mini" type="primary" @click="handlePrintGoodsInventory" class="print no-btn">打印</el-button>
+        <div id="deliverySheet" slot="header" class="deliverySheet-header">
+          <h3>产品库存盘点单</h3>
+        </div>
+        <div class="tips-t">
+          <div>仓库名称编码:{{ goodsInventoryForm.dept_name }}{{ goodsInventoryForm.warehouse_name }}</div>
+          <div>日期:{{ goodsInventoryForm.inventory_time }}</div>
+          <div>编号:{{ goodsInventoryForm.sn }}</div>
+        </div>
+        <el-table
+          :data="goodsInventoryForm.product_list"
+          border
+          :cell-style="{ textAlign: 'center' }"
+          :header-cell-style="{ textAlign: 'center' }"
+          style="width: 100%"
+        >
+          <el-table-column label="序号" width="179">
+            <template #default="scope">
+              {{ scope.$index + 1 }}
+            </template>
+          </el-table-column>
+          <el-table-column label="商品编号" width="170">
+            <template #default="scope">
+              {{ scope.row.product_sn }}
+            </template>
+          </el-table-column>
+          <el-table-column label="商品名称" width="170">
+            <template #default="scope">
+              {{ scope.row.product_name }}
+            </template>
+          </el-table-column>
+          <el-table-column label="规格型号" width="110">
+            <template #default="scope">
+              {{ scope.row.specification }}
+            </template>
+          </el-table-column>
+          <el-table-column label="单位" width="50">
+            <template #default="scope">
+              {{ scope.row.unit }}
+            </template>
+          </el-table-column>
+          <el-table-column label="上期盘点库存" width="110">
+            <template #default="scope">
+              {{ scope.row.stock_num }}
+            </template>
+          </el-table-column>
+          <el-table-column label="本期盘点库存" width="110">
+            <template #default="scope">
+              {{ scope.row.inventory_num }}
+            </template>
+          </el-table-column>
+        </el-table>
+        <div class="tips-t">
+          <div>盘点人:{{ goodsInventoryForm.inventory_person }}</div>
+        </div>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+  
+  <script lang="ts" setup>
+import { ref, onMounted, watch } from 'vue';
+import { useRouter, useRoute } from 'vue-router';
+import * as API_GoodsInventory from '@/api/goodsInventory';
+import Print from 'print-js';
+import * as API_Auth from '@/api/auth';
+import * as API_Setting from '@/api/setting';
+import * as API_BasicSetting from '@/api/basicSetting';
+/*  import { Foundation } from '~/ui-utils'; */
+import { ElMessage, ElMessageBox } from 'element-plus';
+
+const router = useRouter();
+const route = useRoute();
+
+const warehouseList = ref([]);
+const deptList = ref([]);
+const loading = ref(false);
+const params = ref({
+  page_no: 1,
+  page_size: 10,
+});
+const advancedForm = ref({});
+const tableData = ref<any>({});
+const dialogVisible = ref(false);
+const multipleSelection = ref([]);
+const goodsInventoryForm = ref<any>({});
+const adminList = ref([]);
+const searchTime = ref([]);
+
+onMounted(() => {
+  GET_GoodsInventoryList();
+  /* GET_DeptList(); */
+  GET_WarehouseList();
+});
+
+watch(route, () => {
+  params.value.page_no = 1;
+  GET_GoodsInventoryList();
+});
+
+const GET_WarehouseList = () => {
+  API_BasicSetting.getWarehouseListAll().then((response) => {
+    warehouseList.value = response;
+  });
+  API_Auth.getAdministratorList({
+    page_no: 1,
+    page_size: 9999,
+    user_state: 0,
+  }).then((response) => {
+    adminList.value = response.data;
+  });
+};
+
+const handleCheckGoodsInventory = (row) => {
+  router.push({
+    name: 'goodsInventoryAdd',
+    query: {
+      id: row.id,
+      type: 'view',
+    },
+  });
+};
+
+const handleEditGoodsInventory = (row) => {
+  router.push({
+    name: 'goodsInventoryAdd',
+    query: {
+      id: row.id,
+      type: 'edit',
+    },
+  });
+};
+
+const handleSubmitGoodsInventory = (row) => {
+  API_GoodsInventory.getSyncStock(row.id).then(() => {
+    ElMessage.success('处理成功!');
+    GET_GoodsInventoryList();
+  });
+};
+
+const handleAddGoodsInventory = () => {
+  router.push({
+    name: 'goodsInventoryAdd',
+    /*   params: { callback: GET_GoodsInventoryList } */
+  });
+};
+
+const handlePrintGoodsInventoryDialog = (row) => {
+  GET_GoodsInventoryDetail(row.id);
+};
+
+const handleDeleteGoodsInventory = () => {
+  if (!multipleSelection.value.length) return ElMessage.error('请先选择!');
+  ElMessageBox.confirm('确定要删除当前盘点单吗?', '提示', { type: 'warning' })
+    .then(() => {
+      const ids = multipleSelection.value.map((item) => item.id);
+      API_GoodsInventory.deleteGoodsInventory(ids).then(() => {
+        ElMessage.success('删除成功!');
+        GET_GoodsInventoryList();
+      });
+    })
+    .catch(() => {});
+};
+
+const statusFilter = (val) => {
+  switch (val) {
+    case 'NOT_HANDLE':
+      return '未处理';
+    case 'HAS_HANDLE':
+      return '已处理';
+  }
+};
+
+const warehouseName = (val) => {
+  let name = '';
+  warehouseList.value.map((el) => {
+    if (el.id == val) {
+      name = el.name;
+    }
+  });
+  return name;
+};
+
+const GET_DeptList = () => {
+  API_Setting.getDeptList().then((response) => {
+    deptList.value = Foundation.buildTree(response, '0');
+  });
+};
+
+const handlePrintGoodsInventory = () => {
+  Print({
+    printable: 'deliverySheet',
+    type: 'html',
+    targetStyles: ['*'],
+    ignoreElements: ['no-logs', 'goods-image', 'no-btn'],
+  });
+};
+
+const handleSelectionChange = (val) => {
+  multipleSelection.value = val;
+};
+
+const handlePageSizeChange = (size) => {
+  params.value.page_size = size;
+  GET_GoodsInventoryList();
+};
+
+const handlePageCurrentChange = (page) => {
+  params.value.page_no = page;
+  GET_GoodsInventoryList();
+};
+
+const GET_GoodsInventoryDetail = (id) => {
+  API_GoodsInventory.getGoodsInventoryInfo(id).then((response) => {
+    goodsInventoryForm.value = response;
+    if (response.product_list && response.product_list.length) {
+      let str = ref('');
+      response.product_list.forEach(function (i) {
+        str += i.product_name + '、';
+      });
+    }
+    goodsInventoryForm.value.illustrate = str;
+    dialogVisible.value = true;
+  });
+};
+
+const searchEvent = (data) => {
+  params.value = {
+    ...params.value,
+    sn: data,
+  };
+  Object.keys(advancedForm.value).forEach((key) => delete params.value[key]);
+  params.value.page_no = 1;
+  GET_GoodsInventoryList();
+};
+
+const advancedSearchEvent = () => {
+  if (searchTime.value) {
+    advancedForm.value.start_time = searchTime.value[0];
+    advancedForm.value.end_time = searchTime.value[1];
+  }
+  params.value = {
+    ...params.value,
+    ...advancedForm.value,
+  };
+  params.value.page_no = 1;
+  GET_GoodsInventoryList();
+};
+
+const GET_GoodsInventoryList = () => {
+  loading.value = true;
+  API_GoodsInventory.getGoodsInventoryList(params.value)
+    .then((response) => {
+      loading.value = false;
+      tableData.value = response;
+    })
+    .catch(() => {
+      loading.value = false;
+    });
+};
+</script>
+  
+<!--   <style scoped lang="scss">
+  .search {
+    display: flex;
+    align-items: center;
+    background: #fff;
+    overflow: hidden;
+    padding: 30px 10px 10px 10px;
+  
+    .el-form-item {
+      .el-form-item__content {
+        .el-input {
+          width: 200px;
+        }
+      }
+    }
+  
+    .el-button {
+      margin-top: -19px;
+      margin-left: 20px;
+    }
+  }
+  
+  .print {
+    margin-left: 790px;
+  }
+  
+  .deliverySheet-header {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+  }
+  
+  .tips-t {
+    display: flex;
+    padding: 30px 0;
+  
+    div {
+      flex: 1;
+      text-align: left;
+      padding-left: 70px;
+    }
+  }
+  
+  .tips-f {
+    padding: 20px 0;
+  }
+  
+  .face-image {
+    display: block;
+    width: 50px;
+    height: 50px;
+    margin: 0 auto;
+  }
+  
+  .el-dialog__body {
+    padding: 10px 20px;
+  }
+  </style> -->

+ 729 - 0
src/views/stock/goodsInventoryAdd.vue

@@ -0,0 +1,729 @@
+<template>
+  <div class="bg-in-stock" v-loading="loading">
+    <el-form ref="goodsInventoryAddFormRef" :model="goodsInventoryAddForm" :rules="goodsInventoryAddFormRule" label-width="120px" inline class="change-form">
+      <h3 style="width: 100%">盘点单</h3>
+      <el-form-item label="盘点编号" prop="sn" v-if="type === 'edit' || type === 'detail'" class="change-form-item">
+        <el-input v-model="goodsInventoryAddForm.sn" :disabled="true"></el-input>
+      </el-form-item>
+      <el-form-item label="盘点时间" prop="inventory_time" class="change-form-item">
+        <span v-if="id && type !== 'edit'">{{ goodsInventoryAddForm.inventory_time }}</span>
+        <el-date-picker
+          v-else
+          v-model="goodsInventoryAddForm.inventory_time"
+          format="YYYY-MM-DD HH:mm:ss"
+          value-format="YYYY-MM-DD HH:mm:ss"
+          type="datetime"
+          :disabled="type === 'detail' || type === 'audit' || type === 'check'"
+          placeholder="选择日期时间"
+        >
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item label="仓库" prop="warehouse_id" class="change-form-item">
+        <span v-if="id && type !== 'edit'">{{ getWarehouse(goodsInventoryAddForm.warehouse_id) }}</span>
+        <el-select
+          v-else
+          v-model="goodsInventoryAddForm.warehouse_id"
+          @change="handleChangeWareHouse"
+          :disabled="type === 'detail' || type === 'audit' || type === 'check'"
+        >
+          <el-option v-for="item in warehouseList" :key="item.id" :label="item.name" :value="item.id" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="盘点人" prop="inventory_person_id" class="change-form-item">
+        <span v-if="id && type !== 'edit'">{{ getadminList(goodsInventoryAddForm.inventory_person_id) }}</span>
+        <el-select
+          v-else
+          @change="forceUpdate"
+          v-model="goodsInventoryAddForm.inventory_person_id"
+          :disabled="type === 'detail' || type === 'audit' || type === 'check'"
+        >
+          <el-option v-for="item in adminList" :key="item.id" :label="item.nickname" :value="item.id" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="制单人" prop="creator_id" class="change-form-item">
+        <span v-if="id && type !== 'edit'">{{ getadminList(goodsInventoryAddForm.creator_id) }}</span>
+        <el-select
+          v-else
+          v-model="goodsInventoryAddForm.creator_id"
+          :disabled="type === 'detail' || type === 'audit' || type === 'check'"
+          @change="forceUpdate"
+        >
+          <el-option v-for="item in adminList" :key="item.id" :label="item.nickname" :value="item.id" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="盘点类型" prop="inventory_type" class="change-form-item">
+        <span v-if="id && type !== 'edit'">{{ getRoleSplit(goodsInventoryAddForm.inventory_type) }}</span>
+        <el-select
+          v-else
+          v-model="goodsInventoryAddForm.inventory_type"
+          @change="handleChangeInventoryType($event)"
+          :disabled="type === 'detail' || type === 'audit' || type === 'check'"
+        >
+          <el-option v-for="item in typeList" :key="item.id" :label="item.label" :value="item.value" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="是否通知审核人:" prop="has_notice" class="change-form-item">
+        <el-switch v-model="goodsInventoryAddForm.has_notice" inline-prompt :active-text="true" :inactive-text="false" />
+      </el-form-item>
+      <el-form-item label="审核人:" prop="notice_user_id" class="change-form-item" v-if="goodsInventoryAddForm.has_notice">
+        <el-select v-model="goodsInventoryAddForm.notice_user_id" :disabled="type === 'detail' || type === 'audit' || type === 'check'">
+          <el-option v-for="item in auditList" :key="item.id" :label="item.nickname" :value="item.id" />
+        </el-select>
+      </el-form-item>
+      <div class="mx">
+        <h3>商品明细</h3>
+        <el-button class="button" size="mini" type="primary" v-if="type !== 'detail' && type !== 'check'" @click="scanCode">商品扫码</el-button>
+        <el-button
+          class="button"
+          size="mini"
+          type="primary"
+          v-if="type !== 'detail' && type !== 'check'"
+          @click="handleSelectWarehouseEntryBatch"
+          :disabled="selectBtn"
+          >选择</el-button
+        >
+      </div>
+      <div style="width: 100%; display: block">
+        <el-form-item style="width: 100%">
+          <el-table
+            :data="goodsInventoryAddForm.product_list"
+            border
+            :cell-style="{ textAlign: 'center' }"
+            :header-cell-style="{ textAlign: 'center' }"
+            :loading="loading"
+            style="width: 100%; margin-top: 20px"
+          >
+            <el-table-column label="库位号">
+              <template #default="scope">
+                <el-popover placement="right" trigger="click" v-if="scope.row.area_stock_list">
+                  <div>
+                    <p v-for="item in scope.row.area_stock_list" :key="item.id">{{ item.warehouse_area_name }}</p>
+                  </div>
+                  <span slot="reference" v-if="scope.row.area_stock_list.length !== 0">{{ scope.row.area_stock_list[0].warehouse_area_name }}</span>
+                </el-popover>
+              </template>
+            </el-table-column>
+            <!--  <el-table-column label="商品编号">
+              <template #default="scope">
+                <span v-if="id"> {{ scope.row.product_vo.sn }}</span>
+                <span v-else>{{ scope.row.product_vo.sn }}</span>
+              </template>
+            </el-table-column> -->
+            <el-table-column label="商品名称">
+              <template #default="scope">
+                <span v-if="id">{{ scope.row.product_vo.name }}</span>
+                <span v-else>{{ scope.row.product_vo.name }}</span>
+              </template>
+            </el-table-column>
+            <el-table-column label="sku">
+              <template #default="scope">
+                <span v-if="!id"> {{ scope.row.product_vo.sku }}</span>
+                <span v-else> {{ scope.row.product_vo.sku }}</span>
+              </template>
+            </el-table-column>
+            <!-- <el-table-column label="序列号" width="160">
+              <template #default="scope">
+                <div class="sn-code-container">
+                  <span v-for="item in scope.row.sn_code_list" :key="item.id">
+                    <p>{{ item.sn_code }}</p>
+                  </span>
+                </div>
+              </template>
+            </el-table-column>
+            <el-table-column prop="product_vo.spec_name" label="规格型号"> </el-table-column> -->
+            <el-table-column label="单位">
+              <template #default="scope">
+                <span v-if="!id"> {{ scope.row.product_vo.unit }}</span>
+                <span v-else> {{ scope.row.product_vo.unit }}</span>
+              </template>
+            </el-table-column>
+            <el-table-column label="库存数量">
+              <template #default="scope">
+                {{ scope.row.actual_stock }}
+              </template>
+            </el-table-column>
+            <el-table-column label="盘点数量">
+              <template #default="scope">
+                <span v-if="type === 'check'">{{ scope.row.inventory_num }}</span>
+                <el-input
+                  v-else
+                  v-model="scope.row.inventory_num"
+                  type="number"
+                  :min="0"
+                  :maxlength="20"
+                  :disabled="type === 'detail' || type === 'audit' || type === 'check'"
+                ></el-input>
+              </template>
+            </el-table-column>
+            <el-table-column label="差异">
+              <template #default="scope">
+                {{ scope.row.inventory_num - scope.row.actual_stock || 0 }}
+              </template>
+            </el-table-column>
+            <el-table-column label="操作" v-if="type !== 'detail' && type !== 'audit' && type !== 'check'">
+              <template #default="scope">
+                <el-button size="mini" type="danger" @click="goodsInventoryAddForm.product_list.splice(scope.$index, 1)">删除</el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+        </el-form-item>
+      </div>
+    </el-form>
+    <div class="footer">
+      <el-button v-if="type !== 'audit' && type !== 'detail' && type !== 'check'" type="primary" @click="submitGoodsInventoryAddForm">保存 </el-button>
+      <el-button @click="printIng" v-if="type == 'check'">打印</el-button>
+      <el-button @click="$router.back()">返回 </el-button>
+    </div>
+    <el-dialog title="扫码入库" v-model="scanDialogVisible" width="30%" :close-on-click-modal="false">
+      <el-form ref="scanGoodsForm" :model="scanGoodsForm" label-width="120px" inline>
+        <el-form-item label="sku" prop="bar_code">
+          <el-input v-model="scanGoodsForm.bar_code" ref="input" @keyup.enter.native="toSearch()" :minlength="0" :maxlength="100"></el-input>
+        </el-form-item>
+        <el-form-item label="序列号" prop="sn_code">
+          <el-input ref="sn_input" v-model="sn_code" @keyup.enter.native="toSnCode()" :minlength="0" :maxlength="100"></el-input>
+        </el-form-item>
+      </el-form>
+    </el-dialog>
+    <el-dialog title="提示" v-model="dialogVisible" width="30%">
+      <el-form ref="goodsInventoryAddForm" :model="goodsInventoryAddForm" label-width="120px" inline style="width: 900px">
+        <el-form-item label="驳回原因" prop="reject_reason" required="true">
+          <el-input v-model="goodsInventoryAddForm.reject_reason" type="textarea" :minlength="0" :maxlength="100"></el-input>
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <el-button @click="dialogVisible = false">取 消</el-button>
+        <el-button type="primary" @click="handleRejectGoodsInventory()">确 定</el-button>
+      </template>
+    </el-dialog>
+    <el-dialog title="盘点商品" v-model="goodsVisible" width="1000px" @close="closeGoosData">
+      <div style="display: flex; align-items: center; justify-content: flex-end; padding: 10px 0">
+        <span>搜索商品:</span><el-input v-model="params.keyWord" style="width: 200px; margin-right: 5px"></el-input>
+        <el-button @click="searchGoodEvent"> 搜索 </el-button>
+      </div>
+      <el-table :data="goodsData.records" border style="width: 100%" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" />
+        <el-table-column prop="product_vo.name" label="商品名称"></el-table-column>
+        <el-table-column prop="product_vo.sku" label="sku"> </el-table-column>
+        <el-table-column prop="" label="品牌">
+          <template #default="scope">
+            {{ scope.row.product_vo.brand }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="product_vo.weight" label="重量"> </el-table-column>
+        <el-table-column prop="product_vo.unit" label="单位"> </el-table-column>
+      </el-table>
+      <el-pagination
+        @size-change="goodsPageSizeChange"
+        @current-change="goodsPageCurrentChange"
+        :current-page="goodsData.current"
+        :page-sizes="[10, 20, 50, 100]"
+        :page-size="goodsData.size"
+        layout="total, sizes, prev, pager, next, jumper"
+        :total="goodsData.total"
+      >
+      </el-pagination>
+      <template #footer>
+        <el-button @click="closeGoosData">取 消</el-button>
+        <el-button type="primary" @click="submitGoosData()">确 定</el-button>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+  
+  <script lang="ts" setup>
+import { ref, onMounted, computed, nextTick, reactive } from 'vue';
+import { useStore, mapGetters } from 'vuex';
+/* import { Foundation, RegExp } from '~/ui-utils'; */
+import * as API_GoodsInventory from '@/api/goodsInventory';
+import * as API_GoodsExchange from '@/api/goodsExchange';
+import * as API_Setting from '@/api/setting';
+import * as API_BasicSetting from '@/api/basicSetting';
+import * as API_Auth from '@/api/auth';
+import { useRouter, useRoute } from 'vue-router';
+import { ElMessage, ElMessageBox } from 'element-plus';
+
+const router = useRouter();
+const route = useRoute();
+
+const store = useStore();
+const loading = ref(false);
+const adminList = ref<any>([]);
+const dialogVisible = ref(false);
+const warehouseList = ref<any>([]);
+const deptList = ref([]);
+const deptListAll = ref([]);
+const id = ref('');
+const type = ref('');
+const goodsInventoryAddForm = ref<any>({
+  product_list: [],
+  inventory_time: '',
+  inventory_person_id: '',
+  creator_id: '',
+  has_notice: false,
+});
+const goodsInventoryAddFormRule = ref({
+  inventory_person_id: { required: true, message: '请选择盘点人', trigger: 'change' },
+  warehouse_id: { required: true, message: '请选择报损仓库', trigger: 'change' },
+  dept_id: { required: true, message: '请选择所属部门', trigger: 'change' },
+  creator_id: { required: true, message: '请选择制单人', trigger: 'change' },
+});
+const warehouseProduct = ref(null);
+const typeList = ref([]);
+const scanDialogVisible = ref(false);
+const scanGoodsForm = ref<any>({});
+const sn_code = ref('');
+const sn_code_list = ref([]);
+const index = ref('');
+const selectBtn = ref(false);
+/* 盘点商品信息 操作部分 */
+const goodsVisible = ref(false);
+const goodsData = ref<any>([]);
+const params = reactive({
+  page_no: 1,
+  page_size: 10,
+  keyWord: '',
+});
+/* 关闭盘点商品 */
+const closeGoosData = () => {
+  goodsVisible.value = false;
+};
+/* 搜索盘点商品 */
+const searchGoodEvent = () => {
+  API_GoodsExchange.getGoodsInfo(params, goodsInventoryAddForm.value.warehouse_id).then((res) => {
+    goodsData.value = res;
+  });
+};
+/* 选中的商品列表 */
+const goodsList = ref([]);
+const handleSelectionChange = (val) => {
+  goodsList.value = val.map((el) => {
+    /* el.product_id = el.id;
+    el.goods_id = el.id;
+    el.sn_code_list = []; */
+    return el;
+  });
+};
+const submitGoosData = () => {
+  if (goodsList.value.length >= 1) {
+    goodsInventoryAddForm.value.product_list = goodsList.value.map((el) => {
+      /* el.sn_code_list = []; */
+      return el;
+    });
+    goodsVisible.value = false;
+  } else {
+    ElMessage.error('请选择商品信息');
+  }
+};
+/* 盘点商品分页 */
+const goodsPageSizeChange = (size) => {
+  params.page_size = size;
+  searchGoodEvent();
+};
+
+const goodsPageCurrentChange = (page) => {
+  params.page_no = page;
+  searchGoodEvent();
+};
+
+const user = computed(() => store.getters.user);
+const timeDefault = computed(() => {
+  const date = new Date();
+  return `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()} ${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}`;
+});
+/* 获取审核人列表 */
+const auditList = ref<any>([]);
+const GET_AuditList = () => {
+  API_GoodsInventory.getUserByCompany().then((res) => {
+    auditList.value = res;
+  });
+};
+
+onMounted(() => {
+  if (route.query.type === 'view') {
+    type.value = 'view';
+    id.value = route.query.id;
+    GET_goodsInventoryAddDetail();
+  }else{
+    type.value = 'edit';
+    id.value = route.query.id;
+    GET_goodsInventoryAddDetail();
+  }
+ /*  if (route.name === 'goodsInventoryAdd') {
+    goodsInventoryAddForm.value.creator_id = user.value.uid;
+    goodsInventoryAddForm.value.inventory_person_id = user.value.uid;
+    goodsInventoryAddForm.value.dept_id = user.value.dept_id;
+    //goodsInventoryAddForm.value.inventory_time = timeDefault.value;
+  } else if (route.name === 'goodsInventoryDetail') {
+    type.value = 'detail';
+  } else if (route.query.type === 'view') {
+    type.value = 'check';
+    id.value = store.state.route.params.id;
+    GET_goodsInventoryAddDetail();
+    GET_AdministratorList();
+    GET_WarehouseList();
+  } else if (route.name === 'goodsInventoryEdit') {
+    type.value = 'edit';
+    goodsInventoryAddForm.value.creator_id = user.value.uid;
+    goodsInventoryAddForm.value.inventory_person_id = user.value.uid;
+    goodsInventoryAddForm.value.dept_id = user.value.dept_id;
+    //goodsInventoryAddForm.value.inventory_time = timeDefault.value;
+    id.value = store.state.route.params.id;
+    GET_goodsInventoryAddDetail();
+    GET_AdministratorList();
+    GET_WarehouseList();
+  } */
+  GET_AdministratorList();
+  GET_WarehouseList();
+  GET_DeptList();
+  GET_AuditList();
+});
+
+const handleChangeInventoryType = (val: string) => {
+  goodsInventoryAddForm.value.product_list = [];
+  if (val === 'ALL_INVENTORY') {
+    if (!goodsInventoryAddForm.value.warehouse_id) {
+      store.dispatch('message/error', '请先选择仓库!');
+      return;
+    }
+    loading.value = true;
+    API_GoodsInventory.getGoodByWarehouseInventory({ page: 1, size: 10000 }, goodsInventoryAddForm.value.warehouse_id)
+      .then((res) => {
+        res.records.forEach((el) => {
+          el.sn_code_list = [];
+        });
+        goodsInventoryAddForm.value.product_list = res.records;
+        selectBtn.value = true;
+        loading.value = false;
+      })
+      .catch(() => {
+        loading.value = false;
+      });
+  } else {
+    selectBtn.value = false;
+  }
+};
+
+const input = ref();
+const toSnCode = async () => {
+  if (scanGoodsForm.value.bar_code === '') return store.dispatch('message/error', '请录入正确的sku');
+  await API_GoodsExchange.getSnCode('inventory', scanGoodsForm.value.bar_code, sn_code.value.replace(/\s+/g, '')).then(async (res) => {
+    sn_code.value = '';
+    const exists = goodsInventoryAddForm.value.product_list[index.value].sn_code_list.find((item: any) => item.sn_code === res.sn_code && item.sku === res.sku);
+    if (!exists) {
+      if (id.value) {
+        await API_GoodsExchange.skuRedis({
+          send_order_id: id.value,
+          item_id: goodsInventoryAddForm.value.product_list[index.value].id,
+          sku: res,
+        }).then(() => {
+          goodsInventoryAddForm.value.product_list[index.value].sn_code_list.push(res);
+        });
+      } else {
+        goodsInventoryAddForm.value.product_list[index.value].sn_code_list.push(res);
+      }
+    }
+    goodsInventoryAddForm.value.product_list[index.value].inventory_num = goodsInventoryAddForm.value.product_list[index.value].sn_code_list.length;
+    scanGoodsForm.value.bar_code = '';
+    nextTick(() => {
+      input.value.focus();
+    });
+  });
+};
+
+const sn_input = ref();
+const toSearch = () => {
+  API_GoodsExchange.getProduct(goodsInventoryAddForm.value.warehouse_id, scanGoodsForm.value.bar_code.replace(/\s+/g, '')).then((res) => {
+    res.sn_code_list = [];
+    const indexs = goodsInventoryAddForm.value.product_list.findIndex(
+      (el: any) => el.goods_id === res.goods_id && el.product_id === res.product_id && el.product_vo.sku === res.product_vo.sku
+    );
+    if (indexs === -1) {
+      index.value = goodsInventoryAddForm.value.product_list.length;
+      goodsInventoryAddForm.value.product_list.push(res);
+    } else {
+      index.value = indexs;
+    }
+    if (res.product_vo.have_sn) {
+      nextTick(() => {
+        sn_input.value.focus();
+      });
+    } else {
+      goodsInventoryAddForm.value.product_list[index.value].inventory_num += 1;
+    }
+  });
+};
+
+const scanCode = () => {
+  if (!goodsInventoryAddForm.value.warehouse_id) {
+    store.dispatch('message/error', '请选择仓库!');
+    return;
+  }
+  if (!goodsInventoryAddForm.value.inventory_type) {
+    store.dispatch('message/error', '请选择盘点类型!');
+    return;
+  }
+  scanDialogVisible.value = true;
+  nextTick(() => {
+    input.value.focus();
+  });
+};
+
+const getadminList = (value: string) => {
+  const type = adminList.value.find((type: any) => type.id === value);
+  return type ? type.real_name : '未知类型';
+};
+
+const getRoleSplit = (value: string) => {
+  const type = typeList.value.find((type: any) => type.id === value);
+  return type ? type.label : '未知类型';
+};
+
+const getWarehouse = (value: string) => {
+  const type = warehouseList.value.find((type: any) => type.id === value);
+  return type ? type.name : '未知类型';
+};
+
+const printIng = () => {
+  // Implement print functionality
+};
+
+const forceUpdate = () => {
+  store.dispatch('forceUpdate');
+};
+
+const cleanGoodsList = () => {
+  goodsInventoryAddForm.value.product_list = [];
+};
+
+const GET_AdministratorList = () => {
+  API_Auth.getAdministratorList({
+    page_no: 1,
+    page_size: 9999,
+    user_state: 0,
+  }).then((response) => {
+    adminList.value = response.data;
+  });
+};
+
+const handlePassGoodsInventory = () => {
+  store.dispatch('confirm', '确定通过吗?', '提示', { type: 'warning' }).then(() => {
+    API_GoodsInventory.auditGoodsInventory(id.value, { status: 'PASS' })
+      .then(() => {
+        store.dispatch('message/success', '已通过!');
+        const { callback } = store.state.route.params;
+        if (typeof callback === 'function') callback();
+        store.dispatch('delCurrentViews', {
+          view: store.state.route,
+          $router: store.state.router,
+        });
+        store.state.router.push({ name: 'goodsInventory' });
+      })
+      .catch(() => {});
+  });
+};
+
+const handleRejectGoodsInventory = () => {
+  if (!goodsInventoryAddForm.value.reject_reason) {
+    store.dispatch('message/error', '请填写驳回原因!');
+    return;
+  }
+  store
+    .dispatch('confirm', '确定拒绝吗?', '提示', { type: 'warning' })
+    .then(() => {
+      API_GoodsInventory.auditGoodsInventory(id.value, { status: 'REJECT', reject_reason: goodsInventoryAddForm.value.reject_reason }).then(() => {
+        store.dispatch('message/success', '已拒绝!');
+        const { callback } = store.state.route.params;
+        if (typeof callback === 'function') callback();
+        store.dispatch('delCurrentViews', {
+          view: store.state.route,
+          $router: store.state.router,
+        });
+        store.state.router.push({ name: 'goodsInventory' });
+      });
+    })
+    .catch(() => {});
+};
+
+const changewarehouseList = (e: any) => {
+  goodsInventoryAddForm.value.warehouse_id = '';
+  GET_WarehouseList({ dept_id: e });
+  cleanGoodsList();
+};
+
+const GET_WarehouseList = (e?: any) => {
+  API_BasicSetting.getWarehouseListAll().then((response) => {
+    warehouseList.value = response;
+  });
+};
+
+const goodsInventoryAddFormRef = ref();
+const submitGoodsInventoryAddForm = () => {
+  goodsInventoryAddFormRef.value.validate((valid: boolean) => {
+    if (valid) {
+      const params = { ...goodsInventoryAddForm.value };
+      if (params.warehouse_id) {
+        params.warehouse_name = warehouseList.value.find((ware: any) => ware.id === params.warehouse_id).name;
+      }
+      if (params.creator_id) {
+        params.creator = adminList.value.find((admin: any) => admin.id === params.creator_id).real_name;
+      }
+      if (params.inventory_person_id) {
+        params.inventory_person = adminList.value.find((admin: any) => admin.id === params.inventory_person_id).real_name;
+      }
+      params.product_list = params.product_list.map((item: any) => ({
+        diff_num: item.usable_stock - item.inventory_num,
+        inventory_num: item.inventory_num * 1,
+        product_name: item.product_name,
+        product_sn: item.product_sn,
+        product_id: item.product_id,
+        specification: item.product_specification,
+        unit: item.product_unit,
+        remark: item.remark,
+        product_stock_id: item.id,
+        sn_code_list: item.sn_code_list,
+      }));
+      if (id.value) {
+        API_GoodsInventory.editgoodsInventoryAdd(id.value, params).then(() => {
+          ElMessage.success('修改成功!');
+          router.push({ name: 'goodsInventory' });
+        });
+      } else {
+        API_GoodsInventory.addgoodsInventoryAdd(params).then(() => {
+          ElMessage.success('添加成功!');
+          router.push({ name: 'goodsInventory' });
+        });
+      }
+    }
+  });
+};
+
+const handleSelectWarehouseEntryBatch = async () => {
+  if (!goodsInventoryAddForm.value.warehouse_id) {
+    store.dispatch('message/error', '请先选择仓库!');
+    return;
+  }
+  API_GoodsExchange.getGoodsInfo(params, goodsInventoryAddForm.value.warehouse_id, 'le').then((res) => {
+    goodsData.value = res;
+    goodsVisible.value = true;
+  });
+};
+
+const GET_DeptList = () => {
+  API_Setting.getPage({ dictType: 'inventory_type' }).then((res) => {
+    typeList.value = res.data;
+  });
+};
+
+const handleChangeWareHouse = (val: any) => {
+  goodsInventoryAddForm.value.product_list = [];
+};
+
+const GET_goodsInventoryAddDetail = () => {
+  API_GoodsInventory.getGoodsInventoryInfo(route.query.id).then((response) => {
+    if (!response.product_list) {
+      response.product_list = [];
+    }
+    goodsInventoryAddForm.value = response;
+    GET_WarehouseList();
+    /* goodsInventoryAddForm.value.distribution_name = response.staff_name;
+    if (goodsInventoryAddForm.value.product_list) {
+      goodsInventoryAddForm.value.product_list = goodsInventoryAddForm.value.product_list.map((item: any) => {
+        item.inventory_num = item.inventory_num;
+        item.product_specification = item.specification;
+        item.product_unit = item.unit;
+        item.remain_num = item.stock_num;
+        return item;
+      });
+    } else {
+      goodsInventoryAddForm.value.product_list = [];
+    } */
+  });
+};
+</script>
+
+<style scoped>
+.footer {
+  width: 100%;
+  padding: 10px;
+  bottom: 0px;
+  text-align: center;
+  z-index: 999;
+}
+
+.mx {
+  display: flex;
+  align-items: center;
+  width: 100%;
+}
+
+.mx .button {
+  margin-left: 10px;
+}
+
+.change-form {
+  display: flex;
+  justify-content: flex-start;
+  align-items: flex-start;
+  flex-wrap: wrap;
+  min-width: 900px;
+}
+
+.change-form .change-form-item {
+  width: 30%;
+  margin: 0 10px 20px 0;
+  display: flex;
+  flex-direction: row;
+  flex-wrap: nowrap;
+}
+
+.change-form ::v-deep .el-form-item__content {
+  flex: 1;
+  width: 100%;
+}
+
+.change-form ::v-deep .el-date-editor,
+.change-form ::v-deep .el-cascader,
+.change-form ::v-deep .el-select {
+  width: 100%;
+}
+
+.bg-in-stock {
+  background-color: #fff;
+  margin: 10px;
+  padding: 25px;
+}
+
+.goods-info {
+  display: flex;
+}
+
+.goods-info .goods-name-box {
+  text-align: left;
+}
+
+.goods-info .goods-name-box .goods-name {
+  text-overflow: ellipsis;
+  display: -webkit-box;
+  -webkit-line-clamp: 2;
+  -webkit-box-orient: vertical;
+  overflow: hidden;
+  line-height: 16px;
+}
+
+.goods-info .goods-name-box .specs {
+  color: #999999;
+}
+
+.sn-code-container {
+  max-height: 100px;
+  overflow-y: auto;
+}
+
+::v-deep .el-input--suffix .el-input__inner {
+  padding-right: 10px;
+}
+
+::v-deep .error-input .el-input__inner {
+  border: 1px solid red;
+}
+</style>

+ 11 - 7
src/views/stock/goodsTransfer.vue

@@ -17,7 +17,10 @@
           </el-col>
         </el-row>
       </el-form>
-      <el-button @click="advancedSearchEvent"> 搜索 </el-button>
+      <div class="flex justify-end">
+        <el-button class="mr-3" @click="advancedSearchEvent"> 搜索 </el-button>
+      </div>
+      <!-- <el-button @click="advancedSearchEvent"> 搜索 </el-button> -->
     </div>
     <en-table-layout :tableData="tableData.data" ref="table" :loading="loading"
       @selection-change="handleSelectionChange">
@@ -34,14 +37,14 @@
         <el-table-column type="selection" width="55" />
         <el-table-column prop="warehouse_name" label="仓库名称">
         </el-table-column>
-        <el-table-column label="商品编号" prop="sn">
+        <!-- <el-table-column label="商品编号" prop="sn">
         </el-table-column>
         <el-table-column prop="type" label="类别">
           <template #default="scope">
-           <!--  {{ scope.row.product_vo.hire_or_sail=='sail' ? '售卖商品' : '租赁商品'  }} -->
+            {{ scope.row.product_vo.hire_or_sail=='sail' ? '售卖商品' : '租赁商品'  }}
           </template>
-        </el-table-column>
-        <el-table-column prop="goods_name" label="商品名称" />
+        </el-table-column> -->
+        <el-table-column prop="product_name" label="商品名称" />
         <el-table-column prop="type" label="sku">
           <template #default="scope">
             {{ scope.row.product_vo ? scope.row.product_vo.sku : ''  }}
@@ -103,8 +106,9 @@ import * as API_Setting from "@/api/setting";
 import * as API_BasicSetting from "@/api/basicSetting";
 import { useStore } from 'vuex';
 import { useRouter, useRoute } from 'vue-router';
-import EnTableLayout from '@/components/TableLayout/index.vue';
-import EnTableSearch from '@/components/TableSearch/index.vue';
+import { ElMessageBox, ElMessage } from 'element-plus';
+/* import EnTableLayout from '@/components/TableLayout/index.vue';
+import EnTableSearch from '@/components/TableSearch/index.vue'; */
 
 const store = useStore();
 const router = useRouter();

+ 21 - 18
src/views/stock/outbound.vue

@@ -1,6 +1,6 @@
 <template>
   <div>
-    <div class="search">
+    <div class="search bg-white p-3">
       <el-form ref="advancedFormRef" :model="advancedForm" label-width="160px">
         <el-row>
           <el-col :span="activeName === 'first' ? 12 : 8">
@@ -52,7 +52,9 @@
             </el-col> -->
         </el-row>
       </el-form>
-      <el-button @click="advancedSearchEvent"> 搜索 </el-button>
+      <div class="flex justify-end">
+        <el-button class="mr-3" @click="advancedSearchEvent"> 搜索 </el-button>
+      </div>
     </div>
 
     <en-table-layout :tableData="tableData.data" :loading="loading" @selection-change="handleSelectionChange">
@@ -60,9 +62,9 @@
         <div class="inner-toolbar">
           <div class="toolbar-btns">
             <!-- <el-button size="mini" v-if="checkPermission(['addInventory']) && activeName === 'second'" type="primary" @click="handleAddGoodsExchange"
-                >新增入库</el-button
+                >新增入库</el-buttonv-if="checkPermission(['goodsExchangeAdd'])"
               > -->
-            <el-button size="mini" v-if="checkPermission(['goodsExchangeAdd'])" type="primary" @click="handleShiftGoodsExchange">新增出库</el-button>
+            <el-button size="mini" type="primary" @click="handleShiftGoodsExchange">新增出库</el-button>
           </div>
         </div>
       </template>
@@ -79,7 +81,7 @@
             {{ warehouseName(scope.row.warehouse_id) }}
           </template>
         </el-table-column>
-        <el-table-column prop="warehouse_id" label="客户名称">
+        <!-- <el-table-column prop="warehouse_id" label="客户名称">
           <template #default="scope">
             {{ scope.row.customer_name }}
           </template>
@@ -88,13 +90,13 @@
           <template #default="scope">
             {{ scope.row.customer_phone }}
           </template>
-        </el-table-column>
+        </el-table-column> -->
         <el-table-column prop="memo" label="出库类型">
           <template #default="scope">
             <span>{{ outName(scope.row.type) }}</span>
           </template>
         </el-table-column>
-        <el-table-column prop="order_id_list" label="订单编号" />
+      <!--   <el-table-column prop="order_id_list" label="订单编号" /> -->
         <el-table-column label="状态">
           <template #default="scope">
             <span>{{ scope.row.has_submit === 'Y' ? '已出库' : '未出库' }}</span>
@@ -110,12 +112,14 @@
             <span>{{ scope.row.notes }}</span>
           </template>
         </el-table-column>
-        <el-table-column label="操作" width="450">
+        <el-table-column label="操作" width="300">
           <template #default="scope">
-            <el-button size="mini" v-if="checkPermission(['checkInventory'])" @click="handleAuditGoodsExchange(scope.row)">查看</el-button>
+            <!-- v-if="checkPermission(['checkInventory'])" -->
+            <el-button size="mini"  @click="handleAuditGoodsExchange(scope.row)">查看</el-button>
+            <!-- && checkPermission(['editInventory']) && checkPermission(['goodsExchangeEdit']) -->
             <el-button
               size="mini"
-              v-if="scope.row.has_submit === 'N' && checkPermission(['editInventory']) && checkPermission(['goodsExchangeEdit'])"
+              v-if="scope.row.has_submit === 'N'"
               @click="handleEditGoodsExchange(scope.row)"
               >出库</el-button
             >
@@ -211,17 +215,17 @@ const handleClick = (tab) => {
 
 const handleEditGoodsExchange = (row) => {
   router.push({
-    name: 'goodsExchangeEdit',
-    params: { id: row.id },
+    name: 'addOutbound',
+    query: { id: row.id, type: 'edit' },
   });
 };
 
 const handleAuditGoodsExchange = (row) => {
   router.push({
-    name: 'checkInventory',
-    params: {
+    name: 'addOutbound',
+    query: {
       id: row.id,
-      type: activeName.value,
+      type: 'view',
     },
   });
 };
@@ -242,14 +246,13 @@ const handlePageCurrentChange = (page) => {
 
 const handleShiftGoodsExchange = () => {
   router.push({
-    name: 'goodsExchangeAdd',
-    params: { callback: GET_GoodsExchangeList, type: 'first' },
+    name: 'addOutbound',
   });
 };
 
 const handleAddGoodsExchange = () => {
   router.push({
-    name: 'addInventory',
+    name: 'addOutbound',
     params: { callback: GET_GoodsExchangeList, type: 'second' },
   });
 };

+ 31 - 32
src/views/stock/warehousing.vue

@@ -1,6 +1,7 @@
 <template>
   <div>
-    <div class="search flex items-center bg-white pt-2">
+    <!-- flex items-center -->
+    <div class="search bg-white pt-2">
       <el-form ref="advancedFormRef" :model="advancedForm" label-width="100px">
         <el-row>
           <el-col :span="activeName === 'first' ? 12 : 8">
@@ -33,47 +34,47 @@
               </el-select>
             </el-form-item>
           </el-col>
-          <el-col :span="6" v-if="activeName === 'second'">
+          <el-col :span="6">
             <el-form-item label="入库类型">
               <el-select v-model="advancedForm.type" clearable>
                 <el-option v-for="item in entryList" :key="item.id" :label="item.label" :value="item.value" />
               </el-select>
             </el-form-item>
           </el-col>
-          <el-col :span="8" v-if="activeName === 'second'">
+          <el-col :span="8">
             <el-form-item label="客户名称">
               <el-input v-model="advancedForm.customer_name" clearable placeholder="请输入客户名称"></el-input>
             </el-form-item>
           </el-col>
-          <el-col :span="8" v-if="activeName === 'second'">
+          <el-col :span="8">
             <el-form-item label="手机号">
               <el-input v-model="advancedForm.customer_phone" clearable placeholder="请输入手机号"></el-input>
             </el-form-item>
           </el-col>
         </el-row>
       </el-form>
-      <el-button class="mr-3" @click="advancedSearchEvent"> 搜索 </el-button>
+      <div class="flex justify-end">
+        <el-button class="mr-3" @click="advancedSearchEvent"> 搜索 </el-button>
+      </div>
     </div>
 
     <en-table-layout :tableData="tableData.data" :loading="loading" @selection-change="handleSelectionChange">
       <template #toolbar>
         <div class="inner-toolbar">
           <div class="toolbar-btns">
-            <el-button size="mini" v-if="checkPermission(['addInventory']) && activeName === 'second'" type="primary" @click="handleAddGoodsExchange"
-              >新增入库</el-button
-            >
+            <el-button size="mini" type="primary" @click="handleAddGoodsExchange">新增入库</el-button>
           </div>
         </div>
       </template>
 
       <template #table-columns>
         <el-table-column type="selection" width="55" />
-        <el-table-column v-if="activeName === 'first'" prop="sn" label="出库单号">
+        <!-- <el-table-column v-if="activeName === 'first'" prop="sn" label="出库单号">
           <template #default="scope">
-            {{ scope.row.sn }}
+            {{ scope.row.sn }}v-if="checkPermission(['addInventory'])"
           </template>
-        </el-table-column>
-        <el-table-column v-else prop="sn" label="入库单号">
+        </el-table-column> -->
+        <el-table-column prop="sn" label="入库单号">
           <template #default="scope">
             {{ scope.row.sn }}
           </template>
@@ -83,16 +84,16 @@
             {{ warehouseName(scope.row.warehouse_id) }}
           </template>
         </el-table-column>
-        <el-table-column prop="warehouse_id" label="客户名称">
+         <!--<el-table-column prop="warehouse_id" label="客户名称">
           <template #default="scope">
             {{ scope.row.customer_name }}
           </template>
-        </el-table-column>
+        </el-table-column> 
         <el-table-column prop="warehouse_id" label="客户手机号">
           <template #default="scope">
             {{ scope.row.customer_phone }}
           </template>
-        </el-table-column>
+        </el-table-column>-->
         <el-table-column prop="memo" label="入库类型">
           <template #default="scope">
             <span>{{ entryName(scope.row.type) }}</span>
@@ -103,7 +104,7 @@
             <span>{{ scope.row.create_time }}</span>
           </template>
         </el-table-column>
-        <el-table-column prop="order_id_list" label="订单编号" />
+        <!-- <el-table-column prop="order_id_list" label="订单编号" /> -->
         <el-table-column label="状态">
           <template #default="scope">
             <span>{{ scope.row.has_submit === 'Y' ? '已入库' : '未入库' }}</span>
@@ -114,16 +115,12 @@
             <span>{{ scope.row.memo }}</span>
           </template>
         </el-table-column>
-        <el-table-column label="操作" >
+        <el-table-column label="操作">
           <template #default="scope">
-            <el-button class="mr-1 mt-1" size="mini" v-if="checkPermission(['checkInventory'])" @click="handleAuditGoodsExchange(scope.row)">查看</el-button>
-            <el-button
-              size="mini"
-              class="!ml-0 mt-1"
-              v-if="scope.row.has_submit === 'N' && checkPermission(['editInventory']) && checkPermission(['goodsExchangeEdit'])"
-              @click="handleEditGoodsExchange(scope.row)"
-              >入库</el-button
-            >
+            <!-- v-if="checkPermission(['checkInventory'])" -->
+            <el-button class="mr-1 mt-1" size="mini" @click="handleAuditGoodsExchange(scope.row)">查看</el-button>
+            <!-- && checkPermission(['editInventory']) && checkPermission(['goodsExchangeEdit']) -->
+            <el-button size="mini" class="!ml-0 mt-1" v-if="scope.row.has_submit === 'N'" @click="handleEditGoodsExchange(scope.row)">入库</el-button>
           </template>
         </el-table-column>
       </template>
@@ -179,7 +176,7 @@ const GET_DeptList = () => {
   API_Setting.getPage({ dictType: 'warehouse_entry_type' }).then((res) => {
     entryList.value = res.data;
   });
-/*   API_Setting.getPage({ dictType: 'out_warehouse_type' }).then((res) => {
+  /*   API_Setting.getPage({ dictType: 'out_warehouse_type' }).then((res) => {
     outList.value = res.data;
   }); */
 };
@@ -216,17 +213,20 @@ const handleClick = (tab) => {
 
 const handleEditGoodsExchange = (row) => {
   router.push({
-    name: 'editInventory',
-    params: { id: row.id },
+    name: 'addInventory',
+    query: {
+      id: row.id,
+      type: 'edit',
+    },
   });
 };
 
 const handleAuditGoodsExchange = (row) => {
   router.push({
-    name: 'checkInventory',
-    params: {
+    name: 'addInventory',
+    query: {
       id: row.id,
-      type: activeName.value,
+      type: 'view',
     },
   });
 };
@@ -255,7 +255,6 @@ const handleShiftGoodsExchange = () => {
 const handleAddGoodsExchange = () => {
   router.push({
     name: 'addInventory',
-    params: { callback: GET_GoodsExchangeList, type: 'second' },
   });
 };