import { runLogic } from '@af-mobile-client-vue3/services/api/common' import { isWechat } from '@af-mobile-client-vue3/utils/platform-auth' import DrivingConfig from '@af-mobile-client-vue3/views/component/Driving/index.vue' import { createApp } from 'vue' /** * 功能角色配置接口 * 用于定义某个功能基于用户角色的启用条件 */ export interface FeatureRoleConfig { /** 是否启用该功能的总开关 */ enabled: boolean /** 命中即禁用(最高优先级)- 如果用户拥有这些角色之一,则禁用功能 */ denyRoles?: string[] /** 必须具备的角色(全部满足)- 用户必须拥有所有这些角色才能启用功能 */ mustRoles?: string[] /** 至少命中一个即可 - 用户至少拥有这些角色之一即可启用功能 */ maybeRoles?: string[] /** 字段说明,不参与逻辑 - 用于文档或注释 */ __comment?: Record } /** * 根据角色配置判断功能是否可用 * 该函数根据提供的角色配置和用户角色字符串,判断用户是否可以启用某个功能 * 逻辑优先级:总开关 > 禁止角色 > 必须角色 > 可选角色 * @param config 功能角色配置对象 * @param roleStr 用户角色字符串(逗号分隔的角色列表) * @returns 如果功能可用返回 true,否则返回 false */ export function canEnableFeatureByRoleStr( config: FeatureRoleConfig, roleStr: string, ): boolean { // 如果配置为空或未定义,直接返回 false if (config === undefined || config === null) { return false } // 1️⃣ 总开关 - 如果功能未启用,直接返回 false if (!config?.enabled) { return false } // 2️⃣ 将角色字符串转成数组(去空格并过滤空值) const userRoles = roleStr .split(',') .map(r => r.trim()) .filter(Boolean) // 3️⃣ 禁止角色检查(最高优先级)- 如果用户拥有任何禁止角色,则禁用功能 if (config.denyRoles?.some(role => userRoles.includes(role))) { return false } // 4️⃣ 必须角色检查(必须全部满足)- 用户必须拥有所有必须角色 if ( config.mustRoles?.length && !config.mustRoles.every(role => userRoles.includes(role)) ) { return false } // 5️⃣ 可选角色检查(至少命中一个)- 用户至少拥有一个可选角色 if ( config.maybeRoles?.length && !config.maybeRoles.some(role => userRoles.includes(role)) ) { return false } // 所有条件满足,返回 true return true } /** * 处理驾驶配置提交的回调函数 * 当用户在弹窗中提交驾驶配置数据时,调用此函数保存数据并更新用户状态 * @param data 用户提交的驾驶配置数据 * @param userState */ export async function handleDrivingConfigSubmit(data: any, userState: any) { // console.warn('>>> handleDrivingConfigSubmit', data, userState) // 调用后端逻辑保存用户驾驶信息 await runLogic('saveUserDrivingInfoLogic', { ...data, userId: userState.getUserInfo().id }, 'af-linepatrol') // 获取当前用户信息 const currentUserInfo = userState.getUserInfo() // 更新用户信息,将驾驶信息合并到用户状态中 userState.setUserInfo({ ...currentUserInfo, drivingInfo: data }) } /** * 检查并初始化驾驶配置 * 该函数检查当前环境和用户角色是否支持驾驶功能,如果支持且用户未配置驾驶信息,则打开配置弹窗 * 主要用于应用启动时或需要时初始化驾驶相关设置 */ export async function checkAndInitDrivingConfig(userState: any) { // 检查环境条件:不是微信环境且兼容模式不是OA if (!isWechat() && import.meta.env.VITE_APP_COMPATIBLE !== 'OA') { // console.warn('>>> userState', userState) // 调试日志 // 获取驾驶配置(角色权限等) const drivingConfig: any = await runLogic('getLiuliConfiguration', { configName: 'DrivingConfig' }, 'af-system') // 根据配置和用户角色判断是否启用驾驶功能 const isDriving = canEnableFeatureByRoleStr(drivingConfig, userState.getUserInfo().rolestr || userState.getUserInfo().rolestr.rolesnames || '') if (isDriving) { // 获取用户的驾驶信息 const drivingInfoRes: any = await runLogic('getUserDrivingInfoLogic', { userId: userState.getUserInfo().id }, 'af-linepatrol') const drivingInfo = JSON.parse(drivingInfoRes.value) // console.warn('>>>drivingInfoRes', drivingInfoRes) // 调试日志 // console.warn('>>>drivingInfo', drivingInfo) // 调试日志 // 如果驾驶信息为空,说明用户未配置,需要打开配置弹窗 if (drivingInfo === null || Object.keys(drivingInfo).length === 0) { // 打开配置弹窗,并传入提交处理函数 openDrivingConfigPopup() } else { // 如果用户已配置驾驶信息,则更新用户状态 userState.setUserInfo({ ...userState.getUserInfo(), drivingInfo }) // console.warn('用户已配置驾驶信息,则更新用户状态>>>userinfo', userState.getUserInfo()) } } } } /** * 打开驾驶配置弹窗 * 该函数动态创建并显示驾驶配置弹窗组件,监听用户的提交和关闭事件 * 当用户提交数据时,调用传入的回调函数;当用户关闭弹窗时,卸载组件 */ export function openDrivingConfigPopup() { // 创建Vue应用实例,传入弹窗组件和事件监听器 const app = createApp(DrivingConfig, { 'visible': true, // 设置弹窗初始显示 // 监听自定义事件:onSubmit(data, userState) // 对应组件中 emit('onSubmit', data, userState) 'onOnSubmit': async (data: any, userState: any) => { // 监听提交事件,调用回调函数并卸载组件 await handleDrivingConfigSubmit(data, userState) app.unmount() }, // 监听 v-model:visible 对应的 update:visible 事件 'onUpdate:visible': (visible: boolean) => { // 监听弹窗显示状态变化,如果隐藏则卸载组件 if (!visible) { app.unmount() } }, }) // 创建临时DOM元素作为挂载点 const div = document.createElement('div') // 将临时元素添加到页面body中 document.body.appendChild(div) // 将Vue应用挂载到临时元素上 app.mount(div) }