diff --git a/app.go b/app.go
index bf4af75..0496d25 100644
--- a/app.go
+++ b/app.go
@@ -101,6 +101,7 @@ func (a *App) startup(ctx context.Context) {
onExit(a)
})
+ logger.SugaredLogger.Infof(" application startup Version:%s", Version)
}
func (a *App) CheckUpdate() {
@@ -237,18 +238,19 @@ func (a *App) domReady(ctx context.Context) {
// logger.SugaredLogger.Infof("Edge浏览器已安装,路径为: %s", path)
// }
//}()
- followList := data.NewStockDataApi().GetFollowList()
+ followList := data.NewStockDataApi().GetFollowList(0)
for _, follow := range *followList {
- if follow.Cron == "" {
+ if follow.Cron == nil || *follow.Cron == "" {
continue
}
- 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
+ entryID, err := a.cron.AddFunc(*follow.Cron, a.AddCronTask(follow))
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.AlarmChangePercent = follow.AlarmChangePercent
stockData.AlarmPrice = follow.AlarmPrice
+ stockData.Groups = follow.Groups
//当前价格
price, _ := convertor.ToFloat(stockData.Price)
@@ -592,17 +595,19 @@ func (a *App) beforeClose(ctx context.Context) (prevent bool) {
logger.SugaredLogger.Debugf("dialog:%s", dialog)
if dialog == "No" {
return true
+ } else {
+ systray.Quit()
+ a.cron.Stop()
+ return false
}
- return false
}
// shutdown is called at application termination
func (a *App) shutdown(ctx context.Context) {
defer PanicHandler()
// Perform your teardown here
- systray.Quit()
- a.cron.Stop()
- os.Exit(0)
+ //os.Exit(0)
+ logger.SugaredLogger.Infof("application shutdown Version:%s", Version)
}
// Greet returns a greeting for the given name
@@ -612,7 +617,7 @@ func (a *App) Greet(stockCode string) *data.StockInfo {
follow := &data.FollowedStock{
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)
return stockInfo
}
@@ -625,8 +630,8 @@ func (a *App) UnFollow(stockCode string) string {
return data.NewStockDataApi().UnFollow(stockCode)
}
-func (a *App) GetFollowList() *[]data.FollowedStock {
- return data.NewStockDataApi().GetFollowList()
+func (a *App) GetFollowList(groupId int) *[]data.FollowedStock {
+ return data.NewStockDataApi().GetFollowList(groupId)
}
func (a *App) GetStockList(key string) []data.StockBasic {
@@ -796,7 +801,7 @@ func getMsgTypeName(msgType int) string {
func onExit(a *App) {
// 清理操作
- logger.SugaredLogger.Infof("onExit")
+ logger.SugaredLogger.Infof("systray onExit")
//systray.Quit()
//runtime.Quit(a.ctx)
}
@@ -804,7 +809,7 @@ func onExit(a *App) {
func onReady(a *App) {
// 初始化操作
- logger.SugaredLogger.Infof("onReady")
+ logger.SugaredLogger.Infof("systray onReady")
systray.SetIcon(icon2)
systray.SetTitle("go-stock")
systray.SetTooltip("go-stock 股票行情实时获取")
@@ -988,3 +993,46 @@ func OnSecondInstanceLaunch(secondInstanceData options.SecondInstanceData) {
}
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 "移除失败"
+ }
+}
diff --git a/backend/data/fund_data_api.go b/backend/data/fund_data_api.go
index dc652ab..3289fd6 100644
--- a/backend/data/fund_data_api.go
+++ b/backend/data/fund_data_api.go
@@ -344,7 +344,7 @@ func (f *FundApi) CrawlFundNetEstimatedUnit(code string) {
//logger.SugaredLogger.Infof("基金净值信息:%s", htmlContent)
err := json.Unmarshal([]byte(htmlContent), &fundNetUnitValue)
if err != nil {
- logger.SugaredLogger.Errorf("json.Unmarshal error:%s", err.Error())
+ //logger.SugaredLogger.Errorf("json.Unmarshal error:%s", err.Error())
return
}
fund := &FollowedFund{
diff --git a/backend/data/stock_data_api.go b/backend/data/stock_data_api.go
index 062d65a..b6ead3a 100644
--- a/backend/data/stock_data_api.go
+++ b/backend/data/stock_data_api.go
@@ -16,6 +16,7 @@ import (
"github.com/duke-git/lancet/v2/slice"
"github.com/duke-git/lancet/v2/strutil"
"github.com/go-resty/resty/v2"
+ "github.com/samber/lo"
"go-stock/backend/db"
"go-stock/backend/logger"
"go-stock/backend/models"
@@ -90,6 +91,8 @@ type StockInfo struct {
Sort int64 `json:"sort"` //排序
AlarmChangePercent float64 `json:"alarmChangePercent"`
AlarmPrice float64 `json:"alarmPrice"`
+
+ Groups []GroupStock `gorm:"-:all"`
}
func (receiver StockInfo) TableName() string {
@@ -162,8 +165,9 @@ type FollowedStock struct {
AlarmPrice float64
Time time.Time
Sort int64
- Cron string
+ Cron *string
IsDel soft_delete.DeletedAt `gorm:"softDelete:flag"`
+ Groups []GroupStock `gorm:"foreignKey:StockCode;references:StockCode"`
}
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)
}
-func (receiver StockDataApi) GetFollowList() *[]FollowedStock {
+func (receiver StockDataApi) GetFollowList(groupId int) *[]FollowedStock {
+ logger.SugaredLogger.Infof("GetFollowList %d", groupId)
+
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
}
diff --git a/backend/data/stock_group_api.go b/backend/data/stock_group_api.go
new file mode 100644
index 0000000..7d55c9c
--- /dev/null
+++ b/backend/data/stock_group_api.go
@@ -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
+
+}
diff --git a/backend/db/db.go b/backend/db/db.go
index ca8010d..260c3af 100644
--- a/backend/db/db.go
+++ b/backend/db/db.go
@@ -20,7 +20,7 @@ func Init(sqlitePath string) {
Colorful: false,
IgnoreRecordNotFoundError: true,
ParameterizedQueries: false,
- LogLevel: logger.Warn,
+ LogLevel: logger.Info,
},
)
var openDb *gorm.DB
diff --git a/frontend/src/components/settings.vue b/frontend/src/components/settings.vue
index 90d7c57..2492c8a 100644
--- a/frontend/src/components/settings.vue
+++ b/frontend/src/components/settings.vue
@@ -259,36 +259,36 @@ function deletePrompt(ID){
-
+
-
+
- 基础设置
+ 基础设置
-
+
-
+
秒
-
+
-
-
+
+
- 通知设置
+ 通知设置
@@ -310,7 +310,7 @@ function deletePrompt(ID){
- OpenAI设置
+ OpenAI设置
diff --git a/frontend/src/components/stock.vue b/frontend/src/components/stock.vue
index 3674287..c47c397 100644
--- a/frontend/src/components/stock.vue
+++ b/frontend/src/components/stock.vue
@@ -15,7 +15,14 @@ import {
SetCostPriceAndVolume,
SetStockSort,
UnFollow,
- ShareAnalysis, SaveAsMarkdown, GetPromptTemplates, SetStockAICron
+ ShareAnalysis,
+ SaveAsMarkdown,
+ GetPromptTemplates,
+ SetStockAICron,
+ AddGroup,
+ GetGroupList,
+ AddStockGroup,
+ RemoveStockGroup, RemoveGroup
} from '../../wailsjs/go/main/App'
import {
NAvatar,
@@ -47,15 +54,15 @@ import {asBlob} from 'html-docx-js-typescript';
import vueDanmaku from 'vue3-danmaku'
import {keys, pad, padStart} from "lodash";
+import {models} from "../../wailsjs/go/models";
const danmus = ref([])
const ws = ref(null)
-
+const dialog = useDialog()
const toolbars = [0];
const handleProgress = (progress) => {
console.log(`Export progress: ${progress.ratio * 100}%`);
};
const enableEditor= ref(false)
-
const mdPreviewRef = ref(null)
const mdEditorRef = ref(null)
const tipsRef = ref(null)
@@ -65,6 +72,7 @@ const stocks=ref([])
const results=ref({})
const stockList=ref([])
const followList=ref([])
+const groupList=ref([])
const options=ref([])
const modalShow = ref(false)
const modalShow2 = ref(false)
@@ -81,6 +89,7 @@ const formModel = ref({
sort:999,
cron:"",
})
+
const promptTemplates=ref([])
const sysPromptOptions=ref([])
const userPromptOptions=ref([])
@@ -101,7 +110,7 @@ const data = reactive({
enableDanmu: false,
darkTheme:false,
})
-
+const currentGroupId=ref(0)
const theme=computed(() => {
return data.darkTheme ? 'dark' : 'light'
})
@@ -115,15 +124,29 @@ const icon = ref('https://raw.githubusercontent.com/ArvinLovegood/go-stock/maste
const sortedResults = computed(() => {
//console.log("computed",sortedResults.value)
const sortedKeys =keys(results.value).sort();
- console.log("sortedKeys",sortedKeys)
+ //console.log("sortedKeys",sortedKeys)
const sortedObject = {};
sortedKeys.forEach(key => {
- sortedObject[key] = results.value[key];
+ sortedObject[key] = results.value[key];
});
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(()=>{
+
+ GetGroupList().then(result => {
+ groupList.value=result
+ })
GetStockList("").then(result => {
stockList.value = result
options.value=result.map(item => {
@@ -133,7 +156,7 @@ onBeforeMount(()=>{
}
})
})
- GetFollowList().then(result => {
+ GetFollowList(currentGroupId.value).then(result => {
followList.value = result
for (const followedStock of result) {
if(followedStock.StockCode.startsWith("us")){
@@ -495,6 +518,8 @@ async function updateData(result) {
//result.key=result.sort
result.key=GetSortKey(result.sort,result["股票代码"])
results.value[GetSortKey(result.sort,result["股票代码"])]=result
+
+ console.log("updateData",result)
}
@@ -510,7 +535,7 @@ async function monitor() {
function GetSortKey(sort,code){
let sortKey= padStart(sort,8,'0')+"_"+code
- console.log("GetSortKey:",sortKey)
+ //console.log("GetSortKey:",sortKey)
return sortKey
}
@@ -603,7 +628,7 @@ function updateCostPriceAndVolumeNew(code,price,volume,alarm,formModel){
SetCostPriceAndVolume(code,price,volume).then(result => {
modalShow.value=false
message.success(result)
- GetFollowList().then(result => {
+ GetFollowList(currentGroupId.value).then(result => {
followList.value = result
for (const followedStock of result) {
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)
+ })
+}
@@ -861,8 +953,10 @@ function share(code,name){
-
-
+ {delTab(key)}">
+
+
+
@@ -916,11 +1010,82 @@ function share(code,name){
分时
日K
详情
+ AddStockGroupInfo(groupId,result['股票代码'],result['股票名称'])">
+ 设置分组
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+ ({{result['盘前盘后']}} {{result['盘前盘后涨跌幅']}}%)
+
+
+ %
+
+
+
+
+
+
+
+
+ {{"最高 "+result["今日最高价"]+" "+result.highRate }}%
+
+
+ {{"最低 "+result["今日最低价"]+" "+result.lowRate }}%
+
+
+ {{"昨收 "+result["昨日收盘价"]}}
+
+
+ {{"今开 "+result["今日开盘价"]}}
+
+
+
+
+ {{result['股票代码']}}
+
+ 取消关注
+
+
+ AI分析
+
+ 移出分组
+
+
+
+ {{result.volume+"股"}}
+ {{"成本:"+result.costPrice+"*"+result.costVolume+" "+result.profit+"%"+" ( "+result.profitAmount+" ¥ )"}}
+
+
+
+
+ {{result["日期"]+" "+result["时间"]}}
+ 成本
+ 分时
+ 日K
+ 详情
+ AddStockGroupInfo(groupId,result['股票代码'],result['股票名称'])">
+ 设置分组
+
+
+
+
+
+
+
+
+
@@ -991,6 +1156,31 @@ function share(code,name){
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 保存
+
+
+ 取消
+
+
+
+
diff --git a/frontend/src/router/router.js b/frontend/src/router/router.js
index 1cb9834..8eba737 100644
--- a/frontend/src/router/router.js
+++ b/frontend/src/router/router.js
@@ -1,4 +1,4 @@
-import { createMemoryHistory, createRouter } from 'vue-router'
+import {createMemoryHistory, createRouter, createWebHashHistory} from 'vue-router'
import stockView from '../components/stock.vue'
import settingsView from '../components/settings.vue'
@@ -13,7 +13,7 @@ const routes = [
]
const router = createRouter({
- history: createMemoryHistory(),
+ history: createWebHashHistory(),
routes,
})
diff --git a/frontend/wailsjs/go/main/App.d.ts b/frontend/wailsjs/go/main/App.d.ts
index 2420d60..a8d8d94 100644
--- a/frontend/wailsjs/go/main/App.d.ts
+++ b/frontend/wailsjs/go/main/App.d.ts
@@ -5,8 +5,12 @@ import {models} from '../models';
export function AddCronTask(arg1:data.FollowedStock):Promise;
+export function AddGroup(arg1:data.Group):Promise;
+
export function AddPrompt(arg1:models.Prompt):Promise;
+export function AddStockGroup(arg1:number,arg2:string):Promise;
+
export function CheckUpdate():Promise;
export function DelPrompt(arg1:number):Promise;
@@ -21,10 +25,14 @@ export function GetAIResponseResult(arg1:string):Promise;
-export function GetFollowList():Promise;
+export function GetFollowList(arg1:number):Promise;
export function GetFollowedFund():Promise>;
+export function GetGroupList():Promise>;
+
+export function GetGroupStockList(arg1:number):Promise>;
+
export function GetPromptTemplates(arg1:string,arg2:string):Promise;
export function GetStockList(arg1:string):Promise>;
@@ -37,6 +45,10 @@ export function Greet(arg1:string):Promise;
export function NewChatStream(arg1:string,arg2:string,arg3:string,arg4:any):Promise;
+export function RemoveGroup(arg1:number):Promise;
+
+export function RemoveStockGroup(arg1:string,arg2:string,arg3:number):Promise;
+
export function SaveAIResponseResult(arg1:string,arg2:string,arg3:string,arg4:string,arg5:string):Promise;
export function SaveAsMarkdown(arg1:string,arg2:string):Promise;
diff --git a/frontend/wailsjs/go/main/App.js b/frontend/wailsjs/go/main/App.js
index f26cb44..2c2f8e8 100644
--- a/frontend/wailsjs/go/main/App.js
+++ b/frontend/wailsjs/go/main/App.js
@@ -6,10 +6,18 @@ export function AddCronTask(arg1) {
return window['go']['main']['App']['AddCronTask'](arg1);
}
+export function AddGroup(arg1) {
+ return window['go']['main']['App']['AddGroup'](arg1);
+}
+
export function 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() {
return window['go']['main']['App']['CheckUpdate']();
}
@@ -38,14 +46,22 @@ export function GetConfig() {
return window['go']['main']['App']['GetConfig']();
}
-export function GetFollowList() {
- return window['go']['main']['App']['GetFollowList']();
+export function GetFollowList(arg1) {
+ return window['go']['main']['App']['GetFollowList'](arg1);
}
export function 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) {
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);
}
+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) {
return window['go']['main']['App']['SaveAIResponseResult'](arg1, arg2, arg3, arg4, arg5);
}
diff --git a/frontend/wailsjs/go/models.ts b/frontend/wailsjs/go/models.ts
index cf15b91..98bfbbd 100644
--- a/frontend/wailsjs/go/models.ts
+++ b/frontend/wailsjs/go/models.ts
@@ -142,41 +142,29 @@ export namespace data {
return a;
}
}
- export class FollowedStock {
- StockCode: string;
- Name: string;
- Volume: number;
- CostPrice: number;
- Price: number;
- PriceChange: number;
- ChangePercent: number;
- AlarmChangePercent: number;
- AlarmPrice: number;
+ export class Group {
+ ID: number;
// Go type: time
- Time: any;
- Sort: number;
- Cron: string;
- IsDel: number;
+ CreatedAt: any;
+ // Go type: time
+ UpdatedAt: any;
+ // Go type: gorm
+ DeletedAt: any;
+ name: string;
+ sort: number;
static createFrom(source: any = {}) {
- return new FollowedStock(source);
+ return new Group(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.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.name = source["name"];
+ this.sort = source["sort"];
}
convertValues(a: any, classs: any, asMap: boolean = false): any {
@@ -197,6 +185,110 @@ export namespace data {
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 {
ID: number;
@@ -413,6 +505,7 @@ export namespace data {
sort: number;
alarmChangePercent: number;
alarmPrice: number;
+ Groups: GroupStock[];
static createFrom(source: any = {}) {
return new StockInfo(source);
@@ -473,6 +566,7 @@ export namespace data {
this.sort = source["sort"];
this.alarmChangePercent = source["alarmChangePercent"];
this.alarmPrice = source["alarmPrice"];
+ this.Groups = this.convertValues(source["Groups"], GroupStock);
}
convertValues(a: any, classs: any, asMap: boolean = false): any {
diff --git a/go.mod b/go.mod
index 53fd3bb..57473bb 100644
--- a/go.mod
+++ b/go.mod
@@ -14,6 +14,7 @@ require (
github.com/go-resty/resty/v2 v2.16.2
github.com/go-toast/toast v0.0.0-20190211030409-01e6764cf0a4
github.com/robfig/cron/v3 v3.0.1
+ github.com/samber/lo v1.49.1
github.com/stretchr/testify v1.10.0
github.com/wailsapp/wails/v2 v2.10.1
go.uber.org/zap v1.27.0
@@ -59,7 +60,6 @@ require (
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // 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/tkrajina/go-reflector v0.5.8 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
diff --git a/main.go b/main.go
index 2a11de4..485d06f 100644
--- a/main.go
+++ b/main.go
@@ -66,6 +66,13 @@ func main() {
db.Dao.AutoMigrate(&data.FollowedFund{})
db.Dao.AutoMigrate(&data.FundBasic{})
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 {
go initStockData()