feat(auth): 实现系统登录和权限控制功能
- 新增登录页面和相关逻辑 - 添加全局权限控制守卫 - 更新订单列表和详情页面,优化用户体验- 重构部分代码以支持新功能master
parent
781d598ae7
commit
0752efd3ff
|
|
@ -10,8 +10,11 @@ declare module 'vue' {
|
|||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
RouterView: typeof import('vue-router')['RouterView']
|
||||
VanButton: typeof import('vant/es')['Button']
|
||||
VanCellGroup: typeof import('vant/es')['CellGroup']
|
||||
VanCheckbox: typeof import('vant/es')['Checkbox']
|
||||
VanEmpty: typeof import('vant/es')['Empty']
|
||||
VanField: typeof import('vant/es')['Field']
|
||||
VanForm: typeof import('vant/es')['Form']
|
||||
VanIcon: typeof import('vant/es')['Icon']
|
||||
VanList: typeof import('vant/es')['List']
|
||||
VanLoading: typeof import('vant/es')['Loading']
|
||||
|
|
|
|||
|
|
@ -38,8 +38,18 @@ export const submitApproval = (params: any): Promise<AxiosResponse<ApiResponse<a
|
|||
// 将所有参数添加到FormData中
|
||||
Object.keys(params).forEach(key => {
|
||||
if (params[key] !== undefined && params[key] !== null) {
|
||||
// 特殊处理variables参数,它应该是一个对象
|
||||
if (key === 'variables' && typeof params[key] === 'object' && params[key] !== null) {
|
||||
// 将variables对象的每个属性单独添加到FormData中
|
||||
Object.keys(params[key]).forEach(variableKey => {
|
||||
if (params[key][variableKey] !== undefined && params[key][variableKey] !== null) {
|
||||
formData.append(`variables[${variableKey}]`, params[key][variableKey].toString())
|
||||
}
|
||||
})
|
||||
} else {
|
||||
formData.append(key, params[key].toString())
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return http.post('/project/order/order/approve', formData)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { createApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
import router from './router'
|
||||
import { createPinia } from 'pinia'
|
||||
import { store, initStores } from './store'
|
||||
|
||||
// Vant样式
|
||||
import 'vant/lib/index.css'
|
||||
|
|
@ -13,7 +13,10 @@ import '@/styles/index.scss'
|
|||
|
||||
const app = createApp(App)
|
||||
|
||||
app.use(createPinia())
|
||||
app.use(store)
|
||||
app.use(router)
|
||||
|
||||
// 初始化 stores
|
||||
initStores()
|
||||
|
||||
app.mount('#app')
|
||||
|
|
@ -1,17 +1,29 @@
|
|||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import type { RouteRecordRaw } from 'vue-router'
|
||||
import { useAuthStore } from '@/store/auth'
|
||||
import { store } from '@/store'
|
||||
|
||||
const routes: RouteRecordRaw[] = [
|
||||
{
|
||||
path: '/',
|
||||
redirect: '/list'
|
||||
redirect: '/login'
|
||||
},
|
||||
{
|
||||
path: '/login',
|
||||
name: 'Login',
|
||||
component: () => import('@/views/Login/index.vue'),
|
||||
meta: {
|
||||
title: '系统登录',
|
||||
requiresAuth: false
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/list',
|
||||
name: 'OrderList',
|
||||
component: () => import('@/views/List/index.vue'),
|
||||
meta: {
|
||||
title: '订单列表'
|
||||
title: '订单列表',
|
||||
requiresAuth: true
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -19,7 +31,8 @@ const routes: RouteRecordRaw[] = [
|
|||
name: 'OrderDetail',
|
||||
component: () => import('@/views/Detail/index.vue'),
|
||||
meta: {
|
||||
title: '订单详情'
|
||||
title: '订单详情',
|
||||
requiresAuth: true
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
@ -38,7 +51,26 @@ router.beforeEach((to, from, next) => {
|
|||
if (to.meta?.title) {
|
||||
document.title = to.meta.title as string
|
||||
}
|
||||
|
||||
// 检查是否需要认证
|
||||
const requiresAuth = to.matched.some(record => record.meta.requiresAuth !== false)
|
||||
|
||||
// 获取认证状态
|
||||
const authStore = useAuthStore(store)
|
||||
const isAuthenticated = authStore.isAuthenticated || localStorage.getItem('isAuthenticated') === 'true'
|
||||
|
||||
// 如果需要认证但未登录,重定向到登录页
|
||||
if (requiresAuth && !isAuthenticated) {
|
||||
next('/login')
|
||||
}
|
||||
// 如果已登录且访问登录页,重定向到列表页
|
||||
else if (to.path === '/login' && isAuthenticated) {
|
||||
next('/list')
|
||||
}
|
||||
// 其他情况正常跳转
|
||||
else {
|
||||
next()
|
||||
}
|
||||
})
|
||||
|
||||
export default router
|
||||
|
|
@ -6,6 +6,13 @@ export interface ApiResponse<T = any> {
|
|||
total?: number
|
||||
}
|
||||
|
||||
// 登录参数类型
|
||||
export interface LoginParams {
|
||||
username: string
|
||||
password: string
|
||||
rememberMe?: boolean
|
||||
}
|
||||
|
||||
// 订单状态类型
|
||||
export type OrderStatus = '0' | '1' | '2' // 待审批、已审批、已拒绝
|
||||
|
||||
|
|
|
|||
|
|
@ -54,7 +54,9 @@ class HttpClient {
|
|||
switch (status) {
|
||||
case 401:
|
||||
message = '未授权,请重新登录'
|
||||
// 这里可以处理登录跳转逻辑
|
||||
// 清除认证信息并跳转到登录页
|
||||
localStorage.removeItem('isAuthenticated')
|
||||
window.location.href = '/login'
|
||||
break
|
||||
case 403:
|
||||
message = '拒绝访问'
|
||||
|
|
@ -62,6 +64,12 @@ class HttpClient {
|
|||
case 404:
|
||||
message = '请求地址不存在'
|
||||
break
|
||||
case 302:
|
||||
// 处理302重定向到登录页
|
||||
message = '会话已过期,请重新登录'
|
||||
localStorage.removeItem('isAuthenticated')
|
||||
window.location.href = '/login'
|
||||
break
|
||||
case 500:
|
||||
message = '服务器内部错误'
|
||||
break
|
||||
|
|
|
|||
|
|
@ -51,11 +51,11 @@
|
|||
</div>
|
||||
<div class="info-item">
|
||||
<span class="label">BG</span>
|
||||
<span class="value">{{ currentOrderInfo.bgProperty || '' }}</span>
|
||||
<span class="value">{{ currentOrderInfo.bgPropertyDesc || '' }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="label">行业</span>
|
||||
<span class="value">{{ currentOrderInfo.industryType || '' }}</span>
|
||||
<span class="value">{{ currentOrderInfo.industryTypeDesc || '' }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="label">代表处</span>
|
||||
|
|
@ -83,7 +83,7 @@
|
|||
</div>
|
||||
<div class="info-item">
|
||||
<span class="label">币种</span>
|
||||
<span class="value">{{ currentOrderInfo.currencyType || '' }}</span>
|
||||
<span class="value">{{ currentOrderInfo.currencyTypeDesc || '' }}</span>
|
||||
</div>
|
||||
|
||||
<div class="info-item">
|
||||
|
|
@ -100,11 +100,11 @@
|
|||
</div>
|
||||
<div class="info-item">
|
||||
<span class="label">公司直发</span>
|
||||
<span class="value">{{ currentOrderInfo.companyDelivery}}</span>
|
||||
<span class="value">{{ currentOrderInfo.companyDeliveryDesc}}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="label">下单通路</span>
|
||||
<span class="value">{{ currentOrderInfo.orderChannel}}</span>
|
||||
<span class="value">{{ currentOrderInfo.orderChannelDesc}}</span>
|
||||
</div><div class="info-item">
|
||||
<span class="label">供货商</span>
|
||||
<span class="value">{{ currentOrderInfo.supplier}}</span>
|
||||
|
|
@ -113,7 +113,7 @@
|
|||
<span class="value">{{ currentOrderInfo.partnerName}}</span>
|
||||
</div><div class="info-item">
|
||||
<span class="label">进货商类型</span>
|
||||
<span class="value">{{ currentOrderInfo.level}}</span>
|
||||
<span class="value">{{ currentOrderInfo.levelDesc}}</span>
|
||||
</div><div class="info-item">
|
||||
<span class="label">进货商联系人</span>
|
||||
<span class="value">{{ currentOrderInfo.partnerUserName}}</span>
|
||||
|
|
@ -579,8 +579,14 @@ const submitApproval = async () => {
|
|||
showSuccessToast(currentApprovalStatus.value === 0 ? '驳回成功' : '审批通过')
|
||||
approvalDialogVisible.value = false
|
||||
|
||||
// 重新加载详情
|
||||
// 如果是审批通过,跳转到列表页面
|
||||
if (currentApprovalStatus.value !== 0) {
|
||||
// 跳转到列表页面
|
||||
router.push('/list')
|
||||
} else {
|
||||
// 驳回情况下重新加载详情
|
||||
await orderStore.fetchOrderDetail(route.params.id as string)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('提交审批失败:', error)
|
||||
showToast('提交审批失败')
|
||||
|
|
|
|||
|
|
@ -20,8 +20,8 @@
|
|||
<div v-for="order in orderList" :key="order.id" class="order-item" @click="goToDetail(order.id)">
|
||||
<div class="order-header">
|
||||
<div class="order-code">{{ order.orderCode }}</div>
|
||||
<div class="status-tag" :class="getStatusClass(order.orderStatus)">
|
||||
{{ formatOrderStatus(order.orderStatus) }}
|
||||
<div class="status-tag pending">
|
||||
待审批
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue