Explorar el Código

组装单,拆卸单,报损单,盘点单页面

sunlupeng hace 7 meses
padre
commit
cdba17cd5b

+ 4 - 4
config/dev.env.js

@@ -2,12 +2,12 @@ module.exports = {
 	NODE_ENV: '"development"',
 	ENV_CONFIG: '"dev"',
   // 本地数据库:登录用户名 admin123,密码 admin123
-  // BASE_API: '"http://192.168.100.188:9085/admin"',
-  // OS_API: '"http://192.168.100.188:9085/admin"',
+  BASE_API: '"http://192.168.100.188:9085/admin"',
+  OS_API: '"http://192.168.100.188:9085/admin"',
   // BASE_API: '"http://47.103.79.143:9085/admin"',
   // OS_API: '"http://47.103.79.143:9085/admin"',
-  OS_API: '"https://xiaoyou.dgtis.com/admin"',
-  BASE_API: '"https://xiaoyou.dgtis.com/admin"',
+  // OS_API: '"https://xiaoyou.dgtis.com/admin"',
+  // BASE_API: '"https://xiaoyou.dgtis.com/admin"',
   
   
   

+ 49 - 0
src/api/assembly.js

@@ -0,0 +1,49 @@
+import request from '@/utils/request'
+
+export function listAssembly(query) {
+  return request({
+    url: '/warehouse-entry/page',
+    method: 'get',
+    params: query
+  })
+}
+
+export function executeAssembly(query) {
+  return request({
+    url: '/warehouse-entry/execute',
+    method: 'post',
+    params:query
+  })
+}
+
+export function createAssembly(data) {
+  return request({
+    url: '/warehouse-entry/add',
+    method: 'post',
+    data
+  })
+}
+
+export function readAssembly(query) {
+  return request({
+    url: '/warehouse-entry/info',
+    method: 'get',
+    params:query
+  })
+}
+
+export function updateAssembly(data) {
+  return request({
+    url: '/warehouse-entry/edit',
+    method: 'post',
+    data
+  })
+}
+
+export function deleteAssembly(query) {
+  return request({
+    url: '/warehouse-entry/remove',
+    method: 'post',
+    params:query
+  })
+}

+ 49 - 0
src/api/breakage.js

@@ -0,0 +1,49 @@
+import request from '@/utils/request'
+
+export function listBreakage(query) {
+  return request({
+    url: '/warehouse-entry/page',
+    method: 'get',
+    params: query
+  })
+}
+
+export function executeBreakage(query) {
+  return request({
+    url: '/warehouse-entry/execute',
+    method: 'post',
+    params:query
+  })
+}
+
+export function createBreakage(data) {
+  return request({
+    url: '/warehouse-entry/add',
+    method: 'post',
+    data
+  })
+}
+
+export function readBreakage(query) {
+  return request({
+    url: '/warehouse-entry/info',
+    method: 'get',
+    params:query
+  })
+}
+
+export function updateBreakage(data) {
+  return request({
+    url: '/warehouse-entry/edit',
+    method: 'post',
+    data
+  })
+}
+
+export function deleteBreakage(query) {
+  return request({
+    url: '/warehouse-entry/remove',
+    method: 'post',
+    params:query
+  })
+}

+ 49 - 0
src/api/disassembly.js

@@ -0,0 +1,49 @@
+import request from '@/utils/request'
+
+export function listDisassembly(query) {
+  return request({
+    url: '/warehouse-entry/page',
+    method: 'get',
+    params: query
+  })
+}
+
+export function executeDisassembly(query) {
+  return request({
+    url: '/warehouse-entry/execute',
+    method: 'post',
+    params:query
+  })
+}
+
+export function createDisassembly(data) {
+  return request({
+    url: '/warehouse-entry/add',
+    method: 'post',
+    data
+  })
+}
+
+export function readDisassembly(query) {
+  return request({
+    url: '/warehouse-entry/info',
+    method: 'get',
+    params:query
+  })
+}
+
+export function updateDisassembly(data) {
+  return request({
+    url: '/warehouse-entry/edit',
+    method: 'post',
+    data
+  })
+}
+
+export function deleteDisassembly(query) {
+  return request({
+    url: '/warehouse-entry/remove',
+    method: 'post',
+    params:query
+  })
+}

+ 49 - 0
src/api/stockCount.js

@@ -0,0 +1,49 @@
+import request from '@/utils/request'
+
+export function listStockCount(query) {
+  return request({
+    url: '/warehouse-entry/page',
+    method: 'get',
+    params: query
+  })
+}
+
+export function executeStockCount(query) {
+  return request({
+    url: '/warehouse-entry/execute',
+    method: 'post',
+    params:query
+  })
+}
+
+export function createStockCount(data) {
+  return request({
+    url: '/warehouse-entry/add',
+    method: 'post',
+    data
+  })
+}
+
+export function readStockCount(query) {
+  return request({
+    url: '/warehouse-entry/info',
+    method: 'get',
+    params:query
+  })
+}
+
+export function updateStockCount(data) {
+  return request({
+    url: '/warehouse-entry/edit',
+    method: 'post',
+    data
+  })
+}
+
+export function deleteStockCount(query) {
+  return request({
+    url: '/warehouse-entry/remove',
+    method: 'post',
+    params:query
+  })
+}

+ 24 - 0
src/permission.js

@@ -116,22 +116,46 @@ const myRoles = [
   'store',
 
   'stock',
+  // 入库单
   'warehousing',
   'warehousingAdd',
   'warehousingEdit',
   'warehousingDetail',
+  // 出库单
   'retrieval',
   'retrievalAdd',
   'retrievalEdit',
   'retrievalDetail',
+  // 调拨单
   'requisition',
   'requisitionAdd',
   'requisitionEdit',
   'requisitionDetail',
+  // 换货单
   'swap',
   'swapAdd',
   'swapEdit',
   'swapDetail',
+  // 组装单
+  'assembly',
+  'assemblyAdd',
+  'assemblyEdit',
+  'assemblyDetail',
+  // 拆卸单
+  'disassembly',
+  'disassemblyAdd',
+  'disassemblyEdit',
+  'disassemblyDetail',
+  // 报损单
+  'breakage',
+  'breakageAdd',
+  'breakageEdit',
+  'breakageDetail',
+  // 盘点单
+  'stockCount',
+  'stockCountAdd',
+  'stockCountEdit',
+  'stockCountDetail',
 
   'dictManage', 
   'dictList', 

+ 20 - 0
src/router/index.js

@@ -111,6 +111,26 @@ export const asyncRouterMap = [
         { path: 'swapAdd', component: _import('stock/swap/swapAdd'), name: 'swapAdd', meta: { title: '新增换货单', noCache: false, hideTag: true, hidden: true }},
         { path: 'swapEdit/:id', component: _import('stock/swap/swapAdd'), name: 'swapEdit', meta: { title: '编辑换货单', noCache: false, hideTag: true, hidden: true }},
         { path: 'swapDetail/:id', component: _import('stock/swap/swapAdd'), name: 'swapDetail', meta: { title: '换货单详情', noCache: false, hideTag: true, hidden: true }},
+        // 组装单
+        { path: 'assembly', component: _import('stock/assembly/assembly'), name: 'assembly', meta: { title: '组装单', noCache: true }},
+        { path: 'assemblyAdd', component: _import('stock/assembly/assemblyAdd'), name: 'assemblyAdd', meta: { title: '新增组装单', noCache: false, hideTag: true, hidden: true }},
+        { path: 'assemblyEdit/:id', component: _import('stock/assembly/assemblyAdd'), name: 'assemblyEdit', meta: { title: '编辑组装单', noCache: false, hideTag: true, hidden: true }},
+        { path: 'assemblyDetail/:id', component: _import('stock/assembly/assemblyAdd'), name: 'assemblyDetail', meta: { title: '组装单详情', noCache: false, hideTag: true, hidden: true }},
+        // 拆卸单
+        { path: 'disassembly', component: _import('stock/disassembly/disassembly'), name: 'disassembly', meta: { title: '拆卸单', noCache: true }},
+        { path: 'disassemblyAdd', component: _import('stock/disassembly/disassemblyAdd'), name: 'disassemblyAdd', meta: { title: '新增拆卸单', noCache: false, hideTag: true, hidden: true }},
+        { path: 'disassemblyEdit/:id', component: _import('stock/disassembly/disassemblyAdd'), name: 'disassemblyEdit', meta: { title: '编辑拆卸单', noCache: false, hideTag: true, hidden: true }},
+        { path: 'disassemblyDetail/:id', component: _import('stock/disassembly/disassemblyAdd'), name: 'disassemblyDetail', meta: { title: '拆卸单详情', noCache: false, hideTag: true, hidden: true }},
+        // 报损单
+        { path: 'breakage', component: _import('stock/breakage/breakage'), name: 'breakage', meta: { title: '报损单', noCache: true }},
+        { path: 'breakageAdd', component: _import('stock/breakage/breakageAdd'), name: 'breakageAdd', meta: { title: '新增报损单', noCache: false, hideTag: true, hidden: true }},
+        { path: 'breakageEdit/:id', component: _import('stock/breakage/breakageAdd'), name: 'breakageEdit', meta: { title: '编辑报损单', noCache: false, hideTag: true, hidden: true }},
+        { path: 'breakageDetail/:id', component: _import('stock/breakage/breakageAdd'), name: 'breakageDetail', meta: { title: '报损单详情', noCache: false, hideTag: true, hidden: true }},
+        // 盘点单
+        { path: 'stockCount', component: _import('stock/stockCount/stockCount'), name: 'stockCount', meta: { title: '盘点单', noCache: true }},
+        { path: 'stockCountAdd', component: _import('stock/stockCount/stockCountAdd'), name: 'stockCountAdd', meta: { title: '新增盘点单', noCache: false, hideTag: true, hidden: true }},
+        { path: 'stockCountEdit/:id', component: _import('stock/stockCount/stockCountAdd'), name: 'stockCountEdit', meta: { title: '编辑盘点单', noCache: false, hideTag: true, hidden: true }},
+        { path: 'stockCountDetail/:id', component: _import('stock/stockCount/stockCountAdd'), name: 'stockCountDetail', meta: { title: '盘点单详情', noCache: false, hideTag: true, hidden: true }},
       ]
     },
   

+ 282 - 0
src/views/stock/assembly/assembly.vue

@@ -0,0 +1,282 @@
+<template>
+  <div class="app-container calendar-list-container">
+    <!-- 查询和其他操作 -->
+    <div class="filter-container">
+      <el-date-picker v-model="listQuery.startDate" value-format="yyyy-MM-dd" type="date" placeholder="开始日期"
+        style="width:200px">
+      </el-date-picker>
+      <el-date-picker v-model="listQuery.endDate" value-format="yyyy-MM-dd" type="date" placeholder="结束日期"
+        style="width:200px">
+      </el-date-picker>
+      <el-select v-model="listQuery.warehouseId" clearable placeholder="请选择仓库" class="filter-item" style="width: 200px">
+        <el-option :key="item.id" v-for="item in warehouseList" :label="item.warehouseName" :value="item.id">
+        </el-option>
+      </el-select>
+      <el-select v-model="listQuery.isRunFinish" clearable placeholder="请选择状态" class="filter-item" style="width: 200px">
+        <el-option :key="item.type" v-for="item in typeList" :label="item.name" :value="item.type">
+        </el-option>
+      </el-select>
+      <el-button class="filter-item" type="primary" v-waves icon="el-icon-search" @click="handleFilter">查找</el-button>
+      <el-button class="filter-item" v-waves icon="el-icon-refresh" @click="resetQuery">重置</el-button>
+      <el-button class="filter-item" type="primary" @click="handleCreate" icon="el-icon-plus">添加</el-button>
+      <!-- <el-button class="filter-item" :loading="downloadLoading" v-waves icon="el-icon-download"
+        @click="handleDownload">导出</el-button> -->
+      <!-- <el-button class="filter-item" type="success" icon="el-icon-takeaway-box" @click="executeAll">批量入库</el-button> -->
+      <el-button class="filter-item" type="warning" icon="el-icon-delete" @click="delAll">批量删除</el-button>
+    </div>
+
+    <!-- 查询结果 -->
+    <el-table size="small" :data="list" @selection-change="handleSelectionChange" v-loading="listLoading"
+      element-loading-text="正在查询中。。。" border fit highlight-current-row>
+      <el-table-column type="selection" width="55px"> </el-table-column>
+      <el-table-column type="index" label="序号" header-align="center" align="center">
+      </el-table-column>
+      <el-table-column align="center" min-width="150px" label="入库单号">
+        <template slot-scope="scope">
+          <router-link :to="{ name: 'assemblyDetail', params: { id: scope.row.id } }">
+            <div style="color: #337ab7;cursor: pointer;">{{ scope.row.serialCode }}</div>
+          </router-link>
+        </template>
+      </el-table-column>
+      <el-table-column align="center" min-width="100px" label="入库时间" prop="serialDate">
+      </el-table-column>
+      <el-table-column align="center" min-width="100px" label="供应商" prop="supplierName">
+      </el-table-column>
+      <el-table-column align="center" min-width="100px" label="仓库" prop="warehouseName">
+      </el-table-column>
+      <el-table-column align="center" min-width="100px" label="经手人" prop="addHandlerName">
+      </el-table-column>
+      <el-table-column align="center" min-width="100px" label="入库状态">
+        <template slot-scope="props">
+            <span v-if="props.row.isRunFinish == '0'" style="color: #67C23A;font-weight: bold;">已入库</span>
+            <span v-if="props.row.isRunFinish == '1'" style="color: #E6A23C;font-weight: bold;">待入库</span>
+          </template>
+      </el-table-column>
+      <el-table-column align="center" label="操作" width="240px" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button v-if="scope.row.isRunFinish == '1'" type="success" size="small" @click="handleExecute(scope.row)">入库</el-button>
+          <el-button type="primary" size="small" @click="handleUpdate(scope.row)">编辑</el-button>
+          <el-button type="danger" size="small" @click="handleDelete(scope.row)">删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <!-- 分页 -->
+    <div class="pagination-container">
+      <el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange"
+        :current-page="listQuery.page" :page-sizes="[10, 20, 30, 50]" :page-size="listQuery.limit"
+        layout="total, sizes, prev, pager, next, jumper" :total="total">
+      </el-pagination>
+    </div>
+  </div>
+</template>
+<script>
+import { listAssembly, deleteAssembly, executeAssembly } from "@/api/assembly";
+import { warehouseList } from "@/api/warehouse";
+import waves from "@/directive/waves"; // 水波纹指令
+
+export default {
+  directives: { waves },
+  data() {
+    return {
+      downloadLoading: false,
+      warehouseList: [],
+      typeList: [
+        {
+          type: '0',
+          name: "已入库",
+        },
+        {
+          type: '1',
+          name: "待入库",
+        },
+      ],
+      list: [
+
+      ],
+      delarr: [],
+      multipleSelection: [],
+      total: 0,
+      listLoading: false,
+      listQuery: {
+        page: 1,
+        limit: 10,
+        startDate: '',
+        endDate: '',
+        warehouseId: '',
+        isRunFinish: '',
+      },
+    }
+  },
+  created() {
+    this.getStoreList();
+    this.getList();
+  },
+  methods: {
+    /** 获取仓库列表数据 */
+    getStoreList() {
+      warehouseList().then(response => {
+        this.warehouseList = response.data.data;
+      }).catch(() => { });
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.listQuery = {
+        page: 1,
+        limit: 10,
+        startDate: '',
+        endDate: '',
+        warehouseId: '',
+        isRunFinish: '',
+      },
+        this.getList()
+    },
+    handleDownload() {
+      this.downloadLoading = true
+      import('@/vendor/Export2Excel').then(excel => {
+        const tHeader = ['用户ID', '用户名称', '用户昵称', '用户头像']
+        const filterVal = ['id', 'username', 'nickname', 'avatar']
+        excel.export_json_to_excel2(tHeader, this.list, filterVal, '用户信息')
+        this.downloadLoading = false
+      })
+    },
+    handleCreate() {
+      this.$router.push({
+        name: 'assemblyAdd',
+        // params: { callback: this.getList }
+      })
+    },
+    getList() {
+      this.listLoading = true
+      listAssembly(this.listQuery).then(response => {
+        this.list = response.data.data.items
+        this.total = response.data.data.total
+        this.listLoading = false
+      }).catch(() => {
+        this.list = []
+        this.total = 0
+        this.listLoading = false
+      })
+    },
+
+    handleFilter() {
+      this.listQuery.page = 1
+      this.getList()
+    },
+
+    handleSizeChange(val) {
+      this.listQuery.limit = val
+      this.getList()
+    },
+
+    handleCurrentChange(val) {
+      this.listQuery.page = val
+      this.getList()
+    },
+
+    handleUpdate(row) {
+      this.$router.push({
+        name: 'assemblyEdit',
+        params: { id: row.id }
+      })
+    },
+    handleExecute(row) {
+      this.$confirm('确认入库吗?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        executeAssembly({ ids: row.id }).then(response => {
+          this.$notify({
+            title: '成功',
+            message: '入库成功',
+            type: 'success',
+            duration: 2000
+          })
+          this.getList()
+        })
+      }).catch(() => { })
+    },
+    executeAll() {
+      const length = this.multipleSelection.length;
+      if (length > 0) {
+        this.$confirm("确认入库吗?", "提示", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning",
+        }).then(() => {
+          for (let i = 0; i < length; i++) {
+            this.delarr.push(this.multipleSelection[i].id);
+          }
+          const ids = this.delarr.join(",");
+          executeAssembly({ ids: ids }).then(() => {
+            this.$notify({
+              title: "成功",
+              message: "入库成功",
+              type: "success",
+              duration: 2000,
+            });
+            this.getList();
+          })
+        })
+      } else {
+        this.$notify({
+          title: "提示",
+          message: "请选择要入库的信息!",
+          type: "warning",
+        });
+      }
+    },
+    handleDelete(row) {
+      this.$confirm('确认删除吗?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        deleteAssembly({ ids: row.id }).then(response => {
+          this.$notify({
+            title: '成功',
+            message: '删除成功',
+            type: 'success',
+            duration: 2000
+          })
+          this.getList()
+        })
+      }).catch(() => { })
+    },
+    delAll() {
+      const length = this.multipleSelection.length;
+      if (length > 0) {
+        this.$confirm("确认删除吗?", "提示", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning",
+        }).then(() => {
+          for (let i = 0; i < length; i++) {
+            this.delarr.push(this.multipleSelection[i].id);
+          }
+          const ids = this.delarr.join(",");
+          deleteAssembly({ ids: ids }).then(() => {
+            this.$notify({
+              title: "成功",
+              message: "删除成功",
+              type: "success",
+              duration: 2000,
+            });
+            this.getList();
+          })
+        })
+      } else {
+        this.$notify({
+          title: "提示",
+          message: "请选择要删除的信息!",
+          type: "warning",
+        });
+      }
+    },
+    handleSelectionChange(val) {
+      this.multipleSelection = val;
+    },
+  }
+}
+</script>

+ 335 - 0
src/views/stock/assembly/assemblyAdd.vue

@@ -0,0 +1,335 @@
+<template>
+    <div class="app-container">
+        <el-form ref="dataForm" :model="dataForm" :rules="rules" label-width="120px" inline>
+            <h3>通用入库单</h3>
+            <!-- <el-form-item label="名称" prop="name">
+                <el-input v-model="dataForm.name" :minlength="2" :maxlength="20" clearable
+                    placeholder="请输入名称" style="width:200px" :disabled="type === 'detail'"></el-input>
+            </el-form-item> -->
+            <el-form-item label="入库时间" prop="serialDate">
+                <el-date-picker v-model="dataForm.serialDate" value-format="yyyy-MM-dd HH:mm:ss" type="datetime"
+                    placeholder="选择日期时间" style="width:200px" :disabled="type === 'detail'">
+                </el-date-picker>
+            </el-form-item>
+            <el-form-item label="供应商" prop="supplierId">
+                <el-select v-model="dataForm.supplierId" clearable placeholder="请选择" style="width: 200px;" :disabled="type === 'detail'">
+                    <el-option :key="item.id" v-for="item in supplierList" :label="item.businessName" :value="item.id">
+                    </el-option>
+                </el-select>
+            </el-form-item>
+            <el-form-item label="仓库" prop="warehouseId">
+                <el-select v-model="dataForm.warehouseId" clearable placeholder="请选择" style="width: 200px;" :disabled="type === 'detail'">
+                    <el-option :key="item.id" v-for="item in warehouseList" :label="item.warehouseName" :value="item.id">
+                    </el-option>
+                </el-select>
+            </el-form-item>
+            <el-form-item label="经手人" prop="addHandlerId">
+                <el-select v-model="dataForm.addHandlerId" clearable filterable placeholder="请选择" style="width: 200px" :disabled="type === 'detail'">
+                    <el-option :key="item.loginId" v-for="item in recipientsList" :label="item.deptName+'_'+item.userName" :value="item.loginId">
+                    </el-option>
+                </el-select>
+            </el-form-item>
+            
+
+            <!-- <el-form-item label="采购说明" prop="desc">
+                <el-input style="width:535px" v-model="dataForm.desc" :maxlength="120"
+                    type="textarea" :disabled="type === 'detail'" :autosize="{ minRows: 1, maxRows: 4 }"
+                    placeholder="请输入采购说明 最大120字"></el-input>
+            </el-form-item> -->
+            <el-form-item label="附件:" prop="fileIds">
+                <el-upload :limit="1" :action="fileUrl" :file-list="dataForm.fileList" :on-success="handleFileSuccess"
+                    :before-upload="beforeUploadFile" :on-remove="handleRemove">
+                    <el-button size="small" type="primary" :disabled="type === 'detail'">点击上传</el-button>
+                </el-upload>
+            </el-form-item>
+            <div class="mx">
+        <h3>入库明细</h3>
+        <el-button size="small" type="primary" v-if="type !== 'detail'"
+          @click="handleSelectGoods" icon="el-icon-plus">商品/物料</el-button>
+      </div>
+      <el-table size="small" :data="dataForm.inventoryEntryInfos" border :cell-style="{ textAlign: 'center' }"
+            :header-cell-style="{ textAlign: 'center' }" style="width: 100%">
+            <el-table-column label="商品编号">
+              <template slot-scope="scope">
+                {{ scope.row.productCode }}
+              </template>
+            </el-table-column>
+            <el-table-column label="商品名称">
+              <template slot-scope="scope">
+                {{ scope.row.productName }}
+              </template>
+            </el-table-column>
+            <el-table-column label="单价(¥)">
+              <template slot-scope="scope">
+                {{ scope.row.createPrice.toFixed(2) }}
+              </template>
+            </el-table-column>
+            <el-table-column label="库存数量">
+              <template slot-scope="scope">
+                {{ scope.row.createProductNumber }}
+              </template>
+            </el-table-column>
+            <el-table-column label="入库数量">
+              <template slot-scope="scope">
+                <el-form-item v-if="type !== 'detail'" :prop="'inventoryEntryInfos.'+scope.$index+'.updateNumber'" :rules="{ required: true, message: '入库数量不能为空', trigger: 'blur' }" class="tableFormItem">
+                    <el-input-number v-model="scope.row.updateNumber" @change="handleChange(scope.row)" size="small" :min="1" :max="10000" label="入库数量"></el-input-number>
+                </el-form-item>
+                <span v-else>{{ scope.row.updateNumber }}</span>
+              </template>
+            </el-table-column>
+            <el-table-column label="合计(¥)">
+              <template slot-scope="scope">
+                {{ scope.row.sumPrice.toFixed(2) }}
+              </template>
+            </el-table-column>
+            <!-- <el-table-column label="备注">
+              <template slot-scope="scope">
+                <el-input :maxlength="99" v-model="scope.row.remark" :disabled="type === 'detail'" />
+              </template>
+            </el-table-column> -->
+            <el-table-column label="操作" width="150" v-if="type !== 'detail'">
+              <template slot-scope="scope">
+                <el-button size="mini" type="danger"
+                  @click="dataForm.inventoryEntryInfos.splice(scope.$index, 1)">删除</el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+        </el-form>
+        <div class="footer">
+            <el-button type="primary" @click="submitForm" v-if="type !== 'detail'">保存
+            </el-button>
+            <el-button @click="roBack()">返回
+            </el-button>
+        </div>
+    </div>
+</template>
+<script>
+import { createAssembly, updateAssembly, readAssembly } from "@/api/assembly";
+import { supplierList } from "@/api/supplier";
+import { warehouseList } from "@/api/warehouse";
+import { allUserList } from "@/api/public";
+import waves from "@/directive/waves"; // 水波纹指令
+
+export default {
+    directives: { waves },
+    data() {
+        return {
+            fileUrl:this.upLoadUrl,
+            recipientsList:[],
+            supplierList: [],
+            warehouseList: [],
+            id: '',
+            type: '',
+            /** 表单*/
+            dataForm: {
+                serialDate:'',
+                supplierId:undefined,
+                warehouseId:undefined,
+                addHandlerId:undefined,
+                fileIds:undefined,
+                fileList: [],
+                inventoryEntryInfos: []
+            },
+            rules: {
+                serialDate: [
+                    { required: true, message: '请选择入库时间', trigger: 'blur' }
+                ],
+                warehouseId: [
+                    { required: true, message: '请选择仓库', trigger: 'blur' }
+                ],
+                addHandlerId: [
+                    { required: true, message: '请选择经手人', trigger: 'blur' }
+                ],
+            },
+        }
+    },
+    watch: {
+        $route: {
+            immediate: true,
+            handler(newVal) {
+                if (this.$route.name === 'assemblyAdd') {
+                    this.dataForm = {
+                        serialDate:undefined,
+                        supplierId:undefined,
+                        warehouseId:undefined,
+                        addHandlerId:undefined,
+                        fileIds:undefined,
+                        fileList: [],
+                        inventoryEntryInfos: []
+                    }
+                } else if (this.$route.name === 'assemblyDetail') {
+                    this.type = 'detail'
+                }
+                if (this.$route.params.id) {
+                    this.id = this.$route.params.id
+                    this.getDataFormDetail()
+                }
+            }
+        }
+    },
+    mounted() {
+        this.getSupplierList();
+        this.getStoreList(); 
+        this.getAllUserList(); 
+    },
+    methods: {
+        /** 获取供应商列表数据 */
+        getSupplierList(){
+            supplierList().then(response => {
+                this.supplierList = response.data.data;
+            }).catch(() => { });
+        },
+        /** 获取仓库列表数据 */
+        getStoreList() {
+            warehouseList().then(response => {
+                this.warehouseList = response.data.data;
+            }).catch(() => {});
+        },
+        /** 获取人员列表数据 */
+        getAllUserList() {
+            allUserList().then(response => {
+                this.recipientsList = response.data.data;
+            }).catch(() => { });
+        },
+        /** 获取详情页面数据 */
+        getDataFormDetail() {
+            readAssembly({ id: this.id }).then(response => {
+                let dataForm = response.data.data;
+                dataForm.inventoryEntryInfos = dataForm.inventoryEntryInfos == null ? [] : dataForm.inventoryEntryInfos
+                dataForm.inventoryOutInfos = dataForm.inventoryOutInfos == null ? [] : dataForm.inventoryOutInfos
+                this.dataForm = dataForm;
+            }).catch(() => {})
+        },
+         // 选择商品
+        async handleSelectGoods() {
+            if (!this.dataForm.warehouseId) {
+                this.$message.error('请先选择仓库!')
+                return
+            }else{
+                console.log(this.dataForm.inventoryEntryInfos)
+                let selectedIds = this.dataForm.inventoryEntryInfos.map(item => item.id);
+                const Goods = await this.$EnPickerGoods({
+                    // goodsApi: '/warehouse-entry/info/inventory',
+                    selectedIds: selectedIds,
+                    goodsApiParams: { warehouseId: this.dataForm.warehouseId }
+                })
+                if (!Goods.length) return
+                const inventoryEntryInfos = Goods.map(item => {
+                    item.updateNumber = 1
+                    item.sumPrice = item.createPrice * 1
+                    return item
+                })
+                this.dataForm.inventoryEntryInfos = this.dataForm.inventoryEntryInfos && this.dataForm.inventoryEntryInfos.length ? this.dataForm.inventoryEntryInfos.concat(inventoryEntryInfos) : this.dataForm.inventoryEntryInfos = inventoryEntryInfos
+            }
+            
+        },
+        submitForm(){
+            this.$refs["dataForm"].validate((valid) => {
+                if (valid) {
+                    if(this.dataForm.inventoryEntryInfos.length == 0){
+                        this.$message.error('请选择商品/物料!')
+                        return
+                    }else{
+                        if(this.id){
+                            updateAssembly(this.dataForm).then(() => {
+                                this.$notify({
+                                    title: '成功',
+                                    message: '更新成功',
+                                    type: 'success',
+                                    duration: 2000
+                                })
+                                this.roBack();
+                            })
+                        }else{
+                            createAssembly(this.dataForm).then(() => {
+                                this.$notify({
+                                    title: "成功",
+                                    message: "创建成功",
+                                    type: "success",
+                                    duration: 2000,
+                                });
+                                this.roBack();
+                            })
+                        }
+                    }   
+                }
+            });
+        },
+        handleChange(row) {
+            if (row.createPrice && row.updateNumber) {
+                row.sumPrice = row.createPrice * row.updateNumber
+            }
+        },
+        roBack() {
+            // const { callback } = this.$route.params
+            // if (typeof callback === 'function') callback()
+            this.$store.dispatch('delVisitedViews', this.$route).then((views) => {
+                const latestView = views.slice(-1)[0]
+                if (latestView) {
+                    this.$router.push(latestView.path)
+                } else {
+                    this.$router.push('/')
+                }
+            })
+            // this.$router.push({ name: 'assembly' })
+        },
+        handleRemove(file, fileList) {
+        console.log(file, fileList);
+        let fileIds = [];
+        for (let i in fileList) {
+            let id = fileList[i].response.data.id;
+            fileIds.push(id);
+        }
+        this.dataForm.fileIds = fileIds.join(",");
+        },
+        beforeUploadFile(file) {
+        console.log(file);
+        const size = file.size / 1024 / 1024;
+        console.log(size);
+        if (size > 10) {
+            this.$message.error("文件大小不能超过10MB!");
+            return false;
+        }
+        },
+        handleFileSuccess(res, file, fileList) {
+        console.log(file, fileList);
+        console.log("------", "==========");
+        console.log("res = ", res);
+
+        let fileIds = [];
+        for (let i in fileList) {
+            let response = fileList[i].response;
+            if (response.errno && response.errno != "0") {
+            this.$message.error("该文件上传失败,已被移除,请重新上传!");
+            // 上传失败移除该 file 对象
+            fileList.splice(i, 1);
+            } else {
+            let id = fileList[i].response.data.id;
+            fileIds.push(id);
+            }
+        }
+        this.dataForm.fileIds = fileIds.join(",");
+        },
+    }
+}
+</script>
+<style>
+/** 底部步骤 */
+.footer {
+  width: 100%;
+  padding: 10px;
+  bottom: 0px;
+  text-align: center;
+  z-index: 999;
+}
+.mx {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+}
+/** 表格中输入框样式 */
+.tableFormItem {
+  width: 100%;
+  margin-bottom: 0;
+}
+</style>

+ 282 - 0
src/views/stock/breakage/breakage.vue

@@ -0,0 +1,282 @@
+<template>
+  <div class="app-container calendar-list-container">
+    <!-- 查询和其他操作 -->
+    <div class="filter-container">
+      <el-date-picker v-model="listQuery.startDate" value-format="yyyy-MM-dd" type="date" placeholder="开始日期"
+        style="width:200px">
+      </el-date-picker>
+      <el-date-picker v-model="listQuery.endDate" value-format="yyyy-MM-dd" type="date" placeholder="结束日期"
+        style="width:200px">
+      </el-date-picker>
+      <el-select v-model="listQuery.warehouseId" clearable placeholder="请选择仓库" class="filter-item" style="width: 200px">
+        <el-option :key="item.id" v-for="item in warehouseList" :label="item.warehouseName" :value="item.id">
+        </el-option>
+      </el-select>
+      <el-select v-model="listQuery.isRunFinish" clearable placeholder="请选择状态" class="filter-item" style="width: 200px">
+        <el-option :key="item.type" v-for="item in typeList" :label="item.name" :value="item.type">
+        </el-option>
+      </el-select>
+      <el-button class="filter-item" type="primary" v-waves icon="el-icon-search" @click="handleFilter">查找</el-button>
+      <el-button class="filter-item" v-waves icon="el-icon-refresh" @click="resetQuery">重置</el-button>
+      <el-button class="filter-item" type="primary" @click="handleCreate" icon="el-icon-plus">添加</el-button>
+      <!-- <el-button class="filter-item" :loading="downloadLoading" v-waves icon="el-icon-download"
+        @click="handleDownload">导出</el-button> -->
+      <!-- <el-button class="filter-item" type="success" icon="el-icon-takeaway-box" @click="executeAll">批量入库</el-button> -->
+      <el-button class="filter-item" type="warning" icon="el-icon-delete" @click="delAll">批量删除</el-button>
+    </div>
+
+    <!-- 查询结果 -->
+    <el-table size="small" :data="list" @selection-change="handleSelectionChange" v-loading="listLoading"
+      element-loading-text="正在查询中。。。" border fit highlight-current-row>
+      <el-table-column type="selection" width="55px"> </el-table-column>
+      <el-table-column type="index" label="序号" header-align="center" align="center">
+      </el-table-column>
+      <el-table-column align="center" min-width="150px" label="入库单号">
+        <template slot-scope="scope">
+          <router-link :to="{ name: 'breakageDetail', params: { id: scope.row.id } }">
+            <div style="color: #337ab7;cursor: pointer;">{{ scope.row.serialCode }}</div>
+          </router-link>
+        </template>
+      </el-table-column>
+      <el-table-column align="center" min-width="100px" label="入库时间" prop="serialDate">
+      </el-table-column>
+      <el-table-column align="center" min-width="100px" label="供应商" prop="supplierName">
+      </el-table-column>
+      <el-table-column align="center" min-width="100px" label="仓库" prop="warehouseName">
+      </el-table-column>
+      <el-table-column align="center" min-width="100px" label="经手人" prop="addHandlerName">
+      </el-table-column>
+      <el-table-column align="center" min-width="100px" label="入库状态">
+        <template slot-scope="props">
+            <span v-if="props.row.isRunFinish == '0'" style="color: #67C23A;font-weight: bold;">已入库</span>
+            <span v-if="props.row.isRunFinish == '1'" style="color: #E6A23C;font-weight: bold;">待入库</span>
+          </template>
+      </el-table-column>
+      <el-table-column align="center" label="操作" width="240px" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button v-if="scope.row.isRunFinish == '1'" type="success" size="small" @click="handleExecute(scope.row)">入库</el-button>
+          <el-button type="primary" size="small" @click="handleUpdate(scope.row)">编辑</el-button>
+          <el-button type="danger" size="small" @click="handleDelete(scope.row)">删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <!-- 分页 -->
+    <div class="pagination-container">
+      <el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange"
+        :current-page="listQuery.page" :page-sizes="[10, 20, 30, 50]" :page-size="listQuery.limit"
+        layout="total, sizes, prev, pager, next, jumper" :total="total">
+      </el-pagination>
+    </div>
+  </div>
+</template>
+<script>
+import { listBreakage, deleteBreakage, executeBreakage } from "@/api/breakage";
+import { warehouseList } from "@/api/warehouse";
+import waves from "@/directive/waves"; // 水波纹指令
+
+export default {
+  directives: { waves },
+  data() {
+    return {
+      downloadLoading: false,
+      warehouseList: [],
+      typeList: [
+        {
+          type: '0',
+          name: "已入库",
+        },
+        {
+          type: '1',
+          name: "待入库",
+        },
+      ],
+      list: [
+
+      ],
+      delarr: [],
+      multipleSelection: [],
+      total: 0,
+      listLoading: false,
+      listQuery: {
+        page: 1,
+        limit: 10,
+        startDate: '',
+        endDate: '',
+        warehouseId: '',
+        isRunFinish: '',
+      },
+    }
+  },
+  created() {
+    this.getStoreList();
+    this.getList();
+  },
+  methods: {
+    /** 获取仓库列表数据 */
+    getStoreList() {
+      warehouseList().then(response => {
+        this.warehouseList = response.data.data;
+      }).catch(() => { });
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.listQuery = {
+        page: 1,
+        limit: 10,
+        startDate: '',
+        endDate: '',
+        warehouseId: '',
+        isRunFinish: '',
+      },
+        this.getList()
+    },
+    handleDownload() {
+      this.downloadLoading = true
+      import('@/vendor/Export2Excel').then(excel => {
+        const tHeader = ['用户ID', '用户名称', '用户昵称', '用户头像']
+        const filterVal = ['id', 'username', 'nickname', 'avatar']
+        excel.export_json_to_excel2(tHeader, this.list, filterVal, '用户信息')
+        this.downloadLoading = false
+      })
+    },
+    handleCreate() {
+      this.$router.push({
+        name: 'breakageAdd',
+        // params: { callback: this.getList }
+      })
+    },
+    getList() {
+      this.listLoading = true
+      listBreakage(this.listQuery).then(response => {
+        this.list = response.data.data.items
+        this.total = response.data.data.total
+        this.listLoading = false
+      }).catch(() => {
+        this.list = []
+        this.total = 0
+        this.listLoading = false
+      })
+    },
+
+    handleFilter() {
+      this.listQuery.page = 1
+      this.getList()
+    },
+
+    handleSizeChange(val) {
+      this.listQuery.limit = val
+      this.getList()
+    },
+
+    handleCurrentChange(val) {
+      this.listQuery.page = val
+      this.getList()
+    },
+
+    handleUpdate(row) {
+      this.$router.push({
+        name: 'breakageEdit',
+        params: { id: row.id }
+      })
+    },
+    handleExecute(row) {
+      this.$confirm('确认入库吗?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        executeBreakage({ ids: row.id }).then(response => {
+          this.$notify({
+            title: '成功',
+            message: '入库成功',
+            type: 'success',
+            duration: 2000
+          })
+          this.getList()
+        })
+      }).catch(() => { })
+    },
+    executeAll() {
+      const length = this.multipleSelection.length;
+      if (length > 0) {
+        this.$confirm("确认入库吗?", "提示", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning",
+        }).then(() => {
+          for (let i = 0; i < length; i++) {
+            this.delarr.push(this.multipleSelection[i].id);
+          }
+          const ids = this.delarr.join(",");
+          executeBreakage({ ids: ids }).then(() => {
+            this.$notify({
+              title: "成功",
+              message: "入库成功",
+              type: "success",
+              duration: 2000,
+            });
+            this.getList();
+          })
+        })
+      } else {
+        this.$notify({
+          title: "提示",
+          message: "请选择要入库的信息!",
+          type: "warning",
+        });
+      }
+    },
+    handleDelete(row) {
+      this.$confirm('确认删除吗?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        deleteBreakage({ ids: row.id }).then(response => {
+          this.$notify({
+            title: '成功',
+            message: '删除成功',
+            type: 'success',
+            duration: 2000
+          })
+          this.getList()
+        })
+      }).catch(() => { })
+    },
+    delAll() {
+      const length = this.multipleSelection.length;
+      if (length > 0) {
+        this.$confirm("确认删除吗?", "提示", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning",
+        }).then(() => {
+          for (let i = 0; i < length; i++) {
+            this.delarr.push(this.multipleSelection[i].id);
+          }
+          const ids = this.delarr.join(",");
+          deleteBreakage({ ids: ids }).then(() => {
+            this.$notify({
+              title: "成功",
+              message: "删除成功",
+              type: "success",
+              duration: 2000,
+            });
+            this.getList();
+          })
+        })
+      } else {
+        this.$notify({
+          title: "提示",
+          message: "请选择要删除的信息!",
+          type: "warning",
+        });
+      }
+    },
+    handleSelectionChange(val) {
+      this.multipleSelection = val;
+    },
+  }
+}
+</script>

+ 335 - 0
src/views/stock/breakage/breakageAdd.vue

@@ -0,0 +1,335 @@
+<template>
+    <div class="app-container">
+        <el-form ref="dataForm" :model="dataForm" :rules="rules" label-width="120px" inline>
+            <h3>通用入库单</h3>
+            <!-- <el-form-item label="名称" prop="name">
+                <el-input v-model="dataForm.name" :minlength="2" :maxlength="20" clearable
+                    placeholder="请输入名称" style="width:200px" :disabled="type === 'detail'"></el-input>
+            </el-form-item> -->
+            <el-form-item label="入库时间" prop="serialDate">
+                <el-date-picker v-model="dataForm.serialDate" value-format="yyyy-MM-dd HH:mm:ss" type="datetime"
+                    placeholder="选择日期时间" style="width:200px" :disabled="type === 'detail'">
+                </el-date-picker>
+            </el-form-item>
+            <el-form-item label="供应商" prop="supplierId">
+                <el-select v-model="dataForm.supplierId" clearable placeholder="请选择" style="width: 200px;" :disabled="type === 'detail'">
+                    <el-option :key="item.id" v-for="item in supplierList" :label="item.businessName" :value="item.id">
+                    </el-option>
+                </el-select>
+            </el-form-item>
+            <el-form-item label="仓库" prop="warehouseId">
+                <el-select v-model="dataForm.warehouseId" clearable placeholder="请选择" style="width: 200px;" :disabled="type === 'detail'">
+                    <el-option :key="item.id" v-for="item in warehouseList" :label="item.warehouseName" :value="item.id">
+                    </el-option>
+                </el-select>
+            </el-form-item>
+            <el-form-item label="经手人" prop="addHandlerId">
+                <el-select v-model="dataForm.addHandlerId" clearable filterable placeholder="请选择" style="width: 200px" :disabled="type === 'detail'">
+                    <el-option :key="item.loginId" v-for="item in recipientsList" :label="item.deptName+'_'+item.userName" :value="item.loginId">
+                    </el-option>
+                </el-select>
+            </el-form-item>
+            
+
+            <!-- <el-form-item label="采购说明" prop="desc">
+                <el-input style="width:535px" v-model="dataForm.desc" :maxlength="120"
+                    type="textarea" :disabled="type === 'detail'" :autosize="{ minRows: 1, maxRows: 4 }"
+                    placeholder="请输入采购说明 最大120字"></el-input>
+            </el-form-item> -->
+            <el-form-item label="附件:" prop="fileIds">
+                <el-upload :limit="1" :action="fileUrl" :file-list="dataForm.fileList" :on-success="handleFileSuccess"
+                    :before-upload="beforeUploadFile" :on-remove="handleRemove">
+                    <el-button size="small" type="primary" :disabled="type === 'detail'">点击上传</el-button>
+                </el-upload>
+            </el-form-item>
+            <div class="mx">
+        <h3>入库明细</h3>
+        <el-button size="small" type="primary" v-if="type !== 'detail'"
+          @click="handleSelectGoods" icon="el-icon-plus">商品/物料</el-button>
+      </div>
+      <el-table size="small" :data="dataForm.inventoryEntryInfos" border :cell-style="{ textAlign: 'center' }"
+            :header-cell-style="{ textAlign: 'center' }" style="width: 100%">
+            <el-table-column label="商品编号">
+              <template slot-scope="scope">
+                {{ scope.row.productCode }}
+              </template>
+            </el-table-column>
+            <el-table-column label="商品名称">
+              <template slot-scope="scope">
+                {{ scope.row.productName }}
+              </template>
+            </el-table-column>
+            <el-table-column label="单价(¥)">
+              <template slot-scope="scope">
+                {{ scope.row.createPrice.toFixed(2) }}
+              </template>
+            </el-table-column>
+            <el-table-column label="库存数量">
+              <template slot-scope="scope">
+                {{ scope.row.createProductNumber }}
+              </template>
+            </el-table-column>
+            <el-table-column label="入库数量">
+              <template slot-scope="scope">
+                <el-form-item v-if="type !== 'detail'" :prop="'inventoryEntryInfos.'+scope.$index+'.updateNumber'" :rules="{ required: true, message: '入库数量不能为空', trigger: 'blur' }" class="tableFormItem">
+                    <el-input-number v-model="scope.row.updateNumber" @change="handleChange(scope.row)" size="small" :min="1" :max="10000" label="入库数量"></el-input-number>
+                </el-form-item>
+                <span v-else>{{ scope.row.updateNumber }}</span>
+              </template>
+            </el-table-column>
+            <el-table-column label="合计(¥)">
+              <template slot-scope="scope">
+                {{ scope.row.sumPrice.toFixed(2) }}
+              </template>
+            </el-table-column>
+            <!-- <el-table-column label="备注">
+              <template slot-scope="scope">
+                <el-input :maxlength="99" v-model="scope.row.remark" :disabled="type === 'detail'" />
+              </template>
+            </el-table-column> -->
+            <el-table-column label="操作" width="150" v-if="type !== 'detail'">
+              <template slot-scope="scope">
+                <el-button size="mini" type="danger"
+                  @click="dataForm.inventoryEntryInfos.splice(scope.$index, 1)">删除</el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+        </el-form>
+        <div class="footer">
+            <el-button type="primary" @click="submitForm" v-if="type !== 'detail'">保存
+            </el-button>
+            <el-button @click="roBack()">返回
+            </el-button>
+        </div>
+    </div>
+</template>
+<script>
+import { createBreakage, updateBreakage, readBreakage } from "@/api/breakage";
+import { supplierList } from "@/api/supplier";
+import { warehouseList } from "@/api/warehouse";
+import { allUserList } from "@/api/public";
+import waves from "@/directive/waves"; // 水波纹指令
+
+export default {
+    directives: { waves },
+    data() {
+        return {
+            fileUrl:this.upLoadUrl,
+            recipientsList:[],
+            supplierList: [],
+            warehouseList: [],
+            id: '',
+            type: '',
+            /** 表单*/
+            dataForm: {
+                serialDate:'',
+                supplierId:undefined,
+                warehouseId:undefined,
+                addHandlerId:undefined,
+                fileIds:undefined,
+                fileList: [],
+                inventoryEntryInfos: []
+            },
+            rules: {
+                serialDate: [
+                    { required: true, message: '请选择入库时间', trigger: 'blur' }
+                ],
+                warehouseId: [
+                    { required: true, message: '请选择仓库', trigger: 'blur' }
+                ],
+                addHandlerId: [
+                    { required: true, message: '请选择经手人', trigger: 'blur' }
+                ],
+            },
+        }
+    },
+    watch: {
+        $route: {
+            immediate: true,
+            handler(newVal) {
+                if (this.$route.name === 'breakageAdd') {
+                    this.dataForm = {
+                        serialDate:undefined,
+                        supplierId:undefined,
+                        warehouseId:undefined,
+                        addHandlerId:undefined,
+                        fileIds:undefined,
+                        fileList: [],
+                        inventoryEntryInfos: []
+                    }
+                } else if (this.$route.name === 'breakageDetail') {
+                    this.type = 'detail'
+                }
+                if (this.$route.params.id) {
+                    this.id = this.$route.params.id
+                    this.getDataFormDetail()
+                }
+            }
+        }
+    },
+    mounted() {
+        this.getSupplierList();
+        this.getStoreList(); 
+        this.getAllUserList(); 
+    },
+    methods: {
+        /** 获取供应商列表数据 */
+        getSupplierList(){
+            supplierList().then(response => {
+                this.supplierList = response.data.data;
+            }).catch(() => { });
+        },
+        /** 获取仓库列表数据 */
+        getStoreList() {
+            warehouseList().then(response => {
+                this.warehouseList = response.data.data;
+            }).catch(() => {});
+        },
+        /** 获取人员列表数据 */
+        getAllUserList() {
+            allUserList().then(response => {
+                this.recipientsList = response.data.data;
+            }).catch(() => { });
+        },
+        /** 获取详情页面数据 */
+        getDataFormDetail() {
+            readBreakage({ id: this.id }).then(response => {
+                let dataForm = response.data.data;
+                dataForm.inventoryEntryInfos = dataForm.inventoryEntryInfos == null ? [] : dataForm.inventoryEntryInfos
+                dataForm.inventoryOutInfos = dataForm.inventoryOutInfos == null ? [] : dataForm.inventoryOutInfos
+                this.dataForm = dataForm;
+            }).catch(() => {})
+        },
+         // 选择商品
+        async handleSelectGoods() {
+            if (!this.dataForm.warehouseId) {
+                this.$message.error('请先选择仓库!')
+                return
+            }else{
+                console.log(this.dataForm.inventoryEntryInfos)
+                let selectedIds = this.dataForm.inventoryEntryInfos.map(item => item.id);
+                const Goods = await this.$EnPickerGoods({
+                    // goodsApi: '/warehouse-entry/info/inventory',
+                    selectedIds: selectedIds,
+                    goodsApiParams: { warehouseId: this.dataForm.warehouseId }
+                })
+                if (!Goods.length) return
+                const inventoryEntryInfos = Goods.map(item => {
+                    item.updateNumber = 1
+                    item.sumPrice = item.createPrice * 1
+                    return item
+                })
+                this.dataForm.inventoryEntryInfos = this.dataForm.inventoryEntryInfos && this.dataForm.inventoryEntryInfos.length ? this.dataForm.inventoryEntryInfos.concat(inventoryEntryInfos) : this.dataForm.inventoryEntryInfos = inventoryEntryInfos
+            }
+            
+        },
+        submitForm(){
+            this.$refs["dataForm"].validate((valid) => {
+                if (valid) {
+                    if(this.dataForm.inventoryEntryInfos.length == 0){
+                        this.$message.error('请选择商品/物料!')
+                        return
+                    }else{
+                        if(this.id){
+                            updateBreakage(this.dataForm).then(() => {
+                                this.$notify({
+                                    title: '成功',
+                                    message: '更新成功',
+                                    type: 'success',
+                                    duration: 2000
+                                })
+                                this.roBack();
+                            })
+                        }else{
+                            createBreakage(this.dataForm).then(() => {
+                                this.$notify({
+                                    title: "成功",
+                                    message: "创建成功",
+                                    type: "success",
+                                    duration: 2000,
+                                });
+                                this.roBack();
+                            })
+                        }
+                    }   
+                }
+            });
+        },
+        handleChange(row) {
+            if (row.createPrice && row.updateNumber) {
+                row.sumPrice = row.createPrice * row.updateNumber
+            }
+        },
+        roBack() {
+            // const { callback } = this.$route.params
+            // if (typeof callback === 'function') callback()
+            this.$store.dispatch('delVisitedViews', this.$route).then((views) => {
+                const latestView = views.slice(-1)[0]
+                if (latestView) {
+                    this.$router.push(latestView.path)
+                } else {
+                    this.$router.push('/')
+                }
+            })
+            // this.$router.push({ name: 'breakage' })
+        },
+        handleRemove(file, fileList) {
+        console.log(file, fileList);
+        let fileIds = [];
+        for (let i in fileList) {
+            let id = fileList[i].response.data.id;
+            fileIds.push(id);
+        }
+        this.dataForm.fileIds = fileIds.join(",");
+        },
+        beforeUploadFile(file) {
+        console.log(file);
+        const size = file.size / 1024 / 1024;
+        console.log(size);
+        if (size > 10) {
+            this.$message.error("文件大小不能超过10MB!");
+            return false;
+        }
+        },
+        handleFileSuccess(res, file, fileList) {
+        console.log(file, fileList);
+        console.log("------", "==========");
+        console.log("res = ", res);
+
+        let fileIds = [];
+        for (let i in fileList) {
+            let response = fileList[i].response;
+            if (response.errno && response.errno != "0") {
+            this.$message.error("该文件上传失败,已被移除,请重新上传!");
+            // 上传失败移除该 file 对象
+            fileList.splice(i, 1);
+            } else {
+            let id = fileList[i].response.data.id;
+            fileIds.push(id);
+            }
+        }
+        this.dataForm.fileIds = fileIds.join(",");
+        },
+    }
+}
+</script>
+<style>
+/** 底部步骤 */
+.footer {
+  width: 100%;
+  padding: 10px;
+  bottom: 0px;
+  text-align: center;
+  z-index: 999;
+}
+.mx {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+}
+/** 表格中输入框样式 */
+.tableFormItem {
+  width: 100%;
+  margin-bottom: 0;
+}
+</style>

+ 282 - 0
src/views/stock/disassembly/disassembly.vue

@@ -0,0 +1,282 @@
+<template>
+  <div class="app-container calendar-list-container">
+    <!-- 查询和其他操作 -->
+    <div class="filter-container">
+      <el-date-picker v-model="listQuery.startDate" value-format="yyyy-MM-dd" type="date" placeholder="开始日期"
+        style="width:200px">
+      </el-date-picker>
+      <el-date-picker v-model="listQuery.endDate" value-format="yyyy-MM-dd" type="date" placeholder="结束日期"
+        style="width:200px">
+      </el-date-picker>
+      <el-select v-model="listQuery.warehouseId" clearable placeholder="请选择仓库" class="filter-item" style="width: 200px">
+        <el-option :key="item.id" v-for="item in warehouseList" :label="item.warehouseName" :value="item.id">
+        </el-option>
+      </el-select>
+      <el-select v-model="listQuery.isRunFinish" clearable placeholder="请选择状态" class="filter-item" style="width: 200px">
+        <el-option :key="item.type" v-for="item in typeList" :label="item.name" :value="item.type">
+        </el-option>
+      </el-select>
+      <el-button class="filter-item" type="primary" v-waves icon="el-icon-search" @click="handleFilter">查找</el-button>
+      <el-button class="filter-item" v-waves icon="el-icon-refresh" @click="resetQuery">重置</el-button>
+      <el-button class="filter-item" type="primary" @click="handleCreate" icon="el-icon-plus">添加</el-button>
+      <!-- <el-button class="filter-item" :loading="downloadLoading" v-waves icon="el-icon-download"
+        @click="handleDownload">导出</el-button> -->
+      <!-- <el-button class="filter-item" type="success" icon="el-icon-takeaway-box" @click="executeAll">批量入库</el-button> -->
+      <el-button class="filter-item" type="warning" icon="el-icon-delete" @click="delAll">批量删除</el-button>
+    </div>
+
+    <!-- 查询结果 -->
+    <el-table size="small" :data="list" @selection-change="handleSelectionChange" v-loading="listLoading"
+      element-loading-text="正在查询中。。。" border fit highlight-current-row>
+      <el-table-column type="selection" width="55px"> </el-table-column>
+      <el-table-column type="index" label="序号" header-align="center" align="center">
+      </el-table-column>
+      <el-table-column align="center" min-width="150px" label="入库单号">
+        <template slot-scope="scope">
+          <router-link :to="{ name: 'disassemblyDetail', params: { id: scope.row.id } }">
+            <div style="color: #337ab7;cursor: pointer;">{{ scope.row.serialCode }}</div>
+          </router-link>
+        </template>
+      </el-table-column>
+      <el-table-column align="center" min-width="100px" label="入库时间" prop="serialDate">
+      </el-table-column>
+      <el-table-column align="center" min-width="100px" label="供应商" prop="supplierName">
+      </el-table-column>
+      <el-table-column align="center" min-width="100px" label="仓库" prop="warehouseName">
+      </el-table-column>
+      <el-table-column align="center" min-width="100px" label="经手人" prop="addHandlerName">
+      </el-table-column>
+      <el-table-column align="center" min-width="100px" label="入库状态">
+        <template slot-scope="props">
+            <span v-if="props.row.isRunFinish == '0'" style="color: #67C23A;font-weight: bold;">已入库</span>
+            <span v-if="props.row.isRunFinish == '1'" style="color: #E6A23C;font-weight: bold;">待入库</span>
+          </template>
+      </el-table-column>
+      <el-table-column align="center" label="操作" width="240px" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button v-if="scope.row.isRunFinish == '1'" type="success" size="small" @click="handleExecute(scope.row)">入库</el-button>
+          <el-button type="primary" size="small" @click="handleUpdate(scope.row)">编辑</el-button>
+          <el-button type="danger" size="small" @click="handleDelete(scope.row)">删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <!-- 分页 -->
+    <div class="pagination-container">
+      <el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange"
+        :current-page="listQuery.page" :page-sizes="[10, 20, 30, 50]" :page-size="listQuery.limit"
+        layout="total, sizes, prev, pager, next, jumper" :total="total">
+      </el-pagination>
+    </div>
+  </div>
+</template>
+<script>
+import { listDisassembly, deleteDisassembly, executeDisassembly } from "@/api/disassembly";
+import { warehouseList } from "@/api/warehouse";
+import waves from "@/directive/waves"; // 水波纹指令
+
+export default {
+  directives: { waves },
+  data() {
+    return {
+      downloadLoading: false,
+      warehouseList: [],
+      typeList: [
+        {
+          type: '0',
+          name: "已入库",
+        },
+        {
+          type: '1',
+          name: "待入库",
+        },
+      ],
+      list: [
+
+      ],
+      delarr: [],
+      multipleSelection: [],
+      total: 0,
+      listLoading: false,
+      listQuery: {
+        page: 1,
+        limit: 10,
+        startDate: '',
+        endDate: '',
+        warehouseId: '',
+        isRunFinish: '',
+      },
+    }
+  },
+  created() {
+    this.getStoreList();
+    this.getList();
+  },
+  methods: {
+    /** 获取仓库列表数据 */
+    getStoreList() {
+      warehouseList().then(response => {
+        this.warehouseList = response.data.data;
+      }).catch(() => { });
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.listQuery = {
+        page: 1,
+        limit: 10,
+        startDate: '',
+        endDate: '',
+        warehouseId: '',
+        isRunFinish: '',
+      },
+        this.getList()
+    },
+    handleDownload() {
+      this.downloadLoading = true
+      import('@/vendor/Export2Excel').then(excel => {
+        const tHeader = ['用户ID', '用户名称', '用户昵称', '用户头像']
+        const filterVal = ['id', 'username', 'nickname', 'avatar']
+        excel.export_json_to_excel2(tHeader, this.list, filterVal, '用户信息')
+        this.downloadLoading = false
+      })
+    },
+    handleCreate() {
+      this.$router.push({
+        name: 'disassemblyAdd',
+        // params: { callback: this.getList }
+      })
+    },
+    getList() {
+      this.listLoading = true
+      listDisassembly(this.listQuery).then(response => {
+        this.list = response.data.data.items
+        this.total = response.data.data.total
+        this.listLoading = false
+      }).catch(() => {
+        this.list = []
+        this.total = 0
+        this.listLoading = false
+      })
+    },
+
+    handleFilter() {
+      this.listQuery.page = 1
+      this.getList()
+    },
+
+    handleSizeChange(val) {
+      this.listQuery.limit = val
+      this.getList()
+    },
+
+    handleCurrentChange(val) {
+      this.listQuery.page = val
+      this.getList()
+    },
+
+    handleUpdate(row) {
+      this.$router.push({
+        name: 'disassemblyEdit',
+        params: { id: row.id }
+      })
+    },
+    handleExecute(row) {
+      this.$confirm('确认入库吗?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        executeDisassembly({ ids: row.id }).then(response => {
+          this.$notify({
+            title: '成功',
+            message: '入库成功',
+            type: 'success',
+            duration: 2000
+          })
+          this.getList()
+        })
+      }).catch(() => { })
+    },
+    executeAll() {
+      const length = this.multipleSelection.length;
+      if (length > 0) {
+        this.$confirm("确认入库吗?", "提示", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning",
+        }).then(() => {
+          for (let i = 0; i < length; i++) {
+            this.delarr.push(this.multipleSelection[i].id);
+          }
+          const ids = this.delarr.join(",");
+          executeDisassembly({ ids: ids }).then(() => {
+            this.$notify({
+              title: "成功",
+              message: "入库成功",
+              type: "success",
+              duration: 2000,
+            });
+            this.getList();
+          })
+        })
+      } else {
+        this.$notify({
+          title: "提示",
+          message: "请选择要入库的信息!",
+          type: "warning",
+        });
+      }
+    },
+    handleDelete(row) {
+      this.$confirm('确认删除吗?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        deleteDisassembly({ ids: row.id }).then(response => {
+          this.$notify({
+            title: '成功',
+            message: '删除成功',
+            type: 'success',
+            duration: 2000
+          })
+          this.getList()
+        })
+      }).catch(() => { })
+    },
+    delAll() {
+      const length = this.multipleSelection.length;
+      if (length > 0) {
+        this.$confirm("确认删除吗?", "提示", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning",
+        }).then(() => {
+          for (let i = 0; i < length; i++) {
+            this.delarr.push(this.multipleSelection[i].id);
+          }
+          const ids = this.delarr.join(",");
+          deleteDisassembly({ ids: ids }).then(() => {
+            this.$notify({
+              title: "成功",
+              message: "删除成功",
+              type: "success",
+              duration: 2000,
+            });
+            this.getList();
+          })
+        })
+      } else {
+        this.$notify({
+          title: "提示",
+          message: "请选择要删除的信息!",
+          type: "warning",
+        });
+      }
+    },
+    handleSelectionChange(val) {
+      this.multipleSelection = val;
+    },
+  }
+}
+</script>

+ 335 - 0
src/views/stock/disassembly/disassemblyAdd.vue

@@ -0,0 +1,335 @@
+<template>
+    <div class="app-container">
+        <el-form ref="dataForm" :model="dataForm" :rules="rules" label-width="120px" inline>
+            <h3>通用入库单</h3>
+            <!-- <el-form-item label="名称" prop="name">
+                <el-input v-model="dataForm.name" :minlength="2" :maxlength="20" clearable
+                    placeholder="请输入名称" style="width:200px" :disabled="type === 'detail'"></el-input>
+            </el-form-item> -->
+            <el-form-item label="入库时间" prop="serialDate">
+                <el-date-picker v-model="dataForm.serialDate" value-format="yyyy-MM-dd HH:mm:ss" type="datetime"
+                    placeholder="选择日期时间" style="width:200px" :disabled="type === 'detail'">
+                </el-date-picker>
+            </el-form-item>
+            <el-form-item label="供应商" prop="supplierId">
+                <el-select v-model="dataForm.supplierId" clearable placeholder="请选择" style="width: 200px;" :disabled="type === 'detail'">
+                    <el-option :key="item.id" v-for="item in supplierList" :label="item.businessName" :value="item.id">
+                    </el-option>
+                </el-select>
+            </el-form-item>
+            <el-form-item label="仓库" prop="warehouseId">
+                <el-select v-model="dataForm.warehouseId" clearable placeholder="请选择" style="width: 200px;" :disabled="type === 'detail'">
+                    <el-option :key="item.id" v-for="item in warehouseList" :label="item.warehouseName" :value="item.id">
+                    </el-option>
+                </el-select>
+            </el-form-item>
+            <el-form-item label="经手人" prop="addHandlerId">
+                <el-select v-model="dataForm.addHandlerId" clearable filterable placeholder="请选择" style="width: 200px" :disabled="type === 'detail'">
+                    <el-option :key="item.loginId" v-for="item in recipientsList" :label="item.deptName+'_'+item.userName" :value="item.loginId">
+                    </el-option>
+                </el-select>
+            </el-form-item>
+            
+
+            <!-- <el-form-item label="采购说明" prop="desc">
+                <el-input style="width:535px" v-model="dataForm.desc" :maxlength="120"
+                    type="textarea" :disabled="type === 'detail'" :autosize="{ minRows: 1, maxRows: 4 }"
+                    placeholder="请输入采购说明 最大120字"></el-input>
+            </el-form-item> -->
+            <el-form-item label="附件:" prop="fileIds">
+                <el-upload :limit="1" :action="fileUrl" :file-list="dataForm.fileList" :on-success="handleFileSuccess"
+                    :before-upload="beforeUploadFile" :on-remove="handleRemove">
+                    <el-button size="small" type="primary" :disabled="type === 'detail'">点击上传</el-button>
+                </el-upload>
+            </el-form-item>
+            <div class="mx">
+        <h3>入库明细</h3>
+        <el-button size="small" type="primary" v-if="type !== 'detail'"
+          @click="handleSelectGoods" icon="el-icon-plus">商品/物料</el-button>
+      </div>
+      <el-table size="small" :data="dataForm.inventoryEntryInfos" border :cell-style="{ textAlign: 'center' }"
+            :header-cell-style="{ textAlign: 'center' }" style="width: 100%">
+            <el-table-column label="商品编号">
+              <template slot-scope="scope">
+                {{ scope.row.productCode }}
+              </template>
+            </el-table-column>
+            <el-table-column label="商品名称">
+              <template slot-scope="scope">
+                {{ scope.row.productName }}
+              </template>
+            </el-table-column>
+            <el-table-column label="单价(¥)">
+              <template slot-scope="scope">
+                {{ scope.row.createPrice.toFixed(2) }}
+              </template>
+            </el-table-column>
+            <el-table-column label="库存数量">
+              <template slot-scope="scope">
+                {{ scope.row.createProductNumber }}
+              </template>
+            </el-table-column>
+            <el-table-column label="入库数量">
+              <template slot-scope="scope">
+                <el-form-item v-if="type !== 'detail'" :prop="'inventoryEntryInfos.'+scope.$index+'.updateNumber'" :rules="{ required: true, message: '入库数量不能为空', trigger: 'blur' }" class="tableFormItem">
+                    <el-input-number v-model="scope.row.updateNumber" @change="handleChange(scope.row)" size="small" :min="1" :max="10000" label="入库数量"></el-input-number>
+                </el-form-item>
+                <span v-else>{{ scope.row.updateNumber }}</span>
+              </template>
+            </el-table-column>
+            <el-table-column label="合计(¥)">
+              <template slot-scope="scope">
+                {{ scope.row.sumPrice.toFixed(2) }}
+              </template>
+            </el-table-column>
+            <!-- <el-table-column label="备注">
+              <template slot-scope="scope">
+                <el-input :maxlength="99" v-model="scope.row.remark" :disabled="type === 'detail'" />
+              </template>
+            </el-table-column> -->
+            <el-table-column label="操作" width="150" v-if="type !== 'detail'">
+              <template slot-scope="scope">
+                <el-button size="mini" type="danger"
+                  @click="dataForm.inventoryEntryInfos.splice(scope.$index, 1)">删除</el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+        </el-form>
+        <div class="footer">
+            <el-button type="primary" @click="submitForm" v-if="type !== 'detail'">保存
+            </el-button>
+            <el-button @click="roBack()">返回
+            </el-button>
+        </div>
+    </div>
+</template>
+<script>
+import { createDisassembly, updateDisassembly, readDisassembly } from "@/api/disassembly";
+import { supplierList } from "@/api/supplier";
+import { warehouseList } from "@/api/warehouse";
+import { allUserList } from "@/api/public";
+import waves from "@/directive/waves"; // 水波纹指令
+
+export default {
+    directives: { waves },
+    data() {
+        return {
+            fileUrl:this.upLoadUrl,
+            recipientsList:[],
+            supplierList: [],
+            warehouseList: [],
+            id: '',
+            type: '',
+            /** 表单*/
+            dataForm: {
+                serialDate:'',
+                supplierId:undefined,
+                warehouseId:undefined,
+                addHandlerId:undefined,
+                fileIds:undefined,
+                fileList: [],
+                inventoryEntryInfos: []
+            },
+            rules: {
+                serialDate: [
+                    { required: true, message: '请选择入库时间', trigger: 'blur' }
+                ],
+                warehouseId: [
+                    { required: true, message: '请选择仓库', trigger: 'blur' }
+                ],
+                addHandlerId: [
+                    { required: true, message: '请选择经手人', trigger: 'blur' }
+                ],
+            },
+        }
+    },
+    watch: {
+        $route: {
+            immediate: true,
+            handler(newVal) {
+                if (this.$route.name === 'disassemblyAdd') {
+                    this.dataForm = {
+                        serialDate:undefined,
+                        supplierId:undefined,
+                        warehouseId:undefined,
+                        addHandlerId:undefined,
+                        fileIds:undefined,
+                        fileList: [],
+                        inventoryEntryInfos: []
+                    }
+                } else if (this.$route.name === 'disassemblyDetail') {
+                    this.type = 'detail'
+                }
+                if (this.$route.params.id) {
+                    this.id = this.$route.params.id
+                    this.getDataFormDetail()
+                }
+            }
+        }
+    },
+    mounted() {
+        this.getSupplierList();
+        this.getStoreList(); 
+        this.getAllUserList(); 
+    },
+    methods: {
+        /** 获取供应商列表数据 */
+        getSupplierList(){
+            supplierList().then(response => {
+                this.supplierList = response.data.data;
+            }).catch(() => { });
+        },
+        /** 获取仓库列表数据 */
+        getStoreList() {
+            warehouseList().then(response => {
+                this.warehouseList = response.data.data;
+            }).catch(() => {});
+        },
+        /** 获取人员列表数据 */
+        getAllUserList() {
+            allUserList().then(response => {
+                this.recipientsList = response.data.data;
+            }).catch(() => { });
+        },
+        /** 获取详情页面数据 */
+        getDataFormDetail() {
+            readDisassembly({ id: this.id }).then(response => {
+                let dataForm = response.data.data;
+                dataForm.inventoryEntryInfos = dataForm.inventoryEntryInfos == null ? [] : dataForm.inventoryEntryInfos
+                dataForm.inventoryOutInfos = dataForm.inventoryOutInfos == null ? [] : dataForm.inventoryOutInfos
+                this.dataForm = dataForm;
+            }).catch(() => {})
+        },
+         // 选择商品
+        async handleSelectGoods() {
+            if (!this.dataForm.warehouseId) {
+                this.$message.error('请先选择仓库!')
+                return
+            }else{
+                console.log(this.dataForm.inventoryEntryInfos)
+                let selectedIds = this.dataForm.inventoryEntryInfos.map(item => item.id);
+                const Goods = await this.$EnPickerGoods({
+                    // goodsApi: '/warehouse-entry/info/inventory',
+                    selectedIds: selectedIds,
+                    goodsApiParams: { warehouseId: this.dataForm.warehouseId }
+                })
+                if (!Goods.length) return
+                const inventoryEntryInfos = Goods.map(item => {
+                    item.updateNumber = 1
+                    item.sumPrice = item.createPrice * 1
+                    return item
+                })
+                this.dataForm.inventoryEntryInfos = this.dataForm.inventoryEntryInfos && this.dataForm.inventoryEntryInfos.length ? this.dataForm.inventoryEntryInfos.concat(inventoryEntryInfos) : this.dataForm.inventoryEntryInfos = inventoryEntryInfos
+            }
+            
+        },
+        submitForm(){
+            this.$refs["dataForm"].validate((valid) => {
+                if (valid) {
+                    if(this.dataForm.inventoryEntryInfos.length == 0){
+                        this.$message.error('请选择商品/物料!')
+                        return
+                    }else{
+                        if(this.id){
+                            updateDisassembly(this.dataForm).then(() => {
+                                this.$notify({
+                                    title: '成功',
+                                    message: '更新成功',
+                                    type: 'success',
+                                    duration: 2000
+                                })
+                                this.roBack();
+                            })
+                        }else{
+                            createDisassembly(this.dataForm).then(() => {
+                                this.$notify({
+                                    title: "成功",
+                                    message: "创建成功",
+                                    type: "success",
+                                    duration: 2000,
+                                });
+                                this.roBack();
+                            })
+                        }
+                    }   
+                }
+            });
+        },
+        handleChange(row) {
+            if (row.createPrice && row.updateNumber) {
+                row.sumPrice = row.createPrice * row.updateNumber
+            }
+        },
+        roBack() {
+            // const { callback } = this.$route.params
+            // if (typeof callback === 'function') callback()
+            this.$store.dispatch('delVisitedViews', this.$route).then((views) => {
+                const latestView = views.slice(-1)[0]
+                if (latestView) {
+                    this.$router.push(latestView.path)
+                } else {
+                    this.$router.push('/')
+                }
+            })
+            // this.$router.push({ name: 'disassembly' })
+        },
+        handleRemove(file, fileList) {
+        console.log(file, fileList);
+        let fileIds = [];
+        for (let i in fileList) {
+            let id = fileList[i].response.data.id;
+            fileIds.push(id);
+        }
+        this.dataForm.fileIds = fileIds.join(",");
+        },
+        beforeUploadFile(file) {
+        console.log(file);
+        const size = file.size / 1024 / 1024;
+        console.log(size);
+        if (size > 10) {
+            this.$message.error("文件大小不能超过10MB!");
+            return false;
+        }
+        },
+        handleFileSuccess(res, file, fileList) {
+        console.log(file, fileList);
+        console.log("------", "==========");
+        console.log("res = ", res);
+
+        let fileIds = [];
+        for (let i in fileList) {
+            let response = fileList[i].response;
+            if (response.errno && response.errno != "0") {
+            this.$message.error("该文件上传失败,已被移除,请重新上传!");
+            // 上传失败移除该 file 对象
+            fileList.splice(i, 1);
+            } else {
+            let id = fileList[i].response.data.id;
+            fileIds.push(id);
+            }
+        }
+        this.dataForm.fileIds = fileIds.join(",");
+        },
+    }
+}
+</script>
+<style>
+/** 底部步骤 */
+.footer {
+  width: 100%;
+  padding: 10px;
+  bottom: 0px;
+  text-align: center;
+  z-index: 999;
+}
+.mx {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+}
+/** 表格中输入框样式 */
+.tableFormItem {
+  width: 100%;
+  margin-bottom: 0;
+}
+</style>

+ 282 - 0
src/views/stock/stockCount/stockCount.vue

@@ -0,0 +1,282 @@
+<template>
+  <div class="app-container calendar-list-container">
+    <!-- 查询和其他操作 -->
+    <div class="filter-container">
+      <el-date-picker v-model="listQuery.startDate" value-format="yyyy-MM-dd" type="date" placeholder="开始日期"
+        style="width:200px">
+      </el-date-picker>
+      <el-date-picker v-model="listQuery.endDate" value-format="yyyy-MM-dd" type="date" placeholder="结束日期"
+        style="width:200px">
+      </el-date-picker>
+      <el-select v-model="listQuery.warehouseId" clearable placeholder="请选择仓库" class="filter-item" style="width: 200px">
+        <el-option :key="item.id" v-for="item in warehouseList" :label="item.warehouseName" :value="item.id">
+        </el-option>
+      </el-select>
+      <el-select v-model="listQuery.isRunFinish" clearable placeholder="请选择状态" class="filter-item" style="width: 200px">
+        <el-option :key="item.type" v-for="item in typeList" :label="item.name" :value="item.type">
+        </el-option>
+      </el-select>
+      <el-button class="filter-item" type="primary" v-waves icon="el-icon-search" @click="handleFilter">查找</el-button>
+      <el-button class="filter-item" v-waves icon="el-icon-refresh" @click="resetQuery">重置</el-button>
+      <el-button class="filter-item" type="primary" @click="handleCreate" icon="el-icon-plus">添加</el-button>
+      <!-- <el-button class="filter-item" :loading="downloadLoading" v-waves icon="el-icon-download"
+        @click="handleDownload">导出</el-button> -->
+      <!-- <el-button class="filter-item" type="success" icon="el-icon-takeaway-box" @click="executeAll">批量入库</el-button> -->
+      <el-button class="filter-item" type="warning" icon="el-icon-delete" @click="delAll">批量删除</el-button>
+    </div>
+
+    <!-- 查询结果 -->
+    <el-table size="small" :data="list" @selection-change="handleSelectionChange" v-loading="listLoading"
+      element-loading-text="正在查询中。。。" border fit highlight-current-row>
+      <el-table-column type="selection" width="55px"> </el-table-column>
+      <el-table-column type="index" label="序号" header-align="center" align="center">
+      </el-table-column>
+      <el-table-column align="center" min-width="150px" label="入库单号">
+        <template slot-scope="scope">
+          <router-link :to="{ name: 'stockCountDetail', params: { id: scope.row.id } }">
+            <div style="color: #337ab7;cursor: pointer;">{{ scope.row.serialCode }}</div>
+          </router-link>
+        </template>
+      </el-table-column>
+      <el-table-column align="center" min-width="100px" label="入库时间" prop="serialDate">
+      </el-table-column>
+      <el-table-column align="center" min-width="100px" label="供应商" prop="supplierName">
+      </el-table-column>
+      <el-table-column align="center" min-width="100px" label="仓库" prop="warehouseName">
+      </el-table-column>
+      <el-table-column align="center" min-width="100px" label="经手人" prop="addHandlerName">
+      </el-table-column>
+      <el-table-column align="center" min-width="100px" label="入库状态">
+        <template slot-scope="props">
+            <span v-if="props.row.isRunFinish == '0'" style="color: #67C23A;font-weight: bold;">已入库</span>
+            <span v-if="props.row.isRunFinish == '1'" style="color: #E6A23C;font-weight: bold;">待入库</span>
+          </template>
+      </el-table-column>
+      <el-table-column align="center" label="操作" width="240px" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button v-if="scope.row.isRunFinish == '1'" type="success" size="small" @click="handleExecute(scope.row)">入库</el-button>
+          <el-button type="primary" size="small" @click="handleUpdate(scope.row)">编辑</el-button>
+          <el-button type="danger" size="small" @click="handleDelete(scope.row)">删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <!-- 分页 -->
+    <div class="pagination-container">
+      <el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange"
+        :current-page="listQuery.page" :page-sizes="[10, 20, 30, 50]" :page-size="listQuery.limit"
+        layout="total, sizes, prev, pager, next, jumper" :total="total">
+      </el-pagination>
+    </div>
+  </div>
+</template>
+<script>
+import { listStockCount, deleteStockCount, executeStockCount } from "@/api/stockCount";
+import { warehouseList } from "@/api/warehouse";
+import waves from "@/directive/waves"; // 水波纹指令
+
+export default {
+  directives: { waves },
+  data() {
+    return {
+      downloadLoading: false,
+      warehouseList: [],
+      typeList: [
+        {
+          type: '0',
+          name: "已入库",
+        },
+        {
+          type: '1',
+          name: "待入库",
+        },
+      ],
+      list: [
+
+      ],
+      delarr: [],
+      multipleSelection: [],
+      total: 0,
+      listLoading: false,
+      listQuery: {
+        page: 1,
+        limit: 10,
+        startDate: '',
+        endDate: '',
+        warehouseId: '',
+        isRunFinish: '',
+      },
+    }
+  },
+  created() {
+    this.getStoreList();
+    this.getList();
+  },
+  methods: {
+    /** 获取仓库列表数据 */
+    getStoreList() {
+      warehouseList().then(response => {
+        this.warehouseList = response.data.data;
+      }).catch(() => { });
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.listQuery = {
+        page: 1,
+        limit: 10,
+        startDate: '',
+        endDate: '',
+        warehouseId: '',
+        isRunFinish: '',
+      },
+        this.getList()
+    },
+    handleDownload() {
+      this.downloadLoading = true
+      import('@/vendor/Export2Excel').then(excel => {
+        const tHeader = ['用户ID', '用户名称', '用户昵称', '用户头像']
+        const filterVal = ['id', 'username', 'nickname', 'avatar']
+        excel.export_json_to_excel2(tHeader, this.list, filterVal, '用户信息')
+        this.downloadLoading = false
+      })
+    },
+    handleCreate() {
+      this.$router.push({
+        name: 'stockCountAdd',
+        // params: { callback: this.getList }
+      })
+    },
+    getList() {
+      this.listLoading = true
+      listStockCount(this.listQuery).then(response => {
+        this.list = response.data.data.items
+        this.total = response.data.data.total
+        this.listLoading = false
+      }).catch(() => {
+        this.list = []
+        this.total = 0
+        this.listLoading = false
+      })
+    },
+
+    handleFilter() {
+      this.listQuery.page = 1
+      this.getList()
+    },
+
+    handleSizeChange(val) {
+      this.listQuery.limit = val
+      this.getList()
+    },
+
+    handleCurrentChange(val) {
+      this.listQuery.page = val
+      this.getList()
+    },
+
+    handleUpdate(row) {
+      this.$router.push({
+        name: 'stockCountEdit',
+        params: { id: row.id }
+      })
+    },
+    handleExecute(row) {
+      this.$confirm('确认入库吗?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        executeStockCount({ ids: row.id }).then(response => {
+          this.$notify({
+            title: '成功',
+            message: '入库成功',
+            type: 'success',
+            duration: 2000
+          })
+          this.getList()
+        })
+      }).catch(() => { })
+    },
+    executeAll() {
+      const length = this.multipleSelection.length;
+      if (length > 0) {
+        this.$confirm("确认入库吗?", "提示", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning",
+        }).then(() => {
+          for (let i = 0; i < length; i++) {
+            this.delarr.push(this.multipleSelection[i].id);
+          }
+          const ids = this.delarr.join(",");
+          executeStockCount({ ids: ids }).then(() => {
+            this.$notify({
+              title: "成功",
+              message: "入库成功",
+              type: "success",
+              duration: 2000,
+            });
+            this.getList();
+          })
+        })
+      } else {
+        this.$notify({
+          title: "提示",
+          message: "请选择要入库的信息!",
+          type: "warning",
+        });
+      }
+    },
+    handleDelete(row) {
+      this.$confirm('确认删除吗?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        deleteStockCount({ ids: row.id }).then(response => {
+          this.$notify({
+            title: '成功',
+            message: '删除成功',
+            type: 'success',
+            duration: 2000
+          })
+          this.getList()
+        })
+      }).catch(() => { })
+    },
+    delAll() {
+      const length = this.multipleSelection.length;
+      if (length > 0) {
+        this.$confirm("确认删除吗?", "提示", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning",
+        }).then(() => {
+          for (let i = 0; i < length; i++) {
+            this.delarr.push(this.multipleSelection[i].id);
+          }
+          const ids = this.delarr.join(",");
+          deleteStockCount({ ids: ids }).then(() => {
+            this.$notify({
+              title: "成功",
+              message: "删除成功",
+              type: "success",
+              duration: 2000,
+            });
+            this.getList();
+          })
+        })
+      } else {
+        this.$notify({
+          title: "提示",
+          message: "请选择要删除的信息!",
+          type: "warning",
+        });
+      }
+    },
+    handleSelectionChange(val) {
+      this.multipleSelection = val;
+    },
+  }
+}
+</script>

+ 335 - 0
src/views/stock/stockCount/stockCountAdd.vue

@@ -0,0 +1,335 @@
+<template>
+    <div class="app-container">
+        <el-form ref="dataForm" :model="dataForm" :rules="rules" label-width="120px" inline>
+            <h3>通用入库单</h3>
+            <!-- <el-form-item label="名称" prop="name">
+                <el-input v-model="dataForm.name" :minlength="2" :maxlength="20" clearable
+                    placeholder="请输入名称" style="width:200px" :disabled="type === 'detail'"></el-input>
+            </el-form-item> -->
+            <el-form-item label="入库时间" prop="serialDate">
+                <el-date-picker v-model="dataForm.serialDate" value-format="yyyy-MM-dd HH:mm:ss" type="datetime"
+                    placeholder="选择日期时间" style="width:200px" :disabled="type === 'detail'">
+                </el-date-picker>
+            </el-form-item>
+            <el-form-item label="供应商" prop="supplierId">
+                <el-select v-model="dataForm.supplierId" clearable placeholder="请选择" style="width: 200px;" :disabled="type === 'detail'">
+                    <el-option :key="item.id" v-for="item in supplierList" :label="item.businessName" :value="item.id">
+                    </el-option>
+                </el-select>
+            </el-form-item>
+            <el-form-item label="仓库" prop="warehouseId">
+                <el-select v-model="dataForm.warehouseId" clearable placeholder="请选择" style="width: 200px;" :disabled="type === 'detail'">
+                    <el-option :key="item.id" v-for="item in warehouseList" :label="item.warehouseName" :value="item.id">
+                    </el-option>
+                </el-select>
+            </el-form-item>
+            <el-form-item label="经手人" prop="addHandlerId">
+                <el-select v-model="dataForm.addHandlerId" clearable filterable placeholder="请选择" style="width: 200px" :disabled="type === 'detail'">
+                    <el-option :key="item.loginId" v-for="item in recipientsList" :label="item.deptName+'_'+item.userName" :value="item.loginId">
+                    </el-option>
+                </el-select>
+            </el-form-item>
+            
+
+            <!-- <el-form-item label="采购说明" prop="desc">
+                <el-input style="width:535px" v-model="dataForm.desc" :maxlength="120"
+                    type="textarea" :disabled="type === 'detail'" :autosize="{ minRows: 1, maxRows: 4 }"
+                    placeholder="请输入采购说明 最大120字"></el-input>
+            </el-form-item> -->
+            <el-form-item label="附件:" prop="fileIds">
+                <el-upload :limit="1" :action="fileUrl" :file-list="dataForm.fileList" :on-success="handleFileSuccess"
+                    :before-upload="beforeUploadFile" :on-remove="handleRemove">
+                    <el-button size="small" type="primary" :disabled="type === 'detail'">点击上传</el-button>
+                </el-upload>
+            </el-form-item>
+            <div class="mx">
+        <h3>入库明细</h3>
+        <el-button size="small" type="primary" v-if="type !== 'detail'"
+          @click="handleSelectGoods" icon="el-icon-plus">商品/物料</el-button>
+      </div>
+      <el-table size="small" :data="dataForm.inventoryEntryInfos" border :cell-style="{ textAlign: 'center' }"
+            :header-cell-style="{ textAlign: 'center' }" style="width: 100%">
+            <el-table-column label="商品编号">
+              <template slot-scope="scope">
+                {{ scope.row.productCode }}
+              </template>
+            </el-table-column>
+            <el-table-column label="商品名称">
+              <template slot-scope="scope">
+                {{ scope.row.productName }}
+              </template>
+            </el-table-column>
+            <el-table-column label="单价(¥)">
+              <template slot-scope="scope">
+                {{ scope.row.createPrice.toFixed(2) }}
+              </template>
+            </el-table-column>
+            <el-table-column label="库存数量">
+              <template slot-scope="scope">
+                {{ scope.row.createProductNumber }}
+              </template>
+            </el-table-column>
+            <el-table-column label="入库数量">
+              <template slot-scope="scope">
+                <el-form-item v-if="type !== 'detail'" :prop="'inventoryEntryInfos.'+scope.$index+'.updateNumber'" :rules="{ required: true, message: '入库数量不能为空', trigger: 'blur' }" class="tableFormItem">
+                    <el-input-number v-model="scope.row.updateNumber" @change="handleChange(scope.row)" size="small" :min="1" :max="10000" label="入库数量"></el-input-number>
+                </el-form-item>
+                <span v-else>{{ scope.row.updateNumber }}</span>
+              </template>
+            </el-table-column>
+            <el-table-column label="合计(¥)">
+              <template slot-scope="scope">
+                {{ scope.row.sumPrice.toFixed(2) }}
+              </template>
+            </el-table-column>
+            <!-- <el-table-column label="备注">
+              <template slot-scope="scope">
+                <el-input :maxlength="99" v-model="scope.row.remark" :disabled="type === 'detail'" />
+              </template>
+            </el-table-column> -->
+            <el-table-column label="操作" width="150" v-if="type !== 'detail'">
+              <template slot-scope="scope">
+                <el-button size="mini" type="danger"
+                  @click="dataForm.inventoryEntryInfos.splice(scope.$index, 1)">删除</el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+        </el-form>
+        <div class="footer">
+            <el-button type="primary" @click="submitForm" v-if="type !== 'detail'">保存
+            </el-button>
+            <el-button @click="roBack()">返回
+            </el-button>
+        </div>
+    </div>
+</template>
+<script>
+import { createStockCount, updateStockCount, readStockCount } from "@/api/stockCount";
+import { supplierList } from "@/api/supplier";
+import { warehouseList } from "@/api/warehouse";
+import { allUserList } from "@/api/public";
+import waves from "@/directive/waves"; // 水波纹指令
+
+export default {
+    directives: { waves },
+    data() {
+        return {
+            fileUrl:this.upLoadUrl,
+            recipientsList:[],
+            supplierList: [],
+            warehouseList: [],
+            id: '',
+            type: '',
+            /** 表单*/
+            dataForm: {
+                serialDate:'',
+                supplierId:undefined,
+                warehouseId:undefined,
+                addHandlerId:undefined,
+                fileIds:undefined,
+                fileList: [],
+                inventoryEntryInfos: []
+            },
+            rules: {
+                serialDate: [
+                    { required: true, message: '请选择入库时间', trigger: 'blur' }
+                ],
+                warehouseId: [
+                    { required: true, message: '请选择仓库', trigger: 'blur' }
+                ],
+                addHandlerId: [
+                    { required: true, message: '请选择经手人', trigger: 'blur' }
+                ],
+            },
+        }
+    },
+    watch: {
+        $route: {
+            immediate: true,
+            handler(newVal) {
+                if (this.$route.name === 'stockCountAdd') {
+                    this.dataForm = {
+                        serialDate:undefined,
+                        supplierId:undefined,
+                        warehouseId:undefined,
+                        addHandlerId:undefined,
+                        fileIds:undefined,
+                        fileList: [],
+                        inventoryEntryInfos: []
+                    }
+                } else if (this.$route.name === 'stockCountDetail') {
+                    this.type = 'detail'
+                }
+                if (this.$route.params.id) {
+                    this.id = this.$route.params.id
+                    this.getDataFormDetail()
+                }
+            }
+        }
+    },
+    mounted() {
+        this.getSupplierList();
+        this.getStoreList(); 
+        this.getAllUserList(); 
+    },
+    methods: {
+        /** 获取供应商列表数据 */
+        getSupplierList(){
+            supplierList().then(response => {
+                this.supplierList = response.data.data;
+            }).catch(() => { });
+        },
+        /** 获取仓库列表数据 */
+        getStoreList() {
+            warehouseList().then(response => {
+                this.warehouseList = response.data.data;
+            }).catch(() => {});
+        },
+        /** 获取人员列表数据 */
+        getAllUserList() {
+            allUserList().then(response => {
+                this.recipientsList = response.data.data;
+            }).catch(() => { });
+        },
+        /** 获取详情页面数据 */
+        getDataFormDetail() {
+            readStockCount({ id: this.id }).then(response => {
+                let dataForm = response.data.data;
+                dataForm.inventoryEntryInfos = dataForm.inventoryEntryInfos == null ? [] : dataForm.inventoryEntryInfos
+                dataForm.inventoryOutInfos = dataForm.inventoryOutInfos == null ? [] : dataForm.inventoryOutInfos
+                this.dataForm = dataForm;
+            }).catch(() => {})
+        },
+         // 选择商品
+        async handleSelectGoods() {
+            if (!this.dataForm.warehouseId) {
+                this.$message.error('请先选择仓库!')
+                return
+            }else{
+                console.log(this.dataForm.inventoryEntryInfos)
+                let selectedIds = this.dataForm.inventoryEntryInfos.map(item => item.id);
+                const Goods = await this.$EnPickerGoods({
+                    // goodsApi: '/warehouse-entry/info/inventory',
+                    selectedIds: selectedIds,
+                    goodsApiParams: { warehouseId: this.dataForm.warehouseId }
+                })
+                if (!Goods.length) return
+                const inventoryEntryInfos = Goods.map(item => {
+                    item.updateNumber = 1
+                    item.sumPrice = item.createPrice * 1
+                    return item
+                })
+                this.dataForm.inventoryEntryInfos = this.dataForm.inventoryEntryInfos && this.dataForm.inventoryEntryInfos.length ? this.dataForm.inventoryEntryInfos.concat(inventoryEntryInfos) : this.dataForm.inventoryEntryInfos = inventoryEntryInfos
+            }
+            
+        },
+        submitForm(){
+            this.$refs["dataForm"].validate((valid) => {
+                if (valid) {
+                    if(this.dataForm.inventoryEntryInfos.length == 0){
+                        this.$message.error('请选择商品/物料!')
+                        return
+                    }else{
+                        if(this.id){
+                            updateStockCount(this.dataForm).then(() => {
+                                this.$notify({
+                                    title: '成功',
+                                    message: '更新成功',
+                                    type: 'success',
+                                    duration: 2000
+                                })
+                                this.roBack();
+                            })
+                        }else{
+                            createStockCount(this.dataForm).then(() => {
+                                this.$notify({
+                                    title: "成功",
+                                    message: "创建成功",
+                                    type: "success",
+                                    duration: 2000,
+                                });
+                                this.roBack();
+                            })
+                        }
+                    }   
+                }
+            });
+        },
+        handleChange(row) {
+            if (row.createPrice && row.updateNumber) {
+                row.sumPrice = row.createPrice * row.updateNumber
+            }
+        },
+        roBack() {
+            // const { callback } = this.$route.params
+            // if (typeof callback === 'function') callback()
+            this.$store.dispatch('delVisitedViews', this.$route).then((views) => {
+                const latestView = views.slice(-1)[0]
+                if (latestView) {
+                    this.$router.push(latestView.path)
+                } else {
+                    this.$router.push('/')
+                }
+            })
+            // this.$router.push({ name: 'stockCount' })
+        },
+        handleRemove(file, fileList) {
+        console.log(file, fileList);
+        let fileIds = [];
+        for (let i in fileList) {
+            let id = fileList[i].response.data.id;
+            fileIds.push(id);
+        }
+        this.dataForm.fileIds = fileIds.join(",");
+        },
+        beforeUploadFile(file) {
+        console.log(file);
+        const size = file.size / 1024 / 1024;
+        console.log(size);
+        if (size > 10) {
+            this.$message.error("文件大小不能超过10MB!");
+            return false;
+        }
+        },
+        handleFileSuccess(res, file, fileList) {
+        console.log(file, fileList);
+        console.log("------", "==========");
+        console.log("res = ", res);
+
+        let fileIds = [];
+        for (let i in fileList) {
+            let response = fileList[i].response;
+            if (response.errno && response.errno != "0") {
+            this.$message.error("该文件上传失败,已被移除,请重新上传!");
+            // 上传失败移除该 file 对象
+            fileList.splice(i, 1);
+            } else {
+            let id = fileList[i].response.data.id;
+            fileIds.push(id);
+            }
+        }
+        this.dataForm.fileIds = fileIds.join(",");
+        },
+    }
+}
+</script>
+<style>
+/** 底部步骤 */
+.footer {
+  width: 100%;
+  padding: 10px;
+  bottom: 0px;
+  text-align: center;
+  z-index: 999;
+}
+.mx {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+}
+/** 表格中输入框样式 */
+.tableFormItem {
+  width: 100%;
+  margin-bottom: 0;
+}
+</style>