feat(mobile): 主程序前端 nativeApp 桥接契约改造 + /share 接收页 + 子模块切到 Expo 工程

新移动端从 EEUI(weex) 切到 Expo(react-native),UA 标识从 'eeui' 改为 'DooTaskApp',
桥接底层从全局 requireModuleJs 切到 window.__nativeBridge.call(method,args) Promise RPC。
约 52 个文件批量改名(256 处引用):

- 平台识别:$A.isEEUIApp/Vue.prototype.$isEEUIApp → isMobileApp / $isMobileApp
  app.js 顶部 UA 正则 /eeui/i → /DooTaskApp/i
  app.js requireModuleJs 等待逻辑替换为 window.__nativeBridge 就绪判定
- 桥接 API:$A.eeuiAppXXX → $A.nativeAppXXX
- functions/eeui.js 删除,重写为 functions/native-app.js
  底层走 window.__nativeBridge.call;nativeAppSendMessage 把旧 sendMessage 的
  各 action 拆解为独立 method 调用(updateTheme/windowSize/setBadge/vibrate/
  callTel/picturePreview/videoPreview/startMeeting/updateMeetingInfo 等)
- types/dootask-globals.d.ts:方法签名同步改名
- store/actions.js:清理 saveUserInfoBase 内旧的
  userChatList/userUploadUrl sendMessage(二期由 /share 接收页直接调接口替代)

二期 /share 接收页(跨 App 分享):
- pages/share.vue(新增):原生 Share Extension / Android Intent 通过
  dootask://share?token=... 拉起 App 后跳本页;
  调 nativeAppGetSharedPayload 取分享元数据;
  复用 api/users/share/list 渲染会话列表;
  用户选会话 → POST api/dialog/msg/sendfiles 上传 + sendtext 发文本/URL;
  完成后 nativeAppClearSharedPayload 清理 + 跳目标会话
- routes.js 注册 /share 路由
- language/original-web.txt 加 share.vue 用到的文案

构建链路(electron/build.js):
- appbuild app 子命令:前端产物从复制到 resources/mobile/src/public + EEUI docker 构建
  改为同步到 resources/mobile/assets/web(由 plugins/withWebAssets 注入原生 bundle)
- android-upload apk 路径:从 platforms/android/eeuiApp/... 改为
  android/app/build/outputs/apk/release(Expo prebuild 标准布局)

子模块 resources/mobile 指针更新到新 Expo 工程提交(feat/mobile-expo-rewrite 分支)。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
kuaifan 2026-06-17 06:55:52 +00:00
parent 9151939ba5
commit f479047fc9
59 changed files with 772 additions and 650 deletions

55
electron/build.js vendored
View File

@ -401,48 +401,15 @@ async function startBuild(data) {
fs.writeFileSync(indexFile, indexString, 'utf8'); fs.writeFileSync(indexFile, indexString, 'utf8');
// //
if (data.id === 'app') { if (data.id === 'app') {
const eeuiDir = path.resolve(__dirname, "../resources/mobile"); // 新 Expo 移动端:将前端构建产物作为离线包同步到 resources/mobile/assets/web
const publicDir = path.resolve(__dirname, "../resources/mobile/src/public"); // 由 config plugin(withWebAssets) 在 prebuild 时注入原生 bundle运行时本地静态服务 serve。
const containerName = `dootask-eeui-${Date.now()}-${process.pid}`; const mobileDir = path.resolve(__dirname, "../resources/mobile");
fse.removeSync(publicDir) const webDir = path.resolve(mobileDir, "assets/web");
fse.copySync(electronDir, publicDir) fse.removeSync(webDir)
if (argv[3] === "publish") { fse.copySync(electronDir, webDir)
// Android config console.log(`移动端离线包已同步: ${webDir}`);
const gradleFile = path.resolve(eeuiDir, "platforms/android/eeuiApp/local.properties") // 版本号由 resources/mobile/app.config.ts 从根 package.json 动态读取,无需改原生工程;
let gradleResult = fs.existsSync(gradleFile) ? fs.readFileSync(gradleFile, 'utf8') : ""; // App 原生打包在 resources/mobile 下执行 expo prebuild + eas build见 WS7
gradleResult = gradleResult.replace(/(versionCode|versionName)\s*=\s*(.+?)(\n|$)/g, '')
gradleResult += `versionCode = ${config.codeVerson}\nversionName = ${config.version}\n`
fs.writeFileSync(gradleFile, gradleResult, 'utf8')
// iOS config
const xcconfigFile = path.resolve(eeuiDir, "platforms/ios/eeuiApp/Config/Version.xcconfig")
let xcconfigResult = fs.existsSync(xcconfigFile) ? fs.readFileSync(xcconfigFile, 'utf8') : "";
xcconfigResult = xcconfigResult.replace(/(VERSION_CODE|VERSION_NAME)\s*=\s*(.+?)(\n|$)/g, '')
xcconfigResult += `VERSION_CODE = ${config.codeVerson}\nVERSION_NAME = ${config.version}\n`
fs.writeFileSync(xcconfigFile, xcconfigResult, 'utf8')
}
if (['build', 'publish'].includes(argv[3])) {
child_process.execSync(
`docker run -d --name ${containerName} -v ${shellQuote(eeuiDir)}:/work -w /work kuaifan/eeui-cli:0.0.1 sleep infinity`,
{stdio: "ignore", cwd: "resources/mobile"}
);
try {
if (!fs.existsSync(path.resolve(eeuiDir, "node_modules"))) {
child_process.execSync(`docker exec ${containerName} npm install`, {stdio: "inherit", cwd: "resources/mobile"});
}
child_process.execSync(`docker exec ${containerName} node /work/scripts/patch-eeui-build.js`, {stdio: "inherit", cwd: "resources/mobile"});
child_process.execSync(`docker exec ${containerName} eeui build --simple`, {stdio: "inherit", cwd: "resources/mobile"});
} finally {
child_process.execSync(`docker rm -f ${containerName}`, {stdio: "ignore", cwd: "resources/mobile"});
}
} else {
[
path.resolve(publicDir, "../../platforms/ios/eeuiApp/bundlejs/eeui/public"),
path.resolve(publicDir, "../../platforms/android/eeuiApp/app/src/main/assets/eeui/public"),
].some(dir => {
fse.removeSync(dir)
fse.copySync(electronDir, dir)
})
}
return; return;
} }
const output = `dist/${data.id.replace(/\./g, '-')}/${platform}` const output = `dist/${data.id.replace(/\./g, '-')}/${platform}`
@ -560,7 +527,9 @@ if (["dev"].includes(argv[2])) {
process.exit(1) process.exit(1)
} }
const client = r2.createR2Client() const client = r2.createR2Client()
const releaseDir = path.resolve(__dirname, "../resources/mobile/platforms/android/eeuiApp/app/build/outputs/apk/release"); // 新 Expo 移动端apk 由 EAS Build 输出(或本地 expo prebuild + gradle assembleRelease
// EAS 流水线产物路径示例android/app/build/outputs/apk/release 或 EAS 远端构建直接上传。
const releaseDir = path.resolve(__dirname, "../resources/mobile/android/app/build/outputs/apk/release");
if (!fs.existsSync(releaseDir)) { if (!fs.existsSync(releaseDir)) {
console.error("发布文件未找到") console.error("发布文件未找到")
process.exit(1) process.exit(1)

View File

@ -2469,3 +2469,10 @@ AI任务分析
操作引导启动失败 操作引导启动失败
最多只能添加(*)个 最多只能添加(*)个
该标签已存在 该标签已存在
发送给
搜索会话
暂无会话
缺少分享凭据
分享内容不存在或已过期
加载会话列表失败
正在发送

View File

@ -217,11 +217,11 @@ export default {
handler() { handler() {
this.$store.dispatch("websocketConnection"); this.$store.dispatch("websocketConnection");
// //
if (this.$isEEUIApp) { if (this.$isMobileApp) {
this.umengAliasTimer && clearTimeout(this.umengAliasTimer) this.umengAliasTimer && clearTimeout(this.umengAliasTimer)
if (this.userId > 0) { if (this.userId > 0) {
// APP // APP
$A.eeuiAppSendMessage({ $A.nativeAppSendMessage({
action: 'initApp', action: 'initApp',
apiUrl: $A.apiUrl(''), apiUrl: $A.apiUrl(''),
userid: this.userId, userid: this.userId,
@ -231,7 +231,7 @@ export default {
}); });
// //
$A.eeuiAppGetDeviceInfo().then(async info => { $A.nativeAppGetDeviceInfo().then(async info => {
let deviceName = info.deviceName || info.modelName let deviceName = info.deviceName || info.modelName
if (info.systemName === 'Android') { if (info.systemName === 'Android') {
if ($A.strExists(info.modelName, info.brand)) { if ($A.strExists(info.modelName, info.brand)) {
@ -254,14 +254,14 @@ export default {
// //
this.umengAliasTimer = setTimeout(_ => { this.umengAliasTimer = setTimeout(_ => {
this.umengAliasTimer = null; this.umengAliasTimer = null;
$A.eeuiAppSendMessage({ $A.nativeAppSendMessage({
action: 'setUmengAlias', action: 'setUmengAlias',
url: $A.apiUrl('users/umeng/alias') url: $A.apiUrl('users/umeng/alias')
}); });
}, 6000) }, 6000)
} else { } else {
// //
$A.eeuiAppSendMessage({ $A.nativeAppSendMessage({
action: 'delUmengAlias', action: 'delUmengAlias',
url: $A.apiUrl('users/umeng/alias') url: $A.apiUrl('users/umeng/alias')
}); });
@ -385,7 +385,7 @@ export default {
}, },
onRouterViewMounted() { onRouterViewMounted() {
document.documentElement.setAttribute("data-platform", $A.isElectron ? "desktop" : $A.isEEUIApp ? "app" : "web") document.documentElement.setAttribute("data-platform", $A.isElectron ? "desktop" : $A.isMobileApp ? "app" : "web")
}, },
/** /**
@ -649,12 +649,12 @@ export default {
}, },
eeuiEvents() { eeuiEvents() {
if (!this.$isEEUIApp) { if (!this.$isMobileApp) {
return; return;
} }
// //
setTimeout(() => { setTimeout(() => {
this.appActivated && $A.eeuiAppHideWebviewSnapshot() this.appActivated && $A.nativeAppHideWebviewSnapshot()
}, 500) }, 500)
// APP // APP
window.__onAppActive = async () => { window.__onAppActive = async () => {
@ -667,12 +667,12 @@ export default {
this.autoTheme() this.autoTheme()
$A.updateTimezone() $A.updateTimezone()
$A.eeuiAppHideWebviewSnapshot() $A.nativeAppHideWebviewSnapshot()
this.$store.dispatch("safeAreaInsets") this.$store.dispatch("safeAreaInsets")
const nowYmd = $A.daytz().format('YYYY-MM-DD') const nowYmd = $A.daytz().format('YYYY-MM-DD')
if (this.lastCheckUpgradeYmd != nowYmd) { if (this.lastCheckUpgradeYmd != nowYmd) {
this.lastCheckUpgradeYmd = nowYmd this.lastCheckUpgradeYmd = nowYmd
$A.eeuiAppCheckUpdate(); $A.nativeAppCheckUpdate();
} }
} }
// APP // APP
@ -683,12 +683,12 @@ export default {
// APP // APP
return; return;
} }
$A.eeuiAppGetWebviewSnapshot(ok => { $A.nativeAppGetWebviewSnapshot(ok => {
if (!ok || this.appActivated) { if (!ok || this.appActivated) {
// APP // APP
return; return;
} }
$A.eeuiAppShowWebviewSnapshot() $A.nativeAppShowWebviewSnapshot()
}); });
}, 500); }, 500);
} }
@ -714,7 +714,7 @@ export default {
return; return;
} else if (urlType === 1) { } else if (urlType === 1) {
// 使 // 使
$A.eeuiAppOpenWeb(url); $A.nativeAppOpenWeb(url);
return; return;
} }
// App // App
@ -741,7 +741,7 @@ export default {
tourist_id: event.uuid, tourist_id: event.uuid,
} }
}).then(({data}) => { }).then(({data}) => {
$A.eeuiAppSendMessage({ $A.nativeAppSendMessage({
action: 'updateMeetingInfo', action: 'updateMeetingInfo',
infos: { infos: {
uuid: event.uuid, uuid: event.uuid,
@ -790,7 +790,7 @@ export default {
} }
this.$store.state.keyboardShow = event.keyboardType === 'show'; this.$store.state.keyboardShow = event.keyboardType === 'show';
this.$store.state.keyboardHeight = event.keyboardHeight; this.$store.state.keyboardHeight = event.keyboardHeight;
$A.eeuiAppShakeToEditEnabled(this.$store.state.keyboardShow) $A.nativeAppShakeToEditEnabled(this.$store.state.keyboardShow)
} }
// //
window.__onNotificationPermissionStatus = (ret) => { window.__onNotificationPermissionStatus = (ret) => {
@ -801,22 +801,22 @@ export default {
this.goForward({ path: (path || '').indexOf('/') !==0 ? "/" + path : path }); this.goForward({ path: (path || '').indexOf('/') !==0 ? "/" + path : path });
} }
// //
$A.eeuiAppSendMessage({ $A.nativeAppSendMessage({
action: 'windowSize', action: 'windowSize',
width: this.windowWidth, width: this.windowWidth,
height: this.windowHeight, height: this.windowHeight,
}); });
// //
$A.eeuiAppSetHapticBackEnabled(false) $A.nativeAppSetHapticBackEnabled(false)
// //
$A.eeuiAppSetCachesString("languageWebBack", this.$L("后退")) $A.nativeAppSetCachesString("languageWebBack", this.$L("后退"))
$A.eeuiAppSetCachesString("languageWebForward", this.$L("前进")) $A.nativeAppSetCachesString("languageWebForward", this.$L("前进"))
$A.eeuiAppSetCachesString("languageWebBrowser", this.$L("浏览器打开")) $A.nativeAppSetCachesString("languageWebBrowser", this.$L("浏览器打开"))
$A.eeuiAppSetCachesString("languageWebRefresh", this.$L("刷新")) $A.nativeAppSetCachesString("languageWebRefresh", this.$L("刷新"))
$A.eeuiAppSetCachesString("updateDefaultTitle", this.$L("发现新版本")) $A.nativeAppSetCachesString("updateDefaultTitle", this.$L("发现新版本"))
$A.eeuiAppSetCachesString("updateDefaultContent", this.$L("暂无更新介绍!")) $A.nativeAppSetCachesString("updateDefaultContent", this.$L("暂无更新介绍!"))
$A.eeuiAppSetCachesString("updateDefaultCancelText", this.$L("以后再说")) $A.nativeAppSetCachesString("updateDefaultCancelText", this.$L("以后再说"))
$A.eeuiAppSetCachesString("updateDefaultUpdateText", this.$L("立即更新")) $A.nativeAppSetCachesString("updateDefaultUpdateText", this.$L("立即更新"))
}, },
otherEvents() { otherEvents() {

View File

@ -1,6 +1,7 @@
const isElectron = !!(window && window.process && window.process.type && window.electron); const isElectron = !!(window && window.process && window.process.type && window.electron);
const isEEUIApp = window && window.navigator && /eeui/i.test(window.navigator.userAgent); // 新移动端在 UA 追加 DooTaskApp/<codeVersion>resources/mobile/src/webview/WebViewShell.tsx
const isSoftware = isElectron || isEEUIApp; const isMobileApp = window && window.navigator && /DooTaskApp/i.test(window.navigator.userAgent);
const isSoftware = isElectron || isMobileApp;
document.getElementById("app")?.setAttribute("data-preload", "false"); document.getElementById("app")?.setAttribute("data-preload", "false");
@ -8,7 +9,7 @@ import {languageName, switchLanguage as $L} from "./language";
import {isLocalHost} from "./components/Replace/utils"; import {isLocalHost} from "./components/Replace/utils";
import './functions/common' import './functions/common'
import './functions/eeui' import './functions/native-app'
import './functions/web' import './functions/web'
import Vue from 'vue' import Vue from 'vue'
@ -188,8 +189,8 @@ Vue.prototype.copyText = function (obj) {
error: "复制失败" error: "复制失败"
} }
} }
if ($A.isEEUIApp) { if ($A.isMobileApp) {
$A.eeuiAppCopyText(obj.text) $A.nativeAppCopyText(obj.text)
obj.success && $A.messageSuccess(obj.success) obj.success && $A.messageSuccess(obj.success)
return return
} }
@ -207,7 +208,7 @@ $A.Electron = null;
$A.Platform = "web"; $A.Platform = "web";
$A.isMainElectron = false; $A.isMainElectron = false;
$A.isSubElectron = false; $A.isSubElectron = false;
$A.isEEUIApp = isEEUIApp; $A.isMobileApp = isMobileApp;
$A.isElectron = isElectron; $A.isElectron = isElectron;
$A.isSoftware = isSoftware; $A.isSoftware = isSoftware;
$A.openLog = false; $A.openLog = false;
@ -216,7 +217,7 @@ if (isElectron) {
$A.Platform = /macintosh|mac os x/i.test(navigator.userAgent) ? "mac" : "win"; $A.Platform = /macintosh|mac os x/i.test(navigator.userAgent) ? "mac" : "win";
$A.isMainElectron = /\s+MainTaskWindow\//.test(window.navigator.userAgent); $A.isMainElectron = /\s+MainTaskWindow\//.test(window.navigator.userAgent);
$A.isSubElectron = /\s+SubTaskWindow\//.test(window.navigator.userAgent); $A.isSubElectron = /\s+SubTaskWindow\//.test(window.navigator.userAgent);
} else if (isEEUIApp) { } else if (isMobileApp) {
$A.Platform = /(iPhone|iPad|iPod|iOS)/i.test(navigator.userAgent) ? "ios" : "android"; $A.Platform = /(iPhone|iPad|iPod|iOS)/i.test(navigator.userAgent) ? "ios" : "android";
} }
@ -287,7 +288,7 @@ Vue.prototype.$Electron = $A.Electron;
Vue.prototype.$Platform = $A.Platform; Vue.prototype.$Platform = $A.Platform;
Vue.prototype.$isMainElectron = $A.isMainElectron; Vue.prototype.$isMainElectron = $A.isMainElectron;
Vue.prototype.$isSubElectron = $A.isSubElectron; Vue.prototype.$isSubElectron = $A.isSubElectron;
Vue.prototype.$isEEUIApp = $A.isEEUIApp; Vue.prototype.$isMobileApp = $A.isMobileApp;
Vue.prototype.$isSoftware = $A.isSoftware; Vue.prototype.$isSoftware = $A.isSoftware;
Vue.config.productionTip = false; Vue.config.productionTip = false;
@ -324,15 +325,16 @@ const $init = async () => {
const $preload = async () => { const $preload = async () => {
document.getElementById("app")?.setAttribute("data-preload", "true") document.getElementById("app")?.setAttribute("data-preload", "true")
if ($A.isEEUIApp) { if ($A.isMobileApp) {
// 等待新 RN 桥接传输层window.__nativeBridge就绪注入时机为 webview 加载内容前
const requireTime = new Date().getTime(); const requireTime = new Date().getTime();
while (typeof requireModuleJs !== "function") { while (!window.__nativeBridge) {
await new Promise(resolve => setTimeout(resolve, 200)); await new Promise(resolve => setTimeout(resolve, 200));
if (new Date().getTime() - requireTime > 15 * 1000) { if (new Date().getTime() - requireTime > 15 * 1000) {
break break
} }
} }
if (typeof requireModuleJs !== "function") { if (!window.__nativeBridge) {
const errorTip = $A.L("加载失败,请重启软件") const errorTip = $A.L("加载失败,请重启软件")
const errorView = document.querySelector(".app-view-loading") const errorView = document.querySelector(".app-view-loading")
if (errorView) { if (errorView) {
@ -342,8 +344,8 @@ const $preload = async () => {
} }
return return
} }
const pageInfo = $A.eeuiAppGetPageInfo() || {}; // 新移动端单 WebView 套壳永远是首屏isFirstPage 恒 true旧 EEUI 是多 page 容器才需要判定)
store.state.isFirstPage = pageInfo.pageName === 'firstPage' store.state.isFirstPage = true
await store.dispatch("safeAreaInsets") await store.dispatch("safeAreaInsets")
} }

View File

@ -4,7 +4,7 @@
:placement="placement" :placement="placement"
:effect="tooltipTheme" :effect="tooltipTheme"
:delay="delay" :delay="delay"
:disabled="$isEEUIApp || windowTouch || !showTooltip || disabled" :disabled="$isMobileApp || windowTouch || !showTooltip || disabled"
:max-width="tooltipMaxWidth" :max-width="tooltipMaxWidth"
transfer> transfer>
<span ref="content" @mouseenter="handleTooltipIn" class="common-auto-tip" @click="onClick"> <span ref="content" @mouseenter="handleTooltipIn" class="common-auto-tip" @click="onClick">

View File

@ -1,5 +1,5 @@
<template> <template>
<ETooltip v-if="visible" :disabled="$isEEUIApp || windowTouch || content == ''" :content="content"> <ETooltip v-if="visible" :disabled="$isMobileApp || windowTouch || content == ''" :content="content">
<svg v-if="type === 'svg'" viewBox="25 25 50 50" class="common-loading"> <svg v-if="type === 'svg'" viewBox="25 25 50 50" class="common-loading">
<circle cx="50" cy="50" r="20" fill="none" stroke-width="5" stroke-miterlimit="10" class="common-path"></circle> <circle cx="50" cy="50" r="20" fill="none" stroke-width="5" stroke-miterlimit="10" class="common-path"></circle>
</svg> </svg>

View File

@ -257,7 +257,7 @@ export default {
systemInfo: window.systemInfo, systemInfo: window.systemInfo,
windowType: this.windowType, windowType: this.windowType,
isEEUIApp: $A.isEEUIApp, isMobileApp: $A.isMobileApp,
isElectron: $A.isElectron, isElectron: $A.isElectron,
isMainElectron: $A.isMainElectron, isMainElectron: $A.isMainElectron,
isSubElectron: $A.isSubElectron, isSubElectron: $A.isSubElectron,
@ -515,7 +515,7 @@ export default {
width: mergedConfig.width, width: mergedConfig.width,
height: mergedConfig.height, height: mergedConfig.height,
}); });
} else if (this.$isEEUIApp) { } else if (this.$isMobileApp) {
await this.$store.dispatch('openAppChildPage', { await this.$store.dispatch('openAppChildPage', {
pageType: 'app', pageType: 'app',
pageTitle: ' ', pageTitle: ' ',
@ -541,7 +541,7 @@ export default {
path: config.url, path: config.url,
title: config.title || ' ', title: config.title || ' ',
}); });
} else if (this.$isEEUIApp) { } else if (this.$isMobileApp) {
await this.$store.dispatch('openAppChildPage', { await this.$store.dispatch('openAppChildPage', {
pageType: 'app', pageType: 'app',
pageTitle: ' ', pageTitle: ' ',

View File

@ -175,14 +175,14 @@ export default {
}, },
appAndroidEvents() { appAndroidEvents() {
if (this.$isEEUIApp && $A.isAndroid()) { if (this.$isMobileApp && $A.isAndroid()) {
$A.eeuiAppSetPageBackPressed({ $A.nativeAppSetPageBackPressed({
pageName: 'firstPage', pageName: 'firstPage',
}, _ => { }, _ => {
if (this.canBack()) { if (this.canBack()) {
this.onBack(); this.onBack();
} else { } else {
$A.eeuiAppGoDesktop() $A.nativeAppGoDesktop()
} }
}); });
} }

View File

@ -69,7 +69,7 @@ export default {
if (this.duration > 0) { if (this.duration > 0) {
this.timer = setTimeout(this.close, this.duration) this.timer = setTimeout(this.close, this.duration)
} }
$A.eeuiAppSendMessage({ $A.nativeAppSendMessage({
action: 'setVibrate', action: 'setVibrate',
}); });
}, },

View File

@ -198,7 +198,7 @@ export default {
if (this.windowActive) { if (this.windowActive) {
return return
} }
$A.eeuiAppSendMessage({ $A.nativeAppSendMessage({
action: 'setBdageNotify', action: 'setBdageNotify',
bdage: this.unreadAndOverdue, bdage: this.unreadAndOverdue,
}); });

View File

@ -32,7 +32,7 @@ export default {
}, },
previewImageList(l) { previewImageList(l) {
if (l.length > 0) { if (l.length > 0) {
if ($A.isEEUIApp || $A.isElectron) { if ($A.isMobileApp || $A.isElectron) {
let position = Math.min(Math.max(this.$store.state.previewImageIndex, 0), this.$store.state.previewImageList.length - 1) let position = Math.min(Math.max(this.$store.state.previewImageIndex, 0), this.$store.state.previewImageList.length - 1)
let paths = l.map(item => { let paths = l.map(item => {
if ($A.isJson(item)) { if ($A.isJson(item)) {
@ -74,9 +74,9 @@ export default {
}, },
methods: { methods: {
videoPreview(path) { videoPreview(path) {
if ($A.isEEUIApp) { if ($A.isMobileApp) {
$A.eeuiAppSendMessage({ $A.nativeAppSendMessage({
language: $A.eeuiAppConvertLanguage(), language: $A.nativeAppConvertLanguage(),
action: 'videoPreview', action: 'videoPreview',
path path
}); });
@ -89,9 +89,9 @@ export default {
} }
}, },
imagePreview(index, paths) { imagePreview(index, paths) {
if ($A.isEEUIApp) { if ($A.isMobileApp) {
$A.eeuiAppSendMessage({ $A.nativeAppSendMessage({
language: $A.eeuiAppConvertLanguage(), language: $A.nativeAppConvertLanguage(),
action: 'picturePreview', action: 'picturePreview',
position: index, position: index,
paths paths

View File

@ -18,7 +18,7 @@ const convertLocalResourcePath = (() => {
if (initialized) return if (initialized) return
// 设置应用前缀URL // 设置应用前缀URL
if ($A.isEEUIApp || $A.isElectron) { if ($A.isMobileApp || $A.isElectron) {
appPreUrl = window.location.origin + "/" appPreUrl = window.location.origin + "/"
} }

View File

@ -94,14 +94,14 @@ export default {
}, },
showDown() { showDown() {
if (this.$Electron || this.$isEEUIApp || this.windowTouch) { if (this.$Electron || this.$isMobileApp || this.windowTouch) {
return false return false
} }
return this.routeName === 'login' return this.routeName === 'login'
}, },
showPrivacy() { showPrivacy() {
return $A.isDooServer() && this.$isEEUIApp && ['login'].includes(this.routeName) return $A.isDooServer() && this.$isMobileApp && ['login'].includes(this.routeName)
} }
}, },

View File

@ -14,7 +14,7 @@
<Loading v-if="loadIng > 0"/> <Loading v-if="loadIng > 0"/>
<Icon v-else type="ios-search" /> <Icon v-else type="ios-search" />
</div> </div>
<Form class="search-form" action="javascript:void(0)" @submit.native.prevent="$A.eeuiAppKeyboardHide"> <Form class="search-form" action="javascript:void(0)" @submit.native.prevent="$A.nativeAppKeyboardHide">
<Input type="search" ref="searchKey" v-model="searchKey" :placeholder="$L('请输入关键字')"/> <Input type="search" ref="searchKey" v-model="searchKey" :placeholder="$L('请输入关键字')"/>
</Form> </Form>
<div v-if="aiSearchAvailable" class="search-ai" @click="toggleAiSearch"> <div v-if="aiSearchAvailable" class="search-ai" @click="toggleAiSearch">
@ -142,7 +142,7 @@ export default {
}, },
showModal(v) { showModal(v) {
$A.eeuiAppSetScrollDisabled(v) $A.nativeAppSetScrollDisabled(v)
} }
}, },
@ -262,7 +262,7 @@ export default {
}, },
onTouchstart() { onTouchstart() {
$A.eeuiAppKeyboardHide(); $A.nativeAppKeyboardHide();
}, },
onTag(type, e) { onTag(type, e) {

View File

@ -12,7 +12,7 @@
v-if="item.hidden !== true" v-if="item.hidden !== true"
placement="top" placement="top"
:key="key" :key="key"
:disabled="$isEEUIApp || windowTouch || !item.title" :disabled="$isMobileApp || windowTouch || !item.title"
:content="item.title" :content="item.title"
:enterable="false" :enterable="false"
:open-delay="600"> :open-delay="600">

View File

@ -1,7 +1,7 @@
<template> <template>
<ETooltip <ETooltip
:open-delay="openDelay" :open-delay="openDelay"
:disabled="$isEEUIApp || windowTouch || tooltipDisabled || isBot" :disabled="$isMobileApp || windowTouch || tooltipDisabled || isBot"
:placement="tooltipPlacement"> :placement="tooltipPlacement">
<div v-if="user" slot="content" class="common-avatar-transfer"> <div v-if="user" slot="content" class="common-avatar-transfer">
<slot/> <slot/>

View File

@ -63,7 +63,7 @@
<Loading v-if="loadIng > 0"/> <Loading v-if="loadIng > 0"/>
<Icon v-else type="ios-search"/> <Icon v-else type="ios-search"/>
</div> </div>
<Form class="search-form" action="javascript:void(0)" @submit.native.prevent="$A.eeuiAppKeyboardHide"> <Form class="search-form" action="javascript:void(0)" @submit.native.prevent="$A.nativeAppKeyboardHide">
<Input <Input
type="search" type="search"
v-model="searchKey" v-model="searchKey"
@ -377,7 +377,7 @@ export default {
} }
this.$emit("on-show-change", v) this.$emit("on-show-change", v)
// //
$A.eeuiAppSetScrollDisabled(v && this.windowPortrait) $A.nativeAppSetScrollDisabled(v && this.windowPortrait)
}, },
searchKey() { searchKey() {

View File

@ -782,7 +782,7 @@ const timezone = require("dayjs/plugin/timezone");
* @returns {string} * @returns {string}
*/ */
reloadUrl() { reloadUrl() {
if ($A.isEEUIApp && $A.isAndroid()) { if ($A.isMobileApp && $A.isAndroid()) {
let url = window.location.href; let url = window.location.href;
let key = '_=' let key = '_='
let reg = new RegExp(key + '\\d+'); let reg = new RegExp(key + '\\d+');
@ -805,7 +805,7 @@ const timezone = require("dayjs/plugin/timezone");
} }
} }
} }
$A.eeuiAppSetUrl(url); $A.nativeAppSetUrl(url);
} else { } else {
window.location.reload(); window.location.reload();
} }

View File

@ -1,381 +0,0 @@
/**
* EEUI App 专用
*/
import {languageName} from "../language";
(function (window) {
const $ = window.$A;
/**
* =============================================================================
* **************************** EEUI App extra *****************************
* =============================================================================
*/
$.extend({
// 获取eeui模块
eeuiModule(name = 'eeui') {
if (typeof requireModuleJs === "function") {
return requireModuleJs(name);
}
return null;
},
// 获取eeui模块Promise
eeuiModulePromise(name = 'eeui') {
return new Promise((resolve, reject) => {
try {
const eeui = $A.eeuiModule(name);
if (!eeui) {
return reject({msg: "module not found"});
}
resolve(eeui);
} catch (e) {
reject({msg: e.message});
}
})
},
// 获取eeui版本号
eeuiAppVersion() {
return $A.eeuiModule()?.getVersion();
},
// 获取本地软件版本号
eeuiAppLocalVersion() {
return $A.eeuiModule()?.getLocalVersion();
},
// Alert
eeuiAppAlert(object, callback) {
if (typeof callback !== "function") callback = _ => {};
$A.eeuiModule()?.alert(object, callback);
},
// Toast
eeuiAppToast(object) {
$A.eeuiModule()?.toast(object);
},
// 相对地址基于当前地址补全
eeuiAppRewriteUrl(val) {
return $A.eeuiModule()?.rewriteUrl(val);
},
// 获取页面信息
eeuiAppGetPageInfo(pageName) {
return $A.eeuiModule()?.getPageInfo(pageName || "");
},
// 打开app新页面
eeuiAppOpenPage(object, callback) {
if (typeof callback !== "function") {
callback = _ => {};
}
if (typeof object.callback === "function") {
callback = object.callback;
delete object.callback
}
$A.eeuiModule()?.openPage(Object.assign({
softInputMode: "resize",
}, object), callback);
},
// 使用系统浏览器打开网页
eeuiAppOpenWeb(url) {
$A.eeuiModule()?.openWeb(url)
},
// 拦截返回按键事件仅支持android、iOS无效
eeuiAppSetPageBackPressed(object, callback) {
if (typeof callback !== "function") callback = _ => {};
$A.eeuiModule()?.setPageBackPressed(object, callback);
},
// 返回手机桌面
eeuiAppGoDesktop() {
$A.eeuiModule()?.goDesktop();
},
// 打开屏幕常亮
eeuiAppKeepScreenOn() {
$A.eeuiModule()?.keepScreenOn();
},
// 关闭屏幕常亮
eeuiAppKeepScreenOff() {
$A.eeuiModule()?.keepScreenOff();
},
// 隐藏软键盘
eeuiAppKeyboardHide() {
$A.eeuiModule()?.keyboardHide();
},
// 给app发送消息
eeuiAppSendMessage(object) {
$A.eeuiModule("webview")?.sendMessage(object);
},
// 设置浏览器地址
eeuiAppSetUrl(url) {
$A.eeuiModule("webview")?.setUrl(url);
},
// 生成webview快照
eeuiAppGetWebviewSnapshot(callback) {
$A.eeuiModule("webview")?.createSnapshot(callback);
},
// 显示webview快照
eeuiAppShowWebviewSnapshot() {
$A.eeuiModule("webview")?.showSnapshot();
},
// 隐藏webview快照
eeuiAppHideWebviewSnapshot() {
$A.eeuiModule("webview")?.hideSnapshot();
},
// 扫码
eeuiAppScan(callback) {
$A.eeuiModule()?.openScaner({}, (res) => {
switch (res.status) {
case "success":
callback(res.text);
break;
}
});
},
// 检查更新
eeuiAppCheckUpdate() {
$A.eeuiModule()?.checkUpdate();
},
// 获取主题名称 light|dark
eeuiAppGetThemeName() {
return $A.eeuiModule()?.getThemeName();
},
// 判断软键盘是否可见
eeuiAppKeyboardStatus() {
return $A.eeuiModule()?.keyboardStatus();
},
// 设置全局变量
eeuiAppSetVariate(key, value) {
$A.eeuiModule()?.setVariate(key, value);
},
// 获取全局变量
eeuiAppGetVariate(key, defaultVal = "") {
return $A.eeuiModule()?.getVariate(key, defaultVal);
},
// 设置缓存数据
eeuiAppSetCachesString(key, value, expired = 0) {
$A.eeuiModule()?.setCachesString(key, value, expired);
},
// 获取缓存数据
eeuiAppGetCachesString(key, defaultVal = "") {
return $A.eeuiModule()?.getCachesString(key, defaultVal);
},
// 是否长按内容震动仅支持android、iOS无效
eeuiAppSetHapticBackEnabled(val) {
$A.eeuiModule("webview").setHapticBackEnabled(val);
},
// 禁止长按选择仅支持android、iOS无效
eeuiAppSetDisabledUserLongClickSelect(val) {
const webview = $A.eeuiModule("webview");
$A.__disabledUserLongClickSelectTimer && clearTimeout($A.__disabledUserLongClickSelectTimer);
if (!/^\d+$/.test(val)) {
webview.setDisabledUserLongClickSelect(val);
return;
}
webview.setDisabledUserLongClickSelect(true);
$A.__disabledUserLongClickSelectTimer = setTimeout(() => {
$A.__disabledUserLongClickSelectTimer = null;
webview.setDisabledUserLongClickSelect(false);
}, val);
},
__disabledUserLongClickSelectTimer: null,
// 复制文本
eeuiAppCopyText(text) {
$A.eeuiModule()?.copyText(text)
},
// 设置是否禁止滚动
eeuiAppSetScrollDisabled(disabled) {
if (disabled) {
$A.__setScrollDisabledNum++
} else {
$A.__setScrollDisabledNum--
}
$A.eeuiModule("webview")?.setScrollEnabled($A.__setScrollDisabledNum <= 0);
},
__setScrollDisabledNum: 0,
// 设置应用程序级别的摇动撤销仅支持iOS、android无效
eeuiAppShakeToEditEnabled(enabled) {
if (enabled) {
$A.eeuiModule()?.shakeToEditOn();
} else {
$A.eeuiModule()?.shakeToEditOff();
}
},
// 获取最新一张照片
eeuiAppGetLatestPhoto(expiration = 60, timeout = 10) {
return new Promise(async (resolve, reject) => {
try {
const eeui = await $A.eeuiModule();
const timer = timeout > 0 ? setTimeout(() => {
reject({msg: "timeout"});
}, timeout * 1000) : null;
eeui.getLatestPhoto(result => {
timer && clearTimeout(timer);
if (
result.status !== 'success' ||
result.thumbnail.width < 10 || !result.thumbnail.base64 ||
result.original.width < 10 || !result.original.path
) {
return reject({msg: result.error || "no photo"});
}
if (expiration > 0 && (result.created + expiration) < $A.dayjs().unix()) {
return reject({msg: "photo expired"});
}
if ($A.__latestPhotoCreated && $A.__latestPhotoCreated === result.created) {
return reject({msg: "photo expired"});
}
$A.__latestPhotoCreated = result.created;
resolve(result);
});
} catch (e) {
reject(e);
}
})
},
__latestPhotoCreated: null,
// 上传照片(通过 eeuiAppGetLatestPhoto 获取到的pathparams 参数:{url,data,headers,path,fieldName}
eeuiAppUploadPhoto(params, timeout = 30) {
return new Promise(async (resolve, reject) => {
try {
const eeui = await $A.eeuiModulePromise();
const timer = timeout > 0 ? setTimeout(() => {
reject({msg: "timeout"});
}, timeout * 1000) : null;
if (!$A.isJson(params)) {
return reject({msg: "params error"});
}
let onReady = null;
if (typeof params.onReady !== "undefined") {
onReady = params.onReady;
delete params.onReady;
}
eeui.uploadPhoto(params, result => {
if (result.status === 'ready') {
typeof onReady === "function" && onReady(result.id)
return
}
timer && clearTimeout(timer);
if (result.status !== 'success') {
return reject({msg: result.error || "upload failed"});
}
if (result.data.ret !== 1) {
return reject({msg: result.data.msg || "upload failed"});
}
resolve(result.data.data);
});
} catch (e) {
reject(e);
}
})
},
// 取消上传照片
eeuiAppCancelUploadPhoto(id) {
return new Promise(async (resolve, reject) => {
try {
const eeui = await $A.eeuiModulePromise();
eeui.cancelUploadPhoto(id, result => {
if (result.status !== 'success') {
return reject({msg: result.error || "cancel failed"});
}
resolve(result);
});
} catch (e) {
reject(e);
}
})
},
// 获取导航栏和状态栏高度
eeuiAppGetSafeAreaInsets() {
return new Promise(async (resolve, reject) => {
try {
const eeui = await $A.eeuiModulePromise();
eeui.getSafeAreaInsets(result => {
if (result.status !== 'success') {
return reject({msg: result.error || "get failed"});
}
resolve(result);
});
} catch (e) {
reject(e);
}
})
},
// 获取当前语言
eeuiAppConvertLanguage() {
const specialMappings = {
"zh": "zh-Hans",
"zh-CHT": "zh-Hant"
};
return specialMappings[languageName] || languageName;
},
// 获取设备信息
eeuiAppGetDeviceInfo() {
return new Promise(async (resolve, reject) => {
try {
const eeui = await $A.eeuiModulePromise();
eeui.getDeviceInfo(result => {
if (result.status !== 'success') {
return reject({msg: result.error || "get failed"});
}
resolve(result);
});
} catch (e) {
reject(e);
}
})
},
// 判断是否窗口化
eeuiAppIsWindowed() {
return new Promise(async resolve => {
try {
const eeui = await $A.eeuiModulePromise();
resolve(eeui.isFullscreen() === false || eeui.isFullscreen() === 0);
} catch (e) {
resolve(false);
}
})
}
});
window.$A = $;
})(window);

194
resources/assets/js/functions/native-app.js vendored Executable file
View File

@ -0,0 +1,194 @@
/**
* Native App 桥接替代旧 functions/eeui.js
*
* 底层从 weex requireModuleJs 切换为新 RN 桥接 window.__nativeBridgesrc/bridge/injected.ts 注入
* 方法名规则$A.nativeAppXxx(args) __nativeBridge.call('xxx', args)其中 xxx 为首字母小写
*
* 契约见 resources/mobile/src/bridge/CONTRACT.md
*/
import {languageName} from "../language";
(function (window) {
const $ = window.$A;
/** 通用调用入口:返回 Promise桥接未就绪则 resolve undefined避免抛错炸主流程 */
function call(method, args) {
const bridge = window.__nativeBridge;
if (!bridge || typeof bridge.call !== "function") {
return Promise.resolve(undefined);
}
return bridge.call(method, args === undefined ? null : args);
}
/** native method
* 注意所有桥接调用本质是异步同步方法目前用兜底默认值返回 */
function syncDefault(_method, defaultValue) { return defaultValue; }
$.extend({
// === 设备/系统 ===
nativeAppVersion() { return syncDefault('getAppVersion', undefined); },
nativeAppVersionAsync() { return call('getAppVersion'); },
nativeAppLocalVersion() { return syncDefault('getAppLocalVersion', 0); },
nativeAppLocalVersionAsync() { return call('getAppLocalVersion'); },
nativeAppGetPageInfo() { return {}; },
nativeAppGetThemeName() { return syncDefault('getThemeName', undefined); },
nativeAppKeyboardStatus() { return syncDefault('keyboardStatus', undefined); },
nativeAppRewriteUrl(val) { return val; },
// === UI 容器控制 ===
nativeAppAlert(object, callback) {
if (typeof callback !== "function") callback = _ => {};
call('alert', object).then(callback).catch(callback);
},
nativeAppToast(object) { call('toast', typeof object === 'string' ? { message: object } : object); },
nativeAppKeyboardHide() { call('keyboardHide'); },
nativeAppKeepScreenOn() { call('keepScreenOn'); },
nativeAppKeepScreenOff() { call('keepScreenOff'); },
nativeAppSetPageBackPressed(object, callback) {
if (typeof callback !== "function") callback = _ => {};
// 旧契约:原生回调由 setPageBackPressed 触发;新契约用全局事件 __onBackPressed
window.__onBackPressed = callback;
call('setPageBackPressed', object);
},
nativeAppGoDesktop() { call('goDesktop'); },
nativeAppSetHapticBackEnabled(val) { call('setHapticBackEnabled', !!val); },
nativeAppSetDisabledUserLongClickSelect(val) {
$.__disabledUserLongClickSelectTimer && clearTimeout($.__disabledUserLongClickSelectTimer);
if (!/^\d+$/.test(val)) {
call('setScrollDisabled', !!val);
return;
}
call('setScrollDisabled', true);
$.__disabledUserLongClickSelectTimer = setTimeout(() => {
$.__disabledUserLongClickSelectTimer = null;
call('setScrollDisabled', false);
}, parseInt(val));
},
__disabledUserLongClickSelectTimer: null,
nativeAppSetScrollDisabled(disabled) {
if (disabled) {
$.__setScrollDisabledNum++
} else {
$.__setScrollDisabledNum--
}
call('setScrollDisabled', $.__setScrollDisabledNum > 0);
},
__setScrollDisabledNum: 0,
nativeAppShakeToEditEnabled(_enabled) { /* iOS 摇动撤销在 RN 由系统默认支持no-op */ },
// === 存储 ===
nativeAppSetVariate(key, value) { call('setVariate', { key, value }); },
nativeAppGetVariate(_key, defaultVal = "") {
// 异步返回;同步签名兼容兜底(不推荐使用)
return defaultVal;
},
nativeAppGetVariateAsync(key, defaultVal = "") {
return call('getVariate', { key, defaultVal });
},
nativeAppSetCachesString(key, value, expired = 0) { call('setCache', { key, value, expired }); },
nativeAppGetCachesString(_key, defaultVal = "") { return defaultVal; },
nativeAppGetCachesStringAsync(key, defaultVal = "") {
return call('getCache', { key, defaultVal });
},
// === 媒体 ===
nativeAppScan(callback) {
call('scan').then((text) => { typeof callback === 'function' && callback(text); });
},
nativeAppCopyText(text) { call('copyText', text); },
nativeAppGetLatestPhoto(expiration = 60, _timeout = 10) {
return call('getLatestPhoto', { expiration }).then((res) => {
// 旧契约外形:{thumbnail:{base64,width,height}, original:{path,width,height}}
// 新最小实现只返回 {path,width,height,created},包装为兼容形态。
if (!res || !res.path) return Promise.reject({ msg: 'no photo' });
return {
thumbnail: { base64: '', width: res.width, height: res.height },
original: { path: res.path, width: res.width, height: res.height },
created: res.created,
};
});
},
nativeAppUploadPhoto(params, _timeout = 30) {
const onReady = params && params.onReady;
if (typeof onReady === 'function') delete params.onReady;
return call('uploadPhoto', params).then((data) => {
if (typeof onReady === 'function') onReady();
return data;
});
},
nativeAppCancelUploadPhoto(id) { return call('cancelUploadPhoto', { id }); },
// === 交互/外链 ===
nativeAppOpenPage(object, callback) {
if (typeof callback !== "function") callback = _ => {};
if (typeof object.callback === "function") {
callback = object.callback;
delete object.callback
}
call('openPage', object).then(callback).catch(callback);
},
nativeAppOpenWeb(url) { call('openWeb', url); },
nativeAppSetUrl(url) { call('setUrl', url); },
nativeAppGetWebviewSnapshot(callback) { typeof callback === 'function' && callback({status: 'noop'}); },
nativeAppShowWebviewSnapshot() { /* 新移动端不再用 weex 快照机制 */ },
nativeAppHideWebviewSnapshot() { /* 同上 */ },
nativeAppCheckUpdate() { call('checkUpdate'); },
// === 信息(异步)===
nativeAppGetDeviceInfo() {
return call('getDeviceInfo').then((info) => {
if (!info) return Promise.reject({ msg: 'no device info' });
return info;
});
},
nativeAppGetSafeAreaInsets() {
return call('getSafeAreaInsets').then((insets) => {
if (!insets) return Promise.reject({ msg: 'no safe area' });
return { status: 'success', top: insets.top, bottom: insets.bottom, data: insets };
});
},
nativeAppIsWindowed() { return call('isWindowed').then((v) => !!v); },
// === 平台无关:纯前端语言映射(不走桥接) ===
nativeAppConvertLanguage() {
const specialMappings = {"zh": "zh-Hans", "zh-CHT": "zh-Hant"};
return specialMappings[languageName] || languageName;
},
// === sendMessage拆解为独立 method ===
// 旧 $A.nativeAppSendMessage({action:'xxx', ...}) 全部路由到对应桥接 method。
nativeAppSendMessage(object) {
if (!object || typeof object !== 'object') return;
const action = object.action;
const rest = Object.assign({}, object); delete rest.action;
switch (action) {
case 'updateTheme': return call('updateTheme', rest);
case 'windowSize': return call('windowSize', rest);
case 'setBadgeNum':
case 'setBdageNotify': return call('setBadge', { count: parseInt(rest.bdage) || 0 });
case 'setVibrate': return call('vibrate', { time: parseInt(rest.time) || 0 });
case 'callTel': return call('callTel', { tel: rest.tel });
case 'picturePreview': return call('picturePreview', rest);
case 'videoPreview': return call('videoPreview', rest);
case 'clearAllNotify': return call('clearAllNotify');
case 'gotoSetting': return call('gotoNotificationSetting');
case 'getNotificationPermission': return call('getNotificationPermission');
case 'startMeeting': return call('startMeeting', rest);
case 'updateMeetingInfo': return call('updateMeetingInfo', rest);
// 推送注册:新链路 — 不再走 sendMessage外层逻辑改用 registerPush
// 旧 action 静默忽略以兼容尚未迁移的调用点
case 'initApp':
case 'setUmengAlias':
case 'delUmengAlias':
return;
default:
// 未识别 action调试时打日志避免静默失败
if (window.systemInfo && window.systemInfo.debug === 'yes') {
console.warn('[nativeApp] unhandled sendMessage action:', action, rest);
}
}
},
});
window.$A = $;
})(window);

View File

@ -881,7 +881,7 @@ import {convertLocalResourcePath} from "../components/Replace/utils";
config.onCancel(); config.onCancel();
} }
}; };
$A.eeuiAppKeyboardHide() $A.nativeAppKeyboardHide()
$A.Modal.confirm({ $A.Modal.confirm({
render: (h) => { render: (h) => {
return h('div', [ return h('div', [
@ -958,7 +958,7 @@ import {convertLocalResourcePath} from "../components/Replace/utils";
}) })
} }
} }
$A.eeuiAppKeyboardHide() $A.nativeAppKeyboardHide()
$A.Modal.confirm($A.modalConfig(config)); $A.Modal.confirm($A.modalConfig(config));
}, },
@ -970,7 +970,7 @@ import {convertLocalResourcePath} from "../components/Replace/utils";
setTimeout(() => { $A.modalSuccess(config) }, millisecond); setTimeout(() => { $A.modalSuccess(config) }, millisecond);
return; return;
} }
$A.eeuiAppKeyboardHide() $A.nativeAppKeyboardHide()
$A.Modal.success($A.modalConfig(config)); $A.Modal.success($A.modalConfig(config));
}, },
@ -982,7 +982,7 @@ import {convertLocalResourcePath} from "../components/Replace/utils";
setTimeout(() => { $A.modalInfo(config) }, millisecond); setTimeout(() => { $A.modalInfo(config) }, millisecond);
return; return;
} }
$A.eeuiAppKeyboardHide() $A.nativeAppKeyboardHide()
$A.Modal.info($A.modalConfig(config)); $A.Modal.info($A.modalConfig(config));
}, },
@ -997,7 +997,7 @@ import {convertLocalResourcePath} from "../components/Replace/utils";
setTimeout(() => { $A.modalWarning(config) }, millisecond); setTimeout(() => { $A.modalWarning(config) }, millisecond);
return; return;
} }
$A.eeuiAppKeyboardHide() $A.nativeAppKeyboardHide()
$A.Modal.warning($A.modalConfig(config)); $A.Modal.warning($A.modalConfig(config));
}, },
@ -1012,7 +1012,7 @@ import {convertLocalResourcePath} from "../components/Replace/utils";
setTimeout(() => { $A.modalError(config) }, millisecond); setTimeout(() => { $A.modalError(config) }, millisecond);
return; return;
} }
$A.eeuiAppKeyboardHide() $A.nativeAppKeyboardHide()
$A.Modal.error($A.modalConfig(config)); $A.Modal.error($A.modalConfig(config));
}, },
@ -1020,7 +1020,7 @@ import {convertLocalResourcePath} from "../components/Replace/utils";
if (msg === false) { if (msg === false) {
return; return;
} }
$A.eeuiAppKeyboardHide() $A.nativeAppKeyboardHide()
alert($A.L(msg)); alert($A.L(msg));
}, },
@ -1273,8 +1273,8 @@ import {convertLocalResourcePath} from "../components/Replace/utils";
autoDarkMode() { autoDarkMode() {
let darkScheme = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches let darkScheme = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches
if ($A.isEEUIApp) { if ($A.isMobileApp) {
darkScheme = $A.eeuiAppGetThemeName() === "dark" darkScheme = $A.nativeAppGetThemeName() === "dark"
} }
if (darkScheme) { if (darkScheme) {
this.enableDarkMode() this.enableDarkMode()

View File

@ -6,7 +6,7 @@
<div class="login-box"> <div class="login-box">
<div class="login-mode-switch"> <div class="login-mode-switch">
<div class="login-mode-switch-box"> <div class="login-mode-switch-box">
<ETooltip :disabled="$isEEUIApp || windowTouch" :content="$L(loginMode=='qrcode' ? '帐号登录' : '扫码登录')" placement="left"> <ETooltip :disabled="$isMobileApp || windowTouch" :content="$L(loginMode=='qrcode' ? '帐号登录' : '扫码登录')" placement="left">
<span class="login-mode-switch-icon no-dark-content" @click="switchLoginMode"> <span class="login-mode-switch-icon no-dark-content" @click="switchLoginMode">
<svg v-if="loginMode=='qrcode'" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" data-icon="PcOutlined"><path d="M23 16a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h18a2 2 0 0 1 2 2v12ZM21 4H3v9h18V4ZM3 15v1h18v-1H3Zm3 6a1 1 0 0 1 1-1h10a1 1 0 1 1 0 2H7a1 1 0 0 1-1-1Z" fill="currentColor"></path></svg> <svg v-if="loginMode=='qrcode'" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" data-icon="PcOutlined"><path d="M23 16a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h18a2 2 0 0 1 2 2v12ZM21 4H3v9h18V4ZM3 15v1h18v-1H3Zm3 6a1 1 0 0 1 1-1h10a1 1 0 1 1 0 2H7a1 1 0 0 1-1-1Z" fill="currentColor"></path></svg>
<svg v-else viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" data-icon="QrOutlined"><path d="M6.5 7.5a1 1 0 0 1 1-1h1a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1h-1a1 1 0 0 1-1-1v-1Z" fill="currentColor"></path><path d="M4.5 2.5c-1.1 0-2 .9-2 2v7c0 1.1.9 2 2 2h7c1.1 0 2-.9 2-2v-7c0-1.1-.9-2-2-2h-7Zm0 2h7v7h-7v-7ZM11 16a1 1 0 1 1 2 0 1 1 0 0 1-2 0Zm0 3.5a1 1 0 1 1 2 0v1a1 1 0 1 1-2 0v-1Zm4-7.5a1 1 0 1 1 2 0 1 1 0 0 1-2 0Zm3.5 0a1 1 0 0 1 1-1h1a1 1 0 1 1 0 2h-1a1 1 0 0 1-1-1ZM15 17c0-1.1.9-2 2-2h2.5c1.1 0 2 .9 2 2v2.5c0 1.1-.9 2-2 2H17c-1.1 0-2-.9-2-2V17Zm4.5 0H17v2.5h2.5V17Zm-15-2c-1.1 0-2 .9-2 2v2.5c0 1.1.9 2 2 2H7c1.1 0 2-.9 2-2V17c0-1.1-.9-2-2-2H4.5Zm0 2H7v2.5H4.5V17ZM15 4.5c0-1.1.9-2 2-2h2.5c1.1 0 2 .9 2 2V7c0 1.1-.9 2-2 2H17c-1.1 0-2-.9-2-2V4.5Zm4.5 0H17V7h2.5V4.5Z" fill="currentColor"></path></svg> <svg v-else viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" data-icon="QrOutlined"><path d="M6.5 7.5a1 1 0 0 1 1-1h1a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1h-1a1 1 0 0 1-1-1v-1Z" fill="currentColor"></path><path d="M4.5 2.5c-1.1 0-2 .9-2 2v7c0 1.1.9 2 2 2h7c1.1 0 2-.9 2-2v-7c0-1.1-.9-2-2-2h-7Zm0 2h7v7h-7v-7ZM11 16a1 1 0 1 1 2 0 1 1 0 0 1-2 0Zm0 3.5a1 1 0 1 1 2 0v1a1 1 0 1 1-2 0v-1Zm4-7.5a1 1 0 1 1 2 0 1 1 0 0 1-2 0Zm3.5 0a1 1 0 0 1 1-1h1a1 1 0 1 1 0 2h-1a1 1 0 0 1-1-1ZM15 17c0-1.1.9-2 2-2h2.5c1.1 0 2 .9 2 2v2.5c0 1.1-.9 2-2 2H17c-1.1 0-2-.9-2-2V17Zm4.5 0H17v2.5h2.5V17Zm-15-2c-1.1 0-2 .9-2 2v2.5c0 1.1.9 2 2 2H7c1.1 0 2-.9 2-2V17c0-1.1-.9-2-2-2H4.5Zm0 2H7v2.5H4.5V17ZM15 4.5c0-1.1.9-2 2-2h2.5c1.1 0 2 .9 2 2V7c0 1.1-.9 2-2 2H17c-1.1 0-2-.9-2-2V4.5Zm4.5 0H17V7h2.5V4.5Z" fill="currentColor"></path></svg>
@ -205,7 +205,7 @@ export default {
}, },
async mounted() { async mounted() {
this.privacyShow = !!this.$isEEUIApp && (await $A.IDBString("cachePrivacyShow")) !== "no"; this.privacyShow = !!this.$isMobileApp && (await $A.IDBString("cachePrivacyShow")) !== "no";
this.email = await $A.IDBString("cacheLoginEmail") || '' this.email = await $A.IDBString("cacheLoginEmail") || ''
// //
if (this.$isSoftware) { if (this.$isSoftware) {
@ -497,7 +497,7 @@ export default {
this.chackServerUrl().catch(_ => {}); this.chackServerUrl().catch(_ => {});
$A.IDBSet("cachePrivacyShow", "no") $A.IDBSet("cachePrivacyShow", "no")
} else { } else {
$A.eeuiAppGoDesktop() $A.nativeAppGoDesktop()
} }
}, },

View File

@ -180,7 +180,7 @@
<Draggable <Draggable
:list="projectDraggableList" :list="projectDraggableList"
:animation="150" :animation="150"
:disabled="$isEEUIApp || windowTouch || !!projectKeyValue || ownerProjectTabsVisible" :disabled="$isMobileApp || windowTouch || !!projectKeyValue || ownerProjectTabsVisible"
tag="ul" tag="ul"
item-key="id" item-key="id"
draggable="li:not(.pinned)" draggable="li:not(.pinned)"
@ -258,7 +258,7 @@
<Loading v-if="projectKeyLoading > 0"/> <Loading v-if="projectKeyLoading > 0"/>
<Icon v-else type="ios-search" /> <Icon v-else type="ios-search" />
</div> </div>
<Form class="search-form" action="javascript:void(0)" @submit.native.prevent="$A.eeuiAppKeyboardHide"> <Form class="search-form" action="javascript:void(0)" @submit.native.prevent="$A.nativeAppKeyboardHide">
<Input type="search" v-model="projectKeyValue" :placeholder="$L(`共${projectTotal || cacheProjects.length}个项目,搜索...`)" clearable/> <Input type="search" v-model="projectKeyValue" :placeholder="$L(`共${projectTotal || cacheProjects.length}个项目,搜索...`)" clearable/>
</Form> </Form>
</div> </div>
@ -769,7 +769,7 @@ export default {
* @returns {boolean} * @returns {boolean}
*/ */
showDownloadClient() { showDownloadClient() {
return !this.$Electron && !this.$isEEUIApp && !!this.clientDownloadUrl return !this.$Electron && !this.$isMobileApp && !!this.clientDownloadUrl
}, },
/** /**
@ -1562,7 +1562,7 @@ export default {
if (silence) { if (silence) {
return; // return; //
} }
if (!this.natificationReady && !this.$isEEUIApp) { if (!this.natificationReady && !this.$isMobileApp) {
return; // return; //
} }
if (this.windowActive && data.dialog_id === $A.last(this.dialogIns)?.dialog_id) { if (this.windowActive && data.dialog_id === $A.last(this.dialogIns)?.dialog_id) {
@ -1593,7 +1593,7 @@ export default {
const notificationFuncB = (title, body, userimg) => { const notificationFuncB = (title, body, userimg) => {
if (this.__notificationId === id) { if (this.__notificationId === id) {
this.__notificationId = null this.__notificationId = null
if (this.$isEEUIApp) { if (this.$isMobileApp) {
emitter.emit('openMobileNotification', { emitter.emit('openMobileNotification', {
userid: userid, userid: userid,
title, title,

View File

@ -552,7 +552,7 @@ export default {
{value: "vote", label: "群投票", sort: 100}, {value: "vote", label: "群投票", sort: 100},
{value: "addProject", label: "创建项目", sort: 110}, {value: "addProject", label: "创建项目", sort: 110},
{value: "addTask", label: "添加任务", sort: 120}, {value: "addTask", label: "添加任务", sort: 120},
{value: "scan", label: "扫一扫", sort: 130, show: $A.isEEUIApp}, {value: "scan", label: "扫一扫", sort: 130, show: $A.isMobileApp},
// //
{type: 'admin', value: "ldap", label: "LDAP", sort: 160, show: this.userIsAdmin}, {type: 'admin', value: "ldap", label: "LDAP", sort: 160, show: this.userIsAdmin},
@ -1085,7 +1085,7 @@ export default {
this.appPushShow = true; this.appPushShow = true;
break; break;
case 'scan': case 'scan':
$A.eeuiAppScan(this.scanResult); $A.nativeAppScan(this.scanResult);
break; break;
case 'word-chain': case 'word-chain':
case 'vote': case 'vote':

View File

@ -79,24 +79,24 @@
:visibleArrow="false" :visibleArrow="false"
placement="top" placement="top"
popperClass="chat-input-emoji-popover"> popperClass="chat-input-emoji-popover">
<ETooltip slot="reference" ref="emojiTip" :disabled="$isEEUIApp || windowTouch || showEmoji" placement="top" :enterable="false" :content="$L('表情')"> <ETooltip slot="reference" ref="emojiTip" :disabled="$isMobileApp || windowTouch || showEmoji" placement="top" :enterable="false" :content="$L('表情')">
<i class="taskfont">&#xe7ad;</i> <i class="taskfont">&#xe7ad;</i>
</ETooltip> </ETooltip>
<ChatEmoji v-if="showEmoji" @on-select="onSelectEmoji" :searchKey="emojiQuickKey"/> <ChatEmoji v-if="showEmoji" @on-select="onSelectEmoji" :searchKey="emojiQuickKey"/>
</EPopover> </EPopover>
<ETooltip v-else ref="emojiTip" :disabled="$isEEUIApp || windowTouch || showEmoji" placement="top" :enterable="false" :content="$L('表情')"> <ETooltip v-else ref="emojiTip" :disabled="$isMobileApp || windowTouch || showEmoji" placement="top" :enterable="false" :content="$L('表情')">
<i class="taskfont" @click="showEmoji=!showEmoji">&#xe7ad;</i> <i class="taskfont" @click="showEmoji=!showEmoji">&#xe7ad;</i>
</ETooltip> </ETooltip>
</li> </li>
<!-- @ # --> <!-- @ # -->
<li> <li>
<ETooltip placement="top" :disabled="$isEEUIApp || windowTouch" :enterable="false" :content="$L('选择成员')"> <ETooltip placement="top" :disabled="$isMobileApp || windowTouch" :enterable="false" :content="$L('选择成员')">
<i class="taskfont" @click="onToolbar('user')">&#xe78f;</i> <i class="taskfont" @click="onToolbar('user')">&#xe78f;</i>
</ETooltip> </ETooltip>
</li> </li>
<li> <li>
<ETooltip placement="top" :disabled="$isEEUIApp || windowTouch" :enterable="false" :content="$L('选择任务')"> <ETooltip placement="top" :disabled="$isMobileApp || windowTouch" :enterable="false" :content="$L('选择任务')">
<i class="taskfont" @click="onToolbar('task')">&#xe7d6;</i> <i class="taskfont" @click="onToolbar('task')">&#xe7d6;</i>
</ETooltip> </ETooltip>
</li> </li>
@ -109,7 +109,7 @@
:visibleArrow="false" :visibleArrow="false"
placement="top" placement="top"
popperClass="chat-input-more-popover"> popperClass="chat-input-more-popover">
<ETooltip slot="reference" ref="moreTip" :disabled="$isEEUIApp || windowTouch || showMore" placement="top" :enterable="false" :content="$L('展开')"> <ETooltip slot="reference" ref="moreTip" :disabled="$isMobileApp || windowTouch || showMore" placement="top" :enterable="false" :content="$L('展开')">
<i class="taskfont">&#xe790;</i> <i class="taskfont">&#xe790;</i>
</ETooltip> </ETooltip>
<template v-if="!isAiBot"> <template v-if="!isAiBot">
@ -177,7 +177,7 @@
trigger="manual" trigger="manual"
placement="top" placement="top"
popperClass="chat-input-more-popover"> popperClass="chat-input-more-popover">
<ETooltip slot="reference" ref="sendTip" placement="top" :disabled="$isEEUIApp || windowTouch || showMenu" :enterable="false" :content="$L(sendContent)"> <ETooltip slot="reference" ref="sendTip" placement="top" :disabled="$isMobileApp || windowTouch || showMenu" :enterable="false" :content="$L(sendContent)">
<div v-if="loading"> <div v-if="loading">
<div class="chat-load"> <div class="chat-load">
<Loading/> <Loading/>
@ -562,7 +562,7 @@ export default {
} }
}, 1000) }, 1000)
// //
if (this.$isEEUIApp) { if (this.$isMobileApp) {
window.__onPermissionRequest = (type, result) => { window.__onPermissionRequest = (type, result) => {
if (type === 'recordAudio' && result === false) { if (type === 'recordAudio' && result === false) {
// Android // Android
@ -609,7 +609,7 @@ export default {
...mapGetters(['getDialogDraft', 'getDialogQuote']), ...mapGetters(['getDialogDraft', 'getDialogQuote']),
isEnterSend({cacheKeyboard}) { isEnterSend({cacheKeyboard}) {
if (this.$isEEUIApp) { if (this.$isMobileApp) {
return cacheKeyboard.send_button_app === 'enter'; return cacheKeyboard.send_button_app === 'enter';
} else { } else {
return cacheKeyboard.send_button_desktop === 'enter'; return cacheKeyboard.send_button_desktop === 'enter';
@ -624,7 +624,7 @@ export default {
}, },
canCall() { canCall() {
return this.dialogData.type === 'user' && !this.dialogData.bot && this.$isEEUIApp return this.dialogData.type === 'user' && !this.dialogData.bot && this.$isMobileApp
}, },
canAnon() { canAnon() {
@ -838,7 +838,7 @@ export default {
if (this.isAiBot) { if (this.isAiBot) {
return return
} }
$A.eeuiAppGetLatestPhoto().then(({thumbnail, original}) => { $A.nativeAppGetLatestPhoto().then(({thumbnail, original}) => {
const size = Math.min(120, Math.max(100, this.$refs.moreFull.clientWidth)); const size = Math.min(120, Math.max(100, this.$refs.moreFull.clientWidth));
this.maybePhotoStyle = { this.maybePhotoStyle = {
width: size + 'px', width: size + 'px',
@ -1038,7 +1038,7 @@ export default {
}, },
selectionPlugin: { selectionPlugin: {
onTextSelected: (selectedText) => { onTextSelected: (selectedText) => {
if (this.$isEEUIApp || this.windowTouch) { if (this.$isMobileApp || this.windowTouch) {
return return
} }
this.selectedText = !!selectedText.trim() this.selectedText = !!selectedText.trim()
@ -1170,7 +1170,7 @@ export default {
// Set enterkeyhint // Set enterkeyhint
this.$nextTick(_ => { this.$nextTick(_ => {
if (this.$isEEUIApp && this.cacheKeyboard.send_button_app === 'enter') { if (this.$isMobileApp && this.cacheKeyboard.send_button_app === 'enter') {
this.quill.root.setAttribute('enterkeyhint', 'send') this.quill.root.setAttribute('enterkeyhint', 'send')
} }
}) })

View File

@ -94,7 +94,7 @@ export default {
show(v) { show(v) {
this.$store.state.dialogModalShow = v; this.$store.state.dialogModalShow = v;
$A.eeuiAppSetScrollDisabled(v && this.windowPortrait) $A.nativeAppSetScrollDisabled(v && this.windowPortrait)
} }
}, },

View File

@ -142,7 +142,7 @@
<Loading v-if="searchLoad > 0"/> <Loading v-if="searchLoad > 0"/>
<Icon v-else type="ios-search" /> <Icon v-else type="ios-search" />
</div> </div>
<Form class="search-form" action="javascript:void(0)" @submit.native.prevent="$A.eeuiAppKeyboardHide"> <Form class="search-form" action="javascript:void(0)" @submit.native.prevent="$A.nativeAppKeyboardHide">
<Input type="search" ref="searchInput" v-model="searchKey" :placeholder="$L('搜索消息')" @on-keyup="onSearchKeyup" clearable/> <Input type="search" ref="searchInput" v-model="searchKey" :placeholder="$L('搜索消息')" @on-keyup="onSearchKeyup" clearable/>
<div v-if="searchLoad === 0 && searchResult.length > 0" class="search-total">{{searchLocation}}/{{searchResult.length}}</div> <div v-if="searchLoad === 0 && searchResult.length > 0" class="search-total">{{searchLocation}}/{{searchResult.length}}</div>
</Form> </Form>
@ -1892,7 +1892,7 @@ export default {
} }
this.tempMsgs.push(tempMsg) this.tempMsgs.push(tempMsg)
// //
$A.eeuiAppUploadPhoto({ $A.nativeAppUploadPhoto({
url: $A.apiUrl('dialog/msg/sendfile'), url: $A.apiUrl('dialog/msg/sendfile'),
data: { data: {
dialog_id: tempMsg.dialog_id, dialog_id: tempMsg.dialog_id,
@ -2432,7 +2432,7 @@ export default {
onTouchStart() { onTouchStart() {
// Android // Android
if (this.keyboardShow) { if (this.keyboardShow) {
$A.eeuiAppSetDisabledUserLongClickSelect(500); $A.nativeAppSetDisabledUserLongClickSelect(500);
} }
}, },
@ -2600,7 +2600,7 @@ export default {
spinner: 600, spinner: 600,
}).then(({data}) => { }).then(({data}) => {
if (data.tel) { if (data.tel) {
$A.eeuiAppSendMessage({ $A.nativeAppSendMessage({
action: 'callTel', action: 'callTel',
tel: data.tel tel: data.tel
}); });
@ -3547,7 +3547,7 @@ export default {
const {file_uid, file_method} = this.operateItem const {file_uid, file_method} = this.operateItem
if (file_method === "photo") { if (file_method === "photo") {
try { try {
await $A.eeuiAppCancelUploadPhoto(file_uid) await $A.nativeAppCancelUploadPhoto(file_uid)
} catch (e) { } catch (e) {
// //
} }
@ -3932,7 +3932,7 @@ export default {
title, title,
titleFixed: true, titleFixed: true,
}); });
} else if (this.$isEEUIApp) { } else if (this.$isMobileApp) {
this.$store.dispatch('openAppChildPage', { this.$store.dispatch('openAppChildPage', {
pageType: 'app', pageType: 'app',
pageTitle: title, pageTitle: title,
@ -4567,7 +4567,7 @@ export default {
autoScrollInto() { autoScrollInto() {
return this.location === "modal" return this.location === "modal"
&& this.$isEEUIApp && this.$isMobileApp
&& this.windowPortrait && this.windowPortrait
&& this.$refs.input?.isFocus && this.$refs.input?.isFocus
}, },

View File

@ -55,14 +55,14 @@
</Dropdown> </Dropdown>
<template v-if="!file.only_view"> <template v-if="!file.only_view">
<div class="header-icons"> <div class="header-icons">
<ETooltip :disabled="$isEEUIApp || windowTouch" :content="$L('文件链接')"> <ETooltip :disabled="$isMobileApp || windowTouch" :content="$L('文件链接')">
<div class="header-icon" @click="handleClick('link')"><i class="taskfont">&#xe785;</i></div> <div class="header-icon" @click="handleClick('link')"><i class="taskfont">&#xe785;</i></div>
</ETooltip> </ETooltip>
<EPopover v-model="historyShow" trigger="click"> <EPopover v-model="historyShow" trigger="click">
<div class="file-content-history"> <div class="file-content-history">
<FileHistory :value="historyShow" :file="file" @on-restore="onRestoreHistory"/> <FileHistory :value="historyShow" :file="file" @on-restore="onRestoreHistory"/>
</div> </div>
<ETooltip slot="reference" ref="historyTip" :disabled="$isEEUIApp || windowTouch || historyShow" :content="$L('历史版本')"> <ETooltip slot="reference" ref="historyTip" :disabled="$isMobileApp || windowTouch || historyShow" :content="$L('历史版本')">
<div class="header-icon"><i class="taskfont">&#xe71d;</i></div> <div class="header-icon"><i class="taskfont">&#xe71d;</i></div>
</ETooltip> </ETooltip>
</EPopover> </EPopover>

View File

@ -187,7 +187,7 @@ export default {
title, title,
titleFixed: true, titleFixed: true,
}); });
} else if (this.$isEEUIApp) { } else if (this.$isMobileApp) {
this.$store.dispatch('openAppChildPage', { this.$store.dispatch('openAppChildPage', {
pageType: 'app', pageType: 'app',
pageTitle: title, pageTitle: title,

View File

@ -298,7 +298,7 @@ export default {
async onOpen(isDirect = false) { async onOpen(isDirect = false) {
// //
let isMeeting = false; let isMeeting = false;
if ($A.isEEUIApp) { if ($A.isMobileApp) {
isMeeting = this.appMeetingShow; isMeeting = this.appMeetingShow;
} else if ($A.Electron) { } else if ($A.Electron) {
const meetingWindow = await $A.Electron.sendAsync("getChildWindow", 'meeting-window') const meetingWindow = await $A.Electron.sendAsync("getChildWindow", 'meeting-window')
@ -349,7 +349,7 @@ export default {
delete data.name; delete data.name;
delete data.msgs; delete data.msgs;
// App 使 // App 使
if ($A.isEEUIApp) { if ($A.isMobileApp) {
loader(true); loader(true);
this.loadNum = 0 this.loadNum = 0
this.loadTimer && clearInterval(this.loadTimer) this.loadTimer && clearInterval(this.loadTimer)
@ -360,7 +360,7 @@ export default {
clearInterval(this.loadTimer) clearInterval(this.loadTimer)
loader(false) loader(false)
}, 1000) }, 1000)
$A.eeuiAppSendMessage({ $A.nativeAppSendMessage({
action: 'startMeeting', action: 'startMeeting',
meetingParams: { meetingParams: {
name: this.addData.name, name: this.addData.name,

View File

@ -3,7 +3,7 @@
<div :id="id" class="player"> <div :id="id" class="player">
<div class="player-bg" :style="playerStyle"></div> <div class="player-bg" :style="playerStyle"></div>
</div> </div>
<ETooltip :disabled="$isEEUIApp || windowTouch || !username"> <ETooltip :disabled="$isMobileApp || windowTouch || !username">
<div slot="content"> <div slot="content">
{{username}} {{username}}
</div> </div>

View File

@ -7,7 +7,7 @@
<Loading v-if="loadProjects > 0"/> <Loading v-if="loadProjects > 0"/>
<Icon v-else type="ios-search" /> <Icon v-else type="ios-search" />
</div> </div>
<Form class="search-form" action="javascript:void(0)" @submit.native.prevent="$A.eeuiAppKeyboardHide"> <Form class="search-form" action="javascript:void(0)" @submit.native.prevent="$A.nativeAppKeyboardHide">
<Input type="search" v-model="projectKeyValue" :placeholder="$L(loadProjects > 0 ? '更新中...' : '搜索')" clearable/> <Input type="search" v-model="projectKeyValue" :placeholder="$L(loadProjects > 0 ? '更新中...' : '搜索')" clearable/>
</Form> </Form>
</div> </div>

View File

@ -224,7 +224,7 @@ export default {
path: path, path: path,
title: this.$L(title), title: this.$L(title),
}); });
} else if (this.$isEEUIApp) { } else if (this.$isMobileApp) {
e.preventDefault() e.preventDefault()
this.$store.dispatch('openAppChildPage', { this.$store.dispatch('openAppChildPage', {
pageType: 'app', pageType: 'app',

View File

@ -20,7 +20,7 @@
</li> </li>
<template v-if="!(windowWidth <= 980 || projectData.cacheParameter.chat) && projectUser.length > 0" v-for="item in projectUser"> <template v-if="!(windowWidth <= 980 || projectData.cacheParameter.chat) && projectUser.length > 0" v-for="item in projectUser">
<li v-if="item.userid === -1" class="more"> <li v-if="item.userid === -1" class="more">
<ETooltip :disabled="$isEEUIApp || windowTouch" :content="$L('共' + (projectData.project_user.length) + '个成员')"> <ETooltip :disabled="$isMobileApp || windowTouch" :content="$L('共' + (projectData.project_user.length) + '个成员')">
<Icon type="ios-more"/> <Icon type="ios-more"/>
</ETooltip> </ETooltip>
</li> </li>
@ -33,7 +33,7 @@
</ul> </ul>
</li> </li>
<li v-if="!projectData.department_readonly" class="project-icon" @click="addTaskOpen(0)"> <li v-if="!projectData.department_readonly" class="project-icon" @click="addTaskOpen(0)">
<ETooltip :disabled="$isEEUIApp || windowTouch" :content="$L('添加任务')"> <ETooltip :disabled="$isMobileApp || windowTouch" :content="$L('添加任务')">
<Icon class="menu-icon" type="md-add" /> <Icon class="menu-icon" type="md-add" />
</ETooltip> </ETooltip>
</li> </li>
@ -121,7 +121,7 @@
<Draggable <Draggable
:list="columnList" :list="columnList"
:animation="150" :animation="150"
:disabled="sortDisabled || isDepartmentReadonly || $isEEUIApp || windowTouch" :disabled="sortDisabled || isDepartmentReadonly || $isMobileApp || windowTouch"
class="column-list" class="column-list"
tag="ul" tag="ul"
draggable=".column-item" draggable=".column-item"
@ -193,7 +193,7 @@
<Draggable <Draggable
:list="column.tasks" :list="column.tasks"
:animation="150" :animation="150"
:disabled="sortDisabled || isDepartmentReadonly || $isEEUIApp || windowTouch" :disabled="sortDisabled || isDepartmentReadonly || $isMobileApp || windowTouch"
class="task-list" class="task-list"
draggable=".task-draggable" draggable=".task-draggable"
filter=".complete" filter=".complete"
@ -240,7 +240,7 @@
<ETooltip <ETooltip
v-if="item.end_at" v-if="item.end_at"
:class="['task-time', item.today ? 'today' : '', item.overdue ? 'overdue' : '']" :class="['task-time', item.today ? 'today' : '', item.overdue ? 'overdue' : '']"
:disabled="$isEEUIApp || windowTouch" :disabled="$isMobileApp || windowTouch"
:open-delay="600" :open-delay="600"
:content="item.end_at"> :content="item.end_at">
<div v-if="!item.complete_at"><i class="taskfont">&#xe71d;</i>{{ expiresFormat(item.end_at) }}</div> <div v-if="!item.complete_at"><i class="taskfont">&#xe71d;</i>{{ expiresFormat(item.end_at) }}</div>

View File

@ -103,7 +103,7 @@
<Draggable <Draggable
:list="data.project_flow_item" :list="data.project_flow_item"
:animation="150" :animation="150"
:disabled="$isEEUIApp || windowTouch" :disabled="$isMobileApp || windowTouch"
class="taskflow-config-table-list-wrapper" class="taskflow-config-table-list-wrapper"
tag="div" tag="div"
draggable=".column-border" draggable=".column-border"

View File

@ -13,13 +13,13 @@
<Radio label="daily" :disabled="id > 0 && reportData.type =='weekly'">{{ $L("日报") }}</Radio> <Radio label="daily" :disabled="id > 0 && reportData.type =='weekly'">{{ $L("日报") }}</Radio>
</RadioGroup> </RadioGroup>
<ButtonGroup v-if="id === 0" class="report-buttongroup"> <ButtonGroup v-if="id === 0" class="report-buttongroup">
<ETooltip :disabled="$isEEUIApp || windowTouch" :content="prevCycleText" placement="bottom"> <ETooltip :disabled="$isMobileApp || windowTouch" :content="prevCycleText" placement="bottom">
<Button type="primary" @click="prevCycle"> <Button type="primary" @click="prevCycle">
<Icon type="ios-arrow-back" /> <Icon type="ios-arrow-back" />
</Button> </Button>
</ETooltip> </ETooltip>
<div class="report-buttongroup-vertical"></div> <div class="report-buttongroup-vertical"></div>
<ETooltip :disabled="$isEEUIApp || windowTouch || reportData.offset >= 0" :content="nextCycleText" placement="bottom"> <ETooltip :disabled="$isMobileApp || windowTouch || reportData.offset >= 0" :content="nextCycleText" placement="bottom">
<Button type="primary" @click="nextCycle" :disabled="reportData.offset >= 0"> <Button type="primary" @click="nextCycle" :disabled="reportData.offset >= 0">
<Icon type="ios-arrow-forward" /> <Icon type="ios-arrow-forward" />
</Button> </Button>

View File

@ -53,7 +53,7 @@
<Button @click="advanced=!advanced">{{$L('高级选项')}}</Button> <Button @click="advanced=!advanced">{{$L('高级选项')}}</Button>
<ul class="advanced-priority"> <ul class="advanced-priority">
<li v-for="(item, key) in taskPriority" :key="key"> <li v-for="(item, key) in taskPriority" :key="key">
<ETooltip :disabled="$isEEUIApp || windowTouch" :content="taskPriorityContent(item)"> <ETooltip :disabled="$isMobileApp || windowTouch" :content="taskPriorityContent(item)">
<i <i
class="taskfont" class="taskfont"
:style="{color:item.color}" :style="{color:item.color}"

View File

@ -17,7 +17,7 @@
<div v-if="parentId == 0" class="priority"> <div v-if="parentId == 0" class="priority">
<ul> <ul>
<li v-for="(item, key) in taskPriority" :key="key"> <li v-for="(item, key) in taskPriority" :key="key">
<ETooltip v-if="active" :disabled="$isEEUIApp || windowTouch" :content="taskPriorityContent(item)"> <ETooltip v-if="active" :disabled="$isMobileApp || windowTouch" :content="taskPriorityContent(item)">
<i <i
class="taskfont" class="taskfont"
:style="{color:item.color}" :style="{color:item.color}"
@ -57,7 +57,7 @@
<div class="priority"> <div class="priority">
<ul> <ul>
<li v-for="(item, key) in taskPriority" :key="key"> <li v-for="(item, key) in taskPriority" :key="key">
<ETooltip v-if="active" :disabled="$isEEUIApp || windowTouch" :content="taskPriorityContent(item)"> <ETooltip v-if="active" :disabled="$isMobileApp || windowTouch" :content="taskPriorityContent(item)">
<i <i
class="taskfont" class="taskfont"
:style="{color:item.color}" :style="{color:item.color}"

View File

@ -175,7 +175,7 @@ export default {
title: title, title: title,
titleFixed: true, titleFixed: true,
}); });
} else if (this.$isEEUIApp) { } else if (this.$isMobileApp) {
this.$store.dispatch('openAppChildPage', { this.$store.dispatch('openAppChildPage', {
pageType: 'app', pageType: 'app',
pageTitle: title, pageTitle: title,

View File

@ -95,7 +95,7 @@
<p v-if="taskDetail.id"><span>{{taskDetail.id}}</span></p> <p v-if="taskDetail.id"><span>{{taskDetail.id}}</span></p>
</div> </div>
<div class="function"> <div class="function">
<ETooltip v-if="$Electron" :disabled="$isEEUIApp || windowTouch" :content="$L('独立窗口显示')"> <ETooltip v-if="$Electron" :disabled="$isMobileApp || windowTouch" :content="$L('独立窗口显示')">
<i class="taskfont open" @click="openNewWin">&#xe776;</i> <i class="taskfont open" @click="openNewWin">&#xe776;</i>
</ETooltip> </ETooltip>
<div v-if="!isDepartmentReadonly" class="menu"> <div v-if="!isDepartmentReadonly" class="menu">
@ -289,7 +289,7 @@
</div> </div>
<ul class="item-content loop"> <ul class="item-content loop">
<li> <li>
<ETooltip :disabled="$isEEUIApp || windowTouch || !taskDetail.loop_at" :content="`${$L('下个周期')}: ${taskDetail.loop_at}`" placement="right"> <ETooltip :disabled="$isMobileApp || windowTouch || !taskDetail.loop_at" :content="`${$L('下个周期')}: ${taskDetail.loop_at}`" placement="right">
<span ref="loopText" @click="!isDepartmentReadonly && onLoop($event)">{{$L(loopLabel(taskDetail.loop))}}</span> <span ref="loopText" @click="!isDepartmentReadonly && onLoop($event)">{{$L(loopLabel(taskDetail.loop))}}</span>
</ETooltip> </ETooltip>
</li> </li>
@ -1046,7 +1046,7 @@ export default {
this.ready = true; this.ready = true;
this.loadRelatedTasks(); this.loadRelatedTasks();
} else { } else {
$A.eeuiAppKeyboardHide() $A.nativeAppKeyboardHide()
this.timeOpen = false; this.timeOpen = false;
this.timeForce = false; this.timeForce = false;
this.loopForce = false; this.loopForce = false;
@ -1926,7 +1926,7 @@ export default {
this.$store.dispatch('openDialog', dialogId).catch(({msg}) => { this.$store.dispatch('openDialog', dialogId).catch(({msg}) => {
$A.modalError(msg); $A.modalError(msg);
}) })
$A.eeuiAppKeyboardHide(); $A.nativeAppKeyboardHide();
} }
}, },
@ -2085,7 +2085,7 @@ export default {
title: `${file.name} (${$A.bytesToSize(file.size)})`, title: `${file.name} (${$A.bytesToSize(file.size)})`,
titleFixed: true, titleFixed: true,
}); });
} else if (this.$isEEUIApp) { } else if (this.$isMobileApp) {
this.$store.dispatch('openAppChildPage', { this.$store.dispatch('openAppChildPage', {
pageType: 'app', pageType: 'app',
pageTitle: `${file.name} (${$A.bytesToSize(file.size)})`, pageTitle: `${file.name} (${$A.bytesToSize(file.size)})`,
@ -2361,7 +2361,7 @@ export default {
}, },
autoScrollInto() { autoScrollInto() {
return this.$isEEUIApp return this.$isMobileApp
&& this.windowPortrait && this.windowPortrait
&& this.$refs.chatInput?.isFocus && this.$refs.chatInput?.isFocus
}, },

View File

@ -41,7 +41,7 @@ export default {
watch: { watch: {
show(v) { show(v) {
$A.eeuiAppSetScrollDisabled(v && this.windowPortrait) $A.nativeAppSetScrollDisabled(v && this.windowPortrait)
} }
}, },

View File

@ -94,7 +94,7 @@
<ETooltip <ETooltip
v-if="!item.complete_at && item.end_at" v-if="!item.complete_at && item.end_at"
:class="['task-time', item.today ? 'today' : '', item.overdue ? 'overdue' : '']" :class="['task-time', item.today ? 'today' : '', item.overdue ? 'overdue' : '']"
:disabled="$isEEUIApp || windowTouch" :disabled="$isMobileApp || windowTouch"
:open-delay="600" :open-delay="600"
:content="item.end_at"> :content="item.end_at">
<div @click="openTask(item)">{{expiresFormat(item.end_at)}}</div> <div @click="openTask(item)">{{expiresFormat(item.end_at)}}</div>

View File

@ -451,8 +451,8 @@ export default {
$A.modalConfirm({ $A.modalConfirm({
content: `是否拨打电话给 ${this.userData.nickname}`, content: `是否拨打电话给 ${this.userData.nickname}`,
onOk: () => { onOk: () => {
if ($A.isEEUIApp()) { if ($A.isMobileApp()) {
$A.eeuiAppSendMessage({ $A.nativeAppSendMessage({
action: 'callTel', action: 'callTel',
tel: this.userData.tel tel: this.userData.tel
}); });

View File

@ -90,7 +90,7 @@
<i class="taskfont">&#xe71f;</i> <i class="taskfont">&#xe71f;</i>
<em>{{item.sub_complete}}/{{item.sub_num}}</em> <em>{{item.sub_complete}}/{{item.sub_num}}</em>
</div> </div>
<ETooltip v-if="item.end_at" :disabled="$isEEUIApp || windowTouch" :content="item.end_at" placement="right"> <ETooltip v-if="item.end_at" :disabled="$isMobileApp || windowTouch" :content="item.end_at" placement="right">
<div :class="['item-icon', item.today ? 'today' : '', item.overdue ? 'overdue' : '']"> <div :class="['item-icon', item.today ? 'today' : '', item.overdue ? 'overdue' : '']">
<i class="taskfont">&#xe71d;</i> <i class="taskfont">&#xe71d;</i>
<em>{{expiresFormat(item.end_at)}}</em> <em>{{expiresFormat(item.end_at)}}</em>

View File

@ -1010,7 +1010,7 @@ export default {
fileShow(val) { fileShow(val) {
if (!val) { if (!val) {
this.browseFile(0) this.browseFile(0)
$A.eeuiAppKeyboardHide() $A.nativeAppKeyboardHide()
} }
}, },
@ -1508,7 +1508,7 @@ export default {
return; return;
} }
// //
if (this.$Electron || this.$isEEUIApp) { if (this.$Electron || this.$isMobileApp) {
this.openFileSingle(item); this.openFileSingle(item);
return; return;
} }
@ -1526,7 +1526,7 @@ export default {
title: $A.getFileName(item), title: $A.getFileName(item),
titleFixed: true, titleFixed: true,
}); });
} else if (this.$isEEUIApp) { } else if (this.$isMobileApp) {
this.$store.dispatch('openAppChildPage', { this.$store.dispatch('openAppChildPage', {
pageType: 'app', pageType: 'app',
pageTitle: $A.getFileName(item), pageTitle: $A.getFileName(item),

View File

@ -9,7 +9,7 @@
<Loading v-if="searchLoading"/> <Loading v-if="searchLoading"/>
<Icon v-else type="ios-search" /> <Icon v-else type="ios-search" />
</div> </div>
<Form class="search-form" action="javascript:void(0)" @submit.native.prevent="$A.eeuiAppKeyboardHide"> <Form class="search-form" action="javascript:void(0)" @submit.native.prevent="$A.nativeAppKeyboardHide">
<Input <Input
v-if="tabActive==='dialog'" v-if="tabActive==='dialog'"
type="search" type="search"
@ -60,7 +60,7 @@
</div> </div>
</div> </div>
</div> </div>
<div v-if="$isEEUIApp && !appNotificationPermission" class="messenger-notify-permission" @click="onOpenAppSetting"> <div v-if="$isMobileApp && !appNotificationPermission" class="messenger-notify-permission" @click="onOpenAppSetting">
{{$L('未开启通知权限')}}<i class="taskfont">&#xe733;</i> {{$L('未开启通知权限')}}<i class="taskfont">&#xe733;</i>
</div> </div>
<Scrollbar <Scrollbar
@ -356,8 +356,8 @@ export default {
// //
this.$nextTick(_ => this.activeNum++) this.$nextTick(_ => this.activeNum++)
// //
if ($A.isEEUIApp) { if ($A.isMobileApp) {
$A.eeuiAppSendMessage({action: 'getNotificationPermission'}); $A.nativeAppSendMessage({action: 'getNotificationPermission'});
} }
}, },
@ -1243,7 +1243,7 @@ export default {
}, },
onOpenAppSetting() { onOpenAppSetting() {
$A.eeuiAppSendMessage({ $A.nativeAppSendMessage({
action: 'gotoSetting', action: 'gotoSetting',
}); });
}, },

View File

@ -140,7 +140,7 @@ export default {
* 唤醒APP * 唤醒APP
*/ */
wakeApp() { wakeApp() {
if (!$A.Electron && !$A.isEEUIApp && navigator.userAgent.indexOf("MicroMessenger") === -1) { if (!$A.Electron && !$A.isMobileApp && navigator.userAgent.indexOf("MicroMessenger") === -1) {
if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) { if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
try { try {
if (/Android/i.test(navigator.userAgent)) { if (/Android/i.test(navigator.userAgent)) {

View File

@ -113,7 +113,7 @@
<Radio label="close">{{$L('关闭')}}</Radio> <Radio label="close">{{$L('关闭')}}</Radio>
</RadioGroup> </RadioGroup>
<div class="form-tip">{{$L('任务完成后自动归档。')}}</div> <div class="form-tip">{{$L('任务完成后自动归档。')}}</div>
<ETooltip v-if="formDatum.auto_archived=='open'" placement="right" :disabled="$isEEUIApp || windowTouch"> <ETooltip v-if="formDatum.auto_archived=='open'" placement="right" :disabled="$isMobileApp || windowTouch">
<div class="setting-auto-day"> <div class="setting-auto-day">
<Input v-model="formDatum.archived_day" type="number"> <Input v-model="formDatum.archived_day" type="number">
<span slot="append">{{$L('天')}}</span> <span slot="append">{{$L('天')}}</span>

View File

@ -32,7 +32,7 @@
</li> </li>
</ul> </ul>
</div> </div>
<transition :name="$isEEUIApp ? 'mobile-dialog' : 'none'"> <transition :name="$isMobileApp ? 'mobile-dialog' : 'none'">
<div v-if="showContent" class="setting-content"> <div v-if="showContent" class="setting-content">
<MobileNavTitle :title="settingTitleName"/> <MobileNavTitle :title="settingTitleName"/>
<div class="setting-content-title">{{titleNameRoute}}</div> <div class="setting-content-title">{{titleNameRoute}}</div>
@ -62,8 +62,8 @@ export default {
}, },
mounted() { mounted() {
if (this.$isEEUIApp) { if (this.$isMobileApp) {
this.clientVersion = `${window.systemInfo.version} (${$A.eeuiAppLocalVersion()})` this.clientVersion = `${window.systemInfo.version} (${$A.nativeAppLocalVersion()})`
} }
}, },
@ -87,11 +87,11 @@ export default {
{path: 'theme', name: '主题设置'}, {path: 'theme', name: '主题设置'},
] ]
if (this.$Electron || this.$isEEUIApp) { if (this.$Electron || this.$isMobileApp) {
menu.push({path: 'keyboard', name: '键盘设置'}) menu.push({path: 'keyboard', name: '键盘设置'})
} }
if ($A.isDooServer() && this.$isEEUIApp) { if ($A.isDooServer() && this.$isMobileApp) {
menu.push(...[ menu.push(...[
{path: 'privacy', name: '隐私政策', divided: true}, {path: 'privacy', name: '隐私政策', divided: true},
{path: 'delete', name: '删除帐号'}, {path: 'delete', name: '删除帐号'},
@ -198,7 +198,7 @@ export default {
openPrivacy() { openPrivacy() {
const url = $A.apiUrl('privacy') const url = $A.apiUrl('privacy')
if (this.$isEEUIApp) { if (this.$isMobileApp) {
this.$store.dispatch('openAppChildPage', { this.$store.dispatch('openAppChildPage', {
pageType: 'app', pageType: 'app',
pageTitle: ' ', pageTitle: ' ',

View File

@ -38,7 +38,7 @@
</div> </div>
</FormItem> </FormItem>
</template> </template>
<FormItem v-if="$isEEUIApp" :label="$L('发送按钮')"> <FormItem v-if="$isMobileApp" :label="$L('发送按钮')">
<RadioGroup v-model="formData.send_button_app"> <RadioGroup v-model="formData.send_button_app">
<Radio label="button">{{$L('开启')}}</Radio> <Radio label="button">{{$L('开启')}}</Radio>
<Radio label="enter">{{$L('关闭')}}</Radio> <Radio label="enter">{{$L('关闭')}}</Radio>

View File

@ -0,0 +1,334 @@
<template>
<div class="page-share">
<div class="share-header">
<div class="share-cancel" @click="onCancel">{{ $L('取消') }}</div>
<div class="share-title">{{ $L('发送给') }}</div>
<div class="share-action" @click="onSend" :class="{ disabled: !canSend }">
{{ sendingState || $L('发送') }}
</div>
</div>
<div v-if="loading" class="share-loading">
<Loading :content="$L('加载中')"/>
</div>
<div v-else-if="errorMessage" class="share-error">
<p>{{ errorMessage }}</p>
<Button @click="onCancel">{{ $L('返回') }}</Button>
</div>
<template v-else>
<div class="share-preview">
<div v-if="payload.text" class="share-preview-text">{{ payload.text }}</div>
<div v-if="payload.url" class="share-preview-url">{{ payload.url }}</div>
<div v-if="payload.items && payload.items.length" class="share-preview-items">
<div
v-for="(item, idx) in payload.items"
:key="idx"
class="share-preview-item"
>
<div class="name">{{ item.name }}</div>
<div class="meta">{{ formatSize(item.size) }} · {{ item.mime }}</div>
</div>
</div>
</div>
<div class="share-search">
<Input
v-model="keyword"
:placeholder="$L('搜索会话')"
clearable
@on-change="loadList"
/>
</div>
<div class="share-list">
<div
v-for="item in list"
:key="item.name + '_' + (item.extend && item.extend.dialog_ids)"
class="share-list-item"
:class="{ selected: isSelected(item) }"
@click="toggleSelect(item)"
>
<img class="icon" :src="item.icon" alt=""/>
<div class="name">{{ item.name }}</div>
<div v-if="isSelected(item)" class="check"></div>
</div>
<div v-if="!list.length" class="share-list-empty">{{ $L('暂无会话') }}</div>
</div>
</template>
</div>
</template>
<script>
import Loading from "../components/Loading.vue";
/**
* App 分享接收页二期 WS11
*
* 流程原生 (iOS Share Extension / Android Intent) 写共享 payload 到本地
* deep link `dootask://share?token=<x>` __handleLink 跳本页
* $A.nativeAppGetSharedPayload(token) 拿元数据
* api/users/share/list 渲染会话/用户列表type='text' 接口仅返回会话简洁
* 用户选会话 POST api/dialog/msg/sendfiles 上传
* $A.nativeAppClearSharedPayload(token) 清理 + 跳目标会话
*/
export default {
name: "share",
components: { Loading },
data() {
return {
token: "",
payload: { items: [], text: undefined, url: undefined },
list: [],
keyword: "",
selectedIds: [],
loading: true,
errorMessage: "",
sendingState: "",
};
},
computed: {
canSend() {
if (!this.selectedIds.length) return false;
const hasAttachment =
(this.payload.items && this.payload.items.length > 0) ||
this.payload.text ||
this.payload.url;
return !!hasAttachment && !this.sendingState;
},
},
mounted() {
this.token = String(this.$route.query.token || "");
if (!this.token) {
this.errorMessage = this.$L("缺少分享凭据");
this.loading = false;
return;
}
this.loadPayload();
},
methods: {
async loadPayload() {
try {
const result = await this.callBridge("getSharedPayload", { token: this.token });
if (!result) {
this.errorMessage = this.$L("分享内容不存在或已过期");
this.loading = false;
return;
}
this.payload = result;
await this.loadList();
} catch (e) {
this.errorMessage = (e && e.message) || this.$L("加载失败");
} finally {
this.loading = false;
}
},
async loadList() {
// type='text'
// "" type='file'
const params = { url: "users/share/list", data: { type: "text", key: this.keyword } };
try {
const { data } = await this.$store.dispatch("call", params);
const lists = Array.isArray(data) ? data : (data && data.lists) || [];
this.list = lists.filter(it => it.type === "item");
} catch (e) {
this.errorMessage = (e && e.msg) || this.$L("加载会话列表失败");
}
},
isSelected(item) {
const id = item.extend && item.extend.dialog_ids;
return !!id && this.selectedIds.indexOf(id) !== -1;
},
toggleSelect(item) {
const id = item.extend && item.extend.dialog_ids;
if (!id) return;
const idx = this.selectedIds.indexOf(id);
if (idx === -1) this.selectedIds.push(id);
else this.selectedIds.splice(idx, 1);
},
formatSize(bytes) {
if (!bytes && bytes !== 0) return "";
if (bytes < 1024) return bytes + " B";
if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + " KB";
return (bytes / (1024 * 1024)).toFixed(1) + " MB";
},
callBridge(method, args) {
if (window.__nativeBridge && typeof window.__nativeBridge.call === "function") {
return window.__nativeBridge.call(method, args);
}
return Promise.resolve(null);
},
async onSend() {
if (!this.canSend) return;
const dialogIds = this.selectedIds.join(",");
try {
if (this.payload.items && this.payload.items.length) {
this.sendingState = this.$L("正在发送");
for (const item of this.payload.items) {
await this.uploadOne(dialogIds, item);
}
}
// /URL
const extraText = [this.payload.text, this.payload.url].filter(Boolean).join("\n");
if (extraText) {
await this.$store.dispatch("call", {
url: "dialog/msg/sendtext",
method: "post",
data: { dialog_ids: dialogIds, text: extraText, text_type: "text" },
});
}
//
await this.callBridge("clearSharedPayload", { token: this.token });
//
this.$store.state.dialogId = this.selectedIds[0];
this.$router.replace({ name: "manage-messenger" });
} catch (e) {
$A.modalError({ content: (e && e.msg) || this.$L("发送失败") });
this.sendingState = "";
}
},
async uploadOne(dialogIds, item) {
// file:// uri Blob multipart upload
const res = await fetch(item.uri);
const blob = await res.blob();
const form = new FormData();
form.append("dialog_ids", dialogIds);
form.append("files", blob, item.name || "shared");
await this.$store.dispatch("call", {
url: "dialog/msg/sendfiles",
method: "post",
data: form,
headers: { "Content-Type": "multipart/form-data" },
});
},
async onCancel() {
if (this.token) {
try { await this.callBridge("clearSharedPayload", { token: this.token }); } catch (e) { /* ignore */ }
}
this.$router.replace({ name: "index" });
},
},
};
</script>
<style lang="scss" scoped>
.page-share {
height: 100vh;
display: flex;
flex-direction: column;
background: var(--ee-bg-color, #f7f8fa);
.share-header {
display: flex;
align-items: center;
padding: 12px 16px;
background: #fff;
border-bottom: 1px solid #eaecef;
.share-title {
flex: 1;
text-align: center;
font-size: 16px;
font-weight: 600;
}
.share-cancel,
.share-action {
font-size: 14px;
color: #1890ff;
cursor: pointer;
}
.share-action.disabled {
color: #c0c4cc;
cursor: not-allowed;
}
}
.share-loading,
.share-error {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 32px;
text-align: center;
}
.share-preview {
background: #fff;
padding: 12px 16px;
border-bottom: 1px solid #eaecef;
.share-preview-text,
.share-preview-url {
padding: 8px 0;
font-size: 14px;
word-break: break-all;
}
.share-preview-url { color: #1890ff; }
.share-preview-items {
display: flex;
flex-direction: column;
gap: 6px;
}
.share-preview-item {
padding: 6px 8px;
background: #f0f2f5;
border-radius: 4px;
.name { font-size: 13px; }
.meta { font-size: 11px; color: #8c8c8c; margin-top: 2px; }
}
}
.share-search {
padding: 8px 12px;
background: #fff;
border-bottom: 1px solid #eaecef;
}
.share-list {
flex: 1;
overflow-y: auto;
background: #fff;
.share-list-item {
display: flex;
align-items: center;
padding: 10px 16px;
border-bottom: 1px solid #f0f2f5;
cursor: pointer;
&.selected { background: #e6f7ff; }
.icon {
width: 36px;
height: 36px;
border-radius: 18px;
margin-right: 12px;
object-fit: cover;
}
.name {
flex: 1;
font-size: 14px;
}
.check {
font-weight: 600;
color: #1890ff;
}
}
.share-list-empty {
padding: 32px;
text-align: center;
color: #8c8c8c;
font-size: 13px;
}
}
}
</style>

View File

@ -3,7 +3,7 @@
<PageTitle :title="pageName"/> <PageTitle :title="pageName"/>
<Loading v-if="loadIng > 0"/> <Loading v-if="loadIng > 0"/>
<template v-else-if="fileInfo"> <template v-else-if="fileInfo">
<FilePreview v-if="isPreview" :code="code" :file="fileInfo" :historyId="historyId" :headerShow="!$isEEUIApp"/> <FilePreview v-if="isPreview" :code="code" :file="fileInfo" :historyId="historyId" :headerShow="!$isMobileApp"/>
<FileContent v-else v-model="fileShow" :file="fileInfo"/> <FileContent v-else v-model="fileShow" :file="fileInfo"/>
</template> </template>
</div> </div>

View File

@ -35,7 +35,7 @@ export default {
return { return {
loadIng: 0, loadIng: 0,
info: null, info: null,
showHeader: !$A.isEEUIApp, showHeader: !$A.isMobileApp,
} }
}, },
mounted() { mounted() {

View File

@ -14,6 +14,11 @@ export default [
path: '/meeting/:meetingId?/:sharekey?', path: '/meeting/:meetingId?/:sharekey?',
component: () => import('./pages/meeting.vue'), component: () => import('./pages/meeting.vue'),
}, },
{
name: 'share',
path: '/share',
component: () => import('./pages/share.vue'),
},
{ {
name: 'manage', name: 'manage',
path: '/manage', path: '/manage',

View File

@ -35,7 +35,7 @@ export default {
labelWidth: windowWidth > 576 ? 'auto' : '', labelWidth: windowWidth > 576 ? 'auto' : '',
} }
$A.eeuiAppSendMessage({ $A.nativeAppSendMessage({
action: 'windowSize', action: 'windowSize',
width: windowWidth, width: windowWidth,
height: windowHeight, height: windowHeight,
@ -48,10 +48,11 @@ export default {
window.addEventListener('message', ({data}) => { window.addEventListener('message', ({data}) => {
data = $A.jsonParse(data); data = $A.jsonParse(data);
if (data.action === 'eeuiAppSendMessage') { // 兼容:前端内部 iframe/postMessage 转 nativeAppSendMessage 的中转桥
if (data.action === 'nativeAppSendMessage' || data.action === 'eeuiAppSendMessage') {
const items = $A.isArray(data.data) ? data.data : [data.data]; const items = $A.isArray(data.data) ? data.data : [data.data];
items.forEach(item => { items.forEach(item => {
$A.eeuiAppSendMessage(item); $A.nativeAppSendMessage(item);
}) })
} }
}) })
@ -177,7 +178,7 @@ export default {
if (!state.isFirstPage) { if (!state.isFirstPage) {
return resolve(null) return resolve(null)
} }
$A.eeuiAppGetSafeAreaInsets().then(async data => { $A.nativeAppGetSafeAreaInsets().then(async data => {
data.top = data.top || state.safeAreaSize?.data?.top || 0 data.top = data.top || state.safeAreaSize?.data?.top || 0
data.bottom = data.bottom || state.safeAreaSize?.data?.bottom || 0 data.bottom = data.bottom || state.safeAreaSize?.data?.bottom || 0
const proportion = data.height / window.outerHeight const proportion = data.height / window.outerHeight
@ -483,8 +484,8 @@ export default {
action: 'createDownload', action: 'createDownload',
url url
}); });
} else if ($A.isEEUIApp) { } else if ($A.isMobileApp) {
$A.eeuiAppOpenWeb(url); $A.nativeAppOpenWeb(url);
} else { } else {
window.open(url) window.open(url)
} }
@ -557,7 +558,7 @@ export default {
return; return;
} }
if (!$A.dark.utils.supportMode()) { if (!$A.dark.utils.supportMode()) {
if ($A.isEEUIApp) { if ($A.isMobileApp) {
$A.modalWarning("仅Android设置支持主题功能"); $A.modalWarning("仅Android设置支持主题功能");
} else { } else {
$A.modalWarning("仅客户端或Chrome浏览器支持主题功能"); $A.modalWarning("仅客户端或Chrome浏览器支持主题功能");
@ -600,8 +601,8 @@ export default {
state.themeName = $A.dark.isDarkEnabled() ? 'dark' : 'light' state.themeName = $A.dark.isDarkEnabled() ? 'dark' : 'light'
window.localStorage.setItem("__system:themeConf__", state.themeConf) window.localStorage.setItem("__system:themeConf__", state.themeConf)
// //
if ($A.isEEUIApp) { if ($A.isMobileApp) {
$A.eeuiAppSendMessage({ $A.nativeAppSendMessage({
action: 'updateTheme', action: 'updateTheme',
themeName: state.themeName, themeName: state.themeName,
themeDefault: { themeDefault: {
@ -771,23 +772,14 @@ export default {
state.userId = userInfo.userid; state.userId = userInfo.userid;
state.userToken = userInfo.token; state.userToken = userInfo.token;
state.userIsAdmin = $A.inArray('admin', userInfo.identity); state.userIsAdmin = $A.inArray('admin', userInfo.identity);
if ($A.isSubElectron || ($A.isEEUIApp && !state.isFirstPage)) { if ($A.isSubElectron || ($A.isMobileApp && !state.isFirstPage)) {
// 子窗口Electron、不是第一个页面App 不保存 // 子窗口Electron、不是第一个页面App 不保存
} else { } else {
await $A.IDBSet("userInfo", state.userInfo); await $A.IDBSet("userInfo", state.userInfo);
} }
// // 旧 EEUI 用 userChatList/userUploadUrl 把 share/list 和 sendfiles 接口
$A.eeuiAppSendMessage({ // 通过 App Group 同步给 iOS Share Extension 内嵌 UI新移动端 /share 路由
action: 'userChatList', // 由 WebView 内主前端直接调用接口,无需提前同步。
language: $A.eeuiAppConvertLanguage(),
url: $A.mainUrl('api/users/share/list') + `?token=${state.userToken}`
});
$A.eeuiAppSendMessage({
action:"userUploadUrl",
dirUrl: $A.mainUrl('api/file/content/upload') + `?token=${state.userToken}`,
chatUrl: $A.mainUrl('api/dialog/msg/sendfiles') + `?token=${state.userToken}`,
});
//
resolve() resolve()
}) })
}, },
@ -1322,7 +1314,7 @@ export default {
selectclose: "true", selectclose: "true",
channel, channel,
} }
$A.eeuiAppSetVariate(`location::${channel}`, ""); $A.nativeAppSetVariate(`location::${channel}`, "");
const url = $A.urlAddParams(window.location.origin + '/tools/map/index.html', Object.assign(params, objects || {})) const url = $A.urlAddParams(window.location.origin + '/tools/map/index.html', Object.assign(params, objects || {}))
dispatch('openAppChildPage', { dispatch('openAppChildPage', {
pageType: 'app', pageType: 'app',
@ -1335,9 +1327,9 @@ export default {
}, },
callback: ({status}) => { callback: ({status}) => {
if (status === 'pause') { if (status === 'pause') {
const data = $A.jsonParse($A.eeuiAppGetVariate(`location::${channel}`)); const data = $A.jsonParse($A.nativeAppGetVariate(`location::${channel}`));
if (data.point) { if (data.point) {
$A.eeuiAppSetVariate(`location::${channel}`, ""); $A.nativeAppSetVariate(`location::${channel}`, "");
if (data.distance > objects.radius) { if (data.distance > objects.radius) {
$A.modalError(`你选择的位置「${data.title}」不在签到范围内`) $A.modalError(`你选择的位置「${data.title}」不在签到范围内`)
return return
@ -1367,7 +1359,7 @@ export default {
objects.params.showProgress = !isLocalHost(objects.params.url) objects.params.showProgress = !isLocalHost(objects.params.url)
} }
$A.eeuiAppOpenPage(objects) $A.nativeAppOpenPage(objects)
}, },
/** /**

View File

@ -75,7 +75,7 @@ export function openFileInClient(vm, item, options = {}) {
return; return;
} }
if (vm.$isEEUIApp) { if (vm.$isMobileApp) {
vm.$store.dispatch('openAppChildPage', { vm.$store.dispatch('openAppChildPage', {
pageType: 'app', pageType: 'app',
pageTitle: finalTitle, pageTitle: finalTitle,

View File

@ -54,11 +54,11 @@ function __callData(key, requestData, state) {
} else { } else {
deleted_id = [] deleted_id = []
} }
if ($A.isEEUIApp) { if ($A.isMobileApp) {
hasUpdate = state.isFirstPage hasUpdate = state.isFirstPage
} }
if (hasUpdate) { if (hasUpdate) {
if ($A.isSubElectron || ($A.isEEUIApp && !state.isFirstPage)) { if ($A.isSubElectron || ($A.isMobileApp && !state.isFirstPage)) {
// 子窗口Electron、不是第一个页面App 不保存 // 子窗口Electron、不是第一个页面App 不保存
} else { } else {
await $A.IDBSet("callAt", state.callAt) await $A.IDBSet("callAt", state.callAt)

@ -1 +1 @@
Subproject commit 97ac53c3a932041bb8d3fde41a5c6822fb2d95a0 Subproject commit 41d9889b79a7aaab644e1f99c5b16b16ce286881

View File

@ -154,7 +154,7 @@ interface DooTaskGlobal {
/** 是否 Electron 子窗口 */ /** 是否 Electron 子窗口 */
isSubElectron: boolean; isSubElectron: boolean;
/** 是否 EEUI App 环境 */ /** 是否 EEUI App 环境 */
isEEUIApp: boolean; isMobileApp: boolean;
/** 是否 Electron 环境 */ /** 是否 Electron 环境 */
isElectron: boolean; isElectron: boolean;
/** 是否客户端软件环境Electron 或 EEUI */ /** 是否客户端软件环境Electron 或 EEUI */
@ -574,81 +574,81 @@ interface DooTaskGlobal {
/** 获取eeui模块Promise */ /** 获取eeui模块Promise */
eeuiModulePromise(name?: string): Promise<any>; eeuiModulePromise(name?: string): Promise<any>;
/** 获取eeui版本号 */ /** 获取eeui版本号 */
eeuiAppVersion(): string | undefined; nativeAppVersion(): string | undefined;
/** 获取本地软件版本号 */ /** 获取本地软件版本号 */
eeuiAppLocalVersion(): string | undefined; nativeAppLocalVersion(): string | undefined;
/** Alert 弹窗 */ /** Alert 弹窗 */
eeuiAppAlert(object: any, callback?: (result: any) => void): void; nativeAppAlert(object: any, callback?: (result: any) => void): void;
/** Toast 提示 */ /** Toast 提示 */
eeuiAppToast(object: any): void; nativeAppToast(object: any): void;
/** 相对地址基于当前地址补全 */ /** 相对地址基于当前地址补全 */
eeuiAppRewriteUrl(val: string): string | undefined; nativeAppRewriteUrl(val: string): string | undefined;
/** 获取页面信息 */ /** 获取页面信息 */
eeuiAppGetPageInfo(pageName?: string): any; nativeAppGetPageInfo(pageName?: string): any;
/** 打开app新页面 */ /** 打开app新页面 */
eeuiAppOpenPage(object: Record<string, any>, callback?: (result: any) => void): void; nativeAppOpenPage(object: Record<string, any>, callback?: (result: any) => void): void;
/** 使用系统浏览器打开网页 */ /** 使用系统浏览器打开网页 */
eeuiAppOpenWeb(url: string): void; nativeAppOpenWeb(url: string): void;
/** 拦截返回按键事件仅支持android、iOS无效 */ /** 拦截返回按键事件仅支持android、iOS无效 */
eeuiAppSetPageBackPressed(object: any, callback?: (result: any) => void): void; nativeAppSetPageBackPressed(object: any, callback?: (result: any) => void): void;
/** 返回手机桌面 */ /** 返回手机桌面 */
eeuiAppGoDesktop(): void; nativeAppGoDesktop(): void;
/** 打开屏幕常亮 */ /** 打开屏幕常亮 */
eeuiAppKeepScreenOn(): void; nativeAppKeepScreenOn(): void;
/** 关闭屏幕常亮 */ /** 关闭屏幕常亮 */
eeuiAppKeepScreenOff(): void; nativeAppKeepScreenOff(): void;
/** 隐藏软键盘 */ /** 隐藏软键盘 */
eeuiAppKeyboardHide(): void; nativeAppKeyboardHide(): void;
/** 给app发送消息 */ /** 给app发送消息 */
eeuiAppSendMessage(object: any): void; nativeAppSendMessage(object: any): void;
/** 设置浏览器地址 */ /** 设置浏览器地址 */
eeuiAppSetUrl(url: string): void; nativeAppSetUrl(url: string): void;
/** 生成webview快照 */ /** 生成webview快照 */
eeuiAppGetWebviewSnapshot(callback: (result: any) => void): void; nativeAppGetWebviewSnapshot(callback: (result: any) => void): void;
/** 显示webview快照 */ /** 显示webview快照 */
eeuiAppShowWebviewSnapshot(): void; nativeAppShowWebviewSnapshot(): void;
/** 隐藏webview快照 */ /** 隐藏webview快照 */
eeuiAppHideWebviewSnapshot(): void; nativeAppHideWebviewSnapshot(): void;
/** 扫码(成功时回调扫码文本) */ /** 扫码(成功时回调扫码文本) */
eeuiAppScan(callback: (text: string) => void): void; nativeAppScan(callback: (text: string) => void): void;
/** 检查更新 */ /** 检查更新 */
eeuiAppCheckUpdate(): void; nativeAppCheckUpdate(): void;
/** 获取主题名称 light|dark */ /** 获取主题名称 light|dark */
eeuiAppGetThemeName(): string | undefined; nativeAppGetThemeName(): string | undefined;
/** 判断软键盘是否可见 */ /** 判断软键盘是否可见 */
eeuiAppKeyboardStatus(): boolean | undefined; nativeAppKeyboardStatus(): boolean | undefined;
/** 设置全局变量 */ /** 设置全局变量 */
eeuiAppSetVariate(key: string, value: any): void; nativeAppSetVariate(key: string, value: any): void;
/** 获取全局变量 */ /** 获取全局变量 */
eeuiAppGetVariate(key: string, defaultVal?: any): any; nativeAppGetVariate(key: string, defaultVal?: any): any;
/** 设置缓存数据 */ /** 设置缓存数据 */
eeuiAppSetCachesString(key: string, value: string, expired?: number): void; nativeAppSetCachesString(key: string, value: string, expired?: number): void;
/** 获取缓存数据 */ /** 获取缓存数据 */
eeuiAppGetCachesString(key: string, defaultVal?: string): string | undefined; nativeAppGetCachesString(key: string, defaultVal?: string): string | undefined;
/** 是否长按内容震动仅支持android、iOS无效 */ /** 是否长按内容震动仅支持android、iOS无效 */
eeuiAppSetHapticBackEnabled(val: boolean): void; nativeAppSetHapticBackEnabled(val: boolean): void;
/** 禁止长按选择仅支持android、iOS无效传毫秒数则临时禁止 */ /** 禁止长按选择仅支持android、iOS无效传毫秒数则临时禁止 */
eeuiAppSetDisabledUserLongClickSelect(val: boolean | number | string): void; nativeAppSetDisabledUserLongClickSelect(val: boolean | number | string): void;
/** 复制文本 */ /** 复制文本 */
eeuiAppCopyText(text: string): void; nativeAppCopyText(text: string): void;
/** 设置是否禁止滚动 */ /** 设置是否禁止滚动 */
eeuiAppSetScrollDisabled(disabled: boolean): void; nativeAppSetScrollDisabled(disabled: boolean): void;
/** 设置应用程序级别的摇动撤销仅支持iOS、android无效 */ /** 设置应用程序级别的摇动撤销仅支持iOS、android无效 */
eeuiAppShakeToEditEnabled(enabled: boolean): void; nativeAppShakeToEditEnabled(enabled: boolean): void;
/** 获取最新一张照片 */ /** 获取最新一张照片 */
eeuiAppGetLatestPhoto(expiration?: number, timeout?: number): Promise<any>; nativeAppGetLatestPhoto(expiration?: number, timeout?: number): Promise<any>;
/** 上传照片params 参数:{url,data,headers,path,fieldName,onReady?} */ /** 上传照片params 参数:{url,data,headers,path,fieldName,onReady?} */
eeuiAppUploadPhoto(params: Record<string, any>, timeout?: number): Promise<any>; nativeAppUploadPhoto(params: Record<string, any>, timeout?: number): Promise<any>;
/** 取消上传照片 */ /** 取消上传照片 */
eeuiAppCancelUploadPhoto(id: any): Promise<any>; nativeAppCancelUploadPhoto(id: any): Promise<any>;
/** 获取导航栏和状态栏高度 */ /** 获取导航栏和状态栏高度 */
eeuiAppGetSafeAreaInsets(): Promise<any>; nativeAppGetSafeAreaInsets(): Promise<any>;
/** 获取当前语言zh -> zh-Hans 等映射) */ /** 获取当前语言zh -> zh-Hans 等映射) */
eeuiAppConvertLanguage(): string; nativeAppConvertLanguage(): string;
/** 获取设备信息 */ /** 获取设备信息 */
eeuiAppGetDeviceInfo(): Promise<any>; nativeAppGetDeviceInfo(): Promise<any>;
/** 判断是否窗口化 */ /** 判断是否窗口化 */
eeuiAppIsWindowed(): Promise<boolean>; nativeAppIsWindowed(): Promise<boolean>;
} }
/** DooTask 全局工具对象jQuery 实例 + $.extend 扩展方法) */ /** DooTask 全局工具对象jQuery 实例 + $.extend 扩展方法) */