Ver código fonte

Merge branch 'feature/update' into develop

cc12458 1 mês atrás
pai
commit
e40db97f9e

+ 28 - 0
@types/bridge.d.ts

@@ -0,0 +1,28 @@
+interface ScanData {
+  code: string;
+  state: number;
+  type: number;
+  message?: string;
+}
+
+export interface BridgeEventMap {
+  scan: CustomEvent<{code: number, data?: ScanData, message?: string}>;
+}
+
+export class Bridge extends EventTarget {
+  public static getInstance(): Bridge;
+
+  public static print(): Promise<void>;
+  public static print(params: { url?: string }): Promise<void>;
+
+  public static scan(params?: { timeout?: number; signal?: AbortSignal }): Promise<ScanData>;
+
+  /**
+   * 监听扫码事件
+   * @param type 事件类型 'scan'
+   * @param listener 事件回调,参数为 ScanEvent
+   * @param options
+   */
+  addEventListener<T extends keyof BridgeEventMap>(type: T, listener: (event: BridgeEventMap[T]) => void, options?: boolean | AddEventListenerOptions): () => void;
+  removeEventListener<T extends keyof BridgeEventMap>(type: T, listener: (event: BridgeEventMap[T]) => void, options?: boolean | AddEventListenerOptions): () => void;
+}

+ 26 - 10
@types/global.d.ts

@@ -1,18 +1,34 @@
 export {};
+
 declare global {
-  export interface Platform extends EventTarget {
-    addEventListener<K extends keyof PlatformEventMap>(type: K, listener: (this: Platform, ev: PlatformEventMap[K]) => void): void;
+  declare const Bridge: typeof import('./bridge').Bridge;
 
-    removeEventListener<K extends keyof PlatformEventMap>(type: K, listener: (this: Platform, ev: PlatformEventMap[K]) => void): void;
+  interface Window {
+    /* six-pda 设备注入 */
+    bridge: InstanceType<typeof import('./bridge').Bridge>;
+    /**
+     * webview 设备注入的 全局对象(历史遗留)
+     * @deprecated 使用 bridge
+     */
+    platform: InstanceType<typeof import('./bridge').Bridge>;
   }
 
-  export interface PlatformEventMap {
-    scan: CustomEvent<{ code: string; type?: number; message?: string }>;
-  }
+  type BridgeEventMap = import('./bridge').BridgeEventMap;
 
-  interface Window {
-    platform: Platform;
-  }
+  /**
+   * webview 设备注入的 全局对象(历史遗留)
+   * @deprecated 使用 bridge
+   */
+  declare const platform: InstanceType<typeof import('./bridge').Bridge>;
 
-  declare const platform: Platform;
+  /**
+   * Promise 扩展
+   */
+  interface PromiseConstructor {
+    withResolvers<T>(): {
+      promise: Promise<T>;
+      resolve: (value: T | PromiseLike<T>) => void;
+      reject: (reason?: unknown) => void;
+    };
+  }
 }

+ 2 - 1
package.json

@@ -6,7 +6,8 @@
   "scripts": {
     "dev": "vite",
     "build": "run-p type-check \"build-only {@}\" --",
-    "preview": "vite preview",
+    "preview": "vite preview --base=/pharmacy/pda/ --mode development",
+    "device": "run-s build-only preview",
     "test:unit": "vitest",
     "prepare": "cypress install",
     "test:e2e": "start-server-and-test preview http://localhost:4173 'cypress run --e2e'",

+ 1 - 1
src/core/launch/index.ts

@@ -23,4 +23,4 @@ export default async function launch(component: Component, ...launcher: (Launche
 }
 
 export { debugLaunch } from './debug.launch.ts';
-export { platformLaunch } from './platform.launch.ts';
+export { default as platformLaunch } from './platform.launch.ts';

+ 25 - 4
src/core/launch/platform.launch.ts

@@ -1,7 +1,28 @@
-import type { Launcher } from '@/core/launch';
+import { platformIsPDA } from '@/platform';
+import type { Launcher } from '@/core/launch/index.ts';
 
-export function platformLaunch(): Launcher {
-  return async () => {
-    window.platform ??= new EventTarget();
+export function waitFor(condition: () => boolean | Promise<boolean>, timeout: number = 300 * 1000) {
+  const start = Date.now();
+  const { promise, resolve, reject } = Promise.withResolvers<void>();
+  const check = async () => {
+    try {
+      if (await condition()) resolve();
+      else if (timeout && Date.now() - start >= timeout) reject({ message: 'waitForBridge timeout' });
+      else requestAnimationFrame(check);
+    } catch (e) {
+      reject(e);
+    }
+  };
+  return check().then(
+    () => promise,
+    () => promise,
+  );
+}
+
+export default function bridgeLoader(): Launcher {
+  return async function () {
+    if (platformIsPDA()) {
+      await waitFor(() => window.bridge != null);
+    }
   };
 }

+ 2 - 0
src/main.ts

@@ -3,6 +3,8 @@ import { Lazyload } from 'vant';
 import 'vant/es/toast/style'
 import 'vant/es/notify/style'
 
+import './polyfill'
+
 import App from './App.vue';
 import launch, { debugLaunch, platformLaunch } from '@/core/launch';
 

+ 30 - 11
src/pages/StepPage.vue

@@ -20,18 +20,37 @@ const keyword = ref<string>(dataset.value?.no ?? '');
 
 const ignoreParentScanner = ref(false);
 provide('ignoreParentScanner', ignoreParentScanner);
-const update = (event: PlatformEventMap['scan']) => {
-  if (ignoreParentScanner.value) {
-    event.stopPropagation();
-    event.preventDefault();
-  } else {
-    keyword.value = event.detail.code;
-    const toast = showLoadingToast({ message: '查询中...', duration: 0 });
-    search().finally(() => toast.close());
+let onCleanup = () => {};
+tryOnBeforeMount(() => {
+  if (window.bridge) {
+    onCleanup = window.bridge.addEventListener('scan', event => {
+      const detail = event.detail;
+      if ( detail.code !== 0 || detail.data?.code == null ) return;
+      if (ignoreParentScanner.value) {
+        event.stopPropagation();
+        event.preventDefault();
+      } else {
+        keyword.value = event.detail.data?.code ?? '';
+        const toast = showLoadingToast({ message: '查询中...', duration: 0 });
+        search().finally(() => toast.close());
+      }
+    });
+  } else if (window.platform) {
+    const update = (event: CustomEvent) => {
+      if (ignoreParentScanner.value) {
+        event.stopPropagation();
+        event.preventDefault();
+      } else {
+        keyword.value = event.detail.code;
+        const toast = showLoadingToast({ message: '查询中...', duration: 0 });
+        search().finally(() => toast.close());
+      }
+    };
+    platform.addEventListener('scan', update)
+    onCleanup = () => { platform.removeEventListener('scan', update) }
   }
-};
-tryOnBeforeMount(() => platform?.addEventListener('scan', update));
-tryOnUnmounted(() => platform?.removeEventListener('scan', update));
+});
+tryOnUnmounted(() => onCleanup?.());
 
 const {
   data,

+ 5 - 0
src/platform/index.ts

@@ -0,0 +1,5 @@
+const userAgent = navigator.userAgent;
+
+export function platformIsPDA() {
+  return /Six\/applet \(PDA;.+\)/i.test(userAgent);
+}

+ 15 - 0
src/polyfill.ts

@@ -0,0 +1,15 @@
+if (typeof Promise.withResolvers !== 'function') {
+  Promise.withResolvers = function <T>() {
+    let resolve!: (value: T | PromiseLike<T>) => void;
+    let reject!: (reason?: any) => void;
+
+    const promise = new Promise<T>((res, rej) => {
+      resolve = res;
+      reject = rej;
+    });
+
+    return { promise, resolve, reject };
+  };
+}
+
+export {};

+ 0 - 1
src/themes/index.css

@@ -1,5 +1,4 @@
 @import "tailwindcss";
-@import "./legacy.css";
 
 #app {
   height: 100vh;

+ 0 - 144
src/themes/legacy.css

@@ -1,144 +0,0 @@
-
-:root, :host {--font-sans: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--spacing: .25rem;--container-sm: 24rem;--text-xl: 1.25rem;--text-xl--line-height: calc(1.75 / 1.25);--default-font-family: var(--font-sans);--default-mono-font-family: var(--font-mono)}
-
-*, :after, :before, ::backdrop {box-sizing: border-box;border: 0 solid;margin: 0;padding: 0}
-
-::file-selector-button {box-sizing: border-box;border: 0 solid;margin: 0;padding: 0}
-
-html, :host {-webkit-text-size-adjust: 100%;tab-size: 4;line-height: 1.5;font-family: var(--default-font-family, ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings: var(--default-font-feature-settings, normal);font-variation-settings: var(--default-font-variation-settings, normal);-webkit-tap-highlight-color: transparent}
-
-hr {height: 0;color: inherit;border-top-width: 1px}
-
-abbr:where([title]) {-webkit-text-decoration: underline dotted;text-decoration: underline dotted}
-
-h1, h2, h3, h4, h5, h6 {font-size: inherit;font-weight: inherit}
-
-a {color: inherit;-webkit-text-decoration: inherit;text-decoration: inherit}
-
-b, strong {font-weight: bolder}
-
-code, kbd, samp, pre {font-family: var(--default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings: var(--default-mono-font-feature-settings, normal);font-variation-settings: var(--default-mono-font-variation-settings, normal);font-size: 1em}
-
-small {font-size: 80%}
-
-sub, sup {vertical-align: baseline;font-size: 75%;line-height: 0;position: relative}
-
-sub {bottom: -.25em}
-
-sup {top: -.5em}
-
-table {text-indent: 0;border-color: inherit;border-collapse: collapse}
-
-:-moz-focusring {outline: auto}
-
-progress {vertical-align: baseline}
-
-summary {display: list-item}
-
-ol, ul, menu {list-style: none}
-
-img, svg, video, canvas, audio, iframe, embed, object {vertical-align: middle;display: block}
-
-img, video {max-width: 100%;height: auto}
-
-button, input, select, optgroup, textarea {font: inherit;font-feature-settings: inherit;font-variation-settings: inherit;letter-spacing: inherit;color: inherit;opacity: 1;background-color: rgba(0, 0, 0, 0);border-radius: 0}
-
-::file-selector-button {font: inherit;font-feature-settings: inherit;font-variation-settings: inherit;letter-spacing: inherit;color: inherit;opacity: 1;background-color: rgba(0, 0, 0, 0);border-radius: 0}
-
-:where(select:is([multiple],[size])) optgroup {font-weight: bolder}
-
-:where(select:is([multiple],[size])) optgroup option {padding-inline-start: 20px}
-
-::file-selector-button {margin-inline-end: 4px}
-
-::placeholder {opacity: 1}
-
-@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px) {
-  ::placeholder {color: color-mix(in oklab, currentColor 50%, transparent)}
-}
-
-textarea {resize: vertical}
-
-::-webkit-search-decoration {-webkit-appearance: none}
-
-::-webkit-date-and-time-value {min-height: 1lh;text-align: inherit}
-
-::-webkit-datetime-edit {display: inline-flex}
-
-::-webkit-datetime-edit-fields-wrapper {padding: 0}
-
-::-webkit-datetime-edit {padding-block: 0}
-
-::-webkit-datetime-edit-year-field {padding-block: 0}
-
-::-webkit-datetime-edit-month-field {padding-block: 0}
-
-::-webkit-datetime-edit-day-field {padding-block: 0}
-
-::-webkit-datetime-edit-hour-field {padding-block: 0}
-
-::-webkit-datetime-edit-minute-field {padding-block: 0}
-
-::-webkit-datetime-edit-second-field {padding-block: 0}
-
-::-webkit-datetime-edit-millisecond-field {padding-block: 0}
-
-::-webkit-datetime-edit-meridiem-field {padding-block: 0}
-
-:-moz-ui-invalid {box-shadow: none}
-
-button, input:where([type=button],[type=reset],[type=submit]) {-webkit-appearance: button;appearance: button}
-
-::file-selector-button {-webkit-appearance: button;appearance: button}
-
-::-webkit-inner-spin-button {height: auto}
-
-::-webkit-outer-spin-button {height: auto}
-
-[hidden]:where(:not([hidden=until-found])) {display: none !important}
-
-.static {position: static}
-
-.m-auto {margin: auto}
-
-.my-4 {margin-block: calc(var(--spacing) * 4)}
-
-.mt-8 {margin-top: calc(var(--spacing) * 8)}
-
-.block {display: block}
-
-.flex {display: flex}
-
-.table {display: table}
-
-.size-full {width: 100%;height: 100%}
-
-.w-24 {width: calc(var(--spacing) * 24)}
-
-.w-full {width: 100%}
-
-.max-w-sm {max-width: var(--container-sm)}
-
-.min-w-\[600px\] {min-width: 600px}
-
-.flex-auto {flex: auto}
-
-.flex-none {flex: none}
-
-.border-collapse {border-collapse: collapse}
-
-.flex-col {flex-direction: column}
-
-.overflow-hidden {overflow: hidden}
-
-.border {border-style: var(--tw-border-style);border-width: 1px}
-
-.p-4 {padding: calc(var(--spacing) * 4)}
-
-.px-4 {padding-inline: calc(var(--spacing) * 4)}
-
-.py-4 {padding-block: calc(var(--spacing) * 4)}
-
-.text-center {text-align: center}
-
-.text-xl {font-size: var(--text-xl);line-height: var(--tw-leading, var(--text-xl--line-height))}

+ 0 - 8
vite.config.ts

@@ -42,14 +42,6 @@ export default defineConfig(({ mode, command }) => {
         resolvers: [VantResolver()],
         dts: '@types/components.d.ts',
       }),
-
-
-      legacy({
-        targets: ['chrome >=49'],
-        modernTargets: ['chrome >=61'],
-        polyfills: true,
-        modernPolyfills: true,
-      }),
     ],
     resolve: {
       alias: {