浏览代码

Merge branch 'Test' into 'master'

Test

See merge request crowd-2019/crowd-test-service-front!8
薛晓波 5 年之前
父节点
当前提交
1d5814e157
共有 76 个文件被更改,包括 12750 次插入2927 次删除
  1. 2 1
      build/webpack.dev.conf.js
  2. 3 1
      config/dev.env.js
  3. 5 5
      config/index.js
  4. 3 1
      config/prod.env.js
  5. 9 0
      config/proxyConfig.js
  6. 443 309
      package-lock.json
  7. 9 5
      package.json
  8. 49 5
      src/App.vue
  9. 296 99
      src/components/Home.vue
  10. 36 36
      src/components/InstitutionRank.vue
  11. 363 205
      src/components/Mine.vue
  12. 30 38
      src/components/PersonRank.vue
  13. 96 307
      src/components/Square.vue
  14. 458 0
      src/components/authen/AgencyAuthentication.vue
  15. 429 0
      src/components/authen/AgencyAuthenticationCreate.vue
  16. 77 0
      src/components/authen/AuthenticationIndex.vue
  17. 362 0
      src/components/authen/AuthenticationManage.vue
  18. 360 0
      src/components/authen/EnterpriseAuthentication.vue
  19. 332 0
      src/components/authen/EnterpriseAuthenticationCreate.vue
  20. 349 0
      src/components/authen/IndividualAuthentication.vue
  21. 307 0
      src/components/authen/IndividualAuthenticationCreate.vue
  22. 525 0
      src/components/cheat/AgencyAdd.vue
  23. 343 0
      src/components/cheat/AgencyDetail.vue
  24. 683 0
      src/components/cheat/ProjectAdd.vue
  25. 795 245
      src/components/commons/Header.vue
  26. 116 55
      src/components/commons/ProjectItem.vue
  27. 9 3
      src/components/commons/ProvinceCity.vue
  28. 5 0
      src/components/commons/TaskCard.vue
  29. 61 53
      src/components/commons/TaskItem.vue
  30. 6 0
      src/components/project/AnalyseDemand.vue
  31. 871 524
      src/components/project/Project.vue
  32. 429 179
      src/components/project/ProjectCreate.vue
  33. 300 0
      src/components/report/ProjectReport.vue
  34. 281 0
      src/components/report/ProjectReportCreate.vue
  35. 0 221
      src/components/report/Report.vue
  36. 0 173
      src/components/report/ReportCreate.vue
  37. 68 54
      src/components/report/ReportList.vue
  38. 300 0
      src/components/report/TaskReport.vue
  39. 261 0
      src/components/report/TaskReportCreate.vue
  40. 614 187
      src/components/task/Task.vue
  41. 301 129
      src/components/task/TaskCreate.vue
  42. 2 2
      src/constants/enum/index.js
  43. 10 0
      src/constants/enum/report-type.js
  44. 7 0
      src/constants/enum/resource-type.js
  45. 52 24
      src/constants/index.js
  46. 81 0
      src/js/api.js
  47. 44 0
      src/js/fileService.js
  48. 167 0
      src/js/generalService.js
  49. 116 0
      src/js/http.js
  50. 784 0
      src/js/index.js
  51. 65 0
      src/js/projectService.js
  52. 48 0
      src/js/reportService.js
  53. 69 0
      src/js/taskService.js
  54. 0 0
      src/js/test.js
  55. 310 0
      src/js/userService.js
  56. 180 43
      src/main.js
  57. 32 0
      src/mock.js
  58. 6 0
      src/mock/createAnalyseDemandMock.js
  59. 6 0
      src/mock/createProjectMock.js
  60. 6 0
      src/mock/createReportMock.js
  61. 6 0
      src/mock/createTaskMock.js
  62. 96 0
      src/mock/getHomePageMock.js
  63. 139 0
      src/mock/getMyCrowdTestMock.js
  64. 57 0
      src/mock/getProjectDetailMock.js
  65. 27 0
      src/mock/getReportDetailMock.js
  66. 100 0
      src/mock/getSquarePageMock.js
  67. 84 0
      src/mock/getTaskDetailMock.js
  68. 10 0
      src/mock/test.js
  69. 6 0
      src/mock/updateProjectMock.js
  70. 6 0
      src/mock/updateReportMock.js
  71. 6 0
      src/mock/updateTaskMock.js
  72. 179 20
      src/router/index.js
  73. 21 0
      src/store/index.js
  74. 3 3
      src/style/main.scss
  75. 11 0
      tool4deploy/Dockerfile
  76. 28 0
      tool4deploy/conf.d/nginx.conf

+ 2 - 1
build/webpack.dev.conf.js

@@ -42,7 +42,8 @@ const devWebpackConfig = merge(baseWebpackConfig, {
     quiet: true, // necessary for FriendlyErrorsPlugin
     watchOptions: {
       poll: config.dev.poll,
-    }
+    },
+    disableHostCheck: true, //  开发环境使用true方便开发,生产环境使用false
   },
   plugins: [
     new webpack.DefinePlugin({

+ 3 - 1
config/dev.env.js

@@ -3,5 +3,7 @@ const merge = require('webpack-merge')
 const prodEnv = require('./prod.env')
 
 module.exports = merge(prodEnv, {
-  NODE_ENV: '"development"'
+  NODE_ENV: '"development"',
+  API_ROOT: '"//crowd.mooctest.net"',
+  LOGIN_URL: '"http://user.mooctest.net:8081/page/login?redirect=http%3a%2f%2fcrowd.dev.mooctest.net%2f%23%2fmine"'
 })

+ 5 - 5
config/index.js

@@ -3,18 +3,18 @@
 // see http://vuejs-templates.github.io/webpack for documentation.
 
 const path = require('path')
-
+const proxyTable = require('./proxyConfig')
 module.exports = {
   dev: {
 
     // Paths
     assetsSubDirectory: 'static',
     assetsPublicPath: '/',
-    proxyTable: {},
+    proxyTable: proxyTable,
 
     // Various Dev Server settings
     host: 'localhost', // can be overwritten by process.env.HOST
-    port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
+    port: 5757, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
     autoOpenBrowser: false,
     errorOverlay: true,
     notifyOnErrors: true,
@@ -50,13 +50,13 @@ module.exports = {
     // Paths
     assetsRoot: path.resolve(__dirname, '../dist'),
     assetsSubDirectory: 'static',
-    assetsPublicPath: '/',
+    assetsPublicPath: './',
 
     /**
      * Source Maps
      */
 
-    productionSourceMap: true,
+    productionSourceMap: false,
     // https://webpack.js.org/configuration/devtool/#production
     devtool: '#source-map',
 

+ 3 - 1
config/prod.env.js

@@ -1,4 +1,6 @@
 'use strict'
 module.exports = {
-  NODE_ENV: '"production"'
+  NODE_ENV: '"production"',
+  API_ROOT: '"//crowd.mooctest.net"',
+  LOGIN_URL:'"http://user.mooctest.net:8081/page/login?redirect=http%3a%2f%2fcrowd.mooctest.net%2f%23%2fmine"'
 }

+ 9 - 0
config/proxyConfig.js

@@ -0,0 +1,9 @@
+module.exports = {
+  '/api': {
+    target: 'http://localhost:8080/', // 设置你调用的接口域名和端口号
+    changeOrigin: true,     // 跨域
+    pathRewrite: {
+      '^/api': '/'
+    }
+  },
+}

文件差异内容过多而无法显示
+ 443 - 309
package-lock.json


+ 9 - 5
package.json

@@ -11,10 +11,14 @@
     "build": "node build/build.js"
   },
   "dependencies": {
-    "element-ui": "^2.8.2",
+    "axios": "latest",
+    "echarts": "^4.2.1",
+    "element-ui": "^2.11.0",
     "font-awesome": "^4.7.0",
+    "mockjs": "^1.0.1-beta3",
     "vue": "^2.5.2",
-    "vue-router": "^3.0.1"
+    "vue-router": "^3.0.1",
+    "vuex": "^3.1.1"
   },
   "devDependencies": {
     "autoprefixer": "^7.1.2",
@@ -29,7 +33,7 @@
     "babel-preset-stage-2": "^6.22.0",
     "chalk": "^2.0.1",
     "copy-webpack-plugin": "^4.0.1",
-    "css-loader": "^0.28.0",
+    "css-loader": "^3.2.0",
     "eslint": "^4.15.0",
     "eslint-config-standard": "^10.2.1",
     "eslint-friendly-formatter": "^3.0.0",
@@ -58,12 +62,12 @@
     "semver": "^5.3.0",
     "shelljs": "^0.7.6",
     "uglifyjs-webpack-plugin": "^1.1.1",
-    "url-loader": "^0.5.8",
+    "url-loader": "^2.1.0",
     "vue-loader": "^13.3.0",
     "vue-style-loader": "^3.0.1",
     "vue-template-compiler": "^2.5.2",
     "webpack": "^3.6.0",
-    "webpack-bundle-analyzer": "^2.9.0",
+    "webpack-bundle-analyzer": "^3.4.1",
     "webpack-dev-server": "^2.9.1",
     "webpack-merge": "^4.1.0"
   },

+ 49 - 5
src/App.vue

@@ -1,7 +1,9 @@
 <template>
   <div style="height:100%;width:100%;">
     <header-container/>
-    <div class="main-container"><router-view/></div>
+    <div class="main-container">
+      <router-view/>
+    </div>
     <footer-container/>
   </div>
 </template>
@@ -9,18 +11,60 @@
 <script>
 import HeaderContainer from '@/components/commons/Header'
 import FooterContainer from '@/components/commons/Footer'
+import {getCurrentUser, storageGet, storageSave} from '@/js/index'
 
 export default {
   name: 'App',
-  components:{HeaderContainer,FooterContainer},
-  name: 'App'
+  components: {HeaderContainer, FooterContainer},
+  methods: {
+    setUserInfo () {
+      // storageGet('user').then((res)=>{
+      //   if (res == null){
+      //     this.setCurrUserByHttp()
+      //   }else{
+      //     this.fullScreenLoading = false
+      //     this.isLogin = true
+      //   }
+      // }).catch((error)=>{
+      //   this.setCurrUserByHttp()
+      // })
+
+
+      // if (storageGet('user') == null) {
+      //   storageSave('rolesPermissions', {
+      //     'isRegionManager': false,
+      //     'isIndividualUser': false,
+      //     'isEnterpriseUser': false,
+      //     'isAgency': false,
+      //     'isSystemAdministrator': false
+      //   })
+      //   console.log('本地没有用户信息,开始加载用户信息')
+      //   getCurrentUser().then((res) => {
+      //     console.log(res)
+      //     storageSave('user', res)
+      //     storageSave('rolesPermissions', getRolesPermissions(res.roleList))
+      //     console.log('用户信息加载成功')
+      //   }).catch(error => {
+      //     console.log('用户信息加载失败')
+      //     if (error.status == 401) {
+      //       notify('warning', error.data)
+      //     } else {
+      //       notify('error', error.data)
+      //     }
+      //   })
+      // } else {
+      //   this.fullScreenLoading = false
+      //   this.isLogin = true
+      // }
+    },
+  }
 }
 </script>
 
 <style>
-.main-container{
+  .main-container {
     width: 100%;
     min-height: calc(100% - 70px - 64px);
     margin: 0 auto;
-}
+  }
 </style>

+ 296 - 99
src/components/Home.vue

@@ -1,17 +1,148 @@
 <template>
-  <div class="home-container">
+  <div class="home-container" v-loading="loading">
     <div class="home-banner-wrap">
       <el-carousel height="400px" :interval="10000" arrow="always">
-        <el-carousel-item>
-          <img class="banner_back banner_back_1" src="@/assets/img/home_ban1.jpg">
-          <router-link :to="{ name: 'ProjectCreate'}"><div class="btn btn-medium btn-home-apply">申请项目</div></router-link>
-        </el-carousel-item>
-        <el-carousel-item>
-          <img class="banner_back banner_back_2" src="@/assets/img/home_ban2.png">
+        <el-carousel-item v-for="(img,index) in imgList" :key="index">
+          <img class="banner_back banner_back_1" v-bind:src="img">
+          <router-link
+            v-if="user != null && rolesPermissions != null &&( rolesPermissions.isAgency || rolesPermissions.isIndividualUser || rolesPermissions.isSystemAdministrator || rolesPermissions.isEnterpriseUser)"
+            :to="{ name: 'ProjectCreate'}">
+              <el-button class="btn-home-apply" type="primary">创建项目</el-button>
+          </router-link>
         </el-carousel-item>
       </el-carousel>
     </div>
     <div class="home-body-wrap">
+      <div class="title h2">系统统计信息</div>
+      <el-row type="flex" align="middle" justify="center" style="font-size: 14px;">
+        <el-col :span="6" type="flex" align="middle" justify="center" >
+          <el-card class="box-card" shadow="hover" style="margin-right: 40px; background-color: #20A0FF;">
+            <div slot="header" class="clearfix">
+              <span style="font-size: 30px;color: white"><i class="el-icon-user"></i></span>
+            </div>
+            <el-row type="flex" align="middle" justify="center" style="font-size: 14px;">
+              <el-col :span="18" type="flex" align="middle" justify="start"><span style="font-size: 50px; color: white;">{{systemStatistics[0].value}}</span>
+              </el-col>
+              <el-col :span="20" type="flex" align="bottom" justify="end"><span> <el-link style="font-size: 16px; color: white;"
+                                                                                          type="success"
+                                                                                          :underline="false">{{systemStatistics[0].name}}</el-link></span>
+              </el-col>
+            </el-row>
+          </el-card>
+        </el-col>
+        <el-col :span="6" type="flex" align="middle" justify="center">
+          <el-card class="box-card" shadow="hover" style="margin-right: 40px;background-color: #13CE66;">
+            <div slot="header" class="clearfix">
+              <span style="font-size: 30px;color: white;"><i class="el-icon-setting"></i></span>
+            </div>
+            <el-row type="flex" align="middle" justify="center" style="font-size: 14px;">
+              <el-col :span="18" type="flex" align="middle" justify="start"><span style="font-size: 50px;color: white;">{{systemStatistics[1].value}}</span>
+              </el-col>
+              <el-col :span="20" type="flex" align="bottom" justify="end"><span> <el-link style="font-size: 16px;color: white;"
+                                                                                          type="success"
+                                                                                          :underline="false">{{systemStatistics[1].name}}</el-link></span>
+              </el-col>
+            </el-row>
+          </el-card>
+        </el-col>
+        <!--<el-col :span="4">{{project.id}}</el-col>-->
+        <el-col :span="6" type="flex" align="middle" justify="center">
+          <el-card class="box-card" shadow="hover" style="margin-right: 40px;background-color: #F7BA2A;">
+            <div slot="header" class="clearfix">
+              <span style="font-size: 30px;color: white;"><i class="el-icon-user-solid"></i></span>
+            </div>
+            <el-row type="flex" align="middle" justify="center" style="font-size: 14px;">
+              <el-col :span="18" type="flex" align="middle" justify="start"><span style="font-size: 50px;color: white;">{{systemStatistics[2].value}}</span>
+              </el-col>
+              <el-col :span="20" type="flex" align="bottom" justify="end"><span> <el-link style="font-size: 16px;color: white;"
+                                                                                          type="success"
+                                                                                          :underline="false">{{systemStatistics[2].name}}</el-link></span>
+              </el-col>
+            </el-row>
+          </el-card>
+        </el-col>
+        <el-col :span="6" type="flex" align="middle" justify="center">
+          <el-card class="box-card" shadow="hover" style="margin-right: 40px;background-color: #FF4949;">
+            <div slot="header" class="clearfix">
+              <span style="font-size: 30px;color: white;"><i class="el-icon-cpu"></i></span>
+            </div>
+            <el-row type="flex" align="middle" justify="center" style="font-size: 14px;">
+              <el-col :span="18" type="flex" align="middle" justify="start"><span style="font-size: 50px;color: white;">{{systemStatistics[3].value}}</span>
+              </el-col>
+              <el-col :span="20" type="flex" align="bottom" justify="end"><span> <el-link style="font-size: 16px;color: white;"
+                                                                                          type="success"
+                                                                                          :underline="false">{{systemStatistics[3].name}}</el-link></span>
+              </el-col>
+            </el-row>
+          </el-card>
+        </el-col>
+      </el-row>
+      <el-row type="flex" align="middle" justify="center" style="font-size: 14px; margin-top: 15px;">
+        <el-col :span="6" type="flex" align="middle" justify="center">
+          <el-card class="box-card" shadow="hover" style="margin-right: 40px;background-color: #20A0FF;">
+            <div slot="header" class="clearfix">
+              <span style="font-size: 30px;color: white;"><i class="el-icon-coin"></i></span>
+            </div>
+            <el-row type="flex" align="middle" justify="center" style="font-size: 14px;">
+              <el-col :span="18" type="flex" align="middle" justify="start"><span style="font-size: 50px;color: white;">{{systemStatistics[4].value}}</span>
+              </el-col>
+              <el-col :span="20" type="flex" align="bottom" justify="end"><span> <el-link style="font-size: 16px;color: white;"
+                                                                                          type="success"
+                                                                                          :underline="false">{{systemStatistics[4].name}}</el-link></span>
+              </el-col>
+            </el-row>
+          </el-card>
+        </el-col>
+        <el-col :span="6" type="flex" align="middle" justify="center">
+          <el-card class="box-card" shadow="hover" style="margin-right: 40px;background-color: #13CE66;color: white;">
+            <div slot="header" class="clearfix">
+              <span style="font-size: 30px;color: white;"><i class="el-icon-bank-card"></i></span>
+            </div>
+            <el-row type="flex" align="middle" justify="center" style="font-size: 14px;">
+              <el-col :span="18" type="flex" align="middle" justify="start"><span style="font-size: 50px;color: white;">{{systemStatistics[5].value}}</span>
+              </el-col>
+              <el-col :span="20" type="flex" align="bottom" justify="end"><span> <el-link style="font-size: 16px;color: white;"
+                                                                                          type="success"
+                                                                                          :underline="false">{{systemStatistics[5].name}}</el-link></span>
+              </el-col>
+            </el-row>
+          </el-card>
+        </el-col>
+        <!--<el-col :span="4">{{project.id}}</el-col>-->
+        <el-col :span="6" type="flex" align="middle" justify="center">
+          <el-card class="box-card" shadow="hover" style="margin-right: 40px;background-color: #F7BA2A;">
+            <div slot="header" class="clearfix">
+              <span style="font-size: 30px;color: white;"><i class="el-icon-notebook-1"></i></span>
+            </div>
+            <el-row type="flex" align="middle" justify="center" style="font-size: 14px;">
+              <el-col :span="18" type="flex" align="middle" justify="start"><span style="font-size: 50px;color: white;">{{systemStatistics[6].value}}</span>
+              </el-col>
+              <el-col :span="20" type="flex" align="bottom" justify="end"><span> <el-link style="font-size: 16px;color: white;"
+                                                                                          type="success"
+                                                                                          :underline="false">{{systemStatistics[6].name}}</el-link></span>
+              </el-col>
+            </el-row>
+          </el-card>
+        </el-col>
+        <el-col :span="6" type="flex" align="middle" justify="center">
+          <el-card class="box-card" shadow="hover" style="margin-right: 40px;background-color: #FF4949;">
+            <div slot="header" class="clearfix">
+              <span style="font-size: 30px;color: white;"><i class="el-icon-notebook-2"></i></span>
+            </div>
+            <el-row type="flex" align="middle" justify="center" style="font-size: 14px;">
+              <el-col :span="18" type="flex" align="middle" justify="start"><span style="font-size: 50px;color: white;">{{systemStatistics[7].value}}</span>
+              </el-col>
+              <el-col :span="20" type="flex" align="bottom" justify="end"><span> <el-link style="font-size: 16px;color: white;"
+                                                                                          type="success"
+                                                                                          :underline="false">{{systemStatistics[7].name}}</el-link></span>
+              </el-col>
+            </el-row>
+          </el-card>
+        </el-col>
+
+      </el-row>
+    </div>
+    <div class="home-body-wrap">
       <div class="home-block">
         <div class="title">
           热门任务
@@ -20,21 +151,21 @@
           </span>
         </div>
         <el-row :gutter="20">
-          <el-col :span="6" v-for="item,index in taskList" :key="index">
+          <el-col :span="6" v-for="item,index in hotTaskList" :key="index">
             <task-card :item="item"/>
           </el-col>
         </el-row>
       </div>
 
-      <div  class="home-block">
+      <div class="home-block">
         <el-row :gutter="20">
-          <el-col  :xs="20" :sm="20" :md="20" :lg="12" :xl="12">
+          <el-col :xs="20" :sm="20" :md="20" :lg="12" :xl="12">
             <div class="title">机构排名</div>
-            <institution-rank />
+            <institution-rank :item="institutionRank"/>
           </el-col>
-          <el-col  :xs="20" :sm="20" :md="20" :lg="12" :xl="12">
-              <div class="title">用户排名</div>
-              <person-rank />
+          <el-col :xs="20" :sm="20" :md="20" :lg="12" :xl="12">
+            <div class="title">用户排名</div>
+            <person-rank :item="personRank"/>
           </el-col>
         </el-row>
 
@@ -44,103 +175,169 @@
 </template>
 
 <script>
-import TaskCard from "@/components/commons/TaskCard";
-import InstitutionRank from "@/components/InstitutionRank";
-import PersonRank from "@/components/PersonRank";
+import TaskCard from '@/components/commons/TaskCard'
+import InstitutionRank from '@/components/InstitutionRank'
+import PersonRank from '@/components/PersonRank'
+import Http from '@/js/http.js'
+import Apis from '@/js/api.js'
+import {notify} from '@/constants/index'
+import {defaultValue, getIndexStatisticsInfo, getRolesPermissions, storageGet} from '@/js/index'
+
 export default {
-  name: "Home",
-  components: { TaskCard, InstitutionRank, PersonRank },
-  data() {
+  name: 'Home',
+  components: {TaskCard, InstitutionRank, PersonRank},
+  data () {
     return {
-      taskList: [
-        {
-          id: 0,
-          title: "发送群文件测试",
-          description: "任务描述文字xxxx",
-          price: "30",
-          serviceType: 1,
-          status: 0,
-          projectId:123
-        },
-        {
-          id: 1,
-          title: "多人聊天发送文件测试",
-          description: "任务描述文字xxxx",
-          price: "10",
-          serviceType: 0,
-          status: 1,
-          projectId:234
-        },
-        {
-          id: 2,
-          title: "浏览器波洞星球",
-          description: "任务描述文字xxxx",
-          price: "10",
-          serviceType: 2,
-          status: 0,
-          projectId:345
-        },
-        {
-          id: 3,
-          title: "举报支持选择聊天记录(安全)",
-          description: "任务描述文字xxxx",
-          price: "0",
-          serviceType: 1,
-          status: 1,
-          projectId:456
-        }
-      ]
-    };
+      user: null,
+      loading: false,
+      defaultValue: defaultValue,
+      hotTaskList: [],
+      institutionRank: [],
+      personRank: [],
+      imgList: [],
+      rolesPermissions: {},
+      statisticsData: {
+        userNum: 100,
+        agencyNum: 200,
+        deviceNum: 345,
+        projectNum: 23,
+        taskNum: 123
+      },
+        systemStatistics: [{},{},{},{},{},{},{},{}]
+    }
   },
-  methods:{
+  mounted () {
+    console.log('mine mount')
+    this.$nextTick(() => {
+      this.init()
+    })
+  },
+  methods: {
+    init () {
+      // storageGet('user').then((res)=>{
+      //   if (res == null){
+      //     //notify('warning','请登录后访问')
+      //   }else{
+      //     this.user = res
+      //     this.setRolesPermissions()
+      //     this.loadData()
+      //   }
+      // }).catch((error)=>{
+      //   notify('error','用户信息获取失败')
+      // })
+      this.setUserInfo()
+      // if (this.rolesPermissions == null) {
+      //   let NewPage = '_empty' + '?time=' + new Date().getTime() / 500
+      //   this.$router.push(NewPage)
+      //   this.$router.go(-1)
+      // }
+      this.loadData()
+    },
+    //加载数据
+    loadData: function () {
+      this.showLoading()
+      console.log('loadData')
+      Http.get(Apis.PAGE.HOME_PAGE).then((res) => {
+        console.log(res)
+        this.hideLoading()
+        this.hotTaskList = res.hotTaskList
+        this.institutionRank = res.agencyRank
+        this.personRank = res.userRank
+        this.imgList = res.imgList
+        this.systemStatistics = res.systemStatistics
+      }).catch((error) => {
+        this.hideLoading()
+        notify('error', '主页加载失败:' + error.data)
+      })
+    },
+    setUserInfo () {
+      this.user = storageGet('user')
+      this.rolesPermissions = storageGet('rolesPermissions')
+    },
+    showLoading () {
+      this.loading = true
+    },
+    hideLoading () {
+      this.loading = false
+    },
+    getStatisticsData () {
+      getIndexStatisticsInfo().then((res) => {
+        this.statisticsData = res
+      }).catch((error) => {
+        notify('error', '统计数据加载失败')
+      })
+    },
+    getStatisticsDataSuccess () {
+
+    },
+    getStatisticsDataFail () {
+
+    }
+  },
+  created: function () {
+    //notify('info', 'info')
+    //notify('success', 'success')
+    //notify('error', 'error')
+    //notify('warning', 'warning')
+    //this.loadData()
+  },
+  watch: {
+    rolesPermissions (val) {
+      console.log(this.rolesPermissions)
+      console.log(val)
+      this.rolesPermissions = val
+    }
   }
-};
+}
 </script>
 
 <style lang="less" scoped>
-.home-banner-wrap {
-  background: linear-gradient(#4a90e2, rgb(74, 109, 226));
-  background: -webkit-linear-gradient(#4a90e2, rgb(74, 109, 226));
-  background: -o-linear-gradient(#4a90e2, rgb(74, 109, 226));
-  .banner_back {
-    height: 100%;
+  .home-banner-wrap {
+    background: linear-gradient(#4a90e2, rgb(74, 109, 226));
+    background: -webkit-linear-gradient(#4a90e2, rgb(74, 109, 226));
+    background: -o-linear-gradient(#4a90e2, rgb(74, 109, 226));
+    .banner_back {
+      height: 100%;
+    }
+    .banner_back_1 {
+      width: 100%;
+      //float: right;
+    }
   }
-  .banner_back_1 {
-    float: right;
+
+  .el-carousel__item h3 {
+    color: #475669;
+    font-size: 14px;
+    opacity: 0.75;
+    line-height: 150px;
+    margin: 0;
   }
-}
 
-.el-carousel__item h3 {
-  color: #475669;
-  font-size: 14px;
-  opacity: 0.75;
-  line-height: 150px;
-  margin: 0;
-}
+  .el-carousel__item:nth-child(2n) {
+    background-color: #bed2c0;
+  }
 
-.el-carousel__item:nth-child(2n) {
-  background-color: #bed2c0;
-}
+  .el-carousel__item:nth-child(2n + 1) {
+    background-color: #eeeef2;
+  }
 
-.el-carousel__item:nth-child(2n + 1) {
-  background-color: #eeeef2;
-}
+  .home-body-wrap {
+    padding: 20px 80px;
+  }
 
-.home-body-wrap {
-  padding: 40px 80px;
-}
-.more-info {
-  float: right;
-  cursor: pointer;
-  font-size: 1.4rem;
-}
-.btn-home-apply {
-  position: absolute;
-  bottom: 10%;
-  left: 20%;
-}
+  .more-info {
+    float: right;
+    cursor: pointer;
+    font-size: 1.4rem;
+  }
 
-.home-block{
-  margin:10px 0;
-}
+  .btn-home-apply {
+    position: absolute;
+    bottom: 15%;
+    left: 80%;
+  }
+
+  .home-block {
+    margin: 10px 0;
+  }
 </style>

+ 36 - 36
src/components/InstitutionRank.vue

@@ -1,55 +1,55 @@
 <template>
   <div>
-    <el-table :data="tableData"  :showHeader="false" border style="width: 100%">
-      <el-table-column type="index" width="50"></el-table-column>
-      <el-table-column prop="logo" width="120">
+    <el-table :data="tableData" :showHeader="true" border style="width: 100%">
+      <el-table-column type="index" width="50" label="排名"></el-table-column>
+      <el-table-column prop="logo" width="120" label="机构logo">
+        <template slot-scope="scope" >
+          <img class="logo-img" :src="scope.row.logo==null?defaultValue.image:scope.row.logo"/>
+        </template>
+      </el-table-column>
+      <el-table-column prop="name" label="机构名称">
+        <template slot-scope="scope"><span class="institution-name" style="font-size: 12px">{{scope.row.name}}</span></template>
+      </el-table-column>
+      <el-table-column prop="name" label="金额">
         <template slot-scope="scope">
-            <img class="logo-img" :src="scope.row.logo"/>
+          <span class="institution-name" style="font-size: 12px">
+            {{scope.row.allTaskPrice}}
+          </span>
         </template>
       </el-table-column>
-      <el-table-column prop="name"><template slot-scope="scope"><span class="institution-name">{{scope.row.name}}</span></template></el-table-column>
     </el-table>
   </div>
 </template>
 
 <script>
+import {defaultValue} from '@/js/index'
+
 export default {
-  name: "InstitutionRank",
-  data() {
+  name: 'InstitutionRank',
+  props: {item: {}},
+  data () {
     return {
-      tableData: [
-        {
-          logo: "http://www.mooctest.net/assets/img/mooctest.png",
-          name: "慕测科技"
-        },
-        {
-          logo: "https://docs.alibabagroup.com/assets2/images/cn/global/logo_header.png",
-          name: "上海软件"
-        },
-        {
-          logo: "http://www.mooctest.net/assets/img/mooctest.png",
-          name: "QQ众测"
-        },
-        {
-          logo: "https://docs.alibabagroup.com/assets2/images/cn/global/logo_header.png",
-          name: "阿里巴巴"
-        },
-        {
-          logo: "https://docs.alibabagroup.com/assets2/images/cn/global/logo_header.png",
-          name: "阿里巴巴"
-        }
-      ]
-    };
+      tableData: this.item,
+      defaultValue: defaultValue
+    }
+  },
+  watch: {
+    item () {
+      this.tableData = this.item
+    }
   }
-};
+}
 </script>
 
 <style lang="less" scoped>
-.logo-img{
-    width:100px
-}
-.institution-name{
+  .logo-img {
+    height: 50px;
+    width: 100px;
+    object-fit: contain;
+  }
+
+  .institution-name {
     font-size: 16px;
     font-weight: 600;
-}
+  }
 </style>

+ 363 - 205
src/components/Mine.vue

@@ -1,232 +1,390 @@
-
 <template>
   <div class="mine-container">
-    <div class="mine-top-wrapper">
-      <el-row :gutter="0" style="height:100%">
-        <el-col :span="16">
-          <div class="advertise-imgs">
-            <img
-              src="http://sinastorage.com/storage.miaosha.sina.com.cn/products/201903/e496d11b3d74cf660c286fbd5ab8d0bb.png"
-            >
-          </div>
-        </el-col>
-        <el-col :span="8">
-          <div class="user-banner">
-            <p class="head">
-              <a href="javascript:;" class="login-link">
-                <img src="http://www.mooctest.net/assets/img/mooctest.png" class="user-img">
-                <span class="vertify hide"></span>
-              </a>
-            </p>
-            <div class="username_box">
-              <div class="username_icon username_"></div>
-              <span class="username">小明</span>
-            </div>
-            <p class="name">
-              <a href="javascript:;" class="login-btn btn btn-medium btn-info">登录</a>
-              <a
-                href="https://login.sina.com.cn/signup/signup?entry=tech"
-                class="register-btn btn btn-medium btn-info"
-                target="_blank"
-              >注册</a>
-            </p>
-            <p class="scores">
-              <a href="/rule/merit" target="_blank">
-                积分
-                <em class="num1">--</em>
-              </a>
-              <span class="line">|</span>
-              <a href="/rule/merit" target="_blank">
-                威望
-                <em class="num2">--</em>
-              </a>
-            </p>
-            <p>
-              <router-link :to="{ name: 'ProjectCreate'}">
-                <div class="btn btn-medium">申请项目</div>
-              </router-link>
-            </p>
-          </div>
-        </el-col>
-      </el-row>
-    </div>
-    <div class="mine-body">
-      <el-tabs tabPosition="top" type="card">
-        <el-tab-pane label="未完成任务">
-          <task-item v-for="(item,index) in taskList1" :key="index" :taskId="item.id"/>
+    <div id="myChart" style="width: 100%;height: 200px;padding-top: 40px"></div>
+    <!--<div class="mine-top-wrapper">-->
+    <!--<el-row :gutter="0" style="height:100%">-->
+    <!--<el-col :span="16">-->
+    <!--<div class="advertise-imgs">-->
+    <!--<img-->
+    <!--src="http://sinastorage.com/storage.miaosha.sina.com.cn/products/201903/e496d11b3d74cf660c286fbd5ab8d0bb.png"-->
+    <!--&gt;-->
+    <!--</div>-->
+    <!--</el-col>-->
+    <!--<el-col :span="8">-->
+    <!--<div class="user-banner">-->
+    <!--<p class="head">-->
+    <!--<a href="javascript:;" class="login-link">-->
+    <!--<img :src="user == null || user.userVO.photoUrl == null?defaultValue.image:user.userVO.photoUrl"-->
+    <!--class="user-img">-->
+    <!--<span class="vertify hide"></span>-->
+    <!--</a>-->
+    <!--</p>-->
+    <!--<div class="username_box">-->
+    <!--<div class="username_icon username_"></div>-->
+    <!--<span class="username">{{user == null?'...':user.userVO.name}}</span>-->
+    <!--</div>-->
+    <!--&lt;!&ndash;<p class="name">&ndash;&gt;-->
+    <!--&lt;!&ndash;<a href="javascript:;" class="login-btn btn btn-medium btn-info">登录</a>&ndash;&gt;-->
+    <!--&lt;!&ndash;<a&ndash;&gt;-->
+    <!--&lt;!&ndash;href="https://login.sina.com.cn/signup/signup?entry=tech"&ndash;&gt;-->
+    <!--&lt;!&ndash;class="register-btn btn btn-medium btn-info"&ndash;&gt;-->
+    <!--&lt;!&ndash;target="_blank"&ndash;&gt;-->
+    <!--&lt;!&ndash;&gt;注册</a>&ndash;&gt;-->
+    <!--&lt;!&ndash;</p>&ndash;&gt;-->
+    <!--&lt;!&ndash;<p class="scores">&ndash;&gt;-->
+    <!--&lt;!&ndash;<a href="/rule/merit" target="_blank">&ndash;&gt;-->
+    <!--&lt;!&ndash;积分&ndash;&gt;-->
+    <!--&lt;!&ndash;<em class="num1">{{user.score}}</em>&ndash;&gt;-->
+    <!--&lt;!&ndash;</a>&ndash;&gt;-->
+    <!--&lt;!&ndash;<span class="line">|</span>&ndash;&gt;-->
+    <!--&lt;!&ndash;<a href="/rule/merit" target="_blank">&ndash;&gt;-->
+    <!--&lt;!&ndash;威望&ndash;&gt;-->
+    <!--&lt;!&ndash;<em class="num2">{{user.prestige}}</em>&ndash;&gt;-->
+    <!--&lt;!&ndash;</a>&ndash;&gt;-->
+    <!--&lt;!&ndash;</p>&ndash;&gt;-->
+    <!--<p>-->
+    <!--<router-link :to="{ name: 'AuthenticationIndex'}">-->
+    <!--<div class="btn btn-medium">实名认证</div>-->
+    <!--</router-link>-->
+    <!--</p>-->
+    <!--</div>-->
+    <!--</el-col>-->
+    <!--</el-row>-->
+    <!--</div>-->
+    <div class="mine-body" style="text-align: center;">
+      <el-tabs value="myProject" @tab-click="handleTabClick" v-loading="loading" style="width: 90%;margin-left: 5%">
+        <el-tab-pane name="unFinishedTask">
+          <span slot="label">
+            <el-badge class="item" style="margin-top: 10px;margin-bottom: 25px; font-size: 16px;">未完成任务</el-badge>
+          </span>
+          <el-row v-if="unFinishedTaskList != null && unFinishedTaskList.length != 0" type="flex" align="middle"
+                  justify="center" style="font-size: 14px;">
+            <el-col :span="6">任务封面</el-col>
+            <el-col :span="5">任务名称</el-col>
+            <el-col :span="5">任务类型</el-col>
+            <el-col :span="4">任务预算</el-col>
+            <el-col :span="4">操作</el-col>
+          </el-row>
+          <span v-if="unFinishedTaskList == null || unFinishedTaskList.length == 0"> 暂无任务 </span>
+          <task-item v-if="unFinishedTaskList != null || unFinishedTaskList.length > 0"
+                     v-for="(item,index1) in unFinishedTaskList" :key="index1" :task="item"/>
         </el-tab-pane>
-        <el-tab-pane label="已完成任务">
-          <task-item v-for="(item,index) in taskList2" :key="index" :taskId="item.id"/>
+        <el-tab-pane name="finishedTask">
+          <span slot="label">
+            <el-badge class="item" style="margin-top: 10px;margin-bottom: 25px; font-size: 16px;">已完成任务</el-badge>
+          </span>
+          <el-row v-if="finishedTaskList != null && finishedTaskList.length != 0" type="flex" align="middle"
+                  justify="center" style="font-size: 14px;">
+
+            <el-col :span="6">任务封面</el-col>
+            <el-col :span="5">任务名称</el-col>
+            <el-col :span="5">任务类型</el-col>
+            <el-col :span="4">任务预算</el-col>
+            <el-col :span="4">操作</el-col>
+          </el-row>
+          <span v-if="finishedTaskList == null || finishedTaskList.length == 0"> 暂无任务 </span>
+          <task-item v-if="finishedTaskList != null || finishedTaskList.length > 0"
+                     v-for="(item,index2) in finishedTaskList" :key="index2" :task="item"/>
         </el-tab-pane>
-        <el-tab-pane label="已申请项目">
-          <project-item v-for="(item,index) in projectList1" :key="index" :projectId="item.id"/>
+
+
+        <el-tab-pane name="myProject">
+
+          <span slot="label">
+            <el-badge v-if="myProjectNoticeCount>0" :value="myProjectNoticeCount" class="item"
+                      style="height:auto;margin-top: 10px;margin-bottom: 25px; font-size: 16px;">我的项目</el-badge>
+            <el-badge v-if="myProjectNoticeCount==null || myProjectNoticeCount == 0" class="item"
+                      style="margin-top: 10px;margin-bottom: 25px; font-size: 16px;">我的项目</el-badge>
+          </span>
+          <span v-if="myProjects == null || myProjects.length == 0"> 暂无项目 </span>
+          <el-row v-if="myProjects != null && myProjects.length != 0" type="flex" align="middle" justify="center"
+                  style="font-size: 14px;">
+            <el-col :span="6" type="flex" align="middle" justify="center">项目图片</el-col>
+            <el-col :span="6" type="flex" align="middle" justify="center">项目名称</el-col>
+            <el-col :span="6" type="flex" align="middle" justify="center">项目平台</el-col>
+            <el-col :span="2" type="flex" align="middle" justify="center">项目预算</el-col>
+            <el-col :span="4" type="flex" align="middle" justify="center">操作</el-col>
+          </el-row>
+          <project-item v-if="myProjects != null || myProjects.length > 0"
+                        v-for="(item,index3) in myProjects" :key="index3" :projectItem="item"/>
+        </el-tab-pane>
+        <el-tab-pane name="handlingProject">
+          <span slot="label">
+            <el-badge v-if="processProjectNoticeCount>0" :value="processProjectNoticeCount" class="item"
+                      style="margin-top: 10px;margin-bottom: 25px; font-size: 16px;">处理中项目</el-badge>
+            <el-badge v-if="processProjectNoticeCount==null || processProjectNoticeCount==0" class="item"
+                      style="margin-top: 10px;margin-bottom: 25px; font-size: 16px;">处理中项目</el-badge>
+          </span>
+          <el-row v-if="handlingProjects != null && handlingProjects.length != 0" type="flex" align="middle"
+                  justify="center" style="font-size: 14px;">
+            <el-col :span="6">项目图片</el-col>
+            <el-col :span="6">项目名称</el-col>
+            <el-col :span="6">项目平台</el-col>
+            <el-col :span="2">项目预算</el-col>
+            <el-col :span="4">操作</el-col>
+          </el-row>
+          <span v-if="handlingProjects == null || handlingProjects.length == 0"> 暂无项目 </span>
+          <project-item v-if="handlingProjects != null || handlingProjects.length > 0"
+                        v-for="(item,index4) in handlingProjects" :key="index4" :projectItem="item"/>
+        </el-tab-pane>
+        <el-tab-pane name="acceptableProject">
+          <span slot="label">
+            <el-badge v-if="acceptableProjectNoticeCount>0" :value="acceptableProjectNoticeCount" class="item"
+                      style="margin-top: 10px;margin-bottom: 25px; font-size: 16px;">可接收项目</el-badge>
+            <el-badge v-if="acceptableProjectNoticeCount==null || acceptableProjectNoticeCount==0" class="item"
+                      style="margin-top: 10px;margin-bottom: 25px; font-size: 16px;">可接收项目</el-badge>
+          </span>
+          <el-row v-if="acceptableProjects != null && acceptableProjects.length != 0" type="flex" align="middle"
+                  justify="center" style="font-size: 14px;">
+            <el-col :span="6">项目图片</el-col>
+            <el-col :span="6">项目名称</el-col>
+            <el-col :span="6">项目平台</el-col>
+            <el-col :span="2">项目预算</el-col>
+            <el-col :span="4">操作</el-col>
+          </el-row>
+          <span v-if="acceptableProjects == null || acceptableProjects.length == 0"> 暂无项目 </span>
+          <project-item v-if="acceptableProjects != null || acceptableProjects.length > 0"
+                        v-for="(item,index) in acceptableProjects" :key="index" :projectItem="item"/>
         </el-tab-pane>
       </el-tabs>
     </div>
   </div>
 </template>
-      
+
 <script>
-import TaskItem from "@/components/commons/TaskItem";
-import ProjectItem from "@/components/commons/ProjectItem";
+import TaskItem from '@/components/commons/TaskItem'
+import ProjectItem from '@/components/commons/ProjectItem'
+import Http from '@/js/http.js'
+import Apis from '@/js/api.js'
+import {notify} from '@/constants/index'
+import {defaultValue, getRolesPermissions, storageGet} from '@/js/index'
+import echarts from 'echarts'
+
 export default {
-  name: "Mine",
-  components: { TaskItem, ProjectItem },
-  data() {
+  name: 'Mine',
+  components: {TaskItem, ProjectItem},
+  watch: {
+    user (val) {
+      this.user = val
+    },
+    rolesPermissions (val) {
+      this.rolesPermissions = val
+    },
+    deep: true
+  },
+  data () {
     return {
-      taskList1: [
-        {
-          id: 0,
-          title: "发送群文件测试",
-          description: "任务描述文字xxxx",
-          price: "30",
-          serviceType: 1,
-          status: 0
-        },
-        {
-          id: 1,
-          title: "多人聊天发送文件测试",
-          description: "任务描述文字xxxx",
-          price: "10",
-          serviceType: 0,
-          status: 1
-        },
-        {
-          id: 2,
-          title: "浏览器波洞星球",
-          description: "任务描述文字xxxx",
-          price: "10",
-          serviceType: 2,
-          status: 0
-        },
-        {
-          id: 3,
-          title: "举报支持选择聊天记录(安全)",
-          description: "任务描述文字xxxx",
-          price: "0",
-          serviceType: 1,
-          status: 1
-        },
-        {
-          id: 4,
-          title: "发送群文件测试",
-          description: "任务描述文字xxxx",
-          price: "30",
-          serviceType: 1,
-          status: 0
+      loading: false,
+      unFinishedTaskList: [],
+      finishedTaskList: [],
+      appliedProjectList: [],
+      myProjects: [],
+      handlingProjects: [],
+      acceptableProjects: [],
+      defaultValue: defaultValue,
+      myProjectNoticeCount: 0,
+      processProjectNoticeCount: 0,
+      acceptableProjectNoticeCount: 0,
+      rolesPermissions: {
+        isRegionManager: false,
+        isIndividualUser: false,
+        isEnterpriseUser: false,
+        isAgency: false,
+        isSystemAdministrator: false
+      },
+      user: {
+        userVO: {
+          id: '',
+          name: '',
+          photo: '',
+          roleList: []
+        }
+      }
+    }
+  },
+  mounted () {
+    this.$nextTick(() => {
+      this.init()
+    })
+  },
+  methods: {
+    init () {
+      this.setUserInfo()
+      this.setRolesPermissions()
+      this.loadData()
+      this.setEcharts()
+      // storageGet('user').then((res)=>{
+      //   this.user = res;
+      //   this.setRolesPermissions()
+      //   this.loadData()
+      // })
+
+    },
+    loadData () {
+      this.showLoading()
+      Http.get(Apis.PAGE.MY_CROWD_TEST_PAGE.replace('{userId}', this.user.userVO.id)).then((res) => {
+        this.hideLoading()
+        this.processProjectNoticeCount = res.processProjectNoticeCount == null ? 0 : res.processProjectNoticeCount
+        this.myProjectNoticeCount = res.myProjectNoticeCount == null ? 0 : res.myProjectNoticeCount
+        this.acceptableProjectNoticeCount = res.acceptableProjectNoticeCount == null ? 0 : res.acceptableProjectNoticeCount
+        if (res.unfinishedTasks != null && res.unfinishedTasks.length > 0) {
+          this.unFinishedTaskList = res.unfinishedTasks
+        }
+        if (res.finishedTasks != null && res.finishedTasks.length > 0) {
+          this.finishedTaskList = res.finishedTasks
         }
-      ],
-      taskList2: [
-        {
-          id: 6,
-          title: "浏览器波洞星球",
-          description: "任务描述文字xxxx",
-          price: "10",
-          serviceType: 2,
-          status: 0
+        if (res.myProjects != null && res.myProjects.length > 0) {
+          this.myProjects = res.myProjects
+        }
+        if (res.handlingProjects != null && res.handlingProjects.length > 0) {
+          this.handlingProjects = res.handlingProjects
+        }
+        if (res.acceptableProjects != null && res.acceptableProjects.length > 0) {
+          this.acceptableProjects = res.acceptableProjects
+        }
+        // if (res.userVO != null && res.userVO.length > 0) {
+        //   this.user = res.userVO
+        // }
+      }).catch((error) => {
+        this.hideLoading()
+        notify('error', '加载失败:' + error.data)
+      })
+    },
+    setUserInfo () {
+      this.user = storageGet('user')
+    },
+    setRolesPermissions () {
+      this.rolesPermissions = storageGet('rolesPermissions')
+    },
+    setEcharts () {
+      // 基于准备好的dom,初始化echarts实例
+      let myChart = echarts.init(document.getElementById('myChart'))
+      // 绘制图表
+      var option = {
+        title: {
+          text: ''
         },
-        {
-          id: 7,
-          title: "举报支持选择聊天记录(安全)",
-          description: "任务描述文字xxxx",
-          price: "0",
-          serviceType: 1,
-          status: 1
+        tooltip: {
+          //trigger: 'axis'
         },
-        {
-          id: 8,
-          title: "发送群文件测试",
-          description: "任务描述文字xxxx",
-          price: "30",
-          serviceType: 1,
-          status: 0
+        legend: {
+          data: ['接收项目数量', '完成项目数量', '接收任务数量', '完成任务数量', '发布项目数量']
         },
-        {
-          id: 9,
-          title: "多人聊天发送文件测试",
-          description: "任务描述文字xxxx",
-          price: "10",
-          serviceType: 0,
-          status: 1
+        grid: {
+          left: '5%',
+          right: '8%',
+          bottom: '3%',
+          top: '10%',
+          containLabel: true
         },
-        {
-          id: 10,
-          title: "浏览器波洞星球",
-          description: "任务描述文字xxxx",
-          price: "10",
-          serviceType: 2,
-          status: 0
+        toolbox: {
+          feature: {
+            saveAsImage: {
+              title: '保存为图片',
+              name: '我的众测'
+            }
+          },
+          right: '20px'
         },
-        {
-          id: 11,
-          title: "举报支持选择聊天记录(安全)",
-          description: "任务描述文字xxxx",
-          price: "0",
-          serviceType: 1,
-          status: 2
-        }
-      ],
-      projectList1: [
-        {
-          id: 1,
-          code: "27382hdsjkfdskfK",
-          name: "多人聊天发送文件测试",
-          platform: [0],
-          description: "任务描述文字xxxx",
-          price: "10"
+        xAxis: {
+          type: 'category',
+          boundaryGap: false,
+          data: ['2019年5月', '2019年6月', '2019年7月', '2019年8月', '2019年9月', '2019年10月', '2019年11月']
         },
-        {
-          id: 2,
-          code: "jzlk9dfsndfsmd ",
-          name: "多人聊天发送文件测试",
-          platform: [0, 1],
-          description: "任务描述文字xxxx",
-          price: "90"
+        yAxis: {
+          type: 'value'
         },
-        {
-          id: 3,
-          code: "437849sdbsjbsf",
-          name: "多人聊天发送文件测试",
-          platform: [1, 2],
-          description: "任务描述文字xxxx",
-          price: "50"
-        }
-      ]
-    };
+        series: [
+          {
+            name: '接收项目数量',
+            type: 'line',
+            stack: '总量',
+            data: [2, 3, 3, 2, 4, 5, 6]
+          },
+          {
+            name: '完成项目数量',
+            type: 'line',
+            stack: '总量',
+            data: [2, 3, 3, 2, 4, 5, 6]
+          },
+          {
+            name: '接收任务数量',
+            type: 'line',
+            stack: '总量',
+            data: [22, 33, 41, 14, 55, 33, 41]
+          },
+          {
+            name: '完成任务数量',
+            type: 'line',
+            stack: '总量',
+            data: [21, 33, 31, 14, 39, 33, 32]
+          },
+          {
+            name: '发布项目数量',
+            type: 'line',
+            stack: '总量',
+            data: [2, 3, 1, 0, 1, 2, 2]
+          }
+        ]
+      }
+      myChart.setOption(option)
+    },
+    showLoading () {
+      this.loading = true
+    },
+    hideLoading () {
+      this.loading = false
+    },
+    handleTabClick (event) {
+      if (event.name == 'myProject') {
+        //this.myProjectNoticeCount = 0
+      }
+      if (event.name == 'handlingProject') {
+        //this.processProjectNoticeCount = 0
+      }
+      console.log('123')
+      console.log(event)
+    }
+  },
+  created: function () {
+
   }
-};
+}
 </script>
-      
+
 <style lang="less" scoped>
-.mine-container {
-  padding: 0 80px 40px 80px;
-}
-.mine-top-wrapper {
-  height: 350px;
-  background-color: #fff;
-}
-[class*="el-col-"] {
-  height: 100%;
-}
+  .mine-container {
+    padding: 0 80px 40px 80px;
+  }
 
-.advertise-imgs {
-  height: 100%;
-}
+  .mine-top-wrapper {
+    height: 350px;
+    background-color: #fff;
+  }
 
-.advertise-imgs img {
-  width: 100%;
-  height: 100%;
-}
-.user-banner {
-  text-align: center;
-  display: inline-table;
-  height: 100%;
-  width: 100%;
-  margin-top: 40px;
-}
-.mine-body {
-  margin-top: 30px;
-}
+  [class*="el-col-"] {
+    height: 100%;
+  }
+
+  .advertise-imgs {
+    height: 100%;
+  }
+
+  .advertise-imgs img {
+    width: 100%;
+    height: 100%;
+  }
+
+  .user-banner {
+    text-align: center;
+    display: inline-table;
+    height: 100%;
+    width: 100%;
+    margin-top: 40px;
+  }
+
+  .mine-body {
+    margin-top: 30px;
+  }
 </style>
 
-      

+ 30 - 38
src/components/PersonRank.vue

@@ -1,58 +1,50 @@
 <template>
   <div>
-    <el-table :data="tableData" :showHeader="false" border style="width: 100%">
-      <el-table-column type="index" width="50"></el-table-column>
-      <el-table-column prop="logo" width="70">
+    <el-table :data="tableData" :showHeader="true" border style="width: 100%">
+      <el-table-column type="index" width="50" label="排名"></el-table-column>
+      <el-table-column prop="logo" width="70" label="头像">
         <template slot-scope="scope">
-            <img class="user-img" :src="scope.row.logo"/>
+          <img class="user-img" :src="scope.row.logo==null?defaultValue.image:scope.row.logo"/>
+        </template>
+      </el-table-column>
+      <el-table-column prop="name" label="用户名">
+        <template slot-scope="scope"><span class="institution-style" style="font-size: 12px">{{scope.row.name}}</span>
+        </template>
+      </el-table-column>
+      <el-table-column prop="number" label="金额">
+        <template slot-scope="scope">
+          <span class="institution-style" style="font-size: 12px">
+            {{scope.row.allProjectPrice}}
+          </span>
         </template>
       </el-table-column>
-      <el-table-column prop="name"><template slot-scope="scope"><span class="institution-style">{{scope.row.name}}</span></template></el-table-column>
-      <el-table-column prop="number"><template slot-scope="scope"><span class="institution-style">{{scope.row.number}}</span></template></el-table-column>
     </el-table>
   </div>
 </template>
 
 <script>
+import {defaultValue} from '@/js/index'
+
 export default {
-  name: "PersonRank",
-  data() {
+  name: 'PersonRank',
+  props: {item: {}},
+  data () {
     return {
-      tableData: [
-        {
-          logo: "http://www.mooctest.net/assets/img/mooctest.png",
-          name: "小王",
-          number: "200",
-        },
-        {
-          logo: "https://docs.alibabagroup.com/assets2/images/cn/global/logo_header.png",
-          name: "小黄",
-          number: "190",
-        },
-        {
-          logo: "http://www.mooctest.net/assets/img/mooctest.png",
-          name: "小莉",
-          number: "120",
-        },
-        {
-          logo: "https://docs.alibabagroup.com/assets2/images/cn/global/logo_header.png",
-          name: "小张",
-          number: "80",
-        },
-        {
-          logo: "https://docs.alibabagroup.com/assets2/images/cn/global/logo_header.png",
-          name: "小张",
-          number: "70",
-        }
-      ]
+      tableData: this.item,
+      defaultValue: defaultValue
+    }
+  },
+  watch: {
+    item () {
+      this.tableData = this.item
     }
   }
-};
+}
 </script>
 
 <style lang="less" scoped>
-.institution-style{
+  .institution-style {
     font-size: 16px;
     font-weight: 600;
-}
+  }
 </style>

+ 96 - 307
src/components/Square.vue

@@ -2,348 +2,137 @@
   <div class="square-container">
     <div class="title">全部任务</div>
 
-    <div class="square-list-container">
-      <task-item v-for="(item,index) in list" :key="index" :taskId="item.id" />
-      <div v-if="loading" class="loading">
-        <span></span>
-        <span></span>
-        <span></span>
-        <span></span>
-        <span></span>
-        <span></span>
-        <span></span>
-      </div>
-      <div v-if="nomore" class="nomore">没有更多</div>
+    <div class="square-list-container" v-loading="loading" type="flex" align="middle">
+      <el-row v-if="list != null && list.length != 0" type="flex" align="middle" justify="center"  style="font-size: 14px;">
+        <el-col :span="6">任务封面</el-col>
+        <el-col :span="5">任务名称</el-col>
+        <el-col :span="5">任务类型</el-col>
+        <el-col :span="4">任务预算</el-col>
+        <el-col :span="4">操作</el-col>
+      </el-row>
+      <task-item v-if="list!=null&&list.length>0" v-for="(item,index) in list" :key="index" :task="item"/>
+      <!--<div v-if="loading" class="loading">-->
+      <!--<span></span>-->
+      <!--<span></span>-->
+      <!--<span></span>-->
+      <!--<span></span>-->
+      <!--<span></span>-->
+      <!--<span></span>-->
+      <!--<span></span>-->
+      <!--</div>-->
+      <div v-if="list==null || list.length === 0" class="nomore">暂无任务</div>
     </div>
   </div>
 </template>
 
 <script>
-import TaskItem from "@/components/commons/TaskItem";
+import TaskItem from '@/components/commons/TaskItem'
+import Http from '@/js/http.js'
+import Apis from '@/js/api.js'
+import {notify} from '@/constants/index'
 
 export default {
-  name: "Square",
-  components: { TaskItem },
-  data() {
+  name: 'Square',
+  components: {TaskItem},
+  data () {
     return {
-      loading: false,
-      nomore:false,
-      list: [
-        {
-          id: 0,
-          title: "发送群文件测试",
-          platform: [0, 1],
-          description: "任务描述文字xxxx",
-          price: "30",
-          业务类型: 1,
-          participantNum: 30,
-          status: 0
-        },
-        {
-          id: 1,
-          title: "多人聊天发送文件测试",
-          platform: [0],
-          description: "任务描述文字xxxx",
-          price: "10",
-          业务类型: 0,
-          participantNum: 0,
-          status: 1
-        },
-        {
-          id: 2,
-          title: "浏览器波洞星球",
-          platform: [1],
-          description: "任务描述文字xxxx",
-          price: "10",
-          业务类型: 2,
-          participantNum: 21,
-          status: 0
-        },
-        {
-          id: 3,
-          title: "举报支持选择聊天记录(安全)",
-          platform: [0, 1, 2],
-          description: "任务描述文字xxxx",
-          price: "0",
-          业务类型: 1,
-          participantNum: 1,
-          status: 1
-        },
-        {
-          id: 4,
-          title: "发送群文件测试",
-          platform: [0, 1],
-          description: "任务描述文字xxxx",
-          price: "30",
-          业务类型: 1,
-          participantNum: 30,
-          status: 0
-        },
-        {
-          id: 5,
-          title: "多人聊天发送文件测试",
-          platform: [0],
-          description: "任务描述文字xxxx",
-          price: "10",
-          业务类型: 0,
-          participantNum: 0,
-          status: 1
-        },
-        {
-          id: 6,
-          title: "浏览器波洞星球",
-          platform: [1],
-          description: "任务描述文字xxxx",
-          price: "10",
-          业务类型: 2,
-          participantNum: 21,
-          status: 0
-        },
-        {
-          id: 7,
-          title: "举报支持选择聊天记录(安全)",
-          platform: [0, 1, 2],
-          description: "任务描述文字xxxx",
-          price: "0",
-          业务类型: 1,
-          participantNum: 1,
-          status: 1
-        },
-        {
-          id: 8,
-          title: "发送群文件测试",
-          platform: [0, 1],
-          description: "任务描述文字xxxx",
-          price: "30",
-          业务类型: 1,
-          participantNum: 30,
-          status: 0
-        },
-        {
-          id: 9,
-          title: "多人聊天发送文件测试",
-          platform: [0],
-          description: "任务描述文字xxxx",
-          price: "10",
-          业务类型: 0,
-          participantNum: 0,
-          status: 1
-        },
-        {
-          id: 10,
-          title: "浏览器波洞星球",
-          platform: [1],
-          description: "任务描述文字xxxx",
-          price: "10",
-          业务类型: 2,
-          participantNum: 21,
-          status: 0
-        },
-        {
-          id: 11,
-          title: "举报支持选择聊天记录(安全)",
-          platform: [0, 1, 2],
-          description: "任务描述文字xxxx",
-          price: "0",
-          业务类型: 1,
-          participantNum: 1,
-          status: 1
-        }
-      ],
-      list1: [
-        {
-          id: 0,
-          title: "1发送群文件测试",
-          platform: [0, 1],
-          description: "任务描述文字xxxx",
-          price: "30",
-          serviceType: 1,
-          participantNum: 30,
-          status: 0
-        },
-        {
-          id: 1,
-          title: "多人聊天发送文件测试",
-          platform: [0],
-          description: "任务描述文字xxxx",
-          price: "10",
-          serviceType: 0,
-          participantNum: 0,
-          status: 1
-        },
-        {
-          id: 2,
-          title: "浏览器波洞星球",
-          platform: [1],
-          description: "任务描述文字xxxx",
-          price: "10",
-          serviceType: 2,
-          participantNum: 21,
-          status: 0
-        },
-        {
-          id: 3,
-          title: "举报支持选择聊天记录(安全)",
-          platform: [0, 1, 2],
-          description: "任务描述文字xxxx",
-          price: "0",
-          serviceType: 1,
-          participantNum: 1,
-          status: 1
-        },
-        {
-          id: 4,
-          title: "发送群文件测试",
-          platform: [0, 1],
-          description: "任务描述文字xxxx",
-          price: "30",
-          serviceType: 1,
-          participantNum: 30,
-          status: 0
-        },
-        {
-          id: 5,
-          title: "多人聊天发送文件测试",
-          platform: [0],
-          description: "任务描述文字xxxx",
-          price: "10",
-          serviceType: 0,
-          participantNum: 0,
-          status: 1
-        },
-        {
-          id: 6,
-          title: "浏览器波洞星球",
-          platform: [1],
-          description: "任务描述文字xxxx",
-          price: "10",
-          serviceType: 2,
-          participantNum: 21,
-          status: 0
-        },
-        {
-          id: 7,
-          title: "举报支持选择聊天记录(安全)",
-          platform: [0, 1, 2],
-          description: "任务描述文字xxxx",
-          price: "0",
-          serviceType: 1,
-          participantNum: 1,
-          status: 1
-        },
-        {
-          id: 8,
-          title: "发送群文件测试",
-          platform: [0, 1],
-          description: "任务描述文字xxxx",
-          price: "30",
-          serviceType: 1,
-          participantNum: 30,
-          status: 0
-        },
-        {
-          id: 9,
-          title: "多人聊天发送文件测试",
-          platform: [0],
-          description: "任务描述文字xxxx",
-          price: "10",
-          serviceType: 0,
-          participantNum: 0,
-          status: 1
-        },
-        {
-          id: 10,
-          title: "浏览器波洞星球",
-          platform: [1],
-          description: "任务描述文字xxxx",
-          price: "10",
-          serviceType: 2,
-          participantNum: 21,
-          status: 0
-        },
-        {
-          id: 11,
-          title: "举报支持选择聊天记录(安全)",
-          platform: [0, 1, 2],
-          description: "任务描述文字xxxx",
-          price: "0",
-          serviceType: 1,
-          participantNum: 1,
-          status: 1
-        }
-      ]
-    };
+      loading: true,
+      nomore: false,
+      list: [],
+    }
   },
-  mounted() {
-    window.addEventListener("scroll", this.throttle(this.setpage, 1000), false);
+  mounted () {
+    window.addEventListener('scroll', this.throttle(this.setpage, 1000), false)
+  },
+  created () {
+    this.loadData()
   },
   methods: {
-    throttle(func, wait, options) {
-      let context, args, result;
-      let timeout = null;
-      let previous = 0;
-      if (!options) options = {};
-      let later = function() {
-        previous = options.leading === false ? 0 : Number(new Date());
-        timeout = null;
-        result = func.apply(context, args);
-        if (!timeout) context = args = null;
-      };
+    throttle (func, wait, options) {
+      let context, args, result
+      let timeout = null
+      let previous = 0
+      if (!options) options = {}
+      let later = function () {
+        previous = options.leading === false ? 0 : Number(new Date())
+        timeout = null
+        result = func.apply(context, args)
+        if (!timeout) context = args = null
+      }
       return (..._args) => {
-        let now = Number(new Date());
-        if (!previous && options.leading === false) previous = now;
-        let remaining = wait - (now - previous);
-        context = this;
-        args = _args;
+        let now = Number(new Date())
+        if (!previous && options.leading === false) previous = now
+        let remaining = wait - (now - previous)
+        context = this
+        args = _args
         if (remaining <= 0 || remaining > wait) {
-          clearTimeout(timeout);
-          timeout = null;
-          previous = now;
-          result = func.apply(context, args);
-          if (!timeout) context = args = null;
+          clearTimeout(timeout)
+          timeout = null
+          previous = now
+          result = func.apply(context, args)
+          if (!timeout) context = args = null
         } else if (!timeout && options.trailing !== false) {
-          timeout = setTimeout(later, remaining);
+          timeout = setTimeout(later, remaining)
         }
-        return result;
-      };
+        return result
+      }
     },
-    setpage() {
-      if (this.nomore && !this.loading) return; //到达底部不再执行
+    setpage () {
+      if (this.nomore && !this.loading) return //到达底部不再执行
       var scrollTop =
-        document.documentElement.scrollTop || document.body.scrollTop;
+        document.documentElement.scrollTop || document.body.scrollTop
       //变量windowHeight是可视区的高度
       var windowHeight =
-        document.documentElement.clientHeight || document.body.clientHeight;
+        document.documentElement.clientHeight || document.body.clientHeight
       //变量scrollHeight是滚动条的总高度
       var scrollHeight =
-        document.documentElement.scrollHeight || document.body.scrollHeight;
-    //   console.log(scrollTop, windowHeight, scrollHeight);
+        document.documentElement.scrollHeight || document.body.scrollHeight
+      //   console.log(scrollTop, windowHeight, scrollHeight);
       //滚动条到底部的条件
       if (scrollTop + windowHeight + 5 >= scrollHeight) {
-        console.log("加载更多数据");
+        console.log('加载更多数据')
         // this.loading=true;
-        //获取数据请求 请求结束后 
-        //成功设置 this.list =[...this.list,...this.list1];  this.loading=false; 
+        //获取数据请求 请求结束后
+        //成功设置 this.list =[...this.list,...this.list1];  this.loading=false;
         //失败设置 没有更多  this.nomore = true; this.loading = false;
         // window.setTimeout(()=>{this.loading=false;
         // console.log(this.list);},5000)
-        
+
       }
-      else{this.loading=false;}
-      window.clearTimeout();
+      else {
+        this.loading = false
+      }
+      window.clearTimeout()
+    },
+    loadData () {
+      console.log('loadData')
+      this.showLoading()
+      Http.get(Apis.PAGE.SQUARE_PAGE).then((res) => {
+        this.list = res.crowdTaskVOList
+        this.hideLoading()
+      }).catch((error) => {
+        notify('error', '任务加载失败' + error.data)
+      })
+    },
+    showLoading () {
+      this.loading = true
+    },
+    hideLoading () {
+      this.loading = false
     }
   }
-};
+}
 </script>
 
 <style lang="less" scoped>
-.square-container {
-  padding: 40px 80px;
-}
-.nomore{
+  .square-container {
+    padding: 40px 80px;
+  }
+
+  .nomore {
     text-align: center;
     font-size: 1.4rem;
     color: #8a8a8a;
     padding: 5px;
-}
+  }
 </style>

+ 458 - 0
src/components/authen/AgencyAuthentication.vue

@@ -0,0 +1,458 @@
+<template>
+  <div class="create-container">
+    <div class="create-body" v-loading="loading" style="width: 100%">
+      <div class="title">测评机构认证</div>
+      <el-form :model="authentication" :rules="rules" ref="authentication" label-width="12%" class="demo-report">
+        <el-form-item prop="agencyPhoto" label="机构logo">
+          <el-upload
+            v-if="isModifyMode"
+            class="avatar-uploader"
+            action=""
+            :show-file-list="false"
+            :http-request="uploadFile"
+            :before-upload="beforeFileUpload">
+            <img v-if="authentication.agencyPhoto" :src="authentication.agencyPhoto" class="avatar">
+            <i v-else class="el-icon-plus avatar-uploader-icon"></i>
+          </el-upload>
+          <span v-if="!isModifyMode">
+          <el-image
+            style="width: 100px;"
+            :src="authentication.agencyPhoto"
+            fit="scale-down"></el-image>
+        </span>
+        </el-form-item>
+        <el-form-item label="机构名称" prop="evaluationAgencyName">
+          <el-input v-if="isModifyMode" v-model="authentication.evaluationAgencyName"></el-input>
+          <span v-if="!isModifyMode">{{authentication.evaluationAgencyName}}</span>
+        </el-form-item>
+        <!--<el-form-item label="机构电话" prop="name">-->
+        <!--<el-input v-if="isModifyMode" v-model="authentication.mobile"></el-input>-->
+        <!--&lt;!&ndash;<span v-if="!isModifyMode">{{authentication.name}}</span>&ndash;&gt;-->
+        <!--</el-form-item>-->
+        <el-form-item v-if="!isModifyMode" label="认证状态" prop="name">
+          <el-tag :type="authentication.authStatus.style">{{authentication.authStatus.text}}</el-tag>
+        </el-form-item>
+        <el-form-item v-if="!isModifyMode && authentication.authStatus.text == '认证失败'" label="失败原因" prop="name">
+          <el-link v-if="authentication.explain!=null&&authentication.explain!=''" type="danger" disabled>
+            {{authentication.explain}}
+          </el-link>
+          <el-link v-if="authentication.explain==null || authentication.explain==''" type="danger" disabled>管理员未填写
+          </el-link>
+        </el-form-item>
+        <el-form-item label="对公账户" prop="bankAccount">
+          <el-input v-if="isModifyMode" v-model="authentication.bankAccount"></el-input>
+          <span v-if="!isModifyMode">{{authentication.bankAccount}}</span>
+        </el-form-item>
+        <el-form-item label="地址" prop="address">
+          <el-input v-if="isModifyMode" v-model="authentication.address"></el-input>
+          <span v-if="!isModifyMode">{{authentication.address}}</span>
+        </el-form-item>
+        <el-form-item label="测评机构能力" prop="evaluationAgencyAbilityList">
+          <el-checkbox-group v-if="isModifyMode" v-model="authentication.evaluationAgencyAbilityList">
+            <span v-for="(item,index) in serviceTypes" :key="index">
+              <el-checkbox :label="item" name="type">{{item}}&nbsp;&nbsp;&nbsp;&nbsp;</el-checkbox>
+            </span>
+          </el-checkbox-group>
+          <span v-if="!isModifyMode" v-for="(item,index) in authentication.evaluationAgencyAbilityList"
+                :key="index"><span class="badge">{{item}}</span></span>
+        </el-form-item>
+        <el-form-item label="测评机构资源" prop="evaluationAgencyResourceList">
+          <span v-if="isModifyMode" v-for="item in authentication.evaluationAgencyResourceList" :key="item.id"
+                style="width: 2000px">
+            资源类型:&nbsp;<el-select v-model="item.type" placeholder="请选择" style="width: 15%;margin-bottom: 10px"
+                                  :value="item.type">
+              <el-option
+                v-for="item in resourceTypes"
+                :key="item"
+                :label="item"
+                :value="item">
+              </el-option>
+            </el-select>
+            资源名称:&nbsp;<el-input v-model="item.name" style="width: 15%"></el-input>
+            总量:&nbsp;<el-input-number :min="0" v-model="item.totalNum" style="width: 15%"></el-input-number>
+            可用数量:&nbsp;<el-input-number :min="0" :max="item.totalNum" style="width: 15%"
+                                        v-model="item.availableNum"></el-input-number>
+            <el-button type="danger" icon="el-icon-delete" @click="removeAgencyResource(item.id)"></el-button>
+            <br/>
+          </span>
+          <el-button v-if="isModifyMode" type="primary" icon="el-icon-circle-plus" plain size="small"
+                     @click="addAgencyResource">添加资源
+          </el-button>
+          <span v-if="!isModifyMode" v-for="item in authentication.evaluationAgencyResourceList" :key="item.id">
+            资源类型:{{item.type}};&nbsp;&nbsp;资源名称:{{item.name}};&nbsp;&nbsp;资源总量:{{item.totalNum}};&nbsp;&nbsp;可用资源:{{item.availableNum}}<br/>
+          </span>
+        </el-form-item>
+
+        <el-form-item v-if="!isModifyMode">
+          <div class="btn btn-medium btn-info" @click="modifyInfo()">修改</div>
+        </el-form-item>
+        <el-form-item v-if="isModifyMode">
+          <div class="btn btn-primary btn-info" @click="updateAuthInfo()">提交</div>
+          <div class="btn btn-primary" @click="cancelModify()">取消</div>
+        </el-form-item>
+      </el-form>
+    </div>
+  </div>
+</template>
+
+<script>
+import Http from '@/js/http'
+import Apis from '@/js/api'
+import {notify} from '@/constants/index'
+import {
+  defaultValue,
+  getAllAgencyResourceTypes,
+  getAllServiceTypes,
+  getCurrentAgencyAuthInfo,
+  getCurrentAuthenInfo,
+  getCurrentUser,
+  getRolesPermissions,
+  storageGet,
+  storageSave,
+  updateAgencyAuthInfo
+} from '@/js/index'
+
+export default {
+  name: 'AgencyAuthentication',
+  data () {
+    return {
+      userId: 0,
+      user: {},
+      loading: false,
+      isModifyMode: false,
+      resourceTypes: [],
+      serviceTypes: [],
+      authentication: {
+        mobile: '',
+        evaluationAgencyName: '',
+        bankAccount: '',
+        address: '',
+        evaluationAgencyAbilityList: [],
+        evaluationAgencyResourceList: [],
+        photo: [],
+        authStatus: {},
+        agencyPhoto: defaultValue.image,
+        explain: ''
+      },
+      rules: {
+        // agencyPhoto: [
+        //   {required: true, message: '请输入机构名称', trigger: 'blur'},
+        //   { min: 3, max: 50, message: "机构名称长度在 3 到 50 个字符", trigger: "blur" }
+        // ],
+        evaluationAgencyName: [
+          {required: true, message: '请输入机构名称', trigger: 'blur'},
+          {min: 3, max: 50, message: '机构名称长度在 3 到 50 个字符', trigger: 'blur'}
+        ],
+        bankAccount: [
+          {required: true, message: '请输入银行卡账户', trigger: 'blur'},
+          {
+            validator: (rule, value, callback) => {
+              if (!this.checkNumber(value)) {
+                callback(new Error('银行卡账户输入有误'))
+              } else {
+                callback()
+              }
+            }, trigger: 'blur'
+          },
+        ],
+        address: [
+          {required: true, message: '请输入地址', trigger: 'blur'}
+        ],
+        evaluationAgencyAbilityList: [
+          {
+            type: 'array',
+            required: true,
+            message: '请至少选择一种服务类型',
+            trigger: 'change'
+          }
+        ],
+        evaluationAgencyResourceList: [
+          {
+            validator: (rule, value, callback) => {
+              var isError = false
+              if (value == null || value.length == 0) {
+                callback(new Error('机构资源不可为空'))
+              } else {
+                for (var i = 0; i < value.length; i++) {
+                  if (value[i].name == '') {
+                    isError = true
+                    break
+                  }
+                }
+              }
+              if (isError) {
+                callback(new Error('资源名称不可为空'))
+              } else {
+                callback()
+              }
+            }, trigger: 'blur'
+          },
+        ],
+        agencyPhoto: [
+          {
+            validator: (rule, value, callback) => {
+              if (value == null || value == '') {
+                callback(new Error('机构logo不可为空'))
+              } else {
+                callback()
+              }
+            }, trigger: 'blur'
+          },
+        ]
+      }
+    }
+  },
+  mounted () {
+    this.$nextTick(() => {
+      this.init()
+    })
+  },
+  methods: {
+    //初始化数据
+    init () {
+      this.setServiceTypes()
+      this.setResourceTypes()
+      this.setUserInfo()
+      this.getAuthInfo()
+    },
+    //加载数据
+    getAuthInfo () {
+      this.showLoading()
+      getCurrentAgencyAuthInfo(this.user.userVO.id, this.getAuthInfoSuccess, this.getAuthInfoFail)
+    },
+    getAuthInfoSuccess (res) {
+      this.hideLoading()
+      this.authentication.agencyPhoto = res.agencyPhoto == null ? defaultValue.image : res.agencyPhoto
+      this.authentication.evaluationAgencyName = res.evaluationAgencyName == null ? '暂未填写' : res.evaluationAgencyName
+      this.authentication.evaluationAgencyAbilityList = res.evaluationAgencyAbilityList == null ? [] : res.evaluationAgencyAbilityList
+      this.authentication.evaluationAgencyResourceList = res.evaluationAgencyResourceList == null ? [] : res.evaluationAgencyResourceList
+      this.authentication.bankAccount = res.bankAccount == null ? '暂未填写' : res.bankAccount
+      this.authentication.address = res.address == null ? '暂未填写' : res.address
+      this.authentication.authStatus = res.authStatus
+      this.authentication.explain = res.explain
+      console.log(this.authentication)
+    },
+    getAuthInfoFail (error) {
+      this.hideLoading()
+      notify('error', '加载认证信息失败:' + error.data)
+    },
+    //表单进入可编辑状态,可修改表单,不再使用
+    modifyInfo () {
+      this.isModifyMode = true
+    },
+    //提交认证信息
+    updateAuthInfo () {
+      //this.isModifyMode = false
+      this.$refs['authentication'].validate(valid => {
+        if (valid) {
+          this.showLoading()
+          const newAuthentication = {
+            userId: this.user.userVO.id,
+            evaluationAgencyName: this.authentication.evaluationAgencyName,
+            bankAccount: this.authentication.bankAccount,
+            address: this.authentication.address,
+            evaluationAgencyAbilityList: this.authentication.evaluationAgencyAbilityList,
+            evaluationAgencyResourceList: this.authentication.evaluationAgencyResourceList,
+            agencyPhoto: this.authentication.agencyPhoto,
+          }
+          //console.log(newAuthentication)
+          updateAgencyAuthInfo(this.user.userVO.id, newAuthentication, this.updateAuthInfoSuccess, this.updateAuthInfoFail)
+        } else {
+          notify('error', '表单填写错误!')
+          return false
+        }
+      })
+    },
+    updateAuthInfoSuccess (res) {
+      console.log(res)
+      this.hideLoading()
+      this.cancelModify()
+      notify('success', '认证信息修改成功,正在为您刷新用户信息')
+      getCurrentUser().then(res => {
+        storageSave('user', res)
+        this.user = res
+        this.sendBusMessage()
+        //this.rolesPermissions = getRolesPermissions(res.roleList)
+        storageSave('rolesPermissions', getRolesPermissions(res.roleList))
+        this.hideLoading()
+        notify('success', '用户信息刷新成功')
+      }).catch((error) => {
+        this.hideLoading()
+        notify('error', '重新获取用户信息失败:' + error.data)
+      })
+    },
+    updateAuthInfoFail (error) {
+      this.hideLoading()
+      notify('error', error.data)
+    },
+    //取消修改表单,表单进入不可编辑状态,不再使用
+    cancelModify () {
+      this.isModifyMode = false
+      this.getAuthInfo()
+    },
+    //上传文件时移除文件的响应函数
+    handleRemove (file, fileList) {
+      console.log(file, fileList)
+    },
+    //添加文件时的响应函数
+    handleExceed (files, fileList) {
+      this.$message.warning(
+        `当前限制选择 1 个文件,本次选择了 ${
+          files.length
+          } 个文件,共选择了 ${files.length + fileList.length} 个文件`
+      )
+    },
+    //移除文件前的响应函数
+    beforeRemove (file, fileList) {
+      //return this.$confirm(`确定移除 ${file.name}?`)
+    },
+    //文件上传前的响应函数
+    beforeFileUpload () {
+    },
+    //上传文件,此处为上传图片
+    uploadFile (param) {
+      const formData = new FormData()
+      let config = {
+        //添加请求头
+        headers: {'Content-Type': 'multipart/form-data'},
+      }
+      formData.append('file', param.file)
+      Http.upload(Apis.FILE.UPLOAD_IMAGE.replace('{userId}', this.user.userVO.id), formData, config).then((res) => {
+        console.log('上传成功')
+        this.authentication.agencyPhoto = res.data
+        console.log(res.data)
+        notify('success', '上传成功')
+        this.$refs['authentication'].validateField('agencyPhoto');
+      }).catch(error => {
+        notify('error', error.data)
+      })
+    },
+    //设置服务类型
+    setServiceTypes () {
+      getAllServiceTypes().then((res) => {
+        this.serviceTypes = res
+      }).catch((error) => {
+        notify('error', '机构能力加载失败')
+      })
+    },
+    //设置机构资源类型
+    setResourceTypes () {
+      this.resourceTypes = getAllAgencyResourceTypes()
+    },
+    //添加一项测评机构资源
+    addAgencyResource () {
+      const tmpResource = {
+        id: this.authentication.evaluationAgencyResourceList.length,
+        type: this.resourceTypes[0],
+        name: '',
+        totalNum: 0,
+        availableNum: 0,
+      }
+      this.authentication.evaluationAgencyResourceList.push(tmpResource)
+    },
+    //删除一项测评机构资源
+    removeAgencyResource (id) {
+      this.authentication.evaluationAgencyResourceList.splice(id, 1)
+      for (var i = 0; i < this.authentication.evaluationAgencyResourceList.length; i++) {
+        this.authentication.evaluationAgencyResourceList[i].id = i
+      }
+    },
+    //检测测评机构资源填写是否有效
+    checkAgencyResourceVaild () {
+      if (this.authentication.evaluationAgencyResourceList.length === 0) {
+        return true
+      }
+      for (var i = 0; i < this.authentication.evaluationAgencyResourceList.length; i++) {
+        const item = this.authentication.evaluationAgencyResourceList[i]
+        if (item.type === '') {
+          notify('error', '资源类型不能为空')
+          return false
+        }
+        if (item.name === '') {
+          notify('error', '资源名称不能为空')
+          return false
+        }
+        if (item.totalNum < item.availableNum) {
+          notify('error', '资源总数量不能低于可用数量')
+          return false
+        }
+      }
+      return true
+    },
+    //
+    setUserInfo () {
+      this.user = storageGet('user')
+    },
+    //
+    showLoading () {
+      this.loading = true
+    },
+    hideLoading () {
+      this.loading = false
+    },
+    submitSuccess () {
+
+    },
+    sendBusMessage () {
+      this.$root.$emit('user', this.user)
+    },
+    checkNumber (value) {
+      return /^\d+$/.test(value)
+    },
+  },
+  created: function () {
+  }
+}
+</script>
+
+<style scoped>
+  .el-radio {
+    margin: 10px 20px 10px 0;
+  }
+
+  .el-form-item /deep/ .el-tabs__content {
+    max-height: 120px !important;
+    overflow: auto;
+  }
+
+  .el-row {
+    margin-bottom: 10px;
+  }
+
+  .el-input {
+    width: 400px;
+  }
+
+  .avatar-uploader .el-upload {
+    border: 1px dashed #d9d9d9;
+    border-radius: 6px;
+    cursor: pointer;
+    position: relative;
+    overflow: hidden;
+  }
+
+  .avatar-uploader .el-upload:hover {
+    border-color: #409EFF;
+  }
+
+  .avatar-uploader-icon {
+    border: 1px dashed #d9d9d9;
+    border-radius: 6px;
+    font-size: 28px;
+    color: #8c939d;
+    width: 176px;
+    height: 178px;
+    line-height: 178px;
+    text-align: center;
+  }
+
+  .avatar-uploader-icon:hover {
+    border-color: #409EFF;
+  }
+
+  .avatar {
+    width: 178px;
+    height: 178px;
+    display: block;
+  }
+</style>

+ 429 - 0
src/components/authen/AgencyAuthenticationCreate.vue

@@ -0,0 +1,429 @@
+<template>
+  <div class="create-container">
+    <div class="create-body" v-loading="loading">
+      <div class="title">测评机构认证</div>
+      <el-form :model="authentication" :rules="rules" ref="authentication" label-width="12%" class="demo-report">
+        <el-form-item prop="agencyPhoto" label="机构logo">
+          <el-upload
+            class="avatar-uploader"
+            action=""
+            :show-file-list="false"
+            :http-request="uploadFile"
+            :before-upload="beforeFileUpload">
+            <img v-if="authentication.agencyPhoto" :src="authentication.agencyPhoto" class="avatar">
+            <i v-else class="el-icon-plus avatar-uploader-icon"></i>
+          </el-upload>
+          <!--<div v-if="!isModifyMode">-->
+          <!--<span v-if="authentication.photo==null">暂无文件</span>-->
+          <!--<a :href="authentication.photo" v-if="authentication.photo!=null"><i class="fa fa-file-text-o"></i>-->
+          <!--{{authentication.photo}}</a>-->
+          <!--</div>-->
+        </el-form-item>
+        <el-form-item label="机构名称" prop="evaluationAgencyName">
+          <el-input size="small" v-if="isModifyMode" v-model="authentication.evaluationAgencyName"></el-input>
+          <!--<span v-if="!isModifyMode">{{authentication.name}}</span>-->
+        </el-form-item>
+        <!--<el-form-item label="机构电话" prop="name">-->
+        <!--<el-input v-if="isModifyMode" v-model="authentication.mobile"></el-input>-->
+        <!--&lt;!&ndash;<span v-if="!isModifyMode">{{authentication.name}}</span>&ndash;&gt;-->
+        <!--</el-form-item>-->
+        <el-form-item label="银行卡账户" prop="bankAccount">
+          <el-input size="small" v-if="isModifyMode" v-model="authentication.bankAccount"></el-input>
+          <!--<span v-if="!isModifyMode">{{authentication.bankAccount}}</span>-->
+        </el-form-item>
+        <el-form-item label="地址" prop="address">
+          <el-input size="small" v-if="isModifyMode" v-model="authentication.address"></el-input>
+          <!--<span v-if="!isModifyMode">{{authentication.address}}</span>-->
+        </el-form-item>
+        <el-form-item label="测评机构能力" prop="evaluationAgencyAbilityList">
+          <el-checkbox-group v-if="isModifyMode" v-model="authentication.evaluationAgencyAbilityList">
+            <span v-for="(item,index) in serviceTypes" :key="index">
+              <el-checkbox :label="item" name="type">{{item}}&nbsp;&nbsp;&nbsp;&nbsp;</el-checkbox>
+            </span>
+          </el-checkbox-group>
+          <!--<span v-if="!isModifyMode">{{authentication.ability}}</span>-->
+        </el-form-item>
+        <el-form-item label="测评机构资源" prop="evaluationAgencyResourceList">
+          <span v-for="item in authentication.evaluationAgencyResourceList" :key="item.id">
+            资源类型:&nbsp;<el-select size="small" v-model="item.type" placeholder="请选择"
+                                  style="width: 150px;margin-bottom: 10px"
+                                  :value="item.type">
+              <el-option
+                v-for="item in resourceTypes"
+                :key="item"
+                :label="item"
+                :value="item">
+              </el-option>
+            </el-select>
+            资源名称:&nbsp;<el-input size="small" v-model="item.name" style="width: 150px"></el-input>
+            总量:&nbsp;<el-input-number size="small" :min="0" v-model="item.totalNum"></el-input-number>
+            可用数量:&nbsp;<el-input-number size="small" :min="0" :max="item.totalNum"
+                                        v-model="item.availableNum"></el-input-number>
+            <el-button size="small" type="danger" icon="el-icon-delete"
+                       @click="removeAgencyResource(item.id)"></el-button>
+            <br/>
+          </span>
+          <el-button type="primary" icon="el-icon-circle-plus" plain size="small" @click="addAgencyResource">添加资源
+          </el-button>
+          <!--<span v-if="!isModifyMode">{{authentication.resource}}</span>-->
+        </el-form-item>
+
+        <!--<el-form-item v-if="!isModifyMode">-->
+        <!--<div class="btn btn-medium btn-info" @click="modifyInfo()">修改</div>-->
+        <!--<div class="btn btn-medium" @click="cancelModify()">返回</div>-->
+        <!--</el-form-item>-->
+        <el-form-item v-if="isModifyMode">
+          <el-button type="primary" size="small" @click="submitInfo()">提交</el-button>
+          <!--<div  class="btn btn-primary btn-info" @click="submitInfo()">提交</div>-->
+          <!--<div class="btn btn-primary" @click="cancelModify()">取消</div>-->
+        </el-form-item>
+      </el-form>
+    </div>
+  </div>
+</template>
+
+<script>
+import Http from '@/js/http'
+import Apis from '@/js/api'
+import {notify} from '@/constants/index'
+import {
+  getAllAgencyResourceTypes,
+  getAllServiceTypes,
+  getCurrentUser,
+  getRolesPermissions,
+  storageGet,
+  storageSave,
+  uploadAgencyAuthenticationInfo
+} from '@/js/index'
+
+export default {
+  name: 'AgencyAuthenticationCreate',
+  data () {
+    return {
+      userId: 0,
+      user: {},
+      loading: false,
+      isModifyMode: true,
+      resourceTypes: [],
+      serviceTypes: [],
+      authentication: {
+        mobile: '',
+        evaluationAgencyName: '',
+        bankAccount: '',
+        address: '',
+        evaluationAgencyAbilityList: [],
+        evaluationAgencyResourceList: [],
+        photo: [],
+        agencyPhoto: '',
+      },
+      rules: {
+        // agencyPhoto: [
+        //   {required: true, message: '请输入机构名称', trigger: 'blur'},
+        //   { min: 3, max: 50, message: "机构名称长度在 3 到 50 个字符", trigger: "blur" }
+        // ],
+        evaluationAgencyName: [
+          {required: true, message: '请输入机构名称', trigger: 'blur'},
+          {min: 3, max: 50, message: '机构名称长度在 3 到 50 个字符', trigger: 'blur'}
+        ],
+        bankAccount: [
+          {required: true, message: '请输入银行卡账户', trigger: 'blur'},
+          {
+            validator: (rule, value, callback) => {
+              if (!this.checkNumber(value)) {
+                callback(new Error('银行卡账户输入有误'))
+              } else {
+                callback()
+              }
+            }, trigger: 'blur'
+          },
+        ],
+        address: [
+          {required: true, message: '请输入地址', trigger: 'blur'}
+        ],
+        evaluationAgencyAbilityList: [
+          {
+            type: 'array',
+            required: true,
+            message: '请至少选择一种服务类型',
+            trigger: 'change'
+          }
+        ],
+        evaluationAgencyResourceList: [
+          {
+            validator: (rule, value, callback) => {
+              var isError = false
+              if (value == null || value.length == 0) {
+                callback(new Error('机构资源不可为空'))
+              } else {
+                for (var i = 0; i < value.length; i++) {
+                  if (value[i].name == '') {
+                    isError = true
+                    break
+                  }
+                }
+              }
+              if (isError) {
+                callback(new Error('资源名称不可为空'))
+              } else {
+                callback()
+              }
+            }, trigger: 'blur'
+          },
+        ],
+        agencyPhoto: [
+          {
+            validator: (rule, value, callback) => {
+              if (value == null || value == '') {
+                callback(new Error('机构logo不可为空'))
+              } else {
+                callback()
+              }
+            }, trigger: 'blur'
+          },
+        ]
+
+      }
+    }
+  },
+  mounted () {
+    this.$nextTick(() => {
+      this.init()
+    })
+  },
+  methods: {
+    //初始化数据
+    init () {
+      this.setServiceTypes()
+      this.setResourceTypes()
+      this.setUserInfo()
+    },
+    //加载数据
+    loadData: function () {
+    },
+    //表单进入可编辑状态,可修改表单,不再使用
+    modifyInfo () {
+      this.isModifyMode = true
+    },
+    //提交认证信息
+    submitInfo () {
+      //this.isModifyMode = false
+      this.$refs['authentication'].validate(valid => {
+        if (valid) {
+          this.showLoading()
+          const newAuthentication = {
+            userId: this.user.userVO.id,
+            evaluationAgencyName: this.authentication.evaluationAgencyName,
+            bankAccount: this.authentication.bankAccount,
+            address: this.authentication.address,
+            evaluationAgencyAbilityList: this.authentication.evaluationAgencyAbilityList,
+            evaluationAgencyResourceList: this.authentication.evaluationAgencyResourceList,
+            agencyPhoto: this.authentication.agencyPhoto,
+          }
+          console.log(newAuthentication)
+          uploadAgencyAuthenticationInfo(this.user.userVO.id, newAuthentication, this.submitInfoSuccess, this.submitInfoFail)
+        } else {
+          notify('error', '表单填写错误!')
+          return false
+        }
+      })
+    },
+    submitInfoSuccess (res) {
+      console.log(res)
+      getCurrentUser().then(res => {
+        storageSave('user', res)
+        this.user = res
+        this.sendBusMessage()
+        //this.rolesPermissions = getRolesPermissions(res.roleList)
+        storageSave('rolesPermissions', getRolesPermissions(res.roleList))
+        this.hideLoading()
+        this.$alert('认证信息提交成功,将于3个工作日内审核完成', '提交成功', {
+          confirmButtonText: '确定',
+          callback: action => {
+            this.$router.push({
+              name: 'AgencyAuthentication',
+              params: {userId: this.user.userVO.id}
+            })
+          }
+        });
+      }).catch((error) => {
+        this.hideLoading()
+        notify('error', '重新获取用户信息失败:' + error.data)
+      })
+
+    },
+    submitInfoFail (error) {
+      this.hideLoading()
+      notify('error', error.data)
+    },
+    //取消修改表单,表单进入不可编辑状态,不再使用
+    cancelModify () {
+      this.isModifyMode = false
+    },
+    //上传文件时移除文件的响应函数
+    handleRemove (file, fileList) {
+      console.log(file, fileList)
+    },
+    //添加文件时的响应函数
+    handleExceed (files, fileList) {
+      this.$message.warning(
+        `当前限制选择 1 个文件,本次选择了 ${
+          files.length
+          } 个文件,共选择了 ${files.length + fileList.length} 个文件`
+      )
+    },
+    //移除文件前的响应函数
+    beforeRemove (file, fileList) {
+      //return this.$confirm(`确定移除 ${file.name}?`)
+    },
+    //文件上传前的响应函数
+    beforeFileUpload () {
+    },
+    //上传文件,此处为上传图片
+    uploadFile (param) {
+      this.showLoading()
+      const formData = new FormData()
+      let config = {
+        //添加请求头
+        headers: {'Content-Type': 'multipart/form-data'},
+      }
+      formData.append('file', param.file)
+      Http.upload(Apis.FILE.UPLOAD_IMAGE.replace('{userId}', this.user.userVO.id), formData, config).then((res) => {
+        this.hideLoading()
+        this.authentication.agencyPhoto = res.data
+        console.log(res.data)
+        notify('success', '上传成功')
+        this.$refs['authentication'].validateField('agencyPhoto');
+      }).catch(error => {
+        this.hideLoading()
+        notify('error', error.data)
+      })
+    },
+    //设置服务类型
+    setServiceTypes () {
+      getAllServiceTypes().then((res) => {
+        this.serviceTypes = res
+      }).catch((error) => {
+        notify('error', '机构能力加载失败')
+      })
+    },
+    //设置机构资源类型
+    setResourceTypes () {
+      this.resourceTypes = getAllAgencyResourceTypes()
+    },
+    //添加一项测评机构资源
+    addAgencyResource () {
+      const tmpResource = {
+        id: this.authentication.evaluationAgencyResourceList.length,
+        type: this.resourceTypes[0],
+        name: '',
+        totalNum: 0,
+        availableNum: 0,
+      }
+      this.authentication.evaluationAgencyResourceList.push(tmpResource)
+    },
+    //删除一项测评机构资源
+    removeAgencyResource (id) {
+      this.authentication.evaluationAgencyResourceList.splice(id, 1)
+      for (var i = 0; i < this.authentication.evaluationAgencyResourceList.length; i++) {
+        this.authentication.evaluationAgencyResourceList[i].id = i
+      }
+    },
+    //检测测评机构资源填写是否有效
+    checkAgencyResourceVaild () {
+      if (this.authentication.evaluationAgencyResourceList.length === 0) {
+        return true
+      }
+      for (var i = 0; i < this.authentication.evaluationAgencyResourceList.length; i++) {
+        const item = this.authentication.evaluationAgencyResourceList[i]
+        if (item.type === '') {
+          notify('error', '资源类型不能为空')
+          return false
+        }
+        if (item.name === '') {
+          notify('error', '资源名称不能为空')
+          return false
+        }
+        if (item.totalNum < item.availableNum) {
+          notify('error', '资源总数量不能低于可用数量')
+          return false
+        }
+      }
+      return true
+    },
+    //
+    setUserInfo () {
+      this.user = storageGet('user')
+    },
+    //
+    showLoading () {
+      this.loading = true
+    },
+    hideLoading () {
+      this.loading = false
+    },
+    submitSuccess () {
+
+    },
+    sendBusMessage () {
+      this.$root.$emit('user', this.user)
+    },
+    checkNumber (value) {
+      return /^\d+$/.test(value)
+    },
+  },
+  created: function () {
+  }
+}
+</script>
+
+<style scoped>
+  .el-radio {
+    margin: 10px 20px 10px 0;
+  }
+
+  .el-form-item /deep/ .el-tabs__content {
+    max-height: 120px !important;
+    overflow: auto;
+  }
+
+  .el-row {
+    margin-bottom: 10px;
+  }
+
+  .el-input {
+    width: 400px;
+  }
+
+  .avatar-uploader .el-upload {
+    border: 1px dashed #d9d9d9;
+    border-radius: 6px;
+    cursor: pointer;
+    position: relative;
+    overflow: hidden;
+  }
+
+  .avatar-uploader .el-upload:hover {
+    border-color: #409EFF;
+  }
+
+  .avatar-uploader-icon {
+    border: 1px dashed #d9d9d9;
+    border-radius: 6px;
+    font-size: 28px;
+    color: #8c939d;
+    width: 176px;
+    height: 178px;
+    line-height: 178px;
+    text-align: center;
+  }
+
+  .avatar-uploader-icon:hover {
+    border-color: #409EFF;
+  }
+
+  .avatar {
+    width: 178px;
+    height: 178px;
+    display: block;
+  }
+</style>

+ 77 - 0
src/components/authen/AuthenticationIndex.vue

@@ -0,0 +1,77 @@
+<template>
+  <div class="create-container">
+    <div class="create-body">
+      <div class="title">选择认证类型</div>
+      <el-row type="flex" justify="center" align="middle" style="margin-top: 100px;margin-bottom: 100px;" :gutter="50">
+        <el-col :span="6">
+          <el-card :body-style="{ padding: '0px' }" style="cursor: pointer;">
+            <i class="el-icon-user-solid image" style="color:#909399" @click="toIndividualAuthentication"></i>
+            <div style="text-align: center;font-size: 12px"><span>认证为个人用户,可以创建项目</span></div>
+            <div @click="toIndividualAuthentication" style="padding: 14px;text-align: center;font-size: 20px">
+              <span>个人认证</span>
+            </div>
+          </el-card>
+        </el-col>
+        <el-col :span="6">
+          <el-card :body-style="{ padding: '0px' }" style="cursor: pointer;">
+            <i class="el-icon-s-cooperation image" style="color:#909399" @click="toEnterpriseAuthentication"></i>
+            <div style="text-align: center;font-size: 12px"><span>认证为企业用户,可以创建项目</span></div>
+            <div @click="toEnterpriseAuthentication" style="padding: 14px;text-align: center;font-size: 20px">
+              <span>企业认证</span>
+            </div>
+          </el-card>
+        </el-col>
+        <el-col :span="6">
+          <el-card :body-style="{ padding: '0px' }" style="cursor: pointer;">
+            <i class="el-icon-s-tools image" style="color:#909399;" @click="toAgencyAuthentication"></i>
+            <div style="text-align: center;font-size: 12px"><span>认证为测评机构,可以接受任务</span></div>
+            <div @click="toAgencyAuthentication" style="padding: 14px;text-align: center;font-size: 20px">
+              <span>机构认证</span>
+            </div>
+          </el-card>
+        </el-col>
+      </el-row>
+
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'AuthenticationIndex',
+  data () {
+    return {}
+  },
+  methods: {
+    test () {
+      console.log('click')
+    },
+    toIndividualAuthentication () {
+      this.$router.push({
+        name: 'IndividualAuthenticationCreate',
+        // params: {projectId: projectId, taskId: taskId}
+      })
+    },
+    toEnterpriseAuthentication () {
+      this.$router.push({
+        name: 'EnterpriseAuthenticationCreate',
+        // params: {projectId: projectId, taskId: taskId}
+      })
+    },
+    toAgencyAuthentication () {
+      this.$router.push({
+        name: 'AgencyAuthenticationCreate',
+        // params: {projectId: projectId, taskId: taskId}
+      })
+    }
+  }
+}
+</script>
+
+<style scoped>
+  .image {
+    font-size: 150px;
+    text-align: center;
+    display: block;
+  }
+</style>

+ 362 - 0
src/components/authen/AuthenticationManage.vue

@@ -0,0 +1,362 @@
+<template>
+  <div class="create-container" v-loading="loading">
+    <div class="create-body">
+      <div class="title">审核认证信息</div>
+      <el-table
+        :data="handlingAuthList"
+        :row-class-name="rowClassName"
+        stripe
+        style="width: 100%">
+        <el-table-column prop="id" label="编号">
+          <template slot-scope="scope">
+            <span>{{scope.row.id}}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="userInfo" label="用户信息">
+          <template slot-scope="scope">
+            <span style="cursor: pointer">
+              <el-link type="primary">{{scope.row.userName}}</el-link>
+            </span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="type" label="认证类型">
+          <template slot-scope="scope">
+            <span>
+              <el-tag v-if="scope.row.type=='personal'" type="success">个人</el-tag>
+              <el-tag v-if="scope.row.type=='agency'">机构</el-tag>
+              <el-tag v-if="scope.row.type=='enterprise'" type="warning">企业</el-tag>
+            </span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="detail" label="认证详情">
+          <template slot-scope="scope">
+            <el-link type="primary" @click="handleAuthDetail(scope.row.userId,scope.row.type)">认证详情</el-link>
+          </template>
+        </el-table-column>
+        <el-table-column prop="status" label="认证状态">
+          <template slot-scope="scope">
+            <span>
+              <el-tag :type="scope.row.authStatus.style">{{scope.row.authStatus.text}}</el-tag>
+            </span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="date" label="申请时间" width="180">
+          <template slot-scope="scope">
+            <span>{{reformTime(new Date(scope.row.applytime))}}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" width="180">
+          <template slot-scope="scope">
+            <el-button type="primary" size="mini" @click="handleAuthenticationPass(scope.row.userId,scope.row.type)">
+              通过
+            </el-button>
+            <el-button type="danger" size="mini" @click="handleAuthenticationReject(scope.row.userId,scope.row.type)">
+              驳回
+            </el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <el-dialog title="认证详情" :visible.sync="showDialog" center width="40%">
+        <el-form :model="authInfoDetail" label-width="120px" label-position="right">
+          <el-form-item label="类型:">
+            <span>
+              <el-tag v-if="authInfoDetail.type=='personal'" type="success">个人</el-tag>
+              <el-tag v-if="authInfoDetail.type=='agency'">机构</el-tag>
+              <el-tag v-if="authInfoDetail.type=='enterprise'" type="warning">企业</el-tag>
+            </span>
+          </el-form-item>
+          <el-form-item label="姓名:" v-if="authInfoDetail.type == 'personal'">
+            <span>{{authInfoDetail.realName}}</span>
+          </el-form-item>
+          <el-form-item label="身份证号:" v-if="authInfoDetail.type == 'personal'">
+            <span>{{authInfoDetail.IDCard}}</span>
+          </el-form-item>
+          <el-form-item label="身份证照:" v-if="authInfoDetail.type == 'personal'">
+            <span>
+              <el-image
+                style="width: 100px;"
+                :src="authInfoDetail.IDCardPhoto"
+                fit="scale-down"></el-image>
+            </span>
+          </el-form-item>
+          <el-form-item label="银行账号:">
+            <span>{{authInfoDetail.bankAccount}}</span>
+          </el-form-item>
+          <el-form-item label="地址:">
+            <span>{{authInfoDetail.address}}</span>
+          </el-form-item>
+          <el-form-item label="申请时间:">
+            <span>{{reformTime(new Date(authInfoDetail.applyTime))}}</span>
+          </el-form-item>
+
+          <el-form-item label="企业名称:" v-if="authInfoDetail.type == 'enterprise'">
+            <span>{{authInfoDetail.enterpriseName}}</span>
+          </el-form-item>
+          <el-form-item label="法人姓名:" v-if="authInfoDetail.type == 'enterprise'">
+            <span>{{authInfoDetail.legalPersonName}}</span>
+          </el-form-item>
+          <el-form-item label="营业执照:" v-if="authInfoDetail.type == 'enterprise'">
+            <span>
+              <el-image
+                style="width: 100px;"
+                :src="authInfoDetail.businessLicensePhoto"
+                fit="scale-down"></el-image>
+            </span>
+          </el-form-item>
+          <el-form-item label="统一社会信用代码:" v-if="authInfoDetail.type == 'enterprise'">
+            <span>{{authInfoDetail.unifiedSocialCreditCode}}</span>
+          </el-form-item>
+
+          <el-form-item label="机构名称:" v-if="authInfoDetail.type == 'agency'">
+            <span>{{authInfoDetail.evaluationAgencyName}}</span>
+          </el-form-item>
+          <el-form-item label="机构能力:" v-if="authInfoDetail.type == 'agency'">
+            <span>{{authInfoDetail.evaluationAgencyAbilityList}}</span>
+          </el-form-item>
+          <el-form-item label="机构资源:" v-if="authInfoDetail.type == 'agency'">
+            <span>{{authInfoDetail.evaluationAgencyResourceList}}</span>
+          </el-form-item>
+          <el-form-item label="机构Logo:" v-if="authInfoDetail.type == 'agency'">
+            <span>
+              <el-image
+                style="width: 100px;"
+                :src="authInfoDetail.agencyPhoto"
+                fit="scale-down"></el-image>
+            </span>
+          </el-form-item>
+        </el-form>
+        <div slot="footer" class="dialog-footer">
+          <el-button type="info" size="mini" @click="hideAuthDialog()">返回</el-button>
+
+          <el-button type="danger" size="mini"
+                     @click="handleAuthenticationReject(authInfoDetail.userId,authInfoDetail.type)">驳回
+          </el-button>
+
+          <el-button type="primary" size="mini"
+                     @click="handleAuthenticationPass(authInfoDetail.userId,authInfoDetail.type)">通过
+          </el-button>
+        </div>
+      </el-dialog>
+      <!--<el-pagination-->
+      <!--:page-size="20"-->
+      <!--hide-on-single-page-->
+      <!--:pager-count="5"-->
+      <!--:current-page.sync="currentPage"-->
+      <!--layout="prev, pager, next"-->
+      <!--@current-change="handleCurrentChange"-->
+      <!--:total="100">-->
+      <!--</el-pagination>-->
+    </div>
+  </div>
+</template>
+
+<script>
+    import {
+        checkPassAuth,
+        checkRejectAuth,
+        getAllHandledAuthInfo,
+        getAllHandlingAuthInfo,
+        getCurrentAgencyAuthInfo,
+        getCurrentEnterpriseAuthInfo,
+        getCurrentIndividualAuthenInfo,
+        getFormalTimeFromDate
+    } from '@/js/index'
+    import {notify} from '@/constants/index'
+
+    export default {
+        name: 'AuthenticationManage',
+        data () {
+            return {
+                currentPage: 1,
+                loading: false,
+                showDialog: false,
+                authenticationStatusUntreated: '审核中',
+                authenticationStatusPass: '审核通过',
+                authenticationStatusReject: '审核未通过',
+                handlingAuthList: [],
+                handledAuthList: [],
+                authInfoDetail: {
+                    userId: '',
+                    type: '',
+                    realName: '',
+                    IDCard: '',
+                    IDCardPhoto: '',
+                    bankAccount: '',
+                    address: '',
+                    applyTime: '',
+
+                    enterpriseName: '',
+                    legalPersonName: '',
+                    businessLicensePhoto: '',
+                    unifiedSocialCreditCode: '',
+
+                    evaluationAgencyName: '',
+                    evaluationAgencyAbilityList: [],
+                    evaluationAgencyResourceList: [],
+                    agencyPhoto: '',
+                    updateTime: '',
+                    expireTime: ''
+                }
+            }
+        },
+        mounted () {
+            this.$nextTick(() => {
+                this.init()
+            })
+        },
+        methods: {
+            init () {
+                this.getHandlingAuthList()
+                this.getHandledAuthList()
+            },
+            //获取所有未认证信息
+            getHandlingAuthList () {
+                this.showLoading()
+                getAllHandlingAuthInfo(this.getHandlingAuthListSuccess, this.getHandlingAuthListFail)
+            },
+            //获取所有已认证信息
+            getHandlingAuthListSuccess (res) {
+                this.handlingAuthList = res
+                this.hideLoading()
+            },
+            getHandlingAuthListFail (error) {
+                this.hideLoading()
+                notify('error', '获取认证信息失败:' + error.data)
+            },
+            getHandledAuthList () {
+                this.showLoading()
+                getAllHandledAuthInfo(this.getHandledAuthListSuccess, this.getHandledAuthListFail)
+            },
+            getHandledAuthListSuccess (res) {
+                this.handledAuthList = res
+                this.hideLoading()
+            },
+            getHandledAuthListFail (error) {
+                this.hideLoading()
+                notify('error', '获取已认证信息失败:' + error.data)
+            },
+            handleCurrentChange (param) {
+                console.log(param)
+            },
+            handleAuthenticationPass (userId, type) {
+                this.showLoading()
+                checkPassAuth(type, userId, this.handleAuthenticationPassSuccess, this.handleAuthenticationPassFail)
+                // item.status = this.authenticationStatusPass
+                // console.log('通过')
+            },
+            handleAuthenticationPassSuccess (res) {
+                this.hideLoading()
+                this.getHandlingAuthList()
+                console.log(res)
+            },
+            handleAuthenticationPassFail (error) {
+                this.hideLoading()
+                console.log(error)
+                notify('error', '通过失败:' + error.data)
+            },
+            handleAuthenticationReject (userId, type) {
+                this.$prompt('请输入驳回本申请的原因', '提示', {
+                    confirmButtonText: '确定',
+                    cancelButtonText: '取消',
+                }).then((event) => {
+                    const explain = event.value
+                    console.log(explain)
+                    this.showLoading()
+                    const data = {
+                        explain: event.value
+                    }
+                    checkRejectAuth(type, userId, data, this.handleAuthenticationRejectSuccess, this.handleAuthenticationRejectFail)
+                }).catch(() => {
+                })
+            },
+            handleAuthenticationRejectSuccess (res) {
+                this.hideLoading()
+                this.getHandlingAuthList()
+                notify('success', '驳回成功')
+                console.log(res)
+            },
+            handleAuthenticationRejectFail (error) {
+                this.hideLoading()
+                console.log(error)
+                notify('error', '拒绝失败:' + error.data)
+            },
+            handleAuthDetail (userId, type) {
+                this.authInfoDetail.userId = userId
+                this.authInfoDetail.type = type
+                this.getAuthInfo(userId, type)
+            },
+            showLoading () {
+                this.loading = true
+            },
+            hideLoading () {
+                this.loading = false
+            },
+            reformTime (date) {
+                return getFormalTimeFromDate(date)
+            },
+            rowClassName ({row, rowIndex}) {
+                //把每一行的索引放进row.id
+                row.id = rowIndex + 1
+            },
+            showAuthDialog () {
+                this.showDialog = true
+            },
+            hideAuthDialog () {
+                this.showDialog = false
+            },
+            getAuthInfo (userId, type) {
+                this.showLoading()
+                if (type == 'personal') {
+                    getCurrentIndividualAuthenInfo(userId, this.getCurrentIndividualAuthenInfoSuccess, this.getCurrentIndividualAuthenInfoFail)
+                } else if (type == 'enterprise') {
+                    getCurrentEnterpriseAuthInfo(userId, this.getCurrentEnterpriseAuthInfoSuccess, this.getCurrentEnterpriseAuthInfoFail)
+                } else if (type == 'agency') {
+                    getCurrentAgencyAuthInfo(userId, this.getCurrentAgencyAuthInfoSuccess, this.getCurrentAgencyAuthInfoFail)
+                }
+            },
+            getCurrentIndividualAuthenInfoSuccess (res) {
+                this.hideLoading()
+                console.log(res)
+                this.authInfoDetail.realName = res.realName
+                this.authInfoDetail.IDCard = res.idcard
+                this.authInfoDetail.IDCardPhoto = res.idcardPhoto
+                this.authInfoDetail.bankAccount = res.bankAccount
+                this.authInfoDetail.address = res.address
+                this.authInfoDetail.applyTime = res.applyTime
+                this.showAuthDialog()
+                console.log(res)
+
+            },
+            getCurrentIndividualAuthenInfoFail (error) {
+                this.hideLoading()
+                notify('error', '获取个人认证信息出错:' + error.data)
+            },
+            getCurrentEnterpriseAuthInfoSuccess () {
+                this.hideLoading()
+                this.authInfoDetail.enterpriseName = res.enterpriseName
+                this.authInfoDetail.legalPersonName = res.legalPersonName
+                this.authInfoDetail.businessLicensePhoto = res.businessLicensePhoto
+            },
+            getCurrentEnterpriseAuthInfoFail () {
+                this.hideLoading()
+                notify('error', '获取企业认证信息出错:' + error.data)
+            },
+            getCurrentAgencyAuthInfoSuccess () {
+                this.hideLoading()
+                this.authInfoDetail.evaluationAgencyName = res.evaluationAgencyName
+                this.authInfoDetail.evaluationAgencyAbilityList = res.evaluationAgencyAbilityList
+                this.authInfoDetail.evaluationAgencyResourceList = res.evaluationAgencyResourceList
+                this.authInfoDetail.agencyPhoto = res.agencyPhoto
+                this.authInfoDetail.updateTime = res.updateTime
+            },
+            getCurrentAgencyAuthInfoFail () {
+                this.hideLoading()
+                notify('error', '获取机构认证信息出错:' + error.data)
+            }
+        }
+    }
+</script>
+
+<style scoped>
+
+</style>

+ 360 - 0
src/components/authen/EnterpriseAuthentication.vue

@@ -0,0 +1,360 @@
+<template>
+  <div class="create-container">
+    <div class="create-body" v-loading="loading">
+      <div class="title">企业信息认证</div>
+      <el-form :model="authentication" :rules="rules" ref="authentication" label-width="15%" class="demo-report">
+        <el-form-item label="公司名" prop="enterpriseName">
+          <el-input v-if="isModifyMode" v-model="authentication.enterpriseName"></el-input>
+          <span v-if="!isModifyMode">{{authentication.enterpriseName}}</span>
+        </el-form-item>
+        <el-form-item label="公司营业执照" prop="businessLicensePhoto">
+          <el-upload
+            v-if="isModifyMode"
+            class="avatar-uploader"
+            action="https://jsonplaceholder.typicode.com/posts/"
+            :show-file-list="false"
+            :http-request="uploadFile"
+            :before-upload="beforeFileUpload">
+            <img v-if="authentication.businessLicensePhoto" :src="authentication.businessLicensePhoto" class="avatar">
+            <i v-else class="el-icon-plus avatar-uploader-icon"></i>
+          </el-upload>
+          <span v-if="!isModifyMode">
+          <el-image
+            style="width: 100px;"
+            :src="authentication.businessLicensePhoto"
+            fit="scale-down"></el-image>
+        </span>
+          <!--<div v-if="!isModifyMode">-->
+          <!--<span v-if="authentication.photo==null">暂无文件</span>-->
+          <!--<a :href="authentication.photo" v-if="authentication.photo!=null"><i class="fa fa-file-text-o"></i>-->
+          <!--{{authentication.photo}}</a>-->
+          <!--</div>-->
+        </el-form-item>
+        <el-form-item v-if="!isModifyMode" label="认证状态" prop="name">
+          <el-tag :type="authentication.authStatus.style">{{authentication.authStatus.text}}</el-tag>
+        </el-form-item>
+        <el-form-item v-if="!isModifyMode && authentication.authStatus.text == '认证失败'" label="失败原因" prop="name">
+          <el-link v-if="authentication.explain!=null&&authentication.explain!=''" type="danger" disabled>
+            {{authentication.explain}}
+          </el-link>
+          <el-link v-if="authentication.explain==null || authentication.explain==''" type="danger" disabled>管理员未填写
+          </el-link>
+        </el-form-item>
+        <el-form-item label="公司法人姓名" prop="legalPersonName">
+          <el-input v-if="isModifyMode" v-model="authentication.legalPersonName"></el-input>
+          <span v-if="!isModifyMode">{{authentication.legalPersonName}}</span>
+        </el-form-item>
+        <el-form-item label="对公账户" prop="bankAccount">
+          <el-input v-if="isModifyMode" v-model="authentication.bankAccount"></el-input>
+          <span v-if="!isModifyMode">{{authentication.bankAccount}}</span>
+        </el-form-item>
+        <el-form-item label="统一社会信用代码" prop="unifiedSocialCreditCode">
+          <el-input v-if="isModifyMode" v-model="authentication.unifiedSocialCreditCode"></el-input>
+          <span v-if="!isModifyMode">{{authentication.unifiedSocialCreditCode}}</span>
+        </el-form-item>
+        <el-form-item label="公司地址" prop="address">
+          <el-input v-if="isModifyMode" v-model="authentication.address"></el-input>
+          <span v-if="!isModifyMode">{{authentication.address}}</span>
+        </el-form-item>
+
+        <el-form-item v-if="!isModifyMode">
+          <div class="btn btn-medium btn-info" @click="modifyInfo()">修改</div>
+        </el-form-item>
+        <el-form-item v-if="isModifyMode">
+          <div class="btn btn-primary btn-info" @click="updateAuthInfo()">提交</div>
+          <div class="btn btn-primary" @click="cancelModify()">取消</div>
+        </el-form-item>
+      </el-form>
+    </div>
+  </div>
+</template>
+
+<script>
+import Http from '@/js/http'
+import Apis from '@/js/api'
+import {notify} from '@/constants/index'
+import {
+  defaultValue,
+  getCurrentEnterpriseAuthInfo,
+  getCurrentUser,
+  getRolesPermissions,
+  storageGet,
+  storageSave,
+  updateEnterpriseAuthInfo
+} from '@/js/index'
+
+export default {
+  name: 'EnterpriseAuthentication',
+  data () {
+    return {
+      userId: 0,
+      user: {},
+      isModifyMode: false,
+      loading: false,
+      authentication: {
+        enterpriseName: '',
+        legalPersonName: '',
+        bankAccount: '',
+        businessLicensePhoto: defaultValue.image,
+        unifiedSocialCreditCode: '',
+        address: '',
+        authStatus: {text:"审核中", style:"warning"},
+        explain: ''
+      },
+        rules: {
+            enterpriseName: [
+                {required: true, message: '请输入公司名称', trigger: 'blur'},
+                {min: 3, max: 50, message: '机构名称长度在 3 到 50 个字符', trigger: 'blur'}
+            ],
+            businessLicensePhoto: [
+                {
+                    validator: (rule, value, callback) => {
+                        if (value == null || value == '') {
+                            callback(new Error('公司营业执照不能为空'))
+                        } else {
+                            callback()
+                        }
+                    },
+                    trigger: 'blur'
+                },
+            ],
+            legalPersonName: [
+                {required: true, message: '请输入公司法人姓名', trigger: 'blur'}
+            ],
+            bankAccount: [
+                {required: true, message: '请输入对公账户', trigger: 'blur'},
+                {
+                    validator: (rule, value, callback) => {
+                        if (!this.checkNumber(value)) {
+                            callback(new Error('对公账户输入有误'))
+                        } else {
+                            callback()
+                        }
+                    }, trigger: 'blur'
+                },
+            ],
+            unifiedSocialCreditCode: [
+                {required: true, message: '请输入统一社会信用代码', trigger: 'blur'},
+                {
+                    validator: (rule, value, callback) => {
+                        if (!this.checkNumberAndWord(value)) {
+                            callback(new Error('统一社会信用代码输入有误'))
+                        } else {
+                            callback()
+                        }
+                    }, trigger: 'blur'
+                },
+            ],
+            address: [
+                {required: true, message: '请输入公司地址', trigger: 'blur'}
+            ]
+        }
+    }
+  },
+  mounted () {
+    this.$nextTick(() => {
+      this.init()
+    })
+  },
+  methods: {
+    //初始化数据
+    init () {
+      this.setUserInfo()
+      this.getAuthInfo()
+    },
+    //加载数据
+    getAuthInfo () {
+      this.showLoading()
+      getCurrentEnterpriseAuthInfo(this.user.userVO.id, this.getAuthInfoSuccess, this.getAuthInfoFail)
+    },
+    getAuthInfoSuccess (res) {
+        this.hideLoading()
+      this.authentication.enterpriseName = res.enterpriseName == null ? '暂未填写' : res.enterpriseName
+      this.authentication.legalPersonName = res.legalPersonName == null ? '暂未填写' : res.legalPersonName
+      this.authentication.businessLicensePhoto = res.businessLicensePhoto == null ? defaultValue.image : res.businessLicensePhoto
+      this.authentication.unifiedSocialCreditCode = res.unifiedSocialCreditCode == null ? '暂未填写' : res.unifiedSocialCreditCode
+      this.authentication.bankAccount = res.bankAccount == null ? '暂未填写' : res.bankAccount
+      this.authentication.address = res.address == null ? '暂未填写' : res.address
+      this.authentication.authStatus = res.authStatus
+      this.authentication.explain = res.explain
+      console.log(this.authentication)
+    },
+    getAuthInfoFail (error) {
+      this.hideLoading()
+      notify('error', '加载认证信息失败:' + error.data)
+    },
+    //表单进入可编辑状态,可修改表单,不再使用
+    modifyInfo () {
+      this.isModifyMode = true
+    },
+    //提交认证信息
+    updateAuthInfo () {
+      //this.isModifyMode = false
+      this.$refs['authentication'].validate(valid => {
+          if (valid) {
+              this.showLoading()
+              const newAuthentication = {
+                  userId: this.user.userVO.id,
+                  enterpriseName: this.authentication.enterpriseName,
+                  legalPersonName: this.authentication.legalPersonName,
+                  businessLicensePhoto: this.authentication.businessLicensePhoto,
+                  unifiedSocialCreditCode: this.authentication.unifiedSocialCreditCode,
+                  bankAccount: this.authentication.bankAccount,
+                  address: this.authentication.address,
+              }
+              updateEnterpriseAuthInfo(this.user.userVO.id, newAuthentication, this.updateAuthInfoSuccess, this.updateAuthInfoFail)
+          } else {
+              notify('error', '表单填写错误!')
+              return false
+          }
+      })
+
+    },
+    updateAuthInfoSuccess (res) {
+      this.hideLoading()
+      this.cancelModify()
+      console.log(res)
+      this.authentication.enterpriseName = res.enterpriseName == null ? '暂未填写' : res.enterpriseName
+      this.authentication.legalPersonName = res.legalPersonName == null ? '暂未填写' : res.legalPersonName
+      this.authentication.businessLicensePhoto = res.businessLicensePhoto == null ? defaultValue.image : res.businessLicensePhoto
+      this.authentication.unifiedSocialCreditCode = res.unifiedSocialCreditCode == null ? '暂未填写' : res.unifiedSocialCreditCode
+      this.authentication.bankAccount = res.bankAccount == null ? '暂未填写' : res.bankAccount
+      this.authentication.address = res.address == null ? '暂未填写' : res.address
+      notify('success', '认证信息修改成功,正在为您刷新用户信息')
+      getCurrentUser().then(res => {
+        storageSave('user', res)
+        this.user = res
+        this.sendBusMessage()
+        //this.rolesPermissions = getRolesPermissions(res.roleList)
+        storageSave('rolesPermissions', getRolesPermissions(res.roleList))
+        this.hideLoading()
+        notify('success', '用户信息刷新成功')
+      }).catch((error) => {
+        this.hideLoading()
+        notify('error', '重新获取用户信息失败:' + error.data)
+      })
+    },
+    updateAuthInfoFail (error) {
+      this.hideLoading()
+      notify('error', error.data)
+    },
+    //取消修改表单,表单进入不可编辑状态,不再使用
+    cancelModify () {
+      this.isModifyMode = false
+    },
+    //上传文件时移除文件的响应函数
+    handleRemove (file, fileList) {
+      console.log(file, fileList)
+    },
+    //添加文件时的响应函数
+    handleExceed (files, fileList) {
+      this.$message.warning(
+        `当前限制选择 1 个文件,本次选择了 ${
+          files.length
+          } 个文件,共选择了 ${files.length + fileList.length} 个文件`
+      )
+    },
+    //移除文件前的响应函数
+    beforeRemove (file, fileList) {
+      //return this.$confirm(`确定移除 ${file.name}?`)
+    },
+    //文件上传前的响应函数
+    beforeFileUpload () {
+    },
+    //上传文件,此处为上传图片
+    uploadFile (param) {
+      this.showLoading();
+      const formData = new FormData()
+      let config = {
+        //添加请求头
+        headers: {'Content-Type': 'multipart/form-data'},
+      }
+      formData.append('file', param.file)
+      Http.upload(Apis.FILE.UPLOAD_IMAGE.replace('{userId}', this.user.userVO.id), formData, config).then((res) => {
+        this.hideLoading();
+        console.log('上传成功')
+        this.authentication.businessLicensePhoto = res.data
+        console.log(res.data)
+        notify('success', '上传成功')
+      }).catch(error => {
+        this.hideLoading();
+        notify('error', error.data)
+      })
+    },
+    //
+    setUserInfo () {
+      this.user = storageGet('user')
+    },
+    //测试用函数
+    test () {
+
+    },
+    showLoading () {
+      this.loading = true
+    },
+    hideLoading () {
+      this.loading = false
+    },
+    sendBusMessage () {
+      this.$root.$emit('user', this.user)
+    },
+    checkNumber(value){
+        return /^\d+$/.test(value);
+    },
+    checkNumberAndWord(value){
+        return /^[^_IOZSVa-z\W]{2}\d{6}[^_IOZSVa-z\W]{10}$/g.test(value) || /^[A-Za-z0-9]\w{14}$/g.test(value);
+    }
+  },
+}
+</script>
+<style scoped>
+  .el-radio {
+    margin: 10px 20px 10px 0;
+  }
+
+  .el-form-item /deep/ .el-tabs__content {
+    max-height: 120px !important;
+    overflow: auto;
+  }
+
+  .el-row {
+    margin-bottom: 10px;
+  }
+
+  .el-input {
+    width: 400px;
+  }
+
+  .avatar-uploader .el-upload {
+    border: 1px dashed #d9d9d9;
+    border-radius: 6px;
+    cursor: pointer;
+    position: relative;
+    overflow: hidden;
+  }
+
+  .avatar-uploader .el-upload:hover {
+    border-color: #409EFF;
+  }
+
+  .avatar-uploader-icon {
+    border: 1px dashed #d9d9d9;
+    border-radius: 6px;
+    font-size: 28px;
+    color: #8c939d;
+    width: 176px;
+    height: 178px;
+    line-height: 178px;
+    text-align: center;
+  }
+
+  .avatar-uploader-icon:hover {
+    border-color: #409EFF;
+  }
+
+  .avatar {
+    width: 178px;
+    height: 178px;
+    display: block;
+  }
+</style>

+ 332 - 0
src/components/authen/EnterpriseAuthenticationCreate.vue

@@ -0,0 +1,332 @@
+<template>
+  <div class="create-container" v-loading="loading">
+    <div class="create-body">
+      <div class="title">企业信息认证</div>
+      <el-form :model="authentication" :rules="rules" ref="authentication" label-width="15%" class="demo-report">
+        <el-form-item label="公司名" prop="enterpriseName">
+          <el-input size="small" v-if="isModifyMode" v-model="authentication.enterpriseName"></el-input>
+          <!--<span v-if="!isModifyMode">{{authentication.name}}</span>-->
+        </el-form-item>
+        <el-form-item label="公司营业执照" prop="businessLicensePhoto">
+          <el-upload
+            class="avatar-uploader"
+            action="https://jsonplaceholder.typicode.com/posts/"
+            :show-file-list="false"
+            :http-request="uploadFile"
+            :before-upload="beforeFileUpload">
+            <img v-if="authentication.businessLicensePhoto" :src="authentication.businessLicensePhoto" class="avatar">
+            <i v-else class="el-icon-plus avatar-uploader-icon"></i>
+          </el-upload>
+          <!--<div v-if="!isModifyMode">-->
+          <!--<span v-if="authentication.photo==null">暂无文件</span>-->
+          <!--<a :href="authentication.photo" v-if="authentication.photo!=null"><i class="fa fa-file-text-o"></i>-->
+          <!--{{authentication.photo}}</a>-->
+          <!--</div>-->
+        </el-form-item>
+        <el-form-item label="公司法人姓名" prop="legalPersonName">
+          <el-input size="small" v-if="isModifyMode" v-model="authentication.legalPersonName"></el-input>
+          <!--<span v-if="!isModifyMode">{{authentication.name}}</span>-->
+        </el-form-item>
+        <el-form-item label="对公账户" prop="bankAccount">
+          <el-input size="small" v-if="isModifyMode" v-model="authentication.bankAccount"></el-input>
+          <!--<span v-if="!isModifyMode">{{authentication.name}}</span>-->
+        </el-form-item>
+        <el-form-item label="统一社会信用代码" prop="unifiedSocialCreditCode">
+          <el-input size="small" v-if="isModifyMode" v-model="authentication.unifiedSocialCreditCode"></el-input>
+          <!--<span v-if="!isModifyMode">{{authentication.bankAccount}}</span>-->
+        </el-form-item>
+        <el-form-item label="公司地址" prop="address">
+          <el-input size="small" v-if="isModifyMode" v-model="authentication.address"></el-input>
+          <!--<span v-if="!isModifyMode">{{authentication.address}}</span>-->
+        </el-form-item>
+
+        <!--<el-form-item v-if="!isModifyMode">-->
+        <!--<div class="btn btn-medium btn-info" @click="modifyInfo()">修改</div>-->
+        <!--<div class="btn btn-medium" @click="cancelModify()">返回</div>-->
+        <!--</el-form-item>-->
+        <el-form-item v-if="isModifyMode">
+          <div class="btn btn-primary btn-info" @click="submitInfo()">提交</div>
+          <!--<div class="btn btn-primary" @click="cancelModify()">取消</div>-->
+        </el-form-item>
+      </el-form>
+    </div>
+  </div>
+</template>
+
+<script>
+import Http from '@/js/http'
+import Apis from '@/js/api'
+import {notify} from '@/constants/index'
+import {
+  getCurrentUser,
+  getRolesPermissions,
+  storageGet,
+  storageSave,
+  uploadEnterpriseAuthenticationInfo
+} from '@/js/index'
+
+export default {
+  name: 'EnterpriseAuthenticationCreate',
+  data () {
+    return {
+      userId: 0,
+      user: {},
+      isModifyMode: true,
+      loading: false,
+      authentication: {
+        enterpriseName: '',
+        legalPersonName: '',
+        bankAccount: '',
+        businessLicensePhoto: '',
+        unifiedSocialCreditCode: '',
+        address: ''
+      },
+      rules: {
+        enterpriseName: [
+          {required: true, message: '请输入公司名称', trigger: 'blur'},
+          {min: 3, max: 50, message: '机构名称长度在 3 到 50 个字符', trigger: 'blur'}
+        ],
+        businessLicensePhoto: [
+          {
+            validator: (rule, value, callback) => {
+              console.log(value)
+              if (value == null || value == '') {
+                callback(new Error('公司营业执照不能为空'))
+              } else {
+                callback()
+              }
+            },
+            trigger: 'blue'
+          },
+        ],
+        legalPersonName: [
+          {required: true, message: '请输入公司法人姓名', trigger: 'blur'}
+        ],
+        bankAccount: [
+          {required: true, message: '请输入对公账户', trigger: 'blur'},
+          {
+            validator: (rule, value, callback) => {
+              if (!this.checkNumber(value)) {
+                callback(new Error('对公账户输入有误'))
+              } else {
+                callback()
+              }
+            },
+            trigger: 'blur'
+          },
+        ],
+        unifiedSocialCreditCode: [
+          {required: true, message: '请输入统一社会信用代码', trigger: 'blur'},
+          {
+            validator: (rule, value, callback) => {
+              if (!this.checkNumberAndWord(value)) {
+                callback(new Error('统一社会信用代码输入有误'))
+              } else {
+                callback()
+              }
+            }, trigger: 'blur'
+          },
+        ],
+        address: [
+          {required: true, message: '请输入公司地址', trigger: 'blur'}
+        ]
+      }
+    }
+  },
+  mounted () {
+    this.$nextTick(() => {
+      this.init()
+    })
+  },
+  methods: {
+    //初始化数据
+    init () {
+      this.setUserInfo()
+    },
+    //加载数据
+    loadData: function () {
+    },
+    //表单进入可编辑状态,可修改表单,不再使用
+    modifyInfo () {
+      this.isModifyMode = true
+    },
+    //提交认证信息
+    submitInfo () {
+      //this.isModifyMode = false
+      this.$refs['authentication'].validate(valid => {
+        if (valid) {
+          this.showLoading()
+          const newAuthentication = {
+            userId: this.user.userVO.id,
+            enterpriseName: this.authentication.enterpriseName,
+            legalPersonName: this.authentication.legalPersonName,
+            businessLicensePhoto: this.authentication.businessLicensePhoto,
+            unifiedSocialCreditCode: this.authentication.unifiedSocialCreditCode,
+            bankAccount: this.authentication.bankAccount,
+            address: this.authentication.address,
+          }
+          uploadEnterpriseAuthenticationInfo(this.user.userVO.id, newAuthentication, this.submitInfoSuccess, this.submitInfoFail)
+        } else {
+          notify('error', '表单填写错误!')
+          return false
+        }
+      })
+    },
+    submitInfoSuccess (res) {
+      // this.hideLoading()
+      console.log(res)
+      getCurrentUser().then(res => {
+        storageSave('user', res)
+        this.user = res
+        this.sendBusMessage()
+        //this.rolesPermissions = getRolesPermissions(res.roleList)
+        storageSave('rolesPermissions', getRolesPermissions(res.roleList))
+        this.hideLoading()
+        //notify('success', '用户信息刷新成功')
+        this.$alert('认证信息提交成功,将于3个工作日内审核完成', '提交成功', {
+          confirmButtonText: '确定',
+          callback: action => {
+            this.$router.push({
+              name: 'EnterpriseAuthentication',
+              params: {userId: this.user.userVO.id}
+            })
+          }
+        });
+
+        // .catch(_ => {
+        //   this.$router.push({
+        //     name: 'EnterpriseAuthentication',
+        //     params: {userId: this.user.userVO.id}
+        //   })
+        // })
+      }).catch((error) => {
+        this.hideLoading()
+        notify('error', '重新获取用户信息失败:' + error.data)
+      })
+
+    },
+    submitInfoFail (error) {
+      this.hideLoading()
+      notify('error', error.data)
+    },
+    //取消修改表单,表单进入不可编辑状态,不再使用
+    cancelModify () {
+      this.isModifyMode = false
+    },
+    //上传文件时移除文件的响应函数
+    handleRemove (file, fileList) {
+      console.log(file, fileList)
+    },
+    //添加文件时的响应函数
+    handleExceed (files, fileList) {
+      this.$message.warning(
+        `当前限制选择 1 个文件,本次选择了 ${
+          files.length
+          } 个文件,共选择了 ${files.length + fileList.length} 个文件`
+      )
+    },
+    //移除文件前的响应函数
+    beforeRemove (file, fileList) {
+      //return this.$confirm(`确定移除 ${file.name}?`)
+    },
+    //文件上传前的响应函数
+    beforeFileUpload () {
+    },
+    //上传文件,此处为上传图片
+    uploadFile (param) {
+      this.showLoading()
+      const formData = new FormData()
+      let config = {
+        //添加请求头
+        headers: {'Content-Type': 'multipart/form-data'},
+      }
+      formData.append('file', param.file)
+      Http.upload(Apis.FILE.UPLOAD_IMAGE.replace('{userId}', this.user.userVO.id), formData, config).then((res) => {
+        this.hideLoading()
+        console.log('上传成功')
+        this.authentication.businessLicensePhoto = res.data
+        console.log(res.data)
+        notify('success', '上传成功')
+        this.$refs['authentication'].validateField('businessLicensePhoto')
+      }).catch(error => {
+        this.hideLoading()
+        notify('error', error.data)
+      })
+    },
+    //
+    setUserInfo () {
+      this.user = storageGet('user')
+    },
+    //测试用函数
+    test () {
+
+    },
+    showLoading () {
+      this.loading = true
+    },
+    hideLoading () {
+      this.loading = false
+    },
+    sendBusMessage () {
+      this.$root.$emit('user', this.user)
+    },
+    checkNumber (value) {
+      return /^\d+$/.test(value)
+    },
+    checkNumberAndWord (value) {
+      return /^[^_IOZSVa-z\W]{2}\d{6}[^_IOZSVa-z\W]{10}$/g.test(value) || /^[A-Za-z0-9]\w{14}$/g.test(value)
+    }
+  },
+}
+</script>
+<style scoped>
+  .el-radio {
+    margin: 10px 20px 10px 0;
+  }
+
+  .el-form-item /deep/ .el-tabs__content {
+    max-height: 120px !important;
+    overflow: auto;
+  }
+
+  .el-row {
+    margin-bottom: 10px;
+  }
+
+  .el-input {
+    width: 400px;
+  }
+
+  .avatar-uploader .el-upload {
+    border: 1px dashed #d9d9d9;
+    border-radius: 6px;
+    cursor: pointer;
+    position: relative;
+    overflow: hidden;
+  }
+
+  .avatar-uploader .el-upload:hover {
+    border-color: #409EFF;
+  }
+
+  .avatar-uploader-icon {
+    border: 1px dashed #d9d9d9;
+    border-radius: 6px;
+    font-size: 28px;
+    color: #8c939d;
+    width: 176px;
+    height: 178px;
+    line-height: 178px;
+    text-align: center;
+  }
+
+  .avatar-uploader-icon:hover {
+    border-color: #409EFF;
+  }
+
+  .avatar {
+    width: 178px;
+    height: 178px;
+    display: block;
+  }
+</style>

+ 349 - 0
src/components/authen/IndividualAuthentication.vue

@@ -0,0 +1,349 @@
+<template>
+  <div class="create-container" v-loading="loading">
+    <div class="create-body">
+      <div class="title">个人信息认证</div>
+      <el-form :model="authentication" :rules="rules" ref="authentication" label-width="12%" class="demo-report">
+        <el-form-item label="姓名" prop="realName">
+          <el-input v-if="isModifyMode" v-model="authentication.realName"></el-input>
+          <span v-if="!isModifyMode">{{authentication.realName}}</span>
+        </el-form-item>
+        <el-form-item prop="IDCardPhoto" label="手持身份证照片">
+          <el-upload
+            v-if="isModifyMode"
+            class="avatar-uploader"
+            action=""
+            :show-file-list="false"
+            :http-request="uploadFile"
+            :before-upload="beforeFileUpload">
+            <img v-if="authentication.IDCardPhoto" :src="authentication.IDCardPhoto" class="avatar">
+            <i v-else class="el-icon-plus avatar-uploader-icon"></i>
+          </el-upload>
+          <span v-if="!isModifyMode">
+          <el-image
+            style="width: 100px;"
+            :src="authentication.IDCardPhoto"
+            fit="scale-down"></el-image>
+        </span>
+        </el-form-item>
+        <el-form-item label="身份证号" prop="IDCard">
+          <el-input v-if="isModifyMode" v-model="authentication.IDCard"></el-input>
+          <span v-if="!isModifyMode">{{authentication.IDCard}}</span>
+        </el-form-item>
+        <el-form-item v-if="!isModifyMode" label="认证状态" prop="name">
+          <el-tag :type="authentication.authStatus.style">{{authentication.authStatus.text}}</el-tag>
+        </el-form-item>
+        <el-form-item v-if="!isModifyMode && authentication.authStatus.text == '认证失败'" label="失败原因" prop="name">
+          <el-link v-if="authentication.explain!=null&&authentication.explain!=''" type="danger" disabled>
+            {{authentication.explain}}
+          </el-link>
+          <el-link v-if="authentication.explain==null || authentication.explain==''" type="danger" disabled>管理员未填写
+          </el-link>
+        </el-form-item>
+        <el-form-item label="银行卡账户" prop="bankAccount">
+          <el-input v-if="isModifyMode" v-model="authentication.bankAccount"></el-input>
+          <span v-if="!isModifyMode">{{authentication.bankAccount}}</span>
+        </el-form-item>
+        <el-form-item label="地址" prop="address">
+          <el-input v-if="isModifyMode" v-model="authentication.address"></el-input>
+          <span v-if="!isModifyMode">{{authentication.address}}</span>
+        </el-form-item>
+
+        <el-form-item v-if="!isModifyMode">
+          <div v-if="authentication.authStatus.text!='认证通过'" class="btn btn-medium btn-info" @click="modifyInfo()">修改
+          </div>
+        </el-form-item>
+        <el-form-item v-if="isModifyMode">
+          <div class="btn btn-primary btn-info" @click="updateAuthInfo()">提交</div>
+          <div class="btn btn-primary" @click="cancelModify()">取消</div>
+        </el-form-item>
+      </el-form>
+    </div>
+  </div>
+</template>
+
+<script>
+import Http from '@/js/http'
+import Apis from '@/js/api'
+import {notify} from '@/constants/index'
+import {
+  defaultValue,
+  getAllAgencyResourceTypes,
+  getAllServiceTypes,
+  getCurrentIndividualAuthenInfo,
+  getCurrentUser,
+  getProvinceCodeByProvinceName,
+  getProvinceNameByProvinceCode,
+  getRolesPermissions,
+  storageGet,
+  storageSave,
+  updateIndividualAuthInfo
+} from '@/js/index'
+
+export default {
+  name: 'IndividualAuthentication',
+  data () {
+    return {
+      userId: 0,
+      user: {},
+      loading: false,
+      isModifyMode: false,
+      authentication: {
+        IDCardPhoto: defaultValue.image,
+        realName: '',
+        IDCard: '',
+        bankAccount: '',
+        address: '',
+        authStatus: {},
+        explain: ''
+      },
+      rules: {
+        IDCard: [
+          {required: true, message: '请输入身份证号', trigger: 'blur'},
+          {min: 18, max: 18, message: '身份证号输入有误', trigger: 'blur'}
+        ],
+        realName: [
+          {required: true, message: '请输入身份证上的姓名', trigger: 'blur'},
+        ],
+        IDCardPhoto: [
+            {
+                validator: (rule, value, callback) => {
+                    console.log(value);
+                    if (value == null || value == '') {
+                        callback(new Error('手持身份证照片不能为空'))
+                    } else {
+                        callback()
+                    }
+                },
+                trigger: 'blue'
+            },
+        ],
+        bankAccount: [
+          {required: true, message: '请输入银行卡账户', trigger: 'blur'},
+          {
+              validator: (rule, value, callback) => {
+                  if (!this.checkNumber(value)) {
+                      callback(new Error('对银行卡账户有误'))
+                  } else {
+                      callback()
+                  }
+              }, trigger: 'blur'
+          },
+        ],
+        address: [
+          {required: true, message: '请输入地址', trigger: 'blur'}
+        ],
+
+      }
+    }
+  },
+  mounted () {
+    this.$nextTick(() => {
+      this.init()
+    })
+  },
+  watch: {
+    // authentication (val) {
+    //   this.authentication = val
+    // },
+    deep: true
+  },
+  methods: {
+    //初始化数据
+    init () {
+      this.setUserInfo()
+      this.getAuthInfo()
+    },
+    //加载数据
+    getAuthInfo () {
+      this.showLoading()
+      getCurrentIndividualAuthenInfo(this.user.userVO.id, this.getAuthInfoSuccess, this.getAuthInfoFail)
+    },
+    getAuthInfoSuccess (res) {
+      this.hideLoading()
+      this.authentication.IDCardPhoto = res.idcardPhoto == null ? defaultValue.image : res.idcardPhoto
+      this.authentication.realName = res.realName == null ? '暂未填写' : res.realName
+      this.authentication.IDCard = res.idcard == null ? '暂未填写' : res.idcard
+      this.authentication.bankAccount = res.bankAccount == null ? '暂未填写' : res.bankAccount
+      this.authentication.address = res.address == null ? '暂未填写' : res.address
+      this.authentication.authStatus = res.authStatus
+      this.authentication.explain = res.explain
+      console.log(this.authentication)
+    },
+    getAuthInfoFail (error) {
+      this.hideLoading()
+      notify('error', '加载认证信息失败:' + error.data)
+    },
+    //表单进入可编辑状态,可修改表单
+    modifyInfo () {
+      this.isModifyMode = true
+    },
+    //提交认证信息
+    updateAuthInfo () {
+      //this.isModifyMode = false
+
+      this.$refs['authentication'].validate(valid => {
+        if (valid) {
+          this.showLoading()
+          const newAuthentication = {
+            userId: this.user.userVO.id,
+            realName: this.authentication.realName,
+            bankAccount: this.authentication.bankAccount,
+            address: this.authentication.address,
+            IDCardPhoto: this.authentication.IDCardPhoto,
+            IDCard: this.authentication.IDCard,
+          }
+          //console.log(newAuthentication)
+          updateIndividualAuthInfo(this.user.userVO.id, newAuthentication, this.updateAuthInfoSuccess, this.updateAuthInfoFail)
+        } else {
+          notify('error', '表单填写错误!')
+          return false
+        }
+      })
+
+    },
+    updateAuthInfoSuccess (res) {
+      this.hideLoading()
+      this.authentication.IDCardPhoto = res.idcardPhoto == null ? defaultValue.image : res.idcardPhoto
+      this.authentication.realName = res.realName == null ? '暂未填写' : res.realName
+      this.authentication.IDCard = res.idcard == null ? '暂未填写' : res.idcard
+      this.authentication.bankAccount = res.bankAccount == null ? '暂未填写' : res.bankAccount
+      this.authentication.address = res.address == null ? '暂未填写' : res.address
+      this.cancelModify()
+      notify('success', '认证信息修改成功,正在为您刷新用户信息')
+      getCurrentUser().then(res => {
+        storageSave('user', res)
+        this.user = res
+        this.sendBusMessage()
+        //this.rolesPermissions = getRolesPermissions(res.roleList)
+        storageSave('rolesPermissions', getRolesPermissions(res.roleList))
+        this.hideLoading()
+        notify('success', '用户信息刷新成功')
+      }).catch((error) => {
+        this.hideLoading()
+        notify('error', '重新获取用户信息失败:' + error.data)
+      })
+    },
+    updateAuthInfoFail (error) {
+      this.hideLoading()
+      notify('error', error.data)
+    },
+    //取消修改表单,表单进入不可编辑状态,不再使用
+    cancelModify () {
+      this.getAuthInfo()
+      this.isModifyMode = false
+    },
+    //上传文件时移除文件的响应函数
+    handleRemove (file, fileList) {
+      console.log(file, fileList)
+    },
+    //添加文件时的响应函数
+    handleExceed (files, fileList) {
+      this.$message.warning(
+        `当前限制选择 1 个文件,本次选择了 ${
+          files.length
+          } 个文件,共选择了 ${files.length + fileList.length} 个文件`
+      )
+    },
+    //移除文件前的响应函数
+    beforeRemove (file, fileList) {
+      //return this.$confirm(`确定移除 ${file.name}?`)
+    },
+    //文件上传前的响应函数
+    beforeFileUpload () {
+    },
+    //上传文件,此处为上传图片
+    uploadFile (param) {
+      this.showLoading()
+      const formData = new FormData()
+      let config = {
+        //添加请求头
+        headers: {'Content-Type': 'multipart/form-data'},
+      }
+      formData.append('file', param.file)
+      Http.upload(Apis.FILE.UPLOAD_IMAGE.replace('{userId}', this.user.userVO.id), formData, config).then((res) => {
+        this.hideLoading()
+        console.log('上传成功')
+        this.authentication.IDCardPhoto = res.data
+        console.log(res.data)
+        notify('success', '上传成功')
+        this.$refs['authentication'].validateField('IDCardPhoto');
+
+      }).catch(error => {
+        this.hideLoading()
+        notify('error', error.data)
+      })
+    },
+    //
+    setUserInfo () {
+      this.user = storageGet('user')
+    },
+    //
+    showLoading () {
+      this.loading = true
+    },
+    hideLoading () {
+      this.loading = false
+    },
+    sendBusMessage () {
+      this.$root.$emit('user', this.user)
+    },
+    checkNumber(value){
+        return /^\d+$/.test(value);
+    },
+  },
+  created: function () {
+  }
+}
+</script>
+
+<style scoped>
+  .el-radio {
+    margin: 10px 20px 10px 0;
+  }
+
+  .el-form-item /deep/ .el-tabs__content {
+    max-height: 120px !important;
+    overflow: auto;
+  }
+
+  .el-row {
+    margin-bottom: 10px;
+  }
+
+  .el-input {
+    width: 400px;
+  }
+
+  .avatar-uploader .el-upload {
+    border: 1px dashed #d9d9d9;
+    border-radius: 6px;
+    cursor: pointer;
+    position: relative;
+    overflow: hidden;
+  }
+
+  .avatar-uploader .el-upload:hover {
+    border-color: #409EFF;
+  }
+
+  .avatar-uploader-icon {
+    border: 1px dashed #d9d9d9;
+    border-radius: 6px;
+    font-size: 28px;
+    color: #8c939d;
+    width: 176px;
+    height: 178px;
+    line-height: 178px;
+    text-align: center;
+  }
+
+  .avatar-uploader-icon:hover {
+    border-color: #409EFF;
+  }
+
+  .avatar {
+    width: 178px;
+    height: 178px;
+    display: block;
+  }
+</style>

+ 307 - 0
src/components/authen/IndividualAuthenticationCreate.vue

@@ -0,0 +1,307 @@
+<template>
+  <div class="create-container" v-loading="loading">
+    <div class="create-body">
+      <div class="title">个人信息认证</div>
+      <el-form :model="authentication" :rules="rules" ref="authentication" label-width="12%" class="demo-report">
+        <el-form-item label="姓名" prop="realName">
+          <el-input size="small" v-if="isModifyMode" v-model="authentication.realName"></el-input>
+          <!--<span v-if="!isModifyMode">{{authentication.name}}</span>-->
+        </el-form-item>
+        <el-form-item prop="IDCardPhoto" label="手持身份证照片">
+          <el-upload
+            class="avatar-uploader"
+            action=""
+            :show-file-list="false"
+            :http-request="uploadFile"
+            :before-upload="beforeFileUpload">
+            <img v-if="authentication.IDCardPhoto" :src="authentication.IDCardPhoto" class="avatar">
+            <i v-else class="el-icon-plus avatar-uploader-icon"></i>
+          </el-upload>
+          <!--<div v-if="!isModifyMode">-->
+          <!--<span v-if="authentication.photo==null">暂无文件</span>-->
+          <!--<a :href="authentication.photo" v-if="authentication.photo!=null"><i class="fa fa-file-text-o"></i>-->
+          <!--{{authentication.photo}}</a>-->
+          <!--</div>-->
+        </el-form-item>
+        <el-form-item label="身份证号" prop="IDCard">
+          <el-input size="small" v-if="isModifyMode" v-model="authentication.IDCard"></el-input>
+          <!--<span v-if="!isModifyMode">{{authentication.name}}</span>-->
+        </el-form-item>
+
+        <el-form-item label="银行卡账户" prop="bankAccount">
+          <el-input size="small" v-if="isModifyMode" v-model="authentication.bankAccount"></el-input>
+          <!--<span v-if="!isModifyMode">{{authentication.bankAccount}}</span>-->
+        </el-form-item>
+        <el-form-item label="地址" prop="address">
+          <el-input size="small" v-if="isModifyMode" v-model="authentication.address"></el-input>
+          <!--<span v-if="!isModifyMode">{{authentication.address}}</span>-->
+        </el-form-item>
+
+        <!--<el-form-item v-if="!isModifyMode">-->
+        <!--<div class="btn btn-medium btn-info" @click="modifyInfo()">修改</div>-->
+        <!--<div class="btn btn-medium" @click="cancelModify()">返回</div>-->
+        <!--</el-form-item>-->
+        <el-form-item v-if="isModifyMode">
+          <div class="btn btn-primary btn-info" @click="submitInfo()">提交</div>
+          <!--<div class="btn btn-primary" @click="cancelModify()">取消</div>-->
+        </el-form-item>
+      </el-form>
+    </div>
+  </div>
+</template>
+
+<script>
+import Http from '@/js/http'
+import Apis from '@/js/api'
+import {notify} from '@/constants/index'
+import {
+  getAllAgencyResourceTypes,
+  getAllServiceTypes,
+  getCurrentUser,
+  getProvinceCodeByProvinceName,
+  getProvinceNameByProvinceCode,
+  getRolesPermissions,
+  storageGet,
+  storageSave,
+  uploadIndividualAuthenticationInfo,
+} from '@/js/index'
+
+export default {
+  name: 'IndividualAuthenticationCreate',
+  data () {
+    return {
+      userId: 0,
+      user: {},
+      isModifyMode: true,
+      loading: false,
+      authentication: {
+        IDCardPhoto: '',
+        realName: '',
+        IDCard: '',
+        bankAccount: '',
+        address: '',
+      },
+      rules: {
+        IDCard: [
+          {required: true, message: '请输入身份证号', trigger: 'blur'},
+          {min: 18, max: 18, message: '身份证号输入有误', trigger: 'blur'}
+        ],
+        realName: [
+          {required: true, message: '请输入身份证上的姓名', trigger: 'blur'},
+        ],
+        IDCardPhoto: [
+            {
+                validator: (rule, value, callback) => {
+                    console.log(value);
+                    if (value == null || value == '') {
+                        callback(new Error('手持身份证照片不能为空'))
+                    } else {
+                        callback()
+                    }
+                },
+                trigger: 'blue'
+            },
+        ],
+        bankAccount: [
+          {required: true, message: '请输入银行卡账户', trigger: 'blur'},
+          {
+              validator: (rule, value, callback) => {
+                  if (!this.checkNumber(value)) {
+                      callback(new Error('银行卡账户输入有误'))
+                  } else {
+                      callback()
+                  }
+              }, trigger: 'blur'
+          },
+        ],
+        address: [
+          {required: true, message: '请输入地址', trigger: 'blur'}
+        ],
+
+      }
+    }
+  },
+  mounted () {
+    this.$nextTick(() => {
+      this.init()
+    })
+  },
+  methods: {
+    //初始化数据
+    init () {
+      this.setUserInfo()
+    },
+    //加载数据
+    loadData: function () {
+    },
+    //表单进入可编辑状态,可修改表单,不再使用
+    modifyInfo () {
+      this.isModifyMode = true
+    },
+    //提交认证信息
+    submitInfo () {
+      //this.isModifyMode = false
+      this.$refs['authentication'].validate(valid => {
+        if (valid) {
+          this.showLoading()
+          const newAuthentication = {
+            userId: this.user.userVO.id,
+            realName: this.authentication.realName,
+            IDCard: this.authentication.IDCard,
+            IDCardPhoto: this.authentication.IDCardPhoto,
+            bankAccount: this.authentication.bankAccount,
+            address: this.authentication.address
+          }
+          uploadIndividualAuthenticationInfo(this.user.userVO.id, newAuthentication, this.submitInfoSuccess, this.submitInfoFail)
+
+        } else {
+          notify('error', '表单填写错误!')
+          return false
+        }
+      })
+    },
+    submitInfoSuccess (res) {
+      console.log(res)
+      getCurrentUser().then(res => {
+        storageSave('user', res)
+        this.user = res
+        //this.rolesPermissions = getRolesPermissions(res.roleList)
+        storageSave('rolesPermissions', getRolesPermissions(res.roleList))
+        this.hideLoading()
+        //notify('success', '用户信息刷新成功')
+        this.sendBusMessage()
+        this.$alert('认证信息提交成功,将于3个工作日内审核完成', '提交成功', {
+          confirmButtonText: '确定',
+          callback: action => {
+            this.$router.push({
+              name: 'IndividualAuthentication',
+              params: {userId: this.user.userVO.id}
+            })
+          }
+        });
+      }).catch((error) => {
+        this.hideLoading()
+        notify('error', '重新获取用户信息失败:' + error.data)
+      })
+    },
+    submitInfoFail (error) {
+      this.hideLoading()
+      notify('error', error.data)
+    },
+    //取消修改表单,表单进入不可编辑状态,不再使用
+    cancelModify () {
+      this.isModifyMode = false
+    },
+    //上传文件时移除文件的响应函数
+    handleRemove (file, fileList) {
+      console.log(file, fileList)
+    },
+    //添加文件时的响应函数
+    handleExceed (files, fileList) {
+      this.$message.warning(
+        `当前限制选择 1 个文件,本次选择了 ${
+          files.length
+          } 个文件,共选择了 ${files.length + fileList.length} 个文件`
+      )
+    },
+    //移除文件前的响应函数
+    beforeRemove (file, fileList) {
+      //return this.$confirm(`确定移除 ${file.name}?`)
+    },
+    //文件上传前的响应函数
+    beforeFileUpload () {
+    },
+    //上传文件,此处为上传图片
+    uploadFile (param) {
+      this.showLoading()
+      const formData = new FormData()
+      let config = {
+        //添加请求头
+        headers: {'Content-Type': 'multipart/form-data'},
+      }
+      formData.append('file', param.file)
+      Http.upload(Apis.FILE.UPLOAD_IMAGE.replace('{userId}', this.user.userVO.id), formData, config).then((res) => {
+        this.hideLoading()
+        console.log('上传成功')
+        this.authentication.IDCardPhoto = res.data
+        console.log(res.data)
+        notify('success', '上传成功')
+        this.$refs['authentication'].validateField('IDCardPhoto');
+      }).catch(error => {
+        this.hideLoading()
+        notify('error', error.data)
+      })
+    },
+    //
+    setUserInfo () {
+      this.user = storageGet('user')
+    },
+    showLoading () {
+      this.loading = true
+    },
+    hideLoading () {
+      this.loading = false
+    },
+    sendBusMessage () {
+      this.$root.$emit('user', this.user)
+    },
+    checkNumber(value){
+        return /^\d+$/.test(value);
+    },
+  },
+  created: function () {
+  }
+}
+</script>
+
+<style scoped>
+  .el-radio {
+    margin: 10px 20px 10px 0;
+  }
+
+  .el-form-item /deep/ .el-tabs__content {
+    max-height: 120px !important;
+    overflow: auto;
+  }
+
+  .el-row {
+    margin-bottom: 10px;
+  }
+
+  .el-input {
+    width: 400px;
+  }
+
+  .avatar-uploader .el-upload {
+    border: 1px dashed #d9d9d9;
+    border-radius: 6px;
+    cursor: pointer;
+    position: relative;
+    overflow: hidden;
+  }
+
+  .avatar-uploader .el-upload:hover {
+    border-color: #409EFF;
+  }
+
+  .avatar-uploader-icon {
+    border: 1px dashed #d9d9d9;
+    border-radius: 6px;
+    font-size: 28px;
+    color: #8c939d;
+    width: 176px;
+    height: 178px;
+    line-height: 178px;
+    text-align: center;
+  }
+
+  .avatar-uploader-icon:hover {
+    border-color: #409EFF;
+  }
+
+  .avatar {
+    width: 178px;
+    height: 178px;
+    display: block;
+  }
+</style>

+ 525 - 0
src/components/cheat/AgencyAdd.vue

@@ -0,0 +1,525 @@
+<template>
+  <div class="create-container">
+    <div class="create-body">
+      <div class="title">添加机构</div>
+      <el-form v-loading="loading" :model="agency" :rules="rules" ref="agency" label-width="12%" class="demo-report">
+        <el-form-item label="机构名称" prop="name">
+          <el-input size="small" v-if="isModifyMode" v-model="agency.name"></el-input>
+          <!--<span v-if="!isModifyMode">{{agency.name}}</span>-->
+        </el-form-item>
+        <el-form-item size="small" label="机构电话" prop="mobile">
+          <el-input v-if="isModifyMode" v-model="agency.mobile"></el-input>
+          <!--<span v-if="!isModifyMode">{{agency.name}}</span>-->
+        </el-form-item>
+        <el-form-item size="small" label="机构邮箱" prop="email">
+          <el-input v-if="isModifyMode" v-model="agency.email"></el-input>
+          <!--<span v-if="!isModifyMode">{{agency.name}}</span>-->
+        </el-form-item>
+        <el-form-item size="small" label="银行卡账户" prop="bankAccount">
+          <el-input v-if="isModifyMode" v-model="agency.bankAccount"></el-input>
+          <!--<span v-if="!isModifyMode">{{agency.bankAccount}}</span>-->
+        </el-form-item>
+        <el-form-item size="small" label="地址" prop="address">
+          <el-input v-if="isModifyMode" v-model="agency.address"></el-input>
+          <!--<span v-if="!isModifyMode">{{agency.address}}</span>-->
+        </el-form-item>
+        <el-form-item label="测评机构能力" prop="evaluationAgencyAbilityList">
+          <el-checkbox-group v-if="isModifyMode" v-model="agency.evaluationAgencyAbilityList">
+            <span v-for="(item,index) in serviceTypes" :key="index">
+              <el-checkbox :label="item"
+                           name="evaluationAgencyAbilityList">{{item}}&nbsp;&nbsp;&nbsp;&nbsp;</el-checkbox>
+            </span>
+          </el-checkbox-group>
+          <!--<span v-if="!isModifyMode">{{agency.ability}}</span>-->
+        </el-form-item>
+        <el-form-item label="测评机构资源" prop="evaluationAgencyResourceList">
+          <span v-for="item in agency.evaluationAgencyResourceList" :key="item.id">
+            资源类型:&nbsp;<el-select size="small" v-model="item.type" placeholder="请选择"
+                                  style="width: 15%;margin-bottom: 10px"
+                                  :value="item.type">
+              <el-option
+                v-for="item in resourceTypes"
+                :key="item"
+                :label="item"
+                :value="item">
+              </el-option>
+            </el-select>
+            资源名称:&nbsp;<el-input size="small" v-model="item.name" style="width: 15%"></el-input>
+            总量:&nbsp;<el-input-number size="small" :min="0" v-model="item.totalNum"></el-input-number>
+            可用数量:&nbsp;<el-input-number size="small" :min="0" :max="item.totalNum"
+                                        v-model="item.availableNum"></el-input-number>
+            <el-button size="small" type="danger" icon="el-icon-delete"
+                       @click="removeAgencyResource(item.id)"></el-button>
+            <br/>
+          </span>
+          <el-button type="primary" icon="el-icon-circle-plus" plain size="mini" @click="addAgencyResource">添加资源
+          </el-button>
+        </el-form-item>
+        <el-form-item prop="photoUrl" label="机构logo">
+          <el-upload
+            v-if="isModifyMode"
+            class="avatar-uploader"
+            :show-file-list="false"
+            action="https://jsonplaceholder.typicode.com/posts/"
+            :before-upload="beforeFileUpload"
+            :http-request="uploadFile"
+            :file-list="agency.photo"
+          >
+            <img v-if="agency.photoUrl" :src="agency.photoUrl" class="avatar">
+            <i v-else class="el-icon-plus avatar-uploader-icon"></i>
+            <!--<div class="el-upload__text">-->
+            <!--将文件拖到此处,或-->
+            <!--<em>点击上传</em>-->
+            <!--</div>-->
+            <!--<div class="el-upload__tip" slot="tip">请上传报告文件</div>-->
+          </el-upload>
+          <!--<div v-if="!isModifyMode">-->
+          <!--<span v-if="agency.photo==null">暂无文件</span>-->
+          <!--<a :href="agency.photo" v-if="agency.photo!=null"><i class="fa fa-file-text-o"></i>-->
+          <!--{{agency.photo}}</a>-->
+          <!--</div>-->
+        </el-form-item>
+
+        <!--<el-form-item v-if="!isModifyMode">-->
+        <!--<div class="btn btn-medium btn-info" @click="modifyInfo()">修改</div>-->
+        <!--<div class="btn btn-medium" @click="cancelModify()">返回</div>-->
+        <!--</el-form-item>-->
+        <el-form-item v-if="isModifyMode">
+          <div class="btn btn-primary btn-info" @click="submitInfo()">提交</div>
+          <!--<div class="btn btn-primary" @click="cancelModify()">取消</div>-->
+        </el-form-item>
+      </el-form>
+      <el-dialog
+        title="测评机构添加成功"
+        :visible.sync="dialogVisible"
+        width="30%"
+        :before-close="handleDialogClose"
+        center>
+        <span>
+          <el-card class="box-card" shadow="always">
+            <div slot="header" class="clearfix">
+              <span>您添加的机构信息</span>
+            </div>
+            <div class="text item">
+              <ul style="list-style-type:none">
+                <li>机构名称:{{ agency.name }}</li>
+                <li>机构电话:{{ agency.mobile }}</li>
+                <li>银行卡账户:{{ agency.bankAccount }}</li>
+                <li>地址:{{ agency.address }}</li>
+                <li>邮箱:{{ agency.email }}</li>
+              </ul>
+            </div>
+          </el-card>
+          <br/>
+          <el-card class="box-card" shadow="always">
+            <div class="text item">
+              您可以使用以下的账号密码登录系统:
+              <ul style="list-style-type:none">
+                <li>账号:{{ agency.email }}</li>
+                <li>密码:{{ agency.mobile }}</li>
+              </ul>
+              也可以使用手机号{{ agency.mobile }}验证码登录
+            </div>
+          </el-card>
+        </span>
+        <span slot="footer" class="dialog-footer">
+    <el-button @click="handleDialogClose">返 回</el-button>
+    <el-button type="primary" @click="toLogin">去登录</el-button>
+  </span>
+      </el-dialog>
+    </div>
+  </div>
+</template>
+
+<script>
+import Http from '@/js/http'
+import Apis from '@/js/api'
+import {notify} from '@/constants/index'
+import {getAllAbilities, getAllAgencyResourceTypes, storageGet} from '@/js/index'
+
+export default {
+  name: 'AgencyAdd',
+  data () {
+    return {
+      user: {},
+      userId: 0,
+      loading: false,
+      isModifyMode: true,
+      dialogVisible: false,
+      serviceTypes: [],
+      resourceTypes: [],
+      agency: {
+        mobile: '',
+        email: '',
+        name: '',
+        bankAccount: '',
+        address: '',
+        evaluationAgencyAbilityList: [],
+        evaluationAgencyResourceList: [
+          {
+            id: 0,
+            type: '',
+            name: '',
+            totalNum: 0,
+            availableNum: 0,
+          }
+        ],
+        professionalsCount: 0,
+        professionalsFreeCount: 0,
+        serversCount: 0,
+        serversFreeCount: 0,
+        devicesCount: 0,
+        devicesFreeCount: 0,
+        photo: [],
+        photoUrl: '',
+        password: '',
+        username: '',
+      },
+      rules: {
+        name: [
+          {required: true, message: '请输入测评机构名称', trigger: 'blur'}
+          // { min: 3, max: 5, message: "长度在 3 到 5 个字符", trigger: "blur" }
+        ],
+        mobile: [
+          {required: true, message: '请输入手机号', trigger: 'blur'}
+          // { min: 3, max: 5, message: "长度在 3 到 5 个字符", trigger: "blur" }
+        ],
+        email: [
+          {required: true, message: '请输入邮箱地址', trigger: 'blur'}
+          // { min: 3, max: 5, message: "长度在 3 到 5 个字符", trigger: "blur" }
+        ],
+        bankAccount: [
+          {required: true, message: '请输入银行卡账户', trigger: 'blur'},
+          {
+            validator: (rule, value, callback) => {
+              if (!this.checkNumber(value)) {
+                callback(new Error('银行卡账户输入有误'))
+              } else {
+                callback()
+              }
+            }, trigger: 'blur'
+          },
+        ],
+        address: [
+          {required: true, message: '请输入机构地址', trigger: 'blur'}
+          // { min: 3, max: 5, message: "长度在 3 到 5 个字符", trigger: "blur" }
+        ],
+        evaluationAgencyAbilityList: [
+          {type: 'array', required: true, message: '请至少选择一个机构能力', trigger: 'change'}
+          // { min: 3, max: 5, message: "长度在 3 到 5 个字符", trigger: "blur" }
+        ],
+        evaluationAgencyResourceList: [
+          {
+            validator: (rule, value, callback) => {
+              var isError = false
+              if (value == null || value.length == 0) {
+                callback(new Error('机构资源不可为空'))
+              } else {
+                for (var i = 0; i < value.length; i++) {
+                  if (value[i].name == '') {
+                    isError = true
+                    break
+                  }
+                }
+              }
+              if (isError) {
+                callback(new Error('资源名称不可为空'))
+              } else {
+                callback()
+              }
+            }, trigger: 'blur'
+          },
+        ],
+        photoUrl: [
+          {
+            validator: (rule, value, callback) => {
+              if (value == null || value == '') {
+                callback(new Error('机构logo不可为空'))
+              } else {
+                callback()
+              }
+            }, trigger: 'blur'
+          },
+        ]
+      },
+      tableData: [{
+        date: '2016-05-02',
+        name: '王小虎',
+        address: '上海市普陀区金沙江路 1518 弄'
+      }, {
+        date: '2016-05-04',
+        name: '王小虎',
+        address: '上海市普陀区金沙江路 1517 弄'
+      }, {
+        date: '2016-05-01',
+        name: '王小虎',
+        address: '上海市普陀区金沙江路 1519 弄'
+      }, {
+        date: '2016-05-03',
+        name: '王小虎',
+        address: '上海市普陀区金沙江路 1516 弄'
+      }]
+    }
+  },
+  mounted () {
+    this.$nextTick(() => {
+      this.init()
+    })
+  },
+  methods: {
+    //初始化
+    init () {
+      this.setServiceTypes()
+      this.setResourceTypes()
+      this.setUserInfo()
+    },
+    //加载数据
+    loadData: function () {
+    },
+    //表单进入可编辑状态,可修改表单,不再使用
+    modifyInfo () {
+      this.isModifyMode = true
+    },
+    //提交表单
+    submitInfo () {
+      //this.showDialog()
+
+      this.$refs['agency'].validate(valid => {
+        if (valid) {
+          this.showLoading()
+          const newAgency = {
+            mobile: this.agency.mobile,
+            evaluationAgencyName: this.agency.name,
+            bankAccount: this.agency.bankAccount,
+            address: this.agency.address,
+            evaluationAgencyAbilityList: this.agency.evaluationAgencyAbilityList,
+            evaluationAgencyResourceList: this.agency.evaluationAgencyResourceList,
+            agencyPhoto: this.agency.photoUrl,
+            email: this.agency.email
+          }
+          Http.post(Apis.USER.ADD_AGENCY, newAgency).then((res) => {
+            this.hideLoading()
+            console.log(res)
+            // console.log(res.data)
+            //res = res.data
+            this.agency.password = res.userVO.password
+            this.agency.username = res.userVO.userName
+            this.agency.mobile = res.userVO.mobile
+            this.showDialog()
+          }).catch(error => {
+            this.hideLoading()
+            notify('error', error.data)
+          })
+        } else {
+          notify('error', '表单填写错误!')
+          return false
+        }
+      })
+    },
+    //取消修改表单,表单进入不可编辑状态,不再使用
+    cancelModify () {
+      this.isModifyMode = false
+    },
+    //上传文件时移除文件的响应函数
+    handleRemove (file, fileList) {
+      console.log(file, fileList)
+    },
+    //添加文件时的响应函数
+    handleExceed (files, fileList) {
+      this.$message.warning(
+        `当前限制选择 1 个文件,本次选择了 ${
+          files.length
+          } 个文件,共选择了 ${files.length + fileList.length} 个文件`
+      )
+    },
+    //移除文件前的响应函数
+    beforeRemove (file, fileList) {
+      //return this.$confirm(`确定移除 ${file.name}?`)
+    },
+    //文件上传前的响应函数
+    beforeFileUpload () {
+    },
+    //上传文件,此处为上传图片
+    uploadFile (param) {
+      const formData = new FormData()
+      let config = {
+        //添加请求头
+        headers: {'Content-Type': 'multipart/form-data'},
+      }
+      formData.append('file', param.file)
+      //console.log(JSON.parse(this.user).userVO)
+      Http.upload(Apis.FILE.UPLOAD_IMAGE.replace('{userId}', this.user.userVO.id), formData, config).then((res) => {
+        this.agency.photoUrl = res.data
+        console.log(res.data)
+        notify('success', '上传成功')
+        this.$refs['agency'].validateField('photoUrl');
+      }).catch(error => {
+        notify('error', error.data)
+      })
+    },
+    //关闭对话框时的响应函数
+    handleDialogClose (done) {
+      this.$confirm('确认退出?退出前请记录下登录账号和密码,否则无法找回!!!')
+        .then(_ => {
+          //done()
+          this.hideDialog()
+        })
+        .catch(_ => {
+        })
+    },
+    //弹出对话框
+    showDialog () {
+      this.dialogVisible = true
+    },
+    //隐藏对话框
+    hideDialog () {
+      this.dialogVisible = false
+      this.resetForm()
+    },
+    //TODO 跳转到登录页面
+    toLogin () {
+      this.hideDialog()
+      this.$router.push({
+        name: 'Home',
+        // params: {projectId: projectId, taskId: taskId}
+      })
+    },
+    //重置表单
+    resetForm () {
+      this.agency = {
+        mobile: '',
+        email: '',
+        name: '',
+        bankAccount: '',
+        address: '',
+        evaluationAgencyAbilityList: '',
+        evaluationAgencyResourceList: '',
+        photo: [],
+        photoUrl: '',
+        password: '',
+        username: '',
+      }
+    },
+    //设置服务类型
+    setServiceTypes () {
+      this.serviceTypes = getAllAbilities()
+    },
+    //添加一项测评机构资源
+    addAgencyResource () {
+      const tmpResource = {
+        id: this.agency.evaluationAgencyResourceList.length,
+        type: this.resourceTypes[0],
+        name: '',
+        totalNum: 0,
+        availableNum: 0,
+      }
+      this.agency.evaluationAgencyResourceList.push(tmpResource)
+    },
+    //删除一项测评机构资源
+    removeAgencyResource (id) {
+      this.agency.evaluationAgencyResourceList.splice(id, 1)
+      for (var i = 0; i < this.agency.evaluationAgencyResourceList.length; i++) {
+        this.agency.evaluationAgencyResourceList[i].id = i
+      }
+    },
+    //设置测评机构资源类型
+    setResourceTypes () {
+      this.resourceTypes = getAllAgencyResourceTypes()
+    },
+    //检测测评机构资源填写是否有效
+    checkAgencyResourceVaild () {
+      if (this.agency.evaluationAgencyResourceList.length === 0) {
+        return true
+      }
+      for (var i = 0; i < this.agency.evaluationAgencyResourceList.length; i++) {
+        const item = this.agency.evaluationAgencyResourceList[i]
+        if (item.type === '') {
+          notify('error', '资源类型不能为空')
+          return false
+        }
+        if (item.name === '') {
+          notify('error', '资源名称不能为空')
+          return false
+        }
+        if (item.totalNum < item.availableNum) {
+          notify('error', '资源总数量不能低于可用数量')
+          return false
+        }
+      }
+      return true
+    },
+    //获取用户信息
+    setUserInfo () {
+      this.user = storageGet('user')
+    },
+    //显示loading
+    showLoading () {
+      this.loading = true
+    },
+    //隐藏loading
+    hideLoading () {
+      this.loading = false
+    },
+    checkNumber (value) {
+      return /^\d+$/.test(value)
+    },
+  },
+  created: function () {
+  }
+}
+</script>
+
+<style scoped>
+  .el-radio {
+    margin: 10px 20px 10px 0;
+  }
+
+  .el-form-item /deep/ .el-tabs__content {
+    max-height: 120px !important;
+    overflow: auto;
+  }
+
+  .el-row {
+    margin-bottom: 10px;
+  }
+
+  .el-input {
+    width: 400px;
+  }
+
+  .avatar-uploader .el-upload {
+    border: 1px dashed #d9d9d9;
+    border-radius: 6px;
+    cursor: pointer;
+    position: relative;
+    overflow: hidden;
+  }
+
+  .avatar-uploader .el-upload:hover {
+    border-color: #409EFF;
+  }
+
+  .avatar-uploader-icon {
+    font-size: 28px;
+    color: #8c939d;
+    width: 178px;
+    height: 178px;
+    line-height: 178px;
+    text-align: center;
+    border: 1px dashed #d9d9d9;
+    border-radius: 6px;
+    cursor: pointer;
+    position: relative;
+    overflow: hidden;
+  }
+
+  .avatar {
+    width: 178px;
+    height: 178px;
+    display: block;
+  }
+
+  .el-input-number {
+    width: 150px;
+  }
+</style>

+ 343 - 0
src/components/cheat/AgencyDetail.vue

@@ -0,0 +1,343 @@
+<template>
+  <div class="create-container">
+    <div class="create-body">
+      <div class="title">修改能力和资源</div>
+      <el-form v-loading="loading" :model="agency" :rules="rules" ref="agency" label-width="12%" class="demo-report">
+        <el-form-item prop="file" label="机构logo">
+          <span>
+          <el-image
+            style="width: 100px;"
+            :src="agency.agencyPhoto"
+            fit="scale-down"></el-image>
+        </span>
+        </el-form-item>
+        <el-form-item label="机构名称" prop="name">
+          <!--<el-input size="small" v-if="isModifyMode" v-model="agency.name"></el-input>-->
+          <span>{{agency.evaluationAgencyName}}</span>
+        </el-form-item>
+        <el-form-item size="small" label="机构账户" prop="bankAccount">
+          <!--<el-input v-if="isModifyMode" v-model="agency.bankAccount"></el-input>-->
+          <span>{{agency.bankAccount}}</span>
+        </el-form-item>
+        <el-form-item size="small" label="机构地址" prop="address">
+          <!--<el-input v-if="isModifyMode" v-model="agency.address"></el-input>-->
+          <span>{{agency.address}}</span>
+        </el-form-item>
+        <el-form-item label="机构能力" prop="evaluationAgencyAbilityList">
+          <el-checkbox-group v-if="isModifyMode" v-model="agency.evaluationAgencyAbilityList">
+            <span v-for="(item,index) in serviceTypes" :key="index">
+              <el-checkbox :label="item"
+                           name="evaluationAgencyAbilityList">{{item}}&nbsp;&nbsp;&nbsp;&nbsp;</el-checkbox>
+            </span>
+          </el-checkbox-group>
+          <span v-if="!isModifyMode">
+            <span v-for="(item,index) in agency.evaluationAgencyAbilityList" :key="index">
+              <el-tag>{{item}}</el-tag>&nbsp;
+            </span>
+          </span>
+        </el-form-item>
+        <el-form-item label="机构资源" prop="evaluationAgencyResourceList">
+          <span v-if="isModifyMode" v-for="item in agency.evaluationAgencyResourceList" :key="item.id">
+            资源类型:&nbsp;<el-select size="small" v-model="item.type" placeholder="请选择"
+                                  style="width: 15%;margin-bottom: 10px"
+                                  :value="item.type">
+              <el-option
+                v-for="item in resourceTypes"
+                :key="item"
+                :label="item"
+                :value="item">
+              </el-option>
+            </el-select>
+            资源名称:&nbsp;<el-input size="small" v-model="item.name" style="width: 15%" prop="resourceName"></el-input>
+            总量:&nbsp;<el-input-number size="small" :min="0" v-model="item.totalNum"></el-input-number>
+            可用数量:&nbsp;<el-input-number size="small" :min="0" :max="item.totalNum"
+                                        v-model="item.availableNum"></el-input-number>
+            <el-button size="small" type="danger" icon="el-icon-delete"
+                       @click="removeAgencyResource(item.id)"></el-button>
+            <br/>
+          </span>
+          <el-button v-if="isModifyMode" type="primary" icon="el-icon-circle-plus" plain size="mini"
+                     @click="addAgencyResource">添加资源
+          </el-button>
+          <span v-if="!isModifyMode" v-for="item in agency.evaluationAgencyResourceList" :key="item.id">
+            资源类型:{{item.type}};&nbsp;&nbsp;资源名称:{{item.name}};&nbsp;&nbsp;资源总量:{{item.totalNum}};&nbsp;&nbsp;可用资源:{{item.availableNum}}<br/>
+          </span>
+        </el-form-item>
+
+        <!--<el-form-item v-if="!isModifyMode">-->
+        <!--<div class="btn btn-medium btn-info" @click="modifyInfo()">修改</div>-->
+        <!--<div class="btn btn-medium" @click="cancelModify()">返回</div>-->
+        <!--</el-form-item>-->
+        <el-form-item>
+          <el-button v-if="isModifyMode" type="primary" size="small" @click="submitInfo()">提交</el-button>
+          <el-button v-if="isModifyMode" type="info" size="small" @click="cancelModify()">取消</el-button>
+          <el-button v-if="!isModifyMode" type="primary" size="small" @click="modifyInfo()">修改</el-button>
+          <!--<div class="btn btn-primary" @click="cancelModify()">取消</div>-->
+        </el-form-item>
+      </el-form>
+    </div>
+  </div>
+</template>
+
+<script>
+import {notify} from '@/constants/index'
+import {
+  getAllAbilities,
+  getAllAgencyResourceTypes,
+  getCurrentAgencyAuthInfo,
+  storageGet,
+  updateAgencyResourceAndAbility
+} from '@/js/index'
+
+export default {
+  name: 'Agency',
+  data () {
+    return {
+      user: {},
+      userId: 0,
+      loading: false,
+      isModifyMode: false,
+      dialogVisible: false,
+      serviceTypes: [],
+      resourceTypes: [],
+      agency: {
+        evaluationAgencyName: '',
+        bankAccount: '',
+        address: '',
+        evaluationAgencyAbilityList: [],
+        evaluationAgencyResourceList: [
+          {
+            id: 0,
+            type: '',
+            name: '',
+            totalNum: 0,
+            availableNum: 0,
+          }
+        ],
+        agencyPhoto: '',
+      },
+      rules: {
+        evaluationAgencyAbilityList: [
+          {type: 'array', required: true, message: '请至少选择一个机构能力', trigger: 'change'}
+          // { min: 3, max: 5, message: "长度在 3 到 5 个字符", trigger: "blur" }
+        ],
+        evaluationAgencyResourceList: [
+          {
+            validator: (rule, value, callback) => {
+              var isError = false
+              if (value == null || value.length == 0){
+                callback(new Error('机构资源不可为空'))
+              } else {
+                for (var i = 0; i < value.length; i++) {
+                  if (value[i].name == '') {
+                    isError = true
+                    break
+                  }
+                }
+              }
+              if (isError) {
+                callback(new Error('资源名称不可为空'))
+              } else {
+                callback()
+              }
+            }, trigger: 'blur'
+          },
+        ],
+        resourceName: [
+          {required: true, message: '请输入地址', trigger: 'blur'}
+        ]
+      },
+    }
+  },
+  mounted () {
+    this.$nextTick(() => {
+      this.init()
+    })
+  },
+  methods: {
+    //初始化
+    init () {
+      this.setServiceTypes()
+      this.setResourceTypes()
+      this.setUserInfo()
+      this.getAgencyInfo()
+    },
+    getAgencyInfo () {
+      this.showLoading()
+      getCurrentAgencyAuthInfo(this.user.userVO.id, this.getAgencyInfoSuccess, this.getAgencyInfoFail)
+    },
+    getAgencyInfoSuccess (res) {
+      this.hideLoading()
+      this.agency.evaluationAgencyName = res.evaluationAgencyName
+      this.agency.bankAccount = res.bankAccount
+      this.agency.address = res.address
+      this.agency.evaluationAgencyAbilityList = res.evaluationAgencyAbilityList
+      this.agency.evaluationAgencyResourceList = res.evaluationAgencyResourceList
+      this.agency.agencyPhoto = res.agencyPhoto
+    },
+    getAgencyInfoFail (error) {
+      this.hideLoading()
+      notify('error', '获取机构信息失败:' + error.data)
+    },
+    //表单进入可编辑状态,可修改表单,不再使用
+    modifyInfo () {
+      this.isModifyMode = true
+    },
+    //提交表单
+    submitInfo () {
+      this.$refs['agency'].validate(valid => {
+        if (valid) {
+          this.showLoading()
+          const data = {
+            evaluationAgencyAbilityList: this.agency.evaluationAgencyAbilityList,
+            evaluationAgencyResourceList: this.agency.evaluationAgencyResourceList
+          }
+          updateAgencyResourceAndAbility(this.user.userVO.id, data, this.submitInfoSuccess, this.submitInfoFail)
+        } else {
+          notify('error', '表单填写错误!')
+          return false
+        }
+      })
+    },
+    submitInfoSuccess (res) {
+      this.hideLoading()
+      notify('success', '修改成功')
+      this.cancelModify()
+    },
+    submitInfoFail (error) {
+      this.hideLoading()
+      notify('error', '修改资源能力失败:' + error.data)
+    },
+    //取消修改表单,表单进入不可编辑状态,不再使用
+    cancelModify () {
+      this.isModifyMode = false
+      this.getAgencyInfo()
+    },
+    //TODO 跳转到登录页面
+    toLogin () {
+      this.hideDialog()
+      this.$router.push({
+        name: 'Home',
+        // params: {projectId: projectId, taskId: taskId}
+      })
+    },
+    //设置服务类型
+    setServiceTypes () {
+      this.serviceTypes = getAllAbilities()
+    },
+    //添加一项测评机构资源
+    addAgencyResource () {
+      const tmpResource = {
+        id: this.agency.evaluationAgencyResourceList.length,
+        type: this.resourceTypes[0],
+        name: '',
+        totalNum: 0,
+        availableNum: 0,
+      }
+      this.agency.evaluationAgencyResourceList.push(tmpResource)
+    },
+    //删除一项测评机构资源
+    removeAgencyResource (id) {
+      this.agency.evaluationAgencyResourceList.splice(id, 1)
+      for (var i = 0; i < this.agency.evaluationAgencyResourceList.length; i++) {
+        this.agency.evaluationAgencyResourceList[i].id = i
+      }
+    },
+    //设置测评机构资源类型
+    setResourceTypes () {
+      this.resourceTypes = getAllAgencyResourceTypes()
+    },
+    //检测测评机构资源填写是否有效
+    checkAgencyResourceVaild () {
+      if (this.agency.evaluationAgencyResourceList.length === 0) {
+        return true
+      }
+      for (var i = 0; i < this.agency.evaluationAgencyResourceList.length; i++) {
+        const item = this.agency.evaluationAgencyResourceList[i]
+        if (item.type === '') {
+          notify('error', '资源类型不能为空')
+          return false
+        }
+        if (item.name === '') {
+          notify('error', '资源名称不能为空')
+          return false
+        }
+        if (item.totalNum < item.availableNum) {
+          notify('error', '资源总数量不能低于可用数量')
+          return false
+        }
+      }
+      return true
+    },
+    //获取用户信息
+    setUserInfo () {
+      this.user = storageGet('user')
+    },
+    //显示loading
+    showLoading () {
+      this.loading = true
+    },
+    //隐藏loading
+    hideLoading () {
+      this.loading = false
+    }
+  },
+  created: function () {
+  }
+}
+</script>
+
+<style scoped>
+  .el-radio {
+    margin: 10px 20px 10px 0;
+  }
+
+  .el-form-item /deep/ .el-tabs__content {
+    max-height: 120px !important;
+    overflow: auto;
+  }
+
+  .el-row {
+    margin-bottom: 10px;
+  }
+
+  .el-input {
+    width: 400px;
+  }
+
+  .avatar-uploader .el-upload {
+    border: 1px dashed #d9d9d9;
+    border-radius: 6px;
+    cursor: pointer;
+    position: relative;
+    overflow: hidden;
+  }
+
+  .avatar-uploader .el-upload:hover {
+    border-color: #409EFF;
+  }
+
+  .avatar-uploader-icon {
+    font-size: 28px;
+    color: #8c939d;
+    width: 178px;
+    height: 178px;
+    line-height: 178px;
+    text-align: center;
+    border: 1px dashed #d9d9d9;
+    border-radius: 6px;
+    cursor: pointer;
+    position: relative;
+    overflow: hidden;
+  }
+
+  .avatar {
+    width: 178px;
+    height: 178px;
+    display: block;
+  }
+
+  .el-input-number {
+    width: 150px;
+  }
+</style>

+ 683 - 0
src/components/cheat/ProjectAdd.vue

@@ -0,0 +1,683 @@
+<template>
+  <div class="create-container">
+    <div class="create-body" v-loading="loading">
+      <div class="title">创建项目</div>
+      <el-tabs tabPosition="top" type="card">
+        <el-tab-pane label="单个创建项目">
+          <el-form :model="project" :rules="rules" ref="project" label-width="12%" class="demo-report">
+            <el-form-item label="项目名称" prop="name">
+              <el-input v-if="isModifyMode" v-model="project.name"></el-input>
+              <!--<span v-if="!isModifyMode">{{project.name}}</span>-->
+            </el-form-item>
+            <el-form-item label="项目描述" prop="name">
+              <el-input v-if="isModifyMode" v-model="project.description"></el-input>
+              <!--<span v-if="!isModifyMode">{{project.description}}</span>-->
+            </el-form-item>
+            <el-form-item label="联系人姓名" prop="name">
+              <el-input v-if="isModifyMode" v-model="project.contactName"></el-input>
+              <!--<span v-if="!isModifyMode">{{project.contactName}}</span>-->
+            </el-form-item>
+            <el-form-item label="联系人电话" prop="name">
+              <el-input v-if="isModifyMode" v-model="project.contactPhone"></el-input>
+              <!--<span v-if="!isModifyMode">{{project.contactPhone}}</span>-->
+            </el-form-item>
+            <el-form-item label="项目定价" prop="name">
+              <el-input v-if="isModifyMode" v-model="project.price"></el-input>
+              <!--<span v-if="!isModifyMode">{{project.price}}</span>-->
+            </el-form-item>
+            <el-form-item label="平台" prop="platform">
+              <el-checkbox-group v-if="isModifyMode" v-model="project.platform">
+                <span v-for="(item,index) in platforms" :key="index">
+              <el-checkbox :label="item">{{ item }}&nbsp;&nbsp;&nbsp;&nbsp;</el-checkbox>
+            </span>
+              </el-checkbox-group>
+              <!--<span-->
+              <!--v-if="!isModifyMode"-->
+              <!--class="badge"-->
+              <!--v-for="item in project.platform"-->
+              <!--&gt;{{platformType[item]}}</span>-->
+            </el-form-item>
+            <el-form-item label="服务类型" prop="type">
+              <el-checkbox-group v-if="isModifyMode" v-model="project.type">
+            <span v-for="(item,index) in serviceType" :key="index">
+              <el-checkbox :label="item" name="type">{{item}}&nbsp;&nbsp;&nbsp;&nbsp;</el-checkbox>
+            </span>
+              </el-checkbox-group>
+            </el-form-item>
+            <el-form-item prop="file" label="项目需求文档">
+              <el-upload
+                v-if="isModifyMode"
+                drag
+                style="width: 400px"
+                class="upload-demo"
+                action=""
+                :on-remove="handleRemove"
+                :before-remove="beforeRemove"
+                multiple
+                :limit="1"
+                :on-exceed="handleExceed"
+                :before-upload="beforeFileUpload"
+                :http-request="uploadRequireDoc"
+                :file-list="project.requireDoc"
+              >
+                <i class="el-icon-upload"></i>
+                <div class="el-upload__text">
+                  将文件拖到此处,或
+                  <em>点击上传</em>
+                </div>
+                <div class="el-upload__tip" slot="tip">请上传报告文件</div>
+              </el-upload>
+              <!--<div v-if="!isModifyMode">-->
+              <!--<span v-if="project.file==null || project.file.length === 0">暂无文件</span>-->
+              <!--<a :href="project.file[0]" v-if="project.file!=null && project.file.length > 0"><i-->
+              <!--class="fa fa-file-text-o"></i>-->
+              <!--{{project.file[0]}}</a>-->
+              <!--</div>-->
+            </el-form-item>
+            <el-form-item prop="file" label="项目待测文件">
+              <el-upload
+                style="width: 400px"
+                v-if="isModifyMode"
+                drag
+                class="upload-demo"
+                action=""
+                :on-remove="handleRemove"
+                :before-remove="beforeRemove"
+                multiple
+                :limit="1"
+                :on-exceed="handleExceed"
+                :http-request="uploadApkFile"
+                :before-upload="beforeFileUpload"
+                :file-list="project.file"
+              >
+                <i class="el-icon-upload"></i>
+                <div class="el-upload__text">
+                  将文件拖到此处,或
+                  <em>点击上传</em>
+                </div>
+              </el-upload>
+              <!--<div v-if="!isModifyMode">-->
+              <!--<span v-if="project.file==null || project.file.length === 0">暂无文件</span>-->
+              <!--<a :href="project.file[0]" v-if="project.file!=null && project.file.length > 0"><i-->
+              <!--class="fa fa-file-text-o"></i>-->
+              <!--{{project.file[0]}}</a>-->
+              <!--</div>-->
+            </el-form-item>
+            <el-form-item label="项目截止时间" prop="datetime">
+              <div class="block" v-if="isModifyMode">
+                <el-date-picker
+                  v-model="project.datetime"
+                  type="datetime"
+                  placeholder="选择截止时间"
+                  align="right"
+                  :picker-options="pickerOptions"
+                ></el-date-picker>
+              </div>
+              <span v-if="!isModifyMode">{{new Date(project.datetime)}}</span>
+            </el-form-item>
+            <!--<el-form-item v-if="!isModifyMode">-->
+            <!--<div class="btn btn-medium btn-info" @click="modifyInfo()">修改</div>-->
+            <!--<div class="btn btn-medium" @click="cancelModify()">返回</div>-->
+            <!--</el-form-item>-->
+            <el-form-item v-if="isModifyMode">
+              <div class="btn btn-primary btn-info" @click="submitInfo()">确认提交</div>
+            </el-form-item>
+          </el-form>
+        </el-tab-pane>
+        <el-tab-pane label="批量创建项目">
+          <el-form :model="project" :rules="rules" ref="project" label-width="12%" class="demo-report">
+            <el-form-item prop="file" label="Excel模板文件">
+              <a :href="downloadFile">
+                <el-link :underline="false" type="primary"><i
+                  class="el-icon-document"></i>下载文档
+                </el-link>
+              </a>
+            </el-form-item>
+            <el-form-item type="file" prop="file" label="Excel文件">
+              <el-upload
+                v-if="isModifyMode"
+                drag
+                class="upload-demo"
+                action=""
+                :on-remove="handleRemove"
+                :before-remove="beforeRemove"
+                :limit="1"
+                :on-exceed="handleExceed"
+                :before-upload="beforeFileUpload"
+                :http-request="uploadProjectCreateExcelFile"
+                :file-list="project.excelFile"
+              >
+                <i class="el-icon-upload"></i>
+                <div class="el-upload__text">
+                  将文件拖到此处,或
+                  <em>点击上传</em>
+                </div>
+              </el-upload>
+              <!--<div v-if="!isModifyMode">-->
+              <!--<span v-if="project.file==null">暂无文件</span>-->
+              <!--<a :href="project.file" v-if="project.file!=null"><i class="fa fa-file-text-o"></i>-->
+              <!--{{project.file}}</a>-->
+              <!--</div>-->
+            </el-form-item>
+            <el-form-item v-if="isModifyMode">
+              <div class="btn btn-primary btn-info" @click="ensureSubmitExcel()">确认提交</div>
+            </el-form-item>
+          </el-form>
+          <el-dialog
+            title="您添加的项目"
+            :visible.sync="dialogVisible"
+            width="80%"
+            :before-close="handleDialogClose"
+            center>
+        <span>
+          <el-table
+            :data="projectList"
+            style="width: auto">
+            <el-table-column prop="name" label="项目名称">
+              <template slot-scope="scope">
+                <span>{{scope.row.name}}</span>
+              </template>
+            </el-table-column>
+            <el-table-column prop="platform" label="项目测试平台">
+              <template slot-scope="scope">
+                <span v-for="item in JSON.parse(scope.row.platform)" :key="item">
+                   <el-tag type="success">{{item}}</el-tag>&nbsp;&nbsp;
+                </span>
+              </template>
+            </el-table-column>
+            <el-table-column prop="linkMan" label="项目联系人">
+              <template slot-scope="scope">
+                <span>{{scope.row.linkMan}}</span>
+              </template>
+            </el-table-column>
+            <el-table-column prop="linkManMobile" label="联系方式">
+              <template slot-scope="scope">
+                <span>{{scope.row.linkManMobile}}</span>
+              </template>
+            </el-table-column>
+            <el-table-column prop="type" label="项目测试类型">
+              <template slot-scope="scope">
+                <span v-for="item in JSON.parse(scope.row.type)" :key="item">
+                   <el-tag type="success">{{item}}</el-tag>&nbsp;&nbsp;
+                </span>
+              </template>
+            </el-table-column>
+            <el-table-column prop="description" label="项目需求描述">
+              <template slot-scope="scope">
+                <span>{{scope.row.description}}</span>
+              </template>
+            </el-table-column>
+            <el-table-column prop="description" label="测试报告内容">
+              <template slot-scope="scope">
+                <span>{{scope.row.description}}</span>
+              </template>
+            </el-table-column>
+            <el-table-column prop="description" label="测试报告结论">
+              <template slot-scope="scope">
+                <span>{{scope.row.description}}</span>
+              </template>
+            </el-table-column>
+    </el-table>
+        </span>
+            <span slot="footer" class="dialog-footer">
+    <el-button @click="handleDialogClose">取消</el-button>
+    <el-button type="primary" @click="ensureSubmitExcel">确认</el-button>
+  </span>
+          </el-dialog>
+        </el-tab-pane>
+
+      </el-tabs>
+
+    </div>
+  </div>
+</template>
+
+<script>
+import Http from '@/js/http.js'
+import Apis from '@/js/api.js'
+import {notify} from '@/constants/index'
+import {
+  getAllPlatformTypes,
+  getAllServiceTypes,
+  getGreenChannelAddProjectExcelTemplateFile,
+  storageGet
+} from '@/js/index'
+
+export default {
+  name: 'ProjectAdd',
+  data () {
+    return {
+      userId: 0,
+      user: {},
+      loading: false,
+      dialogVisible: false,
+      isModifyMode: true,
+      serviceType: [],
+      platforms: [],
+      isFormSubmit: true,
+      downloadFile: '',
+      project: {
+        name: '',
+        description: '',
+        contactName: '',
+        contactPhone: '',
+        platform: [],
+        type: [],
+        requireDoc: [],
+        requireDocUrl: '',
+        file: [],
+        fileUrl: '',
+        excelFile: [],
+        excelFileUrl: '',
+        price: '',
+        datetime: ''
+      },
+      projectList: [
+        {
+          'projectDetails': {
+            'id': 'PROJECT-2019081319025',
+            'name': '网易云测试',
+            'contactName': '孙加辉',
+            'contactPhone': '13628972489',
+            'type': [
+              1
+            ],
+            'platform': [
+              1,
+              0
+            ],
+            'desc': '无',
+            'doc': '',
+            'file': '',
+            'resource': 1,
+            'location': {
+              'provinceCode': '江苏',
+              'cityCode': '南京'
+            },
+            'institution': 1,
+            'datetime': '2019-08-13T11:14:08.192+0000',
+            'price': 30000.0,
+            'budget': 30000.0,
+            'usage': null
+          },
+          'taskList': [
+            {
+              'id': 'TASK-LDSM-2019081319013',
+              'projectId': 'PROJECT-2019081319025',
+              'title': '网易云测试-安全漏洞扫描',
+              'description': null,
+              'quotePrice': 30000.0,
+              'fixedPrice': 30000.0,
+              'resource': 0,
+              'location': {
+                'provinceCode': '江苏',
+                'cityCode': '南京'
+              },
+              'institution': 1,
+              'serviceType': 1,
+              'status': 5,
+              'datetime': '2019-08-13T11:14:08.192+0000'
+            }
+          ],
+          'reportList': null
+        },
+        {
+          'projectDetails': {
+            'id': 'PROJECT-2019081319026',
+            'name': '网易测试',
+            'contactName': '孙加辉',
+            'contactPhone': '0797-8877663',
+            'type': [
+              4,
+              3
+            ],
+            'platform': [
+              2
+            ],
+            'desc': '无',
+            'doc': '',
+            'file': '',
+            'resource': 1,
+            'location': {
+              'provinceCode': '江苏',
+              'cityCode': '南京'
+            },
+            'institution': 1,
+            'datetime': '2019-08-13T11:14:08.194+0000',
+            'price': 30000.0,
+            'budget': 30000.0,
+            'usage': null
+          },
+          'taskList': [
+            {
+              'id': 'TASK-GNCS-2019081319006',
+              'projectId': 'PROJECT-2019081319026',
+              'title': '网易测试-功能测试',
+              'description': null,
+              'quotePrice': 30000.0,
+              'fixedPrice': 30000.0,
+              'resource': 0,
+              'location': {
+                'provinceCode': '江苏',
+                'cityCode': '南京'
+              },
+              'institution': 1,
+              'serviceType': 4,
+              'status': 5,
+              'datetime': '2019-08-13T11:14:08.194+0000'
+            }
+          ],
+          'reportList': null
+        }
+      ],
+      excelFile: {},
+      rules: {
+        // name: [
+        //   {required: true, message: '请输入报告名称', trigger: 'blur'}
+        //   // { min: 3, max: 5, message: "长度在 3 到 5 个字符", trigger: "blur" }
+        // ],
+        // abstract: [
+        //   {
+        //     required: true,
+        //     message: '请输入摘要信息',
+        //     trigger: 'change'
+        //   }
+        // ],
+        // type: [
+        //   {required: true, message: '请选择报告类型', trigger: 'change'}
+        // ],
+        // conclusion: [
+        //   {required: true, message: '请输入报告结论', trigger: 'blur'}
+        // ]
+      },
+      pickerOptions: {
+        shortcuts: [
+          {
+            text: '今天',
+            onClick (picker) {
+              picker.$emit('pick', new Date())
+            }
+          },
+          {
+            text: '昨天',
+            onClick (picker) {
+              const date = new Date()
+              date.setTime(date.getTime() - 3600 * 1000 * 24)
+              picker.$emit('pick', date)
+            }
+          },
+          {
+            text: '一周前',
+            onClick (picker) {
+              const date = new Date()
+              date.setTime(date.getTime() - 3600 * 1000 * 24 * 7)
+              picker.$emit('pick', date)
+            }
+          }
+        ]
+      },
+      tableData: [{
+        date: '2016-05-02',
+        name: '王小虎',
+        address: '上海市普陀区金沙江路 1518 弄'
+      }, {
+        date: '2016-05-04',
+        name: '王小虎',
+        address: '上海市普陀区金沙江路 1517 弄'
+      }, {
+        date: '2016-05-01',
+        name: '王小虎',
+        address: '上海市普陀区金沙江路 1519 弄'
+      }, {
+        date: '2016-05-03',
+        name: '王小虎',
+        address: '上海市普陀区金沙江路 1516 弄'
+      }]
+    }
+  },
+  mounted () {
+    this.$nextTick(() => {
+      this.init()
+    })
+  },
+  methods: {
+    init () {
+      this.setServiceType()
+      this.setPlatformType()
+      this.setUserInfo()
+      this.setTemplateExcel()
+    },
+    //加载数据
+    loadData: function () {
+    },
+    modifyInfo () {
+      this.isModifyMode = true
+    },
+    submitInfo () {
+      //this.isModifyMode = false
+      this.showLoading()
+      const newProject = {
+        userId: this.user.userVO.id,
+        name: this.project.name,
+        description: this.project.description,
+        contactName: this.project.contactName,
+        contactPhone: this.project.contactPhone,
+        platform: this.project.platform,
+        type: this.project.type,
+        doc: this.project.requireDocUrl,
+        file: this.project.fileUrl,
+        price: this.project.price,
+        datetime: this.project.datetime
+      }
+      Http.post(Apis.PROJECT.ADD_PROJECT, newProject).then((res) => {
+        this.hideLoading()
+        this.createProjectByFormSuccessConfirm()
+        console.log(res)
+      }).catch(error => {
+        this.hideLoading()
+        notify('error', error.data)
+      })
+    },
+    // cancelModify () {
+    //   this.isModifyMode = false
+    // },
+    handleRemove (file, fileList) {
+      console.log(file, fileList)
+    },
+    handleExceed (files, fileList) {
+      this.$message.warning(
+        `当前限制选择 1 个文件,本次选择了 ${
+          files.length
+          } 个文件,共选择了 ${files.length + fileList.length} 个文件`
+      )
+    },
+    beforeRemove (file, fileList) {
+      //return this.$confirm(`确定移除 ${file.name}?`)
+    },
+    beforeFileUpload () {
+
+    },
+    uploadProjectCreateExcelFile (param) {
+      this.showLoading()
+      const formData = new FormData()
+      let config = {
+        //添加请求头
+        headers: {'Content-Type': 'multipart/form-data'},
+      }
+      formData.append('file', param.file)
+      Http.upload(Apis.PROJECT.ADD_PROJECT_BY_EXCEL_PRE.replace('{userId}', this.user.userVO.id), formData, config).then((res) => {
+        console.log(res)
+        console.log(res.data[0].platform)
+        console.log(typeof res.data[0].platform)
+        console.log(typeof JSON.parse(res.data[0].platform))
+        console.log(JSON.parse(res.data[0].platform))
+        this.projectList = res.data
+        this.hideLoading()
+        this.showDialog()
+        //notify('success', '项目添加成功')
+      }).catch(error => {
+        notify('error', error)
+        this.hideLoading()
+      })
+    },
+    uploadRequireDoc (param) {
+      const formData = new FormData()
+      let config = {
+        //添加请求头
+        headers: {'Content-Type': 'multipart/form-data'},
+      }
+      formData.append('file', param.file)
+      Http.upload(Apis.FILE.REQUIREMENT_FILE.replace('{userId}', this.user.userVO.id), formData, config).then((res) => {
+        console.log('上传成功')
+        this.project.requireDocUrl = res.data
+        console.log(res.data)
+        notify('success', '上传成功')
+      }).catch(error => {
+        notify('error', error.data)
+      })
+    },
+    uploadApkFile (param) {
+      const formData = new FormData()
+      let config = {
+        //添加请求头
+        headers: {'Content-Type': 'multipart/form-data'},
+      }
+      formData.append('file', param.file)
+      Http.upload(Apis.FILE.APK.replace('{userId}', this.user.userVO.id), formData, config).then((res) => {
+        console.log('上传成功')
+        this.project.fileUrl = res.data
+        console.log(res)
+        notify('success', '上传成功')
+      }).catch(error => {
+        notify('error', error.data)
+      })
+    },
+    handleDialogClose (done) {
+      this.hideDialog()
+      this.project.excelFile = []
+      // this.$confirm('确认退出?退出前请记录下登录账号和密码,否则无法找回!!!')
+      //   .then(_ => {
+      //     //done()
+      //     this.hideDialog()
+      //   })
+      //   .catch(_ => {
+      //   })
+    },
+    ensureSubmitExcel () {
+      this.hideDialog()
+      this.showLoading()
+      Http.post(Apis.PROJECT.ADD_PROJECT_BY_EXCEL, this.projectList).then((res) => {
+        notify('success', '添加成功')
+        this.hideLoading()
+      }).catch((error) => {
+        notify('error', error.data)
+        this.hideLoading()
+      })
+    },
+    showDialog () {
+      this.dialogVisible = true
+    },
+    hideDialog () {
+      this.dialogVisible = false
+      //this.resetForm()
+    },
+    setServiceType () {
+      getAllServiceTypes().then((res) => {
+        this.serviceType = res
+      }).catch((error) => {
+        notify('error', '获取服务类型出错')
+      })
+    },
+    setPlatformType () {
+      this.platforms = getAllPlatformTypes()
+    },
+    createProjectByFormSuccessConfirm () {
+      this.$confirm('项目创建成功,是否跳转至主页?', '提示', {
+        confirmButtonText: '跳转至主页',
+        cancelButtonText: '继续创建项目',
+        type: 'success'
+      }).then(() => {
+        this.$router.push({
+          name: 'Home',
+          // params: {projectId: projectId, taskId: taskId}
+        })
+        // this.$message({
+        //   type: 'success',
+        //   message: '删除成功!'
+        // });
+      }).catch(() => {
+        this.resetForm()
+        // this.$message({
+        //   type: 'info',
+        //   message: '已取消删除'
+        // });
+      })
+    },
+    resetForm () {
+      this.project = {
+        name: '',
+        description: '',
+        contactName: '',
+        contactPhone: '',
+        platform: [],
+        type: [],
+        requireDoc: [],
+        requireDocUrl: '',
+        file: [],
+        fileUrl: '',
+        excelFile: [],
+        excelFileUrl: '',
+        price: '',
+        datetime: ''
+      }
+    },
+    setUserInfo () {
+      this.user = storageGet('user')
+    },
+    setTemplateExcel () {
+      this.showLoading()
+      getGreenChannelAddProjectExcelTemplateFile(this.setTemplateExcelSuccess, this.setTemplateExcelFail)
+    },
+    setTemplateExcelSuccess (res) {
+      this.hideLoading()
+      this.downloadFile = res.fileUrl
+    },
+    setTemplateExcelFail (error) {
+      this.hideLoading()
+      notify('error', '加载模板文件失败:' + error.data)
+    },
+    showLoading () {
+      this.loading = true
+    },
+    hideLoading () {
+      this.loading = false
+    }
+  },
+  watch: {
+    serviceType (val) {
+      this.serviceType = val
+    }
+  },
+  created: function () {
+  }
+}
+</script>
+
+<style scoped>
+  .el-radio {
+    margin: 10px 20px 10px 0;
+  }
+
+  .el-form-item /deep/ .el-tabs__content {
+    max-height: 120px !important;
+    overflow: auto;
+  }
+
+  .el-row {
+    margin-bottom: 10px;
+  }
+
+  .el-input {
+    width: 400px;
+  }
+</style>

+ 795 - 245
src/components/commons/Header.vue

@@ -1,26 +1,50 @@
 <template>
-  <nav class="navbar">
-    <div class="container">
-      <div class="navbar-translate">
-        <a class="navbar-brand">众测</a>
-        <button
-          type="button"
-          data-toggle="collapse"
-          aria-expanded="false"
-          aria-label="Toggle navigation"
-          @click="openNavBarFunc"
-           v-bind:class="['navbar-toggler',{ 'open-fixed': openNavBar}]"
-        >
-          <span class="navbar-toggler-icon"></span>
-          <span class="navbar-toggler-icon"></span>
-          <span class="navbar-toggler-icon"></span>
-        </button>
+  <nav class="navbar" v-loading.fullscreen.lock="fullScreenLoading">
+    <div class="container" style="min-width: 1100px">
+      <!--<div class="navbar-translate" style="text-align: center;vertical-align: middle;">-->
+      <!--<span>-->
+      <!--<a href="javascript:;">-->
+      <!--<img :src="defaultValue.image" style="height: 50px;object-fit: contain;" >-->
+      <!--</a>-->
+      <!--</span>-->
+      <!--<span  style="margin-bottom: 20px"><a style="font-size: 25px">众测</a></span>-->
+      <!--<button-->
+      <!--type="button"-->
+      <!--data-toggle="collapse"-->
+      <!--aria-expanded="false"-->
+      <!--aria-label="Toggle navigation"-->
+      <!--@click="openNavBarFunc"-->
+      <!--v-bind:class="['navbar-toggler',{ 'open-fixed': openNavBar}]"-->
+      <!--&gt;-->
+      <!--<span class="navbar-toggler-icon"></span>-->
+      <!--<span class="navbar-toggler-icon"></span>-->
+      <!--<span class="navbar-toggler-icon"></span>-->
+      <!--</button>-->
+      <!--</div>-->
+      <div>
+        <ul class="navbar-nav ml-auto">
+          <li class="dropdown nav-item">
+            <router-link to="/home">
+              <a data-toggle="dropdown">
+                <img style="height: 50px;padding-top: 10px" :src="defaultValue.image">
+              </a>
+            </router-link>
+          </li>
+          <li class="dropdown nav-item">
+            <router-link to="/home">
+              <a class="dropdown-toggle nav-link" data-toggle="dropdown">
+                <span style="font-size: 20px">群智众测平台</span>
+              </a>
+            </router-link>
+          </li>
+        </ul>
       </div>
-      <div class="collapse navbar-collapse"  v-bind:style="{right:openNavBar?'230px':'0'}">
-        <ul class="navbar-nav ml-auto"  >
+      <div style="margin-left: 0; flex: auto">
+        <ul class="navbar-nav ml-auto">
+
           <li class="dropdown nav-item">
             <router-link to="/home">
-              <a  class="dropdown-toggle nav-link" data-toggle="dropdown">
+              <a class="dropdown-toggle nav-link" data-toggle="dropdown">
                 <img class="icon" src="@/assets/img/home_icon.svg">
                 <span>首页</span>
               </a>
@@ -28,19 +52,30 @@
           </li>
           <li class="dropdown nav-item">
             <router-link to="/square">
-              <a  class="dropdown-toggle nav-link" data-toggle="dropdown">
+              <a class="dropdown-toggle nav-link" data-toggle="dropdown">
                 <img class="icon" src="@/assets/img/square_icon.svg">
                 <span>任务广场</span>
               </a>
             </router-link>
           </li>
+
+        </ul>
+      </div>
+      <div>
+        <ul class="navbar-nav ml-auto">
+
           <li class="dropdown nav-item">
-            <router-link to="/mine">
-              <a  class="dropdown-toggle nav-link" data-toggle="dropdown">
+            <router-link v-if="isLogin" to="/mine">
+              <a class="dropdown-toggle nav-link" data-toggle="dropdown">
                 <img class="icon" src="@/assets/img/mine_icon.svg">
                 <span>我的众测</span>
               </a>
             </router-link>
+            <a v-if="!isLogin" class="dropdown-toggle nav-link" data-toggle="dropdown"
+               :href="loginUrl">
+              <img class="icon" src="@/assets/img/mine_icon.svg">
+              <span>登录</span>
+            </a>
             <div class="dropdown-menu dropdown-with-icons">
               <a href="./sections.html#headers" class="dropdown-item">
                 <i class="material-icons"></i> Headers
@@ -50,287 +85,802 @@
               </a>
             </div>
           </li>
+          <li class="dropdown nav-item" style="margin-left: 50px">
+            <router-link v-if="isLogin" to="/mine">
+              <a data-toggle="dropdown">
+                <img class="user-img" :src="defaultValue.image">
+              </a>
+            </router-link>
+          </li>
+          <el-dropdown v-if="isLogin">
+            <span class="dropdown-toggle nav-link el-dropdown-link">{{user.userVO.name}}<i
+              class="el-icon-arrow-down el-icon--right"></i>
+            </span>
+            <el-dropdown-menu slot="dropdown">
+              <el-dropdown-item v-if="rolesPermissions.isSystemAdministrator">
+                <router-link :to="{ name: 'AuthenticationManage'}">
+                  <el-link icon="el-icon-view" :underline="false">
+                    审核认证信息
+                  </el-link>
+                </router-link>
+              </el-dropdown-item>
+              <el-dropdown-item v-if="user.authStatus.text == '审核通过' && user.userVO.authType=='agency'">
+                <router-link :to="{ name: 'Agency',params:{userId:user.userVO.id}}">
+                  <el-link icon="el-icon-edit" :underline="false">
+                    修改机构信息
+                  </el-link>
+                </router-link>
+              </el-dropdown-item>
+              <el-dropdown-item v-if="user.authStatus.text == '未实名认证' && !rolesPermissions.isSystemAdministrator">
+                <router-link :to="{ name: 'AuthenticationIndex'}">
+                  <el-link type="info" icon="el-icon-warning-outline" :underline="false">
+                    未实名认证
+                  </el-link>
+                </router-link>
+              </el-dropdown-item>
+              <el-dropdown-item v-if="user.authStatus.text == '认证审核中'" @click.native="handleClickAuthChecking()">
+                <el-link type="warning" icon="el-icon-loading" :underline="false">
+                  认证审核中
+                </el-link>
+              </el-dropdown-item>
+              <el-dropdown-item @click.native="handleClickAuthPass()" v-if="user.authStatus.text == '审核通过'">
+                <el-link type="primary" icon="el-icon-check" :underline="false">
+                  已认证
+                </el-link>
+              </el-dropdown-item>
+              <el-dropdown-item @click.native="handleClickAuthReject()" v-if="user.authStatus.text == '审核未通过'">
+                <el-link type="danger" icon="el-icon-close" :underline="false">
+                  认证失败
+                </el-link>
+              </el-dropdown-item>
+              <el-dropdown-item divided @click.native="userLogout()">登出</el-dropdown-item>
+            </el-dropdown-menu>
+          </el-dropdown>
+          <el-dialog title="认证信息审核中" :visible.sync="isShowAuthCheckingDialog" width="40%"
+                     :before-close="hideAuthCheckingDialog" center>
+            <span>
+              <el-card v-if="authInfo.type" class="box-card">
+                <div slot="header" class="clearfix">
+                  <span>认证信息</span>
+                </div>
+                <div class="text item">
+                  <ul v-if="authInfo.type=='个人'" style="list-style-type:none">
+                    <li>认证类型:{{authInfo.type}}认证</li>
+                    <li>认证姓名:{{authInfo.realName}}</li>
+                    <li>认证账户:{{authInfo.bankAccount}}</li>
+                    <li>认证地址:{{authInfo.address}}</li>
+                    <li>申请时间:{{authInfo.createTime}}</li>
+                    <li>认证状态:{{authInfo.status}}</li>
+                    <li>失败原因:{{authInfo.rejectReason}}</li>
+                  </ul>
+
+                  <ul v-if="authInfo.type=='机构'" style="list-style-type:none">
+                    <li>认证类型:{{authInfo.type}}认证</li>
+                    <li>认证姓名:{{authInfo.evaluationAgencyName}}</li>
+                    <li>认证账户:{{authInfo.bankAccount}}</li>
+                    <li>认证地址:{{authInfo.address}}</li>
+                    <li>申请时间:{{authInfo.createTime}}</li>
+                    <li>认证状态:{{authInfo.status}}</li>
+                    <li>失败原因:{{authInfo.rejectReason}}</li>
+                  </ul>
+
+                  <ul v-if="authInfo.type=='企业'" style="list-style-type:none">
+                    <li>认证类型:{{authInfo.type}}认证</li>
+                    <li>认证企业名称:{{authInfo.companyName}}</li>
+                    <li>认证法人姓名:{{authInfo.legalPersonName}}</li>
+                    <li>认证账户:{{authInfo.bankAccount}}</li>
+                    <li>统一信用代码:{{authInfo.unifiedSocialCreditCode}}</li>
+                    <li>认证地址:{{authInfo.address}}</li>
+                    <li>申请时间:{{authInfo.createTime}}</li>
+                    <li>认证状态:{{authInfo.status}}</li>
+                    <li>失败原因:{{authInfo.rejectReason}}</li>
+                  </ul>
+                </div>
+              </el-card>
+            </span>
+            <span slot="footer" class="dialog-footer">
+              <el-button size="mini" @click="hideAuthCheckingDialog">返回</el-button>
+              <el-button size="mini" type="danger" @click="deleteOldAuthInfo">放弃认证</el-button>
+              <el-button size="mini" type="primary" @click="handleUpdateAuthInfo">重新认证</el-button>
+            </span>
+          </el-dialog>
+          <el-dialog title="认证成功" :visible.sync="isShowAuthPassDialog" width="40%" :before-close="hideAuthPassDialog"
+                     center>
+            <span>
+              <el-card v-if="authInfo.type" class="box-card">
+                <div slot="header" class="clearfix">
+                  <span>认证信息</span>
+                </div>
+                <div class="text item">
+                  <ul v-if="authInfo.type=='个人'" style="list-style-type:none">
+                    <li>认证类型:{{authInfo.type}}认证</li>
+                    <li>认证姓名:{{authInfo.realName}}</li>
+                    <li>认证账户:{{authInfo.bankAccount}}</li>
+                    <li>认证地址:{{authInfo.address}}</li>
+                    <li>申请时间:{{authInfo.createTime}}</li>
+                    <li>认证状态:{{authInfo.status}}</li>
+                    <li>失败原因:{{authInfo.rejectReason}}</li>
+                  </ul>
+
+                  <ul v-if="authInfo.type=='机构'" style="list-style-type:none">
+                    <li>认证类型:{{authInfo.type}}认证</li>
+                    <li>认证姓名:{{authInfo.evaluationAgencyName}}</li>
+                    <li>认证账户:{{authInfo.bankAccount}}</li>
+                    <li>认证地址:{{authInfo.address}}</li>
+                    <li>申请时间:{{authInfo.createTime}}</li>
+                    <li>认证状态:{{authInfo.status}}</li>
+                    <li>失败原因:{{authInfo.rejectReason}}</li>
+                  </ul>
+
+                  <ul v-if="authInfo.type=='企业'" style="list-style-type:none">
+                    <li>认证类型:{{authInfo.type}}认证</li>
+                    <li>认证企业名称:{{authInfo.companyName}}</li>
+                    <li>认证法人姓名:{{authInfo.legalPersonName}}</li>
+                    <li>认证账户:{{authInfo.bankAccount}}</li>
+                    <li>统一信用代码:{{authInfo.unifiedSocialCreditCode}}</li>
+                    <li>认证地址:{{authInfo.address}}</li>
+                    <li>申请时间:{{authInfo.createTime}}</li>
+                    <li>认证状态:{{authInfo.status}}</li>
+                    <li>失败原因:{{authInfo.rejectReason}}</li>
+                  </ul>
+                </div>
+              </el-card>
+            </span>
+            <span slot="footer" class="dialog-footer">
+              <el-button size="mini" @click="hideAuthPassDialog">返回</el-button>
+            </span>
+          </el-dialog>
+          <el-dialog title="认证失败" :visible.sync="isShowAuthRejectDialog" width="40%"
+                     :before-close="hideAuthRejectDialog"
+                     center>
+            <span>
+              <el-card v-if="authInfo.type" class="box-card">
+                <div slot="header" class="clearfix">
+                  <span>认证信息</span>
+                </div>
+                <div class="text item">
+                  <ul v-if="authInfo.type=='个人'" style="list-style-type:none">
+                    <li>认证类型:{{authInfo.type}}认证</li>
+                    <li>认证姓名:{{authInfo.realName}}</li>
+                    <li>认证账户:{{authInfo.bankAccount}}</li>
+                    <li>认证地址:{{authInfo.address}}</li>
+                    <li>申请时间:{{authInfo.createTime}}</li>
+                    <li>认证状态:{{authInfo.status}}</li>
+                    <li>失败原因:{{authInfo.rejectReason}}</li>
+                  </ul>
+
+                  <ul v-if="authInfo.type=='机构'" style="list-style-type:none">
+                    <li>认证类型:{{authInfo.type}}认证</li>
+                    <li>认证姓名:{{authInfo.evaluationAgencyName}}</li>
+                    <li>认证账户:{{authInfo.bankAccount}}</li>
+                    <li>认证地址:{{authInfo.address}}</li>
+                    <li>申请时间:{{authInfo.createTime}}</li>
+                    <li>认证状态:{{authInfo.status}}</li>
+                    <li>失败原因:{{authInfo.rejectReason}}</li>
+                  </ul>
+
+                  <ul v-if="authInfo.type=='企业'" style="list-style-type:none">
+                    <li>认证类型:{{authInfo.type}}认证</li>
+                    <li>认证企业名称:{{authInfo.companyName}}</li>
+                    <li>认证法人姓名:{{authInfo.legalPersonName}}</li>
+                    <li>认证账户:{{authInfo.bankAccount}}</li>
+                    <li>统一信用代码:{{authInfo.unifiedSocialCreditCode}}</li>
+                    <li>认证地址:{{authInfo.address}}</li>
+                    <li>申请时间:{{authInfo.createTime}}</li>
+                    <li>认证状态:{{authInfo.status}}</li>
+                    <li>失败原因:{{authInfo.rejectReason}}</li>
+                  </ul>
+                </div>
+              </el-card>
+            </span>
+            <span slot="footer" class="dialog-footer">
+              <el-button size="mini" @click="hideAuthRejectDialog">返回</el-button>
+              <el-button size="mini" type="danger" @click="deleteOldAuthInfo">放弃认证</el-button>
+              <el-button size="mini" type="primary" @click="handleUpdateAuthInfo">修改认证信息</el-button>
+            </span>
+          </el-dialog>
+          <!--<li class="dropdown nav-item">-->
+          <!--<router-link v-if="isLogin" to="/mine">-->
+          <!--<a class="dropdown-toggle nav-link" data-toggle="dropdown">-->
+          <!--<span>{{user.userVO.name}}</span>-->
+          <!--</a>-->
+          <!--</router-link>-->
+          <!--</li>-->
+          <!--<li class="dropdown nav-item">-->
+          <!--<router-link v-if="isLogin" to="/mine">-->
+          <!--<div style="margin-top: 5px;margin-right: 20px">-->
+          <!--<el-tooltip class="item" effect="dark" content="认证成功" placement="bottom">-->
+          <!--<el-link type="info" disabled icon="el-icon-warning-outline">已认证</el-link>-->
+          <!--</el-tooltip>-->
+          <!--</div>-->
+          <!--</router-link>-->
+          <!--</li>-->
+          <!--<li class="dropdown nav-item">-->
+          <!--<router-link v-if="isLogin" to="/mine">-->
+          <!--<div style="margin-top: 5px;margin-right: 20px">-->
+          <!--<el-tooltip class="item" effect="dark" content="点击进行认证" placement="bottom">-->
+          <!--<el-link type="danger" icon="el-icon-warning-outline">未实名认证</el-link>-->
+          <!--</el-tooltip>-->
+          <!--</div>-->
+          <!--</router-link>-->
+          <!--</li>-->
+          <!--<li>-->
+          <!--<a v-if="isLogin" class="dropdown-toggle nav-link" data-toggle="dropdown" href="#" @click="userLogout()">-->
+          <!--<span>登出</span>-->
+          <!--</a>-->
+          <!--</li>-->
         </ul>
       </div>
     </div>
+
   </nav>
 </template>
 
 <script>
+import {
+  defaultValue,
+  deleteAuthInfo,
+  getCurrentAgencyAuthInfo,
+  getCurrentEnterpriseAuthInfo,
+  getCurrentIndividualAuthenInfo,
+  getCurrentUser,
+  getRolesPermissions,
+  logout,
+  storageGet,
+  storageSave
+} from '@/js/index'
+import {notify} from '@/constants/index'
+
 export default {
-  name: "header-container",
-  data(){
-    return{
-      openNavBar:false
+  name: 'header-container',
+  data () {
+    return {
+      user: {},
+      fullScreenLoading: true,
+      loginUrl: process.env.LOGIN_URL,
+      authInfo: {},
+      isShowAuthCheckingDialog: false,
+      isShowAuthRejectDialog: false,
+      isShowAuthPassDialog: false,
+      //loading: true,
+      openNavBar: false,
+      defaultValue: defaultValue,
+      userIdentity: '',
+      isLogin: false,
+      rolesPermissions: {}
     }
   },
-  methods:{
-    openNavBarFunc(){
-      this.openNavBar = !this.openNavBar;
+  mounted () {
+    this.$nextTick(() => {
+
+    })
+  },
+  watch: {
+    'user.authStatus' (val) {
+      this.user.authStatus = val
+      console.log('changed')
+      console.log(this.user.authStatus)
+    },
+    deep: true
+  },
+  methods: {
+    openNavBarFunc () {
+      this.openNavBar = !this.openNavBar
+    },
+    setCurrUserByHttp () {
+      // getCurrentUser().then((res) => {
+      //   console.log(res)
+      //   storageSave('user', res)
+      //   storageSave('rolesPermissions', getRolesPermissions(res.roleList))
+      //   this.isLogin = true
+      //   this.fullScreenLoading = false
+      // }).catch(error => {
+      //   this.fullScreenLoading = false
+      //   console.log(error)
+      //   if (error.status == 401) {
+      //     notify('warning', error.data)
+      //   } else {
+      //     notify('error', error.data)
+      //   }
+      // })
+    },
+    setUserInfo () {
+      // storageGet('user').then((res)=>{
+      //   if (res == null){
+      //     this.setCurrUserByHttp()
+      //   }else{
+      //     this.fullScreenLoading = false
+      //     this.isLogin = true
+      //   }
+      // }).catch((error)=>{
+      //   this.setCurrUserByHttp()
+      // })
+      if (storageGet('user') == null) {
+        storageSave('rolesPermissions', {
+          'isRegionManager': false,
+          'isIndividualUser': false,
+          'isEnterpriseUser': false,
+          'isAgency': false,
+          'isSystemAdministrator': false
+        })
+        console.log('本地没有用户信息,开始加载用户信息')
+        getCurrentUser().then((res) => {
+          console.log(res)
+          storageSave('user', res)
+          this.user = res
+          this.rolesPermissions = getRolesPermissions(res.roleList)
+          storageSave('rolesPermissions', getRolesPermissions(res.roleList))
+          console.log('用户信息加载成功')
+          this.isLogin = true
+          this.fullScreenLoading = false
+        }).catch((error) => {
+          console.log('用户信息加载失败')
+          this.fullScreenLoading = false
+        })
+      } else {
+        this.user = storageGet('user')
+        this.fullScreenLoading = false
+        this.isLogin = true
+      }
+    },
+    getCurrentUserSuccess (res) {
+      console.log(res)
+      storageSave('user', res)
+      this.user = res
+      this.rolesPermissions = getRolesPermissions(res.roleList)
+      storageSave('rolesPermissions', getRolesPermissions(res.roleList))
+      console.log('用户信息加载成功')
+      this.isLogin = true
+      this.fullScreenLoading = false
+    },
+    getCurrentUserFail (error) {
+      console.log('用户信息加载失败')
+      this.fullScreenLoading = false
+    },
+    userLogout () {
+      this.isLogin = false
+      logout().then((res) => {
+        this.$router.push({
+          name: 'Index',
+        })
+      })
+
+    },
+    showLoading () {
+      this.fullScreenLoading = true
+    },
+    hideLoading () {
+      this.fullScreenLoading = false
+    },
+    handleClickAuthReject () {
+      if (this.user.userVO.authType == 'agency') {
+        this.$router.push({
+          name: 'AgencyAuthentication',
+          params: {userId: this.user.userVO.id}
+        })
+      }
+      if (this.user.userVO.authType == 'enterprise') {
+        this.$router.push({
+          name: 'EnterpriseAuthentication',
+          params: {userId: this.user.userVO.id}
+        })
+      }
+      if (this.user.userVO.authType == 'personal') {
+        this.$router.push({
+          name: 'IndividualAuthentication',
+          params: {userId: this.user.userVO.id}
+        })
+      }
+
+      //this.getAuthInfo()
+    },
+    handleClickAuthPass () {
+      if (this.user.userVO.authType == 'agency') {
+        this.$router.push({
+          name: 'AgencyAuthentication',
+          params: {userId: this.user.userVO.id}
+        })
+      }
+      if (this.user.userVO.authType == 'enterprise') {
+        this.$router.push({
+          name: 'EnterpriseAuthentication',
+          params: {userId: this.user.userVO.id}
+        })
+      }
+      if (this.user.userVO.authType == 'personal') {
+        this.$router.push({
+          name: 'IndividualAuthentication',
+          params: {userId: this.user.userVO.id}
+        })
+      }
+      //this.getAuthInfo()
+    },
+    handleClickAuthChecking () {
+      //this.getAuthInfo()
+      if (this.user.userVO.authType == 'agency') {
+        this.$router.push({
+          name: 'AgencyAuthentication',
+          params: {userId: this.user.userVO.id}
+        })
+      }
+      if (this.user.userVO.authType == 'enterprise') {
+        this.$router.push({
+          name: 'EnterpriseAuthentication',
+          params: {userId: this.user.userVO.id}
+        })
+      }
+      if (this.user.userVO.authType == 'personal') {
+        this.$router.push({
+          name: 'IndividualAuthentication',
+          params: {userId: this.user.userVO.id}
+        })
+      }
+    },
+    showAuthRejectDialog () {
+      this.isShowAuthRejectDialog = true
+    },
+    showAuthPassDialog () {
+      this.isShowAuthPassDialog = true
+    },
+    showAuthCheckingDialog () {
+      this.isShowAuthCheckingDialog = true
+    },
+    hideAuthRejectDialog () {
+      this.isShowAuthRejectDialog = false
+    },
+    hideAuthPassDialog () {
+      this.isShowAuthPassDialog = false
+    },
+    hideAuthCheckingDialog () {
+      this.isShowAuthCheckingDialog = false
+    },
+    deleteOldAuthInfo () {
+      this.hideAuthCheckingDialog()
+      this.hideAuthRejectDialog()
+      this.hideAuthPassDialog()
+      this.showLoading()
+      deleteAuthInfo().then((res) => {
+        this.hideLoading()
+        notify('success', '成功删除认证信息')
+      }).catch((error) => {
+        this.hideLoading()
+        notify('error', '删除认证信息失败:' + error.data)
+      })
+    },
+    getAuthInfo () {
+      this.showLoading()
+      if (this.user.userVO.authType == 'agency') {
+        getCurrentAgencyAuthInfo(this.user.userVO.id, this.getCurrentAgencyAuthInfoSuccess, this.getCurrentAgencyAuthInfoFail)
+      }
+      if (this.user.userVO.authType == 'personal') {
+        getCurrentIndividualAuthenInfo(this.user.userVO.id, this.getCurrentIndividualAuthenInfoSuccess, this.getCurrentIndividualAuthenInfoFail)
+      }
+      if (this.user.userVO.authType == 'enterprise') {
+        getCurrentEnterpriseAuthInfo(this.user.userVO.id, this.getCurrentEnterpriseAuthInfoSuccess, this.getCurrentEnterpriseAuthInfoFail)
+      }
+    },
+    getCurrentAgencyAuthInfoSuccess () {
+      this.hideLoading()
+    },
+    getCurrentAgencyAuthInfoFail () {
+      this.hideLoading()
+    },
+    getCurrentIndividualAuthenInfoSuccess () {
+      this.hideLoading()
+    },
+    getCurrentIndividualAuthenInfoFail () {
+      this.hideLoading()
+    },
+    getCurrentEnterpriseAuthInfoSuccess () {
+      this.hideLoading()
+    },
+    getCurrentEnterpriseAuthInfoFail () {
+      this.hideLoading()
+    },
+    handleUpdateAuthInfo () {
+      this.hideAuthPassDialog()
+      this.hideAuthRejectDialog()
+      this.hideAuthCheckingDialog()
+      if (this.user.userVO.authType == 'personal') {
+        this.$router.push({
+          name: 'IndividualAuthentication',
+          params: {
+            userId: this.authInfo.userId
+          }
+        })
+      }
+      if (this.authInfo.type == 'enterprise') {
+        this.$router.push({
+          name: 'EnterpriseAuthentication',
+          params: {
+            userId: this.authInfo.userId
+          }
+        })
+      }
+      if (this.authInfo.type == 'agency') {
+        this.$router.push({
+          name: 'AgencyAuthentication',
+          params: {
+            userId: this.authInfo.userId
+          }
+        })
+      }
     }
+  },
+  created () {
+    var self = this
+    this.$root.$on('user', function (val) {
+      self.user = val
+    })
+  },
+  beforeMount () {
+    this.setUserInfo()
+    // if (storageGet('user' != null)){
+    //   this.isLogin = true
+    // }
+    console.log(this.isLogin)
   }
-};
+}
 </script>
 
 <style lang="less" scoped>
 
-.open-fixed{
-  position:fixed;
-  right:5px;
-  z-index: 1033;
-}
-
-.navbar {
-  background-color: #fff !important;
-  box-shadow: none;
-  padding-top: 10px;
-  padding-bottom: 10px;
-  color: #000;
-  transition: all 0.15s ease 0s;
-  display: flex;
-  flex-wrap: wrap;
-  align-items: center;
-  justify-content: space-between;
-}
-
-@media (max-width: 991px) {
-  [class*="navbar-expand-"] > .container {
-    padding-left: 15px;
-    padding-right: 15px;
+  .open-fixed {
+    position: fixed;
+    right: 5px;
+    z-index: 1033;
   }
-}
 
-.navbar > .container {
-  display: flex;
-  flex-wrap: wrap;
-  align-items: center;
-  justify-content: space-between;
-  flex: 1;
-}
+  .navbar {
+    background-color: #fff !important;
+    box-shadow: none;
+    padding-top: 10px;
+    padding-bottom: 10px;
+    color: #000;
+    transition: all 0.15s ease 0s;
+    display: flex;
+    flex-wrap: wrap;
+    align-items: center;
+    justify-content: space-between;
+  }
 
-.navbar .navbar-brand {
-  position: relative;
-  color: inherit;
-  font-size: 1.8rem;
-  line-height: 30px;
-  padding: 10px 0;
-  margin-right: 1rem;
-  display: inline-block;
-  white-space: nowrap;
-}
+  @media (max-width: 991px) {
+    [class*="navbar-expand-"] > .container {
+      padding-left: 15px;
+      padding-right: 15px;
+    }
+  }
 
-@media (max-width: 991px) {
-  .navbar .navbar-translate {
-    width: 100%;
-    position: relative;
+  .navbar > .container {
     display: flex;
-    -ms-flex-pack: justify !important;
-    justify-content: space-between !important;
-    -ms-flex-align: center;
+    flex-wrap: wrap;
     align-items: center;
-    transition: transform 0.5s cubic-bezier(0.685, 0.0473, 0.346, 1);
+    justify-content: space-between;
+    flex: 1;
   }
-}
 
-.navbar-collapse {
-  flex-basis: 100%;
-  flex-grow: 1;
-  align-items: center;
-}
+  .navbar .navbar-brand {
+    position: relative;
+    color: inherit;
+    font-size: 1.8rem;
+    line-height: 30px;
+    padding: 10px 0;
+    margin-right: 1rem;
+    display: inline-block;
+    white-space: nowrap;
+  }
 
-@media (max-width: 991px) {
-  .navbar-collapse {
-    position: fixed;
-    display: block;
-    top: 0;
-    height:100vh;
-    width: 230px;
-    right: 0;
-    margin-right: 0 !important;
-    z-index: 1032;
-    visibility: visible;
-    background-color: #fff;
-    overflow-y: visible;
-    border-top: none;
-    text-align: left;
-    padding-right: 0;
-    padding-left: 0;
-    max-height: none !important;
-    -webkit-transform: translate3d(230px, 0, 0);
-    transform: translate3d(230px, 0, 0);
-    transition: all 0.5s cubic-bezier(0.685, 0.0473, 0.346, 1);
+  @media (max-width: 991px) {
+    .navbar .navbar-translate {
+      width: 100%;
+      position: relative;
+      display: flex;
+      -ms-flex-pack: justify !important;
+      justify-content: space-between !important;
+      -ms-flex-align: center;
+      align-items: center;
+      transition: transform 0.5s cubic-bezier(0.685, 0.0473, 0.346, 1);
+    }
   }
-}
 
-@media (min-width: 992px) {
   .navbar-collapse {
-    display: flex !important;
-    flex-basis: auto;
+    flex-basis: 100%;
+    flex-grow: 1;
+    align-items: center;
   }
-}
-
-[type="reset"],
-[type="submit"],
-button,
-html [type="button"] {
-  -webkit-appearance: button;
-}
-
-.navbar-toggler {
-  padding: 0.25rem 0.75rem;
-  font-size: 1.25rem;
-  line-height: 1;
-  background-color: transparent;
-  border: 1px solid transparent;
-  border-radius: 0.25rem;
-  outline: none;
-}
 
+  @media (max-width: 991px) {
+    .navbar-collapse {
+      position: fixed;
+      display: block;
+      top: 0;
+      height: 100vh;
+      width: 230px;
+      right: 0;
+      margin-right: 0 !important;
+      z-index: 1032;
+      visibility: visible;
+      background-color: #fff;
+      overflow-y: visible;
+      border-top: none;
+      text-align: left;
+      padding-right: 0;
+      padding-left: 0;
+      max-height: none !important;
+      -webkit-transform: translate3d(230px, 0, 0);
+      transform: translate3d(230px, 0, 0);
+      transition: all 0.5s cubic-bezier(0.685, 0.0473, 0.346, 1);
+    }
+  }
 
+  @media (min-width: 992px) {
+    .navbar-collapse {
+      display: flex !important;
+      flex-basis: auto;
+    }
+  }
 
-.navbar-toggler:not(:disabled):not(.disabled) {
-  cursor: pointer;
-}
+  [type="reset"],
+  [type="submit"],
+  button,
+  html [type="button"] {
+    -webkit-appearance: button;
+  }
 
-@media (min-width: 992px) {
   .navbar-toggler {
-    display: none;
+    padding: 0.25rem 0.75rem;
+    font-size: 1.25rem;
+    line-height: 1;
+    background-color: transparent;
+    border: 1px solid transparent;
+    border-radius: 0.25rem;
+    outline: none;
   }
-}
-@media (max-width: 991px) {
-  .navbar.navbar-transparent .navbar-toggler .navbar-toggler-icon {
-    background-color: #fff;
+
+  .navbar-toggler:not(:disabled):not(.disabled) {
+    cursor: pointer;
   }
-}
 
-.navbar .navbar-toggler .navbar-toggler-icon + .navbar-toggler-icon {
-  margin-top: 4px;
-}
+  @media (min-width: 992px) {
+    .navbar-toggler {
+      display: none;
+    }
+  }
 
-.navbar .navbar-toggler .navbar-toggler-icon {
-  width: 22px;
-  height: 2px;
-  vertical-align: middle;
-  outline: 0;
-  display: block;
-  border-radius: 1px;
-}
+  @media (max-width: 991px) {
+    .navbar.navbar-transparent .navbar-toggler .navbar-toggler-icon {
+      background-color: #fff;
+    }
+  }
 
-.navbar .navbar-toggler .navbar-toggler-icon {
-  background-color: #555;
-}
+  .navbar .navbar-toggler .navbar-toggler-icon + .navbar-toggler-icon {
+    margin-top: 4px;
+  }
 
-.navbar-toggler-icon {
-  display: inline-block;
-  width: 1.5em;
-  height: 1.5em;
-  vertical-align: middle;
-  content: "";
-  background: no-repeat 50%;
-  background-size: 100% 100%;
-}
+  .navbar .navbar-toggler .navbar-toggler-icon {
+    width: 22px;
+    height: 2px;
+    vertical-align: middle;
+    outline: 0;
+    display: block;
+    border-radius: 1px;
+  }
 
-.navbar-nav {
-  display: flex;
-  flex-direction: column;
-  padding-left: 0;
-  margin-bottom: 0;
-  list-style: none;
-  text-align: center;
-}
+  .navbar .navbar-toggler .navbar-toggler-icon {
+    background-color: #555;
+  }
 
-@media (min-width: 991px) {
-  .navbar .navbar-nav {
-    align-items: center;
+  .navbar-toggler-icon {
+    display: inline-block;
+    width: 1.5em;
+    height: 1.5em;
+    vertical-align: middle;
+    content: "";
+    background: no-repeat 50%;
+    background-size: 100% 100%;
   }
-}
 
-@media (min-width: 992px) {
   .navbar-nav {
-    flex-direction: row;
+    display: flex;
+    flex-direction: column;
+    padding-left: 0;
+    margin-bottom: 0;
+    list-style: none;
+    text-align: center;
   }
-}
 
-@media (max-width: 991px) {
-  .navbar-nav {
-    margin-top:70px;
-    text-align: right;
+  @media (min-width: 991px) {
+    .navbar .navbar-nav {
+      align-items: center;
+    }
   }
-}
 
-.ml-auto,
-.mx-auto {
-  margin-left: auto !important;
-}
+  @media (min-width: 992px) {
+    .navbar-nav {
+      flex-direction: row;
+    }
+  }
 
-.collapsing,
-.dropdown,
-.dropup {
-  position: relative;
-}
+  @media (max-width: 991px) {
+    .navbar-nav {
+      margin-top: 70px;
+      text-align: right;
+    }
+  }
+
+  .ml-auto,
+  .mx-auto {
+    margin-left: auto !important;
+  }
 
-.dropdown-menu {
-  position: absolute;
-  top: 100%;
-  left: 0;
-  z-index: 1000;
-  float: left;
-  min-width: 10rem;
-  padding: 0.5rem 0;
-  margin: 0.125rem 0 0;
-  font-size: 1rem;
-  color: #212529;
-  text-align: left;
-  list-style: none;
-  background-color: #fff;
-  background-clip: padding-box;
-  border: 1px solid rgba(0, 0, 0, 0.15);
-  border-radius: 0.25rem;
-  box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.2),
+  .collapsing,
+  .dropdown,
+  .dropup {
+    position: relative;
+  }
+
+  .dropdown-menu {
+    position: absolute;
+    top: 100%;
+    left: 0;
+    z-index: 1000;
+    float: left;
+    min-width: 10rem;
+    padding: 0.5rem 0;
+    margin: 0.125rem 0 0;
+    font-size: 1rem;
+    color: #212529;
+    text-align: left;
+    list-style: none;
+    background-color: #fff;
+    background-clip: padding-box;
+    border: 1px solid rgba(0, 0, 0, 0.15);
+    border-radius: 0.25rem;
+    box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.2),
     0 1px 5px 0 rgba(0, 0, 0, 0.12);
-  display: none;
-  padding: 0.3125rem 0;
-  border: 0;
-  opacity: 0;
-  transform: scale(0);
-  transform-origin: 0 0;
-  will-change: transform, opacity;
-  transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1),
+    display: none;
+    padding: 0.3125rem 0;
+    border: 0;
+    opacity: 0;
+    transform: scale(0);
+    transform-origin: 0 0;
+    will-change: transform, opacity;
+    transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1),
     opacity 0.2s cubic-bezier(0.4, 0, 0.2, 1);
-  box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.26);
-}
-
-.navbar-nav .dropdown-menu {
-  float: none;
-}
+    box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.26);
+  }
 
-@media (min-width: 992px) {
   .navbar-nav .dropdown-menu {
-    position: absolute;
+    float: none;
   }
-}
 
-@media (min-width: 992px) {
-  .navbar-nav .nav-link {
-    padding-right: 0.5rem;
-    padding-left: 0.5rem;
+  @media (min-width: 992px) {
+    .navbar-nav .dropdown-menu {
+      position: absolute;
+    }
   }
-}
 
-.navbar .navbar-nav .nav-item .nav-link {
-  padding: 15px;
-  // text-align: center;
-  height: 20px;
-  vertical-align: middle;
-  color: inherit;
-  display: block;
-}
+  @media (min-width: 992px) {
+    .navbar-nav .nav-link {
+      padding-right: 0.5rem;
+      padding-left: 0.5rem;
+    }
+  }
 
-.nav-link > span {
-  /* font-size: 1.2rem; */
-  height: 100%;
-  vertical-align: middle;
-  display: inline-block;
-  line-height: 20px;
-}
+  .navbar .navbar-nav .nav-item .nav-link {
+    padding: 15px;
+    // text-align: center;
+    height: 20px;
+    vertical-align: middle;
+    color: inherit;
+    display: block;
+  }
+
+  .nav-link > span {
+    /* font-size: 1.2rem; */
+    height: 100%;
+    vertical-align: middle;
+    display: inline-block;
+    line-height: 20px;
+  }
 </style>

+ 116 - 55
src/components/commons/ProjectItem.vue

@@ -1,75 +1,136 @@
 <template>
   <div class="project-item-container">
-    <span class="col-xl-2 col-lg-3 col-md-4 col-sm-1">
-      <img class="project-cover" src="@/assets/img/home_ban1.jpg">
-    </span>
-    <span class="project-title col-md-2 col-sm-10">{{project.name}}</span>
-    <span class="project-title col-md-2 col-sm-10">{{project.code}}</span>
-    <span class="col-md-1 col-sm-5">
-      <span
-        v-bind:class="['badge',{ 'ios-platform': item.toLowerCase()=='ios','android-platform': item.toLowerCase()=='android','web-platform': item.toLowerCase()=='web'}]"
-        v-for="item in platformType"
-      >{{item}}</span>
-    </span>
-    <span class="col-md-1 col-sm-5">¥{{project.price}}</span>
-    <span class="project-td">
-      <span class="btn btn-medium btn-info" @click="goToProjectDetail(projectId)">查看详情</span>
-    </span>
+    <!--<span class="col-xl-2 col-lg-3 col-md-4 col-sm-1" style="width: 150px">-->
+    <!--<img class="project-cover" src="@/assets/img/home_ban1.jpg">-->
+    <!--</span>-->
+    <!--<span class="project-title col-md-2 col-sm-10" style="width: 150px;font-size: 12px">{{project.name}}</span>-->
+    <!--<span class="project-title col-md-2 col-sm-10" style="width: 10%;font-size: 12px">{{project.id}}</span>-->
+    <!--<span class="col-md-2 col-sm-10" style="width: 10%">-->
+    <!--<span-->
+    <!--style="font-size: 10px;"-->
+    <!--v-bind:class="['badge',{ 'ios-platform': item=='IOS','android-platform': item=='ANDROID','web-platform': item=='WEB'}]"-->
+    <!--v-for="item in project.platform"-->
+    <!--&gt;{{item}}</span>-->
+    <!--</span>-->
+    <!--<span class="col-md-1 col-sm-5" style="width: 10%;font-size: 12px"><div class="badge">¥{{project.budget}}</div></span>-->
+    <!--<span class="project-td" style="width: 15%">-->
+    <!--<span class="btn btn-small btn-info" @click="goToProjectDetail(project.id)">查看详情</span>-->
+    <!--</span>-->
+    <el-row type="flex" align="middle" justify="center" style="font-size: 14px;">
+      <el-col :span="6" type="flex" align="middle" justify="center">
+        <el-badge :value="project.statusVO.text" class="item" :type="project.statusVO.style">
+          <img class="project-cover" src="@/assets/img/home_ban1.jpg">
+        </el-badge>
+      </el-col>
+      <el-col :span="6" type="flex" align="middle" justify="center">{{project.name}}</el-col>
+      <!--<el-col :span="4">{{project.id}}</el-col>-->
+      <el-col :span="6" type="flex" align="middle" justify="center">
+        <span style="font-size: 10px;"
+              v-bind:class="['badge',{ 'ios-platform': item=='IOS','android-platform': item=='ANDROID','web-platform': item=='WEB'}]"
+              v-for="item in project.platform"
+        >{{item}}</span>
+      </el-col>
+      <el-col :span="2" type="flex" align="middle" justify="center">
+        <div class="badge">¥{{project.budget}}</div>
+      </el-col>
+      <el-col :span="4" type="flex" align="middle" justify="center">
+        <el-badge v-if="project.needHandle" is-dot class="item">
+          <span class="btn btn-small btn-info" @click="goToProjectDetail(project.id)">查看详情</span>
+        </el-badge>
+        <span v-if="!project.needHandle" class="btn btn-small btn-info" @click="goToProjectDetail(project.id)">查看详情</span>
+      </el-col>
+    </el-row>
+
+
   </div>
+
 </template>
 
 <script>
-import PlatformType from "@/constants/enum/platform-type";
+import PlatformType from '@/constants/enum/platform-type'
+
 export default {
-  name: "Project-Item",
+  name: 'Project-Item',
   props: {
-    projectId: Number
+    projectItem: {}
   },
-  data() {
+  data () {
     return {
-      project: {
-        id: 1,
-        code: "27382hdsjkfdskfK",
-        name: "多人聊天发送文件测试",
-        platform: [0],
-        description: "任务描述文字xxxx",
-        price: "10"
-      },
-      platformType: []
-    };
+      project: this.projectItem,
+      platformType: PlatformType
+    }
   },
-  mounted() {
-    this.project.platform.map(item => {
-      this.platformType.push(PlatformType[item]);
-    });
+  mounted () {
+    // this.project.platform.map(item => {
+    //   this.platformType.push(PlatformType[item]);
+    // });
   },
   methods: {
-    goToProjectDetail(id) {
-      console.log(id);
-      this.$router.push({ name: "Project", params: { projectId: id } });
+    goToProjectDetail (id) {
+      console.log(id)
+      this.$router.push({name: 'Project', params: {projectId: id}})
     }
   }
-};
+}
 </script>
 
 <style lang="less" scoped>
-.project-item-container {
-  padding: 20px;
-  border: 1px solid #eee;
-  margin: 15px 5px;
-  span {
-    display: inline-block;
+  .project-item-container {
+    /*padding: 20px;*/
+    padding-top: 10px;
+    padding-bottom: 10px;
+    border: 1px solid #eee;
+    margin-top: 5px;
+    margin-bottom: 5px;
+    span {
+      display: inline-block;
+    }
+  }
+
+  .project-cover {
+    width: 200px;
+    height: 130px;
+    vertical-align: middle;
+  }
+
+  .project-title {
+    font-weight: 700;
+  }
+
+  .project-td {
+    //padding: 15px;
+  }
+
+  .el-row {
+    margin-bottom: 20px;
+    &:last-child {
+      margin-bottom: 0;
+    }
+  }
+
+  .el-col {
+    border-radius: 4px;
+  }
+
+  .bg-purple-dark {
+    background: #99a9bf;
+  }
+
+  .bg-purple {
+    background: #d3dce6;
+  }
+
+  .bg-purple-light {
+    background: #e5e9f2;
+  }
+
+  .grid-content {
+    border-radius: 4px;
+    min-height: 36px;
+  }
+
+  .row-bg {
+    //padding: 10px 0;
+    background-color: #f9fafc;
   }
-}
-.project-cover {
-  width: 200px;
-  height: 130px;
-  vertical-align: middle;
-}
-.project-title {
-  font-weight: 700;
-}
-.project-td {
-  padding: 15px;
-}
 </style>

+ 9 - 3
src/components/commons/ProvinceCity.vue

@@ -27,7 +27,7 @@
     </el-form-item>
   </div>
 </template>
- 
+
 <script type="text/javascript">
 import provinceCity from "@/constants/provinceCity.json";
 export default {
@@ -93,12 +93,18 @@ export default {
         this.city = "";
       }
     }
+  },
+  watch:{
+    data(){
+      this.province = this.provinceCode
+      this.city = this.cityCode
+    }
   }
 };
 </script>
- 
+
 <style lang="less" scoped>
 .page-form-item {
   display: inline-block;
 }
-</style>
+</style>

+ 5 - 0
src/components/commons/TaskCard.vue

@@ -35,6 +35,11 @@ export default {
     //   this.platformType.push(PlatformType[item])
     // })
   },
+  watch:{
+    item() {
+
+    }
+  },
   methods:{
     goToTaskDetail(projectId,id){
       this.$router.push({name: "Task", params: {projectId:projectId,taskId: id}})

+ 61 - 53
src/components/commons/TaskItem.vue

@@ -1,73 +1,81 @@
 <template>
-  <div class="task-item-container" >
-       <span class="col-xl-2 col-lg-3 col-md-4 col-sm-1">
-        <img class="task-cover" src="@/assets/img/home_ban1.jpg">
-      </span>
-      <span class="task-title col-md-2 col-sm-10">{{task.title}}</span>
-      <span class="col-md-1 col-sm-5 ">{{serviceType}}</span>
-      <span class="col-md-1 col-sm-5 ">¥{{task.price}}</span>
-      <span class="col-md-1 col-sm-5 ">{{taskStatus}}</span>
-      <span class="task-td">
-       <span class="btn btn-medium btn-info" @click="goToTaskDetail(task.projectId,taskId)">查看详情</span>
-       </span>
-
+  <div class="task-item-container">
+    <el-row type="flex" align="middle" justify="center" style="font-size: 14px;">
+      <el-col :span="6" type="flex" align="middle" justify="center">
+        <el-badge :value="taskTable.statusVO.text" class="item" :type="taskTable.statusVO.style">
+          <img class="task-cover" src="@/assets/img/home_ban1.jpg">
+        </el-badge>
+      </el-col>
+      <el-col :span="5" type="flex" align="middle" justify="center">{{taskTable.title}}</el-col>
+      <!--<el-col :span="4">{{project.id}}</el-col>-->
+      <el-col :span="5" type="flex" align="middle" justify="center">{{taskTable.serviceType}}</el-col>
+      <el-col :span="4" type="flex" align="middle" justify="center">
+        <div class="badge" type="flex" align="middle" justify="center">
+          ¥{{taskTable.quotePrice==null?0:taskTable.quotePrice}}
+        </div>
+      </el-col>
+      <el-col :span="4" type="flex" align="middle" justify="center"><span class="btn btn-medium btn-info"
+                                                                          @click="goToTaskDetail(taskTable.projectId,taskTable.id)">查看详情</span>
+      </el-col>
+    </el-row>
   </div>
 </template>
 
 <script>
-import ServiceType from '@/constants/enum/service-type'
 import TaskStatus from '@/constants/enum/task-status'
+
 export default {
-  name: "Task-Item",
+  name: 'Task-Item',
   props: {
-    taskId: Number
+    task: {}
   },
-  data() {
+  data () {
     return {
-      task: {
-        id: 1,
-        cover: "@/assets/img/home_ban2.png",
-        title: "多人聊天发送文件测试",
-        description: "任务描述文字xxxx",
-        price: "10",
-        serviceType: 0,
-        status: 1,
-        projectId:1123 
-      },
-      taskStatus:"进行中",
-      serviceType:""
+      taskTable: this.task,
+      taskStatus: TaskStatus,//TaskStatus[this.task.status],
     }
   },
-  mounted(){
-    this.taskStatus = TaskStatus[this.task.status];
-    this.serviceType = ServiceType[this.task.serviceType]
+  mounted () {
+    let plats = []
+    //console.log(this.platformType)
+  }
+  ,
+  methods: {
+    goToTaskDetail (projectId, id) {
+      this.$router.push({name: 'Task', params: {projectId: projectId, taskId: id}})
+    }
   },
-  methods:{
-     goToTaskDetail(projectId,id){
-      this.$router.push({name: "Task", params: {projectId:projectId,taskId: id}})
+  watch: {
+    task () {
+      this.taskTable = this.task
     }
   }
-};
+}
+
 </script>
 
 <style lang="less" scoped>
-.task-item-container {
-  padding: 20px;
-  border: 1px solid #eee;
-  margin: 15px 5px;
-  span{
-    display: inline-block;
+  .task-item-container {
+    padding-top: 10px;
+    padding-bottom: 10px;
+    border: 1px solid #eee;
+    /*margin: 15px 5px;*/
+    span {
+      display: inline-block;
+    }
+  }
+
+  .task-cover {
+    width: 200px;
+    height: 130px;
+    vertical-align: middle;
+  }
+
+  .task-title {
+    font-weight: 700;
+  }
+
+  .task-td {
+    /*padding: 15px;*/
   }
-}
-.task-cover {
-  width: 200px;
-  height:130px;
-  vertical-align: middle;
-}
-.task-title{
-  font-weight: 700;
-}
-.task-td{
-    padding:15px;
-}
 </style>

+ 6 - 0
src/components/project/AnalyseDemand.vue

@@ -50,6 +50,8 @@
 </template>
 
 <script>
+import Http from '@/js/http.js'
+import Apis from '@/js/api.js'
 export default {
   name: "AnalyseDemand",
   data() {
@@ -73,6 +75,10 @@ export default {
       this.$refs[formName].validate(valid => {
         if (valid) {
           console.log(this.analyseDemand);
+          Http.get(Apis.PROJECT.CREATE_ANALYSE_DEMAND_SUBMIT,this.analyseDemand).then((res)=>{
+            console.log(res)
+            console.log(this.analyseDemand)
+          })
           //提交 project
         } else {
           console.log("error submit!!");

+ 871 - 524
src/components/project/Project.vue

@@ -1,254 +1,256 @@
 <template>
-  <div class="create-container">
+  <div class="create-container" v-loading="loading">
     <div class="title h1" v-if="!isModifyMode">项目</div>
     <div class="create-body">
-      <div class="title h2" v-if="!isModifyMode">基本信息</div>
-      <div v-if="!isModifyMode" class="el-form-item">
-        <label class="el-form-item__label" style="width: 12%;">编号</label>
-        <div class="el-form-item__content" style="margin-left: 12%;">
-          <div>{{project.code}}</div>
-        </div>
-      </div>
-      <el-form :model="project" :rules="rules" ref="project" label-width="12%" class="demo-project">
-        <el-form-item label="项目名称" prop="name">
-          <el-input v-if="isModifyMode" v-model="project.name"></el-input>
-          <span v-if="!isModifyMode">{{project.name}}</span>
-        </el-form-item>
-        <el-form-item label="联系方式" prop="contact">
-          <div>
-            <el-row :gutter="2">
-              <el-col :span="2">
-                <span>联系人</span>
-              </el-col>
-              <el-col :span="10">
-                <el-input v-if="isModifyMode" v-model="project.contact.name" placeholder="请输入联系人姓名"></el-input>
-                <div v-if="!isModifyMode">{{project.contact.name}}</div>
-              </el-col>
-            </el-row>
-            <el-row :gutter="2">
-              <el-col :span="2">
-                <span>联系人电话</span>
-              </el-col>
-              <el-col :span="10">
-                <el-input
-                  v-if="isModifyMode"
-                  v-model="project.contact.phone"
-                  placeholder="请输入联系人电话"
-                ></el-input>
-                <div v-if="!isModifyMode">{{project.contact.phone}}</div>
-              </el-col>
-            </el-row>
+      <el-row type="flex" align="middle" justify="start">
+        <el-col :span="15">
+          <div class="title h2" v-if="!isModifyMode">基本信息</div>
+          <div v-if="!isModifyMode" class="el-form-item">
+            <label class="el-form-item__label" style="width: 30%;">编号</label>
+            <div class="el-form-item__content" style="margin-left: 30%;">
+              <div>{{projectId}}</div>
+            </div>
           </div>
-        </el-form-item>
-        <el-form-item label="平台" prop="platform">
-          <el-checkbox-group v-if="isModifyMode" v-model="project.platform">
-            <el-checkbox label="0">IOS</el-checkbox>
-            <el-checkbox label="1">ANDROID</el-checkbox>
-            <el-checkbox label="2">WEB</el-checkbox>
-          </el-checkbox-group>
-          <span
-            v-if="!isModifyMode"
-            v-bind:class="['badge',{ 'ios-platform': item.toLowerCase()=='ios','android-platform': item.toLowerCase()=='android','web-platform': item.toLowerCase()=='web'}]"
-            v-for="item in platformType"
-          >{{item}}</span>
-        </el-form-item>
-        <el-form-item label="需求描述" prop="desc">
-          <el-input v-if="isModifyMode" type="textarea" v-model="project.desc"></el-input>
-          <span v-if="!isModifyMode">{{project.desc}}</span>
-        </el-form-item>
-        <el-form-item label="价格" prop="price">
-          <el-input v-if="isModifyMode" type="number" v-model="project.price">
-            <template slot="append">¥</template>
-          </el-input>
-          <span v-if="!isModifyMode">{{project.price}}¥</span>
-        </el-form-item>
+          <el-form :model="project" :rules="rules" ref="project" label-width="30%" class="demo-project">
+            <el-form-item label="项目名称" prop="name">
+              <el-input size="small" v-if="isModifyMode" v-model="project.name"></el-input>
+              <span v-if="!isModifyMode">{{project.name}}</span>
+            </el-form-item>
 
-        <el-form-item label="服务类型" prop="type">
-          <el-checkbox-group v-if="isModifyMode" v-model="project.type">
-            <el-checkbox label="接口测试" name="type"></el-checkbox>
-            <el-checkbox label="安全漏洞扫描" name="type"></el-checkbox>
-            <el-checkbox label="风险评估服务" name="type"></el-checkbox>
-            <el-checkbox label="源代码安全审计服务" name="type"></el-checkbox>
-            <el-checkbox label="功能测试服务" name="type"></el-checkbox>
-            <el-checkbox label="性能测试" name="type"></el-checkbox>
-            <el-checkbox label="功能和易用性测试" name="type"></el-checkbox>
-          </el-checkbox-group>
-          <span v-if="!isModifyMode" class="badge" v-for="item in project.type">{{item}}</span>
-        </el-form-item>
-        <el-form-item label="用途" prop="useage">
-          <el-input v-if="isModifyMode" v-model="project.useage"></el-input>
-          <span v-if="!isModifyMode">{{project.useage}}</span>
-        </el-form-item>
+            <el-form-item size="small" label="联系人" prop="contactName">
+              <el-input v-if="isModifyMode" v-model="project.contactName" placeholder="请输入联系人姓名"></el-input>
+              <span v-if="!isModifyMode">{{project.contactName}}</span>
+            </el-form-item>
+            <el-form-item size="small" label="联系人电话" prop="contactPhone">
+              <el-input v-if="isModifyMode" v-model="project.contactPhone" placeholder="请输入联系人电话"></el-input>
+              <span v-if="!isModifyMode">{{project.contactPhone}}</span>
+            </el-form-item>
+            <el-form-item size="small" label="预算" prop="budget">
+              <el-input v-if="isModifyMode" type="number" v-model="project.budget">
+                ¥
+                <template slot="append"></template>
+              </el-input>
+              <span v-if="!isModifyMode">{{project.budget}}¥</span>
+            </el-form-item>
+            <el-form-item v-if="!isModifyMode" size="small" label="状态" prop="status">
+              <span v-if="!isModifyMode">{{project.status==1?'等待接收':(project.status==2?'已被接收':(project.status==3?'项目已提交':'项目已结束'))}}</span>
+            </el-form-item>
+            <el-form-item label="需求描述">
+              <el-input style="width: 400px" autosize v-if="isModifyMode" type="textarea"
+                        v-model="project.desc"></el-input>
+              <span v-if="!isModifyMode">{{project.desc}}</span>
+            </el-form-item>
+            <!--<el-form-item label="价格" prop="price">-->
+            <!--<el-input v-if="isModifyMode" type="number" v-model="project.price">-->
+            <!--<template slot="append">¥</template>-->
+            <!--</el-input>-->
+            <!--<span v-if="!isModifyMode">{{project.price}}¥</span>-->
+            <!--</el-form-item>-->
+            <el-form-item label="平台" prop="platform">
+              <el-checkbox-group v-if="isModifyMode" v-model="project.platform">
+            <span v-for="(item,index) in platforms" :key="index">
+              <el-checkbox :label="item">{{ item }}&nbsp;&nbsp;&nbsp;&nbsp;</el-checkbox>
+            </span>
+              </el-checkbox-group>
+              <span
+                v-if="!isModifyMode"
+                class="badge"
+                v-for="item in project.platform"
+              >{{item}}</span>
+            </el-form-item>
+            <el-form-item label="服务类型" prop="type">
+              <el-checkbox-group v-if="isModifyMode" v-model="project.type">
+            <span v-for="(item,index) in serviceType" :key="index">
+              <el-checkbox :label="item" name="type">{{ item }}&nbsp;&nbsp;</el-checkbox>
+            </span>
+              </el-checkbox-group>
+              <span v-if="!isModifyMode" class="badge" v-for="item in project.type">{{item}}</span>
+            </el-form-item>
+            <!--<el-form-item label="用途" prop="usage">-->
+            <!--<el-input v-if="isModifyMode" v-model="project.usage"></el-input>-->
+            <!--<span v-if="!isModifyMode">{{project.usage}}</span>-->
+            <!--</el-form-item>-->
 
-        <el-form-item label="预算" prop="budget">
-          <el-input v-if="isModifyMode" type="number" v-model="project.budget">
-            <template slot="append">¥</template>
-          </el-input>
-          <span v-if="!isModifyMode">{{project.budget}}¥</span>
-        </el-form-item>
-        <el-form-item label="项目可见性" prop="resource">
-          <div v-if="!isModifyMode">
-            <div v-if="project.resource=='定向'">{{project.institution}}</div>
-            <div v-if="project.resource=='非定向'">{{project.resource}}</div>
-          </div>
-          <el-tabs
-            :tab-position="tabPosition"
-            v-model="project.resource"
-            style="max-height: 200px;"
-            v-if="isModifyMode"
-          >
-            <el-tab-pane label="定向" name="定向">
-              <el-radio-group v-model="project.institution">
-                <el-radio
-                  :label="item"
-                  name="type"
-                  v-for="item,index in institutionArray"
-                  :key="index"
-                ></el-radio>
-              </el-radio-group>
-            </el-tab-pane>
-            <el-tab-pane label="非定向" name="非定向"></el-tab-pane>
-          </el-tabs>
-        </el-form-item>
 
-        <el-form-item label="需求文档" prop="doc">
-          <el-upload
-            v-if="isModifyMode"
-            class="upload-demo"
-            drag
-            action="https://jsonplaceholder.typicode.com/posts/"
-            multiple
-          >
-            <i class="el-icon-upload"></i>
-            <div class="el-upload__text">
-              将文件拖到此处,或
-              <em>点击上传</em>
-            </div>
-            <div class="el-upload__tip" slot="tip">请上传需求文档</div>
-          </el-upload>
-          <span v-if="!isModifyMode">{{project.doc}}</span>
-        </el-form-item>
-        <el-form-item label="安装包" prop="file">
-          <el-upload
-            v-if="isModifyMode"
-            class="upload-demo"
-            drag
-            action="https://jsonplaceholder.typicode.com/posts/"
-            multiple
-            :before-upload="beforeFileUpload"
-          >
-            <i class="el-icon-upload"></i>
-            <div class="el-upload__text">
-              将文件拖到此处,或
-              <em>点击上传</em>
-            </div>
-            <div class="el-upload__tip" slot="tip">只能上传Android或IOS安装包文件</div>
-          </el-upload>
-          <span v-if="!isModifyMode">{{project.file}}</span>
-        </el-form-item>
-        <el-form-item label="项目截止时间" prop="datetime">
-          <div class="block" v-if="isModifyMode">
-            <el-date-picker
-              v-model="project.datetime"
-              type="datetime"
-              placeholder="选择截止时间"
-              align="right"
-              :picker-options="pickerOptions"
-            ></el-date-picker>
-          </div>
-          <span v-if="!isModifyMode">{{new Date(project.datetime)}}</span>
-        </el-form-item>
-        <el-form-item v-if="isModifyMode">
-          <div class="btn btn-medium btn-info" @click="submitForm('project')">确认修改</div>
-          <div class="btn btn-medium" @click="resetForm('project')">重置</div>
-          <div class="btn btn-medium" @click="cancelMode('project')">取消</div>
-        </el-form-item>
-        <el-form-item v-if="!isModifyMode">
-          <div class="btn btn-medium btn-info" @click="modifyForm()">修改</div>
-          <div class="btn btn-medium btn-info" @click="analyseDemand()">分析需求</div>
-          <div class="btn btn-medium btn-info" @click="createTask()">新建任务</div>
-          <div class="btn btn-medium btn-info" @click="createReport()">上传报告</div>
-        </el-form-item>
-      </el-form>
-    </div>
+            <el-form-item label="项目可见性" prop="resource">
+              <div v-if="!isModifyMode">
+                <div v-if="project.resource=='1'">{{updateLocation(project.location)}}</div>
+                <div v-if="project.resource=='0'">{{project.institution==null?'暂未被接收':project.institution}}</div>
+                <div v-if="project.resource=='2'">{{resourceType[project.resource]}}</div>
+              </div>
+              <el-tabs :tab-position="tabPosition" v-model="project.resource" style="max-height: 200px;"
+                       v-if="isModifyMode">
+                <el-tab-pane :label="resourceType[0]" name="0">
+                  <el-radio-group v-model="project.institution">
+                    <el-radio :label="item" name="type" v-for="(item,index) in institutionArray" :key="index">
+                      {{item.name}}
+                    </el-radio>
+                  </el-radio-group>
+                </el-tab-pane>
+                <el-tab-pane :label="resourceType[1]" name="1">
+                  <provincecity
+                    ref="addFormProvince"
+                    @selectChange="locationChange"
+                    :provinceCode="project.location==null?'3200':project.location.provinceCode"
+                    :cityCode="project.location==null?'3201':project.location.cityCode"
+                  ></provincecity>
+                </el-tab-pane>
+                <el-tab-pane :label="resourceType[2]" name="2"></el-tab-pane>
+              </el-tabs>
+            </el-form-item>
+
+            <el-form-item label="需求文档" prop="doc">
+              <el-upload
+                style="width: 400px"
+                v-if="isModifyMode"
+                drag
+                class="upload-demo"
+                action=""
+                :on-remove="handleRemove"
+                :before-remove="beforeRemove"
+                :limit="1"
+                :on-exceed="handleExceed"
+                :before-upload="beforeFileUpload"
+                :http-request="uploadRequireDoc"
+                :file-list="project.doc"
+              >
+                <i class="el-icon-upload"></i>
+                <div class="el-upload__text">
+                  将文件拖到此处,或
+                  <em>点击上传</em>
+                </div>
+              </el-upload>
+              <span v-if="!isModifyMode">
+            <a :href="project.requireDocUrl" v-if="project.requireDocUrl!=null && project.requireDocUrl!=''"><el-link
+              :underline="false" type="primary"><i
+              class="el-icon-document"></i>下载文档</el-link></a>
+            <i v-if="project.requireDocUrl==null || project.requireDocUrl==''" class="el-icon-document">暂无文档</i>
+          </span>
+            </el-form-item>
+            <el-form-item label="安装包" prop="file">
+              <el-upload
+                style="width: 400px"
+                v-if="isModifyMode"
+                drag
+                class="upload-demo"
+                action=""
+                :on-remove="handleRemove"
+                :before-remove="beforeRemove"
+                :limit="1"
+                :on-exceed="handleExceed"
+                :before-upload="beforeApkUpload"
+                :http-request="uploadApkFile"
+                :file-list="project.file"
+              >
+                <i class="el-icon-upload"></i>
+                <div class="el-upload__text">
+                  将文件拖到此处,或
+                  <em>点击上传</em>
+                </div>
+              </el-upload>
+              <span v-if="!isModifyMode">
+            <a v-if="project.fileUrl!=null && project.fileUrl!=''" :href="project.fileUrl"><el-link :underline="false"
+                                                                                                    type="primary"><i
+              class="el-icon-document"></i>下载文件</el-link></a>
+            <i v-if="project.fileUrl==null || project.fileUrl==''" class="el-icon-document">暂无文件</i>
+          </span>
+            </el-form-item>
+            <el-form-item label="项目截止时间" prop="datetime">
+              <div class="block" v-if="isModifyMode">
+                <el-date-picker
+                  size="small"
+                  v-model="project.datetime"
+                  type="datetime"
+                  placeholder="选择截止时间"
+                  align="right"
+                  :picker-options="pickerOptions"
+                ></el-date-picker>
+              </div>
+              <span v-if="!isModifyMode">{{reformDate(new Date(project.datetime))}}</span>
+            </el-form-item>
+            <el-form-item v-if="isModifyMode">
+              <div class="btn btn-small btn-info" @click="submitForm('project')">确认修改</div>
+              <div class="btn btn-small" @click="resetForm('project')">重置</div>
+              <div class="btn btn-small" @click="cancelMode('project')">取消</div>
+            </el-form-item>
+            <el-form-item v-if="!isModifyMode">
 
+              <el-button v-if="projectOperationControl.confirmFinish" type="success" size="mini" @click="endProject()">
+                结束项目
+              </el-button>
+              <el-button v-if="projectOperationControl.finish" type="primary" size="mini"
+                         @click="submitProjectRequest()">
+                提交项目
+              </el-button>
+              <el-button v-if="projectOperationControl.receive" type="primary" size="mini" @click="receiveProject()">
+                接受项目
+              </el-button>
+              <el-button v-if="projectOperationControl.reject" type="danger" size="mini" @click="rejectProject()">
+                拒绝项目
+              </el-button>
+              <el-button v-if="projectOperationControl.update" type="primary" size="mini" @click="modifyForm()">
+                修改项目
+              </el-button>
+              <el-button v-if="projectOperationControl.createTask" type="primary" size="mini" @click="createNewTask()">
+                新建任务
+              </el-button>
+              <el-button v-if="projectOperationControl.uploadReport" type="primary" size="mini" @click="createReport()">
+                上传报告
+              </el-button>
+            </el-form-item>
+          </el-form>
+
+        </el-col>
+        <el-col :span="5" id="pieImage" style="height: 500px;min-width: 500px">
+        </el-col>
+      </el-row>
+    </div>
     <div class="create-body" v-if="!isModifyMode">
-      <div class="title h2">分析需求</div>
+      <div class="title h2">任务列表</div>
       <div class="task-list">
-        <el-table :data="analyseDemandList" style="width: 100%" max-height="400">
-          <el-table-column prop="institution" label="承接单位" title="承接单位"></el-table-column>
-          <el-table-column prop="feasibilityReport" sortable label="可行性分析报告">
+        <el-table :showHeader="true" :stripe="true" :data="task" style="width: 100%">
+          <el-table-column prop="title" label="任务名称" title="任务名称">
             <template slot-scope="scope">
-              <span v-if="!scope.row.feasibilityReport.url">暂无文件</span>
-              <a
-                :href="scope.row.feasibilityReport.url"
-                v-if="scope.row.feasibilityReport.url"
-                target="_blank"
-              >
-                <i class="fa fa-file-text-o"></i>
-                {{scope.row.feasibilityReport.name}}
-              </a>
+              <span>{{ scope.row.title }}</span>
             </template>
           </el-table-column>
-          <el-table-column prop="priceAuditReport" sortable label="可行性分析报告">
+          <el-table-column prop="datetime" sortable label="任务截止时间">
             <template slot-scope="scope">
-              <span v-if="!scope.row.priceAuditReport.url">暂无文件</span>
-              <a
-                :href="scope.row.priceAuditReport.url"
-                v-if="scope.row.priceAuditReport.url"
-                target="_blank"
-              >
-                <i class="fa fa-file-text-o"></i>
-                {{scope.row.priceAuditReport.name}}
-              </a>
+              <span>{{reformDate(new Date(scope.row.datetime))}}</span>
             </template>
           </el-table-column>
-
-          <el-table-column align="right" label="操作">
-            <template slot-scope="scope">
-              <div
-                class="btn btn-small btn-info"
-                @click="handleAccept(scope.$index, scope.row.id)"
-              >接受</div>
-              <div
-                class="btn btn-small btn-danger"
-                @click="handleReject(scope.$index, scope.row.id)"
-              >拒绝</div>
-            </template>
-          </el-table-column>
-        </el-table>
-      </div>
-    </div>
-
-    <div class="create-body" v-if="!isModifyMode">
-      <div class="title h2">任务列表</div>
-      <div class="task-list">
-        <el-table :showHeader="false" :data="project.task" style="width: 100%" max-height="400">
-          <el-table-column prop="name" label="任务名称" title="任务名称"></el-table-column>
-          <el-table-column prop="datetime" sortable label="任务截止时间"></el-table-column>
           <el-table-column prop="resource" label="任务可见性">
             <template slot-scope="scope">
-              <div v-if="scope.row.resource=='区域'">{{updateLocation(scope.row.location)}}</div>
-              <div v-if="scope.row.resource=='定向'">{{scope.row.institution}}</div>
-              <div v-if="scope.row.resource=='广场'">{{scope.row.resource}}</div>
+              <div v-if="scope.row.resource=='1'">{{scope.row.location.provinceCode}}/{{scope.row.location.cityCode}}
+              </div>
+              <div v-if="scope.row.resource=='0'">{{scope.row.institution}}</div>
+              <div v-if="scope.row.resource=='2'">{{resourceType[scope.row.resource]}}</div>
             </template>
           </el-table-column>
           <el-table-column prop="type" label="业务类型">
             <template slot-scope="scope">
-              <div class="badge">{{scope.row.type}}</div>
+              <div class="badge">{{scope.row.serviceType}}</div>
             </template>
           </el-table-column>
+          <el-table-column align="center" label="状态">
 
+            <template slot-scope="scope">
+              <el-tag :type="scope.row.statusVO.style">{{scope.row.statusVO.text}}</el-tag>
+            </template>
+          </el-table-column>
           <el-table-column align="right" label="操作">
+
             <template slot-scope="scope">
               <div
                 class="btn btn-small btn-info"
                 @click="goToTaskDetail(projectId, scope.row.id)"
-              >查看详情</div>
+              >查看详情
+              </div>
               <div
                 class="btn btn-small btn-danger"
                 @click="handleDelete(scope.$index, scope.row.id)"
-              >删除</div>
+              >删除
+              </div>
             </template>
           </el-table-column>
         </el-table>
@@ -257,389 +259,734 @@
 
     <div class="create-body" v-if="!isModifyMode">
       <div class="title h2">报告列表</div>
-      <report-list/>
+      <report-list v-bind:reports="reportList" v-bind:taskId=null v-bind:projectId="projectId"/>
     </div>
   </div>
 </template>
 
 <script>
-import Enum from "@/constants/enum/index";
-import PlatformType from "@/constants/enum/platform-type";
-import provinceCity from "@/constants/provinceCity.json";
-import ReportList from "@/components/report/ReportList";
+import ReportList from '@/components/report/ReportList'
+import Http from '@/js/http.js'
+import Apis from '@/js/api.js'
+import ResourceType from '@/constants/enum/resource-type'
+import provincecity from '@/components/commons/ProvinceCity'
+import {notify} from '@/constants/index'
+import echarts from 'echarts'
+import {
+  checkFileType,
+  ensureEndProject,
+  getAllInstitutions,
+  getAllPlatformTypes,
+  getAllServiceTypes,
+  getFormalTimeFromDate,
+  getProvinceCodeByProvinceName,
+  getProvinceNameByProvinceCode,
+  receiveProjectRequest,
+  rejectProject,
+  storageGet,
+  submitProjectRequest
+} from '@/js/index'
+
 export default {
-  name: "Project",
-  components: { ReportList },
-  data() {
+  name: 'Project',
+  components: {
+    provincecity,
+    ReportList
+  },
+  data () {
     var validatePass = (rule, value, callback) => {
-      var reg = /^(0|86|17951)?(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$/;
-      if (value.phone) {
-        if (!reg.test(value.phone)) {
-          callback(new Error("请检查手机号码"));
+      var reg = /^(0|86|17951)?(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$/
+      if (this.project.contactPhone) {
+        if (!reg.test(this.project.contactPhone)) {
+          callback(new Error('请检查手机号码'))
         } else {
-          callback();
+          callback()
         }
       }
-    };
+    }
     return {
       projectId: 0,
-      tabPosition: "top",
-      institutionArray: Enum.institution,
+      user: {},
+      loading: false,
+      tabPosition: 'top',
+      institutionArray: [],
       isModifyMode: false,
-      platformType: [],
+      platforms: [],
+      resourceType: ResourceType,
+      serviceType: [],
+      projectOperationControl: {
+        confirmFinish: false,
+        createTask: false,
+        finish: false,
+        receive: false,
+        reject: false,
+        update: false,
+        uploadReport: false,
+      },
       project: {
-        name: "项目名",
-        code: "27382hdsjkfdskfK",
-        contact: {
-          name: "小王",
-          phone: "12426177281"
-        },
-        type: ["安全漏洞扫描"],
-        platform: ["0", "1"],
-        desc: "需求描述文字",
-        doc: "",
-        file: "http://a.apk",
-        resource: "非定向",
-        institution: "",
-        datetime: new Date("2018-11-11 23:11:11"),
-        price: "400",
-        useage: "练习",
-        budget: "100",
-        task: [
-          {
-            id: "1",
-            name: "任务1",
-            desc: "任务描述文字",
-            type: "安全漏洞扫描",
-            resource: "广场",
-            location: "",
-            institution: "",
-            datetime: "2018-11-12 11:11:01",
-            worker: ""
-          },
-          {
-            id: "2",
-            name: "任务2",
-            desc: "任务描述文字",
-            type: "接口测试",
-            resource: "定向",
-            location: "",
-            institution: "上软",
-            datetime: "2018-11-11 10:11:01",
-            worker: ""
-          },
-          {
-            id: "3",
-            name: "任务3",
-            desc: "任务描述文字",
-            type: "功能测试服务",
-            resource: "区域",
-            location: { provinceCode: "3200", cityCode: "3201" },
-            institution: "",
-            datetime: "2018-11-11 11:11:01",
-            worker: ""
-          }
-        ]
+        userId: 0,
+        name: '',
+        type: '',
+        platform: '',
+        desc: '',
+        resource: '',
+        location: '',
+        institution: {},
+        contactName: '',
+        contactPhone: '',
+        doc: [],
+        requireDocUrl: '',
+        file: [],
+        fileUrl: '',
+        budget: '',
+        price: '',
+        datetime: '',
+        usage: '',
+        status: ''
       },
-      analyseDemandList: [
-        {
-          id: "1",
-          institution: "上软",
-          feasibilityReport: {
-            name: "可行性分析报告",
-            url: "feasibilityReport.docx"
-          },
-          priceAuditReport: { name: "价格审核告", url: "priceAuditReport.docx" }
-        }
-      ],
+      task: [],
+      progress: [],
+      reportList: [],
       pickerOptions: {
         shortcuts: [
           {
-            text: "今天",
-            onClick(picker) {
-              picker.$emit("pick", new Date());
+            text: '今天',
+            onClick (picker) {
+              picker.$emit('pick', new Date())
             }
           },
           {
-            text: "昨天",
-            onClick(picker) {
-              const date = new Date();
-              date.setTime(date.getTime() - 3600 * 1000 * 24);
-              picker.$emit("pick", date);
+            text: '昨天',
+            onClick (picker) {
+              const date = new Date()
+              date.setTime(date.getTime() - 3600 * 1000 * 24)
+              picker.$emit('pick', date)
             }
           },
           {
-            text: "一周前",
-            onClick(picker) {
-              const date = new Date();
-              date.setTime(date.getTime() - 3600 * 1000 * 24 * 7);
-              picker.$emit("pick", date);
+            text: '一周前',
+            onClick (picker) {
+              const date = new Date()
+              date.setTime(date.getTime() - 3600 * 1000 * 24 * 7)
+              picker.$emit('pick', date)
             }
           }
         ]
       },
       rules: {
         name: [
-          { required: true, message: "请输入项目名称", trigger: "blur" }
+          {required: true, message: '请输入项目名称', trigger: 'blur'},
+          {min: 5, max: 50, message: '项目名称长度在 5 到 50 个字符', trigger: 'blur'}
+        ],
+        contactName: [
+          {required: true, message: '请输入联系人姓名', trigger: 'blur'}
           // { min: 3, max: 5, message: "长度在 3 到 5 个字符", trigger: "blur" }
         ],
+        contactPhone: [
+          {required: true, message: '请输入手机号', trigger: 'blur'},
+          //{min: 11, max: 11, message: '请输入正确的手机号', trigger: 'blur'}
+        ],
         type: [
           {
-            type: "array",
+            type: 'array',
             required: true,
-            message: "请至少选择一种服务类型",
-            trigger: "change"
+            message: '请至少选择一种服务类型',
+            trigger: 'change'
           }
         ],
         platform: [
           {
-            type: "array",
+            type: 'array',
             required: true,
-            message: "请至少选择一个平台",
-            trigger: "change"
+            message: '请至少选择一个平台',
+            trigger: 'change'
           }
         ],
-        desc: [{ required: true, message: "请填写活动形式", trigger: "blur" }],
-        contact: [{ validator: validatePass, trigger: "blur" }],
+        desc: [{required: false, message: '请填写描述', trigger: 'blur'}],
+        //price: [{required: true, message: '请填写价格', trigger: 'blur'}],
+        budget: [
+          {required: true, message: '预算不可为空', trigger: 'blur'},
+          {
+            validator: (rule, value, callback) => {
+              if (value < 0) {
+                callback(new Error('请输入不小于0的数'))
+              } else {
+                callback()
+              }
+            }, trigger: 'blur'
+          },
+        ],
         resource: [
+          {required: true},
           {
-            required: true,
-            message: "请选择项目可见性",
-            trigger: "change"
-          }
-        ]
+            validator: (rule, value, callback) => {
+              if (value == 0 && this.project.institution == null) {
+                callback(new Error('定向发布至少要选择一个区域管理员'))
+              } else {
+                callback()
+              }
+            }, trigger: 'change'
+          },
+        ],
+        datetime: [{required: true, message: '截止时间不可为空', trigger: 'blur'}],
       }
-    };
+    }
   },
-  mounted() {
+  mounted () {
     this.$nextTick(() => {
-      this.init();
-    });
+      this.init()
+    })
   },
   watch: {
-    "project.resource"() {
-      if (this.project.resource == "非定向") {
-        this.project.institution = "";
-      }
+    serviceType (val) {
+      this.serviceType = val
     },
+    institutionArray (val) {
+      this.institutionArray = val
+    },
+    // 'project.institution' () {
+    //   if (this.project.institution) {
+    //     //this.$refs.addFormProvince.resetProviceCity()
+    //     this.project.location = {provinceCode: '', cityCode: ''}
+    //   }
+    // },
+    // 'project.location' () {
+    //   if (this.project.location.provinceCode || this.project.location.cityCode) {
+    //     this.project.institution = ''
+    //   }
+    // },
+    // 'project.resource' () {
+    //   if (this.project.resource == '2') {
+    //     //this.$refs.addFormProvince.resetProviceCity()
+    //     this.project.institution = ''
+    //     this.project.location = {provinceCode: '', cityCode: ''}
+    //   }
+    // },
     deep: true
   },
   methods: {
-    updateLocation(location) {
-      var provinceName = "";
-      var cityName = "";
-      for (var item of provinceCity.provinces) {
-        if (item.code === location.provinceCode) {
-          provinceName = item.name;
-          for (var city of item.cities) {
-            if (city.code === location.cityCode) {
-              cityName = city.name;
-              break;
-            }
-          }
-        }
-      }
-      return provinceName + " / " + cityName;
+    updateLocation (location) {
+      //console.log(location)
+      const loactionName = getProvinceNameByProvinceCode(location.provinceCode, location.cityCode)
+      // var provinceName = ''
+      // var cityName = ''
+      // for (var item of provinceCityJSON.provinces) {
+      //   if (item.code === location.provinceCode) {
+      //     provinceName = item.name
+      //     for (var city of item.cities) {
+      //       if (city.code === location.cityCode) {
+      //         cityName = city.name
+      //         break
+      //       }
+      //     }
+      //   }
+      // }
+      return loactionName.provinceCode + ' / ' + loactionName.cityCode
     },
-    init() {
-      this.projectId = +this.$route.params.projectId;
-      this.project.platform.map(item => {
-        this.platformType.push(PlatformType[item]);
-      });
+    init () {
+      this.projectId = this.$route.params.projectId
+      this.setServiceType()
+      this.setPlatformType()
+      this.setInstitutions()
+      this.setUserInfo()
+      this.loadData()
+      //this.reformDate(123)
+      // this.project.platform.map(item => {
+      //   this.platformType.push(PlatformType[item])
+      // })
     },
-    submitForm(formName) {
-      this.$refs[formName].validate(valid => {
-        if (valid) {
-          this.isModifyMode = false;
-          console.log(this.project);
-          //提交 project
-        } else {
-          console.log("error submit!!");
-          return false;
-        }
-      });
-    },
-    resetForm(formName) {
-      this.$refs[formName].resetFields();
-      this.project.name = "";
-      this.project.type = [];
-      this.project.platform = [];
-      this.project.desc = "";
-      this.project.doc = "";
-      this.project.file = "";
-      this.project.contact = {
-        name: "",
-        phone: ""
-      };
-      this.project.resource = "非定向";
-      this.project.institution = "";
-      this.project.datetime = "";
-      this.project.price = "";
-      this.project.useage = "";
-      this.project.budget = "";
-    },
-    modifyForm() {
-      this.isModifyMode = true;
-      //获得update 信息
-      this.project = {
-        name: "项目名",
-        code: "27382hdsjkfdskfK",
-        contact: {
-          name: "小王",
-          phone: "13818022817"
+    //画个饼
+    setEcharts () {
+      // 基于准备好的dom,初始化echarts实例
+      let myChart = echarts.init(document.getElementById('pieImage'))
+      // 绘制图表
+      var option = {
+        tooltip: {
+          trigger: 'item',
+          formatter: '{a} <br/>{b}: {c} ({d}%)'
         },
-        type: ["安全漏洞扫描"],
-        platform: ["0", "1"],
-        desc: "需求描述文字",
-        doc: "",
-        file: "http://a.apk",
-        resource: "非定向",
-        institution: "",
-        datetime: new Date("2018-11-11 23:11:11"),
-        price: "400",
-        useage: "练习",
-        budget: "100",
-        task: [
-          {
-            id: "1",
-            name: "任务1",
-            desc: "任务描述文字",
-            type: "安全漏洞扫描",
-            resource: "广场",
-            location: { provinceCode: "", cityCode: "" },
-            institution: "",
-            datetime: "2018-11-12 11:11:01",
-            worker: ""
-          },
-          {
-            id: "2",
-            name: "任务2",
-            desc: "任务描述文字",
-            type: "接口测试",
-            resource: "定向",
-            location: { provinceCode: "", cityCode: "" },
-            institution: "上软",
-            datetime: "2018-11-11 10:11:01",
-            worker: ""
-          },
+        legend: {
+          orient: 'vertical',
+          x: 'left',
+          data: ['已完成', '进行中']
+        },
+        series: [
           {
-            id: "3",
-            name: "任务3",
-            desc: "任务描述文字",
-            type: "功能测试服务",
-            resource: "区域",
-            location: { provinceCode: "3200", cityCode: "3201" },
-            institution: "",
-            datetime: "2018-11-11 11:11:01",
-            worker: ""
+            name: '任务状态',
+            type: 'pie',
+            radius: ['50%', '70%'],
+            avoidLabelOverlap: false,
+            label: {
+              normal: {
+                show: false,
+                position: 'center'
+              },
+              emphasis: {
+                show: true,
+                textStyle: {
+                  fontSize: '30',
+                  fontWeight: 'bold'
+                }
+              }
+            },
+            labelLine: {
+              normal: {
+                show: false
+              }
+            },
+            data: this.progress,
+            color:['#909399','#409EFF']
           }
         ]
-      };
+      }
+      myChart.setOption(option)
     },
-    cancelMode(formName) {
-      this.isModifyMode = false;
-      //获得update 信息
-      this.project = {
-        name: "项目名",
-        code: "27382hdsjkfdskfK",
-        contact: {
-          name: "小王",
-          phone: "13818022817"
-        },
-        type: ["安全漏洞扫描"],
-        platform: ["0", "1"],
-        desc: "需求描述文字",
-        doc: "",
-        file: "http://a.apk",
-        resource: "非定向",
-        institution: "",
-        datetime: new Date("2018-11-11 23:11:11"),
-        price: "400",
-        useage: "练习",
-        budget: "100",
-        task: [
-          {
-            id: "1",
-            name: "任务1",
-            desc: "任务描述文字",
-            type: "安全漏洞扫描",
-            resource: "广场",
-            location: "",
-            institution: "",
-            datetime: "2018-11-12 11:11:01",
-            worker: ""
-          },
-          {
-            id: "2",
-            name: "任务2",
-            desc: "任务描述文字",
-            type: "接口测试",
-            resource: "定向",
-            location: "",
-            institution: "上软",
-            datetime: "2018-11-11 10:11:01",
-            worker: ""
-          },
-          {
-            id: "3",
-            name: "任务3",
-            desc: "任务描述文字",
-            type: "功能测试服务",
-            resource: "区域",
-            location: { provinceCode: "3200", cityCode: "3201" },
-            institution: "",
-            datetime: "2018-11-11 11:11:01",
-            worker: ""
+    //提交修改
+    submitForm (formName) {
+      this.$refs['project'].validate(valid => {
+        if (valid) {
+          this.showLoading()
+          const newProject = {
+            userId: this.user.userVO.id,
+            name: this.project.name,
+            type: this.project.type,
+            platform: this.project.platform,
+            desc: this.project.desc,
+            resource: this.project.resource,
+            location: getProvinceNameByProvinceCode(this.project.location.provinceCode, this.project.location.cityCode),
+            institution: this.project.institution == null ? null : this.project.institution.id,
+            contactName: this.project.contactName,
+            contactPhone: this.project.contactPhone,
+            doc: this.project.requireDocUrl,
+            file: this.project.fileUrl,
+            budget: this.project.budget,
+            price: this.project.price,
+            datetime: this.project.datetime,
+            usage: this.project.usage,
           }
-        ]
-      };
+          Http.put(Apis.PROJECT.UPDATE_PROJECT.replace('{projectId}', this.projectId), newProject).then((res) => {
+            console.log('bb')
+            console.log(res)
+            this.projectId = res.projectDetails.id
+            this.project.name = res.projectDetails.name
+            this.project.contactName = res.projectDetails.contactName
+            this.project.contactPhone = res.projectDetails.contactPhone
+            this.project.type = res.projectDetails.type
+            this.project.platform = res.projectDetails.platform
+            this.project.desc = res.projectDetails.desc
+            this.project.doc = []
+            this.project.file = []
+            this.project.resource = res.projectDetails.resource
+            this.project.location = getProvinceCodeByProvinceName(res.projectDetails.location.provinceCode, res.projectDetails.location.cityCode)
+            this.project.institution = res.projectDetails.institution
+            this.project.datetime = new Date(res.projectDetails.datetime)
+            this.project.price = res.projectDetails.price
+            this.project.budget = res.projectDetails.budget
+            this.project.usage = res.projectDetails.usage
+            this.project.fileUrl = res.projectDetails.file
+            this.project.requireDocUrl = res.projectDetails.doc
+
+            this.task = res.taskList
+            this.reportList = res.reportList
+            this.isModifyMode = false
+            this.hideLoading()
+            notify('success', '项目修改成功')
+          }).catch(error => {
+            this.hideLoading()
+            notify('error', error.data)
+            console.log(error)
+          })
+        } else {
+          notify('error', '表单填写错误!')
+          return false
+        }
+      })
+    },
+    //重置表单
+    resetForm (formName) {
+      this.$refs[formName].resetFields()
+      this.project.name = ''
+      this.project.type = []
+      this.project.platform = []
+      this.project.desc = ''
+      this.project.doc = ''
+      this.project.file = ''
+      this.project.contactName = ''
+      this.project.contactPhone = ''
+      this.project.resource = '2'
+      this.project.institution = ''
+      this.project.datetime = ''
+      this.project.price = ''
+      this.project.usage = ''
+      this.project.budget = ''
+    },
+    //进入修改项目页面
+    modifyForm () {
+      this.isModifyMode = true
+      console.log(this.project.doc)
+      //this.setInstitutions()
+      //获得update 信息
+      //this.loadData()
+    },
+    //接收项目
+    receiveProject () {
+      this.$confirm('确认接收项目?', '提示', {
+        confirmButtonText: '确认接收',
+        cancelButtonText: '取消',
+        type: 'success'
+      }).then(() => {
+        this.showLoading()
+        console.log('接收项目')
+        receiveProjectRequest(this.projectId, this.user.userVO.id, this.receiveProjectSuccess, this.receiveProjectFail)
+      }).catch(() => {
+      })
+    },
+    receiveProjectSuccess (res) {
+      this.hideLoading()
+      notify('success', '项目接收成功!')
+      this.projectOperationControl = res.projectOperationControl
+      this.project.status = res.projectDetails.status
+      this.project.institution = res.projectDetails.institution
     },
-    goToTaskDetail(id) {
+    receiveProjectFail (error) {
+      this.hideLoading()
+      notify('error', '接收项目失败:' + error.data)
+    },
+    //拒绝项目
+    rejectProject () {
+      this.$confirm('确认拒绝项目?', '提示', {
+        confirmButtonText: '确认拒绝',
+        cancelButtonText: '取消',
+        type: 'success'
+      }).then(() => {
+        this.showLoading()
+        rejectProject(this.projectId, this.rejectProjectSuccess, this.rejectProjectFail)
+      }).catch(() => {
+      })
+
+    },
+    rejectProjectSuccess (res) {
+      this.hideLoading()
+      notify('success', '拒绝项目成功')
+    },
+    rejectProjectFail (error) {
+      this.hideLoading()
+      notify('error', '拒绝项目失败:' + error.data)
+    },
+    //提交项目
+    submitProjectRequest () {
+      this.$confirm('确认提交项目?', '提示', {
+        confirmButtonText: '确认提交',
+        cancelButtonText: '取消',
+        type: 'success'
+      }).then(() => {
+        this.showLoading()
+        submitProjectRequest(this.projectId, this.submitProjectRequestSuccess, this.submitProjectRequestFail)
+      }).catch(() => {
+      })
+    },
+    submitProjectRequestSuccess (res) {
+      this.hideLoading()
+      notify('success', '项目提交成功!')
+      this.projectOperationControl = res.projectOperationControl
+      this.project.status = res.projectDetails.status
+      this.project.institution = res.projectDetails.institution
+    },
+    submitProjectRequestFail (error) {
+      this.hideLoading()
+      notify('error', '提交项目失败:' + error.data)
+    },
+    //结束项目
+    endProject () {
+      this.$confirm('确认结束项目?', '提示', {
+        confirmButtonText: '确认结束',
+        cancelButtonText: '取消',
+        type: 'success'
+      }).then(() => {
+        this.showLoading()
+        ensureEndProject(this.projectId, this.endProjectSuccess, this.endProjectFail)
+      }).catch(() => {
+      })
+
+    },
+    endProjectSuccess (res) {
+      this.hideLoading()
+      notify('success', '项目提交成功!')
+      this.projectOperationControl = res.projectOperationControl
+      this.project.status = res.projectDetails.status
+      this.project.institution = res.projectDetails.institution
+    },
+    endProjectFail (error) {
+      this.hideLoading()
+      notify('error', '结束项目失败:' + error.data)
+    },
+    cancelMode (formName) {
+      this.isModifyMode = false
+      this.loadData()
+
+    },
+    goToTaskDetail (projectId, taskId) {
       this.$router.push({
-        name: "Task",
-        params: { projectId: this.projectId, taskId: id }
-      });
+        name: 'Task',
+        params: {projectId: projectId, taskId: taskId}
+      })
     },
-    createTask() {
-      this.$router.push({ name: "TaskCreate" });
+    createNewTask () {
+      const that = this
+      this.$router.push({
+        name: 'TaskCreate',
+        params: {projectId: that.projectId}
+      })
     },
-    createReport() {
-      this.$router.push({ name: "ReportCreate" });
+    createReport () {
+      this.$router.push({
+        name: 'ProjectReportCreate',
+        params: {
+          scope: 0,
+          dependencyCode: this.projectId,
+          projectId: this.projectId,
+        }
+      })
     },
-    handleDelete(index, id) {
-      this.project.task.splice(index, 1);
+    handleDelete (index, id) {
+      this.$confirm('确认删除该任务?')
+        .then(_ => {
+          //done()
+          notify('success', '删除成功')
+        })
+        .catch(_ => {
+          notify('error', '删除失败')
+        })
+      //this.task.splice(index, 1)
     },
-    beforeFileUpload(file) {
-      const isAPK = file.type === "application/vnd.android.package-archive";
-      const isDMG = file.type === "application/octet-stream";
+    beforeApkUpload (file) {
+      const isAPK = file.type === 'application/vnd.android.package-archive'
+      const isDMG = file.type === 'application/octet-stream'
 
       if (!isAPK && !isDMG) {
-        this.$message.error("上传安装包只能是 APK 或 DMG 格式!");
+        this.$message.error('上传安装包只能是 APK 或 DMG 格式!')
+      }
+      return isAPK || isDMG
+    },
+    beforeFileUpload (file) {
+      console.log(file)
+      const isPDF = file.type === 'application/pdf'
+      const isDOC = file.type === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
+      const isEXCEL = file.type === 'application/vnd.ms-excel'
+      const isXLS = file.type === 'application/x-xls'
+      const isTXT = file.type === 'text/plain'
+      const isXLSX = file.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
+      //console.log(file)
+      if (!(isDOC || isEXCEL || isPDF || isTXT || isXLS || isXLSX)) {
+        this.$message.error('上传文件只能是 PDF 、 DOC 、DOCX 、XLS、TXT、XLSX 格式!')
+      }
+      return isDOC || isEXCEL || isPDF || isTXT || isXLS || isXLSX
+    },
+    analyseDemand () {
+      this.$router.push({name: 'AnalyseDemand'})
+    },
+    handleAccept (index, id) {
+      console.log('接受')
+    },
+    handleReject (index, id) {
+      console.log('拒绝')
+    },
+    loadData () {//PROJ--2019073114009
+      this.showLoading()
+      Http.get(Apis.PROJECT.GET_PROJECT.replace('{projectId}', this.projectId)).then((res) => {
+        console.log(res)
+        this.projectId = res.projectDetails.id
+        this.project.name = res.projectDetails.name
+        this.project.contactName = res.projectDetails.contactName
+        this.project.contactPhone = res.projectDetails.contactPhone
+        this.project.type = res.projectDetails.type
+        this.project.platform = res.projectDetails.platform
+        this.project.desc = res.projectDetails.desc
+        this.project.doc = []
+        this.project.file = []
+        this.project.resource = res.projectDetails.resource
+        this.project.location = getProvinceCodeByProvinceName(res.projectDetails.location.provinceCode, res.projectDetails.location.cityCode)
+        this.project.institution = res.projectDetails.institution
+        this.project.datetime = new Date(res.projectDetails.datetime)
+        this.project.price = res.projectDetails.price
+        this.project.budget = res.projectDetails.budget
+        this.project.usage = res.projectDetails.usage
+        this.project.fileUrl = res.projectDetails.file
+        this.project.requireDocUrl = res.projectDetails.doc
+        this.project.userId = res.projectDetails.userId
+        this.project.status = res.projectDetails.status
+        this.task = res.taskList
+        this.reportList = res.reportList
+        this.projectOperationControl = res.projectOperationControl
+        this.progress = res.progress
+        this.hideLoading();
+        for(var i = 0; i < this.progress.length; i++){
+            if(this.progress[i].value != 0){
+                this.setEcharts()
+                break
+            }
+        }
+
+      }).catch((error) => {
+        this.hideLoading()
+        notify('error', error.data)
+      })
+    },
+    locationChange (provinceId, cityId) {
+      if (provinceId || cityId) {
+        this.project.location = {provinceCode: provinceId, cityCode: cityId}
+      }
+    },
+    handleRemove (file, fileList) {
+      console.log(file, fileList)
+    },
+    handleExceed (files, fileList) {
+      this.$message.warning(
+        `当前限制选择 1 个文件,本次选择了 ${
+          files.length
+          } 个文件,共选择了 ${files.length + fileList.length} 个文件`
+      )
+    },
+    beforeRemove (file, fileList) {
+      //return this.$confirm(`确定移除 ${file.name}?`)
+    },
+    beforeUploadRequireDoc () {
+    },
+    beforeUploadApkFile () {
+    },
+    uploadRequireDoc (param) {
+      this.showLoading()
+      const formData = new FormData()
+      let config = {
+        //添加请求头
+        headers: {'Content-Type': 'multipart/form-data'},
+      }
+      formData.append('file', param.file)
+      Http.upload(Apis.FILE.REQUIREMENT_FILE.replace('{userId}', this.user.userVO.id), formData, config).then((res) => {
+        this.project.requireDocUrl = res.data
+        this.hideLoading()
+        notify('success', '需求文档上传成功')
+      }).catch((error) => {
+        this.hideLoading()
+        notify('error', '需求文档上传失败:' + error.data)
+      })
+    },
+    uploadApkFile (param) {
+      this.showLoading()
+      const formData = new FormData()
+      let config = {
+        //添加请求头
+        headers: {'Content-Type': 'multipart/form-data'},
       }
-      return isAPK && isDMG;
+      formData.append('file', param.file)
+      Http.upload(Apis.FILE.APK.replace('{userId}', this.user.userVO.id), formData, config).then((res) => {
+        this.project.fileUrl = res.data
+        this.hideLoading()
+        notify('success', '文件上传成功')
+      }).catch((error) => {
+        this.hideLoading()
+        notify('error', '文件上传失败')
+      })
     },
-    analyseDemand() {
-      this.$router.push({ name: "AnalyseDemand" });
+    setServiceType () {
+      getAllServiceTypes().then((res) => {
+        this.serviceType = res
+      }).catch((error) => {
+        notify('error', '获取项目类型列表失败')
+      })
     },
-    handleAccept(index, id) {
-      console.log("接受");
+    setPlatformType () {
+      this.platforms = getAllPlatformTypes()
     },
-    handleReject(index, id) {
-      console.log("拒绝");
+    setInstitutions () {
+      getAllInstitutions().then((res) => {
+        this.institutionArray = res
+      }).catch((error) => {
+        notify('error', '获取institution失败' + error.data)
+      })
+    },
+    setUserInfo () {
+      this.user = storageGet('user')
+    },
+    showLoading () {
+      this.loading = true
+    },
+    hideLoading () {
+      this.loading = false
+    },
+    reformDate (date) {
+      return getFormalTimeFromDate(date)
     }
   }
-};
+}
 </script>
 
 <style lang="less" scoped>
-.task-list {
-  margin: 0 30px;
-}
-.el-col {
-  padding: 0 !important;
-}
-.el-row {
-  margin-bottom: 10px;
-}
+  .task-list {
+    margin: 0 30px;
+  }
+
+  .el-col {
+    padding: 0 !important;
+  }
+
+  .el-row {
+    margin-bottom: 10px;
+  }
+
+  .el-input {
+    width: 400px;
+  }
 </style>
 
+
+<!--<div class="create-body" v-if="!isModifyMode">-->
+<!--<div class="title h2">分析需求</div>-->
+<!--<div class="task-list">-->
+<!--<el-table :data="analyseDemandList" style="width: 100%" max-height="400">-->
+<!--<el-table-column prop="institution" label="承接单位" title="承接单位"></el-table-column>-->
+<!--<el-table-column prop="feasibilityReport" sortable label="可行性分析报告">-->
+<!--<template slot-scope="scope">-->
+<!--<span v-if="!scope.row.feasibilityReport.url">暂无文件</span>-->
+<!--<a-->
+<!--:href="scope.row.feasibilityReport.url"-->
+<!--v-if="scope.row.feasibilityReport.url"-->
+<!--target="_blank"-->
+<!--&gt;-->
+<!--<i class="fa fa-file-text-o"></i>-->
+<!--{{scope.row.feasibilityReport.name}}-->
+<!--</a>-->
+<!--</template>-->
+<!--</el-table-column>-->
+<!--<el-table-column prop="priceAuditReport" sortable label="可行性分析报告">-->
+<!--<template slot-scope="scope">-->
+<!--<span v-if="!scope.row.priceAuditReport.url">暂无文件</span>-->
+<!--<a-->
+<!--:href="scope.row.priceAuditReport.url"-->
+<!--v-if="scope.row.priceAuditReport.url"-->
+<!--target="_blank"-->
+<!--&gt;-->
+<!--<i class="fa fa-file-text-o"></i>-->
+<!--{{scope.row.priceAuditReport.name}}-->
+<!--</a>-->
+<!--</template>-->
+<!--</el-table-column>-->
+
+<!--<el-table-column align="right" label="操作">-->
+<!--<template slot-scope="scope">-->
+<!--<div-->
+<!--class="btn btn-small btn-info"-->
+<!--@click="handleAccept(scope.$index, scope.row.id)"-->
+<!--&gt;接受-->
+<!--</div>-->
+<!--<div-->
+<!--class="btn btn-small btn-danger"-->
+<!--@click="handleReject(scope.$index, scope.row.id)"-->
+<!--&gt;拒绝-->
+<!--</div>-->
+<!--</template>-->
+<!--</el-table-column>-->
+<!--</el-table>-->
+<!--</div>-->
+<!--</div>-->
+

+ 429 - 179
src/components/project/ProjectCreate.vue

@@ -1,118 +1,115 @@
 <template>
-  <div class="create-container">
-    <div class="title h1">申请项目</div>
+  <div class="create-container" v-loading="loading">
+    <div class="title h1">创建项目</div>
     <div class="create-body">
       <el-form :model="project" :rules="rules" ref="project" label-width="12%" class="demo-project">
         <el-form-item label="项目名称" prop="name">
-          <el-input v-model="project.name"></el-input>
+          <el-input size="small" v-model="project.name" placeholder="请输入项目名称"></el-input>
         </el-form-item>
-        <el-form-item label="联系方式" prop="contact">
-          <div>
-            <el-row :gutter="2">
-              <el-col :span="2">
-                <span>联系人</span>
-              </el-col>
-              <el-col :span="10">
-                <el-input v-model="project.contact.name" placeholder="请输入联系人姓名"></el-input>
-              </el-col>
-            </el-row>
-            <el-row :gutter="2">
-              <el-col :span="2">
-                <span>联系人电话</span>
-              </el-col>
-              <el-col :span="10">
-                <el-input v-model="project.contact.phone" placeholder="请输入联系人电话"></el-input>
-              </el-col>
-            </el-row>
-          </div>
-        </el-form-item>
-        <el-form-item label="平台" prop="platform">
-          <el-checkbox-group v-model="project.platform">
-            <el-checkbox label="0">IOS</el-checkbox>
-            <el-checkbox label="1">ANDROID</el-checkbox>
-            <el-checkbox label="2">WEB</el-checkbox>
-          </el-checkbox-group>
+        <el-form-item label="联系人" prop="contactName">
+          <el-input size="small" v-model="project.contactName" placeholder="请输入联系人姓名"></el-input>
         </el-form-item>
-        <el-form-item label="需求描述" prop="desc">
-          <el-input type="textarea" v-model="project.desc"></el-input>
+        <el-form-item label="手机号" prop="contactPhone">
+          <el-input size="small" v-model="project.contactPhone" placeholder="请输入联系人电话"></el-input>
         </el-form-item>
-        <el-form-item label="价格" prop="price">
-          <el-input type="number" v-model="project.price">
+        <el-form-item label="预算" prop="budget">
+          <el-input size="small" type="number" v-model="project.budget" placeholder="请输入项目预算">
             <template slot="append">¥</template>
           </el-input>
         </el-form-item>
+        <el-form-item label="需求描述" prop="desc">
+          <el-input type="textarea" style="width: 400px" v-model="project.desc"
+                    placeholder="请输入对项目的描述"></el-input>
+        </el-form-item>
+
+        <!--<el-form-item label="价格" prop="price">-->
+        <!--<el-input type="number" v-model="project.price">-->
+        <!--<template slot="append">¥</template>-->
+        <!--</el-input>-->
+        <!--</el-form-item>-->
+        <el-form-item label="平台" prop="platform">
+          <el-checkbox-group v-model="project.platform">
+            <span v-for="(item,index) in platforms" :key="index">
+              <el-checkbox :label="item">{{ item }}&nbsp;&nbsp;&nbsp;&nbsp;</el-checkbox>
+            </span>
+          </el-checkbox-group>
+        </el-form-item>
         <el-form-item label="服务类型" prop="type">
           <el-checkbox-group v-model="project.type">
-            <el-checkbox label="接口测试" name="type"></el-checkbox>
-            <el-checkbox label="安全漏洞扫描" name="type"></el-checkbox>
-            <el-checkbox label="风险评估服务" name="type"></el-checkbox>
-            <el-checkbox label="源代码安全审计服务" name="type"></el-checkbox>
-            <el-checkbox label="功能测试服务" name="type"></el-checkbox>
-            <el-checkbox label="性能测试" name="type"></el-checkbox>
-            <el-checkbox label="功能和易用性测试" name="type"></el-checkbox>
+            <span v-for="(item,index) in serviceType" :key="index">
+              <el-checkbox :label="item" name="type">{{item}}&nbsp;&nbsp;&nbsp;&nbsp;</el-checkbox>
+            </span>
           </el-checkbox-group>
         </el-form-item>
-        <el-form-item label="用途" prop="useage">
-          <el-input v-model="project.useage"></el-input>
-        </el-form-item>
-        <el-form-item label="预算" prop="budget">
-          <el-input type="number" v-model="project.budget">
-            <template slot="append">¥</template>
-          </el-input>
-        </el-form-item>
+
         <el-form-item label="项目可见性" prop="resource">
           <el-tabs
             :tab-position="tabPosition"
             v-model="project.resource"
             style="max-height: 200px;"
           >
-            <el-tab-pane label="定向" name="定向">
-              <el-radio-group v-model="project.institution">
-                <el-radio
-                  :label="item"
-                  name="type"
-                  v-for="item,index in institutionArray"
-                  :key="index"
-                ></el-radio>
+            <el-tab-pane :label="resourceType[0]" name="0">
+              <el-radio-group v-model="project.institution" prop="institution">
+                <el-radio :label="item" name="type" v-for="item,index in institutionArray" :key="index">{{item.name}}
+                </el-radio>
               </el-radio-group>
             </el-tab-pane>
-            <el-tab-pane label="非定向" name="非定向"></el-tab-pane>
+            <el-tab-pane :label="resourceType[1]" name="1">
+              <provincecity
+                ref="addFormProvince"
+                @selectChange="locationChange"
+                :provinceCode="project.location.provinceCode"
+                :cityCode="project.location.cityCode"
+              ></provincecity>
+            </el-tab-pane>
+            <el-tab-pane :label="resourceType[2]" name="2"></el-tab-pane>
           </el-tabs>
         </el-form-item>
         <el-form-item label="需求文档" prop="doc">
           <el-upload
-            class="upload-demo"
+            style="width: 400px"
             drag
-            action="https://jsonplaceholder.typicode.com/posts/"
-            multiple
+            class="upload-demo"
+            action=""
+            :on-remove="handleRemove"
+            :before-remove="beforeRemove"
+            :limit="1"
+            :on-exceed="handleExceed"
+            :before-upload="beforeFileUpload"
+            :http-request="uploadRequireDoc"
+            :file-list="project.doc"
           >
             <i class="el-icon-upload"></i>
             <div class="el-upload__text">
               将文件拖到此处,或
               <em>点击上传</em>
             </div>
-            <div class="el-upload__tip" slot="tip">请上传需求文档</div>
           </el-upload>
         </el-form-item>
         <el-form-item label="安装包" prop="file">
           <el-upload
-            class="upload-demo"
             drag
-            action="https://jsonplaceholder.typicode.com/posts/"
-            multiple
-            :before-upload="beforeFileUpload"
+            style="width: 400px"
+            class="upload-demo"
+            action=""
+            :on-remove="handleRemove"
+            :limit="1"
+            :on-exceed="handleExceed"
+            :before-upload="beforeApkUpload"
+            :http-request="uploadApkFile"
+            :file-list="project.file"
           >
             <i class="el-icon-upload"></i>
             <div class="el-upload__text">
               将文件拖到此处,或
               <em>点击上传</em>
             </div>
-            <div class="el-upload__tip" slot="tip">只能上传Android或IOS安装包文件</div>
           </el-upload>
         </el-form-item>
         <el-form-item label="项目截止时间" prop="datetime">
           <div class="block">
             <el-date-picker
+              size="small"
               v-model="project.datetime"
               type="datetime"
               placeholder="选择截止时间"
@@ -122,7 +119,7 @@
           </div>
         </el-form-item>
         <el-form-item>
-          <div class="btn btn-medium btn-info" @click="submitForm('project')">立即申请</div>
+          <div class="btn btn-medium btn-info" v-on:click="submitForm('project')">立即申请</div>
           <div class="btn btn-medium" @click="resetForm('project')">重置</div>
         </el-form-item>
       </el-form>
@@ -131,179 +128,432 @@
 </template>
 
 <script>
-import Enum from "@/constants/enum/index";
-import PlatformType from "@/constants/enum/platform-type";
-import provinceCity from "@/constants/provinceCity.json";
+import Http from '@/js/http.js'
+import Apis from '@/js/api.js'
+import provincecity from '@/components/commons/ProvinceCity'
+import provinceCityJSON from '@/constants/provinceCity.json'
+import ResourceType from '@/constants/enum/resource-type'
+import {notify} from '@/constants/index'
+import {
+  checkFileType,
+  getAllInstitutions,
+  getAllPlatformTypes,
+  getAllServiceTypes,
+  getProvinceNameByProvinceCode,
+  storageGet
+} from '@/js/index'
+
 export default {
-  name: "ProjectCreate",
-  data() {
+  name: 'ProjectCreate',
+  components: {
+    provincecity
+  },
+  data () {
     var validatePass = (rule, value, callback) => {
-      var reg = /^(0|86|17951)?(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$/;
-      if (value.phone) {
-        if (!reg.test(value.phone)) {
-          callback(new Error("请检查手机号码"));
+      var reg = /^(0|86|17951)?(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$/
+      if (this.contactPhone) {
+        if (!reg.test(this.contactPhone)) {
+          callback(new Error('请检查手机号码'))
         } else {
-          callback();
+          callback()
         }
       }
-    };
+    }
     return {
-      tabPosition: "top",
-      institutionArray: Enum.institution,
-      platformType: [],
+      user: {},
+      loading: false,
+      tabPosition: 'top',
+      institutionArray: [],
+      platforms: [],
+      serviceType: [],
+      resourceType: ResourceType,
       project: {
-        name: "",
-        contact: {
-          name: "",
-          phone: ""
-        },
+        userId: 0,
+        name: '',
+        contactName: '',
+        contactPhone: '',
         type: [],
         platform: [],
-        desc: "",
-        doc: "",
-        file: "",
-        resource: "非定向",
-        institution: "",
-        datetime: "",
-        price: "",
-        useage: "",
-        budget: ""
+        desc: '',
+        doc: [],
+        file: [],
+        requireDocUrl: '',
+        fileUrl: '',
+        resource: '0',
+        location: {provinceCode: '3200', cityCode: '3201'},
+        institution: {},
+        datetime: '',
+        price: '',
+        usage: '',
+        budget: ''
       },
       pickerOptions: {
         shortcuts: [
           {
-            text: "今天",
-            onClick(picker) {
-              picker.$emit("pick", new Date());
+            text: '今天',
+            onClick (picker) {
+              picker.$emit('pick', new Date())
             }
           },
           {
-            text: "昨天",
-            onClick(picker) {
-              const date = new Date();
-              date.setTime(date.getTime() - 3600 * 1000 * 24);
-              picker.$emit("pick", date);
+            text: '昨天',
+            onClick (picker) {
+              const date = new Date()
+              date.setTime(date.getTime() - 3600 * 1000 * 24)
+              picker.$emit('pick', date)
             }
           },
           {
-            text: "一周前",
-            onClick(picker) {
-              const date = new Date();
-              date.setTime(date.getTime() - 3600 * 1000 * 24 * 7);
-              picker.$emit("pick", date);
+            text: '一周前',
+            onClick (picker) {
+              const date = new Date()
+              date.setTime(date.getTime() - 3600 * 1000 * 24 * 7)
+              picker.$emit('pick', date)
             }
           }
         ]
       },
       rules: {
         name: [
-          { required: true, message: "请输入项目名称", trigger: "blur" }
+          {required: true, message: '请输入项目名称', trigger: 'blur'},
+          {min: 5, max: 50, message: '项目名称长度在 5 到 50 个字符', trigger: 'blur'}
+        ],
+        contactName: [
+          {required: true, message: '请输入联系人姓名', trigger: 'blur'}
           // { min: 3, max: 5, message: "长度在 3 到 5 个字符", trigger: "blur" }
         ],
+        contactPhone: [
+          {required: true, message: '请输入手机号', trigger: 'blur'},
+          //{min: 11, max: 11, message: '请输入正确的手机号', trigger: 'blur'}
+        ],
         type: [
           {
-            type: "array",
+            type: 'array',
             required: true,
-            message: "请至少选择一种服务类型",
-            trigger: "change"
+            message: '请至少选择一种服务类型',
+            trigger: 'change'
           }
         ],
         platform: [
           {
-            type: "array",
+            type: 'array',
             required: true,
-            message: "请至少选择一个平台",
-            trigger: "change"
+            message: '请至少选择一个平台',
+            trigger: 'change'
           }
         ],
-        desc: [{ required: true, message: "请填写活动形式", trigger: "blur" }],
-        contact: [{ validator: validatePass, trigger: "blur" }],
+        desc: [{required: false, message: '请填写描述', trigger: 'blur'}],
+        //price: [{required: true, message: '请填写价格', trigger: 'blur'}],
+        budget: [
+          {required: true, message: '预算不可为空', trigger: 'blur'},
+          {
+            validator: (rule, value, callback) => {
+              if(value < 0){
+                callback(new Error('请输入不小于0的数'))
+              } else {
+                callback()
+              }
+            }, trigger: 'blur'
+          },
+        ],
         resource: [
+          {required: true},
           {
-            required: true,
-            message: "请选择项目可见性",
-            trigger: "change"
-          }
-        ]
+            validator: (rule, value, callback) => {
+              if (value == 0 && this.project.institution.id == null) {
+                callback(new Error('定向发布至少要选择一个区域管理员'))
+              } else {
+                callback()
+              }
+            }, trigger: 'change'
+          },
+        ],
+        datetime:[{required: true, message: '截止时间不可为空', trigger: 'blur'}],
       }
-    };
+    }
   },
-  mounted() {
+  mounted () {
     this.$nextTick(() => {
-      this.init();
-    });
+      this.init()
+    })
   },
   watch: {
-    "project.resource"() {
-      if (this.project.resource == "非定向") {
-        this.project.institution = "";
-      }
+    serviceType (val) {
+      this.serviceType = val
+    },
+    institutionArray (val) {
+      this.institutionArray = val
     },
+    // 'project.institution' () {
+    //   if (this.project.institution) {
+    //     this.$refs.addFormProvince.resetProviceCity()
+    //     this.project.location = {provinceCode: '', cityCode: ''}
+    //   }
+    // },
+    // 'project.location' () {
+    //   if (this.project.location.provinceCode || this.project.location.cityCode) {
+    //     this.project.institution = ''
+    //   }
+    // },
+    // 'project.resource' () {
+    //   if (this.project.resource == '2') {
+    //     this.$refs.addFormProvince.resetProviceCity()
+    //     this.project.institution = ''
+    //     this.project.location = {provinceCode: '', cityCode: ''}
+    //   }
+    // },
     deep: true
   },
   methods: {
-    init() {
-      this.project.platform.map(item => {
-        this.platformType.push(PlatformType[item]);
-      });
+    updateLocation (location) {
+      var provinceName = ''
+      var cityName = ''
+      for (var item of provinceCityJSON.provinces) {
+        if (item.code === location.provinceCode) {
+          provinceName = item.name
+          for (var city of item.cities) {
+            if (city.code === location.cityCode) {
+              cityName = city.name
+              break
+            }
+          }
+        }
+      }
+      return provinceName + ' / ' + cityName
+    },
+    locationChange (provinceId, cityId) {
+      if (provinceId || cityId) {
+        this.project.location = {provinceCode: provinceId, cityCode: cityId}
+      }
     },
-    submitForm(formName) {
-      this.$refs[formName].validate(valid => {
+    init () {
+      this.setServiceType()
+      this.setPlatforms()
+      this.setInstitution()
+      this.setUserInfo()
+      // this.project.platform.map(item => {
+      //   this.platformType.push(PlatformType[item])
+      // })
+    },
+    submitForm () {
+      this.$refs['project'].validate(valid => {
         if (valid) {
-          console.log(this.project);
-          //提交 project
+          //console.log(this.project)
+          this.showLoading()
+          const newLocation = getProvinceNameByProvinceCode(this.project.location.provinceCode, this.project.location.cityCode)
+          const newProject = {
+            userId: this.user.userVO.id,
+            name: this.project.name,
+            type: this.project.type,
+            platform: this.project.platform,
+            desc: this.project.desc,
+            resource: this.project.resource,
+            location: newLocation,
+            institution: this.project.institution.id,
+            contactName: this.project.contactName,
+            contactPhone: this.project.contactPhone,
+            doc: this.project.requireDocUrl,
+            file: this.project.fileUrl,
+            budget: this.project.budget,
+            datetime: this.project.datetime,
+            usage: this.project.usage,
+            price: this.project.price
+          }
+          Http.post(Apis.PROJECT.CREATE_PROJECT, newProject).then((res) => {
+            //notify('success', '创建成功')
+            this.hideLoading()
+            this.createProjectSuccess(res.projectDetails.id)
+            // if (window.history.length <= 1) {
+            //   this.$router.push({path: '/'})
+            //   return false
+            // } else {
+            //   this.$router.go(-1)
+            // }
+          }).catch(error => {
+            //console.log(error)
+            notify('error', error.data)
+
+          })
         } else {
-          console.log("error submit!!");
-          return false;
+          console.log(valid)
+          notify('error','表单填写错误!')
+          return false
         }
-      });
+      })
     },
-    resetForm(formName) {
-      this.$refs[formName].resetFields();
-      this.project.name = "";
-      this.project.type = [];
-      this.project.platform = [];
-      this.project.desc = "";
-      this.project.file = "";
-      this.project.doc = "";
-      this.project.contact = {
-        name: "",
-        phone: ""
-      };
+    resetForm (formName) {
+      this.$refs[formName].resetFields()
+      this.project.name = ''
+      this.project.type = []
+      this.project.platform = []
+      this.project.desc = ''
+      this.project.file = ''
+      this.project.doc = ''
+      this.project.contactName = ''
+      this.project.contactPhone = ''
 
-      this.project.resource = "非定向";
-      this.project.institution = "";
-      this.project.datetime = "";
-      this.project.price = "";
-      this.project.useage = "";
-      this.project.budget = "";
+      this.project.resource = '非定向'
+      this.project.institution = ''
+      this.project.datetime = ''
+      this.project.price = ''
+      this.project.usage = ''
+      this.project.budget = ''
+    },
+    beforeApkUpload (file) {
+      const fileType = ['exe', 'apk', 'dmg']
+      return checkFileType(file, fileType, this.beforeApkUploadError)
+    },
+    beforeApkUploadError () {
+      this.$message.error('上传文件只能是exe,dmg,apk格式!')
     },
-    beforeFileUpload(file) {
-      const isAPK = file.type === "application/vnd.android.package-archive";
-      const isDMG = file.type === "application/octet-stream";
+    beforeFileUpload (file) {
+      const fileTypeList = ['pdf', 'xls', 'xlsx', 'doc', 'docx', 'txt']
+      return checkFileType(file, fileTypeList, this.beforeFileUploadError)
+    },
+    beforeFileUploadError () {
+      this.$message.error('上传文件只能是 PDF 、 DOC 、DOCX 、XLS、TXT、XLSX 格式!')
+    },
+    loadData () {
+      Http.get(Apis.PAGE.PROJECT_DETAIL_PAGE).then((res) => {
+        this.project = res.project
+      })
+    },
+    handleRemove (file, fileList) {
+      //console.log(file, fileList)
+    },
+    handleExceed (files, fileList) {
+      this.$message.warning(
+        `当前限制选择 1 个文件,本次选择了 ${
+          files.length
+          } 个文件,共选择了 ${files.length + fileList.length} 个文件`
+      )
+    },
+    beforeRemove (file, fileList) {
+      //return this.$confirm(`确定移除 ${file.name}?`)
+    },
+    uploadRequireDoc (param) {
+      this.showLoading()
+      const formData = new FormData()
+      let config = {
+        //添加请求头
+        headers: {'Content-Type': 'multipart/form-data'},
+      }
+      formData.append('file', param.file)
+      Http.upload(Apis.FILE.REQUIREMENT_FILE.replace('{userId}', this.user.userVO.id), formData, config).then((res) => {
+        //console.log('上传成功')
+        this.hideLoading()
+        notify('success', '需求文档上传成功')
+        this.project.requireDocUrl = res.data
+        //console.log(this.project.doc)
+        //console.log(res.data)
+      }).catch((error) => {
+        this.hideLoading()
+        notify('error', '需求文档上传失败:' + error.data)
+      })
 
-      if (!isAPK && !isDMG) {
-        this.$message.error("上传安装包只能是 APK 或 DMG 格式!");
+    },
+    uploadApkFile (param) {
+      this.showLoading()
+      const formData = new FormData()
+      let config = {
+        //添加请求头
+        headers: {'Content-Type': 'multipart/form-data'},
       }
-      return isAPK && isDMG;
+      formData.append('file', param.file)
+      Http.upload(Apis.FILE.APK.replace('{userId}', this.user.userVO.id), formData, config).then((res) => {
+        this.hideLoading()
+        notify('success', '文件上传成功')
+        this.project.fileUrl = res.data
+        console.log(res)
+      }).catch((error) => {
+        this.hideLoading()
+        notify('error', '文件上传失败:' + error.data)
+      })
+    },
+    setServiceType () {
+      getAllServiceTypes().then((res) => {
+        this.serviceType = res
+      }).catch((error) => {
+        notify('error', '获取项目服务类型列表失败')
+      })
+    },
+    setPlatforms () {
+      this.platforms = getAllPlatformTypes()
+    },
+    setInstitution () {
+      getAllInstitutions().then((res) => {
+        this.institutionArray = res
+      })
+    },
+    setUserInfo () {
+      this.user = storageGet('user')
+    },
+    createProjectSuccess (projectId) {
+      this.$alert('项目创建成功', '创建成功', {
+        confirmButtonText: '确定',
+        callback: action => {
+          this.$router.push({
+            name: 'Project',
+            params: {projectId: projectId}
+          })
+        }
+      })
+    },
+    showLoading () {
+      this.loading = true
+    },
+    hideLoading () {
+      this.loading = false
     }
   }
-};
+}
 </script>
 
 <style lang="less" scoped>
-.el-col {
-  padding: 0 !important;
-}
-.el-row {
-  margin-bottom: 10px;
-}
-.el-radio {
-  margin: 10px 20px 10px 0;
-}
-.el-form-item /deep/.el-tabs__content {
-  max-height: 120px !important;
-  overflow: auto;
-}
+  .el-col {
+    padding: 0 !important;
+  }
+
+  .el-row {
+    margin-bottom: 10px;
+  }
+
+  .el-radio {
+    margin: 10px 20px 10px 0;
+  }
+
+  .el-form-item /deep/ .el-tabs__content {
+    max-height: 120px !important;
+    overflow: auto;
+  }
+
+  .el-input {
+    width: 400px;
+  }
 </style>
 
+<!--<el-form-item label="联系方式" prop="contact">-->
+<!--<div>-->
+<!--<el-row :gutter="2">-->
+<!--<el-col :span="2">-->
+<!--<span>联系人</span>-->
+<!--</el-col>-->
+<!--<el-col :span="10">-->
+<!--<el-input v-model="project.contactName" placeholder="请输入联系人姓名"></el-input>-->
+<!--</el-col>-->
+<!--</el-row>-->
+<!--<el-row :gutter="2">-->
+<!--<el-col :span="2">-->
+<!--<span>联系人电话</span>-->
+<!--</el-col>-->
+<!--<el-col :span="10">-->
+<!--<el-input v-model="project.contactPhone" placeholder="请输入联系人电话"></el-input>-->
+<!--</el-col>-->
+<!--</el-row>-->
+<!--</div>-->
+<!--</el-form-item>-->
+
+
+<!--<el-form-item label="用途" prop="usage">-->
+<!--<el-input v-model="project.usage"></el-input>-->
+<!--</el-form-item>-->

+ 300 - 0
src/components/report/ProjectReport.vue

@@ -0,0 +1,300 @@
+<template>
+  <div class="create-container">
+    <div class="create-body" v-loading="loading">
+      <el-form :model="report" :rules="rules" ref="report" label-width="12%" class="demo-report">
+        <el-form-item label="报告名称" prop="name">
+          <el-input size="small" v-if="isModifyMode" v-model="report.name"></el-input>
+          <span v-if="!isModifyMode">{{report.name}}</span>
+        </el-form-item>
+        <el-form-item label="报告类型" prop="type">
+          <el-radio-group v-if="isModifyMode" v-model="report.type">
+            <span v-for="(item,index) in reportType" :key="index">
+              <el-radio :label="item" name="type">{{item}}</el-radio>
+            </span>
+          </el-radio-group>
+          <span v-if="!isModifyMode" class="badge">{{report.type}}</span>
+        </el-form-item>
+
+        <el-form-item label="测试对象" prop="target">
+          <el-input autosize v-if="isModifyMode" type="textarea" v-model="report.target"></el-input>
+          <span v-if="!isModifyMode">{{report.target}}</span>
+        </el-form-item>
+
+        <el-form-item label="测试内容" prop="content">
+          <el-input autosize v-if="isModifyMode" type="textarea" v-model="report.content"></el-input>
+          <span v-if="!isModifyMode">{{report.content}}</span>
+        </el-form-item>
+        <el-form-item prop="file" label="报告文件">
+          <el-upload
+            style="width: 400px"
+            v-if="isModifyMode"
+            drag
+            class="upload-demo"
+            action=""
+            :on-remove="handleRemove"
+            :before-remove="beforeRemove"
+            multiple
+            :limit="1"
+            :on-exceed="handleExceed"
+            :before-upload="beforeFileUpload"
+            :file-list="report.file"
+            :http-request="uploadReportFile"
+          >
+            <i class="el-icon-upload"></i>
+            <div class="el-upload__text">
+              将文件拖到此处,或
+              <em>点击上传</em>
+            </div>
+            <div class="el-upload__tip" slot="tip">请上传报告文件</div>
+          </el-upload>
+          <div v-if="!isModifyMode">
+            <span v-if="report.fileUrl==null">暂无文件</span>
+            <a :href="report.fileUrl" v-if="report.fileUrl!=null">
+              <el-link :underline="false" type="primary"><i class="el-icon-document"></i>下载文档</el-link>
+            </a>
+          </div>
+        </el-form-item>
+
+        <el-form-item label="结论" prop="conclusion">
+          <el-input autosize v-if="isModifyMode" type="textarea" v-model="report.conclusion"></el-input>
+          <span v-if="!isModifyMode">{{report.conclusion}}</span>
+        </el-form-item>
+        <el-form-item v-if="!isModifyMode">
+          <div class="btn btn-medium btn-info" @click="modifyForm()">修改</div>
+          <div class="btn btn-medium" @click="back()">返回</div>
+        </el-form-item>
+        <el-form-item v-if="isModifyMode">
+          <div class="btn btn-medium btn-info" @click="submitForm('report')">确认修改</div>
+          <div class="btn btn-medium" @click="resetForm('report')">重置</div>
+          <div class="btn btn-medium" @click="cancelCreate('report')">取消</div>
+        </el-form-item>
+      </el-form>
+    </div>
+  </div>
+</template>
+
+<script>
+import Http from '@/js/http.js'
+import Apis from '@/js/api.js'
+import {notify} from '@/constants/index'
+import {getAllReportTypes, storageGet} from '@/js/index'
+
+export default {
+  name: 'ProjectReport',
+  components: {},
+  data () {
+    return {
+      user: {},
+      loading: false,
+      reportId: 0,
+      projectId: '',
+      taskId: '',
+      isModifyMode: false,
+      reportType: [],
+      report: {
+        name: '',
+        type: '',
+        description: '',
+        target: '',
+        content: '',
+        file: [],
+        fileUrl: '',
+        conclusion: ''
+      },
+      rules: {
+        name: [
+          {required: true, message: '任务名称不可为空', trigger: 'blur'},
+          {min: 5, max: 50, message: '报告名称长度在 5 到 50 个字符', trigger: 'blur'}
+        ],
+        type: [
+          {required: true, message: '报告类型不可为空'},
+        ],
+        target: [
+          {required: true, message: '测试对象不可为空', trigger: 'blur'}
+        ],
+        content: [
+          {required: true, message: '测试内容不可为空', trigger: 'blur'}
+        ],
+        conclusion: [
+          {required: true, message: '结论不可为空', trigger: 'blur'}
+        ]
+      }
+    }
+  },
+  mounted () {
+    this.$nextTick(() => {
+      this.init()
+    })
+  },
+  methods: {
+    init () {
+      this.reportId = this.$route.params.reportId
+      this.projectId = this.$route.params.projectId
+      this.taskId = this.$route.params.taskId
+      this.setReportType()
+      this.setUserInfo()
+      this.loadData()
+    },
+    modifyForm () {
+      this.isModifyMode = true
+    },
+    submitForm (formName) {
+      this.$refs['report'].validate(valid => {
+        if (valid) {
+          this.isModifyMode = false
+          this.showLoading()
+          const newReport = {
+            name: this.report.name,
+            scope: this.taskId == null ? 0 : 1,
+            type: this.report.type,
+            dependencyCode: this.taskId == null ? this.projectId : this.taskId,
+            target: this.report.target,
+            content: this.report.content,
+            file: '123.pdf',
+            conclusion: this.report.conclusion
+          }
+          console.log(newReport)
+          Http.put(Apis.REPORT.UPDATE_PROJECT_REPORT.replace('{projectId}', this.projectId).replace('{reportId}', this.reportId), newReport).then((res) => {
+            console.log(res)
+            notify('success', '修改成功')
+            this.hideLoading()
+            this.isModifyMode = false
+          }).catch((error) => {
+            this.hideLoading()
+            notify('error', error.data)
+          })
+          //提交 report
+        } else {
+          notify('error', '表单填写有误')
+          return false
+        }
+      })
+    },
+    resetForm (formName) {
+      this.$refs[formName].resetFields()
+      this.report.name = ''
+      this.report.target = ''
+      this.report.content = ''
+      this.report.file = ''
+      this.report.type = ''
+      this.report.conclusion = ''
+    },
+    cancelCreate () {
+      this.isModifyMode = false
+      //请求 report
+    },
+    handleRemove (file, fileList) {
+      console.log(file, fileList)
+    },
+    handleExceed (files, fileList) {
+      this.$message.warning(
+        `当前限制选择 1 个文件,本次选择了 ${
+          files.length
+          } 个文件,共选择了 ${files.length + fileList.length} 个文件`
+      )
+    },
+    beforeRemove (file, fileList) {
+      //return this.$confirm(`确定移除 ${file.name}?`)
+    },
+    beforeFileUpload (file) {
+      console.log(file)
+      const isPDF = file.type === 'application/pdf'
+      const isDOC = file.type === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
+      const isEXCEL = file.type === 'application/vnd.ms-excel'
+      const isXLS = file.type === 'application/x-xls'
+      const isTXT = file.type === 'text/plain'
+      const isXLSX = file.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
+      //console.log(file)
+      if (!(isDOC || isEXCEL || isPDF || isTXT || isXLS || isXLSX)) {
+        this.$message.error('上传文件只能是 PDF 、 DOC 、DOCX 、XLS、TXT、XLSX 格式!')
+      }
+      return isDOC || isEXCEL || isPDF || isTXT || isXLS || isXLSX
+    },
+    back () {
+      this.$router.push({
+        name: 'Project',
+        params: {projectId: this.projectId}
+      })
+    },
+    loadData () {
+      //pro1564487183259
+      //pro1564487183259_task1564487274060
+      //pro1564487183259pro1564487183259_task1564487274060_rep1564488510500
+      this.showLoading()
+      Http.get(Apis.REPORT.GET_PROJECT_REPORT.replace('{projectId}', this.projectId).replace('{reportId}', this.reportId)).then((res) => {
+        this.report.name = res.crowdReportVO.name
+        this.report.crowdTestTaskId = res.crowdReportVO.crowdTestTaskId
+        this.report.scope = res.crowdReportVO.scope
+        this.report.type = res.crowdReportVO.type
+        this.report.description = res.crowdReportVO.description
+        this.report.content = res.crowdReportVO.content
+        this.report.fileUrl = res.crowdReportVO.file
+        this.report.conclusion = res.crowdReportVO.conclusion
+        this.report.target = res.crowdReportVO.target
+        this.hideLoading()
+        //notify('success', '修改成功')
+      }).catch((error) => {
+        this.hideLoading()
+        notify('error', '打开报告失败:' + error.data)
+      })
+    },
+    uploadReportFile (param) {
+      this.showLoading()
+      const formData = new FormData()
+      let config = {
+        //添加请求头
+        headers: {'Content-Type': 'multipart/form-data'},
+      }
+      formData.append('file', param.file)
+      Http.upload(Apis.FILE.UPLOAD_REPORT_FILE.replace('{userId}', this.user.userVO.id), formData, config).then((res) => {
+        console.log('上传成功')
+        this.report.fileUrl = res.data
+        console.log(res)
+        this.hideLoading()
+      }).catch((error) => {
+        this.hideLoading()
+        notify('error', '文件上传失败:' + error.data)
+      })
+    },
+    setReportType () {
+      getAllReportTypes().then((res) => {
+        this.reportType = res
+      }).catch((error) => {
+        notify('error', '加载报告类型失败')
+      })
+    },
+    setUserInfo () {
+      this.user = storageGet('user')
+    },
+    updateReportSuccess () {
+
+    },
+    showLoading () {
+      this.loading = true
+    },
+    hideLoading () {
+      this.loading = false
+    }
+  },
+  watch: {
+    reportType (val) {
+      this.reportType = val
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+  .el-radio {
+    margin: 10px 20px 10px 0;
+  }
+
+  .el-form-item /deep/ .el-tabs__content {
+    max-height: 120px !important;
+    overflow: auto;
+  }
+
+  .el-row {
+    margin-bottom: 10px;
+  }
+</style>

+ 281 - 0
src/components/report/ProjectReportCreate.vue

@@ -0,0 +1,281 @@
+<template>
+  <div class="create-container" v-loading="loading">
+    <div class="title h1">创建报告</div>
+    <div class="create-body">
+      <el-form :model="report" :rules="rules" ref="report" label-width="12%" class="demo-report">
+        <el-form-item label="报告名称" prop="name">
+          <el-input size="small" v-model="report.name"></el-input>
+        </el-form-item>
+        <el-form-item label="报告类型" prop="type">
+          <el-radio-group v-model="report.type">
+            <span v-for="(item,index) in reportType" :key="index">
+              <el-radio :label="item" name="type">{{item}}</el-radio>
+            </span>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="测试对象" prop="name">
+          <el-input autosize style="width: 400px" type="textarea" v-model="report.target"></el-input>
+        </el-form-item>
+        <el-form-item label="测试内容" prop="name">
+          <el-input autosize style="width: 400px" type="textarea" v-model="report.content"></el-input>
+        </el-form-item>
+        <!--<el-form-item label="摘要" prop="abstract">-->
+        <!--<div>-->
+        <!--<el-row :gutter="2">-->
+        <!--<el-col :span="2">-->
+        <!--<span>测试对象</span>-->
+        <!--</el-col>-->
+        <!--<el-col :span="10">-->
+        <!--<el-input type="textarea" v-model="report.target"></el-input>-->
+        <!--</el-col>-->
+        <!--</el-row>-->
+        <!--<el-row :gutter="2">-->
+        <!--<el-col :span="2">-->
+        <!--<span>测试内容</span>-->
+        <!--</el-col>-->
+        <!--<el-col :span="10">-->
+        <!--<el-input type="textarea" v-model="report.content"></el-input>-->
+        <!--</el-col>-->
+        <!--</el-row>-->
+        <!--</div>-->
+        <!--</el-form-item>-->
+        <el-form-item prop="file" label="报告文件">
+          <el-upload
+            style="width: 400px"
+            drag
+            class="upload-demo"
+            action="https://jsonplaceholder.typicode.com/posts/"
+            :on-remove="handleRemove"
+            :before-remove="beforeRemove"
+            multiple
+            :limit="1"
+            :on-exceed="handleExceed"
+            :before-upload="beforeFileUpload"
+            :file-list="report.file"
+            :http-request="uploadReportFile"
+          >
+            <i class="el-icon-upload"></i>
+            <div class="el-upload__text">
+              将文件拖到此处,或
+              <em>点击上传</em>
+            </div>
+          </el-upload>
+        </el-form-item>
+
+        <el-form-item label="结论" prop="conclusion">
+          <el-input autosize style="width: 400px" type="textarea" v-model="report.conclusion"></el-input>
+        </el-form-item>
+        <el-form-item>
+          <div class="btn btn-medium btn-info" @click="submitForm('report')">提交</div>
+          <div class="btn btn-medium" @click="resetForm('report')">重置</div>
+          <div class="btn btn-medium" @click="cancelCreate('report')">取消</div>
+        </el-form-item>
+      </el-form>
+    </div>
+  </div>
+</template>
+
+<script>
+import Http from '@/js/http.js'
+import Apis from '@/js/api.js'
+import {notify} from '@/constants/index'
+import {getAllReportTypes, storageGet} from '@/js/index'
+
+export default {
+  name: 'ProjectReportCreate',
+  components: {},
+  data () {
+    return {
+      user: {},
+      reportType: [],
+      loading: false,
+      scope: 0,
+      projectId: '',
+      taskId: '',
+      dependencyCode: '',
+      report: {
+        name: '',
+        target: '',
+        content: '',
+        file: [],
+        fileUrl: '',
+        type: '',
+        conclusion: ''
+      },
+      rules: {
+        name: [
+          {required: true, message: '任务名称不可为空', trigger: 'blur'},
+          {min: 5, max: 50, message: '报告名称长度在 5 到 50 个字符', trigger: 'blur'}
+        ],
+        type: [
+          {required: true, message: '报告类型不可为空'},
+        ],
+        target: [
+          {required: true, message: '测试对象不可为空', trigger: 'blur'}
+        ],
+        content: [
+          {required: true, message: '测试内容不可为空', trigger: 'blur'}
+        ],
+        conclusion: [
+          {required: true, message: '结论不可为空', trigger: 'blur'}
+        ]
+      }
+    }
+  },
+  mounted () {
+    this.$nextTick(() => {
+      this.init()
+    })
+  },
+  methods: {
+    init () {
+      this.scope = this.$route.params.scope
+      this.dependencyCode = this.$route.params.dependencyCode
+      this.projectId = this.$route.params.projectId
+      this.taskId = this.$route.params.taskId
+      this.setUserInfo()
+      this.setReportType()
+    },
+    submitForm (formName) {
+      this.$refs['report'].validate(valid => {
+        if (valid) {
+          this.showLoading()
+          const newReport = {
+            name: this.report.name,
+            scope: this.scope,
+            type: this.report.type,
+            dependencyCode: this.dependencyCode,
+            target: this.report.target,
+            content: this.report.content,
+            file: this.report.fileUrl,
+            conclusion: this.report.conclusion
+          }
+          console.log(newReport)
+          Http.post(Apis.REPORT.CREATE_PROJECT_REPORT.replace('{projectId}', this.projectId), newReport).then((res) => {
+            this.hideLoading()
+            this.createReportSuccess(res.crowdReportVO.code)
+          }).catch((error) => {
+            this.hideLoading()
+            notify('error', '报告创建失败:' + error.data)
+          })
+          //提交 report
+        } else {
+          notify('error', '表单填写有误')
+          return false
+        }
+      })
+    },
+    resetForm (formName) {
+      this.$refs[formName].resetFields()
+      this.report.name = ''
+      this.report.abstract.target = ''
+      this.report.abstract.content = ''
+      this.report.file = []
+      this.report.type = ''
+      this.report.conclusion = ''
+    },
+    cancelCreate () {
+      if (window.history.length <= 1) {
+        this.$router.push({path: '/'})
+        return false
+      } else {
+        this.$router.go(-1)
+      }
+    },
+    handleRemove (file, fileList) {
+      console.log(file, fileList)
+    },
+    handleExceed (files, fileList) {
+      this.$message.warning(
+        `当前限制选择 1 个文件,本次选择了 ${
+          files.length
+          } 个文件,共选择了 ${files.length + fileList.length} 个文件`
+      )
+    },
+    beforeRemove (file, fileList) {
+      //return this.$confirm(`确定移除 ${file.name}?`)
+    },
+    beforeFileUpload (file) {
+      console.log(file)
+      const isPDF = file.type === 'application/pdf'
+      const isDOC = file.type === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
+      const isEXCEL = file.type === 'application/vnd.ms-excel'
+      const isXLS = file.type === 'application/x-xls'
+      const isTXT = file.type === 'text/plain'
+      const isXLSX = file.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
+      //console.log(file)
+      if (!(isDOC || isEXCEL || isPDF || isTXT || isXLS || isXLSX)) {
+        this.$message.error('上传文件只能是 PDF 、 DOC 、DOCX 、XLS、TXT、XLSX 格式!')
+      }
+      return isDOC || isEXCEL || isPDF || isTXT || isXLS || isXLSX
+    },
+    loadData () {
+    },
+    uploadReportFile (param) {
+      const formData = new FormData()
+      let config = {
+        //添加请求头
+        headers: {'Content-Type': 'multipart/form-data'},
+      }
+      formData.append('file', param.file)
+      Http.upload(Apis.FILE.UPLOAD_REPORT_FILE.replace('{userId}', this.user.userVO.id), formData, config).then((res) => {
+        console.log('上传成功')
+        this.report.fileUrl = res.data
+        console.log(res)
+      })
+    },
+    setReportType () {
+      this.reportType = getAllReportTypes().then((res) => {
+        this.reportType = res
+      }).catch((error) => {
+        notify('error', '获取报告类型列表失败')
+      })
+    },
+    setUserInfo () {
+      this.user = storageGet('user')
+    },
+    createReportSuccess (reportId) {
+      this.$alert('报告创建成功', '创建成功', {
+        confirmButtonText: '确定',
+        callback: action => {
+          this.$router.push({
+            name: 'ProjectReport',
+            params: {reportId: reportId, projectId: this.projectId}
+          })
+        }
+      })
+    },
+    showLoading () {
+      this.loading = true
+    },
+    hideLoading () {
+      this.loading = false
+    }
+  },
+  watch: {
+    reportType (val) {
+      this.reportType = val
+    }
+  }
+
+}
+</script>
+
+<style lang="less" scoped>
+  .el-radio {
+    margin: 10px 20px 10px 0;
+  }
+
+  .el-form-item /deep/ .el-tabs__content {
+    max-height: 120px !important;
+    overflow: auto;
+  }
+
+  .el-row {
+    margin-bottom: 10px;
+  }
+
+  .el-input {
+    width: 400px;
+  }
+</style>

+ 0 - 221
src/components/report/Report.vue

@@ -1,221 +0,0 @@
-<template>
-  <div class="create-container">
-    <div class="create-body">
-      <el-form :model="report" :rules="rules" ref="report" label-width="12%" class="demo-report">
-        <el-form-item label="报告名称" prop="name">
-          <el-input v-if="isModifyMode" v-model="report.name"></el-input>
-          <span v-if="!isModifyMode">{{report.name}}</span>
-        </el-form-item>
-        <el-form-item label="报告类型" prop="type">
-          <el-radio-group v-if="isModifyMode" v-model="report.type">
-            <el-radio label="项目可行性报告" name="type"></el-radio>
-            <el-radio label="项目测试方案" name="type"></el-radio>
-            <el-radio label="项目测试报告" name="type"></el-radio>
-            <el-radio label="项目缺陷报告" name="type"></el-radio>
-            <el-radio label="项目用例报告" name="type"></el-radio>
-            <el-radio label="其他" name="type"></el-radio>
-          </el-radio-group>
-          <span v-if="!isModifyMode" class="badge">{{report.type}}</span>
-        </el-form-item>
-        <el-form-item label="摘要" prop="abstract">
-          <div>
-            <el-row :gutter="2">
-              <el-col :span="2">
-                <span>测试对象</span>
-              </el-col>
-              <el-col :span="10">
-                <el-input v-if="isModifyMode" type="textarea" v-model="report.abstract.target"></el-input>
-                <span v-if="!isModifyMode">{{report.abstract.target}}</span>
-              </el-col>
-            </el-row>
-            <el-row :gutter="2">
-              <el-col :span="2">
-                <span>测试内容</span>
-              </el-col>
-              <el-col :span="10">
-                <el-input v-if="isModifyMode" type="textarea" v-model="report.abstract.content"></el-input>
-                <span v-if="!isModifyMode">{{report.abstract.content}}</span>
-              </el-col>
-            </el-row>
-          </div>
-        </el-form-item>
-        <el-form-item prop="file" label="报告文件">
-          <el-upload
-            v-if="isModifyMode"
-            drag
-            class="upload-demo"
-            action="https://jsonplaceholder.typicode.com/posts/"
-            :on-remove="handleRemove"
-            :before-remove="beforeRemove"
-            multiple
-            :limit="1"
-            :on-exceed="handleExceed"
-            :before-upload="beforeFileUpload"
-            :file-list="report.file"
-          >
-            <i class="el-icon-upload"></i>
-            <div class="el-upload__text">
-              将文件拖到此处,或
-              <em>点击上传</em>
-            </div>
-            <div class="el-upload__tip" slot="tip">请上传报告文件</div>
-          </el-upload>
-          <div v-if="!isModifyMode">
-            <span v-if="report.file.length==0">暂无文件</span>
-            <a :href="report.file[0].url" v-if="report.file.length>0"><i class="fa fa-file-text-o"></i> {{report.file[0].name}}</a>
-          </div>
-        </el-form-item>
-
-        <el-form-item label="结论" prop="conclusion">
-          <el-input v-if="isModifyMode" type="textarea" v-model="report.conclusion"></el-input>
-          <span v-if="!isModifyMode">{{report.conclusion}}</span>
-        </el-form-item>
-        <el-form-item v-if="!isModifyMode">
-          <div class="btn btn-medium btn-info" @click="modifyForm()">修改</div>
-          <div class="btn btn-medium" @click="back()">返回</div>
-        </el-form-item>
-        <el-form-item v-if="isModifyMode">
-          <div class="btn btn-primary btn-info" @click="submitForm('report')">确认修改</div>
-          <div class="btn btn-primary" @click="resetForm('report')">重置</div>
-          <div class="btn btn-primary" @click="cancelCreate('report')">取消</div>
-        </el-form-item>
-      </el-form>
-    </div>
-  </div>
-</template>
-
-<script>
-export default {
-  name: "Report-Create",
-  components: {},
-  data() {
-    return {
-      reportId: 0,
-      isModifyMode: false,
-      report: {
-        name: "测试报告1",
-        abstract: {
-          target: "测试对象xxxx",
-          content: "测试内容xxxxx"
-        },
-        file: [{ name: "report5", url: "report5.excel" }],
-        type: "项目测试方案",
-        conclusion: "app挺好"
-      },
-      rules: {
-        name: [
-          { required: true, message: "请输入报告名称", trigger: "blur" }
-          // { min: 3, max: 5, message: "长度在 3 到 5 个字符", trigger: "blur" }
-        ],
-        abstract: [
-          {
-            required: true,
-            message: "请输入摘要信息",
-            trigger: "change"
-          }
-        ],
-        type: [
-          { required: true, message: "请选择报告类型", trigger: "change" }
-        ],
-        conclusion: [
-          { required: true, message: "请输入报告结论", trigger: "blur" }
-        ]
-      }
-    };
-  },
-  mounted() {
-    this.$nextTick(() => {
-      this.init();
-    });
-  },
-  methods: {
-    init() {
-      this.reportId = +this.$route.params.reportId;
-    },
-    modifyForm() {
-      this.isModifyMode = true;
-      //请求 report
-      this.report = {
-        name: "测试报告1",
-        abstract: {
-          target: "测试对象xxxx",
-          content: "测试内容xxxxx"
-        },
-        file: [{ name: "report5", url: "report5.excel" }],
-        type: "项目测试方案",
-        conclusion: "app挺好"
-      };
-    },
-    submitForm(formName) {
-      this.$refs[formName].validate(valid => {
-        if (valid) {
-          this.isModifyMode = false;
-          console.log(this.report);
-          //提交 report
-        } else {
-          console.log("error submit!!");
-          return false;
-        }
-      });
-    },
-    resetForm(formName) {
-      this.$refs[formName].resetFields();
-      this.report.name = "";
-      this.report.abstract.target = "";
-      this.report.abstract.content = "";
-      this.report.file = [];
-      this.report.type = "";
-      this.report.conclusion = "";
-    },
-    cancelCreate() {
-      this.isModifyMode = false;
-      //请求 report
-      this.report = {
-        name: "测试报告1",
-        abstract: {
-          target: "测试对象xxxx",
-          content: "测试内容xxxxx"
-        },
-        file: [{ name: "report5", url: "report5.excel" }],
-        type: "项目测试方案",
-        conclusion: "app挺好"
-      };
-    },
-    handleRemove(file, fileList) {
-      console.log(file, fileList);
-    },
-    handleExceed(files, fileList) {
-      this.$message.warning(
-        `当前限制选择 1 个文件,本次选择了 ${
-          files.length
-        } 个文件,共选择了 ${files.length + fileList.length} 个文件`
-      );
-    },
-    beforeRemove(file, fileList) {
-      return this.$confirm(`确定移除 ${file.name}?`);
-    },
-    beforeFileUpload() {},
-    back(){
-      if (window.history.length <= 1) {
-        this.$router.push({ path: "/" });
-        return false;
-      } else {
-        this.$router.go(-1);
-      }
-    }
-  }
-};
-</script>
-
-<style lang="less" scoped>
-.el-radio {
-  margin: 10px 20px 10px 0;
-}
-.el-form-item /deep/.el-tabs__content {
-  max-height: 120px !important;
-  overflow: auto;
-}
-.el-row {
-  margin-bottom: 10px;
-}
-</style>

+ 0 - 173
src/components/report/ReportCreate.vue

@@ -1,173 +0,0 @@
-<template>
-  <div class="create-container">
-    <div class="title h1">创建报告</div>
-    <div class="create-body">
-      <el-form :model="report" :rules="rules" ref="report" label-width="12%" class="demo-report">
-        <el-form-item label="报告名称" prop="name">
-          <el-input v-model="report.name"></el-input>
-        </el-form-item>
-        <el-form-item label="报告类型" prop="type">
-          <el-radio-group v-model="report.type">
-            <el-radio label="项目可行性报告" name="type"></el-radio>
-            <el-radio label="项目测试方案" name="type"></el-radio>
-            <el-radio label="项目测试报告" name="type"></el-radio>
-            <el-radio label="项目缺陷报告" name="type"></el-radio>
-            <el-radio label="项目用例报告" name="type"></el-radio>
-            <el-radio label="其他" name="type"></el-radio>
-          </el-radio-group>
-        </el-form-item>
-        <el-form-item label="摘要" prop="abstract">
-          <div>
-            <el-row :gutter="2">
-              <el-col :span="2">
-                <span>测试对象</span>
-              </el-col>
-              <el-col :span="10">
-                <el-input type="textarea" v-model="report.abstract.target"></el-input>
-              </el-col>
-            </el-row>
-            <el-row :gutter="2">
-              <el-col :span="2">
-                <span>测试内容</span>
-              </el-col>
-              <el-col :span="10">
-                <el-input type="textarea" v-model="report.abstract.content"></el-input>
-              </el-col>
-            </el-row>
-          </div>
-        </el-form-item>
-        <el-form-item prop="file" label="报告文件">
-          <el-upload
-            drag
-            class="upload-demo"
-            action="https://jsonplaceholder.typicode.com/posts/"
-            :on-remove="handleRemove"
-            :before-remove="beforeRemove"
-            multiple
-            :limit="1"
-            :on-exceed="handleExceed"
-            :before-upload="beforeFileUpload"
-            :file-list="report.file"
-          >
-            <i class="el-icon-upload"></i>
-            <div class="el-upload__text">
-              将文件拖到此处,或
-              <em>点击上传</em>
-            </div>
-            <div class="el-upload__tip" slot="tip">请上传报告文件</div>
-          </el-upload>
-        </el-form-item>
-
-        <el-form-item label="结论" prop="conclusion">
-          <el-input type="textarea" v-model="report.conclusion"></el-input>
-        </el-form-item>
-        <el-form-item>
-          <div class="btn btn-primary btn-info" @click="submitForm('report')">提交</div>
-          <div class="btn btn-primary" @click="resetForm('report')">重置</div>
-          <div class="btn btn-primary" @click="cancelCreate('report')">取消</div>
-        </el-form-item>
-      </el-form>
-    </div>
-  </div>
-</template>
-
-<script>
-export default {
-  name: "ReportCreate",
-  components: {},
-  data() {
-    return {
-      report: {
-        name: "",
-        abstract: {
-          target: "",
-          content: ""
-        },
-        file: [],
-        type: "",
-        conclusion: ""
-      },
-      rules: {
-        name: [
-          { required: true, message: "请输入报告名称", trigger: "blur" }
-          // { min: 3, max: 5, message: "长度在 3 到 5 个字符", trigger: "blur" }
-        ],
-        abstract: [
-          {
-            required: true,
-            message: "请输入摘要信息",
-            trigger: "change"
-          }
-        ],
-        type: [
-          { required: true, message: "请选择报告类型", trigger: "change" }
-        ],
-        file: [
-          { required: true, message: "请上传报告文件", trigger: "change" }
-        ],
-        conclusion: [
-          { required: true, message: "请输入报告结论", trigger: "blur" }
-        ]
-      }
-    };
-  },
-  mounted() {},
-  methods: {
-    submitForm(formName) {
-      this.$refs[formName].validate(valid => {
-        if (valid) {
-          console.log(this.report);
-          //提交 report
-        } else {
-          console.log("error submit!!");
-          return false;
-        }
-      });
-    },
-    resetForm(formName) {
-      this.$refs[formName].resetFields();
-      this.report.name = "";
-      this.report.abstract.target = "";
-      this.report.abstract.content = "";
-      this.report.file = [];
-      this.report.type = "";
-      this.report.conclusion = "";
-    },
-    cancelCreate() {
-      if (window.history.length <= 1) {
-        this.$router.push({ path: "/" });
-        return false;
-      } else {
-        this.$router.go(-1);
-      }
-    },
-    handleRemove(file, fileList) {
-      console.log(file, fileList);
-    },
-    handleExceed(files, fileList) {
-      this.$message.warning(
-        `当前限制选择 1 个文件,本次选择了 ${
-          files.length
-        } 个文件,共选择了 ${files.length + fileList.length} 个文件`
-      );
-    },
-    beforeRemove(file, fileList) {
-      return this.$confirm(`确定移除 ${file.name}?`);
-    },
-    beforeFileUpload() {}
-  }
-};
-</script>
-
-<style lang="less" scoped>
-.el-radio {
-  margin: 10px 20px 10px 0;
-}
-.el-form-item /deep/.el-tabs__content {
-  max-height: 120px !important;
-  overflow: auto;
-}
-.el-row {
-  margin-bottom: 10px;
-}
-</style>

+ 68 - 54
src/components/report/ReportList.vue

@@ -9,7 +9,7 @@
       </el-col>
     </el-row>-->
 
-    <el-table :showHeader="false" :data="reportList" style="width: 100%">
+    <el-table :showHeader="true" :data="reportList" style="width: 100%">
       <el-table-column prop="type" label="报告类型" title="报告类型">
         <template slot-scope="scope">
           <span class="badge">{{scope.row.type}}</span>
@@ -17,8 +17,9 @@
       </el-table-column>
       <el-table-column prop="file" sortable label="报告文件">
         <template slot-scope="scope">
-          <span v-if="scope.row.file.length==0">暂无文件</span>
-          <a :href="scope.row.file[0].url" v-if="scope.row.file.length>0" target="_blank"><i class="fa fa-file-text-o"></i> {{scope.row.file[0].name}}</a>
+          <span v-if="scope.row.content==null || scope.row.content==''">暂无文件</span>
+          <a :href="scope.row.file" v-if="scope.row.content!=null" target="_blank"><i
+            class="fa fa-file-text-o"></i> {{scope.row.content}}</a>
         </template>
       </el-table-column>
       <el-table-column align="right" label="操作">
@@ -31,75 +32,88 @@
   </div>
 </template>
 <script>
+
 export default {
-  name: "report-list",
-  data() {
+  name: 'report-list',
+  props: {
+    reports: {},
+    projectId: '',
+    taskId: ''
+  },
+  data () {
     return {
       editIndex: -1,
-      reportList: [
-        {
-          id:1,
-          type: "项目可行性报告",
-          file: []
-        },
-        {
-          id:2,
-          type: "项目测试方案(汇总)",
-          file: [{ name: "report2", url: "report2.excel" }]
-        },
-        {
-          id:3,
-          type: "项目测试报告(汇总)",
-          file: [{ name: "report3", url: "report3.excel" }]
-        },
-        {
-          id:4,
-          type: "项目缺陷报告(汇总)",
-          file: [{ name: "report4", url: "report4.excel" }]
-        },
-        {
-          id:5,
-          type: "项目用例报告(汇总)",
-          file: [{ name: "report5", url: "report5.excel" }]
-        }
-      ]
-    };
+      reportList: this.reports == null ? [] : this.reports,
+      pid: this.projectId,
+      tid: this.taskId,
+    }
   },
   methods: {
-    handleEdit(index, row) {
-      this.$router.push({ name: "Report" ,params:{reportId:row.id}});
+    handleEdit (index, row) {
+      if (this.tid == null) {
+        this.$router.push({
+          name: 'ProjectReport',
+          params: {
+            reportId: row.code,
+            projectId: this.pid
+          }
+        })
+      } else {
+        this.$router.push({
+          name: 'TaskReport',
+          params: {
+            reportId: row.code,
+            projectId: this.pid,
+            taskId: this.tid
+          }
+        })
+      }
+
       // this.editIndex = index;
     },
-    handleDelete(index, row) {
-      this.reportList.splice(index, 1);
+    handleDelete (index, row) {
+      this.reportList.splice(index, 1)
     },
-    cancelEdit(index, row) {
-      this.editIndex = -1;
+    cancelEdit (index, row) {
+      this.editIndex = -1
     },
-    handleRemove(file, fileList) {
-      console.log(file, fileList);
+    handleRemove (file, fileList) {
+      console.log(file, fileList)
     },
-    handleExceed(files, fileList) {
+    handleExceed (files, fileList) {
       this.$message.warning(
         `当前限制选择 1 个文件,本次选择了 ${
           files.length
-        } 个文件,共选择了 ${files.length + fileList.length} 个文件`
-      );
+          } 个文件,共选择了 ${files.length + fileList.length} 个文件`
+      )
+    },
+    beforeRemove (file, fileList) {
+      return this.$confirm(`确定移除 ${file.name}?`)
+    },
+    beforeFileUpload () {
+    }
+  },
+  watch: {
+    reports () {
+      this.reportList = this.reports
     },
-    beforeRemove(file, fileList) {
-      return this.$confirm(`确定移除 ${file.name}?`);
+    projectId () {
+      this.pid = this.projectId
     },
-    beforeFileUpload() {}
+    taskId () {
+      this.tid = this.taskId
+    }
   }
-};
+}
 </script>
 
 
 <style lang="less" scoped>
-.report-container {
-  margin: 0 30px;
-}
-.el-row {
-  margin-bottom: 20px;
-}
+  .report-container {
+    margin: 0 30px;
+  }
+
+  .el-row {
+    margin-bottom: 20px;
+  }
 </style>

+ 300 - 0
src/components/report/TaskReport.vue

@@ -0,0 +1,300 @@
+<template>
+  <div class="create-container">
+    <div class="create-body" v-loading="loading">
+      <el-form :model="report" :rules="rules" ref="report" label-width="12%" class="demo-report">
+        <el-form-item label="报告名称" prop="name">
+          <el-input size="small" v-if="isModifyMode" v-model="report.name"></el-input>
+          <span v-if="!isModifyMode">{{report.name}}</span>
+        </el-form-item>
+        <el-form-item label="报告类型" prop="type">
+          <el-radio-group v-if="isModifyMode" v-model="report.type">
+            <span v-for="(item,index) in reportType" :key="index">
+              <el-radio :label="item" name="type">{{item}}</el-radio>
+            </span>
+          </el-radio-group>
+          <span v-if="!isModifyMode" class="badge">{{report.type}}</span>
+        </el-form-item>
+        <el-form-item label="测试对象" prop="target">
+          <el-input autosize v-if="isModifyMode" type="textarea" v-model="report.target"></el-input>
+          <span v-if="!isModifyMode">{{report.target}}</span>
+        </el-form-item>
+        <el-form-item label="测试内容" prop="content">
+          <el-input autosize v-if="isModifyMode" type="textarea" v-model="report.content"></el-input>
+          <span v-if="!isModifyMode">{{report.content}}</span>
+        </el-form-item>
+        <el-form-item prop="file" label="报告文件">
+          <el-upload
+            style="width: 400px"
+            v-if="isModifyMode"
+            drag
+            class="upload-demo"
+            action=""
+            :on-remove="handleRemove"
+            :before-remove="beforeRemove"
+            multiple
+            :limit="1"
+            :on-exceed="handleExceed"
+            :before-upload="beforeFileUpload"
+            :file-list="report.file"
+            :http-request="uploadReportFile"
+          >
+            <i class="el-icon-upload"></i>
+            <div class="el-upload__text">
+              将文件拖到此处,或
+              <em>点击上传</em>
+            </div>
+            <div class="el-upload__tip" slot="tip">请上传报告文件</div>
+          </el-upload>
+          <div v-if="!isModifyMode">
+            <span v-if="report.fileUrl==null">暂无文件</span>
+            <a :href="report.fileUrl" v-if="report.fileUrl!=null">
+              <el-link :underline="false" type="primary"><i class="el-icon-document"></i>下载文档</el-link>
+            </a>
+          </div>
+        </el-form-item>
+
+        <el-form-item label="结论" prop="conclusion">
+          <el-input autosize v-if="isModifyMode" type="textarea" v-model="report.conclusion"></el-input>
+          <span v-if="!isModifyMode">{{report.conclusion}}</span>
+        </el-form-item>
+        <el-form-item v-if="!isModifyMode">
+          <div class="btn btn-medium btn-info" @click="modifyForm()">修改</div>
+          <div class="btn btn-medium" @click="back()">返回</div>
+        </el-form-item>
+        <el-form-item v-if="isModifyMode">
+          <div class="btn btn-medium btn-info" @click="submitForm('report')">确认修改</div>
+          <div class="btn btn-medium" @click="resetForm('report')">重置</div>
+          <div class="btn btn-medium" @click="cancelCreate('report')">取消</div>
+        </el-form-item>
+      </el-form>
+    </div>
+  </div>
+</template>
+
+<script>
+import Http from '@/js/http.js'
+import Apis from '@/js/api.js'
+import {notify} from '@/constants/index'
+import {getAllReportTypes, storageGet} from '@/js/index'
+
+export default {
+  name: 'TaskReport',
+  components: {},
+  data () {
+    return {
+      user: {},
+      loading: false,
+      reportId: 0,
+      projectId: '',
+      taskId: '',
+      isModifyMode: false,
+      reportType: [],
+      report: {
+        name: '',
+        type: '',
+        description: '',
+        target: '',
+        content: '',
+        file: [],
+        fileUrl: '',
+        conclusion: ''
+      },
+      rules: {
+        name: [
+          {required: true, message: '任务名称不可为空', trigger: 'blur'},
+          {min: 5, max: 50, message: '报告名称长度在 5 到 50 个字符', trigger: 'blur'}
+        ],
+        type: [
+          {required: true, message: '报告类型不可为空'},
+        ],
+        target: [
+          {required: true, message: '测试对象不可为空', trigger: 'blur'}
+        ],
+        content: [
+          {required: true, message: '测试内容不可为空', trigger: 'blur'}
+        ],
+        conclusion: [
+          {required: true, message: '结论不可为空', trigger: 'blur'}
+        ]
+      }
+    }
+  },
+  mounted () {
+    this.$nextTick(() => {
+      this.init()
+    })
+  },
+  methods: {
+    init () {
+      this.reportId = this.$route.params.reportId
+      this.projectId = this.$route.params.projectId
+      this.taskId = this.$route.params.taskId
+      this.setReportType()
+      this.setUserInfo()
+      this.loadData()
+    },
+    modifyForm () {
+      this.isModifyMode = true
+    },
+    submitForm (formName) {
+      this.$refs['report'].validate(valid => {
+        if (valid) {
+          this.isModifyMode = false
+          this.showLoading()
+          const newReport = {
+            name: this.report.name,
+            scope: this.taskId == null ? 0 : 1,
+            type: this.report.type,
+            dependencyCode: this.taskId == null ? this.projectId : this.taskId,
+            target: this.report.target,
+            content: this.report.content,
+            file: this.report.fileUrl,
+            conclusion: this.report.conclusion
+          }
+          console.log(newReport)
+          Http.put(Apis.REPORT.UPDATE_TASK_REPORT.replace('{projectId}', this.projectId).replace('{taskId}', this.taskId).replace('{reportId}', this.reportId), newReport).then((res) => {
+            console.log(res)
+            this.hideLoading()
+            this.isModifyMode = false
+          }).catch((error) => {
+            this.hideLoading()
+            notify('error', error.data)
+          })
+          //提交 report
+        } else {
+          notify('error', '表单填写有误')
+          return false
+        }
+      })
+    },
+    resetForm (formName) {
+      this.$refs[formName].resetFields()
+      this.report.name = ''
+      this.report.target = ''
+      this.report.content = ''
+      this.report.file = ''
+      this.report.type = ''
+      this.report.conclusion = ''
+    },
+    cancelCreate () {
+      this.isModifyMode = false
+      //请求 report
+    },
+    handleRemove (file, fileList) {
+      console.log(file, fileList)
+    },
+    handleExceed (files, fileList) {
+      this.$message.warning(
+        `当前限制选择 1 个文件,本次选择了 ${
+          files.length
+          } 个文件,共选择了 ${files.length + fileList.length} 个文件`
+      )
+    },
+    beforeRemove (file, fileList) {
+      //return this.$confirm(`确定移除 ${file.name}?`)
+    },
+    beforeFileUpload (file) {
+      console.log(file)
+      const isPDF = file.type === 'application/pdf'
+      const isDOC = file.type === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
+      const isEXCEL = file.type === 'application/vnd.ms-excel'
+      const isXLS = file.type === 'application/x-xls'
+      const isTXT = file.type === 'text/plain'
+      const isXLSX = file.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
+      //console.log(file)
+      if (!(isDOC || isEXCEL || isPDF || isTXT || isXLS || isXLSX)) {
+        this.$message.error('上传文件只能是 PDF 、 DOC 、DOCX 、XLS、TXT、XLSX 格式!')
+      }
+      return isDOC || isEXCEL || isPDF || isTXT || isXLS || isXLSX
+    },
+    back () {
+      this.$router.push({
+        name: 'Task',
+        params: {
+          projectId: this.projectId,
+          taskId: this.taskId
+        }
+      })
+    },
+    loadData () {
+      //pro1564487183259
+      //pro1564487183259_task1564487274060
+      //pro1564487183259pro1564487183259_task1564487274060_rep1564488510500
+      this.showLoading()
+      Http.get(Apis.REPORT.GET_TASK_REPORT.replace('{projectId}', this.projectId).replace('{taskId}', this.taskId).replace('{reportId}', this.reportId)).then((res) => {
+        console.log(res)
+        this.report.name = res.crowdReportVO.name
+        this.report.crowdTestTaskId = res.crowdReportVO.crowdTestTaskId
+        this.report.scope = res.crowdReportVO.scope
+        this.report.type = res.crowdReportVO.type
+        this.report.description = res.crowdReportVO.description
+        this.report.content = res.crowdReportVO.content
+        this.report.fileUrl = res.crowdReportVO.file
+        this.report.conclusion = res.crowdReportVO.conclusion
+        this.report.target = res.crowdReportVO.target
+        this.hideLoading()
+      }).catch((error) => {
+        this.hideLoading()
+        notify('error', '打开报告失败:' + error.data)
+      })
+    },
+    uploadReportFile (param) {
+      this.showLoading()
+      const formData = new FormData()
+      let config = {
+        //添加请求头
+        headers: {'Content-Type': 'multipart/form-data'},
+      }
+      formData.append('file', param.file)
+      Http.upload(Apis.FILE.UPLOAD_REPORT_FILE.replace('{userId}', this.user.userVO.id), formData, config).then((res) => {
+        console.log('上传成功')
+        this.report.fileUrl = res.data
+        console.log(res)
+        this.hideLoading()
+      }).catch((error) => {
+        this.hideLoading()
+        notify('error', '文件上传失败:' + error.data)
+      })
+    },
+    setReportType () {
+      getAllReportTypes().then((res) => {
+        this.reportType = res
+      }).catch((error) => {
+        notify('error', '加载报告类型失败')
+      })
+    },
+    setUserInfo () {
+      this.user = storageGet('user')
+    },
+    updateReportSuccess () {
+
+    },
+    showLoading () {
+      this.loading = true
+    },
+    hideLoading () {
+      this.loading = false
+    }
+  },
+  watch: {
+    reportType (val) {
+      this.reportType = val
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+  .el-radio {
+    margin: 10px 20px 10px 0;
+  }
+
+  .el-form-item /deep/ .el-tabs__content {
+    max-height: 120px !important;
+    overflow: auto;
+  }
+
+  .el-row {
+    margin-bottom: 10px;
+  }
+</style>

+ 261 - 0
src/components/report/TaskReportCreate.vue

@@ -0,0 +1,261 @@
+<template>
+  <div class="create-container" v-loading="loading">
+    <div class="title h1">创建报告</div>
+    <div class="create-body">
+      <el-form :model="report" :rules="rules" ref="report" label-width="12%" class="demo-report">
+        <el-form-item label="报告名称" prop="name">
+          <el-input size="small" v-model="report.name"></el-input>
+        </el-form-item>
+        <el-form-item label="报告类型" prop="type">
+          <el-radio-group v-model="report.type">
+            <span v-for="(item,index) in reportType" :key="index">
+              <el-radio :label="item" name="type">{{item}}</el-radio>
+            </span>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="测试对象" prop="target">
+          <el-input autosize style="width: 400px" type="textarea" v-model="report.target"></el-input>
+        </el-form-item>
+        <el-form-item label="测试内容" prop="content">
+          <el-input autosize style="width: 400px" type="textarea" v-model="report.content"></el-input>
+        </el-form-item>
+        <el-form-item prop="file" label="报告文件">
+          <el-upload
+            style="width: 400px"
+            drag
+            class="upload-demo"
+            action="https://jsonplaceholder.typicode.com/posts/"
+            :on-remove="handleRemove"
+            :before-remove="beforeRemove"
+            multiple
+            :limit="1"
+            :on-exceed="handleExceed"
+            :before-upload="beforeFileUpload"
+            :file-list="report.file"
+            :http-request="uploadReportFile"
+          >
+            <i class="el-icon-upload"></i>
+            <div class="el-upload__text">
+              将文件拖到此处,或
+              <em>点击上传</em>
+            </div>
+            <div class="el-upload__tip" slot="tip">请上传报告文件</div>
+          </el-upload>
+        </el-form-item>
+
+        <el-form-item label="结论" prop="conclusion">
+          <el-input autosize style="width: 400px" type="textarea" v-model="report.conclusion"></el-input>
+        </el-form-item>
+        <el-form-item>
+          <div class="btn btn-medium btn-info" @click="submitForm('report')">提交</div>
+          <div class="btn btn-medium" @click="resetForm('report')">重置</div>
+          <div class="btn btn-medium" @click="cancelCreate('report')">取消</div>
+        </el-form-item>
+      </el-form>
+    </div>
+  </div>
+</template>
+
+<script>
+import Http from '@/js/http.js'
+import Apis from '@/js/api.js'
+import {notify} from '@/constants/index'
+import {getAllReportTypes, storageGet} from '@/js/index'
+
+export default {
+  name: 'TaskReportCreate',
+  components: {},
+  data () {
+    return {
+      user: {},
+      loading: false,
+      reportType: [],
+      scope: 0,
+      projectId: '',
+      taskId: '',
+      dependencyCode: '',
+      report: {
+        name: '',
+        target: '',
+        content: '',
+        file: [],
+        fileUrl: '',
+        type: '',
+        conclusion: ''
+      },
+      rules: {
+        name: [
+          {required: true, message: '任务名称不可为空', trigger: 'blur'},
+          {min: 5, max: 50, message: '报告名称长度在 5 到 50 个字符', trigger: 'blur'}
+        ],
+        type: [
+          {required: true, message: '报告类型不可为空'},
+        ],
+        target: [
+          {required: true, message: '测试对象不可为空', trigger: 'blur'}
+        ],
+        content: [
+          {required: true, message: '测试内容不可为空', trigger: 'blur'}
+        ],
+        conclusion: [
+          {required: true, message: '结论不可为空', trigger: 'blur'}
+        ]
+      }
+    }
+  },
+  mounted () {
+    this.$nextTick(() => {
+      this.init()
+    })
+  },
+  methods: {
+    init () {
+      this.scope = this.$route.params.scope
+      this.dependencyCode = this.$route.params.dependencyCode
+      this.projectId = this.$route.params.projectId
+      this.taskId = this.$route.params.taskId
+      this.setUserInfo()
+      this.setReportType()
+    },
+    submitForm (formName) {
+      this.$refs['report'].validate(valid => {
+        if (valid) {
+          this.showLoading()
+          const newReport = {
+            name: this.report.name,
+            scope: this.scope,
+            type: this.report.type,
+            dependencyCode: this.dependencyCode,
+            target: this.report.target,
+            content: this.report.content,
+            file: this.report.fileUrl,
+            conclusion: this.report.conclusion
+          }
+          console.log(newReport)
+          Http.post(Apis.REPORT.CREATE_TASK_REPORT.replace('{projectId}', this.projectId).replace('{taskId}', this.taskId), newReport).then((res) => {
+            this.hideLoading()
+            this.createReportSuccess(res.crowdReportVO.code)
+          }).catch((error) => {
+            this.hideLoading()
+            notify('error', '报告创建失败:' + error.data)
+          })
+        } else {
+          notify('error', '表单填写有误')
+          return false
+        }
+      })
+    },
+    resetForm (formName) {
+      this.$refs[formName].resetFields()
+      this.report.name = ''
+      this.report.abstract.target = ''
+      this.report.abstract.content = ''
+      this.report.file = []
+      this.report.type = ''
+      this.report.conclusion = ''
+    },
+    cancelCreate () {
+      if (window.history.length <= 1) {
+        this.$router.push({path: '/'})
+        return false
+      } else {
+        this.$router.go(-1)
+      }
+    },
+    handleRemove (file, fileList) {
+      console.log(file, fileList)
+    },
+    handleExceed (files, fileList) {
+      this.$message.warning(
+        `当前限制选择 1 个文件,本次选择了 ${
+          files.length
+          } 个文件,共选择了 ${files.length + fileList.length} 个文件`
+      )
+    },
+    beforeRemove (file, fileList) {
+      //return this.$confirm(`确定移除 ${file.name}?`)
+    },
+    beforeFileUpload (file) {
+      console.log(file)
+      const isPDF = file.type === 'application/pdf'
+      const isDOC = file.type === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
+      const isEXCEL = file.type === 'application/vnd.ms-excel'
+      const isXLS = file.type === 'application/x-xls'
+      const isTXT = file.type === 'text/plain'
+      const isXLSX = file.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
+      //console.log(file)
+      if (!(isDOC || isEXCEL || isPDF || isTXT || isXLS || isXLSX)) {
+        this.$message.error('上传文件只能是 PDF 、 DOC 、DOCX 、XLS、TXT、XLSX 格式!')
+      }
+      return isDOC || isEXCEL || isPDF || isTXT || isXLS || isXLSX
+    },
+    loadData () {
+    },
+    uploadReportFile (param) {
+      const formData = new FormData()
+      let config = {
+        //添加请求头
+        headers: {'Content-Type': 'multipart/form-data'},
+      }
+      formData.append('file', param.file)
+      Http.upload(Apis.FILE.UPLOAD_REPORT_FILE.replace('{userId}', this.user.userVO.id), formData, config).then((res) => {
+        console.log('上传成功')
+        this.report.fileUrl = res.data
+        console.log(res)
+      })
+    },
+    setReportType () {
+      this.reportType = getAllReportTypes().then((res) => {
+        this.reportType = res
+      }).catch((error) => {
+        notify('error', '获取报告类型列表失败')
+      })
+    },
+    setUserInfo () {
+      this.user = storageGet('user')
+    },
+    createReportSuccess (reportId) {
+      this.$alert('报告创建成功', '创建成功', {
+        confirmButtonText: '确定',
+        callback: action => {
+          this.$router.push({
+            name: 'TaskReport',
+            params: {reportId: reportId, projectId: this.projectId, taskId: this.taskId}
+          })
+        }
+      })
+    },
+    showLoading () {
+      this.loading = true
+    },
+    hideLoading () {
+      this.loading = false
+    }
+  },
+  watch: {
+    reportType (val) {
+      this.reportType = val
+    }
+  }
+
+}
+</script>
+
+<style lang="less" scoped>
+  .el-radio {
+    margin: 10px 20px 10px 0;
+  }
+
+  .el-form-item /deep/ .el-tabs__content {
+    max-height: 120px !important;
+    overflow: auto;
+  }
+
+  .el-row {
+    margin-bottom: 10px;
+  }
+
+  .el-input {
+    width: 400px;
+  }
+</style>

+ 614 - 187
src/components/task/Task.vue

@@ -1,34 +1,42 @@
 <template>
-  <div class="create-container">
+  <div class="create-container" v-loading="loading">
     <div class="title h1" v-if="!isModifyMode">任务</div>
     <div class="create-body">
       <div class="title h2" v-if="!isModifyMode">基本信息</div>
       <el-form :model="task" :rules="rules" ref="task" label-width="12%" class="demo-task">
-        <el-form-item label="任务名称" prop="name">
-          <el-input v-if="isModifyMode" v-model="task.name"></el-input>
-          <span v-if="!isModifyMode">{{task.name}}</span>
+        <el-form-item label="任务名称" prop="title">
+          <el-input size="small" v-if="isModifyMode" v-model="task.title"></el-input>
+          <span v-if="!isModifyMode">{{task.title}}</span>
         </el-form-item>
         <el-form-item label="任务描述" prop="desc">
-          <el-input v-if="isModifyMode" type="textarea" v-model="task.desc"></el-input>
-          <span v-if="!isModifyMode">{{task.desc}}</span>
+          <el-input autosize v-if="isModifyMode" type="textarea" v-model="task.description"></el-input>
+          <span v-if="!isModifyMode">{{task.description}}</span>
         </el-form-item>
-        <el-form-item label="业务类型" prop="type">
-          <el-radio-group v-if="isModifyMode" v-model="task.type">
-            <el-radio label="接口测试" name="type"></el-radio>
-            <el-radio label="安全漏洞扫描" name="type"></el-radio>
-            <el-radio label="风险评估服务" name="type"></el-radio>
-            <el-radio label="源代码安全审计服务" name="type"></el-radio>
-            <el-radio label="功能测试服务" name="type"></el-radio>
-            <el-radio label="性能测试" name="type"></el-radio>
-            <el-radio label="功能和易用性测试" name="type"></el-radio>
+        <el-form-item label="任务报价" prop="quotePrice">
+          <el-input size="small" type="number" v-if="isModifyMode" v-model="task.quotePrice">
+            <template slot="append">¥</template>
+          </el-input>
+          <span v-if="!isModifyMode">{{task.quotePrice}}¥</span>
+        </el-form-item>
+        <!--<el-form-item type="number" label="任务定价" prop="fixedPrice">-->
+        <!--<el-input v-if="isModifyMode" v-model="task.fixedPrice">-->
+        <!--<template slot="append">¥</template>-->
+        <!--</el-input>-->
+        <!--<span v-if="!isModifyMode">{{task.fixedPrice}}</span>-->
+        <!--</el-form-item>-->
+        <el-form-item label="业务类型" prop="serviceType">
+          <el-radio-group v-if="isModifyMode" v-model="task.serviceType">
+            <span v-for="(item,index) in serviceType" :key="index">
+              <el-radio :label="item" name="type">{{item}}</el-radio>
+            </span>
           </el-radio-group>
-          <span class="badge" v-if="!isModifyMode">{{task.type}}</span>
+          <span class="badge" v-if="!isModifyMode">{{task.serviceType}}</span>
         </el-form-item>
         <el-form-item label="任务可见性" prop="resource">
           <div v-if="!isModifyMode">
-            <div v-if="task.resource=='区域'">{{updateLocation(task.location)}}</div>
-            <div v-if="task.resource=='定向'">{{task.institution}}</div>
-            <div v-if="task.resource=='广场'">{{task.resource}}</div>
+            <!--<div v-if="task.resource=='1'">{{updateLocation(task.location)}}</div>-->
+            <div v-if="task.resource=='0'">{{task.institution}}</div>
+            <div v-if="task.resource=='2'">{{resourceType[task.resource]}}</div>
           </div>
           <el-tabs
             :tab-position="tabPosition"
@@ -36,31 +44,63 @@
             style="max-height: 200px;"
             v-if="isModifyMode"
           >
-            <el-tab-pane label="定向" name="定向">
+            <el-tab-pane :label="resourceType[0]" name="0">
               <el-radio-group v-model="task.institution">
                 <el-radio
                   :label="item"
                   name="type"
                   v-for="item,index in institutionArray"
                   :key="index"
-                ></el-radio>
+                >{{item.name}}
+                </el-radio>
               </el-radio-group>
             </el-tab-pane>
-            <el-tab-pane label="区域" name="区域">
-              <provincecity
-                ref="addFormProvince"
-                @selectChange="locationChange"
-                :provinceCode="task.location.provinceCode"
-                :cityCode="task.location.cityCode"
-              ></provincecity>
-            </el-tab-pane>
-            <el-tab-pane label="广场" name="广场"></el-tab-pane>
+            <!--<el-tab-pane :label="resourceType[1]" name="1">-->
+            <!--<provincecity-->
+            <!--ref="addFormProvince"-->
+            <!--@selectChange="locationChange"-->
+            <!--:provinceCode="task.location == null ||task.location.provinceCode==null?'3200':task.location.provinceCode"-->
+            <!--:cityCode="task.location == null ||task.location.cityCode==null?'3201':task.location.cityCode"-->
+            <!--&gt;</provincecity>-->
+            <!--</el-tab-pane>-->
+            <el-tab-pane :label="resourceType[2]" name="2"></el-tab-pane>
           </el-tabs>
         </el-form-item>
+        <el-form-item label="需求文档" prop="doc">
+          <el-upload
+            style="width: 400px"
+            v-if="isModifyMode"
+            drag
+            class="upload-demo"
+            action=""
+            :on-remove="handleRemove"
+            :before-remove="beforeRemove"
+            :limit="1"
+            :on-exceed="handleExceed"
 
+            :http-request="uploadRequireDoc"
+            :file-list="task.doc"
+          >
+            <i class="el-icon-upload"></i>
+            <div class="el-upload__text">
+              将文件拖到此处,或
+              <em>点击上传</em>
+            </div>
+          </el-upload>
+          <span v-if="!isModifyMode">
+              <span v-if="task.requireDocUrl == null || task.requireDocUrl == ''">
+                <i class="el-icon-document"></i>暂无文件
+              </span>
+              <span v-if="task.requireDocUrl != null && task.requireDocUrl != ''">
+                <a :href="task.requireDocUrl"><el-link :underline="false" type="primary"><i
+                  class="el-icon-document"></i>下载文档</el-link></a>
+              </span>
+            </span>
+        </el-form-item>
         <el-form-item label="任务截止时间" prop="datetime">
           <div class="block" v-if="isModifyMode">
             <el-date-picker
+              size="small"
               v-model="task.datetime"
               type="datetime"
               placeholder="选择截止时间"
@@ -68,223 +108,610 @@
               :picker-options="pickerOptions"
             ></el-date-picker>
           </div>
-          <span v-if="!isModifyMode">{{new Date(task.datetime)}}</span>
+          <span v-if="!isModifyMode">{{reformDate(new Date(task.datetime))}}</span>
         </el-form-item>
         <el-form-item v-if="isModifyMode">
-          <div class="btn btn-medium btn-info" @click="submitForm('task')">确认修改</div>
-          <div class="btn btn-medium" @click="resetForm('task')">重置</div>
-          <div class="btn btn-medium" @click="cancelMode('task')">取消</div>
+          <div class="btn btn-small btn-info" @click="updateTask()">确认修改</div>
+          <div class="btn btn-small" @click="resetForm()">重置</div>
+          <div class="btn btn-small" @click="cancelMode()">取消</div>
         </el-form-item>
         <el-form-item v-if="!isModifyMode">
-          <div class="btn btn-medium btn-info" @click="applyTask()">接收任务</div>
-          <div class="btn btn-medium btn-info" @click="modifyForm()">修改</div>
-          <div class="btn btn-medium btn-info" @click="createReport()">上传报告</div>
-          <div class="btn btn-medium" @click="toProject()">前往项目</div>
+          <el-button size="mini" @click="toProject()">项目详情</el-button>
+          <el-popover
+            placement="top-start"
+            title="确认结束?"
+            width="200"
+            trigger="hover"
+            content="测评机构已提交结束申请,请确认是否结束该任务">
+            <el-button v-if="taskOperationControl.confirmFinish" type="success" size="mini" slot="reference"
+                       @click="endTask()">确认结束
+            </el-button>
+          </el-popover>
+
+          <el-popover
+            placement="top-start"
+            title="确认提交?"
+            width="200"
+            trigger="hover"
+            content="提交任务后不可更改,等待区域管理员验收">
+            <el-button v-if="taskOperationControl.finish" type="primary" size="mini" slot="reference"
+                       @click="submitTaskRequest()">提交任务
+            </el-button>
+          </el-popover>
+
+          <el-popover
+            placement="top-start"
+            title="确认拒绝?"
+            width="200"
+            trigger="hover"
+            content="拒绝后不可再接收此任务,且该任务对您不可见">
+            <el-button v-if="taskOperationControl.reject" type="danger" size="mini" slot="reference"
+                       @click="rejectTask()">拒绝任务
+            </el-button>
+          </el-popover>
+
+          <el-popover
+            placement="top-start"
+            title="确认接收?"
+            width="200"
+            trigger="hover"
+            content="接收任务后请认真完成!">
+            <el-button v-if="taskOperationControl.receive" type="primary" size="mini" slot="reference"
+                       @click="receiveTask()">接收任务
+            </el-button>
+          </el-popover>
+
+
+          <el-button v-if="taskOperationControl.update" type="primary" size="mini" @click="modifyForm()">修改任务
+          </el-button>
+          <el-button v-if="taskOperationControl.uploadReport" type="primary" size="mini" @click="toCreateReport()">
+            上传报告
+          </el-button>
+          <!--<div class="btn btn-small btn-info"-->
+          <!--v-if="taskOperationControl.confirmFinish"-->
+          <!--@click="endTask()">确认结束-->
+          <!--</div>-->
+          <!--<div class="btn btn-small btn-info" v-if="!taskOperationControl.finish" @click="submitTaskRequest()">提交任务-->
+          <!--</div>-->
+          <!--<div class="btn btn-small btn-info" v-if="!taskOperationControl.receive" @click="receiveTask()">接收任务</div>-->
+          <!--<div class="btn btn-small btn-danger" v-if="!taskOperationControl.reject" @click="rejectTask()">拒绝任务</div>-->
+          <!--<div class="btn btn-small btn-info" v-if="taskOperationControl.update" @click="modifyForm()">修改任务</div>-->
+          <!--<div class="btn btn-small btn-info" v-if="!taskOperationControl.uploadReport" @click="toCreateReport()">上传报告-->
+          <!--</div>-->
+
         </el-form-item>
       </el-form>
     </div>
     <div class="create-body" v-if="!isModifyMode">
       <div class="title h2">报告列表</div>
-      <report-list/>
+      <report-list v-bind:reports="reportList" v-bind:taskId="taskId" v-bind:projectId="projectId"/>
     </div>
   </div>
 </template>
 
 <script>
-import Enum from "@/constants/enum/index";
-import provincecity from "@/components/commons/ProvinceCity";
-import provinceCityJSON from "@/constants/provinceCity.json";
-import ReportList from "@/components/report/ReportList";
+import ResourceType from '@/constants/enum/resource-type.js'
+import provincecity from '@/components/commons/ProvinceCity'
+import ReportList from '@/components/report/ReportList'
+import Http from '@/js/http.js'
+import Apis from '@/js/api.js'
+import {notify} from '@/constants/index'
+import {
+  ensureEndTask,
+  getAllAgencies,
+  getAllServiceTypes,
+  getFormalTimeFromDate,
+  getProvinceCodeByProvinceName,
+  getProvinceNameByProvinceCode,
+  getTask,
+  receiveTaskRequest,
+  rejectTask,
+  storageGet,
+  submitTaskRequest,
+  updateTask
+} from '@/js/index'
+
 export default {
-  name: "Task",
+  name: 'Task',
   components: {
     provincecity,
     ReportList
   },
-  data() {
+  data () {
     return {
-      projectId: 0,
-      taskId: 0,
+      user: {},
+      rolesPermissions: {},
+      loading: false,
       isModifyMode: false,
-      institutionArray: Enum.institution,
-      tabPosition: "top",
+      institutionArray: [],
+      tabPosition: 'top',
+      resourceType: ResourceType,
+      serviceType: [],
+      taskId: '',
+      projectId: '',
+      taskOperationControl: {
+        confirmFinish: false,
+        finish: false,
+        receive: false,
+        update: false,
+        uploadReport: false
+      },
       task: {
-        name: "任务名称xxxxs",
-        desc: "任务描述文字",
-        type: "安全漏洞扫描",
-        resource: "区域", //如果是广场不用管Location和institution ,定向看institution,区域看location
-        location: { provinceCode: "3200", cityCode: "3201" },
-        institution: "",
-        datetime: new Date("2018-11-11 23:11:11")
+        agencyId: '',
+        status: '',
+        name: '',
+        desc: '',
+        serviceType: '',
+        resource: '',
+        location: {},
+        institution: {},
+        datetime: '',
+        quotePrice: '',
+        fixedPrice: '',
+        doc: [],
+        requireDocUrl: '123.doc'
       },
+      reportList: [],
       pickerOptions: {
         shortcuts: [
           {
-            text: "今天",
-            onClick(picker) {
-              picker.$emit("pick", new Date());
+            text: '今天',
+            onClick (picker) {
+              picker.$emit('pick', new Date())
             }
           },
           {
-            text: "昨天",
-            onClick(picker) {
-              const date = new Date();
-              date.setTime(date.getTime() - 3600 * 1000 * 24);
-              picker.$emit("pick", date);
+            text: '昨天',
+            onClick (picker) {
+              const date = new Date()
+              date.setTime(date.getTime() - 3600 * 1000 * 24)
+              picker.$emit('pick', date)
             }
           },
           {
-            text: "一周前",
-            onClick(picker) {
-              const date = new Date();
-              date.setTime(date.getTime() - 3600 * 1000 * 24 * 7);
-              picker.$emit("pick", date);
+            text: '一周前',
+            onClick (picker) {
+              const date = new Date()
+              date.setTime(date.getTime() - 3600 * 1000 * 24 * 7)
+              picker.$emit('pick', date)
             }
           }
         ]
       },
       rules: {
-        name: [
-          { required: true, message: "请输入任务名称", trigger: "blur" }
-          // { min: 3, max: 5, message: "长度在 3 到 5 个字符", trigger: "blur" }
+        title: [
+          {required: true, message: '请输入任务名称', trigger: 'blur'},
+          {min: 5, max: 50, message: '任务名称长度在 5 到 50 个字符', trigger: 'blur'}
+        ],
+        type: [
+          {required: true, message: '业务类型不可为空'},
         ],
-        datetime: [
+        desc: [{required: false, message: '请填写描述', trigger: 'blur'}],
+        //price: [{required: true, message: '请填写价格', trigger: 'blur'}],
+        quotePrice: [
+          {required: true, message: '预算不可为空', trigger: 'blur'},
           {
-            type: "date",
-            required: true,
-            message: "请选择截止时间",
-            trigger: "change"
-          }
+            validator: (rule, value, callback) => {
+              if (value <= 0) {
+                callback(new Error('请输入大于0的数'))
+              } else {
+                callback()
+              }
+            }, trigger: 'blur'
+          },
         ],
-        type: [
-          { required: true, message: "请选择业务类型", trigger: "change" }
+        resource: [
+          {required: true},
+          {
+            validator: (rule, value, callback) => {
+              if (value == 0 && this.task.institution.id == null) {
+                callback(new Error('定向发布至少要选择一个测评机构'))
+              } else {
+                callback()
+              }
+            }, trigger: 'change'
+          },
         ],
-        desc: [{ required: true, message: "请填写任务描述", trigger: "blur" }]
+        datetime: [{required: true, message: '截止时间不可为空', trigger: 'blur'}],
       }
-    };
+    }
   },
   watch: {
-    "task.institution"() {
-      if (this.task.institution) {
-        this.$refs.addFormProvince.resetProviceCity();
-        this.task.location = { provinceCode: "", cityCode: "" };
-      }
+    institutionArray (val) {
+      this.institutionArray = val
     },
-    "task.location"() {
-      if (this.task.location.provinceCode || this.task.location.cityCode) {
-        this.task.institution = "";
-      }
-    },
-    "task.resource"() {
-      if (this.task.resource == "广场") {
-        this.$refs.addFormProvince.resetProviceCity();
-        this.task.institution = "";
-        this.task.location = { provinceCode: "", cityCode: "" };
-      }
+    serviceType (val) {
+      this.serviceType = val
     },
+    // 'task.institution' () {
+    //   if (this.task.institution) {
+    //     //this.$refs.addFormProvince.resetProviceCity()
+    //     this.task.location = {provinceCode: '', cityCode: ''}
+    //   }
+    // },
+    // 'task.location' () {
+    //   if (this.task.location.provinceCode || this.task.location.cityCode) {
+    //     this.task.institution = ''
+    //   }
+    // },
+    // 'task.resource' () {
+    //   if (this.task.resource == '广场') {
+    //     this.$refs.addFormProvince.resetProviceCity()
+    //     this.task.institution = ''
+    //     this.task.location = {provinceCode: '', cityCode: ''}
+    //   }
+    // },
     deep: true
   },
-  mounted() {
+  mounted () {
     this.$nextTick(() => {
-      this.init();
-    });
+      this.init()
+    })
   },
   methods: {
-    init() {
-      this.taskId = +this.$route.params.taskId;
-      this.projectId = +this.$route.params.projectId;
-    },
-    updateLocation(location) {
-      var provinceName = "";
-      var cityName = "";
-      for (var item of provinceCityJSON.provinces) {
-        if (item.code === location.provinceCode) {
-          provinceName = item.name;
-          for (var city of item.cities) {
-            if (city.code === location.cityCode) {
-              cityName = city.name;
-              break;
-            }
-          }
-        }
-      }
-      return provinceName + " / " + cityName;
+    init () {
+      this.taskId = this.$route.params.taskId
+      this.projectId = this.$route.params.projectId
+      this.setUserInfo()
+      this.setServiceType()
+      //this.loadData(this.projectId, this.taskId)
+      this.getTaskDetail()
+      this.setInstitutions()
+    },
+
+    //跳转至项目详情页面
+    toProject () {
+      this.$router.push({
+        name: 'Project',
+        params: {projectId: this.projectId}
+      })
+    },
+    //切换至可编辑页面
+    modifyForm () {
+      this.isModifyMode = true
+    },
+    //切换至不可编辑页面
+    cancelMode () {
+      this.isModifyMode = false
+    },
+    //重置表单
+    resetForm () {
+      this.task.name = ''
+      this.task.desc = ''
+      this.task.quotePrice = ''
+      this.task.fixedPrice = ''
+      this.task.type = ''
+      this.task.resource = '2' //如果是广场不用管Location和institution ,定向看institution,区域看location
+      this.task.location = {provinceCode: '', cityCode: ''}
+      this.task.institution = ''
+      this.task.datetime = ''
+    },
+    //显示页面加载画面
+    showLoading () {
+      this.loading = true
+    },
+    //隐藏页面加载画面
+    hideLoading () {
+      this.loading = false
+    },
+    //加载用户信息
+    setUserInfo () {
+      this.user = storageGet('user')
+      this.rolesPermissions = storageGet('rolesPermissions')
+    },
+    //加载任务的服务类型
+    setServiceType () {
+      getAllServiceTypes().then((res) => {
+        this.serviceType = res
+      }).catch((error) => {
+        notify('error', '加载任务类型失败')
+      })
+    },
+    //加载所有的测评机构
+    setInstitutions () {
+      getAllAgencies().then((res) => {
+        this.institutionArray = res
+      }).catch((error) => {
+        notify('error', '获取机构列表失败')
+      })
     },
-    submitForm(formName) {
-      this.$refs[formName].validate(valid => {
+    //获取任务详情
+    getTaskDetail () {
+      this.showLoading()
+      getTask(this.projectId, this.taskId, this.getTaskDetailSuccess, this.getTaskDetailFail)
+    },
+    //获取任务详情成功时回调函数
+    getTaskDetailSuccess (res) {
+      this.hideLoading()
+      //console.log(res.crowdTaskVO)
+      this.taskId = res.crowdTaskVO.id
+      this.projectId = res.crowdTaskVO.projectId
+      this.task.title = res.crowdTaskVO.title
+      this.task.description = res.crowdTaskVO.description
+      this.task.serviceType = res.crowdTaskVO.serviceType
+      this.task.resource = res.crowdTaskVO.resource
+      this.task.location = getProvinceCodeByProvinceName(res.crowdTaskVO.location.provinceCode, res.crowdTaskVO.location.cityCode)
+      this.task.institution = res.crowdTaskVO.institution
+      this.task.datetime = new Date(res.crowdTaskVO.datetime)
+      this.task.quotePrice = res.crowdTaskVO.quotePrice
+      this.task.fixedPrice = res.crowdTaskVO.fixedPrice
+      this.task.doc = []
+      this.task.requireDocUrl = res.crowdTaskVO.requirementFile
+      this.task.agencyId = res.crowdTaskVO.agencyId
+      this.task.status = res.crowdTaskVO.status
+      this.taskOperationControl = res.taskOperationControl
+      this.reportList = res.crowdReportVOList
+    },
+    //获取任务详情失败时回调函数
+    getTaskDetailFail (error) {
+      this.hideLoading()
+      notify('error', '获取任务详情失败:' + error.data)
+    },
+    //更新任务信息
+    updateTask () {
+      this.$refs['task'].validate(valid => {
         if (valid) {
-          this.isModifyMode = false;
-          console.log(this.task);
-          //提交 task
+          this.showLoading()
+          const newTask = {
+            name: this.task.title,
+            desc: this.task.description,
+            type: this.task.serviceType,
+            resource: this.task.resource,
+            location: this.task.location == null ? {} : getProvinceNameByProvinceCode(this.task.location.provinceCode, this.task.location.cityCode),
+            institution: this.task.institution.id,
+            datetime: this.task.datetime,
+            quotePrice: this.task.quotePrice,
+            fixedPrice: this.task.fixedPrice,
+            requirementFile: this.task.requireDocUrl
+          }
+          //console.log(newTask)
+          updateTask(this.projectId, this.taskId, newTask, this.updateTaskSuccess, this.updateTaskFail)
         } else {
-          console.log("error submit!!");
-          return false;
+          notify('error', '表单填写有误!')
+          return false
         }
-      });
-    },
-    cancelMode(formName) {
-      this.isModifyMode = false;
-      //获得task 信息
-      this.task = {
-        name: "任务名称xxxxs",
-        desc: "任务描述文字",
-        type: "安全漏洞扫描",
-        resource: "区域", //如果是广场不用管Location和institution ,定向看institution,区域看location
-        location: { provinceCode: "3200", cityCode: "3201" },
-        institution: "",
-        datetime: new Date("2018-11-11 23:11:11")
-      };
-    },
-    modifyForm() {
-      this.isModifyMode = true;
-      //获得task 信息
-      this.task = {
-        name: "任务名称xxxxs",
-        desc: "任务描述文字",
-        type: "安全漏洞扫描",
-        resource: "区域", //如果是广场不用管Location和institution ,定向看institution,区域看location
-        location: { provinceCode: "3200", cityCode: "3201" },
-        institution: "",
-        datetime: new Date("2018-11-11 23:11:11")
-      };
-    },
-    resetForm(formName) {
-      this.$refs.addFormProvince.resetProviceCity();
-      this.$refs[formName].resetFields();
-      this.task.name = "";
-      this.task.desc = "";
-      this.task.type = "";
-      this.task.resource = "广场"; //如果是广场不用管Location和institution ,定向看institution,区域看location
-      (this.task.location = { provinceCode: "", cityCode: "" }),
-        (this.task.institution = "");
-      this.task.datetime = "";
-    },
-    locationChange(provinceId, cityId) {
-      if (provinceId || cityId)
-        this.task.location = { provinceCode: provinceId, cityCode: cityId };
-    },
-    toProject() {
+      })
+    },
+    //更新任务信息成功时回调函数
+    updateTaskSuccess (res) {
+      this.cancelMode()
+      this.taskId = res.crowdTaskVO.id
+      this.projectId = res.crowdTaskVO.projectId
+      this.task.title = res.crowdTaskVO.title
+      this.task.description = res.crowdTaskVO.description
+      this.task.serviceType = res.crowdTaskVO.serviceType
+      this.task.resource = res.crowdTaskVO.resource
+      this.task.location = res.crowdTaskVO.location == null ? {
+        provinceCode: 3200,
+        cityCode: 3201
+      } : getProvinceCodeByProvinceName(res.crowdTaskVO.location.provinceCode, res.crowdTaskVO.location.cityCode)
+      this.task.institution = res.crowdTaskVO.institution
+      this.task.datetime = new Date(res.crowdTaskVO.datetime)
+      this.task.quotePrice = res.crowdTaskVO.quotePrice
+      this.task.fixedPrice = res.crowdTaskVO.fixedPrice
+      this.task.doc = []
+      this.task.requireDocUrl = res.crowdTaskVO.requirementFile
+      this.reportList = res.crowdReportVOList
+      this.hideLoading()
+      notify('success', '修改成功')
+    },
+    //更新任务信息失败时回调函数
+    updateTaskFail (error) {
+      notify('error', '修改失败:' + error.data)
+      this.hideLoading()
+    },
+    //上传任务需求文档
+    uploadRequireDoc (param) {
+      const formData = new FormData()
+      let config = {
+        //添加请求头
+        headers: {'Content-Type': 'multipart/form-data'},
+      }
+      formData.append('file', param.file)
+      Http.upload(Apis.FILE.REQUIREMENT_FILE.replace('{userId}', this.user.userVO.id), formData, config).then((res) => {
+        this.uploadRequireDocSuccess(res)
+      }).catch((error) => {
+        this.uploadRequireDocFail(error)
+      })
+    },
+    //上传任务需求文档成功时回调函数
+    uploadRequireDocSuccess (res) {
+      this.hideLoading()
+      console.log('上传成功')
+      this.task.requireDocUrl = res.data
+      console.log(res.data)
+    },
+    //上传任务需求文档失败时回调函数
+    uploadRequireDocFail (error) {
+      this.hideLoading()
+      notify('error', '任务需求文档上传失败:' + error.data)
+    },
+    //文档上传前响应函数
+
+    //移除文档前的响应函数
+    beforeRemove (file, fileList) {
+      //return this.$confirm(`确定移除 ${file.name}?`)
+    },
+    //移除文档时的响应函数
+    handleRemove (file, fileList) {
+      console.log(file, fileList)
+    },
+    //需求文档添加进来时的响应函数
+    handleExceed (files, fileList) {
+      this.$message.warning(
+        `当前限制选择 1 个文件,本次选择了 ${
+          files.length
+          } 个文件,共选择了 ${files.length + fileList.length} 个文件`
+      )
+    },
+    //接收任务
+    receiveTask () {
+      this.$confirm('确认接收任务?', '提示', {
+        confirmButtonText: '确认接收',
+        cancelButtonText: '取消',
+        type: 'success'
+      }).then(() => {
+        this.showLoading()
+        receiveTaskRequest(this.projectId, this.taskId, this.user.userVO.id, this.receiveTaskSuccess, this.receiveTaskFail)
+      }).catch(() => {
+      })
+    },
+    //接收任务成功时的回调函数
+    receiveTaskSuccess (res) {
+      this.hideLoading()
+      notify('success', '接收任务成功')
+      console.log(res)
+      this.taskOperationControl = res.taskOperationControl
+      this.task.status = res.crowdTaskVO.status
+      this.task.institution = res.crowdTaskVO.institution
+    },
+    //接收任务失败时的回调函数
+    receiveTaskFail (error) {
+      this.hideLoading()
+      notify('error', '接收任务失败:' + error.data)
+    },
+    //拒绝任务
+    rejectTask () {
+      this.$confirm('确认拒绝任务?拒绝后将不能再接收该任务', '提示', {
+        confirmButtonText: '确认拒绝',
+        cancelButtonText: '取消',
+        type: 'success'
+      }).then(() => {
+        this.showLoading()
+        rejectTask(this.projectId, this.taskId, this.rejectTaskSuccess, this.rejectTaskFail)
+      }).catch(() => {
+
+      })
+    },
+    //拒绝任务成功时的回调函数
+    rejectTaskSuccess (res) {
+      this.hideLoading()
       this.$router.push({
-        name: "Project",
-        params: { projectId: this.projectId }
-      });
+        name: 'Mine'
+      })
+      notify('success', '拒绝任务成功,已为您自动跳转到个人中心')
     },
-    applyTask() {
-      console.log("申请项目");
+    //拒绝任务失败时的回调函数
+    rejectTaskFail (error) {
+      this.hideLoading()
+      notify('error', '拒绝任务失败:' + error.data)
     },
-    createReport() {
-      this.$router.push({ name: "ReportCreate" });
+    //提交结束任务申请
+    submitTaskRequest () {
+      this.$confirm('确认提交任务?提交后将不能再修改', '提示', {
+        confirmButtonText: '确认提交',
+        cancelButtonText: '取消',
+        type: 'success'
+      }).then(() => {
+        this.showLoading()
+        submitTaskRequest(this.projectId, this.taskId, this.submitTaskRequestSuccess, this.submitTaskRequestFail)
+      }).catch(() => {
+
+      })
     },
-  }
-};
+    //提交结束任务申请成功时的回调函数
+    submitTaskRequestSuccess (res) {
+      this.hideLoading()
+      console.log(res)
+      this.taskOperationControl = res.taskOperationControl
+      this.task.status = res.crowdTaskVO.status
+      this.task.institution = res.crowdTaskVO.institution
+      notify('success', '提交任务成功,等待区域管理员审核')
+    },
+    //提交结束任务申请失败时的回调函数
+    submitTaskRequestFail (error) {
+      this.hideLoading()
+      notify('error', '提交任务失败:' + error.data)
+    },
+    //结束任务
+    endTask () {
+      this.$confirm('确认结束任务?', '提示', {
+        confirmButtonText: '确认结束',
+        cancelButtonText: '取消',
+        type: 'success'
+      }).then(() => {
+        this.showLoading()
+        ensureEndTask(this.projectId, this.taskId, this.endTaskSuccess, this.endTaskFail)
+      }).catch(() => {
+
+      })
+    },
+    //结束任务成功时的回调函数
+    endTaskSuccess (res) {
+      this.hideLoading()
+      this.taskOperationControl = res.taskOperationControl
+      this.task.status = res.crowdTaskVO.status
+      this.task.institution = res.crowdTaskVO.institution
+      notify('success', '结束任务成功!')
+    },
+    //结束任务失败时的回调函数
+    endTaskFail (error) {
+      this.hideLoading()
+      notify('error', '结束任务失败:' + error.data)
+    },
+    //跳转到创建项目报告页面
+    toCreateReport () {
+      this.$router.push({
+        name: 'TaskReportCreate',
+        params: {
+          scope: 1,
+          dependencyCode: this.taskId,
+          projectId: this.projectId,
+          taskId: this.taskId,
+        }
+      })
+    },
+    reformDate (date) {
+      return getFormalTimeFromDate(date)
+    }
+  },
+}
+//回收站
+//
+// updateLocation (location) {
+//   console.log(location)
+//   const loactionName = getProvinceNameByProvinceCode(location.provinceCode, location.cityCode)
+//   // var provinceName = ''
+//   // var cityName = ''
+//   // for (var item of provinceCityJSON.provinces) {
+//   //   if (item.code === location.provinceCode) {
+//   //     provinceName = item.name
+//   //     for (var city of item.cities) {
+//   //       if (city.code === location.cityCode) {
+//   //         cityName = city.name
+//   //         break
+//   //       }
+//   //     }
+//   //   }
+//   // }
+//   return loactionName.provinceCode + ' / ' + loactionName.cityCode
+// },
+//
+// locationChange (provinceId, cityId) {
+//   if (provinceId || cityId) {
+//     this.task.location = {provinceCode: provinceId, cityCode: cityId}
+//   }
+// },
+// submitForm (formName) {
+// this.$refs[formName].validate(valid => {
+//   if (valid) {
+//     this.isModifyMode = false
+//
+//   } else {
+//     console.log('error submit!!')
+//     return false
+//   }
+// })
+// },
 </script>
 
 <style lang="less" scoped>
-.el-radio {
-  margin: 10px 20px 10px 0;
-}
-.el-form-item /deep/.el-tabs__content {
-  max-height: 120px !important;
-  overflow: auto;
-}
+  .el-radio {
+    margin: 10px 20px 10px 0;
+  }
+
+  .el-form-item /deep/ .el-tabs__content {
+    max-height: 120px !important;
+    overflow: auto;
+  }
 </style>

+ 301 - 129
src/components/task/TaskCreate.vue

@@ -1,50 +1,77 @@
 <template>
-  <div class="create-container">
+  <div class="create-container" v-loading="loading">
     <div class="title h1">创建任务</div>
     <div class="create-body">
       <el-form :model="task" :rules="rules" ref="task" label-width="12%" class="demo-task">
         <el-form-item label="任务名称" prop="name">
-          <el-input v-model="task.name"></el-input>
+          <el-input size="small" v-model="task.name"></el-input>
         </el-form-item>
         <el-form-item label="任务描述" prop="desc">
-          <el-input type="textarea" v-model="task.desc"></el-input>
+          <el-input autosize type="textarea" style="width: 400px" v-model="task.desc"></el-input>
         </el-form-item>
+        <el-form-item label="任务报价" prop="quotePrice">
+          <el-input size="small" type="number" v-model="task.quotePrice">
+            <template slot="append">¥</template>
+          </el-input>
+        </el-form-item>
+        <!--<el-form-item type="number" label="任务定价" prop="fixedPrice">-->
+        <!--<el-input v-model="task.fixedPrice">-->
+        <!--<template slot="append">¥</template>-->
+        <!--</el-input>-->
+        <!--</el-form-item>-->
         <el-form-item label="业务类型" prop="type">
           <el-radio-group v-model="task.type">
-            <el-radio label="接口测试" name="type"></el-radio>
-            <el-radio label="安全漏洞扫描" name="type"></el-radio>
-            <el-radio label="风险评估服务" name="type"></el-radio>
-            <el-radio label="源代码安全审计服务" name="type"></el-radio>
-            <el-radio label="功能测试服务" name="type"></el-radio>
-            <el-radio label="性能测试" name="type"></el-radio>
-            <el-radio label="功能和易用性测试" name="type"></el-radio>
+            <span v-for="(item,index) in serviceType" :key="index">
+              <el-radio :label="item" name="type">{{item}}</el-radio>
+            </span>
           </el-radio-group>
         </el-form-item>
         <el-form-item label="任务可见性" prop="resource">
-          <el-tabs :tab-position="tabPosition" v-model="task.resource" style="max-height: 200px;">
-            <el-tab-pane label="定向" name="定向">
+          <el-tabs :tab-position="tabPosition" v-model="task.resource" style="width: 800px">
+            <el-tab-pane :label="resourceType[0]" name="0">
               <el-radio-group v-model="task.institution">
                 <el-radio
                   :label="item"
                   name="type"
                   v-for="item,index in institutionArray"
                   :key="index"
-                ></el-radio>
+                >{{item.name}}
+                </el-radio>
               </el-radio-group>
             </el-tab-pane>
-            <el-tab-pane label="区域" name="区域">
-              <provincecity
-                ref="addFormProvince"
-                @selectChange="locationChange"
-                :provinceCode="task.location.provinceCode"
-                :cityCode="task.location.cityCode"
-              ></provincecity>
-            </el-tab-pane>
-            <el-tab-pane label="广场" name="广场"></el-tab-pane>
+            <!--<el-tab-pane :label="resourceType[1]" name="1">-->
+            <!--<provincecity-->
+            <!--ref="addFormProvince"-->
+            <!--@selectChange="locationChange"-->
+            <!--:provinceCode="task.location.provinceCode"-->
+            <!--:cityCode="task.location.cityCode"-->
+            <!--&gt;</provincecity>-->
+            <!--</el-tab-pane>-->
+            <el-tab-pane :label="resourceType[2]" name="2"></el-tab-pane>
           </el-tabs>
         </el-form-item>
-
-        <el-form-item label="任务截止时间" prop="datetime">
+        <el-form-item label="需求文档" prop="doc">
+          <el-upload
+            drag
+            style="width: 400px"
+            class="upload-demo"
+            action=""
+            :on-remove="handleRemove"
+            :before-remove="beforeRemove"
+            :limit="1"
+            :on-exceed="handleExceed"
+            :before-upload="beforeFileUpload"
+            :http-request="uploadRequireDoc"
+            :file-list="task.doc"
+          >
+            <i class="el-icon-upload"></i>
+            <div class="el-upload__text">
+              将文件拖到此处,或
+              <em>点击上传</em>
+            </div>
+          </el-upload>
+        </el-form-item>
+        <el-form-item size="small" label="任务截止时间" prop="datetime">
           <div class="block">
             <el-date-picker
               v-model="task.datetime"
@@ -56,9 +83,9 @@
           </div>
         </el-form-item>
         <el-form-item>
-          <div class="btn btn-primary btn-info" @click="submitForm('task')">立即创建</div>
-          <div class="btn btn-primary" @click="resetForm('task')">重置</div>
-          <div class="btn btn-primary" @click="cancelCreate('task')">取消</div>
+          <div class="btn btn-medium btn-info" @click="submitForm('task')">立即创建</div>
+          <div class="btn btn-medium" @click="resetForm('task')">重置</div>
+          <div class="btn btn-medium" @click="cancelCreate('task')">取消</div>
         </el-form-item>
       </el-form>
     </div>
@@ -66,164 +93,309 @@
 </template>
 
 <script>
-import Enum from "@/constants/enum/index";
-import provincecity from "@/components/commons/ProvinceCity";
-import provinceCityJSON from "@/constants/provinceCity.json";
+import provincecity from '@/components/commons/ProvinceCity'
+import provinceCityJSON from '@/constants/provinceCity.json'
+import Http from '@/js/http.js'
+import Apis from '@/js/api.js'
+import ResourceType from '@/constants/enum/resource-type.js'
+import {notify} from '@/constants/index'
+import {getAllAgencies, getAllServiceTypes, getProvinceNameByProvinceCode, storageGet} from '@/js/index'
+
 export default {
-  name: "Task",
+  name: 'Task',
   components: {
     provincecity
   },
-  data() {
+  data () {
     return {
+      user: {},
       projectId: 0,
-      institutionArray: Enum.institution,
-      tabPosition: "top",
+      institutionArray: [],
+      tabPosition: 'top',
+      resourceType: ResourceType,
+      loading: false,
+      serviceType: [],
       task: {
-        name: "",
-        desc: "",
-        type: "",
-        resource: "广场", //如果是广场不用管Location和institution ,定向看institution,区域看location
-        location: { provinceCode: "", cityCode: "" },
-        institution: "",
-        datetime: ""
+        name: '',
+        desc: '',
+        type: '',
+        resource: '0', //如果是广场不用管Location和institution ,定向看institution,区域看location
+        location: {provinceCode: '3200', cityCode: '3201'},
+        institution: '',
+        datetime: '',
+        quotePrice: '',
+        fixedPrice: '',
+        doc: [],
+        requireDocUrl: '123.doc'
       },
       pickerOptions: {
         shortcuts: [
           {
-            text: "今天",
-            onClick(picker) {
-              picker.$emit("pick", new Date());
+            text: '今天',
+            onClick (picker) {
+              picker.$emit('pick', new Date())
             }
           },
           {
-            text: "昨天",
-            onClick(picker) {
-              const date = new Date();
-              date.setTime(date.getTime() - 3600 * 1000 * 24);
-              picker.$emit("pick", date);
+            text: '昨天',
+            onClick (picker) {
+              const date = new Date()
+              date.setTime(date.getTime() - 3600 * 1000 * 24)
+              picker.$emit('pick', date)
             }
           },
           {
-            text: "一周前",
-            onClick(picker) {
-              const date = new Date();
-              date.setTime(date.getTime() - 3600 * 1000 * 24 * 7);
-              picker.$emit("pick", date);
+            text: '一周前',
+            onClick (picker) {
+              const date = new Date()
+              date.setTime(date.getTime() - 3600 * 1000 * 24 * 7)
+              picker.$emit('pick', date)
             }
           }
         ]
       },
       rules: {
         name: [
-          { required: true, message: "请输入任务名称", trigger: "blur" }
-          // { min: 3, max: 5, message: "长度在 3 到 5 个字符", trigger: "blur" }
+          {required: true, message: '请输入任务名称', trigger: 'blur'},
+          {min: 5, max: 50, message: '任务名称长度在 5 到 50 个字符', trigger: 'blur'}
         ],
-        datetime: [
+        type: [
+          {required: true, message: '业务类型不可为空'},
+        ],
+        desc: [{required: false, message: '请填写描述', trigger: 'blur'}],
+        //price: [{required: true, message: '请填写价格', trigger: 'blur'}],
+        quotePrice: [
+          {required: true, message: '预算不可为空', trigger: 'blur'},
           {
-            type: "date",
-            required: true,
-            message: "请选择截止时间",
-            trigger: "change"
-          }
+            validator: (rule, value, callback) => {
+              if (parseInt(value) < 0) {
+                callback(new Error('请输入不小于0的数'))
+              } else {
+                callback()
+              }
+            }, trigger: 'blur'
+          },
         ],
-        type: [
-          { required: true, message: "请选择业务类型", trigger: "change" }
+        resource: [
+          {required: true},
+          {
+            validator: (rule, value, callback) => {
+              if (value == 0 && this.task.institution.id == null) {
+                callback(new Error('定向发布至少要选择一个测评机构'))
+              } else {
+                callback()
+              }
+            }, trigger: 'change'
+          },
         ],
-        desc: [{ required: true, message: "请填写任务描述", trigger: "blur" }]
+        datetime: [{required: true, message: '截止时间不可为空', trigger: 'blur'}],
       }
-    };
+    }
   },
   watch: {
-    "task.institution"() {
-      if (this.task.institution) {
-        this.$refs.addFormProvince.resetProviceCity();
-        this.task.location = { provinceCode: "", cityCode: "" };
-      }
+    serviceType (val) {
+      this.serviceType = val
     },
-    "task.location"() {
-      if (this.task.location.provinceCode || this.task.location.cityCode) {
-        this.task.institution = "";
-      }
-    },
-    "task.resource"() {
-      if (this.task.resource == "广场") {
-        this.$refs.addFormProvince.resetProviceCity();
-        this.task.institution = "";
-        this.task.location = { provinceCode: "", cityCode: "" };
-      }
+    institution (val) {
+      this.institution = val
     },
+    // 'task.institution' () {
+    //   if (this.task.institution) {
+    //     this.$refs.addFormProvince.resetProviceCity()
+    //     this.task.location = {provinceCode: '', cityCode: ''}
+    //   }
+    // },
+    // 'task.location' () {
+    //   if (this.task.location.provinceCode || this.task.location.cityCode) {
+    //     this.task.institution = ''
+    //   }
+    // },
+    // 'task.resource' () {
+    //   if (this.task.resource == '广场') {
+    //     this.$refs.addFormProvince.resetProviceCity()
+    //     this.task.institution = ''
+    //     this.task.location = {provinceCode: '', cityCode: ''}
+    //   }
+    // },
     deep: true
   },
-  mounted() {
+  mounted () {
     this.$nextTick(() => {
-      this.init();
-    });
+      this.init()
+    })
   },
   methods: {
-    init() {
-      this.projectId = +this.$route.params.projectId;
+    init () {
+      this.projectId = this.$route.params.projectId
+      this.setServiceType()
+      this.setInstitutions()
+      this.setUserInfo()
     },
-    updateLocation(location) {
-      var provinceName = "";
-      var cityName = "";
+    updateLocation (location) {
+      var provinceName = ''
+      var cityName = ''
       for (var item of provinceCityJSON.provinces) {
         if (item.code === location.provinceCode) {
-          provinceName = item.name;
+          provinceName = item.name
           for (var city of item.cities) {
             if (city.code === location.cityCode) {
-              cityName = city.name;
-              break;
+              cityName = city.name
+              break
             }
           }
         }
       }
-      return provinceName + " / " + cityName;
+      return provinceName + ' / ' + cityName
     },
-    submitForm(formName) {
-      this.$refs[formName].validate(valid => {
+    submitForm (formName) {
+      this.$refs['task'].validate(valid => {
         if (valid) {
-          console.log(this.task);
-          //提交 task
+          this.showLoading()
+          const newTask = {
+            name: this.task.name,
+            desc: this.task.desc,
+            type: this.task.type,
+            resource: this.task.resource,
+            location: getProvinceNameByProvinceCode(this.task.location.provinceCode, this.task.location.cityCode),
+            institution: this.task.institution.id,
+            datetime: this.task.datetime,
+            quotePrice: this.task.quotePrice,
+            fixedPrice: this.task.fixedPrice,
+            requirementFile: this.task.requireDocUrl
+          }
+          Http.post(Apis.TASK.CREATE_TASK.replace('{projectId}', this.projectId), newTask).then((res) => {
+            console.log(res)
+            this.hideLoading()
+            this.createTaskSuccess(res.crowdTaskVO.id)
+          }).catch((error) => {
+            console.log(error)
+            this.hideLoading()
+            notify('error', error.data)
+          })
         } else {
-          console.log("error submit!!");
-          return false;
+          notify('error', '表单填写有误!')
+          return false
         }
-      });
-    },
-    resetForm(formName) {
-      this.$refs.addFormProvince.resetProviceCity();
-      this.$refs[formName].resetFields();
-      this.task.name = "";
-      this.task.desc = "";
-      this.task.type = "";
-      this.task.resource = "广场"; //如果是广场不用管Location和institution ,定向看institution,区域看location
-      (this.task.location = { provinceCode: "", cityCode: "" }),
-        (this.task.institution = "");
-      this.task.datetime = "";
-    },
-    locationChange(provinceId, cityId) {
-      if (provinceId || cityId)
-        this.task.location = { provinceCode: provinceId, cityCode: cityId };
-    },
-    cancelCreate() {
+      })
+    },
+    resetForm (formName) {
+      this.$refs.addFormProvince.resetProviceCity()
+      this.$refs[formName].resetFields()
+      this.task.name = ''
+      this.task.desc = ''
+      this.task.type = ''
+      this.task.resource = '广场'; //如果是广场不用管Location和institution ,定向看institution,区域看location
+      (this.task.location = {provinceCode: '', cityCode: ''}),
+        (this.task.institution = '')
+      this.task.datetime = ''
+    },
+    locationChange (provinceId, cityId) {
+      if (provinceId || cityId) {
+        this.task.location = {provinceCode: provinceId, cityCode: cityId}
+      }
+    },
+    cancelCreate () {
       if (window.history.length <= 1) {
-        this.$router.push({ path: "/" });
-        return false;
+        this.$router.push({path: '/'})
+        return false
       } else {
-        this.$router.go(-1);
+        this.$router.go(-1)
       }
+    },
+    handleRemove (file, fileList) {
+      console.log(file, fileList)
+    },
+    handleExceed (files, fileList) {
+      this.$message.warning(
+        `当前限制选择 1 个文件,本次选择了 ${
+          files.length
+          } 个文件,共选择了 ${files.length + fileList.length} 个文件`
+      )
+    },
+    beforeRemove (file, fileList) {
+      //return this.$confirm(`确定移除 ${file.name}?`)
+    },
+    beforeFileUpload (file) {
+      console.log(file)
+      const isPDF = file.type === 'application/pdf'
+      const isDOC = file.type === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
+      const isEXCEL = file.type === 'application/vnd.ms-excel'
+      const isXLS = file.type === 'application/x-xls'
+      const isTXT = file.type === 'text/plain'
+      const isXLSX = file.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
+      //console.log(file)
+      if (!(isDOC || isEXCEL || isPDF || isTXT || isXLS || isXLSX)) {
+        this.$message.error('上传文件只能是 PDF 、 DOC 、DOCX 、XLS、TXT、XLSX 格式!')
+      }
+      return isDOC || isEXCEL || isPDF || isTXT || isXLS || isXLSX
+    },
+    uploadRequireDoc (param) {
+      this.showLoading()
+      const formData = new FormData()
+      let config = {
+        //添加请求头
+        headers: {'Content-Type': 'multipart/form-data'},
+      }
+      formData.append('file', param.file)
+      Http.upload(Apis.FILE.REQUIREMENT_FILE.replace('{userId}', this.user.userVO.id), formData, config).then((res) => {
+        this.hideLoading()
+        notify('success', '上传成功')
+        this.task.requireDocUrl = res.data
+        console.log(res.data)
+      }).catch((error) => {
+        this.hideLoading()
+        notify('error', '上传失败:' + error.data)
+      })
+    },
+    setServiceType () {
+      this.serviceType = getAllServiceTypes().then((res) => {
+        this.serviceType = res
+      }).catch((error) => {
+        notify('error', '加载服务类型列表失败')
+      })
+    },
+    setInstitutions () {
+      getAllAgencies().then((res) => {
+        this.institutionArray = res
+      }).catch((error) => {
+        notify('error', '测评机构加载失败')
+      })
+    },
+    setUserInfo () {
+      this.user = storageGet('user')
+    },
+    createTaskSuccess (taskId) {
+      this.$alert('任务创建成功', '创建成功', {
+        confirmButtonText: '确定',
+        callback: action => {
+          this.$router.push({
+            name: 'Task',
+            params: {projectId: this.projectId, taskId: taskId}
+          })
+        }
+      })
+    },
+    showLoading () {
+      this.loading = true
+    },
+    hideLoading () {
+      this.loading = false
     }
   }
-};
+}
 </script>
 
 <style lang="less" scoped>
-.el-radio {
-  margin: 10px 20px 10px 0;
-}
-.el-form-item /deep/.el-tabs__content {
-  max-height: 120px !important;
-  overflow: auto;
-}
+  .el-radio {
+    margin: 10px 20px 10px 0;
+  }
+
+  .el-input {
+    width: 400px;
+  }
+
+  .el-form-item /deep/ .el-tabs__content {
+    max-height: 120px !important;
+    overflow: auto;
+  }
 </style>

+ 2 - 2
src/constants/enum/index.js

@@ -3,11 +3,11 @@ export default {
         "华东","华北","华中","华南","西南","西北","东北"
     ],
     institution:[
-        "慕测","上软","拓思","4","5","6","7","8","9","10",
+        "1","2","3","4","5","6","7","8","9","10",
         "11","12","13","14","15","16","17","18","19","20",
         "21","22","23","24","25","26","27","28","29","30",
         "31","32","33","34","35","36","37","38","39","40",
         "41","42","43","44","45","46","47","48","49","50",
         "51","52","53","54","55","56","57","58","59","60"
     ]
-}
+}

+ 10 - 0
src/constants/enum/report-type.js

@@ -0,0 +1,10 @@
+let ReportType = {
+  0: "项目可行性报告", //项目可行性报告
+  1: "项目测试方案",    //项目测试方案
+  2: "项目测试报告",   //项目测试报告
+  3: "项目缺陷报告",   //项目缺陷报告
+  4: "项目用例报告",   //项目用例报告
+  5: "其他",   //其他
+}
+
+export default ReportType

+ 7 - 0
src/constants/enum/resource-type.js

@@ -0,0 +1,7 @@
+let ResourceType = {
+  0: "定向",
+  1: "区域",
+  2: "广场",
+}
+
+export default ResourceType

+ 52 - 24
src/constants/index.js

@@ -1,26 +1,54 @@
+import {Notification} from 'element-ui'
+
 export const timeChange = (dateString, formdate) => {
-    if (dateString == null || dateString == '') {
-        return '';
-    }
-    // new Date('');传入毫秒数,也可以得到普通的时间,再对date处理
-    var date = new Date(parseInt(dateString));
-    //获取年份,月份,天数,小时数,分钟数,小于10的显示01-09
-    var year = date.getFullYear();
-    var month = date.getMonth() + 1 < 10 ? "0" + (date.getMonth() + 1) : date.getMonth() + 1;
-    var currentDate = date.getDate() < 10 ? "0" + date.getDate() : date.getDate();
-    var hours = date.getHours() < 10 ? "0" + date.getHours() : date.getHours();
-    var minutes = date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes();
-    if (formdate == null || formdate == "yyyy-mm-dd HH:mm") {
-        return year + "-" + month + "-" + currentDate + " " + hours + ":" + minutes;
-    } else if (formdate == "yyyy-mm-dd") {
-        return year + "-" + month + "-" + currentDate;
-    } else if (formdate == "yyyy-mm") {
-        return year + month;
-    } else if (formdate == "mm-dd") {
-        return month + "-" + currentDate;
-    } else if (formdate == "HH:mm") {
-        return hours + ":" + minutes;
-    } else {
-        return "";
-    }
+  if (dateString == null || dateString == '') {
+    return ''
+  }
+  // new Date('');传入毫秒数,也可以得到普通的时间,再对date处理
+  var date = new Date(parseInt(dateString))
+  //获取年份,月份,天数,小时数,分钟数,小于10的显示01-09
+  var year = date.getFullYear()
+  var month = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1
+  var currentDate = date.getDate() < 10 ? '0' + date.getDate() : date.getDate()
+  var hours = date.getHours() < 10 ? '0' + date.getHours() : date.getHours()
+  var minutes = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()
+  if (formdate == null || formdate == 'yyyy-mm-dd HH:mm') {
+    return year + '-' + month + '-' + currentDate + ' ' + hours + ':' + minutes
+  } else if (formdate == 'yyyy-mm-dd') {
+    return year + '-' + month + '-' + currentDate
+  } else if (formdate == 'yyyy-mm') {
+    return year + month
+  } else if (formdate == 'mm-dd') {
+    return month + '-' + currentDate
+  } else if (formdate == 'HH:mm') {
+    return hours + ':' + minutes
+  } else {
+    return ''
+  }
+}
+export const notify = (type, msg, title) => {
+  var title = '消息'
+  switch (type) {
+    case 'success':
+      title = '成功'
+      break
+    case 'warning':
+      title = '提醒'
+      break
+    case 'info':
+      title = '消息'
+      break
+    case 'error':
+      title = '错误'
+      break
+    default:
+      title = '消息'
+      break
+  }
+  return Notification({
+    title: title,
+    message: msg,
+    type: type,
+    duration: 3000
+  })
 }

+ 81 - 0
src/js/api.js

@@ -0,0 +1,81 @@
+export default {
+  PROJECT: {
+    GET_PROJECT: '/api/project/{projectId}/',
+    CREATE_PROJECT: '/api/project/',
+    UPDATE_PROJECT: '/api/project/{projectId}/',
+    DELETE_PROJECT: '/api/project/{projectId}/',
+    ADD_PROJECT: '/api/greenChannel/project/',
+    ADD_PROJECT_BY_EXCEL_PRE: '/api/greenChannel/excel/{userId}/projects',
+    ADD_PROJECT_BY_EXCEL: '/api/greenChannel/projects',
+    ACCEPT_PROJECT: '/api/project/{projectId}/regionManager/{userId}',
+    REJECT_PROJECT: '/api/project/{projectId}/status/rejected',
+    SUBMIT_PROJECT: '/api/project/{projectId}/status/committed',
+    END_PROJECT: '/api/project/{projectId}/status/finished'
+  },
+  TASK: {
+    GET_TASK: '/api/project/{projectId}/task/{taskId}/',
+    CREATE_TASK: '/api/project/{projectId}/task/',
+    UPDATE_TASK: '/api/project/{projectId}/task/{taskId}/',
+    DELETE_TASK: '/api/project/{projectId}/task/{taskId}/',
+    ACCEPT_TASK: '/api/project/{projectId}/task/{taskId}/agency/{userId}', // PUT
+    REJECT_TASK: '/api/project/{projectId}/task/{taskId}/status/reject',
+    SUBMIT_TASK: '/api/project/{projectId}/task/{taskId}/status/commit',
+    END_TASK: '/api/project/{projectId}/task/{taskId}/status/finished',
+  },
+  REPORT: {
+    GET_TASK_REPORT: '/api/project/{projectId}/task/{taskId}/report/{reportId}/',
+    GET_PROJECT_REPORT: '/api/project/{projectId}/report/{reportId}/',
+    CREATE_TASK_REPORT: '/api/project/{projectId}/task/{taskId}/report/',
+    CREATE_PROJECT_REPORT: '/api/project/{projectId}/report/',
+    UPDATE_TASK_REPORT: '/api/project/{projectId}/task/{taskId}/report/{reportId}/',
+    UPDATE_PROJECT_REPORT: '/api/project/{projectId}/report/{reportId}/',
+    DELETE_TASK_REPORT: '/api/project/{projectId}/task/{taskId}/report/{reportId}/',
+    DELETE_PROJECT_REPORT: ''
+  },
+  FILE: {
+    REQUIREMENT_FILE: '/api/files/requirementfile/{userId}/',
+    APK: '/api/files/apk/{userId}/',
+    UPLOAD_REPORT_FILE: '/api/files/report/{userId}/',
+    UPLOAD_EXCEL: '',
+    UPLOAD_IMAGE: '/api/files/image/{userId}/',
+    GET_TEMPLATE_EXCEL_FILE: ''
+  },
+  USER: {
+    ADD_AGENCY: '/api/greenChannel/agency/',
+    GET_CURRENT_USER: '/api/common/currentUser/',
+    GET_USER_IDENTITY: '',
+    GET_AUTH_URLS: '',
+    LOGOUT: '/api/common/logout',
+    SUBMIT_INDIVIDUAL_AUTHENTICATION_INFO: '/api/user/{userId}/personalAuth/',
+    SUBMIT_ENTERPRISE_AUTHENTICATION_INFO: '/api/user/{userId}/enterpriseAuth',
+    SUBMIT_AGENCY_AUTHENTICATION_INFO: '/api/user/{userId}/agency/',
+    UPDATE_INDIVIDUAL_AUTHENTICATION_INFO: '/api/user/{userId}/personalAuth',
+    UPDATE_ENTERPRISE_AUTHENTICATION_INFO: '/api/user/{userId}/enterpriseAuth',
+    UPDATE_AGENCY_AUTHENTICATION_INFO: '/api/user/{userId}/agency/',
+    UPDATE_AGENCY_RESOURCE_AND_ABILITY:'/api/user/{userId}/agency/resource',
+    GET_INDIVIDUAL_AUTHENTICATION_INFO: '/api/user/{userId}/personalAuth',
+    GET_ENTERPRISE_AUTHENTICATION_INFO: '/api/user/{userId}/enterpriseAuth',
+    GET_AGENCY_AUTHENTICATION_INFO: '/api/user/{userId}/agency',
+    GET_ALL_HANDLING_AUTH_INFO: '/api/user/authentication/handling',
+    GET_ALL_HANDLED_AUTH_INFO: '/api/user/authentication/handled',
+    PASS_AGENCY_AUTH:'/api/user/{userId}/agency/status/accept',
+    PASS_ENTERPRISE_AUTH:'/api/user/{userId}/enterpriseAuth/status/accept',
+    PASS_INDIVIDUAL_AUTH:'/api/user/{userId}/personalAuth/status/accept',
+    REJECT_AGENCY_AUTH:'/api/user/{userId}/agency/status/reject',
+    REJECT_ENTERPRISE_AUTH:'/api/user/{userId}/enterpriseAuth/status/reject',
+    REJECT_INDIVIDUAL_AUTH:'/api/user/{userId}/personalAuth/status/reject',
+  },
+  PAGE: {
+    HOME_PAGE: '/api/common/index/',
+    SQUARE_PAGE: '/api/task/',
+    MY_CROWD_TEST_PAGE: '/api/common/mycrowd/{userId}',
+    TASK_DETAIL_PAGE: '/api/page/taskDetail/{taskId}/',
+    PROJECT_DETAIL_PAGE: '/api/project/{projectId}/',
+    REPORT_DETAIL_PAGE: '/api/page/reportDetail/{reportId}/',
+  },
+  GENERAL: {
+    GET_ALL_ABILITIES: '',
+    GET_ALL_INSTITUTIONS: '/api/regionalManager',
+    GET_ALL_AGENCIES: '/api/agency/list'
+  }
+}

+ 44 - 0
src/js/fileService.js

@@ -0,0 +1,44 @@
+import Http from './http'
+import Apis from './api'
+//上传文档
+export const uploadFile = (url, file) => {
+  const formData = new FormData()
+  let config = {
+    //添加请求头
+    headers: {'Content-Type': 'multipart/form-data'},
+  }
+  formData.append('file', file)
+  return Http.upload(url, formData, config)
+}
+
+//上传图片
+export const uploadImage = (file, uploadImageSuccess, uploadImageFail) => {
+  const formData = new FormData()
+  let config = {
+    //添加请求头
+    headers: {'Content-Type': 'multipart/form-data'},
+  }
+  formData.append('file', file)
+  Http.upload(Apis.FILE.UPLOAD_IMAGE, formData, config).then((res) => {
+    uploadImageSuccess(res)
+  }).catch((error) => {
+    uploadImageFail(error)
+  })
+}
+
+//上传图片前检测
+export const beforeUploadImage = () => {
+
+}
+
+//上传文档前检测
+export const beforeUploadFile = () => {
+
+}
+export const checkFileType = (file, typeList, checkFileTypeError) => {
+  var fileType = file.name.split('.')[file.name.split('.').length - 1].toLowerCase()
+  if (!typeList.includes(fileType)) {
+    checkFileTypeError()
+  }
+  return typeList.includes(fileType)
+}

+ 167 - 0
src/js/generalService.js

@@ -0,0 +1,167 @@
+import Http from './http'
+import Apis from './api'
+import ProvinceJson from '../constants/provinceCity'
+//存session
+export const storageSave = (key, value) => {
+  sessionStorage.setItem(key, JSON.stringify(value))
+}
+
+//取session
+export const storageGet = (key) => {
+  // return new Promise((resolve) => {
+  //   resolve(JSON.parse(sessionStorage.getItem(key)))
+  // })
+  return JSON.parse(sessionStorage.getItem(key))
+}
+
+//获取用户id
+export const getUserIdentity = () => {
+  return Http.get(Apis.USER.GET_USER_IDENTITY)
+}
+
+//获取所有测评能力
+export const getAllAbilities = () => {
+  return ['接口测试', '安全漏洞扫描', '风险评估服务', '源代码安全审计服务', '功能测试服务', '性能测试', '功能和易用性测试']
+  //return Http.get(Apis.GENERAL.GET_ALL_ABILITIES)
+}
+
+//获取所有测评资源种类
+export const getAllAgencyResourceTypes = () => {
+  return ['人力资源', '服务器资源', '专用设备']
+  //return Http.get(Apis.GENERAL.GET_ALL_ABILITIES)
+}
+
+//获取所有服务类型
+export const getAllServiceTypes = () => {
+  const data = ['接口测试', '安全漏洞扫描', '风险评估服务', '源代码安全审计服务', '功能测试服务', '性能测试', '功能和易用性测试']
+  return new Promise((resolve) => {
+    resolve(data)
+  })
+  //return Http.get(Apis.GENERAL.GET_ALL_ABILITIES)
+}
+
+//获取所有报告类型
+export const getAllReportTypes = () => {
+  const data = ['可行性报告', '测试方案', '测试报告', '缺陷报告', '用例报告', '其他']
+  return new Promise((resolve) => {
+    resolve(data)
+  })
+  //return Http.get(Apis.GENERAL.GET_ALL_ABILITIES)
+}
+
+//获取所有平台类型
+export const getAllPlatformTypes = () => {
+  return ['ANDROID', 'IOS', 'WEB']
+  //return Http.get(Apis.GENERAL.GET_ALL_ABILITIES)
+}
+//获取所有定向发布的目标
+export const getAllInstitutions = () => {
+  return Http.get(Apis.GENERAL.GET_ALL_INSTITUTIONS)
+}
+
+//获取所有测评机构
+export const getAllAgencies = () => {
+  // const data = [{
+  //   id: 1,
+  //   name: '慕测'
+  // }, {
+  //   id: 2,
+  //   name: '南大'
+  // }]
+  //
+  // return new Promise((resolve) => {
+  //   resolve(data)
+  // })
+  return Http.get(Apis.GENERAL.GET_ALL_AGENCIES)
+}
+
+//通过代码获取省、市名称
+export const getProvinceNameByProvinceCode = (provinceCode, cityCode) => {
+  for (var i = 0; i < ProvinceJson.provinces.length; i++) {
+    if (ProvinceJson.provinces[i].code == provinceCode) {
+      for (var j = 0; j < ProvinceJson.provinces[i].cities.length; j++) {
+        if (ProvinceJson.provinces[i].cities[j].code == cityCode) {
+          return {
+            'provinceCode': ProvinceJson.provinces[i].name,
+            'cityCode': ProvinceJson.provinces[i].cities[j].name
+          }
+        }
+      }
+    }
+  }
+  return {
+    'provinceCode': '江苏省',
+    'cityCode': '南京市'
+  }
+}
+//通过名称获取省、市代码
+export const getProvinceCodeByProvinceName = (provinceName, cityName) => {
+  for (var i = 0; i < ProvinceJson.provinces.length; i++) {
+    if (ProvinceJson.provinces[i].name == provinceName) {
+      for (var j = 0; j < ProvinceJson.provinces[i].cities.length; j++) {
+        if (ProvinceJson.provinces[i].cities[j].name == cityName) {
+          return {
+            'provinceCode': ProvinceJson.provinces[i].code,
+            'cityCode': ProvinceJson.provinces[i].cities[j].code
+          }
+        }
+      }
+    }
+  }
+  return {
+    'provinceCode': '3200',
+    'cityCode': '3201'
+  }
+}
+
+//获取批量上传项目模板文件
+export const getGreenChannelAddProjectExcelTemplateFile = (getTemplateExcelSuccess, getTemplateExcelFail) => {
+  const data = {
+    fileUrl: 'http://mooctest-crowd-service.oss-cn-hangzhou.aliyuncs.com/Others/%E9%A1%B9%E7%9B%AE%E5%AF%BC%E5%85%A5%E6%A8%A1%E6%9D%BF.xlsx'
+  }
+  new Promise((resolve) => {
+    resolve(data)
+  }).then((res) => {
+    getTemplateExcelSuccess(res)
+  }).catch((error) => {
+    getTemplateExcelFail(error)
+  })
+  // Http.get(Apis.FILE.GET_TEMPLATE_EXCEL_FILE).then((res) => {
+  //   getTemplateExcelSuccess(res)
+  // }).catch((error) => {
+  //   getTemplateExcelFail(error)
+  // })
+}
+Date.prototype.Format = function (fmt) {
+  var o = {
+    'M+': this.getMonth() + 1, //月份
+    'd+': this.getDate(), //日
+    'h+': this.getHours(), //小时
+    'm+': this.getMinutes(), //分
+    's+': this.getSeconds(), //秒
+    'q+': Math.floor((this.getMonth() + 3) / 3), //季度
+    'S': this.getMilliseconds() //毫秒
+  }
+  if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + '').substr(4 - RegExp.$1.length))
+  for (var k in o) {
+    if (new RegExp('(' + k + ')').test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (('00' + o[k]).substr(('' + o[k]).length)))
+  }
+  return fmt
+}
+export const getFormalTimeFromDate = (date) => {
+  return date.Format('yyyy-MM-dd hh:mm:ss')
+}
+
+//
+export const getIndexStatisticsInfo = () => {
+  const data = {
+    userNum: 100,
+    agencyNum: 200,
+    deviceNum: 345,
+    projectNum: 23,
+    taskNum: 123
+  }
+  return new Promise((resolve) => {
+    resolve(data)
+  })
+}

+ 116 - 0
src/js/http.js

@@ -0,0 +1,116 @@
+import axios from 'axios'
+
+const TIME_OUT_MS = 60 * 1000 // 默认请求超时时间
+const BASE_URL = process.env.API_ROOT
+axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'
+
+/*
+ * @param response 返回数据列表
+ */
+function handleResults (response) {
+  let remoteResponse = response.data
+  var result = {
+    success: false,
+    message: '',
+    status: [],
+    errorCode: '',
+    data: {
+      total: 0,
+      results: []
+    }
+  }
+  if (remoteResponse.success) {
+    result.data.results = remoteResponse.data
+    result.data.total = remoteResponse.total
+    result.success = true
+  }
+  if (!remoteResponse.success) {
+    let code = remoteResponse.errorCode
+    if (code === 400) {
+      console.log('传参错误')
+    }
+    result.errorCode = remoteResponse.errorCode
+    result.message = remoteResponse.message
+  }
+  return result
+}
+
+function handleUrl (url) {
+  return BASE_URL + url
+}
+
+/*
+ * @param data 参数列表
+ * @return
+ */
+function handleParams (data) {
+  return JSON.parse(JSON.stringify(data))
+}
+
+export default {
+  post (url, data) {
+    return new Promise((resolve, reject) => {
+      axios.post(handleUrl(url), handleParams(data)).then(
+        (result) => {
+          resolve(result.data)
+        }
+      ).catch(
+        (error) => {
+          reject(error.response)
+        }
+      )
+    })
+  },
+  get (url) {
+    return new Promise((resolve, reject) => {
+      axios.get(handleUrl(url))
+        .then(response => {
+          resolve(response.data)
+        }).catch(error => {
+        reject(error.response)
+      })
+
+    })
+
+  },
+  put (url, data) {
+    return new Promise((resolve, reject) => {
+      axios.put(handleUrl(url), JSON.parse(JSON.stringify(data))).then(
+        (result) => {
+          resolve(result.data)
+        }
+      ).catch(
+        (error) => {
+          reject(error.response)
+        }
+      )
+    })
+  },
+  delete (url, data) {
+    return new Promise((resolve, reject) => {
+      axios.delete(handleUrl(url), {data: handleParams(data)}).then(
+        (result) => {
+          resolve(result)
+        }
+      ).catch(
+        (error) => {
+          reject(error)
+        }
+      )
+    })
+  },
+  upload (url, data, config) {
+    return new Promise((resolve, reject) => {
+      axios.post(handleUrl(url), data, config).then(
+        (result) => {
+          resolve(result)
+        }
+      ).catch(
+        (error) => {
+          reject(error)
+        }
+      )
+    })
+  },
+}
+

+ 784 - 0
src/js/index.js

@@ -0,0 +1,784 @@
+import {
+  checkPassAuth,
+  checkRejectAuth,
+  deleteAuthInfo,
+  getAllHandledAuthInfo,
+  getAllHandlingAuthInfo,
+  getAuthUrls,
+  getCurrentAgencyAuthInfo,
+  getCurrentAuthenInfo,
+  getCurrentEnterpriseAuthInfo,
+  getCurrentIndividualAuthenInfo,
+  getCurrentUser,
+  getRolesPermissions,
+  logout,
+  updateAgencyAuthInfo,
+  updateEnterpriseAuthInfo,
+  updateIndividualAuthInfo,
+  uploadAgencyAuthenticationInfo,
+  uploadEnterpriseAuthenticationInfo,
+  uploadIndividualAuthenticationInfo,
+  updateAgencyResourceAndAbility
+} from './userService'
+import {
+  createProject,
+  deleteProject,
+  ensureEndProject,
+  getProject,
+  receiveProjectRequest,
+  rejectProject,
+  submitProjectRequest,
+  updateProject
+} from './projectService'
+import {
+  createTask,
+  deleteTask,
+  ensureEndTask,
+  getTask,
+  receiveTaskRequest,
+  rejectTask,
+  submitTaskRequest,
+  updateTask
+} from './taskService'
+import {
+  createProjectReport,
+  createTaskReport,
+  deleteProjectReport,
+  deleteTaskReport,
+  getProjectReport,
+  getTaskReport,
+  updateProjectReport,
+  updateTaskReport,
+} from './reportService'
+import {beforeUploadFile, beforeUploadImage, checkFileType, uploadFile, uploadImage,} from './fileService'
+import {
+  getAllAbilities,
+  getAllAgencies,
+  getAllAgencyResourceTypes,
+  getAllInstitutions,
+  getAllPlatformTypes,
+  getAllReportTypes,
+  getAllServiceTypes,
+  getFormalTimeFromDate,
+  getGreenChannelAddProjectExcelTemplateFile,
+  getIndexStatisticsInfo,
+  getProvinceCodeByProvinceName,
+  getProvinceNameByProvinceCode,
+  getUserIdentity,
+  storageGet,
+  storageSave
+} from './generalService'
+
+export {
+  /*******************************************************************************/
+  /*******************************userService*************************************/
+  /*******************************************************************************/
+  //TODO 尚未使用 用户放弃认证,删除用户认证信息
+  deleteAuthInfo,
+  //获取所有未处理认证信息
+  getAllHandlingAuthInfo,
+  //获取所有已处理认证信息
+  getAllHandledAuthInfo,
+  //TODO 目前使用本地数据 需要修改 获取所有可以访问的url
+  getAuthUrls,
+  //TODO 目前使用本地数据 需要修改 获取当前用户的认证信息
+  getCurrentAuthenInfo,
+  //TODO 可以使用 需要重构 获取当前用户信息
+  getCurrentUser,
+  //TODO 基本无用 获取当前用户所有的角色权限
+  getRolesPermissions,
+  //TODO 可以使用 需要重构 用户登出
+  logout,
+  //TODO 尚未使用 代码未实现 更新机构认证信息
+  updateAgencyAuthInfo,
+  //TODO 尚未使用 代码未实现 更新企业认证信息
+  updateEnterpriseAuthInfo,
+  //TODO 尚未使用 代码未实现 更新个人认证信息
+  updateIndividualAuthInfo,
+  //TODO 尚未使用 代码未实现 上传机构认证信息
+  uploadAgencyAuthenticationInfo,
+  //TODO 尚未使用 代码未实现 上传企业认证信息
+  uploadEnterpriseAuthenticationInfo,
+  //TODO 尚未使用 代码未实现 上传个人认证信息
+  uploadIndividualAuthenticationInfo,
+  getCurrentIndividualAuthenInfo,
+  getCurrentEnterpriseAuthInfo,
+  getCurrentAgencyAuthInfo,
+  checkPassAuth,
+  checkRejectAuth,
+  updateAgencyResourceAndAbility
+}
+export {
+  /*******************************************************************************/
+  /*******************************projectService**********************************/
+  /*******************************************************************************/
+  //TODO 可以使用 需要重构 创建项目
+  createProject,
+  //TODO 可以使用 需要重构 删除项目
+  deleteProject,
+  //项目拥有者确认结束项目
+  ensureEndProject,
+  //TODO 可以使用 需要重构 获取项目信息
+  getProject,
+  //区域管理员接收项目
+  receiveProjectRequest,
+  //区域管理员拒绝项目
+  rejectProject,
+  //区域管理员提交项目
+  submitProjectRequest,
+  //TODO 可以使用 需要重构 项目拥有者修改项目
+  updateProject,
+}
+export {
+  /*******************************************************************************/
+  /*******************************taskService*************************************/
+  /*******************************************************************************/
+  //TODO 可以使用 需要重构 创建任务
+  createTask,
+  //TODO 可以使用 需要重构 删除任务
+  deleteTask,
+  //区域管理员确认结束项目
+  ensureEndTask,
+  //查看任务信息
+  getTask,
+  //测评机构接收任务
+  receiveTaskRequest,
+  //测评机构拒绝任务
+  rejectTask,
+  //测评机构提交任务
+  submitTaskRequest,
+  //区域管理员修改任务
+  updateTask,
+}
+export {
+  /*******************************************************************************/
+  /*******************************reportService***********************************/
+  /*******************************************************************************/
+  //TODO 尚未使用 代码未实现 创建项目报告
+  createProjectReport,
+  //TODO 尚未使用 代码未实现 创建任务报告
+  createTaskReport,
+  //TODO 尚未使用 代码未实现 删除项目报告
+  deleteProjectReport,
+  //TODO 尚未使用 代码未实现 删除任务报告
+  deleteTaskReport,
+  //TODO 尚未使用 代码未实现 获取项目报告详情
+  getProjectReport,
+  //TODO 尚未使用 代码未实现 获取任务报告详情
+  getTaskReport,
+  //TODO 尚未使用 代码未实现 修改项目报告
+  updateProjectReport,
+  //TODO 尚未使用 代码未实现 修改任务报告
+  updateTaskReport,
+}
+export {
+  /*******************************************************************************/
+  /*******************************fileService*************************************/
+  /*******************************************************************************/
+  //TODO 尚未使用 代码未实现 上传图片
+  uploadImage,
+  //TODO 尚未使用 代码未实现 上传文档
+  uploadFile,
+  //TODO 尚未使用 代码未实现 校验上传格式
+  checkFileType,
+  //TODO 尚未使用 代码未实现 上传需求文档
+  //TODO 尚未使用 代码未实现 上传安装包
+  //TODO 尚未使用 代码未实现 上传批量创建项目文件
+
+  beforeUploadImage,
+  beforeUploadFile,
+
+}
+export {
+  /*******************************************************************************/
+  /*******************************generalService**********************************/
+  /*******************************************************************************/
+  //TODO 目前使用本地数据 需要修改 获取所有测评能力
+  getAllAbilities,
+  //TODO 可以使用 需要重构 获取所有测评机构
+  getAllAgencies,
+  //TODO 目前使用本地数据 需要修改 获取所有测评能力 获取所有测评资源类型
+  getAllAgencyResourceTypes,
+  //TODO 可以使用 需要重构 获取所有区域管理员
+  getAllInstitutions,
+  //TODO 目前使用本地数据 需要修改 获取所有测试平台类型
+  getAllPlatformTypes,
+  //TODO 目前使用本地数据 需要修改 获取所有报告类型
+  getAllReportTypes,
+  //TODO 目前使用本地数据 需要修改 获取所有服务类型(与获取所有测评能力相同)
+  getAllServiceTypes,
+  //获取绿色通道创建项目时的模板文件
+  getGreenChannelAddProjectExcelTemplateFile,
+  //通过省和市名称获取省市代码
+  getProvinceCodeByProvinceName,
+  //通过省市代码获取省市名称
+  getProvinceNameByProvinceCode,
+  //TODO 尚未使用 代码未实现 获取用户id
+  getUserIdentity,
+  //读取本地数据
+  storageGet,
+  //保存数据到本地
+  storageSave,
+  getFormalTimeFromDate,
+  getIndexStatisticsInfo
+}
+
+export const defaultValue = {
+  name: '普通用户',
+  image: 'http://www.mooctest.net/assets/img/mooctest.png',
+}
+//
+// //存session
+// export const storageSave = (key, value) => {
+//   sessionStorage.setItem(key, JSON.stringify(value))
+// }
+//
+// //取session
+// export const storageGet = (key) => {
+//   // return new Promise((resolve) => {
+//   //   resolve(JSON.parse(sessionStorage.getItem(key)))
+//   // })
+//   return JSON.parse(sessionStorage.getItem(key))
+// }
+//
+// //获取用户id
+// export const getUserIdentity = () => {
+//   return Http.get(Apis.USER.GET_USER_IDENTITY)
+// }
+//
+// //获取用户信息
+// export const getCurrentUser = () => {
+//   // const data = {
+//   //   userVO: {
+//   //     id: 3,
+//   //     photo: 'http://www.mooctest.net/assets/img/mooctest.png',
+//   //     name: '郭超',
+//   //     roleList: ['区域管理员', '个人用户', '企业用户', '测评机构', '系统管理员'],
+//   //     mobile: '110',
+//   //     email: '12345@qq.com',
+//   //   },
+//   //   agency: '',
+//   // }
+//   // return new Promise((resolve) => {
+//   //   resolve(data)
+//   // })
+//   return Http.get(Apis.USER.GET_CURRENT_USER)
+// }
+// //
+// export const getRolesPermissions = (roleList) => {
+//   const roles = {
+//     regionManager: 'RegionalManager',
+//     individualUser: 'generalUser',
+//     enterpriseUser: 'enterpriseUser',
+//     agency: 'evaluationAgency',
+//     systemAdministrator: 'SystemAdministrator'
+//   }
+//   const permissions = {
+//     isRegionManager: false,
+//     isIndividualUser: false,
+//     isEnterpriseUser: false,
+//     isAgency: false,
+//     isSystemAdministrator: false
+//   }
+//   if (roleList.includes(roles.regionManager)) {
+//     permissions.isRegionManager = true
+//     permissions.isEnterpriseUser = true
+//     permissions.isIndividualUser = true
+//   }
+//   if (roleList.includes(roles.agency)) {
+//     permissions.isAgency = true
+//     permissions.isEnterpriseUser = true
+//     permissions.isIndividualUser = true
+//   }
+//   if (roleList.includes(roles.enterpriseUser)) {
+//     permissions.isEnterpriseUser = true
+//   }
+//   if (roleList.includes(roles.individualUser)) {
+//     permissions.isIndividualUser = true
+//   }
+//   if (roleList.includes(roles.systemAdministrator)) {
+//     permissions.isSystemAdministrator = true
+//     permissions.isRegionManager = true
+//     permissions.isAgency = true
+//     permissions.isEnterpriseUser = true
+//     permissions.isIndividualUser = true
+//   }
+//   return permissions
+// }
+//
+// export const logout = () => {
+//   sessionStorage.removeItem('user')
+//   sessionStorage.removeItem('rolesPermissions')
+//   return Http.get(Apis.USER.LOGOUT)
+// }
+//
+// //上传文档
+// export const uploadFile = (url, file) => {
+//   const formData = new FormData()
+//   let config = {
+//     //添加请求头
+//     headers: {'Content-Type': 'multipart/form-data'},
+//   }
+//   formData.append('file', file)
+//   return Http.upload(url, formData, config)
+// }
+//
+// //上传图片
+// export const uploadImage = (file, uploadImageSuccess, uploadImageFail) => {
+//   const formData = new FormData()
+//   let config = {
+//     //添加请求头
+//     headers: {'Content-Type': 'multipart/form-data'},
+//   }
+//   formData.append('file', file)
+//   Http.upload(Apis.FILE.UPLOAD_IMAGE, formData, config).then((res) => {
+//     uploadImageSuccess(res)
+//   }).catch((error) => {
+//     uploadImageFail(error)
+//   })
+// }
+//
+// //上传图片前检测
+// export const beforeUploadImage = () => {
+//
+// }
+//
+// //上传文档前检测
+// export const beforeUploadFile = () => {
+//
+// }
+//
+// //创建项目
+// export const createProject = (project) => {
+//   return Http.post(Apis.PROJECT.CREATE_PROJECT, project)
+// }
+//
+// //修改项目
+// export const updateProject = (project, projectId) => {
+//   return Http.put(Apis.PROJECT.UPDATE_PROJECT.replace('{projectId}', projectId), project)
+// }
+//
+// //查看项目
+// export const getProject = (projectId) => {
+//   Http.get(Apis.PROJECT.GET_PROJECT.replace('{projectId}', projectId))
+// }
+//
+// //删除项目
+// export const deleteProject = (projectId, deleteProjectSuccess, deleteProjectFail) => {
+//   Http.put(Apis.PROJECT.DELETE_PROJECT.replace('{projectId}', projectId), {}).then((res) => {
+//     deleteProjectSuccess(res)
+//   }).catch((error) => {
+//     deleteProjectFail(error)
+//   })
+// }
+//
+// //区域管理员提出接收项目申请
+// export const receiveProjectRequest = (projectId, userId, receiveProjectSuccess, receiveProjectFail) => {
+//   console.log('调用')
+//   Http.put(Apis.PROJECT.ACCEPT_PROJECT.replace('{projectId}', projectId).replace('{userId}', userId), {}).then((res) => {
+//     console.log(res)
+//     receiveProjectSuccess(res)
+//
+//   }).catch((error) => {
+//     console.log(error)
+//     receiveProjectFail(error)
+//   })
+// }
+//
+// //区域管理员拒绝项目
+// export const rejectProject = (projectId, rejectProjectSuccess, rejectProjectFail) => {
+//   Http.put(Apis.PROJECT.REJECT_PROJECT.replace('{projectId}', projectId), {}).then((res) => {
+//     rejectProjectSuccess(res)
+//   }).catch((error) => {
+//     rejectProjectFail(error)
+//   })
+// }
+//
+// //区域管理员提出结束项目申请
+// export const submitProjectRequest = (projectId, submitProjectReuqestSuccess, submitProjectRequestFail) => {
+//   Http.put(Apis.PROJECT.SUBMIT_PROJECT.replace('{projectId}', projectId), {}).then((res) => {
+//     submitProjectReuqestSuccess(res)
+//   }).catch((error) => {
+//     submitProjectRequestFail(error)
+//   })
+// }
+//
+// //用户确认结束项目
+// export const ensureEndProject = (projectId, endProjectSuccess, endProjectFail) => {
+//   Http.put(Apis.PROJECT.END_PROJECT.replace('{projectId}', projectId), {}).then((res) => {
+//     endProjectSuccess(res)
+//   }).catch((error) => {
+//     endProjectFail(error)
+//   })
+// }
+//
+// //创建任务
+// export const createTask = (projectId, task) => {
+//   return Http.post(Apis.TASK.CREATE_TASK.replace('{projectId}', projectId), task)
+// }
+//
+// //修改任务
+// export const updateTask = (projectId, taskId, task, updateTaskSuccess, updateTaskFail) => {
+//   Http.put(Apis.TASK.UPDATE_TASK.replace('{projectId}', projectId).replace('{taskId}', taskId), task).then((res) => {
+//     updateTaskSuccess(res)
+//   }).catch((error) => {
+//     updateTaskFail(error)
+//   })
+// }
+//
+// //查看任务
+// export const getTask = (projectId, taskId, getTaskSuccess, getTaskFail) => {
+//   Http.get(Apis.TASK.GET_TASK.replace('{projectId}', projectId).replace('{taskId}', taskId), {}).then((res) => {
+//     getTaskSuccess(res)
+//   }).catch((error) => {
+//     getTaskFail(error)
+//   })
+// }
+//
+// //删除任务
+// export const deleteTask = (projectId, taskId, deleteTaskSuccess, deleteTaskFail) => {
+//   Http.put(Apis.TASK.DELETE_TASK.replace('{projectId}', projectId).replace('taskId', taskId), {}).then((res) => {
+//     deleteTaskSuccess(res)
+//   }).catch((error) => {
+//     deleteTaskFail(error)
+//   })
+// }
+//
+// //测评机构接受任务
+// export const receiveTaskRequest = (projectId, taskId, userId, receiveTaskRequestSuccess, receiveTaskRequestFail) => {
+//   Http.put(Apis.TASK.ACCEPT_TASK.replace('{projectId}', projectId).replace('{taskId}', taskId).replace('{userId}', userId), {}).then((res) => {
+//     receiveTaskRequestSuccess(res)
+//   }).catch((error) => {
+//     receiveTaskRequestFail(error)
+//   })
+//
+// }
+//
+// //测评机构提出结束任务申请
+// export const submitTaskRequest = (projectId, taskId, submitTaskSuccess, submitTaskFail) => {
+//   Http.put(Apis.TASK.SUBMIT_TASK.replace('{projectId}', projectId).replace('{taskId}', taskId), {}).then((res) => {
+//     submitTaskSuccess(res)
+//   }).catch((error) => {
+//     submitTaskFail(error)
+//   })
+// }
+//
+// export const rejectTask = (projectId, taskId, rejectTaskSuccess, rejectTaskFail) => {
+//   Http.put(Apis.TASK.REJECT_TASK.replace('{projectId}', projectId).replace('{taskId}', taskId), {}).then((res) => {
+//     rejectTaskSuccess(res)
+//   }).catch((error) => {
+//     rejectTaskFail(error)
+//   })
+// }
+//
+// //区域管理员确认结束任务
+// export const ensureEndTask = (projectId, taskId, endTaskSuccess, endTaskFail) => {
+//   Http.put(Apis.TASK.END_TASK.replace('{projectId}', projectId).replace('{taskId}', taskId), {}).then((res) => {
+//     endTaskSuccess(res)
+//   }).catch((error) => {
+//     endTaskFail(error)
+//   })
+// }
+//
+// //创建项目报告
+// export const createProjectReport = () => {
+//
+// }
+//
+// //创建任务报告
+// export const createTaskReport = () => {
+//
+// }
+//
+// //修改项目报告
+// export const updateProjectReport = () => {
+//
+// }
+//
+// //修改任务报告
+// export const updateTaskReport = () => {
+//
+// }
+//
+// //查看报告
+// export const getReport = () => {
+//
+// }
+//
+// //删除项目报告
+// export const deleteProjectReport = (projectId, reportId, deleteProjectReportSuccess, deleteProjectReportFail) => {
+//   Http.put(Apis.REPORT.DELETE_PROJECT_REPORT.replace('{projectId}', projectId).replace('{reportId}', reportId), {}).then((res) => {
+//     deleteProjectReportSuccess(res)
+//   }).catch((error) => {
+//     deleteProjectReportFail(error)
+//   })
+// }
+//
+// //删除任务报告
+// export const deleteTaskReport = (projectId, taskId, reportId, deleteTaskReportSuccess, deleteTaskReportFail) => {
+//   Http.put(Apis.REPORT.DELETE_TASK_REPORT.replace('{projectId}', projectId).replace('{taskId}', taskId).replace('{reportId}', reportId), {}).then((res) => {
+//     deleteTaskReportSuccess(res)
+//   }).catch((error) => {
+//     deleteTaskReportFail(error)
+//   })
+// }
+//
+// //获取所有测评能力
+// export const getAllAbilities = () => {
+//   return ['接口测试', '安全漏洞扫描', '风险评估服务', '源代码安全审计服务', '功能测试服务', '性能测试', '功能和易用性测试']
+//   //return Http.get(Apis.GENERAL.GET_ALL_ABILITIES)
+// }
+//
+// //获取所有测评资源种类
+// export const getAllAgencyResourceTypes = () => {
+//   return ['人力资源', '服务器资源', '专用设备']
+//   //return Http.get(Apis.GENERAL.GET_ALL_ABILITIES)
+// }
+//
+// //获取所有服务类型
+// export const getAllServiceTypes = () => {
+//   const data = ['接口测试', '安全漏洞扫描', '风险评估服务', '源代码安全审计服务', '功能测试服务', '性能测试', '功能和易用性测试']
+//   return new Promise((resolve) => {
+//     resolve(data)
+//   })
+//   //return Http.get(Apis.GENERAL.GET_ALL_ABILITIES)
+// }
+//
+// //获取所有报告类型
+// export const getAllReportTypes = () => {
+//   const data = ['项目可行性报告', '项目测试方案', '项目测试报告', '项目缺陷报告', '项目用例报告', '其他']
+//   return new Promise((resolve) => {
+//     resolve(data)
+//   })
+//   //return Http.get(Apis.GENERAL.GET_ALL_ABILITIES)
+// }
+//
+// //获取所有平台类型
+// export const getAllPlatformTypes = () => {
+//   return ['ANDROID', 'IOS', 'WEB']
+//   //return Http.get(Apis.GENERAL.GET_ALL_ABILITIES)
+// }
+//
+// //获取当前角色可访问的url
+// export const getAuthUrls = () => {
+//   return [
+//     '/', '/home', '/square', '/mine', '/project/create',
+//     '/project/:projectId', '/project/:projectId/task/create',
+//     '/project/:projectId/task/:taskId', '/project/:projectId/analyse',
+//     '/report/create', '/report/:reportId', '/greenChannel/addProject', '/greenChannel/addAgency',
+//     '/authentication/individual', '/authentication/enterprise',
+//     '/authentication/agency', '/authentication/index'
+//   ]
+//   //return Http.get(Apis.USER.GET_AUTH_URLS)
+// }
+//
+// //上传个人认证信息
+// export const uploadIndividualAuthenticationInfo = () => {
+//   Http.post(Apis)
+// }
+//
+// //上传企业认证信息
+// export const uploadEnterpriseAuthenticationInfo = () => {
+//
+// }
+//
+// //上传机构认证信息
+// export const uploadAgencyAuthenticationInfo = () => {
+//
+// }
+//
+// //获取所有定向发布的目标
+// export const getAllInstitutions = () => {
+//   return Http.get(Apis.GENERAL.GET_ALL_INSTITUTIONS)
+// }
+//
+// //获取所有测评机构
+// export const getAllAgencies = () => {
+//   // const data = [{
+//   //   id: 1,
+//   //   name: '慕测'
+//   // }, {
+//   //   id: 2,
+//   //   name: '南大'
+//   // }]
+//   //
+//   // return new Promise((resolve) => {
+//   //   resolve(data)
+//   // })
+//   return Http.get(Apis.GENERAL.GET_ALL_AGENCIES)
+// }
+//
+// //通过代码获取省、市名称
+// export const getProvinceNameByProvinceCode = (provinceCode, cityCode) => {
+//   for (var i = 0; i < ProvinceJson.provinces.length; i++) {
+//     if (ProvinceJson.provinces[i].code == provinceCode) {
+//       for (var j = 0; j < ProvinceJson.provinces[i].cities.length; j++) {
+//         if (ProvinceJson.provinces[i].cities[j].code == cityCode) {
+//           return {
+//             'provinceCode': ProvinceJson.provinces[i].name,
+//             'cityCode': ProvinceJson.provinces[i].cities[j].name
+//           }
+//         }
+//       }
+//     }
+//   }
+//   return {
+//     'provinceCode': '江苏省',
+//     'cityCode': '南京市'
+//   }
+// }
+// //通过名称获取省、市代码
+// export const getProvinceCodeByProvinceName = (provinceName, cityName) => {
+//   for (var i = 0; i < ProvinceJson.provinces.length; i++) {
+//     if (ProvinceJson.provinces[i].name == provinceName) {
+//       for (var j = 0; j < ProvinceJson.provinces[i].cities.length; j++) {
+//         if (ProvinceJson.provinces[i].cities[j].name == cityName) {
+//           return {
+//             'provinceCode': ProvinceJson.provinces[i].code,
+//             'cityCode': ProvinceJson.provinces[i].cities[j].code
+//           }
+//         }
+//       }
+//     }
+//   }
+//   return {
+//     'provinceCode': '3200',
+//     'cityCode': '3201'
+//   }
+// }
+//
+// //获取批量上传项目模板文件
+// export const getGreenChannelAddProjectExcelTemplateFile = (getTemplateExcelSuccess, getTemplateExcelFail) => {
+//   const data = {
+//     fileUrl: 'http://mooctest-crowd-service.oss-cn-hangzhou.aliyuncs.com/Others/%E9%A1%B9%E7%9B%AE%E5%AF%BC%E5%85%A5%E6%A8%A1%E6%9D%BF.xlsx'
+//   }
+//   new Promise((resolve) => {
+//     resolve(data)
+//   }).then((res) => {
+//     getTemplateExcelSuccess(res)
+//   }).catch((error) => {
+//     getTemplateExcelFail(error)
+//   })
+//   // Http.get(Apis.FILE.GET_TEMPLATE_EXCEL_FILE).then((res) => {
+//   //   getTemplateExcelSuccess(res)
+//   // }).catch((error) => {
+//   //   getTemplateExcelFail(error)
+//   // })
+// }
+//
+// //获取所有认证消息
+// export const getAllAuthentications = () => {
+//   return [{
+//     userVO: {},
+//     type: '',
+//     status: '',
+//     authenticationDetail: {}
+//   }]
+// }
+//
+// export const getCurrentAuthenInfo = () => {
+//   const individualData = {
+//     type: '个人',//企业、机构、个人
+//     //共有
+//     id: 1,
+//     userId: 3,
+//     bankAccount: '621000999000999000',
+//     address: '江苏科技大厦',
+//     status: '认证失败',
+//     rejectReason: '太强',
+//     createTime: '2019.13.12',
+//     //个人
+//     realName: '李白',
+//     IDCard: '32092111111111',
+//     IDCardPhoto: 'http://www.mooctest.net/assets/img/mooctest.png',
+//   }
+//   const enterpriseData = {
+//     type: '企业',//企业、机构、个人
+//     //共有
+//     id: 1,
+//     userId: 3,
+//     bankAccount: '621000999000999000',
+//     address: '江苏科技大厦1901',
+//     status: '',
+//     rejectReason: '',
+//     createTime: '',
+//     //企业
+//     companyName: '慕测呀',
+//     legalPersonName: '郭超啊',
+//     businessLicensePhoto: null,
+//     unifiedSocialCreditCode: '1900000000086',
+//
+//   }
+//   const agencyData = {
+//     type: '机构',//企业、机构、个人
+//     //共有
+//     id: 1,
+//     userId: 3,
+//     bankAccount: '100000000086',
+//     address: '江苏科技大厦1901',
+//     status: '',
+//     rejectReason: '123123123',
+//     createTime: '',
+//     //机构
+//     evaluationAgencyName: '慕测科技',
+//     evaluationAgencyAbilityList: ['接口测试', '安全漏洞扫描', '风险评估服务', '源代码安全审计服务', '功能测试服务', '性能测试', '功能和易用性测试'],
+//     evaluationAgencyResourceList: [
+//       {
+//         id: 0,
+//         type: '人力资源',
+//         name: '专家',
+//         totalNum: 100,
+//         availableNum: 3,
+//       },
+//       {
+//         id: 1,
+//         type: '人力资源',
+//         name: '程序员',
+//         totalNum: 100,
+//         availableNum: 3,
+//       }
+//     ],
+//     agencyPhoto: 'http://www.mooctest.net/assets/img/mooctest.png',
+//   }
+//   return new Promise((resolve) => {
+//     resolve(enterpriseData)
+//   })
+// }
+// //放弃认证
+// export const deleteAuthInfo = () => {
+//   const data = {}
+//   return new Promise((resolve) => {
+//     resolve(data)
+//   })
+//   //return Http.get(Apis.GENERAL.GET_ALL_ABILITIES)
+// }
+// //
+// export const updateIndividualAuthInfo = (userId, authInfo) => {
+//   // const data = {}
+//   // return new Promise((resolve) => {
+//   //   resolve(data)
+//   // })
+//   return Http.put(Apis.USER.UPDATE_INDIVIDUAL_AUTHENTICATION_INFO.replace('{userId}', userId), authInfo)
+// }
+// export const updateAgencyAuthInfo = (userId, authInfo) => {
+//   // const data = {}
+//   // return new Promise((resolve) => {
+//   //   resolve(data)
+//   // })
+//   return Http.put(Apis.USER.UPDATE_AGENCY_AUTHENTICATION_INFO.replace('{userId}', userId), authInfo)
+// }
+// export const updateEnterpriseAuthInfo = (userId, authInfo) => {
+//   // const data = {}
+//   // return new Promise((resolve) => {
+//   //   resolve(data)
+//   // })
+//   return Http.put(Apis.USER.UPDATE_ENTERPRISE_AUTHENTICATION_INFO.replace('{userId}', userId), authInfo)
+// }
+// //
+// export const checkFileType = (file, typeList, checkFileTypeError) => {
+//   var fileType = file.name.split('.')[file.name.split('.').length - 1].toLowerCase()
+//   if (!typeList.includes(fileType)) {
+//     checkFileTypeError()
+//   }
+//   return typeList.includes(fileType)
+// }

+ 65 - 0
src/js/projectService.js

@@ -0,0 +1,65 @@
+import Http from './http'
+import Apis from './api'
+//创建项目
+export const createProject = (project) => {
+  return Http.post(Apis.PROJECT.CREATE_PROJECT, project)
+}
+
+//修改项目
+export const updateProject = (project, projectId) => {
+  return Http.put(Apis.PROJECT.UPDATE_PROJECT.replace('{projectId}', projectId), project)
+}
+
+//查看项目
+export const getProject = (projectId) => {
+  Http.get(Apis.PROJECT.GET_PROJECT.replace('{projectId}', projectId))
+}
+
+//删除项目
+export const deleteProject = (projectId, deleteProjectSuccess, deleteProjectFail) => {
+  Http.put(Apis.PROJECT.DELETE_PROJECT.replace('{projectId}', projectId), {}).then((res) => {
+    deleteProjectSuccess(res)
+  }).catch((error) => {
+    deleteProjectFail(error)
+  })
+}
+
+//区域管理员提出接收项目申请
+export const receiveProjectRequest = (projectId, userId, receiveProjectSuccess, receiveProjectFail) => {
+  console.log('调用')
+  Http.put(Apis.PROJECT.ACCEPT_PROJECT.replace('{projectId}', projectId).replace('{userId}', userId), {}).then((res) => {
+    console.log(res)
+    receiveProjectSuccess(res)
+
+  }).catch((error) => {
+    console.log(error)
+    receiveProjectFail(error)
+  })
+}
+
+//区域管理员拒绝项目
+export const rejectProject = (projectId, rejectProjectSuccess, rejectProjectFail) => {
+  Http.put(Apis.PROJECT.REJECT_PROJECT.replace('{projectId}', projectId), {}).then((res) => {
+    rejectProjectSuccess(res)
+  }).catch((error) => {
+    rejectProjectFail(error)
+  })
+}
+
+//区域管理员提出结束项目申请
+export const submitProjectRequest = (projectId, submitProjectReuqestSuccess, submitProjectRequestFail) => {
+  Http.put(Apis.PROJECT.SUBMIT_PROJECT.replace('{projectId}', projectId), {}).then((res) => {
+    submitProjectReuqestSuccess(res)
+  }).catch((error) => {
+    submitProjectRequestFail(error)
+  })
+}
+
+//用户确认结束项目
+export const ensureEndProject = (projectId, endProjectSuccess, endProjectFail) => {
+  Http.put(Apis.PROJECT.END_PROJECT.replace('{projectId}', projectId), {}).then((res) => {
+    endProjectSuccess(res)
+  }).catch((error) => {
+    endProjectFail(error)
+  })
+}

+ 48 - 0
src/js/reportService.js

@@ -0,0 +1,48 @@
+import Http from './http'
+import Apis from './api'
+//创建项目报告
+export const createProjectReport = () => {
+
+}
+
+//创建任务报告
+export const createTaskReport = () => {
+
+}
+
+//修改项目报告
+export const updateProjectReport = () => {
+
+}
+
+//修改任务报告
+export const updateTaskReport = () => {
+
+}
+
+//查看项目报告
+export const getProjectReport = () => {
+
+}
+//查看任务报告
+export const getTaskReport = () => {
+
+}
+
+//删除项目报告
+export const deleteProjectReport = (projectId, reportId, deleteProjectReportSuccess, deleteProjectReportFail) => {
+  Http.put(Apis.REPORT.DELETE_PROJECT_REPORT.replace('{projectId}', projectId).replace('{reportId}', reportId), {}).then((res) => {
+    deleteProjectReportSuccess(res)
+  }).catch((error) => {
+    deleteProjectReportFail(error)
+  })
+}
+
+//删除任务报告
+export const deleteTaskReport = (projectId, taskId, reportId, deleteTaskReportSuccess, deleteTaskReportFail) => {
+  Http.put(Apis.REPORT.DELETE_TASK_REPORT.replace('{projectId}', projectId).replace('{taskId}', taskId).replace('{reportId}', reportId), {}).then((res) => {
+    deleteTaskReportSuccess(res)
+  }).catch((error) => {
+    deleteTaskReportFail(error)
+  })
+}

+ 69 - 0
src/js/taskService.js

@@ -0,0 +1,69 @@
+import Http from './http'
+import Apis from './api'
+//创建任务
+export const createTask = (projectId, task) => {
+  return Http.post(Apis.TASK.CREATE_TASK.replace('{projectId}', projectId), task)
+}
+
+//修改任务
+export const updateTask = (projectId, taskId, task, updateTaskSuccess, updateTaskFail) => {
+  Http.put(Apis.TASK.UPDATE_TASK.replace('{projectId}', projectId).replace('{taskId}', taskId), task).then((res) => {
+    updateTaskSuccess(res)
+  }).catch((error) => {
+    updateTaskFail(error)
+  })
+}
+
+//查看任务
+export const getTask = (projectId, taskId, getTaskSuccess, getTaskFail) => {
+  Http.get(Apis.TASK.GET_TASK.replace('{projectId}', projectId).replace('{taskId}', taskId), {}).then((res) => {
+    getTaskSuccess(res)
+  }).catch((error) => {
+    getTaskFail(error)
+  })
+}
+
+//删除任务
+export const deleteTask = (projectId, taskId, deleteTaskSuccess, deleteTaskFail) => {
+  Http.put(Apis.TASK.DELETE_TASK.replace('{projectId}', projectId).replace('taskId', taskId), {}).then((res) => {
+    deleteTaskSuccess(res)
+  }).catch((error) => {
+    deleteTaskFail(error)
+  })
+}
+
+//测评机构接受任务
+export const receiveTaskRequest = (projectId, taskId, userId, receiveTaskRequestSuccess, receiveTaskRequestFail) => {
+  Http.put(Apis.TASK.ACCEPT_TASK.replace('{projectId}', projectId).replace('{taskId}', taskId).replace('{userId}', userId), {}).then((res) => {
+    receiveTaskRequestSuccess(res)
+  }).catch((error) => {
+    receiveTaskRequestFail(error)
+  })
+
+}
+
+//测评机构提出结束任务申请
+export const submitTaskRequest = (projectId, taskId, submitTaskSuccess, submitTaskFail) => {
+  Http.put(Apis.TASK.SUBMIT_TASK.replace('{projectId}', projectId).replace('{taskId}', taskId), {}).then((res) => {
+    submitTaskSuccess(res)
+  }).catch((error) => {
+    submitTaskFail(error)
+  })
+}
+
+export const rejectTask = (projectId, taskId, rejectTaskSuccess, rejectTaskFail) => {
+  Http.put(Apis.TASK.REJECT_TASK.replace('{projectId}', projectId).replace('{taskId}', taskId), {}).then((res) => {
+    rejectTaskSuccess(res)
+  }).catch((error) => {
+    rejectTaskFail(error)
+  })
+}
+
+//区域管理员确认结束任务
+export const ensureEndTask = (projectId, taskId, endTaskSuccess, endTaskFail) => {
+  Http.put(Apis.TASK.END_TASK.replace('{projectId}', projectId).replace('{taskId}', taskId), {}).then((res) => {
+    endTaskSuccess(res)
+  }).catch((error) => {
+    endTaskFail(error)
+  })
+}

+ 0 - 0
src/js/test.js


+ 310 - 0
src/js/userService.js

@@ -0,0 +1,310 @@
+import Http from './http'
+import Apis from './api'
+//获取用户信息
+export const getCurrentUser = (getCurrentUserSuccess, getCurrentUserFail) => {
+  // const data = {
+  //   userVO: {
+  //     id: 3,
+  //     photo: 'http://www.mooctest.net/assets/img/mooctest.png',
+  //     name: '郭超',
+  //     roleList: ['区域管理员', '个人用户', '企业用户', '测评机构', '系统管理员'],
+  //     mobile: '110',
+  //     email: '12345@qq.com',
+  //   },
+  //   agency: '',
+  // }
+  // return new Promise((resolve) => {
+  //   resolve(data)
+  // })
+  return Http.get(Apis.USER.GET_CURRENT_USER)
+  // Http.get(Apis.USER.GET_CURRENT_USER).then((res) => {
+  //   getCurrentUserSuccess(res)
+  // }).catch((error) => {
+  //   getCurrentUserFail(error)
+  // })
+}
+//
+export const getRolesPermissions = (roleList) => {
+  const roles = {
+    regionManager: 'RegionalManager',
+    individualUser: 'generalUser',
+    enterpriseUser: 'enterpriseUser',
+    agency: 'evaluationAgency',
+    systemAdministrator: 'SystemAdministrator'
+  }
+  const permissions = {
+    isRegionManager: false,
+    isIndividualUser: false,
+    isEnterpriseUser: false,
+    isAgency: false,
+    isSystemAdministrator: false
+  }
+  if (roleList.includes(roles.regionManager)) {
+    permissions.isRegionManager = true
+    permissions.isEnterpriseUser = true
+    permissions.isIndividualUser = true
+  }
+  if (roleList.includes(roles.agency)) {
+    permissions.isAgency = true
+    permissions.isEnterpriseUser = true
+    permissions.isIndividualUser = true
+  }
+  if (roleList.includes(roles.enterpriseUser)) {
+    permissions.isEnterpriseUser = true
+  }
+  if (roleList.includes(roles.individualUser)) {
+    permissions.isIndividualUser = true
+  }
+  if (roleList.includes(roles.systemAdministrator)) {
+    permissions.isSystemAdministrator = true
+    permissions.isRegionManager = true
+    permissions.isAgency = true
+    permissions.isEnterpriseUser = true
+    permissions.isIndividualUser = true
+  }
+  return permissions
+}
+
+export const logout = () => {
+  sessionStorage.removeItem('user')
+  sessionStorage.removeItem('rolesPermissions')
+  return Http.get(Apis.USER.LOGOUT)
+}
+//获取当前角色可访问的url
+export const getAuthUrls = () => {
+  return [
+    '/', '/home', '/square', '/mine', '/project/create',
+    '/project/:projectId', '/project/:projectId/task/create',
+    '/project/:projectId/task/:taskId', '/project/:projectId/analyse',
+    '/report/create', '/report/:reportId', '/greenChannel/addProject', '/greenChannel/addAgency',
+    '/authentication/individual', '/authentication/enterprise',
+    '/authentication/agency', '/authentication/index'
+  ]
+  //return Http.get(Apis.USER.GET_AUTH_URLS)
+}
+
+//上传个人认证信息
+export const uploadIndividualAuthenticationInfo = (userId, userAuthInfo, uploadIndividualAuthenticationInfoSuccess, uploadIndividualAuthenticationInfoFail) => {
+  Http.post(Apis.USER.SUBMIT_INDIVIDUAL_AUTHENTICATION_INFO.replace('{userId}', userId), userAuthInfo).then((res) => {
+    uploadIndividualAuthenticationInfoSuccess(res)
+  }).catch(error => {
+    uploadIndividualAuthenticationInfoFail(error)
+  })
+}
+
+//上传企业认证信息
+export const uploadEnterpriseAuthenticationInfo = (userId, userAuthInfo, uploadEnterpriseAuthenticationInfoSuccess, uploadEnterpriseAuthenticationInfoFail) => {
+  Http.post(Apis.USER.SUBMIT_ENTERPRISE_AUTHENTICATION_INFO.replace('{userId}', userId), userAuthInfo).then((res) => {
+    uploadEnterpriseAuthenticationInfoSuccess(res)
+  }).catch(error => {
+    uploadEnterpriseAuthenticationInfoFail(error)
+  })
+}
+
+//上传机构认证信息
+export const uploadAgencyAuthenticationInfo = (userId, userAuthInfo, uploadAgencyAuthenticationInfoSuccess, uploadAgencyAuthenticationInfoFail) => {
+  Http.post(Apis.USER.SUBMIT_AGENCY_AUTHENTICATION_INFO.replace('{userId}', userId), userAuthInfo).then((res) => {
+    uploadAgencyAuthenticationInfoSuccess(res)
+  }).catch(error => {
+    uploadAgencyAuthenticationInfoFail(error)
+  })
+}
+
+//获取所有未处理认证消息
+export const getAllHandlingAuthInfo = (getAllHandlingAuthInfoSuccess, getAllHandlingAuthInfoFail) => {
+  Http.get(Apis.USER.GET_ALL_HANDLING_AUTH_INFO).then((res) => {
+    getAllHandlingAuthInfoSuccess(res)
+  }).catch((error) => {
+    getAllHandlingAuthInfoFail(error)
+  })
+}
+//获取所有已处理认证消息
+export const getAllHandledAuthInfo = (getAllHandledAuthInfoSuccess, getAllHandledAuthInfoFail) => {
+  Http.get(Apis.USER.GET_ALL_HANDLED_AUTH_INFO).then((res) => {
+    getAllHandledAuthInfoSuccess(res)
+  }).catch((error) => {
+    getAllHandledAuthInfoFail(error)
+  })
+}
+export const getCurrentIndividualAuthenInfo = (userId, getCurrentIndividualAuthenInfoSuccess, getCurrentIndividualAuthenInfoFail) => {
+  Http.get(Apis.USER.GET_INDIVIDUAL_AUTHENTICATION_INFO.replace('{userId}', userId)).then((res) => {
+    getCurrentIndividualAuthenInfoSuccess(res)
+  }).catch((error) => {
+    getCurrentIndividualAuthenInfoFail(error)
+  })
+}
+
+export const getCurrentEnterpriseAuthInfo = (userId, getCurrentEnterpriseAuthInfoSuccess, getCurrentEnterpriseAuthInfoFail) => {
+  Http.get(Apis.USER.GET_ENTERPRISE_AUTHENTICATION_INFO.replace('{userId}', userId)).then((res) => {
+    getCurrentEnterpriseAuthInfoSuccess(res)
+  }).catch((error) => {
+    getCurrentEnterpriseAuthInfoFail(error)
+  })
+}
+export const getCurrentAgencyAuthInfo = (userId, getCurrentEnterpriseAuthInfoSuccess, getCurrentEnterpriseAuthInfoFail) => {
+  Http.get(Apis.USER.GET_AGENCY_AUTHENTICATION_INFO.replace('{userId}', userId)).then((res) => {
+    getCurrentEnterpriseAuthInfoSuccess(res)
+  }).catch((error) => {
+    getCurrentEnterpriseAuthInfoFail(error)
+  })
+}
+export const getCurrentAuthenInfo = () => {
+  const individualData = {
+    type: '个人',//企业、机构、个人
+    //共有
+    id: 1,
+    userId: 3,
+    bankAccount: '621000999000999000',
+    address: '江苏科技大厦',
+    status: '认证失败',
+    rejectReason: '太强',
+    createTime: '2019.13.12',
+    //个人
+    realName: '李白',
+    IDCard: '32092111111111',
+    IDCardPhoto: 'http://www.mooctest.net/assets/img/mooctest.png',
+  }
+  const enterpriseData = {
+    type: '企业',//企业、机构、个人
+    //共有
+    id: 1,
+    userId: 3,
+    bankAccount: '621000999000999000',
+    address: '江苏科技大厦1901',
+    status: '',
+    rejectReason: '',
+    createTime: '',
+    //企业
+    companyName: '慕测呀',
+    legalPersonName: '郭超啊',
+    businessLicensePhoto: null,
+    unifiedSocialCreditCode: '1900000000086',
+
+  }
+  const agencyData = {
+    type: '机构',//企业、机构、个人
+    //共有
+    id: 1,
+    userId: 3,
+    bankAccount: '100000000086',
+    address: '江苏科技大厦1901',
+    status: '',
+    rejectReason: '123123123',
+    createTime: '',
+    //机构
+    evaluationAgencyName: '慕测科技',
+    evaluationAgencyAbilityList: ['接口测试', '安全漏洞扫描', '风险评估服务', '源代码安全审计服务', '功能测试服务', '性能测试', '功能和易用性测试'],
+    evaluationAgencyResourceList: [
+      {
+        id: 0,
+        type: '人力资源',
+        name: '专家',
+        totalNum: 100,
+        availableNum: 3,
+      },
+      {
+        id: 1,
+        type: '人力资源',
+        name: '程序员',
+        totalNum: 100,
+        availableNum: 3,
+      }
+    ],
+    agencyPhoto: 'http://www.mooctest.net/assets/img/mooctest.png',
+  }
+  return new Promise((resolve) => {
+    resolve(enterpriseData)
+  })
+}
+//放弃认证
+export const deleteAuthInfo = () => {
+  const data = {}
+  return new Promise((resolve) => {
+    resolve(data)
+  })
+  //return Http.get(Apis.GENERAL.GET_ALL_ABILITIES)
+}
+//
+export const updateIndividualAuthInfo = (userId, authInfo, updateIndividualAuthInfoSuccess, updateIndividualAuthInfoFail) => {
+  // const data = {}
+  // return new Promise((resolve) => {
+  //   resolve(data)
+  // })
+  Http.put(Apis.USER.UPDATE_INDIVIDUAL_AUTHENTICATION_INFO.replace('{userId}', userId), authInfo).then((res) => {
+    updateIndividualAuthInfoSuccess(res)
+  }).catch((error) => {
+    updateIndividualAuthInfoFail(error)
+  })
+}
+export const updateAgencyAuthInfo = (userId, authInfo, updateAgencyAuthInfoSuccess, updateAgencyAuthInfoFail) => {
+  Http.put(Apis.USER.UPDATE_AGENCY_AUTHENTICATION_INFO.replace('{userId}', userId), authInfo).then((res) => {
+    updateAgencyAuthInfoSuccess(res)
+  }).catch((error) => {
+    updateAgencyAuthInfoFail(error)
+  })
+}
+export const updateAgencyResourceAndAbility = (userId, authInfo, updateAgencyResourceAndAbilitySuccess, updateAgencyResourceAndAbilityFail) => {
+  Http.post(Apis.USER.UPDATE_AGENCY_RESOURCE_AND_ABILITY.replace('{userId}', userId), authInfo).then((res) => {
+    updateAgencyResourceAndAbilitySuccess(res)
+  }).catch((error) => {
+    updateAgencyResourceAndAbilityFail(error)
+  })
+}
+export const updateEnterpriseAuthInfo = (userId, authInfo, updateEnterpriseAuthInfoSuccess, updateEnterpriseAuthInfoFail) => {
+  // const data = {}
+  // return new Promise((resolve) => {
+  //   resolve(data)
+  // })
+  Http.put(Apis.USER.UPDATE_ENTERPRISE_AUTHENTICATION_INFO.replace('{userId}', userId), authInfo).then((res) => {
+    updateEnterpriseAuthInfoSuccess(res)
+  }).catch((error) => {
+    updateEnterpriseAuthInfoFail(error)
+  })
+}
+
+export const checkPassAuth = (type, userId, checkPassAuthSuccess, checkPassAuthFail) => {
+  if (type == 'agency') {
+    Http.put(Apis.USER.PASS_AGENCY_AUTH.replace('{userId}', userId), {}).then((res) => {
+      checkPassAuthSuccess(res)
+    }).catch((error) => {
+      checkPassAuthFail(error)
+    })
+  }
+  if (type == 'personal') {
+    Http.put(Apis.USER.PASS_INDIVIDUAL_AUTH.replace('{userId}', userId), {}).then((res) => {
+      checkPassAuthSuccess(res)
+    }).catch((error) => {
+      checkPassAuthFail(error)
+    })
+  }
+  if (type == 'enterprise') {
+    Http.put(Apis.USER.PASS_ENTERPRISE_AUTH.replace('{userId}', userId), {}).then((res) => {
+      checkPassAuthSuccess(res)
+    }).catch((error) => {
+      checkPassAuthFail(error)
+    })
+  }
+}
+export const checkRejectAuth = (type, userId, data, checkRejectAuthSuccess, checkRejectAuthFail) => {
+  if (type == 'agency') {
+    Http.put(Apis.USER.REJECT_AGENCY_AUTH.replace('{userId}', userId), data).then((res) => {
+      checkRejectAuthSuccess(res)
+    }).catch((error) => {
+      checkRejectAuthFail(error)
+    })
+  }
+  if (type == 'personal') {
+    Http.put(Apis.USER.REJECT_INDIVIDUAL_AUTH.replace('{userId}', userId), data).then((res) => {
+      checkRejectAuthSuccess(res)
+    }).catch((error) => {
+      checkRejectAuthFail(error)
+    })
+  }
+  if (type == 'enterprise') {
+    Http.put(Apis.USER.REJECT_ENTERPRISE_AUTH.replace('{userId}', userId), data).then((res) => {
+      checkRejectAuthSuccess(res)
+    }).catch((error) => {
+      checkRejectAuthFail(error)
+    })
+  }
+}

+ 180 - 43
src/main.js

@@ -4,55 +4,189 @@ import Vue from 'vue'
 import App from './App'
 import router from './router'
 import 'font-awesome/css/font-awesome.css'
-import './style/main.scss';
-
-
+import './style/main.scss'
+import {getAuthUrls, getCurrentUser, getRolesPermissions, storageGet, storageSave} from '@/js/index'
+import {notify} from '@/constants/index'
 import {
-  Carousel, CarouselItem, Row, Col, Table, TableColumn, Form, FormItem, Button, ButtonGroup,
-  Menu, Submenu, MenuItem, MenuItemGroup, Input, InputNumber, Radio, RadioGroup, RadioButton,
-  Checkbox, CheckboxButton, CheckboxGroup, DatePicker, TimeSelect, TimePicker, Switch, Select,
-  Option, Upload, Tabs, TabPane, Collapse, CollapseItem, MessageBox, Message, Notification,
+  Avatar,
+  Badge,
+  Button,
+  ButtonGroup,
+  Card,
+  Carousel,
+  CarouselItem,
+  Checkbox,
+  CheckboxButton,
+  CheckboxGroup,
+  Col,
+  Collapse,
+  CollapseItem,
+  DatePicker,
+  Dialog,
+  Dropdown,
+  DropdownItem,
+  DropdownMenu,
+  Form,
+  FormItem,
+  Image,
+  Input,
+  InputNumber,
+  Link,
+  Loading,
+  Menu,
+  MenuItem,
+  MenuItemGroup,
+  Message,
+  MessageBox,
+  Notification,
+  Option,
+  Pagination,
+  Popover,
+  Radio,
+  RadioButton,
+  RadioGroup,
+  Row,
+  Select,
+  Submenu,
+  Switch,
+  Table,
+  TableColumn,
+  TabPane,
+  Tabs,
+  Tag,
+  TimePicker,
+  TimeSelect,
+  Tooltip,
+  Upload,
 } from 'element-ui'
+function getCurrentUserSuccess(res){
+
+}
+// var _hmt = _hmt || [];
+// (function() {
+//   var hm = document.createElement("script");
+//   hm.src = "https://hm.baidu.com/hm.js?0e3bd98236bd62558926fc433751d60c";
+//   var s = document.getElementsByTagName("script")[0];
+//   s.parentNode.insertBefore(hm, s);
+// })();
+router.beforeEach((to, from, next) => {
+  // if (_hmt) {
+  //   if (to.path) {
+  //     _hmt.push(['_trackPageview', '/#' + to.fullPath]);
+  //   }
+  // }
+  const urls = getAuthUrls()
+  if (storageGet('user') == null) {
+    getCurrentUser().then((res) => {
+      storageSave('user', res)
+      storageSave('rolesPermissions', getRolesPermissions(res.roleList))
+      if (to.matched.some(record => record.meta.requireAuth)) { // 判断该路由是否需要登录权限
+        if (sessionStorage.userName === '2' && urls.includes(to.matched[0].path)) { // 判断缓存里面是否有 userName  //在登录的时候设置它的值
+          next()
+        } else {
+          next({
+            path: '/',
+            query: {
+              redirect: to.fullPath
+            } // 将跳转的路由path作为参数,登录成功后跳转到该路由
+          })
+        }
+      } else {
+        next()
+      }
+    }).catch((error) => {
+      notify('warning', '请登录')
+      if (to.matched.some(record => record.meta.requireAuth)) { // 判断该路由是否需要登录权限
+        if (sessionStorage.userName === '2' && urls.includes(to.matched[0].path)) { // 判断缓存里面是否有 userName  //在登录的时候设置它的值
+          next()
+        } else {
+          next({
+            path: '/',
+            query: {
+              redirect: to.fullPath
+            } // 将跳转的路由path作为参数,登录成功后跳转到该路由
+          })
+        }
+      } else {
+        next()
+      }
+    })
+  } else {
+    if (to.matched.some(record => record.meta.requireAuth)) { // 判断该路由是否需要登录权限
+      if (sessionStorage.userName === '2' && urls.includes(to.matched[0].path)) { // 判断缓存里面是否有 userName  //在登录的时候设置它的值
+        next()
+      } else {
+        next({
+          path: '/',
+          query: {
+            redirect: to.fullPath
+          } // 将跳转的路由path作为参数,登录成功后跳转到该路由
+        })
+      }
+    } else {
+      next()
+    }
+  }
+  //console.log(to.matched[0].path)
+  //console.log(urls.includes(to.matched[0].path))
+
+})
+
+// require('./mock.js')
 Vue.use(Carousel)
 Vue.use(CarouselItem)
 Vue.use(Row)
 Vue.use(Col)
-Vue.use(Table);
-Vue.use(TableColumn);
-Vue.use(Form);
-Vue.use(FormItem);
-Vue.use(Button);
-Vue.use(ButtonGroup);
-Vue.use(Menu);
-Vue.use(Submenu);
-Vue.use(MenuItem);
-Vue.use(MenuItemGroup);
-Vue.use(Input);
-Vue.use(InputNumber);
-Vue.use(Radio);
-Vue.use(RadioGroup);
-Vue.use(RadioButton);
-Vue.use(Checkbox);
-Vue.use(CheckboxButton);
-Vue.use(CheckboxGroup);
-Vue.use(DatePicker);
-Vue.use(TimeSelect);
-Vue.use(TimePicker);
-Vue.use(Switch);
-Vue.use(Select);
-Vue.use(Option);
-Vue.use(Upload);
-Vue.use(Tabs);
-Vue.use(TabPane);
-Vue.use(Collapse);
-Vue.use(CollapseItem);
+Vue.use(Table)
+Vue.use(TableColumn)
+Vue.use(Form)
+Vue.use(FormItem)
+Vue.use(Button)
+Vue.use(ButtonGroup)
+Vue.use(Menu)
+Vue.use(Submenu)
+Vue.use(MenuItem)
+Vue.use(MenuItemGroup)
+Vue.use(Input)
+Vue.use(InputNumber)
+Vue.use(Radio)
+Vue.use(RadioGroup)
+Vue.use(RadioButton)
+Vue.use(Checkbox)
+Vue.use(CheckboxButton)
+Vue.use(CheckboxGroup)
+Vue.use(DatePicker)
+Vue.use(TimeSelect)
+Vue.use(TimePicker)
+Vue.use(Switch)
+Vue.use(Select)
+Vue.use(Option)
+Vue.use(Upload)
+Vue.use(Tabs)
+Vue.use(TabPane)
+Vue.use(Collapse)
+Vue.use(CollapseItem)
+Vue.use(Dialog)
+Vue.use(Card)
+Vue.use(Tag)
+Vue.use(Avatar)
+Vue.use(Pagination)
+Vue.use(Link)
+Vue.use(Loading)
+Vue.use(Tooltip)
+Vue.use(Dropdown)
+Vue.use(DropdownItem)
+Vue.use(DropdownMenu)
+Vue.use(Image)
+Vue.use(Badge)
+Vue.use(Popover)
 
-Vue.prototype.$msgbox = MessageBox;
-Vue.prototype.$alert = MessageBox.alert;
-Vue.prototype.$confirm = MessageBox.confirm;
-Vue.prototype.$prompt = MessageBox.prompt;
-Vue.prototype.$notify = Notification;
-Vue.prototype.$message = Message;
+Vue.prototype.$msgbox = MessageBox
+Vue.prototype.$alert = MessageBox.alert
+Vue.prototype.$confirm = MessageBox.confirm
+Vue.prototype.$prompt = MessageBox.prompt
+Vue.prototype.$notify = Notification
+Vue.prototype.$message = Message
 
 Vue.config.productionTip = false
 
@@ -60,6 +194,9 @@ Vue.config.productionTip = false
 new Vue({
   el: '#app',
   router,
-  components: { App },
+  data:{
+    Bus:new Vue()
+  },
+  components: {App},
   template: '<App/>'
 })

+ 32 - 0
src/mock.js

@@ -0,0 +1,32 @@
+// 引入mockjs
+const Mock = require('mockjs')
+import Apis from './js/api.js'
+//const Apis = require('./js/api')
+const createAnalyseDemandMock = require('./mock/createAnalyseDemandMock')
+const createProjectMock = require('./mock/createProjectMock')
+const createReportMock = require('./mock/createReportMock')
+const createTaskMock = require('./mock/createTaskMock')
+const getMyCrowdTestMock = require('./mock/getMyCrowdTestMock')
+const getProjectDetailMock = require('./mock/getProjectDetailMock')
+const getReportDetailMock = require('./mock/getReportDetailMock')
+const getTaskDetailMock = require('./mock/getTaskDetailMock')
+const getHomePageMock = require('./mock/getHomePageMock')
+const getSquarePageMock = require('./mock/getSquarePageMock')
+const updateProjectMock = require('./mock/updateProjectMock')
+const updateTaskMock = require('./mock/updateTaskMock')
+const updateReportMock = require('./mock/updateReportMock')
+
+//Mock.mock( url, post/get , 返回的数据);
+Mock.mock(Apis.PROJECT.CREATE_ANALYSE_DEMAND_SUBMIT, 'post', createAnalyseDemandMock.data)
+Mock.mock(Apis.PROJECT.CREATE_PROJECT_SUBMIT, 'post', createProjectMock.data)
+Mock.mock(Apis.REPORT.CREATE_REPORT_SUBMIT, 'post', createReportMock.data)
+Mock.mock(Apis.TASK.CREATE_TASK, 'post', createTaskMock.data)
+Mock.mock(Apis.PAGE.HOME_PAGE, 'get', getHomePageMock.data)
+Mock.mock(Apis.PAGE.SQUARE_PAGE, 'get', getSquarePageMock.data)
+Mock.mock(Apis.PAGE.PROJECT_DETAIL_PAGE, 'get', getProjectDetailMock.data)
+Mock.mock(Apis.PAGE.REPORT_DETAIL_PAGE, 'get', getReportDetailMock.data)
+Mock.mock('/api/project/pro1564487183259/task/pro1564487183259_task1564487274060/', 'get', getTaskDetailMock.data)
+Mock.mock(Apis.PAGE.MY_CROWD_TEST_PAGE, 'get', getMyCrowdTestMock.data)
+Mock.mock(Apis.PROJECT.UPDATE_PROJECT_SUBMIT, 'put', updateProjectMock.data)
+Mock.mock(Apis.REPORT.UPDATE_REPORT_SUBMIT, 'put', updateReportMock.data)
+Mock.mock(Apis.TASK.UPDATE_TASK_SUBMIT, 'put', updateTaskMock.data)

+ 6 - 0
src/mock/createAnalyseDemandMock.js

@@ -0,0 +1,6 @@
+var Mock = require('mockjs')
+var data = Mock.mock(null)
+
+export {
+  data
+}

+ 6 - 0
src/mock/createProjectMock.js

@@ -0,0 +1,6 @@
+var Mock = require('mockjs')
+var data = Mock.mock(null)
+
+export {
+  data
+}

+ 6 - 0
src/mock/createReportMock.js

@@ -0,0 +1,6 @@
+var Mock = require('mockjs')
+var data = Mock.mock(null)
+
+export {
+  data
+}

+ 6 - 0
src/mock/createTaskMock.js

@@ -0,0 +1,6 @@
+var Mock = require('mockjs')
+var data = Mock.mock(null)
+
+export {
+  data
+}

+ 96 - 0
src/mock/getHomePageMock.js

@@ -0,0 +1,96 @@
+var Mock = require('mockjs')
+var data = Mock.mock({
+  hotTaskList: [
+    {
+      id: 0,
+      title: '发送群文件测试',
+      description: '任务描述文字xxxx',
+      price: '30',
+      serviceType: 1,
+      status: 0,
+      projectId: 123
+    },
+    {
+      id: 1,
+      title: '多人聊天发送文件测试',
+      description: '任务描述文字xxxx',
+      price: '10',
+      serviceType: 0,
+      status: 1,
+      projectId: 234
+    },
+    {
+      id: 2,
+      title: '浏览器波洞星球',
+      description: '任务描述文字xxxx',
+      price: '10',
+      serviceType: 2,
+      status: 0,
+      projectId: 345
+    },
+    {
+      id: 3,
+      title: '举报支持选择聊天记录(安全)',
+      description: '任务描述文字xxxx',
+      price: '0',
+      serviceType: 1,
+      status: 1,
+      projectId: 456
+    }
+  ],
+  institutionRank: [
+    {
+      logo: 'http://www.mooctest.net/assets/img/mooctest.png',
+      name: '慕测科技'
+    },
+    {
+      logo: 'https://docs.alibabagroup.com/assets2/images/cn/global/logo_header.png',
+      name: '上海软件'
+    },
+    {
+      logo: 'http://www.mooctest.net/assets/img/mooctest.png',
+      name: 'QQ众测'
+    },
+    {
+      logo: 'https://docs.alibabagroup.com/assets2/images/cn/global/logo_header.png',
+      name: '阿里巴巴'
+    },
+    {
+      logo: 'https://docs.alibabagroup.com/assets2/images/cn/global/logo_header.png',
+      name: '阿里巴巴'
+    }
+  ],
+  personRank: [
+    {
+      logo: 'http://www.mooctest.net/assets/img/mooctest.png',
+      name: '小王',
+      number: '200',
+    },
+    {
+      logo: 'https://docs.alibabagroup.com/assets2/images/cn/global/logo_header.png',
+      name: '小黄',
+      number: '190',
+    },
+    {
+      logo: 'http://www.mooctest.net/assets/img/mooctest.png',
+      name: '小莉',
+      number: '120',
+    },
+    {
+      logo: 'https://docs.alibabagroup.com/assets2/images/cn/global/logo_header.png',
+      name: '小张',
+      number: '80',
+    },
+    {
+      logo: 'https://docs.alibabagroup.com/assets2/images/cn/global/logo_header.png',
+      name: '小张',
+      number: '70',
+    }
+  ],
+  imgList: ['../assets/img/home_ban1.jpg', '../assets/img/home_ban2.jpg'],
+
+})
+
+export {
+  data
+}

+ 139 - 0
src/mock/getMyCrowdTestMock.js

@@ -0,0 +1,139 @@
+var Mock = require('mockjs')
+var data = Mock.mock({
+  unFinishedTaskList: [
+    {
+      id: 0,
+      coverImgUrl: 'http://www.mooctest.net/assets/img/mooctest.png',
+      projectId: 1123,
+      title: '发送群文件测试',
+      platform: [0, 1],
+      description: '任务描述文字xxxx',
+      price: '30',
+      serviceType: 1,
+      participantNum: 30,
+      status: 0
+    },
+    {
+      id: 1,
+      coverImgUrl: 'http://www.mooctest.net/assets/img/mooctest.png',
+      projectId: 1123,
+      title: '多人聊天发送文件测试',
+      platform: [0],
+      description: '任务描述文字xxxx',
+      price: '10',
+      serviceType: 0,
+      participantNum: 0,
+      status: 1
+    },
+    {
+      id: 2,
+      coverImgUrl: 'http://www.mooctest.net/assets/img/mooctest.png',
+      projectId: 1123,
+      title: '浏览器波洞星球',
+      platform: [1],
+      description: '任务描述文字xxxx',
+      price: '10',
+      serviceType: 2,
+      participantNum: 21,
+      status: 0
+    },
+    {
+      id: 3,
+      coverImgUrl: 'http://www.mooctest.net/assets/img/mooctest.png',
+      projectId: 1123,
+      title: '举报支持选择聊天记录(安全)',
+      platform: [0, 1, 2],
+      description: '任务描述文字xxxx',
+      price: '0',
+      serviceType: 1,
+      participantNum: 1,
+      status: 1
+    },
+  ],
+  finishedTaskList: [
+    {
+      id: 0,
+      coverImgUrl: 'http://www.mooctest.net/assets/img/mooctest.png',
+      projectId: 1123,
+      title: '发送群文件测试',
+      platform: [0, 1],
+      description: '任务描述文字xxxx',
+      price: '30',
+      serviceType: 1,
+      participantNum: 30,
+      status: 0
+    },
+    {
+      id: 1,
+      coverImgUrl: 'http://www.mooctest.net/assets/img/mooctest.png',
+      projectId: 1123,
+      title: '多人聊天发送文件测试',
+      platform: [0],
+      description: '任务描述文字xxxx',
+      price: '10',
+      serviceType: 0,
+      participantNum: 0,
+      status: 1
+    },
+    {
+      id: 2,
+      coverImgUrl: 'http://www.mooctest.net/assets/img/mooctest.png',
+      projectId: 1123,
+      title: '浏览器波洞星球',
+      platform: [1],
+      description: '任务描述文字xxxx',
+      price: '10',
+      serviceType: 2,
+      participantNum: 21,
+      status: 0
+    },
+    {
+      id: 3,
+      coverImgUrl: 'http://www.mooctest.net/assets/img/mooctest.png',
+      projectId: 1123,
+      title: '举报支持选择聊天记录(安全)',
+      platform: [0, 1, 2],
+      description: '任务描述文字xxxx',
+      price: '0',
+      serviceType: 1,
+      participantNum: 1,
+      status: 1
+    },
+  ],
+  appliedProjectList: [
+    {
+      id: 1,
+      code: '27382hdsjkfdskfK',
+      name: '多人聊天发送文件测试',
+      platform: [0],
+      description: '任务描述文字xxxx',
+      price: '10'
+    },
+    {
+      id: 2,
+      code: 'jzlk9dfsndfsmd ',
+      name: '多人聊天发送文件测试',
+      platform: [0, 1],
+      description: '任务描述文字xxxx',
+      price: '90'
+    },
+    {
+      id: 3,
+      code: '437849sdbsjbsf',
+      name: '多人聊天发送文件测试',
+      platform: [1, 2],
+      description: '任务描述文字xxxx',
+      price: '50'
+    }
+  ],
+  user: {
+    id: 123,
+    name: '李三',
+    score: 100,
+    prestige: 100,
+  }
+})
+
+export {
+  data
+}

+ 57 - 0
src/mock/getProjectDetailMock.js

@@ -0,0 +1,57 @@
+var Mock = require('mockjs')
+var data = Mock.mock({
+  'projectDetails': {
+    'id': 'PROJECT_1',
+    'name': '慕测平台',
+    'contactName': '郭超超',
+    'contactPhone': '18032653383',
+    'type': '1',
+    'platform': 'ceshi',
+    'desc': 'ceshi',
+    'doc': 'ceshi',
+    'file': 'cehsi',
+    'resource': 1,
+    'location': {
+      'provinceCode': '100',
+      'cityCode': '2333'
+    },
+    'institution': 6,
+    'datetime': '2019-07-29T20:54:23.000+0000',
+    'price': 20.0,
+    'budget': 20.0,
+    'usage': null
+  },
+  'taskList': [
+    {
+      'id': 1,
+      'name': '慕测平台-任务一',
+      'crowdTestProjectId': null,
+      'evaluationAgencyId': 1,
+      'type': '0',
+      'description': null,
+      'requirementFile': null,
+      'quotedPrice': 10.0,
+      'fixedPrice': null,
+      'status': 'HAS_CREATED',
+      'createTime': '2019-07-29T21:08:54.000+0000'
+    },
+    {
+      'id': 2,
+      'name': '慕测平台-任务二',
+      'crowdTestProjectId': null,
+      'evaluationAgencyId': 2,
+      'type': '0',
+      'description': null,
+      'requirementFile': null,
+      'quotedPrice': 10.0,
+      'fixedPrice': null,
+      'status': 'HAS_CREATED',
+      'createTime': '2019-07-29T21:08:56.000+0000'
+    }
+  ],
+  'reportList': null
+})
+
+export {
+  data
+}

+ 27 - 0
src/mock/getReportDetailMock.js

@@ -0,0 +1,27 @@
+var Mock = require('mockjs')
+var data = Mock.mock({
+  'report': {
+    'name': '测试报告1',
+    //报告摘要
+    'abstract': {
+      //测试对象
+      'target': 'aaaaaaaaaa',
+      //测试内容
+      'content': 'aaaaaaaaaaa'
+    },
+    'file': [{'name': 'report5', 'url': 'report5.excel'}],
+    // 0: "接口测试",
+    // 1: "安全漏洞扫描",
+    // 2: "风险评估服务",
+    // 3: "源代码安全审计服务",
+    // 4: "功能测试服务",
+    // 5: "性能测试",
+    // 6: "功能和易用性测试",
+    'type': '0',
+    'conclusion': 'app挺好'
+  }
+})
+
+export {
+  data
+}

+ 100 - 0
src/mock/getSquarePageMock.js

@@ -0,0 +1,100 @@
+var Mock = require('mockjs')
+var data = Mock.mock({
+  'taskList': [
+    {
+      //任务id
+      'id': 0,
+      //任务封面图
+      'coverImgUrl': '',
+      //所属项目id
+      'projectId': 1234,
+      //任务标题
+      'title': '发送群文件测试',
+      //任务平台;0:Andriod;1:IOS;2:Web
+      'platform': [0, 1],
+      //任务描述
+      'description': '任务描述文字xxxx',
+      //任务标价
+      'price': '30',
+      //任务服务类型
+      // 0: "接口测试",
+      // 1: "安全漏洞扫描",
+      // 2: "风险评估服务",
+      // 3: "源代码安全审计服务",
+      // 4: "功能测试服务",
+      // 5: "性能测试",
+      // 6: "功能和易用性测试",
+      'serviceType': 1,
+      //任务参与者
+      'participantNum': 30,
+      // 0: "已结束", //已结束
+      // 1: "进行中" //进行中
+      //任务状态
+      'status': 0
+    },
+    {
+      'id': 1,
+      'coverImgUrl': '',
+      'projectId': 1234,
+      'title': '多人聊天发送文件测试',
+      'platform': [0],
+      'description': '任务描述文字xxxx',
+      'price': '10',
+      'serviceType': 0,
+      'participantNum': 0,
+      'status': 1
+    },
+    {
+      'id': 1,
+      'coverImgUrl': '',
+      'projectId': 1234,
+      'title': '多人聊天发送文件测试',
+      'platform': [0],
+      'description': '任务描述文字xxxx',
+      'price': '10',
+      'serviceType': 0,
+      'participantNum': 0,
+      'status': 1
+    },
+    {
+      'id': 1,
+      'coverImgUrl': '',
+      'projectId': 1234,
+      'title': '多人聊天发送文件测试',
+      'platform': [0],
+      'description': '任务描述文字xxxx',
+      'price': '10',
+      'serviceType': 0,
+      'participantNum': 0,
+      'status': 1
+    },
+    {
+      'id': 1,
+      'coverImgUrl': '',
+      'projectId': 1234,
+      'title': '多人聊天发送文件测试',
+      'platform': [0],
+      'description': '任务描述文字xxxx',
+      'price': '10',
+      'serviceType': 0,
+      'participantNum': 0,
+      'status': 1
+    },
+    {
+      'id': 1,
+      'coverImgUrl': '',
+      'projectId': 1234,
+      'title': '多人聊天发送文件测试',
+      'platform': [0],
+      'description': '任务描述文字xxxx',
+      'price': '10',
+      'serviceType': 0,
+      'participantNum': 0,
+      'status': 1
+    }
+  ]
+})
+
+export {
+  data
+}

+ 84 - 0
src/mock/getTaskDetailMock.js

@@ -0,0 +1,84 @@
+var Mock = require('mockjs')
+var data = Mock.mock({
+  //任务信息
+  'crowdTaskVO': {
+    //任务id
+    'id': 1,
+    //任务所属项目id
+    'projectId': 234,
+    //任务标题
+    'title': '多人聊天发送文件测试',
+    //任务描述
+    'description': '任务描述文字xxxx',
+    'budget':0,
+    //任务定价
+    'price': 10,
+    //项目发布类型:定向或非定向
+    // 0: "定向",
+    // 1: "区域",
+    // 2: "广场",
+    'resource': '1',
+    //当任务发布类型为0或2时,location字段无效;发布类型为1时,location字段表示接收任务的区域
+    'location': {'provinceCode': '3200', 'cityCode': '3201'},
+    //当任务发布类型为1或2时,institution字段无效;发布类型为0时,institution字段表示接收任务的区域
+    'institution': '',
+    //任务服务类型
+    // 0: "接口测试",
+    // 1: "安全漏洞扫描",
+    // 2: "风险评估服务",
+    // 3: "源代码安全审计服务",
+    // 4: "功能测试服务",
+    // 5: "性能测试",
+    // 6: "功能和易用性测试",
+    'serviceType': 0,
+    /*任务状态
+              0: "已结束",
+              1: "进行中"
+              */
+    'status': 1,
+    //任务截止时间Date()类型
+    //new Date("2018-11-11 23:11:11")
+    'datetime': 'Sun Nov 11 2018 23:11:11 GMT+0800 (中国标准时间)'
+  },
+  // 任务报告列表
+  'crowdReportVOList': [
+    {
+      //报告id
+      'id': 2,
+      //报告类型
+      // 0: "接口测试",
+      // 1: "安全漏洞扫描",
+      // 2: "风险评估服务",
+      // 3: "源代码安全审计服务",
+      // 4: "功能测试服务",
+      // 5: "性能测试",
+      // 6: "功能和易用性测试",
+      'type': 1,
+      'file': [{
+        //报告文件名
+        'name': 'report2',
+        //报告文件url
+        'url': 'report2.excel'
+      }]
+    },
+    {
+      'id': 3,
+      // 0: "接口测试",
+      // 1: "安全漏洞扫描",
+      // 2: "风险评估服务",
+      // 3: "源代码安全审计服务",
+      // 4: "功能测试服务",
+      // 5: "性能测试",
+      // 6: "功能和易用性测试",
+      'type': 2,
+      'file': [{
+        'name': 'report3',
+        'url': 'report3.excel'
+      }]
+    }
+  ]
+})
+
+export {
+  data
+}

+ 10 - 0
src/mock/test.js

@@ -0,0 +1,10 @@
+var Mock = require('mockjs')
+var data = Mock.mock({
+  'list|1-10': [{
+    'id|+1': 1
+  }]
+})
+
+export {
+  data
+};

+ 6 - 0
src/mock/updateProjectMock.js

@@ -0,0 +1,6 @@
+var Mock = require('mockjs')
+var data = Mock.mock(null)
+
+export {
+  data
+}

+ 6 - 0
src/mock/updateReportMock.js

@@ -0,0 +1,6 @@
+var Mock = require('mockjs')
+var data = Mock.mock(null)
+
+export {
+  data
+}

+ 6 - 0
src/mock/updateTaskMock.js

@@ -0,0 +1,6 @@
+var Mock = require('mockjs')
+var data = Mock.mock(null)
+
+export {
+  data
+}

+ 179 - 20
src/router/index.js

@@ -11,10 +11,8 @@ import Project from '@/components/project/Project'
 import ProjectCreate from '@/components/project/ProjectCreate'
 import AnalyseDemand from '@/components/project/AnalyseDemand'
 
-import Report from '@/components/report/Report'
-import ReportCreate from '@/components/report/ReportCreate'
-
-
+import ProjectAdd from '@/components/cheat/ProjectAdd'
+import AgencyAdd from '@/components/cheat/AgencyAdd'
 
 Vue.use(Router)
 
@@ -23,57 +21,218 @@ export default new Router({
     {
       path: '/',
       name: 'Index',
-      component: Home
+      component: Home,
+      meta: {
+        title: '',
+        requireAuth: false,  // false表示不需要登录,true表示需要登录
+      },
     },
     {
       path: '/home',
       name: 'Home',
-      component: Home
+      component: resolve => require(['@/components/Home.vue'], resolve),
+      meta: {
+        title: '',
+        requireAuth: false,
+      },
     },
     {
       path: '/square',
       name: 'Square',
-      component: Square
+      component: resolve => require(['@/components/Square.vue'], resolve),
+      meta: {
+        title: '',
+        requireAuth: false,
+      },
     },
     {
       path: '/mine',
       name: 'Mine',
-      component: Mine
+      component: resolve => require(['@/components/Mine.vue'], resolve),
+      meta: {
+        title: '',
+        requireAuth: false,
+      },
     },
     {
       path: '/project/create',
       name: 'ProjectCreate',
-      component: ProjectCreate
+      component: resolve => require(['@/components/project/ProjectCreate.vue'], resolve),
+      meta: {
+        title: '',
+        requireAuth: false,
+      },
     },
     {
       path: '/project/:projectId',
       name: 'Project',
-      component: Project
+      component: resolve => require(['@/components/project/Project.vue'], resolve),
+      meta: {
+        title: '',
+        requireAuth: false,
+      },
     },
     {
       path: '/project/:projectId/task/create',
       name: 'TaskCreate',
-      component: TaskCreate
+      component: resolve => require(['@/components/task/TaskCreate.vue'], resolve),
+      meta: {
+        title: '',
+        requireAuth: false,
+      },
     },
     {
       path: '/project/:projectId/task/:taskId',
       name: 'Task',
-      component: Task
+      component: resolve => require(['@/components/task/Task.vue'], resolve),
+      meta: {
+        title: '',
+        requireAuth: false,
+      },
     },
     {
       path: '/project/:projectId/analyse',
       name: 'AnalyseDemand',
-      component: AnalyseDemand
+      component: resolve => require(['@/components/project/AnalyseDemand.vue'], resolve),
+      meta: {
+        title: '',
+        requireAuth: false,
+      },
+    },
+    {
+      path: '/project/:projectId/report/create',
+      name: 'ProjectReportCreate',
+      component: resolve => require(['@/components/report/ProjectReportCreate.vue'], resolve),
+      meta: {
+        title: '',
+        requireAuth: false,
+      },
+    },
+    {
+      path: '/project/:projectId/task/:taskId/report/create',
+      name: 'TaskReportCreate',
+      component: resolve => require(['@/components/report/TaskReportCreate.vue'], resolve),
+      meta: {
+        title: '',
+        requireAuth: false,
+      },
+    },
+    {
+      path: '/project/:projectId/task/:taskId/report/:reportId',
+      name: 'TaskReport',
+      component: resolve => require(['@/components/report/TaskReport.vue'], resolve),
+      meta: {
+        title: '',
+        requireAuth: false,
+      },
     },
     {
-      path: '/report/create',
-      name: 'ReportCreate',
-      component: ReportCreate
+      path: '/project/:projectId/report/:reportId',
+      name: 'ProjectReport',
+      component: resolve => require(['@/components/report/ProjectReport.vue'], resolve),
+      meta: {
+        title: '',
+        requireAuth: false,
+      },
     },
     {
-      path: '/report/:reportId',
-      name: 'Report',
-      component: Report
-    }
+      path: '/greenChannel/addProject',
+      name: 'ProjectAdd',
+      component: resolve => require(['@/components/cheat/ProjectAdd.vue'], resolve),
+      meta: {
+        title: '',
+        requireAuth: false,
+      },
+    },
+    {
+      path: '/greenChannel/addAgency',
+      name: 'AgencyAdd',
+      component: resolve => require(['@/components/cheat/AgencyAdd.vue'], resolve),
+      meta: {
+        title: '',
+        requireAuth: false,
+      },
+    },
+    {
+      path: '/authentication/individual/create',
+      name: 'IndividualAuthenticationCreate',
+      component: resolve => require(['@/components/authen/IndividualAuthenticationCreate.vue'], resolve),
+      meta: {
+        title: '',
+        requireAuth: false,
+      },
+    },
+    {
+      path: '/authentication/enterprise/create',
+      name: 'EnterpriseAuthenticationCreate',
+      component: resolve => require(['@/components/authen/EnterpriseAuthenticationCreate.vue'], resolve),
+      meta: {
+        title: '',
+        requireAuth: false,
+      },
+    },
+    {
+      path: '/authentication/agency/create',
+      name: 'AgencyAuthenticationCreate',
+      component: resolve => require(['@/components/authen/AgencyAuthenticationCreate.vue'], resolve),
+      meta: {
+        title: '',
+        requireAuth: false,
+      },
+    },
+    {
+      path: '/authentication/individual/:userId',
+      name: 'IndividualAuthentication',
+      component: resolve => require(['@/components/authen/IndividualAuthentication.vue'], resolve),
+      meta: {
+        title: '',
+        requireAuth: false,
+      },
+    },
+    {
+      path: '/authentication/enterprise/:userId',
+      name: 'EnterpriseAuthentication',
+      component: resolve => require(['@/components/authen/EnterpriseAuthentication.vue'], resolve),
+      meta: {
+        title: '',
+        requireAuth: false,
+      },
+    },
+    {
+      path: '/authentication/agency/:userId',
+      name: 'AgencyAuthentication',
+      component: resolve => require(['@/components/authen/AgencyAuthentication.vue'], resolve),
+      meta: {
+        title: '',
+        requireAuth: false,
+      },
+    },
+    {
+      path: '/authentication/index',
+      name: 'AuthenticationIndex',
+      component: resolve => require(['@/components/authen/AuthenticationIndex.vue'], resolve),
+      meta: {
+        title: '',
+        requireAuth: false,
+      },
+    },
+    {
+      path: '/authentication/manage',
+      name: 'AuthenticationManage',
+      component: resolve => require(['@/components/authen/AuthenticationManage.vue'], resolve),
+      meta: {
+        title: '',
+        requireAuth: false,
+      },
+    },
+    {
+      path: '/agency/:userId',
+      name: 'Agency',
+      component: resolve => require(['@/components/cheat/AgencyDetail.vue'], resolve),
+      meta: {
+        title: '',
+        requireAuth: false,
+      },
+    },
   ]
 })

+ 21 - 0
src/store/index.js

@@ -0,0 +1,21 @@
+import Vue from 'vue'
+import Vuex from 'vuex'
+
+Vue.use(Vuex)
+
+const store = new Vuex.Store({
+  state: {
+    isLogin:false
+  },
+  mutations:{
+
+  },
+  actions:{
+
+  },
+  modules:{
+
+  }
+})
+
+export default store

文件差异内容过多而无法显示
+ 3 - 3
src/style/main.scss


+ 11 - 0
tool4deploy/Dockerfile

@@ -0,0 +1,11 @@
+FROM nginx
+
+RUN rm -rf /usr/share/nginx/html/*
+
+COPY ./crowd-web /usr/share/nginx/html/
+
+RUN chmod -R 777 /usr/share/nginx/html
+
+EXPOSE 80
+
+CMD ["nginx", "-g", "daemon off;"]

+ 28 - 0
tool4deploy/conf.d/nginx.conf

@@ -0,0 +1,28 @@
+server {
+        listen       80;
+        server_name  crowd.test.mooctest.net;
+        root /usr/share/nginx/html;
+        #charset koi8-r;
+
+        #access_log  logs/host.access.log  main;
+
+        location / {
+            root /usr/share/nginx/html;
+        }
+
+        location /api {
+            proxy_set_header Host                          $host;
+            proxy_set_header X-Real-IP                  $remote_addr;
+            proxy_set_header X-Forwarded-For      $proxy_add_x_forwarded_for;
+            proxy_pass http://backend:8080;
+        }
+
+        #error_page  404              /404.html;
+
+        # redirect server error pages to the static page /50x.html
+        #
+        error_page   500 502 503 504  /50x.html;
+        location = /50x.html {
+            root   html;
+        }
+ }

部分文件因为文件数量过多而无法显示