From 1224419c9e640b398f2711a6799eb38b1d9bc578 Mon Sep 17 00:00:00 2001
From: dzq <dzq@ys.com>
Date: Wed, 18 Jun 2025 15:12:51 +0800
Subject: [PATCH] =?UTF-8?q?feat(approval):=20=E6=B7=BB=E5=8A=A0=E5=AE=A1?=
 =?UTF-8?q?=E6=89=B9=E8=AF=A6=E6=83=85=E6=8E=A5=E5=8F=A3=E5=92=8C=E5=BC=80?=
 =?UTF-8?q?=E6=9F=9C=E4=B8=AD=E7=8A=B6=E6=80=81=E5=A4=84=E7=90=86?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

- 新增审批详情接口getApprovalDetailAssetApi
- 添加开柜中状态(4)到状态映射和类型定义
- 重构审批处理页面,支持分步操作和状态判断
- 添加数量确定功能allocateApprovalGoods
- 优化审批流程,支持开柜中状态下的操作
---
 src/common/apis/approval/index.ts  |  34 ++++-
 src/common/apis/approval/type.ts   |   7 +-
 src/pages/approval/handleApply.vue | 205 ++++++++++++++++++-----------
 src/pages/approvalAsset/list.vue   |   3 +-
 4 files changed, 166 insertions(+), 83 deletions(-)

diff --git a/src/common/apis/approval/index.ts b/src/common/apis/approval/index.ts
index a7c63eb..3271ef1 100644
--- a/src/common/apis/approval/index.ts
+++ b/src/common/apis/approval/index.ts
@@ -1,5 +1,5 @@
 import { request } from '@/http/axios'
-import { SubmitApprovalRequestData, SubmitApprovalResponseData, SearchApiReturnApprovalQuery, ApiResponsePageData, ReturnApprovalEntity, HandleApprovalRequestData, SearchReturnApprovalAssetQuery, ReturnApprovalAssetDTO, HandleApprovalAssetRequestData, ApprovalGoodsCellEntity } from './type'
+import { SubmitApprovalRequestData, SubmitApprovalResponseData, SearchApiReturnApprovalQuery, ApiResponsePageData, ReturnApprovalEntity, HandleApprovalRequestData, SearchReturnApprovalAssetQuery, ReturnApprovalAssetDTO, HandleApprovalAssetRequestData, ApprovalGoodsCellEntity, ReturnApprovalDetailDTO } from './type'
 import { OpenCabinetApiData, ShopOrderGoodsEntity } from '../shop/type'
 
 export const getApprovalListApi = (params: SearchApiReturnApprovalQuery) => {
@@ -50,7 +50,7 @@ export const handleApprovalApi = (data: HandleApprovalRequestData) => {
 }
 
 
-export const handleApprovalAssetApi = (data: HandleApprovalAssetRequestData) => {
+export const handleApprovalAssetApi = (data: HandleApprovalRequestData) => {
   return request<ApiResponseMsgData<string>>({
     url: 'approval/handle/asset',
     method: 'post',
@@ -58,6 +58,14 @@ export const handleApprovalAssetApi = (data: HandleApprovalAssetRequestData) =>
   })
 }
 
+export const allocateApprovalGoods = (data: HandleApprovalAssetRequestData) => {
+  return request<ApiResponseMsgData<string>>({
+    url: 'approval/handle/allocateApprovalGoods',
+    method: 'post',
+    data
+  })
+}
+
 export const getApprovalOrderGoodsApi = (approvalId: number) => {
   return request<ApiResponseMsgData<ShopOrderGoodsEntity[]>>({
     url: 'approval/getApprovalOrderGoods',
@@ -67,11 +75,23 @@ export const getApprovalOrderGoodsApi = (approvalId: number) => {
 }
 
 export const getApprovalGoodsCellApi = (approvalId: number) => {
-  return request<ApiResponseMsgData<ApprovalGoodsCellEntity[]>>({
-    url: 'approval/getApprovalGoodsCell',
-    method: 'get',
-    params: { approvalId }
-  })
+  return request<ApiResponseMsgData<ApprovalGoodsCellEntity[]>>(
+    {
+      url: 'approval/getApprovalGoodsCell',
+      method: 'get',
+      params: { approvalId }
+    }
+  )
+}
+
+export const getApprovalDetailAssetApi = (approvalId: number) => {
+  return request<ApiResponseMsgData<ReturnApprovalDetailDTO>>(
+    {
+      url: 'approval/detail/asset',
+      method: 'get',
+      params: { approval_id: approvalId }
+    }
+  )
 }
 
 /** 打开储物柜接口 */
diff --git a/src/common/apis/approval/type.ts b/src/common/apis/approval/type.ts
index 8ea159e..983976d 100644
--- a/src/common/apis/approval/type.ts
+++ b/src/common/apis/approval/type.ts
@@ -94,7 +94,7 @@ export interface ReturnApprovalEntity {
   auditRemark: string
   /** 审批人姓名 */
   auditName: string
-  /** 审批状态(1待审核 2已通过 3已驳回) */
+  /** 审批状态(1待审核 2已通过 3已驳回 4开柜中) */
   status: number
   /** 审批时间 */
   approvalTime?: string
@@ -134,6 +134,11 @@ export interface ReturnApprovalAssetDTO extends ReturnApprovalEntity {
   goodsList?: ApprovalGoodsEntity[];
 }
 
+export interface ReturnApprovalDetailDTO extends ReturnApprovalAssetDTO {
+  statusStr: string;
+  approvalGoodsCellList?: ApprovalGoodsCellEntity[];
+}
+
 export interface SearchReturnApprovalAssetQuery {
   pageNum: number;
   pageSize: number;
diff --git a/src/pages/approval/handleApply.vue b/src/pages/approval/handleApply.vue
index 54a4bb4..1167172 100644
--- a/src/pages/approval/handleApply.vue
+++ b/src/pages/approval/handleApply.vue
@@ -2,14 +2,15 @@
 import { ref, onMounted, computed } from 'vue'
 import { showConfirmDialog, showDialog, UploaderFileListItem, Popup, Picker, Field, Stepper } from 'vant'
 import axios from "axios"
-import { getApprovalGoodsCellApi, handleApprovalApi, handleApprovalAssetApi, openCabinetApi } from '@/common/apis/approval'
-import type { ApprovalGoodsCellEntity, ApprovalGoodsEntity, HandleApprovalAssetRequestData, HandleApprovalRequestData } from '@/common/apis/approval/type'
+import { allocateApprovalGoods, getApprovalGoodsCellApi, handleApprovalApi, handleApprovalAssetApi, openCabinetApi } from '@/common/apis/approval'
+import type { ApprovalGoodsCellEntity, ApprovalGoodsEntity, HandleApprovalAssetRequestData, HandleApprovalRequestData, ReturnApprovalDetailDTO } from '@/common/apis/approval/type'
 import { useRoute, useRouter } from 'vue-router'
 import { useApprovalStore } from '@/pinia/stores/approval'
 import { useWxStore } from '@/pinia/stores/wx';
+import { getApprovalDetailAssetApi } from '@/common/apis/approval';
 import Compressor from 'compressorjs';
-import { useAb98UserStore } from '@/pinia/stores/ab98-user'
-import { ShopOrderGoodsEntity } from '@/common/apis/shop/type'
+import { useAb98UserStore } from '@/pinia/stores/ab98-user';
+import { ShopOrderGoodsEntity } from '@/common/apis/shop/type';
 
 const { VITE_APP_BASE_API } = import.meta.env;
 const router = useRouter()
@@ -20,6 +21,8 @@ const { openid, balance, corpidLogin, userid: qyUserid, name: qyName } = storeTo
 const ab98UserStore = useAb98UserStore();
 const { tel, userid: ab98Userid, name } = storeToRefs(ab98UserStore);
 
+
+const detailData = ref<ReturnApprovalDetailDTO>();
 const formData = ref<HandleApprovalAssetRequestData>({
     approvalId: approvalStore.currentApproval?.approvalId || 0,
     status: 2,
@@ -61,9 +64,9 @@ const validateForm = () => {
         showConfirmDialog({ title: '提示', message: '驳回时必须填写审核说明' })
         return false
     }
-    
+
     // 验证审批数量
-    if (approvalStore.currentApproval?.status === 1) {
+    if (detailData.value?.status === 1) {
         for (const item of orderGoods.value) {
             if (item.approvalQuantity != null && item.approvalQuantity < 0) {
                 showConfirmDialog({ title: '提示', message: `商品${item.goodsName}的审批数量不能为负数` })
@@ -104,51 +107,53 @@ const previewImage = (url: string) => {
 const approvalGoodsCells = ref<ApprovalGoodsCellEntity[]>([]);
 
 const approvalGoodsCellsWithNames = computed(() => {
-  return approvalGoodsCells.value.map(cell => {
-    const goods = orderGoods.value.find(g => g.approvalGoodsId === cell.approvalGoodsId);
-    return {
-      ...cell,
-      goodsName: goods ? goods.goodsName : ''
-    };
-  });
+    return approvalGoodsCells.value.map(cell => {
+        const goods = orderGoods.value.find(g => g.approvalGoodsId === cell.approvalGoodsId);
+        return {
+            ...cell,
+            goodsName: goods ? goods.goodsName : ''
+        };
+    });
 });
 
-onMounted(async () => {
-    if (!approvalStore.currentApproval) {
+const fetchApprovalDetail = async () => {
+    const approvalId = approvalStore.currentApproval?.approvalId
+    if (!approvalId) {
         router.push('/approvalAsset/list');
         return;
     }
 
-    // 初始化订单商品数据,添加approvalQuantity字段
-    orderGoods.value = (approvalStore.currentApproval.goodsList || []).map(item => ({
-        ...item,
-        approvalQuantity: approvalStore.currentApproval?.status === 1 ? item.applyQuantity : item.approvalQuantity
-    }));
+    try {
+        const result = await getApprovalDetailAssetApi(approvalId);
+        if (result.code === 0) {
+            detailData.value = result.data;
+            orderGoods.value = (result.data.goodsList || []).map(item => ({
+                ...item,
+                approvalQuantity: result.data.status === 1 ? item.applyQuantity : item.approvalQuantity
+            }));
 
-    if (approvalStore.currentApproval.status !== 1) {
-        // 填充历史审批数据
-        formData.value = {
-            ...formData.value,
-            corpid: wxStore.corpid,
-            status: approvalStore.currentApproval.status,
-            returnAmount: approvalStore.currentApproval.returnAmount,
-            auditRemark: approvalStore.currentApproval.auditRemark,
-            auditImages: approvalStore.currentApproval.auditImages
-        };
-
-        // 获取已审批商品格口信息
-        try {
-            const result = await getApprovalGoodsCellApi(approvalStore.currentApproval.approvalId);
-            if (result.code === 0) {
-                approvalGoodsCells.value = result.data;
-            } else {
-                showDialog({ title: '错误', message: result.msg || '获取审批商品格口信息失败' });
+            if (result.data.status !== 1) {
+                formData.value = {
+                    ...formData.value,
+                    corpid: wxStore.corpid,
+                    status: result.data.status,
+                    returnAmount: result.data.returnAmount,
+                    auditRemark: result.data.auditRemark,
+                    auditImages: result.data.auditImages
+                };
+                approvalGoodsCells.value = result.data.approvalGoodsCellList || [];
             }
-        } catch (error) {
-            console.error('获取审批商品格口信息失败:', error);
-            showDialog({ title: '错误', message: '获取审批商品格口信息失败' });
+        } else {
+            showDialog({ title: '错误', message: result.msg || '获取审批详情失败' });
         }
+    } catch (error) {
+        console.error('获取审批详情失败:', error);
+        showDialog({ title: '错误', message: '获取审批详情失败' });
     }
+}
+
+onMounted(async () => {
+    await fetchApprovalDetail();
 })
 
 const handleOpenCell = async (approvalGoodsCellId: number) => {
@@ -186,21 +191,6 @@ const handleOpenCell = async (approvalGoodsCellId: number) => {
 const handleSubmit = async () => {
     if (!validateForm()) return
 
-    // 构建approvalGoodsList
-    formData.value.approvalGoodsList = orderGoods.value.map(item => ({
-        approvalGoodsId: item.approvalGoodsId || 0,
-        approvalId: formData.value.approvalId,
-        goodsId: item.goodsId,
-        goodsName: item.goodsName,
-        externalGoodsId: item.externalGoodsId,
-        corpid: item.corpid,
-        belongType: item.belongType,
-        price: item.price,
-        applyQuantity: item.applyQuantity,
-        approvalQuantity: item.approvalQuantity,
-        coverImg: item.coverImg
-    }))
-
     submitting.value = true
     try {
         formData.value.userid = wxStore.userid;
@@ -239,6 +229,53 @@ const handleComfirm = () => {
     handleSubmit();
 }
 
+const handleAllocateQuantity = async () => {
+    if (!validateForm()) return
+
+    // 构建approvalGoodsList
+    formData.value.approvalGoodsList = orderGoods.value.map(item => ({
+        approvalGoodsId: item.approvalGoodsId || 0,
+        approvalId: formData.value.approvalId,
+        goodsId: item.goodsId,
+        goodsName: item.goodsName,
+        externalGoodsId: item.externalGoodsId,
+        corpid: item.corpid,
+        belongType: item.belongType,
+        price: item.price,
+        applyQuantity: item.applyQuantity,
+        approvalQuantity: item.approvalQuantity,
+        coverImg: item.coverImg
+    }))
+
+    submitting.value = true
+    try {
+        formData.value.userid = wxStore.userid;
+        formData.value.corpid = wxStore.corpid;
+        formData.value.auditUserid = wxStore.userid;
+
+        const { code, msg } = await allocateApprovalGoods(formData.value)
+
+        if (code === 0) {
+            showDialog({ message: '数量确定成功' })
+            await fetchApprovalDetail();
+        } else {
+            console.error('操作失败code:', code, 'msg:', msg)
+            showConfirmDialog({
+                title: '操作失败',
+                message: msg || '数量确定失败'
+            })
+        }
+    } catch (error) {
+        console.error('提交失败:', error)
+        showConfirmDialog({
+            title: '提交失败',
+            message: error instanceof Error ? error.message : '网络请求异常'
+        })
+    } finally {
+        submitting.value = false
+    }
+}
+
 const handleReject = () => {
     formData.value.status = 3;
     handleSubmit();
@@ -252,9 +289,8 @@ const handleReject = () => {
 
         <div class="content-wrapper">
             <van-cell-group>
-                <van-cell title="申请人" :value="approvalStore.currentApproval?.applyUserName" />
-                <van-cell title="当前状态" :value="statusMap[approvalStore.currentApproval?.status || 1]" />
-                <!-- <van-cell title="领用说明" :value="approvalStore.currentApproval?.applyRemark" /> -->
+                <van-cell title="申请人" :value="detailData?.applyUserName" />
+                <van-cell title="当前状态" :value="statusMap[detailData?.status || 1]" />
             </van-cell-group>
 
             <van-cell-group class="product-list">
@@ -277,26 +313,27 @@ const handleReject = () => {
                                 </span>
                             </div>
                             <!-- 审批数量输入框 -->
-                            <div v-if="approvalStore.currentApproval?.status === 1" class="approval-quantity">
+                            <div v-if="detailData?.status === 1" class="approval-quantity">
                                 <span class="label">审批数量:</span>
-                                <van-stepper
-                                    v-model.number="item.approvalQuantity"
-                                    :min="0"
-                                    :max="item.applyQuantity"
-                                    integer
-                                    style="width: 180px;"
-                                />
+                                <van-stepper v-model.number="item.approvalQuantity" :min="0" :max="item.applyQuantity"
+                                    integer style="width: 180px;" />
                             </div>
                             <!-- 查看审批数量 -->
-                            <div v-if="approvalStore.currentApproval?.status === 2" class="approval-quantity-view">
+                            <div v-if="detailData?.status === 2 || detailData?.status === 4"
+                                class="approval-quantity-view">
                                 <span class="label">审批数量:</span>
                                 <span class="value">{{ item.approvalQuantity }}</span>
                             </div>
                         </div>
                     </van-cell>
                 </template>
+                <div class="confirm-quantity-container">
+                    <van-button class="confirm-quantity-btn" v-if="detailData?.status === 1" type="primary"
+                        @click="handleAllocateQuantity" :loading="submitting" plain hairline size="small">
+                        确定审批数量
+                    </van-button>
+                </div>
             </van-cell-group>
-            
             <van-cell-group class="approval-goods-list" v-if="approvalGoodsCells.length > 0">
                 <van-cell title="审批通过商品:" class="section-title" />
                 <template v-for="item in approvalGoodsCellsWithNames" :key="item.approvalGoodsCellId">
@@ -314,8 +351,9 @@ const handleReject = () => {
                             <div class="van-ellipsis">
                                 分配数量:{{ item.allocateQuantity }}
                             </div>
-                            <div class="open-cell-btn">
-                                <van-button type="primary" size="small" @click="handleOpenCell(item.approvalGoodsCellId)" :disabled="isButtonDisabled">
+                            <div v-if="detailData?.status === 4" class="open-cell-btn">
+                                <van-button type="primary" size="small"
+                                    @click="handleOpenCell(item.approvalGoodsCellId)" :disabled="isButtonDisabled">
                                     打开格口
                                 </van-button>
                             </div>
@@ -341,12 +379,13 @@ const handleReject = () => {
                 </div>
             </van-popup>
 
-            <div class="btn-group" v-if="approvalStore.currentApproval?.status === 1">
+            <div class="btn-group" v-if="detailData?.status === 1 || detailData?.status === 4">
                 <van-button type="danger" :loading="submitting" loading-text="提交中..." @click="handleReject"
                     style="flex: 1; height: 44px; border-radius: 8px; font-size: 16px;">
                     拒绝
                 </van-button>
-                <van-button type="primary" :loading="submitting" loading-text="提交中..." @click="handleComfirm"
+                <van-button type="primary" :disabled="detailData?.status === 1" :loading="submitting"
+                    loading-text="提交中..." @click="handleComfirm"
                     style="flex: 1; height: 44px; border-radius: 8px; font-size: 16px;">
                     同意
                 </van-button>
@@ -411,6 +450,7 @@ const handleReject = () => {
 .approval-quantity-view {
     justify-content: flex-end;
 }
+
 .price-row {
     display: flex;
     justify-content: space-between;
@@ -465,6 +505,23 @@ const handleReject = () => {
     padding: 16px;
 }
 
+.confirm-quantity-container {
+    display: flex;
+    justify-content: flex-end;
+    margin-top: 8px;
+}
+
+.confirm-quantity-btn {
+    margin-bottom: 8px;
+    margin-right: 8px;
+    height: 36px;
+    width: 140px;
+    border-radius: 8px;
+    font-size: 16px;
+    padding: 0 20px;
+}
+
+
 .content-wrapper {
     padding-bottom: 100px;
 }
@@ -490,4 +547,4 @@ const handleReject = () => {
     background-color: #ebedf0;
     box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
 }
-</style>
\ No newline at end of file
+</style>
diff --git a/src/pages/approvalAsset/list.vue b/src/pages/approvalAsset/list.vue
index 55a5699..f893318 100644
--- a/src/pages/approvalAsset/list.vue
+++ b/src/pages/approvalAsset/list.vue
@@ -79,7 +79,8 @@ const statusOptions = [
 const statusMap: { [key: number]: string } = {
     1: '待审核',
     2: '已通过',
-    3: '已驳回'
+    3: '已驳回',
+    4: '开柜中'
 }
 
 const statusText = ref('')