feat: support set user phone

This commit is contained in:
2025-12-20 14:27:29 +08:00
parent 8e95dada82
commit 0185e51396
5 changed files with 135 additions and 6 deletions

View File

@@ -18,6 +18,11 @@ export const userService = {
balance
});
},
setPhone(id, phone) {
return httpClient.post(`/users/${id}/phone`, {
phone
});
},
getUser(id) {
return httpClient.get(`/users/${id}`);
},
@@ -35,4 +40,4 @@ export const userService = {
}
});
}
}
}

View File

@@ -6,6 +6,7 @@ import Button from 'primevue/button';
import Column from 'primevue/column';
import ConfirmDialog from 'primevue/confirmdialog';
import DataTable from 'primevue/datatable';
import Dialog from 'primevue/dialog';
import InputText from 'primevue/inputtext';
import ProgressSpinner from 'primevue/progressspinner';
import Toast from 'primevue/toast';
@@ -36,6 +37,11 @@ const users = ref({
const first = ref(0);
const rows = ref(10);
const phoneDialogVisible = ref(false);
const phoneSaving = ref(false);
const phoneTargetUser = ref(null);
const phoneInput = ref('');
const fetchUsers = async () => {
loading.value = true;
try {
@@ -100,6 +106,36 @@ const handleRecharge = (user) => {
});
};
const openPhoneDialog = (user) => {
phoneTargetUser.value = user;
phoneInput.value = (user?.phone || '').toString();
phoneDialogVisible.value = true;
};
const normalizePhone = (v) => v.toString().replace(/\D/g, '').slice(0, 11);
const savePhone = async () => {
if (!phoneTargetUser.value) return;
const phone = normalizePhone(phoneInput.value);
if (phone.length !== 11) {
toast.add({ severity: 'error', summary: '错误', detail: '手机号必须为 11 位数字', life: 3000 });
return;
}
phoneSaving.value = true;
try {
await userService.setPhone(phoneTargetUser.value.id, phone);
toast.add({ severity: 'success', summary: '成功', detail: '手机号已更新', life: 3000 });
phoneDialogVisible.value = false;
await fetchUsers();
} catch (error) {
console.error('Failed to set phone:', error);
toast.add({ severity: 'error', summary: '错误', detail: error?.response?.data?.message || '设置手机号失败', life: 3000 });
} finally {
phoneSaving.value = false;
}
};
onMounted(() => {
fetchUsers();
});
@@ -108,6 +144,25 @@ onMounted(() => {
<template>
<Toast />
<ConfirmDialog />
<Dialog v-model:visible="phoneDialogVisible" modal header="设置手机号" :style="{ width: '420px' }">
<div class="space-y-3">
<div class="text-sm text-gray-600" v-if="phoneTargetUser">
用户{{ phoneTargetUser.username }}ID: {{ phoneTargetUser.id }}
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">手机号</label>
<InputText v-model="phoneInput" class="w-full" placeholder="请输入 11 位手机号" inputmode="numeric"
maxlength="11" @input="(e) => phoneInput = normalizePhone(e.target.value)" />
</div>
</div>
<template #footer>
<div class="flex justify-end gap-2">
<Button label="取消" text @click="phoneDialogVisible = false" />
<Button label="保存" severity="success" :loading="phoneSaving" @click="savePhone" />
</div>
</template>
</Dialog>
<div class="w-full">
<div class="flex justify-between items-center mb-6">
@@ -164,7 +219,7 @@ onMounted(() => {
</template>
</Column>
<Column field="open_id" header="OpenID" sortable></Column>
<Column field="phone" header="Phone" sortable></Column>
<Column field="status" header="状态" sortable>
<template #body="{ data }">
@@ -187,6 +242,8 @@ onMounted(() => {
<div class="flex justify-center space-x-2">
<Button icon="pi pi-credit-card" rounded text severity="success"
@click="handleRecharge(data)" label="充值" />
<Button icon="pi pi-phone" rounded text severity="info" @click="openPhoneDialog(data)"
label="设置手机号" />
</div>
</template>
</Column>