疫情期间,写的两个场景

简介: 落笔前,先期望疫情快快过去,都要生锈了都~

场景一


模拟接口请求,对请求头的参数进行处理,如下图:


image.png


嗯,我是用的vue版本的ant design,然后实现之后是这样的:


image.png


相关代码:


<template>
  <div class="mock-info">
    <a-form :form="form">
      <!-- 基本信息 -->
      <a-divider orientation="left" style="color: #1890ff;">基本信息</a-divider>
      <a-form-item
        v-bind="formItemLayout"
        label="期待名称">
        <a-input 
          v-decorator="[
            'name',
            {rules: [{ required: true, message: '请输入环境域名'}]}
          ]"
          placeholder="请输入期待名称"/>
      </a-form-item>
      <a-form-item
        style="margin-bottom: 0;"
        v-bind="formItemLayoutWithOutLabel">
        <a-switch checkedChildren="JSON" unCheckedChildren="JSON" v-decorator="['is_json', {valuePropName: 'checked', initialValue: false }]" />
      </a-form-item>
      <div class="paramsArr" v-show="!form.getFieldValue('is_json')"> <!--非json展示输入框-->
        <a-form-item
          v-for="(k, index) in form.getFieldValue('baseKeys')"
          :key="k"
          v-bind="index === 0 ? formItemLayout : formItemLayoutWithOutLabel"
          :label="index === 0 ? '参数名称' : ''"
          :required="false"
          style="margin-bottom: 0;">
          <a-input
            v-decorator="[`paramNames[${k}]`]"
            placeholder="参数过滤"
            style="width: 40%; margin-right: 8px"/>
          <a-input
            v-decorator="[`paramValues[${k}]`]"
            placeholder="参数值"
            style="width: 40%; margin-right: 8px"/>
          <a-icon
            v-if="form.getFieldValue('baseKeys').length > 1"
            class="dynamic-delete-button"
            type="minus-circle-o"
            :disabled="form.getFieldValue('baseKeys').length === 1"
            @click="() => removeParam(k)"/>
        </a-form-item>
        <a-form-item v-bind="formItemLayoutWithOutLabel">
          <a-button type="primary" style="width: 60%" @click="addParam">
            <a-icon type="plus" /> 添加参数
          </a-button>
        </a-form-item>
      </div>
      <div v-show="form.getFieldValue('is_json')">
        <a-form-item
          v-bind="formItemLayout"
          label="参数名称">
          <v-jsoneditor 
            style="margin-top: 12px;" 
            :options="options"
            v-model="request_params" />
        </a-form-item>
      </div>
      <!-- 响应信息 -->
      <a-divider orientation="left" style="color: #1890ff;">响应</a-divider>
      <a-form-item
        v-bind="formItemLayout"
        label="HTTP Code">
        <a-select
          v-decorator="[
            'http_code',
            {rules: [{ required: false, message: '请选择'}]}
          ]"
          showSearch
          placeholder="请选择">
          <a-select-option v-for="(item, index) in codes" :key="index" :value="item">{{item}}</a-select-option>
        </a-select>
      </a-form-item>
      <a-form-item
        v-bind="formItemLayout"
        label="延时">
        <a-input-number
          v-decorator="['delay_time', { initialValue: 0 }]"
          :min="0"/>&nbsp;ms
      </a-form-item>
      <div class="httpArr">
        <a-form-item
          v-for="(k, index) in form.getFieldValue('httpKeys')"
          :key="k"
          v-bind="index === 0 ? formItemLayout : formItemLayoutWithOutLabel"
          :label="index === 0 ? 'HTTP头' : ''"
          :required="false"
          style="margin-bottom: 0;">
          <a-select
            mode="combobox"
            v-decorator="[`httpNames[${k}]`]"
            showSearch
            placeholder="请选择"
            style="width: 40%; margin-right: 8px">
            <a-select-option v-for="(item, index) in http_headers" :key="index" :value="item">{{item}}</a-select-option>
          </a-select>
          <a-input
            v-decorator="[`httpValues[${k}]`]"
            placeholder="参数值"
            style="width: 40%; margin-right: 8px"/>
          <a-icon
            v-if="form.getFieldValue('httpKeys').length > 1"
            class="dynamic-delete-button"
            type="minus-circle-o"
            :disabled="form.getFieldValue('httpKeys').length === 1"
            @click="() => removeHttp(k)"/>
        </a-form-item>
        <a-form-item v-bind="formItemLayoutWithOutLabel">
          <a-button type="primary" style="width: 60%" @click="addHttp">
            <a-icon type="plus" /> 添加HTTP头
          </a-button>
        </a-form-item>
      </div>
      <a-form-item
        v-bind="formItemLayout"
        label="Body">
        <v-jsoneditor 
          style="margin-top: 12px;" 
          :options="options"
          v-model="response_body" />
      </a-form-item>
    </a-form>
  </div>
</template>
复制代码


<script>
import VJsoneditor from 'v-jsoneditor'
export default {
  name: 'mock-info',
  components: {
    VJsoneditor, // json编辑器
  },
  props: {
    row: Object, // 回填信息
  },
  data() {
    const formItemLayout = {
        labelCol: {
          span: 5
        },
        wrapperCol: {
          span: 18
        },
      };
    const formItemLayoutWithOutLabel = {
        wrapperCol: {
          span: 18, 
          offset: 5
        },
      };
    const options = {
        mainMenuBar: false,
        mode: 'code'
      };
    // 可以考虑后端返回,也允许用户自己添加
    const codes = [100, 101, 102, 200, 201, 202, 203, 204, 205, 206, 207, 208, 226, 300, 301, 302, 303, 304, 305, 307, 308, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 422, 423, 424, 426, 428, 429, 431, 500, 501, 502, 503, 504, 505, 506, 507, 508, 510, 511]
    // 可以考虑后端返回,也允许用户自己添加
    const http_headers = ['Accept', 'Accept-Charset', 'Accept-Encoding', 'Accept-Language', 'Accept-Datetime', 'Authorization', 'Cache-Control', 'Connection', 'Cookie', 'Content-Disposition', 'Content-Length', 'Content-MD5', 'Content-Type', 'Date', 'Expect', 'From', 'Host', 'If-Match', 'If-Modified-Since',
      'If-None-Match', 'If-Range', 'If-Unmodified-Since', 'Max-Forwards', 'Origin', 'Pragma', 'Proxy-Authorization', 'Range', 'Referer', 'TE', 'User-Agent', 'Upgrade', 'Via', 'Warning', 'X-Requested-With', 'DNT', 'X-Forwarded-For', 'X-Forwarded-Host', 'X-Forwarded-Proto', 'Front-End-Https', 'X-Http-Method-Override',
      'X-ATT-DeviceId', 'X-Wap-Profile', 'Proxy-Connection', 'X-UIDH', 'X-Csrf-Token']
    return {
      formItemLayout,
      formItemLayoutWithOutLabel,
      options,
      baseId: 0, // 基本信息的ID
      httpId: 0, // 响应信息得ID
      request_params: {}, // 请求参数
      response_body: {}, // 响应参数
      codes,
      http_headers,
      itemVal: ''
    };
  },
  beforeCreate() {
    // 创建form
    this.form = this.$form.createForm(this, { name: 'form' });
    this.form.getFieldDecorator('baseKeys', { initialValue: [0], preserve: true });
    this.form.getFieldDecorator('httpKeys', { initialValue: [0], preserve: true });
  },
  mounted() {
    let vm = this
    // 信息回填
    vm.form.setFieldsValue({
      name: vm.row.name,
      is_json: vm.row.is_json == '1' ? true : false, // 这里考虑'0','1','2'之类的
      http_code: vm.row.resp_code,
      delay_time: vm.row.delay || 0
    })
    if(vm.row.id) {
      vm.response_body = JSON.parse(vm.row.resp_body)
      vm.form.id = vm.row.id
      // 回填请求参数
      if(vm.row.is_json == '0') { // 非JSON
        vm.rollbackKeyValue(JSON.parse(vm.row.request_params), 'paramNames', 'paramValues', 'baseKeys', 'baseId')
      }
      if(vm.row.is_json == '1') { // JSON格式
        vm.request_params = JSON.parse(vm.row.request_params)
      }
      // 回填响应参数
      vm.rollbackKeyValue(JSON.parse(vm.row.resp_header), 'httpNames', 'httpValues', 'httpKeys', 'httpId')
    }
  },
  methods: {
    // 回填keyValues值
    rollbackKeyValue(objectData, names, values, keys, seq) {
      let vm = this
      let temp_names = [],
          temp_values = [],
          temp_keys = [];
      let objKeys = Object.keys(objectData)
      if(objKeys.length > 0) {
        objKeys.map((name, index) => {
          temp_names.push(name)
          temp_values.push(objectData[name])
          temp_keys.push(index)
          vm[seq] = index
        })
        // 回填
        vm.form.setFieldsValue({
          [keys]: temp_keys, // 这个要先出来,保证UI被渲染出来了
        })
        vm.$nextTick(() => { // nextTick保证dom被渲染好之后进行下一步操作
          vm.form.setFieldsValue({
            [names]: temp_names,
            [values]: temp_values
          })
        })
      }
    },
    // 移除参数
    removeParam(k) {
      const { form } = this;
      const baseKeys = form.getFieldValue('baseKeys');
      if (baseKeys.length === 1) {
        return;
      }
      form.setFieldsValue({
        baseKeys: baseKeys.filter(key => key !== k),
      });
    },
    // 移除http
    removeHttp(k) {
      const { form } = this;
      const httpKeys = form.getFieldValue('httpKeys');
      if (httpKeys.length === 1) {
        return;
      }
      form.setFieldsValue({
        httpKeys: httpKeys.filter(key => key !== k),
      });
    },
    // 添加参数
    addParam() {
      const { form } = this;
      const baseKeys = form.getFieldValue('baseKeys');
      const nextKeys = baseKeys.concat(++this.baseId);
      form.setFieldsValue({
        baseKeys: nextKeys,
      });
    },
    // 添加Http
    addHttp() {
      const { form } = this;
      const httpKeys = form.getFieldValue('httpKeys');
      const nextKeys = httpKeys.concat(++this.httpId);
      form.setFieldsValue({
        httpKeys: nextKeys,
      });
    }
  },
};
</script>
复制代码


<style lang="less">
.mock-info {
  .dynamic-delete-button {
    cursor: pointer;
    position: relative;
    top: 4px;
    font-size: 24px;
    color: #999;
    transition: all 0.3s;
  }
  .dynamic-delete-button:hover {
    color: #777;
  }
  .dynamic-delete-button[disabled] {
    cursor: not-allowed;
    opacity: 0.5;
  }
}
</style>
复制代码


嗯~这种实现的方式还是和舒服的,不用自己布局,不用自己再次思考逻辑;如果你想自己捣鼓一个,那你是真的闲,还不如花点时间捣鼓其他非编程的东西。


注意:能用react版本的ant design尽量用react版本的~


场景二


根据后台接口返回的字段来渲染。类型值对应不同的组件,如下:


  • 类型值1:单行文本组件
  • 类型值2:多行文本组件
  • 类型值3:单选组件
  • 类型值4:多选组件
  • 类型值5:文件上传组件


每种类型出现的次数是大于等于0,而且后端可配置必填或者非必填。嗯,下面实现它~


因为是移动端的业务,肯定是选UI框架帮我干活啊,这里我选了有赞的vant。用的还是vue去搭建工程,别问为啥不用react,公司给我时间,我就用react~这是业务线啊,想得倒是美,而且还是疫情期间,不压你时间就很好了。所以做完后,乖乖申请回去中台~


下面实现的思路,效果和关键代码~


  1. 动态组件,那么每个字段都要有一个字段标识该组件,这里后端没有配,那么我自己创建一个uuid(能叫得动后端,就叫后端配吧...)


<!-- 进行字段的遍历 -->
  <div v-for="(type, type_index) in alterFields">
    <!-- 单行文本和多行文本区域 -->
    <div class="advertise part" v-if="type.fieldType===1 || type.fieldType ===2">
      <!-- 单行文本内容 -->
      <!-- 多行文本内容 -->
    </div>
    <!-- 单选和多选区域 -->
    <div class="advertise part" v-if="type.fieldType===3 || type.fieldType ===4">
      <!-- 单选内容 -->
      <!-- 多选内容 -->
    </div>
    <!-- 资源上传的区域 -->
    <div class="advertise part" v-if="type.fieldType===5">
        <!--文件上传内容-->
    </div>
  </div>
复制代码


  1. 后端返回类型(优先)/前端写死类型(备选),对后端返回的动态数据进行遍历,以展示不同类型的组件

我这里前端写死了,蓝瘦香菇,三个字"人真懒"。


types: [{
        code: 1,
        text: '单行文本'
      }, {
        code: 2,
        text: '多行文本'
      }, {
        code: 3,
        text: '单选'
      }, {
        code: 4,
        text: '多选'
      }, {
        code: 5,
        text: '文件上传'
      }],
复制代码


  1. 编辑的时候,信息回填前要考虑动态数据时候已经发生改动(时刻以后端返回的动态数据为准来回填)


// 将返回的字段和编辑的字段进行配对,回填
let _alterFields = []
for (let i = 0; i < vm.alterFields.length; i++) {
  let _item = vm.alterFields[i]
  _alterFields.push(_item)
  for (let j = 0; j < vm.editFileds.length; j++) {
    if (_item.id === vm.editFileds[i].id) {
      // 替换值
      _alterFields.splice(i, 1, Object.assign(_item, {
        fieldValue: vm.editFileds[i].fieldValue,
        [_item.uuid]: vm.editFileds[i].fieldValue,
      }))
    }
  }
}
vm.alterFields = _alterFields
复制代码


  1. 前端限制文件上传的大小,有必要自己做什么压缩文件之类的骚操作,这里是内嵌到app里面的,app里面已经对图片处理。上传文件不要直接调公司的服务,直接调上传到云的操作就行,不然公司服务会崩溃的~


// 文件资源的限制
prompt_for_oversize () {
  this.$dialog({
    title: '提  示',
    text: '单个文件大小不应该大于10M',
    confirmText: '了解',
    showCancelBtn: false,
    confirm () { }
  })
}
复制代码


  1. 文件上传使用async await来操作,更加直观明了


realUploadFile (item) {
  let vm = this
  let temp_valueFiled = []
  let be_upload = false
  return new Promise(resolve => {
    // 上传到云
    let formData = new FormData();
    for (let i = 0; i < item[item.uuid].length; i++) {
      let row = item[item.uuid][i]
      if (row.fileName) { // 编辑的时候存在文件就不用再上传到服务器了
        temp_valueFiled.push(row)
        if (temp_valueFiled.length === item[item.uuid].length) { resolve(temp_valueFiled) }
      } else {
        be_upload = true
        console.log('row.file', row.file.size)
        formData.append("files", row.file);
      }
    }
    if (!be_upload) { // 不需要上传的时候直接返回
      return
    }
    vm.api.apply.uploadMultiFiles(formData).then(res => {
      console.log(res)
      if (res.code === '00000') {
        temp_valueFiled.push(...res.data)
        resolve(temp_valueFiled)
      } else {
        vm.$toast({ msg: res.message || '上传失败,请重试!' })
        vm.forbidden = false
      }
    })
  })
}
复制代码


  1. 对单选组件进行处理,非必填的状态下,要允许取消勾选


// 处理单选框(如果是非必填字段,允许用户取消)
handleRadio (type, type_index, item_title) { // type是整个项目,type_index是类型遍历的索引, item_title是选中项目的名称
  if (type.isRequired) { return } // 必选的单选框,啥都不做
  let vm = this
  let union = `${type['uuid']}_${item_title}` // 唯一的标识
  if (vm.radioSet.has(union)) { // 存在集合中
    vm.radioSet.delete(union)
    vm.alterFields.splice(type_index, 1, Object.assign(type, {
      [type.uuid]: ''
    }))
  } else {
    if (vm.radioSet.size > 0) {
      vm.radioSet.forEach(function (val) {
        if (val.indexOf(`${type['uuid']}_`) >= 0) {
          vm.radioSet.delete(val) // 移除当前组件的唯一标识的所有值
        }
      })
    }
    vm.radioSet.add(union) // 每个单选的组件只维护一个数据
  }
},
复制代码


...


效果如下:


image.png


相关文章
程序人生 - 疫情期间外出购物防护指南
程序人生 - 疫情期间外出购物防护指南
103 0
程序人生 - 疫情期间外出购物防护指南
|
安全
程序人生 - 防疫期间能不能点外卖
程序人生 - 防疫期间能不能点外卖
103 0
程序人生 - 防疫期间能不能点外卖
|
安全 5G 计算机视觉
顺风车下线325天后,滴滴向社会公布了整改进展
7月18日,滴滴出行在北京举办了媒体开放日,向全国媒体公布了滴滴顺风车的整改进度,基层产品经理到顺风车事业部总经理,以及滴滴柳青与程维等核心高管,悉数到场。滴滴顺风车事业部总经理张瑞说,“我的心情很复杂,忐忑不安”。
201 0
顺风车下线325天后,滴滴向社会公布了整改进展
|
供应链 双11
疫情期间物资告急,菜鸟为何成为全球抗疫救援运输主力
菜鸟网络开通“全球免费运输救援物资绿色通道”,是在1月25日,也是这一天,武汉封城。这条绿色通道,24小时接听,专人跟进,全球有效。
216 0
疫情期间物资告急,菜鸟为何成为全球抗疫救援运输主力
|
存储 Serverless 网络安全
疫情期间,如何远程办公?
因受到新型冠状病毒疫情的影响,如您需要了解远程办公协作系统/套件/架构/应用等相关问题,可参考以下解决方案进行处理。
1898 0
疫情期间,如何远程办公?
关于服务市场扶持期延长的通知
尊敬的合作伙伴,您好!      非常感谢大家对服务市场的关注和支持,为了更好地扶持服务商的成长,平台将加强扶持力度,特将《蚂蚁服务市场服务协议》第七条中约定的平台不参与分佣的扶持期延长至2019年12月31日。
323 12
|
数据采集 监控 数据可视化
同时间赛跑,数字化疫情防控“分秒必争”
简介: 在一场突如其来的新冠肺炎疫情面前,时间就是生命,时间就是战斗力。与抗击疫情的医生面对病毒的未知一样,阿里云的工程师们也要在不确定性中跟疫情争分夺秒。与疫情赛跑,与时间赛跑,先疫情一步,成为了每个阿里人笃定前行的力量。
同时间赛跑,数字化疫情防控“分秒必争”
|
供应链 安全 定位技术
疫情期间上班风险预估
目前抗疫到了关键时期,而来自各方面复工的呼声也不断涌出 这两天,甚至有朋友圈里的老板,认为感染的风险不过是千万分之几 作为上班族,最关心的也是自身的复工感染风险,毕竟每个人背后都是一个家庭,一人感染全家感染 所以,我以自己为例简单做了一个出行风险分析,希望对大家也有帮助 1.
1225 0
疫情期间上班风险预估
|
运维 关系型数据库 MySQL
疫情期间,遇到业务问题该怎么办?
因受到新型冠状病毒疫情的影响,如您在业务方面遇到相关问题,可参考以下解决方案进行处理。
1734 0
疫情期间,遇到业务问题该怎么办?