Ver Fonte

✨ CRM:完善合同的新增、修改需求

YunaiV há 1 ano atrás
pai
commit
9d44b9acaa

+ 0 - 2
src/views/crm/business/BusinessForm.vue

@@ -155,7 +155,6 @@ const formData = ref({
   id: undefined,
   name: undefined,
   customerId: undefined,
-  contactNextTime: undefined,
   ownerUserId: undefined,
   statusTypeId: undefined,
   dealTime: undefined,
@@ -273,7 +272,6 @@ const resetForm = () => {
     id: undefined,
     name: undefined,
     customerId: undefined,
-    contactNextTime: undefined,
     ownerUserId: undefined,
     statusTypeId: undefined,
     dealTime: undefined,

+ 1 - 1
src/views/crm/business/components/BusinessProductForm.vue

@@ -95,7 +95,7 @@
 </template>
 <script setup lang="ts">
 import * as ProductApi from '@/api/crm/product'
-import { erpCountInputFormatter, erpPriceInputFormatter, erpPriceMultiply } from '@/utils'
+import { erpPriceInputFormatter, erpPriceMultiply } from '@/utils'
 import { DICT_TYPE } from '@/utils/dict'
 
 const props = defineProps<{

+ 165 - 101
src/views/crm/contract/ContractForm.vue

@@ -1,40 +1,58 @@
 <template>
-  <Dialog v-model="dialogVisible" :title="dialogTitle" width="820">
+  <Dialog v-model="dialogVisible" :title="dialogTitle" width="1280">
     <el-form
       ref="formRef"
       v-loading="formLoading"
       :model="formData"
       :rules="formRules"
-      label-width="110px"
+      label-width="120px"
     >
-      <el-row :gutter="20">
-        <el-col :span="12">
+      <el-row>
+        <el-col :span="8">
           <el-form-item label="合同编号" prop="no">
-            <el-input v-model="formData.no" placeholder="请输入合同编号" />
+            <el-input disabled v-model="formData.no" placeholder="保存时自动生成" />
           </el-form-item>
         </el-col>
-        <el-col :span="12">
+        <el-col :span="8">
           <el-form-item label="合同名称" prop="name">
             <el-input v-model="formData.name" placeholder="请输入合同名称" />
           </el-form-item>
         </el-col>
-        <el-col :span="12">
+        <el-col :span="8">
+          <el-form-item label="负责人" prop="ownerUserId">
+            <el-select
+              v-model="formData.ownerUserId"
+              :disabled="formType !== 'create'"
+              class="w-1/1"
+            >
+              <el-option
+                v-for="item in userOptions"
+                :key="item.id"
+                :label="item.nickname"
+                :value="item.id"
+              />
+            </el-select>
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row>
+        <el-col :span="8">
           <el-form-item label="客户名称" prop="customerId">
-            <el-select v-model="formData.customerId">
+            <el-select v-model="formData.customerId" placeholder="请选择客户" class="w-1/1">
               <el-option
                 v-for="item in customerList"
                 :key="item.id"
                 :label="item.name"
-                :value="item.id!"
+                :value="item.id"
               />
             </el-select>
           </el-form-item>
         </el-col>
-        <el-col :span="12">
+        <el-col :span="8">
           <el-form-item label="商机名称" prop="businessId">
-            <el-select v-model="formData.businessId">
+            <el-select :disabled="!formData.customerId" v-model="formData.businessId" class="w-1/1">
               <el-option
-                v-for="item in businessList"
+                v-for="item in getBusinessOptions"
                 :key="item.id"
                 :label="item.name"
                 :value="item.id!"
@@ -42,46 +60,48 @@
             </el-select>
           </el-form-item>
         </el-col>
-        <el-col :span="12">
+      </el-row>
+      <el-row>
+        <el-col :span="8">
           <el-form-item label="下单日期" prop="orderDate">
             <el-date-picker
               v-model="formData.orderDate"
               placeholder="选择下单日期"
               type="date"
               value-format="x"
+              class="!w-1/1"
             />
           </el-form-item>
         </el-col>
-        <el-col :span="12">
-          <el-form-item label="合同金额" prop="price">
-            <el-input v-model="formData.price" placeholder="请输入合同金额" />
-          </el-form-item>
-        </el-col>
-        <el-col :span="12">
+        <el-col :span="8">
           <el-form-item label="开始时间" prop="startTime">
             <el-date-picker
               v-model="formData.startTime"
               placeholder="选择开始时间"
               type="date"
               value-format="x"
+              class="!w-1/1"
             />
           </el-form-item>
         </el-col>
-        <el-col :span="12">
+        <el-col :span="8">
           <el-form-item label="结束时间" prop="endTime">
             <el-date-picker
               v-model="formData.endTime"
               placeholder="选择结束时间"
               type="date"
               value-format="x"
+              class="!w-1/1"
             />
           </el-form-item>
         </el-col>
-        <el-col :span="12">
+      </el-row>
+      <el-row>
+        <el-col :span="8">
           <el-form-item label="公司签约人" prop="signUserId">
-            <el-select v-model="formData.signUserId">
+            <el-select v-model="formData.signUserId" class="w-1/1">
               <el-option
-                v-for="item in userList"
+                v-for="item in userOptions"
                 :key="item.id"
                 :label="item.nickname"
                 :value="item.id!"
@@ -89,61 +109,70 @@
             </el-select>
           </el-form-item>
         </el-col>
-        <el-col :span="12">
-          <el-form-item label="客户签约人" prop="contactId">
-            <el-select v-model="formData.contactId" :disabled="!formData.customerId">
+        <el-col :span="8">
+          <el-form-item label="客户签约人" prop="signContactId">
+            <el-select
+              v-model="formData.signContactId"
+              :disabled="!formData.customerId"
+              class="w-1/1"
+            >
               <el-option
                 v-for="item in getContactOptions"
                 :key="item.id"
                 :label="item.name"
-                :value="item.id!"
+                :value="item.id"
               />
             </el-select>
           </el-form-item>
         </el-col>
-        <el-col :span="12">
-          <el-form-item label="负责人" prop="ownerUserId">
-            <el-select v-model="formData.ownerUserId">
-              <el-option
-                v-for="item in userList"
-                :key="item.id"
-                :label="item.nickname"
-                :value="item.id!"
-              />
-            </el-select>
+        <el-col :span="8">
+          <el-form-item label="备注" prop="remark">
+            <el-input v-model="formData.remark" placeholder="请输入备注" type="textarea" />
           </el-form-item>
         </el-col>
-        <el-col :span="24">
-          <el-form-item label="备注" prop="remark">
+      </el-row>
+      <!-- 子表的表单 -->
+      <ContentWrap>
+        <el-tabs v-model="subTabsName" class="-mt-15px -mb-10px">
+          <el-tab-pane label="产品清单" name="product">
+            <ContractProductForm
+              ref="productFormRef"
+              :products="formData.products"
+              :disabled="disabled"
+            />
+          </el-tab-pane>
+        </el-tabs>
+      </ContentWrap>
+      <el-row>
+        <el-col :span="8">
+          <el-form-item label="产品总金额" prop="totalProductPrice">
             <el-input
-              v-model="formData.remark"
-              :rows="3"
-              placeholder="请输入备注"
-              type="textarea"
+              disabled
+              v-model="formData.totalProductPrice"
+              :formatter="erpPriceInputFormatter"
             />
           </el-form-item>
         </el-col>
-        <!-- TODO @puhui999:productItems 改成 products 会更好点;因为它不是 item 哈 -->
-        <el-col :span="24">
-          <el-form-item label="产品列表" prop="productList">
-            <ProductList v-model="formData.productItems" />
-          </el-form-item>
-        </el-col>
-        <el-col :span="12">
-          <el-form-item label="整单折扣(%)" prop="discountPercent">
+        <el-col :span="8">
+          <el-form-item label="整单折扣(%)" prop="discountPercent">
             <el-input-number
               v-model="formData.discountPercent"
-              :min="0"
-              :max="100"
-              :precision="0"
               placeholder="请输入整单折扣"
-              class="!w-100%"
+              controls-position="right"
+              :min="0"
+              :precision="2"
+              class="!w-1/1"
             />
           </el-form-item>
         </el-col>
-        <el-col :span="12">
-          <el-form-item label="产品总金额(元)" prop="productPrice">
-            {{ fenToYuan(formData.productPrice) }}
+        <el-col :span="8">
+          <el-form-item label="折扣后金额" prop="price">
+            <el-input
+              disabled
+              v-model="formData.totalPrice"
+              placeholder="请输入商机金额"
+              :formatter="erpPriceInputFormatter"
+            />
           </el-form-item>
         </el-col>
       </el-row>
@@ -160,8 +189,9 @@ import * as ContractApi from '@/api/crm/contract'
 import * as UserApi from '@/api/system/user'
 import * as ContactApi from '@/api/crm/contact'
 import * as BusinessApi from '@/api/crm/business'
-import ProductList from './components/ProductList.vue'
-import { fenToYuan } from '@/utils'
+import { erpPriceInputFormatter, erpPriceMultiply } from '@/utils'
+import { useUserStore } from '@/store/modules/user'
+import ContractProductForm from '@/views/crm/contract/components/ContractProductForm.vue'
 
 const { t } = useI18n() // 国际化
 const message = useMessage() // 消息弹窗
@@ -170,30 +200,56 @@ const dialogVisible = ref(false) // 弹窗的是否展示
 const dialogTitle = ref('') // 弹窗的标题
 const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
 const formType = ref('') // 表单的类型:create - 新增;update - 修改
-const formData = ref<ContractApi.ContractVO>({} as ContractApi.ContractVO)
+const formData = ref({
+  id: undefined,
+  no: undefined,
+  name: undefined,
+  customerId: undefined,
+  businessId: undefined,
+  orderDate: undefined,
+  startTime: undefined,
+  endTime: undefined,
+  signUserId: undefined,
+  signContactId: undefined,
+  ownerUserId: undefined,
+  discountPercent: 0,
+  totalProductPrice: undefined,
+  remark: undefined,
+  products: []
+})
 const formRules = reactive({
   name: [{ required: true, message: '合同名称不能为空', trigger: 'blur' }],
   customerId: [{ required: true, message: '客户不能为空', trigger: 'blur' }],
   orderDate: [{ required: true, message: '下单日期不能为空', trigger: 'blur' }],
-  ownerUserId: [{ required: true, message: '负责人不能为空', trigger: 'blur' }],
-  no: [{ required: true, message: '合同编号不能为空', trigger: 'blur' }]
+  ownerUserId: [{ required: true, message: '负责人不能为空', trigger: 'blur' }]
 })
 const formRef = ref() // 表单 Ref
+const userOptions = ref<UserApi.UserVO[]>([]) // 用户列表
+// TODO 芋艿:统一的客户选择面板
+const customerList = ref([]) // 客户列表的数据
+const businessList = ref<BusinessApi.BusinessVO[]>([])
+const contactList = ref<ContactApi.ContactVO[]>([])
 
-/** 监听合同产品变化,计算合同产品总价 */
+/** 子表的表单 */
+const subTabsName = ref('product')
+const productFormRef = ref()
+
+/** 计算 discountPrice、totalPrice 价格 */
 watch(
-  () => formData.value.productItems,
+  () => formData.value,
   (val) => {
-    if (!val || val.length === 0) {
-      formData.value.productPrice = 0
+    if (!val) {
       return
     }
-    // 使用 reduce 函数进行累加
-    formData.value.productPrice = val.reduce(
-      (accumulator, currentValue) =>
-        isNaN(accumulator + currentValue.totalPrice) ? 0 : accumulator + currentValue.totalPrice,
-      0
-    )
+    const totalProductPrice = val.products.reduce((prev, curr) => prev + curr.totalPrice, 0)
+    const discountPrice =
+      val.discountPercent != null
+        ? erpPriceMultiply(totalProductPrice, val.discountPercent / 100.0)
+        : 0
+    const totalPrice = totalProductPrice - discountPrice
+    // 赋值
+    formData.value.totalProductPrice = totalProductPrice
+    formData.value.totalPrice = totalPrice
   },
   { deep: true }
 )
@@ -213,7 +269,18 @@ const open = async (type: string, id?: number) => {
       formLoading.value = false
     }
   }
-  await getAllApi()
+  // 获得客户列表
+  customerList.value = await CustomerApi.getCustomerSimpleList()
+  // 获得用户列表
+  userOptions.value = await UserApi.getSimpleUserList()
+  // 默认新建时选中自己
+  if (formType.value === 'create') {
+    formData.value.ownerUserId = useUserStore().getUser.id
+  }
+  // 获取联系人
+  contactList.value = await ContactApi.getSimpleContactList()
+  // 获得商机列表
+  businessList.value = await BusinessApi.getSimpleBusinessList()
 }
 defineExpose({ open }) // 提供 open 方法,用于打开弹窗
 
@@ -226,6 +293,7 @@ const submitForm = async () => {
   if (!valid) return
   // 提交请求
   formLoading.value = true
+  productFormRef.value.validate()
   try {
     const data = unref(formData.value) as unknown as ContractApi.ContractVO
     if (formType.value === 'create') {
@@ -245,39 +313,35 @@ const submitForm = async () => {
 
 /** 重置表单 */
 const resetForm = () => {
-  formData.value = {} as ContractApi.ContractVO
+  formData.value = {
+    id: undefined,
+    no: undefined,
+    name: undefined,
+    customerId: undefined,
+    businessId: undefined,
+    orderDate: undefined,
+    startTime: undefined,
+    endTime: undefined,
+    signUserId: undefined,
+    signContactId: undefined,
+    ownerUserId: undefined,
+    discountPercent: 0,
+    totalProductPrice: undefined,
+    remark: undefined,
+    products: []
+  }
   formRef.value?.resetFields()
 }
 
-/** 获取其它相关数据 */
-const getAllApi = async () => {
-  await Promise.all([getCustomerList(), getUserList(), getContactListList(), getBusinessList()])
-}
-
-/** 获取客户 */
-const customerList = ref<CustomerApi.CustomerVO[]>([])
-const getCustomerList = async () => {
-  customerList.value = await CustomerApi.getCustomerSimpleList()
-}
+// TODO 芋艿:切换客户时,需要 reset 关联的几个字段
+// TODO 芋艿:选择商机时,需要自动设置
 
 /** 动态获取客户联系人 */
-const contactList = ref<ContactApi.ContactVO[]>([])
 const getContactOptions = computed(() =>
   contactList.value.filter((item) => item.customerId === formData.value.customerId)
 )
-const getContactListList = async () => {
-  contactList.value = await ContactApi.getSimpleContactList()
-}
-
-/** 获取用户列表 */
-const userList = ref<UserApi.UserVO[]>([])
-const getUserList = async () => {
-  userList.value = await UserApi.getSimpleUserList()
-}
-
-/** 获取商机 */
-const businessList = ref<BusinessApi.BusinessVO[]>([])
-const getBusinessList = async () => {
-  businessList.value = await BusinessApi.getSimpleBusinessList()
-}
+/** 动态获取商机 */
+const getBusinessOptions = computed(() =>
+  businessList.value.filter((item) => item.customerId === formData.value.customerId)
+)
 </script>

+ 183 - 0
src/views/crm/contract/components/ContractProductForm.vue

@@ -0,0 +1,183 @@
+<template>
+  <el-form
+    ref="formRef"
+    :model="formData"
+    :rules="formRules"
+    v-loading="formLoading"
+    label-width="0px"
+    :inline-message="true"
+    :disabled="disabled"
+  >
+    <el-table :data="formData" class="-mt-10px">
+      <el-table-column label="序号" type="index" align="center" width="60" />
+      <el-table-column label="产品名称" min-width="180">
+        <template #default="{ row, $index }">
+          <el-form-item :prop="`${$index}.productId`" :rules="formRules.productId" class="mb-0px!">
+            <el-select
+              v-model="row.productId"
+              clearable
+              filterable
+              @change="onChangeProduct($event, row)"
+              placeholder="请选择产品"
+            >
+              <el-option
+                v-for="item in productList"
+                :key="item.id"
+                :label="item.name"
+                :value="item.id"
+              />
+            </el-select>
+          </el-form-item>
+        </template>
+      </el-table-column>
+      <el-table-column label="条码" min-width="150">
+        <template #default="{ row }">
+          <el-form-item class="mb-0px!">
+            <el-input disabled v-model="row.productNo" />
+          </el-form-item>
+        </template>
+      </el-table-column>
+      <el-table-column label="单位" min-width="80">
+        <template #default="{ row }">
+          <dict-tag :type="DICT_TYPE.CRM_PRODUCT_UNIT" :value="row.productUnit" />
+        </template>
+      </el-table-column>
+      <el-table-column label="价格(元)" min-width="120">
+        <template #default="{ row }">
+          <el-form-item class="mb-0px!">
+            <el-input disabled v-model="row.productPrice" :formatter="erpPriceInputFormatter" />
+          </el-form-item>
+        </template>
+      </el-table-column>
+      <el-table-column label="售价(元)" fixed="right" min-width="140">
+        <template #default="{ row, $index }">
+          <el-form-item :prop="`${$index}.contractPrice`" class="mb-0px!">
+            <el-input-number
+              v-model="row.contractPrice"
+              controls-position="right"
+              :min="0.001"
+              :precision="2"
+              class="!w-100%"
+            />
+          </el-form-item>
+        </template>
+      </el-table-column>
+      <el-table-column label="数量" prop="count" fixed="right" min-width="120">
+        <template #default="{ row, $index }">
+          <el-form-item :prop="`${$index}.count`" :rules="formRules.count" class="mb-0px!">
+            <el-input-number
+              v-model="row.count"
+              controls-position="right"
+              :min="0.001"
+              :precision="3"
+              class="!w-100%"
+            />
+          </el-form-item>
+        </template>
+      </el-table-column>
+      <el-table-column label="合计" prop="totalPrice" fixed="right" min-width="140">
+        <template #default="{ row, $index }">
+          <el-form-item :prop="`${$index}.totalPrice`" class="mb-0px!">
+            <el-input disabled v-model="row.totalPrice" :formatter="erpPriceInputFormatter" />
+          </el-form-item>
+        </template>
+      </el-table-column>
+      <el-table-column align="center" fixed="right" label="操作" width="60">
+        <template #default="{ $index }">
+          <el-button @click="handleDelete($index)" link>—</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+  </el-form>
+  <el-row justify="center" class="mt-3" v-if="!disabled">
+    <el-button @click="handleAdd" round>+ 添加产品</el-button>
+  </el-row>
+</template>
+<script setup lang="ts">
+import * as ProductApi from '@/api/crm/product'
+import { erpPriceInputFormatter, erpPriceMultiply } from '@/utils'
+import { DICT_TYPE } from '@/utils/dict'
+
+const props = defineProps<{
+  products: undefined
+  disabled: false
+}>()
+const formLoading = ref(false) // 表单的加载中
+const formData = ref([])
+const formRules = reactive({
+  productId: [{ required: true, message: '产品不能为空', trigger: 'blur' }],
+  contractPrice: [{ required: true, message: '合同价格不能为空', trigger: 'blur' }],
+  count: [{ required: true, message: '产品数量不能为空', trigger: 'blur' }]
+})
+const formRef = ref([]) // 表单 Ref
+const productList = ref<ProductApi.ProductVO[]>([]) // 产品列表
+
+/** 初始化设置产品项 */
+watch(
+  () => props.products,
+  async (val) => {
+    formData.value = val
+  },
+  { immediate: true }
+)
+
+/** 监听合同产品变化,计算合同产品总价 */
+watch(
+  () => formData.value,
+  (val) => {
+    if (!val || val.length === 0) {
+      return
+    }
+    // 循环处理
+    val.forEach((item) => {
+      if (item.contractPrice != null && item.count != null) {
+        item.totalPrice = erpPriceMultiply(item.contractPrice, item.count)
+      } else {
+        item.totalPrice = undefined
+      }
+    })
+  },
+  { deep: true }
+)
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+  const row = {
+    id: undefined,
+    productId: undefined,
+    productUnit: undefined, // 产品单位
+    productNo: undefined, // 产品条码
+    productPrice: undefined, // 产品价格
+    contractPrice: undefined,
+    count: 1
+  }
+  formData.value.push(row)
+}
+
+/** 删除按钮操作 */
+const handleDelete = (index: number) => {
+  formData.value.splice(index, 1)
+}
+
+/** 处理产品变更 */
+const onChangeProduct = (productId, row) => {
+  const product = productList.value.find((item) => item.id === productId)
+  if (product) {
+    row.productUnit = product.unit
+    row.productNo = product.no
+    row.productPrice = product.price
+    row.contractPrice = product.price
+  }
+}
+
+/** 表单校验 */
+const validate = () => {
+  return formRef.value.validate()
+}
+defineExpose({ validate })
+
+/** 初始化 */
+onMounted(async () => {
+  productList.value = await ProductApi.getProductSimpleList()
+})
+</script>

+ 0 - 171
src/views/crm/contract/components/ProductList.vue

@@ -1,171 +0,0 @@
-<!-- 合同 Form 表单下的 Product 列表 -->
-<template>
-  <el-row justify="end">
-    <el-button plain type="primary" @click="openForm">添加产品</el-button>
-  </el-row>
-  <el-table :data="list" :show-overflow-tooltip="true" :stripe="true">
-    <el-table-column align="center" label="产品名称" prop="name" width="120" />
-    <el-table-column
-      :formatter="fenToYuanFormat"
-      align="center"
-      label="价格"
-      prop="price"
-      width="100"
-    />
-    <el-table-column align="center" label="产品类型" prop="categoryName" width="100" />
-    <el-table-column align="center" label="产品单位" prop="unit">
-      <template #default="scope">
-        <dict-tag :type="DICT_TYPE.CRM_PRODUCT_UNIT" :value="scope.row.unit" />
-      </template>
-    </el-table-column>
-    <el-table-column align="center" label="产品编码" prop="no" />
-    <el-table-column align="center" fixed="right" label="数量" prop="count" width="100">
-      <template #default="{ row }: { row: ProductApi.ProductExpandVO }">
-        <el-input-number
-          v-model="row.count"
-          controls-position="right"
-          :min="0"
-          :precision="0"
-          class="!w-100%"
-        />
-      </template>
-    </el-table-column>
-    <el-table-column
-      align="center"
-      fixed="right"
-      label="折扣(%)"
-      prop="discountPercent"
-      width="120"
-    >
-      <template #default="{ row }: { row: ProductApi.ProductExpandVO }">
-        <el-input-number
-          v-model="row.discountPercent"
-          controls-position="right"
-          :min="0"
-          :max="100"
-          :precision="0"
-          class="!w-100%"
-        />
-      </template>
-    </el-table-column>
-    <el-table-column align="center" fixed="right" label="合计" prop="totalPrice" width="100">
-      <template #default="{ row }: { row: ProductApi.ProductExpandVO }">
-        {{ fenToYuan(getTotalPrice(row)) }}
-      </template>
-    </el-table-column>
-    <el-table-column align="center" fixed="right" label="操作" width="60">
-      <template #default="scope">
-        <el-button link type="danger" @click="handleDelete(scope.row.id)"> 移除</el-button>
-      </template>
-    </el-table-column>
-  </el-table>
-
-  <!-- table 选择表单 -->
-  <TableSelectForm ref="tableSelectFormRef" v-model="multipleSelection" title="选择产品">
-    <el-table-column align="center" label="产品名称" prop="name" width="160" />
-    <el-table-column align="center" label="产品类型" prop="categoryName" width="160" />
-    <el-table-column align="center" label="产品单位" prop="unit">
-      <template #default="scope">
-        <dict-tag :type="DICT_TYPE.CRM_PRODUCT_UNIT" :value="scope.row.unit" />
-      </template>
-    </el-table-column>
-    <el-table-column align="center" label="产品编码" prop="no" />
-    <el-table-column
-      :formatter="fenToYuanFormat"
-      align="center"
-      label="价格(元)"
-      prop="price"
-      width="100"
-    />
-  </TableSelectForm>
-</template>
-
-<script lang="ts" setup>
-import * as ProductApi from '@/api/crm/product'
-import { DICT_TYPE } from '@/utils/dict'
-import { fenToYuanFormat } from '@/utils/formatter'
-import { TableSelectForm } from '@/components/Table/index'
-import { fenToYuan, floatToFixed2, yuanToFen } from '@/utils'
-
-defineOptions({ name: 'ProductList' })
-const props = withDefaults(defineProps<{ modelValue: ProductApi.ProductExpandVO[] }>(), {
-  modelValue: () => []
-})
-const emits = defineEmits<{
-  (e: 'update:modelValue', v: any[]): void
-}>()
-
-const list = ref<ProductApi.ProductExpandVO[]>([]) // 已添加的产品列表
-const multipleSelection = ref<ProductApi.ProductExpandVO[]>([]) // 多选
-
-/** 处理删除 */
-const handleDelete = (id: number) => {
-  const index = list.value.findIndex((item) => item.id === id)
-  if (index !== -1) {
-    list.value.splice(index, 1)
-  }
-}
-
-/** 打开 Product 弹窗  */
-const tableSelectFormRef = ref<InstanceType<typeof TableSelectForm>>()
-const openForm = () => {
-  tableSelectFormRef.value?.open(ProductApi.getProductPage)
-}
-
-/** 计算 totalPrice */
-const getTotalPrice = computed(() => (row: ProductApi.ProductExpandVO) => {
-  const totalPrice =
-    (Number(row.price) / 100) * Number(row.count) * (1 - Number(row.discountPercent) / 100)
-  row.totalPrice = isNaN(totalPrice) ? 0 : yuanToFen(totalPrice)
-  return isNaN(totalPrice) ? 0 : totalPrice.toFixed(2)
-})
-
-/** 编辑时合同产品回显 */
-const isSetListValue = ref(false) // 判断是否已经给 list 赋值过,用于编辑表单产品回显
-watch(
-  () => props.modelValue,
-  (val) => {
-    if (!val || val.length === 0 || isSetListValue.value) {
-      return
-    }
-    list.value = [
-      ...props.modelValue.map((item) => {
-        item.totalPrice = floatToFixed2(item.totalPrice) as unknown as number
-        return item
-      })
-    ]
-    isSetListValue.value = true
-  },
-  { immediate: true, deep: true }
-)
-
-/** 监听列表变化,动态更新合同产品列表 */
-watch(
-  list,
-  (val) => {
-    if (!val || val.length === 0) {
-      return
-    }
-    emits('update:modelValue', list.value)
-  },
-  { deep: true }
-)
-
-// 监听产品选择结果动态添加产品到列表中,如果产品存在则不放入列表中
-watch(
-  multipleSelection,
-  (val) => {
-    if (!val || val.length === 0) {
-      return
-    }
-    // 过滤出不在列表中的产品
-    const ids = list.value.map((item) => item.id)
-    const productList = multipleSelection.value.filter((item) => ids.indexOf(item.id) === -1)
-    if (!productList || productList.length === 0) {
-      return
-    }
-    list.value.push(...productList)
-  },
-  { deep: true }
-)
-</script>