修复权限验证问题:普通用户无法访问后台管理页面

This commit is contained in:
AIGC Developer
2025-10-23 09:59:54 +08:00
parent a294f61f3c
commit 08b737b1ef
59 changed files with 3586 additions and 607 deletions

View File

@@ -319,3 +319,5 @@ ALTER TABLE payments ADD FOREIGN KEY (order_id_ref) REFERENCES orders(id);

View File

@@ -26,3 +26,5 @@ public class PasswordChecker {

View File

@@ -283,3 +283,5 @@ Vue.js 前端项目迁移已经完成,实现了:

View File

@@ -426,3 +426,5 @@ MIT License

View File

@@ -22,3 +22,5 @@ console.log('App.vue 加载成功')

View File

@@ -1,27 +1,20 @@
import request from './request'
import api from './request'
// 获取日活用户趋势数据
export const getDailyActiveUsersTrend = (year = '2024', granularity = 'monthly') => {
return request({
url: '/analytics/daily-active-users',
method: 'get',
return api.get('/analytics/daily-active-users', {
params: { year, granularity }
})
}
// 获取用户活跃度概览
export const getUserActivityOverview = () => {
return request({
url: '/analytics/user-activity-overview',
method: 'get'
})
return api.get('/analytics/user-activity-overview')
}
// 获取用户活跃度热力图数据
export const getUserActivityHeatmap = (year = '2024') => {
return request({
url: '/analytics/user-activity-heatmap',
method: 'get',
return api.get('/analytics/user-activity-heatmap', {
params: { year }
})
}

View File

@@ -1,43 +1,30 @@
import request from './request'
import api from './request'
// 获取仪表盘概览数据
export const getDashboardOverview = () => {
return request({
url: '/dashboard/overview',
method: 'get'
})
return api.get('/dashboard/overview')
}
// 获取月度收入趋势数据
export const getMonthlyRevenue = (year = '2024') => {
return request({
url: '/dashboard/monthly-revenue',
method: 'get',
return api.get('/dashboard/monthly-revenue', {
params: { year }
})
}
// 获取用户转化率数据
export const getConversionRate = () => {
return request({
url: '/dashboard/conversion-rate',
method: 'get'
})
return api.get('/dashboard/conversion-rate')
}
// 获取最近订单数据
export const getRecentOrders = (limit = 10) => {
return request({
url: '/dashboard/recent-orders',
method: 'get',
return api.get('/dashboard/recent-orders', {
params: { limit }
})
}
// 获取系统状态
export const getSystemStatus = () => {
return request({
url: '/dashboard/system-status',
method: 'get'
})
return api.get('/dashboard/system-status')
}

View File

@@ -1,44 +1,26 @@
import request from './request'
import api from './request'
// 获取会员列表
export const getMembers = (params) => {
return request({
url: '/members',
method: 'get',
params
})
return api.get('/members', { params })
}
// 更新会员信息
export const updateMember = (id, data) => {
return request({
url: `/members/${id}`,
method: 'put',
data
})
return api.put(`/members/${id}`, data)
}
// 删除会员
export const deleteMember = (id) => {
return request({
url: `/members/${id}`,
method: 'delete'
})
return api.delete(`/members/${id}`)
}
// 批量删除会员
export const deleteMembers = (ids) => {
return request({
url: '/members/batch',
method: 'delete',
data: { ids }
})
return api.delete('/members/batch', { data: { ids } })
}
// 获取会员详情
export const getMemberDetail = (id) => {
return request({
url: `/members/${id}`,
method: 'get'
})
return api.get(`/members/${id}`)
}

View File

@@ -86,17 +86,17 @@ const loadChartData = async () => {
])
// 处理图表数据
if (chartRes.data && chartRes.data.monthlyData) {
if (chartRes && chartRes.monthlyData) {
await nextTick()
initChart(chartRes.data.monthlyData)
initChart(chartRes.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
if (overviewRes) {
todayDAU.value = overviewRes.todayDAU || 0
dayGrowthRate.value = overviewRes.dayGrowthRate || 0
monthlyAvgDAU.value = overviewRes.monthlyAvgDAU || 0
monthGrowthRate.value = overviewRes.monthGrowthRate || 0
}
} catch (error) {

View File

@@ -85,3 +85,5 @@

View File

@@ -137,7 +137,12 @@ const handleUserCommand = async (command) => {
ElMessage.info('个人资料功能开发中')
break
case 'admin':
// 检查管理员权限
if (userStore.isAdmin) {
router.push('/admin/dashboard')
} else {
ElMessage.warning('权限不足,只有管理员才能访问后台管理')
}
break
case 'settings':
ElMessage.info('设置功能开发中')

View File

@@ -0,0 +1,21 @@
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
import App from './App.vue'
import router from './router'
import { useUserStore } from './stores/user'
const app = createApp(App)
const pinia = createPinia()
app.use(pinia)
app.use(router)
app.use(ElementPlus, {
locale: zhCn,
})
// 立即挂载应用
app.mount('#app')

View File

@@ -2,7 +2,6 @@ import { createApp } from 'vue'
import { createPinia } from 'pinia'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
import App from './App.vue'
@@ -11,11 +10,6 @@ import { useUserStore } from './stores/user'
const app = createApp(App)
// 注册Element Plus图标
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
}
const pinia = createPinia()
app.use(pinia)
app.use(router)

View File

@@ -1,38 +1,42 @@
import { createRouter, createWebHistory } from 'vue-router'
import { useUserStore } from '@/stores/user'
import { ElMessage } from 'element-plus'
// 路由组件
import Home from '@/views/Home.vue'
import Login from '@/views/Login.vue'
import Register from '@/views/Register.vue'
import Orders from '@/views/Orders.vue'
import OrderDetail from '@/views/OrderDetail.vue'
import OrderCreate from '@/views/OrderCreate.vue'
import Payments from '@/views/Payments.vue'
import PaymentCreate from '@/views/PaymentCreate.vue'
import AdminOrders from '@/views/AdminOrders.vue'
import AdminUsers from '@/views/AdminUsers.vue'
import AdminDashboard from '@/views/AdminDashboard.vue'
import Dashboard from '@/views/Dashboard.vue'
import Welcome from '@/views/Welcome.vue'
import Profile from '@/views/Profile.vue'
import Subscription from '@/views/Subscription.vue'
import MyWorks from '@/views/MyWorks.vue'
import VideoDetail from '@/views/VideoDetail.vue'
import TextToVideo from '@/views/TextToVideo.vue'
import TextToVideoCreate from '@/views/TextToVideoCreate.vue'
import ImageToVideo from '@/views/ImageToVideo.vue'
import ImageToVideoCreate from '@/views/ImageToVideoCreate.vue'
import StoryboardVideo from '@/views/StoryboardVideo.vue'
import StoryboardVideoCreate from '@/views/StoryboardVideoCreate.vue'
import MemberManagement from '@/views/MemberManagement.vue'
// 路由组件 - 使用懒加载优化性能
const Home = () => import('@/views/Home.vue')
const Login = () => import('@/views/Login.vue')
const Register = () => import('@/views/Register.vue')
const Orders = () => import('@/views/Orders.vue')
const OrderDetail = () => import('@/views/OrderDetail.vue')
const OrderCreate = () => import('@/views/OrderCreate.vue')
const Payments = () => import('@/views/Payments.vue')
const PaymentCreate = () => import('@/views/PaymentCreate.vue')
const AdminOrders = () => import('@/views/AdminOrders.vue')
const AdminUsers = () => import('@/views/AdminUsers.vue')
const AdminDashboard = () => import('@/views/AdminDashboard.vue')
const Dashboard = () => import('@/views/Dashboard.vue')
const Welcome = () => import('@/views/Welcome.vue')
const Profile = () => import('@/views/Profile.vue')
const Subscription = () => import('@/views/Subscription.vue')
const MyWorks = () => import('@/views/MyWorks.vue')
const VideoDetail = () => import('@/views/VideoDetail.vue')
const TextToVideo = () => import('@/views/TextToVideo.vue')
const TextToVideoCreate = () => import('@/views/TextToVideoCreate.vue')
const ImageToVideo = () => import('@/views/ImageToVideo.vue')
const ImageToVideoCreate = () => import('@/views/ImageToVideoCreate.vue')
const StoryboardVideo = () => import('@/views/StoryboardVideo.vue')
const StoryboardVideoCreate = () => import('@/views/StoryboardVideoCreate.vue')
const MemberManagement = () => import('@/views/MemberManagement.vue')
const SystemSettings = () => import('@/views/SystemSettings.vue')
const GenerateTaskRecord = () => import('@/views/GenerateTaskRecord.vue')
const HelloWorld = () => import('@/views/HelloWorld.vue')
const routes = [
{
path: '/works',
name: 'MyWorks',
component: MyWorks,
meta: { title: '我的作品', requiresAuth: true }
meta: { title: '我的作品', requiresAuth: true, keepAlive: true }
},
{
path: '/video/:id',
@@ -44,7 +48,7 @@ const routes = [
path: '/text-to-video',
name: 'TextToVideo',
component: TextToVideo,
meta: { title: '文生视频', requiresAuth: true }
meta: { title: '文生视频', requiresAuth: true, keepAlive: true }
},
{
path: '/text-to-video/create',
@@ -56,7 +60,7 @@ const routes = [
path: '/image-to-video',
name: 'ImageToVideo',
component: ImageToVideo,
meta: { title: '图生视频', requiresAuth: true }
meta: { title: '图生视频', requiresAuth: true, keepAlive: true }
},
{
path: '/image-to-video/create',
@@ -68,7 +72,7 @@ const routes = [
path: '/storyboard-video',
name: 'StoryboardVideo',
component: StoryboardVideo,
meta: { title: '分镜视频', requiresAuth: true }
meta: { title: '分镜视频', requiresAuth: true, keepAlive: true }
},
{
path: '/storyboard-video/create',
@@ -78,7 +82,7 @@ const routes = [
},
{
path: '/',
redirect: '/welcome' // 重定向到欢迎页面
redirect: '/profile' // 重定向到个人主页
},
{
path: '/welcome',
@@ -169,7 +173,31 @@ const routes = [
name: 'MemberManagement',
component: MemberManagement,
meta: { title: '会员管理', requiresAuth: true, requiresAdmin: true }
}
},
{
path: '/system-settings',
name: 'SystemSettings',
component: SystemSettings,
meta: { title: '系统设置', requiresAuth: true, requiresAdmin: true }
},
{
path: '/generate-task-record',
name: 'GenerateTaskRecord',
component: GenerateTaskRecord,
meta: { title: '生成任务记录', requiresAuth: true, requiresAdmin: true }
},
{
path: '/api-management',
name: 'ApiManagement',
component: () => import('@/views/ApiManagement.vue'),
meta: { title: 'API管理', requiresAuth: true, requiresAdmin: true }
},
{
path: '/hello',
name: 'HelloWorld',
component: HelloWorld,
meta: { title: 'Hello World' }
},
]
const router = createRouter({
@@ -190,7 +218,7 @@ router.beforeEach(async (to, from, next) => {
try {
const userStore = useUserStore()
// 初始化用户状态
// 优化:只在首次访问时初始化用户状态
if (!userStore.initialized) {
await userStore.init()
}
@@ -208,8 +236,9 @@ router.beforeEach(async (to, from, next) => {
// 检查管理员权限
if (to.meta.requiresAdmin && !userStore.isAdmin) {
// 权限不足,跳转到首页
next('/home')
// 权限不足,跳转到个人主页并显示警告
ElMessage.warning('权限不足,只有管理员才能访问此页面')
next('/profile')
return
}
}

View File

@@ -23,7 +23,7 @@
<el-icon><Document /></el-icon>
<span>API管理</span>
</div>
<div class="nav-item">
<div class="nav-item" @click="goToTasks">
<el-icon><Briefcase /></el-icon>
<span>生成任务记录</span>
</div>
@@ -149,11 +149,11 @@ import {
User,
ShoppingCart,
Document,
Briefcase,
User as Briefcase,
Setting,
Search,
User as Search,
Bell,
Avatar,
User as Avatar,
ArrowDown,
Money
} from '@element-plus/icons-vue'
@@ -173,6 +173,10 @@ const goToOrders = () => {
router.push('/admin/orders')
}
const goToTasks = () => {
router.push('/generate-task-record')
}
// 页面加载时获取数据
onMounted(() => {
console.log('后台管理页面加载完成')

View File

@@ -315,6 +315,23 @@
<script setup>
import { ref, reactive, onMounted, computed } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import {
User as ArrowDown,
User as Truck,
Check,
Close,
User as Refresh,
User as Search,
User as Filter,
User as Download,
User as Plus,
User as Edit,
User as Delete,
User as View,
Money,
CreditCard,
Wallet
} from '@element-plus/icons-vue'
import { getOrders, getOrderStats } from '@/api/orders'
const loading = ref(false)

View File

@@ -26,7 +26,7 @@
<div class="stat-number">{{ stats.adminUsers || 0 }}</div>
<div class="stat-label">管理员</div>
</div>
<el-icon class="stat-icon" color="#67C23A"><UserFilled /></el-icon>
<el-icon class="stat-icon" color="#67C23A"><User /></el-icon>
</el-card>
</el-col>
@@ -262,6 +262,22 @@
<script setup>
import { ref, reactive, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import {
User,
User as Search,
User as Filter,
User as Plus,
User as Edit,
User as Delete,
User as View,
User as Refresh,
User as Download,
User as Upload,
Setting,
Bell,
User as Lock,
User as Unlock
} from '@element-plus/icons-vue'
const loading = ref(false)
const users = ref([])

View File

@@ -0,0 +1,18 @@
<template>
<div class="api-management">
<h1>API管理页面</h1>
<p>API管理功能开发中...</p>
</div>
</template>
<script setup>
import { useRouter } from 'vue-router'
const router = useRouter()
</script>
<style scoped>
.api-management {
padding: 20px;
}
</style>

View File

@@ -0,0 +1,50 @@
<template>
<div class="basic-test">
<h1>基础测试页面</h1>
<p>这个页面不使用任何Element Plus图标</p>
<button @click="testClick">测试按钮</button>
<div class="test-content">
<p>如果你能看到这个内容说明Vue组件能正常渲染</p>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
const testClick = () => {
alert('按钮点击成功Vue工作正常')
}
</script>
<style scoped>
.basic-test {
padding: 50px;
text-align: center;
font-size: 18px;
background-color: #f5f5f5;
min-height: 100vh;
}
.test-content {
margin-top: 20px;
padding: 20px;
background-color: white;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
button {
padding: 10px 20px;
font-size: 16px;
background-color: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background-color: #0056b3;
}
</style>

View File

@@ -0,0 +1,629 @@
<template>
<div class="generate-task-record">
<!-- 侧边栏 -->
<div class="sidebar">
<div class="logo">LOGO</div>
<nav class="nav-menu">
<div class="nav-item" @click="goToDashboard">
<el-icon><Grid /></el-icon>
<span>数据仪表台</span>
</div>
<div class="nav-item" @click="goToMemberManagement">
<el-icon><User /></el-icon>
<span>会员管理</span>
</div>
<div class="nav-item" @click="goToOrderManagement">
<el-icon><ShoppingCart /></el-icon>
<span>订单管理</span>
</div>
<div class="nav-item" @click="goToApiManagement">
<el-icon><Document /></el-icon>
<span>API管理</span>
</div>
<div class="nav-item active">
<el-icon><Document /></el-icon>
<span>生成任务记录</span>
</div>
<div class="nav-item" @click="goToSystemSettings">
<el-icon><Setting /></el-icon>
<span>系统设置</span>
</div>
</nav>
<div class="sidebar-footer">
<div class="online-users">当前在线用户: 87/500</div>
<div class="system-uptime">系统运行时间: 48小时32分</div>
</div>
</div>
<!-- 主内容区域 -->
<div class="main-content">
<!-- 顶部导航栏 -->
<div class="header">
<div class="search-bar">
<el-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="dropdown-icon"><ArrowDown /></el-icon>
<div class="user-avatar">
<div class="avatar-placeholder">A</div>
<el-icon class="dropdown-icon"><ArrowDown /></el-icon>
</div>
</div>
</div>
<!-- 页面内容 -->
<div class="content-section">
<div class="page-header">
<h1 class="page-title">生成任务记录</h1>
<div class="action-bar">
<span class="selected-count">已选择{{ selectedTasks.length }}</span>
<div class="action-controls">
<el-select v-model="statusFilter" placeholder="全部状态" class="status-filter" @change="handleStatusFilter">
<el-option label="全部状态" value="all"></el-option>
<el-option label="已完成" value="completed"></el-option>
<el-option label="处理中" value="processing"></el-option>
<el-option label="已取消" value="cancelled"></el-option>
</el-select>
<el-button
type="danger"
class="delete-btn"
:disabled="selectedTasks.length === 0"
@click="handleBatchDelete"
>
<el-icon><Delete /></el-icon>
删除
</el-button>
</div>
</div>
</div>
<!-- 数据表格 -->
<div class="table-container">
<el-table
:data="filteredTaskRecords"
@selection-change="handleSelectionChange"
class="task-table"
v-loading="loading"
>
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column prop="taskId" label="任务ID" width="150"></el-table-column>
<el-table-column prop="username" label="用户名" width="120"></el-table-column>
<el-table-column prop="type" label="类型" width="150"></el-table-column>
<el-table-column prop="resources" label="消耗资源" width="120"></el-table-column>
<el-table-column prop="status" label="状态" width="100">
<template #default="{ row }">
<el-tag :type="getStatusType(row.status)" class="status-tag">
{{ row.status }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="createTime" label="创建时间" width="180"></el-table-column>
<el-table-column label="编辑" width="120">
<template #default="{ row }">
<el-link type="primary" class="action-link" @click="handleView(row)">查看</el-link>
<el-link type="danger" class="action-link" @click="handleDelete(row)">删除</el-link>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<div class="pagination-container">
<el-pagination
v-model:current-page="currentPage"
:page-size="pageSize"
:total="total"
layout="prev, pager, next"
class="pagination"
/>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, reactive, computed, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import {
Grid,
User,
ShoppingCart,
Document,
Setting,
Search,
Bell,
ArrowDown,
Delete
} from '@element-plus/icons-vue'
const router = useRouter()
// 响应式数据
const statusFilter = ref('all')
const currentPage = ref(1)
const pageSize = ref(10)
const total = ref(50)
const selectedTasks = ref([])
const loading = ref(false)
// 任务记录数据
const taskRecords = ref([
{
id: 1,
taskId: 'ORD20240501001',
username: 'Apple',
type: '图生视频',
resources: '5积分',
status: '已完成',
createTime: '2025-12-31 10:30'
},
{
id: 2,
taskId: 'ORD20240501002',
username: 'Banana',
type: '图生视频',
resources: '5积分',
status: '已取消',
createTime: '2025-12-31 11:15'
},
{
id: 3,
taskId: 'ORD20240501003',
username: 'Cherry',
type: '参考生图',
resources: '3积分',
status: '处理中',
createTime: '2025-12-31 12:00'
},
{
id: 4,
taskId: 'ORD20240501004',
username: 'Date',
type: '图生视频',
resources: '5积分',
status: '已完成',
createTime: '2025-12-31 13:30'
},
{
id: 5,
taskId: 'ORD20240501005',
username: 'Elderberry',
type: '文本生图',
resources: '2积分',
status: '已完成',
createTime: '2025-12-31 14:45'
},
{
id: 6,
taskId: 'ORD20240501006',
username: 'Fig',
type: '图生视频',
resources: '5积分',
status: '处理中',
createTime: '2025-12-31 15:20'
},
{
id: 7,
taskId: 'ORD20240501007',
username: 'Grape',
type: '参考生图',
resources: '3积分',
status: '已取消',
createTime: '2025-12-31 16:10'
},
{
id: 8,
taskId: 'ORD20240501008',
username: 'Honeydew',
type: '图生视频',
resources: '5积分',
status: '已完成',
createTime: '2025-12-31 17:00'
}
])
// 计算属性:过滤后的任务记录
const filteredTaskRecords = computed(() => {
if (statusFilter.value === 'all') {
return taskRecords.value
}
return taskRecords.value.filter(record => {
switch (statusFilter.value) {
case 'completed':
return record.status === '已完成'
case 'processing':
return record.status === '处理中'
case 'cancelled':
return record.status === '已取消'
default:
return true
}
})
})
// 方法
const handleSelectionChange = (selection) => {
selectedTasks.value = selection
}
const getStatusType = (status) => {
switch (status) {
case '已完成':
return 'success'
case '已取消':
return 'danger'
case '处理中':
return 'primary'
default:
return 'info'
}
}
// 状态筛选
const handleStatusFilter = (value) => {
statusFilter.value = value
selectedTasks.value = [] // 清空选择
}
// 查看任务详情
const handleView = (row) => {
ElMessage.info(`查看任务详情: ${row.taskId}`)
// 这里可以跳转到详情页面或打开详情弹窗
}
// 删除单个任务
const handleDelete = async (row) => {
try {
await ElMessageBox.confirm(
`确定要删除任务 ${row.taskId} 吗?`,
'确认删除',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}
)
// 从数据中删除
const index = taskRecords.value.findIndex(item => item.id === row.id)
if (index > -1) {
taskRecords.value.splice(index, 1)
ElMessage.success('任务删除成功')
}
} catch (error) {
// 用户取消删除
}
}
// 批量删除
const handleBatchDelete = async () => {
if (selectedTasks.value.length === 0) {
ElMessage.warning('请先选择要删除的任务')
return
}
try {
await ElMessageBox.confirm(
`确定要删除选中的 ${selectedTasks.value.length} 个任务吗?`,
'确认批量删除',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}
)
// 批量删除
const selectedIds = selectedTasks.value.map(item => item.id)
taskRecords.value = taskRecords.value.filter(item => !selectedIds.includes(item.id))
selectedTasks.value = []
ElMessage.success(`成功删除 ${selectedIds.length} 个任务`)
} catch (error) {
// 用户取消删除
}
}
// 加载数据
const loadTaskRecords = async () => {
loading.value = true
try {
// 这里可以调用API获取数据
// const response = await taskAPI.getTaskRecords()
// taskRecords.value = response.data
// 模拟API调用
await new Promise(resolve => setTimeout(resolve, 500))
ElMessage.success('数据加载完成')
} catch (error) {
ElMessage.error('数据加载失败')
} finally {
loading.value = false
}
}
// 导航方法
const goToDashboard = () => {
router.push('/dashboard')
}
const goToMemberManagement = () => {
router.push('/member-management')
}
const goToOrderManagement = () => {
router.push('/orders')
}
const goToApiManagement = () => {
router.push('/api-management')
}
const goToSystemSettings = () => {
router.push('/system-settings')
}
// 页面加载时初始化数据
onMounted(() => {
loadTaskRecords()
})
</script>
<style scoped>
.generate-task-record {
display: flex;
height: 100vh;
background-color: #f5f7fa;
}
/* 左侧导航栏 */
.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;
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;
}
/* 主内容区域 */
.main-content {
flex: 1;
display: flex;
flex-direction: column;
}
/* 顶部导航栏 */
.header {
height: 60px;
background: white;
border-bottom: 1px solid #e4e7ed;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 30px;
}
.search-bar {
display: flex;
align-items: center;
background: #f5f7fa;
border-radius: 20px;
padding: 8px 16px;
width: 300px;
}
.search-bar .el-icon {
color: #909399;
margin-right: 8px;
}
.search-input {
border: none;
background: transparent;
outline: none;
flex-grow: 1;
font-size: 14px;
color: #333;
}
.header-actions {
display: flex;
align-items: center;
}
.notification-icon {
font-size: 20px;
color: #606266;
margin-right: 20px;
cursor: pointer;
}
.user-avatar {
display: flex;
align-items: center;
cursor: pointer;
}
.avatar-placeholder {
width: 32px;
height: 32px;
border-radius: 50%;
margin-right: 8px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 14px;
font-weight: bold;
}
.dropdown-icon {
font-size: 12px;
color: #909399;
}
/* 内容区域 */
.content-section {
flex: 1;
padding: 30px;
background-color: #f5f7fa;
}
.page-header {
margin-bottom: 20px;
}
.page-title {
font-size: 24px;
font-weight: 600;
color: #303133;
margin: 0 0 20px 0;
}
.action-bar {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.selected-count {
color: #606266;
font-size: 14px;
}
.action-controls {
display: flex;
align-items: center;
gap: 12px;
}
.status-filter {
width: 120px;
}
.delete-btn {
display: flex;
align-items: center;
gap: 4px;
}
/* 表格样式 */
.table-container {
background: white;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.task-table {
width: 100%;
}
.status-tag {
font-size: 12px;
padding: 4px 8px;
border-radius: 4px;
}
.action-link {
margin-right: 8px;
font-size: 12px;
}
/* 分页样式 */
.pagination-container {
display: flex;
justify-content: center;
padding: 20px;
background: white;
}
.pagination {
margin: 0;
}
/* 响应式设计 */
@media (max-width: 768px) {
.sidebar {
width: 60px;
}
.nav-item span {
display: none;
}
.search-bar {
width: 200px;
}
.content-section {
padding: 15px;
}
}
</style>

View File

@@ -0,0 +1,10 @@
<template>
<div>
<h1>Hello World!</h1>
<p>Vue is working!</p>
</div>
</template>
<script setup>
console.log('Vue component loaded!')
</script>

View File

@@ -20,7 +20,7 @@
<span>订单管理</span>
</div>
<div class="nav-item" @click="goToAPI">
<el-icon><Code /></el-icon>
<el-icon><Document /></el-icon>
<span>API管理</span>
</div>
<div class="nav-item" @click="goToTasks">
@@ -99,84 +99,7 @@
<!-- 图表区域 -->
<section class="charts-section">
<!-- 日活用户趋势图 -->
<div class="chart-card full-width">
<div class="chart-header">
<h3>日活用户趋势</h3>
<div class="year-selector">
<span>2025</span>
<el-icon><ArrowDown /></el-icon>
</div>
</div>
<div class="chart-container">
<div class="line-chart">
<!-- 动态SVG曲线图 -->
<svg width="100%" height="200" :viewBox="`0 0 ${chartWidth} ${chartHeight}`" class="chart-svg">
<!-- 网格线 -->
<defs>
<pattern id="grid" width="60" height="40" patternUnits="userSpaceOnUse">
<path d="M 60 0 L 0 0 0 40" fill="none" stroke="#e2e8f0" stroke-width="0.5"/>
</pattern>
</defs>
<rect width="100%" height="100%" fill="url(#grid)" />
<!-- 动态数据曲线 -->
<path :d="chartPath"
fill="none"
stroke="#3b82f6"
stroke-width="3"
class="chart-line-path"/>
<!-- 动态数据点 -->
<circle
v-for="(point, index) in chartPoints"
:key="index"
:cx="point.x"
:cy="point.y"
r="4"
fill="#3b82f6"
class="chart-dot"
@click="handlePointClick(point)"
style="cursor: pointer;"/>
<!-- 高亮数据点 -->
<template v-if="highlightedPoint">
<circle
:cx="highlightedPoint.x"
:cy="highlightedPoint.y"
r="6"
fill="#3b82f6"
class="highlight-dot"/>
<circle
:cx="highlightedPoint.x"
:cy="highlightedPoint.y"
r="12"
fill="#3b82f6"
opacity="0.2"
class="highlight-ring"/>
<!-- 动态工具提示 -->
<g class="tooltip-group" :transform="`translate(${highlightedPoint.x}, ${highlightedPoint.y - 20})`">
<rect x="-30" y="-40" width="60" height="30" rx="6" fill="#1e293b" class="tooltip-bg"/>
<text x="0" y="-25" text-anchor="middle" fill="white" font-size="12" font-weight="600" class="tooltip-value">
{{ highlightedPoint.value.toLocaleString() }}
</text>
<text x="0" y="-10" text-anchor="middle" fill="white" font-size="10" opacity="0.8" class="tooltip-date">
{{ highlightedPoint.label }}
</text>
<!-- 工具提示箭头 -->
<polygon points="0,0 -5,10 5,10" fill="#1e293b" class="tooltip-arrow"/>
</g>
</template>
</svg>
</div>
<div class="chart-x-axis">
<span v-for="data in monthlyData" :key="data.month">{{ data.label }}</span>
</div>
<div class="chart-y-axis">
<span v-for="tick in [1500, 1200, 900, 600, 300, 0]" :key="tick">{{ tick }}</span>
</div>
</div>
</div>
<DailyActiveUsersChart />
<!-- 用户转化率图 -->
<div class="chart-card full-width">
@@ -235,6 +158,17 @@ import { ref, onMounted, computed } from 'vue'
import { useRouter } from 'vue-router'
import { useUserStore } from '@/stores/user'
import { ElMessage } from 'element-plus'
import {
Grid,
User,
ShoppingCart,
Document,
Setting,
Search,
Bell,
ArrowDown,
Money
} from '@element-plus/icons-vue'
import * as dashboardAPI from '@/api/dashboard'
import DailyActiveUsersChart from '@/components/DailyActiveUsersChart.vue'
@@ -242,6 +176,8 @@ const router = useRouter()
const userStore = useUserStore()
// 数据状态
const loading = ref(false)
const selectedYear = ref('2024')
const dashboardData = ref({
totalUsers: 0,
paidUsers: 0,
@@ -266,70 +202,7 @@ const systemStatus = ref({
serviceStatus: '运行中'
})
const selectedYear = ref(2024)
const highlightedPoint = ref(null)
const loading = ref(false)
// 计算图表尺寸和比例
const chartWidth = 800
const chartHeight = 200
const padding = 60
// 计算数据点的SVG坐标
const chartPoints = computed(() => {
if (monthlyData.value.length === 0) return []
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) => {
const x = padding + (index * (chartWidth - 2 * padding) / (monthlyData.value.length - 1))
const y = padding + ((maxValue - (data.revenue || 0)) / valueRange) * (chartHeight - 2 * padding)
return {
x,
y,
value: data.revenue || 0,
label: `${data.month}`,
month: data.month
}
})
})
// 生成SVG路径
const chartPath = computed(() => {
if (chartPoints.value.length < 2) return ''
let path = `M ${chartPoints.value[0].x},${chartPoints.value[0].y}`
for (let i = 1; i < chartPoints.value.length; i++) {
const prev = chartPoints.value[i - 1]
const curr = chartPoints.value[i]
const next = chartPoints.value[i + 1]
if (next) {
// 使用三次贝塞尔曲线创建平滑路径
const cp1x = prev.x + (curr.x - prev.x) / 3
const cp1y = prev.y
const cp2x = curr.x - (next.x - curr.x) / 3
const cp2y = curr.y
path += ` C ${cp1x},${cp1y} ${cp2x},${cp2y} ${curr.x},${curr.y}`
} else {
// 最后一个点
const cp1x = prev.x + (curr.x - prev.x) / 3
const cp1y = prev.y
path += ` C ${cp1x},${cp1y} ${curr.x},${curr.y} ${curr.x},${curr.y}`
}
}
return path
})
// 处理数据点点击
const handlePointClick = (point) => {
highlightedPoint.value = point
}
// 清理未使用的图表相关代码
// 导航功能
const goToUsers = () => {
@@ -346,15 +219,15 @@ const goToOrders = () => {
}
const goToAPI = () => {
ElMessage.info('跳转到API管理')
router.push('/api-management')
}
const goToTasks = () => {
ElMessage.info('跳转到生成任务记录')
router.push('/generate-task-record')
}
const goToSettings = () => {
ElMessage.info('跳转到系统设置')
router.push('/system-settings')
}
// 加载仪表盘数据
@@ -371,39 +244,39 @@ const loadDashboardData = async () => {
])
// 处理概览数据
if (overviewRes.data) {
if (overviewRes) {
dashboardData.value = {
totalUsers: overviewRes.data.totalUsers || 0,
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
totalUsers: overviewRes.totalUsers || 0,
paidUsers: overviewRes.paidUsers || 0,
todayRevenue: overviewRes.todayRevenue || 0,
totalOrders: overviewRes.totalOrders || 0,
totalRevenue: overviewRes.totalRevenue || 0,
monthRevenue: overviewRes.monthRevenue || 0
}
}
// 处理月度数据
if (monthlyRes.data && monthlyRes.data.monthlyData) {
monthlyData.value = monthlyRes.data.monthlyData
if (monthlyRes && monthlyRes.monthlyData) {
monthlyData.value = monthlyRes.monthlyData
}
// 处理转化率数据
if (conversionRes.data) {
if (conversionRes) {
conversionData.value = {
totalUsers: conversionRes.data.totalUsers || 0,
paidUsers: conversionRes.data.paidUsers || 0,
conversionRate: conversionRes.data.conversionRate || 0,
membershipStats: conversionRes.data.membershipStats || []
totalUsers: conversionRes.totalUsers || 0,
paidUsers: conversionRes.paidUsers || 0,
conversionRate: conversionRes.conversionRate || 0,
membershipStats: conversionRes.membershipStats || []
}
}
// 处理系统状态
if (statusRes.data) {
if (statusRes) {
systemStatus.value = {
onlineUsers: statusRes.data.onlineUsers || 0,
systemUptime: statusRes.data.systemUptime || '0小时0分',
databaseStatus: statusRes.data.databaseStatus || '正常',
serviceStatus: statusRes.data.serviceStatus || '运行中'
onlineUsers: statusRes.onlineUsers || 0,
systemUptime: statusRes.systemUptime || '0小时0分',
databaseStatus: statusRes.databaseStatus || '正常',
serviceStatus: statusRes.serviceStatus || '运行中'
}
}

View File

@@ -25,8 +25,8 @@
<el-icon><Picture /></el-icon>
<span>图生视频</span>
</div>
<div class="nav-item storyboard-item" @click="goToStoryboard">
<el-icon><VideoPlay /></el-icon>
<div class="nav-item storyboard-item" @click="goToStoryboardVideo">
<el-icon><Film /></el-icon>
<span>分镜视频</span>
<el-tag size="small" type="primary" class="sora-tag">Sora2.0</el-tag>
</div>
@@ -148,7 +148,7 @@
import { ref, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { ElIcon, ElButton, ElTag, ElMessage, ElDialog } from 'element-plus'
import { User, Compass, Document, VideoPlay, Picture } from '@element-plus/icons-vue'
import { User, Document, VideoPlay, Picture, Film, Compass } from '@element-plus/icons-vue'
const router = useRouter()
@@ -204,7 +204,7 @@ const goToTextToVideo = () => {
router.push('/text-to-video')
}
const goToStoryboard = () => {
const goToStoryboardVideo = () => {
router.push('/storyboard-video')
}
@@ -252,46 +252,54 @@ onMounted(() => {
/* 左侧导航栏 */
.sidebar {
width: 280px;
background: #1a1a1a;
border-right: 1px solid #333;
padding: 24px 0;
width: 280px !important;
background: #1a1a1a !important;
padding: 24px 0 !important;
border-right: 1px solid #1a1a1a !important;
flex-shrink: 0 !important;
z-index: 100 !important;
display: block !important;
position: relative !important;
}
.logo {
font-size: 18px;
font-weight: 600;
color: #fff;
text-align: center;
margin-bottom: 32px;
padding: 0 24px 32px;
font-size: 20px;
font-weight: 500;
color: white;
}
.nav-menu {
display: flex;
flex-direction: column;
gap: 8px;
padding: 0 20px;
padding: 0 24px;
}
.nav-item {
display: flex;
align-items: center;
gap: 12px;
padding: 12px 16px;
padding: 14px 18px;
margin-bottom: 4px;
border-radius: 8px;
cursor: pointer;
transition: all 0.2s;
color: #d1d5db;
transition: all 0.3s ease;
position: relative;
}
.nav-item:hover {
background: #2a2a2a;
color: #fff;
}
.nav-item.active {
background: #3b82f6;
color: #fff;
background: #1e3a8a;
}
.nav-item .el-icon {
margin-right: 14px;
font-size: 20px;
}
.nav-item span {
font-size: 15px;
flex: 1;
}
.nav-divider {

View File

@@ -782,3 +782,5 @@ const startGenerate = () => {

View File

@@ -150,8 +150,8 @@ import { ref, onMounted, onUnmounted } from 'vue'
import { useRoute } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import {
User, Setting, Bell, Document, Picture, VideoPlay, VideoPause,
FullScreen, Share, Download, Delete, ArrowUp, ArrowDown
User, Setting, Bell, Document, User as Picture, User as VideoPlay, User as VideoPause,
User as FullScreen, User as Share, User as Download, User as Delete, User as ArrowUp, User as ArrowDown
} from '@element-plus/icons-vue'
const route = useRoute()

View File

@@ -71,8 +71,8 @@
<div class="account-item" @click="fillTestAccount('15538239326', '0627')">
<strong>管理员:</strong> 15538239326 / 0627
</div>
<div class="account-item" @click="fillTestAccount('demo', 'demo')">
<strong>普通用户:</strong> demo / demo
<div class="account-item" @click="fillTestAccount('13689270819', '0627')">
<strong>普通用户:</strong> 13689270819 / 0627
</div>
<div class="account-item" @click="fillTestAccount('testuser', 'test123')">
<strong>测试用户:</strong> testuser / test123
@@ -92,7 +92,7 @@ import { ref, reactive, onMounted } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { useUserStore } from '@/stores/user'
import { ElMessage } from 'element-plus'
import { ArrowDown } from '@element-plus/icons-vue'
import { User } from '@element-plus/icons-vue'
const router = useRouter()
const route = useRoute()

View File

@@ -20,7 +20,7 @@
<span>订单管理</span>
</div>
<div class="nav-item" @click="goToAPI">
<el-icon><Code /></el-icon>
<el-icon><Document /></el-icon>
<span>API管理</span>
</div>
<div class="nav-item" @click="goToTasks">
@@ -199,6 +199,18 @@
import { ref, onMounted, computed } from 'vue'
import { useRouter } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import {
Grid,
User,
ShoppingCart,
Document,
Setting,
User as Search,
Bell,
User as ArrowDown,
User as Edit,
User as Delete
} from '@element-plus/icons-vue'
import * as memberAPI from '@/api/members'
const router = useRouter()
@@ -253,15 +265,15 @@ const goToOrders = () => {
}
const goToAPI = () => {
ElMessage.info('跳转到API管理')
router.push('/api-management')
}
const goToTasks = () => {
ElMessage.info('跳转到生成任务记录')
router.push('/generate-task-record')
}
const goToSettings = () => {
ElMessage.info('跳转到系统设置')
router.push('/system-settings')
}
// 表格操作
@@ -455,15 +467,15 @@ const loadMembers = async () => {
})
// 处理API响应数据
if (response.data && response.data.list) {
memberList.value = response.data.list.map(member => ({
if (response && response.list) {
memberList.value = response.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
totalMembers.value = response.total || 0
} else {
// 如果API暂时不可用使用模拟数据
memberList.value = [

View File

@@ -1,5 +1,73 @@
<template>
<div class="works-page">
<!-- 左侧导航栏 -->
<aside class="sidebar">
<!-- Logo -->
<div class="logo">logo</div>
<!-- 导航菜单 -->
<nav class="nav-menu">
<div class="nav-item" @click="goToProfile">
<el-icon><User /></el-icon>
<span>个人主页</span>
</div>
<div class="nav-item" @click="goToSubscription">
<el-icon><Compass /></el-icon>
<span>会员订阅</span>
</div>
<div class="nav-item active">
<el-icon><Document /></el-icon>
<span>我的作品</span>
</div>
</nav>
<!-- 工具分隔线 -->
<div class="divider">
<span>工具</span>
</div>
<!-- 工具菜单 -->
<nav class="tools-menu">
<div class="nav-item" @click="goToTextToVideo">
<el-icon><VideoPlay /></el-icon>
<span>文生视频</span>
</div>
<div class="nav-item" @click="goToImageToVideo">
<el-icon><Picture /></el-icon>
<span>图生视频</span>
</div>
<div class="nav-item" @click="goToStoryboardVideo">
<el-icon><Film /></el-icon>
<span>分镜视频</span>
<el-tag size="small" type="primary" class="sora-tag">Sora2.0</el-tag>
</div>
</nav>
</aside>
<!-- 主内容区域 -->
<main class="main-content">
<!-- 顶部栏 -->
<header class="top-header">
<div class="header-right">
<div class="discount-badge">
<span class="discount-icon">+ 25</span>
<span class="discount-text">首购优惠</span>
</div>
<div class="notification-bell">
<el-icon><Bell /></el-icon>
<span class="notification-badge">5</span>
</div>
<div class="user-avatar">
<el-icon><User /></el-icon>
</div>
<div class="settings-icon">
<el-icon><Setting /></el-icon>
</div>
</div>
</header>
<!-- 内容区域 -->
<div class="content-area">
<div class="toolbar">
<el-radio-group v-model="activeTab" size="small" class="seg-control">
<el-radio-button label="all">全部</el-radio-button>
@@ -9,37 +77,48 @@
</div>
<div class="filters-bar">
<el-space wrap size="small" class="filters">
<el-date-picker v-model="dateRange" type="daterange" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" size="small" />
<el-select v-model="category" placeholder="任务类型" size="small" style="width: 120px" @change="onFilterChange">
<div class="filters-left">
<el-select v-model="dateFilter" placeholder="日期" size="small" style="width: 100px">
<el-option label="今天" value="today" />
<el-option label="本周" value="week" />
<el-option label="本月" value="month" />
</el-select>
<el-select v-model="category" placeholder="任务类型" size="small" style="width: 100px" @change="onFilterChange">
<el-option label="全部" value="all" />
<el-option label="文生视频" value="text2video" />
<el-option label="图生视频" value="image2video" />
<el-option label="分镜视频" value="storyboard" />
<el-option label="参考图" value="reference" />
</el-select>
<el-select v-model="resolution" placeholder="清晰度" clearable size="small" style="width: 120px">
<el-select v-model="resolution" placeholder="清晰度" clearable size="small" style="width: 100px">
<el-option label="标清" value="sd" />
<el-option label="高清" value="hd" />
<el-option label="超清" value="uhd" />
</el-select>
<el-select v-model="sortBy" size="small" style="width: 120px">
<el-select v-model="sortBy" placeholder="比例" size="small" style="width: 100px">
<el-option label="比例" value="ratio" />
<el-option label="时间" value="date" />
<el-option label="热门" value="hot" />
</el-select>
<el-select v-model="order" size="small" style="width: 100px">
<el-option label="升序" value="asc" />
<el-option label="降序" value="desc" />
</el-select>
</el-space>
<div class="right">
<el-input v-model="keyword" placeholder="名字/提示词/ID" size="small" clearable style="width: 220px" @keyup.enter.native="reload" />
<el-button size="small" @click="resetFilters">重置</el-button>
</div>
<div class="filters-right">
<el-input
v-model="keyword"
placeholder="名字/提示词/ID"
size="small"
clearable
style="width: 220px"
@keyup.enter.native="reload"
>
<template #prefix>
<el-icon><Search /></el-icon>
</template>
</el-input>
</div>
</div>
<div class="select-row">
<el-checkbox v-model="multiSelect" size="small">选择多个</el-checkbox>
<el-checkbox v-model="multiSelect" size="small">选择{{ selectedIds.size || 6 }}个项目</el-checkbox>
<template v-if="multiSelect && selectedIds.size">
<el-tag type="success" size="small">已选 {{ selectedIds.size }} 个项目</el-tag>
<el-button size="small" type="primary" @click="bulkDownload" plain>下载</el-button>
@@ -226,6 +305,8 @@
<div class="finished" v-if="!hasMore && filteredItems.length>0">已加载全部内容</div>
<el-empty v-if="!loading && filteredItems.length===0" description="没有找到相关内容" />
</div>
</main>
</div>
</template>
@@ -233,12 +314,13 @@
import { ref, onMounted, computed } from 'vue'
import { useRouter } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Star, MoreFilled, User } from '@element-plus/icons-vue'
import { Star, User, Compass, Document, VideoPlay, Picture, Film, Bell, Setting, Search } from '@element-plus/icons-vue'
const router = useRouter()
const activeTab = ref('all')
const dateRange = ref([])
const dateFilter = ref('')
const category = ref('all')
const resolution = ref('')
const sortBy = ref('date')
@@ -443,6 +525,42 @@ const bulkDelete = async () => {
} catch (_) {}
}
// 导航方法
const goToProfile = () => {
console.log('导航到个人主页')
router.push('/profile')
}
const goToSubscription = () => {
console.log('导航到会员订阅')
router.push('/subscription')
}
const goToTextToVideo = () => {
console.log('导航到文生视频')
router.push('/text-to-video')
}
const goToImageToVideo = () => {
console.log('导航到图生视频')
router.push('/image-to-video')
}
const goToStoryboardVideo = () => {
console.log('导航到分镜视频')
router.push('/storyboard-video')
}
// 重置筛选器
const resetFilters = () => {
dateFilter.value = ''
category.value = 'all'
resolution.value = ''
sortBy.value = 'date'
keyword.value = ''
ElMessage.success('筛选器已重置')
}
onMounted(() => {
loadList()
})
@@ -450,8 +568,189 @@ onMounted(() => {
<style scoped>
.works-page {
padding: 16px 20px;
min-height: 100vh;
background: #0a0a0a;
color: white;
display: flex;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
margin: 0;
padding: 0;
width: 100vw;
height: 100vh;
overflow: hidden;
position: relative;
}
/* 页面特殊效果 */
.works-page::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background:
radial-gradient(circle at 10% 20%, rgba(64, 158, 255, 0.1) 0%, transparent 50%),
radial-gradient(circle at 90% 80%, rgba(103, 194, 58, 0.1) 0%, transparent 50%),
radial-gradient(circle at 50% 50%, rgba(230, 162, 60, 0.05) 0%, transparent 50%);
animation: profileGlow 6s ease-in-out infinite alternate;
pointer-events: none;
z-index: 1;
}
@keyframes profileGlow {
0% { opacity: 0.3; }
100% { opacity: 0.6; }
}
.works-page > * {
position: relative;
z-index: 2;
}
/* 左侧导航栏 */
.sidebar {
width: 280px !important;
background: #1a1a1a !important;
padding: 24px 0 !important;
border-right: 1px solid #1a1a1a !important;
flex-shrink: 0 !important;
z-index: 100 !important;
display: block !important;
position: relative !important;
}
.logo {
padding: 0 24px 32px;
font-size: 20px;
font-weight: 500;
color: white;
}
.nav-menu, .tools-menu {
padding: 0 24px;
}
.nav-item {
display: flex;
align-items: center;
padding: 14px 18px;
margin-bottom: 4px;
border-radius: 8px;
cursor: pointer;
transition: all 0.3s ease;
position: relative;
}
.nav-item:hover {
background: #2a2a2a;
}
.nav-item.active {
background: #1e3a8a;
}
.nav-item .el-icon {
margin-right: 14px;
font-size: 20px;
}
.nav-item span {
font-size: 15px;
flex: 1;
}
.sora-tag {
margin-left: 8px;
font-size: 10px;
padding: 2px 6px;
}
.divider {
margin: 30px 20px 20px;
padding: 0 16px;
color: #666;
font-size: 12px;
font-weight: 500;
text-transform: uppercase;
letter-spacing: 1px;
}
/* 主内容区域 */
.main-content {
flex: 1;
padding: 0;
}
/* 顶部导航栏 */
.top-header {
padding: 20px 30px;
border-bottom: 1px solid #333;
display: flex;
justify-content: flex-end;
}
.header-right {
display: flex;
align-items: center;
gap: 20px;
}
.discount-badge {
display: flex;
align-items: center;
background: #3b82f6;
color: white;
padding: 6px 12px;
border-radius: 20px;
font-size: 12px;
font-weight: 500;
}
.discount-icon {
background: #1e40af;
padding: 2px 6px;
border-radius: 10px;
margin-right: 6px;
}
.notification-bell {
position: relative;
cursor: pointer;
color: #9ca3af;
font-size: 20px;
}
.notification-badge {
position: absolute;
top: -8px;
right: -8px;
background: #ef4444;
color: white;
font-size: 10px;
padding: 2px 6px;
border-radius: 10px;
min-width: 16px;
text-align: center;
}
.user-avatar, .settings-icon {
cursor: pointer;
color: #9ca3af;
font-size: 20px;
}
.user-avatar:hover, .settings-icon:hover, .notification-bell:hover {
color: white;
}
/* 内容区域 */
.content-area {
flex: 1;
padding: 20px 24px;
overflow-y: auto;
}
.toolbar {
display: flex;
align-items: center;
@@ -480,13 +779,27 @@ onMounted(() => {
display: flex;
align-items: center;
justify-content: space-between;
padding: 4px 0 2px;
padding: 12px 0;
border-bottom: 1px solid #333;
margin-bottom: 16px;
background: #1a1a1a;
/* 覆盖 Element Plus 变量,确保与页面背景一致 */
--el-input-bg-color: #0a0a0a;
--el-fill-color-blank: #0a0a0a;
--el-border-color: #2a2a2a;
--el-text-color-regular: #cbd5e1;
}
.filters-left {
display: flex;
align-items: center;
gap: 12px;
}
.filters-right {
display: flex;
align-items: center;
}
:deep(.filters .el-select .el-input__wrapper),
:deep(.filters .el-date-editor.el-input__wrapper),
:deep(.filters .el-input__wrapper) {

View File

@@ -182,7 +182,7 @@ import { ref, reactive, computed } from 'vue'
import { useRouter } from 'vue-router'
import { useOrderStore } from '@/stores/orders'
import { ElMessage } from 'element-plus'
import { Plus, Delete, Check, InfoFilled } from '@element-plus/icons-vue'
import { Plus, Delete, Check, User } from '@element-plus/icons-vue'
const router = useRouter()
const orderStore = useOrderStore()

View File

@@ -69,6 +69,22 @@ import { ref, onMounted } from 'vue'
import { useRoute } from 'vue-router'
import { useOrderStore } from '@/stores/orders'
import { ElMessage } from 'element-plus'
import {
User as ArrowLeft,
User as ArrowRight,
Check,
Close,
User as Warning,
User as Info,
Money,
CreditCard,
Wallet,
User as Truck,
User as Package,
User,
User as Calendar,
User as Clock
} from '@element-plus/icons-vue'
const route = useRoute()
const orderStore = useOrderStore()

View File

@@ -20,7 +20,7 @@
<span>订单管理</span>
</div>
<div class="nav-item" @click="goToAPI">
<el-icon><Code /></el-icon>
<el-icon><Document /></el-icon>
<span>API管理</span>
</div>
<div class="nav-item" @click="goToTasks">
@@ -193,6 +193,23 @@
import { ref, reactive, onMounted, computed } from 'vue'
import { useRouter } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import {
Grid,
User,
ShoppingCart,
Document,
Setting,
User as Search,
Bell,
User as ArrowDown,
User as ArrowLeft,
User as ArrowRight,
User as View,
User as Delete,
CreditCard,
Wallet,
Money
} from '@element-plus/icons-vue'
import * as orderAPI from '@/api/orders'
const router = useRouter()
@@ -446,15 +463,15 @@ const goToMembers = () => {
}
const goToAPI = () => {
ElMessage.info('跳转到API管理')
router.push('/api-management')
}
const goToTasks = () => {
ElMessage.info('跳转到生成任务记录')
router.push('/generate-task-record')
}
const goToSettings = () => {
ElMessage.info('跳转到系统设置')
router.push('/system-settings')
}
onMounted(() => {

View File

@@ -136,6 +136,18 @@
import { ref, reactive } from 'vue'
import { useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import {
Money,
CreditCard,
Wallet,
User as Plus,
Check,
Close,
User as ArrowLeft,
User as ArrowRight,
User as Upload,
User as Download
} from '@element-plus/icons-vue'
const router = useRouter()

View File

@@ -219,6 +219,23 @@
<script setup>
import { ref, reactive, onMounted, computed } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import {
Money,
CreditCard,
Wallet,
User as Search,
User as Filter,
User as Plus,
User as View,
User as Refresh,
User as Download,
User as Upload,
Setting,
Bell,
Check,
Close,
User as Warning
} from '@element-plus/icons-vue'
import { getPayments, testPaymentComplete as testPaymentCompleteApi, createTestPayment } from '@/api/payments'
import { useUserStore } from '@/stores/user'

View File

@@ -17,7 +17,7 @@
</div>
<div class="nav-item">
<el-icon><Document /></el-icon>
<span>我的作品</span>
<span @click="goToMyWorks">我的作品</span>
</div>
</nav>
@@ -29,16 +29,16 @@
<!-- 工具菜单 -->
<nav class="tools-menu">
<div class="nav-item">
<el-icon><Document /></el-icon>
<span>文生视频</span>
<el-icon><VideoPlay /></el-icon>
<span @click="goToTextToVideo">文生视频</span>
</div>
<div class="nav-item">
<el-icon><Picture /></el-icon>
<span>图生视频</span>
<span @click="goToImageToVideo">图生视频</span>
</div>
<div class="nav-item">
<el-icon><VideoPlay /></el-icon>
<span>分镜视频</span>
<el-icon><Film /></el-icon>
<span @click="goToStoryboardVideo">分镜视频</span>
<el-tag size="small" type="primary" class="sora-tag">Sora2.0</el-tag>
</div>
</nav>
@@ -57,7 +57,7 @@
<el-icon><Bell /></el-icon>
<div class="notification-dot"></div>
</div>
<div class="user-status">
<div class="user-status" @click="showUserMenu = !showUserMenu" ref="userStatusRef">
<div class="status-icon"></div>
</div>
</div>
@@ -74,7 +74,6 @@
<p class="profile-status">还没有设置个人简介,点击填写</p>
<p class="user-id">ID 2994509784706419</p>
</div>
<el-button class="edit-btn">编辑资料</el-button>
</div>
</section>
@@ -98,30 +97,175 @@
</section>
</main>
</div>
<!-- 用户菜单下拉 - 使用Teleport渲染到body -->
<Teleport to="body">
<div v-if="showUserMenu" class="user-menu-teleport" :style="menuStyle">
<!-- 管理员功能 -->
<template v-if="userStore.isAdmin">
<div class="menu-item" @click="goToDashboard">
<el-icon><User /></el-icon>
<span>数据仪表盘</span>
</div>
<div class="menu-item" @click="goToOrders">
<el-icon><Document /></el-icon>
<span>订单管理</span>
</div>
<div class="menu-item" @click="goToMembers">
<el-icon><User /></el-icon>
<span>会员管理</span>
</div>
<div class="menu-item" @click="goToSettings">
<el-icon><Setting /></el-icon>
<span>系统设置</span>
</div>
</template>
<!-- 退出登录 -->
<div class="menu-item" @click="logout">
<el-icon><User /></el-icon>
<span>退出登录</span>
</div>
</div>
</Teleport>
</template>
<script setup>
import { ref } from 'vue'
import { ref, onMounted, onUnmounted, computed, nextTick } from 'vue'
import { useRouter } from 'vue-router'
import { useUserStore } from '@/stores/user'
import { ElMessage } from 'element-plus'
import {
User,
Compass,
Document,
Picture,
VideoPlay,
Star,
Bell
Bell,
Setting,
Compass,
VideoPlay,
Picture,
Film
} from '@element-plus/icons-vue'
const router = useRouter()
const userStore = useUserStore()
// 控制用户菜单显示
const showUserMenu = ref(false)
const userStatusRef = ref(null)
// 模拟视频数据
const videos = ref(Array(6).fill({}))
// 计算菜单位置
const menuStyle = computed(() => {
if (!userStatusRef.value || !showUserMenu.value) return {}
const rect = userStatusRef.value.getBoundingClientRect()
return {
position: 'fixed',
top: `${rect.bottom + 8}px`,
right: `${window.innerWidth - rect.right}px`,
zIndex: 99999
}
})
// 跳转到会员订阅页面
const goToSubscription = () => {
router.push('/subscription')
}
const goToMyWorks = () => {
router.push('/works')
}
const goToTextToVideo = () => {
router.push('/text-to-video')
}
const goToImageToVideo = () => {
router.push('/image-to-video')
}
const goToStoryboardVideo = () => {
router.push('/storyboard-video')
}
// 跳转到数据仪表盘
const goToDashboard = () => {
showUserMenu.value = false
// 检查用户权限,只有管理员才能访问数据仪表盘
if (userStore.isAdmin) {
router.push('/admin/dashboard')
} else {
ElMessage.warning('权限不足,只有管理员才能访问数据仪表盘')
}
}
// 跳转到订单管理
const goToOrders = () => {
showUserMenu.value = false
router.push('/orders')
}
// 跳转到会员管理
const goToMembers = () => {
showUserMenu.value = false
// 检查用户权限,只有管理员才能访问会员管理
if (userStore.isAdmin) {
router.push('/member-management')
} else {
ElMessage.warning('权限不足,只有管理员才能访问会员管理')
}
}
// 跳转到系统设置
const goToSettings = () => {
showUserMenu.value = false
// 检查用户权限,只有管理员才能访问系统设置
if (userStore.isAdmin) {
router.push('/system-settings')
} else {
ElMessage.warning('权限不足,只有管理员才能访问系统设置')
}
}
// 退出登录
const logout = async () => {
try {
showUserMenu.value = false
// 清除用户数据
await userStore.logoutUser()
// 清除其他可能的本地存储
localStorage.removeItem('user')
localStorage.removeItem('token')
ElMessage.success('已退出登录')
// 跳转到登录页
router.push('/login')
} catch (error) {
console.error('退出登录失败:', error)
ElMessage.error('退出登录失败')
}
}
// 点击外部关闭菜单
const handleClickOutside = (event) => {
const userStatus = event.target.closest('.user-status')
if (!userStatus) {
showUserMenu.value = false
}
}
onMounted(() => {
document.addEventListener('click', handleClickOutside)
})
onUnmounted(() => {
document.removeEventListener('click', handleClickOutside)
})
</script>
<style scoped>
@@ -135,7 +279,7 @@ const goToSubscription = () => {
padding: 0;
width: 100vw;
height: 100vh;
overflow: hidden;
overflow: visible;
position: relative;
}
@@ -164,32 +308,36 @@ const goToSubscription = () => {
/* 内容层级 */
.profile-page > * {
position: relative;
z-index: 2;
z-index: 1;
}
/* 左侧导航栏 */
.sidebar {
width: 240px;
background: #1a1a1a;
padding: 20px 0;
border-right: 1px solid #333;
width: 280px !important;
background: #1a1a1a !important;
padding: 24px 0 !important;
border-right: 1px solid #1a1a1a !important;
flex-shrink: 0 !important;
z-index: 100 !important;
display: block !important;
position: relative !important;
}
.logo {
padding: 0 20px 30px;
font-size: 18px;
padding: 0 24px 32px;
font-size: 20px;
font-weight: 500;
color: white;
}
.nav-menu, .tools-menu {
padding: 0 20px;
padding: 0 24px;
}
.nav-item {
display: flex;
align-items: center;
padding: 12px 16px;
padding: 14px 18px;
margin-bottom: 4px;
border-radius: 8px;
cursor: pointer;
@@ -206,12 +354,12 @@ const goToSubscription = () => {
}
.nav-item .el-icon {
margin-right: 12px;
font-size: 18px;
margin-right: 14px;
font-size: 20px;
}
.nav-item span {
font-size: 14px;
font-size: 15px;
flex: 1;
}
@@ -243,6 +391,8 @@ const goToSubscription = () => {
border-bottom: 1px solid #333;
display: flex;
justify-content: flex-end;
position: relative;
z-index: 99999;
}
.header-right {
@@ -283,6 +433,15 @@ const goToSubscription = () => {
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
position: relative;
z-index: 100000;
transition: all 0.3s ease;
}
.user-status:hover {
border-color: #66b1ff;
transform: scale(1.05);
}
.status-icon {
@@ -292,6 +451,54 @@ const goToSubscription = () => {
border-radius: 2px;
}
/* 用户菜单样式 */
.user-menu {
position: absolute;
top: 100%;
right: 0;
margin-top: 8px;
background: #1a1a1a;
border: 1px solid #333;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
min-width: 160px;
z-index: 99999;
overflow: hidden;
}
/* Teleport菜单样式 */
.user-menu-teleport {
background: #1a1a1a;
border: 1px solid #333;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
min-width: 160px;
overflow: hidden;
}
.menu-item {
display: flex;
align-items: center;
padding: 12px 16px;
cursor: pointer;
transition: background-color 0.2s ease;
color: white;
font-size: 14px;
}
.menu-item:hover {
background: #2a2a2a;
}
.menu-item .el-icon {
margin-right: 8px;
font-size: 16px;
}
.menu-item:not(:last-child) {
border-bottom: 1px solid #333;
}
/* 用户资料区域 */
.profile-section {
padding: 30px;
@@ -300,6 +507,7 @@ const goToSubscription = () => {
border-radius: 12px;
border: 1px solid #333;
position: relative;
z-index: 1;
}
.profile-section::before {

View File

@@ -5,7 +5,7 @@
<el-card class="register-card">
<template #header>
<div class="register-header">
<el-icon size="32" color="#67C23A"><UserFilled /></el-icon>
<el-icon size="32" color="#67C23A"><User /></el-icon>
<h2>用户注册</h2>
</div>
</template>
@@ -132,6 +132,18 @@ import { useRouter } from 'vue-router'
import { useUserStore } from '@/stores/user'
import { checkUsernameExists, checkEmailExists } from '@/api/auth'
import { ElMessage } from 'element-plus'
import {
User,
Lock,
Message,
Phone,
Calendar,
Location,
Check,
Close,
ArrowLeft,
ArrowRight
} from '@element-plus/icons-vue'
const router = useRouter()
const userStore = useUserStore()

View File

@@ -1,16 +1,23 @@
<template>
<div>
<h1>测试页面</h1>
<p>如果能看到这个页面说明Vue应用正常工作</p>
<div class="simple-test">
<h1>简单测试页面</h1>
<p>如果能看到这个页面说明Vue正常工作</p>
<button @click="testClick">测试按钮</button>
</div>
</template>
<script setup>
console.log('测试页面加载成功')
import { ref } from 'vue'
const testClick = () => {
alert('按钮点击成功!')
}
</script>
<style scoped>
.simple-test {
padding: 50px;
text-align: center;
font-size: 18px;
}
</style>

View File

@@ -26,7 +26,7 @@
<span>图生视频</span>
</div>
<div class="nav-item active storyboard-item">
<el-icon><VideoPlay /></el-icon>
<el-icon><Film /></el-icon>
<span>分镜视频</span>
<el-tag size="small" type="primary" class="sora-tag">Sora2.0</el-tag>
</div>
@@ -148,7 +148,7 @@
import { ref, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { ElIcon, ElButton, ElTag, ElMessage, ElDialog } from 'element-plus'
import { User, Compass, Document, VideoPlay, Picture } from '@element-plus/icons-vue'
import { User, Document, VideoPlay, Picture, Film, Compass } from '@element-plus/icons-vue'
const router = useRouter()
@@ -252,46 +252,54 @@ onMounted(() => {
/* 左侧导航栏 */
.sidebar {
width: 280px;
background: #1a1a1a;
border-right: 1px solid #333;
padding: 24px 0;
width: 280px !important;
background: #1a1a1a !important;
padding: 24px 0 !important;
border-right: 1px solid #1a1a1a !important;
flex-shrink: 0 !important;
z-index: 100 !important;
display: block !important;
position: relative !important;
}
.logo {
font-size: 18px;
font-weight: 600;
color: #fff;
text-align: center;
margin-bottom: 32px;
padding: 0 24px 32px;
font-size: 20px;
font-weight: 500;
color: white;
}
.nav-menu {
display: flex;
flex-direction: column;
gap: 8px;
padding: 0 20px;
padding: 0 24px;
}
.nav-item {
display: flex;
align-items: center;
gap: 12px;
padding: 12px 16px;
padding: 14px 18px;
margin-bottom: 4px;
border-radius: 8px;
cursor: pointer;
transition: all 0.2s;
color: #d1d5db;
transition: all 0.3s ease;
position: relative;
}
.nav-item:hover {
background: #2a2a2a;
color: #fff;
}
.nav-item.active {
background: #3b82f6;
color: #fff;
background: #1e3a8a;
}
.nav-item .el-icon {
margin-right: 14px;
font-size: 20px;
}
.nav-item span {
font-size: 15px;
flex: 1;
}
.nav-divider {

View File

@@ -733,3 +733,5 @@ const startGenerate = () => {

View File

@@ -15,7 +15,7 @@
<el-icon><Compass /></el-icon>
<span>会员订阅</span>
</div>
<div class="nav-item" :class="{ active: currentSection === 'works' }" @click="setSection('works')" @mousedown="console.log('mousedown 我的作品')">
<div class="nav-item" @click="goToMyWorks">
<el-icon><Document /></el-icon>
<span>我的作品</span>
</div>
@@ -29,15 +29,15 @@
<!-- 工具菜单 -->
<nav class="tools-menu">
<div class="nav-item" @click="goToTextToVideo">
<el-icon><Document /></el-icon>
<el-icon><VideoPlay /></el-icon>
<span>文生视频</span>
</div>
<div class="nav-item" @click="goToImageToVideo">
<el-icon><Picture /></el-icon>
<span>图生视频</span>
</div>
<div class="nav-item storyboard-item">
<el-icon><VideoPlay /></el-icon>
<div class="nav-item storyboard-item" @click="goToStoryboardVideo">
<el-icon><Film /></el-icon>
<span>分镜视频</span>
<el-tag size="small" type="primary" class="sora-tag">Sora2.0</el-tag>
</div>
@@ -68,10 +68,12 @@
</div>
<div class="user-right">
<div class="points-pill">
<el-icon><Plus /></el-icon>
<div class="star-icon">
<el-icon><Star /></el-icon>
</div>
<span>50</span>
</div>
<button class="mini-btn">积分详情</button>
<button class="mini-btn" @click="goToOrderDetails">积分详情</button>
<button class="mini-btn" @click="goToWorks">我的订单</button>
</div>
</div>
@@ -90,7 +92,9 @@
<div class="summary-item">
<div class="summary-label">剩余积分</div>
<div class="summary-value highlight">
<el-icon class="plus-icon"><Plus /></el-icon>
<div class="star-icon">
<el-icon><Star /></el-icon>
</div>
<span class="points-number">50</span>
</div>
</div>
@@ -107,7 +111,7 @@
<div class="package-header">
<h4 class="package-title">免费版</h4>
</div>
<div class="package-price">¥0/</div>
<div class="package-price">$0/</div>
<button class="package-button current">当前套餐</button>
<div class="package-features">
<div class="feature-item">
@@ -175,21 +179,70 @@
</template>
</main>
</div>
<!-- 订单详情模态框 -->
<el-dialog
v-model="orderDialogVisible"
title="订单详情"
width="80%"
class="order-dialog"
:modal="true"
:close-on-click-modal="true"
:close-on-press-escape="true"
@close="handleOrderDialogClose"
>
<div class="order-content">
<div class="order-summary">
<h3>账户订单总览</h3>
<div class="summary-stats">
<div class="stat-item">
<span class="stat-label">总订单数</span>
<span class="stat-value">{{ orders.length }}</span>
</div>
<div class="stat-item">
<span class="stat-label">总金额</span>
<span class="stat-value">¥{{ totalAmount }}</span>
</div>
</div>
</div>
<div class="orders-list">
<div class="order-item" v-for="order in orders" :key="order.id">
<div class="order-header">
<span class="order-id">订单号{{ order.id }}</span>
<span class="order-status" :class="order.status">{{ order.statusText }}</span>
</div>
<div class="order-details">
<div class="order-info">
<p><strong>创建时间</strong>{{ order.createdAt }}</p>
<p><strong>订单类型</strong>{{ order.type }}</p>
<p><strong>金额</strong>¥{{ order.amount }}</p>
</div>
<div class="order-actions">
<el-button type="primary" size="small" @click="viewOrderDetail(order)">查看详情</el-button>
</div>
</div>
</div>
</div>
</div>
</el-dialog>
</template>
<script setup>
import { ref } from 'vue'
import { ref, computed } from 'vue'
import MyWorks from '@/views/MyWorks.vue'
import { useRouter } from 'vue-router'
import {
User,
Compass,
Document,
Picture,
VideoPlay,
Plus,
User as Plus,
Bell,
Check
Check,
Compass,
VideoPlay,
Picture,
Film,
Star
} from '@element-plus/icons-vue'
const router = useRouter()
@@ -200,6 +253,10 @@ const goToProfile = () => {
router.push('/profile')
}
const goToMyWorks = () => {
router.push('/works')
}
const goToTextToVideo = () => {
router.push('/text-to-video')
}
@@ -208,11 +265,64 @@ const goToImageToVideo = () => {
router.push('/image-to-video')
}
// 当前主区块subscription | works
const currentSection = ref('subscription')
const setSection = (section) => {
console.log('切换区块到:', section)
currentSection.value = section
const goToStoryboardVideo = () => {
router.push('/storyboard-video')
}
// 订单模态框相关
const orderDialogVisible = ref(false)
const orders = ref([
{
id: 'ORD-2024-001',
status: 'completed',
statusText: '已完成',
createdAt: '2024-01-15 10:30:00',
type: '标准版订阅',
amount: 59.00
},
{
id: 'ORD-2024-002',
status: 'pending',
statusText: '待支付',
createdAt: '2024-01-20 14:20:00',
type: '专业版订阅',
amount: 259.00
},
{
id: 'ORD-2024-003',
status: 'completed',
statusText: '已完成',
createdAt: '2024-01-25 09:15:00',
type: '积分充值',
amount: 100.00
}
])
// 计算总金额
const totalAmount = computed(() => {
return orders.value.reduce((sum, order) => sum + order.amount, 0).toFixed(2)
})
// 显示订单详情模态框
const goToOrderDetails = () => {
console.log('点击积分详情,显示订单详情模态框')
orderDialogVisible.value = true
}
// 关闭订单模态框
const handleOrderDialogClose = () => {
orderDialogVisible.value = false
}
// 查看订单详情
const viewOrderDetail = (order) => {
console.log('查看订单详情:', order)
// 这里可以添加查看订单详情的逻辑
}
// 跳转到我的作品页面
const goToWorks = () => {
router.push('/works')
}
// 选中套餐(紫色边框)
@@ -342,7 +452,10 @@ const selectPlan = (plan) => {
/* 套餐选择 */
.subscription-packages {
padding: 0 40px 30px; /* 与顶部盒子保持一致的左右留白 */
padding: 0 30px 30px; /* 与顶部盒子保持一致的左右留白 */
margin: 0 auto; /* 居中显示,与上方盒子对齐 */
max-width: calc(100% - 80px); /* 限制最大宽度,与上方盒子一致 */
margin-left: 15px; /* 增加左边距,与上方盒子更精确对齐 */
}
.subscription-packages .section-title {
@@ -370,7 +483,7 @@ const selectPlan = (plan) => {
grid-template-columns: repeat(3, 1fr);
gap: 24px;
max-width: 1440px;
margin: 0 40px 0 0; /* 右侧留白与左侧 padding(40px) 保持一致 */
margin: 0 30px 0 0; /* 右侧留白与左侧 padding(30px) 保持一致 */
width: 100%;
align-items: stretch; /* 卡片等高 */
}
@@ -503,9 +616,9 @@ const selectPlan = (plan) => {
/* 顶部合并的两层盒子 */
.top-merged-card {
max-width: none; /* 取消限制,铺满内容区域 */
max-width: calc(100% - 80px); /* 限制最大宽度减去套餐区域向右移动的80px */
width: 100%;
margin: 32px 40px 10px 40px; /* 左右各 40px 留白,与套餐区对齐 */
margin: 20px auto; /* 上下20px左右自动居中 */
background: #1a1a1a; /* 与卡片、页面风格保持一致 */
border: 1px solid #333;
border-radius: 10px;
@@ -515,8 +628,8 @@ const selectPlan = (plan) => {
display: flex;
align-items: center;
justify-content: space-between;
gap: 26px;
padding: 22px 26px; /* 比例放大 */
gap: 20px; /* 与个人主页保持一致 */
padding: 30px; /* 与个人主页保持一致 */
border-bottom: 1px solid #1f2937;
}
@@ -524,7 +637,7 @@ const selectPlan = (plan) => {
display: grid;
grid-template-columns: 1fr auto 1fr auto 1fr;
gap: 30px;
padding: 22px 26px 24px; /* 比例放大 */
padding: 30px; /* 与row-top保持一致 */
align-items: center;
}
@@ -546,6 +659,17 @@ const selectPlan = (plan) => {
.user-id { font-size:15px; color:#9ca3af; }
.user-right { display:flex; align-items:center; gap:12px; }
.points-pill { display:flex; align-items:center; gap:6px; padding:9px 14px; border-radius:999px; background:#0b1220; border:1px solid #1f3758; color:#60a5fa; font-weight:600; font-size:16px; }
.star-icon {
display: flex;
align-items: center;
justify-content: center;
width: 20px;
height: 20px;
background: #3b82f6;
border-radius: 50%;
color: white;
font-size: 12px;
}
.mini-btn { background:#0f172a; color:#e5e7eb; border:1px solid #334155; padding:9px 14px; border-radius:6px; font-size:14px; cursor:pointer; transition:.2s ease; }
.mini-btn:hover { background:#111827; border-color:#3b82f6; }
@@ -554,4 +678,108 @@ const selectPlan = (plan) => {
.top-merged-card .row-top { flex-direction: column; align-items: flex-start; gap: 10px; }
.top-merged-card .row-bottom { grid-template-columns: 1fr; gap: 12px; }
}
/* 订单详情模态框样式 */
.order-dialog {
background: #1a1a1a;
color: white;
}
.order-content {
background: #1a1a1a;
color: white;
}
.order-summary {
margin-bottom: 30px;
padding: 20px;
background: #2a2a2a;
border-radius: 8px;
}
.order-summary h3 {
color: white;
margin: 0 0 15px 0;
font-size: 18px;
}
.summary-stats {
display: flex;
gap: 30px;
}
.stat-item {
display: flex;
flex-direction: column;
gap: 5px;
}
.stat-label {
color: #9ca3af;
font-size: 14px;
}
.stat-value {
color: #60a5fa;
font-size: 16px;
font-weight: 600;
}
.orders-list {
display: flex;
flex-direction: column;
gap: 15px;
}
.order-item {
background: #2a2a2a;
border-radius: 8px;
padding: 20px;
border: 1px solid #333;
}
.order-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
}
.order-id {
color: white;
font-weight: 600;
}
.order-status {
padding: 4px 12px;
border-radius: 4px;
font-size: 12px;
font-weight: 500;
}
.order-status.completed {
background: #10b981;
color: white;
}
.order-status.pending {
background: #f59e0b;
color: white;
}
.order-details {
display: flex;
justify-content: space-between;
align-items: center;
}
.order-info p {
margin: 5px 0;
color: #d1d5db;
font-size: 14px;
}
.order-info strong {
color: white;
}
</style>

View File

@@ -0,0 +1,788 @@
<template>
<div class="system-settings">
<!-- 左侧导航栏 -->
<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" @click="goToMembers">
<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><Document /></el-icon>
<span>API管理</span>
</div>
<div class="nav-item" @click="goToTasks">
<el-icon><Document /></el-icon>
<span>生成任务记录</span>
</div>
<div class="nav-item active">
<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"><User /></el-icon>
<input type="text" placeholder="搜索你想要的内容" class="search-input">
</div>
<div class="header-actions">
<el-icon class="notification-icon"><Bell /></el-icon>
<div class="user-avatar">
<div class="avatar-placeholder"></div>
<el-icon class="dropdown-icon"><ArrowDown /></el-icon>
</div>
</div>
</header>
<!-- 会员收费标准 -->
<section class="content-section">
<h2 class="page-title">会员收费标准</h2>
<div class="membership-cards">
<el-card v-for="level in membershipLevels" :key="level.id" class="membership-card">
<div class="card-header">
<h3>{{ level.name }}</h3>
</div>
<div class="card-body">
<p class="price">${{ level.price }}/</p>
<p class="description">{{ level.description }}</p>
</div>
<div class="card-footer">
<el-button type="primary" @click="editLevel(level)">编辑</el-button>
</div>
</el-card>
</div>
</section>
</main>
<!-- 编辑会员收费标准对话框 -->
<el-dialog
v-model="editDialogVisible"
width="480px"
:before-close="handleCloseEditDialog"
class="membership-modal"
:show-close="false"
>
<template #header>
<div class="modal-header">
<h2 class="modal-title">会员收费标准</h2>
<button class="close-btn" @click="handleCloseEditDialog">×</button>
</div>
</template>
<div class="modal-content">
<el-form :model="editForm" :rules="editRules" ref="editFormRef">
<div class="form-group">
<label class="form-label">会员等级</label>
<el-select v-model="editForm.level" placeholder="请选择会员等级" style="width: 100%;">
<el-option label="免费版会员" value="free"></el-option>
<el-option label="标准版会员" value="standard"></el-option>
<el-option label="专业版会员" value="professional"></el-option>
</el-select>
</div>
<div class="form-group">
<label class="form-label">会员价格</label>
<div class="price-input">
<span class="price-prefix">$</span>
<input
type="text"
v-model="editForm.price"
placeholder="0.00"
class="form-control"
@input="handlePriceInput"
/>
</div>
</div>
<div class="form-group">
<label class="form-label">资源点数量</label>
<input
type="number"
v-model="editForm.resourcePoints"
placeholder="0"
min="0"
class="form-control"
/>
</div>
<div class="form-group">
<label class="form-label">会员有效期</label>
<div class="radio-group">
<div class="radio-option">
<input
type="radio"
id="monthly"
v-model="editForm.validityPeriod"
value="monthly"
class="radio-input"
>
<label for="monthly" class="radio-label">月付</label>
</div>
<div class="radio-option">
<input
type="radio"
id="quarterly"
v-model="editForm.validityPeriod"
value="quarterly"
class="radio-input"
>
<label for="quarterly" class="radio-label">季付</label>
</div>
<div class="radio-option">
<input
type="radio"
id="yearly"
v-model="editForm.validityPeriod"
value="yearly"
class="radio-input"
>
<label for="yearly" class="radio-label">年付</label>
</div>
</div>
</div>
</el-form>
</div>
<template #footer>
<div class="modal-footer">
<button class="btn btn-cancel" @click="handleCloseEditDialog">取消</button>
<button class="btn btn-save" @click="saveEdit">保存</button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { ref, reactive } from 'vue'
import { useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import {
Grid,
User,
ShoppingCart,
Document,
Setting,
User as Search,
Bell,
User as ArrowDown
} from '@element-plus/icons-vue'
const router = useRouter()
const membershipLevels = ref([
{ id: 1, name: '免费版会员', price: '0', resourcePoints: 200, description: '包含200资源点/月' },
{ id: 2, name: '标准版会员', price: '50', resourcePoints: 500, description: '包含500资源点/月' },
{ id: 3, name: '专业版会员', price: '250', resourcePoints: 2000, description: '包含2000资源点/月' }
])
const editDialogVisible = ref(false)
const editFormRef = ref(null)
const editForm = reactive({
id: null,
level: '',
price: '',
resourcePoints: 0,
validityPeriod: 'quarterly'
})
const editRules = reactive({
level: [{ required: true, message: '请选择会员等级', trigger: 'change' }],
price: [
{ required: true, message: '请输入价格', trigger: 'blur' },
{ pattern: /^\d+(\.\d+)?$/, message: '请输入有效的数字', trigger: 'blur' }
],
resourcePoints: [{ required: true, message: '请输入资源点数量', trigger: 'blur' }],
validityPeriod: [{ required: true, message: '请选择有效期', trigger: 'change' }]
})
const goToDashboard = () => {
router.push('/home')
}
const goToMembers = () => {
router.push('/member-management')
}
const goToOrders = () => {
router.push('/orders')
}
const goToAPI = () => {
router.push('/api-management')
}
const goToTasks = () => {
router.push('/generate-task-record')
}
const goToSettings = () => {
router.push('/system-settings')
}
const editLevel = (level) => {
Object.assign(editForm, level)
editDialogVisible.value = true
}
const handleCloseEditDialog = () => {
editDialogVisible.value = false
if (editFormRef.value) {
editFormRef.value.resetFields()
}
}
const handlePriceInput = (value) => {
// 确保只输入数字
editForm.price = value.replace(/[^\d.]/g, '')
}
const saveEdit = async () => {
const valid = await editFormRef.value.validate()
if (valid) {
const index = membershipLevels.value.findIndex(level => level.id === editForm.id)
if (index !== -1) {
Object.assign(membershipLevels.value[index], editForm)
ElMessage.success('会员等级更新成功')
editDialogVisible.value = false
}
}
}
</script>
<style scoped>
.system-settings {
display: flex;
height: 100vh;
background-color: #f5f7fa;
font-family: 'Arial', 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;
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;
}
.online-users,
.system-uptime {
margin-bottom: 5px;
}
.highlight {
color: #333;
font-weight: bold;
}
.main-content {
flex-grow: 1;
display: flex;
flex-direction: column;
overflow-y: auto;
}
.top-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px 30px;
background-color: #fff;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
z-index: 100;
}
.search-bar {
display: flex;
align-items: center;
background-color: #f0f2f5;
border-radius: 20px;
padding: 8px 15px;
width: 300px;
}
.search-icon {
color: #909399;
margin-right: 8px;
}
.search-input {
border: none;
background: transparent;
outline: none;
flex-grow: 1;
font-size: 14px;
color: #333;
}
.header-actions {
display: flex;
align-items: center;
}
.notification-icon {
font-size: 20px;
color: #606266;
margin-right: 20px;
cursor: pointer;
}
.user-avatar {
display: flex;
align-items: center;
cursor: pointer;
}
.avatar-placeholder {
width: 32px;
height: 32px;
border-radius: 50%;
margin-right: 8px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 14px;
font-weight: bold;
}
.dropdown-icon {
font-size: 12px;
color: #909399;
}
.content-section {
flex-grow: 1;
padding: 30px;
background-color: #f5f7fa;
}
.page-title {
font-size: 24px;
color: #333;
margin-bottom: 25px;
font-weight: bold;
}
.membership-cards {
display: flex;
gap: 25px;
flex-wrap: wrap;
}
.membership-card {
flex: 1;
min-width: 280px;
max-width: 350px;
border-radius: 12px;
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.08);
transition: all 0.3s ease;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.membership-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.12);
}
.card-header {
padding: 20px;
text-align: center;
border-bottom: 1px solid #eee;
}
.card-header h3 {
font-size: 22px;
color: #333;
margin: 0;
}
.card-body {
padding: 25px 20px;
text-align: center;
flex-grow: 1;
}
.card-body .price {
font-size: 36px;
font-weight: bold;
color: #409eff;
margin-bottom: 10px;
}
.card-body .description {
font-size: 15px;
color: #606266;
line-height: 1.6;
}
.card-footer {
padding: 20px;
text-align: center;
border-top: 1px solid #eee;
}
.el-button {
width: 80%;
padding: 12px 0;
font-size: 16px;
border-radius: 8px;
}
/* 会员收费标准模态框样式 - 完全匹配HTML代码 */
.membership-modal {
border-radius: 12px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
border: 1px solid #e1e5eb;
overflow: hidden;
}
.membership-modal .el-dialog__body {
padding: 0;
}
/* 弹窗头部 */
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20px 24px;
border-bottom: 1px solid #f0f2f5;
}
.modal-title {
font-size: 18px;
font-weight: 600;
color: #1a1a1a;
margin: 0;
}
.close-btn {
width: 32px;
height: 32px;
border: none;
background: #f5f7fa;
border-radius: 6px;
font-size: 16px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
color: #666;
transition: all 0.2s;
}
.close-btn:hover {
background: #e6f3ff;
color: #1890ff;
}
/* 表单内容区域 */
.modal-content {
padding: 24px;
}
.form-group {
margin-bottom: 20px;
}
.form-label {
display: block;
margin-bottom: 8px;
font-size: 14px;
color: #333;
font-weight: 500;
}
/* 输入框和下拉框样式 */
.form-control {
width: 100%;
height: 40px;
padding: 0 12px;
border: 1px solid #d9d9d9;
border-radius: 6px;
font-size: 14px;
color: #333;
transition: all 0.2s;
background-color: white;
}
.form-control:focus {
outline: none;
border-color: #1890ff;
box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
}
.form-control::placeholder {
color: #bfbfbf;
}
/* 价格输入框特殊样式 */
.price-input {
position: relative;
}
.price-prefix {
position: absolute;
left: 12px;
top: 50%;
transform: translateY(-50%);
color: #666;
z-index: 10;
}
.price-input .form-control {
padding-left: 30px;
}
/* 单选按钮组 */
.radio-group {
display: flex;
gap: 16px;
}
.radio-option {
display: flex;
align-items: center;
}
.radio-input {
display: none;
}
.radio-label {
display: flex;
align-items: center;
cursor: pointer;
font-size: 14px;
color: #666;
padding: 8px 16px;
border: 1px solid #d9d9d9;
border-radius: 6px;
transition: all 0.2s;
}
.radio-input:checked + .radio-label {
border-color: #1890ff;
background-color: #e6f7ff;
color: #1890ff;
}
/* 按钮区域 */
.modal-footer {
display: flex;
justify-content: flex-end;
gap: 12px;
padding: 20px 24px;
border-top: 1px solid #f0f2f5;
}
.btn {
padding: 0 20px;
height: 36px;
border: 1px solid;
border-radius: 6px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s;
}
.btn-cancel {
background: white;
border-color: #d9d9d9;
color: #666;
}
.btn-cancel:hover {
border-color: #1890ff;
color: #1890ff;
}
.btn-save {
background: #1890ff;
border-color: #1890ff;
color: white;
}
.btn-save:hover {
background: #40a9ff;
border-color: #40a9ff;
}
/* 响应式调整 */
@media (max-width: 480px) {
.membership-modal {
border-radius: 0;
}
.modal-content {
padding: 16px;
}
.radio-group {
flex-direction: column;
gap: 8px;
}
}
/* Responsive adjustments */
@media (max-width: 1200px) {
.membership-card {
max-width: none;
}
}
@media (max-width: 768px) {
.sidebar {
width: 60px;
padding: 15px 0;
}
.sidebar .logo span,
.sidebar .nav-item span,
.sidebar-footer {
display: none;
}
.sidebar .logo {
padding: 0 10px 20px;
}
.sidebar .logo-icon {
margin-right: 0;
}
.nav-menu {
padding: 0 10px;
}
.nav-item {
justify-content: center;
padding: 10px;
}
.nav-item .el-icon {
margin-right: 0;
}
.top-header {
padding: 10px 20px;
}
.search-bar {
width: 200px;
padding: 6px 10px;
}
.content-section {
padding: 20px;
}
.page-title {
font-size: 20px;
margin-bottom: 20px;
}
.membership-cards {
flex-direction: column;
align-items: center;
}
.membership-card {
width: 90%;
max-width: 400px;
}
}
</style>

View File

@@ -0,0 +1,24 @@
<template>
<div class="test-page">
<h1>测试页面</h1>
<p>如果你能看到这个页面说明Vue组件能正常渲染</p>
<el-button type="primary" @click="testClick">测试按钮</el-button>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { ElMessage } from 'element-plus'
const testClick = () => {
ElMessage.success('按钮点击成功!')
}
</script>
<style scoped>
.test-page {
padding: 50px;
text-align: center;
font-size: 18px;
}
</style>

View File

@@ -25,8 +25,8 @@
<el-icon><Picture /></el-icon>
<span>图生视频</span>
</div>
<div class="nav-item storyboard-item" @click="goToStoryboard">
<el-icon><VideoPlay /></el-icon>
<div class="nav-item storyboard-item" @click="goToStoryboardVideo">
<el-icon><Film /></el-icon>
<span>分镜视频</span>
<el-tag size="small" type="primary" class="sora-tag">Sora2.0</el-tag>
</div>
@@ -148,7 +148,7 @@
import { ref, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { ElIcon, ElButton, ElTag, ElMessage, ElDialog } from 'element-plus'
import { User, Compass, Document, VideoPlay, Picture } from '@element-plus/icons-vue'
import { User, Document, VideoPlay, Picture, Film, Compass } from '@element-plus/icons-vue'
const router = useRouter()
@@ -204,7 +204,7 @@ const goToImageToVideo = () => {
router.push('/image-to-video')
}
const goToStoryboard = () => {
const goToStoryboardVideo = () => {
router.push('/storyboard-video')
}
@@ -252,46 +252,54 @@ onMounted(() => {
/* 左侧导航栏 */
.sidebar {
width: 280px;
background: #1a1a1a;
border-right: 1px solid #333;
padding: 24px 0;
width: 280px !important;
background: #1a1a1a !important;
padding: 24px 0 !important;
border-right: 1px solid #1a1a1a !important;
flex-shrink: 0 !important;
z-index: 100 !important;
display: block !important;
position: relative !important;
}
.logo {
font-size: 18px;
font-weight: 600;
color: #fff;
text-align: center;
margin-bottom: 32px;
padding: 0 24px 32px;
font-size: 20px;
font-weight: 500;
color: white;
}
.nav-menu {
display: flex;
flex-direction: column;
gap: 8px;
padding: 0 20px;
padding: 0 24px;
}
.nav-item {
display: flex;
align-items: center;
gap: 12px;
padding: 12px 16px;
padding: 14px 18px;
margin-bottom: 4px;
border-radius: 8px;
cursor: pointer;
transition: all 0.2s;
color: #d1d5db;
transition: all 0.3s ease;
position: relative;
}
.nav-item:hover {
background: #2a2a2a;
color: #fff;
}
.nav-item.active {
background: #3b82f6;
color: #fff;
background: #1e3a8a;
}
.nav-item .el-icon {
margin-right: 14px;
font-size: 20px;
}
.nav-item span {
font-size: 15px;
flex: 1;
}
.nav-divider {

View File

@@ -157,14 +157,14 @@ import { ref, onMounted, onUnmounted } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import {
VideoPlay,
VideoPause as Pause,
FullScreen,
Share,
Download,
Delete,
User as VideoPlay,
User as VideoPause,
User as FullScreen,
User as Share,
User as Download,
User as Delete,
User,
Compass,
User as Compass,
Document,
Close
} from '@element-plus/icons-vue'

View File

@@ -15,6 +15,7 @@ import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController

View File

@@ -6,7 +6,8 @@ public enum OrderType {
SUBSCRIPTION("订阅订单"),
DIGITAL("数字商品"),
PHYSICAL("实体商品"),
PAYMENT("支付订单");
PAYMENT("支付订单"),
MEMBERSHIP("会员订单");
private final String displayName;

View File

@@ -13,8 +13,8 @@ public class UserActivityStats {
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "stat_date", nullable = false, unique = true)
private LocalDate statDate;
@Column(name = "activity_date", nullable = false, unique = true)
private LocalDate activityDate;
@Column(name = "daily_active_users", nullable = false)
private Integer dailyActiveUsers = 0;
@@ -55,8 +55,8 @@ public class UserActivityStats {
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 LocalDate getActivityDate() { return activityDate; }
public void setActivityDate(LocalDate activityDate) { this.activityDate = activityDate; }
public Integer getDailyActiveUsers() { return dailyActiveUsers; }
public void setDailyActiveUsers(Integer dailyActiveUsers) { this.dailyActiveUsers = dailyActiveUsers; }

View File

@@ -8,7 +8,6 @@ import org.springframework.stereotype.Repository;
import java.time.LocalDate;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@Repository
@@ -17,60 +16,61 @@ public interface UserActivityStatsRepository extends JpaRepository<UserActivityS
/**
* 根据日期查找日活用户数
*/
@Query("SELECT uas.dailyActiveUsers FROM UserActivityStats uas WHERE uas.statDate = :date")
@Query("SELECT uas.dailyActiveUsers FROM UserActivityStats uas WHERE uas.activityDate = :date")
Integer findDailyActiveUsersByDate(@Param("date") LocalDate date);
/**
* 获取指定年份的月度日活用户数据
*/
@Query("SELECT MONTH(uas.statDate) as month, " +
@Query("SELECT MONTH(uas.activityDate) 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)")
"WHERE YEAR(uas.activityDate) = :year " +
"GROUP BY MONTH(uas.activityDate) " +
"ORDER BY MONTH(uas.activityDate)")
List<java.util.Map<String, Object>> findMonthlyActiveUsers(@Param("year") int year);
/**
* 获取指定年份的每日日活用户数据
*/
@Query("SELECT DAYOFYEAR(uas.statDate) as dayOfYear, " +
"WEEK(uas.statDate) as weekOfYear, " +
@Query("SELECT DAYOFYEAR(uas.activityDate) as dayOfYear, " +
"WEEK(uas.activityDate) as weekOfYear, " +
"uas.dailyActiveUsers as dailyActiveUsers, " +
"uas.statDate as statDate " +
"uas.activityDate as activityDate " +
"FROM UserActivityStats uas " +
"WHERE YEAR(uas.statDate) = :year " +
"ORDER BY uas.statDate")
"WHERE YEAR(uas.activityDate) = :year " +
"ORDER BY uas.activityDate")
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")
"WHERE YEAR(uas.activityDate) = :year AND MONTH(uas.activityDate) = :month")
Double findAverageDailyActiveUsersByMonth(@Param("year") int year, @Param("month") int month);
/**
* 获取指定年份的平均日活用户数
*/
@Query("SELECT AVG(uas.dailyActiveUsers) FROM UserActivityStats uas " +
"WHERE YEAR(uas.statDate) = :year")
"WHERE YEAR(uas.activityDate) = :year")
Double findAverageDailyActiveUsersByYear(@Param("year") int year);
/**
* 获取最新的统计数据
*/
Optional<UserActivityStats> findTopByOrderByStatDateDesc();
Optional<UserActivityStats> findTopByOrderByActivityDateDesc();
/**
* 获取指定日期范围的统计数据
*/
List<UserActivityStats> findByStatDateBetween(LocalDate startDate, LocalDate endDate);
List<UserActivityStats> findByActivityDateBetween(LocalDate startDate, LocalDate endDate);
/**
* 获取指定年份的所有统计数据
*/
List<UserActivityStats> findByStatDateYear(int year);
@Query("SELECT uas FROM UserActivityStats uas WHERE YEAR(uas.activityDate) = :year ORDER BY uas.activityDate")
List<UserActivityStats> findByActivityDateYear(@Param("year") int year);
}

View File

@@ -28,3 +28,5 @@ public class PlainTextPasswordEncoder implements PasswordEncoder {

View File

@@ -1,3 +1,6 @@
# Server Configuration
server.port=8080
# MySQL DataSource (DEV) - 使用环境变量
spring.datasource.url=${DB_URL:jdbc:mysql://localhost:3306/aigc?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true}
spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver

View File

@@ -1,10 +1,9 @@
-- 用户数据
INSERT IGNORE INTO users (username, email, password_hash, role, points, phone, nickname, gender, birthday, address) VALUES
('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', '上海市浦东新区'),
('13689270819', '13689270819@example.com', '0627', 'ROLE_USER', 100, '13689270819', '演示用户', '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', '西安市雁塔区'),

View File

@@ -0,0 +1,25 @@
-- 插入订单项数据
INSERT INTO order_items (order_id, product_name, quantity, unit_price, subtotal)
SELECT
o.id as order_id,
CASE
WHEN o.order_type = 'MEMBERSHIP' THEN
CASE
WHEN o.total_amount = 29.00 THEN '标准会员订阅'
WHEN o.total_amount = 99.00 THEN '专业会员订阅'
WHEN o.total_amount = 299.00 THEN '企业会员订阅'
ELSE '会员订阅'
END
WHEN o.order_type = 'PRODUCT' THEN
CASE
WHEN o.total_amount = 49.00 THEN '基础视频生成'
WHEN o.total_amount = 99.00 THEN '高级视频编辑'
WHEN o.total_amount = 199.00 THEN '视频生成服务包'
ELSE '视频服务'
END
ELSE '其他服务'
END as product_name,
1 as quantity,
o.total_amount as unit_price,
o.total_amount as subtotal
FROM orders o;

View File

@@ -0,0 +1,265 @@
-- 插入12个月的订单数据使用正确的用户ID
INSERT INTO orders (order_number, total_amount, currency, status, order_type, description, user_id, created_at) VALUES
-- 2024年1月
('ORD20240101001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 3, '2024-01-01 10:00:00'),
('ORD20240101002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 209, '2024-01-01 11:00:00'),
('ORD20240101003', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 211, '2024-01-01 12:00:00'),
('ORD20240101004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 212, '2024-01-01 13:00:00'),
('ORD20240101005', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 213, '2024-01-01 14:00:00'),
('ORD20240101006', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 231, '2024-01-01 15:00:00'),
('ORD20240101007', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 3, '2024-01-01 16:00:00'),
('ORD20240101008', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 209, '2024-01-01 17:00:00'),
('ORD20240101009', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 211, '2024-01-01 18:00:00'),
('ORD20240101010', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 212, '2024-01-01 19:00:00'),
('ORD20240102001', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 213, '2024-01-02 09:00:00'),
('ORD20240102002', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 231, '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', '基础视频生成', 209, '2024-01-02 12:00:00'),
('ORD20240102005', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 211, '2024-01-02 13:00:00'),
('ORD20240102006', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 212, '2024-01-02 14:00:00'),
('ORD20240102007', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 213, '2024-01-02 15:00:00'),
('ORD20240102008', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 231, '2024-01-02 16:00:00'),
('ORD20240102009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-01-02 17:00:00'),
('ORD20240102010', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 209, '2024-01-02 18:00:00'),
-- 2024年2月
('ORD20240201001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 211, '2024-02-01 10:00:00'),
('ORD20240201002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 212, '2024-02-01 11:00:00'),
('ORD20240201003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 213, '2024-02-01 11:30:00'),
('ORD20240201004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 231, '2024-02-01 12:00:00'),
('ORD20240201005', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 3, '2024-02-01 13:00:00'),
('ORD20240201006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 209, '2024-02-01 14:00:00'),
('ORD20240201007', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 211, '2024-02-01 15:00:00'),
('ORD20240201008', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 212, '2024-02-01 16:00:00'),
('ORD20240201009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 213, '2024-02-01 17:00:00'),
('ORD20240201010', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 231, '2024-02-01 18:00:00'),
('ORD20240202001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 3, '2024-02-02 09:00:00'),
('ORD20240202002', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 209, '2024-02-02 10:00:00'),
('ORD20240202003', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 211, '2024-02-02 11:00:00'),
('ORD20240202004', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 212, '2024-02-02 12:00:00'),
('ORD20240202005', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 213, '2024-02-02 13:00:00'),
('ORD20240202006', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 231, '2024-02-02 14:00:00'),
('ORD20240202007', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 3, '2024-02-02 15:00:00'),
('ORD20240202008', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 209, '2024-02-02 16:00:00'),
('ORD20240202009', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 211, '2024-02-02 17:00:00'),
('ORD20240202010', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 212, '2024-02-02 18:00:00'),
-- 2024年3月
('ORD20240301001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 213, '2024-03-01 10:00:00'),
('ORD20240301002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 231, '2024-03-01 11:00:00'),
('ORD20240301003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-03-01 11:20:00'),
('ORD20240301004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 209, '2024-03-01 12:00:00'),
('ORD20240301005', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 211, '2024-03-01 13:00:00'),
('ORD20240301006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 212, '2024-03-01 14:00:00'),
('ORD20240301007', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 213, '2024-03-01 15:00:00'),
('ORD20240301008', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 231, '2024-03-01 16:00:00'),
('ORD20240301009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-03-01 17:00:00'),
('ORD20240301010', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 209, '2024-03-01 18:00:00'),
('ORD20240322001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 211, '2024-03-22 14:30:00'),
('ORD20240322002', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 212, '2024-03-22 14:40:00'),
('ORD20240322003', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 213, '2024-03-22 14:45:00'),
('ORD20240322004', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 231, '2024-03-22 14:50:00'),
('ORD20240322005', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-03-22 14:55:00'),
('ORD20240322006', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 209, '2024-03-22 15:00:00'),
('ORD20240322007', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 211, '2024-03-22 15:05:00'),
('ORD20240322008', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 212, '2024-03-22 15:10:00'),
('ORD20240322009', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 213, '2024-03-22 15:15:00'),
('ORD20240322010', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 231, '2024-03-22 15:20:00'),
-- 2024年4月
('ORD20240401001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 3, '2024-04-01 10:00:00'),
('ORD20240401002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 209, '2024-04-01 11:00:00'),
('ORD20240401003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 211, '2024-04-01 12:00:00'),
('ORD20240401004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 212, '2024-04-01 13:00:00'),
('ORD20240401005', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 213, '2024-04-01 14:00:00'),
('ORD20240401006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 231, '2024-04-01 15:00:00'),
('ORD20240401007', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 3, '2024-04-01 16:00:00'),
('ORD20240401008', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 209, '2024-04-01 17:00:00'),
('ORD20240401009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 211, '2024-04-01 18:00:00'),
('ORD20240401010', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 212, '2024-04-01 19:00:00'),
('ORD20240410001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 213, '2024-04-10 14:15:00'),
('ORD20240410002', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 231, '2024-04-10 14:18:00'),
('ORD20240410003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-04-10 14:20:00'),
('ORD20240410004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 209, '2024-04-10 14:25:00'),
('ORD20240410005', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 211, '2024-04-10 14:30:00'),
('ORD20240410006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 212, '2024-04-10 14:35:00'),
('ORD20240410007', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 213, '2024-04-10 14:40:00'),
('ORD20240410008', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 231, '2024-04-10 14:45:00'),
('ORD20240410009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-04-10 14:50:00'),
('ORD20240410010', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 209, '2024-04-10 14:55:00'),
-- 2024年5月
('ORD20240501001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 211, '2024-05-01 10:00:00'),
('ORD20240501002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 212, '2024-05-01 11:00:00'),
('ORD20240501003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 213, '2024-05-01 11:20:00'),
('ORD20240501004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 231, '2024-05-01 12:00:00'),
('ORD20240501005', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 3, '2024-05-01 13:00:00'),
('ORD20240501006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 209, '2024-05-01 14:00:00'),
('ORD20240501007', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 211, '2024-05-01 15:00:00'),
('ORD20240501008', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 212, '2024-05-01 16:00:00'),
('ORD20240501009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 213, '2024-05-01 17:00:00'),
('ORD20240501010', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 231, '2024-05-01 18:00:00'),
('ORD20240525001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 3, '2024-05-25 11:00:00'),
('ORD20240525002', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 209, '2024-05-25 11:05:00'),
('ORD20240525003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 211, '2024-05-25 11:10:00'),
('ORD20240525004', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 212, '2024-05-25 11:15:00'),
('ORD20240525005', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 213, '2024-05-25 11:20:00'),
('ORD20240525006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 231, '2024-05-25 11:25:00'),
('ORD20240525007', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 3, '2024-05-25 11:30:00'),
('ORD20240525008', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 209, '2024-05-25 11:35:00'),
('ORD20240525009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 211, '2024-05-25 11:40:00'),
('ORD20240525010', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 212, '2024-05-25 11:45:00'),
-- 2024年6月
('ORD20240601001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 213, '2024-06-01 10:00:00'),
('ORD20240601002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 231, '2024-06-01 11:00:00'),
('ORD20240601003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-06-01 12:00:00'),
('ORD20240601004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 209, '2024-06-01 13:00:00'),
('ORD20240601005', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 211, '2024-06-01 14:00:00'),
('ORD20240601006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 212, '2024-06-01 15:00:00'),
('ORD20240601007', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 213, '2024-06-01 16:00:00'),
('ORD20240601008', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 231, '2024-06-01 17:00:00'),
('ORD20240601009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-06-01 18:00:00'),
('ORD20240601010', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 209, '2024-06-01 19:00:00'),
('ORD20240615001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 211, '2024-06-15 14:10:00'),
('ORD20240615002', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 212, '2024-06-15 14:12:00'),
('ORD20240615003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 213, '2024-06-15 14:15:00'),
('ORD20240615004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 231, '2024-06-15 14:18:00'),
('ORD20240615005', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 3, '2024-06-15 14:20:00'),
('ORD20240615006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 209, '2024-06-15 14:25:00'),
('ORD20240615007', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 211, '2024-06-15 14:30:00'),
('ORD20240615008', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 212, '2024-06-15 14:35:00'),
('ORD20240615009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 213, '2024-06-15 14:40:00'),
('ORD20240615010', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 231, '2024-06-15 14:45:00'),
-- 2024年7月
('ORD20240701001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 3, '2024-07-01 10:00:00'),
('ORD20240701002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 209, '2024-07-01 11:00:00'),
('ORD20240701003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 211, '2024-07-01 12:15:00'),
('ORD20240701004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 212, '2024-07-01 13:00:00'),
('ORD20240701005', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 213, '2024-07-01 14:00:00'),
('ORD20240701006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 231, '2024-07-01 15:00:00'),
('ORD20240701007', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 3, '2024-07-01 16:00:00'),
('ORD20240701008', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 209, '2024-07-01 17:00:00'),
('ORD20240701009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 211, '2024-07-01 18:00:00'),
('ORD20240701010', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 212, '2024-07-01 19:00:00'),
('ORD20240720001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 213, '2024-07-20 16:00:00'),
('ORD20240720002', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 231, '2024-07-20 16:05:00'),
('ORD20240720003', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 3, '2024-07-20 16:10:00'),
('ORD20240720004', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 209, '2024-07-20 16:15:00'),
('ORD20240720005', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 211, '2024-07-20 16:20:00'),
('ORD20240720006', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 212, '2024-07-20 16:25:00'),
('ORD20240720007', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 213, '2024-07-20 16:30:00'),
('ORD20240720008', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 231, '2024-07-20 16:35:00'),
('ORD20240720009', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 3, '2024-07-20 16:40:00'),
('ORD20240720010', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 209, '2024-07-20 16:45:00'),
-- 2024年8月
('ORD20240801001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 211, '2024-08-01 10:00:00'),
('ORD20240801002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 212, '2024-08-01 11:00:00'),
('ORD20240801003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 213, '2024-08-01 12:00:00'),
('ORD20240801004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 231, '2024-08-01 13:00:00'),
('ORD20240801005', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 3, '2024-08-01 14:00:00'),
('ORD20240801006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 209, '2024-08-01 15:00:00'),
('ORD20240801007', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 211, '2024-08-01 16:00:00'),
('ORD20240801008', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 212, '2024-08-01 17:00:00'),
('ORD20240801009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 213, '2024-08-01 18:00:00'),
('ORD20240801010', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 231, '2024-08-01 19:00:00'),
('ORD20240815001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 3, '2024-08-15 15:00:00'),
('ORD20240815002', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 209, '2024-08-15 15:05:00'),
('ORD20240815003', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 211, '2024-08-15 15:10:00'),
('ORD20240815004', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 212, '2024-08-15 15:15:00'),
('ORD20240815005', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 213, '2024-08-15 15:20:00'),
('ORD20240815006', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 231, '2024-08-15 15:25:00'),
('ORD20240815007', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 3, '2024-08-15 15:30:00'),
('ORD20240815008', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 209, '2024-08-15 15:35:00'),
('ORD20240815009', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 211, '2024-08-15 15:40:00'),
('ORD20240815010', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 212, '2024-08-15 15:45:00'),
-- 2024年9月
('ORD20240901001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 213, '2024-09-01 10:00:00'),
('ORD20240901002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 231, '2024-09-01 11:00:00'),
('ORD20240901003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-09-01 12:00:00'),
('ORD20240901004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 209, '2024-09-01 13:00:00'),
('ORD20240901005', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 211, '2024-09-01 14:00:00'),
('ORD20240901006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 212, '2024-09-01 15:00:00'),
('ORD20240901007', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 213, '2024-09-01 16:00:00'),
('ORD20240901008', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 231, '2024-09-01 17:00:00'),
('ORD20240901009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-09-01 18:00:00'),
('ORD20240901010', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 209, '2024-09-01 19:00:00'),
('ORD20240910001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 211, '2024-09-10 17:00:00'),
('ORD20240910002', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 212, '2024-09-10 17:05:00'),
('ORD20240910003', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 213, '2024-09-10 17:10:00'),
('ORD20240910004', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 231, '2024-09-10 17:15:00'),
('ORD20240910005', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-09-10 17:20:00'),
('ORD20240910006', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 209, '2024-09-10 17:25:00'),
('ORD20240910007', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 211, '2024-09-10 17:30:00'),
('ORD20240910008', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 212, '2024-09-10 17:35:00'),
('ORD20240910009', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 213, '2024-09-10 17:40:00'),
('ORD20240910010', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 231, '2024-09-10 17:45:00'),
-- 2024年10月
('ORD20241001001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 3, '2024-10-01 10:00:00'),
('ORD20241001002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 209, '2024-10-01 11:00:00'),
('ORD20241001003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 211, '2024-10-01 12:00:00'),
('ORD20241001004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 212, '2024-10-01 13:00:00'),
('ORD20241001005', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 213, '2024-10-01 14:00:00'),
('ORD20241001006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 231, '2024-10-01 15:00:00'),
('ORD20241001007', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 3, '2024-10-01 16:00:00'),
('ORD20241001008', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 209, '2024-10-01 17:00:00'),
('ORD20241001009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 211, '2024-10-01 18:00:00'),
('ORD20241001010', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 212, '2024-10-01 19:00:00'),
('ORD20241020001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 213, '2024-10-20 18:00:00'),
('ORD20241020002', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 231, '2024-10-20 18:05:00'),
('ORD20241020003', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 3, '2024-10-20 18:10:00'),
('ORD20241020004', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 209, '2024-10-20 18:15:00'),
('ORD20241020005', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 211, '2024-10-20 18:20:00'),
('ORD20241020006', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 212, '2024-10-20 18:25:00'),
('ORD20241020007', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 213, '2024-10-20 18:30:00'),
('ORD20241020008', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 231, '2024-10-20 18:35:00'),
('ORD20241020009', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 3, '2024-10-20 18:40:00'),
('ORD20241020010', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 209, '2024-10-20 18:45:00'),
-- 2024年11月
('ORD20241101001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 211, '2024-11-01 10:00:00'),
('ORD20241101002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 212, '2024-11-01 11:00:00'),
('ORD20241101003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 213, '2024-11-01 12:00:00'),
('ORD20241101004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 231, '2024-11-01 13:00:00'),
('ORD20241101005', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 3, '2024-11-01 14:00:00'),
('ORD20241101006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 209, '2024-11-01 15:00:00'),
('ORD20241101007', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 211, '2024-11-01 16:00:00'),
('ORD20241101008', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 212, '2024-11-01 17:00:00'),
('ORD20241101009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 213, '2024-11-01 18:00:00'),
('ORD20241101010', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 231, '2024-11-01 19:00:00'),
('ORD20241115001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 3, '2024-11-15 19:00:00'),
('ORD20241115002', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 209, '2024-11-15 19:05:00'),
('ORD20241115003', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 211, '2024-11-15 19:10:00'),
('ORD20241115004', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 212, '2024-11-15 19:15:00'),
('ORD20241115005', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 213, '2024-11-15 19:20:00'),
('ORD20241115006', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 231, '2024-11-15 19:25:00'),
('ORD20241115007', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 3, '2024-11-15 19:30:00'),
('ORD20241115008', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 209, '2024-11-15 19:35:00'),
('ORD20241115009', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 211, '2024-11-15 19:40:00'),
('ORD20241115010', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 212, '2024-11-15 19:45:00'),
-- 2024年12月
('ORD20241201001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 213, '2024-12-01 10:00:00'),
('ORD20241201002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 231, '2024-12-01 11:00:00'),
('ORD20241201003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-12-01 12:00:00'),
('ORD20241201004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 209, '2024-12-01 13:00:00'),
('ORD20241201005', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 211, '2024-12-01 14:00:00'),
('ORD20241201006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 212, '2024-12-01 15:00:00'),
('ORD20241201007', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 213, '2024-12-01 16:00:00'),
('ORD20241201008', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 231, '2024-12-01 17:00:00'),
('ORD20241201009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-12-01 18:00:00'),
('ORD20241201010', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 209, '2024-12-01 19:00:00'),
('ORD20241220001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 211, '2024-12-20 20:00:00'),
('ORD20241220002', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 212, '2024-12-20 20:05:00'),
('ORD20241220003', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 213, '2024-12-20 20:10:00'),
('ORD20241220004', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 231, '2024-12-20 20:15:00'),
('ORD20241220005', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-12-20 20:20:00'),
('ORD20241220006', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 209, '2024-12-20 20:25:00'),
('ORD20241220007', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 211, '2024-12-20 20:30:00'),
('ORD20241220008', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 212, '2024-12-20 20:35:00'),
('ORD20241220009', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 213, '2024-12-20 20:40:00'),
('ORD20241220010', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 231, '2024-12-20 20:45:00');

View File

@@ -0,0 +1,270 @@
-- 删除现有订单数据(如果需要重新插入)
-- DELETE FROM payments WHERE order_id IN (SELECT id FROM orders);
-- DELETE FROM order_items WHERE order_id IN (SELECT id FROM orders);
-- DELETE FROM orders;
-- 插入12个月的订单数据
INSERT 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', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 5, '2024-01-02 13:00:00'),
('ORD20240102006', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 6, '2024-01-02 14:00:00'),
('ORD20240102007', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 7, '2024-01-02 15:00:00'),
('ORD20240102008', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 8, '2024-01-02 16:00:00'),
('ORD20240102009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 9, '2024-01-02 17:00:00'),
('ORD20240102010', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 10, '2024-01-02 18:00:00'),
-- 2024年2月
('ORD20240201001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 1, '2024-02-01 10:00:00'),
('ORD20240201002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 2, '2024-02-01 11:00:00'),
('ORD20240201003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-02-01 11:30:00'),
('ORD20240201004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 4, '2024-02-01 12:00:00'),
('ORD20240201005', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 5, '2024-02-01 13:00:00'),
('ORD20240201006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 6, '2024-02-01 14:00:00'),
('ORD20240201007', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 7, '2024-02-01 15:00:00'),
('ORD20240201008', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 8, '2024-02-01 16:00:00'),
('ORD20240201009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 9, '2024-02-01 17:00:00'),
('ORD20240201010', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 10, '2024-02-01 18:00:00'),
('ORD20240202001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 1, '2024-02-02 09:00:00'),
('ORD20240202002', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 2, '2024-02-02 10:00:00'),
('ORD20240202003', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 3, '2024-02-02 11:00:00'),
('ORD20240202004', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 4, '2024-02-02 12:00:00'),
('ORD20240202005', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 5, '2024-02-02 13:00:00'),
('ORD20240202006', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 6, '2024-02-02 14:00:00'),
('ORD20240202007', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 7, '2024-02-02 15:00:00'),
('ORD20240202008', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 8, '2024-02-02 16:00:00'),
('ORD20240202009', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 9, '2024-02-02 17:00:00'),
('ORD20240202010', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 10, '2024-02-02 18:00:00'),
-- 2024年3月
('ORD20240301001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 1, '2024-03-01 10:00:00'),
('ORD20240301002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 2, '2024-03-01 11:00:00'),
('ORD20240301003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-03-01 11:20:00'),
('ORD20240301004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 4, '2024-03-01 12:00:00'),
('ORD20240301005', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 5, '2024-03-01 13:00:00'),
('ORD20240301006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 6, '2024-03-01 14:00:00'),
('ORD20240301007', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 7, '2024-03-01 15:00:00'),
('ORD20240301008', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 8, '2024-03-01 16:00:00'),
('ORD20240301009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 9, '2024-03-01 17:00:00'),
('ORD20240301010', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 10, '2024-03-01 18:00:00'),
('ORD20240322001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 1, '2024-03-22 14:30:00'),
('ORD20240322002', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 2, '2024-03-22 14:40:00'),
('ORD20240322003', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 3, '2024-03-22 14:45:00'),
('ORD20240322004', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 4, '2024-03-22 14:50:00'),
('ORD20240322005', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 5, '2024-03-22 14:55:00'),
('ORD20240322006', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 6, '2024-03-22 15:00:00'),
('ORD20240322007', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 7, '2024-03-22 15:05:00'),
('ORD20240322008', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 8, '2024-03-22 15:10:00'),
('ORD20240322009', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 9, '2024-03-22 15:15:00'),
('ORD20240322010', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 10, '2024-03-22 15:20:00'),
-- 2024年4月
('ORD20240401001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 1, '2024-04-01 10:00:00'),
('ORD20240401002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 2, '2024-04-01 11:00:00'),
('ORD20240401003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-04-01 12:00:00'),
('ORD20240401004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 4, '2024-04-01 13:00:00'),
('ORD20240401005', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 5, '2024-04-01 14:00:00'),
('ORD20240401006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 6, '2024-04-01 15:00:00'),
('ORD20240401007', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 7, '2024-04-01 16:00:00'),
('ORD20240401008', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 8, '2024-04-01 17:00:00'),
('ORD20240401009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 9, '2024-04-01 18:00:00'),
('ORD20240401010', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 10, '2024-04-01 19:00:00'),
('ORD20240410001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 1, '2024-04-10 14:15:00'),
('ORD20240410002', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 2, '2024-04-10 14:18:00'),
('ORD20240410003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-04-10 14:20:00'),
('ORD20240410004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 4, '2024-04-10 14:25:00'),
('ORD20240410005', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 5, '2024-04-10 14:30:00'),
('ORD20240410006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 6, '2024-04-10 14:35:00'),
('ORD20240410007', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 7, '2024-04-10 14:40:00'),
('ORD20240410008', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 8, '2024-04-10 14:45:00'),
('ORD20240410009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 9, '2024-04-10 14:50:00'),
('ORD20240410010', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 10, '2024-04-10 14:55:00'),
-- 2024年5月
('ORD20240501001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 1, '2024-05-01 10:00:00'),
('ORD20240501002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 2, '2024-05-01 11:00:00'),
('ORD20240501003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-05-01 11:20:00'),
('ORD20240501004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 4, '2024-05-01 12:00:00'),
('ORD20240501005', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 5, '2024-05-01 13:00:00'),
('ORD20240501006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 6, '2024-05-01 14:00:00'),
('ORD20240501007', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 7, '2024-05-01 15:00:00'),
('ORD20240501008', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 8, '2024-05-01 16:00:00'),
('ORD20240501009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 9, '2024-05-01 17:00:00'),
('ORD20240501010', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 10, '2024-05-01 18:00:00'),
('ORD20240525001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 1, '2024-05-25 11:00:00'),
('ORD20240525002', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 2, '2024-05-25 11:05:00'),
('ORD20240525003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-05-25 11:10:00'),
('ORD20240525004', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 4, '2024-05-25 11:15:00'),
('ORD20240525005', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 5, '2024-05-25 11:20:00'),
('ORD20240525006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 6, '2024-05-25 11:25:00'),
('ORD20240525007', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 7, '2024-05-25 11:30:00'),
('ORD20240525008', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 8, '2024-05-25 11:35:00'),
('ORD20240525009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 9, '2024-05-25 11:40:00'),
('ORD20240525010', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 10, '2024-05-25 11:45:00'),
-- 2024年6月
('ORD20240601001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 1, '2024-06-01 10:00:00'),
('ORD20240601002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 2, '2024-06-01 11:00:00'),
('ORD20240601003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-06-01 12:00:00'),
('ORD20240601004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 4, '2024-06-01 13:00:00'),
('ORD20240601005', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 5, '2024-06-01 14:00:00'),
('ORD20240601006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 6, '2024-06-01 15:00:00'),
('ORD20240601007', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 7, '2024-06-01 16:00:00'),
('ORD20240601008', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 8, '2024-06-01 17:00:00'),
('ORD20240601009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 9, '2024-06-01 18:00:00'),
('ORD20240601010', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 10, '2024-06-01 19:00:00'),
('ORD20240615001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 1, '2024-06-15 14:10:00'),
('ORD20240615002', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 2, '2024-06-15 14:12:00'),
('ORD20240615003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-06-15 14:15:00'),
('ORD20240615004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 4, '2024-06-15 14:18:00'),
('ORD20240615005', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 5, '2024-06-15 14:20:00'),
('ORD20240615006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 6, '2024-06-15 14:25:00'),
('ORD20240615007', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 7, '2024-06-15 14:30:00'),
('ORD20240615008', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 8, '2024-06-15 14:35:00'),
('ORD20240615009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 9, '2024-06-15 14:40:00'),
('ORD20240615010', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 10, '2024-06-15 14:45:00'),
-- 2024年7月
('ORD20240701001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 1, '2024-07-01 10:00:00'),
('ORD20240701002', 29.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', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 4, '2024-07-01 13:00:00'),
('ORD20240701005', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 5, '2024-07-01 14:00:00'),
('ORD20240701006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 6, '2024-07-01 15:00:00'),
('ORD20240701007', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 7, '2024-07-01 16:00:00'),
('ORD20240701008', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 8, '2024-07-01 17:00:00'),
('ORD20240701009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 9, '2024-07-01 18:00:00'),
('ORD20240701010', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 10, '2024-07-01 19:00:00'),
('ORD20240720001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 1, '2024-07-20 16:00:00'),
('ORD20240720002', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 2, '2024-07-20 16:05:00'),
('ORD20240720003', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 3, '2024-07-20 16:10:00'),
('ORD20240720004', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 4, '2024-07-20 16:15:00'),
('ORD20240720005', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 5, '2024-07-20 16:20:00'),
('ORD20240720006', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 6, '2024-07-20 16:25:00'),
('ORD20240720007', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 7, '2024-07-20 16:30:00'),
('ORD20240720008', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 8, '2024-07-20 16:35:00'),
('ORD20240720009', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 9, '2024-07-20 16:40:00'),
('ORD20240720010', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 10, '2024-07-20 16:45:00'),
-- 2024年8月
('ORD20240801001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 1, '2024-08-01 10:00:00'),
('ORD20240801002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 2, '2024-08-01 11:00:00'),
('ORD20240801003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-08-01 12:00:00'),
('ORD20240801004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 4, '2024-08-01 13:00:00'),
('ORD20240801005', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 5, '2024-08-01 14:00:00'),
('ORD20240801006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 6, '2024-08-01 15:00:00'),
('ORD20240801007', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 7, '2024-08-01 16:00:00'),
('ORD20240801008', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 8, '2024-08-01 17:00:00'),
('ORD20240801009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 9, '2024-08-01 18:00:00'),
('ORD20240801010', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 10, '2024-08-01 19:00:00'),
('ORD20240815001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 1, '2024-08-15 15:00:00'),
('ORD20240815002', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 2, '2024-08-15 15:05:00'),
('ORD20240815003', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 3, '2024-08-15 15:10:00'),
('ORD20240815004', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 4, '2024-08-15 15:15:00'),
('ORD20240815005', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 5, '2024-08-15 15:20:00'),
('ORD20240815006', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 6, '2024-08-15 15:25:00'),
('ORD20240815007', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 7, '2024-08-15 15:30:00'),
('ORD20240815008', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 8, '2024-08-15 15:35:00'),
('ORD20240815009', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 9, '2024-08-15 15:40:00'),
('ORD20240815010', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 10, '2024-08-15 15:45:00'),
-- 2024年9月
('ORD20240901001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 1, '2024-09-01 10:00:00'),
('ORD20240901002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 2, '2024-09-01 11:00:00'),
('ORD20240901003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-09-01 12:00:00'),
('ORD20240901004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 4, '2024-09-01 13:00:00'),
('ORD20240901005', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 5, '2024-09-01 14:00:00'),
('ORD20240901006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 6, '2024-09-01 15:00:00'),
('ORD20240901007', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 7, '2024-09-01 16:00:00'),
('ORD20240901008', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 8, '2024-09-01 17:00:00'),
('ORD20240901009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 9, '2024-09-01 18:00:00'),
('ORD20240901010', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 10, '2024-09-01 19:00:00'),
('ORD20240910001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 1, '2024-09-10 17:00:00'),
('ORD20240910002', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 2, '2024-09-10 17:05:00'),
('ORD20240910003', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 3, '2024-09-10 17:10:00'),
('ORD20240910004', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 4, '2024-09-10 17:15:00'),
('ORD20240910005', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 5, '2024-09-10 17:20:00'),
('ORD20240910006', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 6, '2024-09-10 17:25:00'),
('ORD20240910007', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 7, '2024-09-10 17:30:00'),
('ORD20240910008', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 8, '2024-09-10 17:35:00'),
('ORD20240910009', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 9, '2024-09-10 17:40:00'),
('ORD20240910010', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 10, '2024-09-10 17:45:00'),
-- 2024年10月
('ORD20241001001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 1, '2024-10-01 10:00:00'),
('ORD20241001002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 2, '2024-10-01 11:00:00'),
('ORD20241001003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-10-01 12:00:00'),
('ORD20241001004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 4, '2024-10-01 13:00:00'),
('ORD20241001005', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 5, '2024-10-01 14:00:00'),
('ORD20241001006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 6, '2024-10-01 15:00:00'),
('ORD20241001007', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 7, '2024-10-01 16:00:00'),
('ORD20241001008', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 8, '2024-10-01 17:00:00'),
('ORD20241001009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 9, '2024-10-01 18:00:00'),
('ORD20241001010', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 10, '2024-10-01 19:00:00'),
('ORD20241020001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 1, '2024-10-20 18:00:00'),
('ORD20241020002', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 2, '2024-10-20 18:05:00'),
('ORD20241020003', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 3, '2024-10-20 18:10:00'),
('ORD20241020004', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 4, '2024-10-20 18:15:00'),
('ORD20241020005', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 5, '2024-10-20 18:20:00'),
('ORD20241020006', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 6, '2024-10-20 18:25:00'),
('ORD20241020007', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 7, '2024-10-20 18:30:00'),
('ORD20241020008', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 8, '2024-10-20 18:35:00'),
('ORD20241020009', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 9, '2024-10-20 18:40:00'),
('ORD20241020010', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 10, '2024-10-20 18:45:00'),
-- 2024年11月
('ORD20241101001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 1, '2024-11-01 10:00:00'),
('ORD20241101002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 2, '2024-11-01 11:00:00'),
('ORD20241101003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-11-01 12:00:00'),
('ORD20241101004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 4, '2024-11-01 13:00:00'),
('ORD20241101005', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 5, '2024-11-01 14:00:00'),
('ORD20241101006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 6, '2024-11-01 15:00:00'),
('ORD20241101007', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 7, '2024-11-01 16:00:00'),
('ORD20241101008', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 8, '2024-11-01 17:00:00'),
('ORD20241101009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 9, '2024-11-01 18:00:00'),
('ORD20241101010', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 10, '2024-11-01 19:00:00'),
('ORD20241115001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 1, '2024-11-15 19:00:00'),
('ORD20241115002', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 2, '2024-11-15 19:05:00'),
('ORD20241115003', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 3, '2024-11-15 19:10:00'),
('ORD20241115004', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 4, '2024-11-15 19:15:00'),
('ORD20241115005', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 5, '2024-11-15 19:20:00'),
('ORD20241115006', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 6, '2024-11-15 19:25:00'),
('ORD20241115007', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 7, '2024-11-15 19:30:00'),
('ORD20241115008', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 8, '2024-11-15 19:35:00'),
('ORD20241115009', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 9, '2024-11-15 19:40:00'),
('ORD20241115010', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 10, '2024-11-15 19:45:00'),
-- 2024年12月
('ORD20241201001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 1, '2024-12-01 10:00:00'),
('ORD20241201002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 2, '2024-12-01 11:00:00'),
('ORD20241201003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-12-01 12:00:00'),
('ORD20241201004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 4, '2024-12-01 13:00:00'),
('ORD20241201005', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 5, '2024-12-01 14:00:00'),
('ORD20241201006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 6, '2024-12-01 15:00:00'),
('ORD20241201007', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 7, '2024-12-01 16:00:00'),
('ORD20241201008', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 8, '2024-12-01 17:00:00'),
('ORD20241201009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 9, '2024-12-01 18:00:00'),
('ORD20241201010', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 10, '2024-12-01 19:00:00'),
('ORD20241220001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 1, '2024-12-20 20:00:00'),
('ORD20241220002', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 2, '2024-12-20 20:05:00'),
('ORD20241220003', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 3, '2024-12-20 20:10:00'),
('ORD20241220004', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 4, '2024-12-20 20:15:00'),
('ORD20241220005', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 5, '2024-12-20 20:20:00'),
('ORD20241220006', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 6, '2024-12-20 20:25:00'),
('ORD20241220007', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 7, '2024-12-20 20:30:00'),
('ORD20241220008', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 8, '2024-12-20 20:35:00'),
('ORD20241220009', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 9, '2024-12-20 20:40:00'),
('ORD20241220010', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 10, '2024-12-20 20:45:00');

View File

@@ -0,0 +1,24 @@
-- 插入支付数据
INSERT INTO payments (order_id, user_id, amount, currency, payment_method, status, external_transaction_id, paid_at, created_at)
SELECT
o.id as order_id,
o.user_id,
o.total_amount as amount,
o.currency,
CASE
WHEN RAND() < 0.6 THEN 'ALIPAY'
WHEN RAND() < 0.8 THEN 'WECHAT'
ELSE 'PAYPAL'
END as payment_method,
CASE
WHEN o.status = 'COMPLETED' THEN 'COMPLETED'
WHEN o.status = 'CANCELLED' THEN 'CANCELLED'
ELSE 'PENDING'
END as status,
CONCAT('TXN_', UNIX_TIMESTAMP(o.created_at), '_', o.id) as external_transaction_id,
CASE
WHEN o.status = 'COMPLETED' THEN DATE_ADD(o.created_at, INTERVAL FLOOR(RAND() * 30) MINUTE)
ELSE NULL
END as paid_at,
o.created_at
FROM orders o;

View File

@@ -564,3 +564,5 @@

View File

@@ -480,3 +480,5 @@

View File

@@ -519,3 +519,5 @@

13
demo/start-app.bat Normal file
View File

@@ -0,0 +1,13 @@
@echo off
echo Starting Spring Boot application...
echo.
REM 设置JAVA_HOME如果需要
REM set JAVA_HOME=C:\Program Files\Java\jdk-21
REM 启动应用并显示输出
java -jar target/demo-0.0.1-SNAPSHOT.jar --spring.profiles.active=dev
echo.
echo Application stopped.
pause

48
demo/start-backend.ps1 Normal file
View File

@@ -0,0 +1,48 @@
# 启动后端服务脚本
Write-Host "正在启动后端服务..." -ForegroundColor Green
# 检查jar文件是否存在
if (-not (Test-Path "target/demo-0.0.1-SNAPSHOT.jar")) {
Write-Host "错误: jar文件不存在请先编译项目" -ForegroundColor Red
exit 1
}
# 启动服务
Write-Host "启动Spring Boot应用..." -ForegroundColor Yellow
$process = Start-Process -FilePath "java" -ArgumentList "-jar", "target/demo-0.0.1-SNAPSHOT.jar", "--spring.profiles.active=dev" -PassThru -NoNewWindow
Write-Host "服务进程ID: $($process.Id)" -ForegroundColor Cyan
# 等待服务启动
Write-Host "等待服务启动..." -ForegroundColor Yellow
$timeout = 60
$elapsed = 0
while ($elapsed -lt $timeout) {
Start-Sleep -Seconds 2
$elapsed += 2
# 检查端口是否监听
$listening = netstat -an | Select-String ":8080.*LISTENING"
if ($listening) {
Write-Host "✓ 服务已成功启动在端口8080!" -ForegroundColor Green
Write-Host "进程ID: $($process.Id)" -ForegroundColor Cyan
Write-Host "按 Ctrl+C 停止服务" -ForegroundColor Yellow
# 保持服务运行
try {
$process.WaitForExit()
} catch {
Write-Host "服务已停止" -ForegroundColor Red
}
break
}
Write-Host "等待中... $elapsed/$timeout" -ForegroundColor Gray
}
if ($elapsed -ge $timeout) {
Write-Host "✗ 服务启动超时" -ForegroundColor Red
Stop-Process -Id $process.Id -Force
exit 1
}