support disable config
This commit is contained in:
@@ -31,8 +31,12 @@ pub struct InstallTask {
|
|||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub use_manifest: bool,
|
pub use_manifest: bool,
|
||||||
pub manifest_url: Option<String>,
|
pub manifest_url: Option<String>,
|
||||||
|
#[serde(default = "default_true")]
|
||||||
|
pub enable_post_install: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn default_true() -> bool { true }
|
||||||
|
|
||||||
impl Default for AppSettings {
|
impl Default for AppSettings {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
@@ -116,7 +120,6 @@ async fn sync_essentials(app: AppHandle) -> Result<bool, String> {
|
|||||||
Ok(response) => {
|
Ok(response) => {
|
||||||
if response.status().is_success() {
|
if response.status().is_success() {
|
||||||
let content = response.text().await.map_err(|e| e.to_string())?;
|
let content = response.text().await.map_err(|e| e.to_string())?;
|
||||||
// 验证 JSON 格式(新格式:{ version: string, essentials: Vec<Software> })
|
|
||||||
let validation: Result<EssentialsRepo, _> = serde_json::from_str(&content);
|
let validation: Result<EssentialsRepo, _> = serde_json::from_str(&content);
|
||||||
if validation.is_ok() {
|
if validation.is_ok() {
|
||||||
let path = get_essentials_path(&app);
|
let path = get_essentials_path(&app);
|
||||||
@@ -194,11 +197,9 @@ fn expand_win_path(path: &str) -> PathBuf {
|
|||||||
];
|
];
|
||||||
|
|
||||||
for var in env_vars {
|
for var in env_vars {
|
||||||
// 创建不区分大小写的正则表达式,匹配 %VAR%
|
|
||||||
let re = Regex::new(&format!(r"(?i)%{}%", var)).unwrap();
|
let re = Regex::new(&format!(r"(?i)%{}%", var)).unwrap();
|
||||||
if re.is_match(&expanded) {
|
if re.is_match(&expanded) {
|
||||||
if let Ok(val) = std::env::var(var) {
|
if let Ok(val) = std::env::var(var) {
|
||||||
// 使用正则表达式替换所有匹配项
|
|
||||||
expanded = re.replace_all(&expanded, val.as_str()).to_string();
|
expanded = re.replace_all(&expanded, val.as_str()).to_string();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -211,7 +212,6 @@ async fn execute_post_install(handle: &AppHandle, log_id: &str, steps: Vec<PostI
|
|||||||
for (i, step) in steps.into_iter().enumerate() {
|
for (i, step) in steps.into_iter().enumerate() {
|
||||||
let step_prefix = format!("Step {}/{}: ", i + 1, steps_len);
|
let step_prefix = format!("Step {}/{}: ", i + 1, steps_len);
|
||||||
|
|
||||||
// 预先提取延迟时间
|
|
||||||
let delay = match &step {
|
let delay = match &step {
|
||||||
PostInstallStep::RegistryBatch { delay_ms, .. } => *delay_ms,
|
PostInstallStep::RegistryBatch { delay_ms, .. } => *delay_ms,
|
||||||
PostInstallStep::FileCopy { delay_ms, .. } => *delay_ms,
|
PostInstallStep::FileCopy { delay_ms, .. } => *delay_ms,
|
||||||
@@ -335,7 +335,6 @@ async fn execute_post_install(handle: &AppHandle, log_id: &str, steps: Vec<PostI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果设置了延迟,执行异步等待
|
|
||||||
if let Some(ms) = delay {
|
if let Some(ms) = delay {
|
||||||
if ms > 0 {
|
if ms > 0 {
|
||||||
emit_log(handle, log_id, "Post-Install", &format!("Waiting for {}ms...", ms), "info");
|
emit_log(handle, log_id, "Post-Install", &format!("Waiting for {}ms...", ms), "info");
|
||||||
@@ -370,6 +369,7 @@ pub fn run() {
|
|||||||
let task_version = task.version.clone();
|
let task_version = task.version.clone();
|
||||||
let use_manifest = task.use_manifest;
|
let use_manifest = task.use_manifest;
|
||||||
let manifest_url = task.manifest_url.clone();
|
let manifest_url = task.manifest_url.clone();
|
||||||
|
let enable_post_install_flag = task.enable_post_install;
|
||||||
|
|
||||||
let log_id = format!("install-{}", task_id);
|
let log_id = format!("install-{}", task_id);
|
||||||
|
|
||||||
@@ -494,7 +494,7 @@ pub fn run() {
|
|||||||
let exit_status = child_proc.wait().map(|s| s.success()).unwrap_or(false);
|
let exit_status = child_proc.wait().map(|s| s.success()).unwrap_or(false);
|
||||||
let status_result = if exit_status { "success" } else { "error" };
|
let status_result = if exit_status { "success" } else { "error" };
|
||||||
|
|
||||||
if status_result == "success" {
|
if status_result == "success" && enable_post_install_flag {
|
||||||
let essentials = get_essentials(handle.clone());
|
let essentials = get_essentials(handle.clone());
|
||||||
let software_info = essentials.and_then(|repo| {
|
let software_info = essentials.and_then(|repo| {
|
||||||
repo.essentials.into_iter().find(|s| s.id == task_id)
|
repo.essentials.into_iter().find(|s| s.id == task_id)
|
||||||
|
|||||||
@@ -35,7 +35,6 @@
|
|||||||
<span class="id-badge">{{ software.id }}</span>
|
<span class="id-badge">{{ software.id }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="version-info">
|
<div class="version-info">
|
||||||
<!-- 情况 1: 已安装且有推荐/最新版本 -->
|
|
||||||
<template v-if="software.version">
|
<template v-if="software.version">
|
||||||
<span class="version-tag">当前: {{ software.version }}</span>
|
<span class="version-tag">当前: {{ software.version }}</span>
|
||||||
<span v-if="software.recommended_version && software.actionLabel === '更新'" class="version-tag recommended">
|
<span v-if="software.recommended_version && software.actionLabel === '更新'" class="version-tag recommended">
|
||||||
@@ -46,7 +45,6 @@
|
|||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- 情况 2: 未安装 -->
|
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<span v-if="software.recommended_version" class="version-tag recommended">
|
<span v-if="software.recommended_version" class="version-tag recommended">
|
||||||
推荐: {{ software.recommended_version }}
|
推荐: {{ software.recommended_version }}
|
||||||
@@ -64,6 +62,19 @@
|
|||||||
|
|
||||||
<div class="card-right" v-if="actionLabel || software.status !== 'idle'">
|
<div class="card-right" v-if="actionLabel || software.status !== 'idle'">
|
||||||
<div class="action-wrapper">
|
<div class="action-wrapper">
|
||||||
|
<!-- 后安装配置开关 -->
|
||||||
|
<div
|
||||||
|
v-if="software.status === 'idle' && (software.post_install || software.post_install_url)"
|
||||||
|
class="post-install-toggle"
|
||||||
|
@click.stop="$emit('togglePostInstall', software.id)"
|
||||||
|
:title="software.enablePostInstall ? '已开启安装后自动配置' : '已关闭安装后自动配置'"
|
||||||
|
>
|
||||||
|
<span class="toggle-label">自动配置</span>
|
||||||
|
<div class="toggle-switch" :class="{ 'is-active': software.enablePostInstall }">
|
||||||
|
<div class="toggle-dot"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
v-if="software.status === 'idle'"
|
v-if="software.status === 'idle'"
|
||||||
@click.stop="$emit('install', software.id, (software as any).targetVersion)"
|
@click.stop="$emit('install', software.id, (software as any).targetVersion)"
|
||||||
@@ -81,18 +92,15 @@
|
|||||||
已安装
|
已安装
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<!-- 等待中状态 -->
|
|
||||||
<div v-else-if="software.status === 'pending'" class="status-pending">
|
<div v-else-if="software.status === 'pending'" class="status-pending">
|
||||||
<span class="wait-text">等待中</span>
|
<span class="wait-text">等待中</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 配置中状态 -->
|
|
||||||
<div v-else-if="software.status === 'configuring'" class="status-configuring">
|
<div v-else-if="software.status === 'configuring'" class="status-configuring">
|
||||||
<div class="mini-spinner"></div>
|
<div class="mini-spinner"></div>
|
||||||
<span class="config-text">正在配置...</span>
|
<span class="config-text">正在配置...</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 安装中状态:显示进度环和百分比 -->
|
|
||||||
<div v-else-if="software.status === 'installing'" class="progress-status">
|
<div v-else-if="software.status === 'installing'" class="progress-status">
|
||||||
<div class="progress-ring-container">
|
<div class="progress-ring-container">
|
||||||
<svg viewBox="0 0 32 32" class="ring-svg">
|
<svg viewBox="0 0 32 32" class="ring-svg">
|
||||||
@@ -139,6 +147,9 @@ const props = defineProps<{
|
|||||||
progress: number;
|
progress: number;
|
||||||
actionLabel?: string;
|
actionLabel?: string;
|
||||||
targetVersion?: string;
|
targetVersion?: string;
|
||||||
|
post_install?: any;
|
||||||
|
post_install_url?: string;
|
||||||
|
enablePostInstall?: boolean;
|
||||||
},
|
},
|
||||||
actionLabel?: string,
|
actionLabel?: string,
|
||||||
selectable?: boolean,
|
selectable?: boolean,
|
||||||
@@ -146,7 +157,7 @@ const props = defineProps<{
|
|||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const emit = defineEmits(['install', 'toggleSelect']);
|
const emit = defineEmits(['install', 'toggleSelect', 'togglePostInstall']);
|
||||||
|
|
||||||
const displayProgress = computed(() => {
|
const displayProgress = computed(() => {
|
||||||
if (!props.software.progress) return '准备中';
|
if (!props.software.progress) return '准备中';
|
||||||
@@ -294,17 +305,6 @@ const handleCardClick = () => {
|
|||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
.description {
|
|
||||||
font-size: 13px;
|
|
||||||
color: var(--text-sec);
|
|
||||||
line-height: 1.4;
|
|
||||||
display: -webkit-box;
|
|
||||||
-webkit-line-clamp: 1;
|
|
||||||
-webkit-box-orient: vertical;
|
|
||||||
overflow: hidden;
|
|
||||||
max-width: 500px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.version-info {
|
.version-info {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
@@ -326,10 +326,64 @@ const handleCardClick = () => {
|
|||||||
.card-right {
|
.card-right {
|
||||||
margin-left: 20px;
|
margin-left: 20px;
|
||||||
min-width: 100px;
|
min-width: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 16px;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.post-install-toggle {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 4px 8px;
|
||||||
|
border-radius: 8px;
|
||||||
|
transition: background-color 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-install-toggle:hover {
|
||||||
|
background-color: rgba(0, 0, 0, 0.03);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-label {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--text-sec);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-switch {
|
||||||
|
width: 32px;
|
||||||
|
height: 18px;
|
||||||
|
background-color: #E5E5EA;
|
||||||
|
border-radius: 9px;
|
||||||
|
position: relative;
|
||||||
|
transition: background-color 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-switch.is-active {
|
||||||
|
background-color: #34C759;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-dot {
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
background-color: white;
|
||||||
|
border-radius: 50%;
|
||||||
|
position: absolute;
|
||||||
|
top: 2px;
|
||||||
|
left: 2px;
|
||||||
|
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
||||||
|
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-switch.is-active .toggle-dot {
|
||||||
|
transform: translateX(14px);
|
||||||
|
}
|
||||||
|
|
||||||
.action-btn {
|
.action-btn {
|
||||||
width: 90px;
|
width: 90px;
|
||||||
height: 34px;
|
height: 34px;
|
||||||
|
|||||||
@@ -47,7 +47,8 @@ export const useSoftwareStore = defineStore('software', {
|
|||||||
initStatus: '正在检查系统环境...',
|
initStatus: '正在检查系统环境...',
|
||||||
lastFetched: 0,
|
lastFetched: 0,
|
||||||
refreshTimer: null as any,
|
refreshTimer: null as any,
|
||||||
batchQueue: [] as string[]
|
batchQueue: [] as string[],
|
||||||
|
postInstallPrefs: {} as Record<string, boolean> // 记录用户对每个软件后安装配置的偏好
|
||||||
}),
|
}),
|
||||||
getters: {
|
getters: {
|
||||||
mergedEssentials: (state) => {
|
mergedEssentials: (state) => {
|
||||||
@@ -66,13 +67,11 @@ export const useSoftwareStore = defineStore('software', {
|
|||||||
let targetVersion = recommendedVersion || availableVersion;
|
let targetVersion = recommendedVersion || availableVersion;
|
||||||
|
|
||||||
if (isInstalled) {
|
if (isInstalled) {
|
||||||
// 逻辑:已安装 >= 推荐 -> 已安装(禁用)
|
|
||||||
// 逻辑:已安装 < 推荐 -> 更新
|
|
||||||
const comp = compareVersions(currentVersion, recommendedVersion);
|
const comp = compareVersions(currentVersion, recommendedVersion);
|
||||||
if (comp >= 0) {
|
if (comp >= 0) {
|
||||||
displayStatus = task ? task.status : 'installed';
|
displayStatus = task ? task.status : 'installed';
|
||||||
actionLabel = '已安装';
|
actionLabel = '已安装';
|
||||||
targetVersion = undefined; // 禁用安装
|
targetVersion = undefined;
|
||||||
} else {
|
} else {
|
||||||
actionLabel = '更新';
|
actionLabel = '更新';
|
||||||
targetVersion = recommendedVersion;
|
targetVersion = recommendedVersion;
|
||||||
@@ -82,6 +81,9 @@ export const useSoftwareStore = defineStore('software', {
|
|||||||
targetVersion = recommendedVersion || availableVersion;
|
targetVersion = recommendedVersion || availableVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取偏好,默认开启
|
||||||
|
const enablePostInstall = state.postInstallPrefs[item.id] !== false;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
version: currentVersion,
|
version: currentVersion,
|
||||||
@@ -90,19 +92,22 @@ export const useSoftwareStore = defineStore('software', {
|
|||||||
status: displayStatus,
|
status: displayStatus,
|
||||||
progress: task ? task.progress : 0,
|
progress: task ? task.progress : 0,
|
||||||
actionLabel,
|
actionLabel,
|
||||||
targetVersion // 传递给视图,用于点击安装
|
targetVersion,
|
||||||
|
enablePostInstall
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
sortedUpdates: (state) => {
|
sortedUpdates: (state) => {
|
||||||
return [...state.updates].map(item => {
|
return [...state.updates].map(item => {
|
||||||
const task = state.activeTasks[item.id];
|
const task = state.activeTasks[item.id];
|
||||||
|
const enablePostInstall = state.postInstallPrefs[item.id] !== false;
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
status: task ? task.status : 'idle',
|
status: task ? task.status : 'idle',
|
||||||
progress: task ? task.progress : 0,
|
progress: task ? task.progress : 0,
|
||||||
actionLabel: '更新',
|
actionLabel: '更新',
|
||||||
targetVersion: item.available_version // 更新页面永远追求最新版
|
targetVersion: item.available_version,
|
||||||
|
enablePostInstall
|
||||||
};
|
};
|
||||||
}).sort(sortByName);
|
}).sort(sortByName);
|
||||||
},
|
},
|
||||||
@@ -113,7 +118,6 @@ export const useSoftwareStore = defineStore('software', {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
// ... (initializeApp, saveSettings, syncEssentials stay the same)
|
|
||||||
async initializeApp() {
|
async initializeApp() {
|
||||||
if (this.isInitialized) return;
|
if (this.isInitialized) return;
|
||||||
this.initStatus = '正在加载应用配置...';
|
this.initStatus = '正在加载应用配置...';
|
||||||
@@ -230,6 +234,9 @@ export const useSoftwareStore = defineStore('software', {
|
|||||||
async install(id: string, targetVersion?: string) {
|
async install(id: string, targetVersion?: string) {
|
||||||
const software = this.findSoftware(id)
|
const software = this.findSoftware(id)
|
||||||
if (software) {
|
if (software) {
|
||||||
|
// 根据偏好决定是否开启后安装配置
|
||||||
|
const enablePostInstall = this.postInstallPrefs[id] !== false;
|
||||||
|
|
||||||
this.activeTasks[id] = { status: 'pending', progress: 0, targetVersion };
|
this.activeTasks[id] = { status: 'pending', progress: 0, targetVersion };
|
||||||
try {
|
try {
|
||||||
await invoke('install_software', {
|
await invoke('install_software', {
|
||||||
@@ -237,7 +244,8 @@ export const useSoftwareStore = defineStore('software', {
|
|||||||
id,
|
id,
|
||||||
version: targetVersion,
|
version: targetVersion,
|
||||||
use_manifest: software.use_manifest || false,
|
use_manifest: software.use_manifest || false,
|
||||||
manifest_url: software.manifest_url || null
|
manifest_url: software.manifest_url || null,
|
||||||
|
enable_post_install: enablePostInstall
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -247,26 +255,26 @@ export const useSoftwareStore = defineStore('software', {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// 注册批量任务
|
togglePostInstallPref(id: string) {
|
||||||
|
const current = this.postInstallPrefs[id] !== false;
|
||||||
|
this.postInstallPrefs[id] = !current;
|
||||||
|
},
|
||||||
|
|
||||||
startBatch(ids: string[]) {
|
startBatch(ids: string[]) {
|
||||||
this.batchQueue = [...ids];
|
this.batchQueue = [...ids];
|
||||||
},
|
},
|
||||||
|
|
||||||
// 引入防抖刷新:仅在批量任务全部处理完后的 2 秒执行全量扫描
|
|
||||||
scheduleDataRefresh() {
|
scheduleDataRefresh() {
|
||||||
if (this.refreshTimer) clearTimeout(this.refreshTimer);
|
if (this.refreshTimer) clearTimeout(this.refreshTimer);
|
||||||
|
|
||||||
this.refreshTimer = setTimeout(async () => {
|
this.refreshTimer = setTimeout(async () => {
|
||||||
await this.fetchAllData();
|
await this.fetchAllData();
|
||||||
|
|
||||||
// 刷新完成后清理所有已终结(成功或失败)的任务状态快照
|
|
||||||
Object.keys(this.activeTasks).forEach(id => {
|
Object.keys(this.activeTasks).forEach(id => {
|
||||||
const status = this.activeTasks[id].status;
|
const status = this.activeTasks[id].status;
|
||||||
if (status === 'success' || status === 'error') {
|
if (status === 'success' || status === 'error') {
|
||||||
delete this.activeTasks[id];
|
delete this.activeTasks[id];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.refreshTimer = null;
|
this.refreshTimer = null;
|
||||||
}, 2000);
|
}, 2000);
|
||||||
},
|
},
|
||||||
@@ -284,13 +292,10 @@ export const useSoftwareStore = defineStore('software', {
|
|||||||
const { id, status, progress } = event.payload
|
const { id, status, progress } = event.payload
|
||||||
const task = this.activeTasks[id];
|
const task = this.activeTasks[id];
|
||||||
|
|
||||||
// 更新任务状态
|
|
||||||
this.activeTasks[id] = { status, progress, targetVersion: task?.targetVersion };
|
this.activeTasks[id] = { status, progress, targetVersion: task?.targetVersion };
|
||||||
|
|
||||||
// 当任务达到终态(成功或失败)时。注意:'configuring' 不是终态。
|
|
||||||
if (status === 'success' || status === 'error') {
|
if (status === 'success' || status === 'error') {
|
||||||
if (status === 'success') {
|
if (status === 'success') {
|
||||||
// 立即进行局部刷新
|
|
||||||
try {
|
try {
|
||||||
const latestInfo = await invoke('get_software_info', { id }) as any;
|
const latestInfo = await invoke('get_software_info', { id }) as any;
|
||||||
if (latestInfo) {
|
if (latestInfo) {
|
||||||
@@ -305,11 +310,9 @@ export const useSoftwareStore = defineStore('software', {
|
|||||||
console.error('Partial refresh failed:', err);
|
console.error('Partial refresh failed:', err);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 立即更新勾选状态
|
|
||||||
this.selectedEssentialIds = this.selectedEssentialIds.filter(i => i !== id);
|
this.selectedEssentialIds = this.selectedEssentialIds.filter(i => i !== id);
|
||||||
this.selectedUpdateIds = this.selectedUpdateIds.filter(i => i !== id);
|
this.selectedUpdateIds = this.selectedUpdateIds.filter(i => i !== id);
|
||||||
|
|
||||||
// 保持绿色“已完成”状态 3 秒,然后自动回归真实状态
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (this.activeTasks[id]?.status === 'success') {
|
if (this.activeTasks[id]?.status === 'success') {
|
||||||
delete this.activeTasks[id];
|
delete this.activeTasks[id];
|
||||||
@@ -317,11 +320,9 @@ export const useSoftwareStore = defineStore('software', {
|
|||||||
}, 3000);
|
}, 3000);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查是否属于正在进行的批量任务
|
|
||||||
const index = this.batchQueue.indexOf(id);
|
const index = this.batchQueue.indexOf(id);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
this.batchQueue.splice(index, 1);
|
this.batchQueue.splice(index, 1);
|
||||||
// 只有批量任务全部结束后,才执行一次全量刷新作为保障
|
|
||||||
if (this.batchQueue.length === 0) {
|
if (this.batchQueue.length === 0) {
|
||||||
this.scheduleDataRefresh();
|
this.scheduleDataRefresh();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,14 +54,16 @@
|
|||||||
<SoftwareCard
|
<SoftwareCard
|
||||||
v-for="item in store.mergedEssentials"
|
v-for="item in store.mergedEssentials"
|
||||||
:key="item.id"
|
:key="item.id"
|
||||||
:software="item"
|
:software="item"
|
||||||
:action-label="item.actionLabel"
|
:action-label="item.actionLabel"
|
||||||
:selectable="true"
|
:selectable="true"
|
||||||
:is-selected="store.selectedEssentialIds.includes(item.id)"
|
:is-selected="store.selectedEssentialIds.includes(item.id)"
|
||||||
:disabled="store.isBusy"
|
:disabled="store.isBusy"
|
||||||
@install="store.install"
|
@install="store.install"
|
||||||
@toggle-select="id => store.toggleSelection(id, 'essential')"
|
@toggle-select="store.toggleSelection($event, 'essential')"
|
||||||
|
@toggle-post-install="store.togglePostInstallPref"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -58,14 +58,16 @@
|
|||||||
<SoftwareCard
|
<SoftwareCard
|
||||||
v-for="item in store.sortedUpdates"
|
v-for="item in store.sortedUpdates"
|
||||||
:key="item.id"
|
:key="item.id"
|
||||||
:software="item"
|
:software="item"
|
||||||
action-label="更新"
|
:action-label="item.actionLabel"
|
||||||
:selectable="true"
|
:selectable="true"
|
||||||
:is-selected="store.selectedUpdateIds.includes(item.id)"
|
:is-selected="store.selectedUpdateIds.includes(item.id)"
|
||||||
:disabled="store.isBusy"
|
:disabled="store.isBusy"
|
||||||
@install="store.install"
|
@install="store.install"
|
||||||
@toggle-select="id => store.toggleSelection(id, 'update')"
|
@toggle-select="store.toggleSelection($event, 'update')"
|
||||||
|
@toggle-post-install="store.togglePostInstallPref"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
Reference in New Issue
Block a user