Merge remote-tracking branch 'origin/main'
This commit is contained in:
46
rc_autoplc_front/src/api/tb/recorddeal.ts
Normal file
46
rc_autoplc_front/src/api/tb/recorddeal.ts
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
export function recordDealadd(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/recordDeal/add',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function recordDealdel(id: string | number) {
|
||||||
|
return request({
|
||||||
|
url: `/recordDeal/del/${id}`,
|
||||||
|
method: 'delete',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function recordDealbyid(id: string | number) {
|
||||||
|
return request({
|
||||||
|
url: `/recordDeal/getById/${id}`,
|
||||||
|
method: 'get',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function recordDeallistByRecordId(recordId: string | number) {
|
||||||
|
return request({
|
||||||
|
url: `/recordDeal/listByRecordId/${recordId}`,
|
||||||
|
method: 'get',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function recordDeallist(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/recordDeal/listPage',
|
||||||
|
method: 'get',
|
||||||
|
params: data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function recordDealupd(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/recordDeal/update',
|
||||||
|
method: 'put',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
39
rc_autoplc_front/src/api/tb/recordinfo.ts
Normal file
39
rc_autoplc_front/src/api/tb/recordinfo.ts
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
export function recordInfoadd(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/recordInfo/add',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function recordInfodel(id: string | number) {
|
||||||
|
return request({
|
||||||
|
url: `/recordInfo/del/${id}`,
|
||||||
|
method: 'delete',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function recordInfobyid(id: string | number) {
|
||||||
|
return request({
|
||||||
|
url: `/recordInfo/getById/${id}`,
|
||||||
|
method: 'get',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function recordInfolist(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/recordInfo/listPage',
|
||||||
|
method: 'get',
|
||||||
|
params: data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function recordInfoupd(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/recordInfo/update',
|
||||||
|
method: 'put',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
26
rc_autoplc_front/src/directives/permission.ts
Normal file
26
rc_autoplc_front/src/directives/permission.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import type { App, DirectiveBinding } from 'vue'
|
||||||
|
import { useAuthStore } from '@/stores/auth'
|
||||||
|
|
||||||
|
function hasPermission(value: unknown): boolean {
|
||||||
|
const authStore = useAuthStore()
|
||||||
|
const codes = Array.isArray(value) ? value : [value]
|
||||||
|
const normalized = codes.filter((code): code is string => typeof code === 'string' && code.length > 0)
|
||||||
|
|
||||||
|
if (!normalized.length) return true
|
||||||
|
return authStore.hasAnyPermission(normalized)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setupPermissionDirective(app: App) {
|
||||||
|
app.directive('permission', {
|
||||||
|
mounted(el: HTMLElement, binding: DirectiveBinding<string | string[]>) {
|
||||||
|
if (!hasPermission(binding.value)) {
|
||||||
|
el.parentNode?.removeChild(el)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
updated(el: HTMLElement, binding: DirectiveBinding<string | string[]>) {
|
||||||
|
if (!hasPermission(binding.value)) {
|
||||||
|
el.parentNode?.removeChild(el)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -7,10 +7,10 @@ import router from './router'
|
|||||||
import ElementPlus from 'element-plus'
|
import ElementPlus from 'element-plus'
|
||||||
import 'element-plus/dist/index.css'
|
import 'element-plus/dist/index.css'
|
||||||
import zhCn from 'element-plus/es/locale/lang/zh-cn'
|
import zhCn from 'element-plus/es/locale/lang/zh-cn'
|
||||||
|
import { setupPermissionDirective } from '@/directives/permission'
|
||||||
|
|
||||||
const app = createApp(App)
|
const app = createApp(App)
|
||||||
|
|
||||||
// 创建 Pinia 实例并配置持久化插件
|
|
||||||
const pinia = createPinia()
|
const pinia = createPinia()
|
||||||
pinia.use(piniaPluginPersistedstate)
|
pinia.use(piniaPluginPersistedstate)
|
||||||
|
|
||||||
@@ -19,5 +19,6 @@ app.use(ElementPlus, {
|
|||||||
})
|
})
|
||||||
app.use(pinia)
|
app.use(pinia)
|
||||||
app.use(router)
|
app.use(router)
|
||||||
|
setupPermissionDirective(app)
|
||||||
|
|
||||||
app.mount('#app')
|
app.mount('#app')
|
||||||
|
|||||||
@@ -1,9 +1,17 @@
|
|||||||
import { createRouter, createWebHashHistory } from 'vue-router'
|
import { createRouter, createWebHistory } from 'vue-router'
|
||||||
import { useAuthStore } from '@/stores/auth'
|
import { useAuthStore } from '@/stores/auth'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
|
|
||||||
|
declare module 'vue-router' {
|
||||||
|
interface RouteMeta {
|
||||||
|
requiresAuth?: boolean
|
||||||
|
permission?: string | string[]
|
||||||
|
hidden?: boolean
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createWebHashHistory(import.meta.env.BASE_URL),
|
history: createWebHistory(import.meta.env.BASE_URL),
|
||||||
routes: [
|
routes: [
|
||||||
{
|
{
|
||||||
path: '/login',
|
path: '/login',
|
||||||
@@ -29,81 +37,83 @@ const router = createRouter({
|
|||||||
path: '/user',
|
path: '/user',
|
||||||
name: 'user',
|
name: 'user',
|
||||||
component: () => import('../views/user/index.vue'),
|
component: () => import('../views/user/index.vue'),
|
||||||
|
meta: { permission: 'sys:user' },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/role',
|
path: '/role',
|
||||||
name: 'role',
|
name: 'role',
|
||||||
component: () => import('../views/role/index.vue'),
|
component: () => import('../views/role/index.vue'),
|
||||||
|
meta: { permission: 'sys:role' },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/department',
|
path: '/department',
|
||||||
name: 'department',
|
name: 'department',
|
||||||
component: () => import('../views/department/index.vue'),
|
component: () => import('../views/department/index.vue'),
|
||||||
|
meta: { permission: 'sys:department' },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/permission',
|
path: '/permission',
|
||||||
name: 'permission',
|
name: 'permission',
|
||||||
component: () => import('../views/permission/index.vue'),
|
component: () => import('../views/permission/index.vue'),
|
||||||
|
meta: { permission: 'sys:permission' },
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: '/position',
|
|
||||||
name: 'position',
|
|
||||||
component: () => import('../views/position/index.vue'),
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: '/manage-log',
|
path: '/manage-log',
|
||||||
name: 'manage-log',
|
name: 'manage-log',
|
||||||
component: () => import('../views/manage-log/index.vue'),
|
component: () => import('../views/manage-log/index.vue'),
|
||||||
|
meta: { permission: 'sys:managelog' },
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: '/user-role',
|
|
||||||
name: 'user-role',
|
|
||||||
component: () => import('../views/user-role/index.vue'),
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: '/island-info',
|
path: '/island-info',
|
||||||
name: 'island-info',
|
name: 'island-info',
|
||||||
component: () => import('../views/islandInfo/index.vue'),
|
component: () => import('../views/islandInfo/index.vue'),
|
||||||
|
meta: { permission: 'data:island' },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/devparam',
|
path: '/devparam',
|
||||||
name: 'devparam',
|
name: 'devparam',
|
||||||
component: () => import('../views/devparam/index.vue'),
|
component: () => import('../views/devparam/index.vue'),
|
||||||
|
meta: { permission: 'data:devparam' },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/devinfo',
|
path: '/devinfo',
|
||||||
name: 'devinfo',
|
name: 'devinfo',
|
||||||
component: () => import('../views/devinfo/index.vue'),
|
component: () => import('../views/devinfo/index.vue'),
|
||||||
|
meta: { permission: 'data:dev' },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/plc-devinfo',
|
path: '/plc-devinfo',
|
||||||
name: 'plc-devinfo',
|
name: 'plc-devinfo',
|
||||||
component: () => import('../views/devinfo/plc.vue'),
|
component: () => import('../views/devinfo/plc.vue'),
|
||||||
|
meta: { permission: 'data:plc' },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/goods-info',
|
path: '/goods-info',
|
||||||
name: 'goods-info',
|
name: 'goods-info',
|
||||||
component: () => import('../views/goods/index.vue'),
|
component: () => import('../views/goods/index.vue'),
|
||||||
|
meta: { permission: 'tb:goodrecord' },
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: '/flow-info',
|
|
||||||
name: 'flow-info',
|
|
||||||
component: () => import('../views/flowinfo/index.vue'),
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: '/step-info',
|
path: '/step-info',
|
||||||
name: 'step-info',
|
name: 'step-info',
|
||||||
component: () => import('../views/stepinfo/index.vue'),
|
component: () => import('../views/stepinfo/index.vue'),
|
||||||
|
meta: { permission: 'data:sop' },
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: '/plc-device-control',
|
|
||||||
name: 'plc-device-control',
|
|
||||||
component: () => import('../views/plcdevicecontrol/index.vue'),
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: '/sample-injection',
|
path: '/sample-injection',
|
||||||
name: 'sample-injection',
|
name: 'sample-injection',
|
||||||
component: () => import('../views/sampleinjection/index.vue'),
|
component: () => import('../views/sampleinjection/index.vue'),
|
||||||
|
meta: { permission: 'tb:goodcontrol' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/record-info',
|
||||||
|
name: 'record-info',
|
||||||
|
component: () => import('../views/recordinfo/index.vue'),
|
||||||
|
meta: { permission: 'tb:exceptionrecord' },
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -115,33 +125,40 @@ router.beforeEach((to, _from, next) => {
|
|||||||
const authStore = useAuthStore()
|
const authStore = useAuthStore()
|
||||||
const token = authStore.getToken()
|
const token = authStore.getToken()
|
||||||
|
|
||||||
// 如果访问登录页
|
|
||||||
if (to.path === '/login') {
|
if (to.path === '/login') {
|
||||||
// 已登录状态下访问登录页,自动跳转到首页
|
|
||||||
if (token) {
|
if (token) {
|
||||||
next('/home')
|
next('/home')
|
||||||
ElMessage.success('已登录,自动跳转')
|
ElMessage.success('已登录,自动跳转')
|
||||||
} else {
|
} else {
|
||||||
// 未登录,正常进入登录页
|
|
||||||
next()
|
next()
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 访问需要认证的页面,但未登录(无token)
|
|
||||||
if (to.meta.requiresAuth && !token) {
|
if (to.meta.requiresAuth && !token) {
|
||||||
ElMessage.warning('请先登录')
|
ElMessage.warning('请先登录')
|
||||||
next('/login')
|
next('/login')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果访问根路径,重定向到首页
|
const permission = to.meta.permission
|
||||||
|
if (permission) {
|
||||||
|
const allowed = Array.isArray(permission)
|
||||||
|
? authStore.hasAnyPermission(permission)
|
||||||
|
: authStore.hasPermission(permission)
|
||||||
|
|
||||||
|
if (!allowed) {
|
||||||
|
ElMessage.warning('暂无访问权限')
|
||||||
|
next('/home')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (to.path === '/') {
|
if (to.path === '/') {
|
||||||
next('/home')
|
next('/home')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 已登录且访问合法页面,正常放行
|
|
||||||
next()
|
next()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,21 @@
|
|||||||
import { ref } from 'vue'
|
import { computed, ref } from 'vue'
|
||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
|
|
||||||
|
export interface AuthUserInfo {
|
||||||
|
username?: string
|
||||||
|
token?: string
|
||||||
|
roles?: string[]
|
||||||
|
permissions?: string[]
|
||||||
|
[key: string]: any
|
||||||
|
}
|
||||||
|
|
||||||
|
export type PermissionCode = string
|
||||||
|
|
||||||
export const useAuthStore = defineStore('auth', () => {
|
export const useAuthStore = defineStore('auth', () => {
|
||||||
const token = ref<string>('')
|
const token = ref<string>('')
|
||||||
|
const userInfo = ref<AuthUserInfo | null>(null)
|
||||||
|
|
||||||
|
const permissions = computed<PermissionCode[]>(() => userInfo.value?.permissions || [])
|
||||||
|
|
||||||
function setToken(newToken: string) {
|
function setToken(newToken: string) {
|
||||||
token.value = newToken
|
token.value = newToken
|
||||||
@@ -12,15 +25,61 @@ export const useAuthStore = defineStore('auth', () => {
|
|||||||
return token.value
|
return token.value
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeToken() {
|
function setUserInfo(info: AuthUserInfo | null) {
|
||||||
|
userInfo.value = info
|
||||||
|
if (info?.token) {
|
||||||
|
token.value = info.token
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getUserInfo(): AuthUserInfo | null {
|
||||||
|
return userInfo.value
|
||||||
|
}
|
||||||
|
|
||||||
|
function setPermissions(nextPermissions: PermissionCode[]) {
|
||||||
|
if (!userInfo.value) {
|
||||||
|
userInfo.value = { permissions: nextPermissions }
|
||||||
|
return
|
||||||
|
}
|
||||||
|
userInfo.value.permissions = nextPermissions
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPermissions(): PermissionCode[] {
|
||||||
|
return permissions.value
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasPermission(code: PermissionCode): boolean {
|
||||||
|
return getPermissions().includes(code)
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasAnyPermission(codes: PermissionCode[]): boolean {
|
||||||
|
if (!codes.length) return true
|
||||||
|
return codes.some(code => hasPermission(code))
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasAllPermissions(codes: PermissionCode[]): boolean {
|
||||||
|
return codes.every(code => hasPermission(code))
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearAuth() {
|
||||||
token.value = ''
|
token.value = ''
|
||||||
|
userInfo.value = null
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
token,
|
token,
|
||||||
|
userInfo,
|
||||||
|
permissions,
|
||||||
setToken,
|
setToken,
|
||||||
getToken,
|
getToken,
|
||||||
removeToken,
|
setUserInfo,
|
||||||
|
getUserInfo,
|
||||||
|
setPermissions,
|
||||||
|
getPermissions,
|
||||||
|
hasPermission,
|
||||||
|
hasAnyPermission,
|
||||||
|
hasAllPermissions,
|
||||||
|
clearAuth,
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
persist: true,
|
persist: true,
|
||||||
|
|||||||
@@ -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}`
|
||||||
},
|
},
|
||||||
@@ -26,7 +27,7 @@ const TokenManager = {
|
|||||||
|
|
||||||
removeToken() {
|
removeToken() {
|
||||||
const authStore = useAuthStore()
|
const authStore = useAuthStore()
|
||||||
authStore.removeToken()
|
authStore.clearAuth()
|
||||||
// 删除默认请求头
|
// 删除默认请求头
|
||||||
delete request.defaults.headers.common['Authorization']
|
delete request.defaults.headers.common['Authorization']
|
||||||
},
|
},
|
||||||
@@ -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(() => {
|
||||||
// 延迟重置标志位,确保跳转完成后再允许下次提示
|
// 延迟重置标志位,确保跳转完成后再允许下次提示
|
||||||
@@ -82,28 +91,27 @@ request.interceptors.request.use(
|
|||||||
// 响应拦截器
|
// 响应拦截器
|
||||||
request.interceptors.response.use(
|
request.interceptors.response.use(
|
||||||
(response: AxiosResponse) => {
|
(response: AxiosResponse) => {
|
||||||
const { data } = response
|
const { data } = response as AxiosResponse<any>
|
||||||
|
const responseToken = data?.token || data?.data?.token
|
||||||
|
const responseCode = data?.code ?? data?.data?.code
|
||||||
|
|
||||||
// 如果返回 code 为 0 且有新 token,更新 token
|
if (responseCode === 0 && responseToken) {
|
||||||
if (data.code === 0 && data.token) {
|
TokenManager.setToken(responseToken)
|
||||||
TokenManager.setToken(data.token)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('data*--', data)
|
console.log('data*--', data)
|
||||||
|
|
||||||
// 处理业务错误码
|
if (responseCode === 302) {
|
||||||
if (data.code === 302) {
|
|
||||||
// 处理登录过期(防重复提示)
|
// 处理登录过期(防重复提示)
|
||||||
handleLoginExpired()
|
handleLoginExpired()
|
||||||
return Promise.reject(data)
|
return Promise.reject(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 其他错误码
|
const hasBusinessCode = responseCode !== undefined && responseCode !== null
|
||||||
if (data.code !== 0 && data.code !== undefined) {
|
if (hasBusinessCode && responseCode !== 0) {
|
||||||
// 检查是否是状态刷新相关的请求,如果是则静默处理某些错误
|
|
||||||
const url = response.config?.url || ''
|
const url = response.config?.url || ''
|
||||||
const isStatusRefreshRequest = url.includes('/plc/plcStatus') || url.includes('/plc/getModel')
|
const isStatusRefreshRequest = url.includes('/plc/plcStatus') || url.includes('/plc/getModel')
|
||||||
const errorMsg = data.message || data.msg || ''
|
const errorMsg = data?.message || data?.msg || data?.data?.message || data?.data?.msg || ''
|
||||||
|
|
||||||
// 如果是状态刷新请求,且错误消息包含特定关键词,则静默处理
|
// 如果是状态刷新请求,且错误消息包含特定关键词,则静默处理
|
||||||
if (isStatusRefreshRequest && (
|
if (isStatusRefreshRequest && (
|
||||||
@@ -125,17 +133,17 @@ request.interceptors.response.use(
|
|||||||
return data
|
return data
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
// 处理401未授权错误
|
if (axios.isAxiosError(error) && error.response?.status === 401) {
|
||||||
if (error.response?.status === 401) {
|
|
||||||
// 处理登录过期(防重复提示)
|
// 处理登录过期(防重复提示)
|
||||||
handleLoginExpired()
|
handleLoginExpired()
|
||||||
return Promise.reject(error)
|
return Promise.reject(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查是否是状态刷新相关的请求
|
const url = axios.isAxiosError(error) ? (error.config?.url || '') : ''
|
||||||
const url = error.config?.url || ''
|
|
||||||
const isStatusRefreshRequest = url.includes('/plc/plcStatus') || url.includes('/plc/getModel')
|
const isStatusRefreshRequest = url.includes('/plc/plcStatus') || url.includes('/plc/getModel')
|
||||||
const errorMsg = error.response?.data?.message || error.response?.data?.msg || '请求失败'
|
const errorMsg = axios.isAxiosError(error)
|
||||||
|
? (error.response?.data?.message || error.response?.data?.msg || error.response?.data?.data?.message || error.response?.data?.data?.msg || '请求失败')
|
||||||
|
: '请求失败'
|
||||||
|
|
||||||
// 如果是状态刷新请求,且错误消息包含特定关键词,则静默处理
|
// 如果是状态刷新请求,且错误消息包含特定关键词,则静默处理
|
||||||
if (isStatusRefreshRequest && (
|
if (isStatusRefreshRequest && (
|
||||||
@@ -150,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)
|
||||||
|
|||||||
@@ -35,71 +35,82 @@
|
|||||||
<el-icon><component :is="getMenuIcon('首页')" /></el-icon>
|
<el-icon><component :is="getMenuIcon('首页')" /></el-icon>
|
||||||
<span>首页</span>
|
<span>首页</span>
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
<el-sub-menu index="system">
|
|
||||||
|
<el-sub-menu v-if="hasPermission(['sys', 'sys:user', 'sys:role', 'sys:department', 'sys:permission', 'sys:managelog', 'sys:userrole'])" index="system">
|
||||||
<template #title>
|
<template #title>
|
||||||
<el-icon><component :is="getMenuIcon('系统管理')" /></el-icon>
|
<el-icon><component :is="getMenuIcon('系统管理')" /></el-icon>
|
||||||
<span>系统信息管理</span>
|
<span>系统信息管理</span>
|
||||||
</template>
|
</template>
|
||||||
<el-menu-item index="/user">
|
<el-menu-item v-if="hasPermission('sys:user')" index="/user">
|
||||||
<el-icon><component :is="getMenuIcon('用户管理')" /></el-icon>
|
<el-icon><component :is="getMenuIcon('用户管理')" /></el-icon>
|
||||||
<span>用户管理</span>
|
<span>用户管理</span>
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
<el-menu-item index="/role">
|
<el-menu-item v-if="hasPermission('sys:role')" index="/role">
|
||||||
<el-icon><component :is="getMenuIcon('角色管理')" /></el-icon>
|
<el-icon><component :is="getMenuIcon('角色管理')" /></el-icon>
|
||||||
<span>角色管理</span>
|
<span>角色管理</span>
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
<el-menu-item index="/permission">
|
<el-menu-item v-if="hasPermission('sys:permission')" index="/permission">
|
||||||
<el-icon><component :is="getMenuIcon('权限管理')" /></el-icon>
|
<el-icon><component :is="getMenuIcon('权限管理')" /></el-icon>
|
||||||
<span>权限管理</span>
|
<span>权限管理</span>
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
<el-menu-item index="/department">
|
<el-menu-item v-if="hasPermission('sys:department')" index="/department">
|
||||||
<el-icon><component :is="getMenuIcon('部门管理')" /></el-icon>
|
<el-icon><component :is="getMenuIcon('部门管理')" /></el-icon>
|
||||||
<span>部门管理</span>
|
<span>部门管理</span>
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
<el-menu-item index="/manage-log">
|
<el-menu-item v-if="hasPermission('sys:managelog')" index="/manage-log">
|
||||||
<el-icon><component :is="getMenuIcon('操作日志管理')" /></el-icon>
|
<el-icon><component :is="getMenuIcon('操作日志管理')" /></el-icon>
|
||||||
<span>操作日志管理</span>
|
<span>操作日志管理</span>
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
</el-sub-menu>
|
</el-sub-menu>
|
||||||
<el-sub-menu index="island">
|
|
||||||
|
<el-sub-menu v-if="hasPermission(['data:plc', 'data:devparam', 'data:devparam', 'data:dev', 'data:island', 'data:sop'])" index="data">
|
||||||
<template #title>
|
<template #title>
|
||||||
<el-icon><component :is="getMenuIcon('业务管理')" /></el-icon>
|
<el-icon><component :is="getMenuIcon('业务管理')" /></el-icon>
|
||||||
<span>基础数据管理</span>
|
<span>基础数据管理</span>
|
||||||
</template>
|
</template>
|
||||||
<el-menu-item index="/plc-devinfo">
|
<el-menu-item v-if="hasPermission('data:plc')" index="/plc-devinfo">
|
||||||
<el-icon><component :is="getMenuIcon('PLC设备管理')" /></el-icon>
|
<el-icon><component :is="getMenuIcon('PLC设备管理')" /></el-icon>
|
||||||
<span>PLC设备管理</span>
|
<span>PLC设备管理</span>
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
<el-menu-item index="/devparam">
|
<el-menu-item v-if="hasPermission('data:devparam')" index="/devparam">
|
||||||
<el-icon><component :is="getMenuIcon('动作参数管理')" /></el-icon>
|
<el-icon><component :is="getMenuIcon('动作参数管理')" /></el-icon>
|
||||||
<span>动作参数管理</span>
|
<span>动作参数管理</span>
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
<el-menu-item index="/devinfo">
|
<el-menu-item v-if="hasPermission('data:dev')" index="/devinfo">
|
||||||
<el-icon><component :is="getMenuIcon('动作管理')" /></el-icon>
|
<el-icon><component :is="getMenuIcon('动作管理')" /></el-icon>
|
||||||
<span>动作管理</span>
|
<span>动作管理</span>
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
<el-menu-item index="/island-info">
|
<el-menu-item v-if="hasPermission('data:island')" index="/island-info">
|
||||||
<el-icon><component :is="getMenuIcon('功能岛管理')" /></el-icon>
|
<el-icon><component :is="getMenuIcon('功能岛管理')" /></el-icon>
|
||||||
<span>功能岛管理</span>
|
<span>功能岛管理</span>
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
<el-menu-item index="/step-info">
|
<el-menu-item v-if="hasPermission('data:sop')" index="/step-info">
|
||||||
<el-icon><component :is="getMenuIcon('流程创建')" /></el-icon>
|
<el-icon><component :is="getMenuIcon('流程创建')" /></el-icon>
|
||||||
<span>SOP管理</span>
|
<span>SOP管理</span>
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
|
<el-menu-item v-if="hasPermission('data:goods')" index="/goods-info">
|
||||||
|
<el-icon><component :is="getMenuIcon('样品管理')" /></el-icon>
|
||||||
|
<span>样品记录</span>
|
||||||
|
</el-menu-item>
|
||||||
</el-sub-menu>
|
</el-sub-menu>
|
||||||
<el-sub-menu index="flow">
|
|
||||||
|
<el-sub-menu v-if="hasPermission(['tb:goodcontrol', 'tb:goodrecord', 'tb:exceptionrecord'])" index="tb">
|
||||||
<template #title>
|
<template #title>
|
||||||
<el-icon><component :is="getMenuIcon('流程管理')" /></el-icon>
|
<el-icon><component :is="getMenuIcon('流程管理')" /></el-icon>
|
||||||
<span>业务流程控制</span>
|
<span>业务流程控制</span>
|
||||||
</template>
|
</template>
|
||||||
<el-menu-item index="/sample-injection">
|
<el-menu-item v-if="hasPermission('tb:goodcontrol')" index="/sample-injection">
|
||||||
<el-icon><component :is="getMenuIcon('进样控制')" /></el-icon>
|
<el-icon><component :is="getMenuIcon('进样控制')" /></el-icon>
|
||||||
<span>进样控制</span>
|
<span>进样控制</span>
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
<el-menu-item index="/goods-info">
|
<el-menu-item v-if="hasPermission('tb:goodrecord')" index="/goods-info">
|
||||||
<el-icon><component :is="getMenuIcon('样品管理')" /></el-icon>
|
<el-icon><component :is="getMenuIcon('样品管理')" /></el-icon>
|
||||||
<span>样品记录</span>
|
<span>样品记录</span>
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
|
<el-menu-item v-if="hasPermission('tb:exceptionrecord')" index="/record-info">
|
||||||
|
<el-icon><component :is="getMenuIcon('流程管理')" /></el-icon>
|
||||||
|
<span>异常记录</span>
|
||||||
|
</el-menu-item>
|
||||||
</el-sub-menu>
|
</el-sub-menu>
|
||||||
</el-menu>
|
</el-menu>
|
||||||
</el-aside>
|
</el-aside>
|
||||||
@@ -113,7 +124,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
import { useRouter, useRoute } from 'vue-router'
|
import { useRouter, useRoute } from 'vue-router'
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
import {
|
import {
|
||||||
@@ -143,26 +154,18 @@ const router = useRouter()
|
|||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const authStore = useAuthStore()
|
const authStore = useAuthStore()
|
||||||
|
|
||||||
// 用户信息(可以从store或localStorage获取)
|
const userInfo = computed(() => authStore.getUserInfo() || {
|
||||||
const userInfo = ref({
|
|
||||||
username: localStorage.getItem('username') || '管理员',
|
username: localStorage.getItem('username') || '管理员',
|
||||||
})
|
})
|
||||||
|
|
||||||
// 当前激活的菜单
|
const activeMenu = computed(() => route.path)
|
||||||
const activeMenu = computed(() => {
|
|
||||||
return route.path
|
|
||||||
})
|
|
||||||
|
|
||||||
// 根据菜单名称获取图标
|
|
||||||
const getMenuIcon = (menuName: string) => {
|
const getMenuIcon = (menuName: string) => {
|
||||||
const iconMap: Record<string, any> = {
|
const iconMap: Record<string, any> = {
|
||||||
// 一级
|
|
||||||
首页: House,
|
首页: House,
|
||||||
系统管理: Setting,
|
系统管理: Setting,
|
||||||
业务管理: Grid,
|
业务管理: Grid,
|
||||||
流程管理: List,
|
流程管理: List,
|
||||||
|
|
||||||
// 系统管理
|
|
||||||
用户管理: User,
|
用户管理: User,
|
||||||
角色管理: Avatar,
|
角色管理: Avatar,
|
||||||
部门管理: OfficeBuilding,
|
部门管理: OfficeBuilding,
|
||||||
@@ -170,35 +173,35 @@ const getMenuIcon = (menuName: string) => {
|
|||||||
职位管理: Briefcase,
|
职位管理: Briefcase,
|
||||||
操作日志管理: Document,
|
操作日志管理: Document,
|
||||||
用户角色管理: UserFilled,
|
用户角色管理: UserFilled,
|
||||||
|
|
||||||
// 业务管理
|
|
||||||
PLC设备管理: Connection,
|
PLC设备管理: Connection,
|
||||||
动作参数管理: Tools,
|
动作参数管理: Tools,
|
||||||
动作管理: Monitor,
|
动作管理: Monitor,
|
||||||
功能岛管理: Grid,
|
功能岛管理: Grid,
|
||||||
|
|
||||||
// 流程管理
|
|
||||||
PLC设备控制: Operation,
|
PLC设备控制: Operation,
|
||||||
样品管理: Box,
|
样品管理: Box,
|
||||||
'标准流程管理': Files, // 文件图标,适合标准流程管理
|
'标准流程管理': Files,
|
||||||
'流程创建': EditPen,
|
'流程创建': EditPen,
|
||||||
进样控制: Operation,
|
进样控制: Operation,
|
||||||
}
|
}
|
||||||
return iconMap[menuName] || EditPen
|
return iconMap[menuName] || EditPen
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理下拉菜单命令
|
const hasPermission = (code: string | string[]) => {
|
||||||
|
const codes = Array.isArray(code) ? code : [code]
|
||||||
|
return authStore.hasAnyPermission(codes)
|
||||||
|
}
|
||||||
|
|
||||||
const handleCommand = (command: string) => {
|
const handleCommand = (command: string) => {
|
||||||
if (command === 'logout') {
|
if (command === 'logout') {
|
||||||
ElMessageBox.confirm('确认退出登录吗?', '提示', {
|
ElMessageBox.confirm('确认退出登录吗?', '提示', {
|
||||||
type: 'warning',
|
type: 'warning',
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
// 清除token和用户信息
|
authStore.clearAuth()
|
||||||
authStore.removeToken()
|
|
||||||
localStorage.removeItem('username')
|
localStorage.removeItem('username')
|
||||||
|
localStorage.removeItem('token')
|
||||||
|
localStorage.removeItem('permissions')
|
||||||
ElMessage.success('退出成功')
|
ElMessage.success('退出成功')
|
||||||
// 跳转到登录页
|
|
||||||
router.push('/login')
|
router.push('/login')
|
||||||
})
|
})
|
||||||
.catch(() => {})
|
.catch(() => {})
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|
||||||
@@ -119,7 +120,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, reactive } from 'vue'
|
import { ref, reactive } from 'vue'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { ElMessage, ElMessageBox, type FormInstance, type FormRules } from 'element-plus'
|
import { ElMessage, type FormInstance, type FormRules } from 'element-plus'
|
||||||
import { User, Lock } from '@element-plus/icons-vue'
|
import { User, Lock } from '@element-plus/icons-vue'
|
||||||
import { userlogin, userregister } from '@/api/system/user'
|
import { userlogin, userregister } from '@/api/system/user'
|
||||||
import { useAuthStore } from '@/stores/auth'
|
import { useAuthStore } from '@/stores/auth'
|
||||||
@@ -161,7 +162,7 @@ const loginRules: FormRules = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 注册表单验证规则
|
// 注册表单验证规则
|
||||||
const validateConfirmPassword = (rule: any, value: string, callback: Function) => {
|
const validateConfirmPassword = (_rule: any, value: string, callback: Function) => {
|
||||||
if (value === '') {
|
if (value === '') {
|
||||||
callback(new Error('请再次输入密码'))
|
callback(new Error('请再次输入密码'))
|
||||||
} else if (value !== registerForm.password) {
|
} else if (value !== registerForm.password) {
|
||||||
@@ -191,34 +192,53 @@ const registerRules: FormRules = {
|
|||||||
|
|
||||||
// 处理登录
|
// 处理登录
|
||||||
const handleLogin = async () => {
|
const handleLogin = async () => {
|
||||||
if (!loginFormRef.value) return
|
if (!loginFormRef.value || loginLoading.value) return
|
||||||
|
|
||||||
await loginFormRef.value.validate(async (valid) => {
|
const valid = await loginFormRef.value.validate().catch(() => false)
|
||||||
if (valid) {
|
if (!valid) return
|
||||||
loginLoading.value = true
|
|
||||||
try {
|
|
||||||
const response: any = await userlogin(loginForm.username, loginForm.password)
|
|
||||||
|
|
||||||
// 根据图片,返回的data字段直接是token字符串
|
loginLoading.value = true
|
||||||
if (response.code === 0 && response.data) {
|
try {
|
||||||
const token = response.data
|
const response: any = await userlogin(loginForm.username, loginForm.password)
|
||||||
// 存储token
|
const loginData = response?.data ?? response
|
||||||
authStore.setToken(token)
|
const token = loginData?.token || response?.token || loginData
|
||||||
// 存储用户名
|
const permissions = Array.isArray(loginData?.permissions)
|
||||||
localStorage.setItem('username', loginForm.username)
|
? loginData.permissions
|
||||||
|
: Array.isArray(response?.permissions)
|
||||||
|
? response.permissions
|
||||||
|
: []
|
||||||
|
const roles = Array.isArray(loginData?.roles)
|
||||||
|
? loginData.roles
|
||||||
|
: Array.isArray(response?.roles)
|
||||||
|
? response.roles
|
||||||
|
: []
|
||||||
|
const userInfo = typeof loginData === 'object' ? loginData : { token }
|
||||||
|
|
||||||
ElMessage.success('登录成功')
|
if (token) {
|
||||||
// 跳转到首页
|
authStore.setToken(token)
|
||||||
router.push('/home')
|
authStore.setUserInfo({
|
||||||
}
|
...userInfo,
|
||||||
} catch (error: any) {
|
username: userInfo.username || loginForm.username,
|
||||||
// 错误提示已在全局响应拦截中处理,这里不重复弹出
|
token,
|
||||||
console.warn('login error:', error)
|
roles,
|
||||||
} finally {
|
permissions,
|
||||||
loginLoading.value = false
|
})
|
||||||
}
|
authStore.setPermissions(permissions)
|
||||||
|
localStorage.setItem('username', userInfo.username || loginForm.username)
|
||||||
|
localStorage.setItem('token', token)
|
||||||
|
localStorage.setItem('permissions', JSON.stringify(permissions))
|
||||||
|
|
||||||
|
ElMessage.success('登录成功')
|
||||||
|
router.push('/home')
|
||||||
|
} else {
|
||||||
|
ElMessage.error(response?.message || '登录失败,未获取到令牌')
|
||||||
}
|
}
|
||||||
})
|
} catch (error: any) {
|
||||||
|
// 错误提示已在全局响应拦截中处理,这里不重复弹出
|
||||||
|
console.warn('login error:', error)
|
||||||
|
} finally {
|
||||||
|
loginLoading.value = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理注册
|
// 处理注册
|
||||||
|
|||||||
@@ -66,7 +66,7 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<div class="toolbar">
|
<div class="toolbar">
|
||||||
<el-button type="primary" @click="openDrawer('create')">新增部门</el-button>
|
<el-button v-permission="'sys:department:add'" type="primary" @click="openDrawer('create')">新增部门</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
@@ -106,8 +106,8 @@
|
|||||||
/>
|
/>
|
||||||
<el-table-column label="操作" width="180" fixed="right">
|
<el-table-column label="操作" width="180" fixed="right">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-button type="primary" link @click="openDrawer('edit', scope.row)">编辑</el-button>
|
<el-button v-permission="'sys:department:upd'" type="primary" link @click="openDrawer('edit', scope.row)">编辑</el-button>
|
||||||
<el-button type="danger" link @click="handleDelete(scope.row)">删除</el-button>
|
<el-button v-permission="'sys:department:del'" type="danger" link @click="handleDelete(scope.row)">删除</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|||||||
@@ -51,7 +51,7 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<div class="toolbar">
|
<div class="toolbar">
|
||||||
<el-button type="primary" @click="handleAdd">
|
<el-button v-permission="'data:dev:add'" type="primary" @click="handleAdd">
|
||||||
<el-icon><Plus /></el-icon>
|
<el-icon><Plus /></el-icon>
|
||||||
新增动作
|
新增动作
|
||||||
</el-button>
|
</el-button>
|
||||||
@@ -105,15 +105,15 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="操作" width="220" fixed="right">
|
<el-table-column label="操作" width="220" fixed="right">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-button type="success" size="small" link @click="handleConfigParams(row)">
|
<el-button v-permission="'data:dev:setparameters'" type="success" size="small" link @click="handleConfigParams(row)">
|
||||||
<el-icon><Setting /></el-icon>
|
<el-icon><Setting /></el-icon>
|
||||||
配置参数
|
配置参数
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button type="primary" size="small" link @click="handleEdit(row)">
|
<el-button v-permission="'data:dev:upd'" type="primary" size="small" link @click="handleEdit(row)">
|
||||||
<el-icon><Edit /></el-icon>
|
<el-icon><Edit /></el-icon>
|
||||||
编辑
|
编辑
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button type="danger" size="small" link @click="handleDelete(row)">
|
<el-button v-permission="'data:dev:del'" type="danger" size="small" link @click="handleDelete(row)">
|
||||||
<el-icon><Delete /></el-icon>
|
<el-icon><Delete /></el-icon>
|
||||||
删除
|
删除
|
||||||
</el-button>
|
</el-button>
|
||||||
@@ -360,6 +360,7 @@ const formData = reactive({
|
|||||||
islandId: undefined as number | undefined,
|
islandId: undefined as number | undefined,
|
||||||
devDesc: '',
|
devDesc: '',
|
||||||
remark: '',
|
remark: '',
|
||||||
|
devModel: 'OTHER',
|
||||||
status: 0, // 状态自动设置为0
|
status: 0, // 状态自动设置为0
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -594,6 +595,7 @@ const resetForm = () => {
|
|||||||
formData.islandId = undefined
|
formData.islandId = undefined
|
||||||
formData.devDesc = ''
|
formData.devDesc = ''
|
||||||
formData.remark = ''
|
formData.remark = ''
|
||||||
|
formData.devModel = 'OTHER'
|
||||||
formData.status = 0
|
formData.status = 0
|
||||||
formRef.value?.clearValidate()
|
formRef.value?.clearValidate()
|
||||||
}
|
}
|
||||||
@@ -611,6 +613,7 @@ const handleEdit = async (item: any) => {
|
|||||||
formData.islandId = data.islandId ?? undefined
|
formData.islandId = data.islandId ?? undefined
|
||||||
formData.devDesc = data.devDesc ?? ''
|
formData.devDesc = data.devDesc ?? ''
|
||||||
formData.remark = data.remark ?? ''
|
formData.remark = data.remark ?? ''
|
||||||
|
formData.devModel = data.devModel ?? 'OTHER'
|
||||||
formData.status = data.status ?? 0
|
formData.status = data.status ?? 0
|
||||||
|
|
||||||
isEdit.value = true
|
isEdit.value = true
|
||||||
@@ -683,6 +686,7 @@ const handleSubmit = async () => {
|
|||||||
devName: formData.devName,
|
devName: formData.devName,
|
||||||
plcAddr: formData.plcAddr,
|
plcAddr: formData.plcAddr,
|
||||||
islandId: formData.islandId,
|
islandId: formData.islandId,
|
||||||
|
devModel: formData.devModel || 'OTHER',
|
||||||
}
|
}
|
||||||
|
|
||||||
if (formData.devDesc) submitData.devDesc = formData.devDesc
|
if (formData.devDesc) submitData.devDesc = formData.devDesc
|
||||||
@@ -959,7 +963,7 @@ const setSelectedParams = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 参数选择变化
|
// 参数选择变化
|
||||||
const handleParamSelectionChange = (selection: any[]) => {
|
const handleParamSelectionChange = (_selection: any[]) => {
|
||||||
// noop
|
// noop
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<div class="toolbar">
|
<div class="toolbar">
|
||||||
<el-button type="primary" @click="handleAdd">
|
<el-button v-permission="'data:plc:add'" type="primary" @click="handleAdd">
|
||||||
<el-icon><Plus /></el-icon>
|
<el-icon><Plus /></el-icon>
|
||||||
新增PLC设备
|
新增PLC设备
|
||||||
</el-button>
|
</el-button>
|
||||||
@@ -84,6 +84,7 @@
|
|||||||
<el-table-column label="操作" width="180" fixed="right">
|
<el-table-column label="操作" width="180" fixed="right">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-button
|
<el-button
|
||||||
|
v-permission="'data:plc:upd'"
|
||||||
type="primary"
|
type="primary"
|
||||||
size="small"
|
size="small"
|
||||||
link
|
link
|
||||||
@@ -93,6 +94,7 @@
|
|||||||
编辑
|
编辑
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
|
v-permission="'data:plc:del'"
|
||||||
type="danger"
|
type="danger"
|
||||||
size="small"
|
size="small"
|
||||||
link
|
link
|
||||||
|
|||||||
@@ -34,12 +34,12 @@
|
|||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" @click="handleSearch">查询</el-button>
|
<el-button v-permission="'data:devparam:select'" type="primary" @click="handleSearch">查询</el-button>
|
||||||
<el-button @click="resetSearch">重置</el-button>
|
<el-button @click="resetSearch">重置</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<div class="toolbar">
|
<div class="toolbar">
|
||||||
<el-button type="primary" @click="handleAdd">
|
<el-button v-permission="'data:devparam:add'" type="primary" @click="handleAdd">
|
||||||
<el-icon><Plus /></el-icon>
|
<el-icon><Plus /></el-icon>
|
||||||
新增动作参数
|
新增动作参数
|
||||||
</el-button>
|
</el-button>
|
||||||
@@ -86,25 +86,31 @@
|
|||||||
</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 }">
|
||||||
<el-button
|
<span v-if="row.formType === 'select'">
|
||||||
v-if="row.formType === 'select'"
|
<el-button
|
||||||
type="success"
|
v-if="canConfigSelectOptions"
|
||||||
size="small"
|
type="success"
|
||||||
link
|
size="small"
|
||||||
@click="handleConfigFormTypeOptions(row)"
|
link
|
||||||
>
|
@click="handleConfigFormTypeOptions(row)"
|
||||||
下拉框
|
>
|
||||||
</el-button>
|
下拉框
|
||||||
<el-button
|
</el-button>
|
||||||
v-else-if="row.formType === 'input' || row.formType === 'number'"
|
<span v-else>下拉框</span>
|
||||||
type="warning"
|
</span>
|
||||||
size="small"
|
<span v-else-if="row.formType === 'input' || row.formType === 'number'">
|
||||||
link
|
<el-button
|
||||||
class="range-config-button"
|
v-if="canConfigRange"
|
||||||
@click="handleConfigRange(row)"
|
type="warning"
|
||||||
>
|
size="small"
|
||||||
{{ getFormTypeLabel(row.formType) || '暂无' }}
|
link
|
||||||
</el-button>
|
class="range-config-button"
|
||||||
|
@click="handleConfigRange(row)"
|
||||||
|
>
|
||||||
|
{{ getFormTypeLabel(row.formType) || '暂无' }}
|
||||||
|
</el-button>
|
||||||
|
<span v-else>{{ getFormTypeLabel(row.formType) || '暂无' }}</span>
|
||||||
|
</span>
|
||||||
<span v-else>{{ getFormTypeLabel(row.formType) || '暂无' }}</span>
|
<span v-else>{{ getFormTypeLabel(row.formType) || '暂无' }}</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
@@ -124,6 +130,7 @@
|
|||||||
<el-table-column label="操作" width="180" fixed="right">
|
<el-table-column label="操作" width="180" fixed="right">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-button
|
<el-button
|
||||||
|
v-permission="'data:devparam:upd'"
|
||||||
type="primary"
|
type="primary"
|
||||||
size="small"
|
size="small"
|
||||||
link
|
link
|
||||||
@@ -133,6 +140,7 @@
|
|||||||
编辑
|
编辑
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
|
v-permission="'data:devparam:del'"
|
||||||
type="danger"
|
type="danger"
|
||||||
size="small"
|
size="small"
|
||||||
link
|
link
|
||||||
@@ -234,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">
|
||||||
@@ -257,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">
|
||||||
@@ -369,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,
|
||||||
@@ -388,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)
|
||||||
@@ -1029,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
|
||||||
@@ -1156,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
|
||||||
|
|||||||
@@ -18,12 +18,12 @@
|
|||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" @click="handleSearch">查询</el-button>
|
<el-button v-permission="'tb:goodcontrolselect'" type="primary" @click="handleSearch">查询</el-button>
|
||||||
<el-button @click="resetSearch">重置</el-button>
|
<el-button @click="resetSearch">重置</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<div class="toolbar">
|
<div class="toolbar">
|
||||||
<el-button type="primary" @click="handleAdd">
|
<el-button v-permission="'tb:goodcontroladd'" type="primary" @click="handleAdd">
|
||||||
<el-icon><Plus /></el-icon>
|
<el-icon><Plus /></el-icon>
|
||||||
新增流程
|
新增流程
|
||||||
</el-button>
|
</el-button>
|
||||||
@@ -97,6 +97,7 @@
|
|||||||
<el-table-column label="操作" width="260" fixed="right">
|
<el-table-column label="操作" width="260" fixed="right">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-button
|
<el-button
|
||||||
|
v-permission="'tb:goodcontrolupdSOP'"
|
||||||
:type="scope.row.hasWorkflow ? 'success' : 'warning'"
|
:type="scope.row.hasWorkflow ? 'success' : 'warning'"
|
||||||
link
|
link
|
||||||
:loading="scope.row.workflowLoading"
|
:loading="scope.row.workflowLoading"
|
||||||
@@ -104,9 +105,9 @@
|
|||||||
>
|
>
|
||||||
{{ scope.row.hasWorkflow ? '编辑流程' : '配置流程' }}
|
{{ scope.row.hasWorkflow ? '编辑流程' : '配置流程' }}
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button type="info" link @click="handleSelectGoods(scope.row)">选择样品</el-button>
|
<el-button v-permission="'tb:goodcontrolchooseSC'" type="info" link @click="handleSelectGoods(scope.row)">选择样品</el-button>
|
||||||
<el-button type="primary" link @click="handleEdit(scope.row)">编辑</el-button>
|
<el-button v-permission="'tb:goodcontrolupd'" type="primary" link @click="handleEdit(scope.row)">编辑</el-button>
|
||||||
<el-button type="danger" link @click="handleDelete(scope.row)">删除</el-button>
|
<el-button v-permission="'tb:goodcontroldel'" type="danger" link @click="handleDelete(scope.row)">删除</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|
||||||
@@ -130,7 +134,7 @@
|
|||||||
/>
|
/>
|
||||||
<el-table-column label="操作" width="120" fixed="right">
|
<el-table-column label="操作" width="120" fixed="right">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-button type="primary" link @click="handleViewDetail(row)">详情</el-button>
|
<el-button v-permission="'tb:goodrecord:detail'" type="primary" link @click="handleViewDetail(row)">详情</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
@@ -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) {
|
||||||
// 待处理 - 显示提示
|
// 待处理 - 显示提示
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<div class="toolbar">
|
<div class="toolbar">
|
||||||
<el-button type="primary" @click="handleAdd">
|
<el-button v-permission="'data:island:add'" type="primary" @click="handleAdd">
|
||||||
<el-icon><Plus /></el-icon>
|
<el-icon><Plus /></el-icon>
|
||||||
新增功能岛
|
新增功能岛
|
||||||
</el-button>
|
</el-button>
|
||||||
@@ -73,11 +73,11 @@
|
|||||||
</el-icon>
|
</el-icon>
|
||||||
<template #dropdown>
|
<template #dropdown>
|
||||||
<el-dropdown-menu>
|
<el-dropdown-menu>
|
||||||
<el-dropdown-item command="edit">
|
<el-dropdown-item v-permission="'data:island:upd'" command="edit">
|
||||||
<el-icon><Edit /></el-icon>
|
<el-icon><Edit /></el-icon>
|
||||||
编辑
|
编辑
|
||||||
</el-dropdown-item>
|
</el-dropdown-item>
|
||||||
<el-dropdown-item command="delete" divided>
|
<el-dropdown-item v-permission="'data:island:del'" command="delete" divided>
|
||||||
<el-icon><Delete /></el-icon>
|
<el-icon><Delete /></el-icon>
|
||||||
删除
|
删除
|
||||||
</el-dropdown-item>
|
</el-dropdown-item>
|
||||||
|
|||||||
@@ -84,7 +84,7 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="操作" width="120" fixed="right">
|
<el-table-column label="操作" width="120" fixed="right">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-button type="primary" link @click="openDetailDialog(scope.row)">详情</el-button>
|
<el-button v-permission="'sys:managelog:detail'" type="primary" link @click="openDetailDialog(scope.row)">详情</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|||||||
@@ -53,7 +53,7 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<div class="toolbar">
|
<div class="toolbar">
|
||||||
<el-button type="primary" @click="openDrawer('create')">新增权限</el-button>
|
<el-button v-permission="'sys:permission:add'" type="primary" @click="openDrawer('create')">新增权限</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
@@ -66,8 +66,8 @@
|
|||||||
<el-table-column prop="parentId" label="上级权限" min-width="180" :formatter="formatParentCell" />
|
<el-table-column prop="parentId" label="上级权限" min-width="180" :formatter="formatParentCell" />
|
||||||
<el-table-column label="操作" width="180" fixed="right">
|
<el-table-column label="操作" width="180" fixed="right">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-button type="primary" link @click="openDrawer('edit', scope.row)">编辑</el-button>
|
<el-button v-permission="'sys:permission:upd'" type="primary" link @click="openDrawer('edit', scope.row)">编辑</el-button>
|
||||||
<el-button type="danger" link @click="handleDelete(scope.row)">删除</el-button>
|
<el-button v-permission="'sys:permission:del'" type="danger" link @click="handleDelete(scope.row)">删除</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
<el-form-item label="职位名称">
|
<el-form-item label="职位名称">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="queryForm.posiName"
|
v-model="queryForm.posiName"
|
||||||
placeholder="输入职位名称"
|
placeholder="输入名称"
|
||||||
clearable
|
clearable
|
||||||
style="width: 200px"
|
style="width: 200px"
|
||||||
/>
|
/>
|
||||||
@@ -25,12 +25,12 @@
|
|||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" @click="handleSearch">查询</el-button>
|
<el-button v-permission="'sys:positionselect'" type="primary" @click="handleSearch">查询</el-button>
|
||||||
<el-button @click="resetSearch">重置</el-button>
|
<el-button @click="resetSearch">重置</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<div class="toolbar">
|
<div class="toolbar">
|
||||||
<el-button type="primary" @click="openDrawer('create')">新增职位</el-button>
|
<el-button v-permission="'sys:positionadd'" type="primary" @click="openDrawer('create')">新增职位</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
@@ -64,8 +64,8 @@
|
|||||||
/>
|
/>
|
||||||
<el-table-column label="操作" width="180" fixed="right">
|
<el-table-column label="操作" width="180" fixed="right">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-button type="primary" link @click="openDrawer('edit', scope.row)">编辑</el-button>
|
<el-button v-permission="'sys:positionupd'" type="primary" link @click="openDrawer('edit', scope.row)">编辑</el-button>
|
||||||
<el-button type="danger" link @click="handleDelete(scope.row)">删除</el-button>
|
<el-button v-permission="'sys:positiondel'" type="danger" link @click="handleDelete(scope.row)">删除</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|||||||
580
rc_autoplc_front/src/views/recordinfo/index.vue
Normal file
580
rc_autoplc_front/src/views/recordinfo/index.vue
Normal file
@@ -0,0 +1,580 @@
|
|||||||
|
<template>
|
||||||
|
<div class="recordinfo-page">
|
||||||
|
<el-breadcrumb separator="/" style="margin-bottom: 16px">
|
||||||
|
<el-breadcrumb-item><router-link to="/home">首页</router-link></el-breadcrumb-item>
|
||||||
|
<el-breadcrumb-item>业务流程控制</el-breadcrumb-item>
|
||||||
|
<el-breadcrumb-item>异常记录</el-breadcrumb-item>
|
||||||
|
</el-breadcrumb>
|
||||||
|
|
||||||
|
<el-card class="search-card" shadow="never">
|
||||||
|
<div class="search-bar">
|
||||||
|
<el-form :inline="true" :model="queryForm" label-width="90px">
|
||||||
|
<el-form-item label="异常名称">
|
||||||
|
<el-input v-model="queryForm.recordName" placeholder="请输入异常名称" clearable style="width: 220px" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="异常类型">
|
||||||
|
<el-select v-model="queryForm.recordType" placeholder="请选择异常类型" clearable style="width: 220px">
|
||||||
|
<el-option label="设备异常" :value="1" />
|
||||||
|
<el-option label="样品异常" :value="2" />
|
||||||
|
<el-option label="操作异常" :value="3" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="处理状态">
|
||||||
|
<el-select v-model="queryForm.recordStatus" placeholder="请选择处理状态" clearable style="width: 220px">
|
||||||
|
<el-option label="未处理" :value="false" />
|
||||||
|
<el-option label="已处理" :value="true" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" @click="handleSearch">查询</el-button>
|
||||||
|
<el-button @click="resetSearch">重置</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<el-card shadow="never">
|
||||||
|
<el-table :data="tableData" stripe border style="width: 100%" v-loading="loading">
|
||||||
|
<el-table-column type="index" label="序号" width="70" :index="getIndex" />
|
||||||
|
<el-table-column prop="recordName" label="异常名称" min-width="160" show-overflow-tooltip />
|
||||||
|
<el-table-column prop="islandId" label="异常功能岛" min-width="150" show-overflow-tooltip>
|
||||||
|
<template #default="{ row }">
|
||||||
|
{{ getIslandName(row.islandId) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="devId" label="异常动作" min-width="150" show-overflow-tooltip>
|
||||||
|
<template #default="{ row }">
|
||||||
|
{{ getActionDisplayName(row) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="recordContent" label="异常记录内容" min-width="260" show-overflow-tooltip />
|
||||||
|
<el-table-column label="操作" width="180" fixed="right">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-button v-permission="'tb:exceptionrecord:handling'" type="success" link @click="handleDeal(row)">异常处理</el-button>
|
||||||
|
<el-button v-permission="'tb:exceptionrecord:detail'" type="primary" link @click="handleView(row)">详情</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="recordType" label="异常类型" width="140" align="center">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-tag :type="getRecordTypeTag(row.recordType)" size="small">
|
||||||
|
{{ getRecordTypeText(row.recordType) }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="recordStatus" label="异常处理状态" width="150" align="center">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-tag :type="row.recordStatus ? 'success' : 'warning'" size="small">
|
||||||
|
{{ row.recordStatus ? '已处理' : '未处理' }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<div class="pagination">
|
||||||
|
<el-pagination
|
||||||
|
v-model:current-page="pagination.pageNum"
|
||||||
|
v-model:page-size="pagination.pageSize"
|
||||||
|
:page-sizes="[10, 20, 50, 100]"
|
||||||
|
layout="total, sizes, prev, pager, next, jumper"
|
||||||
|
:total="total"
|
||||||
|
background
|
||||||
|
@current-change="handleCurrentChange"
|
||||||
|
@size-change="handleSizeChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<el-dialog v-model="detailVisible" title="异常记录详情" width="720px">
|
||||||
|
<el-descriptions :column="1" border>
|
||||||
|
<el-descriptions-item label="异常功能岛">{{ getIslandName(detailData.islandId) }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="异常动作">{{ getActionDisplayName(detailData) }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="异常名称">{{ detailData.recordName || '-' }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="异常类型">{{ getRecordTypeText(detailData.recordType) }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="异常处理状态">{{ detailData.recordStatus ? '已处理' : '未处理' }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="异常记录内容">{{ detailData.recordContent || '-' }}</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="detailVisible = false">关闭</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<el-dialog v-model="dealVisible" title="异常处理" width="980px" destroy-on-close @close="handleDealDialogClose">
|
||||||
|
<div class="deal-container" v-loading="dealLoading">
|
||||||
|
<el-form ref="dealFormRef" :model="dealForm" :rules="dealRules" label-width="120px" class="deal-form">
|
||||||
|
<el-form-item label="异常名称">
|
||||||
|
<el-input v-model="dealForm.recordName" disabled />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="异常类型">
|
||||||
|
<el-input :model-value="getRecordTypeText(dealForm.recordType)" disabled />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="异常处理方案" prop="dealContent">
|
||||||
|
<el-input
|
||||||
|
v-model="dealForm.dealContent"
|
||||||
|
type="textarea"
|
||||||
|
:rows="4"
|
||||||
|
:disabled="!dealEditable"
|
||||||
|
placeholder="请输入异常处理方案"
|
||||||
|
maxlength="500"
|
||||||
|
show-word-limit
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<div class="deal-list-title">异常处理记录</div>
|
||||||
|
<el-table :data="dealList" border stripe style="width: 100%" :loading="dealListLoading">
|
||||||
|
<el-table-column type="index" label="序号" width="70" :index="getDealIndex" />
|
||||||
|
<el-table-column prop="recordName" label="异常名称" min-width="150" show-overflow-tooltip />
|
||||||
|
<el-table-column prop="recordType" label="异常类型" width="140" align="center">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-tag :type="getRecordTypeTag(row.recordType)" size="small">
|
||||||
|
{{ getRecordTypeText(row.recordType) }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="dealContent" label="异常处理方案" min-width="260" show-overflow-tooltip />
|
||||||
|
<el-table-column label="操作" width="110" align="center">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-button v-permission="'tb:exceptionrecord:chose'" type="primary" link @click="handleSelectDeal(row)">选择</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<div class="pagination deal-pagination">
|
||||||
|
<el-pagination
|
||||||
|
v-model:current-page="dealPagination.pageNum"
|
||||||
|
v-model:page-size="dealPagination.pageSize"
|
||||||
|
:page-sizes="[5, 10, 20, 50]"
|
||||||
|
layout="total, sizes, prev, pager, next, jumper"
|
||||||
|
:total="dealTotal"
|
||||||
|
background
|
||||||
|
@current-change="handleDealCurrentChange"
|
||||||
|
@size-change="handleDealSizeChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="dealVisible = false">关闭</el-button>
|
||||||
|
<el-button
|
||||||
|
v-permission="'tb:exceptionrecord:upd'"
|
||||||
|
type="primary"
|
||||||
|
:loading="saveLoading"
|
||||||
|
@click="handleDealSave"
|
||||||
|
>
|
||||||
|
{{ dealEditable ? '保存' : '编辑' }}
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { onMounted, reactive, ref } from 'vue'
|
||||||
|
import type { FormInstance, FormRules } from 'element-plus'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import { islandInfolist } from '@/api/tb/islandinfo'
|
||||||
|
import { devselect } from '@/api/tb/devinfo'
|
||||||
|
import { recordInfoupd, recordInfolist } from '@/api/tb/recordinfo'
|
||||||
|
import { recordDealadd, recordDealupd, recordDeallistByRecordId, recordDeallist } from '@/api/tb/recorddeal'
|
||||||
|
|
||||||
|
interface RecordInfoItem {
|
||||||
|
id?: string | number
|
||||||
|
islandId?: string | number
|
||||||
|
devId?: string | number
|
||||||
|
recordName?: string
|
||||||
|
recordType?: number
|
||||||
|
recordStatus?: boolean
|
||||||
|
recordContent?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RecordDealItem {
|
||||||
|
id?: string | number
|
||||||
|
recordId?: string | number
|
||||||
|
recordName?: string
|
||||||
|
recordType?: number
|
||||||
|
dealContent?: string
|
||||||
|
createTime?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface OptionItem {
|
||||||
|
id?: string | number
|
||||||
|
islandName?: string
|
||||||
|
name?: string
|
||||||
|
devName?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ActionItem {
|
||||||
|
id?: string | number
|
||||||
|
devName?: string
|
||||||
|
actionName?: string
|
||||||
|
name?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const loading = ref(false)
|
||||||
|
const tableData = ref<RecordInfoItem[]>([])
|
||||||
|
const total = ref(0)
|
||||||
|
const detailVisible = ref(false)
|
||||||
|
const detailData = ref<RecordInfoItem>({})
|
||||||
|
|
||||||
|
const islandOptions = ref<OptionItem[]>([])
|
||||||
|
const actionOptions = ref<ActionItem[]>([])
|
||||||
|
const islandMap = ref<Map<string, string>>(new Map())
|
||||||
|
const actionMap = ref<Map<string, string>>(new Map())
|
||||||
|
|
||||||
|
const dealVisible = ref(false)
|
||||||
|
const dealLoading = ref(false)
|
||||||
|
const dealListLoading = ref(false)
|
||||||
|
const saveLoading = ref(false)
|
||||||
|
const dealEditable = ref(true)
|
||||||
|
const dealHasExistingRecord = ref(false)
|
||||||
|
const dealCurrentRecordId = ref<string | number>('')
|
||||||
|
const dealCurrentRecordType = ref<number | undefined>(undefined)
|
||||||
|
const dealCurrentDealId = ref<string | number>('')
|
||||||
|
const dealListMode = ref<'record' | 'type'>('record')
|
||||||
|
const dealList = ref<RecordDealItem[]>([])
|
||||||
|
const dealTotal = ref(0)
|
||||||
|
const dealFormRef = ref<FormInstance>()
|
||||||
|
|
||||||
|
const queryForm = reactive({
|
||||||
|
recordName: '',
|
||||||
|
recordType: '' as number | '',
|
||||||
|
recordStatus: '' as boolean | '',
|
||||||
|
})
|
||||||
|
|
||||||
|
const pagination = reactive({
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
})
|
||||||
|
|
||||||
|
const dealPagination = reactive({
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
})
|
||||||
|
|
||||||
|
const dealForm = reactive<RecordDealItem>({
|
||||||
|
id: undefined,
|
||||||
|
recordId: undefined,
|
||||||
|
recordName: '',
|
||||||
|
recordType: undefined,
|
||||||
|
dealContent: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
const dealRules: FormRules = {
|
||||||
|
dealContent: [{ required: true, message: '请输入异常处理方案', trigger: 'blur' }],
|
||||||
|
}
|
||||||
|
|
||||||
|
const getListFromResponse = (res: any) => {
|
||||||
|
const data = res?.data?.data ?? res?.data ?? res ?? {}
|
||||||
|
return data.records || data.list || data.rows || data || []
|
||||||
|
}
|
||||||
|
|
||||||
|
const getTotalFromResponse = (res: any) => {
|
||||||
|
const data = res?.data?.data ?? res?.data ?? res ?? {}
|
||||||
|
return data.total ?? data.count ?? 0
|
||||||
|
}
|
||||||
|
|
||||||
|
const getFirstRecord = (res: any) => {
|
||||||
|
const list = getListFromResponse(res)
|
||||||
|
return Array.isArray(list) ? list[0] : undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadLookups = async () => {
|
||||||
|
try {
|
||||||
|
const [islandRes, actionRes] = await Promise.all([
|
||||||
|
islandInfolist({ pageNum: 1, pageSize: 1000 }),
|
||||||
|
devselect({ pageNum: 1, pageSize: 1000 }),
|
||||||
|
])
|
||||||
|
islandOptions.value = getListFromResponse(islandRes)
|
||||||
|
actionOptions.value = getListFromResponse(actionRes)
|
||||||
|
|
||||||
|
islandMap.value = new Map(
|
||||||
|
islandOptions.value
|
||||||
|
.filter(item => item.id !== undefined && item.id !== null)
|
||||||
|
.map(item => [String(item.id), item.islandName || item.name || String(item.id)]),
|
||||||
|
)
|
||||||
|
actionMap.value = new Map(
|
||||||
|
actionOptions.value
|
||||||
|
.filter(item => item.id !== undefined && item.id !== null)
|
||||||
|
.map(item => [String(item.id), item.devName || item.actionName || item.name || String(item.id)]),
|
||||||
|
)
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadTableData = async () => {
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
const params = {
|
||||||
|
pageNum: pagination.pageNum,
|
||||||
|
pageSize: pagination.pageSize,
|
||||||
|
recordName: queryForm.recordName || undefined,
|
||||||
|
recordType: queryForm.recordType === '' ? undefined : queryForm.recordType,
|
||||||
|
recordStatus: queryForm.recordStatus === '' ? undefined : queryForm.recordStatus,
|
||||||
|
}
|
||||||
|
const res = await recordInfolist(params)
|
||||||
|
tableData.value = getListFromResponse(res)
|
||||||
|
total.value = getTotalFromResponse(res)
|
||||||
|
} catch (error: any) {
|
||||||
|
ElMessage.error(error?.message || '获取异常记录列表失败')
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadDealList = async () => {
|
||||||
|
dealListLoading.value = true
|
||||||
|
try {
|
||||||
|
const params = {
|
||||||
|
pageNum: dealPagination.pageNum,
|
||||||
|
pageSize: dealPagination.pageSize,
|
||||||
|
}
|
||||||
|
let res: any
|
||||||
|
if (dealListMode.value === 'record' && dealCurrentRecordId.value !== '') {
|
||||||
|
res = await recordDeallistByRecordId(dealCurrentRecordId.value)
|
||||||
|
} else {
|
||||||
|
res = await recordDeallist({ ...params, recordType: dealCurrentRecordType.value })
|
||||||
|
}
|
||||||
|
dealList.value = getListFromResponse(res)
|
||||||
|
dealTotal.value = getTotalFromResponse(res)
|
||||||
|
} catch (error: any) {
|
||||||
|
ElMessage.error(error?.message || '获取异常处理记录失败')
|
||||||
|
} finally {
|
||||||
|
dealListLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const initDealDialog = async (row: RecordInfoItem) => {
|
||||||
|
dealLoading.value = true
|
||||||
|
dealVisible.value = true
|
||||||
|
dealCurrentRecordId.value = row.id ?? ''
|
||||||
|
dealCurrentRecordType.value = row.recordType
|
||||||
|
dealCurrentDealId.value = ''
|
||||||
|
dealHasExistingRecord.value = false
|
||||||
|
dealEditable.value = true
|
||||||
|
dealListMode.value = 'record'
|
||||||
|
dealPagination.pageNum = 1
|
||||||
|
dealPagination.pageSize = 10
|
||||||
|
dealForm.id = undefined
|
||||||
|
dealForm.recordId = row.id
|
||||||
|
dealForm.recordName = row.recordName || ''
|
||||||
|
dealForm.recordType = row.recordType
|
||||||
|
dealForm.dealContent = ''
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await recordDeallistByRecordId(row.id as string | number)
|
||||||
|
const first = getFirstRecord(res)
|
||||||
|
if (first) {
|
||||||
|
dealHasExistingRecord.value = true
|
||||||
|
dealForm.id = first.id
|
||||||
|
dealForm.recordId = first.recordId ?? row.id
|
||||||
|
dealForm.recordName = first.recordName || row.recordName || ''
|
||||||
|
dealForm.recordType = first.recordType ?? row.recordType
|
||||||
|
dealForm.dealContent = first.dealContent || ''
|
||||||
|
dealCurrentDealId.value = first.id ?? ''
|
||||||
|
dealEditable.value = false
|
||||||
|
dealListMode.value = 'record'
|
||||||
|
} else {
|
||||||
|
dealForm.id = undefined
|
||||||
|
dealForm.recordId = row.id
|
||||||
|
dealForm.recordName = row.recordName || ''
|
||||||
|
dealForm.recordType = row.recordType
|
||||||
|
dealForm.dealContent = ''
|
||||||
|
dealEditable.value = true
|
||||||
|
dealListMode.value = 'type'
|
||||||
|
}
|
||||||
|
await loadDealList()
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
dealEditable.value = true
|
||||||
|
dealListMode.value = 'type'
|
||||||
|
await loadDealList()
|
||||||
|
} finally {
|
||||||
|
dealLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSearch = () => {
|
||||||
|
pagination.pageNum = 1
|
||||||
|
loadTableData()
|
||||||
|
}
|
||||||
|
|
||||||
|
const resetSearch = () => {
|
||||||
|
queryForm.recordName = ''
|
||||||
|
queryForm.recordType = ''
|
||||||
|
queryForm.recordStatus = ''
|
||||||
|
pagination.pageNum = 1
|
||||||
|
loadTableData()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleCurrentChange = (page: number) => {
|
||||||
|
pagination.pageNum = page
|
||||||
|
loadTableData()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSizeChange = (size: number) => {
|
||||||
|
pagination.pageSize = size
|
||||||
|
pagination.pageNum = 1
|
||||||
|
loadTableData()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleView = (row: RecordInfoItem) => {
|
||||||
|
detailData.value = { ...row }
|
||||||
|
detailVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDeal = (row: RecordInfoItem) => {
|
||||||
|
initDealDialog(row)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDealDialogClose = () => {
|
||||||
|
dealFormRef.value?.clearValidate()
|
||||||
|
dealHasExistingRecord.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDealCurrentChange = (page: number) => {
|
||||||
|
dealPagination.pageNum = page
|
||||||
|
loadDealList()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDealSizeChange = (size: number) => {
|
||||||
|
dealPagination.pageSize = size
|
||||||
|
dealPagination.pageNum = 1
|
||||||
|
loadDealList()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSelectDeal = (row: RecordDealItem) => {
|
||||||
|
dealForm.dealContent = row.dealContent || ''
|
||||||
|
dealEditable.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDealSave = async () => {
|
||||||
|
if (!dealEditable.value) {
|
||||||
|
dealEditable.value = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
await dealFormRef.value?.validate(async valid => {
|
||||||
|
if (!valid) return
|
||||||
|
|
||||||
|
saveLoading.value = true
|
||||||
|
try {
|
||||||
|
const payload = {
|
||||||
|
...dealForm,
|
||||||
|
recordId: dealCurrentRecordId.value,
|
||||||
|
recordType: dealCurrentRecordType.value,
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dealHasExistingRecord.value) {
|
||||||
|
if (!dealCurrentDealId.value) {
|
||||||
|
ElMessage.error('未找到可修改的异常处理记录')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
await recordDealupd({ ...payload, id: dealCurrentDealId.value })
|
||||||
|
ElMessage.success('异常处理记录修改成功')
|
||||||
|
} else {
|
||||||
|
await recordDealadd({ ...payload, id: undefined })
|
||||||
|
await recordInfoupd({
|
||||||
|
id: dealCurrentRecordId.value,
|
||||||
|
recordStatus: true,
|
||||||
|
})
|
||||||
|
ElMessage.success('异常处理记录新增成功')
|
||||||
|
}
|
||||||
|
|
||||||
|
dealHasExistingRecord.value = true
|
||||||
|
dealEditable.value = false
|
||||||
|
dealListMode.value = 'record'
|
||||||
|
dealPagination.pageNum = 1
|
||||||
|
await loadDealList()
|
||||||
|
await loadTableData()
|
||||||
|
dealVisible.value = false
|
||||||
|
dealFormRef.value?.resetFields()
|
||||||
|
dealHasExistingRecord.value = false
|
||||||
|
dealCurrentDealId.value = ''
|
||||||
|
} catch (error: any) {
|
||||||
|
ElMessage.error(error?.message || '保存异常处理记录失败')
|
||||||
|
} finally {
|
||||||
|
saveLoading.value = false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const getIndex = (index: number) => (pagination.pageNum - 1) * pagination.pageSize + index + 1
|
||||||
|
const getDealIndex = (index: number) => (dealPagination.pageNum - 1) * dealPagination.pageSize + index + 1
|
||||||
|
|
||||||
|
const getIslandName = (id?: string | number) => {
|
||||||
|
if (id === undefined || id === null || id === '') return '-'
|
||||||
|
return islandMap.value.get(String(id)) || String(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
const getActionDisplayName = (row: RecordInfoItem) => {
|
||||||
|
const candidates = [row.devId, (row as any).actionId, (row as any).dealActionId, (row as any).action]
|
||||||
|
for (const candidate of candidates) {
|
||||||
|
if (candidate === undefined || candidate === null || candidate === '') continue
|
||||||
|
const mapped = actionMap.value.get(String(candidate))
|
||||||
|
if (mapped) return mapped
|
||||||
|
}
|
||||||
|
return row.devId !== undefined && row.devId !== null && row.devId !== '' ? String(row.devId) : '-'
|
||||||
|
}
|
||||||
|
|
||||||
|
const getRecordTypeText = (type?: number) => {
|
||||||
|
if (type === 1) return '设备异常'
|
||||||
|
if (type === 2) return '样品异常'
|
||||||
|
if (type === 3) return '操作异常'
|
||||||
|
return '-'
|
||||||
|
}
|
||||||
|
|
||||||
|
const getRecordTypeTag = (type?: number) => {
|
||||||
|
if (type === 1) return 'danger'
|
||||||
|
if (type === 2) return 'warning'
|
||||||
|
if (type === 3) return 'info'
|
||||||
|
return 'default'
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
await loadLookups()
|
||||||
|
await loadTableData()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.recordinfo-page {
|
||||||
|
padding: 0 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-bar {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 16px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination {
|
||||||
|
margin-top: 16px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deal-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deal-form {
|
||||||
|
border: 1px solid var(--el-border-color-lighter);
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 16px 16px 0;
|
||||||
|
background: var(--el-fill-color-blank);
|
||||||
|
}
|
||||||
|
|
||||||
|
.deal-list-title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--el-text-color-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.deal-pagination {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -25,12 +25,12 @@
|
|||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" @click="handleSearch">查询</el-button>
|
<el-button v-permission="'sys:role'" type="primary" @click="handleSearch">查询</el-button>
|
||||||
<el-button @click="resetSearch">重置</el-button>
|
<el-button @click="resetSearch">重置</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<div class="toolbar">
|
<div class="toolbar">
|
||||||
<el-button type="primary" @click="openDrawer('create')">新增角色</el-button>
|
<el-button v-permission="'sys:role:add'" type="primary" @click="openDrawer('create')">新增角色</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
@@ -53,9 +53,9 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="操作" width="260" fixed="right">
|
<el-table-column label="操作" width="260" fixed="right">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-button type="primary" link @click="openDrawer('edit', scope.row)">编辑</el-button>
|
<el-button v-permission="'sys:role:upd'" type="primary" link @click="openDrawer('edit', scope.row)">编辑</el-button>
|
||||||
<el-button type="success" link @click="openPermissionDialog(scope.row)">配置权限</el-button>
|
<el-button v-permission="'sys:role:rolepermission'" type="success" link @click="openPermissionDialog(scope.row)">配置权限</el-button>
|
||||||
<el-button type="danger" link @click="handleDelete(scope.row)">删除</el-button>
|
<el-button v-permission="'sys:role:del'" type="danger" link @click="handleDelete(scope.row)">删除</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|||||||
@@ -142,6 +142,7 @@
|
|||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<div class="operation-actions">
|
<div class="operation-actions">
|
||||||
<el-button
|
<el-button
|
||||||
|
v-permission="'tb:goodcontrol:chooseSOP'"
|
||||||
class="flow-select-btn"
|
class="flow-select-btn"
|
||||||
:type="isFlowSelected(scope.row) ? 'success' : 'primary'"
|
:type="isFlowSelected(scope.row) ? 'success' : 'primary'"
|
||||||
:plain="isFlowSelected(scope.row)"
|
:plain="isFlowSelected(scope.row)"
|
||||||
@@ -150,10 +151,10 @@
|
|||||||
>
|
>
|
||||||
{{ isFlowSelected(scope.row) ? '已选择' : '选择' }}
|
{{ isFlowSelected(scope.row) ? '已选择' : '选择' }}
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button type="success" link @click="handleConfigWorkflow(scope.row)">编辑SOP</el-button>
|
<el-button v-permission="'tb:goodcontrol:updSOP'" type="success" link @click="handleConfigWorkflow(scope.row)">编辑SOP</el-button>
|
||||||
<el-button type="info" link @click="handleViewWorkflow(scope.row)">查看SOP</el-button>
|
<el-button v-permission="'tb:goodcontrol:viewSOP'" type="info" link @click="handleViewWorkflow(scope.row)">查看SOP</el-button>
|
||||||
<el-button type="warning" link @click="handleEditFlow(scope.row)">编辑</el-button>
|
<el-button v-permission="'tb:goodcontrol:upd'" type="warning" link @click="handleEditFlow(scope.row)">编辑</el-button>
|
||||||
<el-button type="danger" link @click="handleDeleteFlow(scope.row)">删除</el-button>
|
<el-button v-permission="'tb:goodcontrol:del'" type="danger" link @click="handleDeleteFlow(scope.row)">删除</el-button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
@@ -275,6 +276,7 @@
|
|||||||
<!-- 操作按钮区域 -->
|
<!-- 操作按钮区域 -->
|
||||||
<div class="card-footer">
|
<div class="card-footer">
|
||||||
<el-button
|
<el-button
|
||||||
|
v-permission="'tb:goodcontrol:model'"
|
||||||
v-if="device.ipAddr"
|
v-if="device.ipAddr"
|
||||||
type="info"
|
type="info"
|
||||||
size="small"
|
size="small"
|
||||||
@@ -286,6 +288,7 @@
|
|||||||
{{ Number(device.realRunModel ?? 0) === 0 ? '自动模式' : '手动模式' }}
|
{{ Number(device.realRunModel ?? 0) === 0 ? '自动模式' : '手动模式' }}
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
|
v-permission="'tb:goodcontrol:connection'"
|
||||||
v-if="device.status === 0 || device.status === undefined || device.status === null"
|
v-if="device.status === 0 || device.status === undefined || device.status === null"
|
||||||
type="success"
|
type="success"
|
||||||
size="small"
|
size="small"
|
||||||
@@ -295,6 +298,7 @@
|
|||||||
连接
|
连接
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
|
v-permission="'tb:goodcontrol:execute'"
|
||||||
v-else-if="device.status === 1"
|
v-else-if="device.status === 1"
|
||||||
type="primary"
|
type="primary"
|
||||||
size="small"
|
size="small"
|
||||||
@@ -304,6 +308,7 @@
|
|||||||
执行
|
执行
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
|
v-permission="'tb:goodcontrol:stop'"
|
||||||
v-else-if="device.status === 2"
|
v-else-if="device.status === 2"
|
||||||
type="info"
|
type="info"
|
||||||
size="small"
|
size="small"
|
||||||
@@ -314,6 +319,7 @@
|
|||||||
停止
|
停止
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
|
v-permission="'tb:goodcontrol:reset'"
|
||||||
v-else-if="device.status === 4"
|
v-else-if="device.status === 4"
|
||||||
type="danger"
|
type="danger"
|
||||||
size="small"
|
size="small"
|
||||||
|
|||||||
@@ -86,6 +86,7 @@
|
|||||||
<div v-if="!hasFlowId" class="flow-input-item flow-confirm-item">
|
<div v-if="!hasFlowId" class="flow-input-item flow-confirm-item">
|
||||||
<span class="flow-input-label"> </span>
|
<span class="flow-input-label"> </span>
|
||||||
<el-button
|
<el-button
|
||||||
|
v-permission="'data:sop:add'"
|
||||||
type="primary"
|
type="primary"
|
||||||
@click="confirmFlowInfo"
|
@click="confirmFlowInfo"
|
||||||
:loading="confirmingFlow"
|
:loading="confirmingFlow"
|
||||||
@@ -134,10 +135,10 @@
|
|||||||
</el-icon>
|
</el-icon>
|
||||||
<template #dropdown>
|
<template #dropdown>
|
||||||
<el-dropdown-menu>
|
<el-dropdown-menu>
|
||||||
<el-dropdown-item command="edit">
|
<el-dropdown-item v-permission="'tb:goodcontrolupd'" command="edit">
|
||||||
<el-icon><Edit /></el-icon>编辑
|
<el-icon><Edit /></el-icon>编辑
|
||||||
</el-dropdown-item>
|
</el-dropdown-item>
|
||||||
<el-dropdown-item command="delete" divided>
|
<el-dropdown-item v-permission="'tb:goodcontroldel'" command="delete" divided>
|
||||||
<el-icon><Delete /></el-icon>删除
|
<el-icon><Delete /></el-icon>删除
|
||||||
</el-dropdown-item>
|
</el-dropdown-item>
|
||||||
</el-dropdown-menu>
|
</el-dropdown-menu>
|
||||||
@@ -189,8 +190,8 @@
|
|||||||
<div class="action-buttons">
|
<div class="action-buttons">
|
||||||
<el-button plain @click="goFlowList">退出</el-button>
|
<el-button plain @click="goFlowList">退出</el-button>
|
||||||
<template v-if="!isViewMode">
|
<template v-if="!isViewMode">
|
||||||
<el-button type="primary" plain @click="clearWorkflow">清空</el-button>
|
<el-button v-permission="'data:sop:clear'" type="primary" plain @click="clearWorkflow">清空</el-button>
|
||||||
<el-button type="primary" @click="saveWorkflow" :loading="savingWorkflow">保存</el-button>
|
<el-button v-permission="'data:sop:save'" type="primary" @click="saveWorkflow" :loading="savingWorkflow">保存</el-button>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,532 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="user-role-page">
|
|
||||||
<el-breadcrumb separator="/" style="margin-bottom: 16px">
|
|
||||||
<el-breadcrumb-item><router-link to="/home">首页</router-link></el-breadcrumb-item>
|
|
||||||
<el-breadcrumb-item>系统管理</el-breadcrumb-item>
|
|
||||||
<el-breadcrumb-item>用户角色管理</el-breadcrumb-item>
|
|
||||||
</el-breadcrumb>
|
|
||||||
<el-card class="search-card" shadow="never">
|
|
||||||
<div class="search-bar">
|
|
||||||
<el-form :inline="true" :model="queryForm" label-width="80px">
|
|
||||||
<el-form-item label="用户">
|
|
||||||
<el-select
|
|
||||||
v-model="queryForm.userId"
|
|
||||||
filterable
|
|
||||||
clearable
|
|
||||||
placeholder="请选择用户"
|
|
||||||
style="width: 200px"
|
|
||||||
>
|
|
||||||
<el-option
|
|
||||||
v-for="item in userOptions"
|
|
||||||
:key="item.id"
|
|
||||||
:label="item.userName || item.nicke || item.nickName"
|
|
||||||
:value="item.id"
|
|
||||||
/>
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="角色">
|
|
||||||
<el-select
|
|
||||||
v-model="queryForm.roleId"
|
|
||||||
filterable
|
|
||||||
clearable
|
|
||||||
placeholder="请选择角色"
|
|
||||||
style="width: 200px"
|
|
||||||
>
|
|
||||||
<el-option
|
|
||||||
v-for="item in roleOptions"
|
|
||||||
:key="item.id"
|
|
||||||
:label="item.roleName || item.roleCode"
|
|
||||||
:value="item.id"
|
|
||||||
/>
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item>
|
|
||||||
<el-button type="primary" @click="handleSearch">查询</el-button>
|
|
||||||
<el-button @click="resetSearch">重置</el-button>
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
<div class="toolbar">
|
|
||||||
<el-button type="primary" @click="openDrawer('create')">新增用户角色关联</el-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</el-card>
|
|
||||||
|
|
||||||
<el-card shadow="never">
|
|
||||||
<el-table
|
|
||||||
:data="tableData"
|
|
||||||
stripe
|
|
||||||
border
|
|
||||||
style="width: 100%"
|
|
||||||
v-loading="loading"
|
|
||||||
>
|
|
||||||
<el-table-column type="index" label="序号" width="70" />
|
|
||||||
<el-table-column
|
|
||||||
prop="userId"
|
|
||||||
label="用户名"
|
|
||||||
min-width="150"
|
|
||||||
>
|
|
||||||
<template #default="scope">
|
|
||||||
{{ getUserName(scope.row.userId) }}
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column
|
|
||||||
prop="roleId"
|
|
||||||
label="角色名"
|
|
||||||
min-width="150"
|
|
||||||
>
|
|
||||||
<template #default="scope">
|
|
||||||
{{ getRoleName(scope.row.roleId) }}
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column
|
|
||||||
prop="remark"
|
|
||||||
label="备注"
|
|
||||||
min-width="200"
|
|
||||||
:formatter="formatCell"
|
|
||||||
/>
|
|
||||||
<el-table-column label="操作" width="120" fixed="right">
|
|
||||||
<template #default="scope">
|
|
||||||
<el-button type="danger" link @click="handleDelete(scope.row)">删除</el-button>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
</el-table>
|
|
||||||
<div class="pagination">
|
|
||||||
<el-pagination
|
|
||||||
v-model:current-page="pagination.pageNum"
|
|
||||||
v-model:page-size="pagination.pageSize"
|
|
||||||
:page-sizes="[10, 20, 50, 100]"
|
|
||||||
layout="total, sizes, prev, pager, next, jumper"
|
|
||||||
:total="total"
|
|
||||||
background
|
|
||||||
@current-change="handleCurrentChange"
|
|
||||||
@size-change="handleSizeChange"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</el-card>
|
|
||||||
|
|
||||||
<el-drawer
|
|
||||||
v-model="drawerVisible"
|
|
||||||
title="新增用户角色关联"
|
|
||||||
direction="rtl"
|
|
||||||
:size="500"
|
|
||||||
>
|
|
||||||
<el-form
|
|
||||||
ref="formRef"
|
|
||||||
:model="form"
|
|
||||||
:rules="rules"
|
|
||||||
label-width="100px"
|
|
||||||
class="drawer-form"
|
|
||||||
>
|
|
||||||
<el-form-item label="用户" prop="userId">
|
|
||||||
<el-select
|
|
||||||
v-model="form.userId"
|
|
||||||
filterable
|
|
||||||
clearable
|
|
||||||
placeholder="请选择用户"
|
|
||||||
style="width: 100%"
|
|
||||||
>
|
|
||||||
<el-option
|
|
||||||
v-for="item in userOptions"
|
|
||||||
:key="item.id"
|
|
||||||
:label="item.userName || item.nicke || item.nickName"
|
|
||||||
:value="item.id"
|
|
||||||
/>
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="角色" prop="roleId">
|
|
||||||
<el-select
|
|
||||||
v-model="form.roleId"
|
|
||||||
filterable
|
|
||||||
clearable
|
|
||||||
placeholder="请选择角色"
|
|
||||||
style="width: 100%"
|
|
||||||
>
|
|
||||||
<el-option
|
|
||||||
v-for="item in roleOptions"
|
|
||||||
:key="item.id"
|
|
||||||
:label="item.roleName || item.roleCode"
|
|
||||||
:value="item.id"
|
|
||||||
/>
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="备注">
|
|
||||||
<el-input
|
|
||||||
v-model="form.remark"
|
|
||||||
type="textarea"
|
|
||||||
placeholder="请输入备注"
|
|
||||||
:rows="3"
|
|
||||||
maxlength="200"
|
|
||||||
show-word-limit
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
<template #footer>
|
|
||||||
<div class="drawer-footer">
|
|
||||||
<el-button @click="drawerVisible = false">取消</el-button>
|
|
||||||
<el-button type="primary" :loading="submitLoading" @click="submitForm">
|
|
||||||
保存
|
|
||||||
</el-button>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</el-drawer>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { onMounted, reactive, ref } from 'vue'
|
|
||||||
import type { FormInstance, FormRules } from 'element-plus'
|
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
|
||||||
import { userRoleAdd, userRoleDel, userRoleList, userRoleByUserId } from '@/api/system/user-role'
|
|
||||||
import { userselect } from '@/api/system/user'
|
|
||||||
import { rleselect } from '@/api/system/role'
|
|
||||||
|
|
||||||
interface UserRoleItem {
|
|
||||||
id?: number | string
|
|
||||||
userId: number | string
|
|
||||||
roleId: number | string
|
|
||||||
remark?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
interface UserItem {
|
|
||||||
id: number | string
|
|
||||||
userName?: string
|
|
||||||
nicke?: string
|
|
||||||
nickName?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
interface RoleItem {
|
|
||||||
id: number | string
|
|
||||||
roleName?: string
|
|
||||||
roleCode?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
const loading = ref(false)
|
|
||||||
const submitLoading = ref(false)
|
|
||||||
const tableData = ref<UserRoleItem[]>([])
|
|
||||||
const total = ref(0)
|
|
||||||
const userOptions = ref<UserItem[]>([])
|
|
||||||
const roleOptions = ref<RoleItem[]>([])
|
|
||||||
const userMap = ref<Map<number | string, string>>(new Map())
|
|
||||||
const roleMap = ref<Map<number | string, string>>(new Map())
|
|
||||||
|
|
||||||
const queryForm = reactive({
|
|
||||||
userId: null as number | string | null,
|
|
||||||
roleId: null as number | string | null,
|
|
||||||
})
|
|
||||||
|
|
||||||
const pagination = reactive({
|
|
||||||
pageNum: 1,
|
|
||||||
pageSize: 10,
|
|
||||||
})
|
|
||||||
|
|
||||||
const drawerVisible = ref(false)
|
|
||||||
|
|
||||||
const formRef = ref<FormInstance>()
|
|
||||||
const form = reactive<UserRoleItem>({
|
|
||||||
userId: '',
|
|
||||||
roleId: '',
|
|
||||||
remark: '',
|
|
||||||
})
|
|
||||||
|
|
||||||
const rules: FormRules = {
|
|
||||||
userId: [{ required: true, message: '请选择用户', trigger: 'change' }],
|
|
||||||
roleId: [{ required: true, message: '请选择角色', trigger: 'change' }],
|
|
||||||
}
|
|
||||||
|
|
||||||
const resetForm = () => {
|
|
||||||
form.userId = ''
|
|
||||||
form.roleId = ''
|
|
||||||
form.remark = ''
|
|
||||||
formRef.value?.clearValidate()
|
|
||||||
}
|
|
||||||
|
|
||||||
const formatCell = (_row: any, _column: any, value: any) => {
|
|
||||||
if (value === 0) return 0
|
|
||||||
return value === undefined || value === null || value === '' ? '暂无' : value
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取用户名
|
|
||||||
const getUserName = (userId: number | string | null | undefined) => {
|
|
||||||
if (!userId) return '暂无'
|
|
||||||
return userMap.value.get(userId) || '暂无'
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取角色名
|
|
||||||
const getRoleName = (roleId: number | string | null | undefined) => {
|
|
||||||
if (!roleId) return '暂无'
|
|
||||||
return roleMap.value.get(roleId) || '暂无'
|
|
||||||
}
|
|
||||||
|
|
||||||
// 加载用户列表
|
|
||||||
const loadUsers = async () => {
|
|
||||||
try {
|
|
||||||
const res: any = await userselect({})
|
|
||||||
const data = Array.isArray(res?.data) ? res.data : Array.isArray(res) ? res : []
|
|
||||||
userOptions.value = data
|
|
||||||
userMap.value.clear()
|
|
||||||
data.forEach((user: UserItem) => {
|
|
||||||
if (user.id) {
|
|
||||||
const userName = user.userName || user.nicke || user.nickName || ''
|
|
||||||
userMap.value.set(user.id, userName)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} catch (error) {
|
|
||||||
console.error('load user list error', error)
|
|
||||||
ElMessage.error('加载用户列表失败')
|
|
||||||
userOptions.value = []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 加载角色列表
|
|
||||||
const loadRoles = async () => {
|
|
||||||
try {
|
|
||||||
const res: any = await rleselect({})
|
|
||||||
const data = Array.isArray(res?.data) ? res.data : Array.isArray(res) ? res : []
|
|
||||||
roleOptions.value = data
|
|
||||||
roleMap.value.clear()
|
|
||||||
data.forEach((role: RoleItem) => {
|
|
||||||
if (role.id) {
|
|
||||||
const roleName = role.roleName || role.roleCode || ''
|
|
||||||
roleMap.value.set(role.id, roleName)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} catch (error) {
|
|
||||||
console.error('load role list error', error)
|
|
||||||
ElMessage.error('加载角色列表失败')
|
|
||||||
roleOptions.value = []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 加载用户角色关联列表
|
|
||||||
const loadList = async () => {
|
|
||||||
loading.value = true
|
|
||||||
try {
|
|
||||||
// 确保用户和角色列表已加载
|
|
||||||
if (userOptions.value.length === 0) {
|
|
||||||
await loadUsers()
|
|
||||||
}
|
|
||||||
if (roleOptions.value.length === 0) {
|
|
||||||
await loadRoles()
|
|
||||||
}
|
|
||||||
|
|
||||||
const params: any = {
|
|
||||||
pageNum: pagination.pageNum,
|
|
||||||
pageSize: pagination.pageSize,
|
|
||||||
}
|
|
||||||
if (queryForm.userId) {
|
|
||||||
params.userId = queryForm.userId
|
|
||||||
}
|
|
||||||
if (queryForm.roleId) {
|
|
||||||
params.roleId = queryForm.roleId
|
|
||||||
}
|
|
||||||
|
|
||||||
const res: any = await userRoleList(params)
|
|
||||||
|
|
||||||
console.log('用户角色关联列表API返回数据:', res)
|
|
||||||
|
|
||||||
let pageData = res?.data
|
|
||||||
|
|
||||||
if (!pageData && (res?.records || res?.total !== undefined)) {
|
|
||||||
pageData = res
|
|
||||||
}
|
|
||||||
|
|
||||||
const recordsFromData =
|
|
||||||
pageData?.records ||
|
|
||||||
pageData?.list ||
|
|
||||||
pageData?.rows ||
|
|
||||||
pageData?.items ||
|
|
||||||
(Array.isArray(pageData?.data) ? pageData.data : undefined)
|
|
||||||
|
|
||||||
const records = Array.isArray(recordsFromData)
|
|
||||||
? recordsFromData
|
|
||||||
: Array.isArray(pageData)
|
|
||||||
? pageData
|
|
||||||
: Array.isArray(res?.data)
|
|
||||||
? res.data
|
|
||||||
: []
|
|
||||||
|
|
||||||
const totalValue =
|
|
||||||
pageData?.total ??
|
|
||||||
pageData?.count ??
|
|
||||||
pageData?.totalCount ??
|
|
||||||
res?.total ??
|
|
||||||
(Array.isArray(records) ? records.length : 0)
|
|
||||||
|
|
||||||
tableData.value = records
|
|
||||||
total.value = Number(totalValue) || 0
|
|
||||||
|
|
||||||
console.log('解析后的数据:', {
|
|
||||||
records: records.length,
|
|
||||||
total: total.value,
|
|
||||||
firstRecord: records[0],
|
|
||||||
})
|
|
||||||
} catch (error: any) {
|
|
||||||
console.error('load user role list error', error)
|
|
||||||
const errorMsg = error?.message || error?.msg || '加载用户角色关联列表失败'
|
|
||||||
ElMessage.error(errorMsg)
|
|
||||||
tableData.value = []
|
|
||||||
total.value = 0
|
|
||||||
} finally {
|
|
||||||
loading.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleSearch = () => {
|
|
||||||
pagination.pageNum = 1
|
|
||||||
loadList()
|
|
||||||
}
|
|
||||||
|
|
||||||
const resetSearch = () => {
|
|
||||||
queryForm.userId = null
|
|
||||||
queryForm.roleId = null
|
|
||||||
handleSearch()
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleSizeChange = (size: number) => {
|
|
||||||
pagination.pageSize = size
|
|
||||||
loadList()
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleCurrentChange = (page: number) => {
|
|
||||||
pagination.pageNum = page
|
|
||||||
loadList()
|
|
||||||
}
|
|
||||||
|
|
||||||
const openDrawer = async (mode: 'create') => {
|
|
||||||
resetForm()
|
|
||||||
drawerVisible.value = true
|
|
||||||
|
|
||||||
// 加载用户和角色数据
|
|
||||||
await Promise.all([loadUsers(), loadRoles()])
|
|
||||||
}
|
|
||||||
|
|
||||||
const submitForm = () => {
|
|
||||||
formRef.value?.validate(async (valid) => {
|
|
||||||
if (!valid) return
|
|
||||||
|
|
||||||
// 检查用户是否已拥有该角色
|
|
||||||
try {
|
|
||||||
const res: any = await userRoleByUserId(form.userId)
|
|
||||||
const data = res?.data ?? res ?? {}
|
|
||||||
|
|
||||||
// 兼容多种返回格式
|
|
||||||
const userRoles = Array.isArray(data)
|
|
||||||
? data
|
|
||||||
: Array.isArray(data.data)
|
|
||||||
? data.data
|
|
||||||
: Array.isArray(data.records)
|
|
||||||
? data.records
|
|
||||||
: Array.isArray(data.list)
|
|
||||||
? data.list
|
|
||||||
: []
|
|
||||||
|
|
||||||
// 检查是否已存在该角色关联
|
|
||||||
const existingRole = userRoles.find((item: any) => item.roleId === form.roleId)
|
|
||||||
|
|
||||||
if (existingRole) {
|
|
||||||
// 获取用户名和角色名
|
|
||||||
const userName = getUserName(form.userId)
|
|
||||||
const roleName = getRoleName(form.roleId)
|
|
||||||
ElMessage.warning(`用户【${userName}】已拥有【${roleName}】角色,无需重复分配`)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} catch (error: any) {
|
|
||||||
console.error('check user role error', error)
|
|
||||||
// 如果检查失败,继续执行新增操作,让后端处理重复情况
|
|
||||||
}
|
|
||||||
|
|
||||||
submitLoading.value = true
|
|
||||||
try {
|
|
||||||
const payload: any = {
|
|
||||||
userId: form.userId,
|
|
||||||
roleId: form.roleId,
|
|
||||||
remark: form.remark || '',
|
|
||||||
}
|
|
||||||
|
|
||||||
await userRoleAdd(payload)
|
|
||||||
ElMessage.success('新增成功')
|
|
||||||
drawerVisible.value = false
|
|
||||||
loadList()
|
|
||||||
} catch (error: any) {
|
|
||||||
console.error('submit user role error', error)
|
|
||||||
const errorMsg = error?.message || error?.msg || '新增失败'
|
|
||||||
ElMessage.error(errorMsg)
|
|
||||||
} finally {
|
|
||||||
submitLoading.value = false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleDelete = (row: UserRoleItem) => {
|
|
||||||
if (!row.id) {
|
|
||||||
ElMessage.warning('缺少关联ID')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const userName = getUserName(row.userId)
|
|
||||||
const roleName = getRoleName(row.roleId)
|
|
||||||
ElMessageBox.confirm(`确认删除用户「${userName}」与角色「${roleName}」的关联吗?`, '提示', {
|
|
||||||
type: 'warning',
|
|
||||||
})
|
|
||||||
.then(async () => {
|
|
||||||
if (row.id == null) {
|
|
||||||
ElMessage.warning('缺少关联ID,无法删除')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
await userRoleDel(row.id)
|
|
||||||
ElMessage.success('删除成功')
|
|
||||||
loadList()
|
|
||||||
} catch (error: any) {
|
|
||||||
console.error('delete user role error', error)
|
|
||||||
const errorMsg = error?.message || error?.msg || '删除失败'
|
|
||||||
ElMessage.error(errorMsg)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(() => {})
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
loadUsers()
|
|
||||||
loadRoles()
|
|
||||||
loadList()
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.user-role-page {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-card {
|
|
||||||
padding-bottom: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-bar {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.toolbar {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pagination {
|
|
||||||
margin-top: 16px;
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
}
|
|
||||||
|
|
||||||
.drawer-footer {
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
gap: 10px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
@@ -17,12 +17,12 @@
|
|||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" @click="handleSearch">查询</el-button>
|
<el-button v-permission="'sys:user'" type="primary" @click="handleSearch">查询</el-button>
|
||||||
<el-button @click="resetSearch">重置</el-button>
|
<el-button @click="resetSearch">重置</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<div class="toolbar">
|
<div class="toolbar">
|
||||||
<el-button type="primary" @click="openDrawer('create')">新增用户</el-button>
|
<el-button v-permission="'sys:user:add'" type="primary" @click="openDrawer('create')">新增用户</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
@@ -92,9 +92,9 @@
|
|||||||
/>
|
/>
|
||||||
<el-table-column label="操作" width="250" fixed="right">
|
<el-table-column label="操作" width="250" fixed="right">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-button type="primary" link @click="openDrawer('edit', scope.row)">编辑</el-button>
|
<el-button v-permission="'sys:user:upd'" type="primary" link @click="openDrawer('edit', scope.row)">编辑</el-button>
|
||||||
<el-button type="success" link @click="openRoleDialog(scope.row)">分配角色</el-button>
|
<el-button v-permission="'sys:user:userrole'" type="success" link @click="openRoleDialog(scope.row)">分配角色</el-button>
|
||||||
<el-button type="danger" link @click="handleDelete(scope.row)">删除</el-button>
|
<el-button v-permission="'sys:user:del'" type="danger" link @click="handleDelete(scope.row)">删除</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|||||||
Reference in New Issue
Block a user