diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 3e6768e..8d0ca95 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -8,7 +8,8 @@ module.exports = { 'plugin:@typescript-eslint/recommended', 'plugin:@typescript-eslint/recommended-requiring-type-checking', 'plugin:react-hooks/recommended', - 'plugin:prettier/recommended' + 'plugin:prettier/recommended', + './.eslintrc-auto-import.json' ], parser: '@typescript-eslint/parser', parserOptions: { diff --git a/.gitignore b/.gitignore index a3dcf30..d2b76e2 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,4 @@ dist-ssr # Auto generated /auto-imports.d.ts +/.eslintrc-auto-import.json diff --git a/build/resolvers/antd.ts b/build/resolvers/antd.ts new file mode 100644 index 0000000..469af1b --- /dev/null +++ b/build/resolvers/antd.ts @@ -0,0 +1,421 @@ +export function kebabCase(key: string): string { + const result: string = key.replace(/([A-Z])/g, ' $1').trim() + return result.split(' ').join('-').toLowerCase() +} + +export type Awaitable = T | PromiseLike + +export interface ImportInfo { + as?: string + name?: string + from: string +} + +export type SideEffectsInfo = (ImportInfo | string)[] | ImportInfo | string | undefined + +export interface ComponentInfo extends ImportInfo { + sideEffects?: SideEffectsInfo +} + +export type ComponentResolveResult = Awaitable + +export type ComponentResolverFunction = (name: string) => ComponentResolveResult + +export interface ComponentResolverObject { + type: 'component' | 'directive' + resolve: ComponentResolverFunction +} + +export type ComponentResolver = ComponentResolverFunction | ComponentResolverObject + +interface IMatcher { + pattern: RegExp + styleDir: string +} + +const matchComponents: IMatcher[] = [ + { + pattern: /^Avatar/, + styleDir: 'avatar' + }, + { + pattern: /^AutoComplete/, + styleDir: 'auto-complete' + }, + { + pattern: /^Anchor/, + styleDir: 'anchor' + }, + + { + pattern: /^Badge/, + styleDir: 'badge' + }, + { + pattern: /^Breadcrumb/, + styleDir: 'breadcrumb' + }, + { + pattern: /^Button/, + styleDir: 'button' + }, + { + pattern: /^Checkbox/, + styleDir: 'checkbox' + }, + { + pattern: /^Card/, + styleDir: 'card' + }, + { + pattern: /^Collapse/, + styleDir: 'collapse' + }, + { + pattern: /^Descriptions/, + styleDir: 'descriptions' + }, + { + pattern: /^RangePicker|^WeekPicker|^MonthPicker/, + styleDir: 'date-picker' + }, + { + pattern: /^Dropdown/, + styleDir: 'dropdown' + }, + + { + pattern: /^Form/, + styleDir: 'form' + }, + { + pattern: /^InputNumber/, + styleDir: 'input-number' + }, + + { + pattern: /^Input|^Textarea/, + styleDir: 'input' + }, + { + pattern: /^Statistic/, + styleDir: 'statistic' + }, + { + pattern: /^CheckableTag/, + styleDir: 'tag' + }, + { + pattern: /^TimeRangePicker/, + styleDir: 'time-picker' + }, + { + pattern: /^Layout/, + styleDir: 'layout' + }, + { + pattern: /^Menu|^SubMenu/, + styleDir: 'menu' + }, + + { + pattern: /^Table/, + styleDir: 'table' + }, + { + pattern: /^TimePicker|^TimeRangePicker/, + styleDir: 'time-picker' + }, + { + pattern: /^Radio/, + styleDir: 'radio' + }, + + { + pattern: /^Image/, + styleDir: 'image' + }, + + { + pattern: /^List/, + styleDir: 'list' + }, + + { + pattern: /^Tab/, + styleDir: 'tabs' + }, + { + pattern: /^Mentions/, + styleDir: 'mentions' + }, + + { + pattern: /^Step/, + styleDir: 'steps' + }, + { + pattern: /^Skeleton/, + styleDir: 'skeleton' + }, + + { + pattern: /^Select/, + styleDir: 'select' + }, + { + pattern: /^TreeSelect/, + styleDir: 'tree-select' + }, + { + pattern: /^Tree|^DirectoryTree/, + styleDir: 'tree' + }, + { + pattern: /^Typography/, + styleDir: 'typography' + }, + { + pattern: /^Timeline/, + styleDir: 'timeline' + }, + { + pattern: /^Upload/, + styleDir: 'upload' + } +] + +export interface AntDesignResolverOptions { + /** + * exclude components that do not require automatic import + * + * @default [] + */ + exclude?: string[] + /** + * import style along with components + * + * @default 'css' + */ + importStyle?: boolean | 'css' | 'less' + /** + * resolve `antd' icons + * + * requires package `@ant-design/icons-vue` + * + * @default false + */ + resolveIcons?: boolean + + /** + * @deprecated use `importStyle: 'css'` instead + */ + importCss?: boolean + /** + * @deprecated use `importStyle: 'less'` instead + */ + importLess?: boolean + + /** + * use commonjs build default false + */ + cjs?: boolean + + /** + * rename package + * + * @default 'antd' + */ + packageName?: string +} + +const getStyleDir = (compName: string): string => { + for (const matchComponent of matchComponents) { + if (compName.match(matchComponent.pattern)) { + return matchComponent.styleDir + } + } + return kebabCase(compName) +} + +const getSideEffects = (compName: string, options: AntDesignResolverOptions): SideEffectsInfo => { + const { importStyle = true } = options + + if (!importStyle) { + return + } + + const lib = options.cjs ? 'lib' : 'es' + const packageName = options?.packageName || 'antd' + + const styleDir = getStyleDir(compName) + return `${packageName}/${lib}/${styleDir}/style` +} + +const primitiveNames = [ + 'Affix', + 'Anchor', + 'AnchorLink', + 'AutoComplete', + 'AutoCompleteOptGroup', + 'AutoCompleteOption', + 'Alert', + 'Avatar', + 'AvatarGroup', + 'BackTop', + 'Badge', + 'BadgeRibbon', + 'Breadcrumb', + 'BreadcrumbItem', + 'BreadcrumbSeparator', + 'Button', + 'ButtonGroup', + 'Calendar', + 'Card', + 'CardGrid', + 'CardMeta', + 'Collapse', + 'CollapsePanel', + 'Carousel', + 'Cascader', + 'Checkbox', + 'CheckboxGroup', + 'Col', + 'Comment', + 'ConfigProvider', + 'DatePicker', + 'MonthPicker', + 'WeekPicker', + 'RangePicker', + 'QuarterPicker', + 'Descriptions', + 'DescriptionsItem', + 'Divider', + 'Dropdown', + 'DropdownButton', + 'Drawer', + 'Empty', + 'Form', + 'FormItem', + 'FormItemRest', + 'Grid', + 'Input', + 'InputGroup', + 'InputPassword', + 'InputSearch', + 'Textarea', + 'Image', + 'ImagePreviewGroup', + 'InputNumber', + 'Layout', + 'LayoutHeader', + 'LayoutSider', + 'LayoutFooter', + 'LayoutContent', + 'List', + 'ListItem', + 'ListItemMeta', + 'Menu', + 'MenuDivider', + 'MenuItem', + 'MenuItemGroup', + 'SubMenu', + 'Mentions', + 'MentionsOption', + 'Modal', + 'Statistic', + 'StatisticCountdown', + 'PageHeader', + 'Pagination', + 'Popconfirm', + 'Popover', + 'Progress', + 'Radio', + 'RadioButton', + 'RadioGroup', + 'Rate', + 'Result', + 'Row', + 'Select', + 'SelectOptGroup', + 'SelectOption', + 'Skeleton', + 'SkeletonButton', + 'SkeletonAvatar', + 'SkeletonInput', + 'SkeletonImage', + 'Slider', + 'Space', + 'Spin', + 'Steps', + 'Step', + 'Switch', + 'Table', + 'TableColumn', + 'TableColumnGroup', + 'TableSummary', + 'TableSummaryRow', + 'TableSummaryCell', + 'Transfer', + 'Tree', + 'TreeNode', + 'DirectoryTree', + 'TreeSelect', + 'TreeSelectNode', + 'Tabs', + 'TabPane', + 'Tag', + 'CheckableTag', + 'TimePicker', + 'TimeRangePicker', + 'Timeline', + 'TimelineItem', + 'Tooltip', + 'Typography', + 'TypographyLink', + 'TypographyParagraph', + 'TypographyText', + 'TypographyTitle', + 'Upload', + 'UploadDragger', + 'LocaleProvider' +] + +const prefix = 'Antd' + +let antdNames: Set + +const genAntdNames = (primitiveNames: string[]): void => { + antdNames = new Set(primitiveNames.map((name) => `${prefix}${name}`)) +} + +genAntdNames(primitiveNames) + +const isAntd = (compName: string): boolean => { + return antdNames.has(compName) +} + +export function AntDesignResolver(options: AntDesignResolverOptions = {}): ComponentResolver { + return { + type: 'component', + resolve: (name: string) => { + if (options.resolveIcons && name.match(/(Outlined|Filled|TwoTone)$/)) { + return { + name, + from: '@ant-design/icons' + } + } + + if (isAntd(name) && !options?.exclude?.includes(name)) { + const importName = name.slice(prefix.length) + const { cjs = false, packageName = 'antd' } = options + const path = `${packageName}/${cjs ? 'lib' : 'es'}` + return { + name: importName, + from: path, + sideEffects: getSideEffects(importName, options) + } + } + } + } +} diff --git a/src/App.tsx b/src/App.tsx index 3693ee6..3561770 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,5 +1,4 @@ import React from 'react' -import { RouterProvider } from 'react-router' import router from '@/router' const App: React.FC = () => { diff --git a/src/AuthRoute.tsx b/src/AuthRoute.tsx index 39b604e..788ba52 100644 --- a/src/AuthRoute.tsx +++ b/src/AuthRoute.tsx @@ -1,6 +1,3 @@ -import { useMatches, useOutlet } from 'react-router' -import { useMemo } from 'react' -import { Navigate } from 'react-router-dom' import { getLoginStatus } from '@/utils/auth.ts' const AuthRoute = () => { diff --git a/src/main.tsx b/src/main.tsx index 892b9e1..89528f3 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -3,13 +3,12 @@ import ReactDOM from 'react-dom/client' import App from './App.tsx' import '@/assets/css/base.css' import '@/assets/css/common.css' -import { ConfigProvider } from 'antd' import zh_CN from 'antd/locale/zh_CN' ReactDOM.createRoot(document.getElementById('root')!).render( - + - + ) diff --git a/src/pages/Login.tsx b/src/pages/Login.tsx index e037f06..40f71af 100644 --- a/src/pages/Login.tsx +++ b/src/pages/Login.tsx @@ -1,10 +1,7 @@ -import React, { useState } from 'react' -import { Button, Form, Input, message } from 'antd' -import { LockOutlined, UserOutlined } from '@ant-design/icons' +import React from 'react' import { login } from '@/utils/auth.ts' import { LOGIN_SUCCESS, LOGIN_USERNAME_PASSWORD_ERROR } from '@/constants/Common.constants.ts' import { setToken } from '@/utils/common.ts' -import { useNavigate } from 'react-router' import '@/assets/css/login.css' const Login: React.FC = () => { @@ -59,36 +56,36 @@ const Login: React.FC = () => {
登 录
-
- - } placeholder={'用户名'} disabled={isLoggingIn} /> - - + - } placeholder={'密码'} disabled={isLoggingIn} /> - - - - -
+ + + diff --git a/src/pages/Manager.tsx b/src/pages/Manager.tsx index 7336a1c..2db7fa6 100644 --- a/src/pages/Manager.tsx +++ b/src/pages/Manager.tsx @@ -1,9 +1,7 @@ import React from 'react' -import { Button, Checkbox, DatePicker, Input, Select, Space, Table } from 'antd' import { removeToken } from '@/utils/common.ts' import { logout } from '@/utils/auth.ts' import '@/assets/css/manager.css' -import { DeleteOutlined, SearchOutlined } from '@ant-design/icons' import { ColumnsType } from 'antd/es/table' type OrderDataType = { @@ -73,11 +71,11 @@ const columns: ColumnsType = [ title: '操作', key: 'action', render: () => ( - + 浏览 编辑 确认订单 - + ) } ] @@ -140,15 +138,15 @@ const Manager: React.FC = () => { <>
- +