diff --git a/.env b/.env
new file mode 100644
index 0000000..b1f7c87
--- /dev/null
+++ b/.env
@@ -0,0 +1 @@
+VITE_BASE_URL = http://127.0.0.1:8888
\ No newline at end of file
diff --git a/src/App.vue b/src/App.vue
index 5d229d9..71e4840 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -1,12 +1,37 @@
diff --git a/src/api/http.js b/src/api/http.js
deleted file mode 100644
index d0889a6..0000000
--- a/src/api/http.js
+++ /dev/null
@@ -1,111 +0,0 @@
-import Request from 'luch-request'
-const tokeyKey = 'Authorization'
-const env = import.meta.env
-
-// 创建实例
-const axiosInstance = new Request({
- baseURL: env.VITE_BASE_URL,
- timeout: 30 * 1000, // 超时配置
- headers: {
- 'Content-Type': 'application/json;charset=UTF-8'
- }
-})
-
-// 请求拦截
-axiosInstance.interceptors.request.use(
- config => {
- const token = ''
- if (token) {
- config.headers[tokeyKey] = ''
- }
- return config
- },
- error => {
- return Promise.reject(error)
- }
-)
-
-// 响应拦截
-axiosInstance.interceptors.response.use(
- response => {
- // console.log('response=>', response)
- const { status, data, config } = response
- if (status === 200) {
- const { code, message, data: resData } = data
- if (code === '0000') {
- return resData
- }
- // 文件
- if (config?.responseType === 'blob') {
- return response
- }
- // token过期
- if (code === '5010') {
- uni.showToast({
- title: 'token过期,请重新登陆!',
- icon: 'none'
- })
- // userStore.logout(false)
- return
- }
- uni.showToast({
- title: message || '接口请求异常',
- icon: 'none'
- })
- return Promise.reject(data)
- }
- uni.showToast({
- title: `${status}服务器响应异常`,
- icon: 'none'
- })
- return Promise.reject(data)
- },
- error => {
- // 如果是取消请求,返回空的Promise,避免触发异常处理
- if (axiosInstance.isCancel(error)) {
- return new Promise(() => {})
- }
- const { response, code, message, config } = error
- if (!response) {
- uni.showToast({
- title: '连接超时,请稍后重试',
- icon: 'none'
- })
- } else {
- const { _retry } = config
- const { status } = response
- if (code === 'ECONNABORTED' && message.indexOf('timeout') !== -1 && !_retry) {
- uni.showToast({
- title: '连接超时,请稍后重试',
- icon: 'none'
- })
- } else {
- uni.showToast({
- title: `${status}`,
- icon: 'none'
- })
- }
- }
- return Promise.reject(error)
- }
-)
-
-/**
- * 上传文件
- * @param {*} url
- * @param {*} data
- * @returns
- */
-export const upload = (url, data) => {
- let formData = new FormData()
- Object.keys(data || []).forEach(key => {
- formData.append(key, data[key])
- })
- return axiosInstance.post(url, formData, {
- headers: {
- 'Content-Type': 'multipart/form-data'
- }
- })
-}
-
-export default axiosInstance
diff --git a/src/api/index.js b/src/api/index.js
new file mode 100644
index 0000000..7b3ee86
--- /dev/null
+++ b/src/api/index.js
@@ -0,0 +1,19 @@
+import net from './request.js';
+
+// import store from '../store';
+
+const API = {
+ /*
+ 用户相关
+ */
+ login: data => net.post('/user/login', data, false), // 登录
+ getUserInfo: () => net.get('/user/info', {}, true), // 获取用户信息
+ getUserInfoById: id => net.get(`/user/info/id`, {}, true), // 获取用户信息
+ updateUserInfo: data => net.put('/user/info', data, true), // 更新用户信息
+ upload: data => net.post('/user/upload', data, true), // 上传头像
+ getLoverInfo: () => net.get('/user/lover', {}, true), // 获取另一半信息
+
+};
+
+export default API
+
diff --git a/src/api/modules/test.js b/src/api/modules/test.js
deleted file mode 100644
index 6c7b64d..0000000
--- a/src/api/modules/test.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import http from '@/api/http.js'
-const VITE_BASE_URL_AUTH = import.meta.env.VITE_BASE_URL_AUTH // 认证中心
-export default {
- login: data => {
- return http.request({
- baseURL: VITE_BASE_URL_AUTH,
- url: '/login',
- method: 'post',
- data
- })
- }
-}
diff --git a/src/api/request.js b/src/api/request.js
new file mode 100644
index 0000000..ac4443f
--- /dev/null
+++ b/src/api/request.js
@@ -0,0 +1,150 @@
+import config from '../config'
+
+const LOGIN_PAGE = '/pages/user/login'
+
+/**
+ * 获取本地 token
+ */
+function getToken() {
+ return uni.getStorageSync('token') || ''
+}
+
+/**
+ * 统一处理未登录或被踢下线
+ */
+function handleAuthFail(checkLogin = true) {
+ console.log('开始清理登录信息并跳转登录页')
+ uni.removeStorageSync('token')
+ uni.removeStorageSync('tokenExpiresAt')
+ uni.removeStorageSync('userInfo')
+ if (checkLogin) {
+ console.log('准备跳转到登录页:', LOGIN_PAGE)
+ // 使用 reLaunch 强制跳转到登录页,避免用户返回到已失效的页面
+ uni.reLaunch({
+ url: LOGIN_PAGE,
+ success: () => {
+ console.log('跳转登录页成功')
+ },
+ fail: (err) => {
+ console.log('跳转登录页失败:', err)
+ }
+ })
+ }
+}
+
+/**
+ * 构建请求头
+ */
+function buildHeaders(customHeaders = {}) {
+ return {
+ 'Content-Type': 'application/json',
+ 'Authorization': getToken(),
+ ...customHeaders
+ }
+}
+
+/**
+ * 通用请求方法
+ */
+function baseRequest({ url, method = 'GET', data = {}, checkLogin = true, headers = {} }) {
+ return new Promise((resolve, reject) => {
+ // 确保URL拼接正确,避免重复的斜杠
+ const fullUrl = config.baseUrl.replace(/\/$/, '') + '/' + url.replace(/^\//, '')
+ console.log('请求URL:', fullUrl)
+
+ uni.request({
+ url: fullUrl,
+ method,
+ data,
+ header: buildHeaders(headers),
+ success: (res) => {
+ const { statusCode, data: resData } = res
+ if (statusCode === 200 && resData) {
+ // 账号在其他设备登录
+ if (resData.code === 409) {
+ uni.showModal({
+ title: '提示',
+ content: '您的账号已在其他设备登录,已强制下线!',
+ showCancel: false,
+ success: () => handleAuthFail(checkLogin)
+ })
+ resolve(resData)
+ return
+ }
+ // 用户认证失败
+ if (resData.code === 5) {
+ handleAuthFail(checkLogin)
+ resolve(resData)
+ return
+ }
+ // 授权已过期
+ if (resData.code === 5) {
+ console.log('检测到授权过期,code=7,准备跳转登录页')
+ uni.showToast({
+ title: '授权已过期,请重新登录',
+ icon: 'none'
+ })
+ handleAuthFail(checkLogin)
+ resolve(resData)
+ return
+ }
+ resolve(resData)
+ } else {
+ reject({
+ code: statusCode,
+ msg: res.errMsg || '网络错误',
+ data: null
+ })
+ }
+ },
+ fail: (err) => {
+ console.log('请求失败:', err)
+ // 处理401未授权错误
+ if (err.statusCode === 401 || err.code === 401) {
+ console.log('检测到401未授权,准备跳转登录页')
+ uni.showToast({
+ title: '授权已过期,请重新登录',
+ icon: 'none'
+ })
+ handleAuthFail(true)
+ reject({
+ code: 7,
+ msg: '授权已过期',
+ data: null
+ })
+ return
+ }
+ reject({
+ code: 0,
+ msg: err.errMsg || '请求失败',
+ data: null
+ })
+ }
+ })
+ })
+}
+
+/**
+ * 导出常用请求方法
+ */
+const request = {
+ get(url, data = {}, checkLogin = true, headers = {}) {
+ return baseRequest({ url, method: 'GET', data, checkLogin, headers })
+ },
+ post(url, data = {}, checkLogin = true, headers = {}) {
+ return baseRequest({ url, method: 'POST', data, checkLogin, headers })
+ },
+ put(url, data = {}, checkLogin = true, headers = {}) {
+ return baseRequest({ url, method: 'PUT', data, checkLogin, headers })
+ },
+ delete(url, data = {}, checkLogin = true, headers = {}) {
+ return baseRequest({ url, method: 'DELETE', data, checkLogin, headers })
+ },
+
+ // 兼容原有的http.request方法
+ request: ({ url, method = 'GET', data = {}, headers = {} }) => {
+ return baseRequest({ url, method, data, checkLogin: true, headers })
+ }
+}
+
+export default request
\ No newline at end of file
diff --git a/src/config/index.js b/src/config/index.js
new file mode 100644
index 0000000..b5e4167
--- /dev/null
+++ b/src/config/index.js
@@ -0,0 +1,18 @@
+// isdev 为 true 表示开发环境 false 表示发布环境
+const isdev = true;
+
+// 开发环境使用代理,生产环境使用完整URL
+const baseUrl = isdev ? 'http://127.0.0.1:8888/' : 'http://lckt.hnlc5588.cn/';// 开发环境代理 & 生产环境
+
+const shareUrl = isdev ? 'https://h5.gwkjxb.com/' : 'http://test_h5.gwkjxb.com/';
+
+const config = {
+ appName: '小呆呆的私人菜谱',
+ baseUrl,
+ appVersion: '1.0.0',
+ developer: '小呆呆的私人菜谱',
+ shareUrl,
+ appID:'wx8ed262fbd9eaaf74',
+ isdev
+}
+export default config
diff --git a/src/manifest.json b/src/manifest.json
index 7093534..55121f6 100644
--- a/src/manifest.json
+++ b/src/manifest.json
@@ -1,6 +1,6 @@
{
- "name" : "zy",
- "appid" : "",
+ "name" : "xdd-menu",
+ "appid" : "__UNI__3FD9A6A",
"description" : "",
"versionName" : "1.0.0",
"versionCode" : "100",
@@ -44,7 +44,7 @@
},
"quickapp" : {},
"mp-weixin" : {
- "appid" : "",
+ "appid" : "wx8ed262fbd9eaaf74",
"mergeVirtualHostAttributes" : true,
"setting" : {
"urlCheck" : false,
diff --git a/src/pages.json b/src/pages.json
index c62bddf..19d6580 100644
--- a/src/pages.json
+++ b/src/pages.json
@@ -2,7 +2,6 @@
"easycom": {
"autoscan": true,
"custom": {
- // uni-ui 规则如下配置
"^uni-(.*)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue",
"^u--(.*)": "uview-plus/components/u-$1/u-$1.vue",
"^u-([^-].*)": "uview-plus/components/u-$1/u-$1.vue",
@@ -12,59 +11,135 @@
}
},
"pages": [
- //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
+ {
+ "path": "pages/user/login",
+ "style": {
+ "navigationBarTitleText": "登录",
+ "enablePullDownRefresh": false,
+ "navigationStyle": "custom"
+ }
+ },
+ {
+ "path": "pages/user/setup",
+ "style": {
+ "navigationBarTitleText": "完善信息",
+ "enablePullDownRefresh": false,
+ "navigationStyle": "custom"
+ }
+ },
{
"path": "pages/home/home",
"style": {
- "navigationBarTitleText": "",
+ "navigationBarTitleText": "我们的纪念日",
+ "enablePullDownRefresh": false,
+ "navigationStyle": "custom"
+ }
+ },
+ {
+ "path": "pages/recipe/recipe",
+ "style": {
+ "navigationBarTitleText": "私人菜谱",
"enablePullDownRefresh": false
}
},
{
- "path": "pages/components/components",
+ "path": "pages/recipe/create",
"style": {
- "navigationBarTitleText": "",
+ "navigationBarTitleText": "创建菜品",
"enablePullDownRefresh": false
}
},
{
- "path": "pages/functions/functions",
+ "path": "pages/recipe/detail",
"style": {
- "navigationBarTitleText": "",
+ "navigationBarTitleText": "菜品详情",
"enablePullDownRefresh": false
}
},
{
- "path": "pages/uploadDemo/uploadDemo",
+ "path": "pages/order/order",
"style": {
- "navigationBarTitleText": "",
+ "navigationBarTitleText": "点餐",
+ "enablePullDownRefresh": false
+ }
+ },
+ {
+ "path": "pages/diary/diary",
+ "style": {
+ "navigationBarTitleText": "我们的日志",
+ "enablePullDownRefresh": false
+ }
+ },
+ {
+ "path": "pages/diary/create",
+ "style": {
+ "navigationBarTitleText": "写日志",
+ "enablePullDownRefresh": false
+ }
+ },
+ {
+ "path": "pages/checkin/checkin",
+ "style": {
+ "navigationBarTitleText": "打卡目标",
+ "enablePullDownRefresh": false
+ }
+ },
+ {
+ "path": "pages/checkin/create",
+ "style": {
+ "navigationBarTitleText": "创建目标",
+ "enablePullDownRefresh": false
+ }
+ },
+ {
+ "path": "pages/profile/profile",
+ "style": {
+ "navigationBarTitleText": "个人中心",
"enablePullDownRefresh": false
}
}
],
"globalStyle": {
"navigationBarBackgroundColor": "#fff",
- "navigationBarTitleText": "订单中心",
- "navigationStyle": "custom",
+ "navigationBarTitleText": "情侣菜谱",
+ "navigationStyle": "default",
"navigationBarTextStyle": "black"
},
"tabBar": {
- "color": "#333333",
- "selectedColor": "#2E69FF",
+ "color": "#999999",
+ "selectedColor": "#FF6B9D",
"borderStyle": "white",
"backgroundColor": "#ffffff",
"list": [
{
"pagePath": "pages/home/home",
- "text": "首页"
+ "text": "首页",
+ "iconPath": "./static/images/home.png",
+ "selectedIconPath": "./static/images/home-active.png"
},
{
- "pagePath": "pages/components/components",
- "text": "组件"
+ "pagePath": "pages/recipe/recipe",
+ "text": "菜谱",
+ "iconPath": "./static/images/recipe.png",
+ "selectedIconPath": "./static/images/recipe-active.png"
},
{
- "pagePath": "pages/functions/functions",
- "text": "功能"
+ "pagePath": "pages/diary/diary",
+ "text": "日志",
+ "iconPath": "./static/images/diary.png",
+ "selectedIconPath": "./static/images/diary-active.png"
+ },
+ {
+ "pagePath": "pages/checkin/checkin",
+ "text": "打卡",
+ "iconPath": "./static/images/checkin.png",
+ "selectedIconPath": "./static/images/checkin-active.png"
+ },
+ {
+ "pagePath": "pages/profile/profile",
+ "text": "我的",
+ "iconPath": "./static/images/profile.png",
+ "selectedIconPath": "./static/images/profile-active.png"
}
]
}
diff --git a/src/pages/checkin/checkin.vue b/src/pages/checkin/checkin.vue
new file mode 100644
index 0000000..72efe3f
--- /dev/null
+++ b/src/pages/checkin/checkin.vue
@@ -0,0 +1,577 @@
+
+
+
+
+
+
+
+
+
+
+ {{ completedCount }}
+ 已完成
+
+
+ {{ inProgressCount }}
+ 进行中
+
+
+ {{ streakDays }}
+ 连续天数
+
+
+
+
+
+
+
+ {{ tab.name }}
+ ({{ tab.count }})
+
+
+
+
+
+
+
+
+
+
+ 进度: {{ goal.completedCount }}/{{ goal.totalCount }}
+ {{ Math.round((goal.completedCount / goal.totalCount) * 100) }}%
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/pages/components/components.vue b/src/pages/components/components.vue
deleted file mode 100644
index 89f3590..0000000
--- a/src/pages/components/components.vue
+++ /dev/null
@@ -1,46 +0,0 @@
-
-
-
-
-
-
- {{ item.name }}
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/pages/diary/diary.vue b/src/pages/diary/diary.vue
new file mode 100644
index 0000000..d59e4e1
--- /dev/null
+++ b/src/pages/diary/diary.vue
@@ -0,0 +1,457 @@
+
+
+
+
+
+
+
+
+
+
+
+ {{ diary.title }}
+ {{ diary.content }}
+
+
+
+
+
+
+
+ +{{ diary.images.length - 3 }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/pages/functions/functions.vue b/src/pages/functions/functions.vue
deleted file mode 100644
index ab2d20c..0000000
--- a/src/pages/functions/functions.vue
+++ /dev/null
@@ -1,50 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
- 皮肤测试
-
-
-
-
-
-
-
-
diff --git a/src/pages/home/home.vue b/src/pages/home/home.vue
index ce8975a..4482726 100644
--- a/src/pages/home/home.vue
+++ b/src/pages/home/home.vue
@@ -1,15 +1,450 @@
-
-
-
-
- 自适应的内容滚动区域,兼容IOS下不显示滚动条
-
- 占位盒子
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 我们在一起已经
+
+ {{ loveDays }}
+ 天
+
+ {{ startDate }}
+
+
+
+
+
+
+
+ 写日志
+
+
+
+
+
+ 点餐下单
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.name }}
+ {{ item.date }}
+
+
+ {{ item.countdown }}
+
+
+
+
+
+
-
-
+
+
+
\ No newline at end of file
diff --git a/src/pages/order/order.vue b/src/pages/order/order.vue
new file mode 100644
index 0000000..aff09b7
--- /dev/null
+++ b/src/pages/order/order.vue
@@ -0,0 +1,562 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ category.name }}
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ dish.name }}
+ {{ dish.description }}
+
+
+
+ {{ dish.cookTime }}分钟
+
+
+
+ {{ dish.difficulty }}
+
+
+
+
+
+ ¥{{ dish.price }}
+ /份
+
+
+
+
+
+
+ {{ getCartQuantity(dish.id) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 清空
+
+
+ 去下单
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/pages/profile/profile.vue b/src/pages/profile/profile.vue
new file mode 100644
index 0000000..aa06291
--- /dev/null
+++ b/src/pages/profile/profile.vue
@@ -0,0 +1,567 @@
+
+
+
+
+
+
+
+
+
+
+
+ 我的功能
+
+
+
+
+
+ 我的菜谱
+
+
+
+
+
+
+ 我的日志
+
+
+
+
+
+
+ 我的目标
+
+
+
+
+
+
+ 设置
+
+
+
+
+
+ 应用设置
+
+
+
+
+
+
+ 隐私设置
+
+
+
+
+
+
+ 消息通知
+
+
+
+
+
+
+ 其他
+
+
+
+
+
+ 帮助中心
+
+
+
+
+
+
+ 意见反馈
+
+
+
+
+
+
+ 关于我们
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/pages/recipe/recipe.vue b/src/pages/recipe/recipe.vue
new file mode 100644
index 0000000..22b8871
--- /dev/null
+++ b/src/pages/recipe/recipe.vue
@@ -0,0 +1,338 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ category.name }}
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ recipe.name }}
+ {{ recipe.description }}
+
+
+
+ {{ recipe.cookTime }}分钟
+
+
+
+ {{ recipe.difficulty }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/pages/user/login.vue b/src/pages/user/login.vue
new file mode 100644
index 0000000..da45a5a
--- /dev/null
+++ b/src/pages/user/login.vue
@@ -0,0 +1,526 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 私人菜谱管理
+
+
+
+ 记录美好时光
+
+
+
+ 打卡目标完成
+
+
+
+ 便捷点餐服务
+
+
+
+
+
+
+ 登录后即可使用全部功能
+
+
+
+
+
+
+
+ 登录即表示同意
+ 《用户协议》
+ 和
+ 《隐私政策》
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pages/user/setup.vue b/src/pages/user/setup.vue
new file mode 100644
index 0000000..62e25aa
--- /dev/null
+++ b/src/pages/user/setup.vue
@@ -0,0 +1,328 @@
+
+
+
+
+ 获取用户头像昵称
+
+
+
+
+
+
+
+
+ 昵称:
+
+
+
+
+
+
+ · 申请获取以下权限
+
+
+ · 获得你的信息(昵称、头像等)
+
+
+
+ 保存
+
+
+
+
+
+
+
diff --git a/src/static/images/checkin-active.png b/src/static/images/checkin-active.png
new file mode 100644
index 0000000..b68cca6
Binary files /dev/null and b/src/static/images/checkin-active.png differ
diff --git a/src/static/images/checkin.png b/src/static/images/checkin.png
new file mode 100644
index 0000000..aa5442f
Binary files /dev/null and b/src/static/images/checkin.png differ
diff --git a/src/static/images/diary-active.png b/src/static/images/diary-active.png
new file mode 100644
index 0000000..7b38c29
Binary files /dev/null and b/src/static/images/diary-active.png differ
diff --git a/src/static/images/diary.png b/src/static/images/diary.png
new file mode 100644
index 0000000..cb537ab
Binary files /dev/null and b/src/static/images/diary.png differ
diff --git a/src/static/images/home-active.png b/src/static/images/home-active.png
new file mode 100644
index 0000000..036f495
Binary files /dev/null and b/src/static/images/home-active.png differ
diff --git a/src/static/images/home.png b/src/static/images/home.png
new file mode 100644
index 0000000..57ce6a1
Binary files /dev/null and b/src/static/images/home.png differ
diff --git a/src/static/images/profile-active.png b/src/static/images/profile-active.png
new file mode 100644
index 0000000..2efe615
Binary files /dev/null and b/src/static/images/profile-active.png differ
diff --git a/src/static/images/profile.png b/src/static/images/profile.png
new file mode 100644
index 0000000..a4324d4
Binary files /dev/null and b/src/static/images/profile.png differ
diff --git a/src/static/images/recipe-active.png b/src/static/images/recipe-active.png
new file mode 100644
index 0000000..2ccafbd
Binary files /dev/null and b/src/static/images/recipe-active.png differ
diff --git a/src/static/images/recipe.png b/src/static/images/recipe.png
new file mode 100644
index 0000000..673c793
Binary files /dev/null and b/src/static/images/recipe.png differ
diff --git a/src/store/user.js b/src/store/user.js
index c74bf31..cb8b9dc 100644
--- a/src/store/user.js
+++ b/src/store/user.js
@@ -4,7 +4,7 @@ export const useUserStore = defineStore({
id: 'user',
state: () => {
return {
- token: '',
+ token: uni.getStorageSync('token') || '', // 从缓存读取token
userInfo: {}, // 用户信息
appInfo: {}, // 应用信息
// 按钮权限编码
@@ -12,10 +12,107 @@ export const useUserStore = defineStore({
// 权限菜单
menuList: [],
// 权限路由
- permissionRoutes: []
+ permissionRoutes: [],
+ // 是否已登录
+ isLoggedIn: !!uni.getStorageSync('token')
}
},
unistorage: true,
- getters: {},
- actions: {}
+ getters: {
+ // 获取用户昵称
+ nickname: (state) => state.userInfo.nickname || '未登录',
+
+ // 获取用户头像
+ avatar: (state) => state.userInfo.avatar || '/static/images/default-avatar.png',
+
+ // 获取用户ID
+ userId: (state) => state.userInfo.userId || '',
+
+ // 检查是否已登录
+ hasLogin: (state) => state.isLoggedIn && !!state.token,
+
+ // 检查是否首次登录
+ isFirstLogin: (state) => state.userInfo.isFirstLogin || false
+ },
+ actions: {
+ // 设置用户信息
+ setUserInfo(userInfo) {
+ this.userInfo = userInfo
+ this.isLoggedIn = true
+ },
+
+ // 设置token
+ setToken(token) {
+ this.token = token
+ // 同时保存到本地缓存
+ uni.setStorageSync('token', token)
+ },
+
+ // 登录
+ async login(loginData) {
+ try {
+ // 这里可以调用登录API
+ // const result = await userApi.login(loginData)
+
+ // 模拟登录成功
+ const mockUserInfo = {
+ userId: '10086',
+ nickname: '小美',
+ avatar: '/static/images/default-avatar.png',
+ level: 'LV.5 美食达人'
+ }
+
+ this.setUserInfo(mockUserInfo)
+ this.setToken('mock_token_' + Date.now())
+
+ return {
+ success: true,
+ data: mockUserInfo
+ }
+ } catch (error) {
+ console.error('登录失败:', error)
+ return {
+ success: false,
+ message: error.message || '登录失败'
+ }
+ }
+ },
+
+ // 登出
+ logout() {
+ this.token = ''
+ this.userInfo = {}
+ this.isLoggedIn = false
+ this.permissionCodes = []
+ this.menuList = []
+ this.permissionRoutes = []
+ // 清除本地缓存
+ uni.removeStorageSync('token')
+ },
+
+ // 更新用户信息
+ updateUserInfo(userInfo) {
+ this.userInfo = { ...this.userInfo, ...userInfo }
+ // 如果更新了昵称,清除首次登录状态
+ if (userInfo.nickname) {
+ this.userInfo.isFirstLogin = false
+ }
+ },
+
+ // 检查登录状态
+ checkLoginStatus() {
+ // 从缓存重新读取token
+ const cachedToken = uni.getStorageSync('token')
+ if (cachedToken && cachedToken !== this.token) {
+ this.token = cachedToken
+ this.isLoggedIn = true
+ }
+ return this.hasLogin
+ },
+
+ // 清除首次登录状态
+ clearFirstLogin() {
+ this.userInfo.isFirstLogin = false
+ }
+ }
})