飞道的博客

让前端工程师躺平——后端大佬教你写通用组件的开发系列二

472人阅读  评论(0)

前言

阅读前请按照顺序参看系列文章,效果更佳!
Vue中路由到一个公共组件,然后根据路径中是否存在文件动态加载组件
让前端工程师躺平——后端大佬教你写通用组件的开发系列一

据说系列文章很难火爆,因为知识点包袱不够多,所以大家看往后不太愿意收藏, 不过没关系了, 系列文章的好处是看着舒服,碎片化时间内很快就看完了,不是吗?

1、回顾下

第一篇基本属于探索阶段,经过摸索,Vue的功能还是非常强大的!
作为前端重要的输出武器,可谓是小李飞刀,例无虚发,刀刀致命。

既然通过验证,说明公共组件可以完成工作,并且可以很方便的进行扩展。即使自动生成的公共组件无法满足需求,也可以让躺平的前端工程师爬起来,继续按需码代码,何乐而不为呢?

第二篇则从大的思路上结合前后端的优势,试图纵览需求。
整体配合完成一个近似不可能的需求(让前端小弟们躺平,也不知道是拯救前端,还是残害前端)。

前端兄弟们,当你们弄清楚这些的时候,应该已经进阶高阶了吧,不会在意这点小小压力 吧?

其实真正完成这个需求,还是一个蛮大的工程,期间遇到的问题依然不少,这不我又来了。

2、后端接口开发

书接上回,话说经那厮后端甩锅王的设计,接口的表设计已经成型,这不,产品经理A又找到门上。

产品经理A:“锅~~, 王~~~,在吗?”

正在码代码的后端甩锅王,忽然听到耳边传来熟悉而带有魔性的声音,不仅心里一颤,随不情愿,但还是故作精神百倍的应了一声,
“哎哎,在这呢。”

产品经理A:“活来了! 上次你说的那个设计挺好的,能不能今天搞几个接口,让前端童鞋玩玩?”

后端甩锅王:“见外了吧,这不是分分钟的事吗? 不过前端童鞋不是请假了吗(躺平)?”

产品经理A:“这不是请假排队打疫苗,到了才发现去的太早,排了个第一名,所以又来上班了。”

后端甩锅王心理暗骂,这倒霉孩子,我的摸鱼时间啊!嘴上却说:“好嘞,这下就让他有活干!”

产品经理A拍了拍后端甩锅王,“大神啊,我就看好你!”

后端甩锅王默默打开编码神器Visual Studio 2019 全球企业规划旗舰版,
右键打开 EF Core Power Tools ,只见他操作如下,不过片刻功夫,三下五除二搞定了实体定义。



经过上述神奇操作,只剩下写写 服务层和 api控制层了。

如果没有定义,默认就按照数字\文本\日期返回控件吧.

private string GetDefaultType(Type type)
 {
   
      if (numberType.Contains(type))
      {
   
          return "Number";
      }
      else if (dateType.Contains(type)){
   
          return "DateTime";
      }
      else
      {
   
          return "Text";
      }
  }

自动按照EF定义获取列信息,并生成列表和表单的定义插入数据库.

//以插入列表为例,看下面代码,超简单
 var type = _unitOfWork.DbContext.Model.GetEntityTypes().FirstOrDefault(x=>x.ClrType.Name == model.ModelName);
 if(type == null)
  {
   
      throw new BusinessException(PublicError.NotFoundModelName, model.ModelName);
  }
  List<UdfListTemplate> templates = new List<UdfListTemplate>();
  var sortId = 10;
  foreach(var p in type.GetProperties())
  {
   
      //var f = p.FieldInfo;
      templates.Add(new UdfListTemplate
      {
   
          ModelGuid = model.ModelGuid,
          ModelName = model.ModelName,
          SysId = model.SysId,
          FieldName = p.Name,
          ControlType = GetDefaultType(p.ClrType),
          SortId = sortId,
          Width = 140,
          IsEncrypte = 0,
          IsFixed = 0,
          IsHidden = 0,
          IsSearch = 1,
          IsSort = 1,
          IsSum = 0
      }) ;
      sortId += 10;
  }
  //一把插入,速度惊人(可查询之前的批插入文章)
  await _unitOfWork.DbContext.BulkInsertAsync<UdfListTemplate>(templates);

定义下前端童鞋的访问接口

 [HttpGet("{modelGuid}")]
 [AllowAnonymous]
   public Task<GetModelDefineResult> GetModelDefine(string modelGuid)
   {
   
       return _modelService.GetModelDefine(modelGuid);          
   }

打完,测试下,收工!

摸摸鱼,可以交付前端童鞋了。

3、前端童鞋的设计

我就是那个前端。
话说那天,本来想给产品经济一个突然袭击,没想到锅王的锅还是砸到我的头上了,哎,这倒霉孩子~~~

为了觉得我很重视这个功能,我先来个ES6的类,开开胃。

3.1 类设计

一般对于接口这种变化的类,通常我们前端的原则是随用随取,设计毛线的类!

比如后端A\B接口返回的格式如下:

//A
{
   
 "data": {
   
    "a":123,
    "b":"aaaaaabbbb"
 }
}
//B
{
   
   "list":["a","b"],
   "saa":"aaa"
}

那我基本是从api获取数据后,拿来就用, 假设data是api的返回值,则

 const a = data.data.a
 const b = data.data.b
 const c = data.list[0]
 const d = data.saa

好爽~~~ ,
要是出错了 就BB后端, 你咋不返回XXX呢?你咋能是 null呢!

这次设计类,有点闲! 摘抄一部分吧~~

// 模块信息定义
class UdfModelInfo {
   
  constructor(modelGuid,
    modelName,
    sysId,
    name,
    businessPk,
    functionOperate,
    formColNum,
    listShowSelect,
    listShowPage,
    listShowNo,
    listShowTree,
    udf1,
    udf2,
    udf3) {
   
    this.modelGuid = modelGuid
    this.modelName = modelName
    this.sysId = sysId
    this.name = name
    this.businessPk = businessPk
    this.functionOperate = functionOperate
    this.formColNum = formColNum
    this.listShowSelect = listShowSelect
    this.listShowPage = listShowPage
    this.listShowNo = listShowNo
    this.listShowTree = listShowTree
    this.udf1 = udf1
    this.udf2 = udf2
    this.udf3 = udf3
  }
}

// 模块\列表\表单 定义
export default class UdfModel {
   
  constructor(model, listTemplate, formTemplate) {
   
    this.model = new UdfModelInfo(...model)
    this.listTemplate = new UdfListTemplate(...listTemplate)
    this.formTemplate = new UdfFormTemplate(...formTemplate)
    this.createDate = new Date()
  }
}

export {
   
  UdfListTemplate,
  UdfFormTemplate,
  UdfModelInfo,
}

3.2 设计个 store存储

这里采用了vuex来存储每次请求的配置信息。我们计划每10分钟内的数据保存到vuex内,如果超过10分钟,则重新请求后端api。

存储数据采用Map来按modelGuid存储,因为它是唯一的。

const state = {
   
  udf: new Map(),
}

给它增加2个 mutations 方法 操作udf

const mutations = {
   
  SET_UDF_MODEL: (state, key, data) => {
   
    const udfModel = new UdfModel(data.model, data.listTemplate, data.formTemplate)
    state.udf.set(key, udfModel)
  },
  CLEAR_CACHE: (state) => {
   
    state.udf.clear()
  },
}

按照vuex规范,我们换需要增加异步Actions,在这里,我们按照存储的时间判断下值是否超过10分钟,如果超过了,则从http里获取配置信息,并更新它。

const actions = {
   
  setUdfModel({
     commit }, guid) {
   
    if (state.udf.has(guid)) {
   
      const val = state.udf.get(guid)
      if (val && Math.abs(((new Date()).getTime() - val.createDate.getTime())) > 1000 * 60 * 10) {
   
        return
      }
    }
    const http = new Http()
    http.fetch({
   
      url: `/Tools/GetModelDefine/${
     guid}`,
      method: 'get',
    }).then(data => {
   
      if (data && 'model' in data) {
   
        commit('SET_UDF_MODEL', guid, data)
      }
    })
  },
  clearCache({
     commit }) {
   
    commit('CLEAR_CACHE')
  },
}

好了,最后导出这些变量。

export default {
   
  namespaced: true,
  state,
  mutations,
  actions,
}

3.3 清理缓存

因为vuex并没有持久化存储,因此用户按F5,则会清理掉所有缓存。 为了让频繁登陆的用户体验更爽,我们在登陆时,主动清理缓存。

在登陆用户的组件内,增加 mapActions的引用.

import {
    mapActions } from 'vuex'

在组件方法中引入清理缓存方法:

methods: {
   
    ...mapActions({
   
      clearUdfCache: 'udf/clearCache',
    }),
 }

然后呢,在组件创建时,调用它.

 created() {
   
    this.clearUdfCache()
}

3.4 加载数据

之前有说过,我们的公共操作方法,已经提取到 mixus类内,因此我们定义 组件的创建方法时,对数据进行加载。

由于是采用同一个公共组件,完成所有模块的增删改查操作,根据Vue的优化策略,再切换路由后,公共组件并没有被销毁,而是被重用,所以其 Created 钩子方法仅仅调用一次。

为了使得切换路由后,仍可以调用新的配置,我们采用监控路由的方法实现载入数据。

watch: {
   
    $route: function(to, from) {
   
      // todo
      // console.log('watch', to)
      let guid = ''
      if (to.meta && 'guid' in to.meta) {
   
        guid = to.meta.guid
      } else {
   
        let arr = to.path.split('/').slice(0, 3)
        arr = arr.map(item => item ? item[0].toUpperCase() + item.substring(1) : '')
        guid = arr.join('')
      }
      console.log('guid=', guid)
      this.$store.dispatch('udf/setUdfModel', guid)
    },
  },

经过上述一系列操作,已经可以很好的载入配置数据了!

4 小结

躺平每一位工程师都不是我希望看到的,我们是希望能更快速的帮助新手们节省时间,把精力投入到更复杂的需求逻辑上。

因此不要焦虑,上述对话只是个玩笑而已,软件工程师是系统开发不可缺失的人才,当然我们也应该多开动下脑筋,让繁琐重复远离人类!这也是软件工程师神圣的职责之一吧~~~


转载:https://blog.csdn.net/webmote/article/details/117552675
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场