From c7655d2adffcd6b8586e760a530d6a691817e8e8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=B5=93=E7=9D=A1=E4=B8=8D=E6=B6=88=E6=AE=8B=E9=85=92?=
<49932926+CodeNoobLH@users.noreply.github.com>
Date: Mon, 16 Jun 2025 10:17:17 +0800
Subject: [PATCH 01/21] =?UTF-8?q?refactor(backend):=20=E4=BC=98=E5=8C=96?=
=?UTF-8?q?=E8=82=A1=E7=A5=A8=E6=8E=92=E5=BA=8F=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 重构了 SetStockSort 函数,增加了事务处理和错误处理
- 添加了对新排序位置是否被占用的检查
- 实现了向前和向后移动排序时对其他记录的影响
- 优化了数据库查询和更新操作,提高了代码的健壮性和性能
---
backend/data/stock_data_api.go | 75 ++++++++++++++++++++++++++++++++--
1 file changed, 71 insertions(+), 4 deletions(-)
diff --git a/backend/data/stock_data_api.go b/backend/data/stock_data_api.go
index 4399358..f6daa0d 100644
--- a/backend/data/stock_data_api.go
+++ b/backend/data/stock_data_api.go
@@ -463,15 +463,82 @@ func (receiver StockDataApi) SetAlarmChangePercent(val, alarmPrice float64, stoc
return "设置成功"
}
-func (receiver StockDataApi) SetStockSort(sort int64, stockCode string) {
+func (receiver StockDataApi) SetStockSort(newSort int64, stockCode string) {
if strutil.HasPrefixAny(stockCode, []string{"gb_"}) {
stockCode = strings.ToLower(stockCode)
stockCode = strings.Replace(stockCode, "gb_", "us", 1)
}
- err := db.Dao.Model(&FollowedStock{}).Where("stock_code = ?", strings.ToLower(stockCode)).Update("sort", sort).Error
- if err != nil {
- logger.SugaredLogger.Error(err.Error())
+
+ tx := db.Dao.Begin()
+ defer func() {
+ if r := recover(); r != nil {
+ tx.Rollback()
+ }
+ }()
+
+ // 获取当前排序值
+ var currentStock FollowedStock
+ if err := tx.Model(&FollowedStock{}).Where("stock_code = ?", strings.ToLower(stockCode)).First(¤tStock).Error; err != nil {
+ tx.Rollback()
+ logger.SugaredLogger.Error("找不到当前股票: ", err.Error())
+ return
}
+
+ oldSort := currentStock.Sort
+
+ // 如果排序值没有变化,直接返回
+ if oldSort == newSort {
+ tx.Rollback()
+ return
+ }
+
+ // 检查新排序位置是否被占用
+ var count int64
+ if err := tx.Model(&FollowedStock{}).Where("sort = ?", newSort).Count(&count).Error; err != nil {
+ tx.Rollback()
+ logger.SugaredLogger.Error("检查新排序位置被占用失败: ", err.Error())
+ return
+ }
+ if count == 0 {
+ // 新位置未被占用,直接更新当前记录
+ if err := tx.Model(&FollowedStock{}).
+ Where("stock_code = ?", strings.ToLower(stockCode)).
+ Update("sort", newSort).Error; err != nil {
+ tx.Rollback()
+ logger.SugaredLogger.Error("更新排序位置失败: ", err.Error())
+ }
+ } else {
+ // 新位置已被占用,需要移动其他记录
+ if newSort < oldSort {
+ // 向前移动:将中间记录向后移动
+ if err := tx.Model(&FollowedStock{}).
+ Where("sort >= ? AND sort < ?", newSort, oldSort).
+ Update("sort", gorm.Expr("sort + 1")).Error; err != nil {
+ tx.Rollback()
+ logger.SugaredLogger.Error("向前排序更新失败: ", err.Error())
+ }
+ } else {
+ // 向后移动:将中间记录向前移动
+ if err := tx.Model(&FollowedStock{}).
+ Where("sort > ? AND sort <= ?", oldSort, newSort).
+ Update("sort", gorm.Expr("sort - 1")).Error; err != nil {
+ tx.Rollback()
+ logger.SugaredLogger.Error("向后排序更新失败: ", err.Error())
+ }
+ }
+
+ // 更新目标记录的排序
+ if err := tx.Model(&FollowedStock{}).
+ Where("stock_code = ?", strings.ToLower(stockCode)).
+ Update("sort", newSort).Error; err != nil {
+ tx.Rollback()
+ logger.SugaredLogger.Error("Failed to update target stock sort: ", err.Error())
+ }
+ }
+ if err := tx.Commit().Error; err != nil {
+ logger.SugaredLogger.Error("Failed to commit transaction: ", err.Error())
+ }
+
}
func (receiver StockDataApi) SetStockAICron(cron string, stockCode string) {
if strutil.HasPrefixAny(stockCode, []string{"gb_"}) {
From 9337084ebf4f2f259605a8f59327222d179fb07a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=B5=93=E7=9D=A1=E4=B8=8D=E6=B6=88=E6=AE=8B=E9=85=92?=
<49932926+CodeNoobLH@users.noreply.github.com>
Date: Mon, 23 Jun 2025 16:37:20 +0800
Subject: [PATCH 02/21] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=8E=92=E5=BA=8F?=
=?UTF-8?q?=E5=90=8E=E7=AB=AF=E4=BB=A3=E7=A0=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
backend/data/stock_data_api.go | 32 +++++++------------------------
frontend/src/components/stock.vue | 5 ++++-
2 files changed, 11 insertions(+), 26 deletions(-)
diff --git a/backend/data/stock_data_api.go b/backend/data/stock_data_api.go
index f6daa0d..b022cdb 100644
--- a/backend/data/stock_data_api.go
+++ b/backend/data/stock_data_api.go
@@ -469,17 +469,9 @@ func (receiver StockDataApi) SetStockSort(newSort int64, stockCode string) {
stockCode = strings.Replace(stockCode, "gb_", "us", 1)
}
- tx := db.Dao.Begin()
- defer func() {
- if r := recover(); r != nil {
- tx.Rollback()
- }
- }()
-
// 获取当前排序值
var currentStock FollowedStock
- if err := tx.Model(&FollowedStock{}).Where("stock_code = ?", strings.ToLower(stockCode)).First(¤tStock).Error; err != nil {
- tx.Rollback()
+ if err := db.Dao.Model(&FollowedStock{}).Where("stock_code = ?", strings.ToLower(stockCode)).First(¤tStock).Error; err != nil {
logger.SugaredLogger.Error("找不到当前股票: ", err.Error())
return
}
@@ -488,56 +480,46 @@ func (receiver StockDataApi) SetStockSort(newSort int64, stockCode string) {
// 如果排序值没有变化,直接返回
if oldSort == newSort {
- tx.Rollback()
return
}
-
// 检查新排序位置是否被占用
var count int64
- if err := tx.Model(&FollowedStock{}).Where("sort = ?", newSort).Count(&count).Error; err != nil {
- tx.Rollback()
+ if err := db.Dao.Model(&FollowedStock{}).Where("sort = ?", newSort).Count(&count).Error; err != nil {
logger.SugaredLogger.Error("检查新排序位置被占用失败: ", err.Error())
return
}
if count == 0 {
// 新位置未被占用,直接更新当前记录
- if err := tx.Model(&FollowedStock{}).
+ if err := db.Dao.Model(&FollowedStock{}).
Where("stock_code = ?", strings.ToLower(stockCode)).
Update("sort", newSort).Error; err != nil {
- tx.Rollback()
logger.SugaredLogger.Error("更新排序位置失败: ", err.Error())
}
} else {
// 新位置已被占用,需要移动其他记录
if newSort < oldSort {
// 向前移动:将中间记录向后移动
- if err := tx.Model(&FollowedStock{}).
+ if err := db.Dao.Model(&FollowedStock{}).
Where("sort >= ? AND sort < ?", newSort, oldSort).
Update("sort", gorm.Expr("sort + 1")).Error; err != nil {
- tx.Rollback()
logger.SugaredLogger.Error("向前排序更新失败: ", err.Error())
}
} else {
// 向后移动:将中间记录向前移动
- if err := tx.Model(&FollowedStock{}).
+ if err := db.Dao.Model(&FollowedStock{}).
Where("sort > ? AND sort <= ?", oldSort, newSort).
Update("sort", gorm.Expr("sort - 1")).Error; err != nil {
- tx.Rollback()
logger.SugaredLogger.Error("向后排序更新失败: ", err.Error())
}
}
// 更新目标记录的排序
- if err := tx.Model(&FollowedStock{}).
+ if err := db.Dao.Model(&FollowedStock{}).
Where("stock_code = ?", strings.ToLower(stockCode)).
Update("sort", newSort).Error; err != nil {
- tx.Rollback()
- logger.SugaredLogger.Error("Failed to update target stock sort: ", err.Error())
+ logger.SugaredLogger.Error("更新股票排序失败: ", err.Error())
}
}
- if err := tx.Commit().Error; err != nil {
- logger.SugaredLogger.Error("Failed to commit transaction: ", err.Error())
- }
}
func (receiver StockDataApi) SetStockAICron(cron string, stockCode string) {
diff --git a/frontend/src/components/stock.vue b/frontend/src/components/stock.vue
index 1b958cd..8f4e4cb 100644
--- a/frontend/src/components/stock.vue
+++ b/frontend/src/components/stock.vue
@@ -226,7 +226,8 @@ onMounted(() => {
GetFollowList(currentGroupId.value).then(result => {
- followList.value = result
+ followList.value = result
+ console.log("onMounted",result)
for (const followedStock of result) {
if(followedStock.StockCode.startsWith("us")){
followedStock.StockCode="gb_"+ followedStock.StockCode.replace("us", "").toLowerCase()
@@ -1273,8 +1274,10 @@ function showK(code,name){
function updateCostPriceAndVolumeNew(code,price,volume,alarm,formModel){
if(formModel.sort){
+ console.log("sort:",formModel.sort)
SetStockSort(formModel.sort,code).then(result => {
//message.success(result)
+ console.log("sort result:",result)
})
}
if(formModel.cron){
From 9f2719cdbc13797ce912ef586adb0d567236ba59 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=B5=93=E7=9D=A1=E4=B8=8D=E6=B6=88=E6=AE=8B=E9=85=92?=
<49932926+CodeNoobLH@users.noreply.github.com>
Date: Mon, 23 Jun 2025 18:09:43 +0800
Subject: [PATCH 03/21] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=8E=92=E5=BA=8F?=
=?UTF-8?q?=E5=89=8D=E7=AB=AF=E4=BB=A3=E7=A0=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
frontend/src/components/stock.vue | 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)
diff --git a/frontend/src/components/stock.vue b/frontend/src/components/stock.vue
index 5120caa..e231977 100644
--- a/frontend/src/components/stock.vue
+++ b/frontend/src/components/stock.vue
@@ -151,7 +151,6 @@ const danmakuColor = computed(()=> {
const icon = ref('https://raw.githubusercontent.com/ArvinLovegood/go-stock/master/build/appicon.png');
const sortedResults = computed(() => {
- ////console.log("computed",sortedResults.value)
const sortedKeys =keys(results.value).sort();
////console.log("sortedKeys",sortedKeys)
const sortedObject = {};
@@ -227,7 +226,6 @@ onMounted(() => {
GetFollowList(currentGroupId.value).then(result => {
followList.value = result
- console.log("onMounted",result)
for (const followedStock of result) {
if(followedStock.StockCode.startsWith("us")){
followedStock.StockCode="gb_"+ followedStock.StockCode.replace("us", "").toLowerCase()
@@ -587,14 +585,16 @@ async function updateData(result) {
}
}
- //result.key=result.sort
+ // result.key=result.sort
+ results.value = Object.fromEntries(
+ Object.entries(results.value).filter(
+ ([key]) => !key.includes(result["股票代码"])
+ ));
result.key=GetSortKey(result.sort,result["股票代码"])
results.value[GetSortKey(result.sort,result["股票代码"])]=result
if(!stocks.value.includes(result["股票代码"])) {
delete results.value[result.key]
}
-
- ////console.log("updateData",result)
}
@@ -1274,10 +1274,8 @@ function showK(code,name){
function updateCostPriceAndVolumeNew(code,price,volume,alarm,formModel){
if(formModel.sort){
- console.log("sort:",formModel.sort)
SetStockSort(formModel.sort,code).then(result => {
//message.success(result)
- console.log("sort result:",result)
})
}
if(formModel.cron){
@@ -1296,6 +1294,7 @@ function updateCostPriceAndVolumeNew(code,price,volume,alarm,formModel){
message.success(result)
GetFollowList(currentGroupId.value).then(result => {
followList.value = result
+ stocks.value=[]
for (const followedStock of result) {
if (!stocks.value.includes(followedStock.StockCode)) {
stocks.value.push(followedStock.StockCode)
From be02343d681f75b946551d9777473ce5b25d0598 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=B5=93=E7=9D=A1=E4=B8=8D=E6=B6=88=E6=AE=8B=E9=85=92?=
<49932926+CodeNoobLH@users.noreply.github.com>
Date: Tue, 24 Jun 2025 18:11:28 +0800
Subject: [PATCH 04/21] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=89=8D=E7=AB=AF?=
=?UTF-8?q?=E5=85=B3=E6=B3=A8=E7=BE=8E=E8=82=A1=E5=90=8E=E4=B8=8D=E4=BC=9A?=
=?UTF-8?q?=E5=B1=95=E7=A4=BA=E7=9A=84=E9=97=AE=E9=A2=98=20=E4=BF=AE?=
=?UTF-8?q?=E5=A4=8D=E5=89=8D=E7=AB=AF=E7=BE=8E=E8=82=A1=E9=BB=98=E8=AE=A4?=
=?UTF-8?q?=E6=8E=92=E5=BA=8F=E9=9D=A0=E5=89=8D=E9=97=AE=E9=A2=98=20?=
=?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=90=8E=E7=AB=AF=E7=BE=8E=E8=82=A1=E6=97=A0?=
=?UTF-8?q?=E6=B3=95=E6=8E=92=E5=BA=8F=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
backend/data/stock_data_api.go | 16 +-
frontend/src/components/stock.vue | 1455 +++++++++++++++--------------
2 files changed, 765 insertions(+), 706 deletions(-)
diff --git a/backend/data/stock_data_api.go b/backend/data/stock_data_api.go
index 130d88b..334f938 100644
--- a/backend/data/stock_data_api.go
+++ b/backend/data/stock_data_api.go
@@ -400,7 +400,13 @@ func (receiver StockDataApi) Follow(stockCode string) string {
logger.SugaredLogger.Error(err)
return "关注失败"
}
-
+ if strings.HasPrefix(stockCode, "us") {
+ stockCode = strings.Replace(stockCode, "us", "gb_", 1)
+ }
+ if strings.HasPrefix(stockCode, "US") {
+ stockCode = strings.Replace(stockCode, "US", "gb_", 1)
+ }
+ stockCode = strings.ToLower(stockCode)
maxSort := int64(0)
db.Dao.Model(&FollowedStock{}).Raw("select max(sort) as sort from followed_stock").Scan(&maxSort)
@@ -464,10 +470,10 @@ func (receiver StockDataApi) SetAlarmChangePercent(val, alarmPrice float64, stoc
}
func (receiver StockDataApi) SetStockSort(newSort int64, stockCode string) {
- if strutil.HasPrefixAny(stockCode, []string{"gb_"}) {
- stockCode = strings.ToLower(stockCode)
- stockCode = strings.Replace(stockCode, "gb_", "us", 1)
- }
+ //if strutil.HasPrefixAny(stockCode, []string{"gb_"}) {
+ // stockCode = strings.ToLower(stockCode)
+ // stockCode = strings.Replace(stockCode, "gb_", "us", 1)
+ //}
// 获取当前排序值
var currentStock FollowedStock
diff --git a/frontend/src/components/stock.vue b/frontend/src/components/stock.vue
index e231977..424d655 100644
--- a/frontend/src/components/stock.vue
+++ b/frontend/src/components/stock.vue
@@ -2,28 +2,31 @@
import {computed, h, onBeforeMount, onBeforeUnmount, onMounted, reactive, ref} from 'vue'
import * as echarts from 'echarts';
import {
+ AddGroup,
+ AddStockGroup,
Follow,
GetAIResponseResult,
GetConfig,
GetFollowList,
+ GetGroupList,
+ GetPromptTemplates,
+ GetStockKLine,
GetStockList,
+ GetStockMinutePriceLineData,
GetVersionInfo,
Greet,
NewChatStream,
+ RemoveGroup,
+ RemoveStockGroup,
SaveAIResponseResult,
+ SaveAsMarkdown,
SendDingDingMessageByType,
SetAlarmChangePercent,
SetCostPriceAndVolume,
- SetStockSort,
- UnFollow,
- ShareAnalysis,
- SaveAsMarkdown,
- GetPromptTemplates,
SetStockAICron,
- AddGroup,
- GetGroupList,
- AddStockGroup,
- RemoveStockGroup, RemoveGroup, GetStockKLine, GetStockMinutePriceLineData
+ SetStockSort,
+ ShareAnalysis,
+ UnFollow
} from '../../wailsjs/go/main/App'
import {
NAvatar,
@@ -35,7 +38,6 @@ import {
NText,
useDialog,
useMessage,
- useModal,
useNotification
} from 'naive-ui'
import {
@@ -46,24 +48,22 @@ import {
WindowReload,
WindowUnfullscreen
} from '../../wailsjs/runtime'
-import {
- Add,
- ChatboxOutline,
-} from '@vicons/ionicons5'
-import {MdPreview,MdEditor } from 'md-editor-v3';
+import {Add, ChatboxOutline,} from '@vicons/ionicons5'
+import {MdEditor, MdPreview} from 'md-editor-v3';
// preview.css相比style.css少了编辑器那部分样式
//import 'md-editor-v3/lib/preview.css';
import 'md-editor-v3/lib/style.css';
-import { ExportPDF } from '@vavt/v3-extension';
+import {ExportPDF} from '@vavt/v3-extension';
import '@vavt/v3-extension/lib/asset/ExportPDF.css';
import html2canvas from "html2canvas";
import {asBlob} from 'html-docx-js-typescript';
import vueDanmaku from 'vue3-danmaku'
-import {keys, pad, padStart} from "lodash";
+import {keys, padStart} from "lodash";
import {useRoute, useRouter} from 'vue-router'
import MoneyTrend from "./moneyTrend.vue";
+
const route = useRoute()
const router = useRouter()
@@ -83,18 +83,18 @@ const kLineChartRef2 = ref(null);
const handleProgress = (progress) => {
//console.log(`Export progress: ${progress.ratio * 100}%`);
};
-const enableEditor= ref(false)
+const enableEditor = ref(false)
const mdPreviewRef = ref(null)
-const mdEditorRef = ref(null)
+const mdEditorRef = ref(null)
const tipsRef = ref(null)
const message = useMessage()
const notify = useNotification()
-const stocks=ref([])
-const results=ref({})
-const stockList=ref([])
-const followList=ref([])
-const groupList=ref([])
-const options=ref([])
+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)
const modalShow3 = ref(false)
@@ -107,84 +107,82 @@ const formModel = ref({
costPrice: 0.000,
volume: 0,
alarm: 0,
- alarmPrice:0,
- sort:999,
- cron:"",
+ alarmPrice: 0,
+ sort: 999,
+ cron: "",
})
-const promptTemplates=ref([])
-const sysPromptOptions=ref([])
-const userPromptOptions=ref([])
+const promptTemplates = ref([])
+const sysPromptOptions = ref([])
+const userPromptOptions = ref([])
const data = reactive({
- modelName:"",
+ modelName: "",
chatId: "",
- question:"",
- sysPromptId:null,
+ question: "",
+ sysPromptId: null,
name: "",
code: "",
- fenshiURL:"",
- kURL:"",
+ fenshiURL: "",
+ kURL: "",
resultText: "Please enter your name below 👇",
fullscreen: false,
airesult: "",
openAiEnable: false,
loading: true,
enableDanmu: false,
- darkTheme:false,
- changePercent:0
+ darkTheme: false,
+ changePercent: 0
})
-const feishiInterval= ref(null)
+const feishiInterval = ref(null)
-const currentGroupId=ref(0)
+const currentGroupId = ref(0)
-
-const theme=computed(() => {
+const theme = computed(() => {
return data.darkTheme ? 'dark' : 'light'
})
-const danmakuColor = computed(()=> {
+const danmakuColor = computed(() => {
return data.darkTheme ? 'color:#fff' : 'color:#000'
})
const icon = ref('https://raw.githubusercontent.com/ArvinLovegood/go-stock/master/build/appicon.png');
const sortedResults = computed(() => {
- const sortedKeys =keys(results.value).sort();
- ////console.log("sortedKeys",sortedKeys)
+ const sortedKeys = keys(results.value).sort();
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]
+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
})
-const showPopover=ref(false)
+const showPopover = ref(false)
-onBeforeMount(()=>{
+onBeforeMount(() => {
GetGroupList().then(result => {
- groupList.value=result
- if(route.query.groupId){
- message.success("切换分组:"+route.query.groupName)
- currentGroupId.value=Number(route.query.groupId)
+ groupList.value = result
+ if (route.query.groupId) {
+ message.success("切换分组:" + route.query.groupName)
+ currentGroupId.value = Number(route.query.groupId)
//console.log("route.params",route.query)
}
})
GetStockList("").then(result => {
stockList.value = result
- options.value=result.map(item => {
+ options.value = result.map(item => {
return {
- label: item.name+" - "+item.ts_code,
+ label: item.name + " - " + item.ts_code,
value: item.ts_code
}
})
@@ -200,11 +198,11 @@ onBeforeMount(()=>{
data.darkTheme = true
}
})
- GetPromptTemplates("","").then(res=>{
- promptTemplates.value=res
+ GetPromptTemplates("", "").then(res => {
+ promptTemplates.value = res
- sysPromptOptions.value=promptTemplates.value.filter(item => item.type === '模型系统Prompt')
- userPromptOptions.value=promptTemplates.value.filter(item => item.type === '模型用户Prompt')
+ sysPromptOptions.value = promptTemplates.value.filter(item => item.type === '模型系统Prompt')
+ userPromptOptions.value = promptTemplates.value.filter(item => item.type === '模型用户Prompt')
//console.log("userPromptOptions",userPromptOptions.value)
//console.log("sysPromptOptions",sysPromptOptions.value)
@@ -214,24 +212,15 @@ onBeforeMount(()=>{
onMounted(() => {
message.loading("Loading...")
- // //console.log(`the component is now mounted.`)
-
- // ticker.value=setInterval(() => {
- // if(isTradingTime()){
- // //monitor()
- // //data.fenshiURL='http://image.sinajs.cn/newchart/min/n/'+data.code+'.gif'+"?t="+Date.now()
- // }
- // }, 3500)
GetFollowList(currentGroupId.value).then(result => {
followList.value = result
for (const followedStock of result) {
- if(followedStock.StockCode.startsWith("us")){
- followedStock.StockCode="gb_"+ followedStock.StockCode.replace("us", "").toLowerCase()
+ if (followedStock.StockCode.startsWith("us")) {
+ followedStock.StockCode = "gb_" + followedStock.StockCode.replace("us", "").toLowerCase()
}
if (!stocks.value.includes(followedStock.StockCode)) {
- ////console.log("followList",followedStock.StockCode)
stocks.value.push(followedStock.StockCode)
}
}
@@ -252,7 +241,7 @@ onMounted(() => {
};
ws.value.onmessage = (event) => {
- if(data.enableDanmu){
+ if (data.enableDanmu) {
danmus.value.push(event.data);
}
};
@@ -267,7 +256,7 @@ onMounted(() => {
})
onBeforeUnmount(() => {
- // //console.log(`the component is now unmounted.`)
+ // //console.log(`the component is now unmounted.`)
//clearInterval(ticker.value)
ws.value.close()
message.destroyAll()
@@ -285,80 +274,69 @@ onBeforeUnmount(() => {
EventsOff("loadingDone")
})
-EventsOn("loadingDone",(data)=>{
+EventsOn("loadingDone", (data) => {
message.loading("刷新股票基础数据...")
GetStockList("").then(result => {
stockList.value = result
- options.value=result.map(item => {
+ options.value = result.map(item => {
return {
- label: item.name+" - "+item.ts_code,
+ label: item.name + " - " + item.ts_code,
value: item.ts_code
}
})
})
})
-EventsOn("refresh",(data)=>{
+EventsOn("refresh", (data) => {
message.success(data)
})
-EventsOn("showSearch",(data)=>{
+EventsOn("showSearch", (data) => {
addBTN.value = data === 1;
})
-EventsOn("stock_price",(data)=>{
+EventsOn("stock_price", (data) => {
updateData(data)
})
-EventsOn("refreshFollowList",(data)=>{
+EventsOn("refreshFollowList", (data) => {
WindowReload()
- // message.loading("refresh...")
- // GetFollowList().then(result => {
- // followList.value = result
- // for (const followedStock of result) {
- // if (!stocks.value.includes(followedStock.StockCode)) {
- // stocks.value.push(followedStock.StockCode)
- // }
- // }
- // monitor()
- // message.destroyAll
- // })
})
-EventsOn("newChatStream",async (msg) => {
+EventsOn("newChatStream", async (msg) => {
////console.log("newChatStream:->",data.airesult)
data.loading = false
////console.log(msg)
if (msg === "DONE") {
- SaveAIResponseResult(data.code, data.name, data.airesult, data.chatId,data.question)
+ SaveAIResponseResult(data.code, data.name, data.airesult, data.chatId, data.question)
message.info("AI分析完成!")
message.destroyAll()
} else {
- if(msg.chatId){
- data.chatId = msg.chatId
- }
- if(msg.question){
- data.question = msg.question
- }
- if(msg.content){
- data.airesult = data.airesult + msg.content
- }
- if(msg.extraContent){
- data.airesult = data.airesult + msg.extraContent
- }
+ if (msg.chatId) {
+ data.chatId = msg.chatId
+ }
+ if (msg.question) {
+ data.question = msg.question
+ }
+ if (msg.content) {
+ data.airesult = data.airesult + msg.content
+ }
+ if (msg.extraContent) {
+ data.airesult = data.airesult + msg.extraContent
+ }
}
})
-EventsOn("changeTab" ,async (msg) => {
+EventsOn("changeTab", async (msg) => {
//console.log("changeTab",msg)
- currentGroupId.value=msg.ID
+ currentGroupId.value = msg.ID
updateTab(currentGroupId.value)
})
-EventsOn("updateVersion",async (msg) => {
+EventsOn("updateVersion", async (msg) => {
const githubTimeStr = msg.published_at;
// 创建一个 Date 对象
const utcDate = new Date(githubTimeStr);
@@ -391,10 +369,10 @@ EventsOn("updateVersion",async (msg) => {
'text-align': 'left',
'font-size': '14px',
}
- }, { default: () => msg.commit?.message })
+ }, {default: () => msg.commit?.message})
},
duration: 5000,
- meta: "发布时间:"+formattedDate,
+ meta: "发布时间:" + formattedDate,
action: () => {
return h(NButton, {
type: 'primary',
@@ -402,12 +380,12 @@ EventsOn("updateVersion",async (msg) => {
onClick: () => {
window.open(msg.html_url)
}
- }, { default: () => '查看' })
+ }, {default: () => '查看'})
}
})
})
-EventsOn("warnMsg",async (msg) => {
+EventsOn("warnMsg", async (msg) => {
notify.error({
avatar: () =>
h(NAvatar, {
@@ -423,7 +401,7 @@ EventsOn("warnMsg",async (msg) => {
'text-align': 'left',
'font-size': '14px',
}
- }, { default: () => msg })
+ }, {default: () => msg})
},
})
})
@@ -448,34 +426,34 @@ function isTradingTime() {
return false;
}
-function AddStock(){
+function AddStock() {
if (!data?.code) {
message.error("请输入有效股票代码");
return;
}
if (!stocks.value.includes(data.code)) {
- Follow(data.code).then(result => {
- if(result==="关注成功"){
- stocks.value.push(data.code)
- message.success(result)
- GetFollowList(currentGroupId.value).then(result => {
- followList.value = result
- })
- monitor();
- }else{
- message.error(result)
- }
- })
- }else{
+ Follow(data.code).then(result => {
+ if (result === "关注成功") {
+ data.code= "gb_" + data.code.replace("us", "").toLowerCase()
+ stocks.value.push(data.code)
+ message.success(result)
+ GetFollowList(currentGroupId.value).then(result => {
+ followList.value = result
+ })
+ monitor();
+ } else {
+ message.error(result)
+ }
+ })
+ } else {
message.error("已经关注了")
}
}
-
-function removeMonitor(code,name,key) {
+function removeMonitor(code, name, key) {
//console.log("removeMonitor",name,code,key)
- stocks.value.splice(stocks.value.indexOf(code),1)
+ stocks.value.splice(stocks.value.indexOf(code), 1)
//console.log("removeMonitor-key",key)
//console.log("removeMonitor-v",results.value[key])
@@ -488,61 +466,58 @@ function removeMonitor(code,name,key) {
}
-function SendDanmu(){
+function SendDanmu() {
//danmus.value.push(data.name)
//console.log("SendDanmu",data.name)
//console.log("SendDanmu-readyState", ws.value.readyState)
ws.value.send(data.name)
}
-function getStockList(value){
+function getStockList(value) {
-
- // //console.log("getStockList",value)
+ // //console.log("getStockList",value)
let result;
- result=stockList.value.filter(item => item.name.includes(value)||item.ts_code.includes(value))
- options.value=result.map(item => {
+ result = stockList.value.filter(item => item.name.includes(value) || item.ts_code.includes(value))
+ options.value = result.map(item => {
return {
- label: item.name+" - "+item.ts_code,
+ label: item.name + " - " + item.ts_code,
value: item.ts_code
}
})
- if(value&&value.indexOf("-")<=0){
- data.code=value
+ if (value && value.indexOf("-") <= 0) {
+ data.code = value
}
//console.log("getStockList-options",data.code)
- if(data.code){
- let findId=data.code
- if(findId.startsWith("us")){
- findId="gb_"+ findId.replace("us", "").toLowerCase()
+ if (data.code) {
+ let findId = data.code
+ if (findId.startsWith("us")) {
+ findId = "gb_" + findId.replace("us", "").toLowerCase()
}
blinkBorder(findId)
}
-
-
}
-function blinkBorder(findId){
+function blinkBorder(findId) {
// 获取要滚动到的元素
let element = document.getElementById(findId);
//console.log("blinkBorder",findId,element)
if (element) {
// 滚动到该元素
- element.scrollIntoView({ behavior: 'smooth'});
- const pelement = document.getElementById(findId +'_gi');
- if(pelement){
+ element.scrollIntoView({behavior: 'smooth'});
+ const pelement = document.getElementById(findId + '_gi');
+ if (pelement) {
// 添加闪烁效果
pelement.classList.add('blink-border');
// 3秒后移除闪烁效果
setTimeout(() => {
pelement.classList.remove('blink-border');
- }, 1000*5);
- }else{
+ }, 1000 * 5);
+ } else {
console.error(`Element with ID ${findId}_gi not found`);
}
}
@@ -551,59 +526,60 @@ function blinkBorder(findId){
async function updateData(result) {
////console.log("stock_price",result['日期'],result['时间'],result['股票代码'],result['股票名称'],result['当前价格'],result['盘前盘后'])
- if(result["当前价格"]<=0){
- result["当前价格"]=result["卖一报价"]
+ if (result["当前价格"] <= 0) {
+ result["当前价格"] = result["卖一报价"]
}
- if (result.changePercent>0) {
- result.type="error"
- result.color="#E88080"
- }else if (result.changePercent<0) {
- result.type="success"
- result.color="#63E2B7"
- }else {
- result.type="default"
- result.color="#FFFFFF"
+ if (result.changePercent > 0) {
+ result.type = "error"
+ result.color = "#E88080"
+ } else if (result.changePercent < 0) {
+ result.type = "success"
+ result.color = "#63E2B7"
+ } else {
+ result.type = "default"
+ result.color = "#FFFFFF"
}
- if(result.profitAmount>0){
- result.profitType="error"
- }else if(result.profitAmount<0){
- result.profitType="success"
+ if (result.profitAmount > 0) {
+ result.profitType = "error"
+ } else if (result.profitAmount < 0) {
+ result.profitType = "success"
+ }
+ if (result["当前价格"]) {
+ if (result.alarmChangePercent > 0 && Math.abs(result.changePercent) >= result.alarmChangePercent) {
+ SendMessage(result, 1)
}
- if(result["当前价格"]){
- if(result.alarmChangePercent>0&&Math.abs(result.changePercent)>=result.alarmChangePercent){
- SendMessage(result,1)
- }
- if(result.alarmPrice>0&&result["当前价格"]>=result.alarmPrice){
- SendMessage(result,2)
- }
-
- if(result.costPrice>0&&result["当前价格"]>=result.costPrice){
- SendMessage(result,3)
- }
+ if (result.alarmPrice > 0 && result["当前价格"] >= result.alarmPrice) {
+ SendMessage(result, 2)
}
+ if (result.costPrice > 0 && result["当前价格"] >= result.costPrice) {
+ SendMessage(result, 3)
+ }
+ }
+
// result.key=result.sort
results.value = Object.fromEntries(
Object.entries(results.value).filter(
([key]) => !key.includes(result["股票代码"])
));
- result.key=GetSortKey(result.sort,result["股票代码"])
- results.value[GetSortKey(result.sort,result["股票代码"])]=result
- if(!stocks.value.includes(result["股票代码"])) {
+
+ result.key = GetSortKey(result.sort, result["股票代码"])
+ results.value[result.key] = result
+ if (!stocks.value.includes(result["股票代码"])) {
delete results.value[result.key]
}
}
async function monitor() {
- if(stocks.value&&stocks.value.length===0){
- showPopover.value=true
+ if (stocks.value && stocks.value.length === 0) {
+ showPopover.value = true
}
for (let code of stocks.value) {
- // //console.log(code)
+
Greet(code).then(result => {
updateData(result)
})
@@ -611,51 +587,53 @@ async function monitor() {
}
-function GetSortKey(sort,code){
- let sortKey= padStart(sort,8,'0')+"_"+code
- ////console.log("GetSortKey:",sortKey)
+function GetSortKey(sort, code) {
+ let sortKey = padStart(sort, 8, '0') + "_" + code
return sortKey
}
function onSelect(item) {
////console.log("onSelect",item)
- if(item.indexOf("-")>0){
- item=item.split("-")[1].toLowerCase()
+ if (item.indexOf("-") > 0) {
+ item = item.split("-")[1].toLowerCase()
}
- if(item.indexOf(".")>0){
- data.code=item.split(".")[1].toLowerCase()+item.split(".")[0]
+ if (item.indexOf(".") > 0) {
+ data.code = item.split(".")[1].toLowerCase() + item.split(".")[0]
}
}
-function search(code,name){
+function search(code, name) {
setTimeout(() => {
//window.open("https://xueqiu.com/S/"+code)
//window.open("https://www.cls.cn/stock?code="+code)
//window.open("https://quote.eastmoney.com/"+code+".html")
//window.open("https://finance.sina.com.cn/realstock/company/"+code+"/nc.shtml")
- window.open("https://www.iwencai.com/unifiedwap/result?w="+name)
+ window.open("https://www.iwencai.com/unifiedwap/result?w=" + name)
//window.open("https://www.iwencai.com/chat/?question="+code)
}, 500)
}
-function setStock(code,name){
- let res=followList.value.filter(item => item.StockCode===code)
- ////console.log("res:",res)
- formModel.value.name=name
- formModel.value.code=code
- formModel.value.volume=res[0].Volume?res[0].Volume:0
- formModel.value.costPrice=res[0].CostPrice
- formModel.value.alarm=res[0].AlarmChangePercent
- formModel.value.alarmPrice=res[0].AlarmPrice
- formModel.value.sort=res[0].Sort
- formModel.value.cron=res[0].Cron
- modalShow.value=true
+
+function setStock(code, name) {
+ let res = followList.value.filter(item => item.StockCode === code)
+ ////console.log("res:",res)
+ formModel.value.name = name
+ formModel.value.code = code
+ formModel.value.volume = res[0].Volume ? res[0].Volume : 0
+ formModel.value.costPrice = res[0].CostPrice
+ formModel.value.alarm = res[0].AlarmChangePercent
+ formModel.value.alarmPrice = res[0].AlarmPrice
+ formModel.value.sort = res[0].Sort
+ formModel.value.cron = res[0].Cron
+ modalShow.value = true
}
-function clearFeishi(){
+
+function clearFeishi() {
//console.log("clearFeishi")
clearInterval(feishiInterval.value)
}
+
function showFsChart(code, name) {
data.name = name
data.code = code
@@ -665,14 +643,14 @@ function showFsChart(code, name) {
const priceData = result.priceData
let category = []
let price = []
- let openprice=0
- let closeprice=0
+ let openprice = 0
+ let closeprice = 0
let volume = []
let volumeRate = []
let min = 0
let max = 0
- openprice=priceData[0].price
- closeprice=priceData[priceData.length-1].price
+ openprice = priceData[0].price
+ closeprice = priceData[priceData.length - 1].price
for (let i = 0; i < priceData.length; i++) {
category.push(priceData[i].time)
price.push(priceData[i].price)
@@ -683,8 +661,8 @@ function showFsChart(code, name) {
max = priceData[i].price
}
if (i > 0) {
- let b=priceData[i].volume - priceData[i - 1].volume
- volumeRate.push(((b-volume[i-1])/volume[i-1]*100).toFixed(2))
+ let b = priceData[i].volume - priceData[i - 1].volume
+ volumeRate.push(((b - volume[i - 1]) / volume[i - 1] * 100).toFixed(2))
volume.push(b)
} else {
volume.push(priceData[i].volume)
@@ -694,7 +672,7 @@ function showFsChart(code, name) {
let option = {
title: {
- subtext: "["+result.date+"] 开盘:"+openprice+" 最新:"+closeprice+" 最高:"+max+" 最低:"+min,
+ subtext: "[" + result.date + "] 开盘:" + openprice + " 最新:" + closeprice + " 最高:" + max + " 最低:" + min,
left: 'center',
top: '10',
textStyle: {
@@ -731,13 +709,13 @@ function showFsChart(code, name) {
}
},
xAxis: [
- {
- type: 'category',
- data: category,
- axisLabel: {
- show: false
- }
- },
+ {
+ type: 'category',
+ data: category,
+ axisLabel: {
+ show: false
+ }
+ },
{
gridIndex: 1,
type: 'category',
@@ -766,8 +744,8 @@ function showFsChart(code, name) {
show: false
},
name: "股价",
- min: (min - min*0.01).toFixed(2),
- max: (max + max*0.01).toFixed(2),
+ min: (min - min * 0.01).toFixed(2),
+ max: (max + max * 0.01).toFixed(2),
minInterval: 0.01,
type: 'value'
},
@@ -785,7 +763,7 @@ function showFsChart(code, name) {
],
visualMap: {
type: 'piecewise',
- seriesIndex:0,
+ seriesIndex: 0,
top: 0,
left: 10,
orient: 'horizontal',
@@ -828,13 +806,13 @@ function showFsChart(code, name) {
type: 'line',
smooth: false,
showSymbol: false,
- lineStyle: {
+ lineStyle: {
width: 3
},
markPoint: {
symbol: 'arrow',
- symbolRotate:90,
- symbolSize: [10,20],
+ symbolRotate: 90,
+ symbolSize: [10, 20],
symbolOffset: [10, 0],
itemStyle: {
color: '#FC290D'
@@ -850,24 +828,24 @@ function showFsChart(code, name) {
markLine: {
symbol: 'none',
data: [
- { type: 'average', name: 'Average' },
- {
- lineStyle:{
- color: '#FFCB00',
- width: 0.5
- },
- yAxis: openprice,
- name: '开盘价'
+ {type: 'average', name: 'Average'},
+ {
+ lineStyle: {
+ color: '#FFCB00',
+ width: 0.5
},
- {
- yAxis: closeprice ,
- symbol: 'none',
- lineStyle:{
- color: 'red',
- width: 0.5
- },
- }
- ]
+ yAxis: openprice,
+ name: '开盘价'
+ },
+ {
+ yAxis: closeprice,
+ symbol: 'none',
+ lineStyle: {
+ color: 'red',
+ width: 0.5
+ },
+ }
+ ]
},
},
{
@@ -884,30 +862,30 @@ function showFsChart(code, name) {
})
}
-function showFenshi(code,name,changePercent){
- data.code=code
- data.name=name
- data.changePercent=changePercent
- data.fenshiURL='http://image.sinajs.cn/newchart/min/n/'+data.code+'.gif'+"?t="+Date.now()
+function showFenshi(code, name, changePercent) {
+ data.code = code
+ data.name = name
+ data.changePercent = changePercent
+ data.fenshiURL = 'http://image.sinajs.cn/newchart/min/n/' + data.code + '.gif' + "?t=" + Date.now()
- if(code.startsWith('hk')){
- data.fenshiURL='http://image.sinajs.cn/newchart/hk_stock/min/'+data.code.replace("hk","")+'.gif'+"?t="+Date.now()
+ if (code.startsWith('hk')) {
+ data.fenshiURL = 'http://image.sinajs.cn/newchart/hk_stock/min/' + data.code.replace("hk", "") + '.gif' + "?t=" + Date.now()
}
- if(code.startsWith('gb_')){
- data.fenshiURL='http://image.sinajs.cn/newchart/usstock/min/'+data.code.replace("gb_","")+'.gif'+"?t="+Date.now()
+ if (code.startsWith('gb_')) {
+ data.fenshiURL = 'http://image.sinajs.cn/newchart/usstock/min/' + data.code.replace("gb_", "") + '.gif' + "?t=" + Date.now()
}
- modalShow2.value=true
+ modalShow2.value = true
}
-function handleFeishi(){
+function handleFeishi() {
showFsChart(data.code, data.name);
- feishiInterval.value=setInterval(() => {
+ feishiInterval.value = setInterval(() => {
showFsChart(data.code, data.name);
- }, 1000*10)
+ }, 1000 * 10)
}
-function calculateMA(dayCount,values) {
+function calculateMA(dayCount, values) {
var result = [];
for (var i = 0, len = values.length; i < len; i++) {
if (i < dayCount) {
@@ -922,39 +900,40 @@ function calculateMA(dayCount,values) {
}
return result;
}
-function handleKLine(){
- GetStockKLine(data.code,data.name,365).then(result => {
+
+function handleKLine() {
+ GetStockKLine(data.code, data.name, 365).then(result => {
//console.log("GetStockKLine",result)
const chart = echarts.init(kLineChartRef.value);
const categoryData = [];
const values = [];
- const volumns=[];
+ const volumns = [];
for (let i = 0; i < result.length; i++) {
- let resultElement=result[i]
+ let resultElement = result[i]
//console.log("resultElement:{}",resultElement)
categoryData.push(resultElement.day)
- let flag=resultElement.close>resultElement.open?1:-1
+ let flag = resultElement.close > resultElement.open ? 1 : -1
values.push([
resultElement.open,
resultElement.close,
resultElement.low,
resultElement.high
])
- volumns.push([i,resultElement.volume/10000,flag])
+ volumns.push([i, resultElement.volume / 10000, flag])
}
////console.log("categoryData",categoryData)
////console.log("values",values)
let option = {
darkMode: data.darkTheme,
//backgroundColor: '#1c1c1c',
- // color:['#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de', '#3ba272', '#fc8452', '#9a60b4', '#ea7ccc'],
+ // color:['#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de', '#3ba272', '#fc8452', '#9a60b4', '#ea7ccc'],
animation: false,
legend: {
bottom: 10,
left: 'center',
data: ['日K', 'MA5', 'MA10', 'MA20', 'MA30'],
textStyle: {
- color: data.darkTheme?'#ccc':'#456'
+ color: data.darkTheme ? '#ccc' : '#456'
},
},
tooltip: {
@@ -968,19 +947,19 @@ function handleKLine(){
}
},
borderWidth: 2,
- borderColor: data.darkTheme?'#456':'#ccc',
- backgroundColor: data.darkTheme?'#456':'#fff',
+ borderColor: data.darkTheme ? '#456' : '#ccc',
+ backgroundColor: data.darkTheme ? '#456' : '#fff',
padding: 10,
textStyle: {
- color: data.darkTheme?'#ccc':'#456'
+ color: data.darkTheme ? '#ccc' : '#456'
},
formatter: function (params) {//修改鼠标划过显示为中文
//console.log("params",params)
- let volum=params[5].data;//ma5的值
- let ma5=params[1].data;//ma5的值
- let ma10=params[2].data;//ma10的值
- let ma20=params[3].data;//ma20的值
- let ma30=params[4].data;//ma30的值
+ let volum = params[5].data;//ma5的值
+ let ma5 = params[1].data;//ma5的值
+ let ma10 = params[2].data;//ma10的值
+ let ma20 = params[3].data;//ma20的值
+ let ma30 = params[4].data;//ma30的值
params = params[0];//开盘收盘最低最高数据汇总
let currentItemData = params.data;
@@ -1047,8 +1026,8 @@ function handleKLine(){
type: 'category',
data: categoryData,
boundaryGap: false,
- axisLine: { onZero: false },
- splitLine: { show: false },
+ axisLine: {onZero: false},
+ splitLine: {show: false},
min: 'dataMin',
max: 'dataMax',
axisPointer: {
@@ -1060,10 +1039,10 @@ function handleKLine(){
gridIndex: 1,
data: categoryData,
boundaryGap: false,
- axisLine: { onZero: false },
- axisTick: { show: false },
- splitLine: { show: false },
- axisLabel: { show: false },
+ axisLine: {onZero: false},
+ axisTick: {show: false},
+ splitLine: {show: false},
+ axisLabel: {show: false},
min: 'dataMin',
max: 'dataMax'
}
@@ -1079,10 +1058,10 @@ function handleKLine(){
scale: true,
gridIndex: 1,
splitNumber: 2,
- axisLabel: { show: false },
- axisLine: { show: false },
- axisTick: { show: false },
- splitLine: { show: false }
+ axisLabel: {show: false},
+ axisLine: {show: false},
+ axisTick: {show: false},
+ splitLine: {show: false}
}
],
dataZoom: [
@@ -1110,8 +1089,8 @@ function handleKLine(){
itemStyle: {
color: upColor,
color0: downColor,
- // borderColor: upBorderColor,
- // borderColor0: downBorderColor
+ // borderColor: upBorderColor,
+ // borderColor0: downBorderColor
},
markPoint: {
label: {
@@ -1192,7 +1171,7 @@ function handleKLine(){
{
name: 'MA5',
type: 'line',
- data: calculateMA(5,values),
+ data: calculateMA(5, values),
smooth: true,
showSymbol: false,
lineStyle: {
@@ -1202,7 +1181,7 @@ function handleKLine(){
{
name: 'MA10',
type: 'line',
- data: calculateMA(10,values),
+ data: calculateMA(10, values),
smooth: true,
showSymbol: false,
lineStyle: {
@@ -1212,7 +1191,7 @@ function handleKLine(){
{
name: 'MA20',
type: 'line',
- data: calculateMA(20,values),
+ data: calculateMA(20, values),
smooth: true,
showSymbol: false,
lineStyle: {
@@ -1222,7 +1201,7 @@ function handleKLine(){
{
name: 'MA30',
type: 'line',
- data: calculateMA(30,values),
+ data: calculateMA(30, values),
smooth: true,
showSymbol: false,
lineStyle: {
@@ -1242,59 +1221,57 @@ function handleKLine(){
]
};
chart.setOption(option);
- chart.on('click',{seriesName:'日K'}, function(params) {
+ chart.on('click', {seriesName: '日K'}, function (params) {
//console.log("click:",params);
});
})
}
-function showMoney(code,name){
- data.code=code
- data.name=name
- modalShow5.value=true
+
+function showMoney(code, name) {
+ data.code = code
+ data.name = name
+ modalShow5.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()
- if(code.startsWith('hk')){
- data.kURL='http://image.sinajs.cn/newchart/hk_stock/daily/'+data.code.replace("hk","")+'.gif'+"?t="+Date.now()
+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()
+ if (code.startsWith('hk')) {
+ data.kURL = 'http://image.sinajs.cn/newchart/hk_stock/daily/' + data.code.replace("hk", "") + '.gif' + "?t=" + Date.now()
}
- if(code.startsWith('gb_')){
- data.kURL='http://image.sinajs.cn/newchart/usstock/daily/'+data.code.replace("gb_","")+'.gif'+"?t="+Date.now()
+ if (code.startsWith('gb_')) {
+ data.kURL = 'http://image.sinajs.cn/newchart/usstock/daily/' + data.code.replace("gb_", "") + '.gif' + "?t=" + Date.now()
}
- modalShow3.value=true
+ modalShow3.value = true
//https://image.sinajs.cn/newchart/usstock/daily/dji.gif
//https://image.sinajs.cn/newchart/hk_stock/daily/06030.gif?1740729404273
}
-
-
-function updateCostPriceAndVolumeNew(code,price,volume,alarm,formModel){
-
- if(formModel.sort){
- SetStockSort(formModel.sort,code).then(result => {
+function updateCostPriceAndVolumeNew(code, price, volume, alarm, formModel) {
+ if (formModel.sort) {
+ SetStockSort(formModel.sort, code).then(result => {
//message.success(result)
})
}
- if(formModel.cron){
- SetStockAICron(formModel.cron,code).then(result => {
+ if (formModel.cron) {
+ SetStockAICron(formModel.cron, code).then(result => {
//message.success(result)
})
}
- if(alarm||formModel.alarmPrice){
- SetAlarmChangePercent(alarm,formModel.alarmPrice,code).then(result => {
+ if (alarm || formModel.alarmPrice) {
+ SetAlarmChangePercent(alarm, formModel.alarmPrice, code).then(result => {
//message.success(result)
})
}
- SetCostPriceAndVolume(code,price,volume).then(result => {
- modalShow.value=false
+ SetCostPriceAndVolume(code, price, volume).then(result => {
+ modalShow.value = false
message.success(result)
GetFollowList(currentGroupId.value).then(result => {
followList.value = result
- stocks.value=[]
+ stocks.value = []
for (const followedStock of result) {
if (!stocks.value.includes(followedStock.StockCode)) {
stocks.value.push(followedStock.StockCode)
@@ -1306,73 +1283,75 @@ function updateCostPriceAndVolumeNew(code,price,volume,alarm,formModel){
})
}
-function fullscreen(){
- if(data.fullscreen){
+function fullscreen() {
+ if (data.fullscreen) {
WindowUnfullscreen()
- }else{
+ } else {
WindowFullscreen()
}
- data.fullscreen=!data.fullscreen
+ data.fullscreen = !data.fullscreen
}
//type 报警类型: 1 涨跌报警;2 股价报警 3 成本价报警
-function SendMessage(result,type){
- let typeName=getTypeName(type)
- let img='http://image.sinajs.cn/newchart/min/n/'+result["股票代码"]+'.gif'+"?t="+Date.now()
- let markdown="### go-stock ["+typeName+"]\n\n"+
- "### "+result["股票名称"]+"("+result["股票代码"]+")\n" +
- "- 当前价格: "+result["当前价格"]+" "+result.changePercent+"%\n" +
- "- 最高价: "+result["今日最高价"]+" "+result.highRate+"\n" +
- "- 最低价: "+result["今日最低价"]+" "+result.lowRate+"\n" +
- "- 昨收价: "+result["昨日收盘价"]+"\n" +
- "- 今开价: "+result["今日开盘价"]+"\n" +
- "- 成本价: "+result.costPrice+" "+result.profit+"% "+result.profitAmount+" ¥\n" +
- "- 成本数量: "+result.costVolume+"股\n" +
- "- 日期: "+result["日期"]+" "+result["时间"]+"\n\n"+
- "\n"
- let title=result["股票名称"]+"("+result["股票代码"]+") "+result["当前价格"]+" "+result.changePercent
+function SendMessage(result, type) {
+ let typeName = getTypeName(type)
+ let img = 'http://image.sinajs.cn/newchart/min/n/' + result["股票代码"] + '.gif' + "?t=" + Date.now()
+ let markdown = "### go-stock [" + typeName + "]\n\n" +
+ "### " + result["股票名称"] + "(" + result["股票代码"] + ")\n" +
+ "- 当前价格: " + result["当前价格"] + " " + result.changePercent + "%\n" +
+ "- 最高价: " + result["今日最高价"] + " " + result.highRate + "\n" +
+ "- 最低价: " + result["今日最低价"] + " " + result.lowRate + "\n" +
+ "- 昨收价: " + result["昨日收盘价"] + "\n" +
+ "- 今开价: " + result["今日开盘价"] + "\n" +
+ "- 成本价: " + result.costPrice + " " + result.profit + "% " + result.profitAmount + " ¥\n" +
+ "- 成本数量: " + result.costVolume + "股\n" +
+ "- 日期: " + result["日期"] + " " + result["时间"] + "\n\n" +
+ "\n"
+ let title = result["股票名称"] + "(" + result["股票代码"] + ") " + result["当前价格"] + " " + result.changePercent
- let msg='{' +
+ let msg = '{' +
' "msgtype": "markdown",' +
' "markdown": {' +
- ' "title":"['+typeName+"]"+title+'",' +
- ' "text": "'+markdown+'"' +
+ ' "title":"[' + typeName + "]" + title + '",' +
+ ' "text": "' + markdown + '"' +
' },' +
' "at": {' +
' "isAtAll": true' +
' }' +
' }'
- // SendDingDingMessage(msg,result["股票代码"])
- SendDingDingMessageByType(msg,result["股票代码"],type)
+ // SendDingDingMessage(msg,result["股票代码"])
+ SendDingDingMessageByType(msg, result["股票代码"], type)
}
-function aiReCheckStock(stock,stockCode) {
- data.modelName=""
- data.airesult=""
- data.time=""
- data.name=stock
- data.code=stockCode
- data.loading=true
- modalShow4.value=true
- message.loading("ai检测中...",{
+
+function aiReCheckStock(stock, stockCode) {
+ data.modelName = ""
+ data.airesult = ""
+ data.time = ""
+ data.name = stock
+ data.code = stockCode
+ data.loading = true
+ modalShow4.value = true
+ message.loading("ai检测中...", {
duration: 0,
})
//
//message.info("sysPromptId:"+data.sysPromptId)
- NewChatStream(stock,stockCode,data.question,data.sysPromptId)
+ NewChatStream(stock, stockCode, data.question, data.sysPromptId)
}
-function aiCheckStock(stock,stockCode){
+
+function aiCheckStock(stock, stockCode) {
GetAIResponseResult(stockCode).then(result => {
- if(result.content){
- data.modelName=result.modelName
- data.chatId=result.chatId
- data.question=result.question
- data.name=stock
- data.code=stockCode
- data.loading=false
- modalShow4.value=true
- data.airesult=result.content
+ if (result.content) {
+ data.modelName = result.modelName
+ data.chatId = result.chatId
+ data.question = result.question
+ data.name = stock
+ data.code = stockCode
+ data.loading = false
+ modalShow4.value = true
+ data.airesult = result.content
const date = new Date(result.CreatedAt);
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
@@ -1380,27 +1359,26 @@ function aiCheckStock(stock,stockCode){
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
const seconds = String(date.getSeconds()).padStart(2, '0');
- data.time=`${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
- }else{
- data.modelName=""
- data.question=""
- data.airesult=""
- data.time=""
- data.name=stock
- data.code=stockCode
- data.loading=true
- modalShow4.value=true
- message.loading("ai检测中...",{
+ data.time = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
+ } else {
+ data.modelName = ""
+ data.question = ""
+ data.airesult = ""
+ data.time = ""
+ data.name = stock
+ data.code = stockCode
+ data.loading = true
+ modalShow4.value = true
+ message.loading("ai检测中...", {
duration: 0,
})
- NewChatStream(stock,stockCode,"",data.sysPromptId)
+ NewChatStream(stock, stockCode, "", data.sysPromptId)
}
})
}
-function getTypeName(type){
- switch (type)
- {
+function getTypeName(type) {
+ switch (type) {
case 1:
return "涨跌报警"
case 2:
@@ -1426,28 +1404,28 @@ window.onerror = function (msg, source, lineno, colno, error) {
lineno: lineno,
colno: colno,
error: error ? error.stack : null,
- data:data,
- results:results,
- followList:followList,
- stockList:stockList,
- stocks:stocks,
- formModel:formModel,
+ data: data,
+ results: results,
+ followList: followList,
+ stockList: stockList,
+ stocks: stocks,
+ formModel: formModel,
});
- message.error("发生错误:"+msg)
+ message.error("发生错误:" + msg)
return true;
};
-function saveAsImage(name,code) {
+function saveAsImage(name, code) {
const element = document.querySelector('.md-editor-preview');
if (element) {
- html2canvas(element,{
+ html2canvas(element, {
useCORS: true, // 解决跨域图片问题
scale: 2, // 提高截图质量
allowTaint: true, // 允许跨域图片
}).then(canvas => {
const link = document.createElement('a');
link.href = canvas.toDataURL('image/png');
- link.download = name+"["+code+']-ai-analysis-result.png';
+ link.download = name + "[" + code + ']-ai-analysis-result.png';
link.click();
});
} else {
@@ -1463,13 +1441,15 @@ async function copyToClipboard() {
message.error('复制失败: ' + err);
}
}
-function saveAsMarkdown(){
- SaveAsMarkdown(data.code,data.name).then(result => {
+
+function saveAsMarkdown() {
+ SaveAsMarkdown(data.code, data.name).then(result => {
message.success(result)
})
}
+
function saveAsMarkdown_old() {
- const blob = new Blob([data.airesult], { type: 'text/markdown;charset=utf-8' });
+ const blob = new Blob([data.airesult], {type: 'text/markdown;charset=utf-8'});
const link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = `${data.name}[${data.code}]-${data.time}ai-analysis-result.md`;
@@ -1477,6 +1457,7 @@ function saveAsMarkdown_old() {
URL.revokeObjectURL(link.href);
link.remove()
}
+
function getHtml(ref) {
if (ref.value) {
// 获取 MdPreview 组件的根元素
@@ -1494,7 +1475,7 @@ async function saveAsWord() {
// 将富文本内容拼接为一个完整的html
const html = getHtml(mdPreviewRef)
const tipsHtml = getHtml(tipsRef)
- const value = `
+ const value = `
${html}
@@ -1508,7 +1489,7 @@ AI赋能股票分析:自选股行情获取,成本盈亏展示,涨跌报警
`
// landscape就是横着的,portrait是竖着的,默认是竖屏portrait。
- const blob = await asBlob(value, { orientation: 'portrait' })
+ const blob = await asBlob(value, {orientation: 'portrait'})
const a = document.createElement('a')
a.href = URL.createObjectURL(blob)
a.download = `${data.name}[${data.code}]-ai-analysis-result.docx`;
@@ -1518,8 +1499,8 @@ AI赋能股票分析:自选股行情获取,成本盈亏展示,涨跌报警
a.remove()
}
-function share(code,name){
- ShareAnalysis(code,name).then(msg => {
+function share(code, name) {
+ ShareAnalysis(code, name).then(msg => {
//message.info(msg)
notify.info({
avatar: () =>
@@ -1529,90 +1510,96 @@ function share(code,name){
src: icon.value
}),
title: '分享到社区',
- duration:1000*30,
+ duration: 1000 * 30,
content: () => {
return h('div', {
style: {
'text-align': 'left',
'font-size': '14px',
}
- }, { default: () => msg })
+ }, {default: () => msg})
},
})
})
}
-const addTabModel=ref({
+
+const addTabModel = ref({
name: '',
sort: 1,
})
-const addTabPane=ref(false)
-function addTab(){
- addTabPane.value=true
+const addTabPane = ref(false)
+
+function addTab() {
+ addTabPane.value = true
}
-function saveTabPane(){
+
+function saveTabPane() {
AddGroup(addTabModel.value).then(result => {
message.info(result)
- addTabPane.value=false
+ addTabPane.value = false
GetGroupList().then(result => {
- groupList.value=result
+ groupList.value = result
})
})
}
-function AddStockGroupInfo(groupId,code,name){
- if(code.startsWith("gb_")){
- code="us"+ code.replace("gb_", "").toLowerCase()
+
+function AddStockGroupInfo(groupId, code, name) {
+ if (code.startsWith("gb_")) {
+ code = "us" + code.replace("gb_", "").toLowerCase()
}
- AddStockGroup(groupId,code).then(result => {
+ AddStockGroup(groupId, code).then(result => {
message.info(result)
GetGroupList().then(result => {
- groupList.value=result
+ groupList.value = result
})
})
}
-function updateTab(name){
- currentGroupId.value=Number(name)
+
+function updateTab(name) {
+ currentGroupId.value = Number(name)
GetFollowList(currentGroupId.value).then(result => {
- stocks.value=[]
- //console.log("GetFollowList",result)
+ stocks.value = []
followList.value = result
for (const followedStock of result) {
- if(followedStock.StockCode.startsWith("us")){
- followedStock.StockCode="gb_"+ followedStock.StockCode.replace("us", "").toLowerCase()
+ if (followedStock.StockCode.startsWith("us")) {
+ followedStock.StockCode = "gb_" + followedStock.StockCode.replace("us", "").toLowerCase()
}
- ////console.log("followList",followedStock.StockCode)
- stocks.value.push(followedStock.StockCode)
+ ////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))
+
+function delTab(name) {
+ let infos = groupList.value = groupList.value.filter(item => item.ID === Number(name))
dialog.create({
title: '删除分组',
type: 'warning',
- content: '确定要删除['+infos[0].name+']分组吗?分组数据将不能恢复哟!',
+ content: '确定要删除[' + infos[0].name + ']分组吗?分组数据将不能恢复哟!',
positiveText: '确定',
negativeText: '取消',
onPositiveClick: () => {
RemoveGroup(name).then(result => {
message.info(result)
GetGroupList().then(result => {
- groupList.value=result
+ groupList.value = result
})
})
}
})
}
-function delStockGroup(code,name,groupId){
- RemoveStockGroup(code,name,groupId).then(result => {
+
+function delStockGroup(code, name, groupId) {
+ RemoveStockGroup(code, name, groupId).then(result => {
updateTab(groupId)
message.info(result)
})
}
-function searchNotice(stockCode){
+function searchNotice(stockCode) {
router.push({
name: 'market',
query: {
@@ -1621,7 +1608,8 @@ function searchNotice(stockCode){
},
})
}
-function searchStockReport(stockCode){
+
+function searchStockReport(stockCode) {
router.push({
name: 'market',
query: {
@@ -1633,384 +1621,447 @@ function searchStockReport(stockCode){
-
-
-
- {{ danmu }}
-
-
-
- {delTab(key)}">
-
-
-
-
-
-
-
-
- ({{result['盘前盘后']}} {{result['盘前盘后涨跌幅']}}%)
-
-
- %
-
-
-
-
-
-
-
-
- {{"最高 "+result["今日最高价"]+" "+result.highRate }}%
-
-
- {{"最低 "+result["今日最低价"]+" "+result.lowRate }}%
-
-
- {{"昨收 "+result["昨日收盘价"]}}
-
-
- {{"今开 "+result["今日开盘价"]}}
-
-
-
-
-
-
- {{"买一 "+result["买一报价"]+'('+result["买一申报"]+")"}}
- {{"卖一 "+result["卖一报价"]+'('+result["卖一申报"]+")"}}
-
-
-
-
- {{"买一 "+result["买一报价"]+'('+result["买一申报"]+")"}}
-
-
- {{"卖一 "+result["卖一报价"]+'('+result["卖一申报"]+")"}}
-
-
-
- {{"买二 "+result["买二报价"]+'('+result["买二申报"]+")"}}
-
-
- {{"卖二 "+result["卖二报价"]+'('+result["卖二申报"]+")"}}
-
-
-
- {{"买三 "+result["买三报价"]+'('+result["买三申报"]+")"}}
-
-
- {{"买三 "+result["卖三报价"]+'('+result["卖三申报"]+")"}}
-
-
-
- {{"买四 "+result["买四报价"]+'('+result["买四申报"]+")"}}
-
-
- {{"卖四 "+result["卖四报价"]+'('+result["卖四申报"]+")"}}
-
-
-
- {{"买五 "+result["买五报价"]+'('+result["买五申报"]+")"}}
-
-
- {{"卖五 "+result["卖五报价"]+'('+result["卖五申报"]+")"}}
-
-
-
-
-
-
- {{result['股票代码']}}
-
- 取消关注
-
-
- AI分析
-
-
-
-
-
- {{result["日期"]+" "+result["时间"]}}
- {{result.volume+"股"}}
- {{"成本:"+result.costPrice+"*"+result.costVolume+" "+result.profit+"%"+" ( "+result.profitAmount+" ¥ )"}}
-
-
-
-
- 成本
- 分时
- 日K
- 资金
- 详情
- 公告
- 研报
-
- AddStockGroupInfo(groupId,result['股票代码'],result['股票名称'])">
- 设置分组
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+ {{ danmu }}
+
+
+
+ {delTab(key)}">
+
+
+
+
-
-
- ({{result['盘前盘后']}} {{result['盘前盘后涨跌幅']}}%)
+
+
+
+ ({{ result['盘前盘后'] }} {{ result['盘前盘后涨跌幅'] }}%)
+
- %
+
+ %
-
+
-
+
- {{"最高 "+result["今日最高价"]+" "+result.highRate }}%
+ {{ "最高 " + result["今日最高价"] + " " + result.highRate }}%
- {{"最低 "+result["今日最低价"]+" "+result.lowRate }}%
+ {{ "最低 " + result["今日最低价"] + " " + result.lowRate }}%
- {{"昨收 "+result["昨日收盘价"]}}
+ {{ "昨收 " + result["昨日收盘价"] }}
- {{"今开 "+result["今日开盘价"]}}
+ {{ "今开 " + result["今日开盘价"] }}
- {{"买一 "+result["买一报价"]+'('+result["买一申报"]+")"}}
- {{"卖一 "+result["卖一报价"]+'('+result["卖一申报"]+")"}}
+ {{ "买一 " + result["买一报价"] + '(' + result["买一申报"] + ")" }}
+ {{ "卖一 " + result["卖一报价"] + '(' + result["卖一申报"] + ")" }}
-
+
- {{"买一 "+result["买一报价"]+'('+result["买一申报"]+")"}}
+ {{ "买一 " + result["买一报价"] + '(' + result["买一申报"] + ")" }}
- {{"卖一 "+result["卖一报价"]+'('+result["卖一申报"]+")"}}
+ {{ "卖一 " + result["卖一报价"] + '(' + result["卖一申报"] + ")" }}
- {{"买二 "+result["买二报价"]+'('+result["买二申报"]+")"}}
+ {{ "买二 " + result["买二报价"] + '(' + result["买二申报"] + ")" }}
- {{"卖二 "+result["卖二报价"]+'('+result["卖二申报"]+")"}}
+ {{ "卖二 " + result["卖二报价"] + '(' + result["卖二申报"] + ")" }}
- {{"买三 "+result["买三报价"]+'('+result["买三申报"]+")"}}
+ {{ "买三 " + result["买三报价"] + '(' + result["买三申报"] + ")" }}
- {{"买三 "+result["卖三报价"]+'('+result["卖三申报"]+")"}}
+ {{ "买三 " + result["卖三报价"] + '(' + result["卖三申报"] + ")" }}
- {{"买四 "+result["买四报价"]+'('+result["买四申报"]+")"}}
+ {{ "买四 " + result["买四报价"] + '(' + result["买四申报"] + ")" }}
- {{"卖四 "+result["卖四报价"]+'('+result["卖四申报"]+")"}}
+ {{ "卖四 " + result["卖四报价"] + '(' + result["卖四申报"] + ")" }}
- {{"买五 "+result["买五报价"]+'('+result["买五申报"]+")"}}
+ {{ "买五 " + result["买五报价"] + '(' + result["买五申报"] + ")" }}
- {{"卖五 "+result["卖五报价"]+'('+result["卖五申报"]+")"}}
+ {{ "卖五 " + result["卖五报价"] + '(' + result["卖五申报"] + ")" }}
- {{result['股票代码']}}
-
+ {{ result['股票代码'] }}
+
取消关注
-
+
AI分析
-
- 移出分组
+
+
- {{result["日期"]+" "+result["时间"]}}
- {{result.volume+"股"}}
- {{"成本:"+result.costPrice+"*"+result.costVolume+" "+result.profit+"%"+" ( "+result.profitAmount+" ¥ )"}}
+ {{ result["日期"] + " " + result["时间"] }}
+ {{ result.volume + "股" }}
+
+ {{ "成本:" + result.costPrice + "*" + result.costVolume + " " + result.profit + "%" + " ( " + result.profitAmount + " ¥ )" }}
+
- 成本
- 分时
- 日K
- 资金
- 详情
- 公告
- 研报
+ 成本
+
+ 分时
+
+ 日K
+ 资金
+
+ 详情
+
+ 公告
+
+ 研报
+
- AddStockGroupInfo(groupId,result['股票代码'],result['股票名称'])">
- 设置分组
+ AddStockGroupInfo(groupId,result['股票代码'],result['股票名称'])">
+ 设置分组
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ({{ result['盘前盘后'] }} {{ result['盘前盘后涨跌幅'] }}%)
+
+
+
+
+ %
+
+
+
+
+
+
+
+
+ {{ "最高 " + result["今日最高价"] + " " + result.highRate }}%
+
+
+ {{ "最低 " + result["今日最低价"] + " " + result.lowRate }}%
+
+
+ {{ "昨收 " + result["昨日收盘价"] }}
+
+
+ {{ "今开 " + result["今日开盘价"] }}
+
+
+
+
+
+
+ {{ "买一 " + result["买一报价"] + '(' + result["买一申报"] + ")" }}
+ {{ "卖一 " + result["卖一报价"] + '(' + result["卖一申报"] + ")" }}
+
+
+
+
+ {{ "买一 " + result["买一报价"] + '(' + result["买一申报"] + ")" }}
+
+
+ {{ "卖一 " + result["卖一报价"] + '(' + result["卖一申报"] + ")" }}
+
+
+
+ {{ "买二 " + result["买二报价"] + '(' + result["买二申报"] + ")" }}
+
+
+ {{ "卖二 " + result["卖二报价"] + '(' + result["卖二申报"] + ")" }}
+
+
+
+ {{ "买三 " + result["买三报价"] + '(' + result["买三申报"] + ")" }}
+
+
+ {{ "买三 " + result["卖三报价"] + '(' + result["卖三申报"] + ")" }}
+
+
+
+ {{ "买四 " + result["买四报价"] + '(' + result["买四申报"] + ")" }}
+
+
+ {{ "卖四 " + result["卖四报价"] + '(' + result["卖四申报"] + ")" }}
+
+
+
+ {{ "买五 " + result["买五报价"] + '(' + result["买五申报"] + ")" }}
+
+
+ {{ "卖五 " + result["卖五报价"] + '(' + result["卖五申报"] + ")" }}
+
+
+
+
+
+
+ {{ result['股票代码'] }}
+
+ 取消关注
+
+
+ AI分析
+
+ 移出分组
+
+
+
+
+ {{ result["日期"] + " " + result["时间"] }}
+ {{ result.volume + "股" }}
+
+ {{ "成本:" + result.costPrice + "*" + result.costVolume + " " + result.profit + "%" + " ( " + result.profitAmount + " ¥ )" }}
+
+
+
+
+
+ 成本
+
+ 分时
+
+ 日K
+ 资金
+
+ 详情
+
+ 公告
+
+ 研报
+
+
+ AddStockGroupInfo(groupId,result['股票代码'],result['股票名称'])">
+ 设置分组
+
+
+
+
+
-
-
-
+
+
+
-
+ :options="options"
+ placeholder="股票指数名称/代码/弹幕"
+ clearable @update-value="getStockList" :on-select="onSelect"/>
-
-
-
- 关注
-
-
- 输入股票名称/代码关键词开始吧~~~
-
+
+
+
+ 关注
+
+
+ 输入股票名称/代码关键词开始吧~~~
+
-
- 发送弹幕
-
-
-
+
+ 发送弹幕
+
+
+
-
-
+
-
-
-
- {{formModel.code.indexOf("hk")>=0?"HK$":"¥"}}
-
-
-
-
-
-
- 股
-
-
-
-
-
-
- %
-
-
-
-
-
-
- {{formModel.code.indexOf("hk")>=0?"HK$":"¥"}}
-
-
-
-
-
-
-
-
-
-
-
-
- 保存
-
-
+
+
+
+ {{ formModel.code.indexOf("hk") >= 0 ? "HK$" : "¥" }}
+
+
+
+
+
+
+ 股
+
+
+
+
+
+
+ %
+
+
+
+
+
+
+ {{ formModel.code.indexOf("hk") >= 0 ? "HK$" : "¥" }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 保存
+
+
+
+ >
+
-
+
-
+
-
+
-
+
保存
-
+
取消
-
-
+
+
-
-
+
+
-
+
-
+
-
+
-
-
+
+
-
- {{data.modelName}}
- {{data.time}}
+
+
+ {{ data.modelName }}
+
+ {{ data.time }}
- *AI分析结果仅供参考,请以实际行情为准。投资需谨慎,风险自担。
+ *AI分析结果仅供参考,请以实际行情为准。投资需谨慎,风险自担。
-
-
+
+
-
-
- 再次分析
+
+ 再次分析
保存为图片
复制到剪切板
保存为Markdown文件
@@ -2030,33 +2081,35 @@ function searchStockReport(stockCode){
-
+
From 7dd10d443e4767e3da189acb61963591b4eeb3c1 Mon Sep 17 00:00:00 2001
From: ArvinLovegood
Date: Wed, 25 Jun 2025 09:40:04 +0800
Subject: [PATCH 05/21] =?UTF-8?q?feat(frontend):=E6=B7=BB=E5=8A=A0?=
=?UTF-8?q?=E7=83=AD=E9=97=A8=E8=82=A1=E7=A5=A8=E3=80=81=E4=BA=8B=E4=BB=B6?=
=?UTF-8?q?=E5=92=8C=E8=AF=9D=E9=A2=98=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 在 App.d.ts 和 App.js 中添加了 HotEvent、HotStock 和 HotTopic 函数
- 在 app_common.go 中实现了相关功能的后端逻辑
- 新增 HotEvents、HotStockList 和 HotTopics 组件用于前端展示
- 更新 market.vue以包含新的热门股票和话题功能
- 在 KLineChart.vue 中添加了代码和名称的显示
---
app_common.go | 17 ++++++
backend/data/market_news_api.go | 69 +++++++++++++++++++++
backend/data/market_news_api_test.go | 27 +++++++++
backend/models/models.go | 45 ++++++++++++++
frontend/src/components/HotEvents.vue | 37 ++++++++++++
frontend/src/components/HotStockList.vue | 76 ++++++++++++++++++++++++
frontend/src/components/HotTopics.vue | 43 ++++++++++++++
frontend/src/components/KLineChart.vue | 2 +-
frontend/src/components/market.vue | 31 +++++++++-
frontend/wailsjs/go/main/App.d.ts | 6 ++
frontend/wailsjs/go/main/App.js | 12 ++++
11 files changed, 362 insertions(+), 3 deletions(-)
create mode 100644 frontend/src/components/HotEvents.vue
create mode 100644 frontend/src/components/HotStockList.vue
create mode 100644 frontend/src/components/HotTopics.vue
diff --git a/app_common.go b/app_common.go
index a73a611..587be55 100644
--- a/app_common.go
+++ b/app_common.go
@@ -31,3 +31,20 @@ func (a App) EMDictCode(code string) []any {
func (a App) AnalyzeSentiment(text string) data.SentimentResult {
return data.AnalyzeSentiment(text)
}
+
+func (a App) HotStock(marketType string) *[]models.HotItem {
+ return data.NewMarketNewsApi().XUEQIUHotStock(50, marketType)
+}
+
+func (a App) HotEvent(size int) *[]models.HotEvent {
+ if size <= 0 {
+ size = 10
+ }
+ return data.NewMarketNewsApi().HotEvent(size)
+}
+func (a App) HotTopic(size int) []any {
+ if size <= 0 {
+ size = 10
+ }
+ return data.NewMarketNewsApi().HotTopic(size)
+}
diff --git a/backend/data/market_news_api.go b/backend/data/market_news_api.go
index d1e5938..ff74b2a 100644
--- a/backend/data/market_news_api.go
+++ b/backend/data/market_news_api.go
@@ -574,3 +574,72 @@ func (m MarketNewsApi) TradingViewNews() *[]models.TVNews {
json.Unmarshal(items, TVNews)
return TVNews
}
+
+func (m MarketNewsApi) XUEQIUHotStock(size int, marketType string) *[]models.HotItem {
+ url := fmt.Sprintf("https://stock.xueqiu.com/v5/stock/hot_stock/list.json?page=1&size=%d&_type=%s&type=%s", size, marketType, marketType)
+ res := &models.XUEQIUHot{}
+ _, err := resty.New().SetTimeout(time.Duration(30)*time.Second).R().
+ SetHeader("Host", "stock.xueqiu.com").
+ SetHeader("Origin", "https://xueqiu.com").
+ SetHeader("Referer", "https://xueqiu.com/").
+ SetHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:140.0) Gecko/20100101 Firefox/140.0").
+ SetHeader("Cookie", "cookiesu=2617378771242871; s=c2121pp1u71; device_id=237a58584ec58d8e4d4e1040700a644f1; Hm_lvt_1db88642e346389874251b5a1eded6e3=1744100219,1744599115; xq_a_token=b7259d09435458cc3f1a963479abb270a1a016ce; xqat=b7259d09435458cc3f1a963479abb270a1a016ce; xq_r_token=28108bfa1d92ac8a46bbb57722633746218621a3; xq_id_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJ1aWQiOi0xLCJpc3MiOiJ1YyIsImV4cCI6MTc1MjU0MTk4OCwiY3RtIjoxNzUwMjMwNjA2NzI0LCJjaWQiOiJkOWQwbjRBWnVwIn0.kU_fz0luJoE7nr-K4UrNUi5-mAG-vMdXtuC4mUKIppILId4UpF70LB70yunxGiNSw6tPFR3-hyLvztKAHtekCUTm3XjUl5b3tEDP-ZUVqHnWXO_5hoeMI8h-Cfx6ZGlIr5x3icvTPkT0OV5CD5A33-ZDTKhKPf-DhJ_-m7CG5GbX4MseOBeMXuLUQUiYHPKhX1QUc0GTGrCzi8Mki0z49D0LVqCSgbsx3UGfowOOyx85_cXb4OAFvIjwbs2p0o_h-ibIT0ngVkkAyEDetVvlcZ_bkardhseCB7k9BEMgH2z8ihgkVxyy3P0degLmDUruhmqn5uZOCi1pVBDvCv9lBg; u=261737877124287; ssxmod_itna=QuG=D5AKiKDIqCqGKi7G7DgmmPlSDWFqKGHDyx4YK0CDmxjKiddDUQivnb8xpnQcGyGYoYhoqEeDBubrDSxD67DK4GTm+ogiw1o3B=xedQHDgBtN=7/i1K53N+rOjquLMU=kbqYxB3DExGkqj0tPi4DxaPD5xDTDWeDGDD3DnnsDQKDRx0kL0oDIxD1D0bmHUEvh38mDYePLmOmDYPYx94Y8KoDeEgsD7HUl/vIGGEAqjLPFegXLD0HolCqr4DCid1qDm+ECfkjDn9sD0KP8fn+CRoDv=tYr4ibx+o=W+8vstf9mjGe3cXseWdBmoFrmf4DA3bFAxnAxD7vYxADaDoerDGHPoxHF+PKGPtDKmiqQGeB5qbi4eg4KDHKDe3DeG0qeEP9xVUoHDDWMYYM0ICr4FBimBDM7D0x4QOECmhul5QCN/m5/74lGm=7x9Wp7A+i7xQ7wlMD4D; ssxmod_itna2=QuG=D5AKiKDIqCqGKi7G7DgmmPlSDWFqKGHDyx4YK0CDmxjKiddDUQivnb8xpnQcGyGYoYhoqoDirSDhPmGD24GajjDuGE3m7or4DlxOSGewHl6iaus2Q62SRX5CFjCds6ltF9xy6iaUuB262UkhRA8UXST=4/b+y3kGKzlGE8T29FA008ljy9jXXC7f7m7QsK667mlUooWrofk=qGZjxtcUrN1NtuAnne1hj+rQP5UnlFkxf+o7VjmatH7u7bCDlbTt3cz6CH9Fl4vye16W/ellc8I3Q37W7ZwiLGD/zPpZcnd2nsqqo/+zRbKAmz4plzwaDqGUe7f9E+P0IFRKqpRv+buQFHBSpcbwND7Q+9XWmnjI2UwKd98jIS3gPXwxvbx4OuiyH8gZ+OEt7DgE/AY/9W4VxDZrlFWyWnC4y4/I0IpAfaGKpbPmauKbkqawqv93vSf+9HamGe0Dt2PNgT3yiEB4vQP2/DdVpcGBOjFujWoHP32OshLPYI20LRCKddwEGkKqPzPwKPc3X5zuB=w2fUdtwKsAW5kQtsl8clNwjC5uDYrxR0h9xaj0xmD+YuI3GPT7xYTalRImPj2wL2=+91a304xa4bTWtP=dLGARhb/efRi0uktaz8i8C04G0x/ZWUzqRza8GGU=FfRfvb4GZM/q2rVsl0nLvRjGeAKgocLouyXs/uwZu3YxbAx30qCbjG1A533zAxIeIgD=0VAc3ixD").
+ SetResult(res).
+ Get(url)
+ if err != nil {
+ logger.SugaredLogger.Errorf("XUEQIUHotStock err:%s", err.Error())
+ return &[]models.HotItem{}
+ }
+ logger.SugaredLogger.Infof("XUEQIUHotStock:%+v", res)
+ return &res.Data.Items
+}
+
+func (m MarketNewsApi) HotEvent(size int) *[]models.HotEvent {
+ events := &[]models.HotEvent{}
+ url := fmt.Sprintf("https://xueqiu.com/hot_event/list.json?count=%d", size)
+ resp, err := resty.New().SetTimeout(time.Duration(30)*time.Second).R().
+ SetHeader("Host", "xueqiu.com").
+ SetHeader("Origin", "https://xueqiu.com").
+ SetHeader("Referer", "https://xueqiu.com/").
+ SetHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:140.0) Gecko/20100101 Firefox/140.0").
+ SetHeader("Cookie", "cookiesu=2617378771242871; s=c2121pp1u71; device_id=237a58584ec58d8e4d4e1040700a644f1; Hm_lvt_1db88642e346389874251b5a1eded6e3=1744100219,1744599115; xq_a_token=b7259d09435458cc3f1a963479abb270a1a016ce; xqat=b7259d09435458cc3f1a963479abb270a1a016ce; xq_r_token=28108bfa1d92ac8a46bbb57722633746218621a3; xq_id_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJ1aWQiOi0xLCJpc3MiOiJ1YyIsImV4cCI6MTc1MjU0MTk4OCwiY3RtIjoxNzUwMjMwNjA2NzI0LCJjaWQiOiJkOWQwbjRBWnVwIn0.kU_fz0luJoE7nr-K4UrNUi5-mAG-vMdXtuC4mUKIppILId4UpF70LB70yunxGiNSw6tPFR3-hyLvztKAHtekCUTm3XjUl5b3tEDP-ZUVqHnWXO_5hoeMI8h-Cfx6ZGlIr5x3icvTPkT0OV5CD5A33-ZDTKhKPf-DhJ_-m7CG5GbX4MseOBeMXuLUQUiYHPKhX1QUc0GTGrCzi8Mki0z49D0LVqCSgbsx3UGfowOOyx85_cXb4OAFvIjwbs2p0o_h-ibIT0ngVkkAyEDetVvlcZ_bkardhseCB7k9BEMgH2z8ihgkVxyy3P0degLmDUruhmqn5uZOCi1pVBDvCv9lBg; u=261737877124287; ssxmod_itna=QuG=D5AKiKDIqCqGKi7G7DgmmPlSDWFqKGHDyx4YK0CDmxjKiddDUQivnb8xpnQcGyGYoYhoqEeDBubrDSxD67DK4GTm+ogiw1o3B=xedQHDgBtN=7/i1K53N+rOjquLMU=kbqYxB3DExGkqj0tPi4DxaPD5xDTDWeDGDD3DnnsDQKDRx0kL0oDIxD1D0bmHUEvh38mDYePLmOmDYPYx94Y8KoDeEgsD7HUl/vIGGEAqjLPFegXLD0HolCqr4DCid1qDm+ECfkjDn9sD0KP8fn+CRoDv=tYr4ibx+o=W+8vstf9mjGe3cXseWdBmoFrmf4DA3bFAxnAxD7vYxADaDoerDGHPoxHF+PKGPtDKmiqQGeB5qbi4eg4KDHKDe3DeG0qeEP9xVUoHDDWMYYM0ICr4FBimBDM7D0x4QOECmhul5QCN/m5/74lGm=7x9Wp7A+i7xQ7wlMD4D; ssxmod_itna2=QuG=D5AKiKDIqCqGKi7G7DgmmPlSDWFqKGHDyx4YK0CDmxjKiddDUQivnb8xpnQcGyGYoYhoqoDirSDhPmGD24GajjDuGE3m7or4DlxOSGewHl6iaus2Q62SRX5CFjCds6ltF9xy6iaUuB262UkhRA8UXST=4/b+y3kGKzlGE8T29FA008ljy9jXXC7f7m7QsK667mlUooWrofk=qGZjxtcUrN1NtuAnne1hj+rQP5UnlFkxf+o7VjmatH7u7bCDlbTt3cz6CH9Fl4vye16W/ellc8I3Q37W7ZwiLGD/zPpZcnd2nsqqo/+zRbKAmz4plzwaDqGUe7f9E+P0IFRKqpRv+buQFHBSpcbwND7Q+9XWmnjI2UwKd98jIS3gPXwxvbx4OuiyH8gZ+OEt7DgE/AY/9W4VxDZrlFWyWnC4y4/I0IpAfaGKpbPmauKbkqawqv93vSf+9HamGe0Dt2PNgT3yiEB4vQP2/DdVpcGBOjFujWoHP32OshLPYI20LRCKddwEGkKqPzPwKPc3X5zuB=w2fUdtwKsAW5kQtsl8clNwjC5uDYrxR0h9xaj0xmD+YuI3GPT7xYTalRImPj2wL2=+91a304xa4bTWtP=dLGARhb/efRi0uktaz8i8C04G0x/ZWUzqRza8GGU=FfRfvb4GZM/q2rVsl0nLvRjGeAKgocLouyXs/uwZu3YxbAx30qCbjG1A533zAxIeIgD=0VAc3ixD").
+ Get(url)
+ if err != nil {
+ logger.SugaredLogger.Errorf("HotEvent err:%s", err.Error())
+ return events
+ }
+ logger.SugaredLogger.Infof("HotEvent:%s", resp.Body())
+ respMap := map[string]any{}
+ err = json.Unmarshal(resp.Body(), &respMap)
+ items, err := json.Marshal(respMap["list"])
+ if err != nil {
+ return events
+ }
+ json.Unmarshal(items, events)
+ return events
+
+}
+
+func (m MarketNewsApi) HotTopic(size int) []any {
+ url := "https://gubatopic.eastmoney.com/interface/GetData.aspx?path=newtopic/api/Topic/HomePageListRead"
+ resp, err := resty.New().SetTimeout(time.Duration(30)*time.Second).R().
+ SetHeader("Host", "gubatopic.eastmoney.com").
+ SetHeader("Origin", "https://gubatopic.eastmoney.com").
+ SetHeader("Referer", "https://gubatopic.eastmoney.com/").
+ SetHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:140.0) Gecko/20100101 Firefox/140.0").
+ SetFormData(map[string]string{
+ "param": fmt.Sprintf("ps=%d&p=1&type=0", size),
+ "path": "newtopic/api/Topic/HomePageListRead",
+ "env": "2",
+ }).
+ Post(url)
+ if err != nil {
+ logger.SugaredLogger.Errorf("HotTopic err:%s", err.Error())
+ return []any{}
+ }
+ logger.SugaredLogger.Infof("HotTopic:%s", resp.Body())
+ respMap := map[string]any{}
+ err = json.Unmarshal(resp.Body(), &respMap)
+ return respMap["re"].([]any)
+
+}
diff --git a/backend/data/market_news_api_test.go b/backend/data/market_news_api_test.go
index 01d489b..d6279bd 100644
--- a/backend/data/market_news_api_test.go
+++ b/backend/data/market_news_api_test.go
@@ -108,3 +108,30 @@ func TestTradingViewNews(t *testing.T) {
logger.SugaredLogger.Debugf("value: %+v", a)
}
}
+
+func TestXUEQIUHotStock(t *testing.T) {
+ db.Init("../../data/stock.db")
+ res := NewMarketNewsApi().XUEQIUHotStock(50, "10")
+ for _, a := range *res {
+ logger.SugaredLogger.Debugf("value: %+v", a)
+ }
+
+}
+
+func TestHotEvent(t *testing.T) {
+ db.Init("../../data/stock.db")
+ res := NewMarketNewsApi().HotEvent(50)
+ for _, a := range *res {
+ logger.SugaredLogger.Debugf("value: %+v", a)
+ }
+
+}
+
+func TestHotTopic(t *testing.T) {
+ db.Init("../../data/stock.db")
+ res := NewMarketNewsApi().HotTopic(10)
+ for _, a := range res {
+ logger.SugaredLogger.Debugf("value: %+v", a)
+ }
+
+}
diff --git a/backend/models/models.go b/backend/models/models.go
index f513055..10d237b 100644
--- a/backend/models/models.go
+++ b/backend/models/models.go
@@ -317,3 +317,48 @@ type TVNews struct {
LogoId string `json:"logo_id"`
} `json:"provider"`
}
+
+type XUEQIUHot struct {
+ Data struct {
+ Items []HotItem `json:"items"`
+ ItemsSize int `json:"items_size"`
+ } `json:"data"`
+ ErrorCode int `json:"error_code"`
+ ErrorDescription string `json:"error_description"`
+}
+
+type HotItem struct {
+ Type int `json:"type"`
+ Code string `json:"code"`
+ Name string `json:"name"`
+ Value float64 `json:"value"`
+ Increment int `json:"increment"`
+ RankChange int `json:"rank_change"`
+ HasExist interface{} `json:"has_exist"`
+ Symbol string `json:"symbol"`
+ Percent float64 `json:"percent"`
+ Current float64 `json:"current"`
+ Chg float64 `json:"chg"`
+ Exchange string `json:"exchange"`
+ StockType int `json:"stock_type"`
+ SubType string `json:"sub_type"`
+ Ad int `json:"ad"`
+ AdId interface{} `json:"ad_id"`
+ ContentId interface{} `json:"content_id"`
+ Page interface{} `json:"page"`
+ Model interface{} `json:"model"`
+ Location interface{} `json:"location"`
+ TradeSession interface{} `json:"trade_session"`
+ CurrentExt interface{} `json:"current_ext"`
+ PercentExt interface{} `json:"percent_ext"`
+}
+
+type HotEvent struct {
+ PicSize interface{} `json:"pic_size"`
+ Tag string `json:"tag"`
+ Id int `json:"id"`
+ Pic string `json:"pic"`
+ Hot int `json:"hot"`
+ StatusCount int `json:"status_count"`
+ Content string `json:"content"`
+}
diff --git a/frontend/src/components/HotEvents.vue b/frontend/src/components/HotEvents.vue
new file mode 100644
index 0000000..8571f3f
--- /dev/null
+++ b/frontend/src/components/HotEvents.vue
@@ -0,0 +1,37 @@
+
+
+
+
+
+ 雪球热门
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frontend/src/components/HotStockList.vue b/frontend/src/components/HotStockList.vue
new file mode 100644
index 0000000..5f978c5
--- /dev/null
+++ b/frontend/src/components/HotStockList.vue
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+ 股票名称
+ 涨跌幅
+ 当前价格
+ 热度
+ 热度变化
+ 排名变化
+
+
+
+
+
+
+
+ {{item.name}} {{item.code}}
+
+
+
+
+ {{item.percent}}%
+ {{item.current}}
+ {{item.value}}
+ {{item.increment}}
+ {{item.rank_change}}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frontend/src/components/HotTopics.vue b/frontend/src/components/HotTopics.vue
new file mode 100644
index 0000000..6a3850f
--- /dev/null
+++ b/frontend/src/components/HotTopics.vue
@@ -0,0 +1,43 @@
+
+
+
+
+
+ 股吧热门
+
+
+
+
+
+
+
+
+
+
+ {{v.name}}
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frontend/src/components/KLineChart.vue b/frontend/src/components/KLineChart.vue
index 5791430..e1889c1 100644
--- a/frontend/src/components/KLineChart.vue
+++ b/frontend/src/components/KLineChart.vue
@@ -60,7 +60,7 @@ function handleKLine(code,name){
////console.log("values",values)
let option = {
title: {
- text: name,
+ text: name+" "+code,
left: '20px',
textStyle: {
color: darkTheme?'#ccc':'#456'
diff --git a/frontend/src/components/market.vue b/frontend/src/components/market.vue
index 7944673..c41038e 100644
--- a/frontend/src/components/market.vue
+++ b/frontend/src/components/market.vue
@@ -26,6 +26,9 @@ import StockResearchReportList from "./StockResearchReportList.vue";
import StockNoticeList from "./StockNoticeList.vue";
import LongTigerRankList from "./LongTigerRankList.vue";
import IndustryResearchReportList from "./IndustryResearchReportList.vue";
+import HotStockList from "./HotStockList.vue";
+import HotEvents from "./HotEvents.vue";
+import HotTopics from "./HotTopics.vue";
const route = useRoute()
const icon = ref('https://raw.githubusercontent.com/ArvinLovegood/go-stock/master/build/appicon.png');
@@ -557,8 +560,32 @@ function ReFlesh(source) {
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
>;
export function Greet(arg1:string):Promise;
+export function HotEvent(arg1:number):Promise;
+
+export function HotStock(arg1:string):Promise;
+
+export function HotTopic(arg1:number):Promise>;
+
export function IndustryResearchReport(arg1:string):Promise>;
export function LongTigerRank(arg1:string):Promise;
diff --git a/frontend/wailsjs/go/main/App.js b/frontend/wailsjs/go/main/App.js
index 27d7441..0e93c54 100644
--- a/frontend/wailsjs/go/main/App.js
+++ b/frontend/wailsjs/go/main/App.js
@@ -126,6 +126,18 @@ export function Greet(arg1) {
return window['go']['main']['App']['Greet'](arg1);
}
+export function HotEvent(arg1) {
+ return window['go']['main']['App']['HotEvent'](arg1);
+}
+
+export function HotStock(arg1) {
+ return window['go']['main']['App']['HotStock'](arg1);
+}
+
+export function HotTopic(arg1) {
+ return window['go']['main']['App']['HotTopic'](arg1);
+}
+
export function IndustryResearchReport(arg1) {
return window['go']['main']['App']['IndustryResearchReport'](arg1);
}
From 2f6c17fb2a60fae04f8d089485a5713375939800 Mon Sep 17 00:00:00 2001
From: ArvinLovegood
Date: Wed, 25 Jun 2025 09:41:16 +0800
Subject: [PATCH 06/21] =?UTF-8?q?feat(frontend):=E6=B7=BB=E5=8A=A0?=
=?UTF-8?q?=E7=83=AD=E9=97=A8=E8=82=A1=E7=A5=A8=E3=80=81=E4=BA=8B=E4=BB=B6?=
=?UTF-8?q?=E5=92=8C=E8=AF=9D=E9=A2=98=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 在 App.d.ts 和 App.js 中添加了 HotEvent、HotStock 和 HotTopic 函数
- 在 app_common.go 中实现了相关功能的后端逻辑
- 新增 HotEvents、HotStockList 和 HotTopics 组件用于前端展示
- 更新 market.vue以包含新的热门股票和话题功能
- 在 KLineChart.vue 中添加了代码和名称的显示
---
backend/data/market_news_api.go | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/backend/data/market_news_api.go b/backend/data/market_news_api.go
index ff74b2a..0a55591 100644
--- a/backend/data/market_news_api.go
+++ b/backend/data/market_news_api.go
@@ -590,7 +590,7 @@ func (m MarketNewsApi) XUEQIUHotStock(size int, marketType string) *[]models.Hot
logger.SugaredLogger.Errorf("XUEQIUHotStock err:%s", err.Error())
return &[]models.HotItem{}
}
- logger.SugaredLogger.Infof("XUEQIUHotStock:%+v", res)
+ // logger.SugaredLogger.Infof("XUEQIUHotStock:%+v", res)
return &res.Data.Items
}
@@ -608,7 +608,7 @@ func (m MarketNewsApi) HotEvent(size int) *[]models.HotEvent {
logger.SugaredLogger.Errorf("HotEvent err:%s", err.Error())
return events
}
- logger.SugaredLogger.Infof("HotEvent:%s", resp.Body())
+ //logger.SugaredLogger.Infof("HotEvent:%s", resp.Body())
respMap := map[string]any{}
err = json.Unmarshal(resp.Body(), &respMap)
items, err := json.Marshal(respMap["list"])
@@ -637,7 +637,7 @@ func (m MarketNewsApi) HotTopic(size int) []any {
logger.SugaredLogger.Errorf("HotTopic err:%s", err.Error())
return []any{}
}
- logger.SugaredLogger.Infof("HotTopic:%s", resp.Body())
+ //logger.SugaredLogger.Infof("HotTopic:%s", resp.Body())
respMap := map[string]any{}
err = json.Unmarshal(resp.Body(), &respMap)
return respMap["re"].([]any)
From e0225c41586e7600d356f25bfe5b8d89966f8b2a Mon Sep 17 00:00:00 2001
From: ArvinLovegood
Date: Wed, 25 Jun 2025 09:43:04 +0800
Subject: [PATCH 07/21] =?UTF-8?q?docs(README):=20=E6=B7=BB=E5=8A=A0?=
=?UTF-8?q?=E7=83=AD=E9=97=A8=E8=82=A1=E7=A5=A8=E3=80=81=E4=BA=8B=E4=BB=B6?=
=?UTF-8?q?=E5=92=8C=E8=AF=9D=E9=A2=98=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 在 README.md 文件的更新日志中添加了 2025.06.25 的更新内容- 新增了热门股票、事件和话题功能
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index e8511ef..62383f6 100644
--- a/README.md
+++ b/README.md
@@ -54,7 +54,7 @@
| 不再强制依赖Chrome浏览器 | ✅ | 默认使用edge浏览器抓取新闻资讯 |
## 👀 更新日志
-
+### 2025.06.25 添加热门股票、事件和话题功能
### 2025.06.18 更新内置股票基础数据,软件内实时市场资讯信息提醒,添加行业研究功能
### 2025.06.15 添加公司公告信息搜索/查看功能
### 2025.06.15 添加个股研报到弹出菜单
From 0e45866421b6d30d0cea4559427d58f1e170eb18 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=B5=93=E7=9D=A1=E4=B8=8D=E6=B6=88=E6=AE=8B=E9=85=92?=
<49932926+CodeNoobLH@users.noreply.github.com>
Date: Wed, 25 Jun 2025 10:21:40 +0800
Subject: [PATCH 08/21] =?UTF-8?q?fix(stock):=20=E4=BC=98=E5=8C=96=E8=82=A1?=
=?UTF-8?q?=E7=A5=A8=E4=BB=A3=E7=A0=81=E5=A4=84=E7=90=86=E9=80=BB=E8=BE=91?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 在关注股票时,仅当股票代码以 "us" 开头时,才将其转换为 "gb_" 前缀的格式
---
frontend/src/components/stock.vue | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/frontend/src/components/stock.vue b/frontend/src/components/stock.vue
index 424d655..89626f7 100644
--- a/frontend/src/components/stock.vue
+++ b/frontend/src/components/stock.vue
@@ -434,7 +434,9 @@ function AddStock() {
if (!stocks.value.includes(data.code)) {
Follow(data.code).then(result => {
if (result === "关注成功") {
- data.code= "gb_" + data.code.replace("us", "").toLowerCase()
+ if (data.code.startsWith("us")) {
+ data.code= "gb_" + data.code.replace("us", "").toLowerCase()
+ }
stocks.value.push(data.code)
message.success(result)
GetFollowList(currentGroupId.value).then(result => {
From 3f4cbca4a7f23c76fb5fbfbdad9886ac5772783e Mon Sep 17 00:00:00 2001
From: ArvinLovegood
Date: Wed, 25 Jun 2025 10:34:57 +0800
Subject: [PATCH 09/21] =?UTF-8?q?docs(README):=E6=B7=BB=E5=8A=A0=E7=83=AD?=
=?UTF-8?q?=E9=97=A8=E8=82=A1=E7=A5=A8=E3=80=81=E4=BA=8B=E4=BB=B6=E5=92=8C?=
=?UTF-8?q?=E8=AF=9D=E9=A2=98=E5=8A=9F=E8=83=BD=EF=BC=8C=E6=9B=B4=E6=96=B0?=
=?UTF-8?q?=E5=BC=80=E5=8F=91=E8=80=85=E5=88=97=E8=A1=A8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 在 README.md 文件的更新日志中添加了 2025.06.25 的更新内容- 新增了热门股票、事件和话题功能
---
frontend/src/components/about.vue | 1 +
1 file changed, 1 insertion(+)
diff --git a/frontend/src/components/about.vue b/frontend/src/components/about.vue
index 399760d..a40f660 100644
--- a/frontend/src/components/about.vue
+++ b/frontend/src/components/about.vue
@@ -135,6 +135,7 @@ EventsOn("updateVersion",async (msg) => {
感谢以下开发者:
+ 浓睡不消残酒
@gnim2600
@XXXiaohuayanGGG
@2lovecode
From 55839d332968aaad244aff1030df2dd1a21d5f8b Mon Sep 17 00:00:00 2001
From: ArvinLovegood
Date: Wed, 25 Jun 2025 13:37:55 +0800
Subject: [PATCH 10/21] =?UTF-8?q?feat(frontend):=E4=BC=98=E5=8C=96?=
=?UTF-8?q?=E7=83=AD=E9=97=A8=E8=82=A1=E7=A5=A8=E5=92=8C=E8=AF=9D=E9=A2=98?=
=?UTF-8?q?=E7=BB=84=E4=BB=B6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 更新热门股票列表,增加更多图标和数据字段
- 改进热门话题组件,添加点击事件和额外信息展示
- 调整股票搜索功能,使用居中弹窗打开链接
- 更新 App.vue 中的图标和菜单项
- 修改后端 HotStock 函数,增加返回数据量
---
app_common.go | 2 +-
frontend/src/App.vue | 36 +++++++++++++++++---
frontend/src/components/HotStockList.vue | 16 +++++++--
frontend/src/components/HotTopics.vue | 42 ++++++++++++++++++++----
frontend/src/components/stock.vue | 16 ++++++++-
5 files changed, 97 insertions(+), 15 deletions(-)
diff --git a/app_common.go b/app_common.go
index 587be55..7a9f6f0 100644
--- a/app_common.go
+++ b/app_common.go
@@ -33,7 +33,7 @@ func (a App) AnalyzeSentiment(text string) data.SentimentResult {
}
func (a App) HotStock(marketType string) *[]models.HotItem {
- return data.NewMarketNewsApi().XUEQIUHotStock(50, marketType)
+ return data.NewMarketNewsApi().XUEQIUHotStock(100, marketType)
}
func (a App) HotEvent(size int) *[]models.HotEvent {
diff --git a/frontend/src/App.vue b/frontend/src/App.vue
index 930966c..b371eed 100644
--- a/frontend/src/App.vue
+++ b/frontend/src/App.vue
@@ -14,7 +14,7 @@ import {createDiscreteApi,darkTheme,lightTheme , NIcon, NText,dateZhCN,zhCN} fro
import {
AlarmOutline,
AnalyticsOutline,
- BarChartSharp, EaselSharp,
+ BarChartSharp, Bonfire, BonfireOutline, EaselSharp,
ExpandOutline, Flag,
Flame, FlameSharp, InformationOutline,
LogoGithub,
@@ -28,6 +28,11 @@ import {
Wallet, WarningOutline,
} from '@vicons/ionicons5'
import {AnalyzeSentiment, GetConfig, GetGroupList} from "../wailsjs/go/main/App";
+import {Dragon, Fire, Gripfire} from "@vicons/fa";
+import {ReportSearch} from "@vicons/tabler";
+import {LocalFireDepartmentRound} from "@vicons/material";
+import {CommentNote20Filled} from "@vicons/fluent";
+import {FireFilled, FireOutlined, NotificationFilled, StockOutlined} from "@vicons/antd";
@@ -241,7 +246,7 @@ const menuOptions = ref([
{default: () => '龙虎榜',}
),
key: 'market6',
- icon: renderIcon(Skull),
+ icon: renderIcon(Dragon),
},
{
label: () =>
@@ -262,7 +267,7 @@ const menuOptions = ref([
{default: () => '个股研报',}
),
key: 'market7',
- icon: renderIcon(NewspaperSharp),
+ icon: renderIcon(StockOutlined),
},
{
label: () =>
@@ -283,7 +288,7 @@ const menuOptions = ref([
{default: () => '公司公告',}
),
key: 'market8',
- icon: renderIcon(NewspaperSharp),
+ icon: renderIcon(NotificationFilled),
},
{
label: () =>
@@ -304,7 +309,28 @@ const menuOptions = ref([
{default: () => '行业研究',}
),
key: 'market9',
- icon: renderIcon(NewspaperSharp),
+ icon: renderIcon(ReportSearch),
+ },
+ {
+ label: () =>
+ h(
+ RouterLink,
+ {
+ href: '#',
+ to: {
+ name: 'market',
+ query: {
+ name: "当前热门",
+ }
+ },
+ onClick: () => {
+ EventsEmit("changeMarketTab", {ID: 0, name: '当前热门'})
+ },
+ },
+ {default: () => '当前热门',}
+ ),
+ key: 'market10',
+ icon: renderIcon(Gripfire),
},
]
},
diff --git a/frontend/src/components/HotStockList.vue b/frontend/src/components/HotStockList.vue
index 5f978c5..9846deb 100644
--- a/frontend/src/components/HotStockList.vue
+++ b/frontend/src/components/HotStockList.vue
@@ -2,6 +2,7 @@
import {onBeforeMount, onUnmounted, ref} from 'vue'
import {HotStock} from "../../wailsjs/go/main/App";
import KLineChart from "./KLineChart.vue";
+import {ArrowBack, ArrowDown, ArrowUp} from "@vicons/ionicons5";
const {marketType}=defineProps(
{
@@ -64,8 +65,19 @@ function getMarketCode(item) {
{{item.percent}}%
{{item.current}}
{{item.value}}
- {{item.increment}}
- {{item.rank_change}}
+
+ {{item.increment}}
+
+
+
+
+
+ {{item.rank_change}}
+
+
+
+
+
diff --git a/frontend/src/components/HotTopics.vue b/frontend/src/components/HotTopics.vue
index 6a3850f..e203788 100644
--- a/frontend/src/components/HotTopics.vue
+++ b/frontend/src/components/HotTopics.vue
@@ -13,26 +13,56 @@ onBeforeMount(async () => {
onUnmounted(()=>{
clearInterval(task.value)
})
+
+function openCenteredWindow(url, width, height) {
+ const left = (window.screen.width - width) / 2;
+ const top = (window.screen.height - height) / 2;
+
+ return window.open(
+ url,
+ 'centeredWindow',
+ `width=${width},height=${height},left=${left},top=${top}`
+ );
+}
+function showPage(htid) {
+ openCenteredWindow(`https://gubatopic.eastmoney.com/topic_v3.html?htid=${htid}`, 1000, 600)
+}
-
-
- 股吧热门
-
+
+
+
+
-
+
-
+
{{v.name}}
+
+
+ 讨论数:
+
+ 浏览量:
+
+
+
diff --git a/frontend/src/components/stock.vue b/frontend/src/components/stock.vue
index 89626f7..8721981 100644
--- a/frontend/src/components/stock.vue
+++ b/frontend/src/components/stock.vue
@@ -606,14 +606,28 @@ function onSelect(item) {
}
+function openCenteredWindow(url, width, height) {
+ const left = (window.screen.width - width) / 2;
+ const top = (window.screen.height - height) / 2;
+
+ return window.open(
+ url,
+ 'centeredWindow',
+ `width=${width},height=${height},left=${left},top=${top}`
+ );
+}
+
function search(code, name) {
setTimeout(() => {
//window.open("https://xueqiu.com/S/"+code)
//window.open("https://www.cls.cn/stock?code="+code)
//window.open("https://quote.eastmoney.com/"+code+".html")
//window.open("https://finance.sina.com.cn/realstock/company/"+code+"/nc.shtml")
- window.open("https://www.iwencai.com/unifiedwap/result?w=" + name)
+ //window.open("https://www.iwencai.com/unifiedwap/result?w=" + name)
//window.open("https://www.iwencai.com/chat/?question="+code)
+
+ openCenteredWindow("https://www.iwencai.com/unifiedwap/result?w=" + name,1000,800)
+
}, 500)
}
From f0ad50303ec160b7d39765f9acc736fe2fae48cc Mon Sep 17 00:00:00 2001
From: ArvinLovegood
Date: Wed, 25 Jun 2025 13:52:31 +0800
Subject: [PATCH 11/21] =?UTF-8?q?feat(frontend):=E4=BC=98=E5=8C=96?=
=?UTF-8?q?=E7=83=AD=E9=97=A8=E8=82=A1=E7=A5=A8=E5=92=8C=E8=AF=9D=E9=A2=98?=
=?UTF-8?q?=E7=BB=84=E4=BB=B6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 更新热门股票列表,增加更多图标和数据字段
- 改进热门话题组件,添加点击事件和额外信息展示
- 调整股票搜索功能,使用居中弹窗打开链接
- 更新 App.vue 中的图标和菜单项
- 修改后端 HotStock 函数,增加返回数据量
---
package-lock.json | 67 +++++++++++++++++++++++++++++++++++++++++++++++
package.json | 12 +++++++++
2 files changed, 79 insertions(+)
create mode 100644 package-lock.json
create mode 100644 package.json
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..df76aa4
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,67 @@
+{
+ "name": "go-stock",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "devDependencies": {
+ "@vicons/antd": "^0.13.0",
+ "@vicons/carbon": "^0.13.0",
+ "@vicons/fa": "^0.13.0",
+ "@vicons/fluent": "^0.13.0",
+ "@vicons/ionicons4": "^0.13.0",
+ "@vicons/ionicons5": "^0.13.0",
+ "@vicons/material": "^0.13.0",
+ "@vicons/tabler": "^0.13.0"
+ }
+ },
+ "node_modules/@vicons/antd": {
+ "version": "0.13.0",
+ "resolved": "https://registry.npmmirror.com/@vicons/antd/-/antd-0.13.0.tgz",
+ "integrity": "sha512-yrUGoUSz2BbGupk9ghQOahc04n5H3MwUDM9pVPsLh9U1uqB47oRWZvYRiZaT1JKPqgTgSE6BXcVw4i9MOF4M+g==",
+ "dev": true
+ },
+ "node_modules/@vicons/carbon": {
+ "version": "0.13.0",
+ "resolved": "https://registry.npmmirror.com/@vicons/carbon/-/carbon-0.13.0.tgz",
+ "integrity": "sha512-Z/jExyyS4gsXJc66oTqV/j98nsaiX2JlQ0IUwu9Ms3rztf8VOHEQRuX8Jey1/zbxJpFY/tU+bWvKPRFYGIvCWQ==",
+ "dev": true
+ },
+ "node_modules/@vicons/fa": {
+ "version": "0.13.0",
+ "resolved": "https://registry.npmmirror.com/@vicons/fa/-/fa-0.13.0.tgz",
+ "integrity": "sha512-BFcDewcT78fSn4Y/fOgqlswbLUEW3+qJK2iJiNtgmkMzadBVpDXhNyVKsYM3V2uKPvDUrZT0JCWDWVRCiBXJZA==",
+ "dev": true
+ },
+ "node_modules/@vicons/fluent": {
+ "version": "0.13.0",
+ "resolved": "https://registry.npmmirror.com/@vicons/fluent/-/fluent-0.13.0.tgz",
+ "integrity": "sha512-bYGZsOE3qzvm3Cm43e7tybgGlr5ZUpYqtRZq0g0Tfupe8jIzLolpvQLNUt1zS8Mgt6goTbUk5YH7Fkv16jkykg==",
+ "dev": true
+ },
+ "node_modules/@vicons/ionicons4": {
+ "version": "0.13.0",
+ "resolved": "https://registry.npmmirror.com/@vicons/ionicons4/-/ionicons4-0.13.0.tgz",
+ "integrity": "sha512-5WHIl/4R5a4i9GONa+hIQWxg/WczrbsCdqxawHZvdd3drsEr+Q3yzlfS+NNRO4WS3uDW2uWLCwoW+yp5TgcKeQ==",
+ "dev": true
+ },
+ "node_modules/@vicons/ionicons5": {
+ "version": "0.13.0",
+ "resolved": "https://registry.npmmirror.com/@vicons/ionicons5/-/ionicons5-0.13.0.tgz",
+ "integrity": "sha512-zvZKBPjEXKN7AXNo2Na2uy+nvuv6SP4KAMQxpKL2vfHMj0fSvuw7JZcOPCjQC3e7ayssKnaoFVAhbYcW6v41qQ==",
+ "dev": true
+ },
+ "node_modules/@vicons/material": {
+ "version": "0.13.0",
+ "resolved": "https://registry.npmmirror.com/@vicons/material/-/material-0.13.0.tgz",
+ "integrity": "sha512-lKVxFNprM+CaBkUH3gt6VjIeiMsKQl2zARQMwTCZruQl2vRHzyeZiKeCflWS99CEfv2JzX/6y697smxlzyxcVw==",
+ "dev": true
+ },
+ "node_modules/@vicons/tabler": {
+ "version": "0.13.0",
+ "resolved": "https://registry.npmmirror.com/@vicons/tabler/-/tabler-0.13.0.tgz",
+ "integrity": "sha512-AykuhiqjszkIoAL/7knIFm6RDOBS1ZmQdJfQ+RNLEah0fVsxykUFCfMBSNZh8lOzC85EtdD1k5g/sv5GYk0Ohg==",
+ "dev": true
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..7cc270d
--- /dev/null
+++ b/package.json
@@ -0,0 +1,12 @@
+{
+ "devDependencies": {
+ "@vicons/antd": "^0.13.0",
+ "@vicons/carbon": "^0.13.0",
+ "@vicons/fa": "^0.13.0",
+ "@vicons/fluent": "^0.13.0",
+ "@vicons/ionicons4": "^0.13.0",
+ "@vicons/ionicons5": "^0.13.0",
+ "@vicons/material": "^0.13.0",
+ "@vicons/tabler": "^0.13.0"
+ }
+}
From 1fbd564bfff2fb5eac8c810d2ab390b3398f0616 Mon Sep 17 00:00:00 2001
From: ArvinLovegood
Date: Wed, 25 Jun 2025 14:10:26 +0800
Subject: [PATCH 12/21] =?UTF-8?q?build(frontend):=E6=9B=B4=E6=96=B0Node.js?=
=?UTF-8?q?=E7=89=88=E6=9C=AC=E5=B9=B6=E8=BF=81=E7=A7=BB=E5=9B=BE=E6=A0=87?=
=?UTF-8?q?=E5=BA=93?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 将 Node.js 版本从 18.x 升级到 20.x
- 从 package.json 中移除 @vicons/ionicons5 依赖
- 在 devDependencies 中添加多个 @vicons 开头的图标库
- 更新 package-lock.json 和相关文件以反映这些更改
---
.github/workflows/main.yml | 2 +-
frontend/package-lock.json | 54 ++++++++++++++++++++++++++++--
frontend/package.json | 9 ++++-
frontend/package.json.md5 | 2 +-
package-lock.json | 67 --------------------------------------
package.json | 12 -------
6 files changed, 62 insertions(+), 84 deletions(-)
delete mode 100644 package-lock.json
delete mode 100644 package.json
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 8bfb5de..dcdbe05 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -47,4 +47,4 @@ jobs:
go-version: '1.24'
build-tags: ${{ github.ref_name }}
build-commit-message: ${{ steps.get_commit_message.outputs.commit_message }}
- node-version: '18.x'
+ node-version: '20.x'
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index f53e553..f7836cc 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -11,7 +11,6 @@
"@types/file-saver": "^2.0.7",
"@vavt/cm-extension": "^1.8.0",
"@vavt/v3-extension": "^3.0.0",
- "@vicons/ionicons5": "^0.13.0",
"echarts": "^5.6.0",
"file-saver": "^2.0.5",
"html2canvas": "^1.4.1",
@@ -22,6 +21,14 @@
"vue3-danmaku": "^1.6.1"
},
"devDependencies": {
+ "@vicons/antd": "^0.13.0",
+ "@vicons/carbon": "^0.13.0",
+ "@vicons/fa": "^0.13.0",
+ "@vicons/fluent": "^0.13.0",
+ "@vicons/ionicons4": "^0.13.0",
+ "@vicons/ionicons5": "^0.13.0",
+ "@vicons/material": "^0.13.0",
+ "@vicons/tabler": "^0.13.0",
"@vitejs/plugin-vue": "^5.2.1",
"html-docx-js-typescript": "^0.1.5",
"naive-ui": "^2.41.0",
@@ -1433,10 +1440,53 @@
"md-editor-v3": ">=5.2.0"
}
},
+ "node_modules/@vicons/antd": {
+ "version": "0.13.0",
+ "resolved": "https://registry.npmmirror.com/@vicons/antd/-/antd-0.13.0.tgz",
+ "integrity": "sha512-yrUGoUSz2BbGupk9ghQOahc04n5H3MwUDM9pVPsLh9U1uqB47oRWZvYRiZaT1JKPqgTgSE6BXcVw4i9MOF4M+g==",
+ "dev": true
+ },
+ "node_modules/@vicons/carbon": {
+ "version": "0.13.0",
+ "resolved": "https://registry.npmmirror.com/@vicons/carbon/-/carbon-0.13.0.tgz",
+ "integrity": "sha512-Z/jExyyS4gsXJc66oTqV/j98nsaiX2JlQ0IUwu9Ms3rztf8VOHEQRuX8Jey1/zbxJpFY/tU+bWvKPRFYGIvCWQ==",
+ "dev": true
+ },
+ "node_modules/@vicons/fa": {
+ "version": "0.13.0",
+ "resolved": "https://registry.npmmirror.com/@vicons/fa/-/fa-0.13.0.tgz",
+ "integrity": "sha512-BFcDewcT78fSn4Y/fOgqlswbLUEW3+qJK2iJiNtgmkMzadBVpDXhNyVKsYM3V2uKPvDUrZT0JCWDWVRCiBXJZA==",
+ "dev": true
+ },
+ "node_modules/@vicons/fluent": {
+ "version": "0.13.0",
+ "resolved": "https://registry.npmmirror.com/@vicons/fluent/-/fluent-0.13.0.tgz",
+ "integrity": "sha512-bYGZsOE3qzvm3Cm43e7tybgGlr5ZUpYqtRZq0g0Tfupe8jIzLolpvQLNUt1zS8Mgt6goTbUk5YH7Fkv16jkykg==",
+ "dev": true
+ },
+ "node_modules/@vicons/ionicons4": {
+ "version": "0.13.0",
+ "resolved": "https://registry.npmmirror.com/@vicons/ionicons4/-/ionicons4-0.13.0.tgz",
+ "integrity": "sha512-5WHIl/4R5a4i9GONa+hIQWxg/WczrbsCdqxawHZvdd3drsEr+Q3yzlfS+NNRO4WS3uDW2uWLCwoW+yp5TgcKeQ==",
+ "dev": true
+ },
"node_modules/@vicons/ionicons5": {
"version": "0.13.0",
"resolved": "https://registry.npmmirror.com/@vicons/ionicons5/-/ionicons5-0.13.0.tgz",
- "integrity": "sha512-zvZKBPjEXKN7AXNo2Na2uy+nvuv6SP4KAMQxpKL2vfHMj0fSvuw7JZcOPCjQC3e7ayssKnaoFVAhbYcW6v41qQ=="
+ "integrity": "sha512-zvZKBPjEXKN7AXNo2Na2uy+nvuv6SP4KAMQxpKL2vfHMj0fSvuw7JZcOPCjQC3e7ayssKnaoFVAhbYcW6v41qQ==",
+ "dev": true
+ },
+ "node_modules/@vicons/material": {
+ "version": "0.13.0",
+ "resolved": "https://registry.npmmirror.com/@vicons/material/-/material-0.13.0.tgz",
+ "integrity": "sha512-lKVxFNprM+CaBkUH3gt6VjIeiMsKQl2zARQMwTCZruQl2vRHzyeZiKeCflWS99CEfv2JzX/6y697smxlzyxcVw==",
+ "dev": true
+ },
+ "node_modules/@vicons/tabler": {
+ "version": "0.13.0",
+ "resolved": "https://registry.npmmirror.com/@vicons/tabler/-/tabler-0.13.0.tgz",
+ "integrity": "sha512-AykuhiqjszkIoAL/7knIFm6RDOBS1ZmQdJfQ+RNLEah0fVsxykUFCfMBSNZh8lOzC85EtdD1k5g/sv5GYk0Ohg==",
+ "dev": true
},
"node_modules/@vitejs/plugin-vue": {
"version": "5.2.1",
diff --git a/frontend/package.json b/frontend/package.json
index 64919e4..24e27d5 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -12,7 +12,6 @@
"@types/file-saver": "^2.0.7",
"@vavt/cm-extension": "^1.8.0",
"@vavt/v3-extension": "^3.0.0",
- "@vicons/ionicons5": "^0.13.0",
"echarts": "^5.6.0",
"file-saver": "^2.0.5",
"html2canvas": "^1.4.1",
@@ -23,6 +22,14 @@
"vue3-danmaku": "^1.6.1"
},
"devDependencies": {
+ "@vicons/antd": "^0.13.0",
+ "@vicons/carbon": "^0.13.0",
+ "@vicons/fa": "^0.13.0",
+ "@vicons/fluent": "^0.13.0",
+ "@vicons/ionicons4": "^0.13.0",
+ "@vicons/ionicons5": "^0.13.0",
+ "@vicons/material": "^0.13.0",
+ "@vicons/tabler": "^0.13.0",
"@vitejs/plugin-vue": "^5.2.1",
"html-docx-js-typescript": "^0.1.5",
"naive-ui": "^2.41.0",
diff --git a/frontend/package.json.md5 b/frontend/package.json.md5
index 3f00715..018b90a 100644
--- a/frontend/package.json.md5
+++ b/frontend/package.json.md5
@@ -1 +1 @@
-b71b647d53bb771e87fac6e1372d9acf
\ No newline at end of file
+f64f2faecc1cae8baa43eca694be54ac
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
deleted file mode 100644
index df76aa4..0000000
--- a/package-lock.json
+++ /dev/null
@@ -1,67 +0,0 @@
-{
- "name": "go-stock",
- "lockfileVersion": 3,
- "requires": true,
- "packages": {
- "": {
- "devDependencies": {
- "@vicons/antd": "^0.13.0",
- "@vicons/carbon": "^0.13.0",
- "@vicons/fa": "^0.13.0",
- "@vicons/fluent": "^0.13.0",
- "@vicons/ionicons4": "^0.13.0",
- "@vicons/ionicons5": "^0.13.0",
- "@vicons/material": "^0.13.0",
- "@vicons/tabler": "^0.13.0"
- }
- },
- "node_modules/@vicons/antd": {
- "version": "0.13.0",
- "resolved": "https://registry.npmmirror.com/@vicons/antd/-/antd-0.13.0.tgz",
- "integrity": "sha512-yrUGoUSz2BbGupk9ghQOahc04n5H3MwUDM9pVPsLh9U1uqB47oRWZvYRiZaT1JKPqgTgSE6BXcVw4i9MOF4M+g==",
- "dev": true
- },
- "node_modules/@vicons/carbon": {
- "version": "0.13.0",
- "resolved": "https://registry.npmmirror.com/@vicons/carbon/-/carbon-0.13.0.tgz",
- "integrity": "sha512-Z/jExyyS4gsXJc66oTqV/j98nsaiX2JlQ0IUwu9Ms3rztf8VOHEQRuX8Jey1/zbxJpFY/tU+bWvKPRFYGIvCWQ==",
- "dev": true
- },
- "node_modules/@vicons/fa": {
- "version": "0.13.0",
- "resolved": "https://registry.npmmirror.com/@vicons/fa/-/fa-0.13.0.tgz",
- "integrity": "sha512-BFcDewcT78fSn4Y/fOgqlswbLUEW3+qJK2iJiNtgmkMzadBVpDXhNyVKsYM3V2uKPvDUrZT0JCWDWVRCiBXJZA==",
- "dev": true
- },
- "node_modules/@vicons/fluent": {
- "version": "0.13.0",
- "resolved": "https://registry.npmmirror.com/@vicons/fluent/-/fluent-0.13.0.tgz",
- "integrity": "sha512-bYGZsOE3qzvm3Cm43e7tybgGlr5ZUpYqtRZq0g0Tfupe8jIzLolpvQLNUt1zS8Mgt6goTbUk5YH7Fkv16jkykg==",
- "dev": true
- },
- "node_modules/@vicons/ionicons4": {
- "version": "0.13.0",
- "resolved": "https://registry.npmmirror.com/@vicons/ionicons4/-/ionicons4-0.13.0.tgz",
- "integrity": "sha512-5WHIl/4R5a4i9GONa+hIQWxg/WczrbsCdqxawHZvdd3drsEr+Q3yzlfS+NNRO4WS3uDW2uWLCwoW+yp5TgcKeQ==",
- "dev": true
- },
- "node_modules/@vicons/ionicons5": {
- "version": "0.13.0",
- "resolved": "https://registry.npmmirror.com/@vicons/ionicons5/-/ionicons5-0.13.0.tgz",
- "integrity": "sha512-zvZKBPjEXKN7AXNo2Na2uy+nvuv6SP4KAMQxpKL2vfHMj0fSvuw7JZcOPCjQC3e7ayssKnaoFVAhbYcW6v41qQ==",
- "dev": true
- },
- "node_modules/@vicons/material": {
- "version": "0.13.0",
- "resolved": "https://registry.npmmirror.com/@vicons/material/-/material-0.13.0.tgz",
- "integrity": "sha512-lKVxFNprM+CaBkUH3gt6VjIeiMsKQl2zARQMwTCZruQl2vRHzyeZiKeCflWS99CEfv2JzX/6y697smxlzyxcVw==",
- "dev": true
- },
- "node_modules/@vicons/tabler": {
- "version": "0.13.0",
- "resolved": "https://registry.npmmirror.com/@vicons/tabler/-/tabler-0.13.0.tgz",
- "integrity": "sha512-AykuhiqjszkIoAL/7knIFm6RDOBS1ZmQdJfQ+RNLEah0fVsxykUFCfMBSNZh8lOzC85EtdD1k5g/sv5GYk0Ohg==",
- "dev": true
- }
- }
-}
diff --git a/package.json b/package.json
deleted file mode 100644
index 7cc270d..0000000
--- a/package.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "devDependencies": {
- "@vicons/antd": "^0.13.0",
- "@vicons/carbon": "^0.13.0",
- "@vicons/fa": "^0.13.0",
- "@vicons/fluent": "^0.13.0",
- "@vicons/ionicons4": "^0.13.0",
- "@vicons/ionicons5": "^0.13.0",
- "@vicons/material": "^0.13.0",
- "@vicons/tabler": "^0.13.0"
- }
-}
From bbab60e2ad02b809b7571cca6f62ea3ba258b3c5 Mon Sep 17 00:00:00 2001
From: ArvinLovegood
Date: Thu, 26 Jun 2025 13:19:07 +0800
Subject: [PATCH 13/21] =?UTF-8?q?docs(README):=E6=B7=BB=E5=8A=A0=E4=BC=98?=
=?UTF-8?q?=E4=BA=91=E6=99=BA=E7=AE=97=E5=B9=B3=E5=8F=B0=E4=BF=A1=E6=81=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 在 README.md 中添加优云智算平台信息,提供免费 GPU 资源和海量源项目镜像
- 在 stock_data_api.go 中增加关注股票数量的限制,最多只能关注 63 只股票
---
README.md | 1 +
backend/data/stock_data_api.go | 7 +++++++
2 files changed, 8 insertions(+)
diff --git a/README.md b/README.md
index 62383f6..b58a6ea 100644
--- a/README.md
+++ b/README.md
@@ -36,6 +36,7 @@
| [大模型聚合平台](https://cloud.siliconflow.cn/i/foufCerk) | ✅ | 如:[硅基流动](https://cloud.siliconflow.cn/i/foufCerk),[火山方舟](https://www.volcengine.com/experience/ark?utm_term=202502dsinvite&ac=DSASUQY5&rc=IJSE43PZ) |
### 各位亲爱的朋友们,如果您对这个项目感兴趣,请先给我一个star吧,谢谢!💕
+- 优云智算(by UCloud):万卡规模4090免费用10小时,新人注册另增50万tokens,海量热门源项目镜像一键部署,[注册链接](https://www.compshare.cn/image-community?ytag=GPU_YY-gh_gostock)
- 经测试目前硅基流动(siliconflow)提供的deepSeek api 服务比较稳定,注册即送2000万Tokens,[注册链接](https://cloud.siliconflow.cn/i/foufCerk)
- 火山方舟:每个模型注册即送50万tokens,[注册链接](https://www.volcengine.com/experience/ark?utm_term=202502dsinvite&ac=DSASUQY5&rc=IJSE43PZ)
- Tushare大数据开放社区,免费提供各类金融数据,助力行业和量化研究(注意:Tushare只需要120积分即可,注册完成个人资料补充即可得120积分!!!),[注册链接](https://tushare.pro/register?reg=701944)
diff --git a/backend/data/stock_data_api.go b/backend/data/stock_data_api.go
index 334f938..f88b590 100644
--- a/backend/data/stock_data_api.go
+++ b/backend/data/stock_data_api.go
@@ -406,6 +406,13 @@ func (receiver StockDataApi) Follow(stockCode string) string {
if strings.HasPrefix(stockCode, "US") {
stockCode = strings.Replace(stockCode, "US", "gb_", 1)
}
+ count := int64(0)
+ db.Dao.Model(&FollowedStock{}).Where("is_del = ?", 0).Count(&count)
+ logger.SugaredLogger.Errorf("Follow-count %v", count)
+ if count >= 63 {
+ return "最多只能关注63只股票"
+ }
+
stockCode = strings.ToLower(stockCode)
maxSort := int64(0)
db.Dao.Model(&FollowedStock{}).Raw("select max(sort) as sort from followed_stock").Scan(&maxSort)
From 0ce7e8e7a751812f598d4082d901d683d512ffc6 Mon Sep 17 00:00:00 2001
From: ArvinLovegood
Date: Thu, 26 Jun 2025 13:25:15 +0800
Subject: [PATCH 14/21] =?UTF-8?q?docs(README):=E6=B7=BB=E5=8A=A0=E4=BC=98?=
=?UTF-8?q?=E4=BA=91=E6=99=BA=E7=AE=97=E5=B9=B3=E5=8F=B0=E4=BF=A1=E6=81=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 在 README.md 中添加优云智算平台信息,提供免费 GPU 资源和海量源项目镜像
---
README.md | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/README.md b/README.md
index b58a6ea..925455b 100644
--- a/README.md
+++ b/README.md
@@ -26,14 +26,14 @@
### 💬 支持大模型/平台
-| 模型 | 状态 | 备注 |
-| --- | --- |-----------------------------------------------------------------------------------------------------------------------------------------------------|
-| [OpenAI](https://platform.openai.com/) | ✅ | 可接入任何 OpenAI 接口格式模型 |
-| [Ollama](https://ollama.com/) | ✅ | 本地大模型运行平台 |
-| [LMStudio](https://lmstudio.ai/) | ✅ | 本地大模型运行平台 |
-| [AnythingLLM](https://anythingllm.com/) | ✅ | 本地知识库 |
-| [DeepSeek](https://www.deepseek.com/) | ✅ | deepseek-reasoner,deepseek-chat |
-| [大模型聚合平台](https://cloud.siliconflow.cn/i/foufCerk) | ✅ | 如:[硅基流动](https://cloud.siliconflow.cn/i/foufCerk),[火山方舟](https://www.volcengine.com/experience/ark?utm_term=202502dsinvite&ac=DSASUQY5&rc=IJSE43PZ) |
+| 模型 | 状态 | 备注 |
+| --- | --- |---------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| [OpenAI](https://platform.openai.com/) | ✅ | 可接入任何 OpenAI 接口格式模型 |
+| [Ollama](https://ollama.com/) | ✅ | 本地大模型运行平台 |
+| [LMStudio](https://lmstudio.ai/) | ✅ | 本地大模型运行平台 |
+| [AnythingLLM](https://anythingllm.com/) | ✅ | 本地知识库 |
+| [DeepSeek](https://www.deepseek.com/) | ✅ | deepseek-reasoner,deepseek-chat |
+| [大模型聚合平台](https://cloud.siliconflow.cn/i/foufCerk) | ✅ | 如:[硅基流动](https://cloud.siliconflow.cn/i/foufCerk),[火山方舟](https://www.volcengine.com/experience/ark?utm_term=202502dsinvite&ac=DSASUQY5&rc=IJSE43PZ) ,[优云智算](https://www.compshare.cn/image-community?ytag=GPU_YY-gh_gostock) |
### 各位亲爱的朋友们,如果您对这个项目感兴趣,请先给我一个star吧,谢谢!💕
- 优云智算(by UCloud):万卡规模4090免费用10小时,新人注册另增50万tokens,海量热门源项目镜像一键部署,[注册链接](https://www.compshare.cn/image-community?ytag=GPU_YY-gh_gostock)
From 86f041b4d67a515bced2746c08a5b76db5bf465b Mon Sep 17 00:00:00 2001
From: ArvinLovegood
Date: Fri, 27 Jun 2025 17:46:50 +0800
Subject: [PATCH 15/21] =?UTF-8?q?feat(frontend):=E6=B7=BB=E5=8A=A0?=
=?UTF-8?q?=E8=B4=A2=E7=BB=8F=E6=97=A5=E5=8E=86=E5=92=8C=E9=87=8D=E5=A4=A7?=
=?UTF-8?q?=E4=BA=8B=E4=BB=B6=E6=97=B6=E9=97=B4=E8=BD=B4=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 在 App.d.ts 和 App.js 中添加了 ClsCalendar 和 InvestCalendarTimeLine 函数
- 在 app_common.go 中实现了对应的后端逻辑
- 新增了 InvestCalendarTimeLine 和 ClsCalendarTimeLine组件用于展示数据
- 更新了 market.vue 中的 tabs,添加了新功能的页面
---
README.md | 1 +
app_common.go | 7 ++
backend/data/market_news_api.go | 49 ++++++++
backend/data/market_news_api_test.go | 16 +++
frontend/package-lock.json | 20 +++-
frontend/package.json | 1 +
frontend/package.json.md5 | 2 +-
.../src/components/ClsCalendarTimeLine.vue | 102 +++++++++++++++++
.../src/components/InvestCalendarTimeLine.vue | 108 ++++++++++++++++++
frontend/src/components/market.vue | 8 ++
frontend/wailsjs/go/main/App.d.ts | 4 +
frontend/wailsjs/go/main/App.js | 8 ++
12 files changed, 321 insertions(+), 5 deletions(-)
create mode 100644 frontend/src/components/ClsCalendarTimeLine.vue
create mode 100644 frontend/src/components/InvestCalendarTimeLine.vue
diff --git a/README.md b/README.md
index 925455b..e6c8e8d 100644
--- a/README.md
+++ b/README.md
@@ -55,6 +55,7 @@
| 不再强制依赖Chrome浏览器 | ✅ | 默认使用edge浏览器抓取新闻资讯 |
## 👀 更新日志
+### 2025.06.27 添加财经日历和重大事件时间轴功能
### 2025.06.25 添加热门股票、事件和话题功能
### 2025.06.18 更新内置股票基础数据,软件内实时市场资讯信息提醒,添加行业研究功能
### 2025.06.15 添加公司公告信息搜索/查看功能
diff --git a/app_common.go b/app_common.go
index 7a9f6f0..600668e 100644
--- a/app_common.go
+++ b/app_common.go
@@ -48,3 +48,10 @@ func (a App) HotTopic(size int) []any {
}
return data.NewMarketNewsApi().HotTopic(size)
}
+
+func (a App) InvestCalendarTimeLine(yearMonth string) []any {
+ return data.NewMarketNewsApi().InvestCalendar(yearMonth)
+}
+func (a App) ClsCalendar() []any {
+ return data.NewMarketNewsApi().ClsCalendar()
+}
diff --git a/backend/data/market_news_api.go b/backend/data/market_news_api.go
index 0a55591..7cc91aa 100644
--- a/backend/data/market_news_api.go
+++ b/backend/data/market_news_api.go
@@ -643,3 +643,52 @@ func (m MarketNewsApi) HotTopic(size int) []any {
return respMap["re"].([]any)
}
+
+func (m MarketNewsApi) InvestCalendar(yearMonth string) []any {
+ if yearMonth == "" {
+ yearMonth = time.Now().Format("2006-01")
+ }
+
+ url := "https://app.jiuyangongshe.com/jystock-app/api/v1/timeline/list"
+ resp, err := resty.New().SetTimeout(time.Duration(30)*time.Second).R().
+ SetHeader("Host", "app.jiuyangongshe.com").
+ SetHeader("Origin", "https://www.jiuyangongshe.com").
+ SetHeader("Referer", "https://www.jiuyangongshe.com/").
+ SetHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:140.0) Gecko/20100101 Firefox/140.0").
+ SetHeader("Content-Type", "application/json").
+ SetHeader("token", "1cc6380a05c652b922b3d85124c85473").
+ SetHeader("platform", "3").
+ SetHeader("Cookie", "SESSION=NDZkNDU2ODYtODEwYi00ZGZkLWEyY2ItNjgxYzY4ZWMzZDEy").
+ SetHeader("timestamp", strconv.FormatInt(time.Now().UnixMilli(), 10)).
+ SetBody(map[string]string{
+ "date": yearMonth,
+ "grade": "0",
+ }).
+ Post(url)
+ if err != nil {
+ logger.SugaredLogger.Errorf("InvestCalendar err:%s", err.Error())
+ return []any{}
+ }
+ //logger.SugaredLogger.Infof("InvestCalendar:%s", resp.Body())
+ respMap := map[string]any{}
+ err = json.Unmarshal(resp.Body(), &respMap)
+ return respMap["data"].([]any)
+
+}
+
+func (m MarketNewsApi) ClsCalendar() []any {
+ url := "https://www.cls.cn/api/calendar/web/list?app=CailianpressWeb&flag=0&os=web&sv=8.4.6&type=0&sign=4b839750dc2f6b803d1c8ca00d2b40be"
+ resp, err := resty.New().SetTimeout(time.Duration(30)*time.Second).R().
+ SetHeader("Host", "www.cls.cn").
+ SetHeader("Origin", "https://www.cls.cn").
+ SetHeader("Referer", "https://www.cls.cn/").
+ SetHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:140.0) Gecko/20100101 Firefox/140.0").
+ Get(url)
+ if err != nil {
+ logger.SugaredLogger.Errorf("ClsCalendar err:%s", err.Error())
+ return []any{}
+ }
+ respMap := map[string]any{}
+ err = json.Unmarshal(resp.Body(), &respMap)
+ return respMap["data"].([]any)
+}
diff --git a/backend/data/market_news_api_test.go b/backend/data/market_news_api_test.go
index d6279bd..9f24c16 100644
--- a/backend/data/market_news_api_test.go
+++ b/backend/data/market_news_api_test.go
@@ -135,3 +135,19 @@ func TestHotTopic(t *testing.T) {
}
}
+
+func TestInvestCalendar(t *testing.T) {
+ db.Init("../../data/stock.db")
+ res := NewMarketNewsApi().InvestCalendar("2025-06")
+ for _, a := range res {
+ logger.SugaredLogger.Debugf("value: %+v", a)
+ }
+}
+
+func TestClsCalendar(t *testing.T) {
+ db.Init("../../data/stock.db")
+ res := NewMarketNewsApi().ClsCalendar()
+ for _, a := range res {
+ logger.SugaredLogger.Debugf("value: %+v", a)
+ }
+}
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index f7836cc..abf5ea7 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -11,6 +11,7 @@
"@types/file-saver": "^2.0.7",
"@vavt/cm-extension": "^1.8.0",
"@vavt/v3-extension": "^3.0.0",
+ "date-fns": "^4.1.0",
"echarts": "^5.6.0",
"file-saver": "^2.0.5",
"html2canvas": "^1.4.1",
@@ -1717,10 +1718,10 @@
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
},
"node_modules/date-fns": {
- "version": "3.6.0",
- "resolved": "https://registry.npmmirror.com/date-fns/-/date-fns-3.6.0.tgz",
- "integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==",
- "dev": true,
+ "version": "4.1.0",
+ "resolved": "https://registry.npmmirror.com/date-fns/-/date-fns-4.1.0.tgz",
+ "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==",
+ "license": "MIT",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/kossnocorp"
@@ -2066,6 +2067,17 @@
"vue": "^3.0.0"
}
},
+ "node_modules/naive-ui/node_modules/date-fns": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmmirror.com/date-fns/-/date-fns-3.6.0.tgz",
+ "integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/kossnocorp"
+ }
+ },
"node_modules/nanoid": {
"version": "3.3.11",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
diff --git a/frontend/package.json b/frontend/package.json
index 24e27d5..ebc6914 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -12,6 +12,7 @@
"@types/file-saver": "^2.0.7",
"@vavt/cm-extension": "^1.8.0",
"@vavt/v3-extension": "^3.0.0",
+ "date-fns": "^4.1.0",
"echarts": "^5.6.0",
"file-saver": "^2.0.5",
"html2canvas": "^1.4.1",
diff --git a/frontend/package.json.md5 b/frontend/package.json.md5
index 018b90a..fce852e 100644
--- a/frontend/package.json.md5
+++ b/frontend/package.json.md5
@@ -1 +1 @@
-f64f2faecc1cae8baa43eca694be54ac
\ No newline at end of file
+2d63c3a999d797889c01d6c96451b197
\ No newline at end of file
diff --git a/frontend/src/components/ClsCalendarTimeLine.vue b/frontend/src/components/ClsCalendarTimeLine.vue
new file mode 100644
index 0000000..c823298
--- /dev/null
+++ b/frontend/src/components/ClsCalendarTimeLine.vue
@@ -0,0 +1,102 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{i+1}}# {{l.title}}
+ 事件
+ 数据
+
+
+
+
+
+
+
+
+
+
+ 公布:{{l.economic.actual }}
+ 预测:{{l.economic.consensus}}
+ 前值:{{l.economic.front}}
+
+
+
+
+
+
+ 没有数据
+
+
+
+ 回到今天
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frontend/src/components/InvestCalendarTimeLine.vue b/frontend/src/components/InvestCalendarTimeLine.vue
new file mode 100644
index 0000000..54d8b3d
--- /dev/null
+++ b/frontend/src/components/InvestCalendarTimeLine.vue
@@ -0,0 +1,108 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{i+1}}# {{l.title}}
+
+
+
+
+
+
+
+
+
+ 没有数据
+
+
+
+ 加载更多
+ 回到今天
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frontend/src/components/market.vue b/frontend/src/components/market.vue
index c41038e..0cc74e0 100644
--- a/frontend/src/components/market.vue
+++ b/frontend/src/components/market.vue
@@ -29,6 +29,8 @@ import IndustryResearchReportList from "./IndustryResearchReportList.vue";
import HotStockList from "./HotStockList.vue";
import HotEvents from "./HotEvents.vue";
import HotTopics from "./HotTopics.vue";
+import InvestCalendarTimeLine from "./InvestCalendarTimeLine.vue";
+import ClsCalendarTimeLine from "./ClsCalendarTimeLine.vue";
const route = useRoute()
const icon = ref('https://raw.githubusercontent.com/ArvinLovegood/go-stock/master/build/appicon.png');
@@ -584,6 +586,12 @@ function ReFlesh(source) {
+
+
+
+
+
+
diff --git a/frontend/wailsjs/go/main/App.d.ts b/frontend/wailsjs/go/main/App.d.ts
index 2f4754b..bc9d171 100644
--- a/frontend/wailsjs/go/main/App.d.ts
+++ b/frontend/wailsjs/go/main/App.d.ts
@@ -15,6 +15,8 @@ export function AnalyzeSentiment(arg1:string):Promise;
export function CheckUpdate():Promise;
+export function ClsCalendar():Promise>;
+
export function DelPrompt(arg1:number):Promise;
export function EMDictCode(arg1:string):Promise>;
@@ -73,6 +75,8 @@ export function HotTopic(arg1:number):Promise>;
export function IndustryResearchReport(arg1:string):Promise>;
+export function InvestCalendarTimeLine(arg1:string):Promise>;
+
export function LongTigerRank(arg1:string):Promise;
export function NewChatStream(arg1:string,arg2:string,arg3:string,arg4:any):Promise;
diff --git a/frontend/wailsjs/go/main/App.js b/frontend/wailsjs/go/main/App.js
index 0e93c54..2259069 100644
--- a/frontend/wailsjs/go/main/App.js
+++ b/frontend/wailsjs/go/main/App.js
@@ -26,6 +26,10 @@ export function CheckUpdate() {
return window['go']['main']['App']['CheckUpdate']();
}
+export function ClsCalendar() {
+ return window['go']['main']['App']['ClsCalendar']();
+}
+
export function DelPrompt(arg1) {
return window['go']['main']['App']['DelPrompt'](arg1);
}
@@ -142,6 +146,10 @@ export function IndustryResearchReport(arg1) {
return window['go']['main']['App']['IndustryResearchReport'](arg1);
}
+export function InvestCalendarTimeLine(arg1) {
+ return window['go']['main']['App']['InvestCalendarTimeLine'](arg1);
+}
+
export function LongTigerRank(arg1) {
return window['go']['main']['App']['LongTigerRank'](arg1);
}
From 43063fa7fb5d061d370ae425dd511990b1bed4dd Mon Sep 17 00:00:00 2001
From: ArvinLovegood
Date: Sun, 29 Jun 2025 17:31:29 +0800
Subject: [PATCH 16/21] =?UTF-8?q?feat(data):=20=E6=B7=BB=E5=8A=A0=E6=90=9C?=
=?UTF-8?q?=E7=B4=A2=E8=82=A1=E7=A5=A8=20API=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 实现了搜索股票 API 的请求和解析功能
- 添加了搜索股票的测试用例
---
backend/data/search_stock_api.go | 55 +++++++++++++++++++++++++++
backend/data/search_stock_api_test.go | 20 ++++++++++
2 files changed, 75 insertions(+)
create mode 100644 backend/data/search_stock_api.go
create mode 100644 backend/data/search_stock_api_test.go
diff --git a/backend/data/search_stock_api.go b/backend/data/search_stock_api.go
new file mode 100644
index 0000000..4b1b7e2
--- /dev/null
+++ b/backend/data/search_stock_api.go
@@ -0,0 +1,55 @@
+package data
+
+import (
+ "encoding/json"
+ "fmt"
+ "github.com/go-resty/resty/v2"
+ "go-stock/backend/logger"
+ "time"
+)
+
+// @Author spark
+// @Date 2025/6/28 21:02
+// @Desc
+// -----------------------------------------------------------------------------------
+type SearchStockApi struct {
+ words string
+}
+
+func NewSearchStockApi(words string) *SearchStockApi {
+ return &SearchStockApi{words: words}
+}
+func (s SearchStockApi) SearchStock() map[string]any {
+ url := "https://np-tjxg-g.eastmoney.com/api/smart-tag/stock/v3/pw/search-code"
+ resp, err := resty.New().SetTimeout(time.Duration(30)*time.Second).R().
+ SetHeader("Host", "np-tjxg-g.eastmoney.com").
+ SetHeader("Origin", "https://xuangu.eastmoney.com").
+ SetHeader("Referer", "https://xuangu.eastmoney.com/").
+ SetHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:140.0) Gecko/20100101 Firefox/140.0").
+ SetHeader("Content-Type", "application/json").
+ SetBody(fmt.Sprintf(`{
+ "keyWord": "%s",
+ "pageSize": 50,
+ "pageNo": 1,
+ "fingerprint": "e38b5faabf9378c8238e57219f0ebc9b",
+ "gids": [],
+ "matchWord": "",
+ "timestamp": "1751113883290349",
+ "shareToGuba": false,
+ "requestId": "8xTWgCDAjvQ5lmvz5mDA3Ydk2AE4yoiJ1751113883290",
+ "needCorrect": true,
+ "removedConditionIdList": [],
+ "xcId": "xc0af28549ab330013ed",
+ "ownSelectAll": false,
+ "dxInfo": [],
+ "extraCondition": ""
+ }`, s.words)).Post(url)
+ if err != nil {
+ logger.SugaredLogger.Errorf("SearchStock-err:%+v", err)
+ return map[string]any{}
+ }
+ respMap := map[string]any{}
+ json.Unmarshal(resp.Body(), &respMap)
+ logger.SugaredLogger.Infof("resp:%+v", respMap["data"])
+ return respMap
+}
diff --git a/backend/data/search_stock_api_test.go b/backend/data/search_stock_api_test.go
new file mode 100644
index 0000000..f324988
--- /dev/null
+++ b/backend/data/search_stock_api_test.go
@@ -0,0 +1,20 @@
+package data
+
+import (
+ "go-stock/backend/db"
+ "go-stock/backend/logger"
+ "testing"
+)
+
+func TestSearchStock(t *testing.T) {
+ db.Init("../../data/stock.db")
+
+ res := NewSearchStockApi("换手率连续5日大于5%").SearchStock()
+ data := res["data"].(map[string]any)
+ result := data["result"].(map[string]any)
+ dataList := result["dataList"].([]any)
+ for _, v := range dataList {
+ logger.SugaredLogger.Infof("v:%+v", v)
+ }
+
+}
From 71f8265bc2c563fe4075c8d497e281f2a33a0eb3 Mon Sep 17 00:00:00 2001
From: sparkmemory
Date: Sun, 29 Jun 2025 18:11:52 +0800
Subject: [PATCH 17/21] =?UTF-8?q?feat(app):=20=E6=B7=BB=E5=8A=A0=E8=82=A1?=
=?UTF-8?q?=E7=A5=A8=E6=90=9C=E7=B4=A2=E5=8A=9F=E8=83=BD=E5=B9=B6=E4=BC=98?=
=?UTF-8?q?=E5=8C=96=E6=B5=8B=E8=AF=95=E7=94=A8=E4=BE=8B?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 在 App 结构中添加 SearchStock 方法,用于股票搜索
- 更新测试用例,增加对搜索结果 columns 的打印
- 使用分号分隔多个搜索条件,提高搜索灵活性
---
app_common.go | 4 ++++
backend/data/search_stock_api_test.go | 6 +++++-
2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/app_common.go b/app_common.go
index 600668e..a82ed4b 100644
--- a/app_common.go
+++ b/app_common.go
@@ -55,3 +55,7 @@ func (a App) InvestCalendarTimeLine(yearMonth string) []any {
func (a App) ClsCalendar() []any {
return data.NewMarketNewsApi().ClsCalendar()
}
+
+func (a App) SearchStock(words string) map[string]any {
+ return data.NewSearchStockApi(words).SearchStock()
+}
diff --git a/backend/data/search_stock_api_test.go b/backend/data/search_stock_api_test.go
index f324988..8d6080b 100644
--- a/backend/data/search_stock_api_test.go
+++ b/backend/data/search_stock_api_test.go
@@ -9,12 +9,16 @@ import (
func TestSearchStock(t *testing.T) {
db.Init("../../data/stock.db")
- res := NewSearchStockApi("换手率连续5日大于5%").SearchStock()
+ res := NewSearchStockApi("换手率连续5日大于5%;科技行业").SearchStock()
data := res["data"].(map[string]any)
result := data["result"].(map[string]any)
dataList := result["dataList"].([]any)
for _, v := range dataList {
logger.SugaredLogger.Infof("v:%+v", v)
}
+ columns := result["columns"].([]any)
+ for _, v := range columns {
+ logger.SugaredLogger.Infof("v:%+v", v)
+ }
}
From e8ebb577b216524fe10a490e18b742781acc5498 Mon Sep 17 00:00:00 2001
From: ArvinLovegood
Date: Mon, 30 Jun 2025 10:45:41 +0800
Subject: [PATCH 18/21] =?UTF-8?q?test:=20=E6=9B=B4=E6=96=B0=E6=B5=8B?=
=?UTF-8?q?=E8=AF=95=E4=BB=A3=E7=A0=81=E5=B9=B6=E4=BC=98=E5=8C=96=E6=97=A5?=
=?UTF-8?q?=E5=BF=97=E8=BE=93=E5=87=BA?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 在 market_news_api.go 中更新了 XUEQIUHotStock 的日志输出
- 在 search_stock_api.go 中注释掉了日志输出语句
- 修改了 search_stock_api_test.go 中的测试用例和日志输出格式
---
backend/data/market_news_api.go | 4 ++--
backend/data/search_stock_api.go | 2 +-
backend/data/search_stock_api_test.go | 13 +++++++------
3 files changed, 10 insertions(+), 9 deletions(-)
diff --git a/backend/data/market_news_api.go b/backend/data/market_news_api.go
index 7cc91aa..ed65097 100644
--- a/backend/data/market_news_api.go
+++ b/backend/data/market_news_api.go
@@ -583,14 +583,14 @@ func (m MarketNewsApi) XUEQIUHotStock(size int, marketType string) *[]models.Hot
SetHeader("Origin", "https://xueqiu.com").
SetHeader("Referer", "https://xueqiu.com/").
SetHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:140.0) Gecko/20100101 Firefox/140.0").
- SetHeader("Cookie", "cookiesu=2617378771242871; s=c2121pp1u71; device_id=237a58584ec58d8e4d4e1040700a644f1; Hm_lvt_1db88642e346389874251b5a1eded6e3=1744100219,1744599115; xq_a_token=b7259d09435458cc3f1a963479abb270a1a016ce; xqat=b7259d09435458cc3f1a963479abb270a1a016ce; xq_r_token=28108bfa1d92ac8a46bbb57722633746218621a3; xq_id_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJ1aWQiOi0xLCJpc3MiOiJ1YyIsImV4cCI6MTc1MjU0MTk4OCwiY3RtIjoxNzUwMjMwNjA2NzI0LCJjaWQiOiJkOWQwbjRBWnVwIn0.kU_fz0luJoE7nr-K4UrNUi5-mAG-vMdXtuC4mUKIppILId4UpF70LB70yunxGiNSw6tPFR3-hyLvztKAHtekCUTm3XjUl5b3tEDP-ZUVqHnWXO_5hoeMI8h-Cfx6ZGlIr5x3icvTPkT0OV5CD5A33-ZDTKhKPf-DhJ_-m7CG5GbX4MseOBeMXuLUQUiYHPKhX1QUc0GTGrCzi8Mki0z49D0LVqCSgbsx3UGfowOOyx85_cXb4OAFvIjwbs2p0o_h-ibIT0ngVkkAyEDetVvlcZ_bkardhseCB7k9BEMgH2z8ihgkVxyy3P0degLmDUruhmqn5uZOCi1pVBDvCv9lBg; u=261737877124287; ssxmod_itna=QuG=D5AKiKDIqCqGKi7G7DgmmPlSDWFqKGHDyx4YK0CDmxjKiddDUQivnb8xpnQcGyGYoYhoqEeDBubrDSxD67DK4GTm+ogiw1o3B=xedQHDgBtN=7/i1K53N+rOjquLMU=kbqYxB3DExGkqj0tPi4DxaPD5xDTDWeDGDD3DnnsDQKDRx0kL0oDIxD1D0bmHUEvh38mDYePLmOmDYPYx94Y8KoDeEgsD7HUl/vIGGEAqjLPFegXLD0HolCqr4DCid1qDm+ECfkjDn9sD0KP8fn+CRoDv=tYr4ibx+o=W+8vstf9mjGe3cXseWdBmoFrmf4DA3bFAxnAxD7vYxADaDoerDGHPoxHF+PKGPtDKmiqQGeB5qbi4eg4KDHKDe3DeG0qeEP9xVUoHDDWMYYM0ICr4FBimBDM7D0x4QOECmhul5QCN/m5/74lGm=7x9Wp7A+i7xQ7wlMD4D; ssxmod_itna2=QuG=D5AKiKDIqCqGKi7G7DgmmPlSDWFqKGHDyx4YK0CDmxjKiddDUQivnb8xpnQcGyGYoYhoqoDirSDhPmGD24GajjDuGE3m7or4DlxOSGewHl6iaus2Q62SRX5CFjCds6ltF9xy6iaUuB262UkhRA8UXST=4/b+y3kGKzlGE8T29FA008ljy9jXXC7f7m7QsK667mlUooWrofk=qGZjxtcUrN1NtuAnne1hj+rQP5UnlFkxf+o7VjmatH7u7bCDlbTt3cz6CH9Fl4vye16W/ellc8I3Q37W7ZwiLGD/zPpZcnd2nsqqo/+zRbKAmz4plzwaDqGUe7f9E+P0IFRKqpRv+buQFHBSpcbwND7Q+9XWmnjI2UwKd98jIS3gPXwxvbx4OuiyH8gZ+OEt7DgE/AY/9W4VxDZrlFWyWnC4y4/I0IpAfaGKpbPmauKbkqawqv93vSf+9HamGe0Dt2PNgT3yiEB4vQP2/DdVpcGBOjFujWoHP32OshLPYI20LRCKddwEGkKqPzPwKPc3X5zuB=w2fUdtwKsAW5kQtsl8clNwjC5uDYrxR0h9xaj0xmD+YuI3GPT7xYTalRImPj2wL2=+91a304xa4bTWtP=dLGARhb/efRi0uktaz8i8C04G0x/ZWUzqRza8GGU=FfRfvb4GZM/q2rVsl0nLvRjGeAKgocLouyXs/uwZu3YxbAx30qCbjG1A533zAxIeIgD=0VAc3ixD").
+ SetHeader("Cookie", "cookiesu=871730774144180; device_id=ee75cebba8a35005c9e7baf7b7dead59; s=ch12b12pfi; Hm_lvt_1db88642e346389874251b5a1eded6e3=1746247619; xq_a_token=361dcfccb1d32a1d9b5b65f1a188b9c9ed1e687d; xqat=361dcfccb1d32a1d9b5b65f1a188b9c9ed1e687d; xq_r_token=450d1db0db9659a6af7cc9297bfa4fccf1776fae; xq_id_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJ1aWQiOi0xLCJpc3MiOiJ1YyIsImV4cCI6MTc1MzgzODAwNiwiY3RtIjoxNzUxMjUxMzc2MDY3LCJjaWQiOiJkOWQwbjRBWnVwIn0.TjEtQ5WEN4ajnVjVnY3J-Qq9LjL-F0eat9Cefv_tLJLqsPhzD2y8Lc1CeIu0Ceqhlad7O_yW1tR9nb2dIjDpyOPzWKxvwSOKXLm8XMoz4LMgE2pysBCH4TsetzHsEOhBsY467q-JX3WoFuqo-dqv1FfLSondZCspjEMFdgPFt2V-2iXJY05YUwcBVUvL74mT9ZjNq0KaDeRBJk_il6UR8yibG7RMbe9xWYz5dSO_wJwWuxvnZ8u9EXC2m-TV7-QHVxFHR_5e8Fodrzg0yIcLU4wBTSoIIQDUKqngajX2W-nUAdo6fr78NNDmoswFVH7T7XMuQciMAqj9MpMCVW3Sog; u=871730774144180; ssxmod_itna=iq+h7KAImDORKYQ4Y5G=nxBKDtD7D3qCD0dGMDxeq7tDRDFqApKDHtA68oon7ziBA0+PbZ9xGN4oYxiNDAPq0iDC+Wjxs9Orw5KQb9iqP4MAn0TbNsbtU22eqbCe=S3vTv6xoDHxY=DU1GzeieDx=PD5xDTDWeDGDD3DmnsDi5YD0KDjBYpH+omDYPDEBYDaxDbDimwY4GCrDDCtc5Dw6bmzDDzznL5WWAPzWffZg3YcFgxf8GwD7y3Dla4rMhw23=cz0Efdk0A5hYDXotDvhoY1/H6neEvOt3o=Q0ruT+5RuxoRhDxCmh5tGP32xBD5G0xS2xcb4quDK0Dy2ZmY/DDWM0qmEeSEDeOCIq1fw1misCY=WAzoOtMwDzGdUjpRk5Z0xQBDI2IMw4H7qNiNBLxWiDD; ssxmod_itna2=iq+h7KAImDORKYQ4Y5G=nxBKDtD7D3qCD0dGMDxeq7tDRDFqApKDHtA68oon7ziBA0+PbZYxD3boBmiEPtDFOEPAeFmDDsuGSxf46oGKwGHd8wtUjFe+oV1lxUzutkGly=nCyCjq=UTHxMxFCr1DsFiKPuEpPVO7GrOyk5Aymnc0+11AFND7v16PvwrFQH4I72=3O1OpK7rGw+poWNCxjj=Ka5QDFWAvEzrDFQcIH=GpKpS90FAyIzGcTyck+yhQKaojn96dRqeIh=HkaFrlGnKwzO+a49=F7/c/MejoR3QM20K9IIOymrMN2bsk2TRdKFiaf4O0ut2MauiOER=iQNW2WVgDrkKzD=57r577wEx2hwkqhf8T8BDvkHZRDirC0bNK4O=G3TSkd3wYwq8bst0t9qF/e3M87NYtU2IWYWzqd=BqEfdqGq0R8wxmqLzpeGeuwSTq1OAiB87gDrozjnGkwDKRdrLz8uDjQKVlGhWk8Wd/rXQjx4pG=BNqpW/6TS1wpfxzGf5CrUhtt0j0wC5AUFo2GbX+QXPzD2guxKXrx8lZUQlwWIHyEUz+OLh0eWUkfHfM0YWXlgOejnuUa06rW9y5maDPipGms751hxKcqLq62pQty4iX3QDF6SRQd3tfEBf3CH7r2xe2qq0qdOI5Ge=GezD/Us5Z0xQBwVAZ2N/XvD0HDD").
SetResult(res).
Get(url)
if err != nil {
logger.SugaredLogger.Errorf("XUEQIUHotStock err:%s", err.Error())
return &[]models.HotItem{}
}
- // logger.SugaredLogger.Infof("XUEQIUHotStock:%+v", res)
+ logger.SugaredLogger.Infof("XUEQIUHotStock:%+v", res)
return &res.Data.Items
}
diff --git a/backend/data/search_stock_api.go b/backend/data/search_stock_api.go
index 4b1b7e2..a1c6f02 100644
--- a/backend/data/search_stock_api.go
+++ b/backend/data/search_stock_api.go
@@ -50,6 +50,6 @@ func (s SearchStockApi) SearchStock() map[string]any {
}
respMap := map[string]any{}
json.Unmarshal(resp.Body(), &respMap)
- logger.SugaredLogger.Infof("resp:%+v", respMap["data"])
+ //logger.SugaredLogger.Infof("resp:%+v", respMap["data"])
return respMap
}
diff --git a/backend/data/search_stock_api_test.go b/backend/data/search_stock_api_test.go
index 8d6080b..4ca5646 100644
--- a/backend/data/search_stock_api_test.go
+++ b/backend/data/search_stock_api_test.go
@@ -9,16 +9,17 @@ import (
func TestSearchStock(t *testing.T) {
db.Init("../../data/stock.db")
- res := NewSearchStockApi("换手率连续5日大于5%;科技行业").SearchStock()
+ res := NewSearchStockApi("算力股;净利润连续3年增长").SearchStock()
data := res["data"].(map[string]any)
result := data["result"].(map[string]any)
dataList := result["dataList"].([]any)
for _, v := range dataList {
- logger.SugaredLogger.Infof("v:%+v", v)
- }
- columns := result["columns"].([]any)
- for _, v := range columns {
- logger.SugaredLogger.Infof("v:%+v", v)
+ d := v.(map[string]any)
+ logger.SugaredLogger.Infof("%s:%s", d["INDUSTRY"], d["SECURITY_SHORT_NAME"])
}
+ //columns := result["columns"].([]any)
+ //for _, v := range columns {
+ // logger.SugaredLogger.Infof("v:%+v", v)
+ //}
}
From bdc3689ac8c9da82cce0220f0dcdae9f4c860302 Mon Sep 17 00:00:00 2001
From: ArvinLovegood
Date: Mon, 30 Jun 2025 11:07:14 +0800
Subject: [PATCH 19/21] =?UTF-8?q?fix(backend):=E4=BF=AE=E5=A4=8D=E9=9B=AA?=
=?UTF-8?q?=E7=90=83=E7=83=AD=E9=97=A8=E8=82=A1=E7=A5=A8=E6=8E=A5=E5=8F=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 新增请求获取 cookies
- 使用 cookies 进行后续请求
- 优化请求头设置
---
backend/data/market_news_api.go | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/backend/data/market_news_api.go b/backend/data/market_news_api.go
index ed65097..904afb3 100644
--- a/backend/data/market_news_api.go
+++ b/backend/data/market_news_api.go
@@ -576,14 +576,23 @@ func (m MarketNewsApi) TradingViewNews() *[]models.TVNews {
}
func (m MarketNewsApi) XUEQIUHotStock(size int, marketType string) *[]models.HotItem {
+ request := resty.New().SetTimeout(time.Duration(30) * time.Second).R()
+ _, err := request.
+ SetHeader("Host", "xueqiu.com").
+ SetHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:140.0) Gecko/20100101 Firefox/140.0").
+ Get("https://xueqiu.com/hq#hot")
+
+ //cookies := resp.Header().Get("Set-Cookie")
+ //logger.SugaredLogger.Infof("cookies:%s", cookies)
+
url := fmt.Sprintf("https://stock.xueqiu.com/v5/stock/hot_stock/list.json?page=1&size=%d&_type=%s&type=%s", size, marketType, marketType)
res := &models.XUEQIUHot{}
- _, err := resty.New().SetTimeout(time.Duration(30)*time.Second).R().
+ _, err = request.
SetHeader("Host", "stock.xueqiu.com").
SetHeader("Origin", "https://xueqiu.com").
SetHeader("Referer", "https://xueqiu.com/").
SetHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:140.0) Gecko/20100101 Firefox/140.0").
- SetHeader("Cookie", "cookiesu=871730774144180; device_id=ee75cebba8a35005c9e7baf7b7dead59; s=ch12b12pfi; Hm_lvt_1db88642e346389874251b5a1eded6e3=1746247619; xq_a_token=361dcfccb1d32a1d9b5b65f1a188b9c9ed1e687d; xqat=361dcfccb1d32a1d9b5b65f1a188b9c9ed1e687d; xq_r_token=450d1db0db9659a6af7cc9297bfa4fccf1776fae; xq_id_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJ1aWQiOi0xLCJpc3MiOiJ1YyIsImV4cCI6MTc1MzgzODAwNiwiY3RtIjoxNzUxMjUxMzc2MDY3LCJjaWQiOiJkOWQwbjRBWnVwIn0.TjEtQ5WEN4ajnVjVnY3J-Qq9LjL-F0eat9Cefv_tLJLqsPhzD2y8Lc1CeIu0Ceqhlad7O_yW1tR9nb2dIjDpyOPzWKxvwSOKXLm8XMoz4LMgE2pysBCH4TsetzHsEOhBsY467q-JX3WoFuqo-dqv1FfLSondZCspjEMFdgPFt2V-2iXJY05YUwcBVUvL74mT9ZjNq0KaDeRBJk_il6UR8yibG7RMbe9xWYz5dSO_wJwWuxvnZ8u9EXC2m-TV7-QHVxFHR_5e8Fodrzg0yIcLU4wBTSoIIQDUKqngajX2W-nUAdo6fr78NNDmoswFVH7T7XMuQciMAqj9MpMCVW3Sog; u=871730774144180; ssxmod_itna=iq+h7KAImDORKYQ4Y5G=nxBKDtD7D3qCD0dGMDxeq7tDRDFqApKDHtA68oon7ziBA0+PbZ9xGN4oYxiNDAPq0iDC+Wjxs9Orw5KQb9iqP4MAn0TbNsbtU22eqbCe=S3vTv6xoDHxY=DU1GzeieDx=PD5xDTDWeDGDD3DmnsDi5YD0KDjBYpH+omDYPDEBYDaxDbDimwY4GCrDDCtc5Dw6bmzDDzznL5WWAPzWffZg3YcFgxf8GwD7y3Dla4rMhw23=cz0Efdk0A5hYDXotDvhoY1/H6neEvOt3o=Q0ruT+5RuxoRhDxCmh5tGP32xBD5G0xS2xcb4quDK0Dy2ZmY/DDWM0qmEeSEDeOCIq1fw1misCY=WAzoOtMwDzGdUjpRk5Z0xQBDI2IMw4H7qNiNBLxWiDD; ssxmod_itna2=iq+h7KAImDORKYQ4Y5G=nxBKDtD7D3qCD0dGMDxeq7tDRDFqApKDHtA68oon7ziBA0+PbZYxD3boBmiEPtDFOEPAeFmDDsuGSxf46oGKwGHd8wtUjFe+oV1lxUzutkGly=nCyCjq=UTHxMxFCr1DsFiKPuEpPVO7GrOyk5Aymnc0+11AFND7v16PvwrFQH4I72=3O1OpK7rGw+poWNCxjj=Ka5QDFWAvEzrDFQcIH=GpKpS90FAyIzGcTyck+yhQKaojn96dRqeIh=HkaFrlGnKwzO+a49=F7/c/MejoR3QM20K9IIOymrMN2bsk2TRdKFiaf4O0ut2MauiOER=iQNW2WVgDrkKzD=57r577wEx2hwkqhf8T8BDvkHZRDirC0bNK4O=G3TSkd3wYwq8bst0t9qF/e3M87NYtU2IWYWzqd=BqEfdqGq0R8wxmqLzpeGeuwSTq1OAiB87gDrozjnGkwDKRdrLz8uDjQKVlGhWk8Wd/rXQjx4pG=BNqpW/6TS1wpfxzGf5CrUhtt0j0wC5AUFo2GbX+QXPzD2guxKXrx8lZUQlwWIHyEUz+OLh0eWUkfHfM0YWXlgOejnuUa06rW9y5maDPipGms751hxKcqLq62pQty4iX3QDF6SRQd3tfEBf3CH7r2xe2qq0qdOI5Ge=GezD/Us5Z0xQBwVAZ2N/XvD0HDD").
+ //SetHeader("Cookie", "cookiesu=871730774144180; device_id=ee75cebba8a35005c9e7baf7b7dead59; s=ch12b12pfi; Hm_lvt_1db88642e346389874251b5a1eded6e3=1746247619; xq_a_token=361dcfccb1d32a1d9b5b65f1a188b9c9ed1e687d; xqat=361dcfccb1d32a1d9b5b65f1a188b9c9ed1e687d; xq_r_token=450d1db0db9659a6af7cc9297bfa4fccf1776fae; xq_id_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJ1aWQiOi0xLCJpc3MiOiJ1YyIsImV4cCI6MTc1MzgzODAwNiwiY3RtIjoxNzUxMjUxMzc2MDY3LCJjaWQiOiJkOWQwbjRBWnVwIn0.TjEtQ5WEN4ajnVjVnY3J-Qq9LjL-F0eat9Cefv_tLJLqsPhzD2y8Lc1CeIu0Ceqhlad7O_yW1tR9nb2dIjDpyOPzWKxvwSOKXLm8XMoz4LMgE2pysBCH4TsetzHsEOhBsY467q-JX3WoFuqo-dqv1FfLSondZCspjEMFdgPFt2V-2iXJY05YUwcBVUvL74mT9ZjNq0KaDeRBJk_il6UR8yibG7RMbe9xWYz5dSO_wJwWuxvnZ8u9EXC2m-TV7-QHVxFHR_5e8Fodrzg0yIcLU4wBTSoIIQDUKqngajX2W-nUAdo6fr78NNDmoswFVH7T7XMuQciMAqj9MpMCVW3Sog; u=871730774144180; ssxmod_itna=iq+h7KAImDORKYQ4Y5G=nxBKDtD7D3qCD0dGMDxeq7tDRDFqApKDHtA68oon7ziBA0+PbZ9xGN4oYxiNDAPq0iDC+Wjxs9Orw5KQb9iqP4MAn0TbNsbtU22eqbCe=S3vTv6xoDHxY=DU1GzeieDx=PD5xDTDWeDGDD3DmnsDi5YD0KDjBYpH+omDYPDEBYDaxDbDimwY4GCrDDCtc5Dw6bmzDDzznL5WWAPzWffZg3YcFgxf8GwD7y3Dla4rMhw23=cz0Efdk0A5hYDXotDvhoY1/H6neEvOt3o=Q0ruT+5RuxoRhDxCmh5tGP32xBD5G0xS2xcb4quDK0Dy2ZmY/DDWM0qmEeSEDeOCIq1fw1misCY=WAzoOtMwDzGdUjpRk5Z0xQBDI2IMw4H7qNiNBLxWiDD; ssxmod_itna2=iq+h7KAImDORKYQ4Y5G=nxBKDtD7D3qCD0dGMDxeq7tDRDFqApKDHtA68oon7ziBA0+PbZYxD3boBmiEPtDFOEPAeFmDDsuGSxf46oGKwGHd8wtUjFe+oV1lxUzutkGly=nCyCjq=UTHxMxFCr1DsFiKPuEpPVO7GrOyk5Aymnc0+11AFND7v16PvwrFQH4I72=3O1OpK7rGw+poWNCxjj=Ka5QDFWAvEzrDFQcIH=GpKpS90FAyIzGcTyck+yhQKaojn96dRqeIh=HkaFrlGnKwzO+a49=F7/c/MejoR3QM20K9IIOymrMN2bsk2TRdKFiaf4O0ut2MauiOER=iQNW2WVgDrkKzD=57r577wEx2hwkqhf8T8BDvkHZRDirC0bNK4O=G3TSkd3wYwq8bst0t9qF/e3M87NYtU2IWYWzqd=BqEfdqGq0R8wxmqLzpeGeuwSTq1OAiB87gDrozjnGkwDKRdrLz8uDjQKVlGhWk8Wd/rXQjx4pG=BNqpW/6TS1wpfxzGf5CrUhtt0j0wC5AUFo2GbX+QXPzD2guxKXrx8lZUQlwWIHyEUz+OLh0eWUkfHfM0YWXlgOejnuUa06rW9y5maDPipGms751hxKcqLq62pQty4iX3QDF6SRQd3tfEBf3CH7r2xe2qq0qdOI5Ge=GezD/Us5Z0xQBwVAZ2N/XvD0HDD").
SetResult(res).
Get(url)
if err != nil {
From 482472af4e3ef4337049f366f7794740a5c99620 Mon Sep 17 00:00:00 2001
From: ArvinLovegood
Date: Mon, 30 Jun 2025 16:27:15 +0800
Subject: [PATCH 20/21] =?UTF-8?q?feat(frontend):=E6=B7=BB=E5=8A=A0?=
=?UTF-8?q?=E6=8C=87=E6=A0=87=E9=80=89=E8=82=A1=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 在 App.vue 中添加指标选股相关路由和菜单项
- 新增 SelectStock 组件实现选股功能
- 在 backend 中调整搜索股票接口的分页参数
---
README.md | 1 +
backend/data/search_stock_api.go | 2 +-
frontend/src/App.vue | 23 ++++-
frontend/src/components/SelectStock.vue | 126 ++++++++++++++++++++++++
frontend/src/components/market.vue | 4 +
frontend/wailsjs/go/main/App.d.ts | 2 +
frontend/wailsjs/go/main/App.js | 4 +
7 files changed, 160 insertions(+), 2 deletions(-)
create mode 100644 frontend/src/components/SelectStock.vue
diff --git a/README.md b/README.md
index e6c8e8d..3330353 100644
--- a/README.md
+++ b/README.md
@@ -55,6 +55,7 @@
| 不再强制依赖Chrome浏览器 | ✅ | 默认使用edge浏览器抓取新闻资讯 |
## 👀 更新日志
+### 2025.06.30 添加指标选股功能
### 2025.06.27 添加财经日历和重大事件时间轴功能
### 2025.06.25 添加热门股票、事件和话题功能
### 2025.06.18 更新内置股票基础数据,软件内实时市场资讯信息提醒,添加行业研究功能
diff --git a/backend/data/search_stock_api.go b/backend/data/search_stock_api.go
index a1c6f02..cea7d58 100644
--- a/backend/data/search_stock_api.go
+++ b/backend/data/search_stock_api.go
@@ -29,7 +29,7 @@ func (s SearchStockApi) SearchStock() map[string]any {
SetHeader("Content-Type", "application/json").
SetBody(fmt.Sprintf(`{
"keyWord": "%s",
- "pageSize": 50,
+ "pageSize": 50000,
"pageNo": 1,
"fingerprint": "e38b5faabf9378c8238e57219f0ebc9b",
"gids": [],
diff --git a/frontend/src/App.vue b/frontend/src/App.vue
index b371eed..f4a78ab 100644
--- a/frontend/src/App.vue
+++ b/frontend/src/App.vue
@@ -31,7 +31,7 @@ import {AnalyzeSentiment, GetConfig, GetGroupList} from "../wailsjs/go/main/App"
import {Dragon, Fire, Gripfire} from "@vicons/fa";
import {ReportSearch} from "@vicons/tabler";
import {LocalFireDepartmentRound} from "@vicons/material";
-import {CommentNote20Filled} from "@vicons/fluent";
+import {BoxSearch20Regular, CommentNote20Filled} from "@vicons/fluent";
import {FireFilled, FireOutlined, NotificationFilled, StockOutlined} from "@vicons/antd";
@@ -332,6 +332,27 @@ const menuOptions = ref([
key: 'market10',
icon: renderIcon(Gripfire),
},
+ {
+ label: () =>
+ h(
+ RouterLink,
+ {
+ href: '#',
+ to: {
+ name: 'market',
+ query: {
+ name: "指标选股",
+ }
+ },
+ onClick: () => {
+ EventsEmit("changeMarketTab", {ID: 0, name: '指标选股'})
+ },
+ },
+ {default: () => '指标选股',}
+ ),
+ key: 'market11',
+ icon: renderIcon(BoxSearch20Regular),
+ },
]
},
{
diff --git a/frontend/src/components/SelectStock.vue b/frontend/src/components/SelectStock.vue
new file mode 100644
index 0000000..af17d2d
--- /dev/null
+++ b/frontend/src/components/SelectStock.vue
@@ -0,0 +1,126 @@
+
+
+
+
+
+
+ 搜索A股
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frontend/src/components/market.vue b/frontend/src/components/market.vue
index 0cc74e0..44eb20c 100644
--- a/frontend/src/components/market.vue
+++ b/frontend/src/components/market.vue
@@ -31,6 +31,7 @@ import HotEvents from "./HotEvents.vue";
import HotTopics from "./HotTopics.vue";
import InvestCalendarTimeLine from "./InvestCalendarTimeLine.vue";
import ClsCalendarTimeLine from "./ClsCalendarTimeLine.vue";
+import SelectStock from "./SelectStock.vue";
const route = useRoute()
const icon = ref('https://raw.githubusercontent.com/ArvinLovegood/go-stock/master/build/appicon.png');
@@ -594,6 +595,9 @@ function ReFlesh(source) {
+
+
+
;
+export function SearchStock(arg1:string):Promise>;
+
export function SendDingDingMessage(arg1:string,arg2:string):Promise;
export function SendDingDingMessageByType(arg1:string,arg2:string,arg3:number):Promise;
diff --git a/frontend/wailsjs/go/main/App.js b/frontend/wailsjs/go/main/App.js
index 2259069..da3813b 100644
--- a/frontend/wailsjs/go/main/App.js
+++ b/frontend/wailsjs/go/main/App.js
@@ -182,6 +182,10 @@ export function SaveAsMarkdown(arg1, arg2) {
return window['go']['main']['App']['SaveAsMarkdown'](arg1, arg2);
}
+export function SearchStock(arg1) {
+ return window['go']['main']['App']['SearchStock'](arg1);
+}
+
export function SendDingDingMessage(arg1, arg2) {
return window['go']['main']['App']['SendDingDingMessage'](arg1, arg2);
}
From 3e16574faaba9b509a67dc06cc174361b7def5c7 Mon Sep 17 00:00:00 2001
From: ArvinLovegood
Date: Mon, 30 Jun 2025 16:51:07 +0800
Subject: [PATCH 21/21] =?UTF-8?q?docs(README):=20=E6=9B=B4=E6=96=B0?=
=?UTF-8?q?=E9=87=8D=E5=A4=A7=E5=8A=9F=E8=83=BD=E5=BC=80=E5=8F=91=E8=AE=A1?=
=?UTF-8?q?=E5=88=92?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 新增股票分析知识库功能,状态为施工中
- 新增Ai智能选股功能,状态为施工中,计划在下半年重点开发
---
README.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/README.md b/README.md
index 3330353..647c819 100644
--- a/README.md
+++ b/README.md
@@ -47,6 +47,8 @@
## 🧩 重大功能开发计划
| 功能说明 | 状态 | 备注 |
|-----------------|----|----------------------------------------------------------------------------------------------------------|
+| 股票分析知识库 | 🚧 | 未来计划 |
+| Ai智能选股 | 🚧 | Ai智能选股功能开发中(下半年重点开发计划) |
| ETF支持 | 🚧 | ETF数据支持 (目前可以查看净值和估值) |
| 美股支持 | ✅ | 美股数据支持 |
| 港股支持 | ✅ | 港股数据支持 |