feat: 新增开发与生产环境配置、重构API请求模块、优化组件自动导入体系及新增表格组件
This commit is contained in:
parent
ecb78e5982
commit
8c4f5fcbac
|
|
@ -0,0 +1,4 @@
|
||||||
|
# 开发环境配置
|
||||||
|
VITE_ENV=development
|
||||||
|
VITE_API_URL=/api
|
||||||
|
VITE_APP_TITLE=Template Admin (Dev)
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
# 生产环境配置
|
||||||
|
VITE_ENV=production
|
||||||
|
VITE_API_URL=/prod-api
|
||||||
|
VITE_APP_TITLE=Template Admin
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
// API 请求封装
|
|
||||||
export const fetchData = async (url: string) => {
|
|
||||||
const response = await fetch(url);
|
|
||||||
return response.json();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
/* eslint-disable */
|
|
||||||
// @ts-nocheck
|
|
||||||
// Generated by unplugin-vue-components
|
|
||||||
// Read more: https://github.com/vuejs/core/pull/3399
|
|
||||||
// biome-ignore lint: disable
|
|
||||||
export {}
|
|
||||||
|
|
||||||
/* prettier-ignore */
|
|
||||||
declare module 'vue' {
|
|
||||||
export interface GlobalComponents {
|
|
||||||
AdminLayout: typeof import('./components/layout/AdminLayout.vue')['default']
|
|
||||||
AdvancedForm: typeof import('./components/form/AdvancedForm.vue')['default']
|
|
||||||
AdvancedTable: typeof import('./components/table/AdvancedTable.vue')['default']
|
|
||||||
Breadcrumb: typeof import('./components/common/Breadcrumb.vue')['default']
|
|
||||||
FooterBar: typeof import('./components/layout/FooterBar.vue')['default']
|
|
||||||
HeaderNav: typeof import('./components/layout/HeaderNav.vue')['default']
|
|
||||||
MainContent: typeof import('./components/layout/MainContent.vue')['default']
|
|
||||||
RouterLink: typeof import('vue-router')['RouterLink']
|
|
||||||
RouterView: typeof import('vue-router')['RouterView']
|
|
||||||
SideMenu: typeof import('./components/layout/SideMenu.vue')['default']
|
|
||||||
TabsBar: typeof import('./components/layout/TabsBar.vue')['default']
|
|
||||||
YourComponent: typeof import('./components/YourComponent.vue')['default']
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,65 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ComponentsEnum } from '@/enum/componentsEnum';
|
||||||
|
|
||||||
|
interface SearchBoxProps {
|
||||||
|
searchColumns: Record<string, any>[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<SearchBoxProps>(), {});
|
||||||
|
|
||||||
|
const { searchColumns } = props;
|
||||||
|
|
||||||
|
const searchModel = ref<Record<string, any>>({});
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'setParams', data: Record<string, any>): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const reset = () => {
|
||||||
|
searchModel.value = {};
|
||||||
|
emit('setParams', searchModel.value);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<ACard>
|
||||||
|
<ARow :gutter="[16, 16]" wrap>
|
||||||
|
<ACol v-for="(item, index) in searchColumns" :key="index" :span="24" :md="12" :lg="6">
|
||||||
|
<AFormItem :label="item?.label ?? item?.title" class="m-0">
|
||||||
|
<AInput
|
||||||
|
v-if="item.components === ComponentsEnum.Input"
|
||||||
|
v-model:value="searchModel[item?.alias ?? item?.dataIndex]"
|
||||||
|
:placeholder="`请输入${item?.title}`"
|
||||||
|
/>
|
||||||
|
<ASelect
|
||||||
|
v-else-if="item.components === ComponentsEnum.Select"
|
||||||
|
v-model:value="searchModel[item?.alias ?? item?.dataIndex]"
|
||||||
|
:placeholder="`请输入${item?.title}`"
|
||||||
|
clearable
|
||||||
|
v-bind="item.componentProps"
|
||||||
|
/>
|
||||||
|
</AFormItem>
|
||||||
|
</ACol>
|
||||||
|
<div class="flex-1">
|
||||||
|
<AFormItem class="m-0">
|
||||||
|
<div class="w-full flex-y-center justify-end gap-12px">
|
||||||
|
<AButton @click="reset">
|
||||||
|
<template #icon>
|
||||||
|
<icon-ic-round-refresh class="align-sub text-icon" />
|
||||||
|
</template>
|
||||||
|
<span class="ml-8px">重置</span>
|
||||||
|
</AButton>
|
||||||
|
<AButton type="primary" ghost @click="emit('setParams', searchModel)">
|
||||||
|
<template #icon>
|
||||||
|
<icon-ic-round-search class="align-sub text-icon" />
|
||||||
|
</template>
|
||||||
|
<span class="ml-8px">搜索</span>
|
||||||
|
</AButton>
|
||||||
|
</div>
|
||||||
|
</AFormItem>
|
||||||
|
</div>
|
||||||
|
</ARow>
|
||||||
|
</ACard>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
|
|
@ -0,0 +1,85 @@
|
||||||
|
<script lang="tsx" setup>
|
||||||
|
import { Button, Popconfirm } from 'ant-design-vue';
|
||||||
|
import { computed } from 'vue';
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
title: string;
|
||||||
|
loading: boolean;
|
||||||
|
columns: Record<string, any>[];
|
||||||
|
list?: Record<string, any>[];
|
||||||
|
tableSize?: 'small' | 'middle' | 'large';
|
||||||
|
pagination?: Record<string, number>;
|
||||||
|
componentProps?: Record<string, number>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<IProps>(), {
|
||||||
|
list: () => [],
|
||||||
|
pagination: () => ({}),
|
||||||
|
componentProps: () => ({}),
|
||||||
|
tableSize: 'small'
|
||||||
|
});
|
||||||
|
|
||||||
|
const { columns, title, list, pagination, componentProps } = toRefs(props);
|
||||||
|
|
||||||
|
const searchColumns = computed(() => {
|
||||||
|
return columns.value.filter(item => item?.search);
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'setPage', data: Record<string, any>): void;
|
||||||
|
(e: 'setParams', data: Record<string, any>): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const aTableRef = ref<any>();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="falling-table">
|
||||||
|
<ACard v-if="searchColumns.length" :bordered="false" class="card-wrapper" title="搜索">
|
||||||
|
<SearchBox :search-columns="searchColumns" @set-params="emit('setParams', $event)" />
|
||||||
|
</ACard>
|
||||||
|
<ACard :bordered="false" :title="title">
|
||||||
|
<template #extra>
|
||||||
|
<slot name="table-extra"></slot>
|
||||||
|
</template>
|
||||||
|
<ATable
|
||||||
|
ref="aTableRef"
|
||||||
|
:columns="columns"
|
||||||
|
:data-source="list"
|
||||||
|
:loading="loading"
|
||||||
|
:pagination="pagination"
|
||||||
|
:size="tableSize"
|
||||||
|
v-bind="componentProps"
|
||||||
|
@change="emit('setPage', $event)"
|
||||||
|
>
|
||||||
|
<template #bodyCell="{ text, record, index, column }">
|
||||||
|
<template v-if="column.dataIndex === 'operation'">
|
||||||
|
<div class="flex-center gap-8px">
|
||||||
|
<div v-for="(item, key) in (column as any).actions" :key="key">
|
||||||
|
<Popconfirm
|
||||||
|
v-if="item.delete"
|
||||||
|
title="确定要删除吗?"
|
||||||
|
@confirm="item?.onClick({ record, index, column })"
|
||||||
|
>
|
||||||
|
<Button danger size="small">{{ item?.title }}</Button>
|
||||||
|
</Popconfirm>
|
||||||
|
<Button v-else size="small" type="primary" @click="item?.onClick({ record, index, column })">
|
||||||
|
{{ item?.title }}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<slot :column="column" :index="index" :record="record" :text="text" name="bodyCell"></slot>
|
||||||
|
</template>
|
||||||
|
</ATable>
|
||||||
|
</ACard>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.falling-table {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 15px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
export enum ComponentsEnum {
|
||||||
|
Input = 'Input',
|
||||||
|
Select = 'Select'
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,130 @@
|
||||||
|
import type { AxiosError, AxiosInstance, AxiosRequestConfig } from 'axios'
|
||||||
|
import axios from 'axios'
|
||||||
|
|
||||||
|
// 对应后端的Result<T>结构
|
||||||
|
export interface Result<T = any> {
|
||||||
|
code: number
|
||||||
|
msg: string
|
||||||
|
data: T
|
||||||
|
isSuccess?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
// 对应后端的ResultCode枚举
|
||||||
|
export enum ResultCode {
|
||||||
|
SUCCESS = 200,
|
||||||
|
BAD_REQUEST = 400,
|
||||||
|
UNAUTHORIZED = 401,
|
||||||
|
FORBIDDEN = 403,
|
||||||
|
NOT_FOUND = 404,
|
||||||
|
INTERNAL_SERVER_ERROR = 500,
|
||||||
|
SERVICE_UNAVAILABLE = 503,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建axios实例
|
||||||
|
const service: AxiosInstance = axios.create({
|
||||||
|
baseURL: import.meta.env.VITE_API_URL, // 从环境变量获取API基础URL
|
||||||
|
timeout: 10000, // 请求超时时间
|
||||||
|
})
|
||||||
|
|
||||||
|
// 请求拦截器
|
||||||
|
service.interceptors.request.use(
|
||||||
|
(config) => {
|
||||||
|
// 在发送请求之前做些什么,例如添加token
|
||||||
|
const token = localStorage.getItem('token')
|
||||||
|
if (token) {
|
||||||
|
config.headers = config.headers || {}
|
||||||
|
config.headers['Authorization'] = token
|
||||||
|
}
|
||||||
|
return config
|
||||||
|
},
|
||||||
|
(error: AxiosError) => {
|
||||||
|
// 对请求错误做些什么
|
||||||
|
return Promise.reject(error)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
// 响应拦截器
|
||||||
|
service.interceptors.response.use(
|
||||||
|
(response) => {
|
||||||
|
const res = response.data
|
||||||
|
|
||||||
|
// 如果自定义code不是200,则判断为错误
|
||||||
|
if (res.code !== ResultCode.SUCCESS) {
|
||||||
|
// 处理特定的错误码
|
||||||
|
switch (res.code) {
|
||||||
|
case ResultCode.UNAUTHORIZED:
|
||||||
|
// 未授权,跳转到登录页
|
||||||
|
window.location.href = '/login'
|
||||||
|
break
|
||||||
|
case ResultCode.FORBIDDEN:
|
||||||
|
// 无权限,显示提示
|
||||||
|
console.error('无权限访问')
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
console.error(res.msg || '请求失败')
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.msg || 'Error'))
|
||||||
|
} else {
|
||||||
|
// 成功请求,标记isSuccess为true
|
||||||
|
res.isSuccess = true
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
},
|
||||||
|
(error: AxiosError) => {
|
||||||
|
// 对响应错误做点什么
|
||||||
|
let message = error.message
|
||||||
|
if (error.response) {
|
||||||
|
// 处理HTTP状态码
|
||||||
|
switch (error.response.status) {
|
||||||
|
case 400:
|
||||||
|
message = '请求参数错误'
|
||||||
|
break
|
||||||
|
case 401:
|
||||||
|
message = '未授权,请登录'
|
||||||
|
window.location.href = '/login'
|
||||||
|
break
|
||||||
|
case 403:
|
||||||
|
message = '拒绝访问'
|
||||||
|
break
|
||||||
|
case 404:
|
||||||
|
message = '请求资源不存在'
|
||||||
|
break
|
||||||
|
case 500:
|
||||||
|
message = '服务器内部错误'
|
||||||
|
break
|
||||||
|
case 503:
|
||||||
|
message = '服务不可用'
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.error(message)
|
||||||
|
return Promise.reject(error)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
// 封装通用请求方法
|
||||||
|
export function request<T = any>(config: AxiosRequestConfig): Promise<Result<T>> {
|
||||||
|
return service(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 封装GET请求
|
||||||
|
export function get<T = any>(url: string, params?: any): Promise<Result<T>> {
|
||||||
|
return request({ method: 'GET', url, params })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 封装POST请求
|
||||||
|
export function post<T = any>(url: string, data?: any): Promise<Result<T>> {
|
||||||
|
return request({ method: 'POST', url, data })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 封装PUT请求
|
||||||
|
export function put<T = any>(url: string, data?: any): Promise<Result<T>> {
|
||||||
|
return request({ method: 'PUT', url, data })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 封装DELETE请求
|
||||||
|
export function del<T = any>(url: string, params?: any): Promise<Result<T>> {
|
||||||
|
return request({ method: 'DELETE', url, params })
|
||||||
|
}
|
||||||
|
|
||||||
|
export default service
|
||||||
|
|
@ -66,7 +66,7 @@ declare global {
|
||||||
const triggerRef: typeof import('vue')['triggerRef']
|
const triggerRef: typeof import('vue')['triggerRef']
|
||||||
const unref: typeof import('vue')['unref']
|
const unref: typeof import('vue')['unref']
|
||||||
const useAttrs: typeof import('vue')['useAttrs']
|
const useAttrs: typeof import('vue')['useAttrs']
|
||||||
const useCounterStore: typeof import('./stores/counter')['useCounterStore']
|
const useCounterStore: typeof import('../stores/counter')['useCounterStore']
|
||||||
const useCssModule: typeof import('vue')['useCssModule']
|
const useCssModule: typeof import('vue')['useCssModule']
|
||||||
const useCssVars: typeof import('vue')['useCssVars']
|
const useCssVars: typeof import('vue')['useCssVars']
|
||||||
const useId: typeof import('vue')['useId']
|
const useId: typeof import('vue')['useId']
|
||||||
|
|
@ -153,7 +153,7 @@ declare module 'vue' {
|
||||||
readonly triggerRef: UnwrapRef<typeof import('vue')['triggerRef']>
|
readonly triggerRef: UnwrapRef<typeof import('vue')['triggerRef']>
|
||||||
readonly unref: UnwrapRef<typeof import('vue')['unref']>
|
readonly unref: UnwrapRef<typeof import('vue')['unref']>
|
||||||
readonly useAttrs: UnwrapRef<typeof import('vue')['useAttrs']>
|
readonly useAttrs: UnwrapRef<typeof import('vue')['useAttrs']>
|
||||||
readonly useCounterStore: UnwrapRef<typeof import('./stores/counter')['useCounterStore']>
|
readonly useCounterStore: UnwrapRef<typeof import('../stores/counter')['useCounterStore']>
|
||||||
readonly useCssModule: UnwrapRef<typeof import('vue')['useCssModule']>
|
readonly useCssModule: UnwrapRef<typeof import('vue')['useCssModule']>
|
||||||
readonly useCssVars: UnwrapRef<typeof import('vue')['useCssVars']>
|
readonly useCssVars: UnwrapRef<typeof import('vue')['useCssVars']>
|
||||||
readonly useId: UnwrapRef<typeof import('vue')['useId']>
|
readonly useId: UnwrapRef<typeof import('vue')['useId']>
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
/* eslint-disable */
|
||||||
|
// @ts-nocheck
|
||||||
|
// Generated by unplugin-vue-components
|
||||||
|
// Read more: https://github.com/vuejs/core/pull/3399
|
||||||
|
// biome-ignore lint: disable
|
||||||
|
export {}
|
||||||
|
|
||||||
|
/* prettier-ignore */
|
||||||
|
declare module 'vue' {
|
||||||
|
export interface GlobalComponents {
|
||||||
|
ABadge: typeof import('ant-design-vue/es')['Badge']
|
||||||
|
ABreadcrumb: typeof import('ant-design-vue/es')['Breadcrumb']
|
||||||
|
ABreadcrumbItem: typeof import('ant-design-vue/es')['BreadcrumbItem']
|
||||||
|
AButton: typeof import('ant-design-vue/es')['Button']
|
||||||
|
ACheckbox: typeof import('ant-design-vue/es')['Checkbox']
|
||||||
|
ACol: typeof import('ant-design-vue/es')['Col']
|
||||||
|
AdminLayout: typeof import('./../components/layout/AdminLayout.vue')['default']
|
||||||
|
ADropdown: typeof import('ant-design-vue/es')['Dropdown']
|
||||||
|
AForm: typeof import('ant-design-vue/es')['Form']
|
||||||
|
AFormItem: typeof import('ant-design-vue/es')['FormItem']
|
||||||
|
AInput: typeof import('ant-design-vue/es')['Input']
|
||||||
|
AInputPassword: typeof import('ant-design-vue/es')['InputPassword']
|
||||||
|
ALayout: typeof import('ant-design-vue/es')['Layout']
|
||||||
|
ALayoutContent: typeof import('ant-design-vue/es')['LayoutContent']
|
||||||
|
ALayoutFooter: typeof import('ant-design-vue/es')['LayoutFooter']
|
||||||
|
ALayoutHeader: typeof import('ant-design-vue/es')['LayoutHeader']
|
||||||
|
ALayoutSider: typeof import('ant-design-vue/es')['LayoutSider']
|
||||||
|
AMenu: typeof import('ant-design-vue/es')['Menu']
|
||||||
|
AMenuDivider: typeof import('ant-design-vue/es')['MenuDivider']
|
||||||
|
AMenuItem: typeof import('ant-design-vue/es')['MenuItem']
|
||||||
|
ARow: typeof import('ant-design-vue/es')['Row']
|
||||||
|
ASpace: typeof import('ant-design-vue/es')['Space']
|
||||||
|
ASubMenu: typeof import('ant-design-vue/es')['SubMenu']
|
||||||
|
ATabPane: typeof import('ant-design-vue/es')['TabPane']
|
||||||
|
ATabs: typeof import('ant-design-vue/es')['Tabs']
|
||||||
|
Breadcrumb: typeof import('./../components/common/Breadcrumb.vue')['default']
|
||||||
|
FallingTable: typeof import('./../components/fallingTable/index.vue')['default']
|
||||||
|
FooterBar: typeof import('./../components/layout/FooterBar.vue')['default']
|
||||||
|
HeaderNav: typeof import('./../components/layout/HeaderNav.vue')['default']
|
||||||
|
MainContent: typeof import('./../components/layout/MainContent.vue')['default']
|
||||||
|
RouterLink: typeof import('vue-router')['RouterLink']
|
||||||
|
RouterView: typeof import('vue-router')['RouterView']
|
||||||
|
SearchBox: typeof import('./../components/fallingTable/components/searchBox.vue')['default']
|
||||||
|
SideMenu: typeof import('./../components/layout/SideMenu.vue')['default']
|
||||||
|
TabsBar: typeof import('./../components/layout/TabsBar.vue')['default']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
"exclude": ["src/**/__tests__/*"],
|
"exclude": ["src/**/__tests__/*"],
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
||||||
|
"module": "es2020",
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": ["./src/*"]
|
"@/*": ["./src/*"]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import vueJsx from '@vitejs/plugin-vue-jsx'
|
||||||
import vueDevTools from 'vite-plugin-vue-devtools'
|
import vueDevTools from 'vite-plugin-vue-devtools'
|
||||||
import AutoImport from 'unplugin-auto-import/vite'
|
import AutoImport from 'unplugin-auto-import/vite'
|
||||||
import Components from 'unplugin-vue-components/vite'
|
import Components from 'unplugin-vue-components/vite'
|
||||||
|
import { AntDesignVueResolver } from 'unplugin-vue-components/resolvers'
|
||||||
|
|
||||||
// https://vite.dev/config/
|
// https://vite.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
|
|
@ -14,34 +15,34 @@ export default defineConfig({
|
||||||
vueJsx(),
|
vueJsx(),
|
||||||
vueDevTools(),
|
vueDevTools(),
|
||||||
AutoImport({
|
AutoImport({
|
||||||
// 自动导入Vue相关API
|
|
||||||
imports: [
|
imports: [
|
||||||
'vue',
|
'vue',
|
||||||
'vue-router',
|
'vue-router',
|
||||||
'pinia',
|
'pinia',
|
||||||
// 可以添加更多需要自动导入的库
|
|
||||||
],
|
],
|
||||||
// 生成自动导入的TS声明文件
|
resolvers: [
|
||||||
dts: 'src/auto-imports.d.ts',
|
AntDesignVueResolver({
|
||||||
// 自动导入目录下的模块
|
importStyle: 'less', // 可选: 'css' | 'less',根据你是否启用了 less 主题定制
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
dts: 'src/types/auto-imports.d.ts',
|
||||||
dirs: [
|
dirs: [
|
||||||
'src/composables',
|
'src/components',
|
||||||
'src/stores',
|
'src/stores',
|
||||||
],
|
],
|
||||||
// 自动导入的API前缀
|
|
||||||
vueTemplate: true,
|
vueTemplate: true,
|
||||||
}),
|
}),
|
||||||
Components({
|
Components({
|
||||||
// 指定组件所在目录,默认为 src/components
|
|
||||||
dirs: ['src/components'],
|
dirs: ['src/components'],
|
||||||
// 组件的有效文件扩展名
|
|
||||||
extensions: ['vue', 'tsx'],
|
extensions: ['vue', 'tsx'],
|
||||||
// 配置文件生成位置
|
dts: 'src/types/components.d.ts',
|
||||||
dts: 'src/components.d.ts',
|
|
||||||
// 搜索子目录
|
|
||||||
deep: true,
|
deep: true,
|
||||||
// 允许子目录作为组件的命名空间前缀
|
|
||||||
directoryAsNamespace: false,
|
directoryAsNamespace: false,
|
||||||
|
resolvers: [
|
||||||
|
AntDesignVueResolver({
|
||||||
|
importStyle: 'less', // 保持与 AutoImport 中一致
|
||||||
|
}),
|
||||||
|
],
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
resolve: {
|
resolve: {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue