因为人事档案具备涉密性,所以本利用没有应用后盾服务,全副性能都在APP本地实现。

开发工具采纳 APICloud Studio3,基于VSCode的(PS:比基于Atom的autio2好用太多);

数据库采纳sqllite,没有应用UI框架,集体感觉AVM自身反对的flex布局配合自写CSS款式,齐全能够实现市面上所有的UI框架的元素,这个取决于集体功力。

一、我的项目思维脑图

二、性能介绍

1、人员花名册

2、编制状况

3、集体核心

三、技术要点

手势明码验证,本地数据库操作,语音播报。

用到的模块

我的项目文件目录

援用一下官网的对于目录构造的介绍

四、性能开发详解

1、首页导航

零碎首页应用tabLayout,能够将相干参数配置在JSON文件中,再在config.xml中将content的值设置成该JSON文件的门路。如果底部导航没有非凡需要这里强烈建议大家应用tabLayout为APP进行布局,官网曾经将各类手机屏幕及不同的分辨率进行了适配,免去了很多对于适配方面的问题。

app.json文件内容,对于json文件的命名是没有限度的,我习惯用app。

{    "name": "root",    "textOffset": 6,    "color": "#999999",    "selectedColor": "#006aff",    "scrollEnabled": false,    "hideNavigationBar": false,    "bgColor": "#fff",    "navigationBar": {        "background": "#006aff",        "shadow": "rgba(0,0,0,0)",        "color": "#fff",        "fontSize": 18,        "hideBackButton": true    },    "tabBar": {      "background": "#fff",      "shadow": "#eee",      "color": "#5E5E5E",      "selectedColor": "#006aff",      "textOffset": 3,      "fontSize": 11,      "scrollEnabled": true,      "index": 1,      "preload": 0,      "frames": [        {          "title": "编制状况",          "name": "home",          "url": "./pages/records/organ"        },        {          "title": "人员花名册",          "name": "course",          "url": "./pages/person/organ"        },        {          "title": "集体核心",          "name": "user",          "url": "./pages/main/main"        }      ],      "list": [        {          "text": "编制",          "iconPath": "./image/authoried-o.png",          "selectedIconPath": "./image/authoried.png"        },        {          "text": "人员",          "iconPath": "./image/person-o.png",          "selectedIconPath": "./image/person.png"        },        {          "text": "我的",          "iconPath": "./image/user-o.png",          "selectedIconPath": "./image/user.png"        }      ]    }  }

2、列表显示及分页

通过上拉刷新和下拉操作,配合JS办法实现分页查问性能。

<template name='list'>    <scroll-view scroll-y class="main" enable-back-to-top refresher-enabled refresher-triggered={refresherTriggered} onrefresherrefresh={this.onrefresherrefresh} onscrolltolower={this.onscrolltolower}>        <view class="item-box">            <view class="item" data-id={item.id} v-for="(item, index) in personList" tapmode onclick="openTab">                <image class="avator" src={item.photo} mode="widthFix"></image>                <text class="item-title">{item.name}</text>                <text class="item-sub-title">{item.nation}</text>            </view>        </view>        <view class="footer">            <text class="loadDesc">{loadStateDesc}</text>        </view>            </scroll-view></template>
<script>    import $util from "../../utils/utils.js"    export default {        name: 'list',            data() {            return{                personList:[],                skip: 0,                refresherTriggered: false,                haveMoreData: true,                loading: false,                organid:0            }        },        computed: {                        loadStateDesc(){                if (this.data.loading || this.data.haveMoreData) {                    return '加载中...';                } else if (this.personList.length > 0) {                    return '没有更多啦';                } else {                    return '临时没有内容';                }            }        },        methods: {            apiready(){                this.data.organid = api.pageParam.id;                this.loadData(false);                //更换头像                api.addEventListener({                    name: 'setavator'                }, (ret, err) => {                    this.loadData();                });                //新增人员信息                api.addEventListener({                    name: 'addperson'                }, (ret, err) => {                    this.loadData();                });                //删除人员信息                api.addEventListener({                    name: 'delperson'                }, (ret, err) => {                    this.loadData();                });                if(api.getPrefs({sync: true,key: 'role'})=='99'){                    //增加编辑按钮                    api.setNavBarAttr({                        rightButtons: [{                            text: '新增'                        }]                    });                    //监听右上角按钮点击事件                    api.addEventListener({                        name: 'navitembtn'                    }, (ret, err) => {                        if (ret.type == 'right') {                            $util.openWin({                                name: 'personadd',                                url: 'personadd.stml',                                title: '新增人员信息',                                pageParam:{                                    organid:this.data.organid                                }                            });                        }                    });                }                        },            loadData(loadMore) {                if (this.data.loading) {                    return;                }                api.showProgress();                this.data.loading = true;                var limit = 15;                var skip = loadMore?(this.data.skip+1)*limit:0;                 // console.log('select id,name,grade,sex,nation,photo from authority where organ = '+this.data.organid+' order by id limit '+limit+' offset '+skip);                 var db = api.require('db');                db.selectSql({                    name: 'doc',                    sql: 'select id,name,grade,sex,nation,photo from authorized where organ = '+this.data.organid+' order by id limit '+limit+' offset '+skip                }, (ret, err)=> {                    // console.log(JSON.stringify(ret));                    // console.log(JSON.stringify(err));                    if (ret.status) {                        let records = ret.data;                        this.data.haveMoreData = records.length == limit;                        if (loadMore) {                            this.data.personList = this.data.personList.concat(records);                        } else {                            this.data.personList = records;                        }                        this.data.skip = skip;                    } else {                        this.data.recordsList = records;                        api.toast({                            msg:err.msg                        })                    }                    this.data.loading = false;                    this.data.refresherTriggered = false;                    api.hideProgress();                });            },            /*下拉刷新页面*/            onrefresherrefresh(){                this.data.refresherTriggered = true;                this.loadData(false);            },            onscrolltolower() {                if (this.data.haveMoreData) {                    this.loadData(true);                }            },            openTab(e){                let id = e.currentTarget.dataset.id;                $util.openWin({                    name: "personinfo",                    url: 'personinfo.stml',                    title: '人员信息',                    pageParam:{                        id:id                    }                });            }        }    }</script>

3、表单提交

采纳AVM自带的from控件,通过onsubmit进行数据提交

4、头像图片上传及base64转码

因为是本地sqllite数据库,人员头像图片须要转成base64编码存储到数据库中。通过官网模块trans进行图片转码操作。

<image class="avator" src={this.data.src} mode="widthFix"  onclick="setavator"></image>             setavator(){                api.actionSheet({                    cancelTitle: '勾销',                    buttons: ['拍照', '关上相册']                }, (ret, err) => {                    if (ret.buttonIndex == 3) {                        return false;                    }                    var sourceType = (ret.buttonIndex == 1) ? 'camera' : 'album';                    api.getPicture({                        sourceType: sourceType,                        allowEdit: true,                        quality: 20,                        destinationType:'url'                    }, (ret, err) => {                        if (ret && ret.data) {                            var trans = api.require('trans');                            trans.decodeImgToBase64({                                imgPath: ret.data                            }, (ret, err) => {                                // console.log(JSON.stringify(ret));                                // console.log(JSON.stringify(err));                                if (ret.status) {                                    let b64 =  "data:image/jpeg;base64,"+ret.base64Str;                                    this.data.src = b64;                                } else {                                    api.toast({                                        msg:'照片上传失败,请从新抉择!'                                    })                                }                            });                        }                    });                });            },

5、sqllite数据库 db模块

因为数据库文件须要存储的利用安装文件中,所有须要官网fs模块配合应用来进行数据库文件的操作。

copyDB(){            var fs = api.require('fs');            fs.copyTo({                oldPath: 'widget://db/doc.db',                newPath: 'fs://db'            }, function(ret, err) {                // console.log(JSON.stringify(ret));                // console.log(JSON.stringify(err));                if (ret.status) {                    // console.log(JSON.stringify(ret));                    api.toast({                        msg:'拷贝数据库胜利!'                    })                } else {                    // console.log(JSON.stringify(err));                    api.toast({                        msg:JSON.stringify(err)                    })                }            });        },        openDB(){            var db = api.require('db');            db.subfile({                directory:'fs://db'            }, (ret, err)=> {                // console.log(JSON.stringify(ret));                // console.log(JSON.stringify(err));                if (ret.status) {                    // console.log(JSON.stringify(ret));                    //关上数据库                    db.openDatabase({                        name: 'doc',                        path: ret.files[0]                    }, (ret, err)=> {                        // console.log(JSON.stringify(ret));                        // console.log(JSON.stringify(err));                        if (ret.status) {                            // console.log(JSON.stringify(ret));                            api.toast({                                msg:'关上数据库胜利!'                            })                        } else {                            // console.log(JSON.stringify(err));                            api.toast({                                msg:JSON.stringify(err)                            })                        }                    });                                    } else {                    // console.log(JSON.stringify(err));                    api.toast({                        msg:JSON.stringify(err)                    })                }            });        },        closeDB(){            var db = api.require('db');            db.closeDatabase({                name: 'doc'            }, function(ret, err) {                if (ret.status) {                    console.log(JSON.stringify(ret));                    api.toast({                        msg:'敞开数据库胜利'                    })                } else {                    // console.log(JSON.stringify(err));                    api.toast({                        msg:JSON.stringify(err)                    })                }            });        },        updateDB(){            var fs = api.require('fs');            var db = api.require('db');            db.closeDatabase({                name: 'doc'            }, (ret, err) => {                if (ret.status) {                    //拷贝文件                    fs.copyTo({                        oldPath: 'widget://doc.db',                        newPath: 'fs://db/'                    }, (ret, err) => {                        if (ret.status) {                             db.subfile({                                directory:'fs://db'                            }, (ret, err)=> {                                if(ret.status){                                    //关上数据库                                    db.openDatabase({                                        name: 'doc',                                        path: ret.files[0]                                    }, (ret, err)=> {                                        if (ret.status) {                                            api.toast({                                                msg:'数据库更新胜利!'                                            })                                        } else {                                            api.toast({                                                msg:JSON.stringify(err)                                            })                                        }                                    });                                }                                else{                                    api.toast({                                        msg:JSON.stringify(err)                                    })                                }                                                          })                        } else {                            api.toast({                                msg:JSON.stringify(err)                            })                        }                    });                } else {                    api.toast({                        msg:JSON.stringify(err)                    })                }            });         },

6、语音播报性能

采纳官网提供的IFLyVoice模块,须要留神的是,根底资源文件和发音人资源文件(.jet文件)须要到科大讯飞开发者平台进行下载导入的我的项目中。还有对数字的解读不是准确,尤其是年份,最好不要用数字,而是用中文。

//增加朗诵按钮                    api.setNavBarAttr({                        rightButtons: [{                            text: '朗诵'                        }]                    });                    //监听右上角按钮点击事件                    api.addEventListener({                        name: 'navitembtn'                    }, (ret, err) => {                        // console.log(JSON.stringify(this.data.info));                        if (ret.type == 'right') {                            var IFlyVoice = api.require('IFlyVoice');                            IFlyVoice.initSpeechSynthesizer((ret)=>{                            //   console.log(JSON.stringify(ret));                            });                            IFlyVoice.startSynthetic({                                text:this.data.info,                                commonPath_Android:'widget://res/android/common.jet',                                pronouncePath_Android:'widget://res/android/xiaoyan.jet',                                pronounceName:'xiaoyan',                                speed:40                            },(ret,err)=>{                                // console.log(JSON.stringify(ret));                                // console.log(JSON.stringify(err));                                if (ret.status) {                                    // console.log('合成胜利');                                } else {                                    // console.log(JSON.stringify(err));                                }                            });                        }                    });

7、手势密码保护

手势密码保护因为官网模块存在款式问题,及原生模块存在遮罩问题,所以采纳了平台上提供的H5模块。APICloud弱小之处在这里进行了酣畅淋漓的体现,通过AVM及原生模块无奈实现的性能,能够再用H5的形式来实现!牛逼!!!!,通过设置全局变量来记录是否已设置手机明码,每次利用启动通过这个变量来判断是否开启手势密码保护。

this.data.islock =api.getPrefs({sync: true,key: 'islock'});                if(this.data.islock=='Y'){                    api.openFrame({                        name: 'h5lock',                        url:'../../html/h5lock.html'                    })                }                else{                    api.toast({                        msg:'您还没有设置手势明码,为了数据安全,请尽快设置。'                    })                }
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">    <title>H5lock</title>    <style type="text/css">        body {            text-align: center;            background-color: #000000;        }        .title {            /*color: #87888a;*/            margin-top: 85px;            font-size: 20px;            font-weight:lighter;        }    </style></head><body><script type="text/javascript" src="../script/H5lock.js"></script><script type="text/javascript">    var opt = {        chooseType: 3, // 3 , 4 , 5,        width: 300, // lock wrap width        height: 300, // lock wrap height        container: 'element', // the id attribute of element        inputEnd: function (psw){} // when draw end param is password string    }    var lock = new H5lock(opt);    lock.init();</script></body></html>
(function(){        window.H5lock = function(obj){            this.height = obj.height;            this.width = obj.width;            this.chooseType = Number(window.localStorage.getItem('chooseType')) || obj.chooseType;            this.devicePixelRatio = window.devicePixelRatio || 1;        };          H5lock.prototype.drawCle = function(x, y) { // 初始化解锁明码面板 小圆圈            this.ctx.strokeStyle = '#87888a';//明码的点点默认的色彩            this.ctx.lineWidth = 2;            this.ctx.beginPath();            this.ctx.arc(x, y, this.r, 0, Math.PI * 2, true);            this.ctx.closePath();            this.ctx.stroke();        }        H5lock.prototype.drawPoint = function(style) { // 初始化圆心            for (var i = 0 ; i < this.lastPoint.length ; i++) {                this.ctx.fillStyle = style;                this.ctx.beginPath();                this.ctx.arc(this.lastPoint[i].x, this.lastPoint[i].y, this.r / 2.5, 0, Math.PI * 2, true);                this.ctx.closePath();                this.ctx.fill();            }        }        H5lock.prototype.drawStatusPoint = function(type) { // 初始化状态线条            for (var i = 0 ; i < this.lastPoint.length ; i++) {                this.ctx.strokeStyle = type;                this.ctx.beginPath();                this.ctx.arc(this.lastPoint[i].x, this.lastPoint[i].y, this.r, 0, Math.PI * 2, true);                this.ctx.closePath();                this.ctx.stroke();            }        }        H5lock.prototype.drawLine = function(style, po, lastPoint) {//style:色彩 解锁轨迹            this.ctx.beginPath();            this.ctx.strokeStyle = style;            this.ctx.lineWidth = 3;            this.ctx.moveTo(this.lastPoint[0].x, this.lastPoint[0].y);             for (var i = 1 ; i < this.lastPoint.length ; i++) {                this.ctx.lineTo(this.lastPoint[i].x, this.lastPoint[i].y);            }            this.ctx.lineTo(po.x, po.y);            this.ctx.stroke();            this.ctx.closePath();         }        H5lock.prototype.createCircle = function() {// 创立解锁点的坐标,依据canvas的大小来平均分配半径             var n = this.chooseType;            var count = 0;            this.r = this.ctx.canvas.width / (1 + 4 * n);// 公式计算            this.lastPoint = [];            this.arr = [];            this.restPoint = [];            var r = this.r;            for (var i = 0 ; i < n ; i++) {                for (var j = 0 ; j < n ; j++) {                    count++;                    var obj = {                        x: j * 4 * r + 3 * r,                        y: i * 4 * r + 3 * r,                        index: count                    };                    this.arr.push(obj);                    this.restPoint.push(obj);                }            }            this.ctx.clearRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height);            for (var i = 0 ; i < this.arr.length ; i++) {                this.drawCle(this.arr[i].x, this.arr[i].y);            }            //return arr;        }        H5lock.prototype.getPosition = function(e) {// 获取touch点绝对于canvas的坐标            var rect = e.currentTarget.getBoundingClientRect();            var po = {                x: (e.touches[0].clientX - rect.left)*this.devicePixelRatio,                y: (e.touches[0].clientY - rect.top)*this.devicePixelRatio              };            return po;        }        H5lock.prototype.update = function(po) {// 外围变换办法在touchmove时候调用            this.ctx.clearRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height);             for (var i = 0 ; i < this.arr.length ; i++) { // 每帧先把面板画进去                this.drawCle(this.arr[i].x, this.arr[i].y);            }             this.drawPoint('#27AED5');// 每帧花轨迹            this.drawStatusPoint('#27AED5');// 每帧花轨迹             this.drawLine('#27AED5',po , this.lastPoint);// 每帧画圆心 // if (this.lastPoint.length == 4) {//     // debugger// }             for (var i = 0 ; i < this.restPoint.length ; i++) {                if (Math.abs(po.x - this.restPoint[i].x) < this.r && Math.abs(po.y - this.restPoint[i].y) < this.r) {                    this.drawPoint(this.restPoint[i].x, this.restPoint[i].y);                    this.lastPoint.push(this.restPoint[i]);                    this.restPoint.splice(i, 1);                    break;                }            }         }        H5lock.prototype.checkPass = function(psw1, psw2) {// 检测明码            var p1 = '',            p2 = '';            for (var i = 0 ; i < psw1.length ; i++) {                p1 += psw1[i].index + psw1[i].index;            }            for (var i = 0 ; i < psw2.length ; i++) {                p2 += psw2[i].index + psw2[i].index;            }            return p1 === p2;        }        H5lock.prototype.storePass = function(psw) {// touchend完结之后对明码和状态的解决             if (this.pswObj.step == 1) {                if (this.checkPass(this.pswObj.fpassword, psw)) {                    this.pswObj.step = 2;                    this.pswObj.spassword = psw;                    document.getElementById('title').innerHTML = '明码保留胜利';                                                        this.drawStatusPoint('#2CFF26');                     this.drawPoint('#2CFF26');                    window.localStorage.setItem('passwordxx', JSON.stringify(this.pswObj.spassword));                    window.localStorage.setItem('chooseType', this.chooseType);                 } else {                    document.getElementById('title').innerHTML = '两次不统一,从新输出';                    this.drawStatusPoint('red');                     this.drawPoint('red');                    delete this.pswObj.step;                }            } else if (this.pswObj.step == 2) {                if (this.checkPass(this.pswObj.spassword, psw)) {                    var title = document.getElementById("title");                    title.style.color = "#2CFF26";                    title.innerHTML = '解锁胜利';                     this.drawStatusPoint('#2CFF26');//小点点外圈高亮                    this.drawPoint('#2CFF26');                    this.drawLine('#2CFF26',this.lastPoint[this.lastPoint.length-1] , this.lastPoint);// 每帧画圆心                     api.closeFrame();                                     } else if (psw.length < 4) {                                        this.drawStatusPoint('red');                    this.drawPoint('red');                    this.drawLine('red',this.lastPoint[this.lastPoint.length-1] , this.lastPoint);// 每帧画圆心                     var title = document.getElementById("title");                    title.style.color = "red";                    title.innerHTML = '请连贯4个点';                 } else {                    this.drawStatusPoint('red');                    this.drawPoint('red');                    this.drawLine('red',this.lastPoint[this.lastPoint.length-1] , this.lastPoint);// 每帧画圆心                      var title = document.getElementById("title");                    title.style.color = "red";                    title.innerHTML = '手势明码谬误,请重试';                }            } else {                this.pswObj.step = 1;                this.pswObj.fpassword = psw;                document.getElementById('title').innerHTML = '再次输出';            }         }        H5lock.prototype.makeState = function() {            if (this.pswObj.step == 2) {                // document.getElementById('updatePassword').style.display = 'block';                //document.getElementById('chooseType').style.display = 'none';                 var title = document.getElementById("title");                title.style.color = "#87888a";                title.innerHTML = '请解锁';             } else if (this.pswObj.step == 1) {                //document.getElementById('chooseType').style.display = 'none';                // document.getElementById('updatePassword').style.display = 'none';            } else {                // document.getElementById('updatePassword').style.display = 'none';                //document.getElementById('chooseType').style.display = 'block';            }        }        H5lock.prototype.setChooseType = function(type){            chooseType = type;            init();        }        H5lock.prototype.updatePassword = function(){            window.localStorage.removeItem('passwordxx');            window.localStorage.removeItem('chooseType');            this.pswObj = {};            document.getElementById('title').innerHTML = '绘制解锁图案';            this.reset();        }        H5lock.prototype.initDom = function(){            var wrap = document.createElement('div');            var str = '<h4 id="title" class="title" style="color:#87888a">请绘制您的图形明码</h4>';             wrap.setAttribute('style','position: absolute;top:0;left:0;right:0;bottom:0;');            var canvas = document.createElement('canvas');            canvas.setAttribute('id','canvas');            canvas.style.cssText = 'background-color: #000;display: inline-block;margin-top: 76px;';            wrap.innerHTML = str;            wrap.appendChild(canvas);             var width = this.width || 320;            var height = this.height || 320;                        document.body.appendChild(wrap);             // 高清屏锁放            canvas.style.width = width + "px";            canvas.style.height = height + "px";            canvas.height = height * this.devicePixelRatio;            canvas.width = width * this.devicePixelRatio;                     }        H5lock.prototype.init = function() {            this.initDom();            this.pswObj = window.localStorage.getItem('passwordxx') ? {                step: 2,                spassword: JSON.parse(window.localStorage.getItem('passwordxx'))            } : {};            this.lastPoint = [];            this.makeState();            this.touchFlag = false;            this.canvas = document.getElementById('canvas');            this.ctx = this.canvas.getContext('2d');            this.createCircle();            this.bindEvent();        }        H5lock.prototype.reset = function() {            this.makeState();            this.createCircle();        }        H5lock.prototype.bindEvent = function() {            var self = this;            this.canvas.addEventListener("touchstart", function (e) {                e.preventDefault();// 某些android 的 touchmove不宜触发 所以减少此行代码                 var po = self.getPosition(e);                  for (var i = 0 ; i < self.arr.length ; i++) {                    if (Math.abs(po.x - self.arr[i].x) < self.r && Math.abs(po.y - self.arr[i].y) < self.r) {                         self.touchFlag = true;                        self.drawPoint(self.arr[i].x,self.arr[i].y);                        self.lastPoint.push(self.arr[i]);                        self.restPoint.splice(i,1);                        break;                    }                 }             }, false);             this.canvas.addEventListener("touchmove", function (e) {                if (self.touchFlag) {                    self.update(self.getPosition(e));                }             }, false);             this.canvas.addEventListener("touchend", function (e) {                 if (self.touchFlag) {                     self.touchFlag = false;                     self.storePass(self.lastPoint);                     setTimeout(function(){                         self.reset();                    }, 1000);                 }               }, false);             //  document.getElementById('updatePassword').addEventListener('click', function(){            //      self.updatePassword();            //   });        }})();

8、设置手势明码

登录胜利之后,在集体核心来设置手势明码。可通过参数设置来初始化明码强度。

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">    <title>H5lock</title>    <style type="text/css">        body {            text-align: center;            background-color: #000000;        }        .title {            /*color: #87888a;*/            margin-top: 85px;            font-size: 20px;            font-weight:lighter;        }        .reset{            position: relative;            top: 200px;            font-size: 20px;            text-align: center;        }    </style></head><body><script type="text/javascript" src="../script/setH5lock.js"></script><script type="text/javascript">    var opt = {        chooseType: 3, // 3 , 4 , 5,        width: 300, // lock wrap width        height: 300, // lock wrap height        container: 'element', // the id attribute of element        inputEnd: function (psw){} // when draw end param is password string    }    var lock = new H5lock(opt);    lock.init();</script></body></html>

9、批改明码

零碎默认设定了用户的初始密码,用户登录零碎后会提醒进行明码批改,批改后的明码进行了MD5加密,因为没有后盾零碎,所以明码的MD5加密,采纳了JS来进行加密。通过开发工具调试控制台装置js插件

装置胜利之后会在文件目录中显示

而后在用的中央间接引入即可。

import $md5 from '../../node_modules/js-md5/build/md5.min.js' var db = api.require('db');                    db.executeSql({                        name: 'doc',                        sql: "update user set password = '"+ md5(ret.text) +"' where id = 1"                    }, (ret, err)=> {                        // console.log(JSON.stringify(ret));                        // console.log(JSON.stringify(err));                        if (ret.status) {                            api.alert({                                title: '音讯揭示',                                msg: '明码批改胜利,请从新登陆',                            }, (ret, err) => {                                //革除用户信息                                api.removePrefs({                                    key: 'username'                                });                                api.removePrefs({                                    key: 'userid'                                });                                api.removePrefs({                                    key: 'password'                                });                                    $util.openWin({                                    name: 'login',                                    url: '../main/login.stml',                                    title: '',                                    hideNavigationBar:true                                });                            });                        } else {                                                    api.toast({                                msg:JSON.stringify(err)                            })                        }                    });

10、封装工具类插件 utils.js

在须要用到插件中通用办法的中央,间接援用即可。

import $util from "../../utils/utils.js"
const $util = {    openWin(param){        var param = {            name: param.name,            url: param.url,            title: param.title||'',            pageParam: param.pageParam||{},            hideNavigationBar: param.hideNavigationBar || false,            navigationBar:{                background:'#1492ff',                shadow: '#fff',                color: '#fff'            }        };        if (this.isApp()) {            api.openTabLayout(param);        } else {            api.openWin(param);        }    },    isApp(){        if (api.platform && api.platform == 'app') {            return true;        }        return false;    },    fitRichText(richtext, width){        var str = `<img style="max-width:${width}px;"`;        var result = richtext.replace(/\<img/gi, str);        return result;    },    isLogin(){        if(api.getPrefs({sync: true,key: 'userid'})){            return true;        }        return false;    },    openDataBase(){        var fs = api.require('fs');        var db = api.require('db');        db.subfile({            directory:'fs://db'        }, (ret, err)=> {            if(ret.status){                //关上数据库                db.openDatabase({                    name: 'doc',                    path: ret.files[0]                }, (ret, err)=> {                    if (ret.status) {                        // api.toast({                        //     msg:'关上数据库胜利!'                        // })                    } else {                        api.toast({                            msg:JSON.stringify(err)                        })                    }                });            }            else{                //拷贝文件                fs.copyTo({                    oldPath: 'widget://doc.db',                    newPath: 'fs://db/'                }, function(ret, err) {                    if (ret.status) {                        db.subfile({                            directory:'fs://db'                        }, (ret, err)=> {                            if(ret.status){                                //关上数据库                                db.openDatabase({                                    name: 'doc',                                    path: ret.files[0]                                }, (ret, err)=> {                                    if (ret.status) {                                     } else {                                        api.toast({                                            msg:JSON.stringify(err)                                        })                                    }                                });                            }                            else{                                api.toast({                                    msg:JSON.stringify(err)                                })                            }                        })                       } else {                        api.toast({                            msg:JSON.stringify(err)                        })                    }                });            }        })    }}export default $util;

11、用户性能权限

零碎分为2级用户,管理员账号和领导账号。通过角色ID进行辨别,管理员账号有信息的增删改查性能,领导账号只有信息的查问性能。

用于登录胜利之后将用户信息进行缓存。

//登陆APP            submit() {                                api.showProgress();                // console.log( "select id,username,password from user where username = '"+this.data.user+"' and password = '"+md5(this.data.psw)+"'");                var db = api.require('db');                db.selectSql({                    name: 'doc',                    sql: "select id,username,password,role from user where username = '"+this.data.user+"' and password = '"+md5(this.data.psw)+"'"                }, (ret, err)=> {                    // console.log(JSON.stringify(ret));                    // console.log(JSON.stringify(err));                    if (ret.status) {                        if(ret.data.length==1){                            api.setPrefs({key:'username',value:ret.data[0].username});                            api.setPrefs({key:'userid',value:ret.data[0].id});                            api.setPrefs({key:'password',value:ret.data[0].password});                            api.setPrefs({key:'role',value:ret.data[0].role});                             api.sendEvent({                                name: 'loginsuccess',                            });                            api.closeWin();                        }                        else{                            api.toast({                                msg:'登陆失败,请输出正确的用户名和明码'                            })                        }                                            } else {                                                api.toast({                            msg:JSON.stringify(err)                        })                    }                    api.hideProgress();                });            }

在须要验证用户权限的中央通过获取角色ID,进行逻辑判断。

if(api.getPrefs({sync: true,key: 'role'})=='99'){                    //增加编辑按钮                    api.setNavBarAttr({                        rightButtons: [{                            text: '编辑'                        }]                    });                    //监听右上角按钮点击事件                    api.addEventListener({                        name: 'navitembtn'                    }, (ret, err) => {                        if (ret.type == 'right') {                            $util.openWin({                                name: 'personedit',                                url: 'personedit.stml',                                title: '人员信息编辑',                                pageParam:{                                    id:this.data.id                                }                            });                        }                    });                }                else{                    //增加朗诵按钮                    api.setNavBarAttr({                        rightButtons: [{                            text: '朗诵'                        }]                    });                    //监听右上角按钮点击事件                    api.addEventListener({                        name: 'navitembtn'                    }, (ret, err) => {                        // console.log(JSON.stringify(this.data.info));                        if (ret.type == 'right') {                            var IFlyVoice = api.require('IFlyVoice');                            IFlyVoice.initSpeechSynthesizer((ret)=>{                            //   console.log(JSON.stringify(ret));                            });                            IFlyVoice.startSynthetic({                                text:this.data.info,                                commonPath_Android:'widget://res/android/common.jet',                                pronouncePath_Android:'widget://res/android/xiaoyan.jet',                                pronounceName:'xiaoyan',                                speed:40                            },(ret,err)=>{                                // console.log(JSON.stringify(ret));                                // console.log(JSON.stringify(err));                                if (ret.status) {                                    // console.log('合成胜利');                                } else {                                    // console.log(JSON.stringify(err));                                }                            });                        }                    });                }

12、双击退出应用程序

利用如果不做任何解决,在利用初始页面登程keyback事件,会弹出提示框提醒是否退出程序,体验感极差。针对此进行了优化,因为利用首页采纳了tablayout,所以只须要在tablayout默认选中项的索引页面中增加双击keyback事件的监听,并通过api.toast进行提醒。

在登录页面也须要增加此监听,应为用户退出登录之后,会主动跳转至登录页,如果不做解决,用户点击物理返回键就会导致用户在没有登录的状况下跳回上一页。加了此监听事件用户点击返回键不做解决,双击会提醒退出程序。
 

//监听返回  双击退出程序                api.setPrefs({                    key: 'time_last',                    value: '0'                });                api.addEventListener({                    name : 'keyback'                    }, (ret, err) => {                    var time_last = api.getPrefs({sync: true,key: 'time_last'});                    var time_now = Date.parse(new Date());                    if (time_now - time_last > 2000) {                        api.setPrefs({key:'time_last',value:time_now});                        api.toast({                            msg : '再按一次退出APP',                            duration : 2000,                            location : 'bottom'                        });                    } else {                        api.closeWidget({                            silent : true                        });                    }                });

13、利用动静权限

安卓10之后,对利用的权限要求进步,不在像老版本一样配置上就会主动获取,必须进行提醒。

根据官网给出的教程进行了动静权限的设置。

增加 mianfest.xml文件

<?xml version="1.0" encoding="UTF-8"?><manifest>    <application name="targetSdkVersion" value="28"/></manifest>

在零碎索引页进行动静权限获取揭示,本零碎只波及到了文件存储权限的获取,如须要获取多个权限,在List[]数组中持续增加须要的权限,而后依据增加的权限个数,做相应的几个判断即可。

let limits=[];                //获取权限                var resultList = api.hasPermission({                    list: ['storage']                });                if (resultList[0].granted) {                    // 已受权,能够持续下一步操作                } else {                    limits.push(resultList[0].name);                }                if(limits.length>0){                    api.requestPermission({                        list: limits,                    }, (res) => {                                            });                }