feat: 更新版本号至2.2.12,新增窗口关闭行为配置选项

This commit is contained in:
ILoveBingLu
2026-03-05 18:02:26 +08:00
parent 05dd789f55
commit fa48ac4abe
6 changed files with 92 additions and 38 deletions
+2
View File
@@ -6,6 +6,8 @@
flex-direction: column;
padding: 16px 0;
transition: width 0.25s ease;
position: relative;
z-index: 100;
&.collapsed {
width: 64px;
+28 -25
View File
@@ -711,17 +711,20 @@
padding: 10px 24px;
border-radius: 9999px;
font-size: 14px;
z-index: 100;
z-index: 10000;
animation: slideDown 0.3s ease;
color: white;
backdrop-filter: blur(24px) saturate(180%);
-webkit-backdrop-filter: blur(24px) saturate(180%);
border: 1px solid rgba(255, 255, 255, 0.2);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12);
&.success {
background: var(--primary);
color: white;
background: rgba(var(--primary-rgb), 0.75);
}
&.error {
background: var(--danger);
color: white;
background: rgba(239, 68, 68, 0.75);
}
}
@@ -2046,17 +2049,17 @@ to {
// 引用样式选择器
.quote-style-options {
display: flex;
gap: 12px;
gap: 8px;
.radio-label {
flex: 1;
position: relative;
border-radius: 12px;
padding: 12px;
border-radius: 8px;
padding: 8px;
cursor: pointer;
display: flex;
align-items: flex-start;
gap: 12px;
gap: 8px;
overflow: hidden;
background: linear-gradient(135deg, rgba(var(--primary-rgb), 0.08) 0%, rgba(var(--primary-rgb), 0.02) 100%);
@@ -2107,14 +2110,14 @@ to {
flex-direction: row;
align-items: flex-start;
justify-content: space-between;
gap: 12px;
gap: 8px;
width: 100%;
.radio-title {
font-size: 14px;
font-weight: 500;
color: var(--text-primary);
margin-top: 16px;
margin-top: 8px;
}
.radio-desc {
@@ -2126,22 +2129,22 @@ to {
// 预览组件样式
.style-preview {
flex: 1;
min-height: 80px;
min-height: 60px;
background: transparent;
margin-bottom: 0;
display: flex;
align-items: flex-start;
justify-content: flex-end;
/* 靠展示,模拟发送方 */
padding: 16px 12px;
justify-content: flex-start;
/* 靠展示,模拟接收方 */
padding: 10px 8px;
border: none;
.preview-avatar {
width: 36px;
height: 36px;
width: 28px;
height: 28px;
border-radius: 50%;
background: var(--bg-tertiary);
margin-left: 10px;
margin-right: 8px;
flex-shrink: 0;
object-fit: cover;
border: 1px solid var(--border-color);
@@ -2154,10 +2157,10 @@ to {
// 经典模式预览
.preview-bubble.default {
background: var(--primary);
/* 使用主色调,模拟发送方 */
/* 使用主色调,模拟接收方 */
border: none;
border-radius: 12px 12px 2px 12px;
/* 真实气泡圆角 */
border-radius: 12px 12px 12px 2px;
/* 左下角小圆角,适合左边消息 */
padding: 10px 12px;
width: fit-content;
max-width: 90%;
@@ -2188,12 +2191,12 @@ to {
display: flex;
flex-direction: column;
width: 100%;
align-items: flex-end;
/* 模拟发送方 */
align-items: flex-start;
/* 模拟接收方 */
.preview-bubble.wechat {
background: var(--primary);
border-radius: 12px 12px 2px 12px;
border-radius: 12px 12px 12px 2px;
padding: 10px 12px;
margin-bottom: 4px;
color: white;
@@ -2205,7 +2208,7 @@ to {
.preview-quote-bubble {
background: var(--bg-tertiary);
border-radius: 12px 4px 12px 12px;
border-radius: 4px;
padding: 4px 10px;
width: fit-content;
max-width: 90%;
+45 -10
View File
@@ -103,6 +103,7 @@ function SettingsPage() {
const [message, setMessage] = useState<{ text: string; success: boolean } | null>(null)
const [showDecryptKey, setShowDecryptKey] = useState(false)
const [showXorKey, setShowXorKey] = useState(false)
const [closeToTray, setCloseToTray] = useState(true)
const [showAesKey, setShowAesKey] = useState(false)
const [showClearDialog, setShowClearDialog] = useState<{
type: 'images' | 'emojis' | 'databases' | 'all' | 'config'
@@ -225,6 +226,10 @@ function SettingsPage() {
setAiEnableThinkingState(savedAiEnableThinking)
setAiMessageLimitState(savedAiMessageLimit)
// 加载关闭行为配置
const savedCloseToTray = await configService.getCloseToTray()
setCloseToTray(savedCloseToTray)
} catch (e) {
console.error('加载配置失败:', e)
}
@@ -762,6 +767,9 @@ function SettingsPage() {
await configService.setAiEnableThinking(aiEnableThinking)
await configService.setAiMessageLimit(aiMessageLimit)
// 保存关闭行为配置
await configService.setCloseToTray(closeToTray)
// 如果数据库配置完整,尝试设置已连接状态(不进行耗时测试,仅标记)
if (decryptKey && dbPath && wxid && decryptKey.length === 64 && isAccountVerified) {
setDbConnected(true, dbPath)
@@ -806,7 +814,7 @@ function SettingsPage() {
<h3 className="section-title" style={{ marginTop: '2rem' }}></h3>
<div className="quote-style-options">
<label className={`radio-label ${appIcon === 'default' ? 'active' : ''}`} style={{ width: 'auto', minWidth: '180px' }}>
<label className={`radio-label ${appIcon === 'default' ? 'active' : ''}`} style={{ width: 'auto', minWidth: '120px' }}>
<input
type="radio"
name="appIcon"
@@ -814,15 +822,14 @@ function SettingsPage() {
checked={appIcon === 'default' || !appIcon}
onChange={() => setAppIcon('default')}
/>
<div className="radio-content">
<span className="radio-title"></span>
<div className="radio-content" style={{ justifyContent: 'center' }}>
<div className="style-preview" style={{ justifyContent: 'center', padding: '10px' }}>
<img src="./logo.png" alt="默认" style={{ width: '48px', height: '48px' }} />
</div>
</div>
</label>
<label className={`radio-label ${appIcon === 'xinnian' ? 'active' : ''}`} style={{ width: 'auto', minWidth: '180px' }}>
<label className={`radio-label ${appIcon === 'xinnian' ? 'active' : ''}`} style={{ width: 'auto', minWidth: '120px' }}>
<input
type="radio"
name="appIcon"
@@ -830,8 +837,7 @@ function SettingsPage() {
checked={appIcon === 'xinnian'}
onChange={() => setAppIcon('xinnian')}
/>
<div className="radio-content">
<span className="radio-title"></span>
<div className="radio-content" style={{ justifyContent: 'center' }}>
<div className="style-preview" style={{ justifyContent: 'center', padding: '10px' }}>
<img src="./xinnian.png" alt="新年" style={{ width: '48px', height: '48px' }} />
</div>
@@ -850,8 +856,8 @@ function SettingsPage() {
onChange={() => setQuoteStyle('default')}
/>
<div className="radio-content">
<span className="radio-title"></span>
<div className="style-preview">
<img src="./logo.png" className="preview-avatar" alt="对方" />
<div className="preview-bubble default">
<div className="preview-quote">
张三: 那天去爬山的照片...
@@ -860,7 +866,6 @@ function SettingsPage() {
</div>
</div>
<img src="./logo.png" className="preview-avatar" alt="我" />
</div>
</div>
</label>
@@ -874,8 +879,8 @@ function SettingsPage() {
onChange={() => setQuoteStyle('wechat')}
/>
<div className="radio-content">
<span className="radio-title"></span>
<div className="style-preview">
<img src="./logo.png" className="preview-avatar" alt="对方" />
<div className="preview-group">
<div className="preview-bubble wechat">
@@ -884,11 +889,41 @@ function SettingsPage() {
张三: 那天去爬山的照片...
</div>
</div>
<img src="./logo.png" className="preview-avatar" alt="我" />
</div>
</div>
</label>
</div>
<h3 className="section-title" style={{ marginTop: '2rem' }}></h3>
<div className="quote-style-options">
<label className={`radio-label ${closeToTray ? 'active' : ''}`}>
<input
type="radio"
name="closeAction"
value="tray"
checked={closeToTray}
onChange={() => setCloseToTray(true)}
/>
<div className="radio-content">
<span className="radio-title"></span>
<span className="radio-desc"></span>
</div>
</label>
<label className={`radio-label ${!closeToTray ? 'active' : ''}`}>
<input
type="radio"
name="closeAction"
value="quit"
checked={!closeToTray}
onChange={() => setCloseToTray(false)}
/>
<div className="radio-content">
<span className="radio-title">退</span>
<span className="radio-desc">退</span>
</div>
</label>
</div>
</div>
)
+15 -1
View File
@@ -31,7 +31,8 @@ export const CONFIG_KEYS = {
AUTH_ENABLED: 'authEnabled',
AUTH_CREDENTIAL_ID: 'authCredentialId',
AUTH_PASSWORD_HASH: 'authPasswordHash',
AUTH_PASSWORD_SALT: 'authPasswordSalt'
AUTH_PASSWORD_SALT: 'authPasswordSalt',
CLOSE_TO_TRAY: 'closeToTray'
} as const
// 当前协议版本 - 更新协议内容时递增此版本号
@@ -557,3 +558,16 @@ export async function loadAiConfigPreset(id: string): Promise<AiConfigPreset | n
const presets = await getAiConfigPresets()
return presets.find(p => p.id === id) || null
}
// --- 窗口关闭行为配置 ---
// 获取关闭按钮行为(true: 最小化到托盘, false: 退出应用)
export async function getCloseToTray(): Promise<boolean> {
const value = await config.get(CONFIG_KEYS.CLOSE_TO_TRAY)
return value !== undefined ? (value as boolean) : true
}
// 设置关闭按钮行为
export async function setCloseToTray(closeToTray: boolean): Promise<void> {
await config.set(CONFIG_KEYS.CLOSE_TO_TRAY, closeToTray)
}