refactor: frontend TS migration + Tailwind4/daisyUI5 unify + BUILDPLATFORM docker build
- migrate frontend to TypeScript (vue-tsc strict in build), upgrade all deps to latest (Vite 8, Tailwind 4, daisyUI 5, Pinia 4, vue-router 5) - restructure frontend dirs (api/components/common/layouts/styles/types/views) - drop Element Plus, add daisyUI TagInput; main CSS 490KB->163KB, entry JS 618KB->1.3KB - rewrite Dockerfile(.cn): frontend/backend stages pinned to $BUILDPLATFORM, CGO_ENABLED=0 cross-compile, no QEMU in multi-arch builds; add .dockerignore - local dev: Vite /api proxy + make dev targets; go:embed all:dist with .gitkeep so backend runs without prior frontend build - fix latent bugs: Keys.vue users ref, Settings.vue undefined userStore, Login.vue Ref-as-error display, res.error misuse - add REFACTOR_PLAN.md (phased refactor log)
This commit is contained in:
@@ -214,22 +214,24 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted, inject } from 'vue';
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { Eye, EyeOff, BadgeCheck, Send, CircleX, CircleCheckBig, TrashIcon, Infinity } from 'lucide-vue-next'; // Ensure lucide-vue-next is installed
|
||||
import { useUserStore } from '../../stores/user';
|
||||
import { Eye, EyeOff, BadgeCheck, Send, CircleX, CircleCheckBig, TrashIcon, Infinity } from '@lucide/vue';
|
||||
import { useUserStore } from '@/stores/user';
|
||||
import BreadcrumbHeader from '@/components/dashboard/BreadcrumbHeader.vue';
|
||||
import { useToast } from '@/composables/toast';
|
||||
import type { UserInfo, TokenInfo } from '@/types';
|
||||
|
||||
const route = useRoute();
|
||||
const userStore = useUserStore();
|
||||
const { setToast } = inject('toast');
|
||||
const { setToast } = useToast();
|
||||
|
||||
const userId = computed(() => route.query.id);
|
||||
|
||||
onMounted(async () => {
|
||||
if (userId.value) {
|
||||
await userStore.getUser(userId.value);
|
||||
await userStore.getUser(userId.value as string);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -237,7 +239,7 @@ const user = computed(() => userStore.user);
|
||||
const loading = computed(() => userStore.loading); // Access loading state
|
||||
|
||||
// 更新状态
|
||||
const updateStatus = async (user) => {
|
||||
const updateStatus = async (user: UserInfo) => {
|
||||
try {
|
||||
const action = user.active ? 'enable' : 'disable';
|
||||
const res = await userStore.userOption(action, [user.id]);
|
||||
@@ -247,7 +249,7 @@ const updateStatus = async (user) => {
|
||||
setToast(res.data?.error || `用户 ${user.id} ${action} 失败`, 'error');
|
||||
}
|
||||
await userStore.refreshUser(user.id);
|
||||
} catch (error) {
|
||||
} catch (error: any) {
|
||||
user.active = !user.active;
|
||||
console.error('状态更新失败:', error);
|
||||
// setToast(error.response.data?.error || '状态更新失败', 'error');
|
||||
@@ -257,7 +259,7 @@ const updateStatus = async (user) => {
|
||||
const updateUser = async () => {
|
||||
if (!user.value) return;
|
||||
try {
|
||||
const payload = {
|
||||
const payload: Partial<UserInfo> = {
|
||||
name: user.value.name,
|
||||
username: user.value.username,
|
||||
email: user.value.email,
|
||||
@@ -270,13 +272,13 @@ const updateUser = async () => {
|
||||
if (user.value.password) {
|
||||
payload.password = user.value.password;
|
||||
}
|
||||
const res = await userStore.editUser(userId.value, payload);
|
||||
const res = await userStore.editUser(userId.value as string, payload);
|
||||
console.log('updateUser', res)
|
||||
if (res.data?.code == 200) {
|
||||
setToast(`User ${userId.value} updated`, 'success');
|
||||
}
|
||||
await userStore.refreshUser(userId.value);
|
||||
} catch (err) {
|
||||
await userStore.refreshUser(userId.value as string);
|
||||
} catch (err: any) {
|
||||
console.error('Error updating user:', err.response?.data?.data?.error);
|
||||
}
|
||||
};
|
||||
@@ -290,11 +292,11 @@ const togglePasswordVisibility = () => {
|
||||
};
|
||||
|
||||
// 格式化角色
|
||||
const formatRole = (role) => {
|
||||
const formatRole = (role?: number): string => {
|
||||
switch (true) {
|
||||
case role > 10:
|
||||
case (role ?? 0) > 10:
|
||||
return 'Root';
|
||||
case role > 0:
|
||||
case (role ?? 0) > 0:
|
||||
return 'Admin';
|
||||
default:
|
||||
return 'U';
|
||||
@@ -316,7 +318,7 @@ const formatRole = (role) => {
|
||||
// }
|
||||
|
||||
// 格式化日期
|
||||
const formatDate = (dateString) => {
|
||||
const formatDate = (dateString?: number): string | null => {
|
||||
if (!dateString) return null;
|
||||
try {
|
||||
return new Intl.DateTimeFormat('sv-SE', { dateStyle: 'short', timeStyle: 'short' }).format(new Date(dateString * 1000)); // Multiply by 1000 for JavaScript Date
|
||||
@@ -327,7 +329,7 @@ const formatDate = (dateString) => {
|
||||
};
|
||||
|
||||
// 删除token
|
||||
const revokeToken = (tokenId) => {
|
||||
const revokeToken = (tokenId: TokenInfo['id']) => {
|
||||
console.log('Revoking token:', tokenId);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user