Browse Source

feat(mallOrder): 新增额外包裹支持多包裹和类型选择

重构新增额外包裹弹窗,支持补寄和分包发货类型,并允许多个包裹录入
- 将组件通信改为事件驱动,通过父组件打开弹窗
- 新增包裹类型选择(补寄/分包发货)
- 支持添加多个包裹,每个包裹包含运单号和快递公司
- 添加状态校验,仅订单状态≥3时显示新增按钮
- 集成后端API提交数据,添加加载状态
ylong 1 tháng trước cách đây
mục cha
commit
89b89a6a1c

+ 102 - 28
src/views/mallOrder/all/components/add-package-dialog.vue

@@ -3,28 +3,50 @@
         :width="600"
         v-model="visible"
         title="新增额外包裹"
-        @open="handleOpen"
+        @closed="handleClosed"
         :body-style="{ padding: '20px' }"
     >
-        <el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
-            <el-form-item label="物流公司" prop="company">
-                <el-select v-model="form.company" placeholder="请选择物流公司" style="width: 100%">
-                    <el-option label="顺丰速运" value="shunfeng" />
-                    <el-option label="圆通速递" value="yuantong" />
-                    <el-option label="中通快递" value="zhongtong" />
-                    <el-option label="韵达快递" value="yunda" />
-                </el-select>
+        <el-form ref="formRef" :model="form" label-width="110px">
+            <el-form-item label="订单编号">
+                <el-input :model-value="orderData.orderId" disabled />
             </el-form-item>
-            <el-form-item label="快递单号" prop="no">
-                <el-input v-model="form.no" placeholder="请输入快递单号" />
+            <el-form-item label="发货运单号">
+                <span class="text-gray-700">{{ orderData.waybillCode || '-' }}</span>
             </el-form-item>
-            <el-form-item label="包裹备注" prop="remark">
-                <el-input v-model="form.remark" type="textarea" placeholder="请输入包裹备注" />
+            <el-form-item label="额外包裹类型" prop="type" :rules="[{ required: true, message: '请选择额外包裹类型' }]">
+                <el-radio-group v-model="form.type">
+                    <el-radio :label="1">补寄</el-radio>
+                    <el-radio :label="2">分包发货</el-radio>
+                </el-radio-group>
             </el-form-item>
+
+            <div class="package-list-container bg-gray-50 p-4 rounded mt-4">
+                <div v-for="(pkg, index) in form.expressList" :key="index" class="package-item relative mb-4 p-3 border border-gray-200 bg-white rounded">
+                    <el-button v-if="form.expressList.length > 1" type="danger" link class="absolute right-2 top-2 z-10" @click="removePackage(index)">删除</el-button>
+                    
+                    <el-form-item :label="`额外运单号`" :prop="`expressList.${index}.waybillCode`" :rules="[{ required: true, message: '请输入额外运单号' }]" class="mb-4 mt-2">
+                        <el-input v-model="pkg.waybillCode" placeholder="请输入物流单号" clearable />
+                    </el-form-item>
+                    
+                    <el-form-item :label="`快递公司`" :prop="`expressList.${index}.expressName`" :rules="[{ required: true, message: '请选择快递公司' }]" class="mb-0">
+                        <dict-data code="shop_order_express_name" v-model="pkg.expressName" type="select" placeholder="请选择快递公司" class="w-full" />
+                    </el-form-item>
+                </div>
+
+                <div class="text-right mt-2">
+                    <el-button type="success" plain @click="addPackage">添加多个包裹</el-button>
+                </div>
+            </div>
+
         </el-form>
         <template #footer>
-            <el-button @click="visible = false">取消</el-button>
-            <el-button type="primary" @click="handleSubmit">确定</el-button>
+            <div class="flex justify-between items-center w-full">
+                <div class="text-green-500 text-sm">额外运单号添加后不支持修改,请仔细核对</div>
+                <div>
+                    <el-button @click="visible = false">取消</el-button>
+                    <el-button type="primary" @click="handleSubmit" :loading="loading">确认</el-button>
+                </div>
+            </div>
         </template>
     </ele-modal>
 </template>
@@ -32,37 +54,89 @@
 <script setup>
 import { ref, reactive } from 'vue';
 import { EleMessage } from 'ele-admin-plus/es';
+import request from '@/utils/request';
 
 const visible = defineModel({ type: Boolean });
 const formRef = ref(null);
+const loading = ref(false);
+const orderData = ref({});
 
 const form = reactive({
-    company: '',
-    no: '',
-    remark: ''
+    type: 1,
+    expressList: [
+        { waybillCode: '', expressName: '' }
+    ]
 });
 
-const rules = {
-    company: [{ required: true, message: '请选择物流公司', trigger: 'change' }],
-    no: [{ required: true, message: '请输入快递单号', trigger: 'blur' }]
+const handleOpen = (order) => {
+    orderData.value = order || {};
+    visible.value = true;
+};
+
+const handleClosed = () => {
+    if (formRef.value) {
+        formRef.value.resetFields();
+    }
+    form.type = 1;
+    form.expressList = [{ waybillCode: '', expressName: '' }];
+    orderData.value = {};
+};
+
+const addPackage = () => {
+    form.expressList.push({ waybillCode: '', expressName: '' });
 };
 
-const handleOpen = () => {
-    form.company = '';
-    form.no = '';
-    form.remark = '';
+const removePackage = (index) => {
+    form.expressList.splice(index, 1);
 };
 
 const handleSubmit = () => {
     formRef.value.validate((valid) => {
         if (valid) {
-            EleMessage.success('添加成功');
-            visible.value = false;
+            loading.value = true;
+            request.post('/shop/shopOrder/addExpress', {
+                orderId: orderData.value.orderId,
+                type: form.type,
+                expressList: form.expressList.map(pkg => ({
+                    expressName: pkg.expressName,
+                    waybillCode: pkg.waybillCode
+                }))
+            }).then(res => {
+                if (res.data.code === 200) {
+                    EleMessage.success('添加成功');
+                    visible.value = false;
+                } else {
+                    EleMessage.error(res.data.msg || '添加失败');
+                }
+            }).catch(e => {
+                console.error(e);
+                EleMessage.error('网络错误');
+            }).finally(() => {
+                loading.value = false;
+            });
         }
     });
 };
 
 defineExpose({
-    handleOpen: () => { visible.value = true; }
+    handleOpen
 });
 </script>
+
+<style scoped>
+.bg-gray-50 {
+    background-color: #f9fafc;
+}
+.border-gray-200 {
+    border-color: #ebeef5;
+}
+.text-gray-700 {
+    color: #606266;
+}
+.text-green-500 {
+    color: #67c23a;
+}
+.w-full {
+    width: 100%;
+}
+</style>

+ 1 - 1
src/views/mallOrder/all/components/order-base-info.vue

@@ -94,7 +94,7 @@
                         </el-popover>
                     </div>
 
-                    <div class="action-area mt-2">
+                    <div class="action-area mt-2" v-if="detail.status >= 3">
                         <el-button type="success" @click="$emit('add-package')">新增额外包裹 <el-icon class="el-icon--right">
                                 <Lightning />
                             </el-icon></el-button>

+ 2 - 2
src/views/mallOrder/all/components/order-detail.vue

@@ -63,7 +63,7 @@ const visible = defineModel({ type: Boolean });
 const detail = ref({});
 const loading = ref(false);
 
-const emit = defineEmits(['push-sms', 'refund']);
+const emit = defineEmits(['push-sms', 'refund', 'add-package']);
 
 const [shop_order_status] = useDictData(['shop_order_status']);
 
@@ -103,7 +103,7 @@ const onOpen = () => {
 };
 
 const openAddPackage = () => {
-    packageRef.value?.open(detail.value);
+    emit('add-package', detail.value);
 };
 
 const handleEditReceiver = () => {

+ 5 - 1
src/views/mallOrder/all/index.vue

@@ -28,7 +28,7 @@
         </ele-card>
 
         <!-- Dialogs -->
-        <order-detail ref="detailRef" @push-sms="openSms" @refund="openRefund" />
+        <order-detail ref="detailRef" @push-sms="openSms" @refund="openRefund" @add-package="openAddPackage" />
         <push-sms-dialog ref="smsRef" />
         <refund-dialog ref="refundRef" @success="fetchData" />
         <add-package-dialog ref="packageRef" />
@@ -132,6 +132,10 @@
         refundRef.value?.handleOpen(row);
     };
 
+    const openAddPackage = (row) => {
+        packageRef.value?.handleOpen(row);
+    };
+
     const openLog = (row) => {
         logRef.value?.handleOpen(row.orderId);
     };