Compare commits

...

11 Commits

Author SHA1 Message Date
spark
9665462ae5 样式修改 2024-12-20 21:02:37 +08:00
spark
71e3953cd8 添加缩略图 2024-12-20 15:06:09 +08:00
spark
bedeaad1f2 添加按钮位置修改 2024-12-20 14:37:38 +08:00
spark
4f05820e2e 优化首次启动速度 2024-12-20 14:34:24 +08:00
spark
abf05aabd8 退出程序添加提示 2024-12-20 14:33:54 +08:00
spark
9016289e96 样式调整 2024-12-20 11:07:46 +08:00
spark
bab53711b7 添加全屏按钮 2024-12-20 11:01:56 +08:00
spark
de67f07f41 修改为深色主题 2024-12-20 10:01:56 +08:00
spark
869223cfb9 修改为深色主题 2024-12-20 10:00:46 +08:00
spark
d240239fcc 窗口标题显示当前时间 2024-12-19 20:59:01 +08:00
spark
6b62385cad 分时图和K线图展示 2024-12-19 13:48:02 +08:00
10 changed files with 128 additions and 36 deletions

1
.gitignore vendored
View File

@@ -109,3 +109,4 @@ dist
data/*.db
build/*.exe
/build/bin/go-stock-dev.exe
/build/bin/

View File

@@ -3,6 +3,16 @@
![Wails and NaiveUI](./build/appicon.png)
## Snapshot
![img_1.png](build/screenshot/img_1.png)
### 成本仓位设置
![img.png](build/screenshot/img.png)
### 日K
![img_2.png](build/screenshot/img_2.png)
### 分时
![img_3.png](build/screenshot/img_3.png)
## About
A China stock data viewer build by [Wails](https://wails.io/) with [NavieUI](https://www.naiveui.com/).

21
app.go
View File

@@ -2,7 +2,9 @@ package main
import (
"context"
"github.com/wailsapp/wails/v2/pkg/runtime"
"go-stock/backend/data"
"go-stock/backend/logger"
)
// App struct
@@ -22,7 +24,7 @@ func (a *App) startup(ctx context.Context) {
}
// domReady is called after front-end resources have been loaded
func (a App) domReady(ctx context.Context) {
func (a *App) domReady(ctx context.Context) {
// Add your action here
}
@@ -30,6 +32,23 @@ func (a App) domReady(ctx context.Context) {
// either by clicking the window close button or calling runtime.Quit.
// Returning true will cause the application to continue, false will continue shutdown as normal.
func (a *App) beforeClose(ctx context.Context) (prevent bool) {
dialog, err := runtime.MessageDialog(ctx, runtime.MessageDialogOptions{
Type: runtime.QuestionDialog,
Title: "go-stock",
Message: "确定关闭吗?",
Buttons: []string{"确定"},
Icon: icon,
CancelButton: "取消",
})
if err != nil {
return false
}
logger.SugaredLogger.Debugf("dialog:%s", dialog)
if dialog == "No" {
return true
}
return false
}

BIN
build/screenshot/img.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

BIN
build/screenshot/img_1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

BIN
build/screenshot/img_2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

BIN
build/screenshot/img_3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

View File

@@ -1,11 +1,13 @@
<script setup>
import stockInfo from './components/stock.vue'
import {ref} from "vue";
import { darkTheme } from 'naive-ui'
const content = ref('数据来源于网络,仅供参考\n投资有风险,入市需谨慎')
</script>
<template>
<n-config-provider :theme="darkTheme">
<n-watermark
:content="content"
cross
@@ -27,6 +29,7 @@ const content = ref('数据来源于网络,仅供参考\n投资有风险,入市
</n-message-provider>
</n-flex>
</n-watermark>
</n-config-provider>
</template>
<style>

View File

@@ -1,7 +1,9 @@
<script setup>
import {h, onBeforeMount, onBeforeUnmount, onMounted, reactive, ref} from 'vue'
import {onBeforeMount, onBeforeUnmount, onMounted, reactive, ref} from 'vue'
import {Greet, Follow, UnFollow, GetFollowList, GetStockList, SetCostPriceAndVolume} from '../../wailsjs/go/main/App'
import {NButton, NFlex, NForm, NFormItem, NInput, NInputNumber, NText, useMessage, useModal} from 'naive-ui'
import {NButton, NFlex, NForm, NFormItem, NInputNumber, NText, useMessage, useModal} from 'naive-ui'
import { WindowFullscreen,WindowUnfullscreen } from '../../wailsjs/runtime'
const message = useMessage()
const modal = useModal()
@@ -13,6 +15,8 @@ const stockList=ref([])
const followList=ref([])
const options=ref([])
const modalShow = ref(false)
const modalShow2 = ref(false)
const modalShow3 = ref(false)
const formModel = ref({
name: "",
code: "",
@@ -23,7 +27,10 @@ const formModel = ref({
const data = reactive({
name: "",
code: "",
fenshiURL:"",
kURL:"",
resultText: "Please enter your name below 👇",
fullscreen: false,
})
@@ -57,7 +64,7 @@ onMounted(() => {
if(isTradingTime()){
monitor()
}
}, 1000)
}, 1500)
})
@@ -119,7 +126,7 @@ function getStockList(){
})
}
function monitor() {
async function monitor() {
for (let code of stocks.value) {
// console.log(code)
Greet(code).then(result => {
@@ -177,6 +184,20 @@ function setStock(code,name){
modalShow.value=true
}
function showFenshi(code,name){
data.code=code
data.name=name
data.fenshiURL='http://image.sinajs.cn/newchart/min/n/'+data.code+'.gif'+"?t="+Date.now()
modalShow2.value=true
}
function showK(code,name){
data.code=code
data.name=name
data.kURL='http://image.sinajs.cn/newchart/daily/n/'+data.code+'.gif'+"?t="+Date.now()
modalShow3.value=true
}
function updateCostPriceAndVolumeNew(code,price,volume){
console.log(code,price,volume)
SetCostPriceAndVolume(code,price,volume).then(result => {
@@ -194,56 +215,77 @@ function updateCostPriceAndVolumeNew(code,price,volume){
})
})
}
function fullscreen(){
if(data.fullscreen){
WindowUnfullscreen()
}else{
WindowFullscreen()
}
data.fullscreen=!data.fullscreen
}
</script>
<template>
<n-grid :x-gap="8" :cols="3" :y-gap="8">
<n-grid :x-gap="8" :cols="3" :y-gap="8" ref="containerRef">
<n-gi v-for="result in results" >
<n-card size="medium" style="min-height: 270px" :data-code="result['股票代码']" :bordered="false" :title="result['股票名称']" :content-style="'font-size: 18px;'" closable @close="removeMonitor(result['股票代码'],result['股票名称'])">
<n-card size="small" :data-code="result['股票代码']" :bordered="false" :title="result['股票名称']" closable @close="removeMonitor(result['股票代码'],result['股票名称'])">
<n-grid :cols="1" :y-gap="6">
<n-gi>
<n-text :type="result.type" >{{result["当前价格"]}}</n-text><n-text style="padding-left: 10px;" :type="result.type">{{ result.s}}</n-text>&nbsp;
<n-text size="small" v-if="result.profitAmountToday>0" :type="result.type">{{result.profitAmountToday}}</n-text>
</n-gi>
</n-grid>
<n-grid :cols="2" :y-gap="4" :x-gap="4" :item-style="'font-size: 14px;'">
<n-gi>
<n-text :type="'info'">{{"最高 "+result["今日最高价"]+" "+result.highRate }}</n-text>
</n-gi>
<n-gi>
<n-text :type="'info'">{{"最低 "+result["今日最低价"]+" "+result.lowRate }}</n-text>
</n-gi>
<n-gi>
<n-text :type="'info'">{{"昨收 "+result["昨日收盘价"]}}</n-text>
</n-gi>
<n-gi>
<n-text :type="'info'">{{"今开 "+result["今日开盘价"]}}</n-text>
</n-gi>
</n-grid>
<n-grid :cols="2" :y-gap="4" :x-gap="4" >
<n-gi>
<n-text :type="'info'">{{"最高 "+result["今日最高价"]+" "+result.highRate }}</n-text>
</n-gi>
<n-gi>
<n-text :type="'info'">{{"最低 "+result["今日最低价"]+" "+result.lowRate }}</n-text>
</n-gi>
<n-gi>
<n-text :type="'info'">{{"昨收 "+result["昨日收盘价"]}}</n-text>
</n-gi>
<n-gi>
<n-text :type="'info'">{{"今开 "+result["今日开盘价"]}}</n-text>
</n-gi>
</n-grid>
<template #header-extra>
<n-tag size="small" v-if="result.volume>0" :type="result.profitType">{{result.volume+""}}</n-tag>
<!-- <n-tag size="small" v-if="result.volume>0" :type="result.profitType">{{result.volume+""}}</n-tag>-->
</template>
<template #footer>
<n-tag size="small" v-if="result.costPrice>0" :type="result.profitType">{{"成本:"+result.costPrice+" "+result.profit+"%"+" ( "+result.profitAmount+" ¥ )"}}</n-tag>
<n-flex justify="center">
<n-tag size="small" v-if="result.volume>0" :type="result.profitType">{{result.volume+""}}</n-tag>
<n-tag size="small" v-if="result.costPrice>0" :type="result.profitType">{{"成本:"+result.costPrice+" "+result.profit+"%"+" ( "+result.profitAmount+" ¥ )"}}</n-tag>
</n-flex>
</template>
<template #action>
<n-flex justify="space-between">
<n-button size="tiny" type="info" @click="setStock(result['股票代码'],result['股票名称'])"> 设置 </n-button>
<n-text :type="'info'">{{result["日期"]+" "+result["时间"]}}</n-text>
<n-button size="tiny" type="info" @click="setStock(result['股票代码'],result['股票名称'])"> 成本 </n-button>
<n-button size="tiny" type="success" @click="showFenshi(result['股票代码'],result['股票名称'])"> 分时 </n-button>
<n-button size="tiny" type="error" @click="showK(result['股票代码'],result['股票名称'])"> 日K </n-button>
<n-button size="tiny" type="warning" @click="search(result['股票代码'],result['股票名称'])"> 详情 </n-button>
</n-flex>
</template>
</n-card >
</n-gi>
<n-gi>
<n-card size="small">
<n-button-group>
<n-auto-complete v-model:value="data.name" type="text"
:input-props="{
autocomplete: 'disabled',
}"
:options="options"
placeholder="输入股票名称或者代码"
clearable class="input" @input="getStockList" :on-select="onSelect"/>
<n-button type="info" @click="AddStock">添加 </n-button>&nbsp;&nbsp;
<n-button type="warning" @click="fullscreen"> {{data.fullscreen?'退出全屏':'全屏'}} </n-button>
</n-button-group>
</n-card>
</n-gi>
</n-grid>
<n-auto-complete v-model:value="data.name" type="text"
:input-props="{
autocomplete: 'disabled',
}"
:options="options"
placeholder="股票名称或者代码"
clearable class="input" @input="getStockList" :on-select="onSelect"/>
<n-button type="info" @click="AddStock"> 添加 </n-button>
<n-modal transform-origin="center" size="small" v-model:show="modalShow" :title="formModel.name" style="width: 400px" :preset="'card'">
<n-form :model="formModel" :rules="{ costPrice: { required: true, message: '请输入成本'}, volume: { required: true, message: '请输入数量'} }" label-placement="left" label-width="80px">
<n-form-item label="成本(元)" path="costPrice">
@@ -257,6 +299,13 @@ function updateCostPriceAndVolumeNew(code,price,volume){
<n-button type="primary" @click="updateCostPriceAndVolumeNew(formModel.code,formModel.costPrice,formModel.volume)">保存</n-button>
</template>
</n-modal>
<n-modal v-model:show="modalShow2" :title="data.name" style="width: 600px" :preset="'card'">
<n-image :src="data.fenshiURL" />
</n-modal>
<n-modal v-model:show="modalShow3" :title="data.name" style="width: 600px" :preset="'card'">
<n-image :src="data.kURL" />
</n-modal>
</template>
<style scoped>

16
main.go
View File

@@ -9,10 +9,12 @@ import (
"github.com/wailsapp/wails/v2/pkg/options"
"github.com/wailsapp/wails/v2/pkg/options/mac"
"github.com/wailsapp/wails/v2/pkg/options/windows"
"github.com/wailsapp/wails/v2/pkg/runtime"
"go-stock/backend/data"
"go-stock/backend/db"
"log"
"os"
"time"
)
//go:embed frontend/dist
@@ -33,14 +35,21 @@ func main() {
db.Dao.AutoMigrate(&data.FollowedStock{})
if stocksBin != nil && len(stocksBin) > 0 {
initStockData()
go initStockData()
}
data.NewStockDataApi().GetStockBaseInfo()
go data.NewStockDataApi().GetStockBaseInfo()
// Create an instance of the app structure
app := NewApp()
ticker := time.NewTicker(time.Second)
defer ticker.Stop()
//定时更新数据
go func() {
for range ticker.C {
runtime.WindowSetTitle(app.ctx, "go-stock "+time.Now().Format("2006-01-02 15:04:05"))
}
}()
// Create application with options
err := wails.Run(&options.App{
Title: "go-stock",
@@ -100,6 +109,7 @@ func main() {
if err != nil {
log.Fatal(err)
}
}
func initStockData() {