This commit is contained in:
李远 2026-03-16 18:32:11 +08:00
parent 6d180b94a8
commit 05650ed956
7 changed files with 607 additions and 212 deletions

View File

@ -49,8 +49,8 @@ export async function changePasswordApi(params: ChangePasswordParams) {
* 退
* @returns Promise<void>
*/
export async function logoutApi() {
return request.post<void>('/logout');
export async function logoutApi(params: { device_no: string }) {
return request.post<void>('/logout', params);
}
/**

View File

@ -59,7 +59,8 @@ const handleChangePassword = () => {
const handleLogout = () => {
// 退
userStore.logout()
const deviceNo = getStorage('device_no') as string
userStore.logout({ device_no: deviceNo })
}
//

View File

@ -55,7 +55,7 @@ const clearUserInfo = () => {
removeStorage('userInfo');
removeStorage('menusInfo');
removeStorage('permissionsInfo');
removeStorage('device_no');
console.log('用户信息已清空');
};
@ -100,9 +100,9 @@ const register = async (params: RegisterParams) => {
/**
* 退
*/
const logout = async () => {
const logout = async (params: { device_no: string }) => {
try {
await logoutApi();
await logoutApi(params);
} catch (error) {
console.error('退出登录接口调用失败', error);
} finally {

View File

@ -9,10 +9,11 @@
</el-button>
</template>
</ClientSearch>
<ClientTable :table-data="clientTree" :columns="clientTableColumns" row-key="id" :tree-props="treeProps">
<!-- 表格组件 -->
<ClientTable :table-data="clientTree" :columns="clientTableColumns">
<template #status="{ row }">
<el-switch :model-value="row.status === 1" :active-value="true" :inactive-value="false" active-text="启用"
inactive-text="禁用" />
<el-switch :model-value="row.status === 1" :active-value="true" :inactive-value="false" />
</template>
<template #action="{ row }">
<el-button type="primary" size="small" @click="handleChange(row)">
@ -20,8 +21,9 @@
</el-button>
</template>
</ClientTable>
<ClientPagination :modelValue="clientSearchForm.currentPage" :pageSizeValue="clientSearchForm.pageSize"
:total="total" @pagination-change="handlePaginationChange" />
<!-- 分页组件 -->
<ClientPagination v-model="currentPage" v-model:pageSizeValue="pageSize" :total="total"
@pagination-change="handlePaginationChange" />
</div>
<!-- 客户弹窗 -->
<ClientDialog :visible="dialogVisible" :title="dialogTitle" :type="dialogType" @confirm="handleSubmit"
@ -31,31 +33,32 @@
<template #phoneOrEmail="{ formData }">
<div class="phone-email">
<div class="tab-btn">
<el-button type="primary" size="small" :class="{ 'active': activeTab === 'email' }"
<el-button :type="activeTab === 'email' ? 'primary' : 'default'" size="small"
@click="activeTab = 'email'">
邮箱
</el-button>
<el-button type="primary" class="phone" size="small"
:class="{ 'active': activeTab === 'phone' }" @click="activeTab = 'phone'">
<el-button :type="activeTab === 'phone' ? 'primary' : 'default'" size="small"
@click="activeTab = 'phone'">
手机号
</el-button>
</div>
<el-form-item prop="email" v-if="activeTab === 'email'" class="email-item">
<el-input v-model="formData.email" placeholder="请输入邮箱"></el-input>
</el-form-item>
<el-form-item prop="phone" v-else class="phone-item">
<el-select v-model="formData.countryCode" :teleported="false" value-key="code" placeholder="国家"
class="country-select">
<el-option v-for="item in countryOptions" :key="item.code" :label="item.code"
:value="item.code">
<div class="country-option">
<span class="country-name">{{ item.name }}</span>
<span class="country-code">{{ item.code }}</span>
</div>
</el-option>
</el-select>
<el-input v-model="formData.phone" placeholder="请输入手机号" clearable />
</el-form-item>
<div class="group">
<el-form-item prop="email" v-if="activeTab === 'email'">
<el-input v-model="clientForm.email" placeholder="请输入邮箱" />
</el-form-item>
<el-form-item prop="phone" class="phone-item" v-if="activeTab === 'phone'">
<el-select v-model="clientForm.countryCode" placeholder="请选择国家区号">
<el-option v-for="item in countryOptions" :key="item.code" :label="item.code"
:value="item.code">
<div class="country-option">
<span class="country-name">{{ item.name }}</span>
<span class="country-code">{{ item.code }}</span>
</div>
</el-option>
</el-select>
<el-input v-model="clientForm.phone" placeholder="请输入手机号" />
</el-form-item>
</div>
</div>
</template>
</ClientForm>
@ -76,31 +79,38 @@ import { getClientListApi, getFeeTemplateOptionsApi, getRiskTemplateOptionsApi,
import { clientSearch, clientAddFormItem, clientChangeFormItem, countryOptions, clientTableColumns } from './options'
import { rules } from './rules'
//
/**
* @description 定义搜索数据
*/
const clientSearchOptions = ref(clientSearch)
const clientSearchForm = ref({
currentPage: 1,
pageSize: 1,
username: '',
status: '正常',
startDateTime: '',
endDateTime: '',
})
//
/**
* @description 定义表格数据
*/
const clientTree = ref<any[]>([])
const treeProps = ref({
children: 'parent',
label: 'username'
})
//
/**
* @description 定义分页数据
*/
const total = ref(0)
const currentPage = ref(1)
const pageSize = ref(10)
// dialog
/**
* @description 定义dialog数据
*/
const dialogTitle = ref('')
const dialogVisible = ref(false)
const dialogType = ref('add')
/**
* @description 定义dialog中form的数据
*/
const clientForm = ref({
//
feeTemplate: '',
@ -116,28 +126,18 @@ const clientForm = ref({
//
userName: '',
status: 1,
id: '',
})
//
const clientFormRef = ref()
const clientFormRules = ref(rules())
const clientFormOptions = ref<any[]>(clientAddFormItem)
//
const activeTab = ref('email')
//
interface FormOption {
label: string;
value: string | number;
}
interface ClientFormOptionsMap {
feeTemplate: FormOption[];
riskTemplate: FormOption[];
agentUsername: FormOption[];
isUpgrade: FormOption[];
status: FormOption[];
}
const clientFormOptionsMap = ref<ClientFormOptionsMap>({
//
const optionsFetched = ref(false)
const useId = ref('')
const clientFormOptions = computed(() => {
return dialogType.value === 'add' ? clientAddFormItem : clientChangeFormItem;
})
const clientFormOptionsMap = ref<any>({
feeTemplate: [],
riskTemplate: [],
agentUsername: [],
@ -150,62 +150,12 @@ const clientFormOptionsMap = ref<ClientFormOptionsMap>({
{ label: '禁用', value: 2 }
],
})
//
const activeTab = ref('email')
//
const fetchClientList = async () => {
const params = {
page: clientSearchForm.value.currentPage,
page_size: clientSearchForm.value.pageSize,
username: clientSearchForm.value.username,
status: clientSearchForm.value.status === '正常' ? 1 : 2,
reg_start_time: clientSearchForm.value.startDateTime.length > 0 ? `${clientSearchForm.value.startDateTime} 0:00:00` : '',
reg_end_time: clientSearchForm.value.endDateTime.length > 0 ? `${clientSearchForm.value.endDateTime} 23:59:59` : '',
}
const data = await getClientListApi(params)
clientTree.value = data.data.map(item => ({
...item,
//
agentUsername: item.par_uid === item.parent?.id ? item.parent?.username : '',
}));
//
total.value = Number(data.total)
clientSearchForm.value.currentPage = Number(data.current_page)
clientSearchForm.value.pageSize = Number(data.per_page)
}
onMounted(async () => {
await fetchClientList()
})
/**
* @description: 搜索事件
* @description 统一数据处理方法
*/
//
const handleSearch = async () => {
try {
await fetchClientList()
} catch (err) {
console.error('获取客户列表失败', err)
}
}
//
const handleReset = () => {
clientSearchForm.value = {
currentPage: 1,
pageSize: 1,
username: '',
status: '正常',
startDateTime: '',
endDateTime: '',
}
fetchClientList() //
}
//
const handleDialogType = (type: string) => {
clientFormOptions.value = type === 'add' ? clientAddFormItem : clientChangeFormItem
}
//
const mapObjectToOptions = (obj: Record<string, string>) => {
return Object.entries(obj).map(([label, value]) => ({
@ -214,8 +164,34 @@ const mapObjectToOptions = (obj: Record<string, string>) => {
}))
}
//
const optionsFetched = ref(false)
/**
* @description 统一获取数据方法
*/
const getClientList = async () => {
const params = {
page: currentPage.value,
page_size: pageSize.value,
username: clientSearchForm.value.username,
status: clientSearchForm.value.status === '正常' ? 1 : 2,
reg_start_time: clientSearchForm.value.startDateTime.length > 0 ? `${clientSearchForm.value.startDateTime} 0:00:00` : '',
reg_end_time: clientSearchForm.value.endDateTime.length > 0 ? `${clientSearchForm.value.endDateTime} 23:59:59` : '',
}
const data = await getClientListApi(params)
//
clientTree.value = data.data.map(item => ({
...item,
//
createdTime: item.created_at,
//
agentUsername: item.par_uid === item.parent?.id ? item.parent?.username : '',
}));
//
total.value = Number(data.total)
currentPage.value = Number(data.current_page)
pageSize.value = Number(data.per_page)
}
//
const getOptions = async () => {
//
if (optionsFetched.value) return
@ -227,7 +203,7 @@ const getOptions = async () => {
getRiskTemplateOptionsApi()
])
// label=value=ID
// label=value=ID
clientFormOptionsMap.value.agentUsername = mapObjectToOptions(agentRes as Record<string, string>)
clientFormOptionsMap.value.feeTemplate = mapObjectToOptions(feeTemplateRes as Record<string, string>)
clientFormOptionsMap.value.riskTemplate = mapObjectToOptions(riskTemplateRes as Record<string, string>)
@ -235,57 +211,90 @@ const getOptions = async () => {
optionsFetched.value = true //
} catch (error) {
console.error('获取表单选项失败:', error)
ElMessage.error('获取表单选项失败,请稍后重试')
}
}
//
/**
* @description 页面加载后获取数据
*/
onMounted(async () => {
await getClientList()
})
/**
* @description 搜索方法
*/
const handleSearch = async () => {
try {
await getClientList()
} catch (err) {
console.error('获取客户列表失败', err)
}
}
const handleReset = async () => {
//
clientSearchForm.value = {
username: '',
status: '正常',
startDateTime: '',
endDateTime: '',
}
try {
await getClientList()
} catch (err) {
console.error('获取客户列表失败', err)
}
}
//
const handleAdd = () => {
//
dialogVisible.value = true
dialogTitle.value = '添加客户'
dialogType.value = 'add'
clientForm.value = {
//
feeTemplate: '',
//
riskTemplate: '',
//
agentUsername: '',
email: '',
phone: '',
countryCode: '+86',
//
isUpgrade: 1,
//
userName: '',
status: 1,
}
getOptions()
}
/**
* @description 表格方法
*/
const handleChange = (row: any) => {
//
dialogVisible.value = true
dialogTitle.value = '修改客户'
dialogType.value = 'change'
useId.value = row.id
getOptions()
}
/**
* @description: 表格修改事件
* @description 分页方法
*/
const handleChange = async (row: any) => {
dialogVisible.value = true
dialogTitle.value = '修改客户'
dialogType.value = 'edit'
handleDialogType(dialogType.value)
//
await getOptions()
// id
clientForm.value = {
id: row.id, // ID
feeTemplate: row.feeTemplate || '', //
riskTemplate: row.riskTemplate || '', //
agentUsername: row.agentUsername || '', //
email: row.email || '', //
phone: row.phone || '', //
countryCode: row.countryCode || '+86', //
isUpgrade: row.isUpgrade || 1, //
userName: row.username || '', //
status: row.status || 1, //
}
}
//
const handlePaginationChange = (page: { currentPage: number, pageSize: number }) => {
clientSearchForm.value.currentPage = page.currentPage
clientSearchForm.value.pageSize = page.pageSize
currentPage.value = page.currentPage
pageSize.value = page.pageSize
handleSearch()
}
/**
* @description: dialog事件
* @description 客户弹窗方法
*/
//
const handleAdd = async () => {
dialogVisible.value = true
dialogType.value = 'add'
dialogTitle.value = '添加客户'
handleDialogType(dialogType.value)
//
await getOptions()
}
const handleSubmit = async () => {
try {
await clientFormRef.value?.validate()
@ -299,11 +308,11 @@ const handleSubmit = async () => {
fee_setting_id: clientForm.value.feeTemplate,
}
await createClientApi(params)
await fetchClientList()
await getClientList()
dialogVisible.value = false
} else {
const params = {
user_id: clientForm.value.id,
user_id: useId.value,
risk_control_id: clientForm.value.riskTemplate,
fee_setting_id: clientForm.value.feeTemplate,
username: clientForm.value.userName,
@ -311,87 +320,54 @@ const handleSubmit = async () => {
status: clientForm.value.status,
}
await editClientApi(params)
await fetchClientList()
await getClientList()
dialogVisible.value = false
}
} catch (err) {
console.error('客户表单验证失败', err)
}
}
const resetForm = () => {
clientForm.value = {
//
feeTemplate: '',
//
riskTemplate: '',
//
agentUsername: '',
email: '',
phone: '',
countryCode: '+86',
//
isUpgrade: 1,
//
userName: '',
status: 1,
id: '',
}
}
//
const handleCancel = () => {
//
dialogVisible.value = false
dialogType.value = 'add'
resetForm()
}
//
const handleClose = () => {
//
dialogVisible.value = false
dialogType.value = 'add'
resetForm()
}
</script>
<style scoped>
<style scoped lang="scss">
.phone-email {
display: flex;
:deep(.el-form-item__content) {
flex-wrap: nowrap;
}
flex: 1;
.tab-btn {
display: flex;
margin-right: 10px;
.el-button {
margin-left: 0;
background-color: transparent;
border: 1px solid #DCDFE6;
color: #303133;
height: 32px;
}
.active {
background-color: #409EFF;
color: #fff;
margin-left: 0;
}
}
.email-item {
.el-input {
width: 100%;
}
}
.group {
display: flex;
flex: 1;
.phone-item {
.el-select {
width: 120px;
margin-right: 10px;
.el-form-item {
flex: 1;
}
.phone-item {
:deep(.el-form-item__content) {
flex-wrap: nowrap;
}
.el-select {
width: 110px;
}
}
}
}

View File

@ -52,7 +52,7 @@ export const clientSearch = [
export const clientTableColumns = [
{ prop: 'id', label: 'ID', align: 'center' as const },
{ prop: 'username', label: '用户名', align: 'center' as const },
{ prop: 'created_at', label: '注册时间', align: 'center' as const },
{ prop: 'createdTime', label: '注册时间', align: 'center' as const },
{ prop: 'agentUsername', label: '所属代理', align: 'center' as const },
{ label: '状态', slotName: 'status', align: 'center' as const },
{ label: '操作', slotName: 'action', align: 'center' as const }
@ -62,10 +62,10 @@ export const clientTableColumns = [
export const clientAddFormItem = [
// { prop: 'clientName', label: '客户名称', type: 'input' as const, placeholder: '客户名称' },
// { prop: 'isUpgrade', label: '是否升级为代理', type: 'radio' as const, placeholder: '是否升级为代理' },
{ prop: 'phoneOrEmail', label: '', type: 'slot' as const, slotName: 'phoneOrEmail' },
{ prop: 'feeTemplate', label: '手续费模板', type: 'select' as const, placeholder: '选择手续费模板' },
{ prop: 'riskTemplate', label: '风控模板', type: 'select' as const, placeholder: '选择风控模板' },
{ prop: 'agentUsername', label: '所属上级', type: 'select' as const, placeholder: '所属上级' },
{ prop: 'phoneOrEmail', label: '', type: 'slot' as const, slotName: 'phoneOrEmail' },
]
//定义修改客户form配置

View File

@ -0,0 +1,398 @@
<template>
<div class="client">
<!-- 搜索组件 -->
<ClientSearch :search-form="clientSearchForm" :search-options="clientSearchOptions" @search="handleSearch"
@reset="handleReset">
<template #button="{ form }">
<el-button type="primary" @click="handleAdd()">
添加客户
</el-button>
</template>
</ClientSearch>
<ClientTable :table-data="clientTree" :columns="clientTableColumns" row-key="id" :tree-props="treeProps">
<template #status="{ row }">
<el-switch :model-value="row.status === 1" :active-value="true" :inactive-value="false" active-text="启用"
inactive-text="禁用" />
</template>
<template #action="{ row }">
<el-button type="primary" size="small" @click="handleChange(row)">
修改
</el-button>
</template>
</ClientTable>
<ClientPagination :modelValue="clientSearchForm.currentPage" :pageSizeValue="clientSearchForm.pageSize"
:total="total" @pagination-change="handlePaginationChange" />
</div>
<!-- 客户弹窗 -->
<ClientDialog :visible="dialogVisible" :title="dialogTitle" :type="dialogType" @confirm="handleSubmit"
@cancel="handleCancel" @close="handleClose">
<ClientForm :form-data="clientForm" :form-rules="clientFormRules" :form-items="clientFormOptions"
:options-map="clientFormOptionsMap" ref="clientFormRef">
<template #phoneOrEmail="{ formData }">
<div class="phone-email">
<div class="tab-btn">
<el-button type="primary" size="small" :class="{ 'active': activeTab === 'email' }"
@click="activeTab = 'email'">
邮箱
</el-button>
<el-button type="primary" class="phone" size="small"
:class="{ 'active': activeTab === 'phone' }" @click="activeTab = 'phone'">
手机号
</el-button>
</div>
<el-form-item prop="email" v-if="activeTab === 'email'" class="email-item">
<el-input v-model="formData.email" placeholder="请输入邮箱"></el-input>
</el-form-item>
<el-form-item prop="phone" v-else class="phone-item">
<el-select v-model="formData.countryCode" :teleported="false" value-key="code" placeholder="国家"
class="country-select">
<el-option v-for="item in countryOptions" :key="item.code" :label="item.code"
:value="item.code">
<div class="country-option">
<span class="country-name">{{ item.name }}</span>
<span class="country-code">{{ item.code }}</span>
</div>
</el-option>
</el-select>
<el-input v-model="formData.phone" placeholder="请输入手机号" clearable />
</el-form-item>
</div>
</template>
</ClientForm>
</ClientDialog>
</template>
<script lang="ts" setup>
//
import ClientSearch from '@/components/common/Search.vue'
import ClientTable from '@/components/common/Table.vue'
import ClientPagination from '@/components/common/Pagination.vue'
import ClientDialog from '@/components/common/Dialog.vue'
import ClientForm from '@/components/common/Form.vue'
//
import { getClientListApi, getFeeTemplateOptionsApi, getRiskTemplateOptionsApi, getAgentOptionsApi, createClientApi, editClientApi } from '@/api/modules/account/client'
//
import { clientSearch, clientAddFormItem, clientChangeFormItem, countryOptions, clientTableColumns } from './options'
import { rules } from './rules'
//
const clientSearchOptions = ref(clientSearch)
const clientSearchForm = ref({
currentPage: 1,
pageSize: 1,
username: '',
status: '正常',
startDateTime: '',
endDateTime: '',
})
//
const clientTree = ref<any[]>([])
const treeProps = ref({
children: 'parent',
label: 'username'
})
//
const total = ref(0)
// dialog
const dialogTitle = ref('')
const dialogVisible = ref(false)
const dialogType = ref('add')
const clientForm = ref({
//
feeTemplate: '',
//
riskTemplate: '',
//
agentUsername: '',
email: '',
phone: '',
countryCode: '+86',
//
isUpgrade: 1,
//
userName: '',
status: 1,
id: '',
})
//
const clientFormRef = ref()
const clientFormRules = ref(rules())
const clientFormOptions = ref<any[]>(clientAddFormItem)
//
const activeTab = ref('email')
//
interface FormOption {
label: string;
value: string | number;
}
interface ClientFormOptionsMap {
feeTemplate: FormOption[];
riskTemplate: FormOption[];
agentUsername: FormOption[];
isUpgrade: FormOption[];
status: FormOption[];
}
const clientFormOptionsMap = ref<ClientFormOptionsMap>({
feeTemplate: [],
riskTemplate: [],
agentUsername: [],
isUpgrade: [
{ label: '是', value: 1 },
{ label: '否', value: 2 }
],
status: [
{ label: '正常', value: 1 },
{ label: '禁用', value: 2 }
],
})
//
const fetchClientList = async () => {
const params = {
page: clientSearchForm.value.currentPage,
page_size: clientSearchForm.value.pageSize,
username: clientSearchForm.value.username,
status: clientSearchForm.value.status === '正常' ? 1 : 2,
reg_start_time: clientSearchForm.value.startDateTime.length > 0 ? `${clientSearchForm.value.startDateTime} 0:00:00` : '',
reg_end_time: clientSearchForm.value.endDateTime.length > 0 ? `${clientSearchForm.value.endDateTime} 23:59:59` : '',
}
const data = await getClientListApi(params)
clientTree.value = data.data.map(item => ({
...item,
//
agentUsername: item.par_uid === item.parent?.id ? item.parent?.username : '',
}));
//
total.value = Number(data.total)
clientSearchForm.value.currentPage = Number(data.current_page)
clientSearchForm.value.pageSize = Number(data.per_page)
}
onMounted(async () => {
await fetchClientList()
})
/**
* @description: 搜索事件
*/
//
const handleSearch = async () => {
try {
await fetchClientList()
} catch (err) {
console.error('获取客户列表失败', err)
}
}
//
const handleReset = () => {
clientSearchForm.value = {
currentPage: 1,
pageSize: 1,
username: '',
status: '正常',
startDateTime: '',
endDateTime: '',
}
fetchClientList() //
}
//
const handleDialogType = (type: string) => {
clientFormOptions.value = type === 'add' ? clientAddFormItem : clientChangeFormItem
}
//
const mapObjectToOptions = (obj: Record<string, string>) => {
return Object.entries(obj).map(([label, value]) => ({
label, // /
value // /ID
}))
}
//
const optionsFetched = ref(false)
const getOptions = async () => {
//
if (optionsFetched.value) return
try {
const [agentRes, feeTemplateRes, riskTemplateRes] = await Promise.all([
getAgentOptionsApi(),
getFeeTemplateOptionsApi(),
getRiskTemplateOptionsApi()
])
// label=value=ID
clientFormOptionsMap.value.agentUsername = mapObjectToOptions(agentRes as Record<string, string>)
clientFormOptionsMap.value.feeTemplate = mapObjectToOptions(feeTemplateRes as Record<string, string>)
clientFormOptionsMap.value.riskTemplate = mapObjectToOptions(riskTemplateRes as Record<string, string>)
optionsFetched.value = true //
} catch (error) {
console.error('获取表单选项失败:', error)
ElMessage.error('获取表单选项失败,请稍后重试')
}
}
/**
* @description: 表格修改事件
*/
const handleChange = async (row: any) => {
dialogVisible.value = true
dialogTitle.value = '修改客户'
dialogType.value = 'edit'
handleDialogType(dialogType.value)
//
await getOptions()
// id
clientForm.value = {
id: row.id, // ID
feeTemplate: row.feeTemplate || '', //
riskTemplate: row.riskTemplate || '', //
agentUsername: row.agentUsername || '', //
email: row.email || '', //
phone: row.phone || '', //
countryCode: row.countryCode || '+86', //
isUpgrade: row.isUpgrade || 1, //
userName: row.username || '', //
status: row.status || 1, //
}
}
//
const handlePaginationChange = (page: { currentPage: number, pageSize: number }) => {
clientSearchForm.value.currentPage = page.currentPage
clientSearchForm.value.pageSize = page.pageSize
handleSearch()
}
/**
* @description: dialog事件
*/
//
const handleAdd = async () => {
dialogVisible.value = true
dialogType.value = 'add'
dialogTitle.value = '添加客户'
handleDialogType(dialogType.value)
//
await getOptions()
}
const handleSubmit = async () => {
try {
await clientFormRef.value?.validate()
if (dialogType.value === 'add') {
const params = {
reg_type: activeTab.value === 'email' ? 1 : 2,
email: clientForm.value.email,
mobile: clientForm.value.phone,
parent_id: clientForm.value.agentUsername,
risk_control_id: clientForm.value.riskTemplate,
fee_setting_id: clientForm.value.feeTemplate,
}
await createClientApi(params)
await fetchClientList()
dialogVisible.value = false
} else {
const params = {
user_id: clientForm.value.id,
risk_control_id: clientForm.value.riskTemplate,
fee_setting_id: clientForm.value.feeTemplate,
username: clientForm.value.userName,
is_levelup: clientForm.value.isUpgrade,
status: clientForm.value.status,
}
await editClientApi(params)
await fetchClientList()
dialogVisible.value = false
}
} catch (err) {
console.error('客户表单验证失败', err)
}
}
const resetForm = () => {
clientForm.value = {
//
feeTemplate: '',
//
riskTemplate: '',
//
agentUsername: '',
email: '',
phone: '',
countryCode: '+86',
//
isUpgrade: 1,
//
userName: '',
status: 1,
id: '',
}
}
//
const handleCancel = () => {
dialogVisible.value = false
dialogType.value = 'add'
resetForm()
}
//
const handleClose = () => {
dialogVisible.value = false
dialogType.value = 'add'
resetForm()
}
</script>
<style scoped>
.phone-email {
display: flex;
:deep(.el-form-item__content) {
flex-wrap: nowrap;
}
.tab-btn {
display: flex;
margin-right: 10px;
.el-button {
margin-left: 0;
background-color: transparent;
border: 1px solid #DCDFE6;
color: #303133;
height: 32px;
}
.active {
background-color: #409EFF;
color: #fff;
}
}
.email-item {
.el-input {
width: 100%;
}
}
.phone-item {
.el-select {
width: 120px;
margin-right: 10px;
}
}
}
</style>

View File

@ -88,6 +88,22 @@ const loginRules = ref<FormRules>({
//
/**
* 生成时间戳拼接6位随机数字的字符串
* @returns {string} 格式示例1710688800000123456
*/
function generateTimestampWithRandomNum() {
// 1.
const timestamp = Date.now();
// 2. 6000000 ~ 999999
// Math.random()0~1100000060
const random6Num = Math.floor(Math.random() * 1000000).toString().padStart(6, '0');
// 3.
return timestamp + random6Num;
}
//
const handleLogin = async () => {
if (!loginFormRef.value) return;
@ -120,15 +136,19 @@ const handleLogin = async () => {
else if (currentTab === 'password') {
// +
await loginFormRef.value.validateField(['password', 'code']);
// device_no1
const deviceNo = generateTimestampWithRandomNum();
//
const loginParams = {
email: loginForm.value.email,
mobile: loginForm.value.phone,
login_type: getStorage('loginType', 'session') === 'email' ? 1 : 2,
code: loginForm.value.code,
password: loginForm.value.password
password: loginForm.value.password,
device_no: deviceNo
};
await userStore.login(loginParams);
setStorage('device_no', deviceNo);
activeTab.value = 'email'; // tab
hideTab.value = false;
loginForm.value = { //