@sybz-components/portal-dev 1.0.9 → 1.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/package.json +2 -2
- package/src/macos-chrome.mjs +8 -6
- package/src/portal-dev.mjs +1 -0
package/README.md
CHANGED
|
@@ -178,4 +178,4 @@ pnpm portal:skill:install
|
|
|
178
178
|
pnpm portal:release
|
|
179
179
|
```
|
|
180
180
|
|
|
181
|
-
`portal:release`
|
|
181
|
+
`portal:release` 会检查工作区和 npm 登录状态、升级 patch 版本并公开发布到 npm。只有确认新版本能从 npm registry 查询到之后,才会创建版本提交和 `portal-dev-v<版本号>` Git tag,并将当前分支及 tags 推送到 Git 远端。发布失败时会恢复本地版本号,避免留下无法安装的空版本。执行前请先提交当前改动,并确认当前分支和远端正确。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sybz-components/portal-dev",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.10",
|
|
4
4
|
"description": "成华和石景山门户自动登录与本地前端联调 CLI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"scripts": {
|
|
23
23
|
"skill:install": "node ./bin/portal-dev.mjs skill install",
|
|
24
24
|
"check": "node --check bin/portal-dev.mjs && node --check src/config-file.mjs && node --check src/configure.mjs && node --check src/macos-chrome.mjs && node --check src/portal-dev.mjs && node --check src/recognize-captcha.mjs",
|
|
25
|
-
"release": "
|
|
25
|
+
"release": "node ./scripts/release.mjs"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
28
|
"@napi-rs/canvas": "^1.0.3",
|
package/src/macos-chrome.mjs
CHANGED
|
@@ -83,13 +83,15 @@ const fillAndSubmit = async (tab, { username, password, captchaText, custom }) =
|
|
|
83
83
|
const visible = (element) => { const style = getComputedStyle(element); const rect = element.getBoundingClientRect(); return style.display !== 'none' && style.visibility !== 'hidden' && rect.width > 0 && rect.height > 0; };
|
|
84
84
|
const inputs = Array.from(document.querySelectorAll('input')).filter(visible);
|
|
85
85
|
const setValue = (element, value) => { const setter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value').set; setter.call(element, value); element.dispatchEvent(new Event('input', {bubbles:true})); element.dispatchEvent(new Event('change', {bubbles:true})); };
|
|
86
|
-
const
|
|
87
|
-
const passwordInput = inputs.find((input) => input
|
|
88
|
-
const captchaInput = inputs.find((input) => /验证码/.test(input
|
|
89
|
-
|
|
86
|
+
const attribute = (input, name) => input.getAttribute(name) || '';
|
|
87
|
+
const passwordInput = inputs.find((input) => attribute(input, 'autocomplete') === 'current-password' || /^password$/i.test(attribute(input, 'name')) || input.type === 'password' || /密码/.test(attribute(input, 'placeholder')));
|
|
88
|
+
const captchaInput = inputs.find((input) => /验证码/.test(attribute(input, 'placeholder')) || /captcha|code/i.test(attribute(input, 'name')));
|
|
89
|
+
const usernameInput = inputs.find((input) => attribute(input, 'autocomplete') === 'username' || /^(username|account|login|user|email|phone)$/i.test(attribute(input, 'name')) || /用户名|账号|邮箱|手机/.test(attribute(input, 'placeholder'))) || inputs.find((input) => input !== passwordInput && input !== captchaInput && /^(text|email|tel|number)$/.test(input.type));
|
|
90
|
+
const missing = [!usernameInput && '账号输入框', !passwordInput && '密码输入框', !${custom} && !captchaInput && '验证码输入框'].filter(Boolean);
|
|
91
|
+
if (missing.length) return JSON.stringify({submitted:false, reason:'未找到' + missing.join('、')});
|
|
90
92
|
setValue(usernameInput, values.username); setValue(passwordInput, values.password); if (captchaInput) setValue(captchaInput, values.captchaText);
|
|
91
93
|
const button = Array.from(document.querySelectorAll('button, input[type="submit"], [role="button"], .btn-box .btn')).filter(visible).find((element) => element.type === 'submit' || /登录|Login|Sign in/i.test(element.textContent || element.value || ''));
|
|
92
|
-
if (!button) return JSON.stringify({submitted:false}); button.click(); return JSON.stringify({submitted:true});
|
|
94
|
+
if (!button) return JSON.stringify({submitted:false, reason:'未找到登录按钮'}); button.click(); return JSON.stringify({submitted:true});
|
|
93
95
|
})()`,
|
|
94
96
|
),
|
|
95
97
|
)
|
|
@@ -107,7 +109,7 @@ const login = async (tab, config, recognizeCaptcha, custom) => {
|
|
|
107
109
|
console.log(`已识别图形验证码(第 ${attempt}/3 次)`)
|
|
108
110
|
}
|
|
109
111
|
const result = await fillAndSubmit(tab, { ...config, captchaText, custom })
|
|
110
|
-
if (!result.submitted) throw new Error('登录表单字段不完整或未找到登录按钮')
|
|
112
|
+
if (!result.submitted) throw new Error(result.reason || '登录表单字段不完整或未找到登录按钮')
|
|
111
113
|
await sleep(1800)
|
|
112
114
|
const state = await pageState(tab)
|
|
113
115
|
if (custom || !state.url.includes('/passport/login/')) return
|
package/src/portal-dev.mjs
CHANGED
|
@@ -209,6 +209,7 @@ const login = async () => {
|
|
|
209
209
|
'input[name="username"]',
|
|
210
210
|
'input[placeholder*="用户名"]',
|
|
211
211
|
'input[placeholder*="账号"]',
|
|
212
|
+
'input[autocomplete="off"]:not([type="password"]):not([placeholder*="验证码"])',
|
|
212
213
|
])
|
|
213
214
|
const passwordInput = await visibleLocator([
|
|
214
215
|
'input[autocomplete="current-password"]',
|