mirror of
https://github.com/ArvinLovegood/go-stock.git
synced 2025-07-19 00:00:09 +08:00
feat(app): 兼容darwin版本浏览跳转,保存图片文件等功能
This commit is contained in:
parent
58f3009902
commit
bbd4bb5b48
79
app.go
79
app.go
@ -14,6 +14,7 @@ import (
|
|||||||
"go-stock/backend/logger"
|
"go-stock/backend/logger"
|
||||||
"go-stock/backend/models"
|
"go-stock/backend/models"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -1201,3 +1202,81 @@ func (a *App) GetStockMoneyTrendByDay(stockCode string, days int) []map[string]a
|
|||||||
slice.Reverse(res)
|
slice.Reverse(res)
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OpenURL
|
||||||
|
//
|
||||||
|
// @Description: 跨平台打开默认浏览器
|
||||||
|
// @receiver a
|
||||||
|
// @param url
|
||||||
|
func (a *App) OpenURL(url string) {
|
||||||
|
runtime.BrowserOpenURL(a.ctx, url)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SaveImage
|
||||||
|
//
|
||||||
|
// @Description: 跨平台保存图片
|
||||||
|
// @receiver a
|
||||||
|
// @param name
|
||||||
|
// @param base64Data
|
||||||
|
// @return error
|
||||||
|
func (a *App) SaveImage(name, base64Data string) string {
|
||||||
|
// 打开保存文件对话框
|
||||||
|
filePath, err := runtime.SaveFileDialog(a.ctx, runtime.SaveDialogOptions{
|
||||||
|
Title: "保存图片",
|
||||||
|
DefaultFilename: name + "AI分析.png",
|
||||||
|
Filters: []runtime.FileFilter{
|
||||||
|
{
|
||||||
|
DisplayName: "PNG 图片",
|
||||||
|
Pattern: "*.png",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil || filePath == "" {
|
||||||
|
return "文件路径,无法保存。"
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解码并保存
|
||||||
|
decodeString, err := base64.StdEncoding.DecodeString(base64Data)
|
||||||
|
if err != nil {
|
||||||
|
return "文件内容异常,无法保存。"
|
||||||
|
}
|
||||||
|
|
||||||
|
err = os.WriteFile(filepath.Clean(filePath), decodeString, 0777)
|
||||||
|
if err != nil {
|
||||||
|
return "保存结果异常,无法保存。"
|
||||||
|
}
|
||||||
|
return filePath
|
||||||
|
}
|
||||||
|
|
||||||
|
// SaveWordFile
|
||||||
|
//
|
||||||
|
// @Description: // 跨平台保存word
|
||||||
|
// @receiver a
|
||||||
|
// @param filename
|
||||||
|
// @param base64Data
|
||||||
|
// @return error
|
||||||
|
func (a *App) SaveWordFile(filename string, base64Data string) string {
|
||||||
|
// 弹出保存文件对话框
|
||||||
|
filePath, err := runtime.SaveFileDialog(a.ctx, runtime.SaveDialogOptions{
|
||||||
|
Title: "保存 Word 文件",
|
||||||
|
DefaultFilename: filename,
|
||||||
|
Filters: []runtime.FileFilter{
|
||||||
|
{DisplayName: "Word 文件", Pattern: "*.docx"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil || filePath == "" {
|
||||||
|
return "文件路径,无法保存。"
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解码 base64 内容
|
||||||
|
decodeString, err := base64.StdEncoding.DecodeString(base64Data)
|
||||||
|
if err != nil {
|
||||||
|
return "文件内容异常,无法保存。"
|
||||||
|
}
|
||||||
|
// 保存为文件
|
||||||
|
err = os.WriteFile(filepath.Clean(filePath), decodeString, 0777)
|
||||||
|
if err != nil {
|
||||||
|
return "保存结果异常,无法保存。"
|
||||||
|
}
|
||||||
|
return filePath
|
||||||
|
}
|
||||||
|
@ -1 +1 @@
|
|||||||
2d63c3a999d797889c01d6c96451b197
|
8d3264f90073dfceb29c3619775d830d
|
@ -1,6 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {onBeforeMount, onUnmounted, ref} from 'vue'
|
import {onBeforeMount, onUnmounted, ref} from 'vue'
|
||||||
import {HotTopic} from "../../wailsjs/go/main/App";
|
import {HotTopic, OpenURL} from "../../wailsjs/go/main/App";
|
||||||
|
import {Environment} from "../../wailsjs/runtime";
|
||||||
const list = ref([])
|
const list = ref([])
|
||||||
const task =ref()
|
const task =ref()
|
||||||
|
|
||||||
@ -18,11 +19,20 @@ function openCenteredWindow(url, width, height) {
|
|||||||
const left = (window.screen.width - width) / 2;
|
const left = (window.screen.width - width) / 2;
|
||||||
const top = (window.screen.height - height) / 2;
|
const top = (window.screen.height - height) / 2;
|
||||||
|
|
||||||
return window.open(
|
Environment().then(env => {
|
||||||
url,
|
switch (env.platform) {
|
||||||
'centeredWindow',
|
case 'windows':
|
||||||
`width=${width},height=${height},left=${left},top=${top}`
|
window.open(
|
||||||
);
|
url,
|
||||||
|
'centeredWindow',
|
||||||
|
`width=${width},height=${height},left=${left},top=${top}`
|
||||||
|
)
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
OpenURL(url)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
function showPage(htid) {
|
function showPage(htid) {
|
||||||
openCenteredWindow(`https://gubatopic.eastmoney.com/topic_v3.html?htid=${htid}`, 1000, 600)
|
openCenteredWindow(`https://gubatopic.eastmoney.com/topic_v3.html?htid=${htid}`, 1000, 600)
|
||||||
|
@ -1,16 +1,19 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {h, onBeforeMount, onMounted, onUnmounted, ref} from 'vue'
|
import {h, onBeforeMount, onMounted, onUnmounted, ref} from 'vue'
|
||||||
import {SearchStock,GetHotStrategy} from "../../wailsjs/go/main/App";
|
import {SearchStock, GetHotStrategy, OpenURL} from "../../wailsjs/go/main/App";
|
||||||
import {useMessage, NText, NTag,NButton} from 'naive-ui'
|
import {useMessage, NText, NTag, NButton} from 'naive-ui'
|
||||||
|
import {Environment} from "../../wailsjs/runtime"
|
||||||
import {RefreshCircleSharp} from "@vicons/ionicons5";
|
import {RefreshCircleSharp} from "@vicons/ionicons5";
|
||||||
|
|
||||||
const message = useMessage()
|
const message = useMessage()
|
||||||
const search = ref('')
|
const search = ref('')
|
||||||
const columns = ref([])
|
const columns = ref([])
|
||||||
const dataList = ref([])
|
const dataList = ref([])
|
||||||
const hotStrategy = ref([])
|
const hotStrategy = ref([])
|
||||||
const traceInfo = ref('')
|
const traceInfo = ref('')
|
||||||
|
|
||||||
function Search() {
|
function Search() {
|
||||||
if(!search.value){
|
if (!search.value) {
|
||||||
message.warning('请输入选股指标或者要求')
|
message.warning('请输入选股指标或者要求')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -18,69 +21,69 @@ function Search() {
|
|||||||
const loading = message.loading("正在获取选股数据...", {duration: 0});
|
const loading = message.loading("正在获取选股数据...", {duration: 0});
|
||||||
SearchStock(search.value).then(res => {
|
SearchStock(search.value).then(res => {
|
||||||
loading.destroy()
|
loading.destroy()
|
||||||
// console.log(res)
|
// console.log(res)
|
||||||
if(res.code==100){
|
if (res.code == 100) {
|
||||||
traceInfo.value=res.data.traceInfo.showText
|
traceInfo.value = res.data.traceInfo.showText
|
||||||
// message.success(res.msg)
|
// message.success(res.msg)
|
||||||
columns.value=res.data.result.columns.filter(item=>!item.hiddenNeed&&(item.title!="市场码"&&item.title!="市场简称")).map(item=>{
|
columns.value = res.data.result.columns.filter(item => !item.hiddenNeed && (item.title != "市场码" && item.title != "市场简称")).map(item => {
|
||||||
if(item.children){
|
if (item.children) {
|
||||||
return {
|
return {
|
||||||
title:item.title+(item.unit?'['+item.unit+']':''),
|
title: item.title + (item.unit ? '[' + item.unit + ']' : ''),
|
||||||
key:item.key,
|
key: item.key,
|
||||||
resizable: true,
|
resizable: true,
|
||||||
minWidth:200,
|
minWidth: 200,
|
||||||
ellipsis: {
|
ellipsis: {
|
||||||
tooltip: true
|
tooltip: true
|
||||||
},
|
},
|
||||||
children:item.children.filter(item=>!item.hiddenNeed).map(item=>{
|
children: item.children.filter(item => !item.hiddenNeed).map(item => {
|
||||||
return {
|
return {
|
||||||
title:item.dateMsg,
|
title: item.dateMsg,
|
||||||
key:item.key,
|
key: item.key,
|
||||||
minWidth:100,
|
minWidth: 100,
|
||||||
resizable: true,
|
resizable: true,
|
||||||
ellipsis: {
|
ellipsis: {
|
||||||
tooltip: true
|
tooltip: true
|
||||||
},
|
},
|
||||||
sorter: (row1, row2) => {
|
sorter: (row1, row2) => {
|
||||||
if(isNumeric(row1[item.key])&&isNumeric(row2[item.key])){
|
if (isNumeric(row1[item.key]) && isNumeric(row2[item.key])) {
|
||||||
return row1[item.key] - row2[item.key];
|
return row1[item.key] - row2[item.key];
|
||||||
}else{
|
} else {
|
||||||
return 'default'
|
return 'default'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}else{
|
} else {
|
||||||
return {
|
return {
|
||||||
title:item.title+(item.unit?'['+item.unit+']':''),
|
title: item.title + (item.unit ? '[' + item.unit + ']' : ''),
|
||||||
key:item.key,
|
key: item.key,
|
||||||
resizable: true,
|
resizable: true,
|
||||||
minWidth:120,
|
minWidth: 120,
|
||||||
ellipsis: {
|
ellipsis: {
|
||||||
tooltip: true
|
tooltip: true
|
||||||
},
|
},
|
||||||
sorter: (row1, row2) => {
|
sorter: (row1, row2) => {
|
||||||
if(isNumeric(row1[item.key])&&isNumeric(row2[item.key])){
|
if (isNumeric(row1[item.key]) && isNumeric(row2[item.key])) {
|
||||||
return row1[item.key] - row2[item.key];
|
return row1[item.key] - row2[item.key];
|
||||||
}else{
|
} else {
|
||||||
return 'default'
|
return 'default'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
dataList.value=res.data.result.dataList
|
dataList.value = res.data.result.dataList
|
||||||
}else {
|
} else {
|
||||||
message.error(res.msg)
|
message.error(res.msg)
|
||||||
}
|
}
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
message.error(err)
|
message.error(err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function isNumeric(value) {
|
function isNumeric(value) {
|
||||||
return !isNaN(parseFloat(value)) && isFinite(value);
|
return !isNaN(parseFloat(value)) && isFinite(value);
|
||||||
}
|
}
|
||||||
@ -88,9 +91,9 @@ function isNumeric(value) {
|
|||||||
onBeforeMount(() => {
|
onBeforeMount(() => {
|
||||||
GetHotStrategy().then(res => {
|
GetHotStrategy().then(res => {
|
||||||
console.log(res)
|
console.log(res)
|
||||||
if(res.code==1){
|
if (res.code == 1) {
|
||||||
hotStrategy.value=res.data
|
hotStrategy.value = res.data
|
||||||
search.value=hotStrategy.value[0].question
|
search.value = hotStrategy.value[0].question
|
||||||
Search()
|
Search()
|
||||||
}
|
}
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
@ -98,8 +101,9 @@ onBeforeMount(() => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
})
|
})
|
||||||
function DoSearch(question){
|
|
||||||
search.value= question
|
function DoSearch(question) {
|
||||||
|
search.value = question
|
||||||
Search()
|
Search()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,60 +111,70 @@ function openCenteredWindow(url, width, height) {
|
|||||||
const left = (window.screen.width - width) / 2;
|
const left = (window.screen.width - width) / 2;
|
||||||
const top = (window.screen.height - height) / 2;
|
const top = (window.screen.height - height) / 2;
|
||||||
|
|
||||||
return window.open(
|
Environment().then(env => {
|
||||||
url,
|
switch (env.platform) {
|
||||||
'centeredWindow',
|
case 'windows':
|
||||||
`width=${width},height=${height},left=${left},top=${top},location=no,menubar=no,toolbar=no,display=standalone`
|
window.open(
|
||||||
);
|
url,
|
||||||
|
'centeredWindow',
|
||||||
|
`width=${width},height=${height},left=${left},top=${top},location=no,menubar=no,toolbar=no,display=standalone`
|
||||||
|
)
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
OpenURL(url)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<n-grid :cols="24" style="max-height: calc(100vh - 170px)">
|
<n-grid :cols="24" style="max-height: calc(100vh - 170px)">
|
||||||
<n-gi :span="4" >
|
<n-gi :span="4">
|
||||||
<n-list bordered style="text-align: left;" hoverable clickable>
|
<n-list bordered style="text-align: left;" hoverable clickable>
|
||||||
<n-scrollbar style="max-height: calc(100vh - 170px);" >
|
<n-scrollbar style="max-height: calc(100vh - 170px);">
|
||||||
<n-list-item v-for="item in hotStrategy" :key="item.rank" @click="DoSearch(item.question)">
|
<n-list-item v-for="item in hotStrategy" :key="item.rank" @click="DoSearch(item.question)">
|
||||||
<n-ellipsis line-clamp="1" :tooltip="true" >
|
<n-ellipsis line-clamp="1" :tooltip="true">
|
||||||
<n-tag size="small" :bordered="false" type="info">#{{item.rank}}</n-tag><n-text type="warning">{{item.question }}</n-text>
|
<n-tag size="small" :bordered="false" type="info">#{{ item.rank }}</n-tag>
|
||||||
<template #tooltip>
|
<n-text type="warning">{{ item.question }}</n-text>
|
||||||
<div style="text-align: center;max-width: 180px">
|
<template #tooltip>
|
||||||
<n-text type="warning">{{item.question }}</n-text>
|
<div style="text-align: center;max-width: 180px">
|
||||||
</div>
|
<n-text type="warning">{{ item.question }}</n-text>
|
||||||
</template>
|
</div>
|
||||||
</n-ellipsis>
|
</template>
|
||||||
</n-list-item>
|
</n-ellipsis>
|
||||||
|
</n-list-item>
|
||||||
</n-scrollbar>
|
</n-scrollbar>
|
||||||
</n-list>
|
</n-list>
|
||||||
|
|
||||||
<!-- <n-virtual-list :items="hotStrategy" :item-size="hotStrategy.length">-->
|
<!-- <n-virtual-list :items="hotStrategy" :item-size="hotStrategy.length">-->
|
||||||
<!-- <template #default="{ item, index }">-->
|
<!-- <template #default="{ item, index }">-->
|
||||||
<!-- <n-card :title="''" size="small">-->
|
<!-- <n-card :title="''" size="small">-->
|
||||||
<!-- <template #header-extra>-->
|
<!-- <template #header-extra>-->
|
||||||
<!-- {{item.rank}}-->
|
<!-- {{item.rank}}-->
|
||||||
<!-- </template>-->
|
<!-- </template>-->
|
||||||
<!-- <n-ellipsis expand-trigger="click" line-clamp="3" :tooltip="false" >-->
|
<!-- <n-ellipsis expand-trigger="click" line-clamp="3" :tooltip="false" >-->
|
||||||
<!-- <n-text type="warning">{{item.question }}</n-text>-->
|
<!-- <n-text type="warning">{{item.question }}</n-text>-->
|
||||||
<!-- </n-ellipsis>-->
|
<!-- </n-ellipsis>-->
|
||||||
<!-- </n-card>-->
|
<!-- </n-card>-->
|
||||||
|
|
||||||
<!-- </template>-->
|
<!-- </template>-->
|
||||||
<!-- </n-virtual-list>-->
|
<!-- </n-virtual-list>-->
|
||||||
</n-gi>
|
</n-gi>
|
||||||
<n-gi :span="20" >
|
<n-gi :span="20">
|
||||||
<n-flex>
|
<n-flex>
|
||||||
<n-input-group style="text-align: left">
|
<n-input-group style="text-align: left">
|
||||||
<n-input :rows="1" clearable v-model:value="search" placeholder="请输入选股指标或者要求" />
|
<n-input :rows="1" clearable v-model:value="search" placeholder="请输入选股指标或者要求"/>
|
||||||
<n-button type="primary" @click="Search">搜索A股</n-button>
|
<n-button type="primary" @click="Search">搜索A股</n-button>
|
||||||
</n-input-group>
|
</n-input-group>
|
||||||
</n-flex>
|
</n-flex>
|
||||||
<n-flex justify="start" v-if="traceInfo" style="margin: 5px 0">
|
<n-flex justify="start" v-if="traceInfo" style="margin: 5px 0">
|
||||||
|
|
||||||
<n-ellipsis line-clamp="1" :tooltip="true" >
|
<n-ellipsis line-clamp="1" :tooltip="true">
|
||||||
<n-text type="info" :bordered="false">选股条件:</n-text><n-text type="warning" :bordered="true">{{traceInfo}}</n-text>
|
<n-text type="info" :bordered="false">选股条件:</n-text>
|
||||||
|
<n-text type="warning" :bordered="true">{{ traceInfo }}</n-text>
|
||||||
<template #tooltip>
|
<template #tooltip>
|
||||||
<div style="text-align: center;max-width: 580px">
|
<div style="text-align: center;max-width: 580px">
|
||||||
<n-text type="warning">{{traceInfo}}</n-text>
|
<n-text type="warning">{{ traceInfo }}</n-text>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</n-ellipsis>
|
</n-ellipsis>
|
||||||
@ -204,7 +218,10 @@ function openCenteredWindow(url, width, height) {
|
|||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
/>
|
/>
|
||||||
<n-text>共找到<n-tag type="info" :bordered="false">{{dataList.length}}</n-tag>只股</n-text>
|
<n-text>共找到
|
||||||
|
<n-tag type="info" :bordered="false">{{ dataList.length }}</n-tag>
|
||||||
|
只股
|
||||||
|
</n-text>
|
||||||
</n-gi>
|
</n-gi>
|
||||||
</n-grid>
|
</n-grid>
|
||||||
|
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
// preview.css相比style.css少了编辑器那部分样式
|
// preview.css相比style.css少了编辑器那部分样式
|
||||||
import 'md-editor-v3/lib/preview.css';
|
import 'md-editor-v3/lib/preview.css';
|
||||||
import {h, onBeforeUnmount, onMounted, ref} from 'vue';
|
import {h, onBeforeUnmount, onMounted, ref} from 'vue';
|
||||||
import {CheckUpdate, GetVersionInfo,GetSponsorInfo} from "../../wailsjs/go/main/App";
|
import {CheckUpdate, GetVersionInfo,GetSponsorInfo,OpenURL} from "../../wailsjs/go/main/App";
|
||||||
import {EventsOff, EventsOn} from "../../wailsjs/runtime";
|
import {EventsOff, EventsOn,Environment} from "../../wailsjs/runtime";
|
||||||
import {NAvatar, NButton, useNotification} from "naive-ui";
|
import {NAvatar, NButton, useNotification} from "naive-ui";
|
||||||
const updateLog = ref('');
|
const updateLog = ref('');
|
||||||
const versionInfo = ref('');
|
const versionInfo = ref('');
|
||||||
@ -85,7 +85,16 @@ EventsOn("updateVersion",async (msg) => {
|
|||||||
type: 'primary',
|
type: 'primary',
|
||||||
size: 'small',
|
size: 'small',
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
window.open(msg.html_url)
|
Environment().then(env => {
|
||||||
|
switch (env.platform) {
|
||||||
|
case 'windows':
|
||||||
|
window.open(msg.html_url)
|
||||||
|
break
|
||||||
|
default :
|
||||||
|
OpenURL(msg.html_url)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}, { default: () => '查看' })
|
}, { default: () => '查看' })
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ import {
|
|||||||
GetConfig,
|
GetConfig,
|
||||||
GetFollowedFund,
|
GetFollowedFund,
|
||||||
GetfundList,
|
GetfundList,
|
||||||
GetVersionInfo,
|
GetVersionInfo, OpenURL,
|
||||||
UnFollowFund
|
UnFollowFund
|
||||||
} from "../../wailsjs/go/main/App";
|
} from "../../wailsjs/go/main/App";
|
||||||
import vueDanmaku from 'vue3-danmaku'
|
import vueDanmaku from 'vue3-danmaku'
|
||||||
@ -147,8 +147,19 @@ function formatterTitle(title){
|
|||||||
|
|
||||||
function search(code,name){
|
function search(code,name){
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
window.open("https://fund.eastmoney.com/"+code+".html","_blank","noreferrer,width=1000,top=100,left=100,status=no,toolbar=no,location=no,scrollbars=no")
|
//window.open("https://fund.eastmoney.com/"+code+".html","_blank","noreferrer,width=1000,top=100,left=100,status=no,toolbar=no,location=no,scrollbars=no")
|
||||||
//window.open("https://finance.sina.com.cn/fund/quotes/"+code+"/bc.shtml","_blank","width=1000,height=800,top=100,left=100,toolbar=no,location=no")
|
//window.open("https://finance.sina.com.cn/fund/quotes/"+code+"/bc.shtml","_blank","width=1000,height=800,top=100,left=100,toolbar=no,location=no")
|
||||||
|
|
||||||
|
Environment().then(env => {
|
||||||
|
switch (env.platform) {
|
||||||
|
case 'windows':
|
||||||
|
window.open("https://fund.eastmoney.com/"+code+".html","_blank","noreferrer,width=1000,top=100,left=100,status=no,toolbar=no,location=no,scrollbars=no")
|
||||||
|
break
|
||||||
|
default :
|
||||||
|
OpenURL("https://fund.eastmoney.com/"+code+".html")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
}, 500)
|
}, 500)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,7 +26,10 @@ import {
|
|||||||
SetStockAICron,
|
SetStockAICron,
|
||||||
SetStockSort,
|
SetStockSort,
|
||||||
ShareAnalysis,
|
ShareAnalysis,
|
||||||
UnFollow
|
UnFollow,
|
||||||
|
OpenURL,
|
||||||
|
SaveImage,
|
||||||
|
SaveWordFile
|
||||||
} from '../../wailsjs/go/main/App'
|
} from '../../wailsjs/go/main/App'
|
||||||
import {
|
import {
|
||||||
NAvatar,
|
NAvatar,
|
||||||
@ -41,6 +44,7 @@ import {
|
|||||||
useNotification
|
useNotification
|
||||||
} from 'naive-ui'
|
} from 'naive-ui'
|
||||||
import {
|
import {
|
||||||
|
Environment,
|
||||||
EventsEmit,
|
EventsEmit,
|
||||||
EventsOff,
|
EventsOff,
|
||||||
EventsOn,
|
EventsOn,
|
||||||
@ -103,7 +107,7 @@ const modalShow3 = ref(false)
|
|||||||
const modalShow4 = ref(false)
|
const modalShow4 = ref(false)
|
||||||
const modalShow5 = ref(false)
|
const modalShow5 = ref(false)
|
||||||
const addBTN = ref(true)
|
const addBTN = ref(true)
|
||||||
const enableTools= ref(false)
|
const enableTools = ref(false)
|
||||||
const formModel = ref({
|
const formModel = ref({
|
||||||
name: "",
|
name: "",
|
||||||
code: "",
|
code: "",
|
||||||
@ -384,7 +388,15 @@ EventsOn("updateVersion", async (msg) => {
|
|||||||
type: 'primary',
|
type: 'primary',
|
||||||
size: 'small',
|
size: 'small',
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
window.open(msg.html_url)
|
Environment().then(env => {
|
||||||
|
switch (env.platform) {
|
||||||
|
case 'windows':
|
||||||
|
window.open(msg.html_url)
|
||||||
|
break
|
||||||
|
default :
|
||||||
|
OpenURL(msg.html_url)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}, {default: () => '查看'})
|
}, {default: () => '查看'})
|
||||||
}
|
}
|
||||||
@ -441,7 +453,7 @@ function AddStock() {
|
|||||||
Follow(data.code).then(result => {
|
Follow(data.code).then(result => {
|
||||||
if (result === "关注成功") {
|
if (result === "关注成功") {
|
||||||
if (data.code.startsWith("us")) {
|
if (data.code.startsWith("us")) {
|
||||||
data.code= "gb_" + data.code.replace("us", "").toLowerCase()
|
data.code = "gb_" + data.code.replace("us", "").toLowerCase()
|
||||||
}
|
}
|
||||||
stocks.value.push(data.code)
|
stocks.value.push(data.code)
|
||||||
message.success(result)
|
message.success(result)
|
||||||
@ -614,12 +626,24 @@ function onSelect(item) {
|
|||||||
function openCenteredWindow(url, width, height) {
|
function openCenteredWindow(url, width, height) {
|
||||||
const left = (window.screen.width - width) / 2;
|
const left = (window.screen.width - width) / 2;
|
||||||
const top = (window.screen.height - height) / 2;
|
const top = (window.screen.height - height) / 2;
|
||||||
|
Environment().then(env => {
|
||||||
|
switch (env.platform) {
|
||||||
|
case 'windows':
|
||||||
|
window.open(url, target, features)
|
||||||
|
break
|
||||||
|
default :
|
||||||
|
OpenURL(url)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
return window.open(
|
|
||||||
url,
|
//
|
||||||
'centeredWindow',
|
// return window.open(
|
||||||
`width=${width},height=${height},left=${left},top=${top}`
|
// url,
|
||||||
);
|
// 'centeredWindow',
|
||||||
|
// `width=${width},height=${height},left=${left},top=${top}`
|
||||||
|
// );
|
||||||
}
|
}
|
||||||
|
|
||||||
function search(code, name) {
|
function search(code, name) {
|
||||||
@ -631,7 +655,7 @@ function search(code, name) {
|
|||||||
//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)
|
//window.open("https://www.iwencai.com/chat/?question="+code)
|
||||||
|
|
||||||
openCenteredWindow("https://www.iwencai.com/unifiedwap/result?w=" + name,1000,800)
|
openCenteredWindow("https://www.iwencai.com/unifiedwap/result?w=" + name, 1000, 800)
|
||||||
|
|
||||||
}, 500)
|
}, 500)
|
||||||
}
|
}
|
||||||
@ -1359,7 +1383,7 @@ function aiReCheckStock(stock, stockCode) {
|
|||||||
//
|
//
|
||||||
|
|
||||||
//message.info("sysPromptId:"+data.sysPromptId)
|
//message.info("sysPromptId:"+data.sysPromptId)
|
||||||
NewChatStream(stock, stockCode, data.question, data.sysPromptId,enableTools.value)
|
NewChatStream(stock, stockCode, data.question, data.sysPromptId, enableTools.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
function aiCheckStock(stock, stockCode) {
|
function aiCheckStock(stock, stockCode) {
|
||||||
@ -1437,21 +1461,42 @@ window.onerror = function (msg, source, lineno, colno, error) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function saveAsImage(name, code) {
|
function saveAsImage(name, code) {
|
||||||
const element = document.querySelector('.md-editor-preview');
|
Environment().then(env => {
|
||||||
if (element) {
|
switch (env.platform) {
|
||||||
html2canvas(element, {
|
case 'windows':
|
||||||
useCORS: true, // 解决跨域图片问题
|
const element = document.querySelector('.md-editor-preview');
|
||||||
scale: 2, // 提高截图质量
|
if (element) {
|
||||||
allowTaint: true, // 允许跨域图片
|
html2canvas(element, {
|
||||||
}).then(canvas => {
|
useCORS: true, // 解决跨域图片问题
|
||||||
const link = document.createElement('a');
|
scale: 2, // 提高截图质量
|
||||||
link.href = canvas.toDataURL('image/png');
|
allowTaint: true, // 允许跨域图片
|
||||||
link.download = name + "[" + code + ']-ai-analysis-result.png';
|
}).then(canvas => {
|
||||||
link.click();
|
const link = document.createElement('a');
|
||||||
});
|
link.href = canvas.toDataURL('image/png');
|
||||||
} else {
|
link.download = name + "[" + code + ']-ai-analysis-result.png';
|
||||||
message.error('无法找到分析结果元素');
|
link.click();
|
||||||
}
|
});
|
||||||
|
} else {
|
||||||
|
message.error('无法找到分析结果元素');
|
||||||
|
}
|
||||||
|
break
|
||||||
|
default :
|
||||||
|
saveCanvasImage(name)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function saveCanvasImage(name) {
|
||||||
|
const element = document.querySelector('.md-editor-preview'); // 要截图的 DOM 节点
|
||||||
|
const canvas = await html2canvas(element)
|
||||||
|
|
||||||
|
const dataUrl = canvas.toDataURL('image/png') // base64 格式
|
||||||
|
const base64 = dataUrl.replace(/^data:image\/png;base64,/, '')
|
||||||
|
|
||||||
|
// 调用 Go 后端保存文件(Wails 绑定方法)
|
||||||
|
await SaveImage(name,base64).then(result => {
|
||||||
|
message.success(result)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async function copyToClipboard() {
|
async function copyToClipboard() {
|
||||||
@ -1511,13 +1556,26 @@ AI赋能股票分析:自选股行情获取,成本盈亏展示,涨跌报警
|
|||||||
`
|
`
|
||||||
// landscape就是横着的,portrait是竖着的,默认是竖屏portrait。
|
// landscape就是横着的,portrait是竖着的,默认是竖屏portrait。
|
||||||
const blob = await asBlob(value, {orientation: 'portrait'})
|
const blob = await asBlob(value, {orientation: 'portrait'})
|
||||||
const a = document.createElement('a')
|
const { platform } = await Environment()
|
||||||
a.href = URL.createObjectURL(blob)
|
switch (platform) {
|
||||||
a.download = `${data.name}[${data.code}]-ai-analysis-result.docx`;
|
case 'windows':
|
||||||
a.click()
|
const a = document.createElement('a')
|
||||||
// 下载后将标签移除
|
a.href = URL.createObjectURL(blob)
|
||||||
URL.revokeObjectURL(a.href);
|
a.download = `${data.name}[${data.code}]-ai-analysis-result.docx`;
|
||||||
a.remove()
|
a.click()
|
||||||
|
// 下载后将标签移除
|
||||||
|
URL.revokeObjectURL(a.href);
|
||||||
|
a.remove()
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
const arrayBuffer = await blob.arrayBuffer()
|
||||||
|
const uint8Array = new Uint8Array(arrayBuffer)
|
||||||
|
const binary = uint8Array.reduce((data, byte) => data + String.fromCharCode(byte), '')
|
||||||
|
const base64 = btoa(binary)
|
||||||
|
await SaveWordFile(`${data.name}[${data.code}]-ai-analysis-result.docx`, base64).then(result => {
|
||||||
|
message.success(result)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function share(code, name) {
|
function share(code, name) {
|
||||||
@ -1747,7 +1805,8 @@ function searchStockReport(stockCode) {
|
|||||||
取消关注
|
取消关注
|
||||||
</n-button>
|
</n-button>
|
||||||
|
|
||||||
<n-button size="tiny" v-if="data.openAiEnable" secondary type="warning" @click="aiCheckStock(result['股票名称'],result['股票代码'])">
|
<n-button size="tiny" v-if="data.openAiEnable" secondary type="warning"
|
||||||
|
@click="aiCheckStock(result['股票名称'],result['股票代码'])">
|
||||||
AI分析
|
AI分析
|
||||||
</n-button>
|
</n-button>
|
||||||
</template>
|
</template>
|
||||||
@ -1756,7 +1815,9 @@ function searchStockReport(stockCode) {
|
|||||||
<n-text :type="'info'">{{ result["日期"] + " " + result["时间"] }}</n-text>
|
<n-text :type="'info'">{{ result["日期"] + " " + result["时间"] }}</n-text>
|
||||||
<n-tag size="small" v-if="result.volume>0" :type="result.profitType">{{ result.volume + "股" }}</n-tag>
|
<n-tag size="small" v-if="result.volume>0" :type="result.profitType">{{ result.volume + "股" }}</n-tag>
|
||||||
<n-tag size="small" v-if="result.costPrice>0" :type="result.profitType">
|
<n-tag size="small" v-if="result.costPrice>0" :type="result.profitType">
|
||||||
{{ "成本:" + result.costPrice + "*" + result.costVolume + " " + result.profit + "%" + " ( " + result.profitAmount + " ¥ )" }}
|
{{
|
||||||
|
"成本:" + result.costPrice + "*" + result.costVolume + " " + result.profit + "%" + " ( " + result.profitAmount + " ¥ )"
|
||||||
|
}}
|
||||||
</n-tag>
|
</n-tag>
|
||||||
</n-flex>
|
</n-flex>
|
||||||
</template>
|
</template>
|
||||||
@ -1815,7 +1876,8 @@ function searchStockReport(stockCode) {
|
|||||||
</n-text>
|
</n-text>
|
||||||
</n-gi>
|
</n-gi>
|
||||||
<n-gi :span="6">
|
<n-gi :span="6">
|
||||||
<stock-spark-line :last-price="Number(result['当前价格'])" :open-price="Number(result['昨日收盘价'])" :stock-code="result['股票代码']" :stock-name="result['股票名称']" ></stock-spark-line>
|
<stock-spark-line :last-price="Number(result['当前价格'])" :open-price="Number(result['昨日收盘价'])"
|
||||||
|
:stock-code="result['股票代码']" :stock-name="result['股票名称']"></stock-spark-line>
|
||||||
</n-gi>
|
</n-gi>
|
||||||
</n-grid>
|
</n-grid>
|
||||||
<n-grid :cols="2" :y-gap="4" :x-gap="4">
|
<n-grid :cols="2" :y-gap="4" :x-gap="4">
|
||||||
@ -1886,9 +1948,10 @@ function searchStockReport(stockCode) {
|
|||||||
取消关注
|
取消关注
|
||||||
</n-button>
|
</n-button>
|
||||||
|
|
||||||
<n-button size="tiny" v-if="data.openAiEnable" secondary type="warning" @click="aiCheckStock(result['股票名称'],result['股票代码'])">
|
<n-button size="tiny" v-if="data.openAiEnable" secondary type="warning"
|
||||||
AI分析
|
@click="aiCheckStock(result['股票名称'],result['股票代码'])">
|
||||||
</n-button>
|
AI分析
|
||||||
|
</n-button>
|
||||||
<n-button secondary type="error" size="tiny"
|
<n-button secondary type="error" size="tiny"
|
||||||
@click="delStockGroup(result['股票代码'],result['股票名称'],group.ID)">移出分组
|
@click="delStockGroup(result['股票代码'],result['股票名称'],group.ID)">移出分组
|
||||||
</n-button>
|
</n-button>
|
||||||
@ -1898,7 +1961,9 @@ function searchStockReport(stockCode) {
|
|||||||
<n-text :type="'info'">{{ result["日期"] + " " + result["时间"] }}</n-text>
|
<n-text :type="'info'">{{ result["日期"] + " " + result["时间"] }}</n-text>
|
||||||
<n-tag size="small" v-if="result.volume>0" :type="result.profitType">{{ result.volume + "股" }}</n-tag>
|
<n-tag size="small" v-if="result.volume>0" :type="result.profitType">{{ result.volume + "股" }}</n-tag>
|
||||||
<n-tag size="small" v-if="result.costPrice>0" :type="result.profitType">
|
<n-tag size="small" v-if="result.costPrice>0" :type="result.profitType">
|
||||||
{{ "成本:" + result.costPrice + "*" + result.costVolume + " " + result.profit + "%" + " ( " + result.profitAmount + " ¥ )" }}
|
{{
|
||||||
|
"成本:" + result.costPrice + "*" + result.costVolume + " " + result.profit + "%" + " ( " + result.profitAmount + " ¥ )"
|
||||||
|
}}
|
||||||
</n-tag>
|
</n-tag>
|
||||||
</n-flex>
|
</n-flex>
|
||||||
</template>
|
</template>
|
||||||
@ -2087,7 +2152,9 @@ function searchStockReport(stockCode) {
|
|||||||
不启用AI函数工具调用
|
不启用AI函数工具调用
|
||||||
</template>
|
</template>
|
||||||
</n-switch>
|
</n-switch>
|
||||||
<n-gradient-text type="error" style="margin-left: 10px">*AI函数工具调用可以增强AI获取数据的能力,但会消耗更多tokens。</n-gradient-text>
|
<n-gradient-text type="error" style="margin-left: 10px">
|
||||||
|
*AI函数工具调用可以增强AI获取数据的能力,但会消耗更多tokens。
|
||||||
|
</n-gradient-text>
|
||||||
</n-flex>
|
</n-flex>
|
||||||
<n-flex justify="space-between" style="margin-bottom: 10px">
|
<n-flex justify="space-between" style="margin-bottom: 10px">
|
||||||
<n-select style="width: 49%" v-model:value="data.sysPromptId" label-field="name" value-field="ID"
|
<n-select style="width: 49%" v-model:value="data.sysPromptId" label-field="name" value-field="ID"
|
||||||
|
6
frontend/wailsjs/go/main/App.d.ts
vendored
6
frontend/wailsjs/go/main/App.d.ts
vendored
@ -89,6 +89,8 @@ export function NewChatStream(arg1:string,arg2:string,arg3:string,arg4:any,arg5:
|
|||||||
|
|
||||||
export function NewsPush(arg1:any):Promise<void>;
|
export function NewsPush(arg1:any):Promise<void>;
|
||||||
|
|
||||||
|
export function OpenURL(arg1:string):Promise<void>;
|
||||||
|
|
||||||
export function ReFleshTelegraphList(arg1:string):Promise<any>;
|
export function ReFleshTelegraphList(arg1:string):Promise<any>;
|
||||||
|
|
||||||
export function RemoveGroup(arg1:number):Promise<string>;
|
export function RemoveGroup(arg1:number):Promise<string>;
|
||||||
@ -99,6 +101,10 @@ export function SaveAIResponseResult(arg1:string,arg2:string,arg3:string,arg4:st
|
|||||||
|
|
||||||
export function SaveAsMarkdown(arg1:string,arg2:string):Promise<string>;
|
export function SaveAsMarkdown(arg1:string,arg2:string):Promise<string>;
|
||||||
|
|
||||||
|
export function SaveImage(arg1:string,arg2:string):Promise<string>;
|
||||||
|
|
||||||
|
export function SaveWordFile(arg1:string,arg2:string):Promise<string>;
|
||||||
|
|
||||||
export function SearchStock(arg1:string):Promise<Record<string, any>>;
|
export function SearchStock(arg1:string):Promise<Record<string, any>>;
|
||||||
|
|
||||||
export function SendDingDingMessage(arg1:string,arg2:string):Promise<string>;
|
export function SendDingDingMessage(arg1:string,arg2:string):Promise<string>;
|
||||||
|
@ -174,6 +174,10 @@ export function NewsPush(arg1) {
|
|||||||
return window['go']['main']['App']['NewsPush'](arg1);
|
return window['go']['main']['App']['NewsPush'](arg1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function OpenURL(arg1) {
|
||||||
|
return window['go']['main']['App']['OpenURL'](arg1);
|
||||||
|
}
|
||||||
|
|
||||||
export function ReFleshTelegraphList(arg1) {
|
export function ReFleshTelegraphList(arg1) {
|
||||||
return window['go']['main']['App']['ReFleshTelegraphList'](arg1);
|
return window['go']['main']['App']['ReFleshTelegraphList'](arg1);
|
||||||
}
|
}
|
||||||
@ -194,6 +198,14 @@ export function SaveAsMarkdown(arg1, arg2) {
|
|||||||
return window['go']['main']['App']['SaveAsMarkdown'](arg1, arg2);
|
return window['go']['main']['App']['SaveAsMarkdown'](arg1, arg2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function SaveImage(arg1, arg2) {
|
||||||
|
return window['go']['main']['App']['SaveImage'](arg1, arg2);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SaveWordFile(arg1, arg2) {
|
||||||
|
return window['go']['main']['App']['SaveWordFile'](arg1, arg2);
|
||||||
|
}
|
||||||
|
|
||||||
export function SearchStock(arg1) {
|
export function SearchStock(arg1) {
|
||||||
return window['go']['main']['App']['SearchStock'](arg1);
|
return window['go']['main']['App']['SearchStock'](arg1);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user