张诺
6 天以前 c8b65690b946b28b179796fbe2f020e732043c58
src/views/salesManagement/salesQuotation/index.vue
@@ -2,22 +2,29 @@
  <div class="app-container">
    <el-card class="box-card">
      <!-- 搜索区域 -->
      <el-row :gutter="20" class="search-row">
      <el-row :gutter="20"
              class="search-row">
        <el-col :span="8">
          <el-input
            v-model="searchForm.quotationNo"
          <el-input v-model="searchForm.quotationNo"
            placeholder="请输入报价单号"
            clearable
            @keyup.enter="handleSearch"
          >
                    @keyup.enter="handleSearch">
            <template #prefix>
              <el-icon><Search /></el-icon>
              <el-icon>
                <Search />
              </el-icon>
            </template>
          </el-input>
        </el-col>
        <el-col :span="8">
          <el-select v-model="searchForm.customer" placeholder="请选择客户" clearable>
                  <el-option v-for="item in customerOption" :key="item.id" :label="item.customerName" :value="item.customerName">
          <el-select v-model="searchForm.customer"
                     placeholder="请选择客户"
                               filterable
                     clearable>
            <el-option v-for="item in customerOption"
                       :key="item.id"
                       :label="item.customerName"
                       :value="item.customerName">
                     {{
                        item.customerName + "——" + item.taxpayerIdentificationNumber
                     }}
@@ -33,30 +40,44 @@
<!--          </el-select>-->
<!--        </el-col>-->
        <el-col :span="8">
          <el-button type="primary" @click="handleSearch">搜索</el-button>
          <el-button type="primary"
                     @click="handleSearch">搜索</el-button>
          <el-button @click="resetSearch">重置</el-button>
          <el-button style="float: right;" type="primary" @click="handleAdd">
          <el-button style="float: right;"
                     type="primary"
                     @click="handleAdd">
            新增报价
          </el-button>
        </el-col>
      </el-row>
      <!-- 报价列表 -->
      <el-table
        :data="filteredList"
      <el-table :data="filteredList"
        style="width: 100%"
        v-loading="loading"
        border
        stripe
        height="calc(100vh - 22em)"
      >
            <el-table-column align="center" label="序号" type="index" width="60" />
        <el-table-column prop="quotationNo" label="报价单号" width="150" />
        <el-table-column prop="customer" label="客户名称" />
        <el-table-column prop="salesperson" label="业务员" width="100" />
        <el-table-column prop="quotationDate" label="报价日期" width="120" />
        <el-table-column prop="validDate" label="有效期至" width="120" />
        <el-table-column prop="totalAmount" label="报价金额" width="120">
                height="calc(100vh - 22em)">
        <el-table-column align="center"
                         label="序号"
                         type="index"
                         width="60" />
        <el-table-column prop="quotationNo"
                         label="报价单号"
                         width="150" />
        <el-table-column prop="customer"
                         label="客户名称" />
        <el-table-column prop="salesperson"
                         label="业务员"
                         width="100" />
        <el-table-column prop="quotationDate"
                         label="报价日期"
                         width="120" />
        <el-table-column prop="validDate"
                         label="有效期至"
                         width="120" />
        <el-table-column prop="totalAmount"
                         label="报价金额"
                         width="120">
          <template #default="scope">
            ¥{{ scope.row.totalAmount.toFixed(2) }}
          </template>
@@ -68,38 +89,60 @@
<!--            </el-tag>-->
<!--          </template>-->
<!--        </el-table-column>-->
        <el-table-column label="操作" width="250" fixed="right" align="center">
        <el-table-column label="操作"
                         width="250"
                         fixed="right"
                         align="center">
          <template #default="scope">
            <el-button link type="primary" @click="handleView(scope.row)">查看</el-button>
            <el-button link type="primary" @click="handleEdit(scope.row)" v-if="scope.row.status === '草稿'">编辑</el-button>
            <el-button link type="danger" @click="handleDelete(scope.row)" v-if="scope.row.status === '草稿'">删除</el-button>
            <el-button link
                       type="primary"
                       @click="handleView(scope.row)">查看</el-button>
            <el-button link
                       type="primary"
                       @click="handleEdit(scope.row)"
                       v-if="scope.row.status === '草稿'">编辑</el-button>
            <el-button link
                       type="danger"
                       @click="handleDelete(scope.row)"
                       v-if="scope.row.status === '草稿'">删除</el-button>
          </template>
        </el-table-column>
      </el-table>
      <!-- 分页 -->
      <pagination
        :total="pagination.total"
      <pagination :total="pagination.total"
        layout="total, sizes, prev, pager, next, jumper"
        :page="pagination.currentPage"
        :limit="pagination.pageSize"
        @pagination="handleCurrentChange"
      />
                  @pagination="handleCurrentChange" />
    </el-card>
    <!-- 新增/编辑对话框 -->
    <el-dialog v-model="dialogVisible" :title="dialogTitle" width="1300px" :close-on-click-modal="false">
      <el-form :model="form" :rules="rules" ref="formRef" label-width="100px">
    <el-dialog v-model="dialogVisible"
               :title="dialogTitle"
               width="1300px"
               :close-on-click-modal="false">
      <el-form :model="form"
               :rules="rules"
               ref="formRef"
               label-width="100px">
        <!-- 基本信息 -->
        <el-card class="form-card" shadow="never">
        <el-card class="form-card"
                 shadow="never">
          <template #header>
            <span class="card-title">基本信息</span>
          </template>
          <el-row :gutter="20">
            <el-col :span="12">
              <el-form-item label="客户名称" prop="customer">
                <el-select v-model="form.customer" placeholder="请选择客户" style="width: 100%" @change="handleCustomerChange">
                           <el-option v-for="item in customerOption" :key="item.id" :label="item.customerName" :value="item.customerName">
              <el-form-item label="客户名称"
                            prop="customer">
                <el-select v-model="form.customer"
                           placeholder="请选择客户"
                                        filterable
                           style="width: 100%"
                           @change="handleCustomerChange">
                  <el-option v-for="item in customerOption"
                             :key="item.id"
                             :label="item.customerName"
                             :value="item.customerName">
                              {{
                                 item.customerName + "——" + item.taxpayerIdentificationNumber
                              }}
@@ -108,9 +151,15 @@
              </el-form-item>
            </el-col>
            <el-col :span="12">
              <el-form-item label="业务员" prop="salesperson">
                <el-select v-model="form.salesperson" placeholder="请选择业务员" style="width: 100%">
                           <el-option v-for="item in userList" :key="item.nickName" :label="item.nickName"
              <el-form-item label="业务员"
                            prop="salesperson">
                <el-select v-model="form.salesperson"
                                        filterable
                           placeholder="请选择业务员"
                           style="width: 100%">
                  <el-option v-for="item in userList"
                             :key="item.nickName"
                             :label="item.nickName"
                                           :value="item.nickName" />
                </el-select>
              </el-form-item>
@@ -118,176 +167,225 @@
          </el-row>
          <el-row :gutter="20">
            <el-col :span="12">
              <el-form-item label="报价日期" prop="quotationDate">
                <el-date-picker
                  v-model="form.quotationDate"
              <el-form-item label="报价日期"
                            prop="quotationDate">
                <el-date-picker v-model="form.quotationDate"
                  type="date"
                  placeholder="选择报价日期"
                  style="width: 100%"
                  format="YYYY-MM-DD"
                  value-format="YYYY-MM-DD"
                />
                                value-format="YYYY-MM-DD" />
              </el-form-item>
            </el-col>
            <el-col :span="12">
              <el-form-item label="有效期至" prop="validDate">
                <el-date-picker
                  v-model="form.validDate"
              <el-form-item label="有效期至"
                            prop="validDate">
                <el-date-picker v-model="form.validDate"
                  type="date"
                  placeholder="选择有效期"
                  style="width: 100%"
                  format="YYYY-MM-DD"
                  value-format="YYYY-MM-DD"
                />
                                value-format="YYYY-MM-DD" />
              </el-form-item>
            </el-col>
          </el-row>
          <el-row :gutter="20">
            <el-col :span="12">
              <el-form-item label="交货期" prop="deliveryPeriod">
                <el-date-picker
                  v-model="form.deliveryPeriod"
              <el-form-item label="交货期"
                            prop="deliveryPeriod">
                <el-date-picker v-model="form.deliveryPeriod"
                  type="date"
                  placeholder="选择交货期"
                  style="width: 100%"
                  format="YYYY-MM-DD"
                  value-format="YYYY-MM-DD"
                />
                                value-format="YYYY-MM-DD" />
              </el-form-item>
            </el-col>
          </el-row>
        </el-card>
        <!-- 产品信息 -->
        <el-card class="form-card" shadow="never">
        <el-card class="form-card"
                 shadow="never">
          <template #header>
            <div class="card-header">
              <span class="card-title">产品信息</span>
              <el-button type="primary" size="small" @click="addProduct">添加产品</el-button>
              <el-button type="primary"
                         size="small"
                         @click="addProduct">添加产品</el-button>
            </div>
          </template>
          <el-table :data="form.products" border style="width: 100%">
            <el-table-column prop="product" label="产品名称" width="200">
          <el-table :data="form.products"
                    border
                    style="width: 100%">
            <el-table-column prop="product"
                             label="产品名称"
                             width="200">
              <template #default="scope">
                        <el-tree-select
                           v-model="scope.row.productId"
                <el-tree-select v-model="scope.row.productId"
                           placeholder="请选择"
                           clearable
                           check-strictly
                           @change="getModels($event, scope.row)"
                           :data="productOptions"
                           :render-after-expand="false"
                           style="width: 100%"
                        />
                                style="width: 100%" />
              </template>
            </el-table-column>
            <el-table-column prop="specification" label="规格型号" width="150">
            <el-table-column prop="specification"
                             label="规格型号"
                             width="150">
              <template #default="scope">
                        <el-select
                           v-model="scope.row.specificationId"
                <el-select v-model="scope.row.specificationId"
                                        filterable
                           placeholder="请选择"
                           clearable
                           @change="getProductModel($event, scope.row)"
                        >
                           <el-option
                              v-for="item in modelOptions"
                           @change="getProductModel($event, scope.row)">
                  <el-option v-for="item in modelOptions"
                              :key="item.id"
                              :label="item.model"
                              :value="item.id"
                           />
                             :value="item.id" />
                        </el-select>
              </template>
            </el-table-column>
            <el-table-column prop="quantity" label="数量">
            <el-table-column prop="quantity"
                             label="数量">
              <template #default="scope">
                <el-input-number v-model="scope.row.quantity" :min="1" :precision="0" style="width: 100%" />
                <el-input-number v-model="scope.row.quantity"
                                 :min="1"
                                 :precision="0"
                                 style="width: 100%" />
              </template>
            </el-table-column>
            <el-table-column prop="unit" label="单位">
            <el-table-column prop="unit"
                             label="单位">
              <template #default="scope">
                <el-input v-model="scope.row.unit" placeholder="单位" />
                <el-input v-model="scope.row.unit"
                          placeholder="单位" />
              </template>
            </el-table-column>
            <el-table-column prop="unitPrice" label="单价">
            <el-table-column prop="unitPrice"
                             label="单价">
              <template #default="scope">
                <el-input-number v-model="scope.row.unitPrice" :min="0" :precision="2" style="width: 100%" @change="calculateAmount(scope.row)" />
                <el-input-number v-model="scope.row.unitPrice"
                                 :min="0"
                                 :precision="2"
                                 style="width: 100%"
                                 @change="calculateAmount(scope.row)" />
              </template>
            </el-table-column>
            <el-table-column prop="amount" label="金额" width="120">
            <el-table-column prop="amount"
                             label="金额"
                             width="120">
              <template #default="scope">
                <span>¥{{ scope.row.amount.toFixed(2) }}</span>
              </template>
            </el-table-column>
            <el-table-column label="操作" width="80" align="center">
            <el-table-column label="操作"
                             width="80"
                             align="center">
              <template #default="scope">
                <el-button link type="danger" @click="removeProduct(scope.$index)">删除</el-button>
                <el-button link
                           type="danger"
                           @click="removeProduct(scope.$index)">删除</el-button>
              </template>
            </el-table-column>
          </el-table>
        </el-card>
        <!-- 费用信息 -->
        <el-card class="form-card" shadow="never">
        <el-card class="form-card"
                 shadow="never">
          <template #header>
            <span class="card-title">费用信息</span>
          </template>
          <el-row :gutter="20">
            <el-col :span="8">
              <el-form-item label="产品小计">
                <el-input-number v-model="form.subtotal" :precision="2" :min="0" style="width: 100%" readonly />
                <el-input-number v-model="form.subtotal"
                                 :precision="2"
                                 :min="0"
                                 style="width: 100%"
                                 readonly />
              </el-form-item>
            </el-col>
            <el-col :span="8">
              <el-form-item label="运费">
                <el-input-number v-model="form.freight" :precision="2" :min="0" style="width: 100%" @change="calculateTotal" />
                <el-input-number v-model="form.freight"
                                 :precision="2"
                                 :min="0"
                                 style="width: 100%"
                                 @change="calculateTotal" />
              </el-form-item>
            </el-col>
            <el-col :span="8">
              <el-form-item label="其他费用">
                <el-input-number v-model="form.otherFee" :precision="2" :min="0" style="width: 100%" @change="calculateTotal" />
                <el-input-number v-model="form.otherFee"
                                 :precision="2"
                                 :min="0"
                                 style="width: 100%"
                                 @change="calculateTotal" />
              </el-form-item>
            </el-col>
          </el-row>
          <el-row :gutter="20">
            <el-col :span="8">
              <el-form-item label="折扣率(%)">
                <el-input-number v-model="form.discountRate" :precision="2" :min="0" :max="100" style="width: 100%" @change="calculateTotal" />
                <el-input-number v-model="form.discountRate"
                                 :precision="2"
                                 :min="0"
                                 :max="100"
                                 style="width: 100%"
                                 @change="calculateTotal" />
              </el-form-item>
            </el-col>
            <el-col :span="8">
              <el-form-item label="折扣金额">
                <el-input-number v-model="form.discountAmount" :precision="2" :min="0" style="width: 100%" readonly />
                <el-input-number v-model="form.discountAmount"
                                 :precision="2"
                                 :min="0"
                                 style="width: 100%"
                                 readonly />
              </el-form-item>
            </el-col>
            <el-col :span="8">
              <el-form-item label="报价总额">
                <el-input-number v-model="form.totalAmount" :precision="2" :min="0" style="width: 100%" readonly />
                <el-input-number v-model="form.totalAmount"
                                 :precision="2"
                                 :min="0"
                                 style="width: 100%"
                                 readonly />
              </el-form-item>
            </el-col>
          </el-row>
        </el-card>
        <!-- 备注信息 -->
        <el-card class="form-card" shadow="never">
        <el-card class="form-card"
                 shadow="never">
          <template #header>
            <span class="card-title">备注信息</span>
          </template>
          <el-form-item label="备注" prop="remark">
            <el-input type="textarea" v-model="form.remark" placeholder="请输入备注信息" rows="3"></el-input>
          <el-form-item label="备注"
                        prop="remark">
            <el-input type="textarea"
                      v-model="form.remark"
                      placeholder="请输入备注信息"
                      rows="3"></el-input>
          </el-form-item>
        </el-card>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary"
                     @click="handleSubmit">确 定</el-button>
          <el-button @click="dialogVisible = false">取 消</el-button>
          <el-button type="primary" @click="handleSubmit">确 定</el-button>
        </div>
      </template>
    </el-dialog>
    <!-- 查看详情对话框 -->
    <el-dialog v-model="viewDialogVisible" title="报价详情" width="800px">
      <el-descriptions :column="2" border>
    <el-dialog v-model="viewDialogVisible"
               title="报价详情"
               width="800px">
      <el-descriptions :column="2"
                       border>
        <el-descriptions-item label="报价单号">{{ currentQuotation.quotationNo }}</el-descriptions-item>
        <el-descriptions-item label="客户名称">{{ currentQuotation.customer }}</el-descriptions-item>
        <el-descriptions-item label="业务员">{{ currentQuotation.salesperson }}</el-descriptions-item>
@@ -297,32 +395,40 @@
<!--        <el-descriptions-item label="报价状态">-->
<!--          <el-tag :type="getStatusType(currentQuotation.status)">{{ currentQuotation.status }}</el-tag>-->
<!--        </el-descriptions-item>-->
        <el-descriptions-item label="报价总额" :span="2">
        <el-descriptions-item label="报价总额"
                              :span="2">
          <span style="font-size: 18px; color: #e6a23c; font-weight: bold;">¥{{ currentQuotation.totalAmount?.toFixed(2) }}</span>
        </el-descriptions-item>
      </el-descriptions>
      <div style="margin-top: 20px;">
        <h4>产品明细</h4>
        <el-table :data="currentQuotation.products" border style="width: 100%">
          <el-table-column prop="product" label="产品名称" />
          <el-table-column prop="specification" label="规格型号" />
          <el-table-column prop="quantity" label="数量" />
          <el-table-column prop="unit" label="单位" />
          <el-table-column prop="unitPrice" label="单价">
        <el-table :data="currentQuotation.products"
                  border
                  style="width: 100%">
          <el-table-column prop="product"
                           label="产品名称" />
          <el-table-column prop="specification"
                           label="规格型号" />
          <el-table-column prop="quantity"
                           label="数量" />
          <el-table-column prop="unit"
                           label="单位" />
          <el-table-column prop="unitPrice"
                           label="单价">
            <template #default="scope">
              ¥{{ scope.row.unitPrice.toFixed(2) }}
            </template>
          </el-table-column>
          <el-table-column prop="amount" label="金额">
          <el-table-column prop="amount"
                           label="金额">
            <template #default="scope">
              ¥{{ scope.row.amount.toFixed(2) }}
            </template>
          </el-table-column>
        </el-table>
      </div>
      <div v-if="currentQuotation.remark" style="margin-top: 20px;">
      <div v-if="currentQuotation.remark"
           style="margin-top: 20px;">
        <h4>备注</h4>
        <p>{{ currentQuotation.remark }}</p>
      </div>
@@ -331,130 +437,141 @@
</template>
<script setup>
import { ref, reactive, computed, onMounted, markRaw, shallowRef } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Search } from '@element-plus/icons-vue'
import Pagination from '@/components/PIMTable/Pagination.vue'
import {getQuotationList,addQuotation,updateQuotation,deleteQuotation} from '@/api/salesManagement/salesQuotation.js'
  import { ref, reactive, computed, onMounted, markRaw, shallowRef } from "vue";
  import { ElMessage, ElMessageBox } from "element-plus";
  import { Search } from "@element-plus/icons-vue";
  import Pagination from "@/components/PIMTable/Pagination.vue";
  import {
    getQuotationList,
    addQuotation,
    updateQuotation,
    deleteQuotation,
  } from "@/api/salesManagement/salesQuotation.js";
import {userListNoPage} from "@/api/system/user.js";
import {customerList} from "@/api/salesManagement/salesLedger.js";
import {modelList, productTreeList} from "@/api/basicData/product.js";
// 响应式数据
const loading = ref(false)
  const loading = ref(false);
const searchForm = reactive({
  quotationNo: '',
  customer: '',
  status: ''
})
    quotationNo: "",
    customer: "",
    status: "",
  });
const quotationList = ref([])
  const quotationList = ref([]);
const productOptions = ref([]);
const modelOptions = ref([]);
const pagination = reactive({
  total: 3,
  currentPage: 1,
  pageSize: 100
})
    pageSize: 100,
  });
const dialogVisible = ref(false)
const viewDialogVisible = ref(false)
const dialogTitle = ref('新增报价')
  const dialogVisible = ref(false);
  const viewDialogVisible = ref(false);
  const dialogTitle = ref("新增报价");
const form = reactive({
  quotationNo: '',
  customer: '',
  salesperson: '',
  quotationDate: '',
  validDate: '',
  paymentMethod: '',
  deliveryPeriod: '',
  status: '草稿',
  remark: '',
    quotationNo: "",
    customer: "",
    salesperson: "",
    quotationDate: "",
    validDate: "",
    paymentMethod: "",
    deliveryPeriod: "",
    status: "草稿",
    remark: "",
  products: [],
  subtotal: 0,
  freight: 0,
  otherFee: 0,
  discountRate: 0,
  discountAmount: 0,
  totalAmount: 0
})
    totalAmount: 0,
  });
const rules = {
  customer: [{ required: true, message: '请选择客户', trigger: 'change' }],
  salesperson: [{ required: true, message: '请选择业务员', trigger: 'change' }],
  quotationDate: [{ required: true, message: '请选择报价日期', trigger: 'change' }],
  validDate: [{ required: true, message: '请选择有效期', trigger: 'change' }],
  deliveryPeriod: [{ required: true, message: '请选择交货期', trigger: 'change' }]
}
    customer: [{ required: true, message: "请选择客户", trigger: "change" }],
    salesperson: [{ required: true, message: "请选择业务员", trigger: "change" }],
    quotationDate: [
      { required: true, message: "请选择报价日期", trigger: "change" },
    ],
    validDate: [{ required: true, message: "请选择有效期", trigger: "change" }],
    deliveryPeriod: [
      { required: true, message: "请选择交货期", trigger: "change" },
    ],
  };
const userList = ref([]);
const customerOption = ref([]);
const isEdit = ref(false)
const editId = ref(null)
const currentQuotation = ref({})
const formRef = ref()
  const isEdit = ref(false);
  const editId = ref(null);
  const currentQuotation = ref({});
  const formRef = ref();
// 计算属性
const filteredList = computed(() => {
  let list = quotationList.value
    let list = quotationList.value;
  if (searchForm.quotationNo) {
    list = list.filter(item => item.quotationNo.includes(searchForm.quotationNo))
      list = list.filter(item =>
        item.quotationNo.includes(searchForm.quotationNo)
      );
  }
  if (searchForm.customer) {
    list = list.filter(item => item.customer === searchForm.customer)
      list = list.filter(item => item.customer === searchForm.customer);
  }
  if (searchForm.status) {
    list = list.filter(item => item.status === searchForm.status)
      list = list.filter(item => item.status === searchForm.status);
  }
  return list
})
    return list;
  });
// 方法
const getStatusType = (status) => {
  const getStatusType = status => {
  const statusMap = {
    '草稿': 'info',
    '已发送': 'primary',
    '客户确认': 'success',
    '已过期': 'danger'
  }
  return statusMap[status] || 'info'
}
      草稿: "info",
      已发送: "primary",
      客户确认: "success",
      已过期: "danger",
    };
    return statusMap[status] || "info";
  };
const resetSearch = () => {
  searchForm.quotationNo = ''
  searchForm.customer = ''
  searchForm.status = ''
}
    searchForm.quotationNo = "";
    searchForm.customer = "";
    searchForm.status = "";
  };
const handleAdd = async () => {
  dialogTitle.value = '新增报价'
  isEdit.value = false
  resetForm()
  dialogVisible.value = true
    dialogTitle.value = "新增报价";
    isEdit.value = false;
    resetForm();
    dialogVisible.value = true;
   let userLists = await userListNoPage();
   // 只复制需要的字段,避免将组件引用放入响应式对象
   userList.value = (userLists.data || []).map(item => ({
    userId: item.userId,
    nickName: item.nickName || '',
    userName: item.userName || ''
      nickName: item.nickName || "",
      userName: item.userName || "",
  }));
   getProductOptions();
   customerList().then((res) => {
    customerList().then(res => {
      // 只复制需要的字段,避免将组件引用放入响应式对象
      customerOption.value = (Array.isArray(res) ? res : []).map(item => ({
      id: item.id,
      customerName: item.customerName || '',
      taxpayerIdentificationNumber: item.taxpayerIdentificationNumber || ''
    }))
        customerName: item.customerName || "",
        taxpayerIdentificationNumber: item.taxpayerIdentificationNumber || "",
      }));
   });
}
  };
const getProductOptions = () => {
   productTreeList().then((res) => {
    productTreeList().then(res => {
      productOptions.value = convertIdToValue(res);
   });
};
function convertIdToValue(data) {
   return data.map((item) => {
    return data.map(item => {
      const { id, children, ...rest } = item;
      const newItem = {
         ...rest,
@@ -471,12 +588,12 @@
   if (!row) return;
   // 如果清空选择,则清空相关字段
   if (!value) {
      row.productId = '';
      row.product = '';
      row.productId = "";
      row.product = "";
      modelOptions.value = [];
      row.specificationId = '';
      row.specification = '';
      row.unit = '';
      row.specificationId = "";
      row.specification = "";
      row.unit = "";
      return;
   }
   // 更新 productId(v-model 已经自动更新,这里确保一致性)
@@ -487,7 +604,7 @@
      row.product = label;
   }
   // 获取规格型号列表
   modelList({ id: value }).then((res) => {
    modelList({ id: value }).then(res => {
      modelOptions.value = res || [];
   });
};
@@ -495,20 +612,20 @@
   if (!row) return;
   // 如果清空选择,则清空相关字段
   if (!value) {
      row.specificationId = '';
      row.specification = '';
      row.unit = '';
      row.specificationId = "";
      row.specification = "";
      row.unit = "";
      return;
   }
   // 更新 specificationId(v-model 已经自动更新,这里确保一致性)
   row.specificationId = value;
   const index = modelOptions.value.findIndex((item) => item.id === value);
    const index = modelOptions.value.findIndex(item => item.id === value);
   if (index !== -1) {
      row.specification = modelOptions.value[index].model;
      row.unit = modelOptions.value[index].unit;
   } else {
      row.specification = '';
      row.unit = '';
      row.specification = "";
      row.unit = "";
   }
};
const findNodeById = (nodes, productId) => {
@@ -525,181 +642,192 @@
   }
   return null; // 没有找到节点,返回null
};
const handleView = (row) => {
  const handleView = row => {
  // 只复制需要的字段,避免将组件引用放入响应式对象
  currentQuotation.value = {
    quotationNo: row.quotationNo || '',
    customer: row.customer || '',
    salesperson: row.salesperson || '',
    quotationDate: row.quotationDate || '',
    validDate: row.validDate || '',
    paymentMethod: row.paymentMethod || '',
    deliveryPeriod: row.deliveryPeriod || '',
    status: row.status || '',
    remark: row.remark || '',
    products: row.products ? row.products.map(product => ({
      productId: product.productId || '',
      product: product.product || product.productName || '',
      specificationId: product.specificationId || '',
      specification: product.specification || '',
      quotationNo: row.quotationNo || "",
      customer: row.customer || "",
      salesperson: row.salesperson || "",
      quotationDate: row.quotationDate || "",
      validDate: row.validDate || "",
      paymentMethod: row.paymentMethod || "",
      deliveryPeriod: row.deliveryPeriod || "",
      status: row.status || "",
      remark: row.remark || "",
      products: row.products
        ? row.products.map(product => ({
            productId: product.productId || "",
            product: product.product || product.productName || "",
            specificationId: product.specificationId || "",
            specification: product.specification || "",
      quantity: product.quantity || 0,
      unit: product.unit || '',
            unit: product.unit || "",
      unitPrice: product.unitPrice || 0,
      amount: product.amount || 0
    })) : [],
    totalAmount: row.totalAmount || 0
  }
  viewDialogVisible.value = true
}
            amount: product.amount || 0,
          }))
        : [],
      totalAmount: row.totalAmount || 0,
    };
    viewDialogVisible.value = true;
  };
const handleEdit = (row) => {
  dialogTitle.value = '编辑报价'
  isEdit.value = true
  editId.value = row.id
  const handleEdit = row => {
    dialogTitle.value = "编辑报价";
    isEdit.value = true;
    editId.value = row.id;
  // 只复制需要的字段,避免将组件引用放入响应式对象
  form.quotationNo = row.quotationNo || ''
  form.customer = row.customer || ''
  form.salesperson = row.salesperson || ''
  form.quotationDate = row.quotationDate || ''
  form.validDate = row.validDate || ''
  form.paymentMethod = row.paymentMethod || ''
  form.deliveryPeriod = row.deliveryPeriod || ''
  form.status = row.status || '草稿'
  form.remark = row.remark || ''
  form.products = row.products ? row.products.map(product => ({
    productId: product.productId || '',
    product: product.product || product.productName || '',
    specificationId: product.specificationId || '',
    specification: product.specification || '',
    form.quotationNo = row.quotationNo || "";
    form.customer = row.customer || "";
    form.salesperson = row.salesperson || "";
    form.quotationDate = row.quotationDate || "";
    form.validDate = row.validDate || "";
    form.paymentMethod = row.paymentMethod || "";
    form.deliveryPeriod = row.deliveryPeriod || "";
    form.status = row.status || "草稿";
    form.remark = row.remark || "";
    form.products = row.products
      ? row.products.map(product => ({
          productId: product.productId || "",
          product: product.product || product.productName || "",
          specificationId: product.specificationId || "",
          specification: product.specification || "",
    quantity: product.quantity || 0,
    unit: product.unit || '',
          unit: product.unit || "",
    unitPrice: product.unitPrice || 0,
    amount: product.amount || 0
  })) : []
  form.subtotal = row.subtotal || 0
  form.freight = row.freight || 0
  form.otherFee = row.otherFee || 0
  form.discountRate = row.discountRate || 0
  form.discountAmount = row.discountAmount || 0
  form.totalAmount = row.totalAmount || 0
  dialogVisible.value = true
}
          amount: product.amount || 0,
        }))
      : [];
    form.subtotal = row.subtotal || 0;
    form.freight = row.freight || 0;
    form.otherFee = row.otherFee || 0;
    form.discountRate = row.discountRate || 0;
    form.discountAmount = row.discountAmount || 0;
    form.totalAmount = row.totalAmount || 0;
    dialogVisible.value = true;
  };
const handleDelete = (row) => {
  ElMessageBox.confirm('确认删除该报价单吗?', '提示', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    type: 'warning'
  const handleDelete = row => {
    ElMessageBox.confirm("确认删除该报价单吗?", "提示", {
      confirmButtonText: "确定",
      cancelButtonText: "取消",
      type: "warning",
  }).then(() => {
    const index = quotationList.value.findIndex(item => item.id === row.id)
      const index = quotationList.value.findIndex(item => item.id === row.id);
    if (index > -1) {
      deleteQuotation(row.id).then(res=>{
        // console.log(res)
        if(res.code===200){
          ElMessage.success('删除成功')
          handleSearch()
            ElMessage.success("删除成功");
            handleSearch();
        }
      })
        });
      // quotationList.value.splice(index, 1)
      // pagination.total--
      // ElMessage.success('删除成功')
    }
  })
}
    });
  };
const resetForm = () => {
  form.customer = ''
  form.salesperson = ''
  form.quotationDate = ''
  form.validDate = ''
  form.paymentMethod = ''
  form.deliveryPeriod = ''
  form.status = '草稿'
  form.remark = ''
  form.products = []
  form.subtotal = 0
  form.freight = 0
  form.otherFee = 0
  form.discountRate = 0
  form.discountAmount = 0
  form.totalAmount = 0
}
    form.customer = "";
    form.salesperson = "";
    form.quotationDate = "";
    form.validDate = "";
    form.paymentMethod = "";
    form.deliveryPeriod = "";
    form.status = "草稿";
    form.remark = "";
    form.products = [];
    form.subtotal = 0;
    form.freight = 0;
    form.otherFee = 0;
    form.discountRate = 0;
    form.discountAmount = 0;
    form.totalAmount = 0;
  };
const addProduct = () => {
  form.products.push({
    productId: '',
    product: '',
    productName: '',
    specificationId: '',
    specification: '',
      productId: "",
      product: "",
      productName: "",
      specificationId: "",
      specification: "",
    quantity: 1,
    unit: '',
      unit: "",
    unitPrice: 0,
    amount: 0
  })
}
      amount: 0,
    });
  };
const removeProduct = (index) => {
  form.products.splice(index, 1)
  calculateSubtotal()
}
  const removeProduct = index => {
    form.products.splice(index, 1);
    calculateSubtotal();
  };
const calculateAmount = (product) => {
  product.amount = product.quantity * product.unitPrice
  calculateSubtotal()
}
  const calculateAmount = product => {
    product.amount = product.quantity * product.unitPrice;
    calculateSubtotal();
  };
const calculateSubtotal = () => {
  form.subtotal = form.products.reduce((sum, product) => sum + product.amount, 0)
  calculateTotal()
}
    form.subtotal = form.products.reduce(
      (sum, product) => sum + product.amount,
      0
    );
    calculateTotal();
  };
const calculateTotal = () => {
  form.discountAmount = form.subtotal * (form.discountRate / 100)
  form.totalAmount = form.subtotal + form.freight + form.otherFee - form.discountAmount
}
    form.discountAmount = form.subtotal * (form.discountRate / 100);
    form.totalAmount =
      form.subtotal + form.freight + form.otherFee - form.discountAmount;
  };
const handleCustomerChange = () => {
  // 可以根据客户信息自动填充一些默认值
}
  };
const handleSubmit = () => {
  formRef.value.validate((valid) => {
    formRef.value.validate(valid => {
    if (valid) {
      if (form.products.length === 0) {
        ElMessage.warning('请至少添加一个产品')
        return
          ElMessage.warning("请至少添加一个产品");
          return;
      }
      
      if (isEdit.value) {
        // 编辑
        const index = quotationList.value.findIndex(item => item.id === editId.value)
          const index = quotationList.value.findIndex(
            item => item.id === editId.value
          );
        if (index > -1) {
          updateQuotation(form).then(res=>{
            // console.log(res)
            if(res.code===200){
              ElMessage.success('编辑成功')
              dialogVisible.value = false
              handleSearch()
                ElMessage.success("编辑成功");
                dialogVisible.value = false;
                handleSearch();
            }
          })
            });
          // quotationList.value[index] = { ...form, id: editId.value }
          // ElMessage.success('编辑成功')
        }
      } else {
        // 新增
        // const newId = Math.max(...quotationList.value.map(item => item.id)) + 1
        form.quotationNo = `QT${new Date().getFullYear()}${String(new Date().getMonth() + 1).padStart(2, '0')}${String(new Date().getDate()).padStart(2, '0')}`
          form.quotationNo = `QT${new Date().getFullYear()}${String(
            new Date().getMonth() + 1
          ).padStart(2, "0")}${String(new Date().getDate()).padStart(2, "0")}`;
        addQuotation(form).then(res=>{
          // console.log(res)
          if(res.code===200){
            ElMessage.success('新增成功')
            dialogVisible.value = false
            handleSearch()
              ElMessage.success("新增成功");
              dialogVisible.value = false;
              handleSearch();
          }
        })
          });
        // quotationList.value.push({
        //   ...form,
@@ -709,68 +837,69 @@
        // pagination.total++
        // ElMessage.success('新增成功')
      }
      }
    });
  };
      
    }
  })
}
const handleCurrentChange = (val) => {
  pagination.currentPage = val.page
  pagination.pageSize = val.limit
}
  const handleCurrentChange = val => {
    pagination.currentPage = val.page;
    pagination.pageSize = val.limit;
  };
const handleSearch = ()=>{
  const params = {
    page:pagination,
    ...searchForm
  }
      ...searchForm,
    };
  getQuotationList(params).then(res=>{
    // console.log(res)
    if(res.code===200){
      // 只复制需要的字段,避免将组件引用或其他对象放入响应式对象
      quotationList.value = (res.data.records || []).map(item => ({
        id: item.id,
        quotationNo: item.quotationNo || '',
        customer: item.customer || '',
        salesperson: item.salesperson || '',
        quotationDate: item.quotationDate || '',
        validDate: item.validDate || '',
        paymentMethod: item.paymentMethod || '',
        deliveryPeriod: item.deliveryPeriod || '',
        status: item.status || '草稿',
        remark: item.remark || '',
        products: item.products ? item.products.map(product => ({
          productId: product.productId || '',
          product: product.product || product.productName || '',
          specificationId: product.specificationId || '',
          specification: product.specification || '',
          quotationNo: item.quotationNo || "",
          customer: item.customer || "",
          salesperson: item.salesperson || "",
          quotationDate: item.quotationDate || "",
          validDate: item.validDate || "",
          paymentMethod: item.paymentMethod || "",
          deliveryPeriod: item.deliveryPeriod || "",
          status: item.status || "草稿",
          remark: item.remark || "",
          products: item.products
            ? item.products.map(product => ({
                productId: product.productId || "",
                product: product.product || product.productName || "",
                specificationId: product.specificationId || "",
                specification: product.specification || "",
          quantity: product.quantity || 0,
          unit: product.unit || '',
                unit: product.unit || "",
          unitPrice: product.unitPrice || 0,
          amount: product.amount || 0
        })) : [],
                amount: product.amount || 0,
              }))
            : [],
        subtotal: item.subtotal || 0,
        freight: item.freight || 0,
        otherFee: item.otherFee || 0,
        discountRate: item.discountRate || 0,
        discountAmount: item.discountAmount || 0,
        totalAmount: item.totalAmount || 0
      }))
      pagination.total = res.data.total
          totalAmount: item.totalAmount || 0,
        }));
        pagination.total = res.data.total;
    }
  })
   customerList().then((res) => {
    });
    customerList().then(res => {
      // 只复制需要的字段,避免将组件引用放入响应式对象
      customerOption.value = (Array.isArray(res) ? res : []).map(item => ({
      id: item.id,
      customerName: item.customerName || '',
      taxpayerIdentificationNumber: item.taxpayerIdentificationNumber || ''
    }))
        customerName: item.customerName || "",
        taxpayerIdentificationNumber: item.taxpayerIdentificationNumber || "",
      }));
   });
}
  };
onMounted(()=>{
  handleSearch()
})
    handleSearch();
  });
</script>
<style scoped>