├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── app ├── browser.py ├── config.py ├── jd.png ├── job │ ├── __init__.py │ ├── bean.py │ ├── bean_app.py │ ├── common.py │ ├── daka.py │ ├── daka_app.py │ ├── data_station.py │ ├── double_sign.py │ ├── red_packet.py │ └── sign_jr.py └── main.py ├── conf └── config.default.json ├── docs ├── browser.png └── qq.png ├── reference ├── daka_app_main.js ├── doJobMoney.html ├── red_packet_index.js ├── 京东小金库现金红包.md ├── 京东惠赚钱签到领钢镚.md ├── 京东金融签到.js ├── 双签赢奖励.js ├── 打卡.md ├── 新版客户端京豆签到.md └── 流量加油站.md └── requirements.txt /.gitattributes: -------------------------------------------------------------------------------- 1 | reference/* linguist-vendored 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *,cover 46 | .hypothesis/ 47 | 48 | # Translations 49 | *.mo 50 | *.pot 51 | 52 | # Django stuff: 53 | *.log 54 | local_settings.py 55 | 56 | # Flask stuff: 57 | instance/ 58 | .webassets-cache 59 | 60 | # Scrapy stuff: 61 | .scrapy 62 | 63 | # Sphinx documentation 64 | docs/_build/ 65 | 66 | # PyBuilder 67 | target/ 68 | 69 | # IPython Notebook 70 | .ipynb_checkpoints 71 | 72 | # pyenv 73 | .python-version 74 | 75 | # celery beat schedule file 76 | celerybeat-schedule 77 | 78 | # dotenv 79 | .env 80 | 81 | # virtualenv 82 | venv/ 83 | ENV/ 84 | 85 | # Spyder project settings 86 | .spyderproject 87 | 88 | # Rope project settings 89 | .ropeproject 90 | 91 | ############################################# 92 | 93 | # IDE / Editors 94 | .idea/ 95 | 96 | ############################################# 97 | 98 | /conf/ 99 | !/conf/config.default.json 100 | 101 | /data/ 102 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 自动登录京东,打卡领钢镚,签到领京豆 2 | 3 | [![Python](https://img.shields.io/badge/Python-3.5%2B-blue.svg)](https://www.python.org) 4 | 5 | 6 | ### 使用方法: 7 | 8 | 1. 安装`Python` (3.5 或更高版本) 9 | 10 | 2. 建立虚拟运行环境(可选) 11 | 12 | 3. 下载代码 13 | 14 | 4. 安装依赖:`pip install -r requirements.txt` 15 | 16 | 5. 创建配置文件(可选) 17 | 18 | 6. 运行:`python app/main.py` 19 | 20 |
21 | 22 | 23 | ## 说明 24 | 25 | 直接登录京东较复杂,不易实现,因此采用了以下两种方式进行登录: 26 | 27 | #### 方式一: 28 | 29 | > 2017-08-13 更新:即现在的默认分支`browser`。 30 | 31 | 借助内置浏览器登录。本方式中使用 `PyQt5` 的 `WebEngine` 构建了个简易浏览器,在其中登录京东即可。 32 | 33 | 登录后浏览器窗口会自动关闭,程序会获取到 cookie,然后就可以继续签到了~ 34 | 35 | ![浏览器方式登录](docs/browser.png) 36 | 37 | 38 | #### 方式二: 39 | 40 | > 2017-08-13 更新:目前此方式[依赖的包](https://github.com/gera2ld/qqlib)存在一些问题,暂不可用,请使用「浏览器方式」登录。 41 | 42 | 通过第三方登录的方式,登录了[绑定的 QQ 帐号](https://safe.jd.com/union/index.action),也就登录了京东。 43 | 44 | 在登录 QQ 时有时会出现需要输入验证码的情况,若是在 [iTerm2](http://www.iterm2.com/) 中运行,验证码图片会显示在终端中,直接输入即可;否则会调用系统关联应用打开验证码图片。 45 | 46 | ![通过 QQ 登录](docs/qq.png) 47 | 48 | 49 | ## 其他 50 | 51 | ### 配置文件说明 52 | 53 | #### 帐号/密码: 54 | 55 | 可以将帐号/密码保存到配置文件中(若使用浏览器方式,可以只保存帐号),这样就不用在每次登录时手动输入了(虽然使用了 cookie 保存登录状态,但京东还是会每隔几天就让你重新登录的...)。 56 | 57 | 将默认配置文件复制为`config.json`,然后使用 [Base85](https://en.wikipedia.org/wiki/Ascii85) 方式将对应的帐号、密码编码后填入配置文件中即可,完成后是这样子的: 58 | 59 | ```json 60 | { 61 | "debug": false, 62 | "jd": { 63 | "username": "b#rBMZeeX@", 64 | "password": "aA9+EcW-iJ" 65 | } 66 | } 67 | ``` 68 | 69 | (是不是比明文安全性多了一点点呢?^_^) 70 | 71 | 编码示例(Python): 72 | 73 | ```python 74 | >>> import base64 75 | >>> base64.b85encode(b'username').decode() 76 | 'b#rBMZeeX@' 77 | ``` 78 | 79 | #### 我没有小白卡/我想跳过某些任务: 80 | 81 | 将想要跳过的任务填写到配置文件中的 `jobs_skip` 中即可。比如想跳过「小白卡钢镚打卡」任务,填写 `Daka` 即可: 82 | 83 | ```json 84 | "jobs_skip": ["Daka"] 85 | ``` 86 | 87 | 跳过多个任务: 88 | 89 | ```json 90 | "jobs_skip": ["DataStation", "Daka"] 91 | ``` 92 | 93 | 任务列表: 94 | 95 | | 任务 | 描述 | 96 | | --- | --- | 97 | | DaKa | 小白卡钢镚打卡(已下线) | 98 | | DakaApp | 京东客户端钢镚打卡 | 99 | | BeanApp | 京东客户端签到领京豆 | 100 | | DoubleSign | 客户端双签赢奖励活动(不定时开放) | 101 | | Bean | 京东会员页签到领京豆 | 102 | | SignJR | 京东金融签到领奖励 | 103 | | DataStation | 流量加油站签到领流量 | 104 | | RedPacket | 京东小金库现金红包(已下线) | 105 | 106 |
107 | 108 | 109 | ### 设置网络代理 110 | 111 | 设置环境变量 `HTTP_PROXY` / `HTTPS_PROXY` 即可。 112 | 113 |
114 | 115 | 116 | ## Example 117 | 118 | ```log 119 | 2017-03-15 10:38:48,711 root[config] INFO: 使用配置文件 "config.json". 120 | 2017-03-15 10:38:48,745 root[main] INFO: # 从文件加载 cookies 成功. 121 | 2017-03-15 10:38:48,745 jobs[daka] INFO: Job Start: 小白卡钢镚打卡 122 | 2017-03-15 10:38:49,734 jobs[daka] INFO: 登录状态: True 123 | 2017-03-15 10:38:50,642 jobs[daka] INFO: 今日已打卡: False; 打卡天数: 2 124 | 2017-03-15 10:38:50,742 jobs[daka] INFO: 打卡成功: True; Message: 打卡成功 125 | 2017-03-15 10:38:50,743 jobs[daka] INFO: Job End. 126 | 2017-03-15 10:38:50,743 jobs[daka] INFO: Job Start: 京东客户端钢镚打卡 127 | 2017-03-15 10:38:50,843 jobs[daka] INFO: 登录状态: True 128 | 2017-03-15 10:38:50,923 jobs[daka_app] INFO: 今日已打卡: False; 打卡天数: 2 129 | 2017-03-15 10:38:51,105 jobs[daka_app] INFO: 打卡成功: True; Message: 打卡成功,成功领取了0.1个钢镚! 130 | 2017-03-15 10:38:51,105 jobs[daka] INFO: Job End. 131 | 2017-03-15 10:38:51,105 jobs[daka] INFO: Job Start: 京东客户端签到领京豆 132 | 2017-03-15 10:38:51,249 jobs[daka] INFO: 登录状态: True 133 | 2017-03-15 10:38:51,344 jobs[bean_app] INFO: 今日已签到: False; 签到天数: 2 134 | 2017-03-15 10:38:51,452 jobs[bean_app] INFO: 签到成功; 获得 2 个京豆. 135 | 2017-03-15 10:38:51,452 jobs[daka] INFO: Job End. 136 | 2017-03-15 10:38:51,452 jobs[daka] INFO: Job Start: 京东会员页签到领京豆 137 | 2017-03-15 10:38:51,967 jobs[daka] INFO: 登录状态: True 138 | 2017-03-15 10:38:52,472 jobs[bean] INFO: 今日已签到: False; 现在有 1087 个京豆. 139 | 2017-03-15 10:38:52,922 jobs[bean] INFO: 签到成功,获得 20 个京豆. 140 | 2017-03-15 10:38:52,923 jobs[daka] INFO: Job End. 141 | 2017-03-15 10:38:52,923 jobs[daka] INFO: Job Start: 京东金融签到领京豆 142 | 2017-03-15 10:38:53,514 jobs[daka] INFO: 登录状态: True 143 | 2017-03-15 10:38:53,582 jobs[bean_jr] INFO: 今天已签到: False; 签到天数: 2 144 | 2017-03-15 10:38:53,681 jobs[bean_jr] INFO: 签到成功,获得 5 个京豆. 145 | 2017-03-15 10:38:53,681 jobs[daka] INFO: Job End. 146 | ================================= 147 | = 任务数: 5; 失败数: 0 148 | = 全部成功 ~ 149 | ================================= 150 | ``` 151 | -------------------------------------------------------------------------------- /app/browser.py: -------------------------------------------------------------------------------- 1 | import locale 2 | import urllib.parse 3 | import urllib.request 4 | from http.cookies import SimpleCookie 5 | from pathlib import Path 6 | 7 | from PyQt5 import QtCore 8 | from PyQt5.QtCore import QUrl, QTimer 9 | from PyQt5.QtGui import QIcon 10 | from PyQt5.QtNetwork import QNetworkProxy 11 | from PyQt5.QtWebEngineWidgets import QWebEngineView 12 | from PyQt5.QtWidgets import QApplication 13 | from requests.cookies import RequestsCookieJar 14 | 15 | from config import config 16 | 17 | # 过滤掉一些不需要的 Qt WebEngine 日志输出 18 | # https://stackoverflow.com/questions/35894171/redirect-qdebug-output-to-file-with-pyqt5 19 | QtCore.qInstallMessageHandler(lambda *args: None) 20 | 21 | APP = None 22 | 23 | 24 | class MobileBrowser(QWebEngineView): 25 | def __init__(self): 26 | QWebEngineView.__init__(self) 27 | 28 | self.config() 29 | self.set_trigger() 30 | 31 | # WebEngine 的 cookie store 没提供获取 cookie 的方法,因此只能通过 cookieAdded 事件捕获。 32 | # 不能用 SimpleCookie, 因为 SimpleCookie 仅以 cookie name 作为 key, 不能存储 name 相同而 domain 不同 33 | # 的 cookie, 后者会覆盖前者, 导致 cookie 丢失. 比如, 京东登录成功后会返回: 34 | # pin=***; expires=Fri, 14-Apr-2017 17:29:28 GMT; domain=.jd.com; path=/ 35 | # pin=***; expires=Fri, 14-Apr-2017 17:29:28 GMT; domain=.360buy.com; path=/ 36 | # 等一系列同名 cookie. 37 | self.cookies = RequestsCookieJar() 38 | 39 | # 当到达 target 时自动关闭浏览器窗口 40 | self.target = None 41 | 42 | def config(self): 43 | self.page().profile().setHttpUserAgent(config.ua) 44 | 45 | proxies = urllib.request.getproxies() 46 | http_proxy = proxies.get('http') or proxies.get('https') 47 | 48 | if http_proxy: 49 | parsed = urllib.parse.urlparse(http_proxy) 50 | proxy = QNetworkProxy() 51 | proxy.setType(QNetworkProxy.HttpProxy) 52 | proxy.setHostName(parsed.hostname) 53 | proxy.setPort(parsed.port) 54 | QNetworkProxy.setApplicationProxy(proxy) 55 | 56 | # NoPersistentCookies, Both session and persistent cookies are stored in memory. 57 | # http://doc.qt.io/qt-5/qwebengineprofile.html#PersistentCookiesPolicy-enum 58 | # cookies 会同步到 python 中,无需由 WebEngine 保存。若保存了,cookieAdded 会触发两次,一次从文件(缓存)加载, 59 | # 一次页面中 Set-Cookie 指令加载,反而复杂了。 60 | self.page().profile().setPersistentCookiesPolicy(0) 61 | self.setZoomFactor(1.2) # 放大一下, 验证码看的清楚... 62 | 63 | def set_trigger(self): 64 | self.titleChanged.connect(self.title_changed) 65 | self.loadFinished.connect(self.load_finished) 66 | 67 | cookie_store = self.page().profile().cookieStore() 68 | cookie_store.cookieAdded.connect(self.cookie_added) 69 | 70 | def title_changed(self, title): 71 | self.setWindowTitle(title) 72 | 73 | def cookie_added(self, cookie): 74 | raw_form = bytes(cookie.toRawForm()).decode() 75 | simple_cookie = SimpleCookie(raw_form) 76 | 77 | for cookie in simple_cookie.values(): 78 | self.cookies.set(cookie.key, cookie) 79 | 80 | def load_and_show(self, url: QUrl): 81 | self.target = url 82 | super().load(url) 83 | 84 | self.show() 85 | self.raise_() # 最前显示 86 | self.activateWindow() 87 | 88 | def load_finished(self, success): 89 | """ 90 | 自动登录动作 91 | """ 92 | if success: 93 | self.apply_actions(self.url().host()) 94 | 95 | def apply_actions(self, host): 96 | """ 97 | 根据地址完成自动填充/登录/关闭窗口动作 98 | """ 99 | code = None 100 | 101 | if host == 'plogin.m.jd.com': 102 | code = """ 103 | $('#username').val('{username}'); 104 | $('#password').val('{password}'); 105 | 106 | if ({auto_submit}) {{ 107 | $('#loginBtn').addClass('btn-active'); 108 | $('#loginBtn').click(); 109 | }} else {{ 110 | $('#username').focus(); 111 | }} 112 | """ 113 | 114 | elif host == 'passport.jd.com': 115 | code = """ 116 | $(document).scrollLeft($(document).width()); // 移动到页面最右侧 117 | $('.login-tab-r').click(); 118 | $('#loginname').val('{username}'); 119 | $('#nloginpwd').val('{password}'); 120 | 121 | if ({auto_submit}) {{ 122 | // 等待页面相关组件加载完成,如 jdSlide 等 123 | setTimeout(function() {{ 124 | $('#loginsubmit').click(); 125 | }}, 1000); 126 | }} 127 | """ 128 | 129 | if code: 130 | code = code.format_map(config.jd) 131 | self.page().runJavaScript(code) 132 | 133 | if host == self.target.host(): 134 | self.setWindowTitle('👌 登录成功,窗口即将关闭...') 135 | 136 | timer = QTimer(self) 137 | timer.timeout.connect(self.close) 138 | timer.start(1000) 139 | 140 | 141 | def get_cookies(url): 142 | starting_up = QApplication.startingUp() 143 | 144 | if starting_up: 145 | global APP 146 | APP = QApplication([]) 147 | icon_path = str(Path(__file__, '../jd.png').resolve()) 148 | APP.setWindowIcon(QIcon(icon_path)) 149 | 150 | the_browser = MobileBrowser() 151 | the_browser.load_and_show(QUrl(url)) 152 | 153 | if starting_up: 154 | # On Unix/Linux Qt is configured to use the system locale settings by default. This can cause a conflict when using POSIX functions. 155 | # http://doc.qt.io/qt-5/qcoreapplication.html#locale-settings 156 | # 重设 locale, 否则某些依赖 locale 的代码可能产生错误, 如 Requests 中解析 cookie 时间的代码. 157 | locale.setlocale(locale.LC_TIME, 'C') 158 | 159 | APP.exec() 160 | 161 | return the_browser.cookies 162 | 163 | 164 | def main(): 165 | test_url = 'https://m.jd.com' 166 | cookies = get_cookies(test_url) 167 | 168 | 169 | if __name__ == '__main__': 170 | main() 171 | -------------------------------------------------------------------------------- /app/config.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import json 3 | import logging 4 | import sys 5 | from base64 import b85decode 6 | from pathlib import Path 7 | 8 | log_format = '%(asctime)s %(name)s[%(module)s] %(levelname)s: %(message)s' 9 | logging.basicConfig(format=log_format, level=logging.INFO) 10 | 11 | 12 | class Config: 13 | def __init__(self): 14 | self.debug = False 15 | self.log_format = log_format 16 | self.ua = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:52.0) Gecko/20100101 Firefox/52.0' 17 | 18 | self.jd = { 19 | 'username': '', 20 | 'password': '' 21 | } 22 | 23 | self.jobs_skip = [] 24 | 25 | @classmethod 26 | def load(cls, d): 27 | the_config = Config() 28 | 29 | the_config.debug = d.get('debug', False) 30 | 31 | try: 32 | the_config.jd = { 33 | 'username': b85decode(d['jd']['username']).decode(), 34 | 'password': b85decode(d['jd']['password']).decode() 35 | } 36 | except Exception as e: 37 | logging.error('获取京东帐号出错: ' + repr(e)) 38 | 39 | if not (the_config.jd['username'] and the_config.jd['password']): 40 | # 有些页面操作还是有用的, 比如移动焦点到输入框... 滚动页面到登录表单位置等 41 | # 所以不禁止 browser 的 auto_login 动作了, 但两项都有才自动提交, 否则只进行自动填充动作 42 | the_config.jd['auto_submit'] = 0 # used in js 43 | logging.info('用户名/密码未找到, 自动登录功能将不可用.') 44 | 45 | else: 46 | the_config.jd['auto_submit'] = 1 47 | 48 | the_config.jobs_skip = d.get('jobs_skip', []) 49 | 50 | return the_config 51 | 52 | 53 | def load_config(): 54 | parser = argparse.ArgumentParser() 55 | parser.add_argument('-c', '--config', help='config file name') 56 | args = parser.parse_args() 57 | 58 | config_name = args.config or 'config.json' 59 | logging.info('使用配置文件 "{}".'.format(config_name)) 60 | 61 | config_file = Path(__file__).parent.joinpath('../conf/', config_name) 62 | 63 | if not config_file.exists(): 64 | config_name = 'config.default.json' 65 | logging.warning('配置文件不存在, 使用默认配置文件 "{}".'.format(config_name)) 66 | config_file = config_file.parent.joinpath(config_name) 67 | 68 | try: 69 | # 略坑, Path.resolve() 在 3.5 和 3.6 上表现不一致... 若文件不存在 3.5 直接抛异常, 而 3.6 70 | # 只有 Path.resolve(strict=True) 才抛, 但 strict 默认为 False. 71 | # 感觉 3.6 的更合理些... 72 | config_file = config_file.resolve() 73 | config_dict = json.loads(config_file.read_text()) 74 | except Exception as e: 75 | sys.exit('# 错误: 配置文件载入失败: {}'.format(e)) 76 | 77 | the_config = Config.load(config_dict) 78 | 79 | return the_config 80 | 81 | 82 | config = load_config() 83 | -------------------------------------------------------------------------------- /app/jd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CaoZ/JD-Coin/287af555c530d68b095018416b67c7d2fb1bad73/app/jd.png -------------------------------------------------------------------------------- /app/job/__init__.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | logger = logging.getLogger('jobs') 4 | 5 | from config import config 6 | from .bean import Bean 7 | from .bean_app import BeanApp 8 | from .sign_jr import SignJR 9 | from .daka_app import DakaApp 10 | from .double_sign import DoubleSign 11 | from .data_station import DataStation 12 | 13 | __all__ = ['jobs_all', 'logger'] 14 | 15 | jobs_mobile = [DakaApp, BeanApp, DataStation] 16 | jobs_web = [Bean, SignJR] 17 | jobs_all = jobs_mobile + jobs_web + [DoubleSign] 18 | 19 | 20 | def set_logger(): 21 | logger.propagate = False 22 | logger.setLevel(logging.INFO) 23 | handler = logging.StreamHandler() 24 | formatter = logging.Formatter(config.log_format) 25 | handler.setFormatter(formatter) 26 | logger.addHandler(handler) 27 | 28 | 29 | set_logger() 30 | -------------------------------------------------------------------------------- /app/job/bean.py: -------------------------------------------------------------------------------- 1 | from pyquery import PyQuery 2 | from requests import HTTPError, ReadTimeout 3 | 4 | from .daka import Daka 5 | 6 | 7 | class Bean(Daka): 8 | job_name = '京东会员页签到领京豆' 9 | 10 | index_url = 'https://vip.jd.com' 11 | info_url = 'https://vip.jd.com/member/getUserInfo.html' 12 | sign_url = 'https://vip.jd.com/sign/index' 13 | test_url = 'https://vip.jd.com/member/myJingBean/index.html' 14 | login_url = test_url 15 | 16 | def __init__(self, session): 17 | super().__init__(session) 18 | self.page_data = '' 19 | 20 | def is_signed(self): 21 | page_data = self._get_page_data() 22 | signed = '已签到' in PyQuery(page_data)('.sign-in').text() 23 | 24 | detail = self.session.get(self.info_url).json() 25 | 26 | if detail['success']: 27 | user_info = detail['result']['userInfo'] 28 | beans_count = user_info['userJingBeanNum'] 29 | self.logger.info('今日已签到: {}; 现在有 {} 个京豆.'.format(signed, beans_count)) 30 | 31 | else: 32 | self.logger.info('今日已签到: {}'.format(signed)) 33 | 34 | return signed 35 | 36 | def sign(self): 37 | try: 38 | r = self.session.get(self.sign_url, timeout=10) 39 | r.raise_for_status() 40 | 41 | sign_message = PyQuery(r.text)('.day-info.active .title').text() 42 | self.logger.info(sign_message) 43 | return True # 似乎没有签到失败的情况,暂且认为签到成功 44 | 45 | except (HTTPError, ReadTimeout) as e: 46 | self.logger.error('签到失败: {}'.format(e)) 47 | return False 48 | 49 | def _get_page_data(self): 50 | if not self.page_data: 51 | self.page_data = self.session.get(self.index_url).text 52 | 53 | return self.page_data 54 | -------------------------------------------------------------------------------- /app/job/bean_app.py: -------------------------------------------------------------------------------- 1 | from .common import RequestError 2 | from .daka import Daka 3 | 4 | 5 | class BeanApp(Daka): 6 | """ 7 | 京东客户端签到领京豆. 由于是 App (Mobile) 端页面, 登录方式与领钢镚的相同, 不同于电脑端领京豆. 8 | """ 9 | job_name = '京东客户端签到领京豆' 10 | 11 | index_url = 'https://bean.m.jd.com' 12 | info_url = 'https://api.m.jd.com/client.action?functionId=findBeanIndex' 13 | sign_url = 'https://api.m.jd.com/client.action?functionId=signBeanIndex' 14 | test_url = 'https://home.m.jd.com' 15 | 16 | client_info = { 17 | 'client': 'ld', 18 | 'clientVersion': '1.0.0' 19 | } 20 | 21 | def is_signed(self): 22 | try: 23 | data = self.fetch_data(self.info_url) 24 | except RequestError as e: 25 | self.logger.error('签到信息获取失败: {}'.format(e.message)) 26 | return False 27 | 28 | # 根据测试, 1 表示已签到, 2 表示未签到, 3 表示未登录 29 | signed = (data['status'] == '1') 30 | sign_days = int(data['continuousDays']) 31 | beans_count = int(data['totalUserBean']) 32 | 33 | self.logger.info('今日已签到: {}; 签到天数: {}; 现有京豆: {}'.format(signed, sign_days, beans_count)) 34 | return signed 35 | 36 | def sign(self): 37 | try: 38 | data = self.fetch_data(self.sign_url) 39 | except RequestError as e: 40 | self.logger.error('签到失败: {}'.format(e.message)) 41 | return False 42 | 43 | sign_success = (data['status'] == '1') 44 | 45 | if sign_success: 46 | bean_count = data['dailyAward']['beanAward']['beanCount'] 47 | message = '获得京豆 {} 个.'.format(bean_count) 48 | else: 49 | message = data['dailyAward']['title'] 50 | 51 | self.logger.info('签到成功: {}; Message: {}'.format(sign_success, message)) 52 | 53 | return sign_success 54 | 55 | def fetch_data(self, url, payload=None): 56 | payload = {**payload, **self.client_info} if payload else self.client_info 57 | 58 | r = self.session.get(url, params=payload) 59 | 60 | try: 61 | as_json = r.json() 62 | except ValueError: 63 | raise RequestError('unexpected response: url: {}; http code: {}'.format(url, r.status_code), response=r) 64 | 65 | if as_json['code'] != '0' or 'errorCode' in as_json or 'errorMessage' in as_json: 66 | error_msg = as_json.get('echo') or as_json.get('errorMessage') or str(as_json) 67 | error_code = as_json.get('errorCode') or as_json.get('code') 68 | raise RequestError(error_msg, code=error_code, response=r) 69 | 70 | # 请求成功 71 | return as_json['data'] 72 | -------------------------------------------------------------------------------- /app/job/common.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | from requests import Response 4 | 5 | 6 | class RequestError(Exception): 7 | def __init__(self, message, code: str = None, response: Response = None): 8 | self.message = message 9 | self.code = code 10 | self.response = response 11 | 12 | 13 | def find_value(pattern, string, default=None, flags=0): 14 | """ 15 | 根据正则表达式在字符串中搜索值,若未找到,返回 default 16 | """ 17 | m = re.search(pattern, string, flags) 18 | 19 | if m: 20 | return m.group(1) 21 | else: 22 | return default 23 | -------------------------------------------------------------------------------- /app/job/daka.py: -------------------------------------------------------------------------------- 1 | import traceback 2 | 3 | from requests import Session 4 | 5 | import browser 6 | import job 7 | from .common import find_value, RequestError 8 | 9 | 10 | class Daka: 11 | job_name = '小白卡钢镚打卡' 12 | 13 | index_url = 'https://bk.jd.com/m/channel/login/daka.html' 14 | login_url = 'https://home.m.jd.com' 15 | sign_url = 'https://bk.jd.com/m/channel/login/clock.html' 16 | test_url = index_url 17 | job_gb_url = 'https://bk.jd.com/m/channel/login/recDakaGb.html' 18 | logger = job.logger 19 | 20 | def __init__(self, session: Session): 21 | self.session = session 22 | self.job_success = False 23 | 24 | def run(self): 25 | self.logger.info('Job Start: {}'.format(self.job_name)) 26 | 27 | is_login = self.is_login() 28 | self.logger.info('登录状态: {}'.format(is_login)) 29 | 30 | if not is_login: 31 | self.logger.info('进行登录...') 32 | try: 33 | self.login() 34 | is_login = True 35 | self.logger.info('登录成功') 36 | except Exception as e: 37 | self.logger.error('登录失败: {}'.format(repr(e))) 38 | 39 | if is_login: 40 | if self.is_signed(): 41 | self.job_success = True 42 | else: 43 | self.job_success = self.sign() 44 | 45 | self.logger.info('Job End.') 46 | 47 | def is_login(self): 48 | r = self.session.get(self.test_url, allow_redirects=False) 49 | 50 | if r.is_redirect and '/login' in r.headers['Location']: 51 | return False 52 | else: 53 | return True 54 | 55 | def login(self): 56 | cookies = browser.get_cookies(self.login_url) 57 | self.session.cookies.update(cookies) 58 | 59 | def is_signed(self): 60 | r = self.session.get(self.index_url) 61 | signed = False 62 | 63 | if r.ok: 64 | sign_pattern = r'dakaed:\s*(\w+)' 65 | days_pattern = r'dakaNumber:\s*(\d+)' 66 | 67 | try: 68 | signed = ('true' == find_value(sign_pattern, r.text)) 69 | sign_days = int(find_value(days_pattern, r.text)) 70 | self.logger.info('今日已打卡: {}; 打卡天数: {}'.format(signed, sign_days)) 71 | 72 | except Exception as e: 73 | self.logger.error('返回数据结构可能有变化, 获取打卡数据失败: {}'.format(e)) 74 | traceback.print_exc() 75 | 76 | return signed 77 | 78 | def sign(self): 79 | try: 80 | data = self.fetch_data(self.sign_url) 81 | self.logger.info('打卡成功: ' + data['resultMessage']) 82 | return True 83 | 84 | except RequestError as e: 85 | if e.code == '0003': 86 | # 已打卡 7 次, 需要先去 "任务" 里完成一个领钢镚任务... 87 | self.logger.info('已打卡 7 次, 去完成领钢镚任务...') 88 | pick_success = self.pick_gb() 89 | 90 | if pick_success: 91 | # 钢镚领取成功, 重新开始打卡任务 92 | return self.sign() 93 | else: 94 | e.message = '钢镚领取任务未成功完成.' 95 | 96 | self.logger.error('打卡失败: ' + e.message) 97 | return False 98 | 99 | def pick_gb(self): 100 | # 任务列表在 https://bk.jd.com/m/money/doJobMoney.html 中看 101 | # 领钢镚的任务的 id 是 82 102 | try: 103 | data = self.fetch_data(self.job_gb_url) 104 | self.logger.info('钢镚领取成功: {}'.format(data['resultMessage'])) 105 | return True 106 | 107 | except RequestError as e: 108 | self.logger.error('领钢镚 -> 钢镚领取失败: {}'.format(e.message)) 109 | return False 110 | 111 | def fetch_data(self, url, payload=None): 112 | r = self.session.get(url, params=payload) 113 | 114 | try: 115 | as_json = r.json() 116 | except ValueError: 117 | raise RequestError('unexpected response: url: {}; http code: {}'.format(url, r.status_code), response=r) 118 | 119 | if as_json['success']: 120 | # 请求成功 121 | return as_json 122 | 123 | else: 124 | error_msg = as_json.get('resultMessage') or str(as_json) 125 | error_code = as_json.get('resultCode') 126 | raise RequestError(error_msg, error_code) 127 | -------------------------------------------------------------------------------- /app/job/daka_app.py: -------------------------------------------------------------------------------- 1 | import traceback 2 | 3 | from .daka import Daka 4 | 5 | 6 | class DakaApp(Daka): 7 | job_name = '京东客户端钢镚打卡' 8 | 9 | index_url = 'https://m.jr.jd.com/spe/qyy/main/index.html?userType=41' 10 | sign_url = 'https://ms.jr.jd.com/gw/generic/base/h5/m/baseSignInEncrypt' 11 | test_url = 'https://ms.jr.jd.com/gw/generic/base/h5/m/baseGetMessByGroupType' 12 | 13 | def __init__(self, session): 14 | super().__init__(session) 15 | self.sign_data = {} 16 | 17 | def get_sign_data(self): 18 | payload = { 19 | 'reqData': '{"clientType":"outH5","userType":41,"groupType":154}', 20 | 'sid': self.session.cookies.get('sid'), 21 | 'source': 'jrm' 22 | } 23 | 24 | sign_data = {} 25 | 26 | try: 27 | # 参见 daka_app_min.js -> h.getSign, 第 1825 行开始 28 | r = self.session.post(self.test_url, data=payload) 29 | as_json = r.json() 30 | 31 | if 'resultData' in as_json: 32 | sign_data = r.json()['resultData']['53'] 33 | 34 | else: 35 | error_msg = as_json.get('resultMsg') or as_json.get('resultMessage') 36 | self.logger.error('获取打卡数据失败: {}'.format(error_msg)) 37 | 38 | except Exception as e: 39 | self.logger.error('获取打卡数据失败: {}'.format(e)) 40 | 41 | return sign_data 42 | 43 | def is_login(self): 44 | sign_data = self.get_sign_data() 45 | 46 | # 参见 daka_app_min.js, 第 1835 行 47 | is_login = 'suitable' in sign_data 48 | 49 | if is_login: 50 | # 用户已登录, sign_data 有效, 存储下 51 | self.sign_data = sign_data 52 | 53 | return is_login 54 | 55 | def is_signed(self): 56 | sign_data = self.sign_data or self.get_sign_data() 57 | 58 | signed = False 59 | 60 | try: 61 | signed = sign_data['signInStatus'] == 1 62 | self.logger.info('今日已打卡: {}'.format(signed)) 63 | 64 | except Exception as e: 65 | self.logger.error('返回数据结构可能有变化, 获取打卡数据失败: {}'.format(e)) 66 | traceback.print_exc() 67 | 68 | return signed 69 | 70 | def sign(self): 71 | payload = { 72 | 'reqData': '{}', 73 | 'sid': self.session.cookies.get('sid'), 74 | 'source': 'jrm' 75 | } 76 | 77 | r = self.session.post(self.sign_url, data=payload) 78 | as_json = r.json() 79 | 80 | if 'resultData' in as_json: 81 | result_data = as_json['resultData'] 82 | # statusCode 14 似乎是表示延期到帐的意思, 如: 签到成功,钢镚将于15个工作日内发放到账 83 | sign_success = result_data['isSuccess'] or result_data['statusCode'] == 14 84 | message = result_data['showMsg'] 85 | 86 | # 参见 daka_app_min.js, 第 1893 行 87 | continuity_days = result_data['continuityDays'] 88 | 89 | if continuity_days > 1: 90 | message += '; 签到天数: {}'.format(continuity_days) 91 | 92 | else: 93 | sign_success = False 94 | message = as_json.get('resultMsg') or as_json.get('resultMessage') 95 | 96 | self.logger.info('打卡成功: {}; Message: {}'.format(sign_success, message)) 97 | 98 | return sign_success 99 | -------------------------------------------------------------------------------- /app/job/data_station.py: -------------------------------------------------------------------------------- 1 | from .daka import Daka 2 | 3 | 4 | class DataStation(Daka): 5 | """ 6 | 流量加油站 7 | """ 8 | job_name = '流量加油站签到领流量' 9 | 10 | index_url = 'https://fbank.m.jd.com' 11 | info_url = 'https://fbank.m.jd.com/api.json?functionId=getFbankIndex' 12 | sign_url = 'https://fbank.m.jd.com/api.json?functionId=fBankSign' 13 | test_url = 'https://home.m.jd.com' 14 | 15 | def is_signed(self): 16 | response = self.session.get(self.info_url).json() 17 | signed = False 18 | 19 | if response['success']: 20 | sign_info = response['signInfo'] 21 | signed = (sign_info['signCode'] != '0') 22 | message = sign_info['message'] 23 | 24 | self.logger.info('今日已签到: {}; Message: {}.'.format(signed, message)) 25 | 26 | else: 27 | message = response.get('message') or response.get('errorMessage') 28 | self.logger.error('签到信息获取失败: {}'.format(message)) 29 | 30 | return signed 31 | 32 | def sign(self): 33 | response = self.session.get(self.sign_url).json() 34 | 35 | if response['success']: 36 | sign_success = ('errorCode' not in response) 37 | message = response.get('errorMessage') or response.get('message') 38 | self.logger.info('签到成功: {}; Message: {}.'.format(sign_success, message)) 39 | return sign_success 40 | 41 | else: 42 | message = response.get('message') or response.get('errorMessage') 43 | self.logger.error('签到失败: {}'.format(message)) 44 | return False 45 | -------------------------------------------------------------------------------- /app/job/double_sign.py: -------------------------------------------------------------------------------- 1 | import traceback 2 | 3 | from pyquery import PyQuery 4 | 5 | from .common import RequestError 6 | from .daka import Daka 7 | 8 | 9 | class DoubleSign(Daka): 10 | job_name = '双签赢奖励' 11 | 12 | index_url = 'https://ljd.m.jd.com/countersign/index.action' 13 | sign_url = 'https://ljd.m.jd.com/countersign/receiveAward.json' 14 | test_url = index_url 15 | 16 | def is_signed(self): 17 | signed = False 18 | 19 | try: 20 | signed = PyQuery(self.page_data())('#awardFlag').val() == '2' 21 | self.logger.info('今日已双签: {}'.format(signed)) 22 | 23 | except Exception as e: 24 | self.logger.error('返回数据结构可能有变化, 获取双签数据失败: {}'.format(e)) 25 | traceback.print_exc() 26 | 27 | return signed 28 | 29 | def sign(self): 30 | # 参见 https://ljd.m.jd.com/js/countersign/countersign.js 31 | 32 | sign_success = True 33 | message = '' 34 | 35 | document = PyQuery(self.page_data()) 36 | 37 | jd_signed = document('#jdHasSign').val() == 'true' 38 | jr_signed = document('#jrHasSign').val() == 'true' 39 | 40 | if not (jd_signed and jr_signed): 41 | sign_success = False 42 | message = '完成双签才可领取礼包' 43 | 44 | else: 45 | try: 46 | res = self.do_sign() 47 | except RequestError as e: 48 | self.logger.error('双签失败: {}'.format(e.message)) 49 | return False 50 | 51 | if res['code'] == '0': 52 | award_data = res.get('data') 53 | 54 | if not award_data: 55 | message = '运气不佳,领到一个空空的礼包' 56 | 57 | else: 58 | award = award_data[0] 59 | sign_success = True 60 | message = '领到 {} 个{}'.format(award['awardCount'], award['awardName']) 61 | 62 | else: 63 | # 活动不定时开启,将活动时间未开始/已结束等情况都视作签到成功 64 | 65 | if res['code'] == 'DS102': 66 | message = '来早了,活动还未开始' 67 | elif res['code'] == 'DS103': 68 | message = '来晚了,活动已经结束了' 69 | elif res['code'] == 'DS104': 70 | message = '运气不佳,领到一个空空的礼包' 71 | elif res['code'] == 'DS106': 72 | sign_success = False 73 | message = '完成双签才可领取礼包' 74 | else: 75 | sign_success = False 76 | message = '未知错误,Code={}'.format(res['code']) 77 | 78 | self.logger.info('双签成功: {}; Message: {}'.format(sign_success, message)) 79 | 80 | return sign_success 81 | 82 | def do_sign(self): 83 | r = self.session.post(self.sign_url) 84 | 85 | try: 86 | as_json = r.json() 87 | except ValueError: 88 | raise RequestError('unexpected response: url: {}; http code: {}'.format(self.sign_url, r.status_code), response=r) 89 | 90 | if 'res' in as_json and 'code' in as_json['res']: 91 | # 请求成功 92 | return as_json['res'] 93 | 94 | else: 95 | error_msg = as_json.get('message') or str(as_json) 96 | error_code = as_json.get('businessCode') or as_json.get('code') 97 | raise RequestError(error_msg, error_code) 98 | 99 | def page_data(self): 100 | if not hasattr(self, '_page_data'): 101 | self._page_data = self.session.get(self.index_url).text 102 | 103 | return self._page_data 104 | -------------------------------------------------------------------------------- /app/job/red_packet.py: -------------------------------------------------------------------------------- 1 | from .daka import Daka 2 | 3 | 4 | class RedPacket(Daka): 5 | job_name = '京东小金库现金红包' 6 | 7 | index_url = 'https://m.jr.jd.com/udc-active/2017/618RedPacket/html/index.html' 8 | sign_url = 'https://ms.jr.jd.com/gw/generic/activity/h5/m/receiveZhiBoXjkRedPacket' 9 | test_url = 'https://home.m.jd.com' 10 | 11 | def is_signed(self): 12 | # 这个任务在领取前不能知道今天是否领取过, 因此返回 None 以便任务能够执行. 13 | return None 14 | 15 | def sign(self): 16 | # 参见 red_packet_index.js 17 | 18 | payload = { 19 | 'reqData': '{"activityCode":"ying_yong_bao_618"}', 20 | 'sid': self.session.cookies.get('sid') 21 | } 22 | 23 | response = self.session.post(self.sign_url, data=payload).json() 24 | 25 | if response['resultCode'] == 0: 26 | sign_success = response['resultData']['success'] 27 | 28 | if sign_success: 29 | self.logger.info('领取成功, 获得 {} 元.'.format(response['resultData']['data'])) 30 | 31 | else: 32 | message = response['resultData'].get('msg') or response.get('resultMsg') 33 | self.logger.info('领取结果: {}'.format(message)) 34 | 35 | if response['resultData'].get('code') == '03': 36 | # 当 code 为 03 时, 表示今天已领过了, 因为领取前无法知道是否领过, 此处也当做任务成功返回 37 | sign_success = True 38 | 39 | return sign_success 40 | 41 | else: 42 | message = response.get('resultMsg') 43 | self.logger.error('领取失败: {}'.format(message)) 44 | return False 45 | -------------------------------------------------------------------------------- /app/job/sign_jr.py: -------------------------------------------------------------------------------- 1 | from .bean import Bean 2 | 3 | 4 | class SignJR(Bean): 5 | job_name = '京东金融签到领奖励' 6 | 7 | index_url = 'https://vip.jr.jd.com' 8 | info_url = 'https://vip.jr.jd.com/newSign/querySignRecord' 9 | sign_url = 'https://vip.jr.jd.com/newSign/doSign' 10 | test_url = 'https://vip.jr.jd.com/coupon/myIntegralDetail' 11 | 12 | def is_signed(self): 13 | r = self.session.post(self.info_url) 14 | signed = False 15 | 16 | if r.ok: 17 | data = r.json() 18 | signed = data['isFlag'] 19 | sign_days = data['signContinuity'] 20 | self.logger.info('今日已签到: {}; 签到天数: {}; 现有钢镚: {}'.format(signed, sign_days, data['accountBalance'])) 21 | 22 | return signed 23 | 24 | def sign(self): 25 | headers = {'Referer': self.index_url} 26 | response = self.session.post(self.sign_url, headers=headers).json() 27 | 28 | sign_success = response['signSuccess'] 29 | sign_data = response['signResData'] 30 | 31 | if sign_success and sign_data: 32 | unit = ['', '京豆', '金币', '钢镚'][sign_data['rewardType']] 33 | count = sign_data['thisAmount'] / 100 if sign_data['rewardType'] == 3 else sign_data['thisAmount'] 34 | self.logger.info('签到成功, 获得 {} 个{}.'.format(count, unit)) 35 | 36 | else: 37 | self.logger.error('签到失败: Code={}'.format(response['resBusiCode'])) 38 | 39 | return sign_success 40 | -------------------------------------------------------------------------------- /app/main.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import os 3 | import pickle 4 | import traceback 5 | from pathlib import Path 6 | 7 | import requests 8 | 9 | from config import config 10 | from job import jobs_all 11 | 12 | 13 | def main(): 14 | session = make_session() 15 | 16 | jobs = [job for job in jobs_all if job.__name__ not in config.jobs_skip] 17 | jobs_failed = [] 18 | 19 | for job_class in jobs: 20 | job = job_class(session) 21 | 22 | try: 23 | job.run() 24 | except Exception as e: 25 | logging.error('# 任务运行出错: ' + repr(e)) 26 | traceback.print_exc() 27 | 28 | if not job.job_success: 29 | jobs_failed.append(job.job_name) 30 | 31 | print('=================================') 32 | print('= 任务数: {}; 失败数: {}'.format(len(jobs), len(jobs_failed))) 33 | 34 | if jobs_failed: 35 | print('= 失败的任务: {}'.format(jobs_failed)) 36 | else: 37 | print('= 全部成功 ~') 38 | 39 | print('=================================') 40 | 41 | save_session(session) 42 | 43 | 44 | def make_session() -> requests.Session: 45 | session = requests.Session() 46 | 47 | session.headers.update({ 48 | 'User-Agent': config.ua 49 | }) 50 | 51 | data_file = Path(__file__).parent.joinpath('../data/cookies') 52 | 53 | if data_file.exists(): 54 | try: 55 | bytes = data_file.read_bytes() 56 | cookies = pickle.loads(bytes) 57 | session.cookies = cookies 58 | logging.info('# 从文件加载 cookies 成功.') 59 | except Exception as e: 60 | logging.info('# 未能成功载入 cookies, 从头开始~') 61 | 62 | return session 63 | 64 | 65 | def save_session(session): 66 | data = pickle.dumps(session.cookies) 67 | 68 | data_dir = Path(__file__).parent.joinpath('../data/') 69 | data_dir.mkdir(exist_ok=True) 70 | data_file = data_dir.joinpath('cookies') 71 | data_file.write_bytes(data) 72 | 73 | 74 | def proxy_patch(): 75 | """ 76 | Requests 似乎不能使用系统的证书系统, 方便起见, 不验证 HTTPS 证书, 便于使用代理工具进行网络调试... 77 | http://docs.python-requests.org/en/master/user/advanced/#ca-certificates 78 | """ 79 | import warnings 80 | from requests.packages.urllib3.exceptions import InsecureRequestWarning 81 | 82 | class XSession(requests.Session): 83 | def __init__(self): 84 | super().__init__() 85 | self.verify = False 86 | 87 | requests.Session = XSession 88 | warnings.simplefilter('ignore', InsecureRequestWarning) 89 | 90 | 91 | if __name__ == '__main__': 92 | if config.debug and os.getenv('HTTPS_PROXY'): 93 | proxy_patch() 94 | 95 | main() 96 | -------------------------------------------------------------------------------- /conf/config.default.json: -------------------------------------------------------------------------------- 1 | { 2 | "debug": false, 3 | "jd": { 4 | "username": "", 5 | "password": "" 6 | }, 7 | "jobs_skip": ["DataStation"] 8 | } 9 | -------------------------------------------------------------------------------- /docs/browser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CaoZ/JD-Coin/287af555c530d68b095018416b67c7d2fb1bad73/docs/browser.png -------------------------------------------------------------------------------- /docs/qq.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CaoZ/JD-Coin/287af555c530d68b095018416b67c7d2fb1bad73/docs/qq.png -------------------------------------------------------------------------------- /reference/daka_app_main.js: -------------------------------------------------------------------------------- 1 | // https://m.jr.jd.com/spe/qyy/main/js/main.min.js 2 | 3 | 'use strict'; 4 | !function (a) { 5 | a.tools = { 6 | beReqdata: function (b) { 7 | return { 8 | reqData: JSON.stringify(b), 9 | sid: a.tools.getSid(), 10 | source: a.tools.getSource() 11 | } 12 | }, 13 | isQyyOut: function () { 14 | return a.tools.getString('userType') ? !1 : !0 15 | }, 16 | getSource: function () { 17 | return a.tools.isApp() ? 'app' : 'jrm' 18 | }, 19 | hasDom: function (a) { 20 | return 0 === a.length ? !1 : !0 21 | }, 22 | getFractionToDecimal: function (a) { 23 | var b = ''; 24 | return - 1 != a.indexOf('%') ? (b = a.split('%'), b[0] / 100) : (b = a.split('/'), b[0] / b[1]) 25 | }, 26 | getString: function (a) { 27 | var b = new RegExp('(^|&)' + a + '=([^&]*)(&|$)', 'i'), 28 | c = window.location.search.substr(1).match(b); 29 | return null != c ? decodeURIComponent(c[2]) : null 30 | }, 31 | getSid: function () { 32 | return a.tools.isApp() ? a.tools.getString('token') || a.tools.getString('sid') || a.tools.getCookie('sid') : a.tools.getString('sid') || a.tools.getCookie('sid') 33 | }, 34 | hasSid: function () { 35 | var b = a.tools.getSid(); 36 | return null === b || '' === b ? !1 : !0 37 | }, 38 | changeToNumber: function (a) { 39 | return 'string' == typeof a ? Number(a) : a 40 | }, 41 | changeToBoolean: function (a) { 42 | return 'boolean' == typeof a ? Boolean(a) : a 43 | }, 44 | getCookie: function (a, b) { 45 | b = b || { 46 | }; 47 | var c, 48 | d = b.raw ? function (a) { 49 | return a 50 | } 51 | : decodeURIComponent; 52 | return (c = new RegExp('(?:^|; )' + encodeURIComponent(a) + '=([^;]*)').exec(document.cookie)) ? d(c[1]) : null 53 | }, 54 | newSetCookie: function (b, c, d) { 55 | if (d = a.extend({ 56 | }, { 57 | domain: 'jr.jd.com', 58 | path: '/' 59 | }, d), null === c && (d.expires = - 1), 'number' == typeof d.expires) { 60 | var e = d.expires, 61 | f = d.expires = new Date; 62 | f.setTime(f.getTime() + 1000 * e * 60 * 60) 63 | } else if ('24h' === d.expires) { 64 | var g = new Date, 65 | f = g.getTime(), 66 | h = g.getHours(), 67 | i = g.getMinutes(), 68 | j = g.getSeconds(), 69 | k = ''; 70 | k = f - 60 * h * 60 * 1000 - 60 * i * 1000 - 1000 * j + 86400000, 71 | k = new Date(k), 72 | d.expires = k.toUTCString() 73 | } 74 | return c = '' + c, 75 | document.cookie = [ 76 | b, 77 | '=', 78 | d.raw ? c : c, 79 | d.expires ? '; expires=' + d.expires : '', 80 | d.path ? '; path=' + d.path : '', 81 | d.domain ? '; domain=' + d.domain : '', 82 | d.secure ? '; secure' : '' 83 | ].join('') 84 | }, 85 | setCookie: function (b, c, d) { 86 | if (d = a.extend({ 87 | }, { 88 | domain: 'jr.jd.com', 89 | path: '/' 90 | }, d), null === c && (d.expires = - 1), 'number' == typeof d.expires) { 91 | var e = d.expires, 92 | f = d.expires = new Date; 93 | f.setTime(f.getTime() + 1000 * e * 60 * 60) 94 | } 95 | return c = '' + c, 96 | document.cookie = [ 97 | b, 98 | '=', 99 | d.raw ? c : c, 100 | d.expires ? '; expires=' + d.expires.toUTCString() : '', 101 | d.path ? '; path=' + d.path : '', 102 | d.domain ? '; domain=' + d.domain : '', 103 | d.secure ? '; secure' : '' 104 | ].join('') 105 | }, 106 | isChinese: function (a) { 107 | var a = a.replace(/(^\s*)|(\s*$)/g, ''); 108 | return !/^[\u4E00-\uFA29]*$/.test(a) || /^[\uE7C7-\uE7F3]*$/.test(a) ? !1 : !0 109 | }, 110 | hasChinese: function (a) { 111 | var b = /[\u4E00-\u9FA5\uF900-\uFA2D]/; 112 | return b.test(a) 113 | }, 114 | isApp: function () { 115 | var a = navigator.userAgent.toLowerCase(); 116 | return 'jdjr-app' == a.match(/jdjr-app/i) ? !0 : !1 117 | }, 118 | clearCookie: function () { 119 | }, 120 | isQQ: function () { 121 | var a = navigator.userAgent.toLowerCase(), 122 | b = /sq/.test(a); 123 | return b 124 | }, 125 | isJDApp: function () { 126 | var a = navigator.userAgent.toLowerCase(); 127 | return 'jdapp' == a.match(/jdapp/i) ? !0 : !1 128 | }, 129 | isIos: function () { 130 | var a = /(iPhone|iPad|iPod)/i.test(navigator.userAgent); 131 | return a 132 | }, 133 | isWeiXin: function () { 134 | var a = window.navigator.userAgent.toLowerCase(); 135 | return 'micromessenger' == a.match(/MicroMessenger/i) ? !0 : !1 136 | }, 137 | isPc: function () { 138 | for (var a = navigator.userAgent, b = new Array('Android', 'iPhone', 'SymbianOS', 'Windows Phone', 'iPad', 'iPod'), c = !0, d = 0; d < b.length; d++) if (a.indexOf(b[d]) > 0) { 139 | c = !1; 140 | break 141 | } 142 | return c 143 | }, 144 | checkIosVersion: function () { 145 | var a = navigator.appVersion.match(/OS (\d+)_(\d+)_?(\d+)?/), 146 | b = parseInt(a[1]), 147 | c = parseInt(a[2]), 148 | d = parseInt(a[3]), 149 | e = [ 150 | b, 151 | c, 152 | d 153 | ]; 154 | return e 155 | }, 156 | checkIos10_2_1: function () { 157 | if (a.tools.isIos()) { 158 | var b = a.tools.checkIosVersion(), 159 | c = b[0], 160 | d = b[1]; 161 | return c >= 10 && d >= 2 ? !0 : !1 162 | } 163 | return !1 164 | }, 165 | getClientType: function () { 166 | var a = ''; 167 | return 1 == tools.checkUrlStatus() ? a = 8 : tools.isWeiXin() ? a = 3 : tools.isJDApp() ? (a = 5, tools.isIos() || (a = 7)) : a = tools.isApp() ? 2 : tools.isPc() ? 1 : 4, 168 | a 169 | }, 170 | checkUrlStatus: function () { 171 | var a = 0, 172 | b = location.origin, 173 | c = 'http://m.jr.jd.com', 174 | d = 'https://m.jr.jd.com', 175 | e = 'http://minner.jr.jd.com'; 176 | return a = b == c ? 0 : b == d ? 0 : b == e ? 10 : 2 177 | }, 178 | isEmptyObject: function (a) { 179 | return '{}' == JSON.stringify(a) 180 | }, 181 | jointUrlParam: function (a, b, c) { 182 | var d = new RegExp('/?/'); 183 | return d.test(a) ? a + '&' + b + '=' + c : a + '?' + b + '=' + c 184 | }, 185 | transmitParam: function (a, b, c, d, e) { 186 | return a.test(c) ? tools.jointUrlParam(d, b, e) : d 187 | }, 188 | getDeviceId: function () { 189 | function b(a) { 190 | var b = new RegExp('(^|&)' + a + '=([^&]*)(&|$)', 'i'), 191 | d = c.substr(1).match(b); 192 | return null != d ? decodeURIComponent(d[2]) : null 193 | } 194 | var c = navigator.userAgent; 195 | c = c.replace(/\;/g, '&'), 196 | c = c.replace(/\//g, '='); 197 | var d = null; 198 | return a.tools.isIos() ? d = b('adid') || b('deviceid') : (d = b('deviceid'), null === d && (d = b('uid'))), 199 | d 200 | }, 201 | forbidScroll: function () { 202 | document.body.style.overflow = 'hidden' 203 | }, 204 | permitScroll: function () { 205 | document.body.style.overflow = 'auto' 206 | }, 207 | passportLogin: function () { 208 | var a = tools.getString('sid'); 209 | '' === a && null === a && (window.location.href = qyy.links.mLogin + encodeURIComponent(location.origin + location.pathname)) 210 | }, 211 | jdjrAppLogin: function () { 212 | var a = tools.getString('token'); 213 | '' === a && null === a && jsBridgeV3.onReady().then(function () { 214 | this.jsToGetResp(function (a) { 215 | a = 'object' == typeof a ? a : JSON.parse(a), 216 | a.data && (window.location.href = location.origin + location.pathname + '?token=' + decodeURIComponent(a.data)) 217 | }, { 218 | type: 1, 219 | data: '' 220 | }) 221 | }) 222 | }, 223 | unifyLogin: function () { 224 | this.isApp() ? this.jdjrAppLogin() : this.passportLogin() 225 | }, 226 | loadSource: function (a, b, c, d) { 227 | if (null === document.getElementById(c)) { 228 | var e = document.createElement(b); 229 | e.src = a, 230 | e.id = c, 231 | document.getElementsByTagName('body') [0].appendChild(e), 232 | document.getElementById(c).onload = function () { 233 | void 0 != d && d() 234 | } 235 | } 236 | }, 237 | checkHost: function (a) { 238 | var b = location.host, 239 | c = function () { 240 | return 'link' === a ? !0 : 'interface' === a ? !1 : !0 241 | }(); 242 | switch (b) { 243 | case 'm.jr.jd.com': 244 | return c ? 'm' : 'ms'; 245 | case 'minner.jr.jd.com': 246 | return c ? 'minner' : 'msinner'; 247 | case 'localhost:8080': 248 | return c ? 'minner' : 'msinner'; 249 | default: 250 | return c ? 'm' : 'ms' 251 | } 252 | }, 253 | dealSystemError: function () { 254 | var b = a('#system-error-wrap'), 255 | c = a('#system-error-reload'); 256 | b.removeClass('hide'), 257 | a.tools.forbidBodyScroll(), 258 | c.click(function () { 259 | location.reload() 260 | }) 261 | }, 262 | forbidBodyScroll: function () { 263 | document.getElementsByTagName('body') [0].style['overflow-y'] = 'hidden' 264 | } 265 | }, 266 | a.jdjr = { 267 | getSid: function () { 268 | var b = a.tools.getString('sid'); 269 | return '' === b || null === b ? !1 : !0 270 | }, 271 | getToken: function () { 272 | var b = a.tools.getString('token'); 273 | return '' === b || null === b ? !1 : !0 274 | } 275 | } 276 | }(Zepto); 277 | var qyy = { 278 | $obj: { 279 | html: $('html'), 280 | body: $('body'), 281 | wrap: $('.wrap'), 282 | dataInput: $('#qyy-data-input') 283 | }, 284 | tabProducts: { 285 | skuMenuMap: [ 286 | ], 287 | skuMenuItemMap: [ 288 | ] 289 | }, 290 | isEnterInLoaing: !0, 291 | isJrUser: !1, 292 | isQyyOut: $.tools.isQyyOut(), 293 | isStatic: 'static' === $('html').data('type') ? !0 : !1, 294 | sid: $.tools.getSid(), 295 | hasSid: $.tools.hasSid(), 296 | token: $.tools.getString('token'), 297 | isIos: $.tools.isIos(), 298 | isInApp: $.tools.isApp(), 299 | isInJdApp: $.tools.isJDApp(), 300 | isInWeixin: $.tools.isWeiXin(), 301 | isInQQ: $.tools.isQQ(), 302 | userType: parseInt($.tools.getString('userType')) || $('#qyy-usertype').attr('data-qyy-usertype'), 303 | isActionErr: !1, 304 | isReturnTop: 0, 305 | needLogin: !1, 306 | isLogin: !1, 307 | inAppLoginInFlag: !0, 308 | headerTitle: '', 309 | hasFixedTop: !1, 310 | hasComFixedTop: !1, 311 | fixedTopSeizeClass: '', 312 | hasFixedBottom: !1, 313 | canChangeAppColor: !0, 314 | protocol: location.protocol 315 | }; 316 | qyy.imgHost = qyy.protocol + '//m.jr.jd.com/spe/qyy/main/', 317 | qyy.links = { 318 | mLogin: qyy.protocol + '//passport.m.jd.com/user/login.action?v=t&sid=&returnurl=', 319 | imgPlaceHoldUrl: qyy.protocol + '//img12.360buyimg.com/jrpmobile/jfs/t2392/247/2876588652/1253/b393637/5719d996N2f175f2f.jpg', 320 | defaultHeaderImg: qyy.protocol + '//img12.360buyimg.com/jrpmobile/jfs/t2644/238/1420176553/1442/96e2885/573d96deN06201af5.png', 321 | xbxyIcon: qyy.protocol + '//m.jr.jd.com/spe/qyy/main/images/icon_xbxy.png', 322 | checkName: 'https://msc.jd.com/auth/loginpage/wcoo/toAuthPage?' + (qyy.isInApp ? 'source=1&businessType=69' : 'source=4&businessType=68') + '&sid=', 323 | checkNameV1: 'https://msc.jd.com/auth/loginpage/wcoo/toAuthPage?' + (qyy.isInApp ? 'source=1&businessType=344' : 'source=2&businessType=344') + '&directReturnUrl=' + encodeURIComponent(location.href), 324 | jimuQb: '//m.jr.jd.com/mjractivity/14757-3.html?sid=', 325 | xjk: qyy.protocol + '//ms.jr.jd.com/xjk/h5/xjk/onekeyredirect.action?sid=', 326 | acZhye: qyy.protocol + '//m.jdpay.com/wallet/login/sid?toUrl=' + encodeURIComponent(qyy.protocol + '//m.jdpay.com/wallet/balance/index.htm?style=normal') + '&sid=' 327 | }, 328 | qyy.statics = { 329 | jrlogo: qyy.protocol + '//m.jr.jd.com/statics/logo.jpg', 330 | successIcon: qyy.protocol + '//m.jr.jd.com/statics/images/success@100.png', 331 | errorIcon: qyy.protocol + '//m.jr.jd.com/statics/images/error@100.png' 332 | }, 333 | qyy.resource = { 334 | vip: 'js/vip/vip.js', 335 | balance: 'js/balance/balance.js' 336 | }, 337 | qyy.wangGuan = qyy.protocol + '//' + $.tools.checkHost('interface') + '.jr.jd.com/gw/generic/base/h5/m/', 338 | qyy.actionMap = { 339 | getAllInfo: qyy.wangGuan + 'baseGetOutH5MessageList', 340 | baseGetMessByGroupTypeEncrypt: qyy.wangGuan + 'baseGetMessByGroupTypeEncrypt', 341 | baseGetMessByGroupType: qyy.wangGuan + 'baseGetMessByGroupType', 342 | getPageInfo: qyy.wangGuan + 'baseOutH5Page', 343 | outH5ReceiveMission: qyy.wangGuan + 'baseOutH5ReceiveMission', 344 | outH5RewardMission: qyy.wangGuan + 'baseOutH5RewardMission', 345 | getMissionAwardlist: qyy.wangGuan + 'baseGetMissionAwardlist', 346 | getMissionDetail: qyy.wangGuan + 'baseGetMissionDetailEncrypt', 347 | baseSignInEncrypt: qyy.wangGuan + 'baseSignInEncrypt', 348 | qyyExposure: '//jrmfp.jr.jd.com/hpvuv' 349 | }, 350 | function (a) { 351 | var b = { 352 | setTitleRight: function () { 353 | }, 354 | inAppUnifyLogin: function (a) { 355 | jsBridgeV3.onReady().then(function () { 356 | this.jsOpenWeb({ 357 | jumpUrl: a, 358 | jumpType: 8, 359 | productId: '', 360 | isclose: !1 361 | }) 362 | }) 363 | }, 364 | unifyAppLogin: function () { 365 | var a = location.href; 366 | qyy.inAppLoginInFlag = !1, 367 | qyy.isInApp ? jsBridgeV3.onReady().then(function () { 368 | this.jsOpenWeb({ 369 | jumpUrl: a, 370 | jumpType: 8, 371 | productId: '', 372 | isclose: !0 373 | }) 374 | }) : location.href = qyy.links.mLogin + a 375 | }, 376 | changeJrAppColor: function (a) { 377 | jsBridgeV3.onReady().then(function () { 378 | this.jsToGetResp(function () { 379 | }, { 380 | type: 3, 381 | colorArr: a.colorArr 382 | }), 383 | void 0 != a.btnText && this.jsToNaWeiXin({ 384 | isShow: !0, 385 | optionType: 2, 386 | btnText: a.btnText, 387 | jumpLiDate: { 388 | isLogin: 2, 389 | jumpLink: a.jumpLink, 390 | isclose: !1 391 | } 392 | }) 393 | }) 394 | }, 395 | initJrAppShare: function (a, b, c, d, e) { 396 | jsBridgeV3.onReady().then(function () { 397 | this.jsToNaWeiXin({ 398 | isShow: !0, 399 | optionType: 1, 400 | btnText: '分享', 401 | jumpLiDate: { 402 | isLogin: 0, 403 | jumpLink: '', 404 | isclose: !1 405 | }, 406 | jumpNaDate: { 407 | type: 7, 408 | productId: 71824013, 409 | isclose: !1 410 | }, 411 | shareDate: { 412 | appId: '', 413 | img: e, 414 | link: d, 415 | desc: c, 416 | title: a, 417 | friendesc: a, 418 | type: 3475734 419 | } 420 | }) 421 | }) 422 | }, 423 | initWeixinShare: function (a, b, c, d, e) { 424 | var f = { 425 | appId: '', 426 | imgUrl: e, 427 | link: d, 428 | desc: c, 429 | title: a 430 | }; 431 | WeixinApi.ready(function (a) { 432 | var b = { 433 | ready: function () { 434 | }, 435 | cancel: function () { 436 | }, 437 | fail: function () { 438 | }, 439 | confirm: function () { 440 | }, 441 | all: function () { 442 | } 443 | }; 444 | a.shareToFriend(f, b), 445 | a.shareToWeibo(f, b), 446 | a.shareToTimeline(f, b) 447 | }) 448 | }, 449 | initJdAppShare: function (a, b, c, d, e) { 450 | var f = encodeURIComponent(d), 451 | g = e; 452 | try { 453 | var h = { 454 | }, 455 | i = [ 456 | ]; 457 | i[0] = a, 458 | i[1] = b, 459 | i[2] = f, 460 | i[3] = g, 461 | h.version = navigator.userAgent.split(';'), 462 | h.isInApp = 'jdapp' == h.version[0].toLowerCase(), 463 | h.isRightVersion = h.isInApp && h.version[2].replace(/\./g, '') >= 400, 464 | h.isRightVersion && ('iphone' == h.version[1].toLowerCase() ? location.href = 'openapp.jdmobile://communication?params={"action":"syncShareData","title":"' + i[0] + '","content":"' + i[1] + '","shareUrl":"' + i[2] + '","iconUrl":"' + i[3] + '"}' : 'android' == h.version[1].toLowerCase() && shareHelper.setShareInfo(i[0], i[1], d, i[3])) 465 | } catch (j) { 466 | } 467 | }, 468 | init: function () { 469 | } 470 | }; 471 | a.communication = b 472 | }(window, Zepto), 473 | function (a, b) { 474 | function c(a, b, c) { 475 | this.countDownId = a, 476 | this.endTime = b, 477 | this.position = c, 478 | this.needClear = !1, 479 | this.formatDateStr = function (a) { 480 | return 0 >= a ? a = '00' : a > 0 && 10 > a && (a = '0' + a), 481 | a 482 | }, 483 | this.initDom = function () { 484 | var a = new Date, 485 | b = 0, 486 | d = 0, 487 | e = 0, 488 | f = 0, 489 | g = 0; 490 | a = a.getTime(), 491 | b = this.endTime - a, 492 | 0 >= b ? (d = e = f = g = '00', this.needClear = !0) : (d = Math.floor(b / 1000 / 60 / 60 / 24), e = Math.floor(b / 1000 / 60 / 60 % 24), f = Math.floor(b / 1000 / 60 % 60), g = Math.floor(b / 1000 % 60), e = this.formatDateStr(e + 24 * d), f = this.formatDateStr(f), g = this.formatDateStr(g)); 493 | var h = '
' + e + ':' + f + ':' + g + '
'; 494 | c.find('div').remove(), 495 | c.append(h) 496 | }, 497 | this.init = function () { 498 | this.initDom() 499 | } 500 | } 501 | function d(a, c) { 502 | function d() { 503 | g.scrollTop = 0, 504 | setInterval(e, 15) 505 | } 506 | function e() { 507 | f || (i += 1, 37 == i ? (j += 1, i -= 1, 180 == j && (i = 0, j = 0)) : (h = g.scrollTop, g.scrollTop += 1, h == g.scrollTop && (g.scrollTop = 0, g.scrollTop += 1))) 508 | } 509 | try { 510 | var f = !1, 511 | g = document.getElementById(a); 512 | g.onmouseover = new Function('isStoped = true'), 513 | g.onmouseout = new Function('isStoped = false'); 514 | var h = 0, 515 | i = 0, 516 | j = 0, 517 | k = (document.getElementById(c), b(document.getElementById(c)).find('ul')), 518 | l = k.find('li:first-child').clone(); 519 | k.append(l), 520 | d() 521 | } catch (m) { 522 | } 523 | } 524 | a.CountDown = c, 525 | a.scrollNotice = d 526 | }(window, Zepto), 527 | function (a, b) { 528 | function c() { 529 | var a = encodeURIComponent(b.tools.getString('qingfrom')); 530 | return (null === a || '' === a) && (a = 0), 531 | a 532 | } 533 | var d = b.tools, 534 | e = { 535 | pixel_1: + qyy.imgHost + 'images/pixel_1.jpg', 536 | pixel_2: + qyy.imgHost + 'images/pixel_2.jpg', 537 | pixel_3: + qyy.imgHost + 'images/pixel_3.jpg', 538 | placeHolderImg: '//img12.360buyimg.com/jrpmobile/jfs/t1903/15/2856573526/1979/8296dea9/571d99a4Nea2597e4.png', 539 | qingfrom: c(), 540 | resetClstag: function (a) { 541 | var b = a.split('_'), 542 | c = [ 543 | ]; 544 | return c[0] = 'Qing_' + b[1] + '_' + b[2], 545 | c[1] = b[3] + '_' + b[4], 546 | c 547 | }, 548 | getGroupBottom: function (a) { 549 | return 1 == a ? 'hasPadding' : '' 550 | }, 551 | getPageClick: function (a, b) { 552 | var c = '', 553 | f = ''; 554 | if (b.floorOutH5Point) f = e.resetClstag(b.floorOutH5Point), 555 | c = 'jrmsc="on" data-qyy-click="" clstag="pageclick|keycount|' + f[0] + '|' + f[1] + '|' + a + '" data-qyy-ejumpType=' + b.fjumpType + ' data-qyy-jumpt="' + b.fjumpUrl + '"'; 556 | else if (b.mLink) { 557 | var g = d.isApp() ? b.jrAppLink : b.mLink; 558 | f = e.resetClstag(b.outH5Point), 559 | c = 'jrmsc="on" data-qyy-click="" clstag="pageclick|keycount|' + f[0] + '|' + f[1] + '|' + a + '" data-qyy-ejumpType=1 data-qyy-jumpt="' + g + '"' 560 | } else f = e.resetClstag(b.outH5Point), 561 | c = 'jrmsc="on" data-qyy-click="" clstag="pageclick|keycount|' + f[0] + '|' + f[1] + '|' + a + '" data-qyy-ejumpType=' + b.ejumpType + ' data-qyy-jumpt="' + b.ejumpUrl + '"'; 562 | return c 563 | }, 564 | getRowTitile: function (a) { 565 | var b = 'com-desc', 566 | c = 'com-title'; 567 | ('' === a.fsubtitle || '' === a.fjumpUrl) && (b = 'com-desc bg-none'), 568 | '' === a.fsubtitle && (c = 'com-title maxWidth100'), 569 | 1 === a.fTitlePosition && (c = 'com-title center'); 570 | var d = '
' + a.ftitle + '
' + a.fsubtitle + '
'; 571 | return d 572 | }, 573 | getFloor: function (a) { 574 | var b = 0 === a.fbackgroundBorder ? 'hasPadding' : '', 575 | c = [ 576 | 'noFloorBottom', 577 | 'hasFloorBottom', 578 | 'hasFloorBottomLine' 579 | ], 580 | d = a.floorType, 581 | e = ''; 582 | if (124 === d || 125 === d) { 583 | qyy.tabProducts.skuMenuMap.push(qyy.tabProducts.skuMenuItemMap), 584 | qyy.tabProducts.skuMenuItemMap = [ 585 | ]; 586 | var f = { 587 | 124: 'jd-sku', 588 | 125: 'zc-sku' 589 | }; 590 | e = '
' + a.floorTitleStr + '
' + a.floorStr + '
' 591 | } else 45 === d ? (qyy.hasComFixedTop = !0, qyy.fixedTopSeizeClass = c[a.fbottomMargin], e = '
' + a.floorTitleStr + a.floorStr + '
') : e = 132 === d ? '
' + a.floorTitleStr + a.floorStr + '
' : '
' + a.floorTitleStr + a.floorStr + '
'; 592 | return e 593 | }, 594 | getFocusElement: function (a) { 595 | var b = '

' + a.etitle1 + '

' + a.etitle2 + '

'; 596 | return b 597 | }, 598 | getFocusGroup: function (a, b) { 599 | var c = '
' + a + '
'; 600 | return c 601 | }, 602 | getBannerElement: function (a) { 603 | var b = '

' + a.etitle1 + '

' + a.etitle2 + '

'; 604 | return b 605 | }, 606 | getBannerGroup: function (a, b) { 607 | var c = ''; 608 | return c 609 | }, 610 | getSingleProductElement: function (a) { 611 | var b = '

' + a.etitle1 + '

' + a.etitle2 + '

' + a.etitle3 + '

' + a.etitle4 + '

' + a.extData + '

'; 612 | return b 613 | }, 614 | getSingleProductGroup: function (a, b) { 615 | var c = '
' + a + '
'; 616 | return c 617 | }, 618 | getImgProductElement: function (a) { 619 | var b = '

' + a.etitle1 + '

' + a.etitle2 + '

'; 620 | return b 621 | }, 622 | getImgProductGroup: function (a, b) { 623 | var c = '
' + a + '
'; 624 | return c 625 | }, 626 | getObjectElement: function (a) { 627 | var b = '

' + a.etitle1 + '

' + a.etitle2 + '

' + a.etitle3 + '

'; 628 | return b 629 | }, 630 | getObjecttGroup: function (a, b) { 631 | var c = '
' + a + '
'; 632 | return c 633 | }, 634 | getSingleIconElement: function (a) { 635 | for (var b = '', c = a.length, d = 0; c > d; d++) { 636 | var f = '
'; 637 | '' === a[d].eproductImgA && (f = ''), 638 | b += '
' + f + '' + a[d].etitle1 + '' + a[d].etitle2 + '
' 639 | } 640 | return b 641 | }, 642 | getSingleIconGroup: function (a, b) { 643 | var c = ''; 644 | return c 645 | }, 646 | getDoubleAndIconElement: function (a) { 647 | var b = '' + a.etitle1 + '', 648 | c = '', 649 | d = 'row classify singleTitle', 650 | f = 'benifit', 651 | g = a.elementType; 652 | 41 === g && (f = 'classify-user-check'), 653 | 42 === g && (f = 'classify-user-tel'), 654 | '' != a.etitle2 && (b = '' + a.etitle1 + '', c = '' + a.etitle2 + '', d = 'row classify'); 655 | var h = '
' + b + c + '
' + a.etitle3 + '
'; 656 | return h 657 | }, 658 | getDoubleAndIconGroup: function (a) { 659 | var b = a; 660 | return b 661 | }, 662 | getRowBannerElement: function (a) { 663 | var b = '
'; 664 | return b 665 | }, 666 | getRowBannerGroup: function (a, b) { 667 | var c = '
' + a + '
'; 668 | return c 669 | }, 670 | getZcNewsElement: function (a) { 671 | var b = '

' + a.etitle1 + '

' + a.etitle2 + '丨' + a.etitle4 + '
'; 672 | return b 673 | }, 674 | getZcNewsGroup: function (a, b) { 675 | var c = '
' + a + '
'; 676 | return c 677 | }, 678 | getMemberInfoElement: function (a) { 679 | var b = ''; 680 | return 1 === a.elementType ? b = '
' : 3 === a.elementType ? b = '
' : 2 === a.elementType && (b = '
' + a.etitle1 + '
'), 681 | b 682 | }, 683 | getMemberInfoGroup: function (a, b) { 684 | var c = '
' + a + '
'; 685 | return c 686 | }, 687 | getMemberMissionElement: function (a) { 688 | var c = ''; 689 | if (0 === a.elementType) c = '
— ' + a.areaShowName + ' —
'; 690 | else { 691 | var d = a.scheduleTargetValue, 692 | f = a.scheduleShowValue, 693 | g = a.frequencyType, 694 | h = a.status, 695 | i = (a.areaShow, a.tag), 696 | j = '', 697 | k = '', 698 | l = 0, 699 | m = h, 700 | n = { 701 | }, 702 | o = '', 703 | p = '', 704 | q = '', 705 | n = { 706 | '-2': '不可领取', 707 | '-1': '未领取任务', 708 | 0: '进行中', 709 | 1: '未领取奖励', 710 | 2: '已完成', 711 | '00': '已完成' 712 | }, 713 | r = [ 714 | '', 715 | '当日', 716 | '当周', 717 | '当月' 718 | ], 719 | s = [ 720 | '去做任务', 721 | '继续完成', 722 | '领取奖励', 723 | '已完成', 724 | '一键开通' 725 | ], 726 | t = [ 727 | 'do-mission', 728 | 'doing-mission', 729 | 'get-prize', 730 | 'has-complete', 731 | 'do-mission' 732 | ]; 733 | - 1 === h ? l = 0 === i ? 4 : 0 : 0 === h ? (l = 1, d > 0 && (m = '00', k += '已完成' + f + '')) : 1 === h ? l = 2 : 2 === h && (l = 3), 734 | p = s[l], 735 | o = t[l], 736 | 0 != g && 2 === h && (p = r[g] + p); 737 | var u = [ 738 | '一次性任务', 739 | '日任务', 740 | '周任务', 741 | '月任务', 742 | '新任务', 743 | '火热任务' 744 | ]; 745 | if (0 !== a.frequencyType) { 746 | var g = a.frequencyType; 747 | j += '' 748 | } 749 | if (a.promotionTag) { 750 | var v = a.promotionTag; 751 | 1 === v && (j += ''), 752 | 2 === v && (j += '') 753 | } 754 | if (a.rewardInfo) { 755 | var w = [ 756 | '', 757 | qyy.imgHost + 'images/md/gold.png', 758 | qyy.imgHost + 'images/md/bean.png', 759 | '', 760 | qyy.imgHost + 'images/md/coupon.png' 761 | ], 762 | x = b.parseJSON(a.rewardInfo); 763 | '' != x.describeOne && (q += '' + x.describeOne + ''), 764 | '' != x.describeTwo && (q += '' + x.describeTwo + '') 765 | } 766 | c = '

' + a.name + '

' + q + '

' + j + '

' + p + '' + k + '
' 767 | } 768 | return c 769 | }, 770 | getMemberMissionGroup: function (a) { 771 | var b = '

暂无可做任务,明天再来看看吧~

', 772 | c = '' === a ? a + b : a; 773 | return c 774 | }, 775 | getMemberbalanceElement: function (a) { 776 | var b = ''; 777 | 1 === a.equestionMark && (b = ''); 778 | var c = '
' + a.etitle1 + ' ' + b + '
'; 779 | return c 780 | }, 781 | getMemberbalanceGroup: function (a, b) { 782 | var c = '
' + a + '
'; 783 | return c 784 | }, 785 | getWeixinElement: function (a) { 786 | var b = '', 787 | c = ''; 788 | 1 === a.equestionMark && (b = '', c = 'pl30'); 789 | var d = ''; 790 | switch (a.elementType) { 791 | case 9: 792 | d = '

钱包余额(元)' + b + '

'; 793 | break; 794 | case 10: 795 | d = '

小白信用' + b + '

'; 796 | break; 797 | case 11: 798 | d = '

京东支付银行卡' + b + '

'; 799 | break; 800 | case 13: 801 | d = '
' + a.etitle9 + '
'; 802 | break; 803 | case 14: 804 | d = '
' + a.etitle9 + '
'; 805 | break; 806 | case 15: 807 | d = '

金币' + b + '

' 808 | } 809 | return d 810 | }, 811 | getWeixinGroup: function (a, b) { 812 | var c = '
' + a + '
'; 813 | return c 814 | }, 815 | callback: function () { 816 | }, 817 | getFixedTopBannerElement1: function (a) { 818 | if (qyy.hasFixedTop = !0, 16 === a.elementType) var b = '
'; 819 | if (17 === a.elementType) { 820 | var c = ''; 821 | a.etitle1 && (c = '
' + a.etitle1 + '
'); 822 | var b = '' + c 823 | } 824 | return b 825 | }, 826 | getFixedTopBannerGroup1: function (a, b) { 827 | var c = '
' + a + '
'; 828 | return c 829 | }, 830 | getFixedTopBannerElement2: function (a) { 831 | qyy.hasFixedTop = !0; 832 | var b = '
' + a.etitle1 + '
'; 833 | return b 834 | }, 835 | getFixedTopBannerGroup2: function (a) { 836 | var b = '
' + qyy.headerTitle + '
' + a + '
'; 837 | return b 838 | }, 839 | getFixedTopMenuElement: function (a) { 840 | var b = '
' + a.etitle1 + '
'; 841 | return b 842 | }, 843 | getFixedTopMenuGroup: function (a) { 844 | var b = '
' + a + '
'; 845 | return b 846 | }, 847 | getFixedTopBottomElement1: function (a) { 848 | var c = a.eredId, 849 | d = a.eid, 850 | f = ''; 851 | 0 != parseInt(c) && b.tools.getCookie('qyy' + c) != c && (f = ''), 852 | qyy.hasFixedBottom = !0; 853 | var g = '

' + a.etitle1 + '

' + f + '
'; 854 | return g 855 | }, 856 | getFixedTopBottomGroup1: function (a) { 857 | var b = '
' + a + '
'; 858 | return b 859 | }, 860 | getButtonElement1: function (a) { 861 | var b = '
' + a.etitle1 + '
'; 862 | return b 863 | }, 864 | getButtonGroup1: function (a, b) { 865 | var c = '
' + a + '
'; 866 | return c 867 | }, 868 | getSingleTextElement: function (a) { 869 | var b = 'center'; 870 | '' != a.extData && (b = a.extData); 871 | var c = '

' + a.etitle1 + '

'; 872 | return c 873 | }, 874 | getSingleTextGroup: function (a, b) { 875 | var c = ''; 876 | return c 877 | }, 878 | getHeightElement: function (a) { 879 | var b = a.spaceHeight + 'px', 880 | c = '

'; 881 | return c 882 | }, 883 | getHeightGroup: function (a, b) { 884 | var c = '
' + a + '
'; 885 | return c 886 | }, 887 | getUserAssetsElement: function (a) { 888 | var b = '', 889 | c = a.elementType, 890 | d = ''; 891 | if (0 === a.ejumpType && (d = ''), 32 === c) { 892 | var f = '获取中', 893 | g = '获取中'; 894 | a.etitle1 && (f = a.etitle1), 895 | a.etitle2 && (g = a.etitle2), 896 | '' != d && (d = ''), 897 | b = '

总资产(元)

' + f + '

今日收益' + g + '

' + d + '
' 898 | } else if (37 === c) { 899 | var h = '获取中', 900 | i = '获取中'; 901 | a.etitle1 && (h = a.etitle1), 902 | a.etitle2 && (i = a.etitle2), 903 | '' != d && (d = ''), 904 | b = '

白条可用额度(元)

' + h + '

' + i + '

' + d + '
' 905 | } else if (33 === c) { 906 | var j = '获取中'; 907 | a.etitle1 && (j = a.etitle1), 908 | b = '

活期定期

' + j + '

' + d + '
' 909 | } else if (34 === c) { 910 | var k = '获取中'; 911 | a.etitle1 && (k = a.etitle1), 912 | b = '

基金

' + k + '

' + d + '
' 913 | } else if (36 === c) b = '

小白理财

' + a.etitle1 + '

' + d + '
'; 914 | else if (35 === c) { 915 | var l = '获取中'; 916 | a.etitle1 && (l = a.etitle1), 917 | b = '

京东小金库

' + l + '

' + d + '
' 918 | } else if (38 === c) { 919 | var m = '获取中'; 920 | a.etitle1 && (m = a.etitle1), 921 | b = '

小白信用

' + m + '

' + d + '
' 922 | } else if (39 === c) { 923 | var n = '获取中'; 924 | a.etitle1 && (n = a.etitle1), 925 | b = '

金条(可借额度)

' + n + '

' + d + '
' 926 | } else if (40 === c) { 927 | var o = '安全退出'; 928 | a.etitle1 && (o = a.etitle1), 929 | b = '
' + o + '
' 930 | } else 31 === c && (b = '
' + a.etitle1 + '' + d + '
'); 931 | return b 932 | }, 933 | getUserAssetsGroup: function (a, b) { 934 | var c = '
' + a + '
'; 935 | return c 936 | }, 937 | getJDappBalanceElement: function (a) { 938 | var b = a.elementType, 939 | c = a.equestionMark, 940 | d = a.equestionMessage, 941 | f = a.eproductImgA, 942 | g = '', 943 | h = '', 944 | i = ''; 945 | return 1 === c && (i = '

' + d + '

'), 946 | 9 === b ? h = '

钱包余额(元)

获取中' + g + '
' + i + '
' : 44 === b ? h = '

账户余额(元)

获取中' + g + '
' + i + '
' : 45 === b ? h = '' != f ? '' : '' : 46 === b ? h = '' != f ? '' : '' : void 0 947 | }, 948 | getJDappBalanceGroup: function (a, b) { 949 | var c = '
' + a + '
'; 950 | return c 951 | }, 952 | getDoubleBannerElement: function (a) { 953 | var b = '
'; 954 | return b 955 | }, 956 | getDoubleBannerGroup: function (a, b) { 957 | var c = '
' + a + '
'; 958 | return c 959 | }, 960 | getLicaiProductElement: function (a) { 961 | var b = a.etitle1, 962 | c = 'item'; 963 | d.hasChinese(b) && (c = 'item chinese'); 964 | var f = '
' + a.etitle1 + '' + a.etitle2 + '
' + a.etitle3 + '' + a.etitle4 + '
'; 965 | return f 966 | }, 967 | getLicaiProductGroup: function (a, b) { 968 | var c = '
' + a + '
'; 969 | return c 970 | }, 971 | getLicaiSkuElement: function (a) { 972 | var b = '

' + a.etitle1 + '

' + a.etitle2 + '

' + a.etitle3 + '

'; 973 | return b 974 | }, 975 | getLicaiSkuGroup: function (a, b) { 976 | var c = '
' + a + '
'; 977 | return c 978 | }, 979 | getCountDownElement: function (a) { 980 | var b = '00', 981 | c = '
' + a.etitle1 + '
' + b + ':' + b + ':' + b + '
'; 982 | return c 983 | }, 984 | getCountDownGroup: function (a, b) { 985 | var c = '
' + a + '
'; 986 | return c 987 | }, 988 | getAutoPlayNoticeElement: function (a) { 989 | var b = '', 990 | c = ''; 991 | 0 == a.ejumpType ? b = 'hide' : c = 'pr2'; 992 | var d = '
  • ' + a.etitle1 + '' + a.etitle2 + '
  • '; 993 | return d 994 | }, 995 | getAutoPlayNoticeGroup: function (a, b) { 996 | var c = '
      ' + a + '
    '; 997 | return c 998 | }, 999 | getBigBannerElement: function (a) { 1000 | var b = ''; 1001 | return b 1002 | }, 1003 | getBigBannerGroup: function (a, b) { 1004 | var c = '
    ' + a + '
    '; 1005 | return c 1006 | }, 1007 | getFixedBottomBtnElement: function (a) { 1008 | var b = '
    ' + a.etitle1 + '
    '; 1009 | return b 1010 | }, 1011 | getFixedBottomBtnGroup: function (a, b) { 1012 | var c = '
    ' + a + '
    '; 1013 | return c 1014 | }, 1015 | getFixedTopElement: function (a) { 1016 | qyy.hasFixedTop = !0; 1017 | var b = ''; 1018 | return b 1019 | }, 1020 | getFixedTopGroup: function (a, b) { 1021 | var c = '
    ' + a + '
    '; 1022 | return c 1023 | }, 1024 | getFixedBottomElement: function (a) { 1025 | var b = ''; 1026 | return b 1027 | }, 1028 | getFixedBottomGroup: function (a, b) { 1029 | var c = '
    ' + a + '
    '; 1030 | return c 1031 | }, 1032 | getJdSkuElement: function (a) { 1033 | var b = '', 1034 | c = ''; 1035 | '' != a.etag && (c = ''), 1036 | b = 0 === a.mallSkuPriceShow ? '' + a.totalJdPrice + '' : '' + a.instalmentsJdPrice + '起x' + a.mallSkuPriceShow + '期'; 1037 | var d = '
    ' + c + '

    ' + a.etitle1 + '

    ' + b + '

    '; 1038 | return 0 === a.totalJdPrice && (d = ''), 1039 | d 1040 | }, 1041 | getJdSkuGroup: function (a) { 1042 | var b = '
    ' + a + '
    '; 1043 | return b 1044 | }, 1045 | getZcSkuElement: function (a) { 1046 | var b = a.zcSkuScheduleShow, 1047 | c = a.projectStatusName, 1048 | d = a.projectStatus, 1049 | f = a.redoundMinAmount, 1050 | g = '', 1051 | h = '', 1052 | i = '', 1053 | j = '', 1054 | k = ''; 1055 | if ('' != a.etag && (k = ''), a.redoundMinAmount || (f = '暂无价格', g = 'hide'), 1 === b) { 1056 | var l = 'status-btn'; 1057 | 6 === d ? (j = a.progress >= 100 ? '100%' : a.progress + '%', h = '
    ' + a.progressShow + '
    ') : (l = 'status-btn gray', h = '
    ' + c + '
    ') 1058 | } else i = 'mb32'; 1059 | var m = '
    ' + k + '

    ' + a.etitle1 + '

    ' + f + '

    ' + h + '
    '; 1060 | return m 1061 | }, 1062 | getZcSkuGroup: function (a) { 1063 | var b = '
    ' + a + '
    '; 1064 | return b 1065 | }, 1066 | getZcTabSkuElement: function (a) { 1067 | var b = a.zcSkuScheduleShow, 1068 | c = a.projectStatusName, 1069 | d = a.projectStatus, 1070 | f = a.redoundMinAmount, 1071 | g = '', 1072 | h = '', 1073 | i = '', 1074 | j = '', 1075 | k = ''; 1076 | if ('' != a.etag && (k = ''), a.redoundMinAmount || (f = '暂无价格', g = 'hide'), 1 === b) { 1077 | var l = 'status-btn'; 1078 | 6 === d ? (j = a.progress >= 100 ? '100%' : a.progress + '%', i = '
    ' + a.progressShow + '
    ') : (l = 'status-btn gray', i = '
    ' + c + '
    ') 1079 | } else h = 'mb32'; 1080 | var m = '
    ' + k + '

    ' + a.etitle1 + '

    ' + f + '

    ' + i + '
    '; 1081 | return m 1082 | }, 1083 | getZcTabSkuGroup: function (a, b) { 1084 | var c = '
    ' + a + '
    '; 1085 | return qyy.tabProducts.skuMenuItemMap.push(b.tagName), 1086 | c 1087 | }, 1088 | getJdTabSkuElement: function (a) { 1089 | var b = '', 1090 | c = ''; 1091 | '' != a.etag && (c = ''), 1092 | b = 0 === a.mallSkuPriceShow ? '' + a.totalJdPrice + '' : '' + a.instalmentsJdPrice + '起x' + a.mallSkuPriceShow + '期'; 1093 | var d = '
    ' + c + '

    ' + a.etitle1 + '

    ' + b + '

    '; 1094 | return 0 === a.totalJdPrice && (d = ''), 1095 | d 1096 | }, 1097 | getJdTabSkuGroup: function (a, b) { 1098 | var c = '
    ' + a + '
    '; 1099 | return qyy.tabProducts.skuMenuItemMap.push(b.tagName), 1100 | c 1101 | }, 1102 | getBanner1to2Element: function (a) { 1103 | var b = { 1104 | getComStr: function (a) { 1105 | var b = '
    '; 1106 | return b 1107 | }, 1108 | getLeftStr: function (a) { 1109 | var b = '
    ', 1110 | c = this.getComStr(a); 1111 | return b + c 1112 | }, 1113 | getRightTopStr: function (a) { 1114 | var b = '
    ', 1115 | c = this.getComStr(a); 1116 | return b + c 1117 | }, 1118 | getRightBottomStr: function (a) { 1119 | var b = '
    ', 1120 | c = this.getComStr(a); 1121 | return b + c 1122 | }, 1123 | init: function (a) { 1124 | var c = { 1125 | 50: 'getLeftStr', 1126 | 51: 'getRightTopStr', 1127 | 52: 'getRightBottomStr' 1128 | }; 1129 | return b[c[a.elementType]](a) 1130 | } 1131 | }; 1132 | return b.init(a) 1133 | }, 1134 | getBanner1to2Group: function (a, b) { 1135 | var c = ''; 1136 | return c 1137 | }, 1138 | getSignElement: function (a) { 1139 | var b = '', 1140 | c = a.elementType, 1141 | d = '获取中...', 1142 | f = '...', 1143 | g = a.etitle1 ? a.etitle1 : d; 1144 | return 53 === c && (b = '
    ' + f + '

    ' + d + '

    ' + d + '

    ' + g + '
    '), 1145 | 54 === c && (b = '
    '), 1146 | b 1147 | }, 1148 | getSignGroup: function (a, b) { 1149 | var c = '
    ' + a + '
    '; 1150 | return c 1151 | } 1152 | }; 1153 | a.tempMap = e 1154 | }(window, Zepto), 1155 | function (a, b) { 1156 | var c = b.tools, 1157 | d = { 1158 | actionErrCount: 0, 1159 | systemPop: function (a) { 1160 | if (1 === this.actionErrCount) { 1161 | qyy.isActionErr = !0, 1162 | b('.detail-cover').remove(); 1163 | var c = '
    ' + a + '
    '; 1164 | b('#qyy-body-wrap').append(c), 1165 | b('.detail-cover').removeClass('hide').addClass('animated fadeIn'), 1166 | setTimeout(function () { 1167 | b('.detail-cover').removeClass('animated fadeIn').addClass('animated fadeOut'), 1168 | setTimeout(function () { 1169 | b('.detail-cover').removeClass('animated fadeOut').addClass('hide') 1170 | }, 1000) 1171 | }, 2000) 1172 | } 1173 | }, 1174 | simplePop: function (a) { 1175 | var b = '
    '; 1176 | if (a.img && (b += ''), a.img90 && (b += ''), a.img100 && (b += ''), a.title && (b += '
    ' + a.title + '
    '), a.title1 && (b += '
    ' + a.title1 + '
    '), a.desc && (b += '
    ' + a.desc + '
    '), a.desc1 && (b += '
    ' + a.desc1 + '
    '), a.subtitle && (b += '
    ' + a.subtitle + '
    '), a.label && (b += '
    ' + a.label + '
    '), a.label_desc && (b += '
    ' + a.label_desc + '
    '), a.label1 && (b += '
    ' + a.label1 + '
    '), a.label_desc1) { 1177 | var d = ''; 1178 | '' != a.scheduleShowValue && (d = '' + a.scheduleShowValue + ''), 1179 | b += '
    ' + a.label_desc1 + d + '
    ' 1180 | } 1181 | if (a.label_desc2 && (b += '
    ' + a.label_desc2 + '
    '), a.progress === !0) { 1182 | var e = c.getFractionToDecimal(a.scheduleShowValue); 1183 | b += '
    ' 1184 | } 1185 | b += '
    ', 1186 | a.btn && (b += '
    ' + a.btn + '
    '), 1187 | a.btn1 && (b += '
    ' + a.btn1 + '
    '), 1188 | a.btn2 && (b += '
    ' + a.btn2 + '
    '), 1189 | a.btn3 && (b += '
    ' + a.btn3 + '
    '), 1190 | a.btn4 && (b += '
    ' + a.btn4 + '
    '), 1191 | b += '
    '; 1192 | var f = ''; 1193 | a.topLabel && (f = '' + a.topLabel + ''); 1194 | var g = ''; 1195 | a.topImg && (g = ''); 1196 | var b = '
    ' + g + f + b + '
    '; 1197 | return b 1198 | }, 1199 | showSimplePop: function (a, c) { 1200 | b('#qyy-pop_com_wrap').remove(), 1201 | b('.wrap').append(a); 1202 | var d = b('#qyy-pop_com_wrap'); 1203 | 'wx' == c && d.addClass('weixin'), 1204 | d.removeClass('hide').addClass('bounceIn'), 1205 | setTimeout(function () { 1206 | d.removeClass('bounceIn') 1207 | }, 150) 1208 | }, 1209 | hideSimplePop: function () { 1210 | var a = b('#qyy-pop_com_wrap'); 1211 | a.addClass('bounceOut'), 1212 | setTimeout(function () { 1213 | a.removeClass('bounceOut').addClass('hide').remove() 1214 | }, 150) 1215 | }, 1216 | showLoading: function () { 1217 | b('#qyy-page-loading').removeClass('hide') 1218 | }, 1219 | hideLoading: function () { 1220 | setTimeout(function () { 1221 | b('#qyy-page-loading').addClass('hide') 1222 | }, 450) 1223 | }, 1224 | enterInAnimation: function () { 1225 | var a = { 1226 | $body: b('#body'), 1227 | $wrap: b('.wrap-container'), 1228 | enterWidthCss: function () { 1229 | this.$wrap.removeClass('hide'), 1230 | this.$body.removeClass('hide').addClass('bounceIn'), 1231 | setTimeout(function () { 1232 | d.hideLoading(), 1233 | a.$body.removeClass('bounceIn') 1234 | }, 410) 1235 | }, 1236 | enterWidthoutCss: function () { 1237 | setTimeout(function () { 1238 | d.hideLoading() 1239 | }, 410), 1240 | this.$wrap.removeClass('hide'), 1241 | this.$body.removeClass('hide') 1242 | }, 1243 | enterRule: function () { 1244 | qyy.isInJdApp ? this.enterWidthoutCss() : b.tools.checkIos10_2_1() ? this.enterWidthoutCss() : this.enterWidthCss() 1245 | }, 1246 | init: function () { 1247 | this.enterRule() 1248 | } 1249 | }; 1250 | a.init() 1251 | } 1252 | }; 1253 | a.popUi = d 1254 | }(window, Zepto), 1255 | function (a, b) { 1256 | var c = a.tempMap, 1257 | d = a.popUi, 1258 | e = a.communication, 1259 | f = (a.links, a.addition, a.checkAjax), 1260 | g = b.tools, 1261 | h = { 1262 | init: function (a, c, e, g, h, i, j, k) { 1263 | var l = k ? 8000 : 0; 1264 | qyy.isEnterInLoaing || d.showLoading(), 1265 | b.ajax({ 1266 | url: a, 1267 | type: c, 1268 | timeout: l, 1269 | dataType: e, 1270 | data: g, 1271 | async: h, 1272 | json: 'callback', 1273 | success: function (a) { 1274 | 0 === a.resultCode ? qyy.isEnterInLoaing || d.hideLoading() : 3 === a.resultCode || (qyy.isActionErr = !0, d.actionErrCount++, d.systemPop('系统开小差了')), 1275 | i(a, j), 1276 | 1 === k && qyy.isQyyOut && f.init(f.getSuccessData({ 1277 | type: '1' 1278 | })) 1279 | }, 1280 | error: function () { 1281 | 1 === k && qyy.isQyyOut && f.init(f.getErrorData({ 1282 | type: '1' 1283 | })), 1284 | qyy.isActionErr = !0, 1285 | d.actionErrCount++, 1286 | d.systemPop('系统开小差了') 1287 | }, 1288 | complete: function (a, c) { 1289 | qyy.isQyyOut && k && 'timeout' == c && b.tools.dealSystemError() 1290 | } 1291 | }) 1292 | }, 1293 | initPage: function (a) { 1294 | if (!g.isEmptyObject(a.resultData)) { 1295 | var c = a.resultData, 1296 | d = c.title, 1297 | f = c.isShare, 1298 | h = c.shareTitle, 1299 | i = c.shareSubtitle, 1300 | j = qyy.protocol + c.shareImgUrl, 1301 | k = c.shareExplain, 1302 | l = c.sharePosition, 1303 | m = c.shareUrl, 1304 | n = c.levitateButton, 1305 | o = c.levitateButtonImg, 1306 | p = c.levitateButtonJumpType, 1307 | q = c.levitateButtonJumpUrl; 1308 | qyy.headerTitle = d, 1309 | qyy.isLogin = Boolean(c.isLogin), 1310 | '' === j && (j = qyy.statics.jrlogo), 1311 | qyy.isReturnTop = c.isReturnTop; 1312 | var r = [ 1313 | 51 1314 | ]; 1315 | if ( - 1 == b.inArray(qyy.userType, r) && (qyy.isStatic || b('#qyy-web-title').html(d)), 1 === parseInt(n)) { 1316 | var s = '
    '; 1317 | b('.wrap-container').append(s) 1318 | } 1319 | if (1 === f) { 1320 | for (var t = l.split(','), u = 0, v = t.length; v > u; u++) 1 == parseInt(t[u]) ? g.isJDApp() && e.initJdAppShare(h, i, k, m, j) : 2 == parseInt(t[1]) && g.isApp() && e.initJrAppShare(h, i, k, m, j); 1321 | g.isWeiXin() && e.initWeixinShare(h, i, k, m, j) 1322 | } 1323 | } 1324 | }, 1325 | loadAllFloor: function (a) { 1326 | var b = { 1327 | focusCount: 0, 1328 | groupTypeList: [ 1329 | ], 1330 | initGroupTypeList: function () { 1331 | this.groupTypeList[0] = [ 1332 | 0, 1333 | c.getFocusElement, 1334 | c.getFocusGroup 1335 | ], 1336 | this.groupTypeList[1] = [ 1337 | 1, 1338 | c.getBannerElement, 1339 | c.getBannerGroup 1340 | ], 1341 | this.groupTypeList[3] = [ 1342 | 3, 1343 | c.getSingleProductElement, 1344 | c.getSingleProductGroup 1345 | ], 1346 | this.groupTypeList[31] = [ 1347 | 31, 1348 | c.getSingleProductElement, 1349 | c.getSingleProductGroup 1350 | ], 1351 | this.groupTypeList[102] = [ 1352 | 102, 1353 | c.getImgProductElement, 1354 | c.getImgProductGroup 1355 | ], 1356 | this.groupTypeList[4] = [ 1357 | 4, 1358 | c.getDoubleAndIconElement, 1359 | c.getDoubleAndIconGroup 1360 | ], 1361 | this.groupTypeList[7] = [ 1362 | 7, 1363 | c.getSingleIconElement, 1364 | c.getSingleIconGroup 1365 | ], 1366 | this.groupTypeList[10] = [ 1367 | 10, 1368 | c.getRowBannerElement, 1369 | c.getRowBannerGroup 1370 | ], 1371 | this.groupTypeList[22] = [ 1372 | 22, 1373 | c.getZcNewsElement, 1374 | c.getZcNewsGroup 1375 | ], 1376 | this.groupTypeList[32] = [ 1377 | 32, 1378 | c.getMemberInfoElement, 1379 | c.getMemberInfoGroup 1380 | ], 1381 | this.groupTypeList[33] = [ 1382 | 33, 1383 | c.getMemberbalanceElement, 1384 | c.getMemberbalanceGroup 1385 | ], 1386 | this.groupTypeList[34] = [ 1387 | 34, 1388 | c.getMemberMissionElement, 1389 | c.getMemberMissionGroup 1390 | ], 1391 | this.groupTypeList[144] = [ 1392 | 144, 1393 | c.getMemberMissionElement, 1394 | c.getMemberMissionGroup 1395 | ], 1396 | this.groupTypeList[145] = [ 1397 | 145, 1398 | c.getMemberMissionElement, 1399 | c.getMemberMissionGroup 1400 | ], 1401 | this.groupTypeList[146] = [ 1402 | 146, 1403 | c.getMemberMissionElement, 1404 | c.getMemberMissionGroup 1405 | ], 1406 | this.groupTypeList[147] = [ 1407 | 147, 1408 | c.getMemberMissionElement, 1409 | c.getMemberMissionGroup 1410 | ], 1411 | this.groupTypeList[148] = [ 1412 | 148, 1413 | c.getMemberMissionElement, 1414 | c.getMemberMissionGroup 1415 | ], 1416 | this.groupTypeList[149] = [ 1417 | 149, 1418 | c.getMemberMissionElement, 1419 | c.getMemberMissionGroup 1420 | ], 1421 | this.groupTypeList[150] = [ 1422 | 150, 1423 | c.getMemberMissionElement, 1424 | c.getMemberMissionGroup 1425 | ], 1426 | this.groupTypeList[151] = [ 1427 | 151, 1428 | c.getMemberMissionElement, 1429 | c.getMemberMissionGroup 1430 | ], 1431 | this.groupTypeList[152] = [ 1432 | 152, 1433 | c.getMemberMissionElement, 1434 | c.getMemberMissionGroup 1435 | ], 1436 | this.groupTypeList[54] = [ 1437 | 54, 1438 | c.getMemberMissionElement, 1439 | c.getMemberMissionGroup 1440 | ], 1441 | this.groupTypeList[47] = [ 1442 | 47, 1443 | c.getJDappBalanceElement, 1444 | c.getJDappBalanceGroup 1445 | ], 1446 | this.groupTypeList[35] = [ 1447 | 35, 1448 | c.getWeixinElement, 1449 | c.getWeixinGroup 1450 | ], 1451 | this.groupTypeList[18] = [ 1452 | 18, 1453 | c.getObjectElement, 1454 | c.getObjecttGroup 1455 | ], 1456 | this.groupTypeList[36] = [ 1457 | 36, 1458 | c.getFixedTopBannerElement1, 1459 | c.getFixedTopBannerGroup1 1460 | ], 1461 | this.groupTypeList[37] = [ 1462 | 37, 1463 | c.getFixedTopBannerElement2, 1464 | c.getFixedTopBannerGroup2 1465 | ], 1466 | this.groupTypeList[38] = [ 1467 | 38, 1468 | c.getFixedTopBottomElement1, 1469 | c.getFixedTopBottomGroup1 1470 | ], 1471 | this.groupTypeList[55] = [ 1472 | 55, 1473 | c.getFixedBottomBtnElement, 1474 | c.getFixedBottomBtnGroup 1475 | ], 1476 | this.groupTypeList[41] = [ 1477 | 41, 1478 | c.getButtonElement1, 1479 | c.getButtonGroup1 1480 | ], 1481 | this.groupTypeList[43] = [ 1482 | 43, 1483 | c.getSingleTextElement, 1484 | c.getSingleTextGroup 1485 | ], 1486 | this.groupTypeList[42] = [ 1487 | 42, 1488 | c.getUserAssetsElement, 1489 | c.getUserAssetsGroup 1490 | ], 1491 | this.groupTypeList[44] = [ 1492 | 44, 1493 | c.getBigBannerElement, 1494 | c.getBigBannerGroup 1495 | ], 1496 | this.groupTypeList[48] = [ 1497 | 48, 1498 | c.getDoubleBannerElement, 1499 | c.getDoubleBannerGroup 1500 | ], 1501 | this.groupTypeList[49] = [ 1502 | 49, 1503 | c.getCountDownElement, 1504 | c.getCountDownGroup 1505 | ], 1506 | this.groupTypeList[51] = [ 1507 | 51, 1508 | c.getLicaiProductElement, 1509 | c.getLicaiProductGroup 1510 | ], 1511 | this.groupTypeList[52] = [ 1512 | 52, 1513 | c.getAutoPlayNoticeElement, 1514 | c.getAutoPlayNoticeGroup 1515 | ], 1516 | this.groupTypeList[45] = [ 1517 | 45, 1518 | c.getFixedTopElement, 1519 | c.getFixedTopGroup 1520 | ], 1521 | this.groupTypeList[46] = [ 1522 | 46, 1523 | c.getFixedBottomElement, 1524 | c.getFixedBottomGroup 1525 | ], 1526 | this.groupTypeList[122] = [ 1527 | 122, 1528 | c.getJdSkuElement, 1529 | c.getJdSkuGroup 1530 | ], 1531 | this.groupTypeList[123] = [ 1532 | 123, 1533 | c.getZcSkuElement, 1534 | c.getZcSkuGroup 1535 | ], 1536 | this.groupTypeList[124] = [ 1537 | 124, 1538 | c.getJdTabSkuElement, 1539 | c.getJdTabSkuGroup 1540 | ], 1541 | this.groupTypeList[125] = [ 1542 | 125, 1543 | c.getZcTabSkuElement, 1544 | c.getZcTabSkuGroup 1545 | ], 1546 | this.groupTypeList[126] = [ 1547 | 126, 1548 | c.getLicaiSkuElement, 1549 | c.getLicaiSkuGroup 1550 | ], 1551 | this.groupTypeList[132] = [ 1552 | 132, 1553 | c.getHeightElement, 1554 | c.getHeightGroup 1555 | ], 1556 | this.groupTypeList[153] = [ 1557 | 153, 1558 | c.getBanner1to2Element, 1559 | c.getBanner1to2Group 1560 | ], 1561 | this.groupTypeList[154] = [ 1562 | 154, 1563 | c.getSignElement, 1564 | c.getSignGroup 1565 | ] 1566 | }, 1567 | callGroupTypeFunction: function (a, b, c) { 1568 | return a(b, c) 1569 | }, 1570 | assembleAndInit: function () { 1571 | var b = '', 1572 | d = a.resultData, 1573 | f = d.pin, 1574 | g = d.resultFloorList; 1575 | qyy.isJrUser = d.isJrUser, 1576 | qyy.isLogin && !qyy.isInApp && 0 != f && qyy.inAppLoginInFlag && e.unifyAppLogin(); 1577 | for (var h = 0, i = g.length; i > h; h++) { 1578 | for (var j = '', k = '', l = '', m = '', n = g[h], o = n.display, p = n.groupList, q = n.outH5Point, r = n.fjumpType, s = n.fjumpUrl, t = n.ftitle, u = n.fsubtitle, v = n.ftitleColor, w = n.fTitlePosition, x = n.fsubtitleColor, y = n.fbottomMargin, z = n.fbackgroundColor, A = n.fbackgroundBorder, B = 0, C = p.length; C > B; B++) if (o) { 1579 | var D = '', 1580 | E = p[B], 1581 | F = E, 1582 | G = E.groupType, 1583 | H = E.defaultShowtotal, 1584 | I = ''; 1585 | qyy.$obj.dataInput.data(G.toString(), H), 1586 | I = E.elementList ? E.elementList : E.elementIconList, 1587 | '' === k ? k = G : k; 1588 | for (var J = 0, K = I.length; K > J; J++) D += this.callGroupTypeFunction(this.groupTypeList[G][1], I[J], z); 1589 | j += this.callGroupTypeFunction(this.groupTypeList[G][2], D, F) 1590 | } 1591 | if (0 === k && this.focusCount++, '' !== t) { 1592 | var L = { 1593 | ftitle: t, 1594 | ftitleColor: v, 1595 | fsubtitle: u, 1596 | fsubtitleColor: x, 1597 | fjumpType: r, 1598 | fjumpUrl: s, 1599 | floorOutH5Point: q, 1600 | fTitlePosition: w 1601 | }; 1602 | l = c.getRowTitile(L) 1603 | } else m = 'hasTopPadding'; 1604 | var M = { 1605 | floorTitleStr: l, 1606 | floorStr: j, 1607 | floorType: k, 1608 | fbottomMargin: y, 1609 | fbackgroundBorder: A, 1610 | fbackgroundColor: z, 1611 | hasFloorTitleTopPadding: m 1612 | }; 1613 | o && (b += c.getFloor(M)) 1614 | } 1615 | qyy.$obj.wrap.append(b) 1616 | }, 1617 | init: function () { 1618 | this.initGroupTypeList(), 1619 | this.assembleAndInit() 1620 | } 1621 | }; 1622 | b.init() 1623 | }, 1624 | getUserGroupData: function (a) { 1625 | if (g.isApp() && setTimeout(function () { 1626 | if (qyy.canChangeAppColor) { 1627 | qyy.canChangeAppColor = !1; 1628 | var a = { 1629 | colorArr: [ 1630 | '#39404D', 1631 | '#39404D' 1632 | ] 1633 | }; 1634 | e.changeJrAppColor(a) 1635 | } 1636 | }, 50), !a.resultData) return !1; 1637 | var c = a.resultData, 1638 | d = c[1].nickName, 1639 | f = c[1].headSculpturer, 1640 | h = c[3].xbresultCode, 1641 | i = c[3].baiXYValue, 1642 | j = { 1643 | '000000': 0 == i ? '立即开通' : '小白信用' + i, 1644 | '0915': '立即开通', 1645 | '0916': '立即开通', 1646 | '0917': '全新升级', 1647 | '-1': '暂无数据' 1648 | }; 1649 | b('.member-user .name').text(d), 1650 | b('.member-user .header').attr('src', f), 1651 | b('#qyy-xbxy-title').text(j[h]) 1652 | }, 1653 | getTopUserHeaderData: function (a) { 1654 | if (a.resultData) { 1655 | var c = a.resultData, 1656 | d = ''; 1657 | c[16] && c[16].headSculpturer && (d = c[16].headSculpturer), 1658 | b('.section-36 .user-img').attr('src', d) 1659 | } else b('.header img').remove(), 1660 | b('.jr-header .header').append('
    '; 358 | 359 | $("#awardInfo").html(html); 360 | $("#JSignDialog").removeClass("hide"); 361 | 362 | } 363 | }, 364 | processExp: function (resultAjax) { 365 | if (resultAjax.res.code == 'DS104') { 366 | //风控用户 367 | var content = "运气不佳,领到一个空空的礼包"; 368 | $.mConfirm({ 369 | title: content, 370 | btnWraper: '朕知道了', 371 | handlerEvent: function (e) { 372 | 373 | }, 374 | confirmBack: function (e) { 375 | createMpingEvent("MJingDouDouble_Know", "", "", "","JingDou_Double"); 376 | var html = ''; 377 | $("#receiveAward").removeClass("status-toreceive").addClass("status-viewaward"); 378 | $("#receiveAward").html(html); 379 | e.remove(); 380 | } 381 | }) 382 | } else if (resultAjax.res.code == 'DS103') { 383 | //活动已结束 384 | var title = "来晚了,活动已经结束了"; 385 | var content = "去看看其他活动吧~"; 386 | 387 | $.mConfirm({ 388 | title: title, 389 | content:'

    ' + content +'

    ', 390 | btnWraper: '朕知道了', 391 | handlerEvent: function (e) { 392 | 393 | }, 394 | confirmBack: function (e) { 395 | createMpingEvent("MJingDouDouble_Know", "", "", "","JingDou_Double"); 396 | e.remove(); 397 | var link = "https://bean.m.jd.com"; 398 | var url = 'openApp.jdMobile://virtual?params={"sourceType" : "sale-act","sourceValue" : "jumpFromShare","category" : "jump","des" : "DM","dmurl" : "' + link + '"}'; 399 | toJDApp.to(url); 400 | } 401 | }) 402 | }else if (resultAjax.res.code == 'DS102') { 403 | //活动已结束 404 | var title = "来早了,活动还未开始"; 405 | var content = "去看看其他活动吧~"; 406 | 407 | $.mConfirm({ 408 | title: title, 409 | content:'

    ' + content +'

    ', 410 | btnWraper: '朕知道了', 411 | handlerEvent: function (e) { 412 | 413 | }, 414 | confirmBack: function (e) { 415 | createMpingEvent("MJingDouDouble_Know", "", "", "","JingDou_Double"); 416 | e.remove(); 417 | var link = "https://bean.m.jd.com"; 418 | var url = 'openApp.jdMobile://virtual?params={"sourceType" : "sale-act","sourceValue" : "jumpFromShare","category" : "jump","des" : "DM","dmurl" : "' + link + '"}'; 419 | toJDApp.to(url); 420 | } 421 | }) 422 | } else if (resultAjax.res.code == 'DS106') { 423 | //活动已结束 424 | var title = "完成双签才可领取礼包"; 425 | var content = "快去签到吧~"; 426 | $.mConfirm({ 427 | title: title, 428 | content:'

    ' + content +'

    ', 429 | btnWraper: '朕知道了', 430 | handlerEvent: function (e) { 431 | 432 | }, 433 | confirmBack: function (e) { 434 | createMpingEvent("MJingDouDouble_Know", "", "", "","JingDou_Double"); 435 | e.remove(); 436 | window.location.reload(); 437 | } 438 | }) 439 | } else { 440 | //其余异常 当做未领奖处理 441 | //活动已结束 442 | var content = "活动太火爆了,稍后再来吧~"; 443 | $.mConfirm({ 444 | title: content, 445 | btnWraper: '朕知道了', 446 | handlerEvent: function (e) { 447 | 448 | }, 449 | confirmBack: function (e) { 450 | createMpingEvent("MJingDouDouble_Know", "", "", "","JingDou_Double"); 451 | window.location.reload(); 452 | e.remove(); 453 | } 454 | }) 455 | } 456 | }, 457 | useAward: function (url,awardType) { 458 | var event_id = ""; 459 | var report_lvl = ""; 460 | if(awardType == 1){ 461 | event_id = "MJingDouHome_SKULevelFour1"; 462 | report_lvl = 4; 463 | } 464 | if(awardType == 2){ 465 | event_id = "MJingDouDouble_CoinUse"; 466 | } 467 | if(awardType == 3){ 468 | event_id = "MJingDouHome_ActivityLevelThree3"; 469 | report_lvl = 3; 470 | } 471 | createMpingEvent(event_id, "", "", "","JingDou_Double",report_lvl); 472 | if (url.indexOf("http") >= 0) { 473 | window.location.href = url; 474 | } else { 475 | if($("#isM").val() == 'true'){ 476 | toJDApp.to(url); 477 | }else{ 478 | //客户端内部直接openApp 479 | window.location.href = url; 480 | } 481 | } 482 | }, 483 | 484 | shareSign: function () { 485 | createMpingEvent("MJingDouDouble_Share", "", "", "","JingDou_Double"); 486 | var shareInfo = $("#counterSignShare").val(); 487 | if(shareInfo == ''){ 488 | var shareParam = { 489 | title: '一大波京豆、神券、金币等你领取', 490 | content: '来京东APP、京东金融APP签到,三重奖励天天领', 491 | url: location.origin + '/countersign/index.action', 492 | img: 'https://m.360buyimg.com/njmobilecms/jfs/t10393/117/1880465648/15598/ffc609c1/59e86165N3494fb59.png', 493 | channel: 'Wxfriends,Wxmoments,Sinaweibo', 494 | callback: null, // 不要依赖回调,不要在回调中加入业务逻辑,不要在回调中处理耗时的操作 495 | clickcallback:null, // 5.2新增 分享面板中点击分享渠道成功后回调 注意 sendDirectShare 不支持这个回调方法 496 | qrparam:null, // 具体配置详见 5.2新增 二维码分享 497 | timeline_title:'' // 5.4新增 朋友圈字段 498 | } 499 | }else{ 500 | var activityShare = $.parseJSON(shareInfo); 501 | var shareParam = { 502 | title: activityShare.shareTitle, 503 | content: activityShare.shareContent, 504 | url: activityShare.shareUrl, 505 | img: activityShare.shareImage, 506 | channel: 'Wxfriends,Wxmoments', 507 | callback: null, // 不要依赖回调,不要在回调中加入业务逻辑,不要在回调中处理耗时的操作 508 | clickcallback:null, // 5.2新增 分享面板中点击分享渠道成功后回调 注意 sendDirectShare 不支持这个回调方法 509 | qrparam:null, // 具体配置详见 5.2新增 二维码分享 510 | timeline_title:'' // 5.4新增 朋友圈字段 511 | } 512 | } 513 | jdShare.callSharePane(shareParam); 514 | }, 515 | 516 | 517 | }; 518 | -------------------------------------------------------------------------------- /reference/打卡.md: -------------------------------------------------------------------------------- 1 | # 打卡 2 | 3 | ## 日常打卡 4 | 5 | `GET https://bk.jd.com/m/money/home/daka.html` 6 | 7 | #### 打卡成功 8 | 9 | ```json 10 | { 11 | "resultCode": "0000", 12 | "resultMessage": "打卡成功", 13 | "data": null, 14 | "success": true 15 | } 16 | ``` 17 | 18 | #### 打卡失败, 今日已领 19 | 20 | ```json 21 | { 22 | "resultCode": "0001", 23 | "resultMessage": "已经打过卡了,每天只能打一次!", 24 | "data": null, 25 | "success": false 26 | } 27 | ``` 28 | 29 | #### 打卡失败, 需先完成领钢镚任务 30 | 31 | ```json 32 | { 33 | "resultCode": "0003", 34 | "resultMessage": "请先领取钢镚", 35 | "data": null, 36 | "success": false 37 | } 38 | ``` 39 | 40 | ## 领钢镚任务 41 | 42 | `GET https://bk.jd.com/m/money/home/recDoJobMoney.html?pcId=82` 43 | 44 | #### 领取成功 45 | 46 | ```json 47 | { 48 | "resultCode": null, 49 | "resultMessage": null, 50 | "data": null, 51 | "success": true 52 | } 53 | ``` 54 | 55 | #### 领取失败 (比如已经领了...) 56 | 57 | ```json 58 | { 59 | "resultCode": "-1", 60 | "resultMessage": "没有找到当前奖品", 61 | "data": null, 62 | "success": false 63 | } 64 | ``` 65 | -------------------------------------------------------------------------------- /reference/新版客户端京豆签到.md: -------------------------------------------------------------------------------- 1 | ### 未登录 2 | 3 | ```json 4 | { 5 | "code": "3" 6 | } 7 | ``` 8 | 9 | 10 | ### 参数错误, 如 `client` 或 `functionId` 不对 11 | 12 | ```json 13 | { 14 | "code": "1", 15 | "echo": "required string parameter 'client' is not present" 16 | } 17 | ``` 18 | 19 | 20 | ### 签到信息: 21 | 22 | ```json 23 | { 24 | "code": "0", 25 | "data": { 26 | "status": "2", 27 | "totalUserBean": "604", 28 | "signRuleInfo": { 29 | "signCycle": "2", 30 | "title": "连续7天签到得奖励" 31 | }, 32 | "continuousDays": "2", 33 | "awardDaysLimit": "7" 34 | } 35 | } 36 | ``` 37 | 38 | `data`.`status`: `2`: 已签到, `4`: 未签到, `5`: 未登录 39 | 40 | 41 | ### 签到: 成功 42 | 43 | ```json 44 | { 45 | "code": "0", 46 | "data": { 47 | "status": "1", 48 | "signShowType": "3", 49 | "signShowBean": { 50 | "signText": "签到成功,已领signAward京豆,翻牌得奖励", 51 | "signAward": "3", 52 | "complated": 0, 53 | "cardText": "每日可翻1张牌", 54 | "awardList": [{}, {}, {}] 55 | } 56 | } 57 | } 58 | ``` 59 | 60 | 61 | ### 签到: 已签到 62 | 63 | ```json 64 | { 65 | "code": "0", 66 | "data": { 67 | "status": "2", 68 | "signShowType": "3", 69 | "signShowBean": { 70 | "signText": "今日已签到,已翻牌,共领signAward京豆", 71 | "signAward": "5", 72 | "complated": 1, 73 | "cardText": "今日已翻1张牌", 74 | "awardList": [{}, {}, {}] 75 | } 76 | } 77 | } 78 | ``` 79 | 80 | 81 | ### 翻牌: 成功 82 | 83 | ```json 84 | { 85 | "code": "0", 86 | "data": { 87 | "signText": "今日已签到,已翻牌,共领signAward京豆", 88 | "signAward": "5", 89 | "complated": 1, 90 | "cardText": "今日已翻1张牌", 91 | "awardList": [{}, {}, {}] 92 | } 93 | } 94 | ``` 95 | 96 | 97 | ### 翻牌: 已翻牌 98 | 99 | ```json 100 | { 101 | "code": "0", 102 | "errorCode": "F301", 103 | "errorMessage": "已翻牌" 104 | } 105 | ``` 106 | -------------------------------------------------------------------------------- /reference/流量加油站.md: -------------------------------------------------------------------------------- 1 | ### 未登录 2 | 3 | ```json 4 | { 5 | "message": "用户未登录", 6 | "businessCode": "-99", 7 | "code": "3", 8 | "success": false 9 | } 10 | ``` 11 | 12 | ### 首页: 13 | 14 | ```json 15 | { 16 | "code": "0", 17 | "signInfo": { 18 | "signCode": "0", 19 | "message": "签到领取今日流量" 20 | }, 21 | "success": true 22 | } 23 | ``` 24 | 25 | ```json 26 | { 27 | "code": "0", 28 | "signInfo": { 29 | "signCode": "403", 30 | "message": "您今日已签到" 31 | }, 32 | "success": true 33 | } 34 | ``` 35 | 36 | ### 签到: 37 | 38 | ```json 39 | { 40 | "message": "您今日已签到", 41 | "errorMessage": "签到成功,流量+1M", 42 | "pin": "***", 43 | "data": 100, 44 | "code": "0", 45 | "success": true 46 | } 47 | ``` 48 | 49 | ```json 50 | { 51 | "errorMessage": "您已成功参与", 52 | "pin": "***", 53 | "errorCode": "302", 54 | "code": "0", 55 | "success": true 56 | } 57 | ``` 58 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | PyQt5==5.10.1 2 | pyquery 3 | requests 4 | --------------------------------------------------------------------------------