Prechádzať zdrojové kódy

Merge branch 'develop' into prod

scorpio 2 rokov pred
rodič
commit
4369a85b14
48 zmenil súbory, kde vykonal 3746 pridanie a 81 odobranie
  1. 5 0
      .eslintrc.cjs
  2. 6 0
      index.html
  3. 2 0
      package.json
  4. 3 0
      src/App.vue
  5. 6 0
      src/api/common.js
  6. 2 2
      src/api/dash/index.js
  7. 12 0
      src/api/fetch.js
  8. 27 0
      src/api/funds/index.js
  9. 2 0
      src/api/index.js
  10. 83 0
      src/api/project/index.js
  11. 5 0
      src/assets/style/main.scss
  12. 73 0
      src/components/area-picker/index.vue
  13. 41 13
      src/components/filepicker/index.vue
  14. 67 0
      src/components/industry-picker/index.vue
  15. 5 3
      src/components/tips-custom/index.vue
  16. 51 0
      src/components/wt-card/index.vue
  17. 8 1
      src/layout/index.vue
  18. 2 0
      src/layout/top.vue
  19. 2 0
      src/router/index.js
  20. 84 0
      src/utils/crypto.js
  21. 54 0
      src/utils/watermark.js
  22. 3 3
      src/views/contract/component/info.vue
  23. 8 4
      src/views/contract/index.vue
  24. 6 1
      src/views/dash/compoents/profile.vue
  25. 32 7
      src/views/dash/compoents/read.vue
  26. 209 0
      src/views/funds/component/info.vue
  27. 49 0
      src/views/funds/detail.vue
  28. 20 30
      src/views/home/component/dash.vue
  29. 0 1
      src/views/home/component/params/params1.vue
  30. 1 1
      src/views/home/component/params/params7.vue
  31. 1 1
      src/views/home/project.vue
  32. 81 0
      src/views/project/componens/approval.vue
  33. 398 0
      src/views/project/componens/info1.vue
  34. 250 0
      src/views/project/componens/info2.vue
  35. 201 0
      src/views/project/componens/info3.vue
  36. 342 0
      src/views/project/componens/info4.vue
  37. 95 0
      src/views/project/componens/info5.vue
  38. 297 0
      src/views/project/componens/info6.vue
  39. 400 0
      src/views/project/componens/info7.vue
  40. 90 0
      src/views/project/componens/info8.vue
  41. 299 0
      src/views/project/componens/map-picker.vue
  42. 84 0
      src/views/project/componens/top.vue
  43. 296 0
      src/views/project/index.vue
  44. 15 5
      src/views/resource/component/preview.vue
  45. 5 2
      src/views/resource/component/row1.vue
  46. 10 6
      src/views/resource/index.vue
  47. 4 1
      src/views/task/component/task-table.vue
  48. 10 0
      yarn.lock

+ 5 - 0
.eslintrc.cjs

@@ -8,6 +8,11 @@ module.exports = {
     ecmaVersion: 'latest',
     sourceType: 'module'
   },
+  globals:{
+    AMap:true,
+    AMapUI:true,
+    Local:true
+  },
   plugins: ['vue', 'prettier'],
   rules: {
     'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',

+ 6 - 0
index.html

@@ -5,6 +5,12 @@
     <link rel="icon" type="image/svg+xml" href="/icon.svg" />
     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
     <title>梧桐树项目云</title>
+      <script type="text/javascript">
+          window._AMapSecurityConfig = {
+              serviceHost:'https://dev.wutongshucloud.com/_AMapService',
+          }
+      </script>
+      <script type="text/javascript" src='https://webapi.amap.com/maps?v=2.0&key=6577c6fd4841e6c69d5fb1bd15bd4696&"'></script>
   </head>
   <body style='background-color: #f6f7f8'>
     <div id="app"></div>

+ 2 - 0
package.json

@@ -9,8 +9,10 @@
     "preview": "vite preview"
   },
   "dependencies": {
+    "@amap/amap-jsapi-loader": "^1.0.1",
     "@element-plus/icons-vue": "^2.0.6",
     "@smallwei/avue": "^3.2.5",
+    "crypto-js": "^4.1.1",
     "dateformat": "^5.0.3",
     "echarts": "^5.4.1",
     "element-plus": "^2.2.9",

+ 3 - 0
src/App.vue

@@ -65,14 +65,17 @@ export default {
 #app {
   background-color: #f6f7f8;
   overflow: hidden;
+
   .single {
     height: 100%;
   }
 }
+
 :deep(.el-main) {
   --el-main-padding: 0 !important;
   padding: 0 !important;
 }
+
 :deep(.el-header) {
   padding: 0 !important;
 }

+ 6 - 0
src/api/common.js

@@ -8,6 +8,12 @@ export default {
       ...params
     })
   },
+  dicChildList(params) {
+    return fetch('/blade-system/dict-biz/dictionary-tree', {
+      clientId: website.clientId,
+      ...params
+    })
+  },
   submit(params) {
     // 保存上传文件素材
     return fetch('/wutong-library/library/save', params, 'post', 'json')

+ 2 - 2
src/api/dash/index.js

@@ -31,11 +31,11 @@ export default {
   },
 
   /**
-   * 公众号文章
+   * 推荐阅读文章
    * @returns {Promise<unknown>}
    */
   mpList() {
-    return fetch('/blade-project-manage-v2/index/v2/v2/mp-list')
+    return fetch('/blade-pc-applet/wechat/home/getHomeRecommendedList')
   },
   /**
    * 头像更新

+ 12 - 0
src/api/fetch.js

@@ -5,6 +5,8 @@ import axios from './axios.js'
 import router from '../router'
 import { getToken, removeToken } from '../utils/auth'
 import { ElMessage } from 'element-plus'
+import crypto from '@/utils/crypto'
+import website from '@/config/website.js'
 
 axios.defaults.baseURL = ''
 
@@ -28,6 +30,11 @@ axios.interceptors.request.use(
 )
 
 // insurance 保险 502 503 504时兜底的
+const desUrl =
+  website.baseUrl.indexOf('https://prod') > -1
+    ? ['blade-pc-applet']
+    : ['blade-pc-applet']
+console.log(website.baseUrl)
 function fetch(
   url = '',
   params = {},
@@ -69,6 +76,11 @@ function fetch(
       }
     }
     const success = response => {
+      // const tmps = desUrl.filter(e => url.indexOf(e) > -1)
+      // if (tmps.length > 0) {
+      //   response = JSON.parse(crypto.decryptDES(response, crypto.desKey))
+      //   console.log(response)
+      // }
       const { status, data = {}, statusText } = response
       if (status >= 200 && status <= 401) {
         if (data.code === 401 || data.code === 400) {

+ 27 - 0
src/api/funds/index.js

@@ -0,0 +1,27 @@
+import fetch from '../fetch.js'
+
+export default {
+  /**
+   * 资金列表
+   * @param params
+   */
+  fundsList(params) {
+    return fetch(
+      '/blade-project-manage-v2/project-dispatch/v2/project-basic-investment-list',
+      params,
+      'get'
+    )
+  },
+  /**
+   * 新增到位资金
+   * @param params
+   */
+  fundsSaveOrUpdate(params) {
+    return fetch(
+      '/blade-project-manage-v2/project-dispatch/v2/submit-project-basic-investment',
+      params,
+      'post',
+      'json'
+    )
+  }
+}

+ 2 - 0
src/api/index.js

@@ -14,6 +14,7 @@ import dispatch from './dispatch/index.js'
 import store from './store/index.js'
 import msg from './msg/index.js'
 import contract from '@/api/contract/index.js'
+import funds from '@/api/funds/index.js'
 import role from '@/api/role/index.js'
 import resource from '@/api/resource/index.js'
 import dash from '@/api/dash/index.js'
@@ -37,6 +38,7 @@ export default {
   store,
   msg,
   contract,
+  funds,
   role,
   resource,
   dash

+ 83 - 0
src/api/project/index.js

@@ -111,6 +111,10 @@ export default {
     // 单个项目包含阶段
     return fetch('/blade-project-manage-v2/stage/v2/projectStages', params)
   },
+  changeStage(params) {
+    // 切换阶段保存
+    return fetch('/blade-project-manage-v2/folder/change-stage', params)
+  },
   folderList(params) {
     // 阶段包含文件夹列表
     return fetch(
@@ -285,6 +289,14 @@ export default {
       'post'
     )
   },
+  /**
+   * 更新下一个阶段
+   * @param params
+   * @returns {Promise<unknown>}
+   */
+  updateCurrentStage(params) {
+    return fetch('/blade-project-manage-v2/stage/v2/next-stage', params)
+  },
   /**
    * 管理员审批项目
    */
@@ -359,6 +371,77 @@ export default {
       params,
       'post'
     )
+  },
+  // 获取项目年度投资
+  projectAnnualInvestment(params) {
+    return fetch(
+      '/blade-project-manage-v2/project-dispatch/v2/project-annual-investment',
+      params
+    )
+  },
+  // 新增或修改年度投资
+  submitAnnualInvestment(params) {
+    return fetch(
+      '/blade-project-manage-v2/project-dispatch/v2/submit-annual-investment',
+      params,
+      'post',
+      'json'
+    )
+  },
+  // 新增或修改年度投资
+  batchSubmitAnnualInvestment(params) {
+    return fetch(
+      '/blade-project-manage-v2/project-dispatch/v2/batch-submit-annual-investment',
+      params,
+      'post',
+      'json'
+    )
+  },
+  // 项目前期文件列表
+  preliminaryFiles(params) {
+    return fetch(
+      '/blade-project-manage-v2/project-dispatch/v2/situation-file-list',
+      params
+    )
+  },
+  // 添加项目前期文件
+  preliminaryFilesAdd(params) {
+    return fetch(
+      '/blade-project-manage-v2/project-dispatch/v2/situation-save-file',
+      params,
+      'post',
+      'json'
+    )
+  },
+  // 删除项目前期文件
+  preliminaryFilesRemove(params) {
+    return fetch(
+      '/blade-project-manage-v2/project-dispatch/v2/situation-delete-file',
+      params,
+      'post'
+    )
+  },
+  /**
+   * 项目照片
+   */
+  addPhotoProject(params) {
+    return fetch(
+      '/blade-project-manage-v2/project-dispatch/v2/save-project-address-pic',
+      params,
+      'post',
+      'json'
+    )
+  },
+  /**
+   * 获取项目地址相关照片
+   * @param params
+   * @returns {Promise | Promise<unknown>}
+   */
+  photoProject(params) {
+    return fetch(
+      '/blade-project-manage-v2/project-dispatch/v2/project-address-pic-list',
+      params
+    )
   }
 }
 

+ 5 - 0
src/assets/style/main.scss

@@ -331,6 +331,11 @@ img {
   font-weight: bold;
 }
 
+
+.bold-500 {
+  font-weight: 500;
+}
+
 .radius-5 {
   border-radius: 5px;
 }

+ 73 - 0
src/components/area-picker/index.vue

@@ -0,0 +1,73 @@
+<template>
+  <div class="full-width">
+    <div>
+      <el-cascader
+        :placeholder="placeholder"
+        clearable
+        class="full-width"
+        v-model="area"
+        :options="areaDic"
+        filterable
+        @change="changeArea"
+      />
+    </div>
+  </div>
+</template>
+<script>
+export default {
+  props: {
+    placeholder: {
+      type: String,
+      default: ''
+    }
+  },
+  data() {
+    return {
+      form: {},
+      areaDic: [],
+      area: ''
+    }
+  },
+  mounted() {
+    this.getArea()
+  },
+  methods: {
+    getArea() {
+      const tmp = localStorage.getItem('area')
+      if (tmp) {
+        this.areaDic = JSON.parse(tmp)
+        return
+      }
+      this.$api.common.region({ code: '' }).then(res => {
+        if (res.code === 200) {
+          const list = res.data.filter(ele => ele.key !== '111111')
+          this.areaDic = list.map(item => this.mapTree(item))
+          localStorage.setItem('area', JSON.stringify(this.areaDic))
+        }
+      })
+    },
+    mapTree(item) {
+      const haveChildren =
+        Array.isArray(item.children) && item.children.length > 0
+      return {
+        key: item,
+        value: item,
+        label: item.title,
+        children: haveChildren ? item.children.map(i => this.mapTree(i)) : []
+      }
+    },
+    changeArea(res) {
+      const tmps = res.map(ele => {
+        return { key: ele.key, title: ele.title }
+      })
+      this.$emit('change', tmps)
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+:deep(.el-input) {
+  width: 100%;
+}
+</style>

+ 41 - 13
src/components/filepicker/index.vue

@@ -9,8 +9,8 @@
         @click="show = true"
         >上传
       </el-button>
-      <el-button v-else type="primary" icon="Upload" @click="show = true"
-        >文件上传
+      <el-button v-else type="primary" icon="Plus" @click="show = true"
+        >{{ btnText }}
       </el-button>
     </div>
     <el-dropdown v-else class="ml-10" @command="commandChange">
@@ -98,18 +98,42 @@
             <el-tab-pane label="合同" name="4"></el-tab-pane>
           </el-tabs>
           <div class="area">
-            <div class="full-width flex flex-center flex-justify-start ml-20">
-              <file-way
+            <div class="full-width ml-20">
+              <div
                 v-if="activeName === '2'"
-                :next="currentRow ? currentRow : ''"
-                @before="goBefore"
-                @goHome="getHome"
-              />
-              <div class="tips flex flex-center flex-justify-start" v-else>
-                <el-icon class="mr-10" color="#409eff" :size="20">
-                  <WarningFilled />
-                </el-icon>
-                {{ tips }}
+                class="flex flex-center flex-justify-between flex-col full-width"
+              >
+                <div
+                  class="tips flex flex-center flex-justify-start mb-10"
+                  v-if="list.length === 0"
+                >
+                  <el-icon class="mr-10" color="#409eff" :size="20">
+                    <WarningFilled />
+                  </el-icon>
+                  当前阶段下暂无文件夹,请点击 资料管理
+                  进行创建文件夹并上传相关文件
+                </div>
+                <div class="flex flex-center flex-justify-between full-width">
+                  <file-way
+                    :next="currentRow ? currentRow : ''"
+                    @before="goBefore"
+                    @goHome="getHome"
+                  />
+                  <el-button
+                    text
+                    type="primary"
+                    @click="
+                      $router.push({
+                        path: '/resource',
+                        query: { id: projectId }
+                      })
+                    "
+                    >资料管理
+                    <el-icon class="ml-10">
+                      <ArrowRight />
+                    </el-icon>
+                  </el-button>
+                </div>
               </div>
             </div>
             <div class="files full-height">
@@ -155,6 +179,10 @@ export default {
     fileWay
   },
   props: {
+    btnText: {
+      type: Boolean,
+      default: '上传文件'
+    },
     projectId: {
       required: true,
       type: String,

+ 67 - 0
src/components/industry-picker/index.vue

@@ -0,0 +1,67 @@
+<template>
+  <div class="full-width">
+    <el-cascader
+      :placeholder="placeholder"
+      clearable
+      class="full-width"
+      v-model="industry"
+      :options="industryList"
+      filterable
+      @change="change"
+    />
+  </div>
+</template>
+
+<script>
+export default {
+  props: {
+    placeholder: {
+      type: String,
+      default: ''
+    }
+  },
+  data() {
+    return {
+      industry: '',
+      industryList: []
+    }
+  },
+  mounted() {
+    this.getList()
+  },
+  methods: {
+    getList() {
+      this.$api.common
+        .dicChildList({ code: 'industry-classification' })
+        .then(res => {
+          if (res.code === 200) {
+            this.industryList = res.data.map(item => this.mapTree(item))
+          }
+        })
+    },
+    mapTree(item) {
+      const haveChildren =
+        Array.isArray(item.children) && item.children.length > 0
+      return {
+        key: item,
+        value: item,
+        label: item.dictValue,
+        children: haveChildren ? item.children.map(i => this.mapTree(i)) : []
+      }
+    },
+    change(res) {
+      const tmps = res.map(ele => {
+        return {
+          id: ele.id,
+          title: ele.dictValue,
+          value: ele.dictKey,
+          code: ele.code
+        }
+      })
+      this.$emit('change', tmps)
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped></style>

+ 5 - 3
src/components/tips-custom/index.vue

@@ -13,9 +13,11 @@
         @click="$router.back()"
         v-if="nav.menus[nav.menus.length - 1].meta.back !== undefined"
       ></el-button>
-      <span class="ml-10 tools font-24">{{
-        nav.menus[nav.menus.length - 1].name
-      }}</span>
+      <slot name="title">
+        <span class="ml-10 tools font-24">{{
+          nav.menus[nav.menus.length - 1].name
+        }}</span>
+      </slot>
     </div>
     <slot />
   </div>

+ 51 - 0
src/components/wt-card/index.vue

@@ -0,0 +1,51 @@
+<template>
+  <el-card shadow="hover">
+    <div class="flex flex-justify-between flex-center mb-10">
+      <div class="font-16 bold-500 flex-justify-start flex">
+        {{ title }}
+      </div>
+      <el-button
+        type="primary"
+        icon="Edit"
+        v-if="editBtn"
+        size="small"
+        @click="change"
+        >{{ btnText }}</el-button
+      >
+    </div>
+    <el-divider />
+    <slot></slot>
+  </el-card>
+</template>
+
+<script>
+export default {
+  props: {
+    title: {
+      type: String,
+      default: ''
+    },
+    editBtn: {
+      type: Boolean,
+      default: false
+    }
+  },
+  data() {
+    return {
+      btnText: '编 辑'
+    }
+  },
+  methods: {
+    change() {
+      if (this.btnText === '保 存') {
+        this.$emit('save')
+      }
+      console.log('fff')
+      this.btnText = this.btnText === '编 辑' ? '保 存' : '编 辑'
+      this.$emit('edit', this.btnText === '编 辑')
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped></style>

+ 8 - 1
src/layout/index.vue

@@ -1,5 +1,9 @@
 <template>
-  <div class="flex flex-justify-start full-screen" @scroll="scroll">
+  <div
+    class="flex flex-justify-start full-screen"
+    v-watermark="text"
+    @scroll="scroll"
+  >
     <el-container>
       <el-header class="header">
         <top @openMenu="show = true" />
@@ -149,6 +153,7 @@ export default {
 .wt-main {
   background-color: #f6f7f8;
   overflow-x: hidden;
+
   .mp {
     top: 200px;
     right: 0;
@@ -161,9 +166,11 @@ export default {
     box-shadow: -1px 0px 1px 1px rgba(51, 51, 51, 0.05098);
   }
 }
+
 .icon {
   width: 140px;
 }
+
 .content {
   overflow-y: scroll;
   height: calc(100vh - 80px);

+ 2 - 0
src/layout/top.vue

@@ -92,6 +92,7 @@ import { useStore } from '../store/user.js'
 import permissionStore from '@/store/permission.js'
 import search from './search/index.vue'
 import config from '../config/website.js'
+import { setWaterMark } from '@/utils/watermark.js'
 
 export default {
   name: 'top',
@@ -269,6 +270,7 @@ export default {
     start() {
       // 开启心跳
       console.log('开启心跳')
+      setWaterMark(this.user.info.deptName, this.user.info.nickName)
       const self = this
       self.timeoutObj && clearTimeout(self.timeoutObj)
       self.serverTimeoutObj && clearTimeout(self.serverTimeoutObj)

+ 2 - 0
src/router/index.js

@@ -4,6 +4,7 @@ import navStore from '../store/nav.js'
 import keepAliveStore from '../store/keepAlive.js'
 import generatedRoutes from '~pages'
 import { setupLayouts } from 'layouts-generated'
+import { removeWatermark } from '@/utils/watermark.js'
 
 // 导出路由
 const routes = setupLayouts(generatedRoutes)
@@ -23,6 +24,7 @@ router.beforeEach((to, from, next) => {
     keepAlive.add(to.name) // 将路由名称添加到 keepAlive 集合中
   }
   if (to.path === '/') {
+    removeWatermark()
     const menu = { active: 0, subActive: 0 }
     localStorage.setItem('index', JSON.stringify(menu))
     localStorage.setItem('data-type', 'project')

+ 84 - 0
src/utils/crypto.js

@@ -0,0 +1,84 @@
+import CryptoJS from 'crypto-js'
+
+export default class crypto {
+  // 使用AesUtil.genAesKey()生成,需和后端配置保持一致
+  static aesKey = 'uQFw4pOEtPdzU4LP3ywbaUtoGMHywnUi'
+
+  // 使用DesUtil.genDesKey()生成,需和后端配置保持一致
+  static desKey = 'XHHUNdnCka60Y5zJ'
+
+  /**
+   * aes 加密方法
+   * @param data
+   * @returns {*}
+   */
+  static encrypt(data) {
+    return this.encryptAES(data, this.aesKey)
+  }
+
+  /**
+   * aes 解密方法
+   * @param data
+   * @returns {*}
+   */
+  static decrypt(data) {
+    return this.decryptAES(data, this.aesKey)
+  }
+
+  /**
+   * aes 加密方法,同java:AesUtil.encryptToBase64(text, aesKey);
+   */
+  static encryptAES(data, key) {
+    const dataBytes = CryptoJS.enc.Utf8.parse(data)
+    const keyBytes = CryptoJS.enc.Utf8.parse(key)
+    const encrypted = CryptoJS.AES.encrypt(dataBytes, keyBytes, {
+      iv: keyBytes,
+      mode: CryptoJS.mode.CBC,
+      padding: CryptoJS.pad.Pkcs7
+    })
+    return CryptoJS.enc.Base64.stringify(encrypted.ciphertext)
+  }
+
+  /**
+   * aes 解密方法,同java:AesUtil.decryptFormBase64ToString(encrypt, aesKey);
+   */
+  static decryptAES(data, key) {
+    const keyBytes = CryptoJS.enc.Utf8.parse(key)
+    const decrypted = CryptoJS.AES.decrypt(data, keyBytes, {
+      iv: keyBytes,
+      mode: CryptoJS.mode.CBC,
+      padding: CryptoJS.pad.Pkcs7
+    })
+    return CryptoJS.enc.Utf8.stringify(decrypted)
+  }
+
+  /**
+   * des 加密方法,同java:DesUtil.encryptToBase64(text, desKey)
+   */
+  static encryptDES(data, key) {
+    const keyHex = CryptoJS.enc.Utf8.parse(key)
+    const encrypted = CryptoJS.DES.encrypt(data, keyHex, {
+      mode: CryptoJS.mode.ECB,
+      padding: CryptoJS.pad.Pkcs7
+    })
+    return encrypted.toString()
+  }
+
+  /**
+   * des 解密方法,同java:DesUtil.decryptFormBase64(encryptBase64, desKey);
+   */
+  static decryptDES(data, key) {
+    const keyHex = CryptoJS.enc.Utf8.parse(key)
+    const decrypted = CryptoJS.DES.decrypt(
+      {
+        ciphertext: CryptoJS.enc.Base64.parse(data)
+      },
+      keyHex,
+      {
+        mode: CryptoJS.mode.ECB,
+        padding: CryptoJS.pad.Pkcs7
+      }
+    )
+    return decrypted.toString(CryptoJS.enc.Utf8)
+  }
+}

+ 54 - 0
src/utils/watermark.js

@@ -0,0 +1,54 @@
+/**  水印添加方法  */
+
+const setWatermark = (str1, str2) => {
+  const id = '1.23452384164.123412415'
+
+  if (document.getElementById(id) !== null) {
+    document.body.removeChild(document.getElementById(id))
+  }
+
+  const can = document.createElement('canvas')
+  // 设置canvas画布大小
+  can.width = 420
+  can.height = 180
+
+  const cans = can.getContext('2d')
+  cans.rotate((-22.5 * Math.PI) / 180) // 水印旋转角度
+  cans.font = '15px Vedana'
+  cans.fillStyle = '#666666'
+  cans.textAlign = 'center'
+  cans.textBaseline = 'Middle'
+  cans.fillText(str1, can.width / 2, can.height) // 水印在画布的位置x,y轴
+  cans.fillText(str2, can.width / 2, can.height + 22)
+
+  const div = document.createElement('div')
+  div.id = id
+  div.style.pointerEvents = 'none'
+  div.style.top = '40px'
+  div.style.left = '0px'
+  div.style.opacity = '0.15'
+  div.style.position = 'fixed'
+  div.style.zIndex = '100000'
+  div.style.width = document.documentElement.clientWidth + 'px'
+  div.style.height = document.documentElement.clientHeight + 'px'
+  div.style.background =
+    'url(' + can.toDataURL('image/png') + ') left top repeat'
+  document.body.appendChild(div)
+  return id
+}
+
+// 添加水印方法
+export const setWaterMark = (str1, str2) => {
+  let id = setWatermark(str1, str2)
+  if (document.getElementById(id) === null) {
+    id = setWatermark(str1, str2)
+  }
+}
+
+// 移除水印方法
+export const removeWatermark = () => {
+  const id = '1.23452384164.123412415'
+  if (document.getElementById(id) !== null) {
+    document.body.removeChild(document.getElementById(id))
+  }
+}

+ 3 - 3
src/views/contract/component/info.vue

@@ -7,8 +7,8 @@
           >{{ disabled ? '编 辑' : '保 存' }}
         </el-button>
         <el-button type="primary" plain @click="libraryDetail">
-          查 看</el-button
-        >
+          查 看
+        </el-button>
       </div>
     </div>
     <div class="padding">
@@ -20,7 +20,7 @@
       >
         <div class="full-width flex flex-center flex-justify-between">
           <el-form-item label="合同名称" class="flex-child-average">
-            <el-input v-if="form.fileFolder" v-model="form.fileFolder.title" />
+            <el-input v-if="form" v-model="form.title" />
           </el-form-item>
           <el-form-item label="合同类别" class="flex-child-average">
             <el-input v-model="form.type" />

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

@@ -54,7 +54,11 @@
       <template #menu-left>
         <div class="flex flex-center">
           <div class="main-color ml-10 mr-20 bold font-15">金额单位:万元</div>
-          <filepicker :project-id="projectId" @submit="selection" />
+          <filepicker
+            btn-text="新增合同"
+            :project-id="projectId"
+            @submit="selection"
+          />
         </div>
       </template>
     </avue-crud>
@@ -128,12 +132,12 @@ export default {
           {
             label: '签订日期',
             prop: 'signTime',
-            width: 100
+            width: 110
           },
           {
             label: '合同状态',
             prop: 'contractsStatus',
-            width: 100,
+            width: 90,
             dicUrl:
               '/api/blade-system/dict-biz/dictionary?code=contract-status',
             props: {
@@ -144,7 +148,7 @@ export default {
           {
             label: '到期日期',
             prop: 'expireTime',
-            width: 100
+            width: 110
           }
         ]
       },

+ 6 - 1
src/views/dash/compoents/profile.vue

@@ -4,7 +4,12 @@
       <div class="bold font-16" style="margin-top: -10px">我的信息</div>
       <div class="mt-10 ml-20" @click="show = true">
         <el-avatar :src="user.info.avatarUrl" :size="100"></el-avatar>
-        <el-icon :size="25" style="margin-left: -30px">
+        <el-icon
+          :size="25"
+          style="margin-left: -20px"
+          color="gray"
+          class="pointer"
+        >
           <EditPen />
         </el-icon>
       </div>

+ 32 - 7
src/views/dash/compoents/read.vue

@@ -4,15 +4,21 @@
     <div class="flex flex-center">
       <div class="flex flex-center ml-10" style="flex: 5">
         <div
-          class="flex flex-col flex-center border radius box-shadow mr-15 mt-15"
+          class="flex flex-col flex-center flex-justify-start border radius box-shadow mr-15 mt-15 item"
           v-for="item in data"
+          :key="item.id"
         >
           <div>
-            <img :src="item.thumb_url" style="width: 50px; height: 120px" />
+            <img class="img" :src="item.defaultImg" />
           </div>
-          <div class="bold padding">{{ item.author }}</div>
-          <div class="lines-2 lines-height-15 grey-9 padding">
-            文章内容文章内容文章内容文章内容文章内容文章内容
+          <div
+            class="lines-2 overflow-hide title lines-height-15 grey-9 padding"
+          >
+            <preview :id="item.fileId">
+              <template #title>
+                {{ item.title }}
+              </template>
+            </preview>
           </div>
         </div>
       </div>
@@ -31,8 +37,11 @@
 </template>
 
 <script>
+import Preview from '@/views/resource/component/preview.vue'
+
 export default {
   name: 'read',
+  components: { Preview },
   data() {
     return {
       data: []
@@ -45,7 +54,7 @@ export default {
     getList() {
       this.$api.dash.mpList().then(res => {
         if (res.code === 200) {
-          // this.data = res.data[0].content
+          this.data = res.data.records
         } else {
           console.log(res)
         }
@@ -55,4 +64,20 @@ export default {
 }
 </script>
 
-<style scoped></style>
+<style scoped>
+.item {
+  width: 260px;
+}
+
+.img {
+  border-top-right-radius: 8px;
+  border-top-left-radius: 8px;
+  width: 260px;
+  height: 180px;
+  object-fit: cover;
+}
+.title {
+  height: 30px;
+  margin-bottom: 10px;
+}
+</style>

+ 209 - 0
src/views/funds/component/info.vue

@@ -0,0 +1,209 @@
+<template>
+  <div>
+    <div
+      class="padding top flex flex-center flex-justify-between ml-20 mr-20 mt-20"
+    >
+      <span>到位资金记录(单位:万元)</span>
+    </div>
+    <div class="ml-20 mr-20 mt-20">
+      <avue-crud
+        :option="option"
+        :data="data"
+        ref="crud"
+        v-model="form"
+        @row-save="handleRowSave"
+        @row-update="rowUpdate"
+        @on-load="onLoad"
+      >
+        <template #fileIds-form="{ row, type }">
+          <div v-if="type === 'view'">
+            <div
+              v-for="i in form.accountInformationFileList"
+              :key="i.id"
+              class="pointer"
+            >
+              {{ i.title }}
+              <el-button text type="primary" plain>查看</el-button>
+            </div>
+          </div>
+          <div v-else-if="type === 'edit'">
+            <div
+              v-if="
+                form.accountInformationFileList &&
+                form.accountInformationFileList.length === 0
+              "
+            >
+              <div>
+                <div v-for="item in fileList" :key="item.id">
+                  {{ item.title }}
+                </div>
+              </div>
+            </div>
+          </div>
+          <div v-else>
+            <div v-for="item in fileList" :key="item.id">
+              {{ item.title }}
+            </div>
+            <div>
+              <div v-for="item in fileList" :key="item.id">
+                {{ item.originalFileName }}
+              </div>
+            </div>
+          </div>
+        </template>
+      </avue-crud>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'info',
+  components: {},
+  props: {
+    info: {
+      type: Object,
+      default: null
+    }
+  },
+  data() {
+    return {
+      id: '',
+      preList: [],
+      show: false,
+      fileList: [],
+      form: {},
+      data: [],
+      option: {
+        align: 'center',
+        menuAlign: 'center',
+        menuWidth: 180,
+        height: 480,
+        size: 'mini',
+        addBtn: true,
+        editBtn: true,
+        viewBtn: true,
+        delBtn: false,
+        refreshBtn: false,
+        columnBtn: false,
+        labelWidth: 240,
+        border: true,
+        column: [
+          {
+            label: '中央预算内投资',
+            prop: 'investmentOfCentralBudget',
+            type: 'number',
+            width: 150,
+            slot: true
+          },
+          {
+            label: '银行贷款',
+            prop: 'bankLoans',
+            type: 'number',
+            width: 150
+          },
+          {
+            label: '专项债券资金',
+            prop: 'specialBondFunds',
+            type: 'number',
+            width: 150
+          },
+          {
+            label: '抗疫特别国债资金',
+            prop: 'antiEpidemicSpecialTreasuryBondFund',
+            type: 'number',
+            width: 150
+          },
+          {
+            label: '其他地方财政性建设基金',
+            prop: 'otherLocalFiscalConstructionFunds',
+            type: 'number',
+            width: 150
+          },
+          {
+            label: '政策性开发金融工具(基金)投资',
+            prop: 'policyBasedDevelopmentFinancialInvestment',
+            type: 'number',
+            width: 150
+          },
+          {
+            label: '省级预算内投资',
+            prop: 'investmentWithinProvincialBudget',
+            type: 'number',
+            width: 150
+          },
+          {
+            label: '市级预算内投资',
+            prop: 'investmentWithinMunicipalBudget',
+            type: 'number',
+            width: 150
+          },
+          {
+            label: '县级预算内投资',
+            prop: 'investmentWithinCountyLevelBudget',
+            type: 'number',
+            width: 150,
+            slot: true
+          }
+        ]
+      }
+    }
+  },
+  created() {
+    this.id = this.$route.query.id
+  },
+  methods: {
+    onLoad() {
+      this.$api.funds.fundsList({ projectId: this.id }).then(res => {
+        if (res.code === 200) {
+          this.data = res.data
+        }
+      })
+    },
+
+    rowUpdate(row, index, done, loading) {
+      loading()
+      const data = Object.assign(this.form, { projectId: this.id })
+      this.$api.funds.fundsSaveOrUpdate(data).then(
+        res => {
+          if (res.code === 200) {
+            this.$message.success(res.msg)
+          } else {
+            this.$message.error(res.msg)
+          }
+          done(row)
+          this.onLoad()
+        },
+        error => {
+          window.console.log(error)
+          loading()
+        }
+      )
+    },
+    handleRowSave(row, done, loading) {
+      loading()
+      const data = Object.assign(row, { projectId: this.id })
+      this.$confirm('请检查并确认所填写内容是否正确!', {
+        type: 'warning'
+      }).then(res => {
+        if (res === 'confirm') {
+          this.$api.funds.fundsSaveOrUpdate(data).then(res => {
+            if (res.code === 200) {
+              done(row)
+              this.onLoad()
+            }
+          })
+        }
+      })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.top {
+  height: 35px;
+  border-radius: var(--el-card-border-radius);
+  background-color: #f5f5f3;
+}
+</style>

+ 49 - 0
src/views/funds/detail.vue

@@ -0,0 +1,49 @@
+<template>
+  <div>
+    <el-card
+      shadow="hover"
+      class="mb-20"
+      style="height: 630px; padding: 0; width: 99%"
+    >
+      <info :project-id="id" :info="detail"></info>
+    </el-card>
+  </div>
+</template>
+<route>
+{
+name: '到位资金详情',
+meta: { layout: 'empty'}
+}
+</route>
+<script>
+import info from '@/views/funds/component/info.vue'
+
+export default {
+  components: { info },
+  data() {
+    return {
+      id: '',
+      detail: null
+    }
+  },
+  created() {
+    this.id = this.$route.query.id
+    // this.getFundsList()
+  },
+  methods: {
+    // getFundsList() {
+    //   this.$api.funds.fundsList({ project: this.id }).then(res => {
+    //     if (res.code === 200) {
+    //       this.detail = res.data
+    //     }
+    //   })
+    // }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+:deep(.el-card) {
+  --el-card-padding: 0 !important;
+}
+</style>

+ 20 - 30
src/views/home/component/dash.vue

@@ -186,7 +186,15 @@
           </div>
         </div>
       </template>
-
+      <template #dict_key="{ row }">
+        <el-tag>
+          {{
+            typeof row.dict_key === 'object'
+              ? row.dict_key.map(ele => ele.title).join('/')
+              : ''
+          }}
+        </el-tag>
+      </template>
       <template #plan_commencement_time-header="{ column }">
         <div class="flex flex-center">
           <div class="mr-5">{{ (column || {}).label }}</div>
@@ -307,20 +315,8 @@
                 />
               </el-select>
             </el-form-item>
-            <el-form-item class="full-width" label="行业分类" prop="tags">
-              <el-select
-                v-model="projectForm.dictKey"
-                clearable
-                placeholder="选择行业分类"
-                style="width: 100%"
-              >
-                <el-option
-                  v-for="item in industryList"
-                  :key="item.dictKey"
-                  :label="item.dictValue"
-                  :value="item.dictKey"
-                />
-              </el-select>
+            <el-form-item class="full-width" label="所属行业" prop="dictKey">
+              <industry-picker @change="changeIndustry" />
             </el-form-item>
             <el-form-item class="full-width" label="建设内容">
               <el-input
@@ -411,10 +407,11 @@ import summaryDialog from '@/views/home/component/summary_dialog.vue'
 import { useStore } from '@/store/user.js'
 import confing from '@/config/website'
 import { ElMessageBox } from 'element-plus'
+import industryPicker from '@/components/industry-picker/index.vue'
 
 export default {
   name: 'dash',
-  components: { BaseButton, formDialog, summaryDialog },
+  components: { BaseButton, formDialog, summaryDialog, industryPicker },
   setup() {
     const permissions = permissionStore()
     const user = useStore()
@@ -502,13 +499,8 @@ export default {
           {
             label: '行业分类',
             prop: 'dict_key',
-            width: 120,
-            dicUrl:
-              '/api/blade-system/dict-biz/dictionary?code=industry-classification',
-            props: {
-              label: 'dictValue',
-              value: 'dictKey'
-            }
+            width: 200,
+            slot: true
           },
           {
             label: '是否入库',
@@ -561,11 +553,6 @@ export default {
             prop: 'report_time',
             width: 120
           },
-          {
-            label: '认定时间',
-            prop: 'year',
-            width: 120
-          },
           {
             label: '项目状态',
             prop: 'report_type',
@@ -711,8 +698,8 @@ export default {
         window.open(routeData.href, '_blank')
       } else if (type === 'view') {
         const routeData = this.$router.resolve({
-          path: '/home/pro_detail',
-          query: { id: this.form.id, projectStage: this.form.project_stage }
+          path: '/project',
+          query: { id: this.form.id }
         })
         window.open(routeData.href, '_blank')
       }
@@ -1047,6 +1034,9 @@ export default {
       if (tmp) {
         this.projectForm.createDept = tmp.id
       }
+    },
+    changeIndustry(list) {
+      this.projectForm.dictKey = list
     }
   }
 }

+ 0 - 1
src/views/home/component/params/params1.vue

@@ -436,7 +436,6 @@ export default {
             if (tmp) {
               this.form.dict_value = tmp.dictValue
             }
-            console.log(tmp)
           }
         })
     },

+ 1 - 1
src/views/home/component/params/params7.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="flex flex-center flex-col">
-    <!-- title and btn -->
+    <!-- wt-card and btn -->
     <div class="flex flex-center full-width flex-justify-between mt-10 mb-10">
       <span class="full-width text-left bold"
         >{{ info.dictValue }}(单位:万元)</span

+ 1 - 1
src/views/home/project.vue

@@ -15,7 +15,7 @@
 
 <route>
 {
-path: '/project',
+path: '/projects',
 name: '项目管理',
 meta: {keepAlive: true,show: false}
 }

+ 81 - 0
src/views/project/componens/approval.vue

@@ -0,0 +1,81 @@
+<template>
+  <div>
+    <!--    项目审批-->
+    <el-dialog v-model="showDialog" title="审核" width="500px">
+      <div class="flex flex-justify-start flex-col">
+        <div class="full-width flex flex-justify-start flex-align-center mb-20">
+          <span>审核状态:</span>
+          <el-radio-group v-model="approvalStatus">
+            <el-radio :label="3">通过</el-radio>
+            <el-radio :label="4">不通过</el-radio>
+          </el-radio-group>
+        </div>
+        <el-input
+          class="mt-20"
+          type="textarea"
+          :rows="5"
+          v-model="approvalMsg"
+          placeholder="请填写审核意见"
+        />
+        <div class="full-width flex flex-justify-end mt-20">
+          <el-button plain type="primary" @click="showDialog = false"
+            >取消
+          </el-button>
+          <el-button type="primary" @click="projectApproval">确定</el-button>
+        </div>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+export default {
+  props: {
+    projectId: {
+      type: String,
+      default: ''
+    }
+  },
+  data() {
+    return {
+      showDialog: false,
+      approvalMsg: '',
+      approvalStatus: 3
+    }
+  },
+  methods: {
+    show() {
+      this.showDialog = true
+    },
+    /**
+     * 管理员审批项目
+     * approvalStatus === 4 审核不通过,需要填写原因
+     */
+    projectApproval() {
+      if (this.approvalStatus === 4 && this.approvalMsg.length === 0) {
+        this.$message.error('请填写审核意见')
+        return
+      }
+      this.showDialog = false
+      this.$api.project
+        .approvalProject({
+          id: this.projectId,
+          reportType: this.approvalStatus,
+          receiptMsg: this.approvalMsg
+        })
+        .then(res => {
+          if (res.code === 200) {
+            this.$message.success(res.msg)
+            this.approvalStatus = 3
+            this.approvalMsg = ''
+            this.$emit('success')
+          } else {
+            this.$message.error(res.msg)
+          }
+        })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped></style>

+ 398 - 0
src/views/project/componens/info1.vue

@@ -0,0 +1,398 @@
+<template>
+  <wt-card
+    title="基础信息"
+    :edit-btn="form.can_update"
+    @edit="change"
+    @save="save"
+  >
+    <el-form class="mt-20" :disabled="disabled">
+      <div class="flex flex-justify-center" v-watermark="{ text: '33' }">
+        <el-form-item class="full-width flex-child-average">
+          <div class="flex flex-center full-width item">
+            <span class="title">项目名称:</span>
+            <el-input
+              placeholder="请输入项目名称"
+              v-model="form.name"
+            ></el-input>
+          </div>
+        </el-form-item>
+        <el-form-item class="full-width flex-child-average">
+          <div class="flex flex-center full-width item">
+            <span class="title">总投资金额:</span>
+            <el-input
+              placeholder="请输入总投资金额"
+              v-model="form.total_amount"
+            >
+              <template #append>万元</template>
+            </el-input>
+          </div>
+        </el-form-item>
+        <el-form-item class="full-width flex-child-average">
+          <div class="flex flex-center full-width item">
+            <span class="title">地区:</span>
+            <area-picker
+              :placeholder="
+                form.province_name !== undefined
+                  ? form.province_name +
+                    '/' +
+                    form.city_name +
+                    '/' +
+                    form.district_name
+                  : ''
+              "
+              @change="changeArea"
+            />
+          </div>
+        </el-form-item>
+      </div>
+      <div class="flex flex-justify-center">
+        <el-form-item class="full-width flex-child-average">
+          <div class="flex flex-center full-width item">
+            <span class="title">主管单位:</span>
+            <el-select
+              v-model="form.competent_unit"
+              placeholder="请选择项目标签"
+              class="full-width"
+            >
+              <el-option
+                v-for="item in deptDic"
+                :key="item.value"
+                :label="item.label"
+                :value="item.value"
+              />
+            </el-select>
+          </div>
+        </el-form-item>
+        <el-form-item class="full-width flex-child-average">
+          <div class="flex flex-center full-width item">
+            <span class="title">责任单位:</span>
+            <el-select
+              v-model="form.responsible_unit"
+              placeholder="请选择责任单位"
+              class="full-width"
+            >
+              <el-option
+                v-for="item in form.tags === 1 ? deptDic : compDic"
+                :key="item.value"
+                :label="item.label"
+                :value="item.value"
+              />
+            </el-select>
+          </div>
+        </el-form-item>
+        <el-form-item class="full-width flex-child-average">
+          <div class="flex flex-center full-width item">
+            <span class="title">责任领导:</span>
+            <el-input
+              placeholder="请输入责任领导"
+              v-model="form.responsible_leader"
+            ></el-input>
+          </div>
+        </el-form-item>
+      </div>
+      <div class="flex flex-justify-center">
+        <el-form-item class="full-width flex-child-average">
+          <div class="flex flex-center full-width item">
+            <span class="title">联系电话:</span>
+            <el-input
+              placeholder="请输入责任领导联系电话"
+              v-model="form.responsible_leader_phone"
+            ></el-input>
+          </div>
+        </el-form-item>
+        <el-form-item class="full-width flex-child-average">
+          <div class="flex flex-center full-width item">
+            <span class="title">所属行业:</span>
+            <industry-picker
+              :placeholder="
+                form.dict_key && typeof form.dict_key === 'object'
+                  ? form.dict_key.map(ele => ele.title).join('/')
+                  : ''
+              "
+              @change="changeIndustry"
+            />
+          </div>
+        </el-form-item>
+        <el-form-item class="full-width flex-child-average">
+          <div class="flex flex-center full-width item">
+            <span class="title">产业项目:</span>
+            <el-select
+              v-model="form.industrial_investment"
+              placeholder="是否是产业项目"
+              class="full-width"
+            >
+              <el-option
+                v-for="item in yesOrNo"
+                :key="item.label"
+                :label="item.label"
+                :value="item.value"
+              />
+            </el-select>
+          </div>
+        </el-form-item>
+      </div>
+      <div class="flex flex-justify-center">
+        <el-form-item class="full-width flex-child-average">
+          <div class="flex flex-center full-width item">
+            <span class="title">民间投资项目:</span>
+            <el-select
+              v-model="form.social_investment"
+              placeholder="是否民间投资项目"
+              class="full-width"
+            >
+              <el-option
+                v-for="item in yesOrNo"
+                :key="item.label"
+                :label="item.label"
+                :value="item.value"
+              />
+            </el-select>
+          </div>
+        </el-form-item>
+        <el-form-item class="full-width flex-child-average">
+          <div class="flex flex-center full-width item">
+            <span class="title">获得资金支持:</span>
+            <el-select
+              v-model="form.is_funded_project"
+              placeholder="是否获得资金支持"
+              class="full-width"
+            >
+              <el-option
+                v-for="item in yesOrNo"
+                :key="item.label"
+                :label="item.label"
+                :value="item.value"
+              />
+            </el-select>
+          </div>
+        </el-form-item>
+        <el-form-item class="full-width flex-child-average">
+          <div class="flex flex-center full-width item">
+            <span class="title">项目标签:</span>
+            <el-select
+              v-model="form.project_stage"
+              placeholder="请选择项目标签"
+              class="full-width"
+            >
+              <el-option
+                v-for="item in projectSituation"
+                :key="item.dictValue"
+                :label="item.dictValue"
+                :value="item.dictKey"
+              />
+            </el-select>
+          </div>
+        </el-form-item>
+      </div>
+      <div class="flex flex-justify-center">
+        <el-form-item class="full-width" style="flex: 2">
+          <div
+            class="flex flex-center flex-justify-start full-width"
+            style="width: 99%"
+          >
+            <span style="width: 100px" class="text-left">项目位置:</span>
+            <div class="full-width">
+              <map-picker
+                :project-id="form.id"
+                :address="form.address"
+                :lat-lng="[form.latitude, form.longitude]"
+                @success="mapSuccess"
+              />
+            </div>
+          </div>
+        </el-form-item>
+      </div>
+      <div class="flex flex-justify-center">
+        <el-form-item class="full-width" style="flex: 1">
+          <div
+            class="flex flex-center flex-align-start full-width"
+            style="width: 99.3%"
+          >
+            <span class="title-textarea">建设规模:</span>
+            <el-input
+              type="textarea"
+              placeholder="请输入建设规模(250 个字以内)"
+              v-model="form.construction_scale"
+              :rows="5"
+            ></el-input>
+          </div>
+        </el-form-item>
+      </div>
+      <div class="flex flex-justify-center">
+        <el-form-item class="full-width" style="flex: 1">
+          <div
+            class="flex flex-center flex-align-start full-width"
+            style="width: 99.3%"
+          >
+            <span class="title-textarea">建设内容:</span>
+            <el-input
+              type="textarea"
+              placeholder="请输入建设内容(250 个字以内)"
+              :maxlength="250"
+              :rows="5"
+              v-model="form.construction_content"
+            ></el-input>
+          </div>
+        </el-form-item>
+      </div>
+    </el-form>
+  </wt-card>
+</template>
+
+<script>
+import wtCard from '@/components/wt-card/index.vue'
+import areaPicker from '@/components/area-picker/index.vue'
+import mapPicker from '@/views/project/componens/map-picker.vue'
+import { useStore } from '@/store/user.js'
+import industryPicker from '@/components/industry-picker/index.vue'
+
+export default {
+  components: {
+    wtCard,
+    areaPicker,
+    mapPicker,
+    industryPicker
+  },
+  props: {
+    info: {
+      type: Object,
+      default: () => {
+        return {}
+      }
+    }
+  },
+  watch: {
+    info: {
+      handler(val) {
+        this.form = val
+        if (val.tags === 1) {
+          // 1 政府项目,主管单位和责任单位都为政府机构
+          this.getDepList()
+        } else {
+          // 2 企业项目,主管单位为机构,责任单位为企业
+          this.getDepList()
+          this.getCompList()
+        }
+        this.getDict('project-situation')
+      },
+      immediate: false
+    }
+  },
+  setup() {
+    const user = useStore()
+    return { user }
+  },
+  data() {
+    return {
+      disabled: true,
+      form: {},
+      photoList: [],
+      yesOrNo: [
+        {
+          label: '否',
+          value: 0
+        },
+        {
+          label: '是',
+          value: 1
+        }
+      ],
+      projectSituation: [],
+      deptDic: [],
+      compDic: []
+    }
+  },
+  methods: {
+    getDict(code) {
+      this.$api.common.dicList({ code }).then(res => {
+        if (res.code === 200) {
+          this.projectSituation = res.data.map(ele => {
+            ele.dictKey = Number.parseInt(ele.dictKey)
+            return ele
+          })
+        }
+      })
+    },
+    getDepList() {
+      const local = {
+        label: this.form.competent_unit_name,
+        value: this.form.competent_unit
+      }
+      this.deptDic.push(local)
+      this.$api.system
+        .getDeptLazy({ parentId: this.form.competent_unit, deptCategory: 3 })
+        .then(res => {
+          if (res.code === 200) {
+            const tmp = res.data.map(ele => {
+              const item = { label: ele.deptName, value: ele.id }
+              return item
+            })
+            this.deptDic = this.deptDic.concat(tmp)
+          }
+        })
+    },
+    getCompList() {
+      this.$api.system.getNewDeptLazy({ deptCategory: 4 }).then(res => {
+        if (res.code === 200) {
+          const tmp = res.data.map(ele => {
+            const item = { label: ele.deptName, value: ele.id }
+            return item
+          })
+          this.compDic = this.compDic.concat(tmp)
+        }
+      })
+    },
+    save() {
+      if (this.photoList.length > 0) {
+        this.$api.project.addPhotoProject(this.photoList).then(res => {
+          if (res.code === 200) {
+            console.log(res)
+          }
+        })
+      }
+      this.$api.project.proUpdate(this.form).then(res => {
+        if (res.code === 200) {
+          this.$message.success(res.msg)
+        }
+      })
+    },
+    change(res) {
+      this.disabled = res
+    },
+    changeArea(list) {
+      this.form.province_code = list[0].key
+      this.form.province_name = list[0].title
+      this.form.city_code = list[1].key
+      this.form.city_name = list[1].title
+      this.form.district_code = list[2].key
+      this.form.district_name = list[2].title
+    },
+    mapSuccess(res, list) {
+      this.form.address = res.address
+      this.form.longitude = res.longitude
+      this.form.latitude = res.latitude
+      this.photoList = list
+    },
+    changeIndustry(tmps) {
+      this.form.dict_key = tmps
+      this.$emit('industry', tmps[0])
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.title {
+  width: 120px;
+  text-align: left;
+}
+
+.title-textarea {
+  width: 100px;
+  text-align: left;
+}
+
+.item {
+  width: 98%;
+}
+</style>

+ 250 - 0
src/views/project/componens/info2.vue

@@ -0,0 +1,250 @@
+<template>
+  <wt-card title="前期情况" class="mt-10">
+    <div class="flex flex-justify-start full-width mt-15">
+      <avue-crud
+        :option="option"
+        :data="data"
+        ref="crud"
+        v-model="form"
+        v-model:page="page"
+        :before-open="beforeOpen"
+        @row-update="rowUpdate"
+        @row-del="rowDel"
+        @current-change="currentChange"
+        @size-change="sizeChange"
+        @refresh-change="refreshChange"
+      >
+        <template #menu="{ row }">
+          <div class="flex flex-center">
+            <preview :id="row.bladeFileId">
+              <template #title>
+                <el-button type="primary" text icon="View">查看</el-button>
+              </template>
+            </preview>
+            <el-button
+              type="primary"
+              text
+              icon="Delete"
+              @click="this.$refs.crud.rowDel(row)"
+              >删除</el-button
+            >
+          </div>
+        </template>
+        <template #menu-left>
+          <div class="flex flex-center">
+            <filepicker
+              :project-id="projectId"
+              :command="dictList"
+              @submit="selection"
+            />
+          </div>
+        </template>
+      </avue-crud>
+    </div>
+  </wt-card>
+</template>
+
+<script>
+import wtCard from '@/components/wt-card/index.vue'
+import filepicker from '@/components/filepicker/index.vue'
+import preview from '@/views/resource/component/preview.vue'
+
+export default {
+  components: { wtCard, filepicker, preview },
+  props: {
+    projectId: {
+      required: true,
+      type: String,
+      default: ''
+    },
+    stageId: {
+      required: true,
+      type: String,
+      default: ''
+    },
+    industry: {
+      type: String,
+      default: 'traffic'
+    }
+  },
+  watch: {
+    projectId: {
+      handler(val) {
+        if (val.length > 0) {
+          this.onLoad()
+        }
+      },
+      immediate: true
+    },
+    industry: {
+      handler(val) {
+        if (val.value === 'agriculture-forestry-water') {
+          this.getDic('agriculture-forestry-water')
+        } else {
+          this.getDic('traffic')
+        }
+      }
+    }
+  },
+  data() {
+    return {
+      form: {},
+      data: [],
+      option: {
+        align: 'center',
+        menuAlign: 'center',
+        menuWidth: 240,
+        size: 'mini',
+        addBtn: false,
+        editBtn: true,
+        editBtnText: '编辑文号',
+        viewBtn: false,
+        delBtn: false,
+        columnBtn: false,
+        labelWidth: 140,
+        border: true,
+        column: [
+          {
+            label: '文件名称',
+            prop: 'fileName',
+            fixed: true,
+            width: 400,
+            editDisplay: false
+          },
+          {
+            label: '文号',
+            prop: 'docNumber',
+            span: 16
+          },
+          {
+            label: '上传人',
+            prop: 'createUserName',
+            width: 120,
+            editDisplay: false
+          },
+          {
+            label: '上传时间',
+            prop: 'createDate',
+            editDisplay: false
+          }
+        ]
+      },
+      page: {
+        size: 10,
+        current: 1
+      },
+      dictList: []
+    }
+  },
+  created() {
+    this.getDic(this.industry.value)
+  },
+  methods: {
+    getDic(code) {
+      this.$api.common.dicList({ code }).then(res => {
+        if (res.code === 200) {
+          this.dictList = res.data.map(e => {
+            return { label: e.dictValue, value: e.dictKey, code }
+          })
+        }
+      })
+    },
+    onLoad() {
+      this.loading = true
+      const data = Object.assign({
+        projectId: this.projectId
+      })
+      this.$api.project
+        .preliminaryFiles(Object.assign(this.page, data))
+        .then(res => {
+          this.loading = false
+          if (res.code === 200) {
+            this.data = res.data.records
+            this.page.total = res.data.total
+          }
+        })
+    },
+    beforeOpen(done, type) {
+      if (type === 'edit') {
+        done()
+      }
+    },
+    rowUpdate(row, index, done, loading) {
+      console.log(row)
+      loading()
+      this.$api.common
+        .fileUpdate({ id: row.bladeFileId, copyNumber: row.docNumber })
+        .then(
+          res => {
+            if (res.code === 200) {
+              this.$message.success(res.msg)
+            } else {
+              this.$message.error(res.msg)
+            }
+            done(row)
+            this.onLoad()
+          },
+          error => {
+            window.console.log(error)
+            loading()
+          }
+        )
+    },
+    rowDel(row, index, done) {
+      this.$confirm('确定将选择数据删除?', {
+        type: 'warning'
+      }).then(res => {
+        if (res === 'confirm') {
+          this.$api.project
+            .preliminaryFilesRemove({ ids: row.id })
+            .then(res => {
+              if (res.code === 200) {
+                this.$message.success(res.msg)
+                this.onLoad()
+              } else {
+                this.$message.error(res.msg)
+              }
+            })
+        }
+      })
+    },
+    currentChange(currentPage) {
+      this.page.current = currentPage
+    },
+    sizeChange(pageSize) {
+      this.page.size = pageSize
+    },
+    refreshChange() {
+      this.onLoad()
+    },
+    selection(list, command, extra) {
+      console.log(command, extra)
+      const tmps = list.map(ele => {
+        return {
+          bladeFileId: ele.fileId,
+          projectId: ele.projectId,
+          fileId: ele.id,
+          dictKey: command.value,
+          code: command.code,
+          folderId: ele.parentId
+        }
+      })
+      this.$api.project.preliminaryFilesAdd(tmps).then(res => {
+        if (res.code === 200) {
+          this.refreshChange()
+        } else {
+          this.$message.error(res.msg)
+        }
+      })
+    },
+    moreContract() {
+      this.$router.push({
+        path: '/contract',
+        query: { id: this.projectId }
+      })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped></style>

+ 201 - 0
src/views/project/componens/info3.vue

@@ -0,0 +1,201 @@
+<template>
+  <wt-card title="相关合同" class="mt-10">
+    {{ form.can_update }}
+    <div
+      class="full-width text-right main-color pointer"
+      style="margin-top: -10px"
+      @click="moreContract"
+    >
+      查看更多>>
+    </div>
+    <div class="flex flex-justify-start full-width mt-15">
+      <avue-crud
+        :option="option"
+        :data="data"
+        ref="crud"
+        v-model="form"
+        :before-open="beforeOpen"
+        @row-del="rowDel"
+        @refresh-change="refreshChange"
+      >
+        <template #menu-left>
+          <div class="flex flex-center">
+            <filepicker
+              v-if="canEdit"
+              btn-text="新增合同"
+              :project-id="projectId"
+              @submit="selection"
+            />
+          </div>
+        </template>
+      </avue-crud>
+    </div>
+  </wt-card>
+</template>
+
+<script>
+import wtCard from '@/components/wt-card/index.vue'
+import filepicker from '@/components/filepicker/index.vue'
+
+export default {
+  name: 'info3',
+  components: {
+    wtCard,
+    filepicker
+  },
+  props: {
+    canEdit: {
+      type: Boolean,
+      default: false
+    },
+    projectId: {
+      required: true,
+      type: String,
+      default: ''
+    },
+    stageId: {
+      required: true,
+      type: String,
+      default: ''
+    }
+  },
+  watch: {
+    stageId: {
+      handler(val) {
+        if (val.length > 0) {
+          this.onLoad()
+        }
+      },
+      immediate: false
+    }
+  },
+  data() {
+    return {
+      form: {},
+      data: [],
+      option: {
+        align: 'center',
+        menuAlign: 'center',
+        menuWidth: 180,
+        size: 'mini',
+        addBtn: false,
+        editBtn: false,
+        viewBtn: true,
+        delBtn: true,
+        columnBtn: false,
+        labelWidth: 140,
+        border: true,
+        column: [
+          {
+            label: '合同名称',
+            prop: 'title',
+            fixed: true
+          },
+          {
+            label: '合同金额(万元)',
+            prop: 'amount',
+            width: 180
+          },
+          {
+            label: '业务联系人',
+            prop: 'contacts',
+            width: 120
+          },
+          {
+            label: '合同乙方',
+            prop: 'partyB'
+          }
+        ]
+      },
+      page: {
+        size: 10,
+        current: 1
+      }
+    }
+  },
+  methods: {
+    onLoad() {
+      this.loading = true
+      const data = Object.assign({
+        projectId: this.projectId,
+        stageId: this.stageId
+      })
+      this.$api.contract
+        .contractList(Object.assign(this.page, data))
+        .then(res => {
+          this.data = res.data.records.map(ele => {
+            if (ele.contractsStatus === -1) {
+              ele.contractsStatus = ''
+            }
+            if (ele.type === -1) {
+              ele.type = ''
+            }
+            return ele
+          })
+          this.page.total = res.data.total
+        })
+        .finally(() => {
+          this.loading = false
+        })
+    },
+    beforeOpen(done, type) {
+      if (type === 'view') {
+        const data = this.$router.resolve({
+          path: '/contract/detail',
+          query: { id: this.form.id }
+        })
+        window.open(data.href, '_blank')
+      }
+    },
+    rowDel(row, index, done) {
+      this.$confirm('确定将选择数据删除?', {
+        type: 'warning'
+      }).then(res => {
+        console.log(res)
+        if (res === 'confirm') {
+          this.$api.contract.contractRemove({ ids: row.id }).then(res => {
+            if (res.code === 200) {
+              this.$message.success(res.msg)
+              this.onLoad()
+            } else {
+              this.$message.error(res.msg)
+            }
+          })
+        }
+      })
+    },
+    currentChange(currentPage) {
+      this.page.current = currentPage
+    },
+    sizeChange(pageSize) {
+      this.page.size = pageSize
+    },
+    refreshChange() {
+      this.onLoad()
+    },
+    selection(list) {
+      const tmps = list.map(ele => {
+        return {
+          fileId: ele.id,
+          projectId: ele.projectId,
+          stageId: this.stageId,
+          title: ele.title
+        }
+      })
+      this.$api.contract.linkContract(tmps).then(res => {
+        if (res.code === 200) {
+          this.refreshChange()
+        }
+      })
+    },
+    moreContract() {
+      this.$router.push({
+        path: '/contract',
+        query: { id: this.projectId }
+      })
+    }
+  }
+}
+</script>
+
+<style scoped></style>

+ 342 - 0
src/views/project/componens/info4.vue

@@ -0,0 +1,342 @@
+<template>
+  <wt-card
+    title="投资基本情况(单位:万元)"
+    class="mt-10"
+    :edit-btn="true"
+    @edit="change"
+    @save="save"
+    @on-load="getFundsList(this.type)"
+  >
+    <div
+      class="full-width text-right main-color pointer"
+      style="margin-top: -10px"
+      :style="styleObject"
+      @click="openFundsList"
+    >
+      更多到位资金>>
+      <el-dialog v-model="show">
+        <info :project-id="this.projectId" />
+      </el-dialog>
+    </div>
+    <div style="display: flex; align-items: center">
+      <el-button-group>
+        <el-button type="primary" @click="getFundsList(1)">到位资金</el-button>
+        <el-button type="primary" @click="getFundsList(2)"
+          >筹措资金<i class="el-icon-arrow-right el-icon--right"></i
+        ></el-button>
+      </el-button-group>
+      <div style="margin-left: 20px">
+        * 点击对应按钮,查看到位资金、筹措资金详情
+      </div>
+    </div>
+    <el-form class="mt-20" :disabled="disabled">
+      <div class="body_title">政策投资: {{ totalZC }} 万元</div>
+      <div class="flex flex-justify-center">
+        <el-form-item class="full-width flex-child-average">
+          <div class="flex flex-center full-width item">
+            <span class="title">中央预算内投资:</span>
+            <el-input
+              class="input"
+              placeholder="中央预算内投资"
+              v-model="this.data.investmentOfCentralBudget"
+            ></el-input>
+          </div>
+        </el-form-item>
+        <el-form-item class="full-width flex-child-average">
+          <div class="flex flex-center full-width item">
+            <span class="title">银行贷款:</span>
+            <el-input
+              class="input"
+              placeholder="银行贷款"
+              v-model="this.data.bankLoans"
+            ></el-input>
+          </div>
+        </el-form-item>
+      </div>
+      <div class="flex flex-justify-center">
+        <el-form-item class="full-width flex-child-average">
+          <div class="flex flex-center full-width item">
+            <span class="title">专项债券资金:</span>
+            <el-input
+              class="input"
+              placeholder="专项债券资金"
+              v-model="this.data.specialBondFunds"
+            ></el-input>
+          </div>
+        </el-form-item>
+        <el-form-item class="full-width flex-child-average">
+          <div class="flex flex-center full-width item">
+            <span class="title">抗疫特别国债资金:</span>
+            <el-input
+              class="input"
+              placeholder="抗疫特别国债资金"
+              v-model="this.data.antiEpidemicSpecialTreasuryBondFund"
+            ></el-input>
+          </div>
+        </el-form-item>
+      </div>
+      <div class="flex flex-justify-center">
+        <el-form-item class="full-width flex-child-average">
+          <div class="flex flex-center full-width item">
+            <span class="title">其他地方财政性建设资金:</span>
+            <el-input
+              class="input"
+              placeholder="其他地方财政性建设资金"
+              v-model="this.data.otherLocalFiscalConstructionFunds"
+            ></el-input>
+          </div>
+        </el-form-item>
+        <el-form-item class="full-width flex-child-average">
+          <div class="flex flex-center full-width item">
+            <span class="title">政策性开发性金融工具(基金)投资:</span>
+            <el-input
+              class="input"
+              placeholder="政策性开发性金融工具(基金)投资"
+              v-model="this.data.policyBasedDevelopmentFinancialInvestment"
+            ></el-input>
+          </div>
+        </el-form-item>
+      </div>
+      <div class="body_title">地方预算内投资: {{ totalDF }} 万元</div>
+      <div class="flex flex-justify-center">
+        <el-form-item class="full-width flex-child-average">
+          <div class="flex flex-center full-width item">
+            <span class="title">省级预算内投资:</span>
+            <el-input
+              class="input"
+              placeholder="省级预算内投资"
+              v-model="this.data.investmentWithinProvincialBudget"
+            ></el-input>
+          </div>
+        </el-form-item>
+        <el-form-item class="full-width flex-child-average">
+          <div class="flex flex-center full-width item">
+            <span class="title">市级预算内投资:</span>
+            <el-input
+              class="input"
+              placeholder="市级预算内投资"
+              v-model="this.data.investmentWithinMunicipalBudget"
+            ></el-input>
+          </div>
+        </el-form-item>
+      </div>
+      <div class="flex flex-justify-center">
+        <el-form-item class="full-width flex-child-average">
+          <div class="flex flex-center full-width item">
+            <span class="title">县级预算内投资:</span>
+            <el-input
+              class="input"
+              placeholder="县级预算内投资"
+              v-model="this.data.investmentWithinCountyLevelBudget"
+            ></el-input>
+          </div>
+        </el-form-item>
+        <el-form-item class="full-width flex-child-average">
+          <div class="flex flex-center full-width item"></div>
+        </el-form-item>
+      </div>
+    </el-form>
+  </wt-card>
+</template>
+
+<script>
+import wtCard from '@/components/wt-card/index.vue'
+import info from '@/views/funds/component/info.vue'
+
+export default {
+  components: {
+    wtCard,
+    info
+  },
+  props: {
+    projectId: {
+      required: true,
+      type: String,
+      default: ''
+    }
+  },
+  watch: {
+    projectId: {
+      handler(val) {
+        if (val.length > 0) {
+          this.getFundsList(1)
+        }
+      },
+      immediate: true
+    }
+  },
+  data() {
+    return {
+      canUpdate: false,
+      show: false,
+      styleObject: {
+        visibility: 'visible'
+      },
+      type: 1,
+      disabled: true,
+      data: {},
+      totalZC: 0,
+      totalDF: 0,
+      t1: 0,
+      t2: 0,
+      t3: 0,
+      t4: 0,
+      t5: 0,
+      t6: 0,
+      t7: 0,
+      t8: 0,
+      t9: 0
+    }
+  },
+  methods: {
+    getFundsList(type) {
+      if (type === 1) {
+        this.disabled = true
+      } else {
+        if (this.canUpdate) {
+          this.disabled = true
+        } else {
+          this.disabled = false
+        }
+      }
+
+      this.type = type
+      this.totalDF = 0
+      this.totalZC = 0
+      this.t1 = 0
+      this.t2 = 0
+      this.t3 = 0
+      this.t4 = 0
+      this.t5 = 0
+      this.t6 = 0
+      this.t7 = 0
+      this.t8 = 0
+      this.t9 = 0
+      if (type === 2) {
+        this.styleObject.visibility = 'hidden'
+      } else {
+        this.styleObject.visibility = 'visible'
+      }
+      this.$api.funds
+        .fundsList({ projectId: this.projectId, type: type })
+        .then(res => {
+          if (res.code === 200) {
+            if (type === 1) {
+              res.data.forEach(item => {
+                this.t1 = this.t1 + (item.investmentOfCentralBudget - 0)
+                this.t2 = this.t2 + (item.bankLoans - 0)
+                this.t3 = this.t3 + (item.specialBondFunds - 0)
+                this.t4 =
+                  this.t4 + (item.antiEpidemicSpecialTreasuryBondFund - 0)
+                this.t5 = this.t5 + (item.otherLocalFiscalConstructionFunds - 0)
+                this.t6 =
+                  this.t6 + (item.policyBasedDevelopmentFinancialInvestment - 0)
+                this.t7 = this.t7 + (item.investmentWithinProvincialBudget - 0)
+                this.t8 = this.t8 + (item.investmentWithinMunicipalBudget - 0)
+                this.t9 = this.t9 + (item.investmentWithinCountyLevelBudget - 0)
+              })
+              this.data.investmentOfCentralBudget = this.t1
+              this.data.bankLoans = this.t2
+              this.data.specialBondFunds = this.t3
+              this.data.antiEpidemicSpecialTreasuryBondFund = this.t4
+              this.data.otherLocalFiscalConstructionFunds = this.t5
+              this.data.policyBasedDevelopmentFinancialInvestment = this.t6
+              this.data.investmentWithinProvincialBudget = this.t7
+              this.data.investmentWithinMunicipalBudget = this.t8
+              this.data.investmentWithinCountyLevelBudget = this.t9
+              this.totalZC =
+                this.t1 + this.t2 + this.t3 + this.t4 + this.t5 + this.t6
+              this.totalDF = this.t7 + this.t8 + this.t9
+            } else {
+              if (res.data.length > 0) {
+                this.data = res.data[0]
+              } else {
+                //默认初始化
+                this.data.type = this.type
+                this.data.projectId = this.projectId
+                this.data.investmentOfCentralBudget = this.t1
+                this.data.bankLoans = this.t2
+                this.data.specialBondFunds = this.t3
+                this.data.antiEpidemicSpecialTreasuryBondFund = this.t4
+                this.data.otherLocalFiscalConstructionFunds = this.t5
+                this.data.policyBasedDevelopmentFinancialInvestment = this.t6
+                this.data.investmentWithinProvincialBudget = this.t7
+                this.data.investmentWithinMunicipalBudget = this.t8
+                this.data.investmentWithinCountyLevelBudget = this.t9
+              }
+
+              this.totalZC =
+                this.data.investmentOfCentralBudget -
+                0 +
+                (this.data.bankLoans - 0) +
+                (this.data.specialBondFunds - 0) +
+                (this.data.antiEpidemicSpecialTreasuryBondFund - 0) +
+                (this.data.otherLocalFiscalConstructionFunds - 0) +
+                (this.data.policyBasedDevelopmentFinancialInvestment - 0)
+              this.totalDF =
+                this.data.investmentWithinProvincialBudget -
+                0 +
+                (this.data.investmentWithinMunicipalBudget - 0) +
+                (this.data.investmentWithinCountyLevelBudget - 0)
+            }
+          }
+        })
+    },
+    save() {
+      if (this.type == 2) {
+        this.$api.funds.fundsSaveOrUpdate(this.data).then(res => {
+          if (res.code === 200) {
+            this.$message.success(res.msg)
+          } else {
+            this.$message.error(res.msg)
+          }
+        })
+      } else {
+        this.$message.warning('到位资金合计不可编辑!')
+      }
+    },
+    change(res) {
+      this.canUpdate = res
+      if (this.type === 2) {
+        this.disabled = res
+      }
+    },
+    openFundsList() {
+      this.show = true
+      // const data = this.$router.resolve({
+      //   path: '/funds/detail',
+      //   query: { id: this.projectId }
+      // })
+      // window.open(data.href, '_blank')
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.title {
+  width: 240px;
+  padding-right: 10px;
+  text-align: right;
+}
+
+.body_title {
+  margin-left: 5%;
+  margin-top: 20px;
+  margin-bottom: 20px;
+  width: 90%;
+  text-align: left;
+}
+
+.title-textarea {
+  width: 85px;
+  text-align: left;
+}
+
+.item {
+  width: 90%;
+}
+.input {
+  width: 50%;
+}
+</style>

+ 95 - 0
src/views/project/componens/info5.vue

@@ -0,0 +1,95 @@
+<template>
+  <wt-card
+    title="建成投产后效益测算"
+    class="mt-10"
+    :edit-btn="true"
+    @edit="change"
+    @save="save"
+  >
+    <el-form class="mt-20" :disabled="disabled">
+      <div class="flex flex-justify-center">
+        <el-form-item class="full-width flex-child-average">
+          <div class="flex flex-center full-width item">
+            <span class="title">年产值:</span>
+            <el-input v-model="form.benefit_annual_output"></el-input>
+          </div>
+        </el-form-item>
+        <el-form-item class="full-width flex-child-average">
+          <div class="flex flex-center full-width item">
+            <span class="title">年税收:</span>
+            <el-input v-model="form.benefit_annual_tax"></el-input>
+          </div>
+        </el-form-item>
+        <el-form-item class="full-width flex-child-average">
+          <div class="flex flex-center full-width item">
+            <span class="title">新增就业人数:</span>
+            <el-input v-model="form.benefit_new_employment"></el-input>
+          </div>
+        </el-form-item>
+      </div>
+    </el-form>
+  </wt-card>
+</template>
+
+<script>
+import wtCard from '@/components/wt-card/index.vue'
+
+export default {
+  components: {
+    wtCard
+  },
+  props: {
+    info: {
+      type: Object,
+      default: () => {
+        return {}
+      }
+    }
+  },
+  watch: {
+    info: {
+      handler(val) {
+        this.form = val
+      },
+      immediate: true
+    }
+  },
+  data() {
+    return {
+      disabled: true,
+      form: {}
+    }
+  },
+  methods: {
+    save() {
+      this.$api.project.proUpdate(this.form).then(res => {
+        if (res.code === 200) {
+          this.$message.success(res.msg)
+        } else {
+          this.$message.error(res.msg)
+        }
+      })
+    },
+    change(res) {
+      this.disabled = res
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.title {
+  width: 120px;
+  padding-right: 10px;
+  text-align: right;
+}
+
+.title-textarea {
+  width: 85px;
+  text-align: left;
+}
+
+.item {
+  width: 90%;
+}
+</style>

+ 297 - 0
src/views/project/componens/info6.vue

@@ -0,0 +1,297 @@
+<template>
+  <wt-card
+    title="年度投资情况(单位:万元)"
+    class="mt-10"
+    :edit-btn="true"
+    @edit="change"
+    @save="save"
+  >
+    <el-form class="mt-20" :disabled="disabled">
+      <div style="text-align: left" class="mt-20 ml-10 mb-20">
+        <span class="title">年份:</span>
+        <el-select v-model="selectYear" @change="changeYear">
+          <el-option
+            v-for="item in years"
+            :key="item.value"
+            :label="item.label"
+            :value="item.value"
+          />
+        </el-select>
+      </div>
+
+      <table>
+        <thead>
+          <tr>
+            <th>类型</th>
+            <th v-for="item in month">
+              {{ item.month != '合计' ? item.month + '月' : '合计' }}
+            </th>
+            <th>合计</th>
+          </tr>
+        </thead>
+        <tbody>
+          <tr>
+            <th>计划投资</th>
+            <th v-for="item in month">
+              <el-input
+                class="th-input"
+                v-model="item.planInvestment"
+                @input="AddUpdateItem(item)"
+              >
+              </el-input>
+            </th>
+            <th>{{ allPlanInvestment }}</th>
+          </tr>
+          <tr>
+            <th>累计投资</th>
+            <th v-for="item in month">
+              <el-input
+                class="th-input"
+                v-model="item.totalInvestment"
+                @input="AddUpdateItem(item)"
+              >
+              </el-input>
+            </th>
+            <th>{{ allTotalInvestment }}</th>
+          </tr>
+          <tr>
+            <th>计划纳统投资</th>
+            <th v-for="item in month">
+              <el-input
+                class="th-input"
+                v-model="item.planNtInvestment"
+                @input="AddUpdateItem(item)"
+              >
+              </el-input>
+            </th>
+            <th>{{ allPlanNtInvestment }}</th>
+          </tr>
+          <tr>
+            <th>累计纳统投资</th>
+            <th v-for="item in month">
+              <el-input
+                class="th-input"
+                v-model="item.totalNtInvestment"
+                @input="AddUpdateItem(item)"
+              >
+              </el-input>
+            </th>
+            <th>{{ allTotalNtInvestment }}</th>
+          </tr>
+        </tbody>
+      </table>
+    </el-form>
+  </wt-card>
+</template>
+
+<script>
+import wtCard from '@/components/wt-card/index.vue'
+
+export default {
+  components: {
+    wtCard
+  },
+  props: {
+    projectId: {
+      required: true,
+      type: String,
+      default: ''
+    }
+  },
+  watch: {
+    projectId: {
+      handler(val) {
+        this.initYear()
+        if (val.length > 0) {
+          this.getList()
+        }
+      },
+      immediate: true
+    }
+  },
+  data() {
+    return {
+      allPlanInvestment: 0,
+      allTotalInvestment: 0,
+      allPlanNtInvestment: 0,
+      allTotalNtInvestment: 0,
+      updateItem: [],
+      data: [],
+      month: [
+        { month: '1-2' },
+        { month: '3' },
+        { month: '4' },
+        { month: '5' },
+        { month: '6' },
+        { month: '7' },
+        { month: '8' },
+        { month: '9' },
+        { month: '10' },
+        { month: '11' },
+        { month: '12' }
+      ],
+      years: [],
+      years2: [],
+      selectYear: new Date().getFullYear(),
+      disabled: true
+    }
+  },
+  methods: {
+    changeYear(res) {
+      this.allPlanInvestment = 0
+      this.allTotalInvestment = 0
+      this.allPlanNtInvestment = 0
+      this.allTotalNtInvestment = 0
+      this.getList()
+    },
+    getList() {
+      this.$api.project
+        .projectAnnualInvestment({
+          projectId: this.projectId,
+          year: this.selectYear
+        })
+        .then(res => {
+          if (res.code === 200) {
+            this.data = res.data
+            this.month.map(monthItem => {
+              const sub = res.data.find(ele => ele.month === monthItem.month)
+              if (sub) {
+                monthItem.id = sub.id
+                monthItem.createDept = sub.createDept
+                monthItem.createTime = sub.createTime
+                monthItem.createUser = sub.createUser
+                monthItem.isDeleted = sub.isDeleted
+                monthItem.planInvestment = sub.planInvestment
+                monthItem.planNtInvestment = sub.planNtInvestment
+                monthItem.projectId = sub.projectId
+                monthItem.status = sub.status
+                monthItem.totalInvestment = sub.totalInvestment
+                monthItem.totalNtInvestment = sub.totalNtInvestment
+                monthItem.updateTime = sub.updateTime
+                monthItem.updateUser = sub.updateUser
+                monthItem.year = sub.year
+
+                this.allTotalNtInvestment =
+                  this.allTotalNtInvestment + (sub.totalNtInvestment - 0)
+                this.allPlanInvestment =
+                  this.allPlanInvestment + (sub.planInvestment - 0)
+                this.allTotalInvestment =
+                  this.allTotalInvestment + (sub.totalInvestment - 0)
+                this.allPlanNtInvestment =
+                  this.allPlanNtInvestment + (sub.planNtInvestment - 0)
+              } else {
+                monthItem.planInvestment = 0
+                monthItem.planNtInvestment = 0
+                monthItem.projectId = this.projectId
+                monthItem.totalInvestment = 0
+                monthItem.totalNtInvestment = 0
+                monthItem.year = this.selectYear
+              }
+            })
+          }
+        })
+    },
+    initYear() {
+      this.years.length = 0
+      const year = new Date().getFullYear()
+      for (let i = 2017; i <= year + 1; i++) {
+        const item = { label: i, value: i }
+        this.years.push(item)
+      }
+      this.years.reverse()
+    },
+    AddUpdateItem(item) {
+      const sub = this.updateItem.find(ele => ele.month === item.month)
+      if (sub) {
+        console.log('这个已经在更新列表中!')
+      } else {
+        this.updateItem.push(item)
+      }
+
+      let index = this.data.findIndex(ele => {
+        if (ele.month === item.month) {
+          return true
+        }
+      })
+      if (index != -1) {
+        this.data.splice(index, 1)
+      }
+      this.data.push(item)
+      //重新计算合计
+      this.allPlanInvestment = 0
+      this.allTotalInvestment = 0
+      this.allPlanNtInvestment = 0
+      this.allTotalNtInvestment = 0
+      this.data.forEach(ele => {
+        this.allTotalNtInvestment =
+          this.allTotalNtInvestment + (ele.totalNtInvestment - 0)
+        this.allPlanInvestment =
+          this.allPlanInvestment + (ele.planInvestment - 0)
+        this.allTotalInvestment =
+          this.allTotalInvestment + (ele.totalInvestment - 0)
+        this.allPlanNtInvestment =
+          this.allPlanNtInvestment + (ele.planNtInvestment - 0)
+      })
+    },
+    change(res) {
+      this.disabled = res
+    },
+    save() {
+      this.$api.project
+        .batchSubmitAnnualInvestment(this.updateItem)
+        .then(res => {
+          if (res.code === 200) {
+            this.$message.success(res.msg)
+          } else {
+            this.$message.error(res.msg)
+          }
+        })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.title {
+  width: 60px;
+  padding-right: 10px;
+  text-align: center;
+}
+
+table {
+  width: 1200px;
+  margin: 10px;
+}
+
+thead {
+  background: #d7d7d7;
+}
+
+tr {
+  height: 40px;
+}
+
+th {
+  height: 40px;
+  width: 7.69%;
+  flex: 1;
+  text-align: center;
+  border: 1px solid #9c9c9c;
+}
+
+.th-input {
+  height: 100%;
+  width: 100%;
+  text-align: center;
+  border: none;
+}
+
+:deep(.el-input__wrapper) {
+  border: none;
+  border-radius: revert;
+}
+
+:deep(.el-input__inner) {
+  text-align: center;
+}
+</style>

+ 400 - 0
src/views/project/componens/info7.vue

@@ -0,0 +1,400 @@
+<template>
+  <wt-card
+    title="其他信息"
+    class="mt-10"
+    :edit-btn="true"
+    @edit="change"
+    @save="save"
+  >
+    <el-form class="mt-20" :disabled="disabled">
+      <div class="body_title bold">入库信息</div>
+      <div class="flex flex-center flex-justify-start">
+        <!--    入库信息 1   -->
+        <div class="flex flex-col">
+          <el-form-item>
+            <div class="flex flex-center">
+              <span class="title">是否入库:</span>
+              <el-select
+                v-model="form.is_storage"
+                placeholder="是否入库"
+                class="wd"
+              >
+                <el-option
+                  v-for="item in yesOrNo"
+                  :key="item.label"
+                  :label="item.label"
+                  :value="item.value"
+                />
+              </el-select>
+            </div>
+          </el-form-item>
+          <el-form-item>
+            <div class="flex flex-center">
+              <span class="title">项目代码:</span>
+              <el-input
+                v-model="form.project_code"
+                placeholder="项目代码"
+                class="wd"
+              ></el-input>
+            </div>
+          </el-form-item>
+          <el-form-item>
+            <div class="flex flex-center" v-if="form.tags === 1">
+              <span class="title">可研批复号:</span>
+              <el-input
+                v-model="form.available_approval_id"
+                placeholder="可研批复号"
+                class="wd"
+              ></el-input>
+            </div>
+            <div class="flex flex-center" v-else>
+              <span class="title">备案号:</span>
+              <el-input
+                v-model="form.record_id"
+                placeholder="备案号"
+                class="wd"
+              ></el-input>
+            </div>
+          </el-form-item>
+        </div>
+        <!--    入库信息 2   -->
+        <div class="flex flex-col ml-20">
+          <el-form-item>
+            <div class="flex flex-center">
+              <span class="title1">计划入库时间:</span>
+              <el-date-picker
+                v-model="form.plan_storage_time"
+                type="date"
+                placeholder="计划入库时间"
+                format="YYYY-MM-DD"
+                value-format="YYYY-MM-DD"
+                style="width: 260px"
+              />
+            </div>
+          </el-form-item>
+          <el-form-item>
+            <div class="flex flex-center">
+              <span class="title1">监管平台代码:</span>
+              <el-input
+                v-model="form.regulatory_platform_code"
+                placeholder="监管平台代码"
+                class="wd"
+              ></el-input>
+            </div>
+          </el-form-item>
+          <el-form-item>
+            <div class="flex flex-center" v-if="form.tags === 1">
+              <span class="title1">可研批复时间:</span>
+              <el-date-picker
+                style="width: 260px"
+                v-model="form.available_approval_date"
+                type="date"
+                placeholder="可研批复时间"
+                format="YYYY-MM-DD"
+                value-format="YYYY-MM-DD"
+              />
+            </div>
+            <div class="flex flex-center" v-else>
+              <span class="title1">备案时间:</span>
+              <el-date-picker
+                style="width: 260px"
+                v-model="form.record_date"
+                type="date"
+                placeholder="备案时间"
+                format="YYYY-MM-DD"
+                value-format="YYYY-MM-DD"
+              />
+            </div>
+          </el-form-item>
+        </div>
+        <!--    入库信息 3   -->
+        <div class="flex flex-col ml-20">
+          <el-form-item>
+            <div class="flex flex-center">
+              <span class="title2">实际入库时间:</span>
+              <el-date-picker
+                v-model="form.storage_time"
+                type="date"
+                placeholder="实际入库时间"
+                format="YYYY-MM-DD"
+                value-format="YYYY-MM-DD"
+                style="width: 100%"
+                @change="changeStorageTime"
+              />
+            </div>
+          </el-form-item>
+          <el-form-item>
+            <div class="flex flex-center">
+              <span class="title2">是否纳入省集中开工:</span>
+              <div class="full-width">
+                <el-select
+                  v-model="form.is_provincial_level_construction"
+                  placeholder="是否纳入省集中开工"
+                  class="full-width"
+                >
+                  <el-option
+                    v-for="item in yesOrNo"
+                    :key="item.label"
+                    :label="item.label"
+                    :value="item.value"
+                  />
+                </el-select>
+              </div>
+            </div>
+          </el-form-item>
+          <el-form-item>
+            <div class="flex flex-center">
+              <span class="title2 nowrap">是否纳入省重点项目:</span>
+              <div class="full-width">
+                <el-select v-model="form.is_provincial_key" style="width: 100%">
+                  <el-option
+                    v-for="item in yesOrNo"
+                    :key="item.label"
+                    :label="item.label"
+                    :value="item.value"
+                  />
+                </el-select>
+              </div>
+            </div>
+          </el-form-item>
+        </div>
+      </div>
+
+      <!--    开工信息    -->
+      <div class="body_title bold">开工信息</div>
+      <div class="flex flex-center flex-justify-start">
+        <div class="flex flex-col">
+          <el-form-item>
+            <div class="flex flex-center">
+              <span class="title">是否开工:</span>
+              <el-select
+                v-model="form.is_start"
+                placeholder="是否开工"
+                class="wd"
+              >
+                <el-option
+                  v-for="item in yesOrNo"
+                  :key="item.label"
+                  :label="item.label"
+                  :value="item.value"
+                />
+              </el-select>
+            </div>
+          </el-form-item>
+          <el-form-item>
+            <div class="flex flex-center">
+              <span class="title">计划竣工时间:</span>
+              <el-date-picker
+                v-model="form.plan_completion_time"
+                type="date"
+                style="width: 260px"
+                placeholder="计划竣工时间"
+                format="YYYY-MM-DD"
+                value-format="YYYY-MM-DD"
+              />
+            </div>
+          </el-form-item>
+        </div>
+        <div class="flex flex-col ml-20">
+          <el-form-item>
+            <div class="flex flex-center">
+              <span class="title">计划开工时间:</span>
+              <el-date-picker
+                v-model="form.plan_commencement_time"
+                type="date"
+                style="width: 260px"
+                placeholder="计划开工时间"
+                format="YYYY-MM-DD"
+                value-format="YYYY-MM-DD"
+              />
+            </div>
+          </el-form-item>
+          <el-form-item>
+            <div class="flex flex-center">
+              <span class="title">实际竣工时间:</span>
+              <el-date-picker
+                v-model="form.completion_time"
+                type="date"
+                style="width: 260px"
+                placeholder="实际竣工时间"
+                format="YYYY-MM-DD"
+                value-format="YYYY-MM-DD"
+                @change="changeCompletionTime"
+              />
+            </div>
+          </el-form-item>
+        </div>
+        <div class="flex flex-col ml-20" style="margin-bottom: 46px">
+          <el-form-item>
+            <div class="flex flex-center">
+              <span class="title2">实际开工时间:</span>
+              <el-date-picker
+                v-model="form.start_time"
+                type="date"
+                style="width: 100%"
+                placeholder="实际开工时间"
+                format="YYYY-MM-DD"
+                value-format="YYYY-MM-DD"
+                @change="changeStartTime"
+              />
+            </div>
+          </el-form-item>
+        </div>
+      </div>
+    </el-form>
+  </wt-card>
+</template>
+
+<script>
+import wtCard from '@/components/wt-card/index.vue'
+
+export default {
+  components: {
+    wtCard
+  },
+  props: {
+    info: {
+      type: Object,
+      default: () => {
+        return {}
+      }
+    }
+  },
+  watch: {
+    info: {
+      handler(val) {
+        this.form = val
+      },
+      immediate: true
+    }
+  },
+  data() {
+    return {
+      yesOrNo: [
+        {
+          label: '否',
+          value: 0
+        },
+        {
+          label: '是',
+          value: 1
+        }
+      ],
+      disabled: true,
+      form: {}
+    }
+  },
+  methods: {
+    changeStorageTime(res) {
+      if (new Date().getTime() < new Date(res).getTime()) {
+        this.$message.warning('实际入库时间不能大于当前时间!')
+      }
+    },
+    changeStartTime(res) {
+      if (new Date().getTime() < new Date(res).getTime()) {
+        this.$message.warning('实际开工时间不能大于当前时间!')
+      }
+    },
+    changeCompletionTime(res) {
+      if (new Date().getTime() < new Date(res).getTime()) {
+        this.$message.warning('实际竣工时间不能大于当前时间!')
+      }
+    },
+    save() {
+      if (this.check()) {
+        return
+      }
+      this.$api.project.proUpdate(this.form).then(res => {
+        if (res.code === 200) {
+          this.$message.success(res.msg)
+        } else {
+          this.$message.error(res.msg)
+        }
+      })
+    },
+    check() {
+      if (new Date().getTime() < new Date(this.form.storage_time).getTime()) {
+        this.$message.error('实际入库时间不能大于当前时间!')
+        return true
+      }
+      if (new Date().getTime() < new Date(this.form.start_time).getTime()) {
+        this.$message.error('实际开工时间不能大于当前时间!')
+        return true
+      }
+      if (
+        new Date().getTime() < new Date(this.form.completion_time).getTime()
+      ) {
+        this.$message.error('实际竣工时间不能大于当前时间!')
+        return true
+      }
+      if (this.form.is_storage == 1) {
+        if (this.form.storage_time == null || this.form.storage_time == '') {
+          this.$message.error('请填写入库时间!')
+          return true
+        }
+      }
+      if (this.form.is_start == 1) {
+        if (this.form.start_time == null || this.form.start_time == '') {
+          this.$message.error('请填写开工时间!')
+          return true
+        }
+      }
+      if (this.form.tags == 1) {
+        //政府投资项目 必须要有可研批复号
+        if (
+          this.form.available_approval_id == '' ||
+          this.form.available_approval_id == null
+        ) {
+          this.$message.error('请填写可研批复号!')
+          return true
+        }
+      }
+      //企业投资项目 必须要有项目代码
+      if (this.form.tags == 2) {
+        if (this.form.project_code == '' || this.form.project_code == null) {
+          this.$message.error('请填写项目代码!')
+          return true
+        }
+      }
+    },
+    change(res) {
+      this.disabled = res
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.body_title {
+  margin-bottom: 10px;
+  width: 90%;
+  text-align: left;
+}
+
+.title {
+  width: 110px;
+  text-align: right;
+  margin-right: 10px;
+}
+
+.title1 {
+  width: 110px;
+  text-align: right;
+  margin-right: 10px;
+}
+
+.title2 {
+  width: 200px;
+  text-align: right;
+  margin-right: 10px;
+}
+
+.title-textarea {
+  width: 85px;
+  text-align: left;
+}
+
+.wd {
+  width: 260px;
+}
+</style>

+ 90 - 0
src/views/project/componens/info8.vue

@@ -0,0 +1,90 @@
+<template>
+  <wt-card title="任务列表" class="mt-10">
+    <div
+      class="flex flex-center full-width flex-justify-between mb-10 flex-col"
+    >
+      <span class="full-width text-left bold mb-10">编制任务</span>
+      <div style="width: 100%" class="mt-10">
+        <task-table
+          :option="option"
+          :data="data"
+          :project-id="projectId"
+          :total="total"
+          @refresh="list"
+        ></task-table>
+      </div>
+    </div>
+  </wt-card>
+</template>
+
+<script>
+import wtCard from '@/components/wt-card/index.vue'
+import TaskTable from '@/views/task/component/task-table.vue'
+
+export default {
+  name: 'info8',
+  components: { wtCard, TaskTable },
+  props: {
+    projectId: {
+      required: true,
+      type: String,
+      default: ''
+    }
+  },
+  watch: {
+    projectId: {
+      handler(val) {
+        if (val !== null && val !== undefined) {
+          this.list()
+        }
+      },
+      immediate: true
+    }
+  },
+  data() {
+    return {
+      data: [],
+      task: {},
+      total: 0,
+      option: {
+        showCheckBox: false,
+        folderChecked: true,
+        column: [
+          {
+            label: '共20个任务',
+            prop: 'title',
+            display: false,
+            width: 300
+          },
+          {
+            label: '标签',
+            prop: 'createUserName'
+          },
+          {
+            label: '时间',
+            prop: 'createUserName'
+          },
+          {
+            label: '执行人',
+            prop: 'createTime'
+          }
+        ]
+      }
+    }
+  },
+  methods: {
+    list() {
+      this.$api.task
+        .taskListByProject({ projectId: this.projectId, level: 1 })
+        .then(res => {
+          if (res.code === 200) {
+            this.data = res.data.records
+            this.total = res.data.total
+          }
+        })
+    }
+  }
+}
+</script>
+
+<style scoped></style>

+ 299 - 0
src/views/project/componens/map-picker.vue

@@ -0,0 +1,299 @@
+<template>
+  <div>
+    <div class="flex flex-center">
+      <el-input
+        class="mr-10"
+        placeholder="请选择项目地址"
+        v-model="this.form.address"
+      ></el-input>
+      <el-button type="primary" plain @click="show = true">查看地图</el-button>
+    </div>
+    <el-dialog v-model="show" :width="960" @close="close">
+      <template #header
+        ><h4 class="full-width text-left">地理位置</h4></template
+      >
+      <div class="full-width flex flex-justify-start">
+        <el-autocomplete
+          v-model="keyword"
+          id="input"
+          type="text"
+          style="width: 50%"
+          :fetch-suggestions="querySearch"
+          placeholder="搜索位置"
+          @keyup.enter="querySearch"
+          @select="handleSelect"
+        />
+        <span
+          class="ml-20 grey-6-bg padding-left padding-right radius-5"
+          style="min-width: 100px"
+          >当前经纬度:{{ longitude }},{{ latitude }}</span
+        >
+      </div>
+      <div class="flex flex-center flex-justify-start flex-col mt-10">
+        <div id="container" class="map"></div>
+        <el-divider />
+        <div class="flex flex-center flex-justify-start full-width">
+          <div class="text-left bold-500 black mr-10">相关图片</div>
+          <filepicker :project-id="projectId" @submit="filePicker" />
+          <span class="ml-20 font-12 grey-6">*请选择图片类型的文件</span>
+        </div>
+        <div class="img-content flex flex-justify-start hide-scrollbar mt-20">
+          <img
+            :src="item.url"
+            v-for="(item, index) in photoList"
+            :key="item.url"
+            @click="showImg(index)"
+          />
+        </div>
+        <div class="full-width flex flex-center flex-justify-end">
+          <el-button type="primary" plain @click="show = false"
+            >取 消
+          </el-button>
+          <el-button type="primary" @click="submit">确 定</el-button>
+        </div>
+      </div>
+    </el-dialog>
+    <el-image-viewer
+      v-if="showImage"
+      :url-list="preList"
+      :initial-index="initial"
+      @close="showImage = false"
+    />
+  </div>
+</template>
+
+<script>
+import filepicker from '@/components/filepicker/index.vue'
+import api from '@/api/index.js'
+
+export default {
+  components: {
+    filepicker
+  },
+  watch: {
+    projectId: {
+      type: String,
+      default: ''
+    },
+    show: {
+      handler(val) {
+        if (val) {
+          this.getPhoto()
+          setTimeout(() => {
+            this.initMap()
+          }, 1000)
+        }
+      },
+      immediate: true
+    },
+    address: {
+      handler(val) {
+        if (val.length > 0) {
+          this.form.address = val
+          this.keyword = val
+        }
+      },
+      immediate: true
+    }
+  },
+  props: {
+    projectId: {
+      required: true,
+      type: String,
+      default: ''
+    },
+    address: {
+      type: String,
+      default: ''
+    },
+    latLng: {
+      type: Array,
+      default: () => {
+        return []
+      }
+    }
+  },
+  data() {
+    return {
+      show: false,
+      showImage: false,
+      initial: 0,
+      preList: [],
+      map: null,
+      geocoder: '',
+      keyword: '',
+      auto: null,
+      latitude: 0,
+      longitude: 0,
+      markAddress: '',
+      placeSearch: null,
+      cityCode: '',
+      markList: [],
+      form: {
+        address: '',
+        longitude: '',
+        latitude: ''
+      },
+      photoList: [],
+      editPhoto: false
+    }
+  },
+  methods: {
+    getPhoto() {
+      this.$api.project
+        .photoProject({ projectId: this.projectId })
+        .then(res => {
+          if (res.code === 200) {
+            this.photoList = res.data.map(ele => {
+              ele.fileVO.url = ele.fileVO.filePath
+              return ele.fileVO
+            })
+            this.preList = this.photoList.map(ele => ele.url)
+          }
+        })
+    },
+    initMap() {
+      window._AMapSecurityConfig = {
+        securityJsCode: 'b7c07b56f6647ae56ff3d926a42d9565'
+      }
+      this.map = new AMap.Map('container', {
+        // 设置地图容器id
+        viewMode: '2D', // 是否为3D地图模式
+        zoom: 13, // 初始化地图级别
+        features: ['bg', 'road', 'building', 'point']
+      })
+      const _this = this
+      AMap.plugin(['AMap.ToolBar', 'AMap.Scale', 'AMap.Geocoder'], function () {
+        _this.map.addControl(new AMap.ToolBar())
+        _this.map.addControl(new AMap.Scale())
+        _this.geocoder = new AMap.Geocoder({
+          radius: 500 // 范围,默认:500
+        })
+      })
+      this.map.on('complete', () => {
+        this.addEvent()
+        this.mapSearchInit()
+        if (this.latLng.length > 0 && this.latLng[0] !== undefined) {
+          this.latitude = this.latLng[0]
+          this.longitude = this.latLng[1]
+          this.addMarker(this.latLng[0], this.latLng[1])
+        } else {
+          const tmp = this.map.getCenter()
+          this.map.setCenter([tmp.lng, tmp.lat])
+        }
+      })
+    },
+    addMarker(lat, lng) {
+      this.map.remove(this.markList)
+      this.map.setCenter([lng, lat])
+      const marker = new AMap.Marker({
+        position: [lng, lat]
+      })
+      this.markList.push(marker)
+      marker.setMap(this.map)
+      this.geocoderAddress(lng, lat)
+    },
+    geocoderAddress(lng, lat) {
+      this.geocoder.getAddress([lng, lat], (status, result) => {
+        if (status === 'complete') {
+          this.form.address = result.regeocode.formattedAddress
+          this.keyword = this.form.address
+        }
+      })
+    },
+    addEvent() {
+      this.map.on('click', event => {
+        this.latitude = event.lnglat.lat
+        this.longitude = event.lnglat.lng
+        this.addMarker(this.latitude, this.longitude)
+      })
+    },
+    /** 初始化搜索工具 */
+    mapSearchInit() {
+      const _this = this
+      AMap.plugin(['AMap.AutoComplete', 'AMap.PlaceSearch'], function () {
+        // 实例化Autocomplete
+        const autoOptions = {
+          city: '全国'
+        }
+        _this.auto = new AMap.AutoComplete(autoOptions)
+        _this.placeSearch = new AMap.PlaceSearch({
+          map: _this.map
+        })
+      })
+    },
+    /** 关键词搜索 */
+    handleSelect(res) {
+      this.placeSearch.setCity(res.adcode)
+      this.placeSearch.search(res.name)
+      this.placeSearch.on('markerClick', res => {
+        this.map.remove(this.markList)
+        this.latitude = res.data.location.lat
+        this.longitude = res.data.location.lng
+        this.geocoderAddress(this.longitude, this.latitude)
+      })
+    },
+    querySearch(key, cb) {
+      this.auto.search(this.keyword, function (status, result) {
+        const tmp = result.tips.map(e => {
+          e.value = e.name + '(' + e.district + ')'
+          return e
+        })
+        cb(tmp)
+      })
+    },
+    submit() {
+      this.form.address = this.keyword
+      this.form.latitude = this.latitude
+      this.form.longitude = this.longitude
+      this.show = false
+      this.$emit('success', this.form, this.editPhoto ? this.photoList : [])
+    },
+    filePicker(list) {
+      this.editPhoto = true
+      const tmps = list
+        .filter(ele => !api.offices.includes(ele.suffix))
+        .map(ele => {
+          console.log(ele)
+          return {
+            bladeFileId: ele.fileId,
+            fileId: ele.id,
+            projectId: ele.projectId,
+            title: ele.title,
+            url: ele.url,
+            folderId: ele.parentId
+          }
+        })
+      this.photoList = this.photoList.concat(tmps)
+      this.preList = this.photoList.map(ele => ele.url)
+    },
+    showImg(index) {
+      this.initial = index
+      this.showImage = true
+    },
+    close() {
+      // this.photoList.length = 0
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.map {
+  width: 100%;
+  height: 400px;
+}
+
+.img-content {
+  width: 100%;
+  height: 140px;
+  overflow-x: scroll;
+
+  img {
+    width: 120px;
+    height: 120px;
+    object-fit: cover;
+    margin-left: 10px;
+  }
+}
+</style>

+ 84 - 0
src/views/project/componens/top.vue

@@ -0,0 +1,84 @@
+<template>
+  <div>
+    <div class="white-bg border radius-5 picker flex flex-center">
+      <span class="padding">项目阶段:</span>
+      <el-select
+        class="padding-right"
+        style="width: 200px"
+        clearable
+        v-model="stage"
+        @change="changeStage"
+      >
+        <el-option
+          v-for="item in stages"
+          :key="item"
+          :label="item.name"
+          :value="item.id"
+        />
+      </el-select>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  props: {
+    projectId: {
+      required: true,
+      type: String,
+      default: ''
+    }
+  },
+  watch: {
+    projectId: {
+      handler(val) {
+        if (val.length > 0) {
+          this.getStage()
+        }
+      },
+      immediate: true
+    }
+  },
+  data() {
+    return {
+      stages: [],
+      stage: ''
+    }
+  },
+  methods: {
+    /**
+     * 获取项目阶段
+     */
+    getStage() {
+      this.$api.project
+        .includeStage({ projectId: this.projectId })
+        .then(res => {
+          if (res.code === 200) {
+            this.stages = res.data
+            const tmp = this.stages.find(ele => ele.isLastSelect === 1)
+            if (tmp) {
+              this.stage = tmp.id
+            } else {
+              this.stage = this.stages[0].id
+            }
+            this.$emit('change', this.stage)
+          }
+        })
+    },
+    changeStage(res) {
+      const tmp = this.stages.find(ele => ele.id === res)
+      this.$emit('filter', tmp.sort)
+      this.$emit('change', res)
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.picker {
+  border: #a3773d solid 1px;
+  :deep(.el-input__wrapper) {
+    box-shadow: none;
+  }
+}
+</style>

+ 296 - 0
src/views/project/index.vue

@@ -0,0 +1,296 @@
+<template>
+  <div>
+    <tips-custom>
+      <template #title>
+        <span class="font-24 bold">{{ detail.name }}</span>
+        <el-tag class="ml-20">{{ detail.tagsName }}</el-tag>
+        <el-tag class="ml-10">{{ detail.report_type_name }}</el-tag>
+      </template>
+      <template #default>
+        <top
+          ref="top"
+          :project-id="projectId"
+          @change="changeStage"
+          @filter="filterStage"
+        />
+      </template>
+    </tips-custom>
+    <div class="mb-20" v-if="detail.report_type === 4">
+      <el-card shadow="hover" style="background-color: #e2eaf5">
+        <div class="flex flex-center flex-justify-start">
+          <el-icon color="#409eff" :size="30">
+            <WarningFilled />
+          </el-icon>
+          <span class="ml-10"
+            >{{ detail.report_type_name }} 审核意见:{{
+              detail.receipt_msg
+            }}</span
+          >
+        </div>
+      </el-card>
+    </div>
+    <!--    content-->
+    <div style="margin-bottom: 65px">
+      <div v-if="[1, 2].includes(currentStage)">
+        <!--        基础信息-->
+        <info1 :info="detail" @industry="changeIndustry" />
+      </div>
+      <!--      前期要件-->
+      <info2
+        v-if="[2, 3].includes(currentStage)"
+        :project-id="projectId"
+        :stage-id="stageId"
+        :industry="industry"
+      />
+      <!--      相关合同-->
+      <info3
+        :project-id="projectId"
+        :can-edit="detail.can_update"
+        :stage-id="stageId"
+      />
+      <!--      投资基本情况-->
+      <info4 v-if="[4].includes(currentStage)" :project-id="projectId" />
+      <!--      建成投产后效益测算-->
+      <info5 v-if="currentStage === 2" :info="detail" />
+      <!--      年度投资情况-->
+      <info6 v-if="currentStage === 4" :project-id="projectId" />
+      <!--      其他信息-->
+      <info7 v-if="[1, 2, 4, 5].includes(currentStage)" :info="detail" />
+      <!--      任务列表-->
+      <info8 v-if="user.info.type === 4" :project-id="projectId" />
+    </div>
+    <!--    buttom-->
+    <div
+      class="bottom flex flex-center flex-justify-end"
+      v-if="user.info.type === 3 && currentStage < 6"
+    >
+      <div class="padding">
+        <el-button type="primary" plain @click="projectCancel"
+          >退 库
+        </el-button>
+        <el-button
+          type="primary"
+          v-if="[0, 1, 4].includes(detail.report_type)"
+          @click="projectReport"
+          plain
+          >上报审核
+        </el-button>
+        <el-button
+          type="primary"
+          plain
+          v-if="detail.report_type === 2"
+          @click="$refs.approval.show()"
+          >审 核
+        </el-button>
+        <el-button
+          type="primary"
+          plain
+          v-if="detail.report_type === 3"
+          @click="projectReportFormal"
+          >上报到固定资产
+        </el-button>
+        <el-button type="primary" @click="nextStage" v-if="currentStage < 6"
+          >下一阶段</el-button
+        >
+      </div>
+    </div>
+
+    <approval ref="approval" :project-id="projectId" @success="getInfo" />
+  </div>
+</template>
+
+<route>
+{
+path: '/project',
+name: '项目详情',
+meta: { layout: 'empty','show': false}
+}
+</route>
+
+<script>
+import tipsCustom from '@/components/tips-custom/index.vue'
+import top from '@/views/project/componens/top.vue'
+import confing from '@/config/website.js'
+import Info1 from '@/views/project/componens/info1.vue'
+import Info2 from '@/views/project/componens/info2.vue'
+import info3 from '@/views/project/componens/info3.vue'
+import Info4 from '@/views/project/componens/info4.vue'
+import Info5 from '@/views/project/componens/info5.vue'
+import Info6 from '@/views/project/componens/info6.vue'
+import Info7 from '@/views/project/componens/info7.vue'
+import Info8 from '@/views/project/componens/info8.vue'
+import { useStore } from '@/store/user.js'
+import approval from '@/views/project/componens/approval.vue'
+
+export default {
+  components: {
+    Info2,
+    Info1,
+    Info4,
+    Info5,
+    Info6,
+    Info7,
+    tipsCustom,
+    top,
+    info3,
+    Info8,
+    approval
+  },
+  setup() {
+    const user = useStore()
+    return { user }
+  },
+  data() {
+    return {
+      projectId: '',
+      stageId: '',
+      currentStage: 1,
+      industry: null,
+      detail: {},
+      stageFilter: false
+    }
+  },
+  mounted() {
+    this.projectId = this.$route.query.id
+    this.getInfo()
+  },
+  methods: {
+    getInfo() {
+      this.$api.project.projectMapInfo(this.projectId).then(res => {
+        if (res.code === 200) {
+          this.detail = res.data
+          delete this.detail._id
+          this.stageId = res.data.stageId
+          if (this.stageFilter === false) {
+            this.currentStage = res.data.current_stage
+          }
+          this.detail.tagsName =
+            this.detail.tags === 1 ? '政府投资项目' : '企业投资项目'
+          const status = confing.reportTypes.find(
+            ele => ele.value === this.detail.report_type
+          )
+          this.industry = this.detail.dict_key[0]
+          if (status) {
+            this.detail.report_type_name = status.label
+          }
+        }
+      })
+    },
+    changeStage(res) {
+      this.stageId = res
+    },
+    changeIndustry(industry) {
+      this.industry = industry
+    },
+    filterStage(res) {
+      this.stageFilter = true
+      this.currentStage = res
+      this.getInfo()
+    },
+    nextStage() {
+      this.$confirm(
+        '请检查当前阶段信息是否完善,点击确定后项目将进行下一个阶段',
+        {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning'
+        }
+      ).then(res => {
+        if (res === 'confirm') {
+          this.currentStage = this.currentStage + 1
+          this.detail.current_stage = this.currentStage
+          this.update()
+        }
+      })
+    },
+    update() {
+      this.$api.project.proUpdate(this.detail).then(res => {
+        if (res.code === 200) {
+          this.$message.success(res.msg)
+          this.updateCurrentStage(this.detail.current_stage)
+        } else {
+          this.$message.error(res.msg)
+        }
+      })
+    },
+    updateCurrentStage(sort) {
+      this.$api.project
+        .updateCurrentStage({ projectId: this.projectId, sort })
+        .then(res => {
+          if (res.code === 200) {
+            this.$refs.top.getStage()
+          }
+        })
+    },
+    /**
+     * 股室上报项目到管理员
+     */
+    projectReport() {
+      this.$confirm('确认上报至管理员进行审核?').then(ele => {
+        if (ele === 'confirm') {
+          this.$api.project.upReportType({ id: this.projectId }).then(res => {
+            if (res.code === 200) {
+              this.$message.success(res.msg)
+              this.getInfo()
+            } else {
+              this.$message.error(res.msg)
+            }
+          })
+        }
+      })
+    },
+    /**
+     * 管理员已经审核通过的项目,上报到固定资产
+     */
+    projectReportFormal() {
+      this.$confirm('确定上报到固定资产?').then(res => {
+        if (res === 'confirm') {
+          this.$api.project
+            .reportToAssets({ ids: this.projectId })
+            .then(res => {
+              if (res.code === 200) {
+                this.$message.success(res.msg)
+                this.getInfo()
+              } else {
+                this.$message.error(res.msg)
+              }
+            })
+        }
+      })
+    },
+    /**
+     * 项目退库
+     */
+    projectCancel() {
+      this.$prompt('请输入退库原因', '提示', {}).then(({ value }) => {
+        if (value === null || value.length === 0) {
+          this.$message.error('请输入退库原因')
+          return
+        }
+        this.$api.project
+          .projectCancel({ id: this.projectId, exitMsg: value })
+          .then(res => {
+            if (res.code === 200) {
+              this.$message.success(res.msg)
+              this.getInfo()
+            } else {
+              this.$message.error(res.msg)
+            }
+          })
+      })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.bottom {
+  position: fixed;
+  bottom: 0;
+  z-index: 3;
+  height: 68px;
+  width: 1300px;
+  background-color: white;
+  box-shadow: 0px -5px 10px rgba(52, 52, 52, 0.1);
+}
+</style>

+ 15 - 5
src/views/resource/component/preview.vue

@@ -1,6 +1,6 @@
 <template>
   <div>
-    <div @click="detail">
+    <div @click="detail" class="pointer">
       <slot name="title">
         <el-button type="primary" text>查看</el-button>
       </slot>
@@ -10,7 +10,7 @@
       :url-list="preList"
       @close="showImage = false"
     />
-    <el-drawer v-model="show" :size="1200">
+    <el-drawer v-model="show" :size="1200" append-to-body>
       <template #title>
         <h4
           class="ml-20 black flex flex-center flex-justify-start full-width font-16 bold"
@@ -32,8 +32,8 @@
           v-if="isAccess === 2 || showAction"
         >
           <el-button type="primary" icon="Download" @click="downloadClick"
-            >下 载</el-button
-          >
+            >下 载
+          </el-button>
           <share
             class="ml-20"
             :project-id="projectId"
@@ -83,12 +83,20 @@ export default {
       show: false,
       data: null,
       preList: [],
-      showImage: false
+      showImage: false,
+      watermarkOptions: {
+        content: 'watermark',
+        gap: [20, 20],
+        offset: [10, 10],
+        zIndex: 5,
+        rotate: -20
+      }
     }
   },
   methods: {
     detail() {
       if (Number(this.id, 10).toString() === 'NaN') {
+        console.log('yyyy')
         // 如果id 不是数字开头,即mongo 62开头的id,查看文章详情
         this.$api.resource.fileDetail(this.id).then(res => {
           if (res.code === 200) {
@@ -134,6 +142,7 @@ export default {
   width: 960px;
   padding: 20px;
 }
+
 .bottom {
   position: fixed;
   bottom: 0;
@@ -144,6 +153,7 @@ export default {
   width: 1200px;
   border: #e6e8ed solid 1px;
 }
+
 :deep(.el-drawer__body) {
   padding: 0;
 }

+ 5 - 2
src/views/resource/component/row1.vue

@@ -53,8 +53,11 @@
         <img v-else src="../../../assets/svg/folder/other.svg" />
       </div>
       <el-tooltip :content="info[column.prop]">
-        <div class="lines-2 padding-right">
-          {{ info[column.prop] }}
+        <div class="padding-right flex flex-align-end flex-justify-start">
+          <div class="lines-2">{{ info[column.prop] }}</div>
+          <div class="font-12 grey-6 ml-10" v-if="info.type === 2">
+            (包含{{ info.fileAmount }}文件)
+          </div>
         </div>
       </el-tooltip>
     </div>

+ 10 - 6
src/views/resource/index.vue

@@ -2,13 +2,11 @@
   <div>
     <tips-custom>
       <template #default>
-        <div class="flex flex-center">
-          <span class="mr-10 nowrap">项目阶段</span>
+        <div class="flex flex-center picker white-bg border radius-5">
+          <span class="padding" style="width: 100px">项目阶段</span>
           <el-select
             v-model="folderInfo.stageId"
-            remote
-            filterable
-            style="width: 200px"
+            style="width: 260px"
             clearable
             placeholder="筛选项目阶段"
             :disabled="!top"
@@ -17,7 +15,7 @@
             <el-option
               v-for="item in stage"
               :key="item.id"
-              :label="item.name"
+              :label="item.name + `,包含 ` + item.fileAmount + ` 个文件`"
               :value="item.id"
             >
             </el-option>
@@ -356,4 +354,10 @@ export default {
 .content {
   height: auto;
 }
+.picker {
+  border: #a3773d solid 1px;
+  :deep(.el-input__wrapper) {
+    box-shadow: none;
+  }
+}
 </style>

+ 4 - 1
src/views/task/component/task-table.vue

@@ -22,7 +22,10 @@
           class="flex-child-shrink flex flex-justify-start first"
           :style="`width:` + item.width + 'px'"
         >
-          共 {{ total }}个任务
+          共<span class="main-color main-color font-16"
+            >&nbsp;{{ total }}&nbsp;</span
+          >
+          个任务
         </div>
         <div v-else class="flex-child-average">
           {{ item.label }}

+ 10 - 0
yarn.lock

@@ -7,6 +7,11 @@
   resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf"
   integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==
 
+"@amap/amap-jsapi-loader@^1.0.1":
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/@amap/amap-jsapi-loader/-/amap-jsapi-loader-1.0.1.tgz#9ec4b4d5d2467eac451f6c852e35db69e9f9f0c0"
+  integrity sha512-nPyLKt7Ow/ThHLkSvn2etQlUzqxmTVgK7bIgwdBRTg2HK5668oN7xVxkaiRe3YZEzGzfV2XgH5Jmu2T73ljejw==
+
 "@babel/parser@^7.20.15", "@babel/parser@^7.21.3":
   version "7.22.5"
   resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.5.tgz#721fd042f3ce1896238cf1b341c77eb7dee7dbea"
@@ -1044,6 +1049,11 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.2:
     shebang-command "^2.0.0"
     which "^2.0.1"
 
+crypto-js@^4.1.1:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.1.1.tgz#9e485bcf03521041bd85844786b83fb7619736cf"
+  integrity sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==
+
 cssesc@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"