feat: 添加任务状态级联触发器,优化支付和做同款功能

主要更新:
- 添加 MySQL 触发器实现 task_status 表到其他表的状态级联
- 移除控制器中的多表状态检查代码
- 完善做同款功能,支持参数传递
- 支付宝 USD 转 CNY 汇率转换
- 修复状态枚举映射问题

注意: 触发器仅在 task_status 更新时触发,部分代码仍直接更新业务表
This commit is contained in:
AIGC Developer
2025-12-08 13:54:02 +08:00
parent 624d560fb4
commit 3c37006ebd
84 changed files with 5325 additions and 1668 deletions

View File

@@ -42,8 +42,8 @@
</nav>
<div class="sidebar-footer">
<div class="online-users">
{{ $t('nav.onlineUsers') }}: <span class="highlight">{{ onlineUsers }}</span>
</div>
{{ $t('nav.todayVisitors') }}: <span class="highlight">{{ onlineUsers }}</span>
</div>
<div class="system-uptime">
{{ $t('nav.systemUptime') }}: <span class="highlight">{{ systemUptime }}</span>
</div>
@@ -93,11 +93,7 @@
<el-select v-model="filters.status" :placeholder="$t('orders.allStatus')" size="small" @change="handleFilterChange">
<el-option :label="$t('orders.allStatus')" value="" />
<el-option :label="$t('orders.pending')" value="PENDING" />
<el-option :label="$t('orders.confirmed')" value="CONFIRMED" />
<el-option :label="$t('orders.paid')" value="PAID" />
<el-option :label="$t('orders.processing')" value="PROCESSING" />
<el-option :label="$t('orders.shipped')" value="SHIPPED" />
<el-option :label="$t('orders.delivered')" value="DELIVERED" />
<el-option :label="$t('orders.completed')" value="COMPLETED" />
<el-option :label="$t('orders.cancelled')" value="CANCELLED" />
<el-option :label="$t('orders.refunded')" value="REFUNDED" />
@@ -290,6 +286,7 @@
import { ref, reactive, onMounted, computed } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import { useI18n } from 'vue-i18n'
import {
Grid,
User,
@@ -310,6 +307,7 @@ import LanguageSwitcher from '@/components/LanguageSwitcher.vue'
const router = useRouter()
const route = useRoute()
const { t } = useI18n()
// 判断是否为管理员模式(基于路由路径)
const isAdminMode = computed(() => route.path.includes('/admin/'))
@@ -324,7 +322,7 @@ const totalOrders = ref(0)
// 系统状态数据
const onlineUsers = ref('0/500')
const systemUptime = ref('加载中...')
const systemUptime = ref(t('nav.loading'))
// 筛选条件
const filters = reactive({
@@ -513,17 +511,17 @@ const viewOrder = async (order) => {
const deleteOrder = async (order) => {
try {
await ElMessageBox.confirm(
`确定要删除订单 ${order.orderNumber || order.id} 吗?`,
'确认删除',
t('orders.confirmDeleteOrder', { orderNumber: order.orderNumber || order.id }),
t('orders.confirmDeleteTitle'),
{
confirmButtonText: '确定',
cancelButtonText: '取消',
confirmButtonText: t('common.confirm'),
cancelButtonText: t('common.cancel'),
type: 'warning',
}
)
const response = await deleteOrderAPI(order.id)
console.log('删除订单响应:', response)
console.log('Delete order response:', response)
// 检查响应状态
if (response.data?.success) {
@@ -532,51 +530,51 @@ const deleteOrder = async (order) => {
orders.value.splice(index, 1)
totalOrders.value--
}
ElMessage.success('删除成功')
ElMessage.success(t('orders.deleteSuccess'))
} else {
ElMessage.error(response.data?.message || '删除失败')
ElMessage.error(response.data?.message || t('orders.deleteFailed'))
}
} catch (error) {
if (error !== 'cancel') {
console.error('删除失败:', error)
ElMessage.error('删除失败: ' + (error.message || '未知错误'))
console.error('Delete failed:', error)
ElMessage.error(t('orders.deleteFailed') + ': ' + (error.message || t('dashboard.unknownError')))
}
}
}
const deleteSelected = async () => {
if (selectedOrders.value.length === 0) {
ElMessage.warning('请先选择要删除的订单')
ElMessage.warning(t('orders.pleaseSelectOrders'))
return
}
try {
await ElMessageBox.confirm(
`确定要删除选中的 ${selectedOrders.value.length} 个订单吗?`,
'批量删除',
t('orders.confirmBatchDelete', { count: selectedOrders.value.length }),
t('orders.batchDeleteTitle'),
{
confirmButtonText: '确定',
cancelButtonText: '取消',
confirmButtonText: t('common.confirm'),
cancelButtonText: t('common.cancel'),
type: 'warning',
}
)
const ids = selectedOrders.value.map(o => o.id)
const response = await deleteOrders(ids)
console.log('批量删除订单响应:', response)
console.log('Batch delete orders response:', response)
if (response.data?.success) {
orders.value = orders.value.filter(o => !ids.includes(o.id))
totalOrders.value -= response.data?.deletedCount || ids.length
selectedOrders.value = []
ElMessage.success(response.data?.message || '批量删除成功')
ElMessage.success(response.data?.message || t('orders.batchDeleteSuccess'))
} else {
ElMessage.error(response.data?.message || '批量删除失败')
ElMessage.error(response.data?.message || t('orders.batchDeleteFailed'))
}
} catch (error) {
if (error !== 'cancel') {
console.error('批量删除失败:', error)
ElMessage.error('批量删除失败: ' + (error.message || '未知错误'))
console.error('Batch delete failed:', error)
ElMessage.error(t('orders.batchDeleteFailed') + ': ' + (error.message || t('dashboard.unknownError')))
}
}
}
@@ -615,8 +613,8 @@ const fetchOrders = async () => {
orders.value = pageData
totalOrders.value = pageData.length
} else {
console.error('API返回数据格式错误: data不是Page对象也不是数组', pageData)
ElMessage.error('API返回数据格式错误')
console.error('API data format error: data is not Page object or array', pageData)
ElMessage.error(t('orders.apiDataFormatError'))
}
} else if (responseData.content) {
// 直接返回Page对象没有success包装
@@ -627,13 +625,13 @@ const fetchOrders = async () => {
orders.value = responseData.list || []
totalOrders.value = responseData.total || 0
} else {
console.error('API返回数据格式错误:', responseData)
ElMessage.error('API返回数据格式错误')
console.error('API data format error:', responseData)
ElMessage.error(t('orders.apiDataFormatError'))
}
} catch (error) {
console.error('获取订单列表失败:', error)
ElMessage.error('获取订单列表失败: ' + (error.message || '未知错误'))
console.error('Get orders list failed:', error)
ElMessage.error(t('orders.loadOrdersFailed') + ': ' + (error.message || t('dashboard.unknownError')))
} finally {
loading.value = false
}
@@ -651,22 +649,26 @@ onMounted(() => {
fetchSystemStats()
})
// 获取系统统计数据
// 获取系统统计数据(当天访问人数和系统运行时间)
const fetchSystemStats = async () => {
try {
// 临时使用计算值后续可以从API获取
// 计算在线用户数(这里简化处理)
const randomOnline = Math.floor(Math.random() * 50) + 10
onlineUsers.value = `${randomOnline}/500`
// 计算系统运行时间(基于当前时间简单模拟)
const hours = new Date().getHours()
const minutes = new Date().getMinutes()
systemUptime.value = `${hours}小时${minutes}`
const response = await fetch('/api/admin/online-stats', {
headers: {
'Authorization': `Bearer ${sessionStorage.getItem('token')}`
}
})
const data = await response.json()
if (data.success) {
onlineUsers.value = data.todayVisitors || 0
systemUptime.value = data.uptime || t('systemSettings.unknown')
} else {
onlineUsers.value = '0'
systemUptime.value = t('systemSettings.unknown')
}
} catch (error) {
console.error('获取系统统计失败:', error)
onlineUsers.value = '0/500'
systemUptime.value = '未知'
console.error('Get online stats failed:', error)
onlineUsers.value = '0'
systemUptime.value = t('systemSettings.unknown')
}
}
</script>
@@ -899,6 +901,39 @@ const fetchSystemStats = async () => {
gap: 16px;
}
/* 确保下拉框选中值可见 */
.toolbar-left :deep(.el-select) {
min-width: 120px;
}
.toolbar-left :deep(.el-select__wrapper) {
color: #374151 !important;
font-size: 14px;
min-height: 32px;
}
.toolbar-left :deep(.el-select__wrapper *) {
color: #374151 !important;
}
.toolbar-left :deep(.el-select__selection) {
display: flex !important;
align-items: center !important;
}
.toolbar-left :deep(.el-select__selected-item) {
color: #374151 !important;
display: inline-flex !important;
visibility: visible !important;
opacity: 1 !important;
}
.toolbar-left :deep(.el-select__placeholder) {
color: #9ca3af !important;
opacity: 1 !important;
visibility: visible !important;
}
.table-container {
background: white;
border-radius: 8px;