init
这个提交包含在:
父节点
9e8571402d
当前提交
e2e7bb066b
235
database/database.js
普通文件
235
database/database.js
普通文件
@ -0,0 +1,235 @@
|
||||
const sqlite3 = require('sqlite3')
|
||||
const path = require('path')
|
||||
const { open } = require('sqlite')
|
||||
const fs = require('fs-extra')
|
||||
|
||||
const dbPath = path.join(process.cwd(), 'database/files.db')
|
||||
|
||||
// 确保数据库目录存在
|
||||
const dbDir = path.dirname(dbPath)
|
||||
fs.ensureDirSync(dbDir)
|
||||
|
||||
async function initDatabase() {
|
||||
const db = await open({
|
||||
filename: dbPath,
|
||||
driver: sqlite3.Database
|
||||
})
|
||||
|
||||
// 设置数据库编码为 UTF-8
|
||||
await db.exec('PRAGMA encoding = "UTF-8"')
|
||||
await db.exec('PRAGMA foreign_keys = ON')
|
||||
|
||||
await db.exec(`
|
||||
CREATE TABLE IF NOT EXISTS files (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
original_name TEXT NOT NULL,
|
||||
file_name TEXT NOT NULL,
|
||||
file_path TEXT NOT NULL,
|
||||
file_size INTEGER NOT NULL,
|
||||
mime_type TEXT NOT NULL,
|
||||
md5 TEXT NOT NULL,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
`)
|
||||
|
||||
// 新增 OCR 结果表
|
||||
await db.exec(`
|
||||
CREATE TABLE IF NOT EXISTS ocr_results (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
file_id INTEGER NOT NULL,
|
||||
ocr_data TEXT NOT NULL,
|
||||
confidence REAL,
|
||||
processing_time INTEGER,
|
||||
recognized_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (file_id) REFERENCES files (id) ON DELETE CASCADE,
|
||||
UNIQUE(file_id)
|
||||
)
|
||||
`)
|
||||
|
||||
await db.close()
|
||||
}
|
||||
|
||||
class FileService {
|
||||
async getDb() {
|
||||
const db = await open({
|
||||
filename: dbPath,
|
||||
driver: sqlite3.Database
|
||||
})
|
||||
|
||||
// 确保每次连接都使用 UTF-8
|
||||
await db.exec('PRAGMA encoding = "UTF-8"')
|
||||
return db
|
||||
}
|
||||
|
||||
async createFile(fileData) {
|
||||
const db = await this.getDb()
|
||||
|
||||
// 确保文件名正确存储
|
||||
const result = await db.run(
|
||||
`INSERT INTO files (original_name, file_name, file_path, file_size, mime_type, md5)
|
||||
VALUES (?, ?, ?, ?, ?, ?)`,
|
||||
[
|
||||
fileData.originalName,
|
||||
fileData.fileName,
|
||||
fileData.filePath,
|
||||
fileData.fileSize,
|
||||
fileData.mimeType,
|
||||
fileData.md5
|
||||
]
|
||||
)
|
||||
|
||||
const file = await db.get(
|
||||
'SELECT * FROM files WHERE id = ?',
|
||||
result.lastID
|
||||
)
|
||||
|
||||
await db.close()
|
||||
|
||||
return this.mapDatabaseToFileRecord(file)
|
||||
}
|
||||
|
||||
async getFilesPaginated(page, pageSize) {
|
||||
const db = await this.getDb()
|
||||
const offset = (page - 1) * pageSize
|
||||
|
||||
const files = await db.all(
|
||||
'SELECT * FROM files ORDER BY created_at DESC LIMIT ? OFFSET ?',
|
||||
[pageSize, offset]
|
||||
)
|
||||
|
||||
const totalResult = await db.get('SELECT COUNT(*) as count FROM files')
|
||||
const total = totalResult.count
|
||||
|
||||
await db.close()
|
||||
|
||||
return {
|
||||
files: files.map(file => this.mapDatabaseToFileRecord(file)),
|
||||
pagination: {
|
||||
page,
|
||||
pageSize,
|
||||
total,
|
||||
totalPages: Math.ceil(total / pageSize)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async getFileById(id) {
|
||||
const db = await this.getDb()
|
||||
const file = await db.get('SELECT * FROM files WHERE id = ?', [id])
|
||||
await db.close()
|
||||
return file ? this.mapDatabaseToFileRecord(file) : null
|
||||
}
|
||||
|
||||
async updateFileMD5(id, md5) {
|
||||
const db = await this.getDb()
|
||||
await db.run(
|
||||
'UPDATE files SET md5 = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?',
|
||||
[md5, id]
|
||||
)
|
||||
await db.close()
|
||||
}
|
||||
|
||||
mapDatabaseToFileRecord(dbFile) {
|
||||
// 确保从数据库读取时正确处理编码
|
||||
let originalName = dbFile.original_name
|
||||
try {
|
||||
// 尝试解码,如果已经是正确编码则不会影响
|
||||
originalName = decodeURIComponent(originalName)
|
||||
} catch (error) {
|
||||
console.warn('文件名解码失败,使用原值:', error)
|
||||
}
|
||||
|
||||
return {
|
||||
id: dbFile.id,
|
||||
originalName: originalName,
|
||||
fileName: dbFile.file_name,
|
||||
filePath: dbFile.file_path,
|
||||
fileSize: dbFile.file_size,
|
||||
mimeType: dbFile.mime_type,
|
||||
md5: dbFile.md5,
|
||||
createdAt: dbFile.created_at,
|
||||
updatedAt: dbFile.updated_at
|
||||
}
|
||||
}
|
||||
async saveOcrResult(fileId, ocrData) {
|
||||
const db = await this.getDb()
|
||||
|
||||
// 将 OCR 数据转为 JSON 字符串存储
|
||||
const ocrDataJson = JSON.stringify(ocrData)
|
||||
|
||||
try {
|
||||
// 尝试更新已存在的记录
|
||||
const result = await db.run(
|
||||
`UPDATE ocr_results SET ocr_data = ?, confidence = ?, processing_time = ?, updated_at = CURRENT_TIMESTAMP
|
||||
WHERE file_id = ?`,
|
||||
[ocrDataJson, ocrData.confidence, ocrData.processingTime, fileId]
|
||||
)
|
||||
|
||||
// 如果没有更新任何行,则插入新记录
|
||||
if (result.changes === 0) {
|
||||
await db.run(
|
||||
`INSERT INTO ocr_results (file_id, ocr_data, confidence, processing_time)
|
||||
VALUES (?, ?, ?, ?)`,
|
||||
[fileId, ocrDataJson, ocrData.confidence, ocrData.processingTime]
|
||||
)
|
||||
}
|
||||
|
||||
await db.close()
|
||||
return { success: true }
|
||||
} catch (error) {
|
||||
await db.close()
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
async getOcrResult(fileId) {
|
||||
const db = await this.getDb()
|
||||
|
||||
const result = await db.get(
|
||||
'SELECT * FROM ocr_results WHERE file_id = ?',
|
||||
[fileId]
|
||||
)
|
||||
|
||||
await db.close()
|
||||
|
||||
if (result) {
|
||||
return {
|
||||
...result,
|
||||
ocr_data: JSON.parse(result.ocr_data)
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
async updateOcrText(fileId, newTextBlocks) {
|
||||
const db = await this.getDb()
|
||||
|
||||
const existingResult = await this.getOcrResult(fileId)
|
||||
if (!existingResult) {
|
||||
throw new Error('没有找到OCR结果')
|
||||
}
|
||||
|
||||
// 更新文本块
|
||||
const updatedOcrData = {
|
||||
...existingResult.ocr_data,
|
||||
textBlocks: newTextBlocks,
|
||||
updatedAt: new Date().toISOString(),
|
||||
manuallyCorrected: true
|
||||
}
|
||||
|
||||
const ocrDataJson = JSON.stringify(updatedOcrData)
|
||||
|
||||
await db.run(
|
||||
'UPDATE ocr_results SET ocr_data = ?, updated_at = CURRENT_TIMESTAMP WHERE file_id = ?',
|
||||
[ocrDataJson, fileId]
|
||||
)
|
||||
|
||||
await db.close()
|
||||
return { success: true }
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { initDatabase, FileService }
|
||||
@ -11,13 +11,17 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"canvas": "^3.2.0",
|
||||
"cors": "^2.8.5",
|
||||
"crypto-ts": "^1.0.2",
|
||||
"express": "^5.1.0",
|
||||
"fs-extra": "^11.3.2",
|
||||
"multer": "^2.0.2",
|
||||
"node-tesseract-ocr": "^2.2.1",
|
||||
"sharp": "^0.34.5",
|
||||
"sqlite": "^5.1.1",
|
||||
"sqlite3": "^5.1.7",
|
||||
"tesseract.js": "^6.0.1",
|
||||
"vue": "^3.5.22",
|
||||
"vue-router": "^4.6.3"
|
||||
},
|
||||
|
||||
317
server/server.js
317
server/server.js
@ -6,6 +6,11 @@ const fs = require('fs-extra')
|
||||
const { calculateFileMD5 } = require('./utils.js')
|
||||
const { initDatabase, FileService } = require('../database/database.js')
|
||||
|
||||
// 新增 OCR 相关依赖
|
||||
const Tesseract = require('tesseract.js')
|
||||
const sharp = require('sharp')
|
||||
const { createCanvas, loadImage } = require('canvas')
|
||||
|
||||
const app = express()
|
||||
const PORT = 3000
|
||||
|
||||
@ -13,9 +18,11 @@ const PORT = 3000
|
||||
initDatabase()
|
||||
const fileService = new FileService()
|
||||
|
||||
// 确保上传目录存在
|
||||
// 确保上传目录和临时目录存在
|
||||
const uploadDir = path.join(process.cwd(), 'uploads')
|
||||
const tempDir = path.join(process.cwd(), 'temp')
|
||||
fs.ensureDirSync(uploadDir)
|
||||
fs.ensureDirSync(tempDir)
|
||||
|
||||
// 配置 multer - 修复中文文件名问题
|
||||
const storage = multer.diskStorage({
|
||||
@ -93,23 +100,30 @@ app.post('/api/upload', upload.single('file'), async (req, res) => {
|
||||
}
|
||||
})
|
||||
|
||||
// 获取文件列表(分页)
|
||||
// 修复获取文件列表接口 - 确保返回正确的数据结构
|
||||
app.get('/api/files', async (req, res) => {
|
||||
try {
|
||||
const page = parseInt(req.query.page) || 1
|
||||
const pageSize = parseInt(req.query.pageSize) || 10
|
||||
const pageSize = parseInt(req.query.pageSize) || 100
|
||||
|
||||
const result = await fileService.getFilesPaginated(page, pageSize)
|
||||
|
||||
// 确保返回的数据使用 UTF-8 编码
|
||||
res.json(result)
|
||||
// 返回统一的数据结构
|
||||
res.json({
|
||||
success: true,
|
||||
data: result.files, // 直接返回文件数组
|
||||
pagination: result.pagination
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('Get files error:', error)
|
||||
res.status(500).json({ error: 'Failed to get files' })
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: 'Failed to get files: ' + error.message
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// 其他接口保持不变...
|
||||
// MD5 检查接口
|
||||
app.post('/api/files/:id/check-md5', async (req, res) => {
|
||||
try {
|
||||
const fileId = parseInt(req.params.id)
|
||||
@ -134,6 +148,7 @@ app.post('/api/files/:id/check-md5', async (req, res) => {
|
||||
}
|
||||
})
|
||||
|
||||
// 更新 MD5 接口
|
||||
app.put('/api/files/:id/update-md5', async (req, res) => {
|
||||
try {
|
||||
const fileId = parseInt(req.params.id)
|
||||
@ -147,6 +162,294 @@ app.put('/api/files/:id/update-md5', async (req, res) => {
|
||||
}
|
||||
})
|
||||
|
||||
// 新增 OCR 识别接口
|
||||
app.post('/api/ocr/recognize', async (req, res) => {
|
||||
try {
|
||||
const { fileId, page } = req.body
|
||||
|
||||
if (!fileId) {
|
||||
return res.status(400).json({ error: 'File ID is required' })
|
||||
}
|
||||
|
||||
const file = await fileService.getFileById(parseInt(fileId))
|
||||
if (!file) {
|
||||
return res.status(404).json({ error: 'File not found' })
|
||||
}
|
||||
|
||||
console.log(`开始OCR识别: ${file.originalName}`)
|
||||
|
||||
// 预处理图像
|
||||
const processedImagePath = await preprocessImage(file.filePath)
|
||||
|
||||
// 使用 Tesseract 进行 OCR 识别
|
||||
const result = await performOCR(processedImagePath)
|
||||
|
||||
// 清理临时文件
|
||||
await fs.remove(processedImagePath)
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: {
|
||||
textBlocks: result.textBlocks,
|
||||
totalPages: result.totalPages || 1,
|
||||
processingTime: result.processingTime,
|
||||
confidence: result.confidence
|
||||
}
|
||||
})
|
||||
|
||||
} catch (error) {
|
||||
console.error('OCR recognition error:', error)
|
||||
res.status(500).json({ error: 'OCR recognition failed: ' + error.message })
|
||||
}
|
||||
})
|
||||
|
||||
// 添加 OCR 结果相关的 API 接口
|
||||
|
||||
// 保存 OCR 结果
|
||||
app.post('/api/ocr/save-result', async (req, res) => {
|
||||
try {
|
||||
const { fileId, ocrData } = req.body
|
||||
|
||||
if (!fileId || !ocrData) {
|
||||
return res.status(400).json({ error: '文件ID和OCR数据是必需的' })
|
||||
}
|
||||
|
||||
await fileService.saveOcrResult(parseInt(fileId), ocrData)
|
||||
|
||||
res.json({ success: true })
|
||||
} catch (error) {
|
||||
console.error('保存OCR结果失败:', error)
|
||||
res.status(500).json({ error: '保存OCR结果失败: ' + error.message })
|
||||
}
|
||||
})
|
||||
|
||||
// 获取 OCR 结果
|
||||
app.get('/api/ocr/result/:fileId', async (req, res) => {
|
||||
try {
|
||||
const fileId = parseInt(req.params.fileId)
|
||||
const result = await fileService.getOcrResult(fileId)
|
||||
|
||||
if (result) {
|
||||
res.json({
|
||||
success: true,
|
||||
data: result.ocr_data
|
||||
})
|
||||
} else {
|
||||
res.json({
|
||||
success: false,
|
||||
error: '未找到OCR结果'
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取OCR结果失败:', error)
|
||||
res.status(500).json({ error: '获取OCR结果失败: ' + error.message })
|
||||
}
|
||||
})
|
||||
|
||||
// 更新 OCR 文本(人工纠错)
|
||||
app.put('/api/ocr/update-text', async (req, res) => {
|
||||
try {
|
||||
const { fileId, textBlocks } = req.body
|
||||
|
||||
if (!fileId || !textBlocks) {
|
||||
return res.status(400).json({ error: '文件ID和文本数据是必需的' })
|
||||
}
|
||||
|
||||
await fileService.updateOcrText(parseInt(fileId), textBlocks)
|
||||
|
||||
res.json({ success: true })
|
||||
} catch (error) {
|
||||
console.error('更新OCR文本失败:', error)
|
||||
res.status(500).json({ error: '更新OCR文本失败: ' + error.message })
|
||||
}
|
||||
})
|
||||
|
||||
// 图像预处理函数
|
||||
async function preprocessImage(imagePath) {
|
||||
const tempOutputPath = path.join(tempDir, `preprocessed-${Date.now()}.png`)
|
||||
|
||||
try {
|
||||
// 使用 sharp 进行图像预处理
|
||||
await sharp(imagePath)
|
||||
.grayscale() // 转为灰度图
|
||||
.normalize() // 标准化图像
|
||||
.linear(1.5, 0) // 增加对比度
|
||||
.sharpen() // 锐化
|
||||
.png()
|
||||
.toFile(tempOutputPath)
|
||||
|
||||
return tempOutputPath
|
||||
} catch (error) {
|
||||
console.error('Image preprocessing failed:', error)
|
||||
// 如果预处理失败,返回原图
|
||||
return imagePath
|
||||
}
|
||||
}
|
||||
|
||||
// OCR 识别函数
|
||||
async function performOCR(imagePath) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const startTime = Date.now()
|
||||
|
||||
Tesseract.recognize(
|
||||
imagePath,
|
||||
'chi_sim+eng', // 中文简体 + 英文
|
||||
{
|
||||
logger: m => console.log(m),
|
||||
tessedit_pageseg_mode: Tesseract.PSM.AUTO,
|
||||
tessedit_char_whitelist: '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\u4e00-\u9fa5,。!?;:"'/'()【】《》…—·'
|
||||
}
|
||||
).then(({ data: { text, confidence } }) => {
|
||||
const processingTime = Date.now() - startTime
|
||||
|
||||
// 解析文本块
|
||||
const textBlocks = parseOCRText(text)
|
||||
|
||||
resolve({
|
||||
textBlocks,
|
||||
confidence,
|
||||
processingTime
|
||||
})
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// 解析 OCR 文本结果
|
||||
function parseOCRText(text) {
|
||||
const blocks = []
|
||||
const lines = text.split('\n').filter(line => line.trim())
|
||||
|
||||
for (const line of lines) {
|
||||
const trimmedLine = line.trim()
|
||||
if (!trimmedLine) continue
|
||||
|
||||
// 检测参考文献
|
||||
if (isReference(trimmedLine)) {
|
||||
blocks.push({
|
||||
type: 'reference',
|
||||
content: trimmedLine
|
||||
})
|
||||
}
|
||||
// 检测引用
|
||||
else if (isCitation(trimmedLine)) {
|
||||
blocks.push({
|
||||
type: 'citation',
|
||||
content: trimmedLine.replace(/^\[\d+\]\s*/, ''),
|
||||
number: extractCitationNumber(trimmedLine)
|
||||
})
|
||||
}
|
||||
// 检测图片标记
|
||||
else if (isImageMarker(trimmedLine)) {
|
||||
blocks.push({
|
||||
type: 'image',
|
||||
content: trimmedLine
|
||||
})
|
||||
}
|
||||
// 普通文本
|
||||
else {
|
||||
blocks.push({
|
||||
type: 'text',
|
||||
content: trimmedLine
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return blocks
|
||||
}
|
||||
|
||||
// 辅助函数
|
||||
function isReference(text) {
|
||||
const refPatterns = [
|
||||
/^参考文献/i,
|
||||
/^references/i,
|
||||
/^bibliography/i,
|
||||
/^\[?\d+\]?\s*\.?\s*[A-Za-z].*\.\s*\d{4}/
|
||||
]
|
||||
return refPatterns.some(pattern => pattern.test(text))
|
||||
}
|
||||
|
||||
function isCitation(text) {
|
||||
return /^\[\d+\]/.test(text)
|
||||
}
|
||||
|
||||
function extractCitationNumber(text) {
|
||||
const match = text.match(/^\[(\d+)\]/)
|
||||
return match ? parseInt(match[1]) : null
|
||||
}
|
||||
|
||||
function isImageMarker(text) {
|
||||
const imagePatterns = [
|
||||
/^图\s*\d+/i,
|
||||
/^figure\s*\d+/i,
|
||||
/^图片\d*/i
|
||||
]
|
||||
return imagePatterns.some(pattern => pattern.test(text))
|
||||
}
|
||||
|
||||
// 获取文件预览接口
|
||||
app.get('/api/files/:id/preview', async (req, res) => {
|
||||
try {
|
||||
const fileId = parseInt(req.params.id)
|
||||
const file = await fileService.getFileById(fileId)
|
||||
|
||||
if (!file) {
|
||||
return res.status(404).json({ error: 'File not found' })
|
||||
}
|
||||
|
||||
// 检查文件是否存在
|
||||
if (!fs.existsSync(file.filePath)) {
|
||||
return res.status(404).json({ error: 'File not found on disk' })
|
||||
}
|
||||
|
||||
// 设置正确的 Content-Type
|
||||
res.setHeader('Content-Type', file.mimeType)
|
||||
|
||||
// 直接发送文件
|
||||
res.sendFile(path.resolve(file.filePath))
|
||||
|
||||
} catch (error) {
|
||||
console.error('File preview error:', error)
|
||||
res.status(500).json({ error: 'Failed to get file preview' })
|
||||
}
|
||||
})
|
||||
|
||||
// 获取文件缩略图接口
|
||||
app.get('/api/files/:id/thumbnail', async (req, res) => {
|
||||
try {
|
||||
const fileId = parseInt(req.params.id)
|
||||
const file = await fileService.getFileById(fileId)
|
||||
|
||||
if (!file) {
|
||||
return res.status(404).json({ error: 'File not found' })
|
||||
}
|
||||
|
||||
// 只对图片生成缩略图
|
||||
if (!file.mimeType.startsWith('image/')) {
|
||||
return res.status(400).json({ error: 'Not an image file' })
|
||||
}
|
||||
|
||||
const thumbnailPath = path.join(tempDir, `thumbnail-${fileId}.jpg`)
|
||||
|
||||
// 生成缩略图
|
||||
await sharp(file.filePath)
|
||||
.resize(100, 100, {
|
||||
fit: 'inside',
|
||||
withoutEnlargement: true
|
||||
})
|
||||
.jpeg({ quality: 80 })
|
||||
.toFile(thumbnailPath)
|
||||
|
||||
res.sendFile(path.resolve(thumbnailPath))
|
||||
|
||||
} catch (error) {
|
||||
console.error('Thumbnail generation error:', error)
|
||||
// 如果缩略图生成失败,返回原图
|
||||
res.sendFile(path.resolve(file.filePath))
|
||||
}
|
||||
})
|
||||
|
||||
// 健康检查接口
|
||||
app.get('/api/health', (req, res) => {
|
||||
res.json({
|
||||
|
||||
@ -18,6 +18,8 @@
|
||||
<tr>
|
||||
<th>文件名</th>
|
||||
<th>大小</th>
|
||||
<th>类型</th>
|
||||
<th>OCR状态</th>
|
||||
<th>MD5</th>
|
||||
<th>上传时间</th>
|
||||
<th>操作</th>
|
||||
@ -25,11 +27,18 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="file in files" :key="file.id">
|
||||
<td class="filename-cell">{{ decodeFileName(file.originalName) }}</td>
|
||||
<td class="filename-cell" :title="decodeFileName(file.originalName)">
|
||||
{{ decodeFileName(file.originalName) }}
|
||||
</td>
|
||||
<td>{{ formatFileSize(file.fileSize) }}</td>
|
||||
<td class="file-type">{{ getFileType(file.mimeType) }}</td>
|
||||
<td class="ocr-status">
|
||||
<span v-if="file.hasOcrResult" class="ocr-done">✓ 已识别</span>
|
||||
<span v-else class="ocr-pending">待识别</span>
|
||||
</td>
|
||||
<td class="md5-cell">{{ file.md5 }}</td>
|
||||
<td>{{ formatDate(file.createdAt) }}</td>
|
||||
<td>
|
||||
<td class="action-buttons">
|
||||
<button
|
||||
@click="checkFileMD5(file)"
|
||||
class="check-button"
|
||||
@ -38,9 +47,10 @@
|
||||
{{ checkingFileId === file.id ? '检查中...' : '检查MD5' }}
|
||||
</button>
|
||||
<button
|
||||
class="btn-ocr"
|
||||
class="ocr-button"
|
||||
@click="handleOcr(file)"
|
||||
title="OCR识别"
|
||||
:disabled="!file.mimeType.startsWith('image/')"
|
||||
>
|
||||
🔍 OCR
|
||||
</button>
|
||||
@ -79,7 +89,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, onUnmounted } from 'vue'
|
||||
import apiManager from '../utils/apiManager.ts'
|
||||
import apiManager from '../utils/apiManager'
|
||||
|
||||
interface FileRecord {
|
||||
id: number
|
||||
@ -91,6 +101,7 @@ interface FileRecord {
|
||||
md5: string
|
||||
createdAt: string
|
||||
updatedAt: string
|
||||
hasOcrResult?: boolean
|
||||
}
|
||||
|
||||
interface PaginationInfo {
|
||||
@ -100,9 +111,11 @@ interface PaginationInfo {
|
||||
totalPages: number
|
||||
}
|
||||
|
||||
interface FileListResponse {
|
||||
files: FileRecord[]
|
||||
interface ApiResponse {
|
||||
success: boolean
|
||||
data: FileRecord[]
|
||||
pagination: PaginationInfo
|
||||
error?: string
|
||||
}
|
||||
|
||||
interface MD5CheckResponse {
|
||||
@ -128,24 +141,26 @@ const emit = defineEmits<{
|
||||
}>()
|
||||
|
||||
// 监听网络状态变化
|
||||
const handleNetworkChange = (event: any) => {
|
||||
const handleNetworkChange = (event: CustomEvent<{ baseUrl: string; isOnline: boolean }>) => {
|
||||
isOnline.value = event.detail.isOnline
|
||||
console.log('文件列表: 网络状态变更', event.detail)
|
||||
|
||||
// 网络状态变化时重新加载文件列表
|
||||
loadFiles(1)
|
||||
}
|
||||
|
||||
const handleOcr = (file: FileRecord): void => {
|
||||
emit('ocrRecognize', file)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
isOnline.value = apiManager.isOnlineMode()
|
||||
window.addEventListener('apiBaseUrlChanged', handleNetworkChange)
|
||||
window.addEventListener('apiBaseUrlChanged', handleNetworkChange as EventListener)
|
||||
loadFiles()
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('apiBaseUrlChanged', handleNetworkChange)
|
||||
window.removeEventListener('apiBaseUrlChanged', handleNetworkChange as EventListener)
|
||||
})
|
||||
|
||||
// 解码文件名显示
|
||||
@ -158,17 +173,55 @@ const decodeFileName = (fileName: string): string => {
|
||||
}
|
||||
}
|
||||
|
||||
// 获取文件类型显示
|
||||
const getFileType = (mimeType: string): string => {
|
||||
if (mimeType.startsWith('image/')) return '图片'
|
||||
if (mimeType.includes('pdf')) return 'PDF'
|
||||
if (mimeType.includes('word') || mimeType.includes('document')) return 'Word'
|
||||
if (mimeType.includes('excel') || mimeType.includes('spreadsheet')) return 'Excel'
|
||||
if (mimeType.includes('powerpoint') || mimeType.includes('presentation')) return 'PPT'
|
||||
if (mimeType.includes('text')) return '文本'
|
||||
return '其他'
|
||||
}
|
||||
|
||||
// 检查文件是否有OCR结果
|
||||
const checkOcrStatus = async (file: FileRecord): Promise<boolean> => {
|
||||
try {
|
||||
const result = await apiManager.get<{ success: boolean; data: any }>(
|
||||
`/api/ocr/result/${file.id}`
|
||||
)
|
||||
return result.success && result.data !== null
|
||||
} catch (error) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
const loadFiles = async (page: number = pagination.value.page): Promise<void> => {
|
||||
try {
|
||||
const result: FileListResponse = await apiManager.request(
|
||||
const result: ApiResponse = await apiManager.request<ApiResponse>(
|
||||
`/api/files?page=${page}&pageSize=${pagination.value.pageSize}`
|
||||
)
|
||||
|
||||
files.value = result.files
|
||||
pagination.value = result.pagination
|
||||
if (result.success && result.data) {
|
||||
// 检查每个文件的OCR状态
|
||||
const filesWithOcrStatus = await Promise.all(
|
||||
result.data.map(async (file) => {
|
||||
const hasOcrResult = await checkOcrStatus(file)
|
||||
return { ...file, hasOcrResult }
|
||||
})
|
||||
)
|
||||
|
||||
files.value = filesWithOcrStatus
|
||||
pagination.value = result.pagination
|
||||
console.log(`成功加载 ${files.value.length} 个文件`)
|
||||
} else {
|
||||
console.error('获取文件列表失败:', result.error)
|
||||
files.value = []
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载文件列表失败:', error)
|
||||
alert('加载文件列表失败,请检查服务是否正常运行')
|
||||
files.value = []
|
||||
}
|
||||
}
|
||||
|
||||
@ -176,7 +229,7 @@ const checkFileMD5 = async (file: FileRecord): Promise<void> => {
|
||||
checkingFileId.value = file.id
|
||||
|
||||
try {
|
||||
const result: MD5CheckResponse = await apiManager.request(
|
||||
const result: MD5CheckResponse = await apiManager.request<MD5CheckResponse>(
|
||||
`/api/files/${file.id}/check-md5`,
|
||||
{ method: 'POST' }
|
||||
)
|
||||
@ -233,6 +286,7 @@ defineExpose({
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden; /* 确保滚动正常工作 */
|
||||
}
|
||||
|
||||
.file-list-header {
|
||||
@ -240,6 +294,7 @@ defineExpose({
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 1rem;
|
||||
flex-shrink: 0; /* 防止头部被压缩 */
|
||||
}
|
||||
|
||||
.header-actions {
|
||||
@ -255,6 +310,7 @@ defineExpose({
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
|
||||
.refresh-button:hover {
|
||||
@ -285,19 +341,19 @@ defineExpose({
|
||||
overflow: auto;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 8px;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.file-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.file-table th,
|
||||
.file-table td {
|
||||
padding: 0.75rem;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid #ddd;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.file-table th {
|
||||
@ -305,22 +361,52 @@ defineExpose({
|
||||
font-weight: 600;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
color: #495057;
|
||||
}
|
||||
|
||||
.file-table tr:hover {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
.filename-cell {
|
||||
max-width: 250px;
|
||||
max-width: 200px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.md5-cell {
|
||||
font-family: monospace;
|
||||
.file-type {
|
||||
font-size: 0.875rem;
|
||||
max-width: 200px;
|
||||
color: #6c757d;
|
||||
}
|
||||
|
||||
.ocr-status {
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.ocr-done {
|
||||
color: #28a745;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.ocr-pending {
|
||||
color: #6c757d;
|
||||
}
|
||||
|
||||
.md5-cell {
|
||||
font-family: 'Courier New', monospace;
|
||||
font-size: 0.75rem;
|
||||
max-width: 120px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
color: #6c757d;
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.check-button {
|
||||
@ -330,7 +416,8 @@ defineExpose({
|
||||
padding: 0.25rem 0.5rem;
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
font-size: 0.875rem;
|
||||
font-size: 0.75rem;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
|
||||
.check-button:hover:not(:disabled) {
|
||||
@ -342,11 +429,35 @@ defineExpose({
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.ocr-button {
|
||||
background: #3498db;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 0.25rem 0.5rem;
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
font-size: 0.75rem;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
|
||||
.ocr-button:hover:not(:disabled) {
|
||||
background: #2980b9;
|
||||
}
|
||||
|
||||
.ocr-button:disabled {
|
||||
background: #bdc3c7;
|
||||
cursor: not-allowed;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
text-align: center;
|
||||
padding: 2rem;
|
||||
color: #666;
|
||||
padding: 3rem;
|
||||
color: #6c757d;
|
||||
font-style: italic;
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
.pagination {
|
||||
@ -356,6 +467,9 @@ defineExpose({
|
||||
gap: 1rem;
|
||||
margin-top: 1rem;
|
||||
padding: 1rem;
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
flex-shrink: 0; /* 防止分页被压缩 */
|
||||
}
|
||||
|
||||
.page-button {
|
||||
@ -365,6 +479,7 @@ defineExpose({
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
|
||||
.page-button:hover:not(:disabled) {
|
||||
@ -377,6 +492,7 @@ defineExpose({
|
||||
}
|
||||
|
||||
.page-info {
|
||||
color: #666;
|
||||
color: #6c757d;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
</style>
|
||||
文件差异内容过多而无法显示
加载差异
@ -90,6 +90,8 @@ const handleOcrRecognize = (file: FileRecord): void => {
|
||||
console.log('导航成功:', res)
|
||||
}).catch((error) => {
|
||||
console.error('导航错误:', error)
|
||||
// 如果路由跳转失败,尝试使用 hash 方式
|
||||
window.location.hash = `/ocr?fileId=${file.id}`
|
||||
})
|
||||
}
|
||||
</script>
|
||||
@ -104,6 +106,8 @@ const handleOcrRecognize = (file: FileRecord): void => {
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: #f5f5f5;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#app {
|
||||
@ -120,6 +124,7 @@ body {
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
flex-shrink: 0; /* 防止头部被压缩 */
|
||||
}
|
||||
|
||||
.network-indicator {
|
||||
@ -143,6 +148,6 @@ body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
overflow: hidden;
|
||||
overflow: hidden; /* 改为 hidden,内部组件自己处理滚动 */
|
||||
}
|
||||
</style>
|
||||
289
yarn.lock
289
yarn.lock
@ -42,6 +42,13 @@
|
||||
optionalDependencies:
|
||||
global-agent "^3.0.0"
|
||||
|
||||
"@emnapi/runtime@^1.7.0":
|
||||
version "1.7.0"
|
||||
resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.7.0.tgz#d7ef3832df8564fe5903bf0567aedbd19538ecbe"
|
||||
integrity sha512-oAYoQnCYaQZKVS53Fq23ceWMRxq5EhQsE0x0RdQ55jT7wagMu5k+fS39v1fiSLrtrLQlXwVINenqhLMtTrV/1Q==
|
||||
dependencies:
|
||||
tslib "^2.4.0"
|
||||
|
||||
"@epic-web/invariant@^1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@epic-web/invariant/-/invariant-1.0.0.tgz#1073e5dee6dd540410784990eb73e4acd25c9813"
|
||||
@ -216,6 +223,153 @@
|
||||
dependencies:
|
||||
"@hapi/hoek" "^11.0.2"
|
||||
|
||||
"@img/colour@^1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@img/colour/-/colour-1.0.0.tgz#d2fabb223455a793bf3bf9c70de3d28526aa8311"
|
||||
integrity sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==
|
||||
|
||||
"@img/sharp-darwin-arm64@0.34.5":
|
||||
version "0.34.5"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz#6e0732dcade126b6670af7aa17060b926835ea86"
|
||||
integrity sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==
|
||||
optionalDependencies:
|
||||
"@img/sharp-libvips-darwin-arm64" "1.2.4"
|
||||
|
||||
"@img/sharp-darwin-x64@0.34.5":
|
||||
version "0.34.5"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz#19bc1dd6eba6d5a96283498b9c9f401180ee9c7b"
|
||||
integrity sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==
|
||||
optionalDependencies:
|
||||
"@img/sharp-libvips-darwin-x64" "1.2.4"
|
||||
|
||||
"@img/sharp-libvips-darwin-arm64@1.2.4":
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz#2894c0cb87d42276c3889942e8e2db517a492c43"
|
||||
integrity sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==
|
||||
|
||||
"@img/sharp-libvips-darwin-x64@1.2.4":
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz#e63681f4539a94af9cd17246ed8881734386f8cc"
|
||||
integrity sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==
|
||||
|
||||
"@img/sharp-libvips-linux-arm64@1.2.4":
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz#b1b288b36864b3bce545ad91fa6dadcf1a4ad318"
|
||||
integrity sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==
|
||||
|
||||
"@img/sharp-libvips-linux-arm@1.2.4":
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz#b9260dd1ebe6f9e3bdbcbdcac9d2ac125f35852d"
|
||||
integrity sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==
|
||||
|
||||
"@img/sharp-libvips-linux-ppc64@1.2.4":
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz#4b83ecf2a829057222b38848c7b022e7b4d07aa7"
|
||||
integrity sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==
|
||||
|
||||
"@img/sharp-libvips-linux-riscv64@1.2.4":
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz#880b4678009e5a2080af192332b00b0aaf8a48de"
|
||||
integrity sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==
|
||||
|
||||
"@img/sharp-libvips-linux-s390x@1.2.4":
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz#74f343c8e10fad821b38f75ced30488939dc59ec"
|
||||
integrity sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==
|
||||
|
||||
"@img/sharp-libvips-linux-x64@1.2.4":
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz#df4183e8bd8410f7d61b66859a35edeab0a531ce"
|
||||
integrity sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==
|
||||
|
||||
"@img/sharp-libvips-linuxmusl-arm64@1.2.4":
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz#c8d6b48211df67137541007ee8d1b7b1f8ca8e06"
|
||||
integrity sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==
|
||||
|
||||
"@img/sharp-libvips-linuxmusl-x64@1.2.4":
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz#be11c75bee5b080cbee31a153a8779448f919f75"
|
||||
integrity sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==
|
||||
|
||||
"@img/sharp-linux-arm64@0.34.5":
|
||||
version "0.34.5"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz#7aa7764ef9c001f15e610546d42fce56911790cc"
|
||||
integrity sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==
|
||||
optionalDependencies:
|
||||
"@img/sharp-libvips-linux-arm64" "1.2.4"
|
||||
|
||||
"@img/sharp-linux-arm@0.34.5":
|
||||
version "0.34.5"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz#5fb0c3695dd12522d39c3ff7a6bc816461780a0d"
|
||||
integrity sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==
|
||||
optionalDependencies:
|
||||
"@img/sharp-libvips-linux-arm" "1.2.4"
|
||||
|
||||
"@img/sharp-linux-ppc64@0.34.5":
|
||||
version "0.34.5"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz#9c213a81520a20caf66978f3d4c07456ff2e0813"
|
||||
integrity sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==
|
||||
optionalDependencies:
|
||||
"@img/sharp-libvips-linux-ppc64" "1.2.4"
|
||||
|
||||
"@img/sharp-linux-riscv64@0.34.5":
|
||||
version "0.34.5"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz#cdd28182774eadbe04f62675a16aabbccb833f60"
|
||||
integrity sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==
|
||||
optionalDependencies:
|
||||
"@img/sharp-libvips-linux-riscv64" "1.2.4"
|
||||
|
||||
"@img/sharp-linux-s390x@0.34.5":
|
||||
version "0.34.5"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz#93eac601b9f329bb27917e0e19098c722d630df7"
|
||||
integrity sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==
|
||||
optionalDependencies:
|
||||
"@img/sharp-libvips-linux-s390x" "1.2.4"
|
||||
|
||||
"@img/sharp-linux-x64@0.34.5":
|
||||
version "0.34.5"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz#55abc7cd754ffca5002b6c2b719abdfc846819a8"
|
||||
integrity sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==
|
||||
optionalDependencies:
|
||||
"@img/sharp-libvips-linux-x64" "1.2.4"
|
||||
|
||||
"@img/sharp-linuxmusl-arm64@0.34.5":
|
||||
version "0.34.5"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz#d6515ee971bb62f73001a4829b9d865a11b77086"
|
||||
integrity sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==
|
||||
optionalDependencies:
|
||||
"@img/sharp-libvips-linuxmusl-arm64" "1.2.4"
|
||||
|
||||
"@img/sharp-linuxmusl-x64@0.34.5":
|
||||
version "0.34.5"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz#d97978aec7c5212f999714f2f5b736457e12ee9f"
|
||||
integrity sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==
|
||||
optionalDependencies:
|
||||
"@img/sharp-libvips-linuxmusl-x64" "1.2.4"
|
||||
|
||||
"@img/sharp-wasm32@0.34.5":
|
||||
version "0.34.5"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz#2f15803aa626f8c59dd7c9d0bbc766f1ab52cfa0"
|
||||
integrity sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==
|
||||
dependencies:
|
||||
"@emnapi/runtime" "^1.7.0"
|
||||
|
||||
"@img/sharp-win32-arm64@0.34.5":
|
||||
version "0.34.5"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz#3706e9e3ac35fddfc1c87f94e849f1b75307ce0a"
|
||||
integrity sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==
|
||||
|
||||
"@img/sharp-win32-ia32@0.34.5":
|
||||
version "0.34.5"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz#0b71166599b049e032f085fb9263e02f4e4788de"
|
||||
integrity sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==
|
||||
|
||||
"@img/sharp-win32-x64@0.34.5":
|
||||
version "0.34.5"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz#a81ffb00e69267cd0a1d626eaedb8a8430b2b2f8"
|
||||
integrity sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==
|
||||
|
||||
"@jridgewell/sourcemap-codec@^1.5.5":
|
||||
version "1.5.5"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz#6912b00d2c631c0d15ce1a7ab57cd657f2a8f8ba"
|
||||
@ -762,6 +916,11 @@ bl@^4.0.3:
|
||||
inherits "^2.0.4"
|
||||
readable-stream "^3.4.0"
|
||||
|
||||
bmp-js@^0.1.0:
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/bmp-js/-/bmp-js-0.1.0.tgz#e05a63f796a6c1ff25f4771ec7adadc148c07233"
|
||||
integrity sha512-vHdS19CnY3hwiNdkaqk93DvjVLfbEcI8mys4UjuWrlX1haDmroo8o4xCzh4wD6DGV6HxRCyauwhHRqMTfERtjw==
|
||||
|
||||
body-parser@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-2.2.0.tgz#f7a9656de305249a715b549b7b8fd1ab9dfddcfa"
|
||||
@ -878,6 +1037,14 @@ call-bound@^1.0.2:
|
||||
call-bind-apply-helpers "^1.0.2"
|
||||
get-intrinsic "^1.3.0"
|
||||
|
||||
canvas@^3.2.0:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/canvas/-/canvas-3.2.0.tgz#877c51aabdb99cbb5b2b378138a6cdd681e9d390"
|
||||
integrity sha512-jk0GxrLtUEmW/TmFsk2WghvgHe8B0pxGilqCL21y8lHkPUGa6FTsnCNtHPOzT8O3y+N+m3espawV80bbBlgfTA==
|
||||
dependencies:
|
||||
node-addon-api "^7.0.0"
|
||||
prebuild-install "^7.1.3"
|
||||
|
||||
chalk@4.1.2:
|
||||
version "4.1.2"
|
||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
|
||||
@ -1089,7 +1256,7 @@ depd@2.0.0, depd@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df"
|
||||
integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==
|
||||
|
||||
detect-libc@^2.0.0:
|
||||
detect-libc@^2.0.0, detect-libc@^2.1.2:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.1.2.tgz#689c5dcdc1900ef5583a4cb9f6d7b473742074ad"
|
||||
integrity sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==
|
||||
@ -1611,6 +1778,11 @@ iconv-lite@^0.6.2, iconv-lite@^0.6.3:
|
||||
dependencies:
|
||||
safer-buffer ">= 2.1.2 < 3.0.0"
|
||||
|
||||
idb-keyval@^6.2.0:
|
||||
version "6.2.2"
|
||||
resolved "https://registry.yarnpkg.com/idb-keyval/-/idb-keyval-6.2.2.tgz#b0171b5f73944854a3291a5cdba8e12768c4854a"
|
||||
integrity sha512-yjD9nARJ/jb1g+CvD0tlhUHOrJ9Sy0P8T9MF3YaLlHnSRpwPfpTX0XIvpmw3gAJUmEu3FiICLBDPXVwyEvrleg==
|
||||
|
||||
ieee754@^1.1.13:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
|
||||
@ -1674,6 +1846,11 @@ is-promise@^4.0.0:
|
||||
resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-4.0.0.tgz#42ff9f84206c1991d26debf520dd5c01042dd2f3"
|
||||
integrity sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==
|
||||
|
||||
is-url@^1.2.4:
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/is-url/-/is-url-1.2.4.tgz#04a4df46d28c4cff3d73d01ff06abeb318a1aa52"
|
||||
integrity sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==
|
||||
|
||||
isexe@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
|
||||
@ -1975,6 +2152,13 @@ node-addon-api@^7.0.0:
|
||||
resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-7.1.1.tgz#1aba6693b0f255258a049d621329329322aad558"
|
||||
integrity sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==
|
||||
|
||||
node-fetch@^2.6.9:
|
||||
version "2.7.0"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d"
|
||||
integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==
|
||||
dependencies:
|
||||
whatwg-url "^5.0.0"
|
||||
|
||||
node-gyp@8.x:
|
||||
version "8.4.1"
|
||||
resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-8.4.1.tgz#3d49308fc31f768180957d6b5746845fbd429937"
|
||||
@ -1991,6 +2175,11 @@ node-gyp@8.x:
|
||||
tar "^6.1.2"
|
||||
which "^2.0.2"
|
||||
|
||||
node-tesseract-ocr@^2.2.1:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/node-tesseract-ocr/-/node-tesseract-ocr-2.2.1.tgz#465fea1a1acd6720efb582d5f6c2bcbb82cce94d"
|
||||
integrity sha512-Q9cD79JGpPNQBxbi1fV+OAsTxYKLpx22sagsxSyKbu1u+t6UarApf5m32uVc8a5QAP1Wk7fIPN0aJFGGEE9DyQ==
|
||||
|
||||
nopt@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88"
|
||||
@ -2042,6 +2231,11 @@ once@^1.3.0, once@^1.3.1, once@^1.4.0:
|
||||
dependencies:
|
||||
wrappy "1"
|
||||
|
||||
opencollective-postinstall@^2.0.3:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz#7a0fff978f6dbfa4d006238fbac98ed4198c3259"
|
||||
integrity sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==
|
||||
|
||||
p-cancelable@^2.0.0:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.1.1.tgz#aab7fbd416582fa32a3db49859c122487c5ed2cf"
|
||||
@ -2103,7 +2297,7 @@ postcss@^8.5.6:
|
||||
picocolors "^1.1.1"
|
||||
source-map-js "^1.2.1"
|
||||
|
||||
prebuild-install@^7.1.1:
|
||||
prebuild-install@^7.1.1, prebuild-install@^7.1.3:
|
||||
version "7.1.3"
|
||||
resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-7.1.3.tgz#d630abad2b147443f20a212917beae68b8092eec"
|
||||
integrity sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==
|
||||
@ -2206,6 +2400,11 @@ readable-stream@^3.0.2, readable-stream@^3.1.1, readable-stream@^3.4.0, readable
|
||||
string_decoder "^1.1.1"
|
||||
util-deprecate "^1.0.1"
|
||||
|
||||
regenerator-runtime@^0.13.3:
|
||||
version "0.13.11"
|
||||
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9"
|
||||
integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==
|
||||
|
||||
require-directory@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
|
||||
@ -2316,7 +2515,7 @@ semver@^6.2.0:
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
|
||||
integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
|
||||
|
||||
semver@^7.3.2, semver@^7.3.5:
|
||||
semver@^7.3.2, semver@^7.3.5, semver@^7.7.3:
|
||||
version "7.7.3"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.3.tgz#4b5f4143d007633a8dc671cd0a6ef9147b8bb946"
|
||||
integrity sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==
|
||||
@ -2365,6 +2564,40 @@ setprototypeof@1.2.0:
|
||||
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424"
|
||||
integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==
|
||||
|
||||
sharp@^0.34.5:
|
||||
version "0.34.5"
|
||||
resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.34.5.tgz#b6f148e4b8c61f1797bde11a9d1cfebbae2c57b0"
|
||||
integrity sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==
|
||||
dependencies:
|
||||
"@img/colour" "^1.0.0"
|
||||
detect-libc "^2.1.2"
|
||||
semver "^7.7.3"
|
||||
optionalDependencies:
|
||||
"@img/sharp-darwin-arm64" "0.34.5"
|
||||
"@img/sharp-darwin-x64" "0.34.5"
|
||||
"@img/sharp-libvips-darwin-arm64" "1.2.4"
|
||||
"@img/sharp-libvips-darwin-x64" "1.2.4"
|
||||
"@img/sharp-libvips-linux-arm" "1.2.4"
|
||||
"@img/sharp-libvips-linux-arm64" "1.2.4"
|
||||
"@img/sharp-libvips-linux-ppc64" "1.2.4"
|
||||
"@img/sharp-libvips-linux-riscv64" "1.2.4"
|
||||
"@img/sharp-libvips-linux-s390x" "1.2.4"
|
||||
"@img/sharp-libvips-linux-x64" "1.2.4"
|
||||
"@img/sharp-libvips-linuxmusl-arm64" "1.2.4"
|
||||
"@img/sharp-libvips-linuxmusl-x64" "1.2.4"
|
||||
"@img/sharp-linux-arm" "0.34.5"
|
||||
"@img/sharp-linux-arm64" "0.34.5"
|
||||
"@img/sharp-linux-ppc64" "0.34.5"
|
||||
"@img/sharp-linux-riscv64" "0.34.5"
|
||||
"@img/sharp-linux-s390x" "0.34.5"
|
||||
"@img/sharp-linux-x64" "0.34.5"
|
||||
"@img/sharp-linuxmusl-arm64" "0.34.5"
|
||||
"@img/sharp-linuxmusl-x64" "0.34.5"
|
||||
"@img/sharp-wasm32" "0.34.5"
|
||||
"@img/sharp-win32-arm64" "0.34.5"
|
||||
"@img/sharp-win32-ia32" "0.34.5"
|
||||
"@img/sharp-win32-x64" "0.34.5"
|
||||
|
||||
shebang-command@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
|
||||
@ -2594,6 +2827,26 @@ tar@^6.0.2, tar@^6.1.11, tar@^6.1.2:
|
||||
mkdirp "^1.0.3"
|
||||
yallist "^4.0.0"
|
||||
|
||||
tesseract.js-core@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/tesseract.js-core/-/tesseract.js-core-6.0.0.tgz#6f25da94f70f8e8f02aff47a43be61d49e6f67c3"
|
||||
integrity sha512-1Qncm/9oKM7xgrQXZXNB+NRh19qiXGhxlrR8EwFbK5SaUbPZnS5OMtP/ghtqfd23hsr1ZvZbZjeuAGcMxd/ooA==
|
||||
|
||||
tesseract.js@^6.0.1:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/tesseract.js/-/tesseract.js-6.0.1.tgz#5b2ff39aae92d59cef79589a43a0f3ab963801cc"
|
||||
integrity sha512-/sPvMvrCtgxnNRCjbTYbr7BRu0yfWDsMZQ2a/T5aN/L1t8wUQN6tTWv6p6FwzpoEBA0jrN2UD2SX4QQFRdoDbA==
|
||||
dependencies:
|
||||
bmp-js "^0.1.0"
|
||||
idb-keyval "^6.2.0"
|
||||
is-url "^1.2.4"
|
||||
node-fetch "^2.6.9"
|
||||
opencollective-postinstall "^2.0.3"
|
||||
regenerator-runtime "^0.13.3"
|
||||
tesseract.js-core "^6.0.0"
|
||||
wasm-feature-detect "^1.2.11"
|
||||
zlibjs "^0.3.1"
|
||||
|
||||
tinyglobby@^0.2.15:
|
||||
version "0.2.15"
|
||||
resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.15.tgz#e228dd1e638cea993d2fdb4fcd2d4602a79951c2"
|
||||
@ -2607,6 +2860,11 @@ toidentifier@1.0.1:
|
||||
resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35"
|
||||
integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==
|
||||
|
||||
tr46@~0.0.3:
|
||||
version "0.0.3"
|
||||
resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
|
||||
integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==
|
||||
|
||||
tree-kill@1.2.2:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc"
|
||||
@ -2617,7 +2875,7 @@ tslib@^1.7.1:
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
|
||||
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
|
||||
|
||||
tslib@^2.1.0:
|
||||
tslib@^2.1.0, tslib@^2.4.0:
|
||||
version "2.8.1"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f"
|
||||
integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==
|
||||
@ -2776,6 +3034,24 @@ wait-on@^9.0.1:
|
||||
minimist "^1.2.8"
|
||||
rxjs "^7.8.2"
|
||||
|
||||
wasm-feature-detect@^1.2.11:
|
||||
version "1.8.0"
|
||||
resolved "https://registry.yarnpkg.com/wasm-feature-detect/-/wasm-feature-detect-1.8.0.tgz#4e9f55b0a64d801f372fbb0324ed11ad3abd0c78"
|
||||
integrity sha512-zksaLKM2fVlnB5jQQDqKXXwYHLQUVH9es+5TOOHwGOVJOCeRBCiPjwSg+3tN2AdTCzjgli4jijCH290kXb/zWQ==
|
||||
|
||||
webidl-conversions@^3.0.0:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
|
||||
integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==
|
||||
|
||||
whatwg-url@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d"
|
||||
integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==
|
||||
dependencies:
|
||||
tr46 "~0.0.3"
|
||||
webidl-conversions "^3.0.0"
|
||||
|
||||
which@^2.0.1, which@^2.0.2:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
|
||||
@ -2844,3 +3120,8 @@ yauzl@^2.10.0:
|
||||
dependencies:
|
||||
buffer-crc32 "~0.2.3"
|
||||
fd-slicer "~1.1.0"
|
||||
|
||||
zlibjs@^0.3.1:
|
||||
version "0.3.1"
|
||||
resolved "https://registry.yarnpkg.com/zlibjs/-/zlibjs-0.3.1.tgz#50197edb28a1c42ca659cc8b4e6a9ddd6d444554"
|
||||
integrity sha512-+J9RrgTKOmlxFSDHo0pI1xM6BLVUv+o0ZT9ANtCxGkjIVCCUdx9alUF8Gm+dGLKbkkkidWIHFDZHDMpfITt4+w==
|
||||
|
||||
正在加载...
在新工单中引用
屏蔽一个用户