wangting
2024-04-08 7d2a2488ad5ee9e8102464e39ef206d42d1124dc
UI上下文展示引擎
已修改7个文件
384 ■■■■ 文件已修改
Source/ProjectWeb/src/components/dynamic-components/dynamic-custom.vue 108 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/ProjectWeb/src/page/index/index.vue 230 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/ProjectWeb/src/router/avue-router.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/ProjectWeb/src/store/modules/user.js 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/ProjectWeb/src/util/util.js 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/ProjectWeb/src/util/validate.js 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/ProjectWeb/src/views/base/UIContentViewer.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/ProjectWeb/src/components/dynamic-components/dynamic-custom.vue
@@ -1,6 +1,6 @@
<template>
  <div class="UI-dynamic" :id="'UI-dynamic-'+areasName+componentVO.oid">
    <div v-if="isError" style="color: #F56C6C">这个自定义页面的地址格式不正确。推荐使用bs=?type=xxx&context=yyy&pparam=zzz这种形式</div>
    <div v-if="isError" style="color: #F56C6C">这个自定义页面的地址格式不正确。推荐使用bs=组件name?type=xxx&context=yyy&pparam=zzz这种形式</div>
    <component v-else :is="currentComponent"
               :btmType="btmType"
               :content="content"
@@ -15,38 +15,39 @@
</template>
<script>
import {queryStringToObject} from '@/util/util'
export default {
  name: "dynamic-custom",
  components:{
    'UI':()=>import('@/views/base/UIContentViewerInDialog'),
    'test':()=>import('@/views/custom-ui/test'),
    'test2':()=>import('@/views/custom-ui/test2'),
  components: {
    'UI': () => import('@/views/base/UIContentViewerInDialog'),
    'test': () => import('@/views/custom-ui/test'),
    'test2': () => import('@/views/custom-ui/test2'),
  },
  props:{
    componentVO:{
      type:Object,
  props: {
    componentVO: {
      type: Object,
      default: {}
    },
    inDialog: {
      type: Boolean,
      default: false
    },
    areasName:{
      type:String,
      default:''
    areasName: {
      type: String,
      default: ''
    },
    sourceData:{
    sourceData: {
      //所属区域的上一区域选中数据
      type:Object,
      type: Object,
      default: {}
    },
    dataStore:{
    dataStore: {
      //弹窗时按钮所属区域选中数据
      type:Array,
      type: Array,
      default: []
    },
    paramVOS:{
      type:Object,
    paramVOS: {
      type: Object,
      default: {}
    },
    isShow: {
@@ -57,17 +58,17 @@
  },
  data() {
    return {
      btmType:'',
      content:'',
      urlParams:{},
      height:'300px',
      customClass:this.componentVO.customClass, //bs=?type=xxx&context=yyy&param=zzz  或者 bs=组件name?type=xxx&context=yyy&param=zzz
      isError:false, //路径解析失败
      btmType: '',
      content: '',
      urlParams: {},
      height: '300px',
      customClass: this.componentVO.customClass, //bs=?type=xxx&context=yyy&param=zzz  或者 bs=组件name?type=xxx&context=yyy&param=zzz
      isError: false, //路径解析失败
      currentComponent: 'UI',//组件name
    }
  },
  watch:{
    sourceData:{
  watch: {
    sourceData: {
      handler(newval) {
        //源数据有变化时变更当前区域数据
        console.log(this.areasName);
@@ -75,51 +76,38 @@
      }
    }
  },
  computed:{
  },
  computed: {},
  created() {
  },
  mounted() {
    if(this.customClass.indexOf("bs=") <0){
      this.isError=true;
      return ;
    if (this.customClass.indexOf("bs=") < 0) {
      this.isError = true;
      return;
    }
    this.customClass=this.componentVO.customClass.split("bs=")[1];
    if(this.customClass.indexOf("?") <0 || this.customClass.indexOf("type=") <0 || this.customClass.indexOf("context=") <0){
      this.isError=true;
      return ;
    this.customClass = this.componentVO.customClass.split("bs=")[1];
    if (this.customClass.indexOf("?") < 0 || this.customClass.indexOf("type=") < 0 || this.customClass.indexOf("context=") < 0) {
      this.isError = true;
      return;
    }
    if(this.customClass.split('?')[0]!='' && this.customClass.split('?')[0]!='UI' && this.customClass.split('?')[0]!='ui'){
      this.currentComponent=this.customClass.split('?')[0];
    if (this.customClass.split('?')[0] != '' && this.customClass.split('?')[0] != 'UI' && this.customClass.split('?')[0] != 'ui') {
      this.currentComponent = this.customClass.split('?')[0];
    }
    this.customClass=this.componentVO.customClass.split("?")[1].split('&');
    let urlParams={};
    let btmType=''
    let content=''
    this.customClass.forEach(item=>{
      var preParam =item.split("=");
      if(preParam[0]=='type'){
        btmType=preParam[1];
      }else if(preParam[0]=='context'){
        content=preParam[1];
      }else{
        urlParams[preParam[0]] = preParam[1];
      }
    })
    let urlParams = queryStringToObject(this.customClass);
    let btmType = urlParams.type;
    let content = urlParams.context;
      this.btmType=btmType,
      this.content=content,
      this.urlParams=Object.assign(this.paramVOS,urlParams)
    this.btmType = btmType;
    this.content = content;
    this.urlParams = Object.assign(this.paramVOS, urlParams)
    //this.getHeight(this.$parent);
 },
  methods:{
    getHeight(el){
      if(el.$el.clientHeight>50){
        this.height=el.$el.clientHeight+'px';
      }else {
  },
  methods: {
    getHeight(el) {
      if (el.$el.clientHeight > 50) {
        this.height = el.$el.clientHeight + 'px';
      } else {
        this.getHeight(el.$parent);
      }
    }
Source/ProjectWeb/src/page/index/index.vue
@@ -29,129 +29,129 @@
</template>
<script>
  import {mapGetters} from "vuex";
  import tags from "./tags";
  import search from "./search";
  import top from "./top/";
  import sidebar from "./sidebar/";
  import admin from "@/util/admin";
  import {validatenull} from "@/util/validate";
  import {calcDate} from "@/util/date.js";
  import {getStore} from "@/util/store.js";
import {mapGetters} from "vuex";
import tags from "./tags";
import search from "./search";
import top from "./top/";
import sidebar from "./sidebar/";
import admin from "@/util/admin";
import {validatenull} from "@/util/validate";
import {calcDate} from "@/util/date.js";
import {getStore} from "@/util/store.js";
  export default {
    components: {
      top,
      tags,
      search,
      sidebar
export default {
  components: {
    top,
    tags,
    search,
    sidebar
  },
  name: "index",
  provide() {
    return {
      index: this
    };
  },
  data() {
    return {
      //搜索控制
      isSearch: false,
      //刷新token锁
      refreshLock: false,
      //刷新token的时间
      refreshTime: "",
      loading:true
    };
  },
  created() {
    //实时检测刷新token
    this.refreshToken();
  },
  mounted() {
    this.init();
    // 左侧菜单加载
    setTimeout(()=>{
      this.loading=false
    },600)
  },
  computed: mapGetters(["isMenu", "isLock", "isCollapse", "website", "menu"]),
  props: [],
  methods: {
    showCollapse() {
      this.$store.commit("SET_COLLAPSE");
    },
    name: "index",
    provide() {
      return {
        index: this
    // 初始化
    init() {
      this.$store.commit("SET_SCREEN", admin.getScreen());
      window.onresize = () => {
        setTimeout(() => {
          this.$store.commit("SET_SCREEN", admin.getScreen());
        }, 0);
      };
      this.$store.dispatch("FlowRoutes").then(() => {
      });
    },
    data() {
      return {
        //搜索控制
        isSearch: false,
        //刷新token锁
        refreshLock: false,
        //刷新token的时间
        refreshTime: "",
        loading:true
      };
    },
    created() {
      //实时检测刷新token
      this.refreshToken();
    },
    mounted() {
      this.init();
      // 左侧菜单加载
      setTimeout(()=>{
        this.loading=false
      },600)
    },
    computed: mapGetters(["isMenu", "isLock", "isCollapse", "website", "menu"]),
    props: [],
    methods: {
      showCollapse() {
        this.$store.commit("SET_COLLAPSE");
      },
      // 初始化
      init() {
        this.$store.commit("SET_SCREEN", admin.getScreen());
        window.onresize = () => {
          setTimeout(() => {
            this.$store.commit("SET_SCREEN", admin.getScreen());
          }, 0);
        };
        this.$store.dispatch("FlowRoutes").then(() => {
        });
      },
      //打开菜单
      openMenu(item = {}) {
        this.$store.dispatch("GetMenu", item.id).then(data => {
          if (data.length !== 0) {
            this.$router.$avueRouter.formatRoutes(data, true);
          }
          //当点击顶部菜单后默认打开第一个菜单
          /*if (!this.validatenull(item)) {
            let itemActive = {},
              childItemActive = 0;
            if (item.path) {
              itemActive = item;
    //打开菜单
    openMenu(item = {}) {
      this.$store.dispatch("GetMenu", item.id).then(data => {
        if (data.length !== 0) {
          this.$router.$avueRouter.formatRoutes(data, true);
        }
        //当点击顶部菜单后默认打开第一个菜单
        /*if (!this.validatenull(item)) {
          let itemActive = {},
            childItemActive = 0;
          if (item.path) {
            itemActive = item;
          } else {
            if (this.menu[childItemActive].length === 0) {
              itemActive = this.menu[childItemActive];
            } else {
              if (this.menu[childItemActive].length === 0) {
                itemActive = this.menu[childItemActive];
              } else {
                itemActive = this.menu[childItemActive].children[childItemActive];
              }
              itemActive = this.menu[childItemActive].children[childItemActive];
            }
            this.$store.commit('SET_MENU_ID', item);
            this.$router.push({
              path: this.$router.$avueRouter.getPath({
                name: (itemActive.label || itemActive.name),
                src: itemActive.path
              }, itemActive.meta)
            });
          }*/
        });
      },
      // 定时检测token
      refreshToken() {
        this.refreshTime = setInterval(() => {
          const token = getStore({
            name: "token",
            debug: true
          }) || {};
          const date = calcDate(token.datetime, new Date().getTime());
          if (validatenull(date)) return;
          if (date.seconds >= this.website.tokenTime && !this.refreshLock) {
            this.refreshLock = true;
            this.$store
              .dispatch("refreshToken")
              .then(() => {
                this.refreshLock = false;
              })
              .catch(() => {
                this.refreshLock = false;
              });
          }
        }, 10000);
      }
          this.$store.commit('SET_MENU_ID', item);
          this.$router.push({
            path: this.$router.$avueRouter.getPath({
              name: (itemActive.label || itemActive.name),
              src: itemActive.path
            }, itemActive.meta)
          });
        }*/
      });
    },
    // 定时检测token
    refreshToken() {
      this.refreshTime = setInterval(() => {
        const token = getStore({
          name: "token",
          debug: true
        }) || {};
        const date = calcDate(token.datetime, new Date().getTime());
        if (validatenull(date)) return;
        if (date.seconds >= this.website.tokenTime && !this.refreshLock) {
          this.refreshLock = true;
          this.$store
            .dispatch("refreshToken")
            .then(() => {
              this.refreshLock = false;
            })
            .catch(() => {
              this.refreshLock = false;
            });
        }
      }, 10000);
    }
  };
  }
};
</script>
<style lang="scss">
 #avue-view .avue-view{
   height: 100%;
   padding: 0 6px !important;
 }
#avue-view > .avue-view{
  height: 100%;
  padding: 0 6px !important;
}
</style>
Source/ProjectWeb/src/router/avue-router.js
@@ -90,7 +90,6 @@
     * first: 为了区分外界 调用formatRoutes 和 当前文件调用 formatRoutes
     */
    formatRoutes: function (aMenu = [], first) {
      // debugger;
      const aRouter = []
      // 获取到全局配置中的 props
      const propsConfig = this.$website.menu.props;
Source/ProjectWeb/src/store/modules/user.js
@@ -2,7 +2,7 @@
import {Message} from 'element-ui'
import {setStore, getStore} from '@/util/store'
import {isURL, validatenull} from '@/util/validate'
import {deepClone} from '@/util/util'
import {deepClone,queryStringToObject} from '@/util/util'
import website from '@/config/website'
import {loginByUsername, loginBySocial, loginBySso, getUserInfo, logout, refreshToken, getButtons} from '@/api/user'
import {getTopMenu, getRoutes} from '@/api/system/menu'
@@ -38,25 +38,11 @@
    item.path = '/' + item.code;
    item.query = {}; // 初始化 item.query
    item.query = queryStringToObject(item.pathValue)
    console.log('item', item);
    if (item.children && item.children.length > 0) {
      updateCode(item.children);
    }
  });
}
function queryStringToObject(queryString) {
  const index = queryString.indexOf('?');
  if (index !== -1) {
    queryString = queryString.substring(index + 1);
  }
  const params = new URLSearchParams(queryString);
  const obj = {};
  for (const [key, value] of params.entries()) {
    obj[key] = value;
  }
  return obj;
}
const user = {
  state: {
@@ -77,7 +63,6 @@
        loginByUsername(userInfo.tenantId, userInfo.deptId, userInfo.roleId, userInfo.username, md5(userInfo.password), userInfo.type, userInfo.key,).then(res => {
          const data = res.data;
          if (data.success) {
            debugger;
            commit('SET_TOKEN', data.obj.sessionInfo.token);
            commit('SET_REFRESH_TOKEN', data.obj.sessionInfo.token);
            commit('SET_TENANT_ID', data.tenant_id);
@@ -257,7 +242,6 @@
  },
  mutations: {
    SET_TOKEN: (state, token) => {
      debugger;
      setToken(token);
      state.token = token;
      setStore({name: 'token', content: state.token})
Source/ProjectWeb/src/util/util.js
@@ -389,3 +389,20 @@
    window.open(URL.createObjectURL(file));
  }
}
/**
 * 解析地址参数
 * @param {String} queryString - 地址?后面部分
 */
export const queryStringToObject = (queryString) => {
  const index = queryString.indexOf('?');
  if (index !== -1) {
    queryString = queryString.substring(index + 1);
  }
  const params = new URLSearchParams(queryString);
  const obj = {};
  for (const [key, value] of params.entries()) {
    obj[key] = value;
  }
  return obj;
}
Source/ProjectWeb/src/util/validate.js
@@ -173,6 +173,14 @@
  else return true;
};
/**
 * URL地址
 * @param {*} s
 */
export function isURL(s) {
  return /^http[s]?:\/\/.*/.test(s)
}
// 登录账号 (字母开头,允许5-16字节,允许字母数字下划线)
export const verifyAccount = (val) => {
  const petter = /^[a-zA-Z][a-zA-Z0-9_]{4,15}$/;
Source/ProjectWeb/src/views/base/UIContentViewer.vue
@@ -77,7 +77,7 @@
  computed: {},
  created() {
    if (verifyNull(this.$route.query.type) || (verifyNull(this.$route.query.context) && verifyNull(this.$route.query.content))) {
      this.$message.error("配置的信息错误,请参考bs=?type=xxx&context=yyy&param=zzz这种形式。其中type是业务类型(或链接类型),context是UI上下文的名称");
      this.$message.error("配置的信息错误,请参考bs=组件name?type=xxx&context=yyy&param=zzz这种形式。其中type是业务类型(或链接类型),context是UI上下文的名称");
      return false;
    }
    this.btmType=this.$route.query.type;