作者 黄张义

提交

要显示太多修改。

为保证性能只显示 25 of 25+ 个文件。

  1 +open_basedir=/www/wwwroot/CRM/:/tmp/
  1 +deny from all
  1 +{"files":["application\\admin\\controller\\facrm\\Achievement.php","application\\admin\\controller\\facrm\\analysis\\Achievement.php","application\\admin\\controller\\facrm\\analysis\\Admin.php","application\\admin\\controller\\facrm\\analysis\\Customer.php","application\\admin\\controller\\facrm\\analysis\\Ranking.php","application\\admin\\controller\\facrm\\apps\\Apps.php","application\\admin\\controller\\facrm\\apps\\Config.php","application\\admin\\controller\\facrm\\apps\\Email.php","application\\admin\\controller\\facrm\\apps\\Notice.php","application\\admin\\controller\\facrm\\apps\\Sms.php","application\\admin\\controller\\facrm\\apps\\Theme.php","application\\admin\\controller\\facrm\\Backlog.php","application\\admin\\controller\\facrm\\business\\Contacts.php","application\\admin\\controller\\facrm\\business\\Index.php","application\\admin\\controller\\facrm\\business\\Record.php","application\\admin\\controller\\facrm\\clues\\Index.php","application\\admin\\controller\\facrm\\clues\\Record.php","application\\admin\\controller\\facrm\\Common.php","application\\admin\\controller\\facrm\\contract\\Index.php","application\\admin\\controller\\facrm\\contract\\Plan.php","application\\admin\\controller\\facrm\\contract\\Receivables.php","application\\admin\\controller\\facrm\\customer\\Contacts.php","application\\admin\\controller\\facrm\\customer\\Index.php","application\\admin\\controller\\facrm\\customer\\Record.php","application\\admin\\controller\\facrm\\Dashboard.php","application\\admin\\controller\\facrm\\Fields.php","application\\admin\\controller\\facrm\\flow\\Index.php","application\\admin\\controller\\facrm\\flow\\Log.php","application\\admin\\controller\\facrm\\Invoice.php","application\\admin\\controller\\facrm\\Notices.php","application\\admin\\controller\\facrm\\Operatelog.php","application\\admin\\controller\\facrm\\product\\Product.php","application\\admin\\controller\\facrm\\product\\Type.php","application\\admin\\controller\\facrm\\product\\Unit.php","application\\admin\\controller\\facrm\\setting\\Cloudcall.php","application\\admin\\controller\\facrm\\setting\\Payonline.php","application\\admin\\controller\\facrm\\setting\\Syndata.php","application\\admin\\controller\\facrm\\setting\\Validate.php","application\\admin\\controller\\facrm\\Tag.php","application\\admin\\controller\\facrm\\Third.php","application\\admin\\controller\\facrm\\workweixin\\Contacts.php","application\\admin\\controller\\facrm\\workweixin\\Index.php","application\\admin\\controller\\facrm\\workweixin\\Users.php","application\\admin\\lang\\zh-cn\\facrm\\contract\\plan.php","application\\admin\\lang\\zh-cn\\facrm\\fields.php","application\\admin\\lang\\zh-cn\\facrm\\notices.php","application\\admin\\model\\facrm\\Achievement.php","application\\admin\\model\\facrm\\business\\Contacts.php","application\\admin\\model\\facrm\\business\\Product.php","application\\admin\\model\\facrm\\Business.php","application\\admin\\model\\facrm\\Cloudcall.php","application\\admin\\model\\facrm\\CloudcallLog.php","application\\admin\\model\\facrm\\Clues.php","application\\admin\\model\\facrm\\contract\\Plan.php","application\\admin\\model\\facrm\\contract\\Product.php","application\\admin\\model\\facrm\\contract\\Receivables.php","application\\admin\\model\\facrm\\Contract.php","application\\admin\\model\\facrm\\customer\\Contacts.php","application\\admin\\model\\facrm\\Customer.php","application\\admin\\model\\facrm\\Fields.php","application\\admin\\model\\facrm\\flow\\Log.php","application\\admin\\model\\facrm\\flow\\Step.php","application\\admin\\model\\facrm\\Flow.php","application\\admin\\model\\facrm\\Invoice.php","application\\admin\\model\\facrm\\Notices.php","application\\admin\\model\\facrm\\Operatelog.php","application\\admin\\model\\facrm\\product\\Product.php","application\\admin\\model\\facrm\\product\\Type.php","application\\admin\\model\\facrm\\product\\Unit.php","application\\admin\\model\\facrm\\qywx\\Contacts.php","application\\admin\\model\\facrm\\qywx\\User.php","application\\admin\\model\\facrm\\record\\Files.php","application\\admin\\model\\facrm\\Record.php","application\\admin\\model\\facrm\\Scene.php","application\\admin\\model\\facrm\\Setting.php","application\\admin\\model\\facrm\\Tag.php","application\\admin\\validate\\facrm\\Business.php","application\\admin\\validate\\facrm\\Clues.php","application\\admin\\validate\\facrm\\contract\\Receivables.php","application\\admin\\validate\\facrm\\Contract.php","application\\admin\\validate\\facrm\\customer\\Contacts.php","application\\admin\\validate\\facrm\\Customer.php","application\\admin\\validate\\facrm\\Fields.php","application\\admin\\validate\\facrm\\Invoice.php","application\\admin\\validate\\facrm\\Notices.php","application\\admin\\validate\\facrm\\product\\Product.php","application\\admin\\validate\\facrm\\product\\Type.php","application\\admin\\validate\\facrm\\product\\Unit.php","application\\admin\\validate\\facrm\\Record.php","application\\admin\\view\\facrm\\achievement\\batch_admin.html","application\\admin\\view\\facrm\\achievement\\batch_team.html","application\\admin\\view\\facrm\\achievement\\index.html","application\\admin\\view\\facrm\\analysis\\achievement\\groups.html","application\\admin\\view\\facrm\\analysis\\achievement\\source.html","application\\admin\\view\\facrm\\analysis\\admin\\achievement.html","application\\admin\\view\\facrm\\analysis\\admin\\index.html","application\\admin\\view\\facrm\\analysis\\admin\\record.html","application\\admin\\view\\facrm\\analysis\\customer\\index.html","application\\admin\\view\\facrm\\analysis\\customer\\industry.html","application\\admin\\view\\facrm\\analysis\\customer\\level.html","application\\admin\\view\\facrm\\analysis\\customer\\source.html","application\\admin\\view\\facrm\\analysis\\ranking\\contract.html","application\\admin\\view\\facrm\\apps\\apps\\add.html","application\\admin\\view\\facrm\\apps\\apps\\edit.html","application\\admin\\view\\facrm\\apps\\apps\\index.html","application\\admin\\view\\facrm\\apps\\apps\\workweixin.html","application\\admin\\view\\facrm\\apps\\email\\add.html","application\\admin\\view\\facrm\\apps\\email\\edit.html","application\\admin\\view\\facrm\\apps\\email\\index.html","application\\admin\\view\\facrm\\apps\\email\\send.html","application\\admin\\view\\facrm\\apps\\email\\sends.html","application\\admin\\view\\facrm\\apps\\notice\\dingding.html","application\\admin\\view\\facrm\\apps\\notice\\email.html","application\\admin\\view\\facrm\\apps\\notice\\index.html","application\\admin\\view\\facrm\\apps\\notice\\min.html","application\\admin\\view\\facrm\\apps\\notice\\mp.html","application\\admin\\view\\facrm\\apps\\notice\\wxwork.html","application\\admin\\view\\facrm\\apps\\sms\\add.html","application\\admin\\view\\facrm\\apps\\sms\\edit.html","application\\admin\\view\\facrm\\apps\\sms\\index.html","application\\admin\\view\\facrm\\apps\\sms\\send.html","application\\admin\\view\\facrm\\apps\\sms\\sends.html","application\\admin\\view\\facrm\\apps\\theme\\index.html","application\\admin\\view\\facrm\\backlog\\contract.html","application\\admin\\view\\facrm\\backlog\\index.html","application\\admin\\view\\facrm\\backlog\\invoice.html","application\\admin\\view\\facrm\\backlog\\receivables.html","application\\admin\\view\\facrm\\business\\contacts\\correlation.html","application\\admin\\view\\facrm\\business\\index\\add.html","application\\admin\\view\\facrm\\business\\index\\edit.html","application\\admin\\view\\facrm\\business\\index\\index.html","application\\admin\\view\\facrm\\business\\record\\add.html","application\\admin\\view\\facrm\\business\\record\\files.html","application\\admin\\view\\facrm\\business\\record\\index.html","application\\admin\\view\\facrm\\clues\\index\\add.html","application\\admin\\view\\facrm\\clues\\index\\common.html","application\\admin\\view\\facrm\\clues\\index\\divert.html","application\\admin\\view\\facrm\\clues\\index\\edit.html","application\\admin\\view\\facrm\\clues\\index\\import.html","application\\admin\\view\\facrm\\clues\\index\\index.html","application\\admin\\view\\facrm\\clues\\index\\recyclebin.html","application\\admin\\view\\facrm\\clues\\index\\transform.html","application\\admin\\view\\facrm\\clues\\record\\add.html","application\\admin\\view\\facrm\\clues\\record\\files.html","application\\admin\\view\\facrm\\clues\\record\\index.html","application\\admin\\view\\facrm\\common\\fields.html","application\\admin\\view\\facrm\\common\\fields_12_2.html","application\\admin\\view\\facrm\\common\\fields_4_12.html","application\\admin\\view\\facrm\\common\\fields_6_2.html","application\\admin\\view\\facrm\\common\\pages.html","application\\admin\\view\\facrm\\contract\\index\\add.html","application\\admin\\view\\facrm\\contract\\index\\change.html","application\\admin\\view\\facrm\\contract\\index\\detail.html","application\\admin\\view\\facrm\\contract\\index\\edit.html","application\\admin\\view\\facrm\\contract\\index\\index.html","application\\admin\\view\\facrm\\contract\\index\\payurl.html","application\\admin\\view\\facrm\\contract\\index\\print.html","application\\admin\\view\\facrm\\contract\\index\\recyclebin.html","application\\admin\\view\\facrm\\contract\\index\\selectbusiness.html","application\\admin\\view\\facrm\\contract\\plan\\add.html","application\\admin\\view\\facrm\\contract\\plan\\edit.html","application\\admin\\view\\facrm\\contract\\plan\\index.html","application\\admin\\view\\facrm\\contract\\receivables\\add.html","application\\admin\\view\\facrm\\contract\\receivables\\detail.html","application\\admin\\view\\facrm\\contract\\receivables\\edit.html","application\\admin\\view\\facrm\\contract\\receivables\\index.html","application\\admin\\view\\facrm\\contract\\receivables\\payurl.html","application\\admin\\view\\facrm\\contract\\receivables\\recyclebin.html","application\\admin\\view\\facrm\\contract\\receivables\\selectcontract.html","application\\admin\\view\\facrm\\customer\\contacts\\add.html","application\\admin\\view\\facrm\\customer\\contacts\\edit.html","application\\admin\\view\\facrm\\customer\\contacts\\index.html","application\\admin\\view\\facrm\\customer\\contacts\\recyclebin.html","application\\admin\\view\\facrm\\customer\\index\\add.html","application\\admin\\view\\facrm\\customer\\index\\common.html","application\\admin\\view\\facrm\\customer\\index\\deal.html","application\\admin\\view\\facrm\\customer\\index\\divert.html","application\\admin\\view\\facrm\\customer\\index\\diyorder.html","application\\admin\\view\\facrm\\customer\\index\\edit.html","application\\admin\\view\\facrm\\customer\\index\\import.html","application\\admin\\view\\facrm\\customer\\index\\index.html","application\\admin\\view\\facrm\\customer\\index\\merge.html","application\\admin\\view\\facrm\\customer\\index\\recover.html","application\\admin\\view\\facrm\\customer\\index\\recyclebin.html","application\\admin\\view\\facrm\\customer\\index\\reduplicate.html","application\\admin\\view\\facrm\\customer\\index\\share.html","application\\admin\\view\\facrm\\customer\\record\\add.html","application\\admin\\view\\facrm\\customer\\record\\calllog.html","application\\admin\\view\\facrm\\customer\\record\\files.html","application\\admin\\view\\facrm\\customer\\record\\index.html","application\\admin\\view\\facrm\\dashboard\\boss.html","application\\admin\\view\\facrm\\dashboard\\index.html","application\\admin\\view\\facrm\\fields\\add.html","application\\admin\\view\\facrm\\fields\\edit.html","application\\admin\\view\\facrm\\fields\\index.html","application\\admin\\view\\facrm\\flow\\index\\add.html","application\\admin\\view\\facrm\\flow\\index\\edit.html","application\\admin\\view\\facrm\\flow\\index\\index.html","application\\admin\\view\\facrm\\flow\\log\\index.html","application\\admin\\view\\facrm\\invoice\\add.html","application\\admin\\view\\facrm\\invoice\\edit.html","application\\admin\\view\\facrm\\invoice\\index.html","application\\admin\\view\\facrm\\invoice\\opener.html","application\\admin\\view\\facrm\\invoice\\recyclebin.html","application\\admin\\view\\facrm\\invoice\\setting.html","application\\admin\\view\\facrm\\notices\\index.html","application\\admin\\view\\facrm\\operatelog\\detail.html","application\\admin\\view\\facrm\\operatelog\\index.html","application\\admin\\view\\facrm\\product\\product\\add.html","application\\admin\\view\\facrm\\product\\product\\edit.html","application\\admin\\view\\facrm\\product\\product\\index.html","application\\admin\\view\\facrm\\product\\product\\recyclebin.html","application\\admin\\view\\facrm\\product\\type\\add.html","application\\admin\\view\\facrm\\product\\type\\edit.html","application\\admin\\view\\facrm\\product\\type\\index.html","application\\admin\\view\\facrm\\product\\type\\recyclebin.html","application\\admin\\view\\facrm\\product\\unit\\add.html","application\\admin\\view\\facrm\\product\\unit\\edit.html","application\\admin\\view\\facrm\\product\\unit\\index.html","application\\admin\\view\\facrm\\product\\unit\\recyclebin.html","application\\admin\\view\\facrm\\setting\\cloudcall\\fromexten.html","application\\admin\\view\\facrm\\setting\\cloudcall\\fromextenedit.html","application\\admin\\view\\facrm\\setting\\cloudcall\\index.html","application\\admin\\view\\facrm\\setting\\cloudcall\\log.html","application\\admin\\view\\facrm\\setting\\cloudcall\\logdetail.html","application\\admin\\view\\facrm\\setting\\cloudcall\\moor.html","application\\admin\\view\\facrm\\setting\\cloudcall\\mycall.html","application\\admin\\view\\facrm\\setting\\cloudcall\\statistics.html","application\\admin\\view\\facrm\\setting\\cloudcall\\tycc100.html","application\\admin\\view\\facrm\\setting\\payonline\\index.html","application\\admin\\view\\facrm\\setting\\syndata\\index.html","application\\admin\\view\\facrm\\setting\\syndata\\synuserset.html","application\\admin\\view\\facrm\\setting\\validate\\edit.html","application\\admin\\view\\facrm\\setting\\validate\\index.html","application\\admin\\view\\facrm\\workweixin\\contacts\\index.html","application\\admin\\view\\facrm\\workweixin\\index\\index.html","application\\admin\\view\\facrm\\workweixin\\users\\edit.html","application\\admin\\view\\facrm\\workweixin\\users\\index.html","public\\assets\\addons\\facrm\\css\\bootstrap-editable.css","public\\assets\\addons\\facrm\\css\\jquery.autocomplete.min.css","public\\assets\\addons\\facrm\\css\\jquery.tagsinput.min.css","public\\assets\\addons\\facrm\\css\\spinner.css","public\\assets\\addons\\facrm\\img\\business-active.png","public\\assets\\addons\\facrm\\img\\business.png","public\\assets\\addons\\facrm\\img\\clear.png","public\\assets\\addons\\facrm\\img\\client-active.png","public\\assets\\addons\\facrm\\img\\client.png","public\\assets\\addons\\facrm\\img\\clue-active.png","public\\assets\\addons\\facrm\\img\\clue.png","public\\assets\\addons\\facrm\\img\\colorful.png","public\\assets\\addons\\facrm\\img\\data-active.png","public\\assets\\addons\\facrm\\img\\data.png","public\\assets\\addons\\facrm\\img\\home-active.png","public\\assets\\addons\\facrm\\img\\home.png","public\\assets\\addons\\facrm\\img\\loading.gif","public\\assets\\addons\\facrm\\img\\logo.png","public\\assets\\addons\\facrm\\img\\plus.png","public\\assets\\addons\\facrm\\img\\spinner.png","public\\assets\\addons\\facrm\\img\\statusbar.png","public\\assets\\addons\\facrm\\js\\bootstrap-editable.min.js","public\\assets\\addons\\facrm\\js\\china.js","public\\assets\\addons\\facrm\\js\\clipboard.min.js","public\\assets\\addons\\facrm\\js\\columntoggle.js","public\\assets\\addons\\facrm\\js\\gzyechart.js","public\\assets\\addons\\facrm\\js\\jquery.autocomplete.js","public\\assets\\addons\\facrm\\js\\jquery.colorpicker.min.js","public\\assets\\addons\\facrm\\js\\jquery.spinner.js","public\\assets\\addons\\facrm\\js\\jquery.tagsinput.js","public\\assets\\js\\backend\\facrm\\achievement.js","public\\assets\\js\\backend\\facrm\\analysis\\achievement.js","public\\assets\\js\\backend\\facrm\\analysis\\admin.js","public\\assets\\js\\backend\\facrm\\analysis\\customer.js","public\\assets\\js\\backend\\facrm\\analysis\\ranking.js","public\\assets\\js\\backend\\facrm\\apps\\apps.js","public\\assets\\js\\backend\\facrm\\apps\\email.js","public\\assets\\js\\backend\\facrm\\apps\\notice.js","public\\assets\\js\\backend\\facrm\\apps\\sms.js","public\\assets\\js\\backend\\facrm\\apps\\theme.js","public\\assets\\js\\backend\\facrm\\backlog.js","public\\assets\\js\\backend\\facrm\\business\\contacts.js","public\\assets\\js\\backend\\facrm\\business\\index.js","public\\assets\\js\\backend\\facrm\\business\\record.js","public\\assets\\js\\backend\\facrm\\clues\\index.js","public\\assets\\js\\backend\\facrm\\clues\\record.js","public\\assets\\js\\backend\\facrm\\contract\\index.js","public\\assets\\js\\backend\\facrm\\contract\\plan.js","public\\assets\\js\\backend\\facrm\\contract\\receivables.js","public\\assets\\js\\backend\\facrm\\customer\\contacts.js","public\\assets\\js\\backend\\facrm\\customer\\index.js","public\\assets\\js\\backend\\facrm\\customer\\record.js","public\\assets\\js\\backend\\facrm\\dashboard.js","public\\assets\\js\\backend\\facrm\\fields.js","public\\assets\\js\\backend\\facrm\\flow\\index.js","public\\assets\\js\\backend\\facrm\\flow\\log.js","public\\assets\\js\\backend\\facrm\\invoice.js","public\\assets\\js\\backend\\facrm\\notices.js","public\\assets\\js\\backend\\facrm\\operatelog.js","public\\assets\\js\\backend\\facrm\\product\\product.js","public\\assets\\js\\backend\\facrm\\product\\type.js","public\\assets\\js\\backend\\facrm\\product\\unit.js","public\\assets\\js\\backend\\facrm\\setting\\cloudcall.js","public\\assets\\js\\backend\\facrm\\setting\\syndata.js","public\\assets\\js\\backend\\facrm\\setting\\validate.js","public\\assets\\js\\backend\\facrm\\workweixin\\contacts.js","public\\assets\\js\\backend\\facrm\\workweixin\\users.js","public\\facrm\\index.html","public\\facrm\\static\\first.png","public\\facrm\\static\\icon.png","public\\facrm\\static\\index.css","public\\facrm\\static\\js\\chunk-vendors.603006ac.js","public\\facrm\\static\\js\\index.ec8b14de.js","public\\facrm\\static\\js\\pages-backlog-check.b4a82bcc.js","public\\facrm\\static\\js\\pages-backlog-checkLog.c23f8625.js","public\\facrm\\static\\js\\pages-backlog-checkLog~pagesA-checkLog-index.c3ac522f.js","public\\facrm\\static\\js\\pages-backlog-check~pages-backlog-checkLog~pages-backlog-index~pages-backlog-list~pages-backlog-rece~c1e1db60.d0007608.js","public\\facrm\\static\\js\\pages-backlog-check~pages-backlog-list~pages-backlog-receivablesCheck~pages-business-addBusiness-ind~a39423a0.4394d373.js","public\\facrm\\static\\js\\pages-backlog-check~pages-backlog-receivablesCheck~pages-business-addBusiness-index~pages-business-a~8be8c46a.a73d244d.js","public\\facrm\\static\\js\\pages-backlog-check~pages-backlog-receivablesCheck~pages-business-addBusiness-index~pages-business-f~d206df56.e0e1e61c.js","public\\facrm\\static\\js\\pages-backlog-index.737ca6aa.js","public\\facrm\\static\\js\\pages-backlog-list.2140c0e5.js","public\\facrm\\static\\js\\pages-backlog-list~pages-client-customerDetails~pages-contract-list-index~pages-invoice-index~pages-~4c39e008.3595a3bc.js","public\\facrm\\static\\js\\pages-backlog-receivablesCheck.19f60493.js","public\\facrm\\static\\js\\pages-business-addBusiness-index.d3928cc4.js","public\\facrm\\static\\js\\pages-business-addBusiness-selectProduct.ff0cd654.js","public\\facrm\\static\\js\\pages-business-addBusiness-selectProduct~pages-contacts-relevance~pages-highSeas-index.d9c04874.js","public\\facrm\\static\\js\\pages-business-detail.4b414062.js","public\\facrm\\static\\js\\pages-business-detail~pages-business-filter~pages-business-followUp~pages-client-filter~pages-client~c521a678.c7c1599a.js","public\\facrm\\static\\js\\pages-business-filter.c7e88fd5.js","public\\facrm\\static\\js\\pages-business-followUp.0b4339a1.js","public\\facrm\\static\\js\\pages-business-index.198f2b20.js","public\\facrm\\static\\js\\pages-business-index~pages-check-index~pages-client-index~pages-clues-list~pages-contacts-list~pages~4442d0f0.112428ac.js","public\\facrm\\static\\js\\pages-business-index~pages-client-index~pages-clues-list~pages-index-index~pages-presentation-index.cc564d85.js","public\\facrm\\static\\js\\pages-check-index.5fe6dbdb.js","public\\facrm\\static\\js\\pages-client-clientSet-clientSet.8006a30f.js","public\\facrm\\static\\js\\pages-client-clientShare.ef632008.js","public\\facrm\\static\\js\\pages-client-customerDetails.9fa2a8ca.js","public\\facrm\\static\\js\\pages-client-deal.4982e646.js","public\\facrm\\static\\js\\pages-client-details-index.77bb2687.js","public\\facrm\\static\\js\\pages-client-filter.d1f5b65d.js","public\\facrm\\static\\js\\pages-client-followUp.3bae8b7c.js","public\\facrm\\static\\js\\pages-client-index.a6ece2b4.js","public\\facrm\\static\\js\\pages-clues-cluesDetails.739a094f.js","public\\facrm\\static\\js\\pages-clues-details.c3f6562f.js","public\\facrm\\static\\js\\pages-clues-filter.557fda28.js","public\\facrm\\static\\js\\pages-clues-followUp.f59a1b03.js","public\\facrm\\static\\js\\pages-clues-index.f0ae8aec.js","public\\facrm\\static\\js\\pages-clues-list.db49c3d9.js","public\\facrm\\static\\js\\pages-contacts-addPerson.0a33c286.js","public\\facrm\\static\\js\\pages-contacts-detail.5aa1af6e.js","public\\facrm\\static\\js\\pages-contacts-filter.0481b8dd.js","public\\facrm\\static\\js\\pages-contacts-list.e4b080df.js","public\\facrm\\static\\js\\pages-contacts-relevance.63273ba3.js","public\\facrm\\static\\js\\pages-contract-index.f4afc78d.js","public\\facrm\\static\\js\\pages-contract-list-index.6679e78f.js","public\\facrm\\static\\js\\pages-highSeas-index.5a91ead9.js","public\\facrm\\static\\js\\pages-index-filter.97c0d12d.js","public\\facrm\\static\\js\\pages-index-index.2faf72d9.js","public\\facrm\\static\\js\\pages-index-index~pages-presentation-index.f6772976.js","public\\facrm\\static\\js\\pages-invoice-apply.fa494271.js","public\\facrm\\static\\js\\pages-invoice-details.e708ca20.js","public\\facrm\\static\\js\\pages-invoice-index.85734240.js","public\\facrm\\static\\js\\pages-invoice-openInvoice.8f0f5ece.js","public\\facrm\\static\\js\\pages-login-apply.237108fc.js","public\\facrm\\static\\js\\pages-login-auth.f7974135.js","public\\facrm\\static\\js\\pages-login-clause.b3cb33f0.js","public\\facrm\\static\\js\\pages-login-index.aab18b40.js","public\\facrm\\static\\js\\pages-member-list.cf369a12.js","public\\facrm\\static\\js\\pages-member-setMember.ae0ca73f.js","public\\facrm\\static\\js\\pages-member-third.cadf06e3.js","public\\facrm\\static\\js\\pages-more-cloudCallSet.1dda9ab3.js","public\\facrm\\static\\js\\pages-more-index.06df51c7.js","public\\facrm\\static\\js\\pages-more-personalDetails.462c8689.js","public\\facrm\\static\\js\\pages-more-recycle.da6323f8.js","public\\facrm\\static\\js\\pages-more-shiftClue.16744b1a.js","public\\facrm\\static\\js\\pages-more-sign.749623dd.js","public\\facrm\\static\\js\\pages-more-subscribe.b1f3e6b1.js","public\\facrm\\static\\js\\pages-more-transfer.8f74b0d9.js","public\\facrm\\static\\js\\pages-performance-celeritySet.f50207d8.js","public\\facrm\\static\\js\\pages-performance-filter.5902575a.js","public\\facrm\\static\\js\\pages-performance-index.4d40c209.js","public\\facrm\\static\\js\\pages-presentation-filter.b001ad44.js","public\\facrm\\static\\js\\pages-presentation-index.d767020a.js","public\\facrm\\static\\js\\pages-product-classify-classify.b0ae76db.js","public\\facrm\\static\\js\\pages-product-list.d722031b.js","public\\facrm\\static\\js\\pages-product-setProduct.4b0f8a69.js","public\\facrm\\static\\js\\pages-receivables-index.7bd2cbdd.js","public\\facrm\\static\\js\\pages-receivables-list.82e7e04c.js","public\\facrm\\static\\js\\pages-receivables-manage.e655b413.js","public\\facrm\\static\\js\\pages-send-index.dfe4ee07.js","public\\facrm\\static\\js\\pagesA-checkLog-index.aca8e454.js","public\\facrm\\static\\js\\pagesA-checkLog-logDetails.fe698fc5.js","public\\facrm\\static\\js\\pagesA-followLog-list.693747b9.js","public\\facrm\\static\\js\\pagesA-plan-list.9c8c2eb1.js","public\\facrm\\static\\js\\pagesA-plan-manage.7b4952e5.js","public\\facrm\\static\\js\\pagesA-wxWork-index.464eb7c5.js","public\\facrm\\static\\second.png","public\\facrm\\static\\third.png","public\\facrm\\uni_modules\\qiun-data-charts\\static\\h5\\echarts.min.js"],"license":"extended","licenseto":"10789","licensekey":"TXCDVNcJflv8IyAW KT3sWyeUeR3CRmtiCKnjxg==","domains":["brocrm.com"],"licensecodes":[],"validations":["22f57669af8d22741d3f7fd83a12766f"],"menus":["facrm","facrm\/customer","facrm\/customer\/index","facrm\/customer\/index\/receive","facrm\/customer\/index\/index","facrm\/customer\/index\/add","facrm\/customer\/index\/edit","facrm\/customer\/index\/del","facrm\/customer\/index\/multi","facrm\/customer\/index\/discard","facrm\/customer\/index\/import","facrm\/customer\/index\/recyclebin","facrm\/customer\/index\/restore","facrm\/customer\/index\/destroy","facrm\/customer\/index\/contractlist","facrm\/customer\/index\/receivableslist","facrm\/customer\/index\/getimporttpl","facrm\/customer\/index\/divert","facrm\/customer\/index\/receivables","facrm\/customer\/index\/contract","facrm\/customer\/index\/detail","facrm\/customer\/index\/contractadd","facrm\/customer\/index\/merge","facrm\/customer\/index\/next","facrm\/customer\/index\/recover","facrm\/customer\/index\/share","facrm\/customer\/index\/sdel","facrm\/customer\/index\/deal","facrm\/customer\/index\/export","facrm\/customer\/contacts","facrm\/customer\/contacts\/index","facrm\/customer\/contacts\/add","facrm\/customer\/contacts\/edit","facrm\/customer\/contacts\/del","facrm\/customer\/contacts\/multi","facrm\/customer\/contacts\/recyclebin","facrm\/customer\/contacts\/destroy","facrm\/customer\/contacts\/restore","facrm\/customer\/record","facrm\/customer\/record\/index","facrm\/customer\/record\/add","facrm\/customer\/record\/edit","facrm\/customer\/record\/del","facrm\/customer\/record\/multi","facrm\/customer\/record\/files","facrm\/customer\/record\/calllog","facrm\/customer\/index\/common","facrm\/customer\/index\/reduplicate","facrm\/business","facrm\/business\/index","facrm\/business\/index\/index","facrm\/business\/index\/add","facrm\/business\/index\/edit","facrm\/business\/index\/del","facrm\/business\/index\/multi","facrm\/business\/index\/product","facrm\/business\/contacts","facrm\/business\/contacts\/index","facrm\/business\/contacts\/correlation","facrm\/business\/contacts\/add","facrm\/business\/contacts\/edit","facrm\/business\/contacts\/del","facrm\/business\/contacts\/multi","facrm\/business\/record","facrm\/business\/record\/index","facrm\/business\/record\/add","facrm\/business\/record\/del","facrm\/business\/record\/edit","facrm\/business\/record\/multi","facrm\/business\/record\/files","facrm\/product","facrm\/product\/product","facrm\/product\/product\/get_type_list","facrm\/product\/product\/get_type_prop","facrm\/product\/product\/get_unit_list","facrm\/product\/product\/index","facrm\/product\/product\/recyclebin","facrm\/product\/product\/add","facrm\/product\/product\/edit","facrm\/product\/product\/del","facrm\/product\/product\/destroy","facrm\/product\/product\/restore","facrm\/product\/product\/multi","facrm\/product\/product\/import","facrm\/product\/type","facrm\/product\/type\/index","facrm\/product\/type\/recyclebin","facrm\/product\/type\/add","facrm\/product\/type\/edit","facrm\/product\/type\/del","facrm\/product\/type\/destroy","facrm\/product\/type\/restore","facrm\/product\/type\/multi","facrm\/product\/unit","facrm\/product\/unit\/edit","facrm\/product\/unit\/index","facrm\/product\/unit\/recyclebin","facrm\/product\/unit\/add","facrm\/product\/unit\/del","facrm\/product\/unit\/destroy","facrm\/product\/unit\/restore","facrm\/product\/unit\/multi","facrm\/contract","facrm\/contract\/index","facrm\/contract\/index\/index","facrm\/contract\/index\/recyclebin","facrm\/contract\/index\/destroy","facrm\/contract\/index\/restore","facrm\/contract\/index\/add","facrm\/contract\/index\/del","facrm\/contract\/index\/multi","facrm\/contract\/index\/print","facrm\/contract\/index\/change","facrm\/contract\/receivables","facrm\/contract\/receivables\/index","facrm\/contract\/receivables\/add","facrm\/contract\/receivables\/edit","facrm\/contract\/receivables\/del","facrm\/contract\/receivables\/multi","facrm\/contract\/receivables\/selectcontract","facrm\/contract\/receivables\/detail","facrm\/contract\/receivables\/recyclebin","facrm\/contract\/receivables\/destroy","facrm\/contract\/receivables\/restore","facrm\/contract\/index\/lists","facrm\/contract\/index\/edit","facrm\/contract\/index\/selectbusiness","facrm\/contract\/index\/selectcontact","facrm\/contract\/index\/selectpage","facrm\/contract\/index\/detail","facrm\/contract\/index\/contractadd","facrm\/contract\/receivables\/lists","facrm\/contract\/receivables\/receivablesadd","facrm\/contract\/plan","facrm\/contract\/plan\/index","facrm\/contract\/plan\/add","facrm\/contract\/plan\/edit","facrm\/contract\/plan\/del","facrm\/contract\/plan\/multi","facrm\/flow","facrm\/flow\/index","facrm\/flow\/index\/index","facrm\/flow\/index\/add","facrm\/flow\/index\/edit","facrm\/flow\/index\/del","facrm\/flow\/index\/multi","facrm\/flow\/log","facrm\/flow\/log\/index","facrm\/flow\/log\/add","facrm\/flow\/log\/edit","facrm\/flow\/log\/del","facrm\/flow\/log\/multi","facrm\/achievement","facrm\/achievement\/index","facrm\/achievement\/admin","facrm\/achievement\/edit","facrm\/achievement\/aedit","facrm\/achievement\/batchteam","facrm\/achievement\/del","facrm\/achievement\/batchadmin","facrm\/achievement\/add","facrm\/achievement\/multi","facrm\/fields","facrm\/fields\/index","facrm\/fields\/add","facrm\/fields\/edit","facrm\/fields\/multi","facrm\/fields\/del","facrm\/apps\/apps","facrm\/apps\/index","facrm\/apps\/apps\/add","facrm\/apps\/apps\/edit","facrm\/apps\/apps\/del","facrm\/apps\/apps\/index","facrm\/apps\/apps\/multi","facrm\/setting\/syndata","facrm\/setting\/syndata\/index","facrm\/setting\/syndata\/synuserset","facrm\/setting\/syndata\/synuser","facrm\/setting\/syndata\/add","facrm\/setting\/syndata\/edit","facrm\/setting\/syndata\/del","facrm\/setting\/syndata\/multi","facrm\/workweixin","facrm\/apps\/apps\/workweixin","facrm\/workweixin\/contacts","facrm\/workweixin\/contacts\/index","facrm\/workweixin\/contacts\/syn","facrm\/workweixin\/contacts\/add","facrm\/workweixin\/contacts\/edit","facrm\/workweixin\/contacts\/del","facrm\/workweixin\/contacts\/multi","facrm\/workweixin\/users","facrm\/workweixin\/users\/index","facrm\/workweixin\/users\/syn","facrm\/workweixin\/users\/add","facrm\/workweixin\/users\/edit","facrm\/workweixin\/users\/del","facrm\/workweixin\/users\/multi","facrm\/apps","facrm\/apps\/email","facrm\/apps\/email\/index","facrm\/apps\/email\/add","facrm\/apps\/email\/edit","facrm\/apps\/email\/send","facrm\/apps\/email\/del","facrm\/apps\/email\/multi","facrm\/apps\/email\/sends","facrm\/apps\/sms","facrm\/apps\/sms\/index","facrm\/apps\/sms\/add","facrm\/apps\/sms\/edit","facrm\/apps\/sms\/send","facrm\/apps\/sms\/sends","facrm\/apps\/sms\/del","facrm\/apps\/sms\/multi","facrm\/apps\/notice","facrm\/apps\/notice\/index","facrm\/apps\/notice\/edit","facrm\/notices","facrm\/notices\/index","facrm\/notices\/add","facrm\/notices\/edit","facrm\/notices\/del","facrm\/notices\/multi","facrm\/apps\/config\/index","facrm\/setting\/validate","facrm\/setting\/validate\/index","facrm\/setting\/validate\/edit","facrm\/setting\/payonline\/index","facrm\/apps\/theme\/index","facrm\/backlog","facrm\/backlog\/index","facrm\/backblog\/index1","facrm\/team_customer\/add","facrm\/team_customer\/edit","facrm\/team_customer\/del","facrm\/team_customer\/multi","facrm\/backlog\/verify","facrm\/backlog\/add","facrm\/backlog\/edit","facrm\/backlog\/del","facrm\/backlog\/multi","facrm\/analysis","facrm\/analysis\/customer","facrm\/analysis\/customer\/level","facrm\/analysis\/customer\/source","facrm\/analysis\/customer\/index","facrm\/analysis\/customer\/industry","facrm\/analysis\/customer\/add","facrm\/analysis\/customer\/edit","facrm\/analysis\/customer\/del","facrm\/analysis\/customer\/multi","facrm\/analysis\/admin","facrm\/analysis\/admin\/index","facrm\/analysis\/admin\/record","facrm\/analysis\/admin\/add","facrm\/analysis\/admin\/edit","facrm\/analysis\/admin\/del","facrm\/analysis\/admin\/multi","facrm\/analysis\/admin\/achievement","facrm\/analysis\/ranking","facrm\/analysis\/ranking\/contract","facrm\/analysis\/ranking\/receivables","facrm\/analysis\/ranking\/record","facrm\/analysis\/ranking\/product","facrm\/analysis\/ranking\/addcustomer","facrm\/analysis\/ranking\/add","facrm\/analysis\/ranking\/edit","facrm\/analysis\/ranking\/del","facrm\/analysis\/ranking\/multi","facrm\/analysis\/ranking\/index","facrm\/analysis\/achievement\/source","facrm\/analysis\/achievement\/groups","facrm\/dashboard","facrm\/dashboard\/index","facrm\/dashboard\/add","facrm\/dashboard\/edit","facrm\/dashboard\/del","facrm\/dashboard\/multi","facrm\/clues","facrm\/clues\/index","facrm\/clues\/index\/index","facrm\/clues\/index\/add","facrm\/clues\/index\/edit","facrm\/clues\/index\/del","facrm\/clues\/index\/discard","facrm\/clues\/index\/receive","facrm\/clues\/index\/divert","facrm\/clues\/index\/transform","facrm\/clues\/index\/import","facrm\/clues\/index\/getimporttpl","facrm\/clues\/index\/multi","facrm\/clues\/index\/next","facrm\/clues\/index\/restore","facrm\/clues\/index\/destroy","facrm\/clues\/index\/recyclebin","facrm\/clues\/index\/common","facrm\/clues\/record","facrm\/clues\/record\/index","facrm\/clues\/record\/add","facrm\/clues\/record\/del","facrm\/clues\/record\/files","facrm\/clues\/record\/edit","facrm\/clues\/record\/multi","facrm\/clues\/record\/calllog","facrm\/setting\/cloudcall","facrm\/setting\/cloudcall\/index","facrm\/setting\/cloudcall\/logdetail","facrm\/setting\/cloudcall\/call","facrm\/setting\/cloudcall\/edit","facrm\/setting\/cloudcall\/fromexten","facrm\/setting\/cloudcall\/fromextenedit","facrm\/setting\/cloudcall\/fromextendel","facrm\/setting\/cloudcall\/log","facrm\/setting\/cloudcall\/statistics","facrm\/invoice","facrm\/invoice\/index","facrm\/invoice\/add","facrm\/invoice\/edit","facrm\/invoice\/del","facrm\/invoice\/lists","facrm\/invoice\/recyclebin","facrm\/invoice\/destroy","facrm\/invoice\/restore","facrm\/invoice\/setting","facrm\/invoice\/opener","facrm\/invoice\/multi","facrm\/operatelog","facrm\/operatelog\/index","facrm\/operatelog\/del","facrm\/operatelog\/detail"]}
  1 +<?php
  2 +
  3 +namespace addons\facrm;
  4 +
  5 +
  6 +use app\admin\model\facrm\Contract;
  7 +use app\common\library\Menu;
  8 +use fast\Tree;
  9 +use think\Addons;
  10 +use think\Db;
  11 +use think\Exception;
  12 +use think\exception\PDOException;
  13 +use think\exception\ValidateException;
  14 +use think\Queue;
  15 +use think\Cookie;
  16 +
  17 +/**
  18 + * 插件
  19 + */
  20 +class Facrm extends Addons
  21 +{
  22 +
  23 + /**
  24 + * 插件安装方法
  25 + * @return bool
  26 + */
  27 + public function install()
  28 + {
  29 + $menu = [];
  30 + $config_file = ADDON_PATH . "facrm" . DS . 'config' . DS . "menu.php";
  31 + if (is_file($config_file)) {
  32 + $menu = include $config_file;
  33 + }
  34 + if ($menu) {
  35 + Menu::create($menu);
  36 + }
  37 + /**
  38 + * 增加手机号字段
  39 + */
  40 + $database=config('database');
  41 + $isexits=Db::query("SELECT 1 FROM information_schema.COLUMNS WHERE table_name='{$database['prefix']}admin' AND COLUMN_NAME='mobile' limit 1");
  42 + if (!$isexits){
  43 + Db::query("ALTER TABLE {$database['prefix']}admin ADD mobile VARCHAR(20) NULL COMMENT '手机'");
  44 + }
  45 +
  46 + //首次安装创建表并导入测试数据
  47 + \think\addons\Service::importsql('facrm');
  48 + if (version_compare(config('fastadmin.version'), '1.3.0', '<') && Db::name("facrm_customer")->count() == 0) {
  49 + $this->importData('testdata','');
  50 + }
  51 + return true;
  52 + }
  53 +
  54 + /**
  55 + * 插件卸载方法
  56 + * @return bool
  57 + */
  58 + public function uninstall()
  59 + {
  60 + $info = get_addon_info('facrm');
  61 + Menu::delete(isset($info['first_menu']) ? $info['first_menu'] : 'facrm');
  62 + return true;
  63 + }
  64 +
  65 + /**
  66 + * 插件启用方法
  67 + */
  68 + public function enable()
  69 + {
  70 + $info = get_addon_info('facrm');
  71 + Menu::enable(isset($info['first_menu']) ? $info['first_menu'] : 'facrm');
  72 + }
  73 +
  74 + /**
  75 + * 插件禁用方法
  76 + */
  77 + public function disable()
  78 + {
  79 + $info = get_addon_info('facrm');
  80 + Menu::disable(isset($info['first_menu']) ? $info['first_menu'] : 'facrm');
  81 + }
  82 +
  83 + /**
  84 + * 插件升级方法
  85 + */
  86 + public function upgrade()
  87 + {
  88 + $menu = include ADDON_PATH . 'facrm' . DS . 'config' . DS . 'menu.php';
  89 + Menu::upgrade('facrm', $menu);
  90 + /**
  91 + * 增加手机号字段
  92 + */
  93 + $database=config('database');
  94 + $isexits=Db::query("SELECT 1 FROM information_schema.COLUMNS WHERE table_name='{$database['prefix']}admin' AND COLUMN_NAME='mobile' limit 1");
  95 + if (!$isexits){
  96 + Db::query("ALTER TABLE {$database['prefix']}admin ADD mobile VARCHAR(20) NULL COMMENT '手机'");
  97 + }
  98 + }
  99 +
  100 + /**
  101 + * 登录后 不跟进和未成交的客户处理
  102 + */
  103 + public function adminLoginInit()
  104 + {
  105 + $config = $this->getConfig();
  106 + //不跟进 lose_day1 //不成交lose_day2
  107 +
  108 + if ($config['lose_day1'] > 0 || ($config['lose_day2'] > 0)) {
  109 + $customerModel = model('\app\admin\model\facrm\Customer');
  110 + $customerModel->where('deal_status', 0)->where('owner_user_id', 'gt', 0);
  111 +
  112 + if ($config['lose_day1'] > 0 && $config['lose_day2'] > 0) {
  113 + //如果不跟进和不成交都开启,掉入公海逻辑
  114 + $customerModel->where(function ($query) use ($config) {
  115 + $query->where('follow_time', '<', (time() - $config['lose_day1'] * 86400))->where('follow_time', 'gt', 0)->whereOr('collect_time', '<', (time() - $config['lose_day2'] * 86400));
  116 + });
  117 + } elseif ($config['lose_day1'] > 0 && ($config['lose_day2'] <= 0)) {
  118 + //如果只开启不跟进,掉入公海逻辑
  119 + $customerModel->where('follow_time', '<', (time() - $config['lose_day1'] * 86400))->where('follow_time', 'gt', 0);
  120 + } elseif ($config['lose_day1'] <= 0 && $config['lose_day2'] > 0) {
  121 + //如果只开启不成交,掉入公海逻辑
  122 + $customerModel->where('collect_time', '<', (time() - $config['lose_day2'] * 86400));
  123 + } else {
  124 + return true;
  125 + }
  126 +
  127 + $lists = $customerModel->fetchSql(false)->select();
  128 + if ($lists) {
  129 + foreach ($lists as $row) {
  130 + $owner_user_id = $row->owner_user_id;
  131 + $row->discard();
  132 + \app\admin\model\AdminLog::create([
  133 + 'title' => __("客户过期自动加入公海"),
  134 + 'content' => json_encode(['id' => $row->id, 'name' => $row->name], JSON_UNESCAPED_UNICODE),
  135 + 'url' => "customer/discard",
  136 + 'admin_id' => $owner_user_id,
  137 + ]);
  138 + }
  139 + }
  140 + }
  141 + }
  142 +
  143 +
  144 + /**
  145 + * 登录后
  146 + */
  147 + public function adminLoginAfter($request){
  148 +
  149 + $exten_type=$request->request('exten_type','');
  150 + $from_exten=$request->request('from_exten','','htmlentities');//工号
  151 + \think\Cookie::set("facrm_extentype", $exten_type?$exten_type:'',86400 * 7);//云呼通话方式
  152 + Cookie::set("facrm_from_exten", $from_exten?$from_exten:'',86400 * 7);
  153 + if($from_exten){
  154 + \app\admin\model\facrm\Cloudcall::edit('','',$from_exten,true);
  155 + }
  156 +
  157 + }
  158 +
  159 +
  160 + /**
  161 + * 审核成功钩子
  162 + * @param $param
  163 + */
  164 + public function facrmFlowVerify(&$param)
  165 + {
  166 + if (!isset($param['types'])) return false;
  167 + $check_status=($param['is_end'] == 1&&$param['status']==1)?2:(($param['status']==0)?3:1);
  168 + switch ($param['types']) {
  169 + case 'receivables':
  170 + if ($param['is_end'] == 1 && $param['status'] == 1) {
  171 + $receivablesModel = new \app\admin\model\facrm\contract\Receivables();
  172 + //$contractModel=new \app\admin\model\facrm\Contract();
  173 + $receivables = $receivablesModel::get($param['types_id']);
  174 + $receivables->contract()->setInc('return_money', $receivables->money);
  175 + $receivables->plan()->update(['status'=>2,'return_money'=>\think\Db::raw("`return_money`+{$receivables['money']}")]);
  176 + }
  177 + //1审核中、2审核通过、3审核未通过
  178 + break;
  179 + case "contract":
  180 +
  181 + if ($param['is_end'] == 1 && $param['status'] == 1) {
  182 + $contractModel = new \app\admin\model\facrm\Contract();
  183 + $contract = $contractModel::get($param['types_id']);
  184 +
  185 + $contract->customer()->update([
  186 + 'deal_status' => 1, 'deal_time' => time(),
  187 + 'purchase_times'=> Db::raw('purchase_times+1'),
  188 + 'purchase_total'=> Db::raw('purchase_total+'.$contract->money),
  189 + ]);
  190 +
  191 + //如果有商机也改成成交状态
  192 + if ($contract->business_id) {
  193 + $contract->business()->update(['is_end' => 1, 'deal_time' => time()]);//把商机改成成交状态
  194 + }
  195 +
  196 + }
  197 + break;
  198 + default:
  199 +
  200 + }
  201 + //消息通知
  202 + try {
  203 + Queue::push("addons\\facrm\\library\\notice\queue\\Flow" . ucfirst($param['types']) . "Job",
  204 + ['model_id' => $param['types_id'], 'data' => ['check_status' => $check_status]]);
  205 + } catch (\Exception $e) {
  206 +
  207 + }
  208 + //消息通知end
  209 +
  210 + return true;
  211 +
  212 + }
  213 +
  214 + /**
  215 + * 用户注册成功钩子
  216 + */
  217 + public function userRegisterSuccessed(&$user)
  218 + {
  219 + return \addons\facrm\library\Helper::synUser($user);
  220 + }
  221 +
  222 + /**
  223 + * 发送邮件成功钩子
  224 + *param_data types类型如customer,contacts| typesid对应的ID
  225 + *send_data发送邮件的内容
  226 + *types_data 当前对象的数据
  227 + * @param $param
  228 + */
  229 + public function facrmSendEmailSuccess($param)
  230 + {
  231 + if (!isset($param['param_data']) || !$param['param_data'] || !isset($param['send_data']) || !$param['send_data']) return false;
  232 + return $this->addRecord($param['param_data'], $param['send_data'], __("发送邮件"));
  233 + }
  234 +
  235 +
  236 + /**
  237 + * 发送短息成功钩子
  238 + *param_data types类型如customer,contacts| typesid对应的ID
  239 + *send_data发送短息的内容
  240 + *types_data 当前对象的数据
  241 + * @param $param
  242 + */
  243 + public function facrmSendSmsSuccess($param)
  244 + {
  245 + if (!isset($param['param_data']) || !$param['param_data'] || !isset($param['send_data']) || !$param['send_data']) return false;
  246 + return $this->addRecord($param['param_data'], $param['send_data'], __("发送短息"));
  247 + }
  248 +
  249 + /**
  250 + * 自动添加跟进
  251 + * @param $param_data
  252 + * @param $send_data
  253 + * @param string $df_content
  254 + * @return bool
  255 + * @throws \think\exception\DbException
  256 + */
  257 + private function addRecord($param_data, $send_data, $df_content = "")
  258 + {
  259 + $result = false;
  260 + $record_data = array();
  261 + if ($param_data && $param_data['types']) {
  262 + switch ($param_data['types']) {
  263 + case "customer":
  264 + //跟进客户
  265 + $customer = model('\app\admin\model\facrm\Customer');
  266 + $rowc = $customer->get($param_data['typesid']);
  267 + if (!$rowc) return false;
  268 + $rowc->follow_time = time();
  269 + $rowc->save();
  270 + $record_data['types'] = "customer";
  271 + $record_data['types_id'] = $rowc->id;
  272 + break;
  273 + case "business":
  274 + $business = model('\app\admin\model\facrm\Business');
  275 + $row = $business->get($param_data['typesid']);
  276 + if (!$row) return false;
  277 + //更新客户表
  278 + $row->customer()->update(["follow_time" => time()]);
  279 + $row->save();
  280 + $record_data['types'] = "business";
  281 + $record_data['types_id'] = $row->id;
  282 + break;
  283 + case "contacts":
  284 + //跟进客户
  285 + $contactsModel = model('\app\admin\model\facrm\customer\Contacts');
  286 + $contacts = $contactsModel->get($param_data['typesid']);
  287 + if (!$contacts || !$contacts->customer) return false;
  288 + $contacts->customer->follow_time = time();
  289 + $contacts->customer->save();
  290 + $record_data['types'] = "customer";
  291 + $record_data['types_id'] = $contacts->customer_id;
  292 + $send_data['content']=(isset($send_data['content']) ? $send_data['content'] : $df_content)."【联系人:{$contacts['name']}】";
  293 + break;
  294 + case "clues":
  295 + //跟进线索
  296 + $cluesModel = model('\app\admin\model\facrm\Clues');
  297 + $rowc = $cluesModel->get($param_data['typesid']);
  298 + if (!$rowc) return false;
  299 + $rowc->follow_time = time();
  300 + $rowc->save();
  301 + $record_data['types'] = "clues";
  302 + $record_data['types_id'] = $rowc->id;
  303 + break;
  304 + default:
  305 + break;
  306 + }
  307 + }
  308 + if ($record_data) {
  309 + (new \app\admin\model\facrm\Record)->allowField(true)->save(array_merge($record_data, [
  310 + 'content' => strip_tags(isset($send_data['content']) ? $send_data['content'] : $df_content),
  311 + 'record_type' => isset($send_data['record_type']) ? $send_data['record_type'] : 0,//跟进类型
  312 + 'create_user_id' => isset($send_data['create_user_id']) ? $send_data['create_user_id'] : 0,
  313 + ]));
  314 + }
  315 + return $result;
  316 + }
  317 +
  318 + /**
  319 + * 导入数据
  320 + */
  321 + protected function importData($sqlname="",$dir='config')
  322 + {
  323 + $sqlFile = ADDON_PATH . 'facrm' . ($dir?DS.$dir:'').DS .$sqlname.'.sql';
  324 +
  325 + if (is_file($sqlFile)) {
  326 + $lines = file($sqlFile);
  327 + $templine = '';
  328 + foreach ($lines as $line) {
  329 + if (substr($line, 0, 2) == '--' || $line == '' || substr($line, 0, 2) == '/*') {
  330 + continue;
  331 + }
  332 +
  333 + $templine .= $line;
  334 + if (substr(trim($line), -1, 1) == ';') {
  335 + $templine = str_ireplace('__PREFIX__', config('database.prefix'), $templine);
  336 + $templine = str_ireplace('INSERT INTO ', 'INSERT IGNORE INTO ', $templine);
  337 + try {
  338 + Db::getPdo()->exec($templine);
  339 + } catch (\Exception $e) {
  340 + echo $e->getMessage();
  341 + }
  342 + $templine = '';
  343 + }
  344 + }
  345 + }
  346 + }
  347 +
  348 + /**
  349 + * 手机号脚本替换
  350 + */
  351 + public function viewFilter(& $content)
  352 + {
  353 + $module = strtolower(request()->module());
  354 + $controller=strtolower(request()->controller());
  355 + $action=strtolower(request()->action());
  356 + if ($module == 'admin'&&$controller=='auth.admin'&&version_compare(config('fastadmin.version'), '1.3.4', '<')) {
  357 + $view=\think\View::instance();
  358 + $mobile=isset($view->row->mobile)?$view->row->mobile:'';
  359 + $str_rp='<div class="form-group hidden layer-footer">';
  360 + $new_rp='<div class="form-group"><label for="mobile" class="control-label col-xs-12 col-sm-2">手机:</label><div class="col-xs-12 col-sm-8"><input type="mobile" class="form-control" id="mobile" name="row[mobile]" value="'.$mobile.'" /></div></div>';
  361 + $content = preg_replace_callback("/{$str_rp}/i", function ($matches) use ($new_rp,$str_rp){
  362 + return $new_rp.$str_rp;
  363 + }, $content);
  364 + }
  365 + if ($module == 'admin'&&$controller=='index'&&$action=='index') {
  366 + $view=\think\View::instance();
  367 + if (!isset($view->auth)) return true;
  368 + //获取合同\,回款待审批
  369 + $contractModel= new Contract();
  370 + $receivablesModel=new \app\admin\model\facrm\contract\Receivables();
  371 + $invoiceModel=new \app\admin\model\facrm\Invoice();
  372 +
  373 +
  374 + $filter_w['check_status'] =['in',[0,1]];
  375 + $total = $contractModel->where($filter_w)->where('','exp','FIND_IN_SET('. $view->auth->id.',flow_admin_id)')->fetchSql(false)->count();
  376 + $total +=$receivablesModel->where($filter_w)->where('','exp','FIND_IN_SET('.$view->auth->id.',flow_admin_id)')->fetchSql(false)->count();
  377 + $total +=$invoiceModel->where($filter_w)->where('','exp','FIND_IN_SET('.$view->auth->id.',flow_admin_id)')->fetchSql(false)->count();
  378 +
  379 +
  380 + $content =$content."<script>function setsidebar(){Backend.api.sidebar({'facrm/backlog':{$total},'facrm':{$total}})}; setTimeout('setsidebar()','5000');</script>";
  381 + }
  382 + //云呼方式
  383 + if ($module == 'admin'&&$controller=='index'&&$action=='login') {
  384 + //获取云呼配置
  385 + $all_types = \addons\facrm\library\cloudcall\Call::getProviders();
  386 + $keys = "";
  387 + foreach ($all_types as $v) {
  388 + $keys .= $keys ? ',' .'cloudcall'. $v : 'cloudcall' . $v;
  389 + }
  390 + $settingModel = new \app\admin\model\facrm\Setting();
  391 + $setting= $settingModel->where('key', 'in', $keys)->where('status', 1)->find();//只找一条云呼通道
  392 + if (!$setting) return true;
  393 + $setting=$setting['values'];
  394 +
  395 + $exten_type=Cookie::get("facrm_extentype");//云呼通话方式
  396 + $from_exten=htmlentities(Cookie::get("facrm_from_exten"));//云呼通话坐席工号
  397 + $str_rp='<div class="form-group checkbox">';
  398 + $new_rp="";
  399 + if (isset($setting['open_exten'])&&$setting['open_exten']){
  400 + $new_rp=' <div class="input-group">
  401 + <div class="input-group-addon"><span class="glyphicon fa fa-phone" aria-hidden="true"></span></div>
  402 + <input type="text" class="form-control" placeholder="云呼工号,如不知道可留空" name="from_exten" value="'.$from_exten.'" />
  403 + </div>';
  404 + }
  405 +
  406 + $new_rp.=' <div class="input-group">
  407 + <div class="input-group-addon"><span class="glyphicon fa fa-phone" aria-hidden="true"></span></div>
  408 + <select class="form-control selectpicker" name="exten_type"><option value=""> 请选择云呼方式</option>
  409 + <option value="Local" '.($exten_type=='Local'?'selected':'').'>工作手机</option>
  410 + <option value="sip" '.($exten_type=='sip'?'selected':'').'>软电话</option>
  411 + <option value="gateway" '.($exten_type=='gateway'?'selected':'').'>话机方式</option>
  412 + </select>
  413 + </div>';
  414 + $content = preg_replace_callback("/{$str_rp}/i", function ($matches) use ($new_rp,$str_rp){
  415 + return $new_rp.$str_rp;
  416 + }, $content);
  417 + }
  418 + }
  419 +
  420 + /**
  421 + * 发票开具钩子
  422 + * @param $param
  423 + */
  424 + public function facrmInvoiceOpener($param){
  425 + //通知
  426 + Queue::push("addons\\facrm\\library\\notice\queue\\InvoiceJob", [
  427 + 'model_id'=>$param['id'],
  428 + ]);
  429 + }
  430 +}
  1 +{php}
  2 +$ignore=[
  3 + 'diy_text','deal_status','deal_time','is_lock',
  4 + 'level','industry','tags','source',"id",
  5 + 'create_user_id','owner_user_id','user_id','ro_user_id',
  6 + 'rw_user_id','province','city','area',
  7 + 'lng','lat','city','next_time',
  8 +];
  9 +$customer_fields=\addons\facrm\library\Helper::getfield('customer','*',['infinity'=>__("不限制唯一字段")],$ignore);
  10 +{/php}
  11 +
  12 +
  13 +<form id="config-form" class="edit-form form-horizontal" role="form" data-toggle="validator" method="POST" action="">
  14 + {if $addon.tips}
  15 + <div class="alert {$addon.tips.extend|default='alert-info-light'}" style="margin-bottom:10px;">
  16 + <b>{$addon.tips.title|htmlentities}</b><br>
  17 + {$addon.tips.value|htmlentities}
  18 + </div>
  19 + {/if}
  20 + <table class="table table-striped">
  21 + <thead>
  22 + <tr>
  23 + <th width="15%">{:__('Title')}</th>
  24 + <th width="85%">{:__('Value')}</th>
  25 + </tr>
  26 + </thead>
  27 + <tbody>
  28 + {foreach $addon.config as $item}
  29 + <tr>
  30 + <td>{$item.title|htmlentities}</td>
  31 + <td>
  32 + <div class="row">
  33 + <div class="col-sm-8 col-xs-12">
  34 + {switch $item.type}
  35 + {case string}
  36 + <input {$item.extend|htmlentities} type="text" name="row[{$item.name|htmlentities}]" value="{$item.value|htmlentities}" class="form-control" data-rule="{$item.rule|htmlentities}" data-tip="{$item.tip|htmlentities}"/>
  37 + {/case}
  38 + {case text}
  39 + <textarea {$item.extend|htmlentities} name="row[{$item.name|htmlentities}]" class="form-control" data-rule="{$item.rule|htmlentities}" rows="5" data-tip="{$item.tip|htmlentities}">{$item.value|htmlentities}</textarea>
  40 + {/case}
  41 + {case array}
  42 + <dl class="fieldlist" data-name="row[{$item.name|htmlentities}]">
  43 + <dd>
  44 + <ins>{:__('键')}</ins>
  45 + <ins>{:__('值')}</ins>
  46 + </dd>
  47 + <dd><a href="javascript:;" class="btn btn-sm btn-success btn-append"><i class="fa fa-plus"></i> {:__('Append')}</a></dd>
  48 + <textarea name="row[{$item.name|htmlentities}]" cols="30" rows="5" class="hide">{$item.value|json_encode|htmlentities}</textarea>
  49 + </dl>
  50 + {/case}
  51 + {case date}
  52 + <input {$item.extend|htmlentities} type="text" name="row[{$item.name|htmlentities}]" value="{$item.value|htmlentities}" class="form-control datetimepicker" data-date-format="YYYY-MM-DD" data-tip="{$item.tip|htmlentities}" data-rule="{$item.rule|htmlentities}"/>
  53 + {/case}
  54 + {case time}
  55 + <input {$item.extend|htmlentities} type="text" name="row[{$item.name|htmlentities}]" value="{$item.value|htmlentities}" class="form-control datetimepicker" data-date-format="HH:mm:ss" data-tip="{$item.tip|htmlentities}" data-rule="{$item.rule|htmlentities}"/>
  56 + {/case}
  57 + {case datetime}
  58 + <input {$item.extend|htmlentities} type="text" name="row[{$item.name|htmlentities}]" value="{$item.value|htmlentities}" class="form-control datetimepicker" data-date-format="YYYY-MM-DD HH:mm:ss" data-tip="{$item.tip|htmlentities}" data-rule="{$item.rule|htmlentities}"/>
  59 + {/case}
  60 + {case number}
  61 + <input {$item.extend|htmlentities} type="number" name="row[{$item.name|htmlentities}]" value="{$item.value|htmlentities}" class="form-control" data-tip="{$item.tip|htmlentities}" data-rule="{$item.rule|htmlentities}"/>
  62 + {/case}
  63 + {case checkbox}
  64 + {foreach name="item.content" item="vo"}
  65 + <label for="row[{$item.name|htmlentities}][]-{$key|htmlentities}"><input id="row[{$item.name|htmlentities}][]-{$key|htmlentities}" name="row[{$item.name|htmlentities}][]" type="checkbox" value="{$key|htmlentities}" data-tip="{$item.tip|htmlentities}" {in name="key" value="$item.value" }checked{/in} /> {$vo|htmlentities}</label>
  66 + {/foreach}
  67 + {/case}
  68 + {case radio}
  69 + {foreach name="item.content" item="vo"}
  70 + <label for="row[{$item.name|htmlentities}]-{$key|htmlentities}"><input id="row[{$item.name|htmlentities}]-{$key|htmlentities}" name="row[{$item.name|htmlentities}]" type="radio" value="{$key|htmlentities}" data-tip="{$item.tip|htmlentities}" {in name="key" value="$item.value" }checked{/in} /> {$vo|htmlentities}</label>
  71 + {/foreach}
  72 + {/case}
  73 + {case value="select" break="0"}{/case}
  74 + {case value="selects"}
  75 + {php}
  76 + if($item['name']==='unique'){
  77 + $item['content']=$customer_fields;
  78 + }
  79 +
  80 + {/php}
  81 + <select {$item.extend|htmlentities} name="row[{$item.name|htmlentities}]{$item.type=='selects'?'[]':''}" class="form-control selectpicker" data-tip="{$item.tip|htmlentities}" {$item.type=='selects'?'multiple':''}>
  82 + {foreach name="item.content" item="vo"}
  83 + <option value="{$key|htmlentities}" {in name="key" value="$item.value" }selected{/in}>{$vo|htmlentities}</option>
  84 + {/foreach}
  85 + </select>
  86 + {/case}
  87 + {case value="image" break="0"}{/case}
  88 + {case value="images"}
  89 + <div class="input-group">
  90 + <input {$item.extend|htmlentities} id="c-{$item.name|htmlentities}" class="form-control" size="50" name="row[{$item.name|htmlentities}]" type="text" value="{$item.value|htmlentities}" data-tip="{$item.tip|htmlentities}" data-rule="{$item.rule|htmlentities}">
  91 + <div class="input-group-addon no-border no-padding">
  92 + <span><button type="button" id="faupload-{$item.name|htmlentities}" class="btn btn-danger faupload" data-input-id="c-{$item.name|htmlentities}" data-mimetype="image/*" data-multiple="{$item.type=='image'?'false':'true'}" data-preview-id="p-{$item.name|htmlentities}"><i class="fa fa-upload"></i> {:__('Upload')}</button></span>
  93 + <span><button type="button" id="fachoose-{$item.name|htmlentities}" class="btn btn-primary fachoose" data-input-id="c-{$item.name|htmlentities}" data-mimetype="image/*" data-multiple="{$item.type=='image'?'false':'true'}"><i class="fa fa-list"></i> {:__('Choose')}</button></span>
  94 + </div>
  95 + <span class="msg-box n-right" for="c-{$item.name|htmlentities}"></span>
  96 + </div>
  97 + <ul class="row list-inline faupload-preview" id="p-{$item.name|htmlentities}"></ul>
  98 + {/case}
  99 + {case value="file" break="0"}{/case}
  100 + {case value="files"}
  101 + <div class="input-group">
  102 + <input {$item.extend|htmlentities} id="c-{$item.name|htmlentities}" class="form-control" size="50" name="row[{$item.name|htmlentities}]" type="text" value="{$item.value|htmlentities}" data-tip="{$item.tip|htmlentities}" data-rule="{$item.rule|htmlentities}">
  103 + <div class="input-group-addon no-border no-padding">
  104 + <span><button type="button" id="faupload-{$item.name|htmlentities}" class="btn btn-danger faupload" data-input-id="c-{$item.name|htmlentities}" data-multiple="{$item.type=='file'?'false':'true'}" data-preview-id="p-{$item.name|htmlentities}"><i class="fa fa-upload"></i> {:__('Upload')}</button></span>
  105 + <span><button type="button" id="fachoose-{$item.name|htmlentities}" class="btn btn-primary fachoose" data-input-id="c-{$item.name|htmlentities}" data-multiple="{$item.type=='file'?'false':'true'}"><i class="fa fa-list"></i> {:__('Choose')}</button></span>
  106 + </div>
  107 + <span class="msg-box n-right" for="c-{$item.name|htmlentities}"></span>
  108 + </div>
  109 + <ul class="row list-inline faupload-preview" id="p-{$item.name|htmlentities}"></ul>
  110 + {/case}
  111 + {case bool}
  112 + <label for="row[{$item.name|htmlentities}]-yes"><input id="row[{$item.name|htmlentities}]-yes" name="row[{$item.name|htmlentities}]" type="radio" value="1" {$item.value?'checked':''} data-tip="{$item.tip|htmlentities}" /> {:__('Yes')}</label>
  113 + <label for="row[{$item.name|htmlentities}]-no"><input id="row[{$item.name|htmlentities}]-no" name="row[{$item.name|htmlentities}]" type="radio" value="0" {$item.value?'':'checked'} data-tip="{$item.tip|htmlentities}" /> {:__('No')}</label>
  114 + {/case}
  115 + {default /}{$item.value|htmlentities}
  116 + {/switch}
  117 + </div>
  118 + <div class="col-sm-4"></div>
  119 + </div>
  120 +
  121 + </td>
  122 + </tr>
  123 + {/foreach}
  124 + </tbody>
  125 + </table>
  126 + <div class="form-group layer-footer">
  127 + <label class="control-label col-xs-12 col-sm-2"></label>
  128 + <div class="col-xs-12 col-sm-8">
  129 + <button type="submit" class="btn btn-success btn-embossed disabled">{:__('OK')}</button>
  130 + <button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
  131 + </div>
  132 + </div>
  133 +</form>
  134 +
  135 +
  136 +
  137 +<script>
  138 + require.callback = function () {
  139 + var tabevent = function () {
  140 + $(document).on("click", ".nav-group li a[data-toggle='tab']", function () {
  141 + var type = $(this).attr("href").substring(1);
  142 + if (type == 'all') {
  143 + $(".table-config tr").show();
  144 + } else {
  145 + $(".table-config tr").hide();
  146 + $(".table-config tr[data-type='" + type + "']").show();
  147 + }
  148 + });
  149 + };
  150 + define('backend/addon', ['jquery', 'form'], function ($, Form) {
  151 + var Controller = {
  152 + config: function () {
  153 + Form.api.bindevent($("form[role=form]"));
  154 + tabevent();
  155 + }
  156 + };
  157 + return Controller;
  158 + });
  159 + define('backend/facrm/apps/config', ['jquery', 'form'], function ($, Form) {
  160 + var Controller = {
  161 + index: function () {
  162 + Form.api.bindevent($("form[role=form]"));
  163 + tabevent();
  164 + }
  165 + };
  166 + return Controller;
  167 + });
  168 + }
  169 +</script>
  1 +<?php
  2 +
  3 +return [
  4 + [
  5 + 'type' => 'array',
  6 + 'name' => 'level',
  7 + 'title' => '客户级别',
  8 + 'value' => [
  9 + 1 => '重点客户',
  10 + '优质客户',
  11 + '普通客户',
  12 + '0' =>'无级别',
  13 + '10000' =>'其它',
  14 + ],
  15 + 'content' => [
  16 + 'value1' => 'title1',
  17 + 'value2' => 'title2',
  18 + ],
  19 + 'tip' => '',
  20 + 'rule' => '',
  21 + 'extend' => '',
  22 + ],
  23 + [
  24 + 'type' => 'array',
  25 + 'name' => 'industry',
  26 + 'title' => '行业',
  27 + 'value' => [
  28 + 1 => '金融业',
  29 + '房地产',
  30 + '商业服务',
  31 + '贸易',
  32 + '运输物流',
  33 + '服务业',
  34 + '文化传媒',
  35 + 'IT/互联网',
  36 + '其它',
  37 + ],
  38 + 'content' => [
  39 + 'value1' => 'title1',
  40 + 'value2' => 'title2',
  41 + ],
  42 + 'tip' => '',
  43 + 'rule' => '',
  44 + 'extend' => '',
  45 + ],
  46 + [
  47 + 'type' => 'array',
  48 + 'name' => 'source',
  49 + 'title' => '客户来源',
  50 + 'value' => [
  51 + 1 => '个人资源',
  52 + '广告',
  53 + '转介绍',
  54 + '搜索引擎',
  55 + '公司资源',
  56 + '电话咨询',
  57 + '官网咨询',
  58 + '公众号',
  59 + '抖音',
  60 + '企业微信',
  61 + 100000 => '其它',
  62 + 0 => '无来源',
  63 + ],
  64 + 'content' => [
  65 + 'value1' => 'title1',
  66 + 'value2' => 'title2',
  67 + ],
  68 + 'tip' => '',
  69 + 'rule' => '',
  70 + 'extend' => '',
  71 + ],
  72 + [
  73 + 'type' => 'array',
  74 + 'name' => 'record_type',
  75 + 'title' => '跟进方式',
  76 + 'value' => [
  77 + 1 => '电话',
  78 + '上门拜访',
  79 + '微信',
  80 + '短息',
  81 + ],
  82 + 'content' => [
  83 + 'value1' => 'title1',
  84 + 'value2' => 'title2',
  85 + ],
  86 + 'tip' => '',
  87 + 'rule' => '',
  88 + 'extend' => '',
  89 + ],
  90 + [
  91 + 'type' => 'array',
  92 + 'name' => 'account',
  93 + 'title' => '收款账户',
  94 + 'value' => [
  95 + 1 => '现金',
  96 + '对公账户',
  97 + '支付宝',
  98 + '微信',
  99 + '其它',
  100 + ],
  101 + 'content' => [
  102 + 'value1' => 'title1',
  103 + 'value2' => 'title2',
  104 + ],
  105 + 'tip' => '',
  106 + 'rule' => '',
  107 + 'extend' => '',
  108 + ],
  109 + [
  110 + 'type' => 'number',
  111 + 'name' => 'possess_num',
  112 + 'title' => '可拥有客户',
  113 + 'value' => '-1',
  114 + 'content' => '',
  115 + 'tip' => '限制一个员工能拥有的非成交客户数量。-1不限制',
  116 + 'rule' => '',
  117 + 'extend' => '',
  118 + ],
  119 + [
  120 + 'type' => 'number',
  121 + 'name' => 'lose_day1',
  122 + 'title' => '不跟进自动公海天数',
  123 + 'value' => '-1',
  124 + 'content' => '',
  125 + 'tip' => '多少天不跟进自动成为公海-1关闭',
  126 + 'rule' => '',
  127 + 'extend' => '',
  128 + ],
  129 + [
  130 + 'type' => 'number',
  131 + 'name' => 'lose_day2',
  132 + 'title' => '不成交自动公海天数',
  133 + 'value' => '-1',
  134 + 'content' => '',
  135 + 'tip' => '和跟进天数是或者关系-1关闭',
  136 + 'rule' => '',
  137 + 'extend' => '',
  138 + ],
  139 + [
  140 + 'type' => 'select',
  141 + 'name' => 'unique',
  142 + 'title' => '客户唯一字段',
  143 + 'value' => 'name',
  144 + 'content' => [
  145 + 'name' => '客户名称',
  146 + 'mobile' => '手机',
  147 + ],
  148 + 'tip' => '校验客户唯一的字段',
  149 + 'rule' => '',
  150 + 'extend' => '',
  151 + ],
  152 + [
  153 + 'type' => 'radio',
  154 + 'name' => 'show_contacts',
  155 + 'title' => '显示联系',
  156 + 'value' => '1',
  157 + 'content' => [
  158 + 1 => '显示',
  159 + '隐藏',
  160 + ],
  161 + 'tip' => '是否在客户列表显示手机和电话',
  162 + 'rule' => '',
  163 + 'extend' => '',
  164 + ],
  165 + [
  166 + 'type' => 'string',
  167 + 'name' => 'min_app_id',
  168 + 'title' => '小程序AppID',
  169 + 'value' => '',
  170 + 'content' => '',
  171 + 'tip' => '',
  172 + 'rule' => '',
  173 + 'extend' => '',
  174 + ],
  175 + [
  176 + 'type' => 'string',
  177 + 'name' => 'min_app_secret',
  178 + 'title' => '小程序Secret',
  179 + 'value' => '',
  180 + 'content' => '',
  181 + 'tip' => '',
  182 + 'rule' => '',
  183 + 'extend' => '',
  184 + ],
  185 + [
  186 + 'type' => 'string',
  187 + 'name' => 'map_qq_key',
  188 + 'title' => '腾讯地图KEY',
  189 + 'value' => '',
  190 + 'content' => '',
  191 + 'tip' => '',
  192 + 'rule' => '',
  193 + 'extend' => '',
  194 + ],
  195 + [
  196 + 'type' => 'string',
  197 + 'name' => 'cprefix',
  198 + 'title' => '合同前缀',
  199 + 'value' => '{:Y}{:m}{:d}{:h}{:i}{:s}{:rand}',
  200 + 'content' => '',
  201 + 'tip' => '{:Y}年,{:m}月,{:d}日,{:h}时,{:i}分{:s}秒,{:rand}6位随机数',
  202 + 'rule' => '',
  203 + 'extend' => '',
  204 + ],
  205 + [
  206 + 'type' => 'string',
  207 + 'name' => 'rprefix',
  208 + 'title' => '回款前缀',
  209 + 'value' => '{:Y}{:m}{:d}{:h}{:i}{:s}{:rand}',
  210 + 'content' => '',
  211 + 'tip' => '{:Y}年,{:m}月,{:d}日,{:h}时,{:i}分{:s}秒,{:rand}6位随机数',
  212 + 'rule' => '',
  213 + 'extend' => '',
  214 + ],
  215 + [
  216 + 'type' => 'radio',
  217 + 'name' => 'deal',
  218 + 'title' => '手动成交',
  219 + 'value' => '0',
  220 + 'content' => [
  221 + 1 => '开启',
  222 + 0 => '关闭',
  223 + ],
  224 + 'tip' => '开启可在跟进成交客户,不需要经过合同流程',
  225 + 'rule' => '',
  226 + 'extend' => '',
  227 + ],
  228 +];
  1 +<?php
  2 + return array (
  3 + 'table_name' => 'fa_facrm_achievement,fa_facrm_business,fa_facrm_business_contacts,fa_facrm_business_product,fa_facrm_cloudcall,fa_facrm_cloudcall_log,fa_facrm_clues,fa_facrm_contract,fa_facrm_contract_order,fa_facrm_contract_plan,fa_facrm_contract_product,fa_facrm_contract_receivables,fa_facrm_customer,fa_facrm_customer_contacts,fa_facrm_fields,fa_facrm_flow,fa_facrm_flow_log,fa_facrm_flow_step,fa_facrm_invoice,fa_facrm_notices,fa_facrm_operatelog,fa_facrm_product,fa_facrm_product_type,fa_facrm_product_unit,fa_facrm_qywx_contacts,fa_facrm_qywx_user,fa_facrm_record,fa_facrm_record_files,fa_facrm_scene,fa_facrm_setting,fa_facrm_tag',
  4 + 'self_path' => 'public/assets/addons/facrm
  5 +application/admin/lang/zh-cn/facrm',
  6 + 'update_data' => '--
  7 +-- 1.0.1
  8 +-- 添加名称字段user_id
  9 +--
  10 +ALTER TABLE `__PREFIX__facrm_customer` ADD COLUMN `user_id` int(11) NULL DEFAULT \'\' COMMENT \'前台用户ID\' AFTER `owner_user_id`;
  11 +
  12 +
  13 +--
  14 +-- 1.0.3
  15 +-- 更改表编码和字段编码和增加字段
  16 +--
  17 +ALTER TABLE `__PREFIX__facrm_customer` DEFAULT CHARACTER SET utf8mb4,
  18 +MODIFY COLUMN `name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT \'客户名称\' ,
  19 +MODIFY COLUMN `remark` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT \'备注\' ;
  20 +
  21 +ALTER TABLE `__PREFIX__facrm_customer_contacts` DEFAULT CHARACTER SET utf8mb4,
  22 +MODIFY COLUMN `name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT \'姓名\' ,
  23 +MODIFY COLUMN `remark` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT \'备注\' ;
  24 +
  25 +ALTER TABLE `__PREFIX__facrm_record` DEFAULT CHARACTER SET utf8mb4,
  26 +MODIFY COLUMN `content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT \'跟进内容\' ;
  27 +
  28 +ALTER TABLE `__PREFIX__facrm_setting` ADD COLUMN `status` tinyint(1) NULL DEFAULT \'1\' COMMENT \'状态\' AFTER `create_time`;
  29 +
  30 +--
  31 +-- 2.0.0
  32 +-- 更改表编码和字段编码和增加字段
  33 +--
  34 +ALTER TABLE `__PREFIX__facrm_record`
  35 +MODIFY COLUMN `types` enum(\'business\',\'clues\',\'customer\') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT \'customer\' COMMENT \'关联类型(customer跟进,business商机跟进,clues线索)\' AFTER `id`;
  36 +
  37 +
  38 +ALTER TABLE `__PREFIX__facrm_record_files`
  39 +MODIFY COLUMN `types` enum(\'business\',\'clues\',\'customer\') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT \'customer\' COMMENT \'关联类型(customer客户,business商机,clues线索)\' AFTER `id`;
  40 +
  41 +
  42 +--
  43 +-- 插入一些必须数据
  44 +--
  45 +INSERT INTO __PREFIX__facrm_flow VALUES (\'1\', \'合同审批\', \'0\', \'contract\', \'0\', \'\', \'\', \'\', \'1610787200\', \'1610787643\', \'1\', null,1);
  46 +INSERT INTO __PREFIX__facrm_flow VALUES (\'2\', \'回款审批\', \'0\', \'receivables\', \'0\', \'\', \'\', \'\', \'1610947811\', \'1618023534\', \'1\', null,2);
  47 +INSERT INTO __PREFIX__facrm_flow VALUES (\'3\', \'发票申请\', \'0\', \'invoice\', \'0\', \'\', \'\', \'\', \'1610947811\', \'1618023534\', \'1\', null,3);
  48 +INSERT INTO __PREFIX__facrm_fields VALUES (\'1\', \'customer\', \'weixin\', \'string\', \'微信\', \'value1|title1\\r\\nvalue2|title2\', \'\', \'\', \'\', \'\', \'\', \'0\', \'50\', \'0\', \'0\', \'\', \'{\\"table\\":\\"\\",\\"conditions\\":\\"\\",\\"key\\":\\"\\",\\"value\\":\\"\\"}\', \'22\', \'1614587422\', \'1614664611\', \'0\', \'0\', \'1\', \'1\', \'normal\');
  49 +INSERT INTO __PREFIX__facrm_fields VALUES (\'2\', \'customer\', \'qq\', \'number\', \'QQ\', \'value1|title1\\r\\nvalue2|title2\', \'\', \'\', \'\', \'\', \'\', \'0\', \'11\', \'0\', \'0\', \'\', \'{\\"table\\":\\"\\",\\"conditions\\":\\"\\",\\"key\\":\\"\\",\\"value\\":\\"\\"}\', \'25\', \'1614587924\', \'1614667071\', \'0\', \'1\', \'0\', \'1\', \'normal\');
  50 +
  51 +INSERT INTO __PREFIX__facrm_scene VALUES (\'1\', \'customer\', \'全部客户\', \'0\', \'1\', null, \'1\', \'\', \'0\', \'0\');
  52 +INSERT INTO __PREFIX__facrm_scene VALUES (\'2\', \'customer\', \'我的客户\', \'0\', \'1\', null, \'1\', \'\', \'0\', \'0\');
  53 +INSERT INTO __PREFIX__facrm_scene VALUES (\'3\', \'customer\', \'下属客户\', \'0\', \'1\', null, \'1\', \'\', \'0\', \'0\');
  54 +INSERT INTO __PREFIX__facrm_scene VALUES (\'4\', \'contacts\', \'全部\', \'0\', \'1\', null, \'1\', \'\', \'0\', \'0\');
  55 +INSERT INTO __PREFIX__facrm_scene VALUES (\'5\', \'contacts\', \'我的\', \'0\', \'1\', null, \'1\', \'\', \'0\', \'0\');
  56 +INSERT INTO __PREFIX__facrm_scene VALUES (\'6\', \'contacts\', \'下属\', \'0\', \'1\', null, \'1\', \'\', \'0\', \'0\');
  57 +INSERT INTO __PREFIX__facrm_scene VALUES (\'7\', \'business\', \'全部商机\', \'0\', \'1\', null, \'1\', \'\', \'0\', \'0\');
  58 +INSERT INTO __PREFIX__facrm_scene VALUES (\'8\', \'business\', \'我的商机\', \'0\', \'1\', null, \'1\', \'\', \'0\', \'0\');
  59 +INSERT INTO __PREFIX__facrm_scene VALUES (\'9\', \'business\', \'下属商机\', \'0\', \'1\', null, \'1\', \'\', \'0\', \'0\');
  60 +INSERT INTO __PREFIX__facrm_scene VALUES (\'10\', \'clues\', \'全部线索\', \'0\', \'1\', null, \'1\', \'\', \'0\', \'0\');
  61 +INSERT INTO __PREFIX__facrm_scene VALUES (\'11\', \'clues\', \'我的线索\', \'0\', \'1\', null, \'1\', \'\', \'0\', \'0\');
  62 +INSERT INTO __PREFIX__facrm_scene VALUES (\'12\', \'clues\', \'下属线索\', \'0\', \'1\', null, \'1\', \'\', \'0\', \'0\');
  63 +
  64 +--
  65 +-- 2.0.2
  66 +-- 添加来源字段
  67 +--
  68 +ALTER TABLE `__PREFIX__facrm_contract`
  69 +ADD COLUMN `source_id` int(11) NULL DEFAULT 0 COMMENT \'来源ID\' AFTER `contacts_id`;
  70 +
  71 +--
  72 +-- 2.0.5
  73 +-- 增加云呼方式
  74 +--
  75 +ALTER TABLE `__PREFIX__facrm_cloudcall`
  76 +MODIFY COLUMN `exten_type` enum(\'gateway\',\'sip\',\'local\') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT \'local\' COMMENT \'接听方式Local为“手机”\' AFTER `from_exten`;
  77 +
  78 +--
  79 +-- 2.0.6
  80 +-- 增加线上收款
  81 +--
  82 +ALTER TABLE `__PREFIX__facrm_record`
  83 +ADD COLUMN `lng` double(14,11) NULL COMMENT \'经度\' AFTER `delete_time`,
  84 +ADD COLUMN `lat` double(14,11) NULL COMMENT \'维度\' AFTER `lng`;
  85 +
  86 +ALTER TABLE `__PREFIX__facrm_contract_receivables`
  87 +ADD COLUMN `pay_status` tinyint(4) NULL DEFAULT 0 COMMENT \'在线支付状态1已付款0未付款\' AFTER `delete_time`,
  88 +ADD COLUMN `pay_type` tinyint(4) NULL DEFAULT 1 COMMENT \'收款方式1默认2在线收款3续费\' AFTER `pay_status`,
  89 +ADD COLUMN `pay_token` varchar(200) NULL COMMENT \'访问支付的token\' AFTER `pay_type`;
  90 +
  91 +
  92 +
  93 +--
  94 +-- 2.0.7
  95 +-- 发票
  96 +--
  97 +ALTER TABLE `__PREFIX__facrm_flow`
  98 +ADD COLUMN `weigh` int(11) NULL DEFAULT 0 COMMENT \'权重\' AFTER `delete_time`,
  99 +MODIFY COLUMN `types` enum(\'contract\',\'invoice\',\'receivables\') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT \'关联对象\' AFTER `config`;
  100 +
  101 +ALTER TABLE `__PREFIX__facrm_flow_log`
  102 +MODIFY COLUMN `types` enum(\'contract\',\'invoice\',\'receivables\') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT \'关联对象\' AFTER `flow_id`;
  103 +
  104 +ALTER TABLE `__PREFIX__facrm_contract`
  105 +ADD COLUMN `invoice_money` decimal(10,2) NULL DEFAULT 0.00 COMMENT \'已开票金额\' ;
  106 +
  107 +--
  108 +-- 2.0.8
  109 +-- 消费总额和次数
  110 +--
  111 +ALTER TABLE `__PREFIX__facrm_customer`
  112 +ADD COLUMN `purchase_total` decimal(18,2) NULL DEFAULT 0 COMMENT \'消费总额\' AFTER `qq`,
  113 +ADD COLUMN `purchase_times` int(10) NULL DEFAULT 0 COMMENT \'消费次数\' AFTER `purchase_total`;
  114 +
  115 +-- 2.0.10
  116 +INSERT INTO `__PREFIX__facrm_scene` (`id`, `types`, `name`, `admin_id`, `create_time`, `update_time`) VALUES (13,\'customer\', \'分享给他人\', \'0\', \'0\', \'0\');
  117 +INSERT INTO `__PREFIX__facrm_scene` (`id`,`types`, `name`, `admin_id`, `create_time`, `update_time`) VALUES (14,\'customer\', \'分享给我的\', \'0\', \'0\', \'0\');
  118 +
  119 +--2.1.0
  120 +-- 增加自定义跟进状态
  121 +ALTER TABLE `__PREFIX__facrm_customer`
  122 +ADD COLUMN `follow_status` enum(\'1\',\'2\',\'3\',\'4\',\'5\',\'0\') DEFAULT \'1\' COMMENT \'跟进状态\';
  123 +ALTER TABLE `__PREFIX__facrm_clues`
  124 +ADD COLUMN `follow_status` enum(\'1\',\'2\',\'3\',\'4\',\'5\',\'0\') DEFAULT \'1\' COMMENT \'跟进状态\';
  125 +
  126 +--2.2.5
  127 +-- 增加回款计划
  128 +ALTER TABLE `__PREFIX__facrm_contract_receivables`
  129 +ADD COLUMN `plan_id` int(11) NOT NULL DEFAULT 0 COMMENT \'关联回款计划\' AFTER `pay_token`;
  130 +
  131 +INSERT INTO `__PREFIX__facrm_fields` ( `id`,`source`,`name`,`type`,`title`,`content`,`defaultvalue`,`rule` ,`msg`,`ok`,`tip`,`decimals`,`length`,`minimum`,`maximum`,`extend`,`setting`,`weigh`,`createtime`,`updatetime`,`isorder`,`iscontribute`,`islist`,`isfilter`,`status`) VALUES (3, \'customer\', \'follow_status\', \'select\', \'跟进状态\', \'1|新客\\r\\n2|待再次沟通\\r\\n3|有意向\\r\\n4|已加微信\\r\\n5|转商机\\r\\n0|无效\', \'1\', \'\', \'\', \'\', \'\', \'0\', \'4\', \'0\', \'0\', \'\', \'{\\"table\\":\\"\\",\\"conditions\\":\\"\\",\\"key\\":\\"\\",\\"value\\":\\"\\"}\', \'6\', \'1694851354\', \'1694851354\', \'0\', \'0\', \'0\', \'0\', \'normal\');
  132 +
  133 +INSERT INTO `__PREFIX__facrm_fields` ( `id`,`source`,`name`,`type`,`title`,`content`,`defaultvalue`,`rule` ,`msg`,`ok`,`tip`,`decimals`,`length`,`minimum`,`maximum`,`extend`,`setting`,`weigh`,`createtime`,`updatetime`,`isorder`,`iscontribute`,`islist`,`isfilter`,`status`) VALUES (4, \'clues\', \'follow_status\', \'select\', \'跟进状态\', \'1|新客\\r\\n2|待再次沟通\\r\\n3|有意向\\r\\n4|已加微信\\r\\n5|转商机\\r\\n0|无效\', \'1\', \'\', \'\', \'\', \'\', \'0\', \'4\', \'0\', \'0\', \'\', \'{\\"table\\":\\"\\",\\"conditions\\":\\"\\",\\"key\\":\\"\\",\\"value\\":\\"\\"}\', \'6\', \'1694851354\', \'1694851354\', \'0\', \'0\', \'0\', \'0\', \'normal\');
  134 +',
  135 +);
  1 +<?php
  2 +/**
  3 + * 自定义表排序
  4 + */
  5 +
  6 +return array(
  7 +
  8 + array("field" => 'id', "title" => '线索ID', "sortable" => true),
  9 +
  10 + array("field" => 'name', "title" => '线索名称', "operate" => "LIKE", "align" => 'left', 'customField' => 'tags', "class" => "tabletd",
  11 + "formatter" => '(function (value, row, index) {
  12 + value=\'<a href="javascript:void(0);" data-url="facrm/clues/index/edit/ids/\' + row.id
  13 + +\'" data-area="[&quot;98%&quot;,&quot;98%&quot;]" class="btn-dialog" data-title="\'+ row.name+\'">\'+ row.name+\'</a>\';
  14 + return value +
  15 + \'<div >\' + Table.api.formatter.flag.call(this, row[\'tags\'], row, index) + \'</div>\';
  16 + })',
  17 + "cellStyle" => '(function(value, row, index, field){return {css: {"max-width":"200px"}};})'),
  18 +
  19 + array("field" => 'tags', "title" => '标签', "visible" => false, "formatter" => "Table.api.formatter.flag", "operate" => 'find_in_set'),
  20 + array("field" => 'level', "title" => '级别', "formatter" => "Table.api.formatter.status", "searchList" => 'levelList'),
  21 + array("field" => 'industry', "title" => '行业', "formatter" => "(function (v, row, index) {
  22 + if(!v) return '无';
  23 + return industryList[v];
  24 + })", "searchList" => 'industryList'),
  25 +
  26 + array("field" => 'source', "title" => '来源', "formatter" => "(function (v, row, index) {
  27 + if(!v) return '无';
  28 + return sourceList[v];
  29 + })", "searchList" => 'sourceList'),
  30 + array("field" => 'telephone', "title" => '电话', "operate" => "LIKE"),
  31 + array("field" => 'mobile', "title" => '手机', "operate" => "LIKE"),
  32 +
  33 + array("field" => 'remark', "title" => '备注', "operate" => "LIKE", "class" => "tabletd", "align" => "left", "cellStyle" => "(function(value, row, index, field){
  34 + return {css: { \"max-width\":\"250px\"}};
  35 + })"),
  36 + array("field" => 'status', "title" => '状态', "formatter" => "Table.api.formatter.status", "searchList" => 'status_obj'),
  37 +
  38 + array("field" => 'owner_user_id', "title" => '负责人', "addclass" => "selectpage", "class" => "tabletd", "cellStyle" => "(function(value, row, index, field){
  39 + return {css: { \"max-width\":\"200px\"}};
  40 + })",
  41 + 'formatter' => "(function (v, r) {
  42 + if (!r.owner_user) return '-';
  43 + return r.owner_user.nickname;})",
  44 + 'extend' => 'data-source="facrm/common/selectpage/model/admin?type=children" data-field="nickname" data-orderBy="id desc"'
  45 + ),
  46 + array("field" => 'create_user_id', "title" => '创建人', "addclass" => "selectpage", "formatter" => '(function (v, r) {
  47 + if (!r.create_user) return \'-\';
  48 + return r.create_user.nickname;
  49 + })',
  50 + "extend" => 'data-source="facrm/common/selectpage/model/admin?type=children" data-field="nickname" data-orderBy="id desc"',
  51 + ),
  52 + array("field" => 'next_time', "title" => '下次跟进', "operate" => "RANGE", "sortable" => true, "formatter" => "Table.api.formatter.datetime", "addclass" => "datetimerange", "extend" => 'autocomplete="off" data-time-picker="true"'),
  53 + array("field" => 'follow_time', "title" => '最近跟进', "operate" => "RANGE", "sortable" => true, "formatter" => "Table.api.formatter.datetime", "addclass" => "datetimerange", "extend" => 'autocomplete="off" data-time-picker="true"'),
  54 + array("field" => 'create_time', "title" => '创建时间', "operate" => "RANGE", "sortable" => true, "formatter" => "Table.api.formatter.datetime", "addclass" => "datetimerange", "extend" => 'autocomplete="off" data-time-picker="true"'),
  55 + array("field" => 'collect_time', "title" => '领取时间', "operate" => "RANGE", "sortable" => true, "formatter" => "Table.api.formatter.datetime", "addclass" => "datetimerange", "extend" => 'autocomplete="off" data-time-picker="true"'),
  56 + array("field" => 'update_time', "title" => '更新时间', "operate" => "RANGE", "sortable" => true, "formatter" => "Table.api.formatter.datetime", "addclass" => "datetimerange", "extend" => 'autocomplete="off" data-time-picker="true"'),
  57 +
  58 +
  59 +
  60 +);
  1 +<?php
  2 +/**
  3 + * 合同自定义表排序
  4 + */
  5 +
  6 +return array(
  7 + array("field" => 'id', "title" => '合同ID', "sortable" => true),
  8 + array("field" => 'number', "title" => '合同编号', "operate" => "LIKE", "align" => 'left',
  9 + "formatter" => '(function (value, row, index) {
  10 + return \'<a href="javascript:void(0);" data-url="facrm/contract/index/detail/ids/\' + row.id
  11 + + \'" data-area="[&quot;98%&quot;,&quot;98%&quot;]" class="btn-dialog" data-title="\' + value + \'">\' + value + \'</a>\';
  12 + })',),
  13 + array("field" => 'name', "title" => '合同名称', "operate" => "LIKE", "align" => 'left',
  14 + "formatter" => '(function (value, row, index) {
  15 + //判断是否逾期
  16 + var newtime = Math.round(new Date().getTime() / 1000).toString();
  17 + if (newtime > row.end_time)
  18 + value = \'<span class="label label-danger">过期</span>\' + value;
  19 + return value;
  20 + })',),
  21 + array("field" => 'customer_id', "title" => '客户名称', "align" => 'left',
  22 + "formatter" => '(function (value, row, index) {
  23 + if (!row.customer) return \'-\';
  24 + return \'<a href="javascript:void(0);" data-url="facrm/customer/index/detail/ids/\' + row.customer.id
  25 + + \'" data-area="[&quot;98%&quot;,&quot;98%&quot;]" class="btn-dialog" data-title="\' + row.customer.name + \'">\' + row.customer.name + \'(\' + row.customer_id + \')\' + \'</a>\';
  26 + })',
  27 + "addclass" => "selectpage", 'extend' => 'data-source="facrm/customer/index?filter=%7B\"scene_id\"%3A\"1\"%7D" data-field="name" data-orderBy="id desc"'),
  28 +
  29 + array("field" => 'money', "title" => '合同金额', "sortable" => true, 'operate' => 'BETWEEN'),
  30 + array("field" => 'return_money', "title" => '回款金额', "sortable" => true, 'operate' => 'BETWEEN'),
  31 + array("field" => 'order_time', "title" => '下单时间', "sortable" => true, 'operate' => 'RANGE', "formatter" => "Table.api.formatter.datetime",
  32 + 'datetimeFormat'=>"YYYY/MM/DD","extend"=>'autocomplete="off" data-time-picker="true"','addclass'=>'datetimerange'),
  33 + array("field" => 'remark', "title" => '备注', "align" => "left", 'operate' => 'LIKE'),
  34 + array("field" => 'start_time', "title" => '开始时间', "operate" => "RANGE", "sortable" => true, "formatter" => "Table.api.formatter.datetime", "addclass" => "datetimerange", "extend" => 'autocomplete="off" data-time-picker="true"'),
  35 + array("field" => 'end_time', "title" => '结束时间', "operate" => "RANGE", "sortable" => true, "formatter" => "Table.api.formatter.datetime", "addclass" => "datetimerange", "extend" => 'autocomplete="off" data-time-picker="true"'),
  36 + array("field" => 'product', "title" => '订购商品', "operate" => false, "align" => 'left',
  37 + "formatter" => '(function (value, row, index) {
  38 + if (!value||value.length == 0) {
  39 + return "商品有误";
  40 + }
  41 + text = "";
  42 + for (i = 0; i < value.length; i++) {
  43 + text += "编码:" + value[i].sku + "|数量:" + value[i].nums +"|" + value[i].name + "" + " <br>";
  44 + }
  45 + return Table.api.formatter.content(text, row, index);
  46 + })',),
  47 +
  48 +
  49 + array("field" => 'create_user_id', "title" => '创建人', "addclass" => "selectpage", "formatter" => '(function (v, r) {
  50 + if (!r.create_user) return \'-\';
  51 + return r.create_user.nickname;
  52 + })',
  53 + "extend" => 'data-source="facrm/common/selectpage/model/admin?type=all" data-field="nickname" data-orderBy="id desc"',
  54 + ),
  55 +
  56 + array("field" => 'order_admin_id', "title" => '签约人', "addclass" => "selectpage", "formatter" => '(function (v, r) {
  57 + if (!r.order_admin) return \'-\';
  58 + return r.order_admin.nickname;
  59 + })',
  60 + "extend" => 'data-source="facrm/common/selectpage/model/admin?type=all" data-field="nickname" data-orderBy="id desc"',
  61 + ),
  62 +
  63 + array("field" => 'create_time', "title" => '创建时间', "operate" => "RANGE", "sortable" => true, "formatter" => "Table.api.formatter.datetime", "addclass" => "datetimerange", "extend" => 'autocomplete="off" data-time-picker="true"'),
  64 + array("field" => 'check_status', "title" => '状态', "formatter" => "Table.api.formatter.status", "searchList" => 'check_status'),
  65 +
  66 +
  67 +
  68 +);
  1 +<?php
  2 +/**
  3 + * 客户自定义表排序
  4 + */
  5 +
  6 +return array(
  7 +
  8 + array("field" => 'id', "title" => '客户ID', "sortable" => true),
  9 +
  10 + array("field" => 'name', "title" => '客户名称', "operate" => "LIKE", "align" => 'left', 'customField' => 'tags', "class" => "tabletd",
  11 + "formatter" => '(function (value, row, index) {
  12 + value=\'<a href="javascript:void(0);" data-url="facrm/customer/record/add/ids/\' + row.id
  13 + +\'" data-area="[&quot;98%&quot;,&quot;98%&quot;]" class="btn-addtabs" data-toggle="tooltip" data-original-title="\'+ value+\'" data-title="\'+ value+\'">\'+ value+\'</a>\';
  14 +
  15 +
  16 + return value +
  17 + \'<div >\' + Table.api.formatter.flag.call(this, row[\'tags\'], row, index) + \'</div>\';
  18 + })',
  19 +
  20 + "cellStyle" => '(function(value, row, index, field){return {css: {"max-width":"200px"}};})'),
  21 +
  22 + array("field" => 'tags', "title" => '标签', "visible" => false, "formatter" => "Table.api.formatter.flag", "operate" => 'find_in_set'),
  23 + array("field" => 'telephone', "title" => '电话', "operate" => "LIKE"),
  24 + array("field" => 'mobile', "title" => '手机', "operate" => "LIKE"),
  25 +
  26 + array("field" => 'owner_user_id', "title" => '负责人', "addclass" => "selectpage", "class" => "tabletd", "cellStyle" => "(function(value, row, index, field){
  27 + return {css: { \"max-width\":\"200px\"}};
  28 + })",
  29 + 'formatter' => "(function (v, r) {
  30 + if (!r.owner_user) return '-';
  31 + return r.owner_user.nickname;})",
  32 + 'extend' => 'data-source="facrm/common/selectpage/model/admin?type=children" data-field="nickname" data-orderBy="id desc"'
  33 + ),
  34 + array("field" => 'deal_status', "title" => '成交状态', "formatter" => "Table.api.formatter.status", "searchList" => 'deal_status'),
  35 + array("field" => 'remark', "title" => '备注', "operate" => "LIKE", "class" => "tabletd", "align" => "left", "cellStyle" => "(function(value, row, index, field){
  36 + return {css: { \"max-width\":\"250px\"}};
  37 + })"),
  38 + array("field" => 'level', "title" => '客户级别', "formatter" => "Table.api.formatter.status", "searchList" => 'levelList'),
  39 + array("field" => 'industry', "title" => '行业', "formatter" => "(function (v, row, index) {
  40 + if(!v) return '无';
  41 + return industryList[v];
  42 + })", "searchList" => 'industryList'),
  43 +
  44 + array("field" => 'source', "title" => '来源', "formatter" => "Table.api.formatter.status", "searchList" => 'sourceList'),
  45 + array("field" => 'create_user_id', "title" => '创建人', "addclass" => "selectpage", "formatter" => '(function (v, r) {
  46 + if (!r.create_user) return \'-\';
  47 + return r.create_user.nickname;
  48 + })',
  49 + "extend" => 'data-source="facrm/common/selectpage/model/admin?type=children" data-field="nickname" data-orderBy="id desc"',
  50 + ),
  51 + array("field" => 'next_time', "title" => '下次跟进', "operate" => "RANGE", "sortable" => true, "formatter" => "Table.api.formatter.datetime", "addclass" => "datetimerange", "extend" => 'autocomplete="off" data-time-picker="true"'),
  52 + array("field" => 'follow_time', "title" => '最近跟进', "operate" => "RANGE", "sortable" => true, "formatter" => "Table.api.formatter.datetime", "addclass" => "datetimerange", "extend" => 'autocomplete="off" data-time-picker="true"'),
  53 + array("field" => 'create_time', "title" => '创建时间', "operate" => "RANGE", "sortable" => true, "formatter" => "Table.api.formatter.datetime", "addclass" => "datetimerange", "extend" => 'autocomplete="off" data-time-picker="true"'),
  54 + array("field" => 'collect_time', "title" => '领取时间', "operate" => "RANGE", "sortable" => true, "formatter" => "Table.api.formatter.datetime", "addclass" => "datetimerange", "extend" => 'autocomplete="off" data-time-picker="true"'),
  55 + array("field" => 'update_time', "title" => '更新时间', "operate" => "RANGE", "sortable" => true, "formatter" => "Table.api.formatter.datetime", "addclass" => "datetimerange", "extend" => 'autocomplete="off" data-time-picker="true"'),
  56 +
  57 +
  58 +
  59 +);
此 diff 太大无法显示。
  1 +<?php
  2 +
  3 +namespace addons\facrm\controller;
  4 +
  5 +use EasyWeChat\Factory;
  6 +use think\Config;
  7 +use think\Db;
  8 +use think\Queue;
  9 +
  10 +/**
  11 + * 定时任务
  12 + * @internal
  13 + */
  14 +class Autotask extends \think\addons\Controller
  15 +{
  16 + protected $noNeedLogin = ["*"];
  17 + protected $layout = '';
  18 +
  19 + public function _initialize()
  20 + {
  21 + set_time_limit(0);
  22 + parent::_initialize();
  23 +
  24 + if (!$this->request->isCli()) {
  25 + $this->error('只允许在终端进行操作!');
  26 + }
  27 + }
  28 +
  29 + /**
  30 + * 定时任务逻辑
  31 + */
  32 + public function index()
  33 + {
  34 + $this->flowcustomer();
  35 + $this->flowbusiness();
  36 + $this->expirecontract();
  37 + $this->expirecustomer();
  38 + $this->flowclues();
  39 + }
  40 +
  41 + /**
  42 + * 待跟进客户提醒
  43 + */
  44 + public function flowcustomer()
  45 + {
  46 +
  47 + //当天开始时间
  48 + $start_time = strtotime(date("Y-m-d", time()));
  49 + //当天结束之间
  50 + $end_time = $start_time + 60 * 60 * 24;
  51 + $customerModel = model('\app\admin\model\facrm\Customer');
  52 + //需要联系客户
  53 + $communicate = $customerModel->where('next_time', 'between', [1, $end_time])
  54 + ->field('COUNT(*) AS count,owner_user_id ')
  55 + ->where('owner_user_id', "<>", '0')
  56 + ->group('owner_user_id')
  57 + ->select();
  58 +
  59 + foreach ($communicate as $row) {
  60 + if ($row->count <= 0) continue;
  61 + //通知队列
  62 + Queue::push("addons\\facrm\\library\\notice\queue\\CustomerJob", [
  63 + 'key' => 'notice_flow_customer',//待跟进通知模板
  64 + 'admin_ids' => $row->owner_user_id,
  65 + 'count' => $row->count,
  66 + ]);
  67 + }
  68 + echo "done";
  69 + return;
  70 + }
  71 +
  72 + /**
  73 + * 待跟进线索提醒
  74 + */
  75 + public function flowclues()
  76 + {
  77 +
  78 + //当天开始时间
  79 + $start_time = strtotime(date("Y-m-d", time()));
  80 + //当天结束之间
  81 + $end_time = $start_time + 60 * 60 * 24;
  82 + $cluesModel = model('\app\admin\model\facrm\Clues');
  83 + //需要联系线索
  84 + $communicate = $cluesModel->where('next_time', 'between', [1, $end_time])
  85 + ->field('COUNT(*) AS count,owner_user_id ')
  86 + ->where('owner_user_id', "<>", '0')
  87 + ->group('owner_user_id')
  88 + ->select();
  89 +
  90 + foreach ($communicate as $row) {
  91 + if ($row->count <= 0) continue;
  92 + //通知队列
  93 + Queue::push("addons\\facrm\\library\\notice\queue\\CluesJob", [
  94 + 'key' => 'notice_flow_clues',//待跟进通知模板
  95 + 'admin_ids' => $row->owner_user_id,
  96 + 'count' => $row->count,
  97 + ]);
  98 + }
  99 + echo "done";
  100 + return;
  101 + }
  102 +
  103 + /**
  104 + * 待跟进商机提醒
  105 + */
  106 + public function flowbusiness()
  107 + {
  108 + //当天开始时间
  109 + $start_time = strtotime(date("Y-m-d", time()));
  110 + //当天结束之间
  111 + $end_time = $start_time + 60 * 60 * 24;
  112 + $thisModel = model('\app\admin\model\facrm\Business');
  113 + //需要联系
  114 + $communicate = $thisModel->where('next_time', 'between', [1, $end_time])
  115 + ->where('is_end', 0)
  116 + ->field('COUNT(*) AS count,owner_user_id ')
  117 + ->where('owner_user_id', "<>", '0')
  118 + ->group('owner_user_id')
  119 + ->select();
  120 +
  121 + foreach ($communicate as $row) {
  122 + if ($row->count <= 0) continue;
  123 + //通知队列
  124 + Queue::push("addons\\facrm\\library\\notice\queue\\BusinessrJob", [
  125 + 'key' => 'notice_flow_business',//待跟进通知模板
  126 + 'admin_ids' => $row->owner_user_id,
  127 + 'count' => $row->count,
  128 + ]);
  129 + }
  130 + echo "done";
  131 + return;
  132 + }
  133 +
  134 + /**
  135 + * 将过期合同(提前三十天)
  136 + */
  137 + public function expirecontract()
  138 + {
  139 +
  140 + //当天开始时间
  141 + $start_time = strtotime(date("Y-m-d", time()));
  142 + //当天结束之间
  143 + $end_time = $start_time + 60 * 60 * 24;
  144 + $thisModel = model('\app\admin\model\facrm\Contract');
  145 + //需要联系
  146 + $communicate = $thisModel->where('end_time', 'between', [1, $end_time + (30 * 86400)])
  147 + ->where('expire_handle', 0)
  148 + ->field('COUNT(*) AS count,owner_user_id ')
  149 + ->where('owner_user_id', "<>", '0')
  150 + ->group('owner_user_id')
  151 + ->select();
  152 +
  153 + foreach ($communicate as $row) {
  154 + if ($row->count <= 0) continue;
  155 + //通知队列
  156 + Queue::push("addons\\facrm\\library\\notice\queue\\ContractJob", [
  157 + 'key' => 'notice_expire_contract',//待跟进通知模板
  158 + 'admin_ids' => $row->owner_user_id,
  159 + 'count' => $row->count,
  160 + ]);
  161 + }
  162 + echo "done";
  163 + return;
  164 +
  165 + }
  166 +
  167 +
  168 + /**
  169 + * 将要过期客户提醒
  170 + */
  171 + public function expirecustomer()
  172 + {
  173 +
  174 + $config = get_addon_config('facrm');
  175 + //判断是否开启过期的功能
  176 + if ($config['lose_day1'] <= 0 && ($config['lose_day2'] <= 0)) {
  177 + echo "done none";
  178 + return;
  179 + }
  180 +
  181 + $thisModel = model('\app\admin\model\facrm\Customer');
  182 +
  183 + $lists = $thisModel->getLoseWhere($config, 1)
  184 + ->field('COUNT(*) AS count,owner_user_id ')
  185 + ->where('owner_user_id', "<>", '0')
  186 + ->group('owner_user_id')
  187 + ->select();
  188 +
  189 + foreach ($lists as $row) {
  190 + if ($row->count <= 0) continue;
  191 + //通知队列
  192 + Queue::push("addons\\facrm\\library\\notice\queue\\CustomerJob", [
  193 + 'key' => 'notice_expire_ccustomer',//客户将过期通知模板
  194 + 'admin_ids' => $row->owner_user_id,
  195 + 'count' => $row->count,
  196 + ]);
  197 + }
  198 + echo "done";
  199 + return;
  200 + }
  201 +
  202 +
  203 + /**
  204 + * 云呼记录同步云呼建议1个小时执行一次【废弃已改用事件通知】
  205 + * @throws Exception
  206 + * @throws \think\db\exception\DataNotFoundException
  207 + * @throws \think\db\exception\ModelNotFoundException
  208 + * @throws \think\exception\DbException
  209 + */
  210 + public function calllog()
  211 + {
  212 + $this->key = "cloudcall";
  213 + //获取云呼配置
  214 + $all_types = \addons\facrm\library\cloudcall\Call::getProviders();
  215 + $keys = "";
  216 + foreach ($all_types as $v) {
  217 + $keys .= $keys ? ',' . $this->key . $v : $this->key . $v;
  218 + }
  219 + $settingModel = new \app\admin\model\facrm\Setting();
  220 + $setting = $settingModel->where('key', 'in', $keys)->where('status', 1)->find();//只找一条云呼通道
  221 +
  222 + if (!$setting) {
  223 + $this->error(__("云呼通道没有配置,请先配置"));
  224 + }
  225 + //获取坐席
  226 +
  227 + $setting = $setting->toArray();
  228 + $setting['key'] = $setting['describe'];
  229 + $setting = array_merge($setting, $setting['values']);
  230 + $call = \addons\facrm\library\cloudcall\Call::instance($setting);
  231 +
  232 +
  233 + $calldata['beginTime'] = datetime(time() - (86400 * 1), 'Y-m-d H:i:s');//开始时间
  234 + $calldata['endTime'] = datetime(time(), 'Y-m-d H:i:s');//结束时间
  235 +
  236 +
  237 + $result = $call->getCallRecord($calldata);
  238 + if (!$result) {
  239 + $this->error($call->getError());
  240 + }
  241 + $result = json_decode($result, true);
  242 + if (isset($result['success']) && $result['success'] && $result['data']) {
  243 + $cloudcallLog = new \app\admin\model\facrm\CloudcallLog();
  244 + foreach ($result['data'] as $r) {
  245 + if (!$r['ACTION_ID']) continue;
  246 +
  247 + $log = $cloudcallLog->where('action_id', $r['ACTION_ID'])->where('status', 0)->find();
  248 + if (!$log) continue;
  249 +
  250 + $log->call_no = $r['CALL_NO'];
  251 + $log->status = $r['STATUS'] == 'dealing' ? 1 : -1;
  252 + $log->record_file = $r['FILE_SERVER'] . '/' . $r['RECORD_FILE_NAME'];
  253 + $log->call_time_length = $r['CALL_TIME_LENGTH'];
  254 +
  255 + $log->save();
  256 + }
  257 +
  258 + }
  259 + }
  260 +
  261 + /**
  262 + * 同步微信员工、客户
  263 + * @throws \think\db\exception\DataNotFoundException
  264 + * @throws \think\db\exception\ModelNotFoundException
  265 + * @throws \think\exception\DbException
  266 + * @throws \think\exception\PDOException
  267 + */
  268 + public function synwx()
  269 + {
  270 + set_time_limit(0);
  271 + $key = "work_weixin_set";
  272 + $settingModel = new \app\admin\model\facrm\Setting();
  273 + $row = $settingModel->where('key', $key)->cache(1800)->find();
  274 + if (!$row) {
  275 + echo "企业微信未配置";
  276 + return;
  277 + }
  278 + $values = json_decode($row['values'], true);//获取器不知道为什么失效了
  279 + if (!$values) {
  280 + echo "企业微信未配置1";
  281 + return;
  282 + }
  283 +
  284 +
  285 + $config = [
  286 + 'corp_id' => $values['corp_id'],
  287 + 'secret' => $values['agent_secret'],
  288 + 'agent_id' => $values['agent_id'],
  289 + //'agent_secret' => $values['agent_secret'],
  290 + ];
  291 + try {
  292 + $app = Factory::work($config);
  293 + $result = $app->user->getDetailedDepartmentUsers(1, true);
  294 + } catch (\Exception $e) {
  295 + $this->error($e->getMessage());
  296 +
  297 + }
  298 + if (!$result || $result['errcode'] != '0') {
  299 + $errmsg = isset($result['errmsg']) ? $result['errmsg'] : 'null';
  300 + echo "获取失败:" . $errmsg;
  301 + return;
  302 + }
  303 + $userlist = $result['userlist'];
  304 + $result = 0;
  305 + foreach ($userlist as $user) {
  306 + //判断系统是否存在
  307 + $qywxUser = \app\admin\model\facrm\qywx\User::getUser($user['userid'], $values, $user);
  308 + if ($qywxUser) $result++;
  309 + }
  310 + echo "同步更新企业微信员工{$result}条";
  311 + /*-----------同步员工end----------------*/
  312 +
  313 + $this->synwxcustomer($values);
  314 + return;
  315 +
  316 +
  317 + }
  318 +
  319 +
  320 + protected function synwxcustomer($values,$page=1,$next_cursor="",$is_action=true){
  321 + $c_config = [
  322 + 'corp_id' => $values['corp_id'],
  323 + 'secret' => $values['customer_secret'], // 客户的 secret
  324 + ];
  325 + $appc = Factory::work($c_config);
  326 + $qywxUserModel = new \app\admin\model\facrm\qywx\User();
  327 + $userList = $qywxUserModel->page($page,100)->order('id asc')->column('admin_id','userid');
  328 + if (!$userList){
  329 + echo "同步客户完成";
  330 + return;
  331 + }
  332 +
  333 + $contactsModel = new \app\admin\model\facrm\qywx\Contacts();
  334 +
  335 + $externalcontact = new \addons\facrm\library\extend\easywechat\Externalcontact($appc);
  336 + try {
  337 + //批量查询客户详情
  338 + $externalList = $externalcontact->batch(array_keys($userList),$next_cursor,100);
  339 + } catch (\Exception $e) {
  340 + echo $e->getMessage();
  341 + }
  342 + if (!$externalList || $externalList['errcode'] != '0' ){
  343 + echo $externalList['errmsg'];
  344 +
  345 + }
  346 + if ($externalList['external_contact_list']&&count($externalList['external_contact_list'])>0){
  347 + $syn_number=count($externalList['external_contact_list']);
  348 + foreach ($externalList['external_contact_list'] as $row) {
  349 + $follow_user = $row['follow_info'];
  350 + $admin_id=isset($userList[$follow_user['userid']])?$userList[$follow_user['userid']]:0;
  351 +
  352 + $contactsModel->getContacts($row, $values, ['admin_id' => $admin_id]);
  353 + }
  354 + if (isset($externalList['next_cursor'])&&$externalList['next_cursor']){
  355 + $syn_number+=$this->synwxcustomer($values,$page,$externalList['next_cursor'],false);
  356 + }
  357 + }
  358 + if (!$is_action){
  359 + return $syn_number;
  360 + }
  361 + echo "本次同步更新{$syn_number}条客户数据";
  362 + return $this->synwxcustomer($values,$page+1);
  363 + }
  364 +}
  1 +<?php
  2 +// +----------------------------------------------------------------------
  3 +// | ThinkPHP [ WE CAN DO IT JUST THINK ]
  4 +// +----------------------------------------------------------------------
  5 +// | Copyright (c) 2006-2015 http://thinkphp.cn All rights reserved.
  6 +// +----------------------------------------------------------------------
  7 +// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  8 +// +----------------------------------------------------------------------
  9 +// | Author: yunwuxin <448901948@qq.com>
  10 +// +----------------------------------------------------------------------
  11 +
  12 +namespace addons\facrm\controller;
  13 +
  14 +use addons\facrm\library\BackendApi;
  15 +use think\Config;
  16 +use think\captcha\Captcha as CaptchaLib;
  17 +
  18 +/**
  19 + * 图片验证码
  20 + * Class Captcha
  21 + * @package addons\facrm\controller
  22 + */
  23 +class Captcha extends BackendApi
  24 +{
  25 + protected $noNeedLogin = ['index'];
  26 + public function index()
  27 + {
  28 + $id=request()->param('id');
  29 + $sid=request()->param('sid');
  30 + if (!$sid){
  31 + session_start();
  32 + session_id();
  33 + $this->success('',session_id());
  34 + }else{
  35 + session_id($sid);
  36 + session_start();
  37 + }
  38 +
  39 + $captcha = new CaptchaLib((array)Config::get('captcha'));
  40 + return $captcha->entry($id);
  41 + }
  42 +}
  1 +<?php
  2 +
  3 +
  4 +namespace addons\facrm\controller;
  5 +
  6 +
  7 +
  8 +use fast\Date;
  9 +use think\addons\Controller;
  10 +
  11 +/**
  12 + * 云呼回调接口
  13 + * @icon fa fa-circle-o
  14 + */
  15 +class Cloudcall extends Controller
  16 +{
  17 + protected $cacheCallName = "cache_call_engine_name";
  18 + protected $calltypes = [];
  19 +
  20 + public function _initialize()
  21 + {
  22 + parent::_initialize();
  23 + $this->request->filter(['strip_tags']);
  24 +
  25 + }
  26 +
  27 + /**
  28 + * 通话记录回调
  29 + * @ApiParams(name="engine", type="string", required=true, description="通道")
  30 + * @ApiBody ("域名/addons/facrm/cloudcall/back?engine=通道(如Tycc100)")
  31 + * @ApidBody
  32 + */
  33 + public function back($engine=null)
  34 + {
  35 + $engine=!$engine?$this->request->request('engine'):$engine;
  36 + $engine=!$engine?$this->request->route('engine'):"";
  37 + if (!$engine){
  38 + $this->error("通道不存在");
  39 + }
  40 + $this->setting = cache($this->cacheCallName.$engine);
  41 +
  42 + if (!$this->setting) {
  43 + $this->key = "cloudcall";
  44 + $settingModel = new \app\admin\model\facrm\Setting();
  45 + $this->setting=$settingModel->where('key', "cloudcall".$engine)->find();
  46 + if (!$this->setting){
  47 + $this->error("通道不存在");
  48 + }
  49 + $this->setting=$this->setting->toArray();
  50 + cache($this->cacheCallName.$engine, $this->setting, 86400);//缓存一天
  51 + }
  52 +
  53 + $this->setting['key'] = $this->setting['describe'];
  54 + $this->setting = array_merge($this->setting, $this->setting['values']);
  55 + $call= \addons\facrm\library\cloudcall\Call::instance($this->setting);
  56 + $result=$call->back();
  57 +
  58 + }
  59 +
  60 +
  61 +}
  1 +<?php
  2 +
  3 +namespace addons\facrm\controller;
  4 +
  5 +use addons\facrm\library\BackendApi;
  6 +use addons\facrm\model\Admin as AdminModel;
  7 +use app\admin\model\AdminLog;
  8 +use think\Config;
  9 +use think\Hook;
  10 +use think\Validate;
  11 +
  12 +/**
  13 + * 登录操作
  14 + * @internal
  15 + */
  16 +class Index extends BackendApi
  17 +{
  18 +
  19 + protected $noNeedLogin = ['login', 'wxlogin','bind','mplogin'];
  20 + protected $noNeedRight = ['logout','unbind','thirdlist'];
  21 + protected $platforms =['admin_min','admin_mp'] ;//admin_min微信小程序登录标识
  22 +
  23 + public function _initialize()
  24 + {
  25 + parent::_initialize();
  26 + //移除HTML标签
  27 + $this->request->filter('trim,strip_tags,htmlspecialchars');
  28 + }
  29 + /**
  30 + * 登录[帐号和密码]
  31 + * @ApiMethod (post)
  32 + * @ApiParams(name="username", type="string", required=true, description="帐号")
  33 + * @ApiParams(name="password", type="string", required=true, description="密码")
  34 + * @ApiParams(name="keeplogin", type="string", required=false, description="保持登录,暂时未做")
  35 + */
  36 + public function login()
  37 + {
  38 + $username = $this->request->post('username');
  39 + $password = $this->request->post('password');
  40 + $keeplogin = $this->request->post('keeplogin');
  41 + $sid=$this->request->post('sid');
  42 + if ($sid){
  43 + session_id($sid);
  44 + session_start();
  45 + }
  46 +
  47 + $rule = [
  48 + 'username' => 'require|length:3,30',
  49 + 'password' => 'require|length:3,30',
  50 + ];
  51 + $data = [
  52 + 'username' => $username,
  53 + 'password' => $password,
  54 +
  55 + ];
  56 + if (Config::get('fastadmin.login_captcha')) {
  57 + $rule['captcha'] = 'require|captcha';
  58 + $data['captcha'] = $this->request->post('captcha');
  59 + }
  60 + $validate = new Validate($rule, [], ['username' => __('Username'), 'password' => __('Password'), 'captcha' => __('Captcha')]);
  61 + $result = $validate->check($data);
  62 + if (!$result) {
  63 +
  64 + $this->error($validate->getError());
  65 + }
  66 +
  67 + AdminLog::setTitle(__('移动端帐号登录'));
  68 + $result = $this->auth->login($username, $password, $keeplogin ? 86400 : 0);
  69 + if ($result === true) {
  70 + $admin = $this->auth->getAdmin();
  71 + if ($admin) {
  72 + Hook::listen("admin_login_after", $this->request);
  73 + $this->success(__("登录成功!"), [
  74 + 'token' => $admin->token,
  75 + 'id' => $admin->id,
  76 + 'username' => $admin->username,
  77 + 'nickname' => $admin->nickname,
  78 + 'avatar' => cdnurl($admin->avatar, true),
  79 + ]);
  80 + }
  81 +
  82 +
  83 + }
  84 + $msg = $this->auth->getError();
  85 + $msg = $msg ? $msg : __('Username or password is incorrect');
  86 + $this->error($msg);
  87 +
  88 +
  89 + }
  90 +
  91 + /**
  92 + * 小程序微信登录
  93 + * @ApiMethod (post)
  94 + * @ApiParams(name="code", type="string", required=true, description="code")
  95 + * @ApiParams(name="encrypted_data", type="string", required=true, description="encrypted_data")
  96 + * @ApiParams(name="iv", type="string", required=true, description="iv")
  97 + */
  98 + public function wxlogin()
  99 + {
  100 +
  101 + $platform='admin_min';
  102 + $model = new AdminModel();
  103 + $post = $this->request->post();
  104 + $third = get_addon_info('third');
  105 + if (!$third || $third['state']!=1) {
  106 + $this->error(__("请先安装第三方登录插件"));
  107 + }
  108 + $data = $model->minLogin($post);
  109 + if (!$data) {
  110 + $this->error($model->getError());
  111 + }
  112 +
  113 + $data['openid'] = $data['openId'];
  114 + $data['unionId'] =isset($data['unionId'])? $data['unionId']:'';
  115 + $data['access_token'] = $data['refresh_token'] = $post['code'];
  116 + $data['expires_in'] = 0;
  117 + $data['userinfo']['nickname'] = $data['nickName'];
  118 + $data['userinfo']['avatar'] = $data['avatarUrl'];
  119 + $third = $model->connects($platform, $data);
  120 +
  121 + AdminLog::setTitle(__('小程序登录'));
  122 + if ($third) {
  123 + if (isset($third->user_id)&&$third->user_id) {
  124 + $admin = $this->auth->direct($third->user_id);
  125 + if ($admin) {
  126 + Hook::listen("admin_login_after", $this->request);
  127 + $this->success(__("登录成功!"), [
  128 + 'token' => $admin->token,
  129 + 'id' => $admin->id,
  130 + 'username' => $admin->username,
  131 + 'nickname' => $admin->nickname,
  132 + 'avatar' => cdnurl($admin->avatar, true),
  133 + ]);
  134 + }
  135 + $this->error(__($this->auth->getError()));
  136 + } else {
  137 + //绑定帐号
  138 + $this->error(__("跳转到绑定帐号"), ['refresh_token' => $third->refresh_token]);
  139 + }
  140 + }
  141 + $this->error(__("登录失败,请重试"));
  142 + }
  143 +
  144 + /**
  145 + * 微信公众号登录
  146 + * @ApiMethod (get)
  147 + * @ApiParams(name="code", type="string", required=true, description="code")
  148 + */
  149 + public function mplogin(){
  150 + $platform='admin_mp';
  151 + $model = new AdminModel();
  152 + $get = $this->request->get();
  153 + $third = get_addon_info('third');
  154 + if (!$third || $third['state']!=1) {
  155 + $this->error(__("请先安装第三方登录插件"));
  156 + }
  157 + $data = $model->mpLogin($get);
  158 + if (!$data) {
  159 + $this->error($model->getError());
  160 + }
  161 + if (!isset($data['original']['openid'])){
  162 + $this->error(__("获取微信登录信息失败"));
  163 + }
  164 +
  165 + $data_param['openid'] = $data['original']['openid'];
  166 + $data_param['unionId'] =isset($data['original']['unionId'])? $data['original']['unionId']:'';
  167 + $data_param['expires_in'] =3600;
  168 + $data_param['userinfo']['nickname'] = $data['nickname'];
  169 + $data_param['userinfo']['avatar'] = $data['avatar'];
  170 + $data_param['access_token'] = $data['access_token'];
  171 + $data_param['refresh_token'] = $data['refresh_token'];
  172 +
  173 + $third = $model->connects($platform, $data_param);
  174 +
  175 + AdminLog::setTitle(__('公众号登录'));
  176 + if ($third) {
  177 + if (isset($third->user_id)&&$third->user_id) {
  178 + $admin = $this->auth->direct($third->user_id);
  179 + if ($admin) {
  180 + Hook::listen("admin_login_after", $this->request);
  181 + $this->success(__("登录成功!"), [
  182 + 'token' => $admin->token,
  183 + 'id' => $admin->id,
  184 + 'username' => $admin->username,
  185 + 'nickname' => $admin->nickname,
  186 + 'avatar' => cdnurl($admin->avatar, true),
  187 + ]);
  188 + }
  189 + $this->error(__($this->auth->getError()));
  190 + } else {
  191 + //绑定帐号
  192 + $this->error(__("跳转到绑定帐号"), ['refresh_token' => $third->refresh_token]);
  193 + }
  194 + }
  195 + $this->error(__("登录失败,请重试"));
  196 + }
  197 +
  198 +
  199 + /**
  200 + * 绑定原有帐号
  201 + * @ApiMethod (POST)
  202 + * @ApiParams(name="username", type="string", required=true, description="帐号")
  203 + * @ApiParams(name="password", type="string", required=true, description="密码")
  204 + * @ApiParams(name="keeplogin", type="string", required=false, description="保持登录,暂时未做")
  205 + * @ApiParams(name="platform", type="string", required=false, description="绑定平台admin_min:小程序 admin_mp:公众号")
  206 + * @ApiParams (name="refresh_token", type="string", required=true, sample="",description="绑定凭证")
  207 + * @ApiReturnParams (name="token", type="string", required=false, sample="0",description="登录凭证")
  208 + * admin_mp
  209 + * @return array
  210 + */
  211 + public function bind()
  212 + {
  213 + $platform = $this->request->post('platform','admin_min');
  214 + $refresh_token = $this->request->post('refresh_token');
  215 + $username = $this->request->post('username');
  216 + $password = $this->request->post('password');
  217 + $keeplogin = $this->request->post('keeplogin');
  218 + $sid=$this->request->post('sid');
  219 + if ($sid){
  220 + session_id($sid);
  221 + session_start();
  222 + }
  223 + if (!$refresh_token) {
  224 + $this->error("获取登录信息错误");
  225 + }
  226 + $rule = [
  227 + 'username' => 'require|length:3,30',
  228 + 'password' => 'require|length:3,30',
  229 + ];
  230 + $data = [
  231 + 'username' => $username,
  232 + 'password' => $password,
  233 +
  234 + ];
  235 + if (Config::get('fastadmin.login_captcha')) {
  236 + $rule['captcha'] = 'require|captcha';
  237 + $data['captcha'] = $this->request->post('captcha');
  238 + }
  239 + $validate = new Validate($rule, [], ['username' => __('用户名'), 'password' => __('密码'), 'captcha' => __('验证码')]);
  240 + $result = $validate->check($data);
  241 + if (!$result) {
  242 + $this->error($validate->getError());
  243 + }
  244 +
  245 + $third = \addons\third\model\Third::where('refresh_token', $refresh_token)->where('platform', $platform)->find();
  246 + if (!$third) {
  247 + $this->error(__('绑定的数据不存在'));
  248 + }
  249 + if ($third->user_id > 0) {
  250 + $this->error(__('已绑定过'));
  251 + }
  252 + if ($third['updatetime'] < (time() - 1800)) {
  253 + $third->delete();
  254 + $this->error(__('请求已经过期,请重试!'));
  255 + }
  256 +
  257 + AdminLog::setTitle(__('小程序绑定登录'));
  258 + $result = $this->auth->login($username, $password, $keeplogin ? 86400 : 0);
  259 + if ($result === true) {
  260 + $admin = $this->auth->getAdmin();
  261 + if ($admin) {
  262 + Hook::listen("admin_login_after", $this->request);
  263 +
  264 + $third['user_id'] = $admin->id;
  265 + $third->save();
  266 + $this->success(__("登录成功!"), [
  267 + 'token' => $admin->token,
  268 + 'id' => $admin->id,
  269 + 'username' => $admin->username,
  270 + 'nickname' => $admin->nickname,
  271 + 'avatar' => cdnurl($admin->avatar, true),
  272 + ]);
  273 + }
  274 + }
  275 + $msg = $this->auth->getError();
  276 + $msg = $msg ? $msg : __('Username or password is incorrect');
  277 + $this->error($msg);
  278 +
  279 + }
  280 +
  281 + /**
  282 + * 解绑
  283 + *@ApiParams(name="platform", type="string", required=true, description="平台:admin_min:小程序 admin_mp:公众号")
  284 + */
  285 + public function unbind(){
  286 + $platform = $this->request->post('platform','admin_min');
  287 + if (!in_array($platform,$this->platforms)){
  288 + $this->error(__('平台不存在'));
  289 + }
  290 + $third = \addons\third\model\Third::where('user_id', $this->auth->id)->where('platform', $platform)->find();
  291 + if (!$third) {
  292 + $this->error(__('绑定的数据不存在'));
  293 + }
  294 + $third->delete();
  295 + $this->success(__("解绑成功!"));
  296 + }
  297 +
  298 + /**
  299 + * 获取第三方登录绑定列表
  300 + */
  301 + public function thirdlist(){
  302 + $third = get_addon_info('third');
  303 + if (!$third || $third['state']!=1) {
  304 + $this->error(__("请先安装第三方登录插件"));
  305 + }
  306 + $thirdlist = \addons\third\model\Third::where('user_id', $this->auth->id)
  307 + ->field('id,platform,openname,logintime')
  308 + ->where('platform', 'in',$this->platforms)->select();
  309 + $this->success('',$thirdlist);
  310 +
  311 + }
  312 +
  313 + /**
  314 + * 退出登录
  315 + */
  316 + public function logout()
  317 + {
  318 + $this->auth->logout();
  319 + $this->success(__("退出成功"));
  320 + }
  321 +
  322 +}
  1 +<?php
  2 +
  3 +
  4 +namespace addons\facrm\controller;
  5 +
  6 +
  7 +use addons\third\model\Third;
  8 +
  9 +use fast\Date;
  10 +use think\addons\Controller;
  11 +use think\Exception;
  12 +use think\Response;
  13 +
  14 +
  15 +/**
  16 + * 订单支付
  17 + * @icon fa fa-circle-o
  18 + */
  19 +class Order extends Controller
  20 +{
  21 +
  22 + protected $layout = 'default';
  23 + protected $pay_config = [];
  24 + protected $key = "payonline";
  25 +
  26 + public function _initialize()
  27 + {
  28 + parent::_initialize();
  29 + $epayinfo = get_addon_info('epay');
  30 + if (!$epayinfo || !$epayinfo['state']){
  31 + $this->error(__("微信支付宝插件未安装或未启用"));
  32 + }
  33 + $this->view->assign("epayinfo", $epayinfo);
  34 +
  35 + $this->request->filter(['strip_tags']);
  36 + $settingModel = new \app\admin\model\facrm\Setting();
  37 + $this->pay_config =\addons\facrm\library\Order::getPayConfig();
  38 + if (!$this->pay_config) {
  39 + $this->error(__("未配置收款"));
  40 + }
  41 + }
  42 +
  43 +
  44 + /**
  45 + * 支付订单[收款]
  46 + */
  47 + public function pay()
  48 + {
  49 +
  50 +
  51 + if (!$this->pay_config['values']['online_pay']) {
  52 + $this->error(__("未配置收款"));
  53 + }
  54 +
  55 + //获取收款单信息
  56 + $pay_token = $this->request->request('pay_token');//访问凭证
  57 + if (!$pay_token) {
  58 + $this->error(__("访问有误"));
  59 + }
  60 + $receivablesModel = new \app\admin\model\facrm\contract\Receivables();
  61 + $payInfo = $receivablesModel->where('pay_token', $pay_token)->find();
  62 + $tempvars=$payInfo->toArray();
  63 +
  64 + $check_data=\addons\facrm\library\Order::checkPay($payInfo, 'pay',$this->pay_config);
  65 + if ($check_data['code']!=1){
  66 + $this->error(__($check_data['msg']));
  67 + }
  68 +
  69 +
  70 + $agreement = __($this->pay_config['values']['agreement'],$tempvars);
  71 + $this->view->assign("row", $payInfo);
  72 + $this->view->assign("agreement", $agreement);
  73 + $this->view->assign("title", __("支付订单"));
  74 + return $this->view->fetch();
  75 +
  76 +
  77 + }
  78 +
  79 + /**
  80 + * 合同续费
  81 + */
  82 + public function renew()
  83 + {
  84 + //获取合同信息
  85 + $pay_token = $this->request->request('pay_token');
  86 + if (!$pay_token) {
  87 + $this->error(__("访问有误"));
  88 + }
  89 +
  90 + //判断是否开启续费功能
  91 + if ($this->pay_config['values']['renew_pay'] != 1) {
  92 + $this->error(__("未开启续费功能"));
  93 + }
  94 +
  95 +
  96 + $contractModel = new \app\admin\model\facrm\Contract();
  97 + $contractInfo = $contractModel->where('renewtoken', $pay_token)->find();
  98 + $check_data=\addons\facrm\library\Order::checkPay($contractInfo, 'renew',$this->pay_config);
  99 + if ($check_data['code']!=1){
  100 + $this->error(__($check_data['msg']));
  101 + }
  102 +
  103 + //判断合同是否设定了续费单价,
  104 + if ($contractInfo['renewmoeny']<=0){
  105 + $contractInfo['renewmoeny']=bcdiv(($contractInfo['money']*$this->pay_config['values']['renew_percentage']),100,2);
  106 + }
  107 + $pay_config=$this->pay_config['values'];
  108 + $pay_config['r_agreement'] = __($pay_config['r_agreement'], $contractInfo->toArray());
  109 +
  110 +
  111 + $this->view->assign("pay_config", $pay_config);
  112 + $this->view->assign("row", $contractInfo);
  113 + $this->view->assign("title", __("续费"));
  114 + return $this->view->fetch();
  115 +
  116 + }
  117 +
  118 +
  119 + /**
  120 + * 提交支付订单
  121 + * @return \addons\epay\library\Collection|\addons\epay\library\RedirectResponse|\addons\epay\library\Response
  122 + * @throws \think\db\exception\DataNotFoundException
  123 + * @throws \think\db\exception\ModelNotFoundException
  124 + * @throws \think\exception\DbException
  125 + */
  126 + public function submit()
  127 + {
  128 + $pay_token = request()->request('pay_token');
  129 + if (!$pay_token) $this->error("付款单不存在");
  130 +
  131 + $info = get_addon_info('epay');
  132 + if (!$info || !$info['state']) {
  133 + $this->error('请在后台插件管理安装微信支付宝整合插件后重试');
  134 + }
  135 + $paytype = $this->request->request('paytype', 'wechat');
  136 + $ordertype = $this->request->request('ordertype', 'pay');
  137 + $method = $this->request->request('method');
  138 + $appid = $this->request->request('appid');//APP的应用ID
  139 + $returnurl = $this->request->request('returnurl', '', 'trim');
  140 + $number = $this->request->request('number', '1', 'intval');//下单数量,只有续费才有效果
  141 +
  142 +
  143 + //公众号和小程序
  144 + $openid = '';
  145 + if (in_array($method, ['miniapp', 'mp'])) {
  146 + $third = Third::where('platform', 'wechat')->where('apptype', $method)->where('user_id', $this->auth->id)->find();
  147 + if (!$third) {
  148 + $this->error("未找到登录用户信息", 'bind');
  149 + }
  150 + $openid = $third['openid'];
  151 + }
  152 + try {
  153 + $response = \addons\facrm\library\Order::submit($pay_token, $ordertype,$paytype, $method, $openid, $appid, $returnurl, ['number' => $number]);
  154 + return $response;
  155 + } catch (\Exception $e) {
  156 + $this->error($e->getMessage());
  157 + }
  158 +
  159 + }
  160 +
  161 + /**
  162 + * 企业支付通知和回调
  163 + */
  164 + public function epay()
  165 + {
  166 + \think\Log::write(isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '_________', 'error');
  167 +
  168 + $type = $this->request->param('type');
  169 + $paytype = $this->request->param('paytype');
  170 + if ($type == 'notify') {
  171 + \think\Log::write('__验证开始__', 'error');
  172 + $pay = \addons\epay\library\Service::checkNotify($paytype);
  173 + if (!$pay) {
  174 + \think\Log::write('__签名错误_', 'error');
  175 + echo '签名错误';
  176 + return;
  177 + }
  178 + $data = $pay->verify();
  179 +
  180 + /* //调试
  181 + $data=array(
  182 + 'total_amount'=>800,
  183 + 'out_trade_no'=>'20220519113008000000003943',
  184 + 'total_fee'=>80000,
  185 + );*/
  186 + try {
  187 + $payamount = $paytype == 'alipay' ? $data['total_amount'] : $data['total_fee'] / 100;
  188 + \think\Log::write('__进入支付_', 'error');
  189 + \addons\facrm\library\Order::settle($data['out_trade_no'], $payamount);
  190 + } catch (Exception $e) {
  191 + \think\Log::write($e->getMessage() . '__支付异常报错_', 'error');
  192 + }
  193 + echo $pay->success();
  194 + } else {
  195 + $pay = \addons\epay\library\Service::checkReturn($paytype);
  196 + if (!$pay) {
  197 + $this->error('签名错误');
  198 + }
  199 + //微信支付没有返回链接
  200 + if ($pay === true) {
  201 + $this->success("请返回网站查看支付状态!", "");
  202 + }
  203 +
  204 + //你可以在这里定义你的提示信息,但切记不可在此编写逻辑
  205 + $this->success("请返回网站查看支付状态!", url("user/index"));
  206 + }
  207 + return;
  208 + }
  209 +
  210 +
  211 + /**
  212 + * 生成二维码
  213 + */
  214 + public function qrcode()
  215 + {
  216 + $text = $this->request->get('text', 'hello world');
  217 +
  218 + //如果有安装二维码插件,则调用插件的生成方法
  219 + if (class_exists("\addons\qrcode\library\Service") && get_addon_info('qrcode')['state']) {
  220 + $qrCode = \addons\qrcode\library\Service::qrcode(['text' => $text]);
  221 + $response = Response::create()->header("Content-Type", "image/png");
  222 +
  223 + header('Content-Type: ' . $qrCode->getContentType());
  224 + $response->content($qrCode->writeString());
  225 + return $response;
  226 + } else {
  227 + $qr = \addons\facrm\library\QRCode::getMinimumQRCode($text);
  228 + $im = $qr->createImage(8, 5);
  229 + header("Content-type: image/png");
  230 + imagepng($im);
  231 + imagedestroy($im);
  232 + return;
  233 + }
  234 + }
  235 +
  236 +
  237 +}
  1 +<?php
  2 +
  3 +
  4 +namespace addons\facrm\controller;
  5 +
  6 +
  7 +use app\admin\model\Admin;
  8 +use EasyWeChat\Factory;
  9 +use think\addons\Controller;
  10 +use think\Hook;
  11 +use think\Log;
  12 +use think\Session;
  13 +use app\admin\model\facrm\qywx\User as QywxUser;
  14 +use EasyWeChat\Kernel\Support;
  15 +use addons\facrm\library\BackendApi;
  16 +
  17 +/**
  18 + * 企业微信通信管理
  19 + * @icon fa fa-circle-o
  20 + */
  21 +class Qywx extends BackendApi
  22 +{
  23 + protected $app = null;//EasyWeChat 实列
  24 + protected $config = array();//企业微信配置
  25 + protected $noNeedRight = ['*'];
  26 + protected $noNeedLogin = ['connect','login','wxlogin'];
  27 +
  28 + public function _initialize()
  29 + {
  30 + //跨域请求检测
  31 + check_cors_request();
  32 + parent::_initialize();
  33 + $this->request->filter(['strip_tags']);
  34 +
  35 + $key = "work_weixin_set";
  36 + $settingModel = new \app\admin\model\facrm\Setting();
  37 + $row = $settingModel->where('key', $key)->find();
  38 + if (!$row) $this->error(__("企业微信未配置"));
  39 + $this->config = json_decode($row['values'], true);//获取器不知道为什么失效了
  40 + if (!$this->config) $this->error(__("企业微信未配置1"));
  41 +
  42 + }
  43 +
  44 + /**
  45 + * 微信验证
  46 + * @ApiInternal
  47 + */
  48 + public function connect()
  49 + {
  50 +
  51 + $config = [
  52 + 'corp_id' => $this->config['corp_id'],
  53 + 'agent_id' => $this->config['agent_id'],
  54 + 'secret' => $this->config['agent_secret'],
  55 + 'token' => $this->config['customer_callback_token'],
  56 + 'aes_key' => $this->config['EncodongAESKey'],
  57 + ];
  58 + $app = Factory::work($config);
  59 + $app->server->push(function($message){
  60 + $res= \addons\facrm\library\qywx\Event::execute($message);
  61 + });
  62 + $response = $app->server->serve();
  63 + $response->send();
  64 +
  65 + }
  66 +
  67 + /**
  68 + * 企业微信H5登录
  69 + * @ApiParams(name="code", type="string", required=true, description="post请求的时候需要")
  70 + * @ApiParams(name="url", type="string", required=true, description="url")
  71 + * @ApiBody ("get是获取一些基本配置")
  72 + *
  73 + */
  74 + public function login(){
  75 + $app_ag_config = [
  76 + 'corp_id' => $this->config['corp_id'],
  77 + 'agent_id' => $this->config['agent_id'],
  78 + 'secret' => $this->config['agent_secret'],
  79 + ];
  80 +
  81 + if (request()->isGet()){
  82 + $url = $this->request->param('url');
  83 + $config = [
  84 + 'corp_id' => $this->config['corp_id'],
  85 + 'agent_id' => $this->config['agent_id'],
  86 + 'secret' => $this->config['customer_secret'],
  87 + ];
  88 + $this->app = $app = Factory::work($config);
  89 + $wx_config = ($app->jssdk->buildConfig(['updateAppMessageShareData', 'updateTimelineShareData'], $debug = false, $beta = false, $json = true, $openTagList = []));
  90 +
  91 + $this->app = $app = Factory::work($app_ag_config);
  92 + $supportExtend=new \addons\facrm\library\extend\easywechat\SupportExtend($app);
  93 + $ag_config = $supportExtend->buildAgentConfig(
  94 + ['getCurExternalContact'],
  95 + $this->config['agent_id'],
  96 + $debug = false,
  97 + $beta = false,
  98 + $json = true,
  99 + $openTagList = [],
  100 + $url
  101 + );
  102 +
  103 + $this->success('',['wx_config'=>json_decode($wx_config,true),'ag_config'=>json_decode($ag_config,true)]);
  104 +
  105 + }else{
  106 +
  107 + $app = Factory::work($app_ag_config);
  108 + $user = $app->oauth->detailed()->user();
  109 + // 获取用户信息
  110 + $userid = $user->getId(); // 对应企业微信英文名(userid)
  111 + if (!$userid) $this->error(__("获取企业微信信息失败"));
  112 +
  113 + $loca_user = QywxUser::getUser($userid);
  114 + if (!$loca_user) {
  115 + //不存在就调用接口去获取
  116 + $c_config = [
  117 + 'corp_id' => $this->config['corp_id'],
  118 + 'secret' => $this->config['contacts_secret'], // 通讯录的 secret
  119 + ];
  120 + $contacts = Factory::work($c_config);
  121 + $qywx_user = $contacts->user->get($userid);
  122 +
  123 + if (!$qywx_user || $qywx_user['errcode'] != '0') $this->error(__("获取企业微信信息失败"));
  124 + $loca_user = QywxUser::getUser($userid, $this->config, $qywx_user);
  125 + }
  126 +
  127 + if (!$loca_user || !$loca_user['admin_id']) {
  128 + $this->error(__("企业微信登录失败"));
  129 + }
  130 +
  131 + $admin = $this->auth->direct($loca_user['admin_id']);
  132 + if ($admin) {
  133 + Hook::listen("admin_login_after", $this->request);
  134 + $this->success(__("登录成功!"), [
  135 + 'token' => $admin->token,
  136 + 'id' => $admin->id,
  137 + 'username' => $admin->username,
  138 + 'nickname' => $admin->nickname,
  139 + 'avatar' => cdnurl($admin->avatar, true),
  140 + ]);
  141 + }
  142 + $this->error(__($this->auth->getError()));
  143 +
  144 + }
  145 + $this->error(__('登录失败'));
  146 +
  147 + }
  148 +
  149 + /**
  150 + * 企业微信小程序登录
  151 + * @ApiBody ("")
  152 + *
  153 + */
  154 + public function wxlogin(){
  155 + $config = [
  156 + 'corp_id' => $this->config['corp_id'],
  157 + 'agent_id' => $this->config['agent_id'],
  158 + 'secret' => $this->config['agent_secret'],
  159 + ];
  160 +
  161 + $app = Factory::work($config);
  162 +
  163 + $miniProgram = $app->miniProgram();
  164 +
  165 + $res = $miniProgram->auth->session("js-code");
  166 +
  167 + if ($res&&isset($res['userid'])){
  168 + $userid = $res['userid']; // 对应企业微信英文名(userid)
  169 + if (!$userid) $this->error(__("获取企业微信信息失败"));
  170 +
  171 + $loca_user = QywxUser::getUser($userid);
  172 + if (!$loca_user) {
  173 + //不存在就调用接口去获取
  174 + $c_config = [
  175 + 'corp_id' => $this->config['corp_id'],
  176 + 'secret' => $this->config['contacts_secret'], // 通讯录的 secret
  177 + ];
  178 + $contacts = Factory::work($c_config);
  179 + $qywx_user = $contacts->user->get($userid);
  180 +
  181 + if (!$qywx_user || $qywx_user['errcode'] != '0') $this->error(__("获取企业微信信息失败"));
  182 + $loca_user = QywxUser::getUser($userid, $this->config, $qywx_user);
  183 + }
  184 +
  185 + if (!$loca_user || !$loca_user['admin_id']) {
  186 + $this->error(__("企业微信登录失败"));
  187 + }
  188 +
  189 + $admin = $this->auth->direct($loca_user['admin_id']);
  190 + if ($admin) {
  191 + Hook::listen("admin_login_after", $this->request);
  192 + $this->success(__("登录成功!"), [
  193 + 'token' => $admin->token,
  194 + 'id' => $admin->id,
  195 + 'username' => $admin->username,
  196 + 'nickname' => $admin->nickname,
  197 + 'avatar' => cdnurl($admin->avatar, true),
  198 + ]);
  199 + }
  200 + $this->error(__($this->auth->getError()));
  201 + }
  202 +
  203 + $this->error(__("获取企业微信信息失败2"));
  204 + }
  205 +
  206 +
  207 + /**
  208 + * 获取客户ID
  209 + * @ApiParams(name="userid", type="string", required=true, description="企业微信客户")
  210 + * @ApiBody ("get是获取一些基本配置")
  211 + * @Internal
  212 + */
  213 + public function getCustomerId()
  214 + {
  215 + $admin = $this->auth->getUserInfo();
  216 + if (!$admin) $this->error(__("未登录"));
  217 +
  218 + $external_userid = $this->request->param('userid');
  219 + if (!$external_userid) $this->error(__("userid不能为空"));
  220 +
  221 + //获取本地微信外部联系人customer_id;
  222 + $contactsModel = new \app\admin\model\facrm\qywx\Contacts();
  223 +
  224 + $qywxContacts = $contactsModel->getContacts($external_userid, $this->config, ['admin_id' => $admin['id']]);
  225 + if (!$qywxContacts) {
  226 + $this->error(__("获取企业客户信息失败"));
  227 + }
  228 + $this->success('', $qywxContacts->customer_id);
  229 + }
  230 +
  231 +
  232 +}
  1 +<?php
  2 +
  3 +namespace addons\facrm\controller\auth;
  4 +
  5 +use addons\facrm\library\BackendApi;
  6 +use app\admin\model\AuthGroup;
  7 +use app\admin\model\AuthGroupAccess;
  8 +use fast\Random;
  9 +use fast\Tree;
  10 +use think\Validate;
  11 +
  12 +/**
  13 + * 管理员管理
  14 + *
  15 + * @icon fa fa-users
  16 + * @remark 一个管理员可以有多个角色组,左侧的菜单根据管理员所拥有的权限进行生成
  17 + */
  18 +class Admin extends BackendApi
  19 +{
  20 +
  21 + /**
  22 + * @var \app\admin\model\Admin
  23 + */
  24 + protected $model = null;
  25 + protected $selectpageFields = 'id,username,nickname,avatar';
  26 + protected $searchFields = 'id,username,nickname';
  27 + protected $childrenGroupIds = [];
  28 + protected $childrenAdminIds = [];
  29 + protected $groupdata=[];
  30 + protected $noNeedRight = ['getGroupdata'];
  31 + public function _initialize()
  32 + {
  33 + parent::_initialize();
  34 + $this->model = model('\app\admin\model\Admin');
  35 +
  36 + $this->childrenAdminIds = $this->auth->getChildrenAdminIds(true);
  37 + $this->childrenGroupIds = $this->auth->getChildrenGroupIds(true);
  38 +
  39 + $groupList = collection(AuthGroup::where('id', 'in', $this->childrenGroupIds)->select())->toArray();
  40 +
  41 + Tree::instance()->init($groupList);
  42 +
  43 + if ($this->auth->isSuperAdmin()) {
  44 + $result = Tree::instance()->getTreeList(Tree::instance()->getTreeArray(0));
  45 + foreach ($result as $k => $v) {
  46 + $this->groupdata[$v['id']] = $v['name'];
  47 + }
  48 + } else {
  49 + $result = [];
  50 + $groups = $this->auth->getGroups();
  51 +
  52 + foreach ($groups as $m => $n) {
  53 + $result[$n['id']] =__($n['name']);
  54 + $childlist = Tree::instance()->getTreeList(Tree::instance()->getTreeArray($n['id']));
  55 + foreach ($childlist as $k => $v) {
  56 + $result[$v['id']] = $v['name'];
  57 + }
  58 +
  59 + }
  60 + $this->groupdata = $result;
  61 + }
  62 +
  63 + }
  64 +
  65 + /**
  66 + * 查看
  67 + */
  68 + public function index()
  69 + {
  70 + //设置过滤方法
  71 + $this->request->filter(['strip_tags', 'trim']);
  72 + //如果发送的来源是Selectpage,则转发到Selectpage
  73 + if ($this->request->request('keyField')) {
  74 + return $this->selectpage();
  75 + }
  76 + $childrenGroupIds = $this->childrenGroupIds;
  77 + $groupName = AuthGroup::where('id', 'in', $childrenGroupIds)
  78 + ->column('id,name');
  79 + $authGroupList = AuthGroupAccess::where('group_id', 'in', $childrenGroupIds)
  80 + ->field('uid,group_id')
  81 + ->select();
  82 +
  83 + $adminGroupName = [];
  84 + foreach ($authGroupList as $k => $v) {
  85 + if (isset($groupName[$v['group_id']])) {
  86 + $adminGroupName[$v['uid']][$v['group_id']] = $groupName[$v['group_id']];
  87 + }
  88 + }
  89 + $groups = $this->auth->getGroups();
  90 + foreach ($groups as $m => $n) {
  91 + $adminGroupName[$this->auth->id][$n['id']] = $n['name'];
  92 + }
  93 + list($where, $sort, $order, $offset, $limit) = $this->buildparams();
  94 +
  95 + $list = $this->model
  96 + ->where($where)
  97 + ->where('id', 'in', $this->childrenAdminIds)
  98 + ->field(['password', 'salt', 'token'], true)
  99 + ->order($sort, $order)
  100 + ->paginate($limit);
  101 +
  102 + foreach ($list as $k => &$v) {
  103 + $groups = isset($adminGroupName[$v['id']]) ? $adminGroupName[$v['id']] : [];
  104 + $v['groups'] = implode(',', array_keys($groups));
  105 + $v['groups_text'] = implode(',', array_values($groups));
  106 + }
  107 + unset($v);
  108 + $result = array("rows" => $list);
  109 + $this->success('', $result);
  110 +
  111 + }
  112 +
  113 + /**
  114 + * 获取员工组
  115 + */
  116 + public function getGroupdata()
  117 + {
  118 + $this->success('',$this->groupdata);
  119 + }
  120 + /**
  121 + * 添加
  122 + */
  123 + public function add()
  124 + {
  125 + if ($this->request->isPost()) {
  126 +
  127 + $params = $this->request->post();
  128 + if ($params) {
  129 + if (!Validate::is($params['password'], '\S{6,16}')) {
  130 + $this->error(__("Please input correct password"));
  131 + }
  132 + $params['salt'] = Random::alnum();
  133 + $params['password'] = md5(md5($params['password']) . $params['salt']);
  134 + $params['avatar'] = '/assets/img/avatar.png'; //设置新管理员默认头像。
  135 + $result = $this->model->validate('\app\admin\validate\Admin.add')->allowField(true)->save($params);
  136 + if ($result === false) {
  137 + $this->error($this->model->getError());
  138 + }
  139 + $group = $this->request->post("group/a");
  140 + //过滤不允许的组别,避免越权
  141 + $group = array_intersect($this->childrenGroupIds, $group);
  142 + $dataset = [];
  143 + foreach ($group as $value) {
  144 + $dataset[] = ['uid' => $this->model->id, 'group_id' => $value];
  145 + }
  146 + model('\app\admin\model\AuthGroupAccess')->saveAll($dataset);
  147 + $this->success();
  148 + }
  149 +
  150 + }
  151 + $this->error();
  152 + }
  153 +
  154 + /**
  155 + * 编辑
  156 + * @ApiParams(name="id", type="int", required=true, description="管理员id")
  157 + * @ApiBody("get获取,post提交修改")
  158 + */
  159 + public function edit()
  160 + {
  161 + $ids = $this->request->request('id', '', 'intval');
  162 + if (!$ids) {
  163 + $this->error(__('No Results were found'));
  164 + }
  165 +
  166 + $row = $this->model->get(['id' => $ids]);
  167 + if (!$row) {
  168 + $this->error(__('No Results were found'));
  169 + }
  170 + if (!in_array($row->id, $this->childrenAdminIds)) {
  171 + $this->error(__('You have no permission'));
  172 + }
  173 + if ($this->request->isPost()) {
  174 +
  175 + $params = $this->request->post();
  176 + if ($params) {
  177 + if ($params['password']) {
  178 + if (!Validate::is($params['password'], '\S{6,16}')) {
  179 + $this->error(__("Please input correct password"));
  180 + }
  181 + $params['salt'] = Random::alnum();
  182 + $params['password'] = md5(md5($params['password']) . $params['salt']);
  183 + } else {
  184 + unset($params['password'], $params['salt']);
  185 + }
  186 + //这里需要针对username和email做唯一验证
  187 + $adminValidate = \think\Loader::validate('\app\admin\validate\Admin');
  188 + $adminValidate->rule([
  189 + 'username' => 'require|regex:\w{3,12}|unique:admin,username,' . $row->id,
  190 + 'email' => 'require|email|unique:admin,email,' . $row->id,
  191 + 'password' => 'regex:\S{32}',
  192 + ]);
  193 + $result = $row->validate('\app\admin\validate\Admin.edit')->allowField(true)->save($params);
  194 +
  195 + if ($result === false) {
  196 + $this->error($row->getError());
  197 + }
  198 +
  199 + // 先移除所有权限
  200 + model('\app\admin\model\AuthGroupAccess')->where('uid', $row->id)->delete();
  201 +
  202 + $group = $this->request->post("group/a");
  203 +
  204 + // 过滤不允许的组别,避免越权
  205 + $group = array_intersect($this->childrenGroupIds, $group);
  206 +
  207 + $dataset = [];
  208 + foreach ($group as $value) {
  209 + $dataset[] = ['uid' => $row->id, 'group_id' => $value];
  210 + }
  211 + model('\app\admin\model\AuthGroupAccess')->saveAll($dataset);
  212 + $this->success();
  213 + }
  214 + $this->error();
  215 + }
  216 + $grouplist = $this->auth->getGroups($row['id']);
  217 + $groupids = [];
  218 + foreach ($grouplist as $k => $v) {
  219 + $groupids[] = $v['id'];
  220 + }
  221 + $this->success('',['row'=>$row,'groupids'=>$groupids]);
  222 + }
  223 +
  224 + /**
  225 + * 删除
  226 + * @ApiParams(name="ids", type="int", required=true, description="管理员id")
  227 + */
  228 + public function del()
  229 + {
  230 + $ids = $this->request->request('ids', '', 'intval');
  231 + if (!$ids) {
  232 + $this->error(__('No Results were found'));
  233 + }
  234 + if (!$this->request->isPost()) {
  235 + $this->error(__("Invalid parameters"));
  236 + }
  237 + $ids = $ids ? $ids : $this->request->post("ids");
  238 + if ($ids) {
  239 + $ids = array_intersect($this->childrenAdminIds, array_filter(explode(',', $ids)));
  240 + // 避免越权删除管理员
  241 + $childrenGroupIds = $this->childrenGroupIds;
  242 + $adminList = $this->model->where('id', 'in', $ids)->where('id', 'in', function ($query) use ($childrenGroupIds) {
  243 + $query->name('auth_group_access')->where('group_id', 'in', $childrenGroupIds)->field('uid');
  244 + })->select();
  245 + if ($adminList) {
  246 + $deleteIds = [];
  247 + foreach ($adminList as $k => $v) {
  248 + $deleteIds[] = $v->id;
  249 + }
  250 + $deleteIds = array_values(array_diff($deleteIds, [$this->auth->id]));
  251 + if ($deleteIds) {
  252 + $this->model->destroy($deleteIds);
  253 + model('\app\admin\model\AuthGroupAccess')->where('uid', 'in', $deleteIds)->delete();
  254 + $this->success();
  255 + }
  256 + }
  257 + }
  258 + $this->error(__('You have no permission'));
  259 + }
  260 +
  261 + /**
  262 + * 下拉搜索
  263 + */
  264 + public function selectpage()
  265 + {
  266 + $this->dataLimit = 'auth';
  267 + $this->dataLimitField = 'id';
  268 + return parent::selectpage();
  269 + }
  270 +}
  1 +<?php
  2 +
  3 +namespace addons\facrm\controller\facrm;
  4 +
  5 +use app\admin\model\AuthGroup;
  6 +use addons\facrm\library\BackendApi;
  7 +use fast\Tree;
  8 +use think\Db;
  9 +use think\Exception;
  10 +
  11 +/**
  12 + * 业绩目标
  13 + *
  14 + */
  15 +class Achievement extends BackendApi
  16 +{
  17 +
  18 + /**
  19 + * @var \app\admin\model\AuthGroup
  20 + */
  21 + protected $model = null;
  22 + //当前登录管理员所有子组别
  23 + protected $childrenGroupIds = [];
  24 + protected $childrenAdminIds = [];
  25 + //当前组别列表数据
  26 + protected $groupdata = [];
  27 + protected $groupList = [];
  28 + //无需要权限判断的方法
  29 + protected $noNeedRight = ['roletree'];
  30 +
  31 + public function _initialize()
  32 + {
  33 + parent::_initialize();
  34 + $this->request->filter(['strip_tags']);
  35 + $this->model = new AuthGroup();
  36 +
  37 + $this->childrenGroupIds = $this->auth->getChildrenGroupIds(true);
  38 + $this->childrenAdminIds = $this->auth->getChildrenAdminIds(true);
  39 + $this->groupList = $groupList = collection(AuthGroup::where('id', 'in', $this->childrenGroupIds)->select())->toArray();
  40 +
  41 + Tree::instance()->init($groupList);
  42 + $result = [];
  43 + if ($this->auth->isSuperAdmin()) {
  44 + $result = Tree::instance()->getTreeList(Tree::instance()->getTreeArray(0));
  45 + } else {
  46 + $groups = $this->auth->getGroups();
  47 + foreach ($groups as $m => $n) {
  48 + $result = array_merge($result, Tree::instance()->getTreeList(Tree::instance()->getTreeArray($n['pid'])));
  49 + }
  50 + }
  51 + $groupName = [];
  52 + foreach ($result as $k => $v) {
  53 + $groupName[$v['id']] = $v['name'];
  54 + }
  55 +
  56 + $this->groupdata = $groupName;
  57 + }
  58 +
  59 + protected $temp_achievement = [
  60 + 'type' => 2,
  61 + 'type_id' => '',
  62 + 'year' => '',
  63 + 'january' => '',
  64 + 'february' => '',
  65 + 'march' => '',
  66 + 'april' => '',
  67 + 'may' => '',
  68 + 'june' => '',
  69 + 'july' => '',
  70 + 'august' => '',
  71 + 'september' => '',
  72 + 'october' => '',
  73 + 'november' => '',
  74 + 'december' => '',
  75 + 'yeartarget' => '',
  76 + ];
  77 +
  78 + /**
  79 + * 查看列表
  80 + * @ApiMethod (get)
  81 + */
  82 + public function index()
  83 + {
  84 + $achievement = new \app\admin\model\facrm\Achievement();
  85 + $filter = $this->request->get("filter", '');
  86 + $filter = (array)json_decode($filter, true);
  87 + $filter_w = [];
  88 + if (isset($filter['search_time'])) {
  89 + $filter_w['year'] = $filter['search_time'];
  90 + unset($filter['search_time']);
  91 + } else {
  92 + $filter_w['year'] = date('Y', time());
  93 + }
  94 + if (isset($filter['config'])) {
  95 + $filter_w['config'] = $filter['config'];
  96 + unset($filter['config']);
  97 + } else {
  98 + $filter_w['config'] = 1;
  99 + }
  100 + $this->request->get(['filter' => json_encode($filter)]);
  101 +
  102 +
  103 + if (isset($filter['group_id'])) {
  104 + $list = AuthGroup::all($filter['group_id']);
  105 + } else {
  106 + $list = AuthGroup::all(array_keys($this->groupdata));
  107 + }
  108 + $list = collection($list)->toArray();
  109 + $groupList = [];
  110 + foreach ($list as $k => $v) {
  111 + $groupList[$v['id']] = $v;
  112 + }
  113 + $list = [];
  114 + foreach ($this->groupdata as $k => $v) {
  115 +
  116 + if (isset($groupList[$k])) {
  117 + $groupList[$k]['name'] = $v;
  118 + $groupList[$k]['achievement'] = $achievement->where('type', 2)->where($filter_w)->where('type_id', $k)->find();
  119 + $groupList[$k]['achievement'] = $groupList[$k]['achievement'] ?: $this->temp_achievement;
  120 + $list[] = $groupList[$k];
  121 +
  122 + }
  123 + }
  124 + $total = count($list);
  125 + $result = array("total" => $total, "rows" => $list, "extend" => ['year' => $filter_w['year'], 'config' => isset($filter_w['config']) ? $filter_w['config'] : '']);
  126 +
  127 + $this->success('',$result);
  128 +
  129 +
  130 + }
  131 +
  132 +
  133 + /**
  134 + * 员工业绩列表
  135 + * @ApiMethod (get)
  136 + */
  137 + public function admin()
  138 + {
  139 + $achievement = new \app\admin\model\facrm\Achievement();
  140 + //设置过滤方法
  141 + $filter = $this->request->get("filter", '');
  142 + $filter = (array)json_decode($filter, true);
  143 + $filter_w = [];
  144 + if (isset($filter['search_time'])) {
  145 + $filter_w['year'] = $filter['search_time'];
  146 + unset($filter['search_time']);
  147 + } else {
  148 + $filter_w['year'] = date('Y', time());
  149 + }
  150 + if (isset($filter['config'])) {
  151 + $filter_w['config'] = $filter['config'];
  152 + unset($filter['config']);
  153 + } else {
  154 + $filter_w['config'] = 1;
  155 + }
  156 +
  157 +
  158 + $this->model =new \app\admin\model\Admin();
  159 + $childrenAdminIds = $this->getFilterChildrenAdminIds($filter);
  160 +
  161 + if ($childrenAdminIds) {
  162 + $this->childrenAdminIds = $childrenAdminIds;
  163 + }
  164 + if (isset($filter['group_id'])) {
  165 + unset($filter['group_id']);
  166 + }
  167 +
  168 + $this->request->get(['filter' => json_encode($filter)]);
  169 + list($where, $sort, $order, $offset, $limit) = $this->buildparams();
  170 + $list = $this->model
  171 + ->where($where)
  172 + ->where('id', 'in', $this->childrenAdminIds)
  173 + ->field(['password', 'salt', 'token'], true)
  174 + ->order($sort, $order)
  175 + ->paginate($limit);
  176 + $this->temp_achievement['type'] = 3;
  177 + foreach ($list as $k => &$row) {
  178 + $row['achievement'] = $achievement->where('type', 3)->where($filter_w)->where('type_id', $row['id'])->find();
  179 + $row['achievement'] = $row['achievement'] ?: $this->temp_achievement;
  180 +
  181 + }
  182 + unset($v);
  183 + $result = array("total" => $list->total(), "rows" => $list->items(), "extend" => ['year' => $filter_w['year'], 'config' => isset($filter_w['config']) ? $filter_w['config'] : '']);
  184 + $this->success('',$result);
  185 + }
  186 +
  187 + /**
  188 + * 团队业绩编辑(单条)
  189 + * @ApiMethod (POST)
  190 + */
  191 + public function edit()
  192 + {
  193 + $param = $this->request->param('row/a');
  194 + $field = $param['field'];
  195 + if (!isset($param['config']) || !in_array($param['config'], [1, 2])) {
  196 + $this->error(__("业绩方式有误"));
  197 + }
  198 + if (!isset($param['year']) && $param['year'] < 2000) {
  199 + $this->error(__("年份有误"));
  200 + }
  201 + if (!isset($param['group_id']) && $param['group_id'] < 0) {
  202 + $this->error(__("权限组有误"));
  203 + }
  204 + $where = [
  205 + 'type' => 2,
  206 + 'type_id' => $param['group_id'],
  207 + 'year' => $param['year'],
  208 + 'config' => $param['config'],
  209 + ];
  210 + $achievement = new \app\admin\model\facrm\Achievement();
  211 + $row = $achievement->where($where)->find();
  212 +
  213 + if (!is_numeric($param[$field]) || $param[$field] < 0) {
  214 + $this->error(__("请输入数字"));
  215 + }
  216 + if (!$row) {
  217 + //添加一条新记录
  218 + $this->temp_achievement['type_id'] = $param['group_id'];
  219 + $this->temp_achievement['year'] = $param['year'];
  220 + $this->temp_achievement['config'] = $param['config'];
  221 + $row = $achievement->create($this->temp_achievement);
  222 +
  223 + if (!$row) {
  224 + $this->error(__("插入数据失败"));
  225 + }
  226 + $row = $achievement->find($row->id);
  227 + }
  228 +
  229 + try {
  230 +
  231 + $old_val = $row->$field;
  232 + if ($old_val == $param[$field]) {
  233 + $this->error(__("没有修改"));
  234 + } elseif ($old_val > $param[$field]) {
  235 + $row->yeartarget = $row->yeartarget - ($old_val - $param[$field]);
  236 + } elseif ($old_val < $param[$field]) {
  237 + $row->yeartarget = $row->yeartarget + ($param[$field] - $old_val);
  238 + }
  239 + $row->$field = $param[$field];
  240 + $row->config = $param['config'];
  241 + $row->save();
  242 + } catch (\Exception $e) {
  243 + $this->error($e->getMessage());
  244 + }
  245 + $this->success();
  246 + }
  247 +
  248 + /**
  249 + * 成员业绩编辑(单条)
  250 + * @param null $ids
  251 + * @ApiMethod (POST)
  252 + */
  253 + public function aedit()
  254 + {
  255 + $param = $this->request->param('row/a');
  256 + $field = $param['field'];
  257 + if (!isset($param['year']) && $param['year'] < 2000) {
  258 + $this->error(__("年份有误"));
  259 + }
  260 + if (!isset($param['admin_id']) && $param['admin_id'] < 0) {
  261 + $this->error(__("权限组有误"));
  262 + }
  263 + if (!isset($param['config']) || !in_array($param['config'], [1, 2])) {
  264 + $this->error(__("业绩方式有误"));
  265 + }
  266 + $where = [
  267 + 'type' => 3,
  268 + 'type_id' => $param['admin_id'],
  269 + 'year' => $param['year'],
  270 + 'config' => $param['config'],
  271 + ];
  272 + $achievement = new \app\admin\model\facrm\Achievement();
  273 + $row = $achievement->where($where)->find();
  274 + if (!is_numeric($param[$field]) || $param[$field] < 0) {
  275 + $this->error(__("请输入数字"));
  276 + }
  277 + if (!$row) {
  278 + //添加一条新记录
  279 + $this->temp_achievement['type_id'] = $param['admin_id'];
  280 + $this->temp_achievement['year'] = $param['year'];
  281 + $this->temp_achievement['type'] = 3;
  282 + $this->temp_achievement['config'] = $param['config'];
  283 + $row = $achievement->create($this->temp_achievement);
  284 +
  285 + if (!$row) {
  286 + $this->error(__("插入数据失败"));
  287 + }
  288 + $row = $achievement->find($row->id);
  289 + }
  290 +
  291 + try {
  292 +
  293 + $old_val = $row->$field;
  294 + if ($old_val == $param[$field]) {
  295 + $this->error(__("没有修改"));
  296 + } elseif ($old_val > $param[$field]) {
  297 + $row->yeartarget = $row->yeartarget - ($old_val - $param[$field]);
  298 + } elseif ($old_val < $param[$field]) {
  299 + $row->yeartarget = $row->yeartarget + ($param[$field] - $old_val);
  300 + }
  301 + $row->$field = $param[$field];
  302 + $row->save();
  303 +
  304 + } catch (\Exception $e) {
  305 + $this->error($e->getMessage());
  306 + }
  307 + $this->success();
  308 + }
  309 +
  310 + /**
  311 + * 团队批量设置
  312 + */
  313 + public function batchTeam(){
  314 + if ($this->request->isPost()) {
  315 + $param = $this->request->param('row/a');
  316 + if (!isset($param['config']) || !in_array($param['config'], [1, 2])) {
  317 + $this->error(__("业绩方式有误"));
  318 + }
  319 + if (!isset($param['year']) && $param['year'] < 2000) {
  320 + $this->error(__("年份有误"));
  321 + }
  322 + if (!isset($param['group_id']) && $param['group_id'] < 0) {
  323 + $this->error(__("部门有误"));
  324 + }
  325 + $where = [
  326 + 'type' => 2,
  327 + 'year' => $param['year'],
  328 + 'config' => $param['config'],
  329 + ];
  330 +
  331 + $result=false;
  332 +
  333 + if ($param['group_id']==0){
  334 + //全部
  335 + unset($param['group_id']);
  336 + foreach ($this->groupList as $g){
  337 + $achievement = new \app\admin\model\facrm\Achievement();
  338 + $where['type_id']=$g['id'];
  339 + $row = $achievement->where($where)->find();
  340 + $this->temp_achievement=array_merge($this->temp_achievement,$param);
  341 + $this->temp_achievement['type_id'] = $where['type_id'];
  342 + $this->temp_achievement['year'] = $where['year'];
  343 + if (!$row) {
  344 + //添加一条新记录
  345 + $result=$achievement->create($this->temp_achievement);
  346 + }else{
  347 + $result=$row->save($this->temp_achievement);
  348 + }
  349 + }
  350 +
  351 + $this->success();
  352 +
  353 + }else{
  354 + $achievement = new \app\admin\model\facrm\Achievement();
  355 + //某一个部门
  356 + $where['type_id']=$param['group_id'];
  357 + unset($param['group_id']);
  358 +
  359 + $row = $achievement->where($where)->find();
  360 + $this->temp_achievement=array_merge($this->temp_achievement,$param);
  361 + $this->temp_achievement['type_id'] = $where['type_id'];
  362 + $this->temp_achievement['year'] = $where['year'];
  363 + if (!$row) {
  364 + //添加一条新记录
  365 + $result=$achievement->create($this->temp_achievement);
  366 + }else{
  367 + $result=$row->save($this->temp_achievement);
  368 + }
  369 + }
  370 + if ($result){
  371 + $this->success();
  372 + }else{
  373 + $this->error(__("添加失败"));
  374 + }
  375 +
  376 +
  377 + }
  378 + $this->error(__("提交方式错误"));
  379 + }
  380 +
  381 + /**
  382 + * 成员批量设置
  383 + */
  384 + public function batchAdmin(){
  385 + if ($this->request->isPost()) {
  386 + $param = $this->request->param('row/a');
  387 + if (!isset($param['config']) || !in_array($param['config'], [1, 2])) {
  388 + $this->error(__("业绩方式有误"));
  389 + }
  390 + if (!isset($param['year']) && $param['year'] < 2000) {
  391 + $this->error(__("年份有误"));
  392 + }
  393 + if (!isset($param['admin_id'])) {
  394 + $this->error(__("员工有误"));
  395 + }
  396 + $where = [
  397 + 'type' => 3,
  398 + 'year' => $param['year'],
  399 + 'config' => $param['config'],
  400 + ];
  401 +
  402 + $result=false;
  403 + if ($param['admin_id']){
  404 + $this->childrenAdminIds=explode(",",$param['admin_id']);
  405 + }
  406 + //全部
  407 + unset($param['admin_id']);
  408 + $lists = \app\admin\model\Admin::where('id', 'in', $this->childrenAdminIds)
  409 + ->field(['password', 'salt', 'token'], true)
  410 + ->select();
  411 +
  412 +
  413 + foreach ($lists as $g){
  414 + $achievement = new \app\admin\model\facrm\Achievement();
  415 + $where['type_id']=$g['id'];
  416 + $row = $achievement->where($where)->find();
  417 + $this->temp_achievement=array_merge($this->temp_achievement,$param);
  418 + $this->temp_achievement['type_id'] = $where['type_id'];
  419 + $this->temp_achievement['year'] = $where['year'];
  420 + $this->temp_achievement['type']=$where['type'];
  421 + if (!$row) {
  422 + //添加一条新记录
  423 + $result=$achievement->create($this->temp_achievement);
  424 + }else{
  425 + $result=$row->isUpdate(true)->save($this->temp_achievement);
  426 + }
  427 + }
  428 +
  429 + $this->success();
  430 + }
  431 +
  432 + $this->error(__("提交方式错误"));
  433 + }
  434 +
  435 +
  436 +
  437 + /**
  438 + * 过滤查找子用户
  439 + * @param $filter
  440 + * @return array|void
  441 + */
  442 + protected function getFilterChildrenAdminIds($filter)
  443 + {
  444 + $childrenAdminIds = [];
  445 + if (isset($filter['group_id'])) {
  446 + $childrenAdminIds = [];
  447 + if ($filter['group_id'] > 0) {
  448 + Tree::instance()->init($this->groupList);
  449 + $groupIds = Tree::instance()->getChildrenIds($filter['group_id'], true);
  450 +
  451 + $authGroupList = \app\admin\model\AuthGroupAccess::
  452 + field('uid,group_id')
  453 + ->where('group_id', 'in', $groupIds)
  454 + ->select();
  455 + foreach ($authGroupList as $k => $v) {
  456 + if (in_array($v['uid'], $childrenAdminIds)) continue;
  457 + $childrenAdminIds[] = $v['uid'];
  458 + }
  459 + if (!$childrenAdminIds) {
  460 +
  461 + $this->error("该组下面没有成员");
  462 + }
  463 + }
  464 + }
  465 + return $childrenAdminIds;
  466 + }
  467 +}
  1 +<?php
  2 +
  3 +namespace addons\facrm\controller\facrm;
  4 +
  5 +use addons\facrm\library\BackendApi;
  6 +use think\Db;
  7 +use think\Exception;
  8 +
  9 +
  10 +/**
  11 + * 待办事项
  12 + */
  13 +class Backlog extends BackendApi
  14 +{
  15 +
  16 + protected $model = null;
  17 + /**
  18 + * 快速搜索时执行查找的字段
  19 + */
  20 + protected $searchFields = 'customer_id,name,mobile,telephone';
  21 + protected $childrenAdminIds = [];
  22 +
  23 + public function _initialize()
  24 + {
  25 + parent::_initialize();
  26 + $this->request->filter(['strip_tags']);
  27 +
  28 + }
  29 +
  30 + /**
  31 + * 待审批列表
  32 + * @ApiParams(name="types", type="string", required=true, description="contract合同审批,receivables回款审批,invoice发票审批")
  33 + */
  34 + public function index()
  35 + {
  36 + $types = $this->request->request('types', "contract");
  37 + $filter_w = [];
  38 + if(!$model_str=\app\admin\model\facrm\Flow::getModelStr($types)){
  39 + $this->error(__("审核类型有误"));
  40 + }
  41 +
  42 + $this->model = model($model_str);
  43 + //$filter_w[]=['exp','FIND_IN_SET('. $this->auth->id.',flow_admin_id)'];
  44 + // $filter_w[]=['exp','FIND_IN_SET(2,flow_admin_id)'];
  45 + $filter_w['check_status'] = ['in', [0, 1]];
  46 +
  47 + list($where, $sort, $order, $offset, $limit) = $this->buildparams();
  48 +
  49 + $total = $this->model
  50 + ->where($where)
  51 + ->where($filter_w)
  52 + ->where('', 'exp', 'FIND_IN_SET(' . $this->auth->id . ',flow_admin_id)')
  53 + ->order($sort, $order)->fetchSql(false)
  54 + ->count();
  55 + $this->model
  56 + ->where($where)
  57 + ->where($filter_w)
  58 + ->where('', 'exp', 'FIND_IN_SET(' . $this->auth->id . ',flow_admin_id)');
  59 +
  60 + switch ($types) {
  61 + case 'receivables':
  62 + $this->model->with([
  63 + 'createUser' => function ($user) {
  64 + $user->field('id,username,nickname');
  65 + },
  66 + 'customer' => function ($customer) {
  67 + $customer->field('id,name');
  68 + },
  69 + 'contract' => function ($customer) {
  70 + $customer->field('id,name,number');
  71 + },
  72 + ]);
  73 + break;
  74 + case "contract":
  75 + $this->model->with([
  76 + 'createUser' => function ($user) {
  77 + $user->field('id,username,nickname');
  78 + },
  79 + 'orderAdmin' => function ($user) {
  80 + $user->field('id,username,nickname');
  81 + },
  82 + 'customer' => function ($customer) {
  83 + $customer->field('id,name');
  84 + },
  85 + ]);
  86 + break;
  87 + case "invoice":
  88 + $this->model->with([
  89 + 'createUser' => function ($user) {
  90 + $user->field('id,username,nickname');
  91 + },
  92 + 'contract' => function ($user) {
  93 + $user->field('id,number,name');
  94 + },
  95 + 'customer' => function ($customer) {
  96 + $customer->field('id,name');
  97 + },
  98 + ]);
  99 + break;
  100 +
  101 + }
  102 +
  103 +
  104 + $list = $this->model->order($sort, $order)
  105 + ->limit($offset, $limit)->fetchSql(false)
  106 + ->select();
  107 + $result = array("rows" => $list);
  108 +
  109 + $this->success('', $result);
  110 +
  111 + }
  112 +
  113 + /**
  114 + * 审批
  115 + * @ApiParams(name="types", type="string", required=true, description="contract合同审批,receivables回款审批")
  116 + * @ApiParams(name="id", type="int", required=true, description="对应的待审批id")
  117 + * @ApiParams(name="type", type="string", required=true, description="reject驳回,【审批的时候才需要】")
  118 + * @ApiParams(name="next_admin_id", type="string", required=true, description="下个审批人,多个逗号隔开,如果是选择审批的话,需要结束就不要传【审批的时候才需要】")
  119 + * @ApiParams(name="remark", type="string", required=true, description="备注,理由都是这个字段,【审批的时候才需要】")
  120 + * @ApiBody ("get是获取审批信息,post是审批")
  121 + */
  122 + public function verify()
  123 + {
  124 + $types = $this->request->request('types', "contract");
  125 + $ids = $this->request->request('id', "0",'intval');
  126 +
  127 + if(!$model_str=\app\admin\model\facrm\Flow::getModelStr($types)){
  128 + $this->error(__("审核类型有误"));
  129 + }
  130 +
  131 + $this->model = model($model_str);
  132 + $Log = model('\app\admin\model\facrm\flow\Log');
  133 + $row = $this->model->get($ids);
  134 + if (!$row) {
  135 + $this->error(__('No Results were found'));
  136 + }
  137 +
  138 + if ($row->check_status == [0, 1]) {
  139 + $this->error(__('不是待审核'));
  140 + }
  141 +
  142 + if (!in_array($this->auth->id, explode(',', $row->flow_admin_id))) {
  143 + $this->error(__('您没有权限审核'));
  144 + }
  145 +
  146 + $flow = model('\app\admin\model\facrm\Flow');
  147 + $flow_r = $flow->where('types', $types)->where("status", 1)
  148 + ->where('id', $row->flow_id)->find();
  149 +
  150 + if (!$flow_r) {
  151 + $row->check_status=3;
  152 + $row->flow_id=0;
  153 + $row->flow_admin_id=$row->check_admin_id="";//已审批的人清空
  154 + $row->save();
  155 + $this->error(__('审核流程不存在,已经直接驳回!'));
  156 + }
  157 +
  158 + $flow_r->step = $flow_r->step()->where('id', '>', $row->step_id)->select();
  159 + if ($this->request->isPost()) {
  160 + $type = $this->request->post("type");
  161 + $next_admin_id = $this->request->post("next_admin_id");
  162 + $log_data = array();
  163 + $log_data['flow_id'] = $row->flow_id;
  164 + $log_data['types'] = $types;
  165 + $log_data['types_id'] = $row->id;
  166 + $log_data['admin_id'] = $this->auth->id;
  167 + $log_data['nickname'] = $this->auth->nickname;
  168 + $log_data['remark'] = $this->request->post("remark", '');
  169 + $log_data['is_end'] = 0;
  170 + $log_data['status'] = 0;//未通过
  171 + Db::startTrans();
  172 + try {
  173 + //驳回
  174 + if ($type == 'reject') {
  175 + $row->check_status = 3;
  176 + $row->check_admin_id = "";//已审批的人清空
  177 + } else {
  178 + //通过
  179 + //判断是否还有下一级审批人
  180 + if ($flow_r->config == 1 && $flow_r->step) {
  181 + $flow_admin_id = $flow_r->step[0]['admin_ids'];
  182 + if ($flow_r->step[0]['type'] == 1) {
  183 + //上级领导审批
  184 + $parentIds = $this->auth->getParentAdminIds($this->auth->id);
  185 + $flow_admin_id = $parentIds ? join(',', $parentIds) : $this->auth->id;//如果没有父类就是最高级的,同时也要审核一下
  186 + }else if ($flow_r->step[0]['type']==3){
  187 + //指定部门
  188 + $auth=new \addons\facrm\library\Auth();
  189 + $groupIds=$auth->getGroupsAdminIds($flow_r->step[0]['admin_ids']);
  190 + $flow_admin_id=$groupIds?join(',',$groupIds):$this->auth->id;//如部门人自己也要审核一下
  191 +
  192 + }
  193 + $row->check_status = 1;
  194 + $row->flow_admin_id = $flow_admin_id;
  195 + $row->step_id = $flow_r->step[0]['id'];
  196 + } elseif ($flow_r->config == 0 && $next_admin_id) {
  197 + $row->check_status = 1;
  198 + $row->flow_admin_id = $next_admin_id;
  199 + } else {
  200 + $row->flow_admin_id = "";
  201 + $row->check_status = 2;
  202 + $log_data['is_end'] = 1;
  203 + }
  204 + $row->check_admin_id .= $row->check_admin_id ? ',' . $this->auth->id : $this->auth->id;
  205 + $log_data['status'] = 1;//通过
  206 + }
  207 + $row->save();
  208 + //记录审核日志
  209 + $Log->save($log_data);
  210 + hook("facrm_flow_verify", array_merge($log_data, ['id' => $Log->id, 'flow' => $flow_r]));
  211 + Db::commit();
  212 + } catch (Exception $e) {
  213 + Db::rollback();
  214 + $this->error($e->getMessage());
  215 + }
  216 + $this->success();
  217 + }
  218 + $return_data=array();
  219 + //获取审核日志
  220 + $log_list = $Log->where('flow_id', $row->flow_id)->where('types_id', $row->id)->select();
  221 + $return_data['row']=$row;
  222 + $return_data['flow']=$flow_r;
  223 + $return_data['log_list']=$log_list;
  224 +
  225 + switch ($types) {
  226 + case "contract":
  227 + $row->product;
  228 + break;
  229 + }
  230 + $this->success('',$return_data);
  231 + }
  232 +
  233 +}
  1 +<?php
  2 +
  3 +namespace addons\facrm\controller\facrm;
  4 +
  5 +use addons\facrm\library\BackendApi;
  6 +use think\Config;
  7 +use think\Db;
  8 +use think\Exception;
  9 +use think\Hook;
  10 +use think\Request;
  11 +
  12 +use app\common\exception\UploadException;
  13 +use app\common\library\Upload;
  14 +use think\Session;
  15 +
  16 +
  17 +/**
  18 + * 共有无需权限接口
  19 + * @internal
  20 + */
  21 +class Common extends BackendApi
  22 +{
  23 + protected $noNeedRight = ['*'];
  24 + protected $noNeedLogin = ['init','getNoticeTpl'];
  25 + public function _initialize()
  26 + {
  27 + parent::_initialize();
  28 + //设置过滤方法
  29 + $this->request->filter(['trim', 'strip_tags', 'htmlspecialchars']);
  30 + }
  31 +
  32 + /**
  33 + * 下拉选择
  34 + * @ApiParams(name="model", type="string", required=true, description="默认admin")
  35 + * @ApiParams(name="keyField", type="string", required=true, description="主键字段,如id")
  36 + * @ApiParams(name="type", type="string", required=false, description="可以空all代表获取全部")
  37 + */
  38 + public function selectpage(){
  39 +
  40 + $modellist=['admin'];
  41 + $model = $this->request->param('model');
  42 + if (!$this->request->request('keyField')){
  43 + $this->error("访问出错");
  44 + }
  45 + if (!in_array($model,$modellist))
  46 + $this->error("非法访问");
  47 +
  48 + $this->model = model('\app\admin\model\\'.$model);
  49 + $type = $this->request->param('type');
  50 +
  51 +
  52 + switch ($model){
  53 + case 'admin':
  54 + $this->selectpageFields =['id','concat(nickname,"(",id,")") as nickname'];
  55 + $custom=['status'=>'normal'];
  56 + if ($type != "all") {
  57 + $childrenAdminIds = $this->auth->getChildrenAdminIds(true);
  58 + $custom['id']= ['in', $childrenAdminIds];
  59 + }
  60 + //暂时处理授权审批 检索员工出错问题
  61 + if (!$this->request->request('searchField')){
  62 + $this->request->request(['searchField' => 'nickname']);
  63 + }
  64 + $this->request->request(['custom' => $custom]);
  65 + break;
  66 + }
  67 + return parent::selectpage();
  68 +
  69 + }
  70 +
  71 + /**
  72 + * 读取省市区数据,联动列表
  73 + * @ApiMethod (GET)
  74 + * @ApiParams(name="province", type="int", required=true, description="省份ID,可空。空就是获取省份列表不空就是获取城市列表")
  75 + * @ApiParams(name="city", type="int", required=true, description="城市ID,可空,空就是获取城市列表不空就是获取区域列表")
  76 + */
  77 + public function area()
  78 + {
  79 + $params = $this->request->get("row/a");
  80 + if (!empty($params)) {
  81 + $province = isset($params['province']) ? $params['province'] : '';
  82 + $city = isset($params['city']) ? $params['city'] : '';
  83 + } else {
  84 + $province = $this->request->get('province', '');
  85 + $city = $this->request->get('city', '');
  86 + }
  87 + $where = ['pid' => 0, 'level' => 1];
  88 + $provincelist = null;
  89 + if ($province !== '') {
  90 + $where['pid'] = $province;
  91 + $where['level'] = 2;
  92 + if ($city !== '') {
  93 + $where['pid'] = $city;
  94 + $where['level'] = 3;
  95 + }
  96 + }
  97 + $provincelist = Db::name('area')->where($where)->field('id as value,name')->select();
  98 + $this->success('', $provincelist);
  99 + }
  100 +
  101 + /**
  102 + * 读取所有省市区数据(用于uview select)
  103 + */
  104 + public function getAllArea(){
  105 + $lists= \addons\facrm\model\Area::getAllCacheChildren();
  106 + $this->success('',array_values($lists));
  107 + }
  108 +
  109 + /**
  110 + * [客户等级、行业类型、来源等]
  111 + */
  112 + public function baseConfig(){
  113 + $this->addon_config = get_addon_config('facrm');
  114 + $this->success('', [
  115 + 'levelList'=>$this->addon_config['level'],
  116 + 'industryList'=>$this->addon_config['industry'],
  117 + 'sourceList'=>$this->addon_config['source'],
  118 + 'accountList'=>$this->addon_config['account'],
  119 + 'recordTypeList'=>$this->addon_config['record_type'],
  120 + 'cprefix'=>$this->addon_config['cprefix'],//合同编号规则
  121 + 'rprefix'=>$this->addon_config['rprefix'],//回款编号规则
  122 + 'deal'=>$this->addon_config['deal'],//开启成交(无需走合同流程)
  123 + ]
  124 + );
  125 + }
  126 +
  127 + /**
  128 + * 基础配置
  129 + * @ApiParams (name="preview", type="int", required=false, description="只要传递说明是获取装修预览")
  130 + * @ApiReturnParams (name="login_captcha", type="string", required=false, sample="0",description="是否需要登录验证码")
  131 + * @ApiReturnParams (name="app_id", type="string", required=false, sample="",description="微信公众号ID")
  132 + * @ApiReturnParams (name="config.upload", type="array", required=false, sample="",description="上传配置,config.upload.cdnurl是图片地址cdn")
  133 + * @ApiReturnParams (name="themeconfig", type="obj", required=false, sample="",description="主题配色")
  134 + */
  135 + public function init(){
  136 + $third=get_addon_config('third');
  137 + //配置信息
  138 + $upload = Config::get('upload');
  139 +
  140 + //如果非服务端中转模式需要修改为中转
  141 + if ($upload['storage'] != 'local' && isset($upload['uploadmode']) && $upload['uploadmode'] != 'server') {
  142 + //临时修改上传模式为服务端中转
  143 + set_addon_config($upload['storage'], ["uploadmode" => "server"], false);
  144 + $upload = \app\common\model\Config::upload();
  145 + // 上传信息配置后
  146 + Hook::listen("upload_config_init", $upload);
  147 +
  148 + $upload = Config::set('upload', array_merge(Config::get('upload'), $upload));
  149 + }
  150 +
  151 + $upload['cdnurl'] = $upload['cdnurl'] ? $upload['cdnurl'] : \request()->domain();
  152 + $upload['uploadurl'] = preg_match("/^((?:[a-z]+:)?\/\/)(.*)/i", $upload['uploadurl']) ? $upload['uploadurl'] : url($upload['storage'] == 'local' ? '/api/common/upload' : $upload['uploadurl'], '', false, true);
  153 +
  154 + $config = [
  155 + 'upload' => $upload
  156 + ];
  157 + $themeconfig=array();
  158 + if ($this->request->request('preview')){
  159 + $themeconfig=Session::get("facrmpreviewtheme");//用于预览
  160 + }
  161 + $themeconfig = $themeconfig?$themeconfig:\addons\facrm\library\Theme::get();
  162 +
  163 +
  164 + if ($themeconfig){
  165 + $themeconfig=\addons\facrm\library\Theme::render($themeconfig);
  166 + }
  167 +
  168 + $payConfig=\addons\facrm\library\Order::getPayConfig();
  169 +
  170 + $this->success('', [
  171 + 'login_captcha'=>Config::get('fastadmin.login_captcha'),//是否需要验证码,
  172 + 'app_id'=>isset($third['wechat']['app_id'])?$third['wechat']['app_id']:'',//企业微信公众号
  173 + 'config'=>$config,//上传配置
  174 + 'themeconfig'=>$themeconfig,//主题设置
  175 + 'payConfig'=>($payConfig?$payConfig['values']:[]),//在线收款配置
  176 + ]
  177 + );
  178 + }
  179 +
  180 + /**
  181 + * 上传文件
  182 + * @ApiMethod (POST)
  183 + * @param File $file 文件流
  184 + */
  185 + public function upload()
  186 + {
  187 +
  188 + $upload_config=config("upload");
  189 + /**
  190 + * 兼容第三方存储,alioss,其它没有测试。
  191 + */
  192 + if ($upload_config['storage']!='local'){
  193 +
  194 + try {
  195 + Session::set("admin", $this->auth->getAdmin());//兼容需要登录的上传插件
  196 + request()->module('admin');
  197 + $objname="\\addons\\".$upload_config["storage"]."\\controller\\Index";
  198 + $uploadClass=new $objname();
  199 +
  200 + $upload_config=config("upload");
  201 + if (isset($upload_config['multipart'])&&$upload_config['multipart']){
  202 + Request::instance()->post($upload_config['multipart']);
  203 + }
  204 + $uploadClass->upload();
  205 +
  206 + }catch (Exception $e){
  207 + $this->error($e->getMessage());
  208 + }
  209 + }
  210 +
  211 + Config::set('default_return_type', 'json');
  212 + //必须设定cdnurl为空,否则cdnurl函数计算错误
  213 + Config::set('upload.cdnurl', '');
  214 + $chunkid = $this->request->post("chunkid");
  215 + if ($chunkid) {
  216 + if (!Config::get('upload.chunking')) {
  217 + $this->error(__('Chunk file disabled'));
  218 + }
  219 + $action = $this->request->post("action");
  220 + $chunkindex = $this->request->post("chunkindex/d");
  221 + $chunkcount = $this->request->post("chunkcount/d");
  222 + $filename = $this->request->post("filename");
  223 + $method = $this->request->method(true);
  224 + if ($action == 'merge') {
  225 + $attachment = null;
  226 + //合并分片文件
  227 + try {
  228 + $upload = new Upload();
  229 + $attachment = $upload->merge($chunkid, $chunkcount, $filename);
  230 + } catch (UploadException $e) {
  231 + $this->error($e->getMessage());
  232 + }
  233 + $this->success(__('上传成功'), ['url' => $attachment->url, 'fullurl' => cdnurl($attachment->url, true)]);
  234 + } elseif ($method == 'clean') {
  235 + //删除冗余的分片文件
  236 + try {
  237 + $upload = new Upload();
  238 + $upload->clean($chunkid);
  239 + } catch (UploadException $e) {
  240 + $this->error($e->getMessage());
  241 + }
  242 + $this->success();
  243 + } else {
  244 + //上传分片文件
  245 + //默认普通上传文件
  246 + $file = $this->request->file('file');
  247 + try {
  248 + $upload = new Upload($file);
  249 + $upload->chunk($chunkid, $chunkindex, $chunkcount);
  250 + } catch (UploadException $e) {
  251 + $this->error($e->getMessage());
  252 + }
  253 + $this->success();
  254 + }
  255 + } else {
  256 + $attachment = null;
  257 + //默认普通上传文件
  258 + $file = $this->request->file('file');
  259 + try {
  260 + $upload = new Upload($file);
  261 + $attachment = $upload->upload();
  262 + } catch (UploadException $e) {
  263 + $this->error($e->getMessage());
  264 + }
  265 +
  266 + $this->success(__('上传成功'), ['url' => $attachment->url, 'fullurl' => cdnurl($attachment->url, true)]);
  267 + }
  268 +
  269 + }
  270 +
  271 + /**
  272 + * 获取通知模板
  273 + * @ApiParams (name="type", type="string", required=false, sample="0",description="flow_contract,flow_invoice,clues_customer,flow_receivables,flow_business")
  274 + */
  275 + public function getNoticeTpl(){
  276 + $engine = $this->request->request('engine','Min');
  277 + $type = $this->request->request('type','');//flow_contract ,flow_receivables,clues_customer,flow_business
  278 +
  279 + //由于微信订阅通知最多只能有3条订阅 所以专门做了此修改
  280 + //审批合同相关通知,
  281 + $flow_contract=['notice_flow_contract','notice_pass_contract','notice_nopass_contract'];
  282 + //审批回款通知
  283 + $flow_receivables=['notice_pass_receivables','notice_flow_receivables','notice_nopass_receivables'];
  284 + //线索和客户
  285 + $clues_customer=['notice_flow_customer','notice_expire_ccustomer','notice_flow_clues'];
  286 + //商机
  287 + $flow_business=['notice_flow_business'];
  288 + //发票
  289 + $flow_invoice=['notice_flow_invoice_nopass','notice_invoice_opener'];
  290 +
  291 +
  292 + $data_temp = \addons\facrm\library\notice\Notice::getTempLplData();
  293 + $keys=array();
  294 + foreach ( $data_temp as $row){
  295 + if(isset($$type)&&in_array($row['key'],$$type)){
  296 + $keys[]=$row['key'].$engine;
  297 + }
  298 + }
  299 + $lists=\app\admin\model\facrm\Setting::where('key','in',$keys)->where('status',1)->select();
  300 + $this->success('',$lists);
  301 + }
  302 +
  303 + /**
  304 + * 检查权限
  305 + */
  306 + public function authcheck(){
  307 + $auth = $this->request->post('auth');
  308 + $this->success('',($auth&&$this->auth->check($auth))?1:0);
  309 + }
  310 +
  311 + /**
  312 + * 腾讯地图经纬度返回地址
  313 + * @ApiParams (name="lat", type="string", required=true, description="lat<纬度>,lng<经度>")
  314 + * @ApiParams (name="lng", type="string", required=true, description="lat<纬度>,lng<经度>")
  315 + * @ApiReturnParams (name="address", type="string", required=true, sample="0",description="定位地址")
  316 + */
  317 + public function geocoder(){
  318 + $url="https://apis.map.qq.com/ws/geocoder/v1/";
  319 + $addon_config = get_addon_config('facrm');
  320 +
  321 + if (!isset($addon_config['map_qq_key'])||!$addon_config['map_qq_key']){
  322 + $this->error('腾讯地图KEY未配置');
  323 + }
  324 +
  325 +
  326 + //lat<纬度>,lng<经度>
  327 + $lat=$this->request->get('lat');
  328 + $lng=$this->request->get('lng');
  329 + //location= 39.984154,116.307490
  330 + if (!$lat||!$lng){
  331 + $this->error("经纬度有误");
  332 + }
  333 +
  334 + $params=['location'=>"{$lat},{$lng}",'key'=>$addon_config['map_qq_key']];
  335 +
  336 + $cachekey=md5("{$lat},{$lng}");
  337 + $result=cache($cachekey);
  338 + if (!$result){
  339 + //缓存没有才去接口那里获取
  340 + $result=\fast\Http::get($url,$params);
  341 + $result=json_decode($result,true);
  342 + if (!$result||!isset($result['status'])||$result['status']!=0||!isset($result['result']['address'])){
  343 + $this->error('获取地址错误');
  344 + }
  345 + cache($cachekey,$result,86400*30);
  346 + }
  347 +
  348 + $this->success('',['address'=>$result['result']['address']]);
  349 + }
  350 +
  351 +
  352 +}
  1 +<?php
  2 +
  3 +namespace addons\facrm\controller\facrm;
  4 +
  5 +use addons\facrm\library\BackendApi;
  6 +use app\admin\model\AuthGroup;
  7 +use app\admin\model\facrm\Contract;
  8 +use app\admin\model\facrm\contract\Receivables;
  9 +use addons\facrm\model\Admin as AdminModel;
  10 +use fast\Tree;
  11 +
  12 +/**
  13 + * 首页
  14 + * @icon fa fa-dashboard
  15 + * @remark 用于展示当前系统中的统计数据、统计报表及重要实时数据
  16 + */
  17 +class Dashboard extends BackendApi
  18 +{
  19 +
  20 + protected $groupList = [];
  21 + protected $groupdata = [];
  22 + protected $noNeedRight = ['getAchievement','getNotice'];
  23 +
  24 + public function _initialize()
  25 + {
  26 + parent::_initialize();
  27 + $this->model = new AdminModel();
  28 + $this->childrenAdminIds = $this->auth->getChildrenAdminIds(true);
  29 + $this->childrenGroupIds = $this->auth->getChildrenGroupIds(true);
  30 +
  31 + $this->groupList = collection(AuthGroup::where('id', 'in', $this->childrenGroupIds)->select())->toArray();
  32 + Tree::instance()->init($this->groupList);
  33 + if ($this->auth->isSuperAdmin()) {
  34 + $result = Tree::instance()->getTreeList(Tree::instance()->getTreeArray(0));
  35 + foreach ($result as $k => $v) {
  36 + $this->groupdata[$v['id']] = $v['name'];
  37 + }
  38 + } else {
  39 + $result = [];
  40 + $groups = $this->auth->getGroups();
  41 + foreach ($groups as $m => $n) {
  42 + $childlist = Tree::instance()->getTreeList(Tree::instance()->getTreeArray($n['id']));
  43 + $temp = [];
  44 + foreach ($childlist as $k => $v) {
  45 + $temp[$v['id']] = $v['name'];
  46 + }
  47 + $result[__($n['name'])] = $temp;
  48 + }
  49 + $this->groupdata = $result;
  50 + }
  51 + }
  52 +
  53 + /**
  54 + * 首页数据
  55 + * @ApiMethod (POST|GET)
  56 + * @ApiParams(name="type", type="string", required=true, description="oneself:自己,team团队")
  57 + * @ApiReturnParams (name="communicate", type="int", required=false, sample="0",description="待跟进客户")
  58 + * @ApiReturnParams (name="lose_num", type="int", required=false, sample="0",description="将过期客户")
  59 + * @ApiReturnParams (name="business", type="int", required=false, sample="0",description="待跟进商机")
  60 + * @ApiReturnParams (name="contract_expire", type="int", required=false, sample="0",description="过期合同")
  61 + * @ApiReturnParams (name="contract_return", type="int", required=false, sample="0",description="待回款合同")
  62 + * @ApiReturnParams (name="contract_flow", type="int", required=false, sample="0",description="待审核合同")
  63 + * @ApiReturnParams (name="receivables_flow", type="int", required=false, sample="0",description="待审核回款")
  64 + * @ApiReturnParams (name="clues_num", type="int", required=false, sample="0",description="待跟进线索")
  65 + */
  66 + public function index()
  67 + {
  68 + $year = $this->request->param('year', date("Y", time()), 'intval');
  69 + $month = $this->request->param('month', intval(date("m", time())), 'intval');
  70 + $config = $this->request->param('config', 1, 'intval');//$config 1=>'合同金额',2=>'回款金额'
  71 + $group_id = $this->request->param('group_id', 0, 'intval');//部门
  72 + $admin_id = $this->request->param('admin_id', 0, 'intval');//员工
  73 + $type = $this->request->param('type', 'oneself');
  74 + $achievementModel = new \app\admin\model\facrm\Achievement();
  75 +
  76 +
  77 + //当天开始时间
  78 + $start_time = strtotime(date("Y-m-d", time()));
  79 + //当天结束之间
  80 + $end_time = $start_time + 60 * 60 * 24;
  81 +
  82 + switch ($type) {
  83 + case 'oneself':
  84 + $return_data=$this->getNotice(true);
  85 + if (!$achievement = $achievementModel->achievement($config, $year, $month, 3, $this->auth->id, $this->auth->id)) {
  86 + $this->error($achievementModel->getError());
  87 + }
  88 + $return_data['achievement'] = $achievement;
  89 + //自己的end
  90 + break;
  91 + case 'team':
  92 + $return_data=$this->getNotice(true);
  93 + if ($group_id && !$admin_id) {
  94 + //如果有选团队并且没有选员工就是团队业绩
  95 + Tree::instance()->init($this->groupList);
  96 + $this->childrenGroupIds = Tree::instance()->getChildrenIds($group_id, true);
  97 +
  98 + $authGroupList = \app\admin\model\AuthGroupAccess::
  99 + field('uid,group_id')
  100 + ->where('group_id', 'in', $this->childrenGroupIds)
  101 + ->select();
  102 + $this->childrenAdminIds=[];
  103 + foreach ($authGroupList as $k => $v) {
  104 + if ($this->childrenAdminIds && in_array($v['uid'], $this->childrenAdminIds)) continue;
  105 + $this->childrenAdminIds[] = $v['uid'];
  106 + }
  107 +
  108 + } else if($admin_id) {
  109 + $this->childrenAdminIds = $admin_id ;
  110 + $this->childrenGroupIds=$admin_id;
  111 + }
  112 +
  113 + $team_achievement = $achievementModel->achievement($config, $year, $month, 2, $this->childrenGroupIds, $this->childrenAdminIds);
  114 + $team_achievement['config']=$config;
  115 + $return_data =array_merge($return_data,
  116 + [
  117 + 'achievement' => $team_achievement,
  118 + ]) ;
  119 + break;
  120 + //团队的end
  121 + default:
  122 + $this->error(__("访问有误"));
  123 + }
  124 +
  125 + $this->success('', $return_data);
  126 +
  127 +
  128 + }
  129 +
  130 + /**
  131 + * 消息和提醒
  132 + * @ApiParams(name="type", type="string", required=true, description="oneself:自己,team团队")
  133 + * @ApiReturnParams (name="communicate", type="int", required=false, sample="0",description="待跟进客户")
  134 + * @ApiReturnParams (name="lose_num", type="int", required=false, sample="0",description="将过期客户")
  135 + * @ApiReturnParams (name="business", type="int", required=false, sample="0",description="待跟进商机")
  136 + * @ApiReturnParams (name="contract_expire", type="int", required=false, sample="0",description="过期合同")
  137 + * @ApiReturnParams (name="contract_return", type="int", required=false, sample="0",description="待回款合同")
  138 + * @ApiReturnParams (name="contract_flow", type="int", required=false, sample="0",description="待审核合同")
  139 + * @ApiReturnParams (name="receivables_flow", type="int", required=false, sample="0",description="待审核回款")
  140 + * @ApiReturnParams (name="clues_num", type="int", required=false, sample="0",description="待跟进线索")
  141 + * @ApiReturnParams (name="invoice_flow", type="int", required=false, sample="0",description="待审批发票")
  142 + * @ApiReturnParams (name="invoice_opener", type="int", required=false, sample="0",description="待开具发票")
  143 + */
  144 + public function getNotice($isReturn=false){
  145 + $type = $this->request->param('type', 'oneself');
  146 + $businessModel = model('\app\admin\model\facrm\Business');
  147 + $customerModel = model('\app\admin\model\facrm\Customer');
  148 + $cluesModel = model('\app\admin\model\facrm\Clues');
  149 + $contractModel = model('\app\admin\model\facrm\Contract');
  150 + $receivablesModel = model('\app\admin\model\facrm\contract\Receivables');
  151 + $invoiceModel = model('\app\admin\model\facrm\Invoice');
  152 + //当天开始时间
  153 + $start_time = strtotime(date("Y-m-d", time()));
  154 + //当天结束之间
  155 + $end_time = $start_time + 60 * 60 * 24;
  156 +
  157 + //更新到期回款计划
  158 + $planModel =new \app\admin\model\facrm\contract\Plan();
  159 + $planModel->where('plan_time', '<', time())->where('status',0)->update(['status'=>'-1']);
  160 + $plan=0;
  161 + if ($this->auth->check('facrm/contract/plan/index')){
  162 + $time=time();
  163 + $planModel->with(['contract']);
  164 + if (!$this->auth->isSuperAdmin() && !$this->auth->check('facrm/contract/index/index')) {
  165 + $planModel->where('contract.order_admin_id', 'in', $this->auth->getChildrenAdminIds(true));
  166 + }
  167 + $plan=$planModel->where('plan_time','<',\think\Db::raw(" ({$time}+(`remind_day`*86400))"))->where('status','neq',2)
  168 + ->fetchSql(false)->count();
  169 + }
  170 +
  171 + switch ($type) {
  172 + case 'oneself':
  173 + //自己的start
  174 + $this->childrenAdminIds = $this->auth->getChildrenAdminIds(true);
  175 + $filter_w['owner_user_id'] = $this->auth->id;
  176 +
  177 + //需要联系客户
  178 + $communicate = $customerModel->where('next_time', 'between', [1, $end_time])->where($filter_w)->count();
  179 +
  180 + //待跟进线索
  181 + $clues_num = $cluesModel->where('next_time', 'between', [1, $end_time])->where($filter_w)->count();
  182 +
  183 + //将要过期的客户
  184 + $lose_num = count($customerModel->getLose($this->auth->id));
  185 +
  186 + $business = $businessModel->where('next_time', 'between', [1, $end_time])->where($filter_w)->count();
  187 + //是否有合同权限
  188 + $contract_return = $contract_expire = 0;
  189 + if ($this->auth->check('facrm/contract/index')) {
  190 + $filter_w['check_status'] = 2;
  191 + //快过期和过期合同
  192 + $contract_expire = $contractModel->where('end_time', 'between', [1, $end_time + (30 * 86400)])->where('expire_handle', 0)->where($filter_w)->count();
  193 + //待回款合同
  194 + $contract_return = $contractModel->where("money", "exp", ">return_money")->where($filter_w)->count();
  195 + }
  196 + //合同审核和回款审核
  197 + $contract_flow = $contractModel->where('find_in_set(:id,flow_admin_id)', ['id' => $this->auth->id])->where('check_status', 'in', [0, 1])->count();
  198 + $receivables_flow = $receivablesModel->where('find_in_set(:id,flow_admin_id)', ['id' => $this->auth->id])->where('check_status', 'in', [0, 1])->count();
  199 +
  200 + //待审发票
  201 + $invoice_flow=$invoiceModel->where('find_in_set(:id,flow_admin_id)', ['id' => $this->auth->id])->where('check_status', 'in', [0, 1])->count();
  202 + //待开具发票
  203 + $invoice_opener=$invoiceModel->where('status', 'in', [0, 1])->where('check_status', 2)->count();
  204 +
  205 +
  206 +
  207 +
  208 +
  209 + $return_data = [
  210 + 'communicate' => $communicate,//待跟进客户
  211 + 'lose_num' => $lose_num, //将过期客户
  212 + 'business' => $business,//待跟进商机
  213 + 'contract_expire' => $contract_expire,//过期合同
  214 + 'contract_return' => $contract_return,//待回款合同
  215 + 'contract_flow' => $contract_flow,//待合同审核
  216 + 'receivables_flow' => $receivables_flow,//待回款审核
  217 + 'clues_num'=>$clues_num,//待跟进线索
  218 + 'invoice_flow'=> $invoice_flow,
  219 + 'invoice_opener'=>$invoice_opener,
  220 + 'plan'=>$plan
  221 +
  222 + ];
  223 + //自己的end
  224 + break;
  225 + case 'team':
  226 + $this->childrenAdminIds = $this->auth->getChildrenAdminIds(true);
  227 + //团队的
  228 + $filter_w = array();
  229 + $filter_w['owner_user_id'] = ['in', $this->childrenAdminIds];
  230 + //需要联系客户
  231 + $team_communicate = $customerModel->where('next_time', 'between', [1, $end_time])->where($filter_w)->count();
  232 +
  233 + //待跟进线索
  234 + $clues_num = $cluesModel->where('next_time', 'between', [1, $end_time])->where($filter_w)->count();
  235 +
  236 + //将要过期的用户
  237 + $team_lose_num = count($customerModel->getLose($this->childrenAdminIds));
  238 +
  239 + $team_business = $businessModel->where('next_time', 'between', [1, $end_time])->where($filter_w)->count();
  240 + //是否有合同权限
  241 + $team_contract_return = $team_contract_expire = 0;
  242 + if ($this->auth->check('facrm/contract/index')) {
  243 + $filter_w['check_status'] = 2;
  244 + //快过期和过期合同
  245 + $team_contract_expire = $contractModel->where('end_time', 'between', [1, $end_time + (30 * 86400)])->where('expire_handle', 0)->where($filter_w)->count();
  246 + //待回款合同
  247 + $team_contract_return = $contractModel->where("money", "exp", ">return_money")->where($filter_w)->count();
  248 + }
  249 +
  250 + $return_data = [
  251 + 'communicate' => $team_communicate,
  252 + 'lose_num' => $team_lose_num,
  253 + 'clues_num'=>$clues_num,//待跟进线索
  254 + 'business' => $team_business,
  255 + 'contract_expire' => $team_contract_expire,
  256 + 'contract_return' => $team_contract_return,
  257 + 'plan'=>$plan
  258 + ];
  259 + break;
  260 + //团队的end
  261 + default:
  262 + $this->error(__("访问有误"));
  263 + }
  264 + if ($isReturn){
  265 + return $return_data;
  266 + }
  267 +
  268 + $this->success('', $return_data);
  269 +
  270 + }
  271 +
  272 +
  273 +
  274 +}
  1 +<?php
  2 +
  3 +namespace addons\facrm\controller\facrm;
  4 +
  5 +use addons\facrm\library\BackendApi;
  6 +use app\common\model\Config;
  7 +use fast\Tree;
  8 +use think\Db;
  9 +
  10 +/**
  11 + * 自定义字段
  12 + *
  13 + * @icon fa fa-circle-o
  14 + */
  15 +class Fields extends BackendApi
  16 +{
  17 +
  18 + /**
  19 + * Fields模型对象
  20 + */
  21 + protected $model = null;
  22 + protected $modelValidate = true;
  23 + protected $modelSceneValidate = true;
  24 + protected $noNeedRight = ['get_fields','selectpage'];
  25 + private $modelList = array();
  26 +
  27 + public function _initialize()
  28 + {
  29 + parent::_initialize();
  30 + $this->model = new \app\admin\model\facrm\Fields;
  31 + $this->modelList = [
  32 + 'customer' => __('客户'),
  33 + 'customer_contacts' => __('联系人'),
  34 + 'contract'=>__("合同"),
  35 + 'contract_receivables'=>__("回款"),
  36 + 'business'=>__("商机"),
  37 + 'clues'=>__("线索"),
  38 + ];
  39 + $this->request->filter(['strip_tags']);
  40 + }
  41 + /**
  42 + * 获取自定义字段
  43 + * @ApiParams(name="source", type="string", required=true, description="customer:客户,customer_contacts联系人")
  44 + * @ApiParams(name="id", type="int", required=true, description="对应数据的id")
  45 + */
  46 + public function get_fields()
  47 + {
  48 + $source=$this->request->request('source','');
  49 +
  50 + if (!in_array($source, array_keys($this->modelList))) {
  51 + $this->error(__("未开放信息"));
  52 + }
  53 + $source=ucfirst($source);
  54 +
  55 + $id = $this->request->param('id', 0, 'intval');
  56 + switch ($source) {
  57 + case 'Contract_receivables':
  58 + $this->model = model('\app\admin\model\facrm\contract\Receivables');
  59 + break;
  60 + case 'Customer_contacts':
  61 + $this->model = model('\app\admin\model\facrm\customer\Contacts');
  62 + break;
  63 + default:
  64 + $this->model = model("\\app\\admin\\model\\facrm\\{$source}");
  65 + }
  66 +
  67 + $values = [];
  68 + if ($id > 0) {
  69 + $values = $this->model->find($id);
  70 + }
  71 + $fields = \app\admin\model\facrm\Fields::getCustomFields($source, $values);
  72 + if ($values&&$fields){
  73 + foreach ($fields as &$row){
  74 + if (isset($values[$row['name']]))$row['value']=$values[$row['name']];
  75 + }
  76 + }
  77 +
  78 + $this->success('',array('fields'=> $fields));
  79 +
  80 + }
  81 +
  82 + /**
  83 + * 关联表联动
  84 + * @internal
  85 + */
  86 + public function selectpage()
  87 + {
  88 + $id = $this->request->get("id/d", 0);
  89 + $fieldInfo = $this->model::get($id);
  90 + if (!$fieldInfo) {
  91 + $this->error("未找到指定字段");
  92 + }
  93 + $setting = $fieldInfo['setting'];
  94 + if (!$setting || !isset($setting['table'])) {
  95 + $this->error("字段配置不正确");
  96 + }
  97 + //搜索关键词,客户端输入以空格分开,这里接收为数组
  98 + $word = (array)$this->request->request("q_word/a");
  99 + //当前页
  100 + $page = $this->request->request("pageNumber");
  101 + //分页大小
  102 + $pagesize = $this->request->request("pageSize");
  103 + //搜索条件
  104 + $andor = $this->request->request("andOr", "and", "strtoupper");
  105 + //排序方式
  106 + $orderby = (array)$this->request->request("orderBy/a");
  107 + //显示的字段
  108 + //$field = $this->request->request("showField");
  109 + $field = $setting['field'];
  110 + //主键
  111 + //$primarykey = $this->request->request("keyField");
  112 + $primarykey = $setting['primarykey'];
  113 + //主键值
  114 + $primaryvalue = $this->request->request("keyValue");
  115 + //搜索字段
  116 + $searchfield = (array)$this->request->request("searchField/a");
  117 + $searchfield = [$field, $primarykey];
  118 + //自定义搜索条件
  119 + $custom = (array)$this->request->request("custom/a");
  120 + $custom = isset($setting['conditions']) ? (array)json_decode($setting['conditions'], true) : [];
  121 + $custom = array_filter($custom);
  122 +
  123 + $admin_id = session('admin.id') ?: 0;
  124 + $user_id = $this->auth->id ?: 0;
  125 + //如果是管理员需要移除user_id筛选,否则会导致管理员无法筛选列表信息
  126 + $admin = $this->request->request("admin/d");
  127 + if ($admin_id && $admin) {
  128 + unset($custom['user_id']);
  129 + } else {
  130 + //如果不是管理员则需要判断是否开放相应的投稿字段
  131 + if (!in_array($fieldInfo['source'], array_keys($this->modelList))) {
  132 + $this->error("未开放栏目信息");
  133 + }
  134 + }
  135 +
  136 + //是否返回树形结构
  137 + $istree = $this->request->request("isTree", 0);
  138 + $ishtml = $this->request->request("isHtml", 0);
  139 + if ($istree) {
  140 + $word = [];
  141 + $pagesize = 99999;
  142 + }
  143 + $order = [];
  144 + foreach ($orderby as $k => $v) {
  145 + $order[$v[0]] = $v[1];
  146 + }
  147 + $field = $field ? $field : 'name';
  148 +
  149 + //如果有primaryvalue,说明当前是初始化传值
  150 + if ($primaryvalue !== null) {
  151 + $where = [$primarykey => ['in', $primaryvalue]];
  152 + $where = function ($query) use ($primaryvalue, $custom, $admin_id, $user_id) {
  153 + $query->where('id', 'in', $primaryvalue);
  154 + if ($custom && is_array($custom)) {
  155 + //替换暂位符
  156 + $search = ["{admin_id}", "{user_id}"];
  157 + $replace = [$admin_id, $user_id];
  158 + foreach ($custom as $k => $v) {
  159 + if (is_array($v) && 2 == count($v)) {
  160 + $query->where($k, trim($v[0]), str_replace($search, $replace, $v[1]));
  161 + } else {
  162 + $query->where($k, '=', str_replace($search, $replace, $v));
  163 + }
  164 + }
  165 + }
  166 + };
  167 + $pagesize = 99999;
  168 + } else {
  169 + $where = function ($query) use ($word, $andor, $field, $searchfield, $custom, $admin_id, $user_id) {
  170 + $logic = $andor == 'AND' ? '&' : '|';
  171 + $searchfield = is_array($searchfield) ? implode($logic, $searchfield) : $searchfield;
  172 + $word = array_filter($word);
  173 + if ($word) {
  174 + foreach ($word as $k => $v) {
  175 + $query->where(str_replace(',', $logic, $searchfield), "like", "%{$v}%");
  176 + }
  177 + }
  178 + if ($custom && is_array($custom)) {
  179 + //替换暂位符
  180 + $search = ["{admin_id}", "{user_id}"];
  181 + $replace = [$admin_id, $user_id];
  182 + foreach ($custom as $k => $v) {
  183 + if (is_array($v) && 2 == count($v)) {
  184 + $query->where($k, trim($v[0]), str_replace($search, $replace, $v[1]));
  185 + } else {
  186 + $query->where($k, '=', str_replace($search, $replace, $v));
  187 + }
  188 + }
  189 + }
  190 + };
  191 + }
  192 + $list = [];
  193 + $total = Db::table($setting['table'])->where($where)->count();
  194 + if ($total > 0) {
  195 + $datalist = Db::table($setting['table'])->where($where)
  196 + ->order($order)
  197 + ->page($page, $pagesize)
  198 + ->field($primarykey . "," . $field . ($istree ? ",pid" : ""))
  199 + ->select();
  200 + foreach ($datalist as $index => &$item) {
  201 + unset($item['password'], $item['salt']);
  202 + $list[] = [
  203 + $primarykey => isset($item[$primarykey]) ? $item[$primarykey] : '',
  204 + $field => isset($item[$field]) ? $item[$field] : '',
  205 + 'pid' => isset($item['pid']) ? $item['pid'] : 0
  206 + ];
  207 + }
  208 + if ($istree && !$primaryvalue) {
  209 + $tree = Tree::instance();
  210 + $tree->init($list, 'pid');
  211 + $list = $tree->getTreeList($tree->getTreeArray(0), $field);
  212 + if (!$ishtml) {
  213 + foreach ($list as &$item) {
  214 + $item = str_replace('&nbsp;', ' ', $item);
  215 + }
  216 + unset($item);
  217 + }
  218 + }
  219 + }
  220 + //这里一定要返回有list这个字段,total是可选的,如果total<=list的数量,则会隐藏分页按钮
  221 + $this->success('', ['list' => $list, 'total' => $total]);
  222 + }
  223 +
  224 +
  225 +
  226 +}
  1 +<?php
  2 +
  3 +namespace addons\facrm\controller\facrm;
  4 +
  5 +
  6 +use addons\facrm\library\BackendApi;
  7 +use think\Db;
  8 +use think\Exception;
  9 +use think\exception\PDOException;
  10 +use think\exception\ValidateException;
  11 +
  12 +
  13 +
  14 +/**
  15 + * 发票管理
  16 + */
  17 +class Invoice extends BackendApi
  18 +{
  19 +
  20 + protected $model = null;
  21 + /**
  22 + * 快速搜索时执行查找的字段
  23 + */
  24 + protected $searchFields = 'invoice_name';
  25 + protected $childrenAdminIds = [];
  26 + protected $noNeedRight = [ 'selectpage','history'];
  27 + protected $tpl_key="invoice_tpl";
  28 +
  29 + public function _initialize()
  30 + {
  31 + parent::_initialize();
  32 + $this->model = model('\app\admin\model\facrm\Invoice');
  33 + //设置过滤方法
  34 + $this->request->filter(['trim', 'strip_tags', 'htmlspecialchars']);
  35 + }
  36 +
  37 + /**
  38 + * 我申请的发票
  39 + * @ApiSummary (返回值里面有scene_list,如果有all全部发票就有权限)
  40 + * @ApiMethod (GET)
  41 + * @ApiReturnParams (name="scene_list", type="array", required=true, sample="0")
  42 + * @ApiBody ("filter里面的scene_id是必传的,参考PC[owner我申请的发票,branch下属申请的发票all全部申请的发票]")
  43 + */
  44 + public function index($scene_list=array())
  45 + {
  46 + //设置过滤方法
  47 + $this->request->filter(['strip_tags']);
  48 + $scene_list = $scene_list?$scene_list:['owner'=>'我申','branch'=>'下属'];
  49 + $customer_id = $this->request->param("customer_id");
  50 + $filter_w = $this->getFilterWhere($scene_list);
  51 +
  52 + if ($customer_id) {
  53 + $filter_w['customer_id'] = $customer_id;
  54 + }
  55 + //如果发送的来源是Selectpage,则转发到Selectpage
  56 + if ($this->request->request('keyField')) {
  57 + $this->request->request(['custom' => $filter_w]);
  58 + return $this->selectpage();
  59 + }
  60 +
  61 + list($where, $sort, $order, $offset, $limit) = $this->buildparams();
  62 + $total = $this->model
  63 + ->where($where)
  64 + ->where($filter_w)
  65 + ->with([
  66 + ])
  67 + ->order($sort, $order)->fetchSql(false)
  68 + ->count();
  69 + $list = $this->model
  70 + ->where($where)
  71 + ->where($filter_w)
  72 + ->with([
  73 + 'createUser' => function ($user) {
  74 + $user->field('id,username,nickname');
  75 + },
  76 + 'contract' => function ($user) {
  77 + $user->field('id,name,number');
  78 + },
  79 + 'customer' => function ($customer) {
  80 + $customer->field('id,name');
  81 + },
  82 + ])
  83 + ->order($sort, $order)
  84 + ->limit($offset, $limit)->fetchSql(false)
  85 + ->select();
  86 + $scene_list=['owner'=>'我申发票'];
  87 +
  88 + if ($this->auth->check('facrm/invoice/index/lists')){
  89 + $scene_list['all']="全部发票";
  90 + }
  91 + if ($this->auth->check('facrm/invoice/index/opener')){
  92 + $scene_list['opener']="财务待开";
  93 + }
  94 + $this->success('',array( "total" => $total,"rows" => $list,'scene_list'=>$scene_list));
  95 +
  96 + }
  97 +
  98 +
  99 + /**
  100 + * 全部发票
  101 + * @ApiMethod (GET)
  102 + * @ApiBody ("filter里面的scene_id是必须是all")
  103 + */
  104 + public function lists(){
  105 + return $this->index(['all'=>'全部发票']);
  106 + }
  107 + /**
  108 + * 申请
  109 + * @ApiMethod (GET)
  110 + * @return mixed
  111 + * @ApiBody ("GET获取参数,【flow审核配置,setting发票配置】,POST提交申请,参数参考PC")
  112 + */
  113 + public function add()
  114 + {
  115 +
  116 + $flow = model('\app\admin\model\facrm\Flow');
  117 + $flow_r =\app\admin\model\facrm\Flow::getFlow($this->auth->id, 'invoice');
  118 +
  119 + if (!$flow_r) $this->error(__('审批配置不存在,请先配置'));
  120 + //获取发票配置
  121 + $settingModel = new \app\admin\model\facrm\Setting();
  122 + $setting = $settingModel->where('key',$this->tpl_key)->where('status',1)->value('values');
  123 + if (!$setting){
  124 + $this->error(__('发票开具申请未开启'));
  125 + }
  126 +
  127 + if ($this->request->isPost()) {
  128 + $params = $this->request->post("row/a");
  129 + if (!isset($params['contract_id']))
  130 + $this->error(__('请选择合同'));
  131 +
  132 +
  133 + $contractModel = new \app\admin\model\facrm\Contract();
  134 + //获取合同情况
  135 + $contract_r = $contractModel->get($params['contract_id']);
  136 + if (!$contract_r)
  137 + $this->error(__('没有找到合同'));
  138 +
  139 +
  140 + if ($contract_r['check_status']!=2)
  141 + $this->error(__('合同未通过审核不能申请发票'));
  142 +
  143 +
  144 + if ($this->model->where('contract_id',$contract_r['id'])->where(function ($query){
  145 + $query->where('check_status','in',[0,1])->whereOr('status','in',[0,1]);
  146 + })->count()){
  147 + $this->error(__("该合同还有未审批或未开票的申请"));
  148 + }
  149 + //判断开票金额,不能大于合同金额且不能大于回款金额
  150 + $money=bcadd($params['money'],$contract_r['invoice_money'],2);
  151 +
  152 + if ($money>$contract_r['money']&&$money>$contract_r['return_money']){
  153 + $this->error(__("累计开票金额,不能大于合同金额且不能大于回款金额"));
  154 + }
  155 +
  156 + $params = array_merge($params, [
  157 + 'create_admin_id' => $this->auth->id,
  158 + 'invoice_admin_id' => 0,
  159 + 'customer_id'=>$contract_r['customer_id'],
  160 + 'status' =>0,
  161 + 'check_status' => 0,
  162 + ]);
  163 +
  164 + $result = false;
  165 + $invoice_id = 0;
  166 + Db::startTrans();
  167 + try {
  168 + $name = str_replace("\\model\\", "\\validate\\", get_class($this->model));
  169 + $this->model->validateFailException(true)->validate( $name . '.add');
  170 + $result = $this->model->allowField(true)->save($params);
  171 + $invoice_id = $this->model->id;
  172 + Db::commit();
  173 + } catch (ValidateException $e) {
  174 + Db::rollback();
  175 + $this->error($e->getMessage());
  176 + } catch (PDOException $e) {
  177 + Db::rollback();
  178 + $this->error($e->getMessage());
  179 + } catch (Exception $e) {
  180 + Db::rollback();
  181 + $this->error($e->getMessage());
  182 + }
  183 + if ($result !== false) {
  184 + //处理合同审核流程
  185 + $flow->addFlow($invoice_id, $this->auth->id, 'invoice', $flow_r);
  186 + hook("facrm_invoice_add", array_merge($params, ['id' => $invoice_id]));
  187 + $this->success();
  188 + } else {
  189 + $this->error(__('No rows were inserted'));
  190 + }
  191 + }
  192 +
  193 +
  194 + $setting=json_decode($setting,true);
  195 + if ($flow_r->config==1)//如果固定审批
  196 + $flow_r['flow_admin_id']=$flow->getAdminIds($flow_r,$this->auth->id);
  197 +
  198 + $this->success('',array('flow'=>$flow_r,'setting'=>$setting));
  199 + }
  200 + /**
  201 + * 获取客户历史发票资料
  202 + * @ApiSummary (用于自动完成发票信息填写)
  203 + * @ApiParams (name="contract_id", type="integer", required=true, description="合同ID")
  204 + * @return mixed
  205 + */
  206 + public function history($contract_id=NULL){
  207 + $contract_id = $this->request->request('contract_id', '', 'intval');
  208 + if (!$this->auth->check('facrm/invoice/add')){
  209 + $this->error(__('You have no permission'));
  210 + }
  211 + if (!$contract_id) {
  212 + $this->error(__('No Results were found'));
  213 + }
  214 + //获取合同信息
  215 + $contractModel= new \app\admin\model\facrm\Contract();
  216 + $contract=$contractModel->where('id',$contract_id)->find();
  217 + if (!$contract){
  218 + $this->error(__('合同信息不存在'));
  219 + }
  220 +
  221 + $invoice =$this->model->where('customer_id',$contract->customer_id)->orderRaw("field(check_status,'2','1','0','3')")->order('id desc')->fetchSql(false)->find();
  222 +
  223 + if ($invoice) {
  224 + $invoice->hidden(['files']);
  225 + }
  226 +
  227 + $this->success('',[
  228 + 'contract'=>[
  229 + 'money'=>$contract['money'],
  230 + 'return_money'=>$contract['money'],
  231 + 'invoice_money'=>$contract['invoice_money']
  232 + ],
  233 + 'invoice'=>$invoice
  234 + ]);
  235 +
  236 + }
  237 +
  238 +
  239 +
  240 +
  241 +
  242 +
  243 + /**
  244 + * 修改
  245 + * @ApiSummary (用于自动完成发票信息填写)
  246 + * @ApiParams (name="ids", type="integer", required=true, description="ID")
  247 + * @ApiBody ("GET获取参数,【flow审核配置,row发票数据】,POST提交申请,参数参考PC")
  248 + */
  249 + public function edit($ids = NULL)
  250 + {
  251 + $ids = $this->request->request('ids', '', 'intval');
  252 + $row = $this->model->get($ids);
  253 + if (!$row) {
  254 + $this->error(__('No Results were found'));
  255 + }
  256 +
  257 + $flow = model('\app\admin\model\facrm\Flow');
  258 +
  259 + if ($row->flow_id){
  260 + $flow->where('id',$row->flow_id);//处理流程被删除
  261 + }
  262 +
  263 + $flow_r = $flow->where('types', 'invoice')->where("status", 1)->find();
  264 + if ($this->request->isPost()) {
  265 +
  266 + $params = $this->request->post("row/a");
  267 + if ($params) {
  268 + if ($row->check_status == 2) {
  269 + //审核通过的只能修改负责人和备注、处理情况、续费单价
  270 + $params_update =array();
  271 + isset($params['remarks'])?$params_update['remarks']=$params['remarks']:'';
  272 + $result = $row->allowField(true)->save($params_update);
  273 + $this->success();
  274 + }
  275 + /* elseif ($row->check_status == 1) {
  276 + //审核中的不能修改
  277 + $this->error(__("审核中的不能修改,请先驳回再修改"));
  278 + }*/
  279 + $params['check_status'] = 0;//重新改成待审核状态
  280 +
  281 + //获取合同情况
  282 + $contract_r = $row->contract;
  283 + if (!$contract_r)
  284 + $this->error(__('没有找到合同'));
  285 +
  286 +
  287 + if ($contract_r['check_status']!=2)
  288 + $this->error(__('合同未通过审核不能申请发票'));
  289 +
  290 + //判断开票金额,不能大于合同金额且不能大于回款金额
  291 + $money=bcadd($params['money'],$contract_r['invoice_money'],2);
  292 +
  293 + if ($money>$contract_r['money']&&$money>$contract_r['return_money']){
  294 + $this->error(__("累计开票金额,不能大于合同金额且不能大于回款金额"));
  295 + }
  296 +
  297 +
  298 + $result = false;
  299 + Db::startTrans();
  300 + try {
  301 + //是否采用模型验证
  302 + $name = str_replace("\\model\\", "\\validate\\", get_class($this->model));
  303 + $row->validateFailException(true)->validate($name . '.edit');
  304 + $invoice_id = $row->id;
  305 + $result = $row->allowField(true)->save($params);
  306 + if ($result) {
  307 +
  308 + }
  309 + Db::commit();
  310 + } catch (ValidateException $e) {
  311 + Db::rollback();
  312 + $this->error($e->getMessage());
  313 + } catch (PDOException $e) {
  314 + Db::rollback();
  315 + $this->error($e->getMessage());
  316 + } catch (Exception $e) {
  317 + Db::rollback();
  318 + $this->error($e->getMessage());
  319 + }
  320 + if ($result !== false) {
  321 + //处理合同审核流程
  322 + $flow->addFlow($invoice_id, $this->auth->id, 'invoice', $flow_r);
  323 + hook("facrm_invoice_edit", array_merge($params, ['id' => $invoice_id]));
  324 + $this->success();
  325 + } else {
  326 + $this->error(__('No rows were updated'));
  327 + }
  328 + }
  329 + $this->error(__('Parameter %s can not be empty', ''));
  330 + }
  331 + $row=$row->toArray();
  332 + //处理附件
  333 + if ($row['files']){
  334 + $row['files']=explode(',',$row['files']);
  335 + foreach ($row['files'] as &$val){
  336 + $val=cdnurl($val,true);
  337 + }
  338 + }
  339 +
  340 + $this->success('',array('flow'=>$flow_r,'row'=>$row));
  341 +
  342 + }
  343 +
  344 + /**
  345 + * 开具
  346 + * @ApiSummary (用于自动完成发票信息填写)
  347 + * @ApiParams (name="ids", type="integer", required=true, description="ID")
  348 + * @ApiBody ("GET获取参数,【row发票数据】,POST提交申请,参数参考PC")
  349 + */
  350 + public function opener($ids=NULL){
  351 + $ids = $this->request->request('ids', '', 'intval');
  352 + //其实就是把发票附件上传
  353 + $row = $this->model->get($ids);
  354 + if (!$row) {
  355 + $this->error(__('No Results were found'));
  356 + }
  357 + if ($row->status==2){
  358 + $this->error(__('已开具,不能重复开具'));
  359 + }
  360 + if ($this->request->isPost()){
  361 +
  362 + $params = $this->request->post("row/a");
  363 + if ($params) {
  364 + $params['status']=2;
  365 + $result = $row->allowField(true)->save($params);
  366 + if ($result){
  367 + $row->contract()->setInc('invoice_money', $row->money);
  368 + //钩子
  369 + hook("facrm_invoice_opener", array_merge($row->toArray(),$params));
  370 + $this->success("成功");
  371 + }
  372 +
  373 +
  374 + }
  375 + $this->error(__('No rows were updated'));
  376 + }
  377 + $this->success('',array('row'=>$row));
  378 + }
  379 +
  380 +
  381 + /**
  382 + * 删除
  383 + * @param string $ids
  384 + */
  385 + public function del($ids = "")
  386 + {
  387 + if (!$this->request->isPost()) {
  388 + $this->error(__("Invalid parameters"));
  389 + }
  390 + $ids = $ids ? $ids : $this->request->post("ids");
  391 + if ($ids) {
  392 + $pk = $this->model->getPk();
  393 + $this->childrenAdminIds = $this->auth->getChildrenAdminIds(true);
  394 + $list = $this->model->where($pk, 'in', $ids)->where('create_admin_id', 'in', $this->childrenAdminIds)->select();
  395 +
  396 + $count = 0;
  397 + Db::startTrans();
  398 + try {
  399 + foreach ($list as $k => $v) {
  400 + $count += $v->delete();
  401 + }
  402 + Db::commit();
  403 + } catch (PDOException $e) {
  404 + Db::rollback();
  405 + $this->error($e->getMessage());
  406 + } catch (Exception $e) {
  407 + Db::rollback();
  408 + $this->error($e->getMessage());
  409 + }
  410 + if ($count) {
  411 + $this->success();
  412 + } else {
  413 + $this->error(__('No rows were deleted'));
  414 + }
  415 + }
  416 + $this->error(__('Parameter %s can not be empty', 'ids'));
  417 + }
  418 +
  419 +
  420 + /**
  421 + * 处理过滤where条件
  422 + * @return array
  423 + */
  424 + private function getFilterWhere($scene_list)
  425 + {
  426 + $filter = $this->request->get("filter", '');
  427 + $filter = (array)json_decode($filter, true);
  428 + $filter_w = [];
  429 + $filter['scene_id'] = isset($filter['scene_id']) ? $filter['scene_id'] : 1;
  430 + if (isset($filter['scene_id'])) {
  431 +
  432 + if (!isset($scene_list[$filter['scene_id']])) {
  433 + $this->error(__("您没有权限"));
  434 + }
  435 + switch ($filter['scene_id']) {
  436 + case 'all':
  437 + //全部
  438 + break;
  439 + case 'owner':
  440 + //我的
  441 + $filter_w['create_admin_id'] = $this->auth->id;
  442 + break;
  443 + case 'branch':
  444 + //下级
  445 + $this->childrenAdminIds = $this->auth->getChildrenAdminIds(false);
  446 + $filter_w['create_admin_id'] = ['in', $this->childrenAdminIds];
  447 + break;
  448 + default://其它的未做 TODO
  449 + $filter_w['create_admin_id'] = $this->auth->id;
  450 + }
  451 + unset($filter['scene_id']);
  452 + $this->request->get(['filter' => json_encode($filter)]);
  453 + }
  454 + return $filter_w;
  455 + }
  456 +
  457 +
  458 +
  459 +}
  1 +<?php
  2 +
  3 +namespace addons\facrm\controller\facrm;
  4 +
  5 +use addons\facrm\library\BackendApi;
  6 +
  7 +
  8 +
  9 +/**
  10 + * 操作记录
  11 + */
  12 +class Operatelog extends BackendApi
  13 +{
  14 +
  15 + protected $model = null;
  16 + protected $noNeedRight = ['index'];
  17 + /**
  18 + * 快速搜索时执行查找的字段
  19 + */
  20 + protected $searchFields = 'content';
  21 +
  22 + public function _initialize()
  23 + {
  24 + parent::_initialize();
  25 + $this->model = model('\app\admin\model\facrm\Operatelog');
  26 + $this->request->filter(['strip_tags']);
  27 + }
  28 +
  29 + /**
  30 + * 查看
  31 + * @ApiSummary (参数根据实际需要传,不需要三个都一起传)
  32 + * @ApiMethod (GET)
  33 + * @ApiParams (name="customer_id", type="int", required=false, description="客户ID")
  34 + * @ApiParams (name="contract_id", type="int", required=false, description="合同ID")
  35 + * @ApiParams (name="receivable_id", type="int", required=false, description="回款ID")
  36 + * @ApiBody ("有分页")
  37 + */
  38 + public function index($customer_id = null, $contract_id = null, $receivable_id = null)
  39 + {
  40 + $customer_id = $customer_id ? $customer_id : $this->request->param("customer_id");
  41 + $contract_id = $contract_id ? $contract_id : $this->request->param("contract_id");
  42 + $receivable_id = $receivable_id ? $receivable_id : $this->request->param("receivable_id");
  43 +
  44 +
  45 + $filter_w = [];
  46 + if ($customer_id) {
  47 + $filter_w['customer_id'] = $customer_id;
  48 + }
  49 + if ($contract_id) {
  50 + $filter_w['contract_id'] = $contract_id;
  51 + }
  52 + if ($receivable_id) {
  53 + $filter_w['receivable_id'] = $receivable_id;
  54 + }
  55 + list($where, $sort, $order, $offset, $limit) = $this->buildparams();
  56 +
  57 + $total = $this->model
  58 + ->where($where)
  59 + ->where($filter_w)
  60 + ->order($sort, $order)->fetchSql(false)
  61 + ->count();
  62 + $list = $this->model
  63 + ->where($filter_w)
  64 + ->where($where)
  65 + ->order($sort, $order)
  66 + ->limit($offset, $limit)->fetchSql(false)
  67 + ->select();
  68 + foreach ($list as $row) {
  69 + $row->hidden(['content']);
  70 + }
  71 + $result = array("total" => $total, "rows" => $list);
  72 + $this->success('', $result);
  73 + }
  74 +
  75 +
  76 + /**
  77 + * 日志详情
  78 + * @ApiParams (name="ids", type="int", required=true, description="日志ID")
  79 + */
  80 + public function detail($ids = NULL)
  81 + {
  82 + $ids = $ids ? $ids : $this->request->param("ids");
  83 + $row = $this->model->get(['id' => $ids]);
  84 + if (!$row) {
  85 + $this->error(__('No Results were found'));
  86 + }
  87 + $this->success('', $row->toArray());
  88 + }
  89 +
  90 +
  91 +}