Bläddra i källkod

优化门店采购逻辑

大大的豆芽 2 månader sedan
förälder
incheckning
22f7efaf9d

+ 2 - 2
admin-ui/src/api/core/sku.js

@@ -59,11 +59,11 @@ export function updateSkuStatus(id,status) {
 
 
 // 查询物料明细列表
-export function purchaseListSku(id) {
+export function purchaseListSku(params) {
   return request({
     url: '/mapi/core/sku/purchase/list',
     method: 'get',
-    params: { "id": id }
+    params: params
   })
 }
 

+ 204 - 116
admin-ui/src/views/systemSet/purchaseGoods/index.vue

@@ -58,103 +58,156 @@
         </Page>
 
         <!--新增-->
-        <el-dialog :title="title" :visible.sync="open" size="70%" append-to-body>
-            <el-card>
-                <el-row :gutter="20">
-                    <el-col :span="4">
-                        <div class="list_title">{{ titleType }}</div>
-                        <div class="head-container-two">
-                            <el-tree :data="categoryList" :props="defaultProps" :expand-on-click-node="false" node-key="id" default-expand-all highlight-current @node-click="handleNodeClick" />
+        <el-dialog :title="title" :visible.sync="open" size="80%" append-to-body>
+            <el-card class="purchase-dialog">
+                <el-row :gutter="20" class="purchase-container">
+                    <!-- 左侧分类选择区域 -->
+                    <el-col :span="4" class="category-section">
+                        <div class="section-title">{{ titleType }}</div>
+                        <div class="category-tree">
+                            <el-tree 
+                                :data="categoryList" 
+                                :props="defaultProps" 
+                                :expand-on-click-node="false" 
+                                node-key="id" 
+                                default-expand-all 
+                                highlight-current 
+                                @node-click="handleNodeClick" 
+                            />
                         </div>
                     </el-col>
-                    <el-col :span="20">
-                        <div class="head-column1">
-                            <el-table :data="addGoodsList">
-                                <el-table-column label="编号" align="center" prop="goodsSkuStoreId" />
-                                <el-table-column label="材料名称" align="center" prop="goodsName" />
-                                <el-table-column label="材料规格" align="center">
+
+                    <!-- 右侧内容区域 -->
+                    <el-col :span="20" class="content-section">
+                        <!-- 上半区:已采购商品列表 -->
+                        <div class="purchased-section">
+                            <div class="section-title">已采购商品</div>
+                            <el-table :data="addGoodsList" border stripe>
+                                <!-- <el-table-column label="编号" align="center" prop="goodsSkuStoreId" width="100" /> -->
+                                <el-table-column label="商品名称" align="center" prop="goodsName" min-width="200" />
+                                <el-table-column label="商品规格" align="center" min-width="150">
                                     <template slot-scope="scope">
-                                        <div v-for="spec in scope.row.specVoList" :key="spec.id" style="height: 20px">
-                                            <p style="text-align: center; margin-top: 1px">{{ spec.specName }}:{{ spec.specValue }}</p>
-                                        </div>
+                                        {{formatSpec(scope.row.specValLists)}}
                                     </template>
                                 </el-table-column>
-                                <el-table-column label="数量" align="center">
+                                <el-table-column label="数量" align="center" width="120">
                                     <template slot-scope="scope">
-                                        <el-input v-if="scope.row.goodsSkuStoreId == vo.goodsSkuStoreId" v-for="vo in purchaseCountVOList" :key="vo.goodsSkuStoreId" v-model="vo.count" :step="1" :min="1" :max="getMaxCount(scope.row)" @change="countPrice" />
+                                        <el-input 
+                                            v-if="scope.row.goodsSkuStoreId == vo.goodsSkuStoreId" 
+                                            v-for="vo in purchaseCountVOList" 
+                                            :key="vo.goodsSkuStoreId" 
+                                            v-model="vo.count" 
+                                            :step="1" 
+                                            :min="1" 
+                                            :max="getMaxCount(scope.row)" 
+                                            @change="countPrice" 
+                                        />
                                     </template>
                                 </el-table-column>
-                                <el-table-column label="价格" align="center" prop="purchasePrice" />
-                                <!--            <el-table-column label="库存" align="center" prop="stock" />-->
-                                <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+                                <el-table-column label="价格" align="center" prop="purchasePrice" width="100" />
+                                <el-table-column label="操作" align="center" width="100" fixed="right">
                                     <template slot-scope="scope">
-                                        <el-button type="text" icon="el-icon-delete-solid" @click="deleteGoods(scope.row)">删除</el-button>
+                                        <el-button type="text" icon="el-icon-delete" @click="deleteGoods(scope.row)">删除</el-button>
                                     </template>
                                 </el-table-column>
                             </el-table>
                         </div>
-                    </el-col>
-                    <el-col :span="20">
-                        <div class="head-column1" style="margin-top: 20px">
-                            <el-table v-loading="loading" fit highlight-current-row border stripe :data="goodsList">
-                                <el-table-column label="编号" align="center" prop="goodsSkuStoreId" />
-                                <el-table-column label="材料名称" align="center" prop="goodsName" />
-                                <el-table-column label="材料规格" align="center">
+
+                        <!-- 下半区:商品列表 -->
+                        <div class="goods-section">
+                            <div class="section-title">商品列表</div>
+                            <el-form :inline="true" :model="goodsQueryParams" class="search-form">
+                                <el-form-item label="搜索商品">
+                                    <el-input 
+                                        v-model="goodsQueryParams.keywords" 
+                                        placeholder="请输入商品名称或条码" 
+                                        clearable 
+                                        @keyup.enter.native="getGoodsList" 
+                                    />
+                                </el-form-item>
+                                <el-form-item>
+                                    <el-button type="primary" @click="getGoodsList">搜索</el-button>
+                                    <el-button @click="resetGoodsQuery">重置</el-button>
+                                </el-form-item>
+                            </el-form>
+                            <el-table 
+                                v-loading="loading" 
+                                :data="goodsList" 
+                                border 
+                                stripe 
+                                highlight-current-row
+                            >
+                                <!-- <el-table-column label="编号" align="center" prop="goodsSkuStoreId" width="100" /> -->
+                                <el-table-column label="商品名称" align="center" prop="goodsName" min-width="200" />
+                                <el-table-column label="商品规格" align="center" min-width="150">
                                     <template slot-scope="scope">
-                                        <div v-for="spec in scope.row.specVoList" :key="spec.id" style="height: 20px">
-                                            <p style="text-align: center; margin-top: 1px">{{ spec.specName }}:{{ spec.specValue }}</p>
-                                        </div>
+                                        {{formatSpec(scope.row.specValLists)}}
                                     </template>
                                 </el-table-column>
-                                <el-table-column label="价格" align="center" prop="purchasePrice" />
-                                <el-table-column label="库存" align="center" prop="stock">
+                                <el-table-column label="价格" align="center" prop="purchasePrice" width="100" />
+                                <el-table-column label="库存" align="center" width="120">
                                     <template slot-scope="scope">
                                         <span :class="{'low-stock': scope.row.stock <= 5}">{{ scope.row.stock }}</span>
                                         <el-tag v-if="scope.row.stock <= 5" size="mini" type="warning">库存不足</el-tag>
                                     </template>
                                 </el-table-column>
-                                <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+                                <el-table-column label="操作" align="center" width="100" fixed="right">
                                     <template slot-scope="scope">
                                         <el-button 
                                             type="text" 
-                                            icon="el-icon-s-shop" 
+                                            icon="el-icon-plus" 
                                             @click="addGoods(scope.row)"
-                                            :disabled="scope.row.stock <= 0"
                                         >
                                             添加
                                         </el-button>
                                     </template>
                                 </el-table-column>
                             </el-table>
+                            <pagination 
+                                v-show="goodsTotal > 0" 
+                                :total="goodsTotal" 
+                                :page.sync="goodsQueryParams.pageNum" 
+                                :limit.sync="goodsQueryParams.pageSize" 
+                                @pagination="getGoodsList" 
+                            />
                         </div>
                     </el-col>
                 </el-row>
-                <el-row :gutter="10" class="box-shadow" style="margin-top: 10px">
+
+                <!-- 底部结算区域 -->
+                <el-row :gutter="10" class="settlement-section">
                     <el-col :span="3">
-                        <el-form label-width="100px" style="height: 100px; padding-top: 40px; text-align: right" :inline="true" size="small">
+                        <el-form label-width="100px" :inline="true" size="small">
                             <el-form-item v-if="goodsType == '1' && userInfoVO.userType != '00'">
                                 <el-checkbox v-model="isUserBalance">是否使用余额</el-checkbox>
                             </el-form-item>
                         </el-form>
                     </el-col>
-                    <el-col :span="18">
-                        <el-form label-width="135px" style="height: 100px; padding-top: 40px; text-align: right" :inline="true" size="small">
-                            <el-form-item label-width="100px" label="总件数:" prop="totalClothNum">
-                                <span style="color: #ff4949">{{ calculateTotalCount }}</span>
+                    <el-col :span="17">
+                        <el-form label-width="135px" :inline="true" size="small">
+                            <el-form-item label="总件数:" prop="totalClothNum">
+                                <span class="price-text">{{ calculateTotalCount }}</span>
                             </el-form-item>
                             <el-form-item label="总金额(元):" prop="totalPrice">
-                                <span style="color: #ff4949">{{ calculateTotalPrice }}</span>
+                                <span class="price-text">{{ calculateTotalPrice }}</span>
                             </el-form-item>
                             <el-form-item label="抵扣金额(元): " v-if="isUserBalance == true">
-                                <span style="color: #ff4949">{{ getNowBalance }}</span>
+                                <span class="price-text">{{ getNowBalance }}</span>
                             </el-form-item>
-                            <el-form-item label-width="155px" label="还需支付金额(元): " v-if="isUserBalance == true">
-                                <span style="color: #ff4949">{{ getNeedPayPrice }}</span>
+                            <el-form-item label="还需支付金额(元): " v-if="isUserBalance == true">
+                                <span class="price-text">{{ getNeedPayPrice }}</span>
                             </el-form-item>
                         </el-form>
                     </el-col>
-                    <el-col :span="3">
-                        <el-button type="primary" style="width: 50%; height: 40px; margin-top: 30px; text-align: center" icon="el-icon-shopping-cart-2" size="small" @click="submitForm">提交</el-button>
+                    <el-col :span="4">
+                        <el-button 
+                            type="primary" 
+                            icon="el-icon-shopping-cart-2" 
+                            size="small" 
+                            @click="submitForm"
+                        >
+                            提交
+                        </el-button>
                     </el-col>
                 </el-row>
             </el-card>
@@ -284,6 +337,15 @@ export default {
             isUserBalance: false,
             orgName: '',
             stockWarningThreshold: 5, // 库存预警阈值
+            // 商品列表分页参数
+            goodsQueryParams: {
+                pageNum: 1,
+                pageSize: 10,
+                categoryId: null,
+                keywords: undefined
+            },
+            // 商品总数
+            goodsTotal: 0,
         }
     },
     created() {
@@ -295,11 +357,12 @@ export default {
         calculateTotalCount() {
             this.totalCount = 0
             this.addGoodsList.forEach((vo) => {
-                let number = this.purchaseCountVOList.find((item) => item.goodsSkuStoreId == vo.goodsSkuStoreId).count
-                this.totalCount = this.totalCount + number
+                let number = Number(this.purchaseCountVOList.find((item) => item.goodsSkuStoreId == vo.goodsSkuStoreId).count);
+                this.totalCount = this.totalCount + number;
             })
             return this.totalCount
         },
+
         calculateTotalPrice() {
             this.totalPrice = 0
             this.addGoodsList.forEach((vo) => {
@@ -340,6 +403,11 @@ export default {
                 this.orgName = '门店名称'
             }
         },
+                    // 格式化规格信息
+    formatSpec(specList) {
+      if (!specList || !specList.length) return '默认规格';
+      return specList.join(' ');
+    },
         getCategoryList() {
             listCategory({ ...this.queryParams, ...{ goodsType: this.goodsType } }).then((response2) => {
                 this.categoryList = response2.rows
@@ -356,12 +424,6 @@ export default {
         addGoods(row) {
             // 非总部进货
             if (this.userInfoVO.userType != '00') {
-                // 判断上级库存
-                if (row.stock <= 0) {
-                    this.$message.warning('库存不足,无法添加');
-                    return;
-                }
-                
                 // 如果已添加集合数量大于0,需要判断当前添加的是否在已添加集合中
                 if (this.addGoodsList.length > 0) {
                     let match = this.addGoodsList.findIndex(item => item.goodsSkuStoreId == row.goodsSkuStoreId);
@@ -438,11 +500,14 @@ export default {
             this.loading = true
             if (this.goodsCategoryId == null) {
                 this.goodsList = []
+                this.goodsTotal = 0
                 this.loading = false
                 return
             }
-            purchaseListSku(this.goodsCategoryId).then((response) => {
-                this.goodsList = response.data
+            this.goodsQueryParams.categoryId = this.goodsCategoryId
+            purchaseListSku(this.goodsQueryParams).then((response) => {
+                this.goodsList = response.rows
+                this.goodsTotal = response.total
                 this.loading = false
             })
         },
@@ -577,85 +642,108 @@ export default {
                     this.$modal.msgError(error.message || '提交失败');
                 });
             }).catch(() => {});
+        },
+        resetGoodsQuery() {
+            this.goodsQueryParams.keywords = undefined;
+            this.getGoodsList();
         }
     }
 }
 </script>
 <style lang="scss" scoped>
-.low-stock {
-  color: #e6a23c;
-  font-weight: bold;
-}
+.purchase-dialog {
+  .purchase-container {
+    min-height: 600px;
+  }
 
-.el-table {
-  .el-button--text {
-    &.is-disabled {
-      color: #c0c4cc;
-      cursor: not-allowed;
+  .category-section {
+    border-right: 1px solid #EBEEF5;
+    height: 100%;
+    
+    .section-title {
+      font-size: 16px;
+      font-weight: bold;
+      margin-bottom: 15px;
+      padding: 0 10px;
+    }
+
+    .category-tree {
+      height: calc(100% - 40px);
+      overflow-y: auto;
     }
   }
-}
 
-.stock-warning {
-  background-color: #fdf6ec;
-  color: #e6a23c;
-  padding: 5px 10px;
-  border-radius: 4px;
-  margin-top: 10px;
-  
-  .warning-title {
+  .content-section {
+    display: flex;
+    flex-direction: column;
+    gap: 20px;
+  }
+
+  .section-title {
+    font-size: 16px;
     font-weight: bold;
-    margin-bottom: 5px;
+    margin-bottom: 15px;
   }
-  
-  .warning-list {
-    display: flex;
-    flex-wrap: wrap;
-    gap: 10px;
-    
-    .warning-item {
-      background: #fff;
-      padding: 5px 10px;
-      border-radius: 4px;
-      border: 1px solid #e6a23c;
-    }
+
+  .purchased-section,
+  .goods-section {
+    background: #fff;
+    border-radius: 4px;
+    padding: 15px;
   }
-}
 
-// 优化表格样式
-.el-table {
-  th {
-    background-color: #f5f7fa;
-    color: #606266;
-    font-weight: 500;
+  .search-form {
+    margin-bottom: 15px;
   }
-  
-  td {
-    padding: 8px 0;
+
+  .settlement-section {
+    margin-top: 20px;
+    padding-top: 20px;
+    border-top: 1px solid #EBEEF5;
   }
-}
 
-// 优化按钮样式
-.el-button--text {
-  padding: 0 5px;
-  
-  &:hover {
-    color: #409EFF;
+  .price-text {
+    color: #ff4949;
+    font-weight: bold;
+  }
+
+  .low-stock {
+    color: #e6a23c;
+    font-weight: bold;
   }
-  
-  &.is-disabled {
-    color: #c0c4cc;
-    cursor: not-allowed;
+
+  .el-table {
+    th {
+      background-color: #f5f7fa;
+      color: #606266;
+      font-weight: 500;
+    }
+    
+    td {
+      padding: 8px 0;
+    }
+  }
+
+  .el-button--text {
+    padding: 0 5px;
     
     &:hover {
+      color: #409EFF;
+    }
+    
+    &.is-disabled {
       color: #c0c4cc;
+      cursor: not-allowed;
+      
+      &:hover {
+        color: #c0c4cc;
+      }
     }
   }
-}
 
-// 优化标签样式
-.el-tag {
-  margin-left: 5px;
-  vertical-align: middle;
+  .el-tag {
+    margin-left: 5px;
+    vertical-align: middle;
+  }
 }
 </style>

+ 4 - 3
yiqi-admin/src/main/java/com/yiqi/admin/controller/core/GoodsSkuController.java

@@ -125,9 +125,10 @@ public class GoodsSkuController extends BaseController {
      */
     @GetMapping("/purchase/list")
     @ApiOperation(value = "查询材料申请物料列表")
-    public R<List<GoodsSkuQueryVO>> purchaseList(@RequestParam("id") Long goodsCategoryId) {
-        List<GoodsSkuQueryVO> list = goodsSkuService.getGoodsSkuPurchaseList(goodsCategoryId);
-        return R.ok(list);
+    public TableDataInfo purchaseList(@RequestParam("categoryId") Long categoryId, @RequestParam(value = "keywords", required = false) String keywords) {
+        startPage();
+        List<GoodsSkuQueryVO> list = goodsSkuService.getGoodsSkuPurchaseList(categoryId, keywords);
+        return getDataTable(list);
     }
 
     /**

+ 5 - 0
yiqi-common/src/main/java/com/yiqi/core/domain/dto/GoodsSkuDTO.java

@@ -40,5 +40,10 @@ public class GoodsSkuDTO {
     @ApiModelProperty("来源类型")
     private String sourceType;
 
+    /**
+     * 关键词
+     */
+    private String keywords;
+
     private List<Long> goodsIdList;
 }

+ 1 - 1
yiqi-common/src/main/java/com/yiqi/core/service/IGoodsSkuService.java

@@ -70,7 +70,7 @@ public interface IGoodsSkuService extends IService<GoodsSku> {
      * @param goodsCategoryId 商品分类id
      * @return 结果
      */
-    public List<GoodsSkuQueryVO> getGoodsSkuPurchaseList(Long goodsCategoryId);
+    public List<GoodsSkuQueryVO> getGoodsSkuPurchaseList(Long goodsCategoryId, String keywords);
 
     /**
      * 零售商品列表

+ 14 - 11
yiqi-core/src/main/java/com/yiqi/core/service/impl/GoodsSkuServiceImpl.java

@@ -324,30 +324,32 @@ public class GoodsSkuServiceImpl extends ServiceImpl<GoodsSkuMapper, GoodsSku> i
     }
 
     @Override
-    public List<GoodsSkuQueryVO> getGoodsSkuPurchaseList(Long goodsCategoryId) {
+    public List<GoodsSkuQueryVO> getGoodsSkuPurchaseList(Long goodsCategoryId, String keywords) {
         SysUser user = SecurityUtils.getLoginUser().getUser();
 
-        List<Long> goodsIdList = goodsInfoService.list(new QueryWrapper<GoodsInfo>().lambda()
-                .eq(GoodsInfo::getGoodsCategoryId, goodsCategoryId)
-                .eq(GoodsInfo::getDelFlag, DeleteStatus.OK.getCode())
-                .eq(GoodsInfo::getStatus, StatusType.OK.getCode())).stream().map(GoodsInfo::getId).collect(Collectors.toList());
+//        List<Long> goodsIdList = goodsInfoService.list(new QueryWrapper<GoodsInfo>().lambda()
+//                .eq(GoodsInfo::getGoodsCategoryId, goodsCategoryId)
+//                .eq(GoodsInfo::getDelFlag, DeleteStatus.OK.getCode())
+//                .eq(GoodsInfo::getStatus, StatusType.OK.getCode())).stream().map(GoodsInfo::getId).collect(Collectors.toList());
         List<GoodsSkuQueryVO> SkuQueryVOS = null;
-        if (CollUtil.isEmpty(goodsIdList)) {
-            return new ArrayList<>();
-        }
+//        if (CollUtil.isEmpty(goodsIdList)) {
+//            return new ArrayList<>();
+//        }
 
         // 总部
         if (SourceType.MANAGER.getCode().equals(user.getUserType())) {
             GoodsSkuDTO goodsSkuDTO = new GoodsSkuDTO();
             goodsSkuDTO.setSourceType(user.getUserType());
-            goodsSkuDTO.setGoodsIdList(goodsIdList);
+            goodsSkuDTO.setKeywords(keywords);
+//            goodsSkuDTO.setGoodsIdList(goodsIdList);
             SkuQueryVOS = baseMapper.selectPurchaseGoodsSkuInfoByHq(goodsSkuDTO);
         }
 
         // 工厂
         if (SourceType.FACTORY.getCode().equals(user.getUserType())) {
             GoodsSkuDTO goodsSkuDTO = new GoodsSkuDTO();
-            goodsSkuDTO.setGoodsIdList(goodsIdList);
+//            goodsSkuDTO.setGoodsIdList(goodsIdList);
+            goodsSkuDTO.setKeywords(keywords);
             SkuQueryVOS = baseMapper.selectPurchaseGoodsSkuInfoByFactory(goodsSkuDTO);
         }
         // 门店
@@ -355,7 +357,8 @@ public class GoodsSkuServiceImpl extends ServiceImpl<GoodsSkuMapper, GoodsSku> i
             GoodsSkuDTO goodsSkuDTO = new GoodsSkuDTO();
             goodsSkuDTO.setSourceType(user.getUserType());
             goodsSkuDTO.setTargetId(user.getStoreId());
-            goodsSkuDTO.setGoodsIdList(goodsIdList);
+            goodsSkuDTO.setKeywords(keywords);
+//            goodsSkuDTO.setGoodsIdList(goodsIdList);
             SkuQueryVOS = baseMapper.selectPurchaseGoodsSkuInfoByStore(goodsSkuDTO);
         }
         if (CollUtil.isEmpty(SkuQueryVOS)) {

+ 8 - 3
yiqi-core/src/main/resources/mapper/core/GoodsSkuMapper.xml

@@ -216,7 +216,9 @@
                 #{item}
             </foreach>
         </if>
-
+        <if test="keywords != null and keywords != ''">
+            and (e.goods_name like concat('%', #{keywords}, '%') or e.goods_code like concat('%', #{keywords}, '%') )
+        </if>
     </select>
 
     <select id="selectPurchaseGoodsSkuInfoByFactory" resultType="com.yiqi.core.domain.vo.GoodsSkuQueryVO">
@@ -236,9 +238,9 @@
     </select>
 
     <select id="selectPurchaseGoodsSkuInfoByStore" resultType="com.yiqi.core.domain.vo.GoodsSkuQueryVO">
-        select a.id as id, a.goods_id as goodsId, a.status as status,
+        select a.id as id, a.goods_id as goodsId, a.status as status, a.specs,
         e.goods_name as goodsName, c.id as goodsSkuStoreId,
-        c.wholesale_price as purchasePrice, c.stock as stock
+        a.wholesale_price as purchasePrice, COALESCE(c.stock, 0) as stock
         from goods_sku a
         left join goods_info e on e.id = a.goods_id
         left join goods_sku_store c on c.goods_sku_id = a.id and c.source_type = '02' and c.target_id = #{storeId}
@@ -249,6 +251,9 @@
                 #{item}
             </foreach>
         </if>
+        <if test="keywords != null and keywords != ''">
+            and (e.goods_name like concat('%', #{keywords}, '%') or e.goods_code like concat('%', #{keywords}, '%') )
+        </if>
     </select>