巡检是企事业单位的常见场景之一,以消防检查为例,秋冬季节气温下降、生产繁忙,用火、用电、用气情况大量增加,消防安全事件多发,一款消防检查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" oninput={this.getKey}/>
<text class="search-btn" onclick="onconfirm">搜索</text>
</view>
<view class="item-box">
<view class="item" data-id={item.id} onclick={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 onsubmit={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" onclick="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" oninput={this.getKey}/>
<text class="search-btn" onclick="onconfirm">搜索</text>
</view>
<view class="item-box">
<view class="item" data-id={item.id} onclick={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 onsubmit={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" onclick="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;
}
}
}