Third.php 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854
  1. <?php
  2. namespace app\adminapi\controller\v1\merchant;
  3. use app\models\merchant\MerchantCodeAudit;
  4. use app\models\merchant\MerchantMiniprogram;
  5. use app\Request;
  6. use crmeb\services\UploadService;
  7. use crmeb\services\UtilService;
  8. use Psr\SimpleCache\InvalidArgumentException;
  9. use think\db\exception\DbException;
  10. use think\Exception;
  11. /**
  12. * 小程序代码管理类
  13. * Class MiniProgram
  14. * @package app\badminapi\controller\merchant
  15. */
  16. class Third extends Open
  17. {
  18. public function initialize($escape = false)
  19. {
  20. parent::initialize(); // TODO: Change the autogenerated stub
  21. }
  22. /**
  23. * 快速创建小程序(不一定用)
  24. * 注意: 该接口创建小程序的类目选择建议参考以下类目表,部分暂未开放类目将会被驳回,详情请参考:快速创建小程序接口-类目参考表。 https://docs.qq.com/sheet/DVnpOUlJZZGJaSUVY
  25. * @param Request $request
  26. * @return mixed
  27. * @throws InvalidArgumentException
  28. */
  29. public function createMiniProgram(Request $request)
  30. {
  31. $data = UtilService::postMore([
  32. ['name', '', '', '', 'empty_check', '请输入企业名'],
  33. ['code', '', '', '', 'empty_check', '请输入企业代码'],
  34. ['code_type', 1, '', '', ['empty_check',
  35. function ($var) {
  36. //企业代码类型(1:统一社会信用代码, 2:组织机构代码,3:营业执照注册号)
  37. if (!in_array($var, [1, 2, 3])) {
  38. return true;
  39. }
  40. return false;
  41. }], ['请选择企业代码类型', '请选择正确的企业代码类型']],
  42. ['legal_persona_wechat', '', '', '', 'empty_check', '请输入法人微信'],
  43. ['legal_persona_name', '', '', '', 'empty_check', '请输入法人姓名'],
  44. ['component_phone', '', '', '', 'empty_check', '请输入第三方联系电话'],
  45. ], $request, false);
  46. try {
  47. $component_access_token = $this->getComponentAccessToken();
  48. $url = 'https://api.weixin.qq.com/cgi-bin/component/fastregisterweapp?action=create&component_access_token=' . $component_access_token;
  49. $res = json_decode(doRequest($url, [], null, true, true), true);
  50. if (isset($res['errcode']) && $res['errcode'] == 0) {
  51. return app('json')->success('ok', '已提交创建,请联系企业法人认证。');
  52. } else {
  53. return app('json')->fail($res['errmsg'] ?? $res['msg'] ?? '请求错误');
  54. }
  55. } catch (Exception $e) {
  56. return app('json')->fail($e->getMessage(), ['file' => $e->getFile(), 'line' => $e->getLine()]);
  57. }
  58. }
  59. //TODO 其他部分慢慢补全
  60. //----
  61. //TODO =====基础信息设置start==========
  62. /**
  63. * 设置服务器域名
  64. * 授权给第三方的小程序,其服务器域名只可以为在第三方平台账号中配置的小程序服务器域名,当小程序通过第三方平台发布代码上线后,小程序原先自己配置的服务器域名将被删除,只保留第三方平台的域名,所以第三方平台在代替小程序发布代码之前,需要调用接口为小程序添加第三方平台自身的域名。 详见https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/Mini_Programs/Server_Address_Configuration.html
  65. */
  66. public function modifyDomain($mer_id, Request $request)
  67. {
  68. $data = UtilService::postMore([
  69. ['action', ''],
  70. ['requestdomain', []],
  71. ['wsrequestdomain', []],
  72. ['uploaddomain', []],
  73. ['downloaddomain', []],
  74. ]);
  75. try {
  76. $access_token = $this->getAuthorizerAccessToken(['mer_id' => $mer_id]);
  77. $url = 'https://api.weixin.qq.com/wxa/modify_domain?access_token=' . $access_token;
  78. $res = json_decode(doRequest($url, $data, null, true, true), true);
  79. if (isset($res['errcode']) && $res['errcode'] == 0) {
  80. return app('json')->success('ok', $res);
  81. } else {
  82. return app('json')->fail($res['errmsg'] ?? $res['msg'] ?? '请求错误');
  83. }
  84. } catch (Exception $e) {
  85. return app('json')->fail($e->getMessage(), ['file' => $e->getFile(), 'line' => $e->getLine()]);
  86. }
  87. }
  88. //TODO =====基础信息设置end==========
  89. //TODO =====代码管理部分start==========
  90. //todo ----代码模板库设置start--------
  91. /**
  92. * 获取代码草稿列表
  93. * 通过本接口,可以获取草稿箱中所有的草稿(临时代码模板);草稿是由第三方平台的开发小程序在使用微信开发者工具上传的,详见 https://developers.weixin.qq.com/miniprogram/dev/devtools/ext.html
  94. * @return mixed
  95. * @throws InvalidArgumentException
  96. */
  97. public function getTemplateDraftList()
  98. {
  99. try {
  100. $component_access_token = $this->getComponentAccessToken();
  101. $url = 'https://api.weixin.qq.com/wxa/gettemplatedraftlist?access_token=' . $component_access_token;
  102. $res = json_decode(doRequest($url, [], null, false), true);
  103. if (isset($res['errcode']) && $res['errcode'] == 0) {
  104. return app('json')->success('ok', $res['draft_list']);
  105. } else {
  106. return app('json')->fail($res['errmsg'] ?? $res['msg'] ?? '请求错误');
  107. }
  108. } catch (Exception $e) {
  109. return app('json')->fail($e->getMessage(), ['file' => $e->getFile(), 'line' => $e->getLine()]);
  110. }
  111. }
  112. /**
  113. * 将草稿添加到代码模板库
  114. * 可以通过获取草稿箱中所有的草稿得到草稿ID;调用本接口可以将临时草稿选为持久的代码模板。
  115. * @param int $draft_id 草稿ID
  116. * @return mixed
  117. * @throws InvalidArgumentException
  118. */
  119. public function addToTemplate($draft_id = '')
  120. {
  121. if ($draft_id == '') {
  122. return app('json')->fail('请选择要添加的草稿');
  123. }
  124. try {
  125. $component_access_token = $this->getComponentAccessToken();
  126. $url = 'https://api.weixin.qq.com/wxa/addtotemplate?access_token=' . $component_access_token;
  127. $data = [
  128. 'draft_id' => $draft_id
  129. ];
  130. $res = json_decode(doRequest($url, $data, null, true, true), true);
  131. if (isset($res['errcode']) && $res['errcode'] == 0) {
  132. return app('json')->success('添加成功');
  133. } else {
  134. return app('json')->fail($res['errmsg'] ?? $res['msg'] ?? '请求错误');
  135. }
  136. } catch (Exception $e) {
  137. return app('json')->fail($e->getMessage(), ['file' => $e->getFile(), 'line' => $e->getLine()]);
  138. }
  139. }
  140. /**
  141. * 获取代码模板列表
  142. * 第三方平台运营者可以登录 open.weixin.qq.com 或者通过将草稿箱的草稿选为代码模板接口,将草稿箱中的某个代码版本添加到代码模板库中
  143. * @return mixed
  144. * @throws InvalidArgumentException
  145. */
  146. public function getTemplateList()
  147. {
  148. try {
  149. $component_access_token = $this->getComponentAccessToken();
  150. $url = 'https://api.weixin.qq.com/wxa/gettemplatelist?access_token=' . $component_access_token;
  151. $res = json_decode(doRequest($url, [], null, false), true);
  152. if (isset($res['errcode']) && $res['errcode'] == 0) {
  153. return app('json')->success('ok', $res['template_list']);
  154. } else {
  155. return app('json')->fail($res['errmsg'] ?? $res['msg'] ?? '请求错误');
  156. }
  157. } catch (Exception $e) {
  158. return app('json')->fail($e->getMessage(), ['file' => $e->getFile(), 'line' => $e->getLine()]);
  159. }
  160. }
  161. /**
  162. * 删除指定代码模板
  163. * 因为代码模板库的模板数量是有上限的,当达到上限或者有某个模板不再需要时,可以调用本接口删除指定的代码模板
  164. * @param int $template_id 模板ID
  165. * @return mixed
  166. * @throws InvalidArgumentException
  167. */
  168. public function deleteTemplate($template_id = '')
  169. {
  170. if ($template_id == '') {
  171. return app('json')->fail('请选择要删除的模板');
  172. }
  173. try {
  174. $component_access_token = $this->getComponentAccessToken();
  175. $url = 'https://api.weixin.qq.com/wxa/deletetemplate?access_token=' . $component_access_token;
  176. $data = [
  177. 'template_id' => $template_id
  178. ];
  179. $res = json_decode(doRequest($url, $data, null, true, true), true);
  180. if (isset($res['errcode']) && $res['errcode'] == 0) {
  181. return app('json')->success('删除完成');
  182. } else {
  183. return app('json')->fail($res['errmsg'] ?? $res['msg'] ?? '请求错误');
  184. }
  185. } catch (Exception $e) {
  186. return app('json')->fail($e->getMessage(), ['file' => $e->getFile(), 'line' => $e->getLine()]);
  187. }
  188. }
  189. //todo ----代码模板库设置end--------
  190. //todo ----代码管理start--------
  191. /**
  192. * 上传小程序代码
  193. * 第三方平台需要先将草稿添加到代码模板库,或者从代码模板库中选取某个代码模板,得到对应的模板 id(template_id); 然后调用本接口可以为已授权的小程序上传代码。
  194. * @param $mer_id
  195. * @param int $template_id
  196. * @param Request $request
  197. * @return mixed
  198. * @throws InvalidArgumentException
  199. */
  200. public function commitCode($mer_id, $template_id, Request $request)
  201. {
  202. $data = UtilService::postMore([
  203. ['ext_json', []],
  204. ['user_version', '', '', '', ['empty_check',
  205. function ($var) {
  206. return (!is_string($var) || strlen($var) >= 64);
  207. }], ['代码版本号', '版本号太长或输入错误']],
  208. ['user_desc', '', '', '', 'empty_check', '请输入代码描述'],
  209. ], $request, false);
  210. try {
  211. $access_token = $this->getAuthorizerAccessToken(['mer_id' => $mer_id]);
  212. $url = 'https://api.weixin.qq.com/wxa/commit?access_token=' . $access_token;
  213. $data['template_id'] = (int)$template_id;
  214. $data['ext_json'] = json_encode($data['ext_json'], JSON_UNESCAPED_UNICODE);
  215. $res = json_decode(doRequest($url, $data, null, true, true), true);
  216. if (isset($res['errcode']) && $res['errcode'] == 0) {
  217. return app('json')->success('上传完成');
  218. } else {
  219. return app('json')->fail($res['errmsg'] ?? $res['msg'] ?? '请求错误');
  220. }
  221. } catch (Exception $e) {
  222. return app('json')->fail($e->getMessage(), ['file' => $e->getFile(), 'line' => $e->getLine()]);
  223. }
  224. }
  225. /**
  226. * 获取已上传的代码的页面列表
  227. * 通过本接口可以获取由第三方平台上传小程序代码的页面列表;用于提交审核的审核项 的 address 参数
  228. * @param int $mer_id
  229. * @return mixed
  230. * @throws InvalidArgumentException
  231. */
  232. public function getPageList($mer_id)
  233. {
  234. try {
  235. $access_token = $this->getAuthorizerAccessToken(['mer_id' => $mer_id]);
  236. $url = 'https://api.weixin.qq.com/wxa/get_page?access_token=' . $access_token;
  237. $res = json_decode(doRequest($url, [], null, false), true);
  238. if (isset($res['errcode']) && $res['errcode'] == 0) {
  239. return app('json')->success('ok', $res['page_list']);
  240. } else {
  241. return app('json')->fail($res['errmsg'] ?? $res['msg'] ?? '请求错误');
  242. }
  243. } catch (Exception $e) {
  244. return app('json')->fail($e->getMessage(), ['file' => $e->getFile(), 'line' => $e->getLine()]);
  245. }
  246. }
  247. /**
  248. * 获取体验版二维码
  249. * 调用本接口可以获取小程序的体验版二维码
  250. * @param int $mer_id 商户号
  251. * @param Request $request
  252. * @return mixed
  253. * @throws InvalidArgumentException
  254. * @throws \Exception
  255. */
  256. public function getQrCode($mer_id, Request $request)
  257. {
  258. $path = $request->get('path');
  259. if ($path) {
  260. $path = urlencode($path);
  261. }
  262. try {
  263. $access_token = $this->getAuthorizerAccessToken(['mer_id' => $mer_id]);
  264. $url = 'https://api.weixin.qq.com/wxa/get_qrcode?access_token=' . $access_token;
  265. if ($path) {
  266. $url .= "&path=" . $path;
  267. }
  268. $res = doRequest($url, [], null, false);
  269. if (!isset(json_decode($res, true)['errcode'])) {
  270. $filename = "mer_" . $mer_id . "_" . time() . random_int(1000, 9999) . ".jpg";//要生成的图片名字
  271. $file_url = 'test_qrcode/' . $mer_id;
  272. $upload = UploadService::init(1);
  273. $uploadRes = $upload->to($file_url)->validate()->stream($res, $filename);
  274. if ($uploadRes === false) {
  275. return app('json')->fail($upload->getError());
  276. }
  277. MerchantMiniprogram::vaildWhere()->where('mer_id', $mer_id)->update(['test_qrcode_url' => $file_url . '/' . $filename, 'update' => time()]);
  278. return app('json')->success('ok', ['url' => sys_config('site_url') . '/uploads/' . $file_url . '/' . $filename]);
  279. } else {
  280. return app('json')->fail($res['errmsg'] ?? $res['msg'] ?? '请求错误');
  281. }
  282. } catch (Exception $e) {
  283. return app('json')->fail($e->getMessage(), ['file' => $e->getFile(), 'line' => $e->getLine()]);
  284. } catch (DbException $e) {
  285. return app('json')->fail($e->getMessage(), ['file' => $e->getFile(), 'line' => $e->getLine()]);
  286. }
  287. }
  288. /**
  289. * 提交审核
  290. * 在调用上传代码接口为小程序上传代码后,可以调用本接口,将上传的代码提交审核。请求参数几乎都不是必须,具体详见文档 https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/Mini_Programs/code/submit_audit.html#%E5%AE%A1%E6%A0%B8%E9%A1%B9%E8%AF%B4%E6%98%8E
  291. * @param $mer_id
  292. * @param Request $request
  293. * @return mixed
  294. * @throws InvalidArgumentException
  295. */
  296. public function submitAudit($mer_id, Request $request)
  297. {
  298. $data = UtilService::postMore([
  299. ['item_list', []],
  300. ['preview_info', []],
  301. ['version_desc', ''],
  302. ['feedback_info', ''],
  303. ['feedback_stuff', ''],
  304. ['ugc_declare', []],
  305. ]);
  306. //var_dump($data);
  307. try {
  308. $access_token = $this->getAuthorizerAccessToken(['mer_id' => $mer_id]);
  309. $url = 'https://api.weixin.qq.com/wxa/submit_audit?access_token=' . $access_token;
  310. $res = json_decode(doRequest($url, $data, null, true, true), true);
  311. if (isset($res['errcode']) && $res['errcode'] == 0) {
  312. $ret = MerchantCodeAudit::create(['mer_id' => $mer_id, 'auditid' => $res['auditid'], 'commit_time' => time()]);
  313. if ($ret) {
  314. return app('json')->success('提交审核完成');
  315. } else {
  316. return app('json')->success(MerchantCodeAudit::getErrorInfo('审核记录失败,请手动记录'), ['auditid' => $res['auditid']]);
  317. }
  318. } else {
  319. return app('json')->fail($res['errmsg'] ?? $res['msg'] ?? '请求错误');
  320. }
  321. } catch (Exception $e) {
  322. return app('json')->fail($e->getMessage(), ['file' => $e->getFile(), 'line' => $e->getLine()]);
  323. } catch (DbException $e) {
  324. return app('json')->fail($e->getMessage(), ['file' => $e->getFile(), 'line' => $e->getLine()]);
  325. }
  326. }
  327. /**
  328. * @param $mer_id
  329. * @param Request $request
  330. * @return mixed
  331. * @throws InvalidArgumentException
  332. * @throws \Exception
  333. */
  334. public function addAuditMedia($mer_id, Request $request)
  335. {
  336. try {
  337. $access_token = $this->getAuthorizerAccessToken(['mer_id' => $mer_id]);
  338. //$filename = "mer_" . $mer_id . "_" . time() . random_int(1000, 9999) . $file_info->getOriginalName();//要生成的图片名字
  339. $file_url = 'upload_media/' . $mer_id;
  340. $upload = UploadService::init(1);
  341. $uploadRes = $upload->to($file_url)->validate()->move('media');
  342. if ($uploadRes === false) {
  343. return app('json')->fail($upload->getError());
  344. }
  345. $res = $upload->getUploadInfo();
  346. $real_path = ltrim($res['thumb_path'], '/');
  347. if (!$real_path) app('json')->fail('资源路径错误!');
  348. $url = "https://api.weixin.qq.com/wxa/uploadmedia?access_token=" . $access_token;
  349. $res = json_decode(doRequest($url, ['media' => new \CURLFile(realpath($real_path))], null, true, false, true), true);
  350. if (isset($res['errcode']) && $res['errcode'] == 0) {
  351. return app('json')->success(['mediaid' => $res['mediaid'], 'type' => $res['type'], 'origin' => $real_path]);
  352. } else {
  353. return app('json')->fail($res['errmsg'] ?? $res['msg'] ?? '请求错误');
  354. }
  355. } catch (Exception $e) {
  356. return app('json')->fail($e->getMessage(), ['file' => $e->getFile(), 'line' => $e->getLine()]);
  357. } catch (DbException $e) {
  358. return app('json')->fail($e->getMessage(), ['file' => $e->getFile(), 'line' => $e->getLine()]);
  359. }
  360. }
  361. /**
  362. * 获取审核列表
  363. * @param Request $request
  364. * @return mixed
  365. * @throws \Exception
  366. */
  367. public function getAuditList(Request $request)
  368. {
  369. $where = UtilService::getMore([
  370. ['mer_id', ''],
  371. ['page', 1],
  372. ['limit', 10],
  373. ['auditid', ''],
  374. ['status', '']
  375. ], $request, false);
  376. return app('json')->success('ok', MerchantCodeAudit::getList($where));
  377. }
  378. /**
  379. * 查询指定发布审核单的审核状态
  380. * 提交审核后,调用本接口可以查询指定发布审核单的审核状态
  381. * @param $mer_id
  382. * @param $auditid
  383. * @return mixed
  384. * @throws InvalidArgumentException
  385. */
  386. public function getAuditStatus($mer_id, $auditid)
  387. {
  388. if (!$auditid) {
  389. return app('json')->fail('请输入提交审核时获得的审核ID');
  390. }
  391. try {
  392. $access_token = $this->getAuthorizerAccessToken(['mer_id' => $mer_id]);
  393. $url = 'https://api.weixin.qq.com/wxa/get_auditstatus?access_token=' . $access_token;
  394. $data = ['auditid' => $auditid];
  395. $res = json_decode(doRequest($url, $data, null, true, true), true);
  396. if (isset($res['errcode']) && $res['errcode'] == 0) {
  397. $data = [
  398. 'status' => $res['status'],
  399. 'reason' => $res['reason'] ?? '',
  400. 'screenshot' => $res['screenshot'] ?? '',
  401. ];
  402. $ret = MerchantCodeAudit::where('auditid', $auditid)->update($data);
  403. if ($ret) {
  404. return app('json')->success('查询完成', $data);
  405. } else {
  406. return app('json')->success('记录失败,请手动记录', $res);
  407. }
  408. } else {
  409. return app('json')->fail($res['errmsg'] ?? $res['msg'] ?? '请求错误');
  410. }
  411. } catch (Exception $e) {
  412. return app('json')->fail($e->getMessage(), ['file' => $e->getFile(), 'line' => $e->getLine()]);
  413. } catch (DbException $e) {
  414. return app('json')->fail($e->getMessage(), ['file' => $e->getFile(), 'line' => $e->getLine()]);
  415. }
  416. }
  417. /**
  418. * 查询最新一次审核单的审核状态
  419. * 调用本接口可以查询最新一次提审单的审核状态
  420. * @param $mer_id
  421. * @return mixed
  422. * @throws InvalidArgumentException
  423. */
  424. public function getLatestAuditStatus($mer_id)
  425. {
  426. try {
  427. $access_token = $this->getAuthorizerAccessToken(['mer_id' => $mer_id]);
  428. $url = 'https://api.weixin.qq.com/wxa/get_latest_auditstatus?access_token=' . $access_token;
  429. $res = json_decode(doRequest($url, [], null, false), true);
  430. if (isset($res['errcode']) && $res['errcode'] == 0) {
  431. $data = [
  432. 'status' => $res['status'],
  433. 'reason' => $res['reason'] ?? '',
  434. 'screenshot' => $res['ScreenShot'] ?? '',
  435. ];
  436. $ret = MerchantCodeAudit::where('auditid', $res['auditid'])->update($data);
  437. if ($ret) {
  438. return app('json')->success('查询完成', $data);
  439. } else {
  440. return app('json')->success('记录失败,请手动记录', $res);
  441. }
  442. } else {
  443. return app('json')->fail($res['errmsg'] ?? $res['msg'] ?? '请求错误');
  444. }
  445. } catch (Exception $e) {
  446. return app('json')->fail($e->getMessage(), ['file' => $e->getFile(), 'line' => $e->getLine()]);
  447. } catch (DbException $e) {
  448. return app('json')->fail($e->getMessage(), ['file' => $e->getFile(), 'line' => $e->getLine()]);
  449. }
  450. }
  451. /**
  452. * 小程序审核撤回
  453. * 调用本接口可以撤回当前的代码审核单
  454. * 注意: 单个帐号每天审核撤回次数最多不超过 1 次,一个月不超过 10 次。
  455. * @param $mer_id
  456. * @return mixed
  457. * @throws InvalidArgumentException
  458. */
  459. public function undoAudit($mer_id)
  460. {
  461. try {
  462. $access_token = $this->getAuthorizerAccessToken(['mer_id' => $mer_id]);
  463. $url = 'https://api.weixin.qq.com/wxa/undocodeaudit?access_token=' . $access_token;
  464. $res = json_decode(doRequest($url, [], null, false), true);
  465. if (isset($res['errcode']) && $res['errcode'] == 0) {
  466. MerchantCodeAudit::where('mer_id', $mer_id)->where('status', 2)->update(['status' => 3]);
  467. return app('json')->success('已撤回');
  468. } else {
  469. return app('json')->fail($res['errmsg'] ?? $res['msg'] ?? '请求错误');
  470. }
  471. } catch (Exception $e) {
  472. return app('json')->fail($e->getMessage(), ['file' => $e->getFile(), 'line' => $e->getLine()]);
  473. } catch (DbException $e) {
  474. return app('json')->fail($e->getMessage(), ['file' => $e->getFile(), 'line' => $e->getLine()]);
  475. }
  476. }
  477. /**
  478. * 发布已通过审核的小程序
  479. * 调用本接口可以发布最后一个审核通过的小程序代码版本
  480. * @param $mer_id
  481. * @return mixed
  482. * @throws InvalidArgumentException
  483. */
  484. public function release($mer_id)
  485. {
  486. try {
  487. $access_token = $this->getAuthorizerAccessToken(['mer_id' => $mer_id]);
  488. $url = 'https://api.weixin.qq.com/wxa/release?access_token=' . $access_token;
  489. $res = json_decode(doRequest($url, [], null, true, true, false, JSON_FORCE_OBJECT), true);
  490. if (isset($res['errcode']) && $res['errcode'] == 0) {
  491. return app('json')->success('发布成功');
  492. } else {
  493. return app('json')->fail($res['errmsg'] ?? $res['msg'] ?? '请求错误');
  494. }
  495. } catch (Exception $e) {
  496. return app('json')->fail($e->getMessage(), ['file' => $e->getFile(), 'line' => $e->getLine()]);
  497. }
  498. }
  499. /**
  500. * 版本回退
  501. * 调用本接口可以将小程序的线上版本进行回退
  502. * 注意:
  503. * 1.如果没有上一个线上版本,将无法回退
  504. * 2.只能向上回退一个版本,即当前版本回退后,不能再调用版本回退接口
  505. * @param $mer_id
  506. * @return mixed
  507. * @throws InvalidArgumentException
  508. */
  509. public function revertCodeRelease($mer_id)
  510. {
  511. try {
  512. $access_token = $this->getAuthorizerAccessToken(['mer_id' => $mer_id]);
  513. $url = 'https://api.weixin.qq.com/wxa/revertcoderelease?access_token=' . $access_token;
  514. $res = json_decode(doRequest($url, [], null, false), true);
  515. if (isset($res['errcode']) && $res['errcode'] == 0) {
  516. return app('json')->success('回退成功');
  517. } else {
  518. return app('json')->fail($res['errmsg'] ?? $res['msg'] ?? '请求错误');
  519. }
  520. } catch (Exception $e) {
  521. return app('json')->fail($e->getMessage(), ['file' => $e->getFile(), 'line' => $e->getLine()]);
  522. }
  523. }
  524. /**
  525. * 分阶段发布
  526. * 发布小程序接口 是全量发布,会影响到现网的所有用户。而本接口时创建一个灰度发布的计划,可以控制发布的节奏,避免一上线就影响到所有的用户。可以多次调用本次接口,将灰度的比例(gray_percentage)逐渐增大
  527. * @param $mer_id
  528. * @param int $gray 灰度比例
  529. * @return mixed
  530. * @throws InvalidArgumentException
  531. */
  532. public function grayRelease($mer_id, $gray)
  533. {
  534. if (!$gray || $gray > 100 || $gray < 1) {
  535. return app('json')->fail('请输入正确的灰度值');
  536. }
  537. try {
  538. $access_token = $this->getAuthorizerAccessToken(['mer_id' => $mer_id]);
  539. $url = 'https://api.weixin.qq.com/wxa/grayrelease?access_token=' . $access_token;
  540. $data = ['gray_percentage' => (int)$gray];
  541. $res = json_decode(doRequest($url, $data, null, true, true), true);
  542. if (isset($res['errcode']) && $res['errcode'] == 0) {
  543. return app('json')->success('分阶段发布成功');
  544. } else {
  545. return app('json')->fail($res['errmsg'] ?? $res['msg'] ?? '请求错误');
  546. }
  547. } catch (Exception $e) {
  548. return app('json')->fail($e->getMessage(), ['file' => $e->getFile(), 'line' => $e->getLine()]);
  549. }
  550. }
  551. /**
  552. * 查询当前分阶段发布详情
  553. * @param $mer_id
  554. * @return mixed
  555. * @throws InvalidArgumentException
  556. */
  557. public function getGrayReleasePlan($mer_id)
  558. {
  559. try {
  560. $access_token = $this->getAuthorizerAccessToken(['mer_id' => $mer_id]);
  561. $url = 'https://api.weixin.qq.com/wxa/getgrayreleaseplan?access_token=' . $access_token;
  562. $res = json_decode(doRequest($url, [], null, false), true);
  563. if (isset($res['errcode']) && $res['errcode'] == 0) {
  564. return app('json')->success('ok', $res['gray_release_plan']);
  565. } else {
  566. return app('json')->fail($res['errmsg'] ?? $res['msg'] ?? '请求错误');
  567. }
  568. } catch (Exception $e) {
  569. return app('json')->fail($e->getMessage(), ['file' => $e->getFile(), 'line' => $e->getLine()]);
  570. }
  571. }
  572. /**
  573. * 取消分阶段发布
  574. * 在小程序分阶段发布期间,可以随时调用本接口取消分阶段发布。取消分阶段发布后,受影响的微信用户(即被灰度升级的微信用户)的小程序版本将回退到分阶段发布前的版本
  575. * @param $mer_id
  576. * @return mixed
  577. * @throws InvalidArgumentException
  578. */
  579. public function revertGrayRelease($mer_id)
  580. {
  581. try {
  582. $access_token = $this->getAuthorizerAccessToken(['mer_id' => $mer_id]);
  583. $url = 'https://api.weixin.qq.com/wxa/revertgrayrelease?access_token=' . $access_token;
  584. $res = json_decode(doRequest($url, [], null, false), true);
  585. if (isset($res['errcode']) && $res['errcode'] == 0) {
  586. return app('json')->success('已取消');
  587. } else {
  588. return app('json')->fail($res['errmsg'] ?? $res['msg'] ?? '请求错误');
  589. }
  590. } catch (Exception $e) {
  591. return app('json')->fail($e->getMessage(), ['file' => $e->getFile(), 'line' => $e->getLine()]);
  592. }
  593. }
  594. /**
  595. * 修改小程序线上代码的可见状态(仅供第三方代小程序调用)
  596. * @param $mer_id
  597. * @param $action
  598. * @return mixed
  599. * @throws InvalidArgumentException
  600. */
  601. public function changeVisitStatus($mer_id, $action)
  602. {
  603. try {
  604. $access_token = $this->getAuthorizerAccessToken(['mer_id' => $mer_id]);
  605. $url = 'https://api.weixin.qq.com/wxa/change_visitstatus?access_token=' . $access_token;
  606. $data = ['action' => $action];
  607. $res = json_decode(doRequest($url, $data, null, true, true), true);
  608. if (isset($res['errcode']) && $res['errcode'] == 0) {
  609. return app('json')->success('修改成功');
  610. } else {
  611. return app('json')->fail($res['errmsg'] ?? $res['msg'] ?? '请求错误');
  612. }
  613. } catch (Exception $e) {
  614. return app('json')->fail($e->getMessage(), ['file' => $e->getFile(), 'line' => $e->getLine()]);
  615. }
  616. }
  617. /**
  618. * 查询当前设置的最低基础库版本及各版本用户占比
  619. * 调用本接口可以查询小程序当前设置的最低基础库版本,以及小程序在各个基础库版本的用户占比
  620. * @param $mer_id
  621. * @return mixed
  622. * @throws InvalidArgumentException
  623. */
  624. public function getWeAppSupportVersion($mer_id)
  625. {
  626. try {
  627. $access_token = $this->getAuthorizerAccessToken(['mer_id' => $mer_id]);
  628. $url = 'https://api.weixin.qq.com/cgi-bin/wxopen/getweappsupportversion?access_token=' . $access_token;
  629. $res = json_decode(doRequest($url, [], null, true), true);
  630. if (isset($res['errcode']) && $res['errcode'] == 0) {
  631. return app('json')->success('ok', ['percentage' => $res['percentage'], 'version' => $res['version']]);
  632. } else {
  633. return app('json')->fail($res['errmsg'] ?? $res['msg'] ?? '请求错误');
  634. }
  635. } catch (Exception $e) {
  636. return app('json')->fail($e->getMessage(), ['file' => $e->getFile(), 'line' => $e->getLine()]);
  637. }
  638. }
  639. /**
  640. * 设置最低基础库版本
  641. * 调用本接口可以设置小程序的最低基础库支持版本,可以先查询当前小程序在各个基础库的用户占比来辅助进行决策
  642. * @param $mer_id
  643. * @param Request $request
  644. * @return mixed
  645. * @throws InvalidArgumentException
  646. */
  647. public function setWeAppSupportVersion($mer_id, Request $request)
  648. {
  649. $version = $request->post('version');
  650. if (!$version) {
  651. return app('json')->fail('请填写要设置的版本');
  652. }
  653. try {
  654. $access_token = $this->getAuthorizerAccessToken(['mer_id' => $mer_id]);
  655. $url = 'https://api.weixin.qq.com/cgi-bin/wxopen/setweappsupportversion?access_token=' . $access_token;
  656. $data = ['version' => $version];
  657. $res = json_decode(doRequest($url, $data, null, true, true), true);
  658. if (isset($res['errcode']) && $res['errcode'] == 0) {
  659. return app('json')->success('设置成功');
  660. } else {
  661. return app('json')->fail($res['errmsg'] ?? $res['msg'] ?? '请求错误');
  662. }
  663. } catch (Exception $e) {
  664. return app('json')->fail($e->getMessage(), ['file' => $e->getFile(), 'line' => $e->getLine()]);
  665. }
  666. }
  667. /**
  668. * 查询服务商的当月提审限额(quota)和加急次数
  669. * 服务商可以调用该接口,查询当月平台分配的提审限额和剩余可提审次数,以及当月分配的审核加急次数和剩余加急次数。(所有旗下小程序共用该额度)
  670. * @param $mer_id
  671. * @return mixed
  672. * @throws InvalidArgumentException
  673. */
  674. public function queryQuota($mer_id)
  675. {
  676. try {
  677. $access_token = $this->getAuthorizerAccessToken(['mer_id' => $mer_id]);
  678. $url = 'https://api.weixin.qq.com/wxa/queryquota?access_token=' . $access_token;
  679. $res = json_decode(doRequest($url, [], null, false), true);
  680. if (isset($res['errcode']) && $res['errcode'] == 0) {
  681. unset($res['errcode']);
  682. unset($res['errmsg']);
  683. return app('json')->success('ok', $res);
  684. } else {
  685. return app('json')->fail($res['errmsg'] ?? $res['msg'] ?? '请求错误');
  686. }
  687. } catch (Exception $e) {
  688. return app('json')->fail($e->getMessage(), ['file' => $e->getFile(), 'line' => $e->getLine()]);
  689. }
  690. }
  691. /**
  692. * 加急审核申请
  693. * 有加急次数的第三方可以通过该接口,对已经提审的小程序进行加急操作,加急后的小程序预计2-12小时内审完。
  694. * @param $mer_id
  695. * @param $auditid
  696. * @return mixed
  697. * @throws InvalidArgumentException
  698. */
  699. public function speedUpAudit($mer_id, $auditid)
  700. {
  701. try {
  702. $access_token = $this->getAuthorizerAccessToken(['mer_id' => $mer_id]);
  703. $url = 'https://api.weixin.qq.com/wxa/speedupaudit?access_token=' . $access_token;
  704. $data = ['auditid' => $auditid];
  705. $res = json_decode(doRequest($url, $data, null, true, true), true);
  706. if (isset($res['errcode']) && $res['errcode'] == 0) {
  707. return app('json')->success('加急完成');
  708. } else {
  709. return app('json')->fail($res['errmsg'] ?? $res['msg'] ?? '请求错误');
  710. }
  711. } catch (Exception $e) {
  712. return app('json')->fail($e->getMessage(), ['file' => $e->getFile(), 'line' => $e->getLine()]);
  713. }
  714. }
  715. /**
  716. * 获取审核时可填写的类目信息
  717. * 本接口可获取已设置的二级类目及用于代码审核的可选三级类目。使用过程中如遇到问题,可在开放平台服务商专区发帖交流。
  718. * @param $mer_id
  719. * @return mixed
  720. * @throws InvalidArgumentException
  721. */
  722. public function getCategory($mer_id)
  723. {
  724. try {
  725. $access_token = $this->getAuthorizerAccessToken(['mer_id' => $mer_id]);
  726. $url = 'https://api.weixin.qq.com/wxa/get_category?access_token=' . $access_token;
  727. $res = json_decode(doRequest($url, [], null, false), true);
  728. if (isset($res['errcode']) && $res['errcode'] == 0) {
  729. return app('json')->success('ok', $res['category_list']);
  730. } else {
  731. return app('json')->fail($res['errmsg'] ?? $res['msg'] ?? '请求错误');
  732. }
  733. } catch (Exception $e) {
  734. return app('json')->fail($e->getMessage(), ['file' => $e->getFile(), 'line' => $e->getLine()]);
  735. }
  736. }
  737. //todo ----代码管理end--------
  738. //todo ----体验者start--------
  739. /**
  740. * 绑定微信用户为体验者
  741. * 第三方平台在帮助旗下授权的小程序提交代码审核之前,可先让小程序运营者体验,体验之前需要将运营者的个人微信号添加到该小程序的体验者名单中。
  742. * 注意: 如果运营者同时也是该小程序的管理员,则无需绑定,管理员默认有体验权限。
  743. * @param $mer_id
  744. * @param Request $request
  745. * @return mixed
  746. * @throws InvalidArgumentException
  747. */
  748. public function bindTester($mer_id, Request $request)
  749. {
  750. $wechatid = $request->post('wechatid');
  751. if (!$wechatid) {
  752. return app('json')->fail('请输入微信号');
  753. }
  754. try {
  755. $access_token = $this->getAuthorizerAccessToken(['mer_id' => $mer_id]);
  756. $url = 'https://api.weixin.qq.com/wxa/bind_tester?access_token=' . $access_token;
  757. $data = ['wechatid' => $wechatid];
  758. $res = json_decode(doRequest($url, $data, null, true, true), true);
  759. if (isset($res['errcode']) && $res['errcode'] == 0) {
  760. $info = MerchantMiniprogram::vaildWhere()->where('mer_id', $mer_id)->find();
  761. $info->save(['tester' => $info['tester'] ? ($info['tester'] . ',' . $wechatid . ':' . $res['userstr']) : $wechatid . ':' . $res['userstr'], 'update' => time()]);
  762. return app('json')->success('绑定完成');
  763. } else {
  764. return app('json')->fail($res['errmsg'] ?? $res['msg'] ?? '请求错误');
  765. }
  766. } catch (Exception $e) {
  767. return app('json')->fail($e->getMessage(), ['file' => $e->getFile(), 'line' => $e->getLine()]);
  768. } catch (DbException $e) {
  769. return app('json')->fail($e->getMessage(), ['file' => $e->getFile(), 'line' => $e->getLine()]);
  770. }
  771. }
  772. /**
  773. * 解除绑定体验者
  774. * 调用本接口可以将特定微信用户从小程序的体验者列表中解绑
  775. * @param $mer_id
  776. * @param Request $request
  777. * @return mixed
  778. * @throws InvalidArgumentException
  779. */
  780. public function unbindTester($mer_id, Request $request)
  781. {
  782. list($wechatid, $userstr) = UtilService::postMore([
  783. ['wechatid', '', '', '', 'empty_check', '请输入要解绑的微信号'],
  784. ['userstr', '', '', '', 'empty_check', '请输入要解绑的人员对应的唯一字符串']
  785. ], $request, true);
  786. try {
  787. $access_token = $this->getAuthorizerAccessToken(['mer_id' => $mer_id]);
  788. $url = 'https://api.weixin.qq.com/wxa/unbind_tester?access_token=' . $access_token;
  789. $data = ['wechatid' => $wechatid, 'userstr' => $userstr];
  790. $res = json_decode(doRequest($url, $data, null, true, true), true);
  791. if (isset($res['errcode']) && $res['errcode'] == 0) {
  792. $info = MerchantMiniprogram::vaildWhere()->where('mer_id', $mer_id)->find();
  793. $member = explode(',', $info['tester']);
  794. foreach ($member as $k => $v) {
  795. if (($wechatid . ":" . $userstr) == $v) {
  796. unset($member[$k]);
  797. }
  798. }
  799. $member = implode(',', $member);
  800. $info->save(['tester' => $member, 'update' => time()]);
  801. return app('json')->success('绑定完成');
  802. } else {
  803. return app('json')->fail($res['errmsg'] ?? $res['msg'] ?? '请求错误');
  804. }
  805. } catch (Exception $e) {
  806. return app('json')->fail($e->getMessage(), ['file' => $e->getFile(), 'line' => $e->getLine()]);
  807. } catch (DbException $e) {
  808. return app('json')->fail($e->getMessage(), ['file' => $e->getFile(), 'line' => $e->getLine()]);
  809. }
  810. }
  811. //todo ----体验者end--------
  812. //TODO =====代码管理部分end===========
  813. }