From 523f96c3b2f8b9078ce80285d2a25f6b225ce683 Mon Sep 17 00:00:00 2001 From: sunlei Date: Sat, 25 Jul 2026 09:51:27 +0800 Subject: [PATCH] =?UTF-8?q?style:=20=E7=BB=9F=E4=B8=80Admin=20JSDoc?= =?UTF-8?q?=E8=A7=84=E8=8C=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/adapter/component/index.ts | 5 - .../src/api/blog/preview-url.ts | 11 - apps/web-antdv-next/src/api/core/auth.ts | 2 - apps/web-antdv-next/src/api/core/menu.spec.ts | 4 - .../src/api/qqbot/message-push.spec.ts | 4 - .../src/api/qqbot/message-push.ts | 108 --- apps/web-antdv-next/src/api/qqbot/napcat.ts | 9 - apps/web-antdv-next/src/api/request.ts | 3 - .../src/api/system/environment.ts | 22 - apps/web-antdv-next/src/api/system/menu.ts | 36 - apps/web-antdv-next/src/api/system/network.ts | 98 --- .../src/components/ktTable/KtTable.tsx | 23 - .../ktTable/components/KtTableFooter.tsx | 8 - .../ktTable/components/KtTableHeader.tsx | 7 - .../components/KtTableResizableTitle.tsx | 8 - .../ktTable/components/KtTableSearch.tsx | 8 - .../ktTable/components/KtTableSettings.tsx | 18 - .../ktTable/components/KtTableSummary.tsx | 23 - .../components/ktTable/hooks/useKtTable.ts | 10 - .../ktTable/hooks/useKtTableActions.spec.tsx | 1 - .../ktTable/hooks/useKtTableActions.tsx | 28 - .../ktTable/hooks/useKtTableColumns.ts | 11 - .../ktTable/hooks/useKtTableResolvedProps.ts | 5 - .../richText/KtTiptapHtmlEditor.spec.tsx | 61 -- .../richText/KtTiptapHtmlEditor.tsx | 26 - apps/web-antdv-next/src/preferences.ts | 5 - apps/web-antdv-next/src/router/admin-sso.ts | 15 - apps/web-antdv-next/src/router/guard.ts | 2 - apps/web-antdv-next/src/router/index.ts | 3 - apps/web-antdv-next/src/router/routes/core.ts | 7 - .../web-antdv-next/src/router/routes/index.ts | 6 - .../src/router/routes/modules/qqbot.spec.ts | 33 - apps/web-antdv-next/src/store/auth.ts | 4 - .../src/views/blog/article/list.spec.ts | 6 - .../src/views/blog/article/list.tsx | 29 - .../src/views/blog/article/preview/index.tsx | 51 -- .../src/views/blog/modules/article-form.ts | 72 -- .../components/EnvironmentEventStream.vue | 6 - .../components/EnvironmentEvidencePanel.vue | 13 - .../components/EnvironmentSiteRail.vue | 18 - .../components/EnvironmentStatusBar.vue | 11 - .../components/EnvironmentTopology.vue | 12 - .../useEnvironmentDashboardStream.ts | 49 -- .../analytics/environment-dashboard.spec.tsx | 34 - .../src/views/dashboard/analytics/index.vue | 151 ---- .../src/views/examples/cropper/index.vue | 3 - .../src/views/examples/form/basic.vue | 3 - .../components/AccountConfigPanel.spec.tsx | 8 - .../AccountMessagePushModal.spec.tsx | 12 - .../components/AccountMessagePushModal.tsx | 62 -- .../AccountMessagePushPanel.spec.tsx | 9 - .../components/AccountMessagePushPanel.tsx | 49 -- .../MessagePushTargetPicker.spec.tsx | 3 - .../components/MessagePushTargetPicker.tsx | 65 -- .../src/views/qqbot/account/list.tsx | 3 - .../qqbot/account/napcat-boundary.spec.ts | 9 - .../qqbot/account/napcat-webui/index.tsx | 45 -- .../napcat-webui/napcat-webui.spec.tsx | 6 - .../useNapcatWebuiGatewaySession.ts | 45 -- .../napcat/NapcatRuntimeProfileDrawer.tsx | 21 - .../qqbot/message-subscription/list.spec.tsx | 7 - .../views/qqbot/message-subscription/list.tsx | 34 - .../MessageTemplateMentions.spec.tsx | 1 - .../components/MessageTemplateMentions.tsx | 22 - .../qqbot/message-template/list.spec.tsx | 6 - .../src/views/qqbot/message-template/list.tsx | 37 - .../src/views/qqbot/permission/list.tsx | 6 - .../plugin-task/components/TaskRunDrawer.tsx | 8 - .../components/PluginPlatformStateDrawer.tsx | 17 - .../NetworkDdnsRecordModal.spec.tsx | 2 - .../components/NetworkDdnsRecordModal.tsx | 51 -- .../components/NetworkDdnsTable.spec.tsx | 1 - .../network/components/NetworkDdnsTable.tsx | 47 -- .../NetworkEndpointHistoryDrawer.spec.tsx | 1 - .../NetworkEndpointHistoryDrawer.tsx | 6 - .../NetworkPortForwardModal.spec.tsx | 1 - .../components/NetworkPortForwardModal.tsx | 23 - .../composables/useNetworkManagementStream.ts | 17 - .../src/views/system/network/list.spec.tsx | 5 - .../src/views/system/network/list.tsx | 78 -- internal/commit/husky-fast-check.mjs | 2 + internal/jsdoc-policy/check-jsdoc.mjs | 709 ++++++++++++++++++ internal/jsdoc-policy/check-jsdoc.test.mjs | 252 +++++++ internal/vite-config/src/options.ts | 3 - internal/vite-config/src/plugins/importmap.ts | 3 - internal/vite-config/src/typing.ts | 239 +----- internal/vite-config/src/utils/env.ts | 5 - package.json | 6 +- .../base/shared/src/constants/globals.ts | 8 - .../@core/base/shared/src/constants/vben.ts | 12 - .../@core/base/shared/src/global-state.ts | 5 - packages/@core/base/shared/src/utils/date.ts | 15 - .../@core/base/shared/src/utils/download.ts | 4 - .../@core/base/shared/src/utils/inference.ts | 23 - packages/@core/base/shared/src/utils/stack.ts | 18 - packages/@core/base/shared/src/utils/to.ts | 5 - packages/@core/base/typings/src/app.d.ts | 46 -- packages/@core/base/typings/src/basic.d.ts | 15 - packages/@core/base/typings/src/helper.d.ts | 54 -- .../@core/base/typings/src/menu-record.ts | 47 -- packages/@core/base/typings/src/tabs.ts | 3 - .../@core/base/typings/src/vue-router.d.ts | 87 --- .../@core/composables/src/use-layout-style.ts | 3 - .../@core/composables/src/use-namespace.ts | 4 - packages/@core/preferences/src/constants.ts | 3 - packages/@core/preferences/src/preferences.ts | 22 - packages/@core/preferences/src/types.ts | 128 ---- .../@core/preferences/src/use-preferences.ts | 64 -- packages/@core/ui-kit/form-ui/src/form-api.ts | 9 - .../ui-kit/form-ui/src/form-render/helper.ts | 7 - packages/@core/ui-kit/form-ui/src/types.ts | 203 ----- .../src/components/layout-content.vue | 6 - .../src/components/layout-footer.vue | 7 - .../src/components/layout-header.vue | 24 - .../src/components/layout-sidebar.vue | 60 -- .../src/components/layout-tabbar.vue | 3 - .../ui-kit/layout-ui/src/hooks/use-layout.ts | 15 - .../@core/ui-kit/layout-ui/src/vben-layout.ts | 132 ---- .../ui-kit/layout-ui/src/vben-layout.vue | 27 - .../src/components/normal-menu/normal-menu.ts | 16 - .../menu-ui/src/hooks/use-menu-context.ts | 12 - .../ui-kit/menu-ui/src/hooks/use-menu.ts | 3 - .../@core/ui-kit/menu-ui/src/sub-menu.vue | 6 - packages/@core/ui-kit/menu-ui/src/types.ts | 58 -- .../@core/ui-kit/menu-ui/src/utils/index.ts | 5 - .../@core/ui-kit/popup-ui/src/alert/alert.ts | 32 - .../ui-kit/popup-ui/src/drawer/drawer.ts | 117 --- .../ui-kit/popup-ui/src/drawer/drawer.vue | 6 - .../@core/ui-kit/popup-ui/src/modal/modal.ts | 131 ---- .../@core/ui-kit/popup-ui/src/modal/modal.vue | 3 - .../popup-ui/src/modal/use-modal-draggable.ts | 5 - .../src/components/back-top/backtop.ts | 12 - .../shadcn-ui/src/components/button/button.ts | 18 - .../src/components/context-menu/interface.ts | 28 - .../count-to-animator/count-to-animator.vue | 6 - .../src/components/dropdown-menu/interface.ts | 16 - .../input-password/input-password.vue | 3 - .../input-password/password-strength.vue | 3 - .../shadcn-ui/src/components/logo/logo.vue | 27 - .../src/components/pin-input/types.ts | 19 - .../src/components/scrollbar/scrollbar.vue | 6 - .../src/components/spinner/loading.vue | 10 - .../src/components/spinner/spinner.vue | 7 - .../ui-kit/shadcn-ui/src/ui/tree/types.ts | 17 - packages/@core/ui-kit/tabs-ui/src/types.ts | 38 - packages/constants/src/core.ts | 6 - .../effects/access/src/access-control.vue | 8 - packages/effects/access/src/accessible.ts | 10 - packages/effects/access/src/directive.ts | 6 - .../api-component/api-component.vue | 29 - .../common-ui/src/components/captcha/types.ts | 127 ---- .../src/components/col-page/types.ts | 8 - .../src/components/count-to/types.ts | 19 - .../src/components/cropper/cropper.vue | 44 -- .../ellipsis-text/ellipsis-text.vue | 44 -- .../components/icon-picker/icon-picker.vue | 9 - .../src/components/icon-picker/icons.ts | 3 - .../src/components/json-viewer/types.ts | 13 - .../src/components/loading/directive.ts | 2 - .../src/components/loading/loading.vue | 10 - .../src/components/loading/spinner.vue | 7 - .../common-ui/src/components/page/types.ts | 8 - .../src/components/resize/resize.vue | 4 - .../src/ui/authentication/code-login.vue | 18 - .../src/ui/authentication/dingding-login.vue | 3 - .../src/ui/authentication/forget-password.vue | 15 - .../ui/authentication/login-expired-modal.vue | 3 - .../src/ui/authentication/qrcode-login.vue | 21 - .../src/ui/authentication/register.vue | 15 - .../common-ui/src/ui/authentication/types.ts | 42 -- .../common-ui/src/ui/fallback/fallback.ts | 17 - .../effects/hooks/src/use-design-tokens.ts | 16 - .../effects/hooks/src/use-hover-toggle.ts | 2 - packages/effects/hooks/src/use-pagination.ts | 8 - .../src/authentication/authentication.vue | 3 - .../layouts/src/basic/content/content.vue | 3 - .../layouts/src/basic/header/header.vue | 3 - .../layouts/src/basic/menu/use-extra-menu.ts | 13 - .../layouts/src/basic/menu/use-mixed-menu.ts | 23 - .../layouts/src/basic/tabbar/use-tabbar.ts | 6 - .../src/widgets/notification/notification.vue | 6 - .../layouts/src/widgets/notification/types.ts | 4 - .../src/widgets/preferences/preferences.vue | 8 - .../src/widgets/theme-toggle/theme-button.vue | 3 - .../widgets/user-dropdown/user-dropdown.vue | 20 - .../src/request-client/modules/downloader.ts | 5 - .../request/src/request-client/modules/sse.ts | 3 - .../src/request-client/preset-interceptors.ts | 3 - .../src/request-client/request-client.ts | 4 - .../request/src/request-client/types.ts | 20 - packages/locales/src/i18n.ts | 18 - packages/locales/src/typing.ts | 12 - packages/stores/src/modules/access.ts | 33 - packages/stores/src/modules/tabbar.ts | 33 - packages/stores/src/modules/timezone.ts | 13 - packages/stores/src/modules/user.ts | 24 - packages/stores/src/setup.ts | 3 - packages/types/src/user.ts | 10 - .../utils/src/helpers/get-popup-container.ts | 5 - 199 files changed, 968 insertions(+), 4488 deletions(-) create mode 100644 internal/jsdoc-policy/check-jsdoc.mjs create mode 100644 internal/jsdoc-policy/check-jsdoc.test.mjs diff --git a/apps/web-antdv-next/src/adapter/component/index.ts b/apps/web-antdv-next/src/adapter/component/index.ts index 1a9cc92..734a382 100644 --- a/apps/web-antdv-next/src/adapter/component/index.ts +++ b/apps/web-antdv-next/src/adapter/component/index.ts @@ -1,8 +1,3 @@ -/** - * 通用组件共同的使用的基础组件,原先放在 adapter/form 内部,限制了使用范围,这里提取出来,方便其他地方使用 - * 可用于 vben-form、vben-modal、vben-drawer 等组件使用, - */ - /* eslint-disable vue/one-component-per-file */ import type { UploadChangeParam, UploadFile, UploadProps } from 'antdv-next'; diff --git a/apps/web-antdv-next/src/api/blog/preview-url.ts b/apps/web-antdv-next/src/api/blog/preview-url.ts index b064a99..65d90e7 100644 --- a/apps/web-antdv-next/src/api/blog/preview-url.ts +++ b/apps/web-antdv-next/src/api/blog/preview-url.ts @@ -10,12 +10,6 @@ type BlogPreviewEnv = { VITE_KT_BLOG_WEB_BASE_URL?: string; }; -/** - * Builds the public KT Blog Web URL used by the Admin preview iframe. - * @param article Article data whose slug is the preferred public post route key. - * @param articleId Admin article id retained in the query string for preview traceability. - * @returns Absolute or same-origin iframe URL for the KT Blog Web post route. - */ export function buildKtBlogPreviewUrl( article: BlogPreviewArticle, articleId: string, @@ -33,11 +27,6 @@ export function buildKtBlogPreviewUrl( return url.toString(); } -/** - * Resolves the Blog Web preview origin and refuses silent localhost fallback in production. - * @param env Vite import meta environment; tests pass a small object to cover production guards. - * @returns Configured Blog Web base URL, or the local development default outside production. - */ export function resolveKtBlogWebBaseUrl(env: BlogPreviewEnv) { const configured = env.VITE_KT_BLOG_WEB_BASE_URL?.trim(); if (configured) { diff --git a/apps/web-antdv-next/src/api/core/auth.ts b/apps/web-antdv-next/src/api/core/auth.ts index 963f22d..0aecad0 100644 --- a/apps/web-antdv-next/src/api/core/auth.ts +++ b/apps/web-antdv-next/src/api/core/auth.ts @@ -1,7 +1,6 @@ import { baseRequestClient, requestClient } from '#/api/request'; export namespace AuthApi { - /** 登录接口参数 */ export interface LoginParams { password?: string; username?: string; @@ -12,7 +11,6 @@ export namespace AuthApi { username?: string; } - /** 登录接口返回值 */ export interface LoginResult { accessToken: string; wordpressAvailable?: boolean; diff --git a/apps/web-antdv-next/src/api/core/menu.spec.ts b/apps/web-antdv-next/src/api/core/menu.spec.ts index e0dd75b..b1ed446 100644 --- a/apps/web-antdv-next/src/api/core/menu.spec.ts +++ b/apps/web-antdv-next/src/api/core/menu.spec.ts @@ -28,10 +28,6 @@ const messagePushMenuNames = [ 'QqBotAccountMessagePushToggle', ]; -/** - * Reads the private menu whitelist's literal source array without exporting it. - * @returns Every string literal used to initialize `SUPPORTED_ADMIN_MENU_NAMES`. - */ function getSupportedAdminMenuNameLiterals() { const sourceFile = ts.createSourceFile( 'menu.ts', diff --git a/apps/web-antdv-next/src/api/qqbot/message-push.spec.ts b/apps/web-antdv-next/src/api/qqbot/message-push.spec.ts index be0860a..377c463 100644 --- a/apps/web-antdv-next/src/api/qqbot/message-push.spec.ts +++ b/apps/web-antdv-next/src/api/qqbot/message-push.spec.ts @@ -549,10 +549,6 @@ const messagePushCallerNames = [ 'updateMessageTemplate', ]; -/** - * Type-checks this focused contract spec with a virtual request client boundary. - * @returns Deterministic TypeScript diagnostics for only this spec and `message-push.ts`. - */ function getMessagePushContractDiagnostics() { const appRoot = resolve('apps/web-antdv-next'); const configPath = resolve(appRoot, 'tsconfig.json'); diff --git a/apps/web-antdv-next/src/api/qqbot/message-push.ts b/apps/web-antdv-next/src/api/qqbot/message-push.ts index 5a3fe69..11f810c 100644 --- a/apps/web-antdv-next/src/api/qqbot/message-push.ts +++ b/apps/web-antdv-next/src/api/qqbot/message-push.ts @@ -181,42 +181,24 @@ export namespace QqbotMessagePushApi { } } -/** - * Lists registered system message sources available to the Admin UI. - * @returns Public source definitions without internal adapter details. - */ export function getMessagePushSources() { return requestClient.get( '/qqbot/message-push/sources', ); } -/** - * Loads one public source definition by its stable source key. - * @param sourceKey - String source identity, encoded before becoming a URL segment. - * @returns The requested source definition. - */ export function getMessagePushSourceDetail(sourceKey: string) { return requestClient.get( `/qqbot/message-push/sources/${encodeURIComponent(sourceKey)}`, ); } -/** - * Loads server-evaluated options for the built-in STUN port-change source. - * @returns Eligible and disabled port-forward and DDNS options. - */ export function getStunMappingPortChangedOptions() { return requestClient.get( '/qqbot/message-push/sources/network.stun.mapping-port-changed/options', ); } -/** - * Pages global message subscriptions using independent list filters. - * @param params - Pagination, source, name, and enabled-state filters. - * @returns A strict `{ items, total }` subscription page. - */ export function getMessageSubscriptionList( params: QqbotMessagePushApi.MessageSubscriptionListQuery, ) { @@ -225,11 +207,6 @@ export function getMessageSubscriptionList( >('/qqbot/message-push/subscriptions', { params }); } -/** - * Creates one source-scoped global message subscription. - * @param data - Complete subscription name, source, configuration, and enabled state. - * @returns The persisted subscription view. - */ export function createMessageSubscription( data: QqbotMessagePushApi.MessageSubscriptionInput, ) { @@ -239,12 +216,6 @@ export function createMessageSubscription( ); } -/** - * Replaces one global subscription without coercing its string ID. - * @param id - Stable subscription ID, encoded before becoming a URL segment. - * @param data - Complete replacement subscription input. - * @returns The updated subscription view. - */ export function updateMessageSubscription( id: string, data: QqbotMessagePushApi.MessageSubscriptionInput, @@ -255,12 +226,6 @@ export function updateMessageSubscription( ); } -/** - * Changes whether a subscription matches future source events. - * @param id - Stable subscription ID, encoded before becoming a URL segment. - * @param enabled - Requested future enabled state. - * @returns The updated subscription view. - */ export function setMessageSubscriptionEnabled(id: string, enabled: boolean) { return requestClient.put( `/qqbot/message-push/subscriptions/${encodeURIComponent(id)}/enabled`, @@ -268,22 +233,12 @@ export function setMessageSubscriptionEnabled(id: string, enabled: boolean) { ); } -/** - * Soft-deletes one global message subscription. - * @param id - Stable subscription ID, encoded before becoming a URL segment. - * @returns Whether the subscription was deleted. - */ export function deleteMessageSubscription(id: string) { return requestClient.delete( `/qqbot/message-push/subscriptions/${encodeURIComponent(id)}`, ); } -/** - * Pages global message templates using independent list filters. - * @param params - Pagination, source, name, and enabled-state filters. - * @returns A strict `{ items, total }` template page. - */ export function getMessageTemplateList( params: QqbotMessagePushApi.MessageTemplateListQuery, ) { @@ -292,11 +247,6 @@ export function getMessageTemplateList( >('/qqbot/message-push/templates', { params }); } -/** - * Creates one source-scoped global message template. - * @param data - Complete template content, source, metadata, and enabled state. - * @returns The persisted template view. - */ export function createMessageTemplate( data: QqbotMessagePushApi.MessageTemplateInput, ) { @@ -306,12 +256,6 @@ export function createMessageTemplate( ); } -/** - * Replaces one global message template without coercing its string ID. - * @param id - Stable template ID, encoded before becoming a URL segment. - * @param data - Complete replacement template input. - * @returns The updated template view. - */ export function updateMessageTemplate( id: string, data: QqbotMessagePushApi.MessageTemplateInput, @@ -322,12 +266,6 @@ export function updateMessageTemplate( ); } -/** - * Changes whether a template can be selected for future bindings and events. - * @param id - Stable template ID, encoded before becoming a URL segment. - * @param enabled - Requested future enabled state. - * @returns The updated template view. - */ export function setMessageTemplateEnabled(id: string, enabled: boolean) { return requestClient.put( `/qqbot/message-push/templates/${encodeURIComponent(id)}/enabled`, @@ -335,22 +273,12 @@ export function setMessageTemplateEnabled(id: string, enabled: boolean) { ); } -/** - * Soft-deletes one global message template when the backend permits it. - * @param id - Stable template ID, encoded before becoming a URL segment. - * @returns Whether the template was deleted. - */ export function deleteMessageTemplate(id: string) { return requestClient.delete( `/qqbot/message-push/templates/${encodeURIComponent(id)}`, ); } -/** - * Renders a source-scoped message template using server-controlled example data. - * @param data - Template content and source identity only. - * @returns Safe rendered text and the example variables used. - */ export function previewMessageTemplate( data: QqbotMessagePushApi.MessageTemplatePreviewInput, ) { @@ -360,23 +288,12 @@ export function previewMessageTemplate( ); } -/** - * Lists message-push bindings belonging to exactly one QQBot account. - * @param selfId - QQBot self ID kept as a string and encoded in the URL. - * @returns Account-scoped binding views with their configured targets. - */ export function getAccountMessagePushBindings(selfId: string) { return requestClient.get< QqbotMessagePushApi.QqbotMessagePublishBindingView[] >(`/qqbot/accounts/${encodeURIComponent(selfId)}/message-push/bindings`); } -/** - * Creates one account-scoped binding from a global subscription and template. - * @param selfId - QQBot self ID kept as a string and encoded in the URL. - * @param data - Subscription, template, target, and enabled-state input. - * @returns The persisted account binding view. - */ export function createAccountMessagePushBinding( selfId: string, data: QqbotMessagePushApi.QqbotMessagePublishBindingInput, @@ -387,13 +304,6 @@ export function createAccountMessagePushBinding( ); } -/** - * Replaces one binding for exactly one QQBot account. - * @param selfId - QQBot self ID kept as a string and encoded in the URL. - * @param id - Stable binding ID, encoded before becoming a URL segment. - * @param data - Subscription, template, target, and enabled-state input. - * @returns The updated account binding view. - */ export function updateAccountMessagePushBinding( selfId: string, id: string, @@ -405,13 +315,6 @@ export function updateAccountMessagePushBinding( ); } -/** - * Changes whether one account binding creates future delivery work. - * @param selfId - QQBot self ID kept as a string and encoded in the URL. - * @param id - Stable binding ID, encoded before becoming a URL segment. - * @param enabled - Requested future enabled state. - * @returns The updated account binding view. - */ export function setAccountMessagePushBindingEnabled( selfId: string, id: string, @@ -423,23 +326,12 @@ export function setAccountMessagePushBindingEnabled( ); } -/** - * Soft-deletes one binding from exactly one QQBot account. - * @param selfId - QQBot self ID kept as a string and encoded in the URL. - * @param id - Stable binding ID, encoded before becoming a URL segment. - * @returns Whether the account binding was deleted. - */ export function deleteAccountMessagePushBinding(selfId: string, id: string) { return requestClient.delete( `/qqbot/accounts/${encodeURIComponent(selfId)}/message-push/bindings/${encodeURIComponent(id)}`, ); } -/** - * Lists group and private-message target choices for exactly one QQBot account. - * @param selfId - QQBot self ID kept as a string and encoded in the URL. - * @returns Availability state plus currently discoverable string-ID targets. - */ export function getAccountMessagePushTargets(selfId: string) { return requestClient.get( `/qqbot/accounts/${encodeURIComponent(selfId)}/message-push/targets`, diff --git a/apps/web-antdv-next/src/api/qqbot/napcat.ts b/apps/web-antdv-next/src/api/qqbot/napcat.ts index fdcbb3a..c6ab663 100644 --- a/apps/web-antdv-next/src/api/qqbot/napcat.ts +++ b/apps/web-antdv-next/src/api/qqbot/napcat.ts @@ -246,9 +246,6 @@ export function getQqbotNapcatRuntimeDetail(accountId: string) { ); } -/** - * Creates a short-lived gateway session for opening one account's NapCat WebUI. - */ export function createQqbotNapcatWebuiSession( data: QqbotNapcatApi.WebuiGatewaySessionCreateBody, ) { @@ -258,18 +255,12 @@ export function createQqbotNapcatWebuiSession( ); } -/** - * Extends an active NapCat WebUI gateway session while the page is alive. - */ export function heartbeatQqbotNapcatWebuiSession(sessionId: string) { return requestClient.post( `/qqbot/napcat/webui/session/${sessionId}/heartbeat`, ); } -/** - * Revokes a NapCat WebUI gateway session when the page leaves the WebUI view. - */ export function revokeQqbotNapcatWebuiSession(sessionId: string) { return requestClient.post( `/qqbot/napcat/webui/session/${sessionId}/revoke`, diff --git a/apps/web-antdv-next/src/api/request.ts b/apps/web-antdv-next/src/api/request.ts index 257dcdc..9586fcf 100644 --- a/apps/web-antdv-next/src/api/request.ts +++ b/apps/web-antdv-next/src/api/request.ts @@ -1,6 +1,3 @@ -/** - * 该文件可自行根据业务逻辑进行调整 - */ import type { AxiosResponseHeaders, RequestClientOptions } from '@vben/request'; import { useAppConfig } from '@vben/hooks'; diff --git a/apps/web-antdv-next/src/api/system/environment.ts b/apps/web-antdv-next/src/api/system/environment.ts index 08d153f..2c864be 100644 --- a/apps/web-antdv-next/src/api/system/environment.ts +++ b/apps/web-antdv-next/src/api/system/environment.ts @@ -142,34 +142,18 @@ export namespace EnvironmentDashboardApi { | 'snapshot-required'; } -/** - * Loads the aggregate Admin environment dashboard snapshot. - * - * @returns Dashboard response unwrapped by the shared Vben request client. - */ export function getEnvironmentDashboard() { return requestClient.get( '/system/environment/dashboard', ); } -/** - * Runs the API read-only self-check endpoint without exposing write actions. - * - * @returns Fresh dashboard response after backend read-only probes complete. - */ export function runEnvironmentSelfCheck() { return requestClient.post( '/system/environment/self-check', ); } -/** - * Builds the EventSource URL for API-emitted dashboard updates. - * - * @param lastEventId Optional SSE replay cursor held only in the current page instance. - * @returns Absolute API URL when the request client exposes a base URL; otherwise a relative path. - */ export function getEnvironmentDashboardEventsUrl(lastEventId?: string) { const query = lastEventId ? `?lastEventId=${encodeURIComponent(lastEventId)}` @@ -177,12 +161,6 @@ export function getEnvironmentDashboardEventsUrl(lastEventId?: string) { return buildApiUrl(`/system/environment/events/stream${query}`); } -/** - * Mirrors the existing API URL joining convention used by local SSE helpers. - * - * @param path API path produced by the environment dashboard wrapper. - * @returns Browser-ready URL that respects proxy or absolute API base configuration. - */ function buildApiUrl(path: string) { const getBaseUrl = (requestClient as unknown as { getBaseUrl?: () => string }) .getBaseUrl; diff --git a/apps/web-antdv-next/src/api/system/menu.ts b/apps/web-antdv-next/src/api/system/menu.ts index 6d6fa82..5e6a4bb 100644 --- a/apps/web-antdv-next/src/api/system/menu.ts +++ b/apps/web-antdv-next/src/api/system/menu.ts @@ -5,7 +5,6 @@ import { requestClient } from '#/api/request'; import { isSupportedAdminMenuName } from '../core/menu'; export namespace SystemMenuApi { - /** 徽标颜色集合 */ export const BadgeVariants = [ 'default', 'destructive', @@ -13,9 +12,7 @@ export namespace SystemMenuApi { 'success', 'warning', ] as const; - /** 徽标类型集合 */ export const BadgeTypes = ['dot', 'normal'] as const; - /** 菜单类型集合 */ export const MenuTypes = [ 'catalog', 'menu', @@ -23,73 +20,40 @@ export namespace SystemMenuApi { 'link', 'button', ] as const; - /** 系统菜单 */ export interface SystemMenu { [key: string]: any; - /** 后端权限标识 */ authCode: string; - /** 子级 */ children?: SystemMenu[]; - /** 组件 */ component?: string; - /** 菜单ID */ id: string; - /** 菜单元数据 */ meta?: { - /** 激活时显示的图标 */ activeIcon?: string; - /** 作为路由时,需要激活的菜单的Path */ activePath?: string; - /** 固定在标签栏 */ affixTab?: boolean; - /** 在标签栏固定的顺序 */ affixTabOrder?: number; - /** 徽标内容(当徽标类型为normal时有效) */ badge?: string; - /** 徽标类型 */ badgeType?: (typeof BadgeTypes)[number]; - /** 徽标颜色 */ badgeVariants?: (typeof BadgeVariants)[number]; - /** 在菜单中隐藏下级 */ hideChildrenInMenu?: boolean; - /** 在面包屑中隐藏 */ hideInBreadcrumb?: boolean; - /** 在菜单中隐藏 */ hideInMenu?: boolean; - /** 在标签栏中隐藏 */ hideInTab?: boolean; - /** 菜单图标 */ icon?: string; - /** 内嵌Iframe的URL */ iframeSrc?: string; - /** 是否缓存页面 */ keepAlive?: boolean; - /** 外链页面的URL */ link?: string; - /** 同一个路由最大打开的标签数 */ maxNumOfOpenTab?: number; - /** 无需基础布局 */ noBasicLayout?: boolean; - /** 是否在新窗口打开 */ openInNewWindow?: boolean; - /** 菜单排序 */ order?: number; - /** 额外的路由参数 */ query?: Recordable; - /** 菜单标题 */ title?: string; }; - /** 菜单名称 */ name: string; - /** 路由路径 */ path: string; - /** 父级ID */ pid: string; - /** 重定向 */ redirect?: string; - /** 排序值 */ sort?: number; - /** 菜单类型 */ type: (typeof MenuTypes)[number]; } } diff --git a/apps/web-antdv-next/src/api/system/network.ts b/apps/web-antdv-next/src/api/system/network.ts index 5f4b567..fad85fa 100644 --- a/apps/web-antdv-next/src/api/system/network.ts +++ b/apps/web-antdv-next/src/api/system/network.ts @@ -193,22 +193,12 @@ export namespace SystemNetworkApi { } } -/** - * Loads the persisted automatic-DDNS record page for either address family. - * @param params - Pagination and independent record/status filters. - * @returns DDNS rows with API-provided FQDN and source state. - */ export function getNetworkDdnsList(params: SystemNetworkApi.DdnsRecordQuery) { return requestClient.get< SystemNetworkApi.PageResult >('/system/network/ddns/list', { params }); } -/** - * Loads eligible and disabled source choices for one DNS address family. - * @param recordType - A selects port-forward IPv4 sources; AAAA selects Agent IPv6. - * @returns Server-controlled source options and their current address state. - */ export function getNetworkDdnsSourceOptions( recordType: SystemNetworkApi.DdnsRecordType, ) { @@ -218,21 +208,12 @@ export function getNetworkDdnsSourceOptions( ); } -/** - * Loads the redacted DNSPod runtime readiness state. - * @returns Provider name plus enabled/configured flags, never credentials. - */ export function getNetworkDdnsProviderStatus() { return requestClient.get( '/system/network/ddns/provider-status', ); } -/** - * Creates one generic A or AAAA automatic-DDNS binding. - * @param data - User-editable record and server-recognized source selector. - * @returns Persisted DDNS record with asynchronous synchronization state. - */ export function createNetworkDdnsRecord( data: SystemNetworkApi.DdnsRecordInput, ) { @@ -242,12 +223,6 @@ export function createNetworkDdnsRecord( ); } -/** - * Updates one persisted automatic-DDNS binding. - * @param id - Stable string record ID. - * @param data - Complete editable DDNS input. - * @returns Updated record with pending synchronization state. - */ export function updateNetworkDdnsRecord( id: string, data: SystemNetworkApi.DdnsRecordInput, @@ -258,33 +233,18 @@ export function updateNetworkDdnsRecord( ); } -/** - * Deletes only the local automatic-update binding, leaving DNSPod unchanged. - * @param id - Stable string record ID. - * @returns Deleted local record state. - */ export function deleteNetworkDdnsRecord(id: string) { return requestClient.delete( `/system/network/ddns/${id}`, ); } -/** - * Requests one immediate provider reconciliation for an eligible source. - * @param id - Stable string record ID. - * @returns Latest DDNS synchronization state. - */ export function retryNetworkDdnsRecord(id: string) { return requestClient.post( `/system/network/ddns/${id}/retry`, ); } -/** - * Loads the persisted port-forward resource page from the API fact source. - * @param params - Pagination and independent protocol/synchronization filters. - * @returns Port-forward rows and the total record count. - */ export function getNetworkPortForwardList( params: SystemNetworkApi.PortForwardQuery, ) { @@ -293,11 +253,6 @@ export function getNetworkPortForwardList( >('/system/network/port-forward/list', { params }); } -/** - * Creates a desired router mapping without exposing router credentials. - * @param data - User-editable mapping fields. - * @returns The persisted pending desired record. - */ export function createNetworkPortForward( data: SystemNetworkApi.PortForwardInput, ) { @@ -307,12 +262,6 @@ export function createNetworkPortForward( ); } -/** - * Updates the editable desired fields of one active mapping. - * @param id - Stable port-forward record ID. - * @param data - Complete editable mapping fields. - * @returns The updated pending desired record. - */ export function updateNetworkPortForward( id: string, data: SystemNetworkApi.PortForwardInput, @@ -323,69 +272,36 @@ export function updateNetworkPortForward( ); } -/** - * Requests confirmed asynchronous deletion of one managed mapping. - * @param id - Stable port-forward record ID. - * @returns The deleting tombstone retained until Agent acknowledgement. - */ export function deleteNetworkPortForward(id: string) { return requestClient.delete( `/system/network/port-forward/${id}`, ); } -/** - * Raises a new reconciliation revision for a failed or conflicted mapping. - * @param id - Stable port-forward record ID. - * @returns The latest pending desired record. - */ export function retryNetworkPortForward(id: string) { return requestClient.post( `/system/network/port-forward/${id}/retry`, ); } -/** - * Enables persistent UDP STUN observation and triggers an immediate probe. - * @param id - Eligible UDP same-port mapping ID. - * @returns The latest pending desired record. - */ export function enableNetworkPortForwardKeeper(id: string) { return requestClient.post( `/system/network/port-forward/${id}/keeper/enable`, ); } -/** - * Stops future STUN renewals without deleting the router mapping. - * @param id - UDP mapping ID whose Keeper is currently desired. - * @returns The latest pending desired record. - */ export function disableNetworkPortForwardKeeper(id: string) { return requestClient.post( `/system/network/port-forward/${id}/keeper/disable`, ); } -/** - * Generates an idempotent request ID for one immediate UDP STUN cycle. - * @param id - Enabled UDP same-port mapping ID. - * @returns The latest desired record carrying the new request ID. - */ export function probeNetworkPortForward(id: string) { return requestClient.post( `/system/network/port-forward/${id}/probe`, ); } -/** - * Loads append-only endpoint transition history for one mapping. - * @param id - Stable port-forward record ID. - * @param params - History pagination values. - * @param params.pageNo - One-based history page number. - * @param params.pageSize - Maximum rows requested for the page. - * @returns Endpoint transition records and their total count. - */ export function getNetworkPortForwardEndpointHistory( id: string, params: { pageNo?: number; pageSize?: number }, @@ -395,21 +311,12 @@ export function getNetworkPortForwardEndpointHistory( >(`/system/network/port-forward/${id}/endpoint-history`, { params }); } -/** - * Loads independent Agent connectivity and revision convergence state. - * @returns Current Agent status without inferring per-record failures. - */ export function getNetworkAgentStatus() { return requestClient.get( '/system/network/agent/status', ); } -/** - * Builds the credentialed EventSource URL for committed network-state changes. - * @param lastEventId - Optional replay cursor retained by the current route instance. - * @returns Browser-ready SSE URL using the configured API base path. - */ export function getNetworkManagementEventsUrl(lastEventId?: string) { const query = lastEventId ? `?lastEventId=${encodeURIComponent(lastEventId)}` @@ -417,11 +324,6 @@ export function getNetworkManagementEventsUrl(lastEventId?: string) { return buildApiUrl(`/system/network/events/stream${query}`); } -/** - * Joins one network API path with the request client's configured base URL. - * @param path - Relative API route for the EventSource connection. - * @returns Absolute or proxy-relative URL matching normal Admin requests. - */ function buildApiUrl(path: string) { const getBaseUrl = (requestClient as unknown as { getBaseUrl?: () => string }) .getBaseUrl; diff --git a/apps/web-antdv-next/src/components/ktTable/KtTable.tsx b/apps/web-antdv-next/src/components/ktTable/KtTable.tsx index bbb4d13..f129177 100644 --- a/apps/web-antdv-next/src/components/ktTable/KtTable.tsx +++ b/apps/web-antdv-next/src/components/ktTable/KtTable.tsx @@ -81,15 +81,6 @@ export default defineComponent({ name: 'KtTable', props: ktTableProps, emits: ['register'], - /** - * 初始化 KtTable 主组件,组装表单、按钮、列、分页、选择和注册式 API。 - * - * @param rawProps 组件显式传入的 props,后续会和 register 配置合并。 - * @param emit Vue setup context。 - * @param emit.emit Vue 事件发送器,用于向业务侧暴露 register API。 - * @param emit.expose Vue 暴露实例方法的函数,用于模板 ref 直接访问表格 API。 - * @param emit.slots 业务侧传入的 title、toolbar、bodyCell、summary、footer 等插槽。 - */ setup(rawProps, { emit, expose, slots }) { const { props, setProps } = useKtTableResolvedProps( rawProps as KtTableProps, @@ -662,9 +653,6 @@ export default defineComponent({ loadData(); } - /** - * 渲染搜索表单区域和表单按钮。 - */ const renderSearchArea = () => { const hasSearch = (formOptions.value.schema?.length || 0) > 0; const hasFormButtons = formButtons.value.length > 0; @@ -714,11 +702,6 @@ export default defineComponent({ ); }; - /** - * 渲染操作列里的行操作按钮。 - * - * @param record 当前行数据。 - */ const renderActionCell = (record: KtTableRecord) => { const { inlineActions, overflowActions } = splitRowActions( getVisibleRowActions(record), @@ -797,9 +780,6 @@ export default defineComponent({ return Math.max(0, Math.floor(visibleCount)); } - /** - * 渲染表格头部左侧业务按钮和 toolbar 插槽。 - */ const renderHeaderButtons = () => { const toolbar = slots.toolbar?.(context); const buttons = headerButtons.value.map((button) => renderButton(button)); @@ -820,9 +800,6 @@ export default defineComponent({ ); }; - /** - * 渲染表格头部右侧设置按钮组。 - */ const renderHeaderSettings = () => { if (!props.showTableSetting) return null; diff --git a/apps/web-antdv-next/src/components/ktTable/components/KtTableFooter.tsx b/apps/web-antdv-next/src/components/ktTable/components/KtTableFooter.tsx index 846119a..f146bb3 100644 --- a/apps/web-antdv-next/src/components/ktTable/components/KtTableFooter.tsx +++ b/apps/web-antdv-next/src/components/ktTable/components/KtTableFooter.tsx @@ -39,14 +39,6 @@ export default defineComponent({ }, }, emits: ['pageChange'], - /** - * 初始化表格底部选择状态和分页区域。 - * - * @param props 底部分页、选择数量和显示开关配置。 - * @param emit Vue setup context。 - * @param emit.emit 分页变化事件发送器。 - * @param emit.slots 底部左侧自定义内容插槽。 - */ setup(props, { emit, slots }) { /** * 将 Antdv Pagination 的页码变化转成 KtTable 分页事件。 diff --git a/apps/web-antdv-next/src/components/ktTable/components/KtTableHeader.tsx b/apps/web-antdv-next/src/components/ktTable/components/KtTableHeader.tsx index ea714dd..44e9fb4 100644 --- a/apps/web-antdv-next/src/components/ktTable/components/KtTableHeader.tsx +++ b/apps/web-antdv-next/src/components/ktTable/components/KtTableHeader.tsx @@ -35,13 +35,6 @@ export default defineComponent({ type: String, }, }, - /** - * 初始化表格头部区域。 - * - * @param props 表格头部 props,目前用于接收默认标题。 - * @param slots Vue setup context。 - * @param slots.slots 头部标题、控制区、按钮和设置区插槽。 - */ setup(props, { slots }) { return () => { const slotTitle = resolveSlotContent(slots.title?.()); diff --git a/apps/web-antdv-next/src/components/ktTable/components/KtTableResizableTitle.tsx b/apps/web-antdv-next/src/components/ktTable/components/KtTableResizableTitle.tsx index a1e2276..a53c23b 100644 --- a/apps/web-antdv-next/src/components/ktTable/components/KtTableResizableTitle.tsx +++ b/apps/web-antdv-next/src/components/ktTable/components/KtTableResizableTitle.tsx @@ -30,14 +30,6 @@ export default defineComponent({ type: Number, }, }, - /** - * 初始化可拖拽列宽表头单元格。 - * - * @param props 表头单元格宽度和列宽变化回调。 - * @param attrs Vue setup context。 - * @param attrs.attrs Antdv Table 透传给 th 的原生属性。 - * @param attrs.slots 表头默认内容插槽。 - */ setup(props, { attrs, slots }) { const dragging = ref(false); const stopNextClick = ref(false); diff --git a/apps/web-antdv-next/src/components/ktTable/components/KtTableSearch.tsx b/apps/web-antdv-next/src/components/ktTable/components/KtTableSearch.tsx index a18aa58..ecb3b76 100644 --- a/apps/web-antdv-next/src/components/ktTable/components/KtTableSearch.tsx +++ b/apps/web-antdv-next/src/components/ktTable/components/KtTableSearch.tsx @@ -33,14 +33,6 @@ export default defineComponent({ }, }, emits: ['transitionEnd', 'transitionStart'], - /** - * 初始化搜索区域的展开/收起动画状态。 - * - * @param props 搜索区显示状态和收起状态。 - * @param emit Vue setup context。 - * @param emit.emit 搜索动画开始和结束事件发送器。 - * @param emit.slots 搜索表单和操作按钮插槽。 - */ setup(props, { emit, slots }) { const shellRef = ref(null); const contentRef = ref(null); diff --git a/apps/web-antdv-next/src/components/ktTable/components/KtTableSettings.tsx b/apps/web-antdv-next/src/components/ktTable/components/KtTableSettings.tsx index a60ef0f..1b771b5 100644 --- a/apps/web-antdv-next/src/components/ktTable/components/KtTableSettings.tsx +++ b/apps/web-antdv-next/src/components/ktTable/components/KtTableSettings.tsx @@ -76,13 +76,6 @@ export default defineComponent({ 'sizeChange', 'visibleColumnKeysChange', ], - /** - * 初始化 KtTable 设置栏内部状态和事件。 - * - * @param props 组件入参,包含列配置、列顺序、可见列、密度、搜索显示和全屏状态。 - * @param emit Vue setup context。 - * @param emit.emit 组件事件发送器,用于把刷新、列设置、密度切换等操作同步给父级表格。 - */ setup(props, { emit }) { const draggingColumnKey = ref(''); const dragOverColumnKey = ref(''); @@ -241,14 +234,6 @@ export default defineComponent({ emit('sizeChange', next); } - /** - * 渲染设置栏中的图标按钮。 - * - * @param key 按钮渲染 key,用于让 Vue 稳定追踪按钮节点。 - * @param title 按钮提示文案,同时作为无障碍名称。 - * @param icon 按钮图标节点。 - * @param onClick 点击按钮时执行的回调函数。 - */ const renderIconButton = ( key: string, title: string, @@ -271,9 +256,6 @@ export default defineComponent({ ); }; - /** - * 渲染列设置弹层和列设置触发按钮。 - */ const renderColumnSetting = () => { if (!props.setting.column) return null; diff --git a/apps/web-antdv-next/src/components/ktTable/components/KtTableSummary.tsx b/apps/web-antdv-next/src/components/ktTable/components/KtTableSummary.tsx index 430efc1..dbbbba3 100644 --- a/apps/web-antdv-next/src/components/ktTable/components/KtTableSummary.tsx +++ b/apps/web-antdv-next/src/components/ktTable/components/KtTableSummary.tsx @@ -24,12 +24,6 @@ type RenderKtTableSummaryOptions = { statistics: KtTableStatistic[]; }; -/** - * 渲染单个统计项内容。 - * - * @param item 当前统计项配置。 - * @param context KtTable 运行时上下文,用于统计项读取行数据、搜索值和选择状态。 - */ const renderStatisticValue = ( item: KtTableStatistic, context: KtTableContext, @@ -48,13 +42,6 @@ const renderStatisticValue = ( ); }; -/** - * 渲染 summary 单元格内容。 - * - * @param context KtTable 运行时上下文。 - * @param statistic 当前列匹配到的统计项配置。 - * @param showDefaultLabel 当前单元格是否需要显示默认“本页统计”文案。 - */ const renderCellContent = ( context: KtTableContext, statistic: KtTableStatistic | undefined, @@ -68,16 +55,6 @@ const renderCellContent = ( return null; }; -/** - * 渲染 KtTable 底部固定 summary 行。 - * - * @param options summary 渲染参数。 - * @param options.columns 当前最终展示的表格列。 - * @param options.context KtTable 运行时上下文。 - * @param options.customSummary 业务侧传入的自定义 summary 插槽。 - * @param options.showSelection 当前表格是否启用选择列。 - * @param options.statistics 当前表格和模块提供的统计项列表。 - */ export const renderKtTableSummary = (options: RenderKtTableSummaryOptions) => { const { columns, context, customSummary, showSelection, statistics } = options; diff --git a/apps/web-antdv-next/src/components/ktTable/hooks/useKtTable.ts b/apps/web-antdv-next/src/components/ktTable/hooks/useKtTable.ts index 202bc11..339f191 100644 --- a/apps/web-antdv-next/src/components/ktTable/hooks/useKtTable.ts +++ b/apps/web-antdv-next/src/components/ktTable/hooks/useKtTable.ts @@ -36,11 +36,6 @@ export function useKtTable< return tableApi; } - /** - * 更新表格 props;未注册时先缓存,注册后再一次性同步。 - * - * @param nextProps 需要合并到表格上的 props 补丁,或基于当前 props 返回补丁的函数。 - */ const setProps: KtTableSetProps = (nextProps) => { if (tableApi) { tableApi.setProps(nextProps); @@ -57,11 +52,6 @@ export function useKtTable< }; }; - /** - * 接收 KtTable 组件实例暴露的 API,并同步注册前缓存的 props。 - * - * @param api KtTable 组件注册时暴露的命令式 API。 - */ const register: KtTableRegisterFn = (api) => { tableApi = api; api.setProps(pendingProps); diff --git a/apps/web-antdv-next/src/components/ktTable/hooks/useKtTableActions.spec.tsx b/apps/web-antdv-next/src/components/ktTable/hooks/useKtTableActions.spec.tsx index 12150da..94c0723 100644 --- a/apps/web-antdv-next/src/components/ktTable/hooks/useKtTableActions.spec.tsx +++ b/apps/web-antdv-next/src/components/ktTable/hooks/useKtTableActions.spec.tsx @@ -36,7 +36,6 @@ vi.mock('antdv-next', () => ({ }), })); -/** Creates the smallest action runtime needed to exercise row rendering. */ function createActionRuntime() { const context = { formApi: {}, diff --git a/apps/web-antdv-next/src/components/ktTable/hooks/useKtTableActions.tsx b/apps/web-antdv-next/src/components/ktTable/hooks/useKtTableActions.tsx index a398d96..4947265 100644 --- a/apps/web-antdv-next/src/components/ktTable/hooks/useKtTableActions.tsx +++ b/apps/web-antdv-next/src/components/ktTable/hooks/useKtTableActions.tsx @@ -77,9 +77,6 @@ export function useKtTableActions(options: UseKtTableActionsOptions) { customButtons.value.filter((button) => button.placement !== 'form'), ); - /** - * 生成 KtTable 默认查询和重置按钮。 - */ const getDefaultButtons = (): KtTableButton[] => { if (!props.showDefaultButtons) return []; @@ -102,12 +99,6 @@ export function useKtTableActions(options: UseKtTableActionsOptions) { ]; }; - /** - * 渲染按钮图标,兼容静态图标和函数式图标。 - * - * @param icon 按钮配置中的图标节点或图标渲染函数。 - * @param targetContext 图标渲染时使用的表格上下文。 - */ const renderIcon = ( icon: KtTableButton['icon'], targetContext: KtTableContext = context, @@ -205,11 +196,6 @@ export function useKtTableActions(options: UseKtTableActionsOptions) { }); } - /** - * 渲染头部或搜索区按钮。 - * - * @param button 当前按钮配置。 - */ const renderButton = (button: KtTableButton) => { return ( { const disabled = typeof action.disabled === 'function' @@ -262,14 +242,6 @@ export function useKtTableActions(options: UseKtTableActionsOptions) { ); }; - /** - * Resolves a readable disabled reason only while a row action is disabled. - * - * @param action Current row action configuration. - * @param row Current table row. - * @param disabled Resolved disabled state for this row. - * @returns Tooltip text, or undefined when no explanation should render. - */ function resolveDisabledReason( action: KtTableRowAction, row: KtTableRecord, diff --git a/apps/web-antdv-next/src/components/ktTable/hooks/useKtTableColumns.ts b/apps/web-antdv-next/src/components/ktTable/hooks/useKtTableColumns.ts index 0c572db..0d6aa0c 100644 --- a/apps/web-antdv-next/src/components/ktTable/hooks/useKtTableColumns.ts +++ b/apps/web-antdv-next/src/components/ktTable/hooks/useKtTableColumns.ts @@ -397,11 +397,6 @@ export function useKtTableColumns(options: UseKtTableColumnsOptions) { return { ...column, ellipsis: column.ellipsis ?? true, - /** - * 合并业务侧 header cell 配置和 KtTable 列宽拖拽配置。 - * - * @param targetColumn Antdv 传入的当前表头列配置。 - */ onHeaderCell: (targetColumn: TableColumnType) => { const originalProps = (originalHeaderCell?.(targetColumn) || {}) as Record; @@ -421,12 +416,6 @@ export function useKtTableColumns(options: UseKtTableColumnsOptions) { width: nextWidth, }; }, - /** - * 合并业务侧 body cell 配置和 KtTable 列最小宽度配置。 - * - * @param record 当前行数据。 - * @param index 当前行在本页的下标。 - */ onCell: (record: KtTableRecord, index?: number) => { const originalProps = (originalCell?.(record, index) || {}) as Record< string, diff --git a/apps/web-antdv-next/src/components/ktTable/hooks/useKtTableResolvedProps.ts b/apps/web-antdv-next/src/components/ktTable/hooks/useKtTableResolvedProps.ts index dd7b013..862d4b9 100644 --- a/apps/web-antdv-next/src/components/ktTable/hooks/useKtTableResolvedProps.ts +++ b/apps/web-antdv-next/src/components/ktTable/hooks/useKtTableResolvedProps.ts @@ -78,11 +78,6 @@ export function useKtTableResolvedProps(rawProps: KtTableProps) { ); } - /** - * 写入 register 模式下的动态 props,并同步最终 props。 - * - * @param nextProps 需要合并的 props 补丁,或基于当前 props 返回补丁的函数。 - */ const setProps: KtTableSetProps = (nextProps) => { const patch = typeof nextProps === 'function' ? nextProps({ ...props }) : nextProps; diff --git a/apps/web-antdv-next/src/components/richText/KtTiptapHtmlEditor.spec.tsx b/apps/web-antdv-next/src/components/richText/KtTiptapHtmlEditor.spec.tsx index fd8a89c..931c0fa 100644 --- a/apps/web-antdv-next/src/components/richText/KtTiptapHtmlEditor.spec.tsx +++ b/apps/web-antdv-next/src/components/richText/KtTiptapHtmlEditor.spec.tsx @@ -23,9 +23,6 @@ type TiptapExpose = ComponentPublicInstance & { setHtml: (value: string) => void; }; -/** - * 模拟 Tiptap Editor 的最小行为,支持组件测试 HTML 同步和禁用态。 - */ class FakeEditor { public html = ''; @@ -46,11 +43,6 @@ class FakeEditor { public options: FakeEditorOptions; - /** - * 记录传入配置并初始化测试用 HTML。 - * - * @param options 编辑器初始化配置,测试只关心内容、可编辑态和更新回调。 - */ constructor(options: FakeEditorOptions) { this.options = options; this.html = options.content || ''; @@ -126,11 +118,6 @@ vi.mock('@tiptap/vue-3', () => ({ type: Object, }, }, - /** - * 渲染当前 FakeEditor HTML,使测试能观察组件传入内容。 - * - * @param props EditorContent 入参,包含当前编辑器实例。 - */ setup(props) { return () => h('div', { @@ -157,15 +144,6 @@ vi.mock('antdv-next', () => ({ }, }, emits: ['click'], - /** - * 用原生 button 替代 antdv-next Button,保留 attrs/disabled/click。 - * - * @param props 按钮入参,测试只读取 disabled。 - * @param context Vue setup context,透传 attrs 和 slots。 - * @param context.attrs 透传到原生 button 的属性。 - * @param context.emit click 事件发送器。 - * @param context.slots 按钮默认插槽。 - */ setup(props, { attrs, emit, slots }) { return () => h( @@ -182,9 +160,6 @@ vi.mock('antdv-next', () => ({ }), Divider: defineComponent({ name: 'MockDivider', - /** - * 渲染工具栏分隔符占位。 - */ setup() { return () => h('span', { class: 'mock-divider' }); }, @@ -198,13 +173,6 @@ vi.mock('antdv-next', () => ({ }, }, emits: ['update:value'], - /** - * 用 input 替代 antdv-next Input,保留 value 双向更新。 - * - * @param props 输入框入参,测试只使用 value。 - * @param context Vue setup context,发送 update:value。 - * @param context.emit update:value 事件发送器。 - */ setup(props, { emit }) { return () => h('input', { @@ -224,13 +192,6 @@ vi.mock('antdv-next', () => ({ }, }, emits: ['cancel', 'ok', 'update:open'], - /** - * 模拟 Modal,只在 open=true 时渲染内容。 - * - * @param props 弹窗入参,测试仅关心 open。 - * @param context Vue setup context。 - * @param context.slots 弹窗默认插槽。 - */ setup(props, { slots }) { return () => props.open ? h('div', { role: 'dialog' }, slots.default?.()) : null; @@ -238,13 +199,6 @@ vi.mock('antdv-next', () => ({ }), Space: defineComponent({ name: 'MockSpace', - /** - * 以 div 包装 Space 内容。 - * - * @param _props 未使用的 Space props。 - * @param context Vue setup context,读取默认 slot。 - * @param context.slots Space 默认插槽。 - */ setup(_props, { slots }) { return () => h('div', slots.default?.()); }, @@ -257,13 +211,6 @@ vi.mock('antdv-next', () => ({ type: String, }, }, - /** - * 直接渲染 Tooltip 默认 slot,避免测试依赖浮层实现。 - * - * @param _props 未使用的 Tooltip props。 - * @param context Vue setup context,读取默认 slot。 - * @param context.slots Tooltip 默认插槽。 - */ setup(_props, { slots }) { return () => h('span', slots.default?.()); }, @@ -279,11 +226,6 @@ vi.mock('@vben/icons', () => ({ type: String, }, }, - /** - * 渲染可识别的图标占位。 - * - * @param props 图标入参,测试不读取但保留 data 属性。 - */ setup(props) { return () => h('i', { 'data-icon': props.icon }); }, @@ -350,9 +292,6 @@ describe('ktTiptapHtmlEditor', () => { it('syncs setHtml changes through a v-model parent', async () => { const Parent = defineComponent({ name: 'TiptapParentHarness', - /** - * 建立父子 v-model 绑定,验证编辑器 emit 会回写父级状态。 - */ setup() { const html = ref('

旧正文

'); const editorRef = ref(null); diff --git a/apps/web-antdv-next/src/components/richText/KtTiptapHtmlEditor.tsx b/apps/web-antdv-next/src/components/richText/KtTiptapHtmlEditor.tsx index e5991d9..e55f9d4 100644 --- a/apps/web-antdv-next/src/components/richText/KtTiptapHtmlEditor.tsx +++ b/apps/web-antdv-next/src/components/richText/KtTiptapHtmlEditor.tsx @@ -98,12 +98,6 @@ function readEditorHtml(editor: Editor | null | undefined, fallback: string) { return editor?.getHTML() || fallback; } -/** - * 渲染工具栏图标,统一使用 Iconify 图标来源。 - * - * @param icon 图标名称,遵循 Vben/Iconify 的 lucide 命名。 - * @returns 图标节点。 - */ const renderIcon = (icon: string) => ( ); @@ -138,14 +132,6 @@ export default defineComponent({ focus: () => true, 'update:modelValue': (_value: string) => true, }, - /** - * 初始化 Tiptap HTML 编辑器,桥接 toolbar 命令、v-model 和 expose API。 - * - * @param props 组件入参,包含 HTML、禁用态、占位符和最小高度。 - * @param context Vue setup context,用于发送编辑器事件并暴露实例方法。 - * @param context.emit 组件事件发送器,用于同步 HTML、change、focus 和 blur。 - * @param context.expose 组件方法暴露器,用于公开编辑器实例与 HTML 读写方法。 - */ setup(props, { emit, expose }) { const currentHtml = ref(props.modelValue || ''); const linkModalOpen = ref(false); @@ -417,12 +403,6 @@ export default defineComponent({ }, ]; - /** - * 渲染一个工具栏命令按钮。 - * - * @param command 当前命令配置。 - * @returns 工具栏按钮节点。 - */ const renderCommandButton = (command: ToolbarCommand): VNodeChild => { const currentEditor = editor.value; const active = currentEditor ? command.isActive?.(currentEditor) : false; @@ -447,9 +427,6 @@ export default defineComponent({ ); }; - /** - * 渲染格式工具栏,按文本、段落、插入、历史分组。 - */ const renderToolbar = () => { const groups = [ toolbarCommands.slice(0, 4), @@ -473,9 +450,6 @@ export default defineComponent({ ); }; - /** - * 渲染链接与图片输入弹窗。 - */ const renderModals = () => ( <> import('#/layouts/basic.vue'); const AuthPageLayout = () => import('#/layouts/auth.vue'); -/** 全局404页面 */ const fallbackNotFoundRoute: RouteRecordRaw = { component: () => import('#/views/_core/fallback/not-found.vue'), meta: { @@ -20,13 +19,7 @@ const fallbackNotFoundRoute: RouteRecordRaw = { path: '/:path(.*)*', }; -/** 基本路由,这些路由是必须存在的 */ const coreRoutes: RouteRecordRaw[] = [ - /** - * 根路由 - * 使用基础布局,作为所有页面的父级容器,子级就不必配置BasicLayout。 - * 此路由必须存在,且不应修改 - */ { component: BasicLayout, meta: { diff --git a/apps/web-antdv-next/src/router/routes/index.ts b/apps/web-antdv-next/src/router/routes/index.ts index eea4d20..15f6e5f 100644 --- a/apps/web-antdv-next/src/router/routes/index.ts +++ b/apps/web-antdv-next/src/router/routes/index.ts @@ -12,27 +12,21 @@ const dynamicRouteFiles = import.meta.glob('./modules/**/*.ts', { // const externalRouteFiles = import.meta.glob('./external/**/*.ts', { eager: true }); // const staticRouteFiles = import.meta.glob('./static/**/*.ts', { eager: true }); -/** 动态路由 */ const dynamicRoutes: RouteRecordRaw[] = mergeRouteModules(dynamicRouteFiles); -/** 外部路由列表,访问这些页面可以不需要Layout,可能用于内嵌在别的系统(不会显示在菜单中) */ // const externalRoutes: RouteRecordRaw[] = mergeRouteModules(externalRouteFiles); // const staticRoutes: RouteRecordRaw[] = mergeRouteModules(staticRouteFiles); const staticRoutes: RouteRecordRaw[] = []; const externalRoutes: RouteRecordRaw[] = []; -/** 路由列表,由基本路由、外部路由和404兜底路由组成 - * 无需走权限验证(会一直显示在菜单中) */ const routes: RouteRecordRaw[] = [ ...coreRoutes, ...externalRoutes, fallbackNotFoundRoute, ]; -/** 基本路由列表,这些路由不需要进入权限拦截 */ const coreRouteNames = traverseTreeValues(coreRoutes, (route) => route.name); -/** 有权限校验的路由列表,包含动态路由和静态路由 */ const accessRoutes = [...dynamicRoutes, ...staticRoutes]; const componentKeys: string[] = Object.keys({ diff --git a/apps/web-antdv-next/src/router/routes/modules/qqbot.spec.ts b/apps/web-antdv-next/src/router/routes/modules/qqbot.spec.ts index 4d7beb2..eddbb1f 100644 --- a/apps/web-antdv-next/src/router/routes/modules/qqbot.spec.ts +++ b/apps/web-antdv-next/src/router/routes/modules/qqbot.spec.ts @@ -27,11 +27,6 @@ const messagePushRoutes: ExpectedMessagePushRoute[] = [ }, ]; -/** - * Returns the text key of a non-computed object-literal property. - * @param property - Candidate route object property from the parsed source. - * @returns The literal property key, or `undefined` when it cannot be read statically. - */ function getPropertyName(property: ts.ObjectLiteralElementLike) { if (!ts.isPropertyAssignment(property) || property.name === undefined) { return undefined; @@ -42,12 +37,6 @@ function getPropertyName(property: ts.ObjectLiteralElementLike) { : undefined; } -/** - * Finds one directly declared property on a route object. - * @param object - Route object literal to inspect. - * @param name - Required literal property key. - * @returns The matching property assignment, if present. - */ function getProperty(object: ts.ObjectLiteralExpression, name: string) { return object.properties.find( (property): property is ts.PropertyAssignment => @@ -55,12 +44,6 @@ function getProperty(object: ts.ObjectLiteralExpression, name: string) { ); } -/** - * Reads a required string-literal property from a route object. - * @param object - Route object literal to inspect. - * @param name - Required literal property key. - * @returns The declared string value, or `undefined` when it is not a string literal. - */ function getStringProperty(object: ts.ObjectLiteralExpression, name: string) { const property = getProperty(object, name); @@ -69,11 +52,6 @@ function getStringProperty(object: ts.ObjectLiteralExpression, name: string) { : undefined; } -/** - * Reads the literal target from a route's lazy dynamic import without invoking it. - * @param object - Route object literal to inspect. - * @returns The module path passed to `import()`. - */ function getLazyComponentPath(object: ts.ObjectLiteralExpression) { const component = getProperty(object, 'component'); @@ -91,11 +69,6 @@ function getLazyComponentPath(object: ts.ObjectLiteralExpression) { return (importCall.arguments[0] as ts.StringLiteral).text; } -/** - * Locates the direct `QqBot.children` array in the route initializer. - * @param sourceFile - Parsed QQBot route module source. - * @returns The direct child route objects of the `QqBot` parent. - */ function getQqBotChildren(sourceFile: ts.SourceFile) { const routesDeclaration = sourceFile.statements.find( (statement): statement is ts.VariableStatement => { @@ -139,16 +112,10 @@ function getQqBotChildren(sourceFile: ts.SourceFile) { ); } -/** - * Collects every route object that declares one of the locked message-push names. - * @param sourceFile - Parsed QQBot route module source. - * @returns All matching objects, including accidental nested or duplicate routes. - */ function getAllMessagePushRoutes(sourceFile: ts.SourceFile) { const routeNames = new Set(messagePushRoutes.map((route) => route.name)); const matches: ts.ObjectLiteralExpression[] = []; - /** Visits route objects so nested copies cannot evade the direct-child assertion. */ function visit(node: ts.Node): void { if (ts.isObjectLiteralExpression(node)) { const routeName = getStringProperty(node, 'name'); diff --git a/apps/web-antdv-next/src/store/auth.ts b/apps/web-antdv-next/src/store/auth.ts index c6a6218..787f740 100644 --- a/apps/web-antdv-next/src/store/auth.ts +++ b/apps/web-antdv-next/src/store/auth.ts @@ -178,10 +178,6 @@ export const useAuthStore = defineStore('auth', () => { }; } - /** - * Restores the Admin client session from its origin-scoped HttpOnly refresh cookie. - * @returns Whether a fresh access token was restored; failures clear stale client identity state. - */ async function restoreSessionFromCookie() { if (accessStore.accessToken) return true; diff --git a/apps/web-antdv-next/src/views/blog/article/list.spec.ts b/apps/web-antdv-next/src/views/blog/article/list.spec.ts index 63b07ff..5ce2ca0 100644 --- a/apps/web-antdv-next/src/views/blog/article/list.spec.ts +++ b/apps/web-antdv-next/src/views/blog/article/list.spec.ts @@ -7,12 +7,6 @@ import { describe, expect, it } from 'vitest'; const source = readFileSync(new URL('list.tsx', import.meta.url), 'utf8'); describe('blog article list preview entry', () => { - /** - * Reads a source slice between two stable markers for modal ordering guards. - * @param start Marker before the function body under assertion. - * @param end Marker after the function body under assertion. - * @returns Source slice used by regression assertions. - */ function getSourceSlice(start: string, end: string) { const startIndex = source.indexOf(start); const endIndex = source.indexOf(end, startIndex + start.length); diff --git a/apps/web-antdv-next/src/views/blog/article/list.tsx b/apps/web-antdv-next/src/views/blog/article/list.tsx index 398521b..a967a37 100644 --- a/apps/web-antdv-next/src/views/blog/article/list.tsx +++ b/apps/web-antdv-next/src/views/blog/article/list.tsx @@ -393,39 +393,21 @@ export default defineComponent({ }); } - /** - * Applies editor schema and form values after the modal has opened so the modal-contained form can mount first. - * @param values Article values selected for the current modal session. - */ async function resetArticleModalForm(values: BlogArticleFormValues) { await setArticleEditorMode(values.editorMode || 'markdown'); await resetArticleForm(values); } - /** - * Resets modal form state before applying create or edit values. - * @param values Article values selected for the current modal session. - */ async function resetArticleForm(values: BlogArticleFormValues) { await articleFormApi.resetForm(); await articleFormApi.setValues(values); await articleFormApi.resetValidate(); } - /** - * Handles editor mode changes from the form control without clearing the current content draft. - * @param mode Editor mode selected by the user. - */ function handleArticleEditorModeChange(mode: BlogArticleEditorMode) { void setArticleEditorMode(mode, { preserveContent: true }); } - /** - * Switches the content field between Markdown, rich HTML, and raw WordPress HTML editing. - * @param mode Editor mode selected for the current modal session. - * @param options Whether the current content draft should be reapplied after schema replacement. - * @param options.preserveContent Reapplies the existing content value after the editor component changes. - */ async function setArticleEditorMode( mode: BlogArticleEditorMode, options: { preserveContent?: boolean } = {}, @@ -458,10 +440,6 @@ export default defineComponent({ await articleFormApi.setValues(nextValues); } - /** - * Opens the article modal in Markdown authoring mode with current table filters as defaults. - * @param context Optional table context supplied by a toolbar button. - */ async function openCreate( context?: KtTableContext, ) { @@ -474,10 +452,6 @@ export default defineComponent({ articleModalApi.setData({ values }).open(); } - /** - * Opens the article modal using raw HTML mode for imported WordPress/Argon content. - * @param row Article row selected from the table. - */ function openEdit(row: WordpressBlogApi.Article) { editingId.value = `${row.id}`; const values = getBlogArticleEditFormValues(row); @@ -496,9 +470,6 @@ export default defineComponent({ }); } - /** - * Validates and submits the article form with the active content format preserved. - */ async function submitArticle() { const { valid } = await articleFormApi.validate(); if (!valid) return; diff --git a/apps/web-antdv-next/src/views/blog/article/preview/index.tsx b/apps/web-antdv-next/src/views/blog/article/preview/index.tsx index 59dda8a..6b4997a 100644 --- a/apps/web-antdv-next/src/views/blog/article/preview/index.tsx +++ b/apps/web-antdv-next/src/views/blog/article/preview/index.tsx @@ -27,9 +27,6 @@ const articleStatusOptions = [ export default defineComponent({ name: 'BlogArticlePreview', - /** - * Wires the current article route id to a full-bleed Blog Web iframe preview. - */ setup() { const route = useRoute(); const router = useRouter(); @@ -64,16 +61,10 @@ export default defineComponent({ { immediate: true }, ); - /** - * Navigates back to the Blog article list. - */ function goBack() { void router.push({ name: 'BlogArticle' }); } - /** - * Opens the current public KT Blog Web preview in a browser tab for direct inspection. - */ function openPreviewInNewWindow() { if (!iframeUrl.value) { return; @@ -82,9 +73,6 @@ export default defineComponent({ window.open(iframeUrl.value, '_blank', 'noopener,noreferrer'); } - /** - * Reloads the article detail and rebuilds the iframe URL for the current route id. - */ async function loadArticlePreview() { const articleId = routeArticleId.value; article.value = null; @@ -108,11 +96,6 @@ export default defineComponent({ } } - /** - * Renders the floating status card without taking layout space from the preview iframe. - * - * @returns Overlay card with article metadata and navigation actions. - */ const renderFloatingCard = () => { return (
@@ -157,11 +140,6 @@ export default defineComponent({ ); }; - /** - * Renders loading, error, and ready iframe states inside the fixed preview canvas. - * - * @returns Current preview body content. - */ const renderBody = () => { if (state.value === 'ready' && iframeUrl.value) { return ( @@ -197,11 +175,6 @@ export default defineComponent({ ); }; - /** - * Renders the stable page root required by Vben route transitions. - * - * @returns Single-root preview page shell. - */ const renderPage = () => { return (
@@ -217,19 +190,11 @@ export default defineComponent({ }, }); -/** - * @param value Raw vue-router route param value. - * @returns A single trimmed article id string. - */ function normalizeRouteParam(value: unknown) { if (Array.isArray(value)) return `${value[0] || ''}`.trim(); return `${value || ''}`.trim(); } -/** - * @param article Blog article detail returned by the Admin API. - * @returns Plain article title for metadata and iframe title attributes. - */ function getArticleTitle(article?: null | WordpressBlogApi.Article) { const value = article?.title; if (typeof value === 'string') return stripHtml(value); @@ -237,10 +202,6 @@ function getArticleTitle(article?: null | WordpressBlogApi.Article) { return stripHtml(value?.raw || value?.rendered || ''); } -/** - * @param previewUrl Iframe URL built from the KT Blog Web base URL. - * @returns Host shown in the floating card so operators can verify the embedded target. - */ function getPreviewHost(previewUrl: string) { if (!previewUrl) { return ''; @@ -254,10 +215,6 @@ function getPreviewHost(previewUrl: string) { } } -/** - * @param value HTML-ish rendered text from WordPress-compatible article fields. - * @returns Plain text safe for compact Admin metadata. - */ function stripHtml(value: string) { return value .replaceAll(/<[^>]*>/g, ' ') @@ -268,10 +225,6 @@ function stripHtml(value: string) { .trim(); } -/** - * @param state Current preview page lifecycle state. - * @returns Ant Design tag color and Chinese label for the floating card. - */ function getStatusMeta(state: PreviewState) { const statusMap = { error: { color: 'error', label: '异常' }, @@ -282,10 +235,6 @@ function getStatusMeta(state: PreviewState) { return statusMap[state]; } -/** - * @param status Article publish status returned by the Admin API. - * @returns Ant Design tag color and Chinese label for article metadata. - */ function getArticleStatusMeta(status?: string) { return ( articleStatusOptions.find((item) => item.value === status) || diff --git a/apps/web-antdv-next/src/views/blog/modules/article-form.ts b/apps/web-antdv-next/src/views/blog/modules/article-form.ts index dad373c..7f5105b 100644 --- a/apps/web-antdv-next/src/views/blog/modules/article-form.ts +++ b/apps/web-antdv-next/src/views/blog/modules/article-form.ts @@ -21,13 +21,6 @@ const SOURCE_ONLY_HTML_PATTERN = /\b(?:hljs-ln|hljs-control|fancybox-wrapper|lazyload|collapse-block|wp-block-(?!code\b)[\w-]+)/; const HTML_TAG_PATTERN = /<\/?[a-z][\s\S]*>/i; -/** - * Builds the content field schema for Markdown, rich HTML, or raw WordPress HTML preservation. - * @param mode Current editor mode; source mode uses a raw textarea to avoid runtime DOM rewrites. - * @param markdownEditor Markdown editor component used for normal local article authoring. - * @param richHtmlEditor Tiptap HTML editor component used for plain HTML authoring. - * @returns Vben form schema for the article content field. - */ export function createBlogArticleContentSchema( mode: BlogArticleEditorMode, markdownEditor: unknown, @@ -79,11 +72,6 @@ export function createBlogArticleContentSchema( } as VbenFormSchema; } -/** - * Builds the editor mode selector schema and forwards mode changes to the article list page. - * @param onChange Callback that receives the next editor mode selected in the form. - * @returns Vben form schema for selecting the article editor mode. - */ export function createBlogArticleEditorModeSchema( onChange?: (mode: BlogArticleEditorMode) => void, ): VbenFormSchema { @@ -107,22 +95,12 @@ export function createBlogArticleEditorModeSchema( } as VbenFormSchema; } -/** - * Maps the UI editor mode back to the API's persisted content format contract. - * @param mode Current editor mode from the article form. - * @returns API content format saved with the article. - */ export function getContentFormatForEditorMode( mode: BlogArticleEditorMode, ): BlogArticleContentFormat { return mode === 'markdown' ? 'markdown' : 'html'; } -/** - * Chooses the editor mode for an existing article without forcing Markdown source or imported Argon HTML into the wrong editor. - * @param article Article row returned by the local blog API. - * @returns Markdown for source-backed articles, source HTML for strong runtime DOM, rich HTML for plain tags. - */ export function getBlogArticleEditorMode( article?: Partial, ): BlogArticleEditorMode { @@ -134,24 +112,12 @@ export function getBlogArticleEditorMode( return HTML_TAG_PATTERN.test(html) ? 'html-rich' : 'markdown'; } -/** - * Chooses the persisted content format for an existing article. - * @param article Article row returned by the local blog API. - * @returns API content format derived from the detected editor mode. - */ export function getBlogArticleContentFormat( article?: Partial, ): BlogArticleContentFormat { return getContentFormatForEditorMode(getBlogArticleEditorMode(article)); } -/** - * Builds form defaults for creating a new article from current table filters. - * @param searchValues Active table search filters used to prefill category and tag fields. - * @param searchValues.categories Active category filters copied into the create form. - * @param searchValues.tags Active tag filters copied into the create form. - * @returns Article form defaults in Markdown mode. - */ export function getBlogArticleCreateFormDefaults( searchValues: { categories?: string[]; @@ -172,11 +138,6 @@ export function getBlogArticleCreateFormDefaults( }; } -/** - * Builds edit form values, preserving WordPress/Argon HTML when the article depends on runtime classes. - * @param row Article row selected from the article table. - * @returns Form values and content format for the edit modal. - */ export function getBlogArticleEditFormValues( row: WordpressBlogApi.Article, ): BlogArticleFormValues { @@ -201,13 +162,6 @@ export function getBlogArticleEditFormValues( }; } -/** - * Builds the API payload while preserving the current content format selected for the modal. - * @param values Current form values from Vben Form. - * @param editingId Current article id, or undefined for create. - * @param editorMode Current editor mode. - * @returns Payload accepted by the blog article save/update API. - */ export function buildBlogArticleSubmitPayload( values: BlogArticleFormValues, editingId: string | undefined, @@ -222,43 +176,22 @@ export function buildBlogArticleSubmitPayload( }; } -/** - * Converts WordPress rendered fields or strings into readable plain text. - * @param value Rendered field or string value. - * @returns HTML-free text. - */ export function getRenderedText( value?: string | WordpressBlogApi.RenderedField, ) { return stripHtml(getRenderedValue(value)); } -/** - * Reads a rendered field without stripping HTML. - * @param value Rendered field or string value. - * @returns Raw/rendered string. - */ function getRenderedValue(value?: string | WordpressBlogApi.RenderedField) { if (!value) return ''; if (typeof value === 'string') return value; return value.raw || value.rendered || ''; } -/** - * Detects whether the article still owns an editable Markdown source snapshot. - * @param article Article row returned by the local blog API. - * @returns true when Admin should prefer Milkdown unless strong runtime-only HTML is present. - */ function hasMarkdownSource(article?: Partial) { return !!article?.contentMarkdown?.trim(); } -/** - * Chooses editable Markdown from an API rendered field and its explicit Markdown source. - * @param value Rendered field or string value. - * @param markdown Explicit Markdown source saved on local articles. - * @returns Markdown text for the Milkdown editor. - */ function getEditableMarkdown( value?: string | WordpressBlogApi.RenderedField, markdown?: string, @@ -267,11 +200,6 @@ function getEditableMarkdown( return getRenderedValue(value); } -/** - * Strips simple HTML tags from Admin labels and excerpts. - * @param value HTML or text value. - * @returns Trimmed text. - */ function stripHtml(value: string) { return value .replaceAll(/<[^>]+>/g, '') diff --git a/apps/web-antdv-next/src/views/dashboard/analytics/components/EnvironmentEventStream.vue b/apps/web-antdv-next/src/views/dashboard/analytics/components/EnvironmentEventStream.vue index aef1ed3..39d2c0a 100644 --- a/apps/web-antdv-next/src/views/dashboard/analytics/components/EnvironmentEventStream.vue +++ b/apps/web-antdv-next/src/views/dashboard/analytics/components/EnvironmentEventStream.vue @@ -7,12 +7,6 @@ defineProps<{ events: EnvironmentEvent[]; }>(); -/** - * Maps event severity to a compact tag color. - * - * @param status Event severity from the API stream or snapshot. - * @returns Antdv tag color value. - */ function getStatusColor(status: EnvironmentHealthStatus) { if (status === 'ok') return 'success'; if (status === 'degraded') return 'warning'; diff --git a/apps/web-antdv-next/src/views/dashboard/analytics/components/EnvironmentEvidencePanel.vue b/apps/web-antdv-next/src/views/dashboard/analytics/components/EnvironmentEvidencePanel.vue index 8c9703c..6aa27d3 100644 --- a/apps/web-antdv-next/src/views/dashboard/analytics/components/EnvironmentEvidencePanel.vue +++ b/apps/web-antdv-next/src/views/dashboard/analytics/components/EnvironmentEvidencePanel.vue @@ -21,13 +21,6 @@ defineEmits<{ selfCheck: []; }>(); -/** - * Returns evidence rows for the selected service or signal. - * - * @param service Selected topology service from the current site. - * @param signal Selected signal when the user drills into one. - * @returns Evidence list shown in the right-side panel. - */ function getEvidenceRows( service?: EnvironmentService, signal?: EnvironmentSignal, @@ -38,12 +31,6 @@ function getEvidenceRows( ); } -/** - * Labels evidence with a stable source and missing-config status. - * - * @param evidence Evidence record from the API contract. - * @returns Human-readable evidence title. - */ function getEvidenceTitle(evidence: EnvironmentEvidence) { return `${evidence.type || 'evidence'} · ${evidence.source}`; } diff --git a/apps/web-antdv-next/src/views/dashboard/analytics/components/EnvironmentSiteRail.vue b/apps/web-antdv-next/src/views/dashboard/analytics/components/EnvironmentSiteRail.vue index 0353402..8a07908 100644 --- a/apps/web-antdv-next/src/views/dashboard/analytics/components/EnvironmentSiteRail.vue +++ b/apps/web-antdv-next/src/views/dashboard/analytics/components/EnvironmentSiteRail.vue @@ -12,12 +12,6 @@ defineEmits<{ selectSite: [siteId: string]; }>(); -/** - * Counts service signals under a site for compact rail evidence. - * - * @param site Site record from the dashboard snapshot. - * @returns Total number of service signals in the site tree. - */ function countSignals(site: EnvironmentSite) { return site.nodes.reduce( (count, node) => @@ -30,12 +24,6 @@ function countSignals(site: EnvironmentSite) { ); } -/** - * Counts unwired signals so missing config remains visible. - * - * @param site Site record from the dashboard snapshot. - * @returns Number of signals marked as unwired by the API. - */ function countUnwiredSignals(site: EnvironmentSite) { return site.nodes.reduce( (count, node) => @@ -51,12 +39,6 @@ function countUnwiredSignals(site: EnvironmentSite) { ); } -/** - * Maps site status to antdv badge status. - * - * @param site Site record from the dashboard snapshot. - * @returns Badge status that preserves unknown/unwired as non-green. - */ function getBadgeStatus(site: EnvironmentSite) { if (site.status === 'online') return 'success'; if (site.status === 'degraded') return 'warning'; diff --git a/apps/web-antdv-next/src/views/dashboard/analytics/components/EnvironmentStatusBar.vue b/apps/web-antdv-next/src/views/dashboard/analytics/components/EnvironmentStatusBar.vue index 1ccc3db..6dc2cbe 100644 --- a/apps/web-antdv-next/src/views/dashboard/analytics/components/EnvironmentStatusBar.vue +++ b/apps/web-antdv-next/src/views/dashboard/analytics/components/EnvironmentStatusBar.vue @@ -17,11 +17,6 @@ defineEmits<{ selfCheck: []; }>(); -/** - * Chooses the strongest global status from summary counters. - * - * @returns Status tag value used by the top dashboard bar. - */ function getGlobalStatus(): EnvironmentHealthStatus { const summary = props.dashboard?.summary; if (!summary) return 'unknown'; @@ -32,12 +27,6 @@ function getGlobalStatus(): EnvironmentHealthStatus { return 'ok'; } -/** - * Maps health status to antdv tag colors without hiding unwired integrations. - * - * @param status Global or signal health status from the API. - * @returns Antdv tag color name. - */ function getStatusColor(status: EnvironmentHealthStatus) { if (status === 'ok') return 'success'; if (status === 'degraded') return 'warning'; diff --git a/apps/web-antdv-next/src/views/dashboard/analytics/components/EnvironmentTopology.vue b/apps/web-antdv-next/src/views/dashboard/analytics/components/EnvironmentTopology.vue index 56be1b7..86b27b6 100644 --- a/apps/web-antdv-next/src/views/dashboard/analytics/components/EnvironmentTopology.vue +++ b/apps/web-antdv-next/src/views/dashboard/analytics/components/EnvironmentTopology.vue @@ -16,12 +16,6 @@ defineEmits<{ selectService: [serviceId: string]; }>(); -/** - * Maps service health to a compact tag color. - * - * @param status Service or signal status from the dashboard model. - * @returns Antdv tag color value. - */ function getStatusColor(status: EnvironmentHealthStatus) { if (status === 'ok') return 'success'; if (status === 'degraded') return 'warning'; @@ -30,12 +24,6 @@ function getStatusColor(status: EnvironmentHealthStatus) { return 'default'; } -/** - * Counts unwired signals in a service. - * - * @param service Service record selected from the current site. - * @returns Number of signals that are visibly missing configuration. - */ function countUnwiredSignals(service: EnvironmentService) { return service.signals.filter((signal) => signal.status === 'unwired').length; } diff --git a/apps/web-antdv-next/src/views/dashboard/analytics/composables/useEnvironmentDashboardStream.ts b/apps/web-antdv-next/src/views/dashboard/analytics/composables/useEnvironmentDashboardStream.ts index 55e9541..70afdb5 100644 --- a/apps/web-antdv-next/src/views/dashboard/analytics/composables/useEnvironmentDashboardStream.ts +++ b/apps/web-antdv-next/src/views/dashboard/analytics/composables/useEnvironmentDashboardStream.ts @@ -20,12 +20,6 @@ export interface UseEnvironmentDashboardStreamOptions { onSnapshotRequired: (event: StreamEvent) => void; } -/** - * Opens one browser EventSource for Admin environment updates after the first HTTP snapshot. - * - * @param options Page-owned callbacks that merge SSE payloads into visible state. - * @returns Controls for starting and closing the stream plus connection state for display. - */ export function useEnvironmentDashboardStream( options: UseEnvironmentDashboardStreamOptions, ) { @@ -33,9 +27,6 @@ export function useEnvironmentDashboardStream( const lastEventId = ref(); let source: EventSource | undefined; - /** - * Starts the SSE connection once and lets the browser handle native reconnects. - */ function start() { if (source) return; connectionState.value = 'connecting'; @@ -53,9 +44,6 @@ export function useEnvironmentDashboardStream( source.addEventListener('error', handleError); } - /** - * Closes the EventSource when the route leaves or the component unmounts. - */ function close() { if (!source) return; source.removeEventListener('open', handleOpen); @@ -69,18 +57,10 @@ export function useEnvironmentDashboardStream( connectionState.value = 'closed'; } - /** - * Marks the stream as open after the browser confirms the connection. - */ function handleOpen() { connectionState.value = 'open'; } - /** - * Applies a backend event entry to the visible event stream. - * - * @param event Browser SSE message carrying an EnvironmentEvent JSON payload. - */ function handleEnvironmentEvent(event: Event) { const payload = parseStreamEvent(event); if (!payload) return; @@ -88,11 +68,6 @@ export function useEnvironmentDashboardStream( options.onEnvironmentEvent(payload); } - /** - * Applies one signal-level update without reloading the dashboard snapshot. - * - * @param event Browser SSE message carrying an EnvironmentEvent JSON payload. - */ function handleEnvironmentSignal(event: Event) { const payload = parseStreamEvent(event); if (!payload) return; @@ -100,11 +75,6 @@ export function useEnvironmentDashboardStream( options.onEnvironmentSignal(payload); } - /** - * Notifies the page that the API replay buffer requires one fresh snapshot. - * - * @param event Browser SSE message carrying the replay-gap event envelope. - */ function handleSnapshotRequired(event: Event) { const payload = parseStreamEvent(event); if (!payload) return; @@ -112,20 +82,12 @@ export function useEnvironmentDashboardStream( options.onSnapshotRequired(payload); } - /** - * Leaves dashboard state unchanged for keepalive events. - */ function handleHeartbeat() { if (connectionState.value === 'connecting') { connectionState.value = 'open'; } } - /** - * Records stream errors without starting polling or manual reconnect loops. - * - * @param event Optional API error payload when the server sends a typed error event. - */ function handleError(event: Event) { connectionState.value = 'error'; const payload = parseStreamEvent(event); @@ -135,12 +97,6 @@ export function useEnvironmentDashboardStream( } } - /** - * Parses JSON payloads from typed SSE events. - * - * @param event Browser EventSource event that may include string data. - * @returns Environment event payload, or undefined when malformed. - */ function parseStreamEvent(event: Event) { const data = (event as MessageEvent).data; if (!data) return undefined; @@ -151,11 +107,6 @@ export function useEnvironmentDashboardStream( } } - /** - * Keeps the replay cursor scoped to the current route instance. - * - * @param event Parsed environment stream event from the API. - */ function rememberEventId(event: StreamEvent) { if (event.eventId) { lastEventId.value = event.eventId; diff --git a/apps/web-antdv-next/src/views/dashboard/analytics/environment-dashboard.spec.tsx b/apps/web-antdv-next/src/views/dashboard/analytics/environment-dashboard.spec.tsx index f6acf13..5c88437 100644 --- a/apps/web-antdv-next/src/views/dashboard/analytics/environment-dashboard.spec.tsx +++ b/apps/web-antdv-next/src/views/dashboard/analytics/environment-dashboard.spec.tsx @@ -131,41 +131,21 @@ class FakeEventSource { readonly listeners = new Map>(); readonly url: string; - /** - * Records the stream URL used by the page so tests can dispatch typed SSE messages. - * - * @param url Browser EventSource URL built from the Admin API wrapper. - */ constructor(url: string) { this.url = url; FakeEventSource.instances.push(this); } - /** - * Stores typed SSE listeners registered by the production stream composable. - * - * @param type SSE event type supplied by the backend stream. - * @param listener Component-side event handler receiving the JSON payload. - */ addEventListener(type: string, listener: FakeEventSourceListener) { const listeners = this.listeners.get(type) ?? new Set(); listeners.add(listener); this.listeners.set(type, listeners); } - /** - * Marks the connection as closed so the unmount lifecycle can be asserted. - */ close() { this.closed = true; } - /** - * Delivers one typed SSE message to the mounted page. - * - * @param type SSE event name sent by the API. - * @param payload JSON-serializable event payload. - */ dispatch(type: string, payload: unknown) { const event = new MessageEvent(type, { data: JSON.stringify(payload), @@ -175,20 +155,11 @@ class FakeEventSource { } } - /** - * Removes an SSE listener during component cleanup. - * - * @param type SSE event type supplied by the backend stream. - * @param listener Previously registered component handler. - */ removeEventListener(type: string, listener: FakeEventSourceListener) { this.listeners.get(type)?.delete(listener); } } -/** - * Flushes Vue microtasks created by API promises and reactive state updates. - */ async function flushDashboardUpdates() { await Promise.resolve(); await nextTick(); @@ -196,11 +167,6 @@ async function flushDashboardUpdates() { await nextTick(); } -/** - * Builds a complete four-site dashboard fixture that mirrors the backend contract. - * - * @param includeMqttEvent Whether the API snapshot should already contain a MQTT-origin event. - */ function createDashboardFixture( includeMqttEvent = false, ): EnvironmentDashboardApi.EnvironmentDashboardResponse { diff --git a/apps/web-antdv-next/src/views/dashboard/analytics/index.vue b/apps/web-antdv-next/src/views/dashboard/analytics/index.vue index 3b95614..afef49e 100644 --- a/apps/web-antdv-next/src/views/dashboard/analytics/index.vue +++ b/apps/web-antdv-next/src/views/dashboard/analytics/index.vue @@ -51,30 +51,18 @@ const streamState = environmentStream.connectionState; onMounted(handleMounted); onBeforeUnmount(handleBeforeUnmount); -/** - * Starts the initial snapshot load when the Vben route component mounts. - */ function handleMounted() { void loadDashboardSnapshot('initial'); } -/** - * Closes the SSE stream when route transitions remove this page. - */ function handleBeforeUnmount() { environmentStream.close(); } -/** - * Handles explicit user refresh without creating timer-based polling. - */ function handleManualRefresh() { void loadDashboardSnapshot('manual'); } -/** - * Runs the read-only backend self-check and replaces visible evidence with its response. - */ async function handleSelfCheck() { selfChecking.value = true; errorText.value = ''; @@ -87,11 +75,6 @@ async function handleSelfCheck() { } } -/** - * Loads a dashboard snapshot for first render, manual refresh, or replay gap recovery. - * - * @param reason Call origin that controls loading state and snapshot-required de-duping. - */ async function loadDashboardSnapshot(reason: SnapshotLoadReason) { if (reason === 'snapshot-required') { if (snapshotRequestInFlight.value) return; @@ -114,22 +97,12 @@ async function loadDashboardSnapshot(reason: SnapshotLoadReason) { } } -/** - * Applies a full dashboard response while preserving still-valid selections. - * - * @param next Dashboard response from GET snapshot or POST self-check. - */ function applyDashboard(next: EnvironmentDashboard) { dashboard.value = next; recentEvents.value = [...(next.events ?? [])]; ensureSelection(next); } -/** - * Preserves selected service when possible, otherwise selects the first risky service. - * - * @param next Dashboard response that becomes the new source of truth. - */ function ensureSelection(next: EnvironmentDashboard) { const existingSite = selectedSiteId.value ? next.sites.find((site) => site.id === selectedSiteId.value) @@ -152,11 +125,6 @@ function ensureSelection(next: EnvironmentDashboard) { selectedSignalId.value = fallbackService?.signals[0]?.id; } -/** - * Updates selected site and moves service selection to that site's first service. - * - * @param siteId Site ID emitted by the left rail. - */ function handleSiteSelect(siteId: string) { selectedSiteId.value = siteId; const site = dashboard.value?.sites.find((item) => item.id === siteId); @@ -165,61 +133,31 @@ function handleSiteSelect(siteId: string) { selectedSignalId.value = service?.signals[0]?.id; } -/** - * Updates selected service inside the active site. - * - * @param serviceId Service ID emitted by the topology panel. - */ function handleServiceSelect(serviceId: string) { const service = findService(selectedSite.value, serviceId); selectedServiceId.value = service?.id; selectedSignalId.value = service?.signals[0]?.id; } -/** - * Adds a stream event to the visible bottom event list. - * - * @param event SSE event envelope sent by the API stream. - */ function handleEnvironmentEvent(event: EnvironmentEvent) { addRecentEvent(event); } -/** - * Merges one signal update into the current dashboard tree without re-fetching. - * - * @param event SSE signal envelope sent by the API stream. - */ function handleEnvironmentSignal(event: EnvironmentEvent) { addRecentEvent(event); applySignalEvent(event); } -/** - * Runs one snapshot load when the API reports a replay buffer gap. - * - * @param event Snapshot-required event envelope from the API stream. - */ function handleSnapshotRequired(event: EnvironmentEvent) { addRecentEvent(event); void loadDashboardSnapshot('snapshot-required'); } -/** - * Shows stream errors as evidence without starting a polling fallback. - * - * @param event Error event envelope from the API stream. - */ function handleStreamError(event: EnvironmentEvent) { addRecentEvent(event); errorText.value = event.summary; } -/** - * Applies one service or signal-level update in-place for visible topology state. - * - * @param event Parsed SSE environment-signal payload. - */ function applySignalEvent(event: EnvironmentEvent) { const site = dashboard.value?.sites.find((item) => item.id === event.siteId); if (!site || !event.serviceId) return; @@ -245,11 +183,6 @@ function applySignalEvent(event: EnvironmentEvent) { site.status = mapSiteStatus(site.nodes.map((item) => item.status)); } -/** - * Inserts a recent event newest-first while de-duping by event ID. - * - * @param event Event from the initial snapshot or SSE stream. - */ function addRecentEvent(event: EnvironmentEvent) { recentEvents.value = [ event, @@ -257,52 +190,26 @@ function addRecentEvent(event: EnvironmentEvent) { ].slice(0, 30); } -/** - * Resolves the currently selected site from reactive IDs. - * - * @returns Selected site or undefined when the dashboard has not loaded. - */ function resolveSelectedSite() { return dashboard.value?.sites.find( (site) => site.id === selectedSiteId.value, ); } -/** - * Resolves the currently selected service from the selected site. - * - * @returns Selected service or undefined when no service is selected. - */ function resolveSelectedService() { return findService(selectedSite.value, selectedServiceId.value); } -/** - * Resolves the currently selected signal from the selected service. - * - * @returns Selected signal or undefined when no signal is selected. - */ function resolveSelectedSignal() { return findSignal(selectedService.value, selectedSignalId.value); } -/** - * Sorts events newest-first using their observed time while keeping stable IDs. - * - * @returns Event list used by the bottom stream panel. - */ function resolveSortedEvents() { return recentEvents.value.toSorted( (left, right) => Date.parse(right.observedAt) - Date.parse(left.observedAt), ); } -/** - * Finds the first non-green service as the default operational focus. - * - * @param sites Dashboard sites from the latest snapshot. - * @returns Preferred site/service pair or undefined when all sites are empty. - */ function findFirstAttentionService(sites: EnvironmentSite[]) { for (const site of sites) { for (const node of site.nodes) { @@ -319,23 +226,10 @@ function findFirstAttentionService(sites: EnvironmentSite[]) { return undefined; } -/** - * Finds the first service under a site. - * - * @param site Site selected by route state or fallback selection. - * @returns First service in the site tree. - */ function getFirstService(site?: EnvironmentSite) { return site?.nodes.flatMap((node) => node.services)[0]; } -/** - * Finds one service by ID within a site. - * - * @param site Site tree to inspect. - * @param serviceId Service ID from user selection or persisted state. - * @returns Matching service when still present. - */ function findService(site?: EnvironmentSite, serviceId?: string) { if (!site || !serviceId) return undefined; for (const node of site.nodes) { @@ -345,48 +239,21 @@ function findService(site?: EnvironmentSite, serviceId?: string) { return undefined; } -/** - * Finds one service by ID within a single node. - * - * @param node Node that owns service records. - * @param serviceId Service ID from an SSE event or user selection. - * @returns Matching service when present. - */ function findServiceInNode(node: EnvironmentNode, serviceId: string) { return node.services.find((service) => service.id === serviceId); } -/** - * Finds the node that owns a service ID. - * - * @param site Site tree to inspect. - * @param serviceId Service ID from the SSE signal envelope. - * @returns Owning node when the service exists. - */ function findNodeByServiceId(site: EnvironmentSite, serviceId: string) { return site.nodes.find((node) => node.services.some((service) => service.id === serviceId), ); } -/** - * Finds one signal by ID within a service. - * - * @param service Service that owns signal records. - * @param signalId Signal ID from selection or an SSE event. - * @returns Matching signal when present. - */ function findSignal(service?: EnvironmentService, signalId?: string) { if (!service || !signalId) return undefined; return service.signals.find((signal) => signal.id === signalId); } -/** - * Converts event source metadata into signal source kinds supported by node badges. - * - * @param sourceKind Event source kind from the SSE envelope. - * @returns Signal source kind stored on the affected signal. - */ function mapEventSourceToSignalSource( sourceKind: EnvironmentEvent['sourceKind'], ): EnvironmentSignal['sourceKind'] { @@ -394,12 +261,6 @@ function mapEventSourceToSignalSource( return sourceKind; } -/** - * Picks the strongest status for a node after a signal update. - * - * @param statuses Service statuses under the same node. - * @returns Strongest health status according to dashboard severity rules. - */ function pickWorstHealthStatus( statuses: EnvironmentHealthStatus[], ): EnvironmentHealthStatus { @@ -421,12 +282,6 @@ function pickWorstHealthStatus( return worst; } -/** - * Maps node health back into the coarser site status union. - * - * @param statuses Node statuses under the same site. - * @returns Site-level status that never marks unknown/unwired integrations green. - */ function mapSiteStatus(statuses: EnvironmentHealthStatus[]) { const worst = pickWorstHealthStatus(statuses); if (worst === 'ok') return 'online'; @@ -437,12 +292,6 @@ function mapSiteStatus(statuses: EnvironmentHealthStatus[]) { return 'unknown'; } -/** - * Normalizes unknown thrown values from request wrappers into alert text. - * - * @param error Error thrown by the request client or runtime code. - * @returns User-visible error summary. - */ function getErrorMessage(error: unknown) { if (error instanceof Error) return error.message; if (typeof error === 'string') return error; diff --git a/apps/web-antdv-next/src/views/examples/cropper/index.vue b/apps/web-antdv-next/src/views/examples/cropper/index.vue index f652eae..2b4454b 100644 --- a/apps/web-antdv-next/src/views/examples/cropper/index.vue +++ b/apps/web-antdv-next/src/views/examples/cropper/index.vue @@ -56,9 +56,6 @@ const cropImage = async () => { } }; -/** - * 下载图片 - */ const downloadImage = () => { if (!cropperImg.value) return; diff --git a/apps/web-antdv-next/src/views/examples/form/basic.vue b/apps/web-antdv-next/src/views/examples/form/basic.vue index 1d2c48d..995640b 100644 --- a/apps/web-antdv-next/src/views/examples/form/basic.vue +++ b/apps/web-antdv-next/src/views/examples/form/basic.vue @@ -440,9 +440,6 @@ function onSubmit(values: Record) { } function handleSetFormValue() { - /** - * 设置表单值(多个) - */ baseFormApi.setValues({ checkboxGroup: ['1'], datePicker: dayjs('2022-01-01'), diff --git a/apps/web-antdv-next/src/views/qqbot/account/components/AccountConfigPanel.spec.tsx b/apps/web-antdv-next/src/views/qqbot/account/components/AccountConfigPanel.spec.tsx index 56d33ae..5c15e11 100644 --- a/apps/web-antdv-next/src/views/qqbot/account/components/AccountConfigPanel.spec.tsx +++ b/apps/web-antdv-next/src/views/qqbot/account/components/AccountConfigPanel.spec.tsx @@ -46,9 +46,6 @@ vi.mock('#/components/ktTable', () => ({ KtTable: defineComponent({ name: 'MockLegacyKtTable', inheritAttrs: false, - /** - * Renders the real parent-owned header callbacks and records legacy table props. - */ setup(_, { attrs, slots }) { return () => { mocks.legacyTableProps.push(attrs); @@ -68,7 +65,6 @@ vi.mock('antdv-next', () => ({ }, Spin: defineComponent({ name: 'MockSpin', - /** Keeps the legacy table subtree mounted for regression assertions. */ setup(_, { slots }) { return () => h('div', slots.default?.()); }, @@ -80,7 +76,6 @@ vi.mock('antdv-next', () => ({ items: Array, }, emits: ['update:activeKey'], - /** Exposes every configured tab through a deterministic clickable button. */ setup(props, { emit }) { return () => h( @@ -102,7 +97,6 @@ vi.mock('antdv-next', () => ({ }), Tag: defineComponent({ name: 'MockTag', - /** Renders tag text without changing the parent structure. */ setup(_, { slots }) { return () => h('span', slots.default?.()); }, @@ -117,7 +111,6 @@ vi.mock('./AccountMessagePushPanel', () => ({ selfId: String, title: Function, }, - /** Renders both inherited header callbacks to prove the ownership boundary. */ setup(props) { return () => h('section', { 'data-testid': 'message-push-panel' }, [ @@ -128,7 +121,6 @@ vi.mock('./AccountMessagePushPanel', () => ({ }), })); -/** Creates the current route account with an unsafe-integer string self ID. */ function createAccount(): QqbotApi.Account { return { connectStatus: 'online', diff --git a/apps/web-antdv-next/src/views/qqbot/account/components/AccountMessagePushModal.spec.tsx b/apps/web-antdv-next/src/views/qqbot/account/components/AccountMessagePushModal.spec.tsx index 02d7b9f..b8a72fe 100644 --- a/apps/web-antdv-next/src/views/qqbot/account/components/AccountMessagePushModal.spec.tsx +++ b/apps/web-antdv-next/src/views/qqbot/account/components/AccountMessagePushModal.spec.tsx @@ -50,7 +50,6 @@ const mocks = vi.hoisted(() => { }; }); -/** Creates one fluent no-op Zod rule for schema-focused tests. */ function createRule(): any { const rule: any = {}; for (const method of [ @@ -72,7 +71,6 @@ vi.mock('#/adapter/form', () => ({ mocks.formOptions = options; const Form = defineComponent({ name: 'MockBindingForm', - /** Renders the schema's real local target-picker component and model wiring. */ setup() { return () => { const targetField = mocks.formOptions.schema.find( @@ -113,7 +111,6 @@ vi.mock('@vben/common-ui', () => ({ mocks.modalOptions = options; const Modal = defineComponent({ name: 'MockBindingModal', - /** Renders modal content while lifecycle remains API-controlled. */ setup(_, { slots }) { return () => h('section', slots.default?.()); }, @@ -134,7 +131,6 @@ vi.mock('./MessagePushTargetPicker', () => ({ value: Array, }, emits: ['update:value'], - /** Exposes one button that exercises the Vben `modelPropName:value` path. */ setup(_, { emit }) { return () => h( @@ -150,9 +146,6 @@ vi.mock('./MessagePushTargetPicker', () => ({ ); }, }), - /** - * Mirrors the production helper so modal tests retain the exact validation boundary. - */ isValidMessagePushTargetId: (targetId: string) => /^[1-9]\d{4,19}$/.test(targetId), })); @@ -162,7 +155,6 @@ vi.mock('#/api/qqbot/message-push', () => ({ updateAccountMessagePushBinding: mocks.update, })); -/** Creates two source families to test compatible-template filtering. */ function createSubscriptions(): QqbotMessagePushApi.MessageSubscriptionView[] { return [ { @@ -219,7 +211,6 @@ function createSubscriptions(): QqbotMessagePushApi.MessageSubscriptionView[] { ]; } -/** Creates templates in both source families. */ function createTemplates(): QqbotMessagePushApi.MessageTemplateView[] { return [ { @@ -249,7 +240,6 @@ function createTemplates(): QqbotMessagePushApi.MessageTemplateView[] { ]; } -/** Creates an edit row whose targets retain API-provided names as strings. */ function createBinding(): QqbotMessagePushApi.QqbotMessagePublishBindingView { return { available: true, @@ -283,7 +273,6 @@ function createBinding(): QqbotMessagePushApi.QqbotMessagePublishBindingView { }; } -/** Creates one manually resolved promise for async session-race assertions. */ function deferred() { let resolve!: (value: T) => void; const promise = new Promise((done) => { @@ -292,7 +281,6 @@ function deferred() { return { promise, resolve }; } -/** Mounts the modal with one implicit publisher and page-owned metadata. */ function mountModal(selfId = '10000000000000001') { return mount(AccountMessagePushModal, { props: { diff --git a/apps/web-antdv-next/src/views/qqbot/account/components/AccountMessagePushModal.tsx b/apps/web-antdv-next/src/views/qqbot/account/components/AccountMessagePushModal.tsx index d810600..6594698 100644 --- a/apps/web-antdv-next/src/views/qqbot/account/components/AccountMessagePushModal.tsx +++ b/apps/web-antdv-next/src/views/qqbot/account/components/AccountMessagePushModal.tsx @@ -64,7 +64,6 @@ export default defineComponent({ }, }, emits: ['saved'], - /** Owns one account-scoped create/edit session without selecting another account. */ setup(props, { emit, expose }) { const editingId = ref(); const modalOpen = ref(false); @@ -75,11 +74,6 @@ export default defineComponent({ commonConfig: { labelClass: 'w-24', }, - /** - * Keeps the selected template only while it remains source-compatible. - * @param values - Current form values after the update. - * @param fieldsChanged - Exact form fields changed by this event. - */ async handleValuesChange(values, fieldsChanged) { if (!fieldsChanged.includes('subscriptionId')) return; selectedSubscriptionId.value = @@ -100,17 +94,12 @@ export default defineComponent({ showDefaultActions: false, wrapperClass: 'grid-cols-1', }); - /** Derives the title from the current isolated binding identity. */ const modalTitle = computed(() => editingId.value ? '编辑消息推送' : '新增消息推送', ); const [Modal, modalApi] = useVbenModal({ class: 'w-[760px]', fullscreenButton: false, - /** - * Persists the active session while containing failures at ModalApi's - * non-awaited callback boundary. - */ async onConfirm() { try { await submit(); @@ -118,10 +107,6 @@ export default defineComponent({ // The request/form layer already presents the persistence error. } }, - /** - * Restores only the latest session after destroy-on-close content mounts. - * @param isOpen - Whether the modal content is currently mounted. - */ async onOpenChange(isOpen: boolean) { modalOpen.value = isOpen; if (!isOpen) return; @@ -138,7 +123,6 @@ export default defineComponent({ }, }); - /** Opens a fresh four-field binding session for the current account path. */ function openCreate() { editingId.value = undefined; beginSession({ @@ -149,10 +133,6 @@ export default defineComponent({ }); } - /** - * Opens an edit session with only API-provided editable binding values. - * @param row - Account binding selected from the panel-owned KtTable. - */ function openEdit(row: QqbotMessagePushApi.QqbotMessagePublishBindingView) { editingId.value = row.id; beginSession({ @@ -167,10 +147,6 @@ export default defineComponent({ }); } - /** - * Stores one revision-bound modal payload before opening its content. - * @param values - Exact four editable values for the new modal session. - */ function beginSession(values: AccountMessagePushFormValues) { sessionRevision += 1; sessionSelfId = props.selfId; @@ -184,17 +160,12 @@ export default defineComponent({ .open(); } - /** - * Resets the mounted form before installing one isolated session. - * @param values - Exact values captured before opening the modal. - */ async function resetForm(values: AccountMessagePushFormValues) { await formApi.resetForm(); await formApi.setValues(values); await formApi.resetValidate(); } - /** Validates and persists one session without putting selfId in the body. */ async function submit() { const revision = sessionRevision; const selfId = sessionSelfId; @@ -222,9 +193,6 @@ export default defineComponent({ } } - /** - * Invalidates an open old-account session before its path identity changes. - */ async function invalidateForSelfIdChange() { sessionRevision += 1; sessionSelfId = ''; @@ -251,12 +219,6 @@ export default defineComponent({ }, }); -/** - * Builds the exact account-binding schema with the local controlled picker. - * @param props - Page-owned subscriptions, templates, and target candidates. - * @param selectedSubscriptionId - Current subscription driving template options. - * @returns Four fields in subscription/template/targets/enabled order. - */ function createFormSchema( props: Readonly<{ selfId: string; @@ -329,11 +291,6 @@ function createFormSchema( ]; } -/** - * Formats one subscription while retaining server validity information. - * @param subscription - Global subscription available to the current account. - * @returns Select label with a stable invalid reason when applicable. - */ function formatSubscriptionLabel( subscription: QqbotMessagePushApi.MessageSubscriptionView, ): string { @@ -344,12 +301,6 @@ function formatSubscriptionLabel( return `${subscription.name} · ${subscription.sourceName}${reason}`; } -/** - * Returns templates whose source matches the selected global subscription. - * @param props - Current page-owned subscription/template collections. - * @param subscriptionId - Exact selected subscription string ID. - * @returns Source-compatible template rows in server order. - */ function compatibleTemplates( props: Readonly<{ subscriptions: QqbotMessagePushApi.MessageSubscriptionView[]; @@ -364,13 +315,6 @@ function compatibleTemplates( return props.templates.filter((template) => template.sourceKey === sourceKey); } -/** - * Checks template/source compatibility without interpreting numeric IDs. - * @param props - Current subscription/template collections. - * @param subscriptionId - Selected subscription string ID. - * @param templateId - Existing template string ID. - * @returns Whether both rows exist and share the exact source key. - */ function isTemplateCompatible( props: Readonly<{ subscriptions: QqbotMessagePushApi.MessageSubscriptionView[]; @@ -384,12 +328,6 @@ function isTemplateCompatible( ); } -/** - * Validates the exact four-field payload before invoking the account API. - * @param props - Current source-compatible metadata. - * @param values - Form-owned binding values. - * @returns A clean API payload or undefined when any ID/target is invalid. - */ function normalizeBindingPayload( props: Readonly<{ subscriptions: QqbotMessagePushApi.MessageSubscriptionView[]; diff --git a/apps/web-antdv-next/src/views/qqbot/account/components/AccountMessagePushPanel.spec.tsx b/apps/web-antdv-next/src/views/qqbot/account/components/AccountMessagePushPanel.spec.tsx index 507ff8c..a745ca1 100644 --- a/apps/web-antdv-next/src/views/qqbot/account/components/AccountMessagePushPanel.spec.tsx +++ b/apps/web-antdv-next/src/views/qqbot/account/components/AccountMessagePushPanel.spec.tsx @@ -32,11 +32,9 @@ const mocks = vi.hoisted(() => { }, tableOptions: undefined as any, }; - /** Installs the real list callback only after the rendered KtTable registers. */ state.registerTable.mockImplementation(() => { state.registeredTableOptions = state.tableOptions; }); - /** Reloads through the registered list callback and records the applied page. */ state.tableApi.reload.mockImplementation(async () => { if (!state.registeredTableOptions) { throw new Error('[MockKtTable]: table is not registered yet.'); @@ -86,7 +84,6 @@ vi.mock('#/components/ktTable', () => ({ KtTable: defineComponent({ name: 'MockAccountMessagePushKtTable', emits: ['register'], - /** Registers first, then renders inherited account header callbacks. */ setup(_, { emit, slots }) { emit('register', {}); return () => @@ -113,7 +110,6 @@ vi.mock('./AccountMessagePushModal', () => ({ templates: Array, }, emits: ['saved'], - /** Exposes create/edit commands plus a deterministic save event. */ setup(_, { emit, expose }) { expose({ openCreate: mocks.modalOpenCreate, @@ -141,7 +137,6 @@ vi.mock('#/api/qqbot/message-push', () => ({ setAccountMessagePushBindingEnabled: mocks.api.toggleBinding, })); -/** Creates one unsafe-integer string-ID binding row. */ function createBinding( overrides: Partial = {}, ): QqbotMessagePushApi.QqbotMessagePublishBindingView { @@ -171,7 +166,6 @@ function createBinding( }; } -/** Creates one global subscription fixture for the account modal. */ function createSubscription( id = '20000000000000001', ): QqbotMessagePushApi.MessageSubscriptionView { @@ -194,7 +188,6 @@ function createSubscription( }; } -/** Creates one source-compatible template fixture. */ function createTemplate( id = '50000000000000001', ): QqbotMessagePushApi.MessageTemplateView { @@ -212,7 +205,6 @@ function createTemplate( }; } -/** Creates a manually controlled promise for stale-response assertions. */ function deferred() { let resolve!: (value: T) => void; const promise = new Promise((done) => { @@ -221,7 +213,6 @@ function deferred() { return { promise, resolve }; } -/** Mounts the panel with visible account header callbacks. */ function mountPanel(selfId = '10000000000000001') { return mount(AccountMessagePushPanel, { props: { diff --git a/apps/web-antdv-next/src/views/qqbot/account/components/AccountMessagePushPanel.tsx b/apps/web-antdv-next/src/views/qqbot/account/components/AccountMessagePushPanel.tsx index 6fc0c1f..c78d472 100644 --- a/apps/web-antdv-next/src/views/qqbot/account/components/AccountMessagePushPanel.tsx +++ b/apps/web-antdv-next/src/views/qqbot/account/components/AccountMessagePushPanel.tsx @@ -66,7 +66,6 @@ export default defineComponent({ type: Function as PropType<() => VNodeChild>, }, }, - /** Owns one permission-gated account binding table and per-account option cache. */ setup(props) { const { hasAccessByCodes } = useAccess(); const canList = hasAccessByCodes([PERMISSIONS.list]); @@ -127,10 +126,6 @@ export default defineComponent({ ]; const api: KtTableApi = { - /** - * Adapts the account binding array while returning the latest page for stale requests. - * @returns Strict KtTable page retaining every string identifier. - */ list: async () => { const revision = loadRevision; const selfId = props.selfId; @@ -204,35 +199,20 @@ export default defineComponent({ size: 'small', }); - /** Opens a blank binding session for this panel's implicit account. */ function openCreate() { modalRef.value?.openCreate(); } - /** - * Opens one existing binding without deriving another account identity. - * @param row - Binding selected from this account's KtTable. - */ function openEdit(row: QqbotMessagePushApi.QqbotMessagePublishBindingView) { modalRef.value?.openEdit(row); } - /** - * Builds account-binding removal confirmation text. - * @param row - Binding awaiting removal. - * @returns Confirmation containing the global subscription name. - */ function getDeleteConfirm( row: QqbotMessagePushApi.QqbotMessagePublishBindingView, ): string { return `确认解绑消息订阅「${row.subscriptionName}」吗?`; } - /** - * Toggles one binding and reloads only the mutable binding list after success. - * @param row - Binding whose enabled state is inverted. - * @param context - Registered KtTable action context. - */ async function handleToggle( row: QqbotMessagePushApi.QqbotMessagePublishBindingView, context: KtTableContext, @@ -245,11 +225,6 @@ export default defineComponent({ await context.reload(); } - /** - * Removes one binding and reloads only the mutable binding list after success. - * @param row - Binding confirmed for account-scoped removal. - * @param context - Registered KtTable action context. - */ async function handleDelete( row: QqbotMessagePushApi.QqbotMessagePublishBindingView, context: KtTableContext, @@ -258,16 +233,10 @@ export default defineComponent({ await context.reload(); } - /** Reloads only bindings after one successful modal persistence. */ async function handleModalSaved() { await tableApi.reload(); } - /** - * Loads the complete subscription/template collection in bounded 100-row pages. - * @param loader - One strict page caller receiving pageNo/pageSize. - * @returns Concatenated server rows until total is reached or progress stops. - */ async function loadAllPages( loader: (params: { pageNo: number; @@ -293,11 +262,6 @@ export default defineComponent({ return rows; } - /** - * Loads per-account modal metadata once and applies only the latest revision. - * @param selfId - Exact account identity captured for this load. - * @param revision - Monotonic revision assigned by `loadAccount`. - */ async function loadMetadata(selfId: string, revision: number) { targetOptionsLoading.value = canLoadTargets; const [subscriptionResult, templateResult, targetResult] = @@ -321,10 +285,6 @@ export default defineComponent({ targetOptionsLoading.value = false; } - /** - * Starts exactly one logical load for a new nonempty account identity. - * @param selfId - Current implicit account identity. - */ async function loadAccount(selfId: string) { const revision = ++loadRevision; latestBindingPage = { items: [], total: 0 }; @@ -341,23 +301,14 @@ export default defineComponent({ ]); } - /** Starts the one authorized initial account load after table registration. */ function activatePanel() { if (canList && props.selfId) void loadAccount(props.selfId); } - /** Invalidates any pending request when this tab's panel unmounts. */ function invalidatePendingLoad() { loadRevision += 1; } - /** - * Renders source, targets, availability, and enabled state. - * @param slot - KtTable body-cell slot payload. - * @param slot.column - Current data column. - * @param slot.record - Current account binding. - * @returns Custom cell content or undefined for native field rendering. - */ function renderBodyCell(slot: { column: TableColumnType; record: QqbotMessagePushApi.QqbotMessagePublishBindingView; diff --git a/apps/web-antdv-next/src/views/qqbot/account/components/MessagePushTargetPicker.spec.tsx b/apps/web-antdv-next/src/views/qqbot/account/components/MessagePushTargetPicker.spec.tsx index 0acbfb5..d6fb0b9 100644 --- a/apps/web-antdv-next/src/views/qqbot/account/components/MessagePushTargetPicker.spec.tsx +++ b/apps/web-antdv-next/src/views/qqbot/account/components/MessagePushTargetPicker.spec.tsx @@ -11,7 +11,6 @@ import MessagePushTargetPicker, { isValidMessagePushTargetId, } from './MessagePushTargetPicker'; -/** Creates type-scoped known group/private target candidates. */ function createOptions(): QqbotMessagePushApi.QqbotMessagePushTargetOption[] { return [ { @@ -27,7 +26,6 @@ function createOptions(): QqbotMessagePushApi.QqbotMessagePushTargetOption[] { ]; } -/** Mounts the controlled picker with optional contract overrides. */ function mountPicker( overrides: Partial<{ available: boolean; @@ -49,7 +47,6 @@ function mountPicker( }); } -/** Reads the newest controlled value emitted by the picker. */ function latestValue( wrapper: ReturnType, ): QqbotMessagePushApi.QqbotMessagePublishTargetInput[] { diff --git a/apps/web-antdv-next/src/views/qqbot/account/components/MessagePushTargetPicker.tsx b/apps/web-antdv-next/src/views/qqbot/account/components/MessagePushTargetPicker.tsx index 4006606..ad72a44 100644 --- a/apps/web-antdv-next/src/views/qqbot/account/components/MessagePushTargetPicker.tsx +++ b/apps/web-antdv-next/src/views/qqbot/account/components/MessagePushTargetPicker.tsx @@ -27,11 +27,6 @@ export interface MessagePushTargetPickerProps { value: QqbotMessagePushApi.QqbotMessagePublishTargetInput[]; } -/** - * Validates one QQ group/user target without numeric conversion. - * @param targetId - Trimmed target identifier supplied by the Select runtime. - * @returns Whether the identifier is 5–20 digits and has no leading zero. - */ export function isValidMessagePushTargetId(targetId: string): boolean { return /^[1-9]\d{4,19}$/.test(targetId); } @@ -69,38 +64,23 @@ export default defineComponent({ }, }, emits: { - /** - * Emits one normalized controlled target collection. - * @param value - Group-first then private targets with string IDs only. - * @returns Whether the payload remains an array for Vue emit validation. - */ 'update:value': ( value: QqbotMessagePushApi.QqbotMessagePublishTargetInput[], ) => Array.isArray(value), }, - /** Owns only selector remount revisions; all durable values stay controlled. */ setup(props, { emit }) { const groupRevision = ref(0); const privateRevision = ref(0); - /** Derives the currently controlled group IDs without cloning other fields. */ const groupIds = computed(() => targetIdsForType(props.value, 'group')); - /** Derives the currently controlled private IDs independently. */ const privateIds = computed(() => targetIdsForType(props.value, 'private')); - /** Maps only server-returned group choices to raw Select values. */ const groupOptions = computed(() => createSelectOptions(props.options, 'group'), ); - /** Maps only server-returned private choices to raw Select values. */ const privateOptions = computed(() => createSelectOptions(props.options, 'private'), ); - /** - * Cleans one installed Select update and remounts only rejected input. - * @param targetType - Selector whose controlled string values changed. - * @param runtimeValue - Raw installed Select emission; may contain bad runtime values. - */ function handleValueUpdate(targetType: TargetType, runtimeValue: unknown) { const targetIds = normalizeTargetIds(runtimeValue); if (containsRejectedTarget(runtimeValue, targetIds)) { @@ -164,12 +144,6 @@ export default defineComponent({ }, }); -/** - * Returns controlled target IDs for exactly one target type. - * @param targets - Current API/form-controlled targets. - * @param targetType - Group or private selector identity. - * @returns Original string IDs in their controlled order. - */ function targetIdsForType( targets: QqbotMessagePushApi.QqbotMessagePublishTargetInput[], targetType: TargetType, @@ -179,12 +153,6 @@ function targetIdsForType( .map((target) => target.targetId); } -/** - * Maps one type's API candidates to plain string-value Select options. - * @param options - Current OneBot candidate snapshot. - * @param targetType - Type allowed in the target selector. - * @returns Type-scoped candidates retaining their server labels. - */ function createSelectOptions( options: QqbotMessagePushApi.QqbotMessagePushTargetOption[], targetType: TargetType, @@ -198,12 +166,6 @@ function createSelectOptions( })); } -/** - * Searches one known candidate by case-insensitive label and string ID. - * @param input - Search text entered into the installed Select. - * @param option - Candidate option produced by `createSelectOptions`. - * @returns Whether its label or target ID contains the query. - */ function filterTargetOption( input: string, option: Record, @@ -215,11 +177,6 @@ function filterTargetOption( ); } -/** - * Sanitizes the installed tags-mode payload without coercing non-string values. - * @param runtimeValue - Raw `update:value` payload from Antdv Next. - * @returns Trimmed, valid, deduplicated string IDs in input order. - */ function normalizeTargetIds(runtimeValue: unknown): string[] { if (!Array.isArray(runtimeValue)) return []; const seen = new Set(); @@ -234,12 +191,6 @@ function normalizeTargetIds(runtimeValue: unknown): string[] { return result; } -/** - * Detects internal Select state that differs from the cleaned controlled value. - * @param runtimeValue - Raw installed component emission. - * @param normalized - Accepted target IDs. - * @returns Whether the affected Select must remount to discard invalid state. - */ function containsRejectedTarget( runtimeValue: unknown, normalized: string[], @@ -252,14 +203,6 @@ function containsRejectedTarget( ); } -/** - * Rebuilds group-first/private-second targets after one selector update. - * @param current - Controlled value carrying existing API name snapshots. - * @param options - Current type-scoped candidate labels. - * @param changedType - Selector whose IDs are replaced. - * @param changedIds - Sanitized replacement IDs. - * @returns Normalized targets with no cross-type name leakage. - */ function mergeTargets( current: QqbotMessagePushApi.QqbotMessagePublishTargetInput[], options: QqbotMessagePushApi.QqbotMessagePushTargetOption[], @@ -291,14 +234,6 @@ function mergeTargets( ); } -/** - * Resolves a display name from only the same target type and identifier. - * @param current - Existing API/form values with optional name snapshots. - * @param options - Current OneBot candidates. - * @param targetType - Exact group/private namespace. - * @param targetId - Exact string target identifier. - * @returns Current candidate label, same-type existing name, or undefined. - */ function resolveTargetName( current: QqbotMessagePushApi.QqbotMessagePublishTargetInput[], options: QqbotMessagePushApi.QqbotMessagePushTargetOption[], diff --git a/apps/web-antdv-next/src/views/qqbot/account/list.tsx b/apps/web-antdv-next/src/views/qqbot/account/list.tsx index dbfa05b..2fda9c7 100644 --- a/apps/web-antdv-next/src/views/qqbot/account/list.tsx +++ b/apps/web-antdv-next/src/views/qqbot/account/list.tsx @@ -529,9 +529,6 @@ export default defineComponent({ }); } - /** - * Opens the route that will own the NapCat WebUI session lifecycle. - */ function openNapcatWebui(row: QqbotApi.Account) { void router.push({ name: 'QqBotAccountNapcatWebui', diff --git a/apps/web-antdv-next/src/views/qqbot/account/napcat-boundary.spec.ts b/apps/web-antdv-next/src/views/qqbot/account/napcat-boundary.spec.ts index 0056e9a..9e04100 100644 --- a/apps/web-antdv-next/src/views/qqbot/account/napcat-boundary.spec.ts +++ b/apps/web-antdv-next/src/views/qqbot/account/napcat-boundary.spec.ts @@ -12,18 +12,9 @@ const accountRoot = resolve( const readAccountSource = (relativePath: string) => readFileSync(resolve(accountRoot, relativePath), 'utf8'); -/** - * Reads repository-root files that define browser-facing deployment boundaries. - * - * @param relativePath - Repository-relative path to read. - * @returns Source text for boundary assertions. - */ const readRepoSource = (relativePath: string) => readFileSync(resolve(cwd(), relativePath), 'utf8'); -/** - * Reads QQBot router module source for route boundary assertions. - */ const readRouteSource = (relativePath: string) => readFileSync( resolve( diff --git a/apps/web-antdv-next/src/views/qqbot/account/napcat-webui/index.tsx b/apps/web-antdv-next/src/views/qqbot/account/napcat-webui/index.tsx index d0f855f..2649b0c 100644 --- a/apps/web-antdv-next/src/views/qqbot/account/napcat-webui/index.tsx +++ b/apps/web-antdv-next/src/views/qqbot/account/napcat-webui/index.tsx @@ -19,9 +19,6 @@ const ATag = Tag as any; export default defineComponent({ name: 'QqBotAccountNapcatWebui', - /** - * Wires route account identity to the page-owned NapCat WebUI session. - */ setup() { const route = useRoute(); const router = useRouter(); @@ -48,32 +45,18 @@ export default defineComponent({ { immediate: true }, ); - /** - * Navigates back to the account list route. - */ function goBack() { void router.push({ name: 'QqBotAccount' }); } - /** - * Reopens the gateway session for the current route account. - */ function reopen() { void session.open(); } - /** - * Closes the current gateway session while staying on this page. - */ function closeSession() { void session.revoke(); } - /** - * Renders the floating metadata panel without taking layout space from the iframe. - * - * @returns Overlay card content for the current session metadata and actions. - */ const renderFloatingCard = () => { return (
@@ -114,11 +97,6 @@ export default defineComponent({ ); }; - /** - * Renders the main state area for loading, error, revoked, and ready states. - * - * @returns TSX content for the current gateway state. - */ const renderBody = () => { if (session.state.value === 'ready' && session.iframeUrl.value) { return ( @@ -161,11 +139,6 @@ export default defineComponent({ ); }; - /** - * Renders the page root required by Vben route transitions. - * - * @returns The stable single-root page shell. - */ const renderPage = () => { return (
@@ -181,23 +154,11 @@ export default defineComponent({ }, }); -/** - * Normalizes a vue-router route param into a single trimmed account id. - * - * @param value - Raw route param value. - * @returns Trimmed account id or an empty string. - */ function normalizeRouteParam(value: unknown) { if (Array.isArray(value)) return `${value[0] || ''}`.trim(); return `${value || ''}`.trim(); } -/** - * Formats the gateway expiry timestamp for compact page metadata. - * - * @param value - Epoch milliseconds returned by the Gateway heartbeat. - * @returns Local date-time text, or an empty string when the value is absent. - */ function formatGatewayExpiresAt(value?: number) { if (!value) return ''; const date = new Date(value); @@ -210,12 +171,6 @@ function formatGatewayExpiresAt(value?: number) { )}`; } -/** - * Maps gateway state to a compact Ant Design status tag. - * - * @param state - Current gateway lifecycle state. - * @returns Tag color and Chinese label for the page header. - */ function getStatusMeta(state: NapcatWebuiGatewaySessionState) { const statusMap = { error: { color: 'error', label: '异常' }, diff --git a/apps/web-antdv-next/src/views/qqbot/account/napcat-webui/napcat-webui.spec.tsx b/apps/web-antdv-next/src/views/qqbot/account/napcat-webui/napcat-webui.spec.tsx index cbfb42f..a15b13a 100644 --- a/apps/web-antdv-next/src/views/qqbot/account/napcat-webui/napcat-webui.spec.tsx +++ b/apps/web-antdv-next/src/views/qqbot/account/napcat-webui/napcat-webui.spec.tsx @@ -134,12 +134,6 @@ vi.mock('#/api/qqbot/napcat', () => ({ revokeQqbotNapcatWebuiSession: vi.fn(), })); -/** - * Creates a mocked gateway session payload for page lifecycle tests. - * - * @param overrides - Partial fields that should replace the default fixture. - * @returns A gateway session payload shaped like the backend response. - */ function createSessionFixture(overrides = {}) { return { account: { diff --git a/apps/web-antdv-next/src/views/qqbot/account/napcat-webui/useNapcatWebuiGatewaySession.ts b/apps/web-antdv-next/src/views/qqbot/account/napcat-webui/useNapcatWebuiGatewaySession.ts index 4caaa0e..69ad86a 100644 --- a/apps/web-antdv-next/src/views/qqbot/account/napcat-webui/useNapcatWebuiGatewaySession.ts +++ b/apps/web-antdv-next/src/views/qqbot/account/napcat-webui/useNapcatWebuiGatewaySession.ts @@ -19,12 +19,6 @@ export type NapcatWebuiGatewaySessionState = | 'ready' | 'revoked'; -/** - * Owns one NapCat WebUI gateway session for the current account page lifetime. - * - * @param accountId - Reactive account id read from the route. - * @returns Reactive gateway session state and lifecycle actions. - */ export function useNapcatWebuiGatewaySession(accountId: Ref) { const account = ref(); const container = ref(); @@ -42,11 +36,6 @@ export function useNapcatWebuiGatewaySession(accountId: Ref) { onBeforeUnmount(handleBeforeUnmount); - /** - * Opens a new gateway session after revoking any existing local session. - * - * @returns A promise that settles after the open attempt finishes. - */ async function open() { const nextAccountId = accountId.value.trim(); heartbeat.pause(); @@ -89,11 +78,6 @@ export function useNapcatWebuiGatewaySession(accountId: Ref) { } } - /** - * Revokes the current gateway session and clears local iframe credentials. - * - * @returns A promise that settles after local state has been cleared. - */ async function revoke() { openToken += 1; heartbeat.pause(); @@ -118,11 +102,6 @@ export function useNapcatWebuiGatewaySession(accountId: Ref) { } } - /** - * Sends one heartbeat for the active ready session and updates its expiry. - * - * @returns A promise that settles after the heartbeat attempt finishes. - */ async function sendHeartbeat() { const currentSessionId = sessionId.value; if (state.value !== 'ready' || !currentSessionId) return; @@ -142,11 +121,6 @@ export function useNapcatWebuiGatewaySession(accountId: Ref) { } } - /** - * Applies the gateway session payload returned by the backend. - * - * @param result - Gateway session payload containing iframe URL and metadata. - */ function applyGatewaySession(result: QqbotNapcatApi.WebuiGatewaySession) { account.value = result.account; container.value = result.container; @@ -155,9 +129,6 @@ export function useNapcatWebuiGatewaySession(accountId: Ref) { sessionId.value = result.sessionId; } - /** - * Clears all local data that can keep a gateway session reachable. - */ function clearGatewaySession() { account.value = undefined; container.value = undefined; @@ -166,12 +137,6 @@ export function useNapcatWebuiGatewaySession(accountId: Ref) { sessionId.value = ''; } - /** - * Revokes a session created after this composable was already invalidated. - * - * @param staleSessionId - Session id returned by an outdated open request. - * @returns A promise that ignores revoke failures because the page is leaving. - */ async function revokeDetachedSession(staleSessionId: string) { try { await revokeQqbotNapcatWebuiSession(staleSessionId); @@ -180,9 +145,6 @@ export function useNapcatWebuiGatewaySession(accountId: Ref) { } } - /** - * Marks the composable disposed and starts best-effort session revocation. - */ function handleBeforeUnmount() { disposed = true; void revoke(); @@ -201,13 +163,6 @@ export function useNapcatWebuiGatewaySession(accountId: Ref) { }; } -/** - * Extracts a user-facing error message from unknown rejection values. - * - * @param error - Unknown error thrown by the request client. - * @param fallback - Message to show when the error has no readable text. - * @returns A Chinese or backend-provided message for page alerts. - */ function getErrorMessage(error: unknown, fallback: string) { if (error instanceof Error && error.message) return error.message; if (typeof error === 'string' && error.trim()) return error.trim(); diff --git a/apps/web-antdv-next/src/views/qqbot/account/napcat/NapcatRuntimeProfileDrawer.tsx b/apps/web-antdv-next/src/views/qqbot/account/napcat/NapcatRuntimeProfileDrawer.tsx index 3395c5b..59a2ab2 100644 --- a/apps/web-antdv-next/src/views/qqbot/account/napcat/NapcatRuntimeProfileDrawer.tsx +++ b/apps/web-antdv-next/src/views/qqbot/account/napcat/NapcatRuntimeProfileDrawer.tsx @@ -39,9 +39,6 @@ export default defineComponent({ { immediate: true }, ); - /** - * Loads sanitized runtime profile evidence for the selected account. - */ async function loadDetail() { if (!props.account?.id) return; loading.value = true; @@ -52,19 +49,11 @@ export default defineComponent({ } } - /** - * Emits both drawer close contracts used by existing QQBot views. - */ function closeDrawer() { emit('update:open', false); emit('close'); } - /** - * Renders compact key/value evidence rows without exposing interactive controls. - * @param label - Human readable field label. - * @param value - Runtime evidence value already sanitized by the API. - */ const renderField = (label: string, value: unknown) => { return (
@@ -74,11 +63,6 @@ export default defineComponent({ ); }; - /** - * Renders a JSON evidence block for profile sections. - * @param title - Section title shown above the evidence block. - * @param value - Sanitized profile object returned by the API. - */ const renderJsonBlock = (title: string, value: unknown) => { if (!value) return null; return ( @@ -91,11 +75,6 @@ export default defineComponent({ ); }; - /** - * Converts scalar runtime evidence into stable display text. - * @param value - Sanitized value from profile detail. - * @returns Display text for compact rows. - */ function formatValue(value: unknown) { if (value === undefined || value === null || value === '') return '-'; if (typeof value === 'object') return JSON.stringify(value); diff --git a/apps/web-antdv-next/src/views/qqbot/message-subscription/list.spec.tsx b/apps/web-antdv-next/src/views/qqbot/message-subscription/list.spec.tsx index 30c81d9..fadf965 100644 --- a/apps/web-antdv-next/src/views/qqbot/message-subscription/list.spec.tsx +++ b/apps/web-antdv-next/src/views/qqbot/message-subscription/list.spec.tsx @@ -30,11 +30,9 @@ const mocks = vi.hoisted(() => { }, tableOptions: undefined as any, }; - /** Installs the list path only when the rendered KtTable emits registration. */ state.registerTable.mockImplementation(() => { state.registeredTableOptions = state.tableOptions; }); - /** Reloads through the registered table options and returns the caller result. */ state.tableApi.reload.mockImplementation(async () => { if (!state.registeredTableOptions) { throw new Error('[MockKtTable]: table is not registered yet.'); @@ -58,7 +56,6 @@ vi.mock('@vben/common-ui', () => ({ Page: defineComponent({ name: 'MockPage', props: { autoContentHeight: Boolean }, - /** Renders a stable marker exposing the root height contract. */ setup(props, { slots }) { return () => h( @@ -76,7 +73,6 @@ vi.mock('@vben/common-ui', () => ({ vi.mock('antdv-next', () => ({ Tag: defineComponent({ name: 'MockTag', - /** Renders enabled-state tag text for the body-cell contract. */ setup(_, { slots }) { return () => h('span', slots.default?.()); }, @@ -87,7 +83,6 @@ vi.mock('#/components/ktTable', () => ({ KtTable: defineComponent({ name: 'MockKtTable', emits: ['register'], - /** Registers the table boundary before rendering its explicit refresh control. */ setup(_, { emit, slots }) { emit('register', {}); return () => @@ -117,7 +112,6 @@ vi.mock('./components/MessageSubscriptionModal', () => ({ default: defineComponent({ name: 'MockMessageSubscriptionModal', emits: ['saved'], - /** Exposes create/edit commands and one deterministic saved trigger. */ setup(_, { emit, expose }) { expose({ openCreate: mocks.modalOpenCreate, @@ -144,7 +138,6 @@ vi.mock('#/api/qqbot/message-push', () => ({ setMessageSubscriptionEnabled: mocks.api.toggle, })); -/** Creates one table row whose identifiers exceed JavaScript's safe integer. */ function createRow(): QqbotMessagePushApi.MessageSubscriptionView { return { createTime: '2026-07-24 10:00:00', diff --git a/apps/web-antdv-next/src/views/qqbot/message-subscription/list.tsx b/apps/web-antdv-next/src/views/qqbot/message-subscription/list.tsx index b7cb706..ce121e9 100644 --- a/apps/web-antdv-next/src/views/qqbot/message-subscription/list.tsx +++ b/apps/web-antdv-next/src/views/qqbot/message-subscription/list.tsx @@ -33,9 +33,6 @@ const AKtTable = KtTable as any; export default defineComponent({ name: 'QqBotMessageSubscriptionList', - /** - * Owns the permission-gated subscription table, metadata cache, and row reloads. - */ setup() { const { hasAccessByCodes } = useAccess(); const canList = hasAccessByCodes(['QqBot:MessageSubscription:List']); @@ -85,7 +82,6 @@ export default defineComponent({ }, ]; const api: KtTableApi = { - /** Passes the caller's strict `{ items, total }` page through unchanged. */ list: async (params) => await getMessageSubscriptionList(params), }; const buttons: Array< @@ -170,35 +166,20 @@ export default defineComponent({ tableTitle: '消息订阅', }); - /** Opens a blank modal session through the page-owned exposed ref. */ function openCreate() { modalRef.value?.openCreate(); } - /** - * Opens one row without copying page-only runtime state into the modal. - * @param row - Subscription selected from KtTable. - */ function openEdit(row: QqbotMessagePushApi.MessageSubscriptionView) { modalRef.value?.openEdit(row); } - /** - * Builds KtTable's delete confirmation text for one subscription. - * @param row - Subscription awaiting delete confirmation. - * @returns Human-readable confirmation text containing the row name. - */ function getDeleteConfirm( row: QqbotMessagePushApi.MessageSubscriptionView, ) { return `确认删除消息订阅「${row.name}」吗?`; } - /** - * Toggles one row and reloads only that table context after success. - * @param row - Subscription whose enabled state is inverted. - * @param context - KtTable row-action context owning the list reload. - */ async function handleToggle( row: QqbotMessagePushApi.MessageSubscriptionView, context: KtTableContext, @@ -207,11 +188,6 @@ export default defineComponent({ await context.reload(); } - /** - * Deletes one row and reloads only that table context after success. - * @param row - Subscription confirmed through KtTable's action system. - * @param context - KtTable row-action context owning the list reload. - */ async function handleDelete( row: QqbotMessagePushApi.MessageSubscriptionView, context: KtTableContext, @@ -220,12 +196,10 @@ export default defineComponent({ await context.reload(); } - /** Reloads the mutable list exactly once after a successful modal save. */ async function handleModalSaved() { await tableApi.reload(); } - /** Loads immutable source metadata once for the authorized page mount. */ async function loadMetadata() { const [nextSources, nextStunOptions] = await Promise.all([ getMessagePushSources(), @@ -235,19 +209,11 @@ export default defineComponent({ stunOptions.value = nextStunOptions; } - /** Starts the single authorized list and metadata load for this mount. */ async function activatePage() { if (!canList) return; await Promise.all([tableApi.reload(), loadMetadata()]); } - /** - * Renders source, status, and empty-value presentation for data columns. - * @param slot - KtTable body-cell slot payload. - * @param slot.column - Column whose custom presentation is requested. - * @param slot.record - Subscription row rendered by the table. - * @returns Custom cell content or undefined for native field rendering. - */ function renderBodyCell(slot: { column: TableColumnType; record: QqbotMessagePushApi.MessageSubscriptionView; diff --git a/apps/web-antdv-next/src/views/qqbot/message-template/components/MessageTemplateMentions.spec.tsx b/apps/web-antdv-next/src/views/qqbot/message-template/components/MessageTemplateMentions.spec.tsx index b7c4dc1..f93d0fc 100644 --- a/apps/web-antdv-next/src/views/qqbot/message-template/components/MessageTemplateMentions.spec.tsx +++ b/apps/web-antdv-next/src/views/qqbot/message-template/components/MessageTemplateMentions.spec.tsx @@ -11,7 +11,6 @@ import { describe, expect, it } from 'vitest'; import MessageTemplateMentions from './MessageTemplateMentions'; -/** Creates one complete source-variable fixture for Mentions behavior. */ function createVariable( overrides: Partial = {}, ): QqbotMessagePushApi.SystemMessageSourceVariableDefinition { diff --git a/apps/web-antdv-next/src/views/qqbot/message-template/components/MessageTemplateMentions.tsx b/apps/web-antdv-next/src/views/qqbot/message-template/components/MessageTemplateMentions.tsx index be69737..6f84fa7 100644 --- a/apps/web-antdv-next/src/views/qqbot/message-template/components/MessageTemplateMentions.tsx +++ b/apps/web-antdv-next/src/views/qqbot/message-template/components/MessageTemplateMentions.tsx @@ -35,16 +35,9 @@ export default defineComponent({ }, }, emits: { - /** - * Keeps the wrapper controlled and forwards only the complete plain-text value. - * @param value - Mentions textarea content after an explicit user update. - * @returns Always true because string payloads are the only supported update. - */ 'update:value': (value: string) => typeof value === 'string', }, - /** Creates a request-free controlled boundary around the installed Mentions. */ setup(props, { emit }) { - /** Maps server variables to the exact `{{key}}` values required after `$`. */ const options = computed(() => props.variables.map((variable) => ({ label: `${variable.key} · ${variable.label} · ${variable.description} · 示例:${variable.example}`, @@ -53,12 +46,6 @@ export default defineComponent({ })), ); - /** - * Filters one option across the four server-owned variable descriptors. - * @param input - Case-insensitive query entered after the `$` prefix. - * @param option - Mentions option carrying the original variable definition. - * @returns Whether key, label, description, or example includes the query. - */ function filterVariableOption( input: string, option: Record, @@ -74,10 +61,6 @@ export default defineComponent({ ].some((field) => field.toLocaleLowerCase().includes(query)); } - /** - * Emits the installed component's controlled value without interpreting its text. - * @param value - Literal textarea value, including CQ-looking substrings. - */ function handleValueUpdate(value: string) { emit('update:value', value); } @@ -99,11 +82,6 @@ export default defineComponent({ }, }); -/** - * Narrows an unknown Mentions option payload to the server variable contract. - * @param value - Candidate option metadata supplied by the installed component. - * @returns Whether all searchable variable fields are strings. - */ function isVariableDefinition( value: unknown, ): value is QqbotMessagePushApi.SystemMessageSourceVariableDefinition { diff --git a/apps/web-antdv-next/src/views/qqbot/message-template/list.spec.tsx b/apps/web-antdv-next/src/views/qqbot/message-template/list.spec.tsx index 2f366d1..8f4d5f8 100644 --- a/apps/web-antdv-next/src/views/qqbot/message-template/list.spec.tsx +++ b/apps/web-antdv-next/src/views/qqbot/message-template/list.spec.tsx @@ -50,7 +50,6 @@ vi.mock('@vben/common-ui', () => ({ Page: defineComponent({ name: 'MockPage', props: { autoContentHeight: Boolean }, - /** Renders one stable route root and exposes the height contract. */ setup(props, { slots }) { return () => h( @@ -72,7 +71,6 @@ vi.mock('@vben/icons', () => ({ vi.mock('antdv-next/dist/tag/index', () => ({ default: defineComponent({ name: 'MockTag', - /** Renders tag children as ordinary escaped text. */ setup(_, { slots }) { return () => h('span', slots.default?.()); }, @@ -92,7 +90,6 @@ vi.mock('#/components/ktTable', () => ({ KtTable: defineComponent({ name: 'MockKtTable', emits: ['register'], - /** Emits the actual registration event before exposing refresh/list rendering. */ setup(_, { emit, slots }) { emit('register', { registered: true }); return () => @@ -132,7 +129,6 @@ vi.mock('./components/MessageTemplateModal', () => ({ }, }, emits: ['saved'], - /** Exposes create/edit and a saved trigger through the rendered modal marker. */ setup(props, { emit, expose }) { expose({ openCreate: mocks.modalOpenCreate, @@ -152,7 +148,6 @@ vi.mock('./components/MessageTemplateModal', () => ({ }), })); -/** Creates one template row while preserving unsafe-integer IDs as strings. */ function createRow( overrides: Partial = {}, ): QqbotMessagePushApi.MessageTemplateView { @@ -171,7 +166,6 @@ function createRow( }; } -/** Creates the page-lifetime source directory fixture. */ function createSources(): QqbotMessagePushApi.SystemMessageSourceDefinition[] { return [ { diff --git a/apps/web-antdv-next/src/views/qqbot/message-template/list.tsx b/apps/web-antdv-next/src/views/qqbot/message-template/list.tsx index e3650d3..f237882 100644 --- a/apps/web-antdv-next/src/views/qqbot/message-template/list.tsx +++ b/apps/web-antdv-next/src/views/qqbot/message-template/list.tsx @@ -32,7 +32,6 @@ const AKtTable = KtTable as any; export default defineComponent({ name: 'QqBotMessageTemplateList', - /** Owns the permission-gated template list, source labels, and row mutations. */ setup() { const { hasAccessByCodes } = useAccess(); const canList = hasAccessByCodes(['QqBot:MessageTemplate:List']); @@ -62,7 +61,6 @@ export default defineComponent({ }, ]; const api: KtTableApi = { - /** Passes the caller's strict `{ items, total }` page through unchanged. */ list: async (params) => await getMessageTemplateList(params), }; const buttons: Array< @@ -149,33 +147,18 @@ export default defineComponent({ tableTitle: '消息模板', }); - /** Opens a blank template session through the page-owned exposed ref. */ function openCreate() { modalRef.value?.openCreate(); } - /** - * Opens one row without copying page-only runtime state into the modal. - * @param row - Template selected from KtTable. - */ function openEdit(row: QqbotMessagePushApi.MessageTemplateView) { modalRef.value?.openEdit(row); } - /** - * Builds KtTable confirmation for one currently unreferenced template. - * @param row - Template awaiting delete confirmation. - * @returns Confirmation text containing the template name. - */ function getDeleteConfirm(row: QqbotMessagePushApi.MessageTemplateView) { return `确认删除消息模板「${row.name}」吗?`; } - /** - * Explains why a referenced template cannot be deleted from the current row. - * @param row - Template whose current reference count controls the action. - * @returns Count-bearing reason, or undefined when delete is enabled. - */ function getDeleteDisabledReason( row: QqbotMessagePushApi.MessageTemplateView, ) { @@ -184,11 +167,6 @@ export default defineComponent({ : undefined; } - /** - * Toggles one row and reloads only its KtTable context after success. - * @param row - Template whose enabled state is inverted. - * @param context - Row-action context owning the affected list. - */ async function handleToggle( row: QqbotMessagePushApi.MessageTemplateView, context: KtTableContext, @@ -197,11 +175,6 @@ export default defineComponent({ await context.reload(); } - /** - * Deletes one row and reloads only its KtTable context after success. - * @param row - Unreferenced template confirmed through KtTable. - * @param context - Row-action context owning the affected list. - */ async function handleDelete( row: QqbotMessagePushApi.MessageTemplateView, context: KtTableContext, @@ -210,29 +183,19 @@ export default defineComponent({ await context.reload(); } - /** Reloads the mutable list exactly once after one successful modal save. */ async function handleModalSaved() { await tableApi.reload(); } - /** Loads the page-lifetime source directory once for an authorized mount. */ async function loadSources() { sources.value = await getMessagePushSources(); } - /** Starts the only automatic list/source load for this route mount. */ async function activatePage() { if (!canList) return; await Promise.all([tableApi.reload(), loadSources()]); } - /** - * Renders source, literal content summary, and enabled presentation. - * @param slot - KtTable body-cell payload. - * @param slot.column - Column requesting a custom presentation. - * @param slot.record - Template row rendered by the table. - * @returns Escaped text/status content or undefined for native rendering. - */ function renderBodyCell(slot: { column: TableColumnType; record: QqbotMessagePushApi.MessageTemplateView; diff --git a/apps/web-antdv-next/src/views/qqbot/permission/list.tsx b/apps/web-antdv-next/src/views/qqbot/permission/list.tsx index 532bd01..a064d44 100644 --- a/apps/web-antdv-next/src/views/qqbot/permission/list.tsx +++ b/apps/web-antdv-next/src/views/qqbot/permission/list.tsx @@ -412,9 +412,6 @@ export default defineComponent({ }; } - /** - * 渲染 KtTable 表头控制区。 - */ const renderHeaderControls = () => { return ( <> @@ -439,9 +436,6 @@ export default defineComponent({ ); }; - /** - * 渲染 KtTable 按钮区里的权限过滤模式。 - */ const renderPermissionModeToolbar = () => { return (
diff --git a/apps/web-antdv-next/src/views/qqbot/plugin-task/components/TaskRunDrawer.tsx b/apps/web-antdv-next/src/views/qqbot/plugin-task/components/TaskRunDrawer.tsx index f0538bf..3140322 100644 --- a/apps/web-antdv-next/src/views/qqbot/plugin-task/components/TaskRunDrawer.tsx +++ b/apps/web-antdv-next/src/views/qqbot/plugin-task/components/TaskRunDrawer.tsx @@ -42,9 +42,6 @@ export default defineComponent({ { immediate: true }, ); - /** - * Loads the latest task run records for the selected plugin task drawer. - */ async function loadRuns() { if (!props.task?.id) return; loading.value = true; @@ -59,11 +56,6 @@ export default defineComponent({ } } - /** - * Renders one scheduled-task execution record with themed evidence blocks. - * - * @param item - Task run row returned by the plugin task API. - */ const renderRun = (item: QqbotPluginTaskApi.TaskRun) => (
diff --git a/apps/web-antdv-next/src/views/qqbot/plugin/components/PluginPlatformStateDrawer.tsx b/apps/web-antdv-next/src/views/qqbot/plugin/components/PluginPlatformStateDrawer.tsx index 45188fd..f91fef0 100644 --- a/apps/web-antdv-next/src/views/qqbot/plugin/components/PluginPlatformStateDrawer.tsx +++ b/apps/web-antdv-next/src/views/qqbot/plugin/components/PluginPlatformStateDrawer.tsx @@ -43,11 +43,6 @@ export default defineComponent({ }, emits: ['close', 'installationAction'], setup(props, { emit }) { - /** - * Maps plugin platform status values to readable themed status tags. - * - * @param status - Runtime, binding, or installation status from the API. - */ const renderStatusTag = (status?: string) => { if (!status) return -; const color = @@ -55,9 +50,6 @@ export default defineComponent({ return {getQqbotStatusLabel(status)}; }; - /** - * Renders recent runtime events with safe summaries for diagnosis. - */ const renderEvents = () => props.runtimeEvents.length > 0 ? (
@@ -79,9 +71,6 @@ export default defineComponent({ 暂无运行事件 ); - /** - * Renders account-to-plugin binding rows for the selected platform state. - */ const renderBindings = () => props.accountBindings.length > 0 ? (
@@ -98,9 +87,6 @@ export default defineComponent({ 暂无账号绑定 ); - /** - * Renders installed plugin rows and exposes safe lifecycle actions. - */ const renderInstallations = () => props.installations.length > 0 ? (
@@ -140,9 +126,6 @@ export default defineComponent({ 暂无安装记录 ); - /** - * Selects the drawer body according to the active platform state tab. - */ const renderContent = () => { if (props.mode === 'events') return renderEvents(); if (props.mode === 'bindings') return renderBindings(); diff --git a/apps/web-antdv-next/src/views/system/network/components/NetworkDdnsRecordModal.spec.tsx b/apps/web-antdv-next/src/views/system/network/components/NetworkDdnsRecordModal.spec.tsx index 578f232..80bed27 100644 --- a/apps/web-antdv-next/src/views/system/network/components/NetworkDdnsRecordModal.spec.tsx +++ b/apps/web-antdv-next/src/views/system/network/components/NetworkDdnsRecordModal.spec.tsx @@ -41,7 +41,6 @@ const mocks = vi.hoisted(() => { }; }); -/** Creates a fluent no-op validation rule for the form-schema fixture. */ function createRule(): any { const rule: any = {}; for (const method of [ @@ -110,7 +109,6 @@ vi.mock('#/locales', () => ({ $t: (key: string) => key, })); -/** Builds one server-returned DDNS row with a Snowflake string ID. */ function createDdnsRow( overrides: Partial = {}, ): SystemNetworkApi.DdnsRecord { diff --git a/apps/web-antdv-next/src/views/system/network/components/NetworkDdnsRecordModal.tsx b/apps/web-antdv-next/src/views/system/network/components/NetworkDdnsRecordModal.tsx index b4582f8..30f4302 100644 --- a/apps/web-antdv-next/src/views/system/network/components/NetworkDdnsRecordModal.tsx +++ b/apps/web-antdv-next/src/views/system/network/components/NetworkDdnsRecordModal.tsx @@ -43,9 +43,6 @@ const dnsLabelPattern = /^[a-z\d](?:[a-z\d-]{0,61}[a-z\d])?$/i; export default defineComponent({ name: 'NetworkDdnsRecordModal', emits: ['saved'], - /** - * Owns the dual-stack DDNS CRUD form while keeping provider details server-side. - */ setup(_, { emit, expose }) { const editingRow = ref(); const recordType = ref('A'); @@ -55,11 +52,6 @@ export default defineComponent({ commonConfig: { labelClass: 'w-24', }, - /** - * Replaces address-family sources immediately without retaining a stale mapping ID. - * @param values - Current form values after the field update. - * @param fieldsChanged - Field names changed in this form event. - */ async handleValuesChange(values, fieldsChanged) { if (!fieldsChanged.includes('recordType')) return; const nextRecordType = @@ -97,10 +89,6 @@ export default defineComponent({ async onConfirm() { await submit(); }, - /** - * Restores form state only after destroy-on-close content has mounted. - * @param isOpen - Whether the modal content is now visible. - */ async onOpenChange(isOpen: boolean) { if (!isOpen) return; const { values } = modalApi.getData(); @@ -113,7 +101,6 @@ export default defineComponent({ }, }); - /** Opens a blank IPv4 DDNS form without provider or credential fields. */ function openCreate() { editingRow.value = undefined; recordType.value = 'A'; @@ -133,10 +120,6 @@ export default defineComponent({ .open(); } - /** - * Opens one record with only the editable DDNS contract copied into the form. - * @param row - Persisted DDNS row selected from KtTable. - */ function openEdit(row: SystemNetworkApi.DdnsRecord) { editingRow.value = row; recordType.value = row.recordType; @@ -159,20 +142,12 @@ export default defineComponent({ .open(); } - /** - * Resets validation and installs only user-editable values. - * @param values - Modal session values excluding provider/runtime state. - */ async function resetForm(values: Partial) { await formApi.resetForm(); await formApi.setValues(values); await formApi.resetValidate(); } - /** - * Loads sources for the selected family while dropping stale response races. - * @param nextRecordType - Address family whose sources the server must evaluate. - */ async function loadSourceOptions( nextRecordType: SystemNetworkApi.DdnsRecordType, ) { @@ -187,7 +162,6 @@ export default defineComponent({ sourceOptions.value = result.items; } - /** Persists one normalized A/AAAA binding and leaves provider work asynchronous. */ async function submit() { const { valid } = await formApi.validate(); if (!valid) return; @@ -245,11 +219,6 @@ export default defineComponent({ }, }); -/** - * Builds the approved dual-stack DDNS form schema without provider credentials. - * @param sourceOptions - Reactive API-owned source choices used by the IPv4 select. - * @returns Vben form fields for record identity, family, source and local behavior. - */ function createFormSchema( sourceOptions: Readonly<{ value: SystemNetworkApi.DdnsSourceOption[]; @@ -333,11 +302,6 @@ function createFormSchema( ]; } -/** - * Formats one server-evaluated source without making eligibility decisions locally. - * @param source - Source option returned by the API. - * @returns Ant Design Select option with a stable string ID and disabled reason. - */ function formatSourceOption(source: SystemNetworkApi.DdnsSourceOption) { const endpoint = source.protocol && source.externalPort @@ -355,22 +319,12 @@ function formatSourceOption(source: SystemNetworkApi.DdnsSourceOption) { }; } -/** - * Formats a stable server reason code without inventing source eligibility rules. - * @param reasonCode - Optional API reason code for an ineligible source. - * @returns Localized prefix plus the stable code for diagnostics. - */ function formatSourceDisabledReason(reasonCode?: null | string): string { return reasonCode ? `${$t('system.network.ddnsSourceUnavailable')}: ${reasonCode}` : $t('system.network.ddnsSourceUnavailable'); } -/** - * Validates a DNSPod zone as ASCII DNS labels with no URL or port syntax. - * @param value - Candidate zone name. - * @returns True only for a normalized multi-label DNS zone. - */ export function isValidDdnsDomain(value: string): boolean { const normalized = value.trim(); if ( @@ -383,11 +337,6 @@ export function isValidDdnsDomain(value: string): boolean { return normalized.split('.').every((label) => dnsLabelPattern.test(label)); } -/** - * Validates an A/AAAA host record, including DNSPod's root-record marker. - * @param value - Candidate host record. - * @returns True for `@` or one or more valid ASCII DNS labels. - */ export function isValidDdnsSubDomain(value: string): boolean { const normalized = value.trim(); if (normalized === '@') return true; diff --git a/apps/web-antdv-next/src/views/system/network/components/NetworkDdnsTable.spec.tsx b/apps/web-antdv-next/src/views/system/network/components/NetworkDdnsTable.spec.tsx index 6fe386a..8559c55 100644 --- a/apps/web-antdv-next/src/views/system/network/components/NetworkDdnsTable.spec.tsx +++ b/apps/web-antdv-next/src/views/system/network/components/NetworkDdnsTable.spec.tsx @@ -101,7 +101,6 @@ vi.mock('#/locales', () => ({ $t: (key: string) => key, })); -/** Builds one dual-stack-capable DDNS table fixture. */ function createDdnsRow( overrides: Partial = {}, ): SystemNetworkApi.DdnsRecord { diff --git a/apps/web-antdv-next/src/views/system/network/components/NetworkDdnsTable.tsx b/apps/web-antdv-next/src/views/system/network/components/NetworkDdnsTable.tsx index d3a3383..1ed9a4a 100644 --- a/apps/web-antdv-next/src/views/system/network/components/NetworkDdnsTable.tsx +++ b/apps/web-antdv-next/src/views/system/network/components/NetworkDdnsTable.tsx @@ -66,9 +66,6 @@ export interface NetworkDdnsTableExposed { export default defineComponent({ name: 'NetworkDdnsTable', - /** - * Owns the independent DDNS KtTable while the route page owns SSE and active-tab refresh. - */ setup(_, { expose }) { const busyRowIds = ref>(new Set()); const modalRef = ref(); @@ -116,11 +113,6 @@ export default defineComponent({ }, ]; const api: KtTableApi = { - /** - * Loads the latest persisted DDNS fact page. - * @param params - KtTable pagination and search values. - * @returns Server-owned DDNS rows and total. - */ list: async (params) => await getNetworkDdnsList(params), }; const buttons: Array> = [ @@ -217,30 +209,18 @@ export default defineComponent({ tableTitle: $t('system.network.ddnsTitle'), }); - /** Opens the blank dual-stack DDNS modal. */ function openCreate() { modalRef.value?.openCreate(); } - /** - * Opens one DDNS record unless another mutation owns its row. - * @param row - Persisted DDNS record. - */ function openEdit(row: SystemNetworkApi.DdnsRecord) { if (!isRowBusy(row)) modalRef.value?.openEdit(row); } - /** Refreshes the table after a successful modal save. */ function handleModalSaved() { void reload(); } - /** - * Runs one DDNS mutation with per-row duplicate suppression. - * @param row - Selected persisted record. - * @param mutation - API operation accepting the stable record ID. - * @param successMessage - Accurate asynchronous-success wording. - */ async function runRowMutation( row: SystemNetworkApi.DdnsRecord, mutation: (id: string) => Promise, @@ -257,11 +237,6 @@ export default defineComponent({ } } - /** - * Replaces the reactive in-flight set instead of mutating it in place. - * @param id - Stable DDNS record ID. - * @param busy - Whether this row currently owns a write. - */ function setRowBusy(id: string, busy: boolean) { const next = new Set(busyRowIds.value); if (busy) next.add(id); @@ -269,16 +244,10 @@ export default defineComponent({ busyRowIds.value = next; } - /** - * Returns whether one row already owns a write request. - * @param row - Persisted DDNS record. - * @returns True while a mutation is in flight. - */ function isRowBusy(row: SystemNetworkApi.DdnsRecord): boolean { return busyRowIds.value.has(row.id); } - /** Loads redacted provider readiness without translating failure into disabled. */ async function loadProviderStatus() { try { providerStatus.value = await getNetworkDdnsProviderStatus(); @@ -288,14 +257,10 @@ export default defineComponent({ } } - /** - * Reloads only DDNS-owned data when requested by the route or a local mutation. - */ async function reload(): Promise { await Promise.allSettled([tableApi.reload(), loadProviderStatus()]); } - /** Renders provider readiness without exposing credential values. */ function renderProviderStatus() { const status = providerStatus.value; let color = 'warning'; @@ -316,13 +281,6 @@ export default defineComponent({ ); } - /** - * Renders dual-stack DDNS cells using only API-returned address and FQDN facts. - * @param cell - KtTable body-cell slot context. - * @param cell.column - Current table column. - * @param cell.record - Current DDNS record. - * @returns Cell content or undefined for default rendering. - */ function renderBodyCell({ column, record }: any) { const row = record as SystemNetworkApi.DdnsRecord; if (column.key === 'identity') { @@ -389,11 +347,6 @@ export default defineComponent({ }, }); -/** - * Resolves whether retry is unsafe without hiding the action. - * @param row - Persisted DDNS record with server-evaluated source eligibility. - * @returns Exact disabled reason, or undefined when retry is allowed. - */ export function getDdnsRetryDisabledReason( row: SystemNetworkApi.DdnsRecord, ): string | undefined { diff --git a/apps/web-antdv-next/src/views/system/network/components/NetworkEndpointHistoryDrawer.spec.tsx b/apps/web-antdv-next/src/views/system/network/components/NetworkEndpointHistoryDrawer.spec.tsx index cd98cb2..a33c581 100644 --- a/apps/web-antdv-next/src/views/system/network/components/NetworkEndpointHistoryDrawer.spec.tsx +++ b/apps/web-antdv-next/src/views/system/network/components/NetworkEndpointHistoryDrawer.spec.tsx @@ -62,7 +62,6 @@ vi.mock('#/locales', () => ({ $t: (key: string) => key, })); -/** Creates the minimal row needed to scope a history request. */ function createRow(id: string): SystemNetworkApi.PortForward { return { desiredPresence: 'present', diff --git a/apps/web-antdv-next/src/views/system/network/components/NetworkEndpointHistoryDrawer.tsx b/apps/web-antdv-next/src/views/system/network/components/NetworkEndpointHistoryDrawer.tsx index 78ab97f..4bd5d6c 100644 --- a/apps/web-antdv-next/src/views/system/network/components/NetworkEndpointHistoryDrawer.tsx +++ b/apps/web-antdv-next/src/views/system/network/components/NetworkEndpointHistoryDrawer.tsx @@ -27,7 +27,6 @@ const eventColors: Record = { export default defineComponent({ name: 'NetworkEndpointHistoryDrawer', - /** Creates a lazy, record-scoped history table inside a disposable drawer. */ setup(_, { expose }) { const selectedRow = ref(); const columns: Array< @@ -64,7 +63,6 @@ export default defineComponent({ }, ]; const api: KtTableApi = { - /** Loads only the selected mapping's append-only endpoint transitions. */ list: async (params) => { if (!selectedRow.value) return { items: [], total: 0 }; return await getNetworkPortForwardEndpointHistory( @@ -108,10 +106,6 @@ export default defineComponent({ }, }); - /** - * Opens history for one mapping and discards rows from the prior selection. - * @param row - Mapping whose append-only history should be queried. - */ function open(row: SystemNetworkApi.PortForward) { selectedRow.value = row; drawerApi.open(); diff --git a/apps/web-antdv-next/src/views/system/network/components/NetworkPortForwardModal.spec.tsx b/apps/web-antdv-next/src/views/system/network/components/NetworkPortForwardModal.spec.tsx index c68fe05..391d627 100644 --- a/apps/web-antdv-next/src/views/system/network/components/NetworkPortForwardModal.spec.tsx +++ b/apps/web-antdv-next/src/views/system/network/components/NetworkPortForwardModal.spec.tsx @@ -35,7 +35,6 @@ const mocks = vi.hoisted(() => { }; }); -/** Creates a fluent no-op validation rule for the form-schema fixture. */ function createRule(): any { const rule: any = {}; for (const method of ['int', 'max', 'min', 'optional', 'or', 'trim']) { diff --git a/apps/web-antdv-next/src/views/system/network/components/NetworkPortForwardModal.tsx b/apps/web-antdv-next/src/views/system/network/components/NetworkPortForwardModal.tsx index e39d5c9..340a6dc 100644 --- a/apps/web-antdv-next/src/views/system/network/components/NetworkPortForwardModal.tsx +++ b/apps/web-antdv-next/src/views/system/network/components/NetworkPortForwardModal.tsx @@ -31,9 +31,6 @@ const protocolOptions = [ export default defineComponent({ name: 'NetworkPortForwardModal', emits: ['saved'], - /** - * Owns the CRUD form while keeping the NAS target and Keeper state read-only. - */ setup(_, { emit, expose }) { const editingRow = ref(); const targetIpv4 = ref(''); @@ -57,7 +54,6 @@ export default defineComponent({ async onConfirm() { await submit(); }, - /** Resets values only after destroy-on-close content has mounted. */ onOpenChange(isOpen: boolean) { if (!isOpen) return; const { values } = modalApi.getData(); @@ -65,10 +61,6 @@ export default defineComponent({ }, }); - /** - * Opens a blank form for one new desired mapping. - * @param fixedTargetIpv4 - Server-controlled NAS target shown read-only. - */ function openCreate(fixedTargetIpv4: string) { editingRow.value = undefined; targetIpv4.value = fixedTargetIpv4; @@ -85,10 +77,6 @@ export default defineComponent({ .open(); } - /** - * Opens an existing row for editing without copying reported/runtime fields. - * @param row - Persisted desired record selected from KtTable. - */ function openEdit(row: SystemNetworkApi.PortForward) { editingRow.value = row; targetIpv4.value = row.targetIpv4; @@ -105,10 +93,6 @@ export default defineComponent({ .open(); } - /** - * Resets validation and installs only user-editable values. - * @param values - Form values excluding target IP, Keeper and secrets. - */ async function resetForm( values: Partial, ) { @@ -117,9 +101,6 @@ export default defineComponent({ await formApi.resetValidate(); } - /** - * Persists the desired mapping and leaves all runtime effects asynchronous. - */ async function submit() { const { valid } = await formApi.validate(); if (!valid) return; @@ -173,10 +154,6 @@ export default defineComponent({ }, }); -/** - * Builds the modal's approved editable schema without any credential field. - * @returns Vben form fields for name, protocol, ports and optional remark. - */ function createFormSchema(): VbenFormSchema[] { const portRule = z .number() diff --git a/apps/web-antdv-next/src/views/system/network/composables/useNetworkManagementStream.ts b/apps/web-antdv-next/src/views/system/network/composables/useNetworkManagementStream.ts index de0de8d..c3e1005 100644 --- a/apps/web-antdv-next/src/views/system/network/composables/useNetworkManagementStream.ts +++ b/apps/web-antdv-next/src/views/system/network/composables/useNetworkManagementStream.ts @@ -9,18 +9,12 @@ export interface UseNetworkManagementStreamOptions { onStateChanged: (event: SystemNetworkApi.StateChangeEvent) => void; } -/** - * Bridges API SSE updates into the network page without exposing MQTT credentials. - * @param options - Page-owned callbacks for committed changes and replay gaps. - * @returns Idempotent start/close controls for route keep-alive lifecycle hooks. - */ export function useNetworkManagementStream( options: UseNetworkManagementStreamOptions, ) { const lastEventId = ref(); let source: EventSource | undefined; - /** Starts one EventSource and relies on native reconnect while the page is active. */ function start() { if (source) return; source = new EventSource(getNetworkManagementEventsUrl(lastEventId.value), { @@ -30,7 +24,6 @@ export function useNetworkManagementStream( source.addEventListener('snapshot-required', handleSnapshotRequired); } - /** Closes the active route stream and removes its typed listeners. */ function close() { if (!source) return; source.removeEventListener('network-state-changed', handleStateChanged); @@ -39,10 +32,6 @@ export function useNetworkManagementStream( source = undefined; } - /** - * Applies one committed MQTT-derived state event exactly once. - * @param event - Browser SSE message containing a safe state-change envelope. - */ function handleStateChanged(event: Event) { const payload = parseStateChange(event); if (!payload || payload.eventId === lastEventId.value) return; @@ -50,16 +39,10 @@ export function useNetworkManagementStream( options.onStateChanged(payload); } - /** Requests one fresh snapshot only when the API cannot replay a missed topic event. */ function handleSnapshotRequired() { options.onSnapshotRequired(); } - /** - * Validates the minimum browser payload before it reaches page state. - * @param event - Typed EventSource message with JSON data. - * @returns Parsed state event, or undefined for malformed/unexpected data. - */ function parseStateChange( event: Event, ): SystemNetworkApi.StateChangeEvent | undefined { diff --git a/apps/web-antdv-next/src/views/system/network/list.spec.tsx b/apps/web-antdv-next/src/views/system/network/list.spec.tsx index 71f1b70..b9d8719 100644 --- a/apps/web-antdv-next/src/views/system/network/list.spec.tsx +++ b/apps/web-antdv-next/src/views/system/network/list.spec.tsx @@ -32,26 +32,22 @@ class FakeEventSource { FakeEventSource.instances.push(this); } - /** Registers one typed SSE listener for the page test. */ addEventListener(type: string, listener: FakeEventSourceListener) { const listeners = this.listeners.get(type) || new Set(); listeners.add(listener); this.listeners.set(type, listeners); } - /** Closes this fake stream and prevents later dispatches. */ close() { this.closed = true; } - /** Dispatches one JSON SSE payload to currently registered listeners. */ dispatch(type: string, data: Record) { if (this.closed) return; const event = new MessageEvent(type, { data: JSON.stringify(data) }); this.listeners.get(type)?.forEach((listener) => listener(event)); } - /** Removes one typed SSE listener from the page test. */ removeEventListener(type: string, listener: FakeEventSourceListener) { this.listeners.get(type)?.delete(listener); } @@ -224,7 +220,6 @@ vi.mock('#/locales', () => ({ $t: (key: string) => key, })); -/** Creates a complete UDP row fixture with string revisions. */ function createRow( overrides: Partial = {}, ): SystemNetworkApi.PortForward { diff --git a/apps/web-antdv-next/src/views/system/network/list.tsx b/apps/web-antdv-next/src/views/system/network/list.tsx index ecc9a3f..d2fbaf3 100644 --- a/apps/web-antdv-next/src/views/system/network/list.tsx +++ b/apps/web-antdv-next/src/views/system/network/list.tsx @@ -92,9 +92,6 @@ const keeperStatusLabels: Record = { export default defineComponent({ name: 'SystemNetworkList', - /** - * Builds the generic persisted network-resource table and event-driven refresh stream. - */ setup() { const { hasAccessByCodes } = useAccess(); const canViewPortForward = hasAccessByCodes([ @@ -192,7 +189,6 @@ export default defineComponent({ }, ]; const api: KtTableApi = { - /** Loads the latest API fact-source page for KtTable. */ list: async (params) => await getNetworkPortForwardList(params), }; const buttons: Array> = [ @@ -364,7 +360,6 @@ export default defineComponent({ tableTitle: $t('system.network.portForwardTitle'), }); - /** Opens the create modal using the server-reported fixed target address. */ function openCreate() { const rowTarget = tableApi.getRows()[0]?.targetIpv4 || ''; void modalRef.value?.openCreate( @@ -372,24 +367,20 @@ export default defineComponent({ ); } - /** Opens one mutable row in the shared CRUD modal. */ function openEdit(row: SystemNetworkApi.PortForward) { if (!isRowBusy(row) && !isDeleting(row)) { void modalRef.value?.openEdit(row); } } - /** Opens the append-only endpoint history drawer for one row. */ function openHistory(row: SystemNetworkApi.PortForward) { historyDrawerRef.value?.open(row); } - /** Reloads after a modal save while preserving serialized request order. */ function handleModalSaved() { void requestRefresh('port-forward'); } - /** Copies an API-approved current endpoint without logging it. */ async function copyEndpoint(row: SystemNetworkApi.PortForward) { const endpoint = getCurrentEndpoint(row); if (!endpoint) return; @@ -397,12 +388,6 @@ export default defineComponent({ message.success($t('system.network.endpointCopied')); } - /** - * Runs one row mutation with per-row duplicate suppression and fact-source reload. - * @param row - Selected persisted mapping. - * @param mutation - API operation accepting the stable record ID. - * @param successMessage - Accurate asynchronous-success wording. - */ async function runRowMutation( row: SystemNetworkApi.PortForward, mutation: (id: string) => Promise, @@ -419,7 +404,6 @@ export default defineComponent({ } } - /** Updates the reactive per-row in-flight set without mutating it in place. */ function setRowBusy(id: string, busy: boolean) { const next = new Set(busyRowIds.value); if (busy) next.add(id); @@ -427,12 +411,10 @@ export default defineComponent({ busyRowIds.value = next; } - /** Returns whether one row already owns an in-flight write request. */ function isRowBusy(row: SystemNetworkApi.PortForward): boolean { return busyRowIds.value.has(row.id); } - /** Loads Agent connectivity without translating refresh failure into offline. */ async function loadAgentStatus() { try { agentStatus.value = await getNetworkAgentStatus(); @@ -442,9 +424,6 @@ export default defineComponent({ } } - /** - * Serializes table and Agent refreshes so stale responses cannot overtake writes. - */ async function requestRefresh( resource: NetworkTabKey = activeTab.value, ): Promise { @@ -470,10 +449,6 @@ export default defineComponent({ } } - /** - * Loads exactly one permission-approved resource without cross-tab requests. - * @param resource - Active or locally-mutated network resource. - */ async function performResourceRefresh(resource: NetworkTabKey) { if (resource === 'ddns') { await ddnsTableRef.value?.reload(); @@ -482,19 +457,10 @@ export default defineComponent({ await Promise.allSettled([tableApi.reload(), loadAgentStatus()]); } - /** - * Checks list permission before any resource request. - * @param resource - Candidate tab resource. - * @returns True when its List permission is present. - */ function canViewResource(resource: NetworkTabKey): boolean { return resource === 'ddns' ? canViewDdns : canViewPortForward; } - /** - * Refreshes only the active resource addressed by one semantic SSE event. - * @param event - Committed API event classified by network resource source. - */ function handleStateChanged(event: SystemNetworkApi.StateChangeEvent) { const resource = event.source === 'ddns' ? 'ddns' : 'port-forward'; if (pageActive && activeTab.value === resource) { @@ -502,22 +468,16 @@ export default defineComponent({ } } - /** Refreshes the active resource when the API cannot replay a missed event. */ function handleSnapshotRequired() { if (pageActive) void requestRefresh(activeTab.value); } - /** - * Selects one allowed tab and immediately requests its first fact snapshot. - * @param key - Tab key emitted by Ant Design Tabs. - */ function handleActiveTabChange(key: NetworkTabKey) { if (!canViewResource(key) || activeTab.value === key) return; activeTab.value = key; if (pageActive) void requestRefresh(key); } - /** Opens the stream before the one initial page snapshot to avoid a subscription gap. */ function activatePage() { if (pageActive || tabItems.length === 0) return; pageActive = true; @@ -525,13 +485,11 @@ export default defineComponent({ void requestRefresh(activeTab.value); } - /** Closes the route-owned stream while preserving its replay cursor. */ function deactivatePage() { pageActive = false; managementStream.close(); } - /** Renders independent Agent connectivity and revision convergence controls. */ function renderAgentControls() { const status = agentStatus.value; return ( @@ -552,7 +510,6 @@ export default defineComponent({ ); } - /** Renders cells without collapsing independent synchronization dimensions. */ function renderBodyCell({ column, record }: any) { const row = record as SystemNetworkApi.PortForward; if (column.key === 'protocol') { @@ -663,11 +620,6 @@ export default defineComponent({ }, }); -/** - * Returns whether a mapping is immutable pending confirmed asynchronous deletion. - * @param row - Persisted port-forward row. - * @returns True for absent tombstones, deleting state, or confirmed deletion. - */ export function isDeleting(row: SystemNetworkApi.PortForward): boolean { return ( row.isDeleted || @@ -676,12 +628,6 @@ export function isDeleting(row: SystemNetworkApi.PortForward): boolean { ); } -/** - * Resolves the Keeper or probe disabled reason without consulting Agent online state. - * @param row - Persisted port-forward row. - * @param requireEnabled - Whether immediate probe additionally requires desired Keeper. - * @returns Readable reason, or undefined when the action is valid. - */ export function getKeeperDisabledReason( row: SystemNetworkApi.PortForward, requireEnabled: boolean, @@ -699,11 +645,6 @@ export function getKeeperDisabledReason( return undefined; } -/** - * Formats the current endpoint already lease-filtered by the API. - * @param row - Persisted port-forward row. - * @returns Exact public IPv4 and port, or undefined when the API withdrew it. - */ export function getCurrentEndpoint( row: SystemNetworkApi.PortForward, ): string | undefined { @@ -712,12 +653,6 @@ export function getCurrentEndpoint( : undefined; } -/** - * Produces the row summary without treating status-refresh failure as Agent offline. - * @param row - Persisted mapping with redacted stable error fields. - * @param status - Last successfully loaded Agent status, when available. - * @returns Error, offline wait, pending wait, or an empty marker. - */ export function getWaitingOrErrorSummary( row: SystemNetworkApi.PortForward, status?: SystemNetworkApi.AgentStatus, @@ -732,12 +667,6 @@ export function getWaitingOrErrorSummary( return '-'; } -/** - * Resolves the independent Agent status color without treating refresh failure as offline. - * @param status - Last successfully loaded Agent status. - * @param unknown - Whether the latest status request failed. - * @returns Ant Design semantic color. - */ function getAgentStatusColor( status: SystemNetworkApi.AgentStatus | undefined, unknown: boolean, @@ -746,12 +675,6 @@ function getAgentStatusColor( return status?.online ? 'success' : 'warning'; } -/** - * Resolves the independent Agent status label shown in the table header. - * @param status - Last successfully loaded Agent status. - * @param unknown - Whether the latest status request failed. - * @returns Localized unknown, online, or offline label. - */ function getAgentStatusLabel( status: SystemNetworkApi.AgentStatus | undefined, unknown: boolean, @@ -762,7 +685,6 @@ function getAgentStatusLabel( : $t('system.network.agentOffline'); } -/** Returns the immutable-row explanation used by CRUD write actions. */ function getWriteDisabledReason( row: SystemNetworkApi.PortForward, ): string | undefined { diff --git a/internal/commit/husky-fast-check.mjs b/internal/commit/husky-fast-check.mjs index 206a837..d3d22db 100644 --- a/internal/commit/husky-fast-check.mjs +++ b/internal/commit/husky-fast-check.mjs @@ -64,6 +64,8 @@ function getStagedFiles() { .filter(Boolean); } +run(getPnpmCommand(), ['run', 'check:jsdoc']); + const files = getStagedFiles().filter((file) => { if (!existsSync(file)) return false; if (!CHECK_ROOTS.some((root) => file.startsWith(root))) return false; diff --git a/internal/jsdoc-policy/check-jsdoc.mjs b/internal/jsdoc-policy/check-jsdoc.mjs new file mode 100644 index 0000000..b485618 --- /dev/null +++ b/internal/jsdoc-policy/check-jsdoc.mjs @@ -0,0 +1,709 @@ +#!/usr/bin/env node + +import { execFileSync } from 'node:child_process'; +import { existsSync, readFileSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { pathToFileURL } from 'node:url'; + +import ts from 'typescript'; +import { parse as parseVueSfc } from 'vue/compiler-sfc'; + +const CODE_FILE_PATTERN = /\.(?:cjs|js|mjs|ts|tsx|vue)$/u; +const HAN_CHARACTER_PATTERN = /\p{Script=Han}/u; +const JSDOC_PREFIX = '/**'; + +const LIFECYCLE_METHOD_NAMES = new Set([ + 'activated', + 'beforeCreate', + 'beforeDestroy', + 'beforeMount', + 'beforeUnmount', + 'beforeUpdate', + 'componentDidCatch', + 'componentDidMount', + 'componentDidUpdate', + 'componentWillMount', + 'componentWillReceiveProps', + 'componentWillUnmount', + 'componentWillUpdate', + 'created', + 'deactivated', + 'destroyed', + 'errorCaptured', + 'getSnapshotBeforeUpdate', + 'mounted', + 'renderTracked', + 'renderTriggered', + 'serverPrefetch', + 'shouldComponentUpdate', + 'unmounted', + 'updated', +]); + +function getIsolatedGitEnvironment() { + return Object.fromEntries( + Object.entries(process.env).filter(([name]) => !name.startsWith('GIT_')), + ); +} + +function getLineStarts(source) { + const starts = [0]; + + for (let index = 0; index < source.length; index += 1) { + const character = source.codePointAt(index); + if (character === 13) { + if (source.codePointAt(index + 1) === 10) { + index += 1; + } + starts.push(index + 1); + } else if (character === 10) { + starts.push(index + 1); + } + } + + return starts; +} + +function getLineAndColumn(lineStarts, position) { + let low = 0; + let high = lineStarts.length - 1; + + while (low <= high) { + const middle = Math.floor((low + high) / 2); + if (lineStarts[middle] <= position) { + low = middle + 1; + } else { + high = middle - 1; + } + } + + const lineIndex = Math.max(0, high); + return { + column: position - lineStarts[lineIndex] + 1, + line: lineIndex + 1, + }; +} + +function getScriptKind(filePath, language) { + const normalizedLanguage = language?.toLowerCase(); + + if (normalizedLanguage === 'tsx' || filePath.endsWith('.tsx')) { + return ts.ScriptKind.TSX; + } + if (normalizedLanguage === 'jsx') { + return ts.ScriptKind.JSX; + } + if ( + normalizedLanguage === 'ts' || + filePath.endsWith('.ts') || + filePath.endsWith('.mts') || + filePath.endsWith('.cts') + ) { + return ts.ScriptKind.TS; + } + return ts.ScriptKind.JS; +} + +function getVueScriptBlocks(filePath, source) { + const { descriptor, errors } = parseVueSfc(source, { + filename: filePath, + sourceMap: false, + }); + + if (errors.length > 0) { + const message = errors + .map((error) => (error instanceof Error ? error.message : String(error))) + .join('; '); + throw new Error(`Vue SFC 解析失败:${message}`); + } + + return [ + descriptor.script + ? { + content: descriptor.script.content, + label: ' + + + + +`; + + const result = inspectFileSource('Component.vue', source); + + assert.equal(result.comments.length, 5); + assert.deepEqual( + result.violations.map(({ rule, target }) => [rule, target]), + [ + ['invalid-target', 'variable'], + ['invalid-target', 'setup'], + ['non-chinese-description', 'named-function-declaration'], + ], + ); +}); + +it('fix mode removes only violations and preserves non-comment tokens', () => { + const source = ` +/** 保留有意义的中文说明。 */ +function keepComment() {} + +/** Remove this historical English description. */ +function removeEnglishComment() {} + +/** 删除变量位置的注释。 */ +const value = 1; + +const named = /** 保留具名函数表达式说明。 */ function namedExpression() { + return value; +}; +`; + const beforeTokens = getCodeTokenSignature('cleanup.ts', source); + + const fixed = applyJsdocPolicyFix('cleanup.ts', source); + + assert.match(fixed.source, /保留有意义的中文说明/); + assert.match(fixed.source, /保留具名函数表达式说明/); + assert.doesNotMatch(fixed.source, /historical English/); + assert.doesNotMatch(fixed.source, /删除变量位置的注释/); + assert.equal(fixed.removedCount, 2); + assert.deepEqual( + inspectFileSource('cleanup.ts', fixed.source).violations, + [], + ); + assert.equal(getCodeTokenSignature('cleanup.ts', fixed.source), beforeTokens); +}); + +it('tracked-file discovery also includes untracked non-ignored code', () => { + const repository = mkdtempSync(path.join(tmpdir(), 'admin-jsdoc-policy-')); + + try { + runFixtureGit(repository, ['init', '--quiet']); + writeFileSync(path.join(repository, '.gitignore'), 'ignored.ts\n'); + writeFileSync(path.join(repository, 'deleted.ts'), 'export {};\n'); + writeFileSync(path.join(repository, 'tracked.ts'), 'export {};\n'); + writeFileSync(path.join(repository, 'untracked.tsx'), 'export {};\n'); + writeFileSync(path.join(repository, 'ignored.ts'), 'export {};\n'); + writeFileSync(path.join(repository, 'notes.md'), '# Notes\n'); + runFixtureGit(repository, [ + 'add', + '.gitignore', + 'deleted.ts', + 'tracked.ts', + ]); + rmSync(path.join(repository, 'deleted.ts')); + + assert.deepEqual(getTrackedCodeFiles(repository), [ + 'tracked.ts', + 'untracked.tsx', + ]); + } finally { + rmSync(repository, { force: true, recursive: true }); + } +}); diff --git a/internal/vite-config/src/options.ts b/internal/vite-config/src/options.ts index f1e2401..3361e8e 100644 --- a/internal/vite-config/src/options.ts +++ b/internal/vite-config/src/options.ts @@ -25,9 +25,6 @@ const getDefaultPwaOptions = (name: string): Partial => ({ }, }); -/** - * importmap CDN 暂时不开启,因为有些包不支持,且网络不稳定 - */ const defaultImportmapOptions: ImportmapPluginOptions = { // 通过 Importmap CDN 方式引入, // 目前只有esm.sh源兼容性好一点,jspm.io对于 esm 入口要求高 diff --git a/internal/vite-config/src/plugins/importmap.ts b/internal/vite-config/src/plugins/importmap.ts index 0ccda99..958ae73 100644 --- a/internal/vite-config/src/plugins/importmap.ts +++ b/internal/vite-config/src/plugins/importmap.ts @@ -1,6 +1,3 @@ -/** - * 参考 https://github.com/jspm/vite-plugin-jspm,调整为需要的功能 - */ import type { GeneratorOptions } from '@jspm/generator'; import type { Plugin } from 'vite'; diff --git a/internal/vite-config/src/typing.ts b/internal/vite-config/src/typing.ts index b63bee9..b2bcc9d 100644 --- a/internal/vite-config/src/typing.ts +++ b/internal/vite-config/src/typing.ts @@ -1,4 +1,5 @@ import type { PluginVisualizerOptions } from 'rollup-plugin-visualizer'; +// prettier-ignore import type { ConfigEnv, UserConfig, @@ -7,328 +8,90 @@ import type { import type { PluginOptions } from 'vite-plugin-dts'; import type { Options as PwaPluginOptions } from 'vite-plugin-pwa'; -/** - * ImportMap 配置接口 - * @description 用于配置模块导入映射,支持自定义导入路径和范围 - * @example - * ```typescript - * { - * imports: { - * 'vue': 'https://unpkg.com/vue@3.2.47/dist/vue.esm-browser.js' - * }, - * scopes: { - * 'https://site.com/': { - * 'vue': 'https://unpkg.com/vue@3.2.47/dist/vue.esm-browser.js' - * } - * } - * } - * ``` - */ interface IImportMap { - /** 模块导入映射 */ imports?: Record; - /** 作用域特定的导入映射 */ scopes?: { [scope: string]: Record; }; } -/** - * 打印插件配置选项 - * @description 用于配置控制台打印信息 - */ interface PrintPluginOptions { - /** - * 打印的数据映射 - * @description 键值对形式的数据,将在控制台打印 - * @example - * ```typescript - * { - * 'App Version': '1.0.0', - * 'Build Time': '2024-01-01' - * } - * ``` - */ infoMap?: Record; } -/** - * Nitro Mock 插件配置选项 - * @description 用于配置 Nitro Mock 服务器的行为 - */ interface NitroMockPluginOptions { - /** - * Mock 服务器包名 - * @default '@vbenjs/nitro-mock' - */ mockServerPackage?: string; - /** - * Mock 服务端口 - * @default 3000 - */ port?: number; - /** - * 是否打印 Mock 日志 - * @default false - */ verbose?: boolean; } -/** - * 归档插件配置选项 - * @description 用于配置构建产物的压缩归档 - */ interface ArchiverPluginOptions { - /** - * 输出文件名 - * @default 'dist' - */ name?: string; - /** - * 输出目录 - * @default '.' - */ outputDir?: string; } -/** - * ImportMap 插件配置 - * @description 用于配置模块的 CDN 导入 - */ interface ImportmapPluginOptions { - /** - * CDN 供应商 - * @default 'jspm.io' - * @description 支持 esm.sh 和 jspm.io 两种 CDN 供应商 - */ defaultProvider?: 'esm.sh' | 'jspm.io'; - /** - * ImportMap 配置数组 - * @description 配置需要从 CDN 导入的包 - * @example - * ```typescript - * [ - * { name: 'vue' }, - * { name: 'pinia', range: '^2.0.0' } - * ] - * ``` - */ importmap?: Array<{ name: string; range?: string }>; - /** - * 手动配置 ImportMap - * @description 自定义 ImportMap 配置 - */ inputMap?: IImportMap; } -/** - * 条件插件配置 - * @description 用于根据条件动态加载插件 - */ interface ConditionPlugin { - /** - * 判断条件 - * @description 当条件为 true 时加载插件 - */ condition?: boolean; - /** - * 插件对象 - * @description 返回插件数组或 Promise - */ plugins: () => PromiseLike | unknown[]; } -/** - * 通用插件配置选项 - * @description 所有插件共用的基础配置 - */ interface CommonPluginOptions { - /** - * 是否开启开发工具 - * @default false - */ devtools?: boolean; - /** - * 环境变量 - * @description 自定义环境变量 - */ env?: Record; - /** - * 是否注入元数据 - * @default true - */ injectMetadata?: boolean; - /** - * 是否为构建模式 - * @default false - */ isBuild?: boolean; - /** - * 构建模式 - * @default 'development' - */ mode?: string; - /** - * 是否开启依赖分析 - * @default false - * @description 使用 rollup-plugin-visualizer 分析依赖 - */ visualizer?: boolean | PluginVisualizerOptions; } -/** - * 应用插件配置选项 - * @description 用于配置应用构建时的插件选项 - */ interface ApplicationPluginOptions extends CommonPluginOptions { - /** - * 应用标题 - * @description 用于 HTML 模板和 PWA 配置的默认标题 - */ appTitle?: string; - /** - * 是否开启压缩归档 - * @default false - * @description 开启后会在打包目录生成 zip 文件 - */ archiver?: boolean; - /** - * 压缩归档插件配置 - * @description 配置压缩归档的行为 - */ archiverPluginOptions?: ArchiverPluginOptions; - /** - * 是否开启压缩 - * @default false - * @description 支持 gzip 和 brotli 压缩 - */ compress?: boolean; - /** - * 压缩类型 - * @default ['gzip'] - * @description 可选的压缩类型 - */ compressTypes?: ('brotli' | 'gzip')[]; - /** - * 是否抽离配置文件 - * @default false - * @description 在构建时抽离配置文件 - */ extraAppConfig?: boolean; - /** - * 是否开启 HTML 插件 - * @default true - */ html?: boolean; - /** - * 是否开启国际化 - * @default false - */ i18n?: boolean; - /** - * 是否开启 ImportMap CDN - * @default false - */ importmap?: boolean; - /** - * ImportMap 插件配置 - */ importmapOptions?: ImportmapPluginOptions; - /** - * 是否注入应用加载动画 - * @default true - */ injectAppLoading?: boolean; - /** - * 是否注入全局 SCSS - * @default true - */ injectGlobalScss?: boolean; - /** - * 是否注入版权信息 - * @default true - */ license?: boolean; - /** - * 是否开启 Nitro Mock - * @default false - */ nitroMock?: boolean; - /** - * Nitro Mock 插件配置 - */ nitroMockOptions?: NitroMockPluginOptions; - /** - * 是否开启控制台打印 - * @default false - */ print?: boolean; - /** - * 打印插件配置 - */ printInfoMap?: PrintPluginOptions['infoMap']; - /** - * 是否开启 PWA - * @default false - */ pwa?: boolean; - /** - * PWA 插件配置 - */ pwaOptions?: Partial; } -/** - * 库插件配置选项 - * @description 用于配置库构建时的插件选项 - */ interface LibraryPluginOptions extends CommonPluginOptions { - /** - * 是否开启 DTS 输出 - * @default true - * @description 生成 TypeScript 类型声明文件 - */ dts?: boolean | PluginOptions; } -/** - * 应用配置选项类型 - */ type ApplicationOptions = ApplicationPluginOptions; -/** - * 库配置选项类型 - */ type LibraryOptions = LibraryPluginOptions; -/** - * 应用配置定义函数类型 - * @description 用于定义应用构建配置 - */ type DefineApplicationOptions = (config?: ConfigEnv) => Promise<{ - /** 应用插件配置 */ application?: ApplicationOptions; - /** Vite 配置 */ vite?: UserConfig; }>; -/** - * 库配置定义函数类型 - * @description 用于定义库构建配置 - */ type DefineLibraryOptions = (config?: ConfigEnv) => Promise<{ - /** 库插件配置 */ library?: LibraryOptions; - /** Vite 配置 */ vite?: UserConfig; }>; -/** - * 配置定义类型 - * @description 应用或库的配置定义 - */ type DefineConfig = DefineApplicationOptions | DefineLibraryOptions; type VbenViteConfig = Promise | UserConfig | UserConfigFnPromise; diff --git a/internal/vite-config/src/utils/env.ts b/internal/vite-config/src/utils/env.ts index 8862aa1..c348250 100644 --- a/internal/vite-config/src/utils/env.ts +++ b/internal/vite-config/src/utils/env.ts @@ -29,11 +29,6 @@ function getConfFiles() { return ['.env', '.env.local', `.env.${mode}`, `.env.${mode}.local`]; } -/** - * Get the environment variables starting with the specified prefix - * @param match prefix - * @param confFiles ext - */ async function loadEnv>( match = 'VITE_GLOB_', confFiles = getConfFiles(), diff --git a/package.json b/package.json index fc6fb3c..6ffdb26 100644 --- a/package.json +++ b/package.json @@ -9,12 +9,13 @@ "build:analyze": "turbo build:analyze", "build:antdv-next": "pnpm run build --filter=@vben/web-antdv-next", "check": "pnpm run check:type", + "check:jsdoc": "pnpm run test:jsdoc && node internal/jsdoc-policy/check-jsdoc.mjs", "check:type": "turbo run typecheck", "clean": "rimraf .turbo apps/*/dist apps/*/dist.zip packages/**/dist packages/**/dist.zip internal/**/dist internal/**/dist.zip", "dev": "pnpm run dev:antdv-next", "dev:antdv-next": "pnpm -F @vben/web-antdv-next run dev", "format": "eslint apps/web-antdv-next internal --cache --fix && prettier . --write --cache --log-level warn && stylelint \"**/*.{vue,css,less,scss}\" --cache --fix", - "lint": "eslint apps/web-antdv-next internal --cache && prettier . --ignore-unknown --check --cache && stylelint \"**/*.{vue,css,less,scss}\" --cache", + "lint": "pnpm run check:jsdoc && eslint apps/web-antdv-next internal --cache && prettier . --ignore-unknown --check --cache && stylelint \"**/*.{vue,css,less,scss}\" --cache", "lint:commit": "eslint apps/web-antdv-next internal/commit/validate-commit-msg.mjs --cache", "postinstall": "pnpm -r run stub --if-present", "prepare": "husky", @@ -23,7 +24,8 @@ "reinstall": "pnpm run clean && rimraf pnpm-lock.yaml && pnpm install", "verify:staged": "node internal/commit/husky-fast-check.mjs", "verify:commit": "pnpm run lint:commit && pnpm -F @vben/web-antdv-next run typecheck", - "test:e2e": "turbo run test:e2e" + "test:e2e": "turbo run test:e2e", + "test:jsdoc": "vitest run internal/jsdoc-policy/check-jsdoc.test.mjs --environment node --reporter=dot" }, "devDependencies": { "@playwright/test": "catalog:", diff --git a/packages/@core/base/shared/src/constants/globals.ts b/packages/@core/base/shared/src/constants/globals.ts index 3c69957..caffcf5 100644 --- a/packages/@core/base/shared/src/constants/globals.ts +++ b/packages/@core/base/shared/src/constants/globals.ts @@ -1,16 +1,8 @@ -/** layout content 组件的高度 */ export const CSS_VARIABLE_LAYOUT_CONTENT_HEIGHT = `--vben-content-height`; -/** layout content 组件的宽度 */ export const CSS_VARIABLE_LAYOUT_CONTENT_WIDTH = `--vben-content-width`; -/** layout header 组件的高度 */ export const CSS_VARIABLE_LAYOUT_HEADER_HEIGHT = `--vben-header-height`; -/** layout footer 组件的高度 */ export const CSS_VARIABLE_LAYOUT_FOOTER_HEIGHT = `--vben-footer-height`; -/** 内容区域的组件ID */ export const ELEMENT_ID_MAIN_CONTENT = `__vben_main_content`; -/** - * @zh_CN 默认命名空间 - */ export const DEFAULT_NAMESPACE = 'vben'; diff --git a/packages/@core/base/shared/src/constants/vben.ts b/packages/@core/base/shared/src/constants/vben.ts index 37b8cd0..25f6c33 100644 --- a/packages/@core/base/shared/src/constants/vben.ts +++ b/packages/@core/base/shared/src/constants/vben.ts @@ -1,22 +1,10 @@ -/** - * @zh_CN GITHUB 仓库地址 - */ export const VBEN_GITHUB_URL = 'https://github.com/vbenjs/vue-vben-admin'; -/** - * @zh_CN 文档地址 - */ export const VBEN_DOC_URL = 'https://doc.vben.pro'; -/** - * @zh_CN Vben Logo - */ export const VBEN_LOGO_URL = 'https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-v1.webp'; -/** - * @zh_CN Vben Admin 首页地址 - */ export const VBEN_PREVIEW_URL = 'https://www.vben.pro'; export const VBEN_ANTDV_NEXT_PREVIEW_URL = 'https://antdv-next.vben.pro'; diff --git a/packages/@core/base/shared/src/global-state.ts b/packages/@core/base/shared/src/global-state.ts index 2d71356..ecd2b5c 100644 --- a/packages/@core/base/shared/src/global-state.ts +++ b/packages/@core/base/shared/src/global-state.ts @@ -1,8 +1,3 @@ -/** - * 全局复用的变量、组件、配置,各个模块之间共享 - * 通过单例模式实现,单例必须注意不受请求影响,例如用户信息这些需要根据请求获取的。后续如果有ssr需求,也不会影响 - */ - interface ComponentsState { [key: string]: any; } diff --git a/packages/@core/base/shared/src/utils/date.ts b/packages/@core/base/shared/src/utils/date.ts index 926050d..981e190 100644 --- a/packages/@core/base/shared/src/utils/date.ts +++ b/packages/@core/base/shared/src/utils/date.ts @@ -44,32 +44,17 @@ export function isDayjsObject(value: any): value is dayjs.Dayjs { return dayjs.isDayjs(value); } -/** - * 获取当前时区 - * @returns 当前时区 - */ export const getSystemTimezone = () => { return dayjs.tz.guess(); }; -/** - * 自定义设置的时区 - */ let currentTimezone = getSystemTimezone(); -/** - * 设置默认时区 - * @param timezone - */ export const setCurrentTimezone = (timezone?: string) => { currentTimezone = timezone || getSystemTimezone(); dayjs.tz.setDefault(currentTimezone); }; -/** - * 获取设置的时区 - * @returns 设置的时区 - */ export const getCurrentTimezone = () => { return currentTimezone; }; diff --git a/packages/@core/base/shared/src/utils/download.ts b/packages/@core/base/shared/src/utils/download.ts index 6f38ee5..1674150 100644 --- a/packages/@core/base/shared/src/utils/download.ts +++ b/packages/@core/base/shared/src/utils/download.ts @@ -96,10 +96,6 @@ export function downloadFileFromBlobPart({ triggerDownload(url, fileName); } -/** - * img url to base64 - * @param url - */ export function urlToBase64(url: string, mineType?: string): Promise { return new Promise((resolve, reject) => { let canvas = document.createElement('CANVAS') as HTMLCanvasElement | null; diff --git a/packages/@core/base/shared/src/utils/inference.ts b/packages/@core/base/shared/src/utils/inference.ts index 195d071..7888b53 100644 --- a/packages/@core/base/shared/src/utils/inference.ts +++ b/packages/@core/base/shared/src/utils/inference.ts @@ -115,29 +115,6 @@ function isNumber(value: any): value is number { return typeof value === 'number' && Number.isFinite(value); } -/** - * Returns the first value in the provided list that is neither `null` nor `undefined`. - * - * This function iterates over the input values and returns the first one that is - * not strictly equal to `null` or `undefined`. If all values are either `null` or - * `undefined`, it returns `undefined`. - * - * @template T - The type of the input values. - * @param {...(T | null | undefined)[]} values - A list of values to evaluate. - * @returns {T | undefined} - The first value that is not `null` or `undefined`, or `undefined` if none are found. - * - * @example - * // Returns 42 because it is the first non-null, non-undefined value. - * getFirstNonNullOrUndefined(undefined, null, 42, 'hello'); // 42 - * - * @example - * // Returns 'hello' because it is the first non-null, non-undefined value. - * getFirstNonNullOrUndefined(null, undefined, 'hello', 123); // 'hello' - * - * @example - * // Returns undefined because all values are either null or undefined. - * getFirstNonNullOrUndefined(undefined, null); // undefined - */ function getFirstNonNullOrUndefined( ...values: (null | T | undefined)[] ): T | undefined { diff --git a/packages/@core/base/shared/src/utils/stack.ts b/packages/@core/base/shared/src/utils/stack.ts index d8f5d4a..0881c4c 100644 --- a/packages/@core/base/shared/src/utils/stack.ts +++ b/packages/@core/base/shared/src/utils/stack.ts @@ -1,6 +1,3 @@ -/** - * @zh_CN 栈数据结构 - */ export class Stack { /** * @zh_CN 栈内元素数量 @@ -8,18 +5,9 @@ export class Stack { get size() { return this.items.length; } - /** - * @zh_CN 是否去重 - */ private readonly dedup: boolean; - /** - * @zh_CN 栈内元素 - */ private items: T[] = []; - /** - * @zh_CN 栈的最大容量 - */ private readonly maxSize?: number; constructor(dedup = true, maxSize?: number) { @@ -93,11 +81,5 @@ export class Stack { } } -/** - * @zh_CN 创建一个栈实例 - * @param dedup 是否去重 - * @param maxSize 栈的最大容量 - * @returns 栈实例 - */ export const createStack = (dedup = true, maxSize?: number) => new Stack(dedup, maxSize); diff --git a/packages/@core/base/shared/src/utils/to.ts b/packages/@core/base/shared/src/utils/to.ts index 6f25405..349869c 100644 --- a/packages/@core/base/shared/src/utils/to.ts +++ b/packages/@core/base/shared/src/utils/to.ts @@ -1,8 +1,3 @@ -/** - * @param { Readonly } promise - * @param {object=} errorExt - Additional Information you can pass to the err object - * @return { Promise } - */ export async function to( promise: Readonly>, errorExt?: object, diff --git a/packages/@core/base/typings/src/app.d.ts b/packages/@core/base/typings/src/app.d.ts index f2b4433..581482e 100644 --- a/packages/@core/base/typings/src/app.d.ts +++ b/packages/@core/base/typings/src/app.d.ts @@ -9,12 +9,6 @@ type LayoutType = type ThemeModeType = 'auto' | 'dark' | 'light'; -/** - * 偏好设置按钮位置 - * fixed 固定在右侧 - * header 顶栏 - * auto 自动 - */ type PreferencesButtonPositionType = 'auto' | 'fixed' | 'header'; type BuiltinThemeType = @@ -42,60 +36,20 @@ type ContentCompactType = 'compact' | 'wide'; type LayoutHeaderModeType = 'auto' | 'auto-scroll' | 'fixed' | 'static'; type LayoutHeaderMenuAlignType = 'center' | 'end' | 'start'; -/** - * 登录过期模式 - * modal 弹窗模式 - * page 页面模式 - */ type LoginExpiredModeType = 'modal' | 'page'; -/** - * 面包屑样式 - * background 背景 - * normal 默认 - */ type BreadcrumbStyleType = 'background' | 'normal'; -/** - * 权限模式 - * backend 后端权限模式 - * frontend 前端权限模式 - * mixed 混合权限模式 - */ type AccessModeType = 'backend' | 'frontend' | 'mixed'; -/** - * 导航风格 - * plain 朴素 - * rounded 圆润 - */ type NavigationStyleType = 'plain' | 'rounded'; -/** - * 标签栏风格 - * brisk 轻快 - * card 卡片 - * chrome 谷歌 - * plain 朴素 - */ type TabsStyleType = 'brisk' | 'card' | 'chrome' | 'plain'; -/** - * 页面切换动画 - */ type PageTransitionType = 'fade' | 'fade-down' | 'fade-slide' | 'fade-up'; -/** - * 页面切换动画 - * panel-center 居中布局 - * panel-left 居左布局 - * panel-right 居右布局 - */ type AuthPageLayoutType = 'panel-center' | 'panel-left' | 'panel-right'; -/** - * 时区选项 - */ interface TimezoneOption { label: string; offset: number; diff --git a/packages/@core/base/typings/src/basic.d.ts b/packages/@core/base/typings/src/basic.d.ts index 2f209f0..0809db8 100644 --- a/packages/@core/base/typings/src/basic.d.ts +++ b/packages/@core/base/typings/src/basic.d.ts @@ -8,25 +8,10 @@ type SelectOption = BasicOption; type TabOption = BasicOption; interface BasicUserInfo { - /** - * 头像 - */ avatar: string; - /** - * 用户昵称 - */ realName: string; - /** - * 用户角色 - */ roles?: string[]; - /** - * 用户id - */ userId: string; - /** - * 用户名 - */ username: string; } diff --git a/packages/@core/base/typings/src/helper.d.ts b/packages/@core/base/typings/src/helper.d.ts index 96d4f37..615a60b 100644 --- a/packages/@core/base/typings/src/helper.d.ts +++ b/packages/@core/base/typings/src/helper.d.ts @@ -1,83 +1,41 @@ import type { ComputedRef, MaybeRef } from 'vue'; -/** - * 深层递归所有属性为可选 - */ type DeepPartial = T extends object ? { [P in keyof T]?: DeepPartial; } : T; -/** - * 深层递归所有属性为只读 - */ type DeepReadonly = { readonly [P in keyof T]: T[P] extends object ? DeepReadonly : T[P]; }; -/** - * 任意类型的异步函数 - */ - type AnyPromiseFunction = ( ...arg: T ) => PromiseLike; -/** - * 任意类型的普通函数 - */ type AnyNormalFunction = (...arg: T) => R; -/** - * 任意类型的函数 - */ type AnyFunction = | AnyNormalFunction | AnyPromiseFunction; -/** - * T | null 包装 - */ type Nullable = null | T; -/** - * T | Not null 包装 - */ type NonNullable = T extends null | undefined ? never : T; -/** - * 字符串类型对象 - */ type Recordable = Record; -/** - * 字符串类型对象(只读) - */ interface ReadonlyRecordable { readonly [key: string]: T; } -/** - * setTimeout 返回值类型 - */ type TimeoutHandle = ReturnType; -/** - * setInterval 返回值类型 - */ type IntervalHandle = ReturnType; -/** - * 也许它是一个计算的 ref,或者一个 getter 函数 - * - */ type MaybeReadonlyRef = (() => T) | ComputedRef; -/** - * 也许它是一个 ref,或者一个普通值,或者一个 getter 函数 - * - */ type MaybeComputedRef = MaybeReadonlyRef | MaybeRef; type Merge = { @@ -88,18 +46,6 @@ type Merge = { : never; }; -/** - * T = [ - * { name: string; age: number; }, - * { sex: 'male' | 'female'; age: string } - * ] - * => - * MergeAll = { - * name: string; - * sex: 'male' | 'female'; - * age: string - * } - */ type MergeAll< T extends object[], R extends object = Record, diff --git a/packages/@core/base/typings/src/menu-record.ts b/packages/@core/base/typings/src/menu-record.ts index 21f6ab5..0aec66a 100644 --- a/packages/@core/base/typings/src/menu-record.ts +++ b/packages/@core/base/typings/src/menu-record.ts @@ -1,9 +1,6 @@ import type { Component } from 'vue'; import type { RouteRecordRaw } from 'vue-router'; -/** - * 扩展路由原始对象 - */ type ExRouteRecordRaw = RouteRecordRaw & { parent?: string; parents?: string[]; @@ -11,65 +8,21 @@ type ExRouteRecordRaw = RouteRecordRaw & { }; interface MenuRecordBadgeRaw { - /** - * 徽标 - */ badge?: string; - /** - * 徽标类型 - */ badgeType?: 'dot' | 'normal'; - /** - * 徽标颜色 - */ badgeVariants?: 'destructive' | 'primary' | string; } -/** - * 菜单原始对象 - */ interface MenuRecordRaw extends MenuRecordBadgeRaw { - /** - * 激活时的图标名 - */ activeIcon?: string; - /** - * 子菜单 - */ children?: MenuRecordRaw[]; - /** - * 是否禁用菜单 - * @default false - */ disabled?: boolean; - /** - * 图标名 - */ icon?: Component | string; - /** - * 菜单名 - */ name: string; - /** - * 排序号 - */ order?: number; - /** - * 父级路径 - */ parent?: string; - /** - * 所有父级路径 - */ parents?: string[]; - /** - * 菜单路径,唯一,可当作key - */ path: string; - /** - * 是否显示菜单 - * @default true - */ show?: boolean; } diff --git a/packages/@core/base/typings/src/tabs.ts b/packages/@core/base/typings/src/tabs.ts index 58f7d26..bf336f3 100644 --- a/packages/@core/base/typings/src/tabs.ts +++ b/packages/@core/base/typings/src/tabs.ts @@ -1,8 +1,5 @@ import type { RouteLocationNormalized } from 'vue-router'; export interface TabDefinition extends RouteLocationNormalized { - /** - * 标签页的key - */ key?: string; } diff --git a/packages/@core/base/typings/src/vue-router.d.ts b/packages/@core/base/typings/src/vue-router.d.ts index 9f1a38a..ebb9126 100644 --- a/packages/@core/base/typings/src/vue-router.d.ts +++ b/packages/@core/base/typings/src/vue-router.d.ts @@ -2,40 +2,13 @@ import type { Component } from 'vue'; import type { Router, RouteRecordRaw } from 'vue-router'; interface RouteMeta { - /** - * 激活图标(菜单/tab) - */ activeIcon?: string; - /** - * 当前激活的菜单,有时候不想激活现有菜单,需要激活父级菜单时使用 - */ activePath?: string; - /** - * 是否固定标签页 - * @default false - */ affixTab?: boolean; - /** - * 固定标签页的顺序 - * @default 0 - */ affixTabOrder?: number; - /** - * 需要特定的角色标识才可以访问 - * @default [] - */ authority?: string[]; - /** - * 徽标 - */ badge?: string; - /** - * 徽标类型 - */ badgeType?: 'dot' | 'normal'; - /** - * 徽标颜色 - */ badgeVariants?: | 'default' | 'destructive' @@ -43,83 +16,23 @@ interface RouteMeta { | 'success' | 'warning' | string; - /** - * 路由的完整路径作为key(默认true) - */ fullPathKey?: boolean; - /** - * 当前路由的子级在菜单中不展现 - * @default false - */ hideChildrenInMenu?: boolean; - /** - * 当前路由在面包屑中不展现 - * @default false - */ hideInBreadcrumb?: boolean; - /** - * 当前路由在菜单中不展现 - * @default false - */ hideInMenu?: boolean; - /** - * 当前路由在标签页不展现 - * @default false - */ hideInTab?: boolean; - /** - * 图标(菜单/tab) - */ icon?: Component | string; - /** - * iframe 地址 - */ iframeSrc?: string; - /** - * 忽略权限,直接可以访问 - * @default false - */ ignoreAccess?: boolean; - /** - * 开启KeepAlive缓存 - */ keepAlive?: boolean; - /** - * 外链-跳转路径 - */ link?: string; - /** - * 路由是否已经加载过 - */ loaded?: boolean; - /** - * 标签页最大打开数量 - * @default -1 - */ maxNumOfOpenTab?: number; - /** - * 菜单可以看到,但是访问会被重定向到403 - */ menuVisibleWithForbidden?: boolean; - /** - * 不使用基础布局(仅在顶级生效) - */ noBasicLayout?: boolean; - /** - * 在新窗口打开 - */ openInNewWindow?: boolean; - /** - * 用于路由->菜单排序 - */ order?: number; - /** - * 菜单所携带的参数 - */ query?: Recordable; - /** - * 标题名称 - */ title: string; } diff --git a/packages/@core/composables/src/use-layout-style.ts b/packages/@core/composables/src/use-layout-style.ts index 395e9e5..c7a5bfa 100644 --- a/packages/@core/composables/src/use-layout-style.ts +++ b/packages/@core/composables/src/use-layout-style.ts @@ -14,9 +14,6 @@ import { getElementVisibleRect } from '@vben-core/shared/utils'; import { useCssVar, useDebounceFn } from '@vueuse/core'; -/** - * @zh_CN content style - */ export function useLayoutContentStyle() { let resizeObserver: null | ResizeObserver = null; const contentElement = ref(null); diff --git a/packages/@core/composables/src/use-namespace.ts b/packages/@core/composables/src/use-namespace.ts index b22cf03..bad282f 100644 --- a/packages/@core/composables/src/use-namespace.ts +++ b/packages/@core/composables/src/use-namespace.ts @@ -1,9 +1,5 @@ import { DEFAULT_NAMESPACE } from '@vben-core/shared/constants'; -/** - * @see copy https://github.com/element-plus/element-plus/blob/dev/packages/hooks/use-namespace/index.ts - */ - const statePrefix = 'is-'; const _bem = ( diff --git a/packages/@core/preferences/src/constants.ts b/packages/@core/preferences/src/constants.ts index 7ec2007..0f31e77 100644 --- a/packages/@core/preferences/src/constants.ts +++ b/packages/@core/preferences/src/constants.ts @@ -81,9 +81,6 @@ const BUILT_IN_THEME_PRESETS: BuiltinThemePreset[] = [ }, ]; -/** - * 时区选项 - */ const DEFAULT_TIME_ZONE_OPTIONS: TimezoneOption[] = [ { offset: -5, diff --git a/packages/@core/preferences/src/preferences.ts b/packages/@core/preferences/src/preferences.ts index 1dfd530..9608255 100644 --- a/packages/@core/preferences/src/preferences.ts +++ b/packages/@core/preferences/src/preferences.ts @@ -40,33 +40,18 @@ class PreferenceManager { ); } - /** - * 清除所有缓存的偏好设置 - */ clearCache = () => { Object.values(STORAGE_KEYS).forEach((key) => this.cache.removeItem(key)); }; - /** - * 获取初始化偏好设置 - */ getInitialPreferences = () => { return this.initialPreferences; }; - /** - * 获取当前偏好设置(只读) - */ getPreferences = () => { return readonly(this.state); }; - /** - * 初始化偏好设置 - * @param options - 初始化配置项 - * @param options.namespace - 命名空间,用于隔离不同应用的配置 - * @param options.overrides - 要覆盖的偏好设置 - */ initPreferences = async ({ namespace, overrides }: InitialOptions) => { // 防止重复初始化 if (this.isInitialized) { @@ -99,9 +84,6 @@ class PreferenceManager { this.isInitialized = true; }; - /** - * 重置偏好设置到初始状态 - */ resetPreferences = () => { // 将状态重置为初始偏好设置 Object.assign(this.state, this.initialPreferences); @@ -113,10 +95,6 @@ class PreferenceManager { this.handleUpdates(this.state); }; - /** - * 更新偏好设置 - * @param updates - 要更新的偏好设置 - */ updatePreferences = (updates: DeepPartial) => { // 深度合并更新内容和当前状态 const mergedState = merge({}, updates, markRaw(this.state)); diff --git a/packages/@core/preferences/src/types.ts b/packages/@core/preferences/src/types.ts index e1ef0a3..91a4870 100644 --- a/packages/@core/preferences/src/types.ts +++ b/packages/@core/preferences/src/types.ts @@ -19,298 +19,170 @@ import type { type SupportedLanguagesType = 'en-US' | 'zh-CN'; interface AppPreferences { - /** 权限模式 */ accessMode: AccessModeType; - /** 登录注册页面布局 */ authPageLayout: AuthPageLayoutType; - /** 检查更新轮询时间 */ checkUpdatesInterval: number; - /** 是否开启灰色模式 */ colorGrayMode: boolean; - /** 是否开启色弱模式 */ colorWeakMode: boolean; - /** 是否开启紧凑模式 */ compact: boolean; - /** 是否开启内容紧凑模式 */ contentCompact: ContentCompactType; - /** 内容紧凑宽度 */ contentCompactWidth: number; - /** 内容内边距 */ contentPadding: number; - /** 内容底部内边距 */ contentPaddingBottom: number; - /** 内容左侧内边距 */ contentPaddingLeft: number; - /** 内容右侧内边距 */ contentPaddingRight: number; - /** 内容顶部内边距 */ contentPaddingTop: number; // /** 应用默认头像 */ defaultAvatar: string; - /** 默认首页地址 */ defaultHomePath: string; // /** 开启动态标题 */ dynamicTitle: boolean; - /** 是否开启检查更新 */ enableCheckUpdates: boolean; - /** 是否显示偏好设置 */ enablePreferences: boolean; - /** - * @zh_CN 是否开启refreshToken - */ enableRefreshToken: boolean; - /** - * @zh_CN 是否开启首选项导航栏吸顶效果 - */ enableStickyPreferencesNavigationBar: boolean; - /** 是否移动端 */ isMobile: boolean; - /** 布局方式 */ layout: LayoutType; - /** 支持的语言 */ locale: SupportedLanguagesType; - /** 登录过期模式 */ loginExpiredMode: LoginExpiredModeType; - /** 应用名 */ name: string; - /** 偏好设置按钮位置 */ preferencesButtonPosition: PreferencesButtonPositionType; - /** - * @zh_CN 是否开启水印 - */ watermark: boolean; - /** - * @zh_CN 水印文案 - */ watermarkContent: string; - /** z-index */ zIndex: number; } interface BreadcrumbPreferences { - /** 面包屑是否启用 */ enable: boolean; - /** 面包屑是否只有一个时隐藏 */ hideOnlyOne: boolean; - /** 面包屑首页图标是否可见 */ showHome: boolean; - /** 面包屑图标是否可见 */ showIcon: boolean; - /** 面包屑风格 */ styleType: BreadcrumbStyleType; } interface CopyrightPreferences { - /** 版权公司名 */ companyName: string; - /** 版权公司名链接 */ companySiteLink: string; - /** 版权日期 */ date: string; - /** 版权是否可见 */ enable: boolean; - /** 备案号 */ icp: string; - /** 备案号链接 */ icpLink: string; - /** 设置面板是否显示*/ settingShow?: boolean; } interface FooterPreferences { - /** 底栏是否可见 */ enable: boolean; - /** 底栏是否固定 */ fixed: boolean; - /** 底栏高度 */ height: number; } interface HeaderPreferences { - /** 顶栏是否启用 */ enable: boolean; - /** 顶栏高度 */ height: number; - /** 顶栏是否隐藏,css-隐藏 */ hidden: boolean; - /** 顶栏菜单位置 */ menuAlign: LayoutHeaderMenuAlignType; - /** header显示模式 */ mode: LayoutHeaderModeType; } interface LogoPreferences { - /** logo是否可见 */ enable: boolean; - /** logo图片适应方式 */ fit: 'contain' | 'cover' | 'fill' | 'none' | 'scale-down'; - /** logo地址 */ source: string; - /** 暗色主题logo地址 (可选,若不设置则使用 source) */ sourceDark?: string; } interface NavigationPreferences { - /** 导航菜单手风琴模式 */ accordion: boolean; - /** 导航菜单是否切割,只在 layout=mixed-nav 生效 */ split: boolean; - /** 导航菜单风格 */ styleType: NavigationStyleType; } interface SidebarPreferences { - /** 点击目录时自动激活子菜单 */ autoActivateChild: boolean; - /** 侧边栏是否折叠 */ collapsed: boolean; - /** 侧边栏折叠按钮是否可见 */ collapsedButton: boolean; - /** 侧边栏折叠时,是否显示title */ collapsedShowTitle: boolean; - /** 侧边栏折叠宽度 */ collapseWidth: number; - /** 侧边栏是否可见 */ enable: boolean; - /** 菜单自动展开状态 */ expandOnHover: boolean; - /** 侧边栏扩展区域是否折叠 */ extraCollapse: boolean; - /** 侧边栏扩展区域折叠宽度 */ extraCollapsedWidth: number; - /** 侧边栏固定按钮是否可见 */ fixedButton: boolean; - /** 侧边栏是否隐藏 - css */ hidden: boolean; - /** 混合侧边栏宽度 */ mixedWidth: number; - /** 侧边栏宽度 */ width: number; } interface ShortcutKeyPreferences { - /** 是否启用快捷键-全局 */ enable: boolean; - /** 是否启用全局锁屏快捷键 */ globalLockScreen: boolean; - /** 是否启用全局注销快捷键 */ globalLogout: boolean; - /** 是否启用全局偏好设置快捷键 */ globalPreferences: boolean; - /** 是否启用全局搜索快捷键 */ globalSearch: boolean; } interface TabbarPreferences { - /** 是否开启多标签页拖拽 */ draggable: boolean; - /** 是否开启多标签页 */ enable: boolean; - /** 标签页高度 */ height: number; - /** 开启标签页缓存功能 */ keepAlive: boolean; - /** 限制最大数量 */ maxCount: number; - /** 是否点击中键时关闭标签 */ middleClickToClose: boolean; - /** 是否持久化标签 */ persist: boolean; - /** 是否开启多标签页图标 */ showIcon: boolean; - /** 显示最大化按钮 */ showMaximize: boolean; - /** 显示更多按钮 */ showMore: boolean; - /** 标签页风格 */ styleType: TabsStyleType; - /** 是否开启访问历史记录 */ visitHistory: boolean; - /** 是否开启鼠标滚轮响应 */ wheelable: boolean; } interface ThemePreferences { - /** 内置主题名 */ builtinType: BuiltinThemeType; - /** 错误色 */ colorDestructive: string; - /** 主题色 */ colorPrimary: string; - /** 成功色 */ colorSuccess: string; - /** 警告色 */ colorWarning: string; - /** 字体大小(单位:px) */ fontSize: number; - /** 当前主题 */ mode: ThemeModeType; - /** 圆角 */ radius: string; - /** 是否开启半深色header(只在theme='light'时生效) */ semiDarkHeader: boolean; - /** 是否开启半深色菜单(只在theme='light'时生效) */ semiDarkSidebar: boolean; } interface TransitionPreferences { - /** 页面切换动画是否启用 */ enable: boolean; // /** 是否开启页面加载loading */ loading: boolean; - /** 页面切换动画 */ name: PageTransitionType | string; - /** 是否开启页面加载进度动画 */ progress: boolean; } interface WidgetPreferences { - /** 是否启用全屏部件 */ fullscreen: boolean; - /** 是否启用全局搜索部件 */ globalSearch: boolean; - /** 是否启用语言切换部件 */ languageToggle: boolean; - /** 是否开启锁屏功能 */ lockScreen: boolean; - /** 是否显示通知部件 */ notification: boolean; - /** 显示刷新按钮 */ refresh: boolean; - /** 是否显示侧边栏显示/隐藏部件 */ sidebarToggle: boolean; - /** 是否显示主题切换部件 */ themeToggle: boolean; - /** 是否显示时区部件 */ timezone: boolean; } interface Preferences { - /** 全局配置 */ app: AppPreferences; - /** 顶栏配置 */ breadcrumb: BreadcrumbPreferences; - /** 版权配置 */ copyright: CopyrightPreferences; - /** 底栏配置 */ footer: FooterPreferences; - /** 面包屑配置 */ header: HeaderPreferences; - /** logo配置 */ logo: LogoPreferences; - /** 导航配置 */ navigation: NavigationPreferences; - /** 快捷键配置 */ shortcutKeys: ShortcutKeyPreferences; - /** 侧边栏配置 */ sidebar: SidebarPreferences; - /** 标签页配置 */ tabbar: TabbarPreferences; - /** 主题配置 */ theme: ThemePreferences; - /** 动画配置 */ transition: TransitionPreferences; - /** 功能配置 */ widget: WidgetPreferences; } diff --git a/packages/@core/preferences/src/use-preferences.ts b/packages/@core/preferences/src/use-preferences.ts index 0507d96..0474eec 100644 --- a/packages/@core/preferences/src/use-preferences.ts +++ b/packages/@core/preferences/src/use-preferences.ts @@ -8,9 +8,6 @@ import { isDarkTheme } from './update-css-variables'; function usePreferences() { const preferences = preferencesManager.getPreferences(); const initialPreferences = preferencesManager.getInitialPreferences(); - /** - * @zh_CN 计算偏好设置的变化 - */ const diffPreference = computed(() => { return diff(initialPreferences, preferences); }); @@ -19,11 +16,6 @@ function usePreferences() { const shortcutKeysPreferences = computed(() => preferences.shortcutKeys); - /** - * @zh_CN 判断是否为暗黑模式 - * @param preferences - 当前偏好设置对象,它的主题值将被用来判断是否为暗黑模式。 - * @returns 如果主题为暗黑模式,返回 true,否则返回 false。 - */ const isDark = computed(() => { return isDarkTheme(preferences.theme.mode); }); @@ -40,72 +32,42 @@ function usePreferences() { return isDark.value ? 'dark' : 'light'; }); - /** - * @zh_CN 布局方式 - */ const layout = computed(() => isMobile.value ? 'sidebar-nav' : appPreferences.value.layout, ); - /** - * @zh_CN 是否显示顶栏 - */ const isShowHeaderNav = computed(() => { return preferences.header.enable; }); - /** - * @zh_CN 是否全屏显示content,不需要侧边、底部、顶部、tab区域 - */ const isFullContent = computed( () => appPreferences.value.layout === 'full-content', ); - /** - * @zh_CN 是否侧边导航模式 - */ const isSideNav = computed( () => appPreferences.value.layout === 'sidebar-nav', ); - /** - * @zh_CN 是否侧边混合模式 - */ const isSideMixedNav = computed( () => appPreferences.value.layout === 'sidebar-mixed-nav', ); - /** - * @zh_CN 是否为头部导航模式 - */ const isHeaderNav = computed( () => appPreferences.value.layout === 'header-nav', ); - /** - * @zh_CN 是否为头部混合导航模式 - */ const isHeaderMixedNav = computed( () => appPreferences.value.layout === 'header-mixed-nav', ); - /** - * @zh_CN 是否为顶部通栏+侧边导航模式 - */ const isHeaderSidebarNav = computed( () => appPreferences.value.layout === 'header-sidebar-nav', ); - /** - * @zh_CN 是否为混合导航模式 - */ const isMixedNav = computed( () => appPreferences.value.layout === 'mixed-nav', ); - /** - * @zh_CN 是否包含侧边导航模式 - */ const isSideMode = computed(() => { return ( isMixedNav.value || @@ -120,56 +82,33 @@ function usePreferences() { return preferences.sidebar.collapsed; }); - /** - * @zh_CN 是否开启keep-alive - * 在tabs可见以及开启keep-alive的情况下才开启 - */ const keepAlive = computed( () => preferences.tabbar.enable && preferences.tabbar.keepAlive, ); - /** - * @zh_CN 登录注册页面布局是否为左侧 - */ const authPanelLeft = computed(() => { return appPreferences.value.authPageLayout === 'panel-left'; }); - /** - * @zh_CN 登录注册页面布局是否为右侧 - */ const authPanelRight = computed(() => { return appPreferences.value.authPageLayout === 'panel-right'; }); - /** - * @zh_CN 登录注册页面布局是否为中间 - */ const authPanelCenter = computed(() => { return appPreferences.value.authPageLayout === 'panel-center'; }); - /** - * @zh_CN 内容是否已经最大化 - * 排除 full-content模式 - */ const contentIsMaximize = computed(() => { const headerIsHidden = preferences.header.hidden; const sidebarIsHidden = preferences.sidebar.hidden; return headerIsHidden && sidebarIsHidden && !isFullContent.value; }); - /** - * @zh_CN 是否启用全局搜索快捷键 - */ const globalSearchShortcutKey = computed(() => { const { enable, globalSearch } = shortcutKeysPreferences.value; return enable && globalSearch; }); - /** - * @zh_CN 是否启用全局注销快捷键 - */ const globalLogoutShortcutKey = computed(() => { const { enable, globalLogout } = shortcutKeysPreferences.value; return enable && globalLogout; @@ -180,9 +119,6 @@ function usePreferences() { return enable && globalLockScreen; }); - /** - * @zh_CN 偏好设置按钮位置 - */ const preferencesButtonPosition = computed(() => { const { enablePreferences, preferencesButtonPosition } = preferences.app; diff --git a/packages/@core/ui-kit/form-ui/src/form-api.ts b/packages/@core/ui-kit/form-ui/src/form-api.ts index f5f353d..935aad0 100644 --- a/packages/@core/ui-kit/form-ui/src/form-api.ts +++ b/packages/@core/ui-kit/form-ui/src/form-api.ts @@ -60,9 +60,6 @@ export class FormApi { public store: Store; - /** - * 组件实例映射 - */ private componentRefMap: Map = new Map(); // 最后一次点击提交时的表单值 @@ -330,12 +327,6 @@ export class FormApi { return; } - /** - * 合并算法有待改进,目前的算法不支持object类型的值。 - * antd的日期时间相关组件的值类型为dayjs对象 - * element-plus的日期时间相关组件的值类型可能为Date对象 - * 以上两种类型需要排除深度合并 - */ const fieldMergeFn = createMerge((obj, key, value) => { if (key in obj) { obj[key] = diff --git a/packages/@core/ui-kit/form-ui/src/form-render/helper.ts b/packages/@core/ui-kit/form-ui/src/form-render/helper.ts index cdb3999..8ac7a23 100644 --- a/packages/@core/ui-kit/form-ui/src/form-render/helper.ts +++ b/packages/@core/ui-kit/form-ui/src/form-render/helper.ts @@ -9,10 +9,6 @@ import type { import { isObject, isString } from '@vben-core/shared/utils'; -/** - * Get the lowest level Zod type. - * This will unpack optionals, refinements, etc. - */ export function getBaseRules< ChildType extends AnyZodObject | ZodTypeAny = ZodTypeAny, >(schema: ChildType | ZodEffects): ChildType | null { @@ -26,9 +22,6 @@ export function getBaseRules< return schema as ChildType; } -/** - * Search for a "ZodDefault" in the Zod stack and return its value. - */ export function getDefaultValueInZodStack(schema: ZodTypeAny): any { if (!schema || isString(schema)) { return; diff --git a/packages/@core/ui-kit/form-ui/src/types.ts b/packages/@core/ui-kit/form-ui/src/types.ts index 4bb64bf..0764875 100644 --- a/packages/@core/ui-kit/form-ui/src/types.ts +++ b/packages/@core/ui-kit/form-ui/src/types.ts @@ -45,11 +45,8 @@ export type FormFieldOptions = Partial< >; export interface FormShape { - /** 默认值 */ default?: any; - /** 字段名 */ fieldName: string; - /** 是否必填 */ required?: boolean; rules?: ZodTypeAny; } @@ -90,42 +87,13 @@ type FormItemDependenciesConditionWithProps = ( ) => MaybeComponentProps | PromiseLike; export interface FormItemDependencies { - /** - * 组件参数 - * @returns 组件参数 - */ componentProps?: FormItemDependenciesConditionWithProps; - /** - * 是否禁用 - * @returns 是否禁用 - */ disabled?: boolean | FormItemDependenciesCondition; - /** - * 是否渲染(删除dom) - * @returns 是否渲染 - */ if?: boolean | FormItemDependenciesCondition; - /** - * 是否必填 - * @returns 是否必填 - */ required?: FormItemDependenciesCondition; - /** - * 字段规则 - */ rules?: FormItemDependenciesConditionWithRules; - /** - * 是否隐藏(Css) - * @returns 是否隐藏 - */ show?: boolean | FormItemDependenciesCondition; - /** - * 任意触发都会执行 - */ trigger?: FormItemDependenciesCondition; - /** - * 触发字段 - */ triggerFields: string[]; } @@ -137,74 +105,20 @@ type ComponentProps = | MaybeComponentProps; export interface FormCommonConfig { - /** - * 在Label后显示一个冒号 - */ colon?: boolean; - /** - * 所有表单项的props - */ componentProps?: ComponentProps; - /** - * 所有表单项的控件样式 - */ controlClass?: string; - /** - * 所有表单项的禁用状态 - * @default false - */ disabled?: boolean; - /** - * 是否禁用所有表单项的change事件监听 - * @default true - */ disabledOnChangeListener?: boolean; - /** - * 是否禁用所有表单项的input事件监听 - * @default true - */ disabledOnInputListener?: boolean; - /** - * 所有表单项的空状态值,默认都是undefined,naive-ui的空状态值是null - */ emptyStateValue?: null | undefined; - /** - * 所有表单项的控件样式 - * @default {} - */ formFieldProps?: FormFieldOptions; - /** - * 所有表单项的栅格布局,支持函数形式 - * @default "" - */ formItemClass?: (() => string) | string; - /** - * 隐藏所有表单项label - * @default false - */ hideLabel?: boolean; - /** - * 是否隐藏必填标记 - * @default false - */ hideRequiredMark?: boolean; - /** - * 所有表单项的label样式 - * @default "" - */ labelClass?: string; - /** - * 所有表单项的label宽度 - */ labelWidth?: number; - /** - * 所有表单项的model属性名 - * @default "modelValue" - */ modelPropName?: string; - /** - * 所有表单项的wrapper样式 - */ wrapperClass?: string; } @@ -241,29 +155,18 @@ export type ArrayToStringFields = Array< export interface FormSchema< T extends BaseFormComponentType = BaseFormComponentType, > extends FormCommonConfig { - /** 组件 */ component: Component | T; - /** 组件参数 */ componentProps?: ComponentProps; - /** 默认值 */ defaultValue?: any; - /** 依赖 */ dependencies?: FormItemDependencies; - /** 描述 */ description?: CustomRenderType; - /** 字段名 */ fieldName: string; - /** 帮助信息 */ help?: CustomRenderType; - /** 是否隐藏表单项 */ hide?: boolean; - /** 表单项 */ label?: CustomRenderType; // 自定义组件内部渲染 renderComponentContent?: RenderComponentContentType; - /** 字段规则 */ rules?: FormSchemaRuleType; - /** 后缀 */ suffix?: CustomRenderType; } @@ -274,75 +177,22 @@ export interface FormFieldProps extends FormSchema { export interface FormRenderProps< T extends BaseFormComponentType = BaseFormComponentType, > { - /** - * 表单字段数组映射字符串配置 默认使用"," - */ arrayToStringFields?: ArrayToStringFields; - /** - * 是否折叠,在showCollapseButton=true下生效 - * true:折叠 false:展开 - */ collapsed?: boolean; - /** - * 折叠时保持行数 - * @default 1 - */ collapsedRows?: number; - /** - * 是否触发resize事件 - * @default false - */ collapseTriggerResize?: boolean; - /** - * 折叠计算时是否为表单内置操作按钮预留一个格子 - * @default true - */ collapseReserveAction?: boolean; - /** - * 表单项通用后备配置,当子项目没配置时使用这里的配置,子项目配置优先级高于此配置 - */ commonConfig?: FormCommonConfig; - /** - * 紧凑模式(移除表单每一项底部为校验信息预留的空间) - */ compact?: boolean; - /** - * 组件v-model事件绑定 - */ componentBindEventMap?: Partial>; - /** - * 组件集合 - */ componentMap: Record; - /** - * 表单字段映射到时间格式 - */ fieldMappingTime?: FieldMappingTime; - /** - * 表单实例 - */ form?: FormContext; - /** - * 表单项布局 - */ layout?: FormLayout; - /** - * 表单定义 - */ schema?: FormSchema[]; - /** - * 是否显示展开/折叠 - */ showCollapseButton?: boolean; - /** - * 格式化日期 - */ - /** - * 表单栅格布局 - * @default "grid-cols-1" - */ wrapperClass?: WrapperClassType; } @@ -358,83 +208,30 @@ export interface VbenFormProps< FormRenderProps, 'componentBindEventMap' | 'componentMap' | 'form' > { - /** - * 操作按钮是否反转(提交按钮前置) - */ actionButtonsReverse?: boolean; - /** - * 操作按钮组的样式 - * newLine: 在新行显示。rowEnd: 在行内显示,靠右对齐(默认)。inline: 使用grid默认样式 - */ actionLayout?: 'inline' | 'newLine' | 'rowEnd'; - /** - * 操作按钮组显示位置,默认靠右显示 - */ actionPosition?: 'center' | 'left' | 'right'; - /** - * 表单操作区域class - */ actionWrapperClass?: ClassType; - /** - * 表单字段数组映射字符串配置 默认使用"," - */ arrayToStringFields?: ArrayToStringFields; - /** - * 表单字段映射 - */ fieldMappingTime?: FieldMappingTime; - /** - * 表单收起展开状态变化回调 - */ handleCollapsedChange?: (collapsed: boolean) => void; - /** - * 表单重置回调 - */ handleReset?: HandleResetFn; - /** - * 表单提交回调 - */ handleSubmit?: HandleSubmitFn; - /** - * 表单值变化回调 - */ handleValuesChange?: ( values: Record, fieldsChanged: string[], ) => void; - /** - * 重置按钮参数 - */ resetButtonOptions?: ActionButtonOptions; - /** - * 验证失败时是否自动滚动到第一个错误字段 - * @default false - */ scrollToFirstError?: boolean; - /** - * 是否显示默认操作按钮 - * @default true - */ showDefaultActions?: boolean; - /** - * 提交按钮参数 - */ submitButtonOptions?: ActionButtonOptions; - /** - * 是否在字段值改变时提交表单 - * @default false - */ submitOnChange?: boolean; - /** - * 是否在回车时提交表单 - * @default false - */ submitOnEnter?: boolean; } diff --git a/packages/@core/ui-kit/layout-ui/src/components/layout-content.vue b/packages/@core/ui-kit/layout-ui/src/components/layout-content.vue index b5abccb..e83d4c5 100644 --- a/packages/@core/ui-kit/layout-ui/src/components/layout-content.vue +++ b/packages/@core/ui-kit/layout-ui/src/components/layout-content.vue @@ -9,13 +9,7 @@ import { useLayoutContentStyle } from '@vben-core/composables'; import { Slot } from '@vben-core/shadcn-ui'; interface Props { - /** - * 内容区域定宽 - */ contentCompact: ContentCompactType; - /** - * 定宽布局宽度 - */ contentCompactWidth: number; padding: number; paddingBottom: number; diff --git a/packages/@core/ui-kit/layout-ui/src/components/layout-footer.vue b/packages/@core/ui-kit/layout-ui/src/components/layout-footer.vue index 3793f92..423c08f 100644 --- a/packages/@core/ui-kit/layout-ui/src/components/layout-footer.vue +++ b/packages/@core/ui-kit/layout-ui/src/components/layout-footer.vue @@ -4,15 +4,8 @@ import type { CSSProperties } from 'vue'; import { computed } from 'vue'; interface Props { - /** - * 是否固定在底部 - */ fixed?: boolean; height: number; - /** - * 是否显示 - * @default true - */ show?: boolean; width: string; zIndex: number; diff --git a/packages/@core/ui-kit/layout-ui/src/components/layout-header.vue b/packages/@core/ui-kit/layout-ui/src/components/layout-header.vue index fba07d4..90e94d5 100644 --- a/packages/@core/ui-kit/layout-ui/src/components/layout-header.vue +++ b/packages/@core/ui-kit/layout-ui/src/components/layout-header.vue @@ -4,37 +4,13 @@ import type { CSSProperties } from 'vue'; import { computed, useSlots } from 'vue'; interface Props { - /** - * 横屏 - */ fullWidth: boolean; - /** - * 高度 - */ height: number; - /** - * 是否移动端 - */ isMobile: boolean; - /** - * 是否显示 - */ show: boolean; - /** - * 侧边菜单宽度 - */ sidebarWidth: number; - /** - * 主题 - */ theme: string | undefined; - /** - * 宽度 - */ width: string; - /** - * zIndex - */ zIndex: number; } diff --git a/packages/@core/ui-kit/layout-ui/src/components/layout-sidebar.vue b/packages/@core/ui-kit/layout-ui/src/components/layout-sidebar.vue index 7c0e9c1..cc70b8a 100644 --- a/packages/@core/ui-kit/layout-ui/src/components/layout-sidebar.vue +++ b/packages/@core/ui-kit/layout-ui/src/components/layout-sidebar.vue @@ -10,82 +10,22 @@ import { useScrollLock } from '@vueuse/core'; import { SidebarCollapseButton, SidebarFixedButton } from './widgets'; interface Props { - /** - * 折叠区域高度 - * @default 42 - */ collapseHeight?: number; - /** - * 折叠宽度 - * @default 48 - */ collapseWidth?: number; - /** - * 隐藏的dom是否可见 - * @default true - */ domVisible?: boolean; - /** - * 扩展区域宽度 - */ extraWidth: number; - /** - * 固定扩展区域 - * @default false - */ fixedExtra?: boolean; - /** - * 头部高度 - */ headerHeight: number; - /** - * 是否侧边混合模式 - * @default false - */ isSidebarMixed?: boolean; - /** - * 顶部margin - * @default 60 - */ marginTop?: number; - /** - * 混合菜单宽度 - * @default 80 - */ mixedWidth?: number; - /** - * 顶部padding - * @default 60 - */ paddingTop?: number; - /** - * 是否显示 - * @default true - */ show?: boolean; - /** - * 显示折叠按钮 - * @default true - */ showCollapseButton?: boolean; - /** - * 显示固定按钮 - * @default true - */ showFixedButton?: boolean; - /** - * 主题 - */ theme: string; - /** - * 宽度 - */ width: number; - /** - * zIndex - * @default 0 - */ zIndex?: number; } diff --git a/packages/@core/ui-kit/layout-ui/src/components/layout-tabbar.vue b/packages/@core/ui-kit/layout-ui/src/components/layout-tabbar.vue index 148600e..4d2a7f5 100644 --- a/packages/@core/ui-kit/layout-ui/src/components/layout-tabbar.vue +++ b/packages/@core/ui-kit/layout-ui/src/components/layout-tabbar.vue @@ -4,9 +4,6 @@ import type { CSSProperties } from 'vue'; import { computed } from 'vue'; interface Props { - /** - * 高度 - */ height: number; } diff --git a/packages/@core/ui-kit/layout-ui/src/hooks/use-layout.ts b/packages/@core/ui-kit/layout-ui/src/hooks/use-layout.ts index 2f2b82b..781b0b3 100644 --- a/packages/@core/ui-kit/layout-ui/src/hooks/use-layout.ts +++ b/packages/@core/ui-kit/layout-ui/src/hooks/use-layout.ts @@ -9,35 +9,20 @@ export function useLayout(props: VbenLayoutProps) { props.isMobile ? 'sidebar-nav' : (props.layout as LayoutType), ); - /** - * 是否全屏显示content,不需要侧边、底部、顶部、tab区域 - */ const isFullContent = computed(() => currentLayout.value === 'full-content'); - /** - * 是否侧边混合模式 - */ const isSidebarMixedNav = computed( () => currentLayout.value === 'sidebar-mixed-nav', ); - /** - * 是否为头部导航模式 - */ const isHeaderNav = computed(() => currentLayout.value === 'header-nav'); - /** - * 是否为混合导航模式 - */ const isMixedNav = computed( () => currentLayout.value === 'mixed-nav' || currentLayout.value === 'header-sidebar-nav', ); - /** - * 是否为头部混合模式 - */ const isHeaderMixedNav = computed( () => currentLayout.value === 'header-mixed-nav', ); diff --git a/packages/@core/ui-kit/layout-ui/src/vben-layout.ts b/packages/@core/ui-kit/layout-ui/src/vben-layout.ts index 9b77ba9..60c1069 100644 --- a/packages/@core/ui-kit/layout-ui/src/vben-layout.ts +++ b/packages/@core/ui-kit/layout-ui/src/vben-layout.ts @@ -6,170 +6,38 @@ import type { } from '@vben-core/typings'; interface VbenLayoutProps { - /** - * 内容区域定宽 - * @default 'wide' - */ contentCompact?: ContentCompactType; - /** - * 定宽布局宽度 - * @default 1200 - */ contentCompactWidth?: number; - /** - * padding - * @default 16 - */ contentPadding?: number; - /** - * paddingBottom - * @default 16 - */ contentPaddingBottom?: number; - /** - * paddingLeft - * @default 16 - */ contentPaddingLeft?: number; - /** - * paddingRight - * @default 16 - */ contentPaddingRight?: number; - /** - * paddingTop - * @default 16 - */ contentPaddingTop?: number; - /** - * footer 是否可见 - * @default false - */ footerEnable?: boolean; - /** - * footer 是否固定 - * @default true - */ footerFixed?: boolean; - /** - * footer 高度 - * @default 32 - */ footerHeight?: number; - /** - * header高度 - * @default 48 - */ headerHeight?: number; - /** - * 顶栏是否隐藏 - * @default false - */ headerHidden?: boolean; - /** - * header 显示模式 - * @default 'fixed' - */ headerMode?: LayoutHeaderModeType; - /** - * header 顶栏主题 - */ headerTheme?: ThemeModeType; - /** - * 是否显示header切换侧边栏按钮 - * @default - */ headerToggleSidebarButton?: boolean; - /** - * header是否显示 - * @default true - */ headerVisible?: boolean; - /** - * 是否移动端显示 - * @default false - */ isMobile?: boolean; - /** - * 布局方式 - * sidebar-nav 侧边菜单布局 - * header-nav 顶部菜单布局 - * mixed-nav 侧边&顶部菜单布局 - * sidebar-mixed-nav 侧边混合菜单布局 - * full-content 全屏内容布局 - * @default sidebar-nav - */ layout?: LayoutType; - /** - * 侧边菜单折叠状态 - * @default false - */ sidebarCollapse?: boolean; - /** - * 侧边菜单折叠按钮 - * @default true - */ sidebarCollapsedButton?: boolean; - /** - * 侧边菜单是否折叠时,是否显示title - * @default true - */ sidebarCollapseShowTitle?: boolean; - /** - * 侧边栏是否可见 - * @default true - */ sidebarEnable?: boolean; - /** - * 侧边菜单折叠额外宽度 - * @default 48 - */ sidebarExtraCollapsedWidth?: number; - /** - * 侧边菜单折叠按钮是否固定 - * @default true - */ sidebarFixedButton?: boolean; - /** - * 侧边栏是否隐藏 - * @default false - */ sidebarHidden?: boolean; - /** - * 混合侧边栏宽度 - * @default 80 - */ sidebarMixedWidth?: number; - /** - * 侧边栏 - * @default dark - */ sidebarTheme?: ThemeModeType; - /** - * 侧边栏宽度 - * @default 210 - */ sidebarWidth?: number; - /** - * 侧边菜单折叠宽度 - * @default 48 - */ sideCollapseWidth?: number; - /** - * tab是否可见 - * @default true - */ tabbarEnable?: boolean; - /** - * tab高度 - * @default 30 - */ tabbarHeight?: number; - /** - * zIndex - * @default 100 - */ zIndex?: number; } export type { VbenLayoutProps }; diff --git a/packages/@core/ui-kit/layout-ui/src/vben-layout.vue b/packages/@core/ui-kit/layout-ui/src/vben-layout.vue index a35ed34..7ab8fe9 100644 --- a/packages/@core/ui-kit/layout-ui/src/vben-layout.vue +++ b/packages/@core/ui-kit/layout-ui/src/vben-layout.vue @@ -102,9 +102,6 @@ const { isSidebarMixedNav, } = useLayout(props); -/** - * 顶栏是否自动隐藏 - */ const isHeaderAutoMode = computed(() => props.headerMode === 'auto'); const headerWrapperHeight = computed(() => { @@ -129,24 +126,15 @@ const getSideCollapseWidth = computed(() => { : sideCollapseWidth; }); -/** - * 动态获取侧边区域是否可见 - */ const sidebarEnableState = computed(() => { return !isHeaderNav.value && sidebarEnable.value; }); -/** - * 侧边区域离顶部高度 - */ const sidebarMarginTop = computed(() => { const { headerHeight, isMobile } = props; return isMixedNav.value && !isMobile ? headerHeight : 0; }); -/** - * 动态获取侧边宽度 - */ const getSidebarWidth = computed(() => { const { isMobile, sidebarHidden, sidebarMixedWidth, sidebarWidth } = props; let width = 0; @@ -175,18 +163,12 @@ const getSidebarWidth = computed(() => { return width; }); -/** - * 获取扩展区域宽度 - */ const sidebarExtraWidth = computed(() => { const { sidebarExtraCollapsedWidth, sidebarWidth } = props; return sidebarExtraCollapse.value ? sidebarExtraCollapsedWidth : sidebarWidth; }); -/** - * 是否侧边栏模式,包含混合侧边 - */ const isSideMode = computed( () => currentLayout.value === 'mixed-nav' || @@ -196,9 +178,6 @@ const isSideMode = computed( currentLayout.value === 'header-sidebar-nav', ); -/** - * header fixed值 - */ const headerFixed = computed(() => { const { headerMode } = props; return ( @@ -213,9 +192,6 @@ const showSidebar = computed(() => { return isSideMode.value && sidebarEnable.value && !props.sidebarHidden; }); -/** - * 遮罩可见性 - */ const maskVisible = computed(() => !sidebarCollapse.value && props.isMobile); const mainStyle = computed(() => { @@ -329,9 +305,6 @@ const headerWrapperStyle = computed((): CSSProperties => { }; }); -/** - * 侧边栏z-index - */ const sidebarZIndex = computed(() => { const { isMobile, zIndex } = props; let offset = isMobile || isSideMode.value ? 1 : -1; diff --git a/packages/@core/ui-kit/menu-ui/src/components/normal-menu/normal-menu.ts b/packages/@core/ui-kit/menu-ui/src/components/normal-menu/normal-menu.ts index 82edb4f..b3f4aa9 100644 --- a/packages/@core/ui-kit/menu-ui/src/components/normal-menu/normal-menu.ts +++ b/packages/@core/ui-kit/menu-ui/src/components/normal-menu/normal-menu.ts @@ -1,26 +1,10 @@ import type { MenuRecordRaw } from '@vben-core/typings'; interface NormalMenuProps { - /** - * 菜单数据 - */ activePath?: string; - /** - * 是否折叠 - */ collapse?: boolean; - /** - * 菜单项 - */ menus?: MenuRecordRaw[]; - /** - * @zh_CN 是否圆润风格 - * @default true - */ rounded?: boolean; - /** - * 主题 - */ theme?: 'dark' | 'light'; } diff --git a/packages/@core/ui-kit/menu-ui/src/hooks/use-menu-context.ts b/packages/@core/ui-kit/menu-ui/src/hooks/use-menu-context.ts index 357b296..a540d65 100644 --- a/packages/@core/ui-kit/menu-ui/src/hooks/use-menu-context.ts +++ b/packages/@core/ui-kit/menu-ui/src/hooks/use-menu-context.ts @@ -6,25 +6,16 @@ import { findComponentUpward } from '../utils'; const menuContextKey = Symbol('menuContext'); -/** - * @zh_CN Provide menu context - */ function createMenuContext(injectMenuData: MenuProvider) { provide(menuContextKey, injectMenuData); } -/** - * @zh_CN Provide menu context - */ function createSubMenuContext(injectSubMenuData: SubMenuProvider) { const instance = getCurrentInstance(); provide(`subMenu:${instance?.uid}`, injectSubMenuData); } -/** - * @zh_CN Inject menu context - */ function useMenuContext() { const instance = getCurrentInstance(); if (!instance) { @@ -34,9 +25,6 @@ function useMenuContext() { return rootMenu; } -/** - * @zh_CN Inject menu context - */ function useSubMenuContext() { const instance = getCurrentInstance(); if (!instance) { diff --git a/packages/@core/ui-kit/menu-ui/src/hooks/use-menu.ts b/packages/@core/ui-kit/menu-ui/src/hooks/use-menu.ts index 9207445..cc1416d 100644 --- a/packages/@core/ui-kit/menu-ui/src/hooks/use-menu.ts +++ b/packages/@core/ui-kit/menu-ui/src/hooks/use-menu.ts @@ -10,9 +10,6 @@ function useMenu() { throw new Error('instance is required'); } - /** - * @zh_CN 获取所有父级菜单链路 - */ const parentPaths = computed(() => { let parent = instance.parent; const paths: string[] = [instance.props.path as string]; diff --git a/packages/@core/ui-kit/menu-ui/src/sub-menu.vue b/packages/@core/ui-kit/menu-ui/src/sub-menu.vue index e4d471f..b7128b9 100644 --- a/packages/@core/ui-kit/menu-ui/src/sub-menu.vue +++ b/packages/@core/ui-kit/menu-ui/src/sub-menu.vue @@ -8,9 +8,6 @@ import { MenuBadge, MenuItem, SubMenu as SubMenuComp } from './components'; import SubMenu from './sub-menu.vue'; interface Props { - /** - * 菜单项 - */ menu: MenuRecordRaw; } @@ -20,9 +17,6 @@ defineOptions({ const props = withDefaults(defineProps(), {}); -/** - * 判断是否有子节点,动态渲染 menu-item/sub-menu-item - */ const hasChildren = computed(() => { const { menu } = props; return ( diff --git a/packages/@core/ui-kit/menu-ui/src/types.ts b/packages/@core/ui-kit/menu-ui/src/types.ts index f3b9c42..f4bca02 100644 --- a/packages/@core/ui-kit/menu-ui/src/types.ts +++ b/packages/@core/ui-kit/menu-ui/src/types.ts @@ -3,93 +3,35 @@ import type { Component, Ref } from 'vue'; import type { MenuRecordBadgeRaw, ThemeModeType } from '@vben-core/typings'; interface MenuProps { - /** - * @zh_CN 是否开启手风琴模式 - * @default true - */ accordion?: boolean; - /** - * @zh_CN 菜单是否折叠 - * @default false - */ collapse?: boolean; - /** - * @zh_CN 菜单折叠时是否显示菜单名称 - * @default false - */ collapseShowTitle?: boolean; - /** - * @zh_CN 默认激活的菜单 - */ defaultActive?: string; - /** - * @zh_CN 默认展开的菜单 - */ defaultOpeneds?: string[]; - /** - * @zh_CN 菜单模式 - * @default vertical - */ mode?: 'horizontal' | 'vertical'; - /** - * @zh_CN 是否圆润风格 - * @default true - */ rounded?: boolean; - /** - * @zh_CN 是否自动滚动到激活的菜单项 - * @default false - */ scrollToActive?: boolean; - /** - * @zh_CN 菜单主题 - * @default dark - */ theme?: ThemeModeType; } interface SubMenuProps extends MenuRecordBadgeRaw { - /** - * @zh_CN 激活图标 - */ activeIcon?: string; - /** - * @zh_CN 是否禁用 - */ disabled?: boolean; - /** - * @zh_CN 图标 - */ icon?: Component | string; - /** - * @zh_CN submenu 名称 - */ path: string; } interface MenuItemProps extends MenuRecordBadgeRaw { - /** - * @zh_CN 图标 - */ activeIcon?: string; - /** - * @zh_CN 是否禁用 - */ disabled?: boolean; - /** - * @zh_CN 图标 - */ icon?: Component | string; - /** - * @zh_CN menuitem 名称 - */ path: string; } diff --git a/packages/@core/ui-kit/menu-ui/src/utils/index.ts b/packages/@core/ui-kit/menu-ui/src/utils/index.ts index 23a1b15..235eb17 100644 --- a/packages/@core/ui-kit/menu-ui/src/utils/index.ts +++ b/packages/@core/ui-kit/menu-ui/src/utils/index.ts @@ -12,11 +12,6 @@ type RawSlots = Exclude | null | string>; type FlattenVNodes = Array; -/** - * @zh_CN Find the parent component upward - * @param instance - * @param parentNames - */ function findComponentUpward( instance: ComponentInternalInstance, parentNames: string[], diff --git a/packages/@core/ui-kit/popup-ui/src/alert/alert.ts b/packages/@core/ui-kit/popup-ui/src/alert/alert.ts index 5a214fa..4bd251c 100644 --- a/packages/@core/ui-kit/popup-ui/src/alert/alert.ts +++ b/packages/@core/ui-kit/popup-ui/src/alert/alert.ts @@ -11,75 +11,43 @@ export type BeforeCloseScope = { }; export type AlertProps = { - /** 关闭前的回调,如果返回false,则终止关闭 */ beforeClose?: ( scope: BeforeCloseScope, ) => boolean | Promise | undefined; - /** 边框 */ bordered?: boolean; - /** - * 按钮对齐方式 - * @default 'end' - */ buttonAlign?: 'center' | 'end' | 'start'; - /** 取消按钮的标题 */ cancelText?: string; - /** 是否居中显示 */ centered?: boolean; - /** 确认按钮的标题 */ confirmText?: string; - /** 弹窗容器的额外样式 */ containerClass?: string; - /** 弹窗提示内容 */ content: Component | string; - /** 弹窗内容的额外样式 */ contentClass?: string; - /** 执行beforeClose回调期间,在内容区域显示一个loading遮罩*/ contentMasking?: boolean; - /** 弹窗底部内容(与按钮在同一个容器中) */ footer?: Component | string; - /** 弹窗的图标(在标题的前面) */ icon?: Component | IconType; - /** - * 弹窗遮罩模糊效果 - */ overlayBlur?: number; - /** 是否显示取消按钮 */ showCancel?: boolean; - /** 弹窗标题 */ title?: string; }; -/** Prompt属性 */ export type PromptProps = { - /** 关闭前的回调,如果返回false,则终止关闭 */ beforeClose?: (scope: { isConfirm: boolean; value: T | undefined; }) => boolean | Promise | undefined; - /** 用于接受用户输入的组件 */ component?: Component; - /** 输入组件的属性 */ componentProps?: Recordable; - /** 输入组件的插槽 */ componentSlots?: | (() => any) | Recordable | VNode | VNodeArrayChildren; - /** 默认值 */ defaultValue?: T; - /** 输入组件的值属性名 */ modelPropName?: string; } & Omit; -/** - * Alert上下文 - */ export type AlertContext = { - /** 执行取消操作 */ doCancel: () => void; - /** 执行确认操作 */ doConfirm: () => void; }; diff --git a/packages/@core/ui-kit/popup-ui/src/drawer/drawer.ts b/packages/@core/ui-kit/popup-ui/src/drawer/drawer.ts index 89cd3b5..35ddc2b 100644 --- a/packages/@core/ui-kit/popup-ui/src/drawer/drawer.ts +++ b/packages/@core/ui-kit/popup-ui/src/drawer/drawer.ts @@ -9,130 +9,39 @@ export type DrawerPlacement = 'bottom' | 'left' | 'right' | 'top'; export type CloseIconPlacement = 'left' | 'right'; export interface DrawerProps { - /** - * 是否挂载到内容区域 - * @default false - */ appendToMain?: boolean; - /** - * 取消按钮文字 - */ cancelText?: string; class?: ClassType; - /** - * 是否显示关闭按钮 - * @default true - */ closable?: boolean; - /** - * 关闭按钮的位置 - */ closeIconPlacement?: CloseIconPlacement; - /** - * 点击弹窗遮罩是否关闭弹窗 - * @default true - */ closeOnClickModal?: boolean; - /** - * 按下 ESC 键是否关闭弹窗 - * @default true - */ closeOnPressEscape?: boolean; - /** - * 确定按钮 loading - * @default false - */ confirmLoading?: boolean; - /** - * 确定按钮文字 - */ confirmText?: string; contentClass?: string; - /** - * 弹窗描述 - */ description?: string; - /** - * 在关闭时销毁抽屉 - */ destroyOnClose?: boolean; - /** - * 是否显示底部 - * @default true - */ footer?: boolean; - /** - * 弹窗底部样式 - */ footerClass?: ClassType; - /** - * 是否显示顶栏 - * @default true - */ header?: boolean; - /** - * 弹窗头部样式 - */ headerClass?: ClassType; - /** - * 弹窗是否显示 - * @default false - */ loading?: boolean; - /** - * 是否显示遮罩 - * @default true - */ modal?: boolean; - /** - * 是否自动聚焦 - */ openAutoFocus?: boolean; - /** - * 弹窗遮罩模糊效果 - */ overlayBlur?: number; - /** - * 抽屉位置 - * @default right - */ placement?: DrawerPlacement; - /** - * 是否显示取消按钮 - * @default true - */ showCancelButton?: boolean; - /** - * 是否显示确认按钮 - * @default true - */ showConfirmButton?: boolean; - /** - * 提交中(锁定抽屉状态) - */ submitting?: boolean; - /** - * 弹窗标题 - */ title?: string; - /** - * 弹窗标题提示 - */ titleTooltip?: string; - /** - * 抽屉层级 - */ zIndex?: number; } export interface DrawerState extends DrawerProps { - /** 弹窗打开状态 */ isOpen?: boolean; - /** - * 共享数据 - */ sharedData?: Record; } @@ -143,37 +52,11 @@ export type ExtendedDrawerApi = DrawerApi & { }; export interface DrawerApiOptions extends DrawerState { - /** - * 独立的抽屉组件 - */ connectedComponent?: Component; - /** - * 关闭前的回调,返回 false 可以阻止关闭 - * @returns - */ onBeforeClose?: () => MaybePromise; - /** - * 点击取消按钮的回调 - */ onCancel?: () => void; - /** - * 弹窗关闭动画结束的回调 - * @returns - */ onClosed?: () => void; - /** - * 点击确定按钮的回调 - */ onConfirm?: () => void; - /** - * 弹窗状态变化回调 - * @param isOpen - * @returns - */ onOpenChange?: (isOpen: boolean) => void; - /** - * 弹窗打开动画结束的回调 - * @returns - */ onOpened?: () => void; } diff --git a/packages/@core/ui-kit/popup-ui/src/drawer/drawer.vue b/packages/@core/ui-kit/popup-ui/src/drawer/drawer.vue index ceca51e..dc74b05 100644 --- a/packages/@core/ui-kit/popup-ui/src/drawer/drawer.vue +++ b/packages/@core/ui-kit/popup-ui/src/drawer/drawer.vue @@ -103,9 +103,6 @@ const { // }, // ); -/** - * 在开启keepAlive情况下 直接通过浏览器按钮/手势等返回 不会关闭弹窗 - */ onDeactivated(() => { // 如果弹窗没有被挂载到内容区域,则关闭弹窗 if (!appendToMain.value) { @@ -153,9 +150,6 @@ const getAppendTo = computed(() => { : undefined; }); -/** - * destroyOnClose功能完善 - */ // 是否打开过 const hasOpened = ref(false); const isClosed = ref(true); diff --git a/packages/@core/ui-kit/popup-ui/src/modal/modal.ts b/packages/@core/ui-kit/popup-ui/src/modal/modal.ts index fa41344..838c6f0 100644 --- a/packages/@core/ui-kit/popup-ui/src/modal/modal.ts +++ b/packages/@core/ui-kit/popup-ui/src/modal/modal.ts @@ -5,149 +5,44 @@ import type { MaybePromise } from '@vben-core/typings'; import type { ModalApi } from './modal-api'; export interface ModalProps { - /** - * 动画类型 - * @default 'slide' - */ animationType?: 'scale' | 'slide'; - /** - * 是否要挂载到内容区域 - * @default false - */ appendToMain?: boolean; - /** - * 是否显示边框 - * @default false - */ bordered?: boolean; - /** - * 取消按钮文字 - */ cancelText?: string; - /** - * 是否居中 - * @default false - */ centered?: boolean; class?: string; - /** - * 是否显示右上角的关闭按钮 - * @default true - */ closable?: boolean; - /** - * 点击弹窗遮罩是否关闭弹窗 - * @default true - */ closeOnClickModal?: boolean; - /** - * 按下 ESC 键是否关闭弹窗 - * @default true - */ closeOnPressEscape?: boolean; - /** - * 禁用确认按钮 - */ confirmDisabled?: boolean; - /** - * 确定按钮 loading - * @default false - */ confirmLoading?: boolean; - /** - * 确定按钮文字 - */ confirmText?: string; contentClass?: string; - /** - * 弹窗描述 - */ description?: string; - /** - * 在关闭时销毁弹窗 - */ destroyOnClose?: boolean; - /** - * 是否可拖拽 - * @default false - */ draggable?: boolean; - /** - * 是否显示底部 - * @default true - */ footer?: boolean; footerClass?: string; - /** - * 是否全屏 - * @default false - */ fullscreen?: boolean; - /** - * 是否显示全屏按钮 - * @default true - */ fullscreenButton?: boolean; - /** - * 是否显示顶栏 - * @default true - */ header?: boolean; headerClass?: string; - /** - * 弹窗是否显示 - * @default false - */ loading?: boolean; - /** - * 是否显示遮罩 - * @default true - */ modal?: boolean; - /** - * 是否自动聚焦 - */ openAutoFocus?: boolean; - /** - * 弹窗遮罩模糊效果 - */ overlayBlur?: number; - /** - * 是否显示取消按钮 - * @default true - */ showCancelButton?: boolean; - /** - * 是否显示确认按钮 - * @default true - */ showConfirmButton?: boolean; - /** - * 提交中(锁定弹窗状态) - */ submitting?: boolean; - /** - * 弹窗标题 - */ title?: string; - /** - * 弹窗标题提示 - */ titleTooltip?: string; - /** - * 弹窗层级 - */ zIndex?: number; } export interface ModalState extends ModalProps { - /** 弹窗打开状态 */ isOpen?: boolean; - /** - * 共享数据 - */ sharedData?: Record; } @@ -158,37 +53,11 @@ export type ExtendedModalApi = ModalApi & { }; export interface ModalApiOptions extends ModalState { - /** - * 独立的弹窗组件 - */ connectedComponent?: Component; - /** - * 关闭前的回调,返回 false 可以阻止关闭 - * @returns - */ onBeforeClose?: () => MaybePromise; - /** - * 点击取消按钮的回调 - */ onCancel?: () => void; - /** - * 弹窗关闭动画结束的回调 - * @returns - */ onClosed?: () => void; - /** - * 点击确定按钮的回调 - */ onConfirm?: () => void; - /** - * 弹窗状态变化回调 - * @param isOpen - * @returns - */ onOpenChange?: (isOpen: boolean) => void; - /** - * 弹窗打开动画结束的回调 - * @returns - */ onOpened?: () => void; } diff --git a/packages/@core/ui-kit/popup-ui/src/modal/modal.vue b/packages/@core/ui-kit/popup-ui/src/modal/modal.vue index e93e4c1..3ad28e2 100644 --- a/packages/@core/ui-kit/popup-ui/src/modal/modal.vue +++ b/packages/@core/ui-kit/popup-ui/src/modal/modal.vue @@ -159,9 +159,6 @@ watch( // }, // ); -/** - * 在开启keepAlive情况下 直接通过浏览器按钮/手势等返回 不会关闭弹窗 - */ onDeactivated(() => { // 如果弹窗没有被挂载到内容区域,则关闭弹窗 if (!appendToMain.value) { diff --git a/packages/@core/ui-kit/popup-ui/src/modal/use-modal-draggable.ts b/packages/@core/ui-kit/popup-ui/src/modal/use-modal-draggable.ts index 84910b7..6481c31 100644 --- a/packages/@core/ui-kit/popup-ui/src/modal/use-modal-draggable.ts +++ b/packages/@core/ui-kit/popup-ui/src/modal/use-modal-draggable.ts @@ -1,8 +1,3 @@ -/** - * @copy https://github.com/element-plus/element-plus/blob/dev/packages/hooks/use-draggable/index.ts - * 调整部分细节 - */ - import type { ComputedRef, Ref } from 'vue'; import { onBeforeUnmount, onMounted, reactive, ref, watchEffect } from 'vue'; diff --git a/packages/@core/ui-kit/shadcn-ui/src/components/back-top/backtop.ts b/packages/@core/ui-kit/shadcn-ui/src/components/back-top/backtop.ts index de422c0..55bd4b1 100644 --- a/packages/@core/ui-kit/shadcn-ui/src/components/back-top/backtop.ts +++ b/packages/@core/ui-kit/shadcn-ui/src/components/back-top/backtop.ts @@ -1,28 +1,16 @@ export const backtopProps = { - /** - * @zh_CN bottom distance. - */ bottom: { default: 40, type: Number, }, - /** - * @zh_CN right distance. - */ right: { default: 40, type: Number, }, - /** - * @zh_CN the target to trigger scroll. - */ target: { default: '', type: String, }, - /** - * @zh_CN the button will not show until the scroll height reaches this value. - */ visibilityHeight: { default: 200, type: Number, diff --git a/packages/@core/ui-kit/shadcn-ui/src/components/button/button.ts b/packages/@core/ui-kit/shadcn-ui/src/components/button/button.ts index a55a4d2..b65eacc 100644 --- a/packages/@core/ui-kit/shadcn-ui/src/components/button/button.ts +++ b/packages/@core/ui-kit/shadcn-ui/src/components/button/button.ts @@ -5,16 +5,7 @@ import type { Component } from 'vue'; import type { ButtonVariants, ButtonVariantSize } from '../../ui'; export interface VbenButtonProps { - /** - * The element or component this component should render as. Can be overwrite by `asChild` - * @defaultValue "div" - */ as?: AsTag | Component; - /** - * Change the default rendered element for the one passed as a child, merging their props and behavior. - * - * Read our [Composition](https://www.reka-ui.com/docs/guides/composition) guide for more details. - */ asChild?: boolean; class?: any; disabled?: boolean; @@ -31,25 +22,16 @@ export interface VbenButtonGroupProps extends Pick< VbenButtonProps, 'disabled' > { - /** 单选模式下允许清除选中 */ allowClear?: boolean; - /** 值改变前的回调 */ beforeChange?: ( value: ValueType, isChecked: boolean, ) => boolean | PromiseLike | undefined; - /** 按钮样式 */ btnClass?: any; - /** 按钮间隔距离 */ gap?: number; - /** 多选模式下限制最多选择的数量。0表示不限制 */ maxCount?: number; - /** 是否允许多选 */ multiple?: boolean; - /** 选项 */ options?: { [key: string]: any; label: CustomRenderType; value: ValueType }[]; - /** 显示图标 */ showIcon?: boolean; - /** 尺寸 */ size?: 'large' | 'middle' | 'small'; } diff --git a/packages/@core/ui-kit/shadcn-ui/src/components/context-menu/interface.ts b/packages/@core/ui-kit/shadcn-ui/src/components/context-menu/interface.ts index 4aa4110..649c6de 100644 --- a/packages/@core/ui-kit/shadcn-ui/src/components/context-menu/interface.ts +++ b/packages/@core/ui-kit/shadcn-ui/src/components/context-menu/interface.ts @@ -1,42 +1,14 @@ import type { Component } from 'vue'; interface IContextMenuItem { - /** - * @zh_CN 是否禁用 - */ disabled?: boolean; - /** - * @zh_CN 点击事件处理 - * @param data - */ handler?: (data: any) => void; - /** - * @zh_CN 是否隐藏 - */ hidden?: boolean; - /** - * @zh_CN 图标 - */ icon?: Component; - /** - * @zh_CN 是否显示图标 - */ inset?: boolean; - /** - * @zh_CN 唯一标识 - */ key: string; - /** - * @zh_CN 是否是分割线 - */ separator?: boolean; - /** - * @zh_CN 快捷键 - */ shortcut?: string; - /** - * @zh_CN 标题 - */ text: string; } export type { IContextMenuItem }; diff --git a/packages/@core/ui-kit/shadcn-ui/src/components/count-to-animator/count-to-animator.vue b/packages/@core/ui-kit/shadcn-ui/src/components/count-to-animator/count-to-animator.vue index 50fece6..fc2fa6e 100644 --- a/packages/@core/ui-kit/shadcn-ui/src/components/count-to-animator/count-to-animator.vue +++ b/packages/@core/ui-kit/shadcn-ui/src/components/count-to-animator/count-to-animator.vue @@ -39,13 +39,7 @@ const props = withDefaults(defineProps(), { const emit = defineEmits<{ finished: []; - /** - * @deprecated 请使用{@link finished}事件 - */ onFinished: []; - /** - * @deprecated 请使用{@link started}事件 - */ onStarted: []; started: []; }>(); diff --git a/packages/@core/ui-kit/shadcn-ui/src/components/dropdown-menu/interface.ts b/packages/@core/ui-kit/shadcn-ui/src/components/dropdown-menu/interface.ts index 01a31a1..1eed959 100644 --- a/packages/@core/ui-kit/shadcn-ui/src/components/dropdown-menu/interface.ts +++ b/packages/@core/ui-kit/shadcn-ui/src/components/dropdown-menu/interface.ts @@ -2,26 +2,10 @@ import type { Component } from 'vue'; interface VbenDropdownMenuItem { disabled?: boolean; - /** - * @zh_CN 点击事件处理 - * @param data - */ handler?: (data: any) => void; - /** - * @zh_CN 图标 - */ icon?: Component; - /** - * @zh_CN 标题 - */ label: string; - /** - * @zh_CN 是否是分割线 - */ separator?: boolean; - /** - * @zh_CN 唯一标识 - */ value: string; } diff --git a/packages/@core/ui-kit/shadcn-ui/src/components/input-password/input-password.vue b/packages/@core/ui-kit/shadcn-ui/src/components/input-password/input-password.vue index e9ff3fb..eb48515 100644 --- a/packages/@core/ui-kit/shadcn-ui/src/components/input-password/input-password.vue +++ b/packages/@core/ui-kit/shadcn-ui/src/components/input-password/input-password.vue @@ -9,9 +9,6 @@ import PasswordStrength from './password-strength.vue'; interface Props { class?: any; - /** - * 是否显示密码强度 - */ passwordStrength?: boolean; } diff --git a/packages/@core/ui-kit/shadcn-ui/src/components/input-password/password-strength.vue b/packages/@core/ui-kit/shadcn-ui/src/components/input-password/password-strength.vue index 4b0be20..84733c7 100644 --- a/packages/@core/ui-kit/shadcn-ui/src/components/input-password/password-strength.vue +++ b/packages/@core/ui-kit/shadcn-ui/src/components/input-password/password-strength.vue @@ -22,9 +22,6 @@ const currentColor = computed(() => { return strengthList[currentStrength.value]; }); -/** - * Check the strength of a password - */ function checkPasswordStrength(password: string) { let strength = 0; diff --git a/packages/@core/ui-kit/shadcn-ui/src/components/logo/logo.vue b/packages/@core/ui-kit/shadcn-ui/src/components/logo/logo.vue index 0bca091..6a542ce 100644 --- a/packages/@core/ui-kit/shadcn-ui/src/components/logo/logo.vue +++ b/packages/@core/ui-kit/shadcn-ui/src/components/logo/logo.vue @@ -4,37 +4,13 @@ import { computed } from 'vue'; import { VbenAvatar } from '../avatar'; interface Props { - /** - * @zh_CN 是否收起文本 - */ collapsed?: boolean; - /** - * @zh_CN Logo 图片适应方式 - */ fit?: 'contain' | 'cover' | 'fill' | 'none' | 'scale-down'; - /** - * @zh_CN Logo 跳转地址 - */ href?: string; - /** - * @zh_CN Logo 图片大小 - */ logoSize?: number; - /** - * @zh_CN Logo 图标 - */ src?: string; - /** - * @zh_CN 暗色主题 Logo 图标 (可选,若不设置则使用 src) - */ srcDark?: string; - /** - * @zh_CN Logo 文本 - */ text: string; - /** - * @zh_CN Logo 主题 - */ theme?: string; } @@ -52,9 +28,6 @@ const props = withDefaults(defineProps(), { fit: 'cover', }); -/** - * @zh_CN 根据主题选择合适的 logo 图标 - */ const logoSrc = computed(() => { // 如果是暗色主题且提供了 srcDark,则使用暗色主题的 logo if (props.theme === 'dark' && props.srcDark) { diff --git a/packages/@core/ui-kit/shadcn-ui/src/components/pin-input/types.ts b/packages/@core/ui-kit/shadcn-ui/src/components/pin-input/types.ts index 182d884..8ffdd61 100644 --- a/packages/@core/ui-kit/shadcn-ui/src/components/pin-input/types.ts +++ b/packages/@core/ui-kit/shadcn-ui/src/components/pin-input/types.ts @@ -1,29 +1,10 @@ interface PinInputProps { class?: any; - /** - * 验证码长度 - */ codeLength?: number; - /** - * 发送验证码按钮文本 - */ createText?: (countdown: number) => string; - /** - * 是否禁用 - */ disabled?: boolean; - /** - * 自定义验证码发送逻辑 - * @returns - */ handleSendCode?: () => Promise; - /** - * 发送验证码按钮loading - */ loading?: boolean; - /** - * 最大重试时间 - */ maxTime?: number; } diff --git a/packages/@core/ui-kit/shadcn-ui/src/components/scrollbar/scrollbar.vue b/packages/@core/ui-kit/shadcn-ui/src/components/scrollbar/scrollbar.vue index 792ad21..b7f4cb9 100644 --- a/packages/@core/ui-kit/shadcn-ui/src/components/scrollbar/scrollbar.vue +++ b/packages/@core/ui-kit/shadcn-ui/src/components/scrollbar/scrollbar.vue @@ -39,12 +39,6 @@ const isAtRight = ref(false); const isAtBottom = ref(false); const isAtLeft = ref(true); -/** - * We have to check if the scroll amount is close enough to some threshold in order to - * more accurately calculate arrivedState. This is because scrollTop/scrollLeft are non-rounded - * numbers, while scrollHeight/scrollWidth and clientHeight/clientWidth are rounded. - * https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight#determine_if_an_element_has_been_totally_scrolled - */ const ARRIVED_STATE_THRESHOLD_PIXELS = 1; const showShadowTop = computed(() => props.shadow && props.shadowTop); diff --git a/packages/@core/ui-kit/shadcn-ui/src/components/spinner/loading.vue b/packages/@core/ui-kit/shadcn-ui/src/components/spinner/loading.vue index 1544f34..8b258fe 100644 --- a/packages/@core/ui-kit/shadcn-ui/src/components/spinner/loading.vue +++ b/packages/@core/ui-kit/shadcn-ui/src/components/spinner/loading.vue @@ -5,19 +5,9 @@ import { cn } from '@vben-core/shared/utils'; interface Props { class?: string; - /** - * @zh_CN 最小加载时间 - * @en_US Minimum loading time - */ minLoadingTime?: number; - /** - * @zh_CN loading状态开启 - */ spinning?: boolean; - /** - * @zh_CN 文字 - */ text?: string; } diff --git a/packages/@core/ui-kit/shadcn-ui/src/components/spinner/spinner.vue b/packages/@core/ui-kit/shadcn-ui/src/components/spinner/spinner.vue index 7e5ce3b..ab9e11e 100644 --- a/packages/@core/ui-kit/shadcn-ui/src/components/spinner/spinner.vue +++ b/packages/@core/ui-kit/shadcn-ui/src/components/spinner/spinner.vue @@ -5,14 +5,7 @@ import { cn } from '@vben-core/shared/utils'; interface Props { class?: string; - /** - * @zh_CN 最小加载时间 - * @en_US Minimum loading time - */ minLoadingTime?: number; - /** - * @zh_CN loading状态开启 - */ spinning?: boolean; } diff --git a/packages/@core/ui-kit/shadcn-ui/src/ui/tree/types.ts b/packages/@core/ui-kit/shadcn-ui/src/ui/tree/types.ts index 53118ba..4ec3f7c 100644 --- a/packages/@core/ui-kit/shadcn-ui/src/ui/tree/types.ts +++ b/packages/@core/ui-kit/shadcn-ui/src/ui/tree/types.ts @@ -4,40 +4,23 @@ import type { FlattenedItem } from 'reka-ui'; import type { Recordable } from '@vben-core/typings'; export interface TreeProps { - /** 单选时允许取消已有选项 */ allowClear?: boolean; - /** 非关联选择时,自动选中上级节点 */ autoCheckParent?: boolean; - /** 显示边框 */ bordered?: boolean; - /** 取消父子关联选择 */ checkStrictly?: boolean; - /** 子级字段名 */ childrenField?: string; - /** 默认展开的键 */ defaultExpandedKeys?: Array; - /** 默认展开的级别(优先级高于defaultExpandedKeys) */ defaultExpandedLevel?: number; - /** 默认值 */ defaultValue?: Arrayable; - /** 禁用 */ disabled?: boolean; - /** 禁用字段名 */ disabledField?: string; - /** 自定义节点类名 */ getNodeClass?: (item: FlattenedItem>) => string; iconField?: string; - /** label字段 */ labelField?: string; - /** 是否多选 */ multiple?: boolean; - /** 显示由iconField指定的图标 */ showIcon?: boolean; - /** 启用展开收缩动画 */ transition?: boolean; - /** 树数据 */ treeData: Recordable[]; - /** 值字段 */ valueField?: string; } diff --git a/packages/@core/ui-kit/tabs-ui/src/types.ts b/packages/@core/ui-kit/tabs-ui/src/types.ts index 19ecf03..978d26b 100644 --- a/packages/@core/ui-kit/tabs-ui/src/types.ts +++ b/packages/@core/ui-kit/tabs-ui/src/types.ts @@ -9,58 +9,20 @@ export type TabsEmits = { export interface TabsProps { active?: string; - /** - * @zh_CN content class - * @default tabs-chrome - */ contentClass?: string; - /** - * @zh_CN 右键菜单 - */ contextMenus?: (data: any) => IContextMenuItem[]; - /** - * @zh_CN 是否可以拖拽 - */ draggable?: boolean; - /** - * @zh_CN 间隙 - * @default 7 - * 仅限 tabs-chrome - */ gap?: number; - /** - * @zh_CN tab 最大宽度 - * 仅限 tabs-chrome - */ maxWidth?: number; - /** - * @zh_CN 点击中键时关闭Tab - */ middleClickToClose?: boolean; - /** - * @zh_CN tab最小宽度 - * 仅限 tabs-chrome - */ minWidth?: number; - /** - * @zh_CN 是否显示图标 - */ showIcon?: boolean; - /** - * @zh_CN 标签页风格 - */ styleType?: TabsStyleType; - /** - * @zh_CN 选项卡数据 - */ tabs?: TabDefinition[]; - /** - * @zh_CN 是否响应滚轮事件 - */ wheelable?: boolean; } diff --git a/packages/constants/src/core.ts b/packages/constants/src/core.ts index 3861466..d956b5d 100644 --- a/packages/constants/src/core.ts +++ b/packages/constants/src/core.ts @@ -1,6 +1,3 @@ -/** - * @zh_CN 登录页面 url 地址 - */ export const LOGIN_PATH = '/auth/login'; export interface LanguageOption { @@ -8,9 +5,6 @@ export interface LanguageOption { value: 'en-US' | 'zh-CN'; } -/** - * Supported languages - */ export const SUPPORT_LANGUAGES: LanguageOption[] = [ { label: '简体中文', diff --git a/packages/effects/access/src/access-control.vue b/packages/effects/access/src/access-control.vue index 219608e..68af2b8 100644 --- a/packages/effects/access/src/access-control.vue +++ b/packages/effects/access/src/access-control.vue @@ -11,16 +11,8 @@ import { computed } from 'vue'; import { useAccess } from './use-access'; interface Props { - /** - * Specified codes is visible - * @default [] - */ codes?: string[]; - /** - * 通过什么方式来控制组件,如果是 role,则传入角色,如果是 code,则传入权限码 - * @default 'role' - */ type?: 'code' | 'role'; } diff --git a/packages/effects/access/src/accessible.ts b/packages/effects/access/src/accessible.ts index eb90814..2c07f3f 100644 --- a/packages/effects/access/src/accessible.ts +++ b/packages/effects/access/src/accessible.ts @@ -71,11 +71,6 @@ async function generateAccessible( return { accessibleMenus, accessibleRoutes }; } -/** - * Generate routes - * @param mode - * @param options - */ async function generateRoutes( mode: AccessModeType, options: GenerateMenuAndRoutesOptions, @@ -107,11 +102,6 @@ async function generateRoutes( } } - /** - * 调整路由树,做以下处理: - * 1. 对未添加redirect的路由添加redirect - * 2. 将懒加载的组件名称修改为当前路由的名称(如果启用了keep-alive的话) - */ resultRoutes = mapTree(resultRoutes, (route) => { // 重新包装component,使用与路由名称相同的name以支持keep-alive的条件缓存。 if ( diff --git a/packages/effects/access/src/directive.ts b/packages/effects/access/src/directive.ts index 35d9d51..776653b 100644 --- a/packages/effects/access/src/directive.ts +++ b/packages/effects/access/src/directive.ts @@ -1,9 +1,3 @@ -/** - * Global authority directive - * Used for fine-grained control of component permissions - * @Example v-access:role="[ROLE_NAME]" or v-access:role="ROLE_NAME" - * @Example v-access:code="[ROLE_CODE]" or v-access:code="ROLE_CODE" - */ import type { App, Directive, DirectiveBinding } from 'vue'; import { useAccess } from './use-access'; diff --git a/packages/effects/common-ui/src/components/api-component/api-component.vue b/packages/effects/common-ui/src/components/api-component/api-component.vue index 38419a7..934b1e2 100644 --- a/packages/effects/common-ui/src/components/api-component/api-component.vue +++ b/packages/effects/common-ui/src/components/api-component/api-component.vue @@ -20,50 +20,24 @@ type OptionsItem = { }; interface Props { - /** 组件 */ component: Component; - /** 是否将value从数字转为string */ numberToString?: boolean; - /** 获取options数据的函数 */ api?: (arg?: any) => Promise>; - /** 传递给api的参数 */ params?: Record; - /** 从api返回的结果中提取options数组的字段名 */ resultField?: string; - /** label字段名 */ labelField?: string; - /** children字段名,需要层级数据的组件可用 */ childrenField?: string; - /** value字段名 */ valueField?: string; - /** disabled字段名 */ disabledField?: string; - /** 组件接收options数据的属性名 */ optionsPropName?: string; - /** 是否立即调用api */ immediate?: boolean; - /** 每次`visibleEvent`事件发生时都重新请求数据 */ alwaysLoad?: boolean; - /** 在api请求之前的回调函数 */ beforeFetch?: AnyPromiseFunction; - /** 在api请求之后的回调函数 */ afterFetch?: AnyPromiseFunction; - /** 直接传入选项数据,也作为api返回空数据时的后备数据 */ options?: OptionsItem[]; - /** 组件的插槽名称,用来显示一个"加载中"的图标 */ loadingSlot?: string; - /** 触发api请求的事件名 */ visibleEvent?: string; - /** 组件的v-model属性名,默认为modelValue。部分组件可能为value */ modelPropName?: string; - /** - * 自动选择 - * - `first`:自动选择第一个选项 - * - `last`:自动选择最后一个选项 - * - `one`: 当请求的结果只有一个选项时,自动选择该选项 - * - 函数:自定义选择逻辑,函数的参数为请求的结果数组,返回值为选择的选项 - * - false:不自动选择(默认) - */ autoSelect?: | 'first' | 'last' @@ -270,11 +244,8 @@ function emitChange() { } const componentRef = ref(); defineExpose({ - /** 获取options数据 */ getOptions: () => unref(getOptions), - /** 获取当前值 */ getValue: () => unref(modelValue), - /** 获取被包装的组件实例 */ getComponentRef: () => componentRef.value as T, /** 更新Api参数 */ updateParam(newParams: Record) { diff --git a/packages/effects/common-ui/src/components/captcha/types.ts b/packages/effects/common-ui/src/components/captcha/types.ts index f73877e..d786b19 100644 --- a/packages/effects/common-ui/src/components/captcha/types.ts +++ b/packages/effects/common-ui/src/components/captcha/types.ts @@ -3,194 +3,67 @@ import type { CSSProperties } from 'vue'; import type { ClassType } from '@vben/types'; export interface CaptchaData { - /** - * x - */ x: number; - /** - * y - */ y: number; - /** - * 时间戳 - */ t: number; } export interface CaptchaPoint extends CaptchaData { - /** - * 数据索引 - */ i: number; } export interface PointSelectionCaptchaCardProps { - /** - * 验证码图片 - */ captchaImage: string; - /** - * 验证码图片高度 - * @default '220px' - */ height?: number | string; - /** - * 水平内边距 - * @default '12px' - */ paddingX?: number | string; - /** - * 垂直内边距 - * @default '16px' - */ paddingY?: number | string; - /** - * 标题 - * @default '请按图依次点击' - */ title?: string; - /** - * 验证码图片宽度 - * @default '300px' - */ width?: number | string; } export interface PointSelectionCaptchaProps extends PointSelectionCaptchaCardProps { - /** - * 是否展示确定按钮 - * @default false - */ showConfirm?: boolean; - /** - * 提示图片 - * @default '' - */ hintImage?: string; - /** - * 提示文本 - * @default '' - */ hintText?: string; } export interface SliderCaptchaProps { class?: ClassType; - /** - * @description 滑块的样式 - * @default {} - */ actionStyle?: CSSProperties; - /** - * @description 滑块条的样式 - * @default {} - */ barStyle?: CSSProperties; - /** - * @description 内容的样式 - * @default {} - */ contentStyle?: CSSProperties; - /** - * @description 组件的样式 - * @default {} - */ wrapperStyle?: CSSProperties; - /** - * @description 是否作为插槽使用,用于联动组件,可参考旋转校验组件 - * @default false - */ isSlot?: boolean; - /** - * @description 验证成功的提示 - * @default '验证通过' - */ successText?: string; - /** - * @description 提示文字 - * @default '请按住滑块拖动' - */ text?: string; } export interface SliderRotateCaptchaProps { - /** - * @description 旋转的角度 - * @default 20 - */ diffDegree?: number; - /** - * @description 图片的宽度 - * @default 260 - */ imageSize?: number; - /** - * @description 图片的样式 - * @default {} - */ imageWrapperStyle?: CSSProperties; - /** - * @description 最大旋转角度 - * @default 270 - */ maxDegree?: number; - /** - * @description 最小旋转角度 - * @default 90 - */ minDegree?: number; - /** - * @description 图片的地址 - */ src?: string; - /** - * @description 默认提示文本 - */ defaultTip?: string; } export interface SliderTranslateCaptchaProps { - /** - * @description 拼图的宽度 - * @default 420 - */ canvasWidth?: number; - /** - * @description 拼图的高度 - * @default 280 - */ canvasHeight?: number; - /** - * @description 切块上正方形的长度 - * @default 42 - */ squareLength?: number; - /** - * @description 切块上圆形的半径 - * @default 10 - */ circleRadius?: number; - /** - * @description 图片的地址 - */ src?: string; - /** - * @description 允许的最大差距 - * @default 3 - */ diffDistance?: number; - /** - * @description 默认提示文本 - */ defaultTip?: string; } diff --git a/packages/effects/common-ui/src/components/col-page/types.ts b/packages/effects/common-ui/src/components/col-page/types.ts index 491d1e6..01e848e 100644 --- a/packages/effects/common-ui/src/components/col-page/types.ts +++ b/packages/effects/common-ui/src/components/col-page/types.ts @@ -1,19 +1,11 @@ import type { PageProps } from '../page/types'; export interface ColPageProps extends PageProps { - /** - * 左侧宽度 - * @default 30 - */ leftWidth?: number; leftMinWidth?: number; leftMaxWidth?: number; leftCollapsedWidth?: number; leftCollapsible?: boolean; - /** - * 右侧宽度 - * @default 70 - */ rightWidth?: number; rightMinWidth?: number; rightCollapsedWidth?: number; diff --git a/packages/effects/common-ui/src/components/count-to/types.ts b/packages/effects/common-ui/src/components/count-to/types.ts index 0b3bd82..c7a8368 100644 --- a/packages/effects/common-ui/src/components/count-to/types.ts +++ b/packages/effects/common-ui/src/components/count-to/types.ts @@ -11,43 +11,24 @@ export const TransitionPresetsKeys = Object.keys( ) as TransitionPresets[]; export interface CountToProps { - /** 初始值 */ startVal?: number; - /** 当前值 */ endVal: number; - /** 是否禁用动画 */ disabled?: boolean; - /** 延迟动画开始的时间 */ delay?: number; - /** 持续时间 */ duration?: number; - /** 小数位数 */ decimals?: number; - /** 小数点 */ decimal?: string; - /** 分隔符 */ separator?: string; - /** 前缀 */ prefix?: string; - /** 后缀 */ suffix?: string; - /** 过渡效果 */ transition?: CubicBezierPoints | EasingFunction | TransitionPresets; - /** 整数部分的类名 */ mainClass?: string; - /** 小数部分的类名 */ decimalClass?: string; - /** 前缀部分的类名 */ prefixClass?: string; - /** 后缀部分的类名 */ suffixClass?: string; - /** 整数部分的样式 */ mainStyle?: StyleValue; - /** 小数部分的样式 */ decimalStyle?: StyleValue; - /** 前缀部分的样式 */ prefixStyle?: StyleValue; - /** 后缀部分的样式 */ suffixStyle?: StyleValue; } diff --git a/packages/effects/common-ui/src/components/cropper/cropper.vue b/packages/effects/common-ui/src/components/cropper/cropper.vue index 1b46705..cef3567 100644 --- a/packages/effects/common-ui/src/components/cropper/cropper.vue +++ b/packages/effects/common-ui/src/components/cropper/cropper.vue @@ -3,13 +3,9 @@ import { onMounted, onUnmounted, ref, watch } from 'vue'; // 定义组件参数 const props = defineProps<{ - /** 裁剪比例 格式如 '1:1', '16:9', '3:4' 等(非必填) */ aspectRatio?: string; - /** 容器高度(默认400) */ height?: number; - /** 图片地址 */ img: string; - /** 容器宽度(默认500) */ width?: number; }>(); @@ -66,9 +62,6 @@ const startDimension = ref([0, 0, 0, 0]); const direction = ref([0, 0, 0, 0]); const moving = ref(false); -/** - * 计算图片的适配尺寸,保证完整显示且不超过最大宽高限制 - */ const calculateImageFitSize = () => { if (!bgImageRef.value) return; @@ -103,10 +96,6 @@ const calculateImageFitSize = () => { currentDimension.value = [padding, padding, padding, padding]; }; -/** - * 验证并解析比例字符串 - * @returns {number|null} 比例值 (width/height),解析失败返回null - */ const parseAndValidateAspectRatio = (): null | number => { // 如果未传入比例参数,直接返回null if (!props.aspectRatio) { @@ -132,10 +121,6 @@ const parseAndValidateAspectRatio = (): null | number => { return width / height; }; -/** - * 设置裁剪区域尺寸 - * @param {Dimension} dimension - [top, right, bottom, left] - */ const setDimension = (dimension: Dimension) => { currentDimension.value = [...dimension]; if (maskViewRef.value) { @@ -143,9 +128,6 @@ const setDimension = (dimension: Dimension) => { } }; -/** - * 调整裁剪区域至指定比例 - */ const adjustCropperToAspectRatio = () => { if (!cropperRef.value) return; @@ -185,9 +167,6 @@ const adjustCropperToAspectRatio = () => { setDimension(newDimension); }; -/** - * 创建裁剪器 - */ const createCropper = () => { // 计算图片适配尺寸 calculateImageFitSize(); @@ -196,11 +175,6 @@ const createCropper = () => { adjustCropperToAspectRatio(); }; -/** - * 处理鼠标按下事件 - * @param {MouseEvent} e - 鼠标事件 - * @param {DragAction} action - 操作类型 - */ const handleMouseDown = (e: MouseEvent, action: DragAction) => { dragging.value = true; startPoint.value = [e.clientX, e.clientY]; @@ -259,10 +233,6 @@ const handleMouseDown = (e: MouseEvent, action: DragAction) => { } }; -/** - * 处理鼠标移动事件 - * @param {MouseEvent} e - 鼠标事件 - */ const handleMouseMove = (e: MouseEvent) => { if (!dragging.value || !cropperRef.value) return; @@ -503,30 +473,16 @@ const handleFixedAspectResize = (diffX: number, diffY: number) => { setDimension(newDimension); }; -/** - * 处理鼠标抬起事件 - */ const handleMouseUp = () => { dragging.value = false; moving.value = false; direction.value = [0, 0, 0, 0]; }; -/** - * 处理图片加载完成 - */ const handleImageLoad = () => { createCropper(); }; -/** - * 裁剪图片 - * @param {'image/jpeg' | 'image/png'} format - 输出图片格式 - * @param {number} quality - 压缩质量(0-1) - * @param {'blob' | 'base64'} outputType - 输出类型 - * @param {number} targetWidth - 目标宽度(可选,不传则为原始裁剪宽度) - * @param {number} targetHeight - 目标高度(可选,不传则为原始裁剪高度) - */ const getCropImage = async ( format: 'image/jpeg' | 'image/png' = 'image/jpeg', quality: number = 0.92, diff --git a/packages/effects/common-ui/src/components/ellipsis-text/ellipsis-text.vue b/packages/effects/common-ui/src/components/ellipsis-text/ellipsis-text.vue index 12f44bd..3be745d 100644 --- a/packages/effects/common-ui/src/components/ellipsis-text/ellipsis-text.vue +++ b/packages/effects/common-ui/src/components/ellipsis-text/ellipsis-text.vue @@ -15,61 +15,17 @@ import { VbenTooltip } from '@vben-core/shadcn-ui'; import { useElementSize } from '@vueuse/core'; interface Props { - /** - * 是否启用点击文本展开全部 - * @default false - */ expand?: boolean; - /** - * 文本最大行数 - * @default 1 - */ line?: number; - /** - * 文本最大宽度 - * @default '100%' - */ maxWidth?: number | string; - /** - * 提示框位置 - * @default 'top' - */ placement?: 'bottom' | 'left' | 'right' | 'top'; - /** - * 是否启用文本提示框 - * @default true - */ tooltip?: boolean; - /** - * 是否只在文本被截断时显示提示框 - * @default false - */ tooltipWhenEllipsis?: boolean; - /** - * 文本截断检测的像素差异阈值,越大则判断越严格 - * @default 3 - */ ellipsisThreshold?: number; - /** - * 提示框背景颜色,优先级高于 overlayStyle - */ tooltipBackgroundColor?: string; - /** - * 提示文本字体颜色,优先级高于 overlayStyle - */ tooltipColor?: string; - /** - * 提示文本字体大小,单位px,优先级高于 overlayStyle - */ tooltipFontSize?: number; - /** - * 提示框内容最大宽度,单位px,默认不设置时,提示文本内容自动与展示文本宽度保持一致 - */ tooltipMaxWidth?: number; - /** - * 提示框内容区域样式 - * @default { textAlign: 'justify' } - */ tooltipOverlayStyle?: CSSProperties; } diff --git a/packages/effects/common-ui/src/components/icon-picker/icon-picker.vue b/packages/effects/common-ui/src/components/icon-picker/icon-picker.vue index c602274..3837c74 100644 --- a/packages/effects/common-ui/src/components/icon-picker/icon-picker.vue +++ b/packages/effects/common-ui/src/components/icon-picker/icon-picker.vue @@ -30,21 +30,12 @@ import { fetchIconsData } from './icons'; interface Props { pageSize?: number; - /** 图标集的名字 */ prefix?: string; - /** 是否自动请求API以获得图标集的数据.提供prefix时有效 */ autoFetchApi?: boolean; - /** - * 图标列表 - */ icons?: string[]; - /** Input组件 */ inputComponent?: VNode; - /** 图标插槽名,预览图标将被渲染到此插槽中 */ iconSlot?: string; - /** input组件的值属性名称 */ modelValueProp?: string; - /** 图标样式 */ iconClass?: string; type?: 'icon' | 'input'; } diff --git a/packages/effects/common-ui/src/components/icon-picker/icons.ts b/packages/effects/common-ui/src/components/icon-picker/icons.ts index 694e904..6c82d37 100644 --- a/packages/effects/common-ui/src/components/icon-picker/icons.ts +++ b/packages/effects/common-ui/src/components/icon-picker/icons.ts @@ -1,8 +1,5 @@ import type { Recordable } from '@vben/types'; -/** - * 一个缓存对象,在不刷新页面时,无需重复请求远程接口 - */ export const ICONS_MAP: Recordable = {}; interface IconifyResponse { diff --git a/packages/effects/common-ui/src/components/json-viewer/types.ts b/packages/effects/common-ui/src/components/json-viewer/types.ts index 8f3a206..360e906 100644 --- a/packages/effects/common-ui/src/components/json-viewer/types.ts +++ b/packages/effects/common-ui/src/components/json-viewer/types.ts @@ -1,25 +1,14 @@ export interface JsonViewerProps { - /** 要展示的结构数据 */ value: any; - /** 展开深度 */ expandDepth?: number; - /** 是否可复制 */ copyable?: boolean; - /** 是否排序 */ sort?: boolean; - /** 显示边框 */ boxed?: boolean; - /** 主题 */ theme?: string; - /** 是否展开 */ expanded?: boolean; - /** 时间格式化函数 */ timeformat?: (time: Date | number | string) => string; - /** 预览模式 */ previewMode?: boolean; - /** 显示数组索引 */ showArrayIndex?: boolean; - /** 显示双引号 */ showDoubleQuotes?: boolean; } @@ -37,8 +26,6 @@ export interface JsonViewerValue { } export interface JsonViewerToggle { - /** 鼠标事件 */ event: MouseEvent; - /** 当前展开状态 */ open: boolean; } diff --git a/packages/effects/common-ui/src/components/loading/directive.ts b/packages/effects/common-ui/src/components/loading/directive.ts index 973a605..6e816df 100644 --- a/packages/effects/common-ui/src/components/loading/directive.ts +++ b/packages/effects/common-ui/src/components/loading/directive.ts @@ -93,9 +93,7 @@ const spinningDirective: Directive = { }; type loadingDirectiveParams = { - /** 是否注册loading指令。如果提供一个string,则将指令注册为指定的名称 */ loading?: boolean | string; - /** 是否注册spinning指令。如果提供一个string,则将指令注册为指定的名称 */ spinning?: boolean | string; }; diff --git a/packages/effects/common-ui/src/components/loading/loading.vue b/packages/effects/common-ui/src/components/loading/loading.vue index faf49e6..e437c9f 100644 --- a/packages/effects/common-ui/src/components/loading/loading.vue +++ b/packages/effects/common-ui/src/components/loading/loading.vue @@ -4,19 +4,9 @@ import { cn } from '@vben-core/shared/utils'; interface LoadingProps { class?: string; - /** - * @zh_CN 最小加载时间 - * @en_US Minimum loading time - */ minLoadingTime?: number; - /** - * @zh_CN loading状态开启 - */ spinning?: boolean; - /** - * @zh_CN 文字 - */ text?: string; } diff --git a/packages/effects/common-ui/src/components/loading/spinner.vue b/packages/effects/common-ui/src/components/loading/spinner.vue index caee2bb..4322ffd 100644 --- a/packages/effects/common-ui/src/components/loading/spinner.vue +++ b/packages/effects/common-ui/src/components/loading/spinner.vue @@ -4,14 +4,7 @@ import { cn } from '@vben-core/shared/utils'; interface SpinnerProps { class?: string; - /** - * @zh_CN 最小加载时间 - * @en_US Minimum loading time - */ minLoadingTime?: number; - /** - * @zh_CN loading状态开启 - */ spinning?: boolean; } defineOptions({ name: 'Spinner' }); diff --git a/packages/effects/common-ui/src/components/page/types.ts b/packages/effects/common-ui/src/components/page/types.ts index c7331ae..bd60d83 100644 --- a/packages/effects/common-ui/src/components/page/types.ts +++ b/packages/effects/common-ui/src/components/page/types.ts @@ -2,16 +2,8 @@ export interface PageProps { title?: string; description?: string; contentClass?: string; - /** - * 根据content可见高度自适应 - */ autoContentHeight?: boolean; headerClass?: string; footerClass?: string; - /** - * Custom height offset value (in pixels) to adjust content area sizing - * when used with autoContentHeight - * @default 0 - */ heightOffset?: number; } diff --git a/packages/effects/common-ui/src/components/resize/resize.vue b/packages/effects/common-ui/src/components/resize/resize.vue index 68be4d9..155d64c 100644 --- a/packages/effects/common-ui/src/components/resize/resize.vue +++ b/packages/effects/common-ui/src/components/resize/resize.vue @@ -1,8 +1,4 @@