提交 89d5a908 authored 作者: 王鹏飞's avatar 王鹏飞

feat: 优化上传逻辑,添加成功提示信息,调整 API 调用方式

上级 a46dc4da
...@@ -71,13 +71,20 @@ describe('OSS upload progress', () => { ...@@ -71,13 +71,20 @@ describe('OSS upload progress', () => {
client.generateObjectUrl.mockReturnValue('https://example.com/video.mp4') client.generateObjectUrl.mockReturnValue('https://example.com/video.mp4')
const onProgress = vi.fn() const onProgress = vi.fn()
await expect( await expect(uploadFile({ name: 'video.mp4' }, { onProgress })).resolves.toBe(
uploadFile({ name: 'video.mp4' }, { onProgress, parallel: 3, retries: 3 }), 'https://example.com/video.mp4',
).resolves.toBe('https://example.com/video.mp4') )
expect(client.multipartUpload).toHaveBeenCalledTimes(2) expect(client.multipartUpload).toHaveBeenCalledTimes(2)
expect(client.multipartUpload.mock.calls[0][2]).toMatchObject({ parallel: 3 }) expect(client.multipartUpload.mock.calls[0][2]).toMatchObject({
expect(client.multipartUpload.mock.calls[1][2]).toMatchObject({ checkpoint, parallel: 3 }) partSize: 4 * 1024 * 1024,
parallel: 3,
})
expect(client.multipartUpload.mock.calls[1][2]).toMatchObject({
checkpoint,
partSize: 4 * 1024 * 1024,
parallel: 3,
})
expect(onProgress.mock.calls.map(([percent]) => percent)).toEqual([50, 100]) expect(onProgress.mock.calls.map(([percent]) => percent)).toEqual([50, 100])
}) })
}) })
...@@ -122,13 +122,14 @@ const ExpandModal = (props, ref) => { ...@@ -122,13 +122,14 @@ const ExpandModal = (props, ref) => {
SlateTransforms.insertNodes(editor, nextNode, { at: existingPath }) SlateTransforms.insertNodes(editor, nextNode, { at: existingPath })
} }
const data = await addExpandRead({ await addExpandRead({
book_id: bookId, book_id: bookId,
chapter_id: chapterId, chapter_id: chapterId,
position: nowRandom, position: nowRandom,
type: flex, type: flex,
...other, ...other,
}) })
message.success('扩展阅读更新成功')
setNowRandom(null) setNowRandom(null)
setExpandVisible(false) setExpandVisible(false)
setLoadLoading(false) setLoadLoading(false)
...@@ -136,13 +137,14 @@ const ExpandModal = (props, ref) => { ...@@ -136,13 +137,14 @@ const ExpandModal = (props, ref) => {
} }
const random = Math.random().toString(10).substring(2, 10) const random = Math.random().toString(10).substring(2, 10)
const data = await addExpandRead({ await addExpandRead({
book_id: bookId, book_id: bookId,
chapter_id: chapterId, chapter_id: chapterId,
position: random, position: random,
type: flex, type: flex,
...other, ...other,
}) })
message.success('扩展阅读添加成功')
editor.restoreSelection() editor.restoreSelection()
if (parseInt(values.flex) === 1) { if (parseInt(values.flex) === 1) {
......
import { useState, useEffect, forwardRef } from 'react' import { useState, useEffect, forwardRef } from 'react'
import { Divider, Input, Space, Button, Form, ColorPicker, Tabs, Select, Row, Col } from 'antd' import {
Divider,
Input,
Space,
Button,
Form,
ColorPicker,
Tabs,
Select,
Row,
Col,
message,
} from 'antd'
import '../../index.less' import '../../index.less'
import { addGallery } from '../../shared/request' import { addGallery } from '../../shared/request'
import { SlateTransforms } from '@wangeditor/editor' import { SlateTransforms } from '@wangeditor/editor'
...@@ -230,6 +242,7 @@ const GalleryModal = (props, ref) => { ...@@ -230,6 +242,7 @@ const GalleryModal = (props, ref) => {
content: JSON.stringify(gallery), content: JSON.stringify(gallery),
position: nowRandom, position: nowRandom,
}) })
message.success('画廊更新成功')
if (flex === 2) { if (flex === 2) {
const aPath = findNodeWithParent( const aPath = findNodeWithParent(
...@@ -260,6 +273,7 @@ const GalleryModal = (props, ref) => { ...@@ -260,6 +273,7 @@ const GalleryModal = (props, ref) => {
content: JSON.stringify(gallery), content: JSON.stringify(gallery),
position: random, position: random,
}) })
message.success('画廊添加成功')
editor.restoreSelection() editor.restoreSelection()
if (parseInt(flex) !== 2) { if (parseInt(flex) !== 2) {
removeSelectedEmptyParagraph(editor, SlateTransforms) removeSelectedEmptyParagraph(editor, SlateTransforms)
......
import { DomEditor, SlateTransforms } from '@wangeditor/editor' import { DomEditor, SlateTransforms } from '@wangeditor/editor'
import { h } from 'snabbdom' import { h } from 'snabbdom'
import { message } from 'antd'
import { openEditorDialog } from '../../core/editor-dialog' import { openEditorDialog } from '../../core/editor-dialog'
import iconClose from '@/assets/images/icon_chapter_close.png' import iconClose from '@/assets/images/icon_chapter_close.png'
import { delChapterTopic } from '../../shared/request' import { delChapterTopic } from '../../shared/request'
...@@ -127,6 +128,7 @@ const renderPractice = (elem, children, editor) => { ...@@ -127,6 +128,7 @@ const renderPractice = (elem, children, editor) => {
book_id: bookId, book_id: bookId,
chapter_id: chapterId, chapter_id: chapterId,
}) })
message.success('题目删除成功')
try { try {
const path = findNodeWithParent( const path = findNodeWithParent(
......
...@@ -142,6 +142,7 @@ const TooltipModal = (props, ref) => { ...@@ -142,6 +142,7 @@ const TooltipModal = (props, ref) => {
chapter_id: chapterId, chapter_id: chapterId,
position: nowRandom, position: nowRandom,
}) })
message.success('气泡删除成功')
if (data) { if (data) {
editor.restoreSelection() editor.restoreSelection()
const nodeEntries = SlateEditor.nodes(editor, { const nodeEntries = SlateEditor.nodes(editor, {
......
...@@ -50,8 +50,6 @@ const VideoModal = ({ open, onClose, payload = {}, runtime }) => { ...@@ -50,8 +50,6 @@ const VideoModal = ({ open, onClose, payload = {}, runtime }) => {
setUploadProgress(0) setUploadProgress(0)
try { try {
const url = await uploadFile(file, { const url = await uploadFile(file, {
parallel: 3,
retries: 3,
onProgress: (percent) => { onProgress: (percent) => {
setUploadProgress(percent) setUploadProgress(percent)
onProgress?.({ percent }) onProgress?.({ percent })
......
...@@ -12,14 +12,18 @@ function DebounceSelect({ fetchOptions, debounceTimeout = 800, ...props }) { ...@@ -12,14 +12,18 @@ function DebounceSelect({ fetchOptions, debounceTimeout = 800, ...props }) {
const fetchId = fetchRef.current const fetchId = fetchRef.current
setOptions([]) setOptions([])
setFetching(true) setFetching(true)
fetchOptions(value).then((newOptions) => { fetchOptions(value)
if (fetchId !== fetchRef.current) { .then((newOptions) => {
// for fetch callback order if (fetchId !== fetchRef.current) {
return // for fetch callback order
} return
setOptions(newOptions) }
setFetching(false) setOptions(newOptions)
}) })
.catch(() => undefined)
.finally(() => {
if (fetchId === fetchRef.current) setFetching(false)
})
} }
return debounce(loadOptions, debounceTimeout) return debounce(loadOptions, debounceTimeout)
}, [fetchOptions, debounceTimeout]) }, [fetchOptions, debounceTimeout])
...@@ -29,6 +33,12 @@ function DebounceSelect({ fetchOptions, debounceTimeout = 800, ...props }) { ...@@ -29,6 +33,12 @@ function DebounceSelect({ fetchOptions, debounceTimeout = 800, ...props }) {
showSearch={{ filterOption: false, onSearch: debounceFetcher }} showSearch={{ filterOption: false, onSearch: debounceFetcher }}
notFoundContent={fetching ? <Spin size='small' /> : null} notFoundContent={fetching ? <Spin size='small' /> : null}
{...props} {...props}
onOpenChange={(open) => {
if (open) {
debounceFetcher('')
debounceFetcher.flush()
}
}}
options={options} options={options}
/> />
) )
......
...@@ -3,8 +3,11 @@ import axios, { notifySuccess } from '@/utils/axios' ...@@ -3,8 +3,11 @@ import axios, { notifySuccess } from '@/utils/axios'
export const getUserInfo = async (params) => export const getUserInfo = async (params) =>
(await axios.post('/api/admin/user/user/getUserInfo', params)).data (await axios.post('/api/admin/user/user/getUserInfo', params)).data
export const changePass = async (params) => export const changePass = async (params) => {
(await axios.post('/api/admin/user/user/changePass', params)).data const response = await axios.post('/api/admin/user/user/changePass', params)
notifySuccess(response.message)
return response.data
}
export const changeInfo = async (params) => { export const changeInfo = async (params) => {
const response = await axios.post('/api/admin/user/user/editUserInfo', params) const response = await axios.post('/api/admin/user/user/editUserInfo', params)
......
...@@ -71,13 +71,13 @@ export const getAllList = async (params) => { ...@@ -71,13 +71,13 @@ export const getAllList = async (params) => {
export const chapterAdd = (params) => getData('/api/admin/book/teacher/chapter/add', params) export const chapterAdd = (params) => getData('/api/admin/book/teacher/chapter/add', params)
export const getInfoById = (params) => export const getInfoById = (params) =>
getData('/api/admin/book/teacher/chapter/getInfoById', params) getData('/api/admin/book/teacher/chapter/getInfoById', params)
export const chapterEdit = (params) => mutate('/api/admin/book/teacher/chapter/edit', params, true) export const chapterEdit = (params) => mutate('/api/admin/book/teacher/chapter/edit', params)
export const chapterDel = (params) => mutate('/api/admin/book/teacher/chapter/del', params, true) export const chapterDel = (params) => mutate('/api/admin/book/teacher/chapter/del', params, true)
export const dragOrder = (params) => export const dragOrder = (params) =>
mutate('/api/admin/book/teacher/chapter/dragOrder', params, true) mutate('/api/admin/book/teacher/chapter/dragOrder', params, true)
export const getInfoByChapterId = (params) => export const getInfoByChapterId = (params) =>
getData('/api/admin/book/teacher/section/getInfoByChapterId', params) getData('/api/admin/book/teacher/section/getInfoByChapterId', params)
export const sectionAdd = (params) => mutate('/api/admin/book/teacher/section/add', params, true) export const sectionAdd = (params) => mutate('/api/admin/book/teacher/section/add', params)
export const sectionEdit = (params) => mutate('/api/admin/book/teacher/section/edit', params) export const sectionEdit = (params) => mutate('/api/admin/book/teacher/section/edit', params)
export const getQuestionList = (params) => export const getQuestionList = (params) =>
getData('/api/admin/book/chapter/question/getQuestionList', params) getData('/api/admin/book/chapter/question/getQuestionList', params)
......
import { useState, useEffect, useRef } from 'react' import { useState, useEffect, useRef } from 'react'
import { Form, Button, Space, Input } from 'antd' import { Form, Button, Space, Input, message } from 'antd'
import { useUserStore } from '@/stores/userStore' import { useUserStore } from '@/stores/userStore'
import { chapterEdit, chapterAdd, sectionAdd } from '../api' import { chapterEdit, chapterAdd, sectionAdd } from '../api'
...@@ -57,6 +57,7 @@ const EditChapterTitle = (props) => { ...@@ -57,6 +57,7 @@ const EditChapterTitle = (props) => {
if (parentId) { if (parentId) {
await sectionAdd({ book_id: bookId, chapter_id: data.id, content: '', word_count: 0 }) await sectionAdd({ book_id: bookId, chapter_id: data.id, content: '', word_count: 0 })
} }
message.success(parentId ? '章节创建成功' : '章节更新成功')
setEditKey(false) setEditKey(false)
setEditValue(null) setEditValue(null)
await getChapterTreeList() await getChapterTreeList()
......
import { useState, useEffect, useRef, useCallback } from 'react' import { useState, useEffect, useRef, useCallback } from 'react'
import { Button, Row, Col, Descriptions, Tree, Dropdown, Modal, Spin, App, Tooltip } from 'antd' import {
Button,
Row,
Col,
Descriptions,
Tree,
Dropdown,
Modal,
Spin,
App,
Tooltip,
Empty,
} from 'antd'
import { import {
EllipsisOutlined, EllipsisOutlined,
DiffOutlined, DiffOutlined,
...@@ -134,6 +146,18 @@ const Examine = () => { ...@@ -134,6 +146,18 @@ const Examine = () => {
} }
if (data.length === 0) { if (data.length === 0) {
chapterRequestRef.current += 1
setGData([])
setExpandedKeys([])
setCheckedKeys([])
setChapterId(0)
setNowTitle('')
setHtml('')
setContentId(false)
setLoadedChapterId(0)
setChapterLoadFailed(false)
contentMd5Ref.current = md5('')
setTreeChapter({ saveBookId: id, saveChapterId: null })
setLoading(false) setLoading(false)
return return
} }
...@@ -538,6 +562,15 @@ const Examine = () => { ...@@ -538,6 +562,15 @@ const Examine = () => {
<div className='book-content-editor' style={{ flex: 1, minWidth: 0 }}> <div className='book-content-editor' style={{ flex: 1, minWidth: 0 }}>
<div className='editor-right'> <div className='editor-right'>
<Spin spinning={loading}> <Spin spinning={loading}>
{!loading && gData.length === 0 && (
<Empty className='chapter-empty' description='暂无章节'>
{isAdminOrCreator && (
<Button type='primary' onClick={addChapterParent}>
新增第一个章节
</Button>
)}
</Empty>
)}
{editorReady && ( {editorReady && (
<WangEditorCustomer <WangEditorCustomer
key={chapterId} key={chapterId}
......
...@@ -92,6 +92,13 @@ ...@@ -92,6 +92,13 @@
gap: 12px; gap: 12px;
color: #6f7886; color: #6f7886;
} }
.chapter-empty {
display: flex;
height: 100%;
flex-direction: column;
align-items: center;
justify-content: center;
}
} }
.draggable-tree { .draggable-tree {
flex: 1; flex: 1;
......
import { act, fireEvent, render, screen, waitFor } from '@testing-library/react' import { act, cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react'
import type { ComponentProps, ReactNode } from 'react' import type { ComponentProps, ReactNode } from 'react'
import { beforeEach, describe, expect, it, vi } from 'vitest' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import Examine from './index' import Examine from './index'
const mocks = vi.hoisted(() => ({ const mocks = vi.hoisted(() => ({
chapterDel: vi.fn(),
confirm: vi.fn(),
getAllList: vi.fn(), getAllList: vi.fn(),
getInfoByChapterId: vi.fn(), getInfoByChapterId: vi.fn(),
sectionEdit: vi.fn(), sectionEdit: vi.fn(),
...@@ -16,7 +18,7 @@ vi.mock('antd', () => { ...@@ -16,7 +18,7 @@ vi.mock('antd', () => {
const PassThrough = ({ children }: { children?: ReactNode }) => <>{children}</> const PassThrough = ({ children }: { children?: ReactNode }) => <>{children}</>
return { return {
App: { useApp: () => ({ modal: { confirm: vi.fn() } }) }, App: { useApp: () => ({ modal: { confirm: mocks.confirm } }) },
Button: ({ children, onClick, ...props }: ComponentProps<'button'>) => ( Button: ({ children, onClick, ...props }: ComponentProps<'button'>) => (
<button onClick={onClick} {...props}> <button onClick={onClick} {...props}>
{children} {children}
...@@ -30,7 +32,34 @@ vi.mock('antd', () => { ...@@ -30,7 +32,34 @@ vi.mock('antd', () => {
))} ))}
</> </>
), ),
Dropdown: PassThrough, Dropdown: ({
children,
menu,
}: {
children?: ReactNode
menu?: {
items?: Array<{ key: string; label: string }>
onClick: (event: { key: string; domEvent: { stopPropagation: () => void } }) => void
}
}) => (
<>
{children}
{menu?.items?.map((item: { key: string; label: string }) => (
<button
key={item.key}
onClick={() => menu.onClick({ key: item.key, domEvent: { stopPropagation: vi.fn() } })}
>
{item.label}
</button>
))}
</>
),
Empty: ({ children, description }: { children?: ReactNode; description?: ReactNode }) => (
<div>
{description}
{children}
</div>
),
Modal: ({ children, open }: { children?: ReactNode; open?: boolean }) => Modal: ({ children, open }: { children?: ReactNode; open?: boolean }) =>
open ? <>{children}</> : null, open ? <>{children}</> : null,
Row: PassThrough, Row: PassThrough,
...@@ -39,17 +68,22 @@ vi.mock('antd', () => { ...@@ -39,17 +68,22 @@ vi.mock('antd', () => {
Tree: ({ Tree: ({
disabled, disabled,
onSelect, onSelect,
titleRender,
treeData = [], treeData = [],
}: { }: {
disabled?: boolean disabled?: boolean
onSelect: (keys: number[], info: { node: { key: number; title: string } }) => void onSelect: (keys: number[], info: { node: { key: number; title: string } }) => void
titleRender?: (node: { key: number; title: string }) => ReactNode
treeData?: Array<{ key: number; title: string }> treeData?: Array<{ key: number; title: string }>
}) => ( }) => (
<div> <div>
{treeData.map((node) => ( {treeData.map((node) => (
<button key={node.key} disabled={disabled} onClick={() => onSelect([node.key], { node })}> <div key={node.key}>
{node.title} <button disabled={disabled} onClick={() => onSelect([node.key], { node })}>
</button> {node.title}
</button>
{titleRender?.(node)}
</div>
))} ))}
</div> </div>
), ),
...@@ -115,7 +149,7 @@ vi.mock('@/utils/common', () => ({ ...@@ -115,7 +149,7 @@ vi.mock('@/utils/common', () => ({
})) }))
vi.mock('./api', () => ({ vi.mock('./api', () => ({
chapterDel: vi.fn(), chapterDel: mocks.chapterDel,
dragOrder: vi.fn(), dragOrder: vi.fn(),
getAllList: mocks.getAllList, getAllList: mocks.getAllList,
getInfoByChapterId: mocks.getInfoByChapterId, getInfoByChapterId: mocks.getInfoByChapterId,
...@@ -135,8 +169,12 @@ const deferred = <T,>() => { ...@@ -135,8 +169,12 @@ const deferred = <T,>() => {
} }
describe('chapter editor lifecycle', () => { describe('chapter editor lifecycle', () => {
afterEach(cleanup)
beforeEach(() => { beforeEach(() => {
vi.clearAllMocks() vi.clearAllMocks()
mocks.chapterDel.mockResolvedValue(true)
mocks.confirm.mockImplementation(({ onOk }) => onOk())
mocks.getAllList.mockResolvedValue({ mocks.getAllList.mockResolvedValue({
code: 200, code: 200,
data: [ data: [
...@@ -188,4 +226,28 @@ describe('chapter editor lifecycle', () => { ...@@ -188,4 +226,28 @@ describe('chapter editor lifecycle', () => {
expect(secondEditor).toHaveAttribute('data-chapter-id', '2') expect(secondEditor).toHaveAttribute('data-chapter-id', '2')
expect(secondEditor).toHaveAttribute('data-html', '<p>章节二内容</p>') expect(secondEditor).toHaveAttribute('data-html', '<p>章节二内容</p>')
}) })
it('clears the last chapter and shows an empty state after deletion', async () => {
mocks.getAllList
.mockResolvedValueOnce({ code: 200, data: [{ id: 1, name: '章节一' }] })
.mockResolvedValueOnce({ code: 200, data: [] })
mocks.getInfoByChapterId.mockResolvedValue({
id: 101,
content: '<p>章节一内容</p>',
selected_editor_ids: [1],
})
render(<Examine />)
expect(await screen.findByTestId('chapter-editor')).toBeInTheDocument()
fireEvent.click(await screen.findByRole('button', { name: '删除' }))
expect(await screen.findByText('暂无章节')).toBeInTheDocument()
expect(screen.queryByTestId('chapter-editor')).not.toBeInTheDocument()
expect(screen.getByRole('button', { name: '新增第一个章节' })).toBeInTheDocument()
expect(mocks.setTreeChapter).toHaveBeenLastCalledWith({
saveBookId: 10,
saveChapterId: null,
})
})
}) })
...@@ -10,6 +10,6 @@ const mutate = async (path, params, notify = false) => { ...@@ -10,6 +10,6 @@ const mutate = async (path, params, notify = false) => {
export const getAppList = (params) => getData('/api/admin/system/app/getList', params) export const getAppList = (params) => getData('/api/admin/system/app/getList', params)
export const addApp = (params) => mutate('/api/admin/system/app/add', params, true) export const addApp = (params) => mutate('/api/admin/system/app/add', params, true)
export const getAppInfo = (params) => getData('/api/admin/system/app/getInfoById', params) export const getAppInfo = (params) => getData('/api/admin/system/app/getInfoById', params)
export const editApp = (params) => getData('/api/admin/system/app/edit', params) export const editApp = (params) => mutate('/api/admin/system/app/edit', params, true)
export const changeStatus = (params) => mutate('/api/admin/system/app/changeStatus', params) export const changeStatus = (params) => mutate('/api/admin/system/app/changeStatus', params, true)
export const delApp = (params) => mutate('/api/admin/system/app/del', params, true) export const delApp = (params) => mutate('/api/admin/system/app/del', params, true)
import { message } from 'antd' import { message } from 'antd'
import axios from '@/utils/axios' import axios, { notifySuccess } from '@/utils/axios'
import type { CouponQuery } from './query' import type { CouponQuery } from './query'
...@@ -47,8 +47,10 @@ export function editCoupon(data: object) { ...@@ -47,8 +47,10 @@ export function editCoupon(data: object) {
return axios.post('/api/admin/system/coupon/edit', data) return axios.post('/api/admin/system/coupon/edit', data)
} }
export function deleteCoupon(data: object) { export async function deleteCoupon(data: object) {
return axios.post('/api/admin/system/coupon/del', data) const response = await axios.post('/api/admin/system/coupon/del', data)
notifySuccess(response.message)
return response
} }
export function getCouponDetail(data: object) { export function getCouponDetail(data: object) {
......
...@@ -145,12 +145,10 @@ const HelpAddEdit = () => { ...@@ -145,12 +145,10 @@ const HelpAddEdit = () => {
// }; // };
try { try {
// message.success(`视频已上传:${uploadProgress}% , 玩命加载中~~`);
message.success(`视频已上传:99% , 正玩命加载中~~`)
const url = await uploadFile(file, { filenamePrefix: 'help' }) const url = await uploadFile(file, { filenamePrefix: 'help' })
// insertFn(result.res.requestUrls[0], '题库视频'); // insertFn(result.res.requestUrls[0], '题库视频');
insertFn(url, '题库视频') insertFn(url, '题库视频')
message.success('视频上传成功')
setLoading(false) setLoading(false)
} catch (error) { } catch (error) {
console.error('上传视频失败:', error) console.error('上传视频失败:', error)
......
...@@ -35,7 +35,10 @@ export async function getPointSettings(): Promise<PointSettings> { ...@@ -35,7 +35,10 @@ export async function getPointSettings(): Promise<PointSettings> {
} }
export async function setPointSwitch(integralSwitch: '0' | '1') { export async function setPointSwitch(integralSwitch: '0' | '1') {
await axios.post('/api/admin/system/config/integralSet', { integral_switch: integralSwitch }) const response = await axios.post('/api/admin/system/config/integralSet', {
integral_switch: integralSwitch,
})
notifySuccess(response.message)
return true return true
} }
......
...@@ -143,7 +143,8 @@ httpRequest.interceptors.response.use( ...@@ -143,7 +143,8 @@ httpRequest.interceptors.response.use(
console.error(`${status}: ${data?.message}`) console.error(`${status}: ${data?.message}`)
} }
} else { } else {
console.log(error) notification.error({ message: '网络请求失败,请稍后重试' })
console.error(error)
} }
return Promise.reject(error.response || error) return Promise.reject(error.response || error)
}, },
......
...@@ -58,14 +58,19 @@ export async function uploadFile(file, options = {}) { ...@@ -58,14 +58,19 @@ export async function uploadFile(file, options = {}) {
const objectName = buildObjectName(file, options) const objectName = buildObjectName(file, options)
if (options.onProgress) { if (options.onProgress) {
const retries = options.retries ?? 0 const {
partSize = 4 * 1024 * 1024,
parallel = 3,
retries = 3,
} = options
let checkpoint let checkpoint
for (let attempt = 0; attempt <= retries; attempt += 1) { for (let attempt = 0; attempt <= retries; attempt += 1) {
try { try {
const result = await oss.multipartUpload(objectName, file, { const result = await oss.multipartUpload(objectName, file, {
checkpoint, checkpoint,
parallel: options.parallel, partSize,
parallel,
progress: (percentage, nextCheckpoint) => { progress: (percentage, nextCheckpoint) => {
checkpoint = nextCheckpoint || checkpoint checkpoint = nextCheckpoint || checkpoint
options.onProgress(Math.round(percentage * 100)) options.onProgress(Math.round(percentage * 100))
......
...@@ -15,13 +15,13 @@ export default defineConfig(() => { ...@@ -15,13 +15,13 @@ export default defineConfig(() => {
port: 5174, port: 5174,
strictPort: true, strictPort: true,
proxy: { proxy: {
// '/api/admin': { '/api/admin': {
// target: 'http://127.0.0.1:7419', target: 'http://127.0.0.1:7419',
// changeOrigin: true, changeOrigin: true,
// secure: false, secure: false,
// rewrite: (path) => path.replace(/^\/api\/admin/, ''), rewrite: (path) => path.replace(/^\/api\/admin/, ''),
// }, },
'/api': 'https://zijingebook.ezijing.com', // '/api': 'https://zijingebook.ezijing.com',
}, },
}, },
build: { build: {
......
Markdown 格式
0% 或
您添加了 0 人 到此讨论。请谨慎行事。
请先完成此评论的编辑!
请 注册 或者 后发表评论