2026-08-17 20:14:17 +03:30
|
|
|
export type SettingSubsectionDef = {
|
|
|
|
|
id: string
|
|
|
|
|
title: string
|
|
|
|
|
match: (key: string) => boolean
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export type SettingGroupDef = {
|
|
|
|
|
id: string
|
|
|
|
|
title: string
|
|
|
|
|
icon: string
|
|
|
|
|
match: (key: string) => boolean
|
|
|
|
|
subsections?: SettingSubsectionDef[]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** گروههای تنظیمات دیپلوی خانگی (can_edit=0) — همتراز پنل ادمین.
|
|
|
|
|
* کلید جدید برای همهٔ نسخهها: اول `controlpanel_server/.../program-setting-catalog.ts`
|
|
|
|
|
* بعد اینجا گروه را مشخص کن تا در «متفرقه» نماند.
|
|
|
|
|
*/
|
|
|
|
|
export const KHANEGI_SYSTEM_SETTING_GROUPS: SettingGroupDef[] = [
|
|
|
|
|
{
|
|
|
|
|
id: 'customer_features',
|
|
|
|
|
title: 'دسترسی مشتری به قابلیتها',
|
|
|
|
|
icon: 'TeamOutlined',
|
|
|
|
|
match: (k) =>
|
2026-10-27 18:07:23 +03:30
|
|
|
/^(enable_automation|enable_conditional_order|enable_product_funds|enable_remittance|has_page_price_trigger|has_page_notification|has_page_gift_card|enable_customer_level_profit|banner_enabled|jibit_enabled|customer_direct_sms|has_page_earn_money|group_sms|customer_special_pricing|enable_gold_credit|tracking_systems_enabled|permision__enabled|show_to_users_chat|has_landing|has_charts)$/.test(
|
2026-08-17 20:14:17 +03:30
|
|
|
k,
|
|
|
|
|
),
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'support_chat',
|
|
|
|
|
title: 'چت پشتیبانی',
|
|
|
|
|
icon: 'MessageOutlined',
|
|
|
|
|
match: (k) => /^(chat_api|chat_api_key|chat_upload_url|chat_download_url)$/.test(k),
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'general',
|
|
|
|
|
title: 'عمومی و برند',
|
|
|
|
|
icon: 'HomeOutlined',
|
|
|
|
|
match: (k) =>
|
2026-08-24 19:39:07 +03:30
|
|
|
/^(name_fa|name_en|app_url|admin_url|apk_download_link|bace_url|server_url|logo_|title_pwa|title_fav|metal_type|main_metal|unit$|open_register|auto_active_customer|store_status|key$|is_store|sms_panel|main_wallet_products|enamad_url|enamad_logo)/.test(
|
2026-08-17 20:14:17 +03:30
|
|
|
k,
|
|
|
|
|
),
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'chart',
|
|
|
|
|
title: 'نمودار قیمت',
|
|
|
|
|
icon: 'LineChartOutlined',
|
|
|
|
|
match: (k) => /^chart_/.test(k),
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'pricing',
|
|
|
|
|
title: 'منبع قیمت و تابلو',
|
|
|
|
|
icon: 'DollarOutlined',
|
|
|
|
|
match: (k) => /^(price_provider|zaarbox_|main_product$)/.test(k) || k.includes('charge_percentage'),
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'montzar',
|
|
|
|
|
title: 'Montzar',
|
|
|
|
|
icon: 'LinkOutlined',
|
|
|
|
|
match: (k) => /^montzar_/.test(k) || k === 'display_montzar',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'store',
|
|
|
|
|
title: 'اتصال فروشگاه',
|
|
|
|
|
icon: 'ShopOutlined',
|
|
|
|
|
match: (k) => /^node_/.test(k) || k === 'montify_name' || k === 'external_order_api_enabled',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'deposit_methods',
|
|
|
|
|
title: 'روشهای واریز',
|
|
|
|
|
icon: 'CreditCardOutlined',
|
|
|
|
|
match: (k) =>
|
|
|
|
|
k.startsWith('external_payment_') || k === 'wallet_payment_provider',
|
|
|
|
|
subsections: [
|
|
|
|
|
{
|
|
|
|
|
id: 'gateway',
|
|
|
|
|
title: 'درگاه فروشگاه / پرداخت آنلاین',
|
|
|
|
|
match: (k) => k.startsWith('external_payment_') || k === 'wallet_payment_provider',
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'payping',
|
|
|
|
|
title: 'درگاه Payping',
|
|
|
|
|
icon: 'WalletOutlined',
|
|
|
|
|
match: (k) => k.startsWith('payping_'),
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'accounting_provider',
|
|
|
|
|
title: 'انتخاب سیستم حسابداری',
|
|
|
|
|
icon: 'AccountBookOutlined',
|
|
|
|
|
match: (k) => k === 'accounting_provider',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'accounting_zarin',
|
|
|
|
|
title: 'حسابداری زرین',
|
|
|
|
|
icon: 'BankOutlined',
|
|
|
|
|
match: (k) => k.startsWith('zarin_'),
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'accounting_tahesab',
|
|
|
|
|
title: 'حسابداری تهحساب',
|
|
|
|
|
icon: 'CalculatorOutlined',
|
|
|
|
|
match: (k) => k.startsWith('tahesab_') || k === 'send_to_tahesab',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'accounting_pargar',
|
|
|
|
|
title: 'حسابداری پرگار',
|
|
|
|
|
icon: 'FileTextOutlined',
|
|
|
|
|
match: (k) => k.startsWith('pargar_') || k === 'send_to_pargar',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'price_channel',
|
|
|
|
|
title: 'ارسال قیمت به کانال',
|
|
|
|
|
icon: 'SendOutlined',
|
|
|
|
|
match: (k) =>
|
|
|
|
|
/^price_channel_/.test(k) || /^(telegram_bot|bale_bot|rubika_bot)/.test(k) || k === 'change_mesghal',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'infra',
|
|
|
|
|
title: 'زیرساخت',
|
|
|
|
|
icon: 'ClusterOutlined',
|
|
|
|
|
match: (k) => /^(wss_enabled|sse_path|profit_gold_api_enabled)$/.test(k),
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'misc',
|
|
|
|
|
title: 'سایر',
|
|
|
|
|
icon: 'EllipsisOutlined',
|
|
|
|
|
match: () => true,
|
|
|
|
|
},
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
export function getKhanegiSystemGroupId(key: string): string {
|
|
|
|
|
for (const group of KHANEGI_SYSTEM_SETTING_GROUPS) {
|
|
|
|
|
if (group.id === 'misc') continue
|
|
|
|
|
if (group.match(key)) return group.id
|
|
|
|
|
}
|
|
|
|
|
return 'misc'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function getKhanegiSubsectionId(key: string, group: SettingGroupDef | undefined): string | null {
|
|
|
|
|
if (!group?.subsections?.length) return null
|
|
|
|
|
for (const sub of group.subsections) {
|
|
|
|
|
if (sub.match(key)) return sub.id
|
|
|
|
|
}
|
|
|
|
|
return null
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function isSecretSettingKey(key: string): boolean {
|
|
|
|
|
return /(password|secret|token|api_key|apikey|private_key|shared_secret)/i.test(key)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function isSwitchSetting(type: string | null | undefined, value: unknown): boolean {
|
|
|
|
|
const t = String(type || '').toLowerCase()
|
|
|
|
|
if (t === 'switch' || t === 'boolean' || t === 'bool') return true
|
|
|
|
|
if (typeof value === 'boolean') return true
|
|
|
|
|
const v = String(value ?? '').trim().toLowerCase()
|
|
|
|
|
return v === 'true' || v === 'false'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function isSettingOn(value: unknown): boolean {
|
|
|
|
|
if (value === true || value === 1) return true
|
|
|
|
|
const v = String(value ?? '').trim().toLowerCase()
|
|
|
|
|
return v === 'true' || v === '1' || v === 'on'
|
|
|
|
|
}
|