5月20日PWC培训

263 阅读3分钟

实战一: 自定义对象列表页展示(Web端)

效果展示

image.png

需求拆解

image.png

image.png

image.png

image.png

image.png

代码展示

自定义控制器代码:

String sql1 = "select _id, name, tel from AccountObj limit 10 offset 0;"
SelectAttribute att = SelectAttribute.builder()
  .needCount(true)
  .needInvalid(false)
  .build()
List rst1 = Fx.object.select(sql1, att) as List
return rst1[1]

自定义组件代码:

<!--
自定义实现一个对象列表页展示:
1. 实现一个定制化的列表页卡片
2. 需要调用APL函数获取对象数据
3. 点击卡片可以打开查看详情
4. 提供一个按钮,点击后可以新建对象
-->

<template>
  <div>
    <template v-for="item in dList">
      <div class="object-item">
        <fx-card :body-style="{ padding: '0px' }">
          <img src="https://shadow.elemecdn.com/app/element/hamburger.9cf7b091-55e9-11e9-a976-7f4d0b07eef6.png" class="image">
          <div style="padding: 14px;">
            <div> 客户id: {{ item._id}}</div>
            <div> 客户名称: {{ item.name }}</div>
            <div> 客户电话: {{ item.tel }}</div>
            <div class="bottom clearfix" style="text-align: center">
              <fx-button type="text" class="button" @click="createObj(item)">新建对象</fx-button>
              <fx-button type="text" class="button" @click="objDetail(item)">查看详情</fx-button>
            </div>
          </div>
        </fx-card>
      </div>
    </template>
  </div>
</template>

<script>
export default {
  data() {
    return {
      dList: [
        {_id: '', name: '', tel: ''},
      ]
    }
  },
  created() {
    this.fetchData()
  },
  methods: {
    // 获取客户对象列表信息
    fetchData() {
      FxUI.userDefine.call_controller('GetObjectData__c').then((res) => {
        if (res.Result.StatusCode === 0) {
          this.dList = res.Value.functionResult.dataList
        } else {
          alert('调用自定义控制器失败')
          console.log(res)
        }
      })
    },
    // 新建客户对象
    createObj(item) {
      console.log('新建客户对象')
      FxUI.objectUIAction.addObject('AccountObj', {
        showType: 'full'
      }).then(res => {
        // todo what you want
      }).catch(err => {
        // handle error
      })
    },
    // 获取客户对象详情
    objDetail(item) {
      console.log('客户对象详情')
      FxUI.objectUIAction.viewObject('AccountObj', item._id)
    }
  }
}
</script>

<style scoped>
.object-item {
  width: 235px;
  display: inline-block;
  margin: 20px;
}
</style>

踩坑: 关于vue的v-for循环

在div标签中,使用vue的v-for循环,会在每次循环的元素外自动加上一个div标签

下面是问ChatGpt的结果:

image.png

image.png

实战二: 自定义实现一个对象表单字段(Web端)

效果展示

image.png

需求拆解

image.png

image.png

image.png

image.png

image.png

image.png

image.png

代码展示

数据传递流向:(下图中字段代表组件)

image.png

第三方网页必加的代码: image.png

<template>

</template>

<script>
export default {
  name: "ThirdApp",
  methods: {
    // 第三方网页需要调用的方法
    closePage() {
      console.log('closePage')
      window.parent.postMessage(JSON.stringify({
        'name': 'close'
      }), '*')
    },
    sendMessage(data) {
      window.parent.postMessage(JSON.stringify({
        'name': 'returnResult',
        'params': data
      }), '*')
    },
    onItemClick(data) {
      this.sendMessage(data)
      this.closePage()
    }
  }
}
</script>

<style scoped>

</style>

测试用第三方网页完整代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>第三方WebPage</title>
    <style>
        body{
            margin: 0;
            padding: 0;
            width: 100%;
            height: 100vh;
            overflow: hidden;
        }
        p{
            margin: 0;
            padding: 0;
        }
        #app {
            height: 100%;
        }
        .container{
            padding-bottom: 40px;
            height: 100%;
            overflow: scroll;
            box-sizing: border-box;
        }
        .item {
            height: 100px;
            box-sizing: border-box;
            width: 100%;
            align-items: center;
            border-bottom: 1px solid #dee1e8;
            padding: 10px 12px;
            font-size: 12px;
            color: #212b36;
        }
        .bottom{
            position: fixed;
            bottom: 0;
            left: 0;
            right: 0;
            height: 40px;
            background-color: #fff;
            display: flex;
            align-items: center;
            justify-content: center;
            border-top: 1px solid #DEE1E8;
        }
    </style>
</head>
<body>
    <div id="app">
        <div class="container">
            <div v-for="(item, index) in list" class="item" @click="onItemClick(item)" >
                <p>公司名称:{{item.name}}</p>
                <p>工商注册号:{{item.regNumber}}</p>
                <p>法人代表:{{item.legalPerson}}</p>
                <p>注册资金:{{item.registeredCapital}}</p>
            </div>
        </div>
        <div class="bottom">
            <button @click="closePage">关闭</button>
        </div>
    </div>
    <!-- <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> -->
    <script src="https://a9.fspage.com/FSR/uipaas/test/vue2.js"></script>
    <script src="https://cdn.bootcss.com/vConsole/3.2.0/vconsole.min.js"></script>
    <script src="https://www.fxiaoke.com/open/jsapi/2.3.4/fsapi.min.js"></script>
    <script>
        var vConsole = new VConsole();
        let app = new Vue({
            el: '#app',
            data: {
                message: 'Hello Vue!',
                list: [
                    {
                        "name":"北京纷扬科技有限责任公司",
                        "tel":"123",
                        "email":"123@163.com",
                        "legalPerson":"罗旭",
                        "registeredCapital":"20000万美元",
                        "regNumber":"110000450231294"
                    },
                    {
                        "name":"广州纷扬信息科技有限公司",
                        "tel":"123",
                        "email":"123@163.com",
                        "legalPerson":"李智钒",
                        "registeredCapital":"100万人民币",
                        "regNumber":"440106001246204"
                    },
                    {
                        "name":"北京纷扬科技有限责任公司上海分公司",
                        "tel":"123",
                        "email":"123@163.com",
                        "legalPerson":"罗旭",
                        "registeredCapital":"-",
                        "regNumber":""
                    },
                    {
                        "name":"河南云纷扬网络科技有限公司",
                        "tel":"123",
                        "email":"123@163.com",
                        "legalPerson":"谷远",
                        "registeredCapital":"100万",
                        "regNumber":"410199000306770"
                    },
                    {
                        "name":"昆明扬纷科技有限公司",
                        "tel":"123",
                        "email":"123@163.com",
                        "legalPerson":"李天龙",
                        "registeredCapital":"10万人民币",
                        "regNumber":"530100000467573"
                    },
                    {
                        "name":"扬州纷信网络科技有限公司",
                        "tel":"123",
                        "email":"123@163.com",
                        "legalPerson":"包国余",
                        "registeredCapital":"100万人民币",
                        "regNumber":"321027000439418"
                    },
                    {
                        "name":"纷扬(上海)设计有限公司",
                        "tel":"123",
                        "email":"123@163.com",
                        "legalPerson":"丁佳",
                        "registeredCapital":"100万人民币",
                        "regNumber":""
                    },
                    {
                        "name":"纷扬(上海)网络科技有限公司",
                        "tel":"123",
                        "email":"123@163.com",
                        "legalPerson":"徐海东",
                        "registeredCapital":"500万人民币",
                        "regNumber":"310115003187023"
                    }
                    ]
            },
            methods: {
                closePage() {
                    console.log('closePage')
                    window.parent.postMessage(JSON.stringify({
                        "name": "close"
                    }), '*');
                },
                sendMessage(data) {
                    window.parent.postMessage(JSON.stringify({
                        "name":"returnResult", 
                        "params": data
                    }), '*');
                },
                onItemClick(data) {
                    this.sendMessage(data)
                    this.closePage()
                }
            }
        });
    </script>
</body>
</html>

新建/编辑页Web端插件:

import InputOpenThirdAppOptions from "/src/components/InputOpenThirdApp.vue";
const InputOpenThirdApp = Vue.extend(InputOpenThirdAppOptions)
export default {
    entry(context, field) {
        return field.api_name === 'name'
    },
    render(context, field, value) {
        const vm = new InputOpenThirdApp()
        vm.$mount()
        vm.$on('change', (val) => {
            context.setData(field.api_name, val)
        })
        return vm.$el
    }
}

自定义组件:

<template>
  <div>
    <fx-input placeholder="请输入内容" v-model="input" class="input-with-select">
      <fx-button slot="append" icon="el-icon-search" @click="dShow=true"></fx-button>
    </fx-input>
    <fx-dialog :visible.sync="dShow" @close="dShow=false">
      <iframe src="https://a9.fspage.com/FSR/uipaas/test/thirdWebPage.html?v=4"></iframe>
    </fx-dialog>
  </div>
</template>

<script>
export default {
  name: "InputOpenThirdApp",
  data() {
    return {
      input: '',
      dShow: false
    }
  },
  created() {
    // 现在纷享不能使用window,作了约束,得用top
    top.addEventListener('message', (e) => {
      console.log(e.data)
      if (e.origin === 'https://a9.fspage.com') { // 可能有多个消息源
        const data = JSON.parse(e.data)
        if(data.name === 'close') {
          this.dShow = false
        } else if(data.name === 'returnResult') {
          this.input = data.params.name
          this.dShow = false
          this.$emit('change', data.params.name)
        }
      }
    })
  },
  methods: {

  }
}
</script>

<!-- 这里不能加scoped,因为input是fx-input组件内部的一个属性-->
<style>
.input-with-select {
    input {
      height: auto !important;
    }
}
</style>

<!-- 这里必须加scoped, 因为新添加的标签在fx-dialog组件里面-->
<style scoped lang="less">
  iframe {
    width: 100%;
    height: 500px;
  }
</style>

实战三: 实现一个页面自定义菜单组件

需求

image.png

需求分析

image.png

效果展示

DC64E9D6867C7D7E8A3BDC60666FBA22.jpg

代码展示

目录结构:

image.png

<!--components/menu/menu.wxml-->
<view class="menu-group">
        <view wx:for="{{ dList }}" wx:for-item="menuData">
            <view class="menu" bindtap="openPage" data-menu="{{menuData}}">
                <image src="{{ menuData.icon }}" mode=""/>
                <text>{{ menuData.name }}</text>
            </view>
        </view>
</view>
/* components/menu/menu.wxss */
.menu-group {
    width: 100%;
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    padding: 20px;
    background-color: orange;
}

.menu {
    width: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    padding-right: 10px;
}

.menu image {
    width: 40px;
    height: 40px;
    border-radius: 40px;
    margin-top: 15px;
    margin-bottom: 10px;
}

.menu text {
    font-size: 12px;
    color: ghostwhite;
}
// components/menu/menu.js
import fsApi from "fs-hera-api"

Component({
    /**
     * 组件的属性列表
     */
    properties: {

    },

    /**
     * 组件的初始数据
     */
    data: {
        dList: [
            {
                name: 'qq',
                icon: 'https://n.sinaimg.cn/sinakd20220708s/579/w690h689/20220708/093c-ebb3af959f02d6334803c3015fe6492b.jpg',
                link: "https://im.qq.com/index/"

            },
            {
                name: '自定义H5应用',
                icon: 'https://n.sinaimg.cn/sinakd20220708s/579/w690h689/20220708/093c-ebb3af959f02d6334803c3015fe6492b.jpg',
                link: "https://fxiaoke.com"
            },
            {
                name: '暂时未定义',
                icon: 'https://n.sinaimg.cn/sinakd20220708s/579/w690h689/20220708/093c-ebb3af959f02d6334803c3015fe6492b.jpg',
                link: 'https://fxiaoke.com'
            }
        ]
    },

    /**
     * 组件的方法列表
     */
    methods: {
        openPage(e) {
            console.log
            let data = e.currentTarget.dataset['menu']
            console.log(data)
            fsApi.page.utilOpen({
                name: data.link
            })
        }
    }
})

config.json文件:

image.png

去除默认样式:

image.png

实战四: 自定义插件实现第三方h5列表数据回填至表单

需求

image.png

image.png

效果展示

F95FDBB3DF3B0ED02072A840462B44D0.jpg948187B6E7673643813549D15197E174.jpg62FFC33168929F0352C6D2284CCE32D0.jpg

代码展示

第三方网页必加的代码:

<template>

</template>

<script>
export default {
  name: "ThirdApp",
  methods: {
    closePage() {
        console.log('closePage')
        FSOpen.webview.close()
    },
    sendMessage(data) {
        console.log('sendMessage')
        FSOpen.util.sendNotification({
            "name":"returnResult", 
            "params": data
        })
    },
    onItemClick(data) {
        this.sendMessage(data)
        this.closePage()
    }
  }
}
</script>

<style scoped>

</style>

第三方网页完整代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>第三方h5Page</title>
    <style>
        body{
            margin: 0;
            padding: 0;
            width: 100%;
            height: 100vh;
            overflow: hidden;
        }
        p{
            margin: 0;
            padding: 0;
        }
        #app {
            height: 100%;
        }
        .container{
            padding-bottom: 40px;
            height: 100%;
            overflow: scroll;
            box-sizing: border-box;
        }
        .item {
            height: 100px;
            box-sizing: border-box;
            width: 100%;
            align-items: center;
            border-bottom: 1px solid #dee1e8;
            padding: 10px 12px;
            font-size: 12px;
            color: #212b36;
        }
        .bottom{
            position: fixed;
            bottom: 0;
            left: 0;
            right: 0;
            height: 40px;
            background-color: #fff;
            display: flex;
            align-items: center;
            justify-content: center;
            border-top: 1px solid #DEE1E8;
        }
    </style>
</head>
<body>
    <div id="app">
        <div class="container">
            <div v-for="(item, index) in list" class="item" @click="onItemClick(item)" >
                <p>公司名称:{{item.name}}</p>
                <p>工商注册号:{{item.regNumber}}</p>
                <p>法人代表:{{item.legalPerson}}</p>
                <p>注册资金:{{item.registeredCapital}}</p>
            </div>
        </div>
        <div class="bottom">
            <button @click="closePage">关闭</button>
        </div>
    </div>
    <!-- <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> -->
    <script src="https://a9.fspage.com/FSR/uipaas/test/vue2.js"></script>
    <script src="https://cdn.bootcss.com/vConsole/3.2.0/vconsole.min.js"></script>
    <script src="https://www.fxiaoke.com/open/jsapi/2.3.4/fsapi.min.js"></script>
    <script>
        var vConsole = new VConsole();
        let app = new Vue({
            el: '#app',
            data: {
                message: 'Hello Vue!',
                list: [
                    {
                        "name":"北京纷扬科技有限责任公司",
                        "tel":"123",
                        "email":"123@163.com",
                        "legalPerson":"罗旭",
                        "registeredCapital":"20000万美元",
                        "regNumber":"110000450231294"
                    },
                    {
                        "name":"广州纷扬信息科技有限公司",
                        "tel":"123",
                        "email":"123@163.com",
                        "legalPerson":"李智钒",
                        "registeredCapital":"100万人民币",
                        "regNumber":"440106001246204"
                    },
                    {
                        "name":"北京纷扬科技有限责任公司上海分公司",
                        "tel":"123",
                        "email":"123@163.com",
                        "legalPerson":"罗旭",
                        "registeredCapital":"-",
                        "regNumber":""
                    },
                    {
                        "name":"河南云纷扬网络科技有限公司",
                        "tel":"123",
                        "email":"123@163.com",
                        "legalPerson":"谷远",
                        "registeredCapital":"100万",
                        "regNumber":"410199000306770"
                    },
                    {
                        "name":"昆明扬纷科技有限公司",
                        "tel":"123",
                        "email":"123@163.com",
                        "legalPerson":"李天龙",
                        "registeredCapital":"10万人民币",
                        "regNumber":"530100000467573"
                    },
                    {
                        "name":"扬州纷信网络科技有限公司",
                        "tel":"123",
                        "email":"123@163.com",
                        "legalPerson":"包国余",
                        "registeredCapital":"100万人民币",
                        "regNumber":"321027000439418"
                    },
                    {
                        "name":"纷扬(上海)设计有限公司",
                        "tel":"123",
                        "email":"123@163.com",
                        "legalPerson":"丁佳",
                        "registeredCapital":"100万人民币",
                        "regNumber":""
                    },
                    {
                        "name":"纷扬(上海)网络科技有限公司",
                        "tel":"123",
                        "email":"123@163.com",
                        "legalPerson":"徐海东",
                        "registeredCapital":"500万人民币",
                        "regNumber":"310115003187023"
                    }
                    ]
            },
            methods: {
                closePage() {
                    console.log('closePage')
                    FSOpen.webview.close()
                },
                sendMessage(data) {
                    console.log('sendMessage')
                    FSOpen.util.sendNotification({
                        "name":"returnResult", 
                        "params": data
                    })
                },
                onItemClick(data) {
                    this.sendMessage(data)
                    this.closePage()
                }
            }
        });
    </script>
</body>
</html>

插件:

export default function (context) {
  return {
    customFieldCom({field}) {
      let comInfo = null;
      if (field && field.api_name === 'field_3Xlbm__c') {
        console.log("test plugin: customFieldCom: " + field.api_name)
        comInfo = {
          name: "cmpt1",
          prop: {test: 1}
        }
      }
      return Promise.resolve(comInfo)//异步return
      //return comInfo //或者直接同步return
    }
  }

组件:

<view class="container">
    <view>
        <view class="i-cell">
            <view class="i-cell-hd">
                <view class="text">
                    插件修改字段名
                </view>
            </view>
            <view class="i-cell-bd">
                <view class="i-cell-input">
                    <button size="mini" type="primary" bindtap="openWebView"> 打开第三方h5</button>
                </view>
            </view>
        </view>
    </view>
</view>
.i-cell {
    display: flex;
    height: 40px;
    box-sizing: border-box;
    align-items: center;
}

.i-cell-hd {
    padding: 10px;
}
import fieldbehavior from "../../fieldbehavior";
import fsApi from "fs-hera-api"
Component({
  behaviors:[fieldbehavior],
  methods:{
    openWebView() {
        fsApi.jsapi.webviewOpen({
            url: `https://a9.fspage.com/FSR/uipaas/test/thirdH5Page.html?v=${+new Date()}`,
            onSuccess: (data) => {
                this.data.context.setData({
                    "field_CBcdg__c": data.tel,
                    "field_oi1K9__c": data.name,
                    "field_e8x8y__c": data.regNumber,
                    "field_47dj2__c": data.registeredCapital
                })
            }
        })
    },
    _testMethod(){
      let {context, field}=this.data;
      let random = Math.round(Math.random()*1000)+''
      context.setData({
        [field.api_name]:random
      })
    }
  },
  lifetimes:{
    attached() {
      if(wx.getSystemInfoSync().brand=="devtools"){
        const mockUtil  = require("../../mockUtils")
        mockUtil.initFieldCom(this, {
          field: {api_name:"test__c", type:'text', label:"测试字段label"},
          is_required:true,
          is_readonly: false,
          value: null
        })
      }
      
      console.group("自定义字段组件 attached")
      console.log(this.data)
      console.log(this.data.field)
      console.log(this.data.context)
      console.groupEnd()
    }
  }
});

常用技巧与案例解析

1. 租户配置存储

image.png

image.png

image.png

2. 系统嵌入

image.png

image.png

3. 跨系统数据通讯

image.png

image.png

实战二与实战四中都涉及了跨系统数据通讯,一个是web与web(第三方)跨系统通讯,另一个是小程序与web(第三方)跨系统通讯

4. 第三方app集成

image.png

image.png

5. 依赖第三方库

image.png

方式1: image.png

方式2: image.png