0
0
Fork 0

直接更新了一万个东西

Browse Source
This commit is contained in:
yunyun 2026-06-01 12:50:47 +08:00
parent 9b3971e310
commit 61109b884a
4 changed files with 659 additions and 29 deletions

View File

@ -388,6 +388,26 @@
align-items: center; align-items: center;
gap: 10px; gap: 10px;
margin: 30px 0; margin: 30px 0;
cursor: pointer;
padding: 20px;
border-radius: 12px;
transition: background 0.2s;
}
.timer-display-container:hover {
background: #f8f9fa;
}
.timer-display-container.clickable {
cursor: pointer;
}
.timer-display-container.not-clickable {
cursor: default;
}
.timer-display-container.not-clickable:hover {
background: transparent;
} }
.timer-digit-group { .timer-digit-group {
@ -721,6 +741,219 @@
font-weight: 700; font-weight: 700;
color: #212529; color: #212529;
} }
.settings-container {
max-width: 600px;
margin: 0 auto;
}
.settings-title {
font-size: 22px;
font-weight: 700;
color: #212529;
margin-bottom: 25px;
text-align: center;
}
.settings-section {
background: #f8f9fa;
border-radius: 10px;
padding: 20px;
margin-bottom: 20px;
border: 1px solid #e9ecef;
}
.settings-section-title {
font-size: 16px;
font-weight: 600;
color: #495057;
margin-bottom: 15px;
padding-bottom: 10px;
border-bottom: 1px solid #dee2e6;
}
.settings-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 12px 0;
}
.settings-item + .settings-item {
border-top: 1px solid #e9ecef;
}
.settings-label {
font-size: 14px;
color: #495057;
}
.settings-hint {
display: block;
font-size: 12px;
color: #adb5bd;
margin-top: 2px;
font-weight: normal;
}
.settings-radio-group {
display: flex;
gap: 15px;
}
.settings-radio-item {
display: flex;
align-items: center;
gap: 6px;
cursor: pointer;
font-size: 14px;
color: #495057;
}
.settings-radio-item input[type="radio"] {
accent-color: #667eea;
width: 16px;
height: 16px;
cursor: pointer;
}
.settings-custom-input {
display: none;
align-items: center;
gap: 8px;
margin-top: 10px;
padding: 10px;
background: white;
border-radius: 8px;
}
.settings-custom-input.visible {
display: flex;
}
.settings-custom-input label {
font-size: 14px;
color: #495057;
white-space: nowrap;
}
.settings-input {
width: 100px;
padding: 8px 12px;
border: 2px solid #dee2e6;
border-radius: 6px;
font-size: 14px;
text-align: center;
transition: border-color 0.2s;
}
.settings-input:focus {
outline: none;
border-color: #667eea;
}
.settings-unit {
font-size: 14px;
color: #6c757d;
}
.toggle-switch {
position: relative;
width: 48px;
height: 26px;
cursor: pointer;
}
.toggle-switch input {
opacity: 0;
width: 0;
height: 0;
}
.toggle-slider {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: #dee2e6;
border-radius: 26px;
transition: all 0.3s;
}
.toggle-slider::before {
content: '';
position: absolute;
width: 20px;
height: 20px;
left: 3px;
bottom: 3px;
background: white;
border-radius: 50%;
transition: all 0.3s;
}
.toggle-switch input:checked + .toggle-slider {
background: #667eea;
}
.toggle-switch input:checked + .toggle-slider::before {
transform: translateX(22px);
}
.about-section {
text-align: center;
}
.about-content {
display: flex;
flex-direction: column;
align-items: center;
padding: 20px 15px;
gap: 15px;
}
.about-logo {
width: 128px;
height: 128px;
border-radius: 20px;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
}
.about-info {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
}
.about-name {
font-size: 18px;
font-weight: 600;
color: #343a40;
margin: 0;
}
.about-version {
font-size: 14px;
color: #868e96;
margin: 0;
}
.about-link {
font-size: 14px;
color: #667eea;
text-decoration: none;
padding: 8px 20px;
border: 1px solid #667eea;
border-radius: 20px;
transition: all 0.3s;
}
.about-link:hover {
background: #667eea;
color: white;
}
</style> </style>
</head> </head>
<body> <body>
@ -759,6 +992,10 @@
<span class="menu-icon">🎲</span> <span class="menu-icon">🎲</span>
<span>随机摇号</span> <span>随机摇号</span>
</li> </li>
<li class="menu-item" onclick="showPage('settings')">
<span class="menu-icon">⚙️</span>
<span>设置</span>
</li>
</ul> </ul>
</nav> </nav>
@ -777,7 +1014,7 @@
<button class="timer-tab" onclick="switchTimerMode('stopwatch')">正计时</button> <button class="timer-tab" onclick="switchTimerMode('stopwatch')">正计时</button>
</div> </div>
<div class="timer-display-container"> <div class="timer-display-container" onclick="handleTimerDisplayClick()" id="timer-display-area">
<div class="timer-digit-group"> <div class="timer-digit-group">
<div class="timer-adj-btns"> <div class="timer-adj-btns">
<button class="timer-adj-btn" onclick="adjustDigit('h-tens', 1)">+</button> <button class="timer-adj-btn" onclick="adjustDigit('h-tens', 1)">+</button>
@ -858,7 +1095,6 @@
<div class="random-controls"> <div class="random-controls">
<button class="random-btn generate" id="random-start-btn" onclick="startRandom()">开始摇号</button> <button class="random-btn generate" id="random-start-btn" onclick="startRandom()">开始摇号</button>
<button class="random-btn stop" id="random-stop-btn" onclick="stopRandom()" style="display:none;">停止</button>
</div> </div>
<div class="random-settings"> <div class="random-settings">
@ -873,9 +1109,69 @@
</div> </div>
</div> </div>
</div> </div>
<div id="page-settings" class="page">
<div class="settings-container">
<h2 class="settings-title">设置</h2>
<div class="settings-section">
<div class="settings-section-title">⏱️ 高效计时</div>
<div class="settings-item">
<span class="settings-label">默认填充的时间</span>
<div class="settings-radio-group">
<label class="settings-radio-item">
<input type="radio" name="timer-fill-mode" value="last" checked onchange="handleFillModeChange(this.value)">
来自上次设定
</label>
<label class="settings-radio-item">
<input type="radio" name="timer-fill-mode" value="custom" onchange="handleFillModeChange(this.value)">
自定义
</label>
</div>
</div>
<div class="settings-custom-input" id="custom-seconds-container">
<label>自定义倒计时默认填充时间</label>
<input type="number" class="settings-input" id="custom-seconds-input" min="1" max="86400" value="300" oninput="handleCustomSecondsChange(this.value)">
<span class="settings-unit"></span>
</div>
</div>
<div class="settings-section">
<div class="settings-section-title">🎲 随机摇号</div>
<div class="settings-item">
<span class="settings-label">跳过动画</span>
<label class="toggle-switch">
<input type="checkbox" id="skip-animation-toggle" onchange="handleSkipAnimationChange(this.checked)">
<span class="toggle-slider"></span>
</label>
</div>
<div class="settings-item">
<span class="settings-label">智能匹配
<span class="settings-hint">避免重复抽中同一号码</span>
</span>
<label class="toggle-switch">
<input type="checkbox" id="smart-match-toggle" onchange="handleSmartMatchChange(this.checked)">
<span class="toggle-slider"></span>
</label>
</div>
</div>
<div class="settings-section about-section">
<div class="settings-section-title">关于</div>
<div class="about-content">
<img src="assets/icon.ico" alt="Logo" class="about-logo">
<div class="about-info">
<h3 class="about-name">课堂小助手 Classroom Assistant</h3>
<p class="about-version" id="about-version"></p>
<a href="#" class="about-link" onclick="openSourceCode(event)">源代码</a>
</div>
</div>
</div>
</div>
</div>
<div class="version-info"> <div class="version-info">
<p id="version-info">课堂小助手 v1.0.0 | 支持Windows 7及以上系统</p> <p id="version-info">课堂小助手 Copyrights 2026 Yunyun By CaelLab</p>
</div> </div>
</main> </main>
</div> </div>
@ -919,6 +1215,7 @@
function updateTimerButtonsVisibility() { function updateTimerButtonsVisibility() {
const btns = document.querySelectorAll('.timer-adj-btn') const btns = document.querySelectorAll('.timer-adj-btn')
const digitBtns = document.querySelectorAll('.timer-digit-btn') const digitBtns = document.querySelectorAll('.timer-digit-btn')
const displayArea = document.getElementById('timer-display-area')
const isActive = isTimerRunning || isTimerPaused const isActive = isTimerRunning || isTimerPaused
const hideAdj = isActive || timerMode === 'stopwatch' const hideAdj = isActive || timerMode === 'stopwatch'
btns.forEach(b => b.style.visibility = hideAdj ? 'hidden' : 'visible') btns.forEach(b => b.style.visibility = hideAdj ? 'hidden' : 'visible')
@ -938,6 +1235,15 @@
t.style.opacity = isActive ? '0.5' : '1' t.style.opacity = isActive ? '0.5' : '1'
t.style.pointerEvents = isActive ? 'none' : 'auto' t.style.pointerEvents = isActive ? 'none' : 'auto'
}) })
if (displayArea) {
if (isActive) {
displayArea.classList.remove('not-clickable')
displayArea.classList.add('clickable')
} else {
displayArea.classList.remove('clickable')
displayArea.classList.add('not-clickable')
}
}
} }
function adjustDigit(id, delta) { function adjustDigit(id, delta) {
@ -990,8 +1296,18 @@
async function loadTimeLastSeconds() { async function loadTimeLastSeconds() {
if (window.electronAPI) { if (window.electronAPI) {
const seconds = await window.electronAPI.getTimeLastSeconds() try {
setTimerDigits(seconds) const fillMode = await window.electronAPI.getTimeFillMode()
let seconds
if (fillMode === 'custom') {
seconds = await window.electronAPI.getTimeCustomSeconds()
} else {
seconds = await window.electronAPI.getTimeLastSeconds()
}
setTimerDigits(seconds)
} catch (error) {
console.log('加载计时器记忆失败:', error)
}
} }
} }
@ -1065,6 +1381,13 @@
updateTimerButtonsVisibility() updateTimerButtonsVisibility()
} }
function handleTimerDisplayClick() {
const isActive = isTimerRunning || isTimerPaused
if (isActive) {
openFullscreen()
}
}
let fullscreenInterval = null let fullscreenInterval = null
let wasMaximizedBeforeFullscreen = false let wasMaximizedBeforeFullscreen = false
@ -1104,9 +1427,11 @@
document.getElementById('fs-s').textContent = s document.getElementById('fs-s').textContent = s
} }
let randomInterval = null
let isRandomRunning = false let isRandomRunning = false
let randomMax = 75 let randomMax = 75
let randomTimeout = null
let skipAnimation = false
let smartMatch = true
async function loadRandomMax() { async function loadRandomMax() {
if (window.electronAPI) { if (window.electronAPI) {
@ -1117,30 +1442,53 @@
} }
async function adjustRandomMax(delta) { async function adjustRandomMax(delta) {
if (isRandomRunning) return
randomMax = Math.max(1, randomMax + delta) randomMax = Math.max(1, randomMax + delta)
document.getElementById('random-max-display').textContent = randomMax document.getElementById('random-max-display').textContent = randomMax
if (window.electronAPI) { if (window.electronAPI) {
await window.electronAPI.setRandomMaxNumber(randomMax) await window.electronAPI.setRandomMaxNumber(randomMax)
await window.electronAPI.resetSmartMatchWeights()
} }
} }
function startRandom() { async function startRandom() {
if (isRandomRunning) return if (isRandomRunning) return
isRandomRunning = true isRandomRunning = true
document.getElementById('random-start-btn').style.display = 'none' document.getElementById('random-start-btn').disabled = true
document.getElementById('random-stop-btn').style.display = 'inline-block' document.getElementById('random-start-btn').style.opacity = '0.5'
document.getElementById('random-display').style.color = '#667eea'
randomInterval = setInterval(() => { let finalNum
const num = Math.floor(Math.random() * randomMax) + 1 if (smartMatch && window.electronAPI) {
document.getElementById('random-display').textContent = num finalNum = await window.electronAPI.pickWeightedRandom()
}, 50) } else {
finalNum = Math.floor(Math.random() * randomMax) + 1
}
if (skipAnimation) {
document.getElementById('random-display').textContent = finalNum
isRandomRunning = false
document.getElementById('random-start-btn').disabled = false
document.getElementById('random-start-btn').style.opacity = '1'
} else {
rollRandom(25, 0, finalNum)
}
} }
function stopRandom() { function rollRandom(delay, count, finalNum) {
isRandomRunning = false const num = Math.floor(Math.random() * randomMax) + 1
clearInterval(randomInterval) document.getElementById('random-display').textContent = num
document.getElementById('random-start-btn').style.display = 'inline-block'
document.getElementById('random-stop-btn').style.display = 'none' const maxRolls = 15 + Math.floor(Math.random() * 8)
const newDelay = count > maxRolls * 0.5 ? delay * 1.12 : delay
if (newDelay < 350) {
randomTimeout = setTimeout(() => rollRandom(newDelay, count + 1, finalNum), newDelay)
} else {
document.getElementById('random-display').textContent = finalNum
isRandomRunning = false
document.getElementById('random-start-btn').disabled = false
document.getElementById('random-start-btn').style.opacity = '1'
document.getElementById('random-display').style.color = '#667eea'
}
} }
async function loadAppInfo() { async function loadAppInfo() {
@ -1149,17 +1497,88 @@
const version = await window.electronAPI.getAppVersion() const version = await window.electronAPI.getAppVersion()
const appName = await window.electronAPI.getAppName() const appName = await window.electronAPI.getAppName()
document.getElementById('version-info').textContent = document.getElementById('version-info').textContent =
appName + ' v' + version + ' | 支持Windows 7及以上系统' appName + ' v' + version + ' | Copyrights 2026 Yunyun By CaelLab'
document.getElementById('about-version').textContent = 'v' + version
} }
} catch (error) { } catch (error) {
console.log('无法获取应用信息:', error) console.log('无法获取应用信息:', error)
} }
} }
document.addEventListener('DOMContentLoaded', () => { function handleFillModeChange(mode) {
const container = document.getElementById('custom-seconds-container')
if (mode === 'custom') {
container.classList.add('visible')
} else {
container.classList.remove('visible')
}
if (window.electronAPI) {
window.electronAPI.setTimeFillMode(mode)
}
}
let customSecondsDebounce = null
function handleCustomSecondsChange(value) {
clearTimeout(customSecondsDebounce)
customSecondsDebounce = setTimeout(() => {
const seconds = Math.max(1, Math.min(86400, parseInt(value) || 300))
if (window.electronAPI) {
window.electronAPI.setTimeCustomSeconds(seconds)
}
}, 500)
}
function handleSkipAnimationChange(checked) {
skipAnimation = checked
if (window.electronAPI) {
window.electronAPI.setRandomSkipAnimation(checked)
}
}
function handleSmartMatchChange(checked) {
smartMatch = checked
if (window.electronAPI) {
window.electronAPI.setSmartMatch(checked)
if (checked) {
window.electronAPI.resetSmartMatchWeights()
}
}
}
async function loadSettings() {
if (window.electronAPI) {
const fillMode = await window.electronAPI.getTimeFillMode()
const radios = document.querySelectorAll('input[name="timer-fill-mode"]')
radios.forEach(radio => {
radio.checked = radio.value === fillMode
})
if (fillMode === 'custom') {
document.getElementById('custom-seconds-container').classList.add('visible')
}
const customSeconds = await window.electronAPI.getTimeCustomSeconds()
document.getElementById('custom-seconds-input').value = customSeconds
skipAnimation = await window.electronAPI.getRandomSkipAnimation()
document.getElementById('skip-animation-toggle').checked = skipAnimation
smartMatch = await window.electronAPI.getSmartMatch()
document.getElementById('smart-match-toggle').checked = smartMatch
}
}
function openSourceCode(e) {
e.preventDefault()
if (window.electronAPI) {
window.electronAPI.openExternalUrl('https://git.caellab.com/yunyun/Classroom-Assistant')
}
}
document.addEventListener('DOMContentLoaded', async () => {
loadAppInfo() loadAppInfo()
loadRandomMax() loadRandomMax()
loadTimeLastSeconds() await loadTimeLastSeconds()
loadSettings()
}) })
</script> </script>
</body> </body>

204
main.js
View File

@ -1,4 +1,4 @@
const { app, BrowserWindow, ipcMain } = require('electron') const { app, BrowserWindow, ipcMain, shell } = require('electron')
const path = require('path') const path = require('path')
const fs = require('fs') const fs = require('fs')
const ini = require('ini') const ini = require('ini')
@ -11,8 +11,13 @@ if (process.platform === 'win32') {
let mainWindow let mainWindow
const configDir = path.join(app.getPath('appData'), 'classroom-assistant', 'ca') const portableDir = process.env.PORTABLE_EXECUTABLE_DIR
const configDir = portableDir
? path.join(portableDir, 'data')
: path.join(app.getPath('appData'), 'classroom-assistant', 'ca')
const configPath = path.join(configDir, 'memory.ini') const configPath = path.join(configDir, 'memory.ini')
const settingsPath = path.join(configDir, 'setting.ini')
const goodRandomPath = path.join(configDir, 'goodrandom.json')
const defaultConfig = { const defaultConfig = {
Random: { Random: {
@ -23,6 +28,17 @@ const defaultConfig = {
} }
} }
const defaultSettings = {
Timer: {
FillMode: 'last',
CustomSeconds: 300
},
Random: {
SkipAnimation: false,
SmartMatch: true
}
}
function ensureConfigDir() { function ensureConfigDir() {
if (!fs.existsSync(configDir)) { if (!fs.existsSync(configDir)) {
fs.mkdirSync(configDir, { recursive: true }) fs.mkdirSync(configDir, { recursive: true })
@ -38,11 +54,15 @@ function loadConfig() {
try { try {
const content = fs.readFileSync(configPath, 'utf-8') const content = fs.readFileSync(configPath, 'utf-8')
const config = ini.parse(content) const config = ini.parse(content)
if (!config.Random || typeof config.Random.MaxNumber !== 'number') { if (!config.Random) {
config.Random = defaultConfig.Random config.Random = defaultConfig.Random
} else {
config.Random.MaxNumber = parseInt(config.Random.MaxNumber) || defaultConfig.Random.MaxNumber
} }
if (!config.Time || typeof config.Time.LastSeconds !== 'number') { if (!config.Time) {
config.Time = defaultConfig.Time config.Time = defaultConfig.Time
} else {
config.Time.LastSeconds = parseInt(config.Time.LastSeconds) || defaultConfig.Time.LastSeconds
} }
saveConfig(config) saveConfig(config)
return config return config
@ -57,6 +77,88 @@ function saveConfig(config) {
fs.writeFileSync(configPath, ini.stringify(config), 'utf-8') fs.writeFileSync(configPath, ini.stringify(config), 'utf-8')
} }
function loadSettings() {
ensureConfigDir()
if (!fs.existsSync(settingsPath)) {
saveSettings(defaultSettings)
return defaultSettings
}
try {
const content = fs.readFileSync(settingsPath, 'utf-8')
const settings = ini.parse(content)
if (!settings.Timer) {
settings.Timer = defaultSettings.Timer
} else {
settings.Timer.FillMode = settings.Timer.FillMode || 'last'
settings.Timer.CustomSeconds = parseInt(settings.Timer.CustomSeconds) || defaultSettings.Timer.CustomSeconds
}
if (!settings.Random) {
settings.Random = defaultSettings.Random
} else {
settings.Random.SkipAnimation = settings.Random.SkipAnimation === 'true' || settings.Random.SkipAnimation === true
settings.Random.SmartMatch = settings.Random.SmartMatch === 'true' || settings.Random.SmartMatch === true || settings.Random.SmartMatch === undefined
}
return settings
} catch (e) {
saveSettings(defaultSettings)
return defaultSettings
}
}
function saveSettings(settings) {
ensureConfigDir()
fs.writeFileSync(settingsPath, ini.stringify(settings), 'utf-8')
}
function generateWeights(maxNumber) {
const weights = {}
const base = maxNumber
for (let i = 1; i <= maxNumber; i++) {
weights[i] = parseFloat(base.toFixed(3))
}
return weights
}
function loadGoodRandom() {
ensureConfigDir()
if (!fs.existsSync(goodRandomPath)) {
const config = loadConfig()
const maxNumber = config.Random.MaxNumber
const data = {
maxNumber: maxNumber,
weights: generateWeights(maxNumber)
}
saveGoodRandom(data)
return data
}
try {
const content = fs.readFileSync(goodRandomPath, 'utf-8')
const data = JSON.parse(content)
const config = loadConfig()
const currentMax = config.Random.MaxNumber
if (data.maxNumber !== currentMax) {
data.maxNumber = currentMax
data.weights = generateWeights(currentMax)
saveGoodRandom(data)
}
return data
} catch (e) {
const config = loadConfig()
const maxNumber = config.Random.MaxNumber
const data = {
maxNumber: maxNumber,
weights: generateWeights(maxNumber)
}
saveGoodRandom(data)
return data
}
}
function saveGoodRandom(data) {
ensureConfigDir()
fs.writeFileSync(goodRandomPath, JSON.stringify(data, null, 2), 'utf-8')
}
function createWindow() { function createWindow() {
mainWindow = new BrowserWindow({ mainWindow = new BrowserWindow({
width: 1000, width: 1000,
@ -181,4 +283,98 @@ ipcMain.handle('set-time-last-seconds', (event, seconds) => {
config.Time.LastSeconds = seconds config.Time.LastSeconds = seconds
saveConfig(config) saveConfig(config)
return true return true
})
ipcMain.handle('get-time-fill-mode', () => {
const settings = loadSettings()
return settings.Timer.FillMode
})
ipcMain.handle('set-time-fill-mode', (event, mode) => {
const settings = loadSettings()
settings.Timer.FillMode = mode
saveSettings(settings)
return true
})
ipcMain.handle('get-time-custom-seconds', () => {
const settings = loadSettings()
return settings.Timer.CustomSeconds
})
ipcMain.handle('set-time-custom-seconds', (event, seconds) => {
const settings = loadSettings()
settings.Timer.CustomSeconds = seconds
saveSettings(settings)
return true
})
ipcMain.handle('get-random-skip-animation', () => {
const settings = loadSettings()
return settings.Random.SkipAnimation
})
ipcMain.handle('set-random-skip-animation', (event, skip) => {
const settings = loadSettings()
settings.Random.SkipAnimation = skip
saveSettings(settings)
return true
})
ipcMain.handle('get-smart-match', () => {
const settings = loadSettings()
return settings.Random.SmartMatch
})
ipcMain.handle('set-smart-match', (event, enabled) => {
const settings = loadSettings()
settings.Random.SmartMatch = enabled
saveSettings(settings)
return true
})
ipcMain.handle('pick-weighted-random', () => {
const data = loadGoodRandom()
const maxNumber = data.maxNumber
const fixedWeight = parseFloat((maxNumber * 0.3).toFixed(3))
const effectiveWeights = {}
let totalWeight = 0
for (let i = 1; i <= maxNumber; i++) {
effectiveWeights[i] = Math.round(data.weights[i]) ** 2 + fixedWeight
totalWeight += effectiveWeights[i]
}
let rand = Math.random() * totalWeight
let picked = 1
for (let i = 1; i <= maxNumber; i++) {
rand -= effectiveWeights[i]
if (rand <= 0) {
picked = i
break
}
}
for (let i = 1; i <= maxNumber; i++) {
if (i === picked) {
data.weights[i] = 0.5
} else {
data.weights[i] = parseFloat(Math.min(data.weights[i] + 1, maxNumber).toFixed(3))
}
}
saveGoodRandom(data)
return picked
})
ipcMain.handle('reset-smart-match-weights', () => {
const config = loadConfig()
const maxNumber = config.Random.MaxNumber
const data = {
maxNumber: maxNumber,
weights: generateWeights(maxNumber)
}
saveGoodRandom(data)
return true
})
ipcMain.handle('open-external-url', (event, url) => {
shell.openExternal(url)
return true
}) })

View File

@ -7,7 +7,8 @@
"start": "electron .", "start": "electron .",
"build": "electron-builder", "build": "electron-builder",
"build:win": "electron-builder --win", "build:win": "electron-builder --win",
"build:win7": "electron-builder --win --config.win.target=nsis" "build:win7": "electron-builder --win --config.win.target=nsis",
"build:portable": "electron-builder --win portable --config.win.target=portable"
}, },
"keywords": [ "keywords": [
"electron", "electron",
@ -46,6 +47,9 @@
"createDesktopShortcut": true, "createDesktopShortcut": true,
"createStartMenuShortcut": true, "createStartMenuShortcut": true,
"shortcutName": "课堂小助手" "shortcutName": "课堂小助手"
},
"portable": {
"artifactName": "课堂小助手-${version}-便携版.exe"
} }
}, },
"dependencies": { "dependencies": {

View File

@ -20,5 +20,16 @@ contextBridge.exposeInMainWorld('electronAPI', {
getRandomMaxNumber: () => ipcRenderer.invoke('get-random-max-number'), getRandomMaxNumber: () => ipcRenderer.invoke('get-random-max-number'),
setRandomMaxNumber: (maxNumber) => ipcRenderer.invoke('set-random-max-number', maxNumber), setRandomMaxNumber: (maxNumber) => ipcRenderer.invoke('set-random-max-number', maxNumber),
getTimeLastSeconds: () => ipcRenderer.invoke('get-time-last-seconds'), getTimeLastSeconds: () => ipcRenderer.invoke('get-time-last-seconds'),
setTimeLastSeconds: (seconds) => ipcRenderer.invoke('set-time-last-seconds', seconds) setTimeLastSeconds: (seconds) => ipcRenderer.invoke('set-time-last-seconds', seconds),
getTimeFillMode: () => ipcRenderer.invoke('get-time-fill-mode'),
setTimeFillMode: (mode) => ipcRenderer.invoke('set-time-fill-mode', mode),
getTimeCustomSeconds: () => ipcRenderer.invoke('get-time-custom-seconds'),
setTimeCustomSeconds: (seconds) => ipcRenderer.invoke('set-time-custom-seconds', seconds),
getRandomSkipAnimation: () => ipcRenderer.invoke('get-random-skip-animation'),
setRandomSkipAnimation: (skip) => ipcRenderer.invoke('set-random-skip-animation', skip),
getSmartMatch: () => ipcRenderer.invoke('get-smart-match'),
setSmartMatch: (enabled) => ipcRenderer.invoke('set-smart-match', enabled),
pickWeightedRandom: () => ipcRenderer.invoke('pick-weighted-random'),
resetSmartMatchWeights: () => ipcRenderer.invoke('reset-smart-match-weights'),
openExternalUrl: (url) => ipcRenderer.invoke('open-external-url', url)
}) })