page_hangye.html 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489
  1. {include file="header" /}
  2. {php}
  3. $cooperationContactPhone = '';
  4. $cooperationContactTel = '';
  5. foreach (['cooperation_phone', 'contact_phone', 'service_phone', 'phone', 'tel'] as $phoneConfigKey) {
  6. $phoneConfigValue = trim((string)config('site.' . $phoneConfigKey));
  7. if ($phoneConfigValue === '') {
  8. continue;
  9. }
  10. $phoneDigits = '';
  11. $phoneAllowed = true;
  12. $phoneTel = '';
  13. foreach (preg_split('//u', $phoneConfigValue, -1, PREG_SPLIT_NO_EMPTY) as $phoneChar) {
  14. if (ctype_digit($phoneChar)) {
  15. $phoneDigits .= $phoneChar;
  16. $phoneTel .= $phoneChar;
  17. continue;
  18. }
  19. if ($phoneChar === '+') {
  20. $phoneTel .= $phoneChar;
  21. continue;
  22. }
  23. if (!in_array($phoneChar, ['(', ')', '-', ' '], true)) {
  24. $phoneAllowed = false;
  25. break;
  26. }
  27. }
  28. if ($phoneAllowed && strlen($phoneDigits) >= 6 && mb_strlen($phoneConfigValue, 'UTF-8') <= 40) {
  29. $cooperationContactPhone = $phoneConfigValue;
  30. $cooperationContactTel = $phoneTel;
  31. break;
  32. }
  33. }
  34. {/php}
  35. <link rel="stylesheet" href="/assets/xtu/cooperation-topbar.css?v=20260508-5">
  36. <link rel="stylesheet" href="/assets/xtu/cooperation.css?v=20260508-15">
  37. <main class="cooperation-page" id="cooperationPage" style="--cooperation-bg:url('{$category.image|default='/assets/xtu/vendor/img/appbanner.jpg'}')">
  38. <div class="cooperation-topbar">
  39. <div class="cooperation-topbar-inner">
  40. <div class="cooperation-topbar-title">{$title|default=cms_t('cooperation_contact_title','联系我们')}</div>
  41. </div>
  42. </div>
  43. <div class="cooperation-shell">
  44. <section class="cooperation-copy">
  45. <div class="cooperation-bar-inner">
  46. <h1>{$title|default=cms_t('cooperation_contact_title','联系我们')}</h1>
  47. <p>{if getCategory($catid,'description')}{:getCategory($catid,'description')}{elseif !empty($category.description) /}{$category.description}{else /}{:cms_t('cooperation_intro','请填写以下信息,我们的商务团队将会尽快与您联系,结合您的行业场景提供产品、方案与合作支持。')}{/if}</p>
  48. </div>
  49. </section>
  50. <section class="cooperation-card" aria-labelledby="cooperationFormTitle">
  51. <div class="cooperation-card-head">
  52. <h2 id="cooperationFormTitle">{:cms_t('cooperation_contact_title','联系我们')}</h2>
  53. <p>{if getCategory($catid,'description')}{:getCategory($catid,'description')}{elseif !empty($category.description) /}{$category.description}{else /}{:cms_t('cooperation_intro','请填写以下信息,我们的商务团队将会尽快与您联系,结合您的行业场景提供产品、方案与合作支持。')}{/if}</p>
  54. </div>
  55. <form id="cooperationLeadForm" class="cooperation-form" data-options-url="{:url('index/cooperation/options')}" data-submit-url="{:url('index/cooperation/submit')}">
  56. <input type="hidden" name="lang" id="cooperationLang" value="{$site_lang|default='cn'}">
  57. <input type="hidden" name="source_page" id="cooperationSourcePage" value="">
  58. <input type="hidden" name="form_token" id="cooperationFormToken" value="{:md5(session_id().'cooperation_lead')}">
  59. <div class="cooperation-honeypot" aria-hidden="true"><input type="text" name="website" tabindex="-1" autocomplete="off" value=""></div>
  60. <div class="cooperation-form-grid">
  61. <div class="cooperation-field"><input type="text" name="name" placeholder="{:cms_t('cooperation_name_placeholder','姓名 *')}" maxlength="80" minlength="2" autocomplete="name" required></div>
  62. <div class="cooperation-field"><input type="tel" name="phone" placeholder="{:cms_t('cooperation_phone_placeholder','电话 *')}" maxlength="40" minlength="6" autocomplete="tel" inputmode="tel" pattern="[0-9+()\-\s]{6,40}" required></div>
  63. <div class="cooperation-field"><input type="email" name="email" placeholder="{:cms_t('cooperation_email_placeholder','电子邮箱 *')}" maxlength="120" autocomplete="email" required></div>
  64. <div class="cooperation-field"><input type="text" name="company" placeholder="{:cms_t('cooperation_company_placeholder','公司名称 *')}" maxlength="120" minlength="2" autocomplete="organization" required></div>
  65. <div class="cooperation-field">
  66. <select id="cooperationRegion" aria-label="{:cms_t('cooperation_region_label','洲/区域')}">
  67. <option value="">{:cms_t('cooperation_region_placeholder','洲/区域 *')}</option>
  68. </select>
  69. </div>
  70. <div class="cooperation-field">
  71. <select name="country" id="cooperationCountry" aria-label="{:cms_t('cooperation_country_label','国家/地区')}" required disabled>
  72. <option value="">{:cms_t('cooperation_country_placeholder','国家/地区 *')}</option>
  73. </select>
  74. </div>
  75. <div class="cooperation-field is-full">
  76. <select name="industry" id="cooperationIndustry" aria-label="{:cms_t('cooperation_industry_label','行业')}" required>
  77. <option value="">{:cms_t('cooperation_industry_placeholder','行业 *')}</option>
  78. </select>
  79. </div>
  80. <div class="cooperation-field is-full">
  81. <textarea name="content" id="cooperationContent" placeholder="{:cms_t('cooperation_content_placeholder','咨询内容 *')}" maxlength="300" required></textarea>
  82. <span class="cooperation-count" id="cooperationContentCount">0/300</span>
  83. </div>
  84. <div class="cooperation-field is-full" id="cooperationCaptchaWrap" style="display:none;">
  85. <input type="hidden" id="cooperationCaptchaNeed" value="{$need_captcha|default=0}">
  86. <label class="screen-reader-text" for="cooperationCaptchaInput">{:cms_t('cooperation_captcha_label','验证码 *')}</label>
  87. <div class="cooperation-captcha-row">
  88. <input type="text" name="verify" id="cooperationCaptchaInput" placeholder="{:cms_t('cooperation_captcha_placeholder','请输入验证码')}" maxlength="6" autocomplete="off">
  89. <a href="javascript:;" class="cooperation-captcha-img-wrap" id="cooperationCaptchaImageLink" aria-label="{:cms_t('cooperation_refresh_captcha','刷新验证码')}"><img src="" alt="{:cms_t('cooperation_captcha_label','验证码')}" id="cooperationCaptchaImage"></a>
  90. </div>
  91. </div>
  92. <div class="cooperation-checks">
  93. <label><input type="checkbox" name="privacy_agree" value="1" required><span>{:cms_t('cooperation_privacy_prefix','已阅读并同意')}<a href="{:getCategory(44,'url')}" target="_blank" rel="noopener">{:cms_t('cooperation_privacy_link','《隐私政策》')}</a></span></label>
  94. </div>
  95. <button class="cooperation-submit" id="cooperationSubmitBtn" type="submit">{:cms_t('cooperation_submit','提交信息')}</button>
  96. <div class="cooperation-message" id="cooperationMessage" role="status" aria-live="polite"></div>
  97. <div class="cooperation-contact">
  98. {if condition="$cooperationContactPhone neq ''"}
  99. <a href="tel:{$cooperationContactTel}" class="cooperation-contact-link"><i class="bi bi-telephone"></i> {$cooperationContactPhone}</a>
  100. {/if}
  101. </div>
  102. </form>
  103. </section>
  104. </div>
  105. </main>
  106. {if condition="!empty($content)"}
  107. <section class="cooperation-content">
  108. <div class="cooperation-content-inner">{$content|raw}</div>
  109. </section>
  110. {/if}
  111. <script>
  112. document.body.classList.add('cooperation-page-body');
  113. (function () {
  114. const siteHeader = document.getElementById('siteHeader');
  115. const syncTopbarPosition = function () {
  116. if (!siteHeader) return;
  117. const headerRect = siteHeader.getBoundingClientRect();
  118. document.documentElement.style.setProperty('--xtu-header-height', Math.max(0, Math.ceil(headerRect.bottom)) + 'px');
  119. };
  120. syncTopbarPosition();
  121. window.addEventListener('load', syncTopbarPosition);
  122. window.addEventListener('resize', syncTopbarPosition);
  123. window.addEventListener('scroll', syncTopbarPosition, { passive: true });
  124. if (window.ResizeObserver && siteHeader) {
  125. new ResizeObserver(syncTopbarPosition).observe(siteHeader);
  126. }
  127. })();
  128. (function () {
  129. const form = document.getElementById('cooperationLeadForm');
  130. if (!form) return;
  131. const regionSelect = document.getElementById('cooperationRegion');
  132. const countrySelect = document.getElementById('cooperationCountry');
  133. const industrySelect = document.getElementById('cooperationIndustry');
  134. const langInput = document.getElementById('cooperationLang');
  135. const sourcePageInput = document.getElementById('cooperationSourcePage');
  136. const submitBtn = document.getElementById('cooperationSubmitBtn');
  137. const messageBox = document.getElementById('cooperationMessage');
  138. const contentInput = document.getElementById('cooperationContent');
  139. const contentCount = document.getElementById('cooperationContentCount');
  140. const optionsUrl = form.getAttribute('data-options-url') || '/index/cooperation/options';
  141. const submitUrl = form.getAttribute('data-submit-url') || '/index/cooperation/submit';
  142. let countryTree = [];
  143. const text = {
  144. region: {:json_encode(cms_t('cooperation_region_placeholder','洲/区域 *'), JSON_UNESCAPED_UNICODE)},
  145. country: {:json_encode(cms_t('cooperation_country_placeholder','国家/地区 *'), JSON_UNESCAPED_UNICODE)},
  146. industry: {:json_encode(cms_t('cooperation_industry_placeholder','行业 *'), JSON_UNESCAPED_UNICODE)},
  147. loading: {:json_encode(cms_t('cooperation_loading','选项加载中...'), JSON_UNESCAPED_UNICODE)},
  148. required: {:json_encode(cms_t('cooperation_required','请完整填写必填信息,并同意隐私政策'), JSON_UNESCAPED_UNICODE)},
  149. invalidEmail: {:json_encode(cms_t('cooperation_invalid_email','请输入正确的电子邮箱'), JSON_UNESCAPED_UNICODE)},
  150. invalidPhone: {:json_encode(cms_t('cooperation_invalid_phone','请输入正确的电话号码,可包含数字、+、-、空格和括号'), JSON_UNESCAPED_UNICODE)},
  151. invalidEmailHint: {:json_encode(cms_t('cooperation_invalid_email_hint','请输入正确的电子邮箱格式,如 name@example.com'), JSON_UNESCAPED_UNICODE)},
  152. tooLong: {:json_encode(cms_t('cooperation_content_too_long','咨询内容请控制在 300 字以内'), JSON_UNESCAPED_UNICODE)},
  153. fieldTooLong: {:json_encode(cms_t('cooperation_field_too_long','输入内容超过长度限制'), JSON_UNESCAPED_UNICODE)},
  154. captchaHint: {:json_encode(cms_t('cooperation_captcha_hint','当前提交较频繁,请先完成验证码'), JSON_UNESCAPED_UNICODE)},
  155. captchaLabel: {:json_encode(cms_t('cooperation_captcha_label','验证码 *'), JSON_UNESCAPED_UNICODE)},
  156. captchaPlaceholder: {:json_encode(cms_t('cooperation_captcha_placeholder','请输入验证码'), JSON_UNESCAPED_UNICODE)},
  157. refreshCaptcha: {:json_encode(cms_t('cooperation_refresh_captcha','刷新验证码'), JSON_UNESCAPED_UNICODE)},
  158. captchaError: {:json_encode(cms_t('cooperation_captcha_error','验证码错误,请重新输入'), JSON_UNESCAPED_UNICODE)},
  159. sending: {:json_encode(cms_t('cooperation_sending','正在提交...'), JSON_UNESCAPED_UNICODE)},
  160. success: {:json_encode(cms_t('cooperation_success','提交成功,我们将尽快与您联系'), JSON_UNESCAPED_UNICODE)},
  161. failed: {:json_encode(cms_t('cooperation_failed','提交失败,请稍后再试'), JSON_UNESCAPED_UNICODE)},
  162. optionsFailed: {:json_encode(cms_t('cooperation_options_failed','选项加载失败,请刷新页面重试'), JSON_UNESCAPED_UNICODE)}
  163. };
  164. function normalizeLang(value) {
  165. const lang = String(value || 'cn').toLowerCase();
  166. if (lang === 'zh-cn' || lang === 'zh' || lang === 'cn') return 'cn';
  167. if (lang.indexOf('en') === 0) return 'en';
  168. return lang;
  169. }
  170. function setMessage(msg, type) {
  171. if (!messageBox) return;
  172. messageBox.textContent = msg || '';
  173. messageBox.className = 'cooperation-message' + (type ? ' is-' + type : '');
  174. }
  175. function showSuccessModal(message) {
  176. let modal = document.getElementById('cooperationSuccessModal');
  177. if (!modal) {
  178. modal = document.createElement('div');
  179. modal.id = 'cooperationSuccessModal';
  180. modal.className = 'custom-modal custom-modal-cooperation-success';
  181. modal.setAttribute('aria-hidden', 'true');
  182. modal.innerHTML = '<div class="custom-modal-dialog cooperation-success-modal-dialog"><div class="custom-modal-box cooperation-success-modal-box"><button class="custom-modal-close" type="button" data-close-modal="cooperationSuccessModal" aria-label="关闭">×</button><div class="cooperation-success-icon"><i class="bi bi-check2-circle"></i></div><h3 class="cooperation-success-title">提交成功</h3><p class="cooperation-success-text"></p><div class="cooperation-success-actions"><button type="button" class="cooperation-success-btn" data-close-modal="cooperationSuccessModal">知道了</button></div></div></div>';
  183. document.body.appendChild(modal);
  184. modal.addEventListener('click', function (e) {
  185. if (e.target === modal) closeSuccessModal();
  186. });
  187. }
  188. const textNode = modal.querySelector('.cooperation-success-text');
  189. if (textNode) textNode.textContent = message || text.success;
  190. modal.classList.add('is-open');
  191. modal.setAttribute('aria-hidden', 'false');
  192. document.body.classList.add('modal-open');
  193. modal.querySelector('.cooperation-success-btn')?.focus();
  194. }
  195. function closeSuccessModal() {
  196. const modal = document.getElementById('cooperationSuccessModal');
  197. if (!modal) return;
  198. modal.classList.remove('is-open');
  199. modal.setAttribute('aria-hidden', 'true');
  200. if (!document.querySelector('.custom-modal.is-open') && !document.querySelector('.header-inline-search.is-open')) {
  201. document.body.classList.remove('modal-open');
  202. }
  203. }
  204. document.addEventListener('click', function (e) {
  205. const closeBtn = e.target.closest && e.target.closest('[data-close-modal="cooperationSuccessModal"]');
  206. if (closeBtn) {
  207. e.preventDefault();
  208. closeSuccessModal();
  209. }
  210. });
  211. document.addEventListener('keydown', function (e) {
  212. if (e.key === 'Escape') closeSuccessModal();
  213. });
  214. function safeText(value) {
  215. return String(value == null ? '' : value);
  216. }
  217. function syncSelectState(select) {
  218. if (!select) return;
  219. select.classList.toggle('is-placeholder', !select.value);
  220. }
  221. function showCaptcha(force) {
  222. const wrap = document.getElementById('cooperationCaptchaWrap');
  223. const input = document.getElementById('cooperationCaptchaInput');
  224. const image = document.getElementById('cooperationCaptchaImage');
  225. const link = document.getElementById('cooperationCaptchaImageLink');
  226. if (!wrap || !input || !image) return;
  227. wrap.style.display = force ? '' : 'none';
  228. input.required = !!force;
  229. if (force && image.src.indexOf('/captcha') === -1) {
  230. image.src = '/index/cooperation/captcha?t=' + Date.now();
  231. }
  232. if (link) {
  233. link.onclick = function () {
  234. image.src = '/index/cooperation/captcha?t=' + Date.now();
  235. return false;
  236. };
  237. }
  238. }
  239. function resetSelect(select, placeholder) {
  240. if (!select) return;
  241. select.innerHTML = '';
  242. const option = document.createElement('option');
  243. option.value = '';
  244. option.textContent = placeholder;
  245. option.disabled = true;
  246. option.selected = true;
  247. select.appendChild(option);
  248. syncSelectState(select);
  249. }
  250. function appendOption(select, value, label) {
  251. if (!select) return;
  252. const option = document.createElement('option');
  253. option.value = safeText(value || label);
  254. option.textContent = safeText(label || value);
  255. select.appendChild(option);
  256. }
  257. function fillCountries(regionValue) {
  258. resetSelect(countrySelect, text.country);
  259. const region = countryTree.find(function (item) {
  260. return String(item.value || item.title || '') === String(regionValue || '');
  261. });
  262. const countries = region && Array.isArray(region.children) ? region.children : [];
  263. countries.forEach(function (item) {
  264. appendOption(countrySelect, item.value, item.title || item.name || item.value);
  265. });
  266. if (countrySelect) {
  267. countrySelect.disabled = !countries.length;
  268. syncSelectState(countrySelect);
  269. }
  270. }
  271. async function loadOptions() {
  272. const lang = normalizeLang(langInput ? langInput.value : 'cn');
  273. if (langInput) langInput.value = lang;
  274. resetSelect(regionSelect, text.loading);
  275. resetSelect(countrySelect, text.country);
  276. resetSelect(industrySelect, text.loading);
  277. if (countrySelect) countrySelect.disabled = true;
  278. try {
  279. const url = optionsUrl + (optionsUrl.indexOf('?') >= 0 ? '&' : '?') + 'lang=' + encodeURIComponent(lang);
  280. const res = await fetch(url, { headers: { 'X-Requested-With': 'XMLHttpRequest' } });
  281. const data = await res.json();
  282. if (data.code !== 1) throw new Error(data.msg || 'options failed');
  283. const payload = data.data || {};
  284. countryTree = Array.isArray(payload.country_tree) ? payload.country_tree : [];
  285. if (Number(payload.need_captcha || 0) === 1) {
  286. showCaptcha(true);
  287. }
  288. resetSelect(regionSelect, text.region);
  289. countryTree.forEach(function (region) {
  290. appendOption(regionSelect, region.value, region.title || region.name || region.value);
  291. });
  292. resetSelect(industrySelect, text.industry);
  293. (Array.isArray(payload.industries) ? payload.industries : []).forEach(function (item) {
  294. appendOption(industrySelect, item.value, item.title || item.name || item.value);
  295. });
  296. } catch (err) {
  297. resetSelect(regionSelect, text.region);
  298. resetSelect(industrySelect, text.industry);
  299. setMessage(text.optionsFailed, 'error');
  300. }
  301. }
  302. if (regionSelect) {
  303. regionSelect.addEventListener('change', function () {
  304. syncSelectState(regionSelect);
  305. fillCountries(regionSelect.value);
  306. });
  307. }
  308. [countrySelect, industrySelect].forEach(function (select) {
  309. if (!select) return;
  310. select.addEventListener('change', function () {
  311. syncSelectState(select);
  312. });
  313. });
  314. function focusField(input) {
  315. if (!input) return;
  316. input.scrollIntoView({ behavior: 'smooth', block: 'center' });
  317. input.focus({ preventScroll: true });
  318. }
  319. function updateContentCount() {
  320. if (!contentInput || !contentCount) return;
  321. const max = Number(contentInput.getAttribute('maxlength') || 300);
  322. const current = contentInput.value.length;
  323. contentCount.textContent = current + '/' + max;
  324. contentCount.style.color = current > max * 0.9 ? '#d92d20' : '#98a2b3';
  325. }
  326. function isValidEmail(value) {
  327. const email = String(value || '').trim();
  328. if (!email || email.length > 120) return false;
  329. return /^[A-Za-z0-9.!#$%&'*+/=?^_`{|}~-]+@[A-Za-z0-9-]+(?:\.[A-Za-z0-9-]+)+$/.test(email);
  330. }
  331. function isValidPhone(value) {
  332. const phone = String(value || '').trim();
  333. if (phone.length < 6 || phone.length > 40) return false;
  334. if (!/^[0-9+()\-\s]+$/.test(phone)) return false;
  335. const digits = phone.replace(/\D/g, '');
  336. return digits.length >= 6;
  337. }
  338. function isWithinMaxLength(input) {
  339. if (!input) return true;
  340. const max = Number(input.getAttribute('maxlength') || 0);
  341. return !max || String(input.value || '').length <= max;
  342. }
  343. function limitInputLength(input) {
  344. if (!input) return;
  345. const max = Number(input.getAttribute('maxlength') || 0);
  346. if (max > 0 && input.value.length > max) {
  347. input.value = input.value.slice(0, max);
  348. }
  349. }
  350. Array.prototype.forEach.call(form.querySelectorAll('input[maxlength], textarea[maxlength]'), function (input) {
  351. input.addEventListener('input', function () {
  352. limitInputLength(input);
  353. if (input === contentInput) updateContentCount();
  354. });
  355. });
  356. if (contentInput) {
  357. contentInput.addEventListener('input', updateContentCount);
  358. updateContentCount();
  359. }
  360. form.addEventListener('submit', async function (e) {
  361. e.preventDefault();
  362. const emailInput = form.querySelector('input[name="email"]');
  363. const phoneInput = form.querySelector('input[name="phone"]');
  364. const privacyInput = form.querySelector('input[name="privacy_agree"]');
  365. const email = emailInput ? emailInput.value.trim() : '';
  366. const phone = phoneInput ? phoneInput.value.trim() : '';
  367. if (!form.checkValidity() || !privacyInput || !privacyInput.checked) {
  368. form.reportValidity && form.reportValidity();
  369. setMessage(text.required, 'error');
  370. return;
  371. }
  372. const captchaWrap = document.getElementById('cooperationCaptchaWrap');
  373. const captchaInput = document.getElementById('cooperationCaptchaInput');
  374. if (captchaWrap && captchaWrap.style.display !== 'none' && (!captchaInput || !captchaInput.value.trim())) {
  375. focusField(captchaInput);
  376. setMessage(text.captchaHint, 'error');
  377. return;
  378. }
  379. if (captchaInput && captchaInput.value) captchaInput.value = captchaInput.value.trim();
  380. const lengthLimitedInputs = Array.prototype.slice.call(form.querySelectorAll('input[maxlength], textarea[maxlength]'));
  381. for (let i = 0; i < lengthLimitedInputs.length; i += 1) {
  382. if (!isWithinMaxLength(lengthLimitedInputs[i])) {
  383. focusField(lengthLimitedInputs[i]);
  384. setMessage(text.fieldTooLong, 'error');
  385. return;
  386. }
  387. }
  388. if (!isValidPhone(phone)) {
  389. focusField(phoneInput);
  390. setMessage(text.invalidPhone, 'error');
  391. return;
  392. }
  393. if (!isValidEmail(email)) {
  394. focusField(emailInput);
  395. setMessage(text.invalidEmailHint || text.invalidEmail, 'error');
  396. return;
  397. }
  398. if (contentInput && contentInput.value.length > 300) {
  399. focusField(contentInput);
  400. setMessage(text.tooLong, 'error');
  401. return;
  402. }
  403. ['name', 'phone', 'email', 'company'].forEach(function (name) {
  404. const input = form.querySelector('[name="' + name + '"]');
  405. if (input) input.value = input.value.trim();
  406. });
  407. if (contentInput) contentInput.value = contentInput.value.trim();
  408. if (sourcePageInput) sourcePageInput.value = window.location.href;
  409. if (submitBtn) submitBtn.disabled = true;
  410. setMessage(text.sending, 'loading');
  411. try {
  412. const body = new URLSearchParams(new FormData(form));
  413. const res = await fetch(submitUrl, {
  414. method: 'POST',
  415. headers: {
  416. 'X-Requested-With': 'XMLHttpRequest',
  417. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
  418. },
  419. body: body.toString()
  420. });
  421. const data = await res.json();
  422. if (data.code === 1) {
  423. form.reset();
  424. updateContentCount();
  425. resetSelect(countrySelect, text.country);
  426. if (countrySelect) {
  427. countrySelect.disabled = true;
  428. syncSelectState(countrySelect);
  429. }
  430. showCaptcha(false);
  431. const successMessage = data.msg || text.success;
  432. setMessage('', '');
  433. showSuccessModal(successMessage);
  434. } else {
  435. if ((data.data && Number(data.data.need_captcha || 0) === 1) || String(data.msg || '').indexOf(text.captchaError) >= 0) {
  436. showCaptcha(true);
  437. }
  438. setMessage(data.msg || text.failed, 'error');
  439. }
  440. } catch (err) {
  441. setMessage(text.failed, 'error');
  442. } finally {
  443. if (submitBtn) submitBtn.disabled = false;
  444. }
  445. });
  446. loadOptions();
  447. })();
  448. </script>
  449. {include file="footer-links" /}
  450. {include file="footer" /}