为什么:这些改动在前几轮就已完成并在 :3005 验证过,但一直留在工作区没有入库。 下一步 3-4 的四个页面依赖其中的公共样式入口(src/styles/business/index.css)与 api/admin 的公共类型(PageResult 等),如果不先收口,新页面的提交就会夹带旧改动, 既说不清 diff 边界,也让 index.css 这类多轮共用的文件长期处于半提交状态。 本提交只做归档,不改行为: - 品牌与接口基址改成 FruitShorts / 短剧服务(.env.*、README、vite 代理) - 去掉前端 mock 数据目录(src/data、src/permissions、stores/auth),改为走真实接口 - 新增 api/admin 下的接口封装与 src/utils/uploader.ts(媒资分片直传) - 新增/改造:轮播图管理、类型管理、操作日志、App 用户管理、后台布局与公共样式
275 lines
5.4 KiB
Vue
275 lines
5.4 KiB
Vue
<script setup lang="ts">
|
|
import { LoginForm, RegisterForm } from './components'
|
|
import { ThemeSwitch } from '@/components/ThemeSwitch'
|
|
import { LocaleDropdown } from '@/components/LocaleDropdown'
|
|
import { useI18n } from '@/hooks/web/useI18n'
|
|
import { getCssVar, underlineToHump } from '@/utils'
|
|
import { useAppStore } from '@/store/modules/app'
|
|
import { computed, ref } from 'vue'
|
|
import { ElScrollbar } from 'element-plus'
|
|
|
|
const appStore = useAppStore()
|
|
const { t } = useI18n()
|
|
const isLogin = ref(true)
|
|
const isDark = computed(() => appStore.getIsDark)
|
|
const toolColor = computed(() => (isDark.value ? '#e5eaf3' : '#303133'))
|
|
|
|
const themeChange = () => {
|
|
const color = getCssVar('--el-bg-color')
|
|
appStore.setMenuTheme(color)
|
|
appStore.setHeaderTheme(color)
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div class="login-page" :class="{ 'is-dark': isDark }">
|
|
<ElScrollbar class="login-scroll">
|
|
<div class="login-shell">
|
|
<section class="login-hero">
|
|
<div class="hero-brand">
|
|
<img src="@/assets/imgs/logo.png" alt="" />
|
|
<span>{{ underlineToHump(appStore.getTitle) }}</span>
|
|
</div>
|
|
<div class="hero-copy">
|
|
<p class="hero-kicker">FruitShorts Studio</p>
|
|
<h1>{{ t('login.welcome') }}</h1>
|
|
<p>{{ t('login.message') }}</p>
|
|
<ul>
|
|
<li>{{ t('login.pointDrama') }}</li>
|
|
<li>{{ t('login.pointPublish') }}</li>
|
|
<li>{{ t('login.pointAccess') }}</li>
|
|
</ul>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="login-panel">
|
|
<div class="login-tools">
|
|
<ThemeSwitch @change="themeChange" />
|
|
<LocaleDropdown :color="toolColor" />
|
|
</div>
|
|
<div class="login-card">
|
|
<LoginForm v-if="isLogin" @to-register="isLogin = false" />
|
|
<RegisterForm v-else @to-login="isLogin = true" />
|
|
</div>
|
|
</section>
|
|
</div>
|
|
</ElScrollbar>
|
|
</div>
|
|
</template>
|
|
|
|
<style lang="less" scoped>
|
|
.login-page {
|
|
height: 100%;
|
|
color: var(--el-text-color-primary);
|
|
background: #eef3f9;
|
|
}
|
|
|
|
.login-scroll {
|
|
height: 100%;
|
|
}
|
|
|
|
.login-shell {
|
|
display: flex;
|
|
min-height: 100vh;
|
|
}
|
|
|
|
.login-hero {
|
|
position: relative;
|
|
display: flex;
|
|
padding: 40px 56px 56px;
|
|
overflow: hidden;
|
|
color: #fff;
|
|
background:
|
|
radial-gradient(circle at 18% 18%, rgb(255 255 255 / 16%), transparent 28%),
|
|
radial-gradient(circle at 82% 78%, rgb(64 158 255 / 45%), transparent 32%),
|
|
linear-gradient(155deg, #0d2344 0%, #1a4f96 52%, #409eff 100%);
|
|
flex: 1.05;
|
|
flex-direction: column;
|
|
justify-content: space-between;
|
|
|
|
&::after {
|
|
position: absolute;
|
|
right: -80px;
|
|
bottom: -120px;
|
|
width: 360px;
|
|
height: 360px;
|
|
border: 1px solid rgb(255 255 255 / 16%);
|
|
border-radius: 50%;
|
|
content: '';
|
|
}
|
|
}
|
|
|
|
.hero-brand {
|
|
position: relative;
|
|
z-index: 1;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12px;
|
|
font-size: 20px;
|
|
font-weight: 700;
|
|
|
|
img {
|
|
width: 42px;
|
|
height: 42px;
|
|
}
|
|
}
|
|
|
|
.hero-copy {
|
|
position: relative;
|
|
z-index: 1;
|
|
max-width: 460px;
|
|
|
|
h1 {
|
|
margin: 10px 0 12px;
|
|
font-size: 40px;
|
|
font-weight: 700;
|
|
line-height: 1.2;
|
|
color: #fff;
|
|
}
|
|
|
|
p {
|
|
margin: 0;
|
|
font-size: 15px;
|
|
line-height: 1.7;
|
|
color: rgb(255 255 255 / 82%);
|
|
}
|
|
}
|
|
|
|
.hero-kicker {
|
|
font-size: 13px;
|
|
font-weight: 600;
|
|
letter-spacing: 0.08em;
|
|
color: #d9ecff !important;
|
|
}
|
|
|
|
.hero-copy ul {
|
|
display: flex;
|
|
padding: 0;
|
|
margin: 28px 0 0;
|
|
list-style: none;
|
|
flex-wrap: wrap;
|
|
gap: 10px;
|
|
|
|
li {
|
|
padding: 8px 14px;
|
|
font-size: 13px;
|
|
color: #fff;
|
|
background: rgb(255 255 255 / 12%);
|
|
border: 1px solid rgb(255 255 255 / 18%);
|
|
border-radius: 999px;
|
|
}
|
|
}
|
|
|
|
.login-panel {
|
|
position: relative;
|
|
display: flex;
|
|
flex: 0.95;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 88px 32px 48px;
|
|
background: #f4f7fb;
|
|
}
|
|
|
|
.login-tools {
|
|
position: absolute;
|
|
top: 22px;
|
|
right: 24px;
|
|
display: flex;
|
|
gap: 12px;
|
|
align-items: center;
|
|
}
|
|
|
|
.login-card {
|
|
width: min(420px, 100%);
|
|
padding: 36px 32px 28px;
|
|
background: #fff;
|
|
border: 1px solid #e6edf5;
|
|
border-radius: 18px;
|
|
box-shadow: 0 18px 50px rgb(15 39 68 / 8%);
|
|
}
|
|
|
|
.is-dark {
|
|
background: #0e1116;
|
|
|
|
.login-hero {
|
|
background:
|
|
radial-gradient(circle at 18% 18%, rgb(64 158 255 / 18%), transparent 30%),
|
|
linear-gradient(155deg, #07111f 0%, #0e2744 58%, #163e73 100%);
|
|
}
|
|
|
|
.login-panel {
|
|
background: #0e1116;
|
|
}
|
|
|
|
.login-card {
|
|
background: #161b22;
|
|
border-color: #2a313c;
|
|
box-shadow: none;
|
|
}
|
|
}
|
|
|
|
@media (width <= 960px) {
|
|
.login-shell {
|
|
flex-direction: column;
|
|
}
|
|
|
|
.login-hero {
|
|
flex: none;
|
|
min-height: 280px;
|
|
padding: 28px 24px 32px;
|
|
}
|
|
|
|
.hero-copy h1 {
|
|
font-size: 30px;
|
|
}
|
|
|
|
.login-panel {
|
|
padding: 72px 16px 32px;
|
|
}
|
|
}
|
|
</style>
|
|
|
|
<style lang="less">
|
|
.login-heading {
|
|
margin-bottom: 8px;
|
|
|
|
h2 {
|
|
margin: 0;
|
|
font-size: 28px;
|
|
font-weight: 700;
|
|
line-height: 1.2;
|
|
color: var(--el-text-color-primary);
|
|
}
|
|
|
|
p {
|
|
margin: 8px 0 0;
|
|
font-size: 14px;
|
|
color: var(--el-text-color-secondary);
|
|
}
|
|
}
|
|
|
|
.login-register {
|
|
display: flex;
|
|
margin-top: 16px;
|
|
font-size: 14px;
|
|
color: var(--el-text-color-secondary);
|
|
gap: 6px;
|
|
align-items: center;
|
|
justify-content: center;
|
|
|
|
button {
|
|
padding: 0;
|
|
font: inherit;
|
|
color: var(--el-color-primary);
|
|
cursor: pointer;
|
|
background: none;
|
|
border: 0;
|
|
}
|
|
}
|
|
|
|
body:has(.login-page) {
|
|
min-width: 0;
|
|
background: transparent;
|
|
}
|
|
</style>
|