APICloud AVM框架 开发CRM客户管理系统

CRM客户管理系统,通过信息技术以及互联网技术协调企业与顾客间在销售、营销和服务上的交互,从而提升其管理方式,向客户提供创新式的个性化的客户交互和服务的过程。其最终目标是吸引新客户、保留老客户以及将已有客户转为忠实客户,增加市场。

APP 开发采用APICloud AVM框架,后台采用PHP。

思维导图

功能介绍
1.客户管理:录入客户信息、客户跟进、客户销售记录、直接拨打客户电话、条件筛选查询、公共客户

2.申请、收、发货管理

3.文档库、知识库

4.工作日志、日程管理

5.产品管理、库存管理

6.门店管理、员工管理

7.统计分析:客户统计分析、门店统计分析、员工统计分析、销售统计分析

8.通讯录、消息提醒

9.即时通讯、视频会议

应用模块

项目目录

开发介绍
首页导航
系统首页使用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
  }]
}

}
动态权限
在首页的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) => {
                    
                });
            }
        }

消息事件通过sendEvent把事件广播出去,然后在其他页面通过addEventListener监听事件,通过事件名和附带的参数进行其他操作。举例:登录成功之后,需要在个人中心加载个人信息,在首页加载相关个人的数据;添加某项数据之后,需要进行刷新列表等等。
APICloud AVM框架 开发CRM客户管理系统_第1张图片

APICloud AVM框架 开发CRM客户管理系统_第2张图片

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)
                })
            })
        }
    }

双击退出程序
在首页、登录页或其他需要双击退出程序的页面,在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
                });
            }
        });
      }

清空缓存
官方自带的API clearCache,可情况全部缓存,也可选择清除多少天前的缓存。

APICloud AVM框架 开发CRM客户管理系统_第3张图片
消息推送采用极光推送,需要集成ajpush模块。
APICloud AVM框架 开发CRM客户管理系统_第4张图片
具体使用方法可详细阅读官方模块文档。
APICloud AVM框架 开发CRM客户管理系统_第5张图片
 推送功能初始化需要在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的时候需要,重新登陆之后可能存在切换账号的情况,也需要重新登陆。

定位功能
因为系统中的定位只需要确定当前位置即可,所有定位功能使用的是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;
                }
            });
        }

视频、语音通话
采用tecnetRTC开发音视频通话功能。需要先去腾讯云平台创建应用申请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 \Tencent\TLSSigAPIv2($sdkappid, $key);
  $sig = $api->genSig($userid);
  
  if($sig){
    returnApiSuccess('查询成功',$sig);
  }
  else{
    returnApiError( '查询失败,请稍后再试');
    exit();
  }
}

用户视频画面需要根据当前视频用户数,进行计算调整。




通讯录
基于scroll-view进行开发实现通讯录功能,可直接拨打电话



echarts图表
由于AVM无法解析cavans,所有图表相关的页面采用的是html,页面添加在html文件夹中,通过open.frame()进行打开。采用的Echarts.js.可去echarts官方下载,如果图标不复杂,建议使用自定义下载只选择用到的控件,减小文件体积;样式也可以自定义然后下载转述js文件,下载连接

文件目录

APICloud AVM框架 开发CRM客户管理系统_第6张图片
APICloud AVM框架 开发CRM客户管理系统_第7张图片
APICloud AVM框架 开发CRM客户管理系统_第8张图片



    
    
    统计-客户
    
    



  

扫描二维码 模块文档中推荐了2种方式,如没特殊需求,推荐使用第一种。 
APICloud AVM框架 开发CRM客户管理系统_第9张图片

APICloud AVM框架 开发CRM客户管理系统_第10张图片
//入口


扫码

//使用

        fnscanner(){
            var FNScanner = api.require('FNScanner');
            FNScanner.open({
                autorotation: true
            }, (ret, err) => {
                console.log(JSON.stringify(ret));
                console.log(JSON.stringify(err));
                if(ret){
                    if(ret.eventType=='success'){
                        api.toast({
                            msg:'扫码成功,即将跳转详情页面'
                        })            
                    }
                }
                else{
                    api.toast({
                        msg:'扫码失败,请再次尝试!'
                    })
                }
            });
        }

数据列表及分页
数据列表的分页查询,主要使用到的是上拉刷新和下拉刷新动作,在动作的回调中处理需要的参数,来实现数据的加载和刷新。其中处理的参数需要配个后台提供的接口进行重定义。



导航栏底部出现“白边”问题处理

如果navigationBar的背景设置了其他颜色,shadow使用默认的颜色,如果页面背景设置成黑色,会有条明显的“白边”效果,这时需要通过设置shadow的颜色来消除“白边”。

1.可在需要的页面通过setNavBarAttr进行设置,具体颜色值根据情况自行选择。
api.setNavBarAttr({

shadow:'#000000'

});

2.如果全局使用,则可在index.json中 设置。
APICloud AVM框架 开发CRM客户管理系统_第11张图片
后台代码
namespace Home\Controller;
require 'vendor/autoload.php'; // 注意位置一定要在 引入ThinkPHP入口文件 之前
use Think\Controller;
use JPush\Client as JPushClient;
class VideoController extends Controller {

  //查询视频会议列表
  public function queryvideomeetinglist(){
    checkscret('secret');//验证授权码
    checkdataPost('limit');//下一次加载多少条
    checkdataPost('userid');//用户ID

    $limit=$_POST['limit'];
    $skip=$_POST['skip'];
    if(empty($skip)){
      $skip=0;
    }
    
    $userid=$_POST['userid'];

    $map['_string']='(find_in_set('.$userid.',getvideomeetingusers(id)) and flag<>\'03\') or (userid='.$userid.' and flag<>\'03\')';

    $releaseInfo=M()->table('crm_video_audio_meeting')->field('id,title,getcode_value(\'音视频类型\',type) lx,type,flag,getusername(userid) fqr,userid,estimatetime,type,note')->where($map)->limit($skip,$limit)->order('estimatetime desc')->select();
    
    if($releaseInfo){
      returnApiSuccess('查询成功',$releaseInfo);
    }
    else{
      returnApiError( '查询失败!');
      exit();
    }
  }

  //查询参加音视频会议人员列表
  public function queryvideomeetingpersonlist(){
    checkscret('secret');//验证授权码

    $releaseInfo=M()->table('crm_user')->field('id as employee_id,name,getorganname(organid) remark,getrolename(roleid) position,pinyin as phonetic')->where($map)->order('organid')->select();
    
    if($releaseInfo){
      returnApiSuccess('查询成功',$releaseInfo);
    }
    else{
      returnApiError( '查询失败!');
      exit();
    }
  }


  //增加视频会议
  public function addvideomeeting(){
    checkscret('secret');//验证授权码
    checkdataPost('userid');//用户ID

    $userid=$_POST['userid'];
    $title=$_POST['title'];
    $note=$_POST['note'];
    $shijian=$_POST['shijian'];
    $ids=$_POST['ids'];

    $arrids=explode(',',$ids);

    $data['userid']=$userid;
    $data['title']=$title;
    $data['note']=$note;    
    $data['estimatetime']=$shijian;
    $data['estimatenum']=count($arrids);
    $data['type']=count($arrids)>9?'01':'02';//01 音频  02 视频
    $data['flag']='01';    

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

    if($releaseInfo){
      //添加人员参加会议记录
      foreach ($arrids as $v) {
        $datap['video_meeting_id']=$releaseInfo;
        $datap['userid']=$v;
        $res=M()->table('crm_video_audio_meeting_users')->data($datap)->add();
        //推送视频会议消息
        try{
            //添加消息记录
            $content='有一个视频会议需要您的参加,时间:'.$shijian;
            $datam['title']='视频会议通知';
            $datam['content']=$content;
            $datam['shijian']=time();
            $datam['flag']='01';//未读
            $datam['type']='03';//会议提醒
            $datam['fqr']=$userid;
            $datam['jsr']=$v;
            $resm=M()->table('crm_message')->data($datam)->add();
            $jpush = new JPushClient(C('JPUSH_APP_KEY'), C('JPUSH_MASTER_SECRET'));
            $response = $jpush->push()
                ->setPlatform('all')  //机型 IOS ANDROID
                ->addAlias($v)
                ->androidNotification($content)
                ->iosNotification($content,'',0,true)
                ->options(array(
                    'apns_production' => true,
                ))
                ->send();
        }
        catch(\Exception $e){
          returnApiSuccess('添加成功',$releaseInfo);
        }   
      } 
      returnApiSuccess('添加成功',$releaseInfo);
    }
    else{
      returnApiError( '添加失败!');
      exit();
    }

  }

  //设置会议状态
  public function setmeeting(){
    checkscret('secret');//验证授权码
    checkdataPost('id');//会议ID
    checkdataPost('flag');//会议状态

    $flag=$_POST['flag'];
    $map['id']=$_POST['id'];
    $data['flag']=$flag;
    if($flag=='02'){
      $data['starttime']=time();
    }
    else if($flag=='03'){
      $data['endtime']=time();
    }

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

    if($releaseInfo){
      returnApiSuccess('设置成功',$releaseInfo);
    }
    else{
      returnApiError( '设置失败!');
      exit();
    }
  }

  //获取会议信息
  public function GetMeetingInfo(){
    checkscret('secret');//验证授权码
    checkdataPost('id');//会议ID

    $id=$_POST['id'];
    $map['id']=$id;

    $releaseInfo=M()->table('crm_video_audio_meeting')->field('title,note,estimatetime,getusername(userid) fqr')->where($map)->find();

    if($releaseInfo){
      //获取与会人员
      $mapu['video_meeting_id']=$id;
      $datau=M()->table('crm_video_audio_meeting_users')->field('userid,getusername(userid) username')->where($mapu)->select();
      if($datau){
        $releaseInfo['users']=$datau;
      }
      returnApiSuccess('查询成功',$releaseInfo);
    }
    else{
      returnApiError( '查询失败!');
      exit();
    }
  }


//获取腾讯视频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 \Tencent\TLSSigAPIv2($sdkappid, $key);
  $sig = $api->genSig($userid);
  
  if($sig){
    returnApiSuccess('查询成功',$sig);
  }
  else{
    returnApiError( '查询失败,请稍后再试');
    exit();
  }
}

}

你可能感兴趣的:(前端html5编辑器)