├── .github
└── workflows
│ ├── Auto.yml
│ └── anker1209.yml
├── .gitignore
├── Jd_unbindCard.conf
├── README.md
├── faq.json
├── image
├── IMG_7050.PNG
├── IMG_7065.PNG
├── IMG_7143.PNG
├── IMG_7144.png
├── IMG_7145.png
├── IMG_7146.png
├── IMG_7147.png
├── IMG_7150.png
├── IMG_7151.png
├── IMG_8927.PNG
├── anker.JPG
├── bg_head_new.png
├── none.cpp
├── screenzy-1614423457282-yd.png
├── screenzy-1614423524222-dx.png
└── screenzy-1614423603123-lt.png
├── install.json
├── package.json
├── scripts
├── Birthday.js
├── ChinaMobile_2021.js
├── ChinaTelecom_2021.js
├── ChinaUnicom_2021.js
├── Chinaunicom.js
├── JD-in-one-v2.js
└── none.cpp
└── upcoming.json
/.github/workflows/Auto.yml:
--------------------------------------------------------------------------------
1 | # 工作流名称
2 | name: Auto master
3 | # 触发工作流事件
4 | on:
5 | schedule:
6 | # cron 表达式,格林威治时间 (GMT) 每小时0分钟开始执行
7 | - cron: '0 */1 * * *'
8 | # 手动触发
9 | workflow_dispatch:
10 | watch:
11 | types: started # Star触发
12 | repository_dispatch:
13 | types: anker1209-Scriptable # 上游作者库名
14 |
15 | # 工作流运行由可以顺序或并行运行的一个或多个作业组成
16 | jobs:
17 | # 此工作流程包含一个名为"repo-sync"的作业
18 | repo-sync:
19 | env:
20 | PAT: ${{ secrets.PAT }}
21 | runs-on: ubuntu-latest
22 | if: github.event.repository.owner.id == github.event.sender.id
23 | # 步骤代表将作为工作一部分执行的一系列任务
24 | steps:
25 | # 在$ GITHUB_WORKSPACE下签出您的存储库,以便您的工作可以访问它
26 | - uses: actions/checkout@v2
27 | with:
28 | persist-credentials: false
29 | # 使用sync 同步
30 | - name: sync anker1209-Scriptable # 需要同步的作者库名
31 | uses: repo-sync/github-sync@v2
32 | if: env.PAT
33 | with:
34 | # 需要 clone 的上游仓库地址
35 | source_repo: "https://github.com/anker1209/Scriptable.git"
36 | # 需要clone上游作者的分支名
37 | source_branch: "main"
38 | # 需要clone到自己项目的分支名
39 | destination_branch: "main"
40 | github_token: ${{ secrets.PAT }}
--------------------------------------------------------------------------------
/.github/workflows/anker1209.yml:
--------------------------------------------------------------------------------
1 | name: Scriptable-sync
2 | on:
3 | push:
4 | branches:
5 | - main
6 | schedule:
7 | # 格林威治时间 (GMT) 每日01时开始执行
8 | - cron: '0 1 * * *'
9 | workflow_dispatch:
10 | watch:
11 | types: started
12 | repository_dispatch:
13 | types: sync-Scriptable/Scriptable
14 | jobs:
15 | repo-sync:
16 | env:
17 | PAT: ${{ secrets.PAT }}
18 | runs-on: ubuntu-latest
19 | if: github.event.repository.owner.id == github.event.sender.id
20 | steps:
21 | - uses: actions/checkout@v2
22 | with:
23 | persist-credentials: false
24 |
25 | - name: sync Scriptable/Scriptable
26 | uses: repo-sync/github-sync@v2
27 | if: env.PAT
28 | with:
29 | source_repo: "https://github.com/anker1209/Scriptable.git"
30 | source_branch: "main"
31 | destination_branch: "Scriptable"
32 | github_token: ${{ secrets.PAT }}
33 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # testing
7 | /coverage
8 |
9 | # production
10 | /build
11 | /.history
12 | /.vscode
13 | /scripts/DmYY.js
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
25 | /.idea
26 |
--------------------------------------------------------------------------------
/Jd_unbindCard.conf:
--------------------------------------------------------------------------------
1 | // @ScriptName 取消绑定京东店铺会员
2 | // @Author @anker1209
3 | // @Function 点击会员卡直达注销页面
4 | // @ScriptURL https://raw.githubusercontent.com/anker1209/Scriptable/main/Jd_unbindCard.conf
5 |
6 | hostname = shopmember.m.jd.com
7 |
8 | ^https:\/\/shopmember\.m\.jd\.com\/shopcard\/\?(venderId=[0-9]+).* url 302 https:\/\/shopmember\.m\.jd\.com\/member\/memberCloseAccount\?$1
9 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Scriptable
2 |
3 | [电报群](https://t.me/Scriptable_JS):https://t.me/Scriptable_JS
4 |
5 | ## 中国联通
6 |
7 | 
8 |
9 | 推荐使用Boxjs代理缓存:
10 |
11 | - [BoxJs 使用教程](https://chavyleung.gitbook.io/boxjs/)
12 |
13 | - [BoxJs 教程视频](https://youtu.be/eIpBrRxiy0w)
14 |
15 | cookie获取方法:
16 |
17 | #### QuanX:
18 |
19 | ```ini
20 | [mitm]
21 | hostname = act.10010.com, m.client.10010.com
22 |
23 | [rewrite_local]
24 | # 获取联通cookie
25 | ^https:\/\/m\.client\.10010\.com\/mobileserviceimportant\/smart\/smartwisdomCommon url script-request-header https://raw.githubusercontent.com/dompling/Script/master/10010/index.js
26 | ```
27 |
28 | #### Surge:
29 |
30 | ```ini
31 | [MITM]
32 | hostname = act.10010.com, m.client.10010.com
33 |
34 | [Script]
35 | Rewrite: 获取联通cookie = type=http-request,pattern=^https:\/\/m\.client\.10010\.com\/mobileserviceimportant\/smart\/smartwisdomCommon,requires-body=1,max-size=0,script-path=https://raw.githubusercontent.com/dompling/Script/master/10010/index.js,script-update-interval=0
36 | ```
37 |
38 | > Boxjs添加YaYa美女订阅链接(感谢YaYa辛苦付出~):
39 | https://raw.githubusercontent.com/dompling/Script/master/dompling.boxjs.json
40 |
41 | > 打开中国联通app --> 首页的流量查询获取Cookie;
42 |
43 | > 运行脚本,点击基础设置-->BoxJS域名,设置为你自己的BoxJS域名,再次运行脚本,选择代理缓存,获取缓存cookie;
44 |
45 | ## 中国移动(暂时不可用)
46 |
47 | 
48 |
49 | 推荐使用Boxjs代理缓存:
50 |
51 | - [BoxJs 使用教程](https://chavyleung.gitbook.io/boxjs/)
52 |
53 | - [BoxJs 教程视频](https://youtu.be/eIpBrRxiy0w)
54 |
55 | cookie获取方法:
56 |
57 | #### QuanX:
58 |
59 | ```ini
60 | [mitm]
61 | hostname = clientaccess.10086.cn
62 |
63 | [rewrite_local]
64 | ^https:\/\/clientaccess.10086.cn\/biz-orange\/LN\/uamrandcodelogin\/autoLogin url script-request-body https://raw.githubusercontent.com/chavyleung/scripts/master/10086/10086.fee.cookie.js
65 | ^https:\/\/clientaccess.10086.cn\/biz-orange\/BN\/realFeeQuery\/getRealFee url script-request-body https://raw.githubusercontent.com/chavyleung/scripts/master/10086/10086.fee.cookie.js
66 | ```
67 |
68 | #### Surge:
69 |
70 | ```ini
71 | [mitm]
72 | hostname = clientaccess.10086.cn
73 |
74 | [Script]
75 | Rewrite: CMCC = type=http-request,pattern=^https:\/\/clientaccess.10086.cn\/biz-orange\/LN\/uamrandcodelogin\/autoLogin,script-path=https://raw.githubusercontent.com/chavyleung/scripts/master/10086/10086.fee.cookie.js,requires-body=true,debug=true
76 | Rewrite: CMCC = type=http-request,pattern=^https:\/\/clientaccess.10086.cn\/biz-orange\/BN\/realFeeQuery\/getRealFee,script-path=https://raw.githubusercontent.com/chavyleung/scripts/master/10086/10086.fee.cookie.js,requires-body=true,debug=true
77 | ```
78 |
79 | > Boxjs添加chavy大佬订阅链接:
80 | https://raw.githubusercontent.com/chavyleung/scripts/master/box/chavy.boxjs.json
81 |
82 | > 打开中国移动APP(非10086),获取一次cookie,点击话费余额再获取一次cookie,若打开app时没有提示获取会话,请在 “我的” --> “设置” --> “登陆设置” 中关闭指纹/faceID登陆,打开自动登录,登陆以后关闭后台,重新打开app获取cookie(注:中国移动app以短信验证码方式登录,本机一键登录可能获取不到cookie);
83 |
84 | > 运行脚本,点击基础设置-->BoxJS域名,设置为你自己的BoxJS域名,再次运行脚本,选择代理缓存,获取缓存cookie
85 |
86 | ## 中国电信
87 |
88 | 
89 |
90 | 推荐使用Boxjs代理缓存:
91 |
92 | - [BoxJs 使用教程](https://chavyleung.gitbook.io/boxjs/)
93 |
94 | - [BoxJs 教程视频](https://youtu.be/eIpBrRxiy0w)
95 |
96 | cookie获取方法(也可以参考[作者Sunert的教程](https://github.com/Sunert/Script/tree/master/TaskConf/dianxin)):
97 |
98 | #### QuanX:
99 |
100 | ```ini
101 | [mitm]
102 | hostname = e.189.cn, mkt.21cn.com
103 |
104 | [rewrite_local]
105 | ^https?:\/\/e\.189\.cn\/store\/user\/package_detail\.do url script-request-header https://raw.githubusercontent.com/Sunert/Script/master/Task/telecomSky.js
106 | https:\/\/mkt\.21cn\.com\/mkt\/api\/user\/queryActivityInfo\.do\?activityId=\d+ url script-request-header https://raw.githubusercontent.com/Sunert/Script/master/Task/telecomSky.js
107 | ```
108 |
109 | #### Surge:
110 |
111 | ```ini
112 | [mitm]
113 | hostname = e.189.cn, mkt.21cn.com
114 |
115 | [Script]
116 | 电信天翼套餐 = type=http-request,pattern=https:\/\/mkt\.21cn\.com\/mkt\/api\/user\/queryActivityInfo\.do\?activityId=\d+,script-path=https://raw.githubusercontent.com/Sunert/Script/master/Task/telecomSky.js
117 | 电信天翼套餐 = type=http-request,pattern=^https?:\/\/e\.189\.cn\/store\/user\/package_detail\.do,script-path=https://raw.githubusercontent.com/Sunert/Script/master/Task/telecomSky.js
118 | ```
119 | > Boxjs添加Sunert大佬订阅链接:
120 | https://raw.githubusercontent.com/Sunert/Script/master/Task/sunert.boxjs.json
121 |
122 | > 打开天翼账号中心,获取cookie;
123 |
124 | > 运行脚本,点击基础设置-->BoxJS域名,设置为你自己的BoxJS域名,再次运行脚本,选择代理缓存,获取缓存cookie;
125 |
126 | > 无代理缓存的,请使用Stream类抓包APP进行手动抓包,获取cookie后填入脚本内注释位置或运行脚本——>账户设置——>手动输入;
127 |
128 | > 脚本内提供网站登录获取cookie,无代理缓存的可尝试网站登录获取cookie
129 |
130 | ## JD_in_one
131 |
132 | 
133 | 
134 |
135 | # 赞赏码
136 |
137 |
--------------------------------------------------------------------------------
/faq.json:
--------------------------------------------------------------------------------
1 | {
2 | "update": "更新日期:2021.04.13",
3 | "desc": "随时更新,遇到问题请先在此查询。如无解决办法,请及时向我反馈。",
4 | "height": "59",
5 | "data": [{
6 | "name": "设置问题",
7 | "item": [{
8 | "question": "▶ Scriptable如何显示行号?",
9 | "answer": "点击scriptable左上角齿轮 —> Editor —> show line numbers。",
10 | "height": "80"
11 | },
12 | {
13 | "question": "▶ 头像没有显示/没有更新",
14 | "answer": "1、京东APP上传头像;2、[重置设置][重置缓存];3、运行脚本。",
15 | "height": "80"
16 | },
17 | {
18 | "question": "▶ 头像下方PLUS标志显示不正常",
19 | "answer": "[重置设置][重置缓存]后重新运行脚本。",
20 | "height": "66"
21 | },
22 | {
23 | "question": "▶ 参数设置如何保留?",
24 | "answer": "参数设置绑定脚本文件名,只要文件名未变,参数将一直作用于该文件。请勿随意更改脚本文件名,更改文件名后,之前设置的所有参数将重置。",
25 | "height": "94"
26 | }
27 | ]
28 | }, {
29 | "name": "数据问题",
30 | "item": [{
31 | "question": "▶ 为什么京豆总数、京享值都变成0了?",
32 | "answer": "若出现京豆总数、京享值为0,未知用户,执行以下操作:“文件”app —> iCloud 云盘 —> scriptable,删除里面的JD_in_one文件夹。tips:请勿使用多设备在该组件里使用同一cookie。",
33 | "height": "108"
34 | },
35 | {
36 | "question": "▶ 提示“请登录您的京东账户/no login”",
37 | "answer": "如果出现此类提示,你的cookie过期了,重新抓cookie。cookie恢复后如果还出现此类提示,请重置缓存,或者将缓存时间临时改为0后运行脚本即可。",
38 | "height": "94"
39 | },
40 | {
41 | "question": "",
42 | "answer": "",
43 | "height": "66"
44 | }
45 | ]
46 | }]
47 | }
48 |
--------------------------------------------------------------------------------
/image/IMG_7050.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Semporia/Scriptable/53bc0fdac648e2a2894db986448da33c62506f23/image/IMG_7050.PNG
--------------------------------------------------------------------------------
/image/IMG_7065.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Semporia/Scriptable/53bc0fdac648e2a2894db986448da33c62506f23/image/IMG_7065.PNG
--------------------------------------------------------------------------------
/image/IMG_7143.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Semporia/Scriptable/53bc0fdac648e2a2894db986448da33c62506f23/image/IMG_7143.PNG
--------------------------------------------------------------------------------
/image/IMG_7144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Semporia/Scriptable/53bc0fdac648e2a2894db986448da33c62506f23/image/IMG_7144.png
--------------------------------------------------------------------------------
/image/IMG_7145.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Semporia/Scriptable/53bc0fdac648e2a2894db986448da33c62506f23/image/IMG_7145.png
--------------------------------------------------------------------------------
/image/IMG_7146.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Semporia/Scriptable/53bc0fdac648e2a2894db986448da33c62506f23/image/IMG_7146.png
--------------------------------------------------------------------------------
/image/IMG_7147.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Semporia/Scriptable/53bc0fdac648e2a2894db986448da33c62506f23/image/IMG_7147.png
--------------------------------------------------------------------------------
/image/IMG_7150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Semporia/Scriptable/53bc0fdac648e2a2894db986448da33c62506f23/image/IMG_7150.png
--------------------------------------------------------------------------------
/image/IMG_7151.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Semporia/Scriptable/53bc0fdac648e2a2894db986448da33c62506f23/image/IMG_7151.png
--------------------------------------------------------------------------------
/image/IMG_8927.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Semporia/Scriptable/53bc0fdac648e2a2894db986448da33c62506f23/image/IMG_8927.PNG
--------------------------------------------------------------------------------
/image/anker.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Semporia/Scriptable/53bc0fdac648e2a2894db986448da33c62506f23/image/anker.JPG
--------------------------------------------------------------------------------
/image/bg_head_new.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Semporia/Scriptable/53bc0fdac648e2a2894db986448da33c62506f23/image/bg_head_new.png
--------------------------------------------------------------------------------
/image/none.cpp:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/image/screenzy-1614423457282-yd.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Semporia/Scriptable/53bc0fdac648e2a2894db986448da33c62506f23/image/screenzy-1614423457282-yd.png
--------------------------------------------------------------------------------
/image/screenzy-1614423524222-dx.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Semporia/Scriptable/53bc0fdac648e2a2894db986448da33c62506f23/image/screenzy-1614423524222-dx.png
--------------------------------------------------------------------------------
/image/screenzy-1614423603123-lt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Semporia/Scriptable/53bc0fdac648e2a2894db986448da33c62506f23/image/screenzy-1614423603123-lt.png
--------------------------------------------------------------------------------
/install.json:
--------------------------------------------------------------------------------
1 | {
2 | "author": "脑瓜",
3 | "scriptable": true,
4 | "icon": "https://avatars2.githubusercontent.com/u/76637082?s=460&u=32c8666ab3e3e7e0aa5c2c570c9e8342f262a925&v=4",
5 | "repo": "https://github.com/anker1209/Scriptable",
6 | "apps": [
7 | {
8 | "version": "2.2.7",
9 | "author": "脑瓜",
10 | "description": "显示京东用户信息、物流信息、白条还款信息、京豆K线图、金豆收支、钢镚、金贴、红包信息",
11 | "scriptURL": "https://raw.githubusercontent.com/anker1209/Scriptable/main/scripts/JD-in-one-v2.js",
12 | "thumb": "https://vkceyugu.cdn.bspapp.com/VKCEYUGU-b1ebbd3c-ca49-405b-957b-effe60782276/e0d872b9-4866-4abf-87f4-a681083e6e04.png",
13 | "name": "JD-in-one-v2",
14 | "title": "JD-in-one-v2",
15 | "depend": [
16 | {
17 | "name": "DmYY",
18 | "scriptURL": "https://raw.githubusercontent.com/dompling/Scriptable/master/Scripts/DmYY.js"
19 | }
20 | ],
21 | "html": [
22 | "作者:@anker1209",
23 | "
",
24 | "
",
25 | "
更新说明
",
26 | "v2.2.7",
27 | "默认账号设置成功时,若无参数输入则缓存",
28 | "v2.2.6",
29 | "脚本调整为直接读取BoxJS内的CK,多账号用户无需点击代理缓存读取CK",
30 | "v2.2.5",
31 | "增加东东农场种植进度",
32 | "缓存目录默认为Local,可选iCloud",
33 | "修复京享值显示",
34 | "红包修改为显示所有红包",
35 | "修复图标不显示",
36 | "取消过期京豆显示",
37 | "
",
38 | "使用说明
"
39 | ],
40 | "images": [
41 | "https://raw.githubusercontent.com/anker1209/Scriptable/main/image/IMG_7150.png",
42 | "https://raw.githubusercontent.com/anker1209/Scriptable/main/image/IMG_7151.png"
43 | ]
44 | },
45 | {
46 | "version": "1.0.3",
47 | "author": "2Ya",
48 | "description": "脚本来自2Ya破壳日,修复农历生日显示错误,有任何问题@anker1209",
49 | "scriptURL": "https://raw.githubusercontent.com/anker1209/Scriptable/main/scripts/Birthday.js",
50 | "thumb": "https://vkceyugu.cdn.bspapp.com/VKCEYUGU-imgbed/d0eee765-d320-490d-a611-5d1b49590441.png",
51 | "name": "Birthday",
52 | "title": "破壳日",
53 | "depend": [
54 | {
55 | "name": "DmYY",
56 | "scriptURL": "https://raw.githubusercontent.com/dompling/Scriptable/master/Scripts/DmYY.js"
57 | },
58 | {
59 | "name": "Calendar",
60 | "scriptURL": "https://raw.githubusercontent.com/dompling/Scriptable/master/Scripts/Calendar.js"
61 | }
62 | ],
63 | "html": [
64 | "原作者:@dompling",
65 | "
",
66 | "
",
67 | "更新说明
",
68 | "v1.0.3 修改年龄/相识显示",
69 | "v1.0.2 修复当月显示bug",
70 | "v1.0.1 增加年、月、天显示",
71 | "
",
72 | "日期填写说明
",
73 | "生日配置
",
74 | "如果过阳历生日,第二行填写阳历生日,第三行填写false或者不填",
75 | "如果过农历生日,第二行填写农历日期,第三行填写true",
76 | "无论阳历还是农历,日期格式均为年-月-日,如:2020-01-01",
77 | "第四行填写阳历日期"
78 | ],
79 | "images": [
80 | "https://raw.githubusercontent.com/anker1209/Scriptable/main/image/IMG_7065.PNG"
81 | ]
82 | },
83 | {
84 | "version": "2.1.0",
85 | "author": "脑瓜",
86 | "description": "中国联通小组件,两种模式,默认为圆环进度条模式,主屏幕长按小组件-->编辑小组件-->Parameter,输入1,使用文字模式",
87 | "scriptURL": "https://raw.githubusercontent.com/anker1209/Scriptable/main/scripts/ChinaUnicom_2021.js",
88 | "thumb": "https://vkceyugu.cdn.bspapp.com/VKCEYUGU-imgbed/34ebdddc-90a8-4eb7-828b-f934c7386e12.png",
89 | "name": "Chinaunicom_2021",
90 | "title": "中国联通",
91 | "depend": [
92 | {
93 | "name": "DmYY",
94 | "scriptURL": "https://raw.githubusercontent.com/dompling/Scriptable/master/Scripts/DmYY.js"
95 | }
96 | ],
97 | "html": [
98 | "作者:@anker1209",
99 | "
",
100 | "教程:https://github.com/anker1209/Scriptable",
101 | "
",
102 | "
",
103 | "更新说明
",
104 | "v2.1.0",
105 | "修改cookie获取方式",
106 | "
"
107 | ],
108 | "images": [
109 | "https://raw.githubusercontent.com/anker1209/Scriptable/main/image/screenzy-1614423603123-lt.png"
110 | ]
111 | },
112 | {
113 | "version": "1.1.0",
114 | "author": "脑瓜",
115 | "description": "中国电信小组件,两种模式,默认为圆环进度条模式,主屏幕长按小组件-->编辑小组件-->Parameter,输入1,使用文字模式",
116 | "scriptURL": "https://raw.githubusercontent.com/anker1209/Scriptable/main/scripts/ChinaTelecom_2021.js",
117 | "thumb": "https://vkceyugu.cdn.bspapp.com/VKCEYUGU-b1ebbd3c-ca49-405b-957b-effe60782276/f12609b2-bf20-4993-be0f-99572d70d1b2.png",
118 | "name": "ChinaTelecom_2021",
119 | "title": "中国电信",
120 | "depend": [
121 | {
122 | "name": "DmYY",
123 | "scriptURL": "https://raw.githubusercontent.com/dompling/Scriptable/master/Scripts/DmYY.js"
124 | }
125 | ],
126 | "html": [
127 | "作者:@anker1209",
128 | "
",
129 | "教程:https://github.com/anker1209/Scriptable",
130 | "
",
131 | "
",
132 | "更新说明
",
133 | "v1.1.0",
134 | "更新设置页面图标",
135 | "
"
136 | ],
137 | "images": [
138 | "https://raw.githubusercontent.com/anker1209/Scriptable/main/image/screenzy-1614423524222-dx.png"
139 | ]
140 | },
141 | {
142 | "version": "1.0.1",
143 | "author": "脑瓜",
144 | "description": "中国移动小组件,两种模式,默认为圆环进度条模式,主屏幕长按小组件-->编辑小组件-->Parameter,输入1,使用文字模式",
145 | "scriptURL": "https://raw.githubusercontent.com/anker1209/Scriptable/main/scripts/ChinaMobile_2021.js",
146 | "thumb": "https://vkceyugu.cdn.bspapp.com/VKCEYUGU-b1ebbd3c-ca49-405b-957b-effe60782276/3270c85e-2904-44cc-85cd-8de325b05743.png",
147 | "name": "ChinaMobile_2021",
148 | "title": "中国移动",
149 | "depend": [
150 | {
151 | "name": "DmYY",
152 | "scriptURL": "https://raw.githubusercontent.com/dompling/Scriptable/master/Scripts/DmYY.js"
153 | },
154 | {
155 | "name": "crypto-js",
156 | "scriptURL": "https://raw.githubusercontent.com/dompling/Scriptable/master/Scripts/crypto-js.min.js"
157 | }
158 | ],
159 | "html": [
160 | "作者:@anker1209",
161 | "
",
162 | "教程:https://github.com/anker1209/Scriptable",
163 | "
",
164 | "
",
165 | "更新说明
",
166 | "v1.0.1",
167 | "更新渐变色数组"
168 | ],
169 | "images": [
170 | "https://raw.githubusercontent.com/anker1209/Scriptable/main/image/screenzy-1614423457282-yd.png"
171 | ]
172 | }
173 | ]
174 | }
175 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "scriptable-types",
3 | "version": "1.0.0",
4 | "author": "2Ya",
5 | "description": "",
6 | "main": "index.js",
7 | "keywords": [
8 | "scriptable",
9 | "ios",
10 | "widget"
11 | ],
12 | "license": "ISC",
13 | "devDependencies": {
14 | "@types/scriptable-ios": "^1.6.1"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/scripts/Birthday.js:
--------------------------------------------------------------------------------
1 | // Variables used by Scriptable.
2 | // These must be at the very top of the file. Do not edit.
3 | // icon-color: pink; icon-glyph: birthday-cake;
4 | // Author: 2Ya UI: 脑瓜 https://t.me/Scriptable_JS
5 | // 该脚本依赖DmYY及Calendar: https://github.com/dompling/Scriptable/tree/master/Scripts
6 | // version:1.0.3
7 | // update:2021/03/14
8 |
9 | // 添加require,是为了vscode中可以正确引入包,以获得自动补全等功能
10 | if (typeof require === "undefined") require = importModule;
11 | const { DmYY, Runing } = require("./DmYY");
12 | const { Calendar } = require("./Calendar");
13 | const $ = new Calendar();
14 | // #####################设置#####################
15 | const extraTextColor = "fc8ac3" //环形进度条中心背景颜色及名字、meetDay颜色
16 | const ringColor = "fc5ead" //环形进度条颜色
17 | const nameTextSize = 15 // 名字大小
18 | const meetDayTextSize = 25 // meetDay文字大小
19 | const ringSize = 60 // 环形进度条大小
20 | const mainTextSize = 13 // 倒数、农历、生日文字大小
21 | const lineHeight = 8 // 倒数、农历、生日文字行间距大小
22 | const leftImageSize = 180 // 左侧图片宽度
23 | //##############################################
24 | let candle = new Request("https://vkceyugu.cdn.bspapp.com/VKCEYUGU-imgbed/ff304168-6cd3-4b5c-bb26-05ae2538f147.png")
25 | let ringIcon = await candle.loadImage()
26 | let countIcon = SFSymbol.named("hourglass.bottomhalf.fill").image;
27 | let lunarIcon = SFSymbol.named("25.square.fill").image; // 农历图标数字
28 | let birthIcon = SFSymbol.named("app.gift.fill").image;
29 |
30 | class Widget extends DmYY {
31 | constructor(arg) {
32 | super(arg);
33 | this.name = "破壳日";
34 | this.en = "birthday";
35 | this.logo ="";
36 | this.LEFT_IMG_KEY = this.FILE_MGR_LOCAL.joinPath(
37 | this.FILE_MGR_LOCAL.documentsDirectory(),
38 | `left_image_${this.SETTING_KEY}.jpg`,
39 | );
40 | this.defaultData = { ...this.defaultData, ...this.settings[this.en] };
41 | if (config.runsInApp) {
42 | this.registerAction("基础设置",this.setWidgetConfig);
43 | this.registerAction("生日配置", this.setWidgetInitConfig);
44 | this.registerAction("头像设置", this.setLeftWidgetImage);
45 | this.registerAction("代理缓存", this.setWidgetBoxJSConfig);
46 | }
47 | }
48 |
49 | defaultData = {
50 | username: "", // 姓名
51 | time: "", // 生日日期
52 | nongli: "", // 农历生日
53 | eday: "", //相识
54 | isLeapMonth: false, //如果是农历闰月第四个参数赋值true即可
55 | };
56 |
57 | contentText = {};
58 |
59 | init = async () => {
60 | try {
61 | this.getCalendarData();
62 | } catch (e) {
63 | console.log(e);
64 | }
65 | };
66 |
67 | getAge = (beginStr) => {
68 | let tmpBirth = {};
69 | tmpBirth.year = 0;
70 | tmpBirth.month = 0;
71 | tmpBirth.day = 0;
72 |
73 | if(beginStr == null || beginStr == '') {
74 | return;
75 | }
76 | let startDate = new Date(beginStr.replace(/-/g, "/"));
77 | let today = new Date();
78 |
79 | let startYear = startDate.getFullYear();
80 | let endYear = today.getFullYear();
81 | let startMonth = startDate.getMonth() + 1;
82 | let endMonth = today.getMonth() + 1;
83 | let startDay = startDate.getDate();
84 | let endDay = today.getDate();
85 | let allDays = 0;
86 | //准确的每个月天数数组,判断闰年平年。
87 | let allDayArr = [];
88 | //当月计算
89 | if(startYear == endYear && startMonth == endMonth) {
90 | tmpBirth.day = endDay - startDay;
91 | return tmpBirth;
92 | }
93 | //正常计算
94 | for(let i = startYear; i <= endYear; i++) {
95 | let currYear = 365
96 | let yearMonth = 12;
97 | if(((i % 4 == 0 && i % 100 !== 0) || i % 400 == 0)) {
98 | allDays += 366;
99 | currYear = 366;
100 | }
101 | let currMonth = 1;
102 | if(i == startYear){
103 | currMonth = startMonth;
104 | }
105 | if(i == endYear){
106 | yearMonth = endMonth;
107 | }
108 | //闰年计算
109 | for(let m = currMonth; m <= yearMonth; m++) {
110 | let fullDays = 30;
111 |
112 | if(m == 1 || m == 3 || m == 8 || m == 10 || m == 12) {
113 | fullDays = 31
114 | } else if(m == 2) {
115 | if(((i % 4 == 0 && i % 100 !== 0) || i % 400 == 0)){
116 | fullDays = 29;
117 | } else {
118 | fullDays = 28;
119 | }
120 | }
121 | let dayObj = {
122 | fullDays:fullDays,
123 | currDays:fullDays
124 | };
125 | if(m == startMonth && i == startYear){
126 | dayObj = {
127 | fullDays:fullDays,
128 | currDays:fullDays-startDay
129 | };
130 | }else
131 | if(m == endMonth && i == endYear){
132 | dayObj = {
133 | fullDays:fullDays,
134 | currDays:endDay
135 | };
136 | }
137 | allDayArr.push(dayObj);
138 | }
139 | }
140 |
141 | if(allDayArr.length == 1) {
142 | tmpBirth.day = allDayArr[0].currDays;
143 | } else if(allDayArr.length == 2) {
144 | var d1 = allDayArr[0].currDays;
145 | var d2 = allDayArr[1].currDays;
146 | //月份天数浮动因子决定准确性
147 | let cfDay = allDayArr[0].fullDays > allDayArr[allDayArr.length - 1].fullDays ? allDayArr[allDayArr.length - 1].fullDays : allDayArr[0].fullDays;
148 | if((d1 + d2) >= cfDay) {
149 | tmpBirth.day = (d1 + d2) - cfDay;
150 | tmpBirth.month += 1;
151 | } else {
152 | tmpBirth.day = d1 + d2;
153 | }
154 | } else {
155 | let d1 = allDayArr[0].currDays;
156 | let d2 = allDayArr[allDayArr.length - 1].currDays;
157 | let sumFullDay = 0;
158 | for(let i = 0; i < allDayArr.length; i++){
159 | sumFullDay += allDayArr[i].fullDays;
160 | }
161 | //月份天数浮动因子决定准确性
162 | let cfDay = allDayArr[0].fullDays > allDayArr[allDayArr.length - 1].fullDays ? allDayArr[allDayArr.length - 1].fullDays : allDayArr[0].fullDays;
163 | if((d1 + d2) >= cfDay){
164 | tmpBirth.day = (d1 + d2) - cfDay;
165 | tmpBirth.month += 1;
166 | } else {
167 | tmpBirth.day = d1 + d2;
168 | }
169 | tmpBirth.month += allDayArr.length - 2;
170 |
171 | if(tmpBirth.month >= 12){
172 | tmpBirth.year += Math.floor(tmpBirth.month / 12);
173 | tmpBirth.month = tmpBirth.month - (tmpBirth.year * 12);
174 | }
175 | }
176 | return tmpBirth;
177 | };
178 |
179 | getEdayNumber = (date) => {
180 | var initDay = date.split("-");
181 | var obj = {
182 | cYear: parseInt(initDay[0]),
183 | cMonth: parseInt(initDay[1]),
184 | cDay: parseInt(initDay[2]),
185 | };
186 | return Math.abs(this.$.daysBetween(obj));
187 | };
188 |
189 | getCalendarData = () => {
190 | const { time, nongli, isLeapMonth, eday } = this.defaultData;
191 | const _data = time.split("-");
192 | const opt = {
193 | year: parseInt(_data[0]),
194 | month: parseInt(_data[1]),
195 | day: parseInt(_data[2]),
196 | nongli,
197 | isLeapMonth,
198 | };
199 |
200 | const response = {};
201 | response.birthdayText = this.$.birthday(opt);
202 | response.nextBirthday = response.birthdayText[0];
203 |
204 | var solarData
205 | if (nongli) {
206 | solarData = this.$.lunar2solar(opt.year, opt.month, opt.day, isLeapMonth)
207 | } else {
208 | solarData = this.$.solar2lunar(opt.year, opt.month, opt.day);
209 | }
210 | response.gregorian = solarData;
211 | response.animal = `${this.$.getAnimalZodiacToEmoji(solarData.Animal)}-${
212 | solarData.Animal
213 | }`;
214 | response.astro = `${this.$.getAstroToEmoji(solarData.astro)}-${solarData.astro}`;
215 | if (this.$.verifyTime(eday)) {
216 | response.meetDay = this.getEdayNumber(eday);
217 | }
218 | this.contentText = response;
219 | };
220 |
221 | setRightCell = (rowCell, icon, iconColor, title, value, dayImage = false) => {
222 | const subWidget = rowCell.addStack();
223 | subWidget.centerAlignContent();
224 | const subImg = subWidget.addImage(icon);
225 | subImg.tintColor = new Color(iconColor);
226 | subImg.imageSize = new Size(mainTextSize, mainTextSize);
227 | subWidget.addSpacer(4);
228 | const subTitle = subWidget.addText(title);
229 | subTitle.font = Font.systemFont(mainTextSize);
230 | subTitle.textColor = this.widgetColor;
231 | subWidget.addSpacer();
232 | const subValue = subWidget.addText(value);
233 | subValue.font = Font.systemFont(mainTextSize);
234 | subValue.textColor = this.widgetColor;
235 | subValue.lineLimit = 1;
236 | if (dayImage) {
237 | subWidget.addSpacer(2);
238 | let dayIcon = subWidget.addImage(dayImage.image);
239 | dayIcon.imageSize = new Size(mainTextSize + 1, mainTextSize + 1);
240 | dayIcon.tintColor = new Color('1ab6f8');;
241 | }
242 | };
243 |
244 | setLeftView = (w) => {
245 | const leftImg = this.getLeftImage();
246 | const left = w.addStack();
247 | left.size = new Size(leftImageSize, 0);
248 | left.cornerRadius = 10;
249 | if (leftImg) {
250 | left.backgroundImage = leftImg;
251 | }
252 | left.addSpacer();
253 | left.layoutVertically();
254 | const leftAdd = left.addStack();
255 | leftAdd.centerAlignContent();
256 | if(this.defaultData.bless) {
257 | leftAdd.size = new Size(leftImageSize, 26);
258 | leftAdd.backgroundColor = new Color(extraTextColor, 0.8);
259 | const bless = leftAdd.addText("✿ "+this.defaultData.bless+" ✿");
260 | bless.textColor = new Color("ffffff", 0.8);
261 | bless.font = Font.mediumSystemFont(mainTextSize);
262 | }
263 | return w;
264 | };
265 |
266 | setRightView = (right) => {
267 | const { time, nongli, isLeapMonth} = this.defaultData;
268 | const _data = time.split("-");
269 | const opt = {
270 | year: parseInt(_data[0]),
271 | month: parseInt(_data[1]),
272 | day: parseInt(_data[2]),
273 | nongli,
274 | isLeapMonth
275 | };
276 | const {
277 | animal,
278 | astro,
279 | gregorian,
280 | nextBirthday,
281 | meetDay,
282 | birthdayText,
283 | } = this.contentText;
284 | const { IMonthCn, IDayCn } = gregorian;
285 | const _birth = `${nextBirthday.cYear}-${nextBirthday.cMonth}-${nextBirthday.cDay}`;
286 | right.layoutVertically();
287 |
288 | const rightTop = right.addStack();
289 | const textContent = rightTop.addStack();
290 | textContent.layoutVertically();
291 | const babyName = textContent.addText(this.defaultData.username);
292 | babyName.font = Font.boldSystemFont(nameTextSize);
293 | babyName.textColor = new Color(extraTextColor);
294 | babyName.lineLimit = 1;
295 | textContent.addSpacer();
296 | if (meetDay) {
297 | const babyDays = textContent.addText(`${meetDay}`);
298 | babyDays.font = Font.boldRoundedSystemFont(meetDayTextSize);
299 | babyDays.textColor = new Color(extraTextColor);
300 | textContent.addSpacer(8);
301 | }
302 |
303 | var preData
304 | if (nongli) {
305 | preData = this.$.lunar2solar(`${nextBirthday.lYear}`-1, opt.month, opt.day, isLeapMonth)
306 | log(preData)
307 | } else {
308 | preData = this.$.solar2lunar(`${nextBirthday.cYear}`-1, opt.month, opt.day)
309 | log(preData)
310 | }
311 | const today = new Date();
312 | const thenDate = new Date(`${nextBirthday.cYear}`, `${nextBirthday.cMonth}`-1, `${nextBirthday.cDay}`);
313 | log(thenDate)
314 | const passDate = new Date(preData.cYear, preData.cMonth-1, preData.cDay);
315 | log(passDate)
316 | const canvSize = 172;
317 | const canvTextSize = 45;
318 | const canvas = new DrawContext();
319 | const canvWidth = 12;
320 | const canvRadius = 80;
321 | const cbgColor = new Color(ringColor, 0.2);
322 | const cfgColor = new Color(ringColor);
323 | const centerColor = new Color(extraTextColor)
324 | const cfontColor = new Color("ffffff");
325 | canvas.size = new Size(canvSize, canvSize);
326 | canvas.opaque = false;
327 | canvas.respectScreenScale = true;
328 |
329 | const gap = today.getTime() - passDate.getTime();
330 | const gap2 = thenDate.getTime() - passDate.getTime();
331 | const deg = Math.floor(gap/gap2 * 100 * 3.6);
332 |
333 | let ctr = new Point(canvSize / 2, canvSize / 2);
334 | const bgx = ctr.x - canvRadius;
335 | const bgy = ctr.y - canvRadius;
336 | const bgd = 2 * canvRadius;
337 | const bgr = new Rect(bgx, bgy, bgd, bgd);
338 |
339 | canvas.setFillColor(cfgColor);
340 | canvas.setStrokeColor(cbgColor);
341 | canvas.setLineWidth(canvWidth);
342 | canvas.strokeEllipse(bgr);
343 |
344 | for (let t = 0; t < deg; t++) {
345 | const rect_x = ctr.x + canvRadius * Math.sin((t * Math.PI) / 180) - canvWidth / 2;
346 | const rect_y = ctr.y - canvRadius * Math.cos((t * Math.PI) / 180) - canvWidth / 2;
347 | const rect_r = new Rect(rect_x, rect_y, canvWidth, canvWidth);
348 | canvas.fillEllipse(rect_r);
349 | };
350 |
351 | const ringBG = new Rect(bgx + canvWidth / 2 + 8, bgy + canvWidth / 2 + 8, canvRadius * 2 - canvWidth -16, canvRadius * 2 - canvWidth - 16);
352 | canvas.setFillColor(centerColor);
353 | canvas.setLineWidth(0);
354 | canvas.fillEllipse(ringBG);
355 | canvas.drawImageInRect(ringIcon, ringBG);
356 |
357 | const canvTextRect = new Rect(0, 100 - canvTextSize / 2 - 10, canvSize, canvTextSize);
358 | canvas.setTextAlignedCenter();
359 | canvas.setTextColor(cfontColor);
360 | canvas.setFont(Font.mediumRoundedSystemFont(canvTextSize));
361 | canvas.drawTextInRect(`${birthdayText[1]}`, canvTextRect);
362 |
363 | const imageContent = rightTop.addStack();
364 | imageContent.addSpacer();
365 | imageContent.size = new Size(0, ringSize);
366 | imageContent.addImage(canvas.getImage());
367 |
368 | const tmpBirth = this.getAge(this.defaultData.eday);
369 | let ageYear = tmpBirth.year > 0 ? `${tmpBirth.year}岁` : '';
370 | let ageMonth = tmpBirth.month > 0 ? `${tmpBirth.month}月` : '';
371 | let ageDay = tmpBirth.day > 0 ? `${tmpBirth.day}天` : '';
372 | const age = ageYear + ageMonth + ageDay;
373 | const dayIcon = SFSymbol.named(tmpBirth.day + '.circle.fill');
374 |
375 | if (tmpBirth.year > 0 && tmpBirth.month > 0 && tmpBirth.day > 0) {
376 | this.setRightCell(right, countIcon, '1ab6f8', '年龄', ageYear + ageMonth, dayIcon);
377 | } else {
378 | this.setRightCell(right, countIcon, '1ab6f8', '年龄', age);
379 | }
380 | right.addSpacer(lineHeight);
381 | this.setRightCell(right, lunarIcon, '30d15b', '农历', `${IMonthCn}${IDayCn}`);
382 | right.addSpacer(lineHeight);
383 | this.setRightCell(right, birthIcon, 'fc6d6d', '生日', _birth);
384 | return right;
385 | };
386 |
387 | fetch = async () => {
388 | const response = await this.$request.get(
389 | "https://api.uomg.com/api/rand.qinghua?format=json",
390 | );
391 | return response.content;
392 | };
393 |
394 | renderSmall = async (w) => {
395 | this.setRightView(w.addStack());
396 | return w;
397 | };
398 |
399 | renderLarge = async (w) => {
400 | w.addSpacer(20);
401 | const body = w.addStack();
402 | const left = body.addStack();
403 | this.setLeftView(left);
404 | body.addSpacer(10);
405 | const right = body.addStack();
406 | this.setRightView(right);
407 |
408 | w.addSpacer();
409 | const footer = w.addStack();
410 | const text = await this.fetch();
411 | const subContent = footer.addText(text);
412 | subContent.font = Font.lightSystemFont(16);
413 | subContent.textColor = this.widgetColor;
414 | w.addSpacer();
415 | return w;
416 | };
417 |
418 | renderMedium = async (w) => {
419 | const body = w.addStack();
420 | const left = body.addStack();
421 | w.setPadding(16, 16, 16, 16);
422 | this.setLeftView(left);
423 | body.addSpacer(10);
424 | const right = body.addStack();
425 | this.setRightView(right);
426 | return w;
427 | };
428 |
429 | /**
430 | * 渲染函数,函数名固定
431 | * 可以根据 this.widgetFamily 来判断小组件尺寸,以返回不同大小的内容
432 | */
433 | async render() {
434 | await this.init();
435 | const widget = new ListWidget();
436 | await this.getWidgetBackgroundImage(widget);
437 | const header = widget.addStack();
438 | if (this.widgetFamily === "medium") {
439 | await this.renderMedium(widget);
440 | } else if (this.widgetFamily === "large") {
441 | await this.renderLarge(widget);
442 | } else {
443 | await this.renderSmall(widget);
444 | }
445 | return widget;
446 | }
447 |
448 | renderMoreHeader = async (header) => {
449 | header.centerAlignContent();
450 | await this.renderHeader(header, this.logo, this.name, this.widgetColor);
451 | header.addSpacer();
452 | const headerMore = header.addStack();
453 | headerMore.setPadding(1, 10, 1, 10);
454 | headerMore.cornerRadius = 10;
455 | const textItem = headerMore.addText(this.defaultData.username);
456 | textItem.font = Font.boldSystemFont(12);
457 | textItem.textColor = this.widgetColor;
458 | textItem.lineLimit = 1;
459 | textItem.rightAlignText();
460 | return header;
461 | };
462 |
463 | /**
464 | * 获取当前插件是否有自定义背景图片
465 | * @reutrn img | false
466 | */
467 | getLeftImage() {
468 | let result = null;
469 | if (this.FILE_MGR_LOCAL.fileExists(this.LEFT_IMG_KEY)) {
470 | result = Image.fromFile(this.LEFT_IMG_KEY);
471 | }
472 | return result;
473 | }
474 |
475 | /**
476 | * 设置当前组件的背景图片
477 | * @param {image} img
478 | */
479 | setLeftImage(img, notify = true) {
480 | if (!img) {
481 | // 移除背景
482 | if (this.FILE_MGR_LOCAL.fileExists(this.LEFT_IMG_KEY)) {
483 | this.FILE_MGR_LOCAL.remove(this.LEFT_IMG_KEY);
484 | }
485 | if (notify) this.notify("移除成功", "小组件图片已移除,稍后刷新生效");
486 | } else {
487 | // 设置背景
488 | // 全部设置一遍,
489 | this.FILE_MGR_LOCAL.writeImage(this.LEFT_IMG_KEY, img);
490 | if (notify) this.notify("设置成功", "小组件图片已设置!稍后刷新生效");
491 | }
492 | }
493 |
494 | setLeftWidgetImage = async () => {
495 | const alert = new Alert();
496 | alert.title = "设置左侧图";
497 | alert.message = "显示左侧图片";
498 | alert.addAction("设置新图");
499 | alert.addAction("清空图片");
500 | alert.addCancelAction("取消");
501 | const actions = [
502 | async () => {
503 | const backImage = await this.chooseImg();
504 | if (!await this.verifyImage(backImage)) return;
505 | await this.setLeftImage(backImage, true);
506 | },
507 | () => {
508 | this.setLeftImage(false, true);
509 | },
510 | ];
511 | const id = await alert.presentAlert();
512 | if (id === -1) return;
513 | actions[id] && actions[id].call(this);
514 | };
515 |
516 | setWidgetInitConfig = async () => {
517 | const a = new Alert();
518 | a.title = "🐣破壳日配置";
519 | a.message = "配置破壳日的基础信息";
520 | a.addTextField("昵称", this.defaultData.username);
521 | a.addTextField("生日/ 年-月-日", this.defaultData.time);
522 | a.addTextField("农历/ true | false", `${this.defaultData.nongli || ""}`);
523 | a.addTextField("相识/ 年-月-日", this.defaultData.eday);
524 | a.addTextField("寄语", this.defaultData.bless);
525 | a.addAction("确定");
526 | a.addCancelAction("取消");
527 | const id = await a.presentAlert();
528 | if (id === -1) return;
529 | this.defaultData.username = a.textFieldValue(0);
530 | this.defaultData.time = a.textFieldValue(1);
531 | this.defaultData.nongli = a.textFieldValue(2) === "true";
532 | this.defaultData.eday = a.textFieldValue(3);
533 | this.defaultData.bless = a.textFieldValue(4);
534 | // 保存到本地
535 | this.settings[this.en] = this.defaultData;
536 | this.saveSettings();
537 | };
538 |
539 | setWidgetBoxJSConfig = async () => {
540 | try {
541 | const datas = await this.getCache();
542 | Object.keys(this.defaultData).forEach((key) => {
543 | this.defaultData[key] = datas[`@${this.en}.${key}`];
544 | });
545 | this.settings[this.en] = this.defaultData;
546 | this.saveSettings();
547 | } catch (e) {
548 | this.notify(this.name, "", "BoxJS 数据读取失败,请点击通知查看教程", "https://chavyleung.gitbook.io/boxjs/awesome/videos");
549 | }
550 | };
551 | }
552 |
553 | Runing(Widget, "", false, { $ });
554 |
--------------------------------------------------------------------------------
/scripts/ChinaMobile_2021.js:
--------------------------------------------------------------------------------
1 | // Variables used by Scriptable.
2 | // These must be at the very top of the file. Do not edit.
3 | // icon-color: deep-green; icon-glyph: mobile-alt;
4 | // Script: 2Ya & 脑瓜
5 | // 电报群:https://t.me/Scriptable_JS @anker1209
6 | // 该脚本小尺寸组件支持两种模式,默认为圆环进度条模式,主屏幕长按小组件-->编辑小组件-->Parameter,输入1,使用文字模式
7 | // 渐变进度条为试验性功能,默认关闭
8 | // version:1.0.1
9 | // update:2021/03/12
10 |
11 | if (typeof require === 'undefined') require = importModule;
12 | const {DmYY, Runing} = require('./DmYY');
13 | const CryptoJS = require('./crypto-js');
14 |
15 | class Widget extends DmYY {
16 | constructor(arg) {
17 | super(arg);
18 | this.name = '中国移动';
19 | this.en = 'ChinaMobile_2021';
20 | this.logo = 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-b1ebbd3c-ca49-405b-957b-effe60782276/855b2333-0c1b-4bc1-9178-aac0c24119a0.png';
21 | this.smallLogo = 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-b1ebbd3c-ca49-405b-957b-effe60782276/b219c861-0b33-4fee-8245-e304275fc2ef.png';
22 | this.Run();
23 | }
24 | widgetParam = args.widgetParameter;
25 | getfee = {}; // 推荐使用Boxjs代理缓存,若无请自行手动抓包后在此输入中国移动getfee数据。
26 | autologin = {}; // 推荐使用Boxjs代理缓存,若无请自行手动抓包后在此输入中国移动autologin数据。
27 | cookie = '';
28 |
29 | gradient = false;
30 |
31 | flowColorHex = '80BA26';
32 | voiceColorHex = 'F18F00';
33 |
34 | ringStackSize = 61;
35 | ringTextSize = 14;
36 | feeTextSize = 21;
37 | textSize = 13;
38 | smallPadding = 16;
39 | padding = 10;
40 | logoScale = 0.24;
41 |
42 | canvSize = 178;
43 | canvWidth = 18;
44 | canvRadius = 80;
45 |
46 | format = (str) => {
47 | return parseInt(str) >= 10 ? str : `0${str}`;
48 | };
49 |
50 | date = new Date();
51 | arrUpdateTime = [
52 | this.format(this.date.getMonth() + 1),
53 | this.format(this.date.getDate()),
54 | this.format(this.date.getHours()),
55 | this.format(this.date.getMinutes()),
56 | ];
57 |
58 | fee = {
59 | title: '话费剩余',
60 | number: 0,
61 | unit: '元',
62 | en: '¥',
63 | };
64 |
65 | flow = {
66 | percent: 0,
67 | title: '流量剩余',
68 | number: 0,
69 | unit: 'MB',
70 | en: 'MB',
71 | icon: 'antenna.radiowaves.left.and.right',
72 | iconColor: new Color('1ab6f8'),
73 | FGColor: new Color(this.flowColorHex),
74 | BGColor: new Color(this.flowColorHex, 0.2),
75 | colors: [],
76 | };
77 |
78 | voice = {
79 | percent: 0,
80 | title: '语音剩余',
81 | number: 0,
82 | unit: '分钟',
83 | en: 'MIN',
84 | icon: 'phone.fill',
85 | iconColor: new Color('30d15b'),
86 | FGColor: new Color(this.voiceColorHex),
87 | BGColor: new Color(this.voiceColorHex, 0.2),
88 | colors: [],
89 | };
90 |
91 | point = {
92 | title: '更新时间',
93 | number: `${this.arrUpdateTime[2]}:${this.arrUpdateTime[3]}`,
94 | unit: '',
95 | icon: 'arrow.2.circlepath',
96 | iconColor: new Color('fc6d6d'),
97 | }
98 |
99 | init = async () => {
100 | try {
101 | await this.login();
102 | await this.queryFee();
103 | await this.queryFlow();
104 | } catch (e) {
105 | console.log(e);
106 | }
107 | };
108 |
109 | async login() {
110 | try {
111 | const options = this.autologin;
112 | const request = new Request(options.url);
113 | Object.keys(options).forEach((key) => {
114 | request[key] = options[key];
115 | });
116 | request.method = 'POST';
117 | await request.loadString();
118 | this.cookie = request.response.headers['Set-Cookie'];
119 | if (this.cookie) {
120 | console.log('✅登陆成功');
121 | } else {
122 | console.log('❌登陆失败');
123 | }
124 | } catch (e) {
125 | console.log('❌登陆失败,请检查 Ck:' + e);
126 | }
127 | }
128 |
129 | async queryFee() {
130 | try {
131 | const options = this.getfee;
132 | const body = JSON.parse(this.decrypt(options.body, 'bAIgvwAuA4tbDr9d'));
133 | const cellNum = body.reqBody.cellNum;
134 | const bodystr = `{"t":"${CryptoJS.MD5(
135 | this.cookie,
136 | ).toString()}","cv":"9.9.9","reqBody":{"cellNum":"${cellNum}"}}`;
137 | options.body = this.encrypt(bodystr, 'bAIgvwAuA4tbDr9d');
138 | options.headers['Cookie'] = this.cookie;
139 | options.headers['xs'] = CryptoJS.MD5(
140 | options.url + '_' + bodystr + '_Leadeon/SecurityOrganization',
141 | ).toString();
142 | const request = new Request(options.url);
143 | request.method = 'POST';
144 | request.headers = options.headers;
145 | request.body = options.body;
146 | const webView = new WebView();
147 | await webView.loadRequest(request);
148 | const response = await webView.evaluateJavaScript(
149 | 'completion(document.body.innerText);',
150 | true,
151 | );
152 | const data = JSON.parse(this.decrypt(response, 'GS7VelkJl5IT1uwQ'));
153 | if (data.retCode === '000000') {
154 | console.log('✅费用信息获取成功');
155 | const {rspBody} = data;
156 | this.fee.number = rspBody.curFee;
157 | } else {
158 | console.log('❌费用信息获取失败,请检查 Ck 配置' + data.retDesc);
159 | }
160 | } catch (e) {
161 | console.log('❌费用信息获取失败:' + e);
162 | }
163 | }
164 |
165 | async queryFlow() {
166 | try {
167 | const options = this.getfee;
168 | const body = JSON.parse(this.decrypt(options.body, 'bAIgvwAuA4tbDr9d'));
169 | const cellNum = body.reqBody.cellNum;
170 | options.url =
171 | 'https://clientaccess.10086.cn/biz-orange/BN/newComboMealResouceUnite/getNewComboMealResource';
172 | const bodystr = `{"t":"${CryptoJS.MD5(
173 | this.cookie,
174 | ).
175 | toString()}","cv":"9.9.9","reqBody":{"cellNum":"${cellNum}","tag":"3"}}`;
176 | options.body = this.encrypt(bodystr, 'bAIgvwAuA4tbDr9d');
177 | options.headers['Cookie'] = this.cookie;
178 | options.headers['xs'] = CryptoJS.MD5(
179 | options.url + '_' + bodystr + '_Leadeon/SecurityOrganization',
180 | ).toString();
181 |
182 | const request = new Request(options.url);
183 | request.method = 'POST';
184 | request.headers = options.headers;
185 | request.body = options.body;
186 | const webView = new WebView();
187 | await webView.loadRequest(request);
188 | const response = await webView.evaluateJavaScript(
189 | 'completion(document.body.innerText);',
190 | true,
191 | );
192 |
193 | const data = JSON.parse(this.decrypt(response, 'GS7VelkJl5IT1uwQ'));
194 | if (data.retCode === '000000') {
195 | console.log('✅套餐信息获取成功');
196 | const res = data.rspBody.qryInfoRsp[0].resourcesTotal;
197 | const flowRes = res.find((r) => r.resourcesCode === '04');
198 | const voiceRes = res.find((r) => r.resourcesCode === '01');
199 | var flowResValue = '未开通',
200 | voiceResValue = '';
201 | if (flowRes) {
202 | const total = this.translateFlow({
203 | value: flowRes.allTotalRes,
204 | code: flowRes.allUnit,
205 | });
206 | const remain = this.translateFlow({
207 | value: flowRes.allRemainRes,
208 | code: flowRes.remUnit,
209 | });
210 |
211 | this.flow.percent = ((remain.value / (total.value || 1)) * 100).toFixed(2);
212 | this.flow.number = flowRes.allRemainRes;
213 | this.flow.unit = `${remain.unit}B`;
214 | this.flow.en = `${remain.unit}B`;
215 | flowResValue = `${flowRes.allRemainRes}${remain.unit}`;
216 | }
217 | if (voiceRes) {
218 | this.voice.percent = ((voiceRes.allRemainRes / (voiceRes.allTotalRes || 1)) * 100).toFixed(2);
219 | this.voice.number = voiceRes.allRemainRes;
220 | voiceResValue = voiceRes.allRemainRes;
221 | }
222 | console.log(`✅流量:` + flowResValue + '\n ✅语音:' + voiceResValue);
223 | } else {
224 | console.log('❌流量信息获取失败,请检查 Ck 配置' + data.retDesc);
225 | }
226 | } catch (e) {
227 | console.log('❌流量信息获取失败:' + e);
228 | }
229 | }
230 |
231 | encrypt(str, key) {
232 | return CryptoJS.AES.encrypt(
233 | CryptoJS.enc.Utf8.parse(str),
234 | CryptoJS.enc.Utf8.parse(key),
235 | {
236 | iv: CryptoJS.enc.Utf8.parse('9791027341711819'),
237 | mode: CryptoJS.mode.CBC,
238 | padding: CryptoJS.pad.Pkcs7,
239 | },
240 | ).toString();
241 | }
242 |
243 | decrypt(str, key) {
244 | return CryptoJS.AES.decrypt(str, CryptoJS.enc.Utf8.parse(key), {
245 | iv: CryptoJS.enc.Utf8.parse('9791027341711819'),
246 | mode: CryptoJS.mode.CBC,
247 | padding: CryptoJS.pad.Pkcs7,
248 | }).toString(CryptoJS.enc.Utf8);
249 | }
250 |
251 | translateFlow(value) {
252 | const unit = [
253 | {unit: 'G', value: 1024, code: '05'},
254 | {unit: 'M', value: 1, code: '04'},
255 | ];
256 | const data = {unit: '', ...value};
257 | unit.forEach((item) => {
258 | if (value.code === item.code) {
259 | data.unit = item.unit;
260 | data.value =
261 | Math.floor(parseFloat(data.value) * item.value * 100) / 100;
262 | }
263 | });
264 | data.value = parseInt(data.value);
265 | return data;
266 | }
267 |
268 | async smallHeader(stack) {
269 | const headerStack = stack.addStack();
270 | headerStack.addSpacer();
271 | const logo = headerStack.addImage(await this.$request.get(this.logo, 'IMG'));
272 | logo.imageSize = new Size(402 * this.logoScale, 125 * this.logoScale);
273 | headerStack.addSpacer();
274 | stack.addSpacer();
275 |
276 | const feeStack = stack.addStack();
277 | feeStack.centerAlignContent();
278 | feeStack.addSpacer();
279 | const feeValue = feeStack.addText(`${this.fee.number}`);
280 | feeValue.font = Font.mediumRoundedSystemFont(this.feeTextSize);
281 | feeValue.textColor = this.widgetColor;
282 | feeStack.addSpacer();
283 | stack.addSpacer();
284 | }
285 |
286 | textLayout(stack, data) {
287 | const rowStack = stack.addStack();
288 | rowStack.centerAlignContent();
289 | const icon = SFSymbol.named(data.icon);
290 | icon.applyHeavyWeight();
291 | let iconElement = rowStack.addImage(icon.image);
292 | iconElement.imageSize = new Size(this.textSize, this.textSize);
293 | iconElement.tintColor = data.iconColor;
294 | rowStack.addSpacer(4);
295 | let title = rowStack.addText(data.title);
296 | rowStack.addSpacer();
297 | let number = rowStack.addText(data.number + data.unit);
298 | ;[title, number].map(t => t.textColor = this.widgetColor);
299 | ;[title, number].map(t => t.font = Font.systemFont(this.textSize));
300 | }
301 |
302 | async mediumCell(canvas, stack, data, color, fee = false, percent) {
303 | const bg = new LinearGradient()
304 | bg.locations = [0, 1]
305 | bg.colors = [
306 | new Color(color, 0.03),
307 | new Color(color, 0.1)
308 | ]
309 | const dataStack = stack.addStack();
310 | dataStack.backgroundGradient = bg;
311 | dataStack.cornerRadius = 20;
312 | dataStack.layoutVertically();
313 | dataStack.addSpacer();
314 |
315 | const topStack = dataStack.addStack();
316 | topStack.addSpacer();
317 | await this.imageCell(canvas, topStack, data, fee, percent);
318 | topStack.addSpacer();
319 |
320 | if (fee) {
321 | dataStack.addSpacer(10);
322 | const updateStack = dataStack.addStack();
323 | updateStack.addSpacer();
324 | updateStack.centerAlignContent();
325 | const updataIcon = SFSymbol.named('arrow.2.circlepath');
326 | updataIcon.applyHeavyWeight();
327 | const updateImg = updateStack.addImage(updataIcon.image);
328 | updateImg.tintColor = new Color(color, 0.6);
329 | updateImg.imageSize = new Size(10, 10);
330 | updateStack.addSpacer(3);
331 | const updateText = updateStack.addText(`${this.arrUpdateTime[2]}:${this.arrUpdateTime[3]}`)
332 | updateText.font = Font.mediumSystemFont(10);
333 | updateText.textColor = new Color(color, 0.6);
334 | updateStack.addSpacer();
335 | }
336 |
337 | dataStack.addSpacer();
338 |
339 | const numberStack = dataStack.addStack();
340 | numberStack.addSpacer();
341 | const number = numberStack.addText(`${data.number} ${data.en}`);
342 | number.font = Font.semiboldSystemFont(15);
343 | numberStack.addSpacer();
344 |
345 | dataStack.addSpacer(3);
346 |
347 | const titleStack = dataStack.addStack();
348 | titleStack.addSpacer();
349 | const title = titleStack.addText(data.title);
350 | title.font = Font.mediumSystemFont(11);
351 | title.textOpacity = 0.7;
352 | titleStack.addSpacer();
353 |
354 | dataStack.addSpacer(15);
355 | ;[title, number].map(t => t.textColor = new Color(color));
356 | }
357 |
358 | async imageCell(canvas, stack, data, fee, percent) {
359 | const canvaStack = stack.addStack();
360 | canvaStack.layoutVertically();
361 | if (!fee) {
362 | this.drawArc(canvas, data.percent * 3.6, data.FGColor, data.BGColor);
363 | canvaStack.size = new Size(this.ringStackSize, this.ringStackSize);
364 | canvaStack.backgroundImage = canvas.getImage();
365 | this.ringContent(canvaStack, data, percent);
366 | } else {
367 | canvaStack.addSpacer(10);
368 | const smallLogo = await this.$request.get(this.smallLogo, 'IMG');
369 | const logoStack = canvaStack.addStack();
370 | logoStack.size = new Size(35, 35);
371 | logoStack.backgroundImage = smallLogo;
372 | }
373 | }
374 |
375 | ringContent(stack, data, percent = false) {
376 | const rowIcon = stack.addStack();
377 | rowIcon.addSpacer();
378 | const icon = SFSymbol.named(data.icon);
379 | icon.applyHeavyWeight();
380 | const iconElement = rowIcon.addImage(icon.image);
381 | iconElement.tintColor = this.gradient ? new Color(data.colors[1]) : data.FGColor;
382 | iconElement.imageSize = new Size(12, 12);
383 | iconElement.imageOpacity = 0.7;
384 | rowIcon.addSpacer();
385 |
386 | stack.addSpacer(1);
387 |
388 | const rowNumber = stack.addStack();
389 | rowNumber.addSpacer();
390 | const number = rowNumber.addText(percent ? `${data.percent}` : `${data.number}`);
391 | number.font = percent ? Font.systemFont(this.ringTextSize - 2) : Font.mediumSystemFont(this.ringTextSize);
392 | rowNumber.addSpacer();
393 |
394 | const rowUnit = stack.addStack();
395 | rowUnit.addSpacer();
396 | const unit = rowUnit.addText(percent ? '%' : data.unit);
397 | unit.font = Font.boldSystemFont(8);
398 | unit.textOpacity = 0.5;
399 | rowUnit.addSpacer();
400 |
401 | if (percent) {
402 | if (this.gradient) {
403 | ;[unit, number].map(t => t.textColor = new Color(data.colors[1]));
404 | } else {
405 | ;[unit, number].map(t => t.textColor = data.FGColor);
406 | }
407 | } else {
408 | ;[unit, number].map(t => t.textColor = this.widgetColor);
409 | }
410 | }
411 |
412 | makeCanvas() {
413 | const canvas = new DrawContext();
414 | canvas.opaque = false;
415 | canvas.respectScreenScale = true;
416 | canvas.size = new Size(this.canvSize, this.canvSize);
417 | return canvas;
418 | }
419 |
420 | sinDeg(deg) {
421 | return Math.sin((deg * Math.PI) / 180);
422 | }
423 |
424 | cosDeg(deg) {
425 | return Math.cos((deg * Math.PI) / 180);
426 | }
427 |
428 | drawArc(canvas, deg, fillColor, strokeColor) {
429 | let ctr = new Point(this.canvSize / 2, this.canvSize / 2);
430 | let bgx = ctr.x - this.canvRadius;
431 | let bgy = ctr.y - this.canvRadius;
432 | let bgd = 2 * this.canvRadius;
433 | let bgr = new Rect(bgx, bgy, bgd, bgd)
434 |
435 | canvas.setStrokeColor(strokeColor);
436 | canvas.setLineWidth(this.canvWidth);
437 | canvas.strokeEllipse(bgr);
438 |
439 | for (let t = 0; t < deg; t++) {
440 | let rect_x = ctr.x + this.canvRadius * this.sinDeg(t) - this.canvWidth / 2;
441 | let rect_y = ctr.y - this.canvRadius * this.cosDeg(t) - this.canvWidth / 2;
442 | let rect_r = new Rect(rect_x, rect_y, this.canvWidth, this.canvWidth);
443 |
444 | canvas.setFillColor(this.gradient ? new Color(fillColor[t]) : fillColor);
445 | canvas.setStrokeColor(strokeColor)
446 | canvas.fillEllipse(rect_r);
447 | }
448 | }
449 |
450 | arrColor() {
451 | let colorArr = [['#FFF000', '#E62490'], ['#FDEB71', '#F8D800'], ['#ABDCFF', '#0396FF'], ['#FEB692', '#EA5455'], ['#FEB692', '#EA5455'], ['#CE9FFC', '#7367F0'], ['#90F7EC', '#32CCBC'], ['#FFF6B7', '#F6416C'], ['#E2B0FF', '#9F44D3'], ['#F97794', '#F072B6'], ['#FCCF31', '#F55555'], ['#5EFCE8', '#736EFE'], ['#FAD7A1', '#E96D71'], ['#FFFF1C', '#00C3FF'], ['#FEC163', '#DE4313'], ['#F6CEEC', '#D939CD'], ['#FDD819', '#E80505'], ['#FFF3B0', '#CA26FF'], ['#2AFADF', '#4C83FF'], ['#EECDA3', '#EF629F'], ['#C2E59C', '#64B3F4'], ['#FFF886', '#F072B6'], ['#F5CBFF', '#C346C2'], ['#FFF720', '#3CD500'], ['#EE9AE5', '#5961F9'], ['#FFC371', '#FF5F6D'], ['#FFD3A5', '#FD6585'], ['#C2FFD8', '#465EFB'], ['#FFC600', '#FD6E6A'], ['#FFC600', '#FD6E6A'], ['#92FE9D', '#00C9FF'], ['#FFDDE1', '#EE9CA7'], ['#F0FF00', '#58CFFB'], ['#FFE985', '#FA742B'], ['#72EDF2', '#5151E5'], ['#F6D242', '#FF52E5'], ['#F9D423', '#FF4E50'], ['#3C8CE7', '#00EAFF'], ['#FCFF00', '#FFA8A8'], ['#FF96F9', '#C32BAC'], ['#D0E6A5', '#FFDD94'], ['#FFDD94', '#FA897B'], ['#FFCC4B', '#FF7D58'], ['#D0E6A5', '#86E3CE'], ['#F0D5B6', '#F16238'], ['#F8EC70', '#F9C708'], ['#C4E86B', '#00BCB4'], ['#FFC446', '#FA0874'], ['#E1EE32', '#FFB547'], ['#FFD804', '#2ACCC8'], ['#E9A6D2', '#E9037B'], ['#F8EC70', '#49E2F6'], ['#A2F8CD', '#A2F852'], ['#49E2F6', '#A2F8CD'], ['#FDEFE2', '#FE214F'], ['#F8EC70', '#A2F8CD'], ['#F8EC70', '#49E2F6'], ['#B7FFE4', '#E4B7FF'], ['#FFB7D1', '#E4B7FF'], ['#D0E6A5', '#86E3CE'], ['#E8E965', '#64C5C7']];
452 | let colors = colorArr[Math.floor(Math.random() * colorArr.length)];
453 | return colors;
454 | }
455 |
456 | gradientColor(colors, step) {
457 | var startRGB = this.colorToRgb(colors[0]),
458 | startR = startRGB[0],
459 | startG = startRGB[1],
460 | startB = startRGB[2];
461 |
462 | var endRGB = this.colorToRgb(colors[1]),
463 | endR = endRGB[0],
464 | endG = endRGB[1],
465 | endB = endRGB[2];
466 |
467 | var sR = (endR - startR) / step,
468 | sG = (endG - startG) / step,
469 | sB = (endB - startB) / step;
470 |
471 | var colorArr = [];
472 | for (var i = 0;i < step; i++) {
473 | var hex = this.colorToHex('rgb(' + parseInt((sR * i + startR)) + ',' + parseInt((sG * i + startG)) + ',' + parseInt((sB * i + startB)) + ')');
474 | colorArr.push(hex);
475 | }
476 | return colorArr;
477 | }
478 |
479 | colorToRgb(sColor) {
480 | var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
481 | var sColor = sColor.toLowerCase();
482 | if (sColor && reg.test(sColor)) {
483 | if (sColor.length === 4) {
484 | var sColorNew = "#";
485 | for (var i = 1; i < 4; i += 1) {
486 | sColorNew += sColor.slice(i, i + 1).concat(sColor.slice(i, i + 1));
487 | }
488 | sColor = sColorNew;
489 | }
490 | var sColorChange = [];
491 | for (var i = 1; i < 7; i += 2) {
492 | sColorChange.push(parseInt("0x" + sColor.slice(i, i + 2)));
493 | }
494 | return sColorChange;
495 | } else {
496 | return sColor;
497 | }
498 | };
499 |
500 | colorToHex(rgb) {
501 | var _this = rgb;
502 | var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
503 | if (/^(rgb|RGB)/.test(_this)) {
504 | var aColor = _this.replace(/(?:\(|\)|rgb|RGB)*/g,"").split(",");
505 | var strHex = "#";
506 | for (var i = 0; i < aColor.length; i++) {
507 | var hex = Number(aColor[i]).toString(16);
508 | hex = hex.length < 2 ? 0 + '' + hex : hex;
509 | if (hex === "0") {
510 | hex += hex;
511 | }
512 | strHex += hex;
513 | }
514 | if (strHex.length !== 7) {
515 | strHex = _this;
516 | }
517 |
518 | return strHex;
519 | } else if (reg.test(_this)) {
520 | var aNum = _this.replace(/#/,"").split("");
521 | if (aNum.length === 6) {
522 | return _this;
523 | } else if (aNum.length === 3) {
524 | var numHex = "#";
525 | for (var i = 0; i < aNum.length; i+=1) {
526 | numHex += (aNum[i] + aNum[i]);
527 | }
528 | return numHex;
529 | }
530 | } else {
531 | return _this;
532 | }
533 | }
534 |
535 | renderSmall = async (w) => {
536 | w.setPadding(this.smallPadding, this.smallPadding, this.smallPadding, this.smallPadding);
537 | await this.smallHeader(w);
538 | const bodyStack = w.addStack();
539 | bodyStack.layoutVertically();
540 | if (this.widgetParam == "1"){
541 | this.textLayout(bodyStack, this.flow);
542 | bodyStack.addSpacer(7);
543 | this.textLayout(bodyStack, this.voice);
544 | bodyStack.addSpacer(7);
545 | this.textLayout(bodyStack, this.point);
546 | } else {
547 | const canvas = this.makeCanvas();
548 | const ringStack = bodyStack.addStack();
549 | this.imageCell(canvas, ringStack, this.flow);
550 | ringStack.addSpacer();
551 | this.imageCell(canvas, ringStack, this.voice);
552 | }
553 | return w;
554 | };
555 |
556 | renderMedium = async (w) => {
557 | w.setPadding(this.padding, this.padding, this.padding, this.padding);
558 | const canvas = this.makeCanvas();
559 | const bodyStack = w.addStack();
560 | await this.mediumCell(canvas, bodyStack, this.fee, '0080CB', true);
561 | bodyStack.addSpacer(this.padding);
562 | await this.mediumCell(canvas, bodyStack, this.flow, this.flowColorHex, false, true);
563 | bodyStack.addSpacer(this.padding);
564 | await this.mediumCell(canvas, bodyStack, this.voice, this.voiceColorHex, false,true);
565 | return w;
566 | };
567 |
568 | renderLarge = async (w) => {
569 | w.addText('暂不支持')
570 | return w;
571 | };
572 |
573 | Run() {
574 | if (config.runsInApp) {
575 | const widgetInitConfig = {
576 | getfee: 'chavy_getfee_cmcc',
577 | autologin: 'chavy_autologin_cmcc',
578 | };
579 | this.registerAction('颜色配置', async () => {
580 | await this.setAlertInput(
581 | `${this.name}颜色配置`,
582 | '进度条颜色|底圈颜色\n底圈颜色留空将跟随进度条颜色并淡显',
583 | {
584 | gradient: '开启渐变进度条?缺省:false',
585 | step1: '流量进度条颜色',
586 | step2: '语音进度条颜色',
587 | inner1: '流量进度条底圈颜色',
588 | inner2: '语音进度条底圈颜色',
589 | },
590 | );
591 | });
592 | this.registerAction('尺寸设置', async () => {
593 | await this.setAlertInput(
594 | `${this.name}尺寸设置`,
595 | '进度条大小|文字大小',
596 | {
597 | logoScale: '小组件logo缩放,缺省:0.24',
598 | ringStackSize: '圆环大小,缺省:61',
599 | ringTextSize: '圆环中心文字大小,缺省:14',
600 | feeTextSize: '话费文字大小,缺省:21',
601 | textSize: '文字模式下文字大小,缺省:13',
602 | smallPadding: '小尺寸组件边距,缺省:16',
603 | padding: '中尺寸组件边距,缺省:10',
604 | },
605 | );
606 | });
607 | this.registerAction('账号设置', async () => {
608 | await this.setAlertInput(
609 | `${this.name}账号`,
610 | '读取 BoxJS 缓存信息',
611 | widgetInitConfig,
612 | );
613 | });
614 | this.registerAction('代理缓存', async () => {
615 | await this.setCacheBoxJSData(widgetInitConfig);
616 | });
617 | this.registerAction('基础设置', this.setWidgetConfig);
618 | }
619 |
620 | try {
621 | const {
622 | getfee,
623 | autologin,
624 | step1,
625 | step2,
626 | inner1,
627 | inner2,
628 | logoScale,
629 | ringStackSize,
630 | ringTextSize,
631 | feeTextSize,
632 | textSize,
633 | smallPadding,
634 | padding,
635 | gradient,
636 | } = this.settings;
637 | this.getfee = JSON.parse(getfee || this.getfee);
638 | this.autologin = JSON.parse(autologin || this.autologin);
639 |
640 | this.gradient = gradient === 'true' ? true : this.gradient;
641 | this.flowColorHex = step1 ? step1 : this.flowColorHex;
642 | this.voiceColorHex = step2 ? step2 : this.voiceColorHex;
643 | this.flow.BGColor = inner1 ? new Color(inner1) : new Color(this.flowColorHex, 0.2);
644 | this.voice.BGColor = inner2 ? new Color(inner2) : new Color(this.voiceColorHex, 0.2);
645 | this.flow.FGColor = new Color(this.flowColorHex);
646 | this.voice.FGColor = new Color(this.voiceColorHex);
647 |
648 | this.logoScale = logoScale ? parseFloat(logoScale) : this.logoScale;
649 | this.ringStackSize = ringStackSize ? parseFloat(ringStackSize) : this.ringStackSize;
650 | this.ringTextSize = ringTextSize ? parseFloat(ringTextSize) : this.ringTextSize;
651 | this.feeTextSize = feeTextSize ? parseFloat(feeTextSize) : this.feeTextSize;
652 | this.textSize = textSize ? parseFloat(textSize) : this.textSize;
653 | this.smallPadding = smallPadding ? parseFloat(smallPadding) : this.smallPadding;
654 | this.padding = padding ? parseFloat(padding) : this.padding;
655 |
656 | if (this.gradient) {
657 | this.flow.colors = this.arrColor();
658 | this.voice.colors = this.arrColor();
659 | this.flow.BGColor = inner1 ? new Color(inner1) : new Color(this.flow.colors[1], 0.2);
660 | this.voice.BGColor = inner2 ? new Color(inner2) : new Color(this.voice.colors[1], 0.2);
661 | this.flow.FGColor = this.gradientColor(this.flow.colors, 360);
662 | this.voice.FGColor = this.gradientColor(this.voice.colors, 360);
663 | this.flowColorHex = this.flow.colors[1];
664 | this.voiceColorHex = this.voice.colors[1];
665 | }
666 |
667 | } catch (e) {
668 | console.log(e);
669 | }
670 | }
671 |
672 | async render() {
673 | await this.init();
674 | const widget = new ListWidget();
675 | await this.getWidgetBackgroundImage(widget);
676 | if (this.widgetFamily === 'medium') {
677 | return await this.renderMedium(widget);
678 | } else if (this.widgetFamily === 'large') {
679 | return await this.renderLarge(widget);
680 | } else {
681 | return await this.renderSmall(widget);
682 | }
683 | }
684 | }
685 |
686 | await Runing(Widget, args.widgetParameter, false);
687 |
--------------------------------------------------------------------------------
/scripts/ChinaTelecom_2021.js:
--------------------------------------------------------------------------------
1 | // Variables used by Scriptable.
2 | // These must be at the very top of the file. Do not edit.
3 | // icon-color: deep-blue; icon-glyph: mobile-alt;
4 | // Script: 2Ya & 脑瓜
5 | // 电报群:https://t.me/Scriptable_JS @anker1209
6 | // 该脚本小尺寸组件支持两种模式,默认为圆环进度条模式,主屏幕长按小组件-->编辑小组件-->Parameter,输入1,使用文字模式
7 | // 渐变进度条为试验性功能,默认关闭
8 | // version:1.1.0
9 | // update:2021/04/02
10 |
11 | if (typeof require === 'undefined') require = importModule;
12 | const {DmYY, Runing} = require('./DmYY');
13 |
14 | class Widget extends DmYY {
15 | constructor(arg) {
16 | super(arg);
17 | this.name = '中国电信';
18 | this.en = 'ChinaTelecom_2021';
19 | this.logo = 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-b1ebbd3c-ca49-405b-957b-effe60782276/fe69a7a3-a0e2-4bf4-bab2-f11fd4b91d7d.png';
20 | this.smallLogo = 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-b1ebbd3c-ca49-405b-957b-effe60782276/0b27cf6d-6b15-42bd-9f66-1b2c668ec5eb.png';
21 | this.Run();
22 | }
23 | cookie = ''; // 推荐使用Boxjs代理缓存,若无请自行手动抓包后在此输入中国电信cookie数据或运行脚本-->账号设置-->手动输入。
24 | widgetParam = args.widgetParameter;
25 |
26 | gradient = false;
27 | usedFlow = false;
28 |
29 | flowColorHex = 'FF6620';
30 | voiceColorHex = '78C100';
31 |
32 | ringStackSize = 61;
33 | ringTextSize = 14;
34 | feeTextSize = 21;
35 | textSize = 13;
36 | smallPadding = 16;
37 | padding = 10;
38 | logoScale = 0.24;
39 |
40 | canvSize = 178;
41 | canvWidth = 18;
42 | canvRadius = 80;
43 |
44 | format = (str) => {
45 | return parseInt(str) >= 10 ? str : `0${str}`;
46 | };
47 |
48 | date = new Date();
49 | arrUpdateTime = [
50 | this.format(this.date.getMonth() + 1),
51 | this.format(this.date.getDate()),
52 | this.format(this.date.getHours()),
53 | this.format(this.date.getMinutes()),
54 | ];
55 |
56 | fee = {
57 | title: '话费余额',
58 | number: 0,
59 | unit: '元',
60 | en: '¥',
61 | };
62 |
63 | flow = {
64 | percent: 0,
65 | max: 40,
66 | title: '可用流量',
67 | number: 0,
68 | unit: 'MB',
69 | en: 'MB',
70 | icon: 'antenna.radiowaves.left.and.right',
71 | iconColor: new Color('1ab6f8'),
72 | FGColor: new Color(this.flowColorHex),
73 | BGColor: new Color(this.flowColorHex, 0.2),
74 | colors: [],
75 | };
76 |
77 | voice = {
78 | percent: 0,
79 | title: '语音剩余',
80 | number: 0,
81 | unit: '分钟',
82 | en: 'MIN',
83 | icon: 'phone.fill',
84 | iconColor: new Color('30d15b'),
85 | FGColor: new Color(this.voiceColorHex),
86 | BGColor: new Color(this.voiceColorHex, 0.2),
87 | colors: [],
88 | };
89 |
90 | point = {
91 | title: '更新时间',
92 | number: `${this.arrUpdateTime[2]}:${this.arrUpdateTime[3]}`,
93 | unit: '',
94 | icon: 'arrow.2.circlepath',
95 | iconColor: new Color('fc6d6d'),
96 | }
97 |
98 | options = {
99 | headers: {
100 | cookie: '',
101 | },
102 | method: 'POST',
103 | };
104 |
105 | fetchUrl = {
106 | detail: 'https://e.189.cn/store/user/package_detail.do',
107 | balance: 'https://e.189.cn/store/user/balance_new.do',
108 | };
109 |
110 | init = async () => {
111 | try {
112 | await this.getData();
113 | } catch (e) {
114 | console.log(e);
115 | }
116 | };
117 |
118 | formatFlow(number) {
119 | const n = number / 1024;
120 | if (n < 1024) {
121 | return {count: n.toFixed(2), unit: 'MB'};
122 | }
123 | return {count: (n / 1024).toFixed(2), unit: 'GB'};
124 | }
125 |
126 | unlimitUser(flow) {
127 | const usedFlow = this.formatFlow(flow);
128 | this.flow.title = '已用流量';
129 | this.flow.number = usedFlow.count;
130 | this.flow.unit = usedFlow.unit;
131 | this.flow.en = usedFlow.unit;
132 | if (this.flow.unit === 'GB') {
133 | this.flow.percent = (100 - (this.flow.number / (this.flow.max || 40)) * 100).toFixed(2);
134 | } else {
135 | this.flow.percent = (100 - (this.flow.number / ((this.flow.max || 40) * 1024)) * 100).toFixed(2);
136 | }
137 | }
138 |
139 | getData = async () => {
140 | const detail = await this.http({
141 | url: this.fetchUrl.detail,
142 | ...this.options,
143 | });
144 | console.log(detail);
145 | const balance = await this.http({
146 | url: this.fetchUrl.balance,
147 | ...this.options,
148 | });
149 |
150 | if (detail.result === 0) {
151 | // 套餐分钟数
152 | if (detail.voiceBalance && detail.voiceAmount) {
153 | this.voice.percent = ((Number(detail.voiceBalance) / Number(detail.voiceAmount)) * 100).toFixed(2);
154 | this.voice.number = detail.voiceBalance;
155 | } else {
156 | detail.items.forEach((data) => {
157 | if (data.offerType == 21) {
158 | data.items.forEach((item) => {
159 | if (item.unitTypeId === '1') {
160 | if (item.ratableAmount !== '0' && item.balanceAmount !== '0') {
161 | this.voice.percent = ((Number(item.balanceAmount) / Number(item.ratableAmount)) * 100).toFixed(2);
162 | this.voice.number = item.balanceAmount;
163 | }
164 | }
165 | });
166 | }
167 | });
168 | }
169 | if (!detail.number && !detail.total) {
170 | detail.items.forEach((data) => {
171 | if (data.offerType !== 19) {
172 | data.items.forEach((item) => {
173 | if (item.unitTypeId === '3') {
174 | if (item.usageAmount !== '0' && item.balanceAmount !== '0') {
175 | this.flow.percent = ((item.balanceAmount / (item.ratableAmount || 1)) * 100).toFixed(2);
176 | const flow = this.formatFlow(item.balanceAmount);
177 | this.flow.number = flow.count;
178 | this.flow.unit = flow.unit;
179 | this.flow.en = flow.unit;
180 | }
181 | if (data.offerType == 21 && item.ratableAmount == '0') {
182 | this.unlimitUser(item.usageAmount);
183 | }
184 | }
185 | });
186 | }
187 | });
188 | } else {
189 | if (this.usedFlow) {
190 | this.unlimitUser(detail.used);
191 | } else {
192 | this.flow.percent = ((detail.balance / (detail.total || 1)) * 100).toFixed(2);
193 | const flow = this.formatFlow(detail.balance);
194 | this.flow.number = flow.count;
195 | this.flow.unit = flow.unit;
196 | this.flow.en = flow.unit;
197 | }
198 | }
199 |
200 | }
201 | if (balance.result === 0) {
202 | // 余额
203 | this.fee.number = parseFloat(parseInt(balance.totalBalanceAvailable) / 100).toFixed(2)};
204 | };
205 |
206 | async smallHeader(stack) {
207 | const headerStack = stack.addStack();
208 | headerStack.addSpacer();
209 | const logo = headerStack.addImage(await this.$request.get(this.logo, 'IMG'));
210 | logo.imageSize = new Size(455 * this.logoScale, 125 * this.logoScale);
211 | headerStack.addSpacer();
212 | stack.addSpacer();
213 |
214 | const feeStack = stack.addStack();
215 | feeStack.centerAlignContent();
216 | feeStack.addSpacer();
217 | const feeValue = feeStack.addText(`${this.fee.number}`);
218 | feeValue.font = Font.mediumRoundedSystemFont(this.feeTextSize);
219 | feeValue.textColor = this.widgetColor;
220 | feeStack.addSpacer();
221 | stack.addSpacer();
222 | }
223 |
224 | textLayout(stack, data) {
225 | const rowStack = stack.addStack();
226 | rowStack.centerAlignContent();
227 | const icon = SFSymbol.named(data.icon);
228 | icon.applyHeavyWeight();
229 | let iconElement = rowStack.addImage(icon.image);
230 | iconElement.imageSize = new Size(this.textSize, this.textSize);
231 | iconElement.tintColor = data.iconColor;
232 | rowStack.addSpacer(4);
233 | let title = rowStack.addText(data.title);
234 | rowStack.addSpacer();
235 | let number = rowStack.addText(data.number + data.unit);
236 | ;[title, number].map(t => t.textColor = this.widgetColor);
237 | ;[title, number].map(t => t.font = Font.systemFont(this.textSize));
238 | }
239 |
240 | async mediumCell(canvas, stack, data, color, fee = false, percent) {
241 | const bg = new LinearGradient()
242 | bg.locations = [0, 1]
243 | bg.colors = [
244 | new Color(color, 0.03),
245 | new Color(color, 0.1)
246 | ]
247 | const dataStack = stack.addStack();
248 | dataStack.backgroundGradient = bg;
249 | dataStack.cornerRadius = 20;
250 | dataStack.layoutVertically();
251 | dataStack.addSpacer();
252 |
253 | const topStack = dataStack.addStack();
254 | topStack.addSpacer();
255 | await this.imageCell(canvas, topStack, data, fee, percent);
256 | topStack.addSpacer();
257 |
258 | if (fee) {
259 | dataStack.addSpacer(10);
260 | const updateStack = dataStack.addStack();
261 | updateStack.addSpacer();
262 | updateStack.centerAlignContent();
263 | const updataIcon = SFSymbol.named('arrow.2.circlepath');
264 | updataIcon.applyHeavyWeight();
265 | const updateImg = updateStack.addImage(updataIcon.image);
266 | updateImg.tintColor = new Color(color, 0.6);
267 | updateImg.imageSize = new Size(10, 10);
268 | updateStack.addSpacer(3);
269 | const updateText = updateStack.addText(`${this.arrUpdateTime[2]}:${this.arrUpdateTime[3]}`)
270 | updateText.font = Font.mediumSystemFont(10);
271 | updateText.textColor = new Color(color, 0.6);
272 | updateStack.addSpacer();
273 | }
274 |
275 | dataStack.addSpacer();
276 |
277 | const numberStack = dataStack.addStack();
278 | numberStack.addSpacer();
279 | const number = numberStack.addText(`${data.number} ${data.en}`);
280 | number.font = Font.semiboldSystemFont(15);
281 | numberStack.addSpacer();
282 |
283 | dataStack.addSpacer(3);
284 |
285 | const titleStack = dataStack.addStack();
286 | titleStack.addSpacer();
287 | const title = titleStack.addText(data.title);
288 | title.font = Font.mediumSystemFont(11);
289 | title.textOpacity = 0.7;
290 | titleStack.addSpacer();
291 |
292 | dataStack.addSpacer(15);
293 | ;[title, number].map(t => t.textColor = new Color(color));
294 | }
295 |
296 | async imageCell(canvas, stack, data, fee, percent) {
297 | const canvaStack = stack.addStack();
298 | canvaStack.layoutVertically();
299 | if (!fee) {
300 | this.drawArc(canvas, data.percent * 3.6, data.FGColor, data.BGColor);
301 | canvaStack.size = new Size(this.ringStackSize, this.ringStackSize);
302 | canvaStack.backgroundImage = canvas.getImage();
303 | this.ringContent(canvaStack, data, percent);
304 | } else {
305 | canvaStack.addSpacer(10);
306 | const smallLogo = await this.$request.get(this.smallLogo, 'IMG');
307 | const logoStack = canvaStack.addStack();
308 | logoStack.size = new Size(30, 30);
309 | logoStack.backgroundImage = smallLogo;
310 | }
311 | }
312 |
313 | ringContent(stack, data, percent = false) {
314 | const rowIcon = stack.addStack();
315 | rowIcon.addSpacer();
316 | const icon = SFSymbol.named(data.icon);
317 | icon.applyHeavyWeight();
318 | const iconElement = rowIcon.addImage(icon.image);
319 | iconElement.tintColor = this.gradient ? new Color(data.colors[1]) : data.FGColor;
320 | iconElement.imageSize = new Size(12, 12);
321 | iconElement.imageOpacity = 0.7;
322 | rowIcon.addSpacer();
323 |
324 | stack.addSpacer(1);
325 |
326 | const rowNumber = stack.addStack();
327 | rowNumber.addSpacer();
328 | const number = rowNumber.addText(percent ? `${data.percent}` : `${data.number}`);
329 | number.font = percent ? Font.systemFont(this.ringTextSize - 2) : Font.mediumSystemFont(this.ringTextSize);
330 | rowNumber.addSpacer();
331 |
332 | const rowUnit = stack.addStack();
333 | rowUnit.addSpacer();
334 | const unit = rowUnit.addText(percent ? '%' : data.unit);
335 | unit.font = Font.boldSystemFont(8);
336 | unit.textOpacity = 0.5;
337 | rowUnit.addSpacer();
338 |
339 | if (percent) {
340 | if (this.gradient) {
341 | ;[unit, number].map(t => t.textColor = new Color(data.colors[1]));
342 | } else {
343 | ;[unit, number].map(t => t.textColor = data.FGColor);
344 | }
345 | } else {
346 | ;[unit, number].map(t => t.textColor = this.widgetColor);
347 | }
348 | }
349 |
350 | makeCanvas() {
351 | const canvas = new DrawContext();
352 | canvas.opaque = false;
353 | canvas.respectScreenScale = true;
354 | canvas.size = new Size(this.canvSize, this.canvSize);
355 | return canvas;
356 | }
357 |
358 | sinDeg(deg) {
359 | return Math.sin((deg * Math.PI) / 180);
360 | }
361 |
362 | cosDeg(deg) {
363 | return Math.cos((deg * Math.PI) / 180);
364 | }
365 |
366 | drawArc(canvas, deg, fillColor, strokeColor) {
367 | let ctr = new Point(this.canvSize / 2, this.canvSize / 2);
368 | let bgx = ctr.x - this.canvRadius;
369 | let bgy = ctr.y - this.canvRadius;
370 | let bgd = 2 * this.canvRadius;
371 | let bgr = new Rect(bgx, bgy, bgd, bgd)
372 |
373 | canvas.setStrokeColor(strokeColor);
374 | canvas.setLineWidth(this.canvWidth);
375 | canvas.strokeEllipse(bgr);
376 |
377 | for (let t = 0; t < deg; t++) {
378 | let rect_x = ctr.x + this.canvRadius * this.sinDeg(t) - this.canvWidth / 2;
379 | let rect_y = ctr.y - this.canvRadius * this.cosDeg(t) - this.canvWidth / 2;
380 | let rect_r = new Rect(rect_x, rect_y, this.canvWidth, this.canvWidth);
381 |
382 | canvas.setFillColor(this.gradient ? new Color(fillColor[t]) : fillColor);
383 | canvas.setStrokeColor(strokeColor)
384 | canvas.fillEllipse(rect_r);
385 | }
386 | }
387 |
388 | arrColor() {
389 | let colorArr = [['#FFF000', '#E62490'], ['#FDEB71', '#F8D800'], ['#ABDCFF', '#0396FF'], ['#FEB692', '#EA5455'], ['#FEB692', '#EA5455'], ['#CE9FFC', '#7367F0'], ['#90F7EC', '#32CCBC'], ['#FFF6B7', '#F6416C'], ['#E2B0FF', '#9F44D3'], ['#F97794', '#F072B6'], ['#FCCF31', '#F55555'], ['#5EFCE8', '#736EFE'], ['#FAD7A1', '#E96D71'], ['#FFFF1C', '#00C3FF'], ['#FEC163', '#DE4313'], ['#F6CEEC', '#D939CD'], ['#FDD819', '#E80505'], ['#FFF3B0', '#CA26FF'], ['#2AFADF', '#4C83FF'], ['#EECDA3', '#EF629F'], ['#C2E59C', '#64B3F4'], ['#FFF886', '#F072B6'], ['#F5CBFF', '#C346C2'], ['#FFF720', '#3CD500'], ['#EE9AE5', '#5961F9'], ['#FFC371', '#FF5F6D'], ['#FFD3A5', '#FD6585'], ['#C2FFD8', '#465EFB'], ['#FFC600', '#FD6E6A'], ['#FFC600', '#FD6E6A'], ['#92FE9D', '#00C9FF'], ['#FFDDE1', '#EE9CA7'], ['#F0FF00', '#58CFFB'], ['#FFE985', '#FA742B'], ['#72EDF2', '#5151E5'], ['#F6D242', '#FF52E5'], ['#F9D423', '#FF4E50'], ['#3C8CE7', '#00EAFF'], ['#FCFF00', '#FFA8A8'], ['#FF96F9', '#C32BAC'], ['#D0E6A5', '#FFDD94'], ['#FFDD94', '#FA897B'], ['#FFCC4B', '#FF7D58'], ['#D0E6A5', '#86E3CE'], ['#F0D5B6', '#F16238'], ['#F8EC70', '#F9C708'], ['#C4E86B', '#00BCB4'], ['#FFC446', '#FA0874'], ['#E1EE32', '#FFB547'], ['#FFD804', '#2ACCC8'], ['#E9A6D2', '#E9037B'], ['#F8EC70', '#49E2F6'], ['#A2F8CD', '#A2F852'], ['#49E2F6', '#A2F8CD'], ['#FDEFE2', '#FE214F'], ['#F8EC70', '#A2F8CD'], ['#F8EC70', '#49E2F6'], ['#B7FFE4', '#E4B7FF'], ['#FFB7D1', '#E4B7FF'], ['#D0E6A5', '#86E3CE'], ['#E8E965', '#64C5C7']];
390 | let colors = colorArr[Math.floor(Math.random() * colorArr.length)];
391 | return colors;
392 | }
393 |
394 | gradientColor(colors, step) {
395 | var startRGB = this.colorToRgb(colors[0]),
396 | startR = startRGB[0],
397 | startG = startRGB[1],
398 | startB = startRGB[2];
399 |
400 | var endRGB = this.colorToRgb(colors[1]),
401 | endR = endRGB[0],
402 | endG = endRGB[1],
403 | endB = endRGB[2];
404 |
405 | var sR = (endR - startR) / step,
406 | sG = (endG - startG) / step,
407 | sB = (endB - startB) / step;
408 |
409 | var colorArr = [];
410 | for (var i = 0;i < step; i++) {
411 | var hex = this.colorToHex('rgb(' + parseInt((sR * i + startR)) + ',' + parseInt((sG * i + startG)) + ',' + parseInt((sB * i + startB)) + ')');
412 | colorArr.push(hex);
413 | }
414 | return colorArr;
415 | }
416 |
417 | colorToRgb(sColor) {
418 | var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
419 | var sColor = sColor.toLowerCase();
420 | if (sColor && reg.test(sColor)) {
421 | if (sColor.length === 4) {
422 | var sColorNew = "#";
423 | for (var i = 1; i < 4; i += 1) {
424 | sColorNew += sColor.slice(i, i + 1).concat(sColor.slice(i, i + 1));
425 | }
426 | sColor = sColorNew;
427 | }
428 | var sColorChange = [];
429 | for (var i = 1; i < 7; i += 2) {
430 | sColorChange.push(parseInt("0x" + sColor.slice(i, i + 2)));
431 | }
432 | return sColorChange;
433 | } else {
434 | return sColor;
435 | }
436 | };
437 |
438 | colorToHex(rgb) {
439 | var _this = rgb;
440 | var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
441 | if (/^(rgb|RGB)/.test(_this)) {
442 | var aColor = _this.replace(/(?:\(|\)|rgb|RGB)*/g,"").split(",");
443 | var strHex = "#";
444 | for (var i = 0; i < aColor.length; i++) {
445 | var hex = Number(aColor[i]).toString(16);
446 | hex = hex.length < 2 ? 0 + '' + hex : hex;
447 | if (hex === "0") {
448 | hex += hex;
449 | }
450 | strHex += hex;
451 | }
452 | if (strHex.length !== 7) {
453 | strHex = _this;
454 | }
455 |
456 | return strHex;
457 | } else if (reg.test(_this)) {
458 | var aNum = _this.replace(/#/,"").split("");
459 | if (aNum.length === 6) {
460 | return _this;
461 | } else if (aNum.length === 3) {
462 | var numHex = "#";
463 | for (var i = 0; i < aNum.length; i+=1) {
464 | numHex += (aNum[i] + aNum[i]);
465 | }
466 | return numHex;
467 | }
468 | } else {
469 | return _this;
470 | }
471 | }
472 |
473 | renderSmall = async (w) => {
474 | w.setPadding(this.smallPadding, this.smallPadding, this.smallPadding, this.smallPadding);
475 | await this.smallHeader(w);
476 | const bodyStack = w.addStack();
477 | bodyStack.layoutVertically();
478 | if (this.widgetParam == "1"){
479 | this.textLayout(bodyStack, this.flow);
480 | bodyStack.addSpacer(7);
481 | this.textLayout(bodyStack, this.voice);
482 | bodyStack.addSpacer(7);
483 | this.textLayout(bodyStack, this.point);
484 | } else {
485 | const canvas = this.makeCanvas();
486 | const ringStack = bodyStack.addStack();
487 | this.imageCell(canvas, ringStack, this.flow);
488 | ringStack.addSpacer();
489 | this.imageCell(canvas, ringStack, this.voice);
490 | }
491 | return w;
492 | };
493 |
494 | renderMedium = async (w) => {
495 | w.setPadding(this.padding, this.padding, this.padding, this.padding);
496 | const canvas = this.makeCanvas();
497 | const bodyStack = w.addStack();
498 | await this.mediumCell(canvas, bodyStack, this.fee, '0A4B9D', true);
499 | bodyStack.addSpacer(this.padding);
500 | await this.mediumCell(canvas, bodyStack, this.flow, this.flowColorHex, false, true);
501 | bodyStack.addSpacer(this.padding);
502 | await this.mediumCell(canvas, bodyStack, this.voice, this.voiceColorHex, false,true);
503 | return w;
504 | };
505 |
506 | renderLarge = async (w) => {
507 | w.addText('暂不支持')
508 | return w;
509 | };
510 |
511 | renderWebView = async () => {
512 | const webView = new WebView();
513 | const url = 'https://e.189.cn/index.do';
514 | await webView.loadURL(url);
515 | await webView.present(false);
516 |
517 | const request = new Request(this.fetchUrl.detail);
518 | request.method = 'POST';
519 | const response = await request.loadJSON();
520 | console.log(response);
521 | if (response.result === -10001) {
522 | const index = await this.generateAlert('未获取到用户信息', [
523 | '取消',
524 | '重试',
525 | ]);
526 | if (index === 0) return;
527 | await this.renderWebView();
528 | } else {
529 | const cookies = request.response.cookies;
530 | let cookie = [];
531 | cookie = cookies.map((item) => `${item.name}=${item.value}`);
532 | cookie = cookie.join('; ');
533 | this.settings.cookie = cookie;
534 | this.saveSettings();
535 | }
536 | };
537 |
538 | Run() {
539 | if (config.runsInApp) {
540 | const widgetInitConfig = {cookie: 'china_telecom_cookie'};
541 | this.registerAction('颜色配置', async () => {
542 | await this.setAlertInput(
543 | `${this.name}颜色配置`,
544 | '进度条颜色|底圈颜色\n底圈颜色留空将跟随进度条颜色并淡显',
545 | {
546 | gradient: '是否开启渐变进度条,缺省:false',
547 | step1: '流量进度条颜色',
548 | step2: '语音进度条颜色',
549 | inner1: '流量进度条底圈颜色',
550 | inner2: '语音进度条底圈颜色',
551 | },
552 | );
553 | }, 'https://gitee.com/anker1209/image/raw/master/jd/colorSet.png');
554 | this.registerAction('尺寸设置', async () => {
555 | await this.setAlertInput(
556 | `${this.name}尺寸设置`,
557 | '进度条大小|文字大小',
558 | {
559 | logoScale: '小组件logo缩放,缺省:0.24',
560 | ringStackSize: '圆环大小,缺省:61',
561 | ringTextSize: '圆环中心文字大小,缺省:14',
562 | feeTextSize: '话费文字大小,缺省:21',
563 | textSize: '文字模式下文字大小,缺省:13',
564 | smallPadding: '小尺寸组件边距,缺省:16',
565 | padding: '中尺寸组件边距,缺省:10',
566 | },
567 | );
568 | }, 'https://gitee.com/anker1209/image/raw/master/jd/resize.png');
569 | this.registerAction('流量设置', async () => {
570 | await this.setAlertInput(
571 | `${this.name}流量设置`,
572 | '是否显示已用流量\n不限量或伪不限量用户可将此值设为true',
573 | {
574 | usedFlow: '是否显示已用流量,缺省:false',
575 | maxFlow: '实际流量或超限流量(GB),缺省:40',
576 | },
577 | );
578 | }, 'https://gitee.com/anker1209/image/raw/master/jd/flow.png');
579 | this.registerAction("账号设置", async () => {
580 | const index = await this.generateAlert("设置账号信息", [
581 | "网站登录",
582 | "手动输入",
583 | ]);
584 | if (index === 0) {
585 | await this.renderWebView();
586 | } else {
587 | await this.setAlertInput("账号设置", "中国电信 cookie", {
588 | cookie: 'cookie',
589 | });
590 | }
591 | }, 'https://gitee.com/anker1209/image/raw/master/jd/account.png');
592 | this.registerAction('代理缓存', async () => {
593 | await this.setCacheBoxJSData(widgetInitConfig);
594 | }, 'https://gitee.com/anker1209/image/raw/master/jd/boxjs.png');
595 | this.registerAction('基础设置', this.setWidgetConfig, 'https://gitee.com/anker1209/image/raw/master/jd/preferences.png');
596 | }
597 |
598 | try {
599 | const {
600 | cookie,
601 | step1,
602 | step2,
603 | inner1,
604 | inner2,
605 | logoScale,
606 | ringStackSize,
607 | ringTextSize,
608 | feeTextSize,
609 | textSize,
610 | smallPadding,
611 | padding,
612 | gradient,
613 | usedFlow,
614 | maxFlow,
615 | } = this.settings;
616 | this.cookie = cookie ? cookie : this.cookie;
617 | if (this.cookie) this.options.headers.cookie = this.cookie;
618 | this.gradient = gradient === 'true' ? true : this.gradient;
619 | this.usedFlow = usedFlow === 'true' ? true : this.usedFlow;
620 | this.flowColorHex = step1 ? step1 : this.flowColorHex;
621 | this.voiceColorHex = step2 ? step2 : this.voiceColorHex;
622 | this.flow.BGColor = inner1 ? new Color(inner1) : new Color(this.flowColorHex, 0.2);
623 | this.voice.BGColor = inner2 ? new Color(inner2) : new Color(this.voiceColorHex, 0.2);
624 | this.flow.FGColor = new Color(this.flowColorHex);
625 | this.voice.FGColor = new Color(this.voiceColorHex);
626 |
627 | this.flow.max = maxFlow ? parseFloat(maxFlow) : this.flow.max;
628 | this.logoScale = logoScale ? parseFloat(logoScale) : this.logoScale;
629 | this.ringStackSize = ringStackSize ? parseFloat(ringStackSize) : this.ringStackSize;
630 | this.ringTextSize = ringTextSize ? parseFloat(ringTextSize) : this.ringTextSize;
631 | this.feeTextSize = feeTextSize ? parseFloat(feeTextSize) : this.feeTextSize;
632 | this.textSize = textSize ? parseFloat(textSize) : this.textSize;
633 | this.smallPadding = smallPadding ? parseFloat(smallPadding) : this.smallPadding;
634 | this.padding = padding ? parseFloat(padding) : this.padding;
635 |
636 | if (this.gradient) {
637 | this.flow.colors = this.arrColor();
638 | this.voice.colors = this.arrColor();
639 | this.flow.BGColor = inner1 ? new Color(inner1) : new Color(this.flow.colors[1], 0.2);
640 | this.voice.BGColor = inner2 ? new Color(inner2) : new Color(this.voice.colors[1], 0.2);
641 | this.flow.FGColor = this.gradientColor(this.flow.colors, 360);
642 | this.voice.FGColor = this.gradientColor(this.voice.colors, 360);
643 | this.flowColorHex = this.flow.colors[1];
644 | this.voiceColorHex = this.voice.colors[1];
645 | }
646 |
647 | } catch (e) {
648 | console.log(e);
649 | }
650 | }
651 |
652 | async render() {
653 | await this.init();
654 | const widget = new ListWidget();
655 | await this.getWidgetBackgroundImage(widget);
656 | if (this.widgetFamily === 'medium') {
657 | return await this.renderMedium(widget);
658 | } else if (this.widgetFamily === 'large') {
659 | return await this.renderLarge(widget);
660 | } else {
661 | return await this.renderSmall(widget);
662 | }
663 | }
664 | }
665 |
666 | await Runing(Widget, args.widgetParameter, false);
667 |
--------------------------------------------------------------------------------
/scripts/ChinaUnicom_2021.js:
--------------------------------------------------------------------------------
1 | // Variables used by Scriptable.
2 | // These must be at the very top of the file. Do not edit.
3 | // icon-color: red; icon-glyph: mobile-alt;
4 | // Author: 脑瓜
5 | // 电报群:https://t.me/Scriptable_JS @anker1209
6 | // 该脚本小尺寸组件支持两种模式,默认为圆环进度条模式,主屏幕长按小组件-->编辑小组件-->Parameter,输入1,使用文字模式
7 | // 渐变进度条为试验性功能,默认关闭
8 | // version:2.1.0
9 | // update:2021/04/02
10 |
11 | if (typeof require === 'undefined') require = importModule;
12 | const {DmYY, Runing} = require('./DmYY');
13 |
14 | class Widget extends DmYY {
15 | constructor(arg) {
16 | super(arg);
17 | this.name = '中国联通';
18 | this.en = 'ChinaUnicom_2021';
19 | this.logo = 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-b1ebbd3c-ca49-405b-957b-effe60782276/cbbfab2c-790c-4308-b11f-299ae4311c07.png';
20 | this.verticalLogo = 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-b1ebbd3c-ca49-405b-957b-effe60782276/00010042-8cc7-4931-afe2-b65ee49f6374.png';
21 | this.Run();
22 | }
23 |
24 | widgetParam = args.widgetParameter;
25 | cookie = ''; // 推荐使用Boxjs代理缓存,若无请自行手动抓包后在此输入中国联通cookie数据。
26 |
27 | gradient = false;
28 |
29 | flowColorHex = '12A6E4';
30 | voiceColorHex = 'F86527';
31 |
32 | ringStackSize = 61;
33 | ringTextSize = 14;
34 | feeTextSize = 21;
35 | textSize = 13;
36 | smallPadding = 16;
37 | padding = 10;
38 | logoScale = 0.24;
39 |
40 | canvSize = 178;
41 | canvWidth = 18;
42 | canvRadius = 80;
43 |
44 | format = (str) => {
45 | return parseInt(str) >= 10 ? str : `0${str}`;
46 | };
47 |
48 | date = new Date();
49 | arrUpdateTime = [
50 | this.format(this.date.getMonth() + 1),
51 | this.format(this.date.getDate()),
52 | this.format(this.date.getHours()),
53 | this.format(this.date.getMinutes()),
54 | ];
55 |
56 | fee = {
57 | title: '话费剩余',
58 | number: 0,
59 | unit: '元',
60 | en: '¥',
61 | };
62 |
63 | flow = {
64 | percent: 0,
65 | title: '已用流量',
66 | number: 0,
67 | unit: 'MB',
68 | en: 'MB',
69 | icon: 'antenna.radiowaves.left.and.right',
70 | iconColor: new Color('1ab6f8'),
71 | FGColor: new Color(this.flowColorHex),
72 | BGColor: new Color(this.flowColorHex, 0.2),
73 | colors: [],
74 | };
75 |
76 | voice = {
77 | percent: 0,
78 | title: '语音剩余',
79 | number: 0,
80 | unit: '分钟',
81 | en: 'MIN',
82 | icon: 'phone.fill',
83 | iconColor: new Color('30d15b'),
84 | FGColor: new Color(this.voiceColorHex),
85 | BGColor: new Color(this.voiceColorHex, 0.2),
86 | colors: [],
87 | };
88 |
89 | point = {
90 | title: '剩余积分',
91 | number: 0,
92 | unit: '',
93 | icon: 'tag.fill',
94 | iconColor: new Color('fc6d6d'),
95 | }
96 |
97 | init = async () => {
98 | try {
99 | await this.getData();
100 | } catch (e) {
101 | console.log(e);
102 | }
103 | };
104 |
105 | async login() {
106 | const url = 'https://m.client.10010.com/dailylottery/static/textdl/userLogin?version=iphone_c@8.0200&desmobile=';
107 | try {
108 | const sign = new Request(url);
109 | sign.headers = {'cookie': this.cookie};
110 | const signInfo = await sign.loadString();
111 |
112 | if (signInfo.indexOf('天天抽奖') >= 0 && signInfo.indexOf('请稍后重试') < 0) {
113 | console.log('用户登录成功');
114 | } else {
115 | console.log('用户登录失败');
116 | }
117 | } catch (e) {
118 | console.log('用户登录失败' + e);
119 | }
120 | }
121 |
122 | async getData() {
123 | await this.login();
124 | const url= 'https://m.client.10010.com/mobileserviceimportant/home/queryUserInfoSeven?version=iphone_c@8.0200&desmobiel=&showType=0';
125 |
126 | try {
127 | const req = new Request(url);
128 | req.headers = {'cookie': this.cookie};
129 | const userInfo = await req.loadJSON();
130 |
131 | if (userInfo.code === 'Y') {
132 | console.log('获取信息成功');
133 | console.log(userInfo.data);
134 | userInfo.data.dataList.forEach((item) => {
135 | if (item.type === 'fee') {
136 | if (item.unit ==='万元') {
137 | this.fee.number = item.number * 10000;
138 | } else {
139 | this.fee.number = item.number;
140 | this.fee.unit = item.unit;
141 | }
142 | this.fee.title = item.remainTitle;
143 | }
144 | if (item.type === 'flow') {
145 | this.flow.number = item.number;
146 | this.flow.unit = item.unit;
147 | this.flow.en = item.unit;
148 | this.flow.percent = (100 - item.persent).toFixed(2);
149 | this.flow.title = item.remainTitle;
150 | }
151 | if (item.type === 'voice') {
152 | this.voice.number = item.number;
153 | this.voice.unit = item.unit;
154 | this.voice.percent = (100 - item.persent).toFixed(2);
155 | this.voice.title = item.remainTitle;
156 | }
157 | if (item.type === 'point') {
158 | this.point.number = item.number;
159 | this.point.title = item.remainTitle;
160 | }
161 | });
162 | } else {
163 | throw 'cookie错误/服务器维护';
164 | }
165 | } catch (e) {
166 | console.log('获取信息失败:' + e);
167 | }
168 | }
169 |
170 | async smallHeader(stack) {
171 | const headerStack = stack.addStack();
172 | headerStack.addSpacer();
173 | const logo = headerStack.addImage(await this.$request.get(this.logo, 'IMG'));
174 | logo.imageSize = new Size(415 * this.logoScale, 125 * this.logoScale);
175 | headerStack.addSpacer();
176 | stack.addSpacer();
177 |
178 | const feeStack = stack.addStack();
179 | feeStack.centerAlignContent();
180 | feeStack.addSpacer();
181 | const feeValue = feeStack.addText(`${this.fee.number}`);
182 | feeValue.font = Font.mediumRoundedSystemFont(this.feeTextSize);
183 | feeValue.textColor = this.widgetColor;
184 | feeStack.addSpacer();
185 | stack.addSpacer();
186 | }
187 |
188 | textLayout(stack, data) {
189 | const rowStack = stack.addStack();
190 | rowStack.centerAlignContent();
191 | const icon = SFSymbol.named(data.icon);
192 | icon.applyHeavyWeight();
193 | let iconElement = rowStack.addImage(icon.image);
194 | iconElement.imageSize = new Size(this.textSize, this.textSize);
195 | iconElement.tintColor = data.iconColor;
196 | rowStack.addSpacer(4);
197 | let title = rowStack.addText(data.title);
198 | rowStack.addSpacer();
199 | let number = rowStack.addText(data.number + data.unit);
200 | ;[title, number].map(t => t.textColor = this.widgetColor);
201 | ;[title, number].map(t => t.font = Font.systemFont(this.textSize));
202 | }
203 |
204 | async mediumCell(canvas, stack, data, color, fee = false, percent) {
205 | const bg = new LinearGradient();
206 | bg.locations = [0, 1];
207 | bg.colors = [
208 | new Color(color, 0.03),
209 | new Color(color, 0.1)
210 | ];
211 | const dataStack = stack.addStack();
212 | dataStack.backgroundGradient = bg;
213 | dataStack.cornerRadius = 20;
214 | dataStack.layoutVertically();
215 | dataStack.addSpacer();
216 |
217 | const topStack = dataStack.addStack();
218 | topStack.addSpacer();
219 | await this.imageCell(canvas, topStack, data, fee, percent);
220 | topStack.addSpacer();
221 |
222 | if (fee) {
223 | dataStack.addSpacer(5);
224 | const updateStack = dataStack.addStack();
225 | updateStack.addSpacer();
226 | updateStack.centerAlignContent();
227 | const updataIcon = SFSymbol.named('arrow.2.circlepath');
228 | updataIcon.applyHeavyWeight();
229 | const updateImg = updateStack.addImage(updataIcon.image);
230 | updateImg.tintColor = new Color(color, 0.6);
231 | updateImg.imageSize = new Size(10, 10);
232 | updateStack.addSpacer(3);
233 | const updateText = updateStack.addText(`${this.arrUpdateTime[2]}:${this.arrUpdateTime[3]}`)
234 | updateText.font = Font.mediumSystemFont(10);
235 | updateText.textColor = new Color(color, 0.6);
236 | updateStack.addSpacer();
237 | /*
238 | let tempStack = dataStack.addStack();
239 | tempStack.layoutVertically()
240 | let tempStack1 = tempStack.addStack()
241 | tempStack1.addSpacer()
242 | let tempText1 = tempStack1.addText(this.flow.colors.toString())
243 | tempStack1.addSpacer()
244 | let tempStack2 = tempStack.addStack()
245 | tempStack2.addSpacer()
246 | let tempText2 = tempStack2.addText(this.voice.colors.toString())
247 | tempStack2.addSpacer()
248 | ;[tempText1, tempText2].map(t => t.font = Font.systemFont(6));
249 | ;[tempText1, tempText2].map(t => t.textColor = updateText.textColor);
250 | */
251 | }
252 |
253 | dataStack.addSpacer();
254 |
255 | const numberStack = dataStack.addStack();
256 | numberStack.addSpacer();
257 | const number = numberStack.addText(`${data.number} ${data.en}`);
258 | number.font = Font.semiboldSystemFont(15);
259 | numberStack.addSpacer();
260 |
261 | dataStack.addSpacer(3);
262 |
263 | const titleStack = dataStack.addStack();
264 | titleStack.addSpacer();
265 | const title = titleStack.addText(data.title);
266 | title.font = Font.mediumSystemFont(11);
267 | title.textOpacity = 0.7;
268 | titleStack.addSpacer();
269 |
270 | dataStack.addSpacer(15);
271 | ;[title, number].map(t => t.textColor = new Color(color));
272 | }
273 |
274 | async imageCell(canvas, stack, data, fee, percent) {
275 | const canvaStack = stack.addStack();
276 | canvaStack.layoutVertically();
277 | if (!fee) {
278 | this.drawArc(canvas, data.percent * 3.6, data.FGColor, data.BGColor);
279 | canvaStack.size = new Size(this.ringStackSize, this.ringStackSize);
280 | canvaStack.backgroundImage = canvas.getImage();
281 | this.ringContent(canvaStack, data, percent);
282 | } else {
283 | canvaStack.addSpacer(10);
284 | const smallLogo = await this.$request.get(this.verticalLogo, 'IMG');
285 | const logoStack = canvaStack.addStack();
286 | logoStack.size = new Size(40, 40);
287 | logoStack.backgroundImage = smallLogo;
288 | }
289 | }
290 |
291 | ringContent(stack, data, percent = false) {
292 | const rowIcon = stack.addStack();
293 | rowIcon.addSpacer();
294 | const icon = SFSymbol.named(data.icon);
295 | icon.applyHeavyWeight();
296 | const iconElement = rowIcon.addImage(icon.image);
297 | iconElement.tintColor = this.gradient ? new Color(data.colors[1]) : data.FGColor;
298 | iconElement.imageSize = new Size(12, 12);
299 | iconElement.imageOpacity = 0.7;
300 | rowIcon.addSpacer();
301 |
302 | stack.addSpacer(1);
303 |
304 | const rowNumber = stack.addStack();
305 | rowNumber.addSpacer();
306 | const number = rowNumber.addText(percent ? `${data.percent}` : `${data.number}`);
307 | number.font = percent ? Font.systemFont(this.ringTextSize - 2) : Font.mediumSystemFont(this.ringTextSize);
308 | rowNumber.addSpacer();
309 |
310 | const rowUnit = stack.addStack();
311 | rowUnit.addSpacer();
312 | const unit = rowUnit.addText(percent ? '%' : data.unit);
313 | unit.font = Font.boldSystemFont(8);
314 | unit.textOpacity = 0.5;
315 | rowUnit.addSpacer();
316 |
317 | if (percent) {
318 | if (this.gradient) {
319 | ;[unit, number].map(t => t.textColor = new Color(data.colors[1]));
320 | } else {
321 | ;[unit, number].map(t => t.textColor = data.FGColor);
322 | }
323 | } else {
324 | ;[unit, number].map(t => t.textColor = this.widgetColor);
325 | }
326 | }
327 |
328 | makeCanvas() {
329 | const canvas = new DrawContext();
330 | canvas.opaque = false;
331 | canvas.respectScreenScale = true;
332 | canvas.size = new Size(this.canvSize, this.canvSize);
333 | return canvas;
334 | }
335 |
336 | sinDeg(deg) {
337 | return Math.sin((deg * Math.PI) / 180);
338 | }
339 |
340 | cosDeg(deg) {
341 | return Math.cos((deg * Math.PI) / 180);
342 | }
343 |
344 | drawArc(canvas, deg, fillColor, strokeColor) {
345 | let ctr = new Point(this.canvSize / 2, this.canvSize / 2);
346 | let bgx = ctr.x - this.canvRadius;
347 | let bgy = ctr.y - this.canvRadius;
348 | let bgd = 2 * this.canvRadius;
349 | let bgr = new Rect(bgx, bgy, bgd, bgd)
350 |
351 | canvas.setStrokeColor(strokeColor);
352 | canvas.setLineWidth(this.canvWidth);
353 | canvas.strokeEllipse(bgr);
354 |
355 | for (let t = 0; t < deg; t++) {
356 | let rect_x = ctr.x + this.canvRadius * this.sinDeg(t) - this.canvWidth / 2;
357 | let rect_y = ctr.y - this.canvRadius * this.cosDeg(t) - this.canvWidth / 2;
358 | let rect_r = new Rect(rect_x, rect_y, this.canvWidth, this.canvWidth);
359 | canvas.setFillColor(this.gradient ? new Color(fillColor[t]) : fillColor);
360 | canvas.setStrokeColor(strokeColor)
361 | canvas.fillEllipse(rect_r);
362 | }
363 | }
364 |
365 | arrColor() {
366 | let colorArr = [['#FFF000', '#E62490'], ['#ABDCFF', '#0396FF'], ['#FEB692', '#EA5455'], ['#FEB692', '#EA5455'], ['#CE9FFC', '#7367F0'], ['#90F7EC', '#32CCBC'], ['#FFF6B7', '#F6416C'], ['#E2B0FF', '#9F44D3'], ['#F97794', '#F072B6'], ['#FCCF31', '#F55555'], ['#5EFCE8', '#736EFE'], ['#FAD7A1', '#E96D71'], ['#FFFF1C', '#00C3FF'], ['#FEC163', '#DE4313'], ['#F6CEEC', '#D939CD'], ['#FDD819', '#E80505'], ['#FFF3B0', '#CA26FF'], ['#EECDA3', '#EF629F'], ['#C2E59C', '#64B3F4'], ['#FFF886', '#F072B6'], ['#F5CBFF', '#C346C2'], ['#FFF720', '#3CD500'], ['#FFC371', '#FF5F6D'], ['#FFD3A5', '#FD6585'], ['#C2FFD8', '#465EFB'], ['#FFC600', '#FD6E6A'], ['#FFC600', '#FD6E6A'], ['#92FE9D', '#00C9FF'], ['#FFDDE1', '#EE9CA7'], ['#F0FF00', '#58CFFB'], ['#FFE985', '#FA742B'], ['#72EDF2', '#5151E5'], ['#F6D242', '#FF52E5'], ['#F9D423', '#FF4E50'], ['#00EAFF', '#3C8CE7'], ['#FCFF00', '#FFA8A8'], ['#FF96F9', '#C32BAC'], ['#FFDD94', '#FA897B'], ['#FFCC4B', '#FF7D58'], ['#D0E6A5', '#86E3CE'], ['#F0D5B6', '#F16238'], ['#C4E86B', '#00BCB4'], ['#FFC446', '#FA0874'], ['#E1EE32', '#FFB547'], ['#FFD804', '#2ACCC8'], ['#E9A6D2', '#E9037B'], ['#F8EC70', '#49E2F6'], ['#A2F8CD', '#A2F852'], ['#A2F8CD', '#00C3FF'], ['#FDEFE2', '#FE214F'], ['#F8EC70', '#A2F8CD'], ['#F8EC70', '#49E2F6'], ['#FFB7D1', '#E4B7FF'], ['#D0E6A5', '#86E3CE'], ['#E8E965', '#64C5C7']];
367 | let colors = colorArr[Math.floor(Math.random() * colorArr.length)];
368 | return colors;
369 | }
370 |
371 | gradientColor(colors, step) {
372 | var startRGB = this.colorToRgb(colors[0]),
373 | startR = startRGB[0],
374 | startG = startRGB[1],
375 | startB = startRGB[2];
376 |
377 | var endRGB = this.colorToRgb(colors[1]),
378 | endR = endRGB[0],
379 | endG = endRGB[1],
380 | endB = endRGB[2];
381 |
382 | var sR = (endR - startR) / step,
383 | sG = (endG - startG) / step,
384 | sB = (endB - startB) / step;
385 |
386 | var colorArr = [];
387 | for (var i = 0;i < step; i++) {
388 | var hex = this.colorToHex('rgb(' + parseInt((sR * i + startR)) + ',' + parseInt((sG * i + startG)) + ',' + parseInt((sB * i + startB)) + ')');
389 | colorArr.push(hex);
390 | }
391 | return colorArr;
392 | }
393 |
394 | colorToRgb(sColor) {
395 | var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
396 | var sColor = sColor.toLowerCase();
397 | if (sColor && reg.test(sColor)) {
398 | if (sColor.length === 4) {
399 | var sColorNew = "#";
400 | for (var i = 1; i < 4; i += 1) {
401 | sColorNew += sColor.slice(i, i + 1).concat(sColor.slice(i, i + 1));
402 | }
403 | sColor = sColorNew;
404 | }
405 | var sColorChange = [];
406 | for (var i = 1; i < 7; i += 2) {
407 | sColorChange.push(parseInt("0x" + sColor.slice(i, i + 2)));
408 | }
409 | return sColorChange;
410 | } else {
411 | return sColor;
412 | }
413 | };
414 |
415 | colorToHex(rgb) {
416 | var _this = rgb;
417 | var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
418 | if (/^(rgb|RGB)/.test(_this)) {
419 | var aColor = _this.replace(/(?:\(|\)|rgb|RGB)*/g,"").split(",");
420 | var strHex = "#";
421 | for (var i = 0; i < aColor.length; i++) {
422 | var hex = Number(aColor[i]).toString(16);
423 | hex = hex.length < 2 ? 0 + '' + hex : hex;
424 | if (hex === "0") {
425 | hex += hex;
426 | }
427 | strHex += hex;
428 | }
429 | if (strHex.length !== 7) {
430 | strHex = _this;
431 | }
432 |
433 | return strHex;
434 | } else if (reg.test(_this)) {
435 | var aNum = _this.replace(/#/,"").split("");
436 | if (aNum.length === 6) {
437 | return _this;
438 | } else if (aNum.length === 3) {
439 | var numHex = "#";
440 | for (var i = 0; i < aNum.length; i+=1) {
441 | numHex += (aNum[i] + aNum[i]);
442 | }
443 | return numHex;
444 | }
445 | } else {
446 | return _this;
447 | }
448 | }
449 |
450 | renderSmall = async (w) => {
451 | w.setPadding(this.smallPadding, this.smallPadding, this.smallPadding, this.smallPadding);
452 | await this.smallHeader(w);
453 | const bodyStack = w.addStack();
454 | bodyStack.layoutVertically();
455 | if (this.widgetParam == "1"){
456 | this.textLayout(bodyStack, this.flow);
457 | bodyStack.addSpacer(7);
458 | this.textLayout(bodyStack, this.voice);
459 | bodyStack.addSpacer(7);
460 | this.textLayout(bodyStack, this.point);
461 | } else {
462 | const canvas = this.makeCanvas();
463 | const ringStack = bodyStack.addStack();
464 | this.imageCell(canvas, ringStack, this.flow);
465 | ringStack.addSpacer();
466 | this.imageCell(canvas, ringStack, this.voice);
467 | }
468 | return w;
469 | };
470 |
471 | renderMedium = async (w) => {
472 | w.setPadding(this.padding, this.padding, this.padding, this.padding);
473 | const canvas = this.makeCanvas();
474 | const bodyStack = w.addStack();
475 | await this.mediumCell(canvas, bodyStack, this.fee, 'd7000f', true);
476 | bodyStack.addSpacer(this.padding);
477 | await this.mediumCell(canvas, bodyStack, this.flow, this.flowColorHex, false, true);
478 | bodyStack.addSpacer(this.padding);
479 | await this.mediumCell(canvas, bodyStack, this.voice, this.voiceColorHex, false,true);
480 | return w;
481 | };
482 |
483 | renderLarge = async (w) => {
484 | w.addText('暂不支持')
485 | return w;
486 | };
487 |
488 | Run() {
489 | if (config.runsInApp) {
490 | const widgetInitConfig = {
491 | cookie: '@YaYa_10010.cookie',
492 | };
493 | this.registerAction('颜色配置', async () => {
494 | await this.setAlertInput(
495 | `${this.name}颜色配置`,
496 | '进度条颜色|底圈颜色\n底圈颜色留空将跟随进度条颜色并淡显',
497 | {
498 | gradient: '是否开启渐变进度条,缺省:false',
499 | step1: '流量进度条颜色',
500 | step2: '语音进度条颜色',
501 | inner1: '流量进度条底圈颜色',
502 | inner2: '语音进度条底圈颜色',
503 | },
504 | );
505 | }, 'https://gitee.com/anker1209/image/raw/master/jd/colorSet.png');
506 | this.registerAction('尺寸设置', async () => {
507 | await this.setAlertInput(
508 | `${this.name}尺寸设置`,
509 | '进度条大小|文字大小',
510 | {
511 | logoScale: '小组件logo缩放,缺省:0.24',
512 | ringStackSize: '圆环大小,缺省:61',
513 | ringTextSize: '圆环中心文字大小,缺省:14',
514 | feeTextSize: '话费文字大小,缺省:21',
515 | textSize: '文字模式下文字大小,缺省:13',
516 | smallPadding: '小尺寸组件边距,缺省:16',
517 | padding: '中尺寸组件边距,缺省:10',
518 | },
519 | );
520 | }, 'https://gitee.com/anker1209/image/raw/master/jd/resize.png');
521 | this.registerAction('账号设置', async () => {
522 | await this.setAlertInput(
523 | `${this.name}账号`,
524 | '读取 BoxJS 缓存信息',
525 | {cookie: 'cookie'},
526 | );
527 | }, 'https://gitee.com/anker1209/image/raw/master/jd/account.png');
528 | this.registerAction('代理缓存', async () => {
529 | await this.setCacheBoxJSData(widgetInitConfig);
530 | }, 'https://gitee.com/anker1209/image/raw/master/jd/boxjs.png');
531 | this.registerAction('基础设置', this.setWidgetConfig, 'https://gitee.com/anker1209/image/raw/master/jd/preferences.png');
532 | }
533 |
534 | try {
535 | const {
536 | cookie,
537 | step1,
538 | step2,
539 | inner1,
540 | inner2,
541 | logoScale,
542 | ringStackSize,
543 | ringTextSize,
544 | feeTextSize,
545 | textSize,
546 | smallPadding,
547 | padding,
548 | gradient,
549 | } = this.settings;
550 | this.cookie = cookie ? cookie : this.cookie;
551 | this.gradient = gradient === 'true' ? true : this.gradient;
552 | this.flowColorHex = step1 ? step1 : this.flowColorHex;
553 | this.voiceColorHex = step2 ? step2 : this.voiceColorHex;
554 | this.flow.BGColor = inner1 ? new Color(inner1) : new Color(this.flowColorHex, 0.2);
555 | this.voice.BGColor = inner2 ? new Color(inner2) : new Color(this.voiceColorHex, 0.2);
556 | this.flow.FGColor = new Color(this.flowColorHex);
557 | this.voice.FGColor = new Color(this.voiceColorHex);
558 |
559 | this.logoScale = logoScale ? parseFloat(logoScale) : this.logoScale;
560 | this.ringStackSize = ringStackSize ? parseFloat(ringStackSize) : this.ringStackSize;
561 | this.ringTextSize = ringTextSize ? parseFloat(ringTextSize) : this.ringTextSize;
562 | this.feeTextSize = feeTextSize ? parseFloat(feeTextSize) : this.feeTextSize;
563 | this.textSize = textSize ? parseFloat(textSize) : this.textSize;
564 | this.smallPadding = smallPadding ? parseFloat(smallPadding) : this.smallPadding;
565 | this.padding = padding ? parseFloat(padding) : this.padding;
566 |
567 | if (this.gradient) {
568 | this.flow.colors = this.arrColor();
569 | this.voice.colors = this.arrColor();
570 | this.flow.BGColor = inner1 ? new Color(inner1) : new Color(this.flow.colors[1], 0.2);
571 | this.voice.BGColor = inner2 ? new Color(inner2) : new Color(this.voice.colors[1], 0.2);
572 | this.flow.FGColor = this.gradientColor(this.flow.colors, 360);
573 | this.voice.FGColor = this.gradientColor(this.voice.colors, 360);
574 | this.flowColorHex = this.flow.colors[1];
575 | this.voiceColorHex = this.voice.colors[1];
576 | }
577 |
578 | } catch (e) {
579 | console.log(e);
580 | }
581 | }
582 |
583 | async render() {
584 | await this.init();
585 | const widget = new ListWidget();
586 | await this.getWidgetBackgroundImage(widget);
587 | if (this.widgetFamily === 'medium') {
588 | return await this.renderMedium(widget);
589 | } else if (this.widgetFamily === 'large') {
590 | return await this.renderLarge(widget);
591 | } else {
592 | return await this.renderSmall(widget);
593 | }
594 | }
595 | }
596 |
597 | await Runing(Widget, args.widgetParameter, false);
598 |
--------------------------------------------------------------------------------
/scripts/Chinaunicom.js:
--------------------------------------------------------------------------------
1 | // Variables used by Scriptable.
2 | // These must be at the very top of the file. Do not edit.
3 | // icon-color: red; icon-glyph: mobile-alt;
4 | // Author: 脑瓜
5 | // Github: https://github.com/anker1209/Scriptable
6 | // 该组件支持两种模式,默认为圆环进度条模式,主屏幕长按小组件-->编辑小组件-->Parameter,输入1,使用文字模式
7 |
8 | // #############设置##############
9 | const files = FileManager.local()
10 | const Tel = '' // 输入联通手机号码,,在两个引号之间输入
11 | const Cookie = '' // 输入联通cookie,在两个引号之间输入
12 | const ringStackSize = 61 // 圆环大小
13 | const ringTextSize = 14 // 圆环中心文字大小
14 | const creditTextSize = 21 // 话费文本大小
15 | const textSize = 13 // 文字模式下文字大小
16 | const databgColor = new Color("12A6E4", 0.2) // 流量环背景颜色
17 | const datafgColor = new Color("12A6E4") // 流量环前景颜色
18 | const voicebgColor = new Color("F86527", 0.2) // 语音环背景颜色
19 | const voicefgColor = new Color("F86527") // 语音环前景颜色
20 | const newBG = false //是否设置或者使用新的背景图片,若要设置背景图片,请勿将下一行值设为true
21 | const removeBG = false //是否需要清空背景图片,如果设置过背景图片,想再使用纯色背景,需将此设置为true清除背景图片缓存
22 | const setbgColor = false //是否设置固定纯色背景,如要设置,请在下行指定背景颜色
23 | const bgColor = "ffffff" // 背景颜色
24 | const widgetParam = args.widgetParameter
25 | let data = await getData()
26 |
27 | const title = "中国联通"
28 | const cuIconUrl = "https://vkceyugu.cdn.bspapp.com/VKCEYUGU-imgbed/f77d3cdc-b757-4acd-9766-a64421bf0c6d.png"
29 | const dataSfs = SFSymbol.named("antenna.radiowaves.left.and.right")
30 | dataSfs.applyHeavyWeight()
31 | const dataIcon = dataSfs.image
32 | const voiceIcon = SFSymbol.named("phone.fill").image
33 | const scoreIcon = SFSymbol.named("tag.fill").image
34 | const iconColor = new Color("FE8900")
35 | const phoneData = data.data.dataList[0]
36 | const credit = data.data.dataList[1]
37 | const voice = data.data.dataList[2]
38 | const score = data.data.dataList[3]
39 | const canvSize = 178
40 | const canvTextSize = 45
41 | const canvas = new DrawContext()
42 | const canvWidth = 18
43 | const canvRadius = 80
44 | const widget = new ListWidget()
45 | widget.setPadding(16, 16, 16, 16) // widget边距(上,下,左,右)
46 |
47 | // ############背景设置############
48 | const path = files.joinPath(files.documentsDirectory(), "Chinaunicom-20210129")
49 | if (newBG && config.runsInApp){
50 | const img = await Photos.fromLibrary()
51 | widget.backgroundImage = img
52 | files.writeImage(path, img)
53 | } else {
54 | if (files.fileExists(path)) {
55 | try {
56 | widget.backgroundImage = files.readImage(path)
57 | log("读取图片成功")
58 | } catch (e){
59 | log(e.message)
60 | }
61 | }
62 | }
63 | if (removeBG && files.fileExists(path)) {
64 | try {
65 | files.remove(path)
66 | log("背景图片清理成功")
67 | } catch (e) {
68 | log(e.message)
69 | }
70 | }
71 | if (setbgColor) {
72 | widget.backgroundColor = new Color(bgColor)
73 | }
74 |
75 | // ############LOGO###############
76 | let headerStack = widget.addStack()
77 | headerStack.layoutVertically
78 | headerStack.addSpacer()
79 | let logo = headerStack.addImage(await getImg(cuIconUrl))
80 | logo.imageSize = new Size(393*0.25, 118*0.25)
81 | headerStack.addSpacer()
82 | widget.addSpacer()
83 |
84 | let creditStack = widget.addStack()
85 | creditStack.centerAlignContent()
86 | creditStack.addSpacer()
87 | let creditElement = creditStack.addText(credit.number)
88 | creditElement.font = Font.mediumRoundedSystemFont(creditTextSize)
89 | creditStack.addSpacer()
90 | widget.addSpacer()
91 |
92 | // ###############################
93 | let bodyStack = widget.addStack()
94 | bodyStack.layoutVertically()
95 |
96 | if (widgetParam == "1"){
97 | await textLayout(dataIcon, phoneData.remainTitle, phoneData.number, phoneData.unit)
98 | bodyStack.addSpacer(8)
99 | await textLayout(voiceIcon, voice.remainTitle, voice.number, voice.unit)
100 | bodyStack.addSpacer(8)
101 | await textLayout(scoreIcon, score.remainTitle, score.number, score.unit)
102 | } else {
103 | canvas.size = new Size(canvSize, canvSize)
104 | canvas.opaque = false
105 | canvas.respectScreenScale = true
106 |
107 | const dataGap = (100-phoneData.persent)*3.6
108 | const voiceGap = (100-voice.persent)*3.6
109 |
110 | drawArc(dataGap, datafgColor, databgColor)
111 | let ringStack = bodyStack.addStack()
112 | let ringLeft = ringStack.addStack()
113 | ringLeft.layoutVertically()
114 | ringLeft.size = new Size(ringStackSize, ringStackSize)
115 | ringLeft.backgroundImage = canvas.getImage()
116 | await ringContent(ringLeft, dataIcon, datafgColor, phoneData.number, phoneData.unit)
117 | ringStack.addSpacer()
118 |
119 | drawArc(voiceGap, voicefgColor, voicebgColor)
120 | let ringRight = ringStack.addStack()
121 | ringRight.layoutVertically()
122 | ringRight.size = new Size(ringStackSize, ringStackSize)
123 | ringRight.backgroundImage = canvas.getImage()
124 | await ringContent(ringRight, voiceIcon, voicefgColor, voice.number, voice.unit)
125 | }
126 | // ###############################
127 | if (!config.runsInWidget) {
128 | await widget.presentSmall()
129 | }
130 | Script.setWidget(widget)
131 | Script.complete()
132 |
133 | async function getImg(url) {
134 | const req = new Request(url)
135 | const img = await req.loadImage()
136 | return img
137 | }
138 |
139 | function sinDeg(deg) {
140 | return Math.sin((deg * Math.PI) / 180)
141 | }
142 |
143 | function cosDeg(deg) {
144 | return Math.cos((deg * Math.PI) / 180)
145 | }
146 |
147 | function ringContent(widget, icon, iconColor, text, unit){
148 | const rowIcon = widget.addStack()
149 | rowIcon.addSpacer()
150 | const iconElement = rowIcon.addImage(icon)
151 | iconElement.tintColor = iconColor
152 | iconElement.imageSize = new Size(12, 12)
153 | iconElement.imageOpacity = 0.7
154 | rowIcon.addSpacer()
155 |
156 | widget.addSpacer(1)
157 |
158 | const rowText = widget.addStack()
159 | rowText.addSpacer()
160 | const textElement = rowText.addText(text)
161 | textElement.font = Font.mediumSystemFont(ringTextSize)
162 | rowText.addSpacer()
163 |
164 | const rowUnit = widget.addStack()
165 | rowUnit.addSpacer()
166 | const unitElement = rowUnit.addText(unit)
167 | unitElement.font = Font.boldSystemFont(8)
168 | unitElement.textOpacity = 0.5
169 | rowUnit.addSpacer()
170 | }
171 |
172 | function textLayout(icon, title, number, unit){
173 | const rowItem = bodyStack.addStack()
174 | rowItem.centerAlignContent()
175 | let iconElement = rowItem.addImage(icon)
176 | iconElement.imageSize = new Size(textSize, textSize)
177 | iconElement.tintColor = iconColor
178 | rowItem.addSpacer(4)
179 | let titleElement = rowItem.addText(title)
180 | titleElement.font = Font.systemFont(textSize)
181 | rowItem.addSpacer()
182 | let numberElement = rowItem.addText(number+unit)
183 | numberElement.font = Font.systemFont(textSize)
184 | }
185 |
186 | function drawArc(deg, fillColor, strokeColor, centerColor) {
187 | let ctr = new Point(canvSize / 2, canvSize / 2),
188 | bgx = ctr.x - canvRadius;
189 | bgy = ctr.y - canvRadius;
190 | bgd = 2 * canvRadius;
191 | bgr = new Rect(bgx, bgy, bgd, bgd)
192 |
193 | canvas.setFillColor(fillColor)
194 | canvas.setStrokeColor(strokeColor)
195 | canvas.setLineWidth(canvWidth)
196 | canvas.strokeEllipse(bgr)
197 |
198 | for (let t = 0; t < deg; t++) {
199 | rect_x = ctr.x + canvRadius * sinDeg(t) - canvWidth / 2
200 | rect_y = ctr.y - canvRadius * cosDeg(t) - canvWidth / 2
201 | rect_r = new Rect(rect_x, rect_y, canvWidth, canvWidth)
202 | canvas.fillEllipse(rect_r)
203 | }
204 | }
205 |
206 | async function getData() {
207 | const cachePath = files.joinPath(files.documentsDirectory(), "Chinaunicom-anker")
208 | var url= 'https://m.client.10010.com/mobileService/home/queryUserInfoSeven.htm?showType=3&version=iphone_c@7.0600&desmobiel='+Tel;
209 | var url1 = 'https://act.10010.com/SigninApp/signin/daySign'
210 | try {
211 | var req = new Request(url)
212 | req.headers = {'cookie': Cookie }
213 | console.log(req)
214 | var data = await req.loadJSON()
215 | console.log(data)
216 | var req1 = new Request(url1);
217 | req1.headers = {'cookie': Cookie }
218 | var data1 = await req1.loadJSON();
219 | if (data.signinState === '0'){
220 | files.writeString(cachePath, JSON.stringify(data))
221 | log("==>数据请求成功")
222 | }
223 | }
224 | catch (e) {
225 | data = JSON.parse(files.readString(cachePath))
226 | log("==>数据请求失败,使用缓存数据/"+ e)
227 | }
228 | return data
229 | }
230 |
--------------------------------------------------------------------------------
/scripts/JD-in-one-v2.js:
--------------------------------------------------------------------------------
1 | // Variables used by Scriptable.
2 | // These must be at the very top of the file. Do not edit.
3 | // icon-color: pink; icon-glyph: shopping-cart;
4 | // Author: 脑瓜
5 | // 电报群: https://t.me/Scriptable_JS @anker1209
6 | // 采用了2Ya美女的京豆收支脚本及DmYY依赖 https://github.com/dompling/Scriptable/tree/master/Scripts
7 | // version:2.2.7
8 | // update:2022/01/04
9 |
10 | if (typeof require === 'undefined') require = importModule;
11 | const {DmYY, Runing} = require('./DmYY');
12 |
13 | class Widget extends DmYY {
14 | constructor(arg) {
15 | super(arg);
16 | this.name = '京东多合一';
17 | this.en = 'jd_in_one';
18 | this.run(module.filename, args);
19 | }
20 | fm = FileManager.local();
21 | CACHE_FOLDER = 'JD_in_one';
22 | cachePath = null;
23 |
24 | logo = 'https://pic.imgdb.cn/item/6187994b2ab3f51d919028cc.png';
25 | JDImg = 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-b1ebbd3c-ca49-405b-957b-effe60782276/43300bf7-61a2-4bd1-94a1-bf2faa2ed9e8.png';
26 | beanImg = 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-imgbed/7ea91cf8-6dea-477c-ae72-cb4d3f646c34.png';
27 | plusFG = 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-b1ebbd3c-ca49-405b-957b-effe60782276/cd0d2b80-0857-4202-8d12-af4eb7d241d6.png';
28 | plusBG = 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-b1ebbd3c-ca49-405b-957b-effe60782276/24fc5a14-edea-4b1b-8e30-bdcc1a27a037.png';
29 | baitiaoImg = 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-b1ebbd3c-ca49-405b-957b-effe60782276/30c40f5b-7428-46c3-a2c0-d81b2b95ec41.png';
30 | plusIcon = 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-b1ebbd3c-ca49-405b-957b-effe60782276/06f78540-a5a4-462e-b8c5-98cb8059efc1.png';
31 | walletImg = 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-b1ebbd3c-ca49-405b-957b-effe60782276/cd89ceec-7895-41ee-a1a3-3d3e7223035f.png';
32 | jingtieImg = 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-b1ebbd3c-ca49-405b-957b-effe60782276/16a7038e-6082-4ad8-b17f-fdd08266fb22.png';
33 | gangbengImg = 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-b1ebbd3c-ca49-405b-957b-effe60782276/9704e332-9e7f-47e8-b09a-1f1991d4aa84.png';
34 | userImage = 'https://img11.360buyimg.com/jdphoto/s120x120_jfs/t21160/90/706848746/2813/d1060df5/5b163ef9N4a3d7aa6.png';
35 | nameImg = 'https://pic.imgdb.cn/item/6188bfb62ab3f51d91bca276.png';
36 | tagImg = 'https://pic.imgdb.cn/item/6188bfc72ab3f51d91bcbcb0.png';
37 |
38 | // 请勿在此修改参数值
39 |
40 | version = '2.2.6';
41 | basicSetting = {
42 | scale: 1.00,
43 | logo: 30,
44 | userImage: 69,
45 | userStack: 103,
46 | division: 25,
47 | interval: 10,
48 | directory: 'Local',
49 | customizeName: '',
50 | customizeAvatar: '',
51 | smallShowType: '京豆、钱包数据',
52 | walletShowType: '红包',
53 | };
54 | chartSetting = {
55 | height: 130,
56 | daySize: 9,
57 | dayText: '',
58 | textSize: 18,
59 | textDayColor: '999999',
60 | textNightColor: '999999',
61 | lineColor: '#FA6859',
62 | linePadding: 15,
63 | barPadding: 5,
64 | smallShowType: '双日视图',
65 | showType: '双日视图',
66 | countBean: '收入-支出',
67 | colorful: '关闭',
68 | };
69 | funcSetting = {
70 | showBaitiao: '打开',
71 | showPackage: '关闭',
72 | showFruit: '打开',
73 | logable: '关闭',
74 | alwaysRefreshChart: '打开',
75 | };
76 | package = {
77 | number: 0,
78 | title: '',
79 | desc: '',
80 | time: '',
81 | status: '',
82 | };
83 | baitiao = {
84 | title: '',
85 | number: 0,
86 | desc: '',
87 | };
88 | redPackage = {
89 | title: '红包',
90 | number: 0,
91 | desc: '今日无过期',
92 | };
93 | extra = {
94 | jingtie: 0,
95 | gangbeng: 0,
96 | };
97 | bean = {
98 | todayIncome: 0,
99 | todayExpense: 0,
100 | ydayIncome: 0,
101 | ydayExpense: 0,
102 | };
103 |
104 | nickName = '未知用户';
105 | jValue = '0';
106 | isPlus = false;
107 |
108 | cookie = '';
109 | userName = '';
110 | CookiesData = [];
111 | cacheChart = false;
112 | beanCount = 0;
113 | maxDays = 6;
114 | rangeTimer = {};
115 | timerKeys = [];
116 | fruitState = "😢";
117 |
118 | doubleDate = this.getDay(1);
119 | doubleDay = Object.keys(this.doubleDate);
120 | yestoday = this.doubleDay[0];
121 | today = this.doubleDay[1];
122 | CACHES = [];
123 |
124 | lineChart(labels = [], datas = [], chartTextSize, topPadding) {
125 | let chartTextColor = Color.dynamic(new Color(this.chartSetting.textDayColor),new Color(this.chartSetting.textNightColor),);
126 | let lineColor = this.chartSetting.lineColor.split(',');
127 | const chartStr = `
128 | {
129 | type: 'bar',
130 | data: {
131 | labels: ${JSON.stringify(labels)},
132 | datasets: [
133 | {
134 | type: 'line',
135 | backgroundColor: '#FFFFFF',
136 | borderColor: getGradientFillHelper('horizontal', ${JSON.stringify(lineColor)}),
137 | borderWidth: ${this.isSmall(true) ? 4 : 3},
138 | pointRadius: ${this.isSmall(true) ? 8 : 6},
139 | fill: false,
140 | showLine: true,
141 | data: ${JSON.stringify(datas)},
142 | },
143 | ],
144 | },
145 | options: {
146 | plugins: {
147 | datalabels: {
148 | display: true,
149 | align: 'top',
150 | color: '#${chartTextColor.hex}',
151 | font: {
152 | family: 'ArialMT',
153 | size: ${chartTextSize}
154 | }
155 | },
156 | },
157 | layout: {
158 | padding: {
159 | left: -20,
160 | right: 0,
161 | top: ${topPadding},
162 | bottom: 0
163 | }
164 | },
165 | responsive: true,
166 | maintainAspectRatio: true,
167 | legend: {
168 | display: false,
169 | },
170 | scales: {
171 | xAxes: [
172 | {
173 | gridLines: {
174 | display: false,
175 | },
176 | ticks: {
177 | display: false,
178 | },
179 | },
180 | ],
181 | yAxes: [
182 | {
183 | ticks: {
184 | display: false,
185 | beginAtZero: false,
186 | },
187 | gridLines: {
188 | display: false,
189 | },
190 | },
191 | ],
192 | },
193 | },
194 | }`;
195 | return chartStr;
196 | }
197 |
198 | barChart(labels = [], datas = [], chartTextSize, topPadding, showType) {
199 | let chartTextColor = Color.dynamic(new Color(this.chartSetting.textDayColor),new Color(this.chartSetting.textNightColor),);
200 | let backgroundColor = [];
201 | if (this.chartSetting.colorful === '打开') backgroundColor = JSON.stringify(this.colorfulBar())
202 | else backgroundColor = `getGradientFillHelper('vertical', ${JSON.stringify(this.chartColors())})`
203 | const chartStr = `
204 | {
205 | type: 'bar',
206 | data: {
207 | labels: ${JSON.stringify(labels)},
208 | datasets: [
209 | {
210 | type: '${showType}',
211 | borderWidth: 0,
212 | pointRadius: 0,
213 | barPercentage: 0.5,
214 | backgroundColor: ${backgroundColor},
215 | borderColor: false,
216 | data: ${JSON.stringify(datas)},
217 | },
218 | ],
219 | },
220 | options: {
221 | plugins: {
222 | datalabels: {
223 | display: true,
224 | align: 'top',
225 | offset: -4,
226 | anchor:'end',
227 | color: '#${chartTextColor.hex}',
228 | font: {
229 | family: 'ArialMT',
230 | size: ${chartTextSize}
231 | }
232 | },
233 | },
234 | layout: {
235 | padding: {
236 | left: -20,
237 | right: 0,
238 | top: ${topPadding},
239 | bottom: 0
240 | }
241 | },
242 | responsive: true,
243 | maintainAspectRatio: true,
244 | legend: {
245 | display: false,
246 | },
247 | title: {
248 | display: false,
249 | },
250 | scales: {
251 | xAxes: [
252 | {
253 | gridLines: {
254 | offsetGridLines: true,
255 | display: false,
256 | },
257 | ticks: {
258 | display: false,
259 | },
260 | },
261 | ],
262 | yAxes: [
263 | {
264 | ticks: {
265 | display: false,
266 | beginAtZero: true,
267 | },
268 | gridLines: {
269 | offsetGridLines: true,
270 | display: false,
271 | },
272 | },
273 | ],
274 | },
275 | },
276 | }`;
277 | return chartStr;
278 | }
279 |
280 | chartColors () {
281 | let colorArr = [['#FFF000', '#E62490'], ['#FDEB71', '#F8D800'], ['#ABDCFF', '#0396FF'], ['#FEB692', '#EA5455'], ['#FEB692', '#EA5455'], ['#CE9FFC', '#7367F0'], ['#90F7EC', '#32CCBC'], ['#FFF6B7', '#F6416C'], ['#E2B0FF', '#9F44D3'], ['#F97794', '#F072B6'], ['#FCCF31', '#F55555'], ['#5EFCE8', '#736EFE'], ['#FAD7A1', '#E96D71'], ['#FFFF1C', '#00C3FF'], ['#FEC163', '#DE4313'], ['#F6CEEC', '#D939CD'], ['#FDD819', '#E80505'], ['#FFF3B0', '#CA26FF'], ['#2AFADF', '#4C83FF'], ['#EECDA3', '#EF629F'], ['#C2E59C', '#64B3F4'], ['#FFF886', '#F072B6'], ['#F5CBFF', '#C346C2'], ['#FFF720', '#3CD500'], ['#EE9AE5', '#5961F9'], ['#FFC371', '#FF5F6D'], ['#FFD3A5', '#FD6585'], ['#C2FFD8', '#465EFB'], ['#FFC600', '#FD6E6A'], ['#FFC600', '#FD6E6A'], ['#92FE9D', '#00C9FF'], ['#FFDDE1', '#EE9CA7'], ['#F0FF00', '#58CFFB'], ['#FFE985', '#FA742B'], ['#72EDF2', '#5151E5'], ['#F6D242', '#FF52E5'], ['#F9D423', '#FF4E50'], ['#3C8CE7', '#00EAFF'], ['#FCFF00', '#FFA8A8'], ['#FF96F9', '#C32BAC'], ['#D0E6A5', '#FFDD94'], ['#FFDD94', '#FA897B'], ['#FFCC4B', '#FF7D58'], ['#D0E6A5', '#86E3CE'], ['#F0D5B6', '#F16238'], ['#F8EC70', '#F9C708'], ['#C4E86B', '#00BCB4'], ['#F5CEC7', '#E79796'], ['#FFC446', '#FA0874'], ['#E1EE32', '#FFB547'], ['#FFD804', '#2ACCC8'], ['#E9A6D2', '#E9037B'], ['#F8EC70', '#49E2F6'], ['#A2F8CD', '#A2F852'], ['#49E2F6', '#A2F8CD'], ['#FDEFE2', '#FE214F'], ['#F8EC70', '#A2F8CD'], ['#F8EC70', '#49E2F6'], ['#D1FFB7', '#FFB7D1'], ['#B7FFE4', '#E4B7FF'], ['#FFB7D1', '#E4B7FF'], ['#D0E6A5', '#86E3CE'], ['#E8E965', '#64C5C7']];
282 | let chartColors = colorArr[Math.floor(Math.random() * colorArr.length)];
283 | //chartColors = ['#DB36A4', '#F7FF00']; // 固定京豆图表填充颜色
284 | return chartColors;
285 | }
286 |
287 | colorfulBar () {
288 | let colorArr = [['#1B9E77', '#D95F02', '#7570B3', '#E7298A', '#66A61E', '#E6AB02'], ['#F46277', '#FC8D59', '#FEE08B', '#E6F598', '#99D594', '#3288BD'], ['#A6CEE3', '#1F78B4', '#B2DF8A', '#33A02C', '#FB9A99', '#E31A1C'], ['#E41A1C', '#377EB8', '#4DAF4A', '#984EA3', '#FF7F00', '#9ED80E'], ['#F81B02', '#FC7715', '#AFBF41', '#50C49F', '#3B95C4', '#B560D4'], ['#FFC000', '#A5D028', '#08CC78', '#F24099', '#5AA6C0', '#F56617'], ['#F09415', '#C1B56B', '#4BAF73', '#5AA6C0', '#D17DF9', '#FA7E5C'], ['#0F6FC6', '#009DD9', '#0BD0D9', '#10CF9B', '#7CCA62', '#A5C249'], ['#9ACD4C', '#FAA93A', '#D35940', '#B258D3', '#63A0CC', '#8AC4A7'], ['#A7EA52', '#EFAB16', '#78AC35', '#35ACA2', '#4083CF', '#FF8021'], ['#9EC544', '#50BEA3', '#4A9CCC', '#9A66CA', '#C54F71', '#DE9C3C'], ['#41AEBD', '#97E9D5', '#A2CF49', '#608F3D', '#F4DE3A', '#FCB11C'], ['#2FA3EE', '#4BCAAD', '#86C157', '#D99C3F', '#CE6633', '#A35DD1'], ['#3399FF', '#69FFFF', '#CCFF33', '#3333FF', '#9933FF', '#FF33FF'], ['#FBC01E', '#EFE1A2', '#FA8716', '#F2575F', '#A5D848', '#A155F9'], ['#90C226', '#54A021', '#E6B91E', '#E76618', '#C42F1A', '#FA8716'], ['#0F6FC6', '#009DD9', '#0BD0D9', '#10CF9B', '#7CCA62', '#A5C249'], ['#FFB91D', '#F97817', '#6DE304', '#F98080', '#8F58F9', '#F789EA'], ['#C70F0C', '#DD6B0D', '#FAA700', '#93E50D', '#17C7BA', '#0A96E4'], ['#40BAD2', '#FAB900', '#90BB23', '#EE7008', '#1AB39F', '#D5393D'], ['#80B606', '#E29F1D', '#2397E2', '#35ACA2', '#5430BB', '#8D34E0'], ['#549E39', '#8AB833', '#C0CF3A', '#029676', '#4AB5C4', '#0989B1'], ['#99CB38', '#63A537', '#37A76F', '#44C1A3', '#4EB3CF', '#51C3F9'], ['#8C73D0', '#C2E8C4', '#C5A6E8', '#B45EC7', '#9FDAFB', '#95C5B0'], ['#1CADE4', '#2683C6', '#27CED7', '#42BA97', '#3E8853', '#62A39F'], ['#B31166', '#E33D6F', '#E45F3C', '#E9943A', '#9B6BF2', '#D53DD0'], ['#76C5EF', '#FEA022', '#FF6700', '#70A525', '#A5D848', '#20768C'], ['#A1D68B', '#5EC795', '#4DADCF', '#CDB756', '#E29C36', '#8EC0C1'], ['#418AB3', '#A6B727', '#F69200', '#80C34F', '#FEC306', '#DF5327'], ['#7FD13B', '#EA157A', '#FEB80A', '#00ADDC', '#738AC8', '#1AB39F'], ['#F0AD00', '#60B5CC', '#E66C7D', '#6BB76D', '#E88651', '#C64847'], ['#5B9BD5', '#ED7D31', '#A5D848', '#FFC000', '#4472C4', '#70AD47'], ['#4F81BD', '#C0504D', '#9BBB59', '#8064A2', '#4BACC6', '#F79646'], ['#F95F9A', '#AC66BB', '#DE6C36', '#F9B639', '#CF6DA4', '#FA8D3D'], ['#F2D908', '#9DE61E', '#0D8BE6', '#C61B1B', '#E26F08', '#8D35D1'], ['#A5B592', '#F3A447', '#E7BC29', '#D092A7', '#9C85C0', '#809EC2'], ['#30ACEC', '#80C34F', '#E29D3E', '#D64A3B', '#D64787', '#A666E1'], ['#A2C816', '#E07602', '#E4C402', '#7DC1EF', '#21449B', '#A2B170'], ['#FF7F01', '#F1B015', '#FBEC85', '#D2C2F1', '#DA5AF4', '#9D09D1'], ['#FDA023', '#A7EA52', '#5ECCF3', '#64A73B', '#EB5605', '#B9CA1A'], ['#00C6BB', '#6FEBA0', '#B6DF5E', '#EFB251', '#EF755F', '#ED515C'], ['#E32D91', '#C830CC', '#4EA6DC', '#4775E7', '#8971E1', '#D54773'], ['#1CADE4', '#2683C6', '#27CED7', '#42BA97', '#3E8853', '#62A39F'], ['#073779', '#8FD9FB', '#FFCC00', '#EB6615', '#C76402', '#B523B4'], ['#4E67C8', '#5ECCF3', '#A7EA52', '#5DCEAF', '#FF8021', '#F14124'], ['#3891A7', '#FEB80A', '#FC8389', '#84AA33', '#F9934E', '#4379EF'], ['#990000', '#FF6600', '#FFBA00', '#99CC00', '#528A02', '#9C007F'], ['#F7901E', '#FEC60B', '#9FE62F', '#4EA5D1', '#4282EA', '#854FED'], ['#E8BC4A', '#83C1C6', '#E78D35', '#909CE1', '#839C41', '#F9826E'], ['#86CE24', '#00A2E6', '#FAC810', '#AA69F7', '#D06B20', '#FF8021'], ['#DF2E28', '#FE801A', '#E9BF35', '#81BB42', '#32C7A9', '#4A9BDC'], ['#31B6FD', '#4584D3', '#5BD078', '#A5D028', '#F5C040', '#05E0DB'], ['#FFCA08', '#F8931D', '#CE8D3E', '#EC7016', '#E64823', '#9C6A6A'], ['#4E79A7', '#F28E2B', '#E15759', '#76B7B2', '#59A14F', '#EDC948'], ['#4E79A7', '#A0CBE8', '#F28E2B', '#FFBE7D', '#59A14F', '#8CD17D'], ['#E03531', '#F0BD27', '#51B364', '#FF684C', '#FFDA66', '#8ACE7E'], ['#4E9F50', '#87D180', '#EF8A0C', '#FCC66D', '#3CA8BC', '#98D9E4'], ['#1F77B4', '#FF7F0E', '#2CA02C', '#D62728', '#9467BD', '#E377C2'], ['#32A251', '#ACD98D', '#FF7F0F', '#FFB977', '#3CB7CC', '#98D9E4'], ];
289 | let chartColors = colorArr[Math.floor(Math.random() * colorArr.length)];
290 | //chartColors = ['#C1B14A','#6FBC75','#39B6B3','#86A1CD','#D083AB','#DF786B']; // 固定京豆图表填充颜色
291 | return chartColors;
292 | }
293 |
294 | isSmall (a = false) {
295 | if (a) return config.widgetFamily == 'small' ? true : false;
296 | else return config.widgetFamily == 'small' ? '_small' : '';
297 | }
298 |
299 | // #####################小组件###################
300 | renderSmall = async (w) => {
301 | const bodyStack = w.addStack();
302 | bodyStack.layoutVertically();
303 | if (this.basicSetting.smallShowType === '个人信息') {
304 | await this.setUserShow(bodyStack);
305 | } else {
306 | await this.setHeaderShow(bodyStack);
307 | bodyStack.addSpacer();
308 | switch (this.chartSetting.smallShowType) {
309 | case '折线图表' :
310 | await this.setChartShow(bodyStack, 1);
311 | break;
312 | case '柱状图表' :
313 | await this.setChartShow(bodyStack, 2);
314 | break;
315 | case '曲线面积图':
316 | await this.setChartShow(bodyStack, 3);
317 | break;
318 | default:
319 | await this.setBeanShow(bodyStack, 22 * this.basicSetting.scale, 40 * this.basicSetting.scale);
320 | }
321 | bodyStack.addSpacer(5 * this.basicSetting.scale);
322 | if (this.funcSetting.showBaitiao === '打开' && this.baitiao.number > 0) {
323 | await this.setBaitiaoShow(bodyStack, true);
324 | } else if (this.basicSetting.walletShowType === '红包') {
325 | await this.setRedPackageShow(bodyStack, true);
326 | } else {
327 | await this.setCoinShow(bodyStack, true);
328 | }
329 | }
330 | return w;
331 | }
332 |
333 | // #####################中组件###################
334 | renderMedium = async (w) => {
335 | const bodyStack = w.addStack();
336 | await this.setUserShow(bodyStack);
337 | bodyStack.addSpacer(this.basicSetting.division * this.basicSetting.scale);
338 | const mainStack = bodyStack.addStack();
339 | mainStack.layoutVertically();
340 | await this.setHeaderShow(mainStack, this.JDImg);
341 | mainStack.addSpacer();
342 | if (this.funcSetting.showPackage === '打开' && this.package.number > 0) {
343 | await this.setPackageShow(mainStack);
344 | mainStack.addSpacer();
345 | } else {
346 | switch (this.chartSetting.showType) {
347 | case '折线图表':
348 | await this.setChartShow(mainStack, 1);
349 | mainStack.addSpacer(5 * this.basicSetting.scale);
350 | break;
351 | case '柱状图表':
352 | await this.setChartShow(mainStack, 2);
353 | mainStack.addSpacer(5 * this.basicSetting.scale);
354 | break;
355 | case '曲线面积图':
356 | await this.setChartShow(mainStack, 3);
357 | mainStack.addSpacer(5 * this.basicSetting.scale);
358 | break;
359 | default:
360 | await this.setBeanShow(mainStack, 30 * this.basicSetting.scale, 50 * this.basicSetting.scale);
361 | mainStack.addSpacer();
362 | }
363 | }
364 | if (this.funcSetting.showBaitiao === '打开' && this.baitiao.number > 0) {
365 | await this.setBaitiaoShow(mainStack);
366 | } else if (this.basicSetting.walletShowType === '红包') {
367 | await this.setRedPackageShow(mainStack);
368 | } else {
369 | await this.setCoinShow(mainStack);
370 | }
371 | return w;
372 | }
373 |
374 | // #####################大组件###################
375 | renderLarge = async (w) => {
376 | const bodyStack = w.addStack();
377 | bodyStack.size = new Size(0, 150);
378 | bodyStack.addSpacer();
379 | await this.setUserShow(bodyStack);
380 | bodyStack.addSpacer();
381 | w.addSpacer(20);
382 | const text = w.addText('\u6211\u600e\u4e48\u8fd9\u4e48\u597d\u770b');
383 | w.addSpacer(20);
384 | text.font = Font.thinSystemFont(30);
385 | text.centerAlignText();
386 | const emoji = w.addText('🤣🥰🤪');
387 | emoji.centerAlignText();
388 | w.addSpacer();
389 | return w;
390 | }
391 |
392 | // #####################用户信息###################
393 | async setUserShow(stack) {
394 | const userStack = stack.addStack();
395 | userStack.size = new Size(this.basicSetting.userStack * this.basicSetting.scale, 0);
396 | userStack.layoutVertically();
397 | // 头像
398 | const userImgStack = userStack.addStack();
399 | userImgStack.addSpacer();
400 | const imgStack = userImgStack.addStack();
401 | if (this.isPlus) {
402 | imgStack.size = new Size(this.basicSetting.userImage * this.basicSetting.scale, this.basicSetting.userImage * this.basicSetting.scale * 1.039);
403 | imgStack.backgroundImage = await this.getImageByUrl(this.plusBG, 'plusBGImage.png');
404 | }
405 | const subStack = imgStack.addStack();
406 | subStack.url = 'openapp.jdmobile://';
407 | subStack.size = new Size(this.basicSetting.userImage * this.basicSetting.scale, this.basicSetting.userImage * this.basicSetting.scale);
408 | subStack.cornerRadius = this.basicSetting.userImage / 2 * this.basicSetting.scale;
409 | subStack.backgroundImage = await this.getImageByUrl(this.basicSetting.customizeAvatar || this.userImage, `userImage_${this.userName}.png`);
410 | if (this.isPlus) {
411 | const userImg = subStack.addImage(await this.getImageByUrl(this.plusFG, 'plusFGImage.png'));
412 | }
413 | userImgStack.addSpacer();
414 | userStack.addSpacer();
415 | // 物流提示
416 | const tipStack = userStack.addStack();
417 | tipStack.addSpacer();
418 | const signStack = tipStack.addStack();
419 | signStack.size = new Size(14 * this.basicSetting.scale, 14 * this.basicSetting.scale)
420 | signStack.backgroundColor = new Color('0dD6A0');
421 | signStack.cornerRadius = 14 * this.basicSetting.scale / 2;
422 | signStack.centerAlignContent();
423 | let signIcon = SFSymbol.named('checkmark');
424 | const signItem = signStack.addImage(signIcon.image);
425 | signItem.imageSize = new Size(8 * this.basicSetting.scale, 8 * this.basicSetting.scale);
426 | signItem.tintColor = new Color('FFFFFF');
427 | if (this.package.number > 0) {
428 | tipStack.addSpacer(3 * this.basicSetting.scale);
429 | const packageStack = tipStack.addStack();
430 | packageStack.size = new Size(14 * this.basicSetting.scale, 14 * this.basicSetting.scale)
431 | packageStack.backgroundColor = new Color('FC8600');
432 | packageStack.cornerRadius = 14 * this.basicSetting.scale / 2;
433 | packageStack.centerAlignContent();
434 | packageStack.setPadding(1 * this.basicSetting.scale, 2 * this.basicSetting.scale, 1 * this.basicSetting.scale, 2 * this.basicSetting.scale);
435 | let packageNum = packageStack.addText(this.package.number.toString());
436 | packageNum.font = Font.mediumSystemFont(15 * this.basicSetting.scale);
437 | packageNum.textColor = new Color('FFFFFF');
438 | packageNum.minimumScaleFactor = 0.1;
439 | }
440 | if (this.funcSetting.showFruit === '打开') {
441 | tipStack.addSpacer(3 * this.basicSetting.scale);
442 | const fruitStack = tipStack.addStack();
443 | fruitStack.size = new Size(14 * this.basicSetting.scale, 14 * this.basicSetting.scale)
444 | fruitStack.backgroundColor = new Color('118AB2');
445 | fruitStack.cornerRadius = 14 * this.basicSetting.scale / 2;
446 | fruitStack.centerAlignContent();
447 | fruitStack.setPadding(1 * this.basicSetting.scale, 2 * this.basicSetting.scale, 1 * this.basicSetting.scale, 2 * this.basicSetting.scale);
448 | let fruitText = fruitStack.addText(this.fruitState);
449 | fruitText.font = Font.mediumSystemFont(15 * this.basicSetting.scale);
450 | fruitText.textColor = new Color('FFFFFF');
451 | fruitText.minimumScaleFactor = 0.1;
452 | }
453 | tipStack.addSpacer();
454 | userStack.addSpacer();
455 | // 用户名
456 | const nameStack = userStack.addStack();
457 | nameStack.centerAlignContent();
458 | if (this.isPlus) {
459 | const nameImg = nameStack.addImage(await this.getImageByUrl(this.plusIcon, 'plusIcon.png'));
460 | nameImg.imageSize = new Size(15 * this.basicSetting.scale, 15 * this.basicSetting.scale);
461 | } else {
462 | const nameIcon = nameStack.addImage(await this.getImageByUrl(this.nameImg, 'nameImg.png'));
463 | nameIcon.imageSize = new Size(15 * this.basicSetting.scale, 15 * this.basicSetting.scale);
464 | }
465 | nameStack.addSpacer(5 * this.basicSetting.scale);
466 | const name = nameStack.addText(this.basicSetting.customizeName || this.nickName);
467 | name.lineLimit = 1;
468 | name.font = Font.regularSystemFont(14 * this.basicSetting.scale);
469 | userStack.addSpacer(5 * this.basicSetting.scale);
470 | // 京享值
471 | const valueStack = userStack.addStack();
472 | valueStack.centerAlignContent();
473 | const lableIcon = valueStack.addImage(await this.getImageByUrl(this.tagImg, 'tagImg.png'));
474 | lableIcon.imageSize = new Size(15 * this.basicSetting.scale, 15 * this.basicSetting.scale);
475 | valueStack.addSpacer(5 * this.basicSetting.scale);
476 | const value = valueStack.addText(this.jValue.toString());
477 | value.font = Font.mediumSystemFont(14 * this.basicSetting.scale);
478 |
479 | valueStack.addSpacer(5 * this.basicSetting.scale);
480 | const jStack = valueStack.addStack();
481 | jStack.backgroundColor = new Color('fa2d19'); // “京享”二字背景颜色
482 | jStack.cornerRadius = 5;
483 | jStack.setPadding(1 * this.basicSetting.scale, 4 * this.basicSetting.scale, 1 * this.basicSetting.scale, 4 * this.basicSetting.scale);
484 | const jLable = jStack.addText('京享');
485 | jLable.font = Font.systemFont(8 * this.basicSetting.scale);
486 | jLable.textColor = new Color('FFFFFF') // “京享”二字字体颜色
487 | ;[name, value].map(t => t.textColor = this.widgetColor);
488 | }
489 |
490 | // #####################顶部内容###################
491 | async setHeaderShow(stack, image) {
492 | const topStack = stack.addStack();
493 | topStack.centerAlignContent();
494 | if (image) {
495 | const JDLogo = topStack.addImage(await this.getImageByUrl(this.logo, 'logoImage.png'));
496 | JDLogo.imageSize = new Size(this.basicSetting.logo * this.basicSetting.scale, this.basicSetting.logo * this.basicSetting.scale);
497 | topStack.addSpacer(10 * this.basicSetting.scale);
498 | const JD = topStack.addImage(await this.getImageByUrl(image, 'jingdongImage.png'));
499 | JD.imageSize = new Size(194 * 0.2 * this.basicSetting.scale, 78 * 0.2 * this.basicSetting.scale);
500 | } else {
501 | const imgStack = topStack.addStack();
502 | if (this.isPlus) {
503 | imgStack.size = new Size(30 * this.basicSetting.scale, 30 * this.basicSetting.scale * 1.039);
504 | imgStack.backgroundImage = await this.getImageByUrl(this.plusBG, 'plusBGImage.png');
505 | }
506 | const subStack = imgStack.addStack();
507 | subStack.url = 'openapp.jdmobile://';
508 | subStack.size = new Size(30 * this.basicSetting.scale, 30 * this.basicSetting.scale);
509 | subStack.cornerRadius = 30 / 2 * this.basicSetting.scale;
510 | subStack.backgroundImage = await this.getImageByUrl(this.basicSetting.customizeAvatar || this.userImage, `userImage_${this.userName}.png`);
511 | if (this.isPlus) {
512 | const userImg = subStack.addImage(await this.getImageByUrl(this.plusFG, 'plusFGImage.png'));
513 | }
514 | }
515 | topStack.addSpacer();
516 | const jdBean = topStack.addText(this.beanCount.toString());
517 | jdBean.font = Font.mediumSystemFont(20 * this.basicSetting.scale);
518 | jdBean.textColor = new Color('fa2d19'); // 右上角京豆数颜色
519 | jdBean.url = 'openapp.jdmobile://virtual?params=%7B%22category%22%3A%22jump%22%2C%22des%22%3A%22m%22%2C%22url%22%3A%22https%3A%2F%2Fbean.m.jd.com%2FbeanDetail%2Findex.action%3FresourceValue%3Dbean%22%7D';
520 | const desStack = topStack.addStack();
521 | desStack.layoutVertically();
522 | desStack.addSpacer(5.5 * this.basicSetting.scale);
523 | const desText = desStack.addText(' 京豆');
524 | desText.font = Font.mediumSystemFont(10 * this.basicSetting.scale);
525 | desText.textColor = new Color('fa2d19', 0.7);
526 | }
527 |
528 | // #####################京豆收支###################
529 | async setBeanShow(stack, textSize, imageSize) {
530 | const beanStack = stack.addStack();
531 | // 今日收支
532 | const yestodayStack = beanStack.addStack();
533 | yestodayStack.layoutVertically();
534 | try {
535 | this.bean.ydayIncome = this.rangeTimer[this.yestoday][0] - this.rangeTimer[this.yestoday][1];
536 | this.bean.ydayExpense = this.rangeTimer[this.yestoday][1];
537 | this.bean.todayIncome = this.rangeTimer[this.today][0] - this.rangeTimer[this.today][1];;
538 | this.bean.todayExpense = this.rangeTimer[this.today][1];
539 | } catch (e) {
540 | this.notify(this.name, '\u597d\u50cf\u4f60\u6628\u5929\u6ca1\u6709\u4f7f\u7528\u8be5\u5c0f\u7ec4\u4ef6\uff0c\u8bf7\u91cd\u7f6e\u4eac\u8c46\u6570\u636e');
541 | }
542 | this.rowBeanCell(
543 | yestodayStack,
544 | this.bean.ydayExpense.toString(),
545 | this.bean.ydayIncome.toString(),
546 | textSize,
547 | '昨日',
548 | );
549 | beanStack.addSpacer();
550 | // 京豆图片
551 | const ddStack = beanStack.addStack();
552 | ddStack.layoutVertically();
553 | const ddImg = ddStack.addImage(await this.getImageByUrl(this.beanImg, 'beanImage.png'));
554 | ddImg.imageSize = new Size(imageSize, imageSize);
555 | beanStack.addSpacer();
556 | // 昨日收支
557 | const todayStack = beanStack.addStack();
558 | todayStack.layoutVertically();
559 | this.rowBeanCell(
560 | todayStack,
561 | this.bean.todayExpense.toString(),
562 | this.bean.todayIncome.toString(),
563 | textSize,
564 | '今日',
565 | );
566 | }
567 |
568 | // #####################京豆图表###################
569 | async setChartShow(stack, type) {
570 | let labels = [], data = [];
571 | Object.keys(this.rangeTimer).forEach((day) => {
572 | const value = this.rangeTimer[day];
573 | const arrDay = day.split('-');
574 | labels.push(arrDay[2]);
575 | if (this.chartSetting.countBean === '收入-支出')
576 | data.push(value[0]);
577 | else data.push(value[0] - value[1]);
578 | });
579 | let cacheKey = `chart${type}Image${this.isSmall()}_${this.userName}.png`;
580 | let textSize = this.chartSetting.textSize;
581 | let linePadding = this.chartSetting.linePadding;
582 | let barPadding = this.chartSetting.barPadding;
583 | if (config.widgetFamily === 'small') {
584 | data.splice(0, 2);
585 | labels.splice(0, 2);
586 | textSize = this.chartSetting.textSize + 7;
587 | linePadding = this.chartSetting.linePadding + 10;
588 | barPadding = this.chartSetting.barPadding + 5;
589 | }
590 | let chartStr;
591 | switch (type) {
592 | case 2:
593 | chartStr = this.barChart(labels, data, textSize, barPadding, 'bar');
594 | break;
595 | case 3:
596 | chartStr = this.barChart(labels, data, textSize, barPadding, 'line');
597 | break;
598 | default:
599 | chartStr = this.lineChart(labels, data, textSize, linePadding);
600 | }
601 | const url = `https://quickchart.io/chart?w=${400}&h=${this.chartSetting.height}&f=png&c=${encodeURIComponent(chartStr)}`;
602 | const chart = await this.getImageByUrl(url, cacheKey, this.cacheChart);
603 |
604 | const chartStack = stack.addStack();
605 | const chartImage = chartStack.addImage(chart);
606 | const beanDateStack = stack.addStack();
607 | let showDays = data.length;
608 | for (let i = 0; i < showDays; i++) {
609 | beanDateStack.addSpacer();
610 | let subStack = beanDateStack.addStack();
611 | let beanDay = beanDateStack.addText(`${labels[i]}${this.chartSetting.dayText}`);
612 | beanDay.textColor = this.widgetColor;
613 | beanDay.font = new Font('ArialMT', this.chartSetting.daySize * this.basicSetting.scale);
614 | beanDay.textOpacity = 0.8;
615 | beanDateStack.addSpacer();
616 | }
617 | }
618 |
619 | // #####################物流信息###################
620 | setPackageShow(stack) {
621 | const packageStack = stack.addStack();
622 | const detailStack = packageStack.addStack();
623 | detailStack.layoutVertically();
624 | const titleStack = detailStack.addStack();
625 | titleStack.centerAlignContent();
626 | const title = titleStack.addText(this.package.title);
627 | title.lineLimit = 1;
628 | title.font = Font.mediumSystemFont(12 * this.basicSetting.scale);
629 | detailStack.addSpacer(2 * this.basicSetting.scale);
630 | const desc = detailStack.addText(this.package.desc);
631 | desc.lineLimit = 3;
632 | desc.font = Font.regularSystemFont(12 * this.basicSetting.scale);
633 | detailStack.addSpacer(2 * this.basicSetting.scale);
634 | const statusStack = detailStack.addStack();
635 | const time = statusStack.addText(this.package.time);
636 | statusStack.addSpacer();
637 | const status = statusStack.addText(this.package.status);
638 | ;[title, desc, time, status].map(t => t.textColor = this.widgetColor);
639 | ;[time, status].map(t => t.font = Font.regularSystemFont(9 * this.basicSetting.scale));
640 | ;[time, status].map(t => t.textOpacity = 0.7);
641 | }
642 |
643 | // #####################金贴&钢镚##################
644 | async setCoinShow(stack, vertical = false) {
645 | await this.getExtraData();
646 | const extraDataStack = stack.addStack();
647 | const jtImage = await this.getImageByUrl(this.jingtieImg, 'jtImage.png');
648 | const gbImage = await this.getImageByUrl(this.gangbengImg, 'gbImage.png');
649 | const dataStack = extraDataStack.addStack();
650 | if (vertical) dataStack.layoutVertically();
651 | this.rowCell(dataStack, jtImage, this.extra.jingtie.toString(), '金贴');
652 | if (vertical) extraDataStack.addSpacer(5 * this.basicSetting.scale);
653 | if (!vertical) dataStack.addSpacer(20 * this.basicSetting.scale);
654 | this.rowCell(dataStack, gbImage, this.extra.gangbeng.toString(), '钢镚');
655 | }
656 |
657 | // #####################京东红包##################
658 | async setRedPackageShow(stack, small = false) {
659 | await this.getRedPackageData();
660 | const walletImage = await this.getImageByUrl(this.walletImg, 'walletImage.png');
661 | small ? this.rowSmallWalletCell(stack, walletImage, this.redPackage) : this.rowWalletCell(stack, walletImage, this.redPackage);
662 | }
663 |
664 | // #####################京东白条##################
665 | async setBaitiaoShow(stack, small = false) {
666 | const baitiaoImage = await this.getImageByUrl(this.baitiaoImg, 'baitiaoImage.png');
667 | small ? this.rowSmallWalletCell(stack, baitiaoImage, this.baitiao) : this.rowWalletCell(stack, baitiaoImage, this.baitiao);
668 | }
669 |
670 | rowCell(stack, image, value, title) {
671 | const rowStack = stack.addStack();
672 | rowStack.centerAlignContent();
673 | const rowImage = rowStack.addImage(image);
674 | rowImage.imageSize = new Size(13 * this.basicSetting.scale, 13 * this.basicSetting.scale);
675 | rowStack.addSpacer();
676 | const rowValue = rowStack.addText(value);
677 | rowValue.font = Font.mediumSystemFont(15 * this.basicSetting.scale);
678 | rowStack.addSpacer();
679 | const rowTitle = rowStack.addText(title);
680 | rowTitle.font = Font.regularSystemFont(13 * this.basicSetting.scale);
681 | ;[rowValue, rowTitle].map(t => t.textColor = this.widgetColor);
682 | }
683 |
684 | rowBeanCell(stack, min, add, textSize, label) {
685 | const rowOne = stack.addStack();
686 | const labelText = rowOne.addText(label);
687 | labelText.font = Font.regularSystemFont(10 * this.basicSetting.scale);
688 | labelText.textOpacity = 0.7;
689 | const rowTwo = stack.addStack();
690 | const rowNumber = rowTwo.addText(add);
691 | rowNumber.font = Font.lightSystemFont(textSize);
692 | if (min < 0) {
693 | const rowThree = stack.addStack();
694 | const minText = rowThree.addText(min);
695 | minText.font = Font.mediumSystemFont(10 * this.basicSetting.scale);
696 | minText.textColor = new Color('fa2d19'); // 支出京豆颜色
697 | }
698 | ;[labelText, rowNumber].map(t => t.textColor = this.widgetColor);
699 | }
700 |
701 | rowWalletCell(stack, image, data) {
702 | const stackOne = stack.addStack();
703 | stackOne.centerAlignContent();
704 | const stackImage = stackOne.addImage(image);
705 | stackImage.imageSize = new Size(127 * 0.17 * this.basicSetting.scale, 75 * 0.17 * this.basicSetting.scale);
706 | stackOne.addSpacer(5 * this.basicSetting.scale);
707 | const title = stackOne.addText(data.title);
708 | title.font = Font.regularSystemFont(13 * this.basicSetting.scale);
709 | stackOne.addSpacer();
710 | const number = stackOne.addText(`${data.number}`);
711 | number.font = Font.mediumSystemFont(15 * this.basicSetting.scale);
712 | stackOne.addSpacer();
713 | const desc = stackOne.addText(data.desc);
714 | desc.font = Font.regularSystemFont(10 * this.basicSetting.scale);
715 | desc.textOpacity = 0.7;
716 | ;[title, number, desc].map(t => t.textColor = this.widgetColor);
717 | }
718 |
719 | rowSmallWalletCell(stack, image, data) {
720 | const stackOne = stack.addStack();
721 | stackOne.centerAlignContent();
722 | const stackImage = stackOne.addImage(image);
723 | stackImage.imageSize = new Size(127 * 0.17 * this.basicSetting.scale, 75 * 0.17 * this.basicSetting.scale);
724 | stackOne.addSpacer();
725 | const number = stackOne.addText(`${data.number}`);
726 | number.font = Font.mediumSystemFont(15 * this.basicSetting.scale);
727 | stack.addSpacer(5 * this.basicSetting.scale);
728 | const stackTwo = stack.addStack();
729 | stackTwo.centerAlignContent();
730 | const title = stackTwo.addText(data.title);
731 | title.font = Font.regularSystemFont(13 * this.basicSetting.scale);
732 | stackTwo.addSpacer();
733 | const desc = stackTwo.addText(data.desc);
734 | desc.font = Font.regularSystemFont(10 * this.basicSetting.scale);
735 | desc.textOpacity = 0.7;
736 | ;[number, title, desc].map(t => t.textColor = this.widgetColor);
737 | }
738 |
739 | init = async () => {
740 | try {
741 | let beanCacheKey = `beanData${this.isSmall()}_${this.userName}`;
742 | let beanCacheData = !this.loadStringCache(beanCacheKey) ? {} : JSON.parse(this.loadStringCache(beanCacheKey));
743 | let beanCache = beanCacheData.data ? beanCacheData.data.assetInfo.beanNum : 0;
744 | await this.TotalBean();
745 | await this.wxData();
746 | console.log(`京豆数据:${beanCache}`);
747 | console.log(`京豆数据:${this.beanCount}`);
748 |
749 | if (!this.cookie) return;
750 | if (Keychain.contains(this.CACHE_KEY)) {
751 | this.rangeTimer = JSON.parse(Keychain.get(this.CACHE_KEY));
752 | if (this.rangeTimer.hasOwnProperty(this.today) && beanCache !== 0 && beanCache == this.beanCount) {
753 | this.cacheChart = this.funcSetting.alwaysRefreshChart ==='打开' ? false : true;
754 | console.log('京豆数据:无变化,使用缓存数据');
755 | return;
756 | }
757 |
758 | this.rangeTimer[this.today] = [0, 0];
759 | const timerKeys = Object.keys(this.rangeTimer);
760 | if (timerKeys.length > this.maxDays) {
761 | for (let i = 0; i < timerKeys.length - this.maxDays; i++) {
762 | delete this.rangeTimer[timerKeys[i]];
763 | }
764 | Keychain.set(this.CACHE_KEY, JSON.stringify(this.rangeTimer));
765 | }
766 |
767 | this.timerKeys = [this.today];
768 | } else {
769 | this.rangeTimer = this.getDay(5);
770 | this.timerKeys = Object.keys(this.rangeTimer);
771 | }
772 | await this.getAmountData();
773 | } catch (e) {
774 | console.log(e);
775 | }
776 | };
777 |
778 | getAmountData = async () => {
779 | let i = 0,
780 | page = 1;
781 | do {
782 | const response = await this.getJingBeanBalanceDetail(page);
783 | const result = response.code === '0';
784 | console.log(`第${page}页:${result ? '请求成功' : '请求失败'}`);
785 | if (response.code === '3') {
786 | i = 1;
787 | // this.notify(this.name, response.message)
788 | console.log(response);
789 | }
790 | if (response && result) {
791 | page++;
792 | let detailList = response.jingDetailList;
793 | if (detailList && detailList.length > 0) {
794 | for (let item of detailList) {
795 | const dates = item.date.split(' ');
796 | if (this.timerKeys.indexOf(dates[0]) > -1) {
797 | const amount = Number(item.amount);
798 | this.rangeTimer[dates[0]][0] += amount;
799 | if (amount < 0)
800 | this.rangeTimer[dates[0]][1] += amount;
801 | } else {
802 | i = 1;
803 | Keychain.set(this.CACHE_KEY, JSON.stringify(this.rangeTimer));
804 | break;
805 | }
806 | }
807 | }
808 | }
809 | } while (i === 0);
810 | }
811 |
812 | getDay(dayNumber) {
813 | let data = {};
814 | let i = dayNumber;
815 | do {
816 | const today = new Date();
817 | const year = today.getFullYear();
818 | const targetday_milliseconds = today.getTime() - 1000 * 60 * 60 * 24 * i;
819 | today.setTime(targetday_milliseconds);
820 | let month = today.getMonth() + 1;
821 | month = month >= 10 ? month : `0${month}`;
822 | let day = today.getDate();
823 | day = day >= 10 ? day : `0${day}`;
824 | data[`${year}-${month}-${day}`] = [0, 0];
825 | i--;
826 | } while (i >= 0);
827 | return data;
828 | }
829 |
830 | TotalBean = async () => {
831 | const dataName = '京豆数据';
832 | let userCache = `beanData${this.isSmall()}`;
833 | const url = 'https://me-api.jd.com/user_new/info/GetJDUserInfoUnion?isLogin=1';
834 | const options = {
835 | headers: {
836 | cookie: this.cookie,
837 | },
838 | };
839 | const response = await this.httpRequest(dataName, url, true, options, userCache);
840 | try {
841 | if (response.retcode === '0' && response['data']) {
842 | this.beanCount = response.data.assetInfo.beanNum;
843 | this.userImage = response.data.userInfo.baseInfo.headImageUrl.replace(/big/, 'mid') || 'https://img11.360buyimg.com/jdphoto/s120x120_jfs/t21160/90/706848746/2813/d1060df5/5b163ef9N4a3d7aa6.png';
844 | this.nickName = response.data.userInfo.baseInfo.nickname;
845 | this.isPlus = response.data.userInfo.isPlusVip === '1' ? true : false;
846 | } else {
847 | this.notify(this.name, response.msg);
848 | console.log('京豆数据:获取失败,' + response.msg)
849 | }
850 | } catch (e) {
851 | console.log(e);
852 | console.log('京豆数据:获取失败,')
853 | }
854 | }
855 |
856 | wxData = async () => {
857 | const dataName = '微信数据';
858 | let userCache = `wxData${this.isSmall()}`;
859 | const url = 'https://wxapp.m.jd.com/kwxhome/myJd/home.json?&useGuideModule=0&bizId=&brandId=&fromType=wxapp&isLogin=1';
860 | const options = {
861 | headers: {
862 | cookie: this.cookie,
863 | },
864 | };
865 | const response = await this.httpRequest(dataName, url, true, options, userCache);
866 | try {
867 | if (response['user']) {
868 | this.jValue = response.user.uclass.replace(/[^0-9]/ig, '');
869 | } else {
870 | // this.notify(this.name, response.msg);
871 | console.log('微信数据:获取失败,' + response.msg)
872 | }
873 | } catch (e) {
874 | console.log(e);
875 | }
876 | }
877 |
878 | getJingBeanBalanceDetail = async (page) => {
879 | try {
880 | const options = {
881 | url: `https://bean.m.jd.com/beanDetail/detail.json`,
882 | body: `page=${page}`,
883 | headers: {
884 | 'X-Requested-With': `XMLHttpRequest`,
885 | Connection: `keep-alive`,
886 | 'Accept-Encoding': `gzip, deflate, br`,
887 | 'Content-Type': `application/x-www-form-urlencoded; charset=UTF-8`,
888 | Origin: `https://bean.m.jd.com`,
889 | 'User-Agent': `Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.1 Safari/605.1.15`,
890 | Cookie: this.cookie,
891 | Host: `bean.m.jd.com`,
892 | Referer: `https://bean.m.jd.com/beanDetail/index.action?resourceValue=bean`,
893 | 'Accept-Language': `zh-cn`,
894 | Accept: `application/json, text/javascript, */*; q=0.01`,
895 | },
896 | };
897 | let params = {...options, method: 'POST'};
898 | let request = new Request(params.url);
899 | Object.keys(params).forEach((key) => {
900 | request[key] = params[key];
901 | });
902 | return await request.loadJSON();
903 | } catch (e) {
904 | console.log(e);
905 | }
906 | }
907 |
908 | getExtraData = async () => {
909 | const JTDataName = '金贴数据';
910 | const JTUrl = 'https://ms.jr.jd.com/gw/generic/uc/h5/m/mySubsidyBalance';
911 | const GBDataName = '钢镚数据';
912 | const GBUrl = 'https://coin.jd.com/m/gb/getBaseInfo.html';
913 | const options = {
914 | headers: {
915 | cookie: this.cookie,
916 | Referer: 'https://home.m.jd.com/myJd/newhome.action?sceneval=2&ufc=&',
917 | },
918 | };
919 | try {
920 | const JTData = await this.httpRequest(JTDataName, JTUrl, true, options, 'jintieData');
921 | const GBData = await this.httpRequest(GBDataName, GBUrl, true, options, 'gangbengData');
922 | if (JTData.resultCode === 0) {
923 | this.extra.jingtie = JTData.resultData.data['balance'];
924 | } else {
925 | // this.notify(this.name, JTdata.resultMsg);
926 | console.log('金贴数据:获取失败,' + JTdata.resultMsg);
927 | };
928 | if (GBData.gbBalance) this.extra.gangbeng = GBData.gbBalance;
929 | } catch(e) {
930 | console.log(e);
931 | }
932 | }
933 |
934 | getPackageData = async () => {
935 | const dataName = '包裹数据';
936 | const url ='https://wq.jd.com/bases/wuliudetail/notify?sceneval=2&sceneval=2&g_login_type=1&callback';
937 | const options = {
938 | headers: {
939 | cookie: this.cookie,
940 | Referer: 'https://home.m.jd.com/myJd/newhome.action?sceneval=2&ufc=&',
941 | },
942 | };
943 | try {
944 | const data = await this.httpRequest(dataName, url, true, options, 'packageData');
945 | if (data.errCode == 0 && data['dealLogList']) {
946 | console.log('包裹数据:获取成功');
947 | console.log(`包裹数据:您有${data['dealLogList'].length}个包裹`);
948 | if (data['dealLogList'].length > 0) {
949 | let item = data.dealLogList[Math.floor(Math.random() * data['dealLogList'].length)]
950 | this.package.number = data.dealLogList.length;
951 | this.package.title = item['name'];
952 | this.package.desc = item['wlStateDesc'];
953 | this.package.time = item['createTime'];
954 | this.package.status = item['stateName'];
955 | }
956 | } else {
957 | console.log('包裹数据:获取失败');
958 | }
959 | } catch (e) {
960 | console.log(e);
961 | }
962 | }
963 |
964 | getRedPackageData = async () => {
965 | const dataName = '红包数据';
966 | const url =
967 | 'https://wq.jd.com/user/info/QueryUserRedEnvelopesV2?type=1&orgFlag=JD_PinGou_New&page=1&cashRedType=1&redBalanceFlag=1&channel=3&sceneval=2&g_login_type=1';
968 | const options = {
969 | headers: {
970 | cookie: this.cookie,
971 | Referer: 'https://home.m.jd.com/myJd/newhome.action?sceneval=2&ufc=&',
972 | },
973 | };
974 | try {
975 | const data = await this.httpRequest(dataName, url, true, options, 'redPackageData');
976 | if (data.errcode === 0) {
977 | this.redPackage.number = data.data.balance ? data.data.balance : 0;
978 | if (data.data.expiredBalance && data.data.expiredBalance !== '') this.redPackage.desc = `即将过期${data.data.expiredBalance}`;
979 | } else {
980 | // this.notify(this.name, data.msg);
981 | console.log('红包数据:获取失败,' + data.msg);
982 | }
983 | } catch (e) {
984 | console.log(e);
985 | }
986 | }
987 |
988 | getJValue = async () => {
989 | const dataName = '京享数据';
990 | const url = 'https://vip.m.jd.com/scoreDetail/current';
991 | const options = {
992 | headers: {
993 | cookie: this.cookie,
994 | },
995 | };
996 | try {
997 | const data = await this.httpRequest(dataName, url, true, options, 'JValue');
998 | if (data.code === 0) {
999 | this.jValue = data.model.scoreDescription.userScore.score;
1000 | } else {
1001 | console.log('京享数据:获取失败');
1002 | };
1003 | } catch (e) {
1004 | console.log(e);
1005 | }
1006 | }
1007 |
1008 | getBaitiaoData = async () => {
1009 | const dataName = '白条数据';
1010 | const url = 'https://ms.jr.jd.com/gw/generic/bt/h5/m/firstScreenNew';
1011 | const options = {
1012 | body: 'reqData={"clientType":"ios","clientVersion":"13.2.3","deviceId":"","environment":"3"}',
1013 | headers: {
1014 | cookie: this.cookie,
1015 | },
1016 | };
1017 | try {
1018 | const data = await this.httpRequest(dataName, url, true, options, 'baitiaoData', 'POST', false);
1019 | if (data.resultCode !== 0) {
1020 | // this.notify(this.name, data['resultMsg']);
1021 | return
1022 | }
1023 | this.baitiao.title = data['resultData']['data']['bill']['title'];
1024 | this.baitiao.number = data['resultData']['data']['bill']['amount'].replace(/,/g, '');
1025 | this.baitiao.desc = data['resultData']['data']['bill']['buttonName'].replace(/最近还款日/, '');
1026 | } catch (e) {
1027 | console.log(e);
1028 | }
1029 | }
1030 |
1031 | getFruitData = async () => {
1032 | const dataName = '东东农场';
1033 | const url = 'https://api.m.jd.com/client.action?functionId=initForFarm';
1034 | const options = {
1035 | body: 'body=version:4&appid=wh5&clientVersion=9.1.0',
1036 | headers: {
1037 | 'User-Agent': 'jdapp;iPhone;9.2.2;14.2;%E4%BA%AC%E4%B8%9C/9.2.2 CFNetwork/1206 Darwin/20.1.0',
1038 | 'Content-Type': 'application/x-www-form-urlencoded',
1039 | 'cookie': this.cookie,
1040 | },
1041 | };
1042 | try {
1043 | const data = await this.httpRequest(dataName, url, true, options, 'FruitData', 'POST', false);
1044 | if (data.msg && data.msg == 'not login') {
1045 | this.fruitState = "X";
1046 | }
1047 | else if (data.farmUserPro.treeState == 2 || data.farmUserPro.treeState == 3) {
1048 | this.fruitState = "100";
1049 | }
1050 | else if (data.farmUserPro.treeState == 0) {
1051 | this.fruitState = "X";
1052 | }
1053 | else {
1054 | this.fruitState = Math.floor((data.farmUserPro.treeEnergy / data.farmUserPro.treeTotalEnergy) * 100).toString();
1055 | }
1056 | } catch (e) {
1057 | console.log(e);
1058 | }
1059 | }
1060 |
1061 | getImageByUrl = async(url, cacheKey, useCache = true, logable = true) => {
1062 | if (this.CACHES.indexOf(cacheKey) < 0) {
1063 | this.CACHES.push(cacheKey);
1064 | this.settings.CACHES = this.CACHES;
1065 | this.saveSettings(false);
1066 | }
1067 | if (useCache) {
1068 | const cacheImg = this.loadImgCache(cacheKey);
1069 | if (cacheImg != undefined && cacheImg != null) {
1070 | if (logable) console.log(`使用缓存:${cacheKey}`);
1071 | return this.loadImgCache(cacheKey);
1072 | }
1073 | }
1074 |
1075 | try {
1076 | if (logable) console.log(`在线请求:${cacheKey}`);
1077 | const req = new Request(url);
1078 | const imgData = await req.load();
1079 | const img = Image.fromData(imgData);
1080 | this.saveImgCache(cacheKey, img);
1081 | return img;
1082 | } catch (e) {
1083 | console.error(`图片加载失败:${e}`);
1084 | let cacheImg = this.loadImgCache(cacheKey);
1085 | if (cacheImg != undefined) {
1086 | console.log(`使用缓存图片:${cacheKey}`);
1087 | return cacheImg;
1088 | }
1089 | console.log(`使用预设图片`);
1090 | let ctx = new DrawContext();
1091 | ctx.size = new Size(80, 80);
1092 | ctx.setFillColor(Color.darkGray());
1093 | ctx.fillRect(new Rect(0, 0, 80, 80));
1094 | return await ctx.getImage();
1095 | }
1096 | }
1097 |
1098 | saveImgCache(cacheKey, img) {
1099 | if (!this.fm.fileExists(this.cachePath)) {
1100 | this.fm.createDirectory(this.cachePath, true);
1101 | };
1102 | const cacheFile = this.fm.joinPath(this.cachePath, cacheKey);
1103 | this.fm.writeImage(cacheFile, img);
1104 | }
1105 |
1106 | loadImgCache(cacheKey) {
1107 | const cacheFile = this.fm.joinPath(this.cachePath, cacheKey);
1108 | const fileExists = this.fm.fileExists(cacheFile);
1109 | let img = undefined;
1110 | if (fileExists) {
1111 | img = Image.fromFile(cacheFile);
1112 | }
1113 | return img;
1114 | }
1115 |
1116 | httpRequest = async(dataName, url, json = true, options, key, method = 'GET', logable = this.funcSetting.logable === '打开') => {
1117 | let cacheKey = `${key}_${this.userName}`;
1118 | if (this.CACHES.indexOf(cacheKey) < 0) {
1119 | this.CACHES.push(cacheKey);
1120 | this.settings.CACHES = this.CACHES;
1121 | this.saveSettings(false);
1122 | }
1123 | let localCache = this.loadStringCache(cacheKey);
1124 | const lastCacheTime = this.getCacheModificationDate(cacheKey);
1125 | const timeInterval = Math.floor((this.getCurrentTimeStamp() - lastCacheTime) / 60);
1126 |
1127 | console.log(`${dataName}:缓存${timeInterval}分钟前,有效期${this.basicSetting.interval}分钟,${localCache.length}`);
1128 |
1129 | if (timeInterval < this.basicSetting.interval && localCache != null && localCache.length > 0) {
1130 | console.log(`${dataName}:读取缓存`);
1131 | return json ? JSON.parse(localCache) : localCache;
1132 | }
1133 |
1134 | let data = null;
1135 | try {
1136 | console.log(`${dataName}:在线请求`);
1137 | let req = new Request(url);
1138 | req.method = method;
1139 | Object.keys(options).forEach((key) => {
1140 | req[key] = options[key];
1141 | });
1142 | data = await (json ? req.loadJSON() : req.loadString());
1143 | if (
1144 | data.errCode === '0' ||
1145 | data.msg === 'success' ||
1146 | data.resultCode === 0
1147 | ) {
1148 | this.saveStringCache(cacheKey, json ? JSON.stringify(data) : data)
1149 | }
1150 | } catch (e) {
1151 | console.error(`${dataName}:请求失败:${e}`);
1152 | }
1153 |
1154 | localCache = this.loadStringCache(cacheKey);
1155 |
1156 | if (!data && localCache != null && localCache.length > 0) {
1157 | console.log(`${dataName}:获取失败,读取缓存`);
1158 | return json ? JSON.parse(localCache) : localCache;
1159 | }
1160 |
1161 | if (logable) {
1162 | console.log(`${dataName}:在线请求响应数据:${JSON.stringify(data)}`);
1163 | }
1164 | return data;
1165 | }
1166 |
1167 | loadStringCache(cacheKey) {
1168 | const cacheFile = this.fm.joinPath(this.cachePath, cacheKey);
1169 | const fileExists = this.fm.fileExists(cacheFile);
1170 | let cacheString = '';
1171 | if (fileExists) {
1172 | cacheString = this.fm.readString(cacheFile);
1173 | }
1174 | return cacheString;
1175 | }
1176 |
1177 | saveStringCache(cacheKey, content) {
1178 | if (!this.fm.fileExists(this.cachePath)) {
1179 | this.fm.createDirectory(this.cachePath, true);
1180 | };
1181 | const cacheFile = this.fm.joinPath(this.cachePath, cacheKey);
1182 | this.fm.writeString(cacheFile, content);
1183 | }
1184 |
1185 | getCacheModificationDate(cacheKey) {
1186 | const cacheFile = this.fm.joinPath(this.cachePath, cacheKey);
1187 | const fileExists = this.fm.fileExists(cacheFile);
1188 | if (fileExists) {
1189 | return this.fm.modificationDate(cacheFile).getTime() / 1000;
1190 | } else {
1191 | return 0;
1192 | }
1193 | }
1194 |
1195 | getCurrentTimeStamp() {
1196 | return new Date().getTime() / 1000;
1197 | }
1198 |
1199 | timeFormat(time) {
1200 | let date;
1201 | if (time) {
1202 | date = new Date(time);
1203 | } else {
1204 | date = new Date();
1205 | }
1206 | return ((date.getMonth() + 1) >= 10 ? (date.getMonth() + 1) : '0' + (date.getMonth() + 1)) + '月' + (date.getDate() >= 10 ? date.getDate() : '0' + date.getDate()) + '日';
1207 | }
1208 |
1209 | async updateCheck(version){
1210 | let data;
1211 | try {
1212 | let updateCheck = new Request('https://raw.githubusercontent.com/anker1209/Scriptable/main/upcoming.json');
1213 | data = await updateCheck.loadJSON();
1214 | if (data.version != version) {
1215 | let updata = new Alert();
1216 | updata.title = `有新版 ${data.version} 可用`;
1217 | updata.addAction('去Github更新');
1218 | updata.addAction('网页版商店更新');
1219 | updata.addCancelAction('稍后');
1220 | updata.message = '\n更新说明:\n' + data.notes + '\n\n点击相应按钮更新脚本';
1221 | let id = await updata.present();
1222 | if (id == 0) {
1223 | Safari.openInApp('https://raw.githubusercontent.com/anker1209/Scriptable/main/scripts/JD-in-one-v2.js');
1224 | } else if (id == 1) {
1225 | Safari.openInApp('http://scriptablejs.gitee.io/store/#/menu/myInfo');
1226 | } else {
1227 | return;
1228 | }
1229 | } else {
1230 | let updata = new Alert();
1231 | updata.title = '暂无更新';
1232 | updata.addCancelAction('好的');
1233 | updata.message = `\n当前版本 ${version} 为最新版本`;
1234 | await updata.present();
1235 | }
1236 | } catch(e) {
1237 | console.log(e);
1238 | }
1239 | }
1240 |
1241 | async faqTable() {
1242 | const table = new UITable();
1243 | table.showSeparators = false;
1244 | let data;
1245 | try {
1246 | let faq = new Request('https://raw.githubusercontent.com/anker1209/Scriptable/main/faq.json');
1247 | data = await faq.loadJSON();
1248 | let info = new UITableRow();
1249 | info.height = parseFloat(data.height);
1250 | let desc = info.addText(data.update, data.desc);
1251 | desc.subtitleColor = Color.blue();
1252 | desc.titleFont = Font.mediumSystemFont(14);
1253 | desc.subtitleFont = Font.systemFont(14);
1254 | table.addRow(info);
1255 | for (let i = 0; i < data.data.length; i++) {
1256 | let header = new UITableRow();
1257 | header.backgroundColor = Color.dynamic(new Color('F5F5F5'), new Color('000000'));;
1258 | let heading = header.addText(data.data[i].name)
1259 | heading.titleFont = Font.mediumSystemFont(17);
1260 | heading.centerAligned();
1261 | table.addRow(header);
1262 | data.data[i].item.forEach((faq) => {
1263 | let row = new UITableRow();
1264 | row.height = parseFloat(faq['height']);
1265 | let rowtext = row.addText(faq['question'], faq['answer']);
1266 | rowtext.titleFont = Font.mediumSystemFont(16);
1267 | rowtext.titleColor = Color.blue();
1268 | rowtext.subtitleFont = Font.systemFont(14);
1269 | rowtext.subtitleColor = Color.dynamic(new Color('000000', 0.7), new Color('ffffff', 0.7));
1270 | table.addRow(row);
1271 | });
1272 | }
1273 | } catch (e) {
1274 | console.log(e);
1275 | }
1276 | await table.present();
1277 | }
1278 |
1279 | async settingCategory(table, item, outfit, category) {
1280 | let header = new UITableRow();
1281 | let heading = header.addText(outfit)
1282 | heading.titleFont = Font.mediumSystemFont(17);
1283 | heading.centerAligned();
1284 | table.addRow(header);
1285 | item.forEach((data) => {
1286 | Object.keys(data.option).forEach((key) => {
1287 | let row = new UITableRow();
1288 | let rowIcon = row.addImageAtURL(data['icon']);
1289 | rowIcon.widthWeight = 100;
1290 | let rowtext = row.addText(data['title']);
1291 | rowtext.widthWeight = 400;
1292 | let rowNumber = row.addText(`${this.settings[category][key]} >`);
1293 | rowNumber.widthWeight = 500;
1294 | rowNumber.rightAligned();
1295 | rowNumber.titleColor = Color.gray();
1296 | rowNumber.titleFont = Font.systemFont(16);
1297 | rowtext.titleFont = Font.systemFont(16);
1298 | row.dismissOnSelect = false;
1299 | row.onSelect = async () => {
1300 | if (data.type == 'text') {
1301 | await this.alertInput(data['title'], data['desc'], category, data['option']);
1302 | } else if (data.type == 'menu') {
1303 | await this.showAlert(data['title'], data['desc'], data['menu'], category, key,);
1304 | }
1305 | await this.tableContent(table);
1306 | }
1307 | table.addRow(row);
1308 | });
1309 | });
1310 | table.reload();
1311 | }
1312 |
1313 | async tableContent(table) {
1314 | const basic = [
1315 | {type: 'text', title: '全局缩放比例', desc: '排版溢出、显示不全的请优先调低此数,建议递减0.05调整,如0.95、0.90……\n\n缺省值:1.00', option: {scale: ''}, icon: 'https://gitee.com/anker1209/image/raw/master/jd/scale.png'},
1316 | {type: 'text', title: '京东标志大小', desc: '京东logo(形象狗)大小\n\n缺省值:30', option: {logo: ''}, icon: 'https://gitee.com/anker1209/image/raw/master/jd/logo.png'},
1317 | {type: 'text', title: '用户头像大小', desc: '⚠️注意:若要修改头像,请在京东app上传后将缓存清除再运行脚本。\n\n缺省值:69', option: {userImage: ''}, icon: 'https://gitee.com/anker1209/image/raw/master/jd/userImage.png'},
1318 | {type: 'text', title: '左侧栏宽度', desc: '左侧用户信息栏整体宽度\n\n缺省值:103', option: {userStack: ''}, icon: 'https://gitee.com/anker1209/image/raw/master/jd/userStack.png'},
1319 | {type: 'text', title: '左右栏间距', desc: '左侧用户信息栏与右侧京豆数据间距\n\n缺省值:25', option: {division: ''}, icon: 'https://gitee.com/anker1209/image/raw/master/jd/division.png'},
1320 | {type: 'text', title: '缓存时间', desc: '数据请求间隔时间\n请设置合适时间,避免频繁访问接口数据以及加载缓慢。单位:分钟\n\n缺省值:10', option: {interval: ''}, icon: 'https://gitee.com/anker1209/image/raw/master/jd/interval.png'},
1321 | {type: 'menu', title: '缓存位置', desc: '将缓存保存在Local或者iCloud。\n\n缺省值:Local', option: {directory: ''}, menu: ['Local', 'iCloud'], icon: 'https://gitee.com/anker1209/image/raw/master/jd/directory.png'},
1322 | {type: 'text', title: '自定义昵称', desc: '自定义用户信息栏的昵称名称,\n留空将显示京东账号昵称。\n\n注意:单脚本多账户若使用自定义昵称,所有账户将同时显示此昵称,如需单独自定义昵称,请复制脚本单独设置。', option: {customizeName: ''}, icon: 'https://gitee.com/anker1209/image/raw/master/jd/customizeName.png'},
1323 | {type: 'text', title: '自定义头像', desc: '自定义用户信息栏的头像,\n留空将显示京东APP头像。\n\n注意:单脚本多账户若使用自定义头像,所有账户将同时显示此头像,如需单独自定义头像,请复制脚本单独设置。', option: {customizeAvatar: ''}, icon: 'https://gitee.com/anker1209/image/raw/master/jd/customizeAvatar.png'},
1324 | {type: 'menu', title: '小组件显示内容', desc: '\n缺省值:京豆、钱包数据', option: {smallShowType: ''}, menu: ['京豆、钱包数据', '个人信息'], icon: 'https://gitee.com/anker1209/image/raw/master/jd/smallShowType.png'},
1325 | {type: 'menu', title: '钱包显示类型', desc: '若要显示钱包内容,白条需关闭或者白条打开的情况下无待还白条。\n\n缺省值:红包', option: {walletShowType: ''}, menu: ['红包', '钢镚和金贴'], icon: 'https://gitee.com/anker1209/image/raw/master/jd/walletShowType.png'},
1326 | ];
1327 | const chart = [
1328 | {type: 'text', title: '图表高度', desc: '京豆数据未与日期对齐的,\n请调低此数值\n\n⚠️如需即时查看调整效果,\n[功能设置]-->刷新图表 需打开。\n\n缺省值:130', option: {height: ''}, icon: 'https://gitee.com/anker1209/image/raw/master/jd/height.png'},
1329 | {type: 'text', title: '日期文字大小', desc: '京豆图表底部日期文字大小\n\n缺省值:9', option: {daySize: ''}, icon: 'https://gitee.com/anker1209/image/raw/master/jd/daySize.png'},
1330 | {type: 'text', title: '日期文字后缀', desc: '京豆图表底部日期文字后缀', option: {dayText: ''}, icon: 'https://gitee.com/anker1209/image/raw/master/jd/dayText.png'},
1331 | {type: 'text', title: '京豆数文字大小', desc: '京豆图表数据文字大小\n\n⚠️如需即时查看调整效果,\n[功能设置]-->刷新图表 需打开。\n\n缺省值:18', option: {textSize: ''}, icon: 'https://gitee.com/anker1209/image/raw/master/jd/textSize.png'},
1332 | {type: 'text', title: '京豆数白天颜色', desc: '⚠️如需即时查看调整效果,\n[功能设置]-->刷新图表 需打开。\n\n缺省值:999999', option: {textDayColor: ''}, icon: 'https://gitee.com/anker1209/image/raw/master/jd/textDayColor.png'},
1333 | {type: 'text', title: '京豆数晚上颜色', desc: '⚠️如需即时查看调整效果,\n[功能设置]-->刷新图表 需打开。\n\n缺省值:999999', option: {textNightColor: ''}, icon: 'https://gitee.com/anker1209/image/raw/master/jd/textNightColor.png'},
1334 | {type: 'text', title: '折线图线条颜色', desc: '支持渐变色,每个颜色之间以英文逗号分隔,颜色值必须带“#”。\n\n缺省值:#FA6859', option: {lineColor: ''}, icon: 'https://gitee.com/anker1209/image/raw/master/jd/lineColor.png'},
1335 | {type: 'text', title: '折线图表顶边距', desc: '京豆折线图顶边距\n京豆数据在顶部被剪切显示不全的,\n请调高此数值。\n\n⚠️如需即时查看调整效果,\n[功能设置]-->刷新图表 需打开。\n\n缺省值:15', option: {linePadding: ''}, icon: 'https://gitee.com/anker1209/image/raw/master/jd/linePadding.png'},
1336 | {type: 'text', title: '柱状图表顶边距', desc: '京豆柱状图和曲线面积图顶边距\n京豆数据在顶部被剪切显示不全的,\n请调高此数值。\n\n⚠️如需即时查看调整效果,\n[功能设置]-->刷新图表 需打开。\n\n缺省值:5', option: {barPadding: ''}, icon: 'https://gitee.com/anker1209/image/raw/master/jd/barPadding.png'},
1337 | {type: 'menu', title: '小组件图表类型', desc: '\n缺省值:双日视图', option: {smallShowType: ''}, menu: ['双日视图', '折线图表', '柱状图表', '曲线面积图'], icon: 'https://gitee.com/anker1209/image/raw/master/jd/smallShowType2.png'},
1338 | {type: 'menu', title: '中组件图表类型', desc: '\n缺省值:双日视图', option: {showType: ''}, menu: ['双日视图', '折线图表', '柱状图表', '曲线面积图'], icon: 'https://gitee.com/anker1209/image/raw/master/jd/showType.png'},
1339 | {type: 'menu', title: '每日京豆数计算', desc: '\n缺省值:收入-支出', option: {countBean: ''}, menu: ['收入-支出', '收入'], icon: 'https://gitee.com/anker1209/image/raw/master/jd/countBean.png'},
1340 | {type: 'menu', title: '多彩柱状图', desc: '设置为打开时仅对柱状图表生效\n\n缺省值:关闭', option: {colorful: ''}, menu: ['打开', '关闭'], icon: 'https://gitee.com/anker1209/image/raw/master/jd/colorful.png'},
1341 | ];
1342 | const func = [
1343 | {type: 'menu', title: '白条信息', desc: '关闭或者打开后无待还白条的情况下,\n会显示基础设置里选择的钱包内容。\n\n缺省值:打开', option: {showBaitiao: ''}, menu: ['打开', '关闭'], icon: 'https://gitee.com/anker1209/image/raw/master/jd/showBaitiao.png'},
1344 | {type: 'menu', title: '包裹信息', desc: '只有中组件显示一条物流信息,\n若无物流信息会显示图表设置里选择的图表类型。\n\n缺省值:关闭', option: {showPackage: ''}, menu: ['打开', '关闭'], icon: 'https://gitee.com/anker1209/image/raw/master/jd/showPackage.png'},
1345 | {type: 'menu', title: '农场进度', desc: '显示东东农场种植进度。\n\n缺省值:打开', option: {showFruit: ''}, menu: ['打开', '关闭'], icon: 'https://gitee.com/anker1209/image/raw/master/jd/showFruit.png'},
1346 | {type: 'menu', title: '运行日志', desc: '出现数据异常请将此值设为true,\n查看运行日志。\n\n⚠️注意:\n查看运行日志需将缓存时间更改为0。\n\n缺省值:关闭', option: {logable: ''}, menu: ['打开', '关闭'], icon: 'https://gitee.com/anker1209/image/raw/master/jd/logable.png'},
1347 | {type: 'menu', title: '刷新图表', desc: '打开,每次刷新组件会随机刷新图表颜色(仅柱状图表和曲线面积图);关闭,则只有在京豆数据有变化的情况下刷新图表颜色及数据。建议在排版调整没有问题后,设置为关闭。设置为打开会加长数据载入时间。\n\n⚠️注意:图表设置选项里修改图表高度、颜色、文字大小、顶边距需打开此选项以查看即时反馈。\n\n缺省值:打开', option: {alwaysRefreshChart: ''}, menu: ['打开', '关闭'], icon: 'https://gitee.com/anker1209/image/raw/master/jd/alwaysRefreshChart.png'},
1348 | ];
1349 | table.removeAllRows();
1350 | let topRow = new UITableRow();
1351 | let leftText = topRow.addButton('教程');
1352 | leftText.widthWeight = 0.25;
1353 | leftText.onTap = async () => {
1354 | await Safari.open('https://github.com/anker1209/Scriptable#jd_in_one');
1355 | }
1356 | let faqText = topRow.addButton('常见问题');
1357 | faqText.widthWeight = 0.25;
1358 | faqText.leftAligned();
1359 | faqText.onTap = async () => {
1360 | await this.faqTable();
1361 | }
1362 | let versionText = topRow.addButton('版本检测');
1363 | versionText.widthWeight = 0.25;
1364 | versionText.rightAligned();
1365 | versionText.onTap = async () => {
1366 | await this.updateCheck(this.version);
1367 | }
1368 | let rightText = topRow.addButton('电报群');
1369 | rightText.widthWeight = 0.25;
1370 | rightText.rightAligned();
1371 | rightText.onTap = async () => {
1372 | await Safari.open('https://t.me/Scriptable_JS');
1373 | }
1374 | table.addRow(topRow);
1375 |
1376 | let header = new UITableRow();
1377 | let heading = header.addText('重置设置')
1378 | heading.titleFont = Font.mediumSystemFont(17);
1379 | heading.centerAligned();
1380 | table.addRow(header);
1381 | let row1 = new UITableRow();
1382 | let rowtext1 = row1.addText('重置缓存','若需要修改头像或数据显示错误,尝试此操作');
1383 | rowtext1.titleFont = Font.systemFont(16);
1384 | rowtext1.subtitleFont = Font.systemFont(12);
1385 | rowtext1.subtitleColor = new Color('999999');
1386 | row1.dismissOnSelect = false;
1387 | row1.onSelect = async () => {
1388 | const options = ['取消', '重置'];
1389 | const message = '所有在线请求的数据缓存将会被清空';
1390 | const index = await this.generateAlert(message, options);
1391 | if (index === 0) return;
1392 | this.fm.remove(this.cachePath);
1393 | delete this.settings['CACHES'];
1394 | this.saveSettings();
1395 | }
1396 | table.addRow(row1);
1397 | let row2 = new UITableRow();
1398 | let rowtext2 = row2.addText('重置京豆数据','若京豆数据缺失或显示有误,尝试此操作');
1399 | rowtext2.titleFont = Font.systemFont(16);
1400 | rowtext2.subtitleFont = Font.systemFont(12);
1401 | rowtext2.subtitleColor = new Color('999999');
1402 | row2.dismissOnSelect = false;
1403 | row2.onSelect = async () => {
1404 | const options = ['取消', '重置'];
1405 | const message = '若缺少京豆数据或显示为0(双日视图或图表的京豆数)采用此操作。京豆数据重置后,将会重新抓取近6天的京豆明细。请勿频繁使用,会产生大量数据';
1406 | const index = await this.generateAlert(message, options);
1407 | if (index === 0) return;
1408 | Keychain.remove(this.settings.CACHE_KEY);
1409 | delete this.settings.CACHE_KEY;
1410 | this.saveSettings();
1411 | }
1412 | table.addRow(row2);
1413 | let row3 = new UITableRow();
1414 | let rowtext3 = row3.addText('重置设置参数','设置参数绑定脚本文件名,请勿随意更改脚本文件名');
1415 | rowtext3.titleFont = Font.systemFont(16);
1416 | rowtext3.subtitleFont = Font.systemFont(12);
1417 | rowtext3.subtitleColor = new Color('999999');
1418 | row3.dismissOnSelect = false;
1419 | row3.onSelect = async () => {
1420 | const options = ['取消', '重置'];
1421 | const message = '本菜单里的所有设置参数将会重置为默认值,重置后请重新打开设置菜单';
1422 | const index = await this.generateAlert(message, options);
1423 | if (index === 0) return;
1424 | delete this.settings['basicSetting'];
1425 | delete this.settings['chartSetting'];
1426 | delete this.settings['funcSetting'];
1427 | this.saveSettings();
1428 | }
1429 | table.addRow(row3);
1430 | await this.settingCategory(table, basic, '基础设置', 'basicSetting');
1431 | await this.settingCategory(table, chart, '图表设置', 'chartSetting');
1432 | await this.settingCategory(table, func, '功能设置', 'funcSetting');
1433 | }
1434 |
1435 | async editSettings() {
1436 | const table = new UITable();
1437 | table.showSeparators = true;
1438 | await this.tableContent(table);
1439 | await table.present(true);
1440 | }
1441 |
1442 | alertInput = async (title, desc, category, opt = {}) => {
1443 | const a = new Alert();
1444 | a.title = title;
1445 | a.message = !desc ? '' : desc;
1446 | let key = Object.keys(opt)[0];
1447 | a.addTextField(key, `${this.settings[category][key]}`);
1448 | a.addAction('确定');
1449 | a.addCancelAction('取消');
1450 | const id = await a.presentAlert();
1451 | if (id === -1) return;
1452 | this.settings[category][key] = a.textFieldValue(0);
1453 | this.saveSettings();
1454 | };
1455 |
1456 | async showAlert(title, message, options, category, key) {
1457 | let alert = new Alert();
1458 | alert.title = title;
1459 | alert.message = message;
1460 | alert.addCancelAction('取消')
1461 | for (const option of options) {
1462 | alert.addAction(option);
1463 | };
1464 | let id = await alert.presentAlert();
1465 | if (id === -1) return;
1466 | this.settings[category][key] = options[id];
1467 | this.saveSettings();
1468 | }
1469 |
1470 | run = (filename, args) => {
1471 | if(!this.settings.basicSetting) this.settings.basicSetting = this.basicSetting;
1472 | Object.keys(this.basicSetting).forEach((key) => {
1473 | if(!this.settings.basicSetting.hasOwnProperty(key))
1474 | this.settings['basicSetting'][key] = this.basicSetting[key];
1475 | });
1476 | if(!this.settings.chartSetting) this.settings.chartSetting = this.chartSetting;
1477 | Object.keys(this.chartSetting).forEach((key) => {
1478 | if(!this.settings.chartSetting.hasOwnProperty(key))
1479 | this.settings['chartSetting'][key] = this.chartSetting[key];
1480 | });
1481 | if(!this.settings.funcSetting) this.settings.funcSetting = this.funcSetting;
1482 | Object.keys(this.funcSetting).forEach((key) => {
1483 | if(!this.settings.funcSetting.hasOwnProperty(key))
1484 | this.settings['funcSetting'][key] = this.funcSetting[key];
1485 | });
1486 | if(!this.settings.CACHES) this.settings.CACHES = [];
1487 | this.CACHES = this.settings.CACHES;
1488 | if (this.settings['basicSetting']['directory'] === 'iCloud') this.fm = FileManager.iCloud();
1489 | this.cachePath = this.fm.joinPath(this.fm.documentsDirectory(), this.CACHE_FOLDER);
1490 |
1491 | if (config.runsInApp) {
1492 | this.registerAction('参数配置', this.editSettings, 'https://gitee.com/anker1209/image/raw/master/jd/setting.png');
1493 | this.registerAction('账号设置', async () => {
1494 | const index = await this.generateAlert('设置账号信息', [
1495 | '网站登录',
1496 | '手动输入',
1497 | ]);
1498 | if (index === 0) {
1499 | await this.jdWebView();
1500 | } else {
1501 | await this.setAlertInput('账号设置', '京东账号cookie\n\n⚠️\n用户名和cookie必须输入!\n多账号注意用户名不要重复!', {
1502 | username: '用户名,必须输入!多账号勿重复!',
1503 | cookie: 'Cookie',
1504 | });
1505 | }
1506 | }, 'https://gitee.com/anker1209/image/raw/master/jd/account.png');
1507 | this.registerAction('代理缓存', this.actionSettings, 'https://gitee.com/anker1209/image/raw/master/jd/boxjs.png');
1508 | this.registerAction('基础设置', this.setWidgetConfig, 'https://gitee.com/anker1209/image/raw/master/jd/preferences.png');
1509 | }
1510 | Object.keys(this.settings['basicSetting']).forEach((key) => {
1511 | if (key == 'customizeName' || key == 'customizeAvatar' || key == 'smallShowType' || key == 'walletShowType' || key == 'directory') {
1512 | this.basicSetting[key] = this.settings['basicSetting'][key];
1513 | } else if (!isNaN(this.settings['basicSetting'][key])) {
1514 | this.basicSetting[key] = parseFloat(this.settings['basicSetting'][key]);
1515 | }
1516 | });
1517 | Object.keys(this.settings['chartSetting']).forEach((key) => {
1518 | if (key == 'textDayColor' || key == 'textNightColor' || key =='showType' || key == 'smallShowType' || key == 'countBean' || key == 'colorful' || key == 'lineColor' || key == 'dayText') {
1519 | this.chartSetting[key] = this.settings['chartSetting'][key];
1520 | } else if (!isNaN(this.settings['chartSetting'][key])) {
1521 | this.chartSetting[key] = parseFloat(this.settings['chartSetting'][key]);
1522 | }
1523 | });
1524 | Object.keys(this.settings['funcSetting']).forEach((key) => {
1525 | this.funcSetting[key] = this.settings['funcSetting'][key];
1526 | });
1527 |
1528 |
1529 | };
1530 |
1531 | jdWebView = async () => {
1532 | const webView = new WebView();
1533 | const url =
1534 | 'https://mcr.jd.com/credit_home/pages/index.html?btPageType=BT&channelName=024';
1535 | await webView.loadURL(url);
1536 | await webView.present(true);
1537 | const req = new Request(
1538 | 'https://ms.jr.jd.com/gw/generic/bt/h5/m/firstScreenNew',
1539 | );
1540 | req.method = 'POST';
1541 | req.body =
1542 | 'reqData={"clientType":"ios","clientVersion":"13.2.3","deviceId":"","environment":"3"}';
1543 | await req.loadJSON();
1544 | const cookies = req.response.cookies;
1545 | const account = {username: '', cookie: ''};
1546 | const cookie = [];
1547 | cookies.forEach((item) => {
1548 | const value = `${item.name}=${item.value}`;
1549 | if (item.name === 'pt_key') cookie.push(value);
1550 | if (item.name === 'pt_pin') {
1551 | account.username = item.value;
1552 | cookie.push(value);
1553 | }
1554 | });
1555 | account.cookie = cookie.join('; ');
1556 | console.log(account);
1557 |
1558 | if (account.cookie) {
1559 | this.settings = {...this.settings, ...account};
1560 | this.saveSettings(false);
1561 | console.log(`${this.name}: cookie获取成功,请关闭窗口!`);
1562 | this.notify(this.name, 'cookie获取成功,请关闭窗口!');
1563 | }
1564 | };
1565 |
1566 | _loadJDCk = async () => {
1567 | try {
1568 | this.CookiesData = await this.getCache('CookiesJD', false)
1569 | if (this.CookiesData) {
1570 | this.CookiesData = this.transforJSON(this.CookiesData)
1571 | } else {
1572 | throw "未获取到数据"
1573 | }
1574 | return true;
1575 | } catch (e) {
1576 | console.log(e);
1577 | this.CookiesData = [];
1578 | return false;
1579 | }
1580 | };
1581 |
1582 | async actionSettings() {
1583 | try {
1584 | const table = new UITable();
1585 | if (!(await this._loadJDCk())) throw 'BoxJS 数据读取失败';
1586 | // 如果是节点,则先远程获取
1587 | this.settings.cookieData = this.CookiesData;
1588 | this.saveSettings(false);
1589 | this.CookiesData.map((t, index) => {
1590 | const r = new UITableRow();
1591 | r.addText(`parameter:${index} ${t.userName}`);
1592 | r.onSelect = (n) => {
1593 | this.settings.username = t.userName;
1594 | this.settings.cookie = t.cookie;
1595 | this.saveSettings();
1596 | };
1597 | table.addRow(r);
1598 | });
1599 | let body = '京东 Ck 缓存成功,根据下标选择相应的 Ck';
1600 | if (this.settings.cookie) {
1601 | body += ',或者使用当前选中Ck:' + this.settings.username;
1602 | }
1603 | this.notify(this.name, body);
1604 | table.present(false);
1605 | } catch (e) {
1606 | console.log(e);
1607 | await this.notify(
1608 | `${this.name} - BoxJS 数据读取失败`,
1609 | '请检查 BoxJS 域名是否为代理复写的域名,如(boxjs.net 或 boxjs.com)。\n若没有配置 BoxJS 相关模块,请点击通知查看教程',
1610 | 'https://chavyleung.gitbook.io/boxjs/awesome/videos'
1611 | )
1612 | }
1613 | }
1614 |
1615 | async getCookie() {
1616 | this.JDindex = typeof args.widgetParameter === 'string'
1617 | ? parseInt(args.widgetParameter)
1618 | : false;
1619 | let _md5 = this.md5(module.filename + this.en);
1620 | if (this.funcSetting.logable === '打开') console.log('当前配置内容:' + JSON.stringify(this.settings));
1621 | try {
1622 | if (this.JDindex !== false && this.JDindex + 1 > 0) {
1623 |
1624 | if (!(await this._loadJDCk())) this.CookiesData = this.settings.cookieData
1625 |
1626 | this.cookie = this.CookiesData[this.JDindex]['cookie'];
1627 | this.userName =this.CookiesData[this.JDindex]["userName"];
1628 | } else {
1629 | this.userName = this.settings.username;
1630 | this.cookie = this.settings.cookie;
1631 | }
1632 | if (!this.cookie) throw "京东 CK 获取失败";
1633 | this.userName = decodeURI(this.userName);
1634 | this.CACHE_KEY = `cache_${_md5}_` + this.userName;
1635 | this.settings.CACHE_KEY = this.CACHE_KEY;
1636 | this.saveSettings(false);
1637 | return true;
1638 | } catch (e) {
1639 | this.notify("错误提示", e);
1640 | return false;
1641 | }
1642 | }
1643 |
1644 | async render() {
1645 | await this.getCookie();
1646 | if (!this.cookie || !this.userName) {
1647 | this.notify(this.name, 'cookie或用户名未设置');
1648 | return;
1649 | };
1650 | await this.init();
1651 | await this.getPackageData();
1652 | if (this.funcSetting.showBaitiao === '打开') await this.getBaitiaoData();
1653 | if (this.funcSetting.showFruit === '打开') await this.getFruitData();
1654 | if (this.funcSetting.logable === '打开') console.log(this.rangeTimer);
1655 | const widget = new ListWidget();
1656 | const padding = 14 * this.basicSetting.scale;
1657 | widget.setPadding(padding, padding, padding, padding);
1658 | await this.getWidgetBackgroundImage(widget);
1659 | if (this.widgetFamily === 'medium') {
1660 | return await this.renderMedium(widget);
1661 | } else if (this.widgetFamily === 'large') {
1662 | return await this.renderLarge(widget);
1663 | } else {
1664 | return await this.renderSmall(widget);
1665 | }
1666 | }
1667 | }
1668 |
1669 | await Runing(Widget, '', false);
1670 |
--------------------------------------------------------------------------------
/scripts/none.cpp:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/upcoming.json:
--------------------------------------------------------------------------------
1 | {
2 | "version":"2.2.7",
3 | "date": "2022.01.04",
4 | "notes": "\n- 脚本调整为直接读取BoxJS内的CK,多账号用户无需点击代理缓存读取CK"
5 | }
6 |
--------------------------------------------------------------------------------