dsh-ponlay-erp 1.8.0 → 1.8.1

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.
Files changed (3) hide show
  1. package/client.js +32 -4
  2. package/index.js +16 -6
  3. package/package.json +1 -1
package/client.js CHANGED
@@ -26,6 +26,11 @@ window.__ModuleLoader__.load({
26
26
 
27
27
  const delay = (ms) => new Promise((resolve) => window.setTimeout(resolve, ms))
28
28
 
29
+ function activeLang(localeFace) {
30
+ const id = String(localeFace.getSnapshot().active || '').toLowerCase()
31
+ return id.startsWith('zh') ? 'zh' : 'en'
32
+ }
33
+
29
34
  // ---------------------------------------------------------------
30
35
  // Dictionaries
31
36
  // ---------------------------------------------------------------
@@ -36,6 +41,7 @@ window.__ModuleLoader__.load({
36
41
  'status.loading': 'Connecting…',
37
42
  'action.retry': 'Retry',
38
43
  'action.openExternal': 'Open in new tab',
44
+ 'action.expandSidebar': 'Expand sidebar',
39
45
  'error.proxyTitle': 'Embedded mode is unavailable',
40
46
  'error.proxyBody': 'The local ERP proxy did not start, so the system cannot be embedded here. You can still open the original site in a new tab.',
41
47
  'error.httpsTitle': 'Embedded mode needs the local http address',
@@ -63,6 +69,7 @@ window.__ModuleLoader__.load({
63
69
  'status.loading': '正在连接…',
64
70
  'action.retry': '重试',
65
71
  'action.openExternal': '在新窗口打开',
72
+ 'action.expandSidebar': '展开侧边栏',
66
73
  'error.proxyTitle': '内嵌模式不可用',
67
74
  'error.proxyBody': '本地 ERP 代理未启动,无法在此页面内嵌;你仍然可以在新窗口打开原站。',
68
75
  'error.httpsTitle': '内嵌模式需要本地 http 地址',
@@ -95,6 +102,7 @@ window.__ModuleLoader__.load({
95
102
  'M6.5 12.5v3M10 12.5v2M13.5 12.5v3M17 12.5v2',
96
103
  ],
97
104
  alert: ['M12 3.2 2.9 19.8h18.2L12 3.2Z', 'M12 9.4v4.4', 'M12 16.6v.2'],
105
+ panelLeft: ['M3.5 5.5h17a1 1 0 0 1 1 1v11a1 1 0 0 1-1 1h-17a1 1 0 0 1-1-1v-11a1 1 0 0 1 1-1Z', 'M9 5.5v13'],
98
106
  }
99
107
 
100
108
  function Icon({ name, size = 16 }) {
@@ -199,11 +207,12 @@ window.__ModuleLoader__.load({
199
207
  // Persistent ERP surface
200
208
  // ---------------------------------------------------------------
201
209
 
202
- function ErpSurface({ t, localeFace, store, usePanelInfo }) {
210
+ function ErpSurface({ t, localeFace, store, usePanelInfo, layout }) {
203
211
  const active = usePanelInfo((info) => info.activePanelId === PANEL_KEY)
204
212
  const rect = useSyncExternalStore(store.subscribe, store.getRect, store.getRect)
205
213
  useSyncExternalStore(localeFace.subscribe, localeFace.getSnapshot, localeFace.getSnapshot)
206
214
 
215
+ const lang = activeLang(localeFace)
207
216
  const [started, setStarted] = useState(false)
208
217
  const [attempt, setAttempt] = useState(0)
209
218
  const [proxy, setProxy] = useState({ phase: 'loading', port: 0, target: DEFAULT_TARGET })
@@ -294,9 +303,10 @@ window.__ModuleLoader__.load({
294
303
  const ready = proxy.phase === 'ready'
295
304
  // A stale browser token must not outlive the server-side session: the
296
305
  // reset page clears the proxy origin's storage and forwards to /login.
297
- const targetPath = judged && !loggedIn ? '/_ponlay/reset' : '/'
306
+ const targetPath = judged && !loggedIn ? `/_ponlay/reset?ponlay_lang=${lang}` : '/'
298
307
  const src = ready && judged ? `http://${PROXY_HOST}:${proxy.port}${targetPath}` : ''
299
308
  const visible = active && Boolean(rect) && rect.width > 0 && rect.height > 0
309
+ const collapsed = Boolean(rect) && rect.left < 120
300
310
  const style = {
301
311
  top: `${rect ? rect.top : 0}px`,
302
312
  left: `${rect ? rect.left : 0}px`,
@@ -344,17 +354,30 @@ window.__ModuleLoader__.load({
344
354
  'div',
345
355
  { className: 'erp-surface', style, 'data-hidden': visible ? 'false' : 'true' },
346
356
  face,
357
+ visible && collapsed
358
+ ? h(
359
+ 'button',
360
+ {
361
+ type: 'button',
362
+ className: 'erp-expand',
363
+ title: t('action.expandSidebar'),
364
+ 'aria-label': t('action.expandSidebar'),
365
+ onClick: () => layout?.toggleSidebar(),
366
+ },
367
+ h(Icon, { name: 'panelLeft', size: 16 }),
368
+ )
369
+ : null,
347
370
  showLoading
348
371
  ? h('div', { className: 'erp-loading', 'aria-hidden': true }, h('span', { className: 'erp-spinner' }), t('status.loading'))
349
372
  : null,
350
373
  )
351
374
  }
352
375
 
353
- function ErpSurfaceHost({ t, localeFace, store, usePanelInfo }) {
376
+ function ErpSurfaceHost({ t, localeFace, store, usePanelInfo, layout }) {
354
377
  // A slot entry that throws blanks its registration; degrade to "off"
355
378
  // instead if the standard kit ever stops providing the panel hook.
356
379
  if (typeof usePanelInfo !== 'function') return null
357
- return h(ErpSurface, { t, localeFace, store, usePanelInfo })
380
+ return h(ErpSurface, { t, localeFace, store, usePanelInfo, layout })
358
381
  }
359
382
 
360
383
  // ---------------------------------------------------------------
@@ -560,6 +583,9 @@ window.__ModuleLoader__.load({
560
583
  .erp-cfg-notice-pending{border-color:color-mix(in srgb,var(--dsw-alias-state-warn-primary) 45%,transparent);color:var(--dsw-alias-state-warn-primary)}
561
584
  .erp-cfg-notice-error{border-color:color-mix(in srgb,var(--dsw-alias-state-error-primary) 45%,transparent);color:var(--dsw-alias-state-error-primary)}
562
585
  .erp-cfg-summary{font-size:12px;line-height:1.6;color:var(--dsw-alias-label-secondary);overflow-wrap:anywhere}
586
+ .erp-expand{position:absolute;top:calc(var(--dsh-frame-top-clearance,0px) + 10px);left:12px;z-index:5;display:flex;align-items:center;justify-content:center;width:32px;height:32px;padding:0;border:1px solid var(--dsw-alias-border-l1);border-radius:9px;background:var(--dsw-alias-bg-overlay);color:var(--dsw-alias-label-secondary);box-shadow:0 6px 18px color-mix(in srgb,var(--dsw-alias-label-primary) 16%,transparent);cursor:pointer;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px)}
587
+ .erp-expand:hover{background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary)}
588
+ .erp-expand:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}
563
589
  @keyframes erp-spin{to{transform:rotate(360deg)}}
564
590
  @media (prefers-reduced-motion:reduce){.erp-spinner{animation-duration:1.6s}}
565
591
  `
@@ -573,6 +599,7 @@ window.__ModuleLoader__.load({
573
599
  inject: ['slots', 'locale'],
574
600
  apply(ctx) {
575
601
  const locale = ctx.get('locale')
602
+ const layout = ctx.get('layout')
576
603
  const store = createRectStore()
577
604
  const dicts = [locale.register('ponlay-erp', 'en', EN), locale.register('ponlay-erp', 'zh', ZH)]
578
605
  ctx.effect(() => () => {
@@ -607,6 +634,7 @@ window.__ModuleLoader__.load({
607
634
  t,
608
635
  localeFace,
609
636
  store,
637
+ layout,
610
638
  usePanelInfo: props.usePanelInfo,
611
639
  }),
612
640
  ),
package/index.js CHANGED
@@ -24,12 +24,20 @@ const INFO_PATH = '/plugin/ponlay-erp/info'
24
24
  const STATE_PATH = '/plugin/ponlay-erp/state'
25
25
  const CONFIG_PATH = '/plugin/ponlay-erp/config'
26
26
  const RESET_PATH = '/_ponlay/reset'
27
- const RESET_HTML = `<!doctype html>
28
- <html lang="zh"><head><meta charset="utf-8"><title>Ponlay ERP</title></head>
27
+ /** Reset page: clear the stale ERP session but seed the UI language. */
28
+ function resetHtml(lang) {
29
+ const locale = lang === 'en' ? 'en' : 'zh'
30
+ return `<!doctype html>
31
+ <html lang="${locale}"><head><meta charset="utf-8"><title>Ponlay ERP</title></head>
29
32
  <body><script>
30
- try { localStorage.clear(); sessionStorage.clear(); } catch (error) {}
33
+ try {
34
+ localStorage.clear();
35
+ sessionStorage.clear();
36
+ localStorage.setItem('GlobalState', JSON.stringify({ language: '${locale}' }));
37
+ } catch (error) {}
31
38
  location.replace('/login');
32
39
  </script></body></html>`
40
+ }
33
41
  const PORT_CANDIDATES = [4317, 4318, 4319, 4320, 4321, 4322, 4323, 4324, 4325, 4326]
34
42
  const MAX_UPSTREAM_BYTES = 8 * 1024 * 1024
35
43
  const MAX_CONFIG_BODY_BYTES = 64 * 1024
@@ -248,13 +256,15 @@ function createProxyHandler(jar, port, target) {
248
256
 
249
257
  // A stale browser token must not outlive the server-side session: clear the
250
258
  // proxy origin's storage, then let the ERP show its own login page.
251
- if (req.url === RESET_PATH) {
259
+ const requestUrl = new URL(req.url || '/', 'http://127.0.0.1')
260
+ if (requestUrl.pathname === RESET_PATH) {
261
+ const html = resetHtml(requestUrl.searchParams.get('ponlay_lang') === 'en' ? 'en' : 'zh')
252
262
  res.writeHead(200, {
253
263
  'content-type': 'text/html; charset=utf-8',
254
264
  'cache-control': 'no-store',
255
- 'content-length': Buffer.byteLength(RESET_HTML),
265
+ 'content-length': Buffer.byteLength(html),
256
266
  })
257
- res.end(req.method === 'HEAD' ? undefined : RESET_HTML)
267
+ res.end(req.method === 'HEAD' ? undefined : html)
258
268
  return
259
269
  }
260
270
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-ponlay-erp",
3
- "version": "1.8.0",
3
+ "version": "1.8.1",
4
4
  "description": "Ponlay ERP system embedded in DeepSeek Harness: the ERP login page or signed-in layout fills the main area, with a configurable system address.",
5
5
  "type": "module",
6
6
  "license": "MIT",