feat(settings):设置界面添加主题切换功能

- 在 Settings 模型中添加 darkTheme 字段
- 在前端 App.vue 中实现暗黑主题切换
- 更新设置界面,增加暗黑主题开关
- 调整股票卡片样式,支持暗黑主题
- 优化 HTML 和 CSS 样式以适应暗黑主题
This commit is contained in:
ArvinLovegood 2025-03-26 15:29:08 +08:00
parent 9d546fd214
commit c8178a6c5f
9 changed files with 68 additions and 41 deletions

10
app.go
View File

@ -319,11 +319,11 @@ func MonitorStockPrices(a *App) {
}
total += stockInfo.ProfitAmountToday
//price, _ := convertor.ToFloat(stockInfo.Price)
//if stockInfo.PrePrice != price {
//logger.SugaredLogger.Infof("-----------------------股票代码: %s, 股票名称: %s, 股票价格: %s,盘前盘后:%s", stockInfo.Code, stockInfo.Name, stockInfo.Price, stockInfo.BA)
go runtime.EventsEmit(a.ctx, "stock_price", stockInfo)
//}
price, _ := convertor.ToFloat(stockInfo.Price)
if stockInfo.PrePrice != price {
logger.SugaredLogger.Infof("-----------------------股票代码: %s, 股票名称: %s, 股票价格: %s,盘前盘后:%s", stockInfo.Code, stockInfo.Name, stockInfo.Price, stockInfo.BA)
go runtime.EventsEmit(a.ctx, "stock_price", stockInfo)
}
}
if total != 0 {
title := "go-stock " + time.Now().Format(time.DateTime) + fmt.Sprintf(" %.2f¥", total)

View File

@ -31,6 +31,7 @@ type Settings struct {
EnableDanmu bool `json:"enableDanmu"`
BrowserPath string `json:"browserPath"`
EnableNews bool `json:"enableNews"`
DarkTheme bool `json:"darkTheme"`
}
func (receiver Settings) TableName() string {
@ -73,6 +74,7 @@ func (s SettingsApi) UpdateConfig() string {
"enable_danmu": s.Config.EnableDanmu,
"browser_path": s.Config.BrowserPath,
"enable_news": s.Config.EnableNews,
"dark_theme": s.Config.DarkTheme,
})
} else {
logger.SugaredLogger.Infof("未找到配置,创建默认配置:%+v", s.Config)
@ -98,6 +100,7 @@ func (s SettingsApi) UpdateConfig() string {
EnableDanmu: s.Config.EnableDanmu,
BrowserPath: s.Config.BrowserPath,
EnableNews: s.Config.EnableNews,
DarkTheme: s.Config.DarkTheme,
})
}
return "保存成功!"

View File

@ -20,9 +20,10 @@ import {
import {GetConfig} from "../wailsjs/go/main/App";
const enableNews= ref(false)
const contentStyle = ref("")
const enableDarkTheme = ref(true)
const content = ref('数据来源于网络,仅供参考;投资有风险,入市需谨慎')
const isFullscreen = ref(false)
const activeKey = ref('stock')
const activeKey = ref('')
const containerRef= ref({})
const realtimeProfit= ref(0)
const telegraph= ref([])
@ -35,7 +36,6 @@ const menuOptions = ref([
to: {
name: 'stock',
params: {
id: 'zh-CN'
},
}
},
@ -60,7 +60,6 @@ const menuOptions = ref([
to: {
name: 'fund',
params: {
id: 'zh-CN'
},
}
},
@ -85,7 +84,6 @@ const menuOptions = ref([
to: {
name: 'settings',
params: {
id: 'zh-CN'
}
}
},
@ -102,7 +100,6 @@ const menuOptions = ref([
to: {
name: 'about',
params: {
id: 'zh-CN'
}
}
},
@ -199,23 +196,35 @@ window.onerror = function (msg, source, lineno, colno, error) {
};
onBeforeMount(()=>{
// GetConfig().then((res)=>{
// console.log(res)
// if(res.darkTheme){
// enableDarkTheme.value=darkTheme
// }
// if(res.enableNews){
// enableNews.value=true
// }
// })
})
onMounted(()=>{
contentStyle.value="max-height: calc(90vh);overflow: hidden"
GetConfig().then((res)=>{
console.log(res)
if(res.darkTheme){
enableDarkTheme.value=darkTheme
}else{
enableDarkTheme.value=null
}
if(res.enableNews){
enableNews.value=true
}
})
})
onMounted(()=>{
contentStyle.value="max-height: calc(90vh);overflow: hidden"
})
</script>
<template>
<n-config-provider :theme="darkTheme" ref="containerRef" >
<n-config-provider ref="containerRef" :theme="enableDarkTheme" >
<n-message-provider >
<n-notification-provider>
<n-modal-provider>

View File

@ -1,6 +1,6 @@
<script setup>
import {onMounted, ref} from "vue";
import {computed, onMounted, ref} from "vue";
import {ExportConfig, GetConfig, SendDingDingMessageByType, UpdateConfig} from "../../wailsjs/go/main/App";
import {useMessage} from "naive-ui";
import {data} from "../../wailsjs/go/models";
@ -36,6 +36,7 @@ const formValue = ref({
enableDanmu:false,
browserPath: '',
enableNews:false,
darkTheme:true,
})
onMounted(()=>{
@ -67,6 +68,7 @@ onMounted(()=>{
formValue.value.enableDanmu = res.enableDanmu
formValue.value.browserPath = res.browserPath
formValue.value.enableNews = res.enableNews
formValue.value.darkTheme = res.darkTheme
console.log(res)
})
@ -97,6 +99,7 @@ function saveConfig(){
enableDanmu:formValue.value.enableDanmu,
browserPath:formValue.value.browserPath,
enableNews:formValue.value.enableNews,
darkTheme:formValue.value.darkTheme
})
//console.log("Settings",config)
@ -170,6 +173,7 @@ function importConfig(){
formValue.value.enableDanmu = config.enableDanmu
formValue.value.browserPath = config.browserPath
formValue.value.enableNews = config.enableNews
formValue.value.darkTheme = config.darkTheme
// formRef.value.resetFields()
};
reader.readAsText(file);
@ -196,12 +200,12 @@ window.onerror = function (event, source, lineno, colno, error) {
<template>
<n-flex justify="left" style="margin-top: 12px;padding-left: 12px">
<n-form ref="formRef" :label-placement="'left'" :label-align="'left'">
<n-grid :cols="24" :x-gap="24" style="text-align: left">
<n-form ref="formRef" :label-placement="'left'" :label-align="'left'" >
<n-grid :cols="24" :x-gap="24" style="text-align: left" >
<n-gi :span="24">
<n-text type="default" style="font-size: 25px;font-weight: bold">基础设置</n-text>
<n-text type="primary" style="font-size: 25px;font-weight: bold">基础设置</n-text>
</n-gi>
<n-form-item-gi :span="10" label="Tushare api token" path="tushareToken" >
<n-form-item-gi :span="10" label="Tushare api token" path="tushareToken" >
<n-input type="text" placeholder="Tushare api token" v-model:value="formValue.tushareToken" clearable />
</n-form-item-gi>
<n-form-item-gi :span="4" label="启动时更新A股/指数信息:" path="updateBasicInfoOnStart" >
@ -214,6 +218,9 @@ window.onerror = function (event, source, lineno, colno, error) {
</template>
</n-input-number>
</n-form-item-gi>
<n-form-item-gi :span="5" label="暗黑主题(重启生效)" path="darkTheme" >
<n-switch v-model:value="formValue.darkTheme" />
</n-form-item-gi>
<n-form-item-gi :span="22" label="浏览器路径:" path="browserPath" >
<n-input type="text" placeholder="浏览器路径" v-model:value="formValue.browserPath" clearable />
</n-form-item-gi>
@ -221,12 +228,12 @@ window.onerror = function (event, source, lineno, colno, error) {
<n-grid :cols="24" :x-gap="24" style="text-align: left">
<n-gi :span="24">
<n-text type="default" style="font-size: 25px;font-weight: bold">通知设置</n-text>
<n-text type="primary" style="font-size: 25px;font-weight: bold">通知设置</n-text>
</n-gi>
<n-form-item-gi :span="6" label="是否启用钉钉推送:" path="dingPush.enable" >
<n-switch v-model:value="formValue.dingPush.enable" />
</n-form-item-gi>
<n-form-item-gi :span="6" label="是否启用本地推送:" path="localPush.enable" >
<n-form-item-gi :span="6" label="是否启用本地推送:" path="localPush.enable" >
<n-switch v-model:value="formValue.localPush.enable" />
</n-form-item-gi>
<n-form-item-gi :span="5" label="弹幕功能:" path="enableDanmu" >
@ -243,36 +250,36 @@ window.onerror = function (event, source, lineno, colno, error) {
<n-grid :cols="24" :x-gap="24" style="text-align: left;">
<n-gi :span="24">
<n-text type="default" style="font-size: 25px;font-weight: bold">OpenAI设置</n-text>
<n-text type="primary" style="font-size: 25px;font-weight: bold">OpenAI设置</n-text>
</n-gi>
<n-form-item-gi :span="3" label="是否启用AI诊股" path="openAI.enable" >
<n-switch v-model:value="formValue.openAI.enable" />
</n-form-item-gi>
<n-form-item-gi :span="9" v-if="formValue.openAI.enable" label="openAI 接口地址:" path="openAI.baseUrl">
<n-form-item-gi :span="9" v-if="formValue.openAI.enable" label="openAI 接口地址:" path="openAI.baseUrl" >
<n-input type="text" placeholder="AI接口地址" v-model:value="formValue.openAI.baseUrl" clearable />
</n-form-item-gi>
<n-form-item-gi :span="5" v-if="formValue.openAI.enable" label="AI Timeout(秒)" title="AI请求超时时间(秒)" path="openAI.timeout">
<n-form-item-gi :span="5" v-if="formValue.openAI.enable" label="AI Timeout(秒)" title="AI请求超时时间(秒)" path="openAI.timeout" >
<n-input-number min="60" step="1" placeholder="AI请求超时时间(秒)" v-model:value="formValue.openAI.timeout" />
</n-form-item-gi>
<n-form-item-gi :span="5" v-if="formValue.openAI.enable" label="Crawler Timeout(秒)" title="资讯采集超时时间(秒)" path="openAI.crawlTimeOut">
<n-form-item-gi :span="5" v-if="formValue.openAI.enable" label="Crawler Timeout(秒)" title="资讯采集超时时间(秒)" path="openAI.crawlTimeOut" >
<n-input-number min="30" step="1" placeholder="资讯采集超时时间(秒)" v-model:value="formValue.openAI.crawlTimeOut" />
</n-form-item-gi>
<n-form-item-gi :span="12" v-if="formValue.openAI.enable" label="openAI 令牌(apiKey)" path="openAI.apiKey">
<n-form-item-gi :span="12" v-if="formValue.openAI.enable" label="openAI 令牌(apiKey)" path="openAI.apiKey" >
<n-input type="text" placeholder="apiKey" v-model:value="formValue.openAI.apiKey" clearable />
</n-form-item-gi>
<n-form-item-gi :span="10" v-if="formValue.openAI.enable" label="AI模型名称" path="openAI.model">
<n-form-item-gi :span="10" v-if="formValue.openAI.enable" label="AI模型名称" path="openAI.model" >
<n-input type="text" placeholder="AI模型名称" v-model:value="formValue.openAI.model" clearable />
</n-form-item-gi>
<n-form-item-gi :span="12" v-if="formValue.openAI.enable" label="openAI temperature" path="openAI.temperature" >
<n-input-number placeholder="temperature" v-model:value="formValue.openAI.temperature"/>
</n-form-item-gi>
<n-form-item-gi :span="5" v-if="formValue.openAI.enable" label="openAI maxTokens" path="openAI.maxTokens">
<n-form-item-gi :span="5" v-if="formValue.openAI.enable" label="openAI maxTokens" path="openAI.maxTokens" >
<n-input-number placeholder="maxTokens" v-model:value="formValue.openAI.maxTokens"/>
</n-form-item-gi>
<n-form-item-gi :span="5" v-if="formValue.openAI.enable" title="天数越多消耗tokens越多" label="日K线数据(天)" path="openAI.maxTokens">
<n-form-item-gi :span="5" v-if="formValue.openAI.enable" title="天数越多消耗tokens越多" label="日K线数据(天)" path="openAI.maxTokens" >
<n-input-number min="30" step="1" max="365" placeholder="日K线数据(天)" title="天数越多消耗tokens越多" v-model:value="formValue.openAI.kDays"/>
</n-form-item-gi>
<n-form-item-gi :span="11" v-if="formValue.openAI.enable" label="模型系统 Prompt" path="openAI.prompt">
<n-form-item-gi :span="11" v-if="formValue.openAI.enable" label="模型系统 Prompt" path="openAI.prompt" >
<n-input v-model:value="formValue.openAI.prompt"
type="textarea"
:show-count="true"
@ -283,7 +290,7 @@ window.onerror = function (event, source, lineno, colno, error) {
}"
/>
</n-form-item-gi>
<n-form-item-gi :span="11" v-if="formValue.openAI.enable" label="模型用户 Prompt" path="openAI.questionTemplate">
<n-form-item-gi :span="11" v-if="formValue.openAI.enable" label="模型用户 Prompt" path="openAI.questionTemplate" >
<n-input v-model:value="formValue.openAI.questionTemplate"
type="textarea"
:show-count="true"

View File

@ -818,7 +818,7 @@ function share(code,name){
<vue-danmaku v-model:danmus="danmus" style="height:100px; width:100%;z-index: 9;position:absolute; top: 400px; pointer-events: none;" ></vue-danmaku>
<n-grid :x-gap="8" :cols="3" :y-gap="8" >
<n-gi :id="result['股票代码']+'_gi'" v-for="result in sortedResults" style="margin-left: 2px;" >
<n-card :id="result['股票代码']" :data-code="result['股票代码']" :bordered="false" :title="result['股票名称']" :closable="false" @close="removeMonitor(result['股票代码'],result['股票名称'],result.key)">
<n-card :id="result['股票代码']" :data-code="result['股票代码']" :bordered="true" :title="result['股票名称']" :closable="false" @close="removeMonitor(result['股票代码'],result['股票名称'],result.key)">
<n-grid :cols="1" :y-gap="6">
<n-gi>
<n-text :type="result.type" >

View File

@ -8,7 +8,7 @@ import fundView from "../components/fund.vue";
const routes = [
{ path: '/', component: stockView,name: 'stock' },
{ path: '/fund', component: fundView,name: 'fund' },
{ path: '/settings/:id', component: settingsView,name: 'settings' },
{ path: '/settings', component: settingsView,name: 'settings' },
{ path: '/about', component: about,name: 'about' },
]

View File

@ -1,12 +1,12 @@
html {
background-color: rgba(27, 38, 54, 1);
/*background-color: rgba(27, 38, 54, 1);*/
text-align: center;
color: white;
/*color: white;*/
}
body {
margin: 0;
color: white;
/*color: white;*/
font-family: "Nunito", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto",
"Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
sans-serif;

View File

@ -172,6 +172,7 @@ export namespace data {
enableDanmu: boolean;
browserPath: string;
enableNews: boolean;
darkTheme: boolean;
static createFrom(source: any = {}) {
return new Settings(source);
@ -204,6 +205,7 @@ export namespace data {
this.enableDanmu = source["enableDanmu"];
this.browserPath = source["browserPath"];
this.enableNews = source["enableNews"];
this.darkTheme = source["darkTheme"];
}
convertValues(a: any, classs: any, asMap: boolean = false): any {

10
main.go
View File

@ -129,13 +129,19 @@ func main() {
// height = 768
//}
darkTheme := data.NewSettingsApi(&data.Settings{}).GetConfig().DarkTheme
backgroundColour := &options.RGBA{R: 255, G: 255, B: 255, A: 1}
if darkTheme {
backgroundColour = &options.RGBA{R: 27, G: 38, B: 54, A: 1}
}
// Create application with options
err := wails.Run(&options.App{
Title: "go-stock",
//Width: width * 4 / 5,
//Height: height * 4 / 5,
MinWidth: 1456,
MinHeight: 800,
MinHeight: 820,
//MaxWidth: width,
//MaxHeight: height,
DisableResize: false,
@ -144,7 +150,7 @@ func main() {
StartHidden: false,
HideWindowOnClose: false,
EnableDefaultContextMenu: true,
BackgroundColour: &options.RGBA{R: 255, G: 255, B: 255, A: 255},
BackgroundColour: backgroundColour,
Assets: assets,
Menu: AppMenu,
Logger: nil,