修复后台折叠状态和保存提示
This commit is contained in:
+3
@@ -1,6 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, onMounted, reactive, ref, watch } from 'vue'
|
import { computed, onMounted, reactive, ref, watch } from 'vue'
|
||||||
|
|
||||||
|
import { showError, showSuccess } from '@/lib/feedback'
|
||||||
import {
|
import {
|
||||||
fetchAdminCloudtentaclesOverrideRules,
|
fetchAdminCloudtentaclesOverrideRules,
|
||||||
fetchAdminCloudtentaclesSkuList,
|
fetchAdminCloudtentaclesSkuList,
|
||||||
@@ -142,8 +143,10 @@ async function saveOverrideRules() {
|
|||||||
overrideRules.value = Array.isArray(response.data.rules)
|
overrideRules.value = Array.isArray(response.data.rules)
|
||||||
? response.data.rules.map((rule) => normalizeEditableRule(rule))
|
? response.data.rules.map((rule) => normalizeEditableRule(rule))
|
||||||
: []
|
: []
|
||||||
|
showSuccess(`商品覆盖规则已保存,共 ${overrideRules.value.length} 条`)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
overrideErrorMessage.value = error instanceof Error ? error.message : '保存 cloudtentacles 覆盖规则失败'
|
overrideErrorMessage.value = error instanceof Error ? error.message : '保存 cloudtentacles 覆盖规则失败'
|
||||||
|
showError(overrideErrorMessage.value)
|
||||||
} finally {
|
} finally {
|
||||||
overrideSaving.value = false
|
overrideSaving.value = false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,9 +30,11 @@ import { formatAdminDateTime } from '@/utils/admin-time'
|
|||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const sidebarStorageKey = 'admin-sidebar-collapsed'
|
const sidebarStorageKey = 'admin-sidebar-collapsed'
|
||||||
|
const sidebarMenuOpenedsStorageKey = 'admin-sidebar-menu-openeds'
|
||||||
const isSidebarCollapsed = ref(
|
const isSidebarCollapsed = ref(
|
||||||
typeof window !== 'undefined' && window.localStorage.getItem(sidebarStorageKey) === '1',
|
typeof window !== 'undefined' && window.localStorage.getItem(sidebarStorageKey) === '1',
|
||||||
)
|
)
|
||||||
|
const sidebarMenuOpeneds = ref(readSidebarMenuOpeneds())
|
||||||
|
|
||||||
const currentRole = computed(() => getAdminRole())
|
const currentRole = computed(() => getAdminRole())
|
||||||
const isAdmin = computed(() => currentRole.value === 'admin')
|
const isAdmin = computed(() => currentRole.value === 'admin')
|
||||||
@@ -110,6 +112,20 @@ function toggleSidebarCollapse() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleSidebarMenuOpen(index: string) {
|
||||||
|
const normalizedIndex = String(index || '').trim()
|
||||||
|
if (!normalizedIndex) return
|
||||||
|
|
||||||
|
sidebarMenuOpeneds.value = Array.from(new Set([...sidebarMenuOpeneds.value, normalizedIndex]))
|
||||||
|
writeSidebarMenuOpeneds(sidebarMenuOpeneds.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleSidebarMenuClose(index: string) {
|
||||||
|
const normalizedIndex = String(index || '').trim()
|
||||||
|
sidebarMenuOpeneds.value = sidebarMenuOpeneds.value.filter((item) => item !== normalizedIndex)
|
||||||
|
writeSidebarMenuOpeneds(sidebarMenuOpeneds.value)
|
||||||
|
}
|
||||||
|
|
||||||
async function submitLogout() {
|
async function submitLogout() {
|
||||||
try {
|
try {
|
||||||
await logoutAdmin()
|
await logoutAdmin()
|
||||||
@@ -121,6 +137,34 @@ async function submitLogout() {
|
|||||||
await router.replace('/admin/login')
|
await router.replace('/admin/login')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function readSidebarMenuOpeneds(): string[] {
|
||||||
|
if (typeof window === 'undefined') {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const rawValue = window.localStorage.getItem(sidebarMenuOpenedsStorageKey)
|
||||||
|
if (!rawValue) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
const parsed = JSON.parse(rawValue)
|
||||||
|
return Array.isArray(parsed)
|
||||||
|
? Array.from(new Set(parsed.map((item) => String(item || '').trim()).filter(Boolean)))
|
||||||
|
: []
|
||||||
|
} catch {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeSidebarMenuOpeneds(openeds: string[]) {
|
||||||
|
if (typeof window === 'undefined') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
window.localStorage.setItem(sidebarMenuOpenedsStorageKey, JSON.stringify(openeds))
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -151,12 +195,14 @@ async function submitLogout() {
|
|||||||
|
|
||||||
<el-menu
|
<el-menu
|
||||||
:default-active="activeNavIndex"
|
:default-active="activeNavIndex"
|
||||||
:default-openeds="['/admin/platform-shops']"
|
:default-openeds="sidebarMenuOpeneds"
|
||||||
router
|
router
|
||||||
class="sidebar-menu"
|
class="sidebar-menu"
|
||||||
:collapse="isSidebarCollapsed"
|
:collapse="isSidebarCollapsed"
|
||||||
:collapse-transition="false"
|
:collapse-transition="false"
|
||||||
:ellipsis="false"
|
:ellipsis="false"
|
||||||
|
@open="handleSidebarMenuOpen"
|
||||||
|
@close="handleSidebarMenuClose"
|
||||||
>
|
>
|
||||||
<template v-for="item in navItems" :key="item.to">
|
<template v-for="item in navItems" :key="item.to">
|
||||||
<el-sub-menu v-if="item.children?.length" :index="item.to">
|
<el-sub-menu v-if="item.children?.length" :index="item.to">
|
||||||
|
|||||||
+10
-4
@@ -52,9 +52,10 @@ type Props = {
|
|||||||
|
|
||||||
defineProps<Props>()
|
defineProps<Props>()
|
||||||
|
|
||||||
const advancedCollapseNames = useRememberedCollapse(
|
const {
|
||||||
'admin:platform-config:cloudtentacles:config:collapse',
|
activeNames: advancedCollapseNames,
|
||||||
)
|
handleChange: handleAdvancedCollapseChange,
|
||||||
|
} = useRememberedCollapse('admin:platform-config:cloudtentacles:config:collapse')
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -250,7 +251,12 @@ const advancedCollapseNames = useRememberedCollapse(
|
|||||||
</el-form>
|
</el-form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-collapse v-model="advancedCollapseNames" class="advanced-collapse">
|
<el-collapse
|
||||||
|
:model-value="advancedCollapseNames"
|
||||||
|
class="advanced-collapse"
|
||||||
|
@update:model-value="handleAdvancedCollapseChange"
|
||||||
|
@change="handleAdvancedCollapseChange"
|
||||||
|
>
|
||||||
<el-collapse-item name="advanced" title="高级参数与调试字段">
|
<el-collapse-item name="advanced" title="高级参数与调试字段">
|
||||||
<el-form label-width="auto" label-position="top">
|
<el-form label-width="auto" label-position="top">
|
||||||
<div class="form-grid">
|
<div class="form-grid">
|
||||||
|
|||||||
+9
-4
@@ -22,14 +22,19 @@ type Props = {
|
|||||||
|
|
||||||
defineProps<Props>()
|
defineProps<Props>()
|
||||||
|
|
||||||
const debugCollapseNames = useRememberedCollapse(
|
const {
|
||||||
'admin:platform-config:cloudtentacles:debug:collapse',
|
activeNames: debugCollapseNames,
|
||||||
)
|
handleChange: handleDebugCollapseChange,
|
||||||
|
} = useRememberedCollapse('admin:platform-config:cloudtentacles:debug:collapse')
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<el-card class="debug-card">
|
<el-card class="debug-card">
|
||||||
<el-collapse v-model="debugCollapseNames">
|
<el-collapse
|
||||||
|
:model-value="debugCollapseNames"
|
||||||
|
@update:model-value="handleDebugCollapseChange"
|
||||||
|
@change="handleDebugCollapseChange"
|
||||||
|
>
|
||||||
<el-collapse-item name="debug">
|
<el-collapse-item name="debug">
|
||||||
<template #title>
|
<template #title>
|
||||||
<div class="debug-title">
|
<div class="debug-title">
|
||||||
|
|||||||
@@ -1,8 +1,22 @@
|
|||||||
import { ref, watch, type Ref } from 'vue'
|
import { ref, watch, type Ref } from 'vue'
|
||||||
|
|
||||||
export function useRememberedCollapse(storageKey: string, defaultValue: string[] = []): Ref<string[]> {
|
export type RememberedCollapseState = {
|
||||||
|
activeNames: Ref<string[]>
|
||||||
|
handleChange: (value: unknown) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useRememberedCollapse(
|
||||||
|
storageKey: string,
|
||||||
|
defaultValue: string[] = [],
|
||||||
|
): RememberedCollapseState {
|
||||||
const activeNames = ref<string[]>(readStoredCollapseNames(storageKey, defaultValue))
|
const activeNames = ref<string[]>(readStoredCollapseNames(storageKey, defaultValue))
|
||||||
|
|
||||||
|
function handleChange(value: unknown) {
|
||||||
|
const nextNames = normalizeCollapseNames(value)
|
||||||
|
activeNames.value = nextNames
|
||||||
|
writeStoredCollapseNames(storageKey, nextNames)
|
||||||
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
activeNames,
|
activeNames,
|
||||||
(names) => {
|
(names) => {
|
||||||
@@ -11,7 +25,10 @@ export function useRememberedCollapse(storageKey: string, defaultValue: string[]
|
|||||||
{ deep: true },
|
{ deep: true },
|
||||||
)
|
)
|
||||||
|
|
||||||
return activeNames
|
return {
|
||||||
|
activeNames,
|
||||||
|
handleChange,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function readStoredCollapseNames(storageKey: string, defaultValue: string[]): string[] {
|
function readStoredCollapseNames(storageKey: string, defaultValue: string[]): string[] {
|
||||||
@@ -32,7 +49,7 @@ function readStoredCollapseNames(storageKey: string, defaultValue: string[]): st
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function writeStoredCollapseNames(storageKey: string, names: string[]): void {
|
function writeStoredCollapseNames(storageKey: string, names: unknown): void {
|
||||||
if (!canUseLocalStorage()) {
|
if (!canUseLocalStorage()) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -45,6 +62,11 @@ function writeStoredCollapseNames(storageKey: string, names: string[]): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function normalizeCollapseNames(value: unknown, fallback: string[] = []): string[] {
|
function normalizeCollapseNames(value: unknown, fallback: string[] = []): string[] {
|
||||||
|
if (typeof value === 'string' || typeof value === 'number') {
|
||||||
|
const normalized = String(value || '').trim()
|
||||||
|
return normalized ? [normalized] : []
|
||||||
|
}
|
||||||
|
|
||||||
if (!Array.isArray(value)) {
|
if (!Array.isArray(value)) {
|
||||||
return [...fallback]
|
return [...fallback]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user