Initial import of frappe sunderer app
This commit is contained in:
Generated
-4
@@ -1087,7 +1087,6 @@
|
|||||||
"resolved": "https://registry.npmmirror.com/css-render/-/css-render-0.15.14.tgz",
|
"resolved": "https://registry.npmmirror.com/css-render/-/css-render-0.15.14.tgz",
|
||||||
"integrity": "sha512-9nF4PdUle+5ta4W5SyZdLCCmFd37uVimSjg1evcTqKJCyvCEEj12WKzOSBNak6r4im4J4iYXKH1OWpUV5LBYFg==",
|
"integrity": "sha512-9nF4PdUle+5ta4W5SyZdLCCmFd37uVimSjg1evcTqKJCyvCEEj12WKzOSBNak6r4im4J4iYXKH1OWpUV5LBYFg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emotion/hash": "~0.8.0",
|
"@emotion/hash": "~0.8.0",
|
||||||
"csstype": "~3.0.5"
|
"csstype": "~3.0.5"
|
||||||
@@ -1110,7 +1109,6 @@
|
|||||||
"resolved": "https://registry.npmmirror.com/date-fns/-/date-fns-4.1.0.tgz",
|
"resolved": "https://registry.npmmirror.com/date-fns/-/date-fns-4.1.0.tgz",
|
||||||
"integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==",
|
"integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "github",
|
"type": "github",
|
||||||
"url": "https://github.com/sponsors/kossnocorp"
|
"url": "https://github.com/sponsors/kossnocorp"
|
||||||
@@ -1747,7 +1745,6 @@
|
|||||||
"integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==",
|
"integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"esbuild": "^0.21.3",
|
"esbuild": "^0.21.3",
|
||||||
"postcss": "^8.4.43",
|
"postcss": "^8.4.43",
|
||||||
@@ -1819,7 +1816,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/vue/-/vue-3.5.26.tgz",
|
"resolved": "https://registry.npmjs.org/vue/-/vue-3.5.26.tgz",
|
||||||
"integrity": "sha512-SJ/NTccVyAoNUJmkM9KUqPcYlY+u8OVL1X5EW9RIs3ch5H2uERxyyIUI4MRxVCSOiEcupX9xNGde1tL9ZKpimA==",
|
"integrity": "sha512-SJ/NTccVyAoNUJmkM9KUqPcYlY+u8OVL1X5EW9RIs3ch5H2uERxyyIUI4MRxVCSOiEcupX9xNGde1tL9ZKpimA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vue/compiler-dom": "3.5.26",
|
"@vue/compiler-dom": "3.5.26",
|
||||||
"@vue/compiler-sfc": "3.5.26",
|
"@vue/compiler-sfc": "3.5.26",
|
||||||
|
|||||||
@@ -80,13 +80,13 @@ const menuOptions = [
|
|||||||
label: 'Dashboard',
|
label: 'Dashboard',
|
||||||
key: 'dashboard',
|
key: 'dashboard',
|
||||||
icon: renderIcon(BookIcon),
|
icon: renderIcon(BookIcon),
|
||||||
props: { onClick: () => router.push('/app/dashboard') }
|
props: { onClick: () => router.push('/sundererapp/dashboard') }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Users',
|
label: 'Users',
|
||||||
key: 'users',
|
key: 'users',
|
||||||
icon: renderIcon(PersonIcon),
|
icon: renderIcon(PersonIcon),
|
||||||
props: { onClick: () => router.push('/app/users') }
|
props: { onClick: () => router.push('/sundererapp/users') }
|
||||||
},
|
},
|
||||||
// 添加更多菜单项...
|
// 添加更多菜单项...
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,166 +1,166 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="password-setup-container">
|
<div class="password-setup-container">
|
||||||
<div class="setup-card">
|
<div class="setup-card">
|
||||||
<h2>设置密码</h2>
|
<h2>设置密码</h2>
|
||||||
|
|
||||||
<form @submit.prevent="setupPassword">
|
<form @submit.prevent="setupPassword">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<label>新密码</label>
|
<label>新密码</label>
|
||||||
<input
|
<input
|
||||||
v-model="newPassword"
|
v-model="newPassword"
|
||||||
type="password"
|
type="password"
|
||||||
placeholder="请输入新密码"
|
placeholder="请输入新密码"
|
||||||
class="input-field"
|
class="input-field"
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<label>确认密码</label>
|
<label>确认密码</label>
|
||||||
<input
|
<input
|
||||||
v-model="confirmPassword"
|
v-model="confirmPassword"
|
||||||
type="password"
|
type="password"
|
||||||
placeholder="请再次输入密码"
|
placeholder="请再次输入密码"
|
||||||
class="input-field"
|
class="input-field"
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="error" class="error">{{ error }}</div>
|
<div v-if="error" class="error">{{ error }}</div>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
:disabled="loading"
|
:disabled="loading"
|
||||||
class="btn-primary"
|
class="btn-primary"
|
||||||
>
|
>
|
||||||
{{ loading ? '设置中...' : '设置密码' }}
|
{{ loading ? '设置中...' : '设置密码' }}
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { useRouter, useRoute } from 'vue-router'
|
import { useRouter, useRoute } from 'vue-router'
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const newPassword = ref('')
|
const newPassword = ref('')
|
||||||
const confirmPassword = ref('')
|
const confirmPassword = ref('')
|
||||||
const error = ref('')
|
const error = ref('')
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
|
|
||||||
const setupPassword = async () => {
|
const setupPassword = async () => {
|
||||||
if (newPassword.value !== confirmPassword.value) {
|
if (newPassword.value !== confirmPassword.value) {
|
||||||
error.value = '两次输入的密码不一致'
|
error.value = '两次输入的密码不一致'
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newPassword.value.length < 6) {
|
if (newPassword.value.length < 6) {
|
||||||
error.value = '密码长度至少为6位'
|
error.value = '密码长度至少为6位'
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
loading.value = true
|
loading.value = true
|
||||||
error.value = ''
|
error.value = ''
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const actualKey = route.query.key
|
const actualKey = route.query.key
|
||||||
if (!actualKey) {
|
if (!actualKey) {
|
||||||
error.value = '无效的密码重置链接'
|
error.value = '无效的密码重置链接'
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await fetch('http://172.25.162.172:8000/api/method/frappe.core.doctype.user.user.update_password', {
|
const response = await fetch('/api/method/frappe.core.doctype.user.user.update_password', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
credentials: 'include',
|
credentials: 'include',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
key: actualKey,
|
key: actualKey,
|
||||||
new_password: newPassword.value
|
new_password: newPassword.value
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
const result = await response.json()
|
const result = await response.json()
|
||||||
|
|
||||||
if (result.exc) {
|
if (result.exc) {
|
||||||
error.value = result.exc || '设置密码失败'
|
error.value = result.exc || '设置密码失败'
|
||||||
} else {
|
} else {
|
||||||
alert('密码设置成功!')
|
alert('密码设置成功!')
|
||||||
router.push('/login')
|
router.push('/login')
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
error.value = '网络错误,请稍后再试'
|
error.value = '网络错误,请稍后再试'
|
||||||
console.error(err)
|
console.error(err)
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.password-setup-container {
|
.password-setup-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
background: linear-gradient(135deg, #00AFFF, #0077CC);
|
background: linear-gradient(135deg, #00AFFF, #0077CC);
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.setup-card {
|
.setup-card {
|
||||||
width: 400px;
|
width: 400px;
|
||||||
padding: 30px;
|
padding: 30px;
|
||||||
background: rgba(0, 0, 0, 0.295);
|
background: rgba(0, 0, 0, 0.295);
|
||||||
backdrop-filter: blur(12px);
|
backdrop-filter: blur(12px);
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
box-shadow: 0 0 30px rgba(0, 175, 255, 0.4);
|
box-shadow: 0 0 30px rgba(0, 175, 255, 0.4);
|
||||||
border: 1px solid rgba(0, 175, 255, 0.3);
|
border: 1px solid rgba(0, 175, 255, 0.3);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-group {
|
.input-group {
|
||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-group label {
|
.input-group label {
|
||||||
display: block;
|
display: block;
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-field {
|
.input-field {
|
||||||
width: 94%;
|
width: 94%;
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
background: rgb(255, 255, 255);
|
background: rgb(255, 255, 255);
|
||||||
color: rgb(0, 0, 0);
|
color: rgb(0, 0, 0);
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
outline: none;
|
outline: none;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
box-shadow: 0 0 0 1px rgba(0, 175, 255, 0.3);
|
box-shadow: 0 0 0 1px rgba(0, 175, 255, 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-primary {
|
.btn-primary {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
background: linear-gradient(90deg, #4CAF50, #45a049);
|
background: linear-gradient(90deg, #4CAF50, #45a049);
|
||||||
color: white;
|
color: white;
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
transition: transform 0.2s, box-shadow 0.2s;
|
transition: transform 0.2s, box-shadow 0.2s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.error {
|
.error {
|
||||||
color: #ff6b6b;
|
color: #ff6b6b;
|
||||||
margin: 10px 0;
|
margin: 10px 0;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -1,258 +1,258 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="login-container">
|
<div class="login-container">
|
||||||
<!-- 背景几何图案 -->
|
<!-- 背景几何图案 -->
|
||||||
<div class="bg-pattern"></div>
|
<div class="bg-pattern"></div>
|
||||||
|
|
||||||
<!-- 登录卡 -->
|
<!-- 登录卡 -->
|
||||||
<div class="login-card">
|
<div class="login-card">
|
||||||
<div class="logo">
|
<div class="logo">
|
||||||
<span class="brand">决裂者终端</span>
|
<span class="brand">决裂者终端</span>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form @submit.prevent="handleLogin">
|
<form @submit.prevent="handleLogin">
|
||||||
<input
|
<input
|
||||||
v-model="email"
|
v-model="email"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="请输入账号"
|
placeholder="请输入账号"
|
||||||
required
|
required
|
||||||
class="input-field"
|
class="input-field"
|
||||||
/>
|
/>
|
||||||
<input
|
<input
|
||||||
v-model="password"
|
v-model="password"
|
||||||
type="password"
|
type="password"
|
||||||
placeholder="请输入密码"
|
placeholder="请输入密码"
|
||||||
required
|
required
|
||||||
class="input-field"
|
class="input-field"
|
||||||
/>
|
/>
|
||||||
<div v-if="error" class="error">{{ error }}</div>
|
<div v-if="error" class="error">{{ error }}</div>
|
||||||
|
|
||||||
<div class="auth-buttons">
|
<div class="auth-buttons">
|
||||||
<button type="submit" :disabled="loginLoading" class="login-btn">
|
<button type="submit" :disabled="loginLoading" class="login-btn">
|
||||||
{{ loginLoading ? '正在登录. . .' : '登录' }}
|
{{ loginLoading ? '正在登录. . .' : '登录' }}
|
||||||
</button>
|
</button>
|
||||||
<button type="button" @click="goToRegister" :disabled="registerLoading" class="register-btn">
|
<button type="button" @click="goToRegister" :disabled="registerLoading" class="register-btn">
|
||||||
{{ registerLoading ? '注册中...' : '注册' }}
|
{{ registerLoading ? '注册中...' : '注册' }}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<p class="footer">© 2026 Sunderer games. </p>
|
<p class="footer">© 2026 Sunderer games. </p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { useRouter } from 'vue-router' // ✅ 确保导入
|
import { useRouter } from 'vue-router' // ✅ 确保导入
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
const email = ref('')
|
const email = ref('')
|
||||||
const password = ref('')
|
const password = ref('')
|
||||||
const error = ref('')
|
const error = ref('')
|
||||||
const loginLoading = ref(false)
|
const loginLoading = ref(false)
|
||||||
const registerLoading = ref(false)
|
const registerLoading = ref(false)
|
||||||
|
|
||||||
|
|
||||||
async function handleLogin() {
|
async function handleLogin() {
|
||||||
loginLoading.value = true
|
loginLoading.value = true
|
||||||
error.value = ''
|
error.value = ''
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await fetch('/api/method/login', {
|
const res = await fetch('/api/method/login', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
credentials: 'include',
|
credentials: 'include',
|
||||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||||
body: new URLSearchParams({ usr: email.value, pwd: password.value })
|
body: new URLSearchParams({ usr: email.value, pwd: password.value })
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
const data = await res.json()
|
const data = await res.json()
|
||||||
throw new Error(data.message || '账号或密码错误')
|
throw new Error(data.message || '账号或密码错误')
|
||||||
}
|
}
|
||||||
|
|
||||||
// 跳转到 Frappe 后台
|
// 跳转到 Frappe 后台
|
||||||
window.location.href = 'http://172.25.162.172:8000/app'
|
window.location.href = '/sundererapp'
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
error.value = err.message
|
error.value = err.message
|
||||||
} finally {
|
} finally {
|
||||||
loginLoading.value = false
|
loginLoading.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleRegister() {
|
async function handleRegister() {
|
||||||
|
|
||||||
registerLoading.value = true
|
registerLoading.value = true
|
||||||
error.value = ''
|
error.value = ''
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await fetch('/api/method/frappe.core.doctype.user.user.sign_up', {
|
const res = await fetch('/api/method/frappe.core.doctype.user.user.sign_up', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
credentials: 'include',
|
credentials: 'include',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
email: email.value,
|
email: email.value,
|
||||||
full_name: email.value.split('@')[0], // 简单处理,可用其他字段
|
full_name: email.value.split('@')[0], // 简单处理,可用其他字段
|
||||||
redirect_to: '/app'
|
redirect_to: '/app'
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
const data = await res.json()
|
const data = await res.json()
|
||||||
throw new Error(data.message || '注册失败')
|
throw new Error(data.message || '注册失败')
|
||||||
}
|
}
|
||||||
|
|
||||||
// 注册成功后,Frappe 会发送验证邮件
|
// 注册成功后,Frappe 会发送验证邮件
|
||||||
alert('注册成功!请查收邮箱验证链接。')
|
alert('注册成功!请查收邮箱验证链接。')
|
||||||
// 或跳转到提示页
|
// 或跳转到提示页
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
error.value = err.message
|
error.value = err.message
|
||||||
} finally {
|
} finally {
|
||||||
registerLoading.value = false
|
registerLoading.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function goToRegister() {
|
function goToRegister() {
|
||||||
router.push('/register')
|
router.push('/register')
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.login-container {
|
.login-container {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
background: linear-gradient(135deg, #00AFFF, #0077CC);
|
background: linear-gradient(135deg, #00AFFF, #0077CC);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 登录卡片保持原样 */
|
/* 登录卡片保持原样 */
|
||||||
.login-card {
|
.login-card {
|
||||||
background: rgba(0, 0, 0, 0.295);
|
background: rgba(0, 0, 0, 0.295);
|
||||||
backdrop-filter: blur(12px);
|
backdrop-filter: blur(12px);
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
padding: 2.5rem;
|
padding: 2.5rem;
|
||||||
width: 360px;
|
width: 360px;
|
||||||
box-shadow: 0 0 30px rgba(0, 175, 255, 0.4);
|
box-shadow: 0 0 30px rgba(0, 175, 255, 0.4);
|
||||||
border: 1px solid rgba(0, 175, 255, 0.3);
|
border: 1px solid rgba(0, 175, 255, 0.3);
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center; /* 水平居中内容 */
|
justify-content: center; /* 水平居中内容 */
|
||||||
align-items: center; /* 垂直居中内容 */
|
align-items: center; /* 垂直居中内容 */
|
||||||
min-height: 300px; /* 防止高度塌陷 */
|
min-height: 300px; /* 防止高度塌陷 */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 其他样式(logo、输入框、按钮等)保持不变... */
|
/* 其他样式(logo、输入框、按钮等)保持不变... */
|
||||||
.logo {
|
.logo {
|
||||||
font-family: 'Arial', sans-serif;
|
font-family: 'Arial', sans-serif;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
margin-bottom: 1.5rem;
|
margin-bottom: 1.5rem;
|
||||||
letter-spacing: 1px;
|
letter-spacing: 1px;
|
||||||
color: white;
|
color: white;
|
||||||
text-shadow: 0 0 10px rgba(0, 175, 255, 0.8), 0 0 20px rgba(0, 175, 255, 0.6);
|
text-shadow: 0 0 10px rgba(0, 175, 255, 0.8), 0 0 20px rgba(0, 175, 255, 0.6);
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.brand {
|
.brand {
|
||||||
color: white;
|
color: white;
|
||||||
font-size: 2.2rem;
|
font-size: 2.2rem;
|
||||||
text-shadow: 0 0 10px rgba(0, 175, 255, 0.8), 0 0 20px rgba(0, 175, 255, 0.6);
|
text-shadow: 0 0 10px rgba(0, 175, 255, 0.8), 0 0 20px rgba(0, 175, 255, 0.6);
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
color: #00FFFF;
|
color: #00FFFF;
|
||||||
font-size: 1.8rem;
|
font-size: 1.8rem;
|
||||||
margin: 0 0.5rem;
|
margin: 0 0.5rem;
|
||||||
text-shadow: 0 0 15px rgba(0, 255, 255, 0.7);
|
text-shadow: 0 0 15px rgba(0, 255, 255, 0.7);
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-field {
|
.input-field {
|
||||||
width: 80%;
|
width: 80%;
|
||||||
padding: 0.8rem 1rem;
|
padding: 0.8rem 1rem;
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
background: rgb(255, 255, 255);
|
background: rgb(255, 255, 255);
|
||||||
color: rgb(0, 0, 0);
|
color: rgb(0, 0, 0);
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
outline: none;
|
outline: none;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
box-shadow: 0 0 0 1px rgba(0, 175, 255, 0.3);
|
box-shadow: 0 0 0 1px rgba(0, 175, 255, 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-field:focus {
|
.input-field:focus {
|
||||||
box-shadow: 0 0 0 2px rgba(0, 175, 255, 0.7), 0 0 10px rgba(0, 175, 255, 0.4);
|
box-shadow: 0 0 0 2px rgba(0, 175, 255, 0.7), 0 0 10px rgba(0, 175, 255, 0.4);
|
||||||
}
|
}
|
||||||
.error {
|
.error {
|
||||||
color: #ff6b6b;
|
color: #ff6b6b;
|
||||||
font-size: 0.85rem;
|
font-size: 0.85rem;
|
||||||
margin: -0.5rem 0 1rem;
|
margin: -0.5rem 0 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-btn {
|
.login-btn {
|
||||||
width: 70%;
|
width: 70%;
|
||||||
padding: 0.8rem;
|
padding: 0.8rem;
|
||||||
background: linear-gradient(90deg, #00AFFF, #0077CC);
|
background: linear-gradient(90deg, #00AFFF, #0077CC);
|
||||||
color: white;
|
color: white;
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: transform 0.2s, box-shadow 0.2s;
|
transition: transform 0.2s, box-shadow 0.2s;
|
||||||
box-shadow: 0 0 15px rgba(0, 175, 255, 0.5);
|
box-shadow: 0 0 15px rgba(0, 175, 255, 0.5);
|
||||||
}
|
}
|
||||||
.register-btn {
|
.register-btn {
|
||||||
width: 70%;
|
width: 70%;
|
||||||
padding: 0.8rem;
|
padding: 0.8rem;
|
||||||
background: linear-gradient(90deg, #6bffce, #c74dff);
|
background: linear-gradient(90deg, #6bffce, #c74dff);
|
||||||
color: white;
|
color: white;
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: transform 0.2s, box-shadow 0.2s;
|
transition: transform 0.2s, box-shadow 0.2s;
|
||||||
box-shadow: 0 0 15px rgba(255, 107, 107, 0.5);
|
box-shadow: 0 0 15px rgba(255, 107, 107, 0.5);
|
||||||
}
|
}
|
||||||
.login-btn:hover:not(:disabled) {
|
.login-btn:hover:not(:disabled) {
|
||||||
transform: translateY(-2px);
|
transform: translateY(-2px);
|
||||||
box-shadow: 0 0 20px rgba(0, 175, 255, 0.7);
|
box-shadow: 0 0 20px rgba(0, 175, 255, 0.7);
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-btn:disabled {
|
.login-btn:disabled {
|
||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
}
|
}
|
||||||
.auth-buttons {
|
.auth-buttons {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
margin-top: 1.5rem;
|
margin-top: 1.5rem;
|
||||||
}
|
}
|
||||||
.footer {
|
.footer {
|
||||||
margin-top: 1.5rem;
|
margin-top: 1.5rem;
|
||||||
color: rgba(255, 255, 255, 0.6);
|
color: rgba(255, 255, 255, 0.6);
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
.register-btn:hover:not(:disabled) {
|
.register-btn:hover:not(:disabled) {
|
||||||
transform: translateY(-2px);
|
transform: translateY(-2px);
|
||||||
box-shadow: 0 0 20px rgba(255, 107, 107, 0.7);
|
box-shadow: 0 0 20px rgba(255, 107, 107, 0.7);
|
||||||
}
|
}
|
||||||
|
|
||||||
.register-btn:disabled {
|
.register-btn:disabled {
|
||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -24,13 +24,13 @@ export default defineConfig({
|
|||||||
manifest: true,
|
manifest: true,
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
output: {
|
output: {
|
||||||
entryFileNames: 'js/[name].[hash].js',
|
entryFileNames: 'js/index.js',
|
||||||
chunkFileNames: 'js/[name].[hash].js',
|
chunkFileNames: 'js/[name].js',
|
||||||
assetFileNames: (assetInfo) => {
|
assetFileNames: (assetInfo) => {
|
||||||
if (assetInfo.name.endsWith('.css')) {
|
if (assetInfo.name.endsWith('.css')) {
|
||||||
return 'css/[name].[hash].[ext]';
|
return 'css/index.css';
|
||||||
}
|
}
|
||||||
return 'assets/[name].[hash].[ext]';
|
return 'assets/[name][extname]';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,9 +42,9 @@ export default defineConfig({
|
|||||||
format: 'umd', // 设置输出格式为 UMD
|
format: 'umd', // 设置输出格式为 UMD
|
||||||
name: 'SundererApp', // 指定全局变量名,构建后应用会挂载到 window.IncreaseAccApp
|
name: 'SundererApp', // 指定全局变量名,构建后应用会挂载到 window.IncreaseAccApp
|
||||||
// 可以保留 hash 以利用缓存,但 UMD 通常用于简单场景,可选
|
// 可以保留 hash 以利用缓存,但 UMD 通常用于简单场景,可选
|
||||||
entryFileNames: 'js/sundererapp.[hash].js', // 例如: increaseacc.js (或 [name].[hash].js)
|
entryFileNames: 'js/sundererapp.js', // 例如: increaseacc.js (或 [name].[hash].js)
|
||||||
chunkFileNames: 'js/sundererapp.[hash].js',
|
chunkFileNames: 'js/[name].js',
|
||||||
assetFileNames: 'js/sundererapp.[hash].[ext]', // 例如: increaseacc.css (或 [name].[hash].[ext])
|
assetFileNames: 'assets/[name][extname]', // 例如: increaseacc.css (或 [name].[hash].[ext])
|
||||||
// UMD 格式可能需要外部依赖,如果 Vue 是全局引入的,需要声明
|
// UMD 格式可能需要外部依赖,如果 Vue 是全局引入的,需要声明
|
||||||
// globals: {
|
// globals: {
|
||||||
// vue: 'Vue' // 假设 Vue 已通过 script 标签全局引入
|
// vue: 'Vue' // 假设 Vue 已通过 script 标签全局引入
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
+24
-2
@@ -1,11 +1,33 @@
|
|||||||
{
|
{
|
||||||
"index.html": {
|
"index.html": {
|
||||||
"file": "js/index.c1R21Jxr.js",
|
"file": "js/index.js",
|
||||||
"name": "index",
|
"name": "index",
|
||||||
"src": "index.html",
|
"src": "index.html",
|
||||||
"isEntry": true,
|
"isEntry": true,
|
||||||
|
"dynamicImports": [
|
||||||
|
"src/views/sundererapp/DashboardView.vue",
|
||||||
|
"src/views/sundererapp/UsersView.vue"
|
||||||
|
],
|
||||||
"css": [
|
"css": [
|
||||||
"css/index.CJO3dQ9s.css"
|
"css/index.css"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"src/views/sundererapp/DashboardView.vue": {
|
||||||
|
"file": "js/DashboardView.js",
|
||||||
|
"name": "DashboardView",
|
||||||
|
"src": "src/views/sundererapp/DashboardView.vue",
|
||||||
|
"isDynamicEntry": true,
|
||||||
|
"imports": [
|
||||||
|
"index.html"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"src/views/sundererapp/UsersView.vue": {
|
||||||
|
"file": "js/UsersView.js",
|
||||||
|
"name": "UsersView",
|
||||||
|
"src": "src/views/sundererapp/UsersView.vue",
|
||||||
|
"isDynamicEntry": true,
|
||||||
|
"imports": [
|
||||||
|
"index.html"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+2
-2
@@ -5,8 +5,8 @@
|
|||||||
<link rel="icon" type="image/svg+xml" href="/assets/sunderer_app/dist/icon3.svg" />
|
<link rel="icon" type="image/svg+xml" href="/assets/sunderer_app/dist/icon3.svg" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>决裂者终端用户中心</title>
|
<title>决裂者终端用户中心</title>
|
||||||
<script type="module" crossorigin src="/assets/sunderer_app/dist/js/index.c1R21Jxr.js"></script>
|
<script type="module" crossorigin src="/assets/sunderer_app/dist/js/index.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/assets/sunderer_app/dist/css/index.CJO3dQ9s.css">
|
<link rel="stylesheet" crossorigin href="/assets/sunderer_app/dist/css/index.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
import{c as l,a as e,b as c,w as o,r as a,o as d,d as _}from"./index.js";const u={__name:"DashboardView",setup(i){return(p,t)=>{const n=a("n-h2"),s=a("n-statistic"),r=a("n-card");return d(),l("div",null,[e(n,null,{default:o(()=>[...t[0]||(t[0]=[_("Dashboard",-1)])]),_:1}),t[1]||(t[1]=c("p",null,"Welcome to your admin dashboard!",-1)),e(r,{title:"Quick Stats",style:{"margin-top":"20px"}},{default:o(()=>[e(s,{label:"Total Users",value:"12345"})]),_:1})])}}};export{u as default};
|
||||||
+261
File diff suppressed because one or more lines are too long
-25
File diff suppressed because one or more lines are too long
Vendored
+56
File diff suppressed because one or more lines are too long
@@ -16,6 +16,6 @@
|
|||||||
<!-- 构建后文件会出现在 sunderer_app/public/ 目录下,例如: sundererapp.a1b2c3d4.js -->
|
<!-- 构建后文件会出现在 sunderer_app/public/ 目录下,例如: sundererapp.a1b2c3d4.js -->
|
||||||
<!-- 所以这里的 src 应该是 /sundererapp.[hash].js -->
|
<!-- 所以这里的 src 应该是 /sundererapp.[hash].js -->
|
||||||
<!-- 注意:你需要将 [hash] 替换为实际构建后生成的哈希值 -->
|
<!-- 注意:你需要将 [hash] 替换为实际构建后生成的哈希值 -->
|
||||||
<script src="/assets/sunderer_app/SundererPage/js/sundererapp.BRnFqPg_.js"></script>
|
<script src="/assets/sunderer_app/SundererPage/js/sundererapp.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -5,8 +5,8 @@
|
|||||||
<link rel="icon" type="image/svg+xml" href="/assets/sunderer_app/dist/icon3.svg" />
|
<link rel="icon" type="image/svg+xml" href="/assets/sunderer_app/dist/icon3.svg" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>决裂者终端用户中心</title>
|
<title>决裂者终端用户中心</title>
|
||||||
<script type="module" crossorigin src="/assets/sunderer_app/dist/js/index.c1R21Jxr.js"></script>
|
<script type="module" crossorigin src="/assets/sunderer_app/dist/js/index.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/assets/sunderer_app/dist/css/index.CJO3dQ9s.css">
|
<link rel="stylesheet" crossorigin href="/assets/sunderer_app/dist/css/index.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
|
|||||||
@@ -16,6 +16,6 @@
|
|||||||
<!-- 构建后文件会出现在 sunderer_app/public/ 目录下,例如: sundererapp.a1b2c3d4.js -->
|
<!-- 构建后文件会出现在 sunderer_app/public/ 目录下,例如: sundererapp.a1b2c3d4.js -->
|
||||||
<!-- 所以这里的 src 应该是 /sundererapp.[hash].js -->
|
<!-- 所以这里的 src 应该是 /sundererapp.[hash].js -->
|
||||||
<!-- 注意:你需要将 [hash] 替换为实际构建后生成的哈希值 -->
|
<!-- 注意:你需要将 [hash] 替换为实际构建后生成的哈希值 -->
|
||||||
<script src="/assets/sunderer_app/SundererPage/js/sundererapp.BRnFqPg_.js"></script>
|
<script src="/assets/sunderer_app/SundererPage/js/sundererapp.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
Reference in New Issue
Block a user