Browse Source

Merge branch 'kd-dev' of https://gitee.com/zhoulisky/kd-web into kd-dev

朱丽平 10 months ago
parent
commit
0687279382
47 changed files with 8257 additions and 10688 deletions
  1. 6190 10253
      package-lock.json
  2. 1 0
      package.json
  3. 21 0
      src/api/projectManage/accept.js
  4. 1 10
      src/api/projectManage/change.js
  5. 4 2
      src/api/projectManage/designCost.js
  6. 21 0
      src/api/projectManage/implement.js
  7. 4 2
      src/api/projectManage/otherCost.js
  8. 4 3
      src/api/projectManage/outsourcingCost.js
  9. 4 2
      src/api/projectManage/personCost.js
  10. 42 0
      src/api/projectManage/projectList.js
  11. 4 2
      src/api/projectManage/wxzctxCost.js
  12. 4 2
      src/api/projectManage/zbCost.js
  13. 4 2
      src/api/projectManage/zjfyycqdtfyCost.js
  14. 4 2
      src/api/projectManage/zztlCost.js
  15. 79 0
      src/components/project-select/index.vue
  16. 19 19
      src/mixins/crud.js
  17. 2 2
      src/option/basicResource/kyAssetList.js
  18. 3 12
      src/option/projectManage/change.js
  19. 2 0
      src/option/projectManage/designCost.js
  20. 3 1
      src/option/projectManage/otherCost.js
  21. 4 1
      src/option/projectManage/outsourcingCost.js
  22. 44 15
      src/option/projectManage/personCost.js
  23. 7 2
      src/option/projectManage/projectList.js
  24. 10 12
      src/option/projectManage/wxzctxCost.js
  25. 2 0
      src/option/projectManage/zbCost.js
  26. 14 13
      src/option/projectManage/zjfyycqdtfyCost.js
  27. 24 16
      src/option/projectManage/zztlCost.js
  28. 1 1
      src/views/basic-resource/comp-basic-info/ky-asset-list.vue
  29. 59 4
      src/views/project-manage/change.vue
  30. 95 63
      src/views/project-manage/components/accept-form.vue
  31. 244 0
      src/views/project-manage/components/all-budget-table.vue
  32. 133 37
      src/views/project-manage/components/apply-form.vue
  33. 90 54
      src/views/project-manage/components/change-form.vue
  34. 54 5
      src/views/project-manage/components/design-cost.vue
  35. 99 65
      src/views/project-manage/components/implement-form.vue
  36. 55 6
      src/views/project-manage/components/other-cost.vue
  37. 56 4
      src/views/project-manage/components/outsourcing-cost.vue
  38. 372 0
      src/views/project-manage/components/outsourcing-doc.vue
  39. 77 4
      src/views/project-manage/components/person-cost.vue
  40. 24 17
      src/views/project-manage/components/project-budget.vue
  41. 106 15
      src/views/project-manage/components/wxzctx-cost.vue
  42. 55 4
      src/views/project-manage/components/zb-cost.vue
  43. 107 15
      src/views/project-manage/components/zjfyycqdtfy-cost.vue
  44. 65 4
      src/views/project-manage/components/zztl-cost.vue
  45. 8 2
      src/views/project-manage/ky-budget.vue
  46. 7 2
      src/views/project-manage/outsourcing.vue
  47. 29 13
      src/views/project-manage/project-list.vue

File diff suppressed because it is too large
+ 6190 - 10253
package-lock.json


+ 1 - 0
package.json

@@ -11,6 +11,7 @@
     "test:e2e": "vue-cli-service test:e2e"
   },
   "dependencies": {
+    "@chnlib/chinese-holiday": "^1.2.0",
     "@swjs/chinese-holidays": "^1.1.0",
     "avue-plugin-ueditor": "^0.1.4",
     "axios": "^0.21.1",

+ 21 - 0
src/api/projectManage/accept.js

@@ -0,0 +1,21 @@
+import request from '@/router/axios';
+
+// 获取阶段性详情
+export const getDetail = (params) => {
+  return request({
+    url: '/api/kd-scientific/xm/jtb/detail',
+    method: 'get',
+    params: {
+      ...params,
+    }
+  })
+}
+
+// 保存项目阶段性报告
+export const save = (row) => {
+  return request({
+    url: '/api/kd-scientific/xm/jtb/submit',
+    method: 'post',
+    data: row
+  })
+}

+ 1 - 10
src/api/projectManage/change.js

@@ -12,19 +12,10 @@ export const getList = (current, size, params) => {
   })
 }
 
-export const add = (row) => {
+export const save = (row) => {
   return request({
     url: '/api/kd-scientific/xm-bgrz/save',
     method: 'post',
     data: row
   })
 }
-
-
-export const update = (row) => {
-  return request({
-    url: '/api/kd-scientific/xm-bgrz/update',
-    method: 'post',
-    data: row
-  })
-}

+ 4 - 2
src/api/projectManage/designCost.js

@@ -30,10 +30,12 @@ export const update = (row) => {
 }
 
 
-export const remove = (data) => {
+export const remove = (ids) => {
   return request({
     url: '/api/kd-scientific/ys-sjfy/remove',
     method: 'post',
-    data
+    params: {
+      ids
+    }
   })
 }

+ 21 - 0
src/api/projectManage/implement.js

@@ -0,0 +1,21 @@
+import request from '@/router/axios';
+
+// 获取阶段性详情
+export const getDetail = (params) => {
+  return request({
+    url: '/api/kd-scientific/xm/jdxbg/detail',
+    method: 'get',
+    params: {
+      ...params,
+    }
+  })
+}
+
+// 保存项目阶段性报告
+export const save = (row) => {
+  return request({
+    url: '/api/kd-scientific/xm/jdxbg/submit',
+    method: 'post',
+    data: row
+  })
+}

+ 4 - 2
src/api/projectManage/otherCost.js

@@ -30,10 +30,12 @@ export const update = (row) => {
 }
 
 
-export const remove = (data) => {
+export const remove = (ids) => {
   return request({
     url: '/api/kd-scientific/ys-qtfy/remove',
     method: 'post',
-    data
+    params: {
+      ids,
+    }
   })
 }

+ 4 - 3
src/api/projectManage/outsourcingCost.js

@@ -29,11 +29,12 @@ export const update = (row) => {
   })
 }
 
-
-export const remove = (data) => {
+export const remove = (ids) => {
   return request({
     url: '/api/kd-scientific/ys-wtwbyjkffy/remove',
     method: 'post',
-    data
+    params: {
+      ids,
+    }
   })
 }

+ 4 - 2
src/api/projectManage/personCost.js

@@ -30,10 +30,12 @@ export const update = (row) => {
 }
 
 
-export const remove = (data) => {
+export const remove = (ids) => {
   return request({
     url: '/api/kd-scientific/ys-ryrgfy/remove',
     method: 'post',
-    data
+    params: {
+      ids,
+    }
   })
 }

+ 42 - 0
src/api/projectManage/projectList.js

@@ -2,6 +2,18 @@ import request from '@/router/axios';
 
 export const getList = (current, size, params) => {
   return request({
+    url: '/api/kd-scientific/xm/summary',
+    method: 'get',
+    params: {
+      ...params,
+      current,
+      size,
+    }
+  })
+}
+
+export const getAllProjectList = (current, size, params) => {
+  return request({
     url: '/api/kd-scientific/xm/list',
     method: 'get',
     params: {
@@ -12,6 +24,16 @@ export const getList = (current, size, params) => {
   })
 }
 
+export const getDetail = (params) => {
+  return request({
+    url: '/api/kd-scientific/xm/detail',
+    method: 'get',
+    params: {
+      ...params,
+    }
+  })
+}
+
 export const add = (row) => {
   return request({
     url: '/api/kd-scientific/xm/save',
@@ -28,3 +50,23 @@ export const update = (row) => {
     data: row
   })
 }
+
+// 获取项目预算总表
+export const getAllBudget = (params) => {
+  return request({
+    url: '/api/kd-scientific/xm/yszb',
+    method: 'get',
+    params: {
+      ...params,
+    }
+  })
+}
+
+// 保存项目阶段性报告
+export const saveJdxbg = (row) => {
+  return request({
+    url: '/api/kd-scientific/xmJdxbg/save',
+    method: 'post',
+    data: row
+  })
+}

+ 4 - 2
src/api/projectManage/wxzctxCost.js

@@ -30,10 +30,12 @@ export const update = (row) => {
 }
 
 
-export const remove = (data) => {
+export const remove = (ids) => {
   return request({
     url: '/api/kd-scientific/ys-wxzctxfy/remove',
     method: 'post',
-    data
+    params: {
+      ids
+    }
   })
 }

+ 4 - 2
src/api/projectManage/zbCost.js

@@ -30,10 +30,12 @@ export const update = (row) => {
 }
 
 
-export const remove = (data) => {
+export const remove = (ids) => {
   return request({
     url: '/api/kd-scientific/ys-zbtsysyfy/remove',
     method: 'post',
-    data
+    params: {
+      ids
+    }
   })
 }

+ 4 - 2
src/api/projectManage/zjfyycqdtfyCost.js

@@ -30,10 +30,12 @@ export const update = (row) => {
 }
 
 
-export const remove = (data) => {
+export const remove = (ids) => {
   return request({
     url: '/api/kd-scientific/ys-zjfyycqdtfy/remove',
     method: 'post',
-    data
+    params: {
+      ids
+    }
   })
 }

+ 4 - 2
src/api/projectManage/zztlCost.js

@@ -30,10 +30,12 @@ export const update = (row) => {
 }
 
 
-export const remove = (data) => {
+export const remove = (ids) => {
   return request({
     url: '/api/kd-scientific/ys-zjtrfy/remove',
     method: 'post',
-    data
+    params: {
+      ids
+    }
   })
 }

+ 79 - 0
src/components/project-select/index.vue

@@ -0,0 +1,79 @@
+<template>
+  <el-select
+    v-model="xmId"
+    filterable
+    placeholder="请选择"
+    :loading="loading"
+    :disabled="disabled"
+    style="width: 100%;"
+    @change="handleProjectChange"
+  >
+    <el-option
+      v-for="item in projectList"
+      :key="item.id"
+      :label="item.xmmc"
+      :value="item.id">
+    </el-option>
+  </el-select>
+</template>
+
+<script>
+import { getAllProjectList, getDetail } from "@/api/projectManage/projectList";
+
+export default {
+  name: 'ProjectSelect',
+  props: {
+    value: [String, Number],
+    params: Object,
+    disabled: {
+      type: Boolean,
+      default: false
+    }
+  },
+  data() {
+    return {
+      xmId: '',
+      loading: false,
+      projectList: []
+    }
+  },
+  mounted() {
+    this.getProjectList();
+  },
+  methods: {
+    findProjectObj(id, callback) {
+      if (!id) {
+        return;
+      }
+      getDetail({ id, ...this.params }).then(({ data }) => {
+        let detailData = {};
+        if (data.success) {
+          detailData = {
+            ...data.data,
+            xmfzrxm: data.data.technicianEntity ? data.data.technicianEntity.name : ''
+          };
+        }
+        callback && callback(detailData);
+      })
+    },
+    getProjectList() {
+      getAllProjectList(1, 99999).then(({ data }) => {
+        if (data.success) {
+          this.projectList = data.data.records;
+          this.xmId = this.value;
+
+          this.findProjectObj(this.value, proData => {
+            this.$emit('change', proData);
+          });
+        }
+      })
+    },
+    handleProjectChange(val) {
+      this.findProjectObj(val, proData => {
+        this.$emit('input', val);
+        this.$emit('change', proData);
+      });
+    },
+  }
+}
+</script>

+ 19 - 19
src/mixins/crud.js

@@ -53,27 +53,27 @@ export default (app, option = {}) => {
     },
     methods: {
       getList() {
-        const callback = () => {
-          this.loading = true;
-          this.api[option.list || 'getList'](this.page.currentPage, this.page.pageSize, this.params).then(res => {
-            let data;
-            if (option.res) {
-              data = option.res(res.data);
-            } else {
-              data = res.data.data;
-            }
-            this.page.total = data[option.total || 'total'] || 0;
-            this.data = data[option.records || 'records'];
-            if (this.listAfter) {
-              this.listAfter(data);
-            }
-            this.loading = false;
-          })
-        }
+        this.loadData();
+      },
+      loadData() {
+        this.loading = true;
+        this.api[option.list || 'getList'](this.page.currentPage, this.page.pageSize, this.params).then(res => {
+          let data;
+          if (option.res) {
+            data = option.res(res.data);
+          } else {
+            data = res.data.data;
+          }
+          this.page.total = data[option.total || 'total'] || 0;
+          this.data = data[option.records || 'records'];
+          if (this.listAfter) {
+            this.listAfter(data);
+          }
+          this.loading = false;
+        })
         if (this.listBefore) {
           this.listBefore();
         }
-        callback();
       },
       getFormData() {
         return this.form;
@@ -175,7 +175,7 @@ export default (app, option = {}) => {
         if (done) done();
         if (this.validatenull(params)) {
           Object.keys(this.params).forEach(ele => {
-            if (!['createTime_dategt', 'createTime_datelt', 'yearAndMonth'].includes(ele)) {
+            if (!['createTime_dategt', 'createTime_datelt', 'yearAndMonth', 'xmId'].includes(ele)) {
               delete this.params[ele];
             }
           })

+ 2 - 2
src/option/basicResource/kyAssetList.js

@@ -52,7 +52,7 @@ export default {
       label: '资产类别',
       prop: 'zclb',
       type: 'select',
-      dicUrl: '/api/kd-system/dict/dictionary?code=zclb',
+      dicUrl: '/api/kd-system/dict-biz/dictionary?code=zclb',
       props: {
         label: 'dictValue',
         value: 'dictKey',
@@ -83,7 +83,7 @@ export default {
       label: '用途',
       prop: 'yt',
       type: 'select',
-      dicUrl: '/api/kd-system/dict/dictionary?code=zcyt',
+      dicUrl: '/api/kd-system/dict-biz/dictionary?code=zcyt',
       props: {
         label: 'dictValue',
         value: 'dictKey',

+ 3 - 12
src/option/projectManage/change.js

@@ -18,19 +18,17 @@ export default {
   column: [
     {
       label: '研发项目名称',
-      prop: 'yfxmmc',
+      prop: 'xmmc',
       type: 'input',
-      search: true,
       minWidth: 240,
       showOverflowTooltip: true,
     },
     {
       label: '研发项目编号',
-      prop: 'yfzcbh',
+      prop: 'xmbh',
       type: 'input',
       minWidth: 160,
       align: 'center',
-      search: true,
       showOverflowTooltip: true,
     },
     {
@@ -39,7 +37,6 @@ export default {
       type: 'select',
       minWidth: 140,
       align: 'center',
-      search: true,
       showOverflowTooltip: true,
     },
     {
@@ -53,7 +50,6 @@ export default {
         label: 'dictValue',
         value: 'dictKey',
       },
-      search: true,
       showOverflowTooltip: true,
     },
     {
@@ -72,13 +68,8 @@ export default {
     },
     {
       label: '变更生效时间',
-      prop: 'bzsxssj',
+      prop: 'bgsxsj',
       width: 160,
-      search: true,
-      props: {
-        label: 'dictValue',
-        value: 'dictKey',
-      },
       align: 'center',
       showOverflowTooltip: true,
     },

+ 2 - 0
src/option/projectManage/designCost.js

@@ -36,6 +36,8 @@ export default {
       width: 90,
       span: 24,
       align: 'center',
+      min: 0,
+      precision: 2,
       showOverflowTooltip: true,
       rules: [{
         required: true,

+ 3 - 1
src/option/projectManage/otherCost.js

@@ -18,7 +18,7 @@ export default {
   column: [
     {
       label: '费用内容',
-      prop: 'fyje',
+      prop: 'fynr',
       type: 'input',
       minWidth: 300,
       span: 24,
@@ -37,6 +37,8 @@ export default {
       span: 24,
       align: 'center',
       showOverflowTooltip: true,
+      min: 0,
+      precision: 2,
       rules: [{
         required: true,
         message: '请输入预算金额',

+ 4 - 1
src/option/projectManage/outsourcingCost.js

@@ -9,7 +9,7 @@ export default {
   viewBtn: true,
   selection: true,
   searchLabelWidth: 90,
-  labelWidth: 90,
+  labelWidth: 120,
   menuWidth: 220,
   dialogClickModal: false,
   dialogWidth: 500,
@@ -48,6 +48,9 @@ export default {
       type: 'number',
       width: 90,
       span: 24,
+      align: 'center',
+      min: 0,
+      precision: 2,
       showOverflowTooltip: true,
       rules: [{
         required: true,

+ 44 - 15
src/option/projectManage/personCost.js

@@ -12,40 +12,56 @@ export default {
   labelWidth: 140,
   menuWidth: 220,
   dialogClickModal: false,
-  dialogWidth: 760,
+  dialogWidth: 500,
   dialogType: "drawer",
   height: '600',
   column: [
     {
       label: '姓名',
-      prop: 'name',
+      prop: 'technicianId',
       type: 'select',
-      span: 12,
+      span: 24,
       width: 100,
       align: 'center',
       showOverflowTooltip: true,
+      dicUrl: '',
+      dicFormatter:(res)=>{
+        return res.data.records
+      },
+      dicQuery: {
+        current: 1,
+        size: 99999,
+        yearAndMonth: ''
+      },
+      props: {
+        label: 'name',
+        value: 'id',
+      },
+      dicFlag: true,
       rules: [{
         required: true,
         message: '请选择姓名',
         trigger: 'change',
-      }]
+      }],
     },
     {
       label: '工号',
       prop: 'number',
       type: 'input',
-      span: 12,
+      span: 24,
       width: 160,
       align: 'center',
+      display: false,
       showOverflowTooltip: true,
     },
     {
       label: '身份证号',
       prop: 'identityCard',
       type: 'input',
-      span: 12,
+      span: 24,
       width: 160,
       align: 'center',
+      display: false,
       showOverflowTooltip: true,
     },
     {
@@ -53,39 +69,52 @@ export default {
       prop: 'zzsc',
       type: 'number',
       min: 0,
-      span: 12,
-      width: 90,
+      precision: 0,
+      span: 24,
+      minWidth: 90,
       align: 'center',
       showOverflowTooltip: true,
+      rules: [{
+        required: true,
+        message: '请输入',
+        trigger: 'blur',
+      }]
     },
     {
       label: '月平均人工费用/元',
       prop: 'pjrgfy',
       type: 'number',
       min: 0,
-      span: 12,
-      width: 90,
+      precision: 2,
+      span: 24,
+      minWidth: 90,
       align: 'center',
       showOverflowTooltip: true,
+      rules: [{
+        required: true,
+        message: '请输入',
+        trigger: 'blur',
+      }]
     },
     {
       label: '预算合计/元',
       prop: 'total',
       type: 'number',
       min: 0,
-      span: 12,
-      width: 80,
+      span: 24,
+      minWidth: 80,
       align: 'center',
+      display: false,
       showOverflowTooltip: true,
     },
     {
       label: '是否为外聘科技人员',
       prop: 'isWp',
-      type: 'number',
       min: 0,
-      span: 12,
-      width: 90,
+      span: 24,
+      minWidth: 90,
       align: 'center',
+      display: false,
       showOverflowTooltip: true,
     },
   ],

+ 7 - 2
src/option/projectManage/projectList.js

@@ -51,7 +51,7 @@ export default {
     },
     {
       label: '项目负责人',
-      prop: 'xmfzr',
+      prop: 'xmfzrxm',
       type: 'input',
       width: 100,
       align: 'center',
@@ -69,12 +69,17 @@ export default {
     },
     {
       label: '项目状态',
-      prop: 'xmzt',
+      prop: 'status',
       type: 'select',
       width: 90,
       align: 'center',
       search: true,
       showOverflowTooltip: true,
+      dicUrl: '/api/kd-system/dict-biz/dictionary?code=project_state',
+      props: {
+        label: 'dictValue',
+        value: 'dictKey',
+      },
     },
     {
       label: '项目报告进度',

+ 10 - 12
src/option/projectManage/wxzctxCost.js

@@ -18,23 +18,19 @@ export default {
   column: [
     {
       label: '资产名称',
-      prop: 'zcmc',
+      prop: 'zcbm',
       type: 'select',
       minWidth: 220,
       span: 24,
-      dicUrl: '',
+      dicUrl: '/api/kd-scientific/zc/simple/list',
       dicFormatter:(res)=>{
-        return res.data.records
-      },
-      dicQuery: {
-        current: 1,
-        size: 99999,
-        yearAndMonth: ''
+        return res.data
       },
       props: {
         label: 'zcmc',
-        value: 'id',
+        value: 'zcbm',
       },
+      dicFlag: true,
       showOverflowTooltip: true,
       rules: [{
         required: true,
@@ -50,10 +46,12 @@ export default {
       span: 24,
       align: 'center',
       showOverflowTooltip: true,
+      min: 0,
+      precision: 0,
       rules: [{
         required: true,
         message: '请输入工作时长',
-        trigger: 'change',
+        trigger: 'blur',
       }]
     },
     {
@@ -64,11 +62,11 @@ export default {
       span: 24,
       align: 'center',
       showOverflowTooltip: true,
-      disabled: true,
+      display: false
     },
     {
       label: '预算合计/元',
-      prop: 'hjfy',
+      prop: 'yshj',
       type: 'number',
       width: 90,
       span: 24,

+ 2 - 0
src/option/projectManage/zbCost.js

@@ -36,6 +36,8 @@ export default {
       width: 90,
       span: 24,
       align: 'center',
+      min: 0,
+      precision: 2,
       showOverflowTooltip: true,
       rules: [{
         required: true,

+ 14 - 13
src/option/projectManage/zjfyycqdtfyCost.js

@@ -18,23 +18,20 @@ export default {
   column: [
     {
       label: '资产名称',
-      prop: 'zcmc',
+      prop: 'zcbm',
       type: 'select',
+      filterable: true,
       minWidth: 140,
       span: 24,
-      dicUrl: '',
+      dicUrl: '/api/kd-scientific/zc/simple/list',
       dicFormatter:(res)=>{
-        return res.data.records
-      },
-      dicQuery: {
-        current: 1,
-        size: 99999,
-        yearAndMonth: ''
+        return res.data
       },
       props: {
         label: 'zcmc',
-        value: 'id',
+        value: 'zcbm',
       },
+      dicFlag: true,
       showOverflowTooltip: true,
       rules: [{
         required: true,
@@ -49,26 +46,28 @@ export default {
       width: 140,
       span: 24,
       align: 'center',
+      min: 0,
+      precision: 0,
       showOverflowTooltip: true,
       rules: [{
         required: true,
         message: '请输入工作时长',
-        trigger: 'change',
+        trigger: 'blur',
       }]
     },
     {
       label: '月折旧额',
-      prop: 'ytxe',
+      prop: 'yzje',
       type: 'number',
       width: 90,
       span: 24,
       align: 'center',
       showOverflowTooltip: true,
-      disabled: true,
+      display: false,
     },
     {
       label: '预算合计/元',
-      prop: 'hjfy',
+      prop: 'yshj',
       type: 'number',
       width: 90,
       span: 24,
@@ -96,6 +95,8 @@ export default {
       width: 120,
       span: 24,
       align: 'center',
+      min: 0,
+      precision: 2,
       showOverflowTooltip: true,
       rules: [{
         required: true,

+ 24 - 16
src/option/projectManage/zztlCost.js

@@ -9,10 +9,10 @@ export default {
   viewBtn: true,
   selection: true,
   searchLabelWidth: 140,
-  labelWidth: 140,
+  labelWidth: 180,
   menuWidth: 220,
   dialogClickModal: false,
-  dialogWidth: 760,
+  dialogWidth: 500,
   dialogType: "drawer",
   height: '600',
   column: [
@@ -21,6 +21,7 @@ export default {
       prop: 'wzmc',
       type: 'input',
       width: 100,
+      span: 24,
       showOverflowTooltip: true,
       rules: [{
         required: true,
@@ -30,38 +31,44 @@ export default {
     },
     {
       label: '用量',
-      prop: 'yl',
+      prop: 'yongLiang',
       type: 'number',
+      min: 0,
+      precision: 2,
       width: 90,
+      span: 24,
       align: 'center',
       showOverflowTooltip: true,
     },
     {
       label: '单价',
-      prop: 'dj',
+      prop: 'danJia',
       type: 'number',
       min: 0,
+      precision: 2,
       width: 100,
+      span: 24,
       align: 'center',
       showOverflowTooltip: true,
     },
     {
       label: '预算金额',
-      prop: 'zzsc',
+      prop: 'wzysje',
       type: 'number',
       min: 0,
-      span: 12,
+      precision: 2,
       width: 90,
+      span: 24,
       align: 'center',
       showOverflowTooltip: true,
+      display: false,
     },
     {
       label: '2-仪器设备名称',
       prop: 'yqsbmc',
       type: 'input',
-      min: 0,
-      span: 12,
-      width: 120,
+      minWidth: 120,
+      span: 24,
       showOverflowTooltip: true,
     },
     {
@@ -69,8 +76,9 @@ export default {
       prop: 'ysje',
       type: 'number',
       min: 0,
-      span: 12,
-      width: 120,
+      precision: 2,
+      minWidth: 140,
+      span: 24,
       align: 'center',
       showOverflowTooltip: true,
     },
@@ -78,9 +86,8 @@ export default {
       label: '3-固定资产名称(租赁)',
       prop: 'gdzcmc',
       type: 'input',
-      min: 0,
-      span: 12,
-      width: 120,
+      minWidth: 110,
+      span: 24,
       showOverflowTooltip: true,
     },
     {
@@ -88,8 +95,9 @@ export default {
       prop: 'zlfyys',
       type: 'number',
       min: 0,
-      span: 12,
-      width: 100,
+      minWidth: 100,
+      span: 24,
+      precision: 2,
       align: 'center',
       showOverflowTooltip: true,
     },

+ 1 - 1
src/views/basic-resource/comp-basic-info/ky-asset-list.vue

@@ -92,7 +92,7 @@
 </template>
 
 <script>
-import { getLastMonthData } from "@/api/basicResource/technicianRoster";
+import { getLastMonthData } from "@/api/basicResource/kyAssetList";
 import {exportBloByPost} from "@/api/common";
 import YearMonthSelect from "@/components/year-month-select";
 import UploadExcelDialog from "@/components/upload-excel-dialog";

+ 59 - 4
src/views/project-manage/change.vue

@@ -1,6 +1,18 @@
 <template>
   <basic-container>
+    <div style="margin-top: 6px;">
+      <el-form :inline="true">
+        <el-form-item label="研发项目名称">
+          <project-select v-model="params.xmId" @change="handleProjectChange"></project-select>
+        </el-form-item>
+        <el-form-item label="研发项目编号">
+          {{ selProject.xmbh }}
+        </el-form-item>
+      </el-form>
+    </div>
+
     <avue-crud
+      ref="crud"
       v-bind="bindVal"
       v-on="onEvent"
       v-model="form"
@@ -43,7 +55,14 @@
       size="960px"
     >
       
-      <change-form></change-form>
+      <change-form
+        v-if="drawerVisible"
+        :projectId="params.xmId"
+        :data="changeFormData"
+        :disabled="isFormReadonly"
+        @success="handleChangeSucc"
+      >
+      </change-form>
     </el-drawer>
   </basic-container>
 </template>
@@ -51,26 +70,51 @@
 <script>
 import {exportBloByPost} from "@/api/common";
 import {getToken} from "@/util/auth";
+import projectSelect from "@/components/project-select";
 import {downloadXls} from "@/util/util";
 import changeForm from "./components/change-form.vue";
 
 
 export default window.$crudCommon({
+  props: {
+    projectId: [String, Number]
+  },
   components: {
-    changeForm
+    changeForm,
+    projectSelect
   },
   data() {
     return {
+      params: {
+        xmId: ''
+      },
+      selProject: {},
       drawerVisible: false,
 
       wideTableColumns: [],
       printTitle: "",
+
+      changeFormData: {},
+      isFormReadonly: false,
     };
   },
+  watch: {
+    "params.xmId"() {
+      this.page.currentPage = 1;
+      this.getList(this.page);
+    }
+  },
+  created() {
+    this.params.xmId = this.projectId;
+  },
   methods: {
+    handleProjectChange(data) {
+      this.selProject = data;
+      
+    },
     handleExport() {
       exportBloByPost(`/api/kd-scientific/xm-bgrz/export?${this.website.tokenHeader}=${getToken()}`, this.params).then(res => {
-        downloadXls(res.data, `项目变更列表.xlsx`);
+        downloadXls(res.data, `${this.selProject.xmmc}项目变更列表.xlsx`);
       });
     },
     /**
@@ -79,13 +123,24 @@ export default window.$crudCommon({
      */
     printTable(isLandscape) {
       this.wideTableColumns = this.$refs.crud.columnOption;
-      this.printTitle = `项目变更列表`;
+      this.printTitle = `${this.selProject.xmmc}项目变更列表`;
       this.$nextTick(() => {
         this.$refs.printWideTable.printTable(isLandscape);
       })
     },
     handleAddChange() {
       this.drawerVisible = true;
+      this.isFormReadonly = false;
+      this.changeFormData = {};
+    },
+    handleRowDbClick(data) {
+      this.drawerVisible = true;
+      this.isFormReadonly = true;
+      this.changeFormData = data;
+    },
+    handleChangeSucc() {
+      this.drawerVisible = false;
+      this.getList();
     }
   },
 }, {

+ 95 - 63
src/views/project-manage/components/accept-form.vue

@@ -1,16 +1,16 @@
 <template>
-  <div class="doc-page">
+  <div class="doc-page" v-loading="loading">
     <h3 class="page-title" style="margin: 24px 0 16px;">科德集团</h3>
     <h3 class="page-title" style="margin: 24px 0 16px;">研发项目验收资料</h3>
 
     <div class="project-basic-info">
       <div class="info-row">{{ `研发项目名称:${ selProject.xmmc || '' }` }}</div>
-      <div class="info-row">{{ `项目负责人:${ selProject.xmfzr || '' }` }}</div>
+      <div class="info-row">{{ `项目负责人:${ selProject.xmfzrxm || '' }` }}</div>
       <div class="info-row">{{ `项目申请单位:${ selProject.xmsqdw || '' }` }}</div>
       <div class="info-row">{{ `项目执行期:${ getXmDateRange || '' }` }}</div>
       <div class="info-row">
         <span>填报时间:</span>
-        <span><el-date-picker v-model="formData.tbsj" type="month" value-format="yyyy-MM" /></span>
+        <span><el-date-picker v-model="formData.tbsj" value-format="yyyy-MM-dd" /></span>
       </div>
     </div>
 
@@ -19,32 +19,17 @@
         <tr>
           <td class="doc-label">研发项目名称</td>
           <td class="doc-input">
-            <el-select
-              v-model="formData.xmId"
-              filterable
-              remote
-              reserve-keyword
-              placeholder="请输入关键词"
-              :remote-method="remoteMethod"
-              :loading="loading"
-              style="width: 100%;"
-              :disabled="!formData.tbsj"
+            <project-select
+              v-model="currProjectId"
               @change="handleProjectChange"
-            >
-              <el-option
-                v-for="item in projectList"
-                :key="item.id"
-                :label="item.xmmc"
-                :value="item.id">
-              </el-option>
-            </el-select>
+            ></project-select>
           </td>
           <td class="doc-label">项目申请单位</td>
           <td class="doc-input">{{ selProject.xmsqdw }}</td>
         </tr>
         <tr>
           <td class="doc-label">项目负责人</td>
-          <td class="doc-input">{{ selProject.xmfzr }} </td>
+          <td class="doc-input">{{ selProject.xmfzrxm }} </td>
           <td class="doc-label">研究类型</td>
           <td class="doc-input">{{ selProject.yjlx }}</td>
         </tr>
@@ -74,8 +59,25 @@
     </table>
 
     <avue-form v-model="formData" :option="option" style="margin-top: 30px; padding: 0;">
-      <template slot="jdbgType" slot-scope="{file}">
-        <span>{{file.originalName}}</span>
+      <template slot="ysbgLabel">
+        <label>验收报告</label>
+        <el-link type="primary" style="position: absolute; left: 220px; z-index: 1;">下载模板</el-link>
+      </template>
+      <template slot="jsbgLabel">
+        <label>技术报告</label>
+        <el-link type="primary" style="position: absolute; left: 220px; z-index: 1;">下载模板</el-link>
+      </template>
+      <template slot="cgbgLabel">
+        <label>成果报告</label>
+        <el-link type="primary" style="position: absolute; left: 220px; z-index: 1;">下载模板</el-link>
+      </template>
+      <template slot="xybgLabel">
+        <label>效益报告</label>
+        <el-link type="primary" style="position: absolute; left: 220px; z-index: 1;">下载模板</el-link>
+      </template>
+      <template slot="yspwLabel">
+        <label>验收批文</label>
+        <el-link type="primary" style="position: absolute; left: 220px; z-index: 1;">下载模板</el-link>
       </template>
     </avue-form>
     <p class="tip">注:可一次上传多个相关文件(文档、表格、图片等)。 支持格式:DOC, PDF, Excel, PNG, JPG, PPT 等。 请确保文件内容清晰有效。</p>
@@ -87,27 +89,30 @@
 </template>
 
 <script>
-import { getDictionary } from "@/api/system/dictbiz";
-import { getList as getProjectList } from "@/api/projectManage/projectList";
-import { add } from "@/api/projectManage/change";
+import projectSelect from "@/components/project-select";
+import { save, getDetail } from "@/api/projectManage/accept";
 import moment from "moment";
 
 export default {
+  components: {
+    projectSelect
+  },
+  props: {
+    projectId: [String, Number]
+  },
   data() {
     return {
       formData: {},
 
-      changeTypeList: [],
-
       loading: false,
       projectList: [],
       selProject: {},
 
+      currProjectId: '',
+
+      loading: false
     };
   },
-  mounted() {
-    this.getDictList("xm_biangeng_field", "changeTypeList");
-  },
   computed: {
     getXmDateRange() {
       if (this.selProject.xmkssj && this.selProject.xmjssj) {
@@ -135,7 +140,7 @@ export default {
               res: "data",
             },
             action: '/api/kd-resource/oss/endpoint/put-file',
-            disabled: !this.formData.xmId
+            disabled: !this.currProjectId
           },
           {
             label: "技术报告",
@@ -150,7 +155,7 @@ export default {
               res: "data",
             },
             action: '/api/kd-resource/oss/endpoint/put-file',
-            disabled: !this.formData.xmId
+            disabled: !this.currProjectId
           },
           {
             label: "成果报告",
@@ -165,7 +170,7 @@ export default {
               res: "data",
             },
             action: '/api/kd-resource/oss/endpoint/put-file',
-            disabled: !this.formData.xmId
+            disabled: !this.currProjectId
           },
           {
             label: "效益报告",
@@ -180,7 +185,7 @@ export default {
               res: "data",
             },
             action: '/api/kd-resource/oss/endpoint/put-file',
-            disabled: !this.formData.xmId
+            disabled: !this.currProjectId
           },
           {
             label: "验收批文",
@@ -195,42 +200,58 @@ export default {
               name: "originalName",
               res: "data",
             },
-            disabled: !this.formData.xmId
+            disabled: !this.currProjectId
           },
         ],
       }
     }
   },
+  watch: {
+    currProjectId() {
+      this.getImplementDetail();
+    }
+  },
+  mounted() {
+    this.currProjectId = this.projectId || '';
+  },
   methods: {
-    getDictList(code, toListKey) {
-      getDictionary({ code }).then((res) => {
-        this[toListKey] = res.data.data.map((item) => {
-          return { label: item.dictValue, value: item.dictKey };
-        });
+    getImplementDetail() {
+      this.loading = true;
+      getDetail({ xmId: this.currProjectId, yearAndMonth: this.yearAndMonth }).then(({ data }) => {
+        this.loading = false;
+        if (data.code == 200 && data.data && Object.keys(data.data).length) {
+          this.formData = {
+            id: data.data.id,
+            xmId: data.data.xmId,
+            tbsj: data.data.tbsj,
+            ysbg: data.data.ysbg ? JSON.parse(data.data.ysbg) : [],
+            jsbg: data.data.jsbg ? JSON.parse(data.data.jsbg) : [],
+            cgbg: data.data.cgbg ? JSON.parse(data.data.cgbg) : [],
+            xybg: data.data.xybg ? JSON.parse(data.data.xybg) : [],
+            yspw: data.data.yspw ? JSON.parse(data.data.yspw) : [],
+          };
+        } else {
+          this.formData = {
+            tbsj: '',
+            ysbg: [],
+            jsbg: [],
+            cgbg: [],
+            xybg: [],
+            yspw: [],
+          };
+        }
+      }).catch(() => {
+        this.loading = false;
       });
     },
-    remoteMethod(query) {
-      if (query !== '') {
-        this.loading = true;
-        setTimeout(() => {
-          this.loading = false;
-          getProjectList(1, 99999, { xmmc: query }).then(({ data }) => {
-            if (data.success) {
-              this.projectList = data.data.records;
-            }
-          })
-        }, 200);
-      } else {
-        this.projectList = [];
-      }
-    },
-    handleProjectChange(val) {
-      let currPro = this.projectList.find(item => item.id === val);
-      this.selProject = currPro;
+    handleProjectChange(data) {
+      this.selProject = data;
     },
     validForm() {
       let errorText = '';
-      if (!this.formData.xmId) {
+      if (!this.formData.tbsj) {
+        errorText = '请选择填报时间';
+      } else if (!this.currProjectId) {
         errorText = '请选择填报的项目';
       }
 
@@ -243,10 +264,21 @@ export default {
         return;
       }
 
-      this.saveData(this.formData);
+      const params = { ...this.formData, xmId: this.currProjectId };
+      params.ysbg = JSON.stringify(params.ysbg);
+      params.jsbg = JSON.stringify(params.jsbg);
+      params.cgbg = JSON.stringify(params.cgbg);
+      params.xybg = JSON.stringify(params.xybg);
+      params.yspw = JSON.stringify(params.yspw);
+
+      this.saveData(params);
     },
     saveData(params) {
-      console.log(params)
+      save(params).then(({ data }) => {
+        if (data.code == 200) {
+          this.$message.success('保存成功!');
+        }
+      });
     }
   },
 };

+ 244 - 0
src/views/project-manage/components/all-budget-table.vue

@@ -0,0 +1,244 @@
+<template>
+  <div v-loading="loading">
+    <div class="container">
+      <div class="operate-btn" style="text-align: right; margin: 10px 16px;">
+        <el-button @click="handleRefresh">刷新</el-button>
+        <el-button type="primary">下载</el-button>
+        <el-button type="primary">打印</el-button>
+      </div>
+      <table class="doc-page">
+        <thead>
+          <th colspan="3">研发项目经费预算表</th>
+        </thead>
+        <tbody>
+          <tr>
+            <td class="doc-label">研发项目名称</td>
+            <td>
+              <project-select v-model="currProjectId" @change="handleProjectChange"></project-select>
+            </td>
+          </tr>
+          <tr>
+            <td class="doc-label">项目申请单位</td>
+            <td>{{ selProject.xmsqdw }}</td>
+          </tr>
+          <tr>
+            <td class="doc-label">项目起止时间</td>
+            <td>{{ getXmDateRange }}</td>
+          </tr>
+          <tr>
+            <td class="doc-label">研究费用预算明细</td>
+            <td style="padding: 0;">
+              <el-table
+                :data="tableData"
+                border
+                style="width: 100%"
+                show-summary
+                class="budget-table"
+                :summary-method="getSummaries"
+              >
+                <el-table-column
+                  prop="kmmc"
+                  label="科目名称"                  
+                >
+                </el-table-column>
+                <el-table-column
+                  prop="sales"
+                  label="科目金额"
+                  width="120"
+                  align="center"
+                >
+                </el-table-column>
+                <el-table-column
+                  prop="ratio"
+                  label="占总预算比例"
+                  align="center"
+                  width="120"
+                >
+                </el-table-column>
+              </el-table>
+            </td>
+          </tr>
+        </tbody>
+      </table>
+    </div>
+  </div>
+</template>
+
+<script>
+import moment from 'moment';
+import projectSelect from "@/components/project-select";
+import { getAllBudget } from "@/api/projectManage/projectList";
+import Decimal from "decimal.js";
+
+export default {
+  props: {
+    projectId: [String, Number]
+  },
+  components: {
+    projectSelect,
+  },
+  data() {
+    return {
+      currProjectId: "",
+      tableData: [{
+        kmmc: '一、人员人工费用',
+      }, {
+        kmmc: '二、直接投入费用'
+      }, {
+        kmmc: '三、折旧费用与长期待摊费用'
+      }, {
+        kmmc: '四、无形资产摊销费用'
+      }, {
+        kmmc: '五、设计费用'
+      }, {
+        kmmc: '六、装备调试费用与试验费用'
+      }, {
+        kmmc: '七、委托外部研究开发费'
+      }, {
+        kmmc: '八、其他费用'
+      }],
+
+      selProject: {},
+
+      loading: false,
+    };
+  },
+  computed: {
+     getXmDateRange() {
+      if (this.selProject.xmkssj && this.selProject.xmjssj) {
+        let xmkssj = moment(this.selProject.xmkssj).format('yyyy年MM月DD日');
+        let xmjssj = moment(this.selProject.xmjssj).format('yyyy年MM月DD日')
+        return `${xmkssj}至${xmjssj}`;
+      }
+      return `年 月 日至 年 月 日`;
+    },
+  },
+  watch: {
+    currProjectId(newVal) {
+      if (!!newVal) {
+        this.getAllBudgetData(newVal);
+      }
+    }
+  },
+  mounted() {
+    this.currProjectId = this.projectId || '';
+  },
+  methods: {
+    handleRefresh() {
+      this.getAllBudgetData(this.selProject.id);
+    },
+    handleProjectChange(data) {
+      this.selProject = data;
+    },
+    getAllBudgetData(id) {
+      this.loading = true;
+      getAllBudget({ xmId: id }).then(({ data }) => {
+        this.loading = false;
+        if (data.success) {
+          const { xmysze } = data.data;
+          let ysze = xmysze === -1 ? 1 : xmysze;
+          this.tableData = this.tableData.map((item, index) => {
+            let readKey = '';
+            if (index == 0) {
+              readKey = 'ryrgfy';
+            } else if (index == 1) {
+              readKey = 'zjtrfy';
+            } else if (index == 2) {
+              readKey = 'zjfyycqdtfy';
+            } else if (index == 3) {
+              readKey = 'wxzctxfy';
+            } else if (index == 4) {
+              readKey = 'sjfy';
+            } else if (index == 5) {
+              readKey = 'zbtsysyfy';
+            } else if (index == 6) {
+              readKey = 'wtwbyjkffy';
+            } else if (index == 7) {
+              readKey = 'qtfy';
+            }
+
+            item.sales = (data.data[readKey] === -1 ? 0 : data.data[readKey]).toFixed(2);
+            let ratio = 0;
+            if (item.sales) {
+              ratio = (new Decimal(item.sales).div(new Decimal(ysze))*100).toFixed(2);
+            }
+            item.ratio = ratio;
+
+            return item;
+          });
+        }
+      }).catch(err => {
+        this.loading = false;
+      });
+    },
+    getSummaries(param) {
+      const { columns, data } = param;
+      const sums = [];
+      columns.forEach((column, index) => {
+        if (index === 0) {
+          sums[index] = '合计';
+          return;
+        }
+        const values = data.map(item => Number(item[column.property]));
+        if (!values.every(value => isNaN(value))) {
+          sums[index] = values.reduce((prev, curr) => {
+            const value = Number(curr);
+            if (!isNaN(value)) {
+              return prev + curr;
+            } else {
+              return prev;
+            }
+          }, 0);
+          // 保留两位小数
+          sums[index] = sums[index].toFixed(2);
+        } else {
+          sums[index] = 'N/A';
+        }
+      });
+      return sums;
+    }
+  }
+};
+</script>
+
+<style lang="scss" scoped>
+.container {
+  width: 800px;
+  margin: 0 auto;
+}
+.doc-page {
+  width: 100%;
+  border: 1px solid #eee;
+  tr,
+  td {
+    border: 1px solid #eee;
+  }
+  td {
+    padding: 12px 8px;
+  }
+  thead th {
+    height: 50px;
+    line-height: 50px;
+    text-align: center;
+    font-weight: bold;
+    font-size: 16px;
+    background-color: rgba(228, 240, 254, 1);
+  }
+  tr td.doc-label {
+    width: 26%;
+    background-color: rgb(246, 246, 246);
+    font-weight: 600;
+    text-align: center;
+    font-size: 14px;
+  }
+}
+
+.budget-table {
+  ::v-deep .el-table__body .el-table__cell {
+    padding: 8px 2px;
+  }
+  ::v-deep .el-table__header .el-table__cell {
+    padding: 10px 2px;
+  }
+} 
+</style>

+ 133 - 37
src/views/project-manage/components/apply-form.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="apply-form">
+  <div class="apply-form" v-loading="loading">
     <h3 class="page-title">科德集团</h3>
 
     <h3 class="page-title" style="margin-bottom: 10px;">{{ getDocTile }}</h3>
@@ -18,32 +18,21 @@
           <td class="doc-input">
             <el-input v-model="formData.xmmc" placeholder="请输入项目名称" />
           </td>
-          <td class="doc-label">项目申请单位</td>
+          <td class="doc-label">项目编号</td>
           <td class="doc-input">
             <el-input
-              v-model="formData.xmsqdw"
-              placeholder="请选择项目申请单位"
+              v-model="formData.xmbh"
+              placeholder="请输入项目编号"
             />
           </td>
         </tr>
         <tr>
-          <td class="doc-label">项目负责人</td>
-          <td class="doc-input">
-            <avue-select
-              v-model="formData.xmfzr"
-              placeholder="请选择"
-              :dic="fzrList"
-              style="width: 100%"
-            ></avue-select>
-          </td>
-          <td class="doc-label">研究类型</td>
-          <td class="doc-input">
-            <avue-select
-              v-model="formData.yjlx"
-              placeholder="请选择"
-              :dic="studyTypeList"
-              style="width: 100%"
-            ></avue-select>
+          <td class="doc-label">项目申请单位</td>
+          <td colspan="3">
+            <el-input
+              v-model="formData.xmsqdw"
+              placeholder="请选择项目申请单位"
+            />
           </td>
         </tr>
         <tr>
@@ -69,6 +58,26 @@
           </td>
         </tr>
         <tr>
+          <td class="doc-label">项目负责人</td>
+          <td class="doc-input">
+            <avue-select
+              v-model="formData.xmfzr"
+              placeholder="请选择"
+              :dic="fzrList"
+              style="width: 100%"
+            ></avue-select>
+          </td>
+          <td class="doc-label">研究类型</td>
+          <td class="doc-input">
+            <avue-select
+              v-model="formData.yjlx"
+              placeholder="请选择"
+              :dic="studyTypeList"
+              style="width: 100%"
+            ></avue-select>
+          </td>
+        </tr>
+        <tr>
           <td class="doc-label">项目来源</td>
           <td class="doc-input">
             <avue-select
@@ -113,7 +122,7 @@
         <tr>
           <td class="doc-label">项目预算总额(万元)</td>
           <td class="doc-input">
-            {{ budgetAmount }}
+              <el-input-number v-model="formData.xmysze" type="number" :min="0" controls-position="right" />
           </td>
           <td class="doc-label">其中</td>
           <td class="doc-input">
@@ -121,7 +130,7 @@
               <div class="year-list-item" v-for="year of yearList" :key="year" :style="{ height: yearList.length == 1 ? '51px' : '32px', lineHeight: yearList.length == 1 ? '51px' : '32px' }">
                 <div class="year" >{{ year }}</div>
                 <div class="year-input">
-                  <input v-model="formData[year]" type="number" />
+                  <input v-model="formData[year]" type="number" :class="{ 'red': budgetIsExceed }" @input="handleYearInput" style="padding: 0 6px;" />
                 </div>
               </div>
             </div>
@@ -130,7 +139,20 @@
       </tbody>
     </table>
 
-    <avue-form v-model="formData" :option="option" style="margin-top: 30px; padding: 0;"></avue-form>
+    <avue-form v-model="formData" :option="option" style="margin-top: 30px; padding: 0;">
+      <template slot="lxpwLabel">
+        <label>立项批文</label>
+        <el-link type="primary" style="position: absolute; left: 220px; z-index: 1;">下载模板</el-link>
+      </template>
+      <template slot="lxbgLabel">
+        <label>立项报告</label>
+        <el-link type="primary" style="position: absolute; left: 220px; z-index: 1;">下载模板</el-link>
+      </template>
+      <template slot="qtzlLabel">
+        <label>其他资料</label>
+        <el-link type="primary" style="position: absolute; left: 220px; z-index: 1;">下载模板</el-link>
+      </template>
+    </avue-form>
     <p class="tip">注:可一次上传多个相关文件(文档、表格、图片等)。 支持格式:DOC, PDF, Excel, PNG, JPG, PPT 等。 请确保文件内容清晰有效。</p>
 
     <div class="btn-wrap" style="text-align: center;">
@@ -142,19 +164,22 @@
 <script>
 import { getDictionary } from "@/api/system/dictbiz";
 import { getList as getTechnicanRosterList } from "@/api/basicResource/technicianRoster";
-import { add, update } from "@/api/projectManage/projectList";
+import { add, update, getDetail } from "@/api/projectManage/projectList";
 import moment from "moment";
 import { deepClone } from "@/util/util";
 
 export default {
+  props: {
+    projectId: [String, Number]
+  },
   data() {
     return {
+      loading: false,
       formData: {},
 
-      // 项目预算总额
-      budgetAmount: 0,
-
       yearList: [],
+      // 预算是否超出
+      budgetIsExceed: false,
 
       // 项目负责人列表
       fzrList: [],
@@ -241,6 +266,9 @@ export default {
     },
     'formData.xmjssj'(newVal) {
       this.yearList = this.getDateRangeYear(this.formData.xmkssj, newVal);
+    },
+    'formData.xmysze'(newVal) {
+      this.calcBudgetIsExceed(newVal);
     }
   },
   computed: {
@@ -273,8 +301,36 @@ export default {
     this.getDictList("implementation_format", "implementFormatList");
     this.getDictList("expected_outcome_form", "expectedOutComeFormList");
     this.getDictList("economic_objectives", "economicObjectivesList");
+    if (this.projectId) {
+      this.getProjectDetail(this.projectId);
+    }
   },
   methods: {
+    getProjectDetail(xmId) {
+      this.loading = true;
+      getDetail({ id: xmId }).then(({ data }) => {
+        this.loading = false;
+        console.log(data)
+        if (data.code == 200) {
+          let beanData = { ...data.data };
+          console.log(beanData)
+          beanData.xmfzr = String(beanData.xmfzr || '');
+          beanData.yqcgxs = beanData.yqcgxs.split(",");
+          beanData.xmjsjjmb = beanData.xmjsjjmb.split(",");
+          beanData.lxpw = beanData.lxpw ? JSON.parse(beanData.lxpw) : [];
+          beanData.lxbg = beanData.lxbg ? JSON.parse(beanData.lxbg) : [];
+          beanData.qtzl = beanData.qtzl ? JSON.parse(beanData.qtzl) : [];
+          beanData.xmyszemx = beanData.xmyszemx ? JSON.parse(beanData.xmyszemx) : [];
+          beanData.xmyszemx.forEach(item => {
+            beanData[item.year] = item.amount;
+          });
+          console.log(beanData)
+          this.formData = { ...beanData };
+        }
+      }).catch(err => {
+        this.loading = false;
+      });
+    },
     getDateRangeYear(sDate, eDate) {
       let yearArr = [];
       if (sDate && eDate) {
@@ -295,6 +351,28 @@ export default {
         });
       });
     },
+    handleYearInput(e) {
+      this.calcBudgetIsExceed(this.formData.xmysze);
+    },
+    /**
+     * 计算是否超出预算
+     * @param total 预算总额
+     */
+    calcBudgetIsExceed(total) {
+      let yearTotal = 0;
+      let projectBudget = Number(total || 0);
+
+      this.yearList.forEach(year => {
+        let num = Number(this.formData[year] || 0);
+        yearTotal += num;
+      });
+
+      if (yearTotal > projectBudget) {
+        this.budgetIsExceed = true;
+      } else {
+        this.budgetIsExceed = false;
+      }
+    },
     /**
      * 获取人员花名册
      */
@@ -308,18 +386,23 @@ export default {
       });
     },
     validForm() {
-      console.log(!this.formData.lxpw)
       let errorText = '';
       if (!this.formData.xmmc) {
         errorText = '请输入项目名称';
       } else if (/技改|技术改造|推广|打样|翻新|产业化|生产线|改造|年产|示范/g.test(this.formData.xmmc)) {
         errorText = '研发项目名称,不符合统计部门的命名要求';
+      } else if (!this.formData.xmbh) {
+        errorText = '请输入项目编号'
+      } else if (!this.formData.yjlx) {
+        errorText = '请选择研究类型'
       } else if (!this.formData.xmfzr) {
         errorText = '请选择项目负责人';
       } else if (!this.formData.xmkssj) {
         errorText = '请选择项目开始时间';
       } else if (!this.formData.xmjssj) {
         errorText = '请选择项目结束时间';
+      } else if (!this.formData.xmysze) {
+        errorText = '请输入项目预算总额';
       } else if (!this.formData.lxpw.length) {
         errorText = '请上传立项批文!';
       } else if (!this.formData.lxbg.length) {
@@ -347,23 +430,32 @@ export default {
       let params = deepClone(this.formData);
       params.yqcgxs = params.yqcgxs ? params.yqcgxs.join(',') : '';
       params.xmjsjjmb = params.xmjsjjmb ? params.xmjsjjmb.join(',') : '';
-      params.lxbg = params.lxbg ? params.lxbg.map(item => item.value).join(',') : '';
-      params.lxpw = params.lxpw ? params.lxpw.map(item => item.value).join(',') : '';
-      params.qtzl = params.qtzl ? params.qtzl.map(item => item.value).join(',') : '';
+      params.lxbg = JSON.stringify(params.lxbg);
+      params.lxpw = JSON.stringify(params.lxpw);
+      params.qtzl = JSON.stringify(params.qtzl);
       let yearAmountList = [];
       this.yearList.forEach(year => {
         yearAmountList.push({ year: Number(year), amount: params[year] || 0 });
         delete params[year];
       });
-      params.yearAmountList = yearAmountList;
+      params.xmyszemx = JSON.stringify(yearAmountList);
 
-      console.log(params)
-      // this.addOrUpdate(params);
+      this.addOrUpdate(params);
     },
     addOrUpdate(params) {
       let func = params.id ? update : add;
-      add(params).then(res => {
-
+      this.loading = true;
+      func(params).then(({ data }) => {
+        this.loading = false;
+        if (data.code == 200) {
+          if (!params.id) {
+            this.$emit('success', data.data);
+            this.formData.id = data.data.xmId;
+          }
+          this.$message.success(params.id ? '修改成功!' : '保存成功!');
+        }
+      }).catch(err => {
+        this.loading = false;
       });
     }
   },
@@ -432,6 +524,10 @@ tr td {
   
 }
 
+.red {
+  color: red;
+}
+
 .tip {
   position: relative;
   top: 0;

+ 90 - 54
src/views/project-manage/components/change-form.vue

@@ -6,31 +6,14 @@
         <tr>
           <td class="doc-label">研发项目名称</td>
           <td class="doc-input">
-            <el-select
-              v-model="formData.xmId"
-              filterable
-              remote
-              reserve-keyword
-              placeholder="请输入关键词"
-              :remote-method="remoteMethod"
-              :loading="loading"
-              style="width: 100%;"
-              @change="handleProjectChange"
-            >
-              <el-option
-                v-for="item in projectList"
-                :key="item.id"
-                :label="item.xmmc"
-                :value="item.id">
-              </el-option>
-            </el-select>
+            <project-select v-model="currProjectId" @change="handleProjectChange" :disabled="disabled"></project-select>
           </td>
           <td class="doc-label">研发项目编号</td>
           <td class="doc-input">{{ selProject.xmbh }}</td>
         </tr>
         <tr>
           <td class="doc-label">项目负责人</td>
-          <td class="doc-input">{{ selProject.xmfzr }} </td>
+          <td class="doc-input">{{ selProject.xmfzrxm }} </td>
           <td class="doc-label">项目申请单位</td>
           <td class="doc-input">{{ selProject.xmsqdw }}</td>
         </tr>
@@ -43,16 +26,17 @@
               placeholder="请选择"
               :dic="changeTypeList"
               style="width: 100%"
+              :disabled="disabled"
             ></avue-select>
           </td>
         </tr>
 
         <tr>
           <td class="doc-label">变更前</td>
-          <td class="doc-input">{{ selProject[formData.zdmc] }}</td>
+          <td class="doc-input">{{ selProject[formData.zdmc == 'xmfzr' ? 'xmfzrxm' : formData.zdmc] }}</td>
           <td class="doc-label">变更后</td>
           <td class="doc-input">
-            <el-input v-if="formData.zdmc === 'xmmc'" placeholder="请输入项目名称" v-model="formData.bghdz" />
+            <el-input v-if="formData.zdmc === 'xmmc'" placeholder="请输入项目名称" v-model="formData.bghdz" :disabled="disabled" />
             <el-date-picker
               v-if="'xmkssj,xmjssj'.indexOf(formData.zdmc) > -1"
               v-model="formData.bghdz"
@@ -60,14 +44,23 @@
               value-format="yyyy-MM-dd"
               placeholder="请选择日期"
               style="width: 100%"
+              :disabled="disabled"
             ></el-date-picker>
+            <avue-select
+              v-if="formData.zdmc === 'xmfzr'"
+              v-model="formData.bghdz"
+              placeholder="请选择"
+              :dic="fzrList"
+              style="width: 100%"
+              :disabled="disabled"
+            ></avue-select>
           </td>
         </tr>
         
         <tr>
           <td class="doc-label">变更原因说明</td>
           <td class="doc-input" colspan="3">
-            <el-input v-model="formData.bgyy" type="textarea" :rows="3" />
+            <el-input v-model="formData.bgyy" type="textarea" :rows="3" :disabled="disabled" />
           </td>
         </tr>
 
@@ -75,11 +68,12 @@
           <td class="doc-label">变更生效时间</td>
           <td class="doc-input" colspan="3">
             <el-date-picker
-              v-model="formData.bzsxssj"
+              v-model="formData.bgsxsj"
               format="yyyy年MM月dd日"
               value-format="yyyy-MM-dd"
               placeholder="请选择日期"
               style="width: 100%"
+              :disabled="disabled"
             ></el-date-picker>
           </td>
         </tr>
@@ -89,22 +83,24 @@
           <td class="doc-input" colspan="3" style="text-align: left;">
             <avue-upload
               action="/api/kd-resource/oss/endpoint/put-file"
+              dataType="object"
               :props-http="{
                 url: 'link',
-                name: 'name',
+                name: 'originalName',
                 res: 'data',
               }"
               type="upload"
               v-model="formData.attachment"
               style="margin: 14px 0 14px 12px;"
+              :disabled="disabled"
             ></avue-upload>
           </td>
         </tr>
       </tbody>
     </table>
 
-    <div class="btn-wrap" style="text-align: center; margin-top: 30px;">
-      <el-button style="width: 160px;" @click="handleSaveBtn">重置</el-button>
+    <div v-if="!disabled" class="btn-wrap" style="text-align: center; margin-top: 30px;">
+      <el-button style="width: 160px;" @click="handleResetBtn">重置</el-button>
       <el-button type="primary" style="width: 160px;" @click="handleSaveBtn">保存</el-button>
     </div>
   </div>
@@ -112,26 +108,67 @@
 
 <script>
 import { getDictionary } from "@/api/system/dictbiz";
-import { getList as getProjectList } from "@/api/projectManage/projectList";
-import { add } from "@/api/projectManage/change";
+import { getList as getTechnicanRosterList } from "@/api/basicResource/technicianRoster";
+import { save } from "@/api/projectManage/change";
 import moment from "moment";
+import projectSelect from "@/components/project-select";
 
 export default {
+  props: {
+    projectId: [String, Number],
+    data: Object,
+    disabled: {
+      type: Boolean,
+      type: false
+    }
+  },
+  components: {
+    projectSelect
+  },
   data() {
     return {
+      currProjectId: '',
       formData: {},
-
       changeTypeList: [],
-
       loading: false,
-      projectList: [],
       selProject: {},
+
+      fzrList: [],
     };
   },
+  watch: {
+    "formData.zdmc"(newVal) {
+      if (newVal == 'xmfzr') {
+        this.getTechnicanRosterListFunc(moment(this.selProject.xmkssj).format('yyyyMM'));
+      }
+    }
+  },
   mounted() {
     this.getDictList("xm_biangeng_field", "changeTypeList");
+    this.currProjectId = this.projectId;
+
+    if (this.data && Object.keys(this.data)) {
+      this.formData = {
+        ...this.data,
+      };
+      let attachment = this.formData.attachment;
+
+      this.formData.attachment = JSON.parse(attachment)
+    }
   },
   methods: {
+    /**
+     * 获取人员花名册
+     */
+    getTechnicanRosterListFunc(yearAndMonth) {
+      getTechnicanRosterList(1, 99999, { yearAndMonth }).then(res => {
+        if (res.data.success) {
+          this.fzrList = res.data.data.records.map(item => {
+            return { label: item.name, value: item.id };
+          });
+        }
+      });
+    },
     getDictList(code, toListKey) {
       getDictionary({ code }).then((res) => {
         this[toListKey] = res.data.data.map((item) => {
@@ -139,34 +176,18 @@ export default {
         });
       });
     },
-    remoteMethod(query) {
-      if (query !== '') {
-        this.loading = true;
-        setTimeout(() => {
-          this.loading = false;
-          getProjectList(1, 99999, { xmmc: query }).then(({ data }) => {
-            if (data.success) {
-              this.projectList = data.data.records;
-            }
-          })
-        }, 200);
-      } else {
-        this.projectList = [];
-      }
-    },
-    handleProjectChange(val) {
-      let currPro = this.projectList.find(item => item.id === val);
-      this.selProject = currPro;
+    handleProjectChange(data) {
+      this.selProject = data;
     },
     validForm() {
       let errorText = '';
-      if (!this.formData.xmId) {
+      if (!this.currProjectId) {
         errorText = '请选择变更的项目';
       } else if (!this.formData.zdmc) {
         errorText = '请选择变更类型';
       } else if (!this.formData.bgyy) {
         errorText = '请输入变更原因';
-      } else if (!this.formData.bzsxssj) {
+      } else if (!this.formData.bgsxsj) {
         errorText = '请选择变更生效时间';
       } else if (!this.formData.bghdz) {
         errorText = '请输入变更后的信息';
@@ -174,6 +195,9 @@ export default {
 
       return errorText;
     },
+    handleResetBtn() {
+      this.formData = {};
+    },
     handleSaveBtn() {
       let errorText = this.validForm();
       if (errorText) {
@@ -181,10 +205,22 @@ export default {
         return;
       }
 
-      this.addOrUpdate(params);
+      const params = {
+        ...this.formData,
+        bgqdz: this.selProject[this.formData.zdmc],
+        attachment: JSON.stringify(this.formData.attachment),
+        xmId: this.currProjectId
+      };
+
+      this.saveData(params);
     },
-    addOrUpdate(params) {
-      console.log(params)
+    saveData(params) {
+      save(params).then(({ data }) => {
+        if (data.code == 200) {
+          this.$message.success("保存成功!");
+          this.$emit("success");
+        }
+      });
     }
   },
 };

+ 54 - 5
src/views/project-manage/components/design-cost.vue

@@ -1,13 +1,21 @@
 <template>
   <div>
+    <div style="margin-top: 6px;">
+      <el-form :inline="true">
+        <el-form-item label="研发项目名称">
+          <project-select v-model="params.xmId" @change="handleProjectChange"></project-select>
+        </el-form-item>
+        <el-form-item label="研发项目编号">
+          {{ selProject.xmbh }}
+        </el-form-item>
+      </el-form>
+    </div>
     <avue-crud
       ref="crud"
       v-bind="bindVal"
       v-on="onEvent"
       v-model="form"
       :page.sync="page"
-      :before-open="handleBeforeOpen"
-      :permission="permissionList"
     >
       <template slot="menuLeft">
         <el-button
@@ -60,24 +68,61 @@
 <script>
 import {exportBloByPost} from "@/api/common";
 import UploadExcelDialog from "@/components/upload-excel-dialog";
+import projectSelect from "@/components/project-select";
 import {getToken} from "@/util/auth";
 import {downloadXls} from "@/util/util";
 
 
 export default window.$crudCommon({
+  props: {
+    projectId: [String, Number]
+  },
   components: {
     UploadExcelDialog,
+    projectSelect,
   },
   data() {
     return {
+      params: {
+        xmId: ''
+      },
+      selProject: {},
+
       wideTableColumns: [],
       printTitle: "",
     };
   },
+  watch: {
+    "params.xmId"() {
+      this.page.currentPage = 1;
+      this.getList(this.page);
+    },
+  },
   created() {
-    this.option.height = window.innerHeight - 270;
+    this.params.xmId = this.projectId;
+    this.option.height = window.innerHeight - 340;
   },
   methods: {
+    handleBeforeOpen(done, type) {
+      if (!this.params.xmId) {
+        this.$message.warning("请选择项目!");
+        return;
+      }
+
+      done();
+    },
+    getList() {
+      if (!this.params.xmId) {
+        return;
+      }
+      this.loadData();
+    },
+    getFormData() {
+      return { ...this.form, xmId: this.params.xmId }
+    },
+    handleProjectChange(data) {
+      this.selProject = data;
+    },
     handleImport() {
       this.$refs.uploadExcelDialog.open('/api/kd-scientific/ys-sjfy/import');
     },
@@ -87,7 +132,7 @@ export default window.$crudCommon({
     },
     handleExport() {
       exportBloByPost(`/api/kd-scientific/ys-sjfy/export?${this.website.tokenHeader}=${getToken()}`, this.params).then(res => {
-        downloadXls(res.data, `设计费用.xlsx`);
+        downloadXls(res.data, `${this.selProject.xmmc}设计费用.xlsx`);
       });
     },
     /**
@@ -96,7 +141,7 @@ export default window.$crudCommon({
      */
     printTable(isLandscape) {
       this.wideTableColumns = this.$refs.crud.columnOption;
-      this.printTitle = `设计费用`;
+      this.printTitle = `${this.selProject.xmmc}设计费用`;
       this.$nextTick(() => {
         this.$refs.printWideTable.printTable(isLandscape);
       })
@@ -106,6 +151,10 @@ export default window.$crudCommon({
   // 模块路径
   name: 'projectManage/designCost',
   res: ({ data }) => {
+    data.records = data.records.map(item => {
+      item.ysje = (item.ysje || 0).toFixed(2);
+      return item;
+    });
     return data;
   },
 });

+ 99 - 65
src/views/project-manage/components/implement-form.vue

@@ -1,15 +1,15 @@
 <template>
-  <div class="doc-page">
+  <div class="doc-page" v-loading="loading">
     <h3 class="page-title" style="margin: 24px 0 16px;">研发项目阶段性报告</h3>
 
     <div class="project-basic-info">
       <div class="info-row">{{ `研发项目名称:${ selProject.xmmc || '' }` }}</div>
-      <div class="info-row">{{ `项目负责人:${ selProject.xmfzr || '' }` }}</div>
+      <div class="info-row">{{ `项目负责人:${ selProject.xmfzrxm || '' }` }}</div>
       <div class="info-row">{{ `项目申请单位:${ selProject.xmsqdw || '' }` }}</div>
       <div class="info-row">{{ `项目执行期:${ getXmDateRange || '' }` }}</div>
       <div class="info-row">
         <span>填报时间:</span>
-        <span><el-date-picker v-model="formData.tbsj" type="month" value-format="yyyy-MM" /></span>
+        <span><el-date-picker v-model="formData.tbsj" value-format="yyyy-MM-dd" /></span>
       </div>
     </div>
 
@@ -18,32 +18,17 @@
         <tr>
           <td class="doc-label">研发项目名称</td>
           <td class="doc-input">
-            <el-select
-              v-model="formData.xmId"
-              filterable
-              remote
-              reserve-keyword
-              placeholder="请输入关键词"
-              :remote-method="remoteMethod"
-              :loading="loading"
-              style="width: 100%;"
-              :disabled="!formData.tbsj"
+            <project-select
+              v-model="currProjectId"
               @change="handleProjectChange"
-            >
-              <el-option
-                v-for="item in projectList"
-                :key="item.id"
-                :label="item.xmmc"
-                :value="item.id">
-              </el-option>
-            </el-select>
+            ></project-select>
           </td>
           <td class="doc-label">项目申请单位</td>
           <td class="doc-input">{{ selProject.xmsqdw }}</td>
         </tr>
         <tr>
           <td class="doc-label">项目负责人</td>
-          <td class="doc-input">{{ selProject.xmfzr }} </td>
+          <td class="doc-input">{{ selProject.xmfzrxm }} </td>
           <td class="doc-label">研究类型</td>
           <td class="doc-input">{{ selProject.yjlx }}</td>
         </tr>
@@ -73,8 +58,25 @@
     </table>
 
     <avue-form v-model="formData" :option="option" style="margin-top: 30px; padding: 0;">
-      <template slot="jdbgType" slot-scope="{file}">
-        <span>{{file.originalName}}</span>
+      <template slot="jdbgLabel">
+        <label>季度报告</label>
+        <el-link type="primary" style="position: absolute; left: 290px; z-index: 1;">下载模板</el-link>
+      </template>
+      <template slot="zqbgLabel">
+        <label>中期报告</label>
+        <el-link type="primary" style="position: absolute; left: 290px; z-index: 1;">下载模板</el-link>
+      </template>
+      <template slot="ndbgLabel">
+        <label>年度报告</label>
+        <el-link type="primary" style="position: absolute; left: 290px; z-index: 1;">下载模板</el-link>
+      </template>
+      <template slot="lcbbgLabel">
+        <label>里程碑报告</label>
+        <el-link type="primary" style="position: absolute; left: 290px; z-index: 1;">下载模板</el-link>
+      </template>
+      <template slot="qtjdxzjbgLabel">
+        <label>其他阶段性总结报告</label>
+        <el-link type="primary" style="position: absolute; left: 290px; z-index: 1;">下载模板</el-link>
       </template>
     </avue-form>
     <p class="tip">注:可一次上传多个相关文件(文档、表格、图片等)。 支持格式:DOC, PDF, Excel, PNG, JPG, PPT 等。 请确保文件内容清晰有效。</p>
@@ -86,27 +88,29 @@
 </template>
 
 <script>
-import { getDictionary } from "@/api/system/dictbiz";
-import { getList as getProjectList } from "@/api/projectManage/projectList";
-import { add } from "@/api/projectManage/change";
+import projectSelect from "@/components/project-select";
+import { save, getDetail } from "@/api/projectManage/implement";
 import moment from "moment";
 
 export default {
+  props: {
+    projectId: [String, Number],
+    yearAndMonth: [Number, String]
+  },
+  components: {
+    projectSelect
+  },
   data() {
     return {
       formData: {},
 
-      changeTypeList: [],
-
       loading: false,
       projectList: [],
-      selProject: {},
 
+      currProjectId: '',
+      selProject: {},
     };
   },
-  mounted() {
-    this.getDictList("xm_biangeng_field", "changeTypeList");
-  },
   computed: {
     getXmDateRange() {
       if (this.selProject.xmkssj && this.selProject.xmjssj) {
@@ -130,11 +134,11 @@ export default {
             dataType: "object",
             propsHttp: {
               url: "link",
-              name: 'name',
+              name: 'originalName',
               res: "data",
             },
             action: '/api/kd-resource/oss/endpoint/put-file',
-            disabled: !this.formData.xmId
+            disabled: !this.currProjectId
           },
           {
             label: "中期报告",
@@ -149,7 +153,7 @@ export default {
               res: "data",
             },
             action: '/api/kd-resource/oss/endpoint/put-file',
-            disabled: !this.formData.xmId
+            disabled: !this.currProjectId
           },
           {
             label: "年度报告",
@@ -164,7 +168,7 @@ export default {
               name: 'originalName',
               res: "data",
             },
-            disabled: !this.formData.xmId
+            disabled: !this.currProjectId
           },
           {
             label: "里程碑报告",
@@ -179,7 +183,7 @@ export default {
               name: 'originalName',
               res: "data",
             },
-            disabled: !this.formData.xmId
+            disabled: !this.currProjectId
           },
           {
             label: "其他阶段性总结报告",
@@ -194,42 +198,61 @@ export default {
               name: 'originalName',
               res: "data",
             },
-            disabled: !this.formData.xmId
+            disabled: !this.currProjectId
           },
         ],
       }
     }
   },
+  watch: {
+    currProjectId() {
+      this.getImplementDetail();
+    }
+  },
+  mounted() {
+    this.currProjectId = this.projectId || '';
+    if (this.currProjectId) {
+      this.getImplementDetail();
+    }
+  },
   methods: {
-    getDictList(code, toListKey) {
-      getDictionary({ code }).then((res) => {
-        this[toListKey] = res.data.data.map((item) => {
-          return { label: item.dictValue, value: item.dictKey };
-        });
+    getImplementDetail() {
+      this.loading = true;
+      getDetail({ xmId: this.currProjectId, yearAndMonth: this.yearAndMonth }).then(({ data }) => {
+        this.loading = false;
+        if (data.code == 200 && data.data && Object.keys(data.data).length) {
+          this.formData = {
+            id: data.data.id,
+            xmId: data.data.xmId,
+            tbsj: data.data.tbsj,
+            jdbg: data.data.jdbg ? JSON.parse(data.data.jdbg) : [],
+            zqbg: data.data.zqbg ? JSON.parse(data.data.zqbg) : [],
+            ndbg: data.data.ndbg ? JSON.parse(data.data.ndbg) : [],
+            lcbbg: data.data.lcbbg ? JSON.parse(data.data.lcbbg) : [],
+            qtjdxzjbg: data.data.qtjdxzjbg ? JSON.parse(data.data.qtjdxzjbg) : [],
+          };
+        } else {
+          this.formData = {
+            tbsj: '',
+            jdbg: [],
+            zqbg: [],
+            ndbg: [],
+            lcbbg: [],
+            qtjdxzjbg: [],
+          };
+        }
+      }).catch(() => {
+        this.loading = false;
       });
     },
-    remoteMethod(query) {
-      if (query !== '') {
-        this.loading = true;
-        setTimeout(() => {
-          this.loading = false;
-          getProjectList(1, 99999, { xmmc: query }).then(({ data }) => {
-            if (data.success) {
-              this.projectList = data.data.records;
-            }
-          })
-        }, 200);
-      } else {
-        this.projectList = [];
-      }
-    },
-    handleProjectChange(val) {
-      let currPro = this.projectList.find(item => item.id === val);
-      this.selProject = currPro;
+    handleProjectChange(data) {
+      this.selProject = data;
     },
     validForm() {
       let errorText = '';
-      if (!this.formData.xmId) {
+      if (!this.formData.tbsj) {
+        errorText = '请选择填报时间';
+      } else if (!this.currProjectId) {
         errorText = '请选择填报的项目';
       }
 
@@ -242,10 +265,21 @@ export default {
         return;
       }
 
-      this.saveData(this.formData);
+      const params = { ...this.formData, xmId: this.currProjectId };
+      params.jdbg = JSON.stringify(params.jdbg);
+      params.zqbg = JSON.stringify(params.zqbg);
+      params.ndbg = JSON.stringify(params.ndbg);
+      params.lcbbg = JSON.stringify(params.lcbbg);
+      params.qtjdxzjbg = JSON.stringify(params.qtjdxzjbg);
+
+      this.saveData(params);
     },
     saveData(params) {
-      console.log(params)
+      save(params).then(({ data }) => {
+        if (data.code == 200) {
+          this.$message.success('保存成功!');
+        }
+      });
     }
   },
 };

+ 55 - 6
src/views/project-manage/components/other-cost.vue

@@ -1,5 +1,16 @@
 <template>
   <div>
+    <div style="margin-top: 6px;">
+      <el-form :inline="true">
+        <el-form-item label="研发项目名称">
+          <project-select v-model="params.xmId" @change="handleProjectChange"></project-select>
+        </el-form-item>
+        <el-form-item label="研发项目编号">
+          {{ selProject.xmbh }}
+        </el-form-item>
+      </el-form>
+    </div>
+
     <avue-crud
       ref="crud"
       v-bind="bindVal"
@@ -7,7 +18,6 @@
       v-model="form"
       :page.sync="page"
       :before-open="handleBeforeOpen"
-      :permission="permissionList"
     >
       <template slot="menuLeft">
         <el-button
@@ -60,26 +70,61 @@
 <script>
 import {exportBloByPost} from "@/api/common";
 import UploadExcelDialog from "@/components/upload-excel-dialog";
+import projectSelect from "@/components/project-select";
 import {getToken} from "@/util/auth";
 import {downloadXls} from "@/util/util";
 
 
 export default window.$crudCommon({
+  props: {
+    projectId: [String, Number]
+  },
   components: {
     UploadExcelDialog,
+    projectSelect
   },
   data() {
     return {
+      params: {
+        xmId: ''
+      },
+      selProject: {},
+
       wideTableColumns: [],
       printTitle: "",
     };
   },
+  watch: {
+    "params.xmId"() {
+      this.page.currentPage = 1;
+      this.getList(this.page);
+    },
+  },
   created() {
-    this.option.height = window.innerHeight - 270;
+    this.params.xmId = this.projectId;
+    this.option.height = window.innerHeight - 340;
   },
   methods: {
-    handleImport() {
-      this.$refs.uploadExcelDialog.open('/api/kd-scientific/ys-qtfy/import');
+    handleBeforeOpen(done, type) {
+      if (!this.params.xmId) {
+        this.$message.warning("请选择项目!");
+        return;
+      }
+
+      done();
+    },
+    getList() {
+      if (!this.params.xmId) {
+        return;
+      }
+      console.log(this.params.xmId)
+      this.loadData();
+    },
+    getFormData() {
+      return { ...this.form, xmId: this.params.xmId }
+    },
+    handleProjectChange(data) {
+      this.selProject = data;
     },
     uploadAfter() {
       this.page.currentPage = 1;
@@ -87,7 +132,7 @@ export default window.$crudCommon({
     },
     handleExport() {
       exportBloByPost(`/api/kd-scientific/ys-qtfy/export?${this.website.tokenHeader}=${getToken()}`, this.params).then(res => {
-        downloadXls(res.data, `其他费用.xlsx`);
+        downloadXls(res.data, `${this.selProject.xmmc}其他费用.xlsx`);
       });
     },
     /**
@@ -96,7 +141,7 @@ export default window.$crudCommon({
      */
     printTable(isLandscape) {
       this.wideTableColumns = this.$refs.crud.columnOption;
-      this.printTitle = `其他费用`;
+      this.printTitle = `${this.selProject.xmmc}其他费用`;
       this.$nextTick(() => {
         this.$refs.printWideTable.printTable(isLandscape);
       })
@@ -106,6 +151,10 @@ export default window.$crudCommon({
   // 模块路径
   name: 'projectManage/otherCost',
   res: ({ data }) => {
+    data.records = data.records.map(item => {
+      item.ysje = (item.ysje || 0).toFixed(2);
+      return item;
+    })
     return data;
   },
 });

+ 56 - 4
src/views/project-manage/components/outsourcing-cost.vue

@@ -1,5 +1,16 @@
 <template>
   <div>
+    <div style="margin-top: 6px;">
+      <el-form :inline="true">
+        <el-form-item label="研发项目名称">
+          <project-select v-model="params.xmId" @change="handleProjectChange"></project-select>
+        </el-form-item>
+        <el-form-item label="研发项目编号">
+          {{ selProject.xmbh }}
+        </el-form-item>
+      </el-form>
+    </div>
+
     <avue-crud
       ref="crud"
       v-bind="bindVal"
@@ -7,7 +18,6 @@
       v-model="form"
       :page.sync="page"
       :before-open="handleBeforeOpen"
-      :permission="permissionList"
     >
       <template slot="menuLeft">
         <el-button
@@ -60,24 +70,61 @@
 <script>
 import {exportBloByPost} from "@/api/common";
 import UploadExcelDialog from "@/components/upload-excel-dialog";
+import projectSelect from "@/components/project-select";
 import {getToken} from "@/util/auth";
 import {downloadXls} from "@/util/util";
 
 
 export default window.$crudCommon({
+  props: {
+    projectId: [String, Number]
+  },
   components: {
     UploadExcelDialog,
+    projectSelect
   },
   data() {
     return {
+      params: {
+        xmId: ''
+      },
+      selProject: {},
+
       wideTableColumns: [],
       printTitle: "",
     };
   },
+  watch: {
+    "params.xmId"() {
+      this.page.currentPage = 1;
+      this.getList(this.page);
+    },
+  },
   created() {
-    this.option.height = window.innerHeight - 270;
+    this.params.xmId = this.projectId;
+    this.option.height = window.innerHeight - 340;
   },
   methods: {
+    handleBeforeOpen(done, type) {
+      if (!this.params.xmId) {
+        this.$message.warning("请选择项目!");
+        return;
+      }
+
+      done();
+    },
+    getList() {
+      if (!this.params.xmId) {
+        return;
+      }
+      this.loadData();
+    },
+    getFormData() {
+      return { ...this.form, xmId: this.params.xmId }
+    },
+    handleProjectChange(data) {
+      this.selProject = data;
+    },
     handleImport() {
       this.$refs.uploadExcelDialog.open('/api/kd-scientific/ys-wtwbyjkffy/import');
     },
@@ -87,7 +134,7 @@ export default window.$crudCommon({
     },
     handleExport() {
       exportBloByPost(`/api/kd-scientific/ys-wtwbyjkffy/export?${this.website.tokenHeader}=${getToken()}`, this.params).then(res => {
-        downloadXls(res.data, `委托外部研究开发费用.xlsx`);
+        downloadXls(res.data, `${this.selProject.xmmc}委托外部研究开发费用.xlsx`);
       });
     },
     /**
@@ -96,7 +143,7 @@ export default window.$crudCommon({
      */
     printTable(isLandscape) {
       this.wideTableColumns = this.$refs.crud.columnOption;
-      this.printTitle = `委托外部研究开发费用`;
+      this.printTitle = `${this.selProject.xmmc}委托外部研究开发费用`;
       this.$nextTick(() => {
         this.$refs.printWideTable.printTable(isLandscape);
       })
@@ -106,6 +153,11 @@ export default window.$crudCommon({
   // 模块路径
   name: 'projectManage/outsourcingCost',
   res: ({ data }) => {
+    data.records = data.records.map(item => {
+      item.wwfy = (item.wwfy || 0).toFixed(2);
+
+      return item;
+    })
     return data;
   },
 });

+ 372 - 0
src/views/project-manage/components/outsourcing-doc.vue

@@ -0,0 +1,372 @@
+<template>
+  <div>
+    <div class="header-btn" style="width: 1200px; margin: 0 auto; text-align: right;">
+      <el-button type="primary">下载</el-button>
+      <el-button type="primary">打印</el-button>
+      <el-button type="primary" @click="handleAddClick">新增</el-button>
+    </div>
+    <div class="doc-page">
+      <h3 class="page-title" style="margin: 24px 0 20px;">委外项目管理</h3>
+      <table class="doc-table">
+        <tbody>
+          <tr>
+            <td class="doc-label">研发项目名称</td>
+            <td class="doc-input">
+              <project-select v-model="currProjectId"></project-select>
+            </td>
+            <td class="doc-label">研发项目编号</td>
+            <td class="doc-input">{{ selProject.xmsqdw }}</td>
+          </tr>
+          <tr>
+            <td colspan="4">
+              <table class="child-table">
+                <thead>
+                  <tr>
+                    <td width="10%">受托方全称</td>
+                    <td width="10%">受托方类型</td>
+                    <td width="10%">合同名称</td>
+                    <td width="10%">委外费用金额(万元)</td>
+                    <td width="8%">是否完成技术合同登记</td>
+                    <td width="8%">技术合同登记类型</td>
+                    <td width="8%">技术合同登记金额(万元)</td>
+                    <td width="31%">附件上传</td>
+                    <td width="5%">操作</td>
+                  </tr>
+                </thead>
+                <tbody>
+                  <tr v-for="(item, index) of  list" :key="index">
+                    <td v-for="key of colKey" :key="key">
+                      <template v-if="key == 'fileTypeList'">
+                        <div class="file-list">
+                          <div class="file-list-item" v-for="(file, fileIdx) of item[key]" :key="fileIdx">
+                            <div class="file-name">{{ file.label }}</div>
+                            <div class="file-url">{{ file.url }}</div>
+                          </div>
+                        </div>
+                      </template>
+                      <span v-else>{{ item[key] }}</span>
+                    </td>
+                    <td width="10%">
+                      <el-button type="text" @click="handleEditClick(item)">编辑</el-button>
+                      <el-button type="text" style="margin-left: 0;">删除</el-button>
+                    </td>
+                  </tr>
+                </tbody>
+              </table>
+            </td>
+          </tr>
+        </tbody>
+      </table>
+
+      <p class="tip">注:可一次上传多个相关文件(文档、表格、图片等)。 支持格式:DOC, PDF, Excel, PNG, JPG, PPT 等。 请确保文件内容清晰有效。</p>
+
+      <el-drawer
+        :visible.sync="drawerVisible"
+        :title="drawerTitle"
+        modal-append-to-body
+        append-to-body
+        size="500px"
+        destroy-on-close
+      >
+        <avue-form v-model="form" :option="option">
+
+        </avue-form>
+      </el-drawer>
+    </div>
+  </div>
+</template>
+
+<script>
+import projectSelect from "@/components/project-select";
+
+export default {
+  props: {
+    projectId: [String, Number]
+  },
+  components: {
+    projectSelect
+  },
+  data() {
+    return {
+      list: [{
+        stfmc: '111',
+        stflx: '境内个人',
+        htmc: '333',
+        wwfyje: 20,
+        isDj: '是',
+        htlx: '技术开发合同',
+        htje: 20,
+        fileTypeList: [{
+          label: '技术合同协议',
+          url: 'aaa.doc'
+        }, {
+          label: '委外费用发票',
+          url: 'bbb.doc'
+        }, {
+          label: '技术合同登记证明',
+          url: 'ccc.doc'
+        }, {
+          label: '受托方交付成果',
+          url: 'ddd.doc'
+        }, {
+          label: '其他资料',
+          url: 'eee.doc'
+        }]
+      }],
+      colKey: ['stfmc', 'stflx', 'htmc', 'wwfyje', 'isDj', 'htlx', 'htje', 'fileTypeList'],
+
+      currProjectId: '',
+      selProject: {},
+
+      drawerTitle: '',
+      drawerVisible: false,
+      option:{
+        labelWidth: 170,
+        column:[
+          {
+            label: '受托方全称',
+            prop: 'stfqc',
+            span: 24,
+            rules: [{
+              required: true,
+              message: "请输入受头发全称",
+              trigger: "blur"
+            }]
+          },
+          {
+            label: '受托方类型',
+            prop: 'stflx',
+            span: 24,
+            type: 'select',
+            dicUrl: '/api/kd-system/dict-biz/dictionary?code=trustee_type',
+            props: {
+              label: 'dictValue',
+              value: 'dictKey',
+            },
+            rules: [{
+              required: true,
+              message: "请选择受托方类型",
+              trigger: "blur"
+            }]
+          },
+          {
+            label: '合同名称',
+            prop: 'htmc',
+            span: 24
+          },
+          {
+            label: '委外费用金额(万元)',
+            prop: 'htmc',
+            span: 24,
+            type: 'number',
+            min: 0,
+            precision: 2,
+          },
+          {
+            label: '是否完成技术合同登记',
+            prop: 'sfwcjshtdj',
+            span: 24,
+            type: 'select',
+            dicUrl: '/api/kd-system/dict-biz/dictionary?code=yes_or_no',
+            props: {
+              label: 'dictValue',
+              value: 'dictKey',
+            },
+            rules: [{
+              required: true,
+              message: "请选择",
+              trigger: "blur"
+            }]
+          },
+          {
+            label: '技术合同类型',
+            prop: 'jshtlx',
+            span: 24,
+            type: 'select',
+            dicUrl: '/api/kd-system/dict-biz/dictionary?code=contract_registration_type',
+            props: {
+              label: 'dictValue',
+              value: 'dictKey',
+            },
+          },
+          {
+            label: '技术合同登记金额(万元)',
+            prop: 'htmc',
+            span: 24,
+            type: 'number',
+            min: 0,
+            precision: 2,
+          },
+          {
+            label: "技术合同协议",
+            prop: "jshtxy",
+            type: "upload",
+            multiple: true,
+            span: 24,
+            dataType: "object",
+            propsHttp: {
+              url: "link",
+              name: "originalName",
+              res: "data",
+            },
+            action: '/api/kd-resource/oss/endpoint/put-file',
+          },
+          
+          {
+            label: "委外费用发票",
+            prop: "wwfyfp",
+            type: "upload",
+            multiple: true,
+            span: 24,
+            dataType: "object",
+            propsHttp: {
+              url: "link",
+              name: "originalName",
+              res: "data",
+            },
+            action: '/api/kd-resource/oss/endpoint/put-file',
+          },
+          {
+            label: "技术合同登记证明",
+            prop: "jshtdjzm",
+            type: "upload",
+            multiple: true,
+            span: 24,
+            dataType: "object",
+            propsHttp: {
+              url: "link",
+              name: "originalName",
+              res: "data",
+            },
+            action: '/api/kd-resource/oss/endpoint/put-file',
+          },
+          {
+            label: "受托方交付成果",
+            prop: "stfjfcg",
+            type: "upload",
+            multiple: true,
+            span: 24,
+            dataType: "object",
+            propsHttp: {
+              url: "link",
+              name: "originalName",
+              res: "data",
+            },
+            action: '/api/kd-resource/oss/endpoint/put-file',
+          },
+          {
+            label: "其他资料",
+            prop: "qtzl",
+            type: "upload",
+            multiple: true,
+            span: 24,
+            dataType: "object",
+            propsHttp: {
+              url: "link",
+              name: "originalName",
+              res: "data",
+            },
+            action: '/api/kd-resource/oss/endpoint/put-file',
+          },
+        ]
+      },
+      form: {},
+
+    };
+  },
+  methods: {
+    handleAddClick() {
+      this.drawerVisible = true;
+      this.drawerTitle = '新增委外信息';
+    },
+    handleEditClick(data) {
+      this.drawerVisible = true;
+      this.form = { ...data };
+      this.drawerTitle = '编辑委外信息';
+    }
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.page-title {
+  text-align: center;
+  font-size: 24px;
+}
+
+.doc-page {
+  width: 1200px;
+  margin: 30px auto;
+}
+.doc-table {
+  width: 100%;
+  border: 1px solid #333;
+}
+.doc-label {
+  text-align: center;
+  padding: 6px;
+  color: #777;
+  font-size: 14px;
+  width: 15%;
+}
+.doc-input {
+  text-align: center;
+  color: #333;
+  width: 35%;
+}
+.doc-table tr td {
+  border: 1px solid #333;
+}
+
+
+.child-table tr {
+  td {
+    border: none;
+    border-right: 1px solid #333;
+    // padding: 6px;
+    padding: 0 6px;
+    text-align: center;
+    color: #666;
+    font-size: 14px; 
+    &:last-child {
+      border: none;
+    }
+  }
+}
+
+.child-table thead tr {
+  border-bottom: 1px solid #333;
+}
+
+.child-table tbody tr {
+  border-bottom: 1px solid #333;
+  &:last-child {
+    border-bottom: 0;
+  } 
+}
+
+.file-list {
+  &-item {
+    display: flex;
+    border-bottom: 1px solid #333;
+    line-height: 32px;
+    text-align: center;
+    .file-name {
+      width: 40%;
+      border-right: 1px solid #333;
+    }
+    .file-url {
+      width: 60%;
+    }
+    &:last-child {
+      border-bottom: 0;
+    }
+  }
+}
+
+.tip {
+  color: red;
+  margin-top: 12px;
+  font-size: 12px;
+}
+</style>

+ 77 - 4
src/views/project-manage/components/person-cost.vue

@@ -1,5 +1,15 @@
 <template>
   <div>
+    <div style="margin-top: 6px;">
+      <el-form :inline="true">
+        <el-form-item label="研发项目名称">
+          <project-select v-model="params.xmId" @change="handleProjectChange"></project-select>
+        </el-form-item>
+        <el-form-item label="研发项目编号">
+          {{ selProject.xmbh }}
+        </el-form-item>
+      </el-form>
+    </div>
     <avue-crud
       ref="crud"
       v-bind="bindVal"
@@ -7,7 +17,6 @@
       v-model="form"
       :page.sync="page"
       :before-open="handleBeforeOpen"
-      :permission="permissionList"
     >
       <template slot="menuLeft">
         <el-button
@@ -41,6 +50,10 @@
         </el-button>
         <print-table-btn @click="printTable" />
       </template>
+
+      <template slot="technicianId" slot-scope="scope">
+        <span>{{ scope.row.name }}</span>
+      </template>
       
     </avue-crud>
 
@@ -60,24 +73,71 @@
 <script>
 import {exportBloByPost} from "@/api/common";
 import UploadExcelDialog from "@/components/upload-excel-dialog";
+import projectSelect from "@/components/project-select";
 import {getToken} from "@/util/auth";
 import {downloadXls} from "@/util/util";
+import Decimal from "decimal.js";
+import moment from "moment";
 
 
 export default window.$crudCommon({
+  props: {
+    projectId: [String, Number]
+  },
   components: {
+    projectSelect,
     UploadExcelDialog,
   },
   data() {
     return {
+      params: {
+        xmId: ''
+      },
+      selProject: {},
+
       wideTableColumns: [],
       printTitle: "",
+
     };
   },
   created() {
-    this.option.height = window.innerHeight - 270;
+    this.params.xmId = this.projectId;
+    this.option.height = window.innerHeight - 340;
+  },
+  watch: {
+    "params.xmId"() {
+      this.page.currentPage = 1;
+      this.getList(this.page);
+    }
   },
   methods: {
+    handleBeforeOpen(done, type) {
+      if (!this.params.xmId) {
+        this.$message.warning("请选择项目!");
+        return;
+      }
+      this.option.column.forEach(item => {
+        if (item.prop == "technicianId") {
+          let yearAndMonth = this.selProject.xmkssj || new Date();
+          item.dicUrl = '/api/kd-scientific/technician/page';
+          item.dicQuery.yearAndMonth = moment(yearAndMonth).format("yyyyMM");
+        }
+      });
+
+      done();
+    },
+    getList() {
+      if (!this.params.xmId) {
+        return;
+      }
+      this.loadData();
+    },
+    getFormData() {
+      return { ...this.form, xmId: this.params.xmId }
+    },
+    handleProjectChange(data) {
+      this.selProject = data;
+    },
     handleImport() {
       let excelParams = { yearAndMonth: this.params.yearAndMonth };
       this.$refs.uploadExcelDialog.open('/api/kd-scientific/ys-ryrgfy/import', excelParams);
@@ -88,7 +148,7 @@ export default window.$crudCommon({
     },
     handleExport() {
       exportBloByPost(`/api/kd-scientific/ys-ryrgfy/export?${this.website.tokenHeader}=${getToken()}`, this.params).then(res => {
-        downloadXls(res.data, `人员人工费用.xlsx`);
+        downloadXls(res.data, `${this.selProject.xmmc}人员人工费用.xlsx`);
       });
     },
     /**
@@ -97,7 +157,7 @@ export default window.$crudCommon({
      */
     printTable(isLandscape) {
       this.wideTableColumns = this.$refs.crud.columnOption;
-      this.printTitle = `人员人工费用`;
+      this.printTitle = `${this.selProject.xmmc}人员人工费用`;
       this.$nextTick(() => {
         this.$refs.printWideTable.printTable(isLandscape);
       })
@@ -107,6 +167,19 @@ export default window.$crudCommon({
   // 模块路径
   name: 'projectManage/personCost',
   res: ({ data }) => {
+    data.records = data.records.map(item => {
+      let zzsc = new Decimal(item.zzsc || 0);
+      let pjrgfy = new Decimal(item.pjrgfy || 0);
+
+      item.technicianId = item.technician.id;
+      item.name = item.technician.name;
+      item.number = item.technician.number;
+      item.identityCard = item.technician.identityCard;
+      item.pjrgfy = (item.pjrgfy || 0).toFixed(2);
+      item.total = zzsc.mul(pjrgfy).toFixed(2);
+      item.isWp = item.nature === '在职' ? '是' : '否';
+      return item;
+    });
     return data;
   },
 });

+ 24 - 17
src/views/project-manage/components/project-budget.vue

@@ -1,34 +1,37 @@
 <template>
   <el-tabs tab-position="left">
-    <el-tab-pane label="研发项目费用预算表格">用户管理</el-tab-pane>
-    <el-tab-pane label="一、人员人工费用">
-      <person-cost />
+    <el-tab-pane label="研发项目费用预算表格" lazy>
+      <all-budget-table :projectId="projectId"></all-budget-table>
     </el-tab-pane>
-    <el-tab-pane label="二、直接投入费用">
-      <zztl-cost></zztl-cost>
+    <el-tab-pane label="一、人员人工费用" lazy>
+      <person-cost :projectId="projectId" />
     </el-tab-pane>
-    <el-tab-pane label="三、折旧费用与长期待摊费用">
-      <zjfyycqdtfy-cost></zjfyycqdtfy-cost>
+    <el-tab-pane label="二、直接投入费用" lazy>
+      <zztl-cost :projectId="projectId"></zztl-cost>
     </el-tab-pane>
-    <el-tab-pane label="四、无形资产摊销费用">
-      <wxzctx-cost></wxzctx-cost>
+    <el-tab-pane label="三、折旧费用与长期待摊费用" lazy>
+      <zjfyycqdtfy-cost :projectId="projectId"></zjfyycqdtfy-cost>
     </el-tab-pane>
-    <el-tab-pane label="五、设计费用">
-      <design-cost></design-cost>
+    <el-tab-pane label="四、无形资产摊销费用" lazy>
+      <wxzctx-cost :projectId="projectId"></wxzctx-cost>
     </el-tab-pane>
-    <el-tab-pane label="六、装备调试费用与实验费用">
-      <zb-cost></zb-cost>
+    <el-tab-pane label="五、设计费用" lazy>
+      <design-cost :projectId="projectId"></design-cost>
     </el-tab-pane>
-    <el-tab-pane label="七、委托外部研究开发费">
-      <outsourcing-cost></outsourcing-cost>
+    <el-tab-pane label="六、装备调试费用与实验费用" lazy>
+      <zb-cost :projectId="projectId"></zb-cost>
     </el-tab-pane>
-    <el-tab-pane label="八、其他费用">
-      <other-cost></other-cost>
+    <el-tab-pane label="七、委托外部研究开发费" lazy>
+      <outsourcing-cost :projectId="projectId"></outsourcing-cost>
+    </el-tab-pane>
+    <el-tab-pane label="八、其他费用" lazy>
+      <other-cost :projectId="projectId"></other-cost>
     </el-tab-pane>
   </el-tabs>
 </template>
 
 <script>
+import allBudgetTable from './all-budget-table.vue';
 import personCost from './person-cost.vue';
 import zztlCost from './zztl-cost.vue';
 import zjfyycqdtfyCost from './zjfyycqdtfy-cost.vue';
@@ -39,7 +42,11 @@ import outsourcingCost from './outsourcing-cost.vue';
 import otherCost from './other-cost.vue';
 
 export default {
+  props: {
+    projectId: [String, Number]
+  },
   components: {
+    allBudgetTable,
     personCost,
     zztlCost,
     zjfyycqdtfyCost,

+ 106 - 15
src/views/project-manage/components/wxzctx-cost.vue

@@ -1,5 +1,15 @@
 <template>
   <div>
+    <div style="margin-top: 6px;">
+      <el-form :inline="true">
+        <el-form-item label="研发项目名称">
+          <project-select v-model="params.xmId" @change="handleProjectChange"></project-select>
+        </el-form-item>
+        <el-form-item label="研发项目编号">
+          {{ selProject.xmbh }}
+        </el-form-item>
+      </el-form>
+    </div>
     <avue-crud
       ref="crud"
       v-bind="bindVal"
@@ -7,7 +17,6 @@
       v-model="form"
       :page.sync="page"
       :before-open="handleBeforeOpen"
-      :permission="permissionList"
     >
       <template slot="menuLeft">
         <el-button
@@ -41,6 +50,10 @@
         </el-button>
         <print-table-btn @click="printTable" />
       </template>
+
+      <template slot="zcbm" slot-scope="scope">
+        <span>{{ scope.row.zcmc }}</span>
+      </template>
       
     </avue-crud>
 
@@ -60,49 +73,117 @@
 <script>
 import {exportBloByPost} from "@/api/common";
 import UploadExcelDialog from "@/components/upload-excel-dialog";
+import projectSelect from "@/components/project-select";
 import {getToken} from "@/util/auth";
 import {downloadXls} from "@/util/util";
+import moment from "moment";
+import Decimal from "decimal.js";
 
 
 export default window.$crudCommon({
+  props: {
+    projectId: [String, Number],
+  },
   components: {
     UploadExcelDialog,
+    projectSelect,
   },
   data() {
     return {
+      params: {
+        xmId: ''
+      },
+      selProject: {},
+
       wideTableColumns: [],
       printTitle: "",
+
+      currZcObj: {},
     };
   },
   created() {
-    this.option.height = window.innerHeight - 270;
+    this.params.xmId = this.projectId;
+    this.option.height = window.innerHeight - 340;
 
     let newOption = { ...this.option };
     // 姓名下拉框,设置监听事件
     newOption.column.forEach(item => {
-      if (item.prop == "zcmc") {
+      if (item.prop == "zcbm") {
         item.change = ({ item }) => {
           if (!!item) {
-            this.form = {
-              ...this.form,
-              ytxe: item.zcyz,
-            };
+            this.currZcObj = item;
           }
         }
       }
     });
     this.option = { ...newOption };
   },
+  watch: {
+    "params.xmId"() {
+      this.page.currentPage = 1;
+      this.getList(this.page);
+    },
+  },
   methods: {
-    handleBeforeOpen(done) {
-      this.option.column.forEach(item => {
-        if (item.prop == "zcmc") {
-          item.dicUrl = '/api/kd-scientific/zc/page';
-          item.dicQuery.yearAndMonth = '202507';
+    validCustom() {
+      const { sysm, ysysm } = this.currZcObj;
+      const { xmkssj, xmjssj } = this.selProject
+      let sm = sysm - ysysm;
+      if (this.form.zzsc > sm) {
+        this.$message.warning(`设备剩余寿命为${sm}月,在项目的工作时长不能大于设备寿命!`);
+        return false;
+      }
+
+      if (xmkssj && xmjssj) {
+        let monthDiff = moment(xmjssj).diff(moment(xmkssj), 'months', true).toFixed(0);
+        if (this.form.zzsc > monthDiff) {
+          this.$message.warning(`项目周期为${monthDiff}月,在项目的工作时长不能大于项目周期!`);
+          return false;
         }
-      });
+      }
+      return true;
+    },
+    addBefore(loading, callback) {
+      if (!this.validCustom()) {
+        loading();
+        return;
+      }
+      callback && callback();
+    },
+    updateBefore(loading, callback) {
+      if (!this.validCustom()) {
+        loading();
+        return false;
+      }
+      callback && callback();
+    },
+    handleBeforeOpen(done) {
+      if (!this.params.xmId) {
+        this.$message.warning("请选择项目!");
+        return;
+      }
+      this.currZcObj = {};
+      // this.option.column.forEach(item => {
+      //   let yearAndMonth = this.selProject.xmkssj || new Date();
+      //   if (item.prop == "zcbm") {
+      //     item.dicUrl = '/api/kd-scientific/zc/simple/list';
+      //     item.dicQuery.yearAndMonth = moment(yearAndMonth).format("yyyyMM");
+      //   }
+      // });
       done();
     },
+    getList() {
+      if (!this.params.xmId) {
+        return;
+      }
+      this.loadData();
+    },
+    getFormData() {
+      return { ...this.form, xmId: this.params.xmId }
+    },
+    handleProjectChange(data) {
+      this.selProject = data;
+    },
     handleImport() {
       this.$refs.uploadExcelDialog.open('/api/kd-scientific/ys-wxzctxfy/import');
     },
@@ -112,7 +193,7 @@ export default window.$crudCommon({
     },
     handleExport() {
       exportBloByPost(`/api/kd-scientific/ys-wxzctxfy/export?${this.website.tokenHeader}=${getToken()}`, this.params).then(res => {
-        downloadXls(res.data, `无形资产摊销费用.xlsx`);
+        downloadXls(res.data, `${this.selProject.xmmc}无形资产摊销费用.xlsx`);
       });
     },
     /**
@@ -121,7 +202,7 @@ export default window.$crudCommon({
      */
     printTable(isLandscape) {
       this.wideTableColumns = this.$refs.crud.columnOption;
-      this.printTitle = `无形资产摊销费用`;
+      this.printTitle = `${this.selProject.xmmc}无形资产摊销费用`;
       this.$nextTick(() => {
         this.$refs.printWideTable.printTable(isLandscape);
       })
@@ -131,6 +212,16 @@ export default window.$crudCommon({
   // 模块路径
   name: 'projectManage/wxzctxCost',
   res: ({ data }) => {
+    data.records = data.records.map(item => {
+      item.zcmc = item.zcEntity ? item.zcEntity.zcmc : '';
+      item.zcbm = item.zcEntity ? item.zcEntity.zcbm : '';
+      item.ytxe = (item.zcEntity ? item.zcEntity.yzje : 0).toFixed(2);
+
+      let zzscD = new Decimal(item.zzsc || 0); // 工作时长
+      let yzjeD = new Decimal(item.ytxe || 0); // 摊销额
+      item.yshj = zzscD.mul(yzjeD).toFixed(2);
+      return item;
+    });
     return data;
   },
 });

+ 55 - 4
src/views/project-manage/components/zb-cost.vue

@@ -1,5 +1,16 @@
 <template>
   <div>
+    <div style="margin-top: 6px;">
+      <el-form :inline="true">
+        <el-form-item label="研发项目名称">
+          <project-select v-model="params.xmId" @change="handleProjectChange"></project-select>
+        </el-form-item>
+        <el-form-item label="研发项目编号">
+          {{ selProject.xmbh }}
+        </el-form-item>
+      </el-form>
+    </div>
+
     <avue-crud
       ref="crud"
       v-bind="bindVal"
@@ -7,7 +18,6 @@
       v-model="form"
       :page.sync="page"
       :before-open="handleBeforeOpen"
-      :permission="permissionList"
     >
       <template slot="menuLeft">
         <el-button
@@ -60,24 +70,61 @@
 <script>
 import {exportBloByPost} from "@/api/common";
 import UploadExcelDialog from "@/components/upload-excel-dialog";
+import projectSelect from "@/components/project-select";
 import {getToken} from "@/util/auth";
 import {downloadXls} from "@/util/util";
 
 
 export default window.$crudCommon({
+  props: {
+    projectId: [String, Number]
+  },
   components: {
     UploadExcelDialog,
+    projectSelect,
   },
   data() {
     return {
+      params: {
+        xmId: ''
+      },
+      selProject: {},
+
       wideTableColumns: [],
       printTitle: "",
     };
   },
+  watch: {
+    "params.xmId"() {
+      this.page.currentPage = 1;
+      this.getList(this.page);
+    },
+  },
   created() {
-    this.option.height = window.innerHeight - 270;
+    this.params.xmId = this.projectId;
+    this.option.height = window.innerHeight - 340;
   },
   methods: {
+    handleBeforeOpen(done, type) {
+      if (!this.params.xmId) {
+        this.$message.warning("请选择项目!");
+        return;
+      }
+
+      done();
+    },
+    getList() {
+      if (!this.params.xmId) {
+        return;
+      }
+      this.loadData();
+    },
+    getFormData() {
+      return { ...this.form, xmId: this.params.xmId }
+    },
+    handleProjectChange(data) {
+      this.selProject = data;
+    },
     handleImport() {
       this.$refs.uploadExcelDialog.open('/api/kd-scientific/ys-zbtsysyfy/import');
     },
@@ -87,7 +134,7 @@ export default window.$crudCommon({
     },
     handleExport() {
       exportBloByPost(`/api/kd-scientific/ys-zbtsysyfy/export?${this.website.tokenHeader}=${getToken()}`, this.params).then(res => {
-        downloadXls(res.data, `装备调试费用与试验费用.xlsx`);
+        downloadXls(res.data, `${this.selProject.xmmc}装备调试费用与试验费用.xlsx`);
       });
     },
     /**
@@ -96,7 +143,7 @@ export default window.$crudCommon({
      */
     printTable(isLandscape) {
       this.wideTableColumns = this.$refs.crud.columnOption;
-      this.printTitle = `装备调试费用与试验费用`;
+      this.printTitle = `${this.selProject.xmmc}装备调试费用与试验费用`
       this.$nextTick(() => {
         this.$refs.printWideTable.printTable(isLandscape);
       })
@@ -106,6 +153,10 @@ export default window.$crudCommon({
   // 模块路径
   name: 'projectManage/zbCost',
   res: ({ data }) => {
+    data.records = data.records.map(item => {
+      item.ysje = (item.ysje || 0).toFixed(2);
+      return item;
+    });
     return data;
   },
 });

+ 107 - 15
src/views/project-manage/components/zjfyycqdtfy-cost.vue

@@ -1,5 +1,15 @@
 <template>
   <div>
+    <div style="margin-top: 6px;">
+      <el-form :inline="true">
+        <el-form-item label="研发项目名称">
+          <project-select v-model="params.xmId" @change="handleProjectChange"></project-select>
+        </el-form-item>
+        <el-form-item label="研发项目编号">
+          {{ selProject.xmbh }}
+        </el-form-item>
+      </el-form>
+    </div>
     <avue-crud
       ref="crud"
       v-bind="bindVal"
@@ -7,7 +17,6 @@
       v-model="form"
       :page.sync="page"
       :before-open="handleBeforeOpen"
-      :permission="permissionList"
     >
       <template slot="menuLeft">
         <el-button
@@ -41,6 +50,10 @@
         </el-button>
         <print-table-btn @click="printTable" />
       </template>
+
+      <template slot="zcbm" slot-scope="scope">
+        <span>{{ scope.row.zcmc }}</span>
+      </template>
       
     </avue-crud>
 
@@ -60,33 +73,51 @@
 <script>
 import {exportBloByPost} from "@/api/common";
 import UploadExcelDialog from "@/components/upload-excel-dialog";
+import projectSelect from "@/components/project-select";
 import {getToken} from "@/util/auth";
 import {downloadXls} from "@/util/util";
+import moment from "moment";
+import Decimal from "decimal.js";
 
 
 export default window.$crudCommon({
+  props: {
+    projectId: [String, Number]
+  },
   components: {
     UploadExcelDialog,
+    projectSelect,
   },
   data() {
     return {
+      params: {
+        xmId: ''
+      },
+      selProject: {},
+
       wideTableColumns: [],
       printTitle: "",
+
+      currZcObj: {},
     };
   },
+  watch: {
+    "params.xmId"() {
+      this.page.currentPage = 1;
+      this.getList(this.page);
+    },
+  },
   created() {
-    this.option.height = window.innerHeight - 270;
+    this.params.xmId = this.projectId;
+    this.option.height = window.innerHeight - 340;
 
     let newOption = { ...this.option };
     // 姓名下拉框,设置监听事件
     newOption.column.forEach(item => {
-      if (item.prop == "zcmc") {
+      if (item.prop == "zcbm") {
         item.change = ({ item }) => {
           if (!!item) {
-            this.form = {
-              ...this.form,
-              ytxe: item.zcyz,
-            };
+            this.currZcObj = item;
           }
         }
       }
@@ -94,15 +125,65 @@ export default window.$crudCommon({
     this.option = { ...newOption };
   },
   methods: {
-    handleBeforeOpen(done) {
-      this.option.column.forEach(item => {
-        if (item.prop == "zcmc") {
-          item.dicUrl = '/api/kd-scientific/zc/page';
-          item.dicQuery.yearAndMonth = '202507';
+    validCustom() {
+      const { sysm, ysysm } = this.currZcObj;
+      const { xmkssj, xmjssj } = this.selProject
+      let sm = sysm - ysysm;
+      if (this.form.zzsc > sm) {
+        this.$message.warning(`设备剩余寿命为${sm}月,在项目的工作时长不能大于设备寿命!`);
+        return false;
+      }
+
+      if (xmkssj && xmjssj) {
+        let monthDiff = moment(xmjssj).diff(moment(xmkssj), 'months', true).toFixed(0);
+        if (this.form.zzsc > monthDiff) {
+          this.$message.warning(`项目周期为${monthDiff}月,在项目的工作时长不能大于项目周期!`);
+          return false;
         }
-      });
+      }
+      return true;
+    },
+    addBefore(loading, callback) {
+      if (!this.validCustom()) {
+        loading();
+        return;
+      }
+      callback && callback();
+    },
+    updateBefore(loading, callback) {
+      if (!this.validCustom()) {
+        loading();
+        return false;
+      }
+      callback && callback();
+    },
+    handleBeforeOpen(done) {
+      if (!this.params.xmId) {
+        this.$message.warning("请选择项目!");
+        return;
+      }
+      this.currZcObj = {};
+      // this.option.column.forEach(item => {
+      //   let yearAndMonth = this.selProject.xmkssj || new Date();
+      //   if (item.prop == "zcbm") {
+      //     item.dicUrl = '/api/kd-scientific/zc/simple/list';
+      //     item.dicQuery.yearAndMonth = moment(yearAndMonth).format("yyyyMM");
+      //   }
+      // });
       done();
     },
+    getList() {
+      if (!this.params.xmId) {
+        return;
+      }
+      this.loadData();
+    },
+    getFormData() {
+      return { ...this.form, xmId: this.params.xmId }
+    },
+    handleProjectChange(data) {
+      this.selProject = data;
+    },
     handleImport() {
       this.$refs.uploadExcelDialog.open('/api/kd-scientific/ys-zjfyycqdtfy/import');
     },
@@ -112,7 +193,7 @@ export default window.$crudCommon({
     },
     handleExport() {
       exportBloByPost(`/api/kd-scientific/ys-zjfyycqdtfy/export?${this.website.tokenHeader}=${getToken()}`, this.params).then(res => {
-        downloadXls(res.data, `折旧费用与长期待摊费用.xlsx`);
+        downloadXls(res.data, `${this.selProject.xmmc}折旧费用与长期待摊费用.xlsx`);
       });
     },
     /**
@@ -121,7 +202,7 @@ export default window.$crudCommon({
      */
     printTable(isLandscape) {
       this.wideTableColumns = this.$refs.crud.columnOption;
-      this.printTitle = `折旧费用与长期待摊费用`;
+      this.printTitle = `${this.selProject.xmmc}折旧费用与长期待摊费用`;
       this.$nextTick(() => {
         this.$refs.printWideTable.printTable(isLandscape);
       })
@@ -131,6 +212,17 @@ export default window.$crudCommon({
   // 模块路径
   name: 'projectManage/zjfyycqdtfyCost',
   res: ({ data }) => {
+    data.records = data.records.map(item => {
+      item.zcmc = item.zcEntity.zcmc;
+      item.zcbm = item.zcEntity.zcbm;
+      item.yzje = (item.zcEntity.yzje || 0).toFixed(2);
+      item.cqdtfyysje = (item.cqdtfyysje || 0).toFixed(2);
+
+      let zzscD = new Decimal(item.zzsc || 0); // 工作时长
+      let yzjeD = new Decimal(item.yzje || 0);
+      item.yshj = zzscD.mul(yzjeD).toFixed(2);
+      return item;
+    });
     return data;
   },
 });

+ 65 - 4
src/views/project-manage/components/zztl-cost.vue

@@ -1,12 +1,21 @@
 <template>
   <div>
+    <div style="margin-top: 6px;">
+      <el-form :inline="true">
+        <el-form-item label="研发项目名称">
+          <project-select v-model="params.xmId" @change="handleProjectChange"></project-select>
+        </el-form-item>
+        <el-form-item label="研发项目编号">
+          {{ selProject.xmbh }}
+        </el-form-item>
+      </el-form>
+    </div>
     <avue-crud
       v-bind="bindVal"
       v-on="onEvent"
       v-model="form"
       :page.sync="page"
       :before-open="handleBeforeOpen"
-      :permission="permissionList"
     >
       <template slot="menuLeft">
         <el-button
@@ -59,24 +68,62 @@
 <script>
 import {exportBloByPost} from "@/api/common";
 import UploadExcelDialog from "@/components/upload-excel-dialog";
+import projectSelect from "@/components/project-select";
 import {getToken} from "@/util/auth";
 import {downloadXls} from "@/util/util";
+import Decimal from "decimal.js";
 
 
 export default window.$crudCommon({
+  props: {
+    projectId: [String, Number]
+  },
   components: {
     UploadExcelDialog,
+    projectSelect,
   },
   data() {
     return {
+      params: {
+        xmId: ''
+      },
+      selProject: {},
+
       wideTableColumns: [],
       printTitle: "",
     };
   },
+  watch: {
+    "params.xmId"() {
+      this.page.currentPage = 1;
+      this.getList(this.page);
+    },
+  },
   created() {
-    this.option.height = window.innerHeight - 270;
+    this.params.xmId = this.projectId;
+    this.option.height = window.innerHeight - 340;
   },
   methods: {
+    handleBeforeOpen(done, type) {
+      if (!this.params.xmId) {
+        this.$message.warning("请选择项目!");
+        return;
+      }
+
+      done();
+    },
+    getList() {
+      if (!this.params.xmId) {
+        return;
+      }
+      this.loadData();
+    },
+    getFormData() {
+      return { ...this.form, xmId: this.params.xmId }
+    },
+    handleProjectChange(data) {
+      this.selProject = data;
+    },
     handleImport() {
       let excelParams = { yearAndMonth: this.params.yearAndMonth };
       this.$refs.uploadExcelDialog.open('/api/kd-scientific/ys-zjtrfy/import', excelParams);
@@ -87,7 +134,7 @@ export default window.$crudCommon({
     },
     handleExport() {
       exportBloByPost(`/api/kd-scientific/ys-zjtrfy/export?${this.website.tokenHeader}=${getToken()}`, this.params).then(res => {
-        downloadXls(res.data, `人员人工费用.xlsx`);
+        downloadXls(res.data, `${this.selProject.xmmc}直接投入费用.xlsx`);
       });
     },
     /**
@@ -96,7 +143,7 @@ export default window.$crudCommon({
      */
     printTable(isLandscape) {
       this.wideTableColumns = this.$refs.crud.columnOption;
-      this.printTitle = `直接投入费用`;
+      this.printTitle = `${this.selProject.xmmc}直接投入费用`;
       this.$nextTick(() => {
         this.$refs.printWideTable.printTable(isLandscape);
       })
@@ -106,6 +153,20 @@ export default window.$crudCommon({
   // 模块路径
   name: 'projectManage/zztlCost',
   res: ({ data }) => {
+
+    data.records = data.records.map(item => {
+      item.yongLiang = item.yongLiang === -1 ? '' : (item.yongLiang).toFixed(2);
+      item.danJia = item.danJia === -1 ? '' : (item.danJia).toFixed(2);
+      item.ysje = item.ysje === -1 ? '' : (item.ysje).toFixed(2);
+      item.zlfyys = item.zlfyys === -1 ? '' : (item.zlfyys).toFixed(2);
+
+      if (item.yongLiang && item.danJia) {
+        item.wzysje = new Decimal(item.yongLiang).mul(item.danJia);
+      }
+
+      return item;
+    });
+
     return data;
   },
 });

+ 8 - 2
src/views/project-manage/ky-budget.vue

@@ -1,9 +1,15 @@
 <template>
-  <div>研发项目经费预算表</div>
+  <basic-container>
+    <project-budget></project-budget>
+  </basic-container>
 </template>
 
 <script>
+import projectBudget from './components/project-budget.vue'
+
 export default {
-  
+  components: {
+    projectBudget
+  }
 }
 </script>

+ 7 - 2
src/views/project-manage/outsourcing.vue

@@ -1,9 +1,14 @@
 <template>
-  <div>委外项目</div>
+  <basic-container>
+    <outsourcing-doc></outsourcing-doc>
+  </basic-container>
 </template>
 
 <script>
+import outsourcingDoc from './components/outsourcing-doc.vue';
 export default {
-  
+  components: {
+    outsourcingDoc
+  }
 }
 </script>

+ 29 - 13
src/views/project-manage/project-list.vue

@@ -7,6 +7,7 @@
       :page.sync="page"
       :before-open="handleBeforeOpen"
       :permission="permissionList"
+      @row-dblclick="handleRowDbClick"
     >
       <template slot="menuLeft">
         <el-button
@@ -49,26 +50,29 @@
       title="项目信息"
       modal-append-to-body
       append-to-body
-      size="1200px"
+      size="1280px"
+      destroy-on-close
     >
       <el-tabs type="border-card">
-        <el-tab-pane label="1、项目立项">
-          <apply-form></apply-form>
+        <el-tab-pane label="1、项目立项" lazy>
+          <apply-form :projectId="currProjectId" @success="handleApplySuccess"></apply-form>
         </el-tab-pane>
-        <el-tab-pane label="2、科研预算">
-          <project-budget></project-budget>
+        <el-tab-pane label="2、科研预算" lazy>
+          <project-budget :projectId="currProjectId"></project-budget>
         </el-tab-pane>
-        <el-tab-pane label="3、项目实施">
-          <implement-form></implement-form>
+        <el-tab-pane label="3、项目实施" lazy>
+          <implement-form :projectId="currProjectId" :yearAndMonth="params.yearAndMonth"></implement-form>
         </el-tab-pane>
-        <el-tab-pane label="4、项目变更">
-          <change></change>
+        <el-tab-pane label="4、项目变更" lazy>
+          <change :projectId="currProjectId"></change>
         </el-tab-pane>
-        <el-tab-pane label="5、项目结题">
-          <accept-form></accept-form>
+        <el-tab-pane label="5、项目结题" lazy>
+          <accept-form :projectId="currProjectId"></accept-form>
+        </el-tab-pane>
+        <el-tab-pane label="6、项目成果" lazy></el-tab-pane>
+        <el-tab-pane label="7、委外材料" lazy>
+          <outsourcing-doc :projectId="currProjectId"></outsourcing-doc>
         </el-tab-pane>
-        <el-tab-pane label="6、项目成果"></el-tab-pane>
-        <el-tab-pane label="7、委外材料"></el-tab-pane>
       </el-tabs>
     </el-drawer>
   </basic-container>
@@ -85,6 +89,7 @@ import projectBudget from "./components/project-budget.vue";
 import implementForm from './components/implement-form.vue';
 import change from "./change.vue";
 import acceptForm from "./components/accept-form.vue";
+import outsourcingDoc from "./components/outsourcing-doc.vue";
 
 
 export default window.$crudCommon({
@@ -95,6 +100,7 @@ export default window.$crudCommon({
     implementForm,
     change,
     acceptForm,
+    outsourcingDoc,
   },
   data() {
     return {
@@ -106,6 +112,8 @@ export default window.$crudCommon({
       printTitle: "",
 
       drawerVisible: false,
+
+      currProjectId: '',
     };
   },
   watch: {
@@ -116,8 +124,16 @@ export default window.$crudCommon({
   },
   methods: {
     handleCreateClick() {
+      this.currProjectId = '';
       this.drawerVisible = true;
     },
+    handleRowDbClick(data) {
+      this.currProjectId = data.id;
+      this.drawerVisible = true;
+    },
+    handleApplySuccess({ xmId }) {
+      this.currProjectId = xmId;
+    },
     handleExport() {
       exportBloByPost(`/api/kd-scientific/technician/export?${this.website.tokenHeader}=${getToken()}`, this.params).then(res => {
         downloadXls(res.data, `科研项目汇总表${this.params.yearAndMonth}.xlsx`);