权限控制完善

This commit is contained in:
2026-05-07 11:37:02 +08:00
parent bdd5b08351
commit c9dc8e9b6c
4 changed files with 122 additions and 70 deletions

View File

@@ -15,6 +15,7 @@ const TokenManager = {
setToken(token: string) { setToken(token: string) {
const authStore = useAuthStore() const authStore = useAuthStore()
authStore.setToken(token) authStore.setToken(token)
isAuthExpired = false
// 同时设置默认请求头 // 同时设置默认请求头
request.defaults.headers.common['Authorization'] = `Bearer ${token}` request.defaults.headers.common['Authorization'] = `Bearer ${token}`
}, },
@@ -45,15 +46,23 @@ TokenManager.initToken()
// 登录过期提示防重复标志 // 登录过期提示防重复标志
let isLoginExpiredShown = false let isLoginExpiredShown = false
let isAuthExpired = false
const isAuthExpiredRequest = (url: string) => {
if (!isAuthExpired) return false
if (!url) return true
return !url.includes('/user/login') && !url.includes('/user/register')
}
// 处理登录过期(防重复提示) // 处理登录过期(防重复提示)
const handleLoginExpired = () => { const handleLoginExpired = () => {
if (!isLoginExpiredShown) { if (!isLoginExpiredShown) {
isLoginExpiredShown = true isLoginExpiredShown = true
isAuthExpired = true
// 清除token // 清除token
TokenManager.removeToken() TokenManager.removeToken()
// 显示提示消息 // 显示提示消息
ElMessage.error('登录已过期,请重新登录') ElMessage.error('用户信息过期,请重新登录')
// 跳转到登录页 // 跳转到登录页
router.replace('/login').finally(() => { router.replace('/login').finally(() => {
// 延迟重置标志位,确保跳转完成后再允许下次提示 // 延迟重置标志位,确保跳转完成后再允许下次提示
@@ -149,6 +158,11 @@ request.interceptors.response.use(
return Promise.reject(error) return Promise.reject(error)
} }
// 如果是认证过期后的后续请求,静默处理业务错误,避免弹出部门加载失败等页面提示
if (isAuthExpiredRequest(url) && errorMsg) {
return Promise.reject(error)
}
// 网络错误或其他错误 // 网络错误或其他错误
ElMessage.error(errorMsg) ElMessage.error(errorMsg)
return Promise.reject(error) return Promise.reject(error)

View File

@@ -12,7 +12,7 @@
:rules="loginRules" :rules="loginRules"
class="login-form" class="login-form"
label-width="0" label-width="0"
@keyup.enter="handleLogin" @submit.prevent="handleLogin"
> >
<el-form-item prop="username"> <el-form-item prop="username">
<el-input <el-input
@@ -21,6 +21,7 @@
size="large" size="large"
:prefix-icon="User" :prefix-icon="User"
clearable clearable
@keydown.enter.prevent="handleLogin"
/> />
</el-form-item> </el-form-item>
@@ -33,7 +34,7 @@
:prefix-icon="Lock" :prefix-icon="Lock"
show-password show-password
clearable clearable
@keyup.enter="handleLogin" @keydown.enter.prevent="handleLogin"
/> />
</el-form-item> </el-form-item>
@@ -191,10 +192,11 @@ const registerRules: FormRules = {
// 处理登录 // 处理登录
const handleLogin = async () => { const handleLogin = async () => {
if (!loginFormRef.value) return if (!loginFormRef.value || loginLoading.value) return
const valid = await loginFormRef.value.validate().catch(() => false)
if (!valid) return
await loginFormRef.value.validate(async (valid) => {
if (valid) {
loginLoading.value = true loginLoading.value = true
try { try {
const response: any = await userlogin(loginForm.username, loginForm.password) const response: any = await userlogin(loginForm.username, loginForm.password)
@@ -226,7 +228,7 @@ const handleLogin = async () => {
localStorage.setItem('token', token) localStorage.setItem('token', token)
localStorage.setItem('permissions', JSON.stringify(permissions)) localStorage.setItem('permissions', JSON.stringify(permissions))
ElMessage.success(response?.message || '登录成功') ElMessage.success('登录成功')
router.push('/home') router.push('/home')
} else { } else {
ElMessage.error(response?.message || '登录失败,未获取到令牌') ElMessage.error(response?.message || '登录失败,未获取到令牌')
@@ -237,8 +239,6 @@ const handleLogin = async () => {
} finally { } finally {
loginLoading.value = false loginLoading.value = false
} }
}
})
} }
// 处理注册 // 处理注册

View File

@@ -86,8 +86,9 @@
</el-table-column> </el-table-column>
<el-table-column prop="formType" label="表单控件" min-width="120" align="left"> <el-table-column prop="formType" label="表单控件" min-width="120" align="left">
<template #default="{ row }"> <template #default="{ row }">
<span v-if="row.formType === 'select'">
<el-button <el-button
v-if="row.formType === 'select'" v-if="canConfigSelectOptions"
type="success" type="success"
size="small" size="small"
link link
@@ -95,8 +96,11 @@
> >
下拉框 下拉框
</el-button> </el-button>
<span v-else>下拉框</span>
</span>
<span v-else-if="row.formType === 'input' || row.formType === 'number'">
<el-button <el-button
v-else-if="row.formType === 'input' || row.formType === 'number'" v-if="canConfigRange"
type="warning" type="warning"
size="small" size="small"
link link
@@ -106,6 +110,8 @@
{{ getFormTypeLabel(row.formType) || '暂无' }} {{ getFormTypeLabel(row.formType) || '暂无' }}
</el-button> </el-button>
<span v-else>{{ getFormTypeLabel(row.formType) || '暂无' }}</span> <span v-else>{{ getFormTypeLabel(row.formType) || '暂无' }}</span>
</span>
<span v-else>{{ getFormTypeLabel(row.formType) || '暂无' }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="dicDataId" label="参数分类" min-width="120" align="left"> <el-table-column prop="dicDataId" label="参数分类" min-width="120" align="left">
@@ -236,12 +242,13 @@
/> />
</el-select> </el-select>
<el-button <el-button
v-if="formData.formType === 'select'" v-if="formData.formType === 'select' && canConfigSelectOptions"
type="primary" type="primary"
@click="handleConfigFormTypeOptionsInDrawer" @click="handleConfigFormTypeOptionsInDrawer"
> >
配置 配置
</el-button> </el-button>
<span v-else-if="formData.formType === 'select'">配置</span>
</div> </div>
</el-form-item> </el-form-item>
<el-form-item label="参数分类" prop="dicTypeId"> <el-form-item label="参数分类" prop="dicTypeId">
@@ -259,11 +266,13 @@
/> />
</el-select> </el-select>
<el-button <el-button
v-if="canConfigSelectOptions"
type="primary" type="primary"
@click="handleConfigCategoryOptionsInDrawer" @click="handleConfigCategoryOptionsInDrawer"
> >
配置 配置
</el-button> </el-button>
<span v-else>配置</span>
</div> </div>
</el-form-item> </el-form-item>
<el-form-item label="参数描述" prop="paramDesc"> <el-form-item label="参数描述" prop="paramDesc">
@@ -371,10 +380,11 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, reactive, onMounted } from 'vue' import { computed, ref, reactive, onMounted } from 'vue'
import type { FormInstance, FormRules } from 'element-plus' import type { FormInstance, FormRules } from 'element-plus'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import { Plus, Edit, Delete, Close } from '@element-plus/icons-vue' import { Plus, Edit, Delete, Close } from '@element-plus/icons-vue'
import { useAuthStore } from '@/stores/auth'
import { import {
devparamadd, devparamadd,
devparamdel, devparamdel,
@@ -390,6 +400,10 @@ const loading = ref(false)
const submitting = ref(false) const submitting = ref(false)
const rangeSubmitting = ref(false) const rangeSubmitting = ref(false)
const authStore = useAuthStore()
const canConfigRange = computed(() => authStore.hasPermission('data:devparam:range'))
const canConfigSelectOptions = computed(() => authStore.hasPermission('data:devparam:select'))
// 参数列表 // 参数列表
const paramList = ref<any[]>([]) const paramList = ref<any[]>([])
const total = ref(0) const total = ref(0)
@@ -1031,6 +1045,10 @@ const resetRangeForm = () => {
} }
const handleConfigRange = async (row: any) => { const handleConfigRange = async (row: any) => {
if (!canConfigRange.value) {
ElMessage.warning('您没有设置动作参数取值范围的权限')
return
}
if (!row?.paramName) { if (!row?.paramName) {
ElMessage.warning('缺少参数名称,无法配置取值范围') ElMessage.warning('缺少参数名称,无法配置取值范围')
return return
@@ -1158,11 +1176,19 @@ const isConfigFormType = ref(false) // 是否配置表单控件的下拉框选
// 打开表单控件下拉框选项配置对话框(从列表) // 打开表单控件下拉框选项配置对话框(从列表)
const handleConfigFormTypeOptions = async (row: any) => { const handleConfigFormTypeOptions = async (row: any) => {
if (!canConfigSelectOptions.value) {
ElMessage.warning('您没有设置动作参数下拉框选项列表的权限')
return
}
await openSelectOptionsDialog(row, true) await openSelectOptionsDialog(row, true)
} }
// 打开表单控件下拉框选项配置对话框(从抽屉) // 打开表单控件下拉框选项配置对话框(从抽屉)
const handleConfigFormTypeOptionsInDrawer = async () => { const handleConfigFormTypeOptionsInDrawer = async () => {
if (!canConfigSelectOptions.value) {
ElMessage.warning('您没有设置动作参数下拉框选项列表的权限')
return
}
if (!formData.paramName) { if (!formData.paramName) {
ElMessage.warning('请先输入参数名称') ElMessage.warning('请先输入参数名称')
return return

View File

@@ -95,12 +95,16 @@
> >
<template #default="{ row }"> <template #default="{ row }">
<el-button <el-button
v-if="canViewStatusRecord"
:type="getStatusType(row.goodsStatus)" :type="getStatusType(row.goodsStatus)"
link link
@click="handleStatusClick(row)" @click="handleStatusClick(row)"
> >
{{ getStatusText(row.goodsStatus) }} {{ getStatusText(row.goodsStatus) }}
</el-button> </el-button>
<span v-else>
{{ getStatusText(row.goodsStatus) }}
</span>
</template> </template>
</el-table-column> </el-table-column>
@@ -327,7 +331,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, reactive, onMounted } from 'vue' import { computed, ref, reactive, onMounted } from 'vue'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { goodsInfolist } from '@/api/tb/goodsinfo' import { goodsInfolist } from '@/api/tb/goodsinfo'
import { flowInfobyid } from '@/api/tb/flowinfo' import { flowInfobyid } from '@/api/tb/flowinfo'
@@ -338,6 +342,7 @@ import { islandInfobyid } from '@/api/tb/islandinfo'
import { devInfobyid } from '@/api/tb/devinfo' import { devInfobyid } from '@/api/tb/devinfo'
import { stepInfolist } from '@/api/tb/stepinfo' import { stepInfolist } from '@/api/tb/stepinfo'
import { devparambyid } from '@/api/tb/devparam' import { devparambyid } from '@/api/tb/devparam'
import { useAuthStore } from '@/stores/auth'
interface GoodsInfoItem { interface GoodsInfoItem {
id?: number | string id?: number | string
@@ -379,6 +384,9 @@ const detailData = reactive<GoodsInfoItem>({})
const detailStatusList = ref<any[]>([]) const detailStatusList = ref<any[]>([])
const detailStatusLoading = ref(false) const detailStatusLoading = ref(false)
const authStore = useAuthStore()
const canViewStatusRecord = computed(() => authStore.hasPermission('tb:goodrecord:record'))
// 样品流程状态列表相关 // 样品流程状态列表相关
const flowStatusDialogVisible = ref(false) const flowStatusDialogVisible = ref(false)
const flowStatusDialogTitle = ref('样品流程状态列表') const flowStatusDialogTitle = ref('样品流程状态列表')
@@ -417,6 +425,10 @@ const getStatusText = (status: number | null | undefined) => {
// 样品状态点击事件处理 // 样品状态点击事件处理
const handleStatusClick = (row: GoodsInfoItem) => { const handleStatusClick = (row: GoodsInfoItem) => {
if (!canViewStatusRecord.value) {
ElMessage.warning('您没有样品状态记录的权限')
return
}
const status = row.goodsStatus const status = row.goodsStatus
if (status === 0) { if (status === 0) {
// 待处理 - 显示提示 // 待处理 - 显示提示