hurx 3 週間 前
コミット
8ddb90f511

+ 50 - 55
src/views/bill/statementInvoice/addInvoiceDialog.vue

@@ -52,29 +52,22 @@
 
       <el-row :gutter="20">
         <el-col :span="24">
-          <el-form-item label="发票附件" prop="invoiceAttachment">
-            <el-button type="primary" size="small" @click="handleOpenFileSelector">
-              <el-icon><Upload /></el-icon>
-              点击上传
-            </el-button>
-            <div style="color: #999; font-size: 12px; margin-top: 5px">支持jpg/png/xlsx等文件</div>
-          </el-form-item>
-        </el-col>
-      </el-row>
-
-      <!-- 附件列表 -->
-      <el-row :gutter="20" v-if="fileList.length > 0">
-        <el-col :span="24">
-          <el-table :data="fileList" border style="width: 100%; margin-top: 10px">
-            <el-table-column type="index" label="序号" width="60" align="center" />
-            <el-table-column prop="name" label="附件名称" min-width="200" align="center" />
-            <el-table-column label="操作" width="150" align="center">
-              <template #default="scope">
-                <el-button link type="primary" size="small" @click="handlePreviewFile(scope.row)">预览</el-button>
-                <el-button link type="danger" size="small" @click="handleRemoveFile(scope.$index)">删除</el-button>
+          <el-form-item label="发票附件" prop="invoiceAnnex">
+            <el-upload
+              :action="uploadAction"
+              :on-success="handleUploadSuccess"
+              :before-upload="beforeUpload"
+              :on-remove="handleRemoveUploadFile"
+              :on-preview="handlePreviewUploadFile"
+              :file-list="fileList"
+              multiple
+            >
+              <el-button type="primary" icon="Upload">点击上传</el-button>
+              <template #tip>
+                <div class="el-upload__tip">支持jpg/png/xlsx等文件,单个文件不超过50MB</div>
               </template>
-            </el-table-column>
-          </el-table>
+            </el-upload>
+          </el-form-item>
         </el-col>
       </el-row>
     </el-form>
@@ -86,15 +79,9 @@
       </div>
     </template>
   </el-dialog>
-
-  <!-- 文件选择器 -->
-  <FileSelector v-model="fileSelectorVisible" :multiple="true" :allowed-types="[1, 2, 3, 4, 5]" title="选择发票附件" @confirm="handleFileSelected" />
 </template>
 
 <script setup name="AddInvoiceDialog" lang="ts">
-import { Upload } from '@element-plus/icons-vue';
-import FileSelector from '@/components/FileSelector/index.vue';
-
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const { invoice_type } = toRefs<any>(proxy?.useDict('invoice_type'));
 interface InvoiceForm {
@@ -104,7 +91,7 @@ interface InvoiceForm {
   invoiceAmount?: number;
   invoiceDate?: string;
   remark?: string;
-  invoiceAttachment?: string;
+  invoiceAnnex?: string;
 }
 
 const initFormData: InvoiceForm = {
@@ -114,14 +101,14 @@ const initFormData: InvoiceForm = {
   invoiceAmount: undefined,
   remark: undefined,
   invoiceDate: undefined,
-  invoiceAttachment: undefined
+  invoiceAnnex: undefined
 };
 
 const formRef = ref<ElFormInstance>();
 const buttonLoading = ref(false);
 const form = ref<InvoiceForm>({ ...initFormData });
 const fileList = ref<any[]>([]);
-const fileSelectorVisible = ref(false);
+const uploadAction = import.meta.env.VITE_APP_BASE_API + '/resource/oss/upload';
 
 const dialog = reactive<DialogOption>({
   visible: false,
@@ -152,14 +139,15 @@ const open = (data?: InvoiceForm) => {
     Object.assign(form.value, data);
 
     // 解析附件地址并回显附件列表
-    if (data.invoiceAttachment) {
-      const urls = data.invoiceAttachment.split(',').filter((url) => url.trim());
+    if (data.invoiceAnnex) {
+      const urls = data.invoiceAnnex.split(',').filter((url) => url.trim());
       fileList.value = urls.map((url, index) => {
         const fileName = url.split('/').pop() || `附件${index + 1}`;
         return {
           name: fileName,
           url: url.trim(),
-          id: undefined
+          uid: Date.now() + index,
+          status: 'success'
         };
       });
     }
@@ -175,39 +163,46 @@ const reset = () => {
   formRef.value?.clearValidate();
 };
 
-/** 打开文件选择器 */
-const handleOpenFileSelector = () => {
-  fileSelectorVisible.value = true;
+/** 上传前校验 */
+const beforeUpload = (file: any) => {
+  const isLt50M = file.size / 1024 / 1024 < 50;
+  if (!isLt50M) {
+    proxy?.$modal.msgWarning('上传文件大小不能超过 50MB!');
+  }
+  return isLt50M;
 };
 
-/** 文件选择完成 */
-const handleFileSelected = (files: any[]) => {
-  if (files && files.length > 0) {
-    files.forEach((file) => {
-      fileList.value.push({
-        name: file.fileName || file.name,
-        url: file.fileUrl || file.url,
-        id: file.id
-      });
+/** 上传成功回调 */
+const handleUploadSuccess = (response: any, uploadFile: any) => {
+  if (response.code === 200) {
+    uploadFile.url = response.data.url;
+    nextTick(() => {
+      form.value.invoiceAnnex = fileList.value
+        .map((f) => f.url)
+        .filter(Boolean)
+        .join(',');
     });
-    form.value.invoiceAttachment = fileList.value.map((f) => f.url || f.name).join(',');
+    proxy?.$modal.msgSuccess('上传成功');
+  } else {
+    proxy?.$modal.msgError(response.msg || '上传失败');
   }
-  fileSelectorVisible.value = false;
 };
 
 /** 删除文件 */
-const handleRemoveFile = (index: number) => {
-  fileList.value.splice(index, 1);
-  form.value.invoiceAttachment = fileList.value.map((f) => f.url || f.name).join(',');
+const handleRemoveUploadFile = (uploadFile: any) => {
+  form.value.invoiceAnnex = fileList.value
+    .map((f) => f.url)
+    .filter(Boolean)
+    .join(',');
 };
 
 /** 预览文件 */
-const handlePreviewFile = (file: any) => {
-  if (!file.url) {
+const handlePreviewUploadFile = (uploadFile: any) => {
+  if (uploadFile.url) {
+    window.open(uploadFile.url, '_blank');
+  } else {
     proxy?.$modal.msgWarning('文件地址不存在');
-    return;
   }
-  window.open(file.url, '_blank');
 };
 
 /** 提交表单 */

+ 43 - 39
src/views/bill/statementOrder/addDrawer.vue

@@ -173,9 +173,16 @@
           <span style="color: #409eff; font-weight: 600">对账附件</span>
         </el-divider>
 
-        <div style="margin-bottom: 10px">
-          <el-button type="primary" icon="Upload" @click="handleOpenFileSelector">点击上传</el-button>
-        </div>
+        <el-upload
+          :action="uploadAction"
+          :on-success="handleUploadSuccess"
+          :before-upload="beforeUpload"
+          :show-file-list="false"
+          multiple
+          style="margin-bottom: 10px"
+        >
+          <el-button type="primary" icon="Upload">点击上传</el-button>
+        </el-upload>
 
         <el-table :data="fileList" border style="width: 100%; margin-bottom: 20px">
           <el-table-column type="index" label="序号" width="80" align="center" />
@@ -185,10 +192,11 @@
               {{ scope.row.url || '暂无地址' }}
             </template>
           </el-table-column>
-          <el-table-column label="操作" width="200" align="center">
+          <el-table-column label="操作" width="250" align="center">
             <template #default="scope">
               <el-button type="primary" link @click="handleDownloadFile(scope.row)">下载</el-button>
               <el-button type="primary" link @click="handlePreviewFile(scope.row)">预览</el-button>
+              <el-button type="danger" link @click="handleRemoveFile(scope.$index)">删除</el-button>
             </template>
           </el-table-column>
         </el-table>
@@ -209,9 +217,6 @@
 
   <!-- 客户订单抽屉 -->
   <OrderMainDrawer ref="orderMainDrawerRef" @success="handleOrderSelected" />
-
-  <!-- 文件选择器 -->
-  <FileSelector v-model="fileSelectorVisible" :multiple="true" :allowed-types="[1, 2, 3, 4, 5]" title="选择对账附件" @confirm="handleFileSelected" />
 </template>
 
 <script setup name="AddDrawer" lang="ts">
@@ -226,7 +231,6 @@ import { OrderDeliverVO } from '@/api/order/orderDeliver/types';
 import { listComStaff } from '@/api/company/comStaff';
 import { ComStaffVO, ComStaffQuery } from '@/api/company/comStaff/types';
 import OrderMainDrawer from './orderMainDrawer.vue';
-import FileSelector from '@/components/FileSelector/index.vue';
 import { getCustomerDeliverOrders } from '@/api/order/orderDeliver';
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@@ -298,8 +302,7 @@ const customerLoading = ref(false);
 const customerOptions = ref<CustomerInfoVO[]>([]);
 const staffOptions = ref<ComStaffVO[]>([]);
 const orderMainDrawerRef = ref<any>();
-const fileSelectorRef = ref<any>();
-const fileSelectorVisible = ref(false);
+const uploadAction = import.meta.env.VITE_APP_BASE_API + '/resource/oss/upload';
 const currentSelectedOrders = ref<OrderDeliverVO[]>([]);
 const preloadedOrders = ref<OrderDeliverVO[]>([]); // 预加载的订单列表
 
@@ -542,41 +545,42 @@ const handleProductCurrentChange = (val: number) => {
   productPage.pageNum = val;
 };
 
-/** 文件上传改变 */
-const handleFileChange = (file: any, uploadFileList: any[]) => {
-  // 更新文件列表
-  fileList.value = uploadFileList;
-  // 更新表单中的附件地址
-  form.value.annexAddress = uploadFileList.map((f) => f.name).join(',');
+/** 上传前校验 */
+const beforeUpload = (file: any) => {
+  const isLt50M = file.size / 1024 / 1024 < 50;
+  if (!isLt50M) {
+    proxy?.$modal.msgWarning('上传文件大小不能超过 50MB!');
+  }
+  return isLt50M;
+};
+
+/** 上传成功回调 */
+const handleUploadSuccess = (response: any, file: any) => {
+  if (response.code === 200) {
+    fileList.value.push({
+      name: file.name,
+      url: response.data.url,
+      id: undefined
+    });
+    // 更新表单中的附件地址
+    form.value.annexAddress = fileList.value
+      .map((f) => f.url)
+      .filter(Boolean)
+      .join(',');
+    proxy?.$modal.msgSuccess('上传成功');
+  } else {
+    proxy?.$modal.msgError(response.msg || '上传失败');
+  }
 };
 
 /** 删除文件 */
 const handleRemoveFile = (index: number) => {
   fileList.value.splice(index, 1);
   // 更新表单中的附件地址
-  form.value.annexAddress = fileList.value.map((f) => f.name).join(',');
-};
-
-/** 打开文件选择器 */
-const handleOpenFileSelector = () => {
-  fileSelectorVisible.value = true;
-};
-
-/** 处理文件选择完成 */
-const handleFileSelected = (files: any[]) => {
-  if (files && files.length > 0) {
-    // 将选中的文件添加到文件列表
-    files.forEach((file) => {
-      fileList.value.push({
-        name: file.fileName || file.name,
-        url: file.fileUrl || file.url,
-        id: file.id
-      });
-    });
-    // 更新表单中的附件地址
-    form.value.annexAddress = fileList.value.map((f) => f.url || f.name).join(',');
-  }
-  fileSelectorVisible.value = false;
+  form.value.annexAddress = fileList.value
+    .map((f) => f.url)
+    .filter(Boolean)
+    .join(',');
 };
 
 /** 下载文件 */

+ 9 - 2
src/views/order/saleOrder/index.vue

@@ -25,7 +25,14 @@
             </el-form-item>
 
             <el-form-item label="提交时间" prop="orderTime">
-              <el-date-picker v-model="dateRange" type="daterange" value-format="YYYY-MM-DD"  range-separator="至" start-placeholder="开始时间" end-placeholder="结束时间" />
+              <el-date-picker
+                v-model="dateRange"
+                type="daterange"
+                value-format="YYYY-MM-DD"
+                range-separator="至"
+                start-placeholder="开始时间"
+                end-placeholder="结束时间"
+              />
             </el-form-item>
 
             <el-form-item>
@@ -616,7 +623,7 @@ const getButtonsByStatus = (orderStatus: string, checkStatus: string): ActionBut
   }
 
   // 发货完成或已完成:显示查看物流按钮
-  if (orderStatus === OrderStatus.SHIPMENT_COMPLETED || orderStatus === OrderStatus.COMPLETED) {
+  if (orderStatus === OrderStatus.PARTIAL_SHIPMENT || orderStatus === OrderStatus.SHIPMENT_COMPLETED || orderStatus === OrderStatus.COMPLETED) {
     buttons.push({ label: '查看物流', handler: handleViewLogistics });
   }
 

+ 55 - 13
src/views/order/saleOrder/sendDetail.vue

@@ -159,21 +159,21 @@
     <el-card shadow="never" class="mb-2" v-show="orderDetail.orderStatus != '0'">
       <template #header>
         <div class="card-header">
-          <span>发货信息:共{{ 0 }}个包裹</span>
-          <el-button type="primary" style="float: right" @click="handleAddDeliver(orderDetail)">添加发货信息</el-button>
+          <span>发货信息:共{{ orderDeliverList.length }}个包裹</span>
+          <el-button type="primary" @click="handleAddDeliver(orderDetail)">添加发货信息</el-button>
         </div>
       </template>
-      <div v-show="totalQuantitySent > 0">
+      <div v-for="deliver in orderDeliverList" :key="deliver.id" class="mb-4">
         <div style="white-space: nowrap" class="mb-2">
-          <span style="margin-right: 16px">发货单号:--</span>
-          <span style="margin-right: 16px">发货时间:--</span>
-          <span style="margin-right: 16px">发货方式:--</span>
-          <span style="margin-right: 16px">送货人:--</span>
-          <span style="margin-right: 16px">手机:--</span>
-          <span style="margin-right: 16px">物流状态:--</span>
-          <span>发货备注:--</span>
+          <span style="margin-right: 16px">发货单号:{{ (deliver as any).deliverCode || '--' }}</span>
+          <span style="margin-right: 16px">发货时间:{{ (deliver as any).createTime || '--' }}</span>
+          <span style="margin-right: 16px">发货方式:{{ getDictLabel(deliver_method, deliver.deliverMethod || '--') }}</span>
+          <span style="margin-right: 16px">送货人:{{ deliver.deliverMan || '--' }}</span>
+          <span style="margin-right: 16px">手机:{{ deliver.phone || '--' }}</span>
+          <span style="margin-right: 16px">物流状态:{{ deliver.logisticsStatus || '--' }}</span>
+          <span>发货备注:{{ deliver.deliverRemark || '--' }}</span>
         </div>
-        <el-table :data="deliverProductList" border style="width: 100%">
+        <el-table :data="deliver.deliverProductList" border style="width: 100%">
           <el-table-column label="产品编号" prop="productNo" align="center" />
           <el-table-column label="商品名称" prop="productName" align="center" />
           <el-table-column label="单位" prop="productUnit" align="center" />
@@ -219,6 +219,9 @@ import { OrderMainVO } from '@/api/order/orderMain/types';
 import { listOrderProduct } from '@/api/order/orderProduct';
 import { OrderProductVO } from '@/api/order/orderProduct/types';
 import { DeliverProductVO } from '@/api/order/deliverProduct/types';
+import { listOrderDeliver } from '@/api/order/orderDeliver';
+import { OrderDeliverVO } from '@/api/order/orderDeliver/types';
+import { listDeliverProduct } from '@/api/order/deliverProduct';
 import { getShippingAddress } from '@/api/customer/customerFile/shippingAddress';
 import { ShippingAddressVO } from '@/api/customer/customerFile/shippingAddress/types';
 import { getWarehouse } from '@/api/company/warehouse';
@@ -231,8 +234,8 @@ import { getInvoiceType } from '@/api/customer/invoiceType';
 import { InvoiceTypeVO } from '@/api/customer/invoiceType/types';
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
-const { order_status, payment_status, fee_type, pay_method } = toRefs<any>(
-  proxy?.useDict('order_status', 'payment_status', 'fee_type', 'pay_method')
+const { order_status, payment_status, fee_type, pay_method, deliver_method } = toRefs<any>(
+  proxy?.useDict('order_status', 'payment_status', 'fee_type', 'pay_method', 'deliver_method')
 );
 const route = useRoute();
 const router = useRouter();
@@ -255,6 +258,8 @@ const invoiceTypeInfo = ref<InvoiceTypeVO>({} as InvoiceTypeVO);
 // 商品明细列表
 const productList = ref<OrderProductVO[]>([]);
 
+// 发货包裹列表
+const orderDeliverList = ref<OrderDeliverVO[]>([]);
 const deliverProductList = ref<DeliverProductVO[]>([]);
 
 // 收货地址信息
@@ -308,6 +313,11 @@ const getOrderDetail = async () => {
       await getDeliverProductList(orderDetail.value);
     }
 
+    // 获取发货单及关联的物流商品信息
+    if (orderDetail.value.id) {
+      await getOrderDeliverListData(orderDetail.value.id);
+    }
+
     // 获取收货地址
     if (orderDetail.value.shippingAddressId) {
       await getShippingAddressDetail(orderDetail.value.shippingAddressId);
@@ -367,6 +377,31 @@ const getDeliverProductList = async (orderDetail: OrderMainVO) => {
   }
 };
 
+// 获取发货单列表
+const getOrderDeliverListData = async (orderId: string | number) => {
+  try {
+    const res = await listOrderDeliver({ orderId, pageNum: 1, pageSize: 100 });
+    const deliverList = (res as any).rows || res.data || [];
+
+    // 为每条发货记录获取商品明细
+    for (const deliver of deliverList) {
+      if (deliver.id) {
+        try {
+          const productRes = await listDeliverProduct({ deliverId: deliver.id, pageNum: 1, pageSize: 100 });
+          deliver.deliverProductList = (productRes as any).rows || productRes.data || [];
+        } catch (error) {
+          console.error(`获取发货单${deliver.id}的商品明细失败:`, error);
+          deliver.deliverProductList = [];
+        }
+      }
+    }
+
+    orderDeliverList.value = deliverList;
+  } catch (error) {
+    console.error('获取发货单列表失败:', error);
+  }
+};
+
 // 获取收货地址详情
 const getShippingAddressDetail = async (addressId: string | number) => {
   try {
@@ -496,6 +531,13 @@ onMounted(() => {
   flex: 1;
 }
 
+.card-header {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  min-height: 40px;
+}
+
 @media print {
   .el-button {
     display: none;