页面按钮权限

This commit is contained in:
huhao
2026-08-11 11:30:27 +08:00
parent d1d3636cf1
commit 94ec5e65ca
8 changed files with 148 additions and 59 deletions
+8 -5
View File
@@ -38,7 +38,7 @@
<view v-for="(item, index) in listData" :key="item.TempDetailId || index" class="card-item audit-card"
@click="handleItemClick(item)">
<!-- 勾选框 -->
<view class="check-circle" :class="{ 'check-circle--checked': isSelected(item) }"
<view v-if="canEdit" class="check-circle" :class="{ 'check-circle--checked': isSelected(item) }"
@click.stop="toggleSelect(item)">
<u-icon v-if="isSelected(item)" name="checkmark" :size="24" color="#fff" />
</view>
@@ -82,7 +82,7 @@
</scroll-view>
<!-- 底部批量操作栏 -->
<view class="audit-bar">
<view v-if="canEdit" class="audit-bar">
<view class="audit-bar__all" @click="handleToggleAll">
<view class="check-circle" :class="{ 'check-circle--checked': isAllSelected }">
<u-icon v-if="isAllSelected" name="checkmark" :size="24" color="#fff" />
@@ -117,7 +117,8 @@
storeToRefs
} from 'pinia'
import {
useUserStore
useUserStore,
useMenuStore
} from '@/store'
import {
reqProjectWorkArea
@@ -129,10 +130,12 @@
} from '@/api/hj.js'
const userStore = useUserStore()
const menuStore = useMenuStore()
const {
currentProject,
userInfo
userInfo,
currentProject
} = storeToRefs(userStore)
const canEdit = computed(() => menuStore.canEditFunc('dailyAudit'))
// ===== 筛选条件 =====
const pipelineCode = ref('')
+7 -3
View File
@@ -125,7 +125,7 @@
</view>
<!-- 底部按钮 -->
<view class="bottom-btns">
<view v-if="canEdit" class="bottom-btns">
<u-button class="btn-delete" size="medium" type="error" @click="handleDelete">删除</u-button>
<u-button class="btn-audit" size="medium" type="primary" @click="handleAudit">审核通过</u-button>
</view>
@@ -134,13 +134,15 @@
<script setup>
import {
ref
ref,
computed
} from 'vue'
import {
onLoad
} from '@dcloudio/uni-app'
import {
useUserStore
useUserStore,
useMenuStore
} from '@/store'
import {
reqPendingWeldingDailyDetail,
@@ -149,9 +151,11 @@
} from '@/api/hj.js'
const userStore = useUserStore()
const menuStore = useMenuStore()
const {
userInfo
} = userStore
const canEdit = computed(() => menuStore.canEditFunc('dailyAudit'))
const tempDetailId = ref('')
const form = ref({})
+10 -4
View File
@@ -155,9 +155,9 @@
<!-- 底部按钮 -->
<view class="bottom-btns">
<u-button v-if="!form.WeldingDate" class="btn-submit" size="medium" type="primary"
<u-button v-if="canEdit && !form.WeldingDate" class="btn-submit" size="medium" type="primary"
@click="handleReport">填报</u-button>
<u-button v-if="form.WeldingDailyId" class="btn-point" size="medium" type="primary"
<u-button v-if="canEdit && form.WeldingDailyId" class="btn-point" size="medium" type="primary"
@click="handlePoint">点口</u-button>
<u-button class="btn-cancel" size="medium" @click="handleClose">取消</u-button>
</view>
@@ -173,15 +173,17 @@
</template>
<script setup>
import { ref } from 'vue'
import { ref, computed } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { reqGetWeldJointByWeldJointId, reqSaveWeldingDailyByWeldJointId, reqGetManualPointSave, reqFitupCheckByWeldJointId } from '@/api/hj.js'
import { reqWeldingLocation } from '@/api/base.js'
import { useUserStore } from '@/store'
import { useUserStore, useMenuStore } from '@/store'
const userStore = useUserStore()
const menuStore = useMenuStore()
const { userInfo } = userStore
const canEdit = computed(() => menuStore.canEditFunc('dailyPaper'))
// ===== 表单数据 =====
const form = ref({})
@@ -252,6 +254,10 @@ const handlePoint = async () => {
}
const handleReport = () => {
if (!canEdit.value) {
uni.showToast({ title: '当前岗位仅可查看', icon: 'none' })
return
}
uni.showModal({
title: '信息提示',
content: '确定要填报吗?',
+9 -3
View File
@@ -168,7 +168,7 @@
<nbd-submit-bar text="提交" :loading="submitting" @click="handleSubmit" />
<nbd-submit-bar v-if="canEdit" text="提交" :loading="submitting" @click="handleSubmit" />
</view>
<nbd-select v-model="showPaintCodePicker" title="选择防腐等级" :list="paintCodeList" label-key="PaintCode" value-key="Id"
@@ -176,11 +176,11 @@
</template>
<script setup>
import { ref } from 'vue'
import { ref, computed } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { storeToRefs } from 'pinia'
import { watch, nextTick } from 'vue'
import { useUserStore } from '@/store'
import { useUserStore, useMenuStore } from '@/store'
import { reqMaterialInfoByMaterialCode, reqPaintCodeList, reqSaveAntiCorrosionCheck, reqGetAntiCorrosionCheck } from '@/api/hj.js'
// 防腐记录字段
@@ -202,7 +202,9 @@ const antiFields = [
const antiList = ref([])
const userStore = useUserStore()
const menuStore = useMenuStore()
const { userInfo, currentProject } = storeToRefs(userStore)
const canEdit = computed(() => menuStore.canEditFunc('antiRust'))
const form = ref({})
const showPaintCodePicker = ref(false)
const paintCodeList = ref([])
@@ -307,6 +309,10 @@ const loadData = async (id) => {
// 提交
const handleSubmit = async () => {
if (!canEdit.value) {
uni.showToast({ title: '当前岗位仅可查看', icon: 'none' })
return
}
if (!antiForm.value.PaintId) {
uni.showToast({ title: '请选择防腐等级', icon: 'none' })
return
+9 -3
View File
@@ -160,7 +160,7 @@
</block>
<!-- 提交按钮 -->
<view class="submit-bar">
<view v-if="canEdit" class="submit-bar">
<view class="btn-primary-gradient" @click="handleSubmit">
<text class="btn-primary-gradient__text">提交结果</text>
</view>
@@ -172,10 +172,10 @@
</template>
<script setup>
import { ref, watch, nextTick } from 'vue'
import { ref, watch, nextTick, computed } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { storeToRefs } from 'pinia'
import { useUserStore } from '@/store'
import { useUserStore, useMenuStore } from '@/store'
import { reqPreWeldJointByWeldJointId, reqSaveFitupCheck, reqCuttingCheckByWeldJointId, reqFitupCheckByWeldJointId } from '@/api/hj'
import { reqGetGrooveTypeList } from '@/api/base'
@@ -209,7 +209,9 @@ const cuttingList = ref([])
const fitupList = ref([])
const userStore = useUserStore()
const menuStore = useMenuStore()
const { userInfo, currentProject } = storeToRefs(userStore)
const canEdit = computed(() => menuStore.canEditFunc('makeRight'))
const info = ref({})
const remark = ref('')
@@ -256,6 +258,10 @@ const handleMutualCheck = () => {
uni.navigateTo({ url: '/scanpages/hj/material_sampling?id=' + id.value })
}
const handleSubmit = () => {
if (!canEdit.value) {
uni.showToast({ title: '当前岗位仅可查看', icon: 'none' })
return
}
uni.showModal({
title: '确认提交',
content: '确定提交吗?',
+9 -3
View File
@@ -169,7 +169,7 @@
</block>
<!-- 提交按钮 -->
<view class="submit-bar">
<view v-if="canEdit" class="submit-bar">
<view class="btn-primary-gradient" @click="handleSubmit">
<text class="btn-primary-gradient__text">提交结果</text>
</view>
@@ -178,10 +178,10 @@
</template>
<script setup>
import { ref, watch, nextTick } from 'vue'
import { ref, watch, nextTick, computed } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { storeToRefs } from 'pinia'
import { useUserStore } from '@/store'
import { useUserStore, useMenuStore } from '@/store'
import { reqPreWeldJointByWeldJointId, reqSaveCuttingCheck, reqCuttingCheckByWeldJointId, reqGetAntiCorrosionCheck } from '@/api/hj'
@@ -217,7 +217,9 @@ const cuttingList = ref([])
const antiListMap = ref({})
const userStore = useUserStore()
const menuStore = useMenuStore()
const { userInfo, currentProject } = storeToRefs(userStore)
const canEdit = computed(() => menuStore.canEditFunc('sampling'))
const info = ref({})
const remark = ref('')
@@ -259,6 +261,10 @@ watch(() => layingOffForm.value.CheckResult, async (val) => {
})
const handleSubmit = () => {
if (!canEdit.value) {
uni.showToast({ title: '当前岗位仅可查看', icon: 'none' })
return
}
uni.showModal({
title: '确认提交',
content: '确定提交吗?',
+36 -11
View File
@@ -36,22 +36,36 @@ export const useMenuStore = defineStore('menu', () => {
const menuProwerList = ref([])
/**
* 岗位权限校验:现场人员(UserType=3)按 WorkPostName 硬编码限制(见 constant.js postMenuPermissions),
* 其余用户不限制
* @param {string} funcKey 功能 key;空表示非扫码类菜单(pipe 管理应用),对现场人员一律隐藏
* 取岗位某功能的数据权限级别(仅按 WorkPostName)
* @returns {'view'|'edit'|null} null 表示无菜单权限
* - WorkPostName 在权限表中:按表配置
* - 不在表中:不限制(edit)
*/
const hasPostPermission = (funcKey) => {
const getPostFuncLevel = (funcKey) => {
if (!funcKey) return null
const userStore = useUserStore()
const info = userStore.userInfo
if (String(info?.UserType) !== '3') return true
if (!funcKey) return false
const allows = postMenuPermissions[info?.WorkPostName]
return !!allows && allows.includes(funcKey)
const postName = String(userStore.userInfo?.WorkPostName || '').trim()
const map = postMenuPermissions[postName]
if (!map) return 'edit'
return map[funcKey] || null
}
/**
* 岗位菜单权限(仅按 WorkPostName)
* @param {string} funcKey 功能 key;空表示非扫码类(pipe),不按岗位拦截,走后端 menuId
*/
const hasPostPermission = (funcKey) => {
if (!funcKey) return true
return !!getPostFuncLevel(funcKey)
}
/**
* 岗位数据权限:是否可编辑(提交/保存);仅可查看时返回 false
*/
const canEditFunc = (funcKey) => getPostFuncLevel(funcKey) === 'edit'
/**
* 校验扫码跳转的页面路径是否有岗位权限(非扫码类路径不限制)
* @param {string} path 页面路径
*/
const canAccessPath = (path) => {
const funcKey = scanPathFuncKeyMap[path]
@@ -59,6 +73,15 @@ export const useMenuStore = defineStore('menu', () => {
return hasPostPermission(funcKey)
}
/**
* 校验页面路径是否可编辑
*/
const canEditPath = (path) => {
const funcKey = scanPathFuncKeyMap[path]
if (!funcKey) return true
return canEditFunc(funcKey)
}
// 应用是否可见:后端菜单权限 + 岗位权限双重过滤
const appVisible = (app) => hasMenuPermission(app.menuId) && hasPostPermission(app.funcKey)
@@ -131,7 +154,9 @@ export const useMenuStore = defineStore('menu', () => {
fetchMenuPowerList,
hasMenuPermission,
hasPostPermission,
canAccessPath
canEditFunc,
canAccessPath,
canEditPath
}
}, {
persist: {
+60 -27
View File
@@ -91,35 +91,68 @@ export const defaultApps = [{
}
]
// 扫码类功能 key:sampling 下料抽检 / makeRight 组对抽查 / antiRust 防腐处理 / dailyPaper 焊接日报 / dailyAudit 日报审核
const ALL_SCAN_FUNCS = ['sampling', 'makeRight', 'antiRust', 'dailyPaper']
// 管理/技术岗位在 4 个扫码功能之外,额外拥有日报审核
const MANAGE_SCAN_FUNCS = [...ALL_SCAN_FUNCS, 'dailyAudit']
// 数据权限:view 可查看 / edit 可编辑
const VIEW = 'view'
const EDIT = 'edit'
// 现场人员(UserType=3)岗位菜单权限,小程序端硬编码(来源:requests/权限.xlsx)
// 未列出的岗位默认无任何扫码类菜单权限;pipe 管理类应用(无 funcKey)对现场人员一律隐藏
// 扫码类功能:sampling 下料 / makeRight 组对 / antiRust 防腐 / dailyPaper 日报
// 扩展:dailyAudit 日报审核
const ALL_VIEW = {
sampling: VIEW,
makeRight: VIEW,
antiRust: VIEW,
dailyPaper: VIEW,
dailyAudit: VIEW,
}
const ALL_EDIT = {
sampling: EDIT,
makeRight: EDIT,
antiRust: EDIT,
dailyPaper: EDIT,
dailyAudit: EDIT,
}
// 岗位权限,仅按 WorkPostName 硬编码(来源:岗位权限表)
// value 为 { [funcKey]: 'view'|'edit' };未列出的岗位不限制扫码类功能
// pipe 管理类应用(无 funcKey)不按岗位拦截,由后端 menuId 控制
export const postMenuPermissions = {
'项目经理': MANAGE_SCAN_FUNCS,
'项目总工': MANAGE_SCAN_FUNCS,
'控制经理': MANAGE_SCAN_FUNCS,
'安环经理': MANAGE_SCAN_FUNCS,
'质量经理': MANAGE_SCAN_FUNCS,
'材料部长': MANAGE_SCAN_FUNCS,
'防腐工程师': MANAGE_SCAN_FUNCS,
'费控工程师': MANAGE_SCAN_FUNCS,
'物流工程师': MANAGE_SCAN_FUNCS,
'管道工程师': MANAGE_SCAN_FUNCS,
'包装工程师': MANAGE_SCAN_FUNCS,
'项目信息员': MANAGE_SCAN_FUNCS,
'材料员': MANAGE_SCAN_FUNCS,
'资料员': MANAGE_SCAN_FUNCS,
'技术员': MANAGE_SCAN_FUNCS,
'质量员': MANAGE_SCAN_FUNCS,
'施工员': MANAGE_SCAN_FUNCS,
'焊工': ['sampling', 'makeRight', 'dailyPaper'],
'管工': ALL_SCAN_FUNCS,
'防腐工': ['antiRust'],
'无损检测工': ['dailyPaper'],
// —— 全部菜单 · 可查看 ——
'项目经理': ALL_VIEW,
'项目总工': ALL_VIEW,
'控制经理': ALL_VIEW,
'安环经理': ALL_VIEW,
'材料部长': ALL_VIEW,
'防腐工程师': ALL_VIEW,
'费控工程师': ALL_VIEW,
'物流工程师': ALL_VIEW,
'包装工程师': ALL_VIEW,
'材料员': ALL_VIEW,
'资料员': ALL_VIEW,
// —— 全部菜单 · 可编辑 ——
'质量经理': ALL_EDIT,
'管道工程师': ALL_EDIT,
'项目信息员': ALL_EDIT,
'技术员': ALL_EDIT,
'质量员': ALL_EDIT,
'施工员': ALL_EDIT,
// —— 现场工种(细粒度)——
'焊工': {
sampling: VIEW,
makeRight: VIEW,
dailyPaper: EDIT,
},
'管工': {
sampling: EDIT,
makeRight: EDIT,
antiRust: VIEW,
dailyPaper: VIEW,
},
'防腐工': {
antiRust: EDIT,
},
'无损检测工': {
dailyPaper: VIEW,
},
}
// 扫码类页面路径 → 功能 key(用于扫码跳转前的岗位权限校验)