feat: add html editor for telegram messages
This commit is contained in:
79
frontend/admin/package-lock.json
generated
79
frontend/admin/package-lock.json
generated
@@ -8,6 +8,7 @@
|
|||||||
"name": "admin",
|
"name": "admin",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@codemirror/lang-html": "^6.4.11",
|
||||||
"@codemirror/lang-json": "^6.0.2",
|
"@codemirror/lang-json": "^6.0.2",
|
||||||
"@codemirror/theme-one-dark": "^6.1.3",
|
"@codemirror/theme-one-dark": "^6.1.3",
|
||||||
"@formkit/drag-and-drop": "^0.5.3",
|
"@formkit/drag-and-drop": "^0.5.3",
|
||||||
@@ -572,6 +573,51 @@
|
|||||||
"@lezer/common": "^1.1.0"
|
"@lezer/common": "^1.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@codemirror/lang-css": {
|
||||||
|
"version": "6.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@codemirror/lang-css/-/lang-css-6.3.1.tgz",
|
||||||
|
"integrity": "sha512-kr5fwBGiGtmz6l0LSJIbno9QrifNMUusivHbnA1H6Dmqy4HZFte3UAICix1VuKo0lMPKQr2rqB+0BkKi/S3Ejg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@codemirror/autocomplete": "^6.0.0",
|
||||||
|
"@codemirror/language": "^6.0.0",
|
||||||
|
"@codemirror/state": "^6.0.0",
|
||||||
|
"@lezer/common": "^1.0.2",
|
||||||
|
"@lezer/css": "^1.1.7"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@codemirror/lang-html": {
|
||||||
|
"version": "6.4.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.4.11.tgz",
|
||||||
|
"integrity": "sha512-9NsXp7Nwp891pQchI7gPdTwBuSuT3K65NGTHWHNJ55HjYcHLllr0rbIZNdOzas9ztc1EUVBlHou85FFZS4BNnw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@codemirror/autocomplete": "^6.0.0",
|
||||||
|
"@codemirror/lang-css": "^6.0.0",
|
||||||
|
"@codemirror/lang-javascript": "^6.0.0",
|
||||||
|
"@codemirror/language": "^6.4.0",
|
||||||
|
"@codemirror/state": "^6.0.0",
|
||||||
|
"@codemirror/view": "^6.17.0",
|
||||||
|
"@lezer/common": "^1.0.0",
|
||||||
|
"@lezer/css": "^1.1.0",
|
||||||
|
"@lezer/html": "^1.3.12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@codemirror/lang-javascript": {
|
||||||
|
"version": "6.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@codemirror/lang-javascript/-/lang-javascript-6.2.4.tgz",
|
||||||
|
"integrity": "sha512-0WVmhp1QOqZ4Rt6GlVGwKJN3KW7Xh4H2q8ZZNGZaP6lRdxXJzmjm4FqvmOojVj6khWJHIb9sp7U/72W7xQgqAA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@codemirror/autocomplete": "^6.0.0",
|
||||||
|
"@codemirror/language": "^6.6.0",
|
||||||
|
"@codemirror/lint": "^6.0.0",
|
||||||
|
"@codemirror/state": "^6.0.0",
|
||||||
|
"@codemirror/view": "^6.17.0",
|
||||||
|
"@lezer/common": "^1.0.0",
|
||||||
|
"@lezer/javascript": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@codemirror/lang-json": {
|
"node_modules/@codemirror/lang-json": {
|
||||||
"version": "6.0.2",
|
"version": "6.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/lang-json/-/lang-json-6.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/lang-json/-/lang-json-6.0.2.tgz",
|
||||||
@@ -1547,6 +1593,17 @@
|
|||||||
"integrity": "sha512-L9X8uHCYU310o99L3/MpJKYxPzXPOS7S0NmBaM7UO/x2Kb2WbmMLSkfvdr1KxRIFYOpbY0Jhn7CfLSUDzL8arQ==",
|
"integrity": "sha512-L9X8uHCYU310o99L3/MpJKYxPzXPOS7S0NmBaM7UO/x2Kb2WbmMLSkfvdr1KxRIFYOpbY0Jhn7CfLSUDzL8arQ==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@lezer/css": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.3.0.tgz",
|
||||||
|
"integrity": "sha512-pBL7hup88KbI7hXnZV3PQsn43DHy6TWyzuyk2AO9UyoXcDltvIdqWKE1dLL/45JVZ+YZkHe1WVHqO6wugZZWcw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@lezer/common": "^1.2.0",
|
||||||
|
"@lezer/highlight": "^1.0.0",
|
||||||
|
"@lezer/lr": "^1.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@lezer/highlight": {
|
"node_modules/@lezer/highlight": {
|
||||||
"version": "1.2.3",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.3.tgz",
|
||||||
@@ -1556,6 +1613,28 @@
|
|||||||
"@lezer/common": "^1.3.0"
|
"@lezer/common": "^1.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@lezer/html": {
|
||||||
|
"version": "1.3.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@lezer/html/-/html-1.3.12.tgz",
|
||||||
|
"integrity": "sha512-RJ7eRWdaJe3bsiiLLHjCFT1JMk8m1YP9kaUbvu2rMLEoOnke9mcTVDyfOslsln0LtujdWespjJ39w6zo+RsQYw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@lezer/common": "^1.2.0",
|
||||||
|
"@lezer/highlight": "^1.0.0",
|
||||||
|
"@lezer/lr": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@lezer/javascript": {
|
||||||
|
"version": "1.5.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.5.4.tgz",
|
||||||
|
"integrity": "sha512-vvYx3MhWqeZtGPwDStM2dwgljd5smolYD2lR2UyFcHfxbBQebqx8yjmFmxtJ/E6nN6u1D9srOiVWm3Rb4tmcUA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@lezer/common": "^1.2.0",
|
||||||
|
"@lezer/highlight": "^1.1.3",
|
||||||
|
"@lezer/lr": "^1.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@lezer/json": {
|
"node_modules/@lezer/json": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@lezer/json/-/json-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/@lezer/json/-/json-1.0.3.tgz",
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
"format": "prettier --write src/"
|
"format": "prettier --write src/"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@codemirror/lang-html": "^6.4.11",
|
||||||
"@codemirror/lang-json": "^6.0.2",
|
"@codemirror/lang-json": "^6.0.2",
|
||||||
"@codemirror/theme-one-dark": "^6.1.3",
|
"@codemirror/theme-one-dark": "^6.1.3",
|
||||||
"@formkit/drag-and-drop": "^0.5.3",
|
"@formkit/drag-and-drop": "^0.5.3",
|
||||||
|
|||||||
133
frontend/admin/src/components/RichTextEditor.vue
Normal file
133
frontend/admin/src/components/RichTextEditor.vue
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
<template>
|
||||||
|
<div class="tw:space-y-2">
|
||||||
|
<textarea
|
||||||
|
ref="textareaRef"
|
||||||
|
class="form-control"
|
||||||
|
:placeholder="placeholder"
|
||||||
|
></textarea>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { onBeforeUnmount, onMounted, ref, watch } from "vue";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
placeholder: {
|
||||||
|
type: String,
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
height: {
|
||||||
|
type: Number,
|
||||||
|
default: 240,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const model = defineModel({
|
||||||
|
type: String,
|
||||||
|
default: "",
|
||||||
|
});
|
||||||
|
|
||||||
|
const textareaRef = ref(null);
|
||||||
|
const summernoteInstance = ref(null);
|
||||||
|
|
||||||
|
const getJQuery = () => window.$ || window.jQuery;
|
||||||
|
|
||||||
|
const normalizeTelegramHtml = (html = "") => {
|
||||||
|
const withoutEmptyParagraphs = html.replace(/<p><br><\/p>/gi, "<br>");
|
||||||
|
const withoutParagraphs = withoutEmptyParagraphs
|
||||||
|
.replace(/<p>/gi, "")
|
||||||
|
.replace(/<\/p>/gi, "<br>");
|
||||||
|
|
||||||
|
return withoutParagraphs.replace(/(?:<br>\s*)+$/i, "").trim();
|
||||||
|
};
|
||||||
|
|
||||||
|
const makeSpoilerButton = ($) => (context) => {
|
||||||
|
const ui = $.summernote.ui;
|
||||||
|
return ui
|
||||||
|
.button({
|
||||||
|
contents: '<i class="fa fa-eye-slash"></i>',
|
||||||
|
tooltip: "Спойлер (Telegram)",
|
||||||
|
click() {
|
||||||
|
const selectedText = context.invoke("editor.getSelectedText") || "";
|
||||||
|
const content = selectedText || "spoiler";
|
||||||
|
context.invoke(
|
||||||
|
"editor.pasteHTML",
|
||||||
|
`<span class="tg-spoiler">${content}</span>`
|
||||||
|
);
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.render();
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
const $ = getJQuery();
|
||||||
|
if (!$ || !textareaRef.value) {
|
||||||
|
console.warn("[RichTextEditor] jQuery или textarea недоступны");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const $el = $(textareaRef.value);
|
||||||
|
|
||||||
|
$el.summernote({
|
||||||
|
height: props.height,
|
||||||
|
placeholder: props.placeholder,
|
||||||
|
shortcuts: false,
|
||||||
|
dialogsInBody: true,
|
||||||
|
disableResizeEditor: true,
|
||||||
|
buttons: {
|
||||||
|
spoiler: makeSpoilerButton($),
|
||||||
|
},
|
||||||
|
toolbar: [
|
||||||
|
["font", ["bold", "underline", "italic", "strikethrough", "clear"]],
|
||||||
|
["para", ["ul", "ol", "paragraph"]],
|
||||||
|
["insert", ["link", "spoiler"]],
|
||||||
|
["view", ["fullscreen", "codeview", "help"]],
|
||||||
|
],
|
||||||
|
callbacks: {
|
||||||
|
onChange(contents) {
|
||||||
|
const normalized = normalizeTelegramHtml(contents ?? "");
|
||||||
|
if (normalized !== contents) {
|
||||||
|
$el.summernote("code", normalized);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
model.value = normalized;
|
||||||
|
},
|
||||||
|
onKeydown(e) {
|
||||||
|
if (e.keyCode === 13) {
|
||||||
|
e.preventDefault();
|
||||||
|
$el.summernote("pasteHTML", "<br>");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (model.value) {
|
||||||
|
$el.summernote("code", normalizeTelegramHtml(model.value));
|
||||||
|
}
|
||||||
|
|
||||||
|
summernoteInstance.value = $el;
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
model,
|
||||||
|
(value) => {
|
||||||
|
const instance = summernoteInstance.value;
|
||||||
|
if (!instance) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const normalized = normalizeTelegramHtml(value || "");
|
||||||
|
const current = normalizeTelegramHtml(instance.summernote("code"));
|
||||||
|
if (current !== normalized) {
|
||||||
|
instance.summernote("code", normalized);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
if (summernoteInstance.value) {
|
||||||
|
summernoteInstance.value.summernote("destroy");
|
||||||
|
summernoteInstance.value = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
@@ -2,12 +2,11 @@
|
|||||||
<SettingsItem :label="label">
|
<SettingsItem :label="label">
|
||||||
<template #default>
|
<template #default>
|
||||||
<div style="margin-bottom: 10px;">
|
<div style="margin-bottom: 10px;">
|
||||||
<textarea
|
<Codemirror
|
||||||
v-model="model"
|
v-model="model"
|
||||||
:rows="rows"
|
|
||||||
:placeholder="placeholder"
|
:placeholder="placeholder"
|
||||||
class="form-control"
|
:extensions="extensions"
|
||||||
></textarea>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
@@ -37,7 +36,12 @@
|
|||||||
|
|
||||||
<div class="collapse" :id="collapseId" style="margin-top: 15px">
|
<div class="collapse" :id="collapseId" style="margin-top: 15px">
|
||||||
<div class="well">
|
<div class="well">
|
||||||
<p>Вы можете использовать переменные:</p>
|
<p>
|
||||||
|
Для формирования сообщения используется HTML разметка.
|
||||||
|
Telegram поддерживает только часть HTML тегов, которые описаны в их
|
||||||
|
<a href="https://core.telegram.org/bots/api#html-style" target="_blank">документации <i class="fa fa-external-link"></i></a>.
|
||||||
|
</p>
|
||||||
|
<p>Дополнительно к этому TeleCart добавляет переменные, которые вы можете использовать, чтобы сделать сообщения динамическими.</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><code>{store_name}</code> — название магазина</li>
|
<li><code>{store_name}</code> — название магазина</li>
|
||||||
<li><code>{order_id}</code> — номер заказа</li>
|
<li><code>{order_id}</code> — номер заказа</li>
|
||||||
@@ -50,19 +54,7 @@
|
|||||||
<li><code>{ip}</code> — IP покупателя</li>
|
<li><code>{ip}</code> — IP покупателя</li>
|
||||||
<li><code>{created_at}</code> — дата и время создания заказа</li>
|
<li><code>{created_at}</code> — дата и время создания заказа</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p>
|
<p></p>
|
||||||
Форматирование: поддерживается
|
|
||||||
<a href="https://core.telegram.org/bots/api#markdownv2-style" target="_blank">
|
|
||||||
*MarkdownV2*
|
|
||||||
<i class="fa fa-external-link"></i>
|
|
||||||
</a>.
|
|
||||||
</p>
|
|
||||||
<p>Символы, которые нужно экранировать в тексте:</p>
|
|
||||||
<pre>_ * [ ] ( ) ~ ` > # + - = | { } . !</pre>
|
|
||||||
<p>
|
|
||||||
Каждый из них нужно экранировать обратным слэшем \, если он не используется для форматирования.
|
|
||||||
Например вместо <code>Заказ #123</code> нужно писать <code>Заказ \#123</code>.
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -78,11 +70,15 @@ import {useSettingsStore} from "@/stores/settings.js";
|
|||||||
import {ref, toRaw, useId} from "vue";
|
import {ref, toRaw, useId} from "vue";
|
||||||
import SettingsItem from "@/components/SettingsItem.vue";
|
import SettingsItem from "@/components/SettingsItem.vue";
|
||||||
import {apiPost} from "@/utils/http.js";
|
import {apiPost} from "@/utils/http.js";
|
||||||
|
import {Codemirror} from "vue-codemirror";
|
||||||
|
import { html } from '@codemirror/lang-html';
|
||||||
|
import { oneDark } from '@codemirror/theme-one-dark';
|
||||||
|
|
||||||
const model = defineModel();
|
const model = defineModel();
|
||||||
const settings = useSettingsStore();
|
const settings = useSettingsStore();
|
||||||
const isSending = ref(false);
|
const isSending = ref(false);
|
||||||
const collapseId = useId();
|
const collapseId = useId();
|
||||||
|
const extensions = [html(), oneDark];
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
label: {
|
label: {
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ class ControllerExtensionModuleTgshop extends Controller
|
|||||||
public function index(): void
|
public function index(): void
|
||||||
{
|
{
|
||||||
$this->runMaintenanceTasks();
|
$this->runMaintenanceTasks();
|
||||||
|
$this->injectAssets();
|
||||||
$this->injectVueJs();
|
$this->injectVueJs();
|
||||||
$this->showConfigPage();
|
$this->showConfigPage();
|
||||||
}
|
}
|
||||||
@@ -272,4 +273,10 @@ class ControllerExtensionModuleTgshop extends Controller
|
|||||||
|
|
||||||
return $log;
|
return $log;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function injectAssets(): void
|
||||||
|
{
|
||||||
|
$this->document->addScript('view/javascript/summernote/summernote.js');
|
||||||
|
$this->document->addStyle('view/javascript/summernote/summernote.css');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,4 +31,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<script type="text/javascript" src="view/javascript/summernote/summernote.js"></script>
|
||||||
|
<link href="view/javascript/summernote/summernote.css" rel="stylesheet" />
|
||||||
{{ footer }}
|
{{ footer }}
|
||||||
|
|||||||
@@ -69,9 +69,6 @@ class SendMessageHandler
|
|||||||
$this->telegramService->sendMessage(
|
$this->telegramService->sendMessage(
|
||||||
$telegramUserId,
|
$telegramUserId,
|
||||||
$message,
|
$message,
|
||||||
[],
|
|
||||||
\Openguru\OpenCartFramework\Telegram\Enums\ChatAction::TYPING,
|
|
||||||
'' // Обычный текст без форматирования
|
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->logger->info('Message sent to Telegram user', [
|
$this->logger->info('Message sent to Telegram user', [
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use Exception;
|
|||||||
use GuzzleHttp\Exception\ClientException;
|
use GuzzleHttp\Exception\ClientException;
|
||||||
use GuzzleHttp\Exception\GuzzleException;
|
use GuzzleHttp\Exception\GuzzleException;
|
||||||
use Openguru\OpenCartFramework\Cache\CacheInterface;
|
use Openguru\OpenCartFramework\Cache\CacheInterface;
|
||||||
|
use Openguru\OpenCartFramework\Telegram\Enums\ChatAction;
|
||||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||||
use Openguru\OpenCartFramework\Http\Request;
|
use Openguru\OpenCartFramework\Http\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
|||||||
@@ -15,33 +15,34 @@ return [
|
|||||||
'telegram' => [
|
'telegram' => [
|
||||||
"bot_token" => "",
|
"bot_token" => "",
|
||||||
"chat_id" => null,
|
"chat_id" => null,
|
||||||
"owner_notification_template" => <<<TEXT
|
"owner_notification_template" => <<<HTML
|
||||||
*Новый заказ \#{order_id}* в магазине *{store_name}*
|
📦 <b>Новый заказ №{order_id}</b>
|
||||||
|
Магазин: <b>{store_name}</b>
|
||||||
|
|
||||||
*Покупатель:* {customer}
|
<b>Покупатель</b>
|
||||||
*Email:* {email}
|
Имя: {customer}
|
||||||
*Телефон:* {phone}
|
Email: {email}
|
||||||
*IP:* {ip}
|
Телефон: {phone}
|
||||||
|
IP: {ip}
|
||||||
|
|
||||||
*Адрес доставки:*
|
<b>Комментарий к заказу</b>
|
||||||
{address}
|
|
||||||
|
|
||||||
*Комментарий:*
|
|
||||||
{comment}
|
{comment}
|
||||||
|
|
||||||
*Сумма заказа:* {total}
|
<b>Сумма заказа:</b> {total}
|
||||||
*Дата оформления:* {created_at}
|
<b>Дата оформления:</b> {created_at}
|
||||||
TEXT,
|
HTML,
|
||||||
"customer_notification_template" => <<<TEXT
|
"customer_notification_template" => <<<HTML
|
||||||
Спасибо за Ваш заказ в магазине *{store_name}*
|
✅ <b>Заказ оформлен</b>
|
||||||
|
|
||||||
*Номер заказа* \#{order_id}
|
Спасибо за ваш заказ в магазине <b>{store_name}</b>.
|
||||||
*Сумма заказа:* {total}
|
|
||||||
*Дата оформления:* {created_at}
|
|
||||||
|
|
||||||
Мы свяжемся с вами при необходимости\.
|
<b>Номер заказа:</b> №{order_id}
|
||||||
Хорошего дня\!
|
<b>Сумма заказа:</b> {total}р.
|
||||||
TEXT,
|
<b>Дата оформления:</b> {created_at}
|
||||||
|
|
||||||
|
Информация о заказе сохранена.
|
||||||
|
При необходимости с вами свяжутся представители магазина.
|
||||||
|
HTML,
|
||||||
"mini_app_url" => "",
|
"mini_app_url" => "",
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,6 @@ class StartCommand extends TelegramCommand
|
|||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->telegram->sendMessage($chatId, $message, $buttons, ChatAction::TYPING, 'html');
|
$this->telegram->sendMessage($chatId, $message, $buttons);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,21 +27,9 @@ class TelegramService
|
|||||||
$this->logger = $logger;
|
$this->logger = $logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function escapeTelegramMarkdownV2(string $text): string
|
|
||||||
{
|
|
||||||
$specials = ['_', '*', '[', ']', '(', ')', '~', '`', '>', '#', '+', '-', '=', '|', '{', '}', '.', '!'];
|
|
||||||
foreach ($specials as $char) {
|
|
||||||
$text = str_replace($char, '\\' . $char, $text);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $text;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function prepareMessage(string $template, array $variables = []): string
|
public function prepareMessage(string $template, array $variables = []): string
|
||||||
{
|
{
|
||||||
$values = array_map([$this, 'escapeTelegramMarkdownV2'], array_values($variables));
|
return str_replace(array_keys($variables), array_values($variables), $template);
|
||||||
|
|
||||||
return str_replace(array_keys($variables), $values, $template);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -54,7 +42,7 @@ class TelegramService
|
|||||||
string $text,
|
string $text,
|
||||||
array $replyMarkup = [],
|
array $replyMarkup = [],
|
||||||
string $chatAction = ChatAction::TYPING,
|
string $chatAction = ChatAction::TYPING,
|
||||||
string $parseMode = 'MarkdownV2'
|
string $parseMode = 'html'
|
||||||
): void {
|
): void {
|
||||||
if (! $this->botToken) {
|
if (! $this->botToken) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
Reference in New Issue
Block a user