*This article is contributed by muyao school
Some time ago, I made an appointment with my friends. The front-end was made with the AVM framework of apiccloud, the back-end was developed with php, and the tp5 framework was used. It was worked out in a few days. Simply share with you the implementation of some function points in the development. You are also welcome to discuss it together.
1, Organize project brain map

2, Project prototype
The prototype is made in front of the code. You can pass it www.devbefore.com/protomobile/47942983009476608 Check
3, Project front end
In this project, the front end is developed with apiccloud AVM multi terminal development technology, and the key points include swiper rotation diagram, network request encapsulation, etc. Use apiccloud multi terminal technology for development to realize a set of code multi terminal operation, and support compiling into Android & IOS app and wechat applet.
1. Steps for using apiccloud:
(1) Download apiccloud studio 3 as a development tool. Download address: www.apicloud.com/studio3
(2) After registering an account, create an app on the console. Console address: www.apicloud.com/console

(3) Set up a certificate and create an Android certificate with one click

(4) APICloud Studio3 pull the code, click the project, and export the cloud check-out

detection

Working directory after checking out
(5) Modify or submit the project source code, and compile a custom Loader for the current project cloud for real machine synchronous debugging preview.
Use the AppLoader to preview the real machine synchronization debugging. The background will automatically download it to the mobile phone with the loader. After installation, click the small circle and enter the ip address: 192.168.2.152 port: 10916. After connection, the real machine will be synchronized, and you can see the results just created.



2. Use of AVM framework
Why AVM?
- Easy to use: it is based on Vue and React and can be used quickly. It is equipped with a special development tool APICloud Studio3.
- Multi terminal: one development, multi terminal rendering, one technology stack to handle mobile terminal development.
- Rich functional APIs: provide 1000 + modules and 20000 + APIs, which can be called directly, and are oriented to industries and scenarios (unlimited)
(1)UI
Official documents: https://docs.apicloud.com/apicloud3/#/component/view?index=4&subIndex=0
Originally, there was an AUI framework made by a tramp man, which was not bad. Later, it used some simple frameworks of large companies. It depends on yourself. Many UIs are designed and written by ourselves. Ali font icon used for font icon. CSS framework, if there is no choice, it is recommended to use AUI. This framework has CSS foundation. You can know what to write at a glance, and it is particularly easy to modify. It's really not working. Change the source code directly.
The official website of apiccloud has assembled a set of vant https://docs.apicloud.com/Client-API/AVM-Components/readme.md
(2) ajax network interaction
//Submit data or files as forms
// Submit data or files as forms api.ajax({ url: 'http://192.168.1.101:3101/upLoad', method: 'post', data: { values: { name: 'haha' }, files: { file: 'fs://a.gif' } } }, function(ret, err) { if (ret) { api.alert({ msg: JSON.stringify(ret) }); } else { api.alert({ msg: JSON.stringify(err) }); } }); // Submit JSON data api.ajax({ url: 'http://192.168.1.101:3101/upLoad', method: 'post', headers: { 'Content-Type': 'application/json;charset=utf-8' }, data: { body: { name: 'haha' } } }, function(ret, err) { if (ret) { api.alert({ msg: JSON.stringify(ret) }); } else { api.alert({ msg: JSON.stringify(err) }); } });
(3) vue instruction usage (v-for v-show v-if v-else v-for v-on v-bind v-model, etc.)
1> Data binding
Use Mustache syntax:
<text text={{msg}}></text>
Use the v-bind command:
<text v-bind:text="msg"></text>
2> Event binding
<template> <text onclick="doThis('avm');">Click me!</text> </template> <script> export default { name: 'test', methods: { doThis(msg){ api.alert({ msg: msg }); } } } </script>
(4) Registration and login
1> Register interface link: http://showdoc.deui.cn/web/#/27?page_id=365
Registration code
<template name='tpl'> <view class="page"> <div class="page1"> <safe-area class="header"> <!-- <text class="header__title">APICloud</text> --> </safe-area> <scroll-view class="main"> <view> <image src="https://baodinglingqian.oss-cn-beijing.aliyuncs.com/1.png" class="touxiang " /> </view> <div class="zhanghao"> <input placeholder="Please enter the account number" v-model="zhanghao" maxlength="10" autofocus /> </div> <div class="mima"> <input type="password" placeholder="Please input a password" v-model="password" /> </div> <text class="zhuce" @click="reg()">register</text> <text class="denglu" @click="handleClick()">Sign in</text> </scroll-view> </div> <image class="originImage" mode="scaleToFill" src={src}></image> </view> </template> <script> export default { name: "tpl", apiready() { api.setStatusBarStyle({ style: "light", color: "-" }); }, data() { return { zhanghao: '', password: '', src: "https://baodinglingqian.oss-cn-beijing.aliyuncs.com/bg.png" }; }, computed: { }, methods: { handleClick(e) { api.openWin({ name: 'main', url: './main.stml', pageParam: { name: 'test' } }); }, reg() { var _this = this; // Submit JSON data api.ajax({ url: 'http://yy.deui.cn/api.php/index/re', method: 'get', // headers: { // 'Content-Type': 'application/json;charset=utf-8' // }, data: { body: { username: _this.zhanghao, password: _this.password } } }, function (ret, err) { console.log(JSON.stringify(ret)) if (ret.msg == 'Return success') { api.toast({ msg: 'login was successful', location: "middle" }); } else { api.alert({ msg: JSON.stringify(err) }); } }); } } }; </script> <style> .denglu { margin-top: 10px; font-size: 14px; } .touxiang { margin-top: 10%; width: 150px; height: 150px; border-radius: 100px; margin: 0 auto; } html { width: 100%; height: 100%; } body { width: 100%; height: 100%; } .originImage { position: absolute; top: 0px; left: 0px; right: 0px; bottom: 0px; z-index: 1; } .page { /* position:fixed; */ position: relative; z-index: 9; width: 100%; height: 100%; } .page1 { position: absolute; top: 0px; left: 0px; right: 0px; bottom: 0px; z-index: 2; } input { padding-left: 10px; line-height: 35px; height: 35px; border-radius: 5px; } .zhanghao { display: block; margin: 0 auto; margin-top: 15%; margin-bottom: 15px; height: 60px; } .mima { display: block; margin: 0 auto; margin-top: 25px; } .zhuce { width: 100%; height: 35px; line-height: 35px; background-color: coral; text-align: center; color: #fff; margin-top: 25px; } .page { height: 100%; background-color: white; } .header { background: #81a9c3; justify-content: center; align-items: center; } .header__title { color: #fff; font-size: 18px; font-weight: bold; height: 50px; line-height: 50px; } .main { flex: 1; padding: 15px; } .h1 { font-size: 24px; } .item { flex-direction: row; padding: 10px 0; } .item__text { color: #333; white-space: nowrap; } .item__value { margin-left: 5px; } .footer { background: #81a9c3; flex-direction: row; justify-content: center; align-items: center; } .footer__text { color: #fff; font-size: 14px; height: 30px; line-height: 30px; } </style>

2> Login interface link: http://showdoc.deui.cn/web/#/27?page_id=364
Login code
<template name='tpl'> <view class="page"> <div class="page1"> <safe-area class="header"> <!-- <text class="header__title">APICloud</text> --> </safe-area> <scroll-view class="main"> <view> <image src="https://baodinglingqian.oss-cn-beijing.aliyuncs.com/1.png" class="touxiang " /> </view> <div class="zhanghao"> <input placeholder="Please enter the account number" v-model="zhanghao" maxlength="10" autofocus /> </div> <div class="mima"> <input type="password" placeholder="Please enter mima" v-model="password" /> </div> <text class="zhuce" @click="login()">Sign in</text> <text class="denglu" @click="handleClick()">register</text> </scroll-view> </div> <image class="originImage" mode="scaleToFill" src={src}></image> </view> </template> <script> export default { name: "tpl", apiready() { api.setStatusBarStyle({ style: "light", color: "-" }); var value = localStorage.getItem('uid'); api.openWin({ name: 'home', url: './home.stml' }); }, data() { return { zhanghao: '', password: '', src: "https://baodinglingqian.oss-cn-beijing.aliyuncs.com/bg.png" }; }, computed: { }, methods: { handleClick(e) { api.openWin({ name: 'region', url: './region.stml', pageParam: { name: 'test' } }); // api.toast({ // msg: this.data.text, // location: "middle" // }); }, login() { var _this = this; api.ajax({ url: 'http://yy.deui.cn/api.php/index/login', method: 'get', // headers: { // 'Content-Type': 'application/json;charset=utf-8' // }, data: { body: { username: _this.zhanghao, password: _this.password } } }, function (ret, err) { console.log(JSON.stringify(ret)) localStorage.setItem('uid', ret.data.data[0]['id']); if (ret.msg == 'Return success') { api.toast({ msg: 'Login succeeded', location: "middle" }); api.openWin({ name: 'home', url: './home.stml' }); } else { api.alert({ msg: JSON.stringify(err) }); } }); } } }; </script> <style> .denglu { margin-top: 10px; font-size: 14px; } .touxiang { margin-top: 10%; width: 150px; height: 150px; border-radius: 100px; margin: 0 auto; } html { width: 100%; height: 100%; } body { width: 100%; height: 100%; } .originImage { position: absolute; top: 0px; left: 0px; right: 0px; bottom: 0px; z-index: 1; } .page { /* position:fixed; */ position: relative; z-index: 9; width: 100%; height: 100%; } .page1 { position: absolute; top: 0px; left: 0px; right: 0px; bottom: 0px; z-index: 2; } input { padding-left: 10px; line-height: 35px; height: 35px; border-radius: 5px; } .zhanghao { display: block; margin: 0 auto; margin-top: 15%; margin-bottom: 15px; height: 60px; } .mima { display: block; margin: 0 auto; margin-top: 25px; } .zhuce { width: 100%; height: 35px; line-height: 35px; background-color: coral; text-align: center; color: #fff; margin-top: 25px; } .page { height: 100%; background-color: white; } .header { background: #81a9c3; justify-content: center; align-items: center; } .header__title { color: #fff; font-size: 18px; font-weight: bold; height: 50px; line-height: 50px; } .main { flex: 1; padding: 15px; } .h1 { font-size: 24px; } .item { flex-direction: row; padding: 10px 0; } .item__text { color: #333; white-space: nowrap; } .item__value { margin-left: 5px; } .footer { background: #81a9c3; flex-direction: row; justify-content: center; align-items: center; } .footer__text { color: #fff; font-size: 14px; height: 30px; line-height: 30px; } </style>

(5) Home page rotation chart
Carousel link: http://showdoc.deui.cn/web/#/27?page_id=366
<template name='tpl'> <view class="page"> <div class="page1"> <safe-area class="header"> <text class="header__title">home page</text> </safe-area> <scroll-view class="main" scroll-y> <swiper class="swiper" id="customSwiper" autoplay circular indicator-dots indicator-color="#ddd" indicator-active-color="#f0f"> <swiper-item class="swiper-item" v-for="(_item,_index) in bannerlist"> <!-- <text class="desc">{_item.image}</text> --> <image mode="scaleToFill" src={_item.image}></image> </swiper-item> </swiper> <div> <a-cell-group> <a-cell v-bind:title="_item.name" v-bind:value="_item.content" v-bind:label="_item.address" arrow-direction="right" @click="godetial(_item)" v-for="(_item,_index) in shangjialist" /> <!-- <a-cell title="Cell" value="content" label="Description information" /> --> </a-cell-group> </div> </scroll-view> </div> <image class="originImage" mode="scaleToFill" src={src}></image> </view> </template> <script> import ACellGroup from "../../components/act/a-cell-group"; import ACell from "../../components/act/a-cell"; export default { name: 'test', data() { return { shangjialist: [], bannerlist: [], current: 0, src: "https://baodinglingqian.oss-cn-beijing.aliyuncs.com/bg.png" } }, methods: { apiready() { this.banner() this.allstores() // var customSwiper = document.getElementById('customSwiper'); // customSwiper.load({ // data: this.data.dataList // }); }, onchange(e) { this.data.current = e.detail.current; }, godetial(item) { console.log(JSON.stringify(item)) api.openWin({ name: 'detial', url: './detial.stml', pageParam: { id: item.id } }); }, banner() { var _this = this; api.ajax({ url: 'http://yy.deui.cn/api.php/index/banner', method: 'get', }, function (ret, err) { if (ret.msg == 'Return success') { _this.data.bannerlist = ret.data.data // var customSwiper = document.getElementById('customSwiper'); // customSwiper.load({ // data: _this.data.bannerlist // }); // console.log(JSON.stringify(_this.bannerlist)) } else { api.alert({ msg: JSON.stringify(err) }); } }); }, allstores() { var _this = this; api.ajax({ url: 'http://yy.deui.cn/api.php/index/stores', method: 'get', }, function (ret, err) { if (ret.msg == 'Return success') { console.log(1) console.log(JSON.stringify(ret.data.data)) console.log(1) var obj = ret.data.data for (let index = 0; index < obj.length; index++) { const element = obj[index]; element['content'] = element['content'].substring(0, 9) + '...' } console.log(JSON.stringify(obj)) _this.data.shangjialist = obj } else { api.alert({ msg: JSON.stringify(err) }); } }); } } } </script> <style> .denglu { margin-top: 10px; font-size: 14px; } .touxiang { margin-top: 10%; width: 150px; height: 150px; border-radius: 100px; margin: 0 auto; } html { width: 100%; height: 100%; } body { width: 100%; height: 100%; } .originImage { position: absolute; top: 0px; left: 0px; right: 0px; bottom: 0px; z-index: 1; } .page { /* position:fixed; */ position: relative; z-index: 9; width: 100%; height: 100%; } .page1 { position: absolute; top: 0px; left: 0px; right: 0px; bottom: 0px; z-index: 2; } input { padding-left: 10px; line-height: 35px; height: 35px; border-radius: 5px; } .zhanghao { display: block; margin: 0 auto; margin-top: 15%; margin-bottom: 15px; height: 60px; } .mima { display: block; margin: 0 auto; margin-top: 25px; } .zhuce { width: 100%; height: 35px; line-height: 35px; background-color: coral; text-align: center; color: #fff; margin-top: 25px; } .page { height: 100%; background-color: white; } .header { background: #81a9c3; justify-content: center; align-items: center; } .header__title { color: #fff; font-size: 18px; font-weight: bold; height: 50px; line-height: 50px; } .main { flex: 1; padding: 0px; } .h1 { font-size: 24px; } .item { flex-direction: row; padding: 10px 0; } .item__text { color: #333; white-space: nowrap; } .item__value { margin-left: 5px; } .footer { background: #81a9c3; flex-direction: row; justify-content: center; align-items: center; } .footer__text { color: #fff; font-size: 14px; height: 30px; line-height: 30px; } .main { width: 100%; height: 100%; } .swiper { width: 100%; height: 190px; /* background-color: blue; */ } .swiper-item { justify-content: center; } .title { padding: 10px 0; font-size: 20px; } .desc { width: 100%; text-align: center; } .container { width: 100%; height: 200px; } .indicator { flex-direction: row; justify-content: center; position: absolute; width: 100%; height: 20px; bottom: 8px; } .indicator-item { width: 15px; height: 8px; margin: 3px; } .indicator-item-normal { background-color: #ddd; } .indicator-item-active { background-color: red; } </style>
(6) Home page list
All store links: http://showdoc.deui.cn/web/#/27?page_id=369
The code of 5 above contains.
<a-cell-group> <a-cell v-bind:title="_item.name" v-bind:value="_item.content" v-bind:label="_item.address" arrow-direction="right" @click="godetial(_item)" v-for="(_item,_index) in shangjialist" /> </a-cell-group> shangjialist: [], allstores() { var _this = this; api.ajax({ url: 'http://yy.deui.cn/api.php/index/stores', method: 'get', }, function (ret, err) { if (ret.msg == 'Return success') { console.log(1) console.log(JSON.stringify(ret.data.data)) console.log(1) var obj = ret.data.data for (let index = 0; index < obj.length; index++) { const element = obj[index]; element['content'] = element['content'].substring(0, 9) + '...' } console.log(JSON.stringify(obj)) _this.data.shangjialist = obj } else { api.alert({ msg: JSON.stringify(err) }); } }); }

(7) Get details by page reference
api.openWin({ name: 'detial', url: './detial.stml', pageParam: { id: 123 } }); apiready() {//like created if (api.pageParam.id) { this.data.id = api.pageParam.id } console.log(this.data.id) }
Store details: http://showdoc.deui.cn/web/#/27?page_id=370
<template> <view class="page"> <view> <a-nav-bar v-bind:title="title" left-text="return" left-arrow @click-left="onClickLeft" @click-right="onClickRight" /> </view> <view> <a-cell-group> <a-cell title="name" v-bind:value="store.name" /> <a-cell title="Telephone" v-bind:value="store.phone" /> <a-cell title="city" v-bind:value="store.city" /> <a-cell title="address" v-bind:value="store.address" /> <a-cell title="content" v-bind:value="store.content" /> </a-cell-group> <!-- <text text={{store.name}}></text> <text text={{store.city}}></text> <text text={{store.content}}></text> <text text={{store.address}}></text> <text text={{store.phone}}></text> --> </view> <view> <a-button type="success">product</a-button> </view> <view> <a-cell-group> <a-cell v-bind:title="_item.name" v-bind:value="_item.content" label="Click to make an appointment" v-for="(_item,_index) in product" @click="yuyuproduct(_item)" /> </a-cell-group> </view> </view> </template> <script> import ACellGroup from "../../components/act/a-cell-group"; import ACell from "../../components/act/a-cell"; import ANavBar from "../../components/act/a-nav-bar"; import AButton from "../../components/act/a-button"; export default { name: 'detial', apiready() {//like created if (api.pageParam.id) { this.data.id = api.pageParam.id } console.log(this.data.id) this.init() }, data() { return { title: "details", id: 1, store: {}, product:[] } }, methods: { init() { var _this = this; api.ajax({ url: 'http://yy.deui.cn/api.php/index/searchstore', method: 'get', data: { body: { id: _this.data.id } } }, function (ret, err) { if (ret.msg == 'Return success') { console.log(1) console.log(JSON.stringify(ret.data.product)) console.log(1) _this.data.store = ret.data.data[0] _this.data.product = ret.data.product } else { api.alert({ msg: JSON.stringify(err) }); } }); }, yuyuproduct(_item){ console.log(JSON.stringify(_item)) }, onClickLeft() { api.closeWin(); }, onClickRight() { } } } </script> <style> .page { height: 100%; } </style>
(8) Navigation bar components
import ANavBar from "../../components/act/a-nav-bar";
<view>
< a-nav-bar v-bind: title = "title" left text = "return" left arrow @ click left = "onclickleft"
@click-right="onClickRight" />
</view>
Note: use of navigation bar components, references in documents
import ACell from"../../components/act/a-nav-bar.stml";
It is recommended to remove the stml suffix and import ACell from"../../components/act/a-nav-bar";

(9) localStorage object usage
main. The object in STML is the object used
localStorage.setItem('uid', ret.data.data[0]['id']);
Here is the usage of localStorage
// Set storage sessionStorage.setItem('key', 'value'); // Get storage var value = sessionStorage.getItem('key'); // Remove storage sessionStorage.removeItem('key'); // Clear all stored items sessionStorage.clear(); // Get the number of existing storage items var length = sessionStorage.length; // Get the storage key name according to the storage item index var keyName = sessionStorage.key(index);
(10) Use of apiccloud components and modules
Add a module to the module. If it is H5, you need to download it and put it into your own code; If it is a native module, you need to add it to your own application and use it with require. There is a tutorial on this topic on the Internet. If you don't know, you can search it.

4, Project background
This is the php background written by myself, using the tp5 framework.

The fastadmin framework under tp5 can generate a simple background according to fastadmin. The database file is:
Background interface code
<?php namespace app\api\controller; use app\common\controller\Api; use think\Db; /** * Home page interface */ class Index extends Api { protected $noNeedLogin = ['*']; protected $noNeedRight = ['*']; /** * home page * */ public function index() { $this->success('Request succeeded'); } //register public function re(){ $username = $this->request->request("username"); $password = md5($this->request->request("password")); $sql = " INSERT INTO `yuyuuser` (`id`, `group_id`, `username`, `nickname`, `password`, `salt`, `email`, `mobile`, `avatar`, `level`, `gender`, `birthday`, `bio`, `money`, `score`, `successions`, `maxsuccessions`, `prevtime`, `logintime`, `loginip`, `loginfailure`, `joinip`, `jointime`, `createtime`, `updatetime`, `token`, `status`, `verification`) VALUES (NULL, '0', '', '".$username ."', '".$password."', '', '', '', '', '0', '0', NULL, '', '0.00', '0', '1', '1', NULL, NULL, '', '0', '', NULL, NULL, NULL, '', '', '')"; $rst = Db::query($sql); $data =1; $this->success('Return success', ['data' => $data]); } //Sign in public function login(){ $username = $this->request->request("username"); $password = md5($this->request->request("password")); $sql = "SELECT nickname,id FROM yuyuuser where nickname='".$username."' and password='".$password."' order by id DESC LIMIT 1"; $rst = Db::query($sql); $this->success('Return success', ['data' => $rst]); } //Get rotation map public function banner() { $sql = "SELECT * FROM `yuyubanner`"; $rst = Db::query($sql); $this->success('Return success', ['data' => $rst]); } //Get network protocol public function xieyi() { $sql = "SELECT * FROM `yuyuxieyi`"; $rst = Db::query($sql); $this->success('Return success', ['data' => $rst]); } //All types public function leixing() { $sql = " SELECT * FROM `yuyutype`"; $rst = Db::query($sql); $this->success('Return success', ['data' => $rst]); } //All stores public function stores() { $sql = " SELECT * FROM `yuyustore`"; $rst = Db::query($sql); $this->success('Return success', ['data' => $rst]); } //Store information public function searchstore() { $id = $this->request->request("id"); $sql = " SELECT * FROM `yuyustore` where id = ".$id; $sql1 = "SELECT * FROM `yuyuproduct` where store_id = ".$id; $rst = Db::query($sql); $rst1 = Db::query($sql1); $this->success('Return success', ['data' => $rst,'product'=>$rst1]); } }