如何用App实现巡检业务数字化?以YonBuilder移动开发平台APICloud为例

巡检是企事业单位的常见场景之一,以消防检查为例,秋冬季节气温下降、生产繁忙,用火、用电、用气情况大量增加,消防安全事件多发,一款消防检查app可以有效减少繁复工作、提升巡检效率。本文将详细介绍如何使用YonBuilder移动开发平台开发消防检查助手app。

一、功能介绍

把消防检查过程中,需要手写填报的文档,在app端以表单填写进行实现;同时可以添加手写签名、关联照片,而且app端表单填报项目可进行下拉选择,极大提高了工作效率;表单填报完成之后可通过系统后台生成word模板文件,app端下载到手机,通过手机连接打印机,可打印纸质文件。App开发采用AVM框架,后台采用PHP。

功能要点:

1、场所登记,分为九小场所和合用场所登记;

2、监督检查记录;

3、责令整改通知书;

4、基本情况拍照,检查过程记录拍照;

5、后台针对上述数据进行多维度分析,导出Excel表格、Word模板文件。

二、思维导图

编辑切换为居中

添加图片注释,不超过 140 字(可选)

三、用到的模块

编辑切换为居中

添加图片注释,不超过 140 字(可选)

四、项目目录

编辑

添加图片注释,不超过 140 字(可选)

五、开发介绍

1、首页导航

系统首页使用tabLayout,可以将相关参数配置在JSON文件中,再在config.xml中将content的值设置成该JSON文件的路径。如果底部导航没有特殊需求这里强烈建议大家使用tabLayout为app进行布局,官方已经将各类手机屏幕及不同的分辨率进行了适配,免去了很多关于适配方面的问题。

编辑切换为居中

添加图片注释,不超过 140 字(可选)

{

"name": "root",

"textOffset": 6,

"color": "#999999",

"selectedColor": "#004494",

"scrollEnabled": false,

"hideNavigationBar": false,

"bgColor": "#fff",

"navigationBar": {

"background": "./images/navbk.png",

"shadow": "rgba(0,0,0,0)",

"color": "#fff",

"fontSize": 18,

"hideBackButton": true

},

"tabBar": {

"background": "#fff",

"shadow": "#eee",

"color": "#5E5E5E",

"selectedColor": "#004494",

"textOffset": 3,

"fontSize": 11,

"scrollEnabled": true,

"index": 0,

"preload": 1,

"frames": [

{

"title": "首页",

"name": "home",

"url": "./pages/index/home"

},

{

"title": "历史记录",

"name": "course",

"url": "./pages/history/records"

},

{

"title": "我的",

"name": "user",

"url": "./pages/user/wode"

}

],

"list": [

{

"text": "首页",

"iconPath": "./images/home.png",

"selectedIconPath": "./images/home-o.png"

},

{

"text": "历史记录",

"iconPath": "./images/his.png",

"selectedIconPath": "./images/his-o.png"

},

{

"text": "我的",

"iconPath": "./images/my.png",

"selectedIconPath": "./images/my-o.png"

}

]

}

}

由于导航使用的tablayout,所有app初始化需要执行的操作,只需要在第一个加载的页面执行即可全局响应。可通过 tabBar中的"index"字段来确定第一个需要加载的页面,通过"preload"来确定需要预加载几个页面。

2、动态权限

动态权限的获取在第一个初始化的页面执行即可。本项目中需要用到存储、相机、相册3个权限。用到的是官方的API方法hasPermission。

编辑切换为居中

添加图片注释,不超过 140 字(可选)

//提示获取存储权限

var limits=[];

var resultList = api.hasPermission({

list: ['storage','camera','photos']

});

if (resultList[0].granted) {

// 已授权,可以继续下一步操作

} else {

limits.push(resultList[0].name);

}

if (resultList[1].granted) {

// 已授权,可以继续下一步操作

} else {

limits.push(resultList[1].name);

}

if (resultList[2].granted) {

// 已授权,可以继续下一步操作

} else {

limits.push(resultList[2].name);

}

if(limits.length>0){

api.requestPermission({

list: limits,

}, function(res) {

// console.log(JSON.stringify(res));

});

}

manifest.xml文件,关于targetSdkVersion的值的大小,这里可以根据下文图片中的说明,结合项目需要上架的平台自行设置。

编辑

添加图片注释,不超过 140 字(可选)

编辑切换为居中

添加图片注释,不超过 140 字(可选)

编辑切换为居中

添加图片注释,不超过 140 字(可选)

<?xml version="1.0" encoding="UTF-8"?>

<manifest>

<application name="targetSdkVersion" value="28"/>

</manifest>

3、消息事件

本项目中通过发送事件sendEvent和监听事件addEventListener,消息事件要学会合理运用来提升app中各个页面之间交互的体验。下面对实现在表单提交成功之后刷新列表页、登陆成功之后跳转页面时重新加载用户信息的具体操作进行说明。

表单数据提交成功之后,在回调里发送事件"addbase",然后关闭页面,跳转至列表页,在列表页的apiready中监听“addbase”事件,在监听成功回调中执行刷新列表的操作。

onsubmit(e){

let result = e.detail.value;

this.data.dwmc = result.dwmc?result.dwmc:this.data.dwmc;

this.data.dwdz = result.dwdz?result.dwdz:this.data.dwdz;

//省略其他字段

let params = {

data:{

values:{

secret: Config.secret,

userid: api.getPrefs({sync: true,key: 'userid'}),

partid: api.getPrefs({sync: true,key: 'partid'}),

id:this.data.id,

dwmc:this.data.dwmc,

dwdz:this.data.dwdz,

//省略

}

}

}

api.showProgress();

Model.addbase(params, (res,err) => {

// console.log(JSON.stringify(res));

// console.log(JSON.stringify(err));

if (res && res.flag == 'Success') {

api.toast({

msg:'登记成功'

});

api.sendEvent({

name: 'addbase',

});

api.closeWin();

} else {

api.toast({

msg:res.msg

})

}

api.hideProgress();

});

},

apiready(){

this.data.tab=api.pageParam.tab;

this.data.tabtitle=api.pageParam.tabtitle;

this.data.refresherTriggered = true;

this.loadData(false);

api.addEventListener({

name: 'setuserinfo'

}, (ret, err) => {

this.loadData(false);

});

//监听增加修改基本信息

api.addEventListener({

name: 'addbase'

}, (ret, err) => {

this.loadData(false);

});

api.addEventListener({

name: 'delbase'

}, (ret, err) => {

this.loadData(false);

});

},

4、接口调用

将接口调用和接口配置分别封装2个JS插件,model.js和config.js。统一管理,避免了在每个页面进行接口调用时都重复写一遍代码,有效简化了每个功能页面的代码量,只需要在回调里专注写自己的业务逻辑即可。

import $util from "../../utils/util.js"

import {Model} from "../../utils/model.js"

import {Config} from "../../utils/config.js"

config.js

class Config{

constructor(){}

}

Config.restUrl = 'http://xiaofang.*******.cn/api.php/Home/Index';

Config.secret = '99d0fd93-***************************';

Config.addbase ='/addbase';//登记基本信息表

Config.querylist ='/querylist';//查询登记单位列表

Config.querybasebyid ='/querybasebyid';//查询登记单位基本信息详情

Config.querybaseinfobyid ='/querybaseinfobyid';//查询登记单位基本信息详情

Config.exportbase ='/exportbase';//下载登记单位基本信息

Config.deletebasebyid ='/deletebasebyid';//删除登记单位基本信息

Config.login ='/login';//登陆

Config.getpart ='/getpart';//获取单位列表

Config.register ='/register';//用户注册

/**省略**/

Config.checkUserStatus ='/checkUserStatus';//获取用户状态

export {Config};

model.js

import {Config} from './config.js';

class Model {

constructor() {}

}

/*登记基本信息表 */

Model.addbase = function (param, callback){

param.url = Config.addbase;

param.method = 'post';

this.request(param, callback);

}

/*查询登记单位列表 */

Model.querylist = function (param, callback){

param.url = Config.querylist;

param.method = 'post';

this.request(param, callback);

}

/*查询登记单位基本信息详情 */

Model.querybasebyid = function (param, callback){

param.url = Config.querybasebyid;

param.method = 'post';

this.request(param, callback);

}

/*查询登记单位基本信息详情 */

Model.querybaseinfobyid = function (param, callback){

param.url = Config.querybaseinfobyid;

param.method = 'post';

this.request(param, callback);

}

/*下载登记单位基本信息 */

Model.exportbase = function (param, callback){

param.url = Config.exportbase;

param.method = 'post';

this.request(param, callback);

}

/*删除登记单位基本信息 */

Model.deletebasebyid = function (param, callback){

param.url = Config.deletebasebyid;

param.method = 'post';

this.request(param, callback);

}

/*登陆模块 */

Model.login = function (param, callback){

param.url = Config.login;

param.method = 'post';

this.request(param, callback);

}

/**省略**/

/*获取用户状态 */

Model.checkUserStatus = function (param, callback){

param.url = Config.checkUserStatus;

param.method = 'post';

this.request(param, callback);

}

Model.request = function(p, callback) {

var param = p;

if (!param.headers) {

param.headers = {};

}

if (param.data && param.data.body) {

param.headers['Content-Type'] = 'application/json; charset=utf-8';

}

if (param.url) {

param.url = Config.restUrl + param.url;

}

api.ajax(param, function(ret, err) {

callback && callback(ret, err);

});

}

export {Model};

5、数据列表及分页查询

数据列表的展示,采用scroll-view标签,通过onrefresherrefresh,onrefresherrefresh触发的事件中进行数据列表的刷新和分页查询。通过refresher-triggered这个属性来设置当前下拉刷新状态,true 表示下拉刷新已经被触发,false 表示下拉刷新未被触发。如果想默认下拉刷新一下可以在apiready中将之设置为true,以此来代替执行数据刷新操作。

如果列表中的每一项的元素较少,而且没有样式的特殊要求,也可以使用list-view来实现。

下面是单位列表的完整页面代码。其他页面的列表基本功能都是一致的,只是在每一项的样式及参数个数上存在差异。

<template name='unitlist'>

<view class="page">

<scroll-view class="main" scroll-y enable-back-to-top refresher-enabled refresher-triggered={refresherTriggered} onrefresherrefresh={this.onrefresherrefresh} onscrolltolower={this.onscrolltolower}>

<view class="search-box">

<input class="serach-input" placeholder="请输入单位名称检索" confirm-type="search" onconfirm="onconfirm" οninput={this.getKey}/>

<text class="search-btn" οnclick="onconfirm">搜索</text>

</view>

<view class="item-box">

<view class="item" data-id={item.id} οnclick={this.openTable} v-for="(item, index) in list">

<text class="item-content">{{item.name}}</text>

<view class="item-sub">

<view class="item-sub-box">

<image class="item-sub-ico" src="../../images/DW.png" mode="aspectFit"></image>

<text class="item-info">{{item.address}}</text>

</view>

<view class="item-sub-box">

<image class="item-sub-ico" src="../../images/CT.png" mode="aspectFit"></image>

<text class="item-info">{{item.type}}</text>

</view>

</view>

</view>

</view>

<view class="footer">

<text class="loadDesc">{loadStateDesc}</text>

</view>

</scroll-view>

</view>

</template>

<script>

import {Model} from '../../utils/model.js'

import {Config} from "../../utils/config.js"

import $util from "../../utils/util.js"

export default {

name: 'unitlist',

data() {

return{

list:[],

skip: 0,

loading: false,

refresherTriggered: false,

haveMoreData: true,

tab:'',

tabtitle:'',

key:''

}

},

computed: {

loadStateDesc(){

if (this.data.loading || this.data.haveMoreData) {

return '加载中...';

} else if (this.list.length > 0) {

return '没有更多啦';

} else {

return '暂时没有内容';

}

}

},

methods: {

apiready(){

this.data.tab=api.pageParam.tab;

this.data.tabtitle=api.pageParam.tabtitle;

this.data.refresherTriggered = true;

this.loadData(false);

api.addEventListener({

name: 'setuserinfo'

}, (ret, err) => {

this.loadData(false);

});

//监听增加修改基本信息

api.addEventListener({

name: 'addbase'

}, (ret, err) => {

this.loadData(false);

});

api.addEventListener({

name: 'delbase'

}, (ret, err) => {

this.loadData(false);

});

},

loadData(loadMore) {

this.data.loading = true;

var that = this;

var limit = 20;

var skip = loadMore?that.data.skip+1:0;

let params = {

data:{

values:{

secret: Config.secret,

userid: api.getPrefs({sync: true,key: 'userid'}),

roleid: api.getPrefs({sync: true,key: 'roleid'}),

partid: api.getPrefs({sync: true,key: 'partid'}),

skip: skip,

limit: limit,

key:this.data.key

}

}

}

api.showProgress();

Model.querylist(params, (res,err) => {

// console.log(JSON.stringify(res));

// console.log(JSON.stringify(err));

if (res && res.flag == 'Success') {

let lists = res.data;

that.data.haveMoreData = lists.length == limit;

if (loadMore) {

that.data.list = that.data.list.concat(lists);

} else {

that.data.list = lists;

}

that.data.skip = skip;

} else {

that.data.haveMoreData = false;

}

that.data.loading = false;

that.data.refresherTriggered = false;

api.hideProgress();

});

},

//打开填写表格

openTable(e) {

var id = e.currentTarget.dataset.id;

$util.openWin({

name: this.data.tab,

url: '../index/'+this.data.tab+'.stml',

title: this.data.tabtitle,

pageParam:{

id:id

}

});

},

/*下拉刷新页面*/

onrefresherrefresh(){

this.data.refresherTriggered = true;

this.loadData(false);

},

onscrolltolower() {

if (this.data.haveMoreData) {

this.loadData(true);

}

},

getKey(e){

this.data.key = e.detail.value;

},

onconfirm(){

this.loadData(false);

}

}

}

</script>

<style>

.main {

height: 100%;

background-color: #eaf0fa;

}

.item-box{

background-color: #fff;

margin: 5px;

}

.item{

border-bottom: 1px solid #efefef;

margin: 0 10px;

justify-content:flex-start;

flex-direction:column;

}

.item-content{

font-size: 17PX;

margin-top: 10px;

}

.item-info{

font-size: 13PX;

color: #666;

margin: 10px 0;

}

.item-sub{

justify-content:space-between;

flex-direction:row;

}

.footer {

height: 44px;

justify-content: center;

align-items: center;

}

.loadDesc {

width: 200px;

text-align: center;

}

.item-sub-ico{

width: 15px;

margin: 10px 0;

}

.item-sub-box{

flex-flow: row nowrap;

}

.search-box{

flex-flow: row nowrap;

align-items: center;

background-color: #2c6ddc;

border-radius: 5px;

margin: 5px;

}

.serach-input{

padding: 5px;

width: 80%;

height: 50px;

border-top-left-radius: 5px;

border-bottom-left-radius: 5px;

}

.search-btn{

width: 20%;

text-align: center;

color: #ffffff;

}

</style>

6、双击退出程序

在首页页面和登陆页面中,添加双击退出程序功能,避免出现单击退出键出现不必要的页面跳转失误。此监听事件要在apiready中执行。

//监听返回 双击退出程序

api.setPrefs({

key: 'time_last',

value: '0'

});

api.addEventListener({

name : 'keyback'

}, function(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

});

}

});

7、账号有效性确认

由于后台针对用户账号,启用了停用功能,后台一旦设置账号停用,app中也应相应地将用户进行退出系统操作。此操作在首页的apiready中进行执行。

isLogin(){

if(!api.getPrefs({sync: true,key:'userid'})){

$util.openWin({

name: 'login',

url: '../user/login.stml',

title: '',

hideNavigationBar:true

});

}

else{

let params = {

data:{

values:{

secret: Config.secret,

userid: api.getPrefs({sync: true,key:'userid'})

}

}

}

api.showProgress();

Model.checkUserStatus(params, (res,err) => {

// console.log(JSON.stringify(res));

// console.log(JSON.stringify(err));

if (res && res.flag == 'Success') {

if(ret.data=='02'){

//清楚缓存用户数据

api.removePrefs({

key: 'name'

});

api.removePrefs({

key: 'userid'

});

api.removePrefs({

key: 'partname'

});

api.removePrefs({

key: 'partid'

});

api.removePrefs({

key: 'role'

});

api.removePrefs({

key: 'rolename'

});

api.removePrefs({

key: 'username'

});

//用户已停用 退出系统

$util.openWin({

name: 'login',

url: '../user/login.stml',

title: '',

hideNavigationBar:true

});

}

} else {

//清除用户信息

api.removePrefs({

key: 'name'

});

api.removePrefs({

key: 'userid'

});

api.removePrefs({

key: 'partname'

});

api.removePrefs({

key: 'partid'

});

api.removePrefs({

key: 'role'

});

api.removePrefs({

key: 'rolename'

});

api.removePrefs({

key: 'username'

});

//用户异常 退出重新登陆

$util.openWin({

name: 'login',

url: '../user/login.stml',

title: '',

hideNavigationBar:true

});

}

api.hideProgress();

});

}

}

8、表单提交、回显

表单使用的是AVM的 from组件,通过onsubmit进行表单数据提交。其中主要用到了input、textarea、radio、checkbox;每个控件的具体使用方法,在官方文档中否有详细的介绍。下面就具体的代码示例进行展示。

编辑切换为居中

添加图片注释,不超过 140 字(可选)

页面代码

<template name='addbase'>

<scroll-view class="page" scroll-y>

<form οnsubmit={this.onsubmit}>

<view class="item">

<text>单位名称:</text>

<input name="dwmc" value={this.data.dwmc} placeholder="请输入单位名称"/>

</view>

<view class="item">

<text>单位地址:</text>

<input name="dwdz" value={this.data.dwdz} placeholder="请输入单位详细地址"/>

</view>

<checkbox-group class="item" name="dwlb">

<text>单位类别:</text>

<view class="item-checkbox">

<label v-for="item in dwlbarr">

<checkbox value={item} v-bind:checked="this.data.seldwlb.indexOf(item)!=-1?true:false"/>

<text>{item}</text>

</label>

</view>

<input name="dwlb_qt" value={this.data.dwlb_qt} placeholder="请输入单位类别"/>

</checkbox-group>

<checkbox-group class="item" name="dwxz">

<text>单位性质:</text>

<view class="item-checkbox">

<label v-for="item in dwxzarr">

<checkbox value={item} v-bind:checked="this.data.seldwxz.indexOf(item)!=-1?true:false"/>

<text>{item}</text>

</label>

</view>

</checkbox-group>

<view class="item">

<text>职工总数:</text>

<input name="zgzs" value={this.data.zgzs} keyboard-type="number" placeholder="请输入单位职工总数"/>

</view>

<view class="item">

<text>消防安全责任人:</text>

<input name="xfaqzrr_xm" value={this.data.xfaqzrr_xm} placeholder="请输入负责人姓名"/>

<input name="xfaqzrr_zw" value={this.data.xfaqzrr_zw} placeholder="请输入负责人职务"/>

<input name="xfaqzrr_dh" value={this.data.xfaqzrr_dh} keyboard-type="number" placeholder="请输入负责人电话"/>

</view>

<view class="item">

<text>消防安全管理人:</text>

<input name="xfaqglr_xm" value={this.data.xfaqglr_xm} placeholder="请输入管理人姓名"/>

<input name="xfaqglr_zw" value={this.data.xfaqglr_zw} placeholder="请输入管理人职务"/>

<input name="xfaqglr_dh" value={this.data.xfaqglr_dh} keyboard-type="number" placeholder="请输入管理人电话"/>

</view>

<view class="item">

<text>专兼职防火干部:</text>

<input name="zjzfhgb_xm" value={this.data.zjzfhgb_xm} placeholder="请输入专兼职防火干部姓名"/>

<input name="zjzfhgb_zw" value={this.data.zjzfhgb_zw} placeholder="请输入专兼职防火干部职务"/>

<input name="zjzfhgb_dh" value={this.data.zjzfhgb_dh} keyboard-type="number" placeholder="请输入专兼职防火干部电话"/>

</view>

<view class="item">

<label class="label-box">

<text class="label-title">建筑层数(层)</text>

<input class="label-input" name="jzcs" value={this.data.jzcs} keyboard-type="number" placeholder="请输入建筑层数(层)"/>

</label>

<label class="label-box">

<text class="label-title">所在层数(层)</text>

<input class="label-input" name="szcs" value={this.data.szcs} keyboard-type="number" placeholder="请输入所在层数(层)"/>

</label>

<label class="label-box">

<text class="label-title">建筑高度(m)</text>

<input class="label-input" name="jzgd" value={this.data.jzgd} keyboard-type="number" placeholder="请输入建筑高度(m)"/>

</label>

<label class="label-box">

<text class="label-title">总建筑面积(㎡)</text>

<input class="label-input" name="zjzmj" value={this.data.zjzmj} keyboard-type="decimal" placeholder="请输入总建筑面积(㎡)"/>

</label>

<label class="label-box">

<text class="label-title">每层建筑面积(㎡)</text>

<input class="label-input" name="mcjzmj" value={this.data.mcjzmj} keyboard-type="decimal" placeholder="请输入每层建筑面积(㎡)"/>

</label>

<label class="label-box">

<text class="label-title">营业面积(㎡)</text>

<input class="label-input" name="yymj" value={this.data.yymj} keyboard-type="decimal" placeholder="请输入营业面积(㎡)"/>

</label>

<label class="label-box">

<text class="label-title">检查时间</text>

<input class="label-input" name="jcsj" value={this.data.jcsj} keyboard-type="number" placeholder="请输入检查时间"/>

</label>

<label class="label-box">

<text class="label-title">投入使用时间</text>

<input class="label-input" name="trsysj" value={this.data.trsysj} keyboard-type="number" placeholder="请输入投入使用时间"/>

</label>

<label class="label-box">

<text class="label-title">开业时间</text>

<input class="label-input" name="kysj" value={this.data.kysj} keyboard-type="number" placeholder="请输入开业时间"/>

</label>

<label class="label-box">

<text class="label-title">租赁房屋户主姓名</text>

<input class="label-input" name="zlfwhzxm" value={this.data.zlfwhzxm} placeholder="请输入租赁房屋户主姓名"/>

</label>

</view>

<view class="item">

<text>生产经营状况:</text>

<input name="scjyzk" value={this.data.scjyzk} placeholder="请输入单位生产经营状况"/>

</view>

<view class="item">

<text>隶属社区:</text>

<input name="lssq" value={this.data.lssq} placeholder="请输入单位隶属社区"/>

</view>

<radio-group class="item" name="ssyjfl">

<text>三色预警分类:</text>

<view class="item-checkbox">

<label v-for="item in ssyjflarr">

<radio value={item} v-bind:checked="this.data.ssyjfl==item?true:false"/>

<text>{item}</text>

</label>

</view>

</radio-group>

<view class="item">

<text>消防设置种类及数量:</text>

<textarea name="xfsszljsl" value={this.data.xfsszljsl} placeholder="请输入消防设置种类及数量"/>

</view>

<view class="item">

<text>检查登记情况:</text>

<textarea name="jcqkdj_1" value={this.data.jcqkdj_1} placeholder="请输入检查登记情况"/>

<textarea name="jcqkdj_2" value={this.data.jcqkdj_2} placeholder="请输入检查登记情况"/>

<textarea name="jcqkdj_3" value={this.data.jcqkdj_3} placeholder="请输入检查登记情况"/>

<textarea name="jcqkdj_4" value={this.data.jcqkdj_4} placeholder="请输入检查登记情况"/>

</view>

<view class="item">

<text>填表说明:</text>

</view>

<button class="btn-submit" type="submit">提交</button>

</form>

<button v-show="isdelete" class="btn-delete" type="button" @click="delbase">删除</button>

</scroll-view>

</template>

表单提交

data() {

return{

dwmc:'',

dwdz:'',

dwlb:'',

dwxz:'',

zgzs:0,

xfaqzrr_xm:'',

xfaqzrr_zw:'',

xfaqzrr_dh:'',

xfaqglr_xm:'',

xfaqglr_zw:'',

xfaqglr_dh:'',

zjzfhgb_xm:'',

zjzfhgb_zw:'',

zjzfhgb_dh:'',

jzcs:null,

jzgd:null,

zjzmj:null,

mcjzmj:null,

szcs:null,

yymj:null,

jcsj:'',

trsysj:'',

kysj:'',

zlfwhzxm:'',

scjyzk:'',

lssq:'',

ssyjfl:'',

xfsszljsl:'',

jcqkdj_1:'',

jcqkdj_2:'',

jcqkdj_3:'',

jcqkdj_4:'',

dwlb_qt:'',

id:0,

ssyjflarr:['红','黄','绿'],

dwlbarr:['购物场所','餐饮场所','住宿场所','公共娱乐场所','休闲健身场所','医疗场所','教学场所','生产加工企业','易燃易爆危险品销售、储存场所','其他'],

dwxzarr:['国有','集体','股份合作公司','股份有限公司','港澳台投资','中外合资','个体私营','其他'],

seldwlb:[],

seldwxz:[],

isdelete:false,

dateList: [$formatDate.lastYear30(),[1,2,3,4,5,6,7,8,9,10,11,12],[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31]],

jcsjSelectorValue:[0,0,0],

trsysjSelectorValue:[0,0,0],

kysjSelectorValue:[0,0,0]

}

},

数据回显

//查询已添加的数据

loadData(){

let params = {

data:{

values:{

secret: Config.secret,

id:this.data.id

}

}

}

api.showProgress();

Model.querybasebyid(params, (res,err) => {

// console.log(JSON.stringify(res));

// console.log(JSON.stringify(err));

if (res && res.flag == 'Success') {

//填充数据

let result=res.data;

this.data.dwmc = result.dwmc?result.dwmc:this.data.dwmc;

this.data.dwdz = result.dwdz?result.dwdz:this.data.dwdz;

this.data.seldwlb = result.dwlb?result.dwlb.split(','):this.data.dwlb;

this.data.dwlb_qt = result.dwlb_qt?result.dwlb_qt:this.data.dwlb_qt;

this.data.seldwxz = result.dwxz?result.dwxz.split(','):this.data.dwxz;

this.data.zgzs = result.zgzs?result.zgzs:this.data.zgzs;

this.data.xfaqzrr_xm = result.xfaqzrr_xm?result.xfaqzrr_xm:this.data.xfaqzrr_xm;

this.data.xfaqzrr_zw = result.xfaqzrr_zw?result.xfaqzrr_zw:this.data.xfaqzrr_zw;

this.data.xfaqzrr_dh = result.xfaqzrr_dh?result.xfaqzrr_dh:this.data.xfaqzrr_dh;

this.data.xfaqglr_xm = result.xfaqglr_xm?result.xfaqglr_xm:this.data.xfaqglr_xm;

this.data.xfaqglr_zw = result.xfaqglr_zw?result.xfaqglr_zw:this.data.xfaqglr_zw;

this.data.xfaqglr_dh = result.xfaqglr_dh?result.xfaqglr_dh:this.data.xfaqglr_dh;

this.data.zjzfhgb_xm = result.zjzfhgb_xm?result.zjzfhgb_xm:this.data.zjzfhgb_xm;

this.data.zjzfhgb_zw = result.zjzfhgb_zw?result.zjzfhgb_zw:this.data.zjzfhgb_zw;

this.data.zjzfhgb_dh = result.zjzfhgb_dh?result.zjzfhgb_dh:this.data.zjzfhgb_dh;

this.data.jzcs = result.jzcs?result.jzcs:this.data.jzcs;

this.data.jzgd = result.jzgd?result.jzgd:this.data.jzgd;

this.data.zjzmj = result.zjzmj?result.zjzmj:this.data.zjzmj;

this.data.mcjzmj = result.mcjzmj?result.mcjzmj:this.data.mcjzmj;

this.data.szcs = result.szcs?result.szcs:this.data.szcs;

this.data.yymj = result.yymj?result.yymj:this.data.yymj;

this.data.jcsj = result.jcsj?result.jcsj:this.data.jcsj;

this.data.trsysj = result.trsysj?result.trsysj:this.data.trsysj;

this.data.kysj = result.kysj?result.kysj:this.data.kysj;

this.data.zlfwhzxm = result.zlfwhzxm?result.zlfwhzxm:this.data.zlfwhzxm;

this.data.scjyzk = result.scjyzk?result.scjyzk:this.data.scjyzk;

this.data.lssq = result.lssq?result.lssq:this.data.lssq;

this.data.ssyjfl = result.ssyjfl?result.ssyjfl:this.data.ssyjfl;

this.data.xfsszljsl = result.xfsszljsl?result.xfsszljsl:this.data.xfsszljsl;

this.data.jcqkdj_1 = result.jcqkdj_1?result.jcqkdj_1:this.data.jcqkdj_1;

this.data.jcqkdj_2 = result.jcqkdj_1?result.jcqkdj_2:this.data.jcqkdj_2;

this.data.jcqkdj_3 = result.jcqkdj_1?result.jcqkdj_3:this.data.jcqkdj_3;

this.data.jcqkdj_4 = result.jcqkdj_1?result.jcqkdj_4:this.data.jcqkdj_4;

} else {

api.toast({

msg:res.msg

})

}

api.hideProgress();

});

},

9、拍照及上传照片,图片预览

拍照使用的是FNPhotograph模块,自带UI的open接口,可选择拍摄照片的质量,可配置使用摄像头方向,同时可配置照片不用存储到相册中、禁用显示相册按钮,保证用户只能现场拍照,可以满足项目需求。

图片上传失败

​重试

项目中很多页面涉及到图片预览功能,分为单图预览和多图预览。图片预览采用的是photoBrowser模块。photoBrowser是一个图片浏览器,支持单张、多张图片查看的功能,可放大缩小图片,支持本地和网络图片资源。若是网络图片资源则会被缓存到本地,缓存到本地上的资源可以通过clearCache接口手动清除。同时本模块支持横竖屏显示,在本app支持横竖屏的情况下,本模块底层会自动监听当前设备的位置状态,自动适配横竖屏以展示图片。

编辑切换为居中

添加图片注释,不超过 140 字(可选)

getPicture(e){

this.data.type = e.currentTarget.dataset.type;

api.actionSheet({

title: '请选择',

cancelTitle: '取消',

buttons: ['选择图片','图片预览']

}, (ret, err)=> {

// console.log(JSON.stringify(ret));

// console.log(JSON.stringify(err));

// var index = ret.buttonIndex;

if(ret.buttonIndex==1){

var FNPhotograph = api.require('FNPhotograph');

FNPhotograph.open({

album: true ,

quality: 'medium'

}, (ret)=>{

// console.log(JSON.stringify(ret));

if(ret.eventType=='takePhoto'){

FNPhotograph.close();

//上传图片

let params = {

data:{

values:{

secret: Config.secret,

baseid:this.data.baseid,

type:this.data.type

},

files:{

'file':ret.imagePath,

}

}

}

api.showProgress();

Model.addbasepicbyid(params, (res,err) => {

// console.log(JSON.stringify(res));

// console.log(JSON.stringify(err));

if (res && res.flag == 'Success') {

if(this.data.type=='01'){

this.data.src1=res.data;

}

else if(this.data.type=='02'){

this.data.src2=res.data;

}

else if(this.data.type=='03'){

this.data.src3=res.data;

}

else if(this.data.type=='04'){

this.data.src4=res.data;

}

} else {

api.toast({

msg:res.msg

})

}

api.hideProgress();

});

}

});

}

else if(ret.buttonIndex==2){

//图片预览

let src='';

if(this.data.type=='01'){

src=this.data.src1;

}

else if(this.data.type=='02'){

src=this.data.src2;

}

else if(this.data.type=='03'){

src=this.data.src3;

}

else if(this.data.type=='04'){

src=this.data.src4;

}

var photoBrowser = api.require('photoBrowser');

photoBrowser.open({

images: [

src

],

placeholderImg: 'widget://res/img/apicloud.png',

bgColor: '#000'

}, (ret, err) => {

if (ret) {

if(ret.eventType=='click'){

photoBrowser.close();

}

} else {

api.toast({

msg:'图片预览失败'

})

}

});

}

});

}

10、页面之间的跳转和参数传递

封装工具类until.js,在其中定义了openWin方法来实现页面之间的跳转。页面跳转时参数的传递通过pageParam添加参数进行,在跳转到的页面通过api.pageParam.xxx在apiready中进行接收。

<view class="tab-item" data-url="addbase" data-title="九小场所登记" tapmode @click="openPage">

<image class="tab-item-logo" src="../../images/JB.png" mode="scaleToFill"></image>

<text class="tab-item-title"> 九小场所登记</text>

</view>

methods: {

apiready(){//like created

this.data.id=api.pageParam.id;

},

openPage(e){

let title = e.currentTarget.dataset.title;

let url = e.currentTarget.dataset.url;

$util.openWin({

name: url,

url: '../index/'+url+'.stml',

title: title,

pageParam:{

id:this.data.id

}

});

}

}

util.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:'../../images/navbk.png',

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;

}

}

export default $util;

11、导航栏自定义按钮点击事件

如果是首页加载的页面,可以在首页中通过索引index进行判断然后分别配置;如果在单独的页面中需要添加的话,可在页面的apiready中进行配置。

编辑切换为居中

添加图片注释,不超过 140 字(可选)

首页中的配置,需要注意的是,如果是页面直接跳转,配置多个页面时没有问题;但如果按钮事件是执行某个页面具体的方法时,就会出现问题。这里建议如果按钮事件是执行某个页面具体的方法,不要在首页中配置,可在页面中通过其他方式进行实现。因为首页配置的内容会在全局使用,而且加载成功之后,通过tabbar切换页面的时候,是不会进行页面刷新操作的。

apiready() {

//导航设置

api.addEventListener({

name:'tabitembtn'

}, (ret) => {

api.setTabBarAttr({

index: ret.index

});

if(ret.index==0){

api.setTabLayoutAttr({

hideNavigationBar:true,

animated:false

});

}

else if(ret.index==2){

api.setNavBarAttr({

rightButtons: [{

iconPath:'widget://image/chart.png'

}]

});

api.setTabLayoutAttr({

hideNavigationBar:false,

animated:false

});

api.addEventListener({

name:'navitembtn'

}, (ret)=>{

if(ret.type=='right'){

$util.openWin({

name: 'chart',

url: 'widget://html/test.html',

title: '统计分析',

pageParam:{

}

})

}

})

}

else{

api.setTabLayoutAttr({

hideNavigationBar:false,

animated:false

});

api.setNavBarAttr({

rightButtons: [{

}]

});

api.addEventListener({

name:'navitembtn'

}, (ret)=>{

})

}

});

},

单独页面中的配置

apiready(){

//添加右上角按钮

api.setNavBarAttr({

rightButtons: [{

text: '添加'

}]

});

//监听右上角按钮点击事件

api.addEventListener({

name: 'navitembtn'

}, (ret, err)=> {

if (ret.type == 'right') {

$util.openWin({

name: 'addjcpics',

url: 'addjcpics.stml',

title: '添加检查记录照片',

pageParam:{

baseid:this.data.baseid

}

});

}

});

},

12、手写签名

手写签名用到的是drawingBoard模块。开发者可自定义固定宽高(w、h)的 “frame”,该“frame”即是可手写签名的背景透明的画板,可将此画板固定在指定的 frame 或 window 上,从而自定义出符合自己需求的各种UI效果的签名功能。

编辑切换为居中

添加图片注释,不超过 140 字(可选)

<template name='signature'>

<view class="page">

<view class="flowbottom">

<button class="btn-clear" tapmode @click="clear">重写</button>

<button class="btn" tapmode @click="submit" disabled={this.data.btn_disabled}>确定</button>

</view>

</view>

</template>

<script>

export default {

name: 'signature',

data() {

return{

btn_disabled:false,

type:''

}

},

methods: {

apiready(){

this.data.type = api.pageParam.type;

var drawingBoard = api.require('drawingBoard');

drawingBoard.open({

rect: {

x: 10,

y: 100,

w: api.frameWidth-20,

h: (api.frameWidth-20)/2

},

styles: {

brush: {

color: '#000000',

width: 3

},

bgColor: '#f0f0f0'

},

fixedOn: api.frameName

});

},

clear(){

var drawingBoard = api.require('drawingBoard');

drawingBoard.clear();

},

submit(){

this.data.btn_disabled = true;

var drawingBoard = api.require('drawingBoard');

drawingBoard.save({

savePath: 'fs://drawingBoard/'+Date.now()+'.png',

copyToAlbum: false

}, (ret)=> {

// console.log(JSON.stringify(ret));

if(ret.absolutePath=='undefined'){

this.data.btn_disabled = false;

api.toast({

msg:'签名失败,请稍后再试'

});

}

else{

//

api.sendEvent({

name: 'singture_success',

extra: {

src: ret.absolutePath,

type:this.data.type

}

});

drawingBoard.close();

api.closeWin();

}

});

}

}

}

</script>

<style>

.page {

display: flex;

flex-flow: row nowrap;

height: 100%;

width: 100%;

background-color: #eaf0fa;

}

.flowbottom{

width: 100%;

align-self: flex-end;

padding: 10px;

}

.btn {

display: block;

height: 50px;

width: 100%;

background:#1492ff;

border-radius: 5px;

color: #fff;

font-size: 20px;

font-weight: bolder;

padding: 0;

margin-top: 10px;

}

.btn-clear {

display: block;

height: 50px;

width: 100%;

background:#ff0000;

border-radius: 5px;

color: #fff;

font-size: 20px;

font-weight: bolder;

padding: 0;

margin-top: 10px;

}

</style>

13、清除缓存

由于项目中有很多拍照、查看照片场景,在使用的过程中,就会产生很多的缓存,导致应用反应变慢。所以在应用中增加了清除缓存功能,用的是官方提供的api.clearCache。

在个人中心 apiready中先获取到应用中的缓存,然后点击清除缓存按钮即可清除。

<view class="item" οnclick="clearCache">

<image class="item-icon" src="../../images/w_02.png" mode="widthFix"></image>

<text class="item-title">缓存</text>

<text class="item-right-cache">{cache}M</text>

</view>

apiready(){

//获取APP缓存 异步返回结果:

api.getCacheSize((ret) => {

this.data.cache = parseInt(ret.size/1024/1024).toFixed(1);

});

},

clearCache(){

api.clearCache(() => {

api.toast({

msg: '清除完成'

});

});

this.data.cache=0;

},

14、下载并打开word文件

点击下载word文件按钮,调用系统接口,接口会把文件的路径进行返回,先通过api.download将文件下载到本地,然后通过模块docInteraction调用第三方app打开文档。

编辑切换为居中

添加图片注释,不超过 140 字(可选)

//监听右上角按钮点击事件

api.addEventListener({

name: 'navitembtn'

}, (ret, err) => {

if (ret.type == 'right') {

let params = {

data:{

values:{

secret: Config.secret,

id:this.data.id

}

}

}

api.showProgress();

Model.exportbase(params, (res,err) => {

if (res && res.flag == 'Success') {

//下载文件

api.download({

url: res.data,

report: true,

cache: false,

allowResume: true

}, (ret, err)=> {

// console.log(JSON.stringify(ret));

if (ret.state == 1) {

//下载成功 跳转WORD预览页面

var docInteraction =

api.require('docInteraction');

docInteraction.open({

path: ret.savePath

}, (ret, err) => {

});

} else {

if(ret.percent>0){

api.toast({

msg:'正在下载'+ret.percent+'%'

})

}

else{

api.toast({

msg:'下载失败,请稍后再试'

})

}

}

});

} else {

api.toast({

msg:'下载失败,请稍后再试'

})

}

api.hideProgress();

});

}

});

15、登录、退出

通过api.setPrefs存储用户登录信息,退出登录清空数据。

//登陆APP

submit() {

var that = this;

var user = that.data.user;

var psw = that.data.psw;

if (!user) {

this.showToast("姓名不能为空");

return;

}

if (!psw) {

this.showToast("密码不能为空");

return;

}

api.showProgress();

const params = {

data: {

values:{

secret: Config.secret,

user:user,

psw:psw

}

}

};

Model.login(params, (res,err) => {

// console.log(JSON.stringify(res));

// console.log(JSON.stringify(err));

if (res && res.flag == "Success") {

that.showToast("提交成功");

api.setPrefs({key:'name',value:res.data.name});

api.setPrefs({key:'userid',value:res.data.id});

api.setPrefs({key:'roleid',value:res.data.role});

api.setPrefs({key:'rolename',value:res.data.rolename});

api.setPrefs({key:'partid',value:res.data.part});

api.setPrefs({key:'partname',value:res.data.partname});

api.setPrefs({key:'username',value:res.data.username});

api.toast({

msg:'登陆成功,欢迎使用'

})

api.sendEvent({

name: 'setuserinfo',

});

api.closeWin();

} else {

that.showToast('登陆失败,请稍后再试');

}

api.hideProgress();

});

},

api.setPrefs设置偏好数据,数据会存储到本地文件系统。api.removePrefs清除本地存储的数据。

loginout(){

api.confirm({

title: '提示',

msg: '确定要退出登录?',

buttons: ['确定', '取消']

}, (ret, err) => {

var index = ret.buttonIndex;

if(index == 1){

//清除用户信息

api.removePrefs({

key: 'name'

});

api.removePrefs({

key: 'userid'

});

api.removePrefs({

key: 'partname'

});

api.removePrefs({

key: 'partid'

});

api.removePrefs({

key: 'role'

});

api.removePrefs({

key: 'rolename'

});

api.removePrefs({

key: 'username'

});

api.toast({

msg:'请重新登陆APP'

})

$util.openWin({

name: 'login',

url: '../user/login.stml',

title: '',

hideNavigationBar:true

});

}

});

}

后台接口

导出word用到了PhpWord,通过composer进行安装,然后再需要调用的地方直接调用,具体使用方法请参代码中示例;其中导出word模板文件有涉及到图片的导出。

<?php

namespace Home\Controller;

use Think\Controller;

class IndexController extends Controller {

//用户登陆

public function login(){

checkscret('secret');//验证授权码

checkdataPost('user');//用户名

checkdataPost('psw');//密码

$user=$_POST['user'];

$psw=$_POST['psw'];

$map['username']=$user;

$map['password']=$psw;

$map['status']='01';//注册之后 需要审核一下

$releaseInfo=M()->table('user')->field('id,name,username,part,role,getrolename(role) rolename,getpartname(part) partname')->where($map)->find();

if($releaseInfo){

returnApiSuccess('查询成功',$releaseInfo);

}

else{

returnApiError('查询失败!');

exit();

}

}

//用户注册

public function register(){

checkscret('secret');//验证授权码

checkdataPost('username');//用户名

checkdataPost('password');//密码

$username=$_POST['username'];

$name=$_POST['name'];

$password=$_POST['password'];

$part=$_POST['part'];

$data['username']=$username;

$data['name']=$name;

$data['password']=$password;

$data['part']=$part;

$data['role']=3;

$data['status']='02';//已注册未审核

$releaseInfo=M()->table('user')->data($data)->add();

if($releaseInfo){

returnApiSuccess('注册成功',$releaseInfo);

}

else{

returnApiError('注册失败!');

exit();

}

}

//基本信息登记

public function addbase(){

checkscret('secret');//验证授权码

checkdataPost('userid');

checkdataPost('partid');

//对应字段

$dwmc=$_POST['dwmc'];

$dwdz=$_POST['dwdz'];

$dwlb=$_POST['dwlb'];

$dwxz=$_POST['dwxz'];

$zgzs=$_POST['zgzs'];

$xfaqzrr_xm=$_POST['xfaqzrr_xm'];

$xfaqzrr_zw=$_POST['xfaqzrr_zw'];

$xfaqzrr_dh=$_POST['xfaqzrr_dh'];

$xfaqglr_xm=$_POST['xfaqglr_xm'];

$xfaqglr_zw=$_POST['xfaqglr_zw'];

$xfaqglr_dh=$_POST['xfaqglr_dh'];

$zjzfhgb_xm=$_POST['zjzfhgb_xm'];

$zjzfhgb_zw=$_POST['zjzfhgb_zw'];

$zjzfhgb_dh=$_POST['zjzfhgb_dh'];

$jzcs=$_POST['jzcs'];

$jzgd=$_POST['jzgd'];

$zjzmj=$_POST['zjzmj'];

$mcjzmj=$_POST['mcjzmj'];

$szcs=$_POST['szcs'];

$yymj=$_POST['yymj'];

$jcsj=$_POST['jcsj'];

$trsysj=$_POST['trsysj'];

$kysj=$_POST['kysj'];

$zlfwhzxm=$_POST['zlfwhzxm'];

$scjyzk=$_POST['scjyzk'];

$lssq=$_POST['lssq'];

$ssyjfl=$_POST['ssyjfl'];

$xfsszljsl=$_POST['xfsszljsl'];

$jcqkdj_1=$_POST['jcqkdj_1'];

$jcqkdj_2=$_POST['jcqkdj_2'];

$jcqkdj_3=$_POST['jcqkdj_3'];

$jcqkdj_4=$_POST['jcqkdj_4'];

$dwlb_qt=$_POST['dwlb_qt'];

$userid=$_POST['userid'];

$partid=$_POST['partid'];

$id=$_POST['id'];

//数据

$data['dwmc']=$dwmc;

$data['dwdz']=$dwdz;

$data['dwlb']=$dwlb;

$data['dwxz']=$dwxz;

$data['zgzs']=$zgzs;

$data['xfaqzrr_xm']=$xfaqzrr_xm;

$data['xfaqzrr_zw']=$xfaqzrr_zw;

$data['xfaqzrr_dh']=$xfaqzrr_dh;

$data['xfaqglr_xm']=$xfaqglr_xm;

$data['xfaqglr_zw']=$xfaqglr_zw;

$data['xfaqglr_dh']=$xfaqglr_dh;

$data['zjzfhgb_xm']=$zjzfhgb_xm;

$data['zjzfhgb_zw']=$zjzfhgb_zw;

$data['zjzfhgb_dh']=$zjzfhgb_dh;

$data['jzcs']=$jzcs;

$data['jzgd']=$jzgd;

$data['zjzmj']=$zjzmj;

$data['mcjzmj']=$mcjzmj;

$data['szcs']=$szcs;

$data['yymj']=$yymj;

$data['jcsj']=$jcsj;

$data['trsysj']=$trsysj;

$data['kysj']=$kysj;

$data['zlfwhzxm']=$zlfwhzxm;

$data['scjyzk']=$scjyzk;

$data['lssq']=$lssq;

$data['ssyjfl']=$ssyjfl;

$data['xfsszljsl']=$xfsszljsl;

$data['jcqkdj_1']=$jcqkdj_1;

$data['jcqkdj_2']=$jcqkdj_2;

$data['jcqkdj_3']=$jcqkdj_3;

$data['jcqkdj_4']=$jcqkdj_4;

$data['dwlb_qt']=$dwlb_qt;

$data['userid']=$userid;

$data['partid']=$partid;

$data['create_time']=time();

if($id){

$map['id']=$id;

//插入数据

$releaseInfo=M()->table('base')->where($map)->save($data);

}

else{

//插入数据

$releaseInfo=M()->table('base')->data($data)->add();

}

if($releaseInfo){

returnApiSuccess('登记成功',$releaseInfo);

}

else{

returnApiError( '登记失败,请稍后再试');

exit();

}

}

//删除登记信息

public function deletebasebyid(){

checkscret('secret');//验证授权码

checkdataPost('id');

$id=$_POST['id'];

$map['id']=$id;

$releaseInfo=M()->table('base')->where($map)->delete();

if($releaseInfo){

returnApiSuccess('删除成功',$releaseInfo);

}

else{

returnApiError('删除失败!');

exit();

}

}

//查询登记单位列表

public function querylist(){

checkscret('secret');//验证授权码

checkdataPost('limit');//下一次加载多少条

checkdataPost('userid');

$limit=$_POST['limit'];

$skip=$_POST['skip'];

if(empty($skip)){

$skip=0;

}

$userid=$_POST['userid'];

$map['userid']=$userid;

$releaseInfo=M()->table('base')->field('id,dwmc as name,dwdz as address,dwlb as type')->where($map)->limit($skip*$limit,$limit)->order('create_time desc')->select();

if($releaseInfo){

returnApiSuccess('查询成功',$releaseInfo);

}

else{

returnApiError('查询失败!');

exit();

}

}

//查询单位基本信息详情

public function querybasebyid(){

checkscret('secret');//验证授权码

checkdataPost('id');//ID

$id=$_POST['id'];

$map['id']=$id;

$releaseInfo=M()->table('base')->where($map)->find();

if($releaseInfo){

returnApiSuccess('查询成功',$releaseInfo);

}

else{

returnApiError('查询失败!');

exit();

}

}

//查询基本信息

public function querybaseinfobyid(){

checkscret('secret');//验证授权码

checkdataPost('id');//ID

$id=$_POST['id'];

$map['id']=$id;

$releaseInfo=M()->table('base')->field('dwmc,dwdz,dwxz,jzgd,jzcs,yymj')->where($map)->find();

if($releaseInfo){

returnApiSuccess('查询成功',$releaseInfo);

}

else{

returnApiError('查询失败!');

exit();

}

}

//导出基本信息表

public function exportbase(){

checkscret('secret');//验证授权码

checkdataPost('id');//ID

$id=$_POST['id'];

$map['id']=$id;

$data=M()->table('base')->where($map)->find();

if ($data) {

require_once "./vendor/autoload.php";

$tmp = new \PhpOffice\PhpWord\TemplateProcessor('./Public/template/temp_base.docx'); //打开模板

$tmp->setValue('dwmc', $data['dwmc']);

$tmp->setValue('dwdz', $data['dwdz']);

$tmp->setValue('dwlb', $data['dwlb']);

$tmp->setValue('dwxz', $data['dwxz']);

$tmp->setValue('zgzs', $data['zgzs']);

$tmp->setValue('xfaqzrr_xm', $data['xfaqzrr_xm']);

$tmp->setValue('xfaqzrr_zw', $data['xfaqzrr_zw']);

$tmp->setValue('xfaqzrr_dh', $data['xfaqzrr_dh']);

$tmp->setValue('xfaqglr_xm', $data['xfaqglr_xm']);

$tmp->setValue('xfaqglr_zw', $data['xfaqglr_zw']);

$tmp->setValue('xfaqglr_dh', $data['xfaqglr_dh']);

$tmp->setValue('zjzfhgb_xm', $data['zjzfhgb_xm']);

$tmp->setValue('zjzfhgb_zw', $data['zjzfhgb_zw']);

$tmp->setValue('zjzfhgb_dh', $data['zjzfhgb_dh']);

$tmp->setValue('jzcs', $data['jzcs']);

$tmp->setValue('jzgd', $data['jzgd']);

$tmp->setValue('zjzmj', $data['zjzmj']);

$tmp->setValue('mcjzmj', $data['mcjzmj']);

$tmp->setValue('kysj', $data['kysj']);

$tmp->setValue('szcs', $data['szcs']);

$tmp->setValue('yymj', $data['yymj']);

$tmp->setValue('jcsj', $data['jcsj']);

$tmp->setValue('trsysj', $data['trsysj']);

$tmp->setValue('zlfwhzxm', $data['zlfwhzxm']);

$tmp->setValue('scjyzk', $data['scjyzk']);

$tmp->setValue('lssq', $data['lssq']);

$tmp->setValue('ssyjfl', $data['ssyjfl']);

$tmp->setValue('xfsszljsl', $data['xfsszljsl']);

$tmp->setValue('jcqkdj_1', $data['jcqkdj_1']);

$tmp->setValue('jcqkdj_2', $data['jcqkdj_2']);

$tmp->setValue('jcqkdj_3', $data['jcqkdj_3']);

$tmp->setValue('jcqkdj_4', $data['jcqkdj_4']);

$tmp->setValue('dwlb_qt', $data['dwlb_qt']);

$tmp->saveAs('./Uploads/九小场所基本情况管理登记表_'.$data['dwmc'].'.docx');

returnApiSuccess('导出成功','http://xiaofang.*********.cn/Uploads/九小场所基本情况管理登记表_'.$data['dwmc'].'.docx');

}

else{

returnApiError('导出失败,请稍后再试!');

exit();

}

}

//消防安全综合治理登记

public function addxfaqzljl(){

checkscret('secret');//验证授权码

checkdataPost('userid');

checkdataPost('partid');

//对应字段

$dwmc=$_POST['dwmc'];

$jcsj=$_POST['jcsj'];

$bjccsmc=$_POST['bjccsmc'];

$bjccsdz=$_POST['bjccsdz'];

$jyz=$_POST['jyz'];

$jyzlxfs=$_POST['jyzlxfs'];

$jzlx=$_POST['jzlx'];

$sfdjjc=$_POST['sfdjjc'];

$sfkf=$_POST['sfkf'];

$djcs=$_POST['djcs'];

$jclb=$_POST['jclb'];

$ltjzcl=$_POST['ltjzcl'];

$sfzr=$_POST['sfzr'];

$jzrs=$_POST['jzrs'];

$jzcs=$_POST['jzcs'];

$zsqysfyaqck=$_POST['zsqysfyaqck'];

$zsqysfytswc=$_POST['zsqysfytswc'];

$zrxs=$_POST['zrxs'];

$hzzdbjxt=$_POST['hzzdbjxt'];

$zdpsmhxt=$_POST['zdpsmhxt'];

$snxfs=$_POST['snxfs'];

$mhq=$_POST['mhq'];

$mhqsl=$_POST['mhqsl'];

$xfssqtqk=$_POST['xfssqtqk'];

$dqxlqk=$_POST['dqxlqk'];

$ddzxcsyqk=$_POST['ddzxcsyqk'];

$sfsymhgwjrqnsbd=$_POST['sfsymhgwjrqnsbd'];

$sfcfyrybwxp=$_POST['sfcfyrybwxp'];

$yrybwxpcfsyqk=$_POST['yrybwxpcfsyqk'];

$sfdqkzxfpx=$_POST['sfdqkzxfpx'];

$ydsh=$_POST['ydsh'];

$yhjzgqk=$_POST['yhjzgqk'];

$userid=$_POST['userid'];

$partid=$_POST['partid'];

$id=$_POST['id'];

$baseid=$_POST['baseid'];

//数据

$data['dwmc']=$dwmc;

$data['jcsj']=$jcsj;

$data['bjccsmc']=$bjccsmc;

$data['bjccsdz']=$bjccsdz;

$data['jyz']=$jyz;

$data['jyzlxfs']=$jyzlxfs;

$data['jzlx']=$jzlx;

$data['sfdjjc']=$sfdjjc;

$data['sfkf']=$sfkf;

$data['djcs']=$djcs;

$data['jclb']=$jclb;

$data['ltjzcl']=$ltjzcl;

$data['sfzr']=$sfzr;

$data['jzrs']=$jzrs;

$data['jzcs']=$jzcs;

$data['zsqysfyaqck']=$zsqysfyaqck;

$data['zsqysfytswc']=$zsqysfytswc;

$data['zrxs']=$zrxs;

$data['hzzdbjxt']=$hzzdbjxt;

$data['zdpsmhxt']=$zdpsmhxt;

$data['snxfs']=$snxfs;

$data['mhq']=$mhq;

$data['mhqsl']=$mhqsl;

$data['xfssqtqk']=$xfssqtqk;

$data['dqxlqk']=$dqxlqk;

$data['ddzxcsyqk']=$ddzxcsyqk;

$data['sfsymhgwjrqnsbd']=$sfsymhgwjrqnsbd;

$data['sfcfyrybwxp']=$sfcfyrybwxp;

$data['yrybwxpcfsyqk']=$yrybwxpcfsyqk;

$data['sfdqkzxfpx']=$sfdqkzxfpx;

$data['ydsh']=$ydsh;

$data['yhjzgqk']=$yhjzgqk;

$data['baseid']=$baseid;

$data['userid']=$userid;

$data['partid']=$partid;

$data['create_time']=time();

//保存文件

$upload = new \Think\Upload(); // 实例化上传类

$upload->rootPath = './Uploads/'; // 设置附件上传根目录

$upload->saveName = array('uniqid', mt_rand(1,999999).'_'.md5(uniqid())); // 自定义图片重命名

$upload->exts = array('jpg', 'jpeg' ,'png'); // 设置附件上传类型 只允许照片

// 上传文件

$uploadinfo = $upload->upload();

if($uploadinfo){

if($uploadinfo['file1']['savepath'] && $uploadinfo['file1']['savename']){

$data['signature_check']="/Uploads/".$uploadinfo['file1']['savepath'].$uploadinfo['file1']['savename'];

}

if($uploadinfo['file2']['savepath'] && $uploadinfo['file2']['savename']){

$data['signature_bcheck']="/Uploads/".$uploadinfo['file2']['savepath'].$uploadinfo['file2']['savename'];

}

}

if($id){

$map['id']=$id;

//插入数据

$releaseInfo=M()->table('zhzljl')->where($map)->save($data);

}

else{

//插入数据

$releaseInfo=M()->table('zhzljl')->data($data)->add();

}

if($releaseInfo){

returnApiSuccess('登记成功',$releaseInfo);

}

else{

returnApiError( '登记失败,请稍后再试');

exit();

}

}

//查询综合检查记录

public function queryxfaqzljlyid(){

checkscret('secret');//验证授权码

checkdataPost('baseid');

$baseid=$_POST['baseid'];

$map['baseid']=$baseid;

$releaseInfo=M()->table('zhzljl')->where($map)->find();

if($releaseInfo){

returnApiSuccess('查询成功',$releaseInfo);

}

else{

returnApiError( '查询失败,请稍后再试');

exit();

}

}

//导出

public function exportxfaqzljl(){

checkscret('secret');//验证授权码

checkdataPost('id');//ID

$id=$_POST['id'];

$map['id']=$id;

$data=M()->table('xf_zhzljl')->where($map)->find();

if ($data) {

require_once "./vendor/autoload.php";

$tmp = new \PhpOffice\PhpWord\TemplateProcessor('./Public/template/temp_zljl.docx'); //打开模板

$tmp->setValue('dwmc', $data['dwmc']);

$tmp->setValue('jcsj', $data['jcsj']);

$tmp->setValue('bjccsmc', $data['bjccsmc']);

$tmp->setValue('bjccsdz', $data['bjccsdz']);

$tmp->setValue('jyz', $data['jyz']);

$tmp->setValue('jyzlxfs', $data['jyzlxfs']);

$tmp->setValue('jzlx', $data['jzlx']);

$tmp->setValue('sfdjjc', $data['sfdjjc']);

$tmp->setValue('djcs', $data['djcs']);

$tmp->setValue('sfkf', $data['sfkf']);

$tmp->setValue('jclb', $data['jclb']);

$tmp->setValue('ltjzcl', $data['ltjzcl']);

$tmp->setValue('sfzr', $data['sfzr']);

$tmp->setValue('jzrs', $data['jzrs']);

$tmp->setValue('jzcs', $data['jzcs']);

$tmp->setValue('zsqysfyaqck', $data['zsqysfyaqck']);

$tmp->setValue('zsqysfytswc', $data['zsqysfytswc']);

$tmp->setValue('zrxs', $data['zrxs']);

$tmp->setValue('hzzdbjxt', $data['hzzdbjxt']);

$tmp->setValue('zdpsmhxt', $data['zdpsmhxt']);

$tmp->setValue('snxfs', $data['snxfs']);

$tmp->setValue('mhq', $data['mhq']);

$tmp->setValue('mhqsl', $data['mhqsl']);

$tmp->setValue('xfssqtqk', $data['xfssqtqk']);

$tmp->setValue('dqxlqk', $data['dqxlqk']);

$tmp->setValue('ddzxcsyqk ', $data['ddzxcsyqk']);

$tmp->setValue('sfsymhgwjrqnsbd', $data['sfsymhgwjrqnsbd']);

$tmp->setValue('sfcfyrybwp', $data['sfcfyrybwxp']);

$tmp->setValue('yrybwxpcfsyqk', $data['yrybwxpcfsyqk']);

$tmp->setValue('sfdqkzxfpx', $data['sfdqkzxfpx']);

$tmp->setValue('ydsh', $data['ydsh']);

$tmp->setValue('yhjzgqk', $data['yhjzgqk']);

$tmp->setImageValue('signature_check', ['path' => '.'.$data['signature_check'], 'width' => 120, 'height' => 20]);

$tmp->setImageValue('signature_bcheck', ['path' => '.'.$data['signature_bcheck'], 'width' => 120, 'height' => 20]);

$tmp->saveAs('./Uploads/合用场所消防安全综合治理记录表_'.$data['bjccsmc'].'.docx');

returnApiSuccess('导出成功','http://xiaofang.********.cn/Uploads/合用场所消防安全综合治理记录表_'.$data['bjccsmc'].'.docx');

}

else{

returnApiError('导出失败,请稍后再试!');

exit();

}

}

//添加基本信息照片

public function addbasepicbyid(){

checkscret('secret');//验证授权码

checkdataPost('baseid');

checkdataPost('type');

$baseid=$_POST['baseid'];

$type=$_POST['type'];

$map['baseid']=$baseid;

$data['baseid']=$baseid;

//保存文件

$upload = new \Think\Upload(); // 实例化上传类

$upload->rootPath = './Uploads/'; // 设置附件上传根目录

$upload->saveName = array('uniqid', mt_rand(1,999999).'_'.md5(uniqid())); // 自定义图片重命名

$upload->exts = array('jpg', 'jpeg' ,'png'); // 设置附件上传类型 只允许照片

// 上传文件

$uploadinfo = $upload->upload();

if($uploadinfo){

if($type=='01'){

$data['mt']="/Uploads/".$uploadinfo['file']['savepath'].$uploadinfo['file']['savename'];

}

else if($type=='02'){

$data['yyzz']="/Uploads/".$uploadinfo['file']['savepath'].$uploadinfo['file']['savename'];

}

else if($type=='03'){

$data['dlqk']="/Uploads/".$uploadinfo['file']['savepath'].$uploadinfo['file']['savename'];

}

else if($type=='04'){

$data['sfz']="/Uploads/".$uploadinfo['file']['savepath'].$uploadinfo['file']['savename'];

}

}

$data['create_time']=time();

if($this->checkbasepic($baseid)){

$releaseInfo=M()->table('basepic')->where($map)->save($data);

}

else{

$releaseInfo=M()->table('basepic')->data($data)->add();

}

if($releaseInfo){

returnApiSuccess('添加成功',"http://xiaofang.******.cn/Uploads/".$uploadinfo['file']['savepath'].$uploadinfo['file']['savename']);

}

else{

returnApiError('添加失败!');

exit();

}

}

function checkbasepic($baseid){

$map['baseid']=$baseid;

$ret=M()->table('basepic')->where($map)->find();

if($ret){

return true;

}

else{

return false;

}

}

}巡检是企事业单位的常见场景之一,以消防检查为例,秋冬季节气温下降、生产繁忙,用火、用电、用气情况大量增加,消防安全事件多发,一款消防检查app可以有效减少繁复工作、提升巡检效率。本文将详细介绍如何使用YonBuilder移动开发平台开发消防检查助手app。

一、功能介绍

把消防检查过程中,需要手写填报的文档,在app端以表单填写进行实现;同时可以添加手写签名、关联照片,而且app端表单填报项目可进行下拉选择,极大提高了工作效率;表单填报完成之后可通过系统后台生成word模板文件,app端下载到手机,通过手机连接打印机,可打印纸质文件。App开发采用AVM框架,后台采用PHP。

功能要点:

1、场所登记,分为九小场所和合用场所登记;

2、监督检查记录;

3、责令整改通知书;

4、基本情况拍照,检查过程记录拍照;

5、后台针对上述数据进行多维度分析,导出Excel表格、Word模板文件。

二、思维导图

编辑切换为居中

添加图片注释,不超过 140 字(可选)

三、用到的模块

编辑切换为居中

添加图片注释,不超过 140 字(可选)

四、项目目录

编辑

添加图片注释,不超过 140 字(可选)

五、开发介绍

1、首页导航

系统首页使用tabLayout,可以将相关参数配置在JSON文件中,再在config.xml中将content的值设置成该JSON文件的路径。如果底部导航没有特殊需求这里强烈建议大家使用tabLayout为app进行布局,官方已经将各类手机屏幕及不同的分辨率进行了适配,免去了很多关于适配方面的问题。

编辑切换为居中

添加图片注释,不超过 140 字(可选)

{

"name": "root",

"textOffset": 6,

"color": "#999999",

"selectedColor": "#004494",

"scrollEnabled": false,

"hideNavigationBar": false,

"bgColor": "#fff",

"navigationBar": {

"background": "./images/navbk.png",

"shadow": "rgba(0,0,0,0)",

"color": "#fff",

"fontSize": 18,

"hideBackButton": true

},

"tabBar": {

"background": "#fff",

"shadow": "#eee",

"color": "#5E5E5E",

"selectedColor": "#004494",

"textOffset": 3,

"fontSize": 11,

"scrollEnabled": true,

"index": 0,

"preload": 1,

"frames": [

{

"title": "首页",

"name": "home",

"url": "./pages/index/home"

},

{

"title": "历史记录",

"name": "course",

"url": "./pages/history/records"

},

{

"title": "我的",

"name": "user",

"url": "./pages/user/wode"

}

],

"list": [

{

"text": "首页",

"iconPath": "./images/home.png",

"selectedIconPath": "./images/home-o.png"

},

{

"text": "历史记录",

"iconPath": "./images/his.png",

"selectedIconPath": "./images/his-o.png"

},

{

"text": "我的",

"iconPath": "./images/my.png",

"selectedIconPath": "./images/my-o.png"

}

]

}

}

由于导航使用的tablayout,所有app初始化需要执行的操作,只需要在第一个加载的页面执行即可全局响应。可通过 tabBar中的"index"字段来确定第一个需要加载的页面,通过"preload"来确定需要预加载几个页面。

2、动态权限

动态权限的获取在第一个初始化的页面执行即可。本项目中需要用到存储、相机、相册3个权限。用到的是官方的API方法hasPermission。

编辑切换为居中

添加图片注释,不超过 140 字(可选)

//提示获取存储权限

var limits=[];

var resultList = api.hasPermission({

list: ['storage','camera','photos']

});

if (resultList[0].granted) {

// 已授权,可以继续下一步操作

} else {

limits.push(resultList[0].name);

}

if (resultList[1].granted) {

// 已授权,可以继续下一步操作

} else {

limits.push(resultList[1].name);

}

if (resultList[2].granted) {

// 已授权,可以继续下一步操作

} else {

limits.push(resultList[2].name);

}

if(limits.length>0){

api.requestPermission({

list: limits,

}, function(res) {

// console.log(JSON.stringify(res));

});

}

manifest.xml文件,关于targetSdkVersion的值的大小,这里可以根据下文图片中的说明,结合项目需要上架的平台自行设置。

编辑

添加图片注释,不超过 140 字(可选)

编辑切换为居中

添加图片注释,不超过 140 字(可选)

编辑切换为居中

添加图片注释,不超过 140 字(可选)

<?xml version="1.0" encoding="UTF-8"?>

<manifest>

<application name="targetSdkVersion" value="28"/>

</manifest>

3、消息事件

本项目中通过发送事件sendEvent和监听事件addEventListener,消息事件要学会合理运用来提升app中各个页面之间交互的体验。下面对实现在表单提交成功之后刷新列表页、登陆成功之后跳转页面时重新加载用户信息的具体操作进行说明。

表单数据提交成功之后,在回调里发送事件"addbase",然后关闭页面,跳转至列表页,在列表页的apiready中监听“addbase”事件,在监听成功回调中执行刷新列表的操作。

onsubmit(e){

let result = e.detail.value;

this.data.dwmc = result.dwmc?result.dwmc:this.data.dwmc;

this.data.dwdz = result.dwdz?result.dwdz:this.data.dwdz;

//省略其他字段

let params = {

data:{

values:{

secret: Config.secret,

userid: api.getPrefs({sync: true,key: 'userid'}),

partid: api.getPrefs({sync: true,key: 'partid'}),

id:this.data.id,

dwmc:this.data.dwmc,

dwdz:this.data.dwdz,

//省略

}

}

}

api.showProgress();

Model.addbase(params, (res,err) => {

// console.log(JSON.stringify(res));

// console.log(JSON.stringify(err));

if (res && res.flag == 'Success') {

api.toast({

msg:'登记成功'

});

api.sendEvent({

name: 'addbase',

});

api.closeWin();

} else {

api.toast({

msg:res.msg

})

}

api.hideProgress();

});

},

apiready(){

this.data.tab=api.pageParam.tab;

this.data.tabtitle=api.pageParam.tabtitle;

this.data.refresherTriggered = true;

this.loadData(false);

api.addEventListener({

name: 'setuserinfo'

}, (ret, err) => {

this.loadData(false);

});

//监听增加修改基本信息

api.addEventListener({

name: 'addbase'

}, (ret, err) => {

this.loadData(false);

});

api.addEventListener({

name: 'delbase'

}, (ret, err) => {

this.loadData(false);

});

},

4、接口调用

将接口调用和接口配置分别封装2个JS插件,model.js和config.js。统一管理,避免了在每个页面进行接口调用时都重复写一遍代码,有效简化了每个功能页面的代码量,只需要在回调里专注写自己的业务逻辑即可。

import $util from "../../utils/util.js"

import {Model} from "../../utils/model.js"

import {Config} from "../../utils/config.js"

config.js

class Config{

constructor(){}

}

Config.restUrl = 'http://xiaofang.*******.cn/api.php/Home/Index';

Config.secret = '99d0fd93-***************************';

Config.addbase ='/addbase';//登记基本信息表

Config.querylist ='/querylist';//查询登记单位列表

Config.querybasebyid ='/querybasebyid';//查询登记单位基本信息详情

Config.querybaseinfobyid ='/querybaseinfobyid';//查询登记单位基本信息详情

Config.exportbase ='/exportbase';//下载登记单位基本信息

Config.deletebasebyid ='/deletebasebyid';//删除登记单位基本信息

Config.login ='/login';//登陆

Config.getpart ='/getpart';//获取单位列表

Config.register ='/register';//用户注册

/**省略**/

Config.checkUserStatus ='/checkUserStatus';//获取用户状态

export {Config};

model.js

import {Config} from './config.js';

class Model {

constructor() {}

}

/*登记基本信息表 */

Model.addbase = function (param, callback){

param.url = Config.addbase;

param.method = 'post';

this.request(param, callback);

}

/*查询登记单位列表 */

Model.querylist = function (param, callback){

param.url = Config.querylist;

param.method = 'post';

this.request(param, callback);

}

/*查询登记单位基本信息详情 */

Model.querybasebyid = function (param, callback){

param.url = Config.querybasebyid;

param.method = 'post';

this.request(param, callback);

}

/*查询登记单位基本信息详情 */

Model.querybaseinfobyid = function (param, callback){

param.url = Config.querybaseinfobyid;

param.method = 'post';

this.request(param, callback);

}

/*下载登记单位基本信息 */

Model.exportbase = function (param, callback){

param.url = Config.exportbase;

param.method = 'post';

this.request(param, callback);

}

/*删除登记单位基本信息 */

Model.deletebasebyid = function (param, callback){

param.url = Config.deletebasebyid;

param.method = 'post';

this.request(param, callback);

}

/*登陆模块 */

Model.login = function (param, callback){

param.url = Config.login;

param.method = 'post';

this.request(param, callback);

}

/**省略**/

/*获取用户状态 */

Model.checkUserStatus = function (param, callback){

param.url = Config.checkUserStatus;

param.method = 'post';

this.request(param, callback);

}

Model.request = function(p, callback) {

var param = p;

if (!param.headers) {

param.headers = {};

}

if (param.data && param.data.body) {

param.headers['Content-Type'] = 'application/json; charset=utf-8';

}

if (param.url) {

param.url = Config.restUrl + param.url;

}

api.ajax(param, function(ret, err) {

callback && callback(ret, err);

});

}

export {Model};

5、数据列表及分页查询

数据列表的展示,采用scroll-view标签,通过onrefresherrefresh,onrefresherrefresh触发的事件中进行数据列表的刷新和分页查询。通过refresher-triggered这个属性来设置当前下拉刷新状态,true 表示下拉刷新已经被触发,false 表示下拉刷新未被触发。如果想默认下拉刷新一下可以在apiready中将之设置为true,以此来代替执行数据刷新操作。

如果列表中的每一项的元素较少,而且没有样式的特殊要求,也可以使用list-view来实现。

下面是单位列表的完整页面代码。其他页面的列表基本功能都是一致的,只是在每一项的样式及参数个数上存在差异。

<template name='unitlist'>

<view class="page">

<scroll-view class="main" scroll-y enable-back-to-top refresher-enabled refresher-triggered={refresherTriggered} onrefresherrefresh={this.onrefresherrefresh} onscrolltolower={this.onscrolltolower}>

<view class="search-box">

<input class="serach-input" placeholder="请输入单位名称检索" confirm-type="search" onconfirm="onconfirm" οninput={this.getKey}/>

<text class="search-btn" οnclick="onconfirm">搜索</text>

</view>

<view class="item-box">

<view class="item" data-id={item.id} οnclick={this.openTable} v-for="(item, index) in list">

<text class="item-content">{{item.name}}</text>

<view class="item-sub">

<view class="item-sub-box">

<image class="item-sub-ico" src="../../images/DW.png" mode="aspectFit"></image>

<text class="item-info">{{item.address}}</text>

</view>

<view class="item-sub-box">

<image class="item-sub-ico" src="../../images/CT.png" mode="aspectFit"></image>

<text class="item-info">{{item.type}}</text>

</view>

</view>

</view>

</view>

<view class="footer">

<text class="loadDesc">{loadStateDesc}</text>

</view>

</scroll-view>

</view>

</template>

<script>

import {Model} from '../../utils/model.js'

import {Config} from "../../utils/config.js"

import $util from "../../utils/util.js"

export default {

name: 'unitlist',

data() {

return{

list:[],

skip: 0,

loading: false,

refresherTriggered: false,

haveMoreData: true,

tab:'',

tabtitle:'',

key:''

}

},

computed: {

loadStateDesc(){

if (this.data.loading || this.data.haveMoreData) {

return '加载中...';

} else if (this.list.length > 0) {

return '没有更多啦';

} else {

return '暂时没有内容';

}

}

},

methods: {

apiready(){

this.data.tab=api.pageParam.tab;

this.data.tabtitle=api.pageParam.tabtitle;

this.data.refresherTriggered = true;

this.loadData(false);

api.addEventListener({

name: 'setuserinfo'

}, (ret, err) => {

this.loadData(false);

});

//监听增加修改基本信息

api.addEventListener({

name: 'addbase'

}, (ret, err) => {

this.loadData(false);

});

api.addEventListener({

name: 'delbase'

}, (ret, err) => {

this.loadData(false);

});

},

loadData(loadMore) {

this.data.loading = true;

var that = this;

var limit = 20;

var skip = loadMore?that.data.skip+1:0;

let params = {

data:{

values:{

secret: Config.secret,

userid: api.getPrefs({sync: true,key: 'userid'}),

roleid: api.getPrefs({sync: true,key: 'roleid'}),

partid: api.getPrefs({sync: true,key: 'partid'}),

skip: skip,

limit: limit,

key:this.data.key

}

}

}

api.showProgress();

Model.querylist(params, (res,err) => {

// console.log(JSON.stringify(res));

// console.log(JSON.stringify(err));

if (res && res.flag == 'Success') {

let lists = res.data;

that.data.haveMoreData = lists.length == limit;

if (loadMore) {

that.data.list = that.data.list.concat(lists);

} else {

that.data.list = lists;

}

that.data.skip = skip;

} else {

that.data.haveMoreData = false;

}

that.data.loading = false;

that.data.refresherTriggered = false;

api.hideProgress();

});

},

//打开填写表格

openTable(e) {

var id = e.currentTarget.dataset.id;

$util.openWin({

name: this.data.tab,

url: '../index/'+this.data.tab+'.stml',

title: this.data.tabtitle,

pageParam:{

id:id

}

});

},

/*下拉刷新页面*/

onrefresherrefresh(){

this.data.refresherTriggered = true;

this.loadData(false);

},

onscrolltolower() {

if (this.data.haveMoreData) {

this.loadData(true);

}

},

getKey(e){

this.data.key = e.detail.value;

},

onconfirm(){

this.loadData(false);

}

}

}

</script>

<style>

.main {

height: 100%;

background-color: #eaf0fa;

}

.item-box{

background-color: #fff;

margin: 5px;

}

.item{

border-bottom: 1px solid #efefef;

margin: 0 10px;

justify-content:flex-start;

flex-direction:column;

}

.item-content{

font-size: 17PX;

margin-top: 10px;

}

.item-info{

font-size: 13PX;

color: #666;

margin: 10px 0;

}

.item-sub{

justify-content:space-between;

flex-direction:row;

}

.footer {

height: 44px;

justify-content: center;

align-items: center;

}

.loadDesc {

width: 200px;

text-align: center;

}

.item-sub-ico{

width: 15px;

margin: 10px 0;

}

.item-sub-box{

flex-flow: row nowrap;

}

.search-box{

flex-flow: row nowrap;

align-items: center;

background-color: #2c6ddc;

border-radius: 5px;

margin: 5px;

}

.serach-input{

padding: 5px;

width: 80%;

height: 50px;

border-top-left-radius: 5px;

border-bottom-left-radius: 5px;

}

.search-btn{

width: 20%;

text-align: center;

color: #ffffff;

}

</style>

6、双击退出程序

在首页页面和登陆页面中,添加双击退出程序功能,避免出现单击退出键出现不必要的页面跳转失误。此监听事件要在apiready中执行。

//监听返回 双击退出程序

api.setPrefs({

key: 'time_last',

value: '0'

});

api.addEventListener({

name : 'keyback'

}, function(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

});

}

});

7、账号有效性确认

由于后台针对用户账号,启用了停用功能,后台一旦设置账号停用,app中也应相应地将用户进行退出系统操作。此操作在首页的apiready中进行执行。

isLogin(){

if(!api.getPrefs({sync: true,key:'userid'})){

$util.openWin({

name: 'login',

url: '../user/login.stml',

title: '',

hideNavigationBar:true

});

}

else{

let params = {

data:{

values:{

secret: Config.secret,

userid: api.getPrefs({sync: true,key:'userid'})

}

}

}

api.showProgress();

Model.checkUserStatus(params, (res,err) => {

// console.log(JSON.stringify(res));

// console.log(JSON.stringify(err));

if (res && res.flag == 'Success') {

if(ret.data=='02'){

//清楚缓存用户数据

api.removePrefs({

key: 'name'

});

api.removePrefs({

key: 'userid'

});

api.removePrefs({

key: 'partname'

});

api.removePrefs({

key: 'partid'

});

api.removePrefs({

key: 'role'

});

api.removePrefs({

key: 'rolename'

});

api.removePrefs({

key: 'username'

});

//用户已停用 退出系统

$util.openWin({

name: 'login',

url: '../user/login.stml',

title: '',

hideNavigationBar:true

});

}

} else {

//清除用户信息

api.removePrefs({

key: 'name'

});

api.removePrefs({

key: 'userid'

});

api.removePrefs({

key: 'partname'

});

api.removePrefs({

key: 'partid'

});

api.removePrefs({

key: 'role'

});

api.removePrefs({

key: 'rolename'

});

api.removePrefs({

key: 'username'

});

//用户异常 退出重新登陆

$util.openWin({

name: 'login',

url: '../user/login.stml',

title: '',

hideNavigationBar:true

});

}

api.hideProgress();

});

}

}

8、表单提交、回显

表单使用的是AVM的 from组件,通过onsubmit进行表单数据提交。其中主要用到了input、textarea、radio、checkbox;每个控件的具体使用方法,在官方文档中否有详细的介绍。下面就具体的代码示例进行展示。

编辑切换为居中

添加图片注释,不超过 140 字(可选)

页面代码

<template name='addbase'>

<scroll-view class="page" scroll-y>

<form οnsubmit={this.onsubmit}>

<view class="item">

<text>单位名称:</text>

<input name="dwmc" value={this.data.dwmc} placeholder="请输入单位名称"/>

</view>

<view class="item">

<text>单位地址:</text>

<input name="dwdz" value={this.data.dwdz} placeholder="请输入单位详细地址"/>

</view>

<checkbox-group class="item" name="dwlb">

<text>单位类别:</text>

<view class="item-checkbox">

<label v-for="item in dwlbarr">

<checkbox value={item} v-bind:checked="this.data.seldwlb.indexOf(item)!=-1?true:false"/>

<text>{item}</text>

</label>

</view>

<input name="dwlb_qt" value={this.data.dwlb_qt} placeholder="请输入单位类别"/>

</checkbox-group>

<checkbox-group class="item" name="dwxz">

<text>单位性质:</text>

<view class="item-checkbox">

<label v-for="item in dwxzarr">

<checkbox value={item} v-bind:checked="this.data.seldwxz.indexOf(item)!=-1?true:false"/>

<text>{item}</text>

</label>

</view>

</checkbox-group>

<view class="item">

<text>职工总数:</text>

<input name="zgzs" value={this.data.zgzs} keyboard-type="number" placeholder="请输入单位职工总数"/>

</view>

<view class="item">

<text>消防安全责任人:</text>

<input name="xfaqzrr_xm" value={this.data.xfaqzrr_xm} placeholder="请输入负责人姓名"/>

<input name="xfaqzrr_zw" value={this.data.xfaqzrr_zw} placeholder="请输入负责人职务"/>

<input name="xfaqzrr_dh" value={this.data.xfaqzrr_dh} keyboard-type="number" placeholder="请输入负责人电话"/>

</view>

<view class="item">

<text>消防安全管理人:</text>

<input name="xfaqglr_xm" value={this.data.xfaqglr_xm} placeholder="请输入管理人姓名"/>

<input name="xfaqglr_zw" value={this.data.xfaqglr_zw} placeholder="请输入管理人职务"/>

<input name="xfaqglr_dh" value={this.data.xfaqglr_dh} keyboard-type="number" placeholder="请输入管理人电话"/>

</view>

<view class="item">

<text>专兼职防火干部:</text>

<input name="zjzfhgb_xm" value={this.data.zjzfhgb_xm} placeholder="请输入专兼职防火干部姓名"/>

<input name="zjzfhgb_zw" value={this.data.zjzfhgb_zw} placeholder="请输入专兼职防火干部职务"/>

<input name="zjzfhgb_dh" value={this.data.zjzfhgb_dh} keyboard-type="number" placeholder="请输入专兼职防火干部电话"/>

</view>

<view class="item">

<label class="label-box">

<text class="label-title">建筑层数(层)</text>

<input class="label-input" name="jzcs" value={this.data.jzcs} keyboard-type="number" placeholder="请输入建筑层数(层)"/>

</label>

<label class="label-box">

<text class="label-title">所在层数(层)</text>

<input class="label-input" name="szcs" value={this.data.szcs} keyboard-type="number" placeholder="请输入所在层数(层)"/>

</label>

<label class="label-box">

<text class="label-title">建筑高度(m)</text>

<input class="label-input" name="jzgd" value={this.data.jzgd} keyboard-type="number" placeholder="请输入建筑高度(m)"/>

</label>

<label class="label-box">

<text class="label-title">总建筑面积(㎡)</text>

<input class="label-input" name="zjzmj" value={this.data.zjzmj} keyboard-type="decimal" placeholder="请输入总建筑面积(㎡)"/>

</label>

<label class="label-box">

<text class="label-title">每层建筑面积(㎡)</text>

<input class="label-input" name="mcjzmj" value={this.data.mcjzmj} keyboard-type="decimal" placeholder="请输入每层建筑面积(㎡)"/>

</label>

<label class="label-box">

<text class="label-title">营业面积(㎡)</text>

<input class="label-input" name="yymj" value={this.data.yymj} keyboard-type="decimal" placeholder="请输入营业面积(㎡)"/>

</label>

<label class="label-box">

<text class="label-title">检查时间</text>

<input class="label-input" name="jcsj" value={this.data.jcsj} keyboard-type="number" placeholder="请输入检查时间"/>

</label>

<label class="label-box">

<text class="label-title">投入使用时间</text>

<input class="label-input" name="trsysj" value={this.data.trsysj} keyboard-type="number" placeholder="请输入投入使用时间"/>

</label>

<label class="label-box">

<text class="label-title">开业时间</text>

<input class="label-input" name="kysj" value={this.data.kysj} keyboard-type="number" placeholder="请输入开业时间"/>

</label>

<label class="label-box">

<text class="label-title">租赁房屋户主姓名</text>

<input class="label-input" name="zlfwhzxm" value={this.data.zlfwhzxm} placeholder="请输入租赁房屋户主姓名"/>

</label>

</view>

<view class="item">

<text>生产经营状况:</text>

<input name="scjyzk" value={this.data.scjyzk} placeholder="请输入单位生产经营状况"/>

</view>

<view class="item">

<text>隶属社区:</text>

<input name="lssq" value={this.data.lssq} placeholder="请输入单位隶属社区"/>

</view>

<radio-group class="item" name="ssyjfl">

<text>三色预警分类:</text>

<view class="item-checkbox">

<label v-for="item in ssyjflarr">

<radio value={item} v-bind:checked="this.data.ssyjfl==item?true:false"/>

<text>{item}</text>

</label>

</view>

</radio-group>

<view class="item">

<text>消防设置种类及数量:</text>

<textarea name="xfsszljsl" value={this.data.xfsszljsl} placeholder="请输入消防设置种类及数量"/>

</view>

<view class="item">

<text>检查登记情况:</text>

<textarea name="jcqkdj_1" value={this.data.jcqkdj_1} placeholder="请输入检查登记情况"/>

<textarea name="jcqkdj_2" value={this.data.jcqkdj_2} placeholder="请输入检查登记情况"/>

<textarea name="jcqkdj_3" value={this.data.jcqkdj_3} placeholder="请输入检查登记情况"/>

<textarea name="jcqkdj_4" value={this.data.jcqkdj_4} placeholder="请输入检查登记情况"/>

</view>

<view class="item">

<text>填表说明:</text>

</view>

<button class="btn-submit" type="submit">提交</button>

</form>

<button v-show="isdelete" class="btn-delete" type="button" @click="delbase">删除</button>

</scroll-view>

</template>

表单提交

data() {

return{

dwmc:'',

dwdz:'',

dwlb:'',

dwxz:'',

zgzs:0,

xfaqzrr_xm:'',

xfaqzrr_zw:'',

xfaqzrr_dh:'',

xfaqglr_xm:'',

xfaqglr_zw:'',

xfaqglr_dh:'',

zjzfhgb_xm:'',

zjzfhgb_zw:'',

zjzfhgb_dh:'',

jzcs:null,

jzgd:null,

zjzmj:null,

mcjzmj:null,

szcs:null,

yymj:null,

jcsj:'',

trsysj:'',

kysj:'',

zlfwhzxm:'',

scjyzk:'',

lssq:'',

ssyjfl:'',

xfsszljsl:'',

jcqkdj_1:'',

jcqkdj_2:'',

jcqkdj_3:'',

jcqkdj_4:'',

dwlb_qt:'',

id:0,

ssyjflarr:['红','黄','绿'],

dwlbarr:['购物场所','餐饮场所','住宿场所','公共娱乐场所','休闲健身场所','医疗场所','教学场所','生产加工企业','易燃易爆危险品销售、储存场所','其他'],

dwxzarr:['国有','集体','股份合作公司','股份有限公司','港澳台投资','中外合资','个体私营','其他'],

seldwlb:[],

seldwxz:[],

isdelete:false,

dateList: [$formatDate.lastYear30(),[1,2,3,4,5,6,7,8,9,10,11,12],[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31]],

jcsjSelectorValue:[0,0,0],

trsysjSelectorValue:[0,0,0],

kysjSelectorValue:[0,0,0]

}

},

数据回显

//查询已添加的数据

loadData(){

let params = {

data:{

values:{

secret: Config.secret,

id:this.data.id

}

}

}

api.showProgress();

Model.querybasebyid(params, (res,err) => {

// console.log(JSON.stringify(res));

// console.log(JSON.stringify(err));

if (res && res.flag == 'Success') {

//填充数据

let result=res.data;

this.data.dwmc = result.dwmc?result.dwmc:this.data.dwmc;

this.data.dwdz = result.dwdz?result.dwdz:this.data.dwdz;

this.data.seldwlb = result.dwlb?result.dwlb.split(','):this.data.dwlb;

this.data.dwlb_qt = result.dwlb_qt?result.dwlb_qt:this.data.dwlb_qt;

this.data.seldwxz = result.dwxz?result.dwxz.split(','):this.data.dwxz;

this.data.zgzs = result.zgzs?result.zgzs:this.data.zgzs;

this.data.xfaqzrr_xm = result.xfaqzrr_xm?result.xfaqzrr_xm:this.data.xfaqzrr_xm;

this.data.xfaqzrr_zw = result.xfaqzrr_zw?result.xfaqzrr_zw:this.data.xfaqzrr_zw;

this.data.xfaqzrr_dh = result.xfaqzrr_dh?result.xfaqzrr_dh:this.data.xfaqzrr_dh;

this.data.xfaqglr_xm = result.xfaqglr_xm?result.xfaqglr_xm:this.data.xfaqglr_xm;

this.data.xfaqglr_zw = result.xfaqglr_zw?result.xfaqglr_zw:this.data.xfaqglr_zw;

this.data.xfaqglr_dh = result.xfaqglr_dh?result.xfaqglr_dh:this.data.xfaqglr_dh;

this.data.zjzfhgb_xm = result.zjzfhgb_xm?result.zjzfhgb_xm:this.data.zjzfhgb_xm;

this.data.zjzfhgb_zw = result.zjzfhgb_zw?result.zjzfhgb_zw:this.data.zjzfhgb_zw;

this.data.zjzfhgb_dh = result.zjzfhgb_dh?result.zjzfhgb_dh:this.data.zjzfhgb_dh;

this.data.jzcs = result.jzcs?result.jzcs:this.data.jzcs;

this.data.jzgd = result.jzgd?result.jzgd:this.data.jzgd;

this.data.zjzmj = result.zjzmj?result.zjzmj:this.data.zjzmj;

this.data.mcjzmj = result.mcjzmj?result.mcjzmj:this.data.mcjzmj;

this.data.szcs = result.szcs?result.szcs:this.data.szcs;

this.data.yymj = result.yymj?result.yymj:this.data.yymj;

this.data.jcsj = result.jcsj?result.jcsj:this.data.jcsj;

this.data.trsysj = result.trsysj?result.trsysj:this.data.trsysj;

this.data.kysj = result.kysj?result.kysj:this.data.kysj;

this.data.zlfwhzxm = result.zlfwhzxm?result.zlfwhzxm:this.data.zlfwhzxm;

this.data.scjyzk = result.scjyzk?result.scjyzk:this.data.scjyzk;

this.data.lssq = result.lssq?result.lssq:this.data.lssq;

this.data.ssyjfl = result.ssyjfl?result.ssyjfl:this.data.ssyjfl;

this.data.xfsszljsl = result.xfsszljsl?result.xfsszljsl:this.data.xfsszljsl;

this.data.jcqkdj_1 = result.jcqkdj_1?result.jcqkdj_1:this.data.jcqkdj_1;

this.data.jcqkdj_2 = result.jcqkdj_1?result.jcqkdj_2:this.data.jcqkdj_2;

this.data.jcqkdj_3 = result.jcqkdj_1?result.jcqkdj_3:this.data.jcqkdj_3;

this.data.jcqkdj_4 = result.jcqkdj_1?result.jcqkdj_4:this.data.jcqkdj_4;

} else {

api.toast({

msg:res.msg

})

}

api.hideProgress();

});

},

9、拍照及上传照片,图片预览

拍照使用的是FNPhotograph模块,自带UI的open接口,可选择拍摄照片的质量,可配置使用摄像头方向,同时可配置照片不用存储到相册中、禁用显示相册按钮,保证用户只能现场拍照,可以满足项目需求。

编辑切换为居中

添加图片注释,不超过 140 字(可选)

项目中很多页面涉及到图片预览功能,分为单图预览和多图预览。图片预览采用的是photoBrowser模块。photoBrowser是一个图片浏览器,支持单张、多张图片查看的功能,可放大缩小图片,支持本地和网络图片资源。若是网络图片资源则会被缓存到本地,缓存到本地上的资源可以通过clearCache接口手动清除。同时本模块支持横竖屏显示,在本app支持横竖屏的情况下,本模块底层会自动监听当前设备的位置状态,自动适配横竖屏以展示图片。

编辑切换为居中

添加图片注释,不超过 140 字(可选)

getPicture(e){

this.data.type = e.currentTarget.dataset.type;

api.actionSheet({

title: '请选择',

cancelTitle: '取消',

buttons: ['选择图片','图片预览']

}, (ret, err)=> {

// console.log(JSON.stringify(ret));

// console.log(JSON.stringify(err));

// var index = ret.buttonIndex;

if(ret.buttonIndex==1){

var FNPhotograph = api.require('FNPhotograph');

FNPhotograph.open({

album: true ,

quality: 'medium'

}, (ret)=>{

// console.log(JSON.stringify(ret));

if(ret.eventType=='takePhoto'){

FNPhotograph.close();

//上传图片

let params = {

data:{

values:{

secret: Config.secret,

baseid:this.data.baseid,

type:this.data.type

},

files:{

'file':ret.imagePath,

}

}

}

api.showProgress();

Model.addbasepicbyid(params, (res,err) => {

// console.log(JSON.stringify(res));

// console.log(JSON.stringify(err));

if (res && res.flag == 'Success') {

if(this.data.type=='01'){

this.data.src1=res.data;

}

else if(this.data.type=='02'){

this.data.src2=res.data;

}

else if(this.data.type=='03'){

this.data.src3=res.data;

}

else if(this.data.type=='04'){

this.data.src4=res.data;

}

} else {

api.toast({

msg:res.msg

})

}

api.hideProgress();

});

}

});

}

else if(ret.buttonIndex==2){

//图片预览

let src='';

if(this.data.type=='01'){

src=this.data.src1;

}

else if(this.data.type=='02'){

src=this.data.src2;

}

else if(this.data.type=='03'){

src=this.data.src3;

}

else if(this.data.type=='04'){

src=this.data.src4;

}

var photoBrowser = api.require('photoBrowser');

photoBrowser.open({

images: [

src

],

placeholderImg: 'widget://res/img/apicloud.png',

bgColor: '#000'

}, (ret, err) => {

if (ret) {

if(ret.eventType=='click'){

photoBrowser.close();

}

} else {

api.toast({

msg:'图片预览失败'

})

}

});

}

});

}

10、页面之间的跳转和参数传递

封装工具类until.js,在其中定义了openWin方法来实现页面之间的跳转。页面跳转时参数的传递通过pageParam添加参数进行,在跳转到的页面通过api.pageParam.xxx在apiready中进行接收。

<view class="tab-item" data-url="addbase" data-title="九小场所登记" tapmode @click="openPage">

<image class="tab-item-logo" src="../../images/JB.png" mode="scaleToFill"></image>

<text class="tab-item-title"> 九小场所登记</text>

</view>

methods: {

apiready(){//like created

this.data.id=api.pageParam.id;

},

openPage(e){

let title = e.currentTarget.dataset.title;

let url = e.currentTarget.dataset.url;

$util.openWin({

name: url,

url: '../index/'+url+'.stml',

title: title,

pageParam:{

id:this.data.id

}

});

}

}

util.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:'../../images/navbk.png',

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;

}

}

export default $util;

11、导航栏自定义按钮点击事件

如果是首页加载的页面,可以在首页中通过索引index进行判断然后分别配置;如果在单独的页面中需要添加的话,可在页面的apiready中进行配置。

编辑切换为居中

添加图片注释,不超过 140 字(可选)

首页中的配置,需要注意的是,如果是页面直接跳转,配置多个页面时没有问题;但如果按钮事件是执行某个页面具体的方法时,就会出现问题。这里建议如果按钮事件是执行某个页面具体的方法,不要在首页中配置,可在页面中通过其他方式进行实现。因为首页配置的内容会在全局使用,而且加载成功之后,通过tabbar切换页面的时候,是不会进行页面刷新操作的。

apiready() {

//导航设置

api.addEventListener({

name:'tabitembtn'

}, (ret) => {

api.setTabBarAttr({

index: ret.index

});

if(ret.index==0){

api.setTabLayoutAttr({

hideNavigationBar:true,

animated:false

});

}

else if(ret.index==2){

api.setNavBarAttr({

rightButtons: [{

iconPath:'widget://image/chart.png'

}]

});

api.setTabLayoutAttr({

hideNavigationBar:false,

animated:false

});

api.addEventListener({

name:'navitembtn'

}, (ret)=>{

if(ret.type=='right'){

$util.openWin({

name: 'chart',

url: 'widget://html/test.html',

title: '统计分析',

pageParam:{

}

})

}

})

}

else{

api.setTabLayoutAttr({

hideNavigationBar:false,

animated:false

});

api.setNavBarAttr({

rightButtons: [{

}]

});

api.addEventListener({

name:'navitembtn'

}, (ret)=>{

})

}

});

},

单独页面中的配置

apiready(){

//添加右上角按钮

api.setNavBarAttr({

rightButtons: [{

text: '添加'

}]

});

//监听右上角按钮点击事件

api.addEventListener({

name: 'navitembtn'

}, (ret, err)=> {

if (ret.type == 'right') {

$util.openWin({

name: 'addjcpics',

url: 'addjcpics.stml',

title: '添加检查记录照片',

pageParam:{

baseid:this.data.baseid

}

});

}

});

},

12、手写签名

手写签名用到的是drawingBoard模块。开发者可自定义固定宽高(w、h)的 “frame”,该“frame”即是可手写签名的背景透明的画板,可将此画板固定在指定的 frame 或 window 上,从而自定义出符合自己需求的各种UI效果的签名功能。

编辑切换为居中

添加图片注释,不超过 140 字(可选)

<template name='signature'>

<view class="page">

<view class="flowbottom">

<button class="btn-clear" tapmode @click="clear">重写</button>

<button class="btn" tapmode @click="submit" disabled={this.data.btn_disabled}>确定</button>

</view>

</view>

</template>

<script>

export default {

name: 'signature',

data() {

return{

btn_disabled:false,

type:''

}

},

methods: {

apiready(){

this.data.type = api.pageParam.type;

var drawingBoard = api.require('drawingBoard');

drawingBoard.open({

rect: {

x: 10,

y: 100,

w: api.frameWidth-20,

h: (api.frameWidth-20)/2

},

styles: {

brush: {

color: '#000000',

width: 3

},

bgColor: '#f0f0f0'

},

fixedOn: api.frameName

});

},

clear(){

var drawingBoard = api.require('drawingBoard');

drawingBoard.clear();

},

submit(){

this.data.btn_disabled = true;

var drawingBoard = api.require('drawingBoard');

drawingBoard.save({

savePath: 'fs://drawingBoard/'+Date.now()+'.png',

copyToAlbum: false

}, (ret)=> {

// console.log(JSON.stringify(ret));

if(ret.absolutePath=='undefined'){

this.data.btn_disabled = false;

api.toast({

msg:'签名失败,请稍后再试'

});

}

else{

//

api.sendEvent({

name: 'singture_success',

extra: {

src: ret.absolutePath,

type:this.data.type

}

});

drawingBoard.close();

api.closeWin();

}

});

}

}

}

</script>

<style>

.page {

display: flex;

flex-flow: row nowrap;

height: 100%;

width: 100%;

background-color: #eaf0fa;

}

.flowbottom{

width: 100%;

align-self: flex-end;

padding: 10px;

}

.btn {

display: block;

height: 50px;

width: 100%;

background:#1492ff;

border-radius: 5px;

color: #fff;

font-size: 20px;

font-weight: bolder;

padding: 0;

margin-top: 10px;

}

.btn-clear {

display: block;

height: 50px;

width: 100%;

background:#ff0000;

border-radius: 5px;

color: #fff;

font-size: 20px;

font-weight: bolder;

padding: 0;

margin-top: 10px;

}

</style>

13、清除缓存

由于项目中有很多拍照、查看照片场景,在使用的过程中,就会产生很多的缓存,导致应用反应变慢。所以在应用中增加了清除缓存功能,用的是官方提供的api.clearCache。

在个人中心 apiready中先获取到应用中的缓存,然后点击清除缓存按钮即可清除。

<view class="item" οnclick="clearCache">

<image class="item-icon" src="../../images/w_02.png" mode="widthFix"></image>

<text class="item-title">缓存</text>

<text class="item-right-cache">{cache}M</text>

</view>

apiready(){

//获取APP缓存 异步返回结果:

api.getCacheSize((ret) => {

this.data.cache = parseInt(ret.size/1024/1024).toFixed(1);

});

},

clearCache(){

api.clearCache(() => {

api.toast({

msg: '清除完成'

});

});

this.data.cache=0;

},

14、下载并打开word文件

点击下载word文件按钮,调用系统接口,接口会把文件的路径进行返回,先通过api.download将文件下载到本地,然后通过模块docInteraction调用第三方app打开文档。

编辑切换为居中

添加图片注释,不超过 140 字(可选)

//监听右上角按钮点击事件

api.addEventListener({

name: 'navitembtn'

}, (ret, err) => {

if (ret.type == 'right') {

let params = {

data:{

values:{

secret: Config.secret,

id:this.data.id

}

}

}

api.showProgress();

Model.exportbase(params, (res,err) => {

if (res && res.flag == 'Success') {

//下载文件

api.download({

url: res.data,

report: true,

cache: false,

allowResume: true

}, (ret, err)=> {

// console.log(JSON.stringify(ret));

if (ret.state == 1) {

//下载成功 跳转WORD预览页面

var docInteraction =

api.require('docInteraction');

docInteraction.open({

path: ret.savePath

}, (ret, err) => {

});

} else {

if(ret.percent>0){

api.toast({

msg:'正在下载'+ret.percent+'%'

})

}

else{

api.toast({

msg:'下载失败,请稍后再试'

})

}

}

});

} else {

api.toast({

msg:'下载失败,请稍后再试'

})

}

api.hideProgress();

});

}

});

15、登录、退出

通过api.setPrefs存储用户登录信息,退出登录清空数据。

//登陆APP

submit() {

var that = this;

var user = that.data.user;

var psw = that.data.psw;

if (!user) {

this.showToast("姓名不能为空");

return;

}

if (!psw) {

this.showToast("密码不能为空");

return;

}

api.showProgress();

const params = {

data: {

values:{

secret: Config.secret,

user:user,

psw:psw

}

}

};

Model.login(params, (res,err) => {

// console.log(JSON.stringify(res));

// console.log(JSON.stringify(err));

if (res && res.flag == "Success") {

that.showToast("提交成功");

api.setPrefs({key:'name',value:res.data.name});

api.setPrefs({key:'userid',value:res.data.id});

api.setPrefs({key:'roleid',value:res.data.role});

api.setPrefs({key:'rolename',value:res.data.rolename});

api.setPrefs({key:'partid',value:res.data.part});

api.setPrefs({key:'partname',value:res.data.partname});

api.setPrefs({key:'username',value:res.data.username});

api.toast({

msg:'登陆成功,欢迎使用'

})

api.sendEvent({

name: 'setuserinfo',

});

api.closeWin();

} else {

that.showToast('登陆失败,请稍后再试');

}

api.hideProgress();

});

},

api.setPrefs设置偏好数据,数据会存储到本地文件系统。api.removePrefs清除本地存储的数据。

loginout(){

api.confirm({

title: '提示',

msg: '确定要退出登录?',

buttons: ['确定', '取消']

}, (ret, err) => {

var index = ret.buttonIndex;

if(index == 1){

//清除用户信息

api.removePrefs({

key: 'name'

});

api.removePrefs({

key: 'userid'

});

api.removePrefs({

key: 'partname'

});

api.removePrefs({

key: 'partid'

});

api.removePrefs({

key: 'role'

});

api.removePrefs({

key: 'rolename'

});

api.removePrefs({

key: 'username'

});

api.toast({

msg:'请重新登陆APP'

})

$util.openWin({

name: 'login',

url: '../user/login.stml',

title: '',

hideNavigationBar:true

});

}

});

}

后台接口

导出word用到了PhpWord,通过composer进行安装,然后再需要调用的地方直接调用,具体使用方法请参代码中示例;其中导出word模板文件有涉及到图片的导出。

<?php

namespace Home\Controller;

use Think\Controller;

class IndexController extends Controller {

//用户登陆

public function login(){

checkscret('secret');//验证授权码

checkdataPost('user');//用户名

checkdataPost('psw');//密码

$user=$_POST['user'];

$psw=$_POST['psw'];

$map['username']=$user;

$map['password']=$psw;

$map['status']='01';//注册之后 需要审核一下

$releaseInfo=M()->table('user')->field('id,name,username,part,role,getrolename(role) rolename,getpartname(part) partname')->where($map)->find();

if($releaseInfo){

returnApiSuccess('查询成功',$releaseInfo);

}

else{

returnApiError('查询失败!');

exit();

}

}

//用户注册

public function register(){

checkscret('secret');//验证授权码

checkdataPost('username');//用户名

checkdataPost('password');//密码

$username=$_POST['username'];

$name=$_POST['name'];

$password=$_POST['password'];

$part=$_POST['part'];

$data['username']=$username;

$data['name']=$name;

$data['password']=$password;

$data['part']=$part;

$data['role']=3;

$data['status']='02';//已注册未审核

$releaseInfo=M()->table('user')->data($data)->add();

if($releaseInfo){

returnApiSuccess('注册成功',$releaseInfo);

}

else{

returnApiError('注册失败!');

exit();

}

}

//基本信息登记

public function addbase(){

checkscret('secret');//验证授权码

checkdataPost('userid');

checkdataPost('partid');

//对应字段

$dwmc=$_POST['dwmc'];

$dwdz=$_POST['dwdz'];

$dwlb=$_POST['dwlb'];

$dwxz=$_POST['dwxz'];

$zgzs=$_POST['zgzs'];

$xfaqzrr_xm=$_POST['xfaqzrr_xm'];

$xfaqzrr_zw=$_POST['xfaqzrr_zw'];

$xfaqzrr_dh=$_POST['xfaqzrr_dh'];

$xfaqglr_xm=$_POST['xfaqglr_xm'];

$xfaqglr_zw=$_POST['xfaqglr_zw'];

$xfaqglr_dh=$_POST['xfaqglr_dh'];

$zjzfhgb_xm=$_POST['zjzfhgb_xm'];

$zjzfhgb_zw=$_POST['zjzfhgb_zw'];

$zjzfhgb_dh=$_POST['zjzfhgb_dh'];

$jzcs=$_POST['jzcs'];

$jzgd=$_POST['jzgd'];

$zjzmj=$_POST['zjzmj'];

$mcjzmj=$_POST['mcjzmj'];

$szcs=$_POST['szcs'];

$yymj=$_POST['yymj'];

$jcsj=$_POST['jcsj'];

$trsysj=$_POST['trsysj'];

$kysj=$_POST['kysj'];

$zlfwhzxm=$_POST['zlfwhzxm'];

$scjyzk=$_POST['scjyzk'];

$lssq=$_POST['lssq'];

$ssyjfl=$_POST['ssyjfl'];

$xfsszljsl=$_POST['xfsszljsl'];

$jcqkdj_1=$_POST['jcqkdj_1'];

$jcqkdj_2=$_POST['jcqkdj_2'];

$jcqkdj_3=$_POST['jcqkdj_3'];

$jcqkdj_4=$_POST['jcqkdj_4'];

$dwlb_qt=$_POST['dwlb_qt'];

$userid=$_POST['userid'];

$partid=$_POST['partid'];

$id=$_POST['id'];

//数据

$data['dwmc']=$dwmc;

$data['dwdz']=$dwdz;

$data['dwlb']=$dwlb;

$data['dwxz']=$dwxz;

$data['zgzs']=$zgzs;

$data['xfaqzrr_xm']=$xfaqzrr_xm;

$data['xfaqzrr_zw']=$xfaqzrr_zw;

$data['xfaqzrr_dh']=$xfaqzrr_dh;

$data['xfaqglr_xm']=$xfaqglr_xm;

$data['xfaqglr_zw']=$xfaqglr_zw;

$data['xfaqglr_dh']=$xfaqglr_dh;

$data['zjzfhgb_xm']=$zjzfhgb_xm;

$data['zjzfhgb_zw']=$zjzfhgb_zw;

$data['zjzfhgb_dh']=$zjzfhgb_dh;

$data['jzcs']=$jzcs;

$data['jzgd']=$jzgd;

$data['zjzmj']=$zjzmj;

$data['mcjzmj']=$mcjzmj;

$data['szcs']=$szcs;

$data['yymj']=$yymj;

$data['jcsj']=$jcsj;

$data['trsysj']=$trsysj;

$data['kysj']=$kysj;

$data['zlfwhzxm']=$zlfwhzxm;

$data['scjyzk']=$scjyzk;

$data['lssq']=$lssq;

$data['ssyjfl']=$ssyjfl;

$data['xfsszljsl']=$xfsszljsl;

$data['jcqkdj_1']=$jcqkdj_1;

$data['jcqkdj_2']=$jcqkdj_2;

$data['jcqkdj_3']=$jcqkdj_3;

$data['jcqkdj_4']=$jcqkdj_4;

$data['dwlb_qt']=$dwlb_qt;

$data['userid']=$userid;

$data['partid']=$partid;

$data['create_time']=time();

if($id){

$map['id']=$id;

//插入数据

$releaseInfo=M()->table('base')->where($map)->save($data);

}

else{

//插入数据

$releaseInfo=M()->table('base')->data($data)->add();

}

if($releaseInfo){

returnApiSuccess('登记成功',$releaseInfo);

}

else{

returnApiError( '登记失败,请稍后再试');

exit();

}

}

//删除登记信息

public function deletebasebyid(){

checkscret('secret');//验证授权码

checkdataPost('id');

$id=$_POST['id'];

$map['id']=$id;

$releaseInfo=M()->table('base')->where($map)->delete();

if($releaseInfo){

returnApiSuccess('删除成功',$releaseInfo);

}

else{

returnApiError('删除失败!');

exit();

}

}

//查询登记单位列表

public function querylist(){

checkscret('secret');//验证授权码

checkdataPost('limit');//下一次加载多少条

checkdataPost('userid');

$limit=$_POST['limit'];

$skip=$_POST['skip'];

if(empty($skip)){

$skip=0;

}

$userid=$_POST['userid'];

$map['userid']=$userid;

$releaseInfo=M()->table('base')->field('id,dwmc as name,dwdz as address,dwlb as type')->where($map)->limit($skip*$limit,$limit)->order('create_time desc')->select();

if($releaseInfo){

returnApiSuccess('查询成功',$releaseInfo);

}

else{

returnApiError('查询失败!');

exit();

}

}

//查询单位基本信息详情

public function querybasebyid(){

checkscret('secret');//验证授权码

checkdataPost('id');//ID

$id=$_POST['id'];

$map['id']=$id;

$releaseInfo=M()->table('base')->where($map)->find();

if($releaseInfo){

returnApiSuccess('查询成功',$releaseInfo);

}

else{

returnApiError('查询失败!');

exit();

}

}

//查询基本信息

public function querybaseinfobyid(){

checkscret('secret');//验证授权码

checkdataPost('id');//ID

$id=$_POST['id'];

$map['id']=$id;

$releaseInfo=M()->table('base')->field('dwmc,dwdz,dwxz,jzgd,jzcs,yymj')->where($map)->find();

if($releaseInfo){

returnApiSuccess('查询成功',$releaseInfo);

}

else{

returnApiError('查询失败!');

exit();

}

}

//导出基本信息表

public function exportbase(){

checkscret('secret');//验证授权码

checkdataPost('id');//ID

$id=$_POST['id'];

$map['id']=$id;

$data=M()->table('base')->where($map)->find();

if ($data) {

require_once "./vendor/autoload.php";

$tmp = new \PhpOffice\PhpWord\TemplateProcessor('./Public/template/temp_base.docx'); //打开模板

$tmp->setValue('dwmc', $data['dwmc']);

$tmp->setValue('dwdz', $data['dwdz']);

$tmp->setValue('dwlb', $data['dwlb']);

$tmp->setValue('dwxz', $data['dwxz']);

$tmp->setValue('zgzs', $data['zgzs']);

$tmp->setValue('xfaqzrr_xm', $data['xfaqzrr_xm']);

$tmp->setValue('xfaqzrr_zw', $data['xfaqzrr_zw']);

$tmp->setValue('xfaqzrr_dh', $data['xfaqzrr_dh']);

$tmp->setValue('xfaqglr_xm', $data['xfaqglr_xm']);

$tmp->setValue('xfaqglr_zw', $data['xfaqglr_zw']);

$tmp->setValue('xfaqglr_dh', $data['xfaqglr_dh']);

$tmp->setValue('zjzfhgb_xm', $data['zjzfhgb_xm']);

$tmp->setValue('zjzfhgb_zw', $data['zjzfhgb_zw']);

$tmp->setValue('zjzfhgb_dh', $data['zjzfhgb_dh']);

$tmp->setValue('jzcs', $data['jzcs']);

$tmp->setValue('jzgd', $data['jzgd']);

$tmp->setValue('zjzmj', $data['zjzmj']);

$tmp->setValue('mcjzmj', $data['mcjzmj']);

$tmp->setValue('kysj', $data['kysj']);

$tmp->setValue('szcs', $data['szcs']);

$tmp->setValue('yymj', $data['yymj']);

$tmp->setValue('jcsj', $data['jcsj']);

$tmp->setValue('trsysj', $data['trsysj']);

$tmp->setValue('zlfwhzxm', $data['zlfwhzxm']);

$tmp->setValue('scjyzk', $data['scjyzk']);

$tmp->setValue('lssq', $data['lssq']);

$tmp->setValue('ssyjfl', $data['ssyjfl']);

$tmp->setValue('xfsszljsl', $data['xfsszljsl']);

$tmp->setValue('jcqkdj_1', $data['jcqkdj_1']);

$tmp->setValue('jcqkdj_2', $data['jcqkdj_2']);

$tmp->setValue('jcqkdj_3', $data['jcqkdj_3']);

$tmp->setValue('jcqkdj_4', $data['jcqkdj_4']);

$tmp->setValue('dwlb_qt', $data['dwlb_qt']);

$tmp->saveAs('./Uploads/九小场所基本情况管理登记表_'.$data['dwmc'].'.docx');

returnApiSuccess('导出成功','http://xiaofang.*********.cn/Uploads/九小场所基本情况管理登记表_'.$data['dwmc'].'.docx');

}

else{

returnApiError('导出失败,请稍后再试!');

exit();

}

}

//消防安全综合治理登记

public function addxfaqzljl(){

checkscret('secret');//验证授权码

checkdataPost('userid');

checkdataPost('partid');

//对应字段

$dwmc=$_POST['dwmc'];

$jcsj=$_POST['jcsj'];

$bjccsmc=$_POST['bjccsmc'];

$bjccsdz=$_POST['bjccsdz'];

$jyz=$_POST['jyz'];

$jyzlxfs=$_POST['jyzlxfs'];

$jzlx=$_POST['jzlx'];

$sfdjjc=$_POST['sfdjjc'];

$sfkf=$_POST['sfkf'];

$djcs=$_POST['djcs'];

$jclb=$_POST['jclb'];

$ltjzcl=$_POST['ltjzcl'];

$sfzr=$_POST['sfzr'];

$jzrs=$_POST['jzrs'];

$jzcs=$_POST['jzcs'];

$zsqysfyaqck=$_POST['zsqysfyaqck'];

$zsqysfytswc=$_POST['zsqysfytswc'];

$zrxs=$_POST['zrxs'];

$hzzdbjxt=$_POST['hzzdbjxt'];

$zdpsmhxt=$_POST['zdpsmhxt'];

$snxfs=$_POST['snxfs'];

$mhq=$_POST['mhq'];

$mhqsl=$_POST['mhqsl'];

$xfssqtqk=$_POST['xfssqtqk'];

$dqxlqk=$_POST['dqxlqk'];

$ddzxcsyqk=$_POST['ddzxcsyqk'];

$sfsymhgwjrqnsbd=$_POST['sfsymhgwjrqnsbd'];

$sfcfyrybwxp=$_POST['sfcfyrybwxp'];

$yrybwxpcfsyqk=$_POST['yrybwxpcfsyqk'];

$sfdqkzxfpx=$_POST['sfdqkzxfpx'];

$ydsh=$_POST['ydsh'];

$yhjzgqk=$_POST['yhjzgqk'];

$userid=$_POST['userid'];

$partid=$_POST['partid'];

$id=$_POST['id'];

$baseid=$_POST['baseid'];

//数据

$data['dwmc']=$dwmc;

$data['jcsj']=$jcsj;

$data['bjccsmc']=$bjccsmc;

$data['bjccsdz']=$bjccsdz;

$data['jyz']=$jyz;

$data['jyzlxfs']=$jyzlxfs;

$data['jzlx']=$jzlx;

$data['sfdjjc']=$sfdjjc;

$data['sfkf']=$sfkf;

$data['djcs']=$djcs;

$data['jclb']=$jclb;

$data['ltjzcl']=$ltjzcl;

$data['sfzr']=$sfzr;

$data['jzrs']=$jzrs;

$data['jzcs']=$jzcs;

$data['zsqysfyaqck']=$zsqysfyaqck;

$data['zsqysfytswc']=$zsqysfytswc;

$data['zrxs']=$zrxs;

$data['hzzdbjxt']=$hzzdbjxt;

$data['zdpsmhxt']=$zdpsmhxt;

$data['snxfs']=$snxfs;

$data['mhq']=$mhq;

$data['mhqsl']=$mhqsl;

$data['xfssqtqk']=$xfssqtqk;

$data['dqxlqk']=$dqxlqk;

$data['ddzxcsyqk']=$ddzxcsyqk;

$data['sfsymhgwjrqnsbd']=$sfsymhgwjrqnsbd;

$data['sfcfyrybwxp']=$sfcfyrybwxp;

$data['yrybwxpcfsyqk']=$yrybwxpcfsyqk;

$data['sfdqkzxfpx']=$sfdqkzxfpx;

$data['ydsh']=$ydsh;

$data['yhjzgqk']=$yhjzgqk;

$data['baseid']=$baseid;

$data['userid']=$userid;

$data['partid']=$partid;

$data['create_time']=time();

//保存文件

$upload = new \Think\Upload(); // 实例化上传类

$upload->rootPath = './Uploads/'; // 设置附件上传根目录

$upload->saveName = array('uniqid', mt_rand(1,999999).'_'.md5(uniqid())); // 自定义图片重命名

$upload->exts = array('jpg', 'jpeg' ,'png'); // 设置附件上传类型 只允许照片

// 上传文件

$uploadinfo = $upload->upload();

if($uploadinfo){

if($uploadinfo['file1']['savepath'] && $uploadinfo['file1']['savename']){

$data['signature_check']="/Uploads/".$uploadinfo['file1']['savepath'].$uploadinfo['file1']['savename'];

}

if($uploadinfo['file2']['savepath'] && $uploadinfo['file2']['savename']){

$data['signature_bcheck']="/Uploads/".$uploadinfo['file2']['savepath'].$uploadinfo['file2']['savename'];

}

}

if($id){

$map['id']=$id;

//插入数据

$releaseInfo=M()->table('zhzljl')->where($map)->save($data);

}

else{

//插入数据

$releaseInfo=M()->table('zhzljl')->data($data)->add();

}

if($releaseInfo){

returnApiSuccess('登记成功',$releaseInfo);

}

else{

returnApiError( '登记失败,请稍后再试');

exit();

}

}

//查询综合检查记录

public function queryxfaqzljlyid(){

checkscret('secret');//验证授权码

checkdataPost('baseid');

$baseid=$_POST['baseid'];

$map['baseid']=$baseid;

$releaseInfo=M()->table('zhzljl')->where($map)->find();

if($releaseInfo){

returnApiSuccess('查询成功',$releaseInfo);

}

else{

returnApiError( '查询失败,请稍后再试');

exit();

}

}

//导出

public function exportxfaqzljl(){

checkscret('secret');//验证授权码

checkdataPost('id');//ID

$id=$_POST['id'];

$map['id']=$id;

$data=M()->table('xf_zhzljl')->where($map)->find();

if ($data) {

require_once "./vendor/autoload.php";

$tmp = new \PhpOffice\PhpWord\TemplateProcessor('./Public/template/temp_zljl.docx'); //打开模板

$tmp->setValue('dwmc', $data['dwmc']);

$tmp->setValue('jcsj', $data['jcsj']);

$tmp->setValue('bjccsmc', $data['bjccsmc']);

$tmp->setValue('bjccsdz', $data['bjccsdz']);

$tmp->setValue('jyz', $data['jyz']);

$tmp->setValue('jyzlxfs', $data['jyzlxfs']);

$tmp->setValue('jzlx', $data['jzlx']);

$tmp->setValue('sfdjjc', $data['sfdjjc']);

$tmp->setValue('djcs', $data['djcs']);

$tmp->setValue('sfkf', $data['sfkf']);

$tmp->setValue('jclb', $data['jclb']);

$tmp->setValue('ltjzcl', $data['ltjzcl']);

$tmp->setValue('sfzr', $data['sfzr']);

$tmp->setValue('jzrs', $data['jzrs']);

$tmp->setValue('jzcs', $data['jzcs']);

$tmp->setValue('zsqysfyaqck', $data['zsqysfyaqck']);

$tmp->setValue('zsqysfytswc', $data['zsqysfytswc']);

$tmp->setValue('zrxs', $data['zrxs']);

$tmp->setValue('hzzdbjxt', $data['hzzdbjxt']);

$tmp->setValue('zdpsmhxt', $data['zdpsmhxt']);

$tmp->setValue('snxfs', $data['snxfs']);

$tmp->setValue('mhq', $data['mhq']);

$tmp->setValue('mhqsl', $data['mhqsl']);

$tmp->setValue('xfssqtqk', $data['xfssqtqk']);

$tmp->setValue('dqxlqk', $data['dqxlqk']);

$tmp->setValue('ddzxcsyqk ', $data['ddzxcsyqk']);

$tmp->setValue('sfsymhgwjrqnsbd', $data['sfsymhgwjrqnsbd']);

$tmp->setValue('sfcfyrybwp', $data['sfcfyrybwxp']);

$tmp->setValue('yrybwxpcfsyqk', $data['yrybwxpcfsyqk']);

$tmp->setValue('sfdqkzxfpx', $data['sfdqkzxfpx']);

$tmp->setValue('ydsh', $data['ydsh']);

$tmp->setValue('yhjzgqk', $data['yhjzgqk']);

$tmp->setImageValue('signature_check', ['path' => '.'.$data['signature_check'], 'width' => 120, 'height' => 20]);

$tmp->setImageValue('signature_bcheck', ['path' => '.'.$data['signature_bcheck'], 'width' => 120, 'height' => 20]);

$tmp->saveAs('./Uploads/合用场所消防安全综合治理记录表_'.$data['bjccsmc'].'.docx');

returnApiSuccess('导出成功','http://xiaofang.********.cn/Uploads/合用场所消防安全综合治理记录表_'.$data['bjccsmc'].'.docx');

}

else{

returnApiError('导出失败,请稍后再试!');

exit();

}

}

//添加基本信息照片

public function addbasepicbyid(){

checkscret('secret');//验证授权码

checkdataPost('baseid');

checkdataPost('type');

$baseid=$_POST['baseid'];

$type=$_POST['type'];

$map['baseid']=$baseid;

$data['baseid']=$baseid;

//保存文件

$upload = new \Think\Upload(); // 实例化上传类

$upload->rootPath = './Uploads/'; // 设置附件上传根目录

$upload->saveName = array('uniqid', mt_rand(1,999999).'_'.md5(uniqid())); // 自定义图片重命名

$upload->exts = array('jpg', 'jpeg' ,'png'); // 设置附件上传类型 只允许照片

// 上传文件

$uploadinfo = $upload->upload();

if($uploadinfo){

if($type=='01'){

$data['mt']="/Uploads/".$uploadinfo['file']['savepath'].$uploadinfo['file']['savename'];

}

else if($type=='02'){

$data['yyzz']="/Uploads/".$uploadinfo['file']['savepath'].$uploadinfo['file']['savename'];

}

else if($type=='03'){

$data['dlqk']="/Uploads/".$uploadinfo['file']['savepath'].$uploadinfo['file']['savename'];

}

else if($type=='04'){

$data['sfz']="/Uploads/".$uploadinfo['file']['savepath'].$uploadinfo['file']['savename'];

}

}

$data['create_time']=time();

if($this->checkbasepic($baseid)){

$releaseInfo=M()->table('basepic')->where($map)->save($data);

}

else{

$releaseInfo=M()->table('basepic')->data($data)->add();

}

if($releaseInfo){

returnApiSuccess('添加成功',"http://xiaofang.******.cn/Uploads/".$uploadinfo['file']['savepath'].$uploadinfo['file']['savename']);

}

else{

returnApiError('添加失败!');

exit();

}

}

function checkbasepic($baseid){

$map['baseid']=$baseid;

$ret=M()->table('basepic')->where($map)->find();

if($ret){

return true;

}

else{

return false;

}

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值