我的頁面開發

?我的頁面開發?
后端

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;可能…