mirror of
https://github.com/ArvinLovegood/go-stock.git
synced 2025-07-19 00:00:09 +08:00
feat(stock):添加股票分组功能
- 新增股票分组相关接口和页面 - 实现分组添加、删除和股票移除功能 - 优化股票列表展示,支持按分组筛选 - 添加分组相关数据结构和 API
This commit is contained in:
parent
9e5650617b
commit
512f9a0757
78
app.go
78
app.go
@ -101,6 +101,7 @@ func (a *App) startup(ctx context.Context) {
|
|||||||
onExit(a)
|
onExit(a)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
logger.SugaredLogger.Infof(" application startup Version:%s", Version)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) CheckUpdate() {
|
func (a *App) CheckUpdate() {
|
||||||
@ -237,18 +238,19 @@ func (a *App) domReady(ctx context.Context) {
|
|||||||
// logger.SugaredLogger.Infof("Edge浏览器已安装,路径为: %s", path)
|
// logger.SugaredLogger.Infof("Edge浏览器已安装,路径为: %s", path)
|
||||||
// }
|
// }
|
||||||
//}()
|
//}()
|
||||||
followList := data.NewStockDataApi().GetFollowList()
|
followList := data.NewStockDataApi().GetFollowList(0)
|
||||||
for _, follow := range *followList {
|
for _, follow := range *followList {
|
||||||
if follow.Cron == "" {
|
if follow.Cron == nil || *follow.Cron == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
entryID, err := a.cron.AddFunc(follow.Cron, a.AddCronTask(follow))
|
entryID, err := a.cron.AddFunc(*follow.Cron, a.AddCronTask(follow))
|
||||||
logger.SugaredLogger.Errorf("添加自动分析任务:%s cron=%s entryID:%v", follow.Name, follow.Cron, entryID)
|
|
||||||
a.cronEntrys[follow.StockCode] = entryID
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
logger.SugaredLogger.Errorf("添加自动分析任务失败:%s cron=%s entryID:%v", follow.Name, *follow.Cron, entryID)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
a.cronEntrys[follow.StockCode] = entryID
|
||||||
}
|
}
|
||||||
|
logger.SugaredLogger.Infof("domReady-cronEntrys:%+v", a.cronEntrys)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -504,6 +506,7 @@ func addStockFollowData(follow data.FollowedStock, stockData *data.StockInfo) {
|
|||||||
stockData.CostVolume = follow.Volume //成本量
|
stockData.CostVolume = follow.Volume //成本量
|
||||||
stockData.AlarmChangePercent = follow.AlarmChangePercent
|
stockData.AlarmChangePercent = follow.AlarmChangePercent
|
||||||
stockData.AlarmPrice = follow.AlarmPrice
|
stockData.AlarmPrice = follow.AlarmPrice
|
||||||
|
stockData.Groups = follow.Groups
|
||||||
|
|
||||||
//当前价格
|
//当前价格
|
||||||
price, _ := convertor.ToFloat(stockData.Price)
|
price, _ := convertor.ToFloat(stockData.Price)
|
||||||
@ -592,17 +595,19 @@ func (a *App) beforeClose(ctx context.Context) (prevent bool) {
|
|||||||
logger.SugaredLogger.Debugf("dialog:%s", dialog)
|
logger.SugaredLogger.Debugf("dialog:%s", dialog)
|
||||||
if dialog == "No" {
|
if dialog == "No" {
|
||||||
return true
|
return true
|
||||||
|
} else {
|
||||||
|
systray.Quit()
|
||||||
|
a.cron.Stop()
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// shutdown is called at application termination
|
// shutdown is called at application termination
|
||||||
func (a *App) shutdown(ctx context.Context) {
|
func (a *App) shutdown(ctx context.Context) {
|
||||||
defer PanicHandler()
|
defer PanicHandler()
|
||||||
// Perform your teardown here
|
// Perform your teardown here
|
||||||
systray.Quit()
|
//os.Exit(0)
|
||||||
a.cron.Stop()
|
logger.SugaredLogger.Infof("application shutdown Version:%s", Version)
|
||||||
os.Exit(0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Greet returns a greeting for the given name
|
// Greet returns a greeting for the given name
|
||||||
@ -612,7 +617,7 @@ func (a *App) Greet(stockCode string) *data.StockInfo {
|
|||||||
follow := &data.FollowedStock{
|
follow := &data.FollowedStock{
|
||||||
StockCode: stockCode,
|
StockCode: stockCode,
|
||||||
}
|
}
|
||||||
db.Dao.Model(follow).Where("stock_code = ?", stockCode).First(follow)
|
db.Dao.Model(follow).Where("stock_code = ?", stockCode).Preload("Groups").Preload("Groups.GroupInfo").First(follow)
|
||||||
stockInfo := getStockInfo(*follow)
|
stockInfo := getStockInfo(*follow)
|
||||||
return stockInfo
|
return stockInfo
|
||||||
}
|
}
|
||||||
@ -625,8 +630,8 @@ func (a *App) UnFollow(stockCode string) string {
|
|||||||
return data.NewStockDataApi().UnFollow(stockCode)
|
return data.NewStockDataApi().UnFollow(stockCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) GetFollowList() *[]data.FollowedStock {
|
func (a *App) GetFollowList(groupId int) *[]data.FollowedStock {
|
||||||
return data.NewStockDataApi().GetFollowList()
|
return data.NewStockDataApi().GetFollowList(groupId)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) GetStockList(key string) []data.StockBasic {
|
func (a *App) GetStockList(key string) []data.StockBasic {
|
||||||
@ -796,7 +801,7 @@ func getMsgTypeName(msgType int) string {
|
|||||||
|
|
||||||
func onExit(a *App) {
|
func onExit(a *App) {
|
||||||
// 清理操作
|
// 清理操作
|
||||||
logger.SugaredLogger.Infof("onExit")
|
logger.SugaredLogger.Infof("systray onExit")
|
||||||
//systray.Quit()
|
//systray.Quit()
|
||||||
//runtime.Quit(a.ctx)
|
//runtime.Quit(a.ctx)
|
||||||
}
|
}
|
||||||
@ -804,7 +809,7 @@ func onExit(a *App) {
|
|||||||
func onReady(a *App) {
|
func onReady(a *App) {
|
||||||
|
|
||||||
// 初始化操作
|
// 初始化操作
|
||||||
logger.SugaredLogger.Infof("onReady")
|
logger.SugaredLogger.Infof("systray onReady")
|
||||||
systray.SetIcon(icon2)
|
systray.SetIcon(icon2)
|
||||||
systray.SetTitle("go-stock")
|
systray.SetTitle("go-stock")
|
||||||
systray.SetTooltip("go-stock 股票行情实时获取")
|
systray.SetTooltip("go-stock 股票行情实时获取")
|
||||||
@ -988,3 +993,46 @@ func OnSecondInstanceLaunch(secondInstanceData options.SecondInstanceData) {
|
|||||||
}
|
}
|
||||||
time.Sleep(time.Second * 3)
|
time.Sleep(time.Second * 3)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *App) AddGroup(group data.Group) string {
|
||||||
|
ok := data.NewStockGroupApi(db.Dao).AddGroup(group)
|
||||||
|
if ok {
|
||||||
|
return "添加成功"
|
||||||
|
} else {
|
||||||
|
return "添加失败"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func (a *App) GetGroupList() []data.Group {
|
||||||
|
return data.NewStockGroupApi(db.Dao).GetGroupList()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) GetGroupStockList(groupId int) []data.GroupStock {
|
||||||
|
return data.NewStockGroupApi(db.Dao).GetGroupStockByGroupId(groupId)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) AddStockGroup(groupId int, stockCode string) string {
|
||||||
|
ok := data.NewStockGroupApi(db.Dao).AddStockGroup(groupId, stockCode)
|
||||||
|
if ok {
|
||||||
|
return "添加成功"
|
||||||
|
} else {
|
||||||
|
return "添加失败"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) RemoveStockGroup(code, name string, groupId int) string {
|
||||||
|
ok := data.NewStockGroupApi(db.Dao).RemoveStockGroup(code, name, groupId)
|
||||||
|
if ok {
|
||||||
|
return "移除成功"
|
||||||
|
} else {
|
||||||
|
return "移除失败"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) RemoveGroup(groupId int) string {
|
||||||
|
ok := data.NewStockGroupApi(db.Dao).RemoveGroup(groupId)
|
||||||
|
if ok {
|
||||||
|
return "移除成功"
|
||||||
|
} else {
|
||||||
|
return "移除失败"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -344,7 +344,7 @@ func (f *FundApi) CrawlFundNetEstimatedUnit(code string) {
|
|||||||
//logger.SugaredLogger.Infof("基金净值信息:%s", htmlContent)
|
//logger.SugaredLogger.Infof("基金净值信息:%s", htmlContent)
|
||||||
err := json.Unmarshal([]byte(htmlContent), &fundNetUnitValue)
|
err := json.Unmarshal([]byte(htmlContent), &fundNetUnitValue)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.SugaredLogger.Errorf("json.Unmarshal error:%s", err.Error())
|
//logger.SugaredLogger.Errorf("json.Unmarshal error:%s", err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fund := &FollowedFund{
|
fund := &FollowedFund{
|
||||||
|
@ -16,6 +16,7 @@ import (
|
|||||||
"github.com/duke-git/lancet/v2/slice"
|
"github.com/duke-git/lancet/v2/slice"
|
||||||
"github.com/duke-git/lancet/v2/strutil"
|
"github.com/duke-git/lancet/v2/strutil"
|
||||||
"github.com/go-resty/resty/v2"
|
"github.com/go-resty/resty/v2"
|
||||||
|
"github.com/samber/lo"
|
||||||
"go-stock/backend/db"
|
"go-stock/backend/db"
|
||||||
"go-stock/backend/logger"
|
"go-stock/backend/logger"
|
||||||
"go-stock/backend/models"
|
"go-stock/backend/models"
|
||||||
@ -90,6 +91,8 @@ type StockInfo struct {
|
|||||||
Sort int64 `json:"sort"` //排序
|
Sort int64 `json:"sort"` //排序
|
||||||
AlarmChangePercent float64 `json:"alarmChangePercent"`
|
AlarmChangePercent float64 `json:"alarmChangePercent"`
|
||||||
AlarmPrice float64 `json:"alarmPrice"`
|
AlarmPrice float64 `json:"alarmPrice"`
|
||||||
|
|
||||||
|
Groups []GroupStock `gorm:"-:all"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (receiver StockInfo) TableName() string {
|
func (receiver StockInfo) TableName() string {
|
||||||
@ -162,8 +165,9 @@ type FollowedStock struct {
|
|||||||
AlarmPrice float64
|
AlarmPrice float64
|
||||||
Time time.Time
|
Time time.Time
|
||||||
Sort int64
|
Sort int64
|
||||||
Cron string
|
Cron *string
|
||||||
IsDel soft_delete.DeletedAt `gorm:"softDelete:flag"`
|
IsDel soft_delete.DeletedAt `gorm:"softDelete:flag"`
|
||||||
|
Groups []GroupStock `gorm:"foreignKey:StockCode;references:StockCode"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (receiver FollowedStock) TableName() string {
|
func (receiver FollowedStock) TableName() string {
|
||||||
@ -429,9 +433,20 @@ func (receiver StockDataApi) SetStockAICron(cron string, stockCode string) {
|
|||||||
db.Dao.Model(&FollowedStock{}).Where("stock_code = ?", strings.ToLower(stockCode)).Update("cron", cron)
|
db.Dao.Model(&FollowedStock{}).Where("stock_code = ?", strings.ToLower(stockCode)).Update("cron", cron)
|
||||||
|
|
||||||
}
|
}
|
||||||
func (receiver StockDataApi) GetFollowList() *[]FollowedStock {
|
func (receiver StockDataApi) GetFollowList(groupId int) *[]FollowedStock {
|
||||||
|
logger.SugaredLogger.Infof("GetFollowList %d", groupId)
|
||||||
|
|
||||||
var result *[]FollowedStock
|
var result *[]FollowedStock
|
||||||
db.Dao.Model(&FollowedStock{}).Order("sort asc,time desc").Find(&result)
|
if groupId == 0 {
|
||||||
|
db.Dao.Model(&FollowedStock{}).Order("sort asc,time desc").Find(&result)
|
||||||
|
} else {
|
||||||
|
infos := NewStockGroupApi(db.Dao).GetGroupStockByGroupId(groupId)
|
||||||
|
codes := lo.FlatMap(infos, func(info GroupStock, idx int) []string {
|
||||||
|
return []string{info.StockCode}
|
||||||
|
})
|
||||||
|
db.Dao.Model(&FollowedStock{}).Where("stock_code in ?", codes).Order("sort asc,time desc").Find(&result)
|
||||||
|
logger.SugaredLogger.Infof("GetFollowList %+v", result)
|
||||||
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
80
backend/data/stock_group_api.go
Normal file
80
backend/data/stock_group_api.go
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
package data
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go-stock/backend/db"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// @Author spark
|
||||||
|
// @Date 2025/4/3 11:18
|
||||||
|
// @Desc
|
||||||
|
// -----------------------------------------------------------------------------------
|
||||||
|
type Group struct {
|
||||||
|
gorm.Model
|
||||||
|
Name string `json:"name" gorm:"index"`
|
||||||
|
Sort int `json:"sort"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Group) TableName() string {
|
||||||
|
return "stock_groups"
|
||||||
|
}
|
||||||
|
|
||||||
|
type GroupStock struct {
|
||||||
|
gorm.Model
|
||||||
|
StockCode string `json:"stockCode" gorm:"index"`
|
||||||
|
GroupId int `json:"groupId" gorm:"index"`
|
||||||
|
GroupInfo Group `json:"groupInfo" gorm:"foreignKey:GroupId;references:ID"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (GroupStock) TableName() string {
|
||||||
|
return "group_stock_info"
|
||||||
|
}
|
||||||
|
|
||||||
|
type StockGroupApi struct {
|
||||||
|
dao *gorm.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewStockGroupApi(dao *gorm.DB) *StockGroupApi {
|
||||||
|
return &StockGroupApi{dao: db.Dao}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (receiver StockGroupApi) AddGroup(group Group) bool {
|
||||||
|
err := receiver.dao.Where("name = ?", group.Name).FirstOrCreate(&group).Updates(&Group{
|
||||||
|
Name: group.Name,
|
||||||
|
Sort: group.Sort,
|
||||||
|
}).Error
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
|
func (receiver StockGroupApi) GetGroupList() []Group {
|
||||||
|
var groups []Group
|
||||||
|
receiver.dao.Find(&groups)
|
||||||
|
return groups
|
||||||
|
}
|
||||||
|
func (receiver StockGroupApi) GetGroupStockByGroupId(groupId int) []GroupStock {
|
||||||
|
var stockGroup []GroupStock
|
||||||
|
receiver.dao.Preload("GroupInfo").Where("group_id = ?", groupId).Find(&stockGroup)
|
||||||
|
return stockGroup
|
||||||
|
}
|
||||||
|
|
||||||
|
func (receiver StockGroupApi) AddStockGroup(groupId int, stockCode string) bool {
|
||||||
|
err := receiver.dao.Where("group_id = ? and stock_code = ?", groupId, stockCode).FirstOrCreate(&GroupStock{
|
||||||
|
GroupId: groupId,
|
||||||
|
StockCode: stockCode,
|
||||||
|
}).Updates(&GroupStock{
|
||||||
|
GroupId: groupId,
|
||||||
|
StockCode: stockCode,
|
||||||
|
}).Error
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (receiver StockGroupApi) RemoveStockGroup(code string, name string, id int) bool {
|
||||||
|
err := receiver.dao.Where("group_id = ? and stock_code = ?", id, code).Delete(&GroupStock{}).Error
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (receiver StockGroupApi) RemoveGroup(id int) bool {
|
||||||
|
err := receiver.dao.Where("id = ?", id).Delete(&Group{}).Error
|
||||||
|
err = receiver.dao.Where("group_id = ?", id).Delete(&GroupStock{}).Error
|
||||||
|
return err == nil
|
||||||
|
|
||||||
|
}
|
@ -20,7 +20,7 @@ func Init(sqlitePath string) {
|
|||||||
Colorful: false,
|
Colorful: false,
|
||||||
IgnoreRecordNotFoundError: true,
|
IgnoreRecordNotFoundError: true,
|
||||||
ParameterizedQueries: false,
|
ParameterizedQueries: false,
|
||||||
LogLevel: logger.Warn,
|
LogLevel: logger.Info,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
var openDb *gorm.DB
|
var openDb *gorm.DB
|
||||||
|
@ -259,36 +259,36 @@ function deletePrompt(ID){
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<n-flex justify="left" style="margin-top: 12px;padding-left: 12px">
|
<n-flex justify="left" style="margin-top: 12px;padding-left: 12px;">
|
||||||
<n-form ref="formRef" :label-placement="'left'" :label-align="'left'" >
|
<n-form ref="formRef" :label-placement="'left'" :label-align="'left'" >
|
||||||
<n-grid :cols="24" :x-gap="24" style="text-align: left" >
|
<n-grid :cols="24" :x-gap="24" style="text-align: left" :layout-shift-disabled="true">
|
||||||
<n-gi :span="24">
|
<n-gi :span="24">
|
||||||
<n-text type="primary" style="font-size: 25px;font-weight: bold">基础设置</n-text>
|
<n-text type="success" style="font-size: 25px;font-weight: bold">基础设置</n-text>
|
||||||
</n-gi>
|
</n-gi>
|
||||||
<n-form-item-gi :span="10" label="Tushare api token:" path="tushareToken" >
|
<n-form-item-gi :span="10" label="Tushare Token:" path="tushareToken" >
|
||||||
<n-input type="text" placeholder="Tushare api token" v-model:value="formValue.tushareToken" clearable />
|
<n-input type="text" placeholder="Tushare api token" v-model:value="formValue.tushareToken" clearable />
|
||||||
</n-form-item-gi>
|
</n-form-item-gi>
|
||||||
<n-form-item-gi :span="4" label="启动时更新A股/指数信息:" path="updateBasicInfoOnStart" >
|
<n-form-item-gi :span="4" label="启动时更新A股/指数信息:" path="updateBasicInfoOnStart" >
|
||||||
<n-switch v-model:value="formValue.updateBasicInfoOnStart" />
|
<n-switch v-model:value="formValue.updateBasicInfoOnStart" />
|
||||||
</n-form-item-gi>
|
</n-form-item-gi>
|
||||||
<n-form-item-gi :span="5" label="数据刷新间隔:" path="refreshInterval" >
|
<n-form-item-gi :span="4" label="数据刷新间隔:" path="refreshInterval" >
|
||||||
<n-input-number v-model:value="formValue.refreshInterval" placeholder="请输入数据刷新间隔(秒)">
|
<n-input-number v-model:value="formValue.refreshInterval" placeholder="请输入数据刷新间隔(秒)">
|
||||||
<template #suffix>
|
<template #suffix>
|
||||||
秒
|
秒
|
||||||
</template>
|
</template>
|
||||||
</n-input-number>
|
</n-input-number>
|
||||||
</n-form-item-gi>
|
</n-form-item-gi>
|
||||||
<n-form-item-gi :span="5" label="暗黑主题:" path="darkTheme" >
|
<n-form-item-gi :span="6" label="暗黑主题:" path="darkTheme" >
|
||||||
<n-switch v-model:value="formValue.darkTheme" />
|
<n-switch v-model:value="formValue.darkTheme" />
|
||||||
</n-form-item-gi>
|
</n-form-item-gi>
|
||||||
<n-form-item-gi :span="22" label="浏览器路径:" path="browserPath" >
|
<n-form-item-gi :span="10" label="浏览器安装路径:" path="browserPath" >
|
||||||
<n-input type="text" placeholder="浏览器路径" v-model:value="formValue.browserPath" clearable />
|
<n-input type="text" placeholder="浏览器安装路径" v-model:value="formValue.browserPath" clearable />
|
||||||
</n-form-item-gi>
|
</n-form-item-gi>
|
||||||
</n-grid>
|
</n-grid>
|
||||||
|
|
||||||
<n-grid :cols="24" :x-gap="24" style="text-align: left">
|
<n-grid :cols="24" :x-gap="24" style="text-align: left">
|
||||||
<n-gi :span="24">
|
<n-gi :span="24">
|
||||||
<n-text type="primary" style="font-size: 25px;font-weight: bold">通知设置</n-text>
|
<n-text type="success" style="font-size: 25px;font-weight: bold">通知设置</n-text>
|
||||||
</n-gi>
|
</n-gi>
|
||||||
<n-form-item-gi :span="6" label="是否启用钉钉推送:" path="dingPush.enable" >
|
<n-form-item-gi :span="6" label="是否启用钉钉推送:" path="dingPush.enable" >
|
||||||
<n-switch v-model:value="formValue.dingPush.enable" />
|
<n-switch v-model:value="formValue.dingPush.enable" />
|
||||||
@ -310,7 +310,7 @@ function deletePrompt(ID){
|
|||||||
|
|
||||||
<n-grid :cols="24" :x-gap="24" style="text-align: left;">
|
<n-grid :cols="24" :x-gap="24" style="text-align: left;">
|
||||||
<n-gi :span="24">
|
<n-gi :span="24">
|
||||||
<n-text type="primary" style="font-size: 25px;font-weight: bold">OpenAI设置</n-text>
|
<n-text type="success" style="font-size: 25px;font-weight: bold">OpenAI设置</n-text>
|
||||||
</n-gi>
|
</n-gi>
|
||||||
<n-form-item-gi :span="3" label="是否启用AI诊股:" path="openAI.enable" >
|
<n-form-item-gi :span="3" label="是否启用AI诊股:" path="openAI.enable" >
|
||||||
<n-switch v-model:value="formValue.openAI.enable" />
|
<n-switch v-model:value="formValue.openAI.enable" />
|
||||||
|
@ -15,7 +15,14 @@ import {
|
|||||||
SetCostPriceAndVolume,
|
SetCostPriceAndVolume,
|
||||||
SetStockSort,
|
SetStockSort,
|
||||||
UnFollow,
|
UnFollow,
|
||||||
ShareAnalysis, SaveAsMarkdown, GetPromptTemplates, SetStockAICron
|
ShareAnalysis,
|
||||||
|
SaveAsMarkdown,
|
||||||
|
GetPromptTemplates,
|
||||||
|
SetStockAICron,
|
||||||
|
AddGroup,
|
||||||
|
GetGroupList,
|
||||||
|
AddStockGroup,
|
||||||
|
RemoveStockGroup, RemoveGroup
|
||||||
} from '../../wailsjs/go/main/App'
|
} from '../../wailsjs/go/main/App'
|
||||||
import {
|
import {
|
||||||
NAvatar,
|
NAvatar,
|
||||||
@ -47,15 +54,15 @@ import {asBlob} from 'html-docx-js-typescript';
|
|||||||
|
|
||||||
import vueDanmaku from 'vue3-danmaku'
|
import vueDanmaku from 'vue3-danmaku'
|
||||||
import {keys, pad, padStart} from "lodash";
|
import {keys, pad, padStart} from "lodash";
|
||||||
|
import {models} from "../../wailsjs/go/models";
|
||||||
const danmus = ref([])
|
const danmus = ref([])
|
||||||
const ws = ref(null)
|
const ws = ref(null)
|
||||||
|
const dialog = useDialog()
|
||||||
const toolbars = [0];
|
const toolbars = [0];
|
||||||
const handleProgress = (progress) => {
|
const handleProgress = (progress) => {
|
||||||
console.log(`Export progress: ${progress.ratio * 100}%`);
|
console.log(`Export progress: ${progress.ratio * 100}%`);
|
||||||
};
|
};
|
||||||
const enableEditor= ref(false)
|
const enableEditor= ref(false)
|
||||||
|
|
||||||
const mdPreviewRef = ref(null)
|
const mdPreviewRef = ref(null)
|
||||||
const mdEditorRef = ref(null)
|
const mdEditorRef = ref(null)
|
||||||
const tipsRef = ref(null)
|
const tipsRef = ref(null)
|
||||||
@ -65,6 +72,7 @@ const stocks=ref([])
|
|||||||
const results=ref({})
|
const results=ref({})
|
||||||
const stockList=ref([])
|
const stockList=ref([])
|
||||||
const followList=ref([])
|
const followList=ref([])
|
||||||
|
const groupList=ref([])
|
||||||
const options=ref([])
|
const options=ref([])
|
||||||
const modalShow = ref(false)
|
const modalShow = ref(false)
|
||||||
const modalShow2 = ref(false)
|
const modalShow2 = ref(false)
|
||||||
@ -81,6 +89,7 @@ const formModel = ref({
|
|||||||
sort:999,
|
sort:999,
|
||||||
cron:"",
|
cron:"",
|
||||||
})
|
})
|
||||||
|
|
||||||
const promptTemplates=ref([])
|
const promptTemplates=ref([])
|
||||||
const sysPromptOptions=ref([])
|
const sysPromptOptions=ref([])
|
||||||
const userPromptOptions=ref([])
|
const userPromptOptions=ref([])
|
||||||
@ -101,7 +110,7 @@ const data = reactive({
|
|||||||
enableDanmu: false,
|
enableDanmu: false,
|
||||||
darkTheme:false,
|
darkTheme:false,
|
||||||
})
|
})
|
||||||
|
const currentGroupId=ref(0)
|
||||||
const theme=computed(() => {
|
const theme=computed(() => {
|
||||||
return data.darkTheme ? 'dark' : 'light'
|
return data.darkTheme ? 'dark' : 'light'
|
||||||
})
|
})
|
||||||
@ -115,15 +124,29 @@ const icon = ref('https://raw.githubusercontent.com/ArvinLovegood/go-stock/maste
|
|||||||
const sortedResults = computed(() => {
|
const sortedResults = computed(() => {
|
||||||
//console.log("computed",sortedResults.value)
|
//console.log("computed",sortedResults.value)
|
||||||
const sortedKeys =keys(results.value).sort();
|
const sortedKeys =keys(results.value).sort();
|
||||||
console.log("sortedKeys",sortedKeys)
|
//console.log("sortedKeys",sortedKeys)
|
||||||
const sortedObject = {};
|
const sortedObject = {};
|
||||||
sortedKeys.forEach(key => {
|
sortedKeys.forEach(key => {
|
||||||
sortedObject[key] = results.value[key];
|
sortedObject[key] = results.value[key];
|
||||||
});
|
});
|
||||||
return sortedObject
|
return sortedObject
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const groupResults=computed(() => {
|
||||||
|
const group={}
|
||||||
|
for (const key in sortedResults.value) {
|
||||||
|
if(stocks.value.includes(sortedResults.value[key]['股票代码'])){
|
||||||
|
group[key]=sortedResults.value[key]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return group
|
||||||
|
})
|
||||||
|
|
||||||
onBeforeMount(()=>{
|
onBeforeMount(()=>{
|
||||||
|
|
||||||
|
GetGroupList().then(result => {
|
||||||
|
groupList.value=result
|
||||||
|
})
|
||||||
GetStockList("").then(result => {
|
GetStockList("").then(result => {
|
||||||
stockList.value = result
|
stockList.value = result
|
||||||
options.value=result.map(item => {
|
options.value=result.map(item => {
|
||||||
@ -133,7 +156,7 @@ onBeforeMount(()=>{
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
GetFollowList().then(result => {
|
GetFollowList(currentGroupId.value).then(result => {
|
||||||
followList.value = result
|
followList.value = result
|
||||||
for (const followedStock of result) {
|
for (const followedStock of result) {
|
||||||
if(followedStock.StockCode.startsWith("us")){
|
if(followedStock.StockCode.startsWith("us")){
|
||||||
@ -495,6 +518,8 @@ async function updateData(result) {
|
|||||||
//result.key=result.sort
|
//result.key=result.sort
|
||||||
result.key=GetSortKey(result.sort,result["股票代码"])
|
result.key=GetSortKey(result.sort,result["股票代码"])
|
||||||
results.value[GetSortKey(result.sort,result["股票代码"])]=result
|
results.value[GetSortKey(result.sort,result["股票代码"])]=result
|
||||||
|
|
||||||
|
console.log("updateData",result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -510,7 +535,7 @@ async function monitor() {
|
|||||||
|
|
||||||
function GetSortKey(sort,code){
|
function GetSortKey(sort,code){
|
||||||
let sortKey= padStart(sort,8,'0')+"_"+code
|
let sortKey= padStart(sort,8,'0')+"_"+code
|
||||||
console.log("GetSortKey:",sortKey)
|
//console.log("GetSortKey:",sortKey)
|
||||||
return sortKey
|
return sortKey
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -603,7 +628,7 @@ function updateCostPriceAndVolumeNew(code,price,volume,alarm,formModel){
|
|||||||
SetCostPriceAndVolume(code,price,volume).then(result => {
|
SetCostPriceAndVolume(code,price,volume).then(result => {
|
||||||
modalShow.value=false
|
modalShow.value=false
|
||||||
message.success(result)
|
message.success(result)
|
||||||
GetFollowList().then(result => {
|
GetFollowList(currentGroupId.value).then(result => {
|
||||||
followList.value = result
|
followList.value = result
|
||||||
for (const followedStock of result) {
|
for (const followedStock of result) {
|
||||||
if (!stocks.value.includes(followedStock.StockCode)) {
|
if (!stocks.value.includes(followedStock.StockCode)) {
|
||||||
@ -851,6 +876,73 @@ function share(code,name){
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
const addTabModel=ref({
|
||||||
|
name: '',
|
||||||
|
sort: 1,
|
||||||
|
})
|
||||||
|
const addTabPane=ref(false)
|
||||||
|
function addTab(){
|
||||||
|
addTabPane.value=true
|
||||||
|
}
|
||||||
|
function saveTabPane(){
|
||||||
|
AddGroup(addTabModel.value).then(result => {
|
||||||
|
message.info(result)
|
||||||
|
addTabPane.value=false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
function AddStockGroupInfo(groupId,code,name){
|
||||||
|
if(code.startsWith("gb_")){
|
||||||
|
code="us"+ code.replace("gb_", "").toLowerCase()
|
||||||
|
}
|
||||||
|
AddStockGroup(groupId,code).then(result => {
|
||||||
|
message.info(result)
|
||||||
|
GetGroupList().then(result => {
|
||||||
|
groupList.value=result
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
function updateTab(name){
|
||||||
|
currentGroupId.value=Number(name)
|
||||||
|
GetFollowList(currentGroupId.value).then(result => {
|
||||||
|
stocks.value=[]
|
||||||
|
console.log("GetFollowList",result)
|
||||||
|
followList.value = result
|
||||||
|
for (const followedStock of result) {
|
||||||
|
if(followedStock.StockCode.startsWith("us")){
|
||||||
|
followedStock.StockCode="gb_"+ followedStock.StockCode.replace("us", "").toLowerCase()
|
||||||
|
}
|
||||||
|
//console.log("followList",followedStock.StockCode)
|
||||||
|
stocks.value.push(followedStock.StockCode)
|
||||||
|
}
|
||||||
|
monitor()
|
||||||
|
message.destroyAll()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
function delTab(name){
|
||||||
|
let infos=groupList.value=groupList.value.filter(item => item.ID === Number(name))
|
||||||
|
dialog.create({
|
||||||
|
title: '删除分组',
|
||||||
|
type: 'warning',
|
||||||
|
content: '确定要删除['+infos[0].name+']分组吗?分组数据将不能恢复哟!',
|
||||||
|
positiveText: '确定',
|
||||||
|
negativeText: '取消',
|
||||||
|
onPositiveClick: () => {
|
||||||
|
RemoveGroup(name).then(result => {
|
||||||
|
message.info(result)
|
||||||
|
GetGroupList().then(result => {
|
||||||
|
groupList.value=result
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
function delStockGroup(code,name,groupId){
|
||||||
|
RemoveStockGroup(code,name,groupId).then(result => {
|
||||||
|
updateTab(groupId)
|
||||||
|
message.info(result)
|
||||||
|
})
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -861,8 +953,10 @@ function share(code,name){
|
|||||||
</n-gradient-text>
|
</n-gradient-text>
|
||||||
</template>
|
</template>
|
||||||
</vue-danmaku>
|
</vue-danmaku>
|
||||||
<n-grid :x-gap="8" :cols="3" :y-gap="8" >
|
<n-tabs type="card" animated addable @add="addTab" @update-value="updateTab" placement="top" @close="(key)=>{delTab(key)}">
|
||||||
<n-gi :id="result['股票代码']+'_gi'" v-for="result in sortedResults" style="margin-left: 2px;" >
|
<n-tab-pane name="0" tab="全部">
|
||||||
|
<n-grid :x-gap="8" :cols="3" :y-gap="8" >
|
||||||
|
<n-gi :id="result['股票代码']+'_gi'" v-for="result in sortedResults" style="margin-left: 2px;" >
|
||||||
<n-card :data-sort="result.sort" :id="result['股票代码']" :data-code="result['股票代码']" :bordered="true" :title="result['股票名称']" :closable="false" @close="removeMonitor(result['股票代码'],result['股票名称'],result.key)">
|
<n-card :data-sort="result.sort" :id="result['股票代码']" :data-code="result['股票代码']" :bordered="true" :title="result['股票名称']" :closable="false" @close="removeMonitor(result['股票代码'],result['股票名称'],result.key)">
|
||||||
<n-grid :cols="1" :y-gap="6">
|
<n-grid :cols="1" :y-gap="6">
|
||||||
<n-gi>
|
<n-gi>
|
||||||
@ -916,11 +1010,82 @@ function share(code,name){
|
|||||||
<n-button size="tiny" type="success" @click="showFenshi(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="error" @click="showK(result['股票代码'],result['股票名称'])"> 日K </n-button>
|
||||||
<n-button size="tiny" type="warning" @click="search(result['股票代码'],result['股票名称'])"> 详情 </n-button>
|
<n-button size="tiny" type="warning" @click="search(result['股票代码'],result['股票名称'])"> 详情 </n-button>
|
||||||
|
<n-dropdown trigger="click" :options="groupList" key-field="ID" label-field="name" @select="(groupId) => AddStockGroupInfo(groupId,result['股票代码'],result['股票名称'])">
|
||||||
|
<n-button type="success" size="tiny">设置分组</n-button>
|
||||||
|
</n-dropdown>
|
||||||
</n-flex>
|
</n-flex>
|
||||||
</template>
|
</template>
|
||||||
</n-card >
|
</n-card >
|
||||||
</n-gi>
|
</n-gi>
|
||||||
</n-grid>
|
</n-grid>
|
||||||
|
</n-tab-pane>
|
||||||
|
<n-tab-pane closable v-for="group in groupList" :group-id="group.ID" :name="group.ID" :tab="group.name">
|
||||||
|
<n-grid :x-gap="8" :cols="3" :y-gap="8" >
|
||||||
|
<n-gi :id="result['股票代码']+'_gi'" v-for="result in groupResults" style="margin-left: 2px;" >
|
||||||
|
<n-card :data-sort="result.sort" :id="result['股票代码']" :data-code="result['股票代码']" :bordered="true" :title="result['股票名称']" :closable="false" @close="removeMonitor(result['股票代码'],result['股票名称'],result.key)">
|
||||||
|
<n-grid :cols="1" :y-gap="6">
|
||||||
|
<n-gi>
|
||||||
|
<n-text :type="result.type" >
|
||||||
|
<n-number-animation :duration="1000" :precision="2" :from="result['上次当前价格']" :to="Number(result['当前价格'])" />
|
||||||
|
<n-tag size="small" :type="result.type" :bordered="false" v-if="result['盘前盘后']>0">({{result['盘前盘后']}} {{result['盘前盘后涨跌幅']}}%)</n-tag>
|
||||||
|
</n-text>
|
||||||
|
<n-text style="padding-left: 10px;" :type="result.type">
|
||||||
|
<n-number-animation :duration="1000" :precision="3" :from="0" :to="result.changePercent" />%
|
||||||
|
</n-text>
|
||||||
|
<n-text size="small" v-if="result.costVolume>0" :type="result.type">
|
||||||
|
<n-number-animation :duration="1000" :precision="2" :from="0" :to="result.profitAmountToday" />
|
||||||
|
</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" :bordered="false">{{result['股票代码']}}</n-tag>
|
||||||
|
<n-button size="tiny" secondary type="primary" @click="removeMonitor(result['股票代码'],result['股票名称'],result.key)">
|
||||||
|
取消关注
|
||||||
|
</n-button>
|
||||||
|
<n-button size="tiny" v-if="data.openAiEnable" secondary type="warning" @click="aiCheckStock(result['股票名称'],result['股票代码'])">
|
||||||
|
AI分析
|
||||||
|
</n-button>
|
||||||
|
<n-button secondary type="error" size="tiny" @click="delStockGroup(result['股票代码'],result['股票名称'],group.ID)">移出分组</n-button>
|
||||||
|
</template>
|
||||||
|
<template #footer>
|
||||||
|
<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.costVolume+" "+result.profit+"%"+" ( "+result.profitAmount+" ¥ )"}}</n-tag>
|
||||||
|
</n-flex>
|
||||||
|
</template>
|
||||||
|
<template #action>
|
||||||
|
<n-flex justify="space-between">
|
||||||
|
<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-dropdown trigger="click" :options="groupList" key-field="ID" label-field="name" @select="(groupId) => AddStockGroupInfo(groupId,result['股票代码'],result['股票名称'])">
|
||||||
|
<n-button type="success" size="tiny">设置分组</n-button>
|
||||||
|
</n-dropdown>
|
||||||
|
|
||||||
|
</n-flex>
|
||||||
|
</template>
|
||||||
|
</n-card >
|
||||||
|
</n-gi>
|
||||||
|
</n-grid>
|
||||||
|
</n-tab-pane>
|
||||||
|
</n-tabs>
|
||||||
<div style="position: fixed;bottom: 18px;right:5px;z-index: 10;width: 400px">
|
<div style="position: fixed;bottom: 18px;right:5px;z-index: 10;width: 400px">
|
||||||
<!-- <n-card :bordered="false">-->
|
<!-- <n-card :bordered="false">-->
|
||||||
<n-input-group >
|
<n-input-group >
|
||||||
@ -991,6 +1156,31 @@ function share(code,name){
|
|||||||
</template>
|
</template>
|
||||||
</n-modal>
|
</n-modal>
|
||||||
|
|
||||||
|
<n-modal v-model:show="addTabPane" title="添加分组" style="width: 400px;text-align: left" :preset="'card'">
|
||||||
|
<n-form
|
||||||
|
:model="addTabModel"
|
||||||
|
size="medium"
|
||||||
|
label-placement="left"
|
||||||
|
> <n-grid :cols="2" >
|
||||||
|
<n-form-item-gi label="分组名称:" path="name" :span="5">
|
||||||
|
<n-input v-model:value="addTabModel.name" style="width: 100%" placeholder="请输入分组名称" />
|
||||||
|
</n-form-item-gi>
|
||||||
|
<n-form-item-gi label="分组排序:" path="sort" :span="5">
|
||||||
|
<n-input-number v-model:value="addTabModel.sort" style="width: 100%" min="0" placeholder="请输入分组排序值" ></n-input-number>
|
||||||
|
</n-form-item-gi>
|
||||||
|
</n-grid>
|
||||||
|
</n-form>
|
||||||
|
<template #footer>
|
||||||
|
<n-flex justify="end">
|
||||||
|
<n-button type="primary" @click="saveTabPane">
|
||||||
|
保存
|
||||||
|
</n-button>
|
||||||
|
<n-button type="warning" @click="addTabPane=false">
|
||||||
|
取消
|
||||||
|
</n-button>
|
||||||
|
</n-flex>
|
||||||
|
</template>
|
||||||
|
</n-modal>
|
||||||
<n-modal v-model:show="modalShow2" :title="data.name" style="width: 600px" :preset="'card'">
|
<n-modal v-model:show="modalShow2" :title="data.name" style="width: 600px" :preset="'card'">
|
||||||
<n-image :src="data.fenshiURL" />
|
<n-image :src="data.fenshiURL" />
|
||||||
</n-modal>
|
</n-modal>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { createMemoryHistory, createRouter } from 'vue-router'
|
import {createMemoryHistory, createRouter, createWebHashHistory} from 'vue-router'
|
||||||
|
|
||||||
import stockView from '../components/stock.vue'
|
import stockView from '../components/stock.vue'
|
||||||
import settingsView from '../components/settings.vue'
|
import settingsView from '../components/settings.vue'
|
||||||
@ -13,7 +13,7 @@ const routes = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createMemoryHistory(),
|
history: createWebHashHistory(),
|
||||||
routes,
|
routes,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
14
frontend/wailsjs/go/main/App.d.ts
vendored
14
frontend/wailsjs/go/main/App.d.ts
vendored
@ -5,8 +5,12 @@ import {models} from '../models';
|
|||||||
|
|
||||||
export function AddCronTask(arg1:data.FollowedStock):Promise<any>;
|
export function AddCronTask(arg1:data.FollowedStock):Promise<any>;
|
||||||
|
|
||||||
|
export function AddGroup(arg1:data.Group):Promise<string>;
|
||||||
|
|
||||||
export function AddPrompt(arg1:models.Prompt):Promise<string>;
|
export function AddPrompt(arg1:models.Prompt):Promise<string>;
|
||||||
|
|
||||||
|
export function AddStockGroup(arg1:number,arg2:string):Promise<string>;
|
||||||
|
|
||||||
export function CheckUpdate():Promise<void>;
|
export function CheckUpdate():Promise<void>;
|
||||||
|
|
||||||
export function DelPrompt(arg1:number):Promise<string>;
|
export function DelPrompt(arg1:number):Promise<string>;
|
||||||
@ -21,10 +25,14 @@ export function GetAIResponseResult(arg1:string):Promise<models.AIResponseResult
|
|||||||
|
|
||||||
export function GetConfig():Promise<data.Settings>;
|
export function GetConfig():Promise<data.Settings>;
|
||||||
|
|
||||||
export function GetFollowList():Promise<any>;
|
export function GetFollowList(arg1:number):Promise<any>;
|
||||||
|
|
||||||
export function GetFollowedFund():Promise<Array<data.FollowedFund>>;
|
export function GetFollowedFund():Promise<Array<data.FollowedFund>>;
|
||||||
|
|
||||||
|
export function GetGroupList():Promise<Array<data.Group>>;
|
||||||
|
|
||||||
|
export function GetGroupStockList(arg1:number):Promise<Array<data.GroupStock>>;
|
||||||
|
|
||||||
export function GetPromptTemplates(arg1:string,arg2:string):Promise<any>;
|
export function GetPromptTemplates(arg1:string,arg2:string):Promise<any>;
|
||||||
|
|
||||||
export function GetStockList(arg1:string):Promise<Array<data.StockBasic>>;
|
export function GetStockList(arg1:string):Promise<Array<data.StockBasic>>;
|
||||||
@ -37,6 +45,10 @@ export function Greet(arg1:string):Promise<data.StockInfo>;
|
|||||||
|
|
||||||
export function NewChatStream(arg1:string,arg2:string,arg3:string,arg4:any):Promise<void>;
|
export function NewChatStream(arg1:string,arg2:string,arg3:string,arg4:any):Promise<void>;
|
||||||
|
|
||||||
|
export function RemoveGroup(arg1:number):Promise<string>;
|
||||||
|
|
||||||
|
export function RemoveStockGroup(arg1:string,arg2:string,arg3:number):Promise<string>;
|
||||||
|
|
||||||
export function SaveAIResponseResult(arg1:string,arg2:string,arg3:string,arg4:string,arg5:string):Promise<void>;
|
export function SaveAIResponseResult(arg1:string,arg2:string,arg3:string,arg4:string,arg5:string):Promise<void>;
|
||||||
|
|
||||||
export function SaveAsMarkdown(arg1:string,arg2:string):Promise<string>;
|
export function SaveAsMarkdown(arg1:string,arg2:string):Promise<string>;
|
||||||
|
@ -6,10 +6,18 @@ export function AddCronTask(arg1) {
|
|||||||
return window['go']['main']['App']['AddCronTask'](arg1);
|
return window['go']['main']['App']['AddCronTask'](arg1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function AddGroup(arg1) {
|
||||||
|
return window['go']['main']['App']['AddGroup'](arg1);
|
||||||
|
}
|
||||||
|
|
||||||
export function AddPrompt(arg1) {
|
export function AddPrompt(arg1) {
|
||||||
return window['go']['main']['App']['AddPrompt'](arg1);
|
return window['go']['main']['App']['AddPrompt'](arg1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function AddStockGroup(arg1, arg2) {
|
||||||
|
return window['go']['main']['App']['AddStockGroup'](arg1, arg2);
|
||||||
|
}
|
||||||
|
|
||||||
export function CheckUpdate() {
|
export function CheckUpdate() {
|
||||||
return window['go']['main']['App']['CheckUpdate']();
|
return window['go']['main']['App']['CheckUpdate']();
|
||||||
}
|
}
|
||||||
@ -38,14 +46,22 @@ export function GetConfig() {
|
|||||||
return window['go']['main']['App']['GetConfig']();
|
return window['go']['main']['App']['GetConfig']();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function GetFollowList() {
|
export function GetFollowList(arg1) {
|
||||||
return window['go']['main']['App']['GetFollowList']();
|
return window['go']['main']['App']['GetFollowList'](arg1);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function GetFollowedFund() {
|
export function GetFollowedFund() {
|
||||||
return window['go']['main']['App']['GetFollowedFund']();
|
return window['go']['main']['App']['GetFollowedFund']();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function GetGroupList() {
|
||||||
|
return window['go']['main']['App']['GetGroupList']();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function GetGroupStockList(arg1) {
|
||||||
|
return window['go']['main']['App']['GetGroupStockList'](arg1);
|
||||||
|
}
|
||||||
|
|
||||||
export function GetPromptTemplates(arg1, arg2) {
|
export function GetPromptTemplates(arg1, arg2) {
|
||||||
return window['go']['main']['App']['GetPromptTemplates'](arg1, arg2);
|
return window['go']['main']['App']['GetPromptTemplates'](arg1, arg2);
|
||||||
}
|
}
|
||||||
@ -70,6 +86,14 @@ export function NewChatStream(arg1, arg2, arg3, arg4) {
|
|||||||
return window['go']['main']['App']['NewChatStream'](arg1, arg2, arg3, arg4);
|
return window['go']['main']['App']['NewChatStream'](arg1, arg2, arg3, arg4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function RemoveGroup(arg1) {
|
||||||
|
return window['go']['main']['App']['RemoveGroup'](arg1);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function RemoveStockGroup(arg1, arg2, arg3) {
|
||||||
|
return window['go']['main']['App']['RemoveStockGroup'](arg1, arg2, arg3);
|
||||||
|
}
|
||||||
|
|
||||||
export function SaveAIResponseResult(arg1, arg2, arg3, arg4, arg5) {
|
export function SaveAIResponseResult(arg1, arg2, arg3, arg4, arg5) {
|
||||||
return window['go']['main']['App']['SaveAIResponseResult'](arg1, arg2, arg3, arg4, arg5);
|
return window['go']['main']['App']['SaveAIResponseResult'](arg1, arg2, arg3, arg4, arg5);
|
||||||
}
|
}
|
||||||
|
@ -142,41 +142,29 @@ export namespace data {
|
|||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export class FollowedStock {
|
export class Group {
|
||||||
StockCode: string;
|
ID: number;
|
||||||
Name: string;
|
|
||||||
Volume: number;
|
|
||||||
CostPrice: number;
|
|
||||||
Price: number;
|
|
||||||
PriceChange: number;
|
|
||||||
ChangePercent: number;
|
|
||||||
AlarmChangePercent: number;
|
|
||||||
AlarmPrice: number;
|
|
||||||
// Go type: time
|
// Go type: time
|
||||||
Time: any;
|
CreatedAt: any;
|
||||||
Sort: number;
|
// Go type: time
|
||||||
Cron: string;
|
UpdatedAt: any;
|
||||||
IsDel: number;
|
// Go type: gorm
|
||||||
|
DeletedAt: any;
|
||||||
|
name: string;
|
||||||
|
sort: number;
|
||||||
|
|
||||||
static createFrom(source: any = {}) {
|
static createFrom(source: any = {}) {
|
||||||
return new FollowedStock(source);
|
return new Group(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(source: any = {}) {
|
constructor(source: any = {}) {
|
||||||
if ('string' === typeof source) source = JSON.parse(source);
|
if ('string' === typeof source) source = JSON.parse(source);
|
||||||
this.StockCode = source["StockCode"];
|
this.ID = source["ID"];
|
||||||
this.Name = source["Name"];
|
this.CreatedAt = this.convertValues(source["CreatedAt"], null);
|
||||||
this.Volume = source["Volume"];
|
this.UpdatedAt = this.convertValues(source["UpdatedAt"], null);
|
||||||
this.CostPrice = source["CostPrice"];
|
this.DeletedAt = this.convertValues(source["DeletedAt"], null);
|
||||||
this.Price = source["Price"];
|
this.name = source["name"];
|
||||||
this.PriceChange = source["PriceChange"];
|
this.sort = source["sort"];
|
||||||
this.ChangePercent = source["ChangePercent"];
|
|
||||||
this.AlarmChangePercent = source["AlarmChangePercent"];
|
|
||||||
this.AlarmPrice = source["AlarmPrice"];
|
|
||||||
this.Time = this.convertValues(source["Time"], null);
|
|
||||||
this.Sort = source["Sort"];
|
|
||||||
this.Cron = source["Cron"];
|
|
||||||
this.IsDel = source["IsDel"];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
convertValues(a: any, classs: any, asMap: boolean = false): any {
|
convertValues(a: any, classs: any, asMap: boolean = false): any {
|
||||||
@ -197,6 +185,110 @@ export namespace data {
|
|||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
export class GroupStock {
|
||||||
|
ID: number;
|
||||||
|
// Go type: time
|
||||||
|
CreatedAt: any;
|
||||||
|
// Go type: time
|
||||||
|
UpdatedAt: any;
|
||||||
|
// Go type: gorm
|
||||||
|
DeletedAt: any;
|
||||||
|
stockCode: string;
|
||||||
|
groupId: number;
|
||||||
|
groupInfo: Group;
|
||||||
|
|
||||||
|
static createFrom(source: any = {}) {
|
||||||
|
return new GroupStock(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(source: any = {}) {
|
||||||
|
if ('string' === typeof source) source = JSON.parse(source);
|
||||||
|
this.ID = source["ID"];
|
||||||
|
this.CreatedAt = this.convertValues(source["CreatedAt"], null);
|
||||||
|
this.UpdatedAt = this.convertValues(source["UpdatedAt"], null);
|
||||||
|
this.DeletedAt = this.convertValues(source["DeletedAt"], null);
|
||||||
|
this.stockCode = source["stockCode"];
|
||||||
|
this.groupId = source["groupId"];
|
||||||
|
this.groupInfo = this.convertValues(source["groupInfo"], Group);
|
||||||
|
}
|
||||||
|
|
||||||
|
convertValues(a: any, classs: any, asMap: boolean = false): any {
|
||||||
|
if (!a) {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
if (a.slice && a.map) {
|
||||||
|
return (a as any[]).map(elem => this.convertValues(elem, classs));
|
||||||
|
} else if ("object" === typeof a) {
|
||||||
|
if (asMap) {
|
||||||
|
for (const key of Object.keys(a)) {
|
||||||
|
a[key] = new classs(a[key]);
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
return new classs(a);
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export class FollowedStock {
|
||||||
|
StockCode: string;
|
||||||
|
Name: string;
|
||||||
|
Volume: number;
|
||||||
|
CostPrice: number;
|
||||||
|
Price: number;
|
||||||
|
PriceChange: number;
|
||||||
|
ChangePercent: number;
|
||||||
|
AlarmChangePercent: number;
|
||||||
|
AlarmPrice: number;
|
||||||
|
// Go type: time
|
||||||
|
Time: any;
|
||||||
|
Sort: number;
|
||||||
|
Cron?: string;
|
||||||
|
IsDel: number;
|
||||||
|
Groups: GroupStock[];
|
||||||
|
|
||||||
|
static createFrom(source: any = {}) {
|
||||||
|
return new FollowedStock(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(source: any = {}) {
|
||||||
|
if ('string' === typeof source) source = JSON.parse(source);
|
||||||
|
this.StockCode = source["StockCode"];
|
||||||
|
this.Name = source["Name"];
|
||||||
|
this.Volume = source["Volume"];
|
||||||
|
this.CostPrice = source["CostPrice"];
|
||||||
|
this.Price = source["Price"];
|
||||||
|
this.PriceChange = source["PriceChange"];
|
||||||
|
this.ChangePercent = source["ChangePercent"];
|
||||||
|
this.AlarmChangePercent = source["AlarmChangePercent"];
|
||||||
|
this.AlarmPrice = source["AlarmPrice"];
|
||||||
|
this.Time = this.convertValues(source["Time"], null);
|
||||||
|
this.Sort = source["Sort"];
|
||||||
|
this.Cron = source["Cron"];
|
||||||
|
this.IsDel = source["IsDel"];
|
||||||
|
this.Groups = this.convertValues(source["Groups"], GroupStock);
|
||||||
|
}
|
||||||
|
|
||||||
|
convertValues(a: any, classs: any, asMap: boolean = false): any {
|
||||||
|
if (!a) {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
if (a.slice && a.map) {
|
||||||
|
return (a as any[]).map(elem => this.convertValues(elem, classs));
|
||||||
|
} else if ("object" === typeof a) {
|
||||||
|
if (asMap) {
|
||||||
|
for (const key of Object.keys(a)) {
|
||||||
|
a[key] = new classs(a[key]);
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
return new classs(a);
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export class Settings {
|
export class Settings {
|
||||||
ID: number;
|
ID: number;
|
||||||
@ -413,6 +505,7 @@ export namespace data {
|
|||||||
sort: number;
|
sort: number;
|
||||||
alarmChangePercent: number;
|
alarmChangePercent: number;
|
||||||
alarmPrice: number;
|
alarmPrice: number;
|
||||||
|
Groups: GroupStock[];
|
||||||
|
|
||||||
static createFrom(source: any = {}) {
|
static createFrom(source: any = {}) {
|
||||||
return new StockInfo(source);
|
return new StockInfo(source);
|
||||||
@ -473,6 +566,7 @@ export namespace data {
|
|||||||
this.sort = source["sort"];
|
this.sort = source["sort"];
|
||||||
this.alarmChangePercent = source["alarmChangePercent"];
|
this.alarmChangePercent = source["alarmChangePercent"];
|
||||||
this.alarmPrice = source["alarmPrice"];
|
this.alarmPrice = source["alarmPrice"];
|
||||||
|
this.Groups = this.convertValues(source["Groups"], GroupStock);
|
||||||
}
|
}
|
||||||
|
|
||||||
convertValues(a: any, classs: any, asMap: boolean = false): any {
|
convertValues(a: any, classs: any, asMap: boolean = false): any {
|
||||||
|
2
go.mod
2
go.mod
@ -14,6 +14,7 @@ require (
|
|||||||
github.com/go-resty/resty/v2 v2.16.2
|
github.com/go-resty/resty/v2 v2.16.2
|
||||||
github.com/go-toast/toast v0.0.0-20190211030409-01e6764cf0a4
|
github.com/go-toast/toast v0.0.0-20190211030409-01e6764cf0a4
|
||||||
github.com/robfig/cron/v3 v3.0.1
|
github.com/robfig/cron/v3 v3.0.1
|
||||||
|
github.com/samber/lo v1.49.1
|
||||||
github.com/stretchr/testify v1.10.0
|
github.com/stretchr/testify v1.10.0
|
||||||
github.com/wailsapp/wails/v2 v2.10.1
|
github.com/wailsapp/wails/v2 v2.10.1
|
||||||
go.uber.org/zap v1.27.0
|
go.uber.org/zap v1.27.0
|
||||||
@ -59,7 +60,6 @@ require (
|
|||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||||
github.com/rivo/uniseg v0.4.7 // indirect
|
github.com/rivo/uniseg v0.4.7 // indirect
|
||||||
github.com/samber/lo v1.49.1 // indirect
|
|
||||||
github.com/tevino/abool v0.0.0-20220530134649-2bfc934cb23c // indirect
|
github.com/tevino/abool v0.0.0-20220530134649-2bfc934cb23c // indirect
|
||||||
github.com/tkrajina/go-reflector v0.5.8 // indirect
|
github.com/tkrajina/go-reflector v0.5.8 // indirect
|
||||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||||
|
7
main.go
7
main.go
@ -66,6 +66,13 @@ func main() {
|
|||||||
db.Dao.AutoMigrate(&data.FollowedFund{})
|
db.Dao.AutoMigrate(&data.FollowedFund{})
|
||||||
db.Dao.AutoMigrate(&data.FundBasic{})
|
db.Dao.AutoMigrate(&data.FundBasic{})
|
||||||
db.Dao.AutoMigrate(&models.PromptTemplate{})
|
db.Dao.AutoMigrate(&models.PromptTemplate{})
|
||||||
|
db.Dao.AutoMigrate(&data.Group{})
|
||||||
|
db.Dao.AutoMigrate(&data.GroupStock{})
|
||||||
|
|
||||||
|
//db.Dao.Model(&data.Group{}).Where("id = ?", 0).FirstOrCreate(&data.Group{
|
||||||
|
// Name: "默认分组",
|
||||||
|
// Sort: 0,
|
||||||
|
//})
|
||||||
|
|
||||||
if stocksBin != nil && len(stocksBin) > 0 {
|
if stocksBin != nil && len(stocksBin) > 0 {
|
||||||
go initStockData()
|
go initStockData()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user