Compare commits
11 Commits
1.0.0
...
v2024.12.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9665462ae5 | ||
|
|
71e3953cd8 | ||
|
|
bedeaad1f2 | ||
|
|
4f05820e2e | ||
|
|
abf05aabd8 | ||
|
|
9016289e96 | ||
|
|
bab53711b7 | ||
|
|
de67f07f41 | ||
|
|
869223cfb9 | ||
|
|
d240239fcc | ||
|
|
6b62385cad |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -109,3 +109,4 @@ dist
|
||||
data/*.db
|
||||
build/*.exe
|
||||
/build/bin/go-stock-dev.exe
|
||||
/build/bin/
|
||||
|
||||
10
README.md
10
README.md
@@ -3,6 +3,16 @@
|
||||

|
||||
|
||||
|
||||
## Snapshot
|
||||

|
||||
### 成本仓位设置
|
||||

|
||||
### 日K
|
||||

|
||||
### 分时
|
||||

|
||||
|
||||
|
||||
## About
|
||||
|
||||
A China stock data viewer build by [Wails](https://wails.io/) with [NavieUI](https://www.naiveui.com/).
|
||||
|
||||
21
app.go
21
app.go
@@ -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
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
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
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
BIN
build/screenshot/img_3.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 117 KiB |
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
<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>
|
||||
<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
16
main.go
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user