├── .gitignore ├── .idea ├── ideawall.iml ├── markdown-navigator.xml ├── markdown-navigator │ └── profiles_settings.xml ├── misc.xml ├── modules.xml └── vcs.xml ├── .yarnclean ├── LICENSE ├── QUES.md ├── README.md ├── app ├── .yarnclean ├── App.js ├── assets │ ├── css │ │ ├── about.css │ │ ├── animate.css │ │ ├── comment.css │ │ ├── control-mydesk.css │ │ ├── control.css │ │ ├── deskstore.css │ │ ├── feedback.css │ │ ├── form.css │ │ ├── ideawall.css │ │ ├── imodal.css │ │ ├── info.css │ │ ├── iview-site.css │ │ ├── preference.css │ │ └── wall.css │ ├── extends │ │ └── netbroken │ │ │ ├── css │ │ │ └── netbroken.css │ │ │ ├── images │ │ │ ├── default_100_percent │ │ │ │ ├── 100-disabled.png │ │ │ │ ├── 100-error-offline.png │ │ │ │ └── 100-offline-sprite.png │ │ │ ├── default_200_percent │ │ │ │ ├── 200-disabled.png │ │ │ │ ├── 200-error-offline.png │ │ │ │ └── 200-offline-sprite.png │ │ │ ├── hello-kugou.gif │ │ │ ├── kumamon-runner.gif │ │ │ ├── novas-coisas.gif │ │ │ ├── offline-sprite-1x.png │ │ │ ├── offline-sprite-2x.png │ │ │ ├── screenshot.gif │ │ │ ├── t-rex-runner-19janil.gif │ │ │ └── t-rex-runner-bot.gif │ │ │ └── js │ │ │ └── netbroken.js │ ├── fonts │ │ ├── infonts │ │ │ └── alipay │ │ │ │ ├── alipay.eot │ │ │ │ ├── alipay.svg │ │ │ │ ├── alipay.ttf │ │ │ │ └── alipay.woff │ │ ├── ionicons.svg │ │ ├── ionicons.ttf │ │ ├── ionicons.woff │ │ └── iview-site │ │ │ ├── iview-site.svg │ │ │ ├── iview-site.ttf │ │ │ └── iview-site.woff │ ├── images │ │ ├── 404.jpg │ │ ├── building │ │ │ ├── 1.gif │ │ │ ├── 2.gif │ │ │ ├── 3.gif │ │ │ └── 4.gif │ │ ├── comp.png │ │ ├── imac.png │ │ ├── kong.png │ │ ├── loading.jpg │ │ ├── offline.png │ │ └── online.png │ ├── js │ │ ├── jquery.min.js │ │ ├── share.js │ │ ├── vue.min.js │ │ └── zxx.min.js │ └── lib │ │ ├── element-ui │ │ ├── css │ │ │ └── element.css │ │ ├── fonts │ │ │ ├── element-icons.ttf │ │ │ └── element-icons.woff │ │ └── js │ │ │ └── element.min.js │ │ ├── font-awesome │ │ ├── css │ │ │ ├── font-awesome.css │ │ │ └── font-awesome.min.css │ │ └── fonts │ │ │ ├── FontAwesome.otf │ │ │ ├── fontawesome-webfont.eot │ │ │ ├── fontawesome-webfont.svg │ │ │ ├── fontawesome-webfont.ttf │ │ │ ├── fontawesome-webfont.woff │ │ │ └── fontawesome-webfont.woff2 │ │ ├── iview │ │ ├── css │ │ │ └── iview.css │ │ └── js │ │ │ └── iview.min.js │ │ └── json-editor │ │ ├── img │ │ └── jsoneditor-icons.svg │ │ ├── jsoneditor-minimalist.js │ │ ├── jsoneditor-minimalist.min.js │ │ ├── jsoneditor.css │ │ ├── jsoneditor.js │ │ ├── jsoneditor.min.css │ │ └── jsoneditor.min.js ├── config │ └── appconfig.json ├── controller │ ├── AboutController.js │ ├── BaseController.js │ ├── BrowserController.js │ ├── CommentController.js │ ├── ControlController.js │ ├── DevStoreController.js │ ├── DeviceInfoController.js │ ├── FeedbackController.js │ ├── HighConfigController.js │ ├── InfoController.js │ ├── JsonEditorController.js │ ├── MediaConfigController.js │ ├── MyDeskController.js │ ├── PageController.js │ ├── PictureController.js │ ├── PreferenceController.js │ ├── PreviewController.js │ ├── ProtectorController.js │ ├── ReadmeController.js │ ├── ResBBSController.js │ ├── VideoController.js │ └── WallController.js ├── core │ ├── Agent.js │ ├── Async.js │ ├── Config.js │ ├── Crypto.js │ ├── Database.js │ ├── Database4Lowdb.js │ ├── Datetime.js │ ├── Download.js │ ├── Fs.js │ ├── Http.js │ ├── Lang.js │ ├── Logger.js │ ├── Model.js │ ├── Notification.js │ ├── Regxp.js │ ├── Screen.js │ ├── Storage.js │ ├── Typer.js │ └── UUID.js ├── dao │ ├── DeviceDeskDao.js │ ├── LocalDeskDao.js │ ├── MediaDao.js │ └── PreferenceDao.js ├── message │ └── DeviceMessage.js ├── model │ ├── DeviceDeskModel.js │ ├── LocalDeskModel.js │ ├── MediaModel.js │ └── PreferenceModel.js ├── package.json ├── process │ ├── main │ │ ├── AppVar.js │ │ ├── ApplicationMenu.js │ │ ├── AutoLaunch.js │ │ ├── AutoUpdater.js │ │ ├── CrashReporter.js │ │ ├── Dialog.js │ │ ├── Dock.js │ │ ├── GlobalShortCut.js │ │ ├── MainProcessHelper.js │ │ ├── PowerMonitor.js │ │ ├── TaskBar.js │ │ ├── Tray.js │ │ └── window │ │ │ ├── AboutWindow.js │ │ │ ├── ControlWindow.js │ │ │ ├── DeviceInfoWindow.js │ │ │ ├── JsonEditorWindow.js │ │ │ ├── PreviewWindow.js │ │ │ ├── ProtectorWindow.js │ │ │ ├── ReadmeWindow.js │ │ │ ├── WallWindow.js │ │ │ └── XBrowserWindow.js │ └── renderer │ │ └── RendererProcessHelper.js ├── resolver │ ├── ArchiveResolver.js │ ├── MailResolver.js │ └── UUIDResolver.js ├── service │ ├── BaseService.js │ ├── MenuService.js │ └── StatusService.js ├── static │ ├── icon │ │ ├── 128.icns │ │ ├── 128.ico │ │ ├── 256.ico │ │ ├── 512.ico │ │ └── 64.ico │ ├── logo │ │ ├── logo-blue.png │ │ ├── logo-blue_128.png │ │ ├── logo-blue_256.png │ │ ├── logo-blue_64.png │ │ ├── logo-blue_64@3x.png │ │ └── logo-jb.png │ └── tray │ │ ├── 100x100.png │ │ ├── 100x100@5x.png │ │ ├── 16x16.png │ │ ├── 200x200.png │ │ ├── 32x32.png │ │ ├── 48x48.png │ │ └── 64x64.png ├── task │ └── UpdateTask.js ├── test │ └── test.js ├── third │ └── Share.js ├── util │ ├── AvatarUtil.js │ ├── PinyinUtil.js │ └── VerifyCodeUtil.js ├── view │ ├── components │ │ ├── About.html │ │ ├── Browser.html │ │ ├── Control.html │ │ ├── DeviceInfo.html │ │ ├── JsonEditor.html │ │ ├── Preview.html │ │ ├── Protector.html │ │ ├── Readme.html │ │ ├── Wall.html │ │ ├── control │ │ │ ├── DeskStore.html │ │ │ ├── Feedback.html │ │ │ ├── MyDesk.html │ │ │ ├── Preference.html │ │ │ ├── ResBBS.html │ │ │ └── mydesk │ │ │ │ ├── Comment.html │ │ │ │ ├── HighConfig.html │ │ │ │ ├── Info.html │ │ │ │ └── MediaConfig.html │ │ └── wall │ │ │ ├── Page.html │ │ │ ├── Picture.html │ │ │ └── Video.html │ ├── errors │ │ ├── building.html │ │ └── netbroken.html │ └── modal │ │ └── Share.Modal.html └── yarn.lock ├── init.js ├── package-lock.json ├── package-macos-app.json ├── package-macos.json ├── package-win32-app.json ├── package-win32.json ├── package.json └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | build 4 | .idea 5 | .vscode -------------------------------------------------------------------------------- /.idea/ideawall.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/markdown-navigator/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.yarnclean: -------------------------------------------------------------------------------- 1 | # test directories 2 | __tests__ 3 | test 4 | tests 5 | powered-test 6 | 7 | # asset directories 8 | docs 9 | doc 10 | website 11 | images 12 | assets 13 | 14 | # examples 15 | example 16 | examples 17 | 18 | # code coverage directories 19 | coverage 20 | .nyc_output 21 | 22 | # build scripts 23 | Makefile 24 | Gulpfile.js 25 | Gruntfile.js 26 | 27 | # configs 28 | appveyor.yml 29 | circle.yml 30 | codeship-services.yml 31 | codeship-steps.yml 32 | wercker.yml 33 | .tern-project 34 | .gitattributes 35 | .editorconfig 36 | .*ignore 37 | .eslintrc 38 | .jshintrc 39 | .flowconfig 40 | .documentup.json 41 | .yarn-metadata.json 42 | .travis.yml 43 | 44 | # misc 45 | *.md 46 | -------------------------------------------------------------------------------- /app/.yarnclean: -------------------------------------------------------------------------------- 1 | # test directories 2 | __tests__ 3 | test 4 | tests 5 | powered-test 6 | 7 | # asset directories 8 | docs 9 | doc 10 | website 11 | images 12 | assets 13 | 14 | # examples 15 | example 16 | examples 17 | 18 | # code coverage directories 19 | coverage 20 | .nyc_output 21 | 22 | # build scripts 23 | Makefile 24 | Gulpfile.js 25 | Gruntfile.js 26 | 27 | # configs 28 | appveyor.yml 29 | circle.yml 30 | codeship-services.yml 31 | codeship-steps.yml 32 | wercker.yml 33 | .tern-project 34 | .gitattributes 35 | .editorconfig 36 | .*ignore 37 | .eslintrc 38 | .jshintrc 39 | .flowconfig 40 | .documentup.json 41 | .yarn-metadata.json 42 | .travis.yml 43 | 44 | # misc 45 | *.md 46 | -------------------------------------------------------------------------------- /app/App.js: -------------------------------------------------------------------------------- 1 | /*主进程*/ 2 | const { 3 | app 4 | } = require('electron'); 5 | 6 | 7 | /** 8 | * 单例锁控制 9 | * 10 | * 通过 app.hasSingleInstanceLock() 判断应用实例当前是否持有单例锁 11 | * 可以通过 app.requestSingleInstanceLock() 请求锁,并且通过 app.releaseSingleInstanceLock() 释放锁。 12 | */ 13 | const gotTheLock = app.requestSingleInstanceLock(); 14 | 15 | if (!gotTheLock) { 16 | app.exit(0); //比 app.quit 更快. 17 | } else { 18 | const logger = require('./core/Logger'); 19 | const helper = require('./process/main/MainProcessHelper'); 20 | const dialog = require('./process/main/Dialog'); 21 | const tray = require('./process/main/Tray'); 22 | const dock = require('./process/main/Dock'); 23 | const AppVar = require('./process/main/AppVar'); 24 | AppVar.checkAppWorkSpace(); //工作命名空间构建 25 | let appVar = AppVar.getAppVar(), 26 | appTray, windows; //全局变量, 防止自动垃圾回收. 27 | const preferenceModel = require('./model/PreferenceModel')(appVar); 28 | preferenceModel.initial(); 29 | 30 | /** 31 | * 获取预阶段配置项 32 | */ 33 | var pref_autoOpenControl = preferenceModel.getByKey("autoOpenControl"); 34 | pref_autoOpenControl = JSON.parse(pref_autoOpenControl.value).enable; 35 | 36 | app.on('second-instance', (event, commandLine, workingDirectory) => { 37 | // 当运行第二个实例时, 相当于重新激活一次. 38 | if (!appTray) { 39 | appTray = tray.init(appVar); 40 | } 41 | dock.init(appVar); 42 | helper.getWallWindow(); 43 | helper.getControlWindow(pref_autoOpenControl || appVar._guide);//如果是首次启动, 自动打开 44 | // //如果当前没有窗口被激活,则创建窗口 45 | // var res = helper.getWallWindow(); 46 | // if (res.result || pref_autoOpenControl) { //如果壁纸窗口已经存在, 就打开控制面板窗口. 47 | // helper.getControlWindow(true); 48 | // } 49 | }); 50 | 51 | 52 | // 这个方法将会在electron初始化完成后被调用 53 | // 某些API只能在初始化之后(此状态之后)被调用 54 | app.on('ready', () => { 55 | const autolaunch = require('./process/main/AutoLaunch'); 56 | const autoUpdater = require('./process/main/AutoUpdater'); 57 | 58 | /** 59 | * 以下 Chrome 指令用以解决: 60 | * Chrome 内核 66+ 版本的新策略: 仅在静音且可视情况下, 才允许音视频自动播放, 否则, 需等待一个交互交互. 61 | */ 62 | app.commandLine.appendSwitch('autoplay-policy', 'no-user-gesture-required'); 63 | //关闭video画中画 64 | app.commandLine.appendSwitch('enable-picture-in-picture', 'disabled'); 65 | 66 | if(appVar._platform === 'darwin') { 67 | var pref_hidedock = preferenceModel.getByKey("hideDock"); 68 | pref_hidedock.value = JSON.parse(pref_hidedock.value); 69 | if (pref_hidedock.value.enable) { 70 | app.dock.hide(); 71 | } 72 | } 73 | 74 | /** 75 | * 开机自启动鉴定[首次启动自动加入开机自启动] 76 | */ 77 | autolaunch.init(appVar, preferenceModel); 78 | 79 | /** 80 | * 初始化壁纸层窗口 81 | */ 82 | helper.getWallWindow(); 83 | helper.getControlWindow(pref_autoOpenControl || appVar._guide); //防止启动的时候资源占用超负荷, 暂时不启用. 84 | 85 | /** 86 | * 初始化系统托盘 87 | */ 88 | appTray = tray.init(appVar); 89 | 90 | dock.init(appVar); 91 | 92 | /** 93 | * 启动自动更新任务 94 | */ 95 | try { 96 | autoUpdater.updateHandle(appVar); 97 | } catch (e) { 98 | //... 99 | } 100 | }); 101 | 102 | //在应用程序开始关闭其窗口之前发出。调用event.preventDefault()将阻止默认行为,这将终止应用程序。 103 | // 注意:如果应用程序quit是由autoupdater.quitandinstall()启动的,那么在所有窗口上发出close事件并关闭它们之后,将发出before quit。 104 | app.on('before-quit', function () { 105 | logger.info("before-quit"); 106 | AppVar.setAppVar({_destory: true}); 107 | }); 108 | 109 | // 当所有窗口关闭时关闭应用程序 110 | app.on('window-all-closed', function () { 111 | logger.info("window-all-closed"); 112 | app.quit(); 113 | if (process.platform !== 'darwin') { //如果是非 mac 系统, 直接退出 114 | 115 | } //如果是 mac 系统, 关闭所有窗口就好, 等待重新唤醒. 116 | }); 117 | 118 | //当应用程序准备退出时执行动作 119 | //在 Windows 系统中,如果应用程序因系统关机/重启或用户注销而关闭,那么这个事件不会被触发。 120 | app.on('will-quit', () => { 121 | logger.info("will-quit"); 122 | //... 123 | }); 124 | 125 | //在应用程序退出时发出 126 | //在 Windows 系统中,如果应用程序因系统关机/重启或用户注销而关闭,那么这个事件不会被触发。 127 | app.on('quit', () => { 128 | logger.info("quit"); 129 | app.releaseSingleInstanceLock();//释放所有的单例锁 130 | tray.fuck(); //干掉托盘 131 | appTray = null; 132 | }); 133 | 134 | //当应用程序激活时,通常在macOS下, win下基本见不到. 135 | app.on('activate', function () { 136 | logger.info("activate"); 137 | if (!appTray) { 138 | appTray = tray.init(appVar); 139 | } 140 | dock.init(appVar); 141 | helper.getWallWindow(); 142 | helper.getControlWindow(true); 143 | }); 144 | } 145 | 146 | /* ↑app对象生命周期维护结束↑ */ -------------------------------------------------------------------------------- /app/assets/css/about.css: -------------------------------------------------------------------------------- 1 | .zxx-about-container { 2 | display: flex; 3 | width: 100%; 4 | height: 275px; 5 | text-align: center; 6 | background: rgb(255, 255, 255); 7 | padding: 20px 0 40px; 8 | position: relative; 9 | } 10 | 11 | .zxx-about-left { 12 | width: 300px; 13 | } 14 | 15 | .zxx-about-left img { 16 | width: 150px; 17 | } 18 | 19 | .zxx-about-right { 20 | width: 100%; 21 | text-align: left; 22 | padding-left: 15px; 23 | } 24 | 25 | .zxx-about-right h1.topic { 26 | color: #333; 27 | margin-bottom: 5px; 28 | 29 | /*线性颜色渐变*/ 30 | background-image: -webkit-linear-gradient(left, magenta, blue, red); 31 | -webkit-background-clip: text; 32 | -webkit-text-fill-color: transparent; 33 | } 34 | 35 | .zxx-about-right p { 36 | font-size: 11px; 37 | color: rgb(132, 132, 132); 38 | } 39 | 40 | .zxx-about-right p.version { 41 | font-weight: 600; 42 | font-size: 11px; 43 | color: rgb(128, 128, 128); 44 | margin-bottom: 15px; 45 | } 46 | 47 | .zxx-about-right p.coyright { 48 | position: absolute; 49 | bottom: 10px; 50 | } 51 | 52 | .zxx-about-bottom { 53 | width: 100%; 54 | height: 50px; 55 | background: rgb(236, 236, 236); 56 | text-align: right; 57 | border-top: 1px solid rgb(170, 170, 170); 58 | line-height: 40px; 59 | padding: 0 20px; 60 | } -------------------------------------------------------------------------------- /app/assets/css/comment.css: -------------------------------------------------------------------------------- 1 | html, body, #app { 2 | margin: 0; 3 | padding: 0; 4 | width: 100%; 5 | height: 100%; 6 | background: transparent; 7 | overflow-y: auto; 8 | overflow-x: hidden; 9 | } 10 | 11 | #comment-containter{ 12 | padding: 10px; 13 | } 14 | -------------------------------------------------------------------------------- /app/assets/css/control-mydesk.css: -------------------------------------------------------------------------------- 1 | .zxx-desk-list-container { 2 | width: 100%; 3 | word-wrap: break-word; 4 | word-break: break-all; 5 | padding: 5px 10px; 6 | overflow-y: auto; 7 | overflow-x: hidden; 8 | } 9 | 10 | .zxx-desk-info-container { 11 | width: 312px; 12 | border-left: 1px solid #eee; 13 | padding-top: 5px; 14 | position: relative; 15 | } 16 | 17 | .zxx-desk-info-container-loading { 18 | position: absolute; 19 | top: 37px; 20 | left: 0; 21 | width: 100%; 22 | height: calc(100% - 37px); 23 | background: transparent; 24 | z-index: 20000; 25 | pointer-events: none; 26 | 27 | } 28 | 29 | .el-dropdown { 30 | font-size: 12px; 31 | cursor: pointer; 32 | } 33 | 34 | .el-card, .el-card__body { 35 | width: 200px; 36 | height: 142px; 37 | } 38 | 39 | .zxx-desk-bg { 40 | width: 200px; 41 | height: 112px; 42 | } 43 | 44 | .el-card__body { 45 | padding: 0; 46 | } 47 | 48 | .el-tag { 49 | margin-right: 8px; 50 | margin-left: 1px; 51 | cursor: pointer; 52 | font-weight: normal; 53 | } 54 | 55 | .zxx-desk-con { 56 | float: left; 57 | margin: 10px; 58 | } 59 | 60 | .zxx-desk-panel { 61 | position: relative; 62 | cursor: pointer; 63 | } 64 | 65 | .zxx-desk-overlay-control { 66 | position: absolute; 67 | top: 45px; 68 | left: 85px; 69 | font-size: 25px; 70 | font-weight: bold; 71 | color: #0094E3; 72 | } 73 | 74 | .zxx-desk-tooltip { 75 | overflow: hidden; 76 | } 77 | 78 | .zxx-desk-tooltip-control { 79 | position: absolute; 80 | top: 0; 81 | right: 0; 82 | font-size: 25px; 83 | font-weight: bold; 84 | color: #67c23a; 85 | } 86 | 87 | .zxx-desk-tooltip-control2 { 88 | position: absolute; 89 | top: 0; 90 | right: 0; 91 | font-size: 12px; 92 | color: #fff; 93 | background: #409eff; 94 | border: 1px solid #409eff; 95 | border-radius: 3px; 96 | padding: 2px; 97 | } 98 | 99 | .zxx-desk-tooltip-edit { 100 | position: absolute; 101 | bottom: 0; 102 | left: 0; 103 | width: 100%; 104 | color: #fff; 105 | background: #000; 106 | opacity: 0.75; 107 | filter: opacity(75%); 108 | padding: 0 2px; 109 | z-index: 520; 110 | font-size: 12px; 111 | line-height: 20px; 112 | height: 20px; 113 | font-family: normal; 114 | padding-left: 5px; 115 | } 116 | 117 | .zxx-desk-tooltip-left { 118 | position: absolute; 119 | top: 0; 120 | left: 0; 121 | font-size: 12px; 122 | color: #000; 123 | background: #FFF; 124 | border: 1px solid #eee; 125 | border-bottom-right-radius: 5px; 126 | padding: 3px 4px; 127 | } 128 | 129 | .zxx-desk-tooltip-right { 130 | position: absolute; 131 | top: 0; 132 | right: 0; 133 | font-size: 12px; 134 | color: #000; 135 | background: #FFF; 136 | border: 1px solid #eee; 137 | border-bottom-right-radius: 5px; 138 | padding: 3px 4px; 139 | } 140 | 141 | .zxx-desk-m-title { 142 | border-bottom: 1px solid #eee; 143 | margin: 5px 0; 144 | font-weight: normal; 145 | padding-bottom: 3px; 146 | font-size: 15px; 147 | } 148 | 149 | #my-device { 150 | min-height: 194px; 151 | } 152 | 153 | #my-desktop { 154 | margin-top: 20px; 155 | } 156 | 157 | .zxx-desk-info-container .el-tabs__content { 158 | height: calc(100% - 32px); 159 | } 160 | 161 | .zxx-desk-info-container .el-tabs__item { 162 | height: 30px; 163 | font-weight: 400; 164 | font-size: 12px; 165 | line-height: 30px; 166 | -webkit-app-region: no-drag; 167 | z-index: 20190105; 168 | } 169 | 170 | .zxx-desk-info-name { 171 | width: calc(100% - 45px); 172 | float: left; 173 | line-height: 21px; 174 | overflow: hidden; 175 | white-space: nowrap; 176 | text-overflow: ellipsis; 177 | font-size: 12px; 178 | } 179 | 180 | .zxx-desk-info-type { 181 | float: right; 182 | margin-right: -8px; 183 | } 184 | 185 | .zxx-desk-overlay-top { 186 | opacity: 0.1; 187 | background: transparent; 188 | z-index: 20001 !important; 189 | display: block !important; 190 | } 191 | 192 | .project-shadow { 193 | box-shadow: 0 2px 12px 0 rgba(0, 0, 0, .1); 194 | } 195 | 196 | .zxx-desk-info-container .el-tabs { 197 | width: 312px; 198 | } 199 | 200 | .zxx-desk-info-container .el-tabs__item { 201 | padding: 0 16px; 202 | } 203 | 204 | .zxx-desk-info-container .el-tabs__nav-wrap { 205 | padding-bottom: 2px; 206 | } 207 | 208 | .zxx-desk-info-container .el-tabs__nav { 209 | width: 100%; 210 | padding: 0 10px; 211 | } 212 | 213 | .zxx-desk-info-container .el-tabs__nav-next, .zxx-desk-info-container .el-tabs__nav-prev { 214 | line-height: 30px; 215 | } 216 | 217 | .zxx-desk-info-container .el-tabs__active-bar { 218 | width: 60px !important; 219 | } -------------------------------------------------------------------------------- /app/assets/css/control.css: -------------------------------------------------------------------------------- 1 | html, body, #app, .el-container, .el-tabs, .el-tabs__content, .el-tab-pane, .el-tab-pane iframe, .iframe_wall { 2 | margin: 0; 3 | padding: 0; 4 | width: 100%; 5 | height: 100%; 6 | background: transparent; 7 | } 8 | 9 | .control-hide { 10 | display: none !important; 11 | } 12 | 13 | .win-control-osbtns { 14 | position: absolute; 15 | top: 0; 16 | right: 6px; 17 | width: 200px; 18 | height: 30px; 19 | font-size: 18px; 20 | text-align: right; 21 | line-height: 30px; 22 | } 23 | 24 | .lock-btn { 25 | margin-right: 7px; 26 | margin-left: 5px; 27 | color: #F56C6C; 28 | font-size: 19px; 29 | } 30 | 31 | .broswer-btn { 32 | margin-right: 7px; 33 | margin-left: 5px; 34 | color: #666 !important; 35 | font-size: 19px; 36 | } 37 | 38 | .win-control-osbtn { 39 | color: #000; 40 | margin: 0 3px; 41 | } 42 | 43 | /*windows的透明就是完全透明了~ 这里处理一下*/ 44 | .win-control-bg { 45 | position: absolute; 46 | top: 0; 47 | left: 0; 48 | width: 100%; 49 | height: 100%; 50 | z-index: 1; 51 | /*background: #fff;*/ 52 | background: rgb(229, 228, 228); 53 | } 54 | 55 | .win-control-upbg { 56 | position: absolute; 57 | top: 0; 58 | left: 0; 59 | width: 100%; 60 | height: 100%; 61 | z-index: 2; 62 | } 63 | 64 | html, body { 65 | overflow-x: hidden; 66 | } 67 | 68 | .ivu-modal-mask, .ivu-modal-content { 69 | background-color: none; 70 | background: transparent; 71 | } 72 | 73 | .el-header { 74 | /*线性色渐变*/ 75 | /*background: -webkit-linear-gradient(top, rgb(230,228,229) 0%,rgb(230, 230, 230) 100%) ;*/ 76 | /*background: rgb(229,228,229);*/ 77 | background: transparent; 78 | color: #333; 79 | text-align: center; 80 | line-height: 30px; 81 | font-size: 13px; 82 | font-family: "PingFang SC"; 83 | } 84 | 85 | .el-container .el-tabs__header { 86 | /*box-shadow: rgb(221,216,218) 1px 1px 1px 0px;*/ 87 | z-index: 20181231; 88 | position: relative; 89 | } 90 | 91 | .el-container .el-tabs { 92 | width: 100%; 93 | height: 100%; 94 | } 95 | 96 | .el-tabs__content { 97 | height: calc(100% - 35px); 98 | } 99 | 100 | .el-tabs__header { 101 | /*background: -webkit-linear-gradient(top, rgb(230,230,230) 0%,rgb(228, 224, 225) 100%) ;*/ 102 | /*background: rgb(229,228,229);*/ 103 | background: transparent; 104 | /*margin: 0 0 10px;*/ 105 | margin: 0; 106 | } 107 | 108 | .el-container .el-tabs__nav-scroll { 109 | padding: 0 15px; 110 | } 111 | 112 | .el-tabs__content { 113 | background: #fff; 114 | } 115 | 116 | .el-container .el-tabs__nav-scroll { 117 | -webkit-user-select: none; 118 | z-index: 20190104; 119 | } 120 | 121 | .el-tabs__item { 122 | height: 35px; 123 | font-weight: 400; 124 | font-size: 13px; 125 | line-height: 30px; 126 | 127 | /*-webkit-app-region: no-drag;*/ 128 | z-index: 20190105; 129 | } 130 | 131 | .el-tabs__item.is-active { 132 | font-weight: 500; 133 | } 134 | 135 | .el-dropdown-menu { 136 | z-index: 100001 !important; 137 | } 138 | 139 | .zxx-controls { 140 | position: absolute; 141 | top: 32px; 142 | right: 5px; 143 | z-index: 20190619; 144 | -webkit-user-select: none; 145 | /*-webkit-app-region: no-drag;*/ 146 | } 147 | 148 | .zxx-real-controls { 149 | } 150 | 151 | .zxx-control-btn { 152 | color: #666 !important; 153 | font-size: 19px; 154 | cursor: pointer; 155 | margin: 0 5px; 156 | } 157 | 158 | .zxx-control-loading { 159 | position: absolute; 160 | top: 3px; 161 | } -------------------------------------------------------------------------------- /app/assets/css/deskstore.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | overflow-y: auto; 3 | overflow-x: hidden; 4 | } -------------------------------------------------------------------------------- /app/assets/css/feedback.css: -------------------------------------------------------------------------------- 1 | .el-checkbox__label { 2 | font-size: 13px; 3 | } 4 | 5 | .ivu-row{ 6 | font-size: 13px; 7 | } -------------------------------------------------------------------------------- /app/assets/css/imodal.css: -------------------------------------------------------------------------------- 1 | html, body, #app { 2 | margin: 0; 3 | padding: 0; 4 | width: 100%; 5 | height: 100%; 6 | background: transparent; 7 | } 8 | 9 | #app{ 10 | margin-top: 25px; 11 | } -------------------------------------------------------------------------------- /app/assets/css/info.css: -------------------------------------------------------------------------------- 1 | #info-containter { 2 | margin-bottom: 10px; 3 | } 4 | 5 | .el-collapse { 6 | padding: 10px 0; 7 | border: none; 8 | } 9 | 10 | .el-collapse-item__header { 11 | height: 35px; 12 | line-height: 35px; 13 | margin: 0 10px; 14 | font-weight: 400; 15 | } 16 | 17 | .el-collapse-item div { 18 | background: #fff; 19 | } 20 | 21 | .el-collapse-item__wrap { 22 | padding: 10px 10px 0; 23 | } 24 | 25 | .el-collapse-item.is-active div[role='tab'] { 26 | box-shadow: rgb(221, 216, 218) 1px 2px 2px 0px; 27 | z-index: 11; 28 | position: relative; 29 | } 30 | 31 | .el-collapse-item.is-active + .el-collapse-item div[role='tab'] { 32 | box-shadow: rgb(221, 216, 218) 1px -2px 2px 0px; 33 | z-index: 10; 34 | position: relative; 35 | } 36 | 37 | .zxx-collapse-content { 38 | white-space: nowrap; 39 | overflow-x: auto; 40 | -webkit-user-select: text; 41 | user-select: text; 42 | margin-bottom: -25px; 43 | padding-bottom: 25px; 44 | } 45 | 46 | .el-collapse-item:last-child .el-collapse-item__header { 47 | border-bottom: none; 48 | } -------------------------------------------------------------------------------- /app/assets/css/preference.css: -------------------------------------------------------------------------------- 1 | #app { 2 | overflow-y: auto; 3 | overflow-x: hidden; 4 | } 5 | 6 | #preference-containter { 7 | padding: 30px; 8 | } 9 | 10 | .el-tabs__content { 11 | width: auto; 12 | } 13 | 14 | .el-form { 15 | padding: 0 50px; 16 | } 17 | 18 | .el-form-item { 19 | margin-bottom: 7px; 20 | } 21 | 22 | .el-form .el-form-item .el-form-item__label { 23 | width: 150px; 24 | line-height: 40px; 25 | } 26 | 27 | .el-form .el-form-item .el-form-item__label span sup { 28 | color: red; 29 | } 30 | 31 | .el-form .el-form-item .el-form-item__content { 32 | margin-left: 165px; 33 | text-align: left; 34 | } 35 | 36 | .desktop-animation-panel{ 37 | padding-right: 0; 38 | float: right; 39 | } 40 | 41 | .desktop-animation-panel.el-form .el-form-item .el-form-item__content{ 42 | margin-left: 10px; 43 | text-align: left; 44 | margin-top: 35px; 45 | } 46 | 47 | .zxx-form-item-desc { 48 | margin-left: 10px; 49 | color: #888; 50 | font-size: 12px; 51 | line-height: 20px; 52 | height: 20px; 53 | display: inline; 54 | } 55 | 56 | .zxx-form-item-desc-newline { 57 | margin-left: 10px; 58 | margin-top: 5px; 59 | color: #888; 60 | font-size: 12px; 61 | line-height: 20px; 62 | height: 20px; 63 | display: block; 64 | } 65 | 66 | .zxx-show-animate-panel { 67 | } 68 | 69 | .zxx-show-animate-panel .el-radio { 70 | margin: 2px 0; 71 | } -------------------------------------------------------------------------------- /app/assets/css/wall.css: -------------------------------------------------------------------------------- 1 | html, body, #app, .iframe_wall, .player-container, #player, .player { 2 | margin: 0; 3 | padding: 0; 4 | width: 100%; 5 | height: 100%; 6 | background: transparent; 7 | } 8 | 9 | .iframe_abs { 10 | position: absolute; 11 | top: 0; 12 | left: 0; 13 | z-index: 1000; 14 | display: none; 15 | } 16 | 17 | .wallpaper-loading, .wallpaper-empty { 18 | position: absolute; 19 | top: 27%; 20 | left: 0; 21 | z-index: 900; 22 | width: 100%; 23 | height: 50px; 24 | text-align: center; 25 | display: none; 26 | } 27 | 28 | .wallpaper-empty { 29 | z-index: 1100; 30 | display: block; 31 | } 32 | 33 | .wallpaper-loading-panel, .wallpaper-empty-panel { 34 | width: 300px; 35 | height: 82px; 36 | line-height: 40px; 37 | background: #000; 38 | border-radius: 15px; 39 | margin: 0 auto; 40 | color: #fff; 41 | padding: 10px 20px; 42 | font-size: 16px; 43 | opacity: 0.8; 44 | } 45 | 46 | .wallpaper-loading-panel i { 47 | font-size: 27px; 48 | } 49 | 50 | .wallpaper-empty-panel img { 51 | width: 30px; 52 | } 53 | 54 | .wallpaper-loading-panel div, .wallpaper-empty-panel div { 55 | height: 50px; 56 | line-height: 16px; 57 | } 58 | 59 | .zxx-random-animate-in { 60 | display: none; 61 | } 62 | 63 | .plyr, .plyr__video-wrapper { 64 | height: 100%; 65 | } 66 | 67 | .player-video { 68 | width: 100%; 69 | height: 100%; 70 | object-fit: fill; /*自动拉伸视频, 但注意该属性兼容性不太强.*/ 71 | display: none; 72 | position:absolute; 73 | top:0; 74 | left: 0; 75 | } -------------------------------------------------------------------------------- /app/assets/extends/netbroken/css/netbroken.css: -------------------------------------------------------------------------------- 1 | /* Copyright 2013 The Chromium Authors. All rights reserved. 2 | * Use of this source code is governed by a BSD-style license that can be 3 | * found in the LICENSE file. */ 4 | 5 | html, body { 6 | padding: 0; 7 | margin: 0; 8 | width: 100%; 9 | height: 100%; 10 | overflow: hidden; 11 | font-size: 14px !important; 12 | } 13 | 14 | .icon { 15 | -webkit-user-select: none; 16 | user-select: none; 17 | display: inline-block; 18 | } 19 | 20 | .icon-offline { 21 | content: -webkit-image-set( url('../images/default_100_percent/100-error-offline.png') 1x, url('../images/default_200_percent/200-error-offline.png') 2x); 22 | position: relative; 23 | } 24 | 25 | .hidden { 26 | display: none; 27 | } 28 | 29 | 30 | /* Offline page */ 31 | 32 | .offline .interstitial-wrapper { 33 | color: #2b2b2b; 34 | font-size: 1em; 35 | line-height: 1.55; 36 | margin: 0 auto; 37 | max-width: 600px; 38 | padding-top: 100px; 39 | width: 100%; 40 | } 41 | 42 | .offline .runner-container { 43 | height: 150px; 44 | max-width: 600px; 45 | overflow: hidden; 46 | position: absolute; 47 | top: 35px; 48 | width: 44px; 49 | } 50 | 51 | .offline .runner-canvas { 52 | height: 150px; 53 | max-width: 600px; 54 | opacity: 1; 55 | overflow: hidden; 56 | position: absolute; 57 | top: 0; 58 | z-index: 2; 59 | } 60 | 61 | .offline .controller { 62 | background: rgba(247, 247, 247, .1); 63 | height: 100vh; 64 | left: 0; 65 | position: absolute; 66 | top: 0; 67 | width: 100vw; 68 | z-index: 1; 69 | } 70 | 71 | #offline-resources { 72 | display: none; 73 | } 74 | 75 | @media (max-width: 420px) { 76 | .suggested-left > #control-buttons, .suggested-right > #control-buttons { 77 | float: none; 78 | } 79 | .snackbar { 80 | left: 0; 81 | bottom: 0; 82 | width: 100%; 83 | border-radius: 0; 84 | } 85 | } 86 | 87 | @media (max-height: 350px) { 88 | h1 { 89 | margin: 0 0 15px; 90 | } 91 | .icon-offline { 92 | margin: 0 0 10px; 93 | } 94 | .interstitial-wrapper { 95 | margin-top: 5%; 96 | } 97 | .nav-wrapper { 98 | margin-top: 30px; 99 | } 100 | } 101 | 102 | @media (min-width: 600px) and (max-width: 736px) and (orientation: landscape) { 103 | .offline .interstitial-wrapper { 104 | margin-left: 0; 105 | margin-right: 0; 106 | } 107 | } 108 | 109 | @media (min-width: 420px) and (max-width: 736px) and (min-height: 240px) and (max-height: 420px) and (orientation:landscape) { 110 | .interstitial-wrapper { 111 | margin-bottom: 100px; 112 | } 113 | } 114 | 115 | @media (min-height: 240px) and (orientation: landscape) { 116 | .offline .interstitial-wrapper { 117 | margin-bottom: 90px; 118 | } 119 | .icon-offline { 120 | margin-bottom: 20px; 121 | } 122 | } 123 | 124 | @media (max-height: 320px) and (orientation: landscape) { 125 | .icon-offline { 126 | margin-bottom: 0; 127 | } 128 | .offline .runner-container { 129 | top: 10px; 130 | } 131 | } 132 | 133 | @media (max-width: 240px) { 134 | .interstitial-wrapper { 135 | overflow: inherit; 136 | padding: 0 8px; 137 | } 138 | } -------------------------------------------------------------------------------- /app/assets/extends/netbroken/images/default_100_percent/100-disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/assets/extends/netbroken/images/default_100_percent/100-disabled.png -------------------------------------------------------------------------------- /app/assets/extends/netbroken/images/default_100_percent/100-error-offline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/assets/extends/netbroken/images/default_100_percent/100-error-offline.png -------------------------------------------------------------------------------- /app/assets/extends/netbroken/images/default_100_percent/100-offline-sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/assets/extends/netbroken/images/default_100_percent/100-offline-sprite.png -------------------------------------------------------------------------------- /app/assets/extends/netbroken/images/default_200_percent/200-disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/assets/extends/netbroken/images/default_200_percent/200-disabled.png -------------------------------------------------------------------------------- /app/assets/extends/netbroken/images/default_200_percent/200-error-offline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/assets/extends/netbroken/images/default_200_percent/200-error-offline.png -------------------------------------------------------------------------------- /app/assets/extends/netbroken/images/default_200_percent/200-offline-sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/assets/extends/netbroken/images/default_200_percent/200-offline-sprite.png -------------------------------------------------------------------------------- /app/assets/extends/netbroken/images/hello-kugou.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/assets/extends/netbroken/images/hello-kugou.gif -------------------------------------------------------------------------------- /app/assets/extends/netbroken/images/kumamon-runner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/assets/extends/netbroken/images/kumamon-runner.gif -------------------------------------------------------------------------------- /app/assets/extends/netbroken/images/novas-coisas.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/assets/extends/netbroken/images/novas-coisas.gif -------------------------------------------------------------------------------- /app/assets/extends/netbroken/images/offline-sprite-1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/assets/extends/netbroken/images/offline-sprite-1x.png -------------------------------------------------------------------------------- /app/assets/extends/netbroken/images/offline-sprite-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/assets/extends/netbroken/images/offline-sprite-2x.png -------------------------------------------------------------------------------- /app/assets/extends/netbroken/images/screenshot.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/assets/extends/netbroken/images/screenshot.gif -------------------------------------------------------------------------------- /app/assets/extends/netbroken/images/t-rex-runner-19janil.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/assets/extends/netbroken/images/t-rex-runner-19janil.gif -------------------------------------------------------------------------------- /app/assets/extends/netbroken/images/t-rex-runner-bot.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/assets/extends/netbroken/images/t-rex-runner-bot.gif -------------------------------------------------------------------------------- /app/assets/fonts/infonts/alipay/alipay.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/assets/fonts/infonts/alipay/alipay.eot -------------------------------------------------------------------------------- /app/assets/fonts/infonts/alipay/alipay.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Generated by IcoMoon 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /app/assets/fonts/infonts/alipay/alipay.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/assets/fonts/infonts/alipay/alipay.ttf -------------------------------------------------------------------------------- /app/assets/fonts/infonts/alipay/alipay.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/assets/fonts/infonts/alipay/alipay.woff -------------------------------------------------------------------------------- /app/assets/fonts/ionicons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/assets/fonts/ionicons.ttf -------------------------------------------------------------------------------- /app/assets/fonts/ionicons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/assets/fonts/ionicons.woff -------------------------------------------------------------------------------- /app/assets/fonts/iview-site/iview-site.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/assets/fonts/iview-site/iview-site.ttf -------------------------------------------------------------------------------- /app/assets/fonts/iview-site/iview-site.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/assets/fonts/iview-site/iview-site.woff -------------------------------------------------------------------------------- /app/assets/images/404.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/assets/images/404.jpg -------------------------------------------------------------------------------- /app/assets/images/building/1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/assets/images/building/1.gif -------------------------------------------------------------------------------- /app/assets/images/building/2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/assets/images/building/2.gif -------------------------------------------------------------------------------- /app/assets/images/building/3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/assets/images/building/3.gif -------------------------------------------------------------------------------- /app/assets/images/building/4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/assets/images/building/4.gif -------------------------------------------------------------------------------- /app/assets/images/comp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/assets/images/comp.png -------------------------------------------------------------------------------- /app/assets/images/imac.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/assets/images/imac.png -------------------------------------------------------------------------------- /app/assets/images/kong.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/assets/images/kong.png -------------------------------------------------------------------------------- /app/assets/images/loading.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/assets/images/loading.jpg -------------------------------------------------------------------------------- /app/assets/images/offline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/assets/images/offline.png -------------------------------------------------------------------------------- /app/assets/images/online.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/assets/images/online.png -------------------------------------------------------------------------------- /app/assets/lib/element-ui/fonts/element-icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/assets/lib/element-ui/fonts/element-icons.ttf -------------------------------------------------------------------------------- /app/assets/lib/element-ui/fonts/element-icons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/assets/lib/element-ui/fonts/element-icons.woff -------------------------------------------------------------------------------- /app/assets/lib/font-awesome/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/assets/lib/font-awesome/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /app/assets/lib/font-awesome/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/assets/lib/font-awesome/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /app/assets/lib/font-awesome/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/assets/lib/font-awesome/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /app/assets/lib/font-awesome/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/assets/lib/font-awesome/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /app/assets/lib/font-awesome/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/assets/lib/font-awesome/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /app/config/appconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "appname": "ideawall - 创意者桌面", 3 | "debug": true, 4 | "publish": "2019.07.09", 5 | "database": { 6 | "encrypt": false 7 | }, 8 | "notifyTimeOut":60000 9 | } -------------------------------------------------------------------------------- /app/controller/AboutController.js: -------------------------------------------------------------------------------- 1 | const baseController = proxy.require('../controller/BaseController'); 2 | 3 | var vm = new Vue({ 4 | el: '#app', 5 | data: function () { 6 | return { 7 | loading: true, 8 | }; 9 | }, 10 | methods: { 11 | linkSite(){ 12 | proxy.openExternal(proxy.appVar._siteurl); 13 | } 14 | }, 15 | created: function () { 16 | }, 17 | mounted() { 18 | var that = this; 19 | } 20 | }); 21 | 22 | 23 | window.onload = function () { 24 | vm.loading = false; 25 | }; -------------------------------------------------------------------------------- /app/controller/BaseController.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/controller/BaseController.js -------------------------------------------------------------------------------- /app/controller/BrowserController.js: -------------------------------------------------------------------------------- 1 | const baseController = proxy.require('../controller/BaseController'); 2 | 3 | var vm = new Vue({ 4 | el: '#app', 5 | data: function () { 6 | return { 7 | loading: true, 8 | link: proxy.link(decodeURIComponent(decodeURIComponent(T.p('link')))), 9 | }; 10 | }, 11 | methods: { 12 | 13 | }, 14 | created: function () { 15 | }, 16 | mounted() { 17 | var that = this; 18 | proxy.ipc.on('ipc_window_browser_cgi', function (event, link, paramJson) { 19 | console.debug('ipc_window_browser_cgi: ' + link); 20 | if (link + '' != that.link + '') { 21 | this.loading = true; 22 | that.link = link; 23 | $$.dealIframe('#iframe_browser', link); 24 | } 25 | }); 26 | 27 | proxy.appVar._browserwindow.webContents.on('did-start-loading', () => { 28 | this.loading = true; 29 | this.$Loading.start(); 30 | }); 31 | proxy.appVar._browserwindow.webContents.on('did-stop-loading', () => { 32 | this.loading = false; 33 | this.$Loading.finish(); 34 | }); 35 | } 36 | }); 37 | 38 | 39 | window.onload = function () { 40 | vm.loading = false; 41 | }; -------------------------------------------------------------------------------- /app/controller/CommentController.js: -------------------------------------------------------------------------------- 1 | const baseController = proxy.require('../controller/BaseController'); 2 | const http = proxy.require('../core/Http'); 3 | const logger = proxy.require('../core/Logger'); 4 | 5 | var vm = new Vue({ 6 | el: '#app', 7 | data: function () { 8 | return { 9 | formKey: T.p('fk'), 10 | origin: proxy.appVar._commenturl, 11 | } 12 | }, 13 | methods: { 14 | //发送通信消息 15 | postMessage(data) {//data 结构为 指令+数据 16 | $('iframe#iframe_comment')[0].contentWindow.postMessage(data, this.origin); 17 | }, 18 | //接收通信消息 19 | getMessage(rs) { 20 | var data = rs.data; 21 | this.postMessage('呵呵哒~'); 22 | } 23 | }, 24 | created: function () { 25 | }, 26 | mounted() { 27 | console.debug('正在加载评论页面~'); 28 | var that = this; 29 | var xiframe = $('iframe#iframe_comment'); 30 | top.vm.netLoading('mydesk', () => { 31 | this.$Loading.start(); 32 | }, () => { 33 | this.$Loading.finish(); 34 | }); 35 | xiframe.load(function () { 36 | parent.vm.loadingDeskConfig = false; 37 | that.postMessage({ 38 | cmd: 'hello', 39 | version: proxy.appVar._version, 40 | }); 41 | }); 42 | } 43 | }); -------------------------------------------------------------------------------- /app/controller/DeviceInfoController.js: -------------------------------------------------------------------------------- 1 | const baseController = proxy.require('../controller/BaseController'); 2 | const http = proxy.require('../core/Http'); 3 | const deviceDeskModel = proxy.require('../model/DeviceDeskModel')(); 4 | 5 | var amIndex; 6 | var vm = new Vue({ 7 | el: '#app', 8 | data: function () { 9 | return { 10 | loadingData: true, 11 | displayId: T.p("displayId"),//设备id 12 | deskTypeName: T.p('deskTypeName'),//设备配置桌面的类型名称. 13 | display: { 14 | id: '',//唯一标识 id 15 | desk_id: '',//配置的桌面 id, 为空代表没有配置. 16 | display_id: '',//设备 id 17 | display_rp: '',//设备分辨率 18 | display_info: {//设备属性: 随时会变化 19 | 20 | }, 21 | },//设备信息 22 | screens: {}, 23 | screen: {//快照信息 24 | 25 | }, 26 | snapSize: {//快照大小 27 | width: 300, 28 | height: 170, 29 | }, 30 | }; 31 | }, 32 | methods: { 33 | setInfo(displayId, paramJson) { 34 | var that = this; 35 | that.loadingData = true; 36 | try { 37 | that.deskTypeName = decodeURI(decodeURI(paramJson.deskTypeName)); 38 | } catch (e) { 39 | } 40 | console.debug(displayId); 41 | that.displayId = displayId; 42 | that.display = deviceDeskModel.getDisplayById(displayId); 43 | if (that.display) { 44 | that.display.display_info = JSON.parse(that.display.display_info); 45 | console.debug(that.display); 46 | var title = $('title').text(); 47 | (title.indexOf && title.indexOf(' - ') === -1) ? $('title').text(that.display.screen_title + ' - ' + title) : ''; 48 | that.screen = that.screens.filter((item) => { 49 | return (that.display.display_id + '' === item.display_id + ''); 50 | })[0]; 51 | that.loadingData = false; 52 | } else { 53 | console.warn('目标设备不存在或已经被移除.'); 54 | proxy.alert('系统提示', '目标设备不存在或已经被移除!', false, 'error'); 55 | } 56 | 57 | } 58 | }, 59 | created: function () { 60 | var that = this; 61 | deviceDeskModel.snapscreen(that.snapSize, (result, rIds, first) => { 62 | that.screens = result; 63 | console.debug(that.screens); 64 | setTimeout(() => { 65 | that.setInfo(this.displayId, {deskTypeName: this.deskTypeName}); 66 | proxy.ipc.on('ipc_window_deviceinfo_cgi', function (event, displayId, paramJson) { 67 | console.debug('ipc_window_deviceinfo_cgi: ' + that.displayId + ' => ' + displayId); 68 | if (displayId + '' != that.displayId + '') { 69 | that.setInfo(displayId, paramJson); 70 | } 71 | }); 72 | }, 500); 73 | //监听初始化数据信息 74 | }, true, true); 75 | }, 76 | mounted() { 77 | var that = this; 78 | } 79 | }); -------------------------------------------------------------------------------- /app/controller/PageController.js: -------------------------------------------------------------------------------- 1 | const baseController = proxy.require('../controller/BaseController'); 2 | const http = proxy.require('../core/Http'); 3 | const localDeskModel = proxy.require('../model/LocalDeskModel')(); 4 | 5 | var vm = new Vue({ 6 | el: '#app', 7 | data: function () { 8 | return { 9 | loading: true, 10 | preview: T.p('preview'), 11 | desk: {}, 12 | source_type: '', //超桌源 13 | source_val: '', 14 | params: { //约定域参数 15 | 16 | }, 17 | animation: { 18 | in: '', 19 | out: '', 20 | }, 21 | prefs: [], 22 | prefs_supports: { //支持的偏好配置项 23 | wholeAudioVolumn: { //全局音量 24 | value: 1.0, 25 | bindkey: 'val', 26 | change: function (_this, _pref, ov, nv) { 27 | _pref.value = nv; 28 | } 29 | }, 30 | deskAnimationOn: { //入场 31 | value: '', 32 | bindkey: 'val', 33 | change: function (_this, _pref, ov, nv) { 34 | if (ov == nv) return false; 35 | _pref.value = nv; 36 | _this.animation.in = (nv == 'random') ? animation.getAnimateIn() : _pref.value; 37 | } 38 | }, 39 | deskAnimationOut: { //出场动画 40 | value: '', 41 | bindkey: 'val', 42 | change: function (_this, _pref, ov, nv) { 43 | if (ov == nv) return false; 44 | _pref.value = nv; 45 | _this.animation.ou = (nv == 'random') ? animation.getAnimateOut() : _pref.value; 46 | } 47 | }, 48 | } 49 | } 50 | }, 51 | methods: { 52 | calcData() { 53 | if (this.desk.source_type && this.desk.source_val) { 54 | this.source_type = this.desk.source_type; 55 | this.source_val = proxy.link(localDeskModel.getIndexPath(this.desk)); 56 | } 57 | }, 58 | //约定域参数计算 59 | calcParams() { 60 | var that = this; 61 | if (that.desk.params) { //暂时不需要. 62 | that.desk.params = JSON.parse(that.desk.params); 63 | Object.assign(that.params, that.desk.params); 64 | } 65 | }, 66 | //处理全局偏好配置项 67 | dealWithPrefs(prefs) { 68 | this.prefs = prefs; 69 | for (var x in prefs) { //遍历每一项配置 70 | var zxx = prefs[x]; 71 | var values = JSON.parse(zxx.value); 72 | var key = zxx.key; 73 | if (this.prefs_supports.hasOwnProperty(key)) { //本地接收处有该配置项 74 | if (values.hasOwnProperty(this.prefs_supports[key].bindkey)) { //配置项中有需要绑定的 key. 75 | this.prefs_supports[key].change(this, this.prefs_supports[key], this.prefs_supports[key].value, values[this.prefs_supports[key].bindkey]); 76 | } 77 | } 78 | } 79 | }, 80 | }, 81 | created: function () { 82 | this.calcData(true); 83 | }, 84 | mounted() { 85 | var that = this; 86 | //接收更新指令 87 | proxy.ipc.on('ipc_wall_update', function (event, data, dp, prefs) { 88 | console.debug('ipc_wall_update'); 89 | console.debug(data); 90 | console.debug(dp); 91 | console.debug(prefs); 92 | that.desk = data; 93 | that.display = dp; 94 | that.dealWithPrefs(prefs); 95 | if (dp && dp.api_pause == 2) { 96 | console.debug('超桌面接收到 ipc 暂停指令'); 97 | } else { 98 | console.debug('超桌面接收到 ipc 启动指令'); 99 | } 100 | proxy.ipc.send('ipc_repeat', 'ipc_wall_showtip', false); 101 | that.calcData(); 102 | that.calcParams(); 103 | }); 104 | } 105 | }); 106 | 107 | window.onload = function () { 108 | vm.loading = false; 109 | }; 110 | 111 | $(function () { 112 | 113 | }); 114 | -------------------------------------------------------------------------------- /app/controller/PreviewController.js: -------------------------------------------------------------------------------- 1 | const baseController = proxy.require('../controller/BaseController'); 2 | const http = proxy.require('../core/Http'); 3 | const localDeskModel = proxy.require('../model/LocalDeskModel')(); 4 | const mediaModel = proxy.require('../model/MediaModel')(); 5 | 6 | var amIndex; 7 | var vm = new Vue({ 8 | el: '#app', 9 | data: function () { 10 | return { 11 | wallpaperEmpty: false, 12 | wallaperEmptyTip: '媒体组为空', 13 | deskId: T.p("deskId"),//桌面id 14 | link: T.p("link"),//link 地址 15 | desk: {},//配置的桌面信息 16 | }; 17 | }, 18 | methods: { 19 | showEmptyTip(bol, tip) { 20 | this.wallpaperEmpty = bol; 21 | if (tip) { 22 | this.wallaperEmptyTip = tip; 23 | }else{ 24 | this.wallaperEmptyTip = '媒体组为空'; 25 | } 26 | }, 27 | setWallpaper(desk_id, paramJson) { 28 | var that = this; 29 | that.link = decodeURI(decodeURI(paramJson.link)); 30 | console.debug(desk_id); 31 | that.deskId = desk_id; 32 | var wallFrame = $('.iframe_wall'); 33 | wallFrame.removeAttr('src').hide(); 34 | console.debug(paramJson); 35 | $('.wallpaper-loading').show(); 36 | that.desk = localDeskModel.getDesk(desk_id); 37 | that.desk.medias = mediaModel.getsByDeskId(desk_id); 38 | console.debug(that.desk); 39 | if (that.desk) { 40 | var title = $('title').text(); 41 | (title.indexOf && title.indexOf(' - ') === -1) ? $('title').text(that.desk.name + ' - ' + title) : ''; 42 | if (that.link) { 43 | var link = that.link; 44 | link = (that.desk.type === 'page' ? './wall/Page.html' : link);//超桌面指定一个默认中继器. 45 | var src = wallFrame.data('src').replace('[SOURCE]', proxy.link(link, {preview: 'yes'})); 46 | wallFrame.attr('src', src); 47 | wallFrame.load(function () { 48 | $(this).show(); 49 | proxy.ipc.send('ipc_repeat', 'ipc_wall_update', that.desk, desk_id); 50 | that.showEmptyTip((that.desk.type !== 'page' && (!that.desk.medias || that.desk.medias.length <= 0))); 51 | }); 52 | } else { 53 | var link = localDeskModel.getIndexPath(that.desk); 54 | console.debug(link); 55 | if (link) { 56 | link = (that.desk.type === 'page' ? './wall/Page.html' : link);//超桌面指定一个默认中继器. 57 | var src = wallFrame.data('src').replace('[SOURCE]', proxy.link(link, {preview: 'yes'})); 58 | wallFrame.attr('src', src); 59 | wallFrame.load(function () { 60 | $(this).show(); 61 | proxy.ipc.send('ipc_repeat', 'ipc_wall_update', that.desk, desk_id); 62 | that.showEmptyTip((that.desk.type !== 'page' && (!that.desk.medias || that.desk.medias.length <= 0))); 63 | }); 64 | } else { 65 | console.warn('当前配置桌面源非法'); 66 | proxy.alert('系统提示', '当前桌面源配置无效', false, 'error', false, that.desk); 67 | } 68 | } 69 | } else { 70 | console.warn('当前尚未配置桌面'); 71 | proxy.alert('系统提示', '桌面数据索引失败!', function (res) { 72 | 73 | }, 'error', false, that.desk); 74 | } 75 | } 76 | }, 77 | created: function () { 78 | }, 79 | mounted() { 80 | var that = this; 81 | //监听初始化数据信息 82 | that.setWallpaper(this.deskId, {link: this.link}); 83 | proxy.ipc.on('ipc_window_preview_cgi', function (event, deskId, paramJson) { 84 | console.debug('ipc_window_preview_cgi: ' + that.deskId + ' => ' + deskId); 85 | if (deskId + '' != that.deskId + '') { 86 | that.setWallpaper(deskId, paramJson); 87 | } 88 | }); 89 | } 90 | }); -------------------------------------------------------------------------------- /app/controller/ReadmeController.js: -------------------------------------------------------------------------------- 1 | const baseController = proxy.require('../controller/BaseController'); 2 | const http = proxy.require('../core/Http'); 3 | const localDeskModel = proxy.require('../model/LocalDeskModel')(); 4 | 5 | var amIndex; 6 | var vm = new Vue({ 7 | el: '#app', 8 | data: function () { 9 | return { 10 | deskId: T.p("deskId"),//桌面id 11 | link: T.p("link"),//link 地址 12 | desk: {},//配置的桌面信息 13 | }; 14 | }, 15 | methods: { 16 | setWallpaper(desk_id, paramJson) { 17 | var that = this; 18 | that.link = decodeURI(decodeURI(paramJson.link)); 19 | console.debug(desk_id); 20 | that.deskId = desk_id; 21 | var wallFrame = $('.iframe_wall'); 22 | wallFrame.removeAttr('src').hide(); 23 | console.debug(paramJson); 24 | $('.wallpaper-loading').show(); 25 | that.desk = localDeskModel.getDesk(desk_id); 26 | console.debug(that.desk); 27 | if (that.desk) { 28 | var title = $('title').text(); 29 | (title.indexOf && title.indexOf(' - ') === -1) ? $('title').text(that.desk.name + ' - ' + title) : ''; 30 | if (that.link) { 31 | var src = wallFrame.data('src').replace('[SOURCE]', proxy.link(that.link)); 32 | wallFrame.attr('src', src); 33 | wallFrame.load(function () { 34 | $('.zxx-loading').hide(); 35 | $(this).show(); 36 | }); 37 | } else { 38 | var link = localDeskModel.getReadmePath(that.desk); 39 | console.debug(link); 40 | if (link) { 41 | var src = wallFrame.data('src').replace('[SOURCE]', proxy.link(link)); 42 | wallFrame.attr('src', src); 43 | wallFrame.load(function () { 44 | $('.zxx-loading').hide(); 45 | $(this).show(); 46 | }); 47 | } else { 48 | console.warn('当前配置桌面源非法'); 49 | proxy.alert('系统提示', '当前桌面源配置无效', false, 'error', false, that.desk); 50 | } 51 | } 52 | } else { 53 | console.warn('当前桌面尚未提供配置说明文件'); 54 | proxy.alert('系统提示', '当前桌面尚未提供配置说明文件!', function (res) { 55 | 56 | }, 'error', false, that.desk); 57 | } 58 | } 59 | }, 60 | created: function () { 61 | }, 62 | mounted() { 63 | var that = this; 64 | //监听初始化数据信息 65 | that.setWallpaper(this.deskId, {link: this.link}); 66 | proxy.ipc.on('ipc_window_readme_cgi', function (event, deskId, paramJson) { 67 | console.debug('ipc_window_readme_cgi: ' + that.deskId + ' => ' + deskId); 68 | if (deskId + '' != that.deskId + '') { 69 | that.setWallpaper(deskId, paramJson); 70 | } 71 | }); 72 | } 73 | }); -------------------------------------------------------------------------------- /app/controller/ResBBSController.js: -------------------------------------------------------------------------------- 1 | const baseController = proxy.require('../controller/BaseController'); 2 | const http = proxy.require('../core/Http'); 3 | const logger = proxy.require('../core/Logger'); 4 | const uuid = proxy.require('../core/UUID')(); 5 | 6 | var vm = new Vue({ 7 | el: '#app', 8 | data: function () { 9 | return { 10 | loading: true, 11 | origin: proxy.appVar._bbsurl, 12 | nowURL: proxy.appVar._bbsurl, 13 | } 14 | }, 15 | methods: { 16 | //发送通信消息 17 | postMessage(data) {//data 结构为 指令+数据 18 | $('iframe#iframe_bbs')[0].contentWindow.postMessage(data, this.origin); 19 | }, 20 | //接收通信消息 21 | getMessage(rs) { 22 | var data = rs.data; 23 | this.nowURL = data.location; 24 | this.postMessage('呵呵哒~'); 25 | } 26 | }, 27 | created: function () { 28 | }, 29 | mounted() { 30 | var that = this; 31 | var xiframe = $('iframe#iframe_bbs'); 32 | proxy.ipc.on('ipc_render_control_resbbs_refresh', (event, cmd) => { 33 | that.loading = true; 34 | xiframe.attr('src', this.nowURL); 35 | }); 36 | proxy.ipc.on('ipc_render_control_resbbs_home', (event, cmd) => { 37 | that.loading = true; 38 | xiframe.attr('src', proxy.appVar._bbsurl); 39 | }); 40 | proxy.ipc.on('ipc_render_control_resbbs_open', (event, cmd) => { 41 | proxy.ipc.send('ipc_window_open', 'browser', that.nowURL); 42 | }); 43 | proxy.ipc.on('ipc_render_control_resbbs_changeurl', (event, url) => { 44 | that.loading = true; 45 | this.nowURL = url; 46 | xiframe.attr('src', url); 47 | }); 48 | top.vm.netLoading('resbbs', () => { 49 | this.$Loading.start(); 50 | }, () => { 51 | this.$Loading.finish(); 52 | }); 53 | xiframe.load(function () { 54 | that.loading = false; 55 | top.vm.loadingTab = false; 56 | that.postMessage({ 57 | cmd: 'hello', 58 | version: proxy.appVar._version, 59 | }); 60 | }); 61 | } 62 | }); 63 | 64 | -------------------------------------------------------------------------------- /app/core/Async.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 异步支撑库[主进程和渲染进程通用, 需要在ideanote.js引用之后调用] 3 | * 4 | * @author troy 5 | * @date 2019/01/21 08:50 PM 6 | */ 7 | const async = require('async'); 8 | 9 | /** 10 | * @constructor 11 | */ 12 | function Async() { 13 | 14 | let target = this;//对象寄存器 15 | 16 | //数据库初始化, 自动执行. 17 | this.init = function () { 18 | }; 19 | 20 | //自动串行并行 21 | this.auto = function (funs, callback) { 22 | async.auto(funs, function (err, results) { 23 | if (typeof callback === 'function') { 24 | callback(err, results); 25 | } 26 | }); 27 | }; 28 | 29 | //Aop切面[经典]. 30 | //规则: 31 | //1. prev没传(传flase), 不妨碍action和after的串行执行. 32 | //2. action没传, 不妨碍prev和after的串行执行. 33 | //3. 全都传了, 串行执行. 34 | //4. prev方法一定要返回一个boolean值, 来确定放行还是拦截. [为方便逻辑性, 如果没有设定返回值(undefined), 就默认为true] 35 | this.aop = function (prev, action, after, topic) { 36 | topic = topic ? topic : ''; 37 | target.auto({ 38 | prev: function (callback) { 39 | if (typeof prev === 'function') { 40 | var r = prev(); 41 | r = (r === undefined ? true : r); 42 | callback(null, r); 43 | return; 44 | } 45 | callback(null, true); 46 | }, 47 | action: [ 48 | 'prev', 49 | function (res, callback) { 50 | if (res.prev) { 51 | if (typeof action === 'function') { 52 | callback(null, action()); 53 | return; 54 | } 55 | callback(null, true); 56 | } else { 57 | console.warn(topic + 'AOP动作日志: prev方法拦截了action的执行!'); 58 | callback(null, false); 59 | } 60 | } 61 | ], 62 | after: [ 63 | 'prev', 'action', 64 | function (res, callback) { 65 | res.action = true;//after不受action动作拦截. 66 | if (res.prev && res.action) { 67 | if (typeof after === 'function') { 68 | callback(null, after()); 69 | return; 70 | } 71 | callback(null, true); 72 | } else { 73 | console.warn(topic + 'AOP动作日志: prev方法拦截了after的执行!'); 74 | callback(null, false); 75 | } 76 | } 77 | ] 78 | }, function (err, results) { 79 | if (err) { 80 | console.error(topic + 'AOP切面动作异常! '); 81 | console.error(err); 82 | } 83 | return results; 84 | }); 85 | }; 86 | 87 | 88 | this.init();//自动初始化. 89 | } 90 | 91 | module.exports = () => { 92 | return new Async(); 93 | }; 94 | 95 | //调用示例 96 | // async.auto({ 97 | // fun1: function () { 98 | // //... 99 | // }, 100 | // fun2: function () { 101 | // //... 102 | // }, 103 | // fun3: [//引用了fun1和fun2的返回值, 那么fun1和fun2是并行的, 他们与fun3是串行的. 104 | // 'fun1', 'fun2', 105 | // function () { 106 | // //... 107 | // } 108 | // ] 109 | // }, function () { 110 | // 111 | // }); 112 | 113 | -------------------------------------------------------------------------------- /app/core/Config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const fs = require('fs'); 3 | const crypto = require('./Crypto'); 4 | const config_file_path = __dirname + "/../config/appconfig.json"; 5 | const global_default_val = undefined; 6 | const json_config = fs.readFileSync(config_file_path); 7 | 8 | /** 9 | * 读取配置项并返回配置数据 10 | * 新增支持配置默认值, 若不传入配置项键, 则直接返回整体值. 11 | * 12 | * @kind AnyProcess [任意进程调用] 13 | * @param {string} configname 配置项名称 14 | * @param {string} defaultval 默认值传递 15 | */ 16 | function get(configname, defaultval) { 17 | try { 18 | let config_obj_ = JSON.parse(json_config); 19 | if (configname) { 20 | if (!config_obj_[configname]) { 21 | return defaultval ? defaultval : global_default_val; 22 | } 23 | return config_obj_[configname]; 24 | } else { 25 | return config_obj_; 26 | } 27 | } catch (e) { 28 | return defaultval ? defaultval : global_default_val; 29 | } 30 | } 31 | 32 | module.exports = { 33 | get, 34 | }; -------------------------------------------------------------------------------- /app/core/Crypto.js: -------------------------------------------------------------------------------- 1 | const Crypto = require('crypto');//加密解密模块 2 | const UUID = require('./UUID');//UUID 模块 3 | 4 | /** 5 | * 加密算法 6 | */ 7 | var Encrypt = function () { 8 | 9 | //MD5加密算法: 不可逆. 10 | this.md5 = function (secret) { 11 | var md5 = Crypto.createHash('md5');//定义加密方式:md5不可逆,此处的md5可以换成任意hash加密的方法名称; 12 | md5.update(new Buffer(secret).toString("binary"), 'utf8');//buffer 处理转为二进制, 否则与其他语言处理结果不一致. 13 | var crypto = md5.digest('hex'); //二进制编码, 可选: hex, latin1, base64. 14 | // console.debug('crypto-encrypt-md5: ' + secret + ' -> ' + crypto); 15 | return crypto; 16 | }; 17 | 18 | //sha256加密算法: 不可逆. 19 | this.sha256 = function (secret) { 20 | var sha256 = Crypto.createHmac('sha256'); 21 | sha256.update(secret); 22 | var crypto = sha256.digest('hex'); 23 | console.debug('crypto-encrypt-sha256: ' + secret + ' -> ' + crypto); 24 | return crypto; 25 | }; 26 | 27 | //对称加密算法: 可逆 28 | this.cipher = function (secret, cryptokey) { 29 | cryptokey = cryptokey ? cryptokey : UUID.v1();//密钥 30 | var cipher = Crypto.createCipher('aes192', cryptokey); 31 | var crypto = cipher.update(secret, 'utf8', 'hex');//编码方式从utf-8转为hex; 32 | crypto += cipher.final('hex');//编码方式从转为hex; 33 | console.debug('crypto-encrypt-cipher: secret -> ' + secret + ', cryptokey -> ' + cryptokey + ', crypto -> ' + crypto); 34 | if (cryptokey) { 35 | return crypto; 36 | } else { 37 | return {'cryptokey': cryptokey, 'crypto': crypto}; 38 | } 39 | }; 40 | 41 | /** 42 | * aes加密 43 | * @param data 待加密内容 44 | * @param secretKey 45 | * @returns {string} 46 | */ 47 | this.aes = function (data, secretKey) { 48 | if (!data) { 49 | return ""; 50 | } 51 | var cipher = Crypto.createCipher('aes-128-ecb', secretKey); 52 | return cipher.update(data, 'utf8', 'hex') + cipher.final('hex'); 53 | }; 54 | }; 55 | var encrypt = new Encrypt(); 56 | 57 | /** 58 | * 解密算法 59 | */ 60 | var Decrypt = function () { 61 | 62 | //对称解密算法 63 | this.cipher = function (crypto, cryptokey) { 64 | var decipher = Crypto.createDecipher('aes192', cryptokey); 65 | var decrypto = decipher.update(secret, 'hex', 'utf8');//编码方式从hex转为utf-8; 66 | decrypto += decipher.final('utf8');//编码方式从utf-8; 67 | console.debug('crypto-cipher-cipher: secret -> ' + secret + ', cryptokey -> ' + cryptokey + ', decrypto -> ' + decrypto); 68 | return decrypto; 69 | }; 70 | 71 | /** 72 | * aes解密 73 | * @param data 待解密内容 74 | * @param secretKey 75 | * @returns {string} 76 | */ 77 | this.aes = function (data, secretKey) { 78 | if (!data) { 79 | return ""; 80 | } 81 | var cipher = Crypto.createDecipher('aes-128-ecb', secretKey); 82 | return cipher.update(data, 'hex', 'utf8') + cipher.final('utf8') 83 | }; 84 | }; 85 | var decrypt = new Decrypt(); 86 | 87 | /** 88 | * 校验器 89 | */ 90 | var Verify = function () { 91 | 92 | //md5校验 93 | this.md5 = function (secret, crypto) { 94 | var crypto4secret = encrypt.md5(secret); 95 | return (crypto4secret === crypto); 96 | }; 97 | 98 | //sha256校验 99 | this.sha256 = function (secret, crypto) { 100 | var crypto4secret = encrypt.sha256(secret); 101 | return (crypto4secret === crypto); 102 | }; 103 | 104 | //对称加密校验 105 | this.cipher = function (secret, crypto, cryptokey) { 106 | var decrypto4secret = decrypt.cipher(crypto, cryptokey); 107 | return (decrypto4secret === secret); 108 | }; 109 | 110 | //aes加密校验 111 | this.aes = function (secret, crypto, cryptokey) { 112 | var decrypt4secret = encrypt.aes(secret, cryptokey); 113 | return (decrypt4secret === crypto); 114 | }; 115 | }; 116 | var verify = new Verify(); 117 | 118 | module.exports = { 119 | encrypt, 120 | decrypt, 121 | verify 122 | }; -------------------------------------------------------------------------------- /app/core/Download.js: -------------------------------------------------------------------------------- 1 | const downloadRequest = require('request'); 2 | const path = require('path'); 3 | const fs = require("fs"); 4 | const logger = require('../core/Logger'); 5 | 6 | // ---- 流式下载类 ---- // 7 | function StreamDownload() { 8 | // 声明下载过程回调函数 9 | this.downloadCallback = null; 10 | } 11 | 12 | // 下载进度 13 | StreamDownload.prototype.showProgress = function (received, total, file, chunkLength) { 14 | const percentage = (received * 100) / total; 15 | // 用回调显示到界面上 16 | this.downloadCallback('progress', percentage, received, total, file, chunkLength); 17 | }; 18 | 19 | /** 20 | * 下载控制 21 | * 22 | * @param patchUrl 目标地址 23 | * @param baseDir 本地存储地址[目录] 24 | * @param setFileName 下载文件名设置 25 | * @param file 文件对象, 用于传递记录 26 | * @param callback 下载过程回调 27 | * @param errorCallback 下载异常回调 28 | */ 29 | StreamDownload.prototype.downloadFile = function (patchUrl, baseDir, setFileName, file, callback, errorCallback) { 30 | try { 31 | logger.info('开始下载 ' + patchUrl); 32 | this.downloadCallback = callback; // 注册回调函数 33 | 34 | const downloadFile = setFileName; // 下载文件名称,也可以从外部传进来 35 | 36 | let receivedBytes = 0; 37 | let totalBytes = 0; 38 | 39 | const req = downloadRequest({ 40 | method: 'GET', 41 | uri: patchUrl 42 | }); 43 | 44 | const out = fs.createWriteStream(path.join(baseDir, downloadFile)); 45 | req.pipe(out); 46 | 47 | 48 | req.on('response', (data) => { 49 | // 更新总文件字节大小 50 | totalBytes = parseInt(data.headers['content-length'], 10); 51 | }); 52 | 53 | req.on('data', (chunk) => { 54 | // 更新下载的文件块字节大小 55 | receivedBytes += chunk.length; 56 | this.showProgress(receivedBytes, totalBytes, file, chunk.length); 57 | }); 58 | 59 | var target = this; 60 | req.on('end', () => { 61 | logger.info('[' + file.name + '] 下载已完成,等待后切面处理.'); 62 | target.downloadCallback('finished', 100, totalBytes, totalBytes, file, 0); 63 | }); 64 | } catch (e) { 65 | console.error(e); 66 | errorCallback(e, file); 67 | } 68 | }; 69 | 70 | 71 | module.exports = () => { 72 | return new StreamDownload(); 73 | }; -------------------------------------------------------------------------------- /app/core/Fs.js: -------------------------------------------------------------------------------- 1 | const logger = require('./Logger');//日志模块 2 | const config = require('./Config');//配置模块 3 | 4 | const fs = require('fs');//Nodejs原生fs模块 用于文件系统读写操作 5 | const child_process = require('child_process');//Nodejs原生child_process模块 用于进程管理 6 | 7 | /** 8 | * 读取文件并执行回调 9 | * @param {string} filepath 文件路径 10 | * @param {function} callback 回调函数 11 | */ 12 | function readFileAndRunCallback(filepath, callback) { 13 | fs.readFile(filepath, (err, data) => { 14 | if (err) { 15 | logger.warn(err); 16 | } 17 | if (typeof callback === "function") { 18 | callback(data); 19 | } 20 | }); 21 | } 22 | 23 | /** 24 | * 同步读取文件 25 | * @param {string} filepath 文件路径 26 | * @return {string} 文件内容 27 | */ 28 | function readFileSync(filepath) { 29 | return fs.readFileSync(filepath); 30 | } 31 | 32 | /** 33 | * 写入文件并执行回调函数 34 | * @param {string} filepath 文件路径 35 | * @param {string|buffer} filedata 写入的数据 36 | * @param {function} callback 回调函数 37 | */ 38 | function writeFileAndRunCallback(filepath, filedata, callback) { 39 | fs.writeFile(filepath, filedata, (err) => { 40 | if (err) { 41 | logger.warn(err); 42 | } 43 | if (typeof callback === "function") { 44 | callback(); 45 | } 46 | }); 47 | } 48 | 49 | /** 50 | * 同步写入文件 51 | * @param {string} filepath 文件路径 52 | * @param {string|buffer} filedata 写入的数据 53 | */ 54 | function writeFileSync(filepath, filedata) { 55 | fs.writeFileSync(filepath, filedata); 56 | } 57 | 58 | /** 59 | * 读取文件夹结构并执行回调函数 60 | * @param {string} dirpath 文件夹路径 61 | * @param {function} callback 回调函数 62 | */ 63 | function readDirAndRunCallback(dirpath, callback) { 64 | fs.readdir(dirpath, (err, files) => { 65 | if (typeof callback === "function") { 66 | callback(files); 67 | } 68 | }); 69 | } 70 | 71 | /** 72 | * 创建空文件 73 | * @param {string} filepath 文件路径 74 | * @return {boolean} [true] 75 | */ 76 | function createEmptyFile(filepath) { 77 | child_process.execSync('type nul > ' + filepath); 78 | return true; 79 | } 80 | 81 | /** 82 | * 创建目录 83 | * @param {string} dirpath 创建的目录绝对地址 84 | * @return {boolean} [true] 85 | */ 86 | function createDir(dirpath) { 87 | child_process.execSync('md ' + dirpath); 88 | return true; 89 | } 90 | 91 | /** 92 | * 判断文件或者文件夹是否存在 93 | * @param {string} checkpath 94 | * @return {boolean} 95 | */ 96 | function checkFileOrDirExist(checkpath) { 97 | return fs.existsSync(checkpath); 98 | } 99 | 100 | /** 101 | * 删除文件或文件夹 102 | * @param {string} deletepath 待删除的文件或文件夹路径 103 | */ 104 | function deleteFileOrDir(deletepath) { 105 | child_process.execSync('rd /s /q ' + deletepath); 106 | } 107 | 108 | /** 109 | * 清空文件夹下所有文件和文件夹 110 | * @param path 111 | */ 112 | function delDir(path) { 113 | let files = []; 114 | if (fs.existsSync(path)) { 115 | files = fs.readdirSync(path); 116 | files.forEach((file, index) => { 117 | let curPath = path + "/" + file; 118 | if (fs.statSync(curPath).isDirectory()) { 119 | delDir(curPath); //递归删除文件夹 120 | } else { 121 | fs.unlinkSync(curPath); //删除文件 122 | } 123 | }); 124 | fs.rmdirSync(path); 125 | } 126 | } 127 | 128 | module.exports = { 129 | readFileAndRunCallback, 130 | readFileSync, 131 | writeFileAndRunCallback, 132 | writeFileSync, 133 | readDirAndRunCallback, 134 | createEmptyFile, 135 | createDir, 136 | checkFileOrDirExist, 137 | deleteFileOrDir, 138 | delDir, 139 | }; -------------------------------------------------------------------------------- /app/core/Http.js: -------------------------------------------------------------------------------- 1 | var logger = require('./Logger');//日志模块 2 | logger.info("HttpService-Initialize"); 3 | const Http = require('http'); 4 | var unirest = require('unirest');//轻量级http请求库 5 | 6 | 7 | /** 8 | * 发送http-post请求并执行回调函数 9 | * @param {string} url 目标url 10 | * @param {object} params 参数对象列表 eg:{"name":"T1","par2":"par2val"} 11 | * @param {function} callback 回调函数 12 | */ 13 | function post(url, params, callback) { 14 | logger.info("[Core][Http-post]发送http请求" + url); 15 | logger.info(params); 16 | var req = unirest.post(url); 17 | req.header('Content-Type', 'application/json') 18 | .header('Accept', 'application/json') 19 | .send(params) 20 | .end(function (data) { 21 | if (data.code == 200) { 22 | logger.info("[Core][Http-post]正常返回"); 23 | callback(true, data.body); 24 | } else { 25 | logger.warn(data); 26 | callback(false, data); 27 | } 28 | }); 29 | } 30 | 31 | function get(url, callback) { 32 | logger.info("[Core][Http-get]发送get请求" + url); 33 | Http.get(url, (res) => { 34 | const {statusCode} = res; 35 | const contentType = res.headers['content-type']; 36 | let error; 37 | if (statusCode !== 200) { 38 | error = new Error('请求失败\n' + 39 | `状态码: ${statusCode}`); 40 | logger.error(error); 41 | // 消费响应的数据以释放内存。 42 | res.resume(); 43 | callback(false, error); 44 | return; 45 | } 46 | //处理数据 47 | res.setEncoding('utf8'); 48 | let rawData = ''; 49 | res.on('data', (chunk) => { 50 | logger.debug(chunk); 51 | rawData += chunk; 52 | }); 53 | res.on('end', () => { 54 | try { 55 | callback(true, rawData, res, url, contentType); 56 | } catch (e) { 57 | logger.error(e); 58 | callback(false, e); 59 | } 60 | }); 61 | }).on('error', (e) => { 62 | logger.error(e); 63 | callback(false, e); 64 | }); 65 | } 66 | 67 | module.exports = {post, get}; -------------------------------------------------------------------------------- /app/core/Lang.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 基层算法封装库 3 | * 4 | * @author troy 5 | * @date 2019/01/21 08:50 PM 6 | */ 7 | function Lang() { 8 | 9 | this.init = function () { 10 | }; 11 | 12 | /** 13 | * 判断是否是数组 最佳算法. 14 | * @param va 15 | * @returns {arg is Array|boolean} 16 | */ 17 | this.isArray = function (va) { 18 | if (typeof Array.isArray === "function") { 19 | return Array.isArray(va); 20 | } else { 21 | return Object.prototype.toString.call(va) === "[object Array]"; 22 | } 23 | }; 24 | 25 | /** 26 | * 判断是否字符串 最简单方法 27 | * 28 | * @param string 29 | * @returns {boolean} 30 | */ 31 | this.isString = function (string) { 32 | return (typeof (string) == 'string'); 33 | }; 34 | 35 | /** 36 | * 判断字符串是否以指定字符串开头 37 | * 38 | * @param string 39 | * @param tstr 40 | */ 41 | this.startsWith = function (string, tstr) { 42 | if (this.isString(string) && this.isString(tstr)) { 43 | return (string.indexOf && string.indexOf(tstr) === 0); 44 | } 45 | }; 46 | 47 | /** 48 | * 判断字符串是否以指定字符串结尾 49 | * 50 | * @param string 51 | * @param tstr 52 | */ 53 | this.endsWith = function (string, tstr) { 54 | if (this.isString(string) && this.isString(tstr)) { 55 | if (string.length >= tstr.length) { 56 | return (string.substr(0, tstr.length) === tstr); 57 | } 58 | } 59 | }; 60 | 61 | /** 62 | * json 对象转 url 字符串, 仅限简单对象 63 | * 64 | * @param json 65 | */ 66 | this.json2UrlParams = function (json) { 67 | var params = ''; 68 | if (json) { 69 | for (var x in json) { 70 | params = params + '&' + x + '=' + json[x]; 71 | } 72 | } 73 | return params; 74 | }; 75 | 76 | /** 77 | * Blob 转 DataURL 78 | */ 79 | this.readBlobAsDataURL = function (blob, callback) { 80 | var a = new FileReader(); 81 | a.onload = function(e) {callback(e.target.result, blob);}; 82 | a.readAsDataURL(blob); 83 | }; 84 | 85 | /** 86 | * ArrayBuffer 转 DataURL 87 | */ 88 | this.readArrayBufferAsDataURL = function(arrayBuffer, options, callback){ 89 | this.readBlobAsDataURL(new Blob(arrayBuffer, options), callback); 90 | }; 91 | 92 | this.init();//自动初始化. 93 | } 94 | 95 | module.exports = () => { 96 | return new Lang(); 97 | }; 98 | 99 | -------------------------------------------------------------------------------- /app/core/Logger.js: -------------------------------------------------------------------------------- 1 | var log4js = require('log4js');//使用log4js作为全局日志模块 2 | var datetime = require('./Datetime')(); 3 | const path = require('path'); 4 | const os = require("os"); 5 | let appvar; 6 | try { 7 | const {remote} = require('electron'); 8 | appVar = remote.getGlobal('appVar') 9 | } catch (e) { 10 | appVar = global.appVar; 11 | } 12 | 13 | var logPath = os.homedir() + "/.ideawall" + "/log"; 14 | 15 | //log4js配置项 16 | log4js.configure({ 17 | appenders: { 18 | everything: { 19 | type: 'dateFile', 20 | filename: logPath + '/ideawall', 21 | pattern: '.yyyy-MM-dd.log', 22 | alwaysIncludePattern: true, 23 | maxLogSize: 1024, 24 | backups: 30, // 日志备份数量,大于该数则自动删除 25 | category: 'logInfo', // 记录器名 26 | keepFileExt: true 27 | } 28 | }, 29 | categories: { 30 | default: { 31 | appenders: ['everything'], 32 | level: 'all' 33 | } 34 | } 35 | }); 36 | //获取logger对象 37 | var logger = log4js.getLogger(); 38 | 39 | /** 40 | * trace级别 41 | * @kind AnyProcess [任意进程调用] 42 | * @param {any} data 日志数据 43 | */ 44 | function trace(data) { 45 | logger.level = 'trace'; 46 | logger.trace(data); 47 | appVar._debug ? console.log(data) : ''; 48 | } 49 | 50 | /** 51 | * debug级别 52 | * @kind AnyProcess [任意进程调用] 53 | * @param {any} data 日志数据 54 | */ 55 | function debug(data) { 56 | logger.level = 'debug'; 57 | logger.debug(data); 58 | appVar._debug ? console.log(data) : '';//debug 级别不在控制台打印 59 | } 60 | 61 | /** 62 | * info级别 63 | * @kind AnyProcess [任意进程调用] 64 | * @param {any} data 日志数据 65 | */ 66 | function info(data) { 67 | logger.level = 'info'; 68 | logger.info(data); 69 | appVar._debug ? console.log(data) : ''; 70 | } 71 | 72 | /** 73 | * warn级别 74 | * @kind AnyProcess [任意进程调用] 75 | * @param {any} data 日志数据 76 | */ 77 | function warn(data) { 78 | logger.level = 'warn'; 79 | logger.warn(data); 80 | appVar._debug ? console.warn(data) : ''; 81 | } 82 | 83 | /** 84 | * log级别 85 | * @kind AnyProcess [任意进程调用] 86 | * @param {any} data 日志数据 87 | */ 88 | function log(data) { 89 | logger.level = 'log'; 90 | logger.log(data); 91 | appVar._debug ? console.log(data) : ''; 92 | } 93 | 94 | /** 95 | * error级别 96 | * @kind AnyProcess [任意进程调用] 97 | * @param {any} data 日志数据 98 | */ 99 | function error(data) { 100 | logger.level = 'error'; 101 | logger.error(data); 102 | appVar._debug ? console.error(data) : ''; 103 | } 104 | 105 | /** 106 | * fatal级别 107 | * @kind AnyProcess [任意进程调用] 108 | * @param {any} data 日志数据 109 | */ 110 | function fatal(data) { 111 | logger.level = 'fatal'; 112 | logger.fatal(data); 113 | appVar._debug ? console.log(data) : ''; 114 | } 115 | 116 | /** 117 | * 定制: 数据库层 打印 118 | * @param data 119 | */ 120 | function sql(data) { 121 | logger.level = 'debug'; 122 | logger.debug(data); 123 | (appVar._debug && appVar._sqllog) ? console.log(data) : '';//debug 级别不在控制台打印 124 | } 125 | 126 | /** 127 | * 压缩打包日志文件, 限定渲染进程调用. 128 | */ 129 | function archive(ipc, callback, dateLimit) { 130 | var logZipFileName = 'ideawall.' + new Date().getTime() + '.log.zip'; 131 | var glob = logPath + '/*.log'; 132 | if (dateLimit === 'today') { 133 | glob = logPath + '/ideawall.' + datetime.nowDate() + '.*.log'; 134 | logZipFileName = 'ideawall.' + datetime.nowDate() + '.log.zip'; 135 | } else if (dateLimit === 'month') { 136 | glob = logPath + '/ideawall.' + datetime.format(false, 'YYYY-MM') + '*.log'; 137 | logZipFileName = 'ideawall.' + datetime.format(false, 'YYYY-MM') + '.log.zip'; 138 | } else if (dateLimit === 'year') { 139 | glob = logPath + '/ideawall.' + datetime.format(false, 'YYYY') + '*.log'; 140 | logZipFileName = 'ideawall.' + datetime.format(false, 'YYYY') + '.log.zip'; 141 | } 142 | var logZipPath = logPath + '/' + logZipFileName; 143 | ipc.send('ipc_resolver', 'archive', { 144 | output: logZipPath, 145 | glob: glob, 146 | name: 'log', 147 | }); 148 | ipc.removeAllListeners('ipc_resolver_ret'); 149 | ipc.on('ipc_resolver_ret', function (event, reb) { 150 | if (typeof callback === 'function') { 151 | callback(reb, logZipFileName, logZipPath); 152 | } 153 | }); 154 | } 155 | 156 | //对外暴露方法 157 | module.exports = { 158 | trace, debug, info, warn, log, error, fatal, sql, archive 159 | }; -------------------------------------------------------------------------------- /app/core/Model.js: -------------------------------------------------------------------------------- 1 | const logger = require('./Logger');//日志模块 2 | const lang = require('./Lang')(); 3 | 4 | function Model() { 5 | 6 | this.init = function () { 7 | 8 | }; 9 | 10 | /** 11 | * 计算表名 12 | * 13 | * @param model 14 | * @returns {string} 15 | */ 16 | this.tbname = function (model) { 17 | return (model.tbinfo.tprefix ? model.tbinfo.tprefix : '') + model.tbinfo.name; 18 | }; 19 | 20 | /** 21 | * 计算列名 22 | * 23 | * @param model 24 | * @param fname 25 | * @returns {string} 26 | */ 27 | this.fieldname = function (model, fname) { 28 | return (model.tbinfo.cprefix ? model.tbinfo.cprefix : '') + fname; 29 | }; 30 | 31 | /** 32 | * 回推数据的时候用于清除列名前缀 33 | * 34 | * @param model 35 | * @param zxx 36 | * @returns {*} 37 | */ 38 | this.rmFp = function (model, zxx) { 39 | var prefix = model.tbinfo.cprefix; 40 | if (prefix && prefix != '' && zxx) { 41 | for (let x in zxx) { 42 | if (x.indexOf(prefix) === 0) { 43 | var newx = x.replace(prefix, ''); 44 | zxx[newx] = zxx[x]; 45 | } 46 | } 47 | } 48 | return zxx; 49 | }; 50 | 51 | /** 52 | * 回推数据的时候用于清除列名前缀 [批量] 53 | * 54 | * @param model 55 | * @param zxxs 56 | * @returns {*} 57 | */ 58 | this.rmFps = function (model, zxxs) { 59 | if (lang.isArray(zxxs)) { 60 | var prefix = model.tbinfo.cprefix; 61 | if (prefix && prefix != '' && zxxs && zxxs.length > 0) { 62 | for (let x in zxxs) { 63 | zxxs[x] = this.rmFp(model, zxxs[x]); 64 | } 65 | } 66 | return zxxs; 67 | } else { 68 | return this.rmFp(model, zxxs); 69 | } 70 | }; 71 | 72 | /** 73 | * 字段合并和缺省处理 74 | * @param model 75 | * @param record 76 | */ 77 | this.field = function (model, record) { 78 | return Object.assign({}, model.columns, record);//会改变第一项的内容, 为防止深拷贝, 第一参数给空对象. 其次, 注意: 只有根属性才会 merage. 79 | // let fields = model.fields; 80 | // for (let x in fields) { 81 | // //延时+闭包, 是因为并发造成的数据异常. 82 | // setTimeout(()=>{ 83 | // (function (x) { 84 | // let zxx = fields[x];//zxx 是原始值, x 是键 85 | // if (record.hasOwnProperty(x)) { 86 | // fields[x] = record[x]; 87 | // } 88 | // })(x); 89 | // }, 100); 90 | // } 91 | // return fields; 92 | }; 93 | 94 | /** 95 | * 批量字段合并和缺省处理 96 | * @param model 97 | * @param records 98 | */ 99 | this.fields = function (model, records) { 100 | for (let x in records) { 101 | records[x] = this.field(model, records[x]); 102 | } 103 | return records; 104 | }; 105 | 106 | /** 107 | * 校验器 108 | * @param model 109 | * @param records 110 | */ 111 | this.validate = function (model, records) { 112 | 113 | }; 114 | 115 | this.init(); 116 | } 117 | 118 | module.exports = () => { 119 | return new Model(); 120 | }; -------------------------------------------------------------------------------- /app/core/Notification.js: -------------------------------------------------------------------------------- 1 | const Electron = require('electron'); 2 | const Shell = Electron.shell; 3 | const Notification = Electron.Notification; 4 | const logger = require('./Logger');//日志模块 5 | const config = require('./Config');//配置模块 6 | 7 | /** 8 | * 显示一个系统原生通知信息 9 | * 10 | * 为了在 macOS 上使用额外的通知按钮, 您的应用程序必须符合以下标准。 11 | * @param option 12 | * @param callback 13 | */ 14 | function notifiy(option, callback) { 15 | option = { 16 | title: option.title,//String 通知的标题, 将在通知窗口的顶部显示. 17 | subtitle: option.subtitle,//String (可选) 通知的副标题, 显示在标题下面。 macOS 18 | body: option.body,//String 通知的正文文本, 将显示在标题或副标题下面. 19 | silent: option.silent,//Boolean(可选) 在显示通知时是否发出系统提示音。 20 | icon: option.icon ? option.icon : '../static/logo/blue-min-pretty.png',//(String | NativeImage ) (可选) 用于在该通知上显示的图标。 21 | hasReply: option.hasReply,//Boolean (可选) 是否在通知中添加一个答复选项. macOS 22 | replyPlaceholder: option.replyPlaceholder,//String(可选) 答复输入框中的占位符。 macOS 23 | actions: option.actions,//NotificationAction[] (可选) macOS - 要添加到通知中的操作 请阅读 NotificationAction文档来了解可用的操作和限制。 24 | sound: option.sound, //String(可选) 显示通知时播放的声音文件的名称。 macOS 25 | closeButtonText: option.closeButtonText,// String(可选) macOS - 自定义的警告框关闭按钮文字。如果该字符串为空,那么将使用本地化的默认文本。 26 | }; 27 | // 创建通知并保存 28 | let hhwNotication = new Notification(option); 29 | hhwNotication.show(); 30 | 31 | hhwNotication.on('show', (event) => { 32 | callback('show', event, option); 33 | }); 34 | 35 | hhwNotication.on('click', (event) => { 36 | callback('click', event, option); 37 | }); 38 | 39 | hhwNotication.on('close', (event) => { 40 | callback('close', event, option); 41 | }); 42 | 43 | hhwNotication.on('reply', (event, reply) => { 44 | callback('reply', event, option, reply); 45 | }); 46 | 47 | hhwNotication.on('action', (event, index) => { 48 | callback('action', event, option, index); 49 | }); 50 | } 51 | 52 | //系统更新通知消息 53 | function notifyUpdater() { 54 | notifiy({ 55 | title: 'ideawall 更新提醒', 56 | subtitle: '', 57 | body: '检测到新版本, 点击前往下载', 58 | silent: false, 59 | actions: [ 60 | { 61 | type: 'button', 62 | text: '前往下载', 63 | }, 64 | { 65 | type: 'button', 66 | text: '稍后提醒', 67 | } 68 | ] 69 | }, (cmd, e, p) => { 70 | if (cmd === 'click' || (cmd === 'action' && p === 0)) { 71 | Shell.openExternal(appVar._updatepageurl); 72 | } 73 | }); 74 | } 75 | 76 | //系统更新完成通知重启消息 77 | function notifyUpdated(subtitle, callback) { 78 | notifiy({ 79 | title: 'ideawall 更新提醒', 80 | subtitle: subtitle, 81 | body: '新的更新已为您准备妥当, 点击重启 ideawall 以体验全新版本.', 82 | silent: false, 83 | actions: [ 84 | { 85 | type: 'button', 86 | text: '重启 ideawall', 87 | }, 88 | { 89 | type: 'button', 90 | text: '稍后处理', 91 | } 92 | ] 93 | }, (cmd, e, p) => { 94 | if (cmd === 'click' || (cmd === 'action' && p === 0)) { 95 | callback(); 96 | } 97 | }); 98 | } 99 | 100 | module.exports = { 101 | notifiy, 102 | notifyUpdater, 103 | notifyUpdated, 104 | }; 105 | -------------------------------------------------------------------------------- /app/core/Regxp.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 常用正则 3 | * @constructor 4 | */ 5 | var Regxp = function () { 6 | 7 | this.password = /^[a-zA-Z]{1}([a-zA-Z0-9]|[._]){5,31}$/; 8 | 9 | this.email = new RegExp("^[a-z0-9]+([._\\-]*[a-z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$"); 10 | 11 | this.mobile = /^[1][3,4,5,7,8][0-9]{9}$/; 12 | 13 | this.idcard = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/; 14 | 15 | this.hanzi = /.*[\u4e00-\u9fa5]+.*$/;//含有汉字 16 | 17 | this.tag = /(^(?!_)(?!.*?_$)[a-zA-Z0-9_\u4e00-\u9fa5]+$)/;//只含有汉字、数字、字母、下划线(不能以下划线开头和结尾) 18 | 19 | this.zhengshu = /^\+?[1-9]\d*$/; 20 | 21 | 22 | /** 23 | * 判断是否含有Emoji表情[utf8mb4] 24 | * 25 | * @param substring 26 | * @returns {boolean} 27 | */ 28 | this.hasEmoji = function (substring) { 29 | for (var i = 0; i < substring.length; i++) { 30 | var hs = substring.charCodeAt(i); 31 | if (0xd800 <= hs && hs <= 0xdbff) { 32 | if (substring.length > 1) { 33 | var ls = substring.charCodeAt(i + 1); 34 | var uc = ((hs - 0xd800) * 0x400) + (ls - 0xdc00) + 0x10000; 35 | if (0x1d000 <= uc && uc <= 0x1f77f) { 36 | return true; 37 | } 38 | } 39 | } else if (substring.length > 1) { 40 | var ls = substring.charCodeAt(i + 1); 41 | if (ls == 0x20e3) { 42 | return true; 43 | } 44 | } else { 45 | if (0x2100 <= hs && hs <= 0x27ff) { 46 | return true; 47 | } else if (0x2B05 <= hs && hs <= 0x2b07) { 48 | return true; 49 | } else if (0x2934 <= hs && hs <= 0x2935) { 50 | return true; 51 | } else if (0x3297 <= hs && hs <= 0x3299) { 52 | return true; 53 | } else if (hs == 0xa9 || hs == 0xae || hs == 0x303d || hs == 0x3030 54 | || hs == 0x2b55 || hs == 0x2b1c || hs == 0x2b1b 55 | || hs == 0x2b50) { 56 | return true; 57 | } 58 | } 59 | } 60 | return false; 61 | }; 62 | 63 | /** 64 | * 统计包含汉字的字符个数 65 | * 汉字占2个字符,非汉字占1个字符 66 | * 67 | * @param chars 68 | * @returns {number} 69 | */ 70 | this.checksum = function (chars) { 71 | var sum = 0; 72 | for (var i = 0; i < chars.length; i++) { 73 | var c = chars.charCodeAt(i); 74 | if ((c >= 0x0001 && c <= 0x007e) || (0xff60 <= c && c <= 0xff9f)) { 75 | sum++; 76 | } else { 77 | sum += 2; 78 | } 79 | } 80 | return sum; 81 | } 82 | 83 | }; 84 | 85 | module.exports = () => { 86 | new RegxpUtil() 87 | }; -------------------------------------------------------------------------------- /app/core/Storage.js: -------------------------------------------------------------------------------- 1 | const global_default_val = "null"; 2 | 3 | /** 4 | * 使用localStorage保存简单数据持久化到本地 5 | * @param {string} key 保存的数据键 6 | * @param {string} value 保存的数据值 7 | * @return {boolean} [true] 8 | */ 9 | function set(key, value) { 10 | window.localStorage.setItem(key, JSON.stringify(value)); 11 | return true; 12 | } 13 | 14 | /** 15 | * 获取保存在localStorage中的数据 16 | * @param {string} key 获取数据的键 17 | * @param {string} dv 默认值 18 | * @return {string} 获取数据的值 19 | */ 20 | function get(key, dv) { 21 | try { 22 | return JSON.parse(window.localStorage.getItem(key)); 23 | } catch (e) { 24 | return dv ? dv : global_default_val; 25 | } 26 | } 27 | 28 | /** 29 | * 根据key删除数据 30 | * @param {string} key 获取数据的键 31 | * @return {boolean} [true] 32 | */ 33 | function remove(key) { 34 | window.localStorage.removeItem(key); 35 | return true; 36 | } 37 | 38 | /** 39 | * 清空数据 40 | * @returns {boolean} 41 | */ 42 | function clear() { 43 | window.localStorage.clear(); 44 | return true; 45 | } 46 | 47 | 48 | /** 49 | * ---扩展 50 | * @type {number} 51 | */ 52 | 53 | 54 | // 过期时间,默认7天 55 | const delay = 7 * 24 * 60 * 60 * 1000; 56 | 57 | /** 58 | * 设置过期时间 59 | * @param delay 60 | * @returns {exports} 61 | */ 62 | function setDelay(delay) { 63 | this.delay = delay; 64 | return this; 65 | } 66 | 67 | /** 68 | * 判断一个 localStorage 是否过期 69 | * @param key 70 | * @returns {boolean} 71 | */ 72 | function isExpire(key) { 73 | var isExpire = true, 74 | value = window.localStorage.getItem(key), 75 | now = new Date().getTime(); 76 | 77 | if (value) { 78 | value = JSON.parse(value); 79 | // 当前时间是否大于过期时间 80 | isExpire = now > value._delay; 81 | } else { 82 | // 没有值也是过期 83 | } 84 | return isExpire; 85 | } 86 | 87 | /** 88 | * 设置 localStorage 89 | * @param key 90 | * @param value 91 | */ 92 | function setEx(key, value) { 93 | window.localStorage.removeItem(key);//在添加之前,先删除,防止在ios等设备下的QUOTA_EXCEEDED_ERR异常 94 | var isObject = value instanceof Object, 95 | _time = new Date().getTime(), 96 | _delay = this.delay; 97 | 98 | // 如果不是对象,新建一个对象把 value 存起来 99 | if (!isObject) { 100 | var b = value; 101 | value = {}; 102 | value._value = b; 103 | } 104 | // 加入时间 105 | value._time = _time; 106 | // 过期时间 107 | value._delay = _time + _delay; 108 | // 是否一个对象 109 | value._isObject = isObject; 110 | window.localStorage.setItem(key, JSON.stringify(value)); 111 | return this; 112 | } 113 | 114 | /** 115 | * 获取某个 localStorage 值 116 | * @param key 117 | * @returns {*} 118 | */ 119 | function getEx(key) { 120 | var isExpire = this.isExpire(key), 121 | value = null; 122 | if (!isExpire) { 123 | value = window.localStorage.getItem(key); 124 | value = JSON.parse(value); 125 | if (!value._isObject) { 126 | value = value._value; 127 | } 128 | } 129 | return value; 130 | } 131 | 132 | module.exports = { 133 | set, 134 | get, 135 | remove, 136 | clear, 137 | setDelay, 138 | isExpire, 139 | setEx, 140 | getEx 141 | } -------------------------------------------------------------------------------- /app/core/Typer.js: -------------------------------------------------------------------------------- 1 | var Typer = function (panelId, dmsg) { 2 | 3 | this.config = { 4 | msg: function (msg) { 5 | return msg; 6 | }, 7 | len: function () { 8 | return this.msg.length; 9 | }, 10 | seq: 0, 11 | speed: 150, //打字时间(ms) 12 | type: function () { 13 | var _this = this; 14 | document.getElementById(panelId).innerHTML = _this.msg.substring(0, _this.seq); 15 | if (_this.seq == _this.len()) { 16 | _this.seq = 0; 17 | clearTimeout(t); 18 | } else { 19 | _this.seq++; 20 | var t = setTimeout(function () { 21 | _this.type() 22 | }, this.speed); 23 | } 24 | } 25 | }; 26 | 27 | this.write = function (text) { 28 | this.config.msg = (text && text !== '' && text !== null) ? text : dmsg; 29 | this.config.type(); 30 | } 31 | }; 32 | 33 | 34 | module.exports = (panelId, dmsg) => { 35 | new Typer(panelId, dmsg) 36 | }; -------------------------------------------------------------------------------- /app/core/UUID.js: -------------------------------------------------------------------------------- 1 | /** 2 | * UUID库[主进程和渲染进程通用, 需要在ideanote.js引用之后调用]. 3 | * 4 | * @author troy 5 | * @date 2019/01/21 05:29 PM 6 | */ 7 | const uuidv1 = require('uuid/v1');//基于时间戳, 生成并返回RFC4122 v1(基于时间戳的)UUID. 8 | const uuidv3 = require('uuid/v3');//基于命名空间, 生成并返回RFC4122 v3 UUID. 9 | const uuidv4 = require('uuid/v4');//基于随机数, 生成并返回RFC4122 v4 UUID. 10 | 11 | function UUID() { 12 | 13 | this.id = '';//默认算法生成的默认id 14 | 15 | //初始化时候即生成默认id. 16 | this.init = function () { 17 | this.id = this.serial(); 18 | }; 19 | 20 | //常规序列生成算法 21 | this.serial = function (numCount, wordCount, myDefinedSN) { 22 | numCount = numCount ? numCount : 6; 23 | wordCount = wordCount ? wordCount : 2; 24 | myDefinedSN = myDefinedSN ? ("-" + myDefinedSN) : ""; 25 | var timestamp = new Date().getTime();//需要13位毫秒级时间戳 26 | var $nums = '0123456789'; 27 | var numsRandom = ''; 28 | for (i = 0; i < numCount; i++) { //需要6位随机数字 29 | numsRandom += $nums.charAt(Math.floor(Math.random() * $nums.length)); 30 | } 31 | var $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; 32 | var charsRandom = ''; 33 | for (i = 0; i < wordCount; i++) { //需要2位随机字母 34 | charsRandom += $chars.charAt(Math.floor(Math.random() * $chars.length)); 35 | } 36 | return charsRandom + timestamp + numsRandom + myDefinedSN;//13位时间戳(毫秒级) + 8位随机数(2位字母置于开头, 6位数字置于结尾) 37 | }; 38 | 39 | this.v1 = function () { 40 | return uuidv1(); 41 | }; 42 | 43 | this.v3 = function (name, namespace) { 44 | return uuidv3(name, namespace); 45 | }; 46 | 47 | this.v4 = function () { 48 | return uuidv4(); 49 | }; 50 | 51 | 52 | this.init();//自动初始化. 53 | } 54 | 55 | module.exports = () => { 56 | return new UUID(); 57 | }; 58 | 59 | -------------------------------------------------------------------------------- /app/dao/LocalDeskDao.js: -------------------------------------------------------------------------------- 1 | const Model = require('../core/Model')(); 2 | const datetime = require('../core/Datetime')(); 3 | const Electron = require('electron'); 4 | 5 | const initscript = '' + 6 | 'CREATE TABLE IF NOT EXISTS "iw_localdesk" (\n' + 7 | ' "ld_id" integer NOT NULL ON CONFLICT IGNORE PRIMARY KEY AUTOINCREMENT,\n' + 8 | ' "ld_author" text(30),\n' + 9 | ' "ld_name" text(50),\n' + 10 | ' "ld_ename" text(80),\n' + 11 | ' "ld_description" text(256),\n' + 12 | ' "ld_preview" text(500),\n' + 13 | ' "ld_date_get" text(30),\n' + 14 | ' "ld_type" text(20) DEFAULT page,\n' + 15 | ' "ld_init_sign" integer(1) DEFAULT 1,\n' + 16 | ' "ld_source_type" text(10) DEFAULT local,\n' + 17 | ' "ld_source_val" text(500),\n' + 18 | ' "ld_switch_media" integer(1) DEFAULT 2,\n' + 19 | ' "ld_switch_source" integer(1) DEFAULT 1,\n' + 20 | ' "ld_params" text(1000) DEFAULT \'\',\n' + 21 | ' "ld_readme_path" text(500),\n' + 22 | ' "ld_feedback" text(500),\n' + 23 | ' CONSTRAINT "ld_key_id" UNIQUE ("ld_id" COLLATE NOCASE ASC) ON CONFLICT IGNORE\n' + 24 | ');'; 25 | 26 | /** 27 | * 设备桌面 Dao 层. 28 | * 29 | * @param model 30 | * @constructor 31 | */ 32 | function LocalDeskDao(model) { 33 | 34 | this._self = undefined; 35 | 36 | this.init = function () { 37 | model.initscript = initscript; 38 | this._self = require('../core/Database')(model); 39 | }; 40 | 41 | /** 42 | * 初始化工作, 用于监测默认数据是否存在, 不存在就插入进入 43 | * @param defaults 44 | * @returns {LocalDeskDao} 45 | */ 46 | this.initial = function (defaults) { 47 | for (var x in defaults) { 48 | var zxx = defaults[x]; 49 | if (!this._self.exist({ 50 | ename: zxx.ename 51 | })) {//未存在 52 | this._self.insert(Model.field(model, zxx)); 53 | }else{//已存在 => 更新一些必要数据 54 | 55 | } 56 | } 57 | return this; 58 | }; 59 | 60 | /** 61 | * 增加桌面项 62 | * 63 | * @param desk 64 | */ 65 | this.addDesk = function (desk) { 66 | if (!this._self.exist({ 67 | ename: desk.ename 68 | })) {//未存在 69 | return this._self.insert(Model.field(model, desk)); 70 | } 71 | return false; 72 | }; 73 | 74 | /** 75 | * 获取所有桌面数据, 等待修正为分页获取. 76 | */ 77 | this.getPage = function () { 78 | return this._self.selectAll(); 79 | }; 80 | 81 | /** 82 | * 根据 id 获取桌面数据 83 | * 84 | * @param id 85 | * @returns {*} 86 | */ 87 | this.getDeskById = function (id) { 88 | return this._self.selectFirst({id: id}); 89 | }; 90 | 91 | /** 92 | * 根据 id 更新数据 93 | * 94 | * @param obj 95 | * @returns {*} 96 | */ 97 | this.updateById = function (obj) { 98 | if (obj.params) { 99 | obj.params = JSON.stringify(obj.params); 100 | } 101 | return this._self.update({id: obj.id}, obj); 102 | }; 103 | 104 | /** 105 | * 根据 id 删除桌面, 须提前取消桌面引用! 106 | * @param id 107 | * @returns {*} 108 | */ 109 | this.deleteById = function (id) { 110 | return this._self.delete({id: obj.id}); 111 | }; 112 | 113 | /** 114 | * 根据索引来判断是否已经存在 115 | * @param desk 116 | */ 117 | this.isExist = function (desk) { 118 | return this._self.exist({ 119 | ename: desk.ename 120 | }); 121 | }; 122 | 123 | this.init();//自动初始化. 124 | } 125 | 126 | module.exports = (model) => { 127 | return new LocalDeskDao(model); 128 | }; -------------------------------------------------------------------------------- /app/dao/MediaDao.js: -------------------------------------------------------------------------------- 1 | const Model = require('../core/Model')(); 2 | const datetime = require('../core/Datetime')(); 3 | 4 | const initscript = '' + 5 | 'CREATE TABLE IF NOT EXISTS "iw_media" (\n' + 6 | ' "m_id" integer NOT NULL ON CONFLICT IGNORE PRIMARY KEY AUTOINCREMENT,\n' + 7 | ' "m_filename" text(200),\n' + 8 | ' "m_filepath" text(5000),\n' + 9 | ' "m_date_add" text(30),\n' + 10 | ' "m_ld_id" integer(11) NOT NULL ON CONFLICT IGNORE,\n' + 11 | ' CONSTRAINT "m_key_id" UNIQUE ("m_id" COLLATE NOCASE ASC) ON CONFLICT IGNORE\n' + 12 | ');'; 13 | 14 | /** 15 | * 桌面媒体组 Dao 层. 16 | * 17 | * @param model 18 | * @constructor 19 | */ 20 | function MediaDao(model) { 21 | 22 | this._self = undefined; 23 | 24 | this.init = function () { 25 | model.initscript = initscript; 26 | this._self = require('../core/Database')(model); 27 | }; 28 | 29 | /** 30 | * 指定桌面的某媒体是否存在 31 | */ 32 | this.isExist = function(deskId, filename, filepath){ 33 | return this._self.exist({ 34 | ld_id: deskId+'', 35 | filename: filename, 36 | filepath: filepath, 37 | }) 38 | }; 39 | 40 | /** 41 | * 新增媒体资源 42 | */ 43 | this.addsByDeskId = function(deskId, medias){ 44 | return this._self.batchInsert(medias); 45 | }; 46 | 47 | /** 48 | * 通过桌面 id 获取媒体组数据 49 | * @param ld_id 50 | */ 51 | this.getsByDeskId = function (ld_id) { 52 | return this._self.execSelect("select * from " 53 | + Model.tbname(model) 54 | + " where " 55 | + Model.fieldname(model, 'ld_id') 56 | + " == " + ld_id + '' 57 | + " order by " + Model.fieldname(model, 'date_add') 58 | + " desc"); 59 | }; 60 | 61 | /** 62 | * 更新桌面媒体组 63 | * 64 | * @param ld_id 65 | * @param medias 66 | */ 67 | this.updatesByDeskId = function (ld_id, medias) { 68 | //1.先直接删掉 69 | this._self.delete({ld_id: ld_id + ''}); 70 | //2.直接批量添加 71 | return this._self.batchInsert(medias); 72 | }; 73 | 74 | /** 75 | * 删除单个媒体数据 76 | * @param ld_id 77 | * @param filepath 78 | */ 79 | this.deleteByDeskId = function (ld_id, mediaId) { 80 | return this._self.delete({ld_id: ld_id + '', id: mediaId+''}); 81 | }; 82 | 83 | /** 84 | * 清空媒体数据 85 | * 86 | * @param ld_id 87 | */ 88 | this.clearByDeskId = function (ld_id) { 89 | return this._self.delete({ld_id: ld_id + ''}); 90 | }; 91 | 92 | 93 | this.init();//自动初始化. 94 | } 95 | 96 | module.exports = (model) => { 97 | return new MediaDao(model); 98 | }; -------------------------------------------------------------------------------- /app/dao/PreferenceDao.js: -------------------------------------------------------------------------------- 1 | const Model = require('../core/Model')(); 2 | const datetime = require('../core/Datetime')(); 3 | 4 | const c_tbs = ['iw_devicedesk', 'iw_media', 'iw_localdesk', 'iw_preference']; 5 | 6 | const initscript = '' + 7 | 'CREATE TABLE IF NOT EXISTS "iw_preference" (\n' + 8 | ' "p_id" integer NOT NULL ON CONFLICT IGNORE PRIMARY KEY AUTOINCREMENT,\n' + 9 | ' "p_key" text(30),\n' + 10 | ' "p_name" text(50),\n' + 11 | ' "p_description" text(500),\n' + 12 | ' "p_remark" text(500),\n' + 13 | ' "p_value" text(2000),\n' + 14 | ' "p_type" text(30) DEFAULT common,\n' + 15 | ' "p_formitem" text(30),\n' + 16 | ' "p_sort" integer(6) DEFAULT 100,\n' + 17 | ' "p_reboot" integer(1) DEFAULT 1,\n' + 18 | ' "p_sync" integer(1) DEFAULT 1,\n' + 19 | ' "p_explicit" integer(1) DEFAULT 2,\n' + 20 | ' "p_os" text(10),\n' + 21 | ' CONSTRAINT "p_key_id" UNIQUE ("p_id" COLLATE NOCASE ASC) ON CONFLICT IGNORE\n' + 22 | ');'; 23 | 24 | /** 25 | * 偏好设置 Dao 层. 26 | * 27 | * @param model 28 | * @constructor 29 | */ 30 | function PreferenceDao(model) { 31 | 32 | this._self = undefined; 33 | 34 | this.init = function () { 35 | model.initscript = initscript; 36 | this._self = require('../core/Database')(model); 37 | }; 38 | 39 | /** 40 | * 清空所有的数据库 41 | * @param tablename 42 | */ 43 | this.clearDatabase = function (tablename) { 44 | if (tablename) { 45 | this._self.dropTable(tablename); 46 | } else { 47 | for (var x in c_tbs) { 48 | this._self.dropTable(c_tbs[x]); 49 | } 50 | } 51 | }; 52 | 53 | /** 54 | * 通过键获取设置项 55 | * 56 | * @param key 57 | */ 58 | this.getByKey = function (key) { 59 | return this._self.selectFirst({key: key}); 60 | }; 61 | 62 | /** 63 | * 获取需要同步向设备的配置项, 返回数组 64 | * @returns {*} 65 | */ 66 | this.getNeedSync = function () { 67 | return this._self.select({sync: 2}); 68 | }; 69 | 70 | /** 71 | * 获取所有的设置项 72 | * @returns {*} 73 | */ 74 | this.getAll = function () { 75 | return this._self.selectAll(); 76 | }; 77 | 78 | /** 79 | * 根据 id 更新设置项 80 | * 81 | * @param obj 82 | * @returns {*} 83 | */ 84 | this.updateById = function (obj) { 85 | console.debug(obj.value); 86 | if (obj.value && typeof (obj.value) != 'string') { 87 | obj.value = JSON.stringify(obj.value); 88 | } 89 | return this._self.update({id: obj.id}, obj); 90 | }; 91 | 92 | /** 93 | * 根据 key 更新设置项 94 | * 95 | * @param obj 96 | * @returns {*} 97 | */ 98 | this.updateBykey = function (obj) { 99 | console.debug(obj.value); 100 | if (obj.value && typeof (obj.value) != 'string') { 101 | obj.value = JSON.stringify(obj.value); 102 | } 103 | return this._self.update({key: obj.key}, obj); 104 | }; 105 | 106 | /** 107 | * 添加一个配置项 108 | * 109 | * @param obj 110 | * @returns {*} 111 | */ 112 | this.add = function (obj) { 113 | if (obj.value && typeof (obj.value) != 'string') { 114 | obj.value = JSON.stringify(obj.value); 115 | } 116 | return this._self.insert(obj); 117 | }; 118 | 119 | 120 | this.init();//自动初始化. 121 | } 122 | 123 | module.exports = (model) => { 124 | return new PreferenceDao(model); 125 | }; -------------------------------------------------------------------------------- /app/message/DeviceMessage.js: -------------------------------------------------------------------------------- 1 | const logger = require('../core/Logger'); 2 | const uuid = require('../core/UUID')(); 3 | const datetime = require('../core/Datetime')(); 4 | const model = require('../core/Model')(); 5 | 6 | //注意: 由于 remote 模块仅限渲染进程调用, 所以, 当前库亦仅限渲染进程调用. 7 | const Electron = require('electron'); 8 | const Remote = Electron.remote; 9 | let appVar; 10 | try { 11 | appVar = Remote.getGlobal('appVar') 12 | } catch (e) { 13 | appVar = global.appVar; 14 | } 15 | 16 | /** 17 | * 本地-我的桌面数据模型 18 | * 19 | * @constructor 20 | */ 21 | function DeviceMessage() { 22 | 23 | /** 24 | * 同步更新指令 25 | * @param displays 26 | */ 27 | this.syncUpdate = function (displays) { 28 | // setTimeout(()=>{//稍微延迟一下, 防止数据未达. 29 | if (!displays) { 30 | for (var x in appVar._wallwindows) { 31 | var win = appVar._wallwindows[x]; 32 | win.window.webContents.send('ipc_wall_update_forward'); 33 | } 34 | } else { 35 | for (var x in displays) { 36 | var dp = displays[x]; 37 | if (!dp) { 38 | return this.syncUpdate();//有可能数组中的元素为 undefined 39 | } 40 | appVar._wallwindows[parseInt(dp.display_id)].window.webContents.send('ipc_wall_update_forward'); 41 | } 42 | } 43 | // }, 500); 44 | }; 45 | 46 | } 47 | 48 | module.exports = () => { 49 | return new DeviceMessage(); 50 | }; -------------------------------------------------------------------------------- /app/model/MediaModel.js: -------------------------------------------------------------------------------- 1 | const logger = require('../core/Logger'); 2 | const uuid = require('../core/UUID')(); 3 | const datetime = require('../core/Datetime')(); 4 | const Model = require('../core/Model')(); 5 | const fs = require("fs"); 6 | 7 | const deviceMessage = require('../message/DeviceMessage')(); 8 | 9 | let model = new (function () { 10 | //数据表信息 11 | this.tbinfo = { 12 | tprefix: 'iw_',//表前缀 13 | cprefix: 'm_',//列前缀 14 | name: 'media',//名称. 15 | anno: '桌面媒体数据表', //注释信息 16 | columns: {//列, 传入一个对象 17 | id: null,//唯一标识 id 18 | filename: '',//文件名 19 | filepath: '',//文件路径 20 | date_add: datetime.now(),//添加时间 21 | ld_id: null,//目标桌面 22 | }, 23 | }; 24 | }); 25 | 26 | /** 27 | * 本地-我的桌面数据模型 28 | * 29 | * @constructor 30 | */ 31 | function MediaModel(appVar) { 32 | 33 | this.dao = undefined; 34 | 35 | this.parent = undefined; 36 | 37 | this.init = function () { 38 | this.dao = require('../dao/MediaDao')(model); 39 | this.parent = require('../model/LocalDeskModel')(model); 40 | }; 41 | 42 | this.isLocalMediaEffect = function (mediaPath) { 43 | if (mediaPath && (mediaPath + '').trim() !== '' && (mediaPath + '').trim().indexOf('http') !== 0) {//非网络媒体 44 | if (fs.existsSync(mediaPath)) { 45 | return mediaPath; 46 | } 47 | } 48 | return false; 49 | }; 50 | 51 | this.isExist = function(deskId, filename, filepath){ 52 | return this.dao.isExist(deskId, filename, filepath); 53 | } 54 | 55 | this.addsByDeskId = function(deskId, medias){ 56 | this.dao.addsByDeskId(deskId, medias); 57 | this.parent.updateById({id: deskId}, true);//更新掉初始化标记, 并且不发送通信指令. 58 | this.syncUpdate(); 59 | }; 60 | 61 | this.getsByDeskId = function (deskId) { 62 | return this.dao.getsByDeskId(deskId); 63 | }; 64 | 65 | this.updatesByDeskId = function (deskId, medias) { 66 | this.dao.updatesByDeskId(deskId, medias); 67 | this.parent.updateById({id: deskId}, true);//更新掉初始化标记, 并且不发送通信指令. 68 | this.syncUpdate(); 69 | }; 70 | 71 | this.deleteByDeskId = function (deskId, mediaId) { 72 | this.dao.deleteByDeskId(deskId, mediaId); 73 | this.syncUpdate(); 74 | }; 75 | 76 | this.clearByDeskId = function (deskId) { 77 | this.dao.clearByDeskId(deskId); 78 | this.syncUpdate(); 79 | }; 80 | 81 | /** 82 | * 同步更新信号发送 83 | */ 84 | this.syncUpdate = function () { 85 | deviceMessage.syncUpdate(); 86 | }; 87 | 88 | this.init(); 89 | } 90 | 91 | module.exports = (appVar) => { 92 | return new MediaModel(appVar); 93 | }; 94 | -------------------------------------------------------------------------------- /app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ideawall", 3 | "author": "周曦 <1747128171@qq.com>", 4 | "version": "1.2.1", 5 | "description": "ideawall - 创意者桌面 [MacOs 版]", 6 | "private": true, 7 | "license": "", 8 | "main": "App.js", 9 | "scripts": { 10 | "start": "electron .", 11 | "debug": "electron . --debug", 12 | "rebuild": "cnpm rebuild -f --runtime=electron --target=5.0.4 --disturl=https://npm.taobao.org/mirrors/atom-shell --abi=72", 13 | "clean": "yarn autoclean -I && yarn autoclean -F", 14 | "mail": "node resolver/MailResolver.js", 15 | "archive": "node resolver/ArchiverResolver.js", 16 | "uuid": "node resolver/UUIDResolver.js --serial --v1", 17 | "test": "node test/test.js" 18 | }, 19 | "engines": { 20 | "node": ">= 6.0.0" 21 | }, 22 | "devDependencies": { 23 | }, 24 | "dependencies": { 25 | "electron-updater": "^4.0.12", 26 | "mousetrap": "^1.6.3", 27 | "archiver": "^3.0.0", 28 | "async": "^2.6.1", 29 | "auto-launch": "^5.0.5", 30 | "better-sqlite3": "^5.4.0", 31 | "log4js": "^3.0.6", 32 | "nodemailer": "^6.2.1", 33 | "nodemailer-smtp-transport": "^2.7.4", 34 | "unirest": "^0.5.1", 35 | "request": "^2.87.0", 36 | "unzip": "^0.1.11", 37 | "uuid": "^3.3.2" 38 | }, 39 | "__npminstall_done": false 40 | } 41 | -------------------------------------------------------------------------------- /app/process/main/ApplicationMenu.js: -------------------------------------------------------------------------------- 1 | const Electron = require('electron'); 2 | const Menu = Electron.Menu; // 菜单模块 3 | const MenuItem = Electron.MenuItem; // 菜单项模块 4 | 5 | const path = require('path');//原生库path模块 6 | const url = require('url'); 7 | const os = require("os"); 8 | const fs = require("fs"); 9 | 10 | const logger = require('../../core/Logger');//引入全局日志组件 11 | const config = require('../../core/Config');//引入全局配置组件 12 | 13 | const relative = '../../'; 14 | 15 | /** 16 | * 添加全局菜单 17 | */ 18 | function init(appVar) { 19 | // 注册应用全局菜单 20 | var template = [{ 21 | label: '编辑', 22 | submenu: [{ 23 | label: '撤销', 24 | accelerator: 'CmdOrCtrl+Z', 25 | role: 'undo' 26 | }, { 27 | label: '重做', 28 | accelerator: 'Shift+CmdOrCtrl+Z', 29 | role: 'redo' 30 | }, { 31 | type: 'separator' 32 | }, { 33 | label: '复制', 34 | accelerator: 'CmdOrCtrl+C', 35 | role: 'copy' 36 | }, { 37 | label: '粘贴', 38 | accelerator: 'CmdOrCtrl+V', 39 | role: 'paste' 40 | }] 41 | }, { 42 | label: '帮助', 43 | role: 'help', 44 | submenu: [{ 45 | label: '学习更多', 46 | click: function () { 47 | Electron.shell.openExternal('http://electron.atom.io') 48 | } 49 | }] 50 | }]; 51 | const menu = Menu.buildFromTemplate(template); 52 | Menu.setApplicationMenu(menu); 53 | } 54 | 55 | module.exports = { 56 | init 57 | }; -------------------------------------------------------------------------------- /app/process/main/AutoLaunch.js: -------------------------------------------------------------------------------- 1 | const Electron = require('electron'); 2 | const App = Electron.app; 3 | 4 | const logger = require('../../core/Logger');//引入全局日志组件 5 | const config = require('../../core/Config');//引入全局配置组件 6 | 7 | const AutoLaunch = require('auto-launch'); 8 | let minecraftAutoLauncher = new AutoLaunch({ 9 | name: App.getName(), 10 | path: App.getPath('exe'), 11 | isHidden: false, 12 | mac: { 13 | useLaunchAgent: true,//使用启动代理模式 14 | } 15 | }); 16 | 17 | /** 18 | * 参数说明: 19 | * name: [String] 应用的名称。 20 | * path: [String] 应用的绝对路径。NW.js和Electron应用程序可选) 21 | * isHidden: [Boolean] 如果true,我们指示操作系统在登录时启动时以隐藏模式启动您的应用程序。默认为false。 22 | * mac: 仅适用于Mac的选项。 23 | * -useLaunchAgent [Boolean] 默认情况下,我们使用AppleScript添加登录项。如果是这样true,我们使用启动代理自动启动您的应用。默认为false。 24 | * 25 | * 方法解析: 26 | * .enable() 将您的应用设置为在启动时自动启动。返回一个Promise。 27 | * .disable() 禁用您的应用在启动时自动启动。返回一个Promise。 28 | * .isEnabled() 返回一个解析为布尔值的Promise; true如果您的应用设置为启动时启动。 29 | * 30 | * 运行过程: 31 | * Linux 一个桌面项创建; 即在.desktop中创建文件~/.config/autostart/。 32 | * 注意:如果启用了自动启动,然后删除了您的应用,则此桌面条目文件将留在用户的计算机上。 33 | * MacOS -AppleScript(默认) 我们执行AppleScript命令以指示System Events为您的应用添加或删除登录项。没有涉及的文件。 34 | * 要查看您的登录项,您可以转到系统偏好设置,用户和组,然后转到登录项。最终用户也可以在此添加或禁用项目(包括您的应用),但大多数典型用户都不知道它。 35 | * 注意:这不是Mac App Store友好的; 如果您在自己的应用中使用它,它将被Mac App Store拒绝。我们对此只有99%的肯定,因为我们还没有真正尝试过。 36 | * -启动代理 这是一个基于文件的方法,如Linux的桌面输入方法。我们.plist在用户Library/LaunchAgents目录中添加一个文件,为您的应用创建启动代理。 37 | * 优点 38 | * 启动代理程序适用于没有UI的守护程序/某些内容,这可能适用于您的应用程序。 39 | * 我们认为此方法似乎更快,如启用或禁用自动启动(应用程序启动所需的时间没有差异)。虽然,这不是一个真正的问题。 40 | * 您可能不相信AppleScript。 41 | * 缺点 42 | * 您的应用不会出现在用户的登录项中。因此,用户只能在应用程序中切换自动启动,如果您为他们提供了当然的设置(您应该这样做!)。 43 | * 这不是一个大问题,因为大多数用户都不知道登录项目首选项,但如果您的应用程序出现在那里,它将是理想的。 44 | * 如果用户要删除您的应用程序,该文件将留在用户的计算机上。 45 | * 如果您发现AppleScript方法不适合您并且此方法有效,请通过创建问题告诉我们。 46 | * 注意:这不是Mac App Store友好的; 如果您在应用程序中使用它,它将被Mac App Store拒绝,因为它到达应用程序沙箱之外。 47 | *Windows 我们在下面添加一个注册表项\HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run。 48 | * 注意:如果用户要删除您的应用程序,这将留在注册表中,但这不是什么大问题。您可以配置卸载程序以取消设置。 49 | */ 50 | function checkLaunch(enable) {//如果是首次启动, 传入一个 true, 设置自启动. 51 | //Promise, 判定是否开机自启动 52 | minecraftAutoLauncher.isEnabled() 53 | .then(function (isEnabled) { 54 | if (isEnabled) {//如果已经生效, 但是设置取消, 就取消 55 | logger.warn("[Process][AutoLaunch] 开机自启动已生效"); 56 | if (!enable) { 57 | switchLaunch(); 58 | } 59 | } else {//如果没有生效, 设置, 就强制设置. 60 | if (enable) { 61 | switchLaunch(true);//默认自动开关设定 62 | } 63 | } 64 | }) 65 | .catch(function (err) { 66 | // handle error 67 | logger.warn("[Process][AutoLaunch] 开机自启动任务失败 => " + err); 68 | }); 69 | } 70 | 71 | /** 72 | * 开机自启动开关 73 | * 74 | * @param enable 75 | */ 76 | function switchLaunch(enable) { 77 | if (enable) { 78 | minecraftAutoLauncher.enable(); 79 | logger.error("[Process][AutoLaunch] 设置开机自启动"); 80 | } else { 81 | minecraftAutoLauncher.disable(); 82 | logger.error("[Process][AutoLaunch] 取消开机自启动"); 83 | } 84 | } 85 | 86 | /** 87 | * 初始化 88 | */ 89 | function init(appVar, preferenceModel) { 90 | appVar._autoLauncher = minecraftAutoLauncher; 91 | var pref_autoLaunch = preferenceModel.getByKey("autoLaunch"); 92 | if (!pref_autoLaunch) { 93 | checkLaunch(true); 94 | preferenceModel.add({ 95 | type: 'common', 96 | formitem: 'switch', 97 | key: 'autoLaunch', 98 | name: '自启动', 99 | description: '开机自动运行 ideawall', 100 | sort: 10, 101 | reboot: 1, 102 | value: { 103 | enable: true, 104 | }, 105 | }); 106 | } else { 107 | pref_autoLaunch.value = JSON.parse(pref_autoLaunch.value); 108 | if (pref_autoLaunch.value.enable) { 109 | checkLaunch(true); 110 | } else { 111 | checkLaunch(false); 112 | } 113 | } 114 | } 115 | 116 | 117 | module.exports = { 118 | init, 119 | checkLaunch, 120 | switchLaunch, 121 | }; -------------------------------------------------------------------------------- /app/process/main/CrashReporter.js: -------------------------------------------------------------------------------- 1 | const { crashReporter } = require('electron'); 2 | 3 | crashReporter.start({ 4 | productName: 'YourName', 5 | companyName: 'YourCompany', 6 | submitURL: 'https://your-domain.com/url-to-submit', 7 | uploadToServer: true 8 | }); -------------------------------------------------------------------------------- /app/process/main/Dialog.js: -------------------------------------------------------------------------------- 1 | const Electron = require('electron'); 2 | const BrowserWindow = Electron.BrowserWindow; 3 | const ipc = Electron.ipcMain; 4 | const Dialog = Electron.dialog; 5 | 6 | const logger = require('../../core/Logger');//引入全局日志组件 7 | const config = require('../../core/Config');//引入全局配置组件 8 | let appVar = global.appVar; 9 | 10 | /** 11 | * 根据 windowId 获取 window 对象. 12 | * @param windowKey 13 | * @returns {*} 14 | */ 15 | function getWindow(windowKey) { 16 | if(windowKey) { 17 | return global.appVar[windowKey] 18 | } 19 | } 20 | 21 | 22 | /** 23 | * 展示 message box, 它会阻塞进程,直到 message box 关闭为止.返回点击按钮的索引值. 24 | */ 25 | ipc.on('dialog.showMessageBox', function (event, winKey, responseIpcCmd, type, buttons, defaultId, title, message, detail, icon, cancelId, noLink) { 26 | logger.info('[Core][Dialog][dialog.showMessageBox] ' + winKey + ' - ' + responseIpcCmd + ' - ' + type); 27 | logger.info('[Core][Dialog][dialog.showMessageBox] ' + message + ' - ' + detail); 28 | var args = { 29 | type: type,//String - 可以是 "none", "info", "error", "question" 或 "warning". 在 Windows, "question" 与 "info" 展示图标相同, 除非你使用 "icon" 参数. 30 | buttons: buttons,// Array - buttons 内容,数组. 31 | defaultId: defaultId,//Integer - 在message box 对话框打开的时候,设置默认button选中,值为在 buttons 数组中的button索引. 32 | title: title ? title : appVar._appname,//String - message box 的标题,一些平台不显示. 33 | message: message,//String - message box 内容. 34 | detail: detail,//String - 额外信息. 35 | icon: icon?icon:(appVar._icon),//NativeImage 36 | cancelId: cancelId,//Integer - 当用户关闭对话框的时候,不是通过点击对话框的button,就返回值.默认值为对应 "cancel" 或 "no" 标签button 的索引值, 或者如果没有这种button,就返回0. 在 OS X 和 Windows 上, "Cancel" button 的索引值将一直是 cancelId, 不管之前是不是特别指出的. 37 | noLink: noLink//Boolean - 在 Windows ,Electron 将尝试识别哪个button 是普通 button (如 "Cancel" 或 "Yes"), 然后再对话框中以链接命令(command links)方式展现其它的 button . 这能让对话框展示得很炫酷.如果你不喜欢这种效果,你可以设置 noLink 为 true. 38 | }; 39 | var win = getWindow(winKey); 40 | if(win) { 41 | Dialog.showMessageBox(win, args, function (response) { 42 | if (responseIpcCmd && responseIpcCmd != '') { 43 | event.sender.send(responseIpcCmd, response); 44 | } 45 | event.returnValue = response; 46 | }); 47 | }else{ 48 | Dialog.showMessageBox(args, function (response) { 49 | if (responseIpcCmd && responseIpcCmd != '') { 50 | event.sender.send(responseIpcCmd, response); 51 | } 52 | event.returnValue = response; 53 | }); 54 | } 55 | }); 56 | 57 | /** 58 | * 展示一个传统的包含错误信息的对话框. 59 | * 在 app 模块触发 ready 事件之前,这个 api 可以被安全调用,通常它被用来在启动的早期阶段报告错误. 在 Linux 上,如果在 app 模块触发 ready 事件之前调用,message 将会被触发显示stderr,并且没有实际GUI 框显示. 60 | * 61 | * 注意: 渲染进程内的错误,不建议调用此通信事件. 错误提示推荐调用showMessageBox实现. 62 | */ 63 | ipc.on('dialog.showErrorBox', function (event, title, content) { 64 | Dialog.showErrorBox(title, content); 65 | }); 66 | 67 | /** 68 | * 成功使用这个方法的话,就返回一个可供用户选择的文件路径数组,失败返回 undefined. 69 | */ 70 | ipc.on('dialog.showOpenDialog', function (event, responseIpcCmd, title, defaultPath, filters, properties) { 71 | let win = BrowserWindow.getFocusedWindow(); 72 | if (win) { 73 | Dialog.showOpenDialog(win, { 74 | title: title,//String - 可以是 "none", "info", "error", "question" 或 "warning". 在 Windows, "question" 与 "info" 展示图标相同, 除非你使用 "icon" 参数. 75 | defaultPath: defaultPath,// Array - buttons 内容,数组. 76 | //filters - Array, 当需要限定用户的行为的时候,指定一个文件数组给用户展示或选择. 例如: 77 | // filters: [ 78 | // { name: 'Images', extensions: ['jpg', 'png', 'gif'] }, 79 | // { name: 'Movies', extensions: ['mkv', 'avi', 'mp4'] }, 80 | // { name: 'Custom File Type', extensions: ['as'] }, 81 | // { name: 'All Files', extensions: ['*'] } 82 | // ] 83 | // extensions 数组应当只包含扩展名,不应该包含通配符或'.'号 (例如 'png' 正确,但是 '.png' 和 '*.png' 不正确). 展示全部文件的话, 使用 '*' 通配符 (不支持其他通配符). 84 | filters: filters, 85 | //properties - Array, 包含了对话框的特性值, 可以包含 openFile, openDirectory, multiSelections and createDirectory 86 | //在 Windows 和 Linux ,一个打开的 dialog 不能既是文件选择框又是目录选择框, 所以如果在这些平台上设置 properties 的值为 ['openFile', 'openDirectory'] , 将展示一个目录选择框. 87 | properties: properties 88 | }, function (filenames) { 89 | if (responseIpcCmd && responseIpcCmd != '') { 90 | event.sender.send(responseIpcCmd, filenames); 91 | } 92 | }); 93 | } else { 94 | logger.info('showOpenDialog: 找不到被激活的窗体'); 95 | } 96 | }); 97 | 98 | /** 99 | * 成功使用这个方法的话,就返回一个可供用户选择的文件路径数组,失败返回 undefined. filters 指定展示一个文件类型数组, 100 | */ 101 | ipc.on('dialog.showSaveDialog', function (event, responseIpcCmd, title, defaultPath, filters) { 102 | Dialog.showSaveDialog(title, defaultPath, filters, function (filenames) { 103 | if (responseIpcCmd && responseIpcCmd != '') { 104 | event.sender.send(responseIpcCmd, filenames); 105 | } 106 | }); 107 | }); -------------------------------------------------------------------------------- /app/process/main/Dock.js: -------------------------------------------------------------------------------- 1 | const Electron = require('electron'); 2 | const App = Electron.app; // 核心应用承载模块 3 | const Menu = Electron.Menu; // 菜单模块 4 | const MenuItem = Electron.MenuItem; // 菜单项模块 5 | const Shell = Electron.shell; 6 | 7 | const path = require('path');//原生库path模块 8 | const url = require('url'); 9 | const os = require("os"); 10 | const fs = require("fs"); 11 | 12 | const logger = require('../../core/Logger');//引入全局日志组件 13 | const config = require('../../core/Config');//引入全局配置组件 14 | 15 | const helper = require('./MainProcessHelper'); 16 | 17 | function init(appVar) { 18 | if (process.platform === 'darwin') { 19 | const dockMenu = buildDockMenu(appVar); 20 | App.dock.setMenu(dockMenu); 21 | } 22 | } 23 | 24 | function buildDockMenu(appVar) { 25 | // 注册应用全局菜单 26 | var template = []; 27 | template.push({ 28 | label: '控制面板', 29 | type: 'normal', 30 | accelerator: 'Shift+CmdOrCtrl+C', 31 | click: function () { 32 | helper.getControlWindow(true, {tab: 'mydesk'}); 33 | }, 34 | }); 35 | template.push({type: 'separator'}); 36 | template.push({ 37 | label: '偏好设置', 38 | type: 'normal', 39 | accelerator: 'CmdOrCtrl+,', 40 | click: function () { 41 | helper.getControlWindow(true, {tab: 'preference'}); 42 | }, 43 | }); 44 | template.push({ 45 | label: '桌面商店', 46 | type: 'normal', 47 | click: function () { 48 | helper.getControlWindow(true, {tab: 'deskstore'}); 49 | }, 50 | }); 51 | template.push({ 52 | label: '资源社区', 53 | type: 'normal', 54 | click: function () { 55 | helper.getControlWindow(true, {tab: 'resbbs'}); 56 | }, 57 | }); 58 | return Menu.buildFromTemplate(template); 59 | } 60 | 61 | 62 | module.exports = { 63 | init 64 | }; -------------------------------------------------------------------------------- /app/process/main/GlobalShortCut.js: -------------------------------------------------------------------------------- 1 | const Electron = require('electron'); 2 | const GlobalShortcut = Electron.globalShortcut; // 全局快捷键模块 3 | 4 | const path = require('path');//原生库path模块 5 | const url = require('url'); 6 | const os = require("os"); 7 | const fs = require("fs"); 8 | 9 | const logger = require('../../core/Logger');//引入全局日志组件 10 | const config = require('../../core/Config');//引入全局配置组件 11 | 12 | const relative = '../../'; 13 | 14 | /** 15 | * 添加全局快捷键 16 | * 在 Linux 和 Windows 上, Command 键没有任何效果, 所以使用 CommandOrControl表述, macOS 是 Command ,在 Linux 和 Windows 上是Control。 17 | * 使用 Alt 代替Option. Option 键只在 macOS 系统上存在, 而 Alt 键在任何系统上都有效. 18 | * Super键是指 Windows 和 Linux 系统上的 Windows 键,但在 macOS 里为 Cmd 键. 19 | * 20 | * 可用的快捷键: 21 | * Command (缩写为Cmd) 22 | * Control (缩写为Ctrl) 23 | * CommandOrControl (缩写为 CmdOrCtrl) 24 | * Alt 25 | * Option 26 | * AltGr 27 | * Shift 28 | * Super 29 | * 30 | * 可用的普通按键: 31 | * 0 to 9 32 | * A to Z 33 | * F1 to F24 34 | * 类似~, !, @, #, $的标点符号 35 | * Plus 36 | * Space 37 | * Tab 38 | * Backspace 39 | * Delete 40 | * Insert 41 | * Return (等同于 Enter) 42 | * Up, Down, Left and Right 43 | * Home 和 End 44 | * PageUp 和 PageDown 45 | * Escape (缩写为 Esc) 46 | * VolumeUp, VolumeDown 和 VolumeMute 47 | * MediaNextTrack、MediaPreviousTrack、MediaStop 和 MediaPlayPause 48 | * PrintScreen 49 | */ 50 | function init(appVar) { 51 | // 注册打开控制台的快捷键 52 | GlobalShortcut.register('CmdOrCtrl+Option+I', function () { 53 | if (appVar._debug) { 54 | let win = Electron.BrowserWindow.getFocusedWindow(); 55 | if (win) { 56 | if (win.webContents.isDevToolsOpened()) { 57 | win.webContents.closeDevTools(); 58 | } else { 59 | win.webContents.openDevTools({detach: true}); 60 | } 61 | } 62 | } 63 | }); 64 | // 注册Ctrl+r的全局事件快捷键: 用于debug模式下, 刷新二级页面. 65 | GlobalShortcut.register('CmdOrCtrl+R', function () { 66 | if (appVar._debug) { 67 | let win = Electron.BrowserWindow.getFocusedWindow(); 68 | if (win && appVar._ready._render) { 69 | let appRenderInit = require('../renderer/app');//执行应用渲染引擎. 70 | async.aop(false, function () { 71 | appRenderInit(); 72 | return true; 73 | }, function () { 74 | win.webContents.executeJavaScript('\ 75 | mainProcess_listener_shortcut_ctrl7r();\ 76 | ', true, function (result) { 77 | console.log("mainProcess_listener_shortcut_ctrl7r通信结果: " + result); 78 | return true; 79 | }); 80 | }, '[主进程] '); 81 | } 82 | } 83 | }); 84 | // 注册Ctrl+Shift+r的全局事件快捷键: 用于debug模式下, 刷新顶级页面. 85 | GlobalShortcut.register('CmdOrCtrl+Shift+R', function () { 86 | if (appVar._debug) { 87 | let win = Electron.BrowserWindow.getFocusedWindow(); 88 | if (win && appVar._ready._render) { 89 | let appRenderInit = require('../renderer/app');//执行应用渲染引擎. 90 | async.aop(false, function () { 91 | appRenderInit(); 92 | return true; 93 | }, function () { 94 | win.webContents.executeJavaScript('\ 95 | mainProcess_listener_shortcut_ctrlshift7r();\ 96 | ', true, function (result) { 97 | console.log("mainProcess_listener_shortcut_ctrlshift7r通信结果: " + result); 98 | return true; 99 | }); 100 | }, '[主进程] '); 101 | } 102 | } 103 | }); 104 | // 注册Ctrl+s的全局事件快捷键 105 | GlobalShortcut.register('CmdOrCtrl+S', function () { 106 | let win = Electron.BrowserWindow.getFocusedWindow(); 107 | if (win && appVar._ready._render) { 108 | win.webContents.executeJavaScript('\ 109 | mainProcess_listener_shortcut_ctrl7s();\ 110 | ', true, function (result) { 111 | console.log("mainProcess_listener_shortcut_ctrl7s通信结果: " + result); 112 | }); 113 | } 114 | }); 115 | 116 | // 注册Tab的全局事件快捷键 117 | GlobalShortcut.register('Tab', function () { 118 | let win = Electron.BrowserWindow.getFocusedWindow(); 119 | if (win && appVar._ready._render) { 120 | win.webContents.executeJavaScript('\ 121 | mainProcess_listener_shortcut_tab();\ 122 | ', true, function (result) { 123 | console.log("mainProcess_listener_shortcut_tab通信结果: " + result); 124 | }); 125 | } 126 | }); 127 | } 128 | 129 | module.exports = { 130 | init 131 | }; -------------------------------------------------------------------------------- /app/process/main/PowerMonitor.js: -------------------------------------------------------------------------------- 1 | const Electron = require('electron'); 2 | 3 | const path = require('path');//原生库path模块 4 | const url = require('url'); 5 | const os = require("os"); 6 | const fs = require("fs"); 7 | 8 | const logger = require('../../core/Logger');//引入全局日志组件 9 | const config = require('../../core/Config');//引入全局配置组件 10 | 11 | const relative = '../../'; 12 | 13 | /** 14 | * 系统能源监控 [在app.on(ready)之后将无法使用. ] 15 | */ 16 | function init(appVar) { 17 | powerMonitor = Electron.powerMonitor; 18 | //在系统挂起的时候触发. 19 | powerMonitor.on('suspend', function () { 20 | console.log('The system is going to sleep'); 21 | }); 22 | //在系统恢复继续工作的时候触发 23 | powerMonitor.on('resume', function () { 24 | console.log('The system is resumed'); 25 | }); 26 | //在系统使用交流电的时候触发 27 | powerMonitor.on('on-ac', function () { 28 | console.log('The system is on-ac'); 29 | }); 30 | //在系统使用电池电源的时候触发 31 | powerMonitor.on('on-battery', function () { 32 | console.log('The system is on-battery'); 33 | }); 34 | } 35 | 36 | module.exports = { 37 | init 38 | }; -------------------------------------------------------------------------------- /app/process/main/TaskBar.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/process/main/TaskBar.js -------------------------------------------------------------------------------- /app/process/main/window/AboutWindow.js: -------------------------------------------------------------------------------- 1 | const Electron = require('electron'); 2 | 3 | const path = require('path');//原生库path模块 4 | const url = require('url'); 5 | const os = require("os"); 6 | const fs = require("fs"); 7 | 8 | const logger = require('../../../core/Logger');//引入全局日志组件 9 | const config = require('../../../core/Config');//引入全局配置组件 10 | const lang = require('../../../core/Lang')(); 11 | const AppVar = require('../../../process/main/AppVar'); 12 | let appVar = AppVar.getAppVar(); 13 | 14 | const relative = '../../../'; 15 | 16 | let xwindow; 17 | 18 | function creat(paramJson) { 19 | logger.info("[Process][MainProcessHelper][AboutWindow]初始化桌面预览窗口"); 20 | 21 | // 创建浏览器窗口。 22 | xwindow = new Electron.BrowserWindow({ 23 | frame: true, //隐藏原生窗口边框 24 | useContentSize: true, 25 | zoomToPageWidth: false,//单击工具栏上的绿色信号灯按钮或单击 窗口>缩放 菜单项时的行为, 仅macOS中有效. 如果为 true, 窗口将放大到网页的本身宽度, false 将使其缩放到屏幕的宽度。 这也会影响直接调用 maximize() 时的行为。 默认值为 false. 26 | backgroundColor: appVar._platform !== 'darwin'?'#FFF':'#80FFFFFF', 27 | show: false,//创建时候是否显示 28 | center: true, 29 | width: 560, 30 | height: 320, 31 | resizable: false, 32 | movable: true, 33 | minimizable: false, 34 | maximizable: false, 35 | title: '', 36 | // alwaysOnTop: true, 37 | opacity: 1.0,//设置窗口初始的不透明度, 介于 0.0 (完全透明) 和 1.0 (完全不透明) 之间。仅支持 Windows 和 macOS 。 38 | darkTheme: false,//强制窗口使用 dark 主题, 只在一些拥有 GTK+3 桌面环境上有效. 默认值为 false. 39 | acceptFirstMouse: true,//是否允许单击web view来激活窗口 40 | disableAutoHideCursor: true,//当 typing 时是否隐藏鼠标.默认 false 41 | focusable: true,//是否可聚焦 42 | transparent: false,//开启窗口透明 43 | hasShadow: true,//窗口是否有阴影。只在 OS X 上有效. 默认为 true。这个打开会造成部分盒子阴影, 体验较差. 44 | skipTaskbar: true, //是否跳过在任务栏中显示窗口. 默认值为false. 45 | enableLargerThanScreen: false,//是否允许改变窗口的大小时, 大于屏幕的尺寸. 默认值为false. 46 | autoHideMenuBar: true,//除非点击 Alt,否则隐藏菜单栏.默认为 false。 47 | webPreferences: { //用于解决not allowed to load local resource的问题 48 | devTools: appVar._debug, 49 | webSecurity: false,//当设置为 false, 它将禁用同源策略 (通常用来测试网站), 如果此选项不是由开发者设置的,还会把 allowRunningInsecureContent设置为 true. 默认值为 true。 50 | nodeIntegration: false, //全局禁用nodejs 51 | nodeIntegrationInWorker: true,//启用多线程 52 | preload: appVar._preloadscript, //提前加载, 通过这个文件调用nodejs和electron语法糖即可. 53 | scrollBounce: true, //在 macOS 启用弹力动画 (橡皮筋) 效果. 默认值为 false 54 | enableRemoteModule: true,//是否启用 Remote 模块。 默认值为 true。 55 | zoomFactor: 1.0, //页面的默认缩放系数, 3.0 表示 300%. 默认值为 1.0. 56 | textAreasAreResizable: false, //让 TextArea 元素可以调整大小. 默认值为 true. 57 | backgroundThrottling: false,//是否在页面成为背景时限制动画和计时器。 这也会影响到 Page Visibility API. 默认值为 true。 58 | } 59 | }); 60 | 61 | 62 | // 旁加载应用的 index.html。 63 | xwindow.loadURL(url.format({ 64 | pathname: path.join(__dirname, relative + "./view/components/About.html"), 65 | protocol: 'file:', 66 | slashes: true 67 | }) + "?windowKey=_aboutwindow&windowId=" + xwindow.id + lang.json2UrlParams(paramJson)); 68 | 69 | // 引入主入口界面 70 | if (appVar._debug) { 71 | // 打开开发者工具 72 | xwindow.webContents.openDevTools({detach: true});//TODO 改为调试模式配置项 73 | } else { 74 | xwindow.webContents.closeDevTools(); 75 | xwindow.webContents.on('devtools-opened', () => { 76 | xwindow.webContents.closeDevTools(); 77 | }); 78 | xwindow.webContents.on('devtools-focused', () => { 79 | xwindow.webContents.closeDevTools(); 80 | }); 81 | } 82 | 83 | // 当窗口关闭时触发 84 | xwindow.on('closed', function () { 85 | logger.info("[Process][MainProcessHelper][_AboutWindow.on._closed_]桌面预览窗口关闭"); 86 | 87 | //将全局xwindow置为null 88 | xwindow = null; 89 | }); 90 | 91 | xwindow.once('ready-to-show', () => { 92 | xwindow.show(); 93 | 94 | // //窗体透明度渐显 95 | // var opacityIndex = setInterval(()=>{ 96 | // if(xwindow.getOpacity() >= 1){ 97 | // clearInterval(opacityIndex); 98 | // } 99 | // xwindow.setOpacity(xwindow.getOpacity() + 0.2); 100 | // }, 100); 101 | }); 102 | AppVar.setAppVar({ 103 | _aboutwindow: xwindow, 104 | }); 105 | return xwindow; 106 | } 107 | 108 | module.exports = { 109 | creat 110 | }; -------------------------------------------------------------------------------- /app/process/main/window/PreviewWindow.js: -------------------------------------------------------------------------------- 1 | const Electron = require('electron'); 2 | 3 | const path = require('path');//原生库path模块 4 | const url = require('url'); 5 | const os = require("os"); 6 | const fs = require("fs"); 7 | 8 | const logger = require('../../../core/Logger');//引入全局日志组件 9 | const config = require('../../../core/Config');//引入全局配置组件 10 | const lang = require('../../../core/Lang')(); 11 | const AppVar = require('../../../process/main/AppVar'); 12 | let appVar = AppVar.getAppVar(); 13 | 14 | const relative = '../../../'; 15 | 16 | let xwindow; 17 | 18 | function creat(deskId, paramJson) { 19 | logger.info("[Process][MainProcessHelper][PreviewWindow]初始化桌面预览窗口"); 20 | 21 | // 创建浏览器窗口。 22 | xwindow = new Electron.BrowserWindow({ 23 | frame: true, //隐藏原生窗口边框 24 | useContentSize: true, 25 | zoomToPageWidth: false,//单击工具栏上的绿色信号灯按钮或单击 窗口>缩放 菜单项时的行为, 仅macOS中有效. 如果为 true, 窗口将放大到网页的本身宽度, false 将使其缩放到屏幕的宽度。 这也会影响直接调用 maximize() 时的行为。 默认值为 false. 26 | backgroundColor: appVar._platform !== 'darwin'?'#FFF':'#80FFFFFF', 27 | show: false,//创建时候是否显示 28 | center: true, 29 | width: 786, 30 | height: 480, 31 | // minWidth: 786, 32 | // minHeight: 480, 33 | resizable: true, 34 | movable: true, 35 | minimizable: true, 36 | maximizable: true, 37 | opacity: 1.0,//设置窗口初始的不透明度, 介于 0.0 (完全透明) 和 1.0 (完全不透明) 之间。仅支持 Windows 和 macOS 。 38 | darkTheme: false,//强制窗口使用 dark 主题, 只在一些拥有 GTK+3 桌面环境上有效. 默认值为 false. 39 | acceptFirstMouse: true,//是否允许单击web view来激活窗口 40 | disableAutoHideCursor: true,//当 typing 时是否隐藏鼠标.默认 false 41 | focusable: true,//是否可聚焦 42 | transparent: false,//开启窗口透明 43 | hasShadow: true,//窗口是否有阴影。只在 OS X 上有效. 默认为 true。这个打开会造成部分盒子阴影, 体验较差. 44 | skipTaskbar: false, //是否跳过在任务栏中显示窗口. 默认值为false. 45 | enableLargerThanScreen: false,//是否允许改变窗口的大小时, 大于屏幕的尺寸. 默认值为false. 46 | autoHideMenuBar: true,//除非点击 Alt,否则隐藏菜单栏.默认为 false。 47 | webPreferences: { //用于解决not allowed to load local resource的问题 48 | devTools: appVar._debug, 49 | webSecurity: false,//当设置为 false, 它将禁用同源策略 (通常用来测试网站), 如果此选项不是由开发者设置的,还会把 allowRunningInsecureContent设置为 true. 默认值为 true。 50 | nodeIntegration: false, //全局禁用nodejs 51 | nodeIntegrationInWorker: true,//启用多线程 52 | preload: appVar._preloadscript, //提前加载, 通过这个文件调用nodejs和electron语法糖即可. 53 | scrollBounce: true, //在 macOS 启用弹力动画 (橡皮筋) 效果. 默认值为 false 54 | enableRemoteModule: true,//是否启用 Remote 模块。 默认值为 true。 55 | zoomFactor: 1.0, //页面的默认缩放系数, 3.0 表示 300%. 默认值为 1.0. 56 | textAreasAreResizable: false, //让 TextArea 元素可以调整大小. 默认值为 true. 57 | backgroundThrottling: false,//是否在页面成为背景时限制动画和计时器。 这也会影响到 Page Visibility API. 默认值为 true。 58 | } 59 | }); 60 | 61 | 62 | // 旁加载应用的 index.html。 63 | xwindow.loadURL(url.format({ 64 | pathname: path.join(__dirname, relative + "./view/components/Preview.html"), 65 | protocol: 'file:', 66 | slashes: true 67 | }) + "?windowKey=_previewwindow&windowId=" + xwindow.id + "&deskId=" + deskId + lang.json2UrlParams(paramJson)); 68 | 69 | // 引入主入口界面 70 | if (appVar._debug) { 71 | // 打开开发者工具 72 | xwindow.webContents.openDevTools({detach: true});//TODO 改为调试模式配置项 73 | } else { 74 | xwindow.webContents.closeDevTools(); 75 | xwindow.webContents.on('devtools-opened', () => { 76 | xwindow.webContents.closeDevTools(); 77 | }); 78 | xwindow.webContents.on('devtools-focused', () => { 79 | xwindow.webContents.closeDevTools(); 80 | }); 81 | } 82 | 83 | // 当窗口关闭时触发 84 | xwindow.on('closed', function () { 85 | logger.info("[Process][MainProcessHelper][_PreviewWindow_.on._closed_]桌面预览窗口关闭"); 86 | 87 | //将全局xwindow置为null 88 | xwindow = null; 89 | }); 90 | 91 | xwindow.once('ready-to-show', () => { 92 | xwindow.show(); 93 | 94 | // //窗体透明度渐显 95 | // var opacityIndex = setInterval(()=>{ 96 | // if(xwindow.getOpacity() >= 1){ 97 | // clearInterval(opacityIndex); 98 | // } 99 | // xwindow.setOpacity(xwindow.getOpacity() + 0.2); 100 | // }, 100); 101 | }); 102 | AppVar.setAppVar({ 103 | _previewId: deskId, 104 | _previewwindow: xwindow, 105 | }); 106 | return xwindow; 107 | } 108 | 109 | module.exports = { 110 | creat 111 | }; -------------------------------------------------------------------------------- /app/process/main/window/XBrowserWindow.js: -------------------------------------------------------------------------------- 1 | const Electron = require('electron'); 2 | 3 | const path = require('path');//原生库path模块 4 | const url = require('url'); 5 | const os = require("os"); 6 | const fs = require("fs"); 7 | 8 | const logger = require('../../../core/Logger');//引入全局日志组件 9 | const config = require('../../../core/Config');//引入全局配置组件 10 | const lang = require('../../../core/Lang')(); 11 | const AppVar = require('../../../process/main/AppVar'); 12 | let appVar = AppVar.getAppVar(); 13 | 14 | const relative = '../../../'; 15 | 16 | let xwindow; 17 | 18 | function creat(link, paramJson) { 19 | logger.info("[Process][MainProcessHelper][BrowserWindow]初始化拟浏览器窗口"); 20 | 21 | // 创建浏览器窗口。 22 | xwindow = new Electron.BrowserWindow({ 23 | // frame: false, //隐藏原生窗口边框 24 | useContentSize: true, 25 | zoomToPageWidth: false,//单击工具栏上的绿色信号灯按钮或单击 窗口>缩放 菜单项时的行为, 仅macOS中有效. 如果为 true, 窗口将放大到网页的本身宽度, false 将使其缩放到屏幕的宽度。 这也会影响直接调用 maximize() 时的行为。 默认值为 false. 26 | backgroundColor: appVar._platform !== 'darwin'?'#FFF':'#80FFFFFF', 27 | show: false,//创建时候是否显示 28 | center: true, 29 | width: 1080, 30 | height: 720, 31 | minWidth: 998, 32 | minHeight: 600, 33 | resizable: true, 34 | movable: true, 35 | minimizable: true, 36 | maximizable: true, 37 | title: 'ideawall 浏览器', 38 | // alwaysOnTop: true, 39 | opacity: 1.0,//设置窗口初始的不透明度, 介于 0.0 (完全透明) 和 1.0 (完全不透明) 之间。仅支持 Windows 和 macOS 。 40 | darkTheme: false,//强制窗口使用 dark 主题, 只在一些拥有 GTK+3 桌面环境上有效. 默认值为 false. 41 | acceptFirstMouse: true,//是否允许单击web view来激活窗口 42 | disableAutoHideCursor: true,//当 typing 时是否隐藏鼠标.默认 false 43 | focusable: true,//是否可聚焦 44 | transparent: false,//开启窗口透明 45 | hasShadow: true,//窗口是否有阴影。只在 OS X 上有效. 默认为 true。这个打开会造成部分盒子阴影, 体验较差. 46 | skipTaskbar: false, //是否跳过在任务栏中显示窗口. 默认值为false. 47 | enableLargerThanScreen: false,//是否允许改变窗口的大小时, 大于屏幕的尺寸. 默认值为false. 48 | autoHideMenuBar: true,//除非点击 Alt,否则隐藏菜单栏.默认为 false。 49 | webPreferences: { //用于解决not allowed to load local resource的问题 50 | devTools: appVar._debug, 51 | webSecurity: false,//当设置为 false, 它将禁用同源策略 (通常用来测试网站), 如果此选项不是由开发者设置的,还会把 allowRunningInsecureContent设置为 true. 默认值为 true。 52 | nodeIntegration: false, //全局禁用nodejs 53 | nodeIntegrationInWorker: true,//启用多线程 54 | preload: appVar._preloadscript, //提前加载, 通过这个文件调用nodejs和electron语法糖即可. 55 | scrollBounce: true, //在 macOS 启用弹力动画 (橡皮筋) 效果. 默认值为 false 56 | enableRemoteModule: true,//是否启用 Remote 模块。 默认值为 true。 57 | zoomFactor: 1.0, //页面的默认缩放系数, 3.0 表示 300%. 默认值为 1.0. 58 | textAreasAreResizable: false, //让 TextArea 元素可以调整大小. 默认值为 true. 59 | backgroundThrottling: false,//是否在页面成为背景时限制动画和计时器。 这也会影响到 Page Visibility API. 默认值为 true。 60 | } 61 | }); 62 | 63 | 64 | // 旁加载应用的 index.html。 65 | xwindow.loadURL(url.format({ 66 | pathname: path.join(__dirname, relative + "./view/components/Browser.html"), 67 | protocol: 'file:', 68 | slashes: true 69 | }) + "?windowKey=_browserwindow&windowId=" + xwindow.id + "&link=" + encodeURIComponent(encodeURIComponent(link)) +lang.json2UrlParams(paramJson)); 70 | 71 | // 引入主入口界面 72 | if (appVar._debug) { 73 | // 打开开发者工具 74 | xwindow.webContents.openDevTools({detach: true});//TODO 改为调试模式配置项 75 | } else { 76 | xwindow.webContents.closeDevTools(); 77 | xwindow.webContents.on('devtools-opened', () => { 78 | xwindow.webContents.closeDevTools(); 79 | }); 80 | xwindow.webContents.on('devtools-focused', () => { 81 | xwindow.webContents.closeDevTools(); 82 | }); 83 | } 84 | 85 | // 当窗口关闭时触发 86 | xwindow.on('closed', function () { 87 | logger.info("[Process][MainProcessHelper][_BrowserWindow.on._closed_]拟浏览器窗口关闭"); 88 | 89 | //将全局xwindow置为null 90 | xwindow = null; 91 | }); 92 | 93 | xwindow.once('ready-to-show', () => { 94 | xwindow.show(); 95 | 96 | // //窗体透明度渐显 97 | // var opacityIndex = setInterval(()=>{ 98 | // if(xwindow.getOpacity() >= 1){ 99 | // clearInterval(opacityIndex); 100 | // } 101 | // xwindow.setOpacity(xwindow.getOpacity() + 0.2); 102 | // }, 100); 103 | }); 104 | AppVar.setAppVar({ 105 | _browserwindow: xwindow, 106 | }); 107 | return xwindow; 108 | } 109 | 110 | module.exports = { 111 | creat 112 | }; -------------------------------------------------------------------------------- /app/process/renderer/RendererProcessHelper.js: -------------------------------------------------------------------------------- 1 | const logger = require('../../core/Logger');//日志模块 2 | 3 | const ipcRenderer = require('electron').ipcRenderer; 4 | 5 | 6 | /** 7 | * 发送消息给主进程 8 | * @kind RendererProcessOnly [仅渲染进程] 9 | * @param {string} signal 发送给主进程的信号 10 | * @param {any} sendargs 发送给主进程的数据 11 | */ 12 | function sendToMainProcess(signal, sendargs) { 13 | logger.info("[Process][RendererProcessHelper][sendToMainProcess]给主进程发送信号 " + signal + " 参数 " + sendargs); 14 | ipcRenderer.send(signal, sendargs);//使用ipcRenderer方法给主进程发送消息 15 | } 16 | 17 | /** 18 | * 根据信号量注册对应的回调函数 19 | * @kind RendererProcessOnly [仅渲染进程] 20 | * @param {string} signal 渲染进程接收的信号 21 | * @param {function} callback 收到信号量要执行的回调函数 22 | */ 23 | function registeCallback(signal, callback) { 24 | logger.info("[Process][RendererProcessHelper][registeCallback]注册信号量 " + signal + " 的回调函数"); 25 | if (typeof callback === "function") { 26 | ipcRenderer.on(signal, (sys, args) => { 27 | callback(args,sys); 28 | }); 29 | return true; 30 | } else { 31 | logger.warn("[Process][RendererProcessHelper][registeCallback]不是函数类型" + callback); 32 | return false; 33 | } 34 | } 35 | 36 | 37 | module.exports = { 38 | sendToMainProcess, 39 | registeCallback 40 | } -------------------------------------------------------------------------------- /app/resolver/ArchiveResolver.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const archiver = require('archiver'); 3 | const child_process = require('child_process'); 4 | 5 | let archiveStore = archiver('zip', { 6 | zlib: {level: 9} // 设置压缩级别 7 | }); 8 | 9 | /** 10 | * 压缩器 11 | * @param outputPath 例如: __dirname + '/example.zip' 12 | * @param callback 13 | * @constructor 14 | */ 15 | var ArchiveResolver = function (outputPath, callback) { 16 | // 创建接收输出流的文件. 17 | this.output = fs.createWriteStream(outputPath); 18 | 19 | this.init = function () { 20 | 21 | this.output.on('close', function () { 22 | console.log('[Core][ArchiveResolver]压缩已完成,输出文件描述符已关闭。output: ' + outputPath); 23 | console.log('[Core][ArchiveResolver]' + archiveStore.pointer() + ' total bytes'); 24 | callback('close'); 25 | }); 26 | 27 | this.output.on('end', function () { 28 | console.log('[Core][ArchiveResolver]压缩结束.'); 29 | callback('close'); 30 | }); 31 | 32 | // archiveStore.on('progress', function (progress) { 33 | // console.log('[Core][ArchiveResolver]压缩进度: ' + progress + '/' + archiveStore.pointer() + ' output: ' + outputPath); 34 | // }); 35 | 36 | archiveStore.on('warning', function (err) { 37 | if (err.code === 'ENOENT') { 38 | // log warning 39 | console.log('[Core][ArchiveResolver]压缩警告 \r\n' + err); 40 | callback('warning'); 41 | } else { 42 | console.log('[Core][ArchiveResolver]压缩失败 \r\n' + err); 43 | callback('error'); 44 | // throw error 45 | throw err; 46 | } 47 | }); 48 | 49 | archiveStore.on('error', function (err) { 50 | console.log('[Core][ArchiveResolver]压缩失败 \r\n' + err); 51 | callback('error'); 52 | throw err; 53 | }); 54 | 55 | // 管道将存档数据传送到文件 56 | archiveStore.pipe(this.output); 57 | }; 58 | 59 | /** 60 | * 从流附加文件 61 | * @param filePath 62 | * @param newname 63 | */ 64 | this.fromStream = function (filePath, newname) { 65 | archiveStore.append(fs.createReadStream(filePath), {name: newname}); 66 | // 完成存档(即我们完成了附加文件,但流还必须完成) 67 | // “close”、“end”或“finish”可以在调用此方法后立即激发,因此请预先注册到它们 68 | archiveStore.finalize(); 69 | }; 70 | 71 | /** 72 | * 从字符串附加文件 73 | * @param str 74 | * @param newname 75 | */ 76 | this.fromString = function (str, newname) { 77 | archiveStore.append(str, {name: newname}); 78 | archiveStore.finalize(); 79 | }; 80 | 81 | /** 82 | * 从缓冲区附加文件 83 | * @param bufferFrom 84 | * @param newname 85 | */ 86 | this.fromBuffer = function (bufferFrom, newname) { 87 | var buffer3 = Buffer.from(bufferFrom); 88 | archiveStore.append(buffer3, {name: newname}); 89 | archiveStore.finalize(); 90 | }; 91 | 92 | /** 93 | * 附加单个文件, 注意与流附加的区别. 性能上, 流附加更佳. 94 | * @param filePath 95 | * @param newname 96 | */ 97 | this.fromFile = function (filePath, newname) { 98 | archiveStore.file(filePath, {name: newname}); 99 | archiveStore.finalize(); 100 | }; 101 | 102 | /** 103 | * 附加子目录中的文件,并将其命名为存档中的“新子目录” 104 | * @param dirPath 105 | * @param newname 若不传 newname, 附加子目录中的文件,将其内容放在存档的根目录中 106 | */ 107 | this.fromDir = function (dirPath, newname) { 108 | archiveStore.directory(dirPath, newname); 109 | archiveStore.finalize(); 110 | }; 111 | 112 | /** 113 | * 全局正则过滤模式 114 | * @param glob 例如: 'subdir/*.txt' 115 | * @param newname 116 | */ 117 | this.fromGlob = function (glob, newname) { 118 | archiveStore.glob(glob, newname); 119 | archiveStore.finalize(); 120 | 121 | }; 122 | 123 | this.init(); 124 | }; 125 | 126 | module.exports = (outputPath, callback) => { 127 | return new ArchiveResolver(outputPath, callback); 128 | }; 129 | -------------------------------------------------------------------------------- /app/resolver/MailResolver.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @Description 邮件发送 3 | * 调用方法:sendMail('1747128171@qq.com','这是测试邮件', 'Hi 少年,这是一封测试邮件'); 4 | */ 5 | 6 | let nodemailer = require('nodemailer'); 7 | // let smtpTransport = require('nodemailer-smtp-transport'); 8 | 9 | const fs = require('fs'); 10 | const path = require('path'); 11 | const child_process = require('child_process'); 12 | 13 | 14 | var config = { 15 | email: { 16 | service: 'qq', 17 | fromname: '"ideawall 创意者桌面" ', 18 | user: 'noreply@16inet.com', 19 | pass: 'eabqosixlvujbjag', 20 | } 21 | }; 22 | 23 | function createTransporter(user) { 24 | return nodemailer.createTransport({ 25 | service: config.email.service, 26 | secure: true, // 使用 SSL 27 | port: 465, // SMTP 端口 28 | secureConnection: true, // 使用了 SSL 29 | auth: { 30 | user: config.email.user, 31 | pass: config.email.pass 32 | }, 33 | // sendmail: true, 34 | // newline: 'windows', 35 | logger: true, 36 | }); 37 | } 38 | 39 | /** 40 | * @param {Object} re 邮件信息 41 | * recipient 收件人 42 | * subject 发送的主题 43 | * text 发送的text内容 44 | * html 发送的html内容 45 | * htmlFilePath 发送的html文件路径(相对于根目录) 三者优先级, 从上往下, 越来越大. => html 有值 -> 无视 text; htmlFilePath 有值 -> 无视 text 和 html. 46 | * attachments 附件集合 => 格式: 47 | * attachments: [ 48 | * { 49 | * filename: 'text.txt',//文件名 50 | * content: 'Hello World!',//文件内容, 你 51 | * contentType: 'text/plain',//文件 MediaType 类型 52 | * 53 | * path: __dirname + '/assets/nyan.gif',//通过 path 指定文件, 不再需要 content 和 contentType. 54 | * 55 | * content: Buffer.from( 56 | * 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/' + 57 | * '//+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4U' + 58 | * 'g9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC', 59 | * 'base64' 60 | * ),//通过输入流来指定, 不再需要 contentType和 path. 61 | * 62 | * cid: 'note@example.com',//一般为邮箱, 官方描述为: 尽可能唯一的标识. 作用未知. 通过 content 和 contentType 声明的附件可忽略该参数, 其余情况, 建议加上. 63 | * }, 64 | * ... 65 | * ] 66 | * @param {String} callback 发送的html文件路径(相对于根目录) 67 | */ 68 | function sendMail(re) { 69 | return new Promise((resolve, reject) => { 70 | const transporter = createTransporter(); 71 | var mailOptions = { 72 | from: config.email.fromname, 73 | to: re.recipient, 74 | subject: re.subject, 75 | text: re.text 76 | }; 77 | if (re.html) { 78 | mailOptions.html = re.html; 79 | if (re.htmlFilePath) { 80 | mailOptions.html = fs.createReadStream(path.resolve(__dirname, re.htmlFilePath)); 81 | } 82 | } 83 | if (re.attachments && re.attachments.length > 0) { 84 | mailOptions.attachments = re.attachments; 85 | } 86 | transporter.sendMail(mailOptions, function (err, info) { 87 | if (err) { 88 | console.log(err); 89 | reject(err) 90 | } else { 91 | console.log('发送成功'); 92 | resolve(); 93 | } 94 | }) 95 | }) 96 | } 97 | 98 | module.exports = { 99 | sendMail 100 | }; 101 | 102 | -------------------------------------------------------------------------------- /app/resolver/UUIDResolver.js: -------------------------------------------------------------------------------- 1 | const child_process = require('child_process'); 2 | const uuid = require('../core/UUID')(); 3 | 4 | //支持的进程参数列表 5 | let processArguments = { 6 | 'serial': false, //默认算法 7 | 'v1': false, // v1 算法 8 | }; 9 | 10 | /** 11 | * 获取执行进程参数 12 | */ 13 | function getArguments() { 14 | var processarg = process.argv.splice(2); 15 | processarg.forEach(function (val, index, array) { 16 | if (val.startsWith('--')) { 17 | processArguments[val.replace('--', '')] = true; 18 | } 19 | }); 20 | console.log('process arguments:', processarg + '\n'); //输出数组 21 | } 22 | 23 | /** 24 | * 主入口 25 | */ 26 | function main(){ 27 | getArguments(); 28 | if(processArguments['v1']){ 29 | console.log(uuid.v1()); 30 | }else{ 31 | console.log(uuid.id); 32 | } 33 | } 34 | main(); -------------------------------------------------------------------------------- /app/service/BaseService.js: -------------------------------------------------------------------------------- 1 | const logger = require('../core/Logger');//日志模块 2 | const config = require('../core/Config');//配置模块 3 | 4 | //基础服务类 5 | function BaseService() { 6 | if (!(this instanceof BaseService)) { 7 | return new BaseService(); 8 | } 9 | 10 | this.logger = logger; 11 | this.config = config; 12 | } 13 | 14 | module.exports = { BaseService } -------------------------------------------------------------------------------- /app/service/MenuService.js: -------------------------------------------------------------------------------- 1 | const logger = require('../common/Logger');//日志模块 2 | var template = require('art-template'); 3 | 4 | setMenu(); 5 | 6 | function setMenu() { 7 | var menu_template = 8 | '
  • ' + 9 | ' ' + 10 | ' ' + 11 | ' Demo' + 12 | ' ' + 13 | '
  • ' + 14 | '
  • ' + 15 | ' ' + 16 | ' ' + 17 | ' ' + 18 | ' ' + 19 | ' 一级菜单' + 20 | ' ' + 21 | ' ' + 22 | ' ' + 36 | '
  • '; 37 | 38 | var render = template.compile(menu_template); 39 | var html = render(); 40 | document.getElementsByClassName('sidebar-menu')[0].innerHTML = html; 41 | logger.info("[Service][MenuService-setMenu]渲染菜单"); 42 | } 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /app/service/StatusService.js: -------------------------------------------------------------------------------- 1 | const logger = require('../core/Logger');//日志模块 2 | var remote = require('electron').remote;//electron的remote模块,用于调用主进程中的对象 3 | 4 | /** 5 | * 设置状态 6 | * @param {string} name 状态名 7 | * @param {any} value 状态值 8 | */ 9 | function setStatus(name, value) { 10 | logger.info("[Service][StatusService-setStatus]设置状态 " + name + " " + value); 11 | let statusMap = remote.getGlobal('sharedStatus').statusMap;//通过remote获取全局sharedStatus对象中的statusMap作为本地的map类型变量 12 | statusMap.set(name, value);//map的set方法 13 | remote.getGlobal('sharedStatus').statusMap = statusMap;//通过remote写回全局sharedStatus对象 14 | } 15 | 16 | /** 17 | * 获取状态 18 | * @param {string} name 状态名 19 | * @return {any|string} 有则返回map中的对象,无则返回空串 20 | */ 21 | function getStatus(name) { 22 | logger.info("[Service][StatusService-getStatus]获取状态 " + name); 23 | let statusMap = remote.getGlobal('sharedStatus').statusMap;//通过remote获取全局sharedStatus对象中的statusMap作为本地的map类型变量 24 | if (statusMap.has(name)) {//判断是否有此类型 25 | logger.info("获取状态 " + name + " 值 " + statusMap.get(name)); 26 | return statusMap.get(name);//有则返回 27 | } else { 28 | return "";//无则返回空字符串 29 | } 30 | } 31 | 32 | module.exports = { 33 | setStatus, 34 | getStatus 35 | } -------------------------------------------------------------------------------- /app/static/icon/128.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/static/icon/128.icns -------------------------------------------------------------------------------- /app/static/icon/128.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/static/icon/128.ico -------------------------------------------------------------------------------- /app/static/icon/256.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/static/icon/256.ico -------------------------------------------------------------------------------- /app/static/icon/512.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/static/icon/512.ico -------------------------------------------------------------------------------- /app/static/icon/64.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/static/icon/64.ico -------------------------------------------------------------------------------- /app/static/logo/logo-blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/static/logo/logo-blue.png -------------------------------------------------------------------------------- /app/static/logo/logo-blue_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/static/logo/logo-blue_128.png -------------------------------------------------------------------------------- /app/static/logo/logo-blue_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/static/logo/logo-blue_256.png -------------------------------------------------------------------------------- /app/static/logo/logo-blue_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/static/logo/logo-blue_64.png -------------------------------------------------------------------------------- /app/static/logo/logo-blue_64@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/static/logo/logo-blue_64@3x.png -------------------------------------------------------------------------------- /app/static/logo/logo-jb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/static/logo/logo-jb.png -------------------------------------------------------------------------------- /app/static/tray/100x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/static/tray/100x100.png -------------------------------------------------------------------------------- /app/static/tray/100x100@5x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/static/tray/100x100@5x.png -------------------------------------------------------------------------------- /app/static/tray/16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/static/tray/16x16.png -------------------------------------------------------------------------------- /app/static/tray/200x200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/static/tray/200x200.png -------------------------------------------------------------------------------- /app/static/tray/32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/static/tray/32x32.png -------------------------------------------------------------------------------- /app/static/tray/48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/static/tray/48x48.png -------------------------------------------------------------------------------- /app/static/tray/64x64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/static/tray/64x64.png -------------------------------------------------------------------------------- /app/task/UpdateTask.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkneoc/ideawall/55512575c70548330f6ca5ba82f64b18acaca178/app/task/UpdateTask.js -------------------------------------------------------------------------------- /app/test/test.js: -------------------------------------------------------------------------------- 1 | const db = require('better-sqlite3')('data/iw.db'); 2 | 3 | db.prepare("insert into iw_devicedesk (dd_display_id, dd_display_rp, dd_display_info) VALUES (?,?,?)") 4 | .run('1346467', '1314646', '000'); 5 | const row = db.prepare('SELECT * FROM iw_devicedesk WHERE dd_display_id=?').get('1346467'); 6 | console.log(row); 7 | 8 | 9 | // sqlite 可以存放json数据 10 | // sqlite数据库中不支持布尔型。 11 | // SQLite将数据值的存储划分为以下几种存储类型: 12 | // NULL: 表示该值为NULL值。 13 | // INTEGER: 无符号整型值。 14 | // REAL: 浮点值。 15 | // TEXT: 文本字符串,存储使用的编码方式为UTF-8、UTF-16BE、UTF-16LE。 16 | // BLOB: 存储Blob数据,该类型数据和输入数据完全相同。 -------------------------------------------------------------------------------- /app/third/Share.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author troy 3 | * @date 2019/2/4 1:48 AM 4 | * @description 社会化分享 5 | * @param 6 | * @return 7 | */ 8 | var Share = function (appVar) { 9 | 10 | this.template = { 11 | qzone: "http://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?url={{URL}}&title={{TITLE}}&desc={{DESCRIPTION}}&summary={{SUMMARY}}&site={{SOURCE}}&pics={{IMAGE}}", 12 | qq: 'http://connect.qq.com/widget/shareqq/index.html?url={{URL}}&title={{TITLE}}&source={{SOURCE}}&desc={{DESCRIPTION}}&pics={{IMAGE}}&summary="{{SUMMARY}}"', 13 | weibo: "https://service.weibo.com/share/share.php?url={{URL}}&title={{TITLE}}&pic={{IMAGE}}&appkey={{WEIBOKEY}}", 14 | wechat: "javascript:void(0)", 15 | douban: "http://shuo.douban.com/!service/share?href={{URL}}&name={{TITLE}}&text={{DESCRIPTION}}&image={{IMAGE}}&starid=0&aid=0&style=11", 16 | linkedin: "http://www.linkedin.com/shareArticle?mini=true&ro=true&title={{TITLE}}&url={{URL}}&summary={{SUMMARY}}&source={{SOURCE}}&armin=armin", 17 | facebook: "https://www.facebook.com/sharer/sharer.php?u={{URL}}", 18 | twitter: "https://twitter.com/intent/tweet?text={{TITLE}}&url={{URL}}&via={{ORIGIN}}", 19 | google: "https://plus.google.com/share?url={{URL}}" 20 | }; 21 | 22 | this.$socialconfig = { 23 | url: appVar._siteurl, 24 | source: appVar._appname, 25 | title: appVar._appname + '. 重新定义桌面, 极致就是艺术.', // 标题,默认读取 document.title 或者 26 | description: '我给你推荐了一个超酷的动态桌面壁纸软件, 快来试试吧~~ ', 27 | image: 'http://m.cdn.ideanote.16inet.com/blue-min-pretty.png', // 图片, 默认取网页中第一个img标签 28 | origin: '', // 分享 @ 相关 twitter 账号 29 | sites: ['weibo', 'qq', 'wechat', 'qzone'], // 启用的站点 30 | disabled: ['douban', 'google', 'linkedin', 'facebook', 'twitter'], // 禁用的站点 31 | wechatQrcodeTitle: '微信扫一扫:分享', // 微信二维码提示文字 32 | wechatQrcodeHelper: '

    微信里点“发现”,扫一下

    二维码便可将本文分享至朋友圈。

    ', 33 | wechatQrcodeSize: 100, 34 | 35 | summary: '', 36 | weibokey: '', 37 | }; 38 | 39 | this.wechatQrCode = undefined; 40 | 41 | /** 42 | * 初始化控制器 43 | */ 44 | this.init = function () { 45 | }; 46 | 47 | /** 48 | * 仅获取链接 49 | */ 50 | this.getLink = function (key, config) { 51 | if (this.template[key]) { 52 | var link = this.template[key]; 53 | for (var x in this.$socialconfig) { 54 | var regx = '/{{' + x.toUpperCase() + '}}/g'; 55 | if (config && config.hasOwnProperty(x)) { 56 | link = link.replace(eval(regx), config[x]); 57 | } else { 58 | link = link.replace(eval(regx), this.$socialconfig[x]); 59 | } 60 | } 61 | console.log('分享链接: ' + link); 62 | return link; 63 | } 64 | return false; 65 | }; 66 | 67 | this.init();//自动初始化 68 | }; 69 | 70 | module.exports = (appVar) => { 71 | return new Share(appVar); 72 | }; -------------------------------------------------------------------------------- /app/util/VerifyCodeUtil.js: -------------------------------------------------------------------------------- 1 | var verifyCodenums = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0", 2 | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 3 | 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' 4 | ]; 5 | var verifyCodestr = ''; 6 | var verVals = []; 7 | 8 | // 绘制验证码 9 | function drawCode(verifyCodestr, eleid) { 10 | var canvas = document.getElementById(eleid + '-canvas'); //获取HTML端画布 11 | var context = canvas.getContext("2d"); //获取画布2D上下文 12 | context.fillStyle = "cornflowerblue"; //画布填充色 13 | context.fillRect(0, 0, canvas.width, canvas.height); //清空画布 14 | context.fillStyle = "white"; //设置字体颜色 15 | context.font = "25px Arial"; //设置字体 16 | var rand = new Array(); 17 | var x = new Array(); 18 | var y = new Array(); 19 | for (var i = 0; i < 4; i++) { 20 | rand.push(rand[i]); 21 | rand[i] = verifyCodenums[Math.floor(Math.random() * verifyCodenums.length)]; 22 | x[i] = i * 20 + 10; 23 | y[i] = Math.random() * 20 + 20; 24 | context.fillText(rand[i], x[i], y[i]); 25 | } 26 | verifyCodestr = rand.join('').toUpperCase(); 27 | //画3条随机线 28 | for (var i = 0; i < 3; i++) { 29 | drawline(canvas, context); 30 | } 31 | 32 | // 画30个随机点 33 | for (var i = 0; i < 30; i++) { 34 | drawDot(canvas, context); 35 | } 36 | convertCanvasToImage(canvas, eleid); 37 | return verifyCodestr; 38 | } 39 | 40 | // 随机线 41 | function drawline(canvas, context) { 42 | context.moveTo(Math.floor(Math.random() * canvas.width), Math.floor(Math.random() * canvas.height)); //随机线的起点x坐标是画布x坐标0位置,y坐标是画布高度的随机数 43 | context.lineTo(Math.floor(Math.random() * canvas.width), Math.floor(Math.random() * canvas.height)); //随机线的终点x坐标是画布宽度,y坐标是画布高度的随机数 44 | context.lineWidth = 0.5; //随机线宽 45 | context.strokeStyle = 'rgba(50,50,50,0.3)'; //随机线描边属性 46 | context.stroke(); //描边,即起点描到终点 47 | } 48 | 49 | // 随机点(所谓画点其实就是画1px像素的线,方法不再赘述) 50 | function drawDot(canvas, context) { 51 | var px = Math.floor(Math.random() * canvas.width); 52 | var py = Math.floor(Math.random() * canvas.height); 53 | context.moveTo(px, py); 54 | context.lineTo(px + 1, py + 1); 55 | context.lineWidth = 0.2; 56 | context.stroke(); 57 | 58 | } 59 | 60 | // 绘制图片 61 | function convertCanvasToImage(canvas, eleid) { 62 | $('#' + eleid + '-canvas').hide(); 63 | var image = $('#' + eleid).children('img'); 64 | image.attr('src', canvas.toDataURL("image/png")); 65 | return image; 66 | } 67 | 68 | // 点击div刷新 69 | function resetVerifyCode(eleid) { 70 | var width = $('#' + eleid).width(); 71 | var height = $('#' + eleid).height(); 72 | $('#' + eleid).children('canvas').remove(); 73 | $('#' + eleid).children('img').before('') 74 | var verVal = drawCode('', eleid); 75 | getVerifyCode(eleid, verVal); 76 | } 77 | 78 | //查询验证码 79 | function getVerifyCode(id, newcode) { 80 | for (var x in verVals) { 81 | if (verVals[x].id === id) { 82 | if (newcode) { 83 | verVals[x].code = newcode; 84 | } else { 85 | return verVals[x].code; 86 | } 87 | } 88 | } 89 | } 90 | 91 | //渲染验证码控件 92 | function renderVerifyCode(seletor) { 93 | var drawDiv = $(seletor); 94 | drawDiv.each(function () { 95 | $(this).html('\n' + 96 | ' '); 97 | var code = drawCode('', $(this).attr('id')); 98 | var id = $(this).attr('id'); 99 | verVals.push({'id': id, 'code': code}); 100 | }); 101 | 102 | drawDiv.on('click', function () { 103 | resetVerifyCode($(this).attr('id')); 104 | }) 105 | } 106 | 107 | $(function () { 108 | renderVerifyCode('.zxx_verifycode_draw');//默认控件类名 109 | }); -------------------------------------------------------------------------------- /app/view/components/About.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
    16 |
    17 |
    18 | 19 |
    20 |
    21 |

    {{proxy.appVar._appname}}

    22 |

    Version {{proxy.appVar._version_show}}

    23 | 24 |

    Privacy Policy: {{proxy.appVar._siteurl}}privacy

    25 |

    Terms of Use: {{proxy.appVar._siteurl}}terms

    26 | 27 |

    Copyright © 2019 inetech.com. All rights reserved.

    28 |
    29 |
    30 |
    31 | 访问 ideawall 官网 32 |
    33 |
    34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /app/view/components/Browser.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
    14 | 16 |
    17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/view/components/JsonEditor.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | [参数编辑器] - ideawall 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
    18 |
    19 |
    20 | 21 |
    22 |
    23 |
    24 |
    25 |
    26 |
    27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /app/view/components/Preview.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | [预览桌面] - ideawall 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
    16 |
    17 |
    18 | 19 |
    20 |
    21 |
    22 |
    23 | 24 |
    {{wallaperEmptyTip}}
    25 |
    26 |
    27 | 31 |
    32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /app/view/components/Protector.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
    16 |
    17 |
    18 | 19 |
    {{proxy.appVar._appname}}
    20 |
    21 |
    22 |
    23 |
    24 | 25 |
    {{wallaperTip}}
    26 |
    27 |
    28 | 32 |
    33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /app/view/components/Readme.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | [README] - ideawall 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
    16 |
    17 |
    18 | 19 |
    20 |
    21 | 25 |
    26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /app/view/components/Wall.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
    16 |
    17 |
    18 | 19 |
    {{proxy.appVar._appname}}
    20 |
    21 |
    22 |
    23 |
    24 | 25 |
    {{wallaperTip}}
    26 |
    27 |
    28 | 32 |
    33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /app/view/components/control/DeskStore.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
    15 | 19 |
    20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /app/view/components/control/ResBBS.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
    15 | 17 |
    18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/view/components/control/mydesk/Comment.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
    14 | 17 |
    18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/view/components/control/mydesk/Info.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
    14 |
    15 | 16 | 17 | 20 |
    21 |
    22 |
    23 |
    24 |
    25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /app/view/components/wall/Page.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
    15 | 17 |
    18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/view/components/wall/Picture.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
    15 | 27 | 28 | 29 | 30 |
    31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /app/view/components/wall/Video.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
    15 | 16 |
    17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/view/errors/building.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 31 | 32 | 33 | 34 |
    35 |
    36 | 37 |
    38 | 此页建设维护中... 39 |
    40 |
    41 |
    42 | 43 | 44 | 45 | 46 | 47 | 74 | 75 | -------------------------------------------------------------------------------- /app/view/modal/Share.Modal.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
    13 |
    14 |
    15 |
    16 | ... 17 |
    18 |
    19 |
    20 |
    22 | 23 |
    24 |
    25 |
    26 |
    27 |
    28 |
    29 | 33 | 36 |
    37 |
    38 |
    39 |
    40 |
    41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 73 | 74 | -------------------------------------------------------------------------------- /init.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 用于跨平台初始化一张 package.json 3 | */ 4 | const path = require('path'); 5 | const fs = require('fs'); 6 | 7 | //支持的进程参数列表 8 | let processArguments = { 9 | 'f': false, //强制覆盖 10 | }; 11 | 12 | //获取执行进程参数 13 | function getArguments() { 14 | var processarg = process.argv.splice(2); 15 | processarg.forEach(function (val, index, array) { 16 | if (val.startsWith('--')) { 17 | processArguments[val.replace('--', '')] = true; 18 | } 19 | }); 20 | console.log('process arguments:', processarg + '\n'); //输出数组 21 | } 22 | 23 | const packageWin32 = path.join(__dirname, './package-win32.json'); 24 | const packageWin32App = path.join(__dirname, './package-win32-app.json'); 25 | const packageMacos = path.join(__dirname, './package-macos.json'); 26 | const packageMacosApp = path.join(__dirname, './package-macos-app.json'); 27 | const targetPackage = path.join(__dirname, './package.json'); 28 | const targetPackageApp = path.join(__dirname, './app/package.json'); 29 | 30 | let readStream, readStreamApp; 31 | getArguments(); 32 | 33 | if (process.platform !== 'darwin') { 34 | if (!fs.existsSync(targetPackage) || !fs.existsSync(targetPackageApp) || processArguments['f']) { 35 | readStream = fs.createReadStream(packageWin32); 36 | readStreamApp = fs.createReadStream(packageWin32App); 37 | } 38 | } else { 39 | if (!fs.existsSync(targetPackage) || !fs.existsSync(targetPackageApp) || processArguments['f']) { 40 | readStream = fs.createReadStream(packageMacos); 41 | readStreamApp = fs.createReadStream(packageMacosApp); 42 | } 43 | } 44 | 45 | if (readStream) { 46 | var writeStream = fs.createWriteStream(targetPackage); 47 | readStream.pipe(writeStream); 48 | } 49 | 50 | if (readStreamApp) { 51 | var writeStreamApp = fs.createWriteStream(targetPackageApp); 52 | readStreamApp.pipe(writeStreamApp); 53 | } -------------------------------------------------------------------------------- /package-macos-app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ideawall", 3 | "author": "周曦 <1747128171@qq.com>", 4 | "version": "1.2.1", 5 | "description": "ideawall - 创意者桌面 [MacOs 版]", 6 | "private": true, 7 | "license": "", 8 | "main": "App.js", 9 | "scripts": { 10 | "start": "electron .", 11 | "debug": "electron . --debug", 12 | "rebuild": "cnpm rebuild -f --runtime=electron --target=5.0.4 --disturl=https://npm.taobao.org/mirrors/atom-shell --abi=72", 13 | "clean": "yarn autoclean -I && yarn autoclean -F", 14 | "mail": "node resolver/MailResolver.js", 15 | "archive": "node resolver/ArchiverResolver.js", 16 | "uuid": "node resolver/UUIDResolver.js --serial --v1", 17 | "test": "node test/test.js" 18 | }, 19 | "engines": { 20 | "node": ">= 6.0.0" 21 | }, 22 | "devDependencies": { 23 | }, 24 | "dependencies": { 25 | "electron-updater": "^4.0.12", 26 | "mousetrap": "^1.6.3", 27 | "archiver": "^3.0.0", 28 | "async": "^2.6.1", 29 | "auto-launch": "^5.0.5", 30 | "better-sqlite3": "^5.4.0", 31 | "log4js": "^3.0.6", 32 | "nodemailer": "^6.2.1", 33 | "nodemailer-smtp-transport": "^2.7.4", 34 | "unirest": "^0.5.1", 35 | "request": "^2.87.0", 36 | "unzip": "^0.1.11", 37 | "uuid": "^3.3.2" 38 | }, 39 | "__npminstall_done": false 40 | } 41 | -------------------------------------------------------------------------------- /package-macos.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ideawall", 3 | "author": "周曦 <1747128171@qq.com>", 4 | "version": "1.2.1", 5 | "description": "ideawall - 创意者桌面 [MacOs 版]", 6 | "private": true, 7 | "license": "", 8 | "main": "app/App.js", 9 | "scripts": { 10 | "init": "node init.js --f", 11 | "start": "electron .", 12 | "debug": "electron . --debug", 13 | "postinstall": "electron-builder install-app-deps", 14 | "clean": "yarn autoclean -I && yarn autoclean -F", 15 | "build": "npm run rebuild && npm run dist", 16 | "dist": "electron-builder", 17 | "dist:dir": "electron-builder --dir", 18 | "dist:all": "electron-builder --platform=all", 19 | "dist:l": "electron-builder --linux --ia32 --x64", 20 | "dist:l32": "electron-builder --linux --ia32", 21 | "dist:l64": "electron-builder --linux --x64", 22 | "dist:w": "electron-builder --win --ia32 --x64", 23 | "dist:w32": "electron-builder --win --ia32", 24 | "dist:w64": "electron-builder --win --x64", 25 | "dist:mac": "export CSC_IDENTITY_AUTO_DISCOVERY=false && electron-builder --mac --x64", 26 | "rebuild": "cnpm rebuild -f --runtime=electron --target=5.0.4 --disturl=https://npm.taobao.org/mirrors/atom-shell --abi=72", 27 | "mail": "node app/resolver/MailResolver.js", 28 | "archive": "node app/resolver/ArchiverResolver.js", 29 | "uuid": "node app/resolver/UUIDResolver.js --serial --v1", 30 | "test": "node app/test/test.js" 31 | }, 32 | "keywords": [ 33 | "ideawall", 34 | "electron", 35 | "wall", 36 | "desktop" 37 | ], 38 | "build": { 39 | "compression": "maximum", 40 | "electronDownload": { 41 | "mirror": "https://npm.taobao.org/mirrors/electron/" 42 | }, 43 | "appId": "com.inetech.leo.ideawall", 44 | "productName": "ideawall", 45 | "copyright": "16inet.com", 46 | "directories": { 47 | "output": "build/mac/" 48 | }, 49 | "files": [ 50 | "**" 51 | ], 52 | "asar": true, 53 | "asarUnpack": [], 54 | "nsis": { 55 | "artifactName": "${name}_${version}_${os}${arch}.${ext}", 56 | "uninstallDisplayName": "${name}_${version}_${os}${arch}.${ext}", 57 | "shortcutName": "ideawall", 58 | "allowElevation": true, 59 | "runAfterFinish": true, 60 | "deleteAppDataOnUninstall": true, 61 | "allowToChangeInstallationDirectory": true, 62 | "oneClick": false, 63 | "installerLanguages": "zh_CN", 64 | "language": 2052, 65 | "perMachine": false, 66 | "createDesktopShortcut": true, 67 | "createStartMenuShortcut": true, 68 | "installerIcon": "app/static/icon/256.ico", 69 | "uninstallerIcon": "app/static/icon/256.ico", 70 | "installerHeaderIcon": "app/static/icon/256.ico" 71 | }, 72 | "linux": { 73 | "target": [ 74 | "tar.gz", 75 | "appImage", 76 | "deb" 77 | ], 78 | "icon": "app/static/icon/256.ico" 79 | }, 80 | "win": { 81 | "target": "nsis", 82 | "icon": "app/static/icon/128.ico" 83 | }, 84 | "dmg": { 85 | "contents": [ 86 | { 87 | "x": 410, 88 | "y": 150, 89 | "type": "link", 90 | "path": "/Applications" 91 | }, 92 | { 93 | "x": 130, 94 | "y": 150, 95 | "type": "file" 96 | } 97 | ] 98 | }, 99 | "mac": { 100 | "icon": "app/static/icon/256.icns" 101 | }, 102 | "publish": [ 103 | { 104 | "provider": "generic", 105 | "url": "http://update.iw.16inet.com/" 106 | } 107 | ] 108 | }, 109 | "engines": { 110 | "node": ">= 6.0.0" 111 | }, 112 | "devDependencies": { 113 | "electron": "^5.0.4", 114 | "electron-rebuild": "^1.8.5", 115 | "electron-packager": "^14.0.0", 116 | "electron-builder": "^20.44.4", 117 | "electron-prebuilt": "^1.4.13" 118 | }, 119 | "dependencies": { 120 | }, 121 | "__npminstall_done": false 122 | } 123 | -------------------------------------------------------------------------------- /package-win32-app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ideawall", 3 | "author": "周曦 <1747128171@qq.com>", 4 | "version": "1.2.1", 5 | "description": "ideawall - 创意者桌面 [Window 版]", 6 | "private": true, 7 | "license": "", 8 | "main": "App.js", 9 | "scripts": { 10 | "start": "electron .", 11 | "debug": "electron . --debug", 12 | "rebuild": "cnpm rebuild -f --runtime=electron --target=5.0.4 --disturl=https://npm.taobao.org/mirrors/atom-shell --abi=72", 13 | "clean": "yarn autoclean -I && yarn autoclean -F", 14 | "mail": "node resolver/MailResolver.js", 15 | "archive": "node resolver/ArchiverResolver.js", 16 | "uuid": "node resolver/UUIDResolver.js --serial --v1", 17 | "test": "node test/test.js" 18 | }, 19 | "engines": { 20 | "node": ">= 6.0.0" 21 | }, 22 | "devDependencies": { 23 | }, 24 | "dependencies": { 25 | "archiver": "^3.0.0", 26 | "async": "^2.6.1", 27 | "auto-launch": "^5.0.5", 28 | "better-sqlite3": "^5.4.0", 29 | "electron-updater": "^4.0.12", 30 | "electron-wallpaper": "^0.0.3", 31 | "mousetrap": "^1.6.3", 32 | "log4js": "^3.0.6", 33 | "nodemailer": "^6.2.1", 34 | "nodemailer-smtp-transport": "^2.7.4", 35 | "screenshot-desktop": "^1.8.0", 36 | "unirest": "^0.5.1", 37 | "request": "^2.87.0", 38 | "unzip": "^0.1.11", 39 | "uuid": "^3.3.2" 40 | }, 41 | "__npminstall_done": false 42 | } 43 | -------------------------------------------------------------------------------- /package-win32.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ideawall", 3 | "author": "周曦 <1747128171@qq.com>", 4 | "version": "1.2.1", 5 | "description": "ideawall - 创意者桌面 [Window 版]", 6 | "private": true, 7 | "license": "", 8 | "main": "app/App.js", 9 | "scripts": { 10 | "init": "node init.js --f", 11 | "start": "electron .", 12 | "debug": "electron . --debug", 13 | "postinstall": "electron-builder install-app-deps", 14 | "clean": "yarn autoclean -I && yarn autoclean -F", 15 | "build": "npm run rebuild && npm run dist", 16 | "dist": "electron-builder", 17 | "dist:dir": "electron-builder --dir", 18 | "dist:all": "electron-builder --platform=all", 19 | "dist:l": "electron-builder --linux --ia32 --x64", 20 | "dist:l32": "electron-builder --linux --ia32", 21 | "dist:l64": "electron-builder --linux --x64", 22 | "dist:w": "electron-builder --win --ia32 --x64", 23 | "dist:w32": "electron-builder --win --ia32", 24 | "dist:w64": "electron-builder --win --x64", 25 | "dist:mac": "export CSC_IDENTITY_AUTO_DISCOVERY=false && electron-builder --mac --x64", 26 | "rebuild": "cnpm rebuild -f --runtime=electron --target=5.0.4 --disturl=https://npm.taobao.org/mirrors/atom-shell --abi=72", 27 | "mail": "node app/resolver/MailResolver.js", 28 | "archive": "node app/resolver/ArchiverResolver.js", 29 | "uuid": "node app/resolver/UUIDResolver.js --serial --v1", 30 | "test": "node app/test/test.js" 31 | }, 32 | "keywords": [ 33 | "ideawall", 34 | "electron", 35 | "wall", 36 | "desktop" 37 | ], 38 | "build": { 39 | "compression": "maximum", 40 | "npmRebuild": false, 41 | "electronVersion": "5.0.4", 42 | "electronDownload": { 43 | "mirror": "https://npm.taobao.org/mirrors/electron/" 44 | }, 45 | "appId": "com.inetech.leo.ideawall", 46 | "productName": "ideawall", 47 | "copyright": "16inet.com", 48 | "directories": { 49 | "output": "build/win32/" 50 | }, 51 | "files": [ 52 | "**" 53 | ], 54 | "asar": true, 55 | "asarUnpack": [], 56 | "nsis": { 57 | "artifactName": "${name}_${version}_${os}${arch}.${ext}", 58 | "uninstallDisplayName": "${name} ${version}", 59 | "shortcutName": "ideawall", 60 | "allowElevation": true, 61 | "runAfterFinish": true, 62 | "deleteAppDataOnUninstall": true, 63 | "allowToChangeInstallationDirectory": true, 64 | "oneClick": false, 65 | "installerLanguages": "zh_CN", 66 | "language": 2052, 67 | "perMachine": false, 68 | "createDesktopShortcut": true, 69 | "createStartMenuShortcut": true, 70 | "installerIcon": "app/static/icon/256.ico", 71 | "uninstallerIcon": "app/static/icon/256.ico", 72 | "installerHeaderIcon": "app/static/icon/256.ico" 73 | }, 74 | "linux": { 75 | "target": [ 76 | "tar.gz", 77 | "appImage", 78 | "deb" 79 | ], 80 | "icon": "app/static/icon/256.ico" 81 | }, 82 | "win": { 83 | "target": "nsis", 84 | "icon": "app/static/icon/256.ico" 85 | }, 86 | "dmg": { 87 | "contents": [ 88 | { 89 | "x": 410, 90 | "y": 150, 91 | "type": "link", 92 | "path": "/Applications" 93 | }, 94 | { 95 | "x": 130, 96 | "y": 150, 97 | "type": "file" 98 | } 99 | ] 100 | }, 101 | "mac": { 102 | "icon": "app/static/icon/256.icns" 103 | }, 104 | "publish": [ 105 | { 106 | "provider": "generic", 107 | "url": "http://update.iw.16inet.com/" 108 | } 109 | ] 110 | }, 111 | "engines": { 112 | "node": ">= 6.0.0" 113 | }, 114 | "devDependencies": { 115 | "electron": "^5.0.4", 116 | "electron-rebuild": "^1.8.5", 117 | "electron-packager": "^14.0.0", 118 | "electron-builder": "^20.44.4", 119 | "electron-prebuilt": "^1.4.13" 120 | }, 121 | "dependencies": { 122 | }, 123 | "__npminstall_done": false 124 | } 125 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ideawall", 3 | "author": "周曦 <1747128171@qq.com>", 4 | "version": "1.2.1", 5 | "description": "ideawall - 创意者桌面 [MacOs 版]", 6 | "private": true, 7 | "license": "", 8 | "main": "app/App.js", 9 | "scripts": { 10 | "init": "node init.js --f", 11 | "start": "electron .", 12 | "debug": "electron . --debug", 13 | "postinstall": "electron-builder install-app-deps", 14 | "clean": "yarn autoclean -I && yarn autoclean -F", 15 | "build": "npm run rebuild && npm run dist", 16 | "dist": "electron-builder", 17 | "dist:dir": "electron-builder --dir", 18 | "dist:all": "electron-builder --platform=all", 19 | "dist:l": "electron-builder --linux --ia32 --x64", 20 | "dist:l32": "electron-builder --linux --ia32", 21 | "dist:l64": "electron-builder --linux --x64", 22 | "dist:w": "electron-builder --win --ia32 --x64", 23 | "dist:w32": "electron-builder --win --ia32", 24 | "dist:w64": "electron-builder --win --x64", 25 | "dist:mac": "export CSC_IDENTITY_AUTO_DISCOVERY=false && electron-builder --mac --x64", 26 | "rebuild": "cnpm rebuild -f --runtime=electron --target=5.0.4 --disturl=https://npm.taobao.org/mirrors/atom-shell --abi=72", 27 | "mail": "node app/resolver/MailResolver.js", 28 | "archive": "node app/resolver/ArchiverResolver.js", 29 | "uuid": "node app/resolver/UUIDResolver.js --serial --v1", 30 | "test": "node app/test/test.js" 31 | }, 32 | "keywords": [ 33 | "ideawall", 34 | "electron", 35 | "wall", 36 | "desktop" 37 | ], 38 | "build": { 39 | "compression": "maximum", 40 | "electronDownload": { 41 | "mirror": "https://npm.taobao.org/mirrors/electron/" 42 | }, 43 | "appId": "com.inetech.leo.ideawall", 44 | "productName": "ideawall", 45 | "copyright": "16inet.com", 46 | "directories": { 47 | "output": "build/mac/" 48 | }, 49 | "files": [ 50 | "**" 51 | ], 52 | "asar": true, 53 | "asarUnpack": [], 54 | "nsis": { 55 | "artifactName": "${name}_${version}_${os}${arch}.${ext}", 56 | "uninstallDisplayName": "${name}_${version}_${os}${arch}.${ext}", 57 | "shortcutName": "ideawall", 58 | "allowElevation": true, 59 | "runAfterFinish": true, 60 | "deleteAppDataOnUninstall": true, 61 | "allowToChangeInstallationDirectory": true, 62 | "oneClick": false, 63 | "installerLanguages": "zh_CN", 64 | "language": 2052, 65 | "perMachine": false, 66 | "createDesktopShortcut": true, 67 | "createStartMenuShortcut": true, 68 | "installerIcon": "app/static/icon/256.ico", 69 | "uninstallerIcon": "app/static/icon/256.ico", 70 | "installerHeaderIcon": "app/static/icon/256.ico" 71 | }, 72 | "linux": { 73 | "target": [ 74 | "tar.gz", 75 | "appImage", 76 | "deb" 77 | ], 78 | "icon": "app/static/icon/256.ico" 79 | }, 80 | "win": { 81 | "target": "nsis", 82 | "icon": "app/static/icon/256.ico" 83 | }, 84 | "dmg": { 85 | "contents": [ 86 | { 87 | "x": 410, 88 | "y": 150, 89 | "type": "link", 90 | "path": "/Applications" 91 | }, 92 | { 93 | "x": 130, 94 | "y": 150, 95 | "type": "file" 96 | } 97 | ] 98 | }, 99 | "mac": { 100 | "icon": "app/static/icon/128.icns" 101 | }, 102 | "publish": [ 103 | { 104 | "provider": "generic", 105 | "url": "http://update.iw.16inet.com/" 106 | } 107 | ] 108 | }, 109 | "engines": { 110 | "node": ">= 6.0.0" 111 | }, 112 | "devDependencies": { 113 | "electron": "^5.0.4", 114 | "electron-rebuild": "^1.8.5", 115 | "electron-packager": "^14.0.0", 116 | "electron-builder": "^20.44.4", 117 | "electron-prebuilt": "^1.4.13" 118 | }, 119 | "dependencies": { 120 | }, 121 | "__npminstall_done": false 122 | } 123 | --------------------------------------------------------------------------------