fix lint and type error
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { describe, it, expect, beforeEach } from 'vitest'
|
import { describe, it, expect, beforeEach, vi } from 'vitest'
|
||||||
import { setActivePinia, createPinia } from 'pinia'
|
import { setActivePinia, createPinia } from 'pinia'
|
||||||
import { mount } from '@vue/test-utils'
|
import { mount } from '@vue/test-utils'
|
||||||
import { createRouter, createMemoryHistory } from 'vue-router'
|
import { createRouter, createMemoryHistory } from 'vue-router'
|
||||||
@@ -56,6 +56,8 @@ describe('MainLayout', () => {
|
|||||||
LogoutOutlined: { template: '<span />' },
|
LogoutOutlined: { template: '<span />' },
|
||||||
SettingOutlined: { template: '<span />' },
|
SettingOutlined: { template: '<span />' },
|
||||||
KeyOutlined: { template: '<span />' },
|
KeyOutlined: { template: '<span />' },
|
||||||
|
// Stub dropdown to render overlay inline (avoids Teleport in jsdom)
|
||||||
|
ADropdown: { template: '<div><slot /><slot name="overlay" /></div>' },
|
||||||
Brand: { template: '<div class="brand-stub" />' },
|
Brand: { template: '<div class="brand-stub" />' },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -143,26 +145,27 @@ describe('MainLayout', () => {
|
|||||||
const wrapper = await mountLayout()
|
const wrapper = await mountLayout()
|
||||||
const vm = wrapper.getCurrentComponent()
|
const vm = wrapper.getCurrentComponent()
|
||||||
const router = vm.appContext.config.globalProperties.$router
|
const router = vm.appContext.config.globalProperties.$router
|
||||||
|
const pushSpy = vi.spyOn(router, 'push')
|
||||||
|
|
||||||
// Find and click the profile menu item
|
// ADropdown is stubbed to render overlay inline, so menu items are in the wrapper
|
||||||
const menuItems = wrapper.findAll('.ant-dropdown-menu-item, .ant-menu-item')
|
const menuItems = wrapper.findAll('.ant-menu-item')
|
||||||
const profileItem = menuItems.find((item) => item.text().includes('个人信息'))
|
const profileItem = menuItems.find((item) => item.text().includes('个人信息'))
|
||||||
if (profileItem) {
|
expect(profileItem).toBeTruthy()
|
||||||
await profileItem.trigger('click')
|
await profileItem!.trigger('click')
|
||||||
}
|
expect(pushSpy).toHaveBeenCalledWith('/profile')
|
||||||
|
|
||||||
// Verify the route in the router after navigation
|
|
||||||
await router.push('/profile')
|
|
||||||
expect(router.currentRoute.value.path).toBe('/profile')
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('navigates to /profile/password when clicking password menu item', async () => {
|
it('navigates to /profile/password when clicking password menu item', async () => {
|
||||||
const wrapper = await mountLayout()
|
const wrapper = await mountLayout()
|
||||||
const vm = wrapper.getCurrentComponent()
|
const vm = wrapper.getCurrentComponent()
|
||||||
const router = vm.appContext.config.globalProperties.$router
|
const router = vm.appContext.config.globalProperties.$router
|
||||||
|
const pushSpy = vi.spyOn(router, 'push')
|
||||||
|
|
||||||
await router.push('/profile/password')
|
const menuItems = wrapper.findAll('.ant-menu-item')
|
||||||
expect(router.currentRoute.value.path).toBe('/profile/password')
|
const passwordItem = menuItems.find((item) => item.text().includes('修改密码'))
|
||||||
|
expect(passwordItem).toBeTruthy()
|
||||||
|
await passwordItem!.trigger('click')
|
||||||
|
expect(pushSpy).toHaveBeenCalledWith('/profile/password')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('renders profile breadcrumb on /profile path', async () => {
|
it('renders profile breadcrumb on /profile path', async () => {
|
||||||
|
|||||||
@@ -41,6 +41,11 @@ vi.mock('@/components/Brand.vue', () => ({
|
|||||||
default: { template: '<div class="brand-stub" />' },
|
default: { template: '<div class="brand-stub" />' },
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
function getSetupState(w: ReturnType<typeof mount>) {
|
||||||
|
// @ts-expect-error setupState is Vue internal, not in public types
|
||||||
|
return w.getCurrentComponent().setupState
|
||||||
|
}
|
||||||
|
|
||||||
describe('Login Page', () => {
|
describe('Login Page', () => {
|
||||||
let wrapper: ReturnType<typeof mount>
|
let wrapper: ReturnType<typeof mount>
|
||||||
|
|
||||||
@@ -89,7 +94,7 @@ describe('Login Page', () => {
|
|||||||
async function submitLogin(
|
async function submitLogin(
|
||||||
fields: { username: string; password: string; remember?: boolean },
|
fields: { username: string; password: string; remember?: boolean },
|
||||||
) {
|
) {
|
||||||
const vm = wrapper.getCurrentComponent().setupState
|
const vm = getSetupState(wrapper)
|
||||||
vm.formState.username = fields.username
|
vm.formState.username = fields.username
|
||||||
vm.formState.password = fields.password
|
vm.formState.password = fields.password
|
||||||
if (fields.remember !== undefined) vm.formState.remember = fields.remember
|
if (fields.remember !== undefined) vm.formState.remember = fields.remember
|
||||||
@@ -188,7 +193,7 @@ describe('Login Page', () => {
|
|||||||
it('shows error message on ApiError', async () => {
|
it('shows error message on ApiError', async () => {
|
||||||
const { api } = await import('@/utils/request')
|
const { api } = await import('@/utils/request')
|
||||||
vi.mocked(api.post).mockRejectedValueOnce(new ApiError('用户名或密码错误', 401))
|
vi.mocked(api.post).mockRejectedValueOnce(new ApiError('用户名或密码错误', 401))
|
||||||
const errorSpy = vi.spyOn(message, 'error').mockImplementation(() => ({}) as any)
|
const errorSpy = vi.spyOn(message, 'error').mockImplementation(() => ({}) as never)
|
||||||
|
|
||||||
await mountPage()
|
await mountPage()
|
||||||
await submitLogin({ username: 'user', password: 'wrong' })
|
await submitLogin({ username: 'user', password: 'wrong' })
|
||||||
@@ -200,7 +205,7 @@ describe('Login Page', () => {
|
|||||||
it('shows network error message on generic error', async () => {
|
it('shows network error message on generic error', async () => {
|
||||||
const { api } = await import('@/utils/request')
|
const { api } = await import('@/utils/request')
|
||||||
vi.mocked(api.post).mockRejectedValueOnce(new Error('Network failure'))
|
vi.mocked(api.post).mockRejectedValueOnce(new Error('Network failure'))
|
||||||
const errorSpy = vi.spyOn(message, 'error').mockImplementation(() => ({}) as any)
|
const errorSpy = vi.spyOn(message, 'error').mockImplementation(() => ({}) as never)
|
||||||
|
|
||||||
await mountPage()
|
await mountPage()
|
||||||
await submitLogin({ username: 'user', password: 'pass' })
|
await submitLogin({ username: 'user', password: 'pass' })
|
||||||
@@ -211,7 +216,7 @@ describe('Login Page', () => {
|
|||||||
|
|
||||||
it('navigates to register page', async () => {
|
it('navigates to register page', async () => {
|
||||||
await mountPage()
|
await mountPage()
|
||||||
const vm = wrapper.getCurrentComponent().setupState
|
const vm = getSetupState(wrapper)
|
||||||
vm.goToRegister()
|
vm.goToRegister()
|
||||||
|
|
||||||
expect(mockPush).toHaveBeenCalledWith('/register')
|
expect(mockPush).toHaveBeenCalledWith('/register')
|
||||||
|
|||||||
@@ -39,6 +39,11 @@ vi.mock('@/components/Brand.vue', () => ({
|
|||||||
default: { template: '<div class="brand-stub" />' },
|
default: { template: '<div class="brand-stub" />' },
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
function getSetupState(w: ReturnType<typeof mount>) {
|
||||||
|
// @ts-expect-error setupState is Vue internal, not in public types
|
||||||
|
return w.getCurrentComponent().setupState
|
||||||
|
}
|
||||||
|
|
||||||
describe('Register Page', () => {
|
describe('Register Page', () => {
|
||||||
let wrapper: ReturnType<typeof mount>
|
let wrapper: ReturnType<typeof mount>
|
||||||
|
|
||||||
@@ -88,11 +93,11 @@ describe('Register Page', () => {
|
|||||||
it('calls /api/v1/register and redirects to /login on success without token', async () => {
|
it('calls /api/v1/register and redirects to /login on success without token', async () => {
|
||||||
const { api } = await import('@/utils/request')
|
const { api } = await import('@/utils/request')
|
||||||
vi.mocked(api.post).mockResolvedValueOnce({})
|
vi.mocked(api.post).mockResolvedValueOnce({})
|
||||||
const successSpy = vi.spyOn(message, 'success').mockImplementation(() => ({}) as any)
|
const successSpy = vi.spyOn(message, 'success').mockImplementation(() => ({}) as never)
|
||||||
|
|
||||||
await mountPage()
|
await mountPage()
|
||||||
const store = useUserStore()
|
const store = useUserStore()
|
||||||
const vm = wrapper.getCurrentComponent().setupState
|
const vm = getSetupState(wrapper)
|
||||||
vm.formState.username = 'newuser'
|
vm.formState.username = 'newuser'
|
||||||
vm.formState.email = 'new@test.com'
|
vm.formState.email = 'new@test.com'
|
||||||
vm.formState.password = 'password123'
|
vm.formState.password = 'password123'
|
||||||
@@ -122,11 +127,11 @@ describe('Register Page', () => {
|
|||||||
user: { id: 2, username: 'newuser', email: 'new@test.com', role: 'user', status: 1 },
|
user: { id: 2, username: 'newuser', email: 'new@test.com', role: 'user', status: 1 },
|
||||||
}
|
}
|
||||||
vi.mocked(api.post).mockResolvedValueOnce(mockResponse)
|
vi.mocked(api.post).mockResolvedValueOnce(mockResponse)
|
||||||
vi.spyOn(message, 'success').mockImplementation(() => ({}) as any)
|
vi.spyOn(message, 'success').mockImplementation(() => ({}) as never)
|
||||||
|
|
||||||
await mountPage()
|
await mountPage()
|
||||||
const store = useUserStore()
|
const store = useUserStore()
|
||||||
const vm = wrapper.getCurrentComponent().setupState
|
const vm = getSetupState(wrapper)
|
||||||
vm.formState.username = 'newuser'
|
vm.formState.username = 'newuser'
|
||||||
vm.formState.email = 'new@test.com'
|
vm.formState.email = 'new@test.com'
|
||||||
vm.formState.password = 'password123'
|
vm.formState.password = 'password123'
|
||||||
@@ -145,10 +150,10 @@ describe('Register Page', () => {
|
|||||||
it('shows error message on ApiError', async () => {
|
it('shows error message on ApiError', async () => {
|
||||||
const { api } = await import('@/utils/request')
|
const { api } = await import('@/utils/request')
|
||||||
vi.mocked(api.post).mockRejectedValueOnce(new ApiError('用户名已存在', 409))
|
vi.mocked(api.post).mockRejectedValueOnce(new ApiError('用户名已存在', 409))
|
||||||
const errorSpy = vi.spyOn(message, 'error').mockImplementation(() => ({}) as any)
|
const errorSpy = vi.spyOn(message, 'error').mockImplementation(() => ({}) as never)
|
||||||
|
|
||||||
await mountPage()
|
await mountPage()
|
||||||
const vm = wrapper.getCurrentComponent().setupState
|
const vm = getSetupState(wrapper)
|
||||||
vm.formState.username = 'existing'
|
vm.formState.username = 'existing'
|
||||||
vm.formState.email = 'e@test.com'
|
vm.formState.email = 'e@test.com'
|
||||||
vm.formState.password = 'password123'
|
vm.formState.password = 'password123'
|
||||||
@@ -164,10 +169,10 @@ describe('Register Page', () => {
|
|||||||
it('shows network error message on generic error', async () => {
|
it('shows network error message on generic error', async () => {
|
||||||
const { api } = await import('@/utils/request')
|
const { api } = await import('@/utils/request')
|
||||||
vi.mocked(api.post).mockRejectedValueOnce(new Error('Network failure'))
|
vi.mocked(api.post).mockRejectedValueOnce(new Error('Network failure'))
|
||||||
const errorSpy = vi.spyOn(message, 'error').mockImplementation(() => ({}) as any)
|
const errorSpy = vi.spyOn(message, 'error').mockImplementation(() => ({}) as never)
|
||||||
|
|
||||||
await mountPage()
|
await mountPage()
|
||||||
const vm = wrapper.getCurrentComponent().setupState
|
const vm = getSetupState(wrapper)
|
||||||
vm.formState.username = 'user'
|
vm.formState.username = 'user'
|
||||||
vm.formState.email = 'u@test.com'
|
vm.formState.email = 'u@test.com'
|
||||||
vm.formState.password = 'password123'
|
vm.formState.password = 'password123'
|
||||||
@@ -182,7 +187,7 @@ describe('Register Page', () => {
|
|||||||
|
|
||||||
it('navigates to login page', async () => {
|
it('navigates to login page', async () => {
|
||||||
await mountPage()
|
await mountPage()
|
||||||
const vm = wrapper.getCurrentComponent().setupState
|
const vm = getSetupState(wrapper)
|
||||||
vm.goToLogin()
|
vm.goToLogin()
|
||||||
|
|
||||||
expect(mockPush).toHaveBeenCalledWith('/login')
|
expect(mockPush).toHaveBeenCalledWith('/login')
|
||||||
|
|||||||
@@ -33,6 +33,11 @@ vi.mock('vue-router', () => ({
|
|||||||
useRoute: () => ({ path: '/profile' }),
|
useRoute: () => ({ path: '/profile' }),
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
function getSetupState(w: ReturnType<typeof mount>) {
|
||||||
|
// @ts-expect-error setupState is Vue internal, not in public types
|
||||||
|
return w.getCurrentComponent().setupState
|
||||||
|
}
|
||||||
|
|
||||||
describe('Profile Page', () => {
|
describe('Profile Page', () => {
|
||||||
let wrapper: ReturnType<typeof mount>
|
let wrapper: ReturnType<typeof mount>
|
||||||
|
|
||||||
@@ -74,7 +79,7 @@ describe('Profile Page', () => {
|
|||||||
|
|
||||||
it('pre-fills email form field', async () => {
|
it('pre-fills email form field', async () => {
|
||||||
await mountPage()
|
await mountPage()
|
||||||
const vm = wrapper.getCurrentComponent().setupState
|
const vm = getSetupState(wrapper)
|
||||||
|
|
||||||
expect(vm.formState.email).toBe('test@example.com')
|
expect(vm.formState.email).toBe('test@example.com')
|
||||||
})
|
})
|
||||||
@@ -86,7 +91,7 @@ describe('Profile Page', () => {
|
|||||||
const successSpy = vi.spyOn(message, 'success').mockImplementation(() => ({}) as never)
|
const successSpy = vi.spyOn(message, 'success').mockImplementation(() => ({}) as never)
|
||||||
|
|
||||||
await mountPage()
|
await mountPage()
|
||||||
const vm = wrapper.getCurrentComponent().setupState
|
const vm = getSetupState(wrapper)
|
||||||
vm.formState.email = 'new@example.com'
|
vm.formState.email = 'new@example.com'
|
||||||
vm.formRef = { validate: vi.fn().mockResolvedValue(true) }
|
vm.formRef = { validate: vi.fn().mockResolvedValue(true) }
|
||||||
await vm.handleSubmit()
|
await vm.handleSubmit()
|
||||||
@@ -103,7 +108,7 @@ describe('Profile Page', () => {
|
|||||||
const errorSpy = vi.spyOn(message, 'error').mockImplementation(() => ({}) as never)
|
const errorSpy = vi.spyOn(message, 'error').mockImplementation(() => ({}) as never)
|
||||||
|
|
||||||
await mountPage()
|
await mountPage()
|
||||||
const vm = wrapper.getCurrentComponent().setupState
|
const vm = getSetupState(wrapper)
|
||||||
vm.formRef = { validate: vi.fn().mockResolvedValue(true) }
|
vm.formRef = { validate: vi.fn().mockResolvedValue(true) }
|
||||||
await vm.handleSubmit()
|
await vm.handleSubmit()
|
||||||
await flushPromises()
|
await flushPromises()
|
||||||
@@ -118,7 +123,7 @@ describe('Profile Page', () => {
|
|||||||
const errorSpy = vi.spyOn(message, 'error').mockImplementation(() => ({}) as never)
|
const errorSpy = vi.spyOn(message, 'error').mockImplementation(() => ({}) as never)
|
||||||
|
|
||||||
await mountPage()
|
await mountPage()
|
||||||
const vm = wrapper.getCurrentComponent().setupState
|
const vm = getSetupState(wrapper)
|
||||||
vm.formRef = { validate: vi.fn().mockResolvedValue(true) }
|
vm.formRef = { validate: vi.fn().mockResolvedValue(true) }
|
||||||
await vm.handleSubmit()
|
await vm.handleSubmit()
|
||||||
await flushPromises()
|
await flushPromises()
|
||||||
|
|||||||
@@ -35,6 +35,11 @@ vi.mock('vue-router', () => ({
|
|||||||
useRoute: () => ({ path: '/profile/password' }),
|
useRoute: () => ({ path: '/profile/password' }),
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
function getSetupState(w: ReturnType<typeof mount>) {
|
||||||
|
// @ts-expect-error setupState is Vue internal, not in public types
|
||||||
|
return w.getCurrentComponent().setupState
|
||||||
|
}
|
||||||
|
|
||||||
describe('Password Change Page', () => {
|
describe('Password Change Page', () => {
|
||||||
let wrapper: ReturnType<typeof mount>
|
let wrapper: ReturnType<typeof mount>
|
||||||
|
|
||||||
@@ -78,7 +83,7 @@ describe('Password Change Page', () => {
|
|||||||
const successSpy = vi.spyOn(message, 'success').mockImplementation(() => ({}) as never)
|
const successSpy = vi.spyOn(message, 'success').mockImplementation(() => ({}) as never)
|
||||||
|
|
||||||
await mountPage()
|
await mountPage()
|
||||||
const vm = wrapper.getCurrentComponent().setupState
|
const vm = getSetupState(wrapper)
|
||||||
vm.formState.old_password = 'oldpass'
|
vm.formState.old_password = 'oldpass'
|
||||||
vm.formState.new_password = 'newpass123'
|
vm.formState.new_password = 'newpass123'
|
||||||
vm.formState.new_password_confirmation = 'newpass123'
|
vm.formState.new_password_confirmation = 'newpass123'
|
||||||
@@ -104,7 +109,7 @@ describe('Password Change Page', () => {
|
|||||||
const errorSpy = vi.spyOn(message, 'error').mockImplementation(() => ({}) as never)
|
const errorSpy = vi.spyOn(message, 'error').mockImplementation(() => ({}) as never)
|
||||||
|
|
||||||
await mountPage()
|
await mountPage()
|
||||||
const vm = wrapper.getCurrentComponent().setupState
|
const vm = getSetupState(wrapper)
|
||||||
vm.formState.old_password = 'wrong'
|
vm.formState.old_password = 'wrong'
|
||||||
vm.formState.new_password = 'newpass123'
|
vm.formState.new_password = 'newpass123'
|
||||||
vm.formState.new_password_confirmation = 'newpass123'
|
vm.formState.new_password_confirmation = 'newpass123'
|
||||||
@@ -123,7 +128,7 @@ describe('Password Change Page', () => {
|
|||||||
const errorSpy = vi.spyOn(message, 'error').mockImplementation(() => ({}) as never)
|
const errorSpy = vi.spyOn(message, 'error').mockImplementation(() => ({}) as never)
|
||||||
|
|
||||||
await mountPage()
|
await mountPage()
|
||||||
const vm = wrapper.getCurrentComponent().setupState
|
const vm = getSetupState(wrapper)
|
||||||
vm.formRef = { validate: vi.fn().mockResolvedValue(true) }
|
vm.formRef = { validate: vi.fn().mockResolvedValue(true) }
|
||||||
await vm.handleSubmit()
|
await vm.handleSubmit()
|
||||||
await flushPromises()
|
await flushPromises()
|
||||||
@@ -138,7 +143,7 @@ describe('Password Change Page', () => {
|
|||||||
vi.spyOn(message, 'error').mockImplementation(() => ({}) as never)
|
vi.spyOn(message, 'error').mockImplementation(() => ({}) as never)
|
||||||
|
|
||||||
await mountPage()
|
await mountPage()
|
||||||
const vm = wrapper.getCurrentComponent().setupState
|
const vm = getSetupState(wrapper)
|
||||||
vm.formRef = { validate: vi.fn().mockResolvedValue(true) }
|
vm.formRef = { validate: vi.fn().mockResolvedValue(true) }
|
||||||
await vm.handleSubmit()
|
await vm.handleSubmit()
|
||||||
await flushPromises()
|
await flushPromises()
|
||||||
|
|||||||
@@ -18,15 +18,20 @@ const rules = {
|
|||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(async () => {
|
||||||
if (userStore.user) {
|
if (userStore.user) {
|
||||||
formState.email = userStore.user.email || ''
|
formState.email = userStore.user.email || ''
|
||||||
}
|
}
|
||||||
userStore.fetchCurrentUser().then(() => {
|
try {
|
||||||
|
await userStore.fetchCurrentUser()
|
||||||
if (userStore.user) {
|
if (userStore.user) {
|
||||||
formState.email = userStore.user.email || ''
|
formState.email = userStore.user.email || ''
|
||||||
}
|
}
|
||||||
})
|
} catch (error: unknown) {
|
||||||
|
if (error instanceof ApiError) {
|
||||||
|
message.error(error.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ describe('useUserManageStore', () => {
|
|||||||
it('sets loading to false and shows error message on failure', async () => {
|
it('sets loading to false and shows error message on failure', async () => {
|
||||||
const { api } = await import('@/utils/request')
|
const { api } = await import('@/utils/request')
|
||||||
vi.mocked(api.get).mockRejectedValueOnce(new Error('Network error'))
|
vi.mocked(api.get).mockRejectedValueOnce(new Error('Network error'))
|
||||||
const errorSpy = vi.spyOn(message, 'error').mockImplementation(() => ({}) as any)
|
const errorSpy = vi.spyOn(message, 'error').mockImplementation(() => ({}) as never)
|
||||||
|
|
||||||
const store = useUserManageStore()
|
const store = useUserManageStore()
|
||||||
await store.fetchUsers()
|
await store.fetchUsers()
|
||||||
|
|||||||
@@ -175,7 +175,7 @@ describe('UserFormModal', () => {
|
|||||||
|
|
||||||
// 验证 PUT payload 包含 status 且不包含 ext
|
// 验证 PUT payload 包含 status 且不包含 ext
|
||||||
expect(api.put).toHaveBeenCalledOnce()
|
expect(api.put).toHaveBeenCalledOnce()
|
||||||
const [url, payload] = vi.mocked(api.put).mock.calls[0]
|
const [url, payload] = vi.mocked(api.put).mock.calls[0]!
|
||||||
expect(url).toContain('/api/v1/users/')
|
expect(url).toContain('/api/v1/users/')
|
||||||
expect(payload).toHaveProperty('status')
|
expect(payload).toHaveProperty('status')
|
||||||
expect(payload).not.toHaveProperty('ext')
|
expect(payload).not.toHaveProperty('ext')
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ async function request<T = unknown>(url: string, options: RequestOptions = {}):
|
|||||||
url = `${url}${separator}${query}`
|
url = `${url}${separator}${query}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
const { params: _params, timeout: _timeout, ...fetchOptions } = options
|
const { params: _params, timeout: _timeout, ...fetchOptions } = options
|
||||||
|
|
||||||
// 超时控制
|
// 超时控制
|
||||||
|
|||||||
Reference in New Issue
Block a user