Merge remote-tracking branch 'origin/main'
This commit is contained in:
@@ -56,7 +56,7 @@ export const FILE_SIZE_LIMITS = {
|
|||||||
// 时间相关常量
|
// 时间相关常量
|
||||||
export const TIME_CONSTANTS = {
|
export const TIME_CONSTANTS = {
|
||||||
ALERT_DURATION: 5000, // 5秒
|
ALERT_DURATION: 5000, // 5秒
|
||||||
REQUEST_TIMEOUT: 30000, // 30秒
|
REQUEST_TIMEOUT: 300000000,
|
||||||
PROGRESS_UPDATE_INTERVAL: 100 // 100毫秒
|
PROGRESS_UPDATE_INTERVAL: 100 // 100毫秒
|
||||||
} as const
|
} as const
|
||||||
|
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ export default {
|
|||||||
localStorage: 'Local Storage',
|
localStorage: 'Local Storage',
|
||||||
s3Storage: 'S3 Storage',
|
s3Storage: 'S3 Storage',
|
||||||
webdavStorage: 'Webdav Storage',
|
webdavStorage: 'Webdav Storage',
|
||||||
chunkUploadNote: 'Enable chunk upload (experimental feature, still in development, currently only available for local storage, may have unknown issues)',
|
chunkUploadNote: 'Enable chunk upload (experimental feature, may have unknown issues)',
|
||||||
s3AccessKeyId: 'S3 AccessKeyId',
|
s3AccessKeyId: 'S3 AccessKeyId',
|
||||||
s3SecretAccessKey: 'S3 SecretAccessKey',
|
s3SecretAccessKey: 'S3 SecretAccessKey',
|
||||||
s3BucketName: 'S3 BucketName',
|
s3BucketName: 'S3 BucketName',
|
||||||
@@ -334,7 +334,7 @@ export default {
|
|||||||
localStorage: 'Local Storage',
|
localStorage: 'Local Storage',
|
||||||
s3Storage: 'S3 Storage',
|
s3Storage: 'S3 Storage',
|
||||||
webdavStorage: 'Webdav Storage',
|
webdavStorage: 'Webdav Storage',
|
||||||
chunkUploadNote: 'Enable chunk upload (experimental feature, still in development, currently only available for local storage, may have unknown issues)',
|
chunkUploadNote: 'Enable chunk upload (experimental feature, may have unknown issues)',
|
||||||
enabled: 'Enabled',
|
enabled: 'Enabled',
|
||||||
disabled: 'Disabled',
|
disabled: 'Disabled',
|
||||||
webdavUrl: 'Please enter Webdav URL',
|
webdavUrl: 'Please enter Webdav URL',
|
||||||
@@ -401,7 +401,7 @@ export default {
|
|||||||
localStorage: 'Local Storage',
|
localStorage: 'Local Storage',
|
||||||
s3Storage: 'S3 Storage',
|
s3Storage: 'S3 Storage',
|
||||||
webdavStorage: 'Webdav Storage',
|
webdavStorage: 'Webdav Storage',
|
||||||
chunkUploadNote: 'Enable chunk upload (experimental feature, still in development, currently only available for local storage, may have unknown issues)',
|
chunkUploadNote: 'Enable chunk upload (experimental feature, may have unknown issues)',
|
||||||
enabled: 'Enabled',
|
enabled: 'Enabled',
|
||||||
disabled: 'Disabled',
|
disabled: 'Disabled',
|
||||||
webdavUrl: 'Please enter Webdav URL',
|
webdavUrl: 'Please enter Webdav URL',
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ export default {
|
|||||||
localStorage: '本地存储',
|
localStorage: '本地存储',
|
||||||
s3Storage: 'S3 存储',
|
s3Storage: 'S3 存储',
|
||||||
webdavStorage: 'Webdav 存储',
|
webdavStorage: 'Webdav 存储',
|
||||||
chunkUploadNote: '开启切片上传(实验性功能,还在开发中,目前仅本地存储可用,可能会出现未知问题)',
|
chunkUploadNote: '开启切片上传(实验性功能,可能会出现未知问题)',
|
||||||
s3AccessKeyId: 'S3 AccessKeyId',
|
s3AccessKeyId: 'S3 AccessKeyId',
|
||||||
s3SecretAccessKey: 'S3 SecretAccessKey',
|
s3SecretAccessKey: 'S3 SecretAccessKey',
|
||||||
s3BucketName: 'S3 BucketName',
|
s3BucketName: 'S3 BucketName',
|
||||||
@@ -369,7 +369,9 @@ export default {
|
|||||||
storagePathPlaceholder: '留空则使用默认路径,可不填写',
|
storagePathPlaceholder: '留空则使用默认路径,可不填写',
|
||||||
storageMethod: '存储方式',
|
storageMethod: '存储方式',
|
||||||
localStorage: '本地存储',
|
localStorage: '本地存储',
|
||||||
chunkUploadNote: '开启切片上传(实验性功能,还在开发中,目前仅本地存储可用,可能会出现未知问题)',
|
s3Storage: 'S3 存储',
|
||||||
|
webdavStorage: 'Webdav 存储',
|
||||||
|
chunkUploadNote: '开启切片上传(实验性功能,可能会出现未知问题)',
|
||||||
uploadLimits: '上传限制',
|
uploadLimits: '上传限制',
|
||||||
uploadPerMinute: '每分钟上传限制',
|
uploadPerMinute: '每分钟上传限制',
|
||||||
uploadCountLimit: '上传数量限制',
|
uploadCountLimit: '上传数量限制',
|
||||||
@@ -382,7 +384,20 @@ export default {
|
|||||||
count: '按次数'
|
count: '按次数'
|
||||||
},
|
},
|
||||||
maxSaveTime: '最长保存时间',
|
maxSaveTime: '最长保存时间',
|
||||||
|
s3AccessKeyId: 'S3 AccessKeyId',
|
||||||
s3SecretAccessKey: 'S3 SecretAccessKey',
|
s3SecretAccessKey: 'S3 SecretAccessKey',
|
||||||
|
s3BucketName: 'S3 BucketName',
|
||||||
|
s3EndpointUrl: 'S3 EndpointUrl',
|
||||||
|
s3RegionName: 'S3 Region Name',
|
||||||
|
s3SignatureVersion: 'S3 Signature Version',
|
||||||
|
s3Hostname: 'S3 Hostname',
|
||||||
|
s3v2: 'S3v2',
|
||||||
|
s3v4: 'S3v4',
|
||||||
|
autoPlaceholder: 'auto',
|
||||||
|
enableProxy: '启用代理',
|
||||||
|
webdavUrlPlaceholder: '请输入 Webdav URL',
|
||||||
|
webdavUsernamePlaceholder: '请输入 Webdav Username',
|
||||||
|
webdavPasswordPlaceholder: '请输入 Webdav Password',
|
||||||
fileSizeUnits: {
|
fileSizeUnits: {
|
||||||
kb: 'KB',
|
kb: 'KB',
|
||||||
mb: 'MB',
|
mb: 'MB',
|
||||||
@@ -457,7 +472,7 @@ export default {
|
|||||||
localStorage: '本地存储',
|
localStorage: '本地存储',
|
||||||
s3Storage: 'S3 存储',
|
s3Storage: 'S3 存储',
|
||||||
webdavStorage: 'Webdav 存储',
|
webdavStorage: 'Webdav 存储',
|
||||||
chunkUploadNote: '开启切片上传(实验性功能,还在开发中,目前仅本地存储可用,可能会出现未知问题)',
|
chunkUploadNote: '开启切片上传(实验性功能,可能会出现未知问题)',
|
||||||
enabled: '已开启',
|
enabled: '已开启',
|
||||||
disabled: '已关闭',
|
disabled: '已关闭',
|
||||||
webdavUrl: '请输入 Webdav URL',
|
webdavUrl: '请输入 Webdav URL',
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ export class FileService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static async updateFile(data: FileEditForm): Promise<ApiResponse> {
|
static async updateFile(data: FileEditForm): Promise<ApiResponse> {
|
||||||
return api.post('/admin/file/update', data)
|
return api.patch('/admin/file/update', data)
|
||||||
}
|
}
|
||||||
|
|
||||||
static async deleteAdminFile(id: number): Promise<ApiResponse> {
|
static async deleteAdminFile(id: number): Promise<ApiResponse> {
|
||||||
|
|||||||
+58
-41
@@ -556,8 +556,11 @@ const fileHash = ref('')
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
const handleFileSelected = (file: File) => {
|
const handleFileSelected = async (file: File) => {
|
||||||
selectedFile.value = file
|
selectedFile.value = file
|
||||||
|
if (!checkOpenUpload()) return
|
||||||
|
if (!checkFileSize(file)) return
|
||||||
|
fileHash.value = await calculateFileHash(file)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -648,51 +651,48 @@ const handlePaste = async (event: ClipboardEvent) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const calculateFileHash = async (file: File): Promise<string> => {
|
const calculateFileHash = async (file: File): Promise<string> => {
|
||||||
return new Promise((resolve) => {
|
|
||||||
const chunkSize = 2097152 // 保持 2MB 的切片大小用于计算哈希
|
|
||||||
const fileReader = new FileReader()
|
|
||||||
let currentChunk = 0
|
|
||||||
const chunks = Math.ceil(file.size / chunkSize)
|
|
||||||
|
|
||||||
fileReader.onload = async (e) => {
|
|
||||||
const chunk = new Uint8Array(e.target!.result as ArrayBuffer)
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 尝试使用 crypto.subtle.digest
|
// 对于小文件,直接计算整个文件的哈希
|
||||||
|
if (file.size <= 10 * 1024 * 1024) {
|
||||||
|
const buffer = await file.arrayBuffer()
|
||||||
if (window.isSecureContext) {
|
if (window.isSecureContext) {
|
||||||
const hashBuffer = await crypto.subtle.digest('SHA-256', chunk)
|
const hashBuffer = await crypto.subtle.digest('SHA-256', buffer)
|
||||||
const hashArray = Array.from(new Uint8Array(hashBuffer))
|
const hashArray = Array.from(new Uint8Array(hashBuffer))
|
||||||
const hashHex = hashArray.map((b) => b.toString(16).padStart(2, '0')).join('')
|
return hashArray.map((b) => b.toString(16).padStart(2, '0')).join('')
|
||||||
|
}
|
||||||
|
return generateFallbackHash(file)
|
||||||
|
}
|
||||||
|
|
||||||
currentChunk++
|
// 对于大文件,取首尾各5MB计算哈希
|
||||||
if (currentChunk < chunks) {
|
const chunkSize = 5 * 1024 * 1024
|
||||||
loadNext()
|
const firstChunk = file.slice(0, chunkSize)
|
||||||
} else {
|
const lastChunk = file.slice(-chunkSize)
|
||||||
resolve(hashHex)
|
|
||||||
}
|
const [firstBuffer, lastBuffer] = await Promise.all([
|
||||||
} else {
|
firstChunk.arrayBuffer(),
|
||||||
// 如果不是安全上下文(HTTP),则返回一个基于文件信息的替代哈希
|
lastChunk.arrayBuffer()
|
||||||
const fallbackHash = generateFallbackHash(file)
|
])
|
||||||
resolve(fallbackHash)
|
|
||||||
|
// 合并首尾数据
|
||||||
|
const combined = new Uint8Array(firstBuffer.byteLength + lastBuffer.byteLength + 16)
|
||||||
|
combined.set(new Uint8Array(firstBuffer), 0)
|
||||||
|
combined.set(new Uint8Array(lastBuffer), firstBuffer.byteLength)
|
||||||
|
// 添加文件大小信息
|
||||||
|
const sizeBytes = new TextEncoder().encode(file.size.toString())
|
||||||
|
combined.set(sizeBytes, firstBuffer.byteLength + lastBuffer.byteLength)
|
||||||
|
|
||||||
|
if (window.isSecureContext) {
|
||||||
|
const hashBuffer = await crypto.subtle.digest('SHA-256', combined)
|
||||||
|
const hashArray = Array.from(new Uint8Array(hashBuffer))
|
||||||
|
return hashArray.map((b) => b.toString(16).padStart(2, '0')).join('')
|
||||||
}
|
}
|
||||||
|
return generateFallbackHash(file)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// 如果 crypto.subtle.digest 失败,使用替代方案
|
|
||||||
const fallbackHash = generateFallbackHash(file)
|
|
||||||
console.error('File hash calculation failed:', err)
|
console.error('File hash calculation failed:', err)
|
||||||
resolve(fallbackHash)
|
return generateFallbackHash(file)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const loadNext = () => {
|
|
||||||
const start = currentChunk * chunkSize
|
|
||||||
const end = start + chunkSize >= file.size ? file.size : start + chunkSize
|
|
||||||
fileReader.readAsArrayBuffer(file.slice(start, end))
|
|
||||||
}
|
|
||||||
|
|
||||||
loadNext()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 生成替代哈希的函数
|
// 生成替代哈希的函数
|
||||||
const generateFallbackHash = (file: File): string => {
|
const generateFallbackHash = (file: File): string => {
|
||||||
// 使用文件名、大小和最后修改时间生成一个简单的哈希
|
// 使用文件名、大小和最后修改时间生成一个简单的哈希
|
||||||
@@ -777,6 +777,11 @@ const getExpirationTime = (method: string, value: string) => {
|
|||||||
|
|
||||||
const handleChunkUpload = async (file: File) => {
|
const handleChunkUpload = async (file: File) => {
|
||||||
try {
|
try {
|
||||||
|
// 确保文件哈希已计算
|
||||||
|
// 每次上传都重新计算哈希,确保哈希值正确
|
||||||
|
const hash = await calculateFileHash(file)
|
||||||
|
fileHash.value = hash
|
||||||
|
console.log('Calculated file hash:', hash)
|
||||||
// 默认切片大小为5MB
|
// 默认切片大小为5MB
|
||||||
const chunkSize = 5 * 1024 * 1024
|
const chunkSize = 5 * 1024 * 1024
|
||||||
const chunks = Math.ceil(file.size / chunkSize)
|
const chunks = Math.ceil(file.size / chunkSize)
|
||||||
@@ -786,6 +791,7 @@ const handleChunkUpload = async (file: File) => {
|
|||||||
name?: string
|
name?: string
|
||||||
upload_id?: string
|
upload_id?: string
|
||||||
existed?: boolean
|
existed?: boolean
|
||||||
|
uploaded_chunks?: number[]
|
||||||
}> = await api.post('chunk/upload/init/', {
|
}> = await api.post('chunk/upload/init/', {
|
||||||
file_name: file.name,
|
file_name: file.name,
|
||||||
file_size: file.size,
|
file_size: file.size,
|
||||||
@@ -800,17 +806,22 @@ const handleChunkUpload = async (file: File) => {
|
|||||||
return initResponse
|
return initResponse
|
||||||
}
|
}
|
||||||
const uploadId = initResponse.detail?.upload_id
|
const uploadId = initResponse.detail?.upload_id
|
||||||
|
const uploadedChunks = new Set(initResponse.detail?.uploaded_chunks || [])
|
||||||
|
|
||||||
// 2. 上传切片
|
// 2. 上传切片(跳过已上传的)
|
||||||
for (let i = 0; i < chunks; i++) {
|
for (let i = 0; i < chunks; i++) {
|
||||||
|
// 跳过已上传的块
|
||||||
|
if (uploadedChunks.has(i)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
const start = i * chunkSize
|
const start = i * chunkSize
|
||||||
const end = Math.min(start + chunkSize, file.size)
|
const end = Math.min(start + chunkSize, file.size)
|
||||||
const chunk = file.slice(start, end)
|
const chunk = file.slice(start, end)
|
||||||
|
|
||||||
const chunkFormData = new FormData()
|
const chunkFormData = new FormData()
|
||||||
chunkFormData.append('chunk', new Blob([chunk], { type: file.type })) // 确保以Blob形式添加
|
chunkFormData.append('chunk', new Blob([chunk], { type: file.type }))
|
||||||
|
|
||||||
// 使用 application/x-www-form-urlencoded 格式
|
|
||||||
const chunkResponse: ApiResponse<unknown> = await api.post(
|
const chunkResponse: ApiResponse<unknown> = await api.post(
|
||||||
`chunk/upload/chunk/${uploadId}/${i}`,
|
`chunk/upload/chunk/${uploadId}/${i}`,
|
||||||
chunkFormData,
|
chunkFormData,
|
||||||
@@ -819,10 +830,16 @@ const handleChunkUpload = async (file: File) => {
|
|||||||
'Content-Type': 'multipart/form-data'
|
'Content-Type': 'multipart/form-data'
|
||||||
},
|
},
|
||||||
onUploadProgress: (progressEvent: { loaded: number; total?: number }) => {
|
onUploadProgress: (progressEvent: { loaded: number; total?: number }) => {
|
||||||
|
// 计算已上传块的大小
|
||||||
|
const uploadedSize = Array.from(uploadedChunks).reduce((acc, idx) => {
|
||||||
|
const chunkEnd = Math.min((idx + 1) * chunkSize, file.size)
|
||||||
|
const chunkStart = idx * chunkSize
|
||||||
|
return acc + (chunkEnd - chunkStart)
|
||||||
|
}, 0)
|
||||||
const percentCompleted = Math.round(
|
const percentCompleted = Math.round(
|
||||||
((i * chunkSize + progressEvent.loaded) * 100) / file.size
|
((uploadedSize + i * chunkSize + progressEvent.loaded) * 100) / file.size
|
||||||
)
|
)
|
||||||
uploadProgress.value = percentCompleted
|
uploadProgress.value = Math.min(percentCompleted, 99)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -405,29 +405,6 @@ const handleUpdate = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 下载文件处理 - 暂时移除未使用的函数
|
|
||||||
// const downloadFile = async (id: number) => {
|
|
||||||
// try {
|
|
||||||
// const response = await FileService.downloadAdminFile(id)
|
|
||||||
|
|
||||||
// const contentDisposition = response.headers['content-disposition']
|
|
||||||
// let filename = 'file'
|
|
||||||
// const filenameMatch = contentDisposition.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/)
|
|
||||||
// if (filenameMatch != null && filenameMatch[1]) {
|
|
||||||
// filename = filenameMatch[1].replace(/['"]/g, '')
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // @ts-expect-error - showSaveFilePicker is not in standard Window interface
|
|
||||||
// if (window.showSaveFilePicker) {
|
|
||||||
// await saveFileByWebApi(response.data, filename)
|
|
||||||
// } else {
|
|
||||||
// await saveFileByElementA(response.data, filename)
|
|
||||||
// }
|
|
||||||
// } catch (error) {
|
|
||||||
// console.error('下载失败:', error)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// 删除文件处理
|
// 删除文件处理
|
||||||
const deleteFile = async (id: number) => {
|
const deleteFile = async (id: number) => {
|
||||||
try {
|
try {
|
||||||
@@ -438,28 +415,6 @@ const deleteFile = async (id: number) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 文件保存辅助函数 - 暂时移除未使用的函数
|
|
||||||
// async function saveFileByElementA(fileBlob: Blob, filename: string) {
|
|
||||||
// const downloadUrl = window.URL.createObjectURL(fileBlob)
|
|
||||||
// const link = document.createElement('a')
|
|
||||||
// link.href = downloadUrl
|
|
||||||
// link.download = filename
|
|
||||||
// document.body.appendChild(link)
|
|
||||||
// link.click()
|
|
||||||
// window.URL.revokeObjectURL(downloadUrl)
|
|
||||||
// document.body.removeChild(link)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// async function saveFileByWebApi(fileBlob: Blob, filename: string) {
|
|
||||||
// // @ts-expect-error - showSaveFilePicker is not in standard Window interface
|
|
||||||
// const newHandle = await window.showSaveFilePicker({
|
|
||||||
// suggestedName: filename
|
|
||||||
// })
|
|
||||||
// const writableStream = await newHandle.createWritable()
|
|
||||||
// await writableStream.write(fileBlob)
|
|
||||||
// await writableStream.close()
|
|
||||||
// }
|
|
||||||
|
|
||||||
// 加载文件列表
|
// 加载文件列表
|
||||||
const loadFiles = async () => {
|
const loadFiles = async () => {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -108,9 +108,9 @@ const refreshData = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const errorMessage = error instanceof Error ? error.message : '获取配置失败'
|
const errorMessage = error instanceof Error ? error.message : t('manage.systemSettings.getConfigFailed')
|
||||||
alertStore.showAlert(errorMessage, 'error')
|
alertStore.showAlert(errorMessage, 'error')
|
||||||
console.error('获取系统配置失败:', error)
|
console.error('Failed to get system config:', error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 转换文件大小为字节
|
// 转换文件大小为字节
|
||||||
@@ -136,12 +136,12 @@ const submitSave = () => {
|
|||||||
|
|
||||||
ConfigService.updateConfig(formData).then((res) => {
|
ConfigService.updateConfig(formData).then((res) => {
|
||||||
if (res.code == 200) {
|
if (res.code == 200) {
|
||||||
alertStore.showAlert('保存成功', 'success')
|
alertStore.showAlert(t('manage.systemSettings.saveSuccess'), 'success')
|
||||||
} else {
|
} else {
|
||||||
alertStore.showAlert(res.message || '保存失败', 'error')
|
alertStore.showAlert(res.message || t('manage.systemSettings.saveFailed'), 'error')
|
||||||
}
|
}
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
const errorMessage = error instanceof Error ? error.message : '保存失败'
|
const errorMessage = error instanceof Error ? error.message : t('manage.systemSettings.saveFailed')
|
||||||
alertStore.showAlert(errorMessage, 'error')
|
alertStore.showAlert(errorMessage, 'error')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -504,6 +504,29 @@ refreshData()
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="space-y-2">
|
||||||
|
<label class="block text-sm font-medium mb-2"
|
||||||
|
:class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']">
|
||||||
|
{{ t('manage.settings.chunkUploadNote') }}
|
||||||
|
</label>
|
||||||
|
<div class="flex items-center">
|
||||||
|
<button type="button" @click="config.enableChunk = config.enableChunk === 1 ? 0 : 1"
|
||||||
|
class="relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"
|
||||||
|
:class="[config.enableChunk === 1 ? 'bg-indigo-600' : 'bg-gray-200']" role="switch"
|
||||||
|
:aria-checked="config.enableChunk === 1">
|
||||||
|
<span
|
||||||
|
class="pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"
|
||||||
|
:class="[
|
||||||
|
config.enableChunk === 1 ? 'translate-x-5' : 'translate-x-0',
|
||||||
|
isDarkMode && config.enableChunk !== 1 ? 'bg-gray-100' : 'bg-white'
|
||||||
|
]" />
|
||||||
|
</button>
|
||||||
|
<span class="ml-3 text-sm" :class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']">
|
||||||
|
{{ config.enableChunk === 1 ? t('common.enabled') : t('common.disabled') }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user