{"version":3,"file":"index.mjs","sources":["../node_modules/vue-router/dist/vue-router.mjs","../src/工具函数/页面上下文.ts","../src/工具函数/任务管理API.ts","../src/工具函数/工业组件API.ts","../src/工具函数/工业按钮指令.ts","../src/工具函数/工业输入框指令.ts","../src/工具函数/原始字节按钮指令.ts","../src/工具函数/事件桥接.ts","../src/工具函数/页面任务守卫.ts","../src/index.ts"],"sourcesContent":["/*!\n  * vue-router v4.5.1\n  * (c) 2025 Eduardo San Martin Morote\n  * @license MIT\n  */\nimport { getCurrentInstance, inject, onUnmounted, onDeactivated, onActivated, computed, unref, watchEffect, defineComponent, reactive, h, provide, ref, watch, shallowRef, shallowReactive, nextTick } from 'vue';\nimport { setupDevtoolsPlugin } from '@vue/devtools-api';\n\nconst isBrowser = typeof document !== 'undefined';\n\n/**\n * Allows differentiating lazy components from functional components and vue-class-component\n * @internal\n *\n * @param component\n */\nfunction isRouteComponent(component) {\n    return (typeof component === 'object' ||\n        'displayName' in component ||\n        'props' in component ||\n        '__vccOpts' in component);\n}\nfunction isESModule(obj) {\n    return (obj.__esModule ||\n        obj[Symbol.toStringTag] === 'Module' ||\n        // support CF with dynamic imports that do not\n        // add the Module string tag\n        (obj.default && isRouteComponent(obj.default)));\n}\nconst assign = Object.assign;\nfunction applyToParams(fn, params) {\n    const newParams = {};\n    for (const key in params) {\n        const value = params[key];\n        newParams[key] = isArray(value)\n            ? value.map(fn)\n            : fn(value);\n    }\n    return newParams;\n}\nconst noop = () => { };\n/**\n * Typesafe alternative to Array.isArray\n * https://github.com/microsoft/TypeScript/pull/48228\n */\nconst isArray = Array.isArray;\n\nfunction warn(msg) {\n    // avoid using ...args as it breaks in older Edge builds\n    const args = Array.from(arguments).slice(1);\n    console.warn.apply(console, ['[Vue Router warn]: ' + msg].concat(args));\n}\n\n/**\n * Encoding Rules (␣ = Space)\n * - Path: ␣ \" < > # ? { }\n * - Query: ␣ \" < > # & =\n * - Hash: ␣ \" < > `\n *\n * On top of that, the RFC3986 (https://tools.ietf.org/html/rfc3986#section-2.2)\n * defines some extra characters to be encoded. Most browsers do not encode them\n * in encodeURI https://github.com/whatwg/url/issues/369, so it may be safer to\n * also encode `!'()*`. Leaving un-encoded only ASCII alphanumeric(`a-zA-Z0-9`)\n * plus `-._~`. This extra safety should be applied to query by patching the\n * string returned by encodeURIComponent encodeURI also encodes `[\\]^`. `\\`\n * should be encoded to avoid ambiguity. Browsers (IE, FF, C) transform a `\\`\n * into a `/` if directly typed in. The _backtick_ (`````) should also be\n * encoded everywhere because some browsers like FF encode it when directly\n * written while others don't. Safari and IE don't encode ``\"<>{}``` in hash.\n */\n// const EXTRA_RESERVED_RE = /[!'()*]/g\n// const encodeReservedReplacer = (c: string) => '%' + c.charCodeAt(0).toString(16)\nconst HASH_RE = /#/g; // %23\nconst AMPERSAND_RE = /&/g; // %26\nconst SLASH_RE = /\\//g; // %2F\nconst EQUAL_RE = /=/g; // %3D\nconst IM_RE = /\\?/g; // %3F\nconst PLUS_RE = /\\+/g; // %2B\n/**\n * NOTE: It's not clear to me if we should encode the + symbol in queries, it\n * seems to be less flexible than not doing so and I can't find out the legacy\n * systems requiring this for regular requests like text/html. In the standard,\n * the encoding of the plus character is only mentioned for\n * application/x-www-form-urlencoded\n * (https://url.spec.whatwg.org/#urlencoded-parsing) and most browsers seems lo\n * leave the plus character as is in queries. To be more flexible, we allow the\n * plus character on the query, but it can also be manually encoded by the user.\n *\n * Resources:\n * - https://url.spec.whatwg.org/#urlencoded-parsing\n * - https://stackoverflow.com/questions/1634271/url-encoding-the-space-character-or-20\n */\nconst ENC_BRACKET_OPEN_RE = /%5B/g; // [\nconst ENC_BRACKET_CLOSE_RE = /%5D/g; // ]\nconst ENC_CARET_RE = /%5E/g; // ^\nconst ENC_BACKTICK_RE = /%60/g; // `\nconst ENC_CURLY_OPEN_RE = /%7B/g; // {\nconst ENC_PIPE_RE = /%7C/g; // |\nconst ENC_CURLY_CLOSE_RE = /%7D/g; // }\nconst ENC_SPACE_RE = /%20/g; // }\n/**\n * Encode characters that need to be encoded on the path, search and hash\n * sections of the URL.\n *\n * @internal\n * @param text - string to encode\n * @returns encoded string\n */\nfunction commonEncode(text) {\n    return encodeURI('' + text)\n        .replace(ENC_PIPE_RE, '|')\n        .replace(ENC_BRACKET_OPEN_RE, '[')\n        .replace(ENC_BRACKET_CLOSE_RE, ']');\n}\n/**\n * Encode characters that need to be encoded on the hash section of the URL.\n *\n * @param text - string to encode\n * @returns encoded string\n */\nfunction encodeHash(text) {\n    return commonEncode(text)\n        .replace(ENC_CURLY_OPEN_RE, '{')\n        .replace(ENC_CURLY_CLOSE_RE, '}')\n        .replace(ENC_CARET_RE, '^');\n}\n/**\n * Encode characters that need to be encoded query values on the query\n * section of the URL.\n *\n * @param text - string to encode\n * @returns encoded string\n */\nfunction encodeQueryValue(text) {\n    return (commonEncode(text)\n        // Encode the space as +, encode the + to differentiate it from the space\n        .replace(PLUS_RE, '%2B')\n        .replace(ENC_SPACE_RE, '+')\n        .replace(HASH_RE, '%23')\n        .replace(AMPERSAND_RE, '%26')\n        .replace(ENC_BACKTICK_RE, '`')\n        .replace(ENC_CURLY_OPEN_RE, '{')\n        .replace(ENC_CURLY_CLOSE_RE, '}')\n        .replace(ENC_CARET_RE, '^'));\n}\n/**\n * Like `encodeQueryValue` but also encodes the `=` character.\n *\n * @param text - string to encode\n */\nfunction encodeQueryKey(text) {\n    return encodeQueryValue(text).replace(EQUAL_RE, '%3D');\n}\n/**\n * Encode characters that need to be encoded on the path section of the URL.\n *\n * @param text - string to encode\n * @returns encoded string\n */\nfunction encodePath(text) {\n    return commonEncode(text).replace(HASH_RE, '%23').replace(IM_RE, '%3F');\n}\n/**\n * Encode characters that need to be encoded on the path section of the URL as a\n * param. This function encodes everything {@link encodePath} does plus the\n * slash (`/`) character. If `text` is `null` or `undefined`, returns an empty\n * string instead.\n *\n * @param text - string to encode\n * @returns encoded string\n */\nfunction encodeParam(text) {\n    return text == null ? '' : encodePath(text).replace(SLASH_RE, '%2F');\n}\n/**\n * Decode text using `decodeURIComponent`. Returns the original text if it\n * fails.\n *\n * @param text - string to decode\n * @returns decoded string\n */\nfunction decode(text) {\n    try {\n        return decodeURIComponent('' + text);\n    }\n    catch (err) {\n        (process.env.NODE_ENV !== 'production') && warn(`Error decoding \"${text}\". Using original value`);\n    }\n    return '' + text;\n}\n\nconst TRAILING_SLASH_RE = /\\/$/;\nconst removeTrailingSlash = (path) => path.replace(TRAILING_SLASH_RE, '');\n/**\n * Transforms a URI into a normalized history location\n *\n * @param parseQuery\n * @param location - URI to normalize\n * @param currentLocation - current absolute location. Allows resolving relative\n * paths. Must start with `/`. Defaults to `/`\n * @returns a normalized history location\n */\nfunction parseURL(parseQuery, location, currentLocation = '/') {\n    let path, query = {}, searchString = '', hash = '';\n    // Could use URL and URLSearchParams but IE 11 doesn't support it\n    // TODO: move to new URL()\n    const hashPos = location.indexOf('#');\n    let searchPos = location.indexOf('?');\n    // the hash appears before the search, so it's not part of the search string\n    if (hashPos < searchPos && hashPos >= 0) {\n        searchPos = -1;\n    }\n    if (searchPos > -1) {\n        path = location.slice(0, searchPos);\n        searchString = location.slice(searchPos + 1, hashPos > -1 ? hashPos : location.length);\n        query = parseQuery(searchString);\n    }\n    if (hashPos > -1) {\n        path = path || location.slice(0, hashPos);\n        // keep the # character\n        hash = location.slice(hashPos, location.length);\n    }\n    // no search and no query\n    path = resolveRelativePath(path != null ? path : location, currentLocation);\n    // empty path means a relative query or hash `?foo=f`, `#thing`\n    return {\n        fullPath: path + (searchString && '?') + searchString + hash,\n        path,\n        query,\n        hash: decode(hash),\n    };\n}\n/**\n * Stringifies a URL object\n *\n * @param stringifyQuery\n * @param location\n */\nfunction stringifyURL(stringifyQuery, location) {\n    const query = location.query ? stringifyQuery(location.query) : '';\n    return location.path + (query && '?') + query + (location.hash || '');\n}\n/**\n * Strips off the base from the beginning of a location.pathname in a non-case-sensitive way.\n *\n * @param pathname - location.pathname\n * @param base - base to strip off\n */\nfunction stripBase(pathname, base) {\n    // no base or base is not found at the beginning\n    if (!base || !pathname.toLowerCase().startsWith(base.toLowerCase()))\n        return pathname;\n    return pathname.slice(base.length) || '/';\n}\n/**\n * Checks if two RouteLocation are equal. This means that both locations are\n * pointing towards the same {@link RouteRecord} and that all `params`, `query`\n * parameters and `hash` are the same\n *\n * @param stringifyQuery - A function that takes a query object of type LocationQueryRaw and returns a string representation of it.\n * @param a - first {@link RouteLocation}\n * @param b - second {@link RouteLocation}\n */\nfunction isSameRouteLocation(stringifyQuery, a, b) {\n    const aLastIndex = a.matched.length - 1;\n    const bLastIndex = b.matched.length - 1;\n    return (aLastIndex > -1 &&\n        aLastIndex === bLastIndex &&\n        isSameRouteRecord(a.matched[aLastIndex], b.matched[bLastIndex]) &&\n        isSameRouteLocationParams(a.params, b.params) &&\n        stringifyQuery(a.query) === stringifyQuery(b.query) &&\n        a.hash === b.hash);\n}\n/**\n * Check if two `RouteRecords` are equal. Takes into account aliases: they are\n * considered equal to the `RouteRecord` they are aliasing.\n *\n * @param a - first {@link RouteRecord}\n * @param b - second {@link RouteRecord}\n */\nfunction isSameRouteRecord(a, b) {\n    // since the original record has an undefined value for aliasOf\n    // but all aliases point to the original record, this will always compare\n    // the original record\n    return (a.aliasOf || a) === (b.aliasOf || b);\n}\nfunction isSameRouteLocationParams(a, b) {\n    if (Object.keys(a).length !== Object.keys(b).length)\n        return false;\n    for (const key in a) {\n        if (!isSameRouteLocationParamsValue(a[key], b[key]))\n            return false;\n    }\n    return true;\n}\nfunction isSameRouteLocationParamsValue(a, b) {\n    return isArray(a)\n        ? isEquivalentArray(a, b)\n        : isArray(b)\n            ? isEquivalentArray(b, a)\n            : a === b;\n}\n/**\n * Check if two arrays are the same or if an array with one single entry is the\n * same as another primitive value. Used to check query and parameters\n *\n * @param a - array of values\n * @param b - array of values or a single value\n */\nfunction isEquivalentArray(a, b) {\n    return isArray(b)\n        ? a.length === b.length && a.every((value, i) => value === b[i])\n        : a.length === 1 && a[0] === b;\n}\n/**\n * Resolves a relative path that starts with `.`.\n *\n * @param to - path location we are resolving\n * @param from - currentLocation.path, should start with `/`\n */\nfunction resolveRelativePath(to, from) {\n    if (to.startsWith('/'))\n        return to;\n    if ((process.env.NODE_ENV !== 'production') && !from.startsWith('/')) {\n        warn(`Cannot resolve a relative location without an absolute path. Trying to resolve \"${to}\" from \"${from}\". It should look like \"/${from}\".`);\n        return to;\n    }\n    if (!to)\n        return from;\n    const fromSegments = from.split('/');\n    const toSegments = to.split('/');\n    const lastToSegment = toSegments[toSegments.length - 1];\n    // make . and ./ the same (../ === .., ../../ === ../..)\n    // this is the same behavior as new URL()\n    if (lastToSegment === '..' || lastToSegment === '.') {\n        toSegments.push('');\n    }\n    let position = fromSegments.length - 1;\n    let toPosition;\n    let segment;\n    for (toPosition = 0; toPosition < toSegments.length; toPosition++) {\n        segment = toSegments[toPosition];\n        // we stay on the same position\n        if (segment === '.')\n            continue;\n        // go up in the from array\n        if (segment === '..') {\n            // we can't go below zero, but we still need to increment toPosition\n            if (position > 1)\n                position--;\n            // continue\n        }\n        // we reached a non-relative path, we stop here\n        else\n            break;\n    }\n    return (fromSegments.slice(0, position).join('/') +\n        '/' +\n        toSegments.slice(toPosition).join('/'));\n}\n/**\n * Initial route location where the router is. Can be used in navigation guards\n * to differentiate the initial navigation.\n *\n * @example\n * ```js\n * import { START_LOCATION } from 'vue-router'\n *\n * router.beforeEach((to, from) => {\n *   if (from === START_LOCATION) {\n *     // initial navigation\n *   }\n * })\n * ```\n */\nconst START_LOCATION_NORMALIZED = {\n    path: '/',\n    // TODO: could we use a symbol in the future?\n    name: undefined,\n    params: {},\n    query: {},\n    hash: '',\n    fullPath: '/',\n    matched: [],\n    meta: {},\n    redirectedFrom: undefined,\n};\n\nvar NavigationType;\n(function (NavigationType) {\n    NavigationType[\"pop\"] = \"pop\";\n    NavigationType[\"push\"] = \"push\";\n})(NavigationType || (NavigationType = {}));\nvar NavigationDirection;\n(function (NavigationDirection) {\n    NavigationDirection[\"back\"] = \"back\";\n    NavigationDirection[\"forward\"] = \"forward\";\n    NavigationDirection[\"unknown\"] = \"\";\n})(NavigationDirection || (NavigationDirection = {}));\n/**\n * Starting location for Histories\n */\nconst START = '';\n// Generic utils\n/**\n * Normalizes a base by removing any trailing slash and reading the base tag if\n * present.\n *\n * @param base - base to normalize\n */\nfunction normalizeBase(base) {\n    if (!base) {\n        if (isBrowser) {\n            // respect <base> tag\n            const baseEl = document.querySelector('base');\n            base = (baseEl && baseEl.getAttribute('href')) || '/';\n            // strip full URL origin\n            base = base.replace(/^\\w+:\\/\\/[^\\/]+/, '');\n        }\n        else {\n            base = '/';\n        }\n    }\n    // ensure leading slash when it was removed by the regex above avoid leading\n    // slash with hash because the file could be read from the disk like file://\n    // and the leading slash would cause problems\n    if (base[0] !== '/' && base[0] !== '#')\n        base = '/' + base;\n    // remove the trailing slash so all other method can just do `base + fullPath`\n    // to build an href\n    return removeTrailingSlash(base);\n}\n// remove any character before the hash\nconst BEFORE_HASH_RE = /^[^#]+#/;\nfunction createHref(base, location) {\n    return base.replace(BEFORE_HASH_RE, '#') + location;\n}\n\nfunction getElementPosition(el, offset) {\n    const docRect = document.documentElement.getBoundingClientRect();\n    const elRect = el.getBoundingClientRect();\n    return {\n        behavior: offset.behavior,\n        left: elRect.left - docRect.left - (offset.left || 0),\n        top: elRect.top - docRect.top - (offset.top || 0),\n    };\n}\nconst computeScrollPosition = () => ({\n    left: window.scrollX,\n    top: window.scrollY,\n});\nfunction scrollToPosition(position) {\n    let scrollToOptions;\n    if ('el' in position) {\n        const positionEl = position.el;\n        const isIdSelector = typeof positionEl === 'string' && positionEl.startsWith('#');\n        /**\n         * `id`s can accept pretty much any characters, including CSS combinators\n         * like `>` or `~`. It's still possible to retrieve elements using\n         * `document.getElementById('~')` but it needs to be escaped when using\n         * `document.querySelector('#\\\\~')` for it to be valid. The only\n         * requirements for `id`s are them to be unique on the page and to not be\n         * empty (`id=\"\"`). Because of that, when passing an id selector, it should\n         * be properly escaped for it to work with `querySelector`. We could check\n         * for the id selector to be simple (no CSS combinators `+ >~`) but that\n         * would make things inconsistent since they are valid characters for an\n         * `id` but would need to be escaped when using `querySelector`, breaking\n         * their usage and ending up in no selector returned. Selectors need to be\n         * escaped:\n         *\n         * - `#1-thing` becomes `#\\31 -thing`\n         * - `#with~symbols` becomes `#with\\\\~symbols`\n         *\n         * - More information about  the topic can be found at\n         *   https://mathiasbynens.be/notes/html5-id-class.\n         * - Practical example: https://mathiasbynens.be/demo/html5-id\n         */\n        if ((process.env.NODE_ENV !== 'production') && typeof position.el === 'string') {\n            if (!isIdSelector || !document.getElementById(position.el.slice(1))) {\n                try {\n                    const foundEl = document.querySelector(position.el);\n                    if (isIdSelector && foundEl) {\n                        warn(`The selector \"${position.el}\" should be passed as \"el: document.querySelector('${position.el}')\" because it starts with \"#\".`);\n                        // return to avoid other warnings\n                        return;\n                    }\n                }\n                catch (err) {\n                    warn(`The selector \"${position.el}\" is invalid. If you are using an id selector, make sure to escape it. You can find more information about escaping characters in selectors at https://mathiasbynens.be/notes/css-escapes or use CSS.escape (https://developer.mozilla.org/en-US/docs/Web/API/CSS/escape).`);\n                    // return to avoid other warnings\n                    return;\n                }\n            }\n        }\n        const el = typeof positionEl === 'string'\n            ? isIdSelector\n                ? document.getElementById(positionEl.slice(1))\n                : document.querySelector(positionEl)\n            : positionEl;\n        if (!el) {\n            (process.env.NODE_ENV !== 'production') &&\n                warn(`Couldn't find element using selector \"${position.el}\" returned by scrollBehavior.`);\n            return;\n        }\n        scrollToOptions = getElementPosition(el, position);\n    }\n    else {\n        scrollToOptions = position;\n    }\n    if ('scrollBehavior' in document.documentElement.style)\n        window.scrollTo(scrollToOptions);\n    else {\n        window.scrollTo(scrollToOptions.left != null ? scrollToOptions.left : window.scrollX, scrollToOptions.top != null ? scrollToOptions.top : window.scrollY);\n    }\n}\nfunction getScrollKey(path, delta) {\n    const position = history.state ? history.state.position - delta : -1;\n    return position + path;\n}\nconst scrollPositions = new Map();\nfunction saveScrollPosition(key, scrollPosition) {\n    scrollPositions.set(key, scrollPosition);\n}\nfunction getSavedScrollPosition(key) {\n    const scroll = scrollPositions.get(key);\n    // consume it so it's not used again\n    scrollPositions.delete(key);\n    return scroll;\n}\n// TODO: RFC about how to save scroll position\n/**\n * ScrollBehavior instance used by the router to compute and restore the scroll\n * position when navigating.\n */\n// export interface ScrollHandler<ScrollPositionEntry extends HistoryStateValue, ScrollPosition extends ScrollPositionEntry> {\n//   // returns a scroll position that can be saved in history\n//   compute(): ScrollPositionEntry\n//   // can take an extended ScrollPositionEntry\n//   scroll(position: ScrollPosition): void\n// }\n// export const scrollHandler: ScrollHandler<ScrollPosition> = {\n//   compute: computeScroll,\n//   scroll: scrollToPosition,\n// }\n\nlet createBaseLocation = () => location.protocol + '//' + location.host;\n/**\n * Creates a normalized history location from a window.location object\n * @param base - The base path\n * @param location - The window.location object\n */\nfunction createCurrentLocation(base, location) {\n    const { pathname, search, hash } = location;\n    // allows hash bases like #, /#, #/, #!, #!/, /#!/, or even /folder#end\n    const hashPos = base.indexOf('#');\n    if (hashPos > -1) {\n        let slicePos = hash.includes(base.slice(hashPos))\n            ? base.slice(hashPos).length\n            : 1;\n        let pathFromHash = hash.slice(slicePos);\n        // prepend the starting slash to hash so the url starts with /#\n        if (pathFromHash[0] !== '/')\n            pathFromHash = '/' + pathFromHash;\n        return stripBase(pathFromHash, '');\n    }\n    const path = stripBase(pathname, base);\n    return path + search + hash;\n}\nfunction useHistoryListeners(base, historyState, currentLocation, replace) {\n    let listeners = [];\n    let teardowns = [];\n    // TODO: should it be a stack? a Dict. Check if the popstate listener\n    // can trigger twice\n    let pauseState = null;\n    const popStateHandler = ({ state, }) => {\n        const to = createCurrentLocation(base, location);\n        const from = currentLocation.value;\n        const fromState = historyState.value;\n        let delta = 0;\n        if (state) {\n            currentLocation.value = to;\n            historyState.value = state;\n            // ignore the popstate and reset the pauseState\n            if (pauseState && pauseState === from) {\n                pauseState = null;\n                return;\n            }\n            delta = fromState ? state.position - fromState.position : 0;\n        }\n        else {\n            replace(to);\n        }\n        // Here we could also revert the navigation by calling history.go(-delta)\n        // this listener will have to be adapted to not trigger again and to wait for the url\n        // to be updated before triggering the listeners. Some kind of validation function would also\n        // need to be passed to the listeners so the navigation can be accepted\n        // call all listeners\n        listeners.forEach(listener => {\n            listener(currentLocation.value, from, {\n                delta,\n                type: NavigationType.pop,\n                direction: delta\n                    ? delta > 0\n                        ? NavigationDirection.forward\n                        : NavigationDirection.back\n                    : NavigationDirection.unknown,\n            });\n        });\n    };\n    function pauseListeners() {\n        pauseState = currentLocation.value;\n    }\n    function listen(callback) {\n        // set up the listener and prepare teardown callbacks\n        listeners.push(callback);\n        const teardown = () => {\n            const index = listeners.indexOf(callback);\n            if (index > -1)\n                listeners.splice(index, 1);\n        };\n        teardowns.push(teardown);\n        return teardown;\n    }\n    function beforeUnloadListener() {\n        const { history } = window;\n        if (!history.state)\n            return;\n        history.replaceState(assign({}, history.state, { scroll: computeScrollPosition() }), '');\n    }\n    function destroy() {\n        for (const teardown of teardowns)\n            teardown();\n        teardowns = [];\n        window.removeEventListener('popstate', popStateHandler);\n        window.removeEventListener('beforeunload', beforeUnloadListener);\n    }\n    // set up the listeners and prepare teardown callbacks\n    window.addEventListener('popstate', popStateHandler);\n    // TODO: could we use 'pagehide' or 'visibilitychange' instead?\n    // https://developer.chrome.com/blog/page-lifecycle-api/\n    window.addEventListener('beforeunload', beforeUnloadListener, {\n        passive: true,\n    });\n    return {\n        pauseListeners,\n        listen,\n        destroy,\n    };\n}\n/**\n * Creates a state object\n */\nfunction buildState(back, current, forward, replaced = false, computeScroll = false) {\n    return {\n        back,\n        current,\n        forward,\n        replaced,\n        position: window.history.length,\n        scroll: computeScroll ? computeScrollPosition() : null,\n    };\n}\nfunction useHistoryStateNavigation(base) {\n    const { history, location } = window;\n    // private variables\n    const currentLocation = {\n        value: createCurrentLocation(base, location),\n    };\n    const historyState = { value: history.state };\n    // build current history entry as this is a fresh navigation\n    if (!historyState.value) {\n        changeLocation(currentLocation.value, {\n            back: null,\n            current: currentLocation.value,\n            forward: null,\n            // the length is off by one, we need to decrease it\n            position: history.length - 1,\n            replaced: true,\n            // don't add a scroll as the user may have an anchor, and we want\n            // scrollBehavior to be triggered without a saved position\n            scroll: null,\n        }, true);\n    }\n    function changeLocation(to, state, replace) {\n        /**\n         * if a base tag is provided, and we are on a normal domain, we have to\n         * respect the provided `base` attribute because pushState() will use it and\n         * potentially erase anything before the `#` like at\n         * https://github.com/vuejs/router/issues/685 where a base of\n         * `/folder/#` but a base of `/` would erase the `/folder/` section. If\n         * there is no host, the `<base>` tag makes no sense and if there isn't a\n         * base tag we can just use everything after the `#`.\n         */\n        const hashIndex = base.indexOf('#');\n        const url = hashIndex > -1\n            ? (location.host && document.querySelector('base')\n                ? base\n                : base.slice(hashIndex)) + to\n            : createBaseLocation() + base + to;\n        try {\n            // BROWSER QUIRK\n            // NOTE: Safari throws a SecurityError when calling this function 100 times in 30 seconds\n            history[replace ? 'replaceState' : 'pushState'](state, '', url);\n            historyState.value = state;\n        }\n        catch (err) {\n            if ((process.env.NODE_ENV !== 'production')) {\n                warn('Error with push/replace State', err);\n            }\n            else {\n                console.error(err);\n            }\n            // Force the navigation, this also resets the call count\n            location[replace ? 'replace' : 'assign'](url);\n        }\n    }\n    function replace(to, data) {\n        const state = assign({}, history.state, buildState(historyState.value.back, \n        // keep back and forward entries but override current position\n        to, historyState.value.forward, true), data, { position: historyState.value.position });\n        changeLocation(to, state, true);\n        currentLocation.value = to;\n    }\n    function push(to, data) {\n        // Add to current entry the information of where we are going\n        // as well as saving the current position\n        const currentState = assign({}, \n        // use current history state to gracefully handle a wrong call to\n        // history.replaceState\n        // https://github.com/vuejs/router/issues/366\n        historyState.value, history.state, {\n            forward: to,\n            scroll: computeScrollPosition(),\n        });\n        if ((process.env.NODE_ENV !== 'production') && !history.state) {\n            warn(`history.state seems to have been manually replaced without preserving the necessary values. Make sure to preserve existing history state if you are manually calling history.replaceState:\\n\\n` +\n                `history.replaceState(history.state, '', url)\\n\\n` +\n                `You can find more information at https://router.vuejs.org/guide/migration/#Usage-of-history-state`);\n        }\n        changeLocation(currentState.current, currentState, true);\n        const state = assign({}, buildState(currentLocation.value, to, null), { position: currentState.position + 1 }, data);\n        changeLocation(to, state, false);\n        currentLocation.value = to;\n    }\n    return {\n        location: currentLocation,\n        state: historyState,\n        push,\n        replace,\n    };\n}\n/**\n * Creates an HTML5 history. Most common history for single page applications.\n *\n * @param base -\n */\nfunction createWebHistory(base) {\n    base = normalizeBase(base);\n    const historyNavigation = useHistoryStateNavigation(base);\n    const historyListeners = useHistoryListeners(base, historyNavigation.state, historyNavigation.location, historyNavigation.replace);\n    function go(delta, triggerListeners = true) {\n        if (!triggerListeners)\n            historyListeners.pauseListeners();\n        history.go(delta);\n    }\n    const routerHistory = assign({\n        // it's overridden right after\n        location: '',\n        base,\n        go,\n        createHref: createHref.bind(null, base),\n    }, historyNavigation, historyListeners);\n    Object.defineProperty(routerHistory, 'location', {\n        enumerable: true,\n        get: () => historyNavigation.location.value,\n    });\n    Object.defineProperty(routerHistory, 'state', {\n        enumerable: true,\n        get: () => historyNavigation.state.value,\n    });\n    return routerHistory;\n}\n\n/**\n * Creates an in-memory based history. The main purpose of this history is to handle SSR. It starts in a special location that is nowhere.\n * It's up to the user to replace that location with the starter location by either calling `router.push` or `router.replace`.\n *\n * @param base - Base applied to all urls, defaults to '/'\n * @returns a history object that can be passed to the router constructor\n */\nfunction createMemoryHistory(base = '') {\n    let listeners = [];\n    let queue = [[START, {}]];\n    let position = 0;\n    base = normalizeBase(base);\n    function setLocation(location, state = {}) {\n        position++;\n        if (position !== queue.length) {\n            // we are in the middle, we remove everything from here in the queue\n            queue.splice(position);\n        }\n        queue.push([location, state]);\n    }\n    function triggerListeners(to, from, { direction, delta }) {\n        const info = {\n            direction,\n            delta,\n            type: NavigationType.pop,\n        };\n        for (const callback of listeners) {\n            callback(to, from, info);\n        }\n    }\n    const routerHistory = {\n        // rewritten by Object.defineProperty\n        location: START,\n        // rewritten by Object.defineProperty\n        state: {},\n        base,\n        createHref: createHref.bind(null, base),\n        replace(to, state) {\n            // remove current entry and decrement position\n            queue.splice(position--, 1);\n            setLocation(to, state);\n        },\n        push(to, state) {\n            setLocation(to, state);\n        },\n        listen(callback) {\n            listeners.push(callback);\n            return () => {\n                const index = listeners.indexOf(callback);\n                if (index > -1)\n                    listeners.splice(index, 1);\n            };\n        },\n        destroy() {\n            listeners = [];\n            queue = [[START, {}]];\n            position = 0;\n        },\n        go(delta, shouldTrigger = true) {\n            const from = this.location;\n            const direction = \n            // we are considering delta === 0 going forward, but in abstract mode\n            // using 0 for the delta doesn't make sense like it does in html5 where\n            // it reloads the page\n            delta < 0 ? NavigationDirection.back : NavigationDirection.forward;\n            position = Math.max(0, Math.min(position + delta, queue.length - 1));\n            if (shouldTrigger) {\n                triggerListeners(this.location, from, {\n                    direction,\n                    delta,\n                });\n            }\n        },\n    };\n    Object.defineProperty(routerHistory, 'location', {\n        enumerable: true,\n        get: () => queue[position][0],\n    });\n    Object.defineProperty(routerHistory, 'state', {\n        enumerable: true,\n        get: () => queue[position][1],\n    });\n    return routerHistory;\n}\n\n/**\n * Creates a hash history. Useful for web applications with no host (e.g. `file://`) or when configuring a server to\n * handle any URL is not possible.\n *\n * @param base - optional base to provide. Defaults to `location.pathname + location.search` If there is a `<base>` tag\n * in the `head`, its value will be ignored in favor of this parameter **but note it affects all the history.pushState()\n * calls**, meaning that if you use a `<base>` tag, it's `href` value **has to match this parameter** (ignoring anything\n * after the `#`).\n *\n * @example\n * ```js\n * // at https://example.com/folder\n * createWebHashHistory() // gives a url of `https://example.com/folder#`\n * createWebHashHistory('/folder/') // gives a url of `https://example.com/folder/#`\n * // if the `#` is provided in the base, it won't be added by `createWebHashHistory`\n * createWebHashHistory('/folder/#/app/') // gives a url of `https://example.com/folder/#/app/`\n * // you should avoid doing this because it changes the original url and breaks copying urls\n * createWebHashHistory('/other-folder/') // gives a url of `https://example.com/other-folder/#`\n *\n * // at file:///usr/etc/folder/index.html\n * // for locations with no `host`, the base is ignored\n * createWebHashHistory('/iAmIgnored') // gives a url of `file:///usr/etc/folder/index.html#`\n * ```\n */\nfunction createWebHashHistory(base) {\n    // Make sure this implementation is fine in terms of encoding, specially for IE11\n    // for `file://`, directly use the pathname and ignore the base\n    // location.pathname contains an initial `/` even at the root: `https://example.com`\n    base = location.host ? base || location.pathname + location.search : '';\n    // allow the user to provide a `#` in the middle: `/base/#/app`\n    if (!base.includes('#'))\n        base += '#';\n    if ((process.env.NODE_ENV !== 'production') && !base.endsWith('#/') && !base.endsWith('#')) {\n        warn(`A hash base must end with a \"#\":\\n\"${base}\" should be \"${base.replace(/#.*$/, '#')}\".`);\n    }\n    return createWebHistory(base);\n}\n\nfunction isRouteLocation(route) {\n    return typeof route === 'string' || (route && typeof route === 'object');\n}\nfunction isRouteName(name) {\n    return typeof name === 'string' || typeof name === 'symbol';\n}\n\nconst NavigationFailureSymbol = Symbol((process.env.NODE_ENV !== 'production') ? 'navigation failure' : '');\n/**\n * Enumeration with all possible types for navigation failures. Can be passed to\n * {@link isNavigationFailure} to check for specific failures.\n */\nvar NavigationFailureType;\n(function (NavigationFailureType) {\n    /**\n     * An aborted navigation is a navigation that failed because a navigation\n     * guard returned `false` or called `next(false)`\n     */\n    NavigationFailureType[NavigationFailureType[\"aborted\"] = 4] = \"aborted\";\n    /**\n     * A cancelled navigation is a navigation that failed because a more recent\n     * navigation finished started (not necessarily finished).\n     */\n    NavigationFailureType[NavigationFailureType[\"cancelled\"] = 8] = \"cancelled\";\n    /**\n     * A duplicated navigation is a navigation that failed because it was\n     * initiated while already being at the exact same location.\n     */\n    NavigationFailureType[NavigationFailureType[\"duplicated\"] = 16] = \"duplicated\";\n})(NavigationFailureType || (NavigationFailureType = {}));\n// DEV only debug messages\nconst ErrorTypeMessages = {\n    [1 /* ErrorTypes.MATCHER_NOT_FOUND */]({ location, currentLocation }) {\n        return `No match for\\n ${JSON.stringify(location)}${currentLocation\n            ? '\\nwhile being at\\n' + JSON.stringify(currentLocation)\n            : ''}`;\n    },\n    [2 /* ErrorTypes.NAVIGATION_GUARD_REDIRECT */]({ from, to, }) {\n        return `Redirected from \"${from.fullPath}\" to \"${stringifyRoute(to)}\" via a navigation guard.`;\n    },\n    [4 /* ErrorTypes.NAVIGATION_ABORTED */]({ from, to }) {\n        return `Navigation aborted from \"${from.fullPath}\" to \"${to.fullPath}\" via a navigation guard.`;\n    },\n    [8 /* ErrorTypes.NAVIGATION_CANCELLED */]({ from, to }) {\n        return `Navigation cancelled from \"${from.fullPath}\" to \"${to.fullPath}\" with a new navigation.`;\n    },\n    [16 /* ErrorTypes.NAVIGATION_DUPLICATED */]({ from, to }) {\n        return `Avoided redundant navigation to current location: \"${from.fullPath}\".`;\n    },\n};\n/**\n * Creates a typed NavigationFailure object.\n * @internal\n * @param type - NavigationFailureType\n * @param params - { from, to }\n */\nfunction createRouterError(type, params) {\n    // keep full error messages in cjs versions\n    if ((process.env.NODE_ENV !== 'production') || !true) {\n        return assign(new Error(ErrorTypeMessages[type](params)), {\n            type,\n            [NavigationFailureSymbol]: true,\n        }, params);\n    }\n    else {\n        return assign(new Error(), {\n            type,\n            [NavigationFailureSymbol]: true,\n        }, params);\n    }\n}\nfunction isNavigationFailure(error, type) {\n    return (error instanceof Error &&\n        NavigationFailureSymbol in error &&\n        (type == null || !!(error.type & type)));\n}\nconst propertiesToLog = ['params', 'query', 'hash'];\nfunction stringifyRoute(to) {\n    if (typeof to === 'string')\n        return to;\n    if (to.path != null)\n        return to.path;\n    const location = {};\n    for (const key of propertiesToLog) {\n        if (key in to)\n            location[key] = to[key];\n    }\n    return JSON.stringify(location, null, 2);\n}\n\n// default pattern for a param: non-greedy everything but /\nconst BASE_PARAM_PATTERN = '[^/]+?';\nconst BASE_PATH_PARSER_OPTIONS = {\n    sensitive: false,\n    strict: false,\n    start: true,\n    end: true,\n};\n// Special Regex characters that must be escaped in static tokens\nconst REGEX_CHARS_RE = /[.+*?^${}()[\\]/\\\\]/g;\n/**\n * Creates a path parser from an array of Segments (a segment is an array of Tokens)\n *\n * @param segments - array of segments returned by tokenizePath\n * @param extraOptions - optional options for the regexp\n * @returns a PathParser\n */\nfunction tokensToParser(segments, extraOptions) {\n    const options = assign({}, BASE_PATH_PARSER_OPTIONS, extraOptions);\n    // the amount of scores is the same as the length of segments except for the root segment \"/\"\n    const score = [];\n    // the regexp as a string\n    let pattern = options.start ? '^' : '';\n    // extracted keys\n    const keys = [];\n    for (const segment of segments) {\n        // the root segment needs special treatment\n        const segmentScores = segment.length ? [] : [90 /* PathScore.Root */];\n        // allow trailing slash\n        if (options.strict && !segment.length)\n            pattern += '/';\n        for (let tokenIndex = 0; tokenIndex < segment.length; tokenIndex++) {\n            const token = segment[tokenIndex];\n            // resets the score if we are inside a sub-segment /:a-other-:b\n            let subSegmentScore = 40 /* PathScore.Segment */ +\n                (options.sensitive ? 0.25 /* PathScore.BonusCaseSensitive */ : 0);\n            if (token.type === 0 /* TokenType.Static */) {\n                // prepend the slash if we are starting a new segment\n                if (!tokenIndex)\n                    pattern += '/';\n                pattern += token.value.replace(REGEX_CHARS_RE, '\\\\$&');\n                subSegmentScore += 40 /* PathScore.Static */;\n            }\n            else if (token.type === 1 /* TokenType.Param */) {\n                const { value, repeatable, optional, regexp } = token;\n                keys.push({\n                    name: value,\n                    repeatable,\n                    optional,\n                });\n                const re = regexp ? regexp : BASE_PARAM_PATTERN;\n                // the user provided a custom regexp /:id(\\\\d+)\n                if (re !== BASE_PARAM_PATTERN) {\n                    subSegmentScore += 10 /* PathScore.BonusCustomRegExp */;\n                    // make sure the regexp is valid before using it\n                    try {\n                        new RegExp(`(${re})`);\n                    }\n                    catch (err) {\n                        throw new Error(`Invalid custom RegExp for param \"${value}\" (${re}): ` +\n                            err.message);\n                    }\n                }\n                // when we repeat we must take care of the repeating leading slash\n                let subPattern = repeatable ? `((?:${re})(?:/(?:${re}))*)` : `(${re})`;\n                // prepend the slash if we are starting a new segment\n                if (!tokenIndex)\n                    subPattern =\n                        // avoid an optional / if there are more segments e.g. /:p?-static\n                        // or /:p?-:p2\n                        optional && segment.length < 2\n                            ? `(?:/${subPattern})`\n                            : '/' + subPattern;\n                if (optional)\n                    subPattern += '?';\n                pattern += subPattern;\n                subSegmentScore += 20 /* PathScore.Dynamic */;\n                if (optional)\n                    subSegmentScore += -8 /* PathScore.BonusOptional */;\n                if (repeatable)\n                    subSegmentScore += -20 /* PathScore.BonusRepeatable */;\n                if (re === '.*')\n                    subSegmentScore += -50 /* PathScore.BonusWildcard */;\n            }\n            segmentScores.push(subSegmentScore);\n        }\n        // an empty array like /home/ -> [[{home}], []]\n        // if (!segment.length) pattern += '/'\n        score.push(segmentScores);\n    }\n    // only apply the strict bonus to the last score\n    if (options.strict && options.end) {\n        const i = score.length - 1;\n        score[i][score[i].length - 1] += 0.7000000000000001 /* PathScore.BonusStrict */;\n    }\n    // TODO: dev only warn double trailing slash\n    if (!options.strict)\n        pattern += '/?';\n    if (options.end)\n        pattern += '$';\n    // allow paths like /dynamic to only match dynamic or dynamic/... but not dynamic_something_else\n    else if (options.strict && !pattern.endsWith('/'))\n        pattern += '(?:/|$)';\n    const re = new RegExp(pattern, options.sensitive ? '' : 'i');\n    function parse(path) {\n        const match = path.match(re);\n        const params = {};\n        if (!match)\n            return null;\n        for (let i = 1; i < match.length; i++) {\n            const value = match[i] || '';\n            const key = keys[i - 1];\n            params[key.name] = value && key.repeatable ? value.split('/') : value;\n        }\n        return params;\n    }\n    function stringify(params) {\n        let path = '';\n        // for optional parameters to allow to be empty\n        let avoidDuplicatedSlash = false;\n        for (const segment of segments) {\n            if (!avoidDuplicatedSlash || !path.endsWith('/'))\n                path += '/';\n            avoidDuplicatedSlash = false;\n            for (const token of segment) {\n                if (token.type === 0 /* TokenType.Static */) {\n                    path += token.value;\n                }\n                else if (token.type === 1 /* TokenType.Param */) {\n                    const { value, repeatable, optional } = token;\n                    const param = value in params ? params[value] : '';\n                    if (isArray(param) && !repeatable) {\n                        throw new Error(`Provided param \"${value}\" is an array but it is not repeatable (* or + modifiers)`);\n                    }\n                    const text = isArray(param)\n                        ? param.join('/')\n                        : param;\n                    if (!text) {\n                        if (optional) {\n                            // if we have more than one optional param like /:a?-static we don't need to care about the optional param\n                            if (segment.length < 2) {\n                                // remove the last slash as we could be at the end\n                                if (path.endsWith('/'))\n                                    path = path.slice(0, -1);\n                                // do not append a slash on the next iteration\n                                else\n                                    avoidDuplicatedSlash = true;\n                            }\n                        }\n                        else\n                            throw new Error(`Missing required param \"${value}\"`);\n                    }\n                    path += text;\n                }\n            }\n        }\n        // avoid empty path when we have multiple optional params\n        return path || '/';\n    }\n    return {\n        re,\n        score,\n        keys,\n        parse,\n        stringify,\n    };\n}\n/**\n * Compares an array of numbers as used in PathParser.score and returns a\n * number. This function can be used to `sort` an array\n *\n * @param a - first array of numbers\n * @param b - second array of numbers\n * @returns 0 if both are equal, < 0 if a should be sorted first, > 0 if b\n * should be sorted first\n */\nfunction compareScoreArray(a, b) {\n    let i = 0;\n    while (i < a.length && i < b.length) {\n        const diff = b[i] - a[i];\n        // only keep going if diff === 0\n        if (diff)\n            return diff;\n        i++;\n    }\n    // if the last subsegment was Static, the shorter segments should be sorted first\n    // otherwise sort the longest segment first\n    if (a.length < b.length) {\n        return a.length === 1 && a[0] === 40 /* PathScore.Static */ + 40 /* PathScore.Segment */\n            ? -1\n            : 1;\n    }\n    else if (a.length > b.length) {\n        return b.length === 1 && b[0] === 40 /* PathScore.Static */ + 40 /* PathScore.Segment */\n            ? 1\n            : -1;\n    }\n    return 0;\n}\n/**\n * Compare function that can be used with `sort` to sort an array of PathParser\n *\n * @param a - first PathParser\n * @param b - second PathParser\n * @returns 0 if both are equal, < 0 if a should be sorted first, > 0 if b\n */\nfunction comparePathParserScore(a, b) {\n    let i = 0;\n    const aScore = a.score;\n    const bScore = b.score;\n    while (i < aScore.length && i < bScore.length) {\n        const comp = compareScoreArray(aScore[i], bScore[i]);\n        // do not return if both are equal\n        if (comp)\n            return comp;\n        i++;\n    }\n    if (Math.abs(bScore.length - aScore.length) === 1) {\n        if (isLastScoreNegative(aScore))\n            return 1;\n        if (isLastScoreNegative(bScore))\n            return -1;\n    }\n    // if a and b share the same score entries but b has more, sort b first\n    return bScore.length - aScore.length;\n    // this is the ternary version\n    // return aScore.length < bScore.length\n    //   ? 1\n    //   : aScore.length > bScore.length\n    //   ? -1\n    //   : 0\n}\n/**\n * This allows detecting splats at the end of a path: /home/:id(.*)*\n *\n * @param score - score to check\n * @returns true if the last entry is negative\n */\nfunction isLastScoreNegative(score) {\n    const last = score[score.length - 1];\n    return score.length > 0 && last[last.length - 1] < 0;\n}\n\nconst ROOT_TOKEN = {\n    type: 0 /* TokenType.Static */,\n    value: '',\n};\nconst VALID_PARAM_RE = /[a-zA-Z0-9_]/;\n// After some profiling, the cache seems to be unnecessary because tokenizePath\n// (the slowest part of adding a route) is very fast\n// const tokenCache = new Map<string, Token[][]>()\nfunction tokenizePath(path) {\n    if (!path)\n        return [[]];\n    if (path === '/')\n        return [[ROOT_TOKEN]];\n    if (!path.startsWith('/')) {\n        throw new Error((process.env.NODE_ENV !== 'production')\n            ? `Route paths should start with a \"/\": \"${path}\" should be \"/${path}\".`\n            : `Invalid path \"${path}\"`);\n    }\n    // if (tokenCache.has(path)) return tokenCache.get(path)!\n    function crash(message) {\n        throw new Error(`ERR (${state})/\"${buffer}\": ${message}`);\n    }\n    let state = 0 /* TokenizerState.Static */;\n    let previousState = state;\n    const tokens = [];\n    // the segment will always be valid because we get into the initial state\n    // with the leading /\n    let segment;\n    function finalizeSegment() {\n        if (segment)\n            tokens.push(segment);\n        segment = [];\n    }\n    // index on the path\n    let i = 0;\n    // char at index\n    let char;\n    // buffer of the value read\n    let buffer = '';\n    // custom regexp for a param\n    let customRe = '';\n    function consumeBuffer() {\n        if (!buffer)\n            return;\n        if (state === 0 /* TokenizerState.Static */) {\n            segment.push({\n                type: 0 /* TokenType.Static */,\n                value: buffer,\n            });\n        }\n        else if (state === 1 /* TokenizerState.Param */ ||\n            state === 2 /* TokenizerState.ParamRegExp */ ||\n            state === 3 /* TokenizerState.ParamRegExpEnd */) {\n            if (segment.length > 1 && (char === '*' || char === '+'))\n                crash(`A repeatable param (${buffer}) must be alone in its segment. eg: '/:ids+.`);\n            segment.push({\n                type: 1 /* TokenType.Param */,\n                value: buffer,\n                regexp: customRe,\n                repeatable: char === '*' || char === '+',\n                optional: char === '*' || char === '?',\n            });\n        }\n        else {\n            crash('Invalid state to consume buffer');\n        }\n        buffer = '';\n    }\n    function addCharToBuffer() {\n        buffer += char;\n    }\n    while (i < path.length) {\n        char = path[i++];\n        if (char === '\\\\' && state !== 2 /* TokenizerState.ParamRegExp */) {\n            previousState = state;\n            state = 4 /* TokenizerState.EscapeNext */;\n            continue;\n        }\n        switch (state) {\n            case 0 /* TokenizerState.Static */:\n                if (char === '/') {\n                    if (buffer) {\n                        consumeBuffer();\n                    }\n                    finalizeSegment();\n                }\n                else if (char === ':') {\n                    consumeBuffer();\n                    state = 1 /* TokenizerState.Param */;\n                }\n                else {\n                    addCharToBuffer();\n                }\n                break;\n            case 4 /* TokenizerState.EscapeNext */:\n                addCharToBuffer();\n                state = previousState;\n                break;\n            case 1 /* TokenizerState.Param */:\n                if (char === '(') {\n                    state = 2 /* TokenizerState.ParamRegExp */;\n                }\n                else if (VALID_PARAM_RE.test(char)) {\n                    addCharToBuffer();\n                }\n                else {\n                    consumeBuffer();\n                    state = 0 /* TokenizerState.Static */;\n                    // go back one character if we were not modifying\n                    if (char !== '*' && char !== '?' && char !== '+')\n                        i--;\n                }\n                break;\n            case 2 /* TokenizerState.ParamRegExp */:\n                // TODO: is it worth handling nested regexp? like :p(?:prefix_([^/]+)_suffix)\n                // it already works by escaping the closing )\n                // https://paths.esm.dev/?p=AAMeJbiAwQEcDKbAoAAkP60PG2R6QAvgNaA6AFACM2ABuQBB#\n                // is this really something people need since you can also write\n                // /prefix_:p()_suffix\n                if (char === ')') {\n                    // handle the escaped )\n                    if (customRe[customRe.length - 1] == '\\\\')\n                        customRe = customRe.slice(0, -1) + char;\n                    else\n                        state = 3 /* TokenizerState.ParamRegExpEnd */;\n                }\n                else {\n                    customRe += char;\n                }\n                break;\n            case 3 /* TokenizerState.ParamRegExpEnd */:\n                // same as finalizing a param\n                consumeBuffer();\n                state = 0 /* TokenizerState.Static */;\n                // go back one character if we were not modifying\n                if (char !== '*' && char !== '?' && char !== '+')\n                    i--;\n                customRe = '';\n                break;\n            default:\n                crash('Unknown state');\n                break;\n        }\n    }\n    if (state === 2 /* TokenizerState.ParamRegExp */)\n        crash(`Unfinished custom RegExp for param \"${buffer}\"`);\n    consumeBuffer();\n    finalizeSegment();\n    // tokenCache.set(path, tokens)\n    return tokens;\n}\n\nfunction createRouteRecordMatcher(record, parent, options) {\n    const parser = tokensToParser(tokenizePath(record.path), options);\n    // warn against params with the same name\n    if ((process.env.NODE_ENV !== 'production')) {\n        const existingKeys = new Set();\n        for (const key of parser.keys) {\n            if (existingKeys.has(key.name))\n                warn(`Found duplicated params with name \"${key.name}\" for path \"${record.path}\". Only the last one will be available on \"$route.params\".`);\n            existingKeys.add(key.name);\n        }\n    }\n    const matcher = assign(parser, {\n        record,\n        parent,\n        // these needs to be populated by the parent\n        children: [],\n        alias: [],\n    });\n    if (parent) {\n        // both are aliases or both are not aliases\n        // we don't want to mix them because the order is used when\n        // passing originalRecord in Matcher.addRoute\n        if (!matcher.record.aliasOf === !parent.record.aliasOf)\n            parent.children.push(matcher);\n    }\n    return matcher;\n}\n\n/**\n * Creates a Router Matcher.\n *\n * @internal\n * @param routes - array of initial routes\n * @param globalOptions - global route options\n */\nfunction createRouterMatcher(routes, globalOptions) {\n    // normalized ordered array of matchers\n    const matchers = [];\n    const matcherMap = new Map();\n    globalOptions = mergeOptions({ strict: false, end: true, sensitive: false }, globalOptions);\n    function getRecordMatcher(name) {\n        return matcherMap.get(name);\n    }\n    function addRoute(record, parent, originalRecord) {\n        // used later on to remove by name\n        const isRootAdd = !originalRecord;\n        const mainNormalizedRecord = normalizeRouteRecord(record);\n        if ((process.env.NODE_ENV !== 'production')) {\n            checkChildMissingNameWithEmptyPath(mainNormalizedRecord, parent);\n        }\n        // we might be the child of an alias\n        mainNormalizedRecord.aliasOf = originalRecord && originalRecord.record;\n        const options = mergeOptions(globalOptions, record);\n        // generate an array of records to correctly handle aliases\n        const normalizedRecords = [mainNormalizedRecord];\n        if ('alias' in record) {\n            const aliases = typeof record.alias === 'string' ? [record.alias] : record.alias;\n            for (const alias of aliases) {\n                normalizedRecords.push(\n                // we need to normalize again to ensure the `mods` property\n                // being non enumerable\n                normalizeRouteRecord(assign({}, mainNormalizedRecord, {\n                    // this allows us to hold a copy of the `components` option\n                    // so that async components cache is hold on the original record\n                    components: originalRecord\n                        ? originalRecord.record.components\n                        : mainNormalizedRecord.components,\n                    path: alias,\n                    // we might be the child of an alias\n                    aliasOf: originalRecord\n                        ? originalRecord.record\n                        : mainNormalizedRecord,\n                    // the aliases are always of the same kind as the original since they\n                    // are defined on the same record\n                })));\n            }\n        }\n        let matcher;\n        let originalMatcher;\n        for (const normalizedRecord of normalizedRecords) {\n            const { path } = normalizedRecord;\n            // Build up the path for nested routes if the child isn't an absolute\n            // route. Only add the / delimiter if the child path isn't empty and if the\n            // parent path doesn't have a trailing slash\n            if (parent && path[0] !== '/') {\n                const parentPath = parent.record.path;\n                const connectingSlash = parentPath[parentPath.length - 1] === '/' ? '' : '/';\n                normalizedRecord.path =\n                    parent.record.path + (path && connectingSlash + path);\n            }\n            if ((process.env.NODE_ENV !== 'production') && normalizedRecord.path === '*') {\n                throw new Error('Catch all routes (\"*\") must now be defined using a param with a custom regexp.\\n' +\n                    'See more at https://router.vuejs.org/guide/migration/#Removed-star-or-catch-all-routes.');\n            }\n            // create the object beforehand, so it can be passed to children\n            matcher = createRouteRecordMatcher(normalizedRecord, parent, options);\n            if ((process.env.NODE_ENV !== 'production') && parent && path[0] === '/')\n                checkMissingParamsInAbsolutePath(matcher, parent);\n            // if we are an alias we must tell the original record that we exist,\n            // so we can be removed\n            if (originalRecord) {\n                originalRecord.alias.push(matcher);\n                if ((process.env.NODE_ENV !== 'production')) {\n                    checkSameParams(originalRecord, matcher);\n                }\n            }\n            else {\n                // otherwise, the first record is the original and others are aliases\n                originalMatcher = originalMatcher || matcher;\n                if (originalMatcher !== matcher)\n                    originalMatcher.alias.push(matcher);\n                // remove the route if named and only for the top record (avoid in nested calls)\n                // this works because the original record is the first one\n                if (isRootAdd && record.name && !isAliasRecord(matcher)) {\n                    if ((process.env.NODE_ENV !== 'production')) {\n                        checkSameNameAsAncestor(record, parent);\n                    }\n                    removeRoute(record.name);\n                }\n            }\n            // Avoid adding a record that doesn't display anything. This allows passing through records without a component to\n            // not be reached and pass through the catch all route\n            if (isMatchable(matcher)) {\n                insertMatcher(matcher);\n            }\n            if (mainNormalizedRecord.children) {\n                const children = mainNormalizedRecord.children;\n                for (let i = 0; i < children.length; i++) {\n                    addRoute(children[i], matcher, originalRecord && originalRecord.children[i]);\n                }\n            }\n            // if there was no original record, then the first one was not an alias and all\n            // other aliases (if any) need to reference this record when adding children\n            originalRecord = originalRecord || matcher;\n            // TODO: add normalized records for more flexibility\n            // if (parent && isAliasRecord(originalRecord)) {\n            //   parent.children.push(originalRecord)\n            // }\n        }\n        return originalMatcher\n            ? () => {\n                // since other matchers are aliases, they should be removed by the original matcher\n                removeRoute(originalMatcher);\n            }\n            : noop;\n    }\n    function removeRoute(matcherRef) {\n        if (isRouteName(matcherRef)) {\n            const matcher = matcherMap.get(matcherRef);\n            if (matcher) {\n                matcherMap.delete(matcherRef);\n                matchers.splice(matchers.indexOf(matcher), 1);\n                matcher.children.forEach(removeRoute);\n                matcher.alias.forEach(removeRoute);\n            }\n        }\n        else {\n            const index = matchers.indexOf(matcherRef);\n            if (index > -1) {\n                matchers.splice(index, 1);\n                if (matcherRef.record.name)\n                    matcherMap.delete(matcherRef.record.name);\n                matcherRef.children.forEach(removeRoute);\n                matcherRef.alias.forEach(removeRoute);\n            }\n        }\n    }\n    function getRoutes() {\n        return matchers;\n    }\n    function insertMatcher(matcher) {\n        const index = findInsertionIndex(matcher, matchers);\n        matchers.splice(index, 0, matcher);\n        // only add the original record to the name map\n        if (matcher.record.name && !isAliasRecord(matcher))\n            matcherMap.set(matcher.record.name, matcher);\n    }\n    function resolve(location, currentLocation) {\n        let matcher;\n        let params = {};\n        let path;\n        let name;\n        if ('name' in location && location.name) {\n            matcher = matcherMap.get(location.name);\n            if (!matcher)\n                throw createRouterError(1 /* ErrorTypes.MATCHER_NOT_FOUND */, {\n                    location,\n                });\n            // warn if the user is passing invalid params so they can debug it better when they get removed\n            if ((process.env.NODE_ENV !== 'production')) {\n                const invalidParams = Object.keys(location.params || {}).filter(paramName => !matcher.keys.find(k => k.name === paramName));\n                if (invalidParams.length) {\n                    warn(`Discarded invalid param(s) \"${invalidParams.join('\", \"')}\" when navigating. See https://github.com/vuejs/router/blob/main/packages/router/CHANGELOG.md#414-2022-08-22 for more details.`);\n                }\n            }\n            name = matcher.record.name;\n            params = assign(\n            // paramsFromLocation is a new object\n            paramsFromLocation(currentLocation.params, \n            // only keep params that exist in the resolved location\n            // only keep optional params coming from a parent record\n            matcher.keys\n                .filter(k => !k.optional)\n                .concat(matcher.parent ? matcher.parent.keys.filter(k => k.optional) : [])\n                .map(k => k.name)), \n            // discard any existing params in the current location that do not exist here\n            // #1497 this ensures better active/exact matching\n            location.params &&\n                paramsFromLocation(location.params, matcher.keys.map(k => k.name)));\n            // throws if cannot be stringified\n            path = matcher.stringify(params);\n        }\n        else if (location.path != null) {\n            // no need to resolve the path with the matcher as it was provided\n            // this also allows the user to control the encoding\n            path = location.path;\n            if ((process.env.NODE_ENV !== 'production') && !path.startsWith('/')) {\n                warn(`The Matcher cannot resolve relative paths but received \"${path}\". Unless you directly called \\`matcher.resolve(\"${path}\")\\`, this is probably a bug in vue-router. Please open an issue at https://github.com/vuejs/router/issues/new/choose.`);\n            }\n            matcher = matchers.find(m => m.re.test(path));\n            // matcher should have a value after the loop\n            if (matcher) {\n                // we know the matcher works because we tested the regexp\n                params = matcher.parse(path);\n                name = matcher.record.name;\n            }\n            // location is a relative path\n        }\n        else {\n            // match by name or path of current route\n            matcher = currentLocation.name\n                ? matcherMap.get(currentLocation.name)\n                : matchers.find(m => m.re.test(currentLocation.path));\n            if (!matcher)\n                throw createRouterError(1 /* ErrorTypes.MATCHER_NOT_FOUND */, {\n                    location,\n                    currentLocation,\n                });\n            name = matcher.record.name;\n            // since we are navigating to the same location, we don't need to pick the\n            // params like when `name` is provided\n            params = assign({}, currentLocation.params, location.params);\n            path = matcher.stringify(params);\n        }\n        const matched = [];\n        let parentMatcher = matcher;\n        while (parentMatcher) {\n            // reversed order so parents are at the beginning\n            matched.unshift(parentMatcher.record);\n            parentMatcher = parentMatcher.parent;\n        }\n        return {\n            name,\n            path,\n            params,\n            matched,\n            meta: mergeMetaFields(matched),\n        };\n    }\n    // add initial routes\n    routes.forEach(route => addRoute(route));\n    function clearRoutes() {\n        matchers.length = 0;\n        matcherMap.clear();\n    }\n    return {\n        addRoute,\n        resolve,\n        removeRoute,\n        clearRoutes,\n        getRoutes,\n        getRecordMatcher,\n    };\n}\nfunction paramsFromLocation(params, keys) {\n    const newParams = {};\n    for (const key of keys) {\n        if (key in params)\n            newParams[key] = params[key];\n    }\n    return newParams;\n}\n/**\n * Normalizes a RouteRecordRaw. Creates a copy\n *\n * @param record\n * @returns the normalized version\n */\nfunction normalizeRouteRecord(record) {\n    const normalized = {\n        path: record.path,\n        redirect: record.redirect,\n        name: record.name,\n        meta: record.meta || {},\n        aliasOf: record.aliasOf,\n        beforeEnter: record.beforeEnter,\n        props: normalizeRecordProps(record),\n        children: record.children || [],\n        instances: {},\n        leaveGuards: new Set(),\n        updateGuards: new Set(),\n        enterCallbacks: {},\n        // must be declared afterwards\n        // mods: {},\n        components: 'components' in record\n            ? record.components || null\n            : record.component && { default: record.component },\n    };\n    // mods contain modules and shouldn't be copied,\n    // logged or anything. It's just used for internal\n    // advanced use cases like data loaders\n    Object.defineProperty(normalized, 'mods', {\n        value: {},\n    });\n    return normalized;\n}\n/**\n * Normalize the optional `props` in a record to always be an object similar to\n * components. Also accept a boolean for components.\n * @param record\n */\nfunction normalizeRecordProps(record) {\n    const propsObject = {};\n    // props does not exist on redirect records, but we can set false directly\n    const props = record.props || false;\n    if ('component' in record) {\n        propsObject.default = props;\n    }\n    else {\n        // NOTE: we could also allow a function to be applied to every component.\n        // Would need user feedback for use cases\n        for (const name in record.components)\n            propsObject[name] = typeof props === 'object' ? props[name] : props;\n    }\n    return propsObject;\n}\n/**\n * Checks if a record or any of its parent is an alias\n * @param record\n */\nfunction isAliasRecord(record) {\n    while (record) {\n        if (record.record.aliasOf)\n            return true;\n        record = record.parent;\n    }\n    return false;\n}\n/**\n * Merge meta fields of an array of records\n *\n * @param matched - array of matched records\n */\nfunction mergeMetaFields(matched) {\n    return matched.reduce((meta, record) => assign(meta, record.meta), {});\n}\nfunction mergeOptions(defaults, partialOptions) {\n    const options = {};\n    for (const key in defaults) {\n        options[key] = key in partialOptions ? partialOptions[key] : defaults[key];\n    }\n    return options;\n}\nfunction isSameParam(a, b) {\n    return (a.name === b.name &&\n        a.optional === b.optional &&\n        a.repeatable === b.repeatable);\n}\n/**\n * Check if a path and its alias have the same required params\n *\n * @param a - original record\n * @param b - alias record\n */\nfunction checkSameParams(a, b) {\n    for (const key of a.keys) {\n        if (!key.optional && !b.keys.find(isSameParam.bind(null, key)))\n            return warn(`Alias \"${b.record.path}\" and the original record: \"${a.record.path}\" must have the exact same param named \"${key.name}\"`);\n    }\n    for (const key of b.keys) {\n        if (!key.optional && !a.keys.find(isSameParam.bind(null, key)))\n            return warn(`Alias \"${b.record.path}\" and the original record: \"${a.record.path}\" must have the exact same param named \"${key.name}\"`);\n    }\n}\n/**\n * A route with a name and a child with an empty path without a name should warn when adding the route\n *\n * @param mainNormalizedRecord - RouteRecordNormalized\n * @param parent - RouteRecordMatcher\n */\nfunction checkChildMissingNameWithEmptyPath(mainNormalizedRecord, parent) {\n    if (parent &&\n        parent.record.name &&\n        !mainNormalizedRecord.name &&\n        !mainNormalizedRecord.path) {\n        warn(`The route named \"${String(parent.record.name)}\" has a child without a name and an empty path. Using that name won't render the empty path child so you probably want to move the name to the child instead. If this is intentional, add a name to the child route to remove the warning.`);\n    }\n}\nfunction checkSameNameAsAncestor(record, parent) {\n    for (let ancestor = parent; ancestor; ancestor = ancestor.parent) {\n        if (ancestor.record.name === record.name) {\n            throw new Error(`A route named \"${String(record.name)}\" has been added as a ${parent === ancestor ? 'child' : 'descendant'} of a route with the same name. Route names must be unique and a nested route cannot use the same name as an ancestor.`);\n        }\n    }\n}\nfunction checkMissingParamsInAbsolutePath(record, parent) {\n    for (const key of parent.keys) {\n        if (!record.keys.find(isSameParam.bind(null, key)))\n            return warn(`Absolute path \"${record.record.path}\" must have the exact same param named \"${key.name}\" as its parent \"${parent.record.path}\".`);\n    }\n}\n/**\n * Performs a binary search to find the correct insertion index for a new matcher.\n *\n * Matchers are primarily sorted by their score. If scores are tied then we also consider parent/child relationships,\n * with descendants coming before ancestors. If there's still a tie, new routes are inserted after existing routes.\n *\n * @param matcher - new matcher to be inserted\n * @param matchers - existing matchers\n */\nfunction findInsertionIndex(matcher, matchers) {\n    // First phase: binary search based on score\n    let lower = 0;\n    let upper = matchers.length;\n    while (lower !== upper) {\n        const mid = (lower + upper) >> 1;\n        const sortOrder = comparePathParserScore(matcher, matchers[mid]);\n        if (sortOrder < 0) {\n            upper = mid;\n        }\n        else {\n            lower = mid + 1;\n        }\n    }\n    // Second phase: check for an ancestor with the same score\n    const insertionAncestor = getInsertionAncestor(matcher);\n    if (insertionAncestor) {\n        upper = matchers.lastIndexOf(insertionAncestor, upper - 1);\n        if ((process.env.NODE_ENV !== 'production') && upper < 0) {\n            // This should never happen\n            warn(`Finding ancestor route \"${insertionAncestor.record.path}\" failed for \"${matcher.record.path}\"`);\n        }\n    }\n    return upper;\n}\nfunction getInsertionAncestor(matcher) {\n    let ancestor = matcher;\n    while ((ancestor = ancestor.parent)) {\n        if (isMatchable(ancestor) &&\n            comparePathParserScore(matcher, ancestor) === 0) {\n            return ancestor;\n        }\n    }\n    return;\n}\n/**\n * Checks if a matcher can be reachable. This means if it's possible to reach it as a route. For example, routes without\n * a component, or name, or redirect, are just used to group other routes.\n * @param matcher\n * @param matcher.record record of the matcher\n * @returns\n */\nfunction isMatchable({ record }) {\n    return !!(record.name ||\n        (record.components && Object.keys(record.components).length) ||\n        record.redirect);\n}\n\n/**\n * Transforms a queryString into a {@link LocationQuery} object. Accept both, a\n * version with the leading `?` and without Should work as URLSearchParams\n\n * @internal\n *\n * @param search - search string to parse\n * @returns a query object\n */\nfunction parseQuery(search) {\n    const query = {};\n    // avoid creating an object with an empty key and empty value\n    // because of split('&')\n    if (search === '' || search === '?')\n        return query;\n    const hasLeadingIM = search[0] === '?';\n    const searchParams = (hasLeadingIM ? search.slice(1) : search).split('&');\n    for (let i = 0; i < searchParams.length; ++i) {\n        // pre decode the + into space\n        const searchParam = searchParams[i].replace(PLUS_RE, ' ');\n        // allow the = character\n        const eqPos = searchParam.indexOf('=');\n        const key = decode(eqPos < 0 ? searchParam : searchParam.slice(0, eqPos));\n        const value = eqPos < 0 ? null : decode(searchParam.slice(eqPos + 1));\n        if (key in query) {\n            // an extra variable for ts types\n            let currentValue = query[key];\n            if (!isArray(currentValue)) {\n                currentValue = query[key] = [currentValue];\n            }\n            currentValue.push(value);\n        }\n        else {\n            query[key] = value;\n        }\n    }\n    return query;\n}\n/**\n * Stringifies a {@link LocationQueryRaw} object. Like `URLSearchParams`, it\n * doesn't prepend a `?`\n *\n * @internal\n *\n * @param query - query object to stringify\n * @returns string version of the query without the leading `?`\n */\nfunction stringifyQuery(query) {\n    let search = '';\n    for (let key in query) {\n        const value = query[key];\n        key = encodeQueryKey(key);\n        if (value == null) {\n            // only null adds the value\n            if (value !== undefined) {\n                search += (search.length ? '&' : '') + key;\n            }\n            continue;\n        }\n        // keep null values\n        const values = isArray(value)\n            ? value.map(v => v && encodeQueryValue(v))\n            : [value && encodeQueryValue(value)];\n        values.forEach(value => {\n            // skip undefined values in arrays as if they were not present\n            // smaller code than using filter\n            if (value !== undefined) {\n                // only append & with non-empty search\n                search += (search.length ? '&' : '') + key;\n                if (value != null)\n                    search += '=' + value;\n            }\n        });\n    }\n    return search;\n}\n/**\n * Transforms a {@link LocationQueryRaw} into a {@link LocationQuery} by casting\n * numbers into strings, removing keys with an undefined value and replacing\n * undefined with null in arrays\n *\n * @param query - query object to normalize\n * @returns a normalized query object\n */\nfunction normalizeQuery(query) {\n    const normalizedQuery = {};\n    for (const key in query) {\n        const value = query[key];\n        if (value !== undefined) {\n            normalizedQuery[key] = isArray(value)\n                ? value.map(v => (v == null ? null : '' + v))\n                : value == null\n                    ? value\n                    : '' + value;\n        }\n    }\n    return normalizedQuery;\n}\n\n/**\n * RouteRecord being rendered by the closest ancestor Router View. Used for\n * `onBeforeRouteUpdate` and `onBeforeRouteLeave`. rvlm stands for Router View\n * Location Matched\n *\n * @internal\n */\nconst matchedRouteKey = Symbol((process.env.NODE_ENV !== 'production') ? 'router view location matched' : '');\n/**\n * Allows overriding the router view depth to control which component in\n * `matched` is rendered. rvd stands for Router View Depth\n *\n * @internal\n */\nconst viewDepthKey = Symbol((process.env.NODE_ENV !== 'production') ? 'router view depth' : '');\n/**\n * Allows overriding the router instance returned by `useRouter` in tests. r\n * stands for router\n *\n * @internal\n */\nconst routerKey = Symbol((process.env.NODE_ENV !== 'production') ? 'router' : '');\n/**\n * Allows overriding the current route returned by `useRoute` in tests. rl\n * stands for route location\n *\n * @internal\n */\nconst routeLocationKey = Symbol((process.env.NODE_ENV !== 'production') ? 'route location' : '');\n/**\n * Allows overriding the current route used by router-view. Internally this is\n * used when the `route` prop is passed.\n *\n * @internal\n */\nconst routerViewLocationKey = Symbol((process.env.NODE_ENV !== 'production') ? 'router view location' : '');\n\n/**\n * Create a list of callbacks that can be reset. Used to create before and after navigation guards list\n */\nfunction useCallbacks() {\n    let handlers = [];\n    function add(handler) {\n        handlers.push(handler);\n        return () => {\n            const i = handlers.indexOf(handler);\n            if (i > -1)\n                handlers.splice(i, 1);\n        };\n    }\n    function reset() {\n        handlers = [];\n    }\n    return {\n        add,\n        list: () => handlers.slice(),\n        reset,\n    };\n}\n\nfunction registerGuard(record, name, guard) {\n    const removeFromList = () => {\n        record[name].delete(guard);\n    };\n    onUnmounted(removeFromList);\n    onDeactivated(removeFromList);\n    onActivated(() => {\n        record[name].add(guard);\n    });\n    record[name].add(guard);\n}\n/**\n * Add a navigation guard that triggers whenever the component for the current\n * location is about to be left. Similar to {@link beforeRouteLeave} but can be\n * used in any component. The guard is removed when the component is unmounted.\n *\n * @param leaveGuard - {@link NavigationGuard}\n */\nfunction onBeforeRouteLeave(leaveGuard) {\n    if ((process.env.NODE_ENV !== 'production') && !getCurrentInstance()) {\n        warn('getCurrentInstance() returned null. onBeforeRouteLeave() must be called at the top of a setup function');\n        return;\n    }\n    const activeRecord = inject(matchedRouteKey, \n    // to avoid warning\n    {}).value;\n    if (!activeRecord) {\n        (process.env.NODE_ENV !== 'production') &&\n            warn('No active route record was found when calling `onBeforeRouteLeave()`. Make sure you call this function inside a component child of <router-view>. Maybe you called it inside of App.vue?');\n        return;\n    }\n    registerGuard(activeRecord, 'leaveGuards', leaveGuard);\n}\n/**\n * Add a navigation guard that triggers whenever the current location is about\n * to be updated. Similar to {@link beforeRouteUpdate} but can be used in any\n * component. The guard is removed when the component is unmounted.\n *\n * @param updateGuard - {@link NavigationGuard}\n */\nfunction onBeforeRouteUpdate(updateGuard) {\n    if ((process.env.NODE_ENV !== 'production') && !getCurrentInstance()) {\n        warn('getCurrentInstance() returned null. onBeforeRouteUpdate() must be called at the top of a setup function');\n        return;\n    }\n    const activeRecord = inject(matchedRouteKey, \n    // to avoid warning\n    {}).value;\n    if (!activeRecord) {\n        (process.env.NODE_ENV !== 'production') &&\n            warn('No active route record was found when calling `onBeforeRouteUpdate()`. Make sure you call this function inside a component child of <router-view>. Maybe you called it inside of App.vue?');\n        return;\n    }\n    registerGuard(activeRecord, 'updateGuards', updateGuard);\n}\nfunction guardToPromiseFn(guard, to, from, record, name, runWithContext = fn => fn()) {\n    // keep a reference to the enterCallbackArray to prevent pushing callbacks if a new navigation took place\n    const enterCallbackArray = record &&\n        // name is defined if record is because of the function overload\n        (record.enterCallbacks[name] = record.enterCallbacks[name] || []);\n    return () => new Promise((resolve, reject) => {\n        const next = (valid) => {\n            if (valid === false) {\n                reject(createRouterError(4 /* ErrorTypes.NAVIGATION_ABORTED */, {\n                    from,\n                    to,\n                }));\n            }\n            else if (valid instanceof Error) {\n                reject(valid);\n            }\n            else if (isRouteLocation(valid)) {\n                reject(createRouterError(2 /* ErrorTypes.NAVIGATION_GUARD_REDIRECT */, {\n                    from: to,\n                    to: valid,\n                }));\n            }\n            else {\n                if (enterCallbackArray &&\n                    // since enterCallbackArray is truthy, both record and name also are\n                    record.enterCallbacks[name] === enterCallbackArray &&\n                    typeof valid === 'function') {\n                    enterCallbackArray.push(valid);\n                }\n                resolve();\n            }\n        };\n        // wrapping with Promise.resolve allows it to work with both async and sync guards\n        const guardReturn = runWithContext(() => guard.call(record && record.instances[name], to, from, (process.env.NODE_ENV !== 'production') ? canOnlyBeCalledOnce(next, to, from) : next));\n        let guardCall = Promise.resolve(guardReturn);\n        if (guard.length < 3)\n            guardCall = guardCall.then(next);\n        if ((process.env.NODE_ENV !== 'production') && guard.length > 2) {\n            const message = `The \"next\" callback was never called inside of ${guard.name ? '\"' + guard.name + '\"' : ''}:\\n${guard.toString()}\\n. If you are returning a value instead of calling \"next\", make sure to remove the \"next\" parameter from your function.`;\n            if (typeof guardReturn === 'object' && 'then' in guardReturn) {\n                guardCall = guardCall.then(resolvedValue => {\n                    // @ts-expect-error: _called is added at canOnlyBeCalledOnce\n                    if (!next._called) {\n                        warn(message);\n                        return Promise.reject(new Error('Invalid navigation guard'));\n                    }\n                    return resolvedValue;\n                });\n            }\n            else if (guardReturn !== undefined) {\n                // @ts-expect-error: _called is added at canOnlyBeCalledOnce\n                if (!next._called) {\n                    warn(message);\n                    reject(new Error('Invalid navigation guard'));\n                    return;\n                }\n            }\n        }\n        guardCall.catch(err => reject(err));\n    });\n}\nfunction canOnlyBeCalledOnce(next, to, from) {\n    let called = 0;\n    return function () {\n        if (called++ === 1)\n            warn(`The \"next\" callback was called more than once in one navigation guard when going from \"${from.fullPath}\" to \"${to.fullPath}\". It should be called exactly one time in each navigation guard. This will fail in production.`);\n        // @ts-expect-error: we put it in the original one because it's easier to check\n        next._called = true;\n        if (called === 1)\n            next.apply(null, arguments);\n    };\n}\nfunction extractComponentsGuards(matched, guardType, to, from, runWithContext = fn => fn()) {\n    const guards = [];\n    for (const record of matched) {\n        if ((process.env.NODE_ENV !== 'production') && !record.components && !record.children.length) {\n            warn(`Record with path \"${record.path}\" is either missing a \"component(s)\"` +\n                ` or \"children\" property.`);\n        }\n        for (const name in record.components) {\n            let rawComponent = record.components[name];\n            if ((process.env.NODE_ENV !== 'production')) {\n                if (!rawComponent ||\n                    (typeof rawComponent !== 'object' &&\n                        typeof rawComponent !== 'function')) {\n                    warn(`Component \"${name}\" in record with path \"${record.path}\" is not` +\n                        ` a valid component. Received \"${String(rawComponent)}\".`);\n                    // throw to ensure we stop here but warn to ensure the message isn't\n                    // missed by the user\n                    throw new Error('Invalid route component');\n                }\n                else if ('then' in rawComponent) {\n                    // warn if user wrote import('/component.vue') instead of () =>\n                    // import('./component.vue')\n                    warn(`Component \"${name}\" in record with path \"${record.path}\" is a ` +\n                        `Promise instead of a function that returns a Promise. Did you ` +\n                        `write \"import('./MyPage.vue')\" instead of ` +\n                        `\"() => import('./MyPage.vue')\" ? This will break in ` +\n                        `production if not fixed.`);\n                    const promise = rawComponent;\n                    rawComponent = () => promise;\n                }\n                else if (rawComponent.__asyncLoader &&\n                    // warn only once per component\n                    !rawComponent.__warnedDefineAsync) {\n                    rawComponent.__warnedDefineAsync = true;\n                    warn(`Component \"${name}\" in record with path \"${record.path}\" is defined ` +\n                        `using \"defineAsyncComponent()\". ` +\n                        `Write \"() => import('./MyPage.vue')\" instead of ` +\n                        `\"defineAsyncComponent(() => import('./MyPage.vue'))\".`);\n                }\n            }\n            // skip update and leave guards if the route component is not mounted\n            if (guardType !== 'beforeRouteEnter' && !record.instances[name])\n                continue;\n            if (isRouteComponent(rawComponent)) {\n                // __vccOpts is added by vue-class-component and contain the regular options\n                const options = rawComponent.__vccOpts || rawComponent;\n                const guard = options[guardType];\n                guard &&\n                    guards.push(guardToPromiseFn(guard, to, from, record, name, runWithContext));\n            }\n            else {\n                // start requesting the chunk already\n                let componentPromise = rawComponent();\n                if ((process.env.NODE_ENV !== 'production') && !('catch' in componentPromise)) {\n                    warn(`Component \"${name}\" in record with path \"${record.path}\" is a function that does not return a Promise. If you were passing a functional component, make sure to add a \"displayName\" to the component. This will break in production if not fixed.`);\n                    componentPromise = Promise.resolve(componentPromise);\n                }\n                guards.push(() => componentPromise.then(resolved => {\n                    if (!resolved)\n                        throw new Error(`Couldn't resolve component \"${name}\" at \"${record.path}\"`);\n                    const resolvedComponent = isESModule(resolved)\n                        ? resolved.default\n                        : resolved;\n                    // keep the resolved module for plugins like data loaders\n                    record.mods[name] = resolved;\n                    // replace the function with the resolved component\n                    // cannot be null or undefined because we went into the for loop\n                    record.components[name] = resolvedComponent;\n                    // __vccOpts is added by vue-class-component and contain the regular options\n                    const options = resolvedComponent.__vccOpts || resolvedComponent;\n                    const guard = options[guardType];\n                    return (guard &&\n                        guardToPromiseFn(guard, to, from, record, name, runWithContext)());\n                }));\n            }\n        }\n    }\n    return guards;\n}\n/**\n * Ensures a route is loaded, so it can be passed as o prop to `<RouterView>`.\n *\n * @param route - resolved route to load\n */\nfunction loadRouteLocation(route) {\n    return route.matched.every(record => record.redirect)\n        ? Promise.reject(new Error('Cannot load a route that redirects.'))\n        : Promise.all(route.matched.map(record => record.components &&\n            Promise.all(Object.keys(record.components).reduce((promises, name) => {\n                const rawComponent = record.components[name];\n                if (typeof rawComponent === 'function' &&\n                    !('displayName' in rawComponent)) {\n                    promises.push(rawComponent().then(resolved => {\n                        if (!resolved)\n                            return Promise.reject(new Error(`Couldn't resolve component \"${name}\" at \"${record.path}\". Ensure you passed a function that returns a promise.`));\n                        const resolvedComponent = isESModule(resolved)\n                            ? resolved.default\n                            : resolved;\n                        // keep the resolved module for plugins like data loaders\n                        record.mods[name] = resolved;\n                        // replace the function with the resolved component\n                        // cannot be null or undefined because we went into the for loop\n                        record.components[name] = resolvedComponent;\n                        return;\n                    }));\n                }\n                return promises;\n            }, [])))).then(() => route);\n}\n\n// TODO: we could allow currentRoute as a prop to expose `isActive` and\n// `isExactActive` behavior should go through an RFC\n/**\n * Returns the internal behavior of a {@link RouterLink} without the rendering part.\n *\n * @param props - a `to` location and an optional `replace` flag\n */\nfunction useLink(props) {\n    const router = inject(routerKey);\n    const currentRoute = inject(routeLocationKey);\n    let hasPrevious = false;\n    let previousTo = null;\n    const route = computed(() => {\n        const to = unref(props.to);\n        if ((process.env.NODE_ENV !== 'production') && (!hasPrevious || to !== previousTo)) {\n            if (!isRouteLocation(to)) {\n                if (hasPrevious) {\n                    warn(`Invalid value for prop \"to\" in useLink()\\n- to:`, to, `\\n- previous to:`, previousTo, `\\n- props:`, props);\n                }\n                else {\n                    warn(`Invalid value for prop \"to\" in useLink()\\n- to:`, to, `\\n- props:`, props);\n                }\n            }\n            previousTo = to;\n            hasPrevious = true;\n        }\n        return router.resolve(to);\n    });\n    const activeRecordIndex = computed(() => {\n        const { matched } = route.value;\n        const { length } = matched;\n        const routeMatched = matched[length - 1];\n        const currentMatched = currentRoute.matched;\n        if (!routeMatched || !currentMatched.length)\n            return -1;\n        const index = currentMatched.findIndex(isSameRouteRecord.bind(null, routeMatched));\n        if (index > -1)\n            return index;\n        // possible parent record\n        const parentRecordPath = getOriginalPath(matched[length - 2]);\n        return (\n        // we are dealing with nested routes\n        length > 1 &&\n            // if the parent and matched route have the same path, this link is\n            // referring to the empty child. Or we currently are on a different\n            // child of the same parent\n            getOriginalPath(routeMatched) === parentRecordPath &&\n            // avoid comparing the child with its parent\n            currentMatched[currentMatched.length - 1].path !== parentRecordPath\n            ? currentMatched.findIndex(isSameRouteRecord.bind(null, matched[length - 2]))\n            : index);\n    });\n    const isActive = computed(() => activeRecordIndex.value > -1 &&\n        includesParams(currentRoute.params, route.value.params));\n    const isExactActive = computed(() => activeRecordIndex.value > -1 &&\n        activeRecordIndex.value === currentRoute.matched.length - 1 &&\n        isSameRouteLocationParams(currentRoute.params, route.value.params));\n    function navigate(e = {}) {\n        if (guardEvent(e)) {\n            const p = router[unref(props.replace) ? 'replace' : 'push'](unref(props.to)\n            // avoid uncaught errors are they are logged anyway\n            ).catch(noop);\n            if (props.viewTransition &&\n                typeof document !== 'undefined' &&\n                'startViewTransition' in document) {\n                document.startViewTransition(() => p);\n            }\n            return p;\n        }\n        return Promise.resolve();\n    }\n    // devtools only\n    if (((process.env.NODE_ENV !== 'production') || __VUE_PROD_DEVTOOLS__) && isBrowser) {\n        const instance = getCurrentInstance();\n        if (instance) {\n            const linkContextDevtools = {\n                route: route.value,\n                isActive: isActive.value,\n                isExactActive: isExactActive.value,\n                error: null,\n            };\n            // @ts-expect-error: this is internal\n            instance.__vrl_devtools = instance.__vrl_devtools || [];\n            // @ts-expect-error: this is internal\n            instance.__vrl_devtools.push(linkContextDevtools);\n            watchEffect(() => {\n                linkContextDevtools.route = route.value;\n                linkContextDevtools.isActive = isActive.value;\n                linkContextDevtools.isExactActive = isExactActive.value;\n                linkContextDevtools.error = isRouteLocation(unref(props.to))\n                    ? null\n                    : 'Invalid \"to\" value';\n            }, { flush: 'post' });\n        }\n    }\n    /**\n     * NOTE: update {@link _RouterLinkI}'s `$slots` type when updating this\n     */\n    return {\n        route,\n        href: computed(() => route.value.href),\n        isActive,\n        isExactActive,\n        navigate,\n    };\n}\nfunction preferSingleVNode(vnodes) {\n    return vnodes.length === 1 ? vnodes[0] : vnodes;\n}\nconst RouterLinkImpl = /*#__PURE__*/ defineComponent({\n    name: 'RouterLink',\n    compatConfig: { MODE: 3 },\n    props: {\n        to: {\n            type: [String, Object],\n            required: true,\n        },\n        replace: Boolean,\n        activeClass: String,\n        // inactiveClass: String,\n        exactActiveClass: String,\n        custom: Boolean,\n        ariaCurrentValue: {\n            type: String,\n            default: 'page',\n        },\n        viewTransition: Boolean,\n    },\n    useLink,\n    setup(props, { slots }) {\n        const link = reactive(useLink(props));\n        const { options } = inject(routerKey);\n        const elClass = computed(() => ({\n            [getLinkClass(props.activeClass, options.linkActiveClass, 'router-link-active')]: link.isActive,\n            // [getLinkClass(\n            //   props.inactiveClass,\n            //   options.linkInactiveClass,\n            //   'router-link-inactive'\n            // )]: !link.isExactActive,\n            [getLinkClass(props.exactActiveClass, options.linkExactActiveClass, 'router-link-exact-active')]: link.isExactActive,\n        }));\n        return () => {\n            const children = slots.default && preferSingleVNode(slots.default(link));\n            return props.custom\n                ? children\n                : h('a', {\n                    'aria-current': link.isExactActive\n                        ? props.ariaCurrentValue\n                        : null,\n                    href: link.href,\n                    // this would override user added attrs but Vue will still add\n                    // the listener, so we end up triggering both\n                    onClick: link.navigate,\n                    class: elClass.value,\n                }, children);\n        };\n    },\n});\n// export the public type for h/tsx inference\n// also to avoid inline import() in generated d.ts files\n/**\n * Component to render a link that triggers a navigation on click.\n */\nconst RouterLink = RouterLinkImpl;\nfunction guardEvent(e) {\n    // don't redirect with control keys\n    if (e.metaKey || e.altKey || e.ctrlKey || e.shiftKey)\n        return;\n    // don't redirect when preventDefault called\n    if (e.defaultPrevented)\n        return;\n    // don't redirect on right click\n    if (e.button !== undefined && e.button !== 0)\n        return;\n    // don't redirect if `target=\"_blank\"`\n    // @ts-expect-error getAttribute does exist\n    if (e.currentTarget && e.currentTarget.getAttribute) {\n        // @ts-expect-error getAttribute exists\n        const target = e.currentTarget.getAttribute('target');\n        if (/\\b_blank\\b/i.test(target))\n            return;\n    }\n    // this may be a Weex event which doesn't have this method\n    if (e.preventDefault)\n        e.preventDefault();\n    return true;\n}\nfunction includesParams(outer, inner) {\n    for (const key in inner) {\n        const innerValue = inner[key];\n        const outerValue = outer[key];\n        if (typeof innerValue === 'string') {\n            if (innerValue !== outerValue)\n                return false;\n        }\n        else {\n            if (!isArray(outerValue) ||\n                outerValue.length !== innerValue.length ||\n                innerValue.some((value, i) => value !== outerValue[i]))\n                return false;\n        }\n    }\n    return true;\n}\n/**\n * Get the original path value of a record by following its aliasOf\n * @param record\n */\nfunction getOriginalPath(record) {\n    return record ? (record.aliasOf ? record.aliasOf.path : record.path) : '';\n}\n/**\n * Utility class to get the active class based on defaults.\n * @param propClass\n * @param globalClass\n * @param defaultClass\n */\nconst getLinkClass = (propClass, globalClass, defaultClass) => propClass != null\n    ? propClass\n    : globalClass != null\n        ? globalClass\n        : defaultClass;\n\nconst RouterViewImpl = /*#__PURE__*/ defineComponent({\n    name: 'RouterView',\n    // #674 we manually inherit them\n    inheritAttrs: false,\n    props: {\n        name: {\n            type: String,\n            default: 'default',\n        },\n        route: Object,\n    },\n    // Better compat for @vue/compat users\n    // https://github.com/vuejs/router/issues/1315\n    compatConfig: { MODE: 3 },\n    setup(props, { attrs, slots }) {\n        (process.env.NODE_ENV !== 'production') && warnDeprecatedUsage();\n        const injectedRoute = inject(routerViewLocationKey);\n        const routeToDisplay = computed(() => props.route || injectedRoute.value);\n        const injectedDepth = inject(viewDepthKey, 0);\n        // The depth changes based on empty components option, which allows passthrough routes e.g. routes with children\n        // that are used to reuse the `path` property\n        const depth = computed(() => {\n            let initialDepth = unref(injectedDepth);\n            const { matched } = routeToDisplay.value;\n            let matchedRoute;\n            while ((matchedRoute = matched[initialDepth]) &&\n                !matchedRoute.components) {\n                initialDepth++;\n            }\n            return initialDepth;\n        });\n        const matchedRouteRef = computed(() => routeToDisplay.value.matched[depth.value]);\n        provide(viewDepthKey, computed(() => depth.value + 1));\n        provide(matchedRouteKey, matchedRouteRef);\n        provide(routerViewLocationKey, routeToDisplay);\n        const viewRef = ref();\n        // watch at the same time the component instance, the route record we are\n        // rendering, and the name\n        watch(() => [viewRef.value, matchedRouteRef.value, props.name], ([instance, to, name], [oldInstance, from, oldName]) => {\n            // copy reused instances\n            if (to) {\n                // this will update the instance for new instances as well as reused\n                // instances when navigating to a new route\n                to.instances[name] = instance;\n                // the component instance is reused for a different route or name, so\n                // we copy any saved update or leave guards. With async setup, the\n                // mounting component will mount before the matchedRoute changes,\n                // making instance === oldInstance, so we check if guards have been\n                // added before. This works because we remove guards when\n                // unmounting/deactivating components\n                if (from && from !== to && instance && instance === oldInstance) {\n                    if (!to.leaveGuards.size) {\n                        to.leaveGuards = from.leaveGuards;\n                    }\n                    if (!to.updateGuards.size) {\n                        to.updateGuards = from.updateGuards;\n                    }\n                }\n            }\n            // trigger beforeRouteEnter next callbacks\n            if (instance &&\n                to &&\n                // if there is no instance but to and from are the same this might be\n                // the first visit\n                (!from || !isSameRouteRecord(to, from) || !oldInstance)) {\n                (to.enterCallbacks[name] || []).forEach(callback => callback(instance));\n            }\n        }, { flush: 'post' });\n        return () => {\n            const route = routeToDisplay.value;\n            // we need the value at the time we render because when we unmount, we\n            // navigated to a different location so the value is different\n            const currentName = props.name;\n            const matchedRoute = matchedRouteRef.value;\n            const ViewComponent = matchedRoute && matchedRoute.components[currentName];\n            if (!ViewComponent) {\n                return normalizeSlot(slots.default, { Component: ViewComponent, route });\n            }\n            // props from route configuration\n            const routePropsOption = matchedRoute.props[currentName];\n            const routeProps = routePropsOption\n                ? routePropsOption === true\n                    ? route.params\n                    : typeof routePropsOption === 'function'\n                        ? routePropsOption(route)\n                        : routePropsOption\n                : null;\n            const onVnodeUnmounted = vnode => {\n                // remove the instance reference to prevent leak\n                if (vnode.component.isUnmounted) {\n                    matchedRoute.instances[currentName] = null;\n                }\n            };\n            const component = h(ViewComponent, assign({}, routeProps, attrs, {\n                onVnodeUnmounted,\n                ref: viewRef,\n            }));\n            if (((process.env.NODE_ENV !== 'production') || __VUE_PROD_DEVTOOLS__) &&\n                isBrowser &&\n                component.ref) {\n                // TODO: can display if it's an alias, its props\n                const info = {\n                    depth: depth.value,\n                    name: matchedRoute.name,\n                    path: matchedRoute.path,\n                    meta: matchedRoute.meta,\n                };\n                const internalInstances = isArray(component.ref)\n                    ? component.ref.map(r => r.i)\n                    : [component.ref.i];\n                internalInstances.forEach(instance => {\n                    // @ts-expect-error\n                    instance.__vrv_devtools = info;\n                });\n            }\n            return (\n            // pass the vnode to the slot as a prop.\n            // h and <component :is=\"...\"> both accept vnodes\n            normalizeSlot(slots.default, { Component: component, route }) ||\n                component);\n        };\n    },\n});\nfunction normalizeSlot(slot, data) {\n    if (!slot)\n        return null;\n    const slotContent = slot(data);\n    return slotContent.length === 1 ? slotContent[0] : slotContent;\n}\n// export the public type for h/tsx inference\n// also to avoid inline import() in generated d.ts files\n/**\n * Component to display the current route the user is at.\n */\nconst RouterView = RouterViewImpl;\n// warn against deprecated usage with <transition> & <keep-alive>\n// due to functional component being no longer eager in Vue 3\nfunction warnDeprecatedUsage() {\n    const instance = getCurrentInstance();\n    const parentName = instance.parent && instance.parent.type.name;\n    const parentSubTreeType = instance.parent && instance.parent.subTree && instance.parent.subTree.type;\n    if (parentName &&\n        (parentName === 'KeepAlive' || parentName.includes('Transition')) &&\n        typeof parentSubTreeType === 'object' &&\n        parentSubTreeType.name === 'RouterView') {\n        const comp = parentName === 'KeepAlive' ? 'keep-alive' : 'transition';\n        warn(`<router-view> can no longer be used directly inside <transition> or <keep-alive>.\\n` +\n            `Use slot props instead:\\n\\n` +\n            `<router-view v-slot=\"{ Component }\">\\n` +\n            `  <${comp}>\\n` +\n            `    <component :is=\"Component\" />\\n` +\n            `  </${comp}>\\n` +\n            `</router-view>`);\n    }\n}\n\n/**\n * Copies a route location and removes any problematic properties that cannot be shown in devtools (e.g. Vue instances).\n *\n * @param routeLocation - routeLocation to format\n * @param tooltip - optional tooltip\n * @returns a copy of the routeLocation\n */\nfunction formatRouteLocation(routeLocation, tooltip) {\n    const copy = assign({}, routeLocation, {\n        // remove variables that can contain vue instances\n        matched: routeLocation.matched.map(matched => omit(matched, ['instances', 'children', 'aliasOf'])),\n    });\n    return {\n        _custom: {\n            type: null,\n            readOnly: true,\n            display: routeLocation.fullPath,\n            tooltip,\n            value: copy,\n        },\n    };\n}\nfunction formatDisplay(display) {\n    return {\n        _custom: {\n            display,\n        },\n    };\n}\n// to support multiple router instances\nlet routerId = 0;\nfunction addDevtools(app, router, matcher) {\n    // Take over router.beforeEach and afterEach\n    // make sure we are not registering the devtool twice\n    if (router.__hasDevtools)\n        return;\n    router.__hasDevtools = true;\n    // increment to support multiple router instances\n    const id = routerId++;\n    setupDevtoolsPlugin({\n        id: 'org.vuejs.router' + (id ? '.' + id : ''),\n        label: 'Vue Router',\n        packageName: 'vue-router',\n        homepage: 'https://router.vuejs.org',\n        logo: 'https://router.vuejs.org/logo.png',\n        componentStateTypes: ['Routing'],\n        app,\n    }, api => {\n        if (typeof api.now !== 'function') {\n            console.warn('[Vue Router]: You seem to be using an outdated version of Vue Devtools. Are you still using the Beta release instead of the stable one? You can find the links at https://devtools.vuejs.org/guide/installation.html.');\n        }\n        // display state added by the router\n        api.on.inspectComponent((payload, ctx) => {\n            if (payload.instanceData) {\n                payload.instanceData.state.push({\n                    type: 'Routing',\n                    key: '$route',\n                    editable: false,\n                    value: formatRouteLocation(router.currentRoute.value, 'Current Route'),\n                });\n            }\n        });\n        // mark router-link as active and display tags on router views\n        api.on.visitComponentTree(({ treeNode: node, componentInstance }) => {\n            if (componentInstance.__vrv_devtools) {\n                const info = componentInstance.__vrv_devtools;\n                node.tags.push({\n                    label: (info.name ? `${info.name.toString()}: ` : '') + info.path,\n                    textColor: 0,\n                    tooltip: 'This component is rendered by &lt;router-view&gt;',\n                    backgroundColor: PINK_500,\n                });\n            }\n            // if multiple useLink are used\n            if (isArray(componentInstance.__vrl_devtools)) {\n                componentInstance.__devtoolsApi = api;\n                componentInstance.__vrl_devtools.forEach(devtoolsData => {\n                    let label = devtoolsData.route.path;\n                    let backgroundColor = ORANGE_400;\n                    let tooltip = '';\n                    let textColor = 0;\n                    if (devtoolsData.error) {\n                        label = devtoolsData.error;\n                        backgroundColor = RED_100;\n                        textColor = RED_700;\n                    }\n                    else if (devtoolsData.isExactActive) {\n                        backgroundColor = LIME_500;\n                        tooltip = 'This is exactly active';\n                    }\n                    else if (devtoolsData.isActive) {\n                        backgroundColor = BLUE_600;\n                        tooltip = 'This link is active';\n                    }\n                    node.tags.push({\n                        label,\n                        textColor,\n                        tooltip,\n                        backgroundColor,\n                    });\n                });\n            }\n        });\n        watch(router.currentRoute, () => {\n            // refresh active state\n            refreshRoutesView();\n            api.notifyComponentUpdate();\n            api.sendInspectorTree(routerInspectorId);\n            api.sendInspectorState(routerInspectorId);\n        });\n        const navigationsLayerId = 'router:navigations:' + id;\n        api.addTimelineLayer({\n            id: navigationsLayerId,\n            label: `Router${id ? ' ' + id : ''} Navigations`,\n            color: 0x40a8c4,\n        });\n        // const errorsLayerId = 'router:errors'\n        // api.addTimelineLayer({\n        //   id: errorsLayerId,\n        //   label: 'Router Errors',\n        //   color: 0xea5455,\n        // })\n        router.onError((error, to) => {\n            api.addTimelineEvent({\n                layerId: navigationsLayerId,\n                event: {\n                    title: 'Error during Navigation',\n                    subtitle: to.fullPath,\n                    logType: 'error',\n                    time: api.now(),\n                    data: { error },\n                    groupId: to.meta.__navigationId,\n                },\n            });\n        });\n        // attached to `meta` and used to group events\n        let navigationId = 0;\n        router.beforeEach((to, from) => {\n            const data = {\n                guard: formatDisplay('beforeEach'),\n                from: formatRouteLocation(from, 'Current Location during this navigation'),\n                to: formatRouteLocation(to, 'Target location'),\n            };\n            // Used to group navigations together, hide from devtools\n            Object.defineProperty(to.meta, '__navigationId', {\n                value: navigationId++,\n            });\n            api.addTimelineEvent({\n                layerId: navigationsLayerId,\n                event: {\n                    time: api.now(),\n                    title: 'Start of navigation',\n                    subtitle: to.fullPath,\n                    data,\n                    groupId: to.meta.__navigationId,\n                },\n            });\n        });\n        router.afterEach((to, from, failure) => {\n            const data = {\n                guard: formatDisplay('afterEach'),\n            };\n            if (failure) {\n                data.failure = {\n                    _custom: {\n                        type: Error,\n                        readOnly: true,\n                        display: failure ? failure.message : '',\n                        tooltip: 'Navigation Failure',\n                        value: failure,\n                    },\n                };\n                data.status = formatDisplay('❌');\n            }\n            else {\n                data.status = formatDisplay('✅');\n            }\n            // we set here to have the right order\n            data.from = formatRouteLocation(from, 'Current Location during this navigation');\n            data.to = formatRouteLocation(to, 'Target location');\n            api.addTimelineEvent({\n                layerId: navigationsLayerId,\n                event: {\n                    title: 'End of navigation',\n                    subtitle: to.fullPath,\n                    time: api.now(),\n                    data,\n                    logType: failure ? 'warning' : 'default',\n                    groupId: to.meta.__navigationId,\n                },\n            });\n        });\n        /**\n         * Inspector of Existing routes\n         */\n        const routerInspectorId = 'router-inspector:' + id;\n        api.addInspector({\n            id: routerInspectorId,\n            label: 'Routes' + (id ? ' ' + id : ''),\n            icon: 'book',\n            treeFilterPlaceholder: 'Search routes',\n        });\n        function refreshRoutesView() {\n            // the routes view isn't active\n            if (!activeRoutesPayload)\n                return;\n            const payload = activeRoutesPayload;\n            // children routes will appear as nested\n            let routes = matcher.getRoutes().filter(route => !route.parent ||\n                // these routes have a parent with no component which will not appear in the view\n                // therefore we still need to include them\n                !route.parent.record.components);\n            // reset match state to false\n            routes.forEach(resetMatchStateOnRouteRecord);\n            // apply a match state if there is a payload\n            if (payload.filter) {\n                routes = routes.filter(route => \n                // save matches state based on the payload\n                isRouteMatching(route, payload.filter.toLowerCase()));\n            }\n            // mark active routes\n            routes.forEach(route => markRouteRecordActive(route, router.currentRoute.value));\n            payload.rootNodes = routes.map(formatRouteRecordForInspector);\n        }\n        let activeRoutesPayload;\n        api.on.getInspectorTree(payload => {\n            activeRoutesPayload = payload;\n            if (payload.app === app && payload.inspectorId === routerInspectorId) {\n                refreshRoutesView();\n            }\n        });\n        /**\n         * Display information about the currently selected route record\n         */\n        api.on.getInspectorState(payload => {\n            if (payload.app === app && payload.inspectorId === routerInspectorId) {\n                const routes = matcher.getRoutes();\n                const route = routes.find(route => route.record.__vd_id === payload.nodeId);\n                if (route) {\n                    payload.state = {\n                        options: formatRouteRecordMatcherForStateInspector(route),\n                    };\n                }\n            }\n        });\n        api.sendInspectorTree(routerInspectorId);\n        api.sendInspectorState(routerInspectorId);\n    });\n}\nfunction modifierForKey(key) {\n    if (key.optional) {\n        return key.repeatable ? '*' : '?';\n    }\n    else {\n        return key.repeatable ? '+' : '';\n    }\n}\nfunction formatRouteRecordMatcherForStateInspector(route) {\n    const { record } = route;\n    const fields = [\n        { editable: false, key: 'path', value: record.path },\n    ];\n    if (record.name != null) {\n        fields.push({\n            editable: false,\n            key: 'name',\n            value: record.name,\n        });\n    }\n    fields.push({ editable: false, key: 'regexp', value: route.re });\n    if (route.keys.length) {\n        fields.push({\n            editable: false,\n            key: 'keys',\n            value: {\n                _custom: {\n                    type: null,\n                    readOnly: true,\n                    display: route.keys\n                        .map(key => `${key.name}${modifierForKey(key)}`)\n                        .join(' '),\n                    tooltip: 'Param keys',\n                    value: route.keys,\n                },\n            },\n        });\n    }\n    if (record.redirect != null) {\n        fields.push({\n            editable: false,\n            key: 'redirect',\n            value: record.redirect,\n        });\n    }\n    if (route.alias.length) {\n        fields.push({\n            editable: false,\n            key: 'aliases',\n            value: route.alias.map(alias => alias.record.path),\n        });\n    }\n    if (Object.keys(route.record.meta).length) {\n        fields.push({\n            editable: false,\n            key: 'meta',\n            value: route.record.meta,\n        });\n    }\n    fields.push({\n        key: 'score',\n        editable: false,\n        value: {\n            _custom: {\n                type: null,\n                readOnly: true,\n                display: route.score.map(score => score.join(', ')).join(' | '),\n                tooltip: 'Score used to sort routes',\n                value: route.score,\n            },\n        },\n    });\n    return fields;\n}\n/**\n * Extracted from tailwind palette\n */\nconst PINK_500 = 0xec4899;\nconst BLUE_600 = 0x2563eb;\nconst LIME_500 = 0x84cc16;\nconst CYAN_400 = 0x22d3ee;\nconst ORANGE_400 = 0xfb923c;\n// const GRAY_100 = 0xf4f4f5\nconst DARK = 0x666666;\nconst RED_100 = 0xfee2e2;\nconst RED_700 = 0xb91c1c;\nfunction formatRouteRecordForInspector(route) {\n    const tags = [];\n    const { record } = route;\n    if (record.name != null) {\n        tags.push({\n            label: String(record.name),\n            textColor: 0,\n            backgroundColor: CYAN_400,\n        });\n    }\n    if (record.aliasOf) {\n        tags.push({\n            label: 'alias',\n            textColor: 0,\n            backgroundColor: ORANGE_400,\n        });\n    }\n    if (route.__vd_match) {\n        tags.push({\n            label: 'matches',\n            textColor: 0,\n            backgroundColor: PINK_500,\n        });\n    }\n    if (route.__vd_exactActive) {\n        tags.push({\n            label: 'exact',\n            textColor: 0,\n            backgroundColor: LIME_500,\n        });\n    }\n    if (route.__vd_active) {\n        tags.push({\n            label: 'active',\n            textColor: 0,\n            backgroundColor: BLUE_600,\n        });\n    }\n    if (record.redirect) {\n        tags.push({\n            label: typeof record.redirect === 'string'\n                ? `redirect: ${record.redirect}`\n                : 'redirects',\n            textColor: 0xffffff,\n            backgroundColor: DARK,\n        });\n    }\n    // add an id to be able to select it. Using the `path` is not possible because\n    // empty path children would collide with their parents\n    let id = record.__vd_id;\n    if (id == null) {\n        id = String(routeRecordId++);\n        record.__vd_id = id;\n    }\n    return {\n        id,\n        label: record.path,\n        tags,\n        children: route.children.map(formatRouteRecordForInspector),\n    };\n}\n//  incremental id for route records and inspector state\nlet routeRecordId = 0;\nconst EXTRACT_REGEXP_RE = /^\\/(.*)\\/([a-z]*)$/;\nfunction markRouteRecordActive(route, currentRoute) {\n    // no route will be active if matched is empty\n    // reset the matching state\n    const isExactActive = currentRoute.matched.length &&\n        isSameRouteRecord(currentRoute.matched[currentRoute.matched.length - 1], route.record);\n    route.__vd_exactActive = route.__vd_active = isExactActive;\n    if (!isExactActive) {\n        route.__vd_active = currentRoute.matched.some(match => isSameRouteRecord(match, route.record));\n    }\n    route.children.forEach(childRoute => markRouteRecordActive(childRoute, currentRoute));\n}\nfunction resetMatchStateOnRouteRecord(route) {\n    route.__vd_match = false;\n    route.children.forEach(resetMatchStateOnRouteRecord);\n}\nfunction isRouteMatching(route, filter) {\n    const found = String(route.re).match(EXTRACT_REGEXP_RE);\n    route.__vd_match = false;\n    if (!found || found.length < 3) {\n        return false;\n    }\n    // use a regexp without $ at the end to match nested routes better\n    const nonEndingRE = new RegExp(found[1].replace(/\\$$/, ''), found[2]);\n    if (nonEndingRE.test(filter)) {\n        // mark children as matches\n        route.children.forEach(child => isRouteMatching(child, filter));\n        // exception case: `/`\n        if (route.record.path !== '/' || filter === '/') {\n            route.__vd_match = route.re.test(filter);\n            return true;\n        }\n        // hide the / route\n        return false;\n    }\n    const path = route.record.path.toLowerCase();\n    const decodedPath = decode(path);\n    // also allow partial matching on the path\n    if (!filter.startsWith('/') &&\n        (decodedPath.includes(filter) || path.includes(filter)))\n        return true;\n    if (decodedPath.startsWith(filter) || path.startsWith(filter))\n        return true;\n    if (route.record.name && String(route.record.name).includes(filter))\n        return true;\n    return route.children.some(child => isRouteMatching(child, filter));\n}\nfunction omit(obj, keys) {\n    const ret = {};\n    for (const key in obj) {\n        if (!keys.includes(key)) {\n            // @ts-expect-error\n            ret[key] = obj[key];\n        }\n    }\n    return ret;\n}\n\n/**\n * Creates a Router instance that can be used by a Vue app.\n *\n * @param options - {@link RouterOptions}\n */\nfunction createRouter(options) {\n    const matcher = createRouterMatcher(options.routes, options);\n    const parseQuery$1 = options.parseQuery || parseQuery;\n    const stringifyQuery$1 = options.stringifyQuery || stringifyQuery;\n    const routerHistory = options.history;\n    if ((process.env.NODE_ENV !== 'production') && !routerHistory)\n        throw new Error('Provide the \"history\" option when calling \"createRouter()\":' +\n            ' https://router.vuejs.org/api/interfaces/RouterOptions.html#history');\n    const beforeGuards = useCallbacks();\n    const beforeResolveGuards = useCallbacks();\n    const afterGuards = useCallbacks();\n    const currentRoute = shallowRef(START_LOCATION_NORMALIZED);\n    let pendingLocation = START_LOCATION_NORMALIZED;\n    // leave the scrollRestoration if no scrollBehavior is provided\n    if (isBrowser && options.scrollBehavior && 'scrollRestoration' in history) {\n        history.scrollRestoration = 'manual';\n    }\n    const normalizeParams = applyToParams.bind(null, paramValue => '' + paramValue);\n    const encodeParams = applyToParams.bind(null, encodeParam);\n    const decodeParams = \n    // @ts-expect-error: intentionally avoid the type check\n    applyToParams.bind(null, decode);\n    function addRoute(parentOrRoute, route) {\n        let parent;\n        let record;\n        if (isRouteName(parentOrRoute)) {\n            parent = matcher.getRecordMatcher(parentOrRoute);\n            if ((process.env.NODE_ENV !== 'production') && !parent) {\n                warn(`Parent route \"${String(parentOrRoute)}\" not found when adding child route`, route);\n            }\n            record = route;\n        }\n        else {\n            record = parentOrRoute;\n        }\n        return matcher.addRoute(record, parent);\n    }\n    function removeRoute(name) {\n        const recordMatcher = matcher.getRecordMatcher(name);\n        if (recordMatcher) {\n            matcher.removeRoute(recordMatcher);\n        }\n        else if ((process.env.NODE_ENV !== 'production')) {\n            warn(`Cannot remove non-existent route \"${String(name)}\"`);\n        }\n    }\n    function getRoutes() {\n        return matcher.getRoutes().map(routeMatcher => routeMatcher.record);\n    }\n    function hasRoute(name) {\n        return !!matcher.getRecordMatcher(name);\n    }\n    function resolve(rawLocation, currentLocation) {\n        // const resolve: Router['resolve'] = (rawLocation: RouteLocationRaw, currentLocation) => {\n        // const objectLocation = routerLocationAsObject(rawLocation)\n        // we create a copy to modify it later\n        currentLocation = assign({}, currentLocation || currentRoute.value);\n        if (typeof rawLocation === 'string') {\n            const locationNormalized = parseURL(parseQuery$1, rawLocation, currentLocation.path);\n            const matchedRoute = matcher.resolve({ path: locationNormalized.path }, currentLocation);\n            const href = routerHistory.createHref(locationNormalized.fullPath);\n            if ((process.env.NODE_ENV !== 'production')) {\n                if (href.startsWith('//'))\n                    warn(`Location \"${rawLocation}\" resolved to \"${href}\". A resolved location cannot start with multiple slashes.`);\n                else if (!matchedRoute.matched.length) {\n                    warn(`No match found for location with path \"${rawLocation}\"`);\n                }\n            }\n            // locationNormalized is always a new object\n            return assign(locationNormalized, matchedRoute, {\n                params: decodeParams(matchedRoute.params),\n                hash: decode(locationNormalized.hash),\n                redirectedFrom: undefined,\n                href,\n            });\n        }\n        if ((process.env.NODE_ENV !== 'production') && !isRouteLocation(rawLocation)) {\n            warn(`router.resolve() was passed an invalid location. This will fail in production.\\n- Location:`, rawLocation);\n            return resolve({});\n        }\n        let matcherLocation;\n        // path could be relative in object as well\n        if (rawLocation.path != null) {\n            if ((process.env.NODE_ENV !== 'production') &&\n                'params' in rawLocation &&\n                !('name' in rawLocation) &&\n                // @ts-expect-error: the type is never\n                Object.keys(rawLocation.params).length) {\n                warn(`Path \"${rawLocation.path}\" was passed with params but they will be ignored. Use a named route alongside params instead.`);\n            }\n            matcherLocation = assign({}, rawLocation, {\n                path: parseURL(parseQuery$1, rawLocation.path, currentLocation.path).path,\n            });\n        }\n        else {\n            // remove any nullish param\n            const targetParams = assign({}, rawLocation.params);\n            for (const key in targetParams) {\n                if (targetParams[key] == null) {\n                    delete targetParams[key];\n                }\n            }\n            // pass encoded values to the matcher, so it can produce encoded path and fullPath\n            matcherLocation = assign({}, rawLocation, {\n                params: encodeParams(targetParams),\n            });\n            // current location params are decoded, we need to encode them in case the\n            // matcher merges the params\n            currentLocation.params = encodeParams(currentLocation.params);\n        }\n        const matchedRoute = matcher.resolve(matcherLocation, currentLocation);\n        const hash = rawLocation.hash || '';\n        if ((process.env.NODE_ENV !== 'production') && hash && !hash.startsWith('#')) {\n            warn(`A \\`hash\\` should always start with the character \"#\". Replace \"${hash}\" with \"#${hash}\".`);\n        }\n        // the matcher might have merged current location params, so\n        // we need to run the decoding again\n        matchedRoute.params = normalizeParams(decodeParams(matchedRoute.params));\n        const fullPath = stringifyURL(stringifyQuery$1, assign({}, rawLocation, {\n            hash: encodeHash(hash),\n            path: matchedRoute.path,\n        }));\n        const href = routerHistory.createHref(fullPath);\n        if ((process.env.NODE_ENV !== 'production')) {\n            if (href.startsWith('//')) {\n                warn(`Location \"${rawLocation}\" resolved to \"${href}\". A resolved location cannot start with multiple slashes.`);\n            }\n            else if (!matchedRoute.matched.length) {\n                warn(`No match found for location with path \"${rawLocation.path != null ? rawLocation.path : rawLocation}\"`);\n            }\n        }\n        return assign({\n            fullPath,\n            // keep the hash encoded so fullPath is effectively path + encodedQuery +\n            // hash\n            hash,\n            query: \n            // if the user is using a custom query lib like qs, we might have\n            // nested objects, so we keep the query as is, meaning it can contain\n            // numbers at `$route.query`, but at the point, the user will have to\n            // use their own type anyway.\n            // https://github.com/vuejs/router/issues/328#issuecomment-649481567\n            stringifyQuery$1 === stringifyQuery\n                ? normalizeQuery(rawLocation.query)\n                : (rawLocation.query || {}),\n        }, matchedRoute, {\n            redirectedFrom: undefined,\n            href,\n        });\n    }\n    function locationAsObject(to) {\n        return typeof to === 'string'\n            ? parseURL(parseQuery$1, to, currentRoute.value.path)\n            : assign({}, to);\n    }\n    function checkCanceledNavigation(to, from) {\n        if (pendingLocation !== to) {\n            return createRouterError(8 /* ErrorTypes.NAVIGATION_CANCELLED */, {\n                from,\n                to,\n            });\n        }\n    }\n    function push(to) {\n        return pushWithRedirect(to);\n    }\n    function replace(to) {\n        return push(assign(locationAsObject(to), { replace: true }));\n    }\n    function handleRedirectRecord(to) {\n        const lastMatched = to.matched[to.matched.length - 1];\n        if (lastMatched && lastMatched.redirect) {\n            const { redirect } = lastMatched;\n            let newTargetLocation = typeof redirect === 'function' ? redirect(to) : redirect;\n            if (typeof newTargetLocation === 'string') {\n                newTargetLocation =\n                    newTargetLocation.includes('?') || newTargetLocation.includes('#')\n                        ? (newTargetLocation = locationAsObject(newTargetLocation))\n                        : // force empty params\n                            { path: newTargetLocation };\n                // @ts-expect-error: force empty params when a string is passed to let\n                // the router parse them again\n                newTargetLocation.params = {};\n            }\n            if ((process.env.NODE_ENV !== 'production') &&\n                newTargetLocation.path == null &&\n                !('name' in newTargetLocation)) {\n                warn(`Invalid redirect found:\\n${JSON.stringify(newTargetLocation, null, 2)}\\n when navigating to \"${to.fullPath}\". A redirect must contain a name or path. This will break in production.`);\n                throw new Error('Invalid redirect');\n            }\n            return assign({\n                query: to.query,\n                hash: to.hash,\n                // avoid transferring params if the redirect has a path\n                params: newTargetLocation.path != null ? {} : to.params,\n            }, newTargetLocation);\n        }\n    }\n    function pushWithRedirect(to, redirectedFrom) {\n        const targetLocation = (pendingLocation = resolve(to));\n        const from = currentRoute.value;\n        const data = to.state;\n        const force = to.force;\n        // to could be a string where `replace` is a function\n        const replace = to.replace === true;\n        const shouldRedirect = handleRedirectRecord(targetLocation);\n        if (shouldRedirect)\n            return pushWithRedirect(assign(locationAsObject(shouldRedirect), {\n                state: typeof shouldRedirect === 'object'\n                    ? assign({}, data, shouldRedirect.state)\n                    : data,\n                force,\n                replace,\n            }), \n            // keep original redirectedFrom if it exists\n            redirectedFrom || targetLocation);\n        // if it was a redirect we already called `pushWithRedirect` above\n        const toLocation = targetLocation;\n        toLocation.redirectedFrom = redirectedFrom;\n        let failure;\n        if (!force && isSameRouteLocation(stringifyQuery$1, from, targetLocation)) {\n            failure = createRouterError(16 /* ErrorTypes.NAVIGATION_DUPLICATED */, { to: toLocation, from });\n            // trigger scroll to allow scrolling to the same anchor\n            handleScroll(from, from, \n            // this is a push, the only way for it to be triggered from a\n            // history.listen is with a redirect, which makes it become a push\n            true, \n            // This cannot be the first navigation because the initial location\n            // cannot be manually navigated to\n            false);\n        }\n        return (failure ? Promise.resolve(failure) : navigate(toLocation, from))\n            .catch((error) => isNavigationFailure(error)\n            ? // navigation redirects still mark the router as ready\n                isNavigationFailure(error, 2 /* ErrorTypes.NAVIGATION_GUARD_REDIRECT */)\n                    ? error\n                    : markAsReady(error) // also returns the error\n            : // reject any unknown error\n                triggerError(error, toLocation, from))\n            .then((failure) => {\n            if (failure) {\n                if (isNavigationFailure(failure, 2 /* ErrorTypes.NAVIGATION_GUARD_REDIRECT */)) {\n                    if ((process.env.NODE_ENV !== 'production') &&\n                        // we are redirecting to the same location we were already at\n                        isSameRouteLocation(stringifyQuery$1, resolve(failure.to), toLocation) &&\n                        // and we have done it a couple of times\n                        redirectedFrom &&\n                        // @ts-expect-error: added only in dev\n                        (redirectedFrom._count = redirectedFrom._count\n                            ? // @ts-expect-error\n                                redirectedFrom._count + 1\n                            : 1) > 30) {\n                        warn(`Detected a possibly infinite redirection in a navigation guard when going from \"${from.fullPath}\" to \"${toLocation.fullPath}\". Aborting to avoid a Stack Overflow.\\n Are you always returning a new location within a navigation guard? That would lead to this error. Only return when redirecting or aborting, that should fix this. This might break in production if not fixed.`);\n                        return Promise.reject(new Error('Infinite redirect in navigation guard'));\n                    }\n                    return pushWithRedirect(\n                    // keep options\n                    assign({\n                        // preserve an existing replacement but allow the redirect to override it\n                        replace,\n                    }, locationAsObject(failure.to), {\n                        state: typeof failure.to === 'object'\n                            ? assign({}, data, failure.to.state)\n                            : data,\n                        force,\n                    }), \n                    // preserve the original redirectedFrom if any\n                    redirectedFrom || toLocation);\n                }\n            }\n            else {\n                // if we fail we don't finalize the navigation\n                failure = finalizeNavigation(toLocation, from, true, replace, data);\n            }\n            triggerAfterEach(toLocation, from, failure);\n            return failure;\n        });\n    }\n    /**\n     * Helper to reject and skip all navigation guards if a new navigation happened\n     * @param to\n     * @param from\n     */\n    function checkCanceledNavigationAndReject(to, from) {\n        const error = checkCanceledNavigation(to, from);\n        return error ? Promise.reject(error) : Promise.resolve();\n    }\n    function runWithContext(fn) {\n        const app = installedApps.values().next().value;\n        // support Vue < 3.3\n        return app && typeof app.runWithContext === 'function'\n            ? app.runWithContext(fn)\n            : fn();\n    }\n    // TODO: refactor the whole before guards by internally using router.beforeEach\n    function navigate(to, from) {\n        let guards;\n        const [leavingRecords, updatingRecords, enteringRecords] = extractChangingRecords(to, from);\n        // all components here have been resolved once because we are leaving\n        guards = extractComponentsGuards(leavingRecords.reverse(), 'beforeRouteLeave', to, from);\n        // leavingRecords is already reversed\n        for (const record of leavingRecords) {\n            record.leaveGuards.forEach(guard => {\n                guards.push(guardToPromiseFn(guard, to, from));\n            });\n        }\n        const canceledNavigationCheck = checkCanceledNavigationAndReject.bind(null, to, from);\n        guards.push(canceledNavigationCheck);\n        // run the queue of per route beforeRouteLeave guards\n        return (runGuardQueue(guards)\n            .then(() => {\n            // check global guards beforeEach\n            guards = [];\n            for (const guard of beforeGuards.list()) {\n                guards.push(guardToPromiseFn(guard, to, from));\n            }\n            guards.push(canceledNavigationCheck);\n            return runGuardQueue(guards);\n        })\n            .then(() => {\n            // check in components beforeRouteUpdate\n            guards = extractComponentsGuards(updatingRecords, 'beforeRouteUpdate', to, from);\n            for (const record of updatingRecords) {\n                record.updateGuards.forEach(guard => {\n                    guards.push(guardToPromiseFn(guard, to, from));\n                });\n            }\n            guards.push(canceledNavigationCheck);\n            // run the queue of per route beforeEnter guards\n            return runGuardQueue(guards);\n        })\n            .then(() => {\n            // check the route beforeEnter\n            guards = [];\n            for (const record of enteringRecords) {\n                // do not trigger beforeEnter on reused views\n                if (record.beforeEnter) {\n                    if (isArray(record.beforeEnter)) {\n                        for (const beforeEnter of record.beforeEnter)\n                            guards.push(guardToPromiseFn(beforeEnter, to, from));\n                    }\n                    else {\n                        guards.push(guardToPromiseFn(record.beforeEnter, to, from));\n                    }\n                }\n            }\n            guards.push(canceledNavigationCheck);\n            // run the queue of per route beforeEnter guards\n            return runGuardQueue(guards);\n        })\n            .then(() => {\n            // NOTE: at this point to.matched is normalized and does not contain any () => Promise<Component>\n            // clear existing enterCallbacks, these are added by extractComponentsGuards\n            to.matched.forEach(record => (record.enterCallbacks = {}));\n            // check in-component beforeRouteEnter\n            guards = extractComponentsGuards(enteringRecords, 'beforeRouteEnter', to, from, runWithContext);\n            guards.push(canceledNavigationCheck);\n            // run the queue of per route beforeEnter guards\n            return runGuardQueue(guards);\n        })\n            .then(() => {\n            // check global guards beforeResolve\n            guards = [];\n            for (const guard of beforeResolveGuards.list()) {\n                guards.push(guardToPromiseFn(guard, to, from));\n            }\n            guards.push(canceledNavigationCheck);\n            return runGuardQueue(guards);\n        })\n            // catch any navigation canceled\n            .catch(err => isNavigationFailure(err, 8 /* ErrorTypes.NAVIGATION_CANCELLED */)\n            ? err\n            : Promise.reject(err)));\n    }\n    function triggerAfterEach(to, from, failure) {\n        // navigation is confirmed, call afterGuards\n        // TODO: wrap with error handlers\n        afterGuards\n            .list()\n            .forEach(guard => runWithContext(() => guard(to, from, failure)));\n    }\n    /**\n     * - Cleans up any navigation guards\n     * - Changes the url if necessary\n     * - Calls the scrollBehavior\n     */\n    function finalizeNavigation(toLocation, from, isPush, replace, data) {\n        // a more recent navigation took place\n        const error = checkCanceledNavigation(toLocation, from);\n        if (error)\n            return error;\n        // only consider as push if it's not the first navigation\n        const isFirstNavigation = from === START_LOCATION_NORMALIZED;\n        const state = !isBrowser ? {} : history.state;\n        // change URL only if the user did a push/replace and if it's not the initial navigation because\n        // it's just reflecting the url\n        if (isPush) {\n            // on the initial navigation, we want to reuse the scroll position from\n            // history state if it exists\n            if (replace || isFirstNavigation)\n                routerHistory.replace(toLocation.fullPath, assign({\n                    scroll: isFirstNavigation && state && state.scroll,\n                }, data));\n            else\n                routerHistory.push(toLocation.fullPath, data);\n        }\n        // accept current navigation\n        currentRoute.value = toLocation;\n        handleScroll(toLocation, from, isPush, isFirstNavigation);\n        markAsReady();\n    }\n    let removeHistoryListener;\n    // attach listener to history to trigger navigations\n    function setupListeners() {\n        // avoid setting up listeners twice due to an invalid first navigation\n        if (removeHistoryListener)\n            return;\n        removeHistoryListener = routerHistory.listen((to, _from, info) => {\n            if (!router.listening)\n                return;\n            // cannot be a redirect route because it was in history\n            const toLocation = resolve(to);\n            // due to dynamic routing, and to hash history with manual navigation\n            // (manually changing the url or calling history.hash = '#/somewhere'),\n            // there could be a redirect record in history\n            const shouldRedirect = handleRedirectRecord(toLocation);\n            if (shouldRedirect) {\n                pushWithRedirect(assign(shouldRedirect, { replace: true, force: true }), toLocation).catch(noop);\n                return;\n            }\n            pendingLocation = toLocation;\n            const from = currentRoute.value;\n            // TODO: should be moved to web history?\n            if (isBrowser) {\n                saveScrollPosition(getScrollKey(from.fullPath, info.delta), computeScrollPosition());\n            }\n            navigate(toLocation, from)\n                .catch((error) => {\n                if (isNavigationFailure(error, 4 /* ErrorTypes.NAVIGATION_ABORTED */ | 8 /* ErrorTypes.NAVIGATION_CANCELLED */)) {\n                    return error;\n                }\n                if (isNavigationFailure(error, 2 /* ErrorTypes.NAVIGATION_GUARD_REDIRECT */)) {\n                    // Here we could call if (info.delta) routerHistory.go(-info.delta,\n                    // false) but this is bug prone as we have no way to wait the\n                    // navigation to be finished before calling pushWithRedirect. Using\n                    // a setTimeout of 16ms seems to work but there is no guarantee for\n                    // it to work on every browser. So instead we do not restore the\n                    // history entry and trigger a new navigation as requested by the\n                    // navigation guard.\n                    // the error is already handled by router.push we just want to avoid\n                    // logging the error\n                    pushWithRedirect(assign(locationAsObject(error.to), {\n                        force: true,\n                    }), toLocation\n                    // avoid an uncaught rejection, let push call triggerError\n                    )\n                        .then(failure => {\n                        // manual change in hash history #916 ending up in the URL not\n                        // changing, but it was changed by the manual url change, so we\n                        // need to manually change it ourselves\n                        if (isNavigationFailure(failure, 4 /* ErrorTypes.NAVIGATION_ABORTED */ |\n                            16 /* ErrorTypes.NAVIGATION_DUPLICATED */) &&\n                            !info.delta &&\n                            info.type === NavigationType.pop) {\n                            routerHistory.go(-1, false);\n                        }\n                    })\n                        .catch(noop);\n                    // avoid the then branch\n                    return Promise.reject();\n                }\n                // do not restore history on unknown direction\n                if (info.delta) {\n                    routerHistory.go(-info.delta, false);\n                }\n                // unrecognized error, transfer to the global handler\n                return triggerError(error, toLocation, from);\n            })\n                .then((failure) => {\n                failure =\n                    failure ||\n                        finalizeNavigation(\n                        // after navigation, all matched components are resolved\n                        toLocation, from, false);\n                // revert the navigation\n                if (failure) {\n                    if (info.delta &&\n                        // a new navigation has been triggered, so we do not want to revert, that will change the current history\n                        // entry while a different route is displayed\n                        !isNavigationFailure(failure, 8 /* ErrorTypes.NAVIGATION_CANCELLED */)) {\n                        routerHistory.go(-info.delta, false);\n                    }\n                    else if (info.type === NavigationType.pop &&\n                        isNavigationFailure(failure, 4 /* ErrorTypes.NAVIGATION_ABORTED */ | 16 /* ErrorTypes.NAVIGATION_DUPLICATED */)) {\n                        // manual change in hash history #916\n                        // it's like a push but lacks the information of the direction\n                        routerHistory.go(-1, false);\n                    }\n                }\n                triggerAfterEach(toLocation, from, failure);\n            })\n                // avoid warnings in the console about uncaught rejections, they are logged by triggerErrors\n                .catch(noop);\n        });\n    }\n    // Initialization and Errors\n    let readyHandlers = useCallbacks();\n    let errorListeners = useCallbacks();\n    let ready;\n    /**\n     * Trigger errorListeners added via onError and throws the error as well\n     *\n     * @param error - error to throw\n     * @param to - location we were navigating to when the error happened\n     * @param from - location we were navigating from when the error happened\n     * @returns the error as a rejected promise\n     */\n    function triggerError(error, to, from) {\n        markAsReady(error);\n        const list = errorListeners.list();\n        if (list.length) {\n            list.forEach(handler => handler(error, to, from));\n        }\n        else {\n            if ((process.env.NODE_ENV !== 'production')) {\n                warn('uncaught error during route navigation:');\n            }\n            console.error(error);\n        }\n        // reject the error no matter there were error listeners or not\n        return Promise.reject(error);\n    }\n    function isReady() {\n        if (ready && currentRoute.value !== START_LOCATION_NORMALIZED)\n            return Promise.resolve();\n        return new Promise((resolve, reject) => {\n            readyHandlers.add([resolve, reject]);\n        });\n    }\n    function markAsReady(err) {\n        if (!ready) {\n            // still not ready if an error happened\n            ready = !err;\n            setupListeners();\n            readyHandlers\n                .list()\n                .forEach(([resolve, reject]) => (err ? reject(err) : resolve()));\n            readyHandlers.reset();\n        }\n        return err;\n    }\n    // Scroll behavior\n    function handleScroll(to, from, isPush, isFirstNavigation) {\n        const { scrollBehavior } = options;\n        if (!isBrowser || !scrollBehavior)\n            return Promise.resolve();\n        const scrollPosition = (!isPush && getSavedScrollPosition(getScrollKey(to.fullPath, 0))) ||\n            ((isFirstNavigation || !isPush) &&\n                history.state &&\n                history.state.scroll) ||\n            null;\n        return nextTick()\n            .then(() => scrollBehavior(to, from, scrollPosition))\n            .then(position => position && scrollToPosition(position))\n            .catch(err => triggerError(err, to, from));\n    }\n    const go = (delta) => routerHistory.go(delta);\n    let started;\n    const installedApps = new Set();\n    const router = {\n        currentRoute,\n        listening: true,\n        addRoute,\n        removeRoute,\n        clearRoutes: matcher.clearRoutes,\n        hasRoute,\n        getRoutes,\n        resolve,\n        options,\n        push,\n        replace,\n        go,\n        back: () => go(-1),\n        forward: () => go(1),\n        beforeEach: beforeGuards.add,\n        beforeResolve: beforeResolveGuards.add,\n        afterEach: afterGuards.add,\n        onError: errorListeners.add,\n        isReady,\n        install(app) {\n            const router = this;\n            app.component('RouterLink', RouterLink);\n            app.component('RouterView', RouterView);\n            app.config.globalProperties.$router = router;\n            Object.defineProperty(app.config.globalProperties, '$route', {\n                enumerable: true,\n                get: () => unref(currentRoute),\n            });\n            // this initial navigation is only necessary on client, on server it doesn't\n            // make sense because it will create an extra unnecessary navigation and could\n            // lead to problems\n            if (isBrowser &&\n                // used for the initial navigation client side to avoid pushing\n                // multiple times when the router is used in multiple apps\n                !started &&\n                currentRoute.value === START_LOCATION_NORMALIZED) {\n                // see above\n                started = true;\n                push(routerHistory.location).catch(err => {\n                    if ((process.env.NODE_ENV !== 'production'))\n                        warn('Unexpected error when starting the router:', err);\n                });\n            }\n            const reactiveRoute = {};\n            for (const key in START_LOCATION_NORMALIZED) {\n                Object.defineProperty(reactiveRoute, key, {\n                    get: () => currentRoute.value[key],\n                    enumerable: true,\n                });\n            }\n            app.provide(routerKey, router);\n            app.provide(routeLocationKey, shallowReactive(reactiveRoute));\n            app.provide(routerViewLocationKey, currentRoute);\n            const unmountApp = app.unmount;\n            installedApps.add(app);\n            app.unmount = function () {\n                installedApps.delete(app);\n                // the router is not attached to an app anymore\n                if (installedApps.size < 1) {\n                    // invalidate the current navigation\n                    pendingLocation = START_LOCATION_NORMALIZED;\n                    removeHistoryListener && removeHistoryListener();\n                    removeHistoryListener = null;\n                    currentRoute.value = START_LOCATION_NORMALIZED;\n                    started = false;\n                    ready = false;\n                }\n                unmountApp();\n            };\n            // TODO: this probably needs to be updated so it can be used by vue-termui\n            if (((process.env.NODE_ENV !== 'production') || __VUE_PROD_DEVTOOLS__) && isBrowser) {\n                addDevtools(app, router, matcher);\n            }\n        },\n    };\n    // TODO: type this as NavigationGuardReturn or similar instead of any\n    function runGuardQueue(guards) {\n        return guards.reduce((promise, guard) => promise.then(() => runWithContext(guard)), Promise.resolve());\n    }\n    return router;\n}\nfunction extractChangingRecords(to, from) {\n    const leavingRecords = [];\n    const updatingRecords = [];\n    const enteringRecords = [];\n    const len = Math.max(from.matched.length, to.matched.length);\n    for (let i = 0; i < len; i++) {\n        const recordFrom = from.matched[i];\n        if (recordFrom) {\n            if (to.matched.find(record => isSameRouteRecord(record, recordFrom)))\n                updatingRecords.push(recordFrom);\n            else\n                leavingRecords.push(recordFrom);\n        }\n        const recordTo = to.matched[i];\n        if (recordTo) {\n            // the type doesn't matter because we are comparing per reference\n            if (!from.matched.find(record => isSameRouteRecord(record, recordTo))) {\n                enteringRecords.push(recordTo);\n            }\n        }\n    }\n    return [leavingRecords, updatingRecords, enteringRecords];\n}\n\n/**\n * Returns the router instance. Equivalent to using `$router` inside\n * templates.\n */\nfunction useRouter() {\n    return inject(routerKey);\n}\n/**\n * Returns the current route location. Equivalent to using `$route` inside\n * templates.\n */\nfunction useRoute(_name) {\n    return inject(routeLocationKey);\n}\n\nexport { NavigationFailureType, RouterLink, RouterView, START_LOCATION_NORMALIZED as START_LOCATION, createMemoryHistory, createRouter, createRouterMatcher, createWebHashHistory, createWebHistory, isNavigationFailure, loadRouteLocation, matchedRouteKey, onBeforeRouteLeave, onBeforeRouteUpdate, parseQuery, routeLocationKey, routerKey, routerViewLocationKey, stringifyQuery, useLink, useRoute, useRouter, viewDepthKey };\n","import { getCurrentInstance } from 'vue';\nimport { useRoute } from 'vue-router';\n\n/**\n * 页面上下文信息接口\n */\nexport interface 页面上下文信息 {\n  页面名称: string;\n  页面路径: string;\n}\n\n/**\n * 从路由获取当前页面名称\n * 这个函数可以在任何地方调用,包括指令钩子\n */\nexport function 获取当前页面名称(): string {\n  // 尝试从当前Vue实例获取路由\n  const instance = getCurrentInstance();\n\n  if (instance) {\n    // 在组件上下文中,使用 useRoute\n    try {\n      const route = useRoute();\n      return (route.name as string) || '未知页面';\n    } catch {\n      // 如果 useRoute 失败,尝试从实例中获取\n      const router = instance.appContext.config.globalProperties.$router;\n      if (router && router.currentRoute) {\n        return (router.currentRoute.value.name as string) || '未知页面';\n      }\n    }\n  }\n\n  // 如果无法获取路由信息,尝试从全局路由实例\n  // 这需要在应用中设置全局路由\n  if (typeof window !== 'undefined' && (window as any).__VUE_ROUTER__) {\n    const router = (window as any).__VUE_ROUTER__;\n    return (router.currentRoute.value.name as string) || '未知页面';\n  }\n\n  return '未知页面';\n}\n\n/**\n * 提供页面上下文给子组件\n * 保留这个函数以保持向后兼容,但实际上不再使用 provide\n */\nexport function 提供页面上下文(_页面名称: string, _页面路径: string) {\n  // 这个函数现在是空操作,因为我们直接从路由获取信息\n  // 保留它是为了不破坏现有代码\n}\n\n/**\n * 在组件或指令中获取页面上下文\n */\nexport function 使用页面上下文(): 页面上下文信息 {\n  const 页面名称 = 获取当前页面名称();\n\n  return {\n    页面名称,\n    页面路径: '/', // 路径信息可以后续从路由中获取\n  };\n}\n\n/**\n * 根据页面上下文生成指令来源标识\n * 格式: v-指令名称-页面名称\n */\nexport function 生成页面级指令来源(指令名称: string): string {\n  const 页面名称 = 获取当前页面名称();\n  return `v-${指令名称}-${页面名称}`;\n}\n","import { invoke } from '@tauri-apps/api/core';\nimport { 获取当前页面名称 } from './页面上下文';\n\n/**\n * 任务管理API - 在TypeScript代码中直接管理Modbus任务\n */\n\n/**\n * Modbus操作类型\n */\nexport enum Modbus操作类型 {\n  读取保持寄存器 = '读取保持寄存器',\n  读取线圈 = '读取线圈',\n  写入单个保持寄存器 = '写入单个保持寄存器',\n  写入多个保持寄存器 = '写入多个保持寄存器',\n  写入单个线圈 = '写入单个线圈',\n  写入多个线圈 = '写入多个线圈',\n  发送原始字节 = '发送原始字节',\n}\n\ninterface Modbus任务公共字段 {\n  操作: {\n    操作类型: Modbus操作类型 | string;\n    [key: string]: any;\n  };\n  备注?: string;\n  指令来源?: string; // 如果不提供,会自动生成\n}\n\n/**\n * Modbus任务配置\n */\nexport type Modbus任务配置 = Modbus任务公共字段 & {\n  设备名称型号: string;\n};\n\n/**\n * 添加单个Modbus任务\n * \n * @example\n * ```typescript\n * // 读取保持寄存器\n * const 队列长度 = await 添加Modbus任务({\n *   设备名称型号: '车床PLC1',\n *   操作: {\n *     操作类型: Modbus操作类型.读取保持寄存器,\n *     起始地址: 100,\n *     数量: 10\n *   },\n *   备注: '读取温度数据'\n * });\n * ```\n */\nexport async function 添加Modbus任务(任务配置: Modbus任务配置): Promise<number> {\n  const 页面名称 = 获取当前页面名称();\n  const 标准化设备名称 = 任务配置.设备名称型号.trim();\n\n  if (标准化设备名称.length === 0) {\n    throw new Error('添加Modbus任务失败: 设备名称型号不能为空');\n  }\n\n  const 完整任务 = {\n    ...任务配置,\n    设备名称型号: 标准化设备名称,\n    指令来源: 任务配置.指令来源 || `TypeScript-${页面名称}`,\n  };\n\n  try {\n    const 队列长度 = await invoke<number>('添加Modbus任务', { 任务: 完整任务 });\n    console.log(`✓ 添加任务成功: ${任务配置.备注 || '未命名'}, 队列长度: ${队列长度}`);\n    return 队列长度;\n  } catch (错误) {\n    console.error('✗ 添加任务失败:', 错误, 任务配置);\n    throw 错误;\n  }\n}\n\n/**\n * 批量添加Modbus任务\n * \n * @example\n * ```typescript\n * const 结果 = await 批量添加Modbus任务([\n *   { 设备名称型号: '车床PLC1', 操作: {...} },\n *   { 设备名称型号: '车床PLC2', 操作: {...} },\n * ]);\n * console.log(`成功: ${结果.成功数量}, 失败: ${结果.失败数量}`);\n * ```\n */\nexport async function 批量添加Modbus任务(任务列表: Modbus任务配置[]): Promise<{\n  成功数量: number;\n  失败数量: number;\n  队列长度列表: number[];\n  错误列表: Array<{ 任务: Modbus任务配置; 错误: any }>;\n}> {\n  const 页面名称 = 获取当前页面名称();\n  let 成功数量 = 0;\n  let 失败数量 = 0;\n  const 队列长度列表: number[] = [];\n  const 错误列表: Array<{ 任务: Modbus任务配置; 错误: any }> = [];\n\n  for (const 任务配置 of 任务列表) {\n    try {\n      const 队列长度 = await 添加Modbus任务({\n        ...任务配置,\n        指令来源: 任务配置.指令来源 || `TypeScript-批量-${页面名称}`,\n      });\n      成功数量++;\n      队列长度列表.push(队列长度);\n    } catch (错误) {\n      失败数量++;\n      错误列表.push({ 任务: 任务配置, 错误 });\n      console.error('✗ 批量添加任务失败:', 错误, 任务配置);\n    }\n  }\n\n  console.log(`批量添加任务完成: 成功 ${成功数量}, 失败 ${失败数量}`);\n  return { 成功数量, 失败数量, 队列长度列表, 错误列表 };\n}\n\n/**\n * 清除指定来源的所有任务\n * \n * @param 指令来源 - 要清除的任务来源标识,可以是部分匹配\n * @returns 被清除的任务数量\n * \n * @example\n * ```typescript\n * // 清除当前页面的所有TypeScript添加的任务\n * const 清除数量 = await 清除指定来源任务('TypeScript');\n * \n * // 清除特定标识的任务\n * const 清除数量 = await 清除指定来源任务('我的自定义任务');\n * ```\n */\nexport async function 清除指定来源任务(指令来源: string): Promise<number> {\n  try {\n    const 清除数量 = await invoke<number>('清除指定来源任务', { 指令来源 });\n    console.log(`✓ 清除任务成功: 来源=\"${指令来源}\", 数量=${清除数量}`);\n    return 清除数量;\n  } catch (错误) {\n    console.error('✗ 清除任务失败:', 错误);\n    throw 错误;\n  }\n}\n\n/**\n * 清除当前页面的所有任务\n * \n * @example\n * ```typescript\n * // 在页面卸载时清除该页面的所有任务\n * onUnmounted(async () => {\n *   await 清除当前页面任务();\n * });\n * ```\n */\nexport async function 清除当前页面任务(): Promise<number> {\n  const 页面名称 = 获取当前页面名称();\n  return await 清除指定来源任务(页面名称);\n}\n\n/**\n * 清除所有TypeScript代码添加的任务\n */\nexport async function 清除所有TypeScript任务(): Promise<number> {\n  return await 清除指定来源任务('TypeScript');\n}\n\n// ==================== 便捷函数 ====================\n\n/**\n * 读取保持寄存器任务\n */\nexport async function 添加读取保持寄存器任务(配置: {\n  设备名称型号: string;\n  起始地址: number;\n  数量: number;\n  备注?: string;\n  指令来源?: string;\n}): Promise<number> {\n  return await 添加Modbus任务({\n    设备名称型号: 配置.设备名称型号,\n    操作: {\n      操作类型: Modbus操作类型.读取保持寄存器,\n      起始地址: 配置.起始地址,\n      数量: 配置.数量,\n    },\n    备注: 配置.备注,\n    指令来源: 配置.指令来源,\n  });\n}\n\n/**\n * 读取线圈任务\n */\nexport async function 添加读取线圈任务(配置: {\n  设备名称型号: string;\n  起始地址: number;\n  数量: number;\n  备注?: string;\n  指令来源?: string;\n}): Promise<number> {\n  return await 添加Modbus任务({\n    设备名称型号: 配置.设备名称型号,\n    操作: {\n      操作类型: Modbus操作类型.读取线圈,\n      起始地址: 配置.起始地址,\n      数量: 配置.数量,\n    },\n    备注: 配置.备注,\n    指令来源: 配置.指令来源,\n  });\n}\n\n/**\n * 写入单个保持寄存器任务\n */\nexport async function 添加写入单个寄存器任务(配置: {\n  设备名称型号: string;\n  寄存器地址: number;\n  数值: number;\n  备注?: string;\n  指令来源?: string;\n}): Promise<number> {\n  return await 添加Modbus任务({\n    设备名称型号: 配置.设备名称型号,\n    操作: {\n      操作类型: Modbus操作类型.写入单个保持寄存器,\n      寄存器地址: 配置.寄存器地址,\n      数值: 配置.数值,\n    },\n    备注: 配置.备注,\n    指令来源: 配置.指令来源,\n  });\n}\n\n/**\n * 写入多个保持寄存器任务\n */\nexport async function 添加写入多个寄存器任务(配置: {\n  设备名称型号: string;\n  起始地址: number;\n  数值: number[];\n  备注?: string;\n  指令来源?: string;\n}): Promise<number> {\n  return await 添加Modbus任务({\n    设备名称型号: 配置.设备名称型号,\n    操作: {\n      操作类型: Modbus操作类型.写入多个保持寄存器,\n      起始地址: 配置.起始地址,\n      数值: 配置.数值,\n    },\n    备注: 配置.备注,\n    指令来源: 配置.指令来源,\n  });\n}\n\n/**\n * 写入单个线圈任务\n */\nexport async function 添加写入单个线圈任务(配置: {\n  设备名称型号: string;\n  线圈地址: number;\n  状态: boolean;\n  备注?: string;\n  指令来源?: string;\n}): Promise<number> {\n  return await 添加Modbus任务({\n    设备名称型号: 配置.设备名称型号,\n    操作: {\n      操作类型: Modbus操作类型.写入单个线圈,\n      线圈地址: 配置.线圈地址,\n      状态: 配置.状态,\n    },\n    备注: 配置.备注,\n    指令来源: 配置.指令来源,\n  });\n}\n\n/**\n * 写入多个线圈任务\n */\nexport async function 添加写入多个线圈任务(配置: {\n  设备名称型号: string;\n  起始地址: number;\n  状态: boolean[];\n  备注?: string;\n  指令来源?: string;\n}): Promise<number> {\n  return await 添加Modbus任务({\n    设备名称型号: 配置.设备名称型号,\n    操作: {\n      操作类型: Modbus操作类型.写入多个线圈,\n      起始地址: 配置.起始地址,\n      状态: 配置.状态,\n    },\n    备注: 配置.备注,\n    指令来源: 配置.指令来源,\n  });\n}\n\n/**\n * 发送原始字节任务\n */\nexport async function 添加原始字节任务(配置: {\n  设备名称型号: string;\n  数据: number[];\n  期望接收字节数?: number;\n  备注?: string;\n  指令来源?: string;\n}): Promise<number> {\n  return await 添加Modbus任务({\n    设备名称型号: 配置.设备名称型号,\n    操作: {\n      操作类型: Modbus操作类型.发送原始字节,\n      数据: 配置.数据,\n      期望接收字节数: 配置.期望接收字节数,\n    },\n    备注: 配置.备注,\n    指令来源: 配置.指令来源,\n  });\n}\n","import { invoke } from \"@tauri-apps/api/core\";\nimport { 清除指定来源任务 } from \"./任务管理API\";\nimport { 生成页面级指令来源 } from \"./页面上下文\";\n\n// ==================== 类型定义 ====================\n\nexport interface 前端Modbus任务 {\n  设备名称型号: string;\n  备注?: string;\n  指令来源: string;\n  操作: {\n    操作类型: string;\n    [键: string]: unknown;\n  };\n}\n\nexport interface 上报执行结果 {\n  是否成功: boolean;\n  成功任务数量: number;\n  错误任务: Array<{ 任务: 前端Modbus任务; 错误: unknown }>;\n  错误信息?: string;\n  成功队列长度: number[];\n}\n\nexport interface 线圈状态事件详情 {\n  设备名称型号: string;\n  线圈地址: number;\n  状态: boolean;\n}\n\nexport interface 保持寄存器事件详情 {\n  设备名称型号: string;\n  起始地址: number;\n  数据: number[];\n}\n\nexport interface 设备状态事件详情 {\n  设备名称型号: string;\n  状态: string;\n  时间戳?: number;\n}\n\n\nexport interface 线圈任务参数 {\n  设备名称型号: string;\n  地址: number;\n  备注?: string;\n  指令来源?: string;\n}\n\nexport interface 寄存器任务参数 {\n  设备名称型号: string;\n  起始地址: number;\n  数量: number;\n  备注?: string;\n  指令来源?: string;\n}\n\nexport interface 写入单个线圈参数 extends 线圈任务参数 {\n  状态: boolean;\n}\n\nexport interface 写入单个寄存器参数 extends 线圈任务参数 {\n  数值: number;\n}\n\nexport interface 写入多个寄存器参数 extends 寄存器任务参数 {\n  数值: number[];\n}\n\nexport interface 写入多个线圈参数 extends 线圈任务参数 {\n  状态列表: boolean[];\n}\n\nexport type 线圈寄存器读写类型 = \"读取\" | \"写入单个\" | \"写入多个\";\n\nexport type 线圈读取操作参数 = 线圈任务参数 & {\n  读写类型: \"读取\";\n  数量?: number;\n  是否读写一次?: boolean;\n  读取回调?: (\n    状态列表: boolean[],\n    当前状态: boolean | boolean[] | null\n  ) => void;\n  状态?: never;\n  状态列表?: never;\n};\n\nexport type 线圈写入单个操作参数 = 线圈任务参数 & {\n  读写类型: \"写入单个\";\n  状态: boolean;\n  状态列表?: never;\n  数量?: never;\n  是否读写一次?: never;\n  读取回调?: never;\n};\n\nexport type 线圈写入多个操作参数 = 线圈任务参数 & {\n  读写类型: \"写入多个\";\n  状态列表: boolean[];\n  状态?: never;\n  数量?: never;\n  是否读写一次?: never;\n  读取回调?: never;\n};\n\nexport type 线圈读写操作参数 =\n  | 线圈读取操作参数\n  | 线圈写入单个操作参数\n  | 线圈写入多个操作参数;\n\nexport interface 线圈读写操作结果 {\n  上报结果: 上报执行结果;\n  取消监听?: () => void;\n  指令来源: string;\n}\nexport interface 寄存器读写操作参数 extends Partial<寄存器任务参数> {\n  设备名称型号: string;\n  地址: number;\n  读写类型: 线圈寄存器读写类型;\n  数量?: number;\n  数值?: number | number[];\n  数据类型: 数据类型;\n  比例系数: number;\n  小数位数: number;\n  是否读写一次?: boolean;\n  读取回调?: (\n    寄存器数据: number[],\n    数值: number | number[] | null\n  ) => void;\n}\n\nexport interface 寄存器读写操作结果 {\n  上报结果: 上报执行结果;\n  取消监听?: () => void;\n  指令来源: string;\n}\n\n// ==================== 常量定义 ====================\n\nexport const 线圈状态事件名称 = \"modbus-线圈状态更新\";\nexport const 保持寄存器事件名称 = \"modbus-保持寄存器更新\";\nexport const 设备状态事件名称 = \"modbus-设备状态变化\";\n\n// ==================== 工具函数 ====================\n\nconst 标准化设备名称 = (设备名称型号: string): string =>\n  设备名称型号.trim();\n\nconst 提取非空设备名称 = (原始名称?: string): string => {\n  if (!原始名称) {\n    return \"\";\n  }\n  const 标准化名称 = 标准化设备名称(原始名称);\n  return 标准化名称.length > 0 ? 标准化名称 : \"\";\n};\n\n/**\n * 生成线圈匹配键,用于事件监听匹配\n */\nexport const 生成线圈匹配键 = (\n  设备名称型号: string,\n  线圈地址: number\n): string => `${标准化设备名称(设备名称型号)}:${线圈地址}`;\n\n/**\n * 生成寄存器匹配键,用于事件监听匹配\n */\nexport const 生成寄存器匹配键 = (\n  设备名称型号: string,\n  寄存器地址: number\n): string => `${标准化设备名称(设备名称型号)}:${寄存器地址}`;\n\n// ==================== 任务操作函数 ====================\n\n/**\n * 上报任务至队列\n * @param 任务列表 - 要添加的Modbus任务列表\n * @param 来源 - 任务来源说明\n * @returns 执行结果,包含成功和失败信息\n */\nexport const 上报任务至队列 = async (\n  任务列表: 前端Modbus任务[],\n  来源: string\n): Promise<上报执行结果> => {\n  if (任务列表.length === 0) {\n    return {\n      是否成功: true,\n      成功任务数量: 0,\n      错误任务: [],\n      成功队列长度: [],\n    };\n  }\n\n  const 错误任务: Array<{ 任务: 前端Modbus任务; 错误: unknown }> = [];\n  const 成功队列长度: number[] = [];\n  let 成功任务数量 = 0;\n\n  for (const 任务 of 任务列表) {\n    try {\n      const 队列长度 = await invoke<number>(\"添加Modbus任务\", { 任务 });\n      成功任务数量 += 1;\n      成功队列长度.push(队列长度);\n      console.info(\n        `工业组件API ${来源} 已入队，当前队列长度: ${队列长度}`,\n        任务\n      );\n    } catch (错误) {\n      console.error(`工业组件API ${来源} 入队失败`, 错误, 任务);\n      错误任务.push({ 任务, 错误 });\n    }\n  }\n\n  if (错误任务.length > 0) {\n    return {\n      是否成功: false,\n      成功任务数量,\n      错误任务,\n      错误信息: \"部分或全部任务入队失败，请检查错误任务列表\",\n      成功队列长度,\n    };\n  }\n\n  return {\n    是否成功: true,\n    成功任务数量,\n    错误任务,\n    成功队列长度,\n  };\n};\n\n/**\n * 创建读取线圈任务\n */\nexport const 创建读取线圈任务 = (参数: 寄存器任务参数): 前端Modbus任务 => {\n  const 设备名称 = 标准化设备名称(参数.设备名称型号);\n  return {\n    设备名称型号: 设备名称,\n    备注: 参数.备注 ?? `${设备名称}-读取线圈`,\n    指令来源: 参数.指令来源 ?? 生成页面级指令来源(\"工业组件API\"),\n    操作: {\n      操作类型: \"读取线圈\",\n      起始地址: 参数.起始地址,\n      数量: 参数.数量,\n    },\n  };\n};\n\n/**\n * 创建读取保持寄存器任务\n */\nexport const 创建读取保持寄存器任务 = (参数: 寄存器任务参数): 前端Modbus任务 => {\n  const 设备名称 = 标准化设备名称(参数.设备名称型号);\n  return {\n    设备名称型号: 设备名称,\n    备注: 参数.备注 ?? `${设备名称}-读取保持寄存器`,\n    指令来源: 参数.指令来源 ?? 生成页面级指令来源(\"工业组件API\"),\n    操作: {\n      操作类型: \"读取保持寄存器\",\n      起始地址: 参数.起始地址,\n      数量: 参数.数量,\n    },\n  };\n};\n\n/**\n * 创建写入单个线圈任务\n */\nexport const 创建写入单个线圈任务 = (参数: 写入单个线圈参数): 前端Modbus任务 => {\n  const 设备名称 = 标准化设备名称(参数.设备名称型号);\n  return {\n    设备名称型号: 设备名称,\n    备注: 参数.备注 ?? `${设备名称}-写入单个线圈`,\n    指令来源: 参数.指令来源 ?? 生成页面级指令来源(\"工业组件API\"),\n    操作: {\n      操作类型: \"写入单个线圈\",\n      线圈地址: 参数.地址,\n      状态: 参数.状态,\n    },\n  };\n};\n\n/**\n * 创建写入多个线圈任务\n */\nexport const 创建写入多个线圈任务 = (\n  参数: 写入多个线圈参数\n): 前端Modbus任务 => {\n  const 设备名称 = 标准化设备名称(参数.设备名称型号);\n  return {\n    设备名称型号: 设备名称,\n    备注: 参数.备注 ?? `${设备名称}-写入多个线圈`,\n    指令来源: 参数.指令来源 ?? 生成页面级指令来源(\"工业组件API\"),\n    操作: {\n      操作类型: \"写入多个线圈\",\n      起始地址: 参数.地址,\n      状态: 参数.状态列表,\n    },\n  };\n};\n\n/**\n * 创建写入单个保持寄存器任务\n */\nexport const 创建写入单个保持寄存器任务 = (\n  参数: 写入单个寄存器参数\n): 前端Modbus任务 => {\n  const 设备名称 = 标准化设备名称(参数.设备名称型号);\n  return {\n    设备名称型号: 设备名称,\n    备注: 参数.备注 ?? `${设备名称}-写入单个保持寄存器`,\n    指令来源: 参数.指令来源 ?? 生成页面级指令来源(\"工业组件API\"),\n    操作: {\n      操作类型: \"写入单个保持寄存器\",\n      寄存器地址: 参数.地址,\n      数值: 参数.数值,\n    },\n  };\n};\n\n/**\n * 创建写入多个保持寄存器任务\n */\nexport const 创建写入多个保持寄存器任务 = (\n  参数: 写入多个寄存器参数\n): 前端Modbus任务 => {\n  const 设备名称 = 标准化设备名称(参数.设备名称型号);\n  return {\n    设备名称型号: 设备名称,\n    备注: 参数.备注 ?? `${设备名称}-写入多个保持寄存器`,\n    指令来源: 参数.指令来源 ?? 生成页面级指令来源(\"工业组件API\"),\n    操作: {\n      操作类型: \"写入多个保持寄存器\",\n      起始地址: 参数.起始地址,\n      数值: 参数.数值,\n    },\n  };\n};\n\n/**\n * 根据配置执行线圈读写操作\n * @param 配置 - 线圈读写操作参数\n * @returns 上报结果与可选的取消监听函数\n */\nexport const 执行线圈读写操作 = async (\n  配置: 线圈读写操作参数\n): Promise<线圈读写操作结果> => {\n  const { 设备名称型号, 地址, 读写类型 } = 配置;\n\n  if (!设备名称型号 || 设备名称型号.trim().length === 0) {\n    throw new Error(\"设备名称型号不能为空\");\n  }\n\n  if (!Number.isInteger(地址) || 地址 < 0 || 地址 > 0xffff) {\n    throw new Error(\"线圈地址必须是 0-65535 的整数\");\n  }\n\n  const 标准化名称 = 标准化设备名称(设备名称型号);\n  const 指令来源 =\n    配置.指令来源 ?? 生成页面级指令来源(\"工业组件API-线圈读写\");\n\n  if (读写类型 === \"读取\") {\n    const 是否读写一次 = 配置.是否读写一次 ?? true;\n    const 数量 = 配置.数量 ?? 1;\n    if (!Number.isInteger(数量) || 数量 <= 0) {\n      throw new Error(\"读取数量必须是正整数\");\n    }\n\n    let 停止监听函数: (() => void) | undefined;\n    let 取消监听函数: (() => void) | undefined;\n    let 已清除任务 = false;\n\n    const 清理任务 = () => {\n      if (已清除任务) {\n        return;\n      }\n      已清除任务 = true;\n      void 清除指定来源任务(指令来源).catch((错误) => {\n        console.warn(`线圈读写封装清除任务失败`, 错误);\n      });\n    };\n\n    const 停止监听并清理 = () => {\n      停止监听函数?.();\n      停止监听函数 = undefined;\n      清理任务();\n      取消监听函数 = undefined;\n    };\n\n    取消监听函数 = 停止监听并清理;\n\n    const 任务 = 创建读取线圈任务({\n      设备名称型号: 标准化名称,\n      起始地址: 地址,\n      数量,\n      备注: 配置.备注 ?? `${标准化名称}-线圈读取封装`,\n      指令来源,\n    });\n\n    if (配置.读取回调 || 是否读写一次) {\n      if (数量 === 1) {\n        const 匹配键 = 生成线圈匹配键(标准化名称, 地址);\n\n        let 已触发一次 = false;\n        停止监听函数 = 监听特定线圈状态(匹配键, (状态) => {\n          配置.读取回调?.([状态], 状态);\n          if (是否读写一次 && !已触发一次) {\n            已触发一次 = true;\n            停止监听并清理();\n          }\n        });\n      } else {\n        const 起始地址 = 地址;\n        let 已触发一次 = false;\n        const 状态缓存 = new Map<number, boolean>();\n\n        const 尝试触发回调 = () => {\n          if (状态缓存.size < 数量) {\n            return;\n          }\n          const 状态列表: boolean[] = [];\n          for (let 偏移 = 0; 偏移 < 数量; 偏移 += 1) {\n            状态列表.push(状态缓存.get(偏移) ?? false);\n          }\n          const 当前状态 = 状态列表.length === 0 ? null : 状态列表;\n          配置.读取回调?.(状态列表, 当前状态);\n          if (是否读写一次 && !已触发一次) {\n            已触发一次 = true;\n            停止监听并清理();\n          }\n        };\n\n        停止监听函数 = 监听线圈状态((详情) => {\n          const 事件设备名称 = 提取非空设备名称(\n            详情.设备名称型号\n          );\n          if (事件设备名称 !== 标准化名称) {\n            return;\n          }\n\n          const 偏移 = 详情.线圈地址 - 起始地址;\n          if (偏移 < 0 || 偏移 >= 数量) {\n            return;\n          }\n\n          状态缓存.set(偏移, 详情.状态);\n          尝试触发回调();\n        });\n      }\n    }\n\n    const 上报结果 = await 上报任务至队列([任务], \"线圈读写封装\");\n\n    if (!上报结果.是否成功) {\n      取消监听函数?.();\n    }\n\n    return {\n      上报结果,\n      取消监听: 取消监听函数,\n      指令来源,\n    };\n  }\n\n  if (读写类型 === \"写入多个\") {\n    const 状态列表 = 配置.状态列表;\n    if (!状态列表 || 状态列表.length === 0) {\n      throw new Error(\"写入多个线圈操作必须提供至少一个布尔状态\");\n    }\n    if (!状态列表.every((项目) => typeof 项目 === \"boolean\")) {\n      throw new Error(\"写入多个线圈的状态列表必须全部为布尔值\");\n    }\n\n    const 任务 = 创建写入多个线圈任务({\n      设备名称型号: 标准化名称,\n      地址,\n      状态列表,\n      备注: 配置.备注 ?? `${标准化名称}-线圈批量写入封装`,\n      指令来源,\n    });\n\n    const 上报结果 = await 上报任务至队列([任务], \"线圈读写封装\");\n\n    return {\n      上报结果,\n      指令来源,\n    };\n  }\n\n  if (读写类型 === \"写入单个\") {\n    if (typeof 配置.状态 !== \"boolean\") {\n      throw new Error(\"写入线圈操作必须提供布尔类型的状态\");\n    }\n\n    const 任务 = 创建写入单个线圈任务({\n      设备名称型号: 标准化名称,\n      地址,\n      状态: 配置.状态,\n      备注: 配置.备注 ?? `${标准化名称}-线圈写入封装`,\n      指令来源,\n    });\n\n    const 上报结果 = await 上报任务至队列([任务], \"线圈读写封装\");\n\n    return {\n      上报结果,\n      指令来源,\n    };\n  }\n\n  throw new Error(`不支持的线圈读写类型: ${读写类型}`);\n};\n\n/**\n * 根据配置执行寄存器读写操作\n * @param 配置 - 寄存器读写操作参数\n * @returns 上报结果与可选的取消监听函数\n */\nexport const 执行寄存器读写操作 = async (\n  配置: 寄存器读写操作参数\n): Promise<寄存器读写操作结果> => {\n  const { 设备名称型号, 地址, 读写类型 } = 配置;\n\n  if (!设备名称型号 || 设备名称型号.trim().length === 0) {\n    throw new Error(\"设备名称型号不能为空\");\n  }\n\n  if (!Number.isInteger(地址) || 地址 < 0 || 地址 > 0xffff) {\n    throw new Error(\"寄存器地址必须是 0-65535 的整数\");\n  }\n\n  const 标准化名称 = 标准化设备名称(设备名称型号);\n  const 指令来源 = 配置.指令来源 ?? 生成页面级指令来源(\"工业组件API-寄存器读写\");\n\n  if (读写类型 === \"读取\") {\n    const 是否读写一次 = 配置.是否读写一次 ?? true;\n    const 数据类型 = 配置.数据类型;\n    const 寄存器块大小 = Math.max(1, 获取数据类型寄存器数量(数据类型));\n    const 逻辑数量 = 配置.数量 ?? 1;\n    if (!Number.isInteger(逻辑数量) || 逻辑数量 <= 0) {\n      throw new Error(\"读取数量必须是正整数\");\n    }\n    const 读取寄存器数量 = 逻辑数量 * 寄存器块大小;\n    if (!Number.isInteger(读取寄存器数量) || 读取寄存器数量 <= 0) {\n      throw new Error(\"读取寄存器数量计算结果无效\");\n    }\n\n    let 停止监听函数: (() => void) | undefined;\n    let 取消监听函数: (() => void) | undefined;\n    let 已清除任务 = false;\n\n    const 清理任务 = () => {\n      if (已清除任务) {\n        return;\n      }\n      已清除任务 = true;\n      void 清除指定来源任务(指令来源).catch((错误) => {\n        console.warn(`寄存器读写封装清除任务失败`, 错误);\n      });\n    };\n\n    const 停止监听并清理 = () => {\n      停止监听函数?.();\n      停止监听函数 = undefined;\n      清理任务();\n      取消监听函数 = undefined;\n    };\n\n    取消监听函数 = 停止监听并清理;\n\n    const 任务 = 创建读取保持寄存器任务({\n      设备名称型号: 标准化名称,\n      起始地址: 地址,\n      数量: 读取寄存器数量,\n      备注: 配置.备注 ?? `${标准化名称}-寄存器读取封装`,\n      指令来源,\n    });\n\n    if (配置.读取回调 || 是否读写一次) {\n      const 寄存器匹配键 = 生成寄存器匹配键(标准化名称, 地址);\n\n      let 已触发一次 = false;\n      停止监听函数 = 监听特定寄存器(\n        寄存器匹配键,\n        读取寄存器数量,\n        (寄存器数据) => {\n          const 是否为多值 = 逻辑数量 > 1;\n\n          let 解析后的数值: number | number[] | null = null;\n\n          if (是否为多值) {\n            const 数值列表: number[] = [];\n            let 转换失败 = false;\n\n            for (let 索引 = 0; 索引 < 逻辑数量; 索引 += 1) {\n              const 偏移量 = 索引 * 寄存器块大小;\n              if (\n                偏移量 + 寄存器块大小 > 寄存器数据.length\n              ) {\n                转换失败 = true;\n                break;\n              }\n              const 寄存器片段 = 寄存器数据.slice(\n                偏移量,\n                偏移量 + 寄存器块大小\n              );\n              const 单值 = 寄存器转数值(\n                寄存器片段,\n                数据类型,\n                配置.比例系数,\n                配置.小数位数\n              );\n              if (单值 === null) {\n                转换失败 = true;\n                break;\n              }\n              数值列表.push(单值);\n            }\n\n            if (!转换失败) {\n              解析后的数值 = 数值列表;\n            }\n          } else {\n            const 单值 = 寄存器转数值(\n              寄存器数据.slice(0, 寄存器块大小),\n              数据类型,\n              配置.比例系数,\n              配置.小数位数\n            );\n            解析后的数值 = 单值;\n          }\n\n          配置.读取回调?.(寄存器数据, 解析后的数值);\n\n          if (是否读写一次 && !已触发一次) {\n            已触发一次 = true;\n            停止监听并清理();\n          }\n        }\n      );\n    }\n\n    const 上报结果 = await 上报任务至队列([任务], \"寄存器读写封装\");\n\n    if (!上报结果.是否成功) {\n      取消监听函数?.();\n    }\n\n    return {\n      上报结果,\n      取消监听: 取消监听函数,\n      指令来源,\n    };\n  }\n\n  if (读写类型 === \"写入单个\" || 读写类型 === \"写入多个\") {\n    const 数据类型 = 配置.数据类型;\n    const 比例系数 = 配置.比例系数;\n\n    if (读写类型 === \"写入单个\") {\n      const 数值 = 配置.数值;\n      if (typeof 数值 !== \"number\") {\n        throw new Error(\"写入单个寄存器时必须提供数值(number)\");\n      }\n\n      const 寄存器数值 = 数值转寄存器(数值, 数据类型, 比例系数);\n      if (!寄存器数值) {\n        throw new Error(\"写入单个寄存器的数值转换失败\");\n      }\n\n      const 任务 = 创建写入单个保持寄存器任务({\n        设备名称型号: 标准化名称,\n        地址,\n        数值: 寄存器数值[0],\n        备注: 配置.备注 ?? `${标准化名称}-寄存器写入封装`,\n        指令来源,\n      });\n\n      const 上报结果 = await 上报任务至队列([任务], \"寄存器读写封装\");\n\n      return {\n        上报结果,\n        指令来源,\n      };\n    }\n\n    // 写入多个\n    const 数值数组 = Array.isArray(配置.数值)\n      ? 配置.数值\n      : typeof 配置.数值 === \"number\"\n        ? [配置.数值]\n        : undefined;\n\n    if (!数值数组 || 数值数组.length === 0) {\n      throw new Error(\"写入多个寄存器时必须提供数值数组或数值\");\n    }\n\n    const 寄存器数值列表: number[] = [];\n    for (const 数值 of 数值数组) {\n      if (typeof 数值 !== \"number\") {\n        throw new Error(\"数值数组必须全部为 number 类型\");\n      }\n      const 转换结果 = 数值转寄存器(数值, 数据类型, 比例系数);\n      if (!转换结果) {\n        throw new Error(\"写入多个寄存器的数值转换失败\");\n      }\n      寄存器数值列表.push(...转换结果);\n    }\n\n    const 任务 = 创建写入多个保持寄存器任务({\n      设备名称型号: 标准化名称,\n      起始地址: 地址,\n      数量: 寄存器数值列表.length,\n      数值: 寄存器数值列表,\n      备注: 配置.备注 ?? `${标准化名称}-寄存器写入封装`,\n      指令来源,\n    });\n\n    const 上报结果 = await 上报任务至队列([任务], \"寄存器读写封装\");\n\n    return {\n      上报结果,\n      指令来源,\n    };\n  }\n\n  throw new Error(`不支持的寄存器读写类型: ${读写类型}`);\n};\n\n// ==================== 事件监听函数 ====================\n\n/**\n * 监听线圈状态变化\n * @param 回调函数 - 当线圈状态更新时调用\n * @returns 返回取消监听的函数\n */\nexport const 监听线圈状态 = (\n  回调函数: (详情: 线圈状态事件详情) => void\n): (() => void) => {\n  const 监听器: EventListener = (事件) => {\n    if (!(事件 instanceof CustomEvent)) {\n      return;\n    }\n\n    const 详情 = 事件.detail as 线圈状态事件详情 | undefined;\n    if (详情) {\n      回调函数(详情);\n    }\n  };\n\n  window.addEventListener(线圈状态事件名称, 监听器);\n\n  return () => {\n    window.removeEventListener(线圈状态事件名称, 监听器);\n  };\n};\n\n/**\n * 监听特定线圈的状态变化\n * @param 匹配键 - 线圈匹配键\n * @param 回调函数 - 当指定线圈状态更新时调用\n * @returns 返回取消监听的函数\n */\nexport const 监听特定线圈状态 = (\n  匹配键: string,\n  回调函数: (状态: boolean) => void\n): (() => void) => {\n  return 监听线圈状态((详情) => {\n    const 事件设备名称 = 提取非空设备名称(\n      详情.设备名称型号\n    );\n\n    if (!事件设备名称) {\n      return;\n    }\n\n    const 事件匹配键 = 生成线圈匹配键(\n      事件设备名称,\n      详情.线圈地址\n    );\n\n    if (事件匹配键 === 匹配键) {\n      回调函数(详情.状态);\n    }\n  });\n};\n\n/**\n * 监听保持寄存器变化\n * @param 回调函数 - 当保持寄存器更新时调用\n * @returns 返回取消监听的函数\n */\nexport const 监听保持寄存器 = (\n  回调函数: (详情: 保持寄存器事件详情) => void\n): (() => void) => {\n  const 监听器: EventListener = (事件) => {\n    if (!(事件 instanceof CustomEvent)) {\n      return;\n    }\n\n    const 详情 = 事件.detail as 保持寄存器事件详情 | undefined;\n    if (详情) {\n      回调函数(详情);\n    }\n  };\n\n  window.addEventListener(保持寄存器事件名称, 监听器);\n\n  return () => {\n    window.removeEventListener(保持寄存器事件名称, 监听器);\n  };\n};\n\n/**\n * 监听特定寄存器的数据变化\n * @param 匹配键 - 寄存器匹配键\n * @param 读取数量 - 从匹配地址开始读取的寄存器数量\n * @param 回调函数 - 当指定寄存器数据更新时调用\n * @returns 返回取消监听的函数\n */\nexport const 监听特定寄存器 = (\n  匹配键: string,\n  读取数量: number,\n  回调函数: (数据: number[]) => void\n): (() => void) => {\n  return 监听保持寄存器((详情) => {\n    const 分隔位置 = 匹配键.lastIndexOf(\":\");\n    if (分隔位置 === -1) {\n      return;\n    }\n\n    const 目标设备 = 匹配键.slice(0, 分隔位置);\n    const 地址片段 = 匹配键.slice(分隔位置 + 1);\n    const 目标地址 = parseInt(地址片段, 10);\n    if (Number.isNaN(目标地址)) {\n      return;\n    }\n\n    const 事件设备名称 = 提取非空设备名称(\n      详情.设备名称型号\n    );\n    if (!事件设备名称) {\n      return;\n    }\n\n    const 目标设备名称 = 标准化设备名称(目标设备);\n    if (事件设备名称 !== 目标设备名称) {\n      return;\n    }\n\n    const 事件匹配键 = 生成寄存器匹配键(\n      事件设备名称,\n      目标地址\n    );\n\n    if (事件匹配键 === 匹配键) {\n      const 偏移 = 目标地址 - 详情.起始地址;\n      if (偏移 >= 0 && 偏移 < 详情.数据.length) {\n        const 寄存器片段 = 详情.数据.slice(偏移, 偏移 + 读取数量);\n        if (寄存器片段.length >= 读取数量) {\n          回调函数(寄存器片段);\n        }\n      }\n    }\n  });\n};\n\n/**\n * 监听设备连接状态变化\n * @param 回调函数 - 当设备状态变化时调用\n * @returns 返回取消监听的函数\n */\nexport const 监听设备状态 = (\n  回调函数: (详情: 设备状态事件详情) => void\n): (() => void) => {\n  const 监听器: EventListener = (事件) => {\n    if (!(事件 instanceof CustomEvent)) {\n      return;\n    }\n\n    const 详情 = 事件.detail as 设备状态事件详情 | undefined;\n    if (详情) {\n      回调函数(详情);\n    }\n  };\n\n  window.addEventListener(设备状态事件名称, 监听器);\n\n  return () => {\n    window.removeEventListener(设备状态事件名称, 监听器);\n  };\n};\n\n/**\n * 监听特定设备的连接状态\n * @param 设备名称型号 - 设备名称，用于匹配状态事件\n * @param 回调函数 - 当指定设备状态变化时调用\n * @returns 返回取消监听的函数\n */\nexport const 监听特定设备状态 = (\n  设备名称型号: string,\n  回调函数: (状态: string) => void\n): (() => void) => {\n  const 目标设备名称 = 标准化设备名称(设备名称型号);\n  return 监听设备状态((详情) => {\n    const 事件设备名称 = 提取非空设备名称(\n      详情.设备名称型号\n    );\n    if (事件设备名称 === 目标设备名称) {\n      回调函数(详情.状态);\n    }\n  });\n};\n\n// ==================== 数据转换函数 ====================\n\n/**\n * 数据类型常量\n */\nexport const 数据类型常量 = {\n  无符号16位: \"无符号16位\",\n  有符号16位: \"有符号16位\",\n  无符号32位: \"无符号32位\",\n  有符号32位: \"有符号32位\",\n  浮点数32位: \"浮点数32位\",\n} as const;\n\nexport type 数据类型 = (typeof 数据类型常量)[keyof typeof 数据类型常量];\n\nexport const 数据类型寄存器数量映射: Record<数据类型, number> = {\n  [数据类型常量.无符号16位]: 1,\n  [数据类型常量.有符号16位]: 1,\n  [数据类型常量.无符号32位]: 2,\n  [数据类型常量.有符号32位]: 2,\n  [数据类型常量.浮点数32位]: 2,\n};\n\n/**\n * 获取指定数据类型所需的寄存器数量\n */\nexport const 获取数据类型寄存器数量 = (数据类型: 数据类型): number => {\n  return 数据类型寄存器数量映射[数据类型] ?? 1;\n};\n\n/**\n * 将寄存器数据转换为数值\n * @param 寄存器数据 - 寄存器数据数组\n * @param 数据类型 - 数据类型\n * @param 比例系数 - 比例系数,默认为1\n * @param 小数位数 - 小数位数,默认为0\n * @returns 转换后的数值,转换失败时返回null\n */\nexport const 寄存器转数值 = (\n  寄存器数据: number[],\n  数据类型: 数据类型 = 数据类型常量.无符号16位,\n  比例系数: number = 1,\n  小数位数: number = 0\n): number | null => {\n  if (寄存器数据.length === 0) {\n    return null;\n  }\n\n  let 数值: number;\n\n  switch (数据类型) {\n    case 数据类型常量.有符号16位: {\n      const 原始值 = 寄存器数据[0];\n      数值 = 原始值 > 0x7fff ? 原始值 - 0x10000 : 原始值;\n      break;\n    }\n    case 数据类型常量.无符号16位: {\n      数值 = 寄存器数据[0];\n      break;\n    }\n    case 数据类型常量.无符号32位: {\n      if (寄存器数据.length < 2) {\n        return null;\n      }\n      const 高位 = 寄存器数据[0];\n      const 低位 = 寄存器数据[1];\n      数值 = 高位 * 0x10000 + 低位;\n      break;\n    }\n    case 数据类型常量.有符号32位: {\n      if (寄存器数据.length < 2) {\n        return null;\n      }\n      const 高位 = 寄存器数据[0];\n      const 低位 = 寄存器数据[1];\n      let 原始值 = 高位 * 0x10000 + 低位;\n      if (原始值 > 0x7fffffff) {\n        原始值 -= 0x100000000;\n      }\n      数值 = 原始值;\n      break;\n    }\n    case 数据类型常量.浮点数32位: {\n      if (寄存器数据.length < 2) {\n        return null;\n      }\n      const 高位 = 寄存器数据[0];\n      const 低位 = 寄存器数据[1];\n      const 缓冲区 = new ArrayBuffer(4);\n      const 视图 = new DataView(缓冲区);\n      视图.setUint16(0, 高位, false);\n      视图.setUint16(2, 低位, false);\n      数值 = 视图.getFloat32(0, false);\n      break;\n    }\n    default: {\n      数值 = 寄存器数据[0];\n      break;\n    }\n  }\n\n  const 显示值 = 数值 / 比例系数;\n  if (!Number.isFinite(显示值)) {\n    return null;\n  }\n\n  if (小数位数 > 0) {\n    const 精度 = Math.pow(10, 小数位数);\n    return Math.round(显示值 * 精度) / 精度;\n  }\n\n  return 显示值;\n};\n\n/**\n * 将数值转换为寄存器数据\n * @param 数值 - 要转换的数值\n * @param 数据类型 - 数据类型\n * @param 比例系数 - 比例系数,默认为1\n * @returns 寄存器数据数组,如果转换失败返回null\n */\nexport const 数值转寄存器 = (\n  数值: number,\n  数据类型: 数据类型 = 数据类型常量.无符号16位,\n  比例系数: number = 1\n): number[] | null => {\n  if (!Number.isFinite(数值)) {\n    return null;\n  }\n\n  switch (数据类型) {\n    case 数据类型常量.浮点数32位: {\n      const 原始浮点 = 数值 * 比例系数;\n      if (!Number.isFinite(原始浮点)) {\n        return null;\n      }\n      const 缓冲区 = new ArrayBuffer(4);\n      const 视图 = new DataView(缓冲区);\n      视图.setFloat32(0, 原始浮点, false);\n      return [视图.getUint16(0, false), 视图.getUint16(2, false)];\n    }\n    case 数据类型常量.无符号32位: {\n      const 缩放值 = 数值 * 比例系数;\n      if (!Number.isFinite(缩放值)) {\n        return null;\n      }\n      const 原始值 = Math.round(缩放值);\n      if (原始值 < 0 || 原始值 > 0xffffffff) {\n        return null;\n      }\n      return [\n        Math.floor(原始值 / 0x10000) & 0xffff,\n        原始值 & 0xffff,\n      ];\n    }\n    case 数据类型常量.有符号32位: {\n      const 缩放值 = 数值 * 比例系数;\n      if (!Number.isFinite(缩放值)) {\n        return null;\n      }\n      let 原始值 = Math.round(缩放值);\n      if (原始值 < -0x80000000 || 原始值 > 0x7fffffff) {\n        return null;\n      }\n      if (原始值 < 0) {\n        原始值 = 0x100000000 + 原始值;\n      }\n      return [\n        Math.floor(原始值 / 0x10000) & 0xffff,\n        原始值 & 0xffff,\n      ];\n    }\n    case 数据类型常量.有符号16位: {\n      const 缩放值 = 数值 * 比例系数;\n      if (!Number.isFinite(缩放值)) {\n        return null;\n      }\n      let 原始值 = Math.round(缩放值);\n      if (原始值 < -0x8000 || 原始值 > 0x7fff) {\n        return null;\n      }\n      if (原始值 < 0) {\n        原始值 = 0x10000 + 原始值;\n      }\n      return [原始值 & 0xffff];\n    }\n    case 数据类型常量.无符号16位:\n    default: {\n      const 缩放值 = 数值 * 比例系数;\n      if (!Number.isFinite(缩放值)) {\n        return null;\n      }\n      const 原始值 = Math.round(缩放值);\n      if (原始值 < 0 || 原始值 > 0xffff) {\n        return null;\n      }\n      return [原始值 & 0xffff];\n    }\n  }\n};\n\nexport interface 寄存器显示选项 {\n  数据类型?: 数据类型;\n  比例系数?: number;\n  小数位数?: number;\n  默认值?: string;\n}\n\n/**\n * 将寄存器数组转换为可显示文本\n */\nexport const 转换寄存器为显示文本 = (\n  寄存器数据: number[],\n  选项: 寄存器显示选项 = {}\n): string => {\n  const {\n    数据类型 = 数据类型常量.无符号16位,\n    比例系数 = 1,\n    小数位数 = 0,\n    默认值 = \"\",\n  } = 选项;\n\n  if (!Object.prototype.hasOwnProperty.call(数据类型寄存器数量映射, 数据类型)) {\n    return 默认值;\n  }\n\n  const 需要寄存器数量 = 获取数据类型寄存器数量(数据类型);\n  if (寄存器数据.length < 需要寄存器数量) {\n    return 默认值;\n  }\n\n  const 有效比例 = 比例系数 > 0 ? 比例系数 : 1;\n  const 数值 = 寄存器转数值(\n    寄存器数据.slice(0, 需要寄存器数量),\n    数据类型,\n    有效比例,\n    小数位数\n  );\n\n  if (数值 === null) {\n    return 默认值;\n  }\n\n  if (小数位数 && 小数位数 > 0) {\n    return 数值.toFixed(小数位数);\n  }\n\n  if (Number.isInteger(数值)) {\n    return 数值.toString();\n  }\n\n  const 默认小数位数 = Math.min(6, Math.max(0, 小数位数 ?? 0));\n  return 默认小数位数 > 0 ? 数值.toFixed(默认小数位数) : 数值.toString();\n};\n\nexport interface 显示文本解析选项 {\n  数据类型?: 数据类型;\n  比例系数?: number;\n  最小值?: number;\n  最大值?: number;\n  允许空字符串返回空数组?: boolean;\n}\n\n/**\n * 将输入文本解析为寄存器数组\n */\nexport const 转换显示文本为寄存器 = (\n  输入文本: string,\n  选项: 显示文本解析选项 = {}\n): number[] | null => {\n  const 文本 = 输入文本.trim();\n  if (文本.length === 0) {\n    return 选项.允许空字符串返回空数组 ? [] : null;\n  }\n\n  const 显示数值 = Number(文本);\n  if (!Number.isFinite(显示数值)) {\n    return null;\n  }\n\n  const {\n    数据类型 = 数据类型常量.无符号16位,\n    比例系数 = 1,\n    最小值,\n    最大值,\n  } = 选项;\n\n  if (!Object.prototype.hasOwnProperty.call(数据类型寄存器数量映射, 数据类型)) {\n    return null;\n  }\n\n  if (最小值 !== undefined && 显示数值 < 最小值) {\n    return null;\n  }\n\n  if (最大值 !== undefined && 显示数值 > 最大值) {\n    return null;\n  }\n\n  const 有效比例 = 比例系数 > 0 ? 比例系数 : 1;\n  return 数值转寄存器(显示数值, 数据类型, 有效比例);\n};\n\nexport default {\n  // 任务操作\n  上报任务至队列,\n  创建读取线圈任务,\n  创建读取保持寄存器任务,\n  创建写入单个线圈任务,\n  创建写入多个线圈任务,\n  创建写入单个保持寄存器任务,\n  创建写入多个保持寄存器任务,\n  执行线圈读写操作,\n  执行寄存器读写操作,\n\n  // 事件监听\n  监听线圈状态,\n  监听特定线圈状态,\n  监听保持寄存器,\n  监听特定寄存器,\n  监听设备状态,\n  监听特定设备状态,\n\n  // 数据转换\n  寄存器转数值,\n  数值转寄存器,\n  转换寄存器为显示文本,\n  转换显示文本为寄存器,\n\n  // 工具函数\n  生成线圈匹配键,\n  生成寄存器匹配键,\n  获取数据类型寄存器数量,\n\n  // 常量\n  数据类型常量,\n  数据类型寄存器数量映射,\n  线圈状态事件名称,\n  保持寄存器事件名称,\n  设备状态事件名称,\n};\n","import type { Directive } from \"vue\";\nimport { 生成页面级指令来源 } from \"./页面上下文\";\nimport {\n  上报任务至队列,\n  生成线圈匹配键,\n  type 线圈状态事件详情,\n  type 设备状态事件详情,\n  type 前端Modbus任务,\n  type 上报执行结果,\n} from \"./工业组件API\";\n\n// 重导出以保持向后兼容\nexport type { 前端Modbus任务, 上报执行结果 };\nexport { 上报任务至队列 };\n\n/**\n * 工业按钮指令支持的操作类型常量，便于在组件中复用并保持类型安全。\n */\nexport const 工业按钮类型常量 = {\n  切换: \"切换\",\n  置ON: \"置ON\",\n  置OFF: \"置OFF\",\n  复归: \"复归\",\n  显示: \"显示\",  // 只读模式,仅显示线圈状态,不允许点击写入\n} as const;\n\nexport type 工业按钮类型 =\n  (typeof 工业按钮类型常量)[keyof typeof 工业按钮类型常量];\n\ntype 操作目标类型 = \"保持寄存器\" | \"线圈\";\n\nexport interface 工业按钮参数 {\n  设备名称型号: string;\n  类型: 工业按钮类型;\n  读取地址: number;\n  写入地址: number;\n  操作目标?: 操作目标类型;\n}\n\ninterface 元素状态 {\n  参数: 工业按钮参数;\n  点击处理器: (事件: Event) => Promise<void>;\n  按下处理器?: (事件: Event) => Promise<void>;\n  弹起处理器?: (事件: Event) => Promise<void>;\n  最近线圈状态: boolean | null;\n  读取任务摘要: string | null;\n  已注册读取任务: boolean;\n  正在注册读取任务: boolean;\n  线圈匹配键: string;\n  设备名称: string;\n  线圈状态监听器: EventListener;\n  设备状态监听器: EventListener;\n  复归按压中: boolean;\n}\n\nconst 默认读取数量 = 1;\nconst 指令名称 = \"工业按钮\";\nconst 允许按钮类型 = new Set<工业按钮类型>(\n  Object.values(工业按钮类型常量),\n);\nconst 允许操作目标 = new Set<操作目标类型>([\"线圈\"]);\nconst 状态样式映射 = {\n  未知: \"工业按钮-状态-未知\",\n  开启: \"工业按钮-状态-开启\",\n  关闭: \"工业按钮-状态-关闭\",\n  连接中: \"工业按钮-设备-连接中\",\n  断开连接: \"工业按钮-设备-断开连接\",\n} as const;\nconst 状态数据属性 = \"data-工业按钮状态\";\nconst 设备状态属性 = \"data-设备连接状态\";\nconst 线圈状态事件名称 = \"modbus-线圈状态更新\";\nconst 设备状态事件名称 = \"modbus-设备状态变化\";\n\nconst 元素状态映射 = new WeakMap<HTMLElement, 元素状态>();\n\nconst 标准化设备名称 = (名称: string): string => 名称.trim();\n\nconst 提取事件设备名称 = (设备名称型号?: string): string => {\n  if (!设备名称型号) {\n    return \"\";\n  }\n  const 名称 = 标准化设备名称(设备名称型号);\n  return 名称.length > 0 ? 名称 : \"\";\n};\n\nconst 生成读取任务摘要 = (参数: 工业按钮参数): string => {\n  const 设备名称 = 标准化设备名称(参数.设备名称型号);\n  return 生成线圈匹配键(设备名称, 参数.读取地址);\n};\n\nconst 计算线圈写入状态 = (\n  类型: 工业按钮类型,\n  当前状态: boolean | null,\n): boolean | null => {\n  switch (类型) {\n    case 工业按钮类型常量.置OFF:\n      return false;\n    case 工业按钮类型常量.置ON:\n      return true;\n    case 工业按钮类型常量.显示:\n      return null;  // 显示模式不写入\n    case 工业按钮类型常量.切换:\n    default:\n      return !(当前状态 ?? false);\n  }\n};\n\nconst 创建读取任务 = (参数: 工业按钮参数) => {\n  const 设备名称 = 标准化设备名称(参数.设备名称型号);\n  const 基础信息 = {\n    设备名称型号: 设备名称,\n    备注: `${设备名称}-读取`,\n    指令来源: 生成页面级指令来源(指令名称),\n  };\n\n  return {\n    ...基础信息,\n    操作: {\n      操作类型: \"读取线圈\" as const,\n      起始地址: 参数.读取地址,\n      数量: 默认读取数量,\n    },\n  };\n};\n\nconst 创建写入任务 = (参数: 工业按钮参数, 线圈状态: boolean) => {\n  const 设备名称 = 标准化设备名称(参数.设备名称型号);\n  const 基础信息 = {\n    设备名称型号: 设备名称,\n    备注: `${设备名称}-写入`,\n    指令来源: 生成页面级指令来源(指令名称),\n  };\n\n  return {\n    ...基础信息,\n    操作: {\n      操作类型: \"写入单个线圈\" as const,\n      线圈地址: 参数.写入地址,\n      状态: 线圈状态,\n    },\n  };\n};\n\nconst 数值在范围内 = (值: number, 最小值: number, 最大值: number): boolean =>\n  Number.isInteger(值) && 值 >= 最小值 && 值 <= 最大值;\n\nconst 生成校验错误 = (参数: 工业按钮参数 | undefined): string[] => {\n  if (!参数) {\n    return [\"未提供指令参数\"];\n  }\n\n  const 错误列表: string[] = [];\n\n  if (!参数.设备名称型号 || 参数.设备名称型号.trim().length === 0) {\n    错误列表.push(\"设备名称型号不能为空\");\n  }\n\n  if (!允许按钮类型.has(参数.类型)) {\n    错误列表.push(`未知的按钮类型: ${参数.类型}`);\n  }\n\n  if (!数值在范围内(参数.读取地址, 0, 0xffff)) {\n    错误列表.push(\"读取地址必须是 0-65535 的整数\");\n  }\n\n  if (!数值在范围内(参数.写入地址, 0, 0xffff)) {\n    错误列表.push(\"写入地址必须是 0-65535 的整数\");\n  }\n\n  if (参数.操作目标 && !允许操作目标.has(参数.操作目标)) {\n    错误列表.push(\"当前仅支持线圈读写\");\n  }\n\n  return 错误列表;\n};\n\nconst 校验参数 = (参数: 工业按钮参数 | undefined): 参数 is 工业按钮参数 => {\n  const 错误列表 = 生成校验错误(参数);\n  if (错误列表.length > 0) {\n    console.warn(`${生成页面级指令来源(指令名称)} 参数校验失败: ${错误列表.join(\"；\")}`, 参数);\n    return false;\n  }\n  return true;\n};\n\nconst 安排读取任务 = async (状态: 元素状态) => {\n  if (!校验参数(状态.参数)) {\n    return;\n  }\n\n  const 新摘要 = 生成读取任务摘要(状态.参数);\n  if (状态.已注册读取任务 && 状态.读取任务摘要 === 新摘要) {\n    return;\n  }\n\n  if (状态.正在注册读取任务) {\n    return;\n  }\n\n  状态.正在注册读取任务 = true;\n  const 上报结果 = await 上报任务至队列(\n    [创建读取任务(状态.参数)],\n    \"注册读取任务\",\n  );\n  状态.正在注册读取任务 = false;\n\n  if (上报结果.是否成功) {\n    状态.已注册读取任务 = true;\n    状态.读取任务摘要 = 新摘要;\n  } else {\n    console.warn(`${生成页面级指令来源(指令名称)} 注册读取任务失败`, 状态.参数, 上报结果);\n  }\n};\n\nconst 更新元素状态样式 = (\n  元素: HTMLElement,\n  状态值: boolean | null,\n) => {\n  // 只移除状态相关样式，保留设备连接状态样式\n  元素.classList.remove(\n    状态样式映射.未知,\n    状态样式映射.开启,\n    状态样式映射.关闭\n  );\n\n  const 目标样式 =\n    状态值 === null\n      ? 状态样式映射.未知\n      : 状态值\n        ? 状态样式映射.开启\n        : 状态样式映射.关闭;\n  元素.classList.add(目标样式);\n\n  元素.setAttribute(\n    状态数据属性,\n    状态值 === null ? \"未知\" : 状态值 ? \"开启\" : \"关闭\",\n  );\n};\n\nconst 更新设备连接状态 = (元素: HTMLElement, 连接状态: string) => {\n  元素.classList.remove(状态样式映射.连接中, 状态样式映射.断开连接);\n\n  if (连接状态 === \"连接中\") {\n    元素.classList.add(状态样式映射.连接中);\n  } else if (连接状态 === \"断开连接\") {\n    元素.classList.add(状态样式映射.断开连接);\n  }\n\n  元素.setAttribute(设备状态属性, 连接状态);\n};\n\nconst 创建并保存状态 = (\n  元素: HTMLElement,\n  参数: 工业按钮参数,\n): 元素状态 => {\n  const 设备名称 = 标准化设备名称(参数.设备名称型号);\n  const 初始线圈匹配键 = 生成线圈匹配键(\n    设备名称,\n    参数.读取地址,\n  );\n\n  const 线圈状态监听器: EventListener = (事件) => {\n    if (!(事件 instanceof CustomEvent)) {\n      return;\n    }\n\n    const 详情 = 事件.detail as 线圈状态事件详情 | undefined;\n    if (!详情) {\n      return;\n    }\n\n    const 当前状态 = 元素状态映射.get(元素);\n    if (!当前状态) {\n      return;\n    }\n\n    const 事件设备名称 = 提取事件设备名称(\n      详情.设备名称型号,\n    );\n\n    if (!事件设备名称 || 事件设备名称 !== 当前状态.设备名称) {\n      return;\n    }\n\n    const 事件匹配键 = 生成线圈匹配键(\n      事件设备名称,\n      详情.线圈地址,\n    );\n\n    if (事件匹配键 !== 当前状态.线圈匹配键) {\n      return;\n    }\n\n    当前状态.最近线圈状态 = Boolean(详情.状态);\n    更新元素状态样式(元素, 当前状态.最近线圈状态);\n  };\n\n  const 设备状态监听器: EventListener = (事件) => {\n    if (!(事件 instanceof CustomEvent)) {\n      return;\n    }\n\n    const 详情 = 事件.detail as 设备状态事件详情 | undefined;\n    if (!详情) {\n      return;\n    }\n\n    const 当前状态 = 元素状态映射.get(元素);\n    if (!当前状态) {\n      return;\n    }\n\n    const 事件设备名称 = 提取事件设备名称(详情.设备名称型号);\n    if (!事件设备名称 || 事件设备名称 !== 当前状态.设备名称) {\n      return;\n    }\n\n    更新设备连接状态(元素, 详情.状态);\n  };\n\n  const 点击处理器 = async (事件: Event) => {\n    事件.preventDefault();\n    const 当前状态 = 元素状态映射.get(元素);\n    if (!当前状态 || !校验参数(当前状态.参数)) {\n      return;\n    }\n\n    // 复归类型使用按下/弹起处理器,不使用点击处理器\n    if (当前状态.参数.类型 === 工业按钮类型常量.复归) {\n      return;\n    }\n\n    // 显示类型不执行写入操作\n    if (当前状态.参数.类型 === 工业按钮类型常量.显示) {\n      return;\n    }\n\n    const 目标状态 = 计算线圈写入状态(\n      当前状态.参数.类型,\n      当前状态.最近线圈状态,\n    );\n\n    if (目标状态 === null) {\n      return;\n    }\n\n    const 上报结果 = await 上报任务至队列(\n      [创建写入任务(当前状态.参数, 目标状态)],\n      \"点击写入\",\n    );\n\n    if (上报结果.是否成功) {\n      void 安排读取任务(当前状态);\n    } else {\n      console.warn(`${生成页面级指令来源(指令名称)} 点击写入失败`, 当前状态.参数, 上报结果);\n    }\n  };\n\n  const 按下处理器 = async (事件: Event) => {\n    事件.preventDefault();\n    const 当前状态 = 元素状态映射.get(元素);\n    if (!当前状态 || !校验参数(当前状态.参数)) {\n      return;\n    }\n\n    if (当前状态.复归按压中) {\n      return;\n    }\n\n    当前状态.复归按压中 = true;\n\n    const 上报结果 = await 上报任务至队列(\n      [创建写入任务(当前状态.参数, true)],\n      \"复归按下写入\",\n    );\n\n    if (上报结果.是否成功) {\n      void 安排读取任务(当前状态);\n    } else {\n      当前状态.复归按压中 = false;\n      console.warn(`${生成页面级指令来源(指令名称)} 复归按下写入失败`, 当前状态.参数, 上报结果);\n    }\n  };\n\n  const 弹起处理器 = async (事件: Event) => {\n    事件.preventDefault();\n    const 当前状态 = 元素状态映射.get(元素);\n    if (!当前状态 || !校验参数(当前状态.参数)) {\n      return;\n    }\n\n    if (!当前状态.复归按压中) {\n      return;\n    }\n\n    try {\n      const 上报结果 = await 上报任务至队列(\n        [创建写入任务(当前状态.参数, false)],\n        \"复归弹起写入\",\n      );\n\n      if (上报结果.是否成功) {\n        void 安排读取任务(当前状态);\n      } else {\n        console.warn(`${生成页面级指令来源(指令名称)} 复归弹起写入失败`, 当前状态.参数, 上报结果);\n      }\n    } finally {\n      当前状态.复归按压中 = false;\n    }\n  };\n\n  const 状态: 元素状态 = {\n    参数,\n    点击处理器,\n    按下处理器,\n    弹起处理器,\n    最近线圈状态: null,\n    读取任务摘要: null,\n    已注册读取任务: false,\n    正在注册读取任务: false,\n    线圈匹配键: 初始线圈匹配键,\n    设备名称,\n    线圈状态监听器,\n    设备状态监听器,\n    复归按压中: false,\n  };\n\n  // 根据按钮类型注册不同的事件监听器\n  if (参数.类型 === 工业按钮类型常量.复归) {\n    元素.addEventListener(\"mousedown\", 按下处理器);\n    元素.addEventListener(\"touchstart\", 按下处理器);\n    元素.addEventListener(\"mouseup\", 弹起处理器);\n    元素.addEventListener(\"touchend\", 弹起处理器);\n    元素.addEventListener(\"touchcancel\", 弹起处理器);\n    元素.addEventListener(\"mouseleave\", 弹起处理器);\n  } else if (参数.类型 === 工业按钮类型常量.显示) {\n    // 显示类型不注册点击事件,但添加标识\n    元素.setAttribute('data-工业按钮类型', '显示');\n    元素.style.cursor = 'default';\n  } else {\n    元素.addEventListener(\"click\", 点击处理器);\n  }\n\n  元素状态映射.set(元素, 状态);\n  window.addEventListener(线圈状态事件名称, 线圈状态监听器);\n  window.addEventListener(设备状态事件名称, 设备状态监听器);\n  更新元素状态样式(元素, 状态.最近线圈状态);\n  return 状态;\n};\n\nexport const 工业按钮指令: Directive<HTMLElement, 工业按钮参数> = {\n  mounted(元素, 绑定) {\n    const 参数 = 绑定.value;\n    if (!校验参数(参数)) {\n      return;\n    }\n\n    const 状态 = 创建并保存状态(元素, 参数);\n    void 安排读取任务(状态);\n  },\n  updated(元素, 绑定) {\n    const 参数 = 绑定.value;\n    if (!校验参数(参数)) {\n      return;\n    }\n\n    const 状态 = 元素状态映射.get(元素);\n    if (状态) {\n      const 原摘要 = 状态.读取任务摘要;\n      状态.参数 = 参数;\n      const 标准化名称 = 标准化设备名称(状态.参数.设备名称型号);\n      状态.线圈匹配键 = 生成线圈匹配键(\n        标准化名称,\n        状态.参数.读取地址,\n      );\n      状态.设备名称 = 标准化名称;\n      状态.已注册读取任务 =\n        状态.已注册读取任务 && 原摘要 === 生成读取任务摘要(参数);\n      if (!状态.已注册读取任务) {\n        状态.读取任务摘要 = null;\n      }\n      void 安排读取任务(状态);\n      更新元素状态样式(元素, 状态.最近线圈状态);\n    } else {\n      const 新状态 = 创建并保存状态(元素, 参数);\n      void 安排读取任务(新状态);\n      更新元素状态样式(元素, 新状态.最近线圈状态);\n    }\n  },\n  unmounted(元素) {\n    const 状态 = 元素状态映射.get(元素);\n    if (状态) {\n      // 根据按钮类型移除相应的事件监听器\n      if (状态.参数.类型 === 工业按钮类型常量.复归) {\n        if (状态.按下处理器) {\n          元素.removeEventListener(\"mousedown\", 状态.按下处理器);\n          元素.removeEventListener(\"touchstart\", 状态.按下处理器);\n        }\n        if (状态.弹起处理器) {\n          元素.removeEventListener(\"mouseup\", 状态.弹起处理器);\n          元素.removeEventListener(\"touchend\", 状态.弹起处理器);\n          元素.removeEventListener(\"touchcancel\", 状态.弹起处理器);\n          元素.removeEventListener(\"mouseleave\", 状态.弹起处理器);\n        }\n      } else if (状态.参数.类型 === 工业按钮类型常量.显示) {\n        // 显示类型没有注册点击事件,无需移除\n      } else {\n        元素.removeEventListener(\"click\", 状态.点击处理器);\n      }\n      window.removeEventListener(线圈状态事件名称, 状态.线圈状态监听器);\n      window.removeEventListener(设备状态事件名称, 状态.设备状态监听器);\n      元素状态映射.delete(元素);\n    }\n  },\n};\n\nexport default 工业按钮指令;\n","import type { Directive } from \"vue\";\nimport {\n  上报任务至队列,\n  生成寄存器匹配键,\n  转换寄存器为显示文本,\n  转换显示文本为寄存器,\n  获取数据类型寄存器数量,\n  数据类型常量,\n  type 保持寄存器事件详情,\n  type 设备状态事件详情,\n  type 数据类型,\n} from \"./工业组件API\";\nimport { 生成页面级指令来源 } from \"./页面上下文\";\n\ntype 输入框元素 = HTMLInputElement | HTMLTextAreaElement;\n/**\n * 工业输入框模式常量，定义输入框的工作模式\n */\nexport const 工业输入框模式常量 = {\n  显示: \"显示\",  // 只读模式，只显示数据不允许输入\n  输入: \"输入\",  // 可编辑模式，允许读取和写入\n} as const;\n\nexport type 工业输入框数据类型 = 数据类型;\n\nexport type 工业输入框模式 =\n  (typeof 工业输入框模式常量)[keyof typeof 工业输入框模式常量];\ntype 输入框视觉状态 = \"未知\" | \"同步\" | \"待写入\" | \"错误\";\n\nexport interface 工业输入框参数 {\n  设备名称型号: string;\n  读取地址: number;\n  写入地址?: number;\n  读取数量?: number;\n  数据类型?: 工业输入框数据类型;\n  模式?: 工业输入框模式;  // 工作模式：显示（只读）或输入（可编辑），默认为输入\n  比例系数?: number;\n  小数位数?: number;\n  最小值?: number;\n  最大值?: number;\n}\n\ninterface 元素状态 {\n  参数: 工业输入框参数;\n  输入元素: 输入框元素;\n  最近寄存器数据: number[] | null;\n  最近显示值: string | null;\n  读取任务摘要: string | null;\n  已注册读取任务: boolean;\n  正在注册读取任务: boolean;\n  正在写入: boolean;\n  寄存器匹配键: string;\n  设备名称: string;\n  寄存器事件监听器: EventListener;\n  设备状态监听器: EventListener;\n  当前视觉状态: 输入框视觉状态;\n  当前模式: 工业输入框模式;\n  输入事件监听器: EventListener;\n  变更事件监听器: EventListener;\n  键盘事件监听器: EventListener;\n}\n\nconst 指令名称 = \"工业输入框\";\nconst 默认比例系数 = 1;\nconst 默认小数位数 = 0;\nconst 保持寄存器事件名称 = \"modbus-保持寄存器更新\";\nconst 设备状态事件名称 = \"modbus-设备状态变化\";\nconst 数据属性状态 = \"data-工业输入框状态\";\nconst 设备状态属性 = \"data-设备连接状态\";\n\nconst 输入框状态样式映射 = {\n  未知: \"工业输入框-状态-未知\",\n  同步: \"工业输入框-状态-同步\",\n  待写入: \"工业输入框-状态-待写入\",\n  错误: \"工业输入框-状态-错误\",\n} as const satisfies Record<输入框视觉状态, string>;\n\nconst 设备连接状态样式映射 = {\n  连接中: \"工业输入框-设备-连接中\",\n  断开连接: \"工业输入框-设备-断开连接\",\n} as const;\n\nconst 元素状态映射 = new WeakMap<HTMLElement, 元素状态>();\n\nconst 标准化设备名称 = (名称: string): string => 名称.trim();\n\nconst 提取事件设备名称 = (设备名称型号?: string): string => {\n  if (!设备名称型号) {\n    return \"\";\n  }\n  const 名称 = 标准化设备名称(设备名称型号);\n  return 名称.length > 0 ? 名称 : \"\";\n};\n\nconst 生成读取任务摘要 = (参数: 工业输入框参数): string => {\n  const 设备名称 = 标准化设备名称(参数.设备名称型号);\n  const 读取数量 = 获取读取寄存器数量(参数);\n  const 数据类型 = 参数.数据类型 ?? 默认数据类型;\n  return `${设备名称}:${参数.读取地址}:${读取数量}:${数据类型}`;\n};\n\nconst 创建读取任务 = (参数: 工业输入框参数) => {\n  const 设备名称 = 标准化设备名称(参数.设备名称型号);\n  const 读取数量 = 获取读取寄存器数量(参数);\n  return {\n    设备名称型号: 设备名称,\n    备注: `${设备名称}-读取`,\n    指令来源: 生成页面级指令来源(指令名称),\n    操作: {\n      操作类型: \"读取保持寄存器\" as const,\n      起始地址: 参数.读取地址,\n      数量: 读取数量,\n    },\n  };\n};\n\nconst 创建写入任务 = (参数: 工业输入框参数, 寄存器值列表: number[]) => {\n  const 设备名称 = 标准化设备名称(参数.设备名称型号);\n  const 写入地址 = 参数.写入地址 ?? 参数.读取地址;\n  const 数值列表 = 寄存器值列表.length > 0 ? 寄存器值列表 : [0];\n\n  return {\n    设备名称型号: 设备名称,\n    备注: `${设备名称}-写入输入框`,\n    指令来源: 生成页面级指令来源(指令名称),\n    操作:\n      数值列表.length === 1\n        ? {\n          操作类型: \"写入单个保持寄存器\" as const,\n          寄存器地址: 写入地址,\n          数值: 数值列表[0],\n        }\n        : {\n          操作类型: \"写入多个保持寄存器\" as const,\n          起始地址: 写入地址,\n          数值: 数值列表,\n        },\n  };\n};\n\nconst 输入框允许数据类型 = new Set<工业输入框数据类型>(\n  Object.values(数据类型常量),\n);\n\nconst 输入框视觉状态全集 = new Set<输入框视觉状态>([\n  \"未知\",\n  \"同步\",\n  \"待写入\",\n  \"错误\",\n]);\n\nconst 默认数据类型: 工业输入框数据类型 =\n  数据类型常量.无符号16位;\n\nconst 默认模式: 工业输入框模式 =\n  工业输入框模式常量.输入;\n\nconst 获取读取寄存器数量 = (参数: 工业输入框参数): number => {\n  const 数据类型 = 参数.数据类型 ?? 默认数据类型;\n  const 最小数量 = 获取数据类型寄存器数量(数据类型);\n  const 指定数量 = 参数.读取数量;\n  if (指定数量 === undefined) {\n    return 最小数量;\n  }\n  return Math.max(指定数量, 最小数量);\n};\n\nconst 移除旧样式 = (元素: HTMLElement) => {\n  元素.classList.remove(...Object.values(输入框状态样式映射));\n};\n\nconst 设置视觉状态 = (状态: 元素状态, 新状态: 输入框视觉状态) => {\n  if (!输入框视觉状态全集.has(新状态)) {\n    return;\n  }\n\n  if (状态.当前视觉状态 === 新状态) {\n    return;\n  }\n\n  移除旧样式(状态.输入元素);\n  const 样式 = 输入框状态样式映射[新状态];\n  状态.输入元素.classList.add(样式);\n  状态.输入元素.setAttribute(数据属性状态, 新状态);\n  状态.当前视觉状态 = 新状态;\n};\n\nconst 复制或初始化视觉状态 = (状态: 元素状态) => {\n  移除旧样式(状态.输入元素);\n  const 样式 = 输入框状态样式映射[状态.当前视觉状态];\n  状态.输入元素.classList.add(样式);\n  状态.输入元素.setAttribute(数据属性状态, 状态.当前视觉状态);\n};\n\nconst 更新设备连接状态 = (元素: HTMLElement, 连接状态: string) => {\n  // 移除旧的设备状态样式\n  元素.classList.remove(\n    设备连接状态样式映射.连接中,\n    设备连接状态样式映射.断开连接\n  );\n\n  if (连接状态 === \"连接中\") {\n    元素.classList.add(设备连接状态样式映射.连接中);\n  } else if (连接状态 === \"断开连接\") {\n    元素.classList.add(设备连接状态样式映射.断开连接);\n    // 断开连接时禁用输入\n    if (元素 instanceof HTMLInputElement || 元素 instanceof HTMLTextAreaElement) {\n      元素.disabled = true;\n    }\n  } else if (连接状态 === \"已连接\") {\n    // 恢复连接时启用输入\n    if (元素 instanceof HTMLInputElement || 元素 instanceof HTMLTextAreaElement) {\n      元素.disabled = false;\n    }\n  }\n\n  元素.setAttribute(设备状态属性, 连接状态);\n};\n\n\nconst 更新输入值显示 = (\n  状态: 元素状态,\n  寄存器数据: number[],\n  强制: boolean,\n) => {\n  const { 输入元素 } = 状态;\n  const 当前聚焦 = document.activeElement === 输入元素;\n  if (!强制 && 当前聚焦) {\n    return;\n  }\n\n  const 显示文本 = 转换寄存器为显示文本(寄存器数据, {\n    数据类型: 状态.参数.数据类型 ?? 默认数据类型,\n    比例系数:\n      状态.参数.比例系数 && 状态.参数.比例系数 > 0\n        ? 状态.参数.比例系数\n        : 默认比例系数,\n    小数位数: 状态.参数.小数位数 ?? 默认小数位数,\n  });\n  状态.最近寄存器数据 = [...寄存器数据];\n  状态.最近显示值 = 显示文本;\n  输入元素.value = 显示文本;\n  设置视觉状态(状态, \"同步\");\n};\n\nconst 生成校验错误 = (参数: 工业输入框参数 | undefined): string[] => {\n  if (!参数) {\n    return [\"未提供指令参数\"];\n  }\n\n  const 错误列表: string[] = [];\n\n  if (!参数.设备名称型号 || 参数.设备名称型号.trim().length === 0) {\n    错误列表.push(\"设备名称型号不能为空\");\n  }\n\n  if (!Number.isInteger(参数.读取地址) || 参数.读取地址 < 0 || 参数.读取地址 > 0xffff) {\n    错误列表.push(\"读取地址必须是 0-65535 的整数\");\n  }\n\n  if (参数.写入地址 !== undefined && (!Number.isInteger(参数.写入地址) || 参数.写入地址 < 0 || 参数.写入地址 > 0xffff)) {\n    错误列表.push(\"写入地址必须是 0-65535 的整数\");\n  }\n\n  if (\n    参数.读取数量 !== undefined &&\n    (!Number.isInteger(参数.读取数量) || 参数.读取数量 <= 0)\n  ) {\n    错误列表.push(\"读取数量必须是正整数\");\n  }\n\n  if (参数.比例系数 !== undefined && 参数.比例系数 <= 0) {\n    错误列表.push(\"比例系数必须大于 0\");\n  }\n\n  if (参数.数据类型 !== undefined) {\n    if (!输入框允许数据类型.has(参数.数据类型)) {\n      错误列表.push(`不支持的数据类型: ${参数.数据类型}`);\n    } else if (\n      参数.读取数量 !== undefined &&\n      Number.isInteger(参数.读取数量) &&\n      参数.读取数量 > 0 &&\n      参数.读取数量 < 获取数据类型寄存器数量(参数.数据类型)\n    ) {\n      错误列表.push(\n        `${参数.数据类型} 至少需要 ${获取数据类型寄存器数量(参数.数据类型)} 个寄存器`,\n      );\n    }\n  }\n\n  // 通信参数由后端配置, 前端不再允许覆盖\n\n  if (参数.最小值 !== undefined && 参数.最大值 !== undefined && 参数.最小值 > 参数.最大值) {\n    错误列表.push(\"最小值不能大于最大值\");\n  }\n\n  return 错误列表;\n};\n\nconst 校验参数 = (参数: 工业输入框参数 | undefined): 参数 is 工业输入框参数 => {\n  const 错误列表 = 生成校验错误(参数);\n  if (错误列表.length > 0) {\n    console.warn(`${生成页面级指令来源(指令名称)} 参数校验失败: ${错误列表.join(\"；\")}`, 参数);\n    return false;\n  }\n  return true;\n};\n\nconst 安排读取任务 = async (状态: 元素状态) => {\n  if (!校验参数(状态.参数)) {\n    return;\n  }\n\n  const 新摘要 = 生成读取任务摘要(状态.参数);\n  if (状态.已注册读取任务 && 状态.读取任务摘要 === 新摘要) {\n    return;\n  }\n\n  if (状态.正在注册读取任务) {\n    return;\n  }\n\n  状态.正在注册读取任务 = true;\n  const 上报结果 = await 上报任务至队列(\n    [创建读取任务(状态.参数)],\n    \"注册保持寄存器读取任务\",\n  );\n  状态.正在注册读取任务 = false;\n\n  if (上报结果.是否成功) {\n    状态.已注册读取任务 = true;\n    状态.读取任务摘要 = 新摘要;\n  } else {\n    console.warn(`${生成页面级指令来源(指令名称)} 注册保持寄存器读取任务失败`, 状态.参数, 上报结果);\n  }\n};\n\nconst 处理写入操作 = async (状态: 元素状态) => {\n  if (!校验参数(状态.参数)) {\n    return;\n  }\n\n  const 用户输入 = 状态.输入元素.value;\n  const 寄存器数据 = 转换显示文本为寄存器(用户输入, {\n    数据类型: 状态.参数.数据类型 ?? 默认数据类型,\n    比例系数:\n      状态.参数.比例系数 && 状态.参数.比例系数 > 0\n        ? 状态.参数.比例系数\n        : 默认比例系数,\n    最小值: 状态.参数.最小值,\n    最大值: 状态.参数.最大值,\n  });\n  if (寄存器数据 === null) {\n    console.warn(`${生成页面级指令来源(指令名称)} 输入值无效`, 用户输入, 状态.参数);\n    设置视觉状态(状态, \"错误\");\n    return;\n  }\n\n  if (状态.正在写入) {\n    return;\n  }\n\n  状态.正在写入 = true;\n  const 上报结果 = await 上报任务至队列(\n    [创建写入任务(状态.参数, 寄存器数据)],\n    \"输入框写入\",\n  );\n  状态.正在写入 = false;\n\n  if (上报结果.是否成功) {\n    更新输入值显示(状态, 寄存器数据, true);\n    void 安排读取任务(状态);\n  } else {\n    console.warn(`${生成页面级指令来源(指令名称)} 输入框写入失败`, 状态.参数, 上报结果);\n    设置视觉状态(状态, \"错误\");\n  }\n};\n\nconst 工业输入框状态切换 = (\n  状态: 元素状态,\n  新状态: 输入框视觉状态,\n) => {\n  设置视觉状态(状态, 新状态);\n};\n\nconst 创建并初始化状态 = (\n  元素: HTMLElement,\n  参数: 工业输入框参数,\n): 元素状态 | null => {\n  if (!(元素 instanceof HTMLInputElement || 元素 instanceof HTMLTextAreaElement)) {\n    console.warn(`${生成页面级指令来源(指令名称)} 仅支持绑定在 <input> 或 <textarea> 元素上`, 元素);\n    return null;\n  }\n\n  const 输入元素: 输入框元素 = 元素;\n  const 设备名称 = 标准化设备名称(参数.设备名称型号);\n  const 寄存器匹配键 = 生成寄存器匹配键(\n    设备名称,\n    参数.读取地址,\n  );\n\n  const 当前模式 = 参数.模式 ?? 默认模式;\n  const 显示模式 = 当前模式 === 工业输入框模式常量.显示;\n\n  // 显示模式下设置为只读\n  if (显示模式) {\n    输入元素.readOnly = true;\n    输入元素.setAttribute('data-工业输入框模式', '显示');\n  } else {\n    输入元素.readOnly = false;\n    输入元素.setAttribute('data-工业输入框模式', '输入');\n  }\n\n  const 状态: 元素状态 = {\n    参数,\n    输入元素,\n    最近寄存器数据: null,\n    最近显示值: 输入元素.value ?? null,\n    读取任务摘要: null,\n    已注册读取任务: false,\n    正在注册读取任务: false,\n    正在写入: false,\n    寄存器匹配键,\n    设备名称,\n    寄存器事件监听器: () => undefined,\n    设备状态监听器: () => undefined,\n    当前视觉状态: \"未知\",\n    当前模式,\n    输入事件监听器: () => undefined,\n    变更事件监听器: () => undefined,\n    键盘事件监听器: () => undefined,\n  };\n\n  const 寄存器事件监听器: EventListener = (事件) => {\n    if (!(事件 instanceof CustomEvent)) {\n      return;\n    }\n\n    const 详情 = 事件.detail as 保持寄存器事件详情 | undefined;\n    if (!详情) {\n      return;\n    }\n\n    const 事件设备名称 = 提取事件设备名称(\n      详情.设备名称型号,\n    );\n\n    if (!事件设备名称 || 事件设备名称 !== 状态.设备名称) {\n      return;\n    }\n\n    const 事件匹配键 = 生成寄存器匹配键(\n      事件设备名称,\n      状态.参数.读取地址,\n    );\n\n    if (事件匹配键 !== 状态.寄存器匹配键) {\n      return;\n    }\n\n    const 偏移 = 状态.参数.读取地址 - 详情.起始地址;\n    if (偏移 < 0 || 偏移 >= 详情.数据.length) {\n      return;\n    }\n\n    const 数据类型 = 状态.参数.数据类型 ?? 默认数据类型;\n    const 需要寄存器数量 = 获取数据类型寄存器数量(数据类型);\n    const 寄存器片段 = 详情.数据.slice(\n      偏移,\n      偏移 + 需要寄存器数量,\n    );\n\n    if (寄存器片段.length < 需要寄存器数量) {\n      return;\n    }\n\n    更新输入值显示(状态, 寄存器片段, false);\n  };\n\n  状态.寄存器事件监听器 = 寄存器事件监听器;\n  window.addEventListener(保持寄存器事件名称, 寄存器事件监听器);\n\n  const 设备状态监听器: EventListener = (事件) => {\n    if (!(事件 instanceof CustomEvent)) {\n      return;\n    }\n\n    const 详情 = 事件.detail as 设备状态事件详情 | undefined;\n    if (!详情) {\n      return;\n    }\n\n    const 当前状态 = 元素状态映射.get(元素);\n    if (!当前状态) {\n      return;\n    }\n\n    const 事件设备名称 = 提取事件设备名称(详情.设备名称型号);\n    if (!事件设备名称 || 事件设备名称 !== 当前状态.设备名称) {\n      return;\n    }\n\n    更新设备连接状态(元素, 详情.状态);\n  };\n\n  状态.设备状态监听器 = 设备状态监听器;\n  window.addEventListener(设备状态事件名称, 设备状态监听器);\n\n  元素状态映射.set(元素, 状态);\n  复制或初始化视觉状态(状态);\n\n  const 输入事件监听器: EventListener = () => {\n    // 显示模式下不允许触发待写入状态\n    if (状态.当前模式 !== 工业输入框模式常量.显示) {\n      工业输入框状态切换(状态, \"待写入\");\n    }\n  };\n\n  const 变更事件监听器: EventListener = () => {\n    // 显示模式下不执行写入操作\n    if (状态.当前模式 !== 工业输入框模式常量.显示) {\n      void 处理写入操作(状态);\n    }\n  };\n\n  const 键盘事件监听器: EventListener = (事件) => {\n    const 键盘事件 = 事件 as KeyboardEvent;\n    if (键盘事件.key === \"Enter\") {\n      键盘事件.preventDefault();\n      // 显示模式下不执行写入操作\n      if (状态.当前模式 !== 工业输入框模式常量.显示) {\n        void 处理写入操作(状态);\n      }\n    }\n  };\n\n  状态.输入事件监听器 = 输入事件监听器;\n  状态.变更事件监听器 = 变更事件监听器;\n  状态.键盘事件监听器 = 键盘事件监听器;\n\n  输入元素.addEventListener(\"input\", 输入事件监听器);\n  输入元素.addEventListener(\"change\", 变更事件监听器);\n  输入元素.addEventListener(\"keydown\", 键盘事件监听器);\n\n  return 状态;\n};\n\nexport const 工业输入框指令: Directive<HTMLElement, 工业输入框参数> = {\n  mounted(元素, 绑定) {\n    const 参数 = 绑定.value;\n    if (!校验参数(参数)) {\n      return;\n    }\n\n    const 状态 = 创建并初始化状态(元素, 参数);\n    if (!状态) {\n      return;\n    }\n\n    void 安排读取任务(状态);\n  },\n  updated(元素, 绑定) {\n    const 参数 = 绑定.value;\n    if (!校验参数(参数)) {\n      return;\n    }\n\n    const 状态 = 元素状态映射.get(元素);\n\n    if (!状态) {\n      const 新状态 = 创建并初始化状态(元素, 参数);\n      if (新状态) {\n        void 安排读取任务(新状态);\n      }\n      return;\n    }\n\n    状态.参数 = 参数;\n\n    // 更新模式\n    const 新模式 = 参数.模式 ?? 默认模式;\n    if (状态.当前模式 !== 新模式) {\n      状态.当前模式 = 新模式;\n      const 显示模式 = 新模式 === 工业输入框模式常量.显示;\n      状态.输入元素.readOnly = 显示模式;\n      状态.输入元素.setAttribute('data-工业输入框模式', 新模式);\n    }\n\n    const 标准化名称 = 标准化设备名称(状态.参数.设备名称型号);\n    状态.寄存器匹配键 = 生成寄存器匹配键(\n      标准化名称,\n      状态.参数.读取地址,\n    );\n    状态.设备名称 = 标准化名称;\n\n    const 原摘要 = 状态.读取任务摘要;\n    状态.已注册读取任务 =\n      状态.已注册读取任务 && 原摘要 === 生成读取任务摘要(状态.参数);\n    if (!状态.已注册读取任务) {\n      状态.读取任务摘要 = null;\n    }\n\n    if (状态.最近寄存器数据 && 状态.最近寄存器数据.length > 0) {\n      更新输入值显示(状态, 状态.最近寄存器数据, false);\n    }\n\n    void 安排读取任务(状态);\n  },\n  unmounted(元素) {\n    const 状态 = 元素状态映射.get(元素);\n    if (!状态) {\n      return;\n    }\n\n    window.removeEventListener(保持寄存器事件名称, 状态.寄存器事件监听器);\n    window.removeEventListener(设备状态事件名称, 状态.设备状态监听器);\n    状态.输入元素.removeEventListener(\"input\", 状态.输入事件监听器);\n    状态.输入元素.removeEventListener(\"change\", 状态.变更事件监听器);\n    状态.输入元素.removeEventListener(\"keydown\", 状态.键盘事件监听器);\n    元素状态映射.delete(元素);\n  },\n};\n\nexport default 工业输入框指令;\n","import type { Directive, DirectiveBinding } from \"vue\";\nimport { invoke } from \"@tauri-apps/api/core\";\nimport { listen } from \"@tauri-apps/api/event\";\nimport { 使用页面上下文 } from \"./页面上下文\";\n\nexport interface 原始字节按钮配置 {\n  设备名称型号: string; // 设备标识\n  发送数据: number[]; // 要发送的字节数组\n  期望接收字节数?: number; // 可选：期望接收的字节数\n}\n\ninterface 原始字节任务 {\n  设备名称型号: string;\n  操作: {\n    操作类型: \"发送原始字节\";\n    数据: number[];\n    期望接收字节数?: number;\n  };\n  备注?: string;\n  指令来源: string;\n}\n\ninterface 原始字节结果事件 {\n  任务: 原始字节任务;\n  结果: {\n    结果类型: \"发送原始字节\";\n    已发送字节数: number;\n    接收数据?: number[];\n  };\n}\n\nconst 创建唯一指令ID = (() => {\n  let 计数器 = 0;\n  return (元素: HTMLElement) => {\n    const 页面上下文 = 使用页面上下文();\n    const 时间戳 = Date.now();\n    const 随机数 = Math.random().toString(36).substring(2, 9);\n    const 元素ID = 元素.tagName.toLowerCase();\n    return `v-原始字节-${页面上下文.页面名称}-${元素ID}-${时间戳}-${计数器++}-${随机数}`;\n  };\n})();\n\nconst 字节数组转十六进制字符串 = (字节: number[]): string => {\n  return 字节.map(b => b.toString(16).padStart(2, '0').toUpperCase()).join(' ');\n};\n\nconst 发送原始字节任务 = async (\n  配置: 原始字节按钮配置,\n  指令ID: string,\n): Promise<void> => {\n  const 标准化名称 = 配置.设备名称型号.trim();\n  if (!标准化名称) {\n    throw new Error(\"发送原始字节任务需要提供设备名称型号\");\n  }\n\n  const 任务: 原始字节任务 = {\n    设备名称型号: 标准化名称,\n    操作: {\n      操作类型: \"发送原始字节\",\n      数据: 配置.发送数据,\n      期望接收字节数: 配置.期望接收字节数,\n    },\n    备注: `原始字节通信 - ${字节数组转十六进制字符串(配置.发送数据)}`,\n    指令来源: 指令ID,\n  };\n\n  try {\n    await invoke(\"添加Modbus任务\", { 任务 });\n    console.log(`✓ 原始字节任务已发送:`, 任务);\n  } catch (错误) {\n    console.error(\"✗ 发送原始字节任务失败:\", 错误);\n    throw 错误;\n  }\n};\n\nconst 原始字节按钮指令: Directive<HTMLButtonElement, 原始字节按钮配置> = {\n  mounted(元素: HTMLButtonElement, 绑定: DirectiveBinding<原始字节按钮配置>) {\n    const 配置 = 绑定.value;\n    const 指令ID = 创建唯一指令ID(元素);\n\n    // 验证配置\n    if (!配置.发送数据 || 配置.发送数据.length === 0) {\n      console.error(\"原始字节按钮配置错误: 发送数据不能为空\");\n      元素.disabled = true;\n      return;\n    }\n\n    if (!配置.设备名称型号 || 配置.设备名称型号.trim().length === 0) {\n      console.error(\"原始字节按钮配置错误: 设备名称型号不能为空\");\n      元素.disabled = true;\n      return;\n    }\n\n    // 验证字节数据有效性\n    const 无效字节 = 配置.发送数据.find(b => b < 0 || b > 255 || !Number.isInteger(b));\n    if (无效字节 !== undefined) {\n      console.error(`原始字节按钮配置错误: 字节值必须在 0-255 之间，发现无效值: ${无效字节}`);\n      元素.disabled = true;\n      return;\n    }\n\n    元素.dataset.指令ID = 指令ID;\n    元素.dataset.原始字节配置 = JSON.stringify(配置);\n\n    // 添加发送状态样式类\n    元素.classList.add(\"原始字节按钮-就绪\");\n\n    // 点击事件处理\n    const 点击处理器 = async (事件: MouseEvent) => {\n      事件.preventDefault();\n\n      if (元素.disabled) {\n        return;\n      }\n\n      // 更新按钮状态为发送中\n      元素.classList.remove(\"原始字节按钮-就绪\", \"原始字节按钮-成功\", \"原始字节按钮-失败\");\n      元素.classList.add(\"原始字节按钮-发送中\");\n      元素.disabled = true;\n\n      const 原始文本 = 元素.textContent;\n      元素.textContent = \"发送中...\";\n\n      try {\n        await 发送原始字节任务(配置, 指令ID);\n\n        // 设置超时以防没有响应\n        setTimeout(() => {\n          if (元素.classList.contains(\"原始字节按钮-发送中\")) {\n            元素.classList.remove(\"原始字节按钮-发送中\");\n            元素.classList.add(\"原始字节按钮-就绪\");\n            元素.disabled = false;\n            元素.textContent = 原始文本;\n          }\n        }, 2000);\n      } catch (错误) {\n        元素.classList.remove(\"原始字节按钮-发送中\");\n        元素.classList.add(\"原始字节按钮-失败\");\n        元素.textContent = \"发送失败\";\n        元素.disabled = false;\n\n        setTimeout(() => {\n          元素.classList.remove(\"原始字节按钮-失败\");\n          元素.classList.add(\"原始字节按钮-就绪\");\n          元素.textContent = 原始文本;\n        }, 2000);\n      }\n    };\n\n    元素.addEventListener(\"click\", 点击处理器);\n    元素.dataset.点击处理器 = \"已绑定\";\n\n    // 监听原始字节结果事件\n    const 监听器 = listen<原始字节结果事件>(\"modbus任务成功\", (事件) => {\n      const { 任务, 结果 } = 事件.payload as 原始字节结果事件;\n\n      if (任务.指令来源 !== 指令ID) {\n        return;\n      }\n\n      if (结果.结果类型 !== \"发送原始字节\") {\n        return;\n      }\n\n      console.log(`✓ 原始字节发送成功:`, {\n        已发送字节数: 结果.已发送字节数,\n        接收数据: 结果.接收数据 ? 字节数组转十六进制字符串(结果.接收数据) : \"无\",\n      });\n\n      // 更新按钮状态为成功\n      元素.classList.remove(\"原始字节按钮-发送中\", \"原始字节按钮-失败\");\n      元素.classList.add(\"原始字节按钮-成功\");\n\n      if (结果.接收数据) {\n        元素.textContent = `✓ 已接收 ${结果.接收数据.length} 字节`;\n      } else {\n        元素.textContent = `✓ 已发送 ${结果.已发送字节数} 字节`;\n      }\n\n      // 恢复按钮状态\n      setTimeout(() => {\n        元素.classList.remove(\"原始字节按钮-成功\");\n        元素.classList.add(\"原始字节按钮-就绪\");\n        元素.disabled = false;\n\n        // 恢复原始文本\n        元素.textContent = 元素.getAttribute(\"data-original-text\") || \"发送数据\";\n      }, 1500);\n    });\n\n    // 存储监听器以便清理\n    (元素 as any).__原始字节监听器__ = 监听器;\n\n    // 存储原始文本\n    元素.setAttribute(\"data-original-text\", 元素.textContent || \"发送数据\");\n  },\n\n  unmounted(元素: HTMLButtonElement) {\n    // 清理监听器\n    const 监听器 = (元素 as any).__原始字节监听器__;\n    if (监听器) {\n      监听器.then((取消监听: () => void) => 取消监听());\n      delete (元素 as any).__原始字节监听器__;\n    }\n  },\n};\n\nexport default 原始字节按钮指令;\n","import { listen, type UnlistenFn } from \"@tauri-apps/api/event\";\n\nconst 线圈事件名称 = \"modbus-coils-updated\" as const;\nconst 保持寄存器事件名称 = \"modbus-holding-registers-updated\" as const;\nconst 设备状态事件名称 = \"modbus-device-status-changed\" as const;\nconst 线圈DOM事件 = \"modbus-线圈状态更新\" as const;\nconst 保持寄存器DOM事件 = \"modbus-保持寄存器更新\" as const;\nconst 设备状态DOM事件 = \"modbus-设备状态变化\" as const;\n\ninterface 线圈更新事件 {\n  设备名称型号?: string;\n  起始地址: number;\n  状态: boolean[];\n}\n\ninterface 保持寄存器更新事件 {\n  设备名称型号?: string;\n  起始地址: number;\n  数据: number[];\n}\n\ninterface 设备状态事件 {\n  设备名称型号?: string;\n  状态: string;\n  时间戳: number;\n}\n\nlet 已初始化 = false;\nconst 取消监听列表: UnlistenFn[] = [];\n\nconst 安全派发 = <T>(事件名称: string, 明细: T) => {\n  try {\n    window.dispatchEvent(new CustomEvent<T>(事件名称, { detail: 明细 }));\n  } catch (错误) {\n    console.error(`${事件名称} 派发失败`, 错误, 明细);\n  }\n};\n\nconst 监听线圈事件 = async () => {\n  try {\n    const 取消监听 = await listen<线圈更新事件>(线圈事件名称, ({ payload }) => {\n      if (!payload || !Array.isArray(payload.状态)) {\n        console.warn(`${线圈事件名称} 负载无效`, payload);\n        return;\n      }\n\n      payload.状态.forEach((状态, 索引) => {\n        安全派发(线圈DOM事件, {\n          设备名称型号: payload.设备名称型号,\n          线圈地址: payload.起始地址 + 索引,\n          状态,\n        });\n      });\n    });\n    取消监听列表.push(取消监听);\n  } catch (错误) {\n    console.error(`监听 ${线圈事件名称} 失败`, 错误);\n  }\n};\n\nconst 监听保持寄存器事件 = async () => {\n  try {\n    const 取消监听 = await listen<保持寄存器更新事件>(\n      保持寄存器事件名称,\n      ({ payload }) => {\n        if (!payload || !Array.isArray(payload.数据)) {\n          console.warn(`${保持寄存器事件名称} 负载无效`, payload);\n          return;\n        }\n\n        安全派发(保持寄存器DOM事件, {\n          设备名称型号: payload.设备名称型号,\n          起始地址: payload.起始地址,\n          数据: payload.数据,\n        });\n      },\n    );\n    取消监听列表.push(取消监听);\n  } catch (错误) {\n    console.error(`监听 ${保持寄存器事件名称} 失败`, 错误);\n  }\n};\n\nconst 监听设备状态事件 = async () => {\n  try {\n    const 取消监听 = await listen<设备状态事件>(\n      设备状态事件名称,\n      ({ payload }) => {\n        if (!payload || !payload.设备名称型号) {\n          console.warn(`${设备状态事件名称} 负载无效`, payload);\n          return;\n        }\n\n        console.info(\n          `设备状态变化: ${payload.设备名称型号} -> ${payload.状态}`,\n          new Date(payload.时间戳)\n        );\n        安全派发(设备状态DOM事件, payload);\n      },\n    );\n    取消监听列表.push(取消监听);\n  } catch (错误) {\n    console.error(`监听 ${设备状态事件名称} 失败`, 错误);\n  }\n};\n\nconst 注册卸载钩子 = () => {\n  window.addEventListener(\"beforeunload\", () => {\n    while (取消监听列表.length > 0) {\n      const 取消监听 = 取消监听列表.pop();\n      try {\n        取消监听?.();\n      } catch (错误) {\n        console.error(\"取消事件监听失败\", 错误);\n      }\n    }\n    已初始化 = false;\n  });\n};\n\nexport const 初始化事件桥接 = async () => {\n  if (已初始化) {\n    return;\n  }\n\n  已初始化 = true;\n  注册卸载钩子();\n  await Promise.all([\n    监听线圈事件(),\n    监听保持寄存器事件(),\n    监听设备状态事件(),\n  ]);\n};\n\nexport default 初始化事件桥接;\n","import type { NavigationGuard, RouteLocationNormalized, Router } from \"vue-router\";\nimport { 清除指定来源任务 } from \"./任务管理API\";\n\ndeclare global {\n  interface Window {\n    __VUE_ROUTER__?: Router;\n  }\n}\n\nconst 已注册标记 = Symbol(\"已注册页面任务守卫\");\n\nexport interface 页面任务守卫选项 {\n  /**\n   * 是否自动同步页面标题\n   * @default true\n   */\n  自动更新标题?: boolean;\n  /**\n   * 页面标题模板函数\n   */\n  生成页面标题?: (目标路由: RouteLocationNormalized) => string;\n  /**\n   * 当无法解析到标题时使用的默认标题\n   * @default \"工业HMI\"\n   */\n  默认标题?: string;\n  /**\n   * 页面标题后缀,例如 \" - 工业监控\"\n   */\n  标题后缀?: string;\n  /**\n   * 是否在控制台输出清理日志\n   * @default true\n   */\n  输出日志?: boolean;\n}\n\nconst typeof目标路由名称为字符串 = (名称: RouteLocationNormalized[\"name\"]): 名称 is string =>\n  typeof 名称 === \"string\" && 名称.trim().length > 0;\n\nconst 默认标题生成器 = (目标路由: RouteLocationNormalized, 默认标题: string): string => {\n  const 元信息标题 = 目标路由.meta?.标题 as string | undefined;\n  if (元信息标题 && 元信息标题.trim().length > 0) {\n    return 元信息标题;\n  }\n\n  if (typeof目标路由名称为字符串(目标路由.name)) {\n    return String(目标路由.name);\n  }\n\n  return 默认标题;\n};\n\nconst 设置文档标题 = (\n  路由: RouteLocationNormalized,\n  选项: 页面任务守卫选项,\n) => {\n  if (选项.自动更新标题 === false) {\n    return;\n  }\n\n  const 默认标题 = 选项.默认标题 ?? \"工业HMI\";\n  const 基础标题 = 选项.生成页面标题\n    ? 选项.生成页面标题(路由)\n    : 默认标题生成器(路由, 默认标题);\n\n  const 标题后缀 = 选项.标题后缀 ?? \" - 工业监控系统\";\n  const 最终标题 = 基础标题\n    ? `${基础标题}${标题后缀}`\n    : 默认标题;\n\n  if (typeof document !== \"undefined\") {\n    document.title = 最终标题;\n  }\n};\n\nconst 输出清理日志 = (\n  页面名称: string,\n  清除数量: number,\n  输出日志: boolean,\n) => {\n  if (!输出日志) {\n    return;\n  }\n\n  if (清除数量 > 0) {\n    console.info(`✓ 自动清理页面任务: ${页面名称}`, { 清除数量 });\n  }\n};\n\nexport const 创建页面任务守卫 = (\n  选项: 页面任务守卫选项 = {},\n): NavigationGuard => {\n  const 输出日志 = 选项.输出日志 ?? true;\n\n  return async (to, from, next) => {\n    try {\n      设置文档标题(to, 选项);\n\n      if (typeof目标路由名称为字符串(from.name)) {\n        const 页面名称 = String(from.name);\n        try {\n          const 清除数量 = await 清除指定来源任务(页面名称);\n          输出清理日志(页面名称, 清除数量, 输出日志);\n        } catch (错误) {\n          if (输出日志) {\n            console.error(`✗ 自动清理页面任务失败: ${页面名称}`, 错误);\n          }\n        }\n      }\n    } finally {\n      next();\n    }\n  };\n};\n\nexport const 设置全局路由引用 = (路由器: Router) => {\n  if (typeof window !== \"undefined\") {\n    window.__VUE_ROUTER__ = 路由器;\n  }\n};\n\nexport const 注册页面任务守卫 = (\n  路由器: Router,\n  选项: 页面任务守卫选项 = {},\n) => {\n  if ((路由器 as any)[已注册标记]) {\n    return;\n  }\n\n  (路由器 as any)[已注册标记] = true;\n  设置全局路由引用(路由器);\n  路由器.beforeEach(创建页面任务守卫(选项));\n};\n","import type { App, Plugin } from \"vue\";\nimport 工业按钮指令, {\n  工业按钮类型常量,\n  type 工业按钮类型,\n  type 工业按钮参数,\n  type 前端Modbus任务,\n  type 上报执行结果,\n} from \"./工具函数/工业按钮指令\";\nimport 工业输入框指令, {\n  工业输入框模式常量,\n  type 工业输入框数据类型,\n  type 工业输入框模式,\n  type 工业输入框参数,\n} from \"./工具函数/工业输入框指令\";\nimport 原始字节按钮指令, {\n  type 原始字节按钮配置,\n} from \"./工具函数/原始字节按钮指令\";\nimport {\n  初始化事件桥接,\n} from \"./工具函数/事件桥接\";\nimport {\n  提供页面上下文,\n  使用页面上下文,\n  生成页面级指令来源,\n  获取当前页面名称,\n  type 页面上下文信息,\n} from \"./工具函数/页面上下文\";\nimport {\n  创建页面任务守卫,\n  注册页面任务守卫,\n  设置全局路由引用,\n  type 页面任务守卫选项,\n} from \"./工具函数/页面任务守卫\";\nimport {\n  添加Modbus任务,\n  批量添加Modbus任务,\n  清除指定来源任务,\n  清除当前页面任务,\n  清除所有TypeScript任务,\n  添加读取保持寄存器任务,\n  添加读取线圈任务,\n  添加写入单个寄存器任务,\n  添加写入多个寄存器任务,\n  添加写入单个线圈任务,\n  添加写入多个线圈任务,\n  添加原始字节任务,\n  Modbus操作类型,\n  type Modbus任务配置,\n} from \"./工具函数/任务管理API\";\nimport {\n  上报任务至队列,\n  创建读取线圈任务,\n  创建读取保持寄存器任务,\n  创建写入单个线圈任务,\n  创建写入多个线圈任务,\n  创建写入单个保持寄存器任务,\n  创建写入多个保持寄存器任务,\n  监听线圈状态,\n  监听特定线圈状态,\n  监听保持寄存器,\n  监听特定寄存器,\n  监听设备状态,\n  监听特定设备状态,\n  寄存器转数值,\n  数值转寄存器,\n  转换寄存器为显示文本,\n  转换显示文本为寄存器,\n  生成线圈匹配键,\n  生成寄存器匹配键,\n  数据类型常量,\n  获取数据类型寄存器数量,\n  数据类型寄存器数量映射,\n  线圈状态事件名称,\n  保持寄存器事件名称,\n  设备状态事件名称,\n  执行线圈读写操作,\n  执行寄存器读写操作,\n  type 线圈状态事件详情,\n  type 保持寄存器事件详情,\n  type 设备状态事件详情,\n  type 线圈任务参数,\n  type 寄存器任务参数,\n  type 写入单个线圈参数,\n  type 写入多个线圈参数,\n  type 写入单个寄存器参数,\n  type 写入多个寄存器参数,\n  type 数据类型,\n  type 寄存器显示选项,\n  type 显示文本解析选项,\n  type 线圈读写操作参数,\n  type 线圈读写操作结果,\n  type 线圈寄存器读写类型,\n  type 寄存器读写操作参数,\n  type 寄存器读写操作结果,\n} from \"./工具函数/工业组件API\";\nimport \"./assets/工业组件状态样式.css\";\n\nexport {\n  工业按钮指令,\n  工业按钮类型常量,\n  工业输入框指令,\n  工业输入框模式常量,\n  原始字节按钮指令,\n  初始化事件桥接,\n  上报任务至队列,\n  提供页面上下文,\n  使用页面上下文,\n  生成页面级指令来源,\n  获取当前页面名称,\n  创建页面任务守卫,\n  注册页面任务守卫,\n  设置全局路由引用,\n  添加Modbus任务,\n  批量添加Modbus任务,\n  清除指定来源任务,\n  清除当前页面任务,\n  清除所有TypeScript任务,\n  添加读取保持寄存器任务,\n  添加读取线圈任务,\n  添加写入单个寄存器任务,\n  添加写入多个寄存器任务,\n  添加写入单个线圈任务,\n  添加写入多个线圈任务,\n  添加原始字节任务,\n  Modbus操作类型,\n  // 工业组件API\n  创建读取线圈任务,\n  创建读取保持寄存器任务,\n  创建写入单个线圈任务,\n  创建写入多个线圈任务,\n  创建写入单个保持寄存器任务,\n  创建写入多个保持寄存器任务,\n  监听线圈状态,\n  监听特定线圈状态,\n  监听保持寄存器,\n  监听特定寄存器,\n  监听设备状态,\n  监听特定设备状态,\n  寄存器转数值,\n  数值转寄存器,\n  转换寄存器为显示文本,\n  转换显示文本为寄存器,\n  生成线圈匹配键,\n  生成寄存器匹配键,\n  获取数据类型寄存器数量,\n  数据类型寄存器数量映射,\n  数据类型常量,\n  线圈状态事件名称,\n  保持寄存器事件名称,\n  设备状态事件名称,\n  执行线圈读写操作,\n  执行寄存器读写操作,\n};\n\nexport type {\n  工业按钮参数,\n  工业按钮类型,\n  工业输入框参数,\n  工业输入框数据类型,\n  工业输入框模式,\n  原始字节按钮配置,\n  前端Modbus任务,\n  上报执行结果,\n  页面上下文信息,\n  页面任务守卫选项,\n  Modbus任务配置,\n  // 工业组件API类型\n  线圈状态事件详情,\n  保持寄存器事件详情,\n  设备状态事件详情,\n  线圈任务参数,\n  寄存器任务参数,\n  写入单个线圈参数,\n  写入多个线圈参数,\n  写入单个寄存器参数,\n  写入多个寄存器参数,\n  数据类型,\n  寄存器显示选项,\n  显示文本解析选项,\n  线圈读写操作参数,\n  线圈读写操作结果,\n  线圈寄存器读写类型,\n  寄存器读写操作参数,\n  寄存器读写操作结果,\n};\n\nexport interface 工业HMI插件选项 {\n  自动初始化事件桥接?: boolean;\n}\n\nexport const 创建工业HMI插件 = (\n  选项: 工业HMI插件选项 = {},\n): Plugin => ({\n  install(应用: App) {\n    应用.directive(\"工业按钮\", 工业按钮指令);\n    应用.directive(\"工业输入框\", 工业输入框指令);\n    应用.directive(\"原始字节按钮\", 原始字节按钮指令);\n\n    if (选项.自动初始化事件桥接 ?? true) {\n      初始化事件桥接().catch((错误) => {\n        console.error(\"工业HMI插件初始化事件桥接失败\", 错误);\n      });\n    }\n  },\n});\n\nexport const 工业HMI插件: Plugin = 创建工业HMI插件();\n\nexport default 工业HMI插件;\n"],"names":["NavigationType","NavigationDirection","NavigationFailureType","routeLocationKey","useRoute","_name","inject","获取当前页面名称","instance","getCurrentInstance","router","提供页面上下文","_页面名称","_页面路径","使用页面上下文","生成页面级指令来源","指令名称","页面名称","Modbus操作类型","添加Modbus任务","任务配置","标准化设备名称","完整任务","队列长度","invoke","错误","批量添加Modbus任务","任务列表","成功数量","失败数量","队列长度列表","错误列表","清除指定来源任务","指令来源","清除数量","清除当前页面任务","清除所有TypeScript任务","添加读取保持寄存器任务","配置","添加读取线圈任务","添加写入单个寄存器任务","添加写入多个寄存器任务","添加写入单个线圈任务","添加写入多个线圈任务","添加原始字节任务","线圈状态事件名称","保持寄存器事件名称","设备状态事件名称","设备名称型号","提取非空设备名称","原始名称","标准化名称","生成线圈匹配键","线圈地址","生成寄存器匹配键","寄存器地址","上报任务至队列","来源","错误任务","成功队列长度","成功任务数量","任务","创建读取线圈任务","参数","设备名称","创建读取保持寄存器任务","创建写入单个线圈任务","创建写入多个线圈任务","创建写入单个保持寄存器任务","创建写入多个保持寄存器任务","执行线圈读写操作","地址","读写类型","是否读写一次","数量","停止监听函数","取消监听函数","已清除任务","清理任务","停止监听并清理","匹配键","已触发一次","监听特定线圈状态","状态","_a","起始地址","状态缓存","尝试触发回调","状态列表","偏移","当前状态","监听线圈状态","详情","上报结果","项目","执行寄存器读写操作","数据类型","寄存器块大小","获取数据类型寄存器数量","逻辑数量","读取寄存器数量","寄存器匹配键","监听特定寄存器","寄存器数据","是否为多值","解析后的数值","数值列表","转换失败","索引","偏移量","寄存器片段","单值","寄存器转数值","比例系数","数值","寄存器数值","数值转寄存器","数值数组","寄存器数值列表","转换结果","回调函数","监听器","事件","事件设备名称","监听保持寄存器","读取数量","分隔位置","目标设备","地址片段","目标地址","目标设备名称","监听设备状态","监听特定设备状态","数据类型常量","数据类型寄存器数量映射","小数位数","原始值","高位","低位","缓冲区","视图","显示值","精度","原始浮点","缩放值","转换寄存器为显示文本","选项","默认值","需要寄存器数量","有效比例","默认小数位数","转换显示文本为寄存器","输入文本","文本","显示数值","最小值","最大值","工业按钮类型常量","默认读取数量","允许按钮类型","允许操作目标","状态样式映射","状态数据属性","设备状态属性","元素状态映射","名称","提取事件设备名称","生成读取任务摘要","计算线圈写入状态","类型","创建读取任务","创建写入任务","线圈状态","数值在范围内","值","生成校验错误","校验参数","安排读取任务","新摘要","更新元素状态样式","元素","状态值","目标样式","更新设备连接状态","连接状态","创建并保存状态","初始线圈匹配键","线圈状态监听器","设备状态监听器","点击处理器","目标状态","按下处理器","弹起处理器","工业按钮指令","绑定","原摘要","新状态","工业输入框模式常量","默认比例系数","数据属性状态","输入框状态样式映射","设备连接状态样式映射","获取读取寄存器数量","默认数据类型","寄存器值列表","写入地址","输入框允许数据类型","输入框视觉状态全集","默认模式","最小数量","指定数量","移除旧样式","设置视觉状态","样式","复制或初始化视觉状态","更新输入值显示","强制","输入元素","当前聚焦","显示文本","处理写入操作","用户输入","工业输入框状态切换","创建并初始化状态","当前模式","寄存器事件监听器","输入事件监听器","变更事件监听器","键盘事件监听器","键盘事件","工业输入框指令","新模式","显示模式","创建唯一指令ID","计数器","页面上下文","时间戳","随机数","元素ID","字节数组转十六进制字符串","字节","b","发送原始字节任务","指令ID","原始字节按钮指令","无效字节","原始文本","listen","结果","取消监听","线圈事件名称","线圈DOM事件","保持寄存器DOM事件","设备状态DOM事件","已初始化","取消监听列表","安全派发","事件名称","明细","监听线圈事件","payload","监听保持寄存器事件","监听设备状态事件","注册卸载钩子","初始化事件桥接","已注册标记","typeof目标路由名称为字符串","默认标题生成器","目标路由","默认标题","元信息标题","设置文档标题","路由","基础标题","标题后缀","最终标题","输出清理日志","输出日志","创建页面任务守卫","to","from","next","设置全局路由引用","路由器","注册页面任务守卫","创建工业HMI插件","应用","工业HMI插件"],"mappings":"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","x_google_ignoreList":[0]}