Z 1 год назад
Родитель
Сommit
f15575e7ba

+ 1 - 0
src/enum/dict.js

@@ -42,6 +42,7 @@ export default {
   工作流任务分配规则的类型: 'bpm_task_assign_rule_type',
   工作流任务分配自定义脚本: 'bpm_task_assign_script',
   流程实例的结果:'bpm_process_instance_result',
+  角色数据权限字典:'role_data_authority_dic',
 
 };
 

+ 425 - 0
src/views/system/dept/components/org-edit.vue

@@ -0,0 +1,425 @@
+<!-- 机构编辑弹窗 -->
+<template>
+  <ele-modal
+    width="880px"
+    :visible="visible"
+    :close-on-click-modal="false"
+    custom-class="ele-dialog-form"
+    :title="isUpdate ? '修改机构' : '添加机构'"
+    @update:visible="updateVisible"
+  >
+    <el-form ref="form" :model="form" :rules="rules" label-width="140px">
+      <el-row :gutter="15">
+        <el-col v-bind="styleResponsive ? { sm: 12 } : { span: 12 }">
+          <el-form-item label="上级机构:">
+            <org-select
+              v-model="form.parentId"
+              :data="organizationList"
+              placeholder="请选择上级机构"
+            />
+          </el-form-item>
+        </el-col>
+        <el-col v-bind="styleResponsive ? { sm: 12 } : { span: 12 }">
+          <el-form-item label="机构名称:" prop="name">
+            <el-input
+              clearable
+              :maxlength="20"
+              v-model="form.name"
+              placeholder="请输入机构名称"
+            />
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item
+            label="机构类型:"
+            prop="type"
+            style="margin-bottom: 22px"
+          >
+            <DictSelection
+              dictName="机构类型"
+              clearable
+              v-model="form.type"
+              labelName="dictValue"
+            >
+            </DictSelection>
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item
+            label="负责人:"
+            style="margin-bottom: 22px"
+          >
+            <el-input
+              @click.native="openStaffSelection"
+              v-model="responsibleName"
+              placeholder="请选择"
+            ></el-input>
+          </el-form-item>
+        </el-col>
+
+        <el-col :span="12">
+
+          <el-form-item
+            label="状态:"
+            style="margin-bottom: 22px"
+          >
+           <el-select v-model="form.status" style="width: 100%">
+             <el-option label="开启" :value="1"></el-option>
+             <el-option label="关闭" :value="0"></el-option>
+           </el-select>
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+
+          <el-form-item
+            label="排序:"
+            style="margin-bottom: 22px"
+          >
+            <el-input
+              v-model="form.sort"
+              placeholder="请选择"
+            ></el-input>
+          </el-form-item>
+        </el-col>
+
+      </el-row>
+    </el-form>
+    <headerTitle
+      title="企业信息"
+      style="margin-top: 30px"
+      v-if="['10', '20'].includes(form.type)"
+    ></headerTitle>
+
+    <el-form
+      ref="enterpriseForm"
+      :model="enterprise"
+      :rules="enterpriseRules"
+      label-width="140px"
+      v-if="['10', '20'].includes(form.type)"
+    >
+      <el-row :gutter="15">
+        <el-col v-bind="styleResponsive ? { sm: 12 } : { span: 12 }">
+          <el-form-item label="企业名称:" prop="name">
+            <el-input
+              clearable
+              :maxlength="50"
+              v-model="enterprise.name"
+              placeholder="请输入企业名称"
+              :disabled="true"
+            />
+          </el-form-item>
+        </el-col>
+
+        <el-col v-bind="styleResponsive ? { sm: 12 } : { span: 12 }">
+          <el-form-item label="企业地址:" prop="address">
+            <el-input
+              clearable
+              :maxlength="50"
+              v-model="enterprise.address"
+              placeholder="请输入企业地址"
+            />
+          </el-form-item>
+        </el-col>
+        <el-col v-bind="styleResponsive ? { sm: 12 } : { span: 12 }">
+          <el-form-item label="企业电话:" prop="tel">
+            <el-input
+              clearable
+              :maxlength="20"
+              v-model="enterprise.tel"
+              placeholder="请输入企业电话"
+            />
+          </el-form-item>
+        </el-col>
+        <el-col v-bind="styleResponsive ? { sm: 12 } : { span: 12 }">
+          <el-form-item label="登记日期:" prop="registerDate">
+            <el-date-picker
+              style="width: 100%"
+              clearable
+              v-model="enterprise.registerDate"
+              type="date"
+              value-format="yyyy-MM-dd"
+              placeholder="请选择日期"
+            >
+            </el-date-picker>
+          </el-form-item>
+        </el-col>
+        <el-col v-bind="styleResponsive ? { sm: 12 } : { span: 12 }">
+          <el-form-item label="统一社会性代码:" prop="unifiedSocialCreditCode">
+            <el-input
+              clearable
+              :maxlength="50"
+              v-model="enterprise.unifiedSocialCreditCode"
+              placeholder="请输入统一社会性代码"
+            />
+          </el-form-item>
+        </el-col>
+        <el-col v-bind="styleResponsive ? { sm: 12 } : { span: 12 }">
+          <el-form-item label="经营范围:" prop="businessScope">
+            <el-input
+              clearable
+              type="textarea"
+              :maxlength="100"
+              v-model="enterprise.businessScope"
+              placeholder="请输入经营范围"
+            />
+          </el-form-item>
+        </el-col>
+        <el-col v-bind="styleResponsive ? { sm: 12 } : { span: 12 }">
+          <el-form-item label="经营产品:" prop="mainProduct">
+            <el-input
+              clearable
+              type="textarea"
+              :maxlength="100"
+              v-model="enterprise.mainProduct"
+              placeholder="请输入经营产品"
+            />
+          </el-form-item>
+        </el-col>
+        <el-col
+          v-bind="styleResponsive ? { sm: 12 } : { span: 12 }"
+          style="margin-bottom: 20px"
+        >
+          <el-form-item label="企业传真:" prop="fax">
+            <el-input
+              clearable
+              v-model="enterprise.fax"
+              placeholder="请输入企业传真"
+            />
+          </el-form-item>
+        </el-col>
+        <el-col v-bind="styleResponsive ? { sm: 12 } : { span: 12 }">
+          <el-form-item prop="files" label="附件:">
+            <fileUpload
+              v-model="enterprise.businessLicenseFile"
+              module="main"
+              :showLib="false"
+              :limit="10"
+            />
+          </el-form-item>
+        </el-col>
+      </el-row>
+    </el-form>
+    <template v-slot:footer>
+      <el-button @click="updateVisible(false)">取消</el-button>
+      <el-button type="primary" :loading="loading" @click="save">
+        保存
+      </el-button>
+    </template>
+    <staffSelection
+      ref="staffSelection"
+      @confirm="confirmStaffSelection"
+    ></staffSelection>
+  </ele-modal>
+</template>
+
+<script>
+  import OrgSelect from './org-select.vue';
+  import OrgTypeSelect from './org-type-select.vue';
+  import staffSelection from './staffSelection.vue';
+  import fileUpload from '@/components/upload/fileUpload';
+  import { copyObj } from '@/utils/util';
+
+  const defEnterprise = {
+    businessLicenseFile: [],
+    name: null,
+    address: null,
+    tel: '',
+    registerDate: '',
+    unifiedSocialCreditCode: '',
+    businessScope: '',
+    mainProduct: '',
+    remark: '',
+    fax: ''
+  };
+  import {
+    addOrganization,
+    updateOrganization,
+    getById
+  } from '@/api/system/organization';
+  export default {
+    components: { OrgSelect, OrgTypeSelect, staffSelection, fileUpload },
+    props: {
+      // 弹窗是否打开
+      visible: Boolean,
+      // 修改回显的数据
+      data: Object,
+      // 上级id
+      parentId: [Number, String],
+      // 机构数据
+      organizationList: Array
+    },
+    data() {
+      const defaultForm = {
+        id: null,
+        parentId: null,
+        name: '',
+        type: '',
+        sort: null,
+        status: 1,
+        manager: []
+      };
+      return {
+        defaultForm,
+        responsibleName: '',
+        // 表单数据
+        form: { ...defaultForm },
+        enterprise: { ...defEnterprise },
+        // 表单验证规则
+        rules: {
+          name: [
+            { required: true, message: '请输入机构名称', trigger: 'blur' }
+          ],
+          manager: [
+            { required: true, message: '请选择负责人', trigger: 'blur' }
+          ],
+          type: [{ required: true, message: '请选择机构类型', trigger: 'blur' }]
+        },
+        // 表单验证规则
+        enterpriseRules: {
+          name: [
+            { required: true, message: '请输入企业名称', trigger: 'blur' }
+          ],
+          address: [
+            { required: true, message: '请输入企业地址', trigger: 'blur' }
+          ],
+          unifiedSocialCreditCode: [
+            { required: true, message: '请输入统一社会性代码', trigger: 'blur' }
+          ]
+        },
+        // 提交状态
+        loading: false,
+        // 是否是修改
+        isUpdate: false
+      };
+    },
+    computed: {
+      // 是否开启响应式布局
+      styleResponsive() {
+        return this.$store.state.theme.styleResponsive;
+      }
+    },
+    methods: {
+      /* 保存编辑 */
+      async save() {
+        if (!(await this.formValidate())) {
+          return false;
+        }
+        if (
+          ['10', '20'].includes(this.form.type) &&
+          !(await this.enterpriseValidate())
+        ) {
+          return false;
+        }
+        let form = {
+          ...this.form
+        };
+        if (['10', '20'].includes(this.form.type)) {
+          form['enterprise'] = this.enterprise;
+        }
+        this.loading = true;
+        const data = {
+          ...form,
+          parentId: this.form.parentId || 0
+        };
+        if (!this.isUpdate) {
+          delete data.id;
+        }
+        const saveOrUpdate = this.isUpdate
+          ? updateOrganization
+          : addOrganization;
+        saveOrUpdate(data)
+          .then((msg) => {
+            this.loading = false;
+            this.$message.success(msg);
+            this.updateVisible(false);
+            this.$emit('done');
+          })
+          .catch((e) => {
+            this.loading = false;
+            // this.$message.error(e.message);
+          });
+      },
+      formValidate() {
+        return new Promise((resolve, reject) => {
+          this.$refs.form.validate((valid) => {
+            resolve(valid);
+          });
+        });
+      },
+      enterpriseValidate() {
+        return new Promise((resolve, reject) => {
+          this.$refs.enterpriseForm.validate((valid) => {
+            resolve(valid);
+          });
+        });
+      },
+
+      //选择负责人
+      confirmStaffSelection(data) {
+        this.form.manager = JSON.parse(JSON.stringify(data));
+        this.responsibleName = data.map((item) => item.name).toString();
+      },
+      openStaffSelection() {
+        console.log(this.form.manager);
+        this.$refs.staffSelection.open(
+          JSON.parse(JSON.stringify(this.form.manager)) || []
+        );
+      },
+      /* 更新visible */
+      updateVisible(value) {
+        this.$emit('update:visible', value);
+      }
+    },
+    watch: {
+      form: {
+        deep: true,
+        handler(n) {
+          this.enterprise.name = n.name;
+        }
+      },
+      visible(visible) {
+        if (visible) {
+          if (this.data) {
+            getById(this.data.id).then((res) => {
+              for (const key in res.enterprise) {
+                this.$set(this.enterprise, key, res.enterprise[key]);
+              }
+              for (const key in res) {
+                if (key == 'parentId') {
+                  this.$set(
+                    this.form,
+                    key,
+                    res[key] == 0 ? '' : res[key] ?? ''
+                  );
+                }
+                if (key != 'enterprise') {
+                  this.$set(this.form, key, res[key]);
+                }
+              }
+
+              this.form.type = '' + this.form.type; //回显
+              this.responsibleName =
+                res.manager && res.manager.map((item) => item.name).toString();
+            });
+
+            // this.form.type = '' + this.form.type; //回显
+            // this.responsibleName =
+            //   this.data.manager &&
+            //   this.data.manager.map((item) => item.name).toString();
+            this.isUpdate = true;
+          } else {
+            this.form.parentId = this.parentId;
+            this.isUpdate = false;
+          }
+        } else {
+          this.$refs.form.clearValidate();
+          this.$refs.enterpriseForm &&
+            this.$refs.enterpriseForm.clearValidate();
+          this.form = { ...this.defaultForm };
+          this.enterprise = { ...defEnterprise };
+          this.responsibleName = '';
+        }
+      }
+    }
+  };
+</script>

+ 42 - 0
src/views/system/dept/components/org-select.vue

@@ -0,0 +1,42 @@
+<!-- 机构选择下拉框 -->
+<template>
+  <ele-tree-select
+    ref="tree"
+    clearable
+    :value="value || ''"
+    :data="data"
+    label-key="name"
+    value-key="id"
+    default-expand-all
+    :placeholder="placeholder"
+    @input="updateValue"
+  />
+</template>
+
+<script>
+  export default {
+    props: {
+      // 选中的数据(v-model)
+      value: [Number,String],
+      // 提示信息
+      placeholder: {
+        type: String,
+        default: '请选择机构'
+      },
+      // 机构数据
+      data: Array
+    },
+    methods: {
+      /* 更新选中数据 */
+      updateValue(value) {
+        this.$emit('input', value);
+
+        let nodesInfo = []
+         nodesInfo = this.$refs['tree'].getHalfCheckedKeys()
+        nodesInfo.push(value)
+        this.$emit('checkedKeys', nodesInfo)
+
+      }
+    }
+  };
+</script>

+ 57 - 0
src/views/system/dept/components/org-type-select.vue

@@ -0,0 +1,57 @@
+<!-- 机构类型选择下拉框 -->
+<template>
+  <el-select
+    clearable
+    :value="value"
+    class="ele-fluid"
+    :placeholder="placeholder"
+    @input="updateValue"
+  >
+    <el-option
+      v-for="item in data"
+      :key="item.dictDataId"
+      :value="item.dictDataCode"
+      :label="item.dictDataName"
+    />
+  </el-select>
+</template>
+
+<script>
+  import { listDictionaryData } from '@/api/system/dictionary-data';
+
+  export default {
+    props: {
+      // 选中的数据(v-modal)
+      value: String,
+      // 提示信息
+      placeholder: {
+        type: String,
+        default: '请选择机构类型'
+      }
+    },
+    data() {
+      return {
+        // 机构类型数据
+        data: []
+      };
+    },
+    created() {
+      /* 获取机构类型数据 */
+      listDictionaryData({
+        dictCode: 'organization_type'
+      })
+        .then((list) => {
+          this.data = list;
+        })
+        .catch((e) => {
+          // this.$message.error(e.message);
+        });
+    },
+    methods: {
+      /* 更新选中数据 */
+      updateValue(value) {
+        this.$emit('input', value);
+      }
+    }
+  };
+</script>

+ 333 - 0
src/views/system/dept/components/staffSelection.vue

@@ -0,0 +1,333 @@
+<template>
+  <div class="container">
+    <!-- 单据弹窗 -->
+    <el-dialog
+      title="员工"
+      :before-close="handleClose"
+      :visible.sync="dialogVisible"
+      :close-on-click-modal="false"
+      :append-to-body="true"
+      width="80%"
+    >
+      <el-row class="zw-page">
+        <el-col :span="6" class="zw-page-left">
+          <el-card>
+            <div class="zw-card-header" slot="header">
+              <span class="zw-header-title details-title">部门</span>
+            </div>
+            <div class="zw-page-left-tree">
+              <el-container class="zw-container">
+                <el-tree
+                  ref="tree"
+                  :data="treeList"
+                  highlight-current
+                  node-key="id"
+                  :props="{ label: 'name' }"
+                  :expand-on-click-node="false"
+                  :default-expand-all="true"
+                  @node-click="handleNodeClick"
+                >
+                </el-tree>
+              </el-container>
+            </div>
+          </el-card>
+        </el-col>
+        <el-col :span="9" class="zw-page-main">
+          <el-card>
+            <div class="zw-card-header" slot="header">
+              <span class="zw-header-title details-title">员工明细 </span>
+            </div>
+            <div class="zw-page-main-list">
+              <el-container class="zw-container">
+                <el-table
+                  :data="staffList"
+                  tooltip-effect="dark"
+                  style="width: 100%"
+                  max-height="500"
+                  :header-cell-style="{
+                    background: '#F0F3F3',
+                    border: 'none'
+                  }"
+                >
+                  <el-table-column prop="code" label="姓名">
+                    <template slot-scope="{ row }">
+                      <div>{{ row.name }}</div>
+                    </template>
+                  </el-table-column>
+                  <el-table-column label="工号">
+                    <template slot-scope="{ row }">
+                      <div>{{ row.jobNumber }}</div>
+                    </template>
+                  </el-table-column>
+                  <el-table-column width="80" label="操作">
+                    <template slot-scope="{ row }">
+                      <el-button
+                        size="mini"
+                        type="primary"
+                        @click="choiceAsset(row)"
+                        :disabled="row.disabled"
+                        icon="el-icon-arrow-right"
+                        circle
+                      >
+                      </el-button>
+                    </template>
+                  </el-table-column>
+                </el-table>
+                <div
+                  v-if="staffList.length !== 0 && isMore"
+                  class="zw-page-list-more"
+                >
+                  <el-link @click="getMore()" type="primary"
+                    >更多<i class="el-icon-caret-bottom"></i>
+                  </el-link>
+                </div>
+              </el-container>
+            </div>
+          </el-card>
+        </el-col>
+        <el-col :span="9" class="zw-page-right">
+          <el-card>
+            <div class="zw-card-header" slot="header">
+              <span class="zw-header-title">已选员工</span>
+            </div>
+            <div class="zw-page-right-list">
+              <el-container class="zw-container">
+                <el-table
+                  :data="selectStafflist"
+                  tooltip-effect="dark"
+                  style="width: 100%"
+                  max-height="500"
+                  :header-cell-style="{
+                    background: '#F0F3F3',
+                    border: 'none'
+                  }"
+                >
+                  <el-table-column prop="code" label="姓名">
+                    <template slot-scope="{ row }">
+                      <div>{{ row.name }}</div>
+                    </template>
+                  </el-table-column>
+                  <el-table-column label="工号">
+                    <template slot-scope="{ row }">
+                      <div>{{ row.jobNumber }}</div>
+                    </template>
+                  </el-table-column>
+                  <el-table-column width="80" label="操作">
+                    <template slot-scope="scope">
+                      <el-button
+                        @click="deleteSelectStaff(scope.row, scope.$index)"
+                        size="mini"
+                        type="danger"
+                        >删除
+                      </el-button>
+                    </template>
+                  </el-table-column>
+                </el-table>
+              </el-container>
+            </div>
+          </el-card>
+        </el-col>
+      </el-row>
+      <div slot="footer" class="dialog-footer">
+        <el-button size="small" @click="handleClose">关 闭</el-button>
+        <el-button size="small" @click="sumbit" type="primary">确 认</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+<script>
+  import { listOrganizations, getUserPage } from '@/api/system/organization';
+  export default {
+    data() {
+      return {
+        form: {
+          groupId: null
+        },
+        treeList: [],
+        staffList: [],
+        selectStafflist: [], //已选员工
+        defaultProps: {
+          children: 'children',
+          label: 'name',
+          value: 'code'
+        },
+        pageNum: 1, //设备当前页数
+        size: 10,
+        isMore: false,
+        dialogVisible: false
+      };
+    },
+    created() {},
+    methods: {
+      open(selectedList) {
+
+        this.dialogVisible = true;
+        this.selectStafflist = selectedList;
+        this.getInfo();
+      },
+      //初始数据
+      async getInfo() {
+        let list = await listOrganizations();
+        this.treeList = this.$util.toTreeData({
+          data: list,
+          idField: 'id',
+          parentIdField: 'parentId'
+        });
+        //this.treeList = res.data;
+      },
+      //选择分类
+      handleNodeClick(data) {
+        this.staffList = [];
+
+        this.form.groupId = data.id;
+        let params = {
+          pageNum: 1,
+          size: this.size,
+          groupId: this.form.groupId
+        };
+        this.getStaffList(params);
+      },
+      //获取员工列表
+      async getStaffList(params) {
+        let res = await getUserPage(params);
+        let list = res.list;
+        if (list.length < res.count) {
+          this.isMore = true;
+        } else {
+          this.isMore = false;
+        }
+        list.forEach((el) => {
+          let _index = this.selectStafflist.findIndex((n) => n.id == el.id);
+          if (_index !== -1) {
+            el.disabled = true;
+          } else {
+            el.disabled = false;
+          }
+        });
+        this.staffList = [...this.staffList, ...list];
+        // this.pageNum = res.pageNum;
+      },
+      //查询更多员工
+      async getMore() {
+        this.pageNum = this.pageNum + 1;
+        let params = {
+          pageNum: this.pageNum,
+          size: this.size,
+          groupId: this.form.groupId
+        };
+        this.getStaffList(params);
+      },
+      //选择员工
+      choiceAsset(info) {
+        let data = JSON.parse(JSON.stringify(info));
+        this.selectStafflist.push(data);
+        info.disabled = true;
+      },
+      //删除已选员工
+      deleteSelectStaff(info, index) {
+        this.staffList.forEach((el) => {
+          if (el.id == info.id) {
+            el.disabled = false;
+          }
+        });
+        this.selectStafflist.splice(index, 1);
+      },
+      //保存
+      sumbit() {
+        if (this.selectStafflist.length === 0) {
+          this.$message.warning('请选择员工');
+        } else {
+          this.$emit(
+            'confirm',
+            JSON.parse(JSON.stringify(this.selectStafflist))
+          );
+          this.handleClose();
+        }
+      },
+      handleClose() {
+        this.staffList = [];
+        this.selectStafflist = [];
+        this.dialogVisible = false;
+      }
+    }
+  };
+</script>
+
+<style lang="scss" scoped>
+  .container {
+    padding: 10px 0;
+  }
+  .zw-container {
+    height: 500px;
+    overflow-y: auto;
+  }
+  .zw-header-title {
+    display: inline-block;
+    margin-right: 10px;
+    font-weight: 600;
+  }
+  .details-title {
+    line-height: 32px;
+    height: 32px;
+  }
+  .zw-page-list-p {
+    font-size: 14px;
+    margin-bottom: 18px;
+    display: flex;
+    justify-content: space-between;
+    // align-items: center;
+    .zw-page-list-right {
+      display: flex;
+    }
+  }
+  .zw-page {
+    background: #fff;
+    //padding: 20px 0;
+    height: 600px;
+    .zw-page-left {
+      padding: 0 10px;
+    }
+    .zw-page-main {
+      padding: 0 10px;
+      .zw-page-main-list {
+        span {
+          margin-right: 10px;
+        }
+        .zw-page-span-num {
+          font-size: 12px;
+          color: #157a2c;
+        }
+        .zw-page-p-operation {
+          text-align: right;
+          // width: 200px;
+        }
+        .zw-page-operation-num {
+          width: 100px;
+          margin: 0 10px;
+        }
+      }
+      .zw-page-list-more {
+        text-align: center;
+      }
+    }
+    .zw-page-right {
+      .zw-card-header {
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        height: 32px;
+      }
+      span {
+        margin-right: 10px;
+      }
+      .zw-page-span-num {
+        font-size: 12px;
+        color: #157a2c;
+      }
+    }
+  }
+  .notes {
+    font-size: 12px;
+    color: #909090;
+  }
+</style>

+ 287 - 0
src/views/system/dept/index.vue

@@ -0,0 +1,287 @@
+<template>
+  <div class="ele-body">
+    <el-card shadow="never" v-loading="loading">
+
+      <!-- 数据表格 -->
+      <ele-pro-table
+        ref="table"
+        row-key="id"
+        :columns="columns"
+        :datasource="datasource"
+        :default-expand-all="false"
+        :need-page="false"
+        cache-key="systemMenuTable"
+        @done=""
+      >
+        <!-- 表头工具栏 -->
+        <template v-slot:toolbar>
+          <el-button
+            size="small"
+            type="primary"
+            icon="el-icon-plus"
+            class="ele-btn-icon"
+            @click="openEdit()"
+          >
+            添加
+          </el-button>
+          <el-button class="ele-btn-icon" size="small" @click="expandAll">
+            展开全部
+          </el-button>
+          <el-button class="ele-btn-icon" size="small" @click="foldAll">
+            折叠全部
+          </el-button>
+        </template>
+        <!-- 标题列 -->
+        <template v-slot:name="{ row }">
+          <i :class="row.icon"></i> {{ row.name }}
+        </template>
+        <!-- 类型列 -->
+        <template v-slot:type="{ row }">
+          <el-tag
+            type="primary"
+            size="mini"
+            :disable-transitions="true"
+            v-if="row.type == 1"
+          >
+            菜单
+          </el-tag>
+          <el-tag
+            type="warning"
+            size="mini"
+            :disable-transitions="true"
+            v-if="row.type == 2"
+          >
+            按钮
+          </el-tag>
+        </template>
+        <template v-slot:status="{ row }">
+          <el-tag
+            type="danger"
+            :disable-transitions="true"
+            v-if="row.status == 0"
+          >
+            关闭
+          </el-tag>
+          <el-tag
+            type="primary"
+            :disable-transitions="true"
+            v-if="row.status == 1"
+          >
+            开启
+          </el-tag>
+        </template>
+        <!-- 操作列 -->
+        <template v-slot:action="{ row }">
+          <el-link
+            type="primary"
+            :underline="false"
+            icon="el-icon-edit"
+            @click="openEdit(row)"
+          >
+            修改
+          </el-link>
+          <el-popconfirm
+            class="ele-action"
+            title="确定要删除吗?"
+            @confirm="remove(row)"
+            v-if="row.id != 99999"
+          >
+            <template v-slot:reference>
+              <el-link type="danger" :underline="false" icon="el-icon-delete">
+                删除
+              </el-link>
+            </template>
+          </el-popconfirm>
+        </template>
+      </ele-pro-table>
+    </el-card>
+    <!-- 编辑弹窗 -->
+    <org-edit
+      :visible.sync="showEdit"
+      :data="editData"
+      :parent-id="parentId"
+      :organization-list="data"
+      @done="reload"
+    />
+  </div>
+</template>
+
+<script>
+
+import OrgEdit from './components/org-edit.vue';
+import {
+  listOrganizations,
+  removeOrganization
+} from '@/api/system/organization';
+
+export default {
+  name: 'SystemOrganization',
+  components: {OrgEdit},
+  data() {
+    return {
+      // 加载状态
+      loading: false,
+      // 列表数据
+      data: [],
+      // 选中数据
+      current: null,
+      // 是否显示表单弹窗
+      showEdit: false,
+      // 编辑回显数据
+      editData: null,
+      // 上级id
+      parentId: null
+    };
+  },
+  computed: {
+    // 表格列配置
+    columns() {
+      return [
+        {
+          columnKey: 'index',
+          type: 'index',
+          width: 45,
+          align: 'center',
+          showOverflowTooltip: true,
+          fixed: 'left'
+        },
+        {
+          prop: 'name',
+          label: '部门名称',
+          showOverflowTooltip: true,
+          minWidth: 110,
+          slot: 'name'
+        },
+        {
+          prop: '',
+          label: '负责人',
+          showOverflowTooltip: true,
+          align: 'center',
+          formatter: (_row) => {
+            return _row.manager.map(item => item.name).join(',')
+          },
+          minWidth: 110,
+        },
+
+        {
+          prop: 'sort',
+          label: '排序',
+          showOverflowTooltip: true,
+          align: 'center',
+          width: 60
+        },
+        {
+          prop: 'status',
+          label: '状态',
+          showOverflowTooltip: true,
+          align: 'center',
+          width: 80,
+          slot: 'status'
+        },
+        {
+          prop: 'createTime',
+          label: '创建时间',
+          showOverflowTooltip: true,
+          align: 'center',
+          minWidth: 110,
+          formatter: (_row, _column, cellValue) => {
+            return this.$util.toDateString(cellValue);
+          }
+        },
+        {
+          columnKey: 'action',
+          label: '操作',
+          width: 190,
+          align: 'center',
+          resizable: false,
+          slot: 'action',
+          showOverflowTooltip: true
+        }
+      ]
+    },
+  },
+  created() {
+    //this.query();
+  },
+  methods: {
+    /* 查询 */
+    async datasource() {
+
+      const data = await listOrganizations()
+      this.data = this.$util.toTreeData({
+        data: data,
+        idField: 'id',
+        parentIdField: 'parentId'
+      });
+      return this.data
+
+    },
+    /* 刷新表格 */
+    reload(where) {
+      this.$refs.table.reload();
+    },
+    /* 选择数据 */
+    onNodeClick(row) {
+      if (row) {
+        this.current = row;
+        this.parentId = row.id;
+        this.$refs.tree.setCurrentKey(row.id);
+      } else {
+        this.current = null;
+        this.parentId = null;
+      }
+    },
+    /* 展开全部 */
+    expandAll() {
+      this.$refs.table.toggleRowExpansionAll(true);
+    },
+    /* 折叠全部 */
+    foldAll() {
+      this.$refs.table.toggleRowExpansionAll(false);
+    },
+    /* 显示编辑 */
+    openEdit(item) {
+      this.editData = item;
+      this.showEdit = true;
+    },
+    /* 删除 */
+    remove() {
+      this.$confirm('确定要删除选中的机构吗?', '提示', {
+        type: 'warning'
+      }).then(() => {
+          const loading = this.$loading({lock: true});
+          removeOrganization([this.current.id])
+            .then((msg) => {
+              loading.close();
+              this.$message.success(msg);
+              this.reload();
+            })
+            .catch((e) => {
+              loading.close();
+              // this.$message.error(e.message);
+            });
+        })
+        .catch(() => {
+        });
+    }
+  }
+};
+</script>
+
+<style lang="scss" scoped>
+.sys-organization-list {
+  height: calc(100vh - 264px);
+  box-sizing: border-box;
+  border-width: 1px;
+  border-style: solid;
+  overflow: auto;
+}
+
+.sys-organization-list :deep(.el-tree-node__content) {
+  height: 40px;
+
+  & > .el-tree-node__expand-icon {
+    margin-left: 10px;
+  }
+}
+</style>

+ 140 - 0
src/views/system/role/components/role-data-auth.vue

@@ -0,0 +1,140 @@
+<!-- 角色权限分配弹窗 -->
+<template>
+  <ele-modal
+    width="460px"
+    title="分配权限"
+    :close-on-click-modal="false" custom-class="ele-dialog-form"
+    :visible.sync="roleDataAuthDialogFlag"
+    :before-close="updateVisible"
+  >
+    <el-form ref="form" :model="form" :rules="rules" label-width="100px">
+      <el-form-item label="角色名称">
+        <el-tag>{{ form.name }}</el-tag>
+      </el-form-item>
+      <el-form-item label="组织名称">
+        <el-tag>{{ form.groupName }}</el-tag>
+      </el-form-item>
+      <el-form-item label="权限范围" prop="dataScope">
+        <DictSelection
+          dictName="角色数据权限字典"
+          clearable
+          v-model="form.dataScope"
+        >
+        </DictSelection>
+      </el-form-item>
+      <el-form-item prop="dataScope">
+        <el-scrollbar
+          v-if="form.dataScope=='2'"
+          v-loading="authLoading"
+          style="height: 40vh"
+          wrap-style="overflow-x: hidden;">
+          <el-tree
+            ref="tree"
+            :data="deptData"
+            :check-strictly="true"
+            highlight-current
+            node-key="id"
+            :props="{ label: 'name' }"
+            :expand-on-click-node="false"
+            show-checkbox
+            :default-expand-all="true"
+            :default-checked-keys="checkedKeys"
+          />
+        </el-scrollbar>
+      </el-form-item>
+    </el-form>
+
+
+    <template v-slot:footer>
+      <el-button @click="updateVisible">取消</el-button>
+      <el-button type="primary" :loading="loading" @click="save">
+        保存
+      </el-button>
+    </template>
+  </ele-modal>
+</template>
+
+<script>
+import {putRoles} from '@/api/system/role';
+import {listOrganizations} from "@/api/system/organization";
+
+export default {
+  components: {},
+  props: {
+    // 弹窗是否打开
+    roleDataAuthDialogFlag: Boolean,
+  },
+  data() {
+    return {
+      form: {
+        dataScope: '',
+        dataScopeDeptIds: ''
+      },
+      rules: {},
+      // 权限数据
+      deptData: [],
+      // 权限数据请求状态
+      authLoading: false,
+      // 提交状态
+      loading: false,
+      // 角色权限选中的keys
+      checkedKeys: [],
+      ids: []
+    };
+  },
+  created() {
+   this.getListOrganizations()
+  },
+  methods: {
+
+    /* 查询权限数据 */
+    init(row) {
+      this.form = row
+      this.form.dataScope = this.form.dataScope + ''
+      this.$nextTick(()=>{
+        this.$refs.tree.setCheckedKeys(this.form.dataScopeDeptIds.split(','))
+      })
+
+    },
+    getListOrganizations(){
+      this.authLoading = true;
+      listOrganizations()
+        .then((list) => {
+          let _list = list.filter((i) => i.name != '超级管理员')
+          this.authLoading = false;
+          this.deptData = this.$util.toTreeData({
+            data: _list,
+            idField: 'id',
+            parentIdField: 'parentId'
+          });
+        })
+        .catch((e) => {
+          this.loading = false;
+          // this.$message.error(e.message);
+        });
+    },
+    /* 保存权限分配 */
+    save() {
+      this.loading = true;
+      const ids = this.$refs.tree.getCheckedKeys().concat(this.$refs.tree.getHalfCheckedKeys());
+      this.form.dataScopeDeptIds = ids.join(',');
+      putRoles(this.form)
+        .then((msg) => {
+          this.loading = false;
+          this.$message.success('操作成功');
+          this.updateVisible();
+          this.$emit('reload');
+        })
+        .catch((e) => {
+          this.loading = false;
+          // this.$message.error(e.message);
+        });
+    },
+    /* 更新visible */
+    updateVisible() {
+      this.$emit('update:roleDataAuthDialogFlag', false);
+    },
+  },
+
+};
+</script>

+ 194 - 170
src/views/system/role/index.vue

@@ -2,7 +2,7 @@
   <div class="ele-body">
     <el-card shadow="never">
       <!-- 搜索表单 -->
-      <role-search @search="reload" />
+      <role-search @search="reload"/>
       <!-- 数据表格 -->
       <ele-pro-table
         ref="table"
@@ -61,6 +61,14 @@
           >
             分配权限
           </el-link>
+          <el-link
+            type="primary"
+            :underline="false"
+            icon="el-icon-finished"
+            @click="openDataAuth(row)"
+          >
+            数据权限
+          </el-link>
           <el-popconfirm
             class="ele-action"
             title="确定要删除此角色吗?"
@@ -76,189 +84,205 @@
       </ele-pro-table>
     </el-card>
     <!-- 编辑弹窗 -->
-    <role-edit :data="current" :visible.sync="showEdit" @done="reload" />
+    <role-edit :data="current" :visible.sync="showEdit" @done="reload"/>
     <!-- 权限分配弹窗 -->
-    <role-auth :data="current" :visible.sync="showAuth" />
+    <role-auth :data="current" :visible.sync="showAuth"/>
+    <!--    数据权限-->
+    <role-data-auth ref="roleDataAuthDialogRef" v-if="roleDataAuthDialogFlag"
+                    :roleDataAuthDialogFlag.sync="roleDataAuthDialogFlag" @reload="reload" />
   </div>
 </template>
 
 <script>
-  import RoleSearch from './components/role-search.vue';
-  import RoleEdit from './components/role-edit.vue';
-  import RoleAuth from './components/role-auth.vue';
-  import {
-    pageRoles,
-    removeRole,
-    removeRoles,
-    putRoles
-  } from '@/api/system/role';
+import RoleSearch from './components/role-search.vue';
+import RoleEdit from './components/role-edit.vue';
+import RoleAuth from './components/role-auth.vue';
+import roleDataAuth from "./components/role-data-auth.vue";
+import {
+  pageRoles,
+  removeRole,
+  removeRoles,
+  putRoles
+} from '@/api/system/role';
 
-  export default {
-    name: 'SystemRole',
-    components: {
-      RoleSearch,
-      RoleEdit,
-      RoleAuth
-    },
-    data () {
-      return {
-        // 表格列配置
-        columns: [
-          {
-            columnKey: 'selection',
-            type: 'selection',
-            width: 45,
-            align: 'center',
-            fixed: 'left'
-          },
-          {
-            columnKey: 'index',
-            label: '序号',
-            type: 'index',
-            width: 55,
-            align: 'center',
-            showOverflowTooltip: true,
-            fixed: 'left'
-          },
-          {
-            prop: 'name',
-            label: '角色名称',
-            align: 'center',
+export default {
+  name: 'SystemRole',
+  components: {
+    RoleSearch,
+    RoleEdit,
+    RoleAuth,
+    roleDataAuth
+  },
+  data() {
+    return {
+      // 表格列配置
+      columns: [
+        {
+          columnKey: 'selection',
+          type: 'selection',
+          width: 45,
+          align: 'center',
+          fixed: 'left'
+        },
+        {
+          columnKey: 'index',
+          label: '序号',
+          type: 'index',
+          width: 55,
+          align: 'center',
+          showOverflowTooltip: true,
+          fixed: 'left'
+        },
+        {
+          prop: 'name',
+          label: '角色名称',
+          align: 'center',
 
-            showOverflowTooltip: true,
-            minWidth: 110
-          },
-          {
-            prop: 'groupName',
-            label: '组织名称',
-            align: 'center',
-            showOverflowTooltip: true,
-            minWidth: 110
-          },
-          {
-            prop: 'enable',
-            label: '启用状态',
-            align: 'center',
+          showOverflowTooltip: true,
+          minWidth: 110
+        },
+        {
+          prop: 'groupName',
+          label: '组织名称',
+          align: 'center',
+          showOverflowTooltip: true,
+          minWidth: 110
+        },
+        {
+          prop: 'enable',
+          label: '启用状态',
+          align: 'center',
 
-            showOverflowTooltip: true,
-            slot: 'enable',
+          showOverflowTooltip: true,
+          slot: 'enable',
 
-            minWidth: 110
-          },
-          {
-            prop: 'createTime',
-            label: '创建时间',
-            align: 'center',
+          minWidth: 110
+        },
+        {
+          prop: 'createTime',
+          label: '创建时间',
+          align: 'center',
 
-            showOverflowTooltip: true,
-            minWidth: 110,
-            formatter: (_row, _column, cellValue) => {
-              return this.$util.toDateString(cellValue);
-            }
-          },
-          {
-            columnKey: 'action',
-            label: '操作',
-            width: 230,
-            align: 'center',
-            resizable: false,
-            slot: 'action',
-            showOverflowTooltip: true
+          showOverflowTooltip: true,
+          minWidth: 110,
+          formatter: (_row, _column, cellValue) => {
+            return this.$util.toDateString(cellValue);
           }
-        ],
-        // 表格选中数据
-        selection: [],
-        // 当前编辑数据
-        current: null,
-        // 是否显示编辑弹窗
-        showEdit: false,
-        // 是否显示导入弹窗
-        showAuth: false,
-        isUpdate: false
-      };
-    },
-    created () {},
-    methods: {
-      /* 表格数据源 */
-      datasource ({ page, limit, where, order }) {
-        return pageRoles({ pageNum: page, size: limit, ...where });
-      },
-      async changeEnable (row) {
-        const res = await putRoles(row);
-        if (res.code == 0) {
-          this.$message({
-            type: 'success',
-            message: '修改成功',
-            customClass: 'ele-message-border'
-          });
-          this.reload();
-        }
-      },
-      /* 刷新表格 */
-      reload (where) {
-        this.$refs.table.reload({ page: 1, where });
-      },
-      /* 显示编辑 */
-      openEdit (row) {
-        if (row) {
-          this.current = Object.assign({}, row);
-        } else {
-          this.current = null;
-        }
-        this.showEdit = true;
-      },
-      /* 显示分配权限 */
-      openAuth (row) {
-        if (row) {
-          this.isUpdate = true;
-          this.current = Object.assign({}, row);
-        } else {
-          this.isUpdate = false;
+        },
+        {
+          columnKey: 'action',
+          label: '操作',
+          width: 320,
+          align: 'center',
+          resizable: false,
+          slot: 'action',
+          showOverflowTooltip: true
         }
+      ],
+      // 表格选中数据
+      selection: [],
+      // 当前编辑数据
+      current: null,
+      // 是否显示编辑弹窗
+      showEdit: false,
+      // 是否显示导入弹窗
+      showAuth: false,
+      isUpdate: false,
+      roleDataAuthDialogFlag: false
+    };
+  },
+  created() {
+  },
+  methods: {
+    /* 表格数据源 */
+    datasource({page, limit, where, order}) {
+      return pageRoles({pageNum: page, size: limit, ...where});
+    },
+    async changeEnable(row) {
+      const res = await putRoles(row);
+      if (res.code == 0) {
+        this.$message({
+          type: 'success',
+          message: '修改成功',
+          customClass: 'ele-message-border'
+        });
+        this.reload();
+      }
+    },
+    /* 刷新表格 */
+    reload(where) {
+      this.$refs.table.reload({page: 1, where});
+    },
+    /* 显示编辑 */
+    openEdit(row) {
+      if (row) {
+        this.current = Object.assign({}, row);
+      } else {
+        this.current = null;
+      }
+      this.showEdit = true;
+    },
+    /* 显示分配权限 */
+    openAuth(row) {
+      if (row) {
+        this.isUpdate = true;
+        this.current = Object.assign({}, row);
+      } else {
+        this.isUpdate = false;
+      }
 
-        this.showAuth = true;
-      },
-      /* 删除 */
-      remove (row) {
-        const loading = this.$loading({ lock: true });
-        removeRole(row.id)
-          .then((msg) => {
-            loading.close();
-            this.$message.success(msg);
-            this.reload();
-          })
-          .catch((e) => {
-            loading.close();
-            this.$message.error(e.message);
-          });
-      },
-      /* 批量删除 */
-      removeBatch () {
-        if (!this.selection.length) {
-          this.$message.error('请至少选择一条数据');
-          return;
-        }
-        this.$confirm('确定要删除选中的角色吗?', '提示', {
-          type: 'warning'
+      this.showAuth = true;
+    },
+    /* 显示分配权限 */
+    openDataAuth(row) {
+      this.roleDataAuthDialogFlag = true
+
+      this.$nextTick(() => {
+        this.$refs.roleDataAuthDialogRef.init({...row})
+      });
+    },
+    /* 删除 */
+    remove(row) {
+      const loading = this.$loading({lock: true});
+      removeRole(row.id)
+        .then((msg) => {
+          loading.close();
+          this.$message.success(msg);
+          this.reload();
         })
-          .then(() => {
-            const loading = this.$loading({ lock: true });
-            removeRole(
-              this.selection.map((d) => d.id),
-              true
-            )
-              .then((msg) => {
-                loading.close();
-                this.$message.success(msg);
-                this.reload();
-              })
-              .catch((e) => {
-                loading.close();
-                this.$message.error(e.message);
-              });
-          })
-          .catch(() => {});
+        .catch((e) => {
+          loading.close();
+          this.$message.error(e.message);
+        });
+    },
+    /* 批量删除 */
+    removeBatch() {
+      if (!this.selection.length) {
+        this.$message.error('请至少选择一条数据');
+        return;
       }
+      this.$confirm('确定要删除选中的角色吗?', '提示', {
+        type: 'warning'
+      })
+        .then(() => {
+          const loading = this.$loading({lock: true});
+          removeRole(
+            this.selection.map((d) => d.id),
+            true
+          )
+            .then((msg) => {
+              loading.close();
+              this.$message.success(msg);
+              this.reload();
+            })
+            .catch((e) => {
+              loading.close();
+              this.$message.error(e.message);
+            });
+        })
+        .catch(() => {
+        });
     }
-  };
+  }
+};
 </script>

+ 1 - 1
vue.config.js

@@ -33,7 +33,7 @@ module.exports = {
       '/api': {
         // target: 'http://124.71.68.31:50001',
         // target: 'http://192.168.1.147:18086',
-        target: 'http://192.168.1.125:18086',
+        target: 'http://192.168.1.147:18086',
         changeOrigin: true, // 只有这个值为true的情况下 才表示开启跨域
         pathRewrite: {
           '^/api': ''