后台管理系统

<div class="homepage_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"
      >
        <!-- index 绑定的是单独展开的哪一列  element期望的是string类型 转换一下-->
        <el-sub-menu :index="menu.id + ''" v-for="menu in menus" :key="menu.id">
          <template #title>
            <span>{{ menu.title }}</span>
          </template>
          <template v-for="menuChildren in menu.children">
            <el-menu-item
              :index="'/' + menu.name + '/' + menuChildren.name"
              v-if="!menuChildren.hidden"
              :key="menuChildren.id"
              >{{ menuChildren.title }}</el-menu-item
            >
          </template>
        </el-sub-menu>
      </el-menu>
    </div>

 开发日记

//根据鼠标移入 移出事件 来判断鼠标选择的是哪一个一级菜单 然后让菜单展示数据
//根据后端给的id来判断
          <li
            v-for="item in menu"
            :key="item.id"
             //传递过去 对应鼠标移动到的菜单对应的id
            @mouseenter="mourseHover(item.id)"
            @mouseleave="mourseOut"
           />

//函数
import {lagsList ,searchCourse} from "../api/api";
//查询标签的数据
let taglist = ref([]);
let searchCourselist = ref([]);

//获取课程标签数据的参数
let tagsParams = {
  pageNum: 1, //页码 默认1
  pageSize: 10, //分页大小 默认10
  entity: {
    firstCategory: "", //一级分类id
  },
};

//鼠标移入 触发
const isFirst = ref(false);
//id辨别移入的是哪一个一级菜单
const mourseHover = (id) => {
  isFirst.value = true;
  //根据一级id来获取数据
  tagsParams.entity.firstCategory = id;
  //课程标签接口
  lagsList(tagsParams).then((res) => {
    taglist.value = res.data.pageInfo.list;
  });
  //课程数据接口
  searchCourse(tagsParams).then(res =>{
    searchCourselist.value = res.data.pageInfo.list;
  })
};
//鼠标移出 触发
const mourseOut = () => {
  isFirst.value = false;
};

分页查询数据

1 利用element分页

//total 是数据的总条数
<el-pagination background layout="prev, pager, next" 
      :total="total"
//切换到最新页数据
       @current-change='handleCurrentChange' />


//参数
let page = reactive({
  pageNum: 1,
  pageSize: 4,
});

//请求商品数据接口
const product = () => {
  searchCourse(page).then((res) => {
    total.value =res.data.pageInfo.total
    productList.value = res.data.pageInfo.list;
  });
};


//分页数据
let total =ref(0);
//val是点击的当前页码
const handleCurrentChange = (val) =>{
 //页码赋值
     page.pageNum =val;
//请求展示商品数据的接口 再次请求----查询对应页数据
     product()
}

一级 二级 难度查询对应数据

//一级
            <el-tag
              class="category-poniter-item"
              effect="plain"
              type="info"
              v-for="item in firstCategorys"
              :key="item.id"
              @click="buildingCondition('fcategory', item.id)"
            >
            </el-tag>
    
// 二级
            <el-tag
              class="category-poniter-item"
              effect="plain"
              type="info"
              v-for="item in secondCategorys"
              :key="item.id"
              @click="buildingCondition('scategory', item.id)"
            >
            </el-tag>

//难度
            <el-tag
              class="category-poniter-item"
              effect="plain"
              type="info"
              v-for="item in difficulty"
              :key="item.id"
              @click="buildingCondition('clevel', item.code)"
            >
            </el-tag>


//二级分类 
let category =reactive({ 
   categoryId: -1 
})
let secondCategorys = ref([]);
const getSecondCate = () =>{
  getSecondCategorys(category).then((res) => {
  secondCategorys.value = res.data.list;
});
}
getSecondCate()



//展示商品接口  
let page = reactive({
  pageNum: 1,
  pageSize: 4,
  entity: {
    firstCategory: "", //一级分类Id
    secondCategory: "", //二级分类Id
    courseLevel: "", // 课程等级(1初级 2 中级 3高级)
    isFree: "", //免费课程
    isMember: "", //会员课程
    sortBy: "", //筛选排序 最新时间 最多购买 价格 time-desc
  },
});
let productList = ref([]);
//根据一级 二级分类的选择来显示商品的内容 应该在一二级接口里面都调用mostNew接口
const product = () => {
  searchCourse(page).then((res) => {
    total.value = res.data.pageInfo.total;
    productList.value = res.data.pageInfo.list;
  });
};
product();



//通过点击事件的type不同 来区分一级 二级 难度
const buildingCondition = () =>{
  if(type === 'fcategory'){
      //一级
    category.categoryId = id;
    getSecondCate ();
    page.entity.firstCategory = id;
    page.entity.secondCategory = '';
    product ();
   return
}
  if(type === 'scategory'){
   //二级
   page.entity.secondCategory = id;
   product ()
}
//难度
  if (type === "clevel") {
    currentType[type].id = id;
    page.entity.courseLevel = id;
    product(page);
    return;
  }
切换页面 ---------页面都写了 只是让一个显示 一个不显示
	    <div class="info-nav">
	      <div class="nav-container">
//真---------标题
	        <div class="chapter-item " @click="chapter = true" >
	          <div :class="chapter? 'active1' : ''">章节</div>
	          <div :class="chapter ? 'line active2' : ''"></div>
	        </div>
//点击false-------标题
	        <div class="chapter-item"  @click="chapter = false">
	          <div :class=" !chapter ?  'active1' : ''">下载资料</div>
	          <div :class="!chapter ? 'line active2' : ''"></div>
	        </div>
	      </div>
	    </div>
//真时 显示------内容
	    <div class="course" v-if="chapter">
	      <div class="main">
	        <div class="introduction">
	          <div class="desc">
	            该课程暂无介绍
	          </div>
	        </div>
	        </div>
	      </div>
	    </div>
//false 显示-------内容
	    <div v-else>
	      <div>
	        <div class="down" v-if="shuju.length > 0">
	          <div class="source">
	            <span class="downloadCourse">哈哈哈哈哈</span>
	            <button class="downloadbtn">下载资料</button>
	          </div>
	        </div>
	      </div>
	      <div>
	        <el-empty
	          description="该课程暂无资料"
	        ></el-empty>
	      </div>
	    </div>


<script setup>
import {ref} from 'vue';

//一上来就是真 
let chapter = ref(true);

let shuju = ref([])
</script>
<li
                v-for="item in loginTxt"
                :key="item.id"
                class="nav-items"
                :class="current == item.id ? 'actives' : ''"
                @click="loginChange(item.id)"
              >
                <a :class="current == item.id ? 'activess' : ''">{{
                  item.text
                }}</a>
</li>
//一个大盒子
           <div class="tab-content">
//账号
              <div class="tab-pane fade show active" v-if="current == 1">
                <!-- 账号登录 -->
                <div class="tab-main" >
                  <el-form ref="ruleFormRef" :model="ruleForm" :rules="rules">
                    <el-form-item class="login-user" prop="username">
                      <el-icon><avatar /></el-icon>
                      <el-input
                        v-model="ruleForm.username"
                        placeholder="请输入您的用户名"
                      />
                    </el-form-item>
                    <el-form-item class="login-password" prop="userpwd">
                      <el-icon><lock /></el-icon>
                      <el-input
                        type="password"
                        v-model="ruleForm.userpwd"
                        placeholder="请输入您的密码"
                      />
                    </el-form-item>
                    <el-form-item class="login-submit">
                      <el-button type="primary" @click="userBtn(ruleFormRef)"
                        >登录</el-button
                      >
                    </el-form-item>
                    <a class="forgetpwd">忘记密码?</a>
                    <div class="login-text">
                      登录即同意相关服务条款和隐私政策
                      <a>《小鹿线用户服务协议》</a><a>《小鹿线隐私政策》</a>
                      若您没有账号,系统将为您自动创建账号并登录。
                    </div>
                  </el-form>
                </div>
              </div>
//否则
              <div class="tab-pane fade" v-else>
                <!-- 短信登录 -->
                <div class="tab-main">
                  <el-form>
                    <el-form-item class="login-user" prop="phone">
                      <el-icon><avatar /></el-icon>
                      <el-input placeholder="请输入您的手机号" />
                    </el-form-item>

                    <el-form-item class="login-Verification" prop="captcha">
                      <el-input placeholder="请输入您的手机号" />
                      <el-button
                        class="btn btn-primary sendcaptcha"
                        type="primary"
                        >发送验证码</el-button
                      >
                    </el-form-item>
                    <div class="login-submit">
                      <el-button
                        class="btn btn-primary sendcaptcha"
                        type="primary"
                        >登录</el-button
                      >
                    </div>
                  </el-form>
                </div>
              </div>

<script setup>
//上来就是账号登录
let current = ref(1);

//数据驱动视图
let loginTxt = reactive(
{id :1 ,text : 账号登录},
{id:2 ,text : 手机号登录}
)

// 接受ID 点击的ID给 current传去 
//当current ==1 时账号 
const  loginChange = (id) =>{
current.value = id
}


<script>


.actives {
  color: #388eff;
  border-bottom: 4px solid #388eff;
}
.activess {
  color: #388eff !important;
}

  单选框

<el-radio-group v-model="radio" @change="change">
              <el-radio :label="1">免费课程</el-radio>
              <el-radio :label="2">会员课程</el-radio>
            </el-radio-group>



//切换免费 会员课程
let radio = ref("0");
const change = (val) => {
  if (val == "1") {
    page.entity.isFree = "1";
    page.entity.isMember = "";
  }
  if (val == "2") {
    page.entity.isMember = "1";
    page.entity.isFree = "";
  }
  product();
};

pinia持久化存储数据

//安装pinia
npm i pinia
//pinia持久化存储数据
npm i pinia-plugin-persist

import { defineStore } from 'pinia'


export const useUserStore = defineStore({
  id: 'user',
  state: () => {
    return {
      token: ''
    }
  },
  actions:{
  	//保存token
setToken( token ){
  		this.token = token;
  	}	,

//清除token
    clearToken(){
      this.token = ''
    }
  },
  // 开启数据缓存
  persist: {
    enabled: true,
    strategies: [{
      key: 'xiaoluxian_user',
      storage: localStorage,
      //paths: ['token']
    }]
  }
})

pinia使用

//登录接口
export const loginByJson = (data) => requests.post(`/api/u/loginByJson`, data);

//引入对应模块
import {useUserStore} from '../store/use'

let store = useUserStore()


const userBtn = () => {
  ruleFormRef.value.validate((valid, fields) => {
    if (valid) {
      loginByJson({
        //加密
        username: Encrypt(ruleForm.username),
        password: Encrypt(ruleForm.userpwd),
      }).then((res) => {
        if (res.meta.code != 10006) {
          ElMessage({
            message: res.meta.msg,
            type: "success",
          });
          return;
        }
        ElMessage({
          message: "成功",
          type: "success",
        });
        //存储token--------------------------------------------------------------------
        store.setToken(res.data.accessToken);
        router.go(-1);
      });
      console.log("用户名和密码验证成功");
    } else {
      ElMessage({
        message: "格式错误",
        type: "success",
      });
    }
  });
};

//请求头带去token

import {useUserStore} from '../store/use'
//2. 请求拦截器
service.interceptors.request.use(
  (config) => {
    let store = useUserStore();
    let token = store.token;
    if (token) {
      config.headers["Authorization"] = token;
    }
    return config;
  },
  (error) => {
    Promise.reject(error);
  }
);

//退出登录

const goLogout = () => {
 ElMessageBox.confirm('确定退出登录吗?', '提示', {
       confirmButtonText: '确定',
       cancelButtonText: '取消',
      type: 'warning'
     }).then(() => {
     	logout().then(res=>{
    		if( res.meta.code=='200'){
    			let userStore = useUserStore();
//把pinia里面的清除函数拿过来---------------------------------------------
    			userStore.clearToken();
    			router.go(0);
   			ElMessage.success({
	      	  message: '退出成功!'
	      	});
    		}
    	})
     
     }).catch(() => {
       ElMessage.info({
         message: '已取消'
       });
     });

视频播放的插件

 

表单校验 

<template>
  <el-form :model='from' 
           :rules= 'rules'
          ref='fromb'>
    
    <el-form-item  prop="name">
      <el-input v-model='from.name' />
      
     <el-button @click ='onSubmit(fromb)'></el-button>
    </el-form-item>
    
  </el-form>
</template>

<script  setup>
import {ref,reactive} from 'vue'
const from = reactive({
    name:''
})

const fromb = ref ()


const rules = reactive({
  name: [
    { required: true, message: 'Please input Activity name', trigger: 'blur' },
    { min: 3, max: 5, message: 'Length should be 3 to 5', trigger: 'blur' },
  ],})
  
const onSubmit =(f) =>{
 f.validate((valid, fields) => {
    if (valid) {
      console.log('submit!')
    } else {
      console.log('error submit!', fields)
    }
  })
}
</script>

flex布局

//flex布局
display :flex;

//justify-content 
justify-content : center ------ 水平居中
justify-content : space-between -------- 先两边贴边 在平分剩余空间(重要)
justify-content : space-around---------- 平分剩余空间

//flex-wrap
flex-wrap : wrap ------- 换行

//align-items
align-items : center --------- 垂直居中

照片 动画效果

.courseItem {
  width: 285px;
  height: 280px;
  margin: 0 20px 20px 0;
//动画效果
  transition: margin-top 0.2s;
}
.courseItem:hover {
//向上移动10px
  margin-top: -10px;
  cursor: pointer;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

puzhiren819

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值