fix chart
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="h-full min-h-0">
|
||||
<BasicShowContent title="تنظیمات" class="h-full">
|
||||
<BasicShowContent :title="pageTitle" class="h-full">
|
||||
<div class="settings-toolbar">
|
||||
<a-input
|
||||
v-model:value="search"
|
||||
@@ -27,6 +27,15 @@
|
||||
</div>
|
||||
|
||||
<!-- <a-button type="primary" :loading="loading" @click="add">افزودن تنظیم</a-button>-->
|
||||
<a-button
|
||||
v-if="isSystemMode"
|
||||
type="primary"
|
||||
class="settings-toolbar__action"
|
||||
:loading="loading"
|
||||
@click="add"
|
||||
>
|
||||
افزودن تنظیم
|
||||
</a-button>
|
||||
<a-button class="settings-toolbar__action" :loading="loading" @click="initConfig">
|
||||
بروزرسانی
|
||||
</a-button>
|
||||
@@ -34,21 +43,20 @@
|
||||
|
||||
<a-spin :spinning="loading && !baseData.length">
|
||||
<a-collapse
|
||||
v-model:activeKey="activeKeys"
|
||||
v-model:activeKey="activeKey"
|
||||
accordion
|
||||
class="settings-collapse"
|
||||
:bordered="false"
|
||||
>
|
||||
<a-collapse-panel
|
||||
v-for="group in SETTING_GROUPS"
|
||||
v-for="group in visibleSettingGroups"
|
||||
:key="group.id"
|
||||
:collapsible="groupedFiltered[group.id]?.length ? undefined : 'disabled'"
|
||||
>
|
||||
<template #header>
|
||||
<div class="settings-collapse-header">
|
||||
<BaseIcon :icon="group.icon" size="18" class="settings-collapse-icon" />
|
||||
<span class="settings-collapse-title">{{ group.title }}</span>
|
||||
<a-badge
|
||||
v-if="groupedFiltered[group.id]"
|
||||
:count="groupedFiltered[group.id].length"
|
||||
:number-style="{ backgroundColor: '#d4af37', color: '#fff', fontSize: '11px' }"
|
||||
/>
|
||||
@@ -57,7 +65,7 @@
|
||||
|
||||
<a-row :gutter="[16, 16]" class="settings-grid">
|
||||
<a-col
|
||||
v-for="row in groupedFiltered[group.id] || []"
|
||||
v-for="row in groupedFiltered[group.id]"
|
||||
:key="row.id"
|
||||
:xs="24"
|
||||
:sm="12"
|
||||
@@ -74,16 +82,16 @@
|
||||
/>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<div v-if="!groupedFiltered[group.id]?.length" class="settings-empty-group">
|
||||
موردی در این گروه یافت نشد
|
||||
</div>
|
||||
</a-collapse-panel>
|
||||
</a-collapse>
|
||||
|
||||
<a-empty
|
||||
v-if="!loading && Object.keys(groupedFiltered).length === 0"
|
||||
description="تنظیمی یافت نشد"
|
||||
v-if="!loading && visibleSettingGroups.length === 0"
|
||||
:description="
|
||||
isSystemMode
|
||||
? 'تنظیم سیستمی فعالی (can_edit=0) یافت نشد — deploy_settings_const.sql را اجرا کنید'
|
||||
: 'تنظیمی یافت نشد'
|
||||
"
|
||||
class="mt-8"
|
||||
/>
|
||||
</a-spin>
|
||||
@@ -161,20 +169,43 @@ import type { FormInstance } from 'ant-design-vue'
|
||||
import { message } from 'ant-design-vue'
|
||||
import type { Const } from '@/model/configuration'
|
||||
import { loading } from '@/utils'
|
||||
import { getEditableConfiguration, setConfiguration } from '@/api/configuration'
|
||||
import { getEditableConfiguration, getSystemConfiguration, setConfiguration, setSystemConfiguration } from '@/api/configuration'
|
||||
import SettingValueField from './SettingValueField.vue'
|
||||
import SettingCard from './SettingCard.vue'
|
||||
import { refreshAppModeMenu } from '@/router'
|
||||
import { useUserStore } from '@/store/userStore'
|
||||
import { setStoreModeFromSettings } from '@/utils/config'
|
||||
import {
|
||||
EDITABLE_SETTING_GROUPS,
|
||||
SYSTEM_SETTING_GROUPS,
|
||||
getSettingGroupId
|
||||
} from './settingGroups'
|
||||
import {
|
||||
SETTING_TYPE_OPTIONS,
|
||||
formatValueForSave,
|
||||
helpText,
|
||||
isSettingVisible,
|
||||
isSettingLocked,
|
||||
isSettingActive,
|
||||
isSwitchOn,
|
||||
resolveSettingFieldType
|
||||
} from './settingTypes'
|
||||
|
||||
const props = withDefaults(defineProps<{ mode?: 'editable' | 'system' }>(), {
|
||||
mode: 'editable'
|
||||
})
|
||||
|
||||
const userStore = useUserStore()
|
||||
function refreshMenuAfterStoreChange() {
|
||||
refreshAppModeMenu(userStore.userInfo?.mobile)
|
||||
}
|
||||
|
||||
const isSystemMode = computed(() => props.mode === 'system')
|
||||
const pageTitle = computed(() => (isSystemMode.value ? 'تنظیمات پیشرفته' : 'تنظیمات'))
|
||||
const settingGroups = computed(() =>
|
||||
isSystemMode.value ? SYSTEM_SETTING_GROUPS : EDITABLE_SETTING_GROUPS
|
||||
)
|
||||
|
||||
const settingTypeOptions = SETTING_TYPE_OPTIONS
|
||||
|
||||
const typeSelectOptions = SETTING_TYPE_OPTIONS.map((t) => ({
|
||||
@@ -224,7 +255,7 @@ function sortRows(rows: Const[]): Const[] {
|
||||
}
|
||||
|
||||
function isEditable(row: Const): boolean {
|
||||
return row.can_edit !== 0 && row.can_edit !== false
|
||||
return !isSettingLocked(row.can_edit)
|
||||
}
|
||||
|
||||
function matchesFilter(row: Const): boolean {
|
||||
@@ -244,13 +275,14 @@ function matchesFilter(row: Const): boolean {
|
||||
|
||||
const filteredRows = computed(() =>
|
||||
sortRows(
|
||||
(baseData.value || []).filter(
|
||||
(row) =>
|
||||
row.id != null &&
|
||||
isEditable(row) &&
|
||||
isSettingVisible(row.key) &&
|
||||
matchesFilter(row)
|
||||
)
|
||||
(baseData.value || []).filter((row) => {
|
||||
if (row.id == null || !matchesFilter(row)) return false
|
||||
if (isSystemMode.value) {
|
||||
// API با system_only=1 فیلتر کرده؛ فقط جستجو اعمال میشود
|
||||
return true
|
||||
}
|
||||
return isEditable(row) && isSettingVisible(row.key)
|
||||
})
|
||||
)
|
||||
)
|
||||
|
||||
@@ -265,148 +297,75 @@ const otherRows = computed(() =>
|
||||
// =============================================================================
|
||||
// گروهبندی تنظیمات — اولین match برنده است؛ misc فقط برای باقیمانده
|
||||
// =============================================================================
|
||||
const SETTING_GROUPS: Array<{
|
||||
id: string
|
||||
title: string
|
||||
icon: string
|
||||
match: (key: string) => boolean
|
||||
}> = [
|
||||
{
|
||||
id: 'general',
|
||||
title: 'عمومی و برند اپ',
|
||||
icon: 'vuesax-linear:home-2',
|
||||
match: (k) =>
|
||||
/^(name_fa|name_en|app_url|admin_url|bace_url|server_url|logo_|title_pwa|title_fav|metal_type|unit$|open_register|auto_active_customer|store_status|key$)/.test(
|
||||
k
|
||||
)
|
||||
},
|
||||
{
|
||||
id: 'chart',
|
||||
title: 'نمودار قیمت',
|
||||
icon: 'vuesax-linear:chart-2',
|
||||
match: (k) => /^chart_/.test(k)
|
||||
},
|
||||
{
|
||||
id: 'pricing',
|
||||
title: 'قیمتگذاری، کارمزد و تابلو',
|
||||
icon: 'vuesax-linear:dollar-circle',
|
||||
match: (k) =>
|
||||
/^(fee_|buy_fee|sell_fee|min_|minimum_|price_provider|zaarbox_|main_product$|show_last_price|close_price|startDay|endDay|up_price|down_price|price_extreme_date|balance_report_exclude)/.test(
|
||||
k
|
||||
) || k.includes('charge_percentage')
|
||||
},
|
||||
{
|
||||
id: 'content',
|
||||
title: 'متنهای اپ (قوانین و درباره)',
|
||||
icon: 'vuesax-linear:document-text',
|
||||
match: (k) => /^text_/.test(k)
|
||||
},
|
||||
{
|
||||
id: 'referral',
|
||||
title: 'معرف، پاداش و ثبتنام',
|
||||
icon: 'vuesax-linear:people',
|
||||
match: (k) =>
|
||||
/^(referral_|gift_for|register_referral|register_jibit|has_page_earn_money|jibit_verification|referral_bonus|invite_link_text)/.test(
|
||||
k
|
||||
)
|
||||
},
|
||||
{
|
||||
id: 'montzar',
|
||||
title: 'همکار قیمت (Montzar)',
|
||||
icon: 'vuesax-linear:link-2',
|
||||
match: (k) => k.startsWith('montzar_') || k === 'display_montzar'
|
||||
},
|
||||
{
|
||||
id: 'store',
|
||||
title: 'اتصال به فروشگاه (Montify)',
|
||||
icon: 'vuesax-linear:shop',
|
||||
match: (k) => /^(external_order|node_|montify_name)/.test(k)
|
||||
},
|
||||
{
|
||||
id: 'payping',
|
||||
title: 'درگاه Payping / Zify',
|
||||
icon: 'vuesax-linear:card',
|
||||
match: (k) => k.startsWith('payping_')
|
||||
},
|
||||
{
|
||||
id: 'tahesab',
|
||||
title: 'تهحساب',
|
||||
icon: 'vuesax-linear:receipt-2',
|
||||
match: (k) => k.startsWith('tahesab_') || k === 'send_to_tahesab'
|
||||
},
|
||||
{
|
||||
id: 'support',
|
||||
title: 'پشتیبانی اپ کاربر',
|
||||
icon: 'vuesax-linear:headphone',
|
||||
match: (k) => k.startsWith('support_messenger') || k === 'deposit_sms_support_number'
|
||||
},
|
||||
{
|
||||
id: 'bots',
|
||||
title: 'بات تلگرام و بله',
|
||||
icon: 'vuesax-linear:messages-2',
|
||||
match: (k) => /^(telegram_bot|bale_bot)/.test(k)
|
||||
},
|
||||
{
|
||||
id: 'notifications',
|
||||
title: 'پیامک و اعلان',
|
||||
icon: 'vuesax-linear:notification',
|
||||
match: (k) => /^(charge_notif|group_sms)/.test(k)
|
||||
},
|
||||
{
|
||||
id: 'features',
|
||||
title: 'محصولات و قابلیتهای سیستم',
|
||||
icon: 'vuesax-linear:setting-2',
|
||||
match: (k) => /^(product_|main_wallet_products|price_from_nasiryan|profit_gold)/.test(k)
|
||||
},
|
||||
{
|
||||
id: 'misc',
|
||||
title: 'سایر تنظیمات',
|
||||
icon: 'vuesax-linear:more-circle',
|
||||
match: () => true
|
||||
}
|
||||
]
|
||||
|
||||
function getGroupId(key: string): string {
|
||||
for (const g of SETTING_GROUPS) {
|
||||
if (g.id === 'misc') continue
|
||||
if (g.match(key)) return g.id
|
||||
}
|
||||
return 'misc'
|
||||
return getSettingGroupId(key, settingGroups.value)
|
||||
}
|
||||
|
||||
const groupedFiltered = computed(() => {
|
||||
const map: Record<string, Const[]> = {}
|
||||
for (const g of SETTING_GROUPS) map[g.id] = []
|
||||
for (const g of settingGroups.value) map[g.id] = []
|
||||
for (const row of filteredRows.value) {
|
||||
const gid = getGroupId(row.key || '')
|
||||
map[gid].push(row)
|
||||
}
|
||||
// حذف گروههای خالی
|
||||
Object.keys(map).forEach((k) => {
|
||||
if (map[k].length === 0) delete map[k]
|
||||
})
|
||||
return map
|
||||
})
|
||||
|
||||
// کالپسهای باز — وقتی سرچ فعال است فقط گروههای دارای نتیجه باز میشوند
|
||||
const defaultOpenGroups = ['general', 'pricing', 'store', 'payping', 'tahesab']
|
||||
const activeKeys = ref<string[]>(defaultOpenGroups)
|
||||
const visibleSettingGroups = computed(() =>
|
||||
settingGroups.value.filter((g) => (groupedFiltered.value[g.id]?.length ?? 0) > 0)
|
||||
)
|
||||
|
||||
const defaultOpenGroupId = computed(() => {
|
||||
const visibleIds = visibleSettingGroups.value.map((g) => g.id)
|
||||
const preferred = isSystemMode.value
|
||||
? ['chart', 'pricing', 'payping', 'tahesab', 'store', 'general']
|
||||
: ['general', 'content', 'pricing', 'referral']
|
||||
const fromPreferred = preferred.find((id) => visibleIds.includes(id))
|
||||
return fromPreferred ?? visibleIds[0]
|
||||
})
|
||||
|
||||
const activeKey = ref<string | undefined>(undefined)
|
||||
|
||||
watch(
|
||||
visibleSettingGroups,
|
||||
(groups) => {
|
||||
const visibleIds = new Set(groups.map((g) => g.id))
|
||||
if (activeKey.value && !visibleIds.has(activeKey.value)) {
|
||||
activeKey.value = groups[0]?.id
|
||||
}
|
||||
if (!activeKey.value && groups.length) {
|
||||
activeKey.value = defaultOpenGroupId.value
|
||||
}
|
||||
},
|
||||
{ flush: 'post' }
|
||||
)
|
||||
|
||||
watch(
|
||||
defaultOpenGroupId,
|
||||
(id) => {
|
||||
if (!activeKey.value && id) {
|
||||
activeKey.value = id
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
watch(search, (q) => {
|
||||
const query = q.trim().toLowerCase()
|
||||
if (!query) {
|
||||
// برگشت به حالت پیشفرض
|
||||
if (activeKeys.value.length === 0 || activeKeys.value.every(k => !defaultOpenGroups.includes(k))) {
|
||||
activeKeys.value = [...defaultOpenGroups]
|
||||
if (!activeKey.value || !visibleSettingGroups.value.some((g) => g.id === activeKey.value)) {
|
||||
activeKey.value = defaultOpenGroupId.value
|
||||
}
|
||||
return
|
||||
}
|
||||
// فقط گروههایی که حداقل یک آیتم matching دارند
|
||||
const matching: string[] = []
|
||||
for (const gid of Object.keys(groupedFiltered.value)) {
|
||||
if (groupedFiltered.value[gid].length > 0) matching.push(gid)
|
||||
}
|
||||
activeKeys.value = matching.length ? matching : defaultOpenGroups
|
||||
const matching = Object.keys(groupedFiltered.value).find(
|
||||
(gid) => (groupedFiltered.value[gid]?.length ?? 0) > 0
|
||||
)
|
||||
activeKey.value = matching ?? defaultOpenGroupId.value
|
||||
}, { flush: 'post' })
|
||||
|
||||
function rowColSpan(row: Const): number {
|
||||
@@ -414,7 +373,8 @@ function rowColSpan(row: Const): number {
|
||||
}
|
||||
|
||||
function isReadonly(row: Const): boolean {
|
||||
return row.can_edit === 0 || row.can_edit === false
|
||||
if (isSystemMode.value) return false
|
||||
return isSettingLocked(row.can_edit)
|
||||
}
|
||||
|
||||
function draftValue(row: Const): string {
|
||||
@@ -443,14 +403,29 @@ onMounted(() => {
|
||||
initConfig()
|
||||
})
|
||||
|
||||
watch(
|
||||
() => props.mode,
|
||||
() => {
|
||||
search.value = ''
|
||||
filterType.value = undefined
|
||||
activeKey.value = undefined
|
||||
initConfig()
|
||||
}
|
||||
)
|
||||
|
||||
async function initConfig() {
|
||||
try {
|
||||
loading.value = true
|
||||
baseData.value = (await getEditableConfiguration()) ?? []
|
||||
const storeRow = baseData.value.find((row) => row.key === 'is_store')
|
||||
if (storeRow) {
|
||||
setStoreModeFromSettings(isSwitchOn(storeRow.value))
|
||||
refreshAppModeMenu()
|
||||
baseData.value =
|
||||
(isSystemMode.value
|
||||
? await getSystemConfiguration()
|
||||
: await getEditableConfiguration()) ?? []
|
||||
if (!isSystemMode.value) {
|
||||
const storeRow = baseData.value.find((row) => row.key === 'is_store')
|
||||
if (storeRow) {
|
||||
setStoreModeFromSettings(isSwitchOn(storeRow.value))
|
||||
refreshMenuAfterStoreChange()
|
||||
}
|
||||
}
|
||||
syncDraftsFromBase()
|
||||
} catch (e) {
|
||||
@@ -534,7 +509,8 @@ async function saveSettingRow(row: Const) {
|
||||
savedFlashIds.value.delete(id)
|
||||
|
||||
try {
|
||||
await setConfiguration({
|
||||
const saveFn = isSystemMode.value ? setSystemConfiguration : setConfiguration
|
||||
await saveFn({
|
||||
id: row.id,
|
||||
key: row.key,
|
||||
value,
|
||||
@@ -551,9 +527,9 @@ async function saveSettingRow(row: Const) {
|
||||
} else {
|
||||
scheduleSave(row)
|
||||
}
|
||||
if (row.key === 'is_store') {
|
||||
if (row.key === 'is_store' && !isSystemMode.value) {
|
||||
setStoreModeFromSettings(isSwitchOn(value))
|
||||
refreshAppModeMenu()
|
||||
refreshMenuAfterStoreChange()
|
||||
}
|
||||
savedFlashIds.value.add(id)
|
||||
if (saveTimers.has(id)) clearTimeout(saveTimers.get(id))
|
||||
@@ -610,7 +586,8 @@ async function ok() {
|
||||
try {
|
||||
await formRef.value?.validateFields()
|
||||
loading.value = true
|
||||
await setConfiguration(payload)
|
||||
const saveFn = isSystemMode.value ? setSystemConfiguration : setConfiguration
|
||||
await saveFn(payload)
|
||||
message.success('تنظیم جدید اضافه شد')
|
||||
addConfigVisible.value = false
|
||||
await initConfig()
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
export type SettingGroupDef = {
|
||||
id: string
|
||||
title: string
|
||||
icon: string
|
||||
match: (key: string) => boolean
|
||||
}
|
||||
|
||||
/** گروههای صفحه تنظیمات عادی (فقط can_edit=1) */
|
||||
export const EDITABLE_SETTING_GROUPS: SettingGroupDef[] = [
|
||||
{
|
||||
id: 'general',
|
||||
title: 'عمومی و برند',
|
||||
icon: 'vuesax-linear:home-2',
|
||||
match: (k) =>
|
||||
/^(name_fa|name_en|bace_url|server_url|logo_|title_pwa|title_fav|open_register|auto_active_customer|store_status|key$)/.test(
|
||||
k
|
||||
)
|
||||
},
|
||||
{
|
||||
id: 'pricing',
|
||||
title: 'کارمزد و محدودیتها',
|
||||
icon: 'vuesax-linear:dollar-circle',
|
||||
match: (k) =>
|
||||
/^(fee_|buy_fee|sell_fee|min_|minimum_|show_last_price|close_price|startDay|endDay|up_price|down_price|price_extreme_date|balance_report_exclude)/.test(
|
||||
k
|
||||
) || k.includes('charge_percentage')
|
||||
},
|
||||
{
|
||||
id: 'content',
|
||||
title: 'متنهای اپ',
|
||||
icon: 'vuesax-linear:document-text',
|
||||
match: (k) => /^text_/.test(k)
|
||||
},
|
||||
{
|
||||
id: 'referral',
|
||||
title: 'معرف و پاداش',
|
||||
icon: 'vuesax-linear:people',
|
||||
match: (k) =>
|
||||
/^(referral_|gift_for|register_referral|register_jibit|jibit_verification|referral_bonus|invite_link_text)/.test(
|
||||
k
|
||||
)
|
||||
},
|
||||
{
|
||||
id: 'montzar',
|
||||
title: 'همکار Montzar',
|
||||
icon: 'vuesax-linear:link-2',
|
||||
match: (k) =>
|
||||
(k.startsWith('montzar_') && !['montzar_base_url', 'montzar_closed'].includes(k)) ||
|
||||
k === 'display_montzar'
|
||||
},
|
||||
{
|
||||
id: 'store',
|
||||
title: 'سفارش خارجی',
|
||||
icon: 'vuesax-linear:shop',
|
||||
match: (k) => /^external_order/.test(k)
|
||||
},
|
||||
{
|
||||
id: 'support',
|
||||
title: 'پشتیبانی',
|
||||
icon: 'vuesax-linear:headphone',
|
||||
match: (k) => k.startsWith('support_messenger') || k === 'deposit_sms_support_number'
|
||||
},
|
||||
{
|
||||
id: 'bots',
|
||||
title: 'باتها',
|
||||
icon: 'vuesax-linear:messages-2',
|
||||
match: (k) => /^(telegram_bot|bale_bot)/.test(k)
|
||||
},
|
||||
{
|
||||
id: 'notifications',
|
||||
title: 'پیامک و اعلان',
|
||||
icon: 'vuesax-linear:notification',
|
||||
match: (k) => /^charge_notif/.test(k)
|
||||
},
|
||||
{
|
||||
id: 'features',
|
||||
title: 'قابلیتهای سیستم',
|
||||
icon: 'vuesax-linear:setting-2',
|
||||
match: (k) => /^(product_|main_wallet_products|price_from_nasiryan|profit_gold)/.test(k)
|
||||
},
|
||||
{
|
||||
id: 'misc',
|
||||
title: 'سایر',
|
||||
icon: 'vuesax-linear:more-circle',
|
||||
match: () => true
|
||||
}
|
||||
]
|
||||
|
||||
/** گروههای صفحه دیپلوی — شامل تنظیمات can_edit=0 */
|
||||
export const SYSTEM_SETTING_GROUPS: SettingGroupDef[] = [
|
||||
{
|
||||
id: 'general',
|
||||
title: 'عمومی و برند',
|
||||
icon: 'vuesax-linear:home-2',
|
||||
match: (k) =>
|
||||
/^(name_fa|name_en|app_url|admin_url|apk_download_link|banner_enabled|bace_url|server_url|logo_|title_pwa|title_fav|metal_type|unit$|open_register|auto_active_customer|store_status|key$|is_store|group_sms|has_page_earn_money)/.test(
|
||||
k
|
||||
)
|
||||
},
|
||||
{
|
||||
id: 'chart',
|
||||
title: 'نمودار قیمت',
|
||||
icon: 'vuesax-linear:chart-2',
|
||||
match: (k) => /^chart_/.test(k)
|
||||
},
|
||||
{
|
||||
id: 'pricing',
|
||||
title: 'منبع قیمت و تابلو',
|
||||
icon: 'vuesax-linear:dollar-circle',
|
||||
match: (k) =>
|
||||
/^(price_provider|zaarbox_|main_product$|default_vc_number)/.test(k) ||
|
||||
k.includes('charge_percentage')
|
||||
},
|
||||
{
|
||||
id: 'montzar',
|
||||
title: 'Montzar',
|
||||
icon: 'vuesax-linear:link-2',
|
||||
match: (k) => /^montzar_/.test(k) || k === 'display_montzar'
|
||||
},
|
||||
{
|
||||
id: 'store',
|
||||
title: 'اتصال فروشگاه',
|
||||
icon: 'vuesax-linear:shop',
|
||||
match: (k) => /^node_/.test(k) || k === 'montify_name' || k === 'external_order_api_enabled'
|
||||
},
|
||||
{
|
||||
id: 'payping',
|
||||
title: 'درگاه Payping',
|
||||
icon: 'vuesax-linear:card',
|
||||
match: (k) => k.startsWith('payping_')
|
||||
},
|
||||
{
|
||||
id: 'tahesab',
|
||||
title: 'تهحساب',
|
||||
icon: 'vuesax-linear:receipt-2',
|
||||
match: (k) => k.startsWith('tahesab_') || k === 'send_to_tahesab'
|
||||
},
|
||||
{
|
||||
id: 'infra',
|
||||
title: 'زیرساخت',
|
||||
icon: 'vuesax-linear:cpu',
|
||||
match: (k) => /^(wss_enabled|sse_path|wss_path|wss_link|wss_trigger_path|profit_gold_api_enabled)/.test(k)
|
||||
},
|
||||
{
|
||||
id: 'misc',
|
||||
title: 'سایر',
|
||||
icon: 'vuesax-linear:more-circle',
|
||||
match: () => true
|
||||
}
|
||||
]
|
||||
|
||||
export function getSettingGroupId(key: string, groups: SettingGroupDef[]): string {
|
||||
for (const g of groups) {
|
||||
if (g.id === 'misc') continue
|
||||
if (g.match(key)) return g.id
|
||||
}
|
||||
return 'misc'
|
||||
}
|
||||
@@ -19,6 +19,15 @@ export const HIDDEN_LEGACY_SETTING_KEYS = new Set([
|
||||
/** فقط وقتی is_store فعال است در پنل دیده میشوند */
|
||||
export const STORE_ONLY_SETTING_KEYS = new Set(['store_status', 'price_from_nasiryan'])
|
||||
|
||||
export function isSettingLocked(canEdit: Const['can_edit']): boolean {
|
||||
return canEdit === 0 || canEdit === false || canEdit === '0'
|
||||
}
|
||||
|
||||
export function isSettingActive(isActive: Const['is_active']): boolean {
|
||||
if (isActive === 0 || isActive === false || isActive === '0') return false
|
||||
return isActive !== null && isActive !== undefined
|
||||
}
|
||||
|
||||
export function isSettingVisible(key: string | undefined | null): boolean {
|
||||
const k = (key || '').trim()
|
||||
if (!k) return false
|
||||
@@ -78,6 +87,8 @@ const KEY_TYPE_FALLBACK: Record<string, SettingFieldType> = {
|
||||
external_order_api_enabled: 'switch',
|
||||
is_store: 'switch',
|
||||
price_from_nasiryan: 'switch',
|
||||
banner_enabled: 'switch',
|
||||
apk_download_link: 'text',
|
||||
node_client_id: 'text',
|
||||
node_shared_secret: 'text',
|
||||
tahesab_host: 'text',
|
||||
|
||||
@@ -11,7 +11,10 @@
|
||||
class="hidden md:inline overflow-auto min-w-[13.5rem]"
|
||||
/>
|
||||
<!-- <component :is="selectedComponent" class="mr-5" />-->
|
||||
<RouterView class="mt-5 min-h-0 w-full flex-1 overflow-hidden md:mr-5 md:mt-0" />
|
||||
<RouterView
|
||||
:key="route.name"
|
||||
class="mt-5 min-h-0 w-full flex-1 overflow-hidden md:mr-5 md:mt-0"
|
||||
/>
|
||||
</div>
|
||||
</BasicMainCard>
|
||||
</div>
|
||||
@@ -20,14 +23,24 @@
|
||||
<script setup lang="ts">
|
||||
import BasicMenu from '@/components/BasicMenu/index.vue'
|
||||
import { useRouterStore } from '@core/stores/router'
|
||||
import { useUserStore } from '@/store/userStore'
|
||||
import { isDeployAdmin } from '@/utils/deployAdmin'
|
||||
import { get } from 'lodash'
|
||||
import type { RouteRecordRaw } from 'vue-router'
|
||||
|
||||
const routerStore = useRouterStore()
|
||||
const route = useRoute()
|
||||
const userStore = useUserStore()
|
||||
const menu = computed(() => {
|
||||
const item = routerStore.routes.find((item) => item.name === 'settings')
|
||||
const children = get(item, 'children[0].children', []) as RouteRecordRaw[]
|
||||
return children.filter((child) => !child.meta?.hideMenu)
|
||||
return children
|
||||
.filter((child) => !child.meta?.hideMenu)
|
||||
.filter(
|
||||
(child) =>
|
||||
!child.meta?.deployAdminOnly || isDeployAdmin(userStore.userInfo?.mobile)
|
||||
)
|
||||
.sort((a, b) => (Number(a.meta?.order) || 99) - (Number(b.meta?.order) || 99))
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user