瀏覽代碼

Merge branch '0709_OA' into test

lex-xin 3 年之前
父節點
當前提交
338ddbaab0

+ 17 - 16
package.json

@@ -14,54 +14,55 @@
     "svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml"
   },
   "dependencies": {
+    "@babel/plugin-proposal-optional-chaining": "^7.11.0",
     "JSONPath": "^0.11.2",
     "axios": "0.18.1",
-    "browserslist": "^4.16.6",
-    "caniuse-lite": "^1.0.30001244",
+    "browserslist": "^4.16.4",
+    "caniuse-lite": "^1.0.30001214",
     "clean-deep": "^3.3.0",
     "copy-to-clipboard": "^3.3.1",
-    "dayjs": "^1.10.6",
+    "dayjs": "^1.8.35",
     "default-passive-events": "^1.0.10",
     "echarts": "^4.8.0",
-    "element-ui": "^2.15.3",
+    "element-ui": "^2.13.2",
     "http-server": "^0.12.3",
     "i": "^0.3.6",
-    "js-base64": "^3.6.1",
+    "js-base64": "^3.6.0",
     "js-cookie": "2.2.0",
     "linq": "^3.2.2",
-    "lodash": "^4.17.21",
+    "lodash": "^4.17.20",
     "moment": "^2.29.1",
     "node-sass": "^4.13.1",
     "normalize.css": "7.0.0",
-    "npm": "^6.14.13",
+    "npm": "^6.13.0",
     "nprogress": "0.2.0",
     "numeral": "^2.0.6",
     "object-diff": "0.0.4",
     "path-to-regexp": "2.4.0",
     "portal-vue": "^2.1.7",
     "qrcodejs2": "0.0.2",
-    "qs": "^6.10.1",
+    "qs": "^6.8.0",
     "screenfull": "^5.1.0",
-    "swiper": "^6.7.5",
+    "swiper": "^6.3.5",
     "v-charts": "^1.19.0",
     "vue": "2.6.10",
     "vue-amap": "^0.5.10",
     "vue-awesome-swiper": "^4.1.1",
     "vue-count-to": "^1.0.13",
     "vue-drag-resize": "^1.5.4",
-    "vue-lunar-calendar-pro": "^1.0.16",
-    "vue-qr": "^2.5.0",
+    "vue-lunar-calendar-pro": "^1.0.14",
+    "vue-qr": "^2.2.1",
     "vue-quill-editor": "^3.0.6",
     "vue-resize": "^1.0.1",
     "vue-router": "3.0.6",
     "vuedraggable": "^2.24.3",
     "vuex": "3.1.0",
-    "wangeditor": "^4.7.5",
-    "webpack-merge": "^5.8.0"
+    "wangeditor": "^4.0.0",
+    "webpack-merge": "^5.3.0"
   },
   "devDependencies": {
     "@babel/core": "7.0.0",
-    "@babel/plugin-proposal-optional-chaining": "^7.14.5",
+    "@babel/plugin-proposal-optional-chaining": "^7.11.0",
     "@babel/register": "7.0.0",
     "@vue/cli-plugin-babel": "3.6.0",
     "@vue/cli-plugin-eslint": "^3.9.1",
@@ -78,7 +79,7 @@
     "eslint": "5.15.3",
     "eslint-plugin-vue": "5.2.2",
     "html-webpack-plugin": "3.2.0",
-    "less": "^3.13.1",
+    "less": "^3.10.3",
     "less-loader": "^5.0.0",
     "mockjs": "1.0.1-beta3",
     "runjs": "^4.3.2",
@@ -89,7 +90,7 @@
     "svg-sprite-loader": "4.1.3",
     "svgo": "1.2.2",
     "vue-template-compiler": "2.6.10",
-    "worker-loader": "^3.0.8"
+    "worker-loader": "^3.0.7"
   },
   "engines": {
     "node": ">=8.9",

+ 18 - 0
src/api/systemManage.js

@@ -130,6 +130,24 @@ export function getUserRole (data) {
   })
 }
 
+// 获取部门
+export function getDepts (data) {
+  return request({
+    url: `/api-oa/api/v1/depts`,
+    method: 'get',
+    params: data
+  })
+}
+
+// 获取岗位
+export function getPosts (data) {
+  return request({
+    url: `/api-oa/api/v1/posts`,
+    method: 'get',
+    params: data
+  })
+}
+
 // 员工操作
 export function employeeOperate (data) {
   return request({

二進制
src/assets/images/base/icon_oa.png


+ 38 - 0
src/layout/components/Navbar.vue

@@ -35,6 +35,33 @@
     </div>
     <div class="right-menu">
       <el-popover
+        placement="bottom"
+        trigger="hover"
+        style="display: flex; height: 89px"
+      >
+        <div class="popover-container" style="text-align: center">OA审批</div>
+
+        <div
+          style="
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            height: 89px;
+          "
+          class="msginfo"
+          @click="gotoOa"
+          slot="reference"
+        >
+          <img
+            src="@/assets/images/base/icon_oa.png"
+            width="24px"
+            height="24px"
+          />
+
+          <!-- <div class="active"></div> -->
+        </div>
+      </el-popover>
+      <el-popover
         v-if="isShowIns"
         placement="bottom"
         trigger="hover"
@@ -245,6 +272,9 @@ import { resetPassword } from "@/api/buildTeam";
 import AppLink from "./Sidebar/Link";
 import { getBelongTopMenuPath } from "@/utils/permission";
 import instructions from "./instructions";
+import { validOaUrl } from '@/utils/validate'
+import Cookies from 'js-cookie'
+import axios from 'axios'
 export default {
   data() {
     return {
@@ -362,6 +392,14 @@ export default {
     checkShow(val) {
       this.isShowIns = val;
     },
+    gotoOa(){
+      console.log(validOaUrl())
+      const Token = Cookies.get('cross-Token')
+      console.log(Token, validOaUrl().split('//')[1])
+      Cookies.set('Admin-Token', Token, { domain: `.${validOaUrl().split('//')[1]}`, path: '/' })
+      // document.cookie = `Adminoken=${Token};domain=oadev.dayaedu.com;`
+      window.open(validOaUrl())
+    }
   },
   watch: {
     resetVisible(val) {

+ 4 - 1
src/store/modules/user.js

@@ -1,5 +1,5 @@
 import { login, logout, getInfo } from '@/api/user'
-import { getToken, setToken, removeToken } from '@/utils/auth'
+import { getToken, setToken, removeToken, removeCrossToken, setCrossToken } from '@/utils/auth'
 import { resetRouter } from '@/router'
 // import qs from 'qs'
 const state = {
@@ -54,6 +54,7 @@ const actions = {
           commit('SET_EXPIRES_IN', data.authentication.expires_in)
           commit('SET_TOKEN', token)
           setToken(token)
+          setCrossToken(data.authentication.access_token)
           resolve()
         }
       }).catch(error => {
@@ -95,6 +96,7 @@ const actions = {
       logout().then(() => {
         commit('SET_TOKEN', '')
         removeToken()
+        removeCrossToken()
         resetRouter()
         commit('SET_NAME', '')
         resolve()
@@ -109,6 +111,7 @@ const actions = {
     return new Promise(resolve => {
       commit('SET_TOKEN', '')
       removeToken()
+      removeCrossToken()
       resolve()
     })
   }

+ 10 - 0
src/utils/auth.js

@@ -1,6 +1,8 @@
 import Cookies from 'js-cookie'
 
 const TokenKey = 'dy_admin_token'
+// const CrossTokenKey = 'Admin-Token'
+const CrossTokenKey = 'cross-Token'
 
 export function getToken () {
   return Cookies.get(TokenKey)
@@ -13,3 +15,11 @@ export function setToken (token) {
 export function removeToken () {
   return Cookies.remove(TokenKey)
 }
+
+export function setCrossToken (token) {
+  return Cookies.set(CrossTokenKey, token)
+}
+
+export function removeCrossToken () {
+  return Cookies.remove(CrossTokenKey)
+}

+ 16 - 0
src/utils/validate.js

@@ -70,6 +70,22 @@ export function vaildTeachingUrl() {
   return returnUrl
 }
 
+// 教务地址
+export function validOaUrl() {
+  let url = window.location.href
+  let returnUrl = ''
+  if (/online/.test(url)) { //线上
+    returnUrl = 'https://oaonline.dayaedu.com'
+  } else if (/dev/.test(url)) { // dev 环境
+    returnUrl = 'http://oadev.dayaedu.com'
+  } else if (/test/.test(url)) { // dev 环境
+    returnUrl = 'http://oatest.dayaedu.com'
+  } else { // 默认dev环境
+    returnUrl = 'http://oadev.dayaedu.com'
+  }
+  return returnUrl
+}
+
 
 export function nextMonthLastDay(year, month) { //日期显示为次月最后一天
   // var time = date ? new Date(date) : new Date();

+ 221 - 13
src/views/categroyManager/insideSetting/staffManager.vue

@@ -102,7 +102,7 @@
             </template>
           </el-table-column>
           <el-table-column align='center'
-                           label="所属部">
+                           label="所属部">
             <template slot-scope="scope">
               <tooltip :content="scope.row.organNameList | joinArray(',')"></tooltip>
             </template>
@@ -157,7 +157,7 @@
     <el-dialog :title="formTitle[formActionTitle]"
                :visible.sync="roleStatus"
                @close="onFormClose('ruleForm')"
-               width="500px">
+               width="650px">
       <el-form :model="form"
                :rules="rules"
                ref="ruleForm">
@@ -201,14 +201,13 @@
                        :value="item.value"></el-option>
           </select-all>
         </el-form-item>
-        <el-form-item label="所属部"
+        <el-form-item label="所属部"
                       prop="organIdLists"
                       :label-width="formLabelWidth">
-                      <!-- style="width: calc(100% - 75px) !important;" -->
           <select-all
                      filterable
                      clearable
-                      placeholder="请选择部"
+                      placeholder="请选择部"
                      collapse-tags
                      v-model.trim="form.organIdLists"
                      multiple>
@@ -217,8 +216,70 @@
                        :label="item.name"
                        :value="item.id"></el-option>
           </select-all>
-          <!-- <el-button @click="onBranchCheckAll">全选</el-button> -->
         </el-form-item>
+        <el-form-item label="所属部门"
+                      prop="deptIds"
+                      :label-width="formLabelWidth">
+          <el-cascader
+                v-model="form.deptIds"
+                placeholder="请选择所属部门"
+                clearable
+                style="width: 100%;"
+                :options="deptList"
+                :show-all-levels="false"
+                :collapse-tags="true"
+                :props="{ multiple: true, checkStrictly: false }"
+              ></el-cascader>
+        </el-form-item>
+        <div v-for="(postDeptIds, index) in form.postDeptIds" :key="index">
+          <el-form-item
+                :label="'岗位管理' + (index + 1)"
+                :label-width="formLabelWidth"
+                class="setWidth"
+                :prop="'postDeptIds.' + index + '.postId'"
+                :rules="[{ required: true, message: '请选择所属岗位', trigger: 'change' }]"
+              >
+              <el-select
+                      filterable
+                      clearable
+                      placeholder="所属岗位(必填)"
+                      style="width: 180px !important"
+                      v-model.trim="postDeptIds.postId">
+                <el-option v-for="item in postList"
+                          :key="item.value"
+                          :label="item.label"
+                          :value="item.value"></el-option>
+              </el-select>
+              </el-form-item>
+              <el-form-item
+                class="setWidth"
+                style="margin: 0 10px;width: 190px !important;"
+                :prop="'postDeptIds.' + index + '.deptIds'"
+              >
+                <el-cascader
+                  v-model="postDeptIds.deptIds"
+                  placeholder="管理部门(非必填)"
+                  clearable
+                  :options="deptList"
+                  :show-all-levels="false"
+                  :collapse-tags="true"
+                  :props="{ multiple: true, checkStrictly: false }"
+                ></el-cascader>
+              </el-form-item>
+              <el-button
+                icon="el-icon-minus"
+                circle
+                v-if="form.postDeptIds.length > 1"
+                 @click.prevent="removePostDept(postDeptIds)"
+                style="height: 40px"
+              ></el-button>
+              <el-button
+                icon="el-icon-plus"
+                @click.prevent="addPostDept"
+                circle
+                style="margin-left: 5px; height: 40px"
+              ></el-button>
+        </div>
         <el-form-item label="工作类型"
                       prop="jobNature"
                       :label-width="formLabelWidth">
@@ -318,9 +379,11 @@
 <script>
 import pagination from '@/components/Pagination/index'
 import { permission } from "@/utils/directivePage";
-import { queryEmployByOrganId, employeeOperate, getUserRole, employeeAdd, employeeUpdate, hasCourseGroupRelation, updateEducationTeacherId, queryEmployeeOrganByUser } from '@/api/systemManage'
+import { queryEmployByOrganId, employeeOperate, getUserRole, employeeAdd, employeeUpdate, hasCourseGroupRelation, updateEducationTeacherId, queryEmployeeOrganByUser, getDepts, getPosts } from '@/api/systemManage'
 import { findEducationTeacher } from '@/api/specialSetting'
 import { findEducationUsers } from '@/api/buildTeam'
+// import Treeselect from '@riophae/vue-treeselect'
+// import '@riophae/vue-treeselect/dist/vue-treeselect.css'
 import Tooltip from '@/components/Tooltip/index'
 import { isvalidPhone } from '@/utils/validate'
 import handover from './modals/handover'
@@ -341,6 +404,8 @@ export default {
       organList: [],
       tableList: [],
       educationList: [],
+      deptList: [],
+      postList: [],
       educationForm: {
         targetUserId: ''
       },
@@ -369,6 +434,12 @@ export default {
         phone: null,
         roleIds: [],
         organIdLists: [],
+        postDeptIds: [{
+          postId: null,
+          deptIds: []
+        }],
+        deptIds: [],
+        // postIds: [],
         jobNature: null,
         entryDate: null,
         contactAddress: null,
@@ -379,7 +450,9 @@ export default {
         gender: [{ required: true, message: '请选择性别', trigger: 'change' }],
         phone: [{ type: 'number', required: true, validator: validPhone, trigger: 'blur' }, { pattern: /^1[3456789]\d{9}$/, message: '请输入正确的手机号', trigger: 'blur' }],
         roleIds: [{ type: 'array', required: true, message: '请选择分类', trigger: 'change' }],
-        organIdLists: [{ type: 'array', required: true, message: '请选择所属部门', trigger: 'change' }],
+        organIdLists: [{ type: 'array', required: true, message: '请选择所属分部', trigger: 'change' }],
+        deptIds: [{ type: 'array', required: true, message: '请选择所属部门', trigger: 'change' }],
+        // postIds: [{ type: 'array', required: true, message: '请选择所属岗位', trigger: 'change' }],
         jobNature: [{ required: true, message: '请选择工作类型', trigger: 'change' }],
         entryDate: [{ required: true, message: '请选择入职时间', trigger: 'blur' }],
 
@@ -412,16 +485,38 @@ export default {
     onRoleSubmit (formName) {
       this.$refs[formName].validate((valid) => {
         if (valid) {
-          this.form.organIdList = this.form.organIdLists.join(',')
+          const { organIdLists, postDeptIds, deptIds, ...res } = this.form
+          let tempPost = []
+          postDeptIds.forEach(post => {
+            let tempIds = []
+            post.deptIds.forEach(item => {
+              tempIds.push(item[item.length - 1])
+            })
+            tempPost.push({
+              postId: post.postId,
+              deptIds: tempIds
+            })
+          })
+          const tempDeptIds = []
+          deptIds.forEach(ds => {
+            tempDeptIds.push(ds[ds.length - 1])
+          })
+
+          let tempForm = {
+            postDeptIds: JSON.stringify(tempPost),
+            organIdList: organIdLists.join(','),
+            deptIds: tempDeptIds,
+            ...res
+          }
           if (this.formActionTitle == 'create') {
             if (this.form.id) { // 判断有没有Id,如果有则删除
               delete this.form.id
             }
-            employeeAdd(this.form).then(res => {
+            employeeAdd(tempForm).then(res => {
               this.messageTips('添加', res)
             })
           } else if (this.formActionTitle == 'update') {
-            employeeUpdate(this.form).then(res => {
+            employeeUpdate(tempForm).then(res => {
               this.messageTips('修改', res)
             })
           }
@@ -464,6 +559,24 @@ export default {
         }
       })
     },
+    /** 转换菜单数据结构 */
+    normalizer(node) {
+      let temp = []
+      if (node.children && node.children.length > 0) {
+        node.children.forEach(item => {
+          let child = this.normalizer(item)
+          let obj = {
+            value: item.deptId,
+            label: item .deptName
+          }
+          if(child && child.length > 0) {
+            obj.children = child
+          }
+          temp.push(obj)
+        })
+      }
+      return temp
+    },
     getRoleList () { // 获取角色
       getUserRole({ delFlag: 0, rows: 9999 }).then(res => {
         let result = res.data
@@ -477,6 +590,32 @@ export default {
           })
         }
       })
+      getDepts({ rows: 9999 }).then(res => {
+        if(res.code == 200 && res.data && res.data.length > 0) {
+          const depts = res.data || []
+          const formatArr = []
+          depts.forEach(dep => {
+            formatArr.push({
+              value: dep.deptId,
+              label: dep.deptName,
+              children: this.normalizer(dep)
+            })
+          })
+          this.deptList = formatArr
+        }
+      })
+      // 岗位
+      getPosts({ rows: 9999 }).then(res => {
+        if(res.code == 200 && res.data && res.data.length > 0) {
+          this.postList = []
+          res.data.forEach(item => {
+            this.postList.push({
+              label: item.postName,
+              value: item.postId
+            })
+          })
+        }
+      })
       this.$store.dispatch('setBranchs')
     },
     async roleOperation (type, data) {
@@ -490,6 +629,36 @@ export default {
       this.roleStatus = true
       // 修改的时候
       if (type == 'update') {
+        // 初始化数据
+        let postDeptArr = []
+        const postDept = data.postDeptIds ? JSON.parse(data.postDeptIds) : []
+
+        if(postDept.length > 0) {
+          postDept.forEach(dept => {
+            let deptIds = dept.deptIds || []
+            let deptArr = []
+            deptIds.forEach(ds => {
+              deptArr.push(this.formatParentId(ds, this.deptList))
+            })
+            postDeptArr.push({
+              postId: dept.postId,
+              deptIds: deptArr
+            })
+          })
+        } else {
+          postDeptArr = [{
+            postId: null,
+            deptIds: []
+          }]
+        }
+
+        const deptIds = data.deptIds ? eval(data.deptIds) : []
+        const tempDeptIds = []
+        if(deptIds.length > 0) {
+          deptIds.forEach(ds => {
+            tempDeptIds.push(this.formatParentId(ds, this.deptList))
+          })
+        }
         this.form = {
           id: data.id,
           realName: data.realName,
@@ -500,9 +669,25 @@ export default {
           jobNature: data.jobNature,
           entryDate: data.entryDate,
           contactAddress: data.contactAddress,
-          postalCode: data.postalCode
+          postalCode: data.postalCode,
+          postDeptIds: postDeptArr,
+          deptIds: tempDeptIds
+        }
+      }
+    },
+    formatParentId(id, list, ids = []) {
+      for (const item of list) {
+        if (item.children) {
+          const cIds = this.formatParentId(id, item.children, [...ids, item.value])
+          if(cIds.includes(id)) {
+            return cIds
+          }
+        }
+        if (item.value === id) {
+          return [...ids, id]
         }
       }
+      return ids
     },
     onFormClose (formName) { // 关闭弹窗重置验证
       this.form = {
@@ -510,9 +695,17 @@ export default {
         gender: null,
         phone: null,
         roleName: null,
+        roleIds: [],
         organIdLists: [],
         jobNature: null,
-        entryDate: null
+        entryDate: null,
+        contactAddress: null,
+        postalCode: null,
+        deptIds: [],
+        postDeptIds: [{
+          postId: null,
+          deptIds: []
+        }]
       }
       this.$refs[formName].resetFields()
     },
@@ -607,6 +800,18 @@ export default {
         }
       })
     },
+    removePostDept(item) {
+      const index = this.form.postDeptIds.indexOf(item);
+      if (index !== -1) {
+        this.form.postDeptIds.splice(index, 1);
+      }
+    },
+    addPostDept() {
+      this.form.postDeptIds.push({
+        postId: null,
+        deptIds: []
+      });
+    },
   },
   watch: {
     educationViseble (val) {
@@ -638,4 +843,7 @@ export default {
 /deep/.el-date-editor.el-input {
   width: 100% !important;
 }
+.setWidth {
+  display: inline-block;
+}
 </style>

+ 8 - 1
vue.config.js

@@ -54,7 +54,7 @@ module.exports = {
     //   warnings: false,
     //   errors: true
     // },
-    https: true,
+    https: false,
     proxy: {
       // change xxx-api/login => mock/login
       // detail: https://cli.vuejs.org/config/#devserver-proxy
@@ -100,6 +100,13 @@ module.exports = {
           '^api-teacher': ''
         }
       },
+      '/api-oa': {
+        target: target,
+        changeOrigin: true,
+        pathRewrite: {
+          '^api-oa': ''
+        }
+      },
       '/jiari': {
         target: 'http://tool.bitefu.net',
         changeOrigin: true,