feat(admin): implement initial admin dashboard and member management

This commit introduces the foundational structure for the admin dashboard, focusing on the member management feature.
Key additions include:

- A new page at `/admin/manage/members` to display and manage members.
- An `AddModal` component with a comprehensive form for creating new members, featuring validation with Zod and input
masking.
- A reusable `PhoneInput` component with country code selection, backed by a new `useCountries` composable and a full
country dataset.
- A custom, user-friendly global error page (`error.vue`) to handle application errors gracefully.
- Updated dashboard sidebar navigation to include the new member management section.
- Added recommended VS Code extensions and settings to improve developer experience.
This commit is contained in:
xiaomai
2025-10-22 21:40:30 +08:00
parent 1fedf7094c
commit e7f2bc2c47
11 changed files with 3902 additions and 3 deletions

View File

@@ -0,0 +1,76 @@
import { countries, type Country } from "~/data/countries";
/**
* 🌍 useCountries composable
* 提供国家相关的搜索、过滤、分组、查找等功能
*/
export const useCountries = () => {
/**
* 获取全部国家
*/
const getAll = (): Country[] => countries;
/**
* 按洲分组
*/
const groupedByContinent = computed(() => {
const groups: Record<string, Country[]> = {};
for (const c of countries) {
const key = c.continent || "Unknown";
if (!groups[key]) groups[key] = [];
groups[key].push(c);
}
return groups;
});
/**
* 按名称搜索(支持多语言字段)
* @param query 搜索关键字
*/
const search = (query: string) => {
if (!query) return countries;
const q = query.toLowerCase();
return countries.filter((c) =>
Object.values(c.name).some((name) => name.toLowerCase().includes(q))
);
};
/**
* 根据国家代码查找
* @param code ISO Alpha-2 或 Alpha-3 代码
*/
const findByCode = (code: string) => {
const upper = code.toUpperCase();
return countries.find((c) => c.code === upper || c.iso3 === upper);
};
/**
* 获取特定语言的显示名称
* @param country 国家对象
* @param lang 语言代码(默认为 en
*/
const getDisplayName = (
country: Country,
lang: keyof Country["name"] = "en"
) => {
return country.name?.[lang] || country.name.en;
};
/**
* 根据洲名筛选
* @param continent 洲名(如 'Asia'、'Europe'
*/
const filterByContinent = (continent: string) => {
const key = continent.trim().toLowerCase();
return countries.filter((c) => c.continent.toLowerCase() === key);
};
return {
getAll,
groupedByContinent,
search,
findByCode,
filterByContinent,
getDisplayName,
};
};