批量优化
This commit is contained in:
1 parent
e3db229f41
commit
aa92ca40a2
79 files changed
+7495
-1104
No files matched your search
@@ -0,0 +1,131 @@
|
||||
/**
|
||||
* 菜单 → 页面 的跳转分发
|
||||
*
|
||||
* 聚合平台里绝大多数业务功能(ERP / OA / CRM / CMS)目前只有 Web 端实现,
|
||||
* 端上没有对应页面;少数功能(记事本、日程提醒)已有原生页面。
|
||||
* 这里统一判定:能走原生就走原生,否则丢进 webview 容器打开 Web 端深链。
|
||||
*/
|
||||
import { createAppTicket } from '@/api/auth.js'
|
||||
|
||||
/** 移动端已有原生页面的功能。匹配顺序即优先级。 */
|
||||
const NATIVE_RULES = [
|
||||
{ pattern: /记事本|笔记|便签|notebook/i, route: '/pages/tools/notepad/index' },
|
||||
{ pattern: /日程|提醒|待办|calendar|schedule/i, route: '/pages/tools/schedule/index' }
|
||||
]
|
||||
|
||||
/** Web 端容器页 */
|
||||
const WEBVIEW_PAGE = '/pages/apps/webview'
|
||||
|
||||
/** 菜单是否命中移动端原生页面 */
|
||||
export function resolveNativeRoute(menu = {}) {
|
||||
const haystack = (menu.title || '') + ' ' + (menu.path || '')
|
||||
const hit = NATIVE_RULES.find((r) => r.pattern.test(haystack))
|
||||
return hit ? hit.route : ''
|
||||
}
|
||||
|
||||
/** 该功能是否在租户套餐内 */
|
||||
export function isMenuLocked(menu = {}) {
|
||||
return menu.locked === true || menu.locked === 1
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开一个菜单功能
|
||||
* @param {object} menu /app/home 返回的菜单项
|
||||
* @param {string} [fallbackTitle] 没有菜单时用于提示的功能名
|
||||
*/
|
||||
export function openMenu(menu, fallbackTitle = '') {
|
||||
const name = (menu && (menu.title || menu.name)) || fallbackTitle || '该功能'
|
||||
|
||||
if (!menu) {
|
||||
uni.showToast({ title: name + '暂未开放', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
if (isMenuLocked(menu)) {
|
||||
uni.showModal({
|
||||
title: '功能未开通',
|
||||
content: '「' + name + '」不在当前套餐范围内,请联系管理员开通后再使用。',
|
||||
showCancel: false,
|
||||
confirmText: '知道了'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 目录节点(还有下级)不直接跳转
|
||||
if (menu.leaf === false) {
|
||||
uni.showToast({ title: '请选择「' + name + '」下的具体功能', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
const native = resolveNativeRoute(menu)
|
||||
if (native) {
|
||||
uni.navigateTo({ url: native })
|
||||
return
|
||||
}
|
||||
|
||||
if (!menu.path) {
|
||||
uni.showToast({ title: name + '暂未开放', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
// 走 Web 端:先换一次性票据实现免登录,失败则降级为直接打开(用户手动登录一次)
|
||||
openWebPage(menu.path, name)
|
||||
}
|
||||
|
||||
/**
|
||||
* 用 Web 端打开指定业务页。
|
||||
*
|
||||
* 关键:这里不传「完整 URL」,而是拆成 path + ticket 两个参数传给容器页。
|
||||
* 原因是 uniapp 各端对 query 的编解码行为不一致 —— H5 端 vue-router 会先解码一次
|
||||
* 并在序列化时把 % 转成 %25,小程序端则不解码;一旦传完整 URL(含 %、#、&),
|
||||
* 就会出现「双重编码」或被截断。path 与 ticket 都是纯 ASCII 无特殊字符,
|
||||
* 任何端都安全。
|
||||
*
|
||||
* @param {string} path 菜单 path,如 /apps/oa/dashboard
|
||||
* @param {string} title 页面标题
|
||||
*/
|
||||
export async function openWebPage(path, title = '') {
|
||||
const name = title || '功能'
|
||||
const target = String(path || '').trim()
|
||||
if (!target) {
|
||||
uni.showToast({ title: name + '暂未开放', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
let ticket = ''
|
||||
try {
|
||||
const data = await createAppTicket()
|
||||
ticket = (data && data.ticket) || ''
|
||||
} catch (e) {
|
||||
// 票据失败不影响打开,只是需要在 webview 内登录一次
|
||||
console.warn('[nav] 获取免登录票据失败,降级为直接打开:', e)
|
||||
}
|
||||
|
||||
uni.navigateTo({
|
||||
url:
|
||||
WEBVIEW_PAGE +
|
||||
'?p=' +
|
||||
encodeURIComponent(target) +
|
||||
'&k=' +
|
||||
encodeURIComponent(ticket) +
|
||||
'&t=' +
|
||||
encodeURIComponent(name)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开 webview 容器页并直接指定完整地址(通用兜底,非免登录场景)。
|
||||
* @param {string} url 完整地址(未编码)
|
||||
* @param {string} title 页面标题
|
||||
*/
|
||||
export function openRawUrl(url, title = '') {
|
||||
if (!url) return
|
||||
uni.navigateTo({
|
||||
url:
|
||||
WEBVIEW_PAGE +
|
||||
'?p=' +
|
||||
encodeURIComponent(url) +
|
||||
'&t=' +
|
||||
encodeURIComponent(title || '功能')
|
||||
})
|
||||
}
|
||||
Reference in new issue
Block a user