案例说明

本案例介绍APP微应用插件是如何开发的,上方区域展示地图,点击查看列表页面展示图二;点击请假表单页面或者地图marker进入图三。

案例效果如下:

图一:

图二:

图三:

开发步骤

1. 项目下载

Gitee仓库下载

git clone https://gitee.com/ketr/jecloud-app-archetype

2.修改项目名称

例如:jecloud-app-demo

命名规则:微应用的访问地址和部署目录是以项目最后一个单词(demo)命名, 可以根据业务需要自行修改

3.准备开发环境

nodev 14.18.3
npmv 6.14.15

4. 安装依赖

4.1 安装远程依赖

// 安装远程私服依赖
npm run setup:lib

在这个脚手架中没有安装app-func(功能解析)的依赖,如果业务组件中用到该依赖的相关东西,需要以下步骤:
1.安装 @jecloud/app-func
执行命令:npm i @jecloud/app-func进行安装

2.在src/app/index.js 引入@jecloud/app-func并注册


// src/app/index.js 代码参考如下:
// 引入功能包
import func from '@jecloud/app-func';
export default {
  /**
   * 可以添加一些自定义依赖
   * @param {*} param0
   */
  onAppInit: function (app) {
    // 安装功能对象
    app.use(func);
    func.setup();

    console.log('App Init', app);
  },
  onLaunch: function () {
    console.log('App Launch');
  },
  onShow: function () {
    console.log('App Show');
  },
  onHide: function () {
    console.log('App Hide');
  },
};

4.1 源码客户安装本地依赖

//安装本地依赖
npm run setup

在这个脚手架中没有安装app-func(功能解析)的依赖,如果业务组件中用到该依赖的相关东西,需要以下步骤:

1.修改package.json文件

"yalc:jecloud": "yalc add @jecloud/utils @jecloud/app-ui  @jecloud/app-func",

再次执行命令:npm run setup进行安装

2.在src/app/index.js 引入@jecloud/app-func并注册


// src/app/index.js 代码参考如下:
// 引入功能包
import func from '@jecloud/app-func';
export default {
  /**
   * 可以添加一些自定义依赖
   * @param {*} param0
   */
  onAppInit: function (app) {
    // 安装功能对象
    app.use(func);
    func.setup();

    console.log('App Init', app);
  },
  onLaunch: function () {
    console.log('App Launch');
  },
  onShow: function () {
    console.log('App Show');
  },
  onHide: function () {
    console.log('App Hide');
  },
};

5. 配置开发环境

新建项目配置文件 .env.development.local,配置系统的代理地址,参考如下:

# 代理服务地址
VUE_APP_SERVICE_PROXY = https://example.jecloud.net
# 代理websocket服务地址
VUE_APP_WEBSOCKET_PROXY = wss://example.jecloud.net

6.启动项目

npm run dev

开发项目(源码案例附在文档后,如有需要,请前往参考~)

1.根目录/src/pages下新建demo文件夹及其相关文件。

2.index.vue 入口文件(地图列表)

核心方法:配置mapinitConfigMap()、 初始化地图initMap()、添加inintMarker()、点击查看列表onMarkerClick()


3.demo.js ajax请求,返回数据
4.urls.js 统一存放ajax请求的url地址
5.form.vue 表单页面

核心方法:加载onLoad()、返回onBackPress()

6.配置pages.json路由文件

7.打包项目

npm run build

在根目录下生成dist文件

8.部署项目

1.找到微应用部署目录:服务器/data/application/openresty/ nginx/jecloud/app/micro,新建 demo 微应用目录:demo。
2.将 dist/build/h5 目录里的文件(不包含 h5 文件夹),上传到服务器 的 demo 目录下

浏览器输入微应用模块地址 http://服务器地址/app/micro/demo,如果可 以访问成功,代表部署成功。

9. 平台配置

1.微应用管理配置

2.添加菜单插件(其中功能插件及其菜单的权限都是跟随PC系统)

10.预览应用

1 浏览器输入地址: 域名/app#/?appId=自己的AppID

例如: https://example.jecloud.net/app#/?appId=2023-0920-1407-4526

2 扫码看效果

核心代码

  • index.vue
    <template>
      <app-config-provider>
        <view class="outer-app-demo-plugin">
          <view class="inner-app-demo-plugin">
            <!-- <uni-card title="地图"> -->
            <div ref="mapRef" class="map" style="width: 100%; height: 450px"></div>
            <!-- </uni-card> -->
            <button class="button-view" type="primary" @click="onMarkerClick"> 查看列表页面 </button>
            <button class="button-view" type="primary" @click="goFunForm()"> 请假表单页面 </button>
          </view>
        </view>
      </app-config-provider>
    </template>

    <script>
      import { onMounted, reactive, defineComponent, onBeforeMount, toRefs, watch, h } from 'vue';
      import AMapLoader from '@amap/amap-jsapi-loader';
      import { getFuncDataList } from './api/demo.js';
      import { onShow } from '@dcloudio/uni-app';
      // import { Modal } from '@jecloud/utils';
      import { showSelectWindow } from '@jecloud/app-func';

      export default defineComponent({
        name: 'Maps',
        components: {},
        setup() {
          const option = reactive({
            lng: 116.404,
            lat: 39.915,
            AMap: null,
            mapRef: null,
            mapData: null,
            data: [],
            markers: [],
          });
          const methods = {
            // 配置map
            initConfigMap() {
              AMapLoader.load({
                key: '651bbe1427b37c74deea8541a643918a', // 申请好的Web端开发者Key,首次调用 load 时必填
                plugins: [
                  'AMap.Scale',
                  'AMap.ToolBar',
                  'AMap.PlaceSearch',
                  'AMap.Geolocation',
                  'AMap.Geocoder',
                  'AMap.Autocomplete',
                  'AMap.OverView',
                  'AMap.MapType',
                  'AMap.PolyEditor',
                  'AMap.CircleEditor',
                  'AMap.DistrictSearch',
                  'AMap.CircleMarker',
                  'AMap.Polyline',
                  'AMap.Pixel',
                ], // 需要使用的的插件列表,如比例尺'AMap.Scale'等
                AMapUI: {
                  version: '1.1',
                  plugins: ['overlay/SimpleMarker', 'geo/DistrictExplorer'],
                },
              }).then((map) => {
                option.AMap = map;
                option.mapData = methods.initMap(map);

                return option.mapData;
              });
            },
            // 初始化地图
            initMap(AMap) {
              const mapData = new AMap.Map(option.mapRef, {
                mapStyle: 'amap://styles/98b26d04358dd80ee479ca1dfe9edd06', // 配置的地图样式
                zoom: 5,
                zooms: [1, 20],
                center: [116.404, 39.915],
                features: ['road', 'bg', 'point', 'building'], // 支持'bg'(地图背景)、'point'(POI点)、'road'(道路)、'building'(建筑物)
                resizeEnable: true, // 监控地图容器尺寸变化,默认值为false
                expandZoomRange: true, // 支持可以扩展最大缩放级别,和zooms属性配合使用,设置为true的时候,zooms的最大级别在PC上可以扩大到20级
              });
              mapData.on('click', (e) => {
                console.log(e);
              });
              return mapData;
            },
            getRandom(min, max) {
              return Math.floor(Math.random() * (max - min + 1) + min);
            },
            // Marker
            inintMarker(item, index) {
              const marker = new option.AMap.Marker({
                map: option.mapData,
                icon: '//a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-default.png',
                position: [option.lng + 0.01 * index, option.lat + 0.01 * index],
                offset: new option.AMap.Pixel(
                  methods.getRandom(-200, 200),
                  methods.getRandom(-100, 100),
                ),
                id: item.HR_QJSQ_ID,
                content: `<div style="background: yellow;border-radius: 50%;width: 40px;height: 40px;text-align: center;line-height: 40px">${
                  index + 1
                }</div>`,
              });
              marker.content = item.HR_QJSQ_ID;
              // 点击事件
              marker.on('click', (e) => {
                methods.goFunForm(e.target.content);
              });

              return marker;
            },
            // 进入表单
            goFunForm(id) {
              uni.navigateTo({
                url: id ? `/pages/demo/form?id=${id}` : '/pages/demo/form',
              });
            },
            // 获取列表数据
            getFuncData() {
              const params = {
                tableCode: 'HR_QJSQ',
                funcCode: 'HR_QJSQ',
              };
              getFuncDataList(params).then((data) => {
                option.data = data.rows;
              });
            },
            // 点击查看列表
            onMarkerClick() {
              showSelectWindow({
                configInfo: 'HR_QJSQ,grid,HR_QJSQ_ID',
                type: 'grid',
                value: '',
                callback: ({ rows }) => {
                  if (rows && rows[0].HR_QJSQ_ID) {
                    methods.goFunForm(rows[0].HR_QJSQ_ID);
                  }
                },
              });
            },
          };

          watch(
            () => [option.AMap, option.data],
            (val, value1) => {
              if (!(option.AMap && value1.length)) {
                return false;
              }
              // 清除标记点
              option.mapData.remove(option.markers);
              option.markers = [];
              // 渲染标记点
              option.data.map((item, index) => {
                const marker = methods.inintMarker(item, index);
                option.markers.push(marker);
              });
            },
            { deep: true },
          );
          onBeforeMount(() => {});
          onMounted(() => {
            // 初始地图
            methods.initConfigMap();
            // 获取列表数据
            methods.getFuncData();
          });
          onShow(() => {
            uni.$on('updateData', () => {
              methods.getFuncData();
            });
          });
          return { ...toRefs(option), ...methods };
        },
      });
    </script>
    <style lang="scss" scoped>
      .outer-app-demo-plugin {
        width: 100%;
        height: calc(100vh - var(--window-top)) !important;
        .inner-app-demo-plugin {
          width: 100%;
          height: 100%;
          overflow: auto;
        }

        .button-view {
          width: 60%;
          margin-top: 30px;
        }
        .func-height {
          height: 600px;
        }
      }
    </style>
  • form.vue
<template>
  <app-config-provider>
    <view class="outer-app-demo-form">
      <je-func
        class="func-height"
        :readonly="isReadonly"
        func-code="HR_QJSQ"
        is-func-form
        :bean-id="beanId"
      />
    </view>
  </app-config-provider>
</template>

<script>
  import { onMounted, defineComponent, onBeforeMount, reactive, toRefs } from 'vue';
  import { onLoad, onBackPress } from '@dcloudio/uni-app';
  export default defineComponent({
    name: 'Maps',
    components: {},
    setup() {
      const state = reactive({ beanId: '', isReadonly: false });
      onBeforeMount(() => {});
      onMounted(() => {});
      // 加载
      onLoad((e) => {
        state.beanId = e.id || '';
        state.isReadonly = e.id;
      });
      // 返回
      onBackPress((e) => {
        if (e.from == 'backbutton') {
          uni.$emit('updateData');
          uni.navigateBack({
            delta: 1, //返回:
          });
          return true;
        }
      });
      return { ...toRefs(state) };
    },
  });
</script>
<style lang="scss" scoped>
  .outer-app-demo-form {
    width: 100%;
    height: calc(100vh - var(--window-top)) !important;
  }
</style>
  • pages.json增加下面内容
  {"path": "pages/demo/index",
      "style": {
        "navigationStyle": "custom",
        "navigationBarTitleText": "培训案例"
      }
    },
    {"path": "pages/demo/form",
      "style": {
        "navigationStyle": "custom",
        "navigationBarTitleText": "表单详情"
      }
    },
最后编辑: 秦永莲  文档更新时间: 2024-11-08 17:00   作者:秦永莲