自存19-48 - 教程

19-菜单管理添加弹窗显示


<script setup>
    import { ref , reactive , onMounted } from 'vue'
    import { userGetMenu } from '../../../api'
    onMounted(() => {
        //菜单数据
        userGetMenu().then(({ data })=>{
            console.log(data)
            permissionData.value = data.data
        })
    })
    //form的数据
    const form = reactive({
        name:'',
        permissions:''
    })
    //树形菜单权限数据
    const permissionData = ref([])
    //弹窗的显示隐藏
    const dialogFormVisable = ref(false)
    //关闭弹窗的回调
    const beforeClose = () => {
        dialogFormVisable.value = false
    }
    //选中权限
    const defaultKeys = [4,5]
    const treeRef = ref()
</script>

import request from '../utils/request'
//发送验证码
export const getCode = (data) => {
    return request.post('/get/code',data)
}
//注册用户
export const userAuthentication = (data) =>{
    return request.post('/user/authentication',data)
}
//登录
export const login = (data) =>{
    return request.post('/login',data)
}
//权限管理列表
export const authAdmin = (params) => {
    return request.get('/auth/admin', { params })
}
//菜单权限数据
export const userGetMenu = (params) => {
    return request.get('/user/getmenu', { params })
}

新添加的部分:

20-菜单管理添加接口联调


<script setup>
    import { ref, reactive, onMounted } from 'vue'
    import { userGetMenu, userSetMenu, menuList} from '../../../api'
    onMounted(() => {
        //菜单数据
        userGetMenu().then(({ data })=>{
            console.log(data)
            permissionData.value = data.data
        })
        getListData()
    })
    const paginationData = reactive({
        pageNum: 1,
        pageSize: 10,
    })
    //请求列表数据
    const getListData = () =>{
        menuList(paginationData).then(( data ) => {
        })
    }
    const formRef = ref()
    //form的数据
    const form = reactive({
        id:'',
        name:'',
        permissions:''
    })
    //树形菜单权限数据
    const permissionData = ref([])
    //弹窗的显示隐藏
    const dialogFormVisable = ref(false)
    //关闭弹窗的回调
    const beforeClose = () => {
        dialogFormVisable.value = false
    }
    //选中权限
    const defaultKeys = [4,5]
    const treeRef = ref()
    const rules = reactive({
        name:[{ required: true, trigger:'blur',message:'请输入权限名称' }]
    })
    //表单提交
    const confirm = async(formEl) => {
        if (!formEl) return
        await formEl.validate((valid,fields) => {
            if(valid){
                //获取到选择的checkbox数据
                const permissions = JSON.stringify( treeRef.value.getCheckedKeys())
                userSetMenu({ name: form.name, permissions, id: form.id}).then(({ data }) => {
                    console.log(data)
                })
            }else{
                console.log('error submit!' , fields )
            }
        })
    }
</script>

import request from '../utils/request'
//发送验证码
export const getCode = (data) => {
    return request.post('/get/code',data)
}
//注册用户
export const userAuthentication = (data) =>{
    return request.post('/user/authentication',data)
}
//登录
export const login = (data) =>{
    return request.post('/login',data)
}
//权限管理列表
export const authAdmin = (params) => {
    return request.get('/auth/admin', { params })
}
//菜单权限数据
export const userGetMenu = (params) => {
    return request.get('/user/getmenu', { params })
}
//菜单权限修改
export const userSetMenu = (data) => {
     return request.post('/user/setmenu',data)
}
//菜单权限列表
export const menuList = (params) => {
    return request.get('/menu/list', { params })
}

21-菜单管理列表和编辑逻辑


<script setup>
    import { ref, reactive, onMounted, nextTick } from 'vue'
    import { userGetMenu, userSetMenu, menuList} from '../../../api'
    onMounted(() => {
        //菜单数据
        userGetMenu().then(({ data })=>{
            console.log(data)
            permissionData.value = data.data
        })
        getListData()
    })
    //列表数据
    const tableData = reactive({
        list: [],
        total: 0
    })
    //打开弹窗
    const open = (rowData = {}) =>{
        dialogFormVisable.value = true
        // 弹窗打开form生成是异步的
        nextTick(() => {
            if(rowData){
                Object.assign(form, { id:rowData.id , name: rowData.name  })
                treeRef.value.setCheckedKeys(rowData.permission)
            }
        })
    }
    const paginationData = reactive({
        pageNum: 1,
        pageSize: 10,
    })
    //请求列表数据
    const getListData = () =>{
        menuList(paginationData).then(({ data }) => {
            const { list, total } = data.data
            tableData.list = list
            tableData.total = total
        })
    }
    const formRef = ref()
    //form的数据
    const form = reactive({
        id:'',
        name:'',
        permissions:''
    })
    //树形菜单权限数据
    const permissionData = ref([])
    //弹窗的显示隐藏
    const dialogFormVisable = ref(false)
    //关闭弹窗的回调
    const beforeClose = () => {
        dialogFormVisable.value = false
        //重置表单
        formRef.value.resetFields()
        //tree选择重置
        treeRef.value.setCheckedKeys(defaultKeys)
    }
    //选中权限
    const defaultKeys = [4,5]
    const treeRef = ref()
    const rules = reactive({
        name:[{ required: true, trigger:'blur',message:'请输入权限名称' }]
    })
    //表单提交
    const confirm = async(formEl) => {
        if (!formEl) return
        await formEl.validate((valid,fields) => {
            if(valid){
                //获取到选择的checkbox数据
                const permissions = JSON.stringify( treeRef.value.getCheckedKeys())
                userSetMenu({ name: form.name, permissions, id: form.id}).then(({ data }) => {
                    console.log(data)
                })
            }else{
                console.log('error submit!' , fields )
            }
        })
    }
</script>

22-菜单管理剩余问题处理


<script setup>
    import { ref, reactive, onMounted, nextTick } from 'vue'
    import { userGetMenu, userSetMenu, menuList} from '../../../api'
    import { Plus } from '@element-plus/icons-vue'
    onMounted(() => {
        //菜单数据
        userGetMenu().then(({ data })=>{
            console.log(data)
            permissionData.value = data.data
        })
        getListData()
    })
    //列表数据
    const tableData = reactive({
        list: [],
        total: 0
    })
    //打开弹窗
    const open = (rowData = {}) =>{
        dialogFormVisable.value = true
        // 弹窗打开form生成是异步的
        nextTick(() => {
            if(rowData){
                Object.assign(form, { id:rowData.id , name: rowData.name  })
                treeRef.value.setCheckedKeys(rowData.permission)
            }
        })
    }
    const paginationData = reactive({
        pageNum: 1,
        pageSize: 10,
    })
    const handleSizeChange = (val) => {
        paginationData.pageSize = val
        getListData()
    }
    const handleCurrentChange = (val) => {
        paginationData.pageNum = val
        getListData()
    }
    //请求列表数据
    const getListData = () =>{
        menuList(paginationData).then(({ data }) => {
            const { list, total } = data.data
            tableData.list = list
            tableData.total = total
        })
    }
    const formRef = ref()
    //form的数据
    const form = reactive({
        id:'',
        name:'',
        permissions:''
    })
    //树形菜单权限数据
    const permissionData = ref([])
    //弹窗的显示隐藏
    const dialogFormVisable = ref(false)
    //关闭弹窗的回调
    const beforeClose = () => {
        dialogFormVisable.value = false
        //重置表单
        formRef.value.resetFields()
        //tree选择重置
        treeRef.value.setCheckedKeys(defaultKeys)
    }
    //选中权限
    const defaultKeys = [4,5]
    const treeRef = ref()
    const rules = reactive({
        name:[{ required: true, trigger:'blur',message:'请输入权限名称' }]
    })
    //表单提交
    const confirm = async(formEl) => {
        if (!formEl) return
        await formEl.validate((valid,fields) => {
            if(valid){
                //获取到选择的checkbox数据
                const permissions = JSON.stringify( treeRef.value.getCheckedKeys())
                userSetMenu({ name: form.name, permissions, id: form.id}).then(({ data }) => {
                    beforeClose()
                    getListData()
                })
            }else{
                console.log('error submit!' , fields )
            }
        })
    }
</script>


<script setup>
</script>

import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import router from './router'
import store from './store'
import PanelHead from './components/panelHead.vue'
router.beforeEach((to,from) =>{
  const token = localStorage.getItem('pz_token')
  //非登录页面token不存在
  if (!token && to.path !== '/login') {
    return '/login'
  }else if (token && to.path === '/login'){
    return '/'
  }else{
    return true
  }
})
// 如果您正在使用CDN引入,请删除下面一行。
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
const app = createApp(App)
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
  app.component(key, component)
}
app.component('PanelHead',PanelHead)
//路由挂载
app.use(router)
//store挂载
app.use(store)
app.mount('#app')

23-账号管理列表

24-账号管理编辑分页功能完成


<script setup>
import { authAdmin, menuSelectList, updateUser } from'../../../api'
import { ref, reactive, onMounted } from 'vue'
import dayjs from 'dayjs'
const paginationData = reactive({
    pageNum: 1,
    pageSize: 10,
})
//列表数据
const tableData = reactive({
    list: [],
    total: 0
})
onMounted(() => {
    getListData()
    menuSelectList().then(({ data }) => {
        options.value = data.data
    })
})
//请求列表
const getListData = () => {
    authAdmin(paginationData).then(({data}) => {
        console.log(data, 'authAdmin')
        const { list, total } = data.data
        list.forEach(item => {
            item.create_time = dayjs(item.create_time).format('YYYY-MM-DD')
        })
        tableData.list = list
        tableData.total = total
    })
}
const handleSizeChange = (val) => {
    paginationData.pageSize = val
    getListData()
}
const handleCurrentChange = (val) => {
    paginationData.pageNum = val
    getListData()
}
//弹窗
const dialogFormVisable = ref(false)
const beforeClose = () => {
}
const rules = reactive({
    name:[{ required: true, trigger: 'blur' , message:'请填写昵称' }],
    permissions_id:[{ required: true, trigger: 'blur' , message:'请选择菜单权限' }],
})
//编辑表单
const formRef = ref()
const form = reactive({
    name:'',
    permissions_id:'',
})
//表单提交
const confirm = async (formEl) => {
    if (!formEl) return
    await formEl.validate((valid,fields) => {
        if(valid){
            const { name, permissions_id } = form
            updateUser({ name, permissions_id}).then(({ data }) => {
                if( data.code === 10000 ){
                    dialogFormVisable.value = false
                    getListData()
                }
            })
        }else{
            console.log('error submit!' , fields )
        }
    })
}
const options = ref([])
//根据权限id匹配权限名称
const permissionName = (id) => {
    const data = options.value.find(el => el.id === id)
    return data ? data.name : '超级管理员'
}
const open = ( rowData ) => {
    dialogFormVisable.value = true
    Object.assign(form, { mobile:rowData.mobile, name: rowData.name, permissions_id:rowData.permissions_id })
}
</script>

import request from '../utils/request'
//发送验证码
export const getCode = (data) => {
    return request.post('/get/code',data)
}
//注册用户
export const userAuthentication = (data) =>{
    return request.post('/user/authentication',data)
}
//登录
export const login = (data) =>{
    return request.post('/login',data)
}
//权限管理列表
export const authAdmin = (params) => {
    return request.get('/auth/admin', { params })
}
//菜单权限数据
export const userGetMenu = () => {
    return request.get('/user/getmenu')
}
//菜单权限修改
export const userSetMenu = (data) => {
     return request.post('/user/setmenu',data)
}
//菜单权限列表
export const menuList = (params) => {
    return request.get('/menu/list', { params })
}
//权限下拉列表
export const menuSelectList = () =>{
    return request.get('/menu/selectlist',)
}
//用户数据修改
export const updateUser = (data) => {
     return request.post('/update/user',data)
}

25-用户权限接口联调和动态路由数据组装


<script setup>
import { useStore } from 'vuex'
import { computed } from 'vue'
import { useRoute,useRouter } from 'vue-router'
//拿到store的实例
const store = useStore()
// 当前路由对象
const route = useRoute()
const router = useRouter()
const selectMenu = computed( ()=> store.state.menu.selectMenu)
//点击关闭tag
const closeTab = (item,index) =>{
    store.commit('closeMenu',item)
    //删除的非当前页tag
    if(route.path !== item.path){
        return
    }
    const selectMenuDate = selectMenu.value
    //删除的最后一项
    if( index === selectMenuData.length){
        //如果tag只有一个元素
        if(!selectMenuData.length) {
            router.push('/')
        }else{
            router.push({
                path:selectMenuData[index -1].path
            })
        }
    }else(//如果删除的是中间位置tag
        router.push({
            path:selectMenuData[index].path
        })
    )
}
const handleClick = (command) => {
    if(command === "cancel" ){
        localStorage.removeItem('pz_token')
        localStorage.removeItem('pz_userInfo')
        window.location.href = window.location.origin
    }
}
</script>


<script setup>
import { ref, reactive, computed } from 'vue'
import { getCode, userAuthentication, login, menuPermissions  } from '../../api'
import { UserFilled, Lock } from '@element-plus/icons-vue'
import { useRouter } from 'vue-router'
import { useStore } from 'vuex'
const imgUrl = new URL('../../../public/login-head.png', import.meta.url).href
//表单数据
const loginForm = reactive({
    userName: '',
    passWord: '',
    validCode: '',
})
//切换表单(0登录 1注册)
const formType = ref(0)
//点击切换登录和注册
const handleChange = () => {
    formType.value = formType.value ? 0 : 1
}
//账号校验规则
const validateUser = (rule,value,callback) =>{
    //不能为空
    if(value === ''){
        callback(new Error('请输入账号'))
    }else{
        const phoneReg =  /^1(3[0-9]|4[01456879]|5[0-35-9]|6[2567]|7[0-8]|8[0-9]|9[0-35-9])\d{8}$/
        phoneReg.test(value) ? callback() : callback(Error('手机号格式不对,请输入正确手机号'))
    }
}
//密码校验
const validatePass = (rule,value,callback) =>{
    //不能为空
    if(value === ''){
        calllback(new Error('请输入密码'))
    }else{
        const reg = /^[a-zA-Z0-9_-]{4,16}$/
        reg.test(value) ? callback() : callback(Error('密码格式不对,需要4-16位字符,请确认格式'))
    }
}
//表单校验
const rules = reactive({
    userName : [{ validator: validateUser, trigger:'blur'}],
    passWord : [{ validator: validatePass, trigger:'blur'}]
})
//发送短信
const countdown = reactive({
    validText:'获取验证码',
    time:60
})
let flag = false
const countdownChange = () =>{
    //如果已发送不处理
    if(flag) return
    //判断手机号是否正确
    const phoneReg =  /^1(3[0-9]|4[01456879]|5[0-35-9]|6[2567]|7[0-8]|8[0-9]|9[0-35-9])\d{8}$/
    if (!loginForm.userName || !phoneReg.test(loginForm.userName)){
        return  ElMessage({
                message: '请检查手机号是否正确',
                type: 'warning',
        })
    }
    //倒计时
    const time = setInterval(()=>{
        if( countdown.time <= 0){
            countdown.time = 60
            countdown.validText = `获取验证码`
            flag = false
            clearInterval(time)
        }else{
            countdown.time -= 1
            countdown.validText = `剩余${countdown.time}s`
        }
    },1000)
    flag = true
    getCode({ tel: loginForm.userName}).then(({ data }) => {
        if(data.code === 10000){
            ElMessage.success('发送成功')
        }
    })
}
const router = useRouter()
const loginFromRef = ref()
const store = useStore()
const routerList =  computed(() => store.state.menu.routerList)
//表单提交
const submitForm = async (formEl) => {
    if (!formEl) return
    //手动触发校验
    await formEl.validate((valid, fields) => {
        if (valid) {
            //注册页面
            if(formType.value){
                userAuthentication(loginForm).then(({ data }) => {
                    if (data.code === 10000) {
                        ElMessage.success('注册成功,请登录')
                        formType.value = 0
                    }
                })
            }else{
                //登录页面
                login(loginForm).then(({data}) => {
                     if (data.code === 10000) {
                        ElMessage.success('登录成功!')
                        console.log(data)
                        //将token和用户信息缓存到浏览器
                        localStorage.setItem('pz_token', data.data.token)
                        localStorage.setItem('pz_userInfo', JSON.stringify(data.data.userInfo))
                        menuPermissions().then(({ data }) => {
                            store.commit('dynamicMenu', data.data)
                            console.log(routerList, 'routerList')
                            // router.push('/')
                        })
                    }
                })
            }
        } else {
        console.log('error submit!', fields)
        }
    })
}
</script>

const state = {
    isCollapse : false,
    selectMenu: [],
    routerList: []
}
const mutations = {
    collapseMenu(state){
        state.isCollapse = !state.isCollapse
    },
    addMenu(state,payload) {
        //对数据进行去重
        if(state.selectMenu.findIndex(item => item.path === payload.path) === -1){
            state.selectMenu.push(payload)
        }
    },
    closeMenu(state,payload){
        //找到点击数据的索引
        const index = state.selectMenu.findIndex(val => val.name === payload.name )
        //通过索引删除数组指定元素
        state.selectMenu.splice(index,1)
    },
    dynamicMenu( state, payload ) {
        //通过glob导入文件
        const modules =  import.meta.glob('../views/**/**/*.vue')
         console.log(modules)
         function routerSet(router){
            router.forEach(route => {
                //判断没有子菜单,拼接路由数据
                if ( !route.children ){
                    const url = `../views${route.meta.path}/index.vue`
                    //拿到获取的vue组件
                    route.component =  modules[url]
                }else{
                    routerSet(route.children)
                }
            })
         }
         routerSet(payload)
         //拿到完整的路由数据
         state.routerList =  payload
    }
}
export default{
    state,
    mutations
}

26-动态路由添加和vuex持久化实现

27-菜单高亮显示和用户信息显示问题解决

28-陪护管理新增陪护师弹窗

29-陪护新增表单校验和接口联调

30-陪护列表显示和接口联调

31-陪护师编辑和批量删除接口联调

32-【C端】项目创建引入router和vant UI

33-【C端】tabbar引入和layout组件实现

34-【C端】登录页面显示效果实现

35-【C端】axios二次封装和登录接口联调

36-【C端】首页页面效果实现

37-【C端】订单详情自定义头部和状态显示

38-【C端】订单详情选择医院功能

39-【C端】订单详情选择就诊时间功能

40-【C端】订单详情剩余表单显示

41-【C端】订单下单和支付功能实现

42-【C端】订单列表显示效果实现

43-【C端】订单详情显示效果(上)

44-【C端】订单详情显示效果(下)

45-【C端】我的页面显示效果

46-【C端】订单列表页面实现效果

47-【C端】订单列表服务状态扭转和问题解决

48-【完结】项目总结和回顾

posted @ 2025-10-23 19:29  ycfenxi  阅读(1)  评论(0)    收藏  举报