mirror of
https://github.com/ArvinLovegood/go-stock.git
synced 2025-07-19 00:00:09 +08:00
feat(frontend): 优化用户界面和功能
- 添加全屏切换功能 - 实现窗口隐藏和退出功能 - 新增设置菜单 - 优化股票信息展示界面 - 调整窗口大小和布局
This commit is contained in:
parent
88fb3ce94c
commit
b1a0e9575b
43
app.go
43
app.go
@ -177,6 +177,11 @@ func addStockFollowData(follow data.FollowedStock, stockData *data.StockInfo) {
|
|||||||
//昨日收盘价
|
//昨日收盘价
|
||||||
preClosePrice, _ := convertor.ToFloat(stockData.PreClose)
|
preClosePrice, _ := convertor.ToFloat(stockData.PreClose)
|
||||||
|
|
||||||
|
//当前价格依然为0 时 使用昨日收盘价为当前价格
|
||||||
|
if price == 0 {
|
||||||
|
price = preClosePrice
|
||||||
|
}
|
||||||
|
|
||||||
//今日最高价
|
//今日最高价
|
||||||
highPrice, _ := convertor.ToFloat(stockData.High)
|
highPrice, _ := convertor.ToFloat(stockData.High)
|
||||||
if highPrice == 0 {
|
if highPrice == 0 {
|
||||||
@ -191,20 +196,34 @@ func addStockFollowData(follow data.FollowedStock, stockData *data.StockInfo) {
|
|||||||
//开盘价
|
//开盘价
|
||||||
//openPrice, _ := convertor.ToFloat(stockData.Open)
|
//openPrice, _ := convertor.ToFloat(stockData.Open)
|
||||||
|
|
||||||
stockData.ChangePrice = mathutil.RoundToFloat(price-preClosePrice, 2)
|
if price > 0 {
|
||||||
stockData.ChangePercent = mathutil.RoundToFloat(mathutil.Div(price-preClosePrice, preClosePrice)*100, 3)
|
stockData.ChangePrice = mathutil.RoundToFloat(price-preClosePrice, 2)
|
||||||
stockData.HighRate = mathutil.RoundToFloat(mathutil.Div(highPrice-preClosePrice, preClosePrice)*100, 3)
|
stockData.ChangePercent = mathutil.RoundToFloat(mathutil.Div(price-preClosePrice, preClosePrice)*100, 3)
|
||||||
stockData.LowRate = mathutil.RoundToFloat(mathutil.Div(lowPrice-preClosePrice, preClosePrice)*100, 3)
|
}
|
||||||
|
if highPrice > 0 {
|
||||||
|
stockData.HighRate = mathutil.RoundToFloat(mathutil.Div(highPrice-preClosePrice, preClosePrice)*100, 3)
|
||||||
|
}
|
||||||
|
if lowPrice > 0 {
|
||||||
|
stockData.LowRate = mathutil.RoundToFloat(mathutil.Div(lowPrice-preClosePrice, preClosePrice)*100, 3)
|
||||||
|
}
|
||||||
if follow.CostPrice > 0 && follow.Volume > 0 {
|
if follow.CostPrice > 0 && follow.Volume > 0 {
|
||||||
stockData.Profit = mathutil.RoundToFloat(mathutil.Div(price-follow.CostPrice, follow.CostPrice)*100, 3)
|
if price > 0 {
|
||||||
stockData.ProfitAmount = mathutil.RoundToFloat((price-follow.CostPrice)*float64(follow.Volume), 2)
|
stockData.Profit = mathutil.RoundToFloat(mathutil.Div(price-follow.CostPrice, follow.CostPrice)*100, 3)
|
||||||
stockData.ProfitAmountToday = mathutil.RoundToFloat((price-preClosePrice)*float64(follow.Volume), 2)
|
stockData.ProfitAmount = mathutil.RoundToFloat((price-follow.CostPrice)*float64(follow.Volume), 2)
|
||||||
|
stockData.ProfitAmountToday = mathutil.RoundToFloat((price-preClosePrice)*float64(follow.Volume), 2)
|
||||||
|
} else {
|
||||||
|
//未开盘时当前价格为昨日收盘价
|
||||||
|
stockData.Profit = mathutil.RoundToFloat(mathutil.Div(preClosePrice-follow.CostPrice, follow.CostPrice)*100, 3)
|
||||||
|
stockData.ProfitAmount = mathutil.RoundToFloat((preClosePrice-follow.CostPrice)*float64(follow.Volume), 2)
|
||||||
|
stockData.ProfitAmountToday = mathutil.RoundToFloat((preClosePrice-preClosePrice)*float64(follow.Volume), 2)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//logger.SugaredLogger.Debugf("stockData:%+v", stockData)
|
//logger.SugaredLogger.Debugf("stockData:%+v", stockData)
|
||||||
if follow.Price != price {
|
if follow.Price != price && price > 0 {
|
||||||
go db.Dao.Model(follow).Where("stock_code = ?", follow.StockCode).Updates(map[string]interface{}{
|
go db.Dao.Model(follow).Where("stock_code = ?", follow.StockCode).Updates(map[string]interface{}{
|
||||||
"price": stockData.Price,
|
"price": price,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -306,10 +325,8 @@ func (a *App) SendDingDingMessageByType(message string, stockCode string, msgTyp
|
|||||||
}
|
}
|
||||||
stockInfo := &data.StockInfo{}
|
stockInfo := &data.StockInfo{}
|
||||||
db.Dao.Model(stockInfo).Where("code = ?", stockCode).First(stockInfo)
|
db.Dao.Model(stockInfo).Where("code = ?", stockCode).First(stockInfo)
|
||||||
if !data.NewAlertWindowsApi("go-stock消息通知", getMsgTypeName(msgType), GenNotificationMsg(stockInfo), "").SendNotification() {
|
go data.NewAlertWindowsApi("go-stock消息通知", getMsgTypeName(msgType), GenNotificationMsg(stockInfo), "").SendNotification()
|
||||||
return data.NewDingDingAPI().SendDingDingMessage(message)
|
return data.NewDingDingAPI().SendDingDingMessage(message)
|
||||||
}
|
|
||||||
return "发送系统消息成功"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func GenNotificationMsg(stockInfo *data.StockInfo) string {
|
func GenNotificationMsg(stockInfo *data.StockInfo) string {
|
||||||
|
@ -295,14 +295,19 @@ func (receiver StockDataApi) GetStockCodeRealTimeData(StockCodes ...string) (*[]
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
stockInfos = append(stockInfos, *stockData)
|
stockInfos = append(stockInfos, *stockData)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
var count int64
|
||||||
|
db.Dao.Model(&StockInfo{}).Where("code = ?", stockData.Code).Count(&count)
|
||||||
|
if count == 0 {
|
||||||
|
db.Dao.Model(&StockInfo{}).Create(stockData)
|
||||||
|
} else {
|
||||||
|
db.Dao.Model(&StockInfo{}).Where("code = ?", stockData.Code).Updates(stockData)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
}
|
}
|
||||||
//var count int64
|
|
||||||
//db.Dao.Model(&StockInfo{}).Where("code = ?", StockCode).Count(&count)
|
|
||||||
//if count == 0 {
|
|
||||||
// go db.Dao.Model(&StockInfo{}).Create(stockData)
|
|
||||||
//} else {
|
|
||||||
// go db.Dao.Model(&StockInfo{}).Where("code = ?", StockCode).Updates(stockData)
|
|
||||||
//}
|
|
||||||
return &stockInfos, err
|
return &stockInfos, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,6 +36,7 @@ func TestParseFullSingleStockData(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestNewStockDataApi(t *testing.T) {
|
func TestNewStockDataApi(t *testing.T) {
|
||||||
|
db.Init("../../data/stock.db")
|
||||||
stockDataApi := NewStockDataApi()
|
stockDataApi := NewStockDataApi()
|
||||||
datas, _ := stockDataApi.GetStockCodeRealTimeData("sh600859", "sh600745")
|
datas, _ := stockDataApi.GetStockCodeRealTimeData("sh600859", "sh600745")
|
||||||
for _, data := range *datas {
|
for _, data := range *datas {
|
||||||
|
22
frontend/package-lock.json
generated
22
frontend/package-lock.json
generated
@ -9,7 +9,8 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vicons/ionicons5": "^0.13.0",
|
"@vicons/ionicons5": "^0.13.0",
|
||||||
"vue": "^3.2.25"
|
"vue": "^3.2.25",
|
||||||
|
"vue-router": "^4.5.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vitejs/plugin-vue": "^5.2.1",
|
"@vitejs/plugin-vue": "^5.2.1",
|
||||||
@ -801,6 +802,11 @@
|
|||||||
"@vue/shared": "3.5.13"
|
"@vue/shared": "3.5.13"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@vue/devtools-api": {
|
||||||
|
"version": "6.6.4",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@vue/devtools-api/-/devtools-api-6.6.4.tgz",
|
||||||
|
"integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g=="
|
||||||
|
},
|
||||||
"node_modules/@vue/reactivity": {
|
"node_modules/@vue/reactivity": {
|
||||||
"version": "3.5.13",
|
"version": "3.5.13",
|
||||||
"resolved": "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.5.13.tgz",
|
"resolved": "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.5.13.tgz",
|
||||||
@ -1241,6 +1247,20 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/vue-router": {
|
||||||
|
"version": "4.5.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/vue-router/-/vue-router-4.5.0.tgz",
|
||||||
|
"integrity": "sha512-HDuk+PuH5monfNuY+ct49mNmkCRK4xJAV9Ts4z9UFc4rzdDnxQLyCMGGc8pKhZhHTVzfanpNwB/lwqevcBwI4w==",
|
||||||
|
"dependencies": {
|
||||||
|
"@vue/devtools-api": "^6.6.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/posva"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"vue": "^3.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/vueuc": {
|
"node_modules/vueuc": {
|
||||||
"version": "0.4.64",
|
"version": "0.4.64",
|
||||||
"resolved": "https://registry.npmmirror.com/vueuc/-/vueuc-0.4.64.tgz",
|
"resolved": "https://registry.npmmirror.com/vueuc/-/vueuc-0.4.64.tgz",
|
||||||
|
@ -10,7 +10,8 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vicons/ionicons5": "^0.13.0",
|
"@vicons/ionicons5": "^0.13.0",
|
||||||
"vue": "^3.2.25"
|
"vue": "^3.2.25",
|
||||||
|
"vue-router": "^4.5.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vitejs/plugin-vue": "^5.2.1",
|
"@vitejs/plugin-vue": "^5.2.1",
|
||||||
|
@ -1 +1 @@
|
|||||||
fda5308055dfd8a9cbfbd89ea27276c4
|
00b8e620dca5bab58d37996f0f350d0a
|
@ -1,13 +1,111 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import stockInfo from './components/stock.vue'
|
import stockInfo from './components/stock.vue'
|
||||||
import {ref} from "vue";
|
import {
|
||||||
import { darkTheme } from 'naive-ui'
|
Quit,
|
||||||
|
WindowFullscreen,
|
||||||
|
WindowHide,
|
||||||
|
WindowIsFullscreen,
|
||||||
|
WindowUnfullscreen
|
||||||
|
} from '../wailsjs/runtime'
|
||||||
|
import {h, ref} from "vue";
|
||||||
|
import {darkTheme, NIcon} from 'naive-ui'
|
||||||
|
import {
|
||||||
|
SettingsOutline,
|
||||||
|
ReorderTwoOutline,
|
||||||
|
ExpandOutline,
|
||||||
|
RefreshOutline, PowerOutline,
|
||||||
|
} from '@vicons/ionicons5'
|
||||||
|
|
||||||
const content = ref('数据来源于网络,仅供参考\n投资有风险,入市需谨慎')
|
const content = ref('数据来源于网络,仅供参考\n投资有风险,入市需谨慎')
|
||||||
</script>
|
const isFullscreen = ref(false)
|
||||||
|
const activeKey = ref('stock')
|
||||||
|
const containerRef= ref({})
|
||||||
|
const menuOptions = ref([
|
||||||
|
{
|
||||||
|
label: '设置',
|
||||||
|
key: 'settings',
|
||||||
|
icon: renderIcon(SettingsOutline),
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
type: 'group',
|
||||||
|
label: '开发中',
|
||||||
|
key: 'setting',
|
||||||
|
children: [
|
||||||
|
// {
|
||||||
|
// label: '叙事者',
|
||||||
|
// key: 'narrator',
|
||||||
|
// icon: renderIcon(PersonIcon)
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// label: '羊男',
|
||||||
|
// key: 'sheep-man',
|
||||||
|
// icon: renderIcon(PersonIcon)
|
||||||
|
// }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: ()=> h("a", {
|
||||||
|
href: '#',
|
||||||
|
onClick: toggleFullscreen
|
||||||
|
}, { default: () => '全屏' }),
|
||||||
|
key: 'full',
|
||||||
|
icon: renderIcon(ExpandOutline),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: ()=> h("a", {
|
||||||
|
href: '#',
|
||||||
|
onClick: WindowHide,
|
||||||
|
}, { default: () => '隐藏到托盘区' }),
|
||||||
|
key: 'hide',
|
||||||
|
icon: renderIcon(ReorderTwoOutline),
|
||||||
|
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: () =>
|
||||||
|
h(
|
||||||
|
'a',
|
||||||
|
{
|
||||||
|
href: '/',
|
||||||
|
target: '_self'
|
||||||
|
},
|
||||||
|
{ default: () => '刷新' }
|
||||||
|
),
|
||||||
|
key: 'stock',
|
||||||
|
icon: renderIcon(RefreshOutline)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: ()=> h("a", {
|
||||||
|
href: '#',
|
||||||
|
onClick: Quit,
|
||||||
|
}, { default: () => '退出程序' }),
|
||||||
|
key: 'exit',
|
||||||
|
icon: renderIcon(PowerOutline),
|
||||||
|
},
|
||||||
|
])
|
||||||
|
function renderIcon(icon) {
|
||||||
|
return () => h(NIcon, null, { default: () => h(icon) })
|
||||||
|
}
|
||||||
|
function toggleFullscreen(e) {
|
||||||
|
console.log(e)
|
||||||
|
WindowIsFullscreen().then((isFull) => {
|
||||||
|
isFullscreen.value = isFull
|
||||||
|
if (isFull) {
|
||||||
|
WindowUnfullscreen()
|
||||||
|
e.target.innerHTML = '全屏'
|
||||||
|
} else {
|
||||||
|
WindowFullscreen()
|
||||||
|
e.target.innerHTML = '取消全屏'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<n-config-provider :theme="darkTheme">
|
|
||||||
|
|
||||||
|
<n-config-provider :theme="darkTheme" ref="containerRef">
|
||||||
<n-watermark
|
<n-watermark
|
||||||
:content="content"
|
:content="content"
|
||||||
cross
|
cross
|
||||||
@ -21,10 +119,26 @@ const content = ref('数据来源于网络,仅供参考\n投资有风险,入市
|
|||||||
:rotate="-15"
|
:rotate="-15"
|
||||||
style="height: 100%"
|
style="height: 100%"
|
||||||
>
|
>
|
||||||
|
|
||||||
<n-flex justify="center">
|
<n-flex justify="center">
|
||||||
<n-message-provider >
|
<n-message-provider >
|
||||||
<n-modal-provider>
|
<n-modal-provider>
|
||||||
<stockInfo/>
|
<n-grid x-gap="12" :cols="1">
|
||||||
|
|
||||||
|
<n-gi>
|
||||||
|
<stockInfo/>
|
||||||
|
</n-gi>
|
||||||
|
<n-gi style="position: sticky;bottom:0;z-index: 9999;">
|
||||||
|
<n-card size="small">
|
||||||
|
<n-menu style="font-size: 18px;"
|
||||||
|
v-model:value="activeKey"
|
||||||
|
mode="horizontal"
|
||||||
|
:options="menuOptions"
|
||||||
|
responsive
|
||||||
|
/>
|
||||||
|
</n-card>
|
||||||
|
</n-gi>
|
||||||
|
</n-grid>
|
||||||
</n-modal-provider>
|
</n-modal-provider>
|
||||||
</n-message-provider>
|
</n-message-provider>
|
||||||
</n-flex>
|
</n-flex>
|
||||||
|
@ -334,13 +334,13 @@ function SendMessage(result,type){
|
|||||||
let img='http://image.sinajs.cn/newchart/min/n/'+result["股票代码"]+'.gif'+"?t="+Date.now()
|
let img='http://image.sinajs.cn/newchart/min/n/'+result["股票代码"]+'.gif'+"?t="+Date.now()
|
||||||
let markdown="### go-stock ["+typeName+"]\n\n"+
|
let markdown="### go-stock ["+typeName+"]\n\n"+
|
||||||
"### "+result["股票名称"]+"("+result["股票代码"]+")\n" +
|
"### "+result["股票名称"]+"("+result["股票代码"]+")\n" +
|
||||||
"- 当前价格: "+result["当前价格"]+" "+result.s+"\n" +
|
"- 当前价格: "+result["当前价格"]+" "+result.changePercent+"%\n" +
|
||||||
"- 最高价: "+result["今日最高价"]+" "+result.highRate+"\n" +
|
"- 最高价: "+result["今日最高价"]+" "+result.highRate+"\n" +
|
||||||
"- 最低价: "+result["今日最低价"]+" "+result.lowRate+"\n" +
|
"- 最低价: "+result["今日最低价"]+" "+result.lowRate+"\n" +
|
||||||
"- 昨收价: "+result["昨日收盘价"]+"\n" +
|
"- 昨收价: "+result["昨日收盘价"]+"\n" +
|
||||||
"- 今开价: "+result["今日开盘价"]+"\n" +
|
"- 今开价: "+result["今日开盘价"]+"\n" +
|
||||||
"- 成本价: "+result.costPrice+" "+result.profit+"% "+result.profitAmount+" ¥\n" +
|
"- 成本价: "+result.costPrice+" "+result.profit+"% "+result.profitAmount+" ¥\n" +
|
||||||
"- 成本数量: "+result.volume+"股\n" +
|
"- 成本数量: "+result.costVolume+"股\n" +
|
||||||
"- 日期: "+result["日期"]+" "+result["时间"]+"\n\n"+
|
"- 日期: "+result["日期"]+" "+result["时间"]+"\n\n"+
|
||||||
"\n"
|
"\n"
|
||||||
let title=result["股票名称"]+"("+result["股票代码"]+") "+result["当前价格"]+" "+result.s
|
let title=result["股票名称"]+"("+result["股票代码"]+") "+result["当前价格"]+" "+result.s
|
||||||
@ -432,7 +432,7 @@ function getHeight() {
|
|||||||
</n-card >
|
</n-card >
|
||||||
</n-gi>
|
</n-gi>
|
||||||
</n-grid>
|
</n-grid>
|
||||||
<n-affix :trigger-bottom="getHeight()/2-10" style="left:0">
|
<n-affix :trigger-bottom="15" style="right:0;z-index: 99990;">
|
||||||
<!-- <n-card :bordered="false">-->
|
<!-- <n-card :bordered="false">-->
|
||||||
<n-input-group>
|
<n-input-group>
|
||||||
|
|
||||||
@ -506,25 +506,5 @@ function getHeight() {
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.result {
|
|
||||||
height: 20px;
|
|
||||||
line-height: 20px;
|
|
||||||
margin: 1.5rem auto;
|
|
||||||
}
|
|
||||||
.input-box {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
.input {
|
|
||||||
width: 200px;
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.light-green {
|
|
||||||
height: 108px;
|
|
||||||
background-color: rgba(0, 128, 0, 0.12);
|
|
||||||
}
|
|
||||||
.green {
|
|
||||||
height: 108px;
|
|
||||||
background-color: rgba(0, 128, 0, 0.24);
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
4
main.go
4
main.go
@ -82,14 +82,14 @@ func main() {
|
|||||||
err := wails.Run(&options.App{
|
err := wails.Run(&options.App{
|
||||||
Title: "go-stock",
|
Title: "go-stock",
|
||||||
Width: 1366,
|
Width: 1366,
|
||||||
Height: 860,
|
Height: 920,
|
||||||
MinWidth: 1024,
|
MinWidth: 1024,
|
||||||
MinHeight: 768,
|
MinHeight: 768,
|
||||||
MaxWidth: 1280,
|
MaxWidth: 1280,
|
||||||
MaxHeight: 960,
|
MaxHeight: 960,
|
||||||
DisableResize: false,
|
DisableResize: false,
|
||||||
Fullscreen: false,
|
Fullscreen: false,
|
||||||
Frameless: false,
|
Frameless: true,
|
||||||
StartHidden: false,
|
StartHidden: false,
|
||||||
HideWindowOnClose: false,
|
HideWindowOnClose: false,
|
||||||
BackgroundColour: &options.RGBA{R: 255, G: 255, B: 255, A: 255},
|
BackgroundColour: &options.RGBA{R: 255, G: 255, B: 255, A: 255},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user