3.8号码提交

This commit is contained in:
yzl 2026-03-08 01:57:09 +08:00
parent 2bf41d8fb4
commit ef84a0b097
5 changed files with 114 additions and 64 deletions

View File

@ -11,7 +11,7 @@ export interface MenuFormParams {
type: number; // 类型1菜单2按钮number类型
status?: number; // 状态1启用2禁用可选编辑时用
id?: number; // 菜单ID仅编辑/删除时传)
parent_id?: number | null; // 上级菜单IDnumber类型
parent_id?: string | null; // 上级菜单IDnumber类型
}
/** 删除菜单参数类型 */

View File

@ -56,7 +56,7 @@
</el-form-item>
<el-form-item label="父级菜单" prop="parentId">
<el-select v-model="menuForm.parentId" placeholder="请选择父级菜单" style="width:100%">
<el-option label="一级菜单" value="0" />
<el-option label="菜单" value="0" />
<el-option v-for="item in menuTree" :key="item.id" :label="item.name" :value="item.id + ''" />
</el-select>
</el-form-item>
@ -67,10 +67,21 @@
<el-input v-model="menuForm.api" placeholder="例如:/api/system/menu/list可选" />
</el-form-item>
<el-form-item label="图标名称" prop="icon">
<el-input v-model="menuForm.icon" placeholder="例如Tools、List" />
<el-select v-model="menuForm.icon" placeholder="请选择图标(二级菜单可留空)" style="width: 100%" clearable>
<el-option v-for="item in iconOptions" :key="item.value" :label="item.label" :value="item.value">
<template #label>
<span style="display: flex; align-items: center; gap: 8px;">
<el-icon v-if="item.icon">
<component :is="item.icon" />
</el-icon>
<span>{{ item.label }}</span>
</span>
</template>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="排序" prop="sort">
<el-input-number v-model="menuForm.sort" :min="0" placeholder="数字越小越靠前默认1" />
<el-input-number v-model="menuForm.sort" :min="0" placeholder="数字越小越靠前默认1" style="width: 100%" />
</el-form-item>
<el-form-item label="菜单类型" prop="type">
<el-radio-group v-model="menuForm.type">
@ -81,7 +92,7 @@
</el-form>
<template #footer>
<el-button @click="dialogVisible = false">取消</el-button>
<el-button @click="() => { { dialogVisible = false, dialogType = 'add' } }">取消</el-button>
<el-button type="primary" @click="handleSubmitMenu">确定</el-button>
</template>
</el-dialog>
@ -92,61 +103,9 @@ import type { FormInstance, FormRules } from 'element-plus'
import { Tools, List, HomeFilled, UserFilled, Platform, BellFilled, GoodsFilled, WarningFilled, Plus } from '@element-plus/icons-vue'
import { getMenuApi, addMenuApi, deleteMenuApi, editMenuApi } from '@/api/modules/menu'
import { rules } from './rules'
//menu
const menuTree = ref<any[]>([])
//
const menuFormRef = ref<FormInstance>()
//
const menuFormRules = reactive<FormRules>({
// 1. +
name: [
{ required: true, message: '请输入菜单名称', trigger: 'blur' },
{ min: 2, max: 20, message: '菜单名称长度在 2 到 20 个字符之间', trigger: 'blur' }
],
// 2. 0
parentId: [{ required: true, message: '请选择父级菜单', trigger: 'change' }
],
// 3. + ///线/
path: [
{ required: true, message: '请输入路由路径', trigger: 'blur' },
{ pattern: /^\/[a-zA-Z0-9_\/]+$/, message: '路由路径必须以/开头,仅包含字母、数字、下划线和斜杠', trigger: 'blur' }
],
// 4.
api: [
{ required: true, pattern: /(^$)|(^\/[a-zA-Z0-9_\/]+$)/, message: '后端路由若填写,必须以/开头,仅包含字母、数字、下划线和斜杠', trigger: 'blur' }
],
// 5.
icon: [
{
required: true,
pattern: /(^$)|(^Tools$|^List$|^HomeFilled$|^UserFilled$|^Platform$|^BellFilled$|^GoodsFilled$|^WarningFilled$)/
, message: '一级菜单有图标二级菜单没有', trigger: 'blur'
}
],
// 6. + + 0
sort: [
{ required: true, message: '请输入排序值', trigger: 'blur' },
{ type: 'number', min: 0, message: '排序值必须是大于等于0的数字', trigger: 'blur' }
],
// 7. 1
type: [
{ required: true, message: '请选择菜单类型', trigger: 'change' },
{ type: 'number', enum: [1, 2], message: '菜单类型只能是1菜单或2按钮', trigger: 'change' }
]
})
const menuForm = ref({
name: '', //
parentId: '0', //
path: '', //
api: '', //
icon: '', //
sort: 1, // 1
type: 1 //
})
//
//
const iconMap: Record<string, any> = {
Tools,
List,
@ -157,6 +116,36 @@ const iconMap: Record<string, any> = {
GoodsFilled,
WarningFilled
}
//
const iconOptions = [
{ label: "无图标", value: "无图标" },
{ label: "Tools(工具)", value: "Tools", icon: Tools },
{ label: "List(列表)", value: "List", icon: List },
{ label: "HomeFilled(首页)", value: "HomeFilled", icon: HomeFilled },
{ label: "UserFilled(用户)", value: "UserFilled", icon: UserFilled },
{ label: "Platform(平台)", value: "Platform", icon: Platform },
{ label: "BellFilled(铃铛)", value: "BellFilled", icon: BellFilled },
{ label: "GoodsFilled(商品)", value: "GoodsFilled", icon: GoodsFilled },
{ label: "WarningFilled(警告)", value: "WarningFilled", icon: WarningFilled },
]
//menu
const menuTree = ref<any[]>([])
//
const menuForm = ref({
name: '', //
parentId: '0', //
path: '', //
api: '', //
icon: '', //
sort: 1, // 1
type: 1 //
})
const menuFormRef = ref<FormInstance>()
//
const menuFormRules = rules(menuForm.value, iconOptions)
//
const dialogVisible = ref(false)
// /
@ -172,7 +161,7 @@ onMounted(async () => {
const res = await getMenuApi()
menuTree.value = filterEnabledMenus(res)
} catch (err) {
ElMessage.error('获取菜单列表失败')
console.error('获取菜单列表失败')
}
})
@ -200,6 +189,7 @@ const handleAddMenu = () => {
type: 1
}
dialogVisible.value = true
console.log('dialogType.value', dialogType.value);
}
//
@ -209,7 +199,7 @@ const handleEditMenu = (row: any) => {
menuForm.value = {
name: row.name,
parentId: row.parentId,
parentId: row.parent_id,
path: row.path,
api: row.api,
icon: row.icon,
@ -228,6 +218,8 @@ const handleSubmitMenu = async () => {
...menuForm.value,
parent_id: menuForm.value.parentId
})
const res = await getMenuApi()
menuTree.value = filterEnabledMenus(res)
} else {
await editMenuApi({
id: currentEditId.value || 0,
@ -235,6 +227,8 @@ const handleSubmitMenu = async () => {
parent_id: menuForm.value.parentId,
...menuForm.value
})
const res = await getMenuApi()
menuTree.value = filterEnabledMenus(res)
}
dialogVisible.value = false
} catch (err) {
@ -246,6 +240,8 @@ const handleSubmitMenu = async () => {
const handleDeleteMenu = async (row: any) => {
try {
await deleteMenuApi({ id: row.id })
const res = await getMenuApi()
menuTree.value = filterEnabledMenus(res)
} catch (err) {
console.log('删除菜单失败', err)
}

View File

@ -0,0 +1,55 @@
import type { FormRules } from 'element-plus'
export const rules = (menuForm: any, iconOptions: any[]): FormRules => {
return {
// 1. 菜单名称:必填 + 长度限制
name: [
{ required: true, message: '请输入菜单名称', trigger: 'blur' },
{ min: 2, max: 20, message: '菜单名称长度在 2 到 20 个字符之间', trigger: 'blur' }
],
// 2. 父级菜单必填默认0无需手动填
parentId: [{ required: true, message: '请选择父级菜单', trigger: 'change' }
],
// 3. 路由路径:必填 + 格式校验(以/开头,仅包含字母/数字/下划线/斜杠)
path: [
{ required: true, message: '请输入路由路径', trigger: 'blur' },
{ pattern: /^\/[a-zA-Z0-9_\/]+$/, message: '路由路径必须以/开头,仅包含字母、数字、下划线和斜杠', trigger: 'blur' }
],
// 4. 后端路由:可选,但填了就必须符合格式
api: [
{ required: true, pattern: /(^$)|(^\/[a-zA-Z0-9_\/]+$)/, message: '后端路由若填写,必须以/开头,仅包含字母、数字、下划线和斜杠', trigger: 'blur' }
],
// 5. 图标名称:可选,但填了就必须是指定范围(匹配你提供的图标列表)
icon: [
{
validator: (rule, value, callback) => {
// 一级菜单必须选图标
if (menuForm.parentId === "0" && !value) {
callback(new Error("一级菜单必须选择图标"))
}
// 若填写了图标,必须是指定范围内的
else if (
value &&
!iconOptions.some(item => item.value === value)
) {
callback(new Error("请选择预设图标"))
}
else {
callback()
}
},
trigger: "change",
},
],
// 6. 排序:必填 + 数字 + 最小值0
sort: [
{ required: true, message: '请输入排序值', trigger: 'blur' },
{ type: 'number', min: 0, message: '排序值必须是大于等于0的数字', trigger: 'blur' }
],
// 7. 菜单类型必填单选框默认1无需手动选
type: [
{ required: true, message: '请选择菜单类型', trigger: 'change' },
{ type: 'number', enum: [1, 2], message: '菜单类型只能是1菜单或2按钮', trigger: 'change' }
]
}
}

View File

@ -156,7 +156,7 @@ const sendCodeApi = async () => {
const sendParams = {
email: forgotPasswordForm.value.email,
mobile: forgotPasswordForm.value.phone,
reg_type: activeTab.value === 'email' ? 1 : 2,
reg_type: getStorage('forgotType', 'session') === 'email' ? 1 : 2,
type:'transfer_code'
}
return userStore.sendCode(sendParams)
@ -166,10 +166,9 @@ const sendCodeApi = async () => {
const handleSendCode = async () => {
//
const type: string = getStorage('forgotType', 'session') || 'email'
const receiver = type === 'phone' ? forgotPasswordForm.value.phone : forgotPasswordForm.value.email;
const currentCaptchaState = type === 'phone' ? phoneCaptchaState : emailCaptchaState;
const sendFunc = type === 'phone' ? "sendPhoneCaptcha" : "sendEmailCaptcha";
//
await sendCaptcha(
type,