diff --git a/icons/128x128.png b/icons/128x128.png index 65388ea..604db54 100644 Binary files a/icons/128x128.png and b/icons/128x128.png differ diff --git a/icons/256x256.png b/icons/256x256.png index ddef713..d8c2d30 100644 Binary files a/icons/256x256.png and b/icons/256x256.png differ diff --git a/icons/512x512.png b/icons/512x512.png index dc99b79..c577e1f 100644 Binary files a/icons/512x512.png and b/icons/512x512.png differ diff --git a/icons/app.icns b/icons/app.icns index f9fdd00..c30b25e 100644 Binary files a/icons/app.icns and b/icons/app.icns differ diff --git a/icons/gaystat.psd b/icons/gaystat.psd new file mode 100644 index 0000000..78eb549 Binary files /dev/null and b/icons/gaystat.psd differ diff --git a/src/css/app.scss b/src/css/app.scss deleted file mode 100644 index 56122f9..0000000 --- a/src/css/app.scss +++ /dev/null @@ -1,138 +0,0 @@ -@charset "UTF-8"; -/** - * 应用主样式 - * @authors yutent - * @date 2018/12/16 17:15:07 - */ - -@import './var.scss'; - -html { - font-size: 12.8px; - width: 100%; - height: 100vh; -} - -body { - display: flex; - flex-direction: column; - width: 100%; - height: 100%; - padding-top: px(12); - line-height: 1.25; - font-size: px(14); - color: nth($cp, 1); - background: transparent; - // background: rgba(88, 88, 88, 0.5); -} - -.app { - position: relative; - display: flex; - flex-direction: column; - height: 100%; - padding: px(16) 0 px(6); - border-radius: px(6); - // background: rgba(88, 88, 88, 0.5); - - &::before { - position: absolute; - left: px(155); - top: px(-70); - width: px(14); - height: px(14); - border-radius: px(2); - background: linear-gradient( - to bottom right, - rgba(88, 88, 88, 0.85) 50%, - transparent 50% - ); - transform: rotate(45deg); - content: ''; - } - - .option, - .close, - .load { - position: absolute; - right: px(6); - top: px(2); - --size: #{px(14)}; - cursor: pointer; - opacity: 0; - - &:hover { - opacity: 1; - } - } - .close { - right: auto; - left: px(6); - } - .load { - right: auto; - left: px(155); - } - - .list { - flex: 1; - - .item { - display: flex; - align-items: center; - height: px(54); - padding: px(10) px(12); - line-height: px(15); - border-bottom: px(1) solid rgba(200, 200, 200, 0.1); - border-top: px(1) solid rgba(0, 0, 0, 0.1); - - &:first-child { - border-top: 0; - } - &:last-child { - border-bottom: 0; - } - - .info { - overflow: hidden; - flex: 1; - - h3 { - font-size: px(14); - } - cite { - color: nth($cp, 3); - } - } - - .last-days { - display: flex; - width: px(64); - height: px(30); - margin: 0 px(6); - } - - .today { - width: px(52); - font-size: px(12); - color: #fff; - text-align: right; - - span { - display: block; - padding: 0 px(4); - } - .percent { - border-radius: px(2); - - &.red { - background: nth($cr, 1); - } - &.green { - background: nth($cg, 3); - } - } - } - } - } -} diff --git a/src/css/float.css b/src/css/float.css new file mode 100644 index 0000000..adb80fd --- /dev/null +++ b/src/css/float.css @@ -0,0 +1 @@ +html{font-size:12.8px;width:100%;height:100vh}body{display:flex;flex-direction:column;width:100%;height:100%;line-height:1.25;font-size:14px;color:var(--color-dark-1);background:rgba(255,255,255,0.3)}.app-drag{-webkit-app-region:drag;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.app-nodrag{-webkit-app-region:no-drag}.app{position:relative;display:flex;flex-direction:column;height:100%;padding:6px 0;border-radius:6px}.app .list{flex:1}.app .list .item{display:flex;align-items:center;height:54px;padding:10px 12px;line-height:15px;border-bottom:1px solid var(--color-plain-3)}.app .list .item:last-child{border-bottom:0}.app .list .item .info{overflow:hidden;flex:1}.app .list .item .info h3{font-size:14px}.app .list .item .info cite{color:var(--color-grey-2)}.app .list .item .last-days{display:flex;width:64px;height:30px;margin:0 6px}.app .list .item .today{width:52px;font-size:12px;text-align:right}.app .list .item .today span{display:block;padding:0 4px}.app .list .item .today .percent{border-radius:2px;color:#fff}.app .list .item .today .percent.red{background:var(--color-red-1)}.app .list .item .today .percent.green{background:var(--color-green-3)} diff --git a/src/css/float.scss b/src/css/float.scss new file mode 100644 index 0000000..3d0c792 --- /dev/null +++ b/src/css/float.scss @@ -0,0 +1,98 @@ +@charset "UTF-8"; +/** + * 浮窗样式 + * @authors yutent + * @date 2018/12/16 17:15:07 + */ + +html { + font-size: 12.8px; + width: 100%; + height: 100vh; +} + +body { + display: flex; + flex-direction: column; + width: 100%; + height: 100%; + line-height: 1.25; + font-size: 14px; + color: var(--color-dark-1); + background: rgba(255, 255, 255, 0.3); +} + +.app-drag { + -webkit-app-region: drag; + user-select: none; +} +.app-nodrag { + -webkit-app-region: no-drag; +} + +.app { + position: relative; + display: flex; + flex-direction: column; + height: 100%; + padding: 6px 0; + border-radius: 6px; + + .list { + flex: 1; + + .item { + display: flex; + align-items: center; + height: 54px; + padding: 10px 12px; + line-height: 15px; + border-bottom: 1px solid var(--color-plain-3); + + &:last-child { + border-bottom: 0; + } + + .info { + overflow: hidden; + flex: 1; + + h3 { + font-size: 14px; + } + cite { + color: var(--color-grey-2); + } + } + + .last-days { + display: flex; + width: 64px; + height: 30px; + margin: 0 6px; + } + + .today { + width: 52px; + font-size: 12px; + text-align: right; + + span { + display: block; + padding: 0 4px; + } + .percent { + border-radius: 2px; + color: #fff; + + &.red { + background: var(--color-red-1); + } + &.green { + background: var(--color-green-3); + } + } + } + } + } +} diff --git a/src/css/var.scss b/src/css/var.scss deleted file mode 100644 index b16f42e..0000000 --- a/src/css/var.scss +++ /dev/null @@ -1,17 +0,0 @@ -$ct: #4db6ac #26a69a #009688; -$cg: #81c784 #66bb6a #4caf50; -$cpp: #ba68c8 #ba68c8 #9c27b0; -$cb: #64b5f6 #42a5f5 #2196f3; -$cr: #ff5061 #eb3b48 #ce3742; -$co: #ffb618 #f39c12 #e67e22; -$cp: #f2f5fc #e8ebf4 #dae1e9; -$cgr: #bdbdbd #9e9e9e #757575; -$cd: #62778d #526273 #425064; - -@mixin ts($c: all, $t: .1s, $m: ease-in-out){ - transition:$c $t $m; -} - -@function px($n: 1) { - @return ($n / 12.8) + rem; -} \ No newline at end of file diff --git a/src/float.html b/src/float.html new file mode 100644 index 0000000..65554fe --- /dev/null +++ b/src/float.html @@ -0,0 +1,38 @@ + + + + + + + + + + + + + +
+ +
+
+

+ +
+ + + +
+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/src/images/app.png b/src/images/app.png index ddef713..d8c2d30 100644 Binary files a/src/images/app.png and b/src/images/app.png differ diff --git a/src/js/float.js b/src/js/float.js new file mode 100644 index 0000000..ea8b241 --- /dev/null +++ b/src/js/float.js @@ -0,0 +1,173 @@ +/** + * + * @author yutent + * @date 2020/12/10 19:53:05 + */ + +import '/lib/anot.js' +import '/lib/form/button.js' +import '/lib/scroll/index.js' +import '/lib/canvas-draw.js' + +import layer from '/lib/layer/index.js' +import Utils from '/lib/utils.js' +import app from '/lib/socket.js' + +const log = console.log + +const $doc = Anot(document) + +function getJsonp(str) { + if (~str.indexOf('jsonpgz')) { + return new Function(`function jsonpgz(d){return d}; return ${str}`)() + } + return false +} + +function getTableData(str) { + var match = str.match(/.*?<\/tbody>/) + var table = document.createElement('table') + var list = [] + var max = 0 + var min = 99 + + table.innerHTML = match[0] + list = Array.from(table.children[0].children) + .map(it => { + let m = +it.children[2].textContent + if (m > max) { + max = m + } + if (m < min) { + min = m + } + return { m } + }) + .reverse() + + list.forEach(it => { + it.h = +(((it.m - min) * 60) / (max - min)).toFixed(2) + }) + return list +} + +Anot({ + $id: 'app', + state: { + list: [], + $dict: {} + }, + + watch: { + 'chapter.content'() { + this.calcuteWords = this.chapter.content.length + }, + currCate() { + this.renderChapterList() + } + }, + mounted() { + var watch_list = Anot.ls('watch_list') || '[]' + + watch_list = JSON.parse(watch_list) + + this.list = watch_list + + for (let it of this.list) { + this.$dict[it.code] = it + } + + app.on('float-visible', function(data) { + console.log(data) + }) + }, + methods: { + close() { + // WIN.close() + }, + getTodayStat(id) { + var res = app.dispatch( + 'fetch', + `https://fundgz.1234567.com.cn/js/${id}.js` + ) + + return getJsonp(res) + }, + + getLastMonth(id) { + var res = app.dispatch( + 'fetch', + `https://fund.eastmoney.com/f10/F10DataApi.aspx?type=lsjz&per=42&code=${id}` + ) + return getTableData(res) + }, + + addGay() { + layer + .prompt('请输入鸡精代号', (val, done) => { + if (val.trim()) { + done() + } + }) + .then(id => { + if (this.$dict[id]) { + return + } + Anot.nextTick(_ => { + var info = this.getTodayStat(id) + var last + if (info) { + last = this.getLastMonth(id) + var tmp = { + code: info.fundcode, + name: info.name, + yesterday: info.dwjz, + curr: info.gsz, + percent: +info.gszzl, + last + } + this.list.unshift(tmp) + this.$dict[tmp.code] = this.list[0] + Anot.ls('watch_list', this.list.$model) + } else { + layer.toast('鸡精不存在', 'error') + } + }) + }) + .catch(Anot.noop) + }, + + updateGay(item) { + var info = this.getTodayStat(item.code) + if (info.dwjz !== item.yesterday) { + item.yesterday = info.dwjz + item.last = this.getLastMonth(item.code) + } + item.curr = info.gsz + item.percent = +info.gszzl + }, + + removeGay(item) { + layer + .confirm(`是否移除[${item.name.slice(0, 5)}...]?`) + .then(_ => { + item.$ups.it.$remove() + delete this.$dict[item.code] + Anot.ls('watch_list', this.list.$model) + }) + .catch(Anot.noop) + }, + + updateGays() { + for (let it of this.list) { + this.updateGay(it) + } + + this.list.sort((a, b) => { + return b.percent - a.percent + }) + + Anot.ls('watch_list', this.list.$model) + } + } +}) diff --git a/src/lib/css/reset-basic.css b/src/lib/css/reset-basic.css index 75b2a0c..651aa7f 100644 --- a/src/lib/css/reset-basic.css +++ b/src/lib/css/reset-basic.css @@ -41,18 +41,38 @@ body {font-family:"Helvetica Neue", Arial,"WenQuanYi Micro Hei","PingFang SC","H code,pre,samp {font-family:Menlo,Monaco,Consolas,"Courier New",monospace;} [anot],[\:repeat],[\:if] {visibility:hidden;} -.do-fn-cl { *zoom: 1; } -.do-fn-cl::after { content: "."; display: block; height: 0; clear: both; visibility: hidden; overflow:hidden;} -.do-fn-clear {clear:both;display:inline;} - -.do-fn-show{display:block;} -.do-fn-hide{display:none;} -.do-fn-fl{float:left;} -.do-fn-fr{float:right;} -.do-fn-noselect {-webkit-touch-callout: none;-webkit-user-select: none;-moz-user-select: none;user-select: none;} -.do-fn-noselect img, .do-fn-noselect a {-webkit-user-drag:none;} -.do-fn-ell {overflow:hidden; white-space:nowrap; text-overflow:ellipsis } -.do-st-thin {-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;} -.do-st-hand {cursor:pointer;} +.noselect {-webkit-touch-callout: none;-webkit-user-select: none;-moz-user-select: none;user-select: none;} +.noselect img, .noselect a {-webkit-user-drag:none;} +.text-ell {overflow:hidden; white-space:nowrap; text-overflow:ellipsis } +.osx-thin {-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;} +:root { + --color-teal-1: #4db6ac; + --color-teal-2: #26a69a; + --color-teal-3: #009688; + --color-green-1: #81c784; + --color-green-2: #66bb6a; + --color-green-3: #4caf50; + --color-purple-1: #9575cd; + --color-purple-2: #9575cd; + --color-purple-3: #673ab7; + --color-blue-1: #64b5f6; + --color-blue-2: #42a5f5; + --color-blue-3: #2196f3; + --color-red-1: #ff5061; + --color-red-2: #eb3b48; + --color-red-3: #ce3742; + --color-orange-1: #ffb618; + --color-orange-2: #f39c12; + --color-orange-3: #e67e22; + --color-plain-1: #f2f5fc; + --color-plain-2: #e8ebf4; + --color-plain-3: #dae1e9; + --color-grey-1: #bdbdbd; + --color-grey-2: #9e9e9e; + --color-grey-3: #757575; + --color-dark-1: #62778d; + --color-dark-2: #526273; + --color-dark-3: #425064; +} \ No newline at end of file diff --git a/src/lib/socket.js b/src/lib/socket.js new file mode 100644 index 0000000..94d7918 --- /dev/null +++ b/src/lib/socket.js @@ -0,0 +1,25 @@ +/** + * 与主进程的通讯 + * @author yutent + * @date 2020/07/14 11:42:02 + */ + +const { ipcRenderer } = require('electron') +const EventEmitter = require('events') +const util = require('util') + +class Socket { + constructor() { + ipcRenderer.on('app', (ev, conn) => { + this.emit(conn.type, conn.data) + }) + } + + dispatch(type = '', data = {}) { + return ipcRenderer.sendSync('app', { data, type }) + } +} + +util.inherits(Socket, EventEmitter) + +export default new Socket() diff --git a/src/main.js b/src/main.js index 9206983..691e63f 100644 --- a/src/main.js +++ b/src/main.js @@ -8,10 +8,8 @@ const { app, BrowserWindow, protocol, ipcMain, net } = require('electron') const path = require('path') const fs = require('iofs') -const createMenu = require('./tools/menu') -const createTay = require('./tools/tray') +const { createMainWindow, createFloatWindow } = require('./tools/window') -const log = console.log const MIME_TYPES = { '.js': 'text/javascript', '.html': 'text/html', @@ -59,7 +57,7 @@ protocol.registerSchemesAsPrivileged([ /* ----------------------------------------------------- */ -app.dock.hide() +// app.dock.hide() // 初始化应用 app.once('ready', () => { @@ -72,44 +70,20 @@ app.once('ready', () => { }) // 创建浏览器窗口 - let win = new BrowserWindow({ - title: '', - width: 320, - height: 360, - resizable: false, - maximizable: false, - frame: false, - transparent: true, - hasShadow: false, - // backgroundColor: '#80585858', - // show: false, - vibrancy: 'dark', - visualEffectState: 'active', - icon: path.resolve(ROOT, './images/app.png'), - webPreferences: { - // webSecurity: false, - experimentalFeatures: true, - nodeIntegration: true, - spellcheck: false - } - }) + app.__main__ = createMainWindow(path.resolve(ROOT, './images/app.png')) + app.__float__ = createFloatWindow() - win.on('closed', () => { + app.__main__.on('closed', () => { + app.__main__ = null + app.__float__ = null app.exit() - win = null - }) - - // win.openDevTools() - - // 然后加载应用的 index.html - win.loadURL('app://local/index.html') - - createMenu(win) - createTay(win) -}) - -ipcMain.on('net', (ev, url) => { - fetch(url).then(r => { - ev.returnValue = r }) }) + +ipcMain.on('app', (ev, conn) => { + if (conn.type === 'fetch') { + fetch(conn.data).then(r => { + ev.returnValue = r + }) + } +}) diff --git a/src/tools/menu.js b/src/tools/menu.js index 4c3a1d2..5f63419 100644 --- a/src/tools/menu.js +++ b/src/tools/menu.js @@ -1,21 +1,25 @@ /** * 菜单项 - * @author yutent - * @date 2019/01/21 20:34:04 + * @author yutent + * @date 2020/12/10 19:30:02 */ -'use strict' - const { Menu } = require('electron') module.exports = function(win) { - let menuList = Menu.buildFromTemplate([ + var menuList = Menu.buildFromTemplate([ { label: '搞基数据', submenu: [ { role: 'about', label: '关于搞基数据' }, { type: 'separator' }, - { role: 'quit', label: '退出' } + { + label: '退出', + accelerator: 'Command+Q', + click(a, b, ev) { + win.destroy() + } + } ] }, { diff --git a/src/tools/tray.js b/src/tools/tray.js index 6f10d94..de08d1e 100644 --- a/src/tools/tray.js +++ b/src/tools/tray.js @@ -1,11 +1,9 @@ /** * 托盘 * @author yutent - * @date 2019/01/21 20:42:07 + * @date 2020/12/10 19:30:20 */ -'use strict' - const { Tray } = require('electron') const path = require('path') const ROOT = __dirname @@ -15,8 +13,9 @@ module.exports = function(win) { win.__TRAY__.on('click', _ => { var b = win.__TRAY__.getBounds() - win.setBounds({ x: b.x - 150, y: b.y + b.height + 4 }) + win.setBounds({ x: b.x - 145, y: b.y + b.height }) win.show() win.focus() + win.webContents.send('app', { type: 'float-visible', data: null }) }) } diff --git a/src/tools/window.js b/src/tools/window.js new file mode 100644 index 0000000..059ac1b --- /dev/null +++ b/src/tools/window.js @@ -0,0 +1,91 @@ +/** + * + * @author yutent + * @date 2020/12/10 14:57:49 + */ + +const { BrowserWindow } = require('electron') + +const createMenu = require('./menu') +const createTay = require('./tray') + +/** + * 应用主窗口 + */ +exports.createMainWindow = function(icon) { + var win = new BrowserWindow({ + title: '搞基数据', + width: 820, + height: 460, + frame: false, + titleBarStyle: 'hiddenInset', + resizable: false, + maximizable: false, + icon, + transparent: true, + vibrancy: 'hud', + visualEffectState: 'active', + webPreferences: { + // webSecurity: false, + experimentalFeatures: true, + nodeIntegration: true, + spellcheck: false + }, + show: false + }) + + // 然后加载应用的 index.html。 + + win.loadURL('app://local/index.html') + + // createAppTray(win) + // ctrlTrayBtn(win) + // createLrcTray(win) + + createMenu(win) + + // win.on('ready-to-show', _ => { + // win.show() + // win.openDevTools() + // }) + + win.on('close', ev => { + ev.preventDefault() + win.hide() + }) + + return win +} + +// 创建悬浮窗口 +exports.createFloatWindow = function() { + var win = new BrowserWindow({ + width: 320, + height: 360, + resizable: false, + maximizable: false, + frame: false, + // transparent: true, + // hasShadow: false, + show: false, + vibrancy: 'hud', + visualEffectState: 'active', + webPreferences: { + // webSecurity: false, + experimentalFeatures: true, + nodeIntegration: true, + spellcheck: false + } + }) + + // win.openDevTools() + + win.on('blur', ev => { + win.hide() + }) + + createTay(win) + win.loadURL('app://local/float.html') + + return win +}