Initial import of frappe sunderer app

This commit is contained in:
microYF
2026-04-23 14:45:47 +00:00
parent 283972860c
commit 0f323e8d41
17 changed files with 3239 additions and 469 deletions
-4
View File
@@ -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>
+257 -257
View File
@@ -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>
+4 -4
View File
@@ -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]';
} }
} }
} }
+3 -3
View File
@@ -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
View File
@@ -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"
] ]
} }
} }
File diff suppressed because one or more lines are too long
+2 -2
View File
@@ -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>
+1
View File
@@ -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};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
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>
+2 -2
View File
@@ -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>
+1 -1
View File
@@ -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>