gaoluyang
5 天以前 a0a35be4065d75b80ba4a9a51da7031e03166766
src/views/salesManagement/salesLedger/index.vue
@@ -46,6 +46,15 @@
              <el-table-column label="产品大类" prop="productCategory" />
              <el-table-column label="规格型号" prop="specificationModel" />
              <el-table-column label="单位" prop="unit" />
              <el-table-column label="产品状态" width="100px" align="center">
                <template #default="scope">
                  <el-tag v-if="scope.row.approveStatus === 0" type="info">未出库</el-tag>
                  <el-tag v-if="scope.row.approveStatus === 1" type="success">已出库</el-tag>
                  <el-tag v-if="scope.row.approveStatus === 2" type="warning">审核中</el-tag>
                  <el-tag v-if="scope.row.approveStatus === 3" type="success">审核成功</el-tag>
                  <el-tag v-if="scope.row.approveStatus === 4" type="danger">审核失败</el-tag>
                </template>
              </el-table-column>
              <el-table-column label="数量" prop="quantity" />
              <el-table-column label="税率(%)" prop="taxRate" />
              <el-table-column label="含税单价(元)" prop="taxInclusiveUnitPrice" :formatter="formattedNumber" />
@@ -64,10 +73,11 @@
        <el-table-column label="录入人" prop="entryPersonName" width="100" show-overflow-tooltip />
        <el-table-column label="录入日期" prop="entryDate" width="120" show-overflow-tooltip />
        <el-table-column label="签订日期" prop="executionDate" width="120" show-overflow-tooltip />
        <el-table-column fixed="right" label="操作" min-width="200" align="center">
        <el-table-column label="发货车牌" prop="shippingCarNumber" width="140" align="center" show-overflow-tooltip />
        <el-table-column label="发货日期" prop="shippingDate" width="140" align="center" show-overflow-tooltip />
        <el-table-column fixed="right" label="操作" min-width="140" align="center">
          <template #default="scope">
            <el-button link type="primary" size="small" :disabled="scope.row.invoiceTotal>0 || scope.row.entryPersonName !== userStore.nickName" @click="openForm('edit', scope.row)">编辑</el-button>
<!--            <el-button link type="primary" size="small" @click="openForm('view', scope.row)">详情</el-button>-->
            <el-button link type="primary" size="small" @click="openForm('edit', scope.row)">编辑</el-button>
            <el-button link type="primary" size="small" @click="downLoadFile(scope.row)">附件</el-button>
            <el-button link type="primary" size="small" @click="openDeliveryForm(scope.row)">发货</el-button>
          </template>
@@ -76,8 +86,14 @@
      <pagination v-show="total > 0" :total="total" layout="total, sizes, prev, pager, next, jumper"
        :page="page.current" :limit="page.size" @pagination="paginationChange" />
    </div>
    <el-dialog v-model="dialogFormVisible" :title="operationType === 'add' ? '新增销售台账页面' : '编辑销售台账页面'" width="70%"
      @close="closeDia">
    <FormDialog
      v-model="dialogFormVisible"
      :title="operationType === 'add' ? '新增销售台账页面' : '编辑销售台账页面'"
      :width="'70%'"
      :operation-type="operationType"
      @close="closeDia"
      @confirm="submitForm"
      @cancel="closeDia">
      <el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef">
        <el-row :gutter="30">
          <el-col :span="12">
@@ -87,7 +103,9 @@
          </el-col>
          <el-col :span="12">
            <el-form-item label="业务员:" prop="salesman">
              <el-select v-model="form.salesman" placeholder="请选择" clearable :disabled="operationType === 'view'" filterable>
              <el-select v-model="form.salesman"
                                     filterable
                         :reserve-keyword="false" placeholder="请选择" clearable :disabled="operationType === 'view'">
                <el-option v-for="item in userList" :key="item.nickName" :label="item.nickName"
                  :value="item.nickName" />
              </el-select>
@@ -100,23 +118,26 @@
              <el-select v-model="form.customerId" placeholder="请选择" clearable :disabled="operationType === 'view'" filterable>
                <el-option v-for="item in customerOption" :key="item.id" :label="item.customerName" :value="item.id">
                  {{
                    item.customerName+'-'+item.type
                    item.customerName+'-'+item.customerType
                  }}
                </el-option>
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="签订日期:" prop="executionDate">
              <el-date-picker style="width: 100%" v-model="form.executionDate" value-format="YYYY-MM-DD"
                              format="YYYY-MM-DD" type="date" placeholder="请选择" clearable :disabled="operationType === 'view'" />
            </el-form-item>
          </el-col>
               <el-col :span="12">
                  <el-form-item label="签订日期:" prop="executionDate">
                     <el-date-picker style="width: 100%" v-model="form.executionDate" value-format="YYYY-MM-DD"
                                             format="YYYY-MM-DD" type="date" placeholder="请选择" clearable :disabled="operationType === 'view'" />
                  </el-form-item>
               </el-col>
        </el-row>
        <el-row :gutter="30">
               <el-col :span="12">
                  <el-form-item label="录入人:" prop="entryPerson">
                     <el-select v-model="form.entryPerson" placeholder="请选择" clearable @change="changs" disabled filterable>
                     <el-select v-model="form.entryPerson"
                                     filterable
                         default-first-option
                         :reserve-keyword="false" placeholder="请选择" clearable @change="changs">
                        <el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.userId" />
                     </el-select>
                  </el-form-item>
@@ -132,14 +153,6 @@
          <el-col :span="12">
            <el-form-item label="付款方式">
              <el-input v-model="form.paymentMethod" placeholder="请输入" clearable :disabled="operationType === 'view'" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="是否开票" prop="isInvoice">
              <el-select v-model="form.isInvoice" placeholder="请选择" clearable>
                <el-option label="是" value="1" />
                <el-option label="否" value="2" />
              </el-select>
            </el-form-item>
          </el-col>
        </el-row>
@@ -198,7 +211,7 @@
          <el-button @click="closeDia">取消</el-button>
        </div>
      </template>
    </el-dialog>
    </FormDialog>
    <el-dialog v-model="productFormVisible" :title="productOperationType === 'add' ? '新增产品' : '编辑产品'" width="40%"
      @close="closeProductDia">
      <el-form :model="productForm" label-width="140px" label-position="top" :rules="productRules" ref="productFormRef">
@@ -320,17 +333,20 @@
                              <span class="value">{{ formatDate(item.createTime) }}</span>
                           </div>
                           <div>
                              <span class="label">客户名称:</span>
                              <span class="value">{{ item.customerName || '张爱有' }}</span>
                              <span class="label">发货车牌号:</span>
                              <span class="value">{{ item.shippingCarNumber }}</span>
                           </div>
                        </div>
                        <div class="info-row">
                           <div>
                              <span class="label">客户名称:</span>
                              <span class="value">{{ item.customerName || '张爱有' }}</span>
                           </div>
                           <span class="label">单号:</span>
                           <span class="value">{{ item.salesContractNo }}</span>
                        </div>
                     </div>
                     <div class="table-section">
                        <table class="product-table">
                           <thead>
@@ -368,7 +384,7 @@
                           </tfoot>
                        </table>
                     </div>
                     <div class="footer-section">
                        <div class="footer-row">
                           <div class="footer-item">
@@ -410,6 +426,21 @@
         <el-form :model="deliveryForm" label-width="120px" label-position="top" :rules="deliveryRules" ref="deliveryFormRef">
            <el-row :gutter="30">
               <el-col :span="24">
                  <el-form-item label="发货类型:" prop="shippingType">
                     <el-select
                        v-model="deliveryForm.shippingType"
                        placeholder="请选择发货类型"
                        style="width: 100%"
                        @change="handleShippingTypeChange"
                     >
                        <el-option label="货车" value="truck" />
                        <el-option label="快递" value="express" />
                     </el-select>
                  </el-form-item>
               </el-col>
            </el-row>
            <el-row :gutter="30">
               <el-col :span="24">
                  <el-form-item label="发货日期:" prop="shippingDate">
                     <el-date-picker
                        style="width: 100%"
@@ -424,11 +455,20 @@
               </el-col>
            </el-row>
            <el-row :gutter="30">
               <el-col :span="24">
               <el-col :span="24" v-if="deliveryForm.shippingType === 'truck'">
                  <el-form-item label="发货车牌号:" prop="shippingCarNumber">
                     <el-input
                        v-model="deliveryForm.shippingCarNumber"
                        placeholder="请输入发货车牌号"
                        clearable
                     />
                  </el-form-item>
               </el-col>
               <el-col :span="24" v-else>
                  <el-form-item label="快递公司:" prop="expressCompany">
                     <el-input
                        v-model="deliveryForm.expressCompany"
                        placeholder="请输入快递公司"
                        clearable
                     />
                  </el-form-item>
@@ -449,27 +489,31 @@
<script setup>
import { getToken } from "@/utils/auth";
import pagination from "@/components/PIMTable/Pagination.vue";
import {onMounted, ref} from "vue";
import {onMounted, ref, getCurrentInstance} from "vue";
import { addShippingInfo } from "@/api/salesManagement/deliveryLedger.js";
import { ElMessageBox } from "element-plus";
import { ElMessageBox, ElMessage } from "element-plus";
import { UploadFilled } from "@element-plus/icons-vue";
import useUserStore from "@/store/modules/user";
import { userListNoPage } from "@/api/system/user.js";
import FileList from "./fileList.vue";
import FileList from '@/views/salesManagement/salesLedger/fileList.vue';
import FormDialog from '@/components/Dialog/FormDialog.vue';
import { getQuotationList } from "@/api/salesManagement/salesQuotation.js";
import {
  ledgerListPage,
  productList,
  customerList,
  addOrUpdateSalesLedger,
  getSalesLedgerWithProducts,
  delLedger,
  addOrUpdateSalesLedgerProduct,
  delProduct,
  delLedgerFile,
   ledgerListPage,
   productList,
   customerList,
   addOrUpdateSalesLedger,
   getSalesLedgerWithProducts,
   delLedger,
   addOrUpdateSalesLedgerProduct,
   delProduct,
   delLedgerFile, getProductInventory,
} from "@/api/salesManagement/salesLedger.js";
import { getQuotationDetail } from "@/api/salesManagement/salesQuotation.js";
import { modelList, productTreeList } from "@/api/basicData/product.js";
import useFormData from "@/hooks/useFormData.js";
import dayjs from "dayjs";
import { getCurrentDate } from "@/utils/index.js";
const userStore = useUserStore();
const { proxy } = getCurrentInstance();
@@ -511,7 +555,6 @@
    productData: [],
    executionDate: "",
    paymentMethod: "",
    isInvoice:"",
  },
  rules: {
    salesman: [{ required: true, message: "请选择", trigger: "change" }],
@@ -519,7 +562,6 @@
    entryPerson: [{ required: true, message: "请选择", trigger: "change" }],
    entryDate: [{ required: true, message: "请选择", trigger: "change" }],
    executionDate: [{ required: true, message: "请选择", trigger: "change" }],
    isInvoice: [{ required: true, message: "请选择", trigger: "change"}],
    },
});
const { form, rules } = toRefs(data);
@@ -579,15 +621,23 @@
const currentDeliveryRow = ref(null);
const deliveryFormData = reactive({
  deliveryForm: {
    shippingType: "truck", // truck: 货车, express: 快递
    shippingDate: "",
    shippingCarNumber: "",
    expressCompany: "",
  },
  deliveryRules: {
    shippingType: [
      { required: true, message: "请选择发货类型", trigger: "change" }
    ],
    shippingDate: [
      { required: true, message: "请选择发货日期", trigger: "change" }
    ],
    shippingCarNumber: [
      { required: true, message: "请输入发货车牌号", trigger: "blur" }
      { validator: (_, value, callback) => validateShippingCarNumber(value, callback), trigger: "blur" }
    ],
    expressCompany: [
      { validator: (_, value, callback) => validateExpressCompany(value, callback), trigger: "blur" }
    ],
  },
});
@@ -607,7 +657,11 @@
// 查询列表
/** 搜索按钮操作 */
const handleQuery = () => {
  page.current = 1;
  // 只有在点击搜索按钮时才重置页码到第一页
  // 避免表单字段change事件干扰分页
  if (arguments.length === 0) {
    page.current = 1;
  }
   expandedRowKeys.value = [];
  getList();
};
@@ -634,8 +688,12 @@
};
// 获取产品大类tree数据
const getProductOptions = () => {
  productTreeList().then((res) => {
    productOptions.value = convertIdToValue(res);
  // 返回 Promise,便于在编辑产品时等待加载完成
  return productTreeList().then((res) => {
    // 兼容接口返回 { data: [] } 或直接返回数组
    const list = Array.isArray(res) ? res : (res?.data ?? []);
    productOptions.value = convertIdToValue(list);
    return productOptions.value;
  });
};
const formattedNumber = (row, column, cellValue) => {
@@ -711,6 +769,19 @@
    return newItem;
  });
}
// 根据名称反查产品大类 id,便于仅存名称时的反显
function findNodeIdByLabel(nodes, label) {
  if (!label) return null;
  for (let i = 0; i < nodes.length; i++) {
    const node = nodes[i];
    if (node.label === label) return node.value;
    if (node.children && node.children.length > 0) {
      const found = findNodeIdByLabel(node.children, label);
      if (found !== null && found !== undefined) return found;
    }
  }
  return null;
}
// 表格选择数据
const handleSelectionChange = (selection) => {
  // 过滤掉子数据
@@ -767,7 +838,12 @@
    customerOption.value = res;
  });
  form.value.entryPerson = userStore.id;
  if (type !== "add") {
  if (type === "add") {
    // 新增时设置录入日期为当天
    form.value.entryDate = getCurrentDate();
    // 签订日期默认为当天
    form.value.executionDate = getCurrentDate();
  } else {
    currentId.value = row.id;
    getSalesLedgerWithProducts({ id: row.id, type: 1 }).then((res) => {
      form.value = { ...res };
@@ -857,13 +933,40 @@
const productIndex = ref(0);
// 打开产品弹框
const openProductForm = (type, row,index) => {
const openProductForm = async (type, row, index) => {
  productOperationType.value = type;
  productForm.value = {};
  proxy.resetForm("productFormRef");
  // 新增、编辑都需先加载产品树,否则 el-tree-select 无数据
  try {
    await getProductOptions();
  } catch (e) {
    console.error("加载产品树失败", e);
  }
  if (type === "edit") {
    productForm.value = { ...row };
    productIndex.value = index;
    // 编辑时根据产品大类名称反查 tree 节点 id,并加载规格型号列表
    try {
      const options = productOptions.value && productOptions.value.length > 0
        ? productOptions.value
        : await getProductOptions();
      const categoryId = findNodeIdByLabel(options, productForm.value.productCategory);
      if (categoryId) {
        const models = await modelList({ id: categoryId });
        modelOptions.value = models || [];
        // 根据当前规格型号名称反查并设置 productModelId,便于下拉框显示已选值
        const currentModel = (modelOptions.value || []).find(
          (m) => m.model === productForm.value.specificationModel
        );
        if (currentModel) {
          productForm.value.productModelId = currentModel.id;
        }
      }
    } catch (e) {
      // 加载失败时保持可编辑,不中断弹窗
      console.error("加载产品规格型号失败", e);
    }
  }
  productFormVisible.value = true;
  getProductOptions();
@@ -1307,15 +1410,6 @@
   const seconds = String(date.getSeconds()).padStart(2, "0");
   return `${year}/${month}/${day} ${hours}:${minutes}:${seconds}`;
};
// 获取当前日期并格式化为 YYYY-MM-DD
function getCurrentDate() {
  const today = new Date();
  const year = today.getFullYear();
  const month = String(today.getMonth() + 1).padStart(2, "0"); // 月份从0开始
  const day = String(today.getDate()).padStart(2, "0");
  return `${year}-${month}-${day}`;
}
// 计算产品总数量
const getTotalQuantity = (products) => {
  if (!products || products.length === 0) return '0';
@@ -1351,6 +1445,20 @@
  return total.toFixed(2);
};
// 发货类型校验:货车时要求车牌,快递时要求快递公司
const validateShippingCarNumber = (value, callback) => {
  if (deliveryForm.value.shippingType === "truck") {
    if (!value) return callback(new Error("请输入发货车牌号"));
  }
  callback();
};
const validateExpressCompany = (value, callback) => {
  if (deliveryForm.value.shippingType === "express") {
    if (!value) return callback(new Error("请输入快递公司"));
  }
  callback();
};
const mathNum = () => {
  console.log("productForm.value", productForm.value);
  if (!productForm.value.taxInclusiveUnitPrice) {
@@ -1381,6 +1489,7 @@
  const totalPrice = parseFloat(productForm.value.taxInclusiveTotalPrice);
  const quantity = parseFloat(productForm.value.quantity);
  const taxRate = Number(productForm.value.taxRate) || 0;
  if (!totalPrice || !quantity || quantity <= 0) {
    return;
@@ -1392,17 +1501,10 @@
  productForm.value.taxInclusiveUnitPrice = (totalPrice / quantity).toFixed(2);
  // 如果有税率,计算不含税总价
  // if (productForm.value.taxRate) {
  //   productForm.value.taxExclusiveTotalPrice =
  //     proxy.calculateTaxExclusiveTotalPrice(
  //       totalPrice,
  //       productForm.value.taxRate
  //     );
  // }
  productForm.value.taxExclusiveTotalPrice =
      proxy.calculateTaxExclusiveTotalPrice(
          totalPrice,
          productForm.value.taxRate
          taxRate
      );
  isCalculating.value = false;
@@ -1418,7 +1520,7 @@
  const exclusiveTotalPrice = parseFloat(productForm.value.taxExclusiveTotalPrice);
  const quantity = parseFloat(productForm.value.quantity);
  const taxRate = productForm.value.taxRate?parseFloat(productForm.value.taxRate):0;
  const taxRate = Number(productForm.value.taxRate) || 0;
  // if (!exclusiveTotalPrice || !quantity || quantity <= 0 || !taxRate) {
  //   return;
@@ -1450,6 +1552,7 @@
  const quantity = parseFloat(productForm.value.quantity);
  const unitPrice = parseFloat(productForm.value.taxInclusiveUnitPrice);
  const taxRate = Number(productForm.value.taxRate) || 0;
  if (!quantity || quantity <= 0 || !unitPrice) {
    return;
@@ -1461,17 +1564,10 @@
  productForm.value.taxInclusiveTotalPrice = (unitPrice * quantity).toFixed(2);
  // 如果有税率,计算不含税总价
  // if (productForm.value.taxRate) {
  //   productForm.value.taxExclusiveTotalPrice =
  //     proxy.calculateTaxExclusiveTotalPrice(
  //       productForm.value.taxInclusiveTotalPrice,
  //       productForm.value.taxRate
  //     );
  // }
  productForm.value.taxExclusiveTotalPrice =
      proxy.calculateTaxExclusiveTotalPrice(
          productForm.value.taxInclusiveTotalPrice,
          productForm.value.taxRate
          taxRate
      );
  isCalculating.value = false;
@@ -1487,6 +1583,7 @@
  const quantity = parseFloat(productForm.value.quantity);
  const unitPrice = parseFloat(productForm.value.taxInclusiveUnitPrice);
  const taxRate = Number(productForm.value.taxRate) || 0;
  if (!quantity || quantity <= 0 || !unitPrice) {
    return;
@@ -1498,17 +1595,10 @@
  productForm.value.taxInclusiveTotalPrice = (unitPrice * quantity).toFixed(2);
  // 如果有税率,计算不含税总价
  // if (productForm.value.taxRate) {
  //   productForm.value.taxExclusiveTotalPrice =
  //     proxy.calculateTaxExclusiveTotalPrice(
  //       productForm.value.taxInclusiveTotalPrice,
  //       productForm.value.taxRate
  //     );
  // }
  productForm.value.taxExclusiveTotalPrice =
      proxy.calculateTaxExclusiveTotalPrice(
          productForm.value.taxInclusiveTotalPrice,
          productForm.value.taxRate
          taxRate
      );
  isCalculating.value = false;
@@ -1523,7 +1613,7 @@
  if (isCalculating.value) return;
  const inclusiveTotalPrice = parseFloat(productForm.value.taxInclusiveTotalPrice);
  const taxRate = parseFloat(productForm.value.taxRate);
  const taxRate = Number(productForm.value.taxRate) || 0;
  // if (!inclusiveTotalPrice || !taxRate) {
  //   return;
@@ -1557,12 +1647,24 @@
// 打开发货弹框
const openDeliveryForm = (row) => {
  currentDeliveryRow.value = row;
  // getProductInventory({ salesLedgerId: row.id, type:1 }).then((res) => {
  //   currentDeliveryRow.value = row;
  //   deliveryForm.value = {
  //     shippingDate: getCurrentDate(),
  //     shippingCarNumber: "",
  //   };
  //   deliveryFormVisible.value = true;
  // }).catch(err => {
  //   ElMessage.error(err.msg);
  // });
   currentDeliveryRow.value = row;
  deliveryForm.value = {
    shippingType: "truck",
    shippingDate: getCurrentDate(),
    shippingCarNumber: "",
    expressCompany: "",
  };
  deliveryFormVisible.value = true;
   deliveryFormVisible.value = true;
};
// 提交发货表单
@@ -1571,8 +1673,10 @@
    if (valid) {
      addShippingInfo({
        salesLedgerId: currentDeliveryRow.value.id,
        shippingType: deliveryForm.value.shippingType,
        shippingDate: deliveryForm.value.shippingDate,
        shippingCarNumber: deliveryForm.value.shippingCarNumber,
        shippingCarNumber: deliveryForm.value.shippingType === "truck" ? deliveryForm.value.shippingCarNumber : "",
        expressCompany: deliveryForm.value.shippingType === "express" ? deliveryForm.value.expressCompany : "",
      })
        .then(() => {
          proxy.$modal.msgSuccess("发货成功");
@@ -1593,6 +1697,15 @@
  currentDeliveryRow.value = null;
};
// 发货类型切换时清空对应字段
const handleShippingTypeChange = (val) => {
  if (val === "truck") {
    deliveryForm.value.expressCompany = "";
  } else {
    deliveryForm.value.shippingCarNumber = "";
  }
};
onMounted(() => {
   getList();
});