CRM即“客户关系管理”,其载体是一种存储客户联系信息以及追踪客户活动的软件。在移动互联时代,CRM客户管理app更具实际价值,可以帮助企业摆脱PC的束缚、以更加灵活的方式开展业务,同时妥善地存储、更新全部客户信息,吸引新客户、保留老客户以及将已有客户转为忠实客户,实现业务增长。
一、思维导图
二、功能介绍
1. 客户管理:录入客户信息、客户跟进、客户销售记录、直接拨打客户电话、条件筛选查询、公共客户;
2. 申请、收、发货管理;
3. 文档库、知识库;
4. 工作日志、日程管理;
5. 产品管理、库存管理;
6. 门店管理、员工管理;
7. 统计分析:客户统计分析、门店统计分析、员工统计分析、销售统计分析;
8. 通讯录、消息提醒;
9. 即时通讯、视频会议。
三、应用模块
四、项目目录
五、开发过程
1. 首页导航
系统首页使用tabLayout,可以将相关参数配置在JSON文件中,再在config.xml中将content的值设置成该JSON文件的路径。如果底部导航没有特殊需求这里强烈建议大家使用tabLayout为app进行布局,官方已经将各类手机屏幕及不同的分辨率进行了适配,免去了很多适配方面的问题。
{ "name": "root", "hideNavigationBar": true, "navigationBar": { "background": "#035dff", "color": "#fff", "shadow": "#035dff", "hideBackButton": true }, "tabBar": { "scrollEnabled": false, "background": "#fff", "shadow": "#f1f1f1", "color": "#8a8a8a", "selectedColor": "#000000", "index":0, "preload": 0, "frames": [{ "name": "home", "url": "pages/main/home.stml", "title": "主页" }, { "name": "notice", "url": "pages/notice/notice-index.stml", "title": "消息通知" }, { "name": "tellbook", "url": "pages/main/tellbook.stml", "title": "通讯录" }, { "name": "my", "url": "pages/seeting/my.stml", "title": "个人中心" }], "list": [{ "text": "主页", "iconPath": "image/navbar/home-o.png", "selectedIconPath": "image/navbar/home.png", "scale":3 }, { "text": "提醒", "iconPath": "image/navbar/notice-o.png", "selectedIconPath": "image/navbar/notice.png", "scale":3 }, { "text": "通讯录", "iconPath": "image/navbar/book-o.png", "selectedIconPath": "image/navbar/book.png", "scale":3 }, { "text": "设置", "iconPath": "image/navbar/set-o.png", "selectedIconPath": "image/navbar/set.png", "scale":3 }] } }
2. 动态权限
在首页的apiready中根据提示授权需要获取的权限,app每次启动的时候就会判断是否已授权,如果未授权就提示进行授权。
apiready(){ let limits=[]; //获取权限 var resultList = api.hasPermission({ list: ['storage', 'location', 'camera', 'photos', 'phone'] }); 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 (resultList[3].granted) { // 已授权,可以继续下一步操作 } else { limits.push(resultList[3].name); } if (resultList[4].granted) { // 已授权,可以继续下一步操作 } else { limits.push(resultList[4].name); } if(limits.length>0){ api.requestPermission({ list: limits, }, (res) => { }); } }
3. 消息事件
通过sendEvent把事件广播出去,然后在其他页面通过addEventListener监听事件,通过事件名和附带的参数进行其他操作。
举例:登录成功之后,需要在个人中心加载个人信息,在首页加载相关个人的数据;添加某项数据之后,需要进行刷新列表等等。
methods: { login(){ if (!this.data.username) { this.showToast("姓名不能为空"); return; } if (!this.data.password) { this.showToast("密码不能为空"); return; } var data={ secret:'', user:this.data.username, psw:this.data.password }; api.showProgress(); POST('Index/queryuserinfo',data,{}).then(ret =>{ // console.log(JSON.stringify(ret)); if(ret.flag=='Success'){ api.setPrefs({key:'username',value:ret.data.username}); //api.setPrefs({key:'password',value:ret.data.password}); api.setPrefs({key:'userid',value:ret.data.id}); api.setPrefs({key:'roleid',value:ret.data.roleid}); api.setPrefs({key:'rolename',value:ret.data.rolename}); api.setPrefs({key:'organid',value:ret.data.organid}); api.setPrefs({key:'organname',value:ret.data.organname}); api.setPrefs({key:'organtype',value:ret.data.organtype}); api.setPrefs({key:'phone',value:ret.data.phone}); api.setPrefs({key:'name',value:ret.data.name}); api.sendEvent({ name: 'loginsuccess', }); api.closeWin(); } else{ api.toast({ msg:'登录失败!请稍后再试。' }) } api.hideProgress(); }).catch(err =>{ api.toast({ msg:JSON.stringify(err) }) }) } }
4. 接口调用
封装了req.js进行接口调用,采用了ES6语法中的Promise是异步编程的一种解决方案(比传统的回调函数更加合理、强大),用同步操作将异步流程表达出来,避免层层嵌套回调。Promise 对象提供统一接口,使得控制异步操作更加容易。有兴趣的同学可以多研究一下Promise。
const config = { schema: 'http', host: '192.168.1.5', path: 'api.php/Home', secret:'776eca99-******-11e9-9897-*******'} function req(options) { const baseUrl = `${config.schema}://${config.host}/${config.path}/`; options.url = baseUrl + options.url; return new Promise((resolve, reject) => { api.ajax(options, (ret, err) => { // console.log('[' + options.method + '] ' + options.url + ' [' + api.winName + '/' + api.frameName + ']n' + JSON.stringify({ // ...options, ret, err // })) if (ret) { resolve(ret); api.hideProgress(); } else { reject(err); api.hideProgress(); } }); })}/** * GET请求快捷方法 * @constructor * @param url {string} 地址 * @param options {Object} 附加参数 */function GET(url, options = {}) { return req({ ...options, url, method: 'GET' });} /** * POST 请求快捷方法 * @param url * @param data * @param options {Object} 附加参数 * @returns {Promise<Object>} * @constructor */function POST(url, data, options = {}) { data.secret = config.secret; return req({ ...options, url, method: 'POST', data: { values: data } });} export { req, GET, POST, config}
在页面中调用的时候首先需要引入js文件。
//引入 import {POST, GET} from '../../script/req.js' //使用 methods: { loadDaily(){ var data={ secret:'', userid: api.getPrefs({sync: true,key: 'userid'}) }; api.showProgress(); POST('Index/queryleastremind',data,{}).then(ret =>{ // console.log(JSON.stringify(ret)); if(ret.flag=='Success'){ this.data.dailyList = ret.data; this.data.isDaily = false; } else{ this.data.isDaily = true; } api.hideProgress(); }).catch(err =>{ this.data.isDaily = true; api.toast({ msg:JSON.stringify(err) }) }) } }
5. 双击退出程序
在首页、登录页或其他需要双击退出程序的页面,在apiready中添加。
apiready(){ //监听返回 双击退出程序 api.setPrefs({ key: 'time_last', value: '0' }); api.addEventListener({ name : 'keyback' }, (ret, err) => { var time_last = api.getPrefs({sync: true,key: 'time_last'}); var time_now = Date.parse(new Date()); if (time_now - time_last > 2000) { api.setPrefs({key:'time_last',value:time_now}); api.toast({ msg : '再按一次退出APP', duration : 2000, location : 'bottom' }); } else { api.closeWidget({ silent : true }); } }); }
6. 清空缓存
官方自带的API clearCache,可清空全部缓存,也可选择清除多少天前的缓存。
7. 消息推送
采用极光推送,需要集成ajpush模块。
具体使用方法可详细阅读官方模块文档。
推送功能初始化需要在app每次启动的时候进行集成,将初始化极光推送的方法集成在util工具类中,在首页进行初始化。
fnReadyAJpush(){ var jpush = api.require('ajpush'); api.addEventListener({name:'pause'}, function(ret,err) { onPause();//监听应用进入后台,通知jpush暂停事件 }) api.addEventListener({name:'resume'}, function(ret,err) { onResume();//监听应用恢复到前台,通知jpush恢复事件 }) //设置初始化 jpush.init(function(ret, err){ if(ret && ret.status){ var ali=$api.getStorage('userid'); var tag=$api.getStorage('roleid'); //绑定别名 if($api.getStorage('userid')){ jpush.bindAliasAndTags({ alias:ali, tags:[tag] }, function(ret, err){ if(ret.statusCode==0){ api.toast({ msg: '推送初始化成功'}); } else{ api.toast({ msg: '绑定别名失败'}); } }); } //监听消息 jpush.setListener(function(ret) { var content = ret.content; alert(content); }); } else{ api.toast({ msg: '推送服务初始化失败'}); } }); }
初始化使用,每次启动app的时候需要,重新登陆之后可能存在切换账 的情况,也需要重新登陆。
8. 定位功能
因为系统中的定位只需要确定当前位置即可,所有定位功能使用的是aMapLBS模块,此模块没有打开地图的功能,只需要在用到的页面直接调用获取定位即可。
使用前需要在config.xml中进行配置,具体参数需要去高德开放平台去申请。
//获取当前位置信息和经纬度 setLocation(){ var aMapLBS = api.require('aMapLBS'); aMap.updateLocationPrivacy({ privacyAgree:'didAgree', privacyShow:'didShow', containStatus:'didContain' }); aMapLBS.configManager({ accuracy: 'hundredMeters', filter: 1 }, (ret, err) => { if (ret.status) { aMapLBS.singleLocation({ timeout: 2 }, (ret, err) => { if (ret.status) { this.data.lon = ret.lon; this.data.lat = ret.lat; } }); aMapLBS.singleAddress({ timeout: 2 }, (ret, err) => { if (ret.status) { this.data.address = ret.formattedAddress; } }); } else{ api.toast({ msg:'定位初始化失败,请开启手机定位。' }) return false; } }); }
9. 视频、语音通话
采用tencentTRTC开发音视频通话功能。需要先去腾讯云平台创建应用申请key,在通过官方提供的方法生成userSig。
生成userSig代码:
//获取腾讯视频RTC usersig public function getQQrtcusersig(){ checkscret('secret');//验证授权码 checkdataPost('userid');//用户ID $sdkappid=C('sdkappid'); $key=C('usersig_key'); $userid=$_POST['userid']; require 'vendor/autoload.php'; $api = new TencentTLSSigAPIv2($sdkappid, $key); $sig = $api->genSig($userid); if($sig){ returnApiSuccess('查询成功',$sig); } else{ returnApiError( '查询失败,请稍后再试'); exit(); } }
用户视频画面需要根据当前视频用户数,进行计算调整。
<template> <view class="page"> <view class="video-bk"></view> <view class="footer"> <view class="footer-item" @click="setLoud"> <image class="footer-item-ico" src='../../image/loud-on.png' mode="widthFix" 声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!