Files
yphsalumni.org/app/components/PhoneInput.vue
xiaomai e7f2bc2c47 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.
2025-10-22 21:40:30 +08:00

65 lines
1.5 KiB
Vue

<!-- ~/components/PhoneInput.vue -->
<script setup lang="ts">
import { USelectMenu, UInput } from "#components";
import { useCountries } from "~/composables/useCountries";
interface Props {
modelValue?: string;
defaultDial?: string;
}
const props = defineProps<Props>();
const emit = defineEmits(["update:modelValue", "update:country"]);
const { getAll } = useCountries();
// 当前选中国家
const selectedCountry = ref(
getAll().find((c) => c.dial === props.defaultDial)?.dial || getAll()[0]?.dial
);
console.table(getAll().map(c => ({ name: c.name.cn, dial: c.dial })));
// 用户输入的电话号码
const phone = ref(props.modelValue || "");
// 计算选项
const countryOptions = computed(() =>
getAll()
.filter((c) => c.dial && c.dial.trim() !== "")
.map((c) => ({
label: `${c.name.cn} (${c.dial || "未知"})`,
id: c.dial || "unknown",
}))
);
// 完整号码输出
const fullNumber = computed(() => {
const dial = selectedCountry.value || "";
return `${dial}${phone.value}`;
});
// 双向绑定
watch(phone, () => emit("update:modelValue", fullNumber.value));
watch(selectedCountry, () => emit("update:country", selectedCountry.value));
</script>
<template>
<div class="flex items-center gap-2">
<!-- 国家区号选择 -->
<USelectMenu
v-model="selectedCountry"
value-key="id"
:items="countryOptions"
/>
<!-- 电话号码输入 -->
<UInput
v-model="phone"
placeholder="输入电话号码"
type="tel"
class="flex-1"
/>
</div>
</template>