逻辑修改.
This commit is contained in:
parent
ece1ef09ad
commit
9e45704c66
|
|
@ -54,7 +54,7 @@
|
|||
</el-table-column>
|
||||
<el-table-column prop="amount" label="提现金额" width="120" align="right" sortable="custom">
|
||||
<template #default="{ row }">
|
||||
<span class="amount">¥{{ row.amount }}</span>
|
||||
<span class="amount">{{ getCurrencySymbol(row.currency) }}{{ row.amount }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="paymentMethod" label="支付方式" width="100" align="center">
|
||||
|
|
@ -135,7 +135,12 @@
|
|||
</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="提现金额">
|
||||
<span class="amount-large">¥{{ withdrawalDetails.amount }}</span>
|
||||
<span class="amount-large">{{ getCurrencySymbol(withdrawalDetails.currency) }}{{ withdrawalDetails.amount }}</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="货币类型">
|
||||
<el-tag :type="withdrawalDetails.currency === 'PHP' ? 'warning' : 'primary'" size="small">
|
||||
{{ withdrawalDetails.currency === 'PHP' ? '比索 (PHP)' : '人民币 (CNY)' }}
|
||||
</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="支付方式">
|
||||
<el-tag :type="getPaymentMethodType(withdrawalDetails.paymentMethod)" size="small">
|
||||
|
|
@ -224,7 +229,7 @@
|
|||
<template #default>
|
||||
<div class="alert-content">
|
||||
<p>提现单号:<strong>{{ approveForm.withdrawalNo }}</strong></p>
|
||||
<p>提现金额:<strong class="amount">¥{{ approveForm.amount }}</strong></p>
|
||||
<p>提现金额:<strong class="amount">{{ getCurrencySymbol(approveForm.currency) }}{{ approveForm.amount }}</strong></p>
|
||||
<p>用户:<strong>{{ approveForm.userName }}</strong></p>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -265,7 +270,7 @@
|
|||
<template #default>
|
||||
<div class="alert-content">
|
||||
<p>提现单号:<strong>{{ rejectForm.withdrawalNo }}</strong></p>
|
||||
<p>提现金额:<strong class="amount">¥{{ rejectForm.amount }}</strong></p>
|
||||
<p>提现金额:<strong class="amount">{{ getCurrencySymbol(rejectForm.currency) }}{{ rejectForm.amount }}</strong></p>
|
||||
<p>用户:<strong>{{ rejectForm.userName }}</strong></p>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -328,6 +333,7 @@ const approveForm = reactive({
|
|||
withdrawalId: '',
|
||||
withdrawalNo: '',
|
||||
amount: '',
|
||||
currency: 'CNY',
|
||||
userName: '',
|
||||
notes: ''
|
||||
})
|
||||
|
|
@ -340,6 +346,7 @@ const rejectForm = reactive({
|
|||
withdrawalId: '',
|
||||
withdrawalNo: '',
|
||||
amount: '',
|
||||
currency: 'CNY',
|
||||
userName: '',
|
||||
reason: ''
|
||||
})
|
||||
|
|
@ -448,6 +455,7 @@ function handleApprove(row) {
|
|||
approveForm.withdrawalId = row.id
|
||||
approveForm.withdrawalNo = row.withdrawalNo
|
||||
approveForm.amount = row.amount
|
||||
approveForm.currency = row.currency || 'CNY'
|
||||
approveForm.userName = row.user?.nickname || row.user?.realName || '-'
|
||||
approveForm.notes = ''
|
||||
approveDialogVisible.value = true
|
||||
|
|
@ -487,6 +495,7 @@ function handleReject(row) {
|
|||
rejectForm.withdrawalId = row.id
|
||||
rejectForm.withdrawalNo = row.withdrawalNo
|
||||
rejectForm.amount = row.amount
|
||||
rejectForm.currency = row.currency || 'CNY'
|
||||
rejectForm.userName = row.user?.nickname || row.user?.realName || '-'
|
||||
rejectForm.reason = ''
|
||||
rejectDialogVisible.value = true
|
||||
|
|
@ -561,6 +570,10 @@ function getStatusTagType(status) {
|
|||
return types[status] || 'info'
|
||||
}
|
||||
|
||||
function getCurrencySymbol(currency) {
|
||||
return currency === 'PHP' ? '₱' : '¥'
|
||||
}
|
||||
|
||||
function getPaymentMethodLabel(method) {
|
||||
const labels = {
|
||||
wechat: '微信',
|
||||
|
|
|
|||
|
|
@ -4,6 +4,9 @@ const fs = require('fs').promises;
|
|||
const { uploadDir } = require('../middleware/upload');
|
||||
const logger = require('../config/logger');
|
||||
|
||||
// 图片处理阈值:小于此大小的图片不进行压缩处理(500KB)
|
||||
const SKIP_PROCESSING_SIZE = 500 * 1024;
|
||||
|
||||
/**
|
||||
* Upload and process image
|
||||
* POST /api/v1/upload/image
|
||||
|
|
@ -19,10 +22,51 @@ const uploadImage = async (req, res, next) => {
|
|||
}
|
||||
|
||||
const originalPath = req.file.path;
|
||||
const originalSize = req.file.size;
|
||||
const originalExt = path.extname(req.file.originalname).toLowerCase();
|
||||
|
||||
// Generate unique filename with .jpg extension (since we're converting to JPEG)
|
||||
// Generate unique filename
|
||||
const timestamp = Date.now();
|
||||
const randomString = Math.random().toString(36).substring(2, 15);
|
||||
|
||||
// 对于小图片或已经是jpg/jpeg格式的小图片,跳过处理直接使用
|
||||
const isSmallImage = originalSize < SKIP_PROCESSING_SIZE;
|
||||
const isJpeg = ['.jpg', '.jpeg'].includes(originalExt);
|
||||
|
||||
if (isSmallImage && isJpeg) {
|
||||
// 小的JPEG图片直接重命名使用,不进行处理
|
||||
const newFilename = `${timestamp}_${randomString}.jpg`;
|
||||
const newPath = path.join(uploadDir, newFilename);
|
||||
|
||||
try {
|
||||
await fs.rename(originalPath, newPath);
|
||||
} catch (renameError) {
|
||||
// 如果重命名失败(跨分区),则复制后删除
|
||||
await fs.copyFile(originalPath, newPath);
|
||||
await fs.unlink(originalPath).catch(() => {});
|
||||
}
|
||||
|
||||
const imageUrl = `/uploads/${newFilename}`;
|
||||
|
||||
logger.info('Image uploaded (skipped processing)', {
|
||||
originalName: req.file.originalname,
|
||||
filename: newFilename,
|
||||
size: originalSize,
|
||||
});
|
||||
|
||||
return res.status(200).json({
|
||||
code: 0,
|
||||
message: 'Image uploaded successfully',
|
||||
data: {
|
||||
url: imageUrl,
|
||||
filename: newFilename,
|
||||
originalName: req.file.originalname,
|
||||
size: originalSize,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// 需要处理的图片
|
||||
const processedFilename = `${timestamp}_${randomString}.jpg`;
|
||||
const processedPath = path.join(uploadDir, processedFilename);
|
||||
|
||||
|
|
@ -32,49 +76,42 @@ const uploadImage = async (req, res, next) => {
|
|||
}
|
||||
|
||||
try {
|
||||
// Process image with Sharp
|
||||
const sharpInstance = sharp(originalPath);
|
||||
// Process image with Sharp - 使用更快的设置
|
||||
const sharpInstance = sharp(originalPath, {
|
||||
failOnError: false, // 不因为小错误而失败
|
||||
limitInputPixels: false, // 不限制输入像素
|
||||
});
|
||||
|
||||
await sharpInstance
|
||||
.resize(1200, 1200, {
|
||||
fit: 'inside',
|
||||
withoutEnlargement: true,
|
||||
})
|
||||
.jpeg({
|
||||
quality: 85,
|
||||
progressive: true,
|
||||
quality: 80, // 稍微降低质量以加快处理速度
|
||||
progressive: false, // 关闭渐进式以加快处理
|
||||
mozjpeg: false, // 不使用mozjpeg以加快速度
|
||||
})
|
||||
.toFile(processedPath);
|
||||
|
||||
// Destroy sharp instance to release file handles
|
||||
sharpInstance.destroy();
|
||||
|
||||
// Delete original file if it's different from processed
|
||||
// On Windows, file deletion can fail due to file locks, so we schedule it for later
|
||||
if (originalPath !== processedPath) {
|
||||
// Schedule deletion after a delay to avoid file lock issues on Windows
|
||||
setTimeout(async () => {
|
||||
try {
|
||||
await fs.unlink(originalPath);
|
||||
logger.info('Original file deleted successfully', { path: originalPath });
|
||||
} catch (unlinkError) {
|
||||
// If deletion still fails, just log it
|
||||
// The file will need to be cleaned up manually or by a cleanup job
|
||||
logger.warn('Could not delete original file', {
|
||||
path: originalPath,
|
||||
error: unlinkError.message
|
||||
});
|
||||
}
|
||||
}, 500); // Wait 500ms before attempting deletion
|
||||
}
|
||||
// Delete original file - 异步删除,不等待
|
||||
fs.unlink(originalPath).catch(unlinkError => {
|
||||
logger.warn('Could not delete original file', {
|
||||
path: originalPath,
|
||||
error: unlinkError.message
|
||||
});
|
||||
});
|
||||
|
||||
// Return relative path for the image (more portable)
|
||||
// Frontend will prepend the base URL as needed
|
||||
// Return relative path for the image
|
||||
const imageUrl = `/uploads/${processedFilename}`;
|
||||
|
||||
logger.info('Image uploaded and processed successfully', {
|
||||
originalName: req.file.originalname,
|
||||
processedFilename,
|
||||
size: req.file.size,
|
||||
originalSize,
|
||||
});
|
||||
|
||||
res.status(200).json({
|
||||
|
|
@ -89,11 +126,7 @@ const uploadImage = async (req, res, next) => {
|
|||
});
|
||||
} catch (processingError) {
|
||||
// Clean up file if processing fails
|
||||
try {
|
||||
await fs.unlink(originalPath);
|
||||
} catch (unlinkError) {
|
||||
logger.error('Failed to delete file after processing error', { error: unlinkError });
|
||||
}
|
||||
fs.unlink(originalPath).catch(() => {});
|
||||
throw processingError;
|
||||
}
|
||||
} catch (error) {
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@ const getWithdrawalList = async (options = {}) => {
|
|||
id: withdrawal.id,
|
||||
withdrawalNo: withdrawal.withdrawalNo,
|
||||
amount: parseFloat(withdrawal.amount).toFixed(2),
|
||||
currency: withdrawal.currency || 'CNY',
|
||||
paymentMethod: withdrawal.paymentMethod,
|
||||
paymentDetails: withdrawal.paymentDetails,
|
||||
status: withdrawal.status,
|
||||
|
|
@ -281,6 +282,7 @@ const getWithdrawalDetails = async (withdrawalId) => {
|
|||
id: withdrawal.id,
|
||||
withdrawalNo: withdrawal.withdrawalNo,
|
||||
amount: parseFloat(withdrawal.amount).toFixed(2),
|
||||
currency: withdrawal.currency || 'CNY',
|
||||
paymentMethod: withdrawal.paymentMethod,
|
||||
paymentDetails: withdrawal.paymentDetails,
|
||||
status: withdrawal.status,
|
||||
|
|
|
|||
|
|
@ -654,6 +654,7 @@ AppServer.prototype.UploadImage = async function(filePath) {
|
|||
url: url,
|
||||
filePath: filePath,
|
||||
name: 'image',
|
||||
timeout: 60000, // 60秒超时
|
||||
header: {
|
||||
'Authorization': authToken
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user