修复权限验证问题:普通用户无法访问后台管理页面
This commit is contained in:
@@ -319,3 +319,5 @@ ALTER TABLE payments ADD FOREIGN KEY (order_id_ref) REFERENCES orders(id);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -26,3 +26,5 @@ public class PasswordChecker {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -283,3 +283,5 @@ Vue.js 前端项目迁移已经完成,实现了:
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -426,3 +426,5 @@ MIT License
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -22,3 +22,5 @@ console.log('App.vue 加载成功')
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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 }
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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')
|
||||
}
|
||||
@@ -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}`)
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -85,3 +85,5 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -137,7 +137,12 @@ const handleUserCommand = async (command) => {
|
||||
ElMessage.info('个人资料功能开发中')
|
||||
break
|
||||
case 'admin':
|
||||
router.push('/admin/dashboard')
|
||||
// 检查管理员权限
|
||||
if (userStore.isAdmin) {
|
||||
router.push('/admin/dashboard')
|
||||
} else {
|
||||
ElMessage.warning('权限不足,只有管理员才能访问后台管理')
|
||||
}
|
||||
break
|
||||
case 'settings':
|
||||
ElMessage.info('设置功能开发中')
|
||||
|
||||
21
demo/frontend/src/main-backup.js
Normal file
21
demo/frontend/src/main-backup.js
Normal 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')
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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('后台管理页面加载完成')
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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([])
|
||||
|
||||
18
demo/frontend/src/views/ApiManagement.vue
Normal file
18
demo/frontend/src/views/ApiManagement.vue
Normal 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>
|
||||
50
demo/frontend/src/views/BasicTest.vue
Normal file
50
demo/frontend/src/views/BasicTest.vue
Normal 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>
|
||||
629
demo/frontend/src/views/GenerateTaskRecord.vue
Normal file
629
demo/frontend/src/views/GenerateTaskRecord.vue
Normal 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>
|
||||
10
demo/frontend/src/views/HelloWorld.vue
Normal file
10
demo/frontend/src/views/HelloWorld.vue
Normal 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>
|
||||
@@ -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 || '运行中'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -782,3 +782,5 @@ const startGenerate = () => {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -1,6 +1,74 @@
|
||||
<template>
|
||||
<div class="works-page">
|
||||
<div class="toolbar">
|
||||
<!-- 左侧导航栏 -->
|
||||
<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>
|
||||
<el-radio-button label="video">视频</el-radio-button>
|
||||
@@ -8,44 +76,55 @@
|
||||
</el-radio-group>
|
||||
</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">
|
||||
<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-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-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" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="filters-bar">
|
||||
<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-select>
|
||||
<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" placeholder="比例" size="small" style="width: 100px">
|
||||
<el-option label="比例" value="ratio" />
|
||||
<el-option label="时间" value="date" />
|
||||
<el-option label="热门" value="hot" />
|
||||
</el-select>
|
||||
<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>
|
||||
<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>
|
||||
<el-button size="small" type="danger" @click="bulkDelete" plain>删除</el-button>
|
||||
</template>
|
||||
</div>
|
||||
<div class="select-row">
|
||||
<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>
|
||||
<el-button size="small" type="danger" @click="bulkDelete" plain>删除</el-button>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<el-row :gutter="16" class="works-grid">
|
||||
<el-col v-for="item in filteredItems" :key="item.id" :xs="24" :sm="12" :md="8" :lg="6">
|
||||
@@ -223,9 +302,11 @@
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<div class="finished" v-if="!hasMore && filteredItems.length>0">已加载全部内容</div>
|
||||
<el-empty v-if="!loading && filteredItems.length===0" description="没有找到相关内容" />
|
||||
</div>
|
||||
<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;
|
||||
@@ -477,16 +776,30 @@ onMounted(() => {
|
||||
}
|
||||
.filters { margin-left: 10px; }
|
||||
.filters-bar {
|
||||
display:flex;
|
||||
align-items:center;
|
||||
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) {
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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(() => {
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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'
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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>
|
||||
@@ -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 {
|
||||
|
||||
@@ -733,3 +733,5 @@ const startGenerate = () => {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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>
|
||||
@@ -50,146 +50,199 @@
|
||||
<MyWorks />
|
||||
</template>
|
||||
<template v-else>
|
||||
<!-- 顶部 两层合并为一个盒子 -->
|
||||
<section class="top-merged-card">
|
||||
<!-- 上层:用户信息 + 右侧按钮 -->
|
||||
<div class="row-top">
|
||||
<div class="user-left">
|
||||
<div class="avatar-wrap">
|
||||
<div class="avatar-circle">
|
||||
<div class="pause-line"></div>
|
||||
<div class="pause-line second"></div>
|
||||
<!-- 顶部 两层合并为一个盒子 -->
|
||||
<section class="top-merged-card">
|
||||
<!-- 上层:用户信息 + 右侧按钮 -->
|
||||
<div class="row-top">
|
||||
<div class="user-left">
|
||||
<div class="avatar-wrap">
|
||||
<div class="avatar-circle">
|
||||
<div class="pause-line"></div>
|
||||
<div class="pause-line second"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="user-meta">
|
||||
<div class="username">mingzi_FBx7foZYDS7inLQb</div>
|
||||
<div class="user-id">ID 2994509784706419</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="user-meta">
|
||||
<div class="username">mingzi_FBx7foZYDS7inLQb</div>
|
||||
<div class="user-id">ID 2994509784706419</div>
|
||||
<div class="user-right">
|
||||
<div class="points-pill">
|
||||
<div class="star-icon">
|
||||
<el-icon><Star /></el-icon>
|
||||
</div>
|
||||
<span>50</span>
|
||||
</div>
|
||||
<button class="mini-btn" @click="goToOrderDetails">积分详情</button>
|
||||
<button class="mini-btn" @click="goToWorks">我的订单</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="user-right">
|
||||
<div class="points-pill">
|
||||
<el-icon><Plus /></el-icon>
|
||||
<span>50</span>
|
||||
<!-- 下层:三项总结 -->
|
||||
<div class="row-bottom">
|
||||
<div class="summary-item">
|
||||
<div class="summary-label">当前生效权益</div>
|
||||
<div class="summary-value">免费版</div>
|
||||
</div>
|
||||
<button class="mini-btn">积分详情</button>
|
||||
<button class="mini-btn" @click="goToWorks">我的订单</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 下层:三项总结 -->
|
||||
<div class="row-bottom">
|
||||
<div class="summary-item">
|
||||
<div class="summary-label">当前生效权益</div>
|
||||
<div class="summary-value">免费版</div>
|
||||
</div>
|
||||
<div class="divider-v"></div>
|
||||
<div class="summary-item">
|
||||
<div class="summary-label">到期时间</div>
|
||||
<div class="summary-value">永久</div>
|
||||
</div>
|
||||
<div class="divider-v"></div>
|
||||
<div class="summary-item">
|
||||
<div class="summary-label">剩余积分</div>
|
||||
<div class="summary-value highlight">
|
||||
<el-icon class="plus-icon"><Plus /></el-icon>
|
||||
<span class="points-number">50</span>
|
||||
<div class="divider-v"></div>
|
||||
<div class="summary-item">
|
||||
<div class="summary-label">到期时间</div>
|
||||
<div class="summary-value">永久</div>
|
||||
</div>
|
||||
<div class="divider-v"></div>
|
||||
<div class="summary-item">
|
||||
<div class="summary-label">剩余积分</div>
|
||||
<div class="summary-value highlight">
|
||||
<div class="star-icon">
|
||||
<el-icon><Star /></el-icon>
|
||||
</div>
|
||||
<span class="points-number">50</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<!-- 套餐选择 -->
|
||||
<section class="subscription-packages">
|
||||
<h3 class="section-title">套餐</h3>
|
||||
<!-- 套餐选择 -->
|
||||
<section class="subscription-packages">
|
||||
<h3 class="section-title">套餐</h3>
|
||||
|
||||
<div class="packages-grid">
|
||||
<!-- 免费版 -->
|
||||
<div class="package-card free-card" :class="{ selected: selectedPlan === 'free' }" @click="selectPlan('free')">
|
||||
<div class="package-header">
|
||||
<h4 class="package-title">免费版</h4>
|
||||
<div class="packages-grid">
|
||||
<!-- 免费版 -->
|
||||
<div class="package-card free-card" :class="{ selected: selectedPlan === 'free' }" @click="selectPlan('free')">
|
||||
<div class="package-header">
|
||||
<h4 class="package-title">免费版</h4>
|
||||
</div>
|
||||
<div class="package-price">$0/月</div>
|
||||
<button class="package-button current">当前套餐</button>
|
||||
<div class="package-features">
|
||||
<div class="feature-item">
|
||||
<el-icon class="check-icon"><Check /></el-icon>
|
||||
<span>新用户首次登陆免费获得50积分</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="package-price">¥0/月</div>
|
||||
<button class="package-button current">当前套餐</button>
|
||||
<div class="package-features">
|
||||
<div class="feature-item">
|
||||
<el-icon class="check-icon"><Check /></el-icon>
|
||||
<span>新用户首次登陆免费获得50积分</span>
|
||||
|
||||
<!-- 标准版 -->
|
||||
<div class="package-card standard-card" :class="{ selected: selectedPlan === 'standard' }" @click="selectPlan('standard')">
|
||||
<div class="package-header">
|
||||
<h4 class="package-title">标准版</h4>
|
||||
<div class="discount-tag">首购低至8.5折</div>
|
||||
</div>
|
||||
<div class="package-price">$59/月</div>
|
||||
<div class="points-box">每月200积分</div>
|
||||
<button class="package-button subscribe">立即订阅</button>
|
||||
<div class="package-features">
|
||||
<div class="feature-item">
|
||||
<el-icon class="check-icon"><Check /></el-icon>
|
||||
<span>快速通道生成</span>
|
||||
</div>
|
||||
<div class="feature-item">
|
||||
<el-icon class="check-icon"><Check /></el-icon>
|
||||
<span>支持商用</span>
|
||||
</div>
|
||||
<div class="feature-item">
|
||||
<el-icon class="check-icon"><Check /></el-icon>
|
||||
<span>下载去水印</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 专业版 -->
|
||||
<div class="package-card premium-card" :class="{ selected: selectedPlan === 'premium' }" @click="selectPlan('premium')">
|
||||
<div class="package-header">
|
||||
<h4 class="package-title">专业版</h4>
|
||||
<div class="value-tag">超值之选</div>
|
||||
</div>
|
||||
<div class="package-price">$259/月</div>
|
||||
<div class="points-box">每月1000积分</div>
|
||||
<button class="package-button premium">立即订阅</button>
|
||||
<div class="package-features">
|
||||
<div class="feature-item">
|
||||
<el-icon class="check-icon"><Check /></el-icon>
|
||||
<span>极速通道生成</span>
|
||||
</div>
|
||||
<div class="feature-item">
|
||||
<el-icon class="check-icon"><Check /></el-icon>
|
||||
<span>支持商用</span>
|
||||
</div>
|
||||
<div class="feature-item">
|
||||
<el-icon class="check-icon"><Check /></el-icon>
|
||||
<span>下载去水印</span>
|
||||
</div>
|
||||
<div class="feature-item">
|
||||
<el-icon class="check-icon"><Check /></el-icon>
|
||||
<span>新功能优先体验</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 标准版 -->
|
||||
<div class="package-card standard-card" :class="{ selected: selectedPlan === 'standard' }" @click="selectPlan('standard')">
|
||||
<div class="package-header">
|
||||
<h4 class="package-title">标准版</h4>
|
||||
<div class="discount-tag">首购低至8.5折</div>
|
||||
</div>
|
||||
<div class="package-price">$59/月</div>
|
||||
<div class="points-box">每月200积分</div>
|
||||
<button class="package-button subscribe">立即订阅</button>
|
||||
<div class="package-features">
|
||||
<div class="feature-item">
|
||||
<el-icon class="check-icon"><Check /></el-icon>
|
||||
<span>快速通道生成</span>
|
||||
</div>
|
||||
<div class="feature-item">
|
||||
<el-icon class="check-icon"><Check /></el-icon>
|
||||
<span>支持商用</span>
|
||||
</div>
|
||||
<div class="feature-item">
|
||||
<el-icon class="check-icon"><Check /></el-icon>
|
||||
<span>下载去水印</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 专业版 -->
|
||||
<div class="package-card premium-card" :class="{ selected: selectedPlan === 'premium' }" @click="selectPlan('premium')">
|
||||
<div class="package-header">
|
||||
<h4 class="package-title">专业版</h4>
|
||||
<div class="value-tag">超值之选</div>
|
||||
</div>
|
||||
<div class="package-price">$259/月</div>
|
||||
<div class="points-box">每月1000积分</div>
|
||||
<button class="package-button premium">立即订阅</button>
|
||||
<div class="package-features">
|
||||
<div class="feature-item">
|
||||
<el-icon class="check-icon"><Check /></el-icon>
|
||||
<span>极速通道生成</span>
|
||||
</div>
|
||||
<div class="feature-item">
|
||||
<el-icon class="check-icon"><Check /></el-icon>
|
||||
<span>支持商用</span>
|
||||
</div>
|
||||
<div class="feature-item">
|
||||
<el-icon class="check-icon"><Check /></el-icon>
|
||||
<span>下载去水印</span>
|
||||
</div>
|
||||
<div class="feature-item">
|
||||
<el-icon class="check-icon"><Check /></el-icon>
|
||||
<span>新功能优先体验</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
</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>
|
||||
|
||||
788
demo/frontend/src/views/SystemSettings.vue
Normal file
788
demo/frontend/src/views/SystemSettings.vue
Normal 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>
|
||||
24
demo/frontend/src/views/TestPage.vue
Normal file
24
demo/frontend/src/views/TestPage.vue
Normal 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>
|
||||
@@ -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 {
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -6,7 +6,8 @@ public enum OrderType {
|
||||
SUBSCRIPTION("订阅订单"),
|
||||
DIGITAL("数字商品"),
|
||||
PHYSICAL("实体商品"),
|
||||
PAYMENT("支付订单");
|
||||
PAYMENT("支付订单"),
|
||||
MEMBERSHIP("会员订单");
|
||||
|
||||
private final String displayName;
|
||||
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -28,3 +28,5 @@ public class PlainTextPasswordEncoder implements PasswordEncoder {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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', '西安市雁塔区'),
|
||||
|
||||
25
demo/src/main/resources/order_items_fixed.sql
Normal file
25
demo/src/main/resources/order_items_fixed.sql
Normal 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;
|
||||
265
demo/src/main/resources/orders_12months_fixed.sql
Normal file
265
demo/src/main/resources/orders_12months_fixed.sql
Normal 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');
|
||||
270
demo/src/main/resources/orders_12months_new.sql
Normal file
270
demo/src/main/resources/orders_12months_new.sql
Normal 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');
|
||||
24
demo/src/main/resources/payments_fixed.sql
Normal file
24
demo/src/main/resources/payments_fixed.sql
Normal 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;
|
||||
@@ -564,3 +564,5 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -480,3 +480,5 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -519,3 +519,5 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
13
demo/start-app.bat
Normal file
13
demo/start-app.bat
Normal 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
48
demo/start-backend.ps1
Normal 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
|
||||
}
|
||||
Reference in New Issue
Block a user