浏览代码

Merge branch 'master' of http://47.110.251.215:3000/web/saber

 Conflicts:
	src/api/manager/contractinfo.js
	src/api/manager/projectinfo.js
	src/views/manager/wbsinfo/edit.vue
liuyc 3 年之前
父节点
当前提交
f6fe7a279c

+ 2 - 0
public/index.html

@@ -110,6 +110,8 @@
 <script src="<%= BASE_URL %>cdn/element-ui/2.15.6/index.js" charset="utf-8"></script>
 <script src="<%= BASE_URL %>cdn/avue/2.9.5/avue.min.js" charset="utf-8"></script>
 <script src="<%= BASE_URL %>cdn/nutflow/wf-design-base/index.umd.min.js" charset="utf-8"></script>
+<script type="text/javascript" src='https://webapi.amap.com/maps?v=1.4.11&key=7ab53b28352e55dc5754699add0ad862&plugin=AMap.PlaceSearch'></script>
+<script src="https://webapi.amap.com/ui/1.0/main.js?v=1.0.11"></script>
 </body>
 
 </html>

+ 82 - 0
src/api/exctab/excelmodel.js

@@ -0,0 +1,82 @@
+import request from '@/router/axios';
+
+//清表树
+export const tabLazytree = (params) => {
+    return request({
+        url: '/api/blade-manager/exceltab/tab-lazytree',
+        method: 'get',
+        params
+    })
+};
+
+//获取列表信息
+export const detailExcel = (params) => {
+    return request({
+        url: '/api/blade-manager/exceltab/detail',
+        method: 'get',
+        params
+    })
+}
+
+//清表编辑 wbs 下拉框选择
+export const getWbsTypeList = (params) => {
+    return request({
+        url: '/api/blade-manager/exceltab/getWbsTypeList',
+        method: 'get',
+        params
+    })
+}
+
+//清表类型
+export const excelType = (params) => {
+    return request({
+        url: ' /api/blade-system/dict-biz/dictionary',
+        method: 'get',
+        params
+    })
+}
+
+//懒加载节点树形结构
+export const wbstree = (params) => {
+    return request({
+        url: ' /api/blade-manager/exceltab/lazy-tree',
+        method: 'get',
+        params
+    })
+}
+
+//wbs树获取表
+export const selectByNodeTable = (params) => {
+    return request({
+        url: ' /api/blade-manager/exceltab/selectByNodeTable',
+        method: 'get',
+        params
+    })
+}
+
+// 添加编辑清表
+export const Excelmodify = (row) => {
+    return request({
+        url: '/api/blade-manager/exceltab/sava-dataInfo',
+        method: 'post',
+        data: row
+    })
+}
+
+// 上传清表
+export const uploadExcel = (row) => {
+    return request({
+        url: '/api/blade-manager/exceltab/put-file-attach',
+        method: 'post',
+        data: row
+    })
+}
+
+// 删除
+export const deleteExcel = (row) => {
+    return request({
+        url: '/api/blade-manager/exceltab/remove',
+        method: 'post',
+        data: row
+    })
+}

+ 50 - 0
src/api/exctab/exceltab.js

@@ -0,0 +1,50 @@
+import request from '@/router/axios';
+
+export const getList = (current, size, params) => {
+  return request({
+    url: '/api/blade-manager/exceltab/list',
+    method: 'get',
+    params: {
+      ...params,
+      current,
+      size,
+    }
+  })
+}
+
+export const getDetail = (id) => {
+  return request({
+    url: '/api/blade-manager/exceltab/detail',
+    method: 'get',
+    params: {
+      id
+    }
+  })
+}
+
+export const remove = (ids) => {
+  return request({
+    url: '/api/blade-manager/exceltab/remove',
+    method: 'post',
+    params: {
+      ids,
+    }
+  })
+}
+
+export const add = (row) => {
+  return request({
+    url: '/api/blade-manager/exceltab/submit',
+    method: 'post',
+    data: row
+  })
+}
+
+export const update = (row) => {
+  return request({
+    url: '/api/blade-manager/exceltab/submit',
+    method: 'post',
+    data: row
+  })
+}
+

+ 75 - 16
src/api/manager/contractinfo.js

@@ -1,18 +1,22 @@
 import request from '@/router/axios';
 
-export const getList = (current, size, params) => {
+export const submitContractInfo = (contractInfo) => {
   return request({
-    url: '/api/blade-manager/contractInfo/page',
+    url: '/api/blade-manager/contractInfo/submit',
+    method: 'post',
+    data: contractInfo
+  })
+}
+export const findContractByProjectId = (pid) => {
+  return request({
+    url: '/api/blade-manager/contractInfo/findContractInfoByPid',
     method: 'get',
     params: {
-      ...params,
-      current,
-      size,
+      pid
     }
   })
 }
-
-export const getDetail = (id) => {
+export const getContractInfo = (id) => {
   return request({
     url: '/api/blade-manager/contractInfo/detail',
     method: 'get',
@@ -21,30 +25,85 @@ export const getDetail = (id) => {
     }
   })
 }
+export const delFileFromUrl = (url) => {
+  return request({
+    url: '/api/blade-manager/contractInfo/deleteFile',
+    method: 'get',
+    params: {
+      url
+    }
+  })
+}
 
-export const remove = (ids) => {
+export const saveUserInfoByProject = (list) => {
   return request({
-    url: '/api/blade-manager/contractInfo/remove',
+    url: '/api/blade-manager/contractInfo/saveUserInfoByProject',
+    method: 'post',
+    data: list
+  })
+}
+
+export const findAllUserByCondition = (info) => {
+  return request({
+    url: '/api/blade-manager/contractInfo/findAllUserByCondition',
     method: 'post',
+    data: info
+  })
+}
+export const findUserListByCondition = (info) => {
+  return request({
+    url: '/api/blade-manager/contractInfo/findUserListByCondition',
+    method: 'post',
+    data: info
+  })
+}
+
+export const findUserByName = (name) => {
+  return request({
+    url: '/api/blade-manager/contractInfo/findUserByName',
+    method: 'get',
     params: {
-      ids,
+      name
     }
   })
 }
 
-export const add = (row) => {
+export const removeUsersByIds = (ids) => {
   return request({
-    url: '/api/blade-manager/contractInfo/submit',
+    url: '/api/blade-manager/contractInfo/removeUsersByIds',
     method: 'post',
-    data: row
+    params: {
+      ids
+    }
   })
 }
 
-export const update = (row) => {
+export const removeContractInfo = (ids) => {
   return request({
-    url: '/api/blade-manager/contractInfo/submit',
+    url: '/api/blade-manager/contractInfo/remove',
     method: 'post',
-    data: row
+    params: {
+      ids
+    }
+  })
+}
+
+export const findJobByRoleId = (id) => {
+  return request({
+    url: '/api/blade-manager/contractInfo/findJobByRoleId',
+    method: 'get',
+    params: {
+      id
+    }
   })
 }
 
+export const resetPasswordByUserId = (userId) => {
+  return request({
+    url: '/api/blade-manager/contractInfo/resetPasswordByUserId',
+    method: 'post',
+    params: {
+      userId
+    }
+  })
+}

+ 10 - 29
src/api/manager/projectinfo.js

@@ -1,6 +1,14 @@
 import request from '@/router/axios';
 
-export const getList = (current, size, params) => {
+export const submitProject = (projectInfo) => {
+  return request({
+    url: '/api/blade-manager/projectInfo/submit',
+    method: 'post',
+    data: projectInfo
+  })
+}
+
+export const getProjectList = (current, size, params) => {
   return request({
     url: '/api/blade-manager/projectInfo/list',
     method: 'get',
@@ -12,7 +20,7 @@ export const getList = (current, size, params) => {
   })
 }
 
-export const getDetail = (id) => {
+export const getProjectDeatil = (id) => {
   return request({
     url: '/api/blade-manager/projectInfo/detail',
     method: 'get',
@@ -21,30 +29,3 @@ export const getDetail = (id) => {
     }
   })
 }
-
-export const remove = (ids) => {
-  return request({
-    url: '/api/blade-manager/projectInfo/remove',
-    method: 'post',
-    params: {
-      ids,
-    }
-  })
-}
-
-export const add = (row) => {
-  return request({
-    url: '/api/blade-manager/projectInfo/submit',
-    method: 'post',
-    data: row
-  })
-}
-
-export const update = (row) => {
-  return request({
-    url: '/api/blade-manager/projectInfo/submit',
-    method: 'post',
-    data: row
-  })
-}
-

+ 11 - 0
src/api/manager/wbstree.js

@@ -113,3 +113,14 @@ export const removeTableById = (id, params) => {
     }
   })
 }
+
+export const importWbsTree = (froms) => {
+  return request({
+    url: '/api/blade-manager/wbsTree/import-wbsTree',
+    method: 'post',
+    //设置请求头
+    headers: { "Content-Type": "multipart/form-data" },
+    data: froms
+  })
+}
+

+ 49 - 0
src/api/system/imageClassificationConfig.js

@@ -0,0 +1,49 @@
+import request from '@/router/axios';
+
+export const getList = (current, size, params) => {
+  return request({
+    url: '/api/blade-manager/imageClassificationConfig/list',
+    method: 'get',
+    params: {
+      ...params,
+      current,
+      size
+    }
+  })
+}
+
+export const getDetail = (id) => {
+  return request({
+    url: '/api/blade-manager/imageClassificationConfig/detail',
+    method: 'get',
+    params: {
+      id
+    }
+  })
+}
+
+export const remove = (ids) => {
+  return request({
+    url: '/api/blade-manager/imageClassificationConfig/remove',
+    method: 'post',
+    params: {
+      ids,
+    }
+  })
+}
+
+export const add = (row) => {
+  return request({
+    url: '/api/blade-manager/imageClassificationConfig/submit',
+    method: 'post',
+    data: row
+  })
+}
+
+export const update = (row) => {
+  return request({
+    url: '/api/blade-manager/imageClassificationConfig/submit',
+    method: 'post',
+    data: row
+  })
+}

+ 1 - 0
src/api/system/menu.js

@@ -102,5 +102,6 @@ export const getRoutes = (topMenuId) => request({
   method: 'get',
   params: {
     topMenuId,
+    sysType:'saber'
   }
 });

+ 135 - 0
src/components/tree-tree/main.vue

@@ -0,0 +1,135 @@
+<template>
+  <div class="flex pd-20">
+    <el-card class="box-card flex1">
+      <div slot="header" class="clearfix">
+        <span>{{leftNum}}项</span>
+      </div>
+      <div>
+        <el-scrollbar :style="scrollbarStyle">
+          <el-tree show-checkbox
+            :data="leftTreeData" @check-change="checkChange('leftTree')"
+            :props="defaultProps" :expand-on-click-node="false"
+            highlight-current node-key="id"
+            ref="leftTree" @node-expand="nodeExpand">
+          </el-tree>
+        </el-scrollbar>
+      </div>
+    </el-card>
+    <div class="flex flex-d-c flex-center" style="width:50px;">
+      <div><el-button @click="addTree" size="mini" icon="el-icon-arrow-right"></el-button></div>
+      <div><el-button @click="delTree" size="mini" icon="el-icon-arrow-left"></el-button></div>
+      
+    </div>
+    <el-card class="box-card flex1">
+      <div slot="header" class="clearfix">
+        <span>{{rightNum}}项</span>
+      </div>
+      <div>
+        <el-scrollbar :style="scrollbarStyle">
+          <el-tree show-checkbox
+            :data="rightTreeData" @check-change="checkChange('rightTree')"
+            :props="defaultProps" :expand-on-click-node="false"
+            highlight-current node-key="id"
+            ref="rightTree" :default-expanded-keys="rightExpands">
+          </el-tree>
+        </el-scrollbar>
+      </div>
+    </el-card>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "treeTree",
+  props: {
+    leftTreeData: {
+      type: Array,
+      default: function () {
+        return [];
+      }
+    },
+    scrollbarStyle:{
+      type:String,
+      default:'height:calc(100vh - 400px)'
+    }
+  },
+  computed: {
+    
+  },
+  data(){
+    return{
+      defaultProps: {
+        children: 'children',
+        label: 'title',
+      },
+      leftNum:0,
+      rightTreeData:[],
+      rightNum:0,
+      rightExpands:[],
+    }
+  },
+
+  methods:{
+    addTree(){
+      //console.log(this.$refs.leftTree.getCheckedNodes())
+      let allTree = JSON.parse(JSON.stringify(this.leftTreeData));
+
+      //把半选和选中的数组key合并
+      let keys = this.$refs.leftTree.getCheckedKeys().concat(this.$refs.leftTree.getHalfCheckedKeys());
+      //console.log(keys,'keys');
+      //console.log(allTree,'allTree');
+      this.getRightTree(allTree,keys);
+      this.rightTreeData = allTree;
+    },
+    getRightTree(arr,keys){
+      //对比所有的node和选中的key
+      for (let i = arr.length-1; i >= 0; i--) {
+        let isIn = false;
+        for (let j = keys.length-1; j >= 0; j--) {
+          if(keys[j] == arr[i].id){
+            isIn = true;
+            //已经匹配到的key移除,节省性能
+            keys.splice(j,1);
+            break;
+          }
+        }
+        if(isIn){
+          //包含在选中的节点,如果有childer继续递归判断
+          if(arr[i].children && arr[i].children.length){
+            this.getRightTree(arr[i].children,keys);
+          }
+        }else{
+          //不包含在选中key的node删除
+          arr.splice(i,1);
+        }
+      }
+    },
+    delTree(){
+      let delNodes = this.$refs.rightTree.getCheckedNodes();
+      //只把选中的节点移除
+      delNodes.forEach((node)=>{
+        //console.log(node)
+        this.$refs.rightTree.remove(node);
+        this.$refs.leftTree.setChecked(node.id,false);
+      })
+      this.rightNum = this.$refs.rightTree.getCheckedKeys().length;
+      this.leftNum = this.$refs.leftTree.getCheckedKeys().length;
+    },
+
+    nodeExpand(data){
+      this.rightExpands = this.rightExpands.concat([data.id]);
+    },
+
+    checkChange(treeName){
+      switch (treeName) {
+        case 'leftTree':
+          this.leftNum = this.$refs.leftTree.getCheckedKeys().length;
+          break;
+        case 'rightTree':
+          this.rightNum = this.$refs.rightTree.getCheckedKeys().length;
+          break;
+      }
+    },
+  }
+};
+</script>

+ 19 - 0
src/config/iconList.js

@@ -114,5 +114,24 @@ export default [
       "iconfont icon-iframe",
       "iconfont icon-huanyingye",
     ]
+  },
+  {
+    label: "客户端图标",
+    list: [
+      'HIcon-work-reports',
+      'HIcon-data-query',
+      'HIcon-log-to-fill-in',
+      'HIcon-rizhichaxunxianshi',
+      'HIcon-neiwaiyejindu',
+      'HIcon-ziliaojindu',
+      'HIcon-yingxiangziliao',
+      'HIcon-gongchengwenjian',
+      'HIcon-cezhandian',
+      'HIcon-pingquxian',
+      'HIcon-shoucang-heji',
+      'HIcon-renwuguanli',
+      'HIcon-guanliyuan1',
+      'HIcon-xiaoxi'
+    ]
   }
 ]

+ 2 - 1
src/main.js

@@ -14,6 +14,7 @@ import {
   iconfontUrl,
   iconfontVersion
 } from '@/config/env';
+
 import i18n from './lang'; // Internationalization
 import './styles/common.scss';
 import basicBlock from './components/basic-block/main';
@@ -27,7 +28,7 @@ import crudCommon from '@/mixins/crud';
 import tenantPackage from './views/system/tenantpackage';
 
 //iconfont
-import "@/styles/font/font_3360398_a0wxj1qt51u.css"
+import "@/styles/icon/index.scss"
 
 // 注册全局crud驱动
 window.$crudCommon = crudCommon;

+ 142 - 114
src/router/views/index.js

@@ -1,119 +1,147 @@
 import Layout from '@/page/index/'
 
 export default [{
-  path: '/wel',
-  component: Layout,
-  redirect: '/wel/index',
-  children: [{
-    path: 'index',
-    name: '首页',
-    meta: {
-      i18n: 'dashboard'
+        path: '/wel',
+        component: Layout,
+        redirect: '/wel/index',
+        children: [{
+            path: 'index',
+            name: '首页',
+            meta: {
+                i18n: 'dashboard'
+            },
+            component: () =>
+                import ( /* webpackChunkName: "views" */ '@/views/wel/index')
+        }, {
+            path: 'dashboard',
+            name: '控制台',
+            meta: {
+                i18n: 'dashboard',
+                menu: false,
+            },
+            component: () =>
+                import ( /* webpackChunkName: "views" */ '@/views/wel/dashboard')
+        }]
+    }, {
+        path: '/test',
+        component: Layout,
+        redirect: '/test/index',
+        children: [{
+            path: 'index',
+            name: '测试页',
+            meta: {
+                i18n: 'test'
+            },
+            component: () =>
+                import ( /* webpackChunkName: "views" */ '@/views/util/test')
+        }]
+    }, {
+        path: '/dict-horizontal',
+        component: Layout,
+        redirect: '/dict-horizontal/index',
+        children: [{
+            path: 'index',
+            name: '字典管理',
+            meta: {
+                i18n: 'dict'
+            },
+            component: () =>
+                import ( /* webpackChunkName: "views" */ '@/views/util/demo/dict-horizontal')
+        }]
+    }, {
+        path: '/dict-vertical',
+        component: Layout,
+        redirect: '/dict-vertical/index',
+        children: [{
+            path: 'index',
+            name: '字典管理',
+            meta: {
+                i18n: 'dict'
+            },
+            component: () =>
+                import ( /* webpackChunkName: "views" */ '@/views/util/demo/dict-vertical')
+        }]
+    }, {
+        path: '/info',
+        component: Layout,
+        redirect: '/info/index',
+        children: [{
+            path: 'index',
+            name: '个人信息',
+            meta: {
+                i18n: 'info'
+            },
+            component: () =>
+                import ( /* webpackChunkName: "views" */ '@/views/system/userinfo')
+        }]
+    }, {
+        path: '/work/process/leave',
+        component: Layout,
+        redirect: '/work/process/leave/form',
+        children: [{
+            path: 'form/:processDefinitionId',
+            name: '请假流程',
+            meta: {
+                i18n: 'work'
+            },
+            component: () =>
+                import ( /* webpackChunkName: "views" */ '@/views/work/process/leave/form')
+        }, {
+            path: 'handle/:taskId/:processInstanceId/:businessId',
+            name: '处理请假流程',
+            meta: {
+                i18n: 'work'
+            },
+            component: () =>
+                import ( /* webpackChunkName: "views" */ '@/views/work/process/leave/handle')
+        }, {
+            path: 'detail/:processInstanceId/:businessId',
+            name: '请假流程详情',
+            meta: {
+                i18n: 'work'
+            },
+            component: () =>
+                import ( /* webpackChunkName: "views" */ '@/views/work/process/leave/detail')
+        }]
+    }, {
+        path: '/wbs',
+        component: Layout,
+        redirect: '/wbs/edit',
+        children: [{
+            path: 'edit/:id',
+            name: '编辑WBS树',
+            meta: {
+                i18n: 'edit'
+            },
+            component: () =>
+                import ( /* webpackChunkName: "views" */ '@/views/manager/wbsinfo/edit')
+        }]
+    }, {
+        path: '/contract',
+        component: Layout,
+        redirect: '/contract/detail',
+        children: [{
+            path: 'detail',
+            name: '创建合同段',
+            meta: {
+                i18n: 'edit'
+            },
+            component: () =>
+                import ( /* webpackChunkName: "views" */ '@/views/manager/contractinfo/detail')
+        }]
     },
-    component: () =>
-      import( /* webpackChunkName: "views" */ '@/views/wel/index')
-  }, {
-    path: 'dashboard',
-    name: '控制台',
-    meta: {
-      i18n: 'dashboard',
-      menu: false,
+    {
+        path: '/excel',
+        component: Layout,
+        redirect: '/excel/excelmodel',
+        children: [{
+            path: 'excelmodel/:id',
+            name: '清表模板',
+            meta: {
+                i18n: 'excelmodel'
+            },
+            component: () =>
+                import ( /* webpackChunkName: "views" */ '@/views/exctab/excelmodel/excelmodel')
+        }]
     },
-    component: () =>
-      import( /* webpackChunkName: "views" */ '@/views/wel/dashboard')
-  }]
-}, {
-  path: '/test',
-  component: Layout,
-  redirect: '/test/index',
-  children: [{
-    path: 'index',
-    name: '测试页',
-    meta: {
-      i18n: 'test'
-    },
-    component: () =>
-      import( /* webpackChunkName: "views" */ '@/views/util/test')
-  }]
-}, {
-  path: '/dict-horizontal',
-  component: Layout,
-  redirect: '/dict-horizontal/index',
-  children: [{
-    path: 'index',
-    name: '字典管理',
-    meta: {
-      i18n: 'dict'
-    },
-    component: () =>
-      import( /* webpackChunkName: "views" */ '@/views/util/demo/dict-horizontal')
-  }]
-}, {
-  path: '/dict-vertical',
-  component: Layout,
-  redirect: '/dict-vertical/index',
-  children: [{
-    path: 'index',
-    name: '字典管理',
-    meta: {
-      i18n: 'dict'
-    },
-    component: () =>
-      import( /* webpackChunkName: "views" */ '@/views/util/demo/dict-vertical')
-  }]
-}, {
-  path: '/info',
-  component: Layout,
-  redirect: '/info/index',
-  children: [{
-    path: 'index',
-    name: '个人信息',
-    meta: {
-      i18n: 'info'
-    },
-    component: () =>
-      import( /* webpackChunkName: "views" */ '@/views/system/userinfo')
-  }]
-}, {
-  path: '/work/process/leave',
-  component: Layout,
-  redirect: '/work/process/leave/form',
-  children: [{
-    path: 'form/:processDefinitionId',
-    name: '请假流程',
-    meta: {
-      i18n: 'work'
-    },
-    component: () =>
-      import( /* webpackChunkName: "views" */ '@/views/work/process/leave/form')
-  }, {
-    path: 'handle/:taskId/:processInstanceId/:businessId',
-    name: '处理请假流程',
-    meta: {
-      i18n: 'work'
-    },
-    component: () =>
-      import( /* webpackChunkName: "views" */ '@/views/work/process/leave/handle')
-  }, {
-    path: 'detail/:processInstanceId/:businessId',
-    name: '请假流程详情',
-    meta: {
-      i18n: 'work'
-    },
-    component: () =>
-      import( /* webpackChunkName: "views" */ '@/views/work/process/leave/detail')
-  }]
-},{
-  path: '/wbs',
-  component: Layout,
-  redirect: '/wbs/edit',
-  children: [{
-    path: 'edit/:id',
-    name: '编辑WBS树',
-    meta: {
-      i18n: 'edit'
-    },
-    component: () =>
-      import( /* webpackChunkName: "views" */ '@/views/manager/wbsinfo/edit')
-  }]
-}]
+]

+ 24 - 0
src/styles/common.scss

@@ -34,9 +34,26 @@ a{
 
 .flex1{flex: 1;}
 
+.flex-d-c{
+  flex-direction: column;
+}
+
 .jc-sb{
   justify-content:space-between
 }
+.jc-al-c{
+  align-items: center;
+}
+.flex-center{
+  justify-content: center;
+  align-items: center;
+}
+
+.grid4x4{
+  display: grid;
+  grid-template-columns: 25% 25% 25% 25%;
+  grid-template-rows: 25% 25% 25% 25%;
+}
 
 .w-100p{width: 100%;}
 .h-100p{height: 100%;}
@@ -65,6 +82,8 @@ a{
 .pd-b-20{padding-bottom: 20px;}
 .pd-20{padding: 20px;}
 
+.box-size-bb{box-sizing: border-box;}
+
 .bgc-f6{background-color: #f6f6f6;}
 .normal-black{color: #606266;}
 .border-grey{
@@ -72,6 +91,9 @@ a{
   border-width: 1px;
   border-style: solid;
 }
+.border-grey-b{
+  border-bottom: 1px solid rgb(187, 187, 187);
+}
 
 .font-s-12{font-size: 12px;}
 .font-c-warning{color: rgb(240, 99, 10);}
@@ -84,6 +106,8 @@ a{
   color: #f56c6c;
 }
 
+.text-align-c{text-align: center;}
+
 .custom-tree-node {
   flex: 1;
   display: flex;

文件差异内容过多而无法显示
+ 0 - 3
src/styles/font/font_3360398_a0wxj1qt51u.css


文件差异内容过多而无法显示
+ 2 - 0
src/styles/icon/_HIcon.scss


文件差异内容过多而无法显示
+ 2 - 0
src/styles/icon/_cicon.scss


文件差异内容过多而无法显示
+ 2 - 0
src/styles/icon/_hcicon.scss


文件差异内容过多而无法显示
+ 2 - 0
src/styles/icon/_icon.scss


文件差异内容过多而无法显示
+ 2 - 0
src/styles/icon/_lib.scss


+ 5 - 0
src/styles/icon/index.scss

@@ -0,0 +1,5 @@
+@import 'icon';
+@import 'lib';
+@import 'cicon';
+@import "hcicon";
+@import "HIcon";

+ 22 - 0
src/views/authority/role.vue

@@ -79,6 +79,7 @@
 
 <script>
   import {add, getList, getRole, getRoleTreeById, grant, grantTree, remove, update} from "@/api/system/role";
+  import {getPostList} from "@/api/system/post";
   import {mapGetters} from "vuex";
   import website from '@/config/website';
 
@@ -166,6 +167,22 @@
                 }
               ]
             },
+            {
+              label: "所属岗位",
+              prop: "pId",
+              type: "tree",
+              hide: true,
+              dicData: [],
+              props: {
+                label: "postName",
+                value: "id"
+              },
+              rules: [{
+                required: true,
+                message: "请选择所属岗位",
+                trigger: "click"
+              }],
+            },
             {
               label: "上级角色",
               prop: "parentId",
@@ -234,6 +251,11 @@
           const column = this.findObject(this.option.column, "parentId");
           column.dicData = res.data.data;
         });
+        let tenantId = website.tenantId;
+        getPostList(tenantId).then(res => {
+          const column = this.findObject(this.option.column, "pId");
+          column.dicData = res.data.data;
+        });
       },
       submit() {
         const menuList = this.$refs.treeMenu.getCheckedKeys();

+ 476 - 0
src/views/exctab/excelmodel/excelmodel.vue

@@ -0,0 +1,476 @@
+<template>
+  <div>
+    <el-row class="box">
+      <!-- 左侧树结构 -->
+      <el-col :span="5">
+        <div class="box">
+          <el-scrollbar>
+            <basic-container>
+              <!-- 树结构 -->
+              <avue-tree
+                :permission="getPermission"
+                :loading="loading"
+                :option="option"
+                :data="data"
+                @node-click="nodeClick"
+              >
+                <span
+                  class="el-tree-node__label"
+                  slot-scope="{ node, data }"
+                >
+                  <div>
+                    <span> {{ data.name }} </span>
+                    <!-- <span> {{ node}} </span> -->
+                    <i
+                      class="el-icon-circle-plus-outline marleft10"
+                      @click.stop="addExcel(data)"
+                      v-if="!data.fileUrl"
+                    ></i>
+                    <i
+                      class="el-icon-edit marleft10"
+                      @click.stop="editExcel()"
+                      v-if="data.fileUrl"
+                    ></i>
+                    <i
+                      class="el-icon-delete marleft10"
+                      @click.stop="deleteExcelM(data)"
+                      v-if="data.fileUrl"
+                    ></i>
+                  </div>
+                </span>
+              </avue-tree>
+            </basic-container>
+          </el-scrollbar>
+        </div>
+      </el-col>
+      <!-- 右侧 -->
+      <el-col
+        :span="19"
+        class="box"
+      >
+        <el-scrollbar>
+          <basic-container>
+            <!-- 上传、删除、下载操作栏 -->
+            <div class="rightHeader">
+              <div class="excelname">
+                <div>名ssssssssssssssssssssssssssssss称</div>
+                <i
+                  class="el-icon-success marleft10"
+                  style="color: rgb(0, 168, 112);"
+                ></i>
+              </div>
+              <el-button
+                size="mini"
+                class="marleft10"
+              >重新上传</el-button>
+              <el-link class="marleft10 colorblue">删除</el-link>
+              <el-link
+                underline
+                class="marleft10 colorblue"
+                style="text-decoration:underline;"
+              >下载EXCEL</el-link>
+            </div>
+          </basic-container>
+        </el-scrollbar>
+      </el-col>
+    </el-row>
+
+    <!-- 弹出框 -->
+    <el-dialog
+      title="新增编辑"
+      class="dialogModel"
+      :visible.sync="dialogTap"
+      width="800px"
+      modal-append-to-body
+      append-to-body
+      :before-close="handleClose"
+    >
+      <div class="dialogBox">
+        <el-form
+          ref="excelForm"
+          :model="excelForm"
+          label-width="80px"
+        >
+          <div style="display: flex;justify-content: space-between;">
+            <el-form-item
+              label="清表名称"
+              style="width: 370px;"
+              size="small"
+            >
+              <el-input v-model="excelForm.nodeName"></el-input>
+            </el-form-item>
+            <el-form-item
+              label="清表类型"
+              style="width: 370px;"
+              size="small"
+            >
+              <el-select
+                v-model="excelForm.name"
+                style="width:100%;"
+                placeholder="请选择清表类型"
+              >
+                <el-option
+                  v-for="(val,index) in exceltypeData"
+                  :key="index"
+                  :label="val.dictValue"
+                  :value="val.id"
+                ></el-option>
+              </el-select>
+            </el-form-item>
+          </div>
+        </el-form>
+        <div class="middle">
+          <div class="left">
+            <div class="select">
+              <el-select
+                placeholder="请选择WBS模板"
+                style="width: 96%;"
+                size="small"
+                @change="wbsmodelchange"
+                v-model="excelForm.wbsId"
+              >
+                <el-option
+                  v-for="(val,index) in wbsmodel"
+                  :key="index"
+                  :label="val.wbsName"
+                  :value="val.id"
+                ></el-option>
+              </el-select>
+            </div>
+            <div class="leftscroll">
+              <avue-tree
+                :permission="getPermission"
+                :loading="loading"
+                :option="option2"
+                :data="wbsdata"
+                @node-click="nodeClickExcel"
+              >
+                <span
+                  class="el-tree-node__label"
+                  slot-scope="{ node, data }"
+                >
+                  <div>
+                    <span> {{ data.deptName }} </span>
+                  </div>
+                </span>
+              </avue-tree>
+            </div>
+          </div>
+          <template>
+            <table
+              class="right"
+              width="49%"
+              bordercolor="#DCDCDC"
+              border="1px"
+            >
+              <thead>
+                <tr>
+                  <td>表名</td>
+                  <td>操作</td>
+                </tr>
+              </thead>
+              <tbody>
+                <tr
+                  v-for="(val,index) in tableData"
+                  :key="index"
+                >
+                  <td>{{val.tableName}}</td>
+                  <td style="text-align: center;height:30px;">
+                    <el-button
+                      v-if="val.isLinkTable!=2"
+                      type="info"
+                      size="small"
+                    >关联</el-button>
+                    <el-button
+                      v-if="val.isLinkTable==2"
+                      type="warning"
+                      size="small"
+                    >取消关联</el-button>
+                  </td>
+                </tr>
+              </tbody>
+            </table>
+          </template>
+        </div>
+      </div>
+      <div class="btbox">
+        <el-button
+          size="mini"
+          @click="handleClose()"
+        >取消</el-button>
+        <el-button
+          type="info"
+          style="margin-left: 50px;"
+          size="mini"
+          @click="saveExcel()"
+        >确定</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { detailExcel, excelType, tabLazytree, getWbsTypeList, wbstree, selectByNodeTable, Excelmodify, uploadExcel } from '@/api/exctab/excelmodel'
+export default {
+  data () {
+    return {
+      loading: false,//懒加载
+      option: {
+        filter: false,
+      },
+      data: [],//清表模板
+      wbsdata: [],//wbs模板
+      //#region   弹框
+      dialogTap: false,
+      option2: {
+        filter: false,
+        lazy: true,
+        treeLoad: (async (node, resolve) => {
+          if (node.data.hasChildren) {
+            const { data: res } = await wbstree({ parentId: node.data.id, wbsId: this.excelForm.wbsId, wbsType: this.excelForm.wbsType })
+            console.log(res);
+            if (res.code === 200) {
+              res.data.forEach((val) => {
+                if (!val.hasChildren) {
+                  val.leaf = true
+                }
+              })
+              return resolve(res.data)
+            }
+          } else {
+            return resolve([])
+          }
+        }),
+      },//弹框里面的wbs树
+      excelForm: {
+        nodeName: '',//清表名称
+        parentId: '',//清表Id
+        wbsId: '',//WBS模板Id
+        wbsType: '',//WBS模板类型
+      },
+      tableData: [],//右侧表数据
+      exceltypeData: [],//清表类型枚举
+      wbsmodel: [],//wbs模板名称枚举
+      //#endregion
+    }
+  },
+  methods: {
+    //#region 接口
+    async tabLazytree (modeId) {//清表树
+      const { data: res } = await tabLazytree({ modeId })
+      console.log(res);
+      if (res.code === 200) {
+        this.data = res.data
+      }
+    },
+    async detailExcel (id) {//获取列表信息
+      const { data: res } = await detailExcel({ id })
+      console.log(res);
+      if (res.code === 200) {
+        console.log(res.data.alias);
+      }
+    },
+    async getWbsTypeList () {//清表编辑 wbs 下拉框选择
+      const { data: res } = await getWbsTypeList()
+      console.log(res);
+      if (res.code === 200) {
+        this.wbsmodel = res.data
+      }
+    },
+    async excelType () {//清表类型
+      const { data: res } = await excelType({ code: 'sys_excltab_type' })
+      console.log(res);
+      if (res.code === 200) {
+        this.exceltypeData = res.data
+      }
+    },
+    async wbstree () {//wbs树懒加载
+      const { data: res } = await wbstree({ parentId: 0, wbsId: this.excelForm.wbsId, wbsType: this.excelForm.wbsType })
+      console.log(res);
+      if (res.code === 200) {
+        res.data.forEach((val) => {
+          if (!val.hasChildren) {
+            val.leaf = true
+          }
+        })
+        this.wbsdata = res.data
+      }
+    },
+    async selectByNodeTable (id, wbsType) {//wbs树获取表
+      const { data: res } = await selectByNodeTable({ id, wbsType })
+      console.log(res);
+      if (res.code === 200) {
+        this.tableData = res.data
+      }
+    },
+    async deleteExcel (ids) {//删除清表
+      const { data: res } = await deleteExcel({ ids })
+      console.log(res);
+      if (res.code === 200) {
+
+      }
+    },
+    async Excelmodify () {//编辑添加清表
+      const { data: res } = await Excelmodify()
+      console.log(res);
+    },
+    async uploadExcel () {//上传清表
+      const { data: res } = await uploadExcel()
+      console.log(res);
+    },
+    //#endregion
+
+    //#region  外层左侧事件
+    nodeClick (data) {//外层树结构
+      console.log(data);
+      // this.detailExcel(data.id)
+    },
+    editExcel () {//编辑
+      console.log(111);
+    },
+    addExcel (data) {//添加
+      this.excelForm.parentId = data.id
+      this.dialogTap = true
+    },
+    deleteExcelM (data) {//删除
+      const _that = this
+      this.$confirm('确定将选择数据删除?', '', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'error'
+      }).then(async () => {
+        await _that.deleteExcel(data.id)
+      }).catch(() => {
+      });
+    },
+    //#endregion
+
+    //#region 弹框属性
+    handleClose () {//关闭弹框触发事件
+      this.excelForm = {
+        nodeName: '',//清表名称
+        parentId: '',//清表Id
+        wbsId: '',//WBS模板Id
+        wbsType: '',//WBS模板类型
+      }
+      this.wbsdata = []  //wbs树数据
+      this.tableData = []//弹框table数据
+      this.dialogTap = false
+    },
+    wbsmodelchange (val) {//wbs模板change事件
+      if (val) {
+        this.wbsmodel.forEach((da) => {
+          if (da.id == val) {
+            this.excelForm.wbsType = da.wbsType
+          }
+        })
+      }
+      this.wbstree()
+    },
+    async nodeClickExcel (data) {//wbs树点击事件
+      console.log(data);
+      this.selectByNodeTable(data.id, data.type)
+    },
+    saveExcel () {//保存按钮
+
+    },
+    //#endregion
+  },
+  created () {
+    this.excelType()//清表类型
+    this.getWbsTypeList()//wbs模板名称
+    // this.tabLazytree(this.$route.params.id)//获取清表树
+    this.tabLazytree(0)
+  }
+}
+</script>
+
+<style scoped lang="scss">
+.marleft10 {
+  margin-left: 10px;
+}
+
+.colorblue {
+  color: rgb(0, 82, 217);
+}
+
+.box {
+  height: 800px;
+}
+
+.el-scrollbar {
+  height: 100%;
+}
+
+.box .el-scrollbar__wrap {
+  overflow: scroll;
+}
+
+.rightHeader {
+  display: flex;
+  justify-content: flex-start;
+  align-items: center;
+  font-size: 14px;
+  background-color: #fff;
+
+  .excelname {
+    box-sizing: border-box;
+    min-width: 200px;
+    height: 28px;
+    border: 1px solid rgb(220, 220, 220);
+    padding: 0 10px;
+    border-radius: 3px;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+  }
+}
+
+.dialogModel {
+  .dialogBox {
+    .middle {
+      display: flex;
+
+      .left {
+        border: 1px solid rgb(220, 220, 220);
+        border-radius: 3px;
+        height: 500px;
+        width: 49%;
+
+        .select {
+          box-sizing: border-box;
+          display: flex;
+          justify-content: center;
+          padding: 5px 0;
+          border-bottom: 1px solid #e0e0e0;
+        }
+        .leftscroll {
+          height: 450px;
+          overflow-y: scroll;
+        }
+      }
+
+      .right {
+        height: auto;
+        height: 60px;
+        max-height: 500px;
+        margin-left: 2%;
+        // height: 500px;
+        border-radius: 3px;
+        td {
+          box-sizing: border-box;
+          padding: 5px 10px;
+          height: 30px;
+          line-height: 30px;
+        }
+      }
+    }
+  }
+
+  .btbox {
+    margin-top: 20px;
+    display: flex;
+    justify-content: center;
+  }
+}
+</style>

+ 260 - 0
src/views/exctab/exceltab.vue

@@ -0,0 +1,260 @@
+<template>
+  <basic-container>
+    <avue-crud
+      :option="option"
+      :table-loading="loading"
+      :data="data"
+      :page.sync="page"
+      :permission="permissionList"
+      :before-open="beforeOpen"
+      v-model="form"
+      ref="crud"
+      @row-update="rowUpdate"
+      @row-save="rowSave"
+      @row-del="rowDel"
+      @search-change="searchChange"
+      @search-reset="searchReset"
+      @selection-change="selectionChange"
+      @current-change="currentChange"
+      @size-change="sizeChange"
+      @refresh-change="refreshChange"
+      @on-load="onLoad"
+    >
+      <template slot="menuLeft">
+        <el-button
+          type="danger"
+          size="small"
+          icon="el-icon-delete"
+          plain
+          v-if="permission.exceltab_delete"
+          @click="handleDelete"
+        >删 除
+        </el-button>
+      </template>
+
+      <template
+        slot-scope="scope"
+        slot="menu"
+      >
+        <el-button
+          type="text"
+          icon="el-icon-circle-plus-outline"
+          size="small"
+          @click.stop="handleAdd(scope.row, scope.index)"
+        >清表模版
+        </el-button>
+      </template>
+      <template
+        slot-scope="{row}"
+        slot="source"
+      >
+        <div style="text-align:center">
+          <i :class="row.source" />
+        </div>
+      </template>
+    </avue-crud>
+  </basic-container>
+</template>
+
+
+<script>
+import { getList, getDetail, add, update, remove } from "@/api/exctab/exceltab";
+import { mapGetters } from "vuex";
+
+export default {
+  data () {
+    return {
+      form: {},
+      query: {},
+      loading: true,
+      page: {
+        pageSize: 10,
+        currentPage: 1,
+        total: 0
+      },
+      selectionList: [],
+      option: {
+        height: 'auto',
+        calcHeight: 30,
+        tip: false,
+        searchShow: true,
+        searchMenuSpan: 6,
+        border: true,
+        index: true,
+        viewBtn: true,
+        selection: true,
+        menuWidth: 300,
+        dialogClickModal: false,
+        column: [
+          {
+            label: '创建时间',
+            prop: 'createTime',
+            width: 300,
+            editDisplay: false,
+            addDisplay: false,
+          },
+          {
+            label: "模版名称",
+            prop: "name",
+            search: true,
+            rules: [{
+              required: true,
+              message: "请输入名称",
+              trigger: "blur"
+            }]
+          },
+
+          {
+            label: "表数量",
+            prop: "tabCout",
+            width: 300,
+            editDisplay: false,
+            addDisplay: false,
+            rules: [{
+              message: "请输入表数量",
+              trigger: "blur",
+            }]
+          }
+        ]
+      },
+      data: []
+    };
+  },
+  computed: {
+    ...mapGetters(["permission"]),
+    permissionList () {
+      return {
+        addBtn: this.vaildData(this.permission.exceltab_add, false),
+        viewBtn: this.vaildData(this.permission.exceltab_view, false),
+        delBtn: this.vaildData(this.permission.exceltab_delete, false),
+        editBtn: this.vaildData(this.permission.exceltab_edit, false)
+      };
+    },
+    ids () {
+      let ids = [];
+      this.selectionList.forEach(ele => {
+        ids.push(ele.id);
+      });
+      return ids.join(",");
+    }
+  },
+  methods: {
+    handleAdd (row) {
+      this.$router.push('/excel/excelmodel/' + row.id);
+    },
+    rowSave (row, done, loading) {
+      add(row).then(() => {
+        this.onLoad(this.page);
+        this.$message({
+          type: "success",
+          message: "操作成功!"
+        });
+        done();
+      }, error => {
+        loading();
+        window.console.log(error);
+      });
+    },
+    rowUpdate (row, index, done, loading) {
+      update(row).then(() => {
+        this.onLoad(this.page);
+        this.$message({
+          type: "success",
+          message: "操作成功!"
+        });
+        done();
+      }, error => {
+        loading();
+        console.log(error);
+      });
+    },
+    rowDel (row) {
+      this.$confirm("确定将选择数据删除?", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      })
+        .then(() => {
+          return remove(row.id);
+        })
+        .then(() => {
+          this.onLoad(this.page);
+          this.$message({
+            type: "success",
+            message: "操作成功!"
+          });
+        });
+    },
+    handleDelete () {
+      if (this.selectionList.length === 0) {
+        this.$message.warning("请选择至少一条数据");
+        return;
+      }
+      this.$confirm("确定将选择数据删除?", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      })
+        .then(() => {
+          return remove(this.ids);
+        })
+        .then(() => {
+          this.onLoad(this.page);
+          this.$message({
+            type: "success",
+            message: "操作成功!"
+          });
+          this.$refs.crud.toggleSelection();
+        });
+    },
+    beforeOpen (done, type) {
+      if (["edit", "view"].includes(type)) {
+        getDetail(this.form.id).then(res => {
+          this.form = res.data.data;
+        });
+      }
+      done();
+    },
+    searchReset () {
+      this.query = {};
+      this.onLoad(this.page);
+    },
+    searchChange (params, done) {
+      this.query = params;
+      this.page.currentPage = 1;
+      this.onLoad(this.page, params);
+      done();
+    },
+    selectionChange (list) {
+      this.selectionList = list;
+    },
+    selectionClear () {
+      this.selectionList = [];
+      this.$refs.crud.toggleSelection();
+    },
+    currentChange (currentPage) {
+      this.page.currentPage = currentPage;
+    },
+    sizeChange (pageSize) {
+      this.page.pageSize = pageSize;
+    },
+    refreshChange () {
+      this.onLoad(this.page, this.query);
+    },
+    onLoad (page, params = {}) {
+      this.query.parentId = 0;
+      this.loading = true;
+      getList(page.currentPage, page.pageSize, Object.assign(params, this.query)).then(res => {
+        const data = res.data.data;
+        this.page.total = data.total;
+        this.data = data.records;
+        this.loading = false;
+        this.selectionClear();
+      });
+    }
+  }
+};
+</script>
+
+<style>
+</style>

+ 689 - 0
src/views/manager/contractinfo/detail.vue

@@ -0,0 +1,689 @@
+<template>
+  <basic-container>
+    <div>
+      <el-tabs v-model="activeType" :before-leave="beforeLeave">
+        <el-tab-pane label="合同段信息" name="1">
+          <div>
+            <el-form :model="contractForm" :rules="contractRules" ref="contractForm" label-width="120px">
+              <el-form-item label="项目名称">
+                <el-input v-model="projectInfo.projectName" disabled></el-input>
+              </el-form-item>
+              <el-row>
+                <el-col :span="12">
+                  <el-form-item label="合同段类型" prop="contractType">
+                    <el-select v-model="contractForm.contractType" placeholder="请选择" class="w-100p">
+                      <el-option v-for="item in contractTypeList" :key="item.id" :label="item.dictValue"  :value="item.dictKey"></el-option>
+                    </el-select>
+                  </el-form-item>
+                </el-col>
+                <el-col :span="12">
+                  <el-form-item label="合同段编号" prop="contractNumber">
+                    <el-input v-model="contractForm.contractNumber"></el-input>
+                  </el-form-item>
+                </el-col>
+              </el-row>
+              <el-row>
+                <el-col :span="12">
+                  <el-form-item label="合同段名称" prop="contractName">
+                    <el-input v-model="contractForm.contractName"></el-input>
+                  </el-form-item>
+                </el-col>
+                <el-col :span="12">
+                  <el-form-item label="参与方进场日期" prop="contractorJoinTime">
+                    <el-date-picker  v-model="contractForm.contractorJoinTime"  type="date" format="yyyy 年 MM 月 dd 日" value-format="yyyy-MM-dd HH:mm:ss"  placeholder="选择日期"></el-date-picker>
+                  </el-form-item>
+                </el-col>
+              </el-row>
+              <el-row>
+                <el-col :span="12">
+                  <el-form-item label="计划开工日期" prop="planStartTime">
+                    <el-date-picker  v-model="contractForm.planStartTime"  type="date" format="yyyy 年 MM 月 dd 日" value-format="yyyy-MM-dd HH:mm:ss" placeholder="选择日期"></el-date-picker>
+                  </el-form-item>
+                </el-col>
+                <el-col :span="12">
+                  <el-form-item label="计划完工日期" prop="planEndTime">
+                    <el-date-picker  v-model="contractForm.planEndTime"  type="date" format="yyyy 年 MM 月 dd 日" value-format="yyyy-MM-dd HH:mm:ss" placeholder="选择日期"></el-date-picker>
+                  </el-form-item>
+                </el-col>
+              </el-row>
+              <el-row>
+                <el-col :span="12">
+                  <el-form-item label="实际开工日期" prop="actualStartTime">
+                    <el-date-picker  v-model="contractForm.actualStartTime"  type="date" format="yyyy 年 MM 月 dd 日" value-format="yyyy-MM-dd HH:mm:ss" placeholder="选择日期"></el-date-picker>
+                  </el-form-item>
+                </el-col>
+                <el-col :span="12">
+                  <el-form-item label="实际完工日期" prop="actualEndTime">
+                    <el-date-picker  v-model="contractForm.actualEndTime"  type="date" format="yyyy 年 MM 月 dd 日" value-format="yyyy-MM-dd HH:mm:ss" placeholder="选择日期"></el-date-picker>
+                  </el-form-item>
+                </el-col>
+              </el-row>
+              <el-row>
+                <el-col :span="12">
+                  <el-form-item label="业主单位名称" prop="contractorUnitName">
+                    <el-input v-model="contractForm.contractorUnitName"></el-input>
+                  </el-form-item>
+                </el-col>
+                <el-col :span="12">
+                  <el-form-item label="合同金额" prop="contractAmount">
+                    <el-input v-model="contractForm.contractAmount">
+                      <template slot="append">万元</template>
+                    </el-input>
+                  </el-form-item>
+                </el-col>
+              </el-row>
+              <el-row>
+                <el-col :span="12">
+                  <el-form-item label="施工单位名称" prop="constructionUnitName">
+                    <el-input v-model="contractForm.constructionUnitName"></el-input>
+                  </el-form-item>
+                </el-col>
+                <el-col :span="12">
+                  <el-form-item label="上传开工令" prop="startFileUrl">
+                    <template v-if="isBackShow">
+                      <el-link type="primary" @click="downloadFile">开工令</el-link>
+                      <el-button @click="delFile" class="mg-l-10" style="color:red" type="text" icon="el-icon-circle-close"></el-button>
+                    </template>
+                    <template v-else>
+                      <el-upload
+                        action="/api/blade-resource/oss/endpoint/put-file-attach"
+                        :on-remove="handleRemove"
+                        :limit="1" :headers=headers
+                        :on-exceed="handleExceed"
+                        :on-success="handleSuccess"
+                        :file-list="fileList">
+                        <el-button size="small" type="primary">点击上传</el-button>
+                      </el-upload>
+                    </template>
+                    
+                  </el-form-item>
+                </el-col>
+              </el-row>
+              <el-row>
+                <el-col :span="12">
+                  <el-form-item label="监理单位名称" prop="supervisionUnitName">
+                    <el-input v-model="contractForm.supervisionUnitName"></el-input>
+                  </el-form-item>
+                </el-col>
+                <el-col :span="12">
+                </el-col>
+              </el-row>
+            </el-form>
+            <el-divider></el-divider>
+            <el-row :gutter="20">
+              <el-col :span="12">
+                <div>组卷归档默认信息</div>
+                <el-form label-width="90px">
+                  <el-row>
+                    <el-col :span="12">
+                      <el-form-item label="立卷人" prop="filer">
+                        <el-input v-model="contractForm.filer"></el-input>
+                      </el-form-item>
+                    </el-col>
+                    <el-col :span="12">
+                      <el-form-item label="保管期限" prop="storagePeriod">
+                        <el-select v-model="contractForm.storagePeriod" placeholder="请选择" class="w-100p">
+                          <el-option label="10年"  value="10年"></el-option>
+                          <el-option label="30年"  value="30年"></el-option>
+                          <el-option label="永久"  value="永久"></el-option>
+                        </el-select>
+                      </el-form-item>
+                    </el-col>
+                  </el-row>
+                  <el-row>
+                    <el-col :span="12">
+                      <el-form-item label="审核人" prop="reviewer">
+                        <el-input v-model="contractForm.reviewer"></el-input>
+                      </el-form-item>
+                    </el-col>
+                    <el-col :span="12">
+                      <el-form-item label="保管密级" prop="securityLevel">
+                        <el-select v-model="contractForm.securityLevel" placeholder="请选择" class="w-100p">
+                          <el-option label="机密"  value="机密"></el-option>
+                          <el-option label="绝密"  value="绝密"></el-option>
+                          <el-option label="秘密"  value="秘密"></el-option>
+                          <el-option label="公开"  value="公开"></el-option>
+                        </el-select>
+                      </el-form-item>
+                    </el-col>
+                  </el-row>
+                  <el-row>
+                    <el-col :span="12">
+                      <el-form-item label="档案前缀" prop="prefix">
+                        <el-input v-model="contractForm.prefix"></el-input>
+                      </el-form-item>
+                    </el-col>
+                    <el-col :span="12">
+                      
+                    </el-col>
+                  </el-row>
+                </el-form>
+              </el-col>
+              <el-col :span="12">
+                <div>附加信息</div>
+                <el-form label-width="90px">
+                  <el-form-item label="项目地址" prop="projectPlace">
+                    <!-- <el-input v-model="contractForm.projectPlace" placeholder="点击后面地图选取地址">
+                      <el-button slot="append" icon="el-icon-map-location" @click="mapDialogVisible = true"></el-button>
+                    </el-input> -->
+                    <avue-input-map  :params="params" placeholder="请选择地图" v-model="flageData" ></avue-input-map>
+                  </el-form-item>
+                  <el-form-item label="起始桩号" prop="startStation">
+                    <el-input v-model="contractForm.startStation"></el-input>
+                  </el-form-item>
+                  <el-form-item label="结束桩号" prop="endStation">
+                    <el-input v-model="contractForm.endStation"></el-input>
+                  </el-form-item>
+                </el-form>
+              </el-col>
+            </el-row>
+          </div>
+        </el-tab-pane>
+        <el-tab-pane label="分配WBS" name="2">
+          <div>
+            <div class="text-align-c">
+              <span class="mg-r-20">选择WBS</span>
+              <el-select v-model="wbsId" @change="wbsChange" placeholder="请选择WBS" style="width:500px;">
+                <el-option v-for="item in wbsList" :key="item.id" :label="item.wbsName" :value="item.id"></el-option>
+              </el-select>
+            </div>
+            <tree-tree :left-tree-data="leftTreeData"></tree-tree>
+          </div>
+        </el-tab-pane>
+        <el-tab-pane label="分配项目人员" name="3">
+          <div>
+            <div class="flex jc-al-c">
+              <span class="mg-r-10">项目名称</span>
+              <el-input v-model="projectInfo.projectName" disabled style="width:300px;margin-right:30px;"></el-input>
+              <span class="mg-r-10">合同段名称</span>
+              <el-input v-model="contractForm.contractName" disabled style="width:300px;"></el-input>
+            </div>
+            <el-divider></el-divider>
+            <div class="flex jc-al-c mg-b-10">
+              <div>
+                <span class="mg-r-10">角色方</span>
+                <el-radio-group v-model="rId">
+                  <el-radio-button v-for="(item) in roleList" :label="item.id" :key="item.key">{{item.title}}</el-radio-button>
+                </el-radio-group>
+              </div>
+              <div>
+                <span class="mg-r-10 mg-l-20">请选择岗位</span>
+                <el-select v-model="postId" filterable placeholder="请输入搜索">
+                  <el-option v-for="item in postList" :key="item.id" :label="item.postName"  :value="item.id"></el-option>
+                </el-select>
+              </div>
+            </div>
+            <div>
+              <el-table  :data="contractUserList" border height="500" style="width: 100%">
+                <el-table-column prop="name" label="姓名" align="center"></el-table-column>
+                <el-table-column prop="account" label="登录账号" align="center"></el-table-column>
+                <el-table-column prop="password" label="密码" align="center"></el-table-column>
+                <el-table-column label="操作" align="center">
+                  <template slot-scope="scope">
+                    <el-link class="mg-r-20" type="primary" @click="copyAccPas(scope.row)">复制</el-link>
+                    <el-link class="mg-r-20" type="primary" @click="resetPassword(scope.row)">重置密码</el-link>
+                    <el-link type="danger" @click="handleDelete(scope.$index, scope.row)">删除</el-link>
+                  </template>
+                </el-table-column>
+              </el-table>
+               <el-input v-model="copyText" ref="copyInput" type="textarea" style='opacity: 0;position: absolute;'></el-input>
+            </div>
+            <div class="flex jc-al-c mg-t-20">
+              <span>添加项目人员</span>
+              <el-select v-model="userId" filterable placeholder="请输入搜索">
+                <el-option v-for="item in userList" :key="item.id" :label="item.name"  :value="item.id"></el-option>
+              </el-select>
+              <el-button type="success" @click="addUserToProject">添加</el-button>
+              <el-button type="primary">创建新用户</el-button>
+              <el-button type="danger" @click="handleDeletes">全部删除</el-button>
+            </div>
+            <el-divider></el-divider>
+          </div>
+        </el-tab-pane>
+      </el-tabs>
+
+      <div class="flex jc-sb">
+        <div></div>
+        <div>
+          <el-button type="success" size="medium" @click="saveQuit">保存并退出</el-button>
+          <el-button type="info" size="medium" v-if="activeType != 1" @click="saveNext('p')">保存并返回上一步</el-button>
+          <el-button type="info" size="medium" v-if="activeType != 3" @click="saveNext('n')">保存并进入下一步</el-button>
+        </div>
+      </div>
+    </div>
+
+  </basic-container>
+</template>
+
+<script>
+  import {getProjectDeatil} from "@/api/manager/projectinfo";
+  import {submitContractInfo,getContractInfo,delFileFromUrl,
+          findJobByRoleId,findAllUserByCondition,findUserByName,
+          saveUserInfoByProject,removeUsersByIds,resetPasswordByUserId} from "@/api/manager/contractinfo";
+  import {getRoleTree} from "@/api/system/role";
+  import {getList as getwbsList} from "@/api/manager/wbsinfo";
+  import {getAlltree} from "@/api/manager/wbstree";
+  import {getDictionary} from "@/api/system/dict";
+  import {remove as removeFile} from "@/api/resource/attach";
+  import website from '@/config/website';
+  import {Base64} from 'js-base64';
+  import {getToken} from '@/util/auth';
+  import {mapGetters} from "vuex";
+
+  import treeTree from "@/components/tree-tree/main"
+  export default {
+    components: {
+      treeTree
+    },
+    data() {
+      return {
+        activeType:'1',
+        typeChang:{
+          1:false,
+          2:false,
+          3:false,
+        },
+
+        pid:'',
+        cid:'',
+        projectInfo:{},
+
+        contractTypeList:[],
+        fileList:[],
+        headers:{},
+        isBackShow:false,
+
+        contractForm:{},
+        contractRules:{
+          contractName: [
+            { required: true, message: '请输入合同段名称', trigger: 'blur' },
+          ],
+        },
+
+        mapDialogVisible:false,
+        params:{
+          zoom: 10,
+          // zoomEnable: false,
+          // dragEnable: false,
+        },
+        flageData:[],
+
+        rId:'',
+        roleList:[],
+        postId:'',
+        postList:[],
+        contractUserList:[],
+        userId:'',
+        userList:[],
+        copyText:'',
+
+        wbsId:'',
+        wbsList:[],
+        leftTreeData:[],
+      }
+    },
+    computed: {
+      ...mapGetters(["userInfo"]),
+    },
+    watch:{
+      contractForm:{
+        handler: function() { // 此处注意,handler函数不能为箭头函数,this会取上下文,而不是组件里的this,此外,深度监听,必须为handler函数名,否则会无效果
+          this.typeChang['1'] = true;
+        },
+        deep: true
+      },
+      activeType: function (newValue) {
+        if(newValue == '3'){
+          this.getRoleList();
+          this.getUserByName();
+        }else if(newValue == '2'){
+          this.getWBSList();
+        }
+      },
+      rId:function(newValue){
+        findJobByRoleId(newValue).then((res)=>{
+          this.postList = res.data.data;
+        }).catch(()=>{
+          this.postList = [];
+        }).finally(()=>{
+          this.postId = '';
+        })
+      },
+      postId:function(newValue){
+        if(newValue){
+          this.findAllUserByCondition();
+        }else{
+          this.contractUserList = [];
+        }
+      }
+    },
+    created() {
+      this.init();
+      //console.log(this.userInfo)
+    },
+    mounted(){
+      this.$nextTick(()=>{
+        this.typeChang = {
+          1:false,
+          2:false,
+          3:false,
+        }
+      })
+    },
+    methods: {
+      init(){
+        this.pid = this.$route.query.pid;
+        this.cid = this.$route.query.cid;
+        if(!this.cid){
+          this.contractForm.pid = this.pid;
+        }else{
+          this.getContractInfo();
+        }
+        if(this.$route.query.type){
+          this.activeType = this.$route.query.type;
+        }
+
+        this.getContractTypeList();
+        this.getProjectDeatil();
+        this.setHeaders(); 
+      },
+      beforeLeave(activeName, oldActiveName){
+        if(oldActiveName == '1' && !this.contractForm.id){
+          this.$message({
+            type: "warning",
+            message: "请先保存合同段后,再进行合同段的分配"
+          });
+          return false;
+        }
+
+       if(this.typeChang[oldActiveName]){
+         this.$confirm('检测到新编辑内容, 是否保存?', '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '不用',
+          type: 'warning'
+        }).then(() => {
+          switch (oldActiveName) {
+            case '1':
+              this.savecontract().then((res)=>{
+                this.contractForm.id = res.data.data.id;
+                this.$message({
+                  type: "success",
+                  message: "保存成功!"
+                });
+              });
+              break;
+          }
+        })
+       }
+      },
+
+      getProjectDeatil(){
+        getProjectDeatil(this.pid).then((res)=>{
+          this.projectInfo = res.data.data;
+        })
+      },
+      getContractInfo(){
+        getContractInfo(this.cid).then((res)=>{
+          this.contractForm = res.data.data;
+          if(this.contractForm.startFileUrl){
+            this.isBackShow = true;
+          }
+          if(this.contractForm.projectPlace){
+            this.flageData = ['','',this.contractForm.projectPlace]
+          }
+          this.$nextTick(()=>{
+            this.typeChang['1'] = false;
+          })
+        })
+      },
+
+      async saveQuit(){
+        if(this.activeType == '1'){
+          await this.savecontract();
+        }
+        this.$message({
+          type: "success",
+          message: "保存成功!"
+        });
+        this.$router.go(-1);
+      },
+      async saveNext(type){
+        if(this.activeType == '1'){
+          let res = await this.savecontract();
+          this.contractForm.id = res.data.data.id;
+        }
+        this.$message({
+          type: "success",
+          message: "保存成功!"
+        });
+        this.typeChang[this.activeType] = false;
+        let num = Number(this.activeType);
+        if(type == 'n'){
+            num++;
+        }else if(type == 'p'){
+            num--;
+        }
+
+        this.activeType = num.toString();
+      },
+
+      savecontract(){
+        return new Promise((resolve, reject) => {
+          this.$refs['contractForm'].validate((valid) => {
+          if (valid) {
+            if(this.flageData.length ==3){
+              this.contractForm.projectPlace = this.flageData[2];
+            }
+            resolve(submitContractInfo(this.contractForm))
+          }else{
+            reject('验证失败')
+          }
+        })
+        })
+      },
+
+      handleRemove(file) {
+        //console.log(file, fileList);
+        removeFile(file.response.data.attachId).then(()=>{
+          this.contractForm.startFileUrl = '';
+        })
+      },
+      handleExceed() {
+        this.$message.warning(`当前限制选择 1 个文件,请先移除后,再次上传`);
+      },
+      handleSuccess(res){
+        this.contractForm.startFileUrl = res.data.link;
+      },
+      setHeaders(){
+        this.headers['Authorization'] = `Basic ${Base64.encode(`${website.clientId}:${website.clientSecret}`)}`;
+        this.headers[website.tokenHeader] = 'bearer ' + getToken()
+      },
+
+      downloadFile(){
+        window.open(this.contractForm.startFileUrl);
+      },
+      delFile(){
+        this.$confirm('是否删除该文件?', '删除开工令', {
+          distinguishCancelAndClose: true,
+          confirmButtonText: '删除',
+          cancelButtonText: '取消'
+        }).then(() => {
+          delFileFromUrl(this.contractForm.startFileUrl).then(()=>{
+            this.isBackShow = false;
+            this.contractForm.startFileUrl = '';
+          })
+        })
+      },
+
+      addUserToProject(){
+        if(!this.userId){
+          this.$message({
+              type: "warning",
+              message: "请先选择用户再进行添加"
+            });
+          return;
+        }
+        if(!this.postId){
+          this.$message({
+              type: "warning",
+              message: "请先选择岗位再进行添加"
+            });
+          return;
+        }
+        if(!this.rId){
+          this.$message({
+              type: "warning",
+              message: "请先选择角色再进行添加"
+            });
+          return;
+        }
+        let list = [{
+          projectId:this.pid,
+          contractId:this.contractForm.id,
+          userId:this.userId,
+          postId:this.postId,
+          roleId:this.rId
+        }];
+        saveUserInfoByProject(list).then(()=>{
+          this.findAllUserByCondition();
+        })
+      },
+
+      findAllUserByCondition(){
+        findAllUserByCondition({
+          "cId": this.contractForm.id,
+          "pId": this.pid,
+          "postId": this.postId,
+          "rId": this.rId
+        }).then((res)=>{
+          this.contractUserList = res.data.data;
+        })
+      },
+
+      handleDelete(index,row){
+        this.$confirm('是否将该用户移除出合同段', '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning'
+        }).then(() => {
+          removeUsersByIds(row.id).then(()=>{
+            this.contractUserList.splice(index,1);
+            this.$message({
+              type: "success",
+              message: "删除成功!"
+            });
+          })
+        })
+      },
+      handleDeletes(){
+        this.$confirm('是否将所有用户移除出合同段', '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning'
+        }).then(() => {
+          let ids = [];
+          this.contractUserList.forEach((element)=>{
+            ids.push(element.id);
+          })
+          removeUsersByIds(ids.join(',')).then(()=>{
+            this.contractUserList = [];
+            this.$message({
+              type: "success",
+              message: "删除成功!"
+            });
+          })
+        })
+      },
+
+      copyAccPas(row){
+        this.copyText = `姓名:${row.name}
+账号:${row.account}
+密码:${row.password}`;
+        this.$nextTick(()=>{
+          this.$refs.copyInput.select()
+          document.execCommand('copy')
+          this.$message({
+            type: "success",
+            message: "成功复制在剪贴板!"
+          });
+        })
+ 
+      },
+
+      resetPassword(row){
+        this.$confirm('是否将用户【'+row.name+'】密码重置为123456', '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning'
+        }).then(() => {
+          resetPasswordByUserId(row.uId).then(()=>{
+            row.password = '123456';
+            this.$message({
+              type: "success",
+              message: "重置成功!"
+            });
+          })
+        })
+      },
+
+      getContractTypeList(){
+        if(this.contractTypeList.length >1){
+          return;
+        }
+        getDictionary({
+          code:'contract_type'
+        }).then((res)=>{
+          res.data.data.forEach(element => {
+            element.dictKey = Number(element.dictKey)
+          });
+          this.contractTypeList = res.data.data;
+        })
+      },
+
+      getRoleList(){
+        if(this.roleList.length > 1){
+          return;
+        }
+
+        getRoleTree().then((res)=>{
+          let list = [];
+          res.data.data.forEach((element)=>{
+            if(element.title == '监理方'||
+               element.title == '业主方'){
+                 list.push(element);
+            }else if(element.title == '施工方'){
+              //给个默认
+              this.rId = element.id;
+              list.push(element);
+            }
+          })
+          this.roleList = list;
+        })
+      },
+      getUserByName(){
+       findUserByName('').then((res)=>{
+         this.userList = res.data.data;
+       })
+     },
+
+    getWBSList(){
+      getwbsList().then((res)=>{
+        this.wbsList = res.data.data.records;
+      })
+    },
+    wbsChange(wbsid){
+      getAlltree(this.userInfo.tenant_id,'',wbsid).then((res)=>{
+        this.leftTreeData = res.data.data;
+      })
+    },
+
+    }
+  };
+</script>
+
+<style scoped lang="scss">
+  .bm-view {
+    width: 100%;
+    height: 300px;
+  }
+</style>

+ 428 - 0
src/views/manager/projectinfo/detail.vue

@@ -0,0 +1,428 @@
+<template>
+  <basic-container>
+    <div>
+      <el-tabs v-model="activeType" :before-leave="beforeLeave">
+        <el-tab-pane label="项目基本信息" name="1">
+          <div>
+            <el-form :model="projectForm" :rules="projectRules" ref="projectForm" label-width="120px">
+              <el-row>
+                <el-col :span="12">
+                  <el-form-item label="项目名称" prop="projectName">
+                    <el-input v-model="projectForm.projectName"></el-input>
+                  </el-form-item>
+                  <el-form-item label="项目别名" prop="projectAlias">
+                    <el-input v-model="projectForm.projectAlias"></el-input>
+                  </el-form-item>
+                  <el-form-item label="项目编号" prop="projectNumber">
+                    <el-input v-model="projectForm.projectNumber"></el-input>
+                  </el-form-item>
+                  <el-form-item label="公路等级" prop="projectGrade">
+                    <el-select v-model="projectForm.projectGrade" placeholder="请选择" class="w-100p">
+                      <el-option v-for="item in highwayGradeList" :key="item.id" :label="item.dictValue"  :value="item.dictKey"></el-option>
+                    </el-select>
+                  </el-form-item>
+                  <el-form-item label="计划开工日期" prop="planStartTime">
+                    <el-date-picker  v-model="projectForm.planStartTime"  type="date" format="yyyy 年 MM 月 dd 日" value-format="yyyy-MM-dd HH:mm:ss" placeholder="选择日期"></el-date-picker>
+                  </el-form-item>
+                  <el-form-item label="实际开工日期" prop="actualStartTime">
+                    <el-date-picker  v-model="projectForm.actualStartTime"  type="date" format="yyyy 年 MM 月 dd 日" value-format="yyyy-MM-dd HH:mm:ss" placeholder="选择日期"></el-date-picker>
+                  </el-form-item>
+                  <el-form-item label="项目预算投资" prop="estimatedAmount">
+                    <el-input v-model="projectForm.estimatedAmount">
+                      <template slot="append">万元</template>
+                    </el-input>
+                  </el-form-item>
+                </el-col>
+                <el-col :span="12">
+                  <el-form-item label="项目概况" prop="projectGist">
+                    <el-input v-model="projectForm.projectGist" type="textarea" :rows="7"></el-input>
+                  </el-form-item>
+                  <el-form-item label="内置里程">
+                    <el-radio-group v-model="radioType">
+                      <el-radio-button label="总里程"></el-radio-button>
+                      <el-radio-button label="路面"></el-radio-button>
+                      <el-radio-button label="路基"></el-radio-button>
+                    </el-radio-group>
+                    <el-input-number v-model="projectForm.projectAllMileage" v-show="radioType == '总里程'" :min="0" label="总里程"></el-input-number>
+                    <el-input-number v-model="projectForm.projectPavement" v-show="radioType == '路面'" :min="0" label="路面"></el-input-number>
+                    <el-input-number v-model="projectForm.projectSubgrade" v-show="radioType == '路基'" :min="0" label="路基"></el-input-number>
+                  </el-form-item>
+                  <el-form-item label="计划完工日期" prop="planEndTime">
+                    <el-date-picker  v-model="projectForm.planEndTime"  type="date" format="yyyy 年 MM 月 dd 日" value-format="yyyy-MM-dd HH:mm:ss" placeholder="选择日期"></el-date-picker>
+                  </el-form-item>
+                  <el-form-item label="实际完工日期" prop="actualEndTime">
+                    <el-date-picker  v-model="projectForm.actualEndTime"  type="date" format="yyyy 年 MM 月 dd 日" value-format="yyyy-MM-dd HH:mm:ss" placeholder="选择日期"></el-date-picker>
+                  </el-form-item>
+                </el-col>
+              </el-row>
+            </el-form>
+          </div>
+        </el-tab-pane>
+        <el-tab-pane label="分配WBS模版" name="2">
+          <div>
+            <div class="text-align-c">
+              <el-radio-group v-model="templateType">
+                <el-radio :label="1">试验</el-radio>
+                <el-radio :label="2">质检</el-radio>
+              </el-radio-group>
+            </div>
+            <div class="text-align-c mg-t-20">
+              <span class="mg-r-20">选择WBS</span>
+              <el-select v-model="wbsId" @change="wbsChange" placeholder="请选择WBS" style="width:500px;">
+                <el-option v-for="item in wbsList" :key="item.id" :label="item.wbsName" :value="item.id"></el-option>
+              </el-select>
+            </div>
+            <tree-tree :left-tree-data="leftTreeData" scrollbarStyle="height:calc(100vh - 500px)"></tree-tree>
+          </div>
+        </el-tab-pane>
+        <el-tab-pane label="分配系统维护人员" name="3">
+          <div>
+            <div class="flex jc-al-c">
+              <span class="mg-r-10">项目名称</span>
+              <el-input v-model="projectForm.projectName" disabled style="width:300px;margin-right:30px;"></el-input>
+              <span class="mg-r-10">合同段名称</span>
+              <el-select v-model="cId" placeholder="请选择" @change="getUserByCondition">
+                <el-option label="全部"  value=""></el-option>
+                <el-option v-for="item in contractList" :key="item.id" :label="item.contractName"  :value="item.id"></el-option>
+              </el-select>
+            </div>
+            <el-divider></el-divider>
+            <div class="flex jc-al-c mg-b-10">
+              <span>维护人员角色</span>
+              <avue-input-tree :check-strictly="true" v-model="rId" placeholder="请选择" type="tree" :dic="roleList" :props="treeProps"></avue-input-tree>
+              <!-- <el-select v-model="rId" clearable placeholder="请选择" @change="getUserByCondition">
+                <el-option v-for="item in roleList" :key="item.id" :label="item.title"  :value="item.id"></el-option>
+              </el-select> -->
+            </div>
+            <div>
+              <el-table  :data="contractUserList" border height="500" style="width: 100%">
+                <el-table-column prop="name" label="姓名" align="center"></el-table-column>
+                <el-table-column prop="postName" label="岗位" align="center"></el-table-column>
+                <el-table-column prop="phone" label="电话" align="center"></el-table-column>
+                <el-table-column label="操作" align="center">
+                  <template slot-scope="scope">
+                    <el-button
+                      size="mini"
+                      type="danger"
+                      @click="handleDelete(scope.$index, scope.row)">删除</el-button>
+                  </template>
+                </el-table-column>
+              </el-table>
+            </div>
+            <div class="flex jc-al-c mg-t-20">
+              <span>添加系内部人员</span>
+              <el-select v-model="userId" filterable placeholder="请输入搜索">
+                <el-option v-for="item in userList" :key="item.id" :label="item.name"  :value="item.id"></el-option>
+              </el-select>
+              <el-button type="success" @click="addUserToProject">添加</el-button>
+              <el-button type="primary">创建新用户</el-button>
+              <el-button type="danger" @click="handleDeletes">全部删除</el-button>
+            </div>
+            <el-divider></el-divider>
+          </div>
+        </el-tab-pane>
+      </el-tabs>
+
+      <div class="flex jc-sb">
+        <div></div>
+        <div>
+          <el-button type="success" size="medium" @click="saveQuit">保存并退出</el-button>
+          <el-button type="info" size="medium" v-if="activeType != 1" @click="saveNext('p')">保存并返回上一步</el-button>
+          <el-button type="info" size="medium" v-if="activeType != 3" @click="saveNext('n')">保存并进入下一步</el-button>
+        </div>
+      </div>
+    </div>
+  </basic-container>
+</template>
+
+<script>
+  import {submitProject,getProjectDeatil} from "@/api/manager/projectinfo";
+  import {findContractByProjectId,saveUserInfoByProject,findUserListByCondition,
+          findUserByName,removeUsersByIds} from "@/api/manager/contractinfo";
+  import {getRoleTree} from "@/api/system/role";
+  import {getDictionary} from "@/api/system/dict";
+  import {mapGetters} from "vuex";
+
+  import treeTree from "@/components/tree-tree/main"
+  export default {
+    components: {
+      treeTree
+    },
+    data() {
+      return {
+        activeType:'1',
+        typeChang:{
+          1:false,
+          2:false,
+          3:false,
+        },
+
+        id:'',
+        highwayGradeList:[],
+        radioType:'总里程',
+
+        projectForm:{},
+        projectRules:{
+          projectName: [
+            { required: true, message: '请输入项目名称', trigger: 'blur' },
+          ],
+          projectAlias: [
+            { required: true, message: '请输入项目别名', trigger: 'blur' },
+          ],
+        },
+
+        contractList:[],
+        cId:'',
+        rId:'',
+        roleList:[],
+        userId:'',
+        userList:[],
+        contractUserList:[],
+
+        treeProps:{
+          label:"title",
+          value:"id"
+        },
+
+        templateType:2,
+
+      }
+    },
+    computed: {
+      ...mapGetters(["userInfo"]),
+    },
+    watch:{
+      projectForm:{
+        handler: function() { // 此处注意,handler函数不能为箭头函数,this会取上下文,而不是组件里的this,此外,深度监听,必须为handler函数名,否则会无效果
+          this.typeChang['1'] = true;
+        },
+        deep: true
+      },
+      activeType: function (newValue) {
+        if(newValue == '3'){
+          this.getContractList();
+          this.getRoleList();
+          this.getUserByCondition();
+          this.getUserByName();
+        }
+      }
+    },
+    created() {
+      this.init();
+      //console.log(this.userInfo)
+    },
+    mounted(){
+      this.$nextTick(()=>{
+        this.typeChang = {
+          1:false,
+          2:false,
+          3:false,
+        }
+      })
+    },
+    methods: {
+     init(){
+       this.getHighwayGradeList();
+       this.id = this.$route.query.id;
+       if(this.id){
+         this.getProjectDeatil();
+       }
+     },
+      beforeLeave(activeName, oldActiveName){
+        if(oldActiveName == '1' && !this.projectForm.id){
+          this.$message({
+            type: "warning",
+            message: "请先保存项目后,再进行项目的分配"
+          });
+          return false;
+        }
+
+       if(this.typeChang[oldActiveName]){
+         this.$confirm('检测到新编辑内容, 是否保存?', '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '不用',
+          type: 'warning'
+        }).then(() => {
+          switch (oldActiveName) {
+            case '1':
+              this.saveProject().then((res)=>{
+                this.projectForm.id = res.data.data.id;
+                this.$message({
+                  type: "success",
+                  message: "保存成功!"
+                });
+              });
+              break;
+          }
+        })
+       }
+     },
+
+     getProjectDeatil(){
+        getProjectDeatil(this.id).then((res)=>{
+          this.projectForm = res.data.data;
+          this.$nextTick(()=>{
+            this.typeChang['1'] = false;
+          })
+        })
+      },
+
+     async saveQuit(){
+       if(this.activeType == '1'){
+          await this.saveProject();
+        }
+       this.$message({
+          type: "success",
+          message: "保存成功!"
+        });
+        this.$router.go(-1);
+     },
+     async saveNext(type){
+        if(this.activeType == '1'){
+          let res = await this.saveProject();
+          this.projectForm.id = res.data.data.id;
+        }
+        this.$message({
+          type: "success",
+          message: "保存成功!"
+        });
+        this.typeChang[this.activeType] = false;
+        let num = Number(this.activeType);
+        if(type == 'n'){
+            num++;
+        }else if(type == 'p'){
+            num--;
+        }
+        
+        this.activeType = num.toString();
+     },
+
+     saveProject(){
+       return new Promise((resolve, reject) => {
+         this.$refs['projectForm'].validate((valid) => {
+          if (valid) {
+            resolve(submitProject(this.projectForm))
+          }else{
+            reject('验证失败')
+          }
+        })
+       })
+     },
+
+     addUserToProject(){
+       if(!this.userId){
+         this.$message({
+            type: "warning",
+            message: "请先选择用户再进行添加"
+          });
+         return;
+       }
+       if(!this.rId){
+         this.$message({
+            type: "warning",
+            message: "请先选择维护人员角色再进行添加"
+          });
+         return;
+       }
+       let list = [{
+         projectId:this.projectForm.id,
+         contractId:this.cId?this.cId:undefined,
+         userId:this.userId,
+         roleId:this.rId
+       }];
+       saveUserInfoByProject(list).then(()=>{
+         this.getUserByCondition();
+       })
+     },
+
+     getUserByCondition(){
+       findUserListByCondition({
+         cId:this.cId,
+         pId:this.projectForm.id,
+         postId:'',
+         rId:this.rId,
+       }).then((res)=>{
+         this.contractUserList = res.data.data;
+       })
+     },
+
+     getUserByName(){
+       findUserByName('').then((res)=>{
+         this.userList = res.data.data;
+       })
+     },
+
+     handleDelete(index,row){
+      this.$confirm('是否将该用户移除出合同段', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        removeUsersByIds(row.id).then(()=>{
+          this.contractUserList.splice(index,1);
+          this.$message({
+            type: "success",
+            message: "删除成功!"
+          });
+        })
+      })
+     },
+     handleDeletes(){
+      this.$confirm('是否将所有用户移除出合同段', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        let ids = [];
+        this.contractUserList.forEach((element)=>{
+          ids.push(element.id);
+        })
+        removeUsersByIds(ids.join(',')).then(()=>{
+          this.contractUserList = [];
+          this.$message({
+            type: "success",
+            message: "删除成功!"
+          });
+        })
+      })
+     },
+
+     getHighwayGradeList(){
+        if(this.highwayGradeList.length >1){
+          return;
+        }
+        getDictionary({
+          code:'highway_grade'
+        }).then((res)=>{
+          res.data.data.forEach(element => {
+            element.dictKey = Number(element.dictKey)
+          });
+          this.highwayGradeList = res.data.data;
+        })
+      },
+
+      getContractList(){
+        if(this.contractList.length < 1){
+          findContractByProjectId(this.projectForm.id).then((res)=>{
+            this.contractList = res.data.data;
+          })
+        }
+      },
+
+      getRoleList(){
+        if(this.roleList.length > 1){
+          return;
+        }
+
+        getRoleTree().then((res)=>{
+          this.roleList = res.data.data
+        })
+      }
+
+    }
+  };
+</script>
+
+<style scoped lang="scss">
+  
+</style>

+ 246 - 0
src/views/manager/projectinfo/list.vue

@@ -0,0 +1,246 @@
+<template>
+  <basic-container>
+    <div>
+      <div class="pd-b-20 border-grey-b">
+        <span class="mg-r-10">选择项目名称</span>
+        <el-select v-model="projectId" @change="projectChange" placeholder="请选择">
+          <el-option  v-for="item in projectList"  :key="item.id" :label="item.projectName" :value="item.id"></el-option>
+        </el-select>
+      </div>
+      <div class="pd-t-20">
+        <el-row :gutter="20"  style="height:calc(100vh - 290px)">
+          <el-col :span="6" v-for="(item,index) in projectPageList" :key="item.id" style="height:20%;" class="mg-b-20 box-size-bb">
+            <el-card @click.native="projectClick(item)" class="box-card h-100p flex flex-center project_name" :class="getBg(index)">
+              {{item.projectAlias}}
+            </el-card>
+          </el-col>
+        </el-row>
+      </div>
+      <div>
+        <el-pagination
+          layout="prev, pager, next" class="text-align-c"
+          @current-change="handleCurrentChange"
+          :current-page.sync="page.currentPage"
+          :total="page.total" :page-size="page.pageSize">
+        </el-pagination>
+      </div>
+    </div>
+
+    <el-dialog title="项目信息" :visible.sync="projectVisible" width="800px" append-to-body>
+      <div class="flex jc-sb pd-b-10">
+        <span>{{curProjiect.projectName}}</span>
+        <div>
+          <el-button size="small" type="success">WBS树管理</el-button>
+          <el-button size="small" @click="editProject" type="primary">编辑项目信息</el-button>
+          <el-button size="small" @click="addContract" type="info">创建新合同段</el-button>
+          <el-button size="small" @click="projectVisible = false">返回</el-button>
+        </div>
+      </div>
+      <div style="height:400px;overflow: auto;" v-if="contractList.length > 0">
+        <el-card shadow="never" v-for="(item,index) in contractList" :key="item.id">
+          <div class="flex jc-sb">
+            <div class="flex jc-al-c">
+              <el-avatar :size="50" :class="getAvatarBg(item.contractType)">{{getFont(item.contractType)}}</el-avatar>
+              <span class="mg-l-10">{{item.contractName}}</span>
+            </div>
+            <div class="flex jc-al-c">
+              <el-link type="primary" @click="editContract(item)">编辑合同段信息</el-link>
+              <el-link type="primary" class="mg-l-10" @click="contractDetail(item,'2')">分配WBS</el-link>
+              <el-link type="primary" class="mg-l-10" @click="contractDetail(item,'3')">分配项目人员</el-link>
+              <el-link type="primary" class="mg-l-10" @click="delContract(item,index)">删除</el-link>
+            </div>
+          </div>
+        </el-card>
+      </div>
+      <div class="text-align-c pd-t-20" v-else>
+        暂无合同段,请先创建合同段
+      </div>
+    </el-dialog>
+  </basic-container>
+</template>
+
+<script>
+  import {getProjectList} from "@/api/manager/projectinfo";
+  import {findContractByProjectId,removeContractInfo} from "@/api/manager/contractinfo";
+  import {getDictionary} from "@/api/system/dict";
+  import {mapGetters} from "vuex";
+  export default {
+    data() {
+      return {
+        projectId:'',
+        curProjiect:{},
+        projectList:[],
+        projectPageList:[],
+
+        projectVisible:false,
+        contractList:[],
+
+        page:{
+          currentPage:1,
+          pageSize:16,
+          total:0
+        }
+      }
+    },
+    computed: {
+      ...mapGetters(["userInfo"]),
+    },
+    created() {
+      this.init();
+      //console.log(this.userInfo)
+    },
+    methods: {
+      init(){
+        this.getProjectList();
+        this.getProjectPageList();
+      },
+
+      getProjectList(){
+        getProjectList(1,999).then((res)=>{
+          this.projectList = res.data.data.records;
+        })
+      },
+      getProjectPageList(){
+        getProjectList(this.page.currentPage,this.page.pageSize).then((res)=>{
+          this.projectPageList = res.data.data.records;
+          this.page.total = res.data.data.total;
+        })
+      },
+
+      projectClick(item){
+        this.curProjiect = item;
+        findContractByProjectId(this.curProjiect.id).then((res)=>{
+          this.contractList = res.data.data;
+        })
+        this.projectVisible = true;
+      },
+
+      handleCurrentChange(val){
+        this.getProjectPageList();
+        this.page.currentPage = val;
+      },
+
+      projectChange(id){
+        for (let i = 0; i < this.projectList.length; i++) {
+          if(id == this.projectList[i].id){
+            this.curProjiect = this.projectList[i];
+            findContractByProjectId(this.curProjiect.id).then((res)=>{
+              this.contractList = res.data.data;
+            })
+            this.projectVisible = true;
+            return;
+          }
+        }
+      },
+
+      addContract(){
+        this.$router.push({
+          path:'/contract/detail',
+          query:{pid:this.curProjiect.id}
+        });
+      },
+      editContract(item){
+        this.$router.push({
+          path:'/contract/detail',
+          query:{
+            pid:item.pid,
+            cid:item.id,
+          }
+        });
+      },
+      editProject(){
+        this.$router.push({
+          path:'/manager/projectinfo/detail',
+          query:{
+            id:this.curProjiect.id
+          }
+        });
+      },
+      contractDetail(item,type){
+        this.$router.push({
+          path:'/contract/detail',
+          query:{
+            pid:item.pid,
+            cid:item.id,
+            type,
+          }
+        });
+      },
+
+      delContract(item,index){
+        this.$confirm('是否删除【'+item.contractName+'】?', '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning'
+        }).then(() => {
+          removeContractInfo(item.id).then(()=>{
+            this.$message({
+              type: "success",
+              message: "删除成功!"
+            });
+            this.contractList.splice(index,1);
+          })
+        })
+      },
+
+      getFont(type){
+        if(type == 1){
+          return '施';
+        }else if(type == 2){
+          return '监';
+        }else if(type == 3){
+          return '业';
+        }
+        return '';
+      },
+      getAvatarBg(type){
+        if(type == 1){
+          return {'abg1':true};
+        }else if(type == 2){
+          return {'abg2':true};
+        }else if(type == 3){
+          return {'abg3':true};
+        }
+        return {};
+      },
+      getBg(index){
+        let num = Math.trunc(index/4);
+        if((num%2)===0){//判定条件余数为0时为偶数
+          return{
+            'bg1':true
+          }
+        }else{
+          return{
+            'bg2':true
+          }
+        }
+      }
+    }
+  };
+</script>
+
+<style scoped lang="scss">
+  .project_name{
+    font-size: 20px;
+    cursor: pointer;
+  }
+  .bg1{
+    background-color: rgb(127, 164, 221);
+    border-color: rgb(187, 187, 187);
+    box-shadow: rgba(0, 0, 0, .4) 0px 2px 6px 0px;
+  }
+  .bg2{
+    background-color: rgb(239, 240, 229);
+    border-color: rgb(187, 187, 187);
+    box-shadow: rgba(0, 0, 0, .4) 0px 2px 6px 0px;
+  }
+  .abg1{
+    background-color: rgb(42, 155, 121);
+  }
+  .abg2{
+    background-color: rgb(155, 108, 42);
+  }
+  .abg3{
+    background-color: rgb(42, 53, 155);
+  }
+</style>

+ 11 - 3
src/views/manager/wbsinfo.vue

@@ -66,6 +66,8 @@
             {
               label: "创建时间",
               prop: "createTime",
+              editDetail:true,
+              addDisabled:true,
             },
             {
               label: "wsb名称",
@@ -77,12 +79,18 @@
               }]
             },
             {
-              label: "wsb属性",
+              label: "划分类型",
+              type: "select",
+              dicUrl: "/api/blade-system/dict/dictionary?code=wbs_type",
+              props: {
+                label: "dictValue",
+                value: "dictKey"
+              },
+              dataType: "number",
               prop: "wbsType",
-              hide:true,
               rules: [{
                 required: true,
-                message: "请输入wsb属性",
+                message: "请选择划分类型",
                 trigger: "blur"
               }]
             },

+ 250 - 117
src/views/manager/wbsinfo/edit.vue

@@ -1,119 +1,124 @@
 <template>
-  <basic-container>
-    <div class="flex">
-      <div class="flex1 mg-r-20">
+<basic-container>
+<el-row :gutter="20">
+  <el-col :span="10">
+      <div class="box">
         <p>工程节点信息</p>
         <div class="flex">
           <el-input placeholder="输入关键字进行过滤" v-model="filterText" @input="filterChange"></el-input>
-          <el-button type="info" class="mg-l-20">导入划分</el-button>
+          <!-- <el-button type="info" class="mg-l-20">导入划分</el-button> -->
         </div>
-        <div v-loading="treeLoad">
-          <el-tree v-show="!filterText"
-            class="filter-tree" lazy
-            :load="loadNode" @node-click="getNodeDetail"
-            :props="defaultProps" :expand-on-click-node="false"
-            highlight-current node-key="id"
-            ref="tree">
-            <span class="custom-tree-node" slot-scope="{ node, data }">
-              <span>
-                {{ node.label }}
-                <el-dropdown @click="command=>{setLeftType(command,data)}">
-                  <el-button
-                    type="text" icon="el-icon-more" class="normal-black">
-                  </el-button>
-                  <el-dropdown-menu slot="dropdown">
-                    <el-dropdown-item @click.native="setLeftType(1,data,node)" icon="el-icon-circle-plus-outline">新增子级</el-dropdown-item>
-                    <el-dropdown-item @click.native="setLeftType(2,data,node)" icon="el-icon-edit">编辑节点</el-dropdown-item>
-                    <el-dropdown-item @click.native="setLeftType(3,data,node)" icon="el-icon-document-copy">复制节点</el-dropdown-item>
-                    <el-dropdown-item @click.native="setLeftType(4,data,node)" icon="iconfont hcicon-danganziliao-biaogetianxie" class="font-s-12">元素公式</el-dropdown-item>
-                    <el-dropdown-item @click.native="setLeftType(5,data,node)" icon="el-icon-coin">元素设置</el-dropdown-item>
-                  </el-dropdown-menu>
-                </el-dropdown>
-              </span>
-            </span>
-          </el-tree>
-          <el-tree v-show="filterText"
-            class="filter-tree"
-            :data="treeData" @node-click="getNodeDetail"
-            :props="defaultProps" :expand-on-click-node="false"
-            highlight-current node-key="id"
-            :filter-node-method="filterNode"
-            ref="treeall">
-            <span class="custom-tree-node" slot-scope="{ node, data }">
-              <span>
-                {{ node.label }}
-                <el-dropdown @click="command=>{setLeftType(command,data)}">
-                  <el-button
-                    type="text" icon="el-icon-more" class="normal-black">
-                  </el-button>
-                  <el-dropdown-menu slot="dropdown">
-                    <el-dropdown-item @click.native="setLeftType(1,data,node)" icon="el-icon-circle-plus-outline">新增子级</el-dropdown-item>
-                    <el-dropdown-item @click.native="setLeftType(2,data,node)" icon="el-icon-edit">编辑节点</el-dropdown-item>
-                    <el-dropdown-item @click.native="setLeftType(3,data,node)" icon="el-icon-document-copy">复制节点</el-dropdown-item>
-                    <el-dropdown-item @click.native="setLeftType(4,data,node)" icon="iconfont hcicon-danganziliao-biaogetianxie" class="font-s-12">元素公式</el-dropdown-item>
-                    <el-dropdown-item @click.native="setLeftType(5,data,node)" icon="el-icon-coin">元素设置</el-dropdown-item>
-                  </el-dropdown-menu>
-                </el-dropdown>
-              </span>
-            </span>
-          </el-tree>
-        </div>
-
-      </div>
-      <div class="flex1">
-        <template v-if="leftType==2 || leftType==1">
-          <p>节点信息</p>
-          <el-table :data="tableData" border style="width: 100%">
-            <el-table-column align="center" prop="deptName" label="当前节点" ></el-table-column>
-            <el-table-column align="center" prop="deptCategory" :formatter="formatCat" label="节点类型" width="180"></el-table-column>
-            <el-table-column align="center" prop="parentName" label="上级节点"></el-table-column>
-          </el-table>
-          <p>
-            <span>当前已创建的元素表</span>
-            <el-button @click="showFormElement" type="text" icon="el-icon-circle-plus-outline" class="text-icon mg-l-10"></el-button>
-            <el-button type="text" icon="el-icon-document-copy" class="text-icon"></el-button>
-          </p>
-          <el-table :data="formData" border style="width: 100%">
-            <el-table-column align="center" prop="tableName" label="表单名称" ></el-table-column>
-            <el-table-column align="center" prop="elementTotal" label="元素总量"></el-table-column>
-            <el-table-column align="center" prop="tableType" :formatter="formatTableType" label="表单类型"></el-table-column>
-            <el-table-column align="center" prop="tableOwner" :formatter="formatOwner" label="所属方"></el-table-column>
-            <el-table-column label="操作">
-              <template slot-scope="scope">
-                <el-button
-                  size="mini"
-                  @click="handleEdit(scope.$index, scope.row)">编辑</el-button>
-                <el-button
-                  size="mini"
-                  type="danger"
-                  @click="handleDelete(scope.$index, scope.row)">删除</el-button>
-              </template>
-            </el-table-column>
-          </el-table>
-        </template>
-        <template v-if="leftType==4">
-          <el-table :data="formData" border style="width: 100%">
-            <el-table-column align="center" prop="tableName" label="表单名称" ></el-table-column>
-            <el-table-column align="center" prop="elementTotal" label="元素总量"></el-table-column>
-            <el-table-column align="center" prop="tableType" :formatter="formatTableType" label="表单类型"></el-table-column>
-            <el-table-column align="center" prop="tableOwner" :formatter="formatOwner" label="所属方"></el-table-column>
-            <el-table-column label="操作">
-              <template slot-scope="scope">
-                <el-button
-                  size="mini"
-                  @click="handleEdit(scope.$index, scope.row)">编辑</el-button>
-                <el-button
-                  size="mini"
-                  type="danger"
-                  @click="handleDelete(scope.$index, scope.row)">删除</el-button>
-              </template>
-            </el-table-column>
-          </el-table>
-        </template>
+        <el-scrollbar>
+            <div v-loading="treeLoad">
+              <el-tree v-show="!filterText"
+                class="filter-tree" lazy
+                :load="loadNode" @node-click="getNodeDetail"
+                :props="defaultProps" :expand-on-click-node="false"
+                highlight-current node-key="id"
+                ref="tree">
+                <span class="custom-tree-node" slot-scope="{ node, data }">
+                  <span>
+                    {{ node.label }}
+                    <el-dropdown @click="command=>{setLeftType(command,data)}">
+                      <el-button
+                        type="text" icon="el-icon-more" class="normal-black">
+                      </el-button>
+                      <el-dropdown-menu slot="dropdown">
+                        <el-dropdown-item @click.native="setLeftType(1,data,node)" icon="el-icon-circle-plus-outline">新增子级</el-dropdown-item>
+                        <el-dropdown-item @click.native="setLeftType(2,data,node)" icon="el-icon-edit">编辑节点</el-dropdown-item>
+                        <el-dropdown-item @click.native="setLeftType(3,data,node)" icon="el-icon-document-copy">复制节点</el-dropdown-item>
+                        <el-dropdown-item @click.native="setLeftType(4,data,node)" icon="iconfont hcicon-danganziliao-biaogetianxie" class="font-s-12">元素公式</el-dropdown-item>
+                        <el-dropdown-item @click.native="setLeftType(5,data,node)" icon="el-icon-coin">元素设置</el-dropdown-item>
+                        <el-dropdown-item @click.native="importTemplate(data,node)" v-if="node.level == 2" icon="el-icon-upload">导入划分</el-dropdown-item>
+                      </el-dropdown-menu>
+                    </el-dropdown>
+                  </span>
+                </span>
+              </el-tree>
+              <el-tree v-show="filterText"
+                class="filter-tree"
+                :data="treeData" @node-click="getNodeDetail"
+                :props="defaultProps" :expand-on-click-node="false"
+                highlight-current node-key="id"
+                :filter-node-method="filterNode"
+                ref="treeall">
+                <span class="custom-tree-node" slot-scope="{ node, data }">
+                  <span>
+                    {{ node.label }}
+                    <el-dropdown @click="command=>{setLeftType(command,data)}">
+                      <el-button
+                        type="text" icon="el-icon-more" class="normal-black">
+                      </el-button>
+                      <el-dropdown-menu slot="dropdown">
+                        <el-dropdown-item @click.native="setLeftType(1,data,node)" icon="el-icon-circle-plus-outline">新增子级</el-dropdown-item>
+                        <el-dropdown-item @click.native="setLeftType(2,data,node)" icon="el-icon-edit">编辑节点</el-dropdown-item>
+                        <el-dropdown-item @click.native="setLeftType(3,data,node)" icon="el-icon-document-copy">复制节点</el-dropdown-item>
+                        <el-dropdown-item @click.native="setLeftType(4,data,node)" icon="iconfont hcicon-danganziliao-biaogetianxie" class="font-s-12">元素公式</el-dropdown-item>
+                        <el-dropdown-item @click.native="setLeftType(5,data,node)" icon="el-icon-coin">元素设置</el-dropdown-item>
+                        <el-dropdown-item @click.native="importTemplate(data,node)" v-if="node.level == 2" icon="el-icon-upload">导入划分</el-dropdown-item>
+                      </el-dropdown-menu>
+                    </el-dropdown>
+                  </span>
+                </span>
+              </el-tree>
+            </div>
+        </el-scrollbar>
       </div>
-    </div>
+  </el-col>
+  <el-col :span="14">
+      <template v-if="leftType==2 || leftType==1">
+        <p>节点信息</p>
+        <el-table :data="tableData" border style="width: 100%">
+          <el-table-column align="center" prop="deptName" label="当前节点" ></el-table-column>
+          <el-table-column align="center" prop="deptCategory" :formatter="formatCat" label="节点类型" width="180"></el-table-column>
+          <el-table-column align="center" prop="parentName" label="上级节点"></el-table-column>
+        </el-table>
+        <p>
+          <span>当前已创建的元素表</span>
+          <el-button @click="showFormElement" type="text" icon="el-icon-circle-plus-outline" class="text-icon mg-l-10"></el-button>
+          <el-button type="text" icon="el-icon-document-copy" class="text-icon"></el-button>
+        </p>
+        <el-table :data="formData" border style="width: 100%">
+          <el-table-column align="center" prop="tableName" label="表单名称" ></el-table-column>
+          <el-table-column align="center" prop="elementTotal" label="元素总量"></el-table-column>
+          <el-table-column align="center" prop="tableType" :formatter="formatTableType" label="表单类型"></el-table-column>
+          <el-table-column align="center" prop="tableOwner" :formatter="formatOwner" label="所属方"></el-table-column>
+          <el-table-column label="操作">
+            <template slot-scope="scope">
+              <el-button
+                size="mini"
+                @click="handleEdit(scope.$index, scope.row)">编辑</el-button>
+              <el-button
+                size="mini"
+                type="danger"
+                @click="handleDelete(scope.$index, scope.row)">删除</el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+      </template>
+      <template v-if="leftType==4">
+        <el-table :data="formData" border style="width: 100%">
+          <el-table-column align="center" prop="tableName" label="表单名称" ></el-table-column>
+          <el-table-column align="center" prop="elementTotal" label="元素总量"></el-table-column>
+          <el-table-column align="center" prop="tableType" :formatter="formatTableType" label="表单类型"></el-table-column>
+          <el-table-column align="center" prop="tableOwner" :formatter="formatOwner" label="所属方"></el-table-column>
+          <el-table-column label="操作" width="200">
+            <template slot-scope="scope">
+              <el-button
+                size="mini"
+                @click="handleEditFormula(scope.$index, scope.row)">编辑元素公式</el-button>
+              <el-button
+                size="mini"
+                type="danger"
+                @click="handleDelete(scope.$index, scope.row)">删除</el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+      </template>
+  </el-col>
+</el-row>
 
-    <el-dialog :title="dialogTitle" :visible.sync="dialogVisible" width="50%" append-to-body>
+  <el-dialog :title="dialogTitle" :visible.sync="dialogVisible" width="50%" append-to-body :close-on-click-modal="false">
       <el-form ref="nodeDetail" :model="nodeDetail" :rules="rules" label-width="110px">
         <el-form-item label="节点名称" prop="deptName">
           <el-input v-model="nodeDetail.deptName"></el-input>
@@ -158,7 +163,7 @@
       </span>
     </el-dialog>
 
-    <el-dialog title="创建新的元素表" :visible.sync="eleVisible" width="80%" append-to-body>
+    <el-dialog title="创建新的元素表" :visible.sync="eleVisible" width="80%" append-to-body :close-on-click-modal="false">
       <el-form ref="eleDialog" :model="eleForm" :rules="eleRules" label-width="110px">
         <el-form-item label="表名" prop="deptName">
           <el-input v-model="eleForm.deptName"></el-input>
@@ -242,7 +247,7 @@
       </span>
     </el-dialog>
 
-    <el-dialog title="模版导入" :visible.sync="importVisible" width="50%" append-to-body>
+    <el-dialog title="模版导入" :visible.sync="importVisible" width="50%" append-to-body :close-on-click-modal="false">
       <p>提示:必须按照系统要求的模版格式上传,否则系统识别无效  <el-link type="primary">下载导入模版</el-link></p>
       <div>
         <el-button size="small" type="primary">本地上传</el-button>
@@ -265,7 +270,7 @@
       </span>
     </el-dialog>
 
-    <el-dialog :title="(curEleTable.tableName?curEleTable.tableName:'')+'  元素编辑'" :visible.sync="editEleVisible" width="80%" append-to-body>
+    <el-dialog :title="(curEleTable.tableName?curEleTable.tableName:'')+'  元素编辑'" :visible.sync="editEleVisible" width="80%" append-to-body :close-on-click-modal="false">
       <p class="font-c-warning">编辑元素信息(请谨慎操作)</p>
         <el-table :data="editEleList" border style="width: 100%" height="400px">
           <el-table-column align="center" type="index" width="50"></el-table-column>
@@ -322,13 +327,48 @@
         <el-button type="primary" @click="saveEles">确 定</el-button>
       </span>
     </el-dialog>
-  </basic-container>
+
+    <el-dialog title="元素公式" :visible.sync="editEleFormulaVisible" width="800px" append-to-body :close-on-click-modal="false">
+      <div class="flex mg-b-10">
+        <el-input v-model="formulaInput" placeholder="请输入内容" size="samll"></el-input>
+        <el-button type="info">保存</el-button>
+      </div>
+        <el-table :data="editEleList" border style="width: 100%" height="400px">
+          <el-table-column align="center" prop="eName" label="元素名称" >
+          </el-table-column>
+          <el-table-column align="center" label="操作" width="200">
+            <template slot-scope="scope">
+              <el-link type="primary" >公式配置</el-link>
+              <el-link class="mg-l-10" type="danger" @click="delEleRowHandle(scope.$index,editEleList)">删除</el-link>
+            </template>
+          </el-table-column>
+        </el-table>
+    </el-dialog>
+
+    <el-dialog title="导入划分" :visible.sync="importTemplateVisible" width="800px" append-to-body :close-on-click-modal="false">
+      <div v-loading="importLoading">
+        <div><el-link type="primary" @click="handleDownload">下载导入模版</el-link></div>
+        <div class="mg-t-20">
+          <el-button type="primary" @click="fileClick">选择文件</el-button>
+          <span v-if="upFile" class="mg-l-20">{{upFile.name}}</span>
+          <input @change="fileChange" type="file" hidden ref="file" accept=".xls, .xlsx">
+        </div>
+        <div v-if="!upFile">当前还未选择文件,请选择需要导入的文件</div>
+      </div>
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="importTemplateVisible = false">取 消</el-button>
+        <el-button type="primary" @click="importTemplateHandle" :loading="importLoading">导 入</el-button>
+      </span>
+    </el-dialog>
+</basic-container>
 </template>
 
 <script>
   import {getLazytree,getDetail,update,selectByNodeTable,getAlltree,
-            saveFormAndElement,selectFormElements,removeTableById} from "@/api/manager/wbstree";
-  import {saveElement,remove as removeElement,updateBatchElements} from "@/api/manager/wbsformelement"
+            saveFormAndElement,selectFormElements,removeTableById,
+            importWbsTree} from "@/api/manager/wbstree";
+  import {saveElement,remove as removeElement,updateBatchElements} from "@/api/manager/wbsformelement";
+  import {getList as getAttchFromOriginalName} from "@/api/resource/attach";
   import {getDictionary} from "@/api/system/dict";
   import {mapGetters} from "vuex";
   export default {
@@ -388,6 +428,14 @@
         curEleTable:{},
         editEleVisible:false,
         editEleList:[],
+
+        editEleFormulaVisible:false,
+        formulaInput:'',
+
+        importTemplateVisible:false,
+        fileUrl:'',
+        upFile:null,
+        importLoading:false,
       };
     },
     computed: {
@@ -421,7 +469,11 @@
           pid = node.data.id
         }
         getLazytree(this.id ,pid,this.userInfo.tenant_id).then((res)=>{
-          return resolve(res.data.data);
+          let arr = [];
+          if(Array.isArray(res.data.data)){
+            arr = res.data.data;
+          }
+          return resolve(arr);
         })
       },
 
@@ -617,6 +669,15 @@
         })
       },
 
+      handleEditFormula(index,row){
+        this.curEleTable = row;
+        selectFormElements(this.curEleTable.id).then((res)=>{
+
+          this.editEleList = res.data.data;
+        })
+        this.editEleFormulaVisible = true;
+      },
+
       saveNewEle(row){
         row.eAllowDeviation = (row.allow?row.allow:'') + (row.deviation?row.deviation:'');
         row.fId = this.curEleTable.id;
@@ -693,6 +754,78 @@
         })
       },
 
+      importTemplate(data){
+        this.importTemplateVisible = true;
+        this.curTreeData = data;
+
+        if(!this.fileUrl){
+          getAttchFromOriginalName(1, 20, {
+            originalName:'WBS划分模板.xls'
+          }).then((res)=>{
+            if(res.data.data.records.length){
+              this.fileUrl = res.data.data.records[0].link;
+            }else{
+              this.fileUrl = '';
+            }
+            
+          })
+        }
+        
+      },
+
+      importTemplateHandle(){
+        if(!this.upFile){
+          this.$message({
+            type: "warning",
+            message: "请先选择文件再进行导入"
+          });
+        }
+        let forms = new FormData();
+        forms.append('excelFile', this.upFile);
+        let wbsTreeFu = {
+          wbsId:this.id,
+          parentId:this.curTreeData.id,
+          // ancestors:'0,'+this.curTreeData.id,
+        }
+        let json = JSON.stringify(wbsTreeFu);
+        let blob = new Blob([json],{type:'application/json'})
+        forms.append('wbsTreeFu', blob);
+        this.importLoading = true;
+        importWbsTree(forms).then(()=>{
+          //this.$router.go(0)
+          let node = this.$refs.tree.getNode(this.curTreeData.id);
+          node.isLeaf = false;
+          this.importTemplateVisible = false;
+        }).finally(()=>{
+          this.importLoading = false;
+        })
+      },
+
+      handleDownload() {
+        if(this.fileUrl){
+          window.open(this.fileUrl);
+        }else{
+          this.$message({
+            type: "warning",
+            message: "请先在附件管理上传【WBS划分模板.xls】文件"
+          });
+        }
+      },
+
+      fileClick(){
+        this.$refs.file.click();
+      },
+
+      fileChange(e){
+        const file = e.target.files[0]
+        if (!file) {
+          // 如果用户没有选择图片,只是点了文件上传这个按钮
+          return
+        }
+        //console.log(file)
+        this.upFile = file;
+      },
+
       getDeptCategorylist(){
         if(this.deptCategorylist.length >1){
           return;
@@ -741,7 +874,7 @@
           code:'data_type'
         }).then((res)=>{
           res.data.data.forEach(element => {
-            element.dictKey = element.dictKey
+            element.dictKey = Number(element.dictKey)
           });
           this.dataTypeList = res.data.data;
         })

+ 282 - 0
src/views/system/imageclassificationconfig.vue

@@ -0,0 +1,282 @@
+<template>
+  <basic-container>
+    <avue-crud :option="option"
+               :table-loading="loading"
+               :data="data"
+               :page.sync="page"
+               :permission="permissionList"
+               :before-open="beforeOpen"
+               v-model="form"
+               :search.sync="search"
+               ref="crud"
+               @row-update="rowUpdate"
+               @row-save="rowSave"
+               @row-del="rowDel"
+               @search-change="searchChange"
+               @search-reset="searchReset"
+               @selection-change="selectionChange"
+               @current-change="currentChange"
+               @size-change="sizeChange"
+               @refresh-change="refreshChange"
+               @on-load="onLoad">
+      <template slot="menuLeft">
+        <el-button type="danger"
+                   size="small"
+                   icon="el-icon-delete"
+                   plain
+                   v-if="permission.imageclassificationconfig_delete"
+                   @click="handleDelete">删 除
+        </el-button>
+      </template>
+      <template slot-scope="{dic:dics}" slot="affiliatedPartySearch">
+        <el-radio-group v-model="search.affiliatedParty" size="medium">
+          <el-radio-button v-for="item in dics" :key="item.id" :label="item.dictKey">{{item.dictValue}}</el-radio-button>
+        </el-radio-group>
+      </template>
+    </avue-crud>
+  </basic-container>
+</template>
+
+<script>
+  import {getList, getDetail, add, update, remove} from "@/api/system/imageClassificationConfig";
+  import {mapGetters} from "vuex";
+
+  export default {
+    data() {
+      return {
+        form: {},
+        query: {},
+        loading: true,
+        page: {
+          pageSize: 20,
+          currentPage: 1,
+          total: 0
+        },
+        search:{},
+        selectionList: [],
+        option: {
+          menuWidth:300,
+          height:'auto',
+          calcHeight: 30,
+          tip: false,
+          searchShow: true,
+          searchMenuSpan: 6,
+          border: true,
+          index: true,
+          viewBtn: true,
+          selection: true,
+          dialogClickModal: false,
+          labelWidth:150,
+          column: [
+            {
+              label: "分类名称",
+              prop: "classfName",
+              rules: [{
+                required: true,
+                message: "请输入分类名称",
+                trigger: "blur"
+              }]
+            },
+            {
+              label: "所属项目阶段",
+              type: "select",
+              dicUrl: "/api/blade-system/dict/dictionary?code=project_stage",
+              props: {
+                label: "dictValue",
+                value: "dictKey"
+              },
+              dataType: "number",
+              prop: "projectStage",
+              rules: [{
+                required: true,
+                message: "请选择所属项目阶段",
+                trigger: "blur"
+              }]
+            },{
+              label: "所属方",
+              type: "select",
+              dicUrl: "/api/blade-system/dict/dictionary?code=affiliated_party",
+              props: {
+                label: "dictValue",
+                value: "dictKey"
+              },
+              dataType: "number",
+              prop: "affiliatedParty",
+              hide:true,
+              search:true,
+              rules: [{
+                required: true,
+                message: "请选择所属方",
+                trigger: "blur"
+              }]
+            },{
+              label: "文件资料类型",
+              type: "select",
+              dicUrl: "/api/blade-system/dict/dictionary?code=file_type",
+              props: {
+                label: "dictValue",
+                value: "dictKey"
+              },
+              dataType: "number",
+              prop: "fileType",
+              rules: [{
+                required: true,
+                message: "请选择文件资料类型",
+                trigger: "blur"
+              }]
+            },{
+              label: "储存目录格式",
+              type: "select",
+              dicUrl: "/api/blade-system/dict/dictionary?code=storage_directory_format",
+              props: {
+                label: "dictValue",
+                value: "dictKey"
+              },
+              hide:true,
+              dataType: "number",
+              prop: "storageDirectoryFormat",
+              rules: [{
+                required: true,
+                message: "请选择储存目录格式",
+                trigger: "blur"
+              }]
+            },
+          ]
+        },
+        data: [],
+      };
+    },
+    computed: {
+      ...mapGetters(["permission"]),
+      permissionList() {
+        return {
+          addBtn: this.vaildData(this.permission.imageclassificationconfig_add, false),
+          viewBtn: this.vaildData(this.permission.imageclassificationconfig_view, false),
+          delBtn: this.vaildData(this.permission.imageclassificationconfig_delete, false),
+          editBtn: this.vaildData(this.permission.imageclassificationconfig_edit, false)
+        };
+      },
+      ids() {
+        let ids = [];
+        this.selectionList.forEach(ele => {
+          ids.push(ele.id);
+        });
+        return ids.join(",");
+      }
+    },
+    methods: {
+      rowSave(row, done, loading) {
+        add(row).then(() => {
+          this.onLoad(this.page);
+          this.$message({
+            type: "success",
+            message: "操作成功!"
+          });
+          done();
+        }, error => {
+          loading();
+          window.console.log(error);
+        });
+      },
+      rowUpdate(row, index, done, loading) {
+        update(row).then(() => {
+          this.onLoad(this.page);
+          this.$message({
+            type: "success",
+            message: "操作成功!"
+          });
+          done();
+        }, error => {
+          loading();
+          console.log(error);
+        });
+      },
+      rowDel(row) {
+        this.$confirm("确定将选择数据删除?", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        })
+          .then(() => {
+            return remove(row.id);
+          })
+          .then(() => {
+            this.onLoad(this.page);
+            this.$message({
+              type: "success",
+              message: "操作成功!"
+            });
+          });
+      },
+      handleDelete() {
+        if (this.selectionList.length === 0) {
+          this.$message.warning("请选择至少一条数据");
+          return;
+        }
+        this.$confirm("确定将选择数据删除?", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        })
+          .then(() => {
+            return remove(this.ids);
+          })
+          .then(() => {
+            this.onLoad(this.page);
+            this.$message({
+              type: "success",
+              message: "操作成功!"
+            });
+            this.$refs.crud.toggleSelection();
+          });
+      },
+      beforeOpen(done, type) {
+        if (["edit", "view"].includes(type)) {
+          getDetail(this.form.id).then(res => {
+            this.form = res.data.data;
+          });
+        }
+        done();
+      },
+      searchReset() {
+        this.query = {};
+        this.onLoad(this.page);
+      },
+      searchChange(params, done) {
+        this.query = params;
+        this.page.currentPage = 1;
+        this.onLoad(this.page, params);
+        done();
+      },
+      selectionChange(list) {
+        this.selectionList = list;
+      },
+      selectionClear() {
+        this.selectionList = [];
+        this.$refs.crud.toggleSelection();
+      },
+      currentChange(currentPage){
+        this.page.currentPage = currentPage;
+      },
+      sizeChange(pageSize){
+        this.page.pageSize = pageSize;
+      },
+      refreshChange() {
+        this.onLoad(this.page, this.query);
+      },
+      onLoad(page, params = {}) {
+        this.loading = true;
+        getList(page.currentPage, page.pageSize, Object.assign(params, this.query)).then(res => {
+          const data = res.data.data;
+          this.page.total = data.total;
+          this.data = data.records;
+          this.loading = false;
+          this.selectionClear();
+        });
+      },
+    }
+  };
+</script>
+
+<style>
+</style>

+ 46 - 11
src/views/system/menu.vue

@@ -95,6 +95,18 @@
                 }
               ]
             },
+            {
+              label: "所属系统",
+              type: "select",
+              dicUrl: "/api/blade-system/client/getClinetAll",
+              props: {
+                label: "clientId",
+                value: "id"
+              },
+              slot: true,
+              prop: "sysId",
+              search: true,
+            },
             {
               label: "路由地址",
               prop: "path",
@@ -129,19 +141,11 @@
               prop: "source",
               type: "icon",
               slot: true,
-              iconList: iconList,
-              rules: [
-                {
-                  required: true,
-                  message: "请输入菜单图标",
-                  trigger: "click"
-                }
-              ]
+              iconList: iconList
             },
             {
               label: "菜单编号",
               prop: "code",
-              search: true,
               rules: [
                 {
                   required: true,
@@ -164,7 +168,7 @@
                   value: 2
                 }
               ],
-              hide: true,
+              value: 1,
               rules: [
                 {
                   required: true,
@@ -176,7 +180,6 @@
             {
               label: "菜单别名",
               prop: "alias",
-              search: true,
               rules: [
                 {
                   required: true,
@@ -209,12 +212,37 @@
                 }
               ]
             },
+            {
+              label: "是否外层",
+              prop: "isLayout",
+              type: "radio",
+              disabled: false,
+              dicData: [
+                {
+                  label: "否",
+                  value: 1
+                },
+                {
+                  label: "是",
+                  value: 2
+                }
+              ],
+              value: 2,
+              rules: [
+                {
+                  required: true,
+                  message: "请选择新窗口打开",
+                  trigger: "blur"
+                }
+              ]
+            },
             {
               label: "菜单排序",
               prop: "sort",
               type: "number",
               row: true,
               span: 24,
+              value: 1,
               rules: [
                 {
                   required: true,
@@ -230,6 +258,13 @@
               span: 24,
               minRows: 2,
               hide: true
+            },
+            {
+              label: "提示语",
+              prop: "textInfo",
+              type: "textarea",
+              span: 24,
+              minRows: 2
             }
           ]
         },

+ 1 - 1
src/views/test.vue

@@ -1,5 +1,5 @@
 <template>
-  <basic-container>测试页1</basic-container>
+  <basic-container>测试页2</basic-container>
 </template>
 
 <script>

+ 13 - 0
src/views/testView/index.vue

@@ -0,0 +1,13 @@
+<template>
+
+</template>
+
+<script>
+export default {
+  name: "index"
+}
+</script>
+
+<style scoped>
+
+</style>

+ 13 - 0
src/views/testView/xxxx/abcd.vue

@@ -0,0 +1,13 @@
+<template>
+
+</template>
+
+<script>
+export default {
+  name: "abcd"
+}
+</script>
+
+<style scoped>
+
+</style>

+ 36 - 36
vue.config.js

@@ -1,39 +1,39 @@
 module.exports = {
-  //路径前缀
-  publicPath: "/",
-  lintOnSave: true,
-  productionSourceMap: false,
-  chainWebpack: (config) => {
-    //忽略的打包文件
-    config.externals({
-      'vue': 'Vue',
-      'vue-router': 'VueRouter',
-      'vuex': 'Vuex',
-      'axios': 'axios',
-      'element-ui': 'ELEMENT',
-    });
-    const entry = config.entry('app');
-    entry.add('babel-polyfill').end();
-    entry.add('classlist-polyfill').end();
-    entry.add('@/mock').end();
-  },
-  css: {
-    extract: { ignoreOrder: true }
-  },
-  //开发模式反向代理配置,生产模式请使用Nginx部署并配置反向代理
-  devServer: {
-    port: 1888,
-    proxy: {
-      '/api': {
-        //本地服务接口地址
-        target: 'http://localhost',
-        //远程演示服务地址,可用于直接启动项目
-        //target: 'https://saber.bladex.vip/api',
-        ws: true,
-        pathRewrite: {
-          '^/api': '/'
+    //路径前缀
+    publicPath: "/",
+    lintOnSave: true,
+    productionSourceMap: false,
+    chainWebpack: (config) => {
+        //忽略的打包文件
+        config.externals({
+            'vue': 'Vue',
+            'vue-router': 'VueRouter',
+            'vuex': 'Vuex',
+            'axios': 'axios',
+            'element-ui': 'ELEMENT',
+        });
+        const entry = config.entry('app');
+        entry.add('babel-polyfill').end();
+        entry.add('classlist-polyfill').end();
+        entry.add('@/mock').end();
+    },
+    css: {
+        extract: { ignoreOrder: true }
+    },
+    //开发模式反向代理配置,生产模式请使用Nginx部署并配置反向代理
+    devServer: {
+        port: 1888,
+        proxy: {
+            '/api': {
+                //本地服务接口地址
+                target: 'http://192.168.31.96',
+                //远程演示服务地址,可用于直接启动项目
+                //target: 'https://saber.bladex.vip/api',
+                ws: true,
+                pathRewrite: {
+                    '^/api': '/'
+                }
+            }
         }
-      }
     }
-  }
-};
+};

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