# 组件扩展

IDE表单开发页面组件可使用组件开发框架进行自定义开发。

# 流程说明

# 配置说明

层次结构如下

# 1.设计组件页面

主要分为三个大部分:组件选择区,表单编辑区,组件配置区

上传组件后,打开组件选择区的扩展组件界面,拖拽对应扩展组件到表单编辑区,添加成功后可看到扩展组件页面

# 2.属性面板(组件配置区)

主要分为两部分:通用组件配置区和扩展组件配置区

通用组件配置区

  • 基础:进行基础组件配置,如绑定字段、标题展示
  • 验证:设置组件绑定值的校验
  • 高级:进行组件扩展配置,如事件绑定,配置扩展属性
  • 样式:调整组件基本样式

扩展组件配置区

  • 扩展:扩展组件私有配置项

可在config.js中extConfig下配置组件单独使用的参数

# 3.设置状态

在表单编辑区中,鼠标悬停在组件上,右上角会出现配置按钮,点击设置状态图标进行状态配置

# 4.PC端配置

视图默认展示绑定的数据,如需设置特定展示内容,如图片,需要在primeton-form-designer项目src/views/index/base.js中单独配置

# 5.移动端配置

移动端配置同PC端一致,不同点为开发文件为mobile.vue,并且默认使用vant ui

# 5.子表格配置

单独配置子表格时可以使用isInChildren进行判断


props: {
  isInChildren:{
    default:false,
  },
}

# 6.组件数据

组件内部可直接使用参数如下


  props: {
    value:{
      type: String | Number | Object | Array,
    },
    mode: { // 编辑态: edit, 查看态:view , 用于在子表格内切换状态
      default: 'edit'
    },
    entityModel:{ // 如果组件绑定了一个实体, 则该属性会传入实体的数据
      default:()=>{}
    },
    readonly: {
      default:false
    },
    disabled: {
      default:false
    },
    settings: {
    type: Object,
    default: () => {},
    },
    icon:'',
    viewId: {},
    viewCode: {
      default: "view",
    },
  },


# 开发基础

# 1.创建开发项目

  • build/mfp.config.js配置打包文件的名字

注意appName唯一不可重复

  • src/components 此文件下新建扩展组件文件夹

  • 扩展组件文件夹下结构

    1. config.vue 属性配置页面

    1. config.js 组件模型。PC端和移动端均可使用,通过props:['activeData']使用
    2. pc.vue pc端渲染
    3. mobile.vue 移动端渲染
  • src/doc 组件说明文档,文档名同组件config.vue中tag。注意:请确保命名不会重复!

  • src/icons/svg 组件图标,图标名同组件config.vue中tagIcon。注意:请确保命名不会重复!

# 2.运行方法

  • 安装依赖 npm install
  • 运行项目 npm run dev
  • 打包项目 npm run build:prod:zip

# 3.开发调试

  • 在组件库上传扩展组件基础开发的zip文件,确保组件库存在扩展组件信息

  • 修改webpack.dev.js中publicPath,publicPath与mfp.config.js中appName一致

  • 使用代理(如nginx)本地扩展组件项目,代理地址为build/mfp.config.js中appName

location /pmSign{
  proxy_pass http://localhost:8080;
}

  • 修改build\plugins\components-plugin.js

window:

class ComponentsPlugin {
  apply(compiler) {
    compiler.hooks.emit.tap("Components Plugin", (compilation) => {
      const outputPath = compiler.path || compilation.options.output.path;
      const jsonFile = outputPath + "\\components.json";
      
      const content = JSON.stringify(configs);
      if (!fs.existsSync(outputPath)) {
        fs.mkdirSync(outputPath, { recursive: true }); 
      }
      fs.writeFileSync(jsonFile, content, {
        encoding: "utf8",
        flag: "w",
      });
    
    });
  }
}

mac:

class ComponentsPlugin {
  apply(compiler) {
    compiler.hooks.emit.tap("Components Plugin", (compilation) => {
      const outputPath = compiler.path || compilation.options.output.path;
      const jsonFile = outputPath + "/components.json";
      
      const content = JSON.stringify(configs);
      if (!fs.existsSync(outputPath)) {
        fs.mkdirSync(outputPath, { recursive: true }); 
      }
      fs.writeFileSync(jsonFile, content, {
        encoding: "utf8",
        flag: "w",
      });
    
    });
  }
}
  • 打开调试开关,打开后需刷新网页

# 开发一个基础input组件

# 1.进行组件基本配置

pc.vue


<template>
  <div>开发一个基础input组件</div>
</template>
<script>
export default {
  name: "myInput",// 与config.js中tag一致
  props: {
    value:{
      type: String | Number | Object | Array,
    },
    mode: { // 编辑态: edit, 查看态:view , 用于在子表格内切换状态
      default: 'edit'
    },
    entityModel:{ // 如果组件绑定了一个实体, 则该属性会传入实体的数据
      default:()=>{}
    },
    readonly: {
      default:false
    },
    disabled: {
      default:false
    },
    settings: {
    type: Object,
    default: () => {},
    },
    icon:'',
    viewId: {},
    viewCode: {
      default: "view",
    },
  },
};
</script>


mobile.vue


<template>
  <div>开发一个基础input组件(移动版)</div>
</template>
<script>
export default {
  name: "myInput",// 与config.js中tag一致
  props: {
    value:{
      type: String | Number | Object | Array,
    },
    mode: { // 编辑态: edit, 查看态:view , 用于在子表格内切换状态
      default: 'edit'
    },
    entityModel:{ // 如果组件绑定了一个实体, 则该属性会传入实体的数据
      default:()=>{}
    },
    readonly: {
      default:false
    },
    disabled: {
      default:false
    },
    settings: {
    type: Object,
    default: () => {},
    },
    icon:'',
    viewId: {},
    viewCode: {
      default: "view",
    },
    activeData: {},// 扩展属性传值
  },
};
</script>


config.vue


<template>
  <div>
    <el-form-item label="扩展信息配置">
      <el-input v-model="activeData.extConfig.text"></el-input>
    </el-form-item>
  </div>
</template>
<script>
export default {
    name:'myInput-config',
    props:['activeData'],
    data(){
      return {
      }
    },
    computed:{
       
    },
    watch:{
     
    },
    methods: {
   
    },
}
</script>


config.js


module.exports = {
    __config__: {
      label: 'myInput',
      tag: 'myInput',
      tagIcon: 'myInput',
      defaultValue: { value: null, code: '', type: 'const', prop: '' },
      span: 24,
      showLabel: true,
      labelWidth: null,
      layout: 'defaultItem', // defaultItem-默认布局,同系统中布局组件配置一致,colFormItem-Form布局,同系统中高级组件配置一致
      required: true,
      regList: [],
    },
    style: {width: '100%'},
    tip: '',
    disabled: false,
    extConfig: {
      text:''
      // 所有扩展属性都写在这里
    },
  }


mfp.config.js


const devMode = process.env.NODE_ENV === 'development';
const appName = 'myExample';//微前端应用名称
module.exports = {
  name: appName,
  shared:{
    vue: { singleton: true },
  },
  filename: `remoteEntry.js`,//微应用入口,不建议修改
  exposes: { // 对外暴露的模块(页面)
    './mobile_entry': './src/mobile_config.js',// 配置模块
    './entry': './src/config.js',// 配置模块
    './store': './src/store/index.js', // 默认将子应用 store 导出,供base应用注册
  },
  remotes: {
    base: 'base@/remoteEntry.js'
  },
}


说明文档

组件图标

# 2.第一次打包

运行build:prod:zip,获得myExample.zip

# 3.上传组件

打包后的zip文件上传afcenter 的组件库

添加组件,测试组件是否添加成功

# 4.本地调试

webpack.dev.js


  devServer: {
    open: false,
    hot: true,
    port: 9006,
    proxy: {
      // 如果开发环境中有跨域问题,在这里配置代理
    },
    headers:{
      'Access-Control-Allow-Origin':'*'
    },
    devMiddleware: {
      index: true,
      mimeTypes: { phtml: 'text/html' },
      publicPath: '/myExample', //开发期增加上下文路径
      serverSideRender: true,
      writeToDisk: false,
    },
    client: {
      logging: 'error',
      overlay: {
        errors: true,
        warnings: false
      }
    },
    // stats: "minimal",
  },


nginx


location /myExample{
  proxy_pass http://localhost:9006;
}

运行本地文件

打开本地调试,刷新页面,检查是否成功连接本地组件扩展项目

成功连接本地组件扩展项目后,可进行本地开发。本地项目更改保存后会实时更新到表单。

完整代码


// pc.vue


<template>
  <div>
    <el-input v-model="value" placeholder="请输入内容"></el-input>
  </div>
</template>
  <script>
export default {
  name: "myInput",
  props: {
    value:{
      type: String | Number | Object | Array,
    },
    mode: { // 编辑态: edit, 查看态:view , 用于在子表格内切换状态
      default: 'edit'
    },
    entityModel:{ // 如果组件绑定了一个实体, 则该属性会传入实体的数据
      default:()=>{}
    },
    readonly: {
      default:false
    },
    disabled: {
      default:false
    },
    settings: {
    type: Object,
    default: () => {},
    },
    icon:'',
    viewId: {},
    viewCode: {
      default: "view",
    },
  },
};
</script>


// mobile.vue


<template>
  <div>
    <van-field v-model="value" label="" placeholder="请输入用户名(移动端)" />
  </div>
</template>
  <script>
export default {
  name: "myInput",
  props: {
    value:{
      type: String | Number | Object | Array,
    },
    mode: { // 编辑态: edit, 查看态:view , 用于在子表格内切换状态
      default: 'edit'
    },
    entityModel:{ // 如果组件绑定了一个实体, 则该属性会传入实体的数据
      default:()=>{}
    },
    readonly: {
      default:false
    },
    disabled: {
      default:false
    },
    settings: {
    type: Object,
    default: () => {},
    },
    icon:'',
    viewId: {},
    viewCode: {
      default: "view",
    },
  },
};
</script>


// config.js


module.exports = {
    __config__: {
      label: 'myInput',
      tag: 'myInput',
      tagIcon: 'myInput',
      defaultValue: { value: null, code: '', type: 'const', prop: '' },
      span: 24,
      showLabel: true,
      labelWidth: null,
      layout: 'colFormItem', // defaultItem-默认布局,同系统中布局组件配置一致,colFormItem-Form布局,同系统中高级组件配置一致
      required: true,
      regList: [],
      // viewId: null, //视图配置项
      // viewCode: 'view', //视图配置项
    },
    style: { width: '100%' },
    tip: '',
    disabled: false,
    extConfig: {
      // 所有扩展属性都写在这里
    },
  }


# 5.最终打包

运行build:prod:zip

# 6.上传调试后组件

上传最新的组件zip文件

# 7.验证组件

关掉本地调试,查看组件是否正常运行

重新上传后,组件未自动更新,请在扩展组件配置界面删除旧组件,重新添加组件

PC端

移动端

  • 如修改版本后,组件未更新,请删除所有数据重新配置

# 扩展一个三方组件

以引用高德地图为例。

# 1.安装官方提供的loader

npm install @amap/amap-jsapi-loader --save 

# 2.基本配置

需要在前端介质 app-config.json 中配置

"amap": {
    "key": "",
    "securityJsCode": "",
    "webServerKey": ""
  }

变量说明:

  • key:高德地址开放平台的https://console.amap.com/ 中我的应用中配置 Web 端(JS API)的 key
  • securityJsCode:我的应用中配置 Web 端(JS API)的安全密钥
  • webServerKey:我的应用中配置 Web 服务的 Key

# 3.代码示例


<template>
  <div class="amap">
    <div id="container"></div>
  </div>
</template>
<script>
import AMapLoader from "@amap/amap-jsapi-loader";

export default {
  name: "amap",
  data() {
    return {
      map: null
    };
  },
  mounted() {
    this.initAMap();
  },
  methods: {
    initAMap() {
      window._AMapSecurityConfig = {
        securityJsCode: 'jscode' // 输入你的jscode
      } 
      AMapLoader.load({
        key: "xxx", //设置您的key
        version: "2.0", // 高德地图版本
        plugins: ["AMap.ToolBar", "AMap.Driving"], // 插件
        AMapUI: {
          // 高德地图UI组件库,可不写,内部提供了覆盖物标注点,以及部分模块的封装
          version: "1.1",
          plugins: []
        },
        Loca: {
          // Loca版本(高性能地图数据可视化库) 可不写
          version: "2.0"
        }
      })
        .then(AMap => {
          // container渲染的id
          this.map = new AMap.Map("container", {
            zoom: 5, // 当前缩放级别
            zooms: [2, 22], // 缩放级别范围
            center: [105.602725, 37.076636] // 中心点
          });
        })
        .catch(e => {
          console.log(e);
        });
    }
  }
};
</script>
<style lang="scss" scoped>
.amap {
  padding: 0px;
  margin: 0px;
  width: 100%;
  height: 100%;
  position: relative;
}
#container {
  padding: 0px;
  margin: 0px;
  width: 100%;
  height: 300px;
  position: absolute;
}
</style> 

# 3.页面展示

# 基于组件扩展

基于日历组件扩展一个可以添加日程的功能

效果如图:

# 创建一个添加日程的表单和视图

  1. 在表单设置处新建参数page_date,并赋给日期组件的默认值

  1. 在视图下,给视图设置新建参数view_date,并在动作设置处的添加新增按钮添加参数page_date

  1. 在视图的快速设置处,添加日期删选,默认值为参数view_date

  1. 新建一个全量视图(方便后续日历组件的单元格标记渲染)

# 日历组件+资源容器,资源容器引用日程的视图

  1. 新建表单,拖动一个日历组件和两个资源容器组件(样式隐藏全量视图);

    资源容器分别绑定默认视图(field_23703160)和 全量视图(field_56598840)

  1. 新建变量v_date

  2. 给日历组件添加点击事件,代码如下:(点击日历,表格查询)

this.v_date = data.day
this.Api.getFrameAsync('field_23703160').then(el => {
  el.Api.doQuery()
})
  1. 给默认视图传参,在扩展属性处添加view_date,如下图:

  1. 在表单设置处添加表单加载前事件(表单初始化时加载数据),代码如下
this.Api.getFrameAsync('field_23703160').then(el => {
  el.Api.doQuery()
})
this.Api.getFrameAsync('field_56598840').then(el => {
  el.Api.doQuery()
})
  1. 自定义渲染日历组件,在日历的自定义渲染模板处添加代码如下
<div slot-scope="{data}">
    <p style="margin-bottom: 0;">{{ data.day.split('-')[2] }}</p>
    <span v-if="(formData.field_56598840 ||[]).map(f => f.date).indexOf(data.day) !== -1" style="display: inline-block;width: 8px;height:8px;border-radius: 4px;background-color: #ccc;"></span>
</div>
上次更新: 2023/7/20下午6:22:36