fix channel price bug 3

This commit is contained in:
2026-07-07 21:10:23 +03:30
parent b58620f062
commit 16397800bb
4 changed files with 121 additions and 14 deletions
@@ -38,6 +38,21 @@
</a-select-option>
</a-select>
<a-select
v-else-if="fieldType === 'multiselect'"
:value="multiSelectValue"
:disabled="disabled"
mode="multiple"
allow-clear
placeholder="انتخاب کنید"
class="w-full"
@update:value="onMultiSelectChange"
>
<a-select-option v-for="opt in selectItems" :key="opt.key" :value="opt.key">
{{ opt.value }}
</a-select-option>
</a-select>
<a-time-picker
v-else-if="fieldType === 'time'"
:value="modelValue || undefined"
@@ -151,6 +166,18 @@ function onSelectChange(val: string | undefined) {
emit('update:value', val ?? '')
}
const multiSelectValue = computed<string[]>(() =>
String(props.modelValue || '')
.split(',')
.map((s) => s.trim())
.filter((s) => s !== '')
)
function onMultiSelectChange(val: string[] | undefined) {
const list = Array.isArray(val) ? val.map((s) => s.trim()).filter((s) => s !== '') : []
emit('update:value', list.join(','))
}
function onTimeChange(val: string | string[] | undefined) {
const v = Array.isArray(val) ? val[0] : val
emit('update:value', v ?? '')
@@ -76,7 +76,13 @@ export const EDITABLE_SETTING_GROUPS: SettingGroupDef[] = [
id: 'bots',
title: 'بات‌ها',
icon: 'vuesax-linear:messages-2',
match: (k) => /^(telegram_bot|bale_bot)/.test(k)
match: (k) => /^(telegram_bot|bale_bot|rubika_bot)/.test(k)
},
{
id: 'price_channel',
title: 'ارسال قیمت به کانال',
icon: 'vuesax-linear:send-2',
match: (k) => /^price_channel_/.test(k) || k === 'change_mesghal'
},
{
id: 'notifications',
@@ -152,6 +158,12 @@ export const SYSTEM_SETTING_GROUPS: SettingGroupDef[] = [
|| k === 'send_to_tahesab'
|| k === 'send_to_pargar'
},
{
id: 'price_channel',
title: 'ارسال قیمت به کانال',
icon: 'vuesax-linear:send-2',
match: (k) => /^price_channel_/.test(k) || /^(telegram_bot|bale_bot|rubika_bot)/.test(k) || k === 'change_mesghal'
},
{
id: 'infra',
title: 'زیرساخت',
@@ -1,7 +1,15 @@
import type { Const } from '@/model/configuration'
import { isStoreApp } from '@/utils/config'
export type SettingFieldType = 'text' | 'number' | 'price' | 'switch' | 'select' | 'longtext' | 'time'
export type SettingFieldType =
| 'text'
| 'number'
| 'price'
| 'switch'
| 'select'
| 'multiselect'
| 'longtext'
| 'time'
export const MAIN_WALLET_PRODUCTS_DEFAULT = '13'
@@ -78,6 +86,7 @@ export const SETTING_TYPE_OPTIONS = [
{ key: 'price', value: 'مبلغ (ریال)' },
{ key: 'switch', value: 'روشن/خاموش' },
{ key: 'select', value: 'انتخابی' },
{ key: 'multiselect', value: 'انتخاب چندتایی' },
{ key: 'longtext', value: 'متن بلند' },
{ key: 'time', value: 'ساعت' }
]
@@ -145,7 +154,19 @@ const KEY_TYPE_FALLBACK: Record<string, SettingFieldType> = {
invite_link_text: 'longtext',
support_messenger: 'select',
deposit_sms_support_number: 'number',
zaarbox_price_key: 'select'
zaarbox_price_key: 'select',
price_channel_enabled: 'switch',
price_channel_messengers: 'multiselect',
price_channel_diff: 'price',
price_channel_min_seconds: 'number',
price_channel_footer_id: 'text',
price_channel_footer_phone: 'text',
price_channel_footer_link: 'text',
price_channel_bale_to: 'text',
price_channel_telegram_to: 'text',
price_channel_rubika_to: 'text',
rubika_bot_token: 'text',
change_mesghal: 'number'
}
const SELECT_LABELS_BY_KEY: Record<string, Record<string, string>> = {
@@ -161,6 +182,11 @@ const SELECT_LABELS_BY_KEY: Record<string, Record<string, string>> = {
rubika: 'روبیکا',
eitaa: 'ایتا',
soroush: 'سروش'
},
price_channel_messengers: {
bale: 'بله',
telegram: 'تلگرام',
rubika: 'روبیکا'
}
}
@@ -169,7 +195,8 @@ const SELECT_OPTIONS_BY_KEY: Record<string, string> = {
price_provider: 'montzar,zaarbox,main_product',
payping_gateway_name: 'sepal,',
unit: 'گرم,کیلوگرم',
support_messenger: 'bale,telegram,whatsapp,rubika,eitaa,soroush'
support_messenger: 'bale,telegram,whatsapp,rubika,eitaa,soroush',
price_channel_messengers: 'bale,telegram,rubika'
}
/** سوییچ‌هایی که مقدار required/خالی دارند (نه true/false) */
@@ -184,13 +211,14 @@ export function referralRequiredToString(checked: boolean): string {
}
export function resolveSettingFieldType(row: Pick<Const, 'key' | 'type'>): SettingFieldType {
const raw = (row.type || '').trim().toLowerCase()
if (['text', 'number', 'price', 'switch', 'select', 'longtext', 'time'].includes(raw)) {
return raw as SettingFieldType
}
// کاتالوگ پنل بر نوعِ دیتابیس اولویت دارد (هم‌راستا با عنوان/توضیح/can_edit)
if (row.key && KEY_TYPE_FALLBACK[row.key]) {
return KEY_TYPE_FALLBACK[row.key]
}
const raw = (row.type || '').trim().toLowerCase()
if (['text', 'number', 'price', 'switch', 'select', 'multiselect', 'longtext', 'time'].includes(raw)) {
return raw as SettingFieldType
}
return 'text'
}
@@ -368,7 +396,7 @@ const KEY_HELP_FALLBACK: Record<string, string> = {
support_messenger_text:
'متن راهنمای پشتیبانی در مودال شارژ حساب (واریز).',
deposit_sms_support_number:
'شماره پشتیبانی؛ با کلیک روی «تماس با پشتیبانی» در اپ، تماس تلفنی برقرار می‌شود. در صفحه واریز هم برای دکمه پیامک با متن شماره حساب استفاده می‌شود.',
'شماره تماس پشتیبانی؛ با کلیک روی «تماس با پشتیبانی» در اپ، تماس تلفنی برقرار می‌شود. در صفحه واریز، درباره ما و قوانین هم نمایش داده می‌شود.',
charge_notif:
'روشن: پس از شارژ کیف توسط ادمین، پیامک به مشتری ارسال می‌شود.',
group_sms:
@@ -440,7 +468,31 @@ const KEY_HELP_FALLBACK: Record<string, string> = {
admin_url:
'آدرس کامل پنل مدیریت (با https).',
main_product_price:
'تنظیم قدیمی — از «منبع قیمت» استفاده کنید. روشن نگه داشتن توصیه نمی‌شود.'
'تنظیم قدیمی — از «منبع قیمت» استفاده کنید. روشن نگه داشتن توصیه نمی‌شود.',
price_channel_enabled:
'روشن: بعد از هر تغییر قیمت، مظنه به‌صورت خودکار به کانال‌های پیام‌رسان انتخاب‌شده ارسال می‌شود.',
price_channel_messengers:
'کدام پیام‌رسان‌ها قیمت را دریافت کنند؟ می‌توانید چند مورد را انتخاب کنید (بله، تلگرام، روبیکا). برای هر پیام‌رسان باید توکن بات و «مقصد ارسال» هم پر شده باشد.',
price_channel_diff:
'اسپرد اضافه فقط برای کانال (ریال): به قیمت خرید کانال اضافه و از قیمت فروش کم می‌شود. صفر یعنی همان قیمت اپ.',
price_channel_min_seconds:
'حداقل فاصله (ثانیه) بین دو ارسال متوالی به کانال. جلوی سیل پیام هنگام نوسان قیمت را می‌گیرد. صفر = هر تغییر قیمت ارسال شود.',
price_channel_footer_id:
'اگر پر باشد، در انتهای پیام کانال نمایش داده می‌شود (مثلاً یوزرنیم کانال). خالی = این خط نمایش داده نمی‌شود.',
price_channel_footer_phone:
'شماره تماسی که در انتهای پیام کانال نشان داده می‌شود. خالی = نمایش داده نمی‌شود.',
price_channel_footer_link:
'لینکی که در انتهای پیام کانال نشان داده می‌شود. خالی = نمایش داده نمی‌شود.',
price_channel_bale_to:
'آیدی چنل یا گروه بله که قیمت برایش ارسال می‌شود. چند مقصد را با ویرگول جدا کنید.',
price_channel_telegram_to:
'آیدی چنل یا گروه تلگرام که قیمت برایش ارسال می‌شود. چند مقصد را با ویرگول جدا کنید.',
price_channel_rubika_to:
'آیدی چنل یا گروه روبیکا که قیمت برایش ارسال می‌شود. چند مقصد را با ویرگول جدا کنید.',
rubika_bot_token:
'توکن ربات روبیکا برای ارسال قیمت به کانال. محرمانه نگه دارید.',
change_mesghal:
'وزن هر مثقال به گرم؛ برای نمایش خط «هر مثقال» در پیام کانال (مثقال = قیمت هر گرم × این عدد، پیش‌فرض ۴٫۳۳۱۸).'
}
/** برچسب فارسی — وقتی در کاتالوگ تعریف شده، بر title_fa دیتابیس اولویت دارد */
@@ -478,7 +530,19 @@ export const KEY_LABEL_FALLBACK: Record<string, string> = {
support_messenger: 'پیام‌رسان پشتیبانی',
support_messenger_id: 'شناسه پشتیبانی',
support_messenger_text: 'متن راهنمای واریز',
deposit_sms_support_number: 'شماره پشتیبانی'
deposit_sms_support_number: 'شماره تماس پشتیبانی',
price_channel_enabled: 'ارسال قیمت به کانال',
price_channel_messengers: 'پیام‌رسان‌های ارسال قیمت',
price_channel_diff: 'اختلاف قیمت کانال',
price_channel_min_seconds: 'حداقل فاصله ارسال (ثانیه)',
price_channel_footer_id: 'آیدی کانال در پیام',
price_channel_footer_phone: 'شماره تماس در پیام',
price_channel_footer_link: 'لینک در پیام',
price_channel_bale_to: 'مقصد ارسال بله',
price_channel_telegram_to: 'مقصد ارسال تلگرام',
price_channel_rubika_to: 'مقصد ارسال روبیکا',
rubika_bot_token: 'توکن بات روبیکا',
change_mesghal: 'وزن مثقال (گرم)'
}
/** غیرقابل ویرایش در پنل — هم‌تراز deploy_settings_const.sql */
@@ -507,7 +571,8 @@ export const SETTING_LOCKED_KEYS = new Set([
'sse_path',
'tahesab_bank_account', 'tahesab_db', 'tahesab_host', 'tahesab_port', 'tahesab_token',
'pargar_api_token', 'pargar_password', 'pargar_username',
'telegram_bot_token',
'telegram_bot_token', 'rubika_bot_token',
'price_channel_bale_to', 'price_channel_telegram_to', 'price_channel_rubika_to',
'unit',
'up_price', 'down_price',
'wss_enabled',
@@ -534,7 +599,10 @@ export const SETTING_EDITABLE_KEYS = new Set([
'sell_fee', 'show_last_price', 'startDay',
'support_messenger', 'support_messenger_id', 'support_messenger_text',
'text_about', 'text_rule',
'zaarbox_price_key'
'zaarbox_price_key',
'price_channel_enabled', 'price_channel_messengers', 'price_channel_diff',
'price_channel_min_seconds', 'price_channel_footer_id', 'price_channel_footer_phone',
'price_channel_footer_link', 'change_mesghal'
])
/** عنوان فارسی — کاتالوگ پنل بر title_fa دیتابیس اولویت دارد */
+1 -1
View File
@@ -19,7 +19,7 @@ export const bannersEventHelp =
'وقتی مشتری روی بنر ضربه می‌زند چه اتفاقی بیفتد؟ اگر مطمئن نیستید «بدون رویداد» را بگذارید.'
export const bannersLinkHelp =
'آدرس کامل صفحه‌ای که باید باز شود. مثال: https://bazretala.ir یا tel:02112345678'
'آدرس کامل صفحه‌ای که باید باز شود. مثال: https://example.com یا tel:02112345678'
export const bannersModalHelp =
'متنی که داخل خود اپ به مشتری نشان داده می‌شود. می‌توانید بولد، لیست و لینک هم بگذارید.'