소스 검색

feature:完成合同和回款模块,增加上传文件的配置以及上传的代码

liuzl 3 년 전
부모
커밋
c16932ea58

+ 3 - 0
.env

@@ -1,5 +1,8 @@
 VUE_GITHUB_USER_NAME=test
 VUE_APP_SECRET_KEY=preview
+VUE_APP_PROTOCOL="http://"
+# 文件上传
+VUE_APP_UPLOAD_WEED='http://192.168.0.252:9333/dir/assign',
 # 租户码
 VUE_APP_TENANT=default
 # 登录验证微服务名称

+ 11 - 11
src/api/contract/collection.js

@@ -2,8 +2,8 @@
  * @Author: liuzhenlin 461480418@qq.ocm
  * @Date: 2023-01-05 16:34:58
  * @LastEditors: liuzhenlin
- * @LastEditTime: 2023-01-07 16:12:48
- * @FilePath: \订单全流程管理系统\src\api\contract\index.js
+ * @LastEditTime: 2023-01-10 13:43:24
+ * @FilePath: \订单全流程管理系统\src\api\contract\collection.js
  */
 import micro_request from '@/utils/micro_request'
 const basePath = process.env.VUE_APP_ParentPath
@@ -12,24 +12,24 @@ export default {
   getList(query) {
     return micro_request.postRequest(basePath, 'CtrContractCollection', 'List', query)
   },
-  // 删除合同
-  delContract(query) {
+  // 删除回款
+  delCollection(query) {
     return micro_request.postRequest(basePath, 'CtrContractCollection', 'Delete', query)
   },
-  // 新增合同
-  addContract(query) {
+  // 新增回款
+  addCollection(query) {
     return micro_request.postRequest(basePath, 'CtrContractCollection', 'Add', query)
   },
-  // 获取合同列表
+  // 获取回款列表
   getDetails(query) {
     return micro_request.postRequest(basePath, 'CtrContractCollection', 'Get', query)
   },
-  // 更新合同
-  updateContract(query) {
+  // 更新回款
+  updateCollection(query) {
     return micro_request.postRequest(basePath, 'CtrContractCollection', 'Update', query)
   },
-  // 转移合同
-  transferContract(query) {
+  // 转移回款
+  transferCollection(query) {
     return micro_request.postRequest(basePath, 'CtrContractCollection', 'Transfer', query)
   },
 }

+ 5 - 9
src/api/contract/collectionPlan.js

@@ -12,12 +12,12 @@ export default {
   getList(query) {
     return micro_request.postRequest(basePath, 'CtrContractCollectionPlan', 'List', query)
   },
-  // 删除合同
-  delContract(query) {
+  // 删除回款计划
+  delCollectionPlan(query) {
     return micro_request.postRequest(basePath, 'CtrContractCollectionPlan', 'Delete', query)
   },
-  // 新增合同
-  addContract(query) {
+  // 新增回款计划
+  addCollectionPlan(query) {
     return micro_request.postRequest(basePath, 'CtrContractCollectionPlan', 'Add', query)
   },
   // 获取合同列表
@@ -25,11 +25,7 @@ export default {
     return micro_request.postRequest(basePath, 'CtrContractCollectionPlan', 'Get', query)
   },
   // 更新合同
-  updateContract(query) {
+  updateCollectionPlan(query) {
     return micro_request.postRequest(basePath, 'CtrContractCollectionPlan', 'Update', query)
   },
-  // 转移合同
-  transferContract(query) {
-    return micro_request.postRequest(basePath, 'CtrContractCollectionPlan', 'Transfer', query)
-  },
 }

+ 32 - 0
src/api/contract/enclosure.js

@@ -0,0 +1,32 @@
+/*
+ * @Author: liuzhenlin 461480418@qq.ocm
+ * @Date: 2023-01-05 16:34:58
+ * @LastEditors: liuzhenlin
+ * @LastEditTime: 2023-01-07 16:12:48
+ * @FilePath: \订单全流程管理系统\src\api\Collection\index.js
+ */
+
+import micro_request from '@/utils/micro_request'
+const basePath = process.env.VUE_APP_ParentPath
+export default {
+  // 获取附件列表
+  getList(query) {
+    return micro_request.postRequest(basePath, 'CtrContractAppend', 'List', query)
+  },
+  // 删除附件
+  delEnclosure(query) {
+    return micro_request.postRequest(basePath, 'CtrContractAppend', 'Delete', query)
+  },
+  // 新增附件
+  addEnclosure(query) {
+    return micro_request.postRequest(basePath, 'CtrContractAppend', 'Add', query)
+  },
+  // 获取附件详情
+  getDetails(query) {
+    return micro_request.postRequest(basePath, 'CtrContractAppend', 'Get', query)
+  },
+  // 更新附件
+  updateEnclosure(query) {
+    return micro_request.postRequest(basePath, 'CtrContractAppend', 'Update', query)
+  },
+}

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

@@ -32,4 +32,8 @@ export default {
   transferContract(query) {
     return micro_request.postRequest(basePath, 'CtrContract', 'Transfer', query)
   },
+  // 活动列表
+  getDynamicsList(query) {
+    return micro_request.postRequest(basePath, 'CtrContract', 'DynamicsList', query)
+  },
 }

+ 31 - 0
src/api/contract/invoice.js

@@ -0,0 +1,31 @@
+/*
+ * @Author: liuzhenlin 461480418@qq.ocm
+ * @Date: 2023-01-05 16:34:58
+ * @LastEditors: liuzhenlin
+ * @LastEditTime: 2023-01-07 16:12:48
+ * @FilePath: \订单全流程管理系统\src\api\Collection\index.js
+ */
+import micro_request from '@/utils/micro_request'
+const basePath = process.env.VUE_APP_ParentPath
+export default {
+  // 获取回款列表
+  getList(query) {
+    return micro_request.postRequest(basePath, 'CtrContractInvoice', 'List', query)
+  },
+  // 删除回款
+  delInvoice(query) {
+    return micro_request.postRequest(basePath, 'CtrContractInvoice', 'Delete', query)
+  },
+  // 新增回款
+  addInvoice(query) {
+    return micro_request.postRequest(basePath, 'CtrContractInvoice', 'Add', query)
+  },
+  // 获取回款详情
+  getDetails(query) {
+    return micro_request.postRequest(basePath, 'CtrContractInvoice', 'Get', query)
+  },
+  // 更新回款
+  updateInvoice(query) {
+    return micro_request.postRequest(basePath, 'CtrContractInvoice', 'Update', query)
+  },
+}

+ 31 - 0
src/utils/uploadajax.js

@@ -0,0 +1,31 @@
+export default function asyncUploadFile(option) {
+  return new Promise(function (resolve, reject) {
+    if (typeof XMLHttpRequest === 'undefined') {
+      return
+    }
+    let xhr = new XMLHttpRequest()
+    const action = option.action
+    const formData = new FormData()
+    formData.append(option.filename, option.file)
+
+    xhr.open('post', action, true)
+    xhr.onload = function () {
+      //即使是404也会进入这个相应函数,所以需要检测状态
+      if (xhr.status < 200 || xhr.status >= 300) {
+        //完成未完成,返回错误
+        reject(Error(xhr.statusText))
+      } else {
+        //完成,返回响应文本
+        resolve(xhr.response)
+      }
+    }
+
+    // 发生错误时的相应函数
+    xhr.onerror = function () {
+      reject(Error('Network Error'))
+    }
+
+    // 发送请求
+    xhr.send(formData)
+  })
+}

+ 304 - 0
src/views/collection/index.vue

@@ -0,0 +1,304 @@
+<!--
+ * @Author: liuzhenlin 461480418@qq.ocm
+ * @Date: 2023-01-10 13:40:41
+ * @LastEditors: liuzhenlin
+ * @LastEditTime: 2023-01-10 14:02:36
+ * @Description: file content
+ * @FilePath: \订单全流程管理系统\src\views\collection\index.vue
+-->
+<template>
+  <div class="collection-manage">
+    <vab-query-form>
+      <vab-query-form-top-panel>
+        <el-form :inline="true" label-width="0px" :model="queryForm" @submit.native.prevent>
+          <el-form-item prop="contractCode">
+            <el-input
+              v-model="queryForm.contractCode"
+              clearable
+              placeholder="合同编号"
+              @keyup.enter.native="queryData" />
+          </el-form-item>
+          <el-form-item prop="custId">
+            <el-input v-model="queryForm.custName" clearable placeholder="客户名称" @keyup.enter.native="queryData" />
+          </el-form-item>
+          <el-form-item prop="custId">
+            <el-select v-model="queryForm.approStatus" clearable placeholder="审核状态">
+              <el-option v-for="item in approStatusOption" :key="item.id" :label="item.label" :value="item.id" />
+            </el-select>
+          </el-form-item>
+          <el-form-item>
+            <el-button icon="el-icon-search" type="primary" @click="queryData">查询</el-button>
+          </el-form-item>
+        </el-form>
+      </vab-query-form-top-panel>
+      <vab-query-form-left-panel :span="12">
+        <!-- <el-button icon="el-icon-plus" size="mini" type="primary" @click="handleEdit()">新建</el-button>
+        <el-button icon="el-icon-delete" type="danger" @click="handleDelete()">删除</el-button> -->
+      </vab-query-form-left-panel>
+      <vab-query-form-right-panel :span="12">
+        <table-tool :check-list.sync="checkList" :columns="columns" />
+      </vab-query-form-right-panel>
+    </vab-query-form>
+    <el-table
+      v-loading="listLoading"
+      border
+      :data="list"
+      height="calc(100vh - 290px)"
+      @selection-change="setSelectRows">
+      <el-table-column align="center" show-overflow-tooltip type="selection" />
+      <el-table-column
+        v-for="(item, index) in finallyColumns"
+        :key="index"
+        align="center"
+        :label="item.label"
+        :min-width="item.width"
+        :prop="item.prop"
+        show-overflow-tooltip
+        :sortable="item.sortable">
+        <template #default="{ row }">
+          <el-button v-if="item.prop === 'custName'" class="link-button" type="text" @click="handleCustDetail(row)">
+            {{ row.custName }}
+          </el-button>
+          <el-button
+            v-else-if="item.prop === 'contractCode'"
+            class="link-button"
+            type="text"
+            @click="handleContractDetail(row)">
+            {{ row.contractCode }}
+          </el-button>
+          <span v-else-if="item.prop == 'collectionType'">
+            {{ collectionTypeOption.filter((item) => item.key == row.collectionType)[0].value || '-' }}
+          </span>
+          <span v-else-if="item.prop == 'approStatus'">{{ row.approStatus == '10' ? '未回款' : '已回款' }}</span>
+          <span v-else-if="item.prop == 'contractAmount'">{{ formatPrice(row.contractAmount) }}</span>
+          <span v-else-if="item.prop == 'collectionAmount'">{{ formatPrice(row.collectionAmount) }}</span>
+          <span v-else>{{ row[item.prop] }}</span>
+        </template>
+      </el-table-column>
+      <!-- <el-table-column align="center" label="操作">
+        <template slot-scope="scope">
+          <el-button type="text" @click="handleDelete(scope.row)">删除</el-button>
+        </template>
+      </el-table-column> -->
+    </el-table>
+    <el-pagination
+      background
+      :current-page="queryForm.pageNum"
+      :layout="layout"
+      :page-size="queryForm.pageSize"
+      :total="total"
+      @current-change="handleCurrentChange"
+      @size-change="handleSizeChange" />
+  </div>
+</template>
+
+<script>
+  import to from 'await-to-js'
+  import collectionApi from '@/api/contract/collection'
+  import TableTool from '@/components/table/TableTool'
+  export default {
+    name: 'OpenSea',
+    components: {
+      TableTool,
+    },
+    data() {
+      return {
+        approStatusOption: [
+          { id: '10', label: '未回款' },
+          { id: '20', label: '已回款' },
+        ],
+        listLoading: false,
+        layout: 'total, sizes, prev, pager, next, jumper',
+        list: [],
+        total: 0,
+        queryForm: {
+          pageNum: 1,
+          pageSize: 10,
+          contractCode: '', // 合同编号
+          contractName: '', //合同名称
+          custName: '', // 客户名称  ()
+          nboName: '', //项目名称
+          approStatus: '', //审批状态
+        },
+        collectionTypeOption: [], //回款方式
+        selectRows: [], //选择的表格数据
+        industryOptions: [], //客户行业
+        // 自定义列表
+        checkList: [],
+        columns: [
+          {
+            label: '合同编号',
+            width: 'auto',
+            prop: 'contractCode',
+            sortable: false,
+            disableCheck: false,
+          },
+          {
+            label: '客户名称',
+            width: 'auto',
+            prop: 'custName',
+            sortable: false,
+            disableCheck: false,
+          },
+          {
+            label: '合同金额',
+            width: '120px',
+            prop: 'contractAmount',
+            sortable: false,
+            disableCheck: false,
+          },
+          {
+            label: '回款方式',
+            width: '100px',
+            prop: 'collectionType',
+            sortable: false,
+            disableCheck: false,
+          },
+          {
+            label: '回款金额',
+            width: '120px',
+            prop: 'collectionAmount',
+            sortable: false,
+            disableCheck: false,
+          },
+          {
+            label: '审核状态',
+            width: '100px',
+            prop: 'approStatus',
+            sortable: false,
+            disableCheck: false,
+          },
+          {
+            label: '备注',
+            width: '100px',
+            prop: 'remark',
+            sortable: false,
+            disableCheck: false,
+          },
+          {
+            label: '更新时间',
+            width: '100px',
+            prop: 'updatedTime',
+            sortable: false,
+            disableCheck: false,
+          },
+          {
+            label: '创建时间',
+            width: '100px',
+            prop: 'createdTime',
+            sortable: false,
+            disableCheck: false,
+          },
+          {
+            label: '创建人',
+            width: '100px',
+            prop: 'createdName',
+            sortable: false,
+            disableCheck: false,
+          },
+        ],
+      }
+    },
+    computed: {
+      finallyColumns() {
+        return this.columns.filter((item) => this.checkList.includes(item.label))
+      },
+    },
+    mounted() {
+      this.getOptions()
+      this.queryData()
+    },
+    methods: {
+      getOptions() {
+        Promise.all([this.getDicts('collection_type')])
+          .then(([collectionType]) => {
+            this.collectionTypeOption = collectionType.data.values || []
+          })
+          .catch((err) => console.log(err))
+      },
+      async queryData() {
+        this.listLoading = true
+        const params = { ...this.queryForm }
+        const [err, res] = await to(collectionApi.getList(params))
+        if (err) return (this.listLoading = false)
+        this.list = res.data.list || []
+        this.total = res.data.total
+        this.listLoading = false
+      },
+      reset() {
+        this.queryForm = {
+          pageNum: 1,
+          pageSize: 10,
+          custCode: '', // 客户编码
+          custName: '', //客户名称
+          custIndustry: '', // 客户行业  ()
+          custLevel: '', //客户级别
+        }
+        this.queryData()
+      },
+      handleSizeChange(val) {
+        this.queryForm.pageSize = val
+        this.queryData()
+      },
+      handleCurrentChange(val) {
+        this.queryForm.pageNum = val
+        this.queryData()
+      },
+      setSelectRows(val) {
+        this.selectRows = val.map((item) => item.id)
+      },
+      // 客户详情
+      handleCustDetail(row) {
+        this.$router.push({
+          path: '/customer/detail',
+          query: {
+            id: row.custId,
+          },
+        })
+      },
+      // 合同详情
+      handleContractDetail(row) {
+        this.$router.push({
+          path: '/contract/detail',
+          query: {
+            id: row.contractId,
+          },
+        })
+      },
+      // 合同删除
+      handleDelete(row = null) {
+        let ids = row ? [row.id] : this.selectRows
+        if (!ids[0]) {
+          return
+        }
+        this.$confirm('确认删除?', '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning',
+        })
+          .then(async () => {
+            const [err, res] = await to(collectionApi.delCollection({ id: ids }))
+            if (err) return
+            if (res.code == 200) {
+              this.$message({
+                type: 'success',
+                message: '删除成功!',
+              })
+              this.queryData()
+            }
+          })
+          .catch(() => {})
+      },
+    },
+  }
+</script>
+
+<style lang="scss" scoped>
+  $base: '.collection-manage';
+  #{$base} {
+    height: calc(100vh - 60px - 12px * 2 - 40px);
+    padding: 12px;
+    background: #fff;
+    transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1), border 0s, color 0.1s, font-size 0s;
+  }
+</style>

+ 309 - 0
src/views/collection/plan.vue

@@ -0,0 +1,309 @@
+<!--
+ * @Author: liuzhenlin 461480418@qq.ocm
+ * @Date: 2023-01-10 13:40:41
+ * @LastEditors: liuzhenlin
+ * @LastEditTime: 2023-01-10 14:21:08
+ * @Description: file content
+ * @FilePath: \订单全流程管理系统\src\views\collection\plan.vue
+-->
+<template>
+  <div class="collection-plan">
+    <vab-query-form>
+      <vab-query-form-top-panel>
+        <el-form :inline="true" label-width="0px" :model="queryForm" @submit.native.prevent>
+          <el-form-item prop="contractCode">
+            <el-input
+              v-model="queryForm.contractCode"
+              clearable
+              placeholder="合同编号"
+              @keyup.enter.native="queryData" />
+          </el-form-item>
+          <el-form-item prop="custId">
+            <el-input v-model="queryForm.custName" clearable placeholder="客户名称" @keyup.enter.native="queryData" />
+          </el-form-item>
+          <el-form-item>
+            <el-button icon="el-icon-search" type="primary" @click="queryData">查询</el-button>
+          </el-form-item>
+        </el-form>
+      </vab-query-form-top-panel>
+      <vab-query-form-left-panel :span="12">
+        <!-- <el-button icon="el-icon-plus" size="mini" type="primary" @click="handleEdit()">新建</el-button>
+        <el-button icon="el-icon-delete" type="danger" @click="handleDelete()">删除</el-button> -->
+      </vab-query-form-left-panel>
+      <vab-query-form-right-panel :span="12">
+        <table-tool :check-list.sync="checkList" :columns="columns" />
+      </vab-query-form-right-panel>
+    </vab-query-form>
+    <el-table
+      v-loading="listLoading"
+      border
+      :data="list"
+      height="calc(100vh - 290px)"
+      @selection-change="setSelectRows">
+      <el-table-column align="center" show-overflow-tooltip type="selection" />
+      <el-table-column
+        v-for="(item, index) in finallyColumns"
+        :key="index"
+        align="center"
+        :label="item.label"
+        :min-width="item.width"
+        :prop="item.prop"
+        show-overflow-tooltip
+        :sortable="item.sortable">
+        <template #default="{ row }">
+          <el-button v-if="item.prop === 'custName'" class="link-button" type="text" @click="handleCustDetail(row)">
+            {{ row.custName }}
+          </el-button>
+          <el-button
+            v-else-if="item.prop === 'contractCode'"
+            class="link-button"
+            type="text"
+            @click="handleContractDetail(row)">
+            {{ row.contractCode }}
+          </el-button>
+          <span v-else-if="item.prop == 'planAmount'">{{ formatPrice(row.planAmount) }}</span>
+          <span v-else-if="item.prop == 'cashedAmount'">{{ formatPrice(row.cashedAmount) }}</span>
+          <span v-else-if="item.label == '未回款金额'">
+            {{ formatPrice(row.planAmount - row.cashedAmount) }}
+          </span>
+          <span v-else-if="item.prop == 'contractStatus'">
+            {{ row.contractStatus == '10' ? '待回款' : row.contractStatus == '20' ? '部分回款' : '全部回款' }}
+          </span>
+          <span v-else>{{ row[item.prop] }}</span>
+        </template>
+      </el-table-column>
+      <!-- <el-table-column align="center" label="操作">
+        <template slot-scope="scope">
+          <el-button type="text" @click="handleDelete(scope.row)">删除</el-button>
+        </template>
+      </el-table-column> -->
+    </el-table>
+    <el-pagination
+      background
+      :current-page="queryForm.pageNum"
+      :layout="layout"
+      :page-size="queryForm.pageSize"
+      :total="total"
+      @current-change="handleCurrentChange"
+      @size-change="handleSizeChange" />
+  </div>
+</template>
+
+<script>
+  import to from 'await-to-js'
+  import collectionPlanApi from '@/api/contract/collectionPlan'
+  import TableTool from '@/components/table/TableTool'
+  export default {
+    name: 'OpenSea',
+    components: {
+      TableTool,
+    },
+    data() {
+      return {
+        approStatusOption: [
+          { id: '10', label: '未回款' },
+          { id: '20', label: '已回款' },
+        ],
+        listLoading: false,
+        layout: 'total, sizes, prev, pager, next, jumper',
+        list: [],
+        total: 0,
+        queryForm: {
+          pageNum: 1,
+          pageSize: 10,
+          contractCode: '', // 合同编号
+          custName: '', // 客户名称  ()
+        },
+        selectRows: [], //选择的表格数据
+        industryOptions: [], //客户行业
+        // 自定义列表
+        checkList: [],
+        columns: [
+          {
+            label: '合同编号',
+            width: 'auto',
+            prop: 'contractCode',
+            sortable: false,
+            disableCheck: false,
+          },
+          {
+            label: '客户名称',
+            width: 'auto',
+            prop: 'custName',
+            sortable: false,
+            disableCheck: false,
+          },
+          {
+            label: '计划回款金额',
+            width: '120px',
+            prop: 'planAmount',
+            sortable: false,
+            disableCheck: false,
+          },
+          {
+            label: '计划回款日期',
+            width: '100px',
+            prop: 'planDatetime',
+            sortable: false,
+            disableCheck: false,
+          },
+          {
+            label: '备注',
+            width: '120px',
+            prop: 'remark',
+            sortable: false,
+            disableCheck: false,
+          },
+          {
+            label: '实际回款金额',
+            width: '120px',
+            prop: 'cashedAmount',
+            sortable: false,
+            disableCheck: false,
+          },
+          {
+            label: '实际回款日期',
+            width: '100px',
+            prop: 'cashedDatetime',
+            sortable: false,
+            disableCheck: false,
+          },
+          {
+            label: '未回款金额',
+            width: '100px',
+            sortable: false,
+            disableCheck: false,
+          },
+          {
+            label: '备注',
+            width: '100px',
+            prop: 'remark',
+            sortable: false,
+            disableCheck: false,
+          },
+          {
+            label: '回款状态',
+            width: '100px',
+            prop: 'contractStatus',
+            sortable: false,
+            disableCheck: false,
+          },
+          {
+            label: '更新时间',
+            width: '100px',
+            prop: 'updatedTime',
+            sortable: false,
+            disableCheck: false,
+          },
+          {
+            label: '创建时间',
+            width: '100px',
+            prop: 'createdTime',
+            sortable: false,
+            disableCheck: false,
+          },
+          {
+            label: '创建人',
+            width: '100px',
+            prop: 'createdName',
+            sortable: false,
+            disableCheck: false,
+          },
+        ],
+      }
+    },
+    computed: {
+      finallyColumns() {
+        return this.columns.filter((item) => this.checkList.includes(item.label))
+      },
+    },
+    mounted() {
+      this.queryData()
+    },
+    methods: {
+      async queryData() {
+        this.listLoading = true
+        const params = { ...this.queryForm }
+        const [err, res] = await to(collectionPlanApi.getList(params))
+        if (err) return (this.listLoading = false)
+        this.list = res.data.list || []
+        this.total = res.data.total
+        this.listLoading = false
+      },
+      reset() {
+        this.queryForm = {
+          pageNum: 1,
+          pageSize: 10,
+          custCode: '', // 客户编码
+          custName: '', //客户名称
+          custIndustry: '', // 客户行业  ()
+          custLevel: '', //客户级别
+        }
+        this.queryData()
+      },
+      handleSizeChange(val) {
+        this.queryForm.pageSize = val
+        this.queryData()
+      },
+      handleCurrentChange(val) {
+        this.queryForm.pageNum = val
+        this.queryData()
+      },
+      setSelectRows(val) {
+        this.selectRows = val.map((item) => item.id)
+      },
+      // 客户详情
+      handleCustDetail(row) {
+        this.$router.push({
+          path: '/customer/detail',
+          query: {
+            id: row.custId,
+          },
+        })
+      },
+      // 合同详情
+      handleContractDetail(row) {
+        this.$router.push({
+          path: '/contract/detail',
+          query: {
+            id: row.contractId,
+          },
+        })
+      },
+      // 回款计划删除
+      handleDelete(row = null) {
+        let ids = row ? [row.id] : this.selectRows
+        if (!ids[0]) {
+          return
+        }
+        this.$confirm('确认删除?', '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning',
+        })
+          .then(async () => {
+            const [err, res] = await to(collectionPlanApi.delCollectionPlan({ id: ids }))
+            if (err) return
+            if (res.code == 200) {
+              this.$message({
+                type: 'success',
+                message: '删除成功!',
+              })
+              this.queryData()
+            }
+          })
+          .catch(() => {})
+      },
+    },
+  }
+</script>
+
+<style lang="scss" scoped>
+  $base: '.collection-plan';
+  #{$base} {
+    height: calc(100vh - 60px - 12px * 2 - 40px);
+    padding: 12px;
+    background: #fff;
+    transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1), border 0s, color 0.1s, font-size 0s;
+  }
+</style>

+ 129 - 42
src/views/contract/components/DetailsCollection.vue

@@ -1,20 +1,23 @@
 <!--
- * @Author: liuzl liuzl0802
+ * @Author: liuzl 461480418@qq.com
  * @Date: 2023-01-09 13:54:40
  * @LastEditors: liuzhenlin
- * @LastEditTime: 2023-01-09 15:28:38
+ * @LastEditTime: 2023-01-10 14:39:40
  * @Description: file content
  * @FilePath: \订单全流程管理系统\src\views\contract\components\DetailsCollection.vue
 -->
 <template>
   <div class="collection-container">
+    <!-- 回款计划 -->
     <div class="collection-plan mb10">
       <el-row class="mb10">
         <el-col class="text-right" :span="24">
-          <el-button icon="el-icon-plus" size="mini" type="primary">新建回款计划</el-button>
+          <el-button icon="el-icon-plus" size="mini" type="primary" @click="$refs.collectionPlan.init()">
+            新建回款计划
+          </el-button>
         </el-col>
       </el-row>
-      <el-table border :data="collectionPlanData" height="calc(100% - 40px)">
+      <el-table border :data="collectionPlanData" height="calc(100% - 50px)">
         <el-table-column
           v-for="(item, index) in planColumns"
           :key="index"
@@ -24,21 +27,37 @@
           :prop="item.prop"
           show-overflow-tooltip>
           <template #default="{ row }">
-            <span v-if="item.label == '合计'">
-              {{ calculatedDiscount(row.tranPrice, row.prodNum) }}
+            <span v-if="item.prop == 'contractStatus'">
+              {{ row.contractStatus == '10' ? '待回款' : row.contractStatus == '20' ? '部分回款' : '全部回款' }}
             </span>
+            <span v-else-if="item.prop == 'planAmount'">{{ formatPrice(row.planAmount) }}</span>
             <span v-else>{{ row[item.prop] }}</span>
           </template>
         </el-table-column>
+        <el-table-column align="center" label="操作">
+          <template slot-scope="scope">
+            <el-button
+              :disabled="scope.row.contractStatus == '30'"
+              type="text"
+              @click="$refs.collection.init(scope.row.id)">
+              新建回款
+            </el-button>
+            <el-button type="text" @click="$refs.collectionPlan.init(scope.row.id)">编辑</el-button>
+            <el-button type="text" @click="handleDel(scope.row, 'plan')">删除</el-button>
+          </template>
+        </el-table-column>
       </el-table>
     </div>
+    <!-- 回款 -->
     <div class="collection">
       <el-row class="mb10">
         <el-col class="text-right" :span="24">
-          <el-button icon="el-icon-plus" size="mini" type="primary">新建回款</el-button>
+          <el-button icon="el-icon-plus" size="mini" type="primary" @click="$refs.collection.init()">
+            新建回款
+          </el-button>
         </el-col>
       </el-row>
-      <el-table border :data="collectionData" height="calc(100% - 40px)">
+      <el-table border :data="collectionData" height="calc(100% - 50px)">
         <el-table-column
           v-for="(item, index) in collectionColumns"
           :key="index"
@@ -48,23 +67,41 @@
           :prop="item.prop"
           show-overflow-tooltip>
           <template #default="{ row }">
-            <span v-if="item.label == '合计'">
-              {{ calculatedDiscount(row.tranPrice, row.prodNum) }}
+            <span v-if="item.prop == 'collectionType'">
+              {{ collectionTypeOption.filter((item) => item.key == row.collectionType)[0].value || '-' }}
             </span>
+            <span v-else-if="item.prop == 'approStatus'">
+              {{ row.approStatus == '10' ? '未回款' : '已回款' }}
+            </span>
+            <span v-else-if="item.prop == 'collectionAmount'">{{ formatPrice(row.collectionAmount) }}</span>
             <span v-else>{{ row[item.prop] }}</span>
           </template>
         </el-table-column>
       </el-table>
     </div>
+    <!-- 新增编辑回款计划 -->
+    <edit-plan ref="collectionPlan" :details="details" @collectionPlanSave="getCollectionPlaneList()" />
+    <!-- 新增编辑回款合同 -->
+    <edit-collection
+      ref="collection"
+      :collection-type-data="collectionTypeOption"
+      :details="details"
+      @collectionSave="getCollectionList()" />
   </div>
 </template>
 
 <script>
   import collectionApi from '@/api/contract/collection'
   import collectionPlanApi from '@/api/contract/collectionPlan'
+  import EditPlan from '@/views/contract/components/EditPlan'
+  import EditCollection from './EditCollection'
   import to from 'await-to-js'
   export default {
     name: 'DetailsCollection',
+    components: {
+      EditPlan,
+      EditCollection,
+    },
     props: {
       details: {
         type: Object,
@@ -73,92 +110,142 @@
     },
     data() {
       return {
-        collectionData: [],
-        collectionPlanData: [],
+        collectionData: [], //回款数据
+        collectionPlanData: [], //回款计划数据
         planColumns: [
           {
-            label: '产品名称',
+            label: '客户名称',
             width: 'auto',
-            prop: 'prodName',
+            prop: 'custName',
           },
           {
-            label: '产品类别',
+            label: '合同编号',
             width: '100px',
-            prop: 'prodClass',
+            prop: 'contractCode',
           },
           {
-            label: '建议成交价',
+            label: '计划回款金额',
             width: '100px',
-            prop: 'sugSalesPrice',
+            prop: 'planAmount',
           },
           {
-            label: '售价',
-            width: '160px',
-            prop: 'tranPrice',
+            label: '回款状态',
+            width: '100px',
+            prop: 'contractStatus',
           },
           {
-            label: '数量',
-            width: '160px',
-            prop: 'prodNum',
+            label: '计划回款日期',
+            width: '100px',
+            prop: 'planDatetime',
           },
           {
-            label: '合计',
-            width: '120px',
+            label: '备注',
+            width: '100px',
+            prop: 'remark',
           },
         ],
         collectionColumns: [
           {
-            label: '产品名称',
+            label: '客户名称',
             width: 'auto',
-            prop: 'prodName',
+            prop: 'custName',
           },
           {
-            label: '产品类别',
+            label: '合同编号',
             width: '100px',
-            prop: 'prodClass',
+            prop: 'contractCode',
           },
           {
-            label: '建议成交价',
+            label: '回款金额',
             width: '100px',
-            prop: 'sugSalesPrice',
+            prop: 'collectionAmount',
           },
           {
-            label: '售价',
+            label: '回款方式',
             width: '160px',
-            prop: 'tranPrice',
+            prop: 'collectionType',
+          },
+          {
+            label: '审核状态',
+            width: '80px',
+            prop: 'approStatus',
           },
           {
-            label: '数量',
+            label: '回款日期',
             width: '160px',
-            prop: 'prodNum',
+            prop: 'collectionDatetime',
           },
           {
-            label: '合计',
-            width: '120px',
+            label: '备注',
+            width: '160px',
+            prop: 'remark',
           },
         ],
+        collectionTypeOption: [], //,回款方式
       }
     },
 
     mounted() {
-      this.getCollectionData()
-      this.getCollectionPlaneData()
+      this.getOptions()
+      this.getCollectionList()
+      this.getCollectionPlaneList()
     },
 
     methods: {
+      getOptions() {
+        Promise.all([this.getDicts('collection_type')])
+          .then(([collectionType]) => {
+            this.collectionTypeOption = collectionType.data.values || []
+          })
+          .catch((err) => console.log(err))
+      },
       // 获取回款和回款计划列表
-      async getCollectionData() {
+      async getCollectionList() {
         let params = { contractId: this.details.id, pageNum: 0 }
         const [err, res] = await to(collectionApi.getList(params))
         if (err) return
         this.collectionData = res.data.list
       },
-      async getCollectionPlaneData() {
+      async getCollectionPlaneList() {
         let params = { contractId: this.details.id, pageNum: 0 }
         const [err, res] = await to(collectionPlanApi.getList(params))
         if (err) return
         this.collectionPlanData = res.data.list
       },
+      // 删除回款计划
+      handleDel(row, type) {
+        this.$confirm('确认删除?', '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning',
+        })
+          .then(async () => {
+            // 回款计划
+            if (type == 'plan') {
+              const [err, res] = await to(collectionPlanApi.delCollectionPlan({ id: [row.id] }))
+              if (err) return
+              if (res.code == 200) {
+                this.$message({
+                  type: 'success',
+                  message: '删除成功!',
+                })
+                this.getCollectionPlaneList()
+              }
+            } else {
+              // 回款
+              const [err, res] = await to(collectionPlanApi.delCollectionPlan({ id: [row.id] }))
+              if (err) return
+              if (res.code == 200) {
+                this.$message({
+                  type: 'success',
+                  message: '删除成功!',
+                })
+                this.queryData()
+              }
+            }
+          })
+          .catch(() => {})
+      },
     },
   }
 </script>

+ 269 - 0
src/views/contract/components/DetailsEnclosure.vue

@@ -0,0 +1,269 @@
+<template>
+  <!-- 回款计划 -->
+  <div class="enclosure-container">
+    <el-row class="mb10">
+      <el-col class="text-right" :span="24">
+        <el-upload
+          ref="uploadRef"
+          action="#"
+          :before-upload="
+            (file) => {
+              return beforeAvatarUpload(file)
+            }
+          "
+          :file-list="fileList"
+          :http-request="uploadrequest">
+          <el-button size="mini" type="primary">点击上传</el-button>
+        </el-upload>
+      </el-col>
+    </el-row>
+    <el-table border :data="enclosureData" height="calc(100% - 80px)">
+      <el-table-column
+        v-for="(item, index) in columns"
+        :key="index"
+        align="center"
+        :label="item.label"
+        :min-width="item.width"
+        :prop="item.prop"
+        show-overflow-tooltip>
+        <template #default="{ row }">
+          <span>{{ row[item.prop] }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column align="center" label="操作">
+        <template slot-scope="scope">
+          <el-button type="text" @click="downFile(scope.row.fileUrl, scope.row.fileName)">下载</el-button>
+          <el-button type="text" @click="rename(scope.row.id)">重命名</el-button>
+          <el-button type="text" @click="handleDel(scope.row)">删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <el-dialog title="编辑" :visible.sync="editVisible" width="300px">
+      <el-form ref="editForm" :model="editFiles" :rules="editRules">
+        <el-row :gutter="20">
+          <el-col :span="24">
+            <el-form-item label="新名称" prop="contractCode">
+              <el-input v-model="editFiles.fileName" placeholder="请输入新名称" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <span slot="footer">
+        <el-button type="primary" @click="saveEditName">保存</el-button>
+        <el-button @click="editVisible = false">取消</el-button>
+      </span>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+  import to from 'await-to-js'
+  import enclosureApi from '@/api/contract/enclosure'
+  import asyncUploadFile from '@/utils/uploadajax'
+  import axios from 'axios'
+
+  export default {
+    name: 'DetailsEnclosure',
+    props: {
+      details: {
+        type: Object,
+        default: () => {},
+      },
+    },
+    data() {
+      return {
+        fileList: [],
+        fileSettings: {
+          // 文件配置信息
+          fileSize: 52428800,
+          fileTypes: '.doc,.docx,.zip,.xls,.xlsx,.rar,.jpg,.jpeg,.gif,.png,.jfif,.txt',
+          pictureSize: 52428800,
+          pictureTypes: '.jpg,.jpeg,.gif,.png,.jfif,.txt',
+          types: '.doc,.docx,.zip,.xls,.xlsx,.rar,.jpg,.jpeg,.gif,.png,.jfif,.mp4,.txt',
+          videoSize: 104857600,
+          videoType: '.mp4',
+        },
+        editVisible: false, //编辑
+        // 编辑文件
+        editFiles: {
+          fileName: '',
+          id: 0,
+        },
+        editRules: {
+          fileName: [{ required: true, trigger: 'blur', message: '请输入新名称' }],
+        },
+        enclosureData: [],
+        columns: [
+          {
+            label: '附件名称',
+            width: 'auto',
+            prop: 'fileName',
+          },
+          {
+            label: '上传人',
+            width: '100px',
+            prop: 'createdName',
+          },
+          {
+            label: '上传时间',
+            width: '100px',
+            prop: 'createdTime',
+          },
+        ],
+      }
+    },
+
+    mounted() {
+      this.getenclosureList()
+    },
+
+    methods: {
+      async getenclosureList() {
+        let params = { contractId: this.details.id, pageNum: 0 }
+        const [err, res] = await to(enclosureApi.getList(params))
+        if (err) return
+        this.enclosureData = res.data.list
+      },
+      // 下载
+      /**
+       * 下载文件以及自定义文件名称
+       */
+      downFile(url, fileName) {
+        const xhr = new XMLHttpRequest()
+        xhr.open('GET', url, true)
+        xhr.responseType = 'blob' // 通过文件下载url拿到对应的blob对象
+        xhr.onload = () => {
+          if (xhr.status === 200) {
+            let link = document.createElement('a')
+            let body = document.querySelector('body')
+            link.href = window.URL.createObjectURL(xhr.response)
+            link.download = fileName
+            link.click()
+            body.removeChild(link)
+            window.URL.revokeObjectURL(link.href)
+          }
+        }
+
+        xhr.send()
+      },
+      // 重命名
+      rename(id) {
+        this.editFiles.id = id
+        this.editVisible = true
+      },
+      // 编辑新名称
+      async saveEditName() {
+        let params = { ...this.editFiles }
+        const [valid] = await to(this.$refs.editForm.validate())
+        if (valid == false) return
+        const [err, res] = await to(enclosureApi.updateEnclosure(params))
+        if (err) return
+        if (res.code == 200) this.getenclosureList()
+        else return
+        this.editVisible = false
+      },
+      // 删除图片
+      handleDel(row) {
+        this.$confirm('确认删除?', '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning',
+        })
+          .then(async () => {
+            const [err, res] = await to(enclosureApi.delEnclosure({ id: [row.id] }))
+            if (err) return
+            if (res.code == 200) {
+              this.$message({
+                type: 'success',
+                message: '删除成功!',
+              })
+              this.getenclosureList()
+            }
+          })
+          .catch(() => {})
+      },
+      // 上传图片
+      beforeAvatarUpload(file) {
+        let flag1 = file.size < this.fileSettings.fileSize
+        if (!flag1) {
+          this.$message.warning('文件过大,请重新选择!')
+          return false
+        }
+        let flag2 = this.fileSettings.fileTypes.split(',').includes('.' + file.name.split('.').pop())
+        if (!flag2) {
+          this.$message.warning('文件类型不符合,请重新选择!')
+          return false
+        }
+        return true
+      },
+      // 上传
+      uploadrequest(option) {
+        let _this = this
+        // let url = process.env.VUE_APP_UPLOAD_WEED
+        axios
+          .post('http://192.168.0.252:9333/dir/assign')
+          .then(function (res) {
+            if (res.data && res.data.fid && res.data.fid !== '') {
+              option.action = `${process.env.VUE_APP_PROTOCOL}${res.data.publicUrl}/${res.data.fid}`
+              let file_name = option.file.name
+              let index = file_name.lastIndexOf('.')
+              let file_extend = ''
+              if (index > 0) {
+                // 截取名称中的扩展名
+                file_extend = file_name.substr(index + 1)
+              }
+              let uploadform = {
+                fileName: file_name, // 资料名称
+                fileUrl: `${process.env.VUE_APP_PROTOCOL}${res.data.publicUrl}/${res.data.fid}`, // 资料存储url
+                size: option.file.size.toString(), // 资料大小
+                fileType: file_extend, // 资料文件类型
+              }
+              asyncUploadFile(option).then(() => {
+                let params = Object.assign({ ...uploadform, contractId: _this.details.id })
+                _this.addEnclosure(params)
+                // 一秒后删除上传信息
+                setTimeout(() => {
+                  _this.$refs.uploadRef.clearFiles()
+                }, 1000)
+              })
+            } else {
+              _this.$message({
+                type: 'warning',
+                message: '未上传成功!请刷新界面重新上传!',
+              })
+            }
+          })
+          .catch(function () {
+            _this.$message({
+              type: 'warning',
+              message: '未上传成功!请重新上传!',
+            })
+          })
+      },
+      // 新增附件接口
+      async addEnclosure(params) {
+        const [err, res] = await to(enclosureApi.addEnclosure(params))
+        if (err) return
+        if (res.code == 200) this.getenclosureList()
+      },
+    },
+  }
+</script>
+
+<style lang="scss" scoped>
+  .enclosure-container {
+    height: 100%;
+    .mb10 {
+      margin-bottom: 10px;
+    }
+    .collection {
+      height: 100%;
+      .el-row {
+        height: 30px;
+      }
+    }
+    .text-right {
+      text-align: right;
+    }
+  }
+</style>

+ 1 - 1
src/views/contract/components/DetailsInfo.vue

@@ -1,5 +1,5 @@
 <!--
- * @Author: liuzl liuzl0802
+ * @Author: liuzl 461480418@qq.com
  * @Date: 2023-01-09 13:54:36
  * @LastEditors: liuzhenlin
  * @LastEditTime: 2023-01-09 14:38:24

+ 163 - 0
src/views/contract/components/DetailsInvoice.vue

@@ -0,0 +1,163 @@
+<template>
+  <!-- 回款计划 -->
+  <div class="invoice-container">
+    <el-row class="mb10">
+      <el-col class="text-right" :span="24">
+        <el-button icon="el-icon-plus" size="mini" type="primary" @click="$refs.invoice.init()">新建发票</el-button>
+      </el-col>
+    </el-row>
+    <el-table border :data="invoiceData" height="calc(100% - 50px)">
+      <el-table-column
+        v-for="(item, index) in columns"
+        :key="index"
+        align="center"
+        :label="item.label"
+        :min-width="item.width"
+        :prop="item.prop"
+        show-overflow-tooltip>
+        <template #default="{ row }">
+          <span v-if="item.prop == 'invoiceType'">
+            {{ invoiceTypeData.filter((item) => item.key == row.invoiceType)[0].value || '-' }}
+          </span>
+          <span v-else-if="item.prop == 'approStatus'">
+            {{ row.approStatus == '10' ? '未通过' : '已通过' }}
+          </span>
+          <span v-else-if="item.prop == 'contractAmount'">
+            {{ formatPrice(row.contractAmount) }}
+          </span>
+          <span v-else-if="item.prop == 'invoiceAmount'">
+            {{ formatPrice(row.invoiceAmount) }}
+          </span>
+          <span v-else>{{ row[item.prop] }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column align="center" label="操作">
+        <template slot-scope="scope">
+          <el-button type="text" @click="$refs.invoicing.init(scope.row.id)">通过</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <edit-invoice ref="invoice" :details="details" :invoice-type-data="invoiceTypeData" @invoiceSave="getInvoiceList" />
+    <invoicing ref="invoicing" @invoiceSave="getInvoiceList" />
+  </div>
+</template>
+
+<script>
+  import to from 'await-to-js'
+  import invoiceApi from '@/api/contract/invoice'
+  import EditInvoice from './EditInvoice'
+  import Invoicing from './Invoicing'
+
+  export default {
+    name: 'DetailsInvoice',
+    components: { EditInvoice, Invoicing },
+    props: {
+      details: {
+        type: Object,
+        default: () => {},
+      },
+    },
+    data() {
+      return {
+        invoiceData: [],
+        invoiceTypeData: [], //发票类型
+        columns: [
+          {
+            label: '客户名称',
+            width: 'auto',
+            prop: 'custName',
+          },
+          {
+            label: '合同编号',
+            width: '100px',
+            prop: 'contractCode',
+          },
+          {
+            label: '合同金额',
+            width: '100px',
+            prop: 'contractAmount',
+          },
+          {
+            label: '开票金额(元)',
+            width: '120px',
+            prop: 'invoiceAmount',
+          },
+          {
+            label: '开票日期',
+            width: '100px',
+            prop: 'invoiceDate',
+          },
+          {
+            label: '实际开票日期',
+            width: '100px',
+            prop: 'actualInvoiceDate',
+          },
+          {
+            label: '开票类型',
+            width: '100px',
+            prop: 'invoiceType',
+          },
+          {
+            label: '发票号码',
+            width: '100px',
+            prop: 'invoiceCode',
+          },
+          {
+            label: '快递单号',
+            width: '100px',
+            prop: 'courierCode',
+          },
+          {
+            label: '审核状态',
+            width: '100px',
+            prop: 'approStatus',
+          },
+          {
+            label: '备注',
+            width: '100px',
+            prop: 'remark',
+          },
+        ],
+      }
+    },
+
+    mounted() {
+      this.getOptions()
+      this.getInvoiceList()
+    },
+
+    methods: {
+      getOptions() {
+        Promise.all([this.getDicts('invoice_type')])
+          .then(([invoiceType]) => {
+            this.invoiceTypeData = invoiceType.data.values || []
+          })
+          .catch((err) => console.log(err))
+      },
+      async getInvoiceList() {
+        let params = { contractId: this.details.id, pageNum: 0 }
+        const [err, res] = await to(invoiceApi.getList(params))
+        if (err) return
+        this.invoiceData = res.data.list
+      },
+    },
+  }
+</script>
+
+<style lang="scss" scoped>
+  .invoice-container {
+    height: 100%;
+    .mb10 {
+      margin-bottom: 10px;
+    }
+    .collection {
+      height: 100%;
+      .el-row {
+        height: 30px;
+      }
+    }
+    .text-right {
+      text-align: right;
+    }
+  }
+</style>

+ 8 - 2
src/views/contract/components/DetailsProduct.vue

@@ -1,8 +1,8 @@
 <!--
- * @Author: liuzl liuzl0802
+ * @Author: liuzl 461480418@qq.com
  * @Date: 2023-01-09 13:54:40
  * @LastEditors: liuzhenlin
- * @LastEditTime: 2023-01-09 14:35:38
+ * @LastEditTime: 2023-01-10 14:38:22
  * @Description: file content
  * @FilePath: \订单全流程管理系统\src\views\contract\components\DetailsProduct.vue
 -->
@@ -21,6 +21,12 @@
           <span v-if="item.label == '合计'">
             {{ calculatedDiscount(row.tranPrice, row.prodNum) }}
           </span>
+          <span v-else-if="item.prop == 'sugSalesPrice'">
+            {{ formatPrice(row.sugSalesPrice) }}
+          </span>
+          <span v-else-if="item.prop == 'tranPrice'">
+            {{ formatPrice(row.tranPrice) }}
+          </span>
           <span v-else>{{ row[item.prop] }}</span>
         </template>
       </el-table-column>

+ 140 - 0
src/views/contract/components/DetailsRecords.vue

@@ -0,0 +1,140 @@
+<!--
+ * @Author: liuzl 461480418@qq.com
+ * @Date: 2023-01-09 17:42:13
+ * @LastEditors: liuzhenlin
+ * @LastEditTime: 2023-01-09 17:55:42
+ * @Description: file content
+ * @FilePath: \订单全流程管理系统\src\views\contract\components\DetailsRecords.vue
+-->
+<template>
+  <ul class="records">
+    <li v-for="(value, key) in dynamicsList" :key="key">
+      <div class="date">
+        {{ key }}
+        <h2>{{ key.split('-')[2] }}</h2>
+        <h3>{{ key.split('-').splice(0, 2).join('.') }}</h3>
+      </div>
+      <ul class="content">
+        <li v-for="(item, index) in dynamicsList[key]" :key="index">
+          <!-- <el-avatar class="user-avatar"
+                           :src="avatar" /> -->
+          <vab-icon class="user-avatar" icon="account-circle-fill" />
+          <div class="text">
+            <p class="action">{{ item.opnPeople }} {{ item.opnType }}</p>
+            <p>{{ item.opnDate }}</p>
+            <p v-if="item.opnContent.custName">
+              客户名称:
+              <span>{{ item.opnContent.custName }}</span>
+            </p>
+            <template v-else-if="item.opnContent.cuctName">
+              <p>
+                联系人名称:
+                <span>{{ item.opnContent.cuctName }}</span>
+              </p>
+              <p>职务:{{ item.opnContent.postion }}</p>
+              <p>手机:{{ item.opnContent.telephone }}</p>
+            </template>
+          </div>
+        </li>
+      </ul>
+    </li>
+  </ul>
+</template>
+
+<script>
+  export default {
+    name: 'Records',
+    props: {
+      dynamicsList: {
+        // eslint-disable-next-line vue/require-prop-type-constructor
+        type: Array | Object,
+        default: () => [],
+      },
+    },
+    data() {
+      return {}
+    },
+
+    mounted() {
+      console.log(this.dynamicsList)
+    },
+
+    methods: {},
+  }
+</script>
+
+<style lang="scss" scoped>
+  .records {
+    margin: 0;
+    padding: 10px 20px;
+    list-style: none;
+    height: 100%;
+    overflow-y: auto;
+
+    > li {
+      display: flex;
+
+      & + li {
+        margin-top: 10px;
+      }
+    }
+
+    .date {
+      width: 100px;
+      display: flex;
+      flex-direction: column;
+      align-items: center;
+
+      h2,
+      h3 {
+        margin: 0;
+      }
+
+      h2 {
+        font-size: 26px;
+        line-height: 32px;
+      }
+    }
+
+    .content {
+      flex: 1;
+      list-style: none;
+
+      li {
+        display: flex;
+
+        & + li {
+          margin-top: 10px;
+        }
+      }
+
+      .user-avatar {
+        font-size: 40px;
+      }
+
+      .text {
+        flex: 1;
+        padding-left: 20px;
+
+        p {
+          font-weight: 500;
+          margin: 0;
+          line-height: 20px;
+
+          span {
+            color: #1d66dc;
+          }
+        }
+
+        p:nth-child(2) {
+          margin-bottom: 10px;
+        }
+
+        .action {
+          font-weight: bold;
+          color: #333;
+        }
+      }
+    }
+  }
+</style>

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

@@ -1,8 +1,162 @@
 <!--
- * @Author: liuzl liuzl0802
- * @Date: 2023-01-09 15:34:06
+ * @Author: liuzl 461480418@qq.com
+ * @Date: 2023-01-09 15:34:20
  * @LastEditors: liuzhenlin
- * @LastEditTime: 2023-01-09 15:35:04
+ * @LastEditTime: 2023-01-09 17:03:58
  * @Description: file content
  * @FilePath: \订单全流程管理系统\src\views\contract\components\EditCollection.vue
 -->
+<template>
+  <el-dialog :title="title" :visible.sync="editVisible" @close="handleClose">
+    <el-form ref="editForm" :model="editForm" :rules="editRules">
+      <el-row :gutter="20">
+        <el-col :span="12">
+          <el-form-item label="合同编号" prop="contractCode">
+            <el-input v-model="editForm.contractCode" :disabled="Boolean(details)" placeholder="请输入合同编号" />
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="回款金额" prop="collectionAmount">
+            <el-input v-model.number="editForm.collectionAmount" clearable placeholder="请输入回款金额" />
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row :gutter="20">
+        <el-col :span="12">
+          <el-form-item label="回款日期" prop="collectionDatetime">
+            <el-date-picker
+              v-model="editForm.collectionDatetime"
+              placeholder="选择回款日期"
+              style="width: 100%"
+              type="date"
+              value-format="yyyy-MM-dd" />
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="回款方式" prop="collectionType">
+            <el-select v-model="editForm.collectionType" placeholder="请选择回款方式" style="width: 100%">
+              <el-option v-for="item in collectionTypeData" :key="item.key" :label="item.value" :value="item.key" />
+            </el-select>
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row :gutter="20">
+        <el-col :span="12">
+          <el-form-item label="备注" prop="collectionType">
+            <el-input v-model="editForm.remark" clearable placeholder="请输入备注" type="textarea" />
+          </el-form-item>
+        </el-col>
+      </el-row>
+    </el-form>
+    <span slot="footer">
+      <el-button v-show="!editForm.id" type="primary" @click="collectionSave">保存</el-button>
+      <el-button v-show="editForm.id" type="primary" @click="contractEdit">保存</el-button>
+      <el-button @click="editVisible = false">取消</el-button>
+    </span>
+  </el-dialog>
+</template>
+
+<script>
+  import to from 'await-to-js'
+  import collectionApi from '@/api/contract/collection'
+  export default {
+    props: {
+      details: {
+        type: Object,
+        default: () => {},
+      },
+      collectionTypeData: {
+        type: Array,
+        default: () => [],
+      },
+    },
+    data() {
+      return {
+        title: '新建回款计划',
+        editVisible: false,
+        editForm: {
+          planId: null, //计划回款id
+          collectionDatetime: '', //回款日期
+          contractCode: '', //合同编号
+          contractId: null, //合同id
+          collectionAmount: '', //回款金额
+          collectionType: '', //回款方式
+          remark: '', //备注
+        },
+        editRules: {
+          contractCode: [{ required: true, trigger: 'blur', message: '请选择合同' }],
+          collectionAmount: [{ required: true, trigger: 'blur', message: '请输入回款金额' }],
+          collectionDatetime: [
+            { required: true, trigger: 'change', validator: this.pickerOptionsStart, message: '请选择回款日期' },
+          ],
+        },
+      }
+    },
+    mounted() {},
+    methods: {
+      async init(planId = null, id) {
+        if (!id) {
+          this.title = '新建回款计划'
+          if (planId) {
+            this.editForm.planId = planId
+          }
+          this.editForm.contractCode = this.details.contractCode
+          this.editForm.contractId = this.details.id
+        } else {
+          this.title = '编辑回款计划'
+          const [err, res] = await to(collectionApi.getDetails({ id }))
+          if (err) return
+          if (res.data) {
+            this.editForm = res.data
+          }
+        }
+        this.editVisible = true
+      },
+      // 保存回款计划
+      async collectionSave() {
+        let params = { ...this.editForm }
+        const [valid] = await to(this.$refs.editForm.validate())
+        if (valid == false) return
+        const [err, res] = await to(collectionApi.addCollection(params))
+        if (err) return
+        if (res.code == 200) this.$message.success(res.msg)
+        else return
+        this.editVisible = false
+        this.$emit('collectionSave')
+      },
+      // 编辑回款计划
+      async contractEdit() {
+        let params = { ...this.editForm }
+        const [valid] = await to(this.$refs.editForm.validate())
+        if (valid == false) return
+        const [err, res] = await to(collectionApi.updatecollectionApi(params))
+        if (err) return
+        if (res.code == 200) this.$message.success(res.msg)
+        else return
+        this.editVisible = false
+        this.$emit('collectionSave')
+      },
+      handleClose() {
+        this.editForm = {
+          planId: null, //计划回款id
+          collectionDatetime: '', //回款日期
+          contractCode: '', //合同编号
+          contractId: null, //合同id
+          collectionAmount: '', //回款金额
+          collectionType: '', //回款方式
+          remark: '', //备注
+        }
+        this.$refs.editForm.resetFields()
+      },
+    },
+  }
+</script>
+
+<style lang="scss" scoped>
+  .mb10 {
+    margin-bottom: 10px;
+  }
+  .proj-col {
+    text-align: right;
+  }
+</style>

+ 160 - 0
src/views/contract/components/EditInvoice.vue

@@ -0,0 +1,160 @@
+<!--
+ * @Author: liuzl 461480418@qq.com
+ * @Date: 2023-01-09 15:34:20
+ * @LastEditors: liuzhenlin
+ * @LastEditTime: 2023-01-10 09:53:19
+ * @Description: file content
+ * @FilePath: \订单全流程管理系统\src\views\contract\components\EditInvoice.vue
+-->
+<template>
+  <el-dialog :title="title" :visible.sync="editVisible" @close="handleClose">
+    <el-form ref="editForm" :model="editForm" :rules="editRules">
+      <el-row :gutter="20">
+        <el-col :span="12">
+          <el-form-item label="合同编号" prop="contractCode">
+            <el-input v-model="editForm.contractCode" :disabled="Boolean(details)" placeholder="请输入合同编号" />
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="开票金额" prop="invoiceAmount">
+            <el-input v-model.number="editForm.invoiceAmount" clearable placeholder="请输入开票金额" />
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row :gutter="20">
+        <el-col :span="12">
+          <el-form-item label="开票日期" prop="invoiceDate">
+            <el-date-picker
+              v-model="editForm.invoiceDate"
+              placeholder="选择开票日期"
+              style="width: 100%"
+              type="date"
+              value-format="yyyy-MM-dd" />
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="开票类型" prop="invoiceType">
+            <el-select v-model="editForm.invoiceType" placeholder="请选择开票类型" style="width: 100%">
+              <el-option v-for="item in invoiceTypeData" :key="item.key" :label="item.value" :value="item.key" />
+            </el-select>
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row :gutter="20">
+        <el-col :span="12">
+          <el-form-item label="备注" prop="remark">
+            <el-input v-model="editForm.remark" clearable placeholder="请输入备注" rows="5" type="textarea" />
+          </el-form-item>
+        </el-col>
+      </el-row>
+    </el-form>
+    <span slot="footer">
+      <el-button v-show="!editForm.id" type="primary" @click="invoiceSave">保存</el-button>
+      <el-button v-show="editForm.id" type="primary" @click="contractEdit">保存</el-button>
+      <el-button @click="editVisible = false">取消</el-button>
+    </span>
+  </el-dialog>
+</template>
+
+<script>
+  import to from 'await-to-js'
+  import invoiceApi from '@/api/contract/invoice'
+  export default {
+    props: {
+      details: {
+        type: Object,
+        default: () => {},
+      },
+      invoiceTypeData: {
+        type: Array,
+        default: () => [],
+      },
+    },
+    data() {
+      return {
+        title: '新建发票',
+        editVisible: false,
+        editForm: {
+          invoiceDate: '', //开票日期
+          contractCode: '', //合同编号
+          contractId: null, //合同id
+          invoiceAmount: '', //开票金额
+          invoiceType: '', //开票类型
+          remark: '', //备注
+        },
+        editRules: {
+          contractCode: [{ required: true, trigger: 'blur', message: '请选择合同' }],
+          invoiceAmount: [{ required: true, trigger: 'blur', message: '请输入开票金额' }],
+          invoiceDate: [{ required: true, trigger: 'change', message: '请选择开票日期' }],
+          invoiceType: [{ required: true, trigger: 'chgange', message: '请输入开票类型' }],
+        },
+      }
+    },
+    mounted() {},
+    methods: {
+      async init(id) {
+        if (!id) {
+          this.title = '新建发票'
+          if (this.details) {
+            console.log(this.details)
+            this.editForm.contractCode = this.details.contractCode
+            this.editForm.contractId = this.details.id
+            console.log(this.editForm)
+          }
+        } else {
+          this.title = '编辑发票'
+          const [err, res] = await to(invoiceApi.getDetails({ id }))
+          if (err) return
+          if (res.data) {
+            this.editForm = res.data
+          }
+        }
+        this.editVisible = true
+      },
+      // 保存发票
+      async invoiceSave() {
+        let params = { ...this.editForm }
+        const [valid] = await to(this.$refs.editForm.validate())
+        if (valid == false) return
+        const [err, res] = await to(invoiceApi.addInvoice(params))
+        if (err) return
+        if (res.code == 200) this.$message.success(res.msg)
+        else return
+        this.editVisible = false
+        this.$emit('invoiceSave')
+      },
+      // 编辑发票
+      async contractEdit() {
+        let params = { ...this.editForm }
+        const [valid] = await to(this.$refs.editForm.validate())
+        if (valid == false) return
+        const [err, res] = await to(invoiceApi.updateInvoice(params))
+        if (err) return
+        if (res.code == 200) this.$message.success(res.msg)
+        else return
+        this.editVisible = false
+        this.$emit('invoiceSave')
+      },
+      handleClose() {
+        this.editForm = {
+          invoiceDate: '', //开票日期
+          contractCode: '', //合同编号
+          contractId: null, //合同id
+          invoiceAmount: '', //开票金额
+          invoiceType: '', //开票类型
+          remark: '', //备注
+        }
+        this.$refs.editForm.resetFields()
+      },
+    },
+  }
+</script>
+
+<style lang="scss" scoped>
+  .mb10 {
+    margin-bottom: 10px;
+  }
+  .proj-col {
+    text-align: right;
+  }
+</style>

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

@@ -0,0 +1,144 @@
+<!--
+ * @Author: liuzl 461480418@qq.com
+ * @Date: 2023-01-09 15:34:20
+ * @LastEditors: liuzhenlin
+ * @LastEditTime: 2023-01-09 16:13:14
+ * @Description: file content
+ * @FilePath: \订单全流程管理系统\src\views\contract\components\EditPlan.vue
+-->
+<template>
+  <el-dialog :title="title" :visible.sync="editVisible" @close="handleClose">
+    <el-form ref="editForm" :model="editForm" :rules="editRules">
+      <el-row :gutter="20">
+        <el-col :span="12">
+          <el-form-item label="合同编号" prop="contractCode">
+            <el-input v-model="editForm.contractCode" :disabled="Boolean(details)" placeholder="请输入合同编号" />
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="计划回款金额" prop="planAmount">
+            <el-input v-model.number="editForm.planAmount" clearable placeholder="请输入计划回款金额" />
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row :gutter="20">
+        <el-col :span="12">
+          <el-form-item label="计划回款日期" prop="planDatetime">
+            <el-date-picker
+              v-model="editForm.planDatetime"
+              placeholder="选择计划回款日期"
+              style="width: 100%"
+              type="date"
+              value-format="yyyy-MM-dd" />
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="备注" prop="remark">
+            <el-input v-model="editForm.remark" clearable placeholder="请输入备注" />
+          </el-form-item>
+        </el-col>
+      </el-row>
+    </el-form>
+    <span slot="footer">
+      <el-button v-show="!editForm.id" type="primary" @click="collectionPlanSave">保存</el-button>
+      <el-button v-show="editForm.id" type="primary" @click="contractEdit">保存</el-button>
+      <el-button @click="editVisible = false">取消</el-button>
+    </span>
+  </el-dialog>
+</template>
+
+<script>
+  import to from 'await-to-js'
+  import collectionPlanApi from '@/api/contract/collectionPlan'
+  export default {
+    props: {
+      details: {
+        type: Object,
+        default: () => {},
+      },
+    },
+    data() {
+      return {
+        title: '新建回款计划',
+        editVisible: false,
+        editForm: {
+          planDatetime: '', //计划回款日期
+          contractCode: '', //合同编号
+          contractId: null, //合同id
+          planAmount: '', //计划回款金额
+          remark: '', //备注
+        },
+        editRules: {
+          contractCode: [{ required: true, trigger: 'blur', message: '请选择合同' }],
+          planAmount: [{ required: true, trigger: 'blur', message: '请输入计划回款金额' }],
+          planDatetime: [
+            { required: true, trigger: 'change', validator: this.pickerOptionsStart, message: '请选择计划回款日期' },
+          ],
+        },
+      }
+    },
+    mounted() {},
+    methods: {
+      async init(id) {
+        if (!id) {
+          this.title = '新建回款计划'
+          if (this.details) {
+            this.editForm.contractCode = this.details.contractCode
+            this.editForm.contractId = this.details.id
+          }
+        } else {
+          this.title = '编辑回款计划'
+          const [err, res] = await to(collectionPlanApi.getDetails({ id }))
+          if (err) return
+          if (res.data) {
+            this.editForm = res.data
+          }
+        }
+        this.editVisible = true
+      },
+      // 保存回款计划
+      async collectionPlanSave() {
+        let params = { ...this.editForm }
+        const [valid] = await to(this.$refs.editForm.validate())
+        if (valid == false) return
+        const [err, res] = await to(collectionPlanApi.addCollectionPlan(params))
+        if (err) return
+        if (res.code == 200) this.$message.success(res.msg)
+        else return
+        this.editVisible = false
+        this.$emit('collectionPlanSave')
+      },
+      // 编辑回款计划
+      async contractEdit() {
+        let params = { ...this.editForm }
+        const [valid] = await to(this.$refs.editForm.validate())
+        if (valid == false) return
+        const [err, res] = await to(collectionPlanApi.updateCollectionPlan(params))
+        if (err) return
+        if (res.code == 200) this.$message.success(res.msg)
+        else return
+        this.editVisible = false
+        this.$emit('collectionPlanSave')
+      },
+      handleClose() {
+        this.editForm = {
+          planDatetime: '', //计划回款日期
+          contractCode: '', //合同编号
+          contractId: null, //合同id
+          planAmount: '', //计划回款金额
+          remark: '', //备注
+        }
+        this.$refs.editForm.resetFields()
+      },
+    },
+  }
+</script>
+
+<style lang="scss" scoped>
+  .mb10 {
+    margin-bottom: 10px;
+  }
+  .proj-col {
+    text-align: right;
+  }
+</style>

+ 0 - 190
src/views/contract/components/EditPlane.vue

@@ -1,190 +0,0 @@
-<!--
- * @Author: liuzl liuzl0802
- * @Date: 2023-01-09 15:34:20
- * @LastEditors: liuzhenlin
- * @LastEditTime: 2023-01-09 15:39:32
- * @Description: file content
- * @FilePath: \订单全流程管理系统\src\views\contract\components\EditPlane.vue
--->
-<template>
-  <el-dialog :title="title" :visible.sync="editVisible" @close="handleClose">
-    <el-form ref="editForm" :model="editForm" :rules="editRules">
-      <el-row :gutter="20">
-        <el-col :span="12">
-          <el-form-item label="客户名称" prop="contractCode">
-            <el-input v-model="editForm.contractCode" placeholder="请输入合同编号" />
-          </el-form-item>
-        </el-col>
-        <el-col :span="12">
-          <el-form-item label="合同编号" prop="contractName">
-            <el-input v-model="editForm.contractName" placeholder="请输入合同名称" />
-          </el-form-item>
-        </el-col>
-      </el-row>
-      <el-row :gutter="20">
-        <el-col :span="12">
-          <el-form-item label="合同开始时间" prop="contractStartTime">
-            <el-date-picker
-              v-model="editForm.contractStartTime"
-              :picker-options="pickerOptionsStart"
-              placeholder="选择开始日期"
-              style="width: 100%"
-              type="date"
-              value-format="yyyy-MM-dd" />
-          </el-form-item>
-        </el-col>
-        <el-col :span="12">
-          <el-form-item label="合同结束时间" prop="contractEndTime">
-            <el-date-picker
-              v-model="editForm.contractEndTime"
-              :picker-options="pickerOptionsEnd"
-              placeholder="选择结束日期"
-              style="width: 100%"
-              type="date"
-              value-format="yyyy-MM-dd" />
-          </el-form-item>
-        </el-col>
-      </el-row>
-    </el-form>
-    <span slot="footer">
-      <el-button v-show="!editForm.id" type="primary" @click="contractSave">保存</el-button>
-      <el-button v-show="editForm.id" type="primary" @click="contractEdit">保存</el-button>
-      <el-button @click="editVisible = false">取消</el-button>
-    </span>
-  </el-dialog>
-</template>
-
-<script>
-  import to from 'await-to-js'
-  import contractApi from '@/api/contract'
-  export default {
-    props: {},
-    data() {
-      return {
-        title: '新建回款计划',
-        editVisible: false,
-        editForm: {
-          contractCode: '', //合同编号
-          contractName: '', //合同名称
-          contractType: '', //合同类型
-        },
-        editRules: {
-          contractCode: [{ required: true, trigger: 'blur', message: '请输入合同编号' }],
-          contractName: [{ required: true, trigger: 'blur', message: '请输入合同名称' }],
-          contractType: [{ required: true, trigger: 'change', message: '请选择合同类型' }],
-          nboName: [{ required: true, trigger: 'change', message: '请选择关联项目' }],
-          contractStartTime: [
-            { required: true, trigger: 'change', validator: this.pickerOptionsStart, message: '请选择开始时间' },
-          ],
-          contractEndTime: [
-            { required: true, trigger: 'change', validator: this.pickerOptionsEnd, message: '请选择结束时间' },
-          ],
-          inchargeId: [{ required: true, trigger: 'change', message: '请选择负责人' }],
-          signatoryName: [{ required: true, trigger: 'change', message: '请选择公司签约人' }],
-          distributorName: [{ required: true, trigger: 'change', message: '请选择经销商' }],
-        },
-      }
-    },
-    mounted() {},
-    methods: {
-      async init(id) {
-        if (!id) {
-          this.title = '新建回款计划'
-        } else {
-          this.title = '编辑合同'
-          const [err, res] = await to(contractApi.getDetails({ id }))
-          if (err) return
-          if (res.data) {
-            // eslint-disable-next-line no-unused-vars
-            let { product, ...data } = res.data
-            this.editForm = data
-            this.productData =
-              product.length > 0
-                ? product.map((item) => ({
-                    id: item.prodId,
-                    prodName: item.prodName,
-                    prodClass: item.prodClass,
-                    guidPrice: item.sugSalesPrice,
-                    price: item.tranPrice,
-                    count: item.prodNum,
-                  }))
-                : []
-          }
-        }
-        this.editVisible = true
-      },
-      // 保存合同
-      async contractSave() {
-        let product = this.productData.map((item) => ({
-          prodId: item.id,
-          prodNum: item.count,
-          maintTerm: 1,
-          sugSalesPrice: item.guidPrice,
-          tranPrice: this.delcommafy(item.price),
-          remark: '',
-        }))
-        let params = Object.assign({ ...this.editForm }, { product })
-        const [valid] = await to(this.$refs.editForm.validate())
-        if (valid == false) return
-        if (product.length == 0) return this.$message.warning('请选择产品信息')
-        const [err, res] = await to(contractApi.addContract(params))
-        if (err) return
-        if (res.code == 200) this.$message.success(res.msg)
-        else return
-        this.editVisible = false
-        this.$emit('contractSave')
-      },
-      // 编辑合同
-      async contractEdit() {
-        let product = this.productData.map((item) => ({
-          prodId: item.id,
-          prodNum: item.count,
-          maintTerm: 1,
-          sugSalesPrice: item.guidPrice,
-          tranPrice: this.delcommafy(item.price),
-          remark: '',
-        }))
-        let params = Object.assign({ ...this.editForm }, { product })
-        const [valid] = await to(this.$refs.editForm.validate())
-        if (valid == false) return
-        if (product.length == 0) return this.$message.warning('请选择产品信息')
-        const [err, res] = await to(contractApi.updateContract(params))
-        if (err) return
-        if (res.code == 200) this.$message.success(res.msg)
-        else return
-        this.editVisible = false
-        this.$emit('contractSave')
-      },
-      handleClose() {
-        this.editForm = {
-          contractCode: '', //合同编号
-          contractName: '', //合同名称
-          contractType: '', //合同类型
-          nboId: null, //项目id
-          nboName: '', //项目名称
-          custName: '', // 客户名称
-          inchargeId: null, //负责人
-          inchargeName: '', //负责人名称
-          contractStartTime: '', //合同开始时间
-          contractEndTime: '', //合同结束时间
-          signatoryName: '', //公司签约人
-          signatoryId: null, //公司签约人id
-          distributorId: null, //经销商id
-          distributorName: '', //经销商name
-          remark: '', //备注
-        }
-        this.productData = []
-        this.$refs.editForm.resetFields()
-      },
-    },
-  }
-</script>
-
-<style lang="scss" scoped>
-  .mb10 {
-    margin-bottom: 10px;
-  }
-  .proj-col {
-    text-align: right;
-  }
-</style>

+ 114 - 0
src/views/contract/components/Invoicing.vue

@@ -0,0 +1,114 @@
+<!--
+ * @Author: liuzl 461480418@qq.com
+ * @Date: 2023-01-09 15:34:20
+ * @LastEditors: liuzhenlin
+ * @LastEditTime: 2023-01-10 10:03:40
+ * @Description: file content
+ * @FilePath: \订单全流程管理系统\src\views\contract\components\Invoicing.vue
+-->
+<template>
+  <el-dialog :title="title" :visible.sync="editVisible" width="500px" @close="handleClose">
+    <el-form ref="editForm" :model="editForm" :rules="editRules">
+      <el-row :gutter="20">
+        <el-col :span="24">
+          <el-form-item label="发票号码" prop="invoiceCode">
+            <el-input v-model="editForm.invoiceCode" placeholder="请输入发票号码" />
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row :gutter="20">
+        <el-col :span="24">
+          <el-form-item label="实际开票日期" prop="actualInvoiceDate">
+            <el-date-picker
+              v-model="editForm.actualInvoiceDate"
+              placeholder="选择实际开票日期"
+              style="width: 100%"
+              type="date"
+              value-format="yyyy-MM-dd" />
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row :gutter="20">
+        <el-col :span="24">
+          <el-form-item label="物流单号" prop="courierCode">
+            <el-input v-model="editForm.courierCode" clearable placeholder="请输入物流单号" />
+          </el-form-item>
+        </el-col>
+      </el-row>
+    </el-form>
+    <span slot="footer">
+      <el-button type="primary" @click="invoiceSave">保存</el-button>
+      <el-button @click="editVisible = false">取消</el-button>
+    </span>
+  </el-dialog>
+</template>
+
+<script>
+  import to from 'await-to-js'
+  import invoiceApi from '@/api/contract/invoice'
+  export default {
+    props: {
+      details: {
+        type: Object,
+        default: () => {},
+      },
+    },
+    data() {
+      return {
+        title: '新建发票',
+        editVisible: false,
+        editForm: {
+          id: 0,
+          approStatus: '20',
+          actualInvoiceDate: '', //实际开票日期
+          invoiceCode: '', //发票号码
+          courierCode: '', //快递单号
+        },
+        editRules: {
+          invoiceCode: [{ required: true, trigger: 'blur', message: '请输入发票号码' }],
+          actualInvoiceDate: [{ required: true, trigger: 'change', message: '请选择实际开票日期' }],
+          courierCode: [{ required: true, trigger: 'blur', message: '请输入快递单号' }],
+        },
+      }
+    },
+    mounted() {},
+    methods: {
+      async init(id) {
+        this.title = '发票审核'
+        this.editForm.id = id
+        this.editVisible = true
+      },
+      // 审核通过
+      async invoiceSave() {
+        let params = { ...this.editForm }
+        const [valid] = await to(this.$refs.editForm.validate())
+        if (valid == false) return
+        const [err, res] = await to(invoiceApi.updateInvoice(params))
+        if (err) return
+        if (res.code == 200) this.$message.success(res.msg)
+        else return
+        this.editVisible = false
+        this.$emit('invoiceSave')
+      },
+      handleClose() {
+        this.editForm = {
+          id: 0,
+          approStatus: '20',
+          actualInvoiceDate: '', //实际开票日期
+          invoiceCode: '', //发票号码
+          courierCode: '', //快递单号
+        }
+        this.$refs.editForm.resetFields()
+      },
+    },
+  }
+</script>
+
+<style lang="scss" scoped>
+  .mb10 {
+    margin-bottom: 10px;
+  }
+  .proj-col {
+    text-align: right;
+  }
+</style>

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

@@ -109,7 +109,6 @@
         this.data = this.productData.map((item) => {
           return { ...item, price: this.setPriceFormat(item['price']) }
         })
-        console.log(this.data)
       },
     },
     created() {

+ 1 - 1
src/views/contract/components/Transfer.vue

@@ -1,5 +1,5 @@
 <!--
- * @Author: liuzl liuzl0802
+ * @Author: liuzl 461480418@qq.com
  * @Date: 2023-01-07 15:44:08
  * @LastEditors: liuzhenlin
  * @LastEditTime: 2023-01-07 16:11:45

+ 37 - 217
src/views/contract/detail.vue

@@ -1,8 +1,8 @@
 <!--
- * @Author: liuzl liuzl0802
+ * @Author: liuzl 461480418@qq.com
  * @Date: 2023-01-05 16:29:01
  * @LastEditors: liuzhenlin
- * @LastEditTime: 2023-01-09 14:43:21
+ * @LastEditTime: 2023-01-09 18:22:10
  * @Description: file content
  * @FilePath: \订单全流程管理系统\src\views\contract\detail.vue
 -->
@@ -22,20 +22,20 @@
               {{ details.custName }}
             </el-descriptions-item>
             <el-descriptions-item content-class-name="my-content" label="合同金额(元)" label-class-name="my-label">
-              {{ details.contractAmount }}
+              {{ formatPrice(details.contractAmount) }}
             </el-descriptions-item>
             <el-descriptions-item content-class-name="my-content" label="下单时间" label-class-name="my-label">
               {{ details.createdTime }}
             </el-descriptions-item>
             <el-descriptions-item content-class-name="my-content" label="回款金额(元)" label-class-name="my-label">
-              {{ details.collectedAmount }}
+              {{ formatPrice(details.collectedAmount) }}
             </el-descriptions-item>
             <el-descriptions-item content-class-name="my-content" label="负责人" label-class-name="my-label">
               {{ details.inchargeName }}
             </el-descriptions-item>
           </el-descriptions>
         </header>
-        <el-tabs v-model="activeName" @tab-click="handleClick">
+        <el-tabs v-model="activeName">
           <el-tab-pane label="详细信息" name="details">
             <details-info :details="details" />
           </el-tab-pane>
@@ -45,24 +45,35 @@
           <el-tab-pane label="回款" name="collection">
             <details-collection v-if="activeName == 'collection'" :details="details" />
           </el-tab-pane>
-          <el-tab-pane label="发票" name="invoice">发票</el-tab-pane>
-          <el-tab-pane label="附件" name="enclosure">附件</el-tab-pane>
+          <el-tab-pane label="发票" name="invoice">
+            <details-invoice v-if="activeName == 'invoice'" :details="details" />
+          </el-tab-pane>
+          <el-tab-pane label="附件" name="enclosure">
+            <details-enclosure v-if="activeName == 'enclosure'" :details="details" />
+          </el-tab-pane>
         </el-tabs>
       </el-col>
+      <el-col :span="8">
+        <details-records :dynamics-list="dynamicsList" />
+      </el-col>
     </el-row>
   </div>
 </template>
 
 <script>
+  import to from 'await-to-js'
   import { mapGetters } from 'vuex'
   import contractApi from '@/api/contract'
   import DetailsInfo from './components/DetailsInfo'
   import DetailsProduct from './components/DetailsProduct'
   import DetailsCollection from './components/DetailsCollection'
+  import DetailsRecords from './components/DetailsRecords'
+  import DetailsInvoice from './components/DetailsInvoice'
+  import DetailsEnclosure from './components/DetailsEnclosure'
 
   export default {
     name: 'ContractDetail',
-    components: { DetailsInfo, DetailsProduct, DetailsCollection },
+    components: { DetailsInfo, DetailsProduct, DetailsCollection, DetailsRecords, DetailsInvoice, DetailsEnclosure },
     data() {
       return {
         id: '',
@@ -70,6 +81,7 @@
         product: [],
         abstract: {},
         activeName: 'details',
+        dynamicsList: [],
       }
     },
     computed: {
@@ -81,7 +93,7 @@
     mounted() {
       this.id = this.$route.query.id
       this.init()
-      this.handleClick({ name: 'details' })
+      this.getRecord()
     },
     methods: {
       init() {
@@ -93,7 +105,21 @@
           }
         })
       },
-      async handleClick() {},
+      async getRecord() {
+        const [err, res] = await to(contractApi.getDynamicsList({ contractId: parseInt(this.id) }))
+        if (err) return
+        if (res.data.list) {
+          let obj = res.data.list
+          const keys = Object.keys(obj).reverse()
+          let records = {}
+          for (const item of keys) {
+            records[item] = obj[item]
+          }
+
+          this.dynamicsList = records
+          console.log(this.dynamicsList)
+        }
+      },
       back() {
         this.$router.go(-1)
       },
@@ -104,7 +130,7 @@
 <style lang="scss" scoped>
   $base: '.details';
   #{$base} {
-    height: calc(100vh - 60px - 50px - 12px * 2 - 40px);
+    height: calc(100vh - 60px - 12px * 2 - 40px);
     display: flex;
     padding: 20px 40px;
 
@@ -182,212 +208,6 @@
       padding-top: 28px;
       text-align: right;
     }
-
-    .records {
-      margin: 0;
-      padding: 10px 20px;
-      list-style: none;
-      height: calc(100% - 60px);
-      overflow-y: auto;
-
-      > li {
-        display: flex;
-
-        & + li {
-          margin-top: 10px;
-        }
-      }
-
-      .date {
-        width: 100px;
-        display: flex;
-        flex-direction: column;
-        align-items: center;
-
-        h2,
-        h3 {
-          margin: 0;
-        }
-
-        h2 {
-          font-size: 26px;
-          line-height: 32px;
-        }
-      }
-
-      .content {
-        flex: 1;
-        list-style: none;
-
-        li {
-          display: flex;
-
-          & + li {
-            margin-top: 10px;
-          }
-        }
-
-        .user-avatar {
-          font-size: 40px;
-        }
-
-        .text {
-          flex: 1;
-          padding-left: 20px;
-
-          p {
-            font-weight: 500;
-            margin: 0;
-            line-height: 20px;
-
-            span {
-              color: #1d66dc;
-            }
-          }
-
-          p:nth-child(2) {
-            margin-bottom: 10px;
-          }
-
-          .action {
-            font-weight: bold;
-            color: #333;
-          }
-        }
-      }
-    }
-
-    .follow {
-      height: 100%;
-      padding: 10px 20px;
-      overflow: auto;
-
-      > li {
-        display: flex;
-
-        + li {
-          margin-top: 10px;
-        }
-      }
-
-      .date {
-        width: 100px;
-        display: flex;
-        flex-direction: column;
-        align-items: center;
-
-        h2,
-        h3 {
-          margin: 0;
-        }
-
-        h2 {
-          font-size: 26px;
-          line-height: 32px;
-        }
-      }
-
-      .content {
-        flex: 1;
-        list-style: none;
-
-        > li {
-          border: 1px solid rgb(215, 232, 244);
-          background: rgb(247, 251, 254);
-          border-radius: 4px;
-          padding: 8px;
-          overflow: hidden;
-
-          .text-container {
-            display: flex;
-          }
-
-          .comments {
-            padding-left: 60px;
-            margin-top: 10px;
-            max-height: 190px;
-            overflow: auto;
-
-            li {
-              display: flex;
-              border-top: 1px solid #e3e5e7;
-
-              .text {
-                flex: 1;
-                padding: 0 10px;
-
-                p {
-                  font-weight: 500;
-                  margin: 0;
-                  line-height: 32px;
-                }
-
-                p:first-child {
-                  line-height: 30px;
-                  font-weight: bold;
-                }
-
-                p:last-child {
-                  font-size: 12px;
-                  color: #9499a0;
-                  text-align: right;
-                }
-              }
-            }
-          }
-
-          + li {
-            margin-top: 10px;
-          }
-        }
-
-        .user-avatar {
-          font-size: 40px;
-        }
-
-        .text {
-          flex: 1;
-          padding-left: 20px;
-          padding-right: 10px;
-
-          p {
-            font-weight: 500;
-            margin: 0;
-            line-height: 32px;
-
-            span {
-              color: #1d66dc;
-            }
-          }
-
-          .action {
-            display: flex;
-            justify-content: space-between;
-
-            span:first-child {
-              font-weight: bold;
-              color: #333;
-            }
-          }
-
-          .footer {
-            display: flex;
-            justify-content: space-between;
-            align-items: center;
-          }
-        }
-      }
-    }
-
-    .no-follow {
-      height: 100%;
-      width: 100%;
-      display: flex;
-      align-items: center;
-      justify-content: center;
-      font-size: 12px;
-      color: rgba(0, 0, 0, 0.65);
-    }
   }
 
   .height-enter-active,

+ 12 - 3
src/views/contract/manage.vue

@@ -6,7 +6,7 @@
  * @FilePath: \订单全流程管理系统\src\views\contract\manage.vue
 -->
 <template>
-  <div class="open-sea-container">
+  <div class="contract-manage">
     <vab-query-form>
       <vab-query-form-top-panel>
         <el-form :inline="true" label-width="0px" :model="queryForm" @submit.native.prevent>
@@ -52,7 +52,7 @@
       v-loading="listLoading"
       border
       :data="list"
-      height="calc(100vh - 340px)"
+      height="calc(100vh - 290px)"
       @selection-change="setSelectRows">
       <el-table-column align="center" show-overflow-tooltip type="selection" />
       <el-table-column
@@ -68,6 +68,9 @@
           <el-button v-if="item.prop === 'custName'" class="link-button" type="text" @click="handleCustDetail(row)">
             {{ row.custName }}
           </el-button>
+          <span v-else-if="item.prop === 'contractAmount'" class="link-button" type="text">
+            {{ formatPrice(row.contractAmount) }}
+          </span>
           <el-button
             v-else-if="item.prop === 'contractName'"
             style="font-size: 14px"
@@ -334,5 +337,11 @@
 </script>
 
 <style lang="scss" scoped>
-  $base: '.open-sea';
+  $base: '.contract-manage';
+  #{$base} {
+    height: calc(100vh - 60px - 12px * 2 - 40px);
+    padding: 12px;
+    background: #fff;
+    transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1), border 0s, color 0.1s, font-size 0s;
+  }
 </style>