mirror of
https://gitee.com/ulthon/ulthon_admin.git
synced 2026-07-09 03:22:51 +08:00
feat(uniapp): 集成 Pinia 状态管理并实现用户认证流程
This commit is contained in:
9
.gitignore
vendored
9
.gitignore
vendored
@@ -40,3 +40,12 @@ result.txt
|
|||||||
test.php
|
test.php
|
||||||
/.env.prod
|
/.env.prod
|
||||||
extend/base/common/command/curd/migrate_output.php
|
extend/base/common/command/curd/migrate_output.php
|
||||||
|
|
||||||
|
# source 目录:多端工程依赖与构建产物
|
||||||
|
/source/**/node_modules
|
||||||
|
/source/**/dist
|
||||||
|
/source/**/.hbuilderx
|
||||||
|
/source/**/.idea
|
||||||
|
/source/**/.vscode
|
||||||
|
.trae/documents/新增 source 目录与 uni-app(CLI)基础工程.md
|
||||||
|
.trae/documents/uni-app 增加 env_request_utils 与用户状态机制.md
|
||||||
|
|||||||
@@ -3,6 +3,9 @@
|
|||||||
// !当前文件的内容应当与 /extend/base/admin/middleware.php 的内容一致,然后再根据实际情况设置
|
// !当前文件的内容应当与 /extend/base/admin/middleware.php 的内容一致,然后再根据实际情况设置
|
||||||
|
|
||||||
// 全局中间件定义文件
|
// 全局中间件定义文件
|
||||||
|
|
||||||
|
use think\middleware\AllowCrossDomain;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
|
||||||
// Session初始化
|
// Session初始化
|
||||||
@@ -14,4 +17,6 @@ return [
|
|||||||
// Csrf安全校验
|
// Csrf安全校验
|
||||||
\app\admin\middleware\CsrfMiddleware::class,
|
\app\admin\middleware\CsrfMiddleware::class,
|
||||||
|
|
||||||
|
AllowCrossDomain::class,
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -520,12 +520,12 @@ class AdminControllerBase extends BaseController
|
|||||||
!in_array($currentController, $adminConfig['no_login_controller']) &&
|
!in_array($currentController, $adminConfig['no_login_controller']) &&
|
||||||
!in_array($currentNode, $adminConfig['no_login_node'])
|
!in_array($currentNode, $adminConfig['no_login_node'])
|
||||||
) {
|
) {
|
||||||
empty($adminId) && $this->error('请先登录后台', [], __url('admin/login/index', ['back_url' => $back_url]));
|
empty($adminId) && $this->error('请先登录后台', [], __url('admin/login/index', ['back_url' => $back_url]), 40101);
|
||||||
|
|
||||||
// 判断是否登录过期
|
// 判断是否登录过期
|
||||||
if ($expireTime !== true && time() > $expireTime) {
|
if ($expireTime !== true && time() > $expireTime) {
|
||||||
session('admin', null);
|
session('admin', null);
|
||||||
$this->error('登录已过期,请重新登录', [], __url('admin/login/index', ['back_url' => $back_url]));
|
$this->error('登录已过期,请重新登录', [], __url('admin/login/index', ['back_url' => $back_url]), 40102);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
2
source/clients/uniapp/.npmrc
Normal file
2
source/clients/uniapp/.npmrc
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
legacy-peer-deps=true
|
||||||
|
|
||||||
5304
source/clients/uniapp/package-lock.json
generated
5304
source/clients/uniapp/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -52,6 +52,7 @@
|
|||||||
"@dcloudio/uni-mp-weixin": "3.0.0-4080720251210001",
|
"@dcloudio/uni-mp-weixin": "3.0.0-4080720251210001",
|
||||||
"@dcloudio/uni-mp-xhs": "3.0.0-4080720251210001",
|
"@dcloudio/uni-mp-xhs": "3.0.0-4080720251210001",
|
||||||
"@dcloudio/uni-quickapp-webview": "3.0.0-4080720251210001",
|
"@dcloudio/uni-quickapp-webview": "3.0.0-4080720251210001",
|
||||||
|
"pinia": "2.1.7",
|
||||||
"uview-plus": "^3.3.65",
|
"uview-plus": "^3.3.65",
|
||||||
"ului.css": "0.0.1",
|
"ului.css": "0.0.1",
|
||||||
"vue": "^3.4.21",
|
"vue": "^3.4.21",
|
||||||
|
|||||||
23
source/clients/uniapp/src/common/index.js
Normal file
23
source/clients/uniapp/src/common/index.js
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
export function sleep(ms) {
|
||||||
|
return new Promise((resolve) => setTimeout(resolve, ms))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function omitEmpty(obj) {
|
||||||
|
const result = {}
|
||||||
|
if (!obj || typeof obj !== 'object') return result
|
||||||
|
|
||||||
|
Object.keys(obj).forEach((key) => {
|
||||||
|
const value = obj[key]
|
||||||
|
if (value === '' || value === null || value === undefined) return
|
||||||
|
result[key] = value
|
||||||
|
})
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
export function toQueryString(params) {
|
||||||
|
const data = omitEmpty(params)
|
||||||
|
const parts = Object.keys(data).map((key) => `${encodeURIComponent(key)}=${encodeURIComponent(data[key])}`)
|
||||||
|
return parts.join('&')
|
||||||
|
}
|
||||||
|
|
||||||
5
source/clients/uniapp/src/config/env.js
Normal file
5
source/clients/uniapp/src/config/env.js
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export const env = {
|
||||||
|
apiBaseUrl: 'http://127.0.0.1:8000',
|
||||||
|
timeout: 60000,
|
||||||
|
}
|
||||||
|
|
||||||
@@ -4,9 +4,13 @@ import {
|
|||||||
import App from "./App.vue";
|
import App from "./App.vue";
|
||||||
import uviewPlus from 'uview-plus'
|
import uviewPlus from 'uview-plus'
|
||||||
import './styles/uview.scss'
|
import './styles/uview.scss'
|
||||||
|
import { pinia } from './store'
|
||||||
|
import { useUserStore } from './store/user'
|
||||||
export function createApp() {
|
export function createApp() {
|
||||||
const app = createSSRApp(App);
|
const app = createSSRApp(App);
|
||||||
app.use(uviewPlus);
|
app.use(uviewPlus);
|
||||||
|
app.use(pinia);
|
||||||
|
useUserStore(pinia).init();
|
||||||
return {
|
return {
|
||||||
app,
|
app,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -22,8 +22,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { setToken } from '../../utils/auth'
|
|
||||||
import { request } from '../../utils/request'
|
import { request } from '../../utils/request'
|
||||||
|
import { useUserStore } from '../../store/user'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
@@ -44,6 +44,7 @@ export default {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const userStore = useUserStore()
|
||||||
this.loading = true
|
this.loading = true
|
||||||
try {
|
try {
|
||||||
const res = await request({
|
const res = await request({
|
||||||
@@ -63,7 +64,7 @@ export default {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
setToken(token)
|
userStore.setToken(token)
|
||||||
uni.showToast({ title: '登录成功', icon: 'none' })
|
uni.showToast({ title: '登录成功', icon: 'none' })
|
||||||
|
|
||||||
uni.navigateBack({
|
uni.navigateBack({
|
||||||
|
|||||||
@@ -18,18 +18,24 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { clearToken, getToken } from '../../utils/auth'
|
|
||||||
import { request } from '../../utils/request'
|
import { request } from '../../utils/request'
|
||||||
|
import { useUserStore } from '../../store/user'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
computed: {
|
||||||
return {
|
userStore() {
|
||||||
token: '',
|
return useUserStore()
|
||||||
}
|
},
|
||||||
|
token() {
|
||||||
|
return this.userStore.token
|
||||||
|
},
|
||||||
|
isLoggedIn() {
|
||||||
|
return this.userStore.isLoggedIn
|
||||||
|
},
|
||||||
},
|
},
|
||||||
onShow() {
|
onShow() {
|
||||||
this.token = getToken()
|
this.userStore.init()
|
||||||
if (!this.token) {
|
if (!this.isLoggedIn) {
|
||||||
this.goLogin()
|
this.goLogin()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -38,7 +44,7 @@ export default {
|
|||||||
uni.navigateTo({ url: '/pages/login/index' })
|
uni.navigateTo({ url: '/pages/login/index' })
|
||||||
},
|
},
|
||||||
async logout() {
|
async logout() {
|
||||||
if (!this.token) {
|
if (!this.isLoggedIn) {
|
||||||
uni.showToast({ title: '当前未登录', icon: 'none' })
|
uni.showToast({ title: '当前未登录', icon: 'none' })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -49,8 +55,7 @@ export default {
|
|||||||
method: 'POST',
|
method: 'POST',
|
||||||
})
|
})
|
||||||
} finally {
|
} finally {
|
||||||
clearToken()
|
this.userStore.logout()
|
||||||
this.token = ''
|
|
||||||
uni.showToast({ title: '已退出', icon: 'none' })
|
uni.showToast({ title: '已退出', icon: 'none' })
|
||||||
uni.switchTab({ url: '/pages/index/index' })
|
uni.switchTab({ url: '/pages/index/index' })
|
||||||
}
|
}
|
||||||
|
|||||||
4
source/clients/uniapp/src/store/index.js
Normal file
4
source/clients/uniapp/src/store/index.js
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
import { createPinia } from 'pinia'
|
||||||
|
|
||||||
|
export const pinia = createPinia()
|
||||||
|
|
||||||
29
source/clients/uniapp/src/store/user.js
Normal file
29
source/clients/uniapp/src/store/user.js
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { defineStore } from 'pinia'
|
||||||
|
|
||||||
|
const TOKEN_KEY = 'ULTHON_ADMIN_TOKEN'
|
||||||
|
|
||||||
|
export const useUserStore = defineStore('user', {
|
||||||
|
state: () => ({
|
||||||
|
token: '',
|
||||||
|
inited: false,
|
||||||
|
}),
|
||||||
|
getters: {
|
||||||
|
isLoggedIn: (state) => !!state.token,
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
init() {
|
||||||
|
if (this.inited) return
|
||||||
|
this.token = uni.getStorageSync(TOKEN_KEY) || ''
|
||||||
|
this.inited = true
|
||||||
|
},
|
||||||
|
setToken(token) {
|
||||||
|
this.token = token || ''
|
||||||
|
uni.setStorageSync(TOKEN_KEY, this.token)
|
||||||
|
},
|
||||||
|
logout() {
|
||||||
|
this.token = ''
|
||||||
|
uni.removeStorageSync(TOKEN_KEY)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
@@ -1,18 +1,39 @@
|
|||||||
import { clearToken, getToken } from './auth'
|
import { env } from '../config/env'
|
||||||
|
import { pinia } from '../store'
|
||||||
|
import { useUserStore } from '../store/user'
|
||||||
|
|
||||||
const BASE_URL = ''
|
const AUTH_REQUIRED_CODE = 40101
|
||||||
|
const AUTH_EXPIRED_CODE = 40102
|
||||||
|
|
||||||
function buildUrl(url) {
|
function buildUrl(url) {
|
||||||
if (!url) return ''
|
if (!url) return ''
|
||||||
if (/^https?:\/\//i.test(url)) return url
|
if (/^https?:\/\//i.test(url)) return url
|
||||||
if (url.startsWith('/')) return `${BASE_URL}${url}`
|
const baseUrl = env.apiBaseUrl || ''
|
||||||
return `${BASE_URL}/${url}`
|
if (url.startsWith('/')) return `${baseUrl}${url}`
|
||||||
|
return `${baseUrl}/${url}`
|
||||||
}
|
}
|
||||||
|
|
||||||
function isLoginError(resData) {
|
function getCurrentRoutePath() {
|
||||||
const msg = (resData && resData.msg) || ''
|
try {
|
||||||
const url = (resData && resData.url) || ''
|
const pages = getCurrentPages()
|
||||||
return msg.includes('请先登录') || msg.includes('登录已过期') || url.includes('/admin/login')
|
const current = pages && pages[pages.length - 1]
|
||||||
|
const route = (current && (current.route || (current.$page && current.$page.fullPath))) || ''
|
||||||
|
return String(route)
|
||||||
|
} catch (e) {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function redirectToLoginIfNeeded() {
|
||||||
|
const route = getCurrentRoutePath()
|
||||||
|
if (route.includes('pages/login/index')) return
|
||||||
|
|
||||||
|
uni.navigateTo({
|
||||||
|
url: '/pages/login/index',
|
||||||
|
fail: () => {
|
||||||
|
uni.reLaunch({ url: '/pages/login/index' })
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function request(options) {
|
export function request(options) {
|
||||||
@@ -24,7 +45,9 @@ export function request(options) {
|
|||||||
...(options.header || {}),
|
...(options.header || {}),
|
||||||
}
|
}
|
||||||
|
|
||||||
const token = getToken()
|
const userStore = useUserStore(pinia)
|
||||||
|
userStore.init()
|
||||||
|
const token = userStore.token
|
||||||
if (token && !header.Authorization) {
|
if (token && !header.Authorization) {
|
||||||
header.Authorization = `Bearer ${token}`
|
header.Authorization = `Bearer ${token}`
|
||||||
}
|
}
|
||||||
@@ -39,7 +62,7 @@ export function request(options) {
|
|||||||
method,
|
method,
|
||||||
data: options.data || {},
|
data: options.data || {},
|
||||||
header,
|
header,
|
||||||
timeout: options.timeout || 60000,
|
timeout: options.timeout || env.timeout || 60000,
|
||||||
success: (res) => {
|
success: (res) => {
|
||||||
const resData = res.data
|
const resData = res.data
|
||||||
|
|
||||||
@@ -61,9 +84,9 @@ export function request(options) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isLoginError(resData)) {
|
if (resData.code === AUTH_REQUIRED_CODE || resData.code === AUTH_EXPIRED_CODE) {
|
||||||
clearToken()
|
userStore.logout()
|
||||||
uni.navigateTo({ url: '/pages/login/index' })
|
redirectToLoginIfNeeded()
|
||||||
}
|
}
|
||||||
|
|
||||||
uni.showToast({ title: resData.msg || '请求失败', icon: 'none' })
|
uni.showToast({ title: resData.msg || '请求失败', icon: 'none' })
|
||||||
@@ -80,4 +103,3 @@ export function request(options) {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user