guhongwei 3 年之前
父节点
当前提交
4a62e15b62

+ 2 - 0
java代码/ruoyi-ui/package.json

@@ -48,6 +48,8 @@
     "js-beautify": "1.13.0",
     "js-cookie": "2.2.1",
     "jsencrypt": "3.0.0-rc.1",
+    "lodash": "^4.17.21",
+    "naf-core": "^0.1.2",
     "nprogress": "0.2.0",
     "quill": "1.3.7",
     "screenfull": "5.0.2",

+ 11 - 1
java代码/ruoyi-ui/src/api/system/role.js

@@ -72,4 +72,14 @@ export function exportRole(query) {
     method: 'get',
     params: query
   })
-}
+}
+
+// // 2022-01-22新增
+// // 账号关联
+// export function roleRelation(data) {
+//   return request({
+//     url: "//role",
+//     method: "post",
+//     data: data,
+//   });
+// }

+ 4 - 0
java代码/ruoyi-ui/src/main.js

@@ -23,6 +23,10 @@ import Pagination from "@/components/Pagination";
 // 自定义表格工具扩展
 import RightToolbar from "@/components/RightToolbar"
 
+// axios
+import "@/plugins/axios";
+import "@/plugins/check-res";
+
 // 全局方法挂载
 Vue.prototype.getDicts = getDicts
 Vue.prototype.getConfigKey = getConfigKey

+ 19 - 0
java代码/ruoyi-ui/src/plugins/axios.js

@@ -0,0 +1,19 @@
+import Vue from 'vue';
+import AxiosWrapper from '@/utils/axios-wrapper';
+
+const Plugin = {
+  install(vue, options) {
+    // 3. 注入组件
+    vue.mixin({
+      created() {
+        if (this.$store && !this.$store.$axios) {
+          this.$store.$axios = this.$axios;
+        }
+      },
+    });
+    // 4. 添加实例方法
+    vue.prototype.$axios = new AxiosWrapper(options);
+  },
+};
+
+Vue.use(Plugin, { baseUrl: process.env.VUE_APP_AXIOS_BASE_URL });

+ 39 - 0
java代码/ruoyi-ui/src/plugins/check-res.js

@@ -0,0 +1,39 @@
+/* eslint-disable no-underscore-dangle */
+/* eslint-disable no-param-reassign */
+/* eslint-disable no-unused-vars */
+/* eslint-disable no-shadow */
+import Vue from 'vue';
+import _ from 'lodash';
+import { Message } from 'element-ui';
+
+const vm = new Vue({});
+const Plugin = {
+  install(Vue, options) {
+    // 4. 添加实例方法
+    Vue.prototype.$checkRes = (res, okText, errText) => {
+      let _okText = okText;
+      let _errText = errText;
+      if (!_.isFunction(okText) && _.isObject(okText) && okText != null) {
+        ({ okText: _okText, errText: _errText } = okText);
+      }
+      const { errcode = 0, errmsg } = res || {};
+      if (errcode === 0) {
+        if (_.isFunction(_okText)) {
+          return _okText();
+        }
+        if (_okText) {
+          Message.success(_okText);
+        }
+        return true;
+      }
+      if (_.isFunction(_errText)) {
+        return _errText();
+      }
+      Message.error(_errText || errmsg);
+      // Message({ message: _errText || errmsg, duration: 60000 });
+      return false;
+    };
+  },
+};
+
+Vue.use(Plugin);

+ 4 - 1
java代码/ruoyi-ui/src/store/index.js

@@ -6,6 +6,8 @@ import tagsView from './modules/tagsView'
 import permission from './modules/permission'
 import settings from './modules/settings'
 import getters from './getters'
+import role_relation from "./role_relation";
+
 
 Vue.use(Vuex);
 
@@ -15,7 +17,8 @@ const store = new Vuex.Store({
     user,
     tagsView,
     permission,
-    settings
+    settings,
+    role_relation
   },
   getters,
   name:false

+ 40 - 0
java代码/ruoyi-ui/src/store/role_relation.js

@@ -0,0 +1,40 @@
+import Vue from "vue";
+import Vuex from "vuex";
+import _ from "lodash";
+Vue.use(Vuex);
+const api = {
+  interface: `/labelAchievement/api/setting`,
+};
+const state = () => ({});
+const mutations = {};
+
+const actions = {
+  async query({ commit }, { skip = 0, limit = null, ...info } = {}) {
+    const res = await this.$axios.$get(api.interface, { skip, limit, ...info });
+    return res;
+  },
+  async create({ commit }, payload) {
+    const res = await this.$axios.$post(`${api.interface}`, payload);
+    return res;
+  },
+  async fetch({ commit }, payload) {
+    const res = await this.$axios.$get(`${api.interface}/${payload}`);
+    return res;
+  },
+  async update({ commit }, { id, ...info } = {}) {
+    const res = await this.$axios.$post(`${api.interface}/${id}`, {
+      ...info,
+    });
+    return res;
+  },
+  async delete({ commit }, payload) {
+    const res = await this.$axios.$delete(`${api.interface}/${payload}`);
+    return res;
+  },
+};
+export default {
+  namespaced: true,
+  state,
+  mutations,
+  actions,
+};

+ 117 - 0
java代码/ruoyi-ui/src/utils/axios-wrapper.js

@@ -0,0 +1,117 @@
+/* eslint-disable no-console */
+/* eslint-disable no-param-reassign */
+
+import _ from 'lodash';
+import Axios from 'axios';
+import { Util, Error } from 'naf-core';
+// import { Indicator } from 'mint-ui';
+import util from './user-util';
+
+const { trimData, isNullOrUndefined } = Util;
+const { ErrorCode } = Error;
+
+let currentRequests = 0;
+
+export default class AxiosWrapper {
+  constructor({ baseUrl = '', unwrap = true } = {}) {
+    this.baseUrl = baseUrl;
+    this.unwrap = unwrap;
+  }
+
+  // 替换uri中的参数变量
+  static merge(uri, query = {}) {
+    if (!uri.includes(':')) {
+      return uri;
+    }
+    const keys = [];
+    const regexp = /\/:([a-z0-9_]+)/gi;
+    let res;
+    // eslint-disable-next-line no-cond-assign
+    while ((res = regexp.exec(uri)) != null) {
+      keys.push(res[1]);
+    }
+    keys.forEach((key) => {
+      if (!isNullOrUndefined(query[key])) {
+        uri = uri.replace(`:${key}`, query[key]);
+      }
+    });
+    return uri;
+  }
+
+  $get(uri, query, options) {
+    return this.$request(uri, null, query, options);
+  }
+
+  $post(uri, data = {}, query, options) {
+    return this.$request(uri, data, query, options);
+  }
+  $delete(uri, data = {}, query, options = {}) {
+    options = { ...options, method: 'delete' };
+    return this.$request(uri, data, query, options);
+  }
+  async $request(uri, data, query, options) {
+    // TODO: 合并query和options
+    if (_.isObject(query) && _.isObject(options)) {
+      options = { params: query, method: 'get', ...options };
+    } else if (_.isObject(query) && !query.params) {
+      options = { params: query };
+    } else if (_.isObject(query) && query.params) {
+      options = query;
+    }
+    if (!options) options = {};
+    if (options.params) options.params = trimData(options.params);
+    const url = AxiosWrapper.merge(uri, options.params);
+    currentRequests += 1;
+    // Indicator.open({
+    //   spinnerType: 'fading-circle',
+    // });
+
+    try {
+      const axios = Axios.create({
+        baseURL: this.baseUrl,
+      });
+      // axios.defaults.headers.common.Authorization = util.token;
+      let res = await axios.request({
+        method: isNullOrUndefined(data) ? 'get' : 'post',
+        url,
+        data,
+        responseType: 'json',
+        ...options,
+      });
+      res = res.data;
+      const { errcode, errmsg, details } = res;
+      if (errcode) {
+        console.warn(`[${uri}] fail: ${errcode}-${errmsg} ${details}`);
+        return res;
+      }
+      // unwrap data
+      if (this.unwrap) {
+        res = _.omit(res, ['errmsg', 'details']);
+        const keys = Object.keys(res);
+        if (keys.length === 1 && keys.includes('data')) {
+          res = res.data;
+        }
+      }
+      return res;
+    } catch (err) {
+      let errmsg = '接口请求失败,请稍后重试';
+      if (err.response) {
+        const { status } = err.response;
+        if (status === 401) errmsg = '用户认证失败,请重新登录';
+        if (status === 403) errmsg = '当前用户不允许执行该操作';
+      }
+      console.error(
+        `[AxiosWrapper] 接口请求失败: ${err.config && err.config.url} - 
+        ${err.message}`
+      );
+      return { errcode: ErrorCode.SERVICE_FAULT, errmsg, details: err.message };
+    } finally {
+      /* eslint-disable */
+      currentRequests -= 1;
+      if (currentRequests <= 0) {
+        currentRequests = 0;
+        // Indicator.close();
+      }
+    }
+  }
+}

+ 50 - 0
java代码/ruoyi-ui/src/utils/methods-util.js

@@ -0,0 +1,50 @@
+import { Util } from 'naf-core';
+
+const { isNullOrUndefined } = Util;
+
+export default {
+  //判断信息是否过期
+  isDateOff(dataDate) {
+    const now = new Date(new Date().getTime() - 24 * 60 * 60 * 1000);
+    dataDate = new Date(dataDate);
+    return now.getTime() <= dataDate.getTime();
+  },
+  //判断企业是否可以执行此动作/显示
+  checkCorp(data) {
+    const { role, unit, selfUnit, status, displayType, userid } = data;
+    if (!isNullOrUndefined(selfUnit) && !isNullOrUndefined(status)) {
+      return role === 'corp' && selfUnit === unit && status === '0';
+    } else if (!isNullOrUndefined(displayType)) {
+      if (role === 'corp') {
+        return role === displayType;
+      } else {
+        return role === displayType && !isNullOrUndefined(userid);
+      }
+    }
+  },
+  //获取url的参数params
+  getParams() {
+    let str = location.href;
+    let num = str.indexOf('?');
+    const param = {};
+    str = str.substr(num + 1);
+    let num2 = str.indexOf('#');
+    let str2 = '';
+    if (num2 > 0) {
+      str2 = str.substr(0, num2);
+    } else {
+      num2 = str.indexOf('/');
+      str2 = str.substr(0, num2);
+    }
+    const arr = str2.split('&');
+    for (let i = 0; i < arr.length; i++) {
+      num = arr[i].indexOf('=');
+      if (num > 0) {
+        const name = arr[i].substring(0, num);
+        const value = arr[i].substr(num + 1);
+        param[name] = decodeURI(value);
+      }
+    }
+    return param;
+  },
+};

+ 69 - 0
java代码/ruoyi-ui/src/utils/user-util.js

@@ -0,0 +1,69 @@
+/* eslint-disable no-console */
+export default {
+  get user() {
+    const val = sessionStorage.getItem('user');
+    try {
+      if (val) return JSON.parse(val);
+    } catch (err) {
+      console.error(err);
+    }
+    return null;
+  },
+  set user(userinfo) {
+    sessionStorage.setItem('user', JSON.stringify(userinfo));
+  },
+  get token() {
+    return sessionStorage.getItem('token');
+  },
+  set token(token) {
+    sessionStorage.setItem('token', token);
+  },
+  get openid() {
+    return sessionStorage.getItem('openid');
+  },
+  set openid(openid) {
+    sessionStorage.setItem('openid', openid);
+  },
+  get isGuest() {
+    return !this.user || this.user.role === 'guest';
+  },
+  save({ userinfo, token }) {
+    sessionStorage.setItem('user', JSON.stringify(userinfo));
+    sessionStorage.setItem('token', token);
+  },
+
+  get corpInfo() {
+    const val = sessionStorage.getItem('corpInfo');
+    if (val) return JSON.parse(val);
+    return null;
+  },
+  set corpInfo(corpInfo) {
+    sessionStorage.setItem('corpInfo', JSON.stringify(corpInfo));
+  },
+  saveCorpInfo(corpInfo) {
+    sessionStorage.setItem('corpInfo', JSON.stringify(corpInfo));
+  },
+
+  get unit() {
+    const val = sessionStorage.getItem('unit');
+    if (val) return JSON.parse(val);
+    return null;
+  },
+  set unit(unitList) {
+    sessionStorage.setItem('unit', JSON.stringify(unitList));
+  },
+  saveUnit(unitList) {
+    sessionStorage.setItem('unit', JSON.stringify(unitList));
+  },
+  get userInfo() {
+    const val = sessionStorage.getItem('userInfo');
+    if (val) return JSON.parse(val);
+    return null;
+  },
+  set userInfo(userInfo) {
+    sessionStorage.setItem('userInfo', JSON.stringify(userInfo));
+  },
+  saveUserInfo(userInfo) {
+    sessionStorage.setItem('userInfo', JSON.stringify(userInfo));
+  },
+};

+ 210 - 8
java代码/ruoyi-ui/src/views/merits/setting/index.vue

@@ -1,24 +1,222 @@
 <template>
   <div id="index">
     <el-row>
-      <el-col :span="24" class="main"> test </el-col>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one">
+          <el-form
+            :model="queryParams"
+            ref="queryForm"
+            v-show="showSearch"
+            :inline="true"
+          >
+            <el-form-item label="角色名称" prop="roleName">
+              <el-input
+                v-model="queryParams.roleName"
+                placeholder="请输入角色名称"
+                clearable
+                size="small"
+                style="width: 240px"
+                @keyup.enter.native="handleQuery"
+              />
+            </el-form-item>
+            <el-form-item>
+              <el-button
+                type="primary"
+                icon="el-icon-search"
+                size="mini"
+                @click="handleQuery"
+                >搜索</el-button
+              >
+              <el-button icon="el-icon-refresh" size="mini" @click="resetQuery"
+                >重置</el-button
+              >
+            </el-form-item>
+          </el-form>
+        </el-col>
+        <el-col :span="24" class="two">
+          <el-table
+            v-loading="loading"
+            :data="roleList"
+            border
+            :header-cell-style="{ 'text-align': 'center' }"
+            :cell-style="{ 'text-align': 'center' }"
+          >
+            <el-table-column
+              label="角色名称"
+              prop="roleName"
+              :show-overflow-tooltip="true"
+            />
+            <el-table-column
+              label="权限字符"
+              prop="roleKey"
+              :show-overflow-tooltip="true"
+            />
+            <el-table-column
+              label="操作"
+              align="center"
+              class-name="small-padding fixed-width"
+            >
+              <template slot-scope="scope">
+                <el-button
+                  size="mini"
+                  type="text"
+                  icon="el-icon-refresh-right"
+                  @click="toRelation(scope.row)"
+                  v-hasPermi="['system:role:relation']"
+                  >账号等级关联</el-button
+                >
+              </template>
+            </el-table-column>
+          </el-table>
+          <pagination
+            v-show="total > 0"
+            :total="total"
+            :page.sync="queryParams.pageNum"
+            :limit.sync="queryParams.pageSize"
+            @pagination="getList"
+          />
+        </el-col>
+      </el-col>
     </el-row>
+    <el-dialog
+      :title="dialog.title"
+      :visible.sync="dialog.show"
+      width="30%"
+      :before-close="toClose"
+    >
+      <el-form ref="form" :model="form" :rules="rules" label-width="100px">
+        <el-form-item label="角色名称">
+          <el-input v-model="form.roleName" disabled></el-input>
+        </el-form-item>
+        <el-form-item label="权限字符">
+          <el-input v-model="form.roleKey" disabled></el-input>
+        </el-form-item>
+        <el-form-item label="账号等级" prop="level">
+          <el-radio-group v-model="form.level">
+            <el-radio label="1">一级账号</el-radio>
+            <el-radio label="2">二级账号</el-radio>
+            <el-radio label="3">三级账号</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" size="mini" @click="onSubmit('form')"
+            >保存</el-button
+          >
+        </el-form-item>
+      </el-form>
+    </el-dialog>
   </div>
 </template>
 
 <script>
-import { mapState, createNamespacedHelpers } from 'vuex';
+import { mapState, mapGetters, createNamespacedHelpers } from "vuex";
+import { listRole } from "@/api/system/role";
+const { mapActions: role_relation } = createNamespacedHelpers("role_relation");
 export default {
-  name: 'index',
+  name: "index",
   props: {},
   components: {},
   data: function () {
-    return {};
+    return {
+      // 遮罩层
+      loading: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 角色表格数据
+      roleList: [],
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        roleName: undefined,
+      },
+      dialog: { title: "账号关联", show: false },
+      // 账号关联
+      form: {},
+      rules: {
+        level: [
+          { required: true, message: "请选择账号等级", trigger: "change" },
+        ],
+      },
+    };
+  },
+  created() {
+    this.getList();
+    this.getDicts("sys_normal_disable").then((response) => {
+      this.statusOptions = response.data;
+    });
+  },
+  methods: {
+    ...role_relation(["query", "update"]),
+    /** 查询角色列表 */
+    getList() {
+      this.loading = true;
+      listRole(this.addDateRange(this.queryParams, this.dateRange)).then(
+        (response) => {
+          this.roleList = response.rows;
+          this.total = response.total;
+          this.loading = false;
+        }
+      );
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.dateRange = [];
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 账号等级关联
+    async toRelation(data) {
+      // 查询该角色关联信息
+      let res = await this.query();
+      if (this.$checkRes(res)) {
+        let arr = {
+          id: res.data.id,
+          roleName: data.roleName,
+          roleKey: data.roleKey,
+        };
+        let relation = res.data.relation.find((i) => i.role == data.roleKey);
+        if (relation) arr.level = relation.level;
+        this.$set(this, `form`, arr);
+        this.dialog = { title: "账号关联", show: true };
+      }
+    },
+    // 保存
+    onSubmit(formName) {
+      this.$refs[formName].validate(async (valid) => {
+        if (valid) {
+          let data = {
+            id: this.form.id,
+            relation: [{ role: this.form.roleKey, level: this.form.level }],
+          };
+          let res = await this.update(data);
+          if (res.code === 200) {
+            this.$message({ type: `success`, message: res.msg });
+            this.toClose();
+          } else {
+            this.$message({ type: `error`, message: res.msg });
+          }
+        } else {
+          console.log("error submit!!");
+          return false;
+        }
+      });
+    },
+    // 账号关联关闭
+    toClose() {
+      this.dialog = { title: "账号关联", show: false };
+      this.getList();
+    },
   },
-  created() {},
-  methods: {},
   computed: {
-    ...mapState(['user']),
+    ...mapGetters(["roles"]),
   },
   metaInfo() {
     return { title: this.$route.meta.title };
@@ -33,4 +231,8 @@ export default {
 };
 </script>
 
-<style lang="less" scoped></style>
+<style lang="scss" scoped>
+.main {
+  padding: 25px 30px 30px;
+}
+</style>

+ 48 - 46
java代码/ruoyi-ui/vue.config.js

@@ -21,9 +21,9 @@ module.exports = {
   // 在npm run build 或 yarn build 时 ,生成文件的目录名称(要和baseUrl的生产环境路径一致)(默认dist)
   outputDir: process.env.VUE_APP_ROUTER,
   // 用于放置生成的静态资源 (js、css、img、fonts) 的;(项目打包之后,静态资源会放在这个文件夹下)
-  assetsDir: 'static',
+  assetsDir: "static",
   // 是否开启eslint保存检测,有效值:ture | false | 'error'
-  lintOnSave: process.env.NODE_ENV === 'development',
+  lintOnSave: process.env.NODE_ENV === "development",
   // 如果你不需要生产环境的 source map,可以将其设置为 false 以加速生产环境构建。
   productionSourceMap: false,
   // webpack-dev-server 相关配置
@@ -35,82 +35,84 @@ module.exports = {
       // detail: https://cli.vuejs.org/config/#devserver-proxy
       [process.env.VUE_APP_BASE_API]: {
         target: `http://192.168.1.197:8112`, // 8112
-        changeOrigin: true
+        changeOrigin: true,
         // pathRewrite: {
         //   ['^' + process.env.VUE_APP_BASE_API]: ''
         // }
-      }
+      },
+      "/labelAchievement/api": {
+        target: "http://192.168.1.197:13001", //http://192.168.1.19:9101
+        changeOrigin: true,
+        ws: false,
+      },
     },
-    disableHostCheck: true
+    disableHostCheck: true,
   },
   configureWebpack: {
     name: name,
     resolve: {
       alias: {
-        '@': resolve('src')
-      }
-    }
+        "@": resolve("src"),
+      },
+    },
   },
   chainWebpack(config) {
-    config.plugins.delete('preload') // TODO: need test
-    config.plugins.delete('prefetch') // TODO: need test
+    config.plugins.delete("preload"); // TODO: need test
+    config.plugins.delete("prefetch"); // TODO: need test
 
     // set svg-sprite-loader
+    config.module.rule("svg").exclude.add(resolve("src/assets/icons")).end();
     config.module
-      .rule('svg')
-      .exclude.add(resolve('src/assets/icons'))
-      .end()
-    config.module
-      .rule('icons')
+      .rule("icons")
       .test(/\.svg$/)
-      .include.add(resolve('src/assets/icons'))
+      .include.add(resolve("src/assets/icons"))
       .end()
-      .use('svg-sprite-loader')
-      .loader('svg-sprite-loader')
+      .use("svg-sprite-loader")
+      .loader("svg-sprite-loader")
       .options({
-        symbolId: 'icon-[name]'
+        symbolId: "icon-[name]",
       })
-      .end()
+      .end();
 
-    config.when(process.env.NODE_ENV !== 'development', config => {
+    config.when(process.env.NODE_ENV !== "development", (config) => {
       config
-        .plugin('ScriptExtHtmlWebpackPlugin')
-        .after('html')
-        .use('script-ext-html-webpack-plugin', [
+        .plugin("ScriptExtHtmlWebpackPlugin")
+        .after("html")
+        .use("script-ext-html-webpack-plugin", [
           {
             // `runtime` must same as runtimeChunk name. default is `runtime`
-            inline: /runtime\..*\.js$/
-          }
+            inline: /runtime\..*\.js$/,
+          },
         ])
-        .end()
+        .end();
       config.optimization.splitChunks({
-        chunks: 'all',
+        chunks: "all",
         cacheGroups: {
           libs: {
-            name: 'chunk-libs',
+            name: "chunk-libs",
             test: /[\\/]node_modules[\\/]/,
             priority: 10,
-            chunks: 'initial' // only package third parties that are initially dependent
+            chunks: "initial", // only package third parties that are initially dependent
           },
           elementUI: {
-            name: 'chunk-elementUI', // split elementUI into a single package
+            name: "chunk-elementUI", // split elementUI into a single package
             priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
-            test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm
+            test: /[\\/]node_modules[\\/]_?element-ui(.*)/, // in order to adapt to cnpm
           },
           commons: {
-            name: 'chunk-commons',
-            test: resolve('src/components'), // can customize your rules
+            name: "chunk-commons",
+            test: resolve("src/components"), // can customize your rules
             minChunks: 3, //  minimum common number
             priority: 5,
-            reuseExistingChunk: true
-          }
-        }
-      })
-      config.optimization.runtimeChunk('single'),
-      {
-        from: path.resolve(__dirname, './public/robots.txt'), // 防爬虫文件
-        to: './' // 到根目录下
-      }
-    })
-  }
-}
+            reuseExistingChunk: true,
+          },
+        },
+      });
+      config.optimization.runtimeChunk("single"),
+        {
+          from: path.resolve(__dirname, "./public/robots.txt"), // 防爬虫文件
+          to: "./", // 到根目录下
+        };
+    });
+  },
+};