Browse Source

feature: 合同功能修改

liuyaqi 2 years ago
parent
commit
b1e455fcb3

+ 3 - 0
src/api/contract/index.js

@@ -28,6 +28,9 @@ export default {
   updateContract(query) {
     return micro_request.postRequest(basePath, 'CtrContract', 'Update', query)
   },
+  updateProduct(query) {
+    return micro_request.postRequest(basePath, 'CtrContract', 'UpdateProduct', query)
+  },
   // 转移合同
   transferContract(query) {
     return micro_request.postRequest(basePath, 'CtrContract', 'Transfer', query)

+ 13 - 0
src/views/contract/components/DetailsCollection.vue

@@ -38,6 +38,9 @@
             <span v-else-if="item.prop == 'planDatetime'">
               {{ parseTime(row.planDatetime, '{y}-{m}-{d}') }}
             </span>
+            <span v-else-if="item.prop == 'planScale'">
+              {{ row.planScale + '%' }}
+            </span>
             <span v-else-if="item.prop == 'planAmount'">{{ formatPrice(row.planAmount) }}</span>
             <span v-else>{{ row[item.prop] }}</span>
           </template>
@@ -166,6 +169,16 @@
             width: '120px',
             prop: 'planDatetime',
           },
+          {
+            label: '计划回款比例',
+            width: '100px',
+            prop: 'planScale',
+          },
+          {
+            label: '回款条件',
+            width: '120px',
+            prop: 'planCondition',
+          },
           {
             label: '备注',
             width: 'auto',

+ 62 - 5
src/views/contract/components/DetailsInfo.vue

@@ -18,21 +18,48 @@
       <el-descriptions-item content-class-name="my-content" label="客户名称" label-class-name="my-label">
         {{ details.custName }}
       </el-descriptions-item>
+      <el-descriptions-item content-class-name="my-content" label="产品线" label-class-name="my-label">
+        {{ productLineOptions[details.productLine] }}
+      </el-descriptions-item>
       <el-descriptions-item content-class-name="my-content" label="项目名称" label-class-name="my-label">
         {{ details.nboName }}
       </el-descriptions-item>
+      <el-descriptions-item content-class-name="my-content" label="所在省" label-class-name="my-label">
+        {{ details.custProvince }}
+      </el-descriptions-item>
+      <el-descriptions-item content-class-name="my-content" label="所在市" label-class-name="my-label">
+        {{ details.custCity }}
+      </el-descriptions-item>
       <el-descriptions-item content-class-name="my-content" label="合同金额" label-class-name="my-label">
         {{ formatPrice(details.contractAmount) }}
       </el-descriptions-item>
+      <el-descriptions-item content-class-name="my-content" label="开票金额" label-class-name="my-label">
+        {{ formatPrice(details.invoiceAmount) }}
+      </el-descriptions-item>
+      <el-descriptions-item content-class-name="my-content" label="回款金额" label-class-name="my-label">
+        {{ formatPrice(details.collectedAmount) }}
+      </el-descriptions-item>
+      <el-descriptions-item content-class-name="my-content" label="质量/履约保证金" label-class-name="my-label">
+        {{ formatPrice(details.earnestMoney) }}
+      </el-descriptions-item>
       <el-descriptions-item content-class-name="my-content" label="负责人" label-class-name="my-label">
         {{ details.inchargeName }}
       </el-descriptions-item>
+      <el-descriptions-item content-class-name="my-content" label="签订单位类型" label-class-name="my-label">
+        {{ signatoryOptions[details.signatoryType] }}
+      </el-descriptions-item>
+      <el-descriptions-item content-class-name="my-content" label="合同签订单位" label-class-name="my-label">
+        {{ details.signatoryUnit }}
+      </el-descriptions-item>
       <el-descriptions-item content-class-name="my-content" label="合同开始时间" label-class-name="my-label">
         {{ parseTime(details.contractStartTime, '{y}-{m}-{d}') }}
       </el-descriptions-item>
       <el-descriptions-item content-class-name="my-content" label="合同结束时间" label-class-name="my-label">
         {{ parseTime(details.contractEndTime, '{y}-{m}-{d}') }}
       </el-descriptions-item>
+      <el-descriptions-item content-class-name="my-content" label="合同签订时间" label-class-name="my-label">
+        {{ parseTime(details.contractSignTime, '{y}-{m}-{d}') }}
+      </el-descriptions-item>
       <el-descriptions-item content-class-name="my-content" label="公司签约人" label-class-name="my-label">
         {{ details.signatoryName }}
       </el-descriptions-item>
@@ -40,7 +67,7 @@
         {{ details.remark }}
       </el-descriptions-item>
       <el-descriptions-item content-class-name="my-content" label="合同类型" label-class-name="my-label">
-        {{ details.contractType }}
+        {{ contractOptions[details.contractType] }}
       </el-descriptions-item>
       <el-descriptions-item content-class-name="my-content" label="创建人" label-class-name="my-label">
         {{ details.createdName }}
@@ -64,10 +91,40 @@
       },
     },
     data() {
-      return {}
+      return {
+        contractOptions: {}, //合同类型
+        productLineOptions: {}, //产品线
+        signatoryOptions: {
+          10: '终端用户',
+          20: '经销商',
+          30: '代理商',
+        },
+      }
+    },
+    mounted() {
+      this.getOptions()
+    },
+    methods: {
+      getOptions() {
+        Promise.all([this.getDicts('contract_type'), this.getDicts('sys_product_line')])
+          .then(([contract, productLine]) => {
+            this.contractOptions = {}
+            contract.data.values.filter((i) => {
+              this.contractOptions[i.key] = i.value
+            })
+            this.productLineOptions = {}
+            productLine.data.values.filter((i) => {
+              this.productLineOptions[i.key] = i.value
+            })
+          })
+          .catch((err) => console.log(err))
+      },
     },
-    mounted() {},
-    methods: {},
   }
 </script>
-<style lang="scss" scoped></style>
+<style lang="scss" scoped>
+  .details-container {
+    height: 100%;
+    overflow: auto;
+  }
+</style>

+ 326 - 3
src/views/contract/components/DetailsProduct.vue

@@ -27,17 +27,178 @@
           <span v-else-if="item.prop == 'tranPrice'">
             {{ formatPrice(row.tranPrice) }}
           </span>
+          <span v-else-if="item.prop == 'purchaseCost'">
+            {{ formatPrice(row.purchaseCost) }}
+          </span>
+          <span v-else-if="item.prop == 'devCost'">
+            {{ formatPrice(row.devCost) }}
+          </span>
+          <span v-else-if="item.prop == 'maintainCost'">
+            {{ formatPrice(row.maintainCost) }}
+          </span>
+          <span v-else-if="item.prop == 'directCost'">
+            {{ formatPrice(row.directCost) }}
+          </span>
+          <span v-else-if="item.prop === 'prodClass'">
+            {{ selectDictLabel(productLineOptions, row.prodClass) }}
+          </span>
+          <span v-else-if="item.prop === 'acceptTime'">
+            {{ parseTime(row.acceptTime, '{y}-{m}-{d}') }}
+          </span>
+          <span v-else-if="item.prop === 'maintainStartTime'">
+            {{ parseTime(row.maintainStartTime, '{y}-{m}-{d}') }}
+          </span>
           <span v-else>{{ row[item.prop] }}</span>
         </template>
       </el-table-column>
+      <el-table-column align="center" fixed="right" label="操作" width="120px">
+        <!-- approStatus 审核状态 10 待提交审核 20 待审核 30 审核已同意 40 审核已拒绝 50 审核已撤销 -->
+        <template slot-scope="scope">
+          <el-button
+            v-permissions="['contract:detail:product:maintain']"
+            :disabled="details.approStatus != '30'"
+            type="text"
+            @click="maintainOpen(scope.row)">
+            维保
+          </el-button>
+          <el-button
+            v-permissions="['contract:detail:product:cost']"
+            :disabled="details.approStatus != '30'"
+            type="text"
+            @click="costOpen(scope.row)">
+            成本
+          </el-button>
+        </template>
+      </el-table-column>
     </el-table>
+
+    <el-dialog title="更新维保信息" :visible.sync="maintainVisible" @close="maintainClose">
+      <el-form :model="maintainForm">
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="合同编号">
+              <el-input v-model="detailsNoMutation.contractCode" disabled />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="产品名称">
+              <el-input v-model="maintainForm.prodName" disabled />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="质保期(天)">
+              <el-input v-model.number="maintainForm.maintainPeriod" placeholder="请输入质保期" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="运维期(天)">
+              <el-input v-model.number="maintainForm.warrantPeriod" placeholder="请输入运维期" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="运维开始时间">
+              <el-date-picker
+                v-model="maintainForm.maintainStartTime"
+                placeholder="选择运维开始时间"
+                style="width: 100%"
+                type="date"
+                value-format="yyyy-MM-dd" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="验收时间">
+              <el-date-picker
+                v-model="maintainForm.acceptTime"
+                placeholder="选择验收时间"
+                style="width: 100%"
+                type="date"
+                value-format="yyyy-MM-dd" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-form-item label="运维约定条款">
+          <el-input
+            v-model="maintainForm.maintainRemark"
+            clearable
+            maxlength="500"
+            placeholder="请输入运维约定条款"
+            :rows="5"
+            show-word-limit
+            type="textarea" />
+        </el-form-item>
+      </el-form>
+      <span slot="footer">
+        <el-button type="primary" @click="maintainEdit">保存</el-button>
+        <el-button @click="maintainClose">取消</el-button>
+      </span>
+    </el-dialog>
+
+    <el-dialog title="更新成本信息" :visible.sync="costVisible" @close="costClose">
+      <el-form :model="costForm">
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="合同编号">
+              <el-input v-model="detailsNoMutation.contractCode" disabled />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="产品名称">
+              <el-input v-model="costForm.prodName" disabled />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="采购成本">
+              <amount-input v-model="costForm.purchaseCost" placeholder="请输入采购成本" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="二次开发成本">
+              <amount-input v-model="costForm.devCost" placeholder="请输入二次开发成本" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="产品维保成本">
+              <amount-input v-model="costForm.maintainCost" placeholder="请输入产品维保成本" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="直接成本">
+              <amount-input v-model="costForm.directCost" placeholder="请输入直接成本" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <span slot="footer">
+        <el-button type="primary" @click="costEdit">保存</el-button>
+        <el-button @click="costClose">取消</el-button>
+      </span>
+    </el-dialog>
   </div>
 </template>
 
 <script>
+  import to from 'await-to-js'
+  import contractApi from '@/api/contract'
+  import AmountInput from '@/components/currency'
+
   export default {
     name: 'DetailsProduct',
+    components: {
+      AmountInput,
+    },
     props: {
+      details: {
+        type: Object,
+        default: () => {},
+      },
       product: {
         type: Array,
         default: () => [],
@@ -46,6 +207,16 @@
     data() {
       return {
         columns: [
+          {
+            label: '合同编号',
+            width: '120px',
+            prop: 'contractCode',
+          },
+          {
+            label: '产品类别',
+            width: '100px',
+            prop: 'prodClass',
+          },
           {
             label: '产品名称',
             width: '120px',
@@ -70,13 +241,91 @@
             label: '合计',
             width: '100px',
           },
+          {
+            label: '采购成本',
+            width: '120px',
+            prop: 'purchaseCost',
+          },
+          {
+            label: '二次开发成本',
+            width: '120px',
+            prop: 'devCost',
+          },
+          {
+            label: '产品维保成本',
+            width: '120px',
+            prop: 'maintainCost',
+          },
+          {
+            label: '直接成本',
+            width: '120px',
+            prop: 'directCost',
+          },
+          {
+            label: '验收时间',
+            width: '120px',
+            prop: 'acceptTime',
+          },
+          {
+            label: '质保期(天)',
+            width: '120px',
+            prop: 'maintainPeriod',
+          },
+          {
+            label: '运维开始时间',
+            width: '120px',
+            prop: 'maintainStartTime',
+          },
+          {
+            label: '运维期(天)',
+            width: '120px',
+            prop: 'warrantPeriod',
+          },
+          {
+            label: '运维约定条款',
+            width: '120px',
+            prop: 'maintainRemark',
+          },
         ],
+        productLineOptions: [],
+        maintainVisible: false,
+        maintainForm: {
+          id: 0,
+          prodName: '',
+          maintainPeriod: 0,
+          warrantPeriod: 0,
+          maintainStartTime: null,
+          maintainRemark: '',
+          acceptTime: null,
+        },
+        costVisible: false,
+        costForm: {
+          id: 0,
+          prodName: '',
+          purchaseCost: 0,
+          devCost: 0,
+          maintainCost: 0,
+          directCost: 0,
+        },
       }
     },
-
-    mounted() {},
-
+    computed: {
+      detailsNoMutation() {
+        let obj = Object.assign({}, this.details)
+        return obj
+      },
+    },
+    mounted() {
+      this.getOptions()
+    },
     methods: {
+      getOptions() {
+        Promise.all([this.getDicts('sys_product_line')])
+          .then(([productLine]) => {
+            this.productLineOptions = productLine.data.values || []
+          })
+          .catch((err) => console.log(err))
+      },
       // 计算总价
       calculatedDiscount(price, count) {
         let intPrice = null
@@ -84,6 +333,80 @@
         else intPrice = price * 100
         return this.formatPrice((intPrice * count) / 100)
       },
+      maintainOpen(data) {
+        this.maintainForm.id = data.id
+        this.maintainForm.prodName = data.prodName
+        this.maintainForm.maintainPeriod = data.maintainPeriod
+        this.maintainForm.warrantPeriod = data.warrantPeriod
+        this.maintainForm.maintainStartTime = data.maintainStartTime
+        this.maintainForm.maintainRemark = data.maintainRemark
+        this.maintainForm.acceptTime = data.acceptTime
+        this.maintainVisible = true
+      },
+      maintainClose() {
+        this.maintainForm.id = 0
+        this.maintainForm.prodName = ''
+        this.maintainForm.maintainPeriod = 0
+        this.maintainForm.warrantPeriod = 0
+        this.maintainForm.maintainStartTime = null
+        this.maintainForm.maintainRemark = ''
+        this.maintainForm.acceptTime = null
+        this.maintainVisible = false
+      },
+      async maintainEdit() {
+        let params = { ...this.maintainForm }
+        params.maintainPeriod = params.maintainPeriod ? params.maintainPeriod : 0
+        params.warrantPeriod = params.warrantPeriod ? params.warrantPeriod : 0
+        const [err, res] = await to(contractApi.updateProduct(params))
+        if (err) {
+          console.error(err)
+          return
+        }
+        if (res.code == 200) {
+          this.$message.success('操作成功')
+        } else {
+          console.error(res)
+        }
+        this.maintainVisible = false
+        this.$emit('productUpdate')
+      },
+      costOpen(data) {
+        this.costForm.id = data.id
+        this.costForm.prodName = data.prodName
+        this.costForm.purchaseCost = data.purchaseCost
+        this.costForm.devCost = data.devCost
+        this.costForm.maintainCost = data.maintainCost
+        this.costForm.directCost = data.directCost
+        this.costVisible = true
+      },
+      costClose() {
+        this.costForm.id = 0
+        this.costForm.prodName = ''
+        this.costForm.purchaseCost = 0
+        this.costForm.devCost = 0
+        this.costForm.maintainCost = 0
+        this.costForm.directCost = 0
+        this.costVisible = false
+      },
+      async costEdit() {
+        let params = { ...this.costForm }
+        params.purchaseCost = params.purchaseCost ? params.purchaseCost : 0
+        params.devCost = params.devCost ? params.devCost : 0
+        params.maintainCost = params.maintainCost ? params.maintainCost : 0
+        params.directCost = params.directCost ? params.directCost : 0
+        const [err, res] = await to(contractApi.updateProduct(params))
+        if (err) {
+          console.error(err)
+          return
+        }
+        if (res.code == 200) {
+          this.$message.success('操作成功')
+        } else {
+          console.error(res)
+        }
+        this.costVisible = false
+        this.$emit('productUpdate')
+      },
     },
   }
 </script>

+ 59 - 3
src/views/contract/components/Edit.vue

@@ -115,10 +115,26 @@
       <el-row :gutter="20">
         <el-col :span="12">
           <el-form-item label="签订单位类型" prop="signatoryType">
-            <el-select v-model="editForm.signatoryType" placeholder="签订单位类型" style="width: 100%">
+            <el-select
+              v-model="editForm.signatoryType"
+              placeholder="签订单位类型"
+              style="width: 100%"
+              @change="signatoryTypeChange">
               <el-option v-for="item in signatoryOptions" :key="item.value" :label="item.value" :value="item.key" />
             </el-select>
           </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="合同签订单位" prop="signatoryUnit">
+            <el-input v-model="editForm.signatoryUnit" disabled placeholder="请选择合同签订单位" />
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row :gutter="20">
+        <el-col :span="12">
+          <el-form-item label="质量/履约保证金(元)" prop="earnestMoney">
+            <el-input v-model.number="editForm.earnestMoney" clearable placeholder="请输入质量/履约保证金" />
+          </el-form-item>
           <el-form-item label="客户签约人" prop="custSignatoryName">
             <el-input
               v-model="editForm.custSignatoryName"
@@ -139,12 +155,23 @@
           </el-form-item>
         </el-col>
       </el-row>
-      <el-row>
+      <el-row :gutter="20">
         <el-col :span="12">
           <el-form-item label="备注" prop="remark">
             <el-input v-model="editForm.remark" placeholder="请输入备注" :rows="5" type="textarea" />
           </el-form-item>
         </el-col>
+        <el-col :span="12">
+          <el-form-item label="合同签订时间" prop="contractSignTime">
+            <el-date-picker
+              v-model="editForm.contractSignTime"
+              :picker-options="pickerOptionsSign"
+              placeholder="选择签订日期"
+              style="width: 100%"
+              type="date"
+              value-format="yyyy-MM-dd" />
+          </el-form-item>
+        </el-col>
       </el-row>
     </el-form>
     <!-- 产品分类 -->
@@ -233,8 +260,11 @@
           inchargeId: null, //销售工程师
           inchargeName: '', //销售工程师姓名
           signatoryType: '',
+          signatoryUnit: '',
+          earnestMoney: 0,
           contractStartTime: '', //合同开始时间
           contractEndTime: '', //合同结束时间
+          contractSignTime: '', //合同签订时间
           signatoryName: '', //公司签约人
           signatoryId: null, //公司签约人id
           distributorId: null, //经销商id
@@ -248,11 +278,15 @@
           contractName: [{ required: true, trigger: 'blur', message: '请输入合同名称' }],
           contractType: [{ required: true, trigger: 'change', message: '请选择合同类型' }],
           signatoryType: [{ required: true, trigger: 'change', message: '请选择签订单位类型' }],
+          signatoryUnit: [{ required: true, trigger: 'change', message: '请选择合同签订单位' }],
           nboName: [{ required: true, trigger: 'change', message: '请选择关联项目' }],
           contractStartTime: [
             { required: true, trigger: 'change', validator: this.pickerOptionsStart, message: '请选择开始时间' },
           ],
           contractEndTime: [{ trigger: 'change', validator: this.pickerOptionsEnd, message: '请选择结束时间' }],
+          contractSignTime: [
+            { required: true, trigger: 'change', validator: this.pickerOptionsSign, message: '请选择签订时间' },
+          ],
           inchargeId: [{ required: true, trigger: 'change', message: '请选择销售工程师' }],
           signatoryName: [{ required: true, trigger: 'change', message: '请选择公司签约人' }],
           distributorName: [{ trigger: 'change', message: '请选择经销商' }],
@@ -273,6 +307,11 @@
             }
           },
         },
+        pickerOptionsSign: {
+          disabledDate: (time) => {
+            return time.getTime() > new Date().getTime()
+          },
+        },
         contractOptions: [], //合同类型
         signatoryOptions: [
           {
@@ -358,6 +397,21 @@
       openProject() {
         this.$refs.project.open()
       },
+      signatoryTypeChange() {
+        // 10: '终端用户'
+        // 20: '经销商'
+        // 30: '代理商'
+        if (this.editForm.signatoryType == '10') {
+          this.editForm.signatoryUnit = this.editForm.custName
+        }
+        if (this.editForm.signatoryType == '20') {
+          this.editForm.signatoryUnit = this.editForm.distributorName
+        }
+        // 现在还没有代理商
+        if (this.editForm.signatoryType == '30') {
+          this.editForm.signatoryUnit = ''
+        }
+      },
       // 关闭选择项目获取项目信息
       getBusinessInfo(data) {
         let business = data[0] || null
@@ -372,6 +426,7 @@
         this.editForm.inchargeId = business.saleId
         this.editForm.inchargeName = business.saleName
         this.businessUserQueryParams = { busId: business.id, custId: business.custId }
+        this.signatoryTypeChange()
         // 获取产品信息
         this.getProjectInfo(business.id)
       },
@@ -385,6 +440,7 @@
         if (!distributor) return
         this.editForm.distributorName = distributor.distName
         this.editForm.distributorId = distributor.id
+        this.signatoryTypeChange()
       },
       // 打开选择公司签约人
       openUser(multiple, property, label) {
@@ -418,7 +474,7 @@
       getContact(data) {
         let user = data[0] || null
         if (!user) return
-        this.editForm['custSignatoryName'] = user.userName
+        this.editForm['custSignatoryName'] = user.cuctName
         this.editForm['custSignatoryId'] = user.id
       },
       // 获取产品信息

+ 3 - 3
src/views/contract/components/EditCollection.vue

@@ -72,7 +72,7 @@
     },
     data() {
       return {
-        title: '新建回款计划',
+        title: '新建回款',
         editVisible: false,
         editForm: {
           planId: null, //计划回款id
@@ -96,14 +96,14 @@
     methods: {
       async init(planId = null, id) {
         if (!id) {
-          this.title = '新建回款计划'
+          this.title = '新建回款'
           if (planId) {
             this.editForm.planId = planId
           }
           this.editForm.contractCode = this.details.contractCode
           this.editForm.contractId = this.details.id
         } else {
-          this.title = '编辑回款计划'
+          this.title = '编辑回款'
           const [err, res] = await to(collectionApi.getDetails({ id }))
           if (err) return
           if (res.data) {

+ 24 - 0
src/views/contract/components/EditPlan.vue

@@ -32,6 +32,20 @@
               value-format="yyyy-MM-dd" />
           </el-form-item>
         </el-col>
+        <el-col :span="12">
+          <el-form-item label="计划回款比例" prop="planScale">
+            <el-input v-model="editForm.planScale" clearable placeholder="请输入计划回款比例">
+              <template slot="append">%</template>
+            </el-input>
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row :gutter="20">
+        <el-col :span="12">
+          <el-form-item label="回款条件" prop="planCondition">
+            <el-input v-model="editForm.planCondition" clearable placeholder="请输入回款条件" />
+          </el-form-item>
+        </el-col>
         <el-col :span="12">
           <el-form-item label="备注" prop="remark">
             <el-input v-model="editForm.remark" clearable placeholder="请输入备注" />
@@ -58,6 +72,11 @@
       },
     },
     data() {
+      const validateNumeric = (rule, value, callback) => {
+        if (isNaN(Number(value))) callback(new Error('只能为数字'))
+        if (Number(value) > 100) callback(new Error('必须小于100'))
+        else callback()
+      }
       return {
         title: '新建回款计划',
         editVisible: false,
@@ -66,6 +85,8 @@
           contractCode: '', //合同编号
           contractId: null, //合同id
           planAmount: '', //计划回款金额
+          planScale: 0,
+          planCondition: '',
           remark: '', //备注
         },
         editRules: {
@@ -74,6 +95,7 @@
           planDatetime: [
             { required: true, trigger: 'change', validator: this.pickerOptionsStart, message: '请选择计划回款日期' },
           ],
+          planScale: [{ trigger: 'change', validator: validateNumeric }],
         },
       }
     },
@@ -101,6 +123,7 @@
         let params = { ...this.editForm }
         const [valid] = await to(this.$refs.editForm.validate())
         if (valid == false) return
+        params.planScale = Number(params.planScale)
         const [err, res] = await to(collectionPlanApi.addCollectionPlan(params))
         if (err) return
         if (res.code == 200) this.$message.success(res.msg)
@@ -113,6 +136,7 @@
         let params = { ...this.editForm }
         const [valid] = await to(this.$refs.editForm.validate())
         if (valid == false) return
+        params.planScale = Number(params.planScale)
         const [err, res] = await to(collectionPlanApi.updateCollectionPlan(params))
         if (err) return
         if (res.code == 200) this.$message.success(res.msg)

+ 19 - 0
src/views/contract/components/ProductTable.vue

@@ -31,6 +31,9 @@
           <span v-else-if="item.label == '合计'">
             {{ calculatedDiscount(row.price, row.count) }}
           </span>
+          <span v-else-if="item.prop === 'prodClass'">
+            {{ selectDictLabel(productLineOptions, row.prodClass) }}
+          </span>
           <span v-else>{{ row[item.prop] }}</span>
         </template>
       </el-table-column>
@@ -78,6 +81,11 @@
             width: '100px',
             prop: 'prodClass',
           },
+          {
+            label: '产品型号',
+            width: '180px',
+            prop: 'prodCode',
+          },
           {
             label: '建议成交价',
             width: '100px',
@@ -98,6 +106,7 @@
             width: '120px',
           },
         ],
+        productLineOptions: [],
       }
     },
     watch: {
@@ -114,6 +123,9 @@
         return { ...item, price: item['price'] }
       })
     },
+    mounted() {
+      this.getOptions()
+    },
     methods: {
       // input修改
       handleChange(row) {
@@ -123,6 +135,13 @@
       handleDel(row) {
         this.$emit('delProductData', row)
       },
+      getOptions() {
+        Promise.all([this.getDicts('sys_product_line')])
+          .then(([productLine]) => {
+            this.productLineOptions = productLine.data.values || []
+          })
+          .catch((err) => console.log(err))
+      },
       // 计算总价
       calculatedDiscount(price, count) {
         let intPrice = price * 100

+ 10 - 1
src/views/contract/detail.vue

@@ -40,6 +40,9 @@
             <el-descriptions-item content-class-name="my-content" label="负责人" label-class-name="my-label">
               {{ details.inchargeName }}
             </el-descriptions-item>
+            <el-descriptions-item content-class-name="my-content" label="回款比例" label-class-name="my-label">
+              {{ scale(details.collectedAmount, details.contractAmount) }}
+            </el-descriptions-item>
           </el-descriptions>
         </header>
         <el-tabs v-model="activeName">
@@ -47,7 +50,7 @@
             <details-info :details="details" />
           </el-tab-pane>
           <el-tab-pane label="产品" name="product">
-            <details-product :product="product" />
+            <details-product :details="details" :product="product" @productUpdate="init" />
           </el-tab-pane>
           <el-tab-pane label="回款" name="collection">
             <details-collection v-if="activeName == 'collection'" :details="details" />
@@ -132,6 +135,12 @@
           this.details = data
         }
       },
+      scale(numer1, numer2) {
+        if (numer2 == 0) {
+          return '-'
+        }
+        return (Math.round((numer1 / numer2) * 10000) / 10000) * 100 + '%'
+      },
       async getRecord() {
         const [err, res] = await to(contractApi.getDynamicsList({ contractId: this.id }))
         if (err) return

+ 27 - 4
src/views/contract/index.vue

@@ -84,6 +84,9 @@
           <span v-else-if="item.prop === 'approStatus'">
             {{ approStatusOption[row.approStatus] }}
           </span>
+          <span v-else-if="item.prop === 'productLine'">
+            {{ productLineOptions[row.productLine] }}
+          </span>
           <span v-else-if="item.label === '合同有效时间'">
             {{ parseTime(row.contractStartTime, '{y}-{m}-{d}') }}~{{ parseTime(row.contractEndTime, '{y}-{m}-{d}') }}
           </span>
@@ -113,11 +116,14 @@
             }}
           </span>
           <span v-else-if="item.label === '合同签订时间'">
-            {{ parseTime(row.createdTime, '{y}-{m}-{d}') }}
+            {{ parseTime(row.contractSignTime, '{y}-{m}-{d}') }}
           </span>
           <span v-else-if="item.label === '回款金额'">
             {{ formatPrice(row.collectedAmount) }}
           </span>
+          <span v-else-if="item.label === '开票金额'">
+            {{ formatPrice(row.invoiceAmount) }}
+          </span>
           <el-button
             v-else-if="item.prop === 'contractCode'"
             style="font-size: 14px"
@@ -210,6 +216,7 @@
         industryOptions: [], //客户行业
         levelOptions: [], //客户级别
         contractOptions: {}, //合同类型
+        productLineOptions: {}, //产品线
         // 自定义列表
         showColumns: [],
         columns: [
@@ -248,6 +255,11 @@
             sortable: false,
             disableCheck: false,
           },
+          {
+            label: '产品线',
+            prop: 'productLine',
+            width: '140px',
+          },
           {
             label: '签订单位类型',
             width: '120px',
@@ -265,7 +277,7 @@
           {
             label: '合同签订时间',
             width: '120px',
-            prop: 'createdTime',
+            prop: 'contractSignTime',
             sortable: false,
             disableCheck: false,
           },
@@ -290,6 +302,13 @@
             sortable: false,
             disableCheck: false,
           },
+          {
+            label: '开票金额',
+            width: '120px',
+            prop: 'invoiceAmount',
+            sortable: false,
+            disableCheck: false,
+          },
           {
             label: '销售工程师',
             width: '120px',
@@ -321,12 +340,16 @@
     },
     methods: {
       getOptions() {
-        Promise.all([this.getDicts('contract_type')])
-          .then(([contract]) => {
+        Promise.all([this.getDicts('contract_type'), this.getDicts('sys_product_line')])
+          .then(([contract, productLine]) => {
             this.contractOptions = {}
             contract.data.values.filter((i) => {
               this.contractOptions[i.key] = i.value
             })
+            this.productLineOptions = {}
+            productLine.data.values.filter((i) => {
+              this.productLineOptions[i.key] = i.value
+            })
           })
           .catch((err) => console.log(err))
       },

+ 4 - 1
src/views/proj/business/components/DetailsContract.vue

@@ -33,6 +33,9 @@
           <span v-else-if="item.prop === 'collectedAmount'">
             {{ formatPrice(row.collectedAmount) }}
           </span>
+          <span v-else-if="item.prop === 'contractSignTime'">
+            {{ parseTime(row.contractSignTime, '{y}-{m}-{d}') }}
+          </span>
           <span v-else-if="item.label === '合同时间'">
             {{ parseTime(row.contractStartTime, '{y}-{m}-{d}') }}~{{ parseTime(row.contractEndTime, '{y}-{m}-{d}') }}
           </span>
@@ -120,7 +123,7 @@
           {
             label: '合同签订时间',
             width: '180px',
-            prop: 'createdTime',
+            prop: 'contractSignTime',
             sortable: false,
             disableCheck: false,
           },