feat(app): 兼容darwin版本浏览跳转,保存图片文件等功能

This commit is contained in:
Gico001 2025-07-10 14:49:10 +08:00
parent 58f3009902
commit bbd4bb5b48
9 changed files with 334 additions and 123 deletions

79
app.go
View File

@ -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
}

View File

@ -1 +1 @@
2d63c3a999d797889c01d6c96451b197 8d3264f90073dfceb29c3619775d830d

View File

@ -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)

View File

@ -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>

View File

@ -3,8 +3,8 @@
// preview.cssstyle.css // preview.cssstyle.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: () => '查看' })
} }

View File

@ -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)
} }

View File

@ -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赋能股票分析自选股行情获取成本盈亏展示涨跌报警
` `
// landscapeportraitportrait // landscapeportraitportrait
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>&nbsp; </n-button>&nbsp;
<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>&nbsp; </n-button>&nbsp;
<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"

View File

@ -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>;

View File

@ -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);
} }