Compare commits
10 Commits
85a625a7f1
...
a294f61f3c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a294f61f3c | ||
|
|
4bd01972d0 | ||
|
|
be1876a03c | ||
|
|
9b301f8df7 | ||
|
|
c671dd66ff | ||
|
|
39d573f03f | ||
|
|
8449423cfb | ||
|
|
c31019e013 | ||
|
|
9f167aa20f | ||
|
|
4b7604f20c |
@@ -316,3 +316,6 @@ ALTER TABLE payments ADD FOREIGN KEY (order_id_ref) REFERENCES orders(id);
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -23,3 +23,6 @@ public class PasswordChecker {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -280,3 +280,6 @@ Vue.js 前端项目迁移已经完成,实现了:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -423,3 +423,6 @@ MIT License
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -19,3 +19,6 @@ console.log('App.vue 加载成功')
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
27
demo/frontend/src/api/analytics.js
Normal file
27
demo/frontend/src/api/analytics.js
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import request from './request'
|
||||||
|
|
||||||
|
// 获取日活用户趋势数据
|
||||||
|
export const getDailyActiveUsersTrend = (year = '2024', granularity = 'monthly') => {
|
||||||
|
return request({
|
||||||
|
url: '/analytics/daily-active-users',
|
||||||
|
method: 'get',
|
||||||
|
params: { year, granularity }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取用户活跃度概览
|
||||||
|
export const getUserActivityOverview = () => {
|
||||||
|
return request({
|
||||||
|
url: '/analytics/user-activity-overview',
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取用户活跃度热力图数据
|
||||||
|
export const getUserActivityHeatmap = (year = '2024') => {
|
||||||
|
return request({
|
||||||
|
url: '/analytics/user-activity-heatmap',
|
||||||
|
method: 'get',
|
||||||
|
params: { year }
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -1,38 +1,43 @@
|
|||||||
import request from './request'
|
import request from './request'
|
||||||
|
|
||||||
export const dashboardApi = {
|
|
||||||
// 获取仪表盘概览数据
|
// 获取仪表盘概览数据
|
||||||
getOverview() {
|
export const getDashboardOverview = () => {
|
||||||
return request.get('/dashboard/overview')
|
return request({
|
||||||
},
|
url: '/dashboard/overview',
|
||||||
|
method: 'get'
|
||||||
// 获取日活数据
|
})
|
||||||
getDailyActiveUsers() {
|
|
||||||
return request.get('/dashboard/daily-active-users')
|
|
||||||
},
|
|
||||||
|
|
||||||
// 获取收入趋势数据
|
|
||||||
getRevenueTrend() {
|
|
||||||
return request.get('/dashboard/revenue-trend')
|
|
||||||
},
|
|
||||||
|
|
||||||
// 获取订单状态分布
|
|
||||||
getOrderStatusDistribution() {
|
|
||||||
return request.get('/dashboard/order-status-distribution')
|
|
||||||
},
|
|
||||||
|
|
||||||
// 获取支付方式分布
|
|
||||||
getPaymentMethodDistribution() {
|
|
||||||
return request.get('/dashboard/payment-method-distribution')
|
|
||||||
},
|
|
||||||
|
|
||||||
// 获取最近订单列表
|
|
||||||
getRecentOrders() {
|
|
||||||
return request.get('/dashboard/recent-orders')
|
|
||||||
},
|
|
||||||
|
|
||||||
// 获取所有仪表盘数据
|
|
||||||
getAllData() {
|
|
||||||
return request.get('/dashboard/all')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取月度收入趋势数据
|
||||||
|
export const getMonthlyRevenue = (year = '2024') => {
|
||||||
|
return request({
|
||||||
|
url: '/dashboard/monthly-revenue',
|
||||||
|
method: 'get',
|
||||||
|
params: { year }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取用户转化率数据
|
||||||
|
export const getConversionRate = () => {
|
||||||
|
return request({
|
||||||
|
url: '/dashboard/conversion-rate',
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取最近订单数据
|
||||||
|
export const getRecentOrders = (limit = 10) => {
|
||||||
|
return request({
|
||||||
|
url: '/dashboard/recent-orders',
|
||||||
|
method: 'get',
|
||||||
|
params: { limit }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取系统状态
|
||||||
|
export const getSystemStatus = () => {
|
||||||
|
return request({
|
||||||
|
url: '/dashboard/system-status',
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
}
|
}
|
||||||
44
demo/frontend/src/api/members.js
Normal file
44
demo/frontend/src/api/members.js
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import request from './request'
|
||||||
|
|
||||||
|
// 获取会员列表
|
||||||
|
export const getMembers = (params) => {
|
||||||
|
return request({
|
||||||
|
url: '/members',
|
||||||
|
method: 'get',
|
||||||
|
params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新会员信息
|
||||||
|
export const updateMember = (id, data) => {
|
||||||
|
return request({
|
||||||
|
url: `/members/${id}`,
|
||||||
|
method: 'put',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除会员
|
||||||
|
export const deleteMember = (id) => {
|
||||||
|
return request({
|
||||||
|
url: `/members/${id}`,
|
||||||
|
method: 'delete'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 批量删除会员
|
||||||
|
export const deleteMembers = (ids) => {
|
||||||
|
return request({
|
||||||
|
url: '/members/batch',
|
||||||
|
method: 'delete',
|
||||||
|
data: { ids }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取会员详情
|
||||||
|
export const getMemberDetail = (id) => {
|
||||||
|
return request({
|
||||||
|
url: `/members/${id}`,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -52,11 +52,12 @@ export const getOrderStats = () => {
|
|||||||
return api.get('/orders/stats')
|
return api.get('/orders/stats')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 批量删除订单
|
||||||
|
export const deleteOrders = (orderIds) => {
|
||||||
|
return api.delete('/orders/batch', { data: orderIds })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除单个订单
|
||||||
|
export const deleteOrder = (id) => {
|
||||||
|
return api.delete(`/orders/${id}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
398
demo/frontend/src/components/DailyActiveUsersChart.vue
Normal file
398
demo/frontend/src/components/DailyActiveUsersChart.vue
Normal file
@@ -0,0 +1,398 @@
|
|||||||
|
<template>
|
||||||
|
<div class="daily-active-users-chart">
|
||||||
|
<div class="chart-header">
|
||||||
|
<h3 class="chart-title">日活用户趋势</h3>
|
||||||
|
<div class="chart-controls">
|
||||||
|
<el-select v-model="selectedYear" @change="loadChartData" placeholder="选择年份">
|
||||||
|
<el-option
|
||||||
|
v-for="year in availableYears"
|
||||||
|
:key="year"
|
||||||
|
:label="`${year}年`"
|
||||||
|
:value="year">
|
||||||
|
</el-option>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="chart-container" ref="chartContainer"></div>
|
||||||
|
|
||||||
|
<div class="chart-footer">
|
||||||
|
<div class="chart-stats">
|
||||||
|
<div class="stat-item">
|
||||||
|
<span class="stat-label">今日日活:</span>
|
||||||
|
<span class="stat-value">{{ formatNumber(todayDAU) }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="stat-item">
|
||||||
|
<span class="stat-label">日增长率:</span>
|
||||||
|
<span class="stat-value" :class="dayGrowthRate >= 0 ? 'positive' : 'negative'">
|
||||||
|
{{ dayGrowthRate >= 0 ? '+' : '' }}{{ dayGrowthRate.toFixed(1) }}%
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="stat-item">
|
||||||
|
<span class="stat-label">月均日活:</span>
|
||||||
|
<span class="stat-value">{{ formatNumber(monthlyAvgDAU) }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="stat-item">
|
||||||
|
<span class="stat-label">月增长率:</span>
|
||||||
|
<span class="stat-value" :class="monthGrowthRate >= 0 ? 'positive' : 'negative'">
|
||||||
|
{{ monthGrowthRate >= 0 ? '+' : '' }}{{ monthGrowthRate.toFixed(1) }}%
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, onMounted, onUnmounted, nextTick } from 'vue'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import * as analyticsAPI from '@/api/analytics'
|
||||||
|
|
||||||
|
// 响应式数据
|
||||||
|
const chartContainer = ref(null)
|
||||||
|
const selectedYear = ref(2024)
|
||||||
|
const availableYears = ref([2023, 2024, 2025])
|
||||||
|
const chartInstance = ref(null)
|
||||||
|
|
||||||
|
// 统计数据
|
||||||
|
const todayDAU = ref(0)
|
||||||
|
const dayGrowthRate = ref(0)
|
||||||
|
const monthlyAvgDAU = ref(0)
|
||||||
|
const monthGrowthRate = ref(0)
|
||||||
|
|
||||||
|
// 动态加载ECharts
|
||||||
|
const loadECharts = () => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (window.echarts) {
|
||||||
|
resolve(window.echarts)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const script = document.createElement('script')
|
||||||
|
script.src = 'https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js'
|
||||||
|
script.onload = () => resolve(window.echarts)
|
||||||
|
script.onerror = reject
|
||||||
|
document.head.appendChild(script)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加载图表数据
|
||||||
|
const loadChartData = async () => {
|
||||||
|
try {
|
||||||
|
// 并行加载图表数据和概览数据
|
||||||
|
const [chartRes, overviewRes] = await Promise.all([
|
||||||
|
analyticsAPI.getDailyActiveUsersTrend(selectedYear.value, 'monthly'),
|
||||||
|
analyticsAPI.getUserActivityOverview()
|
||||||
|
])
|
||||||
|
|
||||||
|
// 处理图表数据
|
||||||
|
if (chartRes.data && chartRes.data.monthlyData) {
|
||||||
|
await nextTick()
|
||||||
|
initChart(chartRes.data.monthlyData)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理概览数据
|
||||||
|
if (overviewRes.data) {
|
||||||
|
todayDAU.value = overviewRes.data.todayDAU || 0
|
||||||
|
dayGrowthRate.value = overviewRes.data.dayGrowthRate || 0
|
||||||
|
monthlyAvgDAU.value = overviewRes.data.monthlyAvgDAU || 0
|
||||||
|
monthGrowthRate.value = overviewRes.data.monthGrowthRate || 0
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('加载图表数据失败:', error)
|
||||||
|
ElMessage.error('加载图表数据失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化图表
|
||||||
|
const initChart = async (data) => {
|
||||||
|
try {
|
||||||
|
const echarts = await loadECharts()
|
||||||
|
|
||||||
|
if (!chartContainer.value) return
|
||||||
|
|
||||||
|
// 销毁现有图表实例
|
||||||
|
if (chartInstance.value) {
|
||||||
|
chartInstance.value.dispose()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建新图表实例
|
||||||
|
chartInstance.value = echarts.init(chartContainer.value)
|
||||||
|
|
||||||
|
// 准备数据
|
||||||
|
const months = ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月']
|
||||||
|
const values = data.map(item => item.avgDailyActive || 0)
|
||||||
|
const maxValues = data.map(item => item.maxDailyActive || 0)
|
||||||
|
const minValues = data.map(item => item.minDailyActive || 0)
|
||||||
|
|
||||||
|
// 图表配置
|
||||||
|
const option = {
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
backgroundColor: 'rgba(0, 0, 0, 0.8)',
|
||||||
|
borderColor: 'rgba(255, 255, 255, 0.1)',
|
||||||
|
borderWidth: 1,
|
||||||
|
textStyle: {
|
||||||
|
color: '#fff',
|
||||||
|
fontSize: 12
|
||||||
|
},
|
||||||
|
formatter: function(params) {
|
||||||
|
const dataIndex = params[0].dataIndex
|
||||||
|
const month = months[dataIndex]
|
||||||
|
const avgValue = values[dataIndex]
|
||||||
|
const maxValue = maxValues[dataIndex]
|
||||||
|
const minValue = minValues[dataIndex]
|
||||||
|
|
||||||
|
return `${month}<br/>
|
||||||
|
平均日活: ${formatNumber(avgValue)}<br/>
|
||||||
|
最高日活: ${formatNumber(maxValue)}<br/>
|
||||||
|
最低日活: ${formatNumber(minValue)}`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
left: '3%',
|
||||||
|
right: '4%',
|
||||||
|
bottom: '3%',
|
||||||
|
top: '10%',
|
||||||
|
containLabel: true
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
data: months,
|
||||||
|
axisLine: {
|
||||||
|
lineStyle: {
|
||||||
|
color: '#e0e0e0'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
axisTick: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
axisLabel: {
|
||||||
|
color: '#666',
|
||||||
|
fontSize: 12
|
||||||
|
}
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
type: 'value',
|
||||||
|
axisLine: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
axisTick: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
axisLabel: {
|
||||||
|
color: '#666',
|
||||||
|
fontSize: 12,
|
||||||
|
formatter: function(value) {
|
||||||
|
return formatNumber(value)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
splitLine: {
|
||||||
|
lineStyle: {
|
||||||
|
color: '#f0f0f0',
|
||||||
|
type: 'dashed'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: '日活用户',
|
||||||
|
type: 'line',
|
||||||
|
data: values,
|
||||||
|
smooth: true,
|
||||||
|
symbol: 'circle',
|
||||||
|
symbolSize: 6,
|
||||||
|
lineStyle: {
|
||||||
|
color: '#3b82f6',
|
||||||
|
width: 3
|
||||||
|
},
|
||||||
|
itemStyle: {
|
||||||
|
color: '#3b82f6',
|
||||||
|
borderColor: '#fff',
|
||||||
|
borderWidth: 2
|
||||||
|
},
|
||||||
|
areaStyle: {
|
||||||
|
color: {
|
||||||
|
type: 'linear',
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
x2: 0,
|
||||||
|
y2: 1,
|
||||||
|
colorStops: [
|
||||||
|
{
|
||||||
|
offset: 0,
|
||||||
|
color: 'rgba(59, 130, 246, 0.3)'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
offset: 1,
|
||||||
|
color: 'rgba(59, 130, 246, 0.05)'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emphasis: {
|
||||||
|
focus: 'series',
|
||||||
|
itemStyle: {
|
||||||
|
color: '#1d4ed8',
|
||||||
|
borderColor: '#fff',
|
||||||
|
borderWidth: 3,
|
||||||
|
shadowBlur: 10,
|
||||||
|
shadowColor: 'rgba(59, 130, 246, 0.5)'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
animation: true,
|
||||||
|
animationDuration: 1000,
|
||||||
|
animationEasing: 'cubicOut'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置图表配置
|
||||||
|
chartInstance.value.setOption(option)
|
||||||
|
|
||||||
|
// 响应式调整
|
||||||
|
window.addEventListener('resize', handleResize)
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('初始化图表失败:', error)
|
||||||
|
ElMessage.error('图表初始化失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理窗口大小变化
|
||||||
|
const handleResize = () => {
|
||||||
|
if (chartInstance.value) {
|
||||||
|
chartInstance.value.resize()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 格式化数字
|
||||||
|
const formatNumber = (num) => {
|
||||||
|
if (num >= 10000) {
|
||||||
|
return (num / 10000).toFixed(1) + '万'
|
||||||
|
}
|
||||||
|
return Math.round(num).toLocaleString()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 组件挂载时加载数据
|
||||||
|
onMounted(() => {
|
||||||
|
loadChartData()
|
||||||
|
})
|
||||||
|
|
||||||
|
// 组件卸载时清理
|
||||||
|
onUnmounted(() => {
|
||||||
|
if (chartInstance.value) {
|
||||||
|
chartInstance.value.dispose()
|
||||||
|
chartInstance.value = null
|
||||||
|
}
|
||||||
|
window.removeEventListener('resize', handleResize)
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.daily-active-users-chart {
|
||||||
|
background: white;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 24px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-title {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1f2937;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-controls {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 300px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-footer {
|
||||||
|
border-top: 1px solid #f3f4f6;
|
||||||
|
padding-top: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-stats {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
padding: 12px;
|
||||||
|
background: #f9fafb;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-label {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #6b7280;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-value {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1f2937;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-value.positive {
|
||||||
|
color: #059669;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-value.negative {
|
||||||
|
color: #dc2626;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 响应式设计 */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.chart-header {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-container {
|
||||||
|
height: 250px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-stats {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
.daily-active-users-chart {
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-container {
|
||||||
|
height: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-stats {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -82,3 +82,6 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import ImageToVideo from '@/views/ImageToVideo.vue'
|
|||||||
import ImageToVideoCreate from '@/views/ImageToVideoCreate.vue'
|
import ImageToVideoCreate from '@/views/ImageToVideoCreate.vue'
|
||||||
import StoryboardVideo from '@/views/StoryboardVideo.vue'
|
import StoryboardVideo from '@/views/StoryboardVideo.vue'
|
||||||
import StoryboardVideoCreate from '@/views/StoryboardVideoCreate.vue'
|
import StoryboardVideoCreate from '@/views/StoryboardVideoCreate.vue'
|
||||||
|
import MemberManagement from '@/views/MemberManagement.vue'
|
||||||
|
|
||||||
const routes = [
|
const routes = [
|
||||||
{
|
{
|
||||||
@@ -162,6 +163,12 @@ const routes = [
|
|||||||
name: 'AdminDashboard',
|
name: 'AdminDashboard',
|
||||||
component: AdminDashboard,
|
component: AdminDashboard,
|
||||||
meta: { title: '后台管理', requiresAuth: true, requiresAdmin: true }
|
meta: { title: '后台管理', requiresAuth: true, requiresAdmin: true }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/member-management',
|
||||||
|
name: 'MemberManagement',
|
||||||
|
component: MemberManagement,
|
||||||
|
meta: { title: '会员管理', requiresAuth: true, requiresAdmin: true }
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -109,7 +109,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { ref, onMounted, nextTick } from 'vue'
|
import { ref, onMounted, nextTick } from 'vue'
|
||||||
import { dashboardApi } from '@/api/dashboard'
|
import * as dashboardAPI from '@/api/dashboard'
|
||||||
|
|
||||||
// 动态加载ECharts
|
// 动态加载ECharts
|
||||||
const loadECharts = () => {
|
const loadECharts = () => {
|
||||||
@@ -145,19 +145,24 @@ export default {
|
|||||||
// 加载仪表盘数据
|
// 加载仪表盘数据
|
||||||
const loadDashboardData = async () => {
|
const loadDashboardData = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await dashboardApi.getAllData()
|
const [overviewRes, monthlyRes, conversionRes, ordersRes] = await Promise.all([
|
||||||
const data = response.data
|
dashboardAPI.getDashboardOverview(),
|
||||||
|
dashboardAPI.getMonthlyRevenue(),
|
||||||
|
dashboardAPI.getConversionRate(),
|
||||||
|
dashboardAPI.getRecentOrders()
|
||||||
|
])
|
||||||
|
|
||||||
overviewData.value = data.overview
|
overviewData.value = overviewRes.data || {}
|
||||||
dailyActiveData.value = data.dailyActiveUsers.dailyData || []
|
revenueData.value = monthlyRes.data?.monthlyData || []
|
||||||
revenueData.value = data.revenueTrend.revenueData || []
|
recentOrders.value = ordersRes.data?.recentOrders || []
|
||||||
orderStatusData.value = data.orderStatusDistribution.statusData || []
|
|
||||||
paymentMethodData.value = data.paymentMethodDistribution.methodData || []
|
// 计算转化率
|
||||||
recentOrders.value = data.recentOrders.orders || []
|
if (conversionRes.data) {
|
||||||
|
overviewData.value.conversionRate = conversionRes.data.conversionRate || 0
|
||||||
|
}
|
||||||
|
|
||||||
// 等待DOM更新后初始化图表
|
|
||||||
await nextTick()
|
await nextTick()
|
||||||
await initCharts()
|
initCharts()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('加载仪表盘数据失败:', error)
|
console.error('加载仪表盘数据失败:', error)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,10 +34,10 @@
|
|||||||
</nav>
|
</nav>
|
||||||
<div class="sidebar-footer">
|
<div class="sidebar-footer">
|
||||||
<div class="online-users">
|
<div class="online-users">
|
||||||
当前在线用户: <span class="highlight">87/500</span>
|
当前在线用户: <span class="highlight">{{ systemStatus.onlineUsers }}/500</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="system-uptime">
|
<div class="system-uptime">
|
||||||
系统运行时间: <span class="highlight">48小时32分</span>
|
系统运行时间: <span class="highlight">{{ systemStatus.systemUptime }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</aside>
|
</aside>
|
||||||
@@ -67,7 +67,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="kpi-content">
|
<div class="kpi-content">
|
||||||
<div class="kpi-title">用户总数</div>
|
<div class="kpi-title">用户总数</div>
|
||||||
<div class="kpi-value">12,847</div>
|
<div class="kpi-value">{{ formatNumber(dashboardData.totalUsers) }}</div>
|
||||||
<div class="kpi-trend positive">+12% 较上月同期</div>
|
<div class="kpi-trend positive">+12% 较上月同期</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -79,7 +79,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="kpi-content">
|
<div class="kpi-content">
|
||||||
<div class="kpi-title">付费用户数</div>
|
<div class="kpi-title">付费用户数</div>
|
||||||
<div class="kpi-value">3,215</div>
|
<div class="kpi-value">{{ formatNumber(dashboardData.paidUsers) }}</div>
|
||||||
<div class="kpi-trend negative">-5% 较上月同期</div>
|
<div class="kpi-trend negative">-5% 较上月同期</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -90,7 +90,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="kpi-content">
|
<div class="kpi-content">
|
||||||
<div class="kpi-title">今日收入</div>
|
<div class="kpi-title">今日收入</div>
|
||||||
<div class="kpi-value">¥28,450</div>
|
<div class="kpi-value">{{ formatCurrency(dashboardData.todayRevenue) }}</div>
|
||||||
<div class="kpi-trend positive">+15% 较上月同期</div>
|
<div class="kpi-trend positive">+15% 较上月同期</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -235,28 +235,40 @@ import { ref, onMounted, computed } from 'vue'
|
|||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { useUserStore } from '@/stores/user'
|
import { useUserStore } from '@/stores/user'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
|
import * as dashboardAPI from '@/api/dashboard'
|
||||||
|
import DailyActiveUsersChart from '@/components/DailyActiveUsersChart.vue'
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
|
|
||||||
// 模拟数据 - 实际项目中应该从API获取
|
// 数据状态
|
||||||
const monthlyData = ref([
|
const dashboardData = ref({
|
||||||
{ month: 1, value: 1200, label: '1月' },
|
totalUsers: 0,
|
||||||
{ month: 2, value: 1100, label: '2月' },
|
paidUsers: 0,
|
||||||
{ month: 3, value: 1000, label: '3月' },
|
todayRevenue: 0,
|
||||||
{ month: 4, value: 900, label: '4月' },
|
totalOrders: 0,
|
||||||
{ month: 5, value: 800, label: '5月' },
|
totalRevenue: 0,
|
||||||
{ month: 6, value: 1000, label: '6月' },
|
monthRevenue: 0
|
||||||
{ month: 7, value: 1200, label: '7月' },
|
})
|
||||||
{ month: 8, value: 1150, label: '8月' },
|
|
||||||
{ month: 9, value: 1300, label: '9月' },
|
|
||||||
{ month: 10, value: 1250, label: '10月' },
|
|
||||||
{ month: 11, value: 1100, label: '11月' },
|
|
||||||
{ month: 12, value: 950, label: '12月' }
|
|
||||||
])
|
|
||||||
|
|
||||||
const selectedYear = ref(2025)
|
const monthlyData = ref([])
|
||||||
|
const conversionData = ref({
|
||||||
|
totalUsers: 0,
|
||||||
|
paidUsers: 0,
|
||||||
|
conversionRate: 0,
|
||||||
|
membershipStats: []
|
||||||
|
})
|
||||||
|
|
||||||
|
const systemStatus = ref({
|
||||||
|
onlineUsers: 0,
|
||||||
|
systemUptime: '0小时0分',
|
||||||
|
databaseStatus: '正常',
|
||||||
|
serviceStatus: '运行中'
|
||||||
|
})
|
||||||
|
|
||||||
|
const selectedYear = ref(2024)
|
||||||
const highlightedPoint = ref(null)
|
const highlightedPoint = ref(null)
|
||||||
|
const loading = ref(false)
|
||||||
|
|
||||||
// 计算图表尺寸和比例
|
// 计算图表尺寸和比例
|
||||||
const chartWidth = 800
|
const chartWidth = 800
|
||||||
@@ -265,18 +277,20 @@ const padding = 60
|
|||||||
|
|
||||||
// 计算数据点的SVG坐标
|
// 计算数据点的SVG坐标
|
||||||
const chartPoints = computed(() => {
|
const chartPoints = computed(() => {
|
||||||
const maxValue = Math.max(...monthlyData.value.map(d => d.value))
|
if (monthlyData.value.length === 0) return []
|
||||||
const minValue = Math.min(...monthlyData.value.map(d => d.value))
|
|
||||||
const valueRange = maxValue - minValue
|
const maxValue = Math.max(...monthlyData.value.map(d => d.revenue || 0))
|
||||||
|
const minValue = Math.min(...monthlyData.value.map(d => d.revenue || 0))
|
||||||
|
const valueRange = maxValue - minValue || 1
|
||||||
|
|
||||||
return monthlyData.value.map((data, index) => {
|
return monthlyData.value.map((data, index) => {
|
||||||
const x = padding + (index * (chartWidth - 2 * padding) / (monthlyData.value.length - 1))
|
const x = padding + (index * (chartWidth - 2 * padding) / (monthlyData.value.length - 1))
|
||||||
const y = padding + ((maxValue - data.value) / valueRange) * (chartHeight - 2 * padding)
|
const y = padding + ((maxValue - (data.revenue || 0)) / valueRange) * (chartHeight - 2 * padding)
|
||||||
return {
|
return {
|
||||||
x,
|
x,
|
||||||
y,
|
y,
|
||||||
value: data.value,
|
value: data.revenue || 0,
|
||||||
label: data.label,
|
label: `${data.month}月`,
|
||||||
month: data.month
|
month: data.month
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -319,7 +333,7 @@ const handlePointClick = (point) => {
|
|||||||
|
|
||||||
// 导航功能
|
// 导航功能
|
||||||
const goToUsers = () => {
|
const goToUsers = () => {
|
||||||
ElMessage.info('跳转到会员管理')
|
router.push('/member-management')
|
||||||
}
|
}
|
||||||
|
|
||||||
const goToOrders = () => {
|
const goToOrders = () => {
|
||||||
@@ -343,27 +357,118 @@ const goToSettings = () => {
|
|||||||
ElMessage.info('跳转到系统设置')
|
ElMessage.info('跳转到系统设置')
|
||||||
}
|
}
|
||||||
|
|
||||||
// 模拟数据加载
|
// 加载仪表盘数据
|
||||||
const loadChartData = async () => {
|
const loadDashboardData = async () => {
|
||||||
try {
|
try {
|
||||||
// 这里应该调用真实的API
|
loading.value = true
|
||||||
// const response = await fetch('/api/dashboard/monthly-active-users')
|
|
||||||
// const data = await response.json()
|
|
||||||
// monthlyData.value = data
|
|
||||||
|
|
||||||
// 模拟API延迟
|
// 并行加载所有数据
|
||||||
await new Promise(resolve => setTimeout(resolve, 500))
|
const [overviewRes, monthlyRes, conversionRes, statusRes] = await Promise.all([
|
||||||
|
dashboardAPI.getDashboardOverview(),
|
||||||
|
dashboardAPI.getMonthlyRevenue(selectedYear.value),
|
||||||
|
dashboardAPI.getConversionRate(),
|
||||||
|
dashboardAPI.getSystemStatus()
|
||||||
|
])
|
||||||
|
|
||||||
// 可以在这里更新数据
|
// 处理概览数据
|
||||||
console.log('图表数据加载完成')
|
if (overviewRes.data) {
|
||||||
} catch (error) {
|
dashboardData.value = {
|
||||||
console.error('加载图表数据失败:', error)
|
totalUsers: overviewRes.data.totalUsers || 0,
|
||||||
ElMessage.error('加载数据失败')
|
paidUsers: overviewRes.data.paidUsers || 0,
|
||||||
|
todayRevenue: overviewRes.data.todayRevenue || 0,
|
||||||
|
totalOrders: overviewRes.data.totalOrders || 0,
|
||||||
|
totalRevenue: overviewRes.data.totalRevenue || 0,
|
||||||
|
monthRevenue: overviewRes.data.monthRevenue || 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 处理月度数据
|
||||||
|
if (monthlyRes.data && monthlyRes.data.monthlyData) {
|
||||||
|
monthlyData.value = monthlyRes.data.monthlyData
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理转化率数据
|
||||||
|
if (conversionRes.data) {
|
||||||
|
conversionData.value = {
|
||||||
|
totalUsers: conversionRes.data.totalUsers || 0,
|
||||||
|
paidUsers: conversionRes.data.paidUsers || 0,
|
||||||
|
conversionRate: conversionRes.data.conversionRate || 0,
|
||||||
|
membershipStats: conversionRes.data.membershipStats || []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理系统状态
|
||||||
|
if (statusRes.data) {
|
||||||
|
systemStatus.value = {
|
||||||
|
onlineUsers: statusRes.data.onlineUsers || 0,
|
||||||
|
systemUptime: statusRes.data.systemUptime || '0小时0分',
|
||||||
|
databaseStatus: statusRes.data.databaseStatus || '正常',
|
||||||
|
serviceStatus: statusRes.data.serviceStatus || '运行中'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('加载仪表盘数据失败:', error)
|
||||||
|
ElMessage.error('加载仪表盘数据失败')
|
||||||
|
|
||||||
|
// 使用默认数据作为后备
|
||||||
|
dashboardData.value = {
|
||||||
|
totalUsers: 10,
|
||||||
|
paidUsers: 8,
|
||||||
|
todayRevenue: 0,
|
||||||
|
totalOrders: 180,
|
||||||
|
totalRevenue: 0,
|
||||||
|
monthRevenue: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
monthlyData.value = [
|
||||||
|
{ month: 1, revenue: 0, orderCount: 0 },
|
||||||
|
{ month: 2, revenue: 0, orderCount: 0 },
|
||||||
|
{ month: 3, revenue: 0, orderCount: 0 },
|
||||||
|
{ month: 4, revenue: 0, orderCount: 0 },
|
||||||
|
{ month: 5, revenue: 0, orderCount: 0 },
|
||||||
|
{ month: 6, revenue: 0, orderCount: 0 },
|
||||||
|
{ month: 7, revenue: 0, orderCount: 0 },
|
||||||
|
{ month: 8, revenue: 0, orderCount: 0 },
|
||||||
|
{ month: 9, revenue: 0, orderCount: 0 },
|
||||||
|
{ month: 10, revenue: 0, orderCount: 0 },
|
||||||
|
{ month: 11, revenue: 0, orderCount: 0 },
|
||||||
|
{ month: 12, revenue: 0, orderCount: 0 }
|
||||||
|
]
|
||||||
|
|
||||||
|
conversionData.value = {
|
||||||
|
totalUsers: 10,
|
||||||
|
paidUsers: 8,
|
||||||
|
conversionRate: 80,
|
||||||
|
membershipStats: []
|
||||||
|
}
|
||||||
|
|
||||||
|
systemStatus.value = {
|
||||||
|
onlineUsers: 50,
|
||||||
|
systemUptime: '48小时32分',
|
||||||
|
databaseStatus: '正常',
|
||||||
|
serviceStatus: '运行中'
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 格式化数字
|
||||||
|
const formatNumber = (num) => {
|
||||||
|
if (num >= 10000) {
|
||||||
|
return (num / 10000).toFixed(1) + '万'
|
||||||
|
}
|
||||||
|
return num.toLocaleString()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 格式化金额
|
||||||
|
const formatCurrency = (amount) => {
|
||||||
|
return '¥' + amount.toLocaleString()
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
loadChartData()
|
loadDashboardData()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -779,3 +779,6 @@ const startGenerate = () => {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
898
demo/frontend/src/views/MemberManagement.vue
Normal file
898
demo/frontend/src/views/MemberManagement.vue
Normal file
@@ -0,0 +1,898 @@
|
|||||||
|
<template>
|
||||||
|
<div class="member-management">
|
||||||
|
<!-- 左侧导航栏 -->
|
||||||
|
<aside class="sidebar">
|
||||||
|
<div class="logo">
|
||||||
|
<div class="logo-icon"></div>
|
||||||
|
<span>LOGO</span>
|
||||||
|
</div>
|
||||||
|
<nav class="nav-menu">
|
||||||
|
<div class="nav-item" @click="goToDashboard">
|
||||||
|
<el-icon><Grid /></el-icon>
|
||||||
|
<span>数据仪表台</span>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item active">
|
||||||
|
<el-icon><User /></el-icon>
|
||||||
|
<span>会员管理</span>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item" @click="goToOrders">
|
||||||
|
<el-icon><ShoppingCart /></el-icon>
|
||||||
|
<span>订单管理</span>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item" @click="goToAPI">
|
||||||
|
<el-icon><Code /></el-icon>
|
||||||
|
<span>API管理</span>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item" @click="goToTasks">
|
||||||
|
<el-icon><Document /></el-icon>
|
||||||
|
<span>生成任务记录</span>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item" @click="goToSettings">
|
||||||
|
<el-icon><Setting /></el-icon>
|
||||||
|
<span>系统设置</span>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
<div class="sidebar-footer">
|
||||||
|
<div class="online-users">
|
||||||
|
当前在线用户: <span class="highlight">87/500</span>
|
||||||
|
</div>
|
||||||
|
<div class="system-uptime">
|
||||||
|
系统运行时间: <span class="highlight">48小时32分</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
<!-- 主内容区域 -->
|
||||||
|
<main class="main-content">
|
||||||
|
<!-- 顶部搜索栏 -->
|
||||||
|
<header class="top-header">
|
||||||
|
<div class="search-bar">
|
||||||
|
<el-icon class="search-icon"><Search /></el-icon>
|
||||||
|
<input type="text" placeholder="搜索你的想要的内容" class="search-input" />
|
||||||
|
</div>
|
||||||
|
<div class="header-actions">
|
||||||
|
<el-icon class="notification-icon"><Bell /></el-icon>
|
||||||
|
<el-icon class="help-icon"><QuestionFilled /></el-icon>
|
||||||
|
<div class="user-avatar">
|
||||||
|
<img src="/images/backgrounds/welcome.jpg" alt="用户头像" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<!-- 会员列表内容 -->
|
||||||
|
<section class="member-content">
|
||||||
|
<div class="content-header">
|
||||||
|
<h2>会员列表</h2>
|
||||||
|
<div class="selection-info" v-if="selectedMembers.length > 0">
|
||||||
|
已选择{{ selectedMembers.length }}项
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="table-toolbar">
|
||||||
|
<div class="toolbar-left">
|
||||||
|
<el-select v-model="selectedLevel" placeholder="全部等级" size="small" @change="handleLevelChange">
|
||||||
|
<el-option label="全部等级" value="all" />
|
||||||
|
<el-option label="专业会员" value="professional" />
|
||||||
|
<el-option label="标准会员" value="standard" />
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
<div class="toolbar-right">
|
||||||
|
<el-button type="danger" size="small" @click="deleteSelected" :disabled="selectedMembers.length === 0">
|
||||||
|
<el-icon><Delete /></el-icon>
|
||||||
|
删除
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="table-container">
|
||||||
|
<table class="member-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="checkbox-col">
|
||||||
|
<input type="checkbox" @change="toggleAllSelection" :checked="isAllSelected" />
|
||||||
|
</th>
|
||||||
|
<th>用户ID</th>
|
||||||
|
<th>用户名</th>
|
||||||
|
<th>会员等级</th>
|
||||||
|
<th>剩余资源点</th>
|
||||||
|
<th>到期时间</th>
|
||||||
|
<th>编辑</th>
|
||||||
|
<th>删除</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr v-for="member in memberList" :key="member.id" class="table-row">
|
||||||
|
<td class="checkbox-col">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
:checked="selectedMembers.some(m => m.id === member.id)"
|
||||||
|
@change="toggleMemberSelection(member)" />
|
||||||
|
</td>
|
||||||
|
<td>{{ member.id }}</td>
|
||||||
|
<td>{{ member.username }}</td>
|
||||||
|
<td>
|
||||||
|
<span class="level-tag" :class="member.level === '专业会员' ? 'professional' : 'standard'">
|
||||||
|
{{ member.level }}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>{{ member.points.toLocaleString() }}</td>
|
||||||
|
<td>{{ member.expiryDate }}</td>
|
||||||
|
<td>
|
||||||
|
<button class="action-btn edit-btn" @click="editMember(member)">编辑</button>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button class="action-btn delete-btn" @click="deleteMember(member)">删除</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 分页 -->
|
||||||
|
<div class="pagination-container">
|
||||||
|
<div class="pagination">
|
||||||
|
<button class="page-btn" @click="prevPage" :disabled="currentPage === 1">‹</button>
|
||||||
|
<button
|
||||||
|
v-for="page in visiblePages"
|
||||||
|
:key="page"
|
||||||
|
class="page-btn"
|
||||||
|
:class="{ active: page === currentPage }"
|
||||||
|
@click="goToPage(page)">
|
||||||
|
{{ page }}
|
||||||
|
</button>
|
||||||
|
<button class="page-btn" @click="nextPage" :disabled="currentPage === totalPages">›</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<!-- 编辑会员对话框 -->
|
||||||
|
<el-dialog
|
||||||
|
v-model="editDialogVisible"
|
||||||
|
title="编辑会员信息"
|
||||||
|
width="500px"
|
||||||
|
:before-close="handleCloseEditDialog">
|
||||||
|
<el-form
|
||||||
|
ref="editFormRef"
|
||||||
|
:model="editForm"
|
||||||
|
:rules="editRules"
|
||||||
|
label-width="100px">
|
||||||
|
<el-form-item label="用户ID" prop="id">
|
||||||
|
<el-input v-model="editForm.id" disabled />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="用户名" prop="username">
|
||||||
|
<el-input v-model="editForm.username" placeholder="请输入用户名" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="会员等级" prop="level">
|
||||||
|
<el-select v-model="editForm.level" placeholder="请选择会员等级">
|
||||||
|
<el-option label="专业会员" value="专业会员" />
|
||||||
|
<el-option label="标准会员" value="标准会员" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="剩余资源点" prop="points">
|
||||||
|
<el-input-number
|
||||||
|
v-model="editForm.points"
|
||||||
|
:min="0"
|
||||||
|
:max="99999"
|
||||||
|
placeholder="请输入资源点" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="到期时间" prop="expiryDate">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="editForm.expiryDate"
|
||||||
|
type="date"
|
||||||
|
placeholder="选择到期时间"
|
||||||
|
format="YYYY-MM-DD"
|
||||||
|
value-format="YYYY-MM-DD" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button @click="editDialogVisible = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="saveEdit" :loading="saveLoading">保存</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, onMounted, computed } from 'vue'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
|
import * as memberAPI from '@/api/members'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
// 数据状态
|
||||||
|
const selectedMembers = ref([])
|
||||||
|
const selectedLevel = ref('all')
|
||||||
|
const currentPage = ref(1)
|
||||||
|
const pageSize = ref(10)
|
||||||
|
const totalMembers = ref(50)
|
||||||
|
|
||||||
|
// 编辑相关状态
|
||||||
|
const editDialogVisible = ref(false)
|
||||||
|
const editFormRef = ref()
|
||||||
|
const saveLoading = ref(false)
|
||||||
|
const editForm = ref({
|
||||||
|
id: '',
|
||||||
|
username: '',
|
||||||
|
level: '',
|
||||||
|
points: 0,
|
||||||
|
expiryDate: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
// 表单验证规则
|
||||||
|
const editRules = {
|
||||||
|
username: [
|
||||||
|
{ required: true, message: '请输入用户名', trigger: 'blur' },
|
||||||
|
{ min: 2, max: 20, message: '用户名长度在 2 到 20 个字符', trigger: 'blur' }
|
||||||
|
],
|
||||||
|
level: [
|
||||||
|
{ required: true, message: '请选择会员等级', trigger: 'change' }
|
||||||
|
],
|
||||||
|
points: [
|
||||||
|
{ required: true, message: '请输入资源点', trigger: 'blur' },
|
||||||
|
{ type: 'number', min: 0, message: '资源点不能小于0', trigger: 'blur' }
|
||||||
|
],
|
||||||
|
expiryDate: [
|
||||||
|
{ required: true, message: '请选择到期时间', trigger: 'change' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
// 模拟会员数据 - 将在API集成后移除
|
||||||
|
const memberList = ref([])
|
||||||
|
|
||||||
|
// 导航功能
|
||||||
|
const goToDashboard = () => {
|
||||||
|
router.push('/')
|
||||||
|
}
|
||||||
|
|
||||||
|
const goToOrders = () => {
|
||||||
|
router.push('/orders')
|
||||||
|
}
|
||||||
|
|
||||||
|
const goToAPI = () => {
|
||||||
|
ElMessage.info('跳转到API管理')
|
||||||
|
}
|
||||||
|
|
||||||
|
const goToTasks = () => {
|
||||||
|
ElMessage.info('跳转到生成任务记录')
|
||||||
|
}
|
||||||
|
|
||||||
|
const goToSettings = () => {
|
||||||
|
ElMessage.info('跳转到系统设置')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 表格操作
|
||||||
|
const isAllSelected = computed(() => {
|
||||||
|
return memberList.value.length > 0 && selectedMembers.value.length === memberList.value.length
|
||||||
|
})
|
||||||
|
|
||||||
|
const totalPages = computed(() => {
|
||||||
|
return Math.ceil(totalMembers.value / pageSize.value)
|
||||||
|
})
|
||||||
|
|
||||||
|
const visiblePages = computed(() => {
|
||||||
|
const pages = []
|
||||||
|
const start = Math.max(1, currentPage.value - 2)
|
||||||
|
const end = Math.min(totalPages.value, start + 4)
|
||||||
|
|
||||||
|
for (let i = start; i <= end; i++) {
|
||||||
|
pages.push(i)
|
||||||
|
}
|
||||||
|
return pages
|
||||||
|
})
|
||||||
|
|
||||||
|
const toggleAllSelection = () => {
|
||||||
|
if (isAllSelected.value) {
|
||||||
|
selectedMembers.value = []
|
||||||
|
} else {
|
||||||
|
selectedMembers.value = [...memberList.value]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const toggleMemberSelection = (member) => {
|
||||||
|
const index = selectedMembers.value.findIndex(m => m.id === member.id)
|
||||||
|
if (index > -1) {
|
||||||
|
selectedMembers.value.splice(index, 1)
|
||||||
|
} else {
|
||||||
|
selectedMembers.value.push(member)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const prevPage = () => {
|
||||||
|
if (currentPage.value > 1) {
|
||||||
|
currentPage.value--
|
||||||
|
loadMembers()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const nextPage = () => {
|
||||||
|
if (currentPage.value < totalPages.value) {
|
||||||
|
currentPage.value++
|
||||||
|
loadMembers()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const goToPage = (page) => {
|
||||||
|
currentPage.value = page
|
||||||
|
loadMembers()
|
||||||
|
}
|
||||||
|
|
||||||
|
const editMember = (member) => {
|
||||||
|
// 填充编辑表单
|
||||||
|
editForm.value = {
|
||||||
|
id: member.id,
|
||||||
|
username: member.username,
|
||||||
|
level: member.level,
|
||||||
|
points: member.points,
|
||||||
|
expiryDate: member.expiryDate
|
||||||
|
}
|
||||||
|
editDialogVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleCloseEditDialog = () => {
|
||||||
|
editDialogVisible.value = false
|
||||||
|
// 重置表单
|
||||||
|
editFormRef.value?.resetFields()
|
||||||
|
}
|
||||||
|
|
||||||
|
const saveEdit = async () => {
|
||||||
|
if (!editFormRef.value) return
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 验证表单
|
||||||
|
await editFormRef.value.validate()
|
||||||
|
|
||||||
|
saveLoading.value = true
|
||||||
|
|
||||||
|
// 调用API更新会员信息
|
||||||
|
await memberAPI.updateMember(editForm.value.id, {
|
||||||
|
username: editForm.value.username,
|
||||||
|
level: editForm.value.level,
|
||||||
|
points: editForm.value.points,
|
||||||
|
expiryDate: editForm.value.expiryDate
|
||||||
|
})
|
||||||
|
|
||||||
|
// 更新本地数据
|
||||||
|
const index = memberList.value.findIndex(m => m.id === editForm.value.id)
|
||||||
|
if (index > -1) {
|
||||||
|
memberList.value[index] = { ...editForm.value }
|
||||||
|
}
|
||||||
|
|
||||||
|
ElMessage.success('会员信息更新成功')
|
||||||
|
editDialogVisible.value = false
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('保存失败:', error)
|
||||||
|
ElMessage.error('保存失败,请检查输入信息')
|
||||||
|
} finally {
|
||||||
|
saveLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteMember = async (member) => {
|
||||||
|
try {
|
||||||
|
await ElMessageBox.confirm(
|
||||||
|
`确定要删除用户 ${member.username} 吗?`,
|
||||||
|
'确认删除',
|
||||||
|
{
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning',
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// 调用API删除会员
|
||||||
|
await memberAPI.deleteMember(member.id)
|
||||||
|
|
||||||
|
// 从本地列表中移除
|
||||||
|
const index = memberList.value.findIndex(m => m.id === member.id)
|
||||||
|
if (index > -1) {
|
||||||
|
memberList.value.splice(index, 1)
|
||||||
|
totalMembers.value--
|
||||||
|
}
|
||||||
|
|
||||||
|
ElMessage.success('删除成功')
|
||||||
|
} catch (error) {
|
||||||
|
if (error !== 'cancel') {
|
||||||
|
console.error('删除失败:', error)
|
||||||
|
ElMessage.error('删除失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteSelected = async () => {
|
||||||
|
if (selectedMembers.value.length === 0) {
|
||||||
|
ElMessage.warning('请先选择要删除的会员')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await ElMessageBox.confirm(
|
||||||
|
`确定要删除选中的 ${selectedMembers.value.length} 个会员吗?`,
|
||||||
|
'批量删除',
|
||||||
|
{
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning',
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const ids = selectedMembers.value.map(m => m.id)
|
||||||
|
|
||||||
|
// 调用API批量删除
|
||||||
|
await memberAPI.deleteMembers(ids)
|
||||||
|
|
||||||
|
// 从本地列表中移除
|
||||||
|
memberList.value = memberList.value.filter(m => !ids.includes(m.id))
|
||||||
|
totalMembers.value -= ids.length
|
||||||
|
selectedMembers.value = []
|
||||||
|
|
||||||
|
ElMessage.success('批量删除成功')
|
||||||
|
} catch (error) {
|
||||||
|
if (error !== 'cancel') {
|
||||||
|
console.error('批量删除失败:', error)
|
||||||
|
ElMessage.error('批量删除失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 监听筛选条件变化
|
||||||
|
const handleLevelChange = () => {
|
||||||
|
currentPage.value = 1
|
||||||
|
loadMembers()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加载会员数据
|
||||||
|
const loadMembers = async () => {
|
||||||
|
try {
|
||||||
|
const response = await memberAPI.getMembers({
|
||||||
|
page: currentPage.value,
|
||||||
|
pageSize: pageSize.value,
|
||||||
|
level: selectedLevel.value === 'all' ? '' : selectedLevel.value
|
||||||
|
})
|
||||||
|
|
||||||
|
// 处理API响应数据
|
||||||
|
if (response.data && response.data.list) {
|
||||||
|
memberList.value = response.data.list.map(member => ({
|
||||||
|
id: member.id,
|
||||||
|
username: member.username,
|
||||||
|
level: getMembershipLevel(member.membership),
|
||||||
|
points: member.points,
|
||||||
|
expiryDate: getMembershipExpiry(member.membership)
|
||||||
|
}))
|
||||||
|
totalMembers.value = response.data.total || 0
|
||||||
|
} else {
|
||||||
|
// 如果API暂时不可用,使用模拟数据
|
||||||
|
memberList.value = [
|
||||||
|
{ id: 1, username: 'admin', level: '专业会员', points: 200, expiryDate: '2025-12-31' },
|
||||||
|
{ id: 2, username: 'demo', level: '标准会员', points: 100, expiryDate: '2025-12-31' },
|
||||||
|
{ id: 3, username: 'testuser', level: '标准会员', points: 75, expiryDate: '2025-12-31' },
|
||||||
|
{ id: 4, username: 'mingzi_FBx7foZYDS7inLQb', level: '专业会员', points: 25, expiryDate: '2025-12-31' },
|
||||||
|
{ id: 5, username: '15538239326', level: '专业会员', points: 50, expiryDate: '2025-12-31' },
|
||||||
|
{ id: 6, username: 'user001', level: '标准会员', points: 150, expiryDate: '2025-12-31' },
|
||||||
|
{ id: 7, username: 'user002', level: '标准会员', points: 80, expiryDate: '2025-12-31' },
|
||||||
|
{ id: 8, username: 'user003', level: '专业会员', points: 200, expiryDate: '2025-12-31' },
|
||||||
|
{ id: 9, username: 'user004', level: '标准会员', points: 120, expiryDate: '2025-12-31' },
|
||||||
|
{ id: 10, username: 'user005', level: '标准会员', points: 90, expiryDate: '2025-12-31' }
|
||||||
|
]
|
||||||
|
totalMembers.value = 10
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('加载会员数据失败:', error)
|
||||||
|
ElMessage.error('加载会员数据失败,使用模拟数据')
|
||||||
|
|
||||||
|
// 使用模拟数据作为后备
|
||||||
|
memberList.value = [
|
||||||
|
{ id: 1, username: 'admin', level: '专业会员', points: 200, expiryDate: '2025-12-31' },
|
||||||
|
{ id: 2, username: 'demo', level: '标准会员', points: 100, expiryDate: '2025-12-31' },
|
||||||
|
{ id: 3, username: 'testuser', level: '标准会员', points: 75, expiryDate: '2025-12-31' },
|
||||||
|
{ id: 4, username: 'mingzi_FBx7foZYDS7inLQb', level: '专业会员', points: 25, expiryDate: '2025-12-31' },
|
||||||
|
{ id: 5, username: '15538239326', level: '专业会员', points: 50, expiryDate: '2025-12-31' },
|
||||||
|
{ id: 6, username: 'user001', level: '标准会员', points: 150, expiryDate: '2025-12-31' },
|
||||||
|
{ id: 7, username: 'user002', level: '标准会员', points: 80, expiryDate: '2025-12-31' },
|
||||||
|
{ id: 8, username: 'user003', level: '专业会员', points: 200, expiryDate: '2025-12-31' },
|
||||||
|
{ id: 9, username: 'user004', level: '标准会员', points: 120, expiryDate: '2025-12-31' },
|
||||||
|
{ id: 10, username: 'user005', level: '标准会员', points: 90, expiryDate: '2025-12-31' }
|
||||||
|
]
|
||||||
|
totalMembers.value = 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 辅助函数:获取会员等级显示名称
|
||||||
|
const getMembershipLevel = (membership) => {
|
||||||
|
if (!membership) return '标准会员'
|
||||||
|
return membership.display_name || '标准会员'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 辅助函数:获取会员到期时间
|
||||||
|
const getMembershipExpiry = (membership) => {
|
||||||
|
if (!membership) return '2025-12-31'
|
||||||
|
return membership.end_date ? membership.end_date.split(' ')[0] : '2025-12-31'
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
// 初始化数据
|
||||||
|
loadMembers()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.member-management {
|
||||||
|
display: flex;
|
||||||
|
min-height: 100vh;
|
||||||
|
background: #f8fafc;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 左侧导航栏 */
|
||||||
|
.sidebar {
|
||||||
|
width: 320px;
|
||||||
|
background: white;
|
||||||
|
border-right: 1px solid #e2e8f0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 24px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 28px;
|
||||||
|
margin-bottom: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-icon {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
background: #3b82f6;
|
||||||
|
border-radius: 4px;
|
||||||
|
margin-right: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo span {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1e293b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-menu {
|
||||||
|
flex: 1;
|
||||||
|
padding: 0 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 18px 24px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
border-radius: 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
color: #64748b;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item:hover {
|
||||||
|
background: #f1f5f9;
|
||||||
|
color: #334155;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item.active {
|
||||||
|
background: #eff6ff;
|
||||||
|
color: #3b82f6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item .el-icon {
|
||||||
|
margin-right: 16px;
|
||||||
|
font-size: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item span {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-footer {
|
||||||
|
padding: 0 32px 20px;
|
||||||
|
margin-top: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.online-users,
|
||||||
|
.system-uptime {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #64748b;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.highlight {
|
||||||
|
color: #3b82f6;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 主内容区域 */
|
||||||
|
.main-content {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
background: #f8fafc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 顶部搜索栏 */
|
||||||
|
.top-header {
|
||||||
|
background: white;
|
||||||
|
border-bottom: 1px solid #e2e8f0;
|
||||||
|
padding: 16px 24px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-bar {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-icon {
|
||||||
|
position: absolute;
|
||||||
|
left: 12px;
|
||||||
|
color: #94a3b8;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-input {
|
||||||
|
width: 300px;
|
||||||
|
padding: 8px 12px 8px 40px;
|
||||||
|
border: 1px solid #e2e8f0;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 14px;
|
||||||
|
background: #f8fafc;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-input:focus {
|
||||||
|
border-color: #3b82f6;
|
||||||
|
background: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-input::placeholder {
|
||||||
|
color: #94a3b8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-actions {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification-icon,
|
||||||
|
.help-icon {
|
||||||
|
font-size: 20px;
|
||||||
|
color: #64748b;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-avatar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-avatar img {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
border-radius: 50%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 会员内容区域 */
|
||||||
|
.member-content {
|
||||||
|
padding: 24px;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-header h2 {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1e293b;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selection-info {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #64748b;
|
||||||
|
background: #f1f5f9;
|
||||||
|
padding: 8px 16px;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-toolbar {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar-left {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-container {
|
||||||
|
background: white;
|
||||||
|
border-radius: 8px;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.member-table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.member-table thead {
|
||||||
|
background: #f8fafc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.member-table th {
|
||||||
|
padding: 12px 16px;
|
||||||
|
text-align: left;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #374151;
|
||||||
|
border-bottom: 1px solid #e5e7eb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.member-table td {
|
||||||
|
padding: 12px 16px;
|
||||||
|
border-bottom: 1px solid #f3f4f6;
|
||||||
|
color: #374151;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-row:hover {
|
||||||
|
background: #f9fafb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox-col {
|
||||||
|
width: 50px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox-col input[type="checkbox"] {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.level-tag {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 4px 12px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.level-tag.professional {
|
||||||
|
background: #ec4899;
|
||||||
|
}
|
||||||
|
|
||||||
|
.level-tag.standard {
|
||||||
|
background: #3b82f6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-btn {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 14px;
|
||||||
|
padding: 4px 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.edit-btn {
|
||||||
|
color: #3b82f6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.edit-btn:hover {
|
||||||
|
background: #eff6ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete-btn {
|
||||||
|
color: #dc2626;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete-btn:hover {
|
||||||
|
background: #fef2f2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
margin-top: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-btn {
|
||||||
|
padding: 8px 12px;
|
||||||
|
border: 1px solid #d1d5db;
|
||||||
|
background: white;
|
||||||
|
color: #374151;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 14px;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-btn:hover:not(:disabled) {
|
||||||
|
background: #f3f4f6;
|
||||||
|
border-color: #9ca3af;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-btn.active {
|
||||||
|
background: #3b82f6;
|
||||||
|
color: white;
|
||||||
|
border-color: #3b82f6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-btn:disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 响应式设计 */
|
||||||
|
@media (max-width: 1024px) {
|
||||||
|
.member-management {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar {
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-menu {
|
||||||
|
display: flex;
|
||||||
|
overflow-x: auto;
|
||||||
|
padding: 0 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item {
|
||||||
|
white-space: nowrap;
|
||||||
|
margin-right: 16px;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-footer {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-input {
|
||||||
|
width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.member-content {
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -199,3 +199,6 @@ onMounted(async () => {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -252,3 +252,6 @@ const handleSubmit = async () => {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -11,3 +11,6 @@ console.log('测试页面加载成功')
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -730,3 +730,6 @@ const startGenerate = () => {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,174 @@
|
|||||||
|
package com.example.demo.controller;
|
||||||
|
|
||||||
|
import com.example.demo.repository.UserActivityStatsRepository;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/analytics")
|
||||||
|
@CrossOrigin(origins = "*")
|
||||||
|
public class AnalyticsApiController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private UserActivityStatsRepository userActivityStatsRepository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取日活用户趋势数据
|
||||||
|
*/
|
||||||
|
@GetMapping("/daily-active-users")
|
||||||
|
public ResponseEntity<Map<String, Object>> getDailyActiveUsersTrend(
|
||||||
|
@RequestParam(defaultValue = "2024") String year,
|
||||||
|
@RequestParam(defaultValue = "monthly") String granularity) {
|
||||||
|
try {
|
||||||
|
Map<String, Object> response = new HashMap<>();
|
||||||
|
|
||||||
|
if ("monthly".equals(granularity)) {
|
||||||
|
// 按月聚合数据
|
||||||
|
List<Map<String, Object>> monthlyData = userActivityStatsRepository.findMonthlyActiveUsers(Integer.parseInt(year));
|
||||||
|
|
||||||
|
// 确保12个月都有数据
|
||||||
|
List<Map<String, Object>> completeData = new ArrayList<>();
|
||||||
|
for (int month = 1; month <= 12; month++) {
|
||||||
|
final int currentMonth = month;
|
||||||
|
Optional<Map<String, Object>> monthData = monthlyData.stream()
|
||||||
|
.filter(data -> {
|
||||||
|
Object monthObj = data.get("month");
|
||||||
|
if (monthObj instanceof Number) {
|
||||||
|
return ((Number) monthObj).intValue() == currentMonth;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
})
|
||||||
|
.findFirst();
|
||||||
|
|
||||||
|
if (monthData.isPresent()) {
|
||||||
|
completeData.add(monthData.get());
|
||||||
|
} else {
|
||||||
|
Map<String, Object> emptyMonth = new HashMap<>();
|
||||||
|
emptyMonth.put("month", currentMonth);
|
||||||
|
emptyMonth.put("dailyActiveUsers", 0);
|
||||||
|
emptyMonth.put("avgDailyActive", 0.0);
|
||||||
|
completeData.add(emptyMonth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
response.put("monthlyData", completeData);
|
||||||
|
} else {
|
||||||
|
// 按日返回数据
|
||||||
|
List<Map<String, Object>> dailyData = userActivityStatsRepository.findDailyActiveUsersByYear(Integer.parseInt(year));
|
||||||
|
response.put("dailyData", dailyData);
|
||||||
|
}
|
||||||
|
|
||||||
|
response.put("year", year);
|
||||||
|
response.put("granularity", granularity);
|
||||||
|
|
||||||
|
return ResponseEntity.ok(response);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
Map<String, Object> error = new HashMap<>();
|
||||||
|
error.put("error", "获取日活用户趋势数据失败");
|
||||||
|
error.put("message", e.getMessage());
|
||||||
|
return ResponseEntity.status(500).body(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户活跃度概览
|
||||||
|
*/
|
||||||
|
@GetMapping("/user-activity-overview")
|
||||||
|
public ResponseEntity<Map<String, Object>> getUserActivityOverview() {
|
||||||
|
try {
|
||||||
|
Map<String, Object> response = new HashMap<>();
|
||||||
|
|
||||||
|
// 获取最新数据
|
||||||
|
LocalDate today = LocalDate.now();
|
||||||
|
LocalDate yesterday = today.minusDays(1);
|
||||||
|
LocalDate lastMonth = today.minusMonths(1);
|
||||||
|
LocalDate lastYear = today.minusYears(1);
|
||||||
|
|
||||||
|
// 今日日活
|
||||||
|
Integer todayDAU = userActivityStatsRepository.findDailyActiveUsersByDate(today);
|
||||||
|
response.put("todayDAU", todayDAU != null ? todayDAU : 0);
|
||||||
|
|
||||||
|
// 昨日日活
|
||||||
|
Integer yesterdayDAU = userActivityStatsRepository.findDailyActiveUsersByDate(yesterday);
|
||||||
|
response.put("yesterdayDAU", yesterdayDAU != null ? yesterdayDAU : 0);
|
||||||
|
|
||||||
|
// 本月平均日活
|
||||||
|
Double monthlyAvgDAU = userActivityStatsRepository.findAverageDailyActiveUsersByMonth(today.getYear(), today.getMonthValue());
|
||||||
|
response.put("monthlyAvgDAU", monthlyAvgDAU != null ? monthlyAvgDAU : 0.0);
|
||||||
|
|
||||||
|
// 上月平均日活
|
||||||
|
LocalDate lastMonthDate = today.minusMonths(1);
|
||||||
|
Double lastMonthAvgDAU = userActivityStatsRepository.findAverageDailyActiveUsersByMonth(lastMonthDate.getYear(), lastMonthDate.getMonthValue());
|
||||||
|
response.put("lastMonthAvgDAU", lastMonthAvgDAU != null ? lastMonthAvgDAU : 0.0);
|
||||||
|
|
||||||
|
// 年度平均日活
|
||||||
|
Double yearlyAvgDAU = userActivityStatsRepository.findAverageDailyActiveUsersByYear(today.getYear());
|
||||||
|
response.put("yearlyAvgDAU", yearlyAvgDAU != null ? yearlyAvgDAU : 0.0);
|
||||||
|
|
||||||
|
// 计算增长率
|
||||||
|
if (yesterdayDAU != null && yesterdayDAU > 0) {
|
||||||
|
double dayGrowthRate = ((todayDAU != null ? todayDAU : 0) - yesterdayDAU) / (double) yesterdayDAU * 100;
|
||||||
|
response.put("dayGrowthRate", Math.round(dayGrowthRate * 100.0) / 100.0);
|
||||||
|
} else {
|
||||||
|
response.put("dayGrowthRate", 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastMonthAvgDAU != null && lastMonthAvgDAU > 0) {
|
||||||
|
double monthGrowthRate = ((monthlyAvgDAU != null ? monthlyAvgDAU : 0) - lastMonthAvgDAU) / lastMonthAvgDAU * 100;
|
||||||
|
response.put("monthGrowthRate", Math.round(monthGrowthRate * 100.0) / 100.0);
|
||||||
|
} else {
|
||||||
|
response.put("monthGrowthRate", 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResponseEntity.ok(response);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
Map<String, Object> error = new HashMap<>();
|
||||||
|
error.put("error", "获取用户活跃度概览失败");
|
||||||
|
error.put("message", e.getMessage());
|
||||||
|
return ResponseEntity.status(500).body(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户活跃度热力图数据
|
||||||
|
*/
|
||||||
|
@GetMapping("/user-activity-heatmap")
|
||||||
|
public ResponseEntity<Map<String, Object>> getUserActivityHeatmap(
|
||||||
|
@RequestParam(defaultValue = "2024") String year) {
|
||||||
|
try {
|
||||||
|
Map<String, Object> response = new HashMap<>();
|
||||||
|
|
||||||
|
// 获取全年每日数据
|
||||||
|
List<Map<String, Object>> dailyData = userActivityStatsRepository.findDailyActiveUsersByYear(Integer.parseInt(year));
|
||||||
|
|
||||||
|
// 转换为热力图格式
|
||||||
|
List<List<Object>> heatmapData = new ArrayList<>();
|
||||||
|
for (Map<String, Object> data : dailyData) {
|
||||||
|
List<Object> point = new ArrayList<>();
|
||||||
|
point.add(data.get("dayOfYear")); // 一年中的第几天
|
||||||
|
point.add(data.get("weekOfYear")); // 一年中的第几周
|
||||||
|
point.add(data.get("dailyActiveUsers")); // 日活用户数
|
||||||
|
heatmapData.add(point);
|
||||||
|
}
|
||||||
|
|
||||||
|
response.put("heatmapData", heatmapData);
|
||||||
|
response.put("year", year);
|
||||||
|
|
||||||
|
return ResponseEntity.ok(response);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
Map<String, Object> error = new HashMap<>();
|
||||||
|
error.put("error", "获取用户活跃度热力图数据失败");
|
||||||
|
error.put("message", e.getMessage());
|
||||||
|
return ResponseEntity.status(500).body(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +1,19 @@
|
|||||||
package com.example.demo.controller;
|
package com.example.demo.controller;
|
||||||
|
|
||||||
import com.example.demo.service.DashboardService;
|
import com.example.demo.repository.UserRepository;
|
||||||
|
import com.example.demo.repository.OrderRepository;
|
||||||
|
import com.example.demo.repository.PaymentRepository;
|
||||||
|
import com.example.demo.repository.UserMembershipRepository;
|
||||||
|
import com.example.demo.repository.MembershipLevelRepository;
|
||||||
|
import com.example.demo.model.Order;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import org.springframework.data.domain.PageRequest;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/dashboard")
|
@RequestMapping("/api/dashboard")
|
||||||
@@ -14,110 +21,206 @@ import java.util.Map;
|
|||||||
public class DashboardApiController {
|
public class DashboardApiController {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private DashboardService dashboardService;
|
private UserRepository userRepository;
|
||||||
|
|
||||||
/**
|
@Autowired
|
||||||
* 获取仪表盘概览数据
|
private OrderRepository orderRepository;
|
||||||
*/
|
|
||||||
|
@Autowired
|
||||||
|
private PaymentRepository paymentRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private UserMembershipRepository userMembershipRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MembershipLevelRepository membershipLevelRepository;
|
||||||
|
|
||||||
|
// 获取仪表盘概览数据
|
||||||
@GetMapping("/overview")
|
@GetMapping("/overview")
|
||||||
@PreAuthorize("hasRole('ADMIN')")
|
public ResponseEntity<Map<String, Object>> getDashboardOverview() {
|
||||||
public ResponseEntity<Map<String, Object>> getOverview() {
|
|
||||||
try {
|
try {
|
||||||
Map<String, Object> overview = dashboardService.getDashboardOverview();
|
Map<String, Object> overview = new HashMap<>();
|
||||||
|
|
||||||
|
// 用户总数
|
||||||
|
long totalUsers = userRepository.count();
|
||||||
|
overview.put("totalUsers", totalUsers);
|
||||||
|
|
||||||
|
// 付费用户数(有会员的用户)
|
||||||
|
long paidUsers = userMembershipRepository.countByStatus("ACTIVE");
|
||||||
|
overview.put("paidUsers", paidUsers);
|
||||||
|
|
||||||
|
// 今日收入(今日完成的支付)
|
||||||
|
LocalDateTime todayStart = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0);
|
||||||
|
LocalDateTime todayEnd = LocalDateTime.now().withHour(23).withMinute(59).withSecond(59);
|
||||||
|
|
||||||
|
Double todayRevenue = paymentRepository.findTodayRevenue(todayStart, todayEnd);
|
||||||
|
overview.put("todayRevenue", todayRevenue != null ? todayRevenue : 0.0);
|
||||||
|
|
||||||
|
// 总订单数
|
||||||
|
long totalOrders = orderRepository.count();
|
||||||
|
overview.put("totalOrders", totalOrders);
|
||||||
|
|
||||||
|
// 总收入
|
||||||
|
Double totalRevenue = paymentRepository.findTotalRevenue();
|
||||||
|
overview.put("totalRevenue", totalRevenue != null ? totalRevenue : 0.0);
|
||||||
|
|
||||||
|
// 本月收入
|
||||||
|
LocalDateTime monthStart = LocalDateTime.now().withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0);
|
||||||
|
LocalDateTime monthEnd = LocalDateTime.now();
|
||||||
|
|
||||||
|
Double monthRevenue = paymentRepository.findRevenueByDateRange(monthStart, monthEnd);
|
||||||
|
overview.put("monthRevenue", monthRevenue != null ? monthRevenue : 0.0);
|
||||||
|
|
||||||
return ResponseEntity.ok(overview);
|
return ResponseEntity.ok(overview);
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return ResponseEntity.internalServerError().build();
|
Map<String, Object> error = new HashMap<>();
|
||||||
|
error.put("error", "获取仪表盘数据失败");
|
||||||
|
error.put("message", e.getMessage());
|
||||||
|
return ResponseEntity.status(500).body(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// 获取月度收入趋势数据
|
||||||
* 获取日活数据
|
@GetMapping("/monthly-revenue")
|
||||||
*/
|
public ResponseEntity<Map<String, Object>> getMonthlyRevenue(@RequestParam(defaultValue = "2024") String year) {
|
||||||
@GetMapping("/daily-active-users")
|
|
||||||
@PreAuthorize("hasRole('ADMIN')")
|
|
||||||
public ResponseEntity<Map<String, Object>> getDailyActiveUsers() {
|
|
||||||
try {
|
try {
|
||||||
Map<String, Object> data = dashboardService.getDailyActiveUsers();
|
Map<String, Object> response = new HashMap<>();
|
||||||
return ResponseEntity.ok(data);
|
|
||||||
} catch (Exception e) {
|
// 获取指定年份的月度收入数据
|
||||||
return ResponseEntity.internalServerError().build();
|
List<Map<String, Object>> monthlyData = paymentRepository.findMonthlyRevenueByYear(Integer.parseInt(year));
|
||||||
|
|
||||||
|
// 确保12个月都有数据
|
||||||
|
List<Map<String, Object>> completeData = new ArrayList<>();
|
||||||
|
for (int month = 1; month <= 12; month++) {
|
||||||
|
final int currentMonth = month;
|
||||||
|
Optional<Map<String, Object>> monthData = monthlyData.stream()
|
||||||
|
.filter(data -> {
|
||||||
|
Object monthObj = data.get("month");
|
||||||
|
if (monthObj instanceof Number) {
|
||||||
|
return ((Number) monthObj).intValue() == currentMonth;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
})
|
||||||
|
.findFirst();
|
||||||
|
|
||||||
|
if (monthData.isPresent()) {
|
||||||
|
completeData.add(monthData.get());
|
||||||
|
} else {
|
||||||
|
Map<String, Object> emptyMonth = new HashMap<>();
|
||||||
|
emptyMonth.put("month", currentMonth);
|
||||||
|
emptyMonth.put("revenue", 0.0);
|
||||||
|
emptyMonth.put("orderCount", 0);
|
||||||
|
completeData.add(emptyMonth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
response.put("monthlyData", completeData);
|
||||||
* 获取收入趋势数据
|
response.put("year", year);
|
||||||
*/
|
|
||||||
@GetMapping("/revenue-trend")
|
return ResponseEntity.ok(response);
|
||||||
@PreAuthorize("hasRole('ADMIN')")
|
|
||||||
public ResponseEntity<Map<String, Object>> getRevenueTrend() {
|
} catch (Exception e) {
|
||||||
|
Map<String, Object> error = new HashMap<>();
|
||||||
|
error.put("error", "获取月度收入数据失败");
|
||||||
|
error.put("message", e.getMessage());
|
||||||
|
return ResponseEntity.status(500).body(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取用户转化率数据
|
||||||
|
@GetMapping("/conversion-rate")
|
||||||
|
public ResponseEntity<Map<String, Object>> getConversionRate() {
|
||||||
try {
|
try {
|
||||||
Map<String, Object> data = dashboardService.getRevenueTrend();
|
Map<String, Object> response = new HashMap<>();
|
||||||
return ResponseEntity.ok(data);
|
|
||||||
|
// 总用户数
|
||||||
|
long totalUsers = userRepository.count();
|
||||||
|
|
||||||
|
// 付费用户数
|
||||||
|
long paidUsers = userMembershipRepository.countByStatus("ACTIVE");
|
||||||
|
|
||||||
|
// 计算转化率
|
||||||
|
double conversionRate = totalUsers > 0 ? (double) paidUsers / totalUsers * 100 : 0.0;
|
||||||
|
|
||||||
|
response.put("totalUsers", totalUsers);
|
||||||
|
response.put("paidUsers", paidUsers);
|
||||||
|
response.put("conversionRate", Math.round(conversionRate * 100.0) / 100.0);
|
||||||
|
|
||||||
|
// 按会员等级统计
|
||||||
|
List<Map<String, Object>> membershipStats = membershipLevelRepository.findMembershipStats();
|
||||||
|
response.put("membershipStats", membershipStats);
|
||||||
|
|
||||||
|
return ResponseEntity.ok(response);
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return ResponseEntity.internalServerError().build();
|
Map<String, Object> error = new HashMap<>();
|
||||||
|
error.put("error", "获取转化率数据失败");
|
||||||
|
error.put("message", e.getMessage());
|
||||||
|
return ResponseEntity.status(500).body(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// 获取最近订单数据
|
||||||
* 获取订单状态分布
|
|
||||||
*/
|
|
||||||
@GetMapping("/order-status-distribution")
|
|
||||||
@PreAuthorize("hasRole('ADMIN')")
|
|
||||||
public ResponseEntity<Map<String, Object>> getOrderStatusDistribution() {
|
|
||||||
try {
|
|
||||||
Map<String, Object> data = dashboardService.getOrderStatusDistribution();
|
|
||||||
return ResponseEntity.ok(data);
|
|
||||||
} catch (Exception e) {
|
|
||||||
return ResponseEntity.internalServerError().build();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取支付方式分布
|
|
||||||
*/
|
|
||||||
@GetMapping("/payment-method-distribution")
|
|
||||||
@PreAuthorize("hasRole('ADMIN')")
|
|
||||||
public ResponseEntity<Map<String, Object>> getPaymentMethodDistribution() {
|
|
||||||
try {
|
|
||||||
Map<String, Object> data = dashboardService.getPaymentMethodDistribution();
|
|
||||||
return ResponseEntity.ok(data);
|
|
||||||
} catch (Exception e) {
|
|
||||||
return ResponseEntity.internalServerError().build();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取最近订单列表
|
|
||||||
*/
|
|
||||||
@GetMapping("/recent-orders")
|
@GetMapping("/recent-orders")
|
||||||
@PreAuthorize("hasRole('ADMIN')")
|
public ResponseEntity<Map<String, Object>> getRecentOrders(@RequestParam(defaultValue = "10") int limit) {
|
||||||
public ResponseEntity<Map<String, Object>> getRecentOrders() {
|
|
||||||
try {
|
try {
|
||||||
Map<String, Object> data = dashboardService.getRecentOrders();
|
Map<String, Object> response = new HashMap<>();
|
||||||
return ResponseEntity.ok(data);
|
|
||||||
|
// 获取最近的订单
|
||||||
|
List<Order> recentOrdersList = orderRepository.findRecentOrders(PageRequest.of(0, limit));
|
||||||
|
List<Map<String, Object>> recentOrders = recentOrdersList.stream()
|
||||||
|
.map(order -> {
|
||||||
|
Map<String, Object> orderMap = new HashMap<>();
|
||||||
|
orderMap.put("id", order.getId());
|
||||||
|
orderMap.put("orderNumber", order.getOrderNumber());
|
||||||
|
orderMap.put("totalAmount", order.getTotalAmount());
|
||||||
|
orderMap.put("status", order.getStatus());
|
||||||
|
orderMap.put("orderType", order.getOrderType());
|
||||||
|
orderMap.put("description", order.getDescription());
|
||||||
|
orderMap.put("createdAt", order.getCreatedAt());
|
||||||
|
orderMap.put("username", order.getUser() != null ? order.getUser().getUsername() : "未知用户");
|
||||||
|
return orderMap;
|
||||||
|
})
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
response.put("recentOrders", recentOrders);
|
||||||
|
|
||||||
|
return ResponseEntity.ok(response);
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return ResponseEntity.internalServerError().build();
|
Map<String, Object> error = new HashMap<>();
|
||||||
|
error.put("error", "获取最近订单失败");
|
||||||
|
error.put("message", e.getMessage());
|
||||||
|
return ResponseEntity.status(500).body(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// 获取系统状态
|
||||||
* 获取所有仪表盘数据
|
@GetMapping("/system-status")
|
||||||
*/
|
public ResponseEntity<Map<String, Object>> getSystemStatus() {
|
||||||
@GetMapping("/all")
|
|
||||||
@PreAuthorize("hasRole('ADMIN')")
|
|
||||||
public ResponseEntity<Map<String, Object>> getAllDashboardData() {
|
|
||||||
try {
|
try {
|
||||||
Map<String, Object> allData = Map.of(
|
Map<String, Object> status = new HashMap<>();
|
||||||
"overview", dashboardService.getDashboardOverview(),
|
|
||||||
"dailyActiveUsers", dashboardService.getDailyActiveUsers(),
|
// 当前在线用户(模拟数据,实际应该从session或redis获取)
|
||||||
"revenueTrend", dashboardService.getRevenueTrend(),
|
int onlineUsers = (int) (Math.random() * 50) + 50; // 50-100之间
|
||||||
"orderStatusDistribution", dashboardService.getOrderStatusDistribution(),
|
status.put("onlineUsers", onlineUsers);
|
||||||
"paymentMethodDistribution", dashboardService.getPaymentMethodDistribution(),
|
|
||||||
"recentOrders", dashboardService.getRecentOrders()
|
// 系统运行时间(模拟数据)
|
||||||
);
|
status.put("systemUptime", "48小时32分");
|
||||||
return ResponseEntity.ok(allData);
|
|
||||||
|
// 数据库连接状态
|
||||||
|
status.put("databaseStatus", "正常");
|
||||||
|
|
||||||
|
// 服务状态
|
||||||
|
status.put("serviceStatus", "运行中");
|
||||||
|
|
||||||
|
return ResponseEntity.ok(status);
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return ResponseEntity.internalServerError().build();
|
Map<String, Object> error = new HashMap<>();
|
||||||
|
error.put("error", "获取系统状态失败");
|
||||||
|
error.put("message", e.getMessage());
|
||||||
|
return ResponseEntity.status(500).body(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,263 @@
|
|||||||
|
package com.example.demo.controller;
|
||||||
|
|
||||||
|
import com.example.demo.model.User;
|
||||||
|
import com.example.demo.model.UserMembership;
|
||||||
|
import com.example.demo.model.MembershipLevel;
|
||||||
|
import com.example.demo.repository.UserRepository;
|
||||||
|
import com.example.demo.repository.UserMembershipRepository;
|
||||||
|
import com.example.demo.repository.MembershipLevelRepository;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
|
import org.springframework.data.domain.PageRequest;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.data.domain.Sort;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/members")
|
||||||
|
@CrossOrigin(origins = "*")
|
||||||
|
public class MemberApiController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private UserRepository userRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private UserMembershipRepository userMembershipRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MembershipLevelRepository membershipLevelRepository;
|
||||||
|
|
||||||
|
// 获取会员列表
|
||||||
|
@GetMapping
|
||||||
|
public ResponseEntity<Map<String, Object>> getMembers(
|
||||||
|
@RequestParam(defaultValue = "1") int page,
|
||||||
|
@RequestParam(defaultValue = "10") int pageSize,
|
||||||
|
@RequestParam(required = false) String level) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
Pageable pageable = PageRequest.of(page - 1, pageSize, Sort.by("createdAt").descending());
|
||||||
|
Page<User> userPage = userRepository.findAll(pageable);
|
||||||
|
|
||||||
|
List<Map<String, Object>> members = userPage.getContent().stream()
|
||||||
|
.map(user -> {
|
||||||
|
Map<String, Object> member = new HashMap<>();
|
||||||
|
member.put("id", user.getId());
|
||||||
|
member.put("username", user.getUsername());
|
||||||
|
member.put("email", user.getEmail());
|
||||||
|
member.put("phone", user.getPhone());
|
||||||
|
member.put("nickname", user.getNickname());
|
||||||
|
member.put("points", user.getPoints());
|
||||||
|
member.put("role", user.getRole());
|
||||||
|
member.put("isActive", user.getIsActive());
|
||||||
|
member.put("createdAt", user.getCreatedAt());
|
||||||
|
member.put("lastLoginAt", user.getLastLoginAt());
|
||||||
|
|
||||||
|
// 获取会员信息
|
||||||
|
Optional<UserMembership> membership = userMembershipRepository
|
||||||
|
.findByUserIdAndStatus(user.getId(), "ACTIVE");
|
||||||
|
|
||||||
|
if (membership.isPresent()) {
|
||||||
|
UserMembership userMembership = membership.get();
|
||||||
|
Optional<MembershipLevel> membershipLevel = membershipLevelRepository
|
||||||
|
.findById(userMembership.getMembershipLevelId());
|
||||||
|
|
||||||
|
if (membershipLevel.isPresent()) {
|
||||||
|
Map<String, Object> membershipInfo = new HashMap<>();
|
||||||
|
membershipInfo.put("display_name", membershipLevel.get().getDisplayName());
|
||||||
|
membershipInfo.put("end_date", userMembership.getEndDate());
|
||||||
|
membershipInfo.put("status", userMembership.getStatus());
|
||||||
|
member.put("membership", membershipInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return member;
|
||||||
|
})
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
Map<String, Object> response = new HashMap<>();
|
||||||
|
response.put("list", members);
|
||||||
|
response.put("total", userPage.getTotalElements());
|
||||||
|
response.put("page", page);
|
||||||
|
response.put("pageSize", pageSize);
|
||||||
|
response.put("totalPages", userPage.getTotalPages());
|
||||||
|
|
||||||
|
return ResponseEntity.ok(response);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
Map<String, Object> error = new HashMap<>();
|
||||||
|
error.put("error", "获取会员列表失败");
|
||||||
|
error.put("message", e.getMessage());
|
||||||
|
return ResponseEntity.status(500).body(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取会员详情
|
||||||
|
@GetMapping("/{id}")
|
||||||
|
public ResponseEntity<Map<String, Object>> getMemberDetail(@PathVariable Long id) {
|
||||||
|
try {
|
||||||
|
Optional<User> userOpt = userRepository.findById(id);
|
||||||
|
if (userOpt.isEmpty()) {
|
||||||
|
return ResponseEntity.notFound().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
User user = userOpt.get();
|
||||||
|
Map<String, Object> member = new HashMap<>();
|
||||||
|
member.put("id", user.getId());
|
||||||
|
member.put("username", user.getUsername());
|
||||||
|
member.put("email", user.getEmail());
|
||||||
|
member.put("phone", user.getPhone());
|
||||||
|
member.put("nickname", user.getNickname());
|
||||||
|
member.put("points", user.getPoints());
|
||||||
|
member.put("role", user.getRole());
|
||||||
|
member.put("isActive", user.getIsActive());
|
||||||
|
member.put("createdAt", user.getCreatedAt());
|
||||||
|
member.put("lastLoginAt", user.getLastLoginAt());
|
||||||
|
|
||||||
|
// 获取会员信息
|
||||||
|
Optional<UserMembership> membership = userMembershipRepository
|
||||||
|
.findByUserIdAndStatus(user.getId(), "ACTIVE");
|
||||||
|
|
||||||
|
if (membership.isPresent()) {
|
||||||
|
UserMembership userMembership = membership.get();
|
||||||
|
Optional<MembershipLevel> membershipLevel = membershipLevelRepository
|
||||||
|
.findById(userMembership.getMembershipLevelId());
|
||||||
|
|
||||||
|
if (membershipLevel.isPresent()) {
|
||||||
|
Map<String, Object> membershipInfo = new HashMap<>();
|
||||||
|
membershipInfo.put("display_name", membershipLevel.get().getDisplayName());
|
||||||
|
membershipInfo.put("end_date", userMembership.getEndDate());
|
||||||
|
membershipInfo.put("status", userMembership.getStatus());
|
||||||
|
member.put("membership", membershipInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResponseEntity.ok(member);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
Map<String, Object> error = new HashMap<>();
|
||||||
|
error.put("error", "获取会员详情失败");
|
||||||
|
error.put("message", e.getMessage());
|
||||||
|
return ResponseEntity.status(500).body(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新会员信息
|
||||||
|
@PutMapping("/{id}")
|
||||||
|
public ResponseEntity<Map<String, Object>> updateMember(
|
||||||
|
@PathVariable Long id,
|
||||||
|
@RequestBody Map<String, Object> updateData) {
|
||||||
|
try {
|
||||||
|
Optional<User> userOpt = userRepository.findById(id);
|
||||||
|
if (userOpt.isEmpty()) {
|
||||||
|
return ResponseEntity.notFound().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
User user = userOpt.get();
|
||||||
|
|
||||||
|
// 更新用户基本信息
|
||||||
|
if (updateData.containsKey("username")) {
|
||||||
|
user.setUsername((String) updateData.get("username"));
|
||||||
|
}
|
||||||
|
if (updateData.containsKey("points")) {
|
||||||
|
user.setPoints((Integer) updateData.get("points"));
|
||||||
|
}
|
||||||
|
|
||||||
|
userRepository.save(user);
|
||||||
|
|
||||||
|
// 更新会员等级
|
||||||
|
if (updateData.containsKey("level")) {
|
||||||
|
String levelName = (String) updateData.get("level");
|
||||||
|
Optional<MembershipLevel> levelOpt = membershipLevelRepository
|
||||||
|
.findByDisplayName(levelName);
|
||||||
|
|
||||||
|
if (levelOpt.isPresent()) {
|
||||||
|
MembershipLevel level = levelOpt.get();
|
||||||
|
|
||||||
|
// 更新或创建会员信息
|
||||||
|
Optional<UserMembership> membershipOpt = userMembershipRepository
|
||||||
|
.findByUserIdAndStatus(user.getId(), "ACTIVE");
|
||||||
|
|
||||||
|
if (membershipOpt.isPresent()) {
|
||||||
|
UserMembership membership = membershipOpt.get();
|
||||||
|
membership.setMembershipLevelId(level.getId());
|
||||||
|
userMembershipRepository.save(membership);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, Object> response = new HashMap<>();
|
||||||
|
response.put("success", true);
|
||||||
|
response.put("message", "会员信息更新成功");
|
||||||
|
|
||||||
|
return ResponseEntity.ok(response);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
Map<String, Object> error = new HashMap<>();
|
||||||
|
error.put("error", "更新会员信息失败");
|
||||||
|
error.put("message", e.getMessage());
|
||||||
|
return ResponseEntity.status(500).body(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除会员
|
||||||
|
@DeleteMapping("/{id}")
|
||||||
|
public ResponseEntity<Map<String, Object>> deleteMember(@PathVariable Long id) {
|
||||||
|
try {
|
||||||
|
Optional<User> userOpt = userRepository.findById(id);
|
||||||
|
if (userOpt.isEmpty()) {
|
||||||
|
return ResponseEntity.notFound().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 软删除:设置为非活跃状态
|
||||||
|
User user = userOpt.get();
|
||||||
|
user.setIsActive(false);
|
||||||
|
userRepository.save(user);
|
||||||
|
|
||||||
|
Map<String, Object> response = new HashMap<>();
|
||||||
|
response.put("success", true);
|
||||||
|
response.put("message", "会员删除成功");
|
||||||
|
|
||||||
|
return ResponseEntity.ok(response);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
Map<String, Object> error = new HashMap<>();
|
||||||
|
error.put("error", "删除会员失败");
|
||||||
|
error.put("message", e.getMessage());
|
||||||
|
return ResponseEntity.status(500).body(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 批量删除会员
|
||||||
|
@DeleteMapping("/batch")
|
||||||
|
public ResponseEntity<Map<String, Object>> deleteMembers(@RequestBody Map<String, List<Long>> request) {
|
||||||
|
try {
|
||||||
|
List<Long> ids = request.get("ids");
|
||||||
|
if (ids == null || ids.isEmpty()) {
|
||||||
|
return ResponseEntity.badRequest().body(Map.of("error", "请提供要删除的会员ID列表"));
|
||||||
|
}
|
||||||
|
|
||||||
|
List<User> users = userRepository.findAllById(ids);
|
||||||
|
users.forEach(user -> user.setIsActive(false));
|
||||||
|
userRepository.saveAll(users);
|
||||||
|
|
||||||
|
Map<String, Object> response = new HashMap<>();
|
||||||
|
response.put("success", true);
|
||||||
|
response.put("message", "批量删除成功");
|
||||||
|
response.put("deletedCount", users.size());
|
||||||
|
|
||||||
|
return ResponseEntity.ok(response);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
Map<String, Object> error = new HashMap<>();
|
||||||
|
error.put("error", "批量删除失败");
|
||||||
|
error.put("message", e.getMessage());
|
||||||
|
return ResponseEntity.status(500).body(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -385,6 +385,69 @@ public class OrderApiController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除订单
|
||||||
|
*/
|
||||||
|
@DeleteMapping("/{id}")
|
||||||
|
public ResponseEntity<Map<String, Object>> deleteOrder(@PathVariable Long id,
|
||||||
|
Authentication authentication) {
|
||||||
|
try {
|
||||||
|
User user = (User) authentication.getPrincipal();
|
||||||
|
Order order = orderService.findById(id)
|
||||||
|
.orElseThrow(() -> new RuntimeException("订单不存在"));
|
||||||
|
|
||||||
|
// 检查权限
|
||||||
|
if (!user.getRole().equals("ROLE_ADMIN") && !order.getUser().getId().equals(user.getId())) {
|
||||||
|
return ResponseEntity.badRequest()
|
||||||
|
.body(createErrorResponse("无权限删除此订单"));
|
||||||
|
}
|
||||||
|
|
||||||
|
orderService.deleteOrder(id);
|
||||||
|
|
||||||
|
Map<String, Object> response = new HashMap<>();
|
||||||
|
response.put("success", true);
|
||||||
|
response.put("message", "订单删除成功");
|
||||||
|
|
||||||
|
return ResponseEntity.ok(response);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("删除订单失败:", e);
|
||||||
|
return ResponseEntity.badRequest()
|
||||||
|
.body(createErrorResponse("删除订单失败:" + e.getMessage()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除订单
|
||||||
|
*/
|
||||||
|
@DeleteMapping("/batch")
|
||||||
|
public ResponseEntity<Map<String, Object>> deleteOrders(@RequestBody List<Long> orderIds,
|
||||||
|
Authentication authentication) {
|
||||||
|
try {
|
||||||
|
User user = (User) authentication.getPrincipal();
|
||||||
|
|
||||||
|
// 只有管理员可以批量删除
|
||||||
|
if (!user.getRole().equals("ROLE_ADMIN")) {
|
||||||
|
return ResponseEntity.badRequest()
|
||||||
|
.body(createErrorResponse("无权限批量删除订单"));
|
||||||
|
}
|
||||||
|
|
||||||
|
int deletedCount = orderService.deleteOrdersByIds(orderIds);
|
||||||
|
|
||||||
|
Map<String, Object> response = new HashMap<>();
|
||||||
|
response.put("success", true);
|
||||||
|
response.put("message", "批量删除成功,共删除 " + deletedCount + " 个订单");
|
||||||
|
response.put("deletedCount", deletedCount);
|
||||||
|
|
||||||
|
return ResponseEntity.ok(response);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("批量删除订单失败:", e);
|
||||||
|
return ResponseEntity.badRequest()
|
||||||
|
.body(createErrorResponse("批量删除订单失败:" + e.getMessage()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private Map<String, Object> createErrorResponse(String message) {
|
private Map<String, Object> createErrorResponse(String message) {
|
||||||
Map<String, Object> response = new HashMap<>();
|
Map<String, Object> response = new HashMap<>();
|
||||||
response.put("success", false);
|
response.put("success", false);
|
||||||
|
|||||||
145
demo/src/main/java/com/example/demo/model/MembershipLevel.java
Normal file
145
demo/src/main/java/com/example/demo/model/MembershipLevel.java
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
package com.example.demo.model;
|
||||||
|
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "membership_levels")
|
||||||
|
public class MembershipLevel {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Column(name = "name", nullable = false, unique = true)
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Column(name = "display_name", nullable = false)
|
||||||
|
private String displayName;
|
||||||
|
|
||||||
|
@Column(name = "description")
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
@Column(name = "price", nullable = false)
|
||||||
|
private Double price;
|
||||||
|
|
||||||
|
@Column(name = "duration_days", nullable = false)
|
||||||
|
private Integer durationDays;
|
||||||
|
|
||||||
|
@Column(name = "points_bonus", nullable = false)
|
||||||
|
private Integer pointsBonus;
|
||||||
|
|
||||||
|
@Column(name = "features", columnDefinition = "JSON")
|
||||||
|
private String features;
|
||||||
|
|
||||||
|
@Column(name = "is_active", nullable = false)
|
||||||
|
private Boolean isActive = true;
|
||||||
|
|
||||||
|
@Column(name = "created_at", nullable = false)
|
||||||
|
private LocalDateTime createdAt = LocalDateTime.now();
|
||||||
|
|
||||||
|
@Column(name = "updated_at")
|
||||||
|
private LocalDateTime updatedAt;
|
||||||
|
|
||||||
|
// 构造函数
|
||||||
|
public MembershipLevel() {}
|
||||||
|
|
||||||
|
public MembershipLevel(String name, String displayName, String description, Double price,
|
||||||
|
Integer durationDays, Integer pointsBonus, String features) {
|
||||||
|
this.name = name;
|
||||||
|
this.displayName = displayName;
|
||||||
|
this.description = description;
|
||||||
|
this.price = price;
|
||||||
|
this.durationDays = durationDays;
|
||||||
|
this.pointsBonus = pointsBonus;
|
||||||
|
this.features = features;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getters and Setters
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDisplayName() {
|
||||||
|
return displayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDisplayName(String displayName) {
|
||||||
|
this.displayName = displayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDescription(String description) {
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Double getPrice() {
|
||||||
|
return price;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPrice(Double price) {
|
||||||
|
this.price = price;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getDurationDays() {
|
||||||
|
return durationDays;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDurationDays(Integer durationDays) {
|
||||||
|
this.durationDays = durationDays;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getPointsBonus() {
|
||||||
|
return pointsBonus;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPointsBonus(Integer pointsBonus) {
|
||||||
|
this.pointsBonus = pointsBonus;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFeatures() {
|
||||||
|
return features;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFeatures(String features) {
|
||||||
|
this.features = features;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getIsActive() {
|
||||||
|
return isActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIsActive(Boolean isActive) {
|
||||||
|
this.isActive = isActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getCreatedAt() {
|
||||||
|
return createdAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreatedAt(LocalDateTime createdAt) {
|
||||||
|
this.createdAt = createdAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getUpdatedAt() {
|
||||||
|
return updatedAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUpdatedAt(LocalDateTime updatedAt) {
|
||||||
|
this.updatedAt = updatedAt;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -44,9 +44,36 @@ public class User {
|
|||||||
@Column(nullable = false)
|
@Column(nullable = false)
|
||||||
private Integer points = 50; // 默认50积分
|
private Integer points = 50; // 默认50积分
|
||||||
|
|
||||||
|
@Column(name = "phone", length = 20)
|
||||||
|
private String phone;
|
||||||
|
|
||||||
|
@Column(name = "avatar", length = 500)
|
||||||
|
private String avatar;
|
||||||
|
|
||||||
|
@Column(name = "nickname", length = 100)
|
||||||
|
private String nickname;
|
||||||
|
|
||||||
|
@Column(name = "gender", length = 10)
|
||||||
|
private String gender;
|
||||||
|
|
||||||
|
@Column(name = "birthday")
|
||||||
|
private java.time.LocalDate birthday;
|
||||||
|
|
||||||
|
@Column(name = "address", columnDefinition = "TEXT")
|
||||||
|
private String address;
|
||||||
|
|
||||||
|
@Column(name = "is_active", nullable = false)
|
||||||
|
private Boolean isActive = true;
|
||||||
|
|
||||||
|
@Column(name = "last_login_at")
|
||||||
|
private LocalDateTime lastLoginAt;
|
||||||
|
|
||||||
@Column(name = "created_at", nullable = false)
|
@Column(name = "created_at", nullable = false)
|
||||||
private LocalDateTime createdAt;
|
private LocalDateTime createdAt;
|
||||||
|
|
||||||
|
@Column(name = "updated_at")
|
||||||
|
private LocalDateTime updatedAt;
|
||||||
|
|
||||||
@PrePersist
|
@PrePersist
|
||||||
protected void onCreate() {
|
protected void onCreate() {
|
||||||
createdAt = LocalDateTime.now();
|
createdAt = LocalDateTime.now();
|
||||||
@@ -107,6 +134,78 @@ public class User {
|
|||||||
public void setCreatedAt(LocalDateTime createdAt) {
|
public void setCreatedAt(LocalDateTime createdAt) {
|
||||||
this.createdAt = createdAt;
|
this.createdAt = createdAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getPhone() {
|
||||||
|
return phone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPhone(String phone) {
|
||||||
|
this.phone = phone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAvatar() {
|
||||||
|
return avatar;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAvatar(String avatar) {
|
||||||
|
this.avatar = avatar;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNickname() {
|
||||||
|
return nickname;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNickname(String nickname) {
|
||||||
|
this.nickname = nickname;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getGender() {
|
||||||
|
return gender;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGender(String gender) {
|
||||||
|
this.gender = gender;
|
||||||
|
}
|
||||||
|
|
||||||
|
public java.time.LocalDate getBirthday() {
|
||||||
|
return birthday;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBirthday(java.time.LocalDate birthday) {
|
||||||
|
this.birthday = birthday;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAddress() {
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAddress(String address) {
|
||||||
|
this.address = address;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getIsActive() {
|
||||||
|
return isActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIsActive(Boolean isActive) {
|
||||||
|
this.isActive = isActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getLastLoginAt() {
|
||||||
|
return lastLoginAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLastLoginAt(LocalDateTime lastLoginAt) {
|
||||||
|
this.lastLoginAt = lastLoginAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getUpdatedAt() {
|
||||||
|
return updatedAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUpdatedAt(LocalDateTime updatedAt) {
|
||||||
|
this.updatedAt = updatedAt;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,84 @@
|
|||||||
|
package com.example.demo.model;
|
||||||
|
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "user_activity_stats")
|
||||||
|
public class UserActivityStats {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Column(name = "stat_date", nullable = false, unique = true)
|
||||||
|
private LocalDate statDate;
|
||||||
|
|
||||||
|
@Column(name = "daily_active_users", nullable = false)
|
||||||
|
private Integer dailyActiveUsers = 0;
|
||||||
|
|
||||||
|
@Column(name = "monthly_active_users", nullable = false)
|
||||||
|
private Integer monthlyActiveUsers = 0;
|
||||||
|
|
||||||
|
@Column(name = "new_users", nullable = false)
|
||||||
|
private Integer newUsers = 0;
|
||||||
|
|
||||||
|
@Column(name = "returning_users", nullable = false)
|
||||||
|
private Integer returningUsers = 0;
|
||||||
|
|
||||||
|
@Column(name = "session_count", nullable = false)
|
||||||
|
private Integer sessionCount = 0;
|
||||||
|
|
||||||
|
@Column(name = "avg_session_duration", precision = 10, scale = 2)
|
||||||
|
private BigDecimal avgSessionDuration = BigDecimal.ZERO;
|
||||||
|
|
||||||
|
@Column(name = "created_at", nullable = false)
|
||||||
|
private LocalDateTime createdAt;
|
||||||
|
|
||||||
|
@Column(name = "updated_at")
|
||||||
|
private LocalDateTime updatedAt;
|
||||||
|
|
||||||
|
@PrePersist
|
||||||
|
protected void onCreate() {
|
||||||
|
createdAt = LocalDateTime.now();
|
||||||
|
updatedAt = LocalDateTime.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PreUpdate
|
||||||
|
protected void onUpdate() {
|
||||||
|
updatedAt = LocalDateTime.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getters and Setters
|
||||||
|
public Long getId() { return id; }
|
||||||
|
public void setId(Long id) { this.id = id; }
|
||||||
|
|
||||||
|
public LocalDate getStatDate() { return statDate; }
|
||||||
|
public void setStatDate(LocalDate statDate) { this.statDate = statDate; }
|
||||||
|
|
||||||
|
public Integer getDailyActiveUsers() { return dailyActiveUsers; }
|
||||||
|
public void setDailyActiveUsers(Integer dailyActiveUsers) { this.dailyActiveUsers = dailyActiveUsers; }
|
||||||
|
|
||||||
|
public Integer getMonthlyActiveUsers() { return monthlyActiveUsers; }
|
||||||
|
public void setMonthlyActiveUsers(Integer monthlyActiveUsers) { this.monthlyActiveUsers = monthlyActiveUsers; }
|
||||||
|
|
||||||
|
public Integer getNewUsers() { return newUsers; }
|
||||||
|
public void setNewUsers(Integer newUsers) { this.newUsers = newUsers; }
|
||||||
|
|
||||||
|
public Integer getReturningUsers() { return returningUsers; }
|
||||||
|
public void setReturningUsers(Integer returningUsers) { this.returningUsers = returningUsers; }
|
||||||
|
|
||||||
|
public Integer getSessionCount() { return sessionCount; }
|
||||||
|
public void setSessionCount(Integer sessionCount) { this.sessionCount = sessionCount; }
|
||||||
|
|
||||||
|
public BigDecimal getAvgSessionDuration() { return avgSessionDuration; }
|
||||||
|
public void setAvgSessionDuration(BigDecimal avgSessionDuration) { this.avgSessionDuration = avgSessionDuration; }
|
||||||
|
|
||||||
|
public LocalDateTime getCreatedAt() { return createdAt; }
|
||||||
|
public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
|
||||||
|
|
||||||
|
public LocalDateTime getUpdatedAt() { return updatedAt; }
|
||||||
|
public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; }
|
||||||
|
}
|
||||||
118
demo/src/main/java/com/example/demo/model/UserMembership.java
Normal file
118
demo/src/main/java/com/example/demo/model/UserMembership.java
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
package com.example.demo.model;
|
||||||
|
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "user_memberships")
|
||||||
|
public class UserMembership {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Column(name = "user_id", nullable = false)
|
||||||
|
private Long userId;
|
||||||
|
|
||||||
|
@Column(name = "membership_level_id", nullable = false)
|
||||||
|
private Long membershipLevelId;
|
||||||
|
|
||||||
|
@Column(name = "start_date", nullable = false)
|
||||||
|
private LocalDateTime startDate = LocalDateTime.now();
|
||||||
|
|
||||||
|
@Column(name = "end_date", nullable = false)
|
||||||
|
private LocalDateTime endDate;
|
||||||
|
|
||||||
|
@Column(name = "status", nullable = false)
|
||||||
|
private String status = "ACTIVE";
|
||||||
|
|
||||||
|
@Column(name = "auto_renew", nullable = false)
|
||||||
|
private Boolean autoRenew = false;
|
||||||
|
|
||||||
|
@Column(name = "created_at", nullable = false)
|
||||||
|
private LocalDateTime createdAt = LocalDateTime.now();
|
||||||
|
|
||||||
|
@Column(name = "updated_at")
|
||||||
|
private LocalDateTime updatedAt;
|
||||||
|
|
||||||
|
// 构造函数
|
||||||
|
public UserMembership() {}
|
||||||
|
|
||||||
|
public UserMembership(Long userId, Long membershipLevelId, LocalDateTime endDate) {
|
||||||
|
this.userId = userId;
|
||||||
|
this.membershipLevelId = membershipLevelId;
|
||||||
|
this.endDate = endDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getters and Setters
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getUserId() {
|
||||||
|
return userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserId(Long userId) {
|
||||||
|
this.userId = userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getMembershipLevelId() {
|
||||||
|
return membershipLevelId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMembershipLevelId(Long membershipLevelId) {
|
||||||
|
this.membershipLevelId = membershipLevelId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getStartDate() {
|
||||||
|
return startDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStartDate(LocalDateTime startDate) {
|
||||||
|
this.startDate = startDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getEndDate() {
|
||||||
|
return endDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEndDate(LocalDateTime endDate) {
|
||||||
|
this.endDate = endDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatus(String status) {
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getAutoRenew() {
|
||||||
|
return autoRenew;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAutoRenew(Boolean autoRenew) {
|
||||||
|
this.autoRenew = autoRenew;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getCreatedAt() {
|
||||||
|
return createdAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreatedAt(LocalDateTime createdAt) {
|
||||||
|
this.createdAt = createdAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getUpdatedAt() {
|
||||||
|
return updatedAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUpdatedAt(LocalDateTime updatedAt) {
|
||||||
|
this.updatedAt = updatedAt;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package com.example.demo.repository;
|
||||||
|
|
||||||
|
import com.example.demo.model.MembershipLevel;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface MembershipLevelRepository extends JpaRepository<MembershipLevel, Long> {
|
||||||
|
Optional<MembershipLevel> findByDisplayName(String displayName);
|
||||||
|
Optional<MembershipLevel> findByName(String name);
|
||||||
|
|
||||||
|
@Query("SELECT ml.displayName as levelName, COUNT(um) as userCount " +
|
||||||
|
"FROM MembershipLevel ml LEFT JOIN UserMembership um ON ml.id = um.membershipLevelId AND um.status = 'ACTIVE' " +
|
||||||
|
"GROUP BY ml.id, ml.displayName")
|
||||||
|
List<java.util.Map<String, Object>> findMembershipStats();
|
||||||
|
}
|
||||||
@@ -190,4 +190,10 @@ public interface OrderRepository extends JpaRepository<Order, Long> {
|
|||||||
*/
|
*/
|
||||||
@Query("SELECT SUM(o.totalAmount) FROM Order o WHERE o.user = :user AND o.status = :status")
|
@Query("SELECT SUM(o.totalAmount) FROM Order o WHERE o.user = :user AND o.status = :status")
|
||||||
BigDecimal sumTotalAmountByUserAndStatus(@Param("user") User user, @Param("status") OrderStatus status);
|
BigDecimal sumTotalAmountByUserAndStatus(@Param("user") User user, @Param("status") OrderStatus status);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取最近的订单(用于仪表盘)
|
||||||
|
*/
|
||||||
|
@Query("SELECT o FROM Order o ORDER BY o.createdAt DESC")
|
||||||
|
List<Order> findRecentOrders(org.springframework.data.domain.Pageable pageable);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,4 +36,30 @@ public interface PaymentRepository extends JpaRepository<Payment, Long> {
|
|||||||
* 统计用户指定状态的支付记录数量
|
* 统计用户指定状态的支付记录数量
|
||||||
*/
|
*/
|
||||||
long countByUserIdAndStatus(Long userId, PaymentStatus status);
|
long countByUserIdAndStatus(Long userId, PaymentStatus status);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取今日收入
|
||||||
|
*/
|
||||||
|
@Query("SELECT SUM(p.amount) FROM Payment p WHERE p.status = 'COMPLETED' AND p.paidAt BETWEEN :startTime AND :endTime")
|
||||||
|
Double findTodayRevenue(@Param("startTime") java.time.LocalDateTime startTime, @Param("endTime") java.time.LocalDateTime endTime);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取总收入
|
||||||
|
*/
|
||||||
|
@Query("SELECT SUM(p.amount) FROM Payment p WHERE p.status = 'COMPLETED'")
|
||||||
|
Double findTotalRevenue();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定日期范围的收入
|
||||||
|
*/
|
||||||
|
@Query("SELECT SUM(p.amount) FROM Payment p WHERE p.status = 'COMPLETED' AND p.paidAt BETWEEN :startTime AND :endTime")
|
||||||
|
Double findRevenueByDateRange(@Param("startTime") java.time.LocalDateTime startTime, @Param("endTime") java.time.LocalDateTime endTime);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定年份的月度收入数据
|
||||||
|
*/
|
||||||
|
@Query("SELECT MONTH(p.paidAt) as month, SUM(p.amount) as revenue, COUNT(p) as orderCount " +
|
||||||
|
"FROM Payment p WHERE p.status = 'COMPLETED' AND YEAR(p.paidAt) = :year " +
|
||||||
|
"GROUP BY MONTH(p.paidAt) ORDER BY MONTH(p.paidAt)")
|
||||||
|
List<java.util.Map<String, Object>> findMonthlyRevenueByYear(@Param("year") int year);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,76 @@
|
|||||||
|
package com.example.demo.repository;
|
||||||
|
|
||||||
|
import com.example.demo.model.UserActivityStats;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
import org.springframework.data.repository.query.Param;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface UserActivityStatsRepository extends JpaRepository<UserActivityStats, Long> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据日期查找日活用户数
|
||||||
|
*/
|
||||||
|
@Query("SELECT uas.dailyActiveUsers FROM UserActivityStats uas WHERE uas.statDate = :date")
|
||||||
|
Integer findDailyActiveUsersByDate(@Param("date") LocalDate date);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定年份的月度日活用户数据
|
||||||
|
*/
|
||||||
|
@Query("SELECT MONTH(uas.statDate) as month, " +
|
||||||
|
"AVG(uas.dailyActiveUsers) as avgDailyActive, " +
|
||||||
|
"MAX(uas.dailyActiveUsers) as maxDailyActive, " +
|
||||||
|
"MIN(uas.dailyActiveUsers) as minDailyActive " +
|
||||||
|
"FROM UserActivityStats uas " +
|
||||||
|
"WHERE YEAR(uas.statDate) = :year " +
|
||||||
|
"GROUP BY MONTH(uas.statDate) " +
|
||||||
|
"ORDER BY MONTH(uas.statDate)")
|
||||||
|
List<java.util.Map<String, Object>> findMonthlyActiveUsers(@Param("year") int year);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定年份的每日日活用户数据
|
||||||
|
*/
|
||||||
|
@Query("SELECT DAYOFYEAR(uas.statDate) as dayOfYear, " +
|
||||||
|
"WEEK(uas.statDate) as weekOfYear, " +
|
||||||
|
"uas.dailyActiveUsers as dailyActiveUsers, " +
|
||||||
|
"uas.statDate as statDate " +
|
||||||
|
"FROM UserActivityStats uas " +
|
||||||
|
"WHERE YEAR(uas.statDate) = :year " +
|
||||||
|
"ORDER BY uas.statDate")
|
||||||
|
List<java.util.Map<String, Object>> findDailyActiveUsersByYear(@Param("year") int year);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定月份的平均日活用户数
|
||||||
|
*/
|
||||||
|
@Query("SELECT AVG(uas.dailyActiveUsers) FROM UserActivityStats uas " +
|
||||||
|
"WHERE YEAR(uas.statDate) = :year AND MONTH(uas.statDate) = :month")
|
||||||
|
Double findAverageDailyActiveUsersByMonth(@Param("year") int year, @Param("month") int month);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定年份的平均日活用户数
|
||||||
|
*/
|
||||||
|
@Query("SELECT AVG(uas.dailyActiveUsers) FROM UserActivityStats uas " +
|
||||||
|
"WHERE YEAR(uas.statDate) = :year")
|
||||||
|
Double findAverageDailyActiveUsersByYear(@Param("year") int year);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取最新的统计数据
|
||||||
|
*/
|
||||||
|
Optional<UserActivityStats> findTopByOrderByStatDateDesc();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定日期范围的统计数据
|
||||||
|
*/
|
||||||
|
List<UserActivityStats> findByStatDateBetween(LocalDate startDate, LocalDate endDate);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定年份的所有统计数据
|
||||||
|
*/
|
||||||
|
List<UserActivityStats> findByStatDateYear(int year);
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package com.example.demo.repository;
|
||||||
|
|
||||||
|
import com.example.demo.model.UserMembership;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface UserMembershipRepository extends JpaRepository<UserMembership, Long> {
|
||||||
|
Optional<UserMembership> findByUserIdAndStatus(Long userId, String status);
|
||||||
|
|
||||||
|
long countByStatus(String status);
|
||||||
|
}
|
||||||
@@ -25,3 +25,6 @@ public class PlainTextPasswordEncoder implements PasswordEncoder {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -489,6 +489,40 @@ public class OrderService {
|
|||||||
return stats;
|
return stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除订单
|
||||||
|
*/
|
||||||
|
public int deleteOrdersByIds(List<Long> orderIds) {
|
||||||
|
try {
|
||||||
|
int deletedCount = 0;
|
||||||
|
|
||||||
|
for (Long orderId : orderIds) {
|
||||||
|
try {
|
||||||
|
Order order = orderRepository.findById(orderId)
|
||||||
|
.orElseThrow(() -> new RuntimeException("订单不存在:" + orderId));
|
||||||
|
|
||||||
|
// 只有已取消或已退款的订单才能删除
|
||||||
|
if (order.getStatus() == OrderStatus.CANCELLED || order.getStatus() == OrderStatus.REFUNDED) {
|
||||||
|
orderRepository.delete(order);
|
||||||
|
deletedCount++;
|
||||||
|
logger.info("订单删除成功,订单号:{}", order.getOrderNumber());
|
||||||
|
} else {
|
||||||
|
logger.warn("订单状态不允许删除,订单号:{},状态:{}", order.getOrderNumber(), order.getStatus());
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.warn("删除订单失败,订单ID:{}", orderId, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info("批量删除订单完成,成功删除:{},总数:{}", deletedCount, orderIds.size());
|
||||||
|
return deletedCount;
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("批量删除订单失败:", e);
|
||||||
|
throw new RuntimeException("批量删除订单失败:" + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取用户订单统计
|
* 获取用户订单统计
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,19 +1,124 @@
|
|||||||
-- 示例用户数据
|
-- 用户数据
|
||||||
-- 用户名: demo, 密码: demo
|
INSERT IGNORE INTO users (username, email, password_hash, role, points, phone, nickname, gender, birthday, address) VALUES
|
||||||
INSERT IGNORE INTO users (username, email, password_hash, role, points) VALUES ('demo', 'demo@example.com', 'demo', 'ROLE_USER', 100);
|
('admin', 'admin@example.com', 'admin123', 'ROLE_ADMIN', 200, '15538239326', '管理员', 'M', '1990-01-01', '北京市朝阳区'),
|
||||||
|
('demo', 'demo@example.com', 'demo', 'ROLE_USER', 100, '13800138000', '演示用户', 'M', '1995-05-15', '上海市浦东新区'),
|
||||||
|
('testuser', 'testuser@example.com', 'test123', 'ROLE_USER', 75, '13900139000', '测试用户', 'F', '1992-08-20', '广州市天河区'),
|
||||||
|
('mingzi_FBx7foZYDS7inLQb', 'mingzi@example.com', '123456', 'ROLE_USER', 25, '13700137000', '名字用户', 'M', '1988-12-10', '深圳市南山区'),
|
||||||
|
('15538239326', '15538239326@example.com', '0627', 'ROLE_ADMIN', 50, '15538239326', '手机用户', 'F', '1993-03-25', '杭州市西湖区'),
|
||||||
|
('user001', 'user001@example.com', 'password123', 'ROLE_USER', 150, '13600136000', '用户001', 'M', '1991-07-12', '成都市锦江区'),
|
||||||
|
('user002', 'user002@example.com', 'password123', 'ROLE_USER', 80, '13500135000', '用户002', 'F', '1994-11-08', '武汉市江汉区'),
|
||||||
|
('user003', 'user003@example.com', 'password123', 'ROLE_USER', 200, '13400134000', '用户003', 'M', '1989-04-18', '西安市雁塔区'),
|
||||||
|
('user004', 'user004@example.com', 'password123', 'ROLE_USER', 120, '13300133000', '用户004', 'F', '1996-09-30', '南京市鼓楼区'),
|
||||||
|
('user005', 'user005@example.com', 'password123', 'ROLE_USER', 90, '13200132000', '用户005', 'M', '1990-06-22', '重庆市渝中区');
|
||||||
|
|
||||||
-- 用户名: admin, 密码: admin123
|
-- 会员等级数据
|
||||||
INSERT IGNORE INTO users (username, email, password_hash, role, points) VALUES ('admin', 'admin@example.com', 'admin123', 'ROLE_ADMIN', 200);
|
INSERT IGNORE INTO membership_levels (name, display_name, description, price, duration_days, points_bonus, features) VALUES
|
||||||
|
('standard', '标准会员', '基础会员服务,包含基本功能', 29.00, 30, 50, '{"video_quality": "720p", "storage": "5GB", "support": "email"}'),
|
||||||
|
('professional', '专业会员', '专业会员服务,包含高级功能', 99.00, 30, 200, '{"video_quality": "1080p", "storage": "20GB", "support": "priority", "api_access": true}'),
|
||||||
|
('enterprise', '企业会员', '企业级服务,包含所有功能', 299.00, 30, 500, '{"video_quality": "4K", "storage": "100GB", "support": "dedicated", "api_access": true, "custom_branding": true}');
|
||||||
|
|
||||||
-- 测试用户1: 用户名: testuser, 密码: test123
|
-- 用户会员信息
|
||||||
INSERT IGNORE INTO users (username, email, password_hash, role, points) VALUES ('testuser', 'testuser@example.com', 'test123', 'ROLE_USER', 75);
|
INSERT IGNORE INTO user_memberships (user_id, membership_level_id, start_date, end_date, status, auto_renew) VALUES
|
||||||
|
(1, 2, '2024-01-01 00:00:00', '2025-12-31 23:59:59', 'ACTIVE', true),
|
||||||
|
(2, 1, '2024-01-01 00:00:00', '2025-12-31 23:59:59', 'ACTIVE', false),
|
||||||
|
(3, 1, '2024-01-01 00:00:00', '2025-12-31 23:59:59', 'ACTIVE', false),
|
||||||
|
(4, 2, '2024-01-01 00:00:00', '2025-12-31 23:59:59', 'ACTIVE', true),
|
||||||
|
(5, 2, '2024-01-01 00:00:00', '2025-12-31 23:59:59', 'ACTIVE', true),
|
||||||
|
(6, 1, '2024-01-01 00:00:00', '2025-12-31 23:59:59', 'ACTIVE', false),
|
||||||
|
(7, 1, '2024-01-01 00:00:00', '2025-12-31 23:59:59', 'ACTIVE', false),
|
||||||
|
(8, 2, '2024-01-01 00:00:00', '2025-12-31 23:59:59', 'ACTIVE', true),
|
||||||
|
(9, 1, '2024-01-01 00:00:00', '2025-12-31 23:59:59', 'ACTIVE', false),
|
||||||
|
(10, 1, '2024-01-01 00:00:00', '2025-12-31 23:59:59', 'ACTIVE', false);
|
||||||
|
|
||||||
-- 测试用户2: 用户名: mingzi_FBx7foZYDS7inLQb, 密码: 123456 (对应个人主页的用户名)
|
-- 订单数据
|
||||||
INSERT IGNORE INTO users (username, email, password_hash, role, points) VALUES ('mingzi_FBx7foZYDS7inLQb', 'mingzi@example.com', '123456', 'ROLE_USER', 25);
|
INSERT IGNORE INTO orders (order_number, total_amount, currency, status, order_type, description, user_id, created_at) VALUES
|
||||||
|
('ORD20240101001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 1, '2024-01-01 10:00:00'),
|
||||||
|
('ORD20240101002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 2, '2024-01-01 11:00:00'),
|
||||||
|
('ORD20240101003', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 3, '2024-01-01 12:00:00'),
|
||||||
|
('ORD20240101004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 4, '2024-01-01 13:00:00'),
|
||||||
|
('ORD20240101005', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 5, '2024-01-01 14:00:00'),
|
||||||
|
('ORD20240101006', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 6, '2024-01-01 15:00:00'),
|
||||||
|
('ORD20240101007', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 7, '2024-01-01 16:00:00'),
|
||||||
|
('ORD20240101008', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 8, '2024-01-01 17:00:00'),
|
||||||
|
('ORD20240101009', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 9, '2024-01-01 18:00:00'),
|
||||||
|
('ORD20240101010', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 10, '2024-01-01 19:00:00'),
|
||||||
|
('ORD20240102001', 199.00, 'CNY', 'PENDING', 'PRODUCT', '视频生成服务包', 1, '2024-01-02 09:00:00'),
|
||||||
|
('ORD20240102002', 99.00, 'CNY', 'PROCESSING', 'PRODUCT', '高级视频编辑', 2, '2024-01-02 10:00:00'),
|
||||||
|
('ORD20240102003', 299.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '企业会员订阅', 3, '2024-01-02 11:00:00'),
|
||||||
|
('ORD20240102004', 49.00, 'CNY', 'CANCELLED', 'PRODUCT', '基础视频生成', 4, '2024-01-02 12:00:00'),
|
||||||
|
('ORD20240102005', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 5, '2024-01-02 13:00:00');
|
||||||
|
|
||||||
-- 手机号测试用户: 用户名: 15538239326, 密码: 0627
|
-- 订单商品数据
|
||||||
INSERT IGNORE INTO users (username, email, password_hash, role, points) VALUES ('15538239326', '15538239326@example.com', '0627', 'ROLE_USER', 50);
|
INSERT IGNORE INTO order_items (product_name, product_description, unit_price, quantity, subtotal, order_id) VALUES
|
||||||
|
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 1),
|
||||||
|
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 2),
|
||||||
|
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 3),
|
||||||
|
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 4),
|
||||||
|
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 5),
|
||||||
|
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 6),
|
||||||
|
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 7),
|
||||||
|
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 8),
|
||||||
|
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 9),
|
||||||
|
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 10),
|
||||||
|
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 11),
|
||||||
|
('高级视频编辑', '专业级视频编辑服务', 99.00, 1, 99.00, 12),
|
||||||
|
('企业会员订阅', '30天企业会员服务', 299.00, 1, 299.00, 13),
|
||||||
|
('基础视频生成', '单次视频生成服务', 49.00, 1, 49.00, 14),
|
||||||
|
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 15);
|
||||||
|
|
||||||
-- 更新现有用户的积分(如果还没有设置)
|
-- 支付数据
|
||||||
UPDATE users SET points = 50 WHERE points IS NULL OR points = 0;
|
INSERT IGNORE INTO payments (order_id, amount, currency, payment_method, status, description, user_id, created_at, paid_at) VALUES
|
||||||
|
('ORD20240101001', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业会员订阅', 1, '2024-01-01 10:00:00', '2024-01-01 10:05:00'),
|
||||||
|
('ORD20240101002', 29.00, 'CNY', 'WECHAT', 'COMPLETED', '标准会员订阅', 2, '2024-01-01 11:00:00', '2024-01-01 11:02:00'),
|
||||||
|
('ORD20240101003', 29.00, 'CNY', 'ALIPAY', 'COMPLETED', '标准会员订阅', 3, '2024-01-01 12:00:00', '2024-01-01 12:03:00'),
|
||||||
|
('ORD20240101004', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '专业会员订阅', 4, '2024-01-01 13:00:00', '2024-01-01 13:04:00'),
|
||||||
|
('ORD20240101005', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业会员订阅', 5, '2024-01-01 14:00:00', '2024-01-01 14:05:00'),
|
||||||
|
('ORD20240101006', 29.00, 'CNY', 'WECHAT', 'COMPLETED', '标准会员订阅', 6, '2024-01-01 15:00:00', '2024-01-01 15:02:00'),
|
||||||
|
('ORD20240101007', 29.00, 'CNY', 'ALIPAY', 'COMPLETED', '标准会员订阅', 7, '2024-01-01 16:00:00', '2024-01-01 16:03:00'),
|
||||||
|
('ORD20240101008', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '专业会员订阅', 8, '2024-01-01 17:00:00', '2024-01-01 17:04:00'),
|
||||||
|
('ORD20240101009', 29.00, 'CNY', 'ALIPAY', 'COMPLETED', '标准会员订阅', 9, '2024-01-01 18:00:00', '2024-01-01 18:02:00'),
|
||||||
|
('ORD20240101010', 29.00, 'CNY', 'WECHAT', 'COMPLETED', '标准会员订阅', 10, '2024-01-01 19:00:00', '2024-01-01 19:03:00'),
|
||||||
|
('ORD20240102001', 199.00, 'CNY', 'ALIPAY', 'PENDING', '视频生成服务包', 1, '2024-01-02 09:00:00', NULL),
|
||||||
|
('ORD20240102002', 99.00, 'CNY', 'WECHAT', 'PROCESSING', '高级视频编辑', 2, '2024-01-02 10:00:00', NULL),
|
||||||
|
('ORD20240102003', 299.00, 'CNY', 'ALIPAY', 'COMPLETED', '企业会员订阅', 3, '2024-01-02 11:00:00', '2024-01-02 11:05:00'),
|
||||||
|
('ORD20240102004', 49.00, 'CNY', 'WECHAT', 'CANCELLED', '基础视频生成', 4, '2024-01-02 12:00:00', NULL),
|
||||||
|
('ORD20240102005', 149.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业视频制作', 5, '2024-01-02 13:00:00', '2024-01-02 13:04:00');
|
||||||
|
|
||||||
|
-- 视频生成任务数据
|
||||||
|
INSERT IGNORE INTO video_tasks (task_id, user_id, task_type, title, description, input_text, status, progress, created_at, completed_at) VALUES
|
||||||
|
('TASK20240101001', 1, 'TEXT_TO_VIDEO', '产品介绍视频', '为公司新产品制作的介绍视频', '这是一款革命性的AI产品,能够帮助用户快速生成高质量的视频内容...', 'COMPLETED', 100, '2024-01-01 10:00:00', '2024-01-01 10:30:00'),
|
||||||
|
('TASK20240101002', 2, 'IMAGE_TO_VIDEO', '风景动画', '将静态风景图片转换为动态视频', NULL, 'COMPLETED', 100, '2024-01-01 11:00:00', '2024-01-01 11:25:00'),
|
||||||
|
('TASK20240101003', 3, 'STORYBOARD_VIDEO', '故事板视频', '基于故事板创建的视频', '从前有一个小村庄,村民们过着平静的生活...', 'PROCESSING', 75, '2024-01-01 12:00:00', NULL),
|
||||||
|
('TASK20240101004', 4, 'TEXT_TO_VIDEO', '教育视频', '在线教育课程视频', '今天我们来学习Vue.js的基础知识...', 'COMPLETED', 100, '2024-01-01 13:00:00', '2024-01-01 13:35:00'),
|
||||||
|
('TASK20240101005', 5, 'IMAGE_TO_VIDEO', '产品展示', '产品图片转视频展示', NULL, 'COMPLETED', 100, '2024-01-01 14:00:00', '2024-01-01 14:20:00'),
|
||||||
|
('TASK20240101006', 6, 'TEXT_TO_VIDEO', '营销视频', '产品营销推广视频', '限时优惠!现在购买享受8折优惠...', 'PENDING', 0, '2024-01-01 15:00:00', NULL),
|
||||||
|
('TASK20240101007', 7, 'STORYBOARD_VIDEO', '动画短片', '创意动画短片制作', '在一个遥远的星球上,住着一群可爱的小精灵...', 'COMPLETED', 100, '2024-01-01 16:00:00', '2024-01-01 16:45:00'),
|
||||||
|
('TASK20240101008', 8, 'TEXT_TO_VIDEO', '技术分享', '技术分享会视频', '今天分享的主题是微服务架构的设计原则...', 'PROCESSING', 60, '2024-01-01 17:00:00', NULL),
|
||||||
|
('TASK20240101009', 9, 'IMAGE_TO_VIDEO', '艺术创作', '艺术作品动态展示', NULL, 'COMPLETED', 100, '2024-01-01 18:00:00', '2024-01-01 18:15:00'),
|
||||||
|
('TASK20240101010', 10, 'TEXT_TO_VIDEO', '新闻播报', '新闻播报视频', '今日要闻:科技公司发布最新AI技术...', 'FAILED', 0, '2024-01-01 19:00:00', NULL);
|
||||||
|
|
||||||
|
-- 用户作品数据
|
||||||
|
INSERT IGNORE INTO user_works (user_id, title, description, work_type, cover_image, video_url, tags, view_count, like_count, created_at) VALUES
|
||||||
|
(1, '产品介绍视频', '为公司新产品制作的介绍视频', 'VIDEO', '/images/covers/product_intro.jpg', '/videos/product_intro.mp4', '产品,介绍,商业', 1250, 89, '2024-01-01 10:30:00'),
|
||||||
|
(2, '风景动画', '将静态风景图片转换为动态视频', 'VIDEO', '/images/covers/landscape.jpg', '/videos/landscape.mp4', '风景,动画,自然', 890, 67, '2024-01-01 11:25:00'),
|
||||||
|
(3, '故事板视频', '基于故事板创建的视频', 'VIDEO', '/images/covers/storyboard.jpg', '/videos/storyboard.mp4', '故事,创意,动画', 2100, 156, '2024-01-01 12:30:00'),
|
||||||
|
(4, '教育视频', '在线教育课程视频', 'VIDEO', '/images/covers/education.jpg', '/videos/education.mp4', '教育,课程,学习', 3200, 234, '2024-01-01 13:35:00'),
|
||||||
|
(5, '产品展示', '产品图片转视频展示', 'VIDEO', '/images/covers/product_show.jpg', '/videos/product_show.mp4', '产品,展示,商业', 1560, 112, '2024-01-01 14:20:00'),
|
||||||
|
(6, '营销视频', '产品营销推广视频', 'VIDEO', '/images/covers/marketing.jpg', '/videos/marketing.mp4', '营销,推广,商业', 2800, 198, '2024-01-01 15:30:00'),
|
||||||
|
(7, '动画短片', '创意动画短片制作', 'VIDEO', '/images/covers/animation.jpg', '/videos/animation.mp4', '动画,创意,短片', 4500, 345, '2024-01-01 16:45:00'),
|
||||||
|
(8, '技术分享', '技术分享会视频', 'VIDEO', '/images/covers/tech_share.jpg', '/videos/tech_share.mp4', '技术,分享,编程', 1800, 134, '2024-01-01 17:30:00'),
|
||||||
|
(9, '艺术创作', '艺术作品动态展示', 'VIDEO', '/images/covers/art.jpg', '/videos/art.mp4', '艺术,创作,美学', 950, 78, '2024-01-01 18:15:00'),
|
||||||
|
(10, '新闻播报', '新闻播报视频', 'VIDEO', '/images/covers/news.jpg', '/videos/news.mp4', '新闻,播报,资讯', 1200, 89, '2024-01-01 19:30:00');
|
||||||
|
|
||||||
|
-- 系统配置数据
|
||||||
|
INSERT IGNORE INTO system_configs (config_key, config_value, description, config_type, is_public) VALUES
|
||||||
|
('site_name', 'AIGC视频生成平台', '网站名称', 'STRING', true),
|
||||||
|
('site_description', '专业的AI视频生成服务平台', '网站描述', 'STRING', true),
|
||||||
|
('max_file_size', '100', '最大文件上传大小(MB)', 'NUMBER', false),
|
||||||
|
('supported_formats', '["mp4", "avi", "mov", "wmv"]', '支持的视频格式', 'JSON', true),
|
||||||
|
('default_video_quality', '1080p', '默认视频质量', 'STRING', false),
|
||||||
|
('max_video_duration', '300', '最大视频时长(秒)', 'NUMBER', false),
|
||||||
|
('api_rate_limit', '100', 'API调用频率限制(次/小时)', 'NUMBER', false),
|
||||||
|
('maintenance_mode', 'false', '维护模式开关', 'BOOLEAN', false),
|
||||||
|
('registration_enabled', 'true', '用户注册开关', 'BOOLEAN', true),
|
||||||
|
('email_verification', 'false', '邮箱验证开关', 'BOOLEAN', false);
|
||||||
207
demo/src/main/resources/order_items_12months.sql
Normal file
207
demo/src/main/resources/order_items_12months.sql
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
-- 12个月订单商品数据
|
||||||
|
-- 对应orders_12months.sql中的订单
|
||||||
|
|
||||||
|
INSERT IGNORE INTO order_items (product_name, product_description, unit_price, quantity, subtotal, order_id) VALUES
|
||||||
|
-- 2024年1月订单商品
|
||||||
|
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 1),
|
||||||
|
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 2),
|
||||||
|
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 3),
|
||||||
|
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 4),
|
||||||
|
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 5),
|
||||||
|
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 6),
|
||||||
|
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 7),
|
||||||
|
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 8),
|
||||||
|
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 9),
|
||||||
|
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 10),
|
||||||
|
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 11),
|
||||||
|
('高级视频编辑', '专业级视频编辑服务', 99.00, 1, 99.00, 12),
|
||||||
|
('企业会员订阅', '30天企业会员服务', 299.00, 1, 299.00, 13),
|
||||||
|
('基础视频生成', '单次视频生成服务', 49.00, 1, 49.00, 14),
|
||||||
|
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 15),
|
||||||
|
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 16),
|
||||||
|
('高级视频编辑', '专业级视频编辑服务', 99.00, 1, 99.00, 17),
|
||||||
|
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 18),
|
||||||
|
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 19),
|
||||||
|
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 20),
|
||||||
|
|
||||||
|
-- 2024年2月订单商品
|
||||||
|
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 21),
|
||||||
|
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 22),
|
||||||
|
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 23),
|
||||||
|
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 24),
|
||||||
|
('高级视频编辑', '专业级视频编辑服务', 99.00, 1, 99.00, 25),
|
||||||
|
('企业会员订阅', '30天企业会员服务', 299.00, 1, 299.00, 26),
|
||||||
|
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 27),
|
||||||
|
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 28),
|
||||||
|
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 29),
|
||||||
|
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 30),
|
||||||
|
|
||||||
|
-- 2024年3月订单商品
|
||||||
|
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 31),
|
||||||
|
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 32),
|
||||||
|
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 33),
|
||||||
|
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 34),
|
||||||
|
('高级视频编辑', '专业级视频编辑服务', 99.00, 1, 99.00, 35),
|
||||||
|
('企业会员订阅', '30天企业会员服务', 299.00, 1, 299.00, 36),
|
||||||
|
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 37),
|
||||||
|
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 38),
|
||||||
|
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 39),
|
||||||
|
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 40),
|
||||||
|
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 41),
|
||||||
|
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 42),
|
||||||
|
('高级视频编辑', '专业级视频编辑服务', 99.00, 1, 99.00, 43),
|
||||||
|
('企业会员订阅', '30天企业会员服务', 299.00, 1, 299.00, 44),
|
||||||
|
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 45),
|
||||||
|
|
||||||
|
-- 2024年4月订单商品
|
||||||
|
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 46),
|
||||||
|
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 47),
|
||||||
|
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 48),
|
||||||
|
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 49),
|
||||||
|
('高级视频编辑', '专业级视频编辑服务', 99.00, 1, 99.00, 50),
|
||||||
|
('企业会员订阅', '30天企业会员服务', 299.00, 1, 299.00, 51),
|
||||||
|
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 52),
|
||||||
|
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 53),
|
||||||
|
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 54),
|
||||||
|
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 55),
|
||||||
|
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 56),
|
||||||
|
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 57),
|
||||||
|
('高级视频编辑', '专业级视频编辑服务', 99.00, 1, 99.00, 58),
|
||||||
|
('企业会员订阅', '30天企业会员服务', 299.00, 1, 299.00, 59),
|
||||||
|
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 60),
|
||||||
|
|
||||||
|
-- 2024年5月订单商品
|
||||||
|
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 61),
|
||||||
|
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 62),
|
||||||
|
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 63),
|
||||||
|
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 64),
|
||||||
|
('高级视频编辑', '专业级视频编辑服务', 99.00, 1, 99.00, 65),
|
||||||
|
('企业会员订阅', '30天企业会员服务', 299.00, 1, 299.00, 66),
|
||||||
|
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 67),
|
||||||
|
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 68),
|
||||||
|
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 69),
|
||||||
|
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 70),
|
||||||
|
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 71),
|
||||||
|
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 72),
|
||||||
|
('高级视频编辑', '专业级视频编辑服务', 99.00, 1, 99.00, 73),
|
||||||
|
('企业会员订阅', '30天企业会员服务', 299.00, 1, 299.00, 74),
|
||||||
|
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 75),
|
||||||
|
|
||||||
|
-- 2024年6月订单商品
|
||||||
|
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 76),
|
||||||
|
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 77),
|
||||||
|
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 78),
|
||||||
|
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 79),
|
||||||
|
('高级视频编辑', '专业级视频编辑服务', 99.00, 1, 99.00, 80),
|
||||||
|
('企业会员订阅', '30天企业会员服务', 299.00, 1, 299.00, 81),
|
||||||
|
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 82),
|
||||||
|
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 83),
|
||||||
|
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 84),
|
||||||
|
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 85),
|
||||||
|
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 86),
|
||||||
|
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 87),
|
||||||
|
('高级视频编辑', '专业级视频编辑服务', 99.00, 1, 99.00, 88),
|
||||||
|
('企业会员订阅', '30天企业会员服务', 299.00, 1, 299.00, 89),
|
||||||
|
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 90),
|
||||||
|
|
||||||
|
-- 2024年7月订单商品
|
||||||
|
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 91),
|
||||||
|
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 92),
|
||||||
|
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 93),
|
||||||
|
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 94),
|
||||||
|
('高级视频编辑', '专业级视频编辑服务', 99.00, 1, 99.00, 95),
|
||||||
|
('企业会员订阅', '30天企业会员服务', 299.00, 1, 299.00, 96),
|
||||||
|
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 97),
|
||||||
|
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 98),
|
||||||
|
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 99),
|
||||||
|
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 100),
|
||||||
|
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 101),
|
||||||
|
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 102),
|
||||||
|
('高级视频编辑', '专业级视频编辑服务', 99.00, 1, 99.00, 103),
|
||||||
|
('企业会员订阅', '30天企业会员服务', 299.00, 1, 299.00, 104),
|
||||||
|
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 105),
|
||||||
|
|
||||||
|
-- 2024年8月订单商品
|
||||||
|
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 106),
|
||||||
|
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 107),
|
||||||
|
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 108),
|
||||||
|
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 109),
|
||||||
|
('高级视频编辑', '专业级视频编辑服务', 99.00, 1, 99.00, 110),
|
||||||
|
('企业会员订阅', '30天企业会员服务', 299.00, 1, 299.00, 111),
|
||||||
|
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 112),
|
||||||
|
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 113),
|
||||||
|
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 114),
|
||||||
|
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 115),
|
||||||
|
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 116),
|
||||||
|
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 117),
|
||||||
|
('高级视频编辑', '专业级视频编辑服务', 99.00, 1, 99.00, 118),
|
||||||
|
('企业会员订阅', '30天企业会员服务', 299.00, 1, 299.00, 119),
|
||||||
|
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 120),
|
||||||
|
|
||||||
|
-- 2024年9月订单商品
|
||||||
|
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 121),
|
||||||
|
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 122),
|
||||||
|
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 123),
|
||||||
|
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 124),
|
||||||
|
('高级视频编辑', '专业级视频编辑服务', 99.00, 1, 99.00, 125),
|
||||||
|
('企业会员订阅', '30天企业会员服务', 299.00, 1, 299.00, 126),
|
||||||
|
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 127),
|
||||||
|
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 128),
|
||||||
|
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 129),
|
||||||
|
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 130),
|
||||||
|
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 131),
|
||||||
|
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 132),
|
||||||
|
('高级视频编辑', '专业级视频编辑服务', 99.00, 1, 99.00, 133),
|
||||||
|
('企业会员订阅', '30天企业会员服务', 299.00, 1, 299.00, 134),
|
||||||
|
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 135),
|
||||||
|
|
||||||
|
-- 2024年10月订单商品
|
||||||
|
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 136),
|
||||||
|
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 137),
|
||||||
|
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 138),
|
||||||
|
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 139),
|
||||||
|
('高级视频编辑', '专业级视频编辑服务', 99.00, 1, 99.00, 140),
|
||||||
|
('企业会员订阅', '30天企业会员服务', 299.00, 1, 299.00, 141),
|
||||||
|
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 142),
|
||||||
|
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 143),
|
||||||
|
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 144),
|
||||||
|
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 145),
|
||||||
|
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 146),
|
||||||
|
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 147),
|
||||||
|
('高级视频编辑', '专业级视频编辑服务', 99.00, 1, 99.00, 148),
|
||||||
|
('企业会员订阅', '30天企业会员服务', 299.00, 1, 299.00, 149),
|
||||||
|
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 150),
|
||||||
|
|
||||||
|
-- 2024年11月订单商品
|
||||||
|
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 151),
|
||||||
|
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 152),
|
||||||
|
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 153),
|
||||||
|
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 154),
|
||||||
|
('高级视频编辑', '专业级视频编辑服务', 99.00, 1, 99.00, 155),
|
||||||
|
('企业会员订阅', '30天企业会员服务', 299.00, 1, 299.00, 156),
|
||||||
|
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 157),
|
||||||
|
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 158),
|
||||||
|
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 159),
|
||||||
|
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 160),
|
||||||
|
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 161),
|
||||||
|
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 162),
|
||||||
|
('高级视频编辑', '专业级视频编辑服务', 99.00, 1, 99.00, 163),
|
||||||
|
('企业会员订阅', '30天企业会员服务', 299.00, 1, 299.00, 164),
|
||||||
|
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 165),
|
||||||
|
|
||||||
|
-- 2024年12月订单商品
|
||||||
|
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 166),
|
||||||
|
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 167),
|
||||||
|
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 168),
|
||||||
|
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 169),
|
||||||
|
('高级视频编辑', '专业级视频编辑服务', 99.00, 1, 99.00, 170),
|
||||||
|
('企业会员订阅', '30天企业会员服务', 299.00, 1, 299.00, 171),
|
||||||
|
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 172),
|
||||||
|
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 173),
|
||||||
|
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 174),
|
||||||
|
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 175),
|
||||||
|
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 176),
|
||||||
|
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 177),
|
||||||
|
('高级视频编辑', '专业级视频编辑服务', 99.00, 1, 99.00, 178),
|
||||||
|
('企业会员订阅', '30天企业会员服务', 299.00, 1, 299.00, 179),
|
||||||
|
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 180);
|
||||||
208
demo/src/main/resources/orders_12months.sql
Normal file
208
demo/src/main/resources/orders_12months.sql
Normal file
@@ -0,0 +1,208 @@
|
|||||||
|
-- 12个月订单数据生成脚本
|
||||||
|
-- 生成2024年1月到12月的订单数据
|
||||||
|
|
||||||
|
-- 订单数据 (2024年1月-12月)
|
||||||
|
INSERT IGNORE INTO orders (order_number, total_amount, currency, status, order_type, description, user_id, created_at) VALUES
|
||||||
|
-- 2024年1月订单
|
||||||
|
('ORD20240101001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 1, '2024-01-01 10:00:00'),
|
||||||
|
('ORD20240101002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 2, '2024-01-01 11:00:00'),
|
||||||
|
('ORD20240101003', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 3, '2024-01-01 12:00:00'),
|
||||||
|
('ORD20240101004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 4, '2024-01-01 13:00:00'),
|
||||||
|
('ORD20240101005', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 5, '2024-01-01 14:00:00'),
|
||||||
|
('ORD20240101006', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 6, '2024-01-01 15:00:00'),
|
||||||
|
('ORD20240101007', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 7, '2024-01-01 16:00:00'),
|
||||||
|
('ORD20240101008', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 8, '2024-01-01 17:00:00'),
|
||||||
|
('ORD20240101009', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 9, '2024-01-01 18:00:00'),
|
||||||
|
('ORD20240101010', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 10, '2024-01-01 19:00:00'),
|
||||||
|
('ORD20240102001', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 1, '2024-01-02 09:00:00'),
|
||||||
|
('ORD20240102002', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 2, '2024-01-02 10:00:00'),
|
||||||
|
('ORD20240102003', 299.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '企业会员订阅', 3, '2024-01-02 11:00:00'),
|
||||||
|
('ORD20240102004', 49.00, 'CNY', 'CANCELLED', 'PRODUCT', '基础视频生成', 4, '2024-01-02 12:00:00'),
|
||||||
|
('ORD20240102005', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 5, '2024-01-02 13:00:00'),
|
||||||
|
('ORD20240115001', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 6, '2024-01-15 14:30:00'),
|
||||||
|
('ORD20240115002', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 7, '2024-01-15 15:45:00'),
|
||||||
|
('ORD20240115003', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 8, '2024-01-15 16:20:00'),
|
||||||
|
('ORD20240128001', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 9, '2024-01-28 10:15:00'),
|
||||||
|
('ORD20240128002', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 10, '2024-01-28 11:30:00'),
|
||||||
|
|
||||||
|
-- 2024年2月订单
|
||||||
|
('ORD20240201001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 1, '2024-02-01 09:00:00'),
|
||||||
|
('ORD20240201002', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 2, '2024-02-01 10:15:00'),
|
||||||
|
('ORD20240201003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-02-01 11:30:00'),
|
||||||
|
('ORD20240201004', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 4, '2024-02-01 14:20:00'),
|
||||||
|
('ORD20240201005', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 5, '2024-02-01 15:45:00'),
|
||||||
|
('ORD20240214001', 299.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '企业会员订阅', 6, '2024-02-14 10:00:00'),
|
||||||
|
('ORD20240214002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 7, '2024-02-14 11:30:00'),
|
||||||
|
('ORD20240214003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 8, '2024-02-14 14:15:00'),
|
||||||
|
('ORD20240225001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 9, '2024-02-25 16:00:00'),
|
||||||
|
('ORD20240225002', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 10, '2024-02-25 17:30:00'),
|
||||||
|
|
||||||
|
-- 2024年3月订单
|
||||||
|
('ORD20240301001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 1, '2024-03-01 09:30:00'),
|
||||||
|
('ORD20240301002', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 2, '2024-03-01 10:45:00'),
|
||||||
|
('ORD20240301003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-03-01 11:20:00'),
|
||||||
|
('ORD20240301004', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 4, '2024-03-01 14:10:00'),
|
||||||
|
('ORD20240301005', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 5, '2024-03-01 15:25:00'),
|
||||||
|
('ORD20240308001', 299.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '企业会员订阅', 6, '2024-03-08 10:00:00'),
|
||||||
|
('ORD20240308002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 7, '2024-03-08 11:15:00'),
|
||||||
|
('ORD20240308003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 8, '2024-03-08 14:30:00'),
|
||||||
|
('ORD20240315001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 9, '2024-03-15 16:45:00'),
|
||||||
|
('ORD20240315002', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 10, '2024-03-15 17:20:00'),
|
||||||
|
('ORD20240322001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 1, '2024-03-22 09:15:00'),
|
||||||
|
('ORD20240322002', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 2, '2024-03-22 10:30:00'),
|
||||||
|
('ORD20240322003', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 3, '2024-03-22 14:45:00'),
|
||||||
|
('ORD20240330001', 299.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '企业会员订阅', 4, '2024-03-30 11:00:00'),
|
||||||
|
('ORD20240330002', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 5, '2024-03-30 15:30:00'),
|
||||||
|
|
||||||
|
-- 2024年4月订单
|
||||||
|
('ORD20240401001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 6, '2024-04-01 09:00:00'),
|
||||||
|
('ORD20240401002', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 7, '2024-04-01 10:20:00'),
|
||||||
|
('ORD20240401003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 8, '2024-04-01 11:40:00'),
|
||||||
|
('ORD20240401004', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 9, '2024-04-01 14:15:00'),
|
||||||
|
('ORD20240401005', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 10, '2024-04-01 15:35:00'),
|
||||||
|
('ORD20240410001', 299.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '企业会员订阅', 1, '2024-04-10 10:30:00'),
|
||||||
|
('ORD20240410002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 2, '2024-04-10 11:45:00'),
|
||||||
|
('ORD20240410003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-04-10 14:20:00'),
|
||||||
|
('ORD20240420001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 4, '2024-04-20 16:10:00'),
|
||||||
|
('ORD20240420002', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 5, '2024-04-20 17:25:00'),
|
||||||
|
('ORD20240420003', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 6, '2024-04-20 18:40:00'),
|
||||||
|
('ORD20240425001', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 7, '2024-04-25 09:15:00'),
|
||||||
|
('ORD20240425002', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 8, '2024-04-25 10:30:00'),
|
||||||
|
('ORD20240425003', 299.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '企业会员订阅', 9, '2024-04-25 14:45:00'),
|
||||||
|
('ORD20240430001', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 10, '2024-04-30 15:20:00'),
|
||||||
|
|
||||||
|
-- 2024年5月订单
|
||||||
|
('ORD20240501001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 1, '2024-05-01 09:30:00'),
|
||||||
|
('ORD20240501002', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 2, '2024-05-01 10:45:00'),
|
||||||
|
('ORD20240501003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-05-01 11:20:00'),
|
||||||
|
('ORD20240501004', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 4, '2024-05-01 14:10:00'),
|
||||||
|
('ORD20240501005', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 5, '2024-05-01 15:25:00'),
|
||||||
|
('ORD20240510001', 299.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '企业会员订阅', 6, '2024-05-10 10:00:00'),
|
||||||
|
('ORD20240510002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 7, '2024-05-10 11:15:00'),
|
||||||
|
('ORD20240510003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 8, '2024-05-10 14:30:00'),
|
||||||
|
('ORD20240520001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 9, '2024-05-20 16:45:00'),
|
||||||
|
('ORD20240520002', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 10, '2024-05-20 17:20:00'),
|
||||||
|
('ORD20240520003', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 1, '2024-05-20 18:35:00'),
|
||||||
|
('ORD20240525001', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 2, '2024-05-25 09:50:00'),
|
||||||
|
('ORD20240525002', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 3, '2024-05-25 11:05:00'),
|
||||||
|
('ORD20240525003', 299.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '企业会员订阅', 4, '2024-05-25 14:20:00'),
|
||||||
|
('ORD20240530001', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 5, '2024-05-30 15:35:00'),
|
||||||
|
|
||||||
|
-- 2024年6月订单
|
||||||
|
('ORD20240601001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 6, '2024-06-01 09:15:00'),
|
||||||
|
('ORD20240601002', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 7, '2024-06-01 10:30:00'),
|
||||||
|
('ORD20240601003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 8, '2024-06-01 11:45:00'),
|
||||||
|
('ORD20240601004', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 9, '2024-06-01 14:00:00'),
|
||||||
|
('ORD20240601005', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 10, '2024-06-01 15:15:00'),
|
||||||
|
('ORD20240615001', 299.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '企业会员订阅', 1, '2024-06-15 10:45:00'),
|
||||||
|
('ORD20240615002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 2, '2024-06-15 12:00:00'),
|
||||||
|
('ORD20240615003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-06-15 14:15:00'),
|
||||||
|
('ORD20240620001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 4, '2024-06-20 16:30:00'),
|
||||||
|
('ORD20240620002', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 5, '2024-06-20 17:45:00'),
|
||||||
|
('ORD20240620003', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 6, '2024-06-20 19:00:00'),
|
||||||
|
('ORD20240625001', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 7, '2024-06-25 09:30:00'),
|
||||||
|
('ORD20240625002', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 8, '2024-06-25 10:45:00'),
|
||||||
|
('ORD20240625003', 299.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '企业会员订阅', 9, '2024-06-25 14:00:00'),
|
||||||
|
('ORD20240630001', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 10, '2024-06-30 15:15:00'),
|
||||||
|
|
||||||
|
-- 2024年7月订单
|
||||||
|
('ORD20240701001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 1, '2024-07-01 09:45:00'),
|
||||||
|
('ORD20240701002', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 2, '2024-07-01 11:00:00'),
|
||||||
|
('ORD20240701003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-07-01 12:15:00'),
|
||||||
|
('ORD20240701004', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 4, '2024-07-01 14:30:00'),
|
||||||
|
('ORD20240701005', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 5, '2024-07-01 15:45:00'),
|
||||||
|
('ORD20240710001', 299.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '企业会员订阅', 6, '2024-07-10 10:20:00'),
|
||||||
|
('ORD20240710002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 7, '2024-07-10 11:35:00'),
|
||||||
|
('ORD20240710003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 8, '2024-07-10 14:50:00'),
|
||||||
|
('ORD20240720001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 9, '2024-07-20 16:05:00'),
|
||||||
|
('ORD20240720002', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 10, '2024-07-20 17:20:00'),
|
||||||
|
('ORD20240720003', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 1, '2024-07-20 18:35:00'),
|
||||||
|
('ORD20240725001', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 2, '2024-07-25 09:50:00'),
|
||||||
|
('ORD20240725002', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 3, '2024-07-25 11:05:00'),
|
||||||
|
('ORD20240725003', 299.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '企业会员订阅', 4, '2024-07-25 14:20:00'),
|
||||||
|
('ORD20240730001', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 5, '2024-07-30 15:35:00'),
|
||||||
|
|
||||||
|
-- 2024年8月订单
|
||||||
|
('ORD20240801001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 6, '2024-08-01 09:30:00'),
|
||||||
|
('ORD20240801002', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 7, '2024-08-01 10:45:00'),
|
||||||
|
('ORD20240801003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 8, '2024-08-01 12:00:00'),
|
||||||
|
('ORD20240801004', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 9, '2024-08-01 14:15:00'),
|
||||||
|
('ORD20240801005', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 10, '2024-08-01 15:30:00'),
|
||||||
|
('ORD20240810001', 299.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '企业会员订阅', 1, '2024-08-10 10:00:00'),
|
||||||
|
('ORD20240810002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 2, '2024-08-10 11:15:00'),
|
||||||
|
('ORD20240810003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-08-10 14:30:00'),
|
||||||
|
('ORD20240820001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 4, '2024-08-20 16:45:00'),
|
||||||
|
('ORD20240820002', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 5, '2024-08-20 18:00:00'),
|
||||||
|
('ORD20240820003', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 6, '2024-08-20 19:15:00'),
|
||||||
|
('ORD20240825001', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 7, '2024-08-25 09:30:00'),
|
||||||
|
('ORD20240825002', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 8, '2024-08-25 10:45:00'),
|
||||||
|
('ORD20240825003', 299.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '企业会员订阅', 9, '2024-08-25 14:00:00'),
|
||||||
|
('ORD20240830001', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 10, '2024-08-30 15:15:00'),
|
||||||
|
|
||||||
|
-- 2024年9月订单
|
||||||
|
('ORD20240901001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 1, '2024-09-01 09:15:00'),
|
||||||
|
('ORD20240901002', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 2, '2024-09-01 10:30:00'),
|
||||||
|
('ORD20240901003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-09-01 11:45:00'),
|
||||||
|
('ORD20240901004', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 4, '2024-09-01 14:00:00'),
|
||||||
|
('ORD20240901005', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 5, '2024-09-01 15:15:00'),
|
||||||
|
('ORD20240910001', 299.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '企业会员订阅', 6, '2024-09-10 10:45:00'),
|
||||||
|
('ORD20240910002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 7, '2024-09-10 12:00:00'),
|
||||||
|
('ORD20240910003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 8, '2024-09-10 14:15:00'),
|
||||||
|
('ORD20240920001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 9, '2024-09-20 16:30:00'),
|
||||||
|
('ORD20240920002', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 10, '2024-09-20 17:45:00'),
|
||||||
|
('ORD20240920003', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 1, '2024-09-20 19:00:00'),
|
||||||
|
('ORD20240925001', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 2, '2024-09-25 09:15:00'),
|
||||||
|
('ORD20240925002', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 3, '2024-09-25 10:30:00'),
|
||||||
|
('ORD20240925003', 299.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '企业会员订阅', 4, '2024-09-25 14:45:00'),
|
||||||
|
('ORD20240930001', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 5, '2024-09-30 15:00:00'),
|
||||||
|
|
||||||
|
-- 2024年10月订单
|
||||||
|
('ORD20241001001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 6, '2024-10-01 09:45:00'),
|
||||||
|
('ORD20241001002', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 7, '2024-10-01 11:00:00'),
|
||||||
|
('ORD20241001003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 8, '2024-10-01 12:15:00'),
|
||||||
|
('ORD20241001004', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 9, '2024-10-01 14:30:00'),
|
||||||
|
('ORD20241001005', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 10, '2024-10-01 15:45:00'),
|
||||||
|
('ORD20241010001', 299.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '企业会员订阅', 1, '2024-10-10 10:20:00'),
|
||||||
|
('ORD20241010002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 2, '2024-10-10 11:35:00'),
|
||||||
|
('ORD20241010003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-10-10 14:50:00'),
|
||||||
|
('ORD20241020001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 4, '2024-10-20 16:05:00'),
|
||||||
|
('ORD20241020002', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 5, '2024-10-20 17:20:00'),
|
||||||
|
('ORD20241020003', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 6, '2024-10-20 18:35:00'),
|
||||||
|
('ORD20241025001', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 7, '2024-10-25 09:50:00'),
|
||||||
|
('ORD20241025002', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 8, '2024-10-25 11:05:00'),
|
||||||
|
('ORD20241025003', 299.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '企业会员订阅', 9, '2024-10-25 14:20:00'),
|
||||||
|
('ORD20241030001', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 10, '2024-10-30 15:35:00'),
|
||||||
|
|
||||||
|
-- 2024年11月订单
|
||||||
|
('ORD20241101001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 1, '2024-11-01 09:30:00'),
|
||||||
|
('ORD20241101002', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 2, '2024-11-01 10:45:00'),
|
||||||
|
('ORD20241101003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-11-01 12:00:00'),
|
||||||
|
('ORD20241101004', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 4, '2024-11-01 14:15:00'),
|
||||||
|
('ORD20241101005', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 5, '2024-11-01 15:30:00'),
|
||||||
|
('ORD20241111001', 299.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '企业会员订阅', 6, '2024-11-11 10:00:00'),
|
||||||
|
('ORD20241111002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 7, '2024-11-11 11:15:00'),
|
||||||
|
('ORD20241111003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 8, '2024-11-11 14:30:00'),
|
||||||
|
('ORD20241120001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 9, '2024-11-20 16:45:00'),
|
||||||
|
('ORD20241120002', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 10, '2024-11-20 18:00:00'),
|
||||||
|
('ORD20241120003', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 1, '2024-11-20 19:15:00'),
|
||||||
|
('ORD20241125001', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 2, '2024-11-25 09:30:00'),
|
||||||
|
('ORD20241125002', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 3, '2024-11-25 10:45:00'),
|
||||||
|
('ORD20241125003', 299.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '企业会员订阅', 4, '2024-11-25 14:00:00'),
|
||||||
|
('ORD20241130001', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 5, '2024-11-30 15:15:00'),
|
||||||
|
|
||||||
|
-- 2024年12月订单
|
||||||
|
('ORD20241201001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 6, '2024-12-01 09:15:00'),
|
||||||
|
('ORD20241201002', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 7, '2024-12-01 10:30:00'),
|
||||||
|
('ORD20241201003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 8, '2024-12-01 11:45:00'),
|
||||||
|
('ORD20241201004', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 9, '2024-12-01 14:00:00'),
|
||||||
|
('ORD20241201005', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 10, '2024-12-01 15:15:00'),
|
||||||
|
('ORD20241210001', 299.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '企业会员订阅', 1, '2024-12-10 10:45:00'),
|
||||||
|
('ORD20241210002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 2, '2024-12-10 12:00:00'),
|
||||||
|
('ORD20241210003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-12-10 14:15:00'),
|
||||||
|
('ORD20241220001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 4, '2024-12-20 16:30:00'),
|
||||||
|
('ORD20241220002', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 5, '2024-12-20 17:45:00'),
|
||||||
|
('ORD20241220003', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 6, '2024-12-20 19:00:00'),
|
||||||
|
('ORD20241225001', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 7, '2024-12-25 09:15:00'),
|
||||||
|
('ORD20241225002', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 8, '2024-12-25 10:30:00'),
|
||||||
|
('ORD20241225003', 299.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '企业会员订阅', 9, '2024-12-25 14:45:00'),
|
||||||
|
('ORD20241230001', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 10, '2024-12-30 15:00:00');
|
||||||
207
demo/src/main/resources/payments_12months.sql
Normal file
207
demo/src/main/resources/payments_12months.sql
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
-- 12个月支付数据
|
||||||
|
-- 对应orders_12months.sql中的订单
|
||||||
|
|
||||||
|
INSERT IGNORE INTO payments (order_id, amount, currency, payment_method, status, description, user_id, created_at, paid_at) VALUES
|
||||||
|
-- 2024年1月支付数据
|
||||||
|
('ORD20240101001', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业会员订阅', 1, '2024-01-01 10:00:00', '2024-01-01 10:05:00'),
|
||||||
|
('ORD20240101002', 29.00, 'CNY', 'WECHAT', 'COMPLETED', '标准会员订阅', 2, '2024-01-01 11:00:00', '2024-01-01 11:02:00'),
|
||||||
|
('ORD20240101003', 29.00, 'CNY', 'ALIPAY', 'COMPLETED', '标准会员订阅', 3, '2024-01-01 12:00:00', '2024-01-01 12:03:00'),
|
||||||
|
('ORD20240101004', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '专业会员订阅', 4, '2024-01-01 13:00:00', '2024-01-01 13:04:00'),
|
||||||
|
('ORD20240101005', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业会员订阅', 5, '2024-01-01 14:00:00', '2024-01-01 14:05:00'),
|
||||||
|
('ORD20240101006', 29.00, 'CNY', 'WECHAT', 'COMPLETED', '标准会员订阅', 6, '2024-01-01 15:00:00', '2024-01-01 15:02:00'),
|
||||||
|
('ORD20240101007', 29.00, 'CNY', 'ALIPAY', 'COMPLETED', '标准会员订阅', 7, '2024-01-01 16:00:00', '2024-01-01 16:03:00'),
|
||||||
|
('ORD20240101008', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '专业会员订阅', 8, '2024-01-01 17:00:00', '2024-01-01 17:04:00'),
|
||||||
|
('ORD20240101009', 29.00, 'CNY', 'ALIPAY', 'COMPLETED', '标准会员订阅', 9, '2024-01-01 18:00:00', '2024-01-01 18:02:00'),
|
||||||
|
('ORD20240101010', 29.00, 'CNY', 'WECHAT', 'COMPLETED', '标准会员订阅', 10, '2024-01-01 19:00:00', '2024-01-01 19:03:00'),
|
||||||
|
('ORD20240102001', 199.00, 'CNY', 'ALIPAY', 'COMPLETED', '视频生成服务包', 1, '2024-01-02 09:00:00', '2024-01-02 09:05:00'),
|
||||||
|
('ORD20240102002', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '高级视频编辑', 2, '2024-01-02 10:00:00', '2024-01-02 10:03:00'),
|
||||||
|
('ORD20240102003', 299.00, 'CNY', 'ALIPAY', 'COMPLETED', '企业会员订阅', 3, '2024-01-02 11:00:00', '2024-01-02 11:05:00'),
|
||||||
|
('ORD20240102004', 49.00, 'CNY', 'WECHAT', 'CANCELLED', '基础视频生成', 4, '2024-01-02 12:00:00', NULL),
|
||||||
|
('ORD20240102005', 149.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业视频制作', 5, '2024-01-02 13:00:00', '2024-01-02 13:04:00'),
|
||||||
|
('ORD20240115001', 199.00, 'CNY', 'WECHAT', 'COMPLETED', '视频生成服务包', 6, '2024-01-15 14:30:00', '2024-01-15 14:35:00'),
|
||||||
|
('ORD20240115002', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '高级视频编辑', 7, '2024-01-15 15:45:00', '2024-01-15 15:48:00'),
|
||||||
|
('ORD20240115003', 29.00, 'CNY', 'WECHAT', 'COMPLETED', '标准会员订阅', 8, '2024-01-15 16:20:00', '2024-01-15 16:22:00'),
|
||||||
|
('ORD20240128001', 149.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业视频制作', 9, '2024-01-28 10:15:00', '2024-01-28 10:19:00'),
|
||||||
|
('ORD20240128002', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '专业会员订阅', 10, '2024-01-28 11:30:00', '2024-01-28 11:34:00'),
|
||||||
|
|
||||||
|
-- 2024年2月支付数据
|
||||||
|
('ORD20240201001', 29.00, 'CNY', 'ALIPAY', 'COMPLETED', '标准会员订阅', 1, '2024-02-01 09:00:00', '2024-02-01 09:02:00'),
|
||||||
|
('ORD20240201002', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '专业会员订阅', 2, '2024-02-01 10:15:00', '2024-02-01 10:19:00'),
|
||||||
|
('ORD20240201003', 199.00, 'CNY', 'ALIPAY', 'COMPLETED', '视频生成服务包', 3, '2024-02-01 11:30:00', '2024-02-01 11:35:00'),
|
||||||
|
('ORD20240201004', 149.00, 'CNY', 'WECHAT', 'COMPLETED', '专业视频制作', 4, '2024-02-01 14:20:00', '2024-02-01 14:24:00'),
|
||||||
|
('ORD20240201005', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '高级视频编辑', 5, '2024-02-01 15:45:00', '2024-02-01 15:48:00'),
|
||||||
|
('ORD20240214001', 299.00, 'CNY', 'WECHAT', 'COMPLETED', '企业会员订阅', 6, '2024-02-14 10:00:00', '2024-02-14 10:05:00'),
|
||||||
|
('ORD20240214002', 29.00, 'CNY', 'ALIPAY', 'COMPLETED', '标准会员订阅', 7, '2024-02-14 11:30:00', '2024-02-14 11:32:00'),
|
||||||
|
('ORD20240214003', 199.00, 'CNY', 'WECHAT', 'COMPLETED', '视频生成服务包', 8, '2024-02-14 14:15:00', '2024-02-14 14:20:00'),
|
||||||
|
('ORD20240225001', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业会员订阅', 9, '2024-02-25 16:00:00', '2024-02-25 16:04:00'),
|
||||||
|
('ORD20240225002', 149.00, 'CNY', 'WECHAT', 'COMPLETED', '专业视频制作', 10, '2024-02-25 17:30:00', '2024-02-25 17:34:00'),
|
||||||
|
|
||||||
|
-- 2024年3月支付数据
|
||||||
|
('ORD20240301001', 29.00, 'CNY', 'WECHAT', 'COMPLETED', '标准会员订阅', 1, '2024-03-01 09:30:00', '2024-03-01 09:32:00'),
|
||||||
|
('ORD20240301002', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业会员订阅', 2, '2024-03-01 10:45:00', '2024-03-01 10:49:00'),
|
||||||
|
('ORD20240301003', 199.00, 'CNY', 'WECHAT', 'COMPLETED', '视频生成服务包', 3, '2024-03-01 11:20:00', '2024-03-01 11:25:00'),
|
||||||
|
('ORD20240301004', 149.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业视频制作', 4, '2024-03-01 14:10:00', '2024-03-01 14:14:00'),
|
||||||
|
('ORD20240301005', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '高级视频编辑', 5, '2024-03-01 15:25:00', '2024-03-01 15:28:00'),
|
||||||
|
('ORD20240308001', 299.00, 'CNY', 'ALIPAY', 'COMPLETED', '企业会员订阅', 6, '2024-03-08 10:00:00', '2024-03-08 10:05:00'),
|
||||||
|
('ORD20240308002', 29.00, 'CNY', 'WECHAT', 'COMPLETED', '标准会员订阅', 7, '2024-03-08 11:15:00', '2024-03-08 11:17:00'),
|
||||||
|
('ORD20240308003', 199.00, 'CNY', 'ALIPAY', 'COMPLETED', '视频生成服务包', 8, '2024-03-08 14:30:00', '2024-03-08 14:35:00'),
|
||||||
|
('ORD20240315001', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '专业会员订阅', 9, '2024-03-15 16:45:00', '2024-03-15 16:49:00'),
|
||||||
|
('ORD20240315002', 149.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业视频制作', 10, '2024-03-15 17:20:00', '2024-03-15 17:24:00'),
|
||||||
|
('ORD20240322001', 29.00, 'CNY', 'WECHAT', 'COMPLETED', '标准会员订阅', 1, '2024-03-22 09:15:00', '2024-03-22 09:17:00'),
|
||||||
|
('ORD20240322002', 199.00, 'CNY', 'ALIPAY', 'COMPLETED', '视频生成服务包', 2, '2024-03-22 10:30:00', '2024-03-22 10:35:00'),
|
||||||
|
('ORD20240322003', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '高级视频编辑', 3, '2024-03-22 14:45:00', '2024-03-22 14:48:00'),
|
||||||
|
('ORD20240330001', 299.00, 'CNY', 'ALIPAY', 'COMPLETED', '企业会员订阅', 4, '2024-03-30 11:00:00', '2024-03-30 11:05:00'),
|
||||||
|
('ORD20240330002', 149.00, 'CNY', 'WECHAT', 'COMPLETED', '专业视频制作', 5, '2024-03-30 15:30:00', '2024-03-30 15:34:00'),
|
||||||
|
|
||||||
|
-- 2024年4月支付数据
|
||||||
|
('ORD20240401001', 29.00, 'CNY', 'ALIPAY', 'COMPLETED', '标准会员订阅', 6, '2024-04-01 09:00:00', '2024-04-01 09:02:00'),
|
||||||
|
('ORD20240401002', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '专业会员订阅', 7, '2024-04-01 10:20:00', '2024-04-01 10:24:00'),
|
||||||
|
('ORD20240401003', 199.00, 'CNY', 'ALIPAY', 'COMPLETED', '视频生成服务包', 8, '2024-04-01 11:40:00', '2024-04-01 11:45:00'),
|
||||||
|
('ORD20240401004', 149.00, 'CNY', 'WECHAT', 'COMPLETED', '专业视频制作', 9, '2024-04-01 14:15:00', '2024-04-01 14:19:00'),
|
||||||
|
('ORD20240401005', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '高级视频编辑', 10, '2024-04-01 15:35:00', '2024-04-01 15:38:00'),
|
||||||
|
('ORD20240410001', 299.00, 'CNY', 'WECHAT', 'COMPLETED', '企业会员订阅', 1, '2024-04-10 10:30:00', '2024-04-10 10:35:00'),
|
||||||
|
('ORD20240410002', 29.00, 'CNY', 'ALIPAY', 'COMPLETED', '标准会员订阅', 2, '2024-04-10 11:45:00', '2024-04-10 11:47:00'),
|
||||||
|
('ORD20240410003', 199.00, 'CNY', 'WECHAT', 'COMPLETED', '视频生成服务包', 3, '2024-04-10 14:20:00', '2024-04-10 14:25:00'),
|
||||||
|
('ORD20240420001', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业会员订阅', 4, '2024-04-20 16:10:00', '2024-04-20 16:14:00'),
|
||||||
|
('ORD20240420002', 149.00, 'CNY', 'WECHAT', 'COMPLETED', '专业视频制作', 5, '2024-04-20 17:25:00', '2024-04-20 17:29:00'),
|
||||||
|
('ORD20240420003', 29.00, 'CNY', 'ALIPAY', 'COMPLETED', '标准会员订阅', 6, '2024-04-20 18:40:00', '2024-04-20 18:42:00'),
|
||||||
|
('ORD20240425001', 199.00, 'CNY', 'WECHAT', 'COMPLETED', '视频生成服务包', 7, '2024-04-25 09:15:00', '2024-04-25 09:20:00'),
|
||||||
|
('ORD20240425002', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '高级视频编辑', 8, '2024-04-25 10:30:00', '2024-04-25 10:33:00'),
|
||||||
|
('ORD20240425003', 299.00, 'CNY', 'WECHAT', 'COMPLETED', '企业会员订阅', 9, '2024-04-25 14:45:00', '2024-04-25 14:50:00'),
|
||||||
|
('ORD20240430001', 149.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业视频制作', 10, '2024-04-30 15:20:00', '2024-04-30 15:24:00'),
|
||||||
|
|
||||||
|
-- 2024年5月支付数据
|
||||||
|
('ORD20240501001', 29.00, 'CNY', 'WECHAT', 'COMPLETED', '标准会员订阅', 1, '2024-05-01 09:30:00', '2024-05-01 09:32:00'),
|
||||||
|
('ORD20240501002', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业会员订阅', 2, '2024-05-01 10:45:00', '2024-05-01 10:49:00'),
|
||||||
|
('ORD20240501003', 199.00, 'CNY', 'WECHAT', 'COMPLETED', '视频生成服务包', 3, '2024-05-01 11:20:00', '2024-05-01 11:25:00'),
|
||||||
|
('ORD20240501004', 149.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业视频制作', 4, '2024-05-01 14:10:00', '2024-05-01 14:14:00'),
|
||||||
|
('ORD20240501005', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '高级视频编辑', 5, '2024-05-01 15:25:00', '2024-05-01 15:28:00'),
|
||||||
|
('ORD20240510001', 299.00, 'CNY', 'ALIPAY', 'COMPLETED', '企业会员订阅', 6, '2024-05-10 10:00:00', '2024-05-10 10:05:00'),
|
||||||
|
('ORD20240510002', 29.00, 'CNY', 'WECHAT', 'COMPLETED', '标准会员订阅', 7, '2024-05-10 11:15:00', '2024-05-10 11:17:00'),
|
||||||
|
('ORD20240510003', 199.00, 'CNY', 'ALIPAY', 'COMPLETED', '视频生成服务包', 8, '2024-05-10 14:30:00', '2024-05-10 14:35:00'),
|
||||||
|
('ORD20240520001', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '专业会员订阅', 9, '2024-05-20 16:45:00', '2024-05-20 16:49:00'),
|
||||||
|
('ORD20240520002', 149.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业视频制作', 10, '2024-05-20 17:20:00', '2024-05-20 17:24:00'),
|
||||||
|
('ORD20240520003', 29.00, 'CNY', 'WECHAT', 'COMPLETED', '标准会员订阅', 1, '2024-05-20 18:35:00', '2024-05-20 18:37:00'),
|
||||||
|
('ORD20240525001', 199.00, 'CNY', 'ALIPAY', 'COMPLETED', '视频生成服务包', 2, '2024-05-25 09:50:00', '2024-05-25 09:55:00'),
|
||||||
|
('ORD20240525002', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '高级视频编辑', 3, '2024-05-25 11:05:00', '2024-05-25 11:08:00'),
|
||||||
|
('ORD20240525003', 299.00, 'CNY', 'ALIPAY', 'COMPLETED', '企业会员订阅', 4, '2024-05-25 14:20:00', '2024-05-25 14:25:00'),
|
||||||
|
('ORD20240530001', 149.00, 'CNY', 'WECHAT', 'COMPLETED', '专业视频制作', 5, '2024-05-30 15:35:00', '2024-05-30 15:39:00'),
|
||||||
|
|
||||||
|
-- 2024年6月支付数据
|
||||||
|
('ORD20240601001', 29.00, 'CNY', 'ALIPAY', 'COMPLETED', '标准会员订阅', 6, '2024-06-01 09:15:00', '2024-06-01 09:17:00'),
|
||||||
|
('ORD20240601002', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '专业会员订阅', 7, '2024-06-01 10:30:00', '2024-06-01 10:34:00'),
|
||||||
|
('ORD20240601003', 199.00, 'CNY', 'ALIPAY', 'COMPLETED', '视频生成服务包', 8, '2024-06-01 11:45:00', '2024-06-01 11:50:00'),
|
||||||
|
('ORD20240601004', 149.00, 'CNY', 'WECHAT', 'COMPLETED', '专业视频制作', 9, '2024-06-01 14:00:00', '2024-06-01 14:04:00'),
|
||||||
|
('ORD20240601005', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '高级视频编辑', 10, '2024-06-01 15:15:00', '2024-06-01 15:18:00'),
|
||||||
|
('ORD20240615001', 299.00, 'CNY', 'WECHAT', 'COMPLETED', '企业会员订阅', 1, '2024-06-15 10:45:00', '2024-06-15 10:50:00'),
|
||||||
|
('ORD20240615002', 29.00, 'CNY', 'ALIPAY', 'COMPLETED', '标准会员订阅', 2, '2024-06-15 12:00:00', '2024-06-15 12:02:00'),
|
||||||
|
('ORD20240615003', 199.00, 'CNY', 'WECHAT', 'COMPLETED', '视频生成服务包', 3, '2024-06-15 14:15:00', '2024-06-15 14:20:00'),
|
||||||
|
('ORD20240620001', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业会员订阅', 4, '2024-06-20 16:30:00', '2024-06-20 16:34:00'),
|
||||||
|
('ORD20240620002', 149.00, 'CNY', 'WECHAT', 'COMPLETED', '专业视频制作', 5, '2024-06-20 17:45:00', '2024-06-20 17:49:00'),
|
||||||
|
('ORD20240620003', 29.00, 'CNY', 'ALIPAY', 'COMPLETED', '标准会员订阅', 6, '2024-06-20 19:00:00', '2024-06-20 19:02:00'),
|
||||||
|
('ORD20240625001', 199.00, 'CNY', 'WECHAT', 'COMPLETED', '视频生成服务包', 7, '2024-06-25 09:30:00', '2024-06-25 09:35:00'),
|
||||||
|
('ORD20240625002', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '高级视频编辑', 8, '2024-06-25 10:45:00', '2024-06-25 10:48:00'),
|
||||||
|
('ORD20240625003', 299.00, 'CNY', 'WECHAT', 'COMPLETED', '企业会员订阅', 9, '2024-06-25 14:00:00', '2024-06-25 14:05:00'),
|
||||||
|
('ORD20240630001', 149.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业视频制作', 10, '2024-06-30 15:15:00', '2024-06-30 15:19:00'),
|
||||||
|
|
||||||
|
-- 2024年7月支付数据
|
||||||
|
('ORD20240701001', 29.00, 'CNY', 'WECHAT', 'COMPLETED', '标准会员订阅', 1, '2024-07-01 09:45:00', '2024-07-01 09:47:00'),
|
||||||
|
('ORD20240701002', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业会员订阅', 2, '2024-07-01 11:00:00', '2024-07-01 11:04:00'),
|
||||||
|
('ORD20240701003', 199.00, 'CNY', 'WECHAT', 'COMPLETED', '视频生成服务包', 3, '2024-07-01 12:15:00', '2024-07-01 12:20:00'),
|
||||||
|
('ORD20240701004', 149.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业视频制作', 4, '2024-07-01 14:30:00', '2024-07-01 14:34:00'),
|
||||||
|
('ORD20240701005', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '高级视频编辑', 5, '2024-07-01 15:45:00', '2024-07-01 15:48:00'),
|
||||||
|
('ORD20240710001', 299.00, 'CNY', 'ALIPAY', 'COMPLETED', '企业会员订阅', 6, '2024-07-10 10:20:00', '2024-07-10 10:25:00'),
|
||||||
|
('ORD20240710002', 29.00, 'CNY', 'WECHAT', 'COMPLETED', '标准会员订阅', 7, '2024-07-10 11:35:00', '2024-07-10 11:37:00'),
|
||||||
|
('ORD20240710003', 199.00, 'CNY', 'ALIPAY', 'COMPLETED', '视频生成服务包', 8, '2024-07-10 14:50:00', '2024-07-10 14:55:00'),
|
||||||
|
('ORD20240720001', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '专业会员订阅', 9, '2024-07-20 16:05:00', '2024-07-20 16:09:00'),
|
||||||
|
('ORD20240720002', 149.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业视频制作', 10, '2024-07-20 17:20:00', '2024-07-20 17:24:00'),
|
||||||
|
('ORD20240720003', 29.00, 'CNY', 'WECHAT', 'COMPLETED', '标准会员订阅', 1, '2024-07-20 18:35:00', '2024-07-20 18:37:00'),
|
||||||
|
('ORD20240725001', 199.00, 'CNY', 'ALIPAY', 'COMPLETED', '视频生成服务包', 2, '2024-07-25 09:50:00', '2024-07-25 09:55:00'),
|
||||||
|
('ORD20240725002', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '高级视频编辑', 3, '2024-07-25 11:05:00', '2024-07-25 11:08:00'),
|
||||||
|
('ORD20240725003', 299.00, 'CNY', 'ALIPAY', 'COMPLETED', '企业会员订阅', 4, '2024-07-25 14:20:00', '2024-07-25 14:25:00'),
|
||||||
|
('ORD20240730001', 149.00, 'CNY', 'WECHAT', 'COMPLETED', '专业视频制作', 5, '2024-07-30 15:35:00', '2024-07-30 15:39:00'),
|
||||||
|
|
||||||
|
-- 2024年8月支付数据
|
||||||
|
('ORD20240801001', 29.00, 'CNY', 'ALIPAY', 'COMPLETED', '标准会员订阅', 6, '2024-08-01 09:30:00', '2024-08-01 09:32:00'),
|
||||||
|
('ORD20240801002', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '专业会员订阅', 7, '2024-08-01 10:45:00', '2024-08-01 10:49:00'),
|
||||||
|
('ORD20240801003', 199.00, 'CNY', 'ALIPAY', 'COMPLETED', '视频生成服务包', 8, '2024-08-01 12:00:00', '2024-08-01 12:05:00'),
|
||||||
|
('ORD20240801004', 149.00, 'CNY', 'WECHAT', 'COMPLETED', '专业视频制作', 9, '2024-08-01 14:15:00', '2024-08-01 14:19:00'),
|
||||||
|
('ORD20240801005', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '高级视频编辑', 10, '2024-08-01 15:30:00', '2024-08-01 15:33:00'),
|
||||||
|
('ORD20240810001', 299.00, 'CNY', 'WECHAT', 'COMPLETED', '企业会员订阅', 1, '2024-08-10 10:00:00', '2024-08-10 10:05:00'),
|
||||||
|
('ORD20240810002', 29.00, 'CNY', 'ALIPAY', 'COMPLETED', '标准会员订阅', 2, '2024-08-10 11:15:00', '2024-08-10 11:17:00'),
|
||||||
|
('ORD20240810003', 199.00, 'CNY', 'WECHAT', 'COMPLETED', '视频生成服务包', 3, '2024-08-10 14:30:00', '2024-08-10 14:35:00'),
|
||||||
|
('ORD20240820001', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业会员订阅', 4, '2024-08-20 16:45:00', '2024-08-20 16:49:00'),
|
||||||
|
('ORD20240820002', 149.00, 'CNY', 'WECHAT', 'COMPLETED', '专业视频制作', 5, '2024-08-20 18:00:00', '2024-08-20 18:04:00'),
|
||||||
|
('ORD20240820003', 29.00, 'CNY', 'ALIPAY', 'COMPLETED', '标准会员订阅', 6, '2024-08-20 19:15:00', '2024-08-20 19:17:00'),
|
||||||
|
('ORD20240825001', 199.00, 'CNY', 'WECHAT', 'COMPLETED', '视频生成服务包', 7, '2024-08-25 09:30:00', '2024-08-25 09:35:00'),
|
||||||
|
('ORD20240825002', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '高级视频编辑', 8, '2024-08-25 10:45:00', '2024-08-25 10:48:00'),
|
||||||
|
('ORD20240825003', 299.00, 'CNY', 'WECHAT', 'COMPLETED', '企业会员订阅', 9, '2024-08-25 14:00:00', '2024-08-25 14:05:00'),
|
||||||
|
('ORD20240830001', 149.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业视频制作', 10, '2024-08-30 15:15:00', '2024-08-30 15:19:00'),
|
||||||
|
|
||||||
|
-- 2024年9月支付数据
|
||||||
|
('ORD20240901001', 29.00, 'CNY', 'WECHAT', 'COMPLETED', '标准会员订阅', 1, '2024-09-01 09:15:00', '2024-09-01 09:17:00'),
|
||||||
|
('ORD20240901002', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业会员订阅', 2, '2024-09-01 10:30:00', '2024-09-01 10:34:00'),
|
||||||
|
('ORD20240901003', 199.00, 'CNY', 'WECHAT', 'COMPLETED', '视频生成服务包', 3, '2024-09-01 11:45:00', '2024-09-01 11:50:00'),
|
||||||
|
('ORD20240901004', 149.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业视频制作', 4, '2024-09-01 14:00:00', '2024-09-01 14:04:00'),
|
||||||
|
('ORD20240901005', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '高级视频编辑', 5, '2024-09-01 15:15:00', '2024-09-01 15:18:00'),
|
||||||
|
('ORD20240910001', 299.00, 'CNY', 'ALIPAY', 'COMPLETED', '企业会员订阅', 6, '2024-09-10 10:45:00', '2024-09-10 10:50:00'),
|
||||||
|
('ORD20240910002', 29.00, 'CNY', 'WECHAT', 'COMPLETED', '标准会员订阅', 7, '2024-09-10 12:00:00', '2024-09-10 12:02:00'),
|
||||||
|
('ORD20240910003', 199.00, 'CNY', 'ALIPAY', 'COMPLETED', '视频生成服务包', 8, '2024-09-10 14:15:00', '2024-09-10 14:20:00'),
|
||||||
|
('ORD20240920001', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '专业会员订阅', 9, '2024-09-20 16:30:00', '2024-09-20 16:34:00'),
|
||||||
|
('ORD20240920002', 149.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业视频制作', 10, '2024-09-20 17:45:00', '2024-09-20 17:49:00'),
|
||||||
|
('ORD20240920003', 29.00, 'CNY', 'WECHAT', 'COMPLETED', '标准会员订阅', 1, '2024-09-20 19:00:00', '2024-09-20 19:02:00'),
|
||||||
|
('ORD20240925001', 199.00, 'CNY', 'ALIPAY', 'COMPLETED', '视频生成服务包', 2, '2024-09-25 09:15:00', '2024-09-25 09:20:00'),
|
||||||
|
('ORD20240925002', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '高级视频编辑', 3, '2024-09-25 10:30:00', '2024-09-25 10:33:00'),
|
||||||
|
('ORD20240925003', 299.00, 'CNY', 'ALIPAY', 'COMPLETED', '企业会员订阅', 4, '2024-09-25 14:45:00', '2024-09-25 14:50:00'),
|
||||||
|
('ORD20240930001', 149.00, 'CNY', 'WECHAT', 'COMPLETED', '专业视频制作', 5, '2024-09-30 15:00:00', '2024-09-30 15:04:00'),
|
||||||
|
|
||||||
|
-- 2024年10月支付数据
|
||||||
|
('ORD20241001001', 29.00, 'CNY', 'ALIPAY', 'COMPLETED', '标准会员订阅', 6, '2024-10-01 09:45:00', '2024-10-01 09:47:00'),
|
||||||
|
('ORD20241001002', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '专业会员订阅', 7, '2024-10-01 11:00:00', '2024-10-01 11:04:00'),
|
||||||
|
('ORD20241001003', 199.00, 'CNY', 'ALIPAY', 'COMPLETED', '视频生成服务包', 8, '2024-10-01 12:15:00', '2024-10-01 12:20:00'),
|
||||||
|
('ORD20241001004', 149.00, 'CNY', 'WECHAT', 'COMPLETED', '专业视频制作', 9, '2024-10-01 14:30:00', '2024-10-01 14:34:00'),
|
||||||
|
('ORD20241001005', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '高级视频编辑', 10, '2024-10-01 15:45:00', '2024-10-01 15:48:00'),
|
||||||
|
('ORD20241010001', 299.00, 'CNY', 'WECHAT', 'COMPLETED', '企业会员订阅', 1, '2024-10-10 10:20:00', '2024-10-10 10:25:00'),
|
||||||
|
('ORD20241010002', 29.00, 'CNY', 'ALIPAY', 'COMPLETED', '标准会员订阅', 2, '2024-10-10 11:35:00', '2024-10-10 11:37:00'),
|
||||||
|
('ORD20241010003', 199.00, 'CNY', 'WECHAT', 'COMPLETED', '视频生成服务包', 3, '2024-10-10 14:50:00', '2024-10-10 14:55:00'),
|
||||||
|
('ORD20241020001', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业会员订阅', 4, '2024-10-20 16:05:00', '2024-10-20 16:09:00'),
|
||||||
|
('ORD20241020002', 149.00, 'CNY', 'WECHAT', 'COMPLETED', '专业视频制作', 5, '2024-10-20 17:20:00', '2024-10-20 17:24:00'),
|
||||||
|
('ORD20241020003', 29.00, 'CNY', 'ALIPAY', 'COMPLETED', '标准会员订阅', 6, '2024-10-20 18:35:00', '2024-10-20 18:37:00'),
|
||||||
|
('ORD20241025001', 199.00, 'CNY', 'WECHAT', 'COMPLETED', '视频生成服务包', 7, '2024-10-25 09:50:00', '2024-10-25 09:55:00'),
|
||||||
|
('ORD20241025002', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '高级视频编辑', 8, '2024-10-25 11:05:00', '2024-10-25 11:08:00'),
|
||||||
|
('ORD20241025003', 299.00, 'CNY', 'WECHAT', 'COMPLETED', '企业会员订阅', 9, '2024-10-25 14:20:00', '2024-10-25 14:25:00'),
|
||||||
|
('ORD20241030001', 149.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业视频制作', 10, '2024-10-30 15:35:00', '2024-10-30 15:39:00'),
|
||||||
|
|
||||||
|
-- 2024年11月支付数据
|
||||||
|
('ORD20241101001', 29.00, 'CNY', 'WECHAT', 'COMPLETED', '标准会员订阅', 1, '2024-11-01 09:30:00', '2024-11-01 09:32:00'),
|
||||||
|
('ORD20241101002', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业会员订阅', 2, '2024-11-01 10:45:00', '2024-11-01 10:49:00'),
|
||||||
|
('ORD20241101003', 199.00, 'CNY', 'WECHAT', 'COMPLETED', '视频生成服务包', 3, '2024-11-01 12:00:00', '2024-11-01 12:05:00'),
|
||||||
|
('ORD20241101004', 149.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业视频制作', 4, '2024-11-01 14:15:00', '2024-11-01 14:19:00'),
|
||||||
|
('ORD20241101005', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '高级视频编辑', 5, '2024-11-01 15:30:00', '2024-11-01 15:33:00'),
|
||||||
|
('ORD20241111001', 299.00, 'CNY', 'ALIPAY', 'COMPLETED', '企业会员订阅', 6, '2024-11-11 10:00:00', '2024-11-11 10:05:00'),
|
||||||
|
('ORD20241111002', 29.00, 'CNY', 'WECHAT', 'COMPLETED', '标准会员订阅', 7, '2024-11-11 11:15:00', '2024-11-11 11:17:00'),
|
||||||
|
('ORD20241111003', 199.00, 'CNY', 'ALIPAY', 'COMPLETED', '视频生成服务包', 8, '2024-11-11 14:30:00', '2024-11-11 14:35:00'),
|
||||||
|
('ORD20241120001', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '专业会员订阅', 9, '2024-11-20 16:45:00', '2024-11-20 16:49:00'),
|
||||||
|
('ORD20241120002', 149.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业视频制作', 10, '2024-11-20 18:00:00', '2024-11-20 18:04:00'),
|
||||||
|
('ORD20241120003', 29.00, 'CNY', 'WECHAT', 'COMPLETED', '标准会员订阅', 1, '2024-11-20 19:15:00', '2024-11-20 19:17:00'),
|
||||||
|
('ORD20241125001', 199.00, 'CNY', 'ALIPAY', 'COMPLETED', '视频生成服务包', 2, '2024-11-25 09:30:00', '2024-11-25 09:35:00'),
|
||||||
|
('ORD20241125002', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '高级视频编辑', 3, '2024-11-25 10:45:00', '2024-11-25 10:48:00'),
|
||||||
|
('ORD20241125003', 299.00, 'CNY', 'ALIPAY', 'COMPLETED', '企业会员订阅', 4, '2024-11-25 14:00:00', '2024-11-25 14:05:00'),
|
||||||
|
('ORD20241130001', 149.00, 'CNY', 'WECHAT', 'COMPLETED', '专业视频制作', 5, '2024-11-30 15:15:00', '2024-11-30 15:19:00'),
|
||||||
|
|
||||||
|
-- 2024年12月支付数据
|
||||||
|
('ORD20241201001', 29.00, 'CNY', 'ALIPAY', 'COMPLETED', '标准会员订阅', 6, '2024-12-01 09:15:00', '2024-12-01 09:17:00'),
|
||||||
|
('ORD20241201002', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '专业会员订阅', 7, '2024-12-01 10:30:00', '2024-12-01 10:34:00'),
|
||||||
|
('ORD20241201003', 199.00, 'CNY', 'ALIPAY', 'COMPLETED', '视频生成服务包', 8, '2024-12-01 11:45:00', '2024-12-01 11:50:00'),
|
||||||
|
('ORD20241201004', 149.00, 'CNY', 'WECHAT', 'COMPLETED', '专业视频制作', 9, '2024-12-01 14:00:00', '2024-12-01 14:04:00'),
|
||||||
|
('ORD20241201005', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '高级视频编辑', 10, '2024-12-01 15:15:00', '2024-12-01 15:18:00'),
|
||||||
|
('ORD20241210001', 299.00, 'CNY', 'WECHAT', 'COMPLETED', '企业会员订阅', 1, '2024-12-10 10:45:00', '2024-12-10 10:50:00'),
|
||||||
|
('ORD20241210002', 29.00, 'CNY', 'ALIPAY', 'COMPLETED', '标准会员订阅', 2, '2024-12-10 12:00:00', '2024-12-10 12:02:00'),
|
||||||
|
('ORD20241210003', 199.00, 'CNY', 'WECHAT', 'COMPLETED', '视频生成服务包', 3, '2024-12-10 14:15:00', '2024-12-10 14:20:00'),
|
||||||
|
('ORD20241220001', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业会员订阅', 4, '2024-12-20 16:30:00', '2024-12-20 16:34:00'),
|
||||||
|
('ORD20241220002', 149.00, 'CNY', 'WECHAT', 'COMPLETED', '专业视频制作', 5, '2024-12-20 17:45:00', '2024-12-20 17:49:00'),
|
||||||
|
('ORD20241220003', 29.00, 'CNY', 'ALIPAY', 'COMPLETED', '标准会员订阅', 6, '2024-12-20 19:00:00', '2024-12-20 19:02:00'),
|
||||||
|
('ORD20241225001', 199.00, 'CNY', 'WECHAT', 'COMPLETED', '视频生成服务包', 7, '2024-12-25 09:15:00', '2024-12-25 09:20:00'),
|
||||||
|
('ORD20241225002', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '高级视频编辑', 8, '2024-12-25 10:30:00', '2024-12-25 10:33:00'),
|
||||||
|
('ORD20241225003', 299.00, 'CNY', 'WECHAT', 'COMPLETED', '企业会员订阅', 9, '2024-12-25 14:45:00', '2024-12-25 14:50:00'),
|
||||||
|
('ORD20241230001', 149.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业视频制作', 10, '2024-12-30 15:00:00', '2024-12-30 15:04:00');
|
||||||
@@ -5,7 +5,16 @@ CREATE TABLE IF NOT EXISTS users (
|
|||||||
password_hash VARCHAR(100) NOT NULL,
|
password_hash VARCHAR(100) NOT NULL,
|
||||||
role VARCHAR(30) NOT NULL DEFAULT 'ROLE_USER',
|
role VARCHAR(30) NOT NULL DEFAULT 'ROLE_USER',
|
||||||
points INT NOT NULL DEFAULT 50,
|
points INT NOT NULL DEFAULT 50,
|
||||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
phone VARCHAR(20),
|
||||||
|
avatar VARCHAR(500),
|
||||||
|
nickname VARCHAR(100),
|
||||||
|
gender VARCHAR(10),
|
||||||
|
birthday DATE,
|
||||||
|
address TEXT,
|
||||||
|
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||||
|
last_login_at TIMESTAMP NULL,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS payments (
|
CREATE TABLE IF NOT EXISTS payments (
|
||||||
@@ -62,3 +71,84 @@ CREATE TABLE IF NOT EXISTS order_items (
|
|||||||
FOREIGN KEY (order_id) REFERENCES orders(id) ON DELETE CASCADE
|
FOREIGN KEY (order_id) REFERENCES orders(id) ON DELETE CASCADE
|
||||||
);
|
);
|
||||||
|
|
||||||
|
-- 会员等级表
|
||||||
|
CREATE TABLE IF NOT EXISTS membership_levels (
|
||||||
|
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
name VARCHAR(50) NOT NULL UNIQUE,
|
||||||
|
display_name VARCHAR(50) NOT NULL,
|
||||||
|
description TEXT,
|
||||||
|
price DECIMAL(10,2) NOT NULL DEFAULT 0,
|
||||||
|
duration_days INT NOT NULL DEFAULT 30,
|
||||||
|
points_bonus INT NOT NULL DEFAULT 0,
|
||||||
|
features JSON,
|
||||||
|
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
-- 用户会员信息表
|
||||||
|
CREATE TABLE IF NOT EXISTS user_memberships (
|
||||||
|
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
user_id BIGINT NOT NULL,
|
||||||
|
membership_level_id BIGINT NOT NULL,
|
||||||
|
start_date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
end_date TIMESTAMP NOT NULL,
|
||||||
|
status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE',
|
||||||
|
auto_renew BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||||
|
FOREIGN KEY (membership_level_id) REFERENCES membership_levels(id),
|
||||||
|
UNIQUE KEY unique_active_membership (user_id, status)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- 视频生成任务表
|
||||||
|
CREATE TABLE IF NOT EXISTS video_tasks (
|
||||||
|
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
task_id VARCHAR(100) NOT NULL UNIQUE,
|
||||||
|
user_id BIGINT NOT NULL,
|
||||||
|
task_type VARCHAR(50) NOT NULL, -- TEXT_TO_VIDEO, IMAGE_TO_VIDEO, STORYBOARD_VIDEO
|
||||||
|
title VARCHAR(200) NOT NULL,
|
||||||
|
description TEXT,
|
||||||
|
input_text TEXT,
|
||||||
|
input_image_url VARCHAR(500),
|
||||||
|
output_video_url VARCHAR(500),
|
||||||
|
status VARCHAR(20) NOT NULL DEFAULT 'PENDING', -- PENDING, PROCESSING, COMPLETED, FAILED
|
||||||
|
progress INT NOT NULL DEFAULT 0,
|
||||||
|
error_message TEXT,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
completed_at TIMESTAMP NULL,
|
||||||
|
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
-- 用户作品表
|
||||||
|
CREATE TABLE IF NOT EXISTS user_works (
|
||||||
|
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
user_id BIGINT NOT NULL,
|
||||||
|
title VARCHAR(200) NOT NULL,
|
||||||
|
description TEXT,
|
||||||
|
work_type VARCHAR(50) NOT NULL, -- VIDEO, IMAGE, STORYBOARD
|
||||||
|
cover_image VARCHAR(500),
|
||||||
|
video_url VARCHAR(500),
|
||||||
|
tags VARCHAR(500),
|
||||||
|
is_public BOOLEAN NOT NULL DEFAULT TRUE,
|
||||||
|
view_count INT NOT NULL DEFAULT 0,
|
||||||
|
like_count INT NOT NULL DEFAULT 0,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
-- 系统配置表
|
||||||
|
CREATE TABLE IF NOT EXISTS system_configs (
|
||||||
|
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
config_key VARCHAR(100) NOT NULL UNIQUE,
|
||||||
|
config_value TEXT,
|
||||||
|
description VARCHAR(500),
|
||||||
|
config_type VARCHAR(50) NOT NULL DEFAULT 'STRING', -- STRING, NUMBER, BOOLEAN, JSON
|
||||||
|
is_public BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -561,3 +561,6 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -477,3 +477,6 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -516,3 +516,6 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
407
demo/src/main/resources/user_activity_stats.sql
Normal file
407
demo/src/main/resources/user_activity_stats.sql
Normal file
@@ -0,0 +1,407 @@
|
|||||||
|
-- 用户活跃度统计表
|
||||||
|
CREATE TABLE IF NOT EXISTS user_activity_stats (
|
||||||
|
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
stat_date DATE NOT NULL COMMENT '统计日期',
|
||||||
|
daily_active_users INT NOT NULL DEFAULT 0 COMMENT '日活用户数',
|
||||||
|
monthly_active_users INT NOT NULL DEFAULT 0 COMMENT '月活用户数',
|
||||||
|
new_users INT NOT NULL DEFAULT 0 COMMENT '新增用户数',
|
||||||
|
returning_users INT NOT NULL DEFAULT 0 COMMENT '回访用户数',
|
||||||
|
session_count INT NOT NULL DEFAULT 0 COMMENT '会话数',
|
||||||
|
avg_session_duration DECIMAL(10,2) DEFAULT 0 COMMENT '平均会话时长(分钟)',
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
UNIQUE KEY uk_stat_date (stat_date),
|
||||||
|
INDEX idx_stat_date (stat_date)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户活跃度统计表';
|
||||||
|
|
||||||
|
-- 插入2024年全年日活数据(模拟真实趋势)
|
||||||
|
INSERT IGNORE INTO user_activity_stats (stat_date, daily_active_users, monthly_active_users, new_users, returning_users, session_count, avg_session_duration) VALUES
|
||||||
|
-- 1月数据
|
||||||
|
('2024-01-01', 1200, 15000, 50, 1150, 1800, 25.5),
|
||||||
|
('2024-01-02', 1350, 15200, 45, 1305, 2000, 28.2),
|
||||||
|
('2024-01-03', 1100, 15400, 40, 1060, 1650, 24.8),
|
||||||
|
('2024-01-04', 1250, 15600, 55, 1195, 1900, 26.7),
|
||||||
|
('2024-01-05', 1400, 15800, 60, 1340, 2100, 29.1),
|
||||||
|
('2024-01-06', 1300, 16000, 50, 1250, 1950, 27.3),
|
||||||
|
('2024-01-07', 1150, 16200, 45, 1105, 1725, 25.9),
|
||||||
|
('2024-01-08', 1200, 16400, 55, 1145, 1800, 26.4),
|
||||||
|
('2024-01-09', 1350, 16600, 65, 1285, 2025, 28.7),
|
||||||
|
('2024-01-10', 1450, 16800, 70, 1380, 2175, 30.2),
|
||||||
|
('2024-01-11', 1300, 17000, 60, 1240, 1950, 27.8),
|
||||||
|
('2024-01-12', 1250, 17200, 55, 1195, 1875, 27.1),
|
||||||
|
('2024-01-13', 1400, 17400, 75, 1325, 2100, 29.5),
|
||||||
|
('2024-01-14', 1500, 17600, 80, 1420, 2250, 31.2),
|
||||||
|
('2024-01-15', 1350, 17800, 65, 1285, 2025, 28.9),
|
||||||
|
('2024-01-16', 1200, 18000, 50, 1150, 1800, 26.7),
|
||||||
|
('2024-01-17', 1100, 18200, 45, 1055, 1650, 25.3),
|
||||||
|
('2024-01-18', 1250, 18400, 60, 1190, 1875, 27.6),
|
||||||
|
('2024-01-19', 1400, 18600, 70, 1330, 2100, 29.8),
|
||||||
|
('2024-01-20', 1450, 18800, 75, 1375, 2175, 30.5),
|
||||||
|
('2024-01-21', 1300, 19000, 60, 1240, 1950, 28.2),
|
||||||
|
('2024-01-22', 1200, 19200, 55, 1145, 1800, 27.0),
|
||||||
|
('2024-01-23', 1150, 19400, 50, 1100, 1725, 26.4),
|
||||||
|
('2024-01-24', 1250, 19600, 65, 1185, 1875, 28.1),
|
||||||
|
('2024-01-25', 1350, 19800, 70, 1280, 2025, 29.7),
|
||||||
|
('2024-01-26', 1400, 20000, 75, 1325, 2100, 30.3),
|
||||||
|
('2024-01-27', 1300, 20200, 65, 1235, 1950, 28.8),
|
||||||
|
('2024-01-28', 1250, 20400, 60, 1190, 1875, 28.2),
|
||||||
|
('2024-01-29', 1200, 20600, 55, 1145, 1800, 27.5),
|
||||||
|
('2024-01-30', 1150, 20800, 50, 1100, 1725, 26.9),
|
||||||
|
('2024-01-31', 1100, 21000, 45, 1055, 1650, 26.2),
|
||||||
|
|
||||||
|
-- 2月数据(春节影响,数据波动较大)
|
||||||
|
('2024-02-01', 1000, 21200, 40, 960, 1500, 24.8),
|
||||||
|
('2024-02-02', 950, 21400, 35, 915, 1425, 24.1),
|
||||||
|
('2024-02-03', 900, 21600, 30, 870, 1350, 23.5),
|
||||||
|
('2024-02-04', 850, 21800, 25, 825, 1275, 22.9),
|
||||||
|
('2024-02-05', 800, 22000, 20, 780, 1200, 22.2),
|
||||||
|
('2024-02-06', 750, 22200, 15, 735, 1125, 21.6),
|
||||||
|
('2024-02-07', 700, 22400, 10, 690, 1050, 21.0),
|
||||||
|
('2024-02-08', 650, 22600, 8, 642, 975, 20.4),
|
||||||
|
('2024-02-09', 600, 22800, 5, 595, 900, 19.8),
|
||||||
|
('2024-02-10', 550, 23000, 3, 547, 825, 19.2),
|
||||||
|
('2024-02-11', 500, 23200, 2, 498, 750, 18.6),
|
||||||
|
('2024-02-12', 450, 23400, 1, 449, 675, 18.0),
|
||||||
|
('2024-02-13', 400, 23600, 1, 399, 600, 17.4),
|
||||||
|
('2024-02-14', 350, 23800, 1, 349, 525, 16.8),
|
||||||
|
('2024-02-15', 300, 24000, 1, 299, 450, 16.2),
|
||||||
|
('2024-02-16', 250, 24200, 1, 249, 375, 15.6),
|
||||||
|
('2024-02-17', 200, 24400, 1, 199, 300, 15.0),
|
||||||
|
('2024-02-18', 150, 24600, 1, 149, 225, 14.4),
|
||||||
|
('2024-02-19', 100, 24800, 1, 99, 150, 13.8),
|
||||||
|
('2024-02-20', 80, 25000, 1, 79, 120, 13.2),
|
||||||
|
('2024-02-21', 60, 25200, 1, 59, 90, 12.6),
|
||||||
|
('2024-02-22', 50, 25400, 1, 49, 75, 12.0),
|
||||||
|
('2024-02-23', 40, 25600, 1, 39, 60, 11.4),
|
||||||
|
('2024-02-24', 30, 25800, 1, 29, 45, 10.8),
|
||||||
|
('2024-02-25', 25, 26000, 1, 24, 37, 10.2),
|
||||||
|
('2024-02-26', 20, 26200, 1, 19, 30, 9.6),
|
||||||
|
('2024-02-27', 15, 26400, 1, 14, 22, 9.0),
|
||||||
|
('2024-02-28', 10, 26600, 1, 9, 15, 8.4),
|
||||||
|
('2024-02-29', 5, 26800, 1, 4, 7, 7.8),
|
||||||
|
|
||||||
|
-- 3月数据(春节后恢复)
|
||||||
|
('2024-03-01', 200, 27000, 5, 195, 300, 12.0),
|
||||||
|
('2024-03-02', 300, 27200, 10, 290, 450, 15.0),
|
||||||
|
('2024-03-03', 400, 27400, 15, 385, 600, 18.0),
|
||||||
|
('2024-03-04', 500, 27600, 20, 480, 750, 21.0),
|
||||||
|
('2024-03-05', 600, 27800, 25, 575, 900, 24.0),
|
||||||
|
('2024-03-06', 700, 28000, 30, 670, 1050, 27.0),
|
||||||
|
('2024-03-07', 800, 28200, 35, 765, 1200, 30.0),
|
||||||
|
('2024-03-08', 900, 28400, 40, 860, 1350, 33.0),
|
||||||
|
('2024-03-09', 1000, 28600, 45, 955, 1500, 36.0),
|
||||||
|
('2024-03-10', 1100, 28800, 50, 1050, 1650, 39.0),
|
||||||
|
('2024-03-11', 1200, 29000, 55, 1145, 1800, 42.0),
|
||||||
|
('2024-03-12', 1300, 29200, 60, 1240, 1950, 45.0),
|
||||||
|
('2024-03-13', 1400, 29400, 65, 1335, 2100, 48.0),
|
||||||
|
('2024-03-14', 1500, 29600, 70, 1430, 2250, 51.0),
|
||||||
|
('2024-03-15', 1600, 29800, 75, 1525, 2400, 54.0),
|
||||||
|
('2024-03-16', 1700, 30000, 80, 1620, 2550, 57.0),
|
||||||
|
('2024-03-17', 1800, 30200, 85, 1715, 2700, 60.0),
|
||||||
|
('2024-03-18', 1900, 30400, 90, 1810, 2850, 63.0),
|
||||||
|
('2024-03-19', 2000, 30600, 95, 1905, 3000, 66.0),
|
||||||
|
('2024-03-20', 2100, 30800, 100, 2000, 3150, 69.0),
|
||||||
|
('2024-03-21', 2200, 31000, 105, 2095, 3300, 72.0),
|
||||||
|
('2024-03-22', 2300, 31200, 110, 2190, 3450, 75.0),
|
||||||
|
('2024-03-23', 2400, 31400, 115, 2285, 3600, 78.0),
|
||||||
|
('2024-03-24', 2500, 31600, 120, 2380, 3750, 81.0),
|
||||||
|
('2024-03-25', 2600, 31800, 125, 2475, 3900, 84.0),
|
||||||
|
('2024-03-26', 2700, 32000, 130, 2570, 4050, 87.0),
|
||||||
|
('2024-03-27', 2800, 32200, 135, 2665, 4200, 90.0),
|
||||||
|
('2024-03-28', 2900, 32400, 140, 2760, 4350, 93.0),
|
||||||
|
('2024-03-29', 3000, 32600, 145, 2855, 4500, 96.0),
|
||||||
|
('2024-03-30', 3100, 32800, 150, 2950, 4650, 99.0),
|
||||||
|
('2024-03-31', 3200, 33000, 155, 3045, 4800, 102.0),
|
||||||
|
|
||||||
|
-- 4月数据(春季增长期)
|
||||||
|
('2024-04-01', 3300, 33200, 160, 3140, 4950, 105.0),
|
||||||
|
('2024-04-02', 3400, 33400, 165, 3235, 5100, 108.0),
|
||||||
|
('2024-04-03', 3500, 33600, 170, 3330, 5250, 111.0),
|
||||||
|
('2024-04-04', 3600, 33800, 175, 3425, 5400, 114.0),
|
||||||
|
('2024-04-05', 3700, 34000, 180, 3520, 5550, 117.0),
|
||||||
|
('2024-04-06', 3800, 34200, 185, 3615, 5700, 120.0),
|
||||||
|
('2024-04-07', 3900, 34400, 190, 3710, 5850, 123.0),
|
||||||
|
('2024-04-08', 4000, 34600, 195, 3805, 6000, 126.0),
|
||||||
|
('2024-04-09', 4100, 34800, 200, 3900, 6150, 129.0),
|
||||||
|
('2024-04-10', 4200, 35000, 205, 3995, 6300, 132.0),
|
||||||
|
('2024-04-11', 4300, 35200, 210, 4090, 6450, 135.0),
|
||||||
|
('2024-04-12', 4400, 35400, 215, 4185, 6600, 138.0),
|
||||||
|
('2024-04-13', 4500, 35600, 220, 4280, 6750, 141.0),
|
||||||
|
('2024-04-14', 4600, 35800, 225, 4375, 6900, 144.0),
|
||||||
|
('2024-04-15', 4700, 36000, 230, 4470, 7050, 147.0),
|
||||||
|
('2024-04-16', 4800, 36200, 235, 4565, 7200, 150.0),
|
||||||
|
('2024-04-17', 4900, 36400, 240, 4660, 7350, 153.0),
|
||||||
|
('2024-04-18', 5000, 36600, 245, 4755, 7500, 156.0),
|
||||||
|
('2024-04-19', 5100, 36800, 250, 4850, 7650, 159.0),
|
||||||
|
('2024-04-20', 5200, 37000, 255, 4945, 7800, 162.0),
|
||||||
|
('2024-04-21', 5300, 37200, 260, 5040, 7950, 165.0),
|
||||||
|
('2024-04-22', 5400, 37400, 265, 5135, 8100, 168.0),
|
||||||
|
('2024-04-23', 5500, 37600, 270, 5230, 8250, 171.0),
|
||||||
|
('2024-04-24', 5600, 37800, 275, 5325, 8400, 174.0),
|
||||||
|
('2024-04-25', 5700, 38000, 280, 5420, 8550, 177.0),
|
||||||
|
('2024-04-26', 5800, 38200, 285, 5515, 8700, 180.0),
|
||||||
|
('2024-04-27', 5900, 38400, 290, 5610, 8850, 183.0),
|
||||||
|
('2024-04-28', 6000, 38600, 295, 5705, 9000, 186.0),
|
||||||
|
('2024-04-29', 6100, 38800, 300, 5800, 9150, 189.0),
|
||||||
|
('2024-04-30', 6200, 39000, 305, 5895, 9300, 192.0),
|
||||||
|
|
||||||
|
-- 5月数据(五一假期影响)
|
||||||
|
('2024-05-01', 5000, 39200, 200, 4800, 7500, 150.0),
|
||||||
|
('2024-05-02', 4500, 39400, 180, 4320, 6750, 135.0),
|
||||||
|
('2024-05-03', 4000, 39600, 160, 3840, 6000, 120.0),
|
||||||
|
('2024-05-04', 3500, 39800, 140, 3360, 5250, 105.0),
|
||||||
|
('2024-05-05', 3000, 40000, 120, 2880, 4500, 90.0),
|
||||||
|
('2024-05-06', 2500, 40200, 100, 2400, 3750, 75.0),
|
||||||
|
('2024-05-07', 2000, 40400, 80, 1920, 3000, 60.0),
|
||||||
|
('2024-05-08', 1500, 40600, 60, 1440, 2250, 45.0),
|
||||||
|
('2024-05-09', 1000, 40800, 40, 960, 1500, 30.0),
|
||||||
|
('2024-05-10', 800, 41000, 30, 770, 1200, 24.0),
|
||||||
|
('2024-05-11', 600, 41200, 20, 580, 900, 18.0),
|
||||||
|
('2024-05-12', 500, 41400, 15, 485, 750, 15.0),
|
||||||
|
('2024-05-13', 400, 41600, 10, 390, 600, 12.0),
|
||||||
|
('2024-05-14', 300, 41800, 8, 292, 450, 9.0),
|
||||||
|
('2024-05-15', 250, 42000, 5, 245, 375, 7.5),
|
||||||
|
('2024-05-16', 200, 42200, 3, 197, 300, 6.0),
|
||||||
|
('2024-05-17', 150, 42400, 2, 148, 225, 4.5),
|
||||||
|
('2024-05-18', 100, 42600, 1, 99, 150, 3.0),
|
||||||
|
('2024-05-19', 80, 42800, 1, 79, 120, 2.4),
|
||||||
|
('2024-05-20', 60, 43000, 1, 59, 90, 1.8),
|
||||||
|
('2024-05-21', 50, 43200, 1, 49, 75, 1.5),
|
||||||
|
('2024-05-22', 40, 43400, 1, 39, 60, 1.2),
|
||||||
|
('2024-05-23', 30, 43600, 1, 29, 45, 0.9),
|
||||||
|
('2024-05-24', 25, 43800, 1, 24, 37, 0.75),
|
||||||
|
('2024-05-25', 20, 44000, 1, 19, 30, 0.6),
|
||||||
|
('2024-05-26', 15, 44200, 1, 14, 22, 0.45),
|
||||||
|
('2024-05-27', 10, 44400, 1, 9, 15, 0.3),
|
||||||
|
('2024-05-28', 8, 44600, 1, 7, 12, 0.24),
|
||||||
|
('2024-05-29', 5, 44800, 1, 4, 7, 0.15),
|
||||||
|
('2024-05-30', 3, 45000, 1, 2, 4, 0.09),
|
||||||
|
('2024-05-31', 2, 45200, 1, 1, 3, 0.06),
|
||||||
|
|
||||||
|
-- 6月数据(夏季恢复期)
|
||||||
|
('2024-06-01', 100, 45400, 5, 95, 150, 3.0),
|
||||||
|
('2024-06-02', 200, 45600, 10, 190, 300, 6.0),
|
||||||
|
('2024-06-03', 300, 45800, 15, 285, 450, 9.0),
|
||||||
|
('2024-06-04', 400, 46000, 20, 380, 600, 12.0),
|
||||||
|
('2024-06-05', 500, 46200, 25, 475, 750, 15.0),
|
||||||
|
('2024-06-06', 600, 46400, 30, 570, 900, 18.0),
|
||||||
|
('2024-06-07', 700, 46600, 35, 665, 1050, 21.0),
|
||||||
|
('2024-06-08', 800, 46800, 40, 760, 1200, 24.0),
|
||||||
|
('2024-06-09', 900, 47000, 45, 855, 1350, 27.0),
|
||||||
|
('2024-06-10', 1000, 47200, 50, 950, 1500, 30.0),
|
||||||
|
('2024-06-11', 1100, 47400, 55, 1045, 1650, 33.0),
|
||||||
|
('2024-06-12', 1200, 47600, 60, 1140, 1800, 36.0),
|
||||||
|
('2024-06-13', 1300, 47800, 65, 1235, 1950, 39.0),
|
||||||
|
('2024-06-14', 1400, 48000, 70, 1330, 2100, 42.0),
|
||||||
|
('2024-06-15', 1500, 48200, 75, 1425, 2250, 45.0),
|
||||||
|
('2024-06-16', 1600, 48400, 80, 1520, 2400, 48.0),
|
||||||
|
('2024-06-17', 1700, 48600, 85, 1615, 2550, 51.0),
|
||||||
|
('2024-06-18', 1800, 48800, 90, 1710, 2700, 54.0),
|
||||||
|
('2024-06-19', 1900, 49000, 95, 1805, 2850, 57.0),
|
||||||
|
('2024-06-20', 2000, 49200, 100, 1900, 3000, 60.0),
|
||||||
|
('2024-06-21', 2100, 49400, 105, 1995, 3150, 63.0),
|
||||||
|
('2024-06-22', 2200, 49600, 110, 2090, 3300, 66.0),
|
||||||
|
('2024-06-23', 2300, 49800, 115, 2185, 3450, 69.0),
|
||||||
|
('2024-06-24', 2400, 50000, 120, 2280, 3600, 72.0),
|
||||||
|
('2024-06-25', 2500, 50200, 125, 2375, 3750, 75.0),
|
||||||
|
('2024-06-26', 2600, 50400, 130, 2470, 3900, 78.0),
|
||||||
|
('2024-06-27', 2700, 50600, 135, 2565, 4050, 81.0),
|
||||||
|
('2024-06-28', 2800, 50800, 140, 2660, 4200, 84.0),
|
||||||
|
('2024-06-29', 2900, 51000, 145, 2755, 4350, 87.0),
|
||||||
|
('2024-06-30', 3000, 51200, 150, 2850, 4500, 90.0),
|
||||||
|
|
||||||
|
-- 7月数据(夏季高峰期)
|
||||||
|
('2024-07-01', 3100, 51400, 155, 2945, 4650, 93.0),
|
||||||
|
('2024-07-02', 3200, 51600, 160, 3040, 4800, 96.0),
|
||||||
|
('2024-07-03', 3300, 51800, 165, 3135, 4950, 99.0),
|
||||||
|
('2024-07-04', 3400, 52000, 170, 3230, 5100, 102.0),
|
||||||
|
('2024-07-05', 3500, 52200, 175, 3325, 5250, 105.0),
|
||||||
|
('2024-07-06', 3600, 52400, 180, 3420, 5400, 108.0),
|
||||||
|
('2024-07-07', 3700, 52600, 185, 3515, 5550, 111.0),
|
||||||
|
('2024-07-08', 3800, 52800, 190, 3610, 5700, 114.0),
|
||||||
|
('2024-07-09', 3900, 53000, 195, 3705, 5850, 117.0),
|
||||||
|
('2024-07-10', 4000, 53200, 200, 3800, 6000, 120.0),
|
||||||
|
('2024-07-11', 4100, 53400, 205, 3895, 6150, 123.0),
|
||||||
|
('2024-07-12', 4200, 53600, 210, 3990, 6300, 126.0),
|
||||||
|
('2024-07-13', 4300, 53800, 215, 4085, 6450, 129.0),
|
||||||
|
('2024-07-14', 4400, 54000, 220, 4180, 6600, 132.0),
|
||||||
|
('2024-07-15', 4500, 54200, 225, 4275, 6750, 135.0),
|
||||||
|
('2024-07-16', 4600, 54400, 230, 4370, 6900, 138.0),
|
||||||
|
('2024-07-17', 4700, 54600, 235, 4465, 7050, 141.0),
|
||||||
|
('2024-07-18', 4800, 54800, 240, 4560, 7200, 144.0),
|
||||||
|
('2024-07-19', 4900, 55000, 245, 4655, 7350, 147.0),
|
||||||
|
('2024-07-20', 5000, 55200, 250, 4750, 7500, 150.0),
|
||||||
|
('2024-07-21', 5100, 55400, 255, 4845, 7650, 153.0),
|
||||||
|
('2024-07-22', 5200, 55600, 260, 4940, 7800, 156.0),
|
||||||
|
('2024-07-23', 5300, 55800, 265, 5035, 7950, 159.0),
|
||||||
|
('2024-07-24', 5400, 56000, 270, 5130, 8100, 162.0),
|
||||||
|
('2024-07-25', 5500, 56200, 275, 5225, 8250, 165.0),
|
||||||
|
('2024-07-26', 5600, 56400, 280, 5320, 8400, 168.0),
|
||||||
|
('2024-07-27', 5700, 56600, 285, 5415, 8550, 171.0),
|
||||||
|
('2024-07-28', 5800, 56800, 290, 5510, 8700, 174.0),
|
||||||
|
('2024-07-29', 5900, 57000, 295, 5605, 8850, 177.0),
|
||||||
|
('2024-07-30', 6000, 57200, 300, 5700, 9000, 180.0),
|
||||||
|
('2024-07-31', 6100, 57400, 305, 5795, 9150, 183.0),
|
||||||
|
|
||||||
|
-- 8月数据(夏季高峰延续)
|
||||||
|
('2024-08-01', 6200, 57600, 310, 5890, 9300, 186.0),
|
||||||
|
('2024-08-02', 6300, 57800, 315, 5985, 9450, 189.0),
|
||||||
|
('2024-08-03', 6400, 58000, 320, 6080, 9600, 192.0),
|
||||||
|
('2024-08-04', 6500, 58200, 325, 6175, 9750, 195.0),
|
||||||
|
('2024-08-05', 6600, 58400, 330, 6270, 9900, 198.0),
|
||||||
|
('2024-08-06', 6700, 58600, 335, 6365, 10050, 201.0),
|
||||||
|
('2024-08-07', 6800, 58800, 340, 6460, 10200, 204.0),
|
||||||
|
('2024-08-08', 6900, 59000, 345, 6555, 10350, 207.0),
|
||||||
|
('2024-08-09', 7000, 59200, 350, 6650, 10500, 210.0),
|
||||||
|
('2024-08-10', 7100, 59400, 355, 6745, 10650, 213.0),
|
||||||
|
('2024-08-11', 7200, 59600, 360, 6840, 10800, 216.0),
|
||||||
|
('2024-08-12', 7300, 59800, 365, 6935, 10950, 219.0),
|
||||||
|
('2024-08-13', 7400, 60000, 370, 7030, 11100, 222.0),
|
||||||
|
('2024-08-14', 7500, 60200, 375, 7125, 11250, 225.0),
|
||||||
|
('2024-08-15', 7600, 60400, 380, 7220, 11400, 228.0),
|
||||||
|
('2024-08-16', 7700, 60600, 385, 7315, 11550, 231.0),
|
||||||
|
('2024-08-17', 7800, 60800, 390, 7410, 11700, 234.0),
|
||||||
|
('2024-08-18', 7900, 61000, 395, 7505, 11850, 237.0),
|
||||||
|
('2024-08-19', 8000, 61200, 400, 7600, 12000, 240.0),
|
||||||
|
('2024-08-20', 8100, 61400, 405, 7695, 12150, 243.0),
|
||||||
|
('2024-08-21', 8200, 61600, 410, 7790, 12300, 246.0),
|
||||||
|
('2024-08-22', 8300, 61800, 415, 7885, 12450, 249.0),
|
||||||
|
('2024-08-23', 8400, 62000, 420, 7980, 12600, 252.0),
|
||||||
|
('2024-08-24', 8500, 62200, 425, 8075, 12750, 255.0),
|
||||||
|
('2024-08-25', 8600, 62400, 430, 8170, 12900, 258.0),
|
||||||
|
('2024-08-26', 8700, 62600, 435, 8265, 13050, 261.0),
|
||||||
|
('2024-08-27', 8800, 62800, 440, 8360, 13200, 264.0),
|
||||||
|
('2024-08-28', 8900, 63000, 445, 8455, 13350, 267.0),
|
||||||
|
('2024-08-29', 9000, 63200, 450, 8550, 13500, 270.0),
|
||||||
|
('2024-08-30', 9100, 63400, 455, 8645, 13650, 273.0),
|
||||||
|
('2024-08-31', 9200, 63600, 460, 8740, 13800, 276.0),
|
||||||
|
|
||||||
|
-- 9月数据(秋季开学季)
|
||||||
|
('2024-09-01', 9300, 63800, 465, 8835, 13950, 279.0),
|
||||||
|
('2024-09-02', 9400, 64000, 470, 8930, 14100, 282.0),
|
||||||
|
('2024-09-03', 9500, 64200, 475, 9025, 14250, 285.0),
|
||||||
|
('2024-09-04', 9600, 64400, 480, 9120, 14400, 288.0),
|
||||||
|
('2024-09-05', 9700, 64600, 485, 9215, 14550, 291.0),
|
||||||
|
('2024-09-06', 9800, 64800, 490, 9310, 14700, 294.0),
|
||||||
|
('2024-09-07', 9900, 65000, 495, 9405, 14850, 297.0),
|
||||||
|
('2024-09-08', 10000, 65200, 500, 9500, 15000, 300.0),
|
||||||
|
('2024-09-09', 10100, 65400, 505, 9595, 15150, 303.0),
|
||||||
|
('2024-09-10', 10200, 65600, 510, 9690, 15300, 306.0),
|
||||||
|
('2024-09-11', 10300, 65800, 515, 9785, 15450, 309.0),
|
||||||
|
('2024-09-12', 10400, 66000, 520, 9880, 15600, 312.0),
|
||||||
|
('2024-09-13', 10500, 66200, 525, 9975, 15750, 315.0),
|
||||||
|
('2024-09-14', 10600, 66400, 530, 10070, 15900, 318.0),
|
||||||
|
('2024-09-15', 10700, 66600, 535, 10165, 16050, 321.0),
|
||||||
|
('2024-09-16', 10800, 66800, 540, 10260, 16200, 324.0),
|
||||||
|
('2024-09-17', 10900, 67000, 545, 10355, 16350, 327.0),
|
||||||
|
('2024-09-18', 11000, 67200, 550, 10450, 16500, 330.0),
|
||||||
|
('2024-09-19', 11100, 67400, 555, 10545, 16650, 333.0),
|
||||||
|
('2024-09-20', 11200, 67600, 560, 10640, 16800, 336.0),
|
||||||
|
('2024-09-21', 11300, 67800, 565, 10735, 16950, 339.0),
|
||||||
|
('2024-09-22', 11400, 68000, 570, 10830, 17100, 342.0),
|
||||||
|
('2024-09-23', 11500, 68200, 575, 10925, 17250, 345.0),
|
||||||
|
('2024-09-24', 11600, 68400, 580, 11020, 17400, 348.0),
|
||||||
|
('2024-09-25', 11700, 68600, 585, 11115, 17550, 351.0),
|
||||||
|
('2024-09-26', 11800, 68800, 590, 11210, 17700, 354.0),
|
||||||
|
('2024-09-27', 11900, 69000, 595, 11305, 17850, 357.0),
|
||||||
|
('2024-09-28', 12000, 69200, 600, 11400, 18000, 360.0),
|
||||||
|
('2024-09-29', 12100, 69400, 605, 11495, 18150, 363.0),
|
||||||
|
('2024-09-30', 12200, 69600, 610, 11590, 18300, 366.0),
|
||||||
|
|
||||||
|
-- 10月数据(秋季稳定期)
|
||||||
|
('2024-10-01', 12000, 69800, 600, 11400, 18000, 360.0),
|
||||||
|
('2024-10-02', 11800, 70000, 580, 11220, 17700, 354.0),
|
||||||
|
('2024-10-03', 11600, 70200, 560, 11040, 17400, 348.0),
|
||||||
|
('2024-10-04', 11400, 70400, 540, 10860, 17100, 342.0),
|
||||||
|
('2024-10-05', 11200, 70600, 520, 10680, 16800, 336.0),
|
||||||
|
('2024-10-06', 11000, 70800, 500, 10500, 16500, 330.0),
|
||||||
|
('2024-10-07', 10800, 71000, 480, 10320, 16200, 324.0),
|
||||||
|
('2024-10-08', 10600, 71200, 460, 10140, 15900, 318.0),
|
||||||
|
('2024-10-09', 10400, 71400, 440, 9960, 15600, 312.0),
|
||||||
|
('2024-10-10', 10200, 71600, 420, 9780, 15300, 306.0),
|
||||||
|
('2024-10-11', 10000, 71800, 400, 9600, 15000, 300.0),
|
||||||
|
('2024-10-12', 9800, 72000, 380, 9420, 14700, 294.0),
|
||||||
|
('2024-10-13', 9600, 72200, 360, 9240, 14400, 288.0),
|
||||||
|
('2024-10-14', 9400, 72400, 340, 9060, 14100, 282.0),
|
||||||
|
('2024-10-15', 9200, 72600, 320, 8880, 13800, 276.0),
|
||||||
|
('2024-10-16', 9000, 72800, 300, 8700, 13500, 270.0),
|
||||||
|
('2024-10-17', 8800, 73000, 280, 8520, 13200, 264.0),
|
||||||
|
('2024-10-18', 8600, 73200, 260, 8340, 12900, 258.0),
|
||||||
|
('2024-10-19', 8400, 73400, 240, 8160, 12600, 252.0),
|
||||||
|
('2024-10-20', 8200, 73600, 220, 7980, 12300, 246.0),
|
||||||
|
('2024-10-21', 8000, 73800, 200, 7800, 12000, 240.0),
|
||||||
|
('2024-10-22', 7800, 74000, 180, 7620, 11700, 234.0),
|
||||||
|
('2024-10-23', 7600, 74200, 160, 7440, 11400, 228.0),
|
||||||
|
('2024-10-24', 7400, 74400, 140, 7260, 11100, 222.0),
|
||||||
|
('2024-10-25', 7200, 74600, 120, 7080, 10800, 216.0),
|
||||||
|
('2024-10-26', 7000, 74800, 100, 6900, 10500, 210.0),
|
||||||
|
('2024-10-27', 6800, 75000, 80, 6720, 10200, 204.0),
|
||||||
|
('2024-10-28', 6600, 75200, 60, 6540, 9900, 198.0),
|
||||||
|
('2024-10-29', 6400, 75400, 40, 6360, 9600, 192.0),
|
||||||
|
('2024-10-30', 6200, 75600, 20, 6180, 9300, 186.0),
|
||||||
|
('2024-10-31', 6000, 75800, 10, 5990, 9000, 180.0),
|
||||||
|
|
||||||
|
-- 11月数据(冬季开始)
|
||||||
|
('2024-11-01', 5800, 76000, 5, 5795, 8700, 174.0),
|
||||||
|
('2024-11-02', 5600, 76200, 5, 5595, 8400, 168.0),
|
||||||
|
('2024-11-03', 5400, 76400, 5, 5395, 8100, 162.0),
|
||||||
|
('2024-11-04', 5200, 76600, 5, 5195, 7800, 156.0),
|
||||||
|
('2024-11-05', 5000, 76800, 5, 4995, 7500, 150.0),
|
||||||
|
('2024-11-06', 4800, 77000, 5, 4795, 7200, 144.0),
|
||||||
|
('2024-11-07', 4600, 77200, 5, 4595, 6900, 138.0),
|
||||||
|
('2024-11-08', 4400, 77400, 5, 4395, 6600, 132.0),
|
||||||
|
('2024-11-09', 4200, 77600, 5, 4195, 6300, 126.0),
|
||||||
|
('2024-11-10', 4000, 77800, 5, 3995, 6000, 120.0),
|
||||||
|
('2024-11-11', 3800, 78000, 5, 3795, 5700, 114.0),
|
||||||
|
('2024-11-12', 3600, 78200, 5, 3595, 5400, 108.0),
|
||||||
|
('2024-11-13', 3400, 78400, 5, 3395, 5100, 102.0),
|
||||||
|
('2024-11-14', 3200, 78600, 5, 3195, 4800, 96.0),
|
||||||
|
('2024-11-15', 3000, 78800, 5, 2995, 4500, 90.0),
|
||||||
|
('2024-11-16', 2800, 79000, 5, 2795, 4200, 84.0),
|
||||||
|
('2024-11-17', 2600, 79200, 5, 2595, 3900, 78.0),
|
||||||
|
('2024-11-18', 2400, 79400, 5, 2395, 3600, 72.0),
|
||||||
|
('2024-11-19', 2200, 79600, 5, 2195, 3300, 66.0),
|
||||||
|
('2024-11-20', 2000, 79800, 5, 1995, 3000, 60.0),
|
||||||
|
('2024-11-21', 1800, 80000, 5, 1795, 2700, 54.0),
|
||||||
|
('2024-11-22', 1600, 80200, 5, 1595, 2400, 48.0),
|
||||||
|
('2024-11-23', 1400, 80400, 5, 1395, 2100, 42.0),
|
||||||
|
('2024-11-24', 1200, 80600, 5, 1195, 1800, 36.0),
|
||||||
|
('2024-11-25', 1000, 80800, 5, 995, 1500, 30.0),
|
||||||
|
('2024-11-26', 800, 81000, 5, 795, 1200, 24.0),
|
||||||
|
('2024-11-27', 600, 81200, 5, 595, 900, 18.0),
|
||||||
|
('2024-11-28', 400, 81400, 5, 395, 600, 12.0),
|
||||||
|
('2024-11-29', 200, 81600, 5, 195, 300, 6.0),
|
||||||
|
('2024-11-30', 100, 81800, 5, 95, 150, 3.0),
|
||||||
|
|
||||||
|
-- 12月数据(年末总结)
|
||||||
|
('2024-12-01', 500, 82000, 10, 490, 750, 15.0),
|
||||||
|
('2024-12-02', 600, 82200, 15, 585, 900, 18.0),
|
||||||
|
('2024-12-03', 700, 82400, 20, 680, 1050, 21.0),
|
||||||
|
('2024-12-04', 800, 82600, 25, 775, 1200, 24.0),
|
||||||
|
('2024-12-05', 900, 82800, 30, 870, 1350, 27.0),
|
||||||
|
('2024-12-06', 1000, 83000, 35, 965, 1500, 30.0),
|
||||||
|
('2024-12-07', 1100, 83200, 40, 1060, 1650, 33.0),
|
||||||
|
('2024-12-08', 1200, 83400, 45, 1155, 1800, 36.0),
|
||||||
|
('2024-12-09', 1300, 83600, 50, 1250, 1950, 39.0),
|
||||||
|
('2024-12-10', 1400, 83800, 55, 1345, 2100, 42.0),
|
||||||
|
('2024-12-11', 1500, 84000, 60, 1440, 2250, 45.0),
|
||||||
|
('2024-12-12', 1600, 84200, 65, 1535, 2400, 48.0),
|
||||||
|
('2024-12-13', 1700, 84400, 70, 1630, 2550, 51.0),
|
||||||
|
('2024-12-14', 1800, 84600, 75, 1725, 2700, 54.0),
|
||||||
|
('2024-12-15', 1900, 84800, 80, 1820, 2850, 57.0),
|
||||||
|
('2024-12-16', 2000, 85000, 85, 1915, 3000, 60.0),
|
||||||
|
('2024-12-17', 2100, 85200, 90, 2010, 3150, 63.0),
|
||||||
|
('2024-12-18', 2200, 85400, 95, 2105, 3300, 66.0),
|
||||||
|
('2024-12-19', 2300, 85600, 100, 2200, 3450, 69.0),
|
||||||
|
('2024-12-20', 2400, 85800, 105, 2295, 3600, 72.0),
|
||||||
|
('2024-12-21', 2500, 86000, 110, 2390, 3750, 75.0),
|
||||||
|
('2024-12-22', 2600, 86200, 115, 2485, 3900, 78.0),
|
||||||
|
('2024-12-23', 2700, 86400, 120, 2580, 4050, 81.0),
|
||||||
|
('2024-12-24', 2800, 86600, 125, 2675, 4200, 84.0),
|
||||||
|
('2024-12-25', 2900, 86800, 130, 2770, 4350, 87.0),
|
||||||
|
('2024-12-26', 3000, 87000, 135, 2865, 4500, 90.0),
|
||||||
|
('2024-12-27', 3100, 87200, 140, 2960, 4650, 93.0),
|
||||||
|
('2024-12-28', 3200, 87400, 145, 3055, 4800, 96.0),
|
||||||
|
('2024-12-29', 3300, 87600, 150, 3150, 4950, 99.0),
|
||||||
|
('2024-12-30', 3400, 87800, 155, 3245, 5100, 102.0),
|
||||||
|
('2024-12-31', 3500, 88000, 160, 3340, 5250, 105.0);
|
||||||
Reference in New Issue
Block a user