完成2.0版
parent
e51c15db73
commit
1fb6b67fa8
|
@ -1,7 +1,9 @@
|
||||||
## 摸鱼搞基小工具
|
## 搞基爱啪啪
|
||||||
> 搞基专用, 你懂的。
|
> “搞基爱啪啪” 是一款开源的, 非专业的搞基软件, 上面的数据全来自网络, 不对准确性作任何保证.
|
||||||
|
|
||||||
|
|
||||||
|
搞基有风险, 入行需谨慎. 你亏了别找我, 赚了可以给我发红包.
|
||||||
|
|
||||||
## 编译
|
## 编译
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
@ -10,4 +12,4 @@ npm run pack
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
![preview](./preview.jpg)
|
![preview](./preview.png)
|
BIN
preview.jpg
BIN
preview.jpg
Binary file not shown.
Before Width: | Height: | Size: 38 KiB |
Binary file not shown.
After Width: | Height: | Size: 99 KiB |
|
@ -1 +1 @@
|
||||||
html{font-size:12.8px;width:100%;height:100vh}body{overflow:hidden;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;height:100%}.app .sidebar{display:flex;flex-direction:column;justify-content:space-between;width:76px;height:100%;padding:48px 22px 24px;background:var(--color-dark-1);color:var(--color-plain-1)}.app .sidebar .item{cursor:pointer}.app .sidebar .item:hover,.app .sidebar .item.active{color:var(--color-orange-1)}.app .sidebar .item:active{color:var(--color-orange-2)}.app .select-box{display:flex;flex-direction:column;width:200px;height:100%;background:rgba(255,255,255,0.5)}.app .select-box .form{display:flex;align-items:center;width:100%;height:35px;padding:0 6px;background:#fff;border-bottom:1px solid var(--color-plain-2)}.app .select-box .form wc-input{flex:1;margin-right:12px}.app .select-box .list{flex:1}.app .select-box .list .item{display:flex;flex-direction:column;justify-content:center;height:48px;padding:6px;transition:color 0.15s ease-in-out, background 0.15s ease-in-out;cursor:pointer}.app .select-box .list .item section{display:flex;justify-content:space-between;align-items:center}.app .select-box .list .item cite{color:var(--color-grey-2)}.app .select-box .list .item .percent{padding:0 4px;border-radius:2px;font-size:12px;color:#fff;background:var(--color-grey-1)}.app .select-box .list .item .percent.red{background:var(--color-red-1)}.app .select-box .list .item .percent.green{background:var(--color-green-3)}.app .select-box .list .item:hover{color:var(--color-orange-1);background:rgba(255,255,255,0.35)}.app .select-box .list .item.active{color:var(--color-orange-3);background:rgba(255,255,255,0.7)}.app .detail{flex:1;height:100%;border-left:1px solid var(--color-plain-2);background:#fff}.app .detail .title{width:100%;height:35px;padding:0 16px;line-height:35px;font-size:16px;font-weight:bold}.app .detail .card{width:96%;padding:12px 12px 16px;margin:12px 2% 24px;border:0;background:#fff;box-shadow:0 0 8px rgba(0,0,0,0.075)}.app .detail .card legend{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;color:#64b5f6}
|
html{font-size:12.8px;width:100%;height:100vh}body{overflow:hidden;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;height:100%}.app .sidebar{display:flex;flex-direction:column;justify-content:space-between;width:76px;height:100%;padding:48px 22px 24px;background:var(--color-dark-1);color:var(--color-plain-1)}.app .sidebar .item{cursor:pointer}.app .sidebar .item:hover,.app .sidebar .item.active{color:var(--color-orange-1)}.app .sidebar .item:active{color:var(--color-orange-2)}.app .select-box{display:flex;flex-direction:column;width:200px;height:100%;background:rgba(255,255,255,0.5)}.app .select-box .form{display:flex;align-items:center;width:100%;height:35px;padding:0 6px;background:#fff;border-bottom:1px solid var(--color-plain-2)}.app .select-box .form wc-input{flex:1}.app .select-box .list{flex:1}.app .select-box .list .item{display:flex;flex-direction:column;justify-content:center;height:48px;padding:6px;transition:color 0.15s ease-in-out, background 0.15s ease-in-out;cursor:pointer}.app .select-box .list .item section{display:flex;justify-content:space-between;align-items:center}.app .select-box .list .item cite{color:var(--color-grey-2)}.app .select-box .list .item .percent{padding:0 4px;border-radius:2px;font-size:12px;font-weight:bold;color:var(--color-grey-1)}.app .select-box .list .item .percent.red{color:var(--color-red-1)}.app .select-box .list .item .percent.green{color:var(--color-green-3)}.app .select-box .list .item:nth-child(odd){background:rgba(255,255,255,0.35)}.app .select-box .list .item:hover{color:var(--color-blue-1);background:rgba(255,255,255,0.35)}.app .select-box .list .item.active{color:var(--color-blue-3);background:rgba(255,255,255,0.7)}.app .detail{position:relative;flex:1;height:100%;border-left:1px solid var(--color-plain-2);background:#fff}.app .detail .title{display:flex;justify-content:space-between;align-items:center;width:100%;height:35px;padding:0 16px;font-size:16px;font-weight:bold}.app .detail .title span{display:inline-flex}.app .detail .title wc-button{margin:0 6px}.app .detail .card{width:96%;padding:12px 12px 16px;margin:12px 2% 24px;border:0;background:#fff;box-shadow:0 0 8px rgba(0,0,0,0.075)}.app .detail .card legend{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;color:#64b5f6}.app .detail.blur::after{position:absolute;left:0;top:0;z-index:999;width:100%;height:100%;content:'';background:rgba(255,255,255,0.75);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px)}.app .preferences{width:640px;height:360px;border-radius:10px}.app .preferences .titlebar{width:100%;height:72px;border-bottom:1px solid var(--color-plain-3);background:var(--color-plain-1)}.app .preferences .titlebar .title{width:100%;height:24px;line-height:24px;text-align:center}.app .preferences .titlebar nav{display:flex;width:100%;height:40px;padding:0 16px;--size: 18px}.app .preferences .titlebar nav span{display:flex;flex-direction:column;align-items:center;justify-content:center;width:52px;height:40px;margin:0 6px;border-radius:6px;font-size:12px}.app .preferences .titlebar nav span.active{background:var(--color-plain-2);color:var(--color-blue-1)}.app .preferences .titlebar nav span:hover{background:var(--color-plain-2)}.app .preferences .tab-panel{padding:64px}.app .preferences .tab-panel p{margin-bottom:16px}.app .preferences .tab-panel .field{display:flex;align-items:center;height:64px}.app .preferences .tab-panel .field .label{width:200px;color:var(--color-grey-1)}
|
||||||
|
|
110
src/css/app.scss
110
src/css/app.scss
|
@ -77,7 +77,6 @@ body {
|
||||||
|
|
||||||
wc-input {
|
wc-input {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
margin-right: 12px;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,24 +106,28 @@ body {
|
||||||
padding: 0 4px;
|
padding: 0 4px;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: #fff;
|
font-weight: bold;
|
||||||
background: var(--color-grey-1);
|
color: var(--color-grey-1);
|
||||||
|
|
||||||
&.red {
|
&.red {
|
||||||
background: var(--color-red-1);
|
color: var(--color-red-1);
|
||||||
}
|
}
|
||||||
&.green {
|
&.green {
|
||||||
background: var(--color-green-3);
|
color: var(--color-green-3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:nth-child(odd) {
|
||||||
|
background: rgba(255, 255, 255, 0.35);
|
||||||
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: var(--color-orange-1);
|
color: var(--color-blue-1);
|
||||||
background: rgba(255, 255, 255, 0.35);
|
background: rgba(255, 255, 255, 0.35);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.active {
|
&.active {
|
||||||
color: var(--color-orange-3);
|
color: var(--color-blue-3);
|
||||||
background: rgba(255, 255, 255, 0.7);
|
background: rgba(255, 255, 255, 0.7);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -132,18 +135,28 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
.detail {
|
.detail {
|
||||||
|
position: relative;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
border-left: 1px solid var(--color-plain-2);
|
border-left: 1px solid var(--color-plain-2);
|
||||||
background: #fff;
|
background: #fff;
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 35px;
|
height: 35px;
|
||||||
padding: 0 16px;
|
padding: 0 16px;
|
||||||
line-height: 35px;
|
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
|
||||||
|
span {
|
||||||
|
display: inline-flex;
|
||||||
|
}
|
||||||
|
wc-button {
|
||||||
|
margin: 0 6px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.card {
|
.card {
|
||||||
|
@ -160,5 +173,86 @@ body {
|
||||||
color: #64b5f6;
|
color: #64b5f6;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.blur {
|
||||||
|
&::after {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
z-index: 999;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
content: '';
|
||||||
|
background: rgba(255, 255, 255, 0.75);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.preferences {
|
||||||
|
width: 640px;
|
||||||
|
height: 360px;
|
||||||
|
border-radius: 10px;
|
||||||
|
|
||||||
|
.titlebar {
|
||||||
|
width: 100%;
|
||||||
|
height: 72px;
|
||||||
|
border-bottom: 1px solid var(--color-plain-3);
|
||||||
|
background: var(--color-plain-1);
|
||||||
|
|
||||||
|
.title {
|
||||||
|
width: 100%;
|
||||||
|
height: 24px;
|
||||||
|
line-height: 24px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
height: 40px;
|
||||||
|
padding: 0 16px;
|
||||||
|
|
||||||
|
span {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 52px;
|
||||||
|
height: 40px;
|
||||||
|
margin: 0 6px;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 12px;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
background: var(--color-plain-2);
|
||||||
|
color: var(--color-blue-1);
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
background: var(--color-plain-2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
--size: 18px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-panel {
|
||||||
|
padding: 64px;
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
height: 64px;
|
||||||
|
|
||||||
|
.label {
|
||||||
|
width: 200px;
|
||||||
|
color: var(--color-grey-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,17 +19,16 @@
|
||||||
<cite :text="it.code"></cite>
|
<cite :text="it.code"></cite>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<canvas class="last-days" width="128" height="60" :draw="it.last"></canvas>
|
|
||||||
|
|
||||||
<div class="today">
|
<div class="today">
|
||||||
<span class="money" :text="it.curr"></span>
|
<span class="money" :text="'¥' + it.cm"></span>
|
||||||
<span
|
<span
|
||||||
class="percent"
|
class="percent"
|
||||||
:class="{red: it.percent > 0, green: it.percent < 0}"
|
:class="{red: it.cp > 0, green: it.cp < 0}"
|
||||||
:text="it.percent + '%'">
|
:text="it.cp + '%'">
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
<section :if="list.length === 0" class="item">啥基都没有...</section>
|
||||||
</wc-scroll>
|
</wc-scroll>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -15,26 +15,33 @@
|
||||||
|
|
||||||
<aside class="sidebar app-drag">
|
<aside class="sidebar app-drag">
|
||||||
<wc-icon class="app-nodrag item stat active" is="chart"></wc-icon>
|
<wc-icon class="app-nodrag item stat active" is="chart"></wc-icon>
|
||||||
<wc-icon class="app-nodrag item opt" is="menu-dot"></wc-icon>
|
<wc-icon class="app-nodrag item opt" is="menu-dot" @click="showPreferencesPanel"></wc-icon>
|
||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
<div class="select-box">
|
<div class="select-box">
|
||||||
<section class="form">
|
<section class="form">
|
||||||
<wc-input maxlength="6" placeholder="输入编号搞新基" round size="mini"></wc-input>
|
<wc-input
|
||||||
<wc-button circle size="mini" color="orange" icon="plus"></wc-button>
|
maxlength="6"
|
||||||
|
placeholder="输入编号搞新基"
|
||||||
|
round
|
||||||
|
@submit="addGay"
|
||||||
|
:duplex="input"
|
||||||
|
size="mini">
|
||||||
|
</wc-input>
|
||||||
</section>
|
</section>
|
||||||
<wc-scroll class="list">
|
<wc-scroll class="list">
|
||||||
<item
|
<item
|
||||||
class="item"
|
class="item"
|
||||||
:class="{active: curr.code === it.code}"
|
:class="{active: curr.code === it.code}"
|
||||||
|
@click="viewGay(it)"
|
||||||
:for="it in list">
|
:for="it in list">
|
||||||
<strong class="text-ell" :text="it.name"></strong>
|
<strong class="text-ell" :text="it.name"></strong>
|
||||||
<section>
|
<section>
|
||||||
<cite :text="it.code"></cite>
|
<cite :text="it.code"></cite>
|
||||||
<span
|
<span
|
||||||
class="percent"
|
class="percent"
|
||||||
:class="{red: it.percent > 0, green: it.percent < 0}"
|
:class="{red: it.cp > 0, green: it.cp < 0}"
|
||||||
:text="it.percent + '%'">
|
:text="it.cp + '%'">
|
||||||
</span>
|
</span>
|
||||||
</section>
|
</section>
|
||||||
</item>
|
</item>
|
||||||
|
@ -42,23 +49,70 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="detail">
|
<div class="detail" :class="{blur: !curr.code}">
|
||||||
<section class="title app-drag">
|
<section class="title app-drag">
|
||||||
[{{curr.code}}] {{curr.name}}
|
<span>[{{curr.code}}] {{curr.name}}</span>
|
||||||
|
<span>
|
||||||
|
<wc-button
|
||||||
|
circle
|
||||||
|
size="mini"
|
||||||
|
@click="removeGay"
|
||||||
|
icon="trash">
|
||||||
|
</wc-button>
|
||||||
|
<wc-button
|
||||||
|
circle
|
||||||
|
color="red"
|
||||||
|
size="mini"
|
||||||
|
@click="updateGay"
|
||||||
|
icon="eye">
|
||||||
|
</wc-button>
|
||||||
|
</span>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<fieldset class="card">
|
<fieldset class="card">
|
||||||
<legend>60天红绿榜</legend>
|
<legend>实时数据</legend>
|
||||||
<wc-rank :attr-list="curr.last60"></wc-rank>
|
<wc-rank :attr-stat="curr.stat"></wc-rank>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<fieldset class="card">
|
<fieldset class="card">
|
||||||
<legend>单位净值走势</legend>
|
<legend>单位净值走势</legend>
|
||||||
<wc-rank :attr-list="curr.last60"></wc-rank>
|
<wc-line :attr-list="curr.line"></wc-line>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<wc-layer ref="pre" mask mask-close radius="10px" >
|
||||||
|
<div class="preferences">
|
||||||
|
<div class="titlebar">
|
||||||
|
<div class="title">hello</div>
|
||||||
|
<nav>
|
||||||
|
<span :class="{active: preferences.tab === 1}" @click="switchTab(1)">
|
||||||
|
<wc-icon is="setting"></wc-icon>
|
||||||
|
常规
|
||||||
|
</span>
|
||||||
|
<span :class="{active: preferences.tab === 2}" @click="switchTab(2)">
|
||||||
|
<wc-icon is="info"></wc-icon>
|
||||||
|
关于
|
||||||
|
</span>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="tab-panel" :visible="preferences.tab === 1">
|
||||||
|
<section class="field">
|
||||||
|
<span class="label">神奇的2点半提醒</span>
|
||||||
|
<wc-switch :duplex="preferences.notify"></wc-switch>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="tab-panel" :visible="preferences.tab === 2">
|
||||||
|
<p>“搞基爱啪啪” 是一款开源的, 非专业的搞基软件, 上面的数据全来自网络, 不对准确性作任何保证. </p>
|
||||||
|
<p>搞基有风险, 入行需谨慎. 你亏了别找我, 赚了可以给我发红包.</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</wc-layer>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
388
src/js/app.js
388
src/js/app.js
|
@ -8,21 +8,18 @@
|
||||||
|
|
||||||
import '/lib/anot.js'
|
import '/lib/anot.js'
|
||||||
import '/lib/form/button.js'
|
import '/lib/form/button.js'
|
||||||
|
import '/lib/form/switch.js'
|
||||||
import '/lib/scroll/index.js'
|
import '/lib/scroll/index.js'
|
||||||
import '/lib/chart/rank.js'
|
import '/lib/chart/rank.js'
|
||||||
import '/lib/canvas-draw.js'
|
import '/lib/chart/line.js'
|
||||||
|
|
||||||
import layer from '/lib/layer/index.js'
|
import layer from '/lib/layer/index.js'
|
||||||
import Utils from '/lib/utils.js'
|
import Utils from '/lib/utils.js'
|
||||||
|
|
||||||
|
import app from '/lib/socket.js'
|
||||||
|
|
||||||
const log = console.log
|
const log = console.log
|
||||||
|
|
||||||
const { ipcRenderer } = require('electron')
|
|
||||||
|
|
||||||
// http://fund.eastmoney.com/pingzhongdata/161725.js?v=20201209153939
|
|
||||||
|
|
||||||
const $doc = Anot(document)
|
|
||||||
|
|
||||||
function getJsonp(str) {
|
function getJsonp(str) {
|
||||||
if (~str.indexOf('jsonpgz')) {
|
if (~str.indexOf('jsonpgz')) {
|
||||||
return new Function(`function jsonpgz(d){return d}; return ${str}`)()
|
return new Function(`function jsonpgz(d){return d}; return ${str}`)()
|
||||||
|
@ -30,216 +27,255 @@ function getJsonp(str) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTableData(str) {
|
function getLineStat(str) {
|
||||||
var match = str.match(/<tbody[^]*?>.*?<\/tbody>/)
|
return new Function(`${str}; return {line: Data_netWorthTrend.map(it => ({
|
||||||
var table = document.createElement('table')
|
x: ~~(it.x/1000),
|
||||||
var list = []
|
y: +(it.y * 10000).toFixed(0),
|
||||||
var max = 0
|
p: it.equityReturn
|
||||||
var min = 99
|
})), e1: +syl_1y, e3: +syl_3y, e6: +syl_6y, e12: +syl_1n}`)()
|
||||||
|
|
||||||
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({
|
Anot({
|
||||||
$id: 'app',
|
$id: 'app',
|
||||||
state: {
|
state: {
|
||||||
|
input: '',
|
||||||
curr: {
|
curr: {
|
||||||
code: '161725',
|
code: '',
|
||||||
name: '招商中证白酒指数分级',
|
name: '',
|
||||||
last60: [
|
stat: '',
|
||||||
1.56,
|
line: ''
|
||||||
2.81,
|
|
||||||
0.82,
|
|
||||||
-0.18,
|
|
||||||
-1.67,
|
|
||||||
-2.34,
|
|
||||||
1.36,
|
|
||||||
-1.52,
|
|
||||||
-0.92,
|
|
||||||
-0.49,
|
|
||||||
-1.74,
|
|
||||||
0.03,
|
|
||||||
1.15,
|
|
||||||
-0.21,
|
|
||||||
0.46,
|
|
||||||
1.45,
|
|
||||||
5.54,
|
|
||||||
1.7,
|
|
||||||
-0.33,
|
|
||||||
-0.11,
|
|
||||||
-1.11,
|
|
||||||
-0.76,
|
|
||||||
3.16,
|
|
||||||
0.32,
|
|
||||||
1.85,
|
|
||||||
-2.54,
|
|
||||||
-1.08,
|
|
||||||
0.91,
|
|
||||||
3.27,
|
|
||||||
2.84,
|
|
||||||
-2.83,
|
|
||||||
1.67,
|
|
||||||
1.1,
|
|
||||||
0.48,
|
|
||||||
1.89,
|
|
||||||
-0.66,
|
|
||||||
1.91,
|
|
||||||
2.15,
|
|
||||||
0.12,
|
|
||||||
1.75,
|
|
||||||
-3.43,
|
|
||||||
3.88,
|
|
||||||
-1.37,
|
|
||||||
-1.62,
|
|
||||||
0.38,
|
|
||||||
1.49,
|
|
||||||
1.03,
|
|
||||||
0.6,
|
|
||||||
-3.51,
|
|
||||||
0.5,
|
|
||||||
0.6,
|
|
||||||
-3.01,
|
|
||||||
0.87,
|
|
||||||
-0.03,
|
|
||||||
0.99,
|
|
||||||
3.4,
|
|
||||||
0.32,
|
|
||||||
1.53,
|
|
||||||
-0.46,
|
|
||||||
0.84
|
|
||||||
].join(',')
|
|
||||||
},
|
},
|
||||||
list: [],
|
list: [],
|
||||||
$dict: {}
|
$dict: {},
|
||||||
|
preferences: {
|
||||||
|
tab: 1,
|
||||||
|
notify: Anot.ls('notify') === '1'
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
'chapter.content'() {
|
'preferences.notify'(v) {
|
||||||
this.calcuteWords = this.chapter.content.length
|
Anot.ls('notify', v ^ 0)
|
||||||
},
|
if (v) {
|
||||||
currCate() {
|
app.dispatch('notify')
|
||||||
this.renderChapterList()
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
// WIN.on('blur', _ => {
|
var gays = Anot.ls('gays') || '{}'
|
||||||
// WIN.hide()
|
var list = []
|
||||||
// })
|
var old = this.syncOldStat()
|
||||||
|
|
||||||
var watch_list = Anot.ls('watch_list') || '[]'
|
if (old === false) {
|
||||||
|
gays = JSON.parse(gays)
|
||||||
|
|
||||||
watch_list = JSON.parse(watch_list)
|
for (let code in gays) {
|
||||||
|
let { name, cm, cp, t } = gays[code]
|
||||||
|
list.push({ code, name, cm, cp, t })
|
||||||
|
this.$dict[code] = 1
|
||||||
|
}
|
||||||
|
list.sort((a, b) => b.cp - a.cp)
|
||||||
|
|
||||||
this.list = watch_list
|
this.list = list
|
||||||
|
}
|
||||||
|
|
||||||
for (let it of this.list) {
|
if (this.preferences.notify) {
|
||||||
this.$dict[it.code] = it
|
app.dispatch('notify')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
close() {
|
syncOldStat() {
|
||||||
// WIN.close()
|
var old = Anot.ls('watch_list')
|
||||||
|
var list = []
|
||||||
|
var dict = {}
|
||||||
|
|
||||||
|
if (old) {
|
||||||
|
old = JSON.parse(old)
|
||||||
|
for (let it of old) {
|
||||||
|
dict[it.code] = {
|
||||||
|
name: it.name,
|
||||||
|
cm: +it.curr,
|
||||||
|
cp: it.percent,
|
||||||
|
t: Date.now()
|
||||||
|
}
|
||||||
|
list.push({ code: it.code, ...dict[it.code] })
|
||||||
|
}
|
||||||
|
|
||||||
|
list.sort((a, b) => b.cp - a.cp)
|
||||||
|
this.list = list
|
||||||
|
|
||||||
|
Anot.ls('gays', dict)
|
||||||
|
Anot.ls('watch_list', null)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
},
|
},
|
||||||
getTodayStat(id) {
|
|
||||||
var res = ipcRenderer.sendSync(
|
showPreferencesPanel() {
|
||||||
'net',
|
this.$refs.pre.show()
|
||||||
|
},
|
||||||
|
|
||||||
|
switchTab(n) {
|
||||||
|
this.preferences.tab = n
|
||||||
|
},
|
||||||
|
|
||||||
|
getGayStat(id) {
|
||||||
|
var res = app.dispatch(
|
||||||
|
'fetch',
|
||||||
`https://fundgz.1234567.com.cn/js/${id}.js`
|
`https://fundgz.1234567.com.cn/js/${id}.js`
|
||||||
)
|
)
|
||||||
|
|
||||||
return getJsonp(res)
|
return getJsonp(res)
|
||||||
},
|
},
|
||||||
|
|
||||||
getLastMonth(id) {
|
|
||||||
var res = ipcRenderer.sendSync(
|
|
||||||
'net',
|
|
||||||
`https://fund.eastmoney.com/f10/F10DataApi.aspx?type=lsjz&per=42&code=${id}`
|
|
||||||
)
|
|
||||||
return getTableData(res)
|
|
||||||
},
|
|
||||||
|
|
||||||
addGay() {
|
addGay() {
|
||||||
layer
|
var code = this.input
|
||||||
.prompt('请输入鸡精代号', (val, done) => {
|
var gay
|
||||||
if (val.trim()) {
|
|
||||||
done()
|
if (this.$dict[code]) {
|
||||||
}
|
layer.toast('这个鸡精在列表呢~~~', 'warn')
|
||||||
})
|
this.input = ''
|
||||||
.then(id => {
|
|
||||||
if (this.$dict[id]) {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
Anot.nextTick(_ => {
|
|
||||||
var info = this.getTodayStat(id)
|
if (code.length < 6) {
|
||||||
var last
|
return
|
||||||
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]
|
if (/[^\d]/.test(code)) {
|
||||||
Anot.ls('watch_list', this.list.$model)
|
layer.toast('只能通过鸡精编号添加', 'error')
|
||||||
|
this.input = ''
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
gay = this.getGayStat(code)
|
||||||
|
|
||||||
|
if (gay) {
|
||||||
|
let tmp = {
|
||||||
|
code: gay.fundcode,
|
||||||
|
name: gay.name,
|
||||||
|
cm: +gay.gsz,
|
||||||
|
cp: +gay.gszzl,
|
||||||
|
t: Date.now()
|
||||||
|
}
|
||||||
|
this.input = ''
|
||||||
|
this.list.push(tmp)
|
||||||
|
this.$dict[tmp.code] = 1
|
||||||
|
this.list.sort((a, b) => b.cp - a.cp)
|
||||||
|
this.saveCache()
|
||||||
} else {
|
} else {
|
||||||
layer.toast('鸡精不存在', 'error')
|
layer.toast('鸡精不存在', 'error')
|
||||||
}
|
}
|
||||||
})
|
|
||||||
})
|
|
||||||
.catch(Anot.noop)
|
|
||||||
},
|
},
|
||||||
|
|
||||||
updateGay(item) {
|
updateGay() {
|
||||||
var info = this.getTodayStat(item.code)
|
var { code, stat } = this.curr
|
||||||
if (info.dwjz !== item.yesterday) {
|
var info = this.getGayStat(code)
|
||||||
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) {
|
for (let it of this.list) {
|
||||||
this.updateGay(it)
|
if (it.code === code) {
|
||||||
|
let d
|
||||||
|
|
||||||
|
it.cm = +info.gsz
|
||||||
|
it.cp = +info.gszzl
|
||||||
|
|
||||||
|
this.list.sort((a, b) => b.cp - a.cp)
|
||||||
|
|
||||||
|
d = new Date(info.gztime.slice(0, 10) + ' 00:00:00')
|
||||||
|
d = ~~(d.getTime() / 1000) - 24 * 3600
|
||||||
|
|
||||||
|
// 如果走势最后的日期比当前最新的小, 则全量更新
|
||||||
|
if (it.t < d) {
|
||||||
|
Anot.ls(code, null)
|
||||||
|
this.viewGay(it)
|
||||||
|
console.log('update all stat...')
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.list.sort((a, b) => {
|
stat = JSON.parse(stat)
|
||||||
return b.percent - a.percent
|
stat.cm = it.cm
|
||||||
})
|
stat.cp = it.cp
|
||||||
|
this.curr.stat = JSON.stringify(stat)
|
||||||
|
|
||||||
Anot.ls('watch_list', this.list.$model)
|
this.saveCache()
|
||||||
|
layer.toast('数据更新成功', 'success')
|
||||||
|
Anot.ss('last_update', Date.now())
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
removeGay() {
|
||||||
|
var { code, name } = this.curr
|
||||||
|
layer
|
||||||
|
.confirm(`是否移除「${name}」?`)
|
||||||
|
.then(_ => {
|
||||||
|
for (let it of this.list) {
|
||||||
|
if (it.code === code) {
|
||||||
|
this.list.remove(it)
|
||||||
|
delete this.$dict[code]
|
||||||
|
Anot.ls(code, null)
|
||||||
|
this.saveCache()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.viewGay(this.list[0])
|
||||||
|
})
|
||||||
|
.catch(Anot.noop)
|
||||||
|
},
|
||||||
|
|
||||||
|
saveCache() {
|
||||||
|
var dict = {}
|
||||||
|
for (let it of this.list) {
|
||||||
|
var { code, name, cm, cp, t } = it
|
||||||
|
dict[code] = { name, cm, cp, t }
|
||||||
|
}
|
||||||
|
Anot.ls('gays', dict)
|
||||||
|
},
|
||||||
|
|
||||||
|
viewGay(item) {
|
||||||
|
var gay = Anot.ls(item.code)
|
||||||
|
var rank, line
|
||||||
|
var { cm, cp, t } = item
|
||||||
|
|
||||||
|
this.curr.code = item.code
|
||||||
|
this.curr.name = item.name
|
||||||
|
|
||||||
|
if (gay) {
|
||||||
|
gay = JSON.parse(gay)
|
||||||
|
var last = gay.line[gay.line.length - 1].x
|
||||||
|
if (last < t) {
|
||||||
|
gay = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!gay) {
|
||||||
|
gay = app.dispatch(
|
||||||
|
'fetch',
|
||||||
|
`http://fund.eastmoney.com/pingzhongdata/${
|
||||||
|
item.code
|
||||||
|
}.js?v=${Date.now()}`
|
||||||
|
)
|
||||||
|
gay = getLineStat(gay)
|
||||||
|
item.t = gay.line[gay.line.length - 1].x
|
||||||
|
this.saveCache()
|
||||||
|
Anot.ls(item.code, JSON.stringify(gay))
|
||||||
|
}
|
||||||
|
|
||||||
|
rank = gay.line.slice(-60).map(_ => _.p)
|
||||||
|
line = JSON.stringify(gay.line)
|
||||||
|
|
||||||
|
this.curr.stat = JSON.stringify({
|
||||||
|
rank,
|
||||||
|
e1: gay.e1,
|
||||||
|
e3: gay.e3,
|
||||||
|
e6: gay.e6,
|
||||||
|
e12: gay.e12,
|
||||||
|
cm,
|
||||||
|
cp
|
||||||
|
})
|
||||||
|
this.curr.line = line
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
160
src/js/float.js
160
src/js/float.js
|
@ -5,18 +5,11 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import '/lib/anot.js'
|
import '/lib/anot.js'
|
||||||
import '/lib/form/button.js'
|
|
||||||
import '/lib/scroll/index.js'
|
import '/lib/scroll/index.js'
|
||||||
import '/lib/canvas-draw.js'
|
|
||||||
|
|
||||||
import layer from '/lib/layer/index.js'
|
import layer from '/lib/layer/index.js'
|
||||||
import Utils from '/lib/utils.js'
|
|
||||||
import app from '/lib/socket.js'
|
import app from '/lib/socket.js'
|
||||||
|
|
||||||
const log = console.log
|
|
||||||
|
|
||||||
const $doc = Anot(document)
|
|
||||||
|
|
||||||
function getJsonp(str) {
|
function getJsonp(str) {
|
||||||
if (~str.indexOf('jsonpgz')) {
|
if (~str.indexOf('jsonpgz')) {
|
||||||
return new Function(`function jsonpgz(d){return d}; return ${str}`)()
|
return new Function(`function jsonpgz(d){return d}; return ${str}`)()
|
||||||
|
@ -24,156 +17,71 @@ function getJsonp(str) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTableData(str) {
|
|
||||||
var match = str.match(/<tbody[^]*?>.*?<\/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({
|
Anot({
|
||||||
$id: 'app',
|
$id: 'app',
|
||||||
state: {
|
state: {
|
||||||
list: [],
|
list: []
|
||||||
$dict: {}
|
|
||||||
},
|
|
||||||
|
|
||||||
watch: {
|
|
||||||
'chapter.content'() {
|
|
||||||
this.calcuteWords = this.chapter.content.length
|
|
||||||
},
|
|
||||||
currCate() {
|
|
||||||
this.renderChapterList()
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
var watch_list = Anot.ls('watch_list') || '[]'
|
this.reloadGays()
|
||||||
|
|
||||||
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', data => {
|
app.on('float-visible', data => {
|
||||||
var time = +Anot.ss('last_update') || 0
|
var time = +Anot.ss('last_update') || 0
|
||||||
var now = Date.now()
|
var now = Date.now()
|
||||||
|
|
||||||
// 如果离上次更新超过15分钟, 则自动更新
|
// 如果离上次更新超过15分钟, 则自动更新
|
||||||
if (now - time > 15 * 60 * 1000) {
|
if (now - time > 15 * 60 * 1000) {
|
||||||
this.updateGays()
|
this.updateGays()
|
||||||
Anot.ss('last_update', now)
|
Anot.ss('last_update', now)
|
||||||
|
} else {
|
||||||
|
this.reloadGays()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
close() {
|
reloadGays() {
|
||||||
// WIN.close()
|
var gays = Anot.ls('gays') || '{}'
|
||||||
|
var list = []
|
||||||
|
|
||||||
|
gays = JSON.parse(gays)
|
||||||
|
|
||||||
|
for (let code in gays) {
|
||||||
|
let { name, cm, cp, t } = gays[code]
|
||||||
|
list.push({ code, name, cm, cp, t })
|
||||||
|
}
|
||||||
|
list.sort((a, b) => b.cp - a.cp)
|
||||||
|
|
||||||
|
this.list = list
|
||||||
},
|
},
|
||||||
getTodayStat(id) {
|
|
||||||
|
getGayStat(id) {
|
||||||
var res = app.dispatch(
|
var res = app.dispatch(
|
||||||
'fetch',
|
'fetch',
|
||||||
`https://fundgz.1234567.com.cn/js/${id}.js`
|
`https://fundgz.1234567.com.cn/js/${id}.js`
|
||||||
)
|
)
|
||||||
|
|
||||||
return getJsonp(res)
|
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) {
|
updateGay(item) {
|
||||||
var info = this.getTodayStat(item.code)
|
var info = this.getGayStat(item.code)
|
||||||
if (info.dwjz !== item.yesterday) {
|
item.cm = +info.gsz
|
||||||
item.yesterday = info.dwjz
|
item.cp = +info.gszzl
|
||||||
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() {
|
updateGays() {
|
||||||
for (let it of this.list) {
|
for (let it of this.list) {
|
||||||
this.updateGay(it)
|
this.updateGay(it)
|
||||||
}
|
}
|
||||||
|
this.list.sort((a, b) => b.cp - a.cp)
|
||||||
this.list.sort((a, b) => {
|
this.saveCache()
|
||||||
return b.percent - a.percent
|
},
|
||||||
})
|
saveCache() {
|
||||||
|
var dict = {}
|
||||||
Anot.ls('watch_list', this.list.$model)
|
for (let it of this.list) {
|
||||||
|
var { code, name, cm, cp, t } = it
|
||||||
|
dict[code] = { name, cm, cp, t }
|
||||||
|
}
|
||||||
|
Anot.ls('gays', dict)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,44 +0,0 @@
|
||||||
/**
|
|
||||||
* canvas渲染
|
|
||||||
* @author yutent<yutent.io@gmail.com>
|
|
||||||
* @date 2020/07/27 11:34:59
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict'
|
|
||||||
|
|
||||||
const log = console.log
|
|
||||||
|
|
||||||
const RED = '#ff5061'
|
|
||||||
const GREEN = '#4caf50'
|
|
||||||
|
|
||||||
Anot.directive('draw', {
|
|
||||||
priority: 1500,
|
|
||||||
init(binding) {
|
|
||||||
var elem = binding.element
|
|
||||||
var ctx = elem.getContext('2d')
|
|
||||||
binding.$ctx = ctx
|
|
||||||
},
|
|
||||||
update: function(val) {
|
|
||||||
var list = val.$model
|
|
||||||
var start = list.shift()
|
|
||||||
var end = list[list.length - 1]
|
|
||||||
var x = 0
|
|
||||||
|
|
||||||
this.$ctx.clearRect(0, 0, 128, 60)
|
|
||||||
|
|
||||||
this.$ctx.fillStyle = '#a7a8ab'
|
|
||||||
this.$ctx.fillRect(0, 29, 128, 1)
|
|
||||||
|
|
||||||
this.$ctx.beginPath()
|
|
||||||
this.$ctx.strokeStyle = start.m < end.m ? RED : GREEN
|
|
||||||
this.$ctx.lineWidth = 2
|
|
||||||
this.$ctx.moveTo(0, 60 - start.h)
|
|
||||||
|
|
||||||
while (list.length) {
|
|
||||||
start = list.shift()
|
|
||||||
x += 3
|
|
||||||
this.$ctx.lineTo(x, 60 - start.h)
|
|
||||||
}
|
|
||||||
this.$ctx.stroke()
|
|
||||||
}
|
|
||||||
})
|
|
|
@ -0,0 +1,253 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @authors yutent (yutent.io@gmail.com)
|
||||||
|
* @date 2020-12-08 11:30:52
|
||||||
|
* @version v1.0.0
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
import $ from '../utils.js'
|
||||||
|
import '../form/button.js'
|
||||||
|
|
||||||
|
const DARK = '#62778d'
|
||||||
|
const BLUE = '#64b5f6'
|
||||||
|
const PLAIN = '#f2f5fc'
|
||||||
|
|
||||||
|
export default class Line extends HTMLElement {
|
||||||
|
static get observedAttributes() {
|
||||||
|
return ['list']
|
||||||
|
}
|
||||||
|
|
||||||
|
props = {
|
||||||
|
list: []
|
||||||
|
}
|
||||||
|
|
||||||
|
state = {
|
||||||
|
key: 1,
|
||||||
|
list: []
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super()
|
||||||
|
|
||||||
|
Object.defineProperty(this, 'root', {
|
||||||
|
value: this.attachShadow({ mode: 'open' }),
|
||||||
|
writable: true,
|
||||||
|
enumerable: false,
|
||||||
|
configurable: true
|
||||||
|
})
|
||||||
|
|
||||||
|
this.root.innerHTML = `<style>* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0; }
|
||||||
|
|
||||||
|
::before,
|
||||||
|
::after {
|
||||||
|
box-sizing: border-box; }
|
||||||
|
|
||||||
|
:host {
|
||||||
|
display: flex;
|
||||||
|
width: 680px; }
|
||||||
|
|
||||||
|
.container {
|
||||||
|
position: relative;
|
||||||
|
padding: 24px 0 0; }
|
||||||
|
|
||||||
|
canvas {
|
||||||
|
width: 680px;
|
||||||
|
height: 230px; }
|
||||||
|
|
||||||
|
section {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0; }
|
||||||
|
</style>
|
||||||
|
<div class="container">
|
||||||
|
<canvas></canvas>
|
||||||
|
<section>
|
||||||
|
<wc-button color="blue" data-key="1" size="mini">1月</wc-button>
|
||||||
|
<wc-button data-key="3" size="mini">3月</wc-button>
|
||||||
|
<wc-button data-key="6" size="mini">半年</wc-button>
|
||||||
|
<wc-button data-key="12" size="mini">1年</wc-button>
|
||||||
|
<wc-button data-key="36" size="mini">3年</wc-button>
|
||||||
|
<wc-button data-key="999" size="mini">所有</wc-button>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
|
||||||
|
var elem = this.root.children[1]
|
||||||
|
this.__SCENE__ = elem.firstElementChild
|
||||||
|
this.__FILTER__ = elem.lastElementChild
|
||||||
|
this.__CTX__ = this.__SCENE__.getContext('2d')
|
||||||
|
this.__SCENE__.width = 680
|
||||||
|
this.__SCENE__.height = 230
|
||||||
|
}
|
||||||
|
|
||||||
|
_getTime(n) {
|
||||||
|
var now = new Date()
|
||||||
|
var time = { getTime: _ => 0 }
|
||||||
|
var Y = now.getFullYear()
|
||||||
|
var m = now.getMonth()
|
||||||
|
var d = now.getDate()
|
||||||
|
|
||||||
|
switch (n) {
|
||||||
|
case 1:
|
||||||
|
time = new Date(Y, m - 1, d, 0, 0, 0)
|
||||||
|
break
|
||||||
|
case 3:
|
||||||
|
time = new Date(Y, m - 3, d, 0, 0, 0)
|
||||||
|
break
|
||||||
|
case 6:
|
||||||
|
time = new Date(Y, m - 6, d, 0, 0, 0)
|
||||||
|
break
|
||||||
|
case 12:
|
||||||
|
time = new Date(Y - 1, m, d, 0, 0, 0)
|
||||||
|
break
|
||||||
|
case 36:
|
||||||
|
time = new Date(Y - 3, m, d, 0, 0, 0)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return time.getTime()
|
||||||
|
}
|
||||||
|
|
||||||
|
_filter(n) {
|
||||||
|
if (n < 999) {
|
||||||
|
var time = this._getTime(n)
|
||||||
|
this.state.list = this.props.list.filter(it => it.x >= time)
|
||||||
|
} else {
|
||||||
|
this.state.list = this.props.list.concat()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
draw() {
|
||||||
|
var { list, key } = this.state
|
||||||
|
var ctx = this.__CTX__
|
||||||
|
var x = 36
|
||||||
|
var max = 0
|
||||||
|
var min = Number.MAX_SAFE_INTEGER
|
||||||
|
var step = 0 // 纵坐标间隔
|
||||||
|
var dis = +(640 / list.length).toFixed(2) || 1 // 横坐标间隔
|
||||||
|
var point
|
||||||
|
var p1, p2, p3, p4
|
||||||
|
var format = key > 12 ? 'Y/m' : 'm/d'
|
||||||
|
|
||||||
|
for (let it of list) {
|
||||||
|
if (max < it.y) {
|
||||||
|
max = it.y
|
||||||
|
}
|
||||||
|
if (min > it.y) {
|
||||||
|
min = it.y
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
min = ~~(min / 100)
|
||||||
|
max = Math.ceil(max / 100)
|
||||||
|
step = ~~((max - min) / 3)
|
||||||
|
|
||||||
|
p1 = Math.floor(list.length / 4)
|
||||||
|
p2 = Math.floor(list.length / 2)
|
||||||
|
p3 = Math.floor((list.length * 3) / 4)
|
||||||
|
p4 = list.length - 1
|
||||||
|
|
||||||
|
ctx.clearRect(0, 0, 680, 230)
|
||||||
|
|
||||||
|
// 纵坐标数值
|
||||||
|
ctx.font = '12px Arial'
|
||||||
|
ctx.textAlign = 'right'
|
||||||
|
ctx.fillStyle = DARK
|
||||||
|
ctx.fillText(min / 100, 32, 205)
|
||||||
|
ctx.fillText((min + step) / 100, 32, 155)
|
||||||
|
ctx.fillText((min + step + step) / 100, 32, 105)
|
||||||
|
ctx.fillText((min + step + step + step) / 100, 32, 55)
|
||||||
|
|
||||||
|
ctx.font = '10px Arial'
|
||||||
|
ctx.textAlign = 'left'
|
||||||
|
ctx.fillText(new Date(list[0].x).format(format), x - 12, 225)
|
||||||
|
ctx.fillText(new Date(list[p1].x).format(format), x + dis * p1 - 12, 225)
|
||||||
|
ctx.fillText(new Date(list[p2].x).format(format), x + dis * p2 - 12, 225)
|
||||||
|
ctx.fillText(new Date(list[p3].x).format(format), x + dis * p3 - 12, 225)
|
||||||
|
ctx.fillText(
|
||||||
|
new Date(list[p4].x).format(format),
|
||||||
|
x + dis * p4 - 12 - (key > 12 ? 24 : 4),
|
||||||
|
225
|
||||||
|
)
|
||||||
|
|
||||||
|
// x轴参考线
|
||||||
|
ctx.fillStyle = PLAIN
|
||||||
|
ctx.fillRect(x, 50, 648, 1)
|
||||||
|
ctx.fillRect(x, 100, 648, 1)
|
||||||
|
ctx.fillRect(x, 150, 648, 1)
|
||||||
|
ctx.fillRect(x, 200, 648, 1)
|
||||||
|
|
||||||
|
// y轴参考 线
|
||||||
|
ctx.fillRect(x, 0, 1, 210)
|
||||||
|
ctx.fillRect(x + dis * p1, 0, 1, 210)
|
||||||
|
ctx.fillRect(x + dis * p2, 0, 1, 210)
|
||||||
|
ctx.fillRect(x + dis * p3, 0, 1, 210)
|
||||||
|
ctx.fillRect(x + dis * p4, 0, 1, 210)
|
||||||
|
|
||||||
|
point = list.shift()
|
||||||
|
|
||||||
|
// 曲线
|
||||||
|
ctx.beginPath()
|
||||||
|
ctx.strokeStyle = BLUE
|
||||||
|
ctx.lineWidth = 1
|
||||||
|
ctx.moveTo(x, 200 - (((point.y / 100 - min) / step) * 50).toFixed(0))
|
||||||
|
|
||||||
|
while (list.length) {
|
||||||
|
let y
|
||||||
|
|
||||||
|
point = list.shift()
|
||||||
|
|
||||||
|
y = 200 - (((point.y / 100 - min) / step) * 50).toFixed(0)
|
||||||
|
x += dis
|
||||||
|
|
||||||
|
ctx.lineTo(x, y)
|
||||||
|
}
|
||||||
|
ctx.stroke()
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedCallback() {
|
||||||
|
$.bind(this.__FILTER__, 'click', ev => {
|
||||||
|
var el = ev.target
|
||||||
|
if (this.props.list.length < 1) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (el.tagName === 'WC-BUTTON') {
|
||||||
|
var k = +el.dataset.key
|
||||||
|
|
||||||
|
$.each(this.__FILTER__.children, function(it) {
|
||||||
|
it.removeAttribute('color')
|
||||||
|
})
|
||||||
|
el.setAttribute('color', 'blue')
|
||||||
|
|
||||||
|
this.state.key = k
|
||||||
|
this._filter(k)
|
||||||
|
this.draw()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
attributeChangedCallback(name, old, val) {
|
||||||
|
if (val === null || old === val) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch (name) {
|
||||||
|
case 'list':
|
||||||
|
try {
|
||||||
|
var list = JSON.parse(val)
|
||||||
|
list.forEach(it => (it.x = it.x * 1000))
|
||||||
|
this.props.list = list
|
||||||
|
this._filter(this.state.key)
|
||||||
|
this.removeAttribute('list')
|
||||||
|
this.draw()
|
||||||
|
} catch (e) {}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!customElements.get('wc-line')) {
|
||||||
|
customElements.define('wc-line', Line)
|
||||||
|
}
|
|
@ -8,16 +8,18 @@
|
||||||
|
|
||||||
const RED = '#ff5061'
|
const RED = '#ff5061'
|
||||||
const GREEN = '#4caf50'
|
const GREEN = '#4caf50'
|
||||||
|
const BLUE = '#64b5f6'
|
||||||
const GREY = '#bdbdbd'
|
const GREY = '#bdbdbd'
|
||||||
const PLAIN = '#f2f5fc'
|
const PLAIN = '#f2f5fc'
|
||||||
|
const DARK = '#62778d'
|
||||||
|
|
||||||
export default class Rank extends HTMLElement {
|
export default class Rank extends HTMLElement {
|
||||||
static get observedAttributes() {
|
static get observedAttributes() {
|
||||||
return ['list']
|
return ['stat']
|
||||||
}
|
}
|
||||||
|
|
||||||
props = {
|
props = {
|
||||||
list: ''
|
stat: {}
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
|
@ -56,12 +58,12 @@ canvas {
|
||||||
}
|
}
|
||||||
|
|
||||||
draw() {
|
draw() {
|
||||||
var { list } = this.props
|
var { rank, e1, e3, e6, e12, cm, cp } = this.props.stat
|
||||||
var ctx = this.__CTX__
|
var ctx = this.__CTX__
|
||||||
var x = 32
|
var x = 32
|
||||||
|
|
||||||
while (list.length < 60) {
|
while (rank.length < 60) {
|
||||||
list.unshift(0)
|
rank.unshift(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.clearRect(0, 0, 680, 101)
|
ctx.clearRect(0, 0, 680, 101)
|
||||||
|
@ -75,15 +77,34 @@ canvas {
|
||||||
ctx.fillText('-5%', 28, 80)
|
ctx.fillText('-5%', 28, 80)
|
||||||
ctx.fillText('-10%', 28, 100)
|
ctx.fillText('-10%', 28, 100)
|
||||||
|
|
||||||
|
ctx.font = '10px menlo,Hiragino Sans GB'
|
||||||
|
ctx.textAlign = 'left'
|
||||||
|
ctx.fillStyle = DARK
|
||||||
|
ctx.fillText('60天红绿榜', 160, 10)
|
||||||
|
|
||||||
|
ctx.font = '12px menlo,Hiragino Sans GB'
|
||||||
|
ctx.fillText(`最近1个月收益: ${e1}%`, 360, 25)
|
||||||
|
ctx.fillText(`最近3个月收益: ${e3}%`, 360, 45)
|
||||||
|
ctx.fillText(`最近半年收益: ${e6}%`, 528, 25)
|
||||||
|
ctx.fillText(`最近一年收益: ${e12}%`, 528, 45)
|
||||||
|
|
||||||
|
ctx.fillStyle = cp > 0 ? RED : cp === 0 ? GREY : GREEN
|
||||||
|
ctx.fillRect(360, 65, 140, 20)
|
||||||
|
ctx.fillRect(526, 65, 140, 20)
|
||||||
|
ctx.fillStyle = '#fff'
|
||||||
|
ctx.font = 'bold 14px menlo,Hiragino Sans GB'
|
||||||
|
ctx.fillText(`实时净值: ¥${cm}`, 364, 80)
|
||||||
|
ctx.fillText(`实时涨跌: ${cp}%`, 532, 80)
|
||||||
|
|
||||||
ctx.fillStyle = PLAIN
|
ctx.fillStyle = PLAIN
|
||||||
ctx.fillRect(28, 25, 652, 1)
|
ctx.fillRect(28, 25, 320, 1)
|
||||||
ctx.fillRect(28, 75, 652, 1)
|
ctx.fillRect(28, 75, 320, 1)
|
||||||
ctx.fillStyle = GREY
|
ctx.fillStyle = GREY
|
||||||
ctx.fillRect(28, 0, 1, 140)
|
ctx.fillRect(28, 0, 1, 140)
|
||||||
ctx.fillRect(0, 50, 680, 1)
|
ctx.fillRect(0, 50, 348, 1)
|
||||||
|
|
||||||
while (list.length) {
|
while (rank.length) {
|
||||||
var n = list.shift()
|
var n = rank.shift()
|
||||||
var y = Math.ceil(50 - (n / 10) * 50)
|
var y = Math.ceil(50 - (n / 10) * 50)
|
||||||
|
|
||||||
ctx.fillStyle = n > 0 ? RED : GREEN
|
ctx.fillStyle = n > 0 ? RED : GREEN
|
||||||
|
@ -94,7 +115,7 @@ canvas {
|
||||||
ctx.fillRect(x, y, 3, 50 - y)
|
ctx.fillRect(x, y, 3, 50 - y)
|
||||||
}
|
}
|
||||||
|
|
||||||
x += 10
|
x += 5
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,11 +124,13 @@ canvas {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
switch (name) {
|
switch (name) {
|
||||||
case 'list':
|
case 'stat':
|
||||||
var list = val.split(',')
|
try {
|
||||||
this.props.list = list.map(n => +n)
|
var stat = JSON.parse(val)
|
||||||
this.removeAttribute('list')
|
this.props.stat = stat
|
||||||
|
this.removeAttribute('stat')
|
||||||
this.draw()
|
this.draw()
|
||||||
|
} catch (e) {}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
40
src/main.js
40
src/main.js
|
@ -4,7 +4,14 @@
|
||||||
* @date 2019/09/16 20:51:19
|
* @date 2019/09/16 20:51:19
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const { app, BrowserWindow, protocol, ipcMain, net } = require('electron')
|
const {
|
||||||
|
app,
|
||||||
|
BrowserWindow,
|
||||||
|
protocol,
|
||||||
|
ipcMain,
|
||||||
|
net,
|
||||||
|
Notification
|
||||||
|
} = require('electron')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const fs = require('iofs')
|
const fs = require('iofs')
|
||||||
|
|
||||||
|
@ -24,6 +31,8 @@ const MIME_TYPES = {
|
||||||
|
|
||||||
const ROOT = __dirname
|
const ROOT = __dirname
|
||||||
|
|
||||||
|
var timer
|
||||||
|
|
||||||
function fetch(url) {
|
function fetch(url) {
|
||||||
return new Promise((y, n) => {
|
return new Promise((y, n) => {
|
||||||
var conn = net.request(url)
|
var conn = net.request(url)
|
||||||
|
@ -47,6 +56,22 @@ function fetch(url) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function ring() {
|
||||||
|
var n = 5
|
||||||
|
var t = setInterval(() => {
|
||||||
|
var notify = new Notification({
|
||||||
|
title: '搞基⏰',
|
||||||
|
subtitle: '神奇的2点半到啦',
|
||||||
|
body: '神奇的2点半到啦, 该加仓的加仓, 该卖的卖啦'
|
||||||
|
})
|
||||||
|
notify.show()
|
||||||
|
n--
|
||||||
|
if (n === 0) {
|
||||||
|
clearInterval(t)
|
||||||
|
}
|
||||||
|
}, 1000)
|
||||||
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------- */
|
/* ----------------------------------------------------- */
|
||||||
app.commandLine.appendSwitch('--lang', 'zh-CN')
|
app.commandLine.appendSwitch('--lang', 'zh-CN')
|
||||||
app.commandLine.appendSwitch('--autoplay-policy', 'no-user-gesture-required')
|
app.commandLine.appendSwitch('--autoplay-policy', 'no-user-gesture-required')
|
||||||
|
@ -85,5 +110,18 @@ ipcMain.on('app', (ev, conn) => {
|
||||||
fetch(conn.data).then(r => {
|
fetch(conn.data).then(r => {
|
||||||
ev.returnValue = r
|
ev.returnValue = r
|
||||||
})
|
})
|
||||||
|
} else if (conn.type === 'notify') {
|
||||||
|
clearTimeout(timer)
|
||||||
|
var t1 = Date.now()
|
||||||
|
var t2 = new Date()
|
||||||
|
t2.setHours(14)
|
||||||
|
t2.setMinutes(0)
|
||||||
|
t2.setSeconds(0)
|
||||||
|
|
||||||
|
if (t2.getTime() - t1 > 0) {
|
||||||
|
timer = setTimeout(ring, t2.getTime() - t1)
|
||||||
|
}
|
||||||
|
|
||||||
|
ev.returnValue = true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -13,7 +13,7 @@ module.exports = function(win) {
|
||||||
|
|
||||||
win.__TRAY__.on('click', _ => {
|
win.__TRAY__.on('click', _ => {
|
||||||
var b = win.__TRAY__.getBounds()
|
var b = win.__TRAY__.getBounds()
|
||||||
win.setBounds({ x: b.x - 145, y: b.y + b.height })
|
win.setBounds({ x: b.x - 120, y: b.y + b.height })
|
||||||
win.show()
|
win.show()
|
||||||
win.focus()
|
win.focus()
|
||||||
win.webContents.send('app', { type: 'float-visible', data: null })
|
win.webContents.send('app', { type: 'float-visible', data: null })
|
||||||
|
|
|
@ -34,19 +34,13 @@ exports.createMainWindow = function(icon) {
|
||||||
show: false
|
show: false
|
||||||
})
|
})
|
||||||
|
|
||||||
// 然后加载应用的 index.html。
|
|
||||||
|
|
||||||
win.loadURL('app://local/index.html')
|
win.loadURL('app://local/index.html')
|
||||||
|
|
||||||
// createAppTray(win)
|
|
||||||
// ctrlTrayBtn(win)
|
|
||||||
// createLrcTray(win)
|
|
||||||
|
|
||||||
createMenu(win)
|
createMenu(win)
|
||||||
|
|
||||||
win.on('ready-to-show', _ => {
|
win.on('ready-to-show', _ => {
|
||||||
win.show()
|
win.show()
|
||||||
win.openDevTools()
|
// win.openDevTools()
|
||||||
})
|
})
|
||||||
|
|
||||||
win.on('close', ev => {
|
win.on('close', ev => {
|
||||||
|
@ -60,18 +54,15 @@ exports.createMainWindow = function(icon) {
|
||||||
// 创建悬浮窗口
|
// 创建悬浮窗口
|
||||||
exports.createFloatWindow = function() {
|
exports.createFloatWindow = function() {
|
||||||
var win = new BrowserWindow({
|
var win = new BrowserWindow({
|
||||||
width: 320,
|
width: 280,
|
||||||
height: 360,
|
height: 360,
|
||||||
resizable: false,
|
resizable: false,
|
||||||
maximizable: false,
|
maximizable: false,
|
||||||
frame: false,
|
frame: false,
|
||||||
// transparent: true,
|
|
||||||
// hasShadow: false,
|
|
||||||
show: false,
|
show: false,
|
||||||
vibrancy: 'hud',
|
vibrancy: 'hud',
|
||||||
visualEffectState: 'active',
|
visualEffectState: 'active',
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
// webSecurity: false,
|
|
||||||
experimentalFeatures: true,
|
experimentalFeatures: true,
|
||||||
nodeIntegration: true,
|
nodeIntegration: true,
|
||||||
spellcheck: false
|
spellcheck: false
|
||||||
|
|
Loading…
Reference in New Issue