feat: add initial styling and layout for portal views

- Created a global CSS file for consistent styling across the application.
- Implemented the Explore, Home, Topics, and various user views with responsive design.
- Added a Login view with OTP functionality and a Checkout view for order processing.
- Developed a NotFound view for handling 404 errors.
- Established a configuration file for Vite with Tailwind CSS integration.
This commit is contained in:
2025-12-26 09:18:41 +08:00
parent a4262b4a52
commit bcbd3327ea
40 changed files with 3795 additions and 0 deletions

24
frontend/portal/.gitignore vendored Normal file
View File

@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

View File

@@ -0,0 +1,5 @@
# Vue 3 + Vite
This template should help get you started developing with Vue 3 in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
Learn more about IDE Support for Vue in the [Vue Docs Scaling up Guide](https://vuejs.org/guide/scaling-up/tooling.html#ide-support).

View File

@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>portal</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>

2580
frontend/portal/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,27 @@
{
"name": "portal",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"@primevue/themes": "^4.5.4",
"@tailwindcss/vite": "^4.1.18",
"pinia": "^3.0.4",
"primeicons": "^7.0.0",
"primevue": "^4.5.4",
"sass": "^1.97.1",
"tailwindcss": "^4.1.18",
"tailwindcss-animate": "^1.0.7",
"vue": "^3.5.24",
"vue-router": "^4.6.4"
},
"devDependencies": {
"@vitejs/plugin-vue": "^6.0.1",
"vite": "^7.2.4"
}
}

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -0,0 +1,3 @@
<template>
<router-view />
</template>

View File

@@ -0,0 +1,30 @@
@import "tailwindcss";
@plugin "tailwindcss-animate";
:root {
--color-primary-50: #eff6ff;
--color-primary-100: #dbeafe;
--color-primary-200: #bfdbfe;
--color-primary-300: #93c5fd;
--color-primary-400: #60a5fa;
--color-primary-500: #3b82f6;
--color-primary-600: #2563eb;
--color-primary-700: #1d4ed8;
--color-primary-800: #1e40af;
--color-primary-900: #1e3a8a;
--color-primary-950: #172554;
}
@theme {
--color-primary-50: var(--color-primary-50);
--color-primary-100: var(--color-primary-100);
--color-primary-200: var(--color-primary-200);
--color-primary-300: var(--color-primary-300);
--color-primary-400: var(--color-primary-400);
--color-primary-500: var(--color-primary-500);
--color-primary-600: var(--color-primary-600);
--color-primary-700: var(--color-primary-700);
--color-primary-800: var(--color-primary-800);
--color-primary-900: var(--color-primary-900);
--color-primary-950: var(--color-primary-950);
}

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>

After

Width:  |  Height:  |  Size: 496 B

View File

@@ -0,0 +1,57 @@
<template>
<footer class="bg-slate-900 text-slate-400 mt-auto">
<div class="mx-auto max-w-screen-xl px-4 sm:px-6 lg:px-8 py-12">
<div class="grid grid-cols-1 md:grid-cols-4 gap-8">
<!-- Brand -->
<div class="col-span-1">
<div class="flex items-center gap-2 mb-4">
<div class="w-8 h-8 bg-white/10 rounded-lg flex items-center justify-center text-white font-bold text-xl">Q</div>
<span class="text-xl font-bold text-white">Quyun</span>
</div>
<p class="text-sm leading-relaxed mb-6">专业的租户管理与内容交付平台连接创作者与用户探索内容的无限可能</p>
<div class="flex gap-4">
<a href="#" class="w-8 h-8 rounded-full bg-white/5 flex items-center justify-center hover:bg-white/20 hover:text-white transition-all"><i class="pi pi-twitter"></i></a>
<a href="#" class="w-8 h-8 rounded-full bg-white/5 flex items-center justify-center hover:bg-white/20 hover:text-white transition-all"><i class="pi pi-github"></i></a>
<a href="#" class="w-8 h-8 rounded-full bg-white/5 flex items-center justify-center hover:bg-white/20 hover:text-white transition-all"><i class="pi pi-discord"></i></a>
</div>
</div>
<!-- Links -->
<div>
<h3 class="text-white font-bold mb-4">关于我们</h3>
<ul class="space-y-3 text-sm">
<li><a href="#" class="hover:text-white transition-colors">平台介绍</a></li>
<li><a href="#" class="hover:text-white transition-colors">加入我们</a></li>
<li><a href="#" class="hover:text-white transition-colors">联系方式</a></li>
<li><a href="#" class="hover:text-white transition-colors">合作伙伴</a></li>
</ul>
</div>
<div>
<h3 class="text-white font-bold mb-4">帮助中心</h3>
<ul class="space-y-3 text-sm">
<li><a href="#" class="hover:text-white transition-colors">用户指南</a></li>
<li><a href="#" class="hover:text-white transition-colors">创作者手册</a></li>
<li><a href="#" class="hover:text-white transition-colors">常见问题</a></li>
<li><a href="#" class="hover:text-white transition-colors">反馈建议</a></li>
</ul>
</div>
<div>
<h3 class="text-white font-bold mb-4">法律条款</h3>
<ul class="space-y-3 text-sm">
<li><a href="#" class="hover:text-white transition-colors">用户协议</a></li>
<li><a href="#" class="hover:text-white transition-colors">隐私政策</a></li>
<li><a href="#" class="hover:text-white transition-colors">知识产权</a></li>
<li><a href="#" class="hover:text-white transition-colors">社区规范</a></li>
</ul>
</div>
</div>
<div class="border-t border-slate-800 mt-12 pt-8 flex flex-col md:flex-row justify-between items-center text-xs">
<p>© 2025 Quyun Platform. All rights reserved.</p>
<p class="mt-2 md:mt-0">ICP 88888888 -1 | 公安网备 11010102000000 </p>
</div>
</div>
</footer>
</template>

View File

@@ -0,0 +1,43 @@
<script setup>
import { ref } from 'vue'
defineProps({
msg: String,
})
const count = ref(0)
</script>
<template>
<h1>{{ msg }}</h1>
<div class="card">
<button type="button" @click="count++">count is {{ count }}</button>
<p>
Edit
<code>components/HelloWorld.vue</code> to test HMR
</p>
</div>
<p>
Check out
<a href="https://vuejs.org/guide/quick-start.html#local" target="_blank"
>create-vue</a
>, the official Vue + Vite starter
</p>
<p>
Learn more about IDE Support for Vue in the
<a
href="https://vuejs.org/guide/scaling-up/tooling.html#ide-support"
target="_blank"
>Vue Docs Scaling up Guide</a
>.
</p>
<p class="read-the-docs">Click on the Vite and Vue logos to learn more</p>
</template>
<style scoped>
.read-the-docs {
color: #888;
}
</style>

View File

@@ -0,0 +1,88 @@
<template>
<nav class="fixed top-0 w-full z-50 bg-white border-b border-slate-200 h-16">
<div class="mx-auto max-w-screen-xl px-4 sm:px-6 lg:px-8 h-full flex items-center justify-between">
<!-- Left: Logo -->
<router-link to="/" class="flex items-center gap-2">
<div class="w-8 h-8 bg-primary-600 rounded-lg flex items-center justify-center text-white font-bold text-xl">Q</div>
<span class="text-xl font-bold text-slate-900 hidden sm:block">Quyun</span>
</router-link>
<!-- Center-Left: Nav Links (Desktop) -->
<div class="hidden md:flex items-center space-x-8">
<router-link to="/" class="text-slate-600 font-medium hover:text-primary-600" active-class="text-primary-600">首页</router-link>
<router-link to="/explore" class="text-slate-600 font-medium hover:text-primary-600" active-class="text-primary-600">发现</router-link>
<router-link to="/topics" class="text-slate-600 font-medium hover:text-primary-600" active-class="text-primary-600">专题</router-link>
</div>
<!-- Center-Right: Global Search -->
<div class="hidden sm:flex flex-1 max-w-md mx-8">
<div class="relative w-full">
<i class="pi pi-search absolute left-3 top-1/2 -translate-y-1/2 text-slate-400"></i>
<input
type="text"
placeholder="搜索感兴趣的内容..."
class="w-full h-10 pl-10 pr-4 rounded-full bg-slate-100 border-none focus:bg-white focus:ring-2 focus:ring-primary-100 text-sm transition-all"
>
</div>
</div>
<!-- Right: User Actions -->
<div class="flex items-center gap-4">
<template v-if="isLoggedIn">
<!-- Notification -->
<router-link to="/me/notifications" class="relative w-10 h-10 flex items-center justify-center rounded-full hover:bg-slate-50 text-slate-600">
<i class="pi pi-bell text-xl"></i>
<span class="absolute top-2 right-2 w-2 h-2 bg-red-500 rounded-full border border-white"></span>
</router-link>
<!-- Creator Entry -->
<router-link to="/creator/apply" class="hidden sm:flex items-center gap-1 px-3 py-1.5 text-sm font-medium text-slate-600 hover:bg-slate-50 rounded-lg border border-slate-200">
<i class="pi pi-pencil"></i>
<span>创作</span>
</router-link>
<!-- Avatar Dropdown -->
<div class="relative group">
<button class="w-9 h-9 rounded-full overflow-hidden border border-slate-200 focus:ring-2 ring-primary-100">
<img src="https://api.dicebear.com/7.x/avataaars/svg?seed=Felix" alt="User" class="w-full h-full object-cover">
</button>
<!-- Dropdown Menu (Mock) -->
<div class="absolute right-0 top-full mt-2 w-48 bg-white rounded-xl shadow-lg border border-slate-100 py-1 hidden group-hover:block">
<div class="px-4 py-3 border-b border-slate-50">
<p class="text-sm font-bold text-slate-900">Felix Demo</p>
<p class="text-xs text-slate-500 truncate">felix@example.com</p>
</div>
<router-link to="/me" class="block px-4 py-2 text-sm text-slate-700 hover:bg-slate-50">个人中心</router-link>
<router-link to="/creator" class="block px-4 py-2 text-sm text-slate-700 hover:bg-slate-50">创作者中心</router-link>
<div class="border-t border-slate-50 mt-1"></div>
<button @click="logout" class="block w-full text-left px-4 py-2 text-sm text-red-600 hover:bg-red-50">退出登录</button>
</div>
</div>
</template>
<template v-else>
<router-link to="/auth/login" class="text-slate-600 font-medium hover:text-primary-600 px-3 py-2">登录</router-link>
<router-link to="/auth/login" class="bg-primary-600 text-white px-5 py-2 rounded-full font-medium hover:bg-primary-700 transition-colors">注册</router-link>
</template>
<!-- Mobile Menu Button -->
<button class="md:hidden w-10 h-10 flex items-center justify-center text-slate-600">
<i class="pi pi-bars text-xl"></i>
</button>
</div>
</div>
</nav>
</template>
<script setup>
import { ref } from 'vue';
import { useRouter } from 'vue-router';
const isLoggedIn = ref(true); // Mock login state
const router = useRouter();
const logout = () => {
isLoggedIn.value = false;
router.push('/');
};
</script>

View File

@@ -0,0 +1,5 @@
<template>
<div class="min-h-screen bg-slate-50 flex items-center justify-center p-4">
<router-view />
</div>
</template>

View File

@@ -0,0 +1,14 @@
<template>
<div class="min-h-screen flex flex-col bg-slate-50">
<TopNavbar />
<main class="flex-grow pt-16">
<router-view />
</main>
<AppFooter />
</div>
</template>
<script setup>
import TopNavbar from '../components/TopNavbar.vue';
import AppFooter from '../components/AppFooter.vue';
</script>

View File

@@ -0,0 +1,68 @@
<template>
<div class="min-h-screen flex flex-col bg-slate-50">
<TopNavbar />
<main class="flex-grow pt-16">
<div class="mx-auto max-w-screen-xl px-4 sm:px-6 lg:px-8 py-8 flex gap-8">
<!-- Sidebar -->
<aside class="w-[280px] flex-shrink-0 hidden lg:block">
<div class="bg-white rounded-2xl shadow-sm border border-slate-100 overflow-hidden sticky top-24">
<!-- User Brief -->
<div class="p-6 border-b border-slate-100 bg-slate-50/50">
<div class="flex items-center gap-4">
<img src="https://api.dicebear.com/7.x/avataaars/svg?seed=Felix" class="w-12 h-12 rounded-full border-2 border-white shadow-sm" />
<div class="overflow-hidden">
<div class="font-bold text-slate-900 truncate">Felix Demo</div>
<div class="text-xs text-slate-500">ID: 9527330</div>
</div>
</div>
</div>
<!-- Menus -->
<nav class="p-4 space-y-1">
<router-link to="/me" exact-active-class="bg-primary-50 text-primary-600 font-semibold" class="flex items-center gap-3 px-4 py-3 rounded-lg text-slate-600 hover:bg-slate-50 transition-colors">
<i class="pi pi-home text-lg"></i>
<span>概览</span>
</router-link>
<router-link to="/me/orders" active-class="bg-primary-50 text-primary-600 font-semibold" class="flex items-center gap-3 px-4 py-3 rounded-lg text-slate-600 hover:bg-slate-50 transition-colors">
<i class="pi pi-shopping-bag text-lg"></i>
<span>我的订单</span>
</router-link>
<router-link to="/me/wallet" active-class="bg-primary-50 text-primary-600 font-semibold" class="flex items-center gap-3 px-4 py-3 rounded-lg text-slate-600 hover:bg-slate-50 transition-colors">
<i class="pi pi-wallet text-lg"></i>
<span>我的钱包</span>
</router-link>
<router-link to="/me/library" active-class="bg-primary-50 text-primary-600 font-semibold" class="flex items-center gap-3 px-4 py-3 rounded-lg text-slate-600 hover:bg-slate-50 transition-colors">
<i class="pi pi-book text-lg"></i>
<span>已购内容</span>
</router-link>
<router-link to="/me/notifications" active-class="bg-primary-50 text-primary-600 font-semibold" class="flex items-center gap-3 px-4 py-3 rounded-lg text-slate-600 hover:bg-slate-50 transition-colors">
<i class="pi pi-bell text-lg"></i>
<span>消息中心</span>
</router-link>
<div class="my-2 border-t border-slate-100"></div>
<router-link to="/me/profile" active-class="bg-primary-50 text-primary-600 font-semibold" class="flex items-center gap-3 px-4 py-3 rounded-lg text-slate-600 hover:bg-slate-50 transition-colors">
<i class="pi pi-user text-lg"></i>
<span>个人资料</span>
</router-link>
<router-link to="/me/security" active-class="bg-primary-50 text-primary-600 font-semibold" class="flex items-center gap-3 px-4 py-3 rounded-lg text-slate-600 hover:bg-slate-50 transition-colors">
<i class="pi pi-shield text-lg"></i>
<span>账号安全</span>
</router-link>
</nav>
</div>
</aside>
<!-- Main Content -->
<div class="flex-grow min-w-0">
<router-view />
</div>
</div>
</main>
<AppFooter />
</div>
</template>
<script setup>
import TopNavbar from '../components/TopNavbar.vue';
import AppFooter from '../components/AppFooter.vue';
</script>

View File

@@ -0,0 +1,26 @@
import { createApp } from 'vue';
import { createPinia } from 'pinia';
import PrimeVue from 'primevue/config';
import Aura from '@primevue/themes/aura';
import App from './App.vue';
import router from './router';
import './assets/main.css';
import 'primeicons/primeicons.css';
const app = createApp(App);
app.use(createPinia());
app.use(router);
app.use(PrimeVue, {
theme: {
preset: Aura,
options: {
prefix: 'p',
darkModeSelector: '.my-app-dark',
cssLayer: false
}
}
});
app.mount('#app');

View File

@@ -0,0 +1,161 @@
import { createRouter, createWebHistory } from 'vue-router'
import LayoutMain from '../layout/LayoutMain.vue'
import LayoutAuth from '../layout/LayoutAuth.vue'
import LayoutUser from '../layout/LayoutUser.vue'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
component: LayoutMain,
children: [
{
path: '',
name: 'home',
component: () => import('../views/HomeView.vue')
},
{
path: 'contents/:id',
name: 'content-detail',
component: () => import('../views/content/DetailView.vue')
},
{
path: 't/:id',
name: 'tenant-home',
component: () => import('../views/tenant/HomeView.vue')
},
{
path: 'explore',
name: 'explore',
component: () => import('../views/ExploreView.vue') // Placeholder
},
{
path: 'topics',
name: 'topics',
component: () => import('../views/TopicsView.vue') // Placeholder
},
{
path: 'creator/apply',
name: 'creator-apply',
component: () => import('../views/creator/ApplyView.vue')
}
]
},
{
path: '/auth',
component: LayoutAuth,
children: [
{
path: 'login',
name: 'login',
component: () => import('../views/auth/LoginView.vue')
}
]
},
{
path: '/me',
component: LayoutUser,
children: [
{
path: '',
name: 'user-dashboard',
component: () => import('../views/user/DashboardView.vue')
},
{
path: 'orders',
name: 'user-orders',
component: () => import('../views/user/OrdersView.vue') // Placeholder
},
{
path: 'wallet',
name: 'user-wallet',
component: () => import('../views/user/WalletView.vue') // Placeholder
},
{
path: 'library',
name: 'user-library',
component: () => import('../views/user/LibraryView.vue') // Placeholder
},
{
path: 'notifications',
name: 'user-notifications',
component: () => import('../views/user/NotificationsView.vue') // Placeholder
},
{
path: 'profile',
name: 'user-profile',
component: () => import('../views/user/ProfileView.vue') // Placeholder
},
{
path: 'security',
name: 'user-security',
component: () => import('../views/user/SecurityView.vue') // Placeholder
}
]
},
{
path: '/creator',
component: LayoutUser, // Initially use LayoutUser, later maybe specialized LayoutCreator
children: [
{
path: '',
name: 'creator-dashboard',
component: () => import('../views/creator/DashboardView.vue')
},
{
path: 'contents',
name: 'creator-contents',
component: () => import('../views/creator/ContentsView.vue')
},
{
path: 'orders',
name: 'creator-orders',
component: () => import('../views/creator/OrdersView.vue')
},
{
path: 'settings',
name: 'creator-settings',
component: () => import('../views/creator/SettingsView.vue')
}
]
},
{
path: '/checkout',
component: LayoutMain, // Or a simplified checkout layout
children: [
{
path: '',
name: 'checkout',
component: () => import('../views/order/CheckoutView.vue')
}
]
},
{
path: '/payment/:id',
component: LayoutMain,
children: [
{
path: '',
name: 'payment',
component: () => import('../views/order/PaymentView.vue')
}
]
},
// Fallback
{
path: '/:pathMatch(.*)*',
name: 'not-found',
component: () => import('../views/misc/NotFoundView.vue')
}
],
scrollBehavior(to, from, savedPosition) {
if (savedPosition) {
return savedPosition
} else {
return { top: 0 }
}
}
})
export default router

View File

@@ -0,0 +1,79 @@
:root {
font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
line-height: 1.5;
font-weight: 400;
color-scheme: light dark;
color: rgba(255, 255, 255, 0.87);
background-color: #242424;
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
a {
font-weight: 500;
color: #646cff;
text-decoration: inherit;
}
a:hover {
color: #535bf2;
}
body {
margin: 0;
display: flex;
place-items: center;
min-width: 320px;
min-height: 100vh;
}
h1 {
font-size: 3.2em;
line-height: 1.1;
}
button {
border-radius: 8px;
border: 1px solid transparent;
padding: 0.6em 1.2em;
font-size: 1em;
font-weight: 500;
font-family: inherit;
background-color: #1a1a1a;
cursor: pointer;
transition: border-color 0.25s;
}
button:hover {
border-color: #646cff;
}
button:focus,
button:focus-visible {
outline: 4px auto -webkit-focus-ring-color;
}
.card {
padding: 2em;
}
#app {
max-width: 1280px;
margin: 0 auto;
padding: 2rem;
text-align: center;
}
@media (prefers-color-scheme: light) {
:root {
color: #213547;
background-color: #ffffff;
}
a:hover {
color: #747bff;
}
button {
background-color: #f9f9f9;
}
}

View File

@@ -0,0 +1,6 @@
<template>
<div class="mx-auto max-w-screen-xl my-8 p-8 bg-white rounded-xl shadow-sm">
<h1 class="text-2xl font-bold mb-4">Explore</h1>
<p class="text-slate-400">(Explore content)</p>
</div>
</template>

View File

@@ -0,0 +1,224 @@
<template>
<div class="mx-auto max-w-screen-xl px-4 sm:px-6 lg:px-8 py-8">
<!-- Hero Banner -->
<div class="relative w-full h-[400px] rounded-2xl overflow-hidden bg-slate-900 mb-8 group">
<!-- Mock Carousel Image -->
<img src="https://images.unsplash.com/photo-1514306191717-452ec28c7f31?ixlib=rb-1.2.1&auto=format&fit=crop&w=1950&q=80" class="w-full h-full object-cover opacity-80 transition-transform duration-700 group-hover:scale-105" alt="Banner">
<div class="absolute inset-0 bg-gradient-to-t from-black/80 via-transparent to-transparent"></div>
<div class="absolute bottom-0 left-0 p-10 max-w-2xl text-white">
<div class="inline-block px-3 py-1 bg-red-600 text-white text-xs font-bold rounded mb-3">置顶推荐</div>
<h2 class="text-4xl font-bold mb-4 leading-tight">京剧霸王别姬全本实录程派艺术的巅峰演绎</h2>
<p class="text-lg text-slate-200 line-clamp-2">梅兰芳大师经典之作高清修复版独家上线感受国粹魅力重温梨园风华</p>
</div>
<!-- Arrows (Always visible as per spec) -->
<button class="absolute left-4 top-1/2 -translate-y-1/2 w-12 h-12 bg-black/30 hover:bg-black/50 text-white rounded-full flex items-center justify-center backdrop-blur-sm transition-all"><i class="pi pi-chevron-left text-xl"></i></button>
<button class="absolute right-4 top-1/2 -translate-y-1/2 w-12 h-12 bg-black/30 hover:bg-black/50 text-white rounded-full flex items-center justify-center backdrop-blur-sm transition-all"><i class="pi pi-chevron-right text-xl"></i></button>
<!-- Indicators -->
<div class="absolute bottom-4 left-1/2 -translate-x-1/2 flex gap-2">
<span class="w-2 h-2 rounded-full bg-white"></span>
<span class="w-2 h-2 rounded-full bg-white/50"></span>
<span class="w-2 h-2 rounded-full bg-white/50"></span>
</div>
</div>
<!-- Filter Bar -->
<div class="mb-8">
<div class="flex items-center gap-8 border-b border-slate-200 pb-4 mb-4">
<button class="text-lg font-bold text-primary-600 border-b-2 border-primary-600 -mb-4.5 pb-4 px-2">推荐</button>
<button class="text-lg font-medium text-slate-500 hover:text-slate-800 -mb-4.5 pb-4 px-2 transition-colors">最新</button>
<button class="text-lg font-medium text-slate-500 hover:text-slate-800 -mb-4.5 pb-4 px-2 transition-colors">热门</button>
</div>
<!-- Tags -->
<div class="flex flex-wrap gap-3">
<button class="px-4 py-1.5 rounded-full bg-slate-900 text-white text-sm font-medium">全部</button>
<button class="px-4 py-1.5 rounded-full bg-slate-100 text-slate-600 hover:bg-slate-200 text-sm font-medium transition-colors">京剧</button>
<button class="px-4 py-1.5 rounded-full bg-slate-100 text-slate-600 hover:bg-slate-200 text-sm font-medium transition-colors">昆曲</button>
<button class="px-4 py-1.5 rounded-full bg-slate-100 text-slate-600 hover:bg-slate-200 text-sm font-medium transition-colors">越剧</button>
<button class="px-4 py-1.5 rounded-full bg-slate-100 text-slate-600 hover:bg-slate-200 text-sm font-medium transition-colors">名家名段</button>
<button class="px-4 py-1.5 rounded-full bg-slate-100 text-slate-600 hover:bg-slate-200 text-sm font-medium transition-colors">戏曲教学</button>
</div>
</div>
<!-- Main Layout: Grid 9:3 -->
<div class="grid grid-cols-12 gap-8">
<!-- Main Feed (Left 9) -->
<div class="col-span-12 lg:col-span-8 xl:col-span-9 space-y-6">
<!-- Card Variant 1: Single Image (Right) -->
<router-link to="/contents/1" class="block bg-white rounded-xl shadow-sm border border-slate-100 p-5 hover:shadow-md transition-shadow group">
<div class="flex gap-6">
<div class="flex-1 min-w-0">
<div class="flex items-center gap-2 mb-2">
<span class="px-1.5 py-0.5 rounded text-xs font-medium bg-red-50 text-red-600 border border-red-100">置顶</span>
<span class="text-xs text-slate-500 border border-slate-200 px-1 rounded">[京剧]</span>
</div>
<h3 class="text-lg font-bold text-slate-900 mb-2 leading-snug group-hover:text-primary-600 transition-colors">锁麟囊选段春秋亭外风雨暴 (张火丁亲授版)</h3>
<p class="text-base text-slate-500 line-clamp-2 mb-4 leading-relaxed">张火丁教授亲自讲解程派发音技巧深度剖析锁麟囊中春秋亭一折的唱腔设计与情感表达包含完整示范与逐句拆解</p>
<div class="flex items-center justify-between">
<div class="flex items-center gap-3 text-sm text-slate-500">
<img src="https://api.dicebear.com/7.x/avataaars/svg?seed=Zhang" class="w-6 h-6 rounded-full">
<span>张火丁工作室</span>
<span class="w-1 h-1 bg-slate-300 rounded-full"></span>
<span>行当青衣</span>
<span class="w-1 h-1 bg-slate-300 rounded-full"></span>
<span>2小时前</span>
</div>
<div class="flex items-center gap-4">
<span class="text-sm text-slate-400"><i class="pi pi-eye mr-1"></i> 1.2</span>
<span class="text-lg font-bold text-red-600">¥ 9.90</span>
</div>
</div>
</div>
<div class="w-[240px] h-[135px] flex-shrink-0 rounded-lg overflow-hidden relative bg-slate-100 hidden sm:block">
<img src="https://images.unsplash.com/photo-1576014131795-d44019d02374?ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=60" class="w-full h-full object-cover">
<div class="absolute inset-0 bg-black/20 flex items-center justify-center">
<i class="pi pi-play-circle text-4xl text-white opacity-80"></i>
</div>
<span class="absolute bottom-2 right-2 px-1.5 py-0.5 bg-black/60 text-white text-xs rounded">15:30</span>
</div>
</div>
</router-link>
<!-- Card Variant 2: No Image (Text Only) -->
<div class="bg-white rounded-xl shadow-sm border border-slate-100 p-5 hover:shadow-md transition-shadow group">
<div class="flex items-center gap-2 mb-2">
<span class="px-1.5 py-0.5 rounded text-xs font-medium bg-green-50 text-green-600 border border-green-100">限免</span>
<span class="text-xs text-slate-500 border border-slate-200 px-1 rounded">[昆曲]</span>
</div>
<h3 class="text-lg font-bold text-slate-900 mb-3 group-hover:text-primary-600 transition-colors">浅谈昆曲牡丹亭中的水磨腔艺术特点</h3>
<p class="text-base text-slate-500 line-clamp-3 mb-4 leading-relaxed">昆曲之所以被称为百戏之祖其细腻婉转的水磨腔功不可没本文将从发音吐字行腔三个维度带您领略昆曲的声韵之美对于初学者来说掌握字头字腹字尾的处理是关键...</p>
<div class="flex items-center justify-between">
<div class="flex items-center gap-3 text-sm text-slate-500">
<img src="https://api.dicebear.com/7.x/avataaars/svg?seed=Li" class="w-6 h-6 rounded-full">
<span>梨园小生</span>
<span class="w-1 h-1 bg-slate-300 rounded-full"></span>
<span>昨天</span>
</div>
<div class="flex items-center gap-2">
<span class="text-xs text-slate-400 line-through">¥ 5.00</span>
<span class="text-sm font-bold text-green-600 border border-green-200 px-2 py-0.5 rounded">限时免费</span>
</div>
</div>
</div>
<!-- Card Variant 3: 3 Images -->
<div class="bg-white rounded-xl shadow-sm border border-slate-100 p-5 hover:shadow-md transition-shadow group">
<h3 class="text-lg font-bold text-slate-900 mb-3 group-hover:text-primary-600 transition-colors">[图集] 2024 新年京剧晚会后台探班名角云集</h3>
<div class="grid grid-cols-3 gap-2 mb-4">
<div class="aspect-[4/3] rounded-lg overflow-hidden bg-slate-100">
<img src="https://images.unsplash.com/photo-1469571486292-0ba58a3f068b?ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=60" class="w-full h-full object-cover hover:scale-105 transition-transform duration-500">
</div>
<div class="aspect-[4/3] rounded-lg overflow-hidden bg-slate-100">
<img src="https://images.unsplash.com/photo-1533174072545-e8d4aa97edf9?ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=60" class="w-full h-full object-cover hover:scale-105 transition-transform duration-500">
</div>
<div class="aspect-[4/3] rounded-lg overflow-hidden bg-slate-100 relative">
<img src="https://images.unsplash.com/photo-1516450360452-9312f5e86fc7?ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=60" class="w-full h-full object-cover hover:scale-105 transition-transform duration-500">
<div class="absolute bottom-2 right-2 px-1.5 py-0.5 bg-black/60 text-white text-xs rounded">+9</div>
</div>
</div>
<div class="flex items-center justify-between">
<div class="flex items-center gap-3 text-sm text-slate-500">
<img src="https://api.dicebear.com/7.x/avataaars/svg?seed=Photo" class="w-6 h-6 rounded-full">
<span>戏曲摄影师老王</span>
<span class="w-1 h-1 bg-slate-300 rounded-full"></span>
<span>3天前</span>
</div>
<span class="text-sm text-slate-400"><i class="pi pi-eye mr-1"></i> 8.5k</span>
</div>
</div>
<!-- Load More -->
<div class="pt-4 text-center">
<button class="px-8 py-3 bg-white border border-slate-200 rounded-full text-slate-600 hover:bg-slate-50 hover:text-primary-600 font-medium transition-all shadow-sm">
点击加载更多内容
</button>
</div>
</div>
<!-- Sidebar (Right 3) -->
<div class="hidden lg:block lg:col-span-4 xl:col-span-3 space-y-6">
<!-- Announcement -->
<div class="bg-white rounded-xl shadow-sm border border-slate-100 p-5">
<h3 class="font-bold text-slate-900 mb-4 flex items-center gap-2">
<i class="pi pi-megaphone text-orange-500"></i> 公告
</h3>
<ul class="space-y-3 text-sm text-slate-600">
<li class="line-clamp-1 hover:text-primary-600 cursor-pointer"> 关于调整创作者收益结算周期的通知</li>
<li class="line-clamp-1 hover:text-primary-600 cursor-pointer"> 国粹传承戏曲短视频大赛开启</li>
<li class="line-clamp-1 hover:text-primary-600 cursor-pointer"> 平台系统维护升级公告 (12.30)</li>
</ul>
</div>
<!-- Recommended Tenants -->
<div class="bg-white rounded-xl shadow-sm border border-slate-100 p-5">
<h3 class="font-bold text-slate-900 mb-4">推荐名家</h3>
<div class="space-y-4">
<div class="flex items-center gap-3">
<img src="https://api.dicebear.com/7.x/avataaars/svg?seed=Master1" class="w-10 h-10 rounded-full">
<div class="flex-1 min-w-0">
<div class="font-bold text-slate-900 text-sm truncate">梅派传人小林</div>
<div class="text-xs text-slate-500 truncate">粉丝 12.5</div>
</div>
<button class="px-3 py-1 bg-primary-50 text-primary-600 text-xs font-bold rounded-full hover:bg-primary-100">关注</button>
</div>
<div class="flex items-center gap-3">
<img src="https://api.dicebear.com/7.x/avataaars/svg?seed=Master2" class="w-10 h-10 rounded-full">
<div class="flex-1 min-w-0">
<div class="font-bold text-slate-900 text-sm truncate">豫剧李大师</div>
<div class="text-xs text-slate-500 truncate">粉丝 8.9</div>
</div>
<button class="px-3 py-1 bg-primary-50 text-primary-600 text-xs font-bold rounded-full hover:bg-primary-100">关注</button>
</div>
<div class="flex items-center gap-3">
<img src="https://api.dicebear.com/7.x/avataaars/svg?seed=Master3" class="w-10 h-10 rounded-full">
<div class="flex-1 min-w-0">
<div class="font-bold text-slate-900 text-sm truncate">越剧小生阿强</div>
<div class="text-xs text-slate-500 truncate">粉丝 5.2</div>
</div>
<button class="px-3 py-1 bg-slate-100 text-slate-400 text-xs font-bold rounded-full">已关注</button>
</div>
</div>
</div>
<!-- Trending List -->
<div class="bg-white rounded-xl shadow-sm border border-slate-100 p-5">
<h3 class="font-bold text-slate-900 mb-4 flex items-center gap-2">
<i class="pi pi-chart-line text-red-500"></i> 本周热门
</h3>
<ul class="space-y-4">
<li class="flex gap-3 items-start">
<span class="text-red-500 font-bold italic text-lg w-4">1</span>
<div class="flex-1">
<h4 class="text-sm font-medium text-slate-800 line-clamp-2 hover:text-primary-600 cursor-pointer">智取威虎山选段今日痛饮庆功酒</h4>
<span class="text-xs text-slate-400 mt-1 block">15.2 阅读</span>
</div>
</li>
<li class="flex gap-3 items-start">
<span class="text-orange-500 font-bold italic text-lg w-4">2</span>
<div class="flex-1">
<h4 class="text-sm font-medium text-slate-800 line-clamp-2 hover:text-primary-600 cursor-pointer">深度解析京剧脸谱颜色的含义</h4>
<span class="text-xs text-slate-400 mt-1 block">9.8 阅读</span>
</div>
</li>
<li class="flex gap-3 items-start">
<span class="text-yellow-500 font-bold italic text-lg w-4">3</span>
<div class="flex-1">
<h4 class="text-sm font-medium text-slate-800 line-clamp-2 hover:text-primary-600 cursor-pointer">黄梅戏女驸马全场高清</h4>
<span class="text-xs text-slate-400 mt-1 block">7.5 阅读</span>
</div>
</li>
</ul>
</div>
<!-- Ad / Promo -->
<div class="rounded-xl overflow-hidden shadow-sm">
<img src="https://images.unsplash.com/photo-1557683316-973673baf926?ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=60" class="w-full h-40 object-cover">
<div class="bg-white p-3 flex justify-between items-center">
<span class="text-xs text-slate-400 border border-slate-200 px-1 rounded">广告</span>
<span class="text-sm font-medium text-slate-700">戏曲周边商城上线啦</span>
</div>
</div>
</div>
</div>
</div>
</template>

View File

@@ -0,0 +1,6 @@
<template>
<div class="mx-auto max-w-screen-xl my-8 p-8 bg-white rounded-xl shadow-sm">
<h1 class="text-2xl font-bold mb-4">Topics</h1>
<p class="text-slate-400">(Topic list)</p>
</div>
</template>

View File

@@ -0,0 +1,124 @@
<template>
<div class="bg-white rounded-2xl shadow-xl w-full max-w-4xl overflow-hidden flex min-h-[550px]">
<!-- Left Brand Area -->
<div class="hidden md:flex w-1/2 bg-slate-900 relative p-12 flex-col justify-between text-white">
<!-- Decor/Bg could be here -->
<div class="z-10">
<div class="flex items-center gap-2 mb-8">
<div class="w-8 h-8 bg-white/20 rounded flex items-center justify-center font-bold">Q</div>
<span class="text-xl font-bold">Quyun</span>
</div>
<h1 class="text-4xl font-bold leading-tight mb-4">探索戏曲的<br>无限可能</h1>
<p class="text-slate-400">专业的租户管理与内容交付平台连接创作者与用户</p>
</div>
<div class="text-xs text-slate-500 z-10">© 2025 Quyun. All rights reserved.</div>
</div>
<!-- Right Form Area -->
<div class="w-full md:w-1/2 p-8 sm:p-12 flex flex-col justify-center bg-white relative">
<div v-if="step === 1">
<h2 class="text-2xl font-bold text-slate-900 mb-2">欢迎回来</h2>
<p class="text-sm text-slate-500 mb-8">未注册的手机号验证后将自动创建账号</p>
<form @submit.prevent="getOTP">
<div class="mb-6">
<label class="block text-sm font-medium text-slate-700 mb-2">手机号码</label>
<div class="flex">
<span class="inline-flex items-center px-4 rounded-l-lg border border-r-0 border-slate-300 bg-slate-50 text-slate-500 text-sm">+86</span>
<input
v-model="phone"
type="tel"
class="flex-1 block w-full rounded-r-lg border-slate-300 focus:border-primary-500 focus:ring-primary-500 sm:text-lg py-3"
placeholder="请输入手机号"
required
>
</div>
</div>
<div class="flex items-start mb-6">
<div class="flex items-center h-5">
<input id="terms" v-model="agreed" type="checkbox" class="w-5 h-5 rounded border-slate-300 text-primary-600 focus:ring-primary-500">
</div>
<label for="terms" class="ml-3 text-sm text-slate-500">
我已阅读并同意 <a href="#" class="text-primary-600 hover:underline">用户协议</a> <a href="#" class="text-primary-600 hover:underline">隐私政策</a>
</label>
</div>
<button
type="submit"
class="w-full flex justify-center py-3 px-4 border border-transparent rounded-lg shadow-sm text-lg font-medium text-white bg-primary-600 hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500 disabled:opacity-50 disabled:cursor-not-allowed"
:disabled="!agreed || !phone"
>
获取验证码
</button>
</form>
<div class="mt-8">
<div class="relative">
<div class="absolute inset-0 flex items-center">
<div class="w-full border-t border-slate-200"></div>
</div>
<div class="relative flex justify-center text-sm">
<span class="px-2 bg-white text-slate-500">其他方式登录</span>
</div>
</div>
<div class="mt-6 flex justify-center gap-6">
<button class="w-10 h-10 rounded-full bg-slate-50 border border-slate-200 flex items-center justify-center hover:bg-slate-100 text-green-600"><i class="pi pi-wechat text-xl"></i></button>
<button class="w-10 h-10 rounded-full bg-slate-50 border border-slate-200 flex items-center justify-center hover:bg-slate-100 text-slate-800"><i class="pi pi-github text-xl"></i></button>
</div>
</div>
</div>
<div v-else-if="step === 2">
<button @click="step = 1" class="absolute top-8 left-8 text-slate-400 hover:text-slate-600"><i class="pi pi-arrow-left mr-1"></i> 返回</button>
<h2 class="text-2xl font-bold text-slate-900 mb-2">输入验证码</h2>
<p class="text-sm text-slate-500 mb-8">验证码已发送至 +86 {{ phone }}</p>
<div class="flex gap-3 mb-8 justify-center">
<input
v-for="i in 6" :key="i"
type="text"
maxlength="1"
class="w-12 h-14 text-center text-2xl font-bold border border-slate-300 rounded-lg focus:border-primary-500 focus:ring-2 focus:ring-primary-200"
>
</div>
<div class="text-center mb-8">
<button class="text-sm text-slate-500 hover:text-primary-600">59s 后重新获取</button>
</div>
<button
@click="login"
class="w-full flex justify-center py-3 px-4 border border-transparent rounded-lg shadow-sm text-lg font-medium text-white bg-primary-600 hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500"
>
登录 / 注册
</button>
</div>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue';
import { useRouter } from 'vue-router';
const router = useRouter();
const step = ref(1);
const phone = ref('');
const agreed = ref(false);
const getOTP = () => {
if(!agreed.value) return;
// Simulate API call
setTimeout(() => {
step.value = 2;
}, 500);
};
const login = () => {
// Simulate Login
setTimeout(() => {
router.push('/');
}, 800);
};
</script>

View File

@@ -0,0 +1,10 @@
<template>
<div>
<!-- Placeholder for Content Detail View -->
<div class="bg-white p-8 rounded-xl shadow-sm border border-slate-100 mx-auto max-w-screen-xl my-8 text-center">
<h1 class="text-2xl font-bold mb-4">Content Detail Page</h1>
<p class="text-slate-500">ID: {{ $route.params.id }}</p>
<p class="text-slate-400 mt-2">(Implementation pending based on PAGE_CONTENT_DETAIL.md)</p>
</div>
</div>
</template>

View File

@@ -0,0 +1,7 @@
<template>
<div class="mx-auto max-w-3xl my-12 bg-white rounded-xl shadow-sm border border-slate-100 p-8">
<h1 class="text-2xl font-bold mb-4 text-center">Creator Application</h1>
<p class="text-slate-500 text-center mb-8">Join us and start your creative journey.</p>
<p class="text-slate-400 text-center">(Implementation pending based on PAGE_TENANT_APPLY.md)</p>
</div>
</template>

View File

@@ -0,0 +1,6 @@
<template>
<div class="p-8">
<h1 class="text-2xl font-bold mb-4">Creator Contents</h1>
<p class="text-slate-400">(List of contents)</p>
</div>
</template>

View File

@@ -0,0 +1,7 @@
<template>
<div class="p-8">
<h1 class="text-2xl font-bold mb-4">Creator Dashboard</h1>
<p class="text-slate-500">Welcome to the Creator Center.</p>
<p class="text-slate-400 mt-2">(Implementation pending based on PAGE_TENANT_MANAGEMENT.md)</p>
</div>
</template>

View File

@@ -0,0 +1,6 @@
<template>
<div class="p-8">
<h1 class="text-2xl font-bold mb-4">Creator Orders</h1>
<p class="text-slate-400">(List of orders)</p>
</div>
</template>

View File

@@ -0,0 +1,6 @@
<template>
<div class="p-8">
<h1 class="text-2xl font-bold mb-4">Creator Settings</h1>
<p class="text-slate-400">(Tenant settings)</p>
</div>
</template>

View File

@@ -0,0 +1,16 @@
<template>
<div class="min-h-screen flex items-center justify-center bg-slate-50">
<div class="text-center">
<div class="mb-6">
<!-- Use an image or illustration here -->
<i class="pi pi-compass text-6xl text-slate-300"></i>
</div>
<h1 class="text-4xl font-bold text-slate-900 mb-4">404</h1>
<p class="text-xl text-slate-600 mb-8">抱歉您访问的页面走丢了</p>
<div class="flex justify-center gap-4">
<router-link to="/" class="px-6 py-3 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors">返回首页</router-link>
<button @click="$router.back()" class="px-6 py-3 border border-slate-300 text-slate-700 rounded-lg hover:bg-slate-50 transition-colors">返回上一页</button>
</div>
</div>
</div>
</template>

View File

@@ -0,0 +1,6 @@
<template>
<div class="mx-auto max-w-screen-xl my-8 p-8 bg-white rounded-xl shadow-sm">
<h1 class="text-2xl font-bold mb-4">Checkout</h1>
<p class="text-slate-400">(Checkout flow)</p>
</div>
</template>

View File

@@ -0,0 +1,6 @@
<template>
<div class="mx-auto max-w-screen-xl my-8 p-8 bg-white rounded-xl shadow-sm">
<h1 class="text-2xl font-bold mb-4">Payment Cashier</h1>
<p class="text-slate-400">Order ID: {{ $route.params.id }}</p>
</div>
</template>

View File

@@ -0,0 +1,10 @@
<template>
<div>
<!-- Placeholder for Tenant Home View -->
<div class="bg-white p-8 rounded-xl shadow-sm border border-slate-100 mx-auto max-w-screen-xl my-8 text-center">
<h1 class="text-2xl font-bold mb-4">Tenant Home Page</h1>
<p class="text-slate-500">Tenant ID: {{ $route.params.id }}</p>
<p class="text-slate-400 mt-2">(Implementation pending based on PAGE_TENANT_HOME.md)</p>
</div>
</div>
</template>

View File

@@ -0,0 +1,72 @@
<template>
<div class="mx-auto max-w-screen-xl px-4 sm:px-6 lg:px-8 py-8">
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<!-- Stat Cards -->
<div class="bg-white p-6 rounded-xl shadow-sm border border-slate-100 flex items-center gap-4">
<div class="w-12 h-12 rounded-full bg-blue-50 text-blue-600 flex items-center justify-center text-xl"><i class="pi pi-wallet"></i></div>
<div>
<div class="text-sm text-slate-500">账户余额</div>
<div class="text-2xl font-bold text-slate-900">¥ 128.50</div>
</div>
<!-- <button class="ml-auto text-sm font-medium text-primary-600 hover:bg-primary-50 px-3 py-1.5 rounded transition-colors">充值</button> -->
</div>
<div class="bg-white p-6 rounded-xl shadow-sm border border-slate-100 flex items-center gap-4">
<div class="w-12 h-12 rounded-full bg-yellow-50 text-yellow-600 flex items-center justify-center text-xl"><i class="pi pi-star"></i></div>
<div>
<div class="text-sm text-slate-500">我的积分</div>
<div class="text-2xl font-bold text-slate-900">2,450</div>
</div>
</div>
<div class="bg-white p-6 rounded-xl shadow-sm border border-slate-100 flex items-center gap-4">
<div class="w-12 h-12 rounded-full bg-red-50 text-red-600 flex items-center justify-center text-xl"><i class="pi pi-ticket"></i></div>
<div>
<div class="text-sm text-slate-500">优惠券</div>
<div class="text-2xl font-bold text-slate-900">3 </div>
</div>
</div>
</div>
<!-- Recent Orders -->
<div class="mt-8 bg-white rounded-xl shadow-sm border border-slate-100 p-6">
<div class="flex items-center justify-between mb-6">
<h2 class="text-xl font-bold text-slate-900">最近订单</h2>
<router-link to="/me/orders" class="text-sm text-primary-600 hover:text-primary-700 font-medium">查看全部 <i class="pi pi-angle-right"></i></router-link>
</div>
<div class="space-y-4">
<div class="flex items-center gap-4 p-4 border border-slate-100 rounded-lg hover:border-slate-300 transition-colors cursor-pointer">
<div class="w-16 h-16 bg-slate-100 rounded object-cover flex-shrink-0">
<img src="https://images.unsplash.com/photo-1514306191717-452ec28c7f31?ixlib=rb-1.2.1&auto=format&fit=crop&w=100&q=60" class="w-full h-full object-cover rounded">
</div>
<div class="flex-1 min-w-0">
<h3 class="font-bold text-slate-900 truncate">霸王别姬全本实录珍藏版</h3>
<div class="text-sm text-slate-500 mt-1">2025-12-24 14:30 · 订单号: 82934712</div>
</div>
<div class="text-right">
<div class="font-bold text-slate-900">¥ 9.90</div>
<div class="text-sm text-green-600 mt-1">交易成功</div>
</div>
</div>
<!-- More items... -->
</div>
</div>
<!-- Recent Views -->
<div class="mt-8 bg-white rounded-xl shadow-sm border border-slate-100 p-6">
<div class="flex items-center justify-between mb-6">
<h2 class="text-xl font-bold text-slate-900">最近浏览</h2>
<button class="text-sm text-slate-500 hover:text-slate-700"><i class="pi pi-trash"></i> 清空历史</button>
</div>
<div class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 gap-4">
<div v-for="i in 5" :key="i" class="group cursor-pointer">
<div class="aspect-[16/9] bg-slate-100 rounded-lg overflow-hidden mb-2 relative">
<img :src="`https://images.unsplash.com/photo-1469571486292-0ba58a3f068b?ixlib=rb-1.2.1&auto=format&fit=crop&w=300&q=60`" class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-500">
<div class="absolute inset-0 bg-black/0 group-hover:bg-black/10 transition-colors"></div>
</div>
<h4 class="text-sm font-medium text-slate-800 line-clamp-2 group-hover:text-primary-600">京剧名家谈戏曲传承与创新发展的思考</h4>
<div class="text-xs text-slate-400 mt-1">10分钟前</div>
</div>
</div>
</div>
</div>
</template>

View File

@@ -0,0 +1,6 @@
<template>
<div class="p-8">
<h1 class="text-2xl font-bold mb-4">My Library</h1>
<p class="text-slate-400">(Purchased content)</p>
</div>
</template>

View File

@@ -0,0 +1,6 @@
<template>
<div class="p-8">
<h1 class="text-2xl font-bold mb-4">Notifications</h1>
<p class="text-slate-400">(Message center)</p>
</div>
</template>

View File

@@ -0,0 +1,6 @@
<template>
<div class="p-8">
<h1 class="text-2xl font-bold mb-4">My Orders</h1>
<p class="text-slate-400">(Order list)</p>
</div>
</template>

View File

@@ -0,0 +1,6 @@
<template>
<div class="p-8">
<h1 class="text-2xl font-bold mb-4">Profile Settings</h1>
<p class="text-slate-400">(Edit profile)</p>
</div>
</template>

View File

@@ -0,0 +1,6 @@
<template>
<div class="p-8">
<h1 class="text-2xl font-bold mb-4">Account Security</h1>
<p class="text-slate-400">(Password and bindings)</p>
</div>
</template>

View File

@@ -0,0 +1,6 @@
<template>
<div class="p-8">
<h1 class="text-2xl font-bold mb-4">My Wallet</h1>
<p class="text-slate-400">(Balance and transactions)</p>
</div>
</template>

View File

@@ -0,0 +1,22 @@
import tailwindcss from '@tailwindcss/vite'
import vue from '@vitejs/plugin-vue'
import { defineConfig } from 'vite'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
tailwindcss(),
],
server: {
host: '0.0.0.0',
port: 5174,
strictPort: true,
proxy: {
'/v1': {
target: 'http://localhost:8080',
changeOrigin: true
}
}
},
})