rocket-render:快速构建中后台系统

大家好,我是河畔一角,今天给大家介绍一款开源的lowcode插件:rocket-render。我把它定义为火箭引擎,主要基于Vue2+ElementUI封装,使用json快速构建中后台页面。

rocket-render开发背景

前端是一个很有意思的职业,有着UI的既视感:所见即所得;在前端开发领域里面,中后台算是一股清流;做多了以后,基本上千篇一律;它很容易做到复用,又很难做到完全通用。我个人做过很多的后台系统,根据自身的经验结合实战开源了一套rocket-render插件,它不能解决所有问题,它目前也主要是解决简单的重复性问题。其实市面上有很多类似这方面的解决方案了,我呢,只是给大家多一种选择。

rocket-render能解决什么问题

  1. 开发表单、表格、详情等大量重复代码问题。
  2. 形成标准化的后台方案,避免参差不齐。

rocket-render提供哪些能力

  1. 快速开发查询表单,支持多种模式。
  2. 快速开发常规表格,封装很多快捷功能,支持Element所有表格功能。
  3. 快速开发复杂表单,支持事件联动、嵌套、自定义等。
  4. 快速开发详情页面,支持官方所有功能,同时支持快捷功能。

rocket-render提供哪些组件

  1. SearchForm主要用于查询表单
  2. RokcetForm主要用于复杂页面表单
  3. RocketTable主要用于构建表格
  4. RocketDesc主要用于构建详情页面

rocket-render相关文档

  1. NPM地址:rocket-render
  2. Github: rocket-render
  3. 开发文档:rocket-doc
  4. 线上预览:rocket-render

rocket-render使用效果预览

  1. 基本的查询表单

  1. 拥有丰富的表格功能

  1. 快速搭建详情页面

rocket-render开发介绍

安装使用

  1. 安装插件
yarn add rocket-render -S
# 或者
npm install rocket-render -S
复制代码
  1. 组件注册
// 导入包
import RocketRender from 'rocket-render'
// 导入样式
import 'rocket-render/lib/rocket-render.css'
Vue.use(RocketRender)
复制代码

查询表单介绍

目前支持三种模式的表单:行内表单、栅格表单、flex表单。

  1. 栅格表单

所谓栅格表单,其实就是栅格布局。根据屏幕分辨率动态控制,1920以上每行4列,1200以上每行3列,1200以下每行2列。

<search-form inline="grid" :json="form" :model.sync="queryForm" @handleQuery="getList"/>

<script>
  export default {
    data() {
      return {
        queryForm: {},
        form: [
            {
                type: "input",
                model: "user_name",
                label: "用户",
                placeholder: "请输入用户名称",
            },
            {
                type: "switch",
                model: "open",
                label: "状态"
            }
        ]
      }
    },
    methods:{
      getList(){}
    }
  };
</script>
复制代码
  1. Flex表单

flex表单为左右结构,左边依然是行内布局,相比于行内表单,flex只是把查询和重置按钮放到了右边。

<search-form inline="flex" :json="form" :model.sync="queryForm" @handleQuery="getList"/>

<script>
  export default {
    data() {
      return {
        queryForm: {},
        form: [
            {
                type: "input",
                model: "user_name",
                label: "用户",
                placeholder: "请输入用户名称",
            },
            {
                type: "switch",
                model: "open",
                label: "状态"
            }
        ]
      }
    },
    methods:{
      getList(){}
    }
  };
</script>
复制代码
  1. 行内表单

行内表单表现形式为所有表单控件排成一行,超出自动换行。

<search-form inline="inline" :json="form" :model.sync="queryForm" @handleQuery="getList"/>

<script>
  export default {
    data() {
      return {
        queryForm: {},
        form: [
            {
                type: "input",
                model: "user_name",
                label: "用户",
                placeholder: "请输入用户名称",
            },
            {
                type: "switch",
                model: "open",
                label: "状态"
            }
        ]
      }
    },
    methods:{
      getList(){}
    }
  };
</script>
复制代码

复杂表单介绍

rocket-form主要用来开发复杂表单,支持单列,多列,事件联动等

  1. 基本用法

一般我们遇到的就是垂直表单,rocket-form支持所有的表单组件,同时支持label、button在表单中的渲染

<rocket-form
  ref="rocketForm"
  :json="dialogConfig"
  v-model="rocketForm"
  @handleSubmit="handleSubmit"
  @handleClose="handleClose"
></rocket-form>
<script>
  export default {
    data() {
      return {
        dialogConfig: {
          showFooter: true,//自带footer是否显示
          // 布局方式,同element
          layout: {
            gutter: 15,
          },
          // 表单列表
          formList: [
            {
              type: 'text',
              label: '用户名称',
              placeholder: '请输入用户名称',
              model: 'cname',
              required: true,
              width: '80%',
              tips: {
                align: 'right',
                text: '长度最大6位',
              },
              rules: [
                {
                  required: true,
                  message: '请输入用户名称',
                  trigger: ['change', 'blur'],
                },
                {
                  pattern: /^[a-zA-Z0-9_\u4e00-\u9fa5]{1,10}$/,
                  message: '1-10个字符,支持中文、字母、数字和下划线',
                  trigger: ['change', 'blur'],
                },
              ],
            },
            {
              type: 'select',
              label: '用户状态',
              placeholder: '请选择用户状态',
              model: 'user_status',
              tips: '至少选择一项',
              options: [
                { label: '已注销', value: 1 },
                { label: '老用户', value: 2 },
                { label: '新用户', value: 3 },
              ],
            },
            {
              type: 'radio',
              label: '使用状态',
              placeholder: '请选择使用状态',
              model: 'use_status',
              options: [
                { label: '在线', value: 1 },
                { label: '离线', value: 2 },
              ],
            },
            {
              type: 'switch',
              label: '启用状态',
              model: 'status',
            },
            {
              type: 'date',
              label: '注册日期',
              model: 'register_date',
              shortcuts: true,
            },
            {
              type: 'checkbox',
              label: '兴趣',
              model: 'intrest',
              options: [
                { label: '游泳', value: 1 },
                { label: '打乒乓球', value: 2 },
                { label: '台球', value: 3 },
                { label: '篮球', value: 4 },
              ],
            },
            {
              type: 'textarea',
              label: '用户描述',
              placeholder: '请输入用户描述',
              model: 'remark',
              rows: 4,
            },
          ],
        },
        // v-model对象,可初始化值
        rocketForm: {
          cname: 'jack',
          intrest: [1, 2],
        },
      };
    },
    methods: {
      async handleSubmit() {
        // 接口提交,大家可以修改为自己的调用方式
        const res = await this.$request.get('/user/submit', this.rocketForm);
        if (res) {
          this.$message.success('操作成功');
          // 如果需要,可对表单进行重置
          this.$refs['rocketForm'].handleReset();
          // 关闭页面
          this.handleClose();
        }
      },
      getSelectList(val, values, model) {
        this.$request.get('/select/list').then((res) => {
          this.dialogConfig.formList[2].list[1].options = res;
        });
      },
      // 关闭弹窗
      handleClose() {},
    },
  };
</script>
复制代码
  1. 嵌套表单

一行内可以嵌套多个表单

<rocket-form
  :json="dialogConfig"
  v-model="rocketForm"
  @handleSubmit="handleSubmit"
  @handleClose="handleClose"
></rocket-form>
<script>
  export default {
    data() {
      return {
        dialogConfig: {
          showFooter: true,
          layout: {
            gutter: 15,
          },
          formList: [
            {
              type: 'inline',
              label: '下拉组合',
              list: [
                {
                  type: 'select',
                  placeholder: '请选择省份',
                  model: 'user_province',
                  change: this.getSelectList,
                  options: [
                    {
                      label: '湖北省',
                      value: 10001,
                    },
                    {
                      label: '上海市',
                      value: 20001,
                    },
                  ],
                },
                {
                  type: 'select',
                  placeholder: '请选择城市',
                  model: 'user_city',
                  options: [
                    {
                      label: '武汉市',
                      value: 10001,
                    },
                    {
                      label: '上海市',
                      value: 20001,
                    },
                  ],
                },
              ],
            },
            {
              type: 'inline',
              label: '随意组合',
              list: [
                {
                  type: 'radio',
                  label: '',
                  placeholder: '请选择使用状态',
                  model: 'use_status',
                  options: [
                    { label: '在线', value: 1 },
                    { label: '离线', value: 2 },
                  ],
                },
                {
                  type: 'switch',
                  label: '启用状态',
                  model: 'status',
                },
              ],
            },
            {
              type: 'inline',
              label: '概率配置',
              list: [
                {
                  span: 8,
                  type: 'select',
                  placeholder: '请选择概率配置',
                  model: 'a3',
                  labelWidth: '0',
                  options: [
                    { label: '10%', value: 1 },
                    { label: '20%', value: 2 },
                    { label: '30%', value: 3 },
                    { label: '40%', value: 4 },
                  ],
                },
                {
                  span: 8,
                  type: 'input',
                  placeholder: '请输入概率配置',
                  model: 'a4',
                  append: '%',
                  labelWidth: '0',
                },
                {
                  span: 3,
                  type: 'button',
                  button: {
                    type: 'text',
                    text: '按钮',
                  },
                  labelWidth: '0',
                },
                {
                  span: 5,
                  type: 'label',
                  text: '普通文本',
                },
              ],
            },
            {
              type: 'group',
              label: '分组 - 组合',
              list: [
                [
                  {
                    span: 8,
                    type: 'input',
                    placeholder: '请输入抽取次数',
                    label: '抽取',
                    labelWidth: '80px',
                    model: 'a7',
                    rules: [
                      {
                        required: true,
                        message: '请输入抽取次数',
                        trigger: 'blur',
                      },
                    ],
                    label1: '次可开启宝箱1',
                  },
                  {
                    span: 8,
                    type: 'input',
                    placeholder: '请输入奖励金币',
                    label: '奖励金币',
                    model: 'a8',
                    rules: [
                      {
                        required: true,
                        message: '请输入奖励金币',
                        trigger: 'blur',
                      },
                    ],
                  },
                  {
                    span: 3,
                    type: 'button',
                    button: {
                      type: 'primary',
                      round: true,
                      icon: 'el-icon-plus',
                      text: '按钮',
                    },
                    click(value, config) {
                      // 可监听点击事件
                      console.log(value, config);
                    },
                    labelWidth: '0',
                  },
                ],
              ],
            },
          ],
        },
        // v-model对象,可初始化值
        rocketForm: {
          cname: 'jack',
          intrest: [1, 2],
        },
      };
    },
    methods: {
      async handleSubmit() { },
      getSelectList(val, values, model) { },
      handleClose() { }
    },
  };
</script>
复制代码

表格介绍

rocket-table支持el-table的所有功能,属性和事件均透传,同时添加很多方便使用的快捷功能

支持功能如下:

  1. 基础表格
  2. 表格分页(可控制隐藏,默认显示)
  3. 工具条(刷新、表格密度、列设置、全屏)
  4. 单列可点击、多列可点击
  5. 多个链接(link)渲染、图片渲染、url渲染、badge状态渲染
  6. 特殊数据格式化(formatter)
  7. 操作区域权限控制(创建、编辑、删除)
  8. 表格列排序、表头跨列、数据跨行
  9. 通过v-bind=" a t t r s " v o n = " attrs"和v-on=" listners"保留大部分原生属性和事件
  10. 支持表格索引列、支持表格多选功能
  11. 支持表格自定义列

基本用法

<search-form  :json="form" :model.sync="queryForm" @handleQuery="getTableList" />
<rocket-table
    :column.sync="columns"
    :data="list"
    :pagination.sync="pagination"
    @handleChange="getTableList"
    @handleAction="handleAction"
>
  <template v-slot:title>用户列表</template>
</rocket-table>
<script>
export default {
    data () {
        return {
            // 保存查询条件
            queryForm: {},
            form: [
                {
                    type: 'text',
                    model: 'user_name',
                    label: '用户',
                    placeholder: '请输入用户名称',
                }
            ],
            columns: [
                {
                    prop: 'selection',
                    type: 'selection',
                    label: '选框',
                },
                {
                    prop: 'uid',
                    label: '用户ID',
                    align: 'left',
                    type: 'click'
                },
                {
                    prop: 'user_img',
                    label: '头像',
                    type: 'image',
                    image: {
                        type: 'single'
                    }
                },
                {
                    prop: 'use_status',
                    label: '当前状态',
                    formatter (row) {
                        return {
                        1: '在线',
                        2: '离线',
                        }[row.use_status]
                    },
                },
                {
                    prop: 'user_status_name',
                    label: '用户状态',
                    type:'badge',
                    badge:{
                        id: "user_status",//渲染的字段
                        state: {
                            1: "warning",//设置颜色
                            2: "primary",
                            3: "danger",
                            4: "info"
                        },
                    }
                },
                {
                    prop: 'register_date',
                    label: '注册时间',
                }
            ],
            list: [],
            // 分页对象,目前为固定结构
            pagination: {
                pageNum: 1,
                pageSize: 20,
                total: 0,
            }
        }
    },
    mounted () {
        this.getTableList()
    },
    methods: {
        // 首页列表查询,page为子组件传递的页码,默认为1
        getTableList (pageNum = 1) {
            this.pagination.pageNum = pageNum
            const data = {
                ...this.queryForm, // 查询表单数据
                ...this.pagination, // 默认分页数据
            }
            this.$request.get('/basic/list',data).then((res) => {
                this.list = res.list.slice(0,5)
                this.pagination.total = res.total
            })
        }
    }
}
</script>
复制代码

列点击、操作按钮列,图片渲染

支持单元格点击、操作按钮列、图片、链接渲染,简单的属性配置即可实现复杂的功能

<rocket-table
    :column.sync="columns"
    :data="list"
    :pagination.sync="pagination"
    @handleChange="getTableList"
    @handleAction="handleAction"
    @handleCellClick="handleCellClick"
    @selection-change="handleSelectionChange"
>
    <template v-slot:title>用户列表</template>
    <template v-slot:action>
    <el-button type="primary" @click="showModal1 = true"
        >操作按钮</el-button
    >
    </template>
</rocket-table>
<script>
export default {
    data () {
        return {
            columns: [
                {
                    prop: 'selection',
                    type: 'selection',
                    label: '选框',
                },
                {
                    prop: 'uid',
                    label: '用户ID',
                    align: 'left',
                    type: 'click'
                },
                {
                    prop: 'user_img',
                    label: '头像',
                    type: 'image',
                    image: {
                        type: 'single'
                    }
                }
            ],
            list: [],
            // 分页对象
            pagination: {
                pageNum: 1,
                pageSize: 20,
                total: 0,
            }
        }
    },
    mounted () {
        this.getTableList()
    },
    methods: {
        // 首页列表查询,page为子组件传递的页码,默认为1
        getTableList (pageNum = 1) {
            this.pagination.pageNum = pageNum
            const data = {
                ...this.queryForm, // 查询表单数据
                ...this.pagination, // 默认分页数据
            }
            this.$request.get('/basic/list',data).then((res) => {
                this.list = res.list.slice(0,5)
                this.pagination.total = res.total
            })
        },
        // 操作项点击,根据按钮索引开发不同业务逻辑
        handleAction({ index, row, type }){
            if(index === 0){
                // 点击了第一个操作按钮
            }else if(index === 1){
                // 点击了第二个操作按钮
            }
            // 也可根据type进行列判断,代替索引
            if(type === 'user_state'){
                // 点击了用户状态按钮
            }
        },
        /**
         * 列点击
         * 1. 只有其中一列可点击,通常只用row就够了,不需要根据prop做判断
         * 2. 有多列可点击,根据prop判断是哪一列被触发了
         * 3. 某一列有多个点击按钮,点击按钮的时候,会把对应的值回传回来(link)
        */
        handleCellClick({ row, prop, link }){
            // 如果是多个列都绑定了click事件,可根据prop来区分是哪一列
            if(prop === 'uid'){
                this.$message.success('点击了用户ID')
            }
        },
        // 列多选
        handleSelectionChange (rows) {
            this.$message.success('勾选项id为' + rows.map(item => item.id))
        }
    },
}
</script>
复制代码

跨行用法

支持列自定义、跨行跨列

<rocket-table
    :column.sync="columns"
    :data="list"
>
</rocket-table>
<script>
export default {
    data(){
        return {
            columns:[
                {
                    prop: 'user_info',
                    label: '用户信息',
                    align: 'center',
                    span: [ // 多级表头
                        {
                            prop: "cname",
                            label: "用户名称",// 普通列渲染
                            showOverflowTooltip:true // true/false/不填,默认为true
                        },
                        {
                            prop: "intrest_name",
                            label: "兴趣",
                            width: 70,// 可调整列宽度
                        },
                    ]
                },
                {
                    prop: "uid",
                    label: "用户ID",
                    type: 'label'
                }
            ],
            list:[],// 表格渲染数据
            pagination:{ page:1 }
        }
    },
     mounted () {
        this.getTableList()
    },
    methods: {
        // 首页列表查询,page为子组件传递的页码,默认为1
        getTableList (page = 1) {
            this.pagination.page = page
            const data = {
                ...this.queryForm, // 查询表单数据
                ...this.pagination, // 默认分页数据
            }
            this.$request.get('/basic/list',data).then((res) => {
                this.list = res.list.slice(0,5)
            })
        }
    }
}
</script>
复制代码

详情组件介绍

详情页面也是中后台经常使用的一个功能,如果用原生开发,要复制太多的标签组件,使用json开发反而最容易,整个用法同el-descriptions

基本用法 - 不带边框

<rocket-desc :json="json1" :values="values1" />

<script>
  export default {
    data() {
      return {
        json1: {
          title: '基础描述-1',
          list: [
            {
              label: '用户名称',
              prop: 'userName',
            },
            {
              label: '用户性别',
              prop: 'userSex',
            },
            {
              label: '用户年龄',
              prop: 'userName',
            },
            {
              label: '用户职业',
              prop: 'userJob',
            },
            {
              label: '用户年薪',
              prop: 'userSalary',
            },
          ],
        },
        values1: {
          userName: '杰克',
          userAge: 30,
          userSex: '未知',
          userJob: '前端工程师',
          userSalary: '20万',
        },
      };
    },
  };
</script>
复制代码

基本用法 - 带边框,每行 2 列

<rocket-desc :json="json2" :values="values2" />

<script>
  export default {
    data() {
      return {
        json2: {
          title: '基础描述-2',
          border: true,
          column: 2,
          list: [
            {
              label: '用户名称',
              prop: 'userName',
            },
            {
              label: '用户性别',
              prop: 'userSex',
            },
            {
              label: '用户年龄',
              prop: 'userName',
            },
            {
              label: '用户职业',
              prop: 'userJob',
            },
            {
              label: '用户年薪',
              prop: 'userSalary',
            },
          ],
        },
        values2: {
          userName: '杰克',
          userAge: 30,
          userSex: '未知',
          userJob: '前端工程师',
          userSalary: '20万',
        },
      };
    },
  };
</script>
复制代码

基本用法 - 垂直分布

<rocket-desc :json="json3" :values="values3" />

<script>
  export default {
    data() {
      return {
        json3: {
          title: '基础描述-3',
          border: true,
          column: 4,
          direction: 'vertical',
          extra: '看我',
          list: [
            {
              label: '用户名称',
              prop: 'userName',
            },
            {
              label: '用户性别',
              prop: 'userSex',
              formatter({ userSex }) {
                return userSex == '未知' ? '泰国人妖' : userSex;
              },
            },
            {
              label: '用户年龄',
              prop: 'userName',
            },
            {
              label: '用户职业',
              prop: 'userJob',
            },
            {
              label: '用户年薪',
              prop: 'userSalary',
            },
            {
              label: '用户地址',
              prop: 'address',
            },
          ],
        },
        values3: {
          userName: '杰克',
          userAge: 30,
          userSex: '未知',
          userJob: '前端工程师',
          userSalary: '20万',
          address: '上海市浦东新区东方明珠',
        },
      };
    },
  };
</script>
复制代码

基本用法 - 弹框中显示

<el-button @click="showVisible = true" type="primary"> 弹框中显示 </el-button>
<el-dialog
  title="弹框描述"
  :visible.sync="showVisible"
  width="40%"
  :before-close="handleClose"
>
  <rocket-desc :json="json2" :values="values" class="mt20" />
  <rocket-desc :json="json4" :values="values" class="mt20" />
  <span slot="footer" class="dialog-footer">
    <el-button @click="handleClose">取 消</el-button>
    <el-button type="primary" @click="handleClose">确定</el-button>
  </span>
</el-dialog>
<rocket-desc :json="json3" :values="values3" />

<script>
  export default {
    data() {
      return {
        showVisible: false,
        json2: {
          title: '基础描述-2',
          border: true,
          column: 2,
          list: [
            {
              label: '用户名称',
              prop: 'userName',
            },
            {
              label: '用户性别',
              prop: 'userSex',
            },
            {
              label: '用户年龄',
              prop: 'userName',
            },
            {
              label: '用户职业',
              prop: 'userJob',
            },
            {
              label: '用户年薪',
              prop: 'userSalary',
            },
            {
              label: '用户地址',
              prop: 'address',
            },
          ],
        },
        json4: {
          title: '基础描述-4',
          border: true,
          column: 1,
          list: [
            {
              label: '用户名称',
              prop: 'userName',
            },
            {
              label: '用户性别',
              prop: 'userSex',
            },
            {
              label: '用户年龄',
              prop: 'userName',
            },
            {
              label: '用户职业',
              prop: 'userJob',
            },
            {
              label: '用户年薪',
              prop: 'userSalary',
            },
            {
              label: '用户地址',
              prop: 'address',
            },
          ],
        },
        values: {
          userName: '杰克',
          userAge: 30,
          userSex: '未知',
          userJob: '前端工程师',
          userSalary: '20万',
          address: '上海市浦东新区东方明珠',
        },
      };
    },
    methods: {
      handleClose() {
        this.showVisible = false;
      },
    },
  };
</script>
复制代码

基本用法 - 自定义标题、label 和 value

<rocket-desc :json="json2" :values="values" class="mt20">
  <template slot="title">
    <el-button type="primary" size="small">自定义标题</el-button>
  </template>
  <template slot="extra">
    <el-button type="primary" size="small">右上角自定义</el-button>
  </template>
  <template slot="userName">
    <i class="el-icon-user"></i>
    {{ values.userName }}
  </template>
  <template slot="userSex">
    <el-tag>{{ values.userSex }}</el-tag>
  </template>
</rocket-desc>
<el-tabs v-model="activeType" class="mt20">
  <el-tab-pane label="注册信息" name="1">
    <rocket-desc :json="json4" :values="values" />
  </el-tab-pane>
  <el-tab-pane label="认证信息" name="2">
    <rocket-desc :json="json4" :values="values" />
  </el-tab-pane>
  <el-tab-pane label="补充信息" name="3">
    <rocket-desc :json="json4" :values="values" />
  </el-tab-pane>
</el-tabs>
<script>
  export default {
    data() {
      return {
        activeType: '1',
        showVisible: false,
        json2: {
          title: '标题自定义插槽',
          border: true,
          type: 'slot',
          list: [
            {
              label: '用户名称',
              prop: 'userName',
              type: 'slot',
              slotLabelName: 'userName',
            },
            {
              label: '用户性别',
              prop: 'userSex',
              type: 'slot',
              slotValueName: 'userSex',
            },
            {
              label: '用户年龄',
              prop: 'userName',
            },
            {
              label: '用户职业',
              prop: 'userJob',
            },
            {
              label: '用户年薪',
              prop: 'userSalary',
            },
            {
              label: '用户地址',
              prop: 'address',
            },
          ],
        },
        json4: {
          border: true,
          list: [
            {
              label: '用户名称',
              prop: 'userName',
            },
            {
              label: '用户性别',
              prop: 'userSex',
            },
            {
              label: '用户年龄',
              prop: 'userName',
            },
            {
              label: '用户职业',
              prop: 'userJob',
            },
            {
              label: '用户年薪',
              prop: 'userSalary',
            },
            {
              label: '用户地址',
              prop: 'address',
            },
          ],
        },
        values: {
          userName: '杰克',
          userAge: 30,
          userSex: '未知',
          userJob: '前端工程师',
          userSalary: '20万',
          address: '上海市浦东新区东方明珠',
        },
      };
    },
    methods: {
      handleClose() {
        this.showVisible = false;
      },
    },
  };
</script>
复制代码

rocket-desc组件使用起来跟表格类似,支持formatter格式化。

以上就是整个rocket-render的介绍,如果大家有中后台的系统开发需求,我相信rocket-render一定能够帮到你,如果系统有不合理的地方,也欢迎大家指正。

猜你喜欢

转载自juejin.im/post/7033022685404020773