style(frontend): 优化 Components 代码风格和结构

- 统一移除语句末尾分号,规范代码格式
- 优化组件类型定义和 props 声明
- 改进组件文档和示例代码
- 提升代码可读性和一致性
This commit is contained in:
ianshaw
2025-12-25 08:40:12 -08:00
parent 1ac8b1f03e
commit 5deef27e1d
38 changed files with 2582 additions and 1485 deletions

View File

@@ -8,31 +8,31 @@
<div class="space-y-6">
<h1 class="text-3xl font-bold text-gray-900">Dashboard</h1>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
<div class="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-4">
<!-- Stats Cards -->
<div class="bg-white p-6 rounded-lg shadow">
<div class="rounded-lg bg-white p-6 shadow">
<div class="text-sm text-gray-600">API Keys</div>
<div class="text-2xl font-bold text-gray-900">5</div>
</div>
<div class="bg-white p-6 rounded-lg shadow">
<div class="rounded-lg bg-white p-6 shadow">
<div class="text-sm text-gray-600">Total Usage</div>
<div class="text-2xl font-bold text-gray-900">1,234</div>
</div>
<div class="bg-white p-6 rounded-lg shadow">
<div class="rounded-lg bg-white p-6 shadow">
<div class="text-sm text-gray-600">Balance</div>
<div class="text-2xl font-bold text-indigo-600">${{ balance }}</div>
</div>
<div class="bg-white p-6 rounded-lg shadow">
<div class="rounded-lg bg-white p-6 shadow">
<div class="text-sm text-gray-600">Status</div>
<div class="text-2xl font-bold text-green-600">Active</div>
</div>
</div>
<div class="bg-white p-6 rounded-lg shadow">
<h2 class="text-xl font-semibold mb-4">Recent Activity</h2>
<div class="rounded-lg bg-white p-6 shadow">
<h2 class="mb-4 text-xl font-semibold">Recent Activity</h2>
<p class="text-gray-600">No recent activity</p>
</div>
</div>
@@ -40,12 +40,12 @@
</template>
<script setup lang="ts">
import { computed } from 'vue';
import { AppLayout } from '@/components/layout';
import { useAuthStore } from '@/stores';
import { computed } from 'vue'
import { AppLayout } from '@/components/layout'
import { useAuthStore } from '@/stores'
const authStore = useAuthStore();
const balance = computed(() => authStore.user?.balance.toFixed(2) || '0.00');
const authStore = useAuthStore()
const balance = computed(() => authStore.user?.balance.toFixed(2) || '0.00')
</script>
```
@@ -56,11 +56,11 @@ const balance = computed(() => authStore.user?.balance.toFixed(2) || '0.00');
```vue
<template>
<AuthLayout>
<h2 class="text-2xl font-bold text-gray-900 mb-6">Welcome Back</h2>
<h2 class="mb-6 text-2xl font-bold text-gray-900">Welcome Back</h2>
<form @submit.prevent="handleSubmit" class="space-y-4">
<div>
<label for="username" class="block text-sm font-medium text-gray-700 mb-1">
<label for="username" class="mb-1 block text-sm font-medium text-gray-700">
Username
</label>
<input
@@ -68,13 +68,13 @@ const balance = computed(() => authStore.user?.balance.toFixed(2) || '0.00');
v-model="form.username"
type="text"
required
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-transparent"
class="w-full rounded-lg border border-gray-300 px-3 py-2 focus:border-transparent focus:ring-2 focus:ring-indigo-500"
placeholder="Enter your username"
/>
</div>
<div>
<label for="password" class="block text-sm font-medium text-gray-700 mb-1">
<label for="password" class="mb-1 block text-sm font-medium text-gray-700">
Password
</label>
<input
@@ -82,7 +82,7 @@ const balance = computed(() => authStore.user?.balance.toFixed(2) || '0.00');
v-model="form.password"
type="password"
required
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-transparent"
class="w-full rounded-lg border border-gray-300 px-3 py-2 focus:border-transparent focus:ring-2 focus:ring-indigo-500"
placeholder="Enter your password"
/>
</div>
@@ -90,7 +90,7 @@ const balance = computed(() => authStore.user?.balance.toFixed(2) || '0.00');
<button
type="submit"
:disabled="loading"
class="w-full bg-indigo-600 text-white py-2 px-4 rounded-lg hover:bg-indigo-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
class="w-full rounded-lg bg-indigo-600 px-4 py-2 text-white transition-colors hover:bg-indigo-700 disabled:cursor-not-allowed disabled:opacity-50"
>
{{ loading ? 'Logging in...' : 'Login' }}
</button>
@@ -99,7 +99,7 @@ const balance = computed(() => authStore.user?.balance.toFixed(2) || '0.00');
<template #footer>
<p class="text-gray-600">
Don't have an account?
<router-link to="/register" class="text-indigo-600 hover:underline font-medium">
<router-link to="/register" class="font-medium text-indigo-600 hover:underline">
Sign up
</router-link>
</p>
@@ -108,32 +108,32 @@ const balance = computed(() => authStore.user?.balance.toFixed(2) || '0.00');
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { useRouter } from 'vue-router';
import { AuthLayout } from '@/components/layout';
import { useAuthStore, useAppStore } from '@/stores';
import { ref } from 'vue'
import { useRouter } from 'vue-router'
import { AuthLayout } from '@/components/layout'
import { useAuthStore, useAppStore } from '@/stores'
const router = useRouter();
const authStore = useAuthStore();
const appStore = useAppStore();
const router = useRouter()
const authStore = useAuthStore()
const appStore = useAppStore()
const form = ref({
username: '',
password: '',
});
password: ''
})
const loading = ref(false);
const loading = ref(false)
async function handleSubmit() {
loading.value = true;
loading.value = true
try {
await authStore.login(form.value);
appStore.showSuccess('Login successful!');
await router.push('/dashboard');
await authStore.login(form.value)
appStore.showSuccess('Login successful!')
await router.push('/dashboard')
} catch (error) {
appStore.showError('Invalid username or password');
appStore.showError('Invalid username or password')
} finally {
loading.value = false;
loading.value = false
}
}
</script>
@@ -152,42 +152,42 @@ async function handleSubmit() {
<h1 class="text-3xl font-bold text-gray-900">API Keys</h1>
<button
@click="showCreateModal = true"
class="bg-indigo-600 text-white px-4 py-2 rounded-lg hover:bg-indigo-700 transition-colors"
class="rounded-lg bg-indigo-600 px-4 py-2 text-white transition-colors hover:bg-indigo-700"
>
Create New Key
</button>
</div>
<!-- API Keys List -->
<div class="bg-white rounded-lg shadow overflow-hidden">
<div class="overflow-hidden rounded-lg bg-white shadow">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
Name
</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
Key
</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
<th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-500">Name</th>
<th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-500">Key</th>
<th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-500">
Status
</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
<th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-500">
Created
</th>
<th class="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase">
<th class="px-6 py-3 text-right text-xs font-medium uppercase text-gray-500">
Actions
</th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200">
<tbody class="divide-y divide-gray-200 bg-white">
<tr v-for="key in apiKeys" :key="key.id">
<td class="px-6 py-4 whitespace-nowrap">{{ key.name }}</td>
<td class="whitespace-nowrap px-6 py-4">{{ key.name }}</td>
<td class="px-6 py-4 font-mono text-sm">{{ key.key }}</td>
<td class="px-6 py-4">
<span
class="px-2 py-1 text-xs rounded-full"
:class="key.status === 'active' ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'"
class="rounded-full px-2 py-1 text-xs"
:class="
key.status === 'active'
? 'bg-green-100 text-green-800'
: 'bg-red-100 text-red-800'
"
>
{{ key.status }}
</span>
@@ -196,9 +196,7 @@ async function handleSubmit() {
{{ new Date(key.created_at).toLocaleDateString() }}
</td>
<td class="px-6 py-4 text-right">
<button class="text-red-600 hover:text-red-800 text-sm">
Delete
</button>
<button class="text-sm text-red-600 hover:text-red-800">Delete</button>
</td>
</tr>
</tbody>
@@ -209,12 +207,12 @@ async function handleSubmit() {
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { AppLayout } from '@/components/layout';
import type { ApiKey } from '@/types';
import { ref } from 'vue'
import { AppLayout } from '@/components/layout'
import type { ApiKey } from '@/types'
const showCreateModal = ref(false);
const apiKeys = ref<ApiKey[]>([]);
const showCreateModal = ref(false)
const apiKeys = ref<ApiKey[]>([])
// Fetch API keys on mount
// fetchApiKeys();
@@ -233,34 +231,40 @@ const apiKeys = ref<ApiKey[]>([]);
<h1 class="text-3xl font-bold text-gray-900">User Management</h1>
<button
@click="showCreateUser = true"
class="bg-indigo-600 text-white px-4 py-2 rounded-lg hover:bg-indigo-700 transition-colors"
class="rounded-lg bg-indigo-600 px-4 py-2 text-white transition-colors hover:bg-indigo-700"
>
Create User
</button>
</div>
<!-- Users Table -->
<div class="bg-white rounded-lg shadow">
<div class="rounded-lg bg-white shadow">
<div class="p-6">
<div class="space-y-4">
<div v-for="user in users" :key="user.id" class="flex items-center justify-between border-b pb-4">
<div
v-for="user in users"
:key="user.id"
class="flex items-center justify-between border-b pb-4"
>
<div>
<div class="font-medium text-gray-900">{{ user.username }}</div>
<div class="text-sm text-gray-500">{{ user.email }}</div>
</div>
<div class="flex items-center space-x-4">
<span
class="px-2 py-1 text-xs rounded-full"
:class="user.role === 'admin' ? 'bg-purple-100 text-purple-800' : 'bg-blue-100 text-blue-800'"
class="rounded-full px-2 py-1 text-xs"
:class="
user.role === 'admin'
? 'bg-purple-100 text-purple-800'
: 'bg-blue-100 text-blue-800'
"
>
{{ user.role }}
</span>
<span class="text-sm font-medium text-gray-700">
${{ user.balance.toFixed(2) }}
</span>
<button class="text-indigo-600 hover:text-indigo-800 text-sm">
Edit
</button>
<button class="text-sm text-indigo-600 hover:text-indigo-800">Edit</button>
</div>
</div>
</div>
@@ -271,12 +275,12 @@ const apiKeys = ref<ApiKey[]>([]);
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { AppLayout } from '@/components/layout';
import type { User } from '@/types';
import { ref } from 'vue'
import { AppLayout } from '@/components/layout'
import type { User } from '@/types'
const showCreateUser = ref(false);
const users = ref<User[]>([]);
const showCreateUser = ref(false)
const users = ref<User[]>([])
// Fetch users on mount
// fetchUsers();
@@ -294,36 +298,34 @@ const users = ref<User[]>([]);
<h1 class="text-3xl font-bold text-gray-900">Profile Settings</h1>
<!-- User Info Card -->
<div class="bg-white rounded-lg shadow p-6 space-y-4">
<div class="space-y-4 rounded-lg bg-white p-6 shadow">
<h2 class="text-xl font-semibold text-gray-900">Account Information</h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">
Username
</label>
<div class="px-3 py-2 bg-gray-50 rounded-lg text-gray-900">
<label class="mb-1 block text-sm font-medium text-gray-700"> Username </label>
<div class="rounded-lg bg-gray-50 px-3 py-2 text-gray-900">
{{ user?.username }}
</div>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">
Email
</label>
<div class="px-3 py-2 bg-gray-50 rounded-lg text-gray-900">
<label class="mb-1 block text-sm font-medium text-gray-700"> Email </label>
<div class="rounded-lg bg-gray-50 px-3 py-2 text-gray-900">
{{ user?.email }}
</div>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">
Role
</label>
<div class="px-3 py-2 bg-gray-50 rounded-lg">
<label class="mb-1 block text-sm font-medium text-gray-700"> Role </label>
<div class="rounded-lg bg-gray-50 px-3 py-2">
<span
class="px-2 py-1 text-xs rounded-full"
:class="user?.role === 'admin' ? 'bg-purple-100 text-purple-800' : 'bg-blue-100 text-blue-800'"
class="rounded-full px-2 py-1 text-xs"
:class="
user?.role === 'admin'
? 'bg-purple-100 text-purple-800'
: 'bg-blue-100 text-blue-800'
"
>
{{ user?.role }}
</span>
@@ -331,10 +333,8 @@ const users = ref<User[]>([]);
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">
Balance
</label>
<div class="px-3 py-2 bg-gray-50 rounded-lg text-indigo-600 font-semibold">
<label class="mb-1 block text-sm font-medium text-gray-700"> Balance </label>
<div class="rounded-lg bg-gray-50 px-3 py-2 font-semibold text-indigo-600">
${{ user?.balance.toFixed(2) }}
</div>
</div>
@@ -342,12 +342,12 @@ const users = ref<User[]>([]);
</div>
<!-- Change Password Card -->
<div class="bg-white rounded-lg shadow p-6 space-y-4">
<div class="space-y-4 rounded-lg bg-white p-6 shadow">
<h2 class="text-xl font-semibold text-gray-900">Change Password</h2>
<form @submit.prevent="handleChangePassword" class="space-y-4">
<div>
<label for="old-password" class="block text-sm font-medium text-gray-700 mb-1">
<label for="old-password" class="mb-1 block text-sm font-medium text-gray-700">
Current Password
</label>
<input
@@ -355,12 +355,12 @@ const users = ref<User[]>([]);
v-model="passwordForm.old_password"
type="password"
required
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500"
class="w-full rounded-lg border border-gray-300 px-3 py-2 focus:ring-2 focus:ring-indigo-500"
/>
</div>
<div>
<label for="new-password" class="block text-sm font-medium text-gray-700 mb-1">
<label for="new-password" class="mb-1 block text-sm font-medium text-gray-700">
New Password
</label>
<input
@@ -368,13 +368,13 @@ const users = ref<User[]>([]);
v-model="passwordForm.new_password"
type="password"
required
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500"
class="w-full rounded-lg border border-gray-300 px-3 py-2 focus:ring-2 focus:ring-indigo-500"
/>
</div>
<button
type="submit"
class="bg-indigo-600 text-white px-4 py-2 rounded-lg hover:bg-indigo-700 transition-colors"
class="rounded-lg bg-indigo-600 px-4 py-2 text-white transition-colors hover:bg-indigo-700"
>
Update Password
</button>
@@ -385,27 +385,27 @@ const users = ref<User[]>([]);
</template>
<script setup lang="ts">
import { ref, computed } from 'vue';
import { AppLayout } from '@/components/layout';
import { useAuthStore, useAppStore } from '@/stores';
import { ref, computed } from 'vue'
import { AppLayout } from '@/components/layout'
import { useAuthStore, useAppStore } from '@/stores'
const authStore = useAuthStore();
const appStore = useAppStore();
const authStore = useAuthStore()
const appStore = useAppStore()
const user = computed(() => authStore.user);
const user = computed(() => authStore.user)
const passwordForm = ref({
old_password: '',
new_password: '',
});
new_password: ''
})
async function handleChangePassword() {
try {
// await changePasswordAPI(passwordForm.value);
appStore.showSuccess('Password updated successfully!');
passwordForm.value = { old_password: '', new_password: '' };
appStore.showSuccess('Password updated successfully!')
passwordForm.value = { old_password: '', new_password: '' }
} catch (error) {
appStore.showError('Failed to update password');
appStore.showError('Failed to update password')
}
}
</script>