From b446c21afc2cb0fdb02926785b50aced337f036d Mon Sep 17 00:00:00 2001
From: mohammad sedighi
+ برای قالبهای دارای لینک، مقدار «لینک اپ» را در تنظیمات پر کنید. +
++ فقط متن میانی را بنویسید. نام مشتری و نام اپ بهصورت خودکار اضافه میشوند. +
++ همین متن دقیقاً برای گیرنده ارسال میشود. قبل از ارسال پیشنمایش را بررسی کنید. +
+متن حاوی عبارت نامناسب است — قبل از ارسال اصلاح کنید.
-- متغیرها در سرور جایگزین میشوند: %نام% · %نام_اپ% · %لینک_اپ% +
+ طول پیامک بیش از {{ DIRECT_SMS_MAX_LENGTH }} کاراکتر است. +
++ نام اپ در تنظیمات خالی است؛ در پایان پیام از «اپ» استفاده میشود.
@@ -52,9 +117,13 @@ import type { Customer } from '@/model/customer' import { isMobile } from '@core/utils/is' import BasicModal from '@/components/BasicModal.vue' import { - buildDirectSmsSnippets, + DIRECT_SMS_MAX_LENGTH, + DIRECT_SMS_TEMPLATES, findProfanity, - sendCustomerDirectSms + formatDirectSms, + resolveTemplateBody, + sendCustomerDirectSms, + type DirectSmsTemplate } from '@/api/customerDirectSms' import { getConfiguration } from '@/api/configuration' @@ -74,29 +143,89 @@ const visibleProxy = computed({ }) const loading = ref(false) -const message = ref('') +const activeTab = ref<'templates' | 'manual'>('templates') +const selectedTemplateKey = ref(DIRECT_SMS_TEMPLATES[0]?.key ?? '') +const manualBody = ref('') const appName = ref('') const appUrl = ref('') +const templates = DIRECT_SMS_TEMPLATES + const modalTitle = computed(() => props.customer?.name ? `پیامک به ${props.customer.name}` : 'ارسال پیامک به مشتری' ) -const snippets = computed(() => - buildDirectSmsSnippets(props.customer, appName.value, appUrl.value) +const customerDisplayName = computed( + () => (props.customer?.name ?? '').trim() || 'مشتری' ) -const profanityHit = computed(() => findProfanity(message.value)) +const appDisplayName = computed(() => appName.value.trim() || 'اپ') + +const templateCtx = computed(() => ({ + appUrl: appUrl.value.trim(), + appName: appDisplayName.value +})) + +function isTemplateDisabled(tpl: DirectSmsTemplate): boolean { + return Boolean(tpl.requiresAppUrl && !appUrl.value.trim()) +} + +const needsAppUrlHint = computed(() => + templates.some((t) => t.requiresAppUrl) +) + +const selectedTemplate = computed( + () => templates.find((t) => t.key === selectedTemplateKey.value) ?? null +) + +const bodyText = computed(() => { + if (activeTab.value === 'manual') return manualBody.value.trim() + const tpl = selectedTemplate.value + if (!tpl || isTemplateDisabled(tpl)) return '' + return resolveTemplateBody(tpl, templateCtx.value) +}) + +const previewMessage = computed(() => { + if (!bodyText.value) return '' + return formatDirectSms({ + customerName: customerDisplayName.value, + body: bodyText.value, + appName: appDisplayName.value + }) +}) + +const previewLength = computed(() => previewMessage.value.length) + +const previewOverLimit = computed(() => previewLength.value > DIRECT_SMS_MAX_LENGTH) + +/** سقف تقریبی برای بدنهٔ دستی تا کل پیام از ۷۰۰ رد نشود */ +const manualMaxLength = computed(() => { + const wrapperLen = formatDirectSms({ + customerName: customerDisplayName.value, + body: '', + appName: appDisplayName.value + }).length + return Math.max(50, DIRECT_SMS_MAX_LENGTH - wrapperLen - 1) +}) + +const profanityHit = computed(() => findProfanity(previewMessage.value)) const canSubmit = computed( - () => message.value.trim().length > 0 && !profanityHit.value && !loading.value + () => + previewMessage.value.trim().length > 0 && + Boolean(bodyText.value) && + !profanityHit.value && + !previewOverLimit.value && + !loading.value ) watch( () => props.visible, async (open) => { if (!open) return - message.value = '' + activeTab.value = 'templates' + manualBody.value = '' + selectedTemplateKey.value = DIRECT_SMS_TEMPLATES[0]?.key ?? '' try { const rows = await getConfiguration() const list = Array.isArray(rows) ? rows : [] @@ -106,23 +235,20 @@ watch( appName.value = '' appUrl.value = '' } + // اگر قالب اول به لینک نیاز دارد و لینک نیست، اولین قالب قابلاستفاده را انتخاب کن + const firstOk = templates.find((t) => !isTemplateDisabled(t)) + if (firstOk) selectedTemplateKey.value = firstOk.key } ) -function appendSnippet(text: string) { - if (!text) return - const current = message.value - const needsSpace = current.length > 0 && !/\s$/.test(current) - message.value = current + (needsSpace ? ' ' : '') + text -} - function close() { visibleProxy.value = false } async function submit() { if (!props.customer?.id || !canSubmit.value) return - const hit = findProfanity(message.value) + const finalMessage = previewMessage.value.trim() + const hit = findProfanity(finalMessage) if (hit) { antMessage.error('متن حاوی محتوای نامناسب است') return @@ -131,7 +257,7 @@ async function submit() { loading.value = true await sendCustomerDirectSms({ customer_id: Number(props.customer.id), - message: message.value.trim() + message: finalMessage }) antMessage.success('پیامک ارسال شد') emit('sent')