18-经过actions方法封装请求以及补充计算属性

首页菜单添加补充计算属性

<template>
    <div class="home-container">
  <div class="home-header">头部</div>
      <div class="home-menu">
      <el-menu
        active-text-color="#ffd04b"
        background-color="#545c64"
        class="el-menu-vertical-demo"
        default-active="2"
        text-color="#fff"
        :unique-opened="true"
        :router="true"
      >
        <el-sub-menu v-for="menu in newMenus" :index="menu.id">
          <template #title>
        <span>{{ menu.title }}</span>
        </template>
          <template v-for="submenu in menu.children">
        <el-menu-item v-if="submenu.hidden === 0" :index="submenu.id">{{ submenu.title }}</el-menu-item>
        </template>
      </el-sub-menu>
    </el-menu>
  </div>
<div class="home-content">右侧内容</div>
</div>
</template>
<script lang='ts' setup>
/**
{
id: {
title: "一级菜单",
children: [
{title: "二级菜单"},
{title: "二级菜单"},
{title: "二级菜单"},
{title: "二级菜单"},
]
}
}
* */
import { computed } from 'vue'
import { useStore } from 'vuex'
interface MenuObj {
id: string
title: string
parentId: string
hidden: 0 | 1
children?: MenuObj[]
}
interface NewMenus {
[key: string]: MenuObj
}
const store = useStore();
const newMenus = computed<NewMenus>(() => store.getters.getNewMenus);
  console.log('newMenus---------home-----------', newMenus)
</script>
  <style lang='less' scoped>
  .home-container {
  position: relative;
  height: 100%;
  .home-header {
  height: 70px;
  background-color: goldenrod;
  }
  .home-menu {
  position: absolute;
  top: 70px;
  left: 0;
  bottom: 0;
  width: 250px;
  background-color: #a37676;
  }
  .home-content {
  position: absolute;
  top: 70px;
  right: 0;
  left: 250px;
  bottom: 0;
  background-color: skyblue;
  }
  }
</style>

通过actions方法封装用户信息请求

import { createStore } from 'vuex'
import { type App } from 'vue'
import { getAdminInfoApi } from '@/api/login'
interface MenuObj {
id: string
parentId: string
children?: MenuObj[]
}
interface State {
menus: MenuObj[]
}
interface NewMenus {
[key: string]: Partial<MenuObj>
  }
  const store = createStore<State>({
    state() {
    return {
    menus: []
    }
    },
    getters: {
    getNewMenus(state) {
    const newMenus: NewMenus = {}
    const menus = state.menus
    for (let i = 0; i < menus.length; i++) {
    const menu = menus[i] as MenuObj
    if (menu.parentId === '0') {
    // 一级菜单:初始化 children 为空数组,方便后续 push
    newMenus[menu.id] = {
    ...menus[i],
    children: newMenus[menu.id]?.children || []
    }
    } else {
    // 子级菜单:根据 parentId 找到对应的父级
    const parentId = menu.parentId
    newMenus[parentId] = newMenus[parentId] || {}
    newMenus[parentId].children = newMenus[parentId].children || []
    newMenus[parentId].children.push(menu)
    }
    }
    console.log('newMenus--------------------', newMenus)
    return newMenus;
    }
    },
    mutations: {
    updateMenus(state, menus) {
    console.log('updateMenus--->', state, menus)
    state.menus = menus
    }
    },
    actions: {
    getAdminInfoApi({ commit }) {
    return new Promise((resolve, reject) => {
    getAdminInfoApi().then((res) => {
    if(res.code === 200) {
    // 用户信息存储到vuex
    commit('updateMenus', res.data.menus)
    resolve(res.data)
    }else {
    reject(res)
    }
    })
    })
    }
    },
    modules: {}
    })
    export const initStore = (app: App<Element>) => {
      app.use(store)
      }
      export default store

使用这个封装的方法改造路由

import {
createRouter,
createWebHashHistory,
type RouteRecordRaw
} from 'vue-router'
import { type App } from 'vue'
import store from '../store'
import Cookie from 'js-cookie'
const routes: RouteRecordRaw[] = [
{
path: '/',
redirect: '/login'
},
{
path: '/login',
name: 'login',
component: () => import('../views/login/login.vue')
},
{
path: '/home',
name: 'home',
component: () => import('../views/home/home.vue')
}
]
const router = createRouter({
history: createWebHashHistory(),
routes // 路由配置
})
// 前置导航守卫
router.beforeEach((to, from, next) => {
// 1、token && vuex里面的 menus 为空
const token = Cookie.get('token')
console.log(store)
if(token && store.state.menus.length === 0) {
console.log('menus为空')
// 获取用户信息
store.dispatch('getAdminInfoApi');
}
next()
})
export const initRouter = (app: App<Element>) => {
  app.use(router)
  }

使用这个封装的方法改造登录页面

<template>
    <div class="login-rule-form">
      <div class="content">
    <div class="title">商品管理系统</div>
        <el-form ref="ruleFormRef" :model="ruleForm" status-icon :rules="rules" label-width="60px">
          <el-form-item prop="username" label="账号">
          <el-input v-model="ruleForm.username" type="text" placeholder="请输入账号"/>
        </el-form-item>
          <el-form-item prop="pwd" label="密码">
          <el-input v-model="ruleForm.pwd" type="password" placeholder="请输入密码"/>
        </el-form-item>
        <el-form-item>
        <el-button type="primary" @click="loginFn()">登录</el-button>
        </el-form-item>
      </el-form>
    </div>
  </div>
</template>
  <script lang='ts' setup>
  import { onMounted, reactive, ref } from 'vue'
  import { adminLoginApi, getAdminInfoApi } from '@/api/login'
  import Cookie from 'js-cookie'
  import { ElMessage } from 'element-plus'
  import { useRouter } from 'vue-router'
  import { useStore } from 'vuex'
  let ruleForm = reactive({
  username: "",
  pwd: ""
  })
  // 自定义密码校验规则(_variable - 未使用的变量 ts不校验)
  const validatePwd = (_rule: unknown, value: string | undefined, callback: (msg?: string) => void) => {
  if(!value) {
  callback('密码不能为空')
  } else {
  callback()
  }
  }
  // 校验规则
  let rules = reactive({
  username: [
  {
  required: true,
  message: '用户名不能为空',
  trigger: 'blur'
  }
  ],
  pwd: [
  {
  required: true,
  validator: validatePwd,
  trigger: 'blur'
  }
  ]
  })
  // 获取el-form组件对象
  let ruleFormRef = ref()
  // 获取项目路由对象
  let router = useRouter()
  // 获取当前项目的vuex对象
  let store = useStore()
  onMounted(() => {
  // console.log('组件实例:', ruleFormRef.value)
  // console.log('DOM 元素:', ruleFormRef.value?.$el)
  })
  // 点击登录
  const loginFn = () => {
  ruleFormRef.value.validate().then(() => {
  adminLoginApi({
  username: ruleForm.username,
  password: ruleForm.pwd
  }).then((res) => {
  if(res.code === 200) {
  // 储存cookie
  Cookie.set('token', res.data.token, { expires: 7 })
  ElMessage.success('登录成功')
  // 获取用户信息
  store.dispatch('getAdminInfoApi').then(res => {
  // 跳转home页面
  router.push('/home')
  })
  } else {
  ElMessage.error('登录报错')
  }
  })
  }).catch(() => {
  console.log('校验不通过')
  })
  }
</script>
  <style lang='less' scoped>
  .login-rule-form {
  width: 100%;
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: #f5f5f5;
  overflow: hidden;
  box-sizing: border-box;
  margin: 0;
  padding: 0;
  .content {
  width: 420px;
  padding: 40px;
  background-color: #fff;
  border-radius: 8px;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
  box-sizing: border-box;
  .title {
  font-size: 28px;
  font-weight: bold;
  text-align: center;
  margin-bottom: 30px;
  }
  }
  :deep(.el-form) {
  .el-form-item {
  margin-bottom: 20px;
  &:last-child {
  margin-bottom: 0;
  }
  }
  .el-button {
  width: 100%;
  }
  }
  }
</style>
posted @ 2026-01-21 10:32  gccbuaa  阅读(0)  评论(0)    收藏  举报