我的页面开发 
后端

data\me_page.js

我的页面静态数据

module.exports = () => {return {superCard: {beanCount: 1555,tips: "下单得5倍吃货豆,兑专享红包",},cards: [{label: "常用功能",size: 30,items: [{iconUrl: "/imgs/me_page/coupang.png",label: "红包卡券",count: 25,},{iconUrl: "/imgs/me_page/like.png",label: "店铺关注",count: 5,},{iconUrl: "/imgs/me_page/serve.png",label: "客服",count: 0,},{iconUrl: "/imgs/me_page/location.png",label: "地址",count: 0,},],},{label: "互动玩乐",size: 30,items: [{iconUrl: "/imgs/me_page/bean.png",label: "赚吃货豆",count: 0,},{iconUrl: "/imgs/me_page/cash.png",label: "现金提款机",count: 0,},{iconUrl: "/imgs/me_page/redbag.png",label: "天天赚现金",count: 0,},{iconUrl: "/imgs/me_page/exiaobao.png",label: "冲吧饿小宝",count: 0,},],},{label: "更多推荐",size: 20,items: [{iconUrl: "location-o",label: "我的地址",count: 0,},{iconUrl: "service-o",label: "我的客服",count: 0,},{iconUrl: "gold-coin-o",label: "签到领现金",count: 0,},{iconUrl: "hotel-o",label: "企业订餐",count: 0,},{iconUrl: "label-o",label: "发票助手",count: 0,},{iconUrl: "award-o",label: "0元抽手机",count: 0,},{iconUrl: "balance-o",label: "瓜分吃货豆",count: 0,},{iconUrl: "smile-comment-o",label: "冲吧饿小宝",count: 0,},{iconUrl: "coupon-o",label: "省钱好券",count: 0,},{iconUrl: "diamond-o",label: "品牌会员",count: 0,},{iconUrl: "smile-comment-o",label: "冲吧饿小宝",count: 0,},{iconUrl: "coupon-o",label: "省钱好券",count: 0,},{iconUrl: "diamond-o",label: "品牌会员",count: 0,},],},],// features: [//   {//     iconUrl: '/imgs/me_page/coupang.png',//     label: '红包卡券',//     count: 25,//   },//   {//     iconUrl: '/imgs/me_page/like.png',//     label: '店铺关注',//     count: 5,//   },//   {//     iconUrl: '/imgs/me_page/serve.png',//     label: '客服',//     count: 0,//   },//   {//     iconUrl: '/imgs/me_page/location.png',//     label: '地址',//     count: 0,//   },// ],// entertainments: [//   {//     iconUrl: '/imgs/me_page/bean.png',//     label: '赚吃货豆',//     count: 0,//   },//   {//     iconUrl: '/imgs/me_page/cash.png',//     label: '现金提款机',//     count: 0,//   },//   {//     iconUrl: '/imgs/me_page/redbag.png',//     label: '天天赚现金',//     count: 0,//   },//   {//     iconUrl: '/imgs/me_page/exiaobao.png',//     label: '冲吧饿小宝',//     count: 0,//   },// ],// recommends: [//   {//     iconUrl: 'location-o',//     label: '我的地址',//     count: 0,//   },//   {//     iconUrl: 'service-o',//     label: '我的客服',//     count: 0,//   },//   {//     iconUrl: 'gold-coin-o',//     label: '签到领现金',//     count: 0,//   },//   {//     iconUrl: 'hotel-o',//     label: '企业订餐',//     count: 0,//   },//   {//     iconUrl: 'label-o',//     label: '发票助手',//     count: 0,//   },//   {//     iconUrl: 'award-o',//     label: '0元抽手机',//     count: 0,//   },//   {//     iconUrl: 'balance-o',//     label: '瓜分吃货豆',//     count: 0,//   },//   {//     iconUrl: 'smile-comment-o',//     label: '冲吧饿小宝',//     count: 0,//   },//   {//     iconUrl: 'coupon-o',//     label: '省钱好券',//     count: 0,//   },//   {//     iconUrl: 'diamond-o',//     label: '品牌会员',//     count: 0,//   },//   {//     iconUrl: 'smile-comment-o',//     label: '冲吧饿小宝',//     count: 0,//   },//   {//     iconUrl: 'coupon-o',//     label: '省钱好券',//     count: 0,//   },//   {//     iconUrl: 'diamond-o',//     label: '品牌会员',//     count: 0,//   },// ],};
};

src\db.js

配置静态路由

const test = require('../data/test')
const homePage = require('../data/home_page')
const mePage = require("../data/me_page");
function responseData(data) {return {code: 0,data,msg: "请求成功"}
}
module.exports = () => {return {test: test(),home_page: responseData(homePage()),me_page: responseData(mePage())}
}
前端

src\views\tabs\me\MeView.vue

请求我的页面api接口数据。

 <script setup lang="ts">
import type { ISuperCard } from '@/types'
import { useAsync } from '@/use/useAsync'
// import { useAuth } from '@/use/useAuth'
import { fetchMePageData } from '@/api/me'
import OpLoadingView from '@/components/OpLoadingView.vue'
import { useRouter } from 'vue-router'const router = useRouter()
// const { user, logout } = useAuth()
const { data, pending } = useAsync(fetchMePageData, {cards: [],superCard: {} as ISuperCard
})const gotoLogin = () => {router.push({name: 'login'})
}
</script><template><div class="me-page op-fullscreen"><div class="me-page__top"><!-- user.id --><template v-if="false"><img class="avatar" :src="user.avatar" /><div class="name">{{ user.nickname }}</div><div class="account op-then-border" @click="logout">退出</div></template><template v-else><img class="avatar" src="https://b.yzcdn.cn/vant/icon-demo-1126.png" /><div class="name" @click="gotoLogin">请登录</div><div class="account op-then-border" @click="gotoLogin">账号登陆</div></template></div><OpLoadingView :loading="pending" type="skeleton"><div class="me-page__super-card"><div class="super-card__left"><div class="super-card__left__top"><img class="card-img" src="@/assets/imgs/me_page/super-card.png" /><div class="divider"></div><div class="bean">吃货豆:</div><div class="bean-count">{{ data.superCard.beanCount }}</div></div><div class="super-card__left__tips">{{ data.superCard.tips }}</div></div><VanIcon name="arrow" size="14" color="rgb(212, 189, 178)"></VanIcon></div><div class="me-page__card" v-for="v in data.cards" :key="v.label"><div class="me-page__card__title">{{ v.label }}</div><div class="me-page__card__items"><div class="me-page__card__item" v-for="cv in v.items" :key="cv.iconUrl"><VanIcon :name="cv.iconUrl" :size="v.size"></VanIcon><div class="label">{{ cv.label }}<span v-if="cv.count" class="count">{{ cv.count }}</span></div></div></div></div></OpLoadingView></div>
</template>

自定义hooks-useAuth 实现登录页面逻辑
后端

实现模拟用户登录,生成鉴权token逻辑

data\user_list.js

静态用户列表。

module.exports = () => {return [{id: 1,username: "muke",password: "ilovemuke",nickname: "测试账号",avatar: "/imgs/me_page/avatar.png",},{id: 2,username: "duzhaoquan",password: "1234",nickname: "银河护卫",avatar: "/imgs/me_page/avatar.png",},];
};

src\controller\auth.js

处理 auth 路由业务逻辑

const TokenService = require("../service/token");
const userList = require("../../data/user_list");module.exports = (req, res, next) => {const { username, password } = req.body;const userListData = userList();const userInfo = userListData.find((v) => v.username === username && v.password === password);if (!userInfo) {req.fail("请输入正确的用户名和密码");return;}delete userInfo.password;const token = TokenService.create({ username });res.success({token,userInfo,});
};

src\service\token.js

用于生成鉴权 token 以及校验合法性逻辑

const jwt = require("jsonwebtoken");
const secret = "SLDLKKDS323ssdd@#@@gf";const AUTH_URL = ["/api/user_info"];/*** 创建JWT令牌* @param {Object} useInfo - 用户信息对象,将被编码到JWT令牌中* @returns {string} 返回生成的JWT令牌字符串*/
const create = (useInfo) => {return jwt.sign(useInfo, secret, { expiresIn: 5 * 60 * 60 }); // 使用jwt.sign方法生成令牌,设置过期时间为5小时(5 * 60 * 60秒)
};/*** 解析JWT令牌的函数* @param {string} token - 需要解析的JWT令牌* @returns {object|null} - 返回解析后的令牌对象,如果解析失败或令牌不存在则返回null*/
const parse = (token) => {if (token) { // 检查令牌是否存在try {return jwt.verify(token, secret); // 尝试验证并解析令牌} catch (e) { // 捕获验证过程中可能发生的错误return null; // 如果验证失败,返回null}}return null; // 如果令牌不存在,返回null
};/*** 检查给定路径是否为认证URL* @param {string} path - 需要检查的路径* @returns {boolean} - 如果路径在认证URL列表中则返回true,否则返回false*/
const isAuthURL = (path) => {return AUTH_URL.includes(path); // 使用includes方法检查路径是否存在于AUTH_URL数组中
};/*** 检查请求是否授权的函数* @param {Object} req - 请求对象,包含请求路径和请求头信息* @returns {boolean} 返回true表示授权,false表示未授权*/
const isAuthorized = (req) => {// 检查请求路径是否为认证URLif (!isAuthURL(req.path)) {return true; // 如果不是认证URL,直接返回true,表示授权通过}// 从请求头中获取tokenconst token = req.headers["x-token"];// 解析tokenconst result = parse(token);// 打印token和解析结果,用于调试console.log("==========", req.headers["x-token"], result);// 检查解析结果中是否存在usernameif (result && result.username) {return true; // 如果解析结果有效且包含username,返回true,表示授权通过}return false; // 否则返回false,表示未授权
};module.exports = {create,isAuthorized,parse,
};

src\router.js

配置 auth 路由

const test = require("./controller/test");
const home_search = require("./controller/home_search");
const shop_list = require("./controller/shop_list");
const auth = require("./controller/auth");module.exports = (app) => {app.use("/api/test", test);app.use("/api/home_search", home_search);app.use("/api/shop_list", shop_list);app.use("/api/auth", auth);
};

src\app.js

设置全局鉴权拦截器

// 鉴权
server.use((req, res, next) => {if (TokenService.isAuthorized(req)) {next();} else {res.sendStatus(401);}
});
前端

src\types\user.d.ts

定义登录接口用户信息类型

export interface ILoginInfo {username: string;password: string;
}export interface IUserInfo {id: number | stringavatar: stringnickname: string
}export interface IAuth {token: stringuseriNFO: IUserInfo
}

src\api\user.ts

定义登录接口

import type { ILoginInfo, IAuth } from '@/types'
import axios from './base'
export const auth = ({ username, password }: ILoginInfo) => {return axios.post<IAuth, IAuth>('/auth', { username, password })
}

src\use\useAuth.ts

定义登录、退出登录 hook

import { useUserStore } from '@/stores/user'
import { computed } from 'vue'
import { auth } from '@/api/user'
import type { ILoginInfo } from '@/types'export function useAuth() {const store = useUserStore()const user = computed(() => store.getUserInfo)const login = async (data: ILoginInfo) => {const { token, userInfo } = await auth(data)store.setInfo({ token, userInfo })}const logout = () => {store.removeInfo()}return { user, login, logout }
}

src\stores\user.ts

定义缓存用户信息的 store

import type { IUserInfo } from '@/types'
import { defineStore } from 'pinia'
import { computed, ref } from 'vue'
// import { useLocalStorage } from '@/use/useLocalStorage'export interface IUserState {userInfo: IUserInfotoken: string
}// 设置默认信息
const getDefaultUserInfo = (): IUserInfo => ({id: '',avatar: 'https://b.yzcdn.cn/vant/icon-demo-1126.png',nickname: '请登录'
})export const useUserStore = defineStore('user', () => {// const {//   value: $userInfo,//   setValue: $setUserInfoValue,//   removeItem: $removeUserInfoItem// } = useLocalStorage('userInfo', getDefaultUserInfo())// const { setValue: $setTokenValue, removeItem: $removeTokenItem } = useLocalStorage('token', '')const state = ref({userInfo: getDefaultUserInfo(),token: ''})// 获取信息const getUserInfo = computed(() => {// 为什么不直接读 localStorage 的值呢?// 因为读取 localStorage 是比较耗时的操作,所以这里先读 store// if (!state.value.userInfo || !state.value.userInfo.id) {//   state.value.userInfo = $userInfo.value// }return state.value.userInfo})// 登陆时设置信息const setInfo = ({ token, userInfo }: IUserState) => {state.value.userInfo = userInfostate.value.token = token// $setUserInfoValue(userInfo)// $setTokenValue(token)}// 移除信息const removeInfo = () => {state.value.userInfo = getDefaultUserInfo()state.value.token = ''// $removeUserInfoItem()// $removeTokenItem()}return {state,getUserInfo,setInfo,removeInfo}
})
创建登录页,实现登录功能

src\views\login\LoginView.vue

<script setup lang="ts">
import { ref } from 'vue'
import type { ILoginInfo } from '@/types'
import { useAuth } from '@/use/useAuth'
const username = ref('')
const password = ref('')
const onClickLeft = () => history.back() //回到上一个页面
const { login } = useAuth()const onSubmit = async (data: ILoginInfo) => {await login(data)onClickLeft()
}
</script><template><div class="login-page on-fullscreen"><VanNavBar title="请登录" left-text="返回" left-arrow @click="onClickLeft"></VanNavBar><VanForm class="login-page__form" @submit="onSubmit"><VanCellGroup inset><VanFieldv-model="username"name="username"label="用户名"placeholder="用户名":rules="[{ required: true, message: '请填写用户名' }]"/><VanFieldv-model="password"name="password"label="密码"placeholder="密码":rules="[{ required: true, message: '请填写密码' }]"/></VanCellGroup><div style="margin: 16px"><VanButton round block type="primary" native-type="submit">登陆</VanButton></div></VanForm></div>
</template><style lang="scss" scoped>
.login-page {.login-page__form {margin-top: 100px;}
}
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/100493.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/100493.shtml
英文地址,请注明出处:http://en.pswp.cn/diannao/100493.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java Swagger2 能显示页面但看不到一个接口

反复检查之后&#xff0c;发现问题出在的代码如下&#xff1a; ApiModelProperty(value "材料链接地址", example "{ApiHost}/storage/test.pdf")private String url; 结论&#xff1a;example的值包括了 { 和 } &#xff0c;导致网页解析的JSON数据失败…

2025年- H143-Lc344. 反转字符串(字符串)--Java版

1.题目2.思路 方法一&#xff1a;比如有5个元素 s[0],s[1],s[2],s[3],s[4] 反转之后对应 s[4],s[3],s[2],s[1],s[0] 所以s[0]s[4], s[1]s[3] s[i]s[n-1-i] 方法2:双指针 left0,rights.length-1; 当left<right的时候&#xff0c;交换两个元素的位置&#xff0c;左指针左移&am…

微服务高可用流程讲解

如何理解从前端nginx到后端微服务高可用架构问题&#xff0c;下面从nginx、gateway、nacos、各个服务节点的角度讲解下应该如何进行高可用&#xff0c;比如nginx是前端向后端进行的负载均衡&#xff0c;也相当于均衡地向各个gateway网关进行请求&#xff0c;再由gateway网关拉取…

留个档,Unity,Animation控制相机,出现抖动的问题记录

起因是项目用了一段高度自定义的过程复杂的相机Animation&#xff0c;来控制虚拟相机位移旋转。 发现在不同的电脑上&#xff0c;出现了不同程度的抖动。 搜索过程中&#xff0c;发现关键词&#xff1a;World Origin Rebasing。 Unity 世界坐标使用 float&#xff08;单精度浮点…

组合对冲策略(外汇版)

在复杂多变的外汇市场中&#xff0c;投资者常常面临着汇率波动带来的风险。为了降低这种风险&#xff0c;对冲策略成为了一种有效的风险管理工具。以下将详细介绍三种组合对冲策略&#xff0c;它们分别是基于多货币正负相关对冲、区域性货币对冲以及全日元货币对冲的策略。①多…

GPT-5-Codex 正式发布:迈向真正的“自主编程”时代

在 Anthropic Claude 近期遭遇争议的同时&#xff0c;OpenAI 推出了其编程领域的王牌产品——GPT-5-Codex。这并非简单的模型升级&#xff0c;而是基于 GPT-5 专为“自主编程”&#xff08;Autonomous Programming&#xff09;场景深度优化的专用版本&#xff0c;标志着 AI 编程…

java面试:了解redis的集群么,怎么通过redis的集群来实现redis的高可用?

我们知道&#xff0c;为了帮助数据库缓解高并发的压力&#xff0c;我们会上reids缓存帮助数据库分摊&#xff0c;虽说常见场景的并发量还不足以让redis宕机&#xff0c;但假设出现了极高的并发场景&#xff0c;redis依旧是有宕机的可能的&#xff0c;毕竟单点部署的redis容易出…

氧气科技亮相GDMS全球数字营销峰会,分享AI搜索时代GEO新观

2025年9月16日&#xff0c;全球数字营销领域的年度盛会——GDMS&#xff08;Global Digital Marketing Summit&#xff09;在上海国家会展中心盛大举行。作为品牌数字化转型的风向标&#xff0c;本届峰会汇聚来自全球的CEO、CMO、CDO及营销领域高管&#xff0c;共同探讨AI驱动下…

搭建Gin通用框架

Gin Web 开发脚手架技术文档 项目概述 本项目是一个基于 Gin 框架的 Go Web 开发脚手架模板&#xff0c;提供了完整的项目结构、配置管理、日志记录、MySQL 和 Redis 数据库连接等常用功能集成。 项目结构 gindemo/ ├── gindemo.exe # 编译后的可执行文件 ├── g…

windows 平台下 ffmpeg 硬件编解码环境查看

环境&#xff1a; 1&#xff0c;nvidia 显卡 2&#xff0c;驱动安装 powershell 下 执行如下命令&#xff0c;出现GPU信息 说明驱动安装正常。 nvidia-smi 3&#xff0c;安装支持 NVENC 的 FFmpeg &#xff08;1&#xff09;Windows 下 编译 FFmpeg 需要 CUDA Toolkit &am…

08_多层感知机

1. 单层感知机 1.1 感知机① 线性回归输出的是一个实数&#xff0c;感知机输出的是一个离散的类。1.2 训练感知机 ① 如果分类正确的话y<w,x>为正数&#xff0c;负号后变为一个负数&#xff0c;max后输出为0&#xff0c;则梯度不进行更新。 ② 如果分类错了&#xff0c;y…

安卓实现miniLzo压缩算法

LZO官方源码 http://www.oberhumer.com/opensource/lzo 找到miniLZO点击Dowload miniLZO下载源码 http://www.oberhumer.com/opensource/lzo/download/minilzo-2.10.tar.gz demo源码(包含安卓) https://github.com/xzw421771880/MiniLzo_Mobile.git 1.代码部分 1.1.测试…

如何在ubuntu下用pip安装aider,解决各种报错问题

aider中文文档网站上给出的安装说明比较简单&#xff1a; https://aider.doczh.com/docs/install.html 但是在一个干净的ubuntu环境中按文档中的命令安装时&#xff0c;会报错&#xff0c;经过一番尝试之后&#xff0c;解决了报错问题&#xff0c;成功完成了安装。 成功安装执…

Kotlin flow详解

流式数据处理基础 Kotlin Flow 是基于协程的流式数据处理 API&#xff0c;要深入理解 Flow&#xff0c;首先需要明确流的概念及其处理方式。 流(Stream)如同水流&#xff0c;是一种连续不断的数据序列&#xff0c;在编程中具有以下核心特征&#xff1a; 数据按顺序产生和消费支…

DeepSeek V3 深度解析:MoE、MLA 与 GRPO 的架构革新

简介 DeepSeek&#xff08;深度求索&#xff09;是一家源自中国的人工智能公司&#xff0c;成立于2023年&#xff0c;总部位于中国杭州。前身是国内量化投资巨头幻方量化的子公司。公司专注于开发低成本、高性能的AI模型&#xff0c;致力于通过技术创新推动人工智能技术的普惠…

Flask学习笔记(三)--URL构建与模板的使用

一、URL构建url_for()函数对于动态构建特定函数的URL非常有用。 该函数接受函数的名称作为第一个参数&#xff0c;并接受一个或多个关键字参数&#xff0c;每个参数对应于URL的变量部分。from flask import Flask, redirect, url_forapp Flask(__name__)app.route(/admin)def …

Pyside6 + QML - 从官方的例程开始

导言如上所示&#xff0c;登上Qt Pyside6的官方网址&#xff1a;https://doc.qt.io/qtforpython-6/index.html&#xff0c;点击“Write your first Qt application”的"Start here!"按钮。 效果&#xff1a;工程代码&#xff1a; github:https://github.com/q1641293…

Python爬虫实战:研究Pandas,构建物联网数据采集和分析系统

1. 引言 1.1 研究背景 物联网(Internet of Things, IoT)作为新一代信息技术的重要组成部分,已广泛应用于智能交通、环境监测、智慧家居等多个领域。据 Gartner 预测,到 2025 年全球物联网设备数量将达到 750 亿台,产生的数据量将突破 zettabyte 级别。物联网平台作为数据…

深度学习入门基石:线性回归与 Softmax 回归精讲

一、线性回归&#xff1a;从房价预测看懂 “连续值预测” 逻辑 线性回归是深度学习的 “敲门砖”&#xff0c;它的核心思想是用线性关系拟合数据规律&#xff0c;解决连续值预测问题—— 比如根据房屋特征估算房价、根据温度湿度预测降雨量等。 1. 从生活案例到数学模型 拿房价…

GPT-5-Codex CLI保姆级教程:获取API Key配置与openai codex安装详解

朋友们&#xff0c;就在 2025 年 9 月中旬&#xff0c;OpenAI 悄悄扔下了一颗重磅炸弹&#xff1a;GPT-5-Codex。 如果你以为这只是又一次平平无奇的模型升级&#xff0c;那可就大错特错了。 我可以这么说&#xff1a;软件开发的游戏规则&#xff0c;从这一刻起&#xff0c;可能…