poi-plugin-kancolle-chs 1.3.8 → 1.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.es +4 -1
- package/package.json +1 -1
- package/src/config.es +3 -2
- package/src/constants.es +1 -1
- package/src/core/startup-checker.es +136 -0
- package/src/views/MainPanel.es +437 -41
package/index.es
CHANGED
|
@@ -3,6 +3,7 @@ import { configManager } from './src/config'
|
|
|
3
3
|
import { dataLoader } from './src/loaders/data-loader'
|
|
4
4
|
import { mainPatcher } from './src/core/main-patcher'
|
|
5
5
|
import { resourceManager } from './src/core/resource-manager'
|
|
6
|
+
import { startupChecker } from './src/core/startup-checker'
|
|
6
7
|
|
|
7
8
|
// 导出插件在 POI 中展示的界面组件
|
|
8
9
|
export const reactClass = MainPanel
|
|
@@ -31,7 +32,9 @@ export const pluginDidLoad = async () => {
|
|
|
31
32
|
await mainPatcher.buildAndDeploy()
|
|
32
33
|
}
|
|
33
34
|
|
|
34
|
-
// 4.
|
|
35
|
+
// 4. 后台静默自检:即便用户未打开插件面板,也自动检查更新并在有更新时置顶弹窗提醒
|
|
36
|
+
startupChecker.scheduleStartupCheck(2000)
|
|
37
|
+
|
|
35
38
|
console.log('[砍口垒汉化计划PLUS] 插件加载完毕,原生汉化模式已生效!')
|
|
36
39
|
} else {
|
|
37
40
|
console.log('[砍口垒汉化计划PLUS] 插件当前处于停用状态,确保环境纯净官方原版...')
|
package/package.json
CHANGED
package/src/config.es
CHANGED
|
@@ -93,8 +93,9 @@ class ConfigManager {
|
|
|
93
93
|
|
|
94
94
|
if (saved && typeof saved === 'object') {
|
|
95
95
|
this.config = { ...DEFAULT_CONFIG, ...saved }
|
|
96
|
-
|
|
97
|
-
|
|
96
|
+
// 自动保障:只要自动检查更新为开启状态,汉化资源自检与弹窗提醒同步开启
|
|
97
|
+
if (this.config.autoCheckUpdate !== false) {
|
|
98
|
+
this.config.autoCheckResourceUpdate = true
|
|
98
99
|
}
|
|
99
100
|
} else {
|
|
100
101
|
// 若首次启动且无配置,尝试全平台推荐路径初始化
|
package/src/constants.es
CHANGED
|
@@ -15,7 +15,7 @@ export const OFFICIAL_REPO_GIT = 'https://github.com/asaico/Kancolle_to_CHS.git'
|
|
|
15
15
|
export const OFFICIAL_REPO_RELEASES = 'https://github.com/asaico/Kancolle_to_CHS/releases'
|
|
16
16
|
|
|
17
17
|
// 插件版本与 npm 元信息
|
|
18
|
-
let pkgVersion = '1.
|
|
18
|
+
let pkgVersion = '1.4.2'
|
|
19
19
|
try {
|
|
20
20
|
const pkg = require('../package.json')
|
|
21
21
|
if (pkg && pkg.version) pkgVersion = pkg.version
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { configManager } from '../config'
|
|
2
|
+
import { resourceUpdater } from './resource-updater'
|
|
3
|
+
import { checkPluginUpdate } from './plugin-updater'
|
|
4
|
+
import { PLUGIN_VERSION } from '../constants'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* POI 启动自检管理器 (单例)
|
|
8
|
+
* 在后台静默检查插件本体版本 (npm) 与本地汉化资源增量 (GitHub)。
|
|
9
|
+
* 检查结果同步派发给插件面板 (MainPanel),由插件内原生的暗黑风格 Blueprint Alert 统一弹窗展示,
|
|
10
|
+
* 彻底移除侵入式的 Windows 原生白色系统对话框。
|
|
11
|
+
*/
|
|
12
|
+
class StartupChecker {
|
|
13
|
+
constructor() {
|
|
14
|
+
this.hasChecked = false
|
|
15
|
+
this.isChecking = false
|
|
16
|
+
this.lastResult = null
|
|
17
|
+
this.listeners = new Set()
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
subscribe(listener) {
|
|
21
|
+
this.listeners.add(listener)
|
|
22
|
+
return () => this.listeners.delete(listener)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
notify() {
|
|
26
|
+
for (const fn of this.listeners) {
|
|
27
|
+
try {
|
|
28
|
+
fn(this.lastResult)
|
|
29
|
+
} catch (_) {}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* 启动时异步后台静默检查 (延迟 2 秒执行,避开 POI 启动窗口与网络初始化高峰)
|
|
35
|
+
*/
|
|
36
|
+
scheduleStartupCheck(delayMs = 2000) {
|
|
37
|
+
if (this.hasChecked) return
|
|
38
|
+
setTimeout(() => {
|
|
39
|
+
this.checkOnStartup().catch((e) => {
|
|
40
|
+
console.warn('[KanCHS] 启动后台自检异常:', e)
|
|
41
|
+
})
|
|
42
|
+
}, delayMs)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* 执行启动自检逻辑
|
|
47
|
+
*/
|
|
48
|
+
async checkOnStartup() {
|
|
49
|
+
if (this.hasChecked || this.isChecking) return
|
|
50
|
+
this.isChecking = true
|
|
51
|
+
this.hasChecked = true
|
|
52
|
+
|
|
53
|
+
// 检查配置开关
|
|
54
|
+
const autoCheck = configManager.get('autoCheckUpdate', true) !== false &&
|
|
55
|
+
configManager.get('autoCheckResourceUpdate', true) !== false
|
|
56
|
+
|
|
57
|
+
if (!autoCheck) {
|
|
58
|
+
console.log('[KanCHS] 启动自检已在配置中关闭,跳过检查。')
|
|
59
|
+
this.isChecking = false
|
|
60
|
+
return
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const sourceDir = configManager.resolveSourcePath()
|
|
64
|
+
const mirrorId = configManager.get('downloadMirror', 'ghproxy')
|
|
65
|
+
|
|
66
|
+
console.log('[KanCHS] 正在后台静默检查插件与汉化资源远端更新...')
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
// 并发检查插件本体版本 (npm) 与本地汉化资源增量 (GitHub)
|
|
70
|
+
const [pluginRes, resourceRes] = await Promise.all([
|
|
71
|
+
checkPluginUpdate(PLUGIN_VERSION).catch((err) => {
|
|
72
|
+
console.warn('[KanCHS] 检查插件本体更新异常:', err.message)
|
|
73
|
+
return { hasUpdate: false, latestVersion: PLUGIN_VERSION }
|
|
74
|
+
}),
|
|
75
|
+
sourceDir
|
|
76
|
+
? resourceUpdater.checkIncrementalUpdates({ sourceDir, mirrorId }).catch((err) => {
|
|
77
|
+
console.warn('[KanCHS] 检查汉化资源增量异常:', err.message)
|
|
78
|
+
return null
|
|
79
|
+
})
|
|
80
|
+
: null,
|
|
81
|
+
])
|
|
82
|
+
|
|
83
|
+
const hasPlugin = Boolean(pluginRes && pluginRes.hasUpdate)
|
|
84
|
+
const hasResource = Boolean(
|
|
85
|
+
resourceRes &&
|
|
86
|
+
resourceRes.hasUpdate &&
|
|
87
|
+
Array.isArray(resourceRes.changedFiles) &&
|
|
88
|
+
resourceRes.changedFiles.length > 0
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
this.lastResult = {
|
|
92
|
+
pluginRes: pluginRes || { hasUpdate: false, latestVersion: PLUGIN_VERSION },
|
|
93
|
+
resourceRes,
|
|
94
|
+
hasPlugin,
|
|
95
|
+
hasResource,
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
this.notify()
|
|
99
|
+
|
|
100
|
+
if (hasPlugin || hasResource) {
|
|
101
|
+
console.log(`[KanCHS] 发现更新!插件更新: ${hasPlugin}, 资源变动: ${hasResource ? resourceRes.changedFiles.length + '项' : '无'}`)
|
|
102
|
+
this.notifyUpdateToast({
|
|
103
|
+
pluginRes: this.lastResult.pluginRes,
|
|
104
|
+
resourceRes,
|
|
105
|
+
hasPlugin,
|
|
106
|
+
hasResource,
|
|
107
|
+
})
|
|
108
|
+
} else {
|
|
109
|
+
console.log('[KanCHS] 启动自检完成:插件与汉化资源均为最新版本,保持完全静默。')
|
|
110
|
+
}
|
|
111
|
+
} catch (err) {
|
|
112
|
+
console.warn('[KanCHS] 启动检查失败:', err)
|
|
113
|
+
} finally {
|
|
114
|
+
this.isChecking = false
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* 发送 POI 系统 Toast 提示(非侵入式,完全不使用原生白色对话框)
|
|
120
|
+
*/
|
|
121
|
+
notifyUpdateToast({ pluginRes, resourceRes, hasPlugin, hasResource }) {
|
|
122
|
+
try {
|
|
123
|
+
if (typeof window !== 'undefined' && typeof window.toast === 'function') {
|
|
124
|
+
if (hasResource && hasPlugin) {
|
|
125
|
+
window.toast(`[砍口垒汉化] 发现插件 v${pluginRes.latestVersion} 及 ${resourceRes.changedFiles.length} 项资源更新,已在面板就绪!`, { type: 'warning' })
|
|
126
|
+
} else if (hasResource) {
|
|
127
|
+
window.toast(`[砍口垒汉化] 发现 ${resourceRes.changedFiles.length} 项汉化资源可更新,已在面板就绪!`, { type: 'warning' })
|
|
128
|
+
} else if (hasPlugin) {
|
|
129
|
+
window.toast(`[砍口垒汉化] 发现插件新版本 v${pluginRes.latestVersion},已在面板就绪!`, { type: 'warning' })
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
} catch (_) {}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export const startupChecker = new StartupChecker()
|
package/src/views/MainPanel.es
CHANGED
|
@@ -39,6 +39,7 @@ import {
|
|
|
39
39
|
NPM_PACKAGE_URL,
|
|
40
40
|
} from '../constants'
|
|
41
41
|
import { checkPluginUpdate } from '../core/plugin-updater'
|
|
42
|
+
import { startupChecker } from '../core/startup-checker'
|
|
42
43
|
|
|
43
44
|
export class MainPanel extends Component {
|
|
44
45
|
rootRef = React.createRef()
|
|
@@ -92,6 +93,8 @@ export class MainPanel extends Component {
|
|
|
92
93
|
showUnconfiguredAlert: false, // 启用汉化时资源包未配置提示弹窗
|
|
93
94
|
showRestartConfirm: false, // 重启 POI 客户端二次确认弹窗
|
|
94
95
|
showResourceUpdateAlert: false, // 启动或检查检测到本地汉化资源有更新提醒弹窗
|
|
96
|
+
showPluginUpdateAlert: false, // 启动或检查检测到插件本体有新版本更新提醒弹窗
|
|
97
|
+
showPostUpdateRestartAlert: false, // 资源更新完成后提示是否自动清缓存并重启弹窗
|
|
95
98
|
logs: [],
|
|
96
99
|
}
|
|
97
100
|
}
|
|
@@ -121,33 +124,78 @@ export class MainPanel extends Component {
|
|
|
121
124
|
}).catch(() => {})
|
|
122
125
|
}
|
|
123
126
|
|
|
124
|
-
//
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
127
|
+
// 监听与同步全局启动自检结果 (由 index.es 或 MainPanel 触发)
|
|
128
|
+
this.unsubStartupChecker = startupChecker.subscribe((res) => {
|
|
129
|
+
if (res) {
|
|
130
|
+
this.setState({
|
|
131
|
+
pluginUpdate: res.pluginRes || this.state.pluginUpdate,
|
|
132
|
+
resourceUpdaterStatus: {
|
|
133
|
+
...this.state.resourceUpdaterStatus,
|
|
134
|
+
hasIncrementalUpdate: res.hasResource,
|
|
135
|
+
changedFiles: res.resourceRes?.changedFiles || [],
|
|
136
|
+
},
|
|
137
|
+
showResourceUpdateAlert: res.hasResource,
|
|
138
|
+
showPluginUpdateAlert: res.hasPlugin,
|
|
139
|
+
})
|
|
140
|
+
}
|
|
141
|
+
})
|
|
133
142
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
this.
|
|
143
|
+
if (startupChecker.lastResult) {
|
|
144
|
+
const res = startupChecker.lastResult
|
|
145
|
+
this.setState({
|
|
146
|
+
pluginUpdate: res.pluginRes || this.state.pluginUpdate,
|
|
147
|
+
resourceUpdaterStatus: {
|
|
148
|
+
...this.state.resourceUpdaterStatus,
|
|
149
|
+
hasIncrementalUpdate: res.hasResource,
|
|
150
|
+
changedFiles: res.resourceRes?.changedFiles || [],
|
|
151
|
+
},
|
|
152
|
+
showResourceUpdateAlert: res.hasResource,
|
|
153
|
+
showPluginUpdateAlert: res.hasPlugin,
|
|
154
|
+
})
|
|
155
|
+
} else {
|
|
156
|
+
const shouldAutoCheck = this.state.config.autoCheckUpdate !== false
|
|
157
|
+
if (shouldAutoCheck && !startupChecker.hasChecked) {
|
|
158
|
+
startupChecker.scheduleStartupCheck(500)
|
|
159
|
+
}
|
|
137
160
|
}
|
|
138
161
|
|
|
139
162
|
// 针对旧版 POI 或特定主题外层容器修正高度与滚动上下文
|
|
140
163
|
this.fixParentScrollStyles()
|
|
164
|
+
setTimeout(this.fixParentScrollStyles, 50)
|
|
165
|
+
setTimeout(this.fixParentScrollStyles, 250)
|
|
166
|
+
|
|
167
|
+
const rootEl = this.rootRef.current
|
|
168
|
+
if (rootEl) {
|
|
169
|
+
rootEl.addEventListener('wheel', this.handleWheel, { passive: false })
|
|
170
|
+
|
|
171
|
+
const doc = rootEl.ownerDocument || document
|
|
172
|
+
const win = doc.defaultView || (typeof window !== 'undefined' ? window : null)
|
|
173
|
+
this.currentDoc = doc
|
|
174
|
+
this.currentWin = win
|
|
175
|
+
|
|
176
|
+
if (win) {
|
|
177
|
+
win.addEventListener('resize', this.handleResize)
|
|
178
|
+
if (win !== window) {
|
|
179
|
+
// 独立新窗口模式:在 window 与 document 均挂载滚轮监听,实现全屏无死角即时滚动响应
|
|
180
|
+
win.addEventListener('wheel', this.handleWheel, { passive: false })
|
|
181
|
+
doc.addEventListener('wheel', this.handleWheel, { passive: false })
|
|
182
|
+
}
|
|
183
|
+
}
|
|
141
184
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
185
|
+
// 确保进入新窗口时容器立即可获得焦点与滚动上下文
|
|
186
|
+
setTimeout(() => {
|
|
187
|
+
try {
|
|
188
|
+
rootEl.focus({ preventScroll: true })
|
|
189
|
+
} catch (_) {}
|
|
190
|
+
}, 50)
|
|
145
191
|
}
|
|
146
192
|
|
|
147
193
|
// 监听窗口与容器自适应宽度变化,实现动态窄窗紧凑排版适配
|
|
148
194
|
this.handleResize = () => {
|
|
149
195
|
if (this.rootRef && this.rootRef.current) {
|
|
150
196
|
this.setState({ containerWidth: this.rootRef.current.offsetWidth })
|
|
197
|
+
} else if (this.currentWin) {
|
|
198
|
+
this.setState({ containerWidth: this.currentWin.innerWidth })
|
|
151
199
|
} else if (typeof window !== 'undefined') {
|
|
152
200
|
this.setState({ containerWidth: window.innerWidth })
|
|
153
201
|
}
|
|
@@ -205,27 +253,65 @@ export class MainPanel extends Component {
|
|
|
205
253
|
if (this.pluginUpdateNoticeTimer) clearTimeout(this.pluginUpdateNoticeTimer)
|
|
206
254
|
if (this.unsubConfig) this.unsubConfig()
|
|
207
255
|
if (this.unsubGit) this.unsubGit()
|
|
256
|
+
if (this.unsubStartupChecker) this.unsubStartupChecker()
|
|
208
257
|
if (typeof window !== 'undefined') {
|
|
209
258
|
window.removeEventListener('resize', this.handleResize)
|
|
210
259
|
}
|
|
211
260
|
if (this.rootRef && this.rootRef.current) {
|
|
212
261
|
this.rootRef.current.removeEventListener('wheel', this.handleWheel)
|
|
213
262
|
}
|
|
263
|
+
if (this.currentWin) {
|
|
264
|
+
this.currentWin.removeEventListener('resize', this.handleResize)
|
|
265
|
+
if (this.currentWin !== window) {
|
|
266
|
+
this.currentWin.removeEventListener('wheel', this.handleWheel)
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
if (this.currentDoc && this.currentDoc !== document) {
|
|
270
|
+
this.currentDoc.removeEventListener('wheel', this.handleWheel)
|
|
271
|
+
}
|
|
214
272
|
if (this.ro) {
|
|
215
273
|
this.ro.disconnect()
|
|
216
274
|
}
|
|
217
275
|
}
|
|
218
276
|
|
|
219
277
|
/**
|
|
220
|
-
* 自动向上递归修正 POI 外层 Tab
|
|
278
|
+
* 自动向上递归修正 POI 外层 Tab 及独立新窗口容器的高度与 flex 布局,确保内层滚动条与滚轮绝对可用
|
|
221
279
|
*/
|
|
222
280
|
fixParentScrollStyles = () => {
|
|
223
281
|
try {
|
|
224
282
|
const root = this.rootRef.current
|
|
225
283
|
if (!root) return
|
|
284
|
+
|
|
285
|
+
const doc = root.ownerDocument || document
|
|
286
|
+
const win = doc.defaultView || window
|
|
287
|
+
const isDetachedWindow = (doc !== document) || (win !== window) || Boolean(doc.getElementById('plugin-mountpoint'))
|
|
288
|
+
|
|
289
|
+
// 1. 若处于独立新窗口模式,修正 html、body 及 #plugin-mountpoint 的高度与溢出策略
|
|
290
|
+
if (isDetachedWindow) {
|
|
291
|
+
if (doc.documentElement) {
|
|
292
|
+
if (doc.documentElement.style.height !== '100%') doc.documentElement.style.height = '100%'
|
|
293
|
+
if (doc.documentElement.style.overflow !== 'hidden') doc.documentElement.style.overflow = 'hidden'
|
|
294
|
+
}
|
|
295
|
+
if (doc.body) {
|
|
296
|
+
if (doc.body.style.height !== '100%') doc.body.style.height = '100%'
|
|
297
|
+
if (doc.body.style.margin !== '0px') doc.body.style.margin = '0'
|
|
298
|
+
if (doc.body.style.padding !== '0px') doc.body.style.padding = '0'
|
|
299
|
+
if (doc.body.style.overflow !== 'hidden') doc.body.style.overflow = 'hidden'
|
|
300
|
+
}
|
|
301
|
+
const mountpoint = doc.getElementById('plugin-mountpoint')
|
|
302
|
+
if (mountpoint) {
|
|
303
|
+
if (mountpoint.style.height !== '100vh') mountpoint.style.height = '100vh'
|
|
304
|
+
if (mountpoint.style.maxHeight !== '100vh') mountpoint.style.maxHeight = '100vh'
|
|
305
|
+
if (mountpoint.style.display !== 'flex') mountpoint.style.display = 'flex'
|
|
306
|
+
if (mountpoint.style.flexDirection !== 'column') mountpoint.style.flexDirection = 'column'
|
|
307
|
+
if (mountpoint.style.overflow !== 'hidden') mountpoint.style.overflow = 'hidden'
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// 2. 向上递归修正所有外层容器的高度与 flex 布局
|
|
226
312
|
let parent = root.parentElement
|
|
227
313
|
let depth = 0
|
|
228
|
-
while (parent && depth <
|
|
314
|
+
while (parent && depth < 6) {
|
|
229
315
|
const id = parent.id || ''
|
|
230
316
|
const cls = parent.className || ''
|
|
231
317
|
if (
|
|
@@ -235,9 +321,17 @@ export class MainPanel extends Component {
|
|
|
235
321
|
id.includes('poi-plugin-kancolle-chs') ||
|
|
236
322
|
id === 'plugin-mountpoint'
|
|
237
323
|
) {
|
|
238
|
-
if (
|
|
324
|
+
if (id === 'plugin-mountpoint') {
|
|
325
|
+
if (parent.style.height !== '100vh') parent.style.height = '100vh'
|
|
326
|
+
if (parent.style.maxHeight !== '100vh') parent.style.maxHeight = '100vh'
|
|
327
|
+
} else {
|
|
328
|
+
if (parent.style.height !== '100%') parent.style.height = '100%'
|
|
329
|
+
if (parent.style.maxHeight !== '100%') parent.style.maxHeight = '100%'
|
|
330
|
+
}
|
|
239
331
|
if (parent.style.display !== 'flex') parent.style.display = 'flex'
|
|
240
332
|
if (parent.style.flexDirection !== 'column') parent.style.flexDirection = 'column'
|
|
333
|
+
if (parent.style.flex !== '1 1 0px' && parent.style.flex !== '1') parent.style.flex = '1 1 0'
|
|
334
|
+
if (parent.style.minHeight !== '0px') parent.style.minHeight = '0'
|
|
241
335
|
if (parent.style.overflow !== 'hidden') parent.style.overflow = 'hidden'
|
|
242
336
|
}
|
|
243
337
|
parent = parent.parentElement
|
|
@@ -247,20 +341,50 @@ export class MainPanel extends Component {
|
|
|
247
341
|
}
|
|
248
342
|
|
|
249
343
|
/**
|
|
250
|
-
*
|
|
344
|
+
* 滚轮平滑滚动双重补偿与新窗口即时响应机制
|
|
251
345
|
*/
|
|
252
346
|
handleWheel = (e) => {
|
|
253
347
|
const container = this.rootRef.current
|
|
254
348
|
if (!container) return
|
|
255
|
-
if (container.scrollHeight <= container.clientHeight) return
|
|
256
349
|
|
|
257
|
-
//
|
|
258
|
-
const
|
|
259
|
-
|
|
260
|
-
if (
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
350
|
+
// 如果事件目标是拥有独立滚动条的子元素(如 textarea),不予干涉
|
|
351
|
+
const target = e.target
|
|
352
|
+
if (target && (target.tagName === 'TEXTAREA' || target.tagName === 'INPUT')) {
|
|
353
|
+
if (target.scrollHeight > target.clientHeight) return
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// 获取当前所属窗口(若在新窗口打开,则使用该独立窗口的 window 与 rAF)
|
|
357
|
+
const win = container.ownerDocument?.defaultView || (typeof window !== 'undefined' ? window : null)
|
|
358
|
+
const isDetachedWindow = (container.ownerDocument !== document) || (win && win !== window)
|
|
359
|
+
|
|
360
|
+
// 计算滚轮位移量
|
|
361
|
+
let delta = e.deltaY
|
|
362
|
+
if (e.deltaMode === 1) delta *= 25
|
|
363
|
+
else if (e.deltaMode === 2) delta *= container.clientHeight
|
|
364
|
+
|
|
365
|
+
if (container.scrollHeight <= container.clientHeight) {
|
|
366
|
+
// 容错重试:若尚未修正外层样式导致高度膨胀,立即修正一次
|
|
367
|
+
this.fixParentScrollStyles()
|
|
368
|
+
if (container.scrollHeight <= container.clientHeight) return
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
if (isDetachedWindow) {
|
|
372
|
+
// 独立新窗口模式:直接驱动 scrollTop 确保 100% 极速平滑滚动响应
|
|
373
|
+
container.scrollTop += delta
|
|
374
|
+
if (e.cancelable) e.preventDefault()
|
|
375
|
+
} else {
|
|
376
|
+
// 常规主窗口 Tab:双重补偿保障机制
|
|
377
|
+
const prevScrollTop = container.scrollTop
|
|
378
|
+
const rAF = (win && typeof win.requestAnimationFrame === 'function')
|
|
379
|
+
? win.requestAnimationFrame.bind(win)
|
|
380
|
+
: requestAnimationFrame
|
|
381
|
+
|
|
382
|
+
rAF(() => {
|
|
383
|
+
if (container && container.scrollTop === prevScrollTop && delta !== 0) {
|
|
384
|
+
container.scrollTop += delta
|
|
385
|
+
}
|
|
386
|
+
})
|
|
387
|
+
}
|
|
264
388
|
}
|
|
265
389
|
|
|
266
390
|
/**
|
|
@@ -510,6 +634,22 @@ export class MainPanel extends Component {
|
|
|
510
634
|
}
|
|
511
635
|
}
|
|
512
636
|
|
|
637
|
+
/**
|
|
638
|
+
* 清除游戏缓存并自动重启 POI 客户端 (更新完成后一键执行)
|
|
639
|
+
*/
|
|
640
|
+
executeClearCacheAndRestartPoi = async () => {
|
|
641
|
+
this.setState({ showPostUpdateRestartAlert: false })
|
|
642
|
+
this.addLog('正在全方位清理游戏底层缓存与会话数据...')
|
|
643
|
+
try {
|
|
644
|
+
await resourceManager.clearGameCache()
|
|
645
|
+
this.addLog('游戏缓存清理完成,即将自动重启 POI 客户端...')
|
|
646
|
+
} catch (e) {
|
|
647
|
+
console.warn('清理游戏缓存异常:', e)
|
|
648
|
+
this.addLog(`清理游戏缓存轻微异常: ${e.message},继续执行重启...`)
|
|
649
|
+
}
|
|
650
|
+
this.executeRestartPoi()
|
|
651
|
+
}
|
|
652
|
+
|
|
513
653
|
/**
|
|
514
654
|
* 点击切换总开关 (弹出二次确认弹窗,防止用户误触并支持自动清缓存刷新)
|
|
515
655
|
*/
|
|
@@ -977,6 +1117,81 @@ export class MainPanel extends Component {
|
|
|
977
1117
|
}
|
|
978
1118
|
}
|
|
979
1119
|
|
|
1120
|
+
/**
|
|
1121
|
+
* 一键检查插件和汉化资源的更新
|
|
1122
|
+
* @param {boolean} silent 是否静默检查 (后台自动检查不显示全局状态文字,但若有资源更新依旧弹窗)
|
|
1123
|
+
*/
|
|
1124
|
+
handleCheckAllUpdates = async (silent = false) => {
|
|
1125
|
+
this.setState({ isCheckingPluginUpdate: true })
|
|
1126
|
+
if (!silent) {
|
|
1127
|
+
this.setState({
|
|
1128
|
+
statusMessage: '正在一键检查插件本体与汉化资源更新...',
|
|
1129
|
+
statusIntent: Intent.PRIMARY,
|
|
1130
|
+
})
|
|
1131
|
+
this.addLog('正在一键检查插件本体(npm)与汉化资源包(GitHub)远端更新...')
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
try {
|
|
1135
|
+
// 并发执行:1. 插件 npm 版本检查 2. 汉化资源增量文件哈希比对
|
|
1136
|
+
const [pluginRes] = await Promise.all([
|
|
1137
|
+
checkPluginUpdate(PLUGIN_VERSION).catch((e) => {
|
|
1138
|
+
this.addLog(`检查插件更新失败: ${e.message}`)
|
|
1139
|
+
return { hasUpdate: false, latestVersion: PLUGIN_VERSION }
|
|
1140
|
+
}),
|
|
1141
|
+
this.handleCheckIncrementalUpdates({
|
|
1142
|
+
isAutoStartup: silent,
|
|
1143
|
+
showAlert: true,
|
|
1144
|
+
}).catch((e) => {
|
|
1145
|
+
this.addLog(`检查汉化资源更新失败: ${e.message}`)
|
|
1146
|
+
return null
|
|
1147
|
+
}),
|
|
1148
|
+
])
|
|
1149
|
+
|
|
1150
|
+
this.setState({
|
|
1151
|
+
pluginUpdate: pluginRes || { hasUpdate: false, latestVersion: PLUGIN_VERSION },
|
|
1152
|
+
isCheckingPluginUpdate: false,
|
|
1153
|
+
hidePluginUpdateNotice: false,
|
|
1154
|
+
})
|
|
1155
|
+
|
|
1156
|
+
if (pluginRes && pluginRes.hasUpdate) {
|
|
1157
|
+
this.addLog(`🎉 发现插件新版本: v${pluginRes.latestVersion} (当前已安装: v${PLUGIN_VERSION})`)
|
|
1158
|
+
this.setState({ showPluginUpdateAlert: true })
|
|
1159
|
+
if (!silent) {
|
|
1160
|
+
this.setState({
|
|
1161
|
+
statusMessage: `🎉 发现插件新版本 v${pluginRes.latestVersion}!请前往 POI「设置 - 插件」面板更新`,
|
|
1162
|
+
statusIntent: Intent.WARNING,
|
|
1163
|
+
})
|
|
1164
|
+
}
|
|
1165
|
+
} else {
|
|
1166
|
+
this.addLog(`插件本体当前已是最新版本 (v${PLUGIN_VERSION})`)
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
if (!silent) {
|
|
1170
|
+
const hasResUpdate = Boolean(
|
|
1171
|
+
this.state.resourceUpdaterStatus &&
|
|
1172
|
+
this.state.resourceUpdaterStatus.hasIncrementalUpdate &&
|
|
1173
|
+
this.state.resourceUpdaterStatus.changedFiles &&
|
|
1174
|
+
this.state.resourceUpdaterStatus.changedFiles.length > 0
|
|
1175
|
+
)
|
|
1176
|
+
if (!pluginRes?.hasUpdate && !hasResUpdate) {
|
|
1177
|
+
this.setState({
|
|
1178
|
+
statusMessage: `✅ 检查完成:插件本体与汉化资源包均为最新版本!`,
|
|
1179
|
+
statusIntent: Intent.SUCCESS,
|
|
1180
|
+
})
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
} catch (err) {
|
|
1184
|
+
this.setState({
|
|
1185
|
+
isCheckingPluginUpdate: false,
|
|
1186
|
+
statusMessage: `检查更新失败: ${err.message}`,
|
|
1187
|
+
statusIntent: Intent.DANGER,
|
|
1188
|
+
})
|
|
1189
|
+
this.addLog(`一键检查更新异常: ${err.message}`)
|
|
1190
|
+
} finally {
|
|
1191
|
+
this.setState({ isCheckingPluginUpdate: false })
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
|
|
980
1195
|
/**
|
|
981
1196
|
* 极度健壮的打开本地文件夹方法 (优先 Electron openPath,兜底 Windows explorer)
|
|
982
1197
|
*/
|
|
@@ -1240,6 +1455,7 @@ export class MainPanel extends Component {
|
|
|
1240
1455
|
isUpdating: false,
|
|
1241
1456
|
updateType: null,
|
|
1242
1457
|
},
|
|
1458
|
+
showPostUpdateRestartAlert: true,
|
|
1243
1459
|
})
|
|
1244
1460
|
await this.refreshAllStatus()
|
|
1245
1461
|
} catch (e) {
|
|
@@ -1280,12 +1496,13 @@ export class MainPanel extends Component {
|
|
|
1280
1496
|
*/
|
|
1281
1497
|
handleCheckIncrementalUpdates = async (options = {}) => {
|
|
1282
1498
|
const isAutoStartup = Boolean(options && options.isAutoStartup)
|
|
1499
|
+
const showAlert = options && options.showAlert !== undefined ? Boolean(options.showAlert) : true
|
|
1283
1500
|
const sourceDir = configManager.resolveSourcePath()
|
|
1284
1501
|
if (!sourceDir) {
|
|
1285
1502
|
if (!isAutoStartup) {
|
|
1286
1503
|
this.setState({ statusMessage: '尚未配置汉化资源包路径,请先指定或下载资源包', statusIntent: Intent.WARNING })
|
|
1287
1504
|
}
|
|
1288
|
-
return
|
|
1505
|
+
return null
|
|
1289
1506
|
}
|
|
1290
1507
|
|
|
1291
1508
|
if (!isAutoStartup) {
|
|
@@ -1307,11 +1524,11 @@ export class MainPanel extends Component {
|
|
|
1307
1524
|
hasIncrementalUpdate: true,
|
|
1308
1525
|
changedFiles: res.changedFiles,
|
|
1309
1526
|
},
|
|
1310
|
-
showResourceUpdateAlert:
|
|
1311
|
-
statusMessage:
|
|
1312
|
-
statusIntent: Intent.
|
|
1527
|
+
showResourceUpdateAlert: showAlert,
|
|
1528
|
+
statusMessage: `🎉 检测到 ${res.changedFiles.length} 个汉化资源文件可更新`,
|
|
1529
|
+
statusIntent: Intent.WARNING,
|
|
1313
1530
|
})
|
|
1314
|
-
this.addLog(
|
|
1531
|
+
this.addLog(`🎉 检测到 ${res.changedFiles.length} 个汉化资源文件与远端有差异${showAlert ? ',已弹出更新提醒窗口' : ''}`)
|
|
1315
1532
|
} else {
|
|
1316
1533
|
this.setState({
|
|
1317
1534
|
resourceUpdaterStatus: {
|
|
@@ -1326,6 +1543,7 @@ export class MainPanel extends Component {
|
|
|
1326
1543
|
this.addLog('启动自检完成:本地汉化资源已是最新版本,无变动文件')
|
|
1327
1544
|
}
|
|
1328
1545
|
}
|
|
1546
|
+
return res
|
|
1329
1547
|
} catch (e) {
|
|
1330
1548
|
if (!isAutoStartup) {
|
|
1331
1549
|
this.setState({
|
|
@@ -1334,6 +1552,7 @@ export class MainPanel extends Component {
|
|
|
1334
1552
|
})
|
|
1335
1553
|
}
|
|
1336
1554
|
this.addLog(`检查汉化资源变动失败: ${e.message}`)
|
|
1555
|
+
return null
|
|
1337
1556
|
} finally {
|
|
1338
1557
|
if (!isAutoStartup) {
|
|
1339
1558
|
this.setState({ isProcessing: false })
|
|
@@ -1383,6 +1602,7 @@ export class MainPanel extends Component {
|
|
|
1383
1602
|
},
|
|
1384
1603
|
statusMessage: '轻量化更新成功!所有变动词条已自动合流并重新部署生效',
|
|
1385
1604
|
statusIntent: Intent.SUCCESS,
|
|
1605
|
+
showPostUpdateRestartAlert: true,
|
|
1386
1606
|
})
|
|
1387
1607
|
await this.refreshAllStatus()
|
|
1388
1608
|
} catch (e) {
|
|
@@ -1701,6 +1921,8 @@ export class MainPanel extends Component {
|
|
|
1701
1921
|
showTimeoutAlert,
|
|
1702
1922
|
showRestartConfirm,
|
|
1703
1923
|
showResourceUpdateAlert,
|
|
1924
|
+
showPluginUpdateAlert,
|
|
1925
|
+
showPostUpdateRestartAlert,
|
|
1704
1926
|
logs,
|
|
1705
1927
|
} = this.state
|
|
1706
1928
|
|
|
@@ -1745,8 +1967,9 @@ export class MainPanel extends Component {
|
|
|
1745
1967
|
style={{
|
|
1746
1968
|
width: '100%',
|
|
1747
1969
|
height: '100%',
|
|
1748
|
-
minHeight:
|
|
1970
|
+
minHeight: 0,
|
|
1749
1971
|
maxHeight: '100%',
|
|
1972
|
+
flex: '1 1 0',
|
|
1750
1973
|
overflowY: 'auto',
|
|
1751
1974
|
overflowX: 'hidden',
|
|
1752
1975
|
WebkitOverflowScrolling: 'touch',
|
|
@@ -1848,22 +2071,42 @@ export class MainPanel extends Component {
|
|
|
1848
2071
|
}
|
|
1849
2072
|
}
|
|
1850
2073
|
|
|
2074
|
+
/* 新窗口与常规 Tab 模式全层级自适应滚动链保障 */
|
|
2075
|
+
html, body {
|
|
2076
|
+
height: 100% !important;
|
|
2077
|
+
overflow: hidden !important;
|
|
2078
|
+
}
|
|
2079
|
+
#plugin-mountpoint {
|
|
2080
|
+
height: 100vh !important;
|
|
2081
|
+
max-height: 100vh !important;
|
|
2082
|
+
display: flex !important;
|
|
2083
|
+
flex-direction: column !important;
|
|
2084
|
+
overflow: hidden !important;
|
|
2085
|
+
box-sizing: border-box !important;
|
|
2086
|
+
}
|
|
2087
|
+
.poi-app-tabpane,
|
|
1851
2088
|
#poi-plugin-kancolle-chs,
|
|
1852
2089
|
#poi-plugin-kancolle-chs.poi-app-tabpane,
|
|
1853
2090
|
.poi-plugin-content-poi-plugin-kancolle-chs {
|
|
1854
2091
|
height: 100% !important;
|
|
2092
|
+
max-height: 100% !important;
|
|
1855
2093
|
display: flex !important;
|
|
2094
|
+
flex: 1 1 0 !important;
|
|
2095
|
+
min-height: 0 !important;
|
|
1856
2096
|
flex-direction: column !important;
|
|
1857
2097
|
overflow: hidden !important;
|
|
2098
|
+
box-sizing: border-box !important;
|
|
1858
2099
|
}
|
|
1859
2100
|
.kancolle-chs-plus-scroll-container {
|
|
1860
2101
|
height: 100% !important;
|
|
1861
|
-
min-height:
|
|
2102
|
+
min-height: 0 !important;
|
|
1862
2103
|
max-height: 100% !important;
|
|
2104
|
+
flex: 1 1 0 !important;
|
|
1863
2105
|
overflow-y: auto !important;
|
|
1864
2106
|
overflow-x: hidden !important;
|
|
1865
2107
|
-webkit-overflow-scrolling: touch !important;
|
|
1866
2108
|
outline: none !important;
|
|
2109
|
+
box-sizing: border-box !important;
|
|
1867
2110
|
}
|
|
1868
2111
|
.kancolle-chs-plus-scroll-container::-webkit-scrollbar {
|
|
1869
2112
|
width: 8px;
|
|
@@ -1918,11 +2161,21 @@ export class MainPanel extends Component {
|
|
|
1918
2161
|
small
|
|
1919
2162
|
minimal
|
|
1920
2163
|
icon="refresh"
|
|
1921
|
-
title="
|
|
1922
|
-
text={
|
|
1923
|
-
|
|
2164
|
+
title="一键检查插件本体(npm)与汉化资源包(GitHub)更新"
|
|
2165
|
+
text={
|
|
2166
|
+
isCheckingPluginUpdate
|
|
2167
|
+
? '检查中...'
|
|
2168
|
+
: (pluginUpdate.hasUpdate && resourceUpdaterStatus.hasIncrementalUpdate)
|
|
2169
|
+
? '发现更新! (插件+资源)'
|
|
2170
|
+
: pluginUpdate.hasUpdate
|
|
2171
|
+
? `插件新版 v${pluginUpdate.latestVersion}!`
|
|
2172
|
+
: resourceUpdaterStatus.hasIncrementalUpdate
|
|
2173
|
+
? `资源可更新 (${(resourceUpdaterStatus.changedFiles || []).length})`
|
|
2174
|
+
: (isCompact ? '检查更新' : '一键检查更新')
|
|
2175
|
+
}
|
|
2176
|
+
intent={(pluginUpdate.hasUpdate || resourceUpdaterStatus.hasIncrementalUpdate) ? Intent.WARNING : Intent.NONE}
|
|
1924
2177
|
loading={isCheckingPluginUpdate}
|
|
1925
|
-
onClick={() => this.
|
|
2178
|
+
onClick={() => this.handleCheckAllUpdates(false)}
|
|
1926
2179
|
/>
|
|
1927
2180
|
<Button
|
|
1928
2181
|
small
|
|
@@ -2427,9 +2680,19 @@ export class MainPanel extends Component {
|
|
|
2427
2680
|
|
|
2428
2681
|
<div style={{ marginTop: '8px' }}>
|
|
2429
2682
|
<Switch
|
|
2430
|
-
label="
|
|
2431
|
-
checked={config.autoCheckResourceUpdate !==
|
|
2432
|
-
onChange={() =>
|
|
2683
|
+
label="每次启动 POI 时静默自动检查更新并在有更新时弹窗提示"
|
|
2684
|
+
checked={config.autoCheckResourceUpdate !== false && config.autoCheckUpdate !== false}
|
|
2685
|
+
onChange={() => {
|
|
2686
|
+
const current = config.autoCheckResourceUpdate !== false && config.autoCheckUpdate !== false
|
|
2687
|
+
configManager.update({
|
|
2688
|
+
autoCheckUpdate: !current,
|
|
2689
|
+
autoCheckResourceUpdate: !current,
|
|
2690
|
+
})
|
|
2691
|
+
this.setState({
|
|
2692
|
+
statusMessage: `已${!current ? '开启' : '关闭'}每次启动 POI 自动检查更新提醒`,
|
|
2693
|
+
statusIntent: Intent.SUCCESS,
|
|
2694
|
+
})
|
|
2695
|
+
}}
|
|
2433
2696
|
/>
|
|
2434
2697
|
</div>
|
|
2435
2698
|
</div>
|
|
@@ -3422,6 +3685,139 @@ export class MainPanel extends Component {
|
|
|
3422
3685
|
</div>
|
|
3423
3686
|
</div>
|
|
3424
3687
|
</Alert>
|
|
3688
|
+
|
|
3689
|
+
{/* 启动与一键检查发现更新时的统一提醒弹窗 (资源更新 / 插件更新 / 两者皆有) */}
|
|
3690
|
+
<Alert
|
|
3691
|
+
isOpen={showResourceUpdateAlert || showPluginUpdateAlert}
|
|
3692
|
+
cancelButtonText="稍后再说"
|
|
3693
|
+
confirmButtonText={
|
|
3694
|
+
resourceUpdaterStatus.hasIncrementalUpdate
|
|
3695
|
+
? (isCompact ? '立即更新资源' : `⚡ 立即轻量更新资源 (${(resourceUpdaterStatus.changedFiles || []).length}项)`)
|
|
3696
|
+
: '查看插件发布页'
|
|
3697
|
+
}
|
|
3698
|
+
intent={Intent.PRIMARY}
|
|
3699
|
+
icon={pluginUpdate.hasUpdate && resourceUpdaterStatus.hasIncrementalUpdate ? 'notifications' : (resourceUpdaterStatus.hasIncrementalUpdate ? 'cloud-download' : 'updated')}
|
|
3700
|
+
onCancel={() => this.setState({ showResourceUpdateAlert: false, showPluginUpdateAlert: false })}
|
|
3701
|
+
onConfirm={() => {
|
|
3702
|
+
const hasRes = resourceUpdaterStatus.hasIncrementalUpdate
|
|
3703
|
+
this.setState({ showResourceUpdateAlert: false, showPluginUpdateAlert: false })
|
|
3704
|
+
if (hasRes) {
|
|
3705
|
+
this.handleApplyIncrementalUpdates()
|
|
3706
|
+
} else {
|
|
3707
|
+
this.handleOpenExternal(pluginUpdate.npmUrl || NPM_PACKAGE_URL)
|
|
3708
|
+
}
|
|
3709
|
+
}}
|
|
3710
|
+
canOutsideClickCancel={true}
|
|
3711
|
+
canEscapeKeyCancel={true}
|
|
3712
|
+
className={isDarkTheme ? 'bp3-dark bp4-dark kancolle-chs-dark-theme' : ''}
|
|
3713
|
+
style={{ maxWidth: '540px' }}
|
|
3714
|
+
>
|
|
3715
|
+
<div style={{ lineHeight: '1.6' }}>
|
|
3716
|
+
<h5 style={{ margin: '0 0 10px 0', fontSize: '15px', fontWeight: 'bold' }}>
|
|
3717
|
+
{pluginUpdate.hasUpdate && resourceUpdaterStatus.hasIncrementalUpdate
|
|
3718
|
+
? '🎉 发现插件与汉化资源均有新更新!'
|
|
3719
|
+
: pluginUpdate.hasUpdate
|
|
3720
|
+
? '🎉 发现砍口垒汉化计划PLUS插件新版本!'
|
|
3721
|
+
: '📦 发现本地汉化资源有新更新!'}
|
|
3722
|
+
</h5>
|
|
3723
|
+
|
|
3724
|
+
{/* 插件本体更新板块 */}
|
|
3725
|
+
{pluginUpdate.hasUpdate && (
|
|
3726
|
+
<div
|
|
3727
|
+
style={{
|
|
3728
|
+
padding: '10px 12px',
|
|
3729
|
+
background: 'rgba(16, 107, 163, 0.08)',
|
|
3730
|
+
borderRadius: '6px',
|
|
3731
|
+
borderLeft: '4px solid #106ba3',
|
|
3732
|
+
marginBottom: resourceUpdaterStatus.hasIncrementalUpdate ? '12px' : '8px',
|
|
3733
|
+
}}
|
|
3734
|
+
>
|
|
3735
|
+
<div style={{ fontWeight: 'bold', fontSize: '13px', color: '#106ba3' }}>
|
|
3736
|
+
🚀 插件本体新版本: v{pluginUpdate.latestVersion}(当前已安装: v{PLUGIN_VERSION})
|
|
3737
|
+
</div>
|
|
3738
|
+
<div style={{ fontSize: '12px', color: '#444', marginTop: '4px' }}>
|
|
3739
|
+
更新方法:点击 POI 顶部菜单【设置】➔【插件】➔ 找到【砍口垒汉化计划PLUS】点击【更新】即可。
|
|
3740
|
+
</div>
|
|
3741
|
+
</div>
|
|
3742
|
+
)}
|
|
3743
|
+
|
|
3744
|
+
{/* 汉化资源更新板块 */}
|
|
3745
|
+
{resourceUpdaterStatus.hasIncrementalUpdate && (
|
|
3746
|
+
<div>
|
|
3747
|
+
<p style={{ margin: '0 0 8px 0', fontSize: '13px' }}>
|
|
3748
|
+
经比对官方汉化仓库,检测到本地有 <strong>{(resourceUpdaterStatus.changedFiles || []).length}</strong> 个汉化文件可更新:
|
|
3749
|
+
</p>
|
|
3750
|
+
{(resourceUpdaterStatus.changedFiles || []).length > 0 && (
|
|
3751
|
+
<div
|
|
3752
|
+
style={{
|
|
3753
|
+
maxHeight: '130px',
|
|
3754
|
+
overflowY: 'auto',
|
|
3755
|
+
background: 'rgba(0,0,0,0.03)',
|
|
3756
|
+
padding: '8px 10px',
|
|
3757
|
+
borderRadius: '6px',
|
|
3758
|
+
border: '1px solid rgba(0,0,0,0.08)',
|
|
3759
|
+
marginBottom: '10px',
|
|
3760
|
+
fontSize: '12px',
|
|
3761
|
+
fontFamily: 'monospace',
|
|
3762
|
+
}}
|
|
3763
|
+
>
|
|
3764
|
+
<div style={{ fontWeight: 'bold', marginBottom: '4px', color: '#0d8050' }}>变动文件列表:</div>
|
|
3765
|
+
{(resourceUpdaterStatus.changedFiles || []).slice(0, 8).map((f, idx) => (
|
|
3766
|
+
<div key={idx} style={{ whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
|
|
3767
|
+
• {typeof f === 'string' ? f : (f.path || f.file || JSON.stringify(f))}
|
|
3768
|
+
</div>
|
|
3769
|
+
))}
|
|
3770
|
+
{(resourceUpdaterStatus.changedFiles || []).length > 8 && (
|
|
3771
|
+
<div style={{ color: '#888', fontStyle: 'italic', marginTop: '2px' }}>
|
|
3772
|
+
... 等共 {(resourceUpdaterStatus.changedFiles || []).length} 个文件
|
|
3773
|
+
</div>
|
|
3774
|
+
)}
|
|
3775
|
+
</div>
|
|
3776
|
+
)}
|
|
3777
|
+
<div style={{ fontSize: '12px', color: '#666' }}>
|
|
3778
|
+
💡 推荐执行轻量增量更新,仅下载替换变动文件,耗时极短且无需重新下载完整资源包。
|
|
3779
|
+
</div>
|
|
3780
|
+
</div>
|
|
3781
|
+
)}
|
|
3782
|
+
</div>
|
|
3783
|
+
</Alert>
|
|
3784
|
+
|
|
3785
|
+
{/* 汉化资源更新完成后的清缓存并重启确认弹窗 */}
|
|
3786
|
+
<Alert
|
|
3787
|
+
isOpen={showPostUpdateRestartAlert}
|
|
3788
|
+
cancelButtonText="稍后手动重启"
|
|
3789
|
+
confirmButtonText="⚡ 清缓存并重启 POI"
|
|
3790
|
+
intent={Intent.PRIMARY}
|
|
3791
|
+
icon="refresh"
|
|
3792
|
+
onCancel={() => this.setState({ showPostUpdateRestartAlert: false })}
|
|
3793
|
+
onConfirm={this.executeClearCacheAndRestartPoi}
|
|
3794
|
+
canOutsideClickCancel={true}
|
|
3795
|
+
canEscapeKeyCancel={true}
|
|
3796
|
+
className={isDarkTheme ? 'bp3-dark bp4-dark kancolle-chs-dark-theme' : ''}
|
|
3797
|
+
style={{ maxWidth: '480px' }}
|
|
3798
|
+
>
|
|
3799
|
+
<div style={{ lineHeight: '1.6' }}>
|
|
3800
|
+
<h5 style={{ margin: '0 0 10px 0', fontSize: '15px', fontWeight: 'bold' }}>
|
|
3801
|
+
🎉 汉化资源已更新完成!
|
|
3802
|
+
</h5>
|
|
3803
|
+
<p style={{ margin: '0 0 10px 0', fontSize: '13px' }}>
|
|
3804
|
+
所有汉化资源已成功下载并自动完成合流注入。<br />
|
|
3805
|
+
是否立即<strong>自动清理游戏缓存并重启 POI</strong>,使最新资源彻底生效?
|
|
3806
|
+
</p>
|
|
3807
|
+
<div
|
|
3808
|
+
style={{
|
|
3809
|
+
fontSize: '12px',
|
|
3810
|
+
color: '#d9822b',
|
|
3811
|
+
background: 'rgba(217, 130, 43, 0.1)',
|
|
3812
|
+
padding: '8px 10px',
|
|
3813
|
+
borderRadius: '4px',
|
|
3814
|
+
borderLeft: '3px solid #d9822b',
|
|
3815
|
+
}}
|
|
3816
|
+
>
|
|
3817
|
+
<span>💡 <strong>安全建议:</strong>若当前舰队正在出击战斗中,建议点击「稍后手动重启」,待出击结束回港安全后再行重启。</span>
|
|
3818
|
+
</div>
|
|
3819
|
+
</div>
|
|
3820
|
+
</Alert>
|
|
3425
3821
|
</div>
|
|
3426
3822
|
)
|
|
3427
3823
|
}
|