perf: 优化系统参数

This commit is contained in:
Pang 2024-01-17 13:58:48 +08:00
parent 96b0cb8aa0
commit 0a4ac6abb7
36 changed files with 279 additions and 235 deletions

View File

@ -372,27 +372,20 @@ class IndexController extends InvokeController
} }
/** /**
* 设置语言和皮肤 * 保存配置
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|string
*/ */
public function setting__theme_language() public function storage__synch()
{ {
return view('setting', [ $key = Request::input('key');
'theme' => Request::input('theme'), $value = Request::input('value');
'language' => Request::input('language') if ($key) {
]); $value = [$key => $value];
} }
if (!is_array($value)) {
/** $value = Base::json2array($value);
* 设置用户信息 }
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View return view('storage', ['value' => Base::array2json($value)]);
*/
public function setting__userinfo()
{
return view('setting', [
'userid' => Request::input('userid'),
'token' => Request::input('token')
]);
} }
/** /**

View File

@ -15,6 +15,9 @@ class VerifyCsrfToken extends Middleware
// 接口部分 // 接口部分
'api/*', 'api/*',
// 保存配置
'storage/synch/',
// 发布桌面端 // 发布桌面端
'desktop/publish/', 'desktop/publish/',
]; ];

View File

@ -177,7 +177,7 @@ services:
okr: okr:
container_name: "dootask-okr-${APP_ID}" container_name: "dootask-okr-${APP_ID}"
image: "kuaifan/doookr:0.0.29" image: "kuaifan/doookr:0.0.30"
environment: environment:
TZ: "${TIMEZONE:-PRC}" TZ: "${TIMEZONE:-PRC}"
DOO_TASK_URL: "http://${APP_IPPR}.3" DOO_TASK_URL: "http://${APP_IPPR}.3"

View File

@ -12,6 +12,7 @@
<!--style--> <!--style-->
<link rel="stylesheet" type="text/css" href="./css/iview.css"> <link rel="stylesheet" type="text/css" href="./css/iview.css">
<link rel="stylesheet" type="text/css" href="./css/loading.css"> <link rel="stylesheet" type="text/css" href="./css/loading.css">
<script src="./js/loading-theme.js"></script>
<script src="./js/jsencrypt.min.js"></script> <script src="./js/jsencrypt.min.js"></script>
<script src="./js/scroll-into-view.min.js"></script> <script src="./js/scroll-into-view.min.js"></script>
<script src="./config.js"></script> <script src="./config.js"></script>
@ -20,7 +21,7 @@
<div id="app"> <div id="app">
<div class="app-view-loading"> <div class="app-view-loading no-dark-mode">
<div> <div>
<div>PAGE LOADING</div> <div>PAGE LOADING</div>
<span></span> <span></span>

View File

@ -19,9 +19,6 @@
<!--网络提示--> <!--网络提示-->
<NetworkException v-if="windowLandscape"/> <NetworkException v-if="windowLandscape"/>
<!--Hidden IFrame-->
<iframe v-for="item in iframes" :key="item.key" v-if="item.url" v-show="false" :src="item.url"></iframe>
<!--引导页--> <!--引导页-->
<GuidePage/> <GuidePage/>
</div> </div>
@ -44,7 +41,7 @@ import NetworkException from "./components/NetworkException";
import GuidePage from "./components/GuidePage"; import GuidePage from "./components/GuidePage";
import TaskOperation from "./pages/manage/components/TaskOperation"; import TaskOperation from "./pages/manage/components/TaskOperation";
import {mapState} from "vuex"; import {mapState} from "vuex";
import {languageType} from "./language"; import {languageName} from "./language";
export default { export default {
components: {TaskOperation, NetworkException, PreviewImageState, RightBottom, FloatSpinner, GuidePage}, components: {TaskOperation, NetworkException, PreviewImageState, RightBottom, FloatSpinner, GuidePage},
@ -53,7 +50,6 @@ export default {
return { return {
routePath: null, routePath: null,
searchInter: null, searchInter: null,
iframes: [],
} }
}, },
@ -61,8 +57,6 @@ export default {
this.electronEvents(); this.electronEvents();
this.eeuiEvents(); this.eeuiEvents();
this.otherEvents(); this.otherEvents();
this.synchThemeLanguage();
this.synchAppTheme();
}, },
mounted() { mounted() {
@ -80,11 +74,7 @@ export default {
}, },
computed: { computed: {
...mapState(['ws', 'themeMode', 'themeIsDark', 'windowOrientation']), ...mapState(['ws', 'themeConf', 'windowOrientation']),
isSoftware() {
return this.$Electron || this.$isEEUiApp;
},
}, },
watch: { watch: {
@ -108,7 +98,6 @@ export default {
userId: { userId: {
handler() { handler() {
this.$store.dispatch("websocketConnection"); this.$store.dispatch("websocketConnection");
this.synchUserToken();
// //
if (this.userId > 0) { if (this.userId > 0) {
if (this.$isEEUiApp) { if (this.$isEEUiApp) {
@ -143,6 +132,13 @@ export default {
} }
}) })
} }
//
window.localStorage.setItem("__system:userId__", this.userId)
window.localStorage.setItem("__system:userToken__", this.userToken)
$A.storageByIframe({
userId: this.userId,
userToken: this.userToken,
})
}, },
immediate: true immediate: true
}, },
@ -187,10 +183,6 @@ export default {
this.$store.dispatch("audioStop", true) this.$store.dispatch("audioStop", true)
} }
}, },
themeIsDark() {
this.synchThemeLanguage();
}
}, },
methods: { methods: {
@ -226,42 +218,12 @@ export default {
}); });
}, },
synchUserToken() {
if (this.isSoftware) {
this.iframes = this.iframes.filter(({key}) => key != 'synchUserToken')
this.iframes.push({
key: 'synchUserToken',
url: $A.apiUrl(`../setting/userinfo?userid=${this.userId}&token=${this.userToken}`)
})
}
},
autoTheme() { autoTheme() {
if (this.themeMode === "auto") { if (this.themeConf === "auto") {
this.$store.dispatch("synchTheme") this.$store.dispatch("synchTheme")
} }
}, },
synchThemeLanguage() {
if (this.isSoftware) {
this.iframes = this.iframes.filter(({key}) => key != 'synchThemeLanguage')
this.iframes.push({
key: 'synchThemeLanguage',
url: $A.apiUrl(`../setting/theme_language?theme=${this.themeIsDark ? 'dark' : 'light'}&language=${languageType}`)
})
}
this.synchAppTheme()
},
synchAppTheme() {
if (this.$isEEUiApp) {
$A.eeuiAppSendMessage({
action: 'updateTheme',
themeName: this.themeIsDark ? 'dark' : 'light',
});
}
},
windowSizeListener() { windowSizeListener() {
const windowWidth = $A(window).width(), const windowWidth = $A(window).width(),
windowHeight = $A(window).height(), windowHeight = $A(window).height(),
@ -315,10 +277,7 @@ export default {
this.$Electron.registerMsgListener('browserWindowFocus', _ => { this.$Electron.registerMsgListener('browserWindowFocus', _ => {
this.$store.state.windowActive = true; this.$store.state.windowActive = true;
}) })
this.iframes.push({ $A.loadIframe($A.apiUrl("../manifest")).catch(_ => {})
key: 'manifest',
url: $A.apiUrl("../manifest")
})
$A.bindScreenshotKey(this.$store.state.cacheKeyboard); $A.bindScreenshotKey(this.$store.state.cacheKeyboard);
// //
this.$Electron.sendMessage('setMenuLanguage', { this.$Electron.sendMessage('setMenuLanguage', {
@ -422,7 +381,7 @@ export default {
}, },
otherEvents() { otherEvents() {
if (!this.isSoftware) { if (!this.$isSoftware) {
// //
const hiddenProperty = 'hidden' in document ? 'hidden' : 'webkitHidden' in document ? 'webkitHidden' : 'mozHidden' in document ? 'mozHidden' : null; const hiddenProperty = 'hidden' in document ? 'hidden' : 'webkitHidden' in document ? 'webkitHidden' : 'mozHidden' in document ? 'mozHidden' : null;
const visibilityChangeEvent = hiddenProperty.replace(/hidden/i, 'visibilitychange'); const visibilityChangeEvent = hiddenProperty.replace(/hidden/i, 'visibilitychange');

View File

@ -2,7 +2,7 @@ const isElectron = !!(window && window.process && window.process.type);
const isEEUiApp = window && window.navigator && /eeui/i.test(window.navigator.userAgent); const isEEUiApp = window && window.navigator && /eeui/i.test(window.navigator.userAgent);
import microappInit from "./microapp" import microappInit from "./microapp"
import {switchLanguage as $L, setLanguage, getLanguage} from "./language"; import {switchLanguage as $L} from "./language";
import './functions/common' import './functions/common'
import './functions/eeui' import './functions/eeui'
@ -147,6 +147,7 @@ $A.isMainElectron = false;
$A.isSubElectron = false; $A.isSubElectron = false;
$A.isEEUiApp = isEEUiApp; $A.isEEUiApp = isEEUiApp;
$A.isElectron = isElectron; $A.isElectron = isElectron;
$A.isSoftware = isEEUiApp || isElectron;
$A.openLog = false; $A.openLog = false;
if (isElectron) { if (isElectron) {
$A.Electron = electron; $A.Electron = electron;
@ -192,6 +193,7 @@ 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.$isEEUiApp = $A.isEEUiApp;
Vue.prototype.$isSoftware = $A.isSoftware;
Vue.config.productionTip = false; Vue.config.productionTip = false;
Vue.mixin(mixin) Vue.mixin(mixin)

View File

@ -294,11 +294,11 @@ export default {
} }
}, },
computed: { computed: {
...mapState(['themeIsDark']), ...mapState(['themeName']),
editTheme() { editTheme() {
if (this.theme == 'auto') { if (this.theme == 'auto') {
if (this.themeIsDark) { if (this.themeName === 'dark') {
return "dracula-dark" return "dracula-dark"
} else { } else {
return "chrome" return "chrome"

View File

@ -37,7 +37,7 @@
<script> <script>
import {mapState} from "vuex"; import {mapState} from "vuex";
import IFrame from "../pages/manage/components/IFrame"; import IFrame from "../pages/manage/components/IFrame";
import {languageType} from "../language"; import {languageName} from "../language";
export default { export default {
name: "Drawio", name: "Drawio",
@ -67,15 +67,15 @@ export default {
} }
}, },
created() { created() {
let lang = languageType; let lang = languageName;
switch (languageType) { switch (languageName) {
case 'zh-CHT': case 'zh-CHT':
lang = 'zh-tw' lang = 'zh-tw'
break; break;
} }
let lightbox = this.readOnly ? 1 : 0; let lightbox = this.readOnly ? 1 : 0;
let chrome = this.readOnly ? 0 : 1; let chrome = this.readOnly ? 0 : 1;
let theme = this.themeIsDark ? 'dark' : 'kennedy'; let theme = this.themeName === 'dark' ? 'dark' : 'kennedy';
let title = this.title ? encodeURIComponent(this.title) : ''; let title = this.title ? encodeURIComponent(this.title) : '';
let query = `?title=${title}&chrome=${chrome}&lightbox=${lightbox}&ui=${theme}&lang=${lang}&offline=1&pwa=0&embed=1&noLangIcon=1&noExitBtn=1&noSaveBtn=1&saveAndExit=0&spin=1&proto=json`; let query = `?title=${title}&chrome=${chrome}&lightbox=${lightbox}&ui=${theme}&lang=${lang}&offline=1&pwa=0&embed=1&noLangIcon=1&noExitBtn=1&noSaveBtn=1&saveAndExit=0&spin=1&proto=json`;
if (this.$Electron) { if (this.$Electron) {
@ -103,7 +103,7 @@ export default {
}, },
}, },
computed: { computed: {
...mapState(['themeIsDark']) ...mapState(['themeName'])
}, },
methods: { methods: {
formatZoom(val) { formatZoom(val) {

View File

@ -50,8 +50,6 @@
</template> </template>
<script> <script>
import {mapState} from "vuex";
export default { export default {
name: 'GanttView', name: 'GanttView',
props: { props: {

View File

@ -77,8 +77,6 @@
</template> </template>
<script> <script>
import {mapState} from "vuex";
export default { export default {
name: 'ImgUpload', name: 'ImgUpload',
props: { props: {

View File

@ -5,7 +5,8 @@
<Loading/> <Loading/>
</div> </div>
</transition> </transition>
<micro-app v-if="url && !loading" <micro-app
v-if="url && !loading"
:name='name' :name='name'
:url='url' :url='url'
inline inline
@ -18,19 +19,19 @@
@unmount='handleUnmount' @unmount='handleUnmount'
@error='handleError' @error='handleError'
@datachange='handleDataChange' @datachange='handleDataChange'
></micro-app> />
</div> </div>
</template> </template>
<script> <script>
import Vue from 'vue' import Vue from 'vue'
import store from '../store/index' import store from '../store/index'
import { mapState } from "vuex"; import {mapState} from "vuex";
import { EventCenterForMicroApp, unmountAllApps } from '@micro-zoe/micro-app' import {EventCenterForMicroApp, unmountAllApps} from '@micro-zoe/micro-app'
import DialogWrapper from '../pages/manage/components/DialogWrapper.vue' import DialogWrapper from '../pages/manage/components/DialogWrapper.vue'
import UserSelect from "./UserSelect.vue"; import UserSelect from "./UserSelect.vue";
import { languageList, languageType } from "../language"; import {languageList, languageName} from "../language";
import { DatePicker } from 'view-design-hi'; import {DatePicker} from 'view-design-hi';
export default { export default {
name: "MicroApps", name: "MicroApps",
@ -47,9 +48,10 @@ export default {
type: String, type: String,
default: "" default: ""
}, },
datas:{ datas: {
type: Object, type: Object,
default: () => {} default: () => {
}
} }
}, },
data() { data() {
@ -64,13 +66,13 @@ export default {
this.appData = this.getAppData this.appData = this.getAppData
}, },
watch: { watch: {
loading(val){ loading(val) {
if(val){ if (val) {
this.showSpin = true; this.showSpin = true;
} }
}, },
path(val) { path(val) {
this.appData = { path: val } this.appData = {path: val}
}, },
datas: { datas: {
handler(info) { handler(info) {
@ -80,7 +82,7 @@ export default {
}, },
'$route': { '$route': {
handler(to) { handler(to) {
if(to.name == 'manage-apps' || to.name == 'single-apps'){ if (to.name == 'manage-apps' || to.name == 'single-apps') {
this.appData = { this.appData = {
path: to.hash || to.fullPath path: to.hash || to.fullPath
} }
@ -90,10 +92,10 @@ export default {
}, },
userToken(val) { userToken(val) {
this.appData = this.getAppData; this.appData = this.getAppData;
if(!val){ if (!val) {
unmountAllApps({ destroy: true }) unmountAllApps({destroy: true})
this.loading = true; this.loading = true;
}else{ } else {
this.loading = false; this.loading = false;
} }
}, },
@ -101,9 +103,9 @@ export default {
computed: { computed: {
...mapState([ ...mapState([
'userInfo', 'userInfo',
'themeMode', 'themeName',
]), ]),
getAppData(){ getAppData() {
return { return {
type: 'init', type: 'init',
url: this.url, url: this.url,
@ -116,10 +118,11 @@ export default {
DatePicker DatePicker
} }
}, },
theme: this.themeMode, theme: this.themeName,
languages: { languages: {
languageList, languageList,
languageType, languageName,
languageType: languageName,
}, },
userInfo: this.userInfo, userInfo: this.userInfo,
path: this.path, path: this.path,
@ -132,17 +135,17 @@ export default {
// //
window.eventCenterForAppNameVite = new EventCenterForMicroApp(e.detail.name) window.eventCenterForAppNameVite = new EventCenterForMicroApp(e.detail.name)
this.appData = this.getAppData this.appData = this.getAppData
this.showSpin = window["eventCenterForAppNameViteLoad-" + e.detail.name] ? false : true this.showSpin = !window["eventCenterForAppNameViteLoad-" + e.detail.name]
}, },
handleBeforeMount(e) { handleBeforeMount(e) {
window["eventCenterForAppNameViteLoad-" + e.detail.name] = 1; window["eventCenterForAppNameViteLoad-" + e.detail.name] = 1;
}, },
handleMount(e) { handleMount(e) {
// //
if(this.datas){ if (this.datas) {
this.appData = this.datas; this.appData = this.datas;
} }
if(this.path){ if (this.path) {
this.appData.path = this.path this.appData.path = this.path
} }
this.showSpin = false; this.showSpin = false;

View File

@ -64,7 +64,7 @@
import {mapState} from "vuex"; import {mapState} from "vuex";
import IFrame from "../pages/manage/components/IFrame"; import IFrame from "../pages/manage/components/IFrame";
import {languageType} from "../language"; import {languageName} from "../language";
export default { export default {
name: "OnlyOffice", name: "OnlyOffice",
@ -114,7 +114,7 @@ export default {
}, },
computed: { computed: {
...mapState(['userInfo', 'themeIsDark']), ...mapState(['userInfo', 'themeName']),
fileType() { fileType() {
return this.getType(this.value.type); return this.getType(this.value.type);
@ -211,8 +211,8 @@ export default {
this.docEditor = null; this.docEditor = null;
} }
// //
let lang = languageType; let lang = languageName;
switch (languageType) { switch (languageName) {
case 'zh-CHT': case 'zh-CHT':
lang = "zh-TW"; lang = "zh-TW";
break; break;
@ -239,7 +239,7 @@ export default {
"name": this.userInfo.nickname "name": this.userInfo.nickname
}, },
"customization": { "customization": {
"uiTheme": this.themeIsDark ? "theme-dark" : "theme-classic-light", "uiTheme": this.themeName === 'dark' ? "theme-dark" : "theme-classic-light",
"forcesave": true, "forcesave": true,
"help": false, "help": false,
}, },

View File

@ -43,7 +43,6 @@
<script> <script>
import MarkdownPreview from "./MDEditor/components/preview"; import MarkdownPreview from "./MDEditor/components/preview";
import axios from "axios"; import axios from "axios";
import {mapState} from "vuex";
import {Store} from "le5le-store"; import {Store} from "le5le-store";
export default { export default {
@ -99,12 +98,8 @@ export default {
}, },
computed: { computed: {
isSoftware() {
return this.$Electron || this.$isEEUiApp;
},
showSSO() { showSSO() {
return this.isSoftware && ['login'].includes(this.$route.name) return this.$isSoftware && ['login'].includes(this.$route.name)
}, },
showDown() { showDown() {
@ -119,7 +114,7 @@ export default {
methods: { methods: {
isNotServer() { isNotServer() {
let apiHome = $A.getDomain(window.systemInfo.apiUrl) let apiHome = $A.getDomain(window.systemInfo.apiUrl)
return this.isSoftware && (apiHome == "" || apiHome == "public") return this.$isSoftware && (apiHome == "" || apiHome == "public")
}, },
checkVersion() { checkVersion() {

View File

@ -59,7 +59,7 @@
import tinymce from 'tinymce/tinymce'; import tinymce from 'tinymce/tinymce';
import ImgUpload from "./ImgUpload"; import ImgUpload from "./ImgUpload";
import {mapState} from "vuex"; import {mapState} from "vuex";
import {languageType} from "../language"; import {languageName} from "../language";
const windowTouch = "ontouchend" in document const windowTouch = "ontouchend" in document
@ -191,7 +191,7 @@
this.destroy(); this.destroy();
}, },
computed: { computed: {
...mapState(['themeIsDark']), ...mapState(['themeName']),
headers() { headers() {
return { return {
@ -258,8 +258,8 @@
}, },
option(isFull) { option(isFull) {
let lang = languageType; let lang = languageName;
switch (languageType) { switch (languageName) {
case 'zh': case 'zh':
lang = "zh_CN"; lang = "zh_CN";
break; break;
@ -312,7 +312,7 @@
resize: !isFull, resize: !isFull,
convert_urls:false, convert_urls:false,
toolbar_mode: 'sliding', toolbar_mode: 'sliding',
content_css: this.themeIsDark ? 'dark' : 'default', content_css: this.themeName === 'dark' ? 'dark' : 'default',
setup: (editor) => { setup: (editor) => {
editor.ui.registry.addMenuButton('uploadImages', { editor.ui.registry.addMenuButton('uploadImages', {
text: this.$L('图片'), text: this.$L('图片'),

View File

@ -1055,6 +1055,64 @@ const localforage = require("localforage");
}, },
__loadCss: {}, __loadCss: {},
/**
* 动态加载iframe
* @param url
* @param loadedRemove
* @returns {Promise<unknown>}
*/
loadIframe(url, loadedRemove = 0) {
return new Promise(async (resolve, reject) => {
url = $A.originUrl(url)
//
let i = 0
while (this.__loadIframe[url] === "loading") {
await new Promise(r => setTimeout(r, 1000))
i++
if (i > 30) {
return reject("加载超时")
}
}
if (this.__loadIframe[url] === "loaded") {
return resolve(false)
}
this.__loadIframe[url] = "loading"
//
const iframe = document.createElement("iframe")
iframe.style.display = 'none'
iframe.src = url
iframe.onload = () => {
this.__loadIframe[url] = "loaded"
resolve(true)
if (loadedRemove > 0) {
setTimeout(() => {
document.body.removeChild(iframe)
delete this.__loadIframe[url]
}, loadedRemove)
}
}
iframe.onerror = (e) => {
this.__loadIframe[url] = "error"
reject(e)
}
document.body.appendChild(iframe)
})
},
loadIframes(urls) {
return new Promise(resolve => {
let i = 0
const recursiveCallback = () => {
if (++i < urls.length) {
this.loadIframe(urls[i]).finally(recursiveCallback)
} else {
resolve()
}
}
this.loadIframe(urls[0]).finally(recursiveCallback)
})
},
__loadIframe: {},
/** /**
* 对象中有Date格式的转成指定格式 * 对象中有Date格式的转成指定格式
* @param params * @param params

View File

@ -914,6 +914,17 @@ import {MarkdownPreview} from "../store/markdown";
} }
} }
return false; return false;
},
/**
* 通过Iframe存储数据
* @param json
*/
storageByIframe(json) {
if ($A.isSoftware) {
const value = encodeURIComponent(JSON.stringify(json));
$A.loadIframe($A.apiUrl(`../storage/synch?value=${value}`), 100).catch(_ => {})
}
} }
}); });
@ -1320,7 +1331,6 @@ import {MarkdownPreview} from "../store/markdown";
html { html {
min-width: 100%; min-width: 100%;
min-height: 100%; min-height: 100%;
background: #000;
} }
.child-view { .child-view {
background-color: #fff; background-color: #fff;

View File

@ -1,9 +1,13 @@
const utils = require('./utils') const utils = require('./utils')
const languageList = utils.languageTypes const languageList = utils.languageList
const languageType = utils.getLanguage() const languageName = utils.getLanguage()
const languageRege = {} const languageRege = {}
if (typeof window.LANGUAGE_DATA === "undefined") {
window.LANGUAGE_DATA = {}
}
/** /**
* 添加语言数据 * 添加语言数据
* @param data * @param data
@ -36,18 +40,15 @@ function setLanguage(language, silence = false) {
if (language === undefined) { if (language === undefined) {
return return
} }
if(silence){ if (silence) {
window.localStorage.setItem("__language:type__", language) utils.saveLanguage(language)
$A.reloadUrl() $A.reloadUrl()
}else{ } else {
$A.modalConfirm({ $A.modalConfirm({
content: '切换语言需要刷新后生效,是否确定刷新?', content: '切换语言需要刷新后生效,是否确定刷新?',
cancelText: '取消', cancelText: '取消',
okText: '确定', okText: '确定',
onOk: () => { onOk: () => setLanguage(language, true)
window.localStorage.setItem("__language:type__", language)
$A.reloadUrl()
}
}) })
} }
} }
@ -74,12 +75,12 @@ function switchLanguage(text) {
// //
if (typeof window.LANGUAGE_DATA === "undefined" if (typeof window.LANGUAGE_DATA === "undefined"
|| typeof window.LANGUAGE_DATA["key"] === "undefined" || typeof window.LANGUAGE_DATA["key"] === "undefined"
|| typeof window.LANGUAGE_DATA[languageType] === "undefined") { || typeof window.LANGUAGE_DATA[languageName] === "undefined") {
return text return text
} }
const index = window.LANGUAGE_DATA["key"][text] || -1 const index = window.LANGUAGE_DATA["key"][text] || -1
if (index > -1) { if (index > -1) {
return window.LANGUAGE_DATA[languageType][index] || text return window.LANGUAGE_DATA[languageName][index] || text
} }
if (typeof languageRege[text] === "undefined") { if (typeof languageRege[text] === "undefined") {
languageRege[text] = false languageRege[text] = false
@ -89,7 +90,7 @@ function switchLanguage(text) {
if (rege.test(text)) { if (rege.test(text)) {
let j = 0 let j = 0
const index = window.LANGUAGE_DATA["key"][key] const index = window.LANGUAGE_DATA["key"][key]
const value = (window.LANGUAGE_DATA[languageType][index] || key)?.replace(/\(\*\)/g, function () { const value = (window.LANGUAGE_DATA[languageName][index] || key)?.replace(/\(\*\)/g, function () {
return "$" + (++j) return "$" + (++j)
}) })
languageRege[text] = {rege, value} languageRege[text] = {rege, value}
@ -118,10 +119,11 @@ function switchLanguage(text) {
languageTmp.push(text) languageTmp.push(text)
window.localStorage.setItem(key, JSON.stringify(languageTmp)) window.localStorage.setItem(key, JSON.stringify(languageTmp))
} }
} catch (e) { } } catch (e) {
}
}, 10) }, 10)
} }
return text return text
} }
export { languageType, languageList, addLanguage, setLanguage, getLanguage, switchLanguage } export {languageName, languageList, addLanguage, setLanguage, getLanguage, switchLanguage}

View File

@ -2,7 +2,7 @@ export default {
/** /**
* 语言类型 * 语言类型
*/ */
languageTypes: { languageList: {
"zh": "简体中文", "zh": "简体中文",
"zh-CHT": "繁體中文", "zh-CHT": "繁體中文",
"en": "English", "en": "English",
@ -49,8 +49,8 @@ export default {
* @returns {string} * @returns {string}
*/ */
getLanguage() { getLanguage() {
let lang = window.localStorage.getItem("__language:type__") let lang = window.localStorage.getItem("__system:languageName__")
if (typeof lang === "string" && typeof this.languageTypes[lang] !== "undefined") { if (typeof lang === "string" && typeof this.languageList[lang] !== "undefined") {
return lang; return lang;
} }
lang = 'en'; lang = 'en';
@ -69,12 +69,20 @@ export default {
lang = 'zh-CHT' lang = 'zh-CHT'
break; break;
default: default:
if (typeof this.languageTypes[navLang] !== "undefined") { if (typeof this.languageList[navLang] !== "undefined") {
lang = navLang lang = navLang
} }
break; break;
} }
window.localStorage.setItem("__language:type__", lang) this.saveLanguage(lang)
return lang return lang
} },
/**
* 保存语言
* @param lang
*/
saveLanguage(lang) {
window.localStorage.setItem("__system:languageName__", lang)
},
} }

View File

@ -3,19 +3,13 @@
</template> </template>
<script> <script>
import {languageType} from "../language"; import {languageName} from "../language";
export default { export default {
data() { data() {
return {} return {}
}, },
computed: {
isSoftware() {
return this.$Electron || this.$isEEUiApp;
},
},
mounted() { mounted() {
if (/^https*:/i.test(window.location.protocol)) { if (/^https*:/i.test(window.location.protocol)) {
if (this.$router.mode === "hash") { if (this.$router.mode === "hash") {
@ -36,7 +30,7 @@ export default {
methods: { methods: {
start() { start() {
if (this.isSoftware) { if (this.$isSoftware) {
this.goNext() this.goNext()
return; return;
} }
@ -52,7 +46,7 @@ export default {
}, },
goIndex() { goIndex() {
if (languageType === "zh" || languageType === "zh-CHT") { if (languageName === "zh" || languageName === "zh-CHT") {
window.location.href = $A.apiUrl("../site/zh/index.html") window.location.href = $A.apiUrl("../site/zh/index.html")
} else { } else {
window.location.href = $A.apiUrl("../site/en/index.html") window.location.href = $A.apiUrl("../site/en/index.html")

View File

@ -27,7 +27,7 @@
<transition name="login-mode"> <transition name="login-mode">
<div v-if="loginMode=='access'" class="login-access"> <div v-if="loginMode=='access'" class="login-access">
<Input <Input
v-if="isSoftware && cacheServerUrl" v-if="$isSoftware && cacheServerUrl"
:value="$A.getDomain(cacheServerUrl)" :value="$A.getDomain(cacheServerUrl)"
prefix="ios-globe-outline" prefix="ios-globe-outline"
size="large" size="large"
@ -121,7 +121,7 @@
v-for="(item, key) in themeList" v-for="(item, key) in themeList"
:key="key" :key="key"
:name="item.value" :name="item.value"
:selected="themeMode === item.value">{{$L(item.name)}}</DropdownItem> :selected="themeConf === item.value">{{$L(item.name)}}</DropdownItem>
</DropdownMenu> </DropdownMenu>
</Dropdown> </Dropdown>
<Dropdown placement="right-start" transfer @on-click="onLanguage"> <Dropdown placement="right-start" transfer @on-click="onLanguage">
@ -136,7 +136,7 @@
v-for="(item, key) in languageList" v-for="(item, key) in languageList"
:key="key" :key="key"
:name="key" :name="key"
:selected="languageType === key">{{item}}</DropdownItem> :selected="languageName === key">{{item}}</DropdownItem>
</DropdownMenu> </DropdownMenu>
</Dropdown> </Dropdown>
</DropdownMenu> </DropdownMenu>
@ -165,7 +165,7 @@
<script> <script>
import {mapState} from "vuex"; import {mapState} from "vuex";
import {Store} from "le5le-store"; import {Store} from "le5le-store";
import {languageList, languageType, setLanguage} from "../language"; import {languageList, languageName, setLanguage} from "../language";
import VueQrcode from "@chenfengyuan/vue-qrcode"; import VueQrcode from "@chenfengyuan/vue-qrcode";
export default { export default {
@ -175,7 +175,7 @@ export default {
loadIng: 0, loadIng: 0,
languageList, languageList,
languageType, languageName,
qrcodeVal: '', qrcodeVal: '',
qrcodeTimer: null, qrcodeTimer: null,
@ -210,7 +210,7 @@ export default {
this.privacyShow = !!this.$isEEUiApp && (await $A.IDBString("cachePrivacyShow")) !== "no"; this.privacyShow = !!this.$isEEUiApp && (await $A.IDBString("cachePrivacyShow")) !== "no";
this.email = await $A.IDBString("cacheLoginEmail") || '' this.email = await $A.IDBString("cacheLoginEmail") || ''
// //
if (this.isSoftware) { if (this.$isSoftware) {
this.chackServerUrl().catch(_ => {}); this.chackServerUrl().catch(_ => {});
} else { } else {
this.setServerUrl('').catch(_ => {}); this.setServerUrl('').catch(_ => {});
@ -254,16 +254,12 @@ export default {
...mapState([ ...mapState([
'cacheServerUrl', 'cacheServerUrl',
'themeMode', 'themeConf',
'themeList', 'themeList',
]), ]),
isSoftware() {
return this.$Electron || this.$isEEUiApp;
},
currentLanguage() { currentLanguage() {
return languageList[languageType] || 'Language' return languageList[languageName] || 'Language'
}, },
welcomeTitle() { welcomeTitle() {
@ -493,7 +489,7 @@ export default {
isNotServer() { isNotServer() {
let apiHome = $A.getDomain(window.systemInfo.apiUrl) let apiHome = $A.getDomain(window.systemInfo.apiUrl)
return this.isSoftware && (apiHome == "" || apiHome == "public") return this.$isSoftware && (apiHome == "" || apiHome == "public")
}, },
onBlur() { onBlur() {

View File

@ -205,7 +205,7 @@
</template> </template>
<script> <script>
import { mapState } from "vuex"; import {mapState} from "vuex";
import DrawerOverlay from "../../components/DrawerOverlay"; import DrawerOverlay from "../../components/DrawerOverlay";
import UserSelect from "../../components/UserSelect"; import UserSelect from "../../components/UserSelect";
import Report from "../manage/components/Report"; import Report from "../manage/components/Report";

View File

@ -31,7 +31,7 @@
<script> <script>
import DrawerOverlay from "../../../components/DrawerOverlay"; import DrawerOverlay from "../../../components/DrawerOverlay";
import store from '../../../store/state' import store from '../../../store/state'
import {languageType} from "../../../language"; import {languageName} from "../../../language";
export default { export default {
name: "ApproveSetting", name: "ApproveSetting",
components: {DrawerOverlay}, components: {DrawerOverlay},
@ -48,7 +48,7 @@ export default {
watch: { watch: {
approvalSettingShow(val) { approvalSettingShow(val) {
if (val) { if (val) {
this.iframeSrc = $A.apiUrl(`../approve/#/?name=${this.name}&token=${store.userToken}&lang=${languageType}`) this.iframeSrc = $A.apiUrl(`../approve/#/?name=${this.name}&token=${store.userToken}&lang=${languageName}`)
} }
} }
}, },

View File

@ -137,7 +137,7 @@ export default {
}, },
computed: { computed: {
...mapState(['cacheTasks', 'taskCompleteTemps', 'wsOpenNum', 'themeIsDark']), ...mapState(['cacheTasks', 'taskCompleteTemps', 'wsOpenNum', 'themeName']),
...mapGetters(['transforTasks']), ...mapGetters(['transforTasks']),
@ -189,7 +189,7 @@ export default {
}; };
if (data.p_name) { if (data.p_name) {
let priorityStyle = `background-color:${data.p_color}`; let priorityStyle = `background-color:${data.p_color}`;
if (this.themeIsDark) { if (this.themeName === 'dark') {
priorityStyle = `color:${data.p_color};border:1px solid ${data.p_color};padding:1px 3px;`; priorityStyle = `color:${data.p_color};border:1px solid ${data.p_color};padding:1px 3px;`;
} }
task.priority = `<span class="priority" style="${priorityStyle}">${data.p_name}</span>`; task.priority = `<span class="priority" style="${priorityStyle}">${data.p_name}</span>`;

View File

@ -55,8 +55,6 @@
</template> </template>
<script> <script>
import {mapState} from "vuex";
export default { export default {
name: "ProjectArchived", name: "ProjectArchived",
data() { data() {

View File

@ -79,8 +79,6 @@
</template> </template>
<script> <script>
import {mapState} from "vuex";
export default { export default {
name: "ProjectManagement", name: "ProjectManagement",
data() { data() {

View File

@ -24,11 +24,11 @@ export default {
} }
}, },
computed: { computed: {
...mapState(['themeIsDark']), ...mapState(['themeName']),
myStyle() { myStyle() {
const {color, background, backgroundColor, themeIsDark} = this; const {color, background, backgroundColor, themeName} = this;
if (themeIsDark) { if (themeName === 'dark') {
return { return {
color: backgroundColor || background, color: backgroundColor || background,
borderColor: backgroundColor || background, borderColor: backgroundColor || background,

View File

@ -432,7 +432,6 @@
</template> </template>
<script> <script>
import axios from "axios";
import {mapState} from "vuex"; import {mapState} from "vuex";
import {sortBy} from "lodash"; import {sortBy} from "lodash";
import DrawerOverlay from "../../components/DrawerOverlay"; import DrawerOverlay from "../../components/DrawerOverlay";

View File

@ -15,7 +15,7 @@
</template> </template>
<script> <script>
import {languageList, languageType, setLanguage} from "../../../language"; import {languageList, languageName, setLanguage} from "../../../language";
import {mapState} from "vuex"; import {mapState} from "vuex";
export default { export default {
@ -43,7 +43,7 @@ export default {
methods: { methods: {
initData() { initData() {
this.$set(this.formData, 'language', languageType); this.$set(this.formData, 'language', languageName);
this.formData_bak = $A.cloneJSON(this.formData); this.formData_bak = $A.cloneJSON(this.formData);
}, },

View File

@ -36,7 +36,7 @@ export default {
computed: { computed: {
...mapState([ ...mapState([
'themeMode', 'themeConf',
'themeList', 'themeList',
'formLabelPosition', 'formLabelPosition',
'formLabelWidth' 'formLabelWidth'
@ -45,7 +45,7 @@ export default {
methods: { methods: {
initData() { initData() {
this.$set(this.formData, 'theme', this.themeMode); this.$set(this.formData, 'theme', this.themeConf);
this.formData_bak = $A.cloneJSON(this.formData); this.formData_bak = $A.cloneJSON(this.formData);
}, },

View File

@ -2,11 +2,11 @@
</template> </template>
<script> <script>
import {languageType} from "../language"; import {languageName} from "../language";
export default { export default {
mounted() { mounted() {
if (languageType === "zh" || languageType === "zh-CHT") { if (languageName === "zh" || languageName === "zh-CHT") {
window.location.href = $A.apiUrl("../site/zh/price.html") window.location.href = $A.apiUrl("../site/zh/price.html")
} else { } else {
window.location.href = $A.apiUrl("../site/en/price.html") window.location.href = $A.apiUrl("../site/en/price.html")

View File

@ -1,6 +1,6 @@
import {Store} from 'le5le-store'; import {Store} from 'le5le-store';
import * as openpgp from 'openpgp_hi/lightweight'; import * as openpgp from 'openpgp_hi/lightweight';
import {languageType} from "../language"; import {languageName} from "../language";
import {$callData, $urlSafe, SSEClient} from './utils' import {$callData, $urlSafe, SSEClient} from './utils'
export default { export default {
@ -83,8 +83,9 @@ export default {
// 加载语言包 // 加载语言包
await $A.loadScriptS([ await $A.loadScriptS([
`language/web/key.js`, `language/web/key.js`,
`language/web/${languageType}.js`, `language/web/${languageName}.js`,
]) ])
$A.storageByIframe({languageName})
resolve(action) resolve(action)
}) })
@ -101,7 +102,7 @@ export default {
if (!$A.isJson(params)) params = {url: params} if (!$A.isJson(params)) params = {url: params}
const header = { const header = {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'language': languageType, 'language': languageName,
'token': state.userToken, 'token': state.userToken,
'fd': $A.getSessionStorageString("userWsFd"), 'fd': $A.getSessionStorageString("userWsFd"),
'version': window.systemInfo.version || "0.0.1", 'version': window.systemInfo.version || "0.0.1",
@ -464,10 +465,11 @@ export default {
/** /**
* 设置主题 * 设置主题
* @param state * @param state
* @param dispatch
* @param mode * @param mode
* @returns {Promise<unknown>} * @returns {Promise<unknown>}
*/ */
setTheme({state}, mode) { setTheme({state, dispatch}, mode) {
return new Promise(function (resolve) { return new Promise(function (resolve) {
if (mode === undefined) { if (mode === undefined) {
resolve(false) resolve(false)
@ -482,6 +484,21 @@ export default {
resolve(false) resolve(false)
return; return;
} }
dispatch("synchTheme", mode)
resolve(true)
});
},
/**
* 同步主题
* @param state
* @param dispatch
* @param mode
*/
synchTheme({state, dispatch}, mode = undefined) {
if (typeof mode === "undefined") {
mode = state.themeConf
}
switch (mode) { switch (mode) {
case 'dark': case 'dark':
$A.dark.enableDarkMode() $A.dark.enableDarkMode()
@ -490,34 +507,20 @@ export default {
$A.dark.disableDarkMode() $A.dark.disableDarkMode()
break; break;
default: default:
state.themeConf = "auto"
$A.dark.autoDarkMode() $A.dark.autoDarkMode()
break; break;
} }
state.themeMode = mode; state.themeName = $A.dark.isDarkEnabled() ? 'dark' : 'light'
state.themeIsDark = $A.dark.isDarkEnabled(); window.localStorage.setItem("__system:themeConf__", state.themeConf)
window.localStorage.setItem("__theme:mode__", mode); //
resolve(true) if ($A.isEEUiApp) {
$A.eeuiAppSendMessage({
action: 'updateTheme',
themeName: state.themeName,
}); });
},
/**
* 同步主题
* @param state
*/
synchTheme({state}) {
switch (state.themeMode) {
case 'dark':
$A.dark.enableDarkMode()
break;
case 'light':
$A.dark.disableDarkMode()
break;
default:
state.themeMode = "auto"
$A.dark.autoDarkMode()
break;
} }
state.themeIsDark = $A.dark.isDarkEnabled() $A.storageByIframe({themeConf: state.themeConf})
}, },
/** /**
@ -833,11 +836,15 @@ export default {
*/ */
handleKeyboard({state}, newData) { handleKeyboard({state}, newData) {
return new Promise(resolve => { return new Promise(resolve => {
const data = $A.isJson(newData) ? newData : ($A.jsonParse(window.localStorage.getItem("__keyboard:data__")) || {}) if (!window.localStorage.getItem("__system:keyboardConf__")) {
window.localStorage.setItem("__system:keyboardConf__", window.localStorage.getItem("__keyboard:data__"))
window.localStorage.removeItem("__keyboard:data__")
}
const data = $A.isJson(newData) ? newData : ($A.jsonParse(window.localStorage.getItem("__system:keyboardConf__")) || {})
data.screenshot_key = (data.screenshot_key || "").trim().toLowerCase() data.screenshot_key = (data.screenshot_key || "").trim().toLowerCase()
data.send_button_app = data.send_button_app || 'button' // button, enter 移动端发送按钮,默认 button (页面按钮发送) data.send_button_app = data.send_button_app || 'button' // button, enter 移动端发送按钮,默认 button (页面按钮发送)
data.send_button_desktop = data.send_button_desktop || 'enter' // button, enter 桌面端发送按钮,默认 enter (键盘回车发送) data.send_button_desktop = data.send_button_desktop || 'enter' // button, enter 桌面端发送按钮,默认 enter (键盘回车发送)
window.localStorage.setItem("__keyboard:data__", $A.jsonStringify(data)) window.localStorage.setItem("__system:keyboardConf__", $A.jsonStringify(data))
state.cacheKeyboard = data state.cacheKeyboard = data
resolve(data) resolve(data)
}) })
@ -854,13 +861,13 @@ export default {
return new Promise(async resolve => { return new Promise(async resolve => {
try { try {
// localStorage // localStorage
const languageType = window.localStorage.getItem("__language:type__"); const themeConf = window.localStorage.getItem("__system:themeConf__");
const keyboardData = window.localStorage.getItem("__keyboard:data__"); const languageName = window.localStorage.getItem("__system:languageName__");
const themeMode = window.localStorage.getItem("__theme:mode__"); const keyboardConf = window.localStorage.getItem("__system:keyboardConf__");
window.localStorage.clear(); window.localStorage.clear();
window.localStorage.setItem("__language:type__", languageType) window.localStorage.setItem("__system:themeConf__", themeConf)
window.localStorage.setItem("__keyboard:data__", keyboardData) window.localStorage.setItem("__system:languageName__", languageName)
window.localStorage.setItem("__theme:mode__", themeMode) window.localStorage.setItem("__system:keyboardConf__", keyboardConf)
// localForage // localForage
const clientId = await $A.IDBString("clientId") const clientId = await $A.IDBString("clientId")
@ -3372,7 +3379,7 @@ export default {
let url = $A.apiUrl('../ws'); let url = $A.apiUrl('../ws');
url = url.replace("https://", "wss://"); url = url.replace("https://", "wss://");
url = url.replace("http://", "ws://"); url = url.replace("http://", "ws://");
url += `?action=web&token=${state.userToken}&language=${languageType}`; url += `?action=web&token=${state.userToken}&language=${languageName}`;
// //
const wgLog = $A.openLog; const wgLog = $A.openLog;
const wsRandom = $A.randomString(16); const wsRandom = $A.randomString(16);

View File

@ -188,13 +188,13 @@ export default {
], ],
// 主题皮肤 // 主题皮肤
themeMode: window.localStorage.getItem("__theme:mode__"), themeConf: window.localStorage.getItem("__system:themeConf__"), // auto|light|dark
themeName: null, // 自动生成
themeList: [ themeList: [
{name: '跟随系统', value: 'auto'}, {name: '跟随系统', value: 'auto'},
{name: '明亮', value: 'light'}, {name: '明亮', value: 'light'},
{name: '暗黑', value: 'dark'}, {name: '暗黑', value: 'dark'},
], ],
themeIsDark: false,
// 客户端新版本号 // 客户端新版本号
clientNewVersion: null, clientNewVersion: null,

View File

@ -0,0 +1,14 @@
let themeName = window.localStorage.getItem('__system:themeConf__')
if (!['dark', 'light'].includes(themeName)) {
let isDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches
if (/eeui/i.test(window.navigator.userAgent)) {
isDark = requireModuleJs("eeui").getThemeName() === "dark"
}
themeName = isDark ? 'dark' : 'light'
}
if (themeName === 'dark') {
let style = document.createElement('style');
style.rel = 'stylesheet';
style.innerHTML = '.app-view-loading{background-color:#0D0D0D}'
document.head.appendChild(style);
}

View File

@ -16,6 +16,7 @@
@endif @endif
<link rel="stylesheet" type="text/css" href="{{ asset_main('css/iview.css') }}?v={{ $version }}"> <link rel="stylesheet" type="text/css" href="{{ asset_main('css/iview.css') }}?v={{ $version }}">
<link rel="stylesheet" type="text/css" href="{{ asset_main('css/loading.css') }}?v={{ $version }}"> <link rel="stylesheet" type="text/css" href="{{ asset_main('css/loading.css') }}?v={{ $version }}">
<script src="{{ asset_main('js/loading-theme.js') }}?v={{ $version }}"></script>
<script src="{{ asset_main('js/jsencrypt.min.js') }}?v={{ $version }}"></script> <script src="{{ asset_main('js/jsencrypt.min.js') }}?v={{ $version }}"></script>
<script src="{{ asset_main('js/scroll-into-view.min.js') }}?v={{ $version }}"></script> <script src="{{ asset_main('js/scroll-into-view.min.js') }}?v={{ $version }}"></script>
<script> <script>
@ -36,7 +37,7 @@
@extends('ie') @extends('ie')
<div id="app"> <div id="app">
<div class="app-view-loading"> <div class="app-view-loading no-dark-mode">
<div> <div>
<div>PAGE LOADING</div> <div>PAGE LOADING</div>
<span></span> <span></span>

View File

@ -1,14 +0,0 @@
<script>
@if ($theme)
window.localStorage.setItem("__theme:mode__", "{{ $theme }}");
@endif
@if ($language)
window.localStorage.setItem("__language:type__", "{{ $language }}");
@endif
@if ($userid)
window.localStorage.setItem("__user:userid__", "{{ $userid }}");
@endif
@if ($token)
window.localStorage.setItem("__user:token__", "{{ $token }}");
@endif
</script>

View File

@ -0,0 +1,21 @@
<script>
function isArray(obj) {
return typeof (obj) == "object" && Object.prototype.toString.call(obj).toLowerCase() == '[object array]' && typeof obj.length == "number";
}
function isJson(obj) {
return typeof (obj) == "object" && Object.prototype.toString.call(obj).toLowerCase() == "[object object]" && typeof obj.length == "undefined";
}
let storages = {!! $value !!};
if (isArray(storages)) {
storages.forEach(storage => {
window.localStorage.setItem(`__system:${storage.key}__`, storage.value);
})
} else if (isJson(storages)) {
for (let key in storages) {
let value = storages[key];
window.localStorage.setItem(`__system:${key}__`, value);
}
}
</script>