af-mobile-client-vue3 1.4.92 → 1.4.94
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { runLogic } from '@af-mobile-client-vue3/services/api/common'
|
|
2
|
+
import { isWechat } from '@af-mobile-client-vue3/utils/platform-auth'
|
|
3
|
+
import DrivingConfig from '@af-mobile-client-vue3/views/component/Driving/index.vue'
|
|
4
|
+
import { createApp } from 'vue'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 功能角色配置接口
|
|
8
|
+
* 用于定义某个功能基于用户角色的启用条件
|
|
9
|
+
*/
|
|
10
|
+
export interface FeatureRoleConfig {
|
|
11
|
+
/** 是否启用该功能的总开关 */
|
|
12
|
+
enabled: boolean
|
|
13
|
+
|
|
14
|
+
/** 命中即禁用(最高优先级)- 如果用户拥有这些角色之一,则禁用功能 */
|
|
15
|
+
denyRoles?: string[]
|
|
16
|
+
|
|
17
|
+
/** 必须具备的角色(全部满足)- 用户必须拥有所有这些角色才能启用功能 */
|
|
18
|
+
mustRoles?: string[]
|
|
19
|
+
|
|
20
|
+
/** 至少命中一个即可 - 用户至少拥有这些角色之一即可启用功能 */
|
|
21
|
+
maybeRoles?: string[]
|
|
22
|
+
|
|
23
|
+
/** 字段说明,不参与逻辑 - 用于文档或注释 */
|
|
24
|
+
__comment?: Record<string, string>
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* 根据角色配置判断功能是否可用
|
|
28
|
+
* 该函数根据提供的角色配置和用户角色字符串,判断用户是否可以启用某个功能
|
|
29
|
+
* 逻辑优先级:总开关 > 禁止角色 > 必须角色 > 可选角色
|
|
30
|
+
* @param config 功能角色配置对象
|
|
31
|
+
* @param roleStr 用户角色字符串(逗号分隔的角色列表)
|
|
32
|
+
* @returns 如果功能可用返回 true,否则返回 false
|
|
33
|
+
*/
|
|
34
|
+
export function canEnableFeatureByRoleStr(
|
|
35
|
+
config: FeatureRoleConfig,
|
|
36
|
+
roleStr: string,
|
|
37
|
+
): boolean {
|
|
38
|
+
// 如果配置为空或未定义,直接返回 false
|
|
39
|
+
if (config === undefined || config === null) {
|
|
40
|
+
return false
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// 1️⃣ 总开关 - 如果功能未启用,直接返回 false
|
|
44
|
+
if (!config?.enabled) {
|
|
45
|
+
return false
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// 2️⃣ 将角色字符串转成数组(去空格并过滤空值)
|
|
49
|
+
const userRoles = roleStr
|
|
50
|
+
.split(',')
|
|
51
|
+
.map(r => r.trim())
|
|
52
|
+
.filter(Boolean)
|
|
53
|
+
|
|
54
|
+
// 3️⃣ 禁止角色检查(最高优先级)- 如果用户拥有任何禁止角色,则禁用功能
|
|
55
|
+
if (config.denyRoles?.some(role => userRoles.includes(role))) {
|
|
56
|
+
return false
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// 4️⃣ 必须角色检查(必须全部满足)- 用户必须拥有所有必须角色
|
|
60
|
+
if (
|
|
61
|
+
config.mustRoles?.length
|
|
62
|
+
&& !config.mustRoles.every(role => userRoles.includes(role))
|
|
63
|
+
) {
|
|
64
|
+
return false
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// 5️⃣ 可选角色检查(至少命中一个)- 用户至少拥有一个可选角色
|
|
68
|
+
if (
|
|
69
|
+
config.maybeRoles?.length
|
|
70
|
+
&& !config.maybeRoles.some(role => userRoles.includes(role))
|
|
71
|
+
) {
|
|
72
|
+
return false
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// 所有条件满足,返回 true
|
|
76
|
+
return true
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* 处理驾驶配置提交的回调函数
|
|
81
|
+
* 当用户在弹窗中提交驾驶配置数据时,调用此函数保存数据并更新用户状态
|
|
82
|
+
* @param data 用户提交的驾驶配置数据
|
|
83
|
+
* @param userState
|
|
84
|
+
*/
|
|
85
|
+
export async function handleDrivingConfigSubmit(data: any, userState: any) {
|
|
86
|
+
// console.warn('>>> handleDrivingConfigSubmit', data, userState)
|
|
87
|
+
// 调用后端逻辑保存用户驾驶信息
|
|
88
|
+
await runLogic('saveUserDrivingInfoLogic', { ...data, userId: userState.getUserInfo().id }, 'af-linepatrol')
|
|
89
|
+
// 获取当前用户信息
|
|
90
|
+
const currentUserInfo = userState.getUserInfo()
|
|
91
|
+
// 更新用户信息,将驾驶信息合并到用户状态中
|
|
92
|
+
userState.setUserInfo({ ...currentUserInfo, drivingInfo: data })
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* 检查并初始化驾驶配置
|
|
97
|
+
* 该函数检查当前环境和用户角色是否支持驾驶功能,如果支持且用户未配置驾驶信息,则打开配置弹窗
|
|
98
|
+
* 主要用于应用启动时或需要时初始化驾驶相关设置
|
|
99
|
+
*/
|
|
100
|
+
export async function checkAndInitDrivingConfig(userState: any) {
|
|
101
|
+
// 检查环境条件:不是微信环境且兼容模式不是OA
|
|
102
|
+
if (!isWechat() && import.meta.env.VITE_APP_COMPATIBLE !== 'OA') {
|
|
103
|
+
// console.warn('>>> userState', userState) // 调试日志
|
|
104
|
+
// 获取驾驶配置(角色权限等)
|
|
105
|
+
const drivingConfig: any = await runLogic('getLiuliConfiguration', { configName: 'DrivingConfig' }, 'af-linepatrol')
|
|
106
|
+
// 根据配置和用户角色判断是否启用驾驶功能
|
|
107
|
+
const isDriving = canEnableFeatureByRoleStr(drivingConfig, userState.getUserInfo().rolestr || userState.getUserInfo().rolestr.rolesnames || '')
|
|
108
|
+
if (isDriving) {
|
|
109
|
+
// 获取用户的驾驶信息
|
|
110
|
+
const drivingInfoRes: any = await runLogic('getUserDrivingInfoLogic', { userId: userState.getUserInfo().id }, 'af-linepatrol')
|
|
111
|
+
const drivingInfo = JSON.parse(drivingInfoRes.value)
|
|
112
|
+
// console.warn('>>>drivingInfoRes', drivingInfoRes) // 调试日志
|
|
113
|
+
// console.warn('>>>drivingInfo', drivingInfo) // 调试日志
|
|
114
|
+
// 如果驾驶信息为空,说明用户未配置,需要打开配置弹窗
|
|
115
|
+
if (drivingInfo === null || Object.keys(drivingInfo).length === 0) {
|
|
116
|
+
// 打开配置弹窗,并传入提交处理函数
|
|
117
|
+
openDrivingConfigPopup()
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
// 如果用户已配置驾驶信息,则更新用户状态
|
|
121
|
+
userState.setUserInfo({ ...userState.getUserInfo(), drivingInfo })
|
|
122
|
+
// console.warn('用户已配置驾驶信息,则更新用户状态>>>userinfo', userState.getUserInfo())
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* 打开驾驶配置弹窗
|
|
130
|
+
* 该函数动态创建并显示驾驶配置弹窗组件,监听用户的提交和关闭事件
|
|
131
|
+
* 当用户提交数据时,调用传入的回调函数;当用户关闭弹窗时,卸载组件
|
|
132
|
+
*/
|
|
133
|
+
export function openDrivingConfigPopup() {
|
|
134
|
+
// 创建Vue应用实例,传入弹窗组件和事件监听器
|
|
135
|
+
const app = createApp(DrivingConfig, {
|
|
136
|
+
'visible': true, // 设置弹窗初始显示
|
|
137
|
+
// 监听自定义事件:onSubmit(data, userState)
|
|
138
|
+
// 对应组件中 emit('onSubmit', data, userState)
|
|
139
|
+
'onOnSubmit': async (data: any, userState: any) => {
|
|
140
|
+
// 监听提交事件,调用回调函数并卸载组件
|
|
141
|
+
await handleDrivingConfigSubmit(data, userState)
|
|
142
|
+
app.unmount()
|
|
143
|
+
},
|
|
144
|
+
// 监听 v-model:visible 对应的 update:visible 事件
|
|
145
|
+
'onUpdate:visible': (visible: boolean) => {
|
|
146
|
+
// 监听弹窗显示状态变化,如果隐藏则卸载组件
|
|
147
|
+
if (!visible) {
|
|
148
|
+
app.unmount()
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
})
|
|
152
|
+
// 创建临时DOM元素作为挂载点
|
|
153
|
+
const div = document.createElement('div')
|
|
154
|
+
// 将临时元素添加到页面body中
|
|
155
|
+
document.body.appendChild(div)
|
|
156
|
+
// 将Vue应用挂载到临时元素上
|
|
157
|
+
app.mount(div)
|
|
158
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import XForm from '@af-mobile-client-vue3/components/data/XForm/index.vue'
|
|
3
|
+
import { runLogic } from '@af-mobile-client-vue3/services/api/common'
|
|
4
|
+
import { useUserStore } from '@af-mobile-client-vue3/stores'
|
|
5
|
+
import { showToast, Button as VanButton } from 'vant'
|
|
6
|
+
import { onMounted, ref } from 'vue'
|
|
7
|
+
// 定义 props 和 emits
|
|
8
|
+
const props = defineProps<{
|
|
9
|
+
visible: boolean
|
|
10
|
+
}>()
|
|
11
|
+
const emit = defineEmits<{
|
|
12
|
+
(event: 'update:visible', value: boolean): void
|
|
13
|
+
(event: 'onSubmit', value: any, userState: any): void
|
|
14
|
+
}>()
|
|
15
|
+
const userState = useUserStore()
|
|
16
|
+
const drivingFrom = ref()
|
|
17
|
+
const showLogoutConfirm = ref(false)
|
|
18
|
+
onMounted(() => {
|
|
19
|
+
// console.log('>>>onMounted', props)
|
|
20
|
+
showLogoutConfirm.value = props.visible
|
|
21
|
+
runLogic('getLiuliConfiguration', {
|
|
22
|
+
configName: 'DrivingConfigForm',
|
|
23
|
+
}, 'af-linepatrol')
|
|
24
|
+
.then((DrivingConfigForm) => {
|
|
25
|
+
// console.log('>>>res', DrivingConfigForm)
|
|
26
|
+
const initParams = {
|
|
27
|
+
formItems: DrivingConfigForm,
|
|
28
|
+
}
|
|
29
|
+
if ((userState.getUserInfo()?.drivingInfo?.drivingMode || null) === null) {
|
|
30
|
+
drivingFrom.value?.init(initParams)
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
drivingFrom.value?.init({
|
|
34
|
+
...initParams,
|
|
35
|
+
formData: userState.getUserInfo()?.drivingInfo,
|
|
36
|
+
})
|
|
37
|
+
}
|
|
38
|
+
})
|
|
39
|
+
.catch((err) => {
|
|
40
|
+
console.error('>>>err', err)
|
|
41
|
+
showToast('获取配置失败')
|
|
42
|
+
})
|
|
43
|
+
})
|
|
44
|
+
function onsubmit(data: any) {
|
|
45
|
+
// console.warn('>>>onsubmit', data, userState)
|
|
46
|
+
emit('onSubmit', data, userState)
|
|
47
|
+
// emit('update:visible', false)
|
|
48
|
+
}
|
|
49
|
+
function updateModalVisible(visible = false) {
|
|
50
|
+
showLogoutConfirm.value = visible
|
|
51
|
+
emit('update:visible', visible)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async function handleSubmitClick() {
|
|
55
|
+
// 调用 XForm 对外暴露的 submit 方法(如果存在)
|
|
56
|
+
const res = await drivingFrom.value.asyncSubmit()
|
|
57
|
+
onsubmit(res?.realForm)
|
|
58
|
+
}
|
|
59
|
+
function handleCloseClick() {
|
|
60
|
+
updateModalVisible(false)
|
|
61
|
+
}
|
|
62
|
+
defineExpose({ updateModalVisible })
|
|
63
|
+
</script>
|
|
64
|
+
|
|
65
|
+
<template>
|
|
66
|
+
<div v-if="showLogoutConfirm" class="driving-popup-overlay">
|
|
67
|
+
<div class="driving-popup-container">
|
|
68
|
+
<XForm
|
|
69
|
+
ref="drivingFrom"
|
|
70
|
+
service-name:="af-linepatrol"
|
|
71
|
+
:is-group-form="true"
|
|
72
|
+
:submit-button="false"
|
|
73
|
+
/>
|
|
74
|
+
<div class="driving-popup-footer">
|
|
75
|
+
<VanButton
|
|
76
|
+
class="close-btn"
|
|
77
|
+
|
|
78
|
+
plain block
|
|
79
|
+
@click="handleCloseClick"
|
|
80
|
+
>
|
|
81
|
+
取消
|
|
82
|
+
</VanButton>
|
|
83
|
+
<VanButton
|
|
84
|
+
class="submit-btn"
|
|
85
|
+
type="primary"
|
|
86
|
+
block
|
|
87
|
+
@click="handleSubmitClick"
|
|
88
|
+
>
|
|
89
|
+
确认修改
|
|
90
|
+
</VanButton>
|
|
91
|
+
</div>
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
</template>
|
|
95
|
+
|
|
96
|
+
<style scoped lang="less">
|
|
97
|
+
.driving-popup-overlay {
|
|
98
|
+
position: fixed;
|
|
99
|
+
inset: 0;
|
|
100
|
+
z-index: 100;
|
|
101
|
+
display: flex;
|
|
102
|
+
align-items: center;
|
|
103
|
+
justify-content: center;
|
|
104
|
+
background-color: rgba(0, 0, 0, 0.5);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.driving-popup-container {
|
|
108
|
+
width: 90%;
|
|
109
|
+
max-width: 400px;
|
|
110
|
+
max-height: 80vh;
|
|
111
|
+
padding: 16px;
|
|
112
|
+
overflow-y: auto;
|
|
113
|
+
border-radius: 12px;
|
|
114
|
+
background-color: #fff;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.driving-popup-footer {
|
|
118
|
+
display: flex;
|
|
119
|
+
gap: 8px;
|
|
120
|
+
padding-top: 16px;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.driving-popup-footer .submit-btn,
|
|
124
|
+
.driving-popup-footer .close-btn {
|
|
125
|
+
flex: 1;
|
|
126
|
+
}
|
|
127
|
+
</style>
|
|
@@ -7,6 +7,7 @@ import { getUserPermissions } from '@af-mobile-client-vue3/services/api/search'
|
|
|
7
7
|
import { useSettingStore } from '@af-mobile-client-vue3/stores/modules/setting'
|
|
8
8
|
import { useUserStore } from '@af-mobile-client-vue3/stores/modules/user'
|
|
9
9
|
import { UserType } from '@af-mobile-client-vue3/types/auth'
|
|
10
|
+
import { checkAndInitDrivingConfig } from '@af-mobile-client-vue3/utils/driving/drivingUtils'
|
|
10
11
|
import { isWechat } from '@af-mobile-client-vue3/utils/platform-auth'
|
|
11
12
|
import { funcToRouter, loadRoutes } from '@af-mobile-client-vue3/utils/routerUtil'
|
|
12
13
|
import { secureStorageBatchWrite, secureStorageRead } from '@af-mobile-client-vue3/utils/secureStorage'
|
|
@@ -223,6 +224,8 @@ async function afterGeneral(result, token = '') {
|
|
|
223
224
|
|
|
224
225
|
// 每次重新登录时,清除indexedDB缓存
|
|
225
226
|
// indexedDB.clear()
|
|
227
|
+
// 如果不是微信和OA 进行超速相关判断
|
|
228
|
+
checkAndInitDrivingConfig(userState)
|
|
226
229
|
}
|
|
227
230
|
async function wxLoginFun() {
|
|
228
231
|
await localStorage.setItem('wechatLoginPending', 'true')
|
|
@@ -8,12 +8,14 @@ import { Dialog as vanDialog, Icon as vanIcon, Sticky as VanSticky,
|
|
|
8
8
|
} from 'vant'
|
|
9
9
|
import { computed, onMounted, onUnmounted, ref } from 'vue'
|
|
10
10
|
import { useRouter } from 'vue-router'
|
|
11
|
+
import { openDrivingConfigPopup } from '~root/src/utils/driving/drivingUtils'
|
|
11
12
|
import ModifyPassword from './comm/ModifyPassword.vue'
|
|
12
13
|
|
|
13
14
|
const router = useRouter()
|
|
14
15
|
const username = useUserStore().getUserInfo().name
|
|
15
16
|
const fullnames = useUserStore().getLogin().f.resources.fullnames
|
|
16
17
|
const roleName = useUserStore().getLogin().f.resources.f_role_name
|
|
18
|
+
const userInfo = useUserStore().getUserInfo()
|
|
17
19
|
|
|
18
20
|
// 修改密码弹窗显示状态
|
|
19
21
|
const showModifyPassword = ref(false)
|
|
@@ -250,6 +252,13 @@ const webMobileConfig = useSettingStore().getSetting()
|
|
|
250
252
|
</div>
|
|
251
253
|
<van-icon name="arrow" class="menu-arrow" />
|
|
252
254
|
</div>
|
|
255
|
+
<div v-if="userInfo?.drivingInfo !== undefined && userInfo?.drivingInfo !== null" class="menu-item" @click="openDrivingConfigPopup">
|
|
256
|
+
<div class="menu-item-content">
|
|
257
|
+
<van-icon name="logistics" class="menu-icon" />
|
|
258
|
+
<span class="menu-text">修改行驶方式</span>
|
|
259
|
+
</div>
|
|
260
|
+
<van-icon name="arrow" class="menu-arrow" />
|
|
261
|
+
</div>
|
|
253
262
|
<div class="menu-item" @click="exit_login">
|
|
254
263
|
<div class="menu-item-content">
|
|
255
264
|
<van-icon name="sign" class="menu-icon logout-icon" />
|