ContractProductForm.vue 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. <template>
  2. <el-form
  3. ref="formRef"
  4. :model="formData"
  5. :rules="formRules"
  6. v-loading="formLoading"
  7. label-width="0px"
  8. :inline-message="true"
  9. :disabled="disabled"
  10. >
  11. <el-table :data="formData" class="-mt-10px">
  12. <el-table-column label="序号" type="index" align="center" width="60" />
  13. <el-table-column label="产品名称" min-width="180">
  14. <template #default="{ row, $index }">
  15. <el-form-item :prop="`${$index}.productId`" :rules="formRules.productId" class="mb-0px!">
  16. <el-select
  17. v-model="row.productId"
  18. clearable
  19. filterable
  20. @change="onChangeProduct($event, row)"
  21. placeholder="请选择产品"
  22. >
  23. <el-option
  24. v-for="item in productList"
  25. :key="item.id"
  26. :label="item.name"
  27. :value="item.id"
  28. />
  29. </el-select>
  30. </el-form-item>
  31. </template>
  32. </el-table-column>
  33. <el-table-column label="条码" min-width="150">
  34. <template #default="{ row }">
  35. <el-form-item class="mb-0px!">
  36. <el-input disabled v-model="row.productNo" />
  37. </el-form-item>
  38. </template>
  39. </el-table-column>
  40. <el-table-column label="单位" min-width="80">
  41. <template #default="{ row }">
  42. <dict-tag :type="DICT_TYPE.CRM_PRODUCT_UNIT" :value="row.productUnit" />
  43. </template>
  44. </el-table-column>
  45. <el-table-column label="价格(元)" min-width="120">
  46. <template #default="{ row }">
  47. <el-form-item class="mb-0px!">
  48. <el-input disabled v-model="row.productPrice" :formatter="erpPriceInputFormatter" />
  49. </el-form-item>
  50. </template>
  51. </el-table-column>
  52. <el-table-column label="售价(元)" fixed="right" min-width="140">
  53. <template #default="{ row, $index }">
  54. <el-form-item :prop="`${$index}.contractPrice`" class="mb-0px!">
  55. <el-input-number
  56. v-model="row.contractPrice"
  57. controls-position="right"
  58. :min="0.001"
  59. :precision="2"
  60. class="!w-100%"
  61. />
  62. </el-form-item>
  63. </template>
  64. </el-table-column>
  65. <el-table-column label="数量" prop="count" fixed="right" min-width="120">
  66. <template #default="{ row, $index }">
  67. <el-form-item :prop="`${$index}.count`" :rules="formRules.count" class="mb-0px!">
  68. <el-input-number
  69. v-model="row.count"
  70. controls-position="right"
  71. :min="0.001"
  72. :precision="3"
  73. class="!w-100%"
  74. />
  75. </el-form-item>
  76. </template>
  77. </el-table-column>
  78. <el-table-column label="合计" prop="totalPrice" fixed="right" min-width="140">
  79. <template #default="{ row, $index }">
  80. <el-form-item :prop="`${$index}.totalPrice`" class="mb-0px!">
  81. <el-input disabled v-model="row.totalPrice" :formatter="erpPriceInputFormatter" />
  82. </el-form-item>
  83. </template>
  84. </el-table-column>
  85. <el-table-column align="center" fixed="right" label="操作" width="60">
  86. <template #default="{ $index }">
  87. <el-button @click="handleDelete($index)" link>—</el-button>
  88. </template>
  89. </el-table-column>
  90. </el-table>
  91. </el-form>
  92. <el-row justify="center" class="mt-3" v-if="!disabled">
  93. <el-button @click="handleAdd" round>+ 添加产品</el-button>
  94. </el-row>
  95. </template>
  96. <script setup lang="ts">
  97. import * as ProductApi from '@/api/crm/product'
  98. import { erpPriceInputFormatter, erpPriceMultiply } from '@/utils'
  99. import { DICT_TYPE } from '@/utils/dict'
  100. const props = defineProps<{
  101. products: undefined
  102. disabled: false
  103. }>()
  104. const formLoading = ref(false) // 表单的加载中
  105. const formData = ref([])
  106. const formRules = reactive({
  107. productId: [{ required: true, message: '产品不能为空', trigger: 'blur' }],
  108. contractPrice: [{ required: true, message: '合同价格不能为空', trigger: 'blur' }],
  109. count: [{ required: true, message: '产品数量不能为空', trigger: 'blur' }]
  110. })
  111. const formRef = ref([]) // 表单 Ref
  112. const productList = ref<ProductApi.ProductVO[]>([]) // 产品列表
  113. /** 初始化设置产品项 */
  114. watch(
  115. () => props.products,
  116. async (val) => {
  117. formData.value = val
  118. },
  119. { immediate: true }
  120. )
  121. /** 监听合同产品变化,计算合同产品总价 */
  122. watch(
  123. () => formData.value,
  124. (val) => {
  125. if (!val || val.length === 0) {
  126. return
  127. }
  128. // 循环处理
  129. val.forEach((item) => {
  130. if (item.contractPrice != null && item.count != null) {
  131. item.totalPrice = erpPriceMultiply(item.contractPrice, item.count)
  132. } else {
  133. item.totalPrice = undefined
  134. }
  135. })
  136. },
  137. { deep: true }
  138. )
  139. /** 新增按钮操作 */
  140. const handleAdd = () => {
  141. const row = {
  142. id: undefined,
  143. productId: undefined,
  144. productUnit: undefined, // 产品单位
  145. productNo: undefined, // 产品条码
  146. productPrice: undefined, // 产品价格
  147. contractPrice: undefined,
  148. count: 1
  149. }
  150. formData.value.push(row)
  151. }
  152. /** 删除按钮操作 */
  153. const handleDelete = (index: number) => {
  154. formData.value.splice(index, 1)
  155. }
  156. /** 处理产品变更 */
  157. const onChangeProduct = (productId, row) => {
  158. const product = productList.value.find((item) => item.id === productId)
  159. if (product) {
  160. row.productUnit = product.unit
  161. row.productNo = product.no
  162. row.productPrice = product.price
  163. row.contractPrice = product.price
  164. }
  165. }
  166. /** 表单校验 */
  167. const validate = () => {
  168. return formRef.value.validate()
  169. }
  170. defineExpose({ validate })
  171. /** 初始化 */
  172. onMounted(async () => {
  173. productList.value = await ProductApi.getProductSimpleList()
  174. })
  175. </script>