3.8号码提交
This commit is contained in:
parent
2bf41d8fb4
commit
ef84a0b097
|
|
@ -11,7 +11,7 @@ export interface MenuFormParams {
|
|||
type: number; // 类型:1菜单2按钮(number类型)
|
||||
status?: number; // 状态:1启用2禁用(可选,编辑时用)
|
||||
id?: number; // 菜单ID(仅编辑/删除时传)
|
||||
parent_id?: number | null; // 上级菜单ID(number类型)
|
||||
parent_id?: string | null; // 上级菜单ID(number类型)
|
||||
}
|
||||
|
||||
/** 删除菜单参数类型 */
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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' }
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Reference in New Issue