@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 CHANGED
@@ -178,4 +178,4 @@ pnpm portal:skill:install
178
178
  pnpm portal:release
179
179
  ```
180
180
 
181
- `portal:release` 会执行检查、升级 patch 版本、创建版本提交和 Git tag、发布 npm 包,最后将当前分支及 tags 推送到 Git 远端。执行前请确认当前分支、远端和工作区状态。
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.9",
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": "pnpm check && npm version patch && npm publish && git push --follow-tags"
25
+ "release": "node ./scripts/release.mjs"
26
26
  },
27
27
  "dependencies": {
28
28
  "@napi-rs/canvas": "^1.0.3",
@@ -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 usernameInput = inputs.find((input) => input.autocomplete === 'username' || ['username','account','login','user','email'].includes(input.name) || /用户名|账号|邮箱|手机/.test(input.placeholder));
87
- const passwordInput = inputs.find((input) => input.autocomplete === 'current-password' || input.name === 'password' || input.type === 'password' || input.placeholder.includes('密码'));
88
- const captchaInput = inputs.find((input) => /验证码/.test(input.placeholder) || /captcha|code/i.test(input.name));
89
- if (!usernameInput || !passwordInput || (!${custom} && !captchaInput)) return JSON.stringify({submitted:false});
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
@@ -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"]',