逻辑修改.

This commit is contained in:
18631081161 2025-12-24 21:07:03 +08:00
parent ece1ef09ad
commit 9e45704c66
4 changed files with 84 additions and 35 deletions

View File

@ -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: '微信',

View File

@ -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) {

View File

@ -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,

View File

@ -654,6 +654,7 @@ AppServer.prototype.UploadImage = async function(filePath) {
url: url,
filePath: filePath,
name: 'image',
timeout: 60000, // 60秒超时
header: {
'Authorization': authToken
},