crm开源系统 tp框架_聊聊这个倾注10年的开源项目,如何一步步火爆GitHub

近几年悟空CRM开源项目在GitHub和码云上迅速蹿红,并获得了上千用户的关注。目前累计2,000,000下载量。社区人数达到30,000多人。在国内浩瀚的开源市场,悟空CRM在开源道路上倾注10多年的心血。

2010年初,受国外salesforce、zoho等saas供应商的影响,越来越多的企业开始投入CRM的研发。为找到属于自己的品牌方向,悟空团队以openerp(odoo)为标杆,开始了在开源道路上探索,并为之进行了近十年的投入。

2014年第一个版本发布

悟空CRM项目在2010开始启动,对于初创团队来讲,产品的研发迭代以及投入精力有限,直到2104年悟空CRM推出第一个开源CRM版本V0.0.1,当时的国内企业管理软件的开源市场并未完全成熟,再加上V0.0.1版本存在功能和技术的限制,产品发布后并没有获得大量的用户群体。

2016年继续迭代

悟空CRM在版本迭代上并没有想想的那么快,一部分研发投入开源、一部分研发投入二次开发项目,毕竟对于一个企业来讲,生存是第一要素。经过两年的12次迭代代,2016年悟空CRM版本迭代至V0.4.5,并在码云和Github上发布后,获得了上千家用户的下载和体验。V0.4.5该版本在原有的基础上做了全面升级和改造,是目前市场上使用较为稳定一个版本。

但是在这个技术日新月异的时代。node、vue、微服务、Python、AI各种技术不断兴起,悟空CRM开源提供的技术已经很难满足现有技术爱好者的需求,开源道路在国内再一次受到阻力,开源项目暂且搁置。

2019年一次新的挑战

是否继续开源?是一个很艰难的决定。毕竟开源项目要投入大量的精力。对企业的成本是不小的挑战。但是悟空CRM毕竟在开源道路上已经倾注多年的心血,开源是必将继续!

重整旗鼓!这一次在技术方面面临一个重大的调整,悟空CRM决定推出目前流行的前后端分离技术,后端采用PHP和JAVA 两种开发语言,前端采用最火爆的vue架构。两种后台开发语言架构是国内唯一尝试的,无论是PHP或者JAVA任一技术栈的开发人员都可尝试学习。

2019年做极致的开源产品

2019年4月PHP版发布了:基于TP5.0+vue+ElementUI的前后端分离CRM系统2019年6月JAVA版发布了:基于jfinal+vue+ElementUI的前后端分离CRM系统项目

下载地址:https://gitee.com/wukongcrm

两个产品同年发布,发布后便获得的大量开源爱好者的关注和亲睐。高质量的源码、高标准的UI设计,这一次不仅仅在技术上悟空CRM投入的大量的时间和精力,在用户体验和UI上也进行了全面的升级的改造。

10年磨一剑,悟空CRM的开源道路还需继续前进,也会不断面临更大的挑战,相信这个开源方向已经嵌入悟空CRM的骨髓,悟空的金箍棒总有一天会变得更强大。

悟空CRM开源项目主要功能:悟空CRM开源版一共包含了100多种模块应用

JAVA版本

核心框架:jfinal3.8缓存:redis caffeine数据库连接池:Druid工具类:hutool,fastjson,poi-ooxml定时任务:jfinal-cron项目构建工具:mavenWeb容器:tomcat,undertow(默认)前端MVVM框架:Vue.JS 2.5.x路由:Vue-Router 3.x数据交互:AxiosUI框架:Element-UI 2.6.3项目结构

├──  LICENSE├──  README.md├──  build                        //  配置│      ├──  build.js│      ├──  check-versions.js│      ├──  logo.png│      ├──  utils.js│      ├──  vue-loader.conf.js│      ├──  webpack.base.conf.js│      ├──  webpack.dev.conf.js│      └──  webpack.prod.conf.js├──  config│      ├──  dev.env.js│      ├──  index.js│      └──  prod.env.js├──  favicon.ico├──  index.html                      //  入口html文件├──  package-lock.json├──  package.json                     //  定义项目所需要的各种模块,以及配置信息├──  src│      ├──  App.vue                   //  页面入口│      ├──  api                        //  api接口│      │      ├──  businessIntelligence    //  商业智能│      │      ├──  common.js                   //  公共│      │      ├──  customermanagement        //  客户管理│      │      ├──  login.js                   //  登录│      │      ├──  oamanagement                    //办公│      │      ├──  personCenter│      │      └──  systemManagement│      ├──  assets                            //  图片和图标│      │      ├──  401_images│      │      ├──  404_images│      │      ├──  iconfont│      │      └──  img│      ├──  components                         //  自定义组件│      │      ├──  CreateCom                     //  新建│      │      │      ├──  CrmRelative.vue              //  关联客户管理列表│      │      │      ├──  CrmRelativeCell.vue│      │      │      ├──  CrmRelativeTable.vue│      │      │      ├──  XhBusinessStatus.vue        //  商机状态│      │      │      ├──  XhCustomerAddress.vue  //  新建客户下的地图位置│      │      │      ├──  XhDate.vue                        //  时间选择│      │      │      ├──  XhDateTime.vue│      │      │      ├──  XhFiles.vue                        //  附件│      │      │      ├──  XhInput.vue                      //  单行输入框│      │      │      ├──  XhMultipleSelect.vue        //  多选│      │      │      ├──  XhProduct.vue                  //  产品关联│      │      │      ├──  XhProuctCate.vue              //  产品类别│      │      │      ├──  XhReceivablesPlan.vue      //  回款计划│      │      │      ├──  XhSelect.vue                        //  单选│      │      │      ├──  XhStrucUserCell.vue            //  员工部门选择框│      │      │      ├──  XhStructure.vue                    //  部门选择│      │      │      ├──  XhStructureCell.vue│      │      │      ├──  XhTextarea.vue                      //  多行输入框│      │      │      ├──  XhUser.vue                            //  员工选择│      │      │      ├──  XhUserCell.vue│      │      │      ├──  arrayMixin.js                            //  公共逻辑│      │      │      ├──  index.js│      │      │      ├──  objMixin.js│      │      │      └──  stringMixin.js│      │      ├──  CreateSections.vue                          //  容器布局│      │      ├──  CreateView.vue│      │      ├──  DetailCell.vue│      │      ├──  EditImage.vue                                    //  编辑图片│      │      ├──  Examine                                          //  审批展示和操作│      │      ├──  MapView.vue                                      //  地图预览位置│      │      ├──  SlideView.vue│      │      ├──  emoji.vue                                              //  表情│      │      ├──  flexbox                                                  //  flex│      │      │      ├──  flexbox-item.vue│      │      │      ├──  flexbox.vue│      │      │      └──  index.js│      │      ├──  relatedBusiness.vue                              //  关联客户内容│      │      ├──  reminder.vue│      │      ├──  selectEmployee                                    //  选择员工│      │      └──  vuePictureViewer                                  //  文件预览│      ├──  directives                                            //  自定义指令│      │      ├──  empty│      │      ├──  photo│      ├──  filters                                          //  过滤器│      ├──  main.js                                         //  程序入口│      ├──  permission.js                                                    //  路由处理│      ├──  route加载更多

复制代码通过权限注解在拦截器判断用户是否拥有访问权限

@Overridepublic void intercept(Invocation invocation) {    //TODO 权限功能后台拦截    Permissions permissions=invocation.getMethod().getAnnotation(Permissions.class);    if(permissions!=null&&permissions.value().length>0){        JSONObject jsonObject= Aop.get(AdminRoleService.class).auth(BaseUtil.getUserId());        //组装应有权限列表        List arr=queryAuth(jsonObject, "");        boolean isRelease=false;        for (String key : permissions.value()) {            if(!isRelease){                if(arr.contains(key)){                    isRelease=true;                }            }        }        if(!isRelease){            invocation.getController().renderJson(R.error("无权访问"));            return;        }    }    invocation.invoke();

}复制代码通过AOP和注解对数据进行非空校验,无需一个个判断参数是否为空,数据为空直接返回 自定义分页数据接收,自动处理分页参数和数据对象,给controller方法加上参数 BasePageRequest,T为对象类型,然后参数就会自动组装成分页参数和定义的对象类,以下为实现代码:

public class PageParaGetter extends ParaGetter {    public PageParaGetter(String parameterName, String defaultValue) {        super(parameterName, defaultValue);    }    @Override    protected BasePageRequest to(String s) {        return null;    }@Override@SuppressWarnings("unchecked")public BasePageRequest get(Action action, Controller controller) {    Parameter[] parameters=action.getMethod().getParameters();    Class clazz=null;    for (Parameter parameter:parameters){        if(BasePageRequest.class.isAssignableFrom(parameter.getType())){            Type parameterizedType=parameter.getParameterizedType();            if (parameterizedType instanceof ParameterizedType) {                Type[] params = ((ParameterizedType) parameterizedType).getActualTypeArguments();                clazz= TypeUtils.getClass(params[0]);            }            break;        }    }    boolean isJson=controller.getHeader("Content-Type")!=null&&controller.getHeader("Content-Type").toLowerCase().contains("application/json");    return isJson?new BasePageRequest(controller.getRawData(),clazz):new BasePageRequest(controller.getKv(),clazz);}}

复制代码自定义json工厂,实现对数据的个性化解析返回,如实现将数据返回时将数据转成驼峰规则,自定义某种类型的对象的返回格式等。可以自定义错误处理模板,在出现错误或者其他异常的情况下,可以给予用户一个清晰的提示,避免用户看到一些无用的错误信息等功能文件可以上传到项目目录之外,避免了重新打包项目后文件的丢失

@Overridepublic void configConstant(Constants me) {    me.setDevMode(prop.getBoolean("jfinal.devMode", true));    me.setInjectDependency(true);    //设置上传文件到哪个目录    me.setBaseUploadPath(BaseConstant.UPLOAD_PATH);    me.setBaseDownloadPath(BaseConstant.UPLOAD_PATH);  //自定义json工厂    me.setJsonFactory(new ErpJsonFactory());    //限制上传100M    me.setMaxPostSize(104857600);}

复制代码采用项目分层化的设计,职责分工明确,降低代码的耦合性Hander->对指定规则的url进行捕获或者放心Interceptor->环绕式AOP拦截,对访问权限,数据权限,参数等进行校验,可以配置在全局,单个路由,单个controller,单个方法等上面,可进行自定义实现,对数据进行处理Router->对不同规则的数据进行分发,不同url进入不同路由和controllerController->对参数进行组装,将数据传入到service处理后进行render返回Service->对业务代码进行处理,并将数据转入Db处理或缓存 Db->对数据库进行操作 Render->将service返回的数据在controller进行返回,以及出错后通过SQL模板功能,将sql写入到xx.sql文件中,如果sql文件有变动,无需重新编译打包,直接改动sql文件中的sql即可,以下为自动扫描指定路径下sql文件的代码:

private void getSqlTemplate(String path, ActiveRecordPlugin arp) {    File file = new File(path);    if (file.exists()) {        File[] files = file.listFiles();        if (files != null && files.length > 0) {            for (File childFile : files) {                if (childFile.isDirectory()) {                    getSqlTemplate(childFile.getAbsolutePath(), arp);                } else {                    if (childFile.getName().toLowerCase().endsWith(".sql")) {                        arp.addSqlTemplate(childFile.getAbsolutePath().replace(PathKit.getRootClassPath(), "").replace("", "/"));                    }                }            }        }    }}

PHP版本后端框架:

ThinkPHP 5.0.2前端MVVM框架:Vue.JS 2.5.x路由:Vue-Router 3.x数据交互:AxiosUI框架:Element-UI 2.6.3悟空crm9.0的运行环境要求PHP5.6以上悟空CRM9.0(PHP)版本应用部署目录结构

├─application           应用目录(可设置)│  ├─admin               系统设置目录│  │  ├─config.php      模块配置文件│  │  ├─common.php      模块函数文件│  │  ├─controller      控制器目录│  │  ├─model           模型目录│  │  ├─validate        验证器目录│  │  ├─view            视图目录│  │  └─lang            语言包│  ├─bi                  商业智能模块目录│  │  ├─config.php      模块配置文件│  │  ├─common.php      模块函数文件│  │  ├─controller      控制器目录│  │  ├─model           模型目录│  │  ├─validate        验证器目录│  │  ├─view            视图目录│  │  └─lang            语言包│  ├─common              公共模块目录│  │  ├─adapter         认证权限类目录│  │  ├─behavior        行为(钩子)目录│  │  ├─controller      公共控制器目录│  │  └─lang            语言包​│  ├─crm                 客户管理目录│  │  ├─config.php      模块配置文件│  │  ├─common.php      模块函数文件│  │  ├─controller      控制器目录│  │  ├─model           模型目录│  │  ├─validate        验证器目录│  │  ├─view            视图目录│  │  └─lang            语言包│  ├─lang                语言包│  ├─oa                  办公目录│  │  ├─config.php      模块配置文件│  │  ├─common.php      模块函数文件│  │  ├─controller      控制器目录│  │  ├─model           模型目录│  │  ├─validate        验证器目录│  │  ├─view            视图目录│  │  └─lang            语言包│  ├─work                项目管理目录│  │  ├─config.php      模块配置文件│  │  ├─common.php      模块函数文件│  │  ├─controller      控制器目录│  │  ├─model           模型目录│  │  ├─validate        验证器目录│  │  ├─view            视图目录│  │  └─lang            语言包│  ├─command.php        命令行工具配置文件│  ├─common.php         应用公共(函数)文件│  ├─tags.php           应用行为扩展定义文件├─config                配置目录(可定义)│  ├─config.php         应用(公共)配置文件│  ├─database.php       数据库配置文件│  ├─route_admin.php    系统设置路由文件│  ├─route_bi.php       商业智能路由文件│  ├─route_crm.php      客户管理路由文件│  ├─route_oa.php       办公路由文件│  ├─route_work.php     项目管理路由文件│  └─version.php        版本信息文件├─extend                扩展类库目录(可定义)├─public                WEB 部署目录(对外访问目录)│  ├─sql                安装及更新sql目录│  ├─static             静态资源存放目录(css,js,image)│  └─.uploads           上传文件目录├─runtime               应用的运行时目录(可写,可设置)├─static                前端VUE打包目录=├─vendor                第三方类库目录(Composer)├─thinkphp              框架系统目录│  ├─lang               语言包目录│  ├─library            框架核心类库目录│  │  ├─think           Think 类库包目录│  │  └─traits          系统 Traits 目录│  ├─tpl                系统模板目录│  ├─.htaccess          用于 apache 的重写│  ├─.travis.yml        CI 定义文件│  ├─base.php           基础定义文件│  ├─composer.json      composer 定义文件│  ├─console.php        控制台入口文件│  ├─convention.php     惯例配置文件│  ├─helper.php         助手函数文件(可选)│  ├─LICENSE.txt        授权说明文件│  ├─phpunit.xml        单元测试配置文件│  ├─README.md          README 文件│  └─start.php          框架引导文件├─composer.json         composer 定义文件├─LICENSE.txt           授权说明文件├─README.md             README 文件├─think                  命令行入口文件├─index.php             应用入口文件├─index.html            前端展示入口文件复制代码系统截图
2aebbe32ca6ee49e18681927bd2637fb.png
1044d94a02affc56c047bd272d8c4e95.png
629ca366053fa42a2e880ee246dad11c.png
ae2ddd5c874b1392ac110b48cefb5c2d.png
f1210f1b8b088440cbc5c0c796d5e9d8.png
9e2c6925f49f8e0fb82c6e67b75871c0.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
代码中已集成前端vue打包后文件,可免去打包操作: 以本地(phpstudy集成环境)搭建举例: 下载代码,在服务器根目录(www目录)下创建文件夹,并放置代码; 浏览器访问 http://localhost/文件夹目录/index.php/admin/install/index.html 根据安装提示步骤,完成部署安装 开发依赖(需个性化安装或调整前端代码请按照以下教程,一键安装用户可忽略) 数据交互 数据交互通过axios以及RESTful架构来实现 用户校验通过登录返回的auth_key放在header 值得注意的一点是:跨域的情况下,会有预请求OPTION的情况 Server搭建 服务端使用的框架为thinkphp5.0.2,搭建前请确保拥有lamp/lnmp/wamp环境。 这里所说的搭建其实就是把server框架放入WEB运行环境,并使用80端口。 导入服务端根文件夹数据库文件public/sql/5kcrm.sql,并修改config/database.php配置文件。 配置要求 PHP >= 5.6.0 (暂不支持PHP7及以上本) 当访问 http://localhost/ 前端部署 安装node.js 前端部分是基于node.js上运行的,所以必须先安装node.js,本要求为6.0以上 使用npm安装依赖 下载前端代码; 可将代码放置在后端同级目录frontend,执行命令安装依赖: npm install 修改内部配置 修改请求地址或域名:config/dev.env.js里修改BASE_API(开发环境服务端地址,默认localhost) 修改自定义端口:config/index.js里面的dev对象的port参数(默认8080,不建议修改) 运行前端 npm run dev 注意:前端服务启动,默认会占用8080端口,所以在启动前端服务之前,请确认8080端口没有被占用。 程序运行之前需搭建好Server端

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值