|
|
@@ -0,0 +1,785 @@
|
|
|
+<template>
|
|
|
+ <!-- 新增对账详情抽屉 -->
|
|
|
+ <el-drawer v-model="drawer.visible" size="75%" direction="rtl" :before-close="handleDrawerClose" :close-on-click-modal="true">
|
|
|
+ <template #header>
|
|
|
+ <div class="drawer-header">
|
|
|
+ <span class="order-title">新增对账</span>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <div class="drawer-content">
|
|
|
+ <el-form ref="formRef" :model="form" :rules="rules" label-width="120px">
|
|
|
+ <!-- 基本信息 -->
|
|
|
+ <el-divider content-position="left">
|
|
|
+ <span style="color: #409eff; font-weight: 600">基本信息</span>
|
|
|
+ </el-divider>
|
|
|
+
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :span="8" v-if="isEdit">
|
|
|
+ <el-form-item label="对账单号" prop="statementOrderNo">
|
|
|
+ <el-input v-model="form.statementOrderNo" disabled />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8" v-if="isEdit">
|
|
|
+ <el-form-item label="对账状态" prop="statementStatus">
|
|
|
+ <el-input v-model="form.statementStatus" disabled />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="客户名称" prop="customerId">
|
|
|
+ <el-select
|
|
|
+ v-model="form.customerId"
|
|
|
+ filterable
|
|
|
+ remote
|
|
|
+ reserve-keyword
|
|
|
+ placeholder="请输入客户名称"
|
|
|
+ :remote-method="remoteSearchCustomer"
|
|
|
+ :loading="customerLoading"
|
|
|
+ clearable
|
|
|
+ style="width: 100%"
|
|
|
+ @change="handleCustomerChange"
|
|
|
+ >
|
|
|
+ <el-option v-for="item in customerOptions" :key="item.id" :label="item.customerName" :value="item.id" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="对账单金额" prop="amount">
|
|
|
+ <el-input v-model="form.amount" disabled />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="对账人" prop="statementSelfId">
|
|
|
+ <el-select
|
|
|
+ v-model="form.statementSelfId"
|
|
|
+ placeholder="请选择对账人"
|
|
|
+ clearable
|
|
|
+ filterable
|
|
|
+ style="width: 100%"
|
|
|
+ @change="handleStaffChange"
|
|
|
+ >
|
|
|
+ <el-option v-for="staff in staffOptions" :key="staff.staffId" :label="staff.staffName" :value="staff.staffId" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="对账人联系方式" prop="statementSelfPhone">
|
|
|
+ <el-input v-model="form.statementSelfPhone" placeholder="请填写对账人联系方式" clearable />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="对账日期" prop="statementDate">
|
|
|
+ <el-date-picker v-model="form.statementDate" type="date" placeholder="请选择对账日期" style="width: 100%" value-format="YYYY-MM-DD" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="支付状态" prop="isPaymentStatus">
|
|
|
+ <el-select v-model="form.isPaymentStatus" placeholder="请选择支付状态" clearable style="width: 100%">
|
|
|
+ <el-option v-for="dict in payment_status" :key="dict.value" :label="dict.label" :value="dict.value" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="发票状态" prop="isInvoiceStatus">
|
|
|
+ <el-select v-model="form.isInvoiceStatus" placeholder="请选择发票状态" clearable style="width: 100%">
|
|
|
+ <el-option v-for="dict in invoice_issuance_status" :key="dict.value" :label="dict.label" :value="dict.value" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :span="24">
|
|
|
+ <el-form-item label="备注" prop="remark">
|
|
|
+ <el-input v-model="form.remark" type="textarea" :rows="3" placeholder="请输入备注" maxlength="500" show-word-limit />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <!-- 对账明细 -->
|
|
|
+ <el-divider content-position="left">
|
|
|
+ <span style="color: #409eff; font-weight: 600">对账明细</span>
|
|
|
+ </el-divider>
|
|
|
+
|
|
|
+ <div class="table-actions" style="margin-bottom: 15px">
|
|
|
+ <el-button type="primary" icon="Plus" @click="handleAddDetail">选择订单</el-button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <el-table :data="form.detailList" border style="width: 100%; margin-bottom: 20px">
|
|
|
+ <el-table-column type="index" label="序号" width="60" align="center" />
|
|
|
+ <el-table-column prop="orderNo" label="订单编号" min-width="150" align="center" />
|
|
|
+ <el-table-column prop="deliverCode" label="发货单编号" min-width="150" align="center" />
|
|
|
+ <el-table-column prop="amount" label="金额" min-width="120" align="center" />
|
|
|
+ <el-table-column prop="orderTime" label="下单日期" min-width="120" align="center" />
|
|
|
+ <el-table-column prop="userName" label="下单人" min-width="100" align="center" />
|
|
|
+ <el-table-column prop="userDept" label="部门" min-width="120" align="center" />
|
|
|
+ </el-table>
|
|
|
+ <!--
|
|
|
+ <div v-if="form.detailList.length === 0" class="empty-data">
|
|
|
+ <el-empty description="暂无数据" :image-size="100" />
|
|
|
+ </div> -->
|
|
|
+
|
|
|
+ <!-- 商品清单 -->
|
|
|
+ <el-divider content-position="left">
|
|
|
+ <span style="color: #409eff; font-weight: 600">商品清单</span>
|
|
|
+ </el-divider>
|
|
|
+
|
|
|
+ <el-table :data="pagedProductList" border style="width: 100%; margin-bottom: 20px">
|
|
|
+ <el-table-column
|
|
|
+ type="index"
|
|
|
+ label="序号"
|
|
|
+ width="60"
|
|
|
+ align="center"
|
|
|
+ :index="(index) => (productPage.pageNum - 1) * productPage.pageSize + index + 1"
|
|
|
+ />
|
|
|
+ <el-table-column prop="orderNo" label="订单编号" min-width="120" align="center" />
|
|
|
+ <el-table-column prop="productNo" label="商品编号" min-width="120" align="center" />
|
|
|
+ <el-table-column prop="itemName" label="商品名称" min-width="180" align="center" />
|
|
|
+ <el-table-column prop="unitName" label="单位" width="80" align="center" />
|
|
|
+ <el-table-column prop="quantity" label="数量" width="100" align="center" />
|
|
|
+ <el-table-column prop="unitPrice" label="单价" width="100" align="center">
|
|
|
+ <template #default="scope">
|
|
|
+ {{ scope.row.unitPrice ? Number(scope.row.unitPrice).toFixed(2) : '0.00' }}
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="小计" width="120" align="center">
|
|
|
+ <template #default="scope">
|
|
|
+ {{ (Number(scope.row.quantity || 0) * Number(scope.row.unitPrice || 0)).toFixed(2) }}
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+
|
|
|
+ <!-- 分页 -->
|
|
|
+ <el-pagination
|
|
|
+ v-if="form.productList.length > 0"
|
|
|
+ v-model:current-page="productPage.pageNum"
|
|
|
+ v-model:page-size="productPage.pageSize"
|
|
|
+ :page-sizes="[10, 20, 50, 100]"
|
|
|
+ layout="total, sizes, prev, pager, next, jumpers"
|
|
|
+ :total="productPage.total"
|
|
|
+ @size-change="handleProductSizeChange"
|
|
|
+ @current-change="handleProductCurrentChange"
|
|
|
+ style="margin-top: 15px"
|
|
|
+ />
|
|
|
+
|
|
|
+ <!-- 对账附件 -->
|
|
|
+ <el-divider content-position="left">
|
|
|
+ <span style="color: #409eff; font-weight: 600">对账附件</span>
|
|
|
+ </el-divider>
|
|
|
+
|
|
|
+ <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" />
|
|
|
+ <el-table-column prop="name" label="文件名称" min-width="200" align="center" />
|
|
|
+ <el-table-column prop="url" label="文件地址" min-width="250" align="center">
|
|
|
+ <template #default="scope">
|
|
|
+ {{ scope.row.url || '暂无地址' }}
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <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>
|
|
|
+ <!--
|
|
|
+ <div v-if="fileList.length === 0" class="empty-data">
|
|
|
+ <el-empty description="暂无附件" :image-size="100" />
|
|
|
+ </div> -->
|
|
|
+ </el-form>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <template #footer>
|
|
|
+ <div class="drawer-footer">
|
|
|
+ <el-button @click="handleDrawerClose(() => (drawer.visible = false))">取消</el-button>
|
|
|
+ <el-button type="primary" :loading="buttonLoading" @click="handleSubmit">确定</el-button>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-drawer>
|
|
|
+
|
|
|
+ <!-- 客户订单抽屉 -->
|
|
|
+ <OrderMainDrawer ref="orderMainDrawerRef" @success="handleOrderSelected" />
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup name="AddDrawer" lang="ts">
|
|
|
+import { addStatementOrder, updateStatementOrder } from '@/api/bill/statementOrder';
|
|
|
+import { StatementOrderForm } from '@/api/bill/statementOrder/types';
|
|
|
+import { StatementDetailForm } from '@/api/bill/statementDetail/types';
|
|
|
+import { getListBycustomerName } from '@/api/customer/customerFile/customerInfo';
|
|
|
+import { CustomerInfoVO } from '@/api/customer/customerFile/customerInfo/types';
|
|
|
+import { listOrderMain, getOrderMain } from '@/api/order/orderMain';
|
|
|
+import { OrderMainVO, OrderMainQuery, OrderMainForm } from '@/api/order/orderMain/types';
|
|
|
+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 { getCustomerDeliverOrders } from '@/api/order/orderDeliver';
|
|
|
+
|
|
|
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
|
|
+const { statement_status, invoice_issuance_status, payment_status } = toRefs<any>(
|
|
|
+ proxy?.useDict('statement_status', 'statement_order_type', 'invoice_issuance_status', 'payment_status')
|
|
|
+);
|
|
|
+
|
|
|
+const initFormData: StatementOrderForm = {
|
|
|
+ id: undefined,
|
|
|
+ statementOrderNo: undefined,
|
|
|
+ customerId: undefined,
|
|
|
+ customerNo: undefined,
|
|
|
+ customerName: undefined,
|
|
|
+ amount: undefined,
|
|
|
+ statementSelfId: undefined,
|
|
|
+ statementSelf: undefined,
|
|
|
+ statementSelfPhone: undefined,
|
|
|
+ statementStatus: undefined,
|
|
|
+ isPaymentStatus: '1',
|
|
|
+ isInvoiceStatus: '0',
|
|
|
+ statementDate: undefined,
|
|
|
+ annexAddress: undefined,
|
|
|
+ rejectRemark: undefined,
|
|
|
+ remark: undefined,
|
|
|
+ detailList: [],
|
|
|
+ productList: []
|
|
|
+};
|
|
|
+
|
|
|
+const emit = defineEmits(['success']);
|
|
|
+
|
|
|
+const formRef = ref<any>();
|
|
|
+const buttonLoading = ref(false);
|
|
|
+
|
|
|
+const form = ref<
|
|
|
+ StatementOrderForm & {
|
|
|
+ actualAmount?: string;
|
|
|
+ accountingVerification?: string;
|
|
|
+ skuProductName?: string;
|
|
|
+ skuProductModel?: string;
|
|
|
+ attachmentRemark?: string;
|
|
|
+ }
|
|
|
+>({ ...initFormData });
|
|
|
+
|
|
|
+const rules = reactive({
|
|
|
+ customerName: [{ required: true, message: '请输入客户名称', trigger: 'blur' }],
|
|
|
+ statementSelfId: [{ required: true, message: '请选择对账人', trigger: 'blur' }],
|
|
|
+ statementSelfPhone: [
|
|
|
+ { required: true, message: '请输入对账人手机号', trigger: 'blur' },
|
|
|
+ { pattern: /^1[3-9]\d{9}$/ as RegExp, message: '请输入正确的手机号格式', trigger: 'blur' }
|
|
|
+ ]
|
|
|
+} as any);
|
|
|
+
|
|
|
+const fileList = ref<any[]>([]);
|
|
|
+
|
|
|
+const productPage = reactive({
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 10,
|
|
|
+ total: 0
|
|
|
+});
|
|
|
+
|
|
|
+const drawer = reactive<DialogOption>({
|
|
|
+ visible: false,
|
|
|
+ title: '新增对账'
|
|
|
+});
|
|
|
+
|
|
|
+const isEdit = ref(false); // 是否为编辑模式
|
|
|
+
|
|
|
+const customerLoading = ref(false);
|
|
|
+const customerOptions = ref<CustomerInfoVO[]>([]);
|
|
|
+const staffOptions = ref<ComStaffVO[]>([]);
|
|
|
+const orderMainDrawerRef = ref<any>();
|
|
|
+const uploadAction = import.meta.env.VITE_APP_BASE_API + '/resource/oss/upload';
|
|
|
+const currentSelectedOrders = ref<OrderDeliverVO[]>([]);
|
|
|
+const preloadedOrders = ref<OrderDeliverVO[]>([]); // 预加载的订单列表
|
|
|
+
|
|
|
+/** 计算当前页的商品列表 */
|
|
|
+const pagedProductList = computed(() => {
|
|
|
+ const start = (productPage.pageNum - 1) * productPage.pageSize;
|
|
|
+ const end = start + productPage.pageSize;
|
|
|
+ return form.value.productList?.slice(start, end) || [];
|
|
|
+});
|
|
|
+const preloadedTotal = ref(0); // 预加载的订单总数
|
|
|
+
|
|
|
+/** 打开新增/编辑对账详情抽屉 */
|
|
|
+const open = (id?: string | number, data?: StatementOrderForm) => {
|
|
|
+ reset();
|
|
|
+
|
|
|
+ if (id && data) {
|
|
|
+ // 编辑模式
|
|
|
+ isEdit.value = true;
|
|
|
+ drawer.title = '编辑对账';
|
|
|
+ Object.assign(form.value, data);
|
|
|
+
|
|
|
+ // 将客户信息添加到下拉选项中,以便回显
|
|
|
+ if (data.customerId && data.customerName) {
|
|
|
+ customerOptions.value = [
|
|
|
+ {
|
|
|
+ id: data.customerId,
|
|
|
+ customerName: data.customerName,
|
|
|
+ customerNo: data.customerNo || ''
|
|
|
+ } as CustomerInfoVO
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ // 解析附件地址并回显附件列表
|
|
|
+ if (data.annexAddress) {
|
|
|
+ const urls = data.annexAddress.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
|
|
|
+ };
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置商品列表分页总数
|
|
|
+ if (data.productList && data.productList.length > 0) {
|
|
|
+ productPage.total = data.productList.length;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 新增模式
|
|
|
+ isEdit.value = false;
|
|
|
+ drawer.title = '新增对账';
|
|
|
+ }
|
|
|
+
|
|
|
+ // 先打开抽屉
|
|
|
+ drawer.visible = true;
|
|
|
+
|
|
|
+ // 异步加载员工列表
|
|
|
+ getStaffList();
|
|
|
+
|
|
|
+ // 编辑模式下,如果有客户ID,异步预加载订单列表
|
|
|
+ if (id && data?.customerId) {
|
|
|
+ preloadOrders(data.customerId);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 表单重置 */
|
|
|
+const reset = () => {
|
|
|
+ form.value = { ...initFormData };
|
|
|
+ fileList.value = [];
|
|
|
+ productPage.pageNum = 1;
|
|
|
+ productPage.pageSize = 10;
|
|
|
+ productPage.total = 0;
|
|
|
+ customerOptions.value = [];
|
|
|
+ currentSelectedOrders.value = [];
|
|
|
+ preloadedOrders.value = [];
|
|
|
+ preloadedTotal.value = 0;
|
|
|
+ formRef.value?.clearValidate();
|
|
|
+};
|
|
|
+
|
|
|
+/** 远程搜索客户 */
|
|
|
+const remoteSearchCustomer = async (query: string) => {
|
|
|
+ if (query) {
|
|
|
+ customerLoading.value = true;
|
|
|
+ try {
|
|
|
+ const res = await getListBycustomerName(query);
|
|
|
+ customerOptions.value = res.data;
|
|
|
+ } catch (error) {
|
|
|
+ console.error(error);
|
|
|
+ } finally {
|
|
|
+ customerLoading.value = false;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ customerOptions.value = [];
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 客户变更 */
|
|
|
+const handleCustomerChange = async (customerId: string | number) => {
|
|
|
+ if (customerId) {
|
|
|
+ const customer = customerOptions.value.find((item) => item.id === customerId);
|
|
|
+ if (customer) {
|
|
|
+ form.value.customerName = customer.customerName;
|
|
|
+ form.value.customerNo = customer.customerNo;
|
|
|
+ }
|
|
|
+ // 预加载订单列表
|
|
|
+ await preloadOrders(customerId);
|
|
|
+ } else {
|
|
|
+ form.value.customerName = undefined;
|
|
|
+ form.value.customerNo = undefined;
|
|
|
+ preloadedOrders.value = [];
|
|
|
+ preloadedTotal.value = 0;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 预加载订单列表 */
|
|
|
+const preloadOrders = async (customerId: string | number) => {
|
|
|
+ try {
|
|
|
+ const res = await getCustomerDeliverOrders(customerId);
|
|
|
+ preloadedOrders.value = res.rows || [];
|
|
|
+ preloadedTotal.value = res.total || 0;
|
|
|
+ } catch (error) {
|
|
|
+ console.error('预加载订单列表失败:', error);
|
|
|
+ preloadedOrders.value = [];
|
|
|
+ preloadedTotal.value = 0;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 选择订单 */
|
|
|
+const handleSelectOrder = () => {
|
|
|
+ if (!form.value.customerId) {
|
|
|
+ proxy?.$modal.msgWarning('请先选择客户');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 传递当前已选中的订单、产品列表、预加载的订单列表和总数
|
|
|
+ orderMainDrawerRef.value?.open(
|
|
|
+ form.value.customerId,
|
|
|
+ currentSelectedOrders.value,
|
|
|
+ form.value.productList,
|
|
|
+ preloadedOrders.value,
|
|
|
+ preloadedTotal.value
|
|
|
+ );
|
|
|
+};
|
|
|
+
|
|
|
+/** 获取员工列表 */
|
|
|
+const getStaffList = async () => {
|
|
|
+ try {
|
|
|
+ const res = await listComStaff();
|
|
|
+ staffOptions.value = res.rows || [];
|
|
|
+ } catch (error) {
|
|
|
+ console.error('获取员工列表失败:', error);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 员工变更 */
|
|
|
+const handleStaffChange = (staffId: string | number) => {
|
|
|
+ if (staffId) {
|
|
|
+ const staff = staffOptions.value.find((item) => item.staffId === staffId);
|
|
|
+ if (staff) {
|
|
|
+ form.value.statementSelf = staff.staffName || '';
|
|
|
+ form.value.statementSelfPhone = staff.phone || '';
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ form.value.statementSelf = undefined;
|
|
|
+ form.value.statementSelfPhone = '';
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 订单选择成功回调 */
|
|
|
+const handleOrderSelected = (data: any) => {
|
|
|
+ const { orders, products } = data;
|
|
|
+
|
|
|
+ if (orders && orders.length > 0) {
|
|
|
+ let totalAmount = 0;
|
|
|
+
|
|
|
+ // 保存当前选中的订单
|
|
|
+ currentSelectedOrders.value = orders;
|
|
|
+
|
|
|
+ // 清空现有数据
|
|
|
+ form.value.detailList = [];
|
|
|
+ form.value.productList = [];
|
|
|
+
|
|
|
+ // 填充对账明细
|
|
|
+ orders.forEach((order: any) => {
|
|
|
+ totalAmount += Number(order.totalAmount || 0);
|
|
|
+
|
|
|
+ const detail: any = {
|
|
|
+ id: undefined,
|
|
|
+ statementOrderId: undefined,
|
|
|
+ orderNo: order.orderCode,
|
|
|
+ deliverCode: order.deliverCode || '',
|
|
|
+ orderTime: order.orderTime || '',
|
|
|
+ amount: order.totalAmount,
|
|
|
+ type: order.orderType || '',
|
|
|
+ orderId: order.id,
|
|
|
+ signingDate: order.receivingTime || order.signingDate || '',
|
|
|
+ userId: order.createBy,
|
|
|
+ userName: order.createName || '',
|
|
|
+ userDeptId: order.createDept,
|
|
|
+ userDept: order.createDeptName || ''
|
|
|
+ };
|
|
|
+ form.value.detailList?.push(detail);
|
|
|
+ });
|
|
|
+
|
|
|
+ // 设置总金额
|
|
|
+ form.value.amount = totalAmount;
|
|
|
+
|
|
|
+ // 直接使用传递过来的产品列表
|
|
|
+ if (products && products.length > 0) {
|
|
|
+ form.value.productList = products;
|
|
|
+ productPage.total = products.length;
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 添加对账明细 */
|
|
|
+const handleAddDetail = () => {
|
|
|
+ if (!form.value.customerId) {
|
|
|
+ proxy?.$modal.msgWarning('请先选择客户');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 传递当前已选中的订单、产品列表、预加载的订单列表和总数
|
|
|
+ orderMainDrawerRef.value?.open(
|
|
|
+ form.value.customerId,
|
|
|
+ currentSelectedOrders.value,
|
|
|
+ form.value.productList,
|
|
|
+ preloadedOrders.value,
|
|
|
+ preloadedTotal.value
|
|
|
+ );
|
|
|
+};
|
|
|
+
|
|
|
+/** 产品分页大小改变 */
|
|
|
+const handleProductSizeChange = (val: number) => {
|
|
|
+ productPage.pageSize = val;
|
|
|
+};
|
|
|
+
|
|
|
+/** 产品分页页码改变 */
|
|
|
+const handleProductCurrentChange = (val: number) => {
|
|
|
+ productPage.pageNum = val;
|
|
|
+};
|
|
|
+
|
|
|
+/** 上传前校验 */
|
|
|
+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.url)
|
|
|
+ .filter(Boolean)
|
|
|
+ .join(',');
|
|
|
+};
|
|
|
+
|
|
|
+/** 下载文件 */
|
|
|
+const handleDownloadFile = async (file: any) => {
|
|
|
+ if (!file.url) {
|
|
|
+ proxy?.$modal.msgWarning('文件地址不存在');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 使用fetch获取文件
|
|
|
+ const response = await fetch(file.url);
|
|
|
+ const blob = await response.blob();
|
|
|
+
|
|
|
+ // 创建Blob URL
|
|
|
+ const blobUrl = window.URL.createObjectURL(blob);
|
|
|
+
|
|
|
+ // 创建下载链接
|
|
|
+ const link = document.createElement('a');
|
|
|
+ link.href = blobUrl;
|
|
|
+ link.download = file.name || '附件';
|
|
|
+ document.body.appendChild(link);
|
|
|
+ link.click();
|
|
|
+
|
|
|
+ // 清理
|
|
|
+ document.body.removeChild(link);
|
|
|
+ window.URL.revokeObjectURL(blobUrl);
|
|
|
+ } catch (error) {
|
|
|
+ console.error('下载失败:', error);
|
|
|
+ // 如果fetch失败,回退到直接打开链接的方式
|
|
|
+ const link = document.createElement('a');
|
|
|
+ link.href = file.url;
|
|
|
+ link.download = file.name || '附件';
|
|
|
+ link.target = '_blank';
|
|
|
+ document.body.appendChild(link);
|
|
|
+ link.click();
|
|
|
+ document.body.removeChild(link);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 预览文件 */
|
|
|
+const handlePreviewFile = (file: any) => {
|
|
|
+ if (!file.url) {
|
|
|
+ proxy?.$modal.msgWarning('文件地址不存在');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 在新窗口打开文件
|
|
|
+ window.open(file.url, '_blank');
|
|
|
+};
|
|
|
+
|
|
|
+/** 提交表单 */
|
|
|
+const handleSubmit = async () => {
|
|
|
+ if (!formRef.value) return;
|
|
|
+ console.log(form.value);
|
|
|
+
|
|
|
+ await formRef.value.validate(async (valid) => {
|
|
|
+ if (valid) {
|
|
|
+ buttonLoading.value = true;
|
|
|
+ try {
|
|
|
+ if (isEdit.value) {
|
|
|
+ // 编辑模式
|
|
|
+ await updateStatementOrder(form.value);
|
|
|
+ proxy?.$modal.msgSuccess('修改成功');
|
|
|
+ } else {
|
|
|
+ // 新增模式
|
|
|
+ await addStatementOrder(form.value);
|
|
|
+ proxy?.$modal.msgSuccess('新增成功');
|
|
|
+ }
|
|
|
+ drawer.visible = false;
|
|
|
+ emit('success');
|
|
|
+ } catch (error) {
|
|
|
+ console.error(error);
|
|
|
+ } finally {
|
|
|
+ buttonLoading.value = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+/** 关闭抽屉前的回调 */
|
|
|
+const handleDrawerClose = (done: () => void) => {
|
|
|
+ if (buttonLoading.value) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ done();
|
|
|
+ reset();
|
|
|
+};
|
|
|
+
|
|
|
+defineExpose({
|
|
|
+ open
|
|
|
+});
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped lang="scss">
|
|
|
+.drawer-header {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 10px;
|
|
|
+
|
|
|
+ .order-title {
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #303133;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.drawer-content {
|
|
|
+ padding: 0 20px 20px;
|
|
|
+ height: calc(100% - 60px);
|
|
|
+ overflow-y: auto;
|
|
|
+}
|
|
|
+
|
|
|
+.assign-dialog-content {
|
|
|
+ padding: 0 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.assign-target-section {
|
|
|
+ margin-bottom: 20px;
|
|
|
+
|
|
|
+ .target-input-wrapper {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 8px;
|
|
|
+
|
|
|
+ .required-mark {
|
|
|
+ color: #f56c6c;
|
|
|
+ font-size: 14px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .label {
|
|
|
+ font-size: 14px;
|
|
|
+ color: #606266;
|
|
|
+ white-space: nowrap;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .or-divider {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ font-size: 14px;
|
|
|
+ color: #909399;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.product-list-section {
|
|
|
+ margin-top: 20px;
|
|
|
+}
|
|
|
+
|
|
|
+.detail-header {
|
|
|
+ padding: 15px 20px;
|
|
|
+ background-color: #f5f7fa;
|
|
|
+ border-radius: 4px;
|
|
|
+ margin-bottom: 20px;
|
|
|
+
|
|
|
+ .info-item {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 5px;
|
|
|
+
|
|
|
+ .label {
|
|
|
+ font-size: 12px;
|
|
|
+ color: #909399;
|
|
|
+ }
|
|
|
+
|
|
|
+ .value {
|
|
|
+ font-size: 14px;
|
|
|
+ color: #303133;
|
|
|
+ font-weight: 500;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.detail-tabs {
|
|
|
+ .tab-actions {
|
|
|
+ margin-bottom: 15px;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+:deep(.el-alert__title) {
|
|
|
+ font-size: 13px;
|
|
|
+}
|
|
|
+
|
|
|
+.empty-data {
|
|
|
+ padding: 20px 0;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+
|
|
|
+.drawer-footer {
|
|
|
+ display: flex;
|
|
|
+ justify-content: flex-end;
|
|
|
+ gap: 10px;
|
|
|
+ padding: 15px 20px;
|
|
|
+ border-top: 1px solid #e4e7ed;
|
|
|
+}
|
|
|
+
|
|
|
+:deep(.el-upload__tip) {
|
|
|
+ margin-top: 8px;
|
|
|
+ font-size: 12px;
|
|
|
+ color: #909399;
|
|
|
+}
|
|
|
+</style>
|