1// åºå·æ°æ®:æ£å¸¸é¡µé¢ç± form.html åæ¥æ³¨å ¥ window.countryCallingCodes; 2// å½ä¸æ§ç¼å HTML(æ²¡ææ°æ®èæ¬æ ç¾)æ¶,ç± ensureCallingCodes() 卿å è½½èªæ 3let _callingCodesPromise = null 4function ensureCallingCodes() { 5 if (window.countryCallingCodes && window.countryCallingCodes.length) return Promise.resolve() 6 if (!_callingCodesPromise) { 7 _callingCodesPromise = new Promise((resolve) => { 8 const ver = document.documentElement.getAttribute('data-app-version') 9 const script = document.createElement('script') 10 script.src = '/assets/js/unit/country-calling-codes.js' + (ver ? '?v=' + ver : '') 11 script.onload = resolve 12 script.onerror = () => resolve() // å è½½å¤±è´¥ä¹æ¾è¡,åç»èµ°ç©ºæ°æ® +86 å åº 13 document.head.appendChild(script) 14 }) 15 } 16 return _callingCodesPromise 17} 18 19// å ¨å±ç¼åï¼é²æ¢é¡µé¢å¤ä¸ªè¯¢çç»ä»¶éå¤è¯·æ± IP ä¿¡æ¯ 20let _ipInfoPromise = null // å ±äº«ç Promiseï¼ç¡®ä¿åªåèµ·ä¸æ¬¡è¯·æ± 21let _cachedAreaCode = null // ç¼åå¹é å°ççµè¯åºå·ï¼å¦ +86ï¼ 22class ScriptForm extends Script { 23 constructor(params) { 24 super(params) 25 this.formType = params.formType 26 this.is_inquiry_captcha = Number(params.is_inquiry_captcha) || 0 27 this.$form = document.querySelector(`#inquiry-${this.attrId}`) 28 if (!this.$form) throw new Error('$form not found') 29 this.$submit = this.$form.querySelector('.base-button__inner') 30 this.$file = this.$form.querySelector('[type="file"]') 31 this.$file_box = this.$form.querySelector('.unit-form__control--file') 32 this.$file_list = this.$form.querySelector('.unit-form__file-list') 33 this.file_config = [] 34 this.is_record_input = false 35 this.is_record_submit = false 36 this.utils = Utilts.ins() 37 38 } 39 /** åå§åï¼æ¯æå¼æ¥ */ 40 async init() { 41 this._initTel() 42 this._fix() 43 this._initCheckboxGroup() 44 this._initDropdownList() 45 this._observeFormVisible() 46 this._initInquiry() 47 // console.log('init') 48 } 49 // ä½¿ç¨ IntersectionObserver æå è½½ï¼è¡¨åè¿å ¥è§å£åæè¯·æ± IP ä¿¡æ¯ 50 _observeFormVisible() { 51 if (!this.$form) return 52 // console.log('form', this.$form) 53 const observer = new IntersectionObserver((entries) => { 54 entries.forEach(entry => { 55 // console.log('entry', entry) 56 if (entry.isIntersecting) { 57 this._getIpInfo() 58 observer.disconnect() 59 } 60 }) 61 }, { threshold: 0 }) 62 observer.observe(this.$form) 63 } 64 _initTel() { 65 const phoneList = this.$form.querySelectorAll('[name="phone"]') 66 // åå¨å¾ åå§åççµè¯æ¡æ¶æç¡®ä¿åºå·æ°æ®å¯ç¨,é¿å æ çµè¯å段ç页é¢åèµ·æ°æ®å è½½ 67 const needInit = Array.from(phoneList).some(dom => 68 dom.classList.contains('phone-input') && !dom.parentElement?.querySelector('.area-code-display') 69 ) 70 if (!needInit) return 71 ensureCallingCodes().then(() => { 72 phoneList.forEach((inputDom, index) => { 73 if (!inputDom.classList.contains('phone-input')) return 74 const has = !!inputDom.parentElement?.querySelector('.area-code-display'); 75 if(has) return 76 const displaySelectDom = Object.assign(document.createElement('div'), { 77 className: 'unit-form__control form-control phone-area-code area-code-display dropdown-toggle', 78 textContent: '+86' 79 }) 80 const selectDom = Object.assign(document.createElement('select'), { 81 className: 'phone-area-code unit-form__control form-control area-code-select', 82 name: 'phone-area-code' 83 }) 84 ;(window.countryCallingCodes || []).forEach(item => { 85 const option = document.createElement('option'); 86 option.value = item.code; 87 option.textContent = `ï¼${item.code}ï¼ ${window.app.utilts.$t(item.name)}`; 88 selectDom.appendChild(option) 89 }) 90 selectDom.addEventListener('change', function(event) { 91 displaySelectDom.innerText = event.target.value 92 }) 93 inputDom.classList.add('phone-input') 94 inputDom.before(displaySelectDom, selectDom) 95 // ä¼å 使ç¨å·²ç¼åçåºå·ï¼å åæ sessionStorageï¼ï¼å¦åé»è®¤ +86 96 selectDom.value = _cachedAreaCode || sessionStorage.getItem('areaCode') || '+86' 97 displaySelectDom.textContent = _cachedAreaCode || sessionStorage.getItem('areaCode') || '+86' 98 }) 99 }) 100 } 101 _fix() { 102 console.log(`this.formType`, this.formType); 103 if (this.formType === 'subscription') return 104 let hasContent = false 105 this.$form.querySelectorAll('textarea').forEach(item => { 106 if (item.getAttribute('name') === 'content') hasContent = true 107 }) 108 109 if (!hasContent) { 110 console.log(43, this.$form.querySelector('.unit-form__item.unit-form__item-submit')); 111 this.$form.querySelector('.unit-form__item.unit-form__item-submit').outerHTML = `<div text-style="3" class="follow-font-family_size unit-form__item form-group col-12 "> 112 <label class="unit-form__item-inner "> 113 114 <textarea class="unit-form__control form-control" rows="5" name="content" data-title="content" maxlength="65530" placeholder="content" required="required" minlength="1"></textarea> 115 <div class="invalid-feedback">textarea must not exceed 65530 in length!</div> 116
117 <span class="unit-form__label col-form-label">${this.utils.$t('content')}</span> 118 </label> 119 </div>` + this.$form.querySelector('.unit-form__item.unit-form__item-submit').outerHTML 120 } 121 } 122 _initCheckboxGroup(){ 123 this.$form.addEventListener('click', function(evt){ 124 if (evt.target.classList.contains('unit-form__checkbox-list-inner')) { 125 evt.stopPropagation() 126 evt.preventDefault() 127 return false 128 } 129 const elem = evt.target.closest('.unit-form__checkbox-inner') 130 if (elem) { 131 evt.stopPropagation() 132 const checkbox = elem.querySelector('input[type="checkbox"]') 133 if(checkbox && evt.target !== checkbox){ 134 evt.preventDefault() 135 checkbox.checked = !checkbox.checked 136 } 137 } else if (evt.target.closest('.unit-form__checkbox-list')) { 138 evt.preventDefault() 139 } 140 }) 141 } 142 143 _initDropdownList() { 144 var _t = this; 145 const dropdownList = this.$form.querySelectorAll('.dropdown') 146 const showMap = new WeakMap() 147 function showDropdownMenu(dropdownMenu, show) { 148 if (show) { 149 dropdownMenu.classList.add('show') 150 showMap.set(dropdownMenu, true) 151 } else { 152 dropdownMenu.classList.remove('show') 153 showMap.set(dropdownMenu, false) 154 } 155 } 156 document.addEventListener('click', function (evt) { 157 let elem = evt.target.closest('.dropdown') 158 dropdownList.forEach(function (dropdown) { 159 if (dropdown && elem !== dropdown) { 160 const dropdownMenu = dropdown.querySelector('.dropdown-menu') 161 // dropdownMenu.classList.remove('show') 162 showDropdownMenu(dropdownMenu, false) 163 } 164 }) 165 }) 166 dropdownList.forEach(function (dropdown) { 167 const dropdownToggle = dropdown.querySelector('.dropdown-toggle') 168 const dropdownMenu = dropdown.querySelector('.dropdown-menu') 169 if (dropdownToggle && dropdownMenu) { 170 const input = dropdown.querySelector('input.form-control') 171 const popperInstance = Popper.createPopper(dropdownToggle, dropdownMenu, { 172 placement: 'bottom', 173 strategy: 'absolute', 174 adaptive: false, 175 roundOffsets: false, 176 modifiers: [ 177 { 178 name: 'computeStyles', 179 options: { 180 roundOffsets: ({ x, y }) => ({ 181 x: 0, 182 y: input.parentNode.offsetHeight || 47, 183 }), 184 }, 185 }, 186 ], 187 }) 188 dropdownToggle.addEventListener('click', function () { 189 // dropdownMenu.classList.toggle('show') 190 showDropdownMenu(dropdownMenu, !showMap.get(dropdownMenu)) // é¿å ç§»å¨ç«¯ show æ·»å åç§»é¤ 191 popperInstance.update() // 触åéæ°è®¡ç®å®ä½ 192 }) 193 dropdownMenu.addEventListener('click', function (evt) { 194 if (evt.target.classList.contains('dropdown-item')) { 195 evt.stopPropagation() 196 evt.preventDefault() 197 if (input&&!(evt.target.classList.contains('multi_select'))) { 198 input.value = evt.target.innerText 199 } 200 // dropdownMenu.classList.remove('show') 201 showDropdownMenu(dropdownMenu, false) 202 } 203 if (evt.target.classList.contains('multi_select')) { 204 evt.stopPropagation() 205 evt.preventDefault() 206 if(evt.target.classList.contains('current_multi_select')){ 207 evt.target.classList.remove('current_multi_select') 208 }else{ 209 evt.target.classList.add('current_multi_select') 210 } 211 input.style.color = 'transparent' 212 updateTags(dropdownMenu,input) 213 } 214 }) 215 var multiListInpur = dropdownMenu.querySelectorAll('input[type="checkbox"]') 216 if(multiListInpur){ 217 multiListInpur.forEach((checkbox)=>{ 218 checkbox.addEventListener('click', function (evt) { 219 if(checkbox.parentNode.classList.contains('current_multi_select')){ 220 checkbox.parentNode.classList.remove('current_multi_select') 221 }else{ 222 checkbox.parentNode.classList.add('current_multi_select') 223 } 224 updateTags(dropdownMenu,input) 225 }) 226 }) 227 } 228 // multiListInpur?.map.addEventListener('click', function (evt) { 229 // console.log(evt) 230 // }) 231 } 232 }) 233 function updateTags(dropdown,input) { 234 const $tags_wrap = dropdown.parentNode.querySelector('.multi_select__tags-wrap') 235 const $tags = dropdown.parentNode.querySelector('.multi_select__tags') 236 const $rest = $tags_wrap.querySelector('.multi_select__tags-rest') 237 $rest.classList.add('d-none') 238 let multiList = Array.from(dropdown.querySelectorAll('.multi_select')).forEac
238h(a=>{ 239 a.querySelector('input').checked = false; 240 }) 241 let list = Array.from(dropdown.querySelectorAll('.current_multi_select')) 242 input.value = '' 243 $tags.innerHTML = list?.map(it => { 244 input.value = input.value + it.title+',' 245 it.querySelector('input').checked = true; 246 return `<div class="multi_select__tag"> 247 <div class="multi_select__tag-inner"> 248 <span class="multi_select__tag-text">${it.title}</span><i class="multi_select__tag-close iconfont icon-action-close-2"></i> 249 </div> 250 </div>` 251 }).join('') || ''; 252 253 let tagsSelect =Array.from($tags.querySelectorAll('.multi_select__tag-inner')) 254 tagsSelect.forEach(tag=>{ 255 256 var multiSelectClose = tag.querySelector('.multi_select__tag-close') 257 multiSelectClose.addEventListener('click',function(evt){ 258 evt.stopPropagation() 259 evt.preventDefault() 260 let title = tag.querySelector('.multi_select__tag-text').innerText 261 list?.map(it => { 262 if(it.title.trim().toLowerCase() == title.trim().toLowerCase()){ 263 it?.click() 264 } 265 }) 266 }) 267 }) 268 // 强å¶ä¸è¡ çç¥åç»æ ç¾------------------------------------------------------------ 269 const $tag_list = $tags.querySelectorAll('.multi_select__tag-inner') 270 const wrapRight = $tags_wrap.getBoundingClientRect().right 271 let hideCount = 0 272 for (let i = $tag_list.length-1; i >= 1; i--) { 273 const item = $tag_list[i]; 274 const rect = item.getBoundingClientRect(); 275 if (rect.right > wrapRight) { 276 item.parentNode.classList.add('d-none') 277 hideCount++ 278 } else { 279 break 280 } 281 } 282 if (hideCount) { 283 $rest.querySelector('.multi_select__tag-text').innerText = `+ ${hideCount}` 284 for (let i = 1; i < $tag_list.length; i++) { // æ£æ¥æ¯å¦å$restéå 285 const item = $tag_list[i]; 286 if (!item.parentNode.classList.contains('d-none') && item.getBoundingClientRect().right > $rest.getBoundingClientRect().left - 6) { 287 item.parentNode.classList.add('d-none') 288 hideCount++ 289 $rest.querySelector('.multi_select__tag-text').innerText = `+ ${hideCount}` 290 break 291 } else if (item.parentNode.classList.contains('d-none')){ 292 break 293 } 294 } 295 $rest.classList.remove('d-none') 296 } else { 297 $rest.classList.add('d-none') 298 } 299 // æ ç¾æ¢è¡ï¼æ´æ°é«åº¦ ------------------------------------------------------------ 300 // if ($tags_wrap.offsetHeight) { 301 // $input_wrap.style.height = $tags_wrap.offsetHeight + 8 + 'px' 302 // } else { 303 // $input_wrap.style.height = '' 304 // } 305 // popperInstance.update() 306 } 307 } 308 309 // æ ¹æ®è®¿å®¢ IP è·åå½å®¶ä¿¡æ¯ï¼å¹¶èªå¨å¹é 设置çµè¯åºå· 310 async _getIpInfo() { 311 // è¥å·²æç¼åï¼å åæ sessionStorageï¼ï¼ç´æ¥åºç¨ 312 const cached = _cachedAreaCode || sessionStorage.getItem('areaCode') 313 if (cached) { 314 _cachedAreaCode = cached 315 this._applyAreaCode(cached) 316 return 317 } 318 // è¥å ¶ä»ç»ä»¶æ£å¨è¯·æ±ï¼å æ¬è·åIPåè·ååºå·ï¼ï¼çå¾ å ¶ç»æå³å¯ 319 if (_ipInfoPromise) { 320 await _ipInfoPromise 321 return 322 } 323 // å°è·åIP + è·ååºå·å并为ä¸ä¸ª Promiseï¼é²æ¢ä»»ä½ç¯èéå¤è¯·æ± 324 _ipInfoPromise = this._fetchAreaCode() 325 try { 326 const areaCode = await _ipInfoPromise 327 if (areaCode) { 328 _cachedAreaCode = areaCode 329 sessionStorage.setItem('areaCode', areaCode) 330 this._applyAreaCode(areaCode) 331 } 332 } catch (err) { 333 console.error('_getIpInfo error:', err) 334 } 335 } 336 337 // è·å IP 并请æ±åºå·ä¿¡æ¯ï¼è¿åå¹é å°çåºå· 338 async _fetchAreaCode() { 339 // åè setInquiryRecord ä¸ç IP è·åæ¹å¼ï¼å 读 sessionStorageï¼æ²¡æåè¯·æ± ifconfig.me 340 let ip = sessionStorage.getItem('ip') 341 if (!ip) { 342 try { 343 ip = await new Promise((resolve, reject) => { 344 var xhr = new XMLHttpRequest() 345 xhr.timeout = 5000 346 xhr.open('GET', 'https://www.ifconfig.me/ip', true) 347 xhr.onreadystatechange = function () { 348 if (xhr.readyState === 4 && xhr.status === 200) { 349 resolve(xhr.responseText) 350 } else if (xhr.status !== 200) { 351 reject('Error: ' + xhr.status) 352 } 353 } 354 xhr.send() 355 }) 356 sessionStorage.setItem('ip', ip) 357 } catch { 358 console.log('ip请æ±å¤±è´¥') 359 return null 360 } 361 } 362 const res = await this.utilts.request({ 363 url: '/visitor/get-ip-info', 364 method: 'GET', 365 params: { 366 ip, 367 lang: 'en' 368 } 369 }) 370 if (res.code === 0 && res.data && res.data.countryCode) { 371 await ensureCallingCodes() 372 const codes = window.countryCallingCodes || [] 373 const match = codes.find(item => 374 item.countryCode && item.countryCode.toUpperCase() === res.data.countryCode.toUpperCase() 375 ) 376 return match ? match.code : '+86' 377 } 378 return null 379 } 380 381 // å°å¹é å°çåºå·åºç¨å°é¡µé¢ææçµè¯åºå·éæ©å¨ 382 _applyAreaCode(areaCode) { 383 document.querySelectorAll('.area-code-select').forEach(selectDom => { 384 selectDom.value = areaCode 385 const display = selectDom.parentElement?.querySelector('.area-code-display') 386 if (display) display.textContent = areaCode 387 }) 388 } 389 390 /** 391* åå§å询ç 392 */ 393 _initInquiry() { 394 window.isInquiry = true 395 this._initEvent() 396 this._submitInquiryForm() 397 this._uploadFileChange() 398 } 399 _initEvent() { 400 // è®°å½å¡«åè®°å½ 401 this.$form.querySelectorAll('input').forEach($el => { 402 $el.addEventListener('focus', () => { 403 if (!this.is_record_input) { 404 this.is_record_input = true 405 this.utilts.setInquiryRecord('inquiry_start').then(res => console.log(res.msg)) 406 } 407 }) 408 }) 409 this.$form.querySelectorAll('input[type="text"],input[type="email"],input[type="tel"]').forEach($el => { 410 $el.addEventListener('input', () => { this.checkText($el) }) 411 $el.addEventListener('blur', () => { $el.value = $el.value.trim() }) 412 }) 413 this.$form.querySelectorAll('textarea').forEach($el => { 414 $el.addEventListener('focus', () => { 415 if (!this.is_record_input) { 416 this.is_record_input = true 417 this.utilts.setInquiryRecord('inquiry_start').then(res => console.log(res.msg)) 418 } 419 }) 420 $el.addEventListener('input', () => { this.checkText($el) }) 421 $el.addEventListener('blur', () => { $el.value = $el.value.trim() }) 422 }) 423 /** form email è¾å ¥çæå转å°å */ 424 if (this.$form.querySelectorAll('[type="email"]').length > 0) { 425 this.$form.querySelectorAll('[type="email"]').forEach(formItem => { 426 formItem.addEventListener('blur', function () { 427 this.value = this.value.toLowerCase() 428 }) 429 }) 430 } 431 } 432 433 // 注åform æäº¤äºä»¶ 434 _submitInquiryForm() { 435 this.$form.addEventListener('submit', async (event) => { 436 event.preventDefault() 437 // éªè¯è¡¨åä¿¡æ¯æ¯å¦åæ³ï¼ä¸åæ³ä¸æäº¤ 438 if (!this._inquirySet(event)) return console.warn('this._inquirySet() return false') 439 this.utilts.setBtnLoadingStatus(this.$submit, true) 440 // è®°å½æäº¤è®°å½ 441 // const data = await this.utilts.setInquiryRecord('inquiry_submit') 442 // 设置ï¼è·åè¦ä¿åç表åä¿¡æ¯ 443 const { preset_config, custom_config } = this._inquiryConfig()
444 const type = this.utils.urlParams.type 445 switch (this.formType) { 446 // 产å详æ 询ç 447 case 'product-detail-inquiry': { 448 // è·åå ¶å®äº§å详æ ä¿¡æ¯ 449 const inquire_pro = type === 'quoteList' ? this._inquiryQuoteList() : this._inquiryDetailList() 450 // è®°å½æäº¤è®°å½ 451 await this.utilts.setInquiryRecord('inquiry_submit', this._getConfigParams(preset_config, custom_config, inquire_pro)) 452 //æäº¤ä¿å表å 453 this._inquiryRequest(preset_config, custom_config, inquire_pro) 454 if(type === 'quoteList') { 455 localStorage.removeItem('productQuoteList') 456 localStorage.removeItem('productQuoteIdList') 457 } 458 break 459 } 460 // æ®é询ç 461 case 'inquiry': 462 // è·åå ¶å®äº§å详æ ä¿¡æ¯ 463 const inquire_pro = type === 'quoteList' ? this._inquiryQuoteList() : this._inquiryDetailList() 464 // è®°å½æäº¤è®°å½ 465 await this.utilts.setInquiryRecord('inquiry_submit', this._getConfigParams(preset_config, custom_config, inquire_pro)) 466 //æäº¤ä¿å表å 467 this._inquiryRequest(preset_config, custom_config, inquire_pro) 468 if(type === 'quoteList') { 469 localStorage.removeItem('productQuoteList') 470 localStorage.removeItem('productQuoteIdList') 471 } 472 break 473 // 社åªè¯¢ç 474 case 'socialMedia': 475 // è®°å½æäº¤è®°å½ 476 await this.utilts.setInquiryRecord('inquiry_submit', this._getConfigParams(preset_config, custom_config, {})) 477 //æäº¤ä¿å表å 478 this._inquiryRequest(preset_config, custom_config, {}) 479 break 480 // é®ç¥¨è®¢é 481 case 'subscription': 482 await this.utilts.setInquiryRecord('inquiry_submit', this._getConfigParams(preset_config)) 483 this._subscriptionsRequest(preset_config) 484 break 485 default: 486 break 487 } 488 }) 489 } 490 491 // æ£æ¥è®¾ç½® 492 _inquirySet(event) { 493 event.preventDefault() 494 event.stopPropagation() 495 this.is_record_submit = true 496 // è£ ä¿®æ¨¡å¼ä¸ä¸è½ä¿å表å 497 if (this.utilts.checkDesign() || !window.isInquiry) return false 498 window.isInquiry = false 499 setTimeout(function () { window.isInquiry = true }, 2000) 500 // this.$form.classList.add('was-validated') 501 let success = true 502 // éªè¯è¡¨å项 503 for (const $formItem of this.$form) { 504 // if (!$formItem.checkValidity()) { success = false; break } 505 let res = this.checkText($formItem) 506 if (!res) { success = false } 507 } 508 const formData = new FormData(this.$form) 509 this.$form.querySelectorAll('.unit-form__checkbox-list[required]').forEach(function(groupNode){ 510 const name = groupNode.getAttribute('name') 511 if (name) { 512 const checked = formData.getAll(name) 513 if (checked.length) { 514 groupNode.classList.remove('is-invalid') 515 } else { 516 success = false 517 groupNode.classList.add('is-invalid') 518 } 519 } 520 }) 521 this.$form.querySelectorAll('.unit-form__select-box [required]').forEach(function(selectNode){ 522 const name = selectNode.getAttribute('name') 523 if (name) { 524 const selectedVal = formData.get(name) 525 if (selectedVal) { 526 selectNode.classList.remove('is-invalid') 527 } else { 528 success = false 529 selectNode.classList.add('is-invalid') 530 } 531 } 532 }) 533 // ä¸ä¼ æä»¶éªè¯ 534 if (this.$file && !this._fileCheck()) success = false 535 return success 536 } 537 checkText($formItem) { 538 if (!this.is_record_submit) return true 539 let type = $formItem.getAttribute('type') 540 let readonly = $formItem.getAttribute('readonly') !== null 541 if (readonly) return true
542 let checkMap = { // æ ¡éªçè¾å ¥æ¡ç±»å 543 isText: $formItem.nodeName === 'INPUT' && type === 'text', 544 isEmail: $formItem.nodeName === 'INPUT' && type === 'email', 545 isTel: $formItem.nodeName === 'INPUT' && type === 'tel', 546 isTextarea: $formItem.nodeName === 'TEXTAREA', 547 } 548 let hasValidate = false 549 for (const key in checkMap) { 550 if (checkMap[key]) { 551 hasValidate = true 552 break 553 } 554 } 555 if (!hasValidate) return true 556 557 let required = $formItem.getAttribute('required') !== null 558 let minlength = required ? (parseInt($formItem.getAttribute('minlength')) || 1) : 0 559 let pattern = $formItem.getAttribute('pattern') ? new RegExp($formItem.getAttribute('pattern'), 'ig') : null 560 let value = $formItem.value.toString().trim() 561 let success = true 562 563 if (pattern && !pattern.test(value)) { 564 success = false 565 } 566 if (checkMap['isText'] || checkMap['isTextarea'] || checkMap['isTel']) { 567 if (required && value.length < minlength) { 568 success = false 569 } 570 } else if (checkMap['isEmail'] && !$formItem.checkValidity()) { 571 console.log('isEmail'); 572 573 success = false 574 } 575 if (success) { 576 $formItem.classList.remove('is-invalid') 577 $formItem.classList.add('is-valid') 578 } else { 579 $formItem.classList.add('is-invalid') 580 $formItem.classList.remove('is-valid') 581 } 582 583 return success 584 } 585 // è·åconfig 586 _inquiryConfig() { 587 // è·åè¦ä¿åçä¿¡æ¯ 588 var preset_config = {} //é»è®¤ç表å项 589 var custom_config = [] //èªå®ä¹ç表å项 590 var formControls = this.$form.querySelectorAll('.form-control[name]') 591 /** 592 * @type {{[string]: {custom_config?, multiple_value?}}} 593 */ 594 const formControlsMap = Array.from(formControls).reduce(function (map, elem) { 595 const mapKey = elem.getAttribute('name') 596 map[mapKey] = Object.assign({}, elem.dataset) 597 try { 598 if (elem.dataset.custom_config) { 599 map[mapKey].custom_config = JSON.parse(elem.dataset.custom_config) 600 } 601 } catch (e) { 602 603 } 604 return map 605 }, {}) 606 607 const _$form = document.querySelector(`#inquiry-${this.attrId}`) 608 const formData = new FormData(_$form) 609 const serializeArray = [] 610 const formNames = Array.from(new Set(formData.keys())) 611 for (const fieldName of formNames) { 612 if (formControlsMap[fieldName] && formControlsMap[fieldName].multiple_value && formControlsMap[fieldName].multiple_value !== 'false') { 613 // multiple value 614 serializeArray.push({name: fieldName, value: formData.getAll(fieldName)}) 615 } else { 616 // single value 617 serializeArray.push({name: fieldName, value: formData.get(fieldName)}) 618 } 619 } 620 // åºåèªå®ä¹è¡¨åå ç´ åç³»ç»è¡¨åå ç´ 621 serializeArray.forEach(function (item, index) { 622 const formItemConfig = formControlsMap[item.name] 623 const formItemCustomConfig = formItemConfig.custom_config || {} 624 const customFromType = formItemCustomConfig.define_type; 625 if (Array.isArray(item.value)) { 626 if ('multi_image' === customFromType) { 627 item.value = item.value.map(function (val, idx) { 628 try { 629 val = JSON.parse(val) 630 } catch (e) { 631 console.warn(idx, e) 632 } 633 return val 634 }) 635 item.value = JSON.stringify(item.value) 636 } else { 637 item.value = item.value.join(',') 638 } 639 } 640 if (item.name.indexOf('form_') === 0) { 641 if (!formItemCustomConfig.define_type) { 642 formItemCustomConfig.define_type = 'text' 643 } 644 645 custom_config.push(Object.assign(formItemCustomConfig, item, { 646 // title: formControls[index].getAttribute('data-title') || formControls[index].placeholder || formControls[index].getAttribute('placeholder') 647 title: formControlsMap[item.name].title || _$form.querySelector(`[name="${item.name}"]`)?.getAttribute('placeholder') 648 })) 649 650 } else if (typeof item.value !== 'object') { 651 preset_config[item.name] = item.value 652 } 653 }) 654 // åå¹¶åºå·åçµè¯å·ç 655 if(preset_config['phone-area-code'] && preset_config['phone']){ 656 preset_config['phone'] = preset_config['phone-area-code'] + ' ' + preset_config['phone'] 657 } 658 delete preset_config['phone-area-code'] 659 // 妿æä¸ä¼ æä»¶ï¼æ·»å å°èªå®ä¹configéé¢ 660 if (this.file_config.length > 0) { 661 custom_config = [...custom_config, ...this.file_config] 662 } 663 664 return { preset_config, custom_config } 665 } 666
667 // è·åDetailList 668 _inquiryDetailList() { 669 return window.app.info.productInquireList 670 .filter(item => item.selected) 671 .map(item => { 672 return { 673 id: item.content_id, 674 page_url: item.href, 675 thumb: (item.detail_thumb || '').replace(/&/gi, '&'), 676 title: item.detail_title 677 } 678 }) } 679 680 // è·åå¤äº§å询çå表 681 _inquiryQuoteList() { 682 return window.app.info.productQuoteList 683 .map(item => { 684 return { 685 id: item.id, 686 page_url: item.page_url, 687 thumb: item.thumb.replace(/&/gi, '&'), 688 title: item.title, 689 amount: item.amount 690 } 691 }) 692 } 693 694 // 询ç表åæäº¤ 695 async _inquiryRequest(preset_config, custom_config, inquire_pro) { 696 let params = this._getConfigParams(preset_config, custom_config, inquire_pro) 697 // 产åæé ç询çåªéæäº¤éä¸çæé 产å 698 let matchProducts = JSON.parse(sessionStorage.getItem('matchProducts') || '[]') 699 let mainProduct = JSON.parse(sessionStorage.getItem('mainProduct')) 700 if (window.app.info.isMatchProducts && matchProducts && matchProducts.length && mainProduct) { 701 params.product_list = matchProducts.map(el => { 702 return { 703 id: el.product_id, 704 page_url: el.page_url, 705 thumb: el.thumb_prefix, 706 title: el.title 707 } 708 }) 709 params.product_list.unshift(mainProduct) 710 } 711 const utilts = window.app.utilts 712 const that = this 713 // let flagRetry = false 714 const _handleInquiry = async function (captcha, flagRetry) { 715 if (captcha) { 716 // è ¾è®¯éªè¯ 717 const captcha_token = await that.utilts.checkTCaptcha('inquiry') 718 if (captcha_token) params.token = captcha_token 719 else { 720 utilts.setBtnLoadingStatus(that.$submit, false) 721 return 722 } 723 } 724 const stringify = 1 725 const url = '/inquiry/insert' 726 const method = 'POST' 727 if(sessionStorage.getItem('ip')){ 728 params.ip = sessionStorage.getItem('ip') 729 } 730 return utilts.request({stringify, url, method, params}) 731 .then(res => { 732 utilts.recordClientInquiredTimes() 733 that.handleInquireSuccess(res, params) 734 }) 735 .catch((res) => { 736 if (res && res.code && parseInt(res.code) === 103) { 737 // 103 éªè¯ç 738 if (flagRetry) { 739 // 鲿¢æ éå¼¹éªè¯ç 740 throw new Error('retry captcha') 741 } 742 return _handleInquiry(true, true) 743 } else if (res && res.msg) { 744 new Modal().warning(res.msg, 'Prompt').open() 745 } else { 746 new Modal().warning('Unknown error', 'Prompt').open() 747 } 748 utilts.setBtnLoadingStatus(that.$submit, false) 749 }) 750 } 751 let needleCaptcha = false
752 const cfgRes = await this.getSiteData() 753 if (cfgRes && cfgRes.data && cfgRes.data.tencent_verify_id) { 754 // è®¾ç½®ææ°çéªè¯ç 客æ·ç«¯id 755 window.app.info.site.tencent_verify_id = cfgRes.data.tencent_verify_id 756 } 757 if (cfgRes.data && cfgRes.data.site_config) { 758 const site_config = cfgRes.data.site_config 759 const tencent_verify_id = cfgRes.data.tencent_verify_id 760 console.log('tencent_verify_id ~~~~~~~~~', tencent_verify_id) 761 const page_type = window.app.info.page.page_type || '' 762 const is_landing_page = page_type === 'landing_page' 763 const captcha_switch = is_landing_page ? site_config.ads_inquiry_captcha_switch : site_config.inquiry_captcha_switch 764 const first_no_check = is_landing_page ? site_config.ads_inquiry_captcha_first_no_check_switch : site_config.inquiry_captcha_first_no_check_switch 765 const count = utilts.getClientInquiredTimes() 766 needleCaptcha = captcha_switch ? ( first_no_check ? count > 0 : true ) : false 767 if (site_config.inquiry_success_redirect_time && !isNaN(site_config.inquiry_success_redirect_time)) { 768 sessionStorage.setItem('success_redirect_time', Number(site_config.inquiry_success_redirect_time)) 769 } 770 } 771 return _handleInquiry(needleCaptcha, false) 772 } 773 774 /** 775 * 询çæå 776 * @param res 777 * @param {{email?:string}} params 778 */ 779 handleInquireSuccess(res, params) { 780 this.$form.dispatchEvent(new CustomEvent('form-inquire:success', {id: this.$form.id})) 781 this.utilts.setBtnLoadingStatus(this.$submit, false) 782 this.file_config = [] 783 // 社åªè¯¢çè®°å½, 2:表示询çæåååå°é¦é¡µæ¶å¼¹åºè天å表 784 if (this.formType === 'socialMedia') this.utilts.setItem('social_status', 2) 785 if (this.formType === 'inquiry' || this.formType === 'product-detail-inquiry') { 786 this.utilts.setGtag('begin_inquiy') 787 const contentId = window.renderInfo && window.renderInfo.page && window.renderInfo.page.content_id || 0 788 this.utilts.recordInquiredProduct(contentId) 789 } 790 sessionStorage.setItem('prev_url', location.pathname) 791 window.app.info.user.guest_id = res.data.member_id 792 sessionStorage.setItem('prev_inquire_email', (params && params.email) || '') 793 794 const type = this.utils.urlParams.type 795 if(type === 'quoteList') { 796 sessionStorage.removeItem('prev_url') 797 } 798 window.location.href = globalThis.Server.getRinseHref('/inquire_success.html', window.app.info.site) 799 } 800 801 /** 802 * è·åæ¯å¦å¼å¯å¹¿å页询çéªè¯ 803 * è¿ç§»å° Utilts.getSiteData 804 * @deprecated 805 * @returns {Promise<unknown>} 806 */ 807 async getSiteData() { 808 const params = { 809 site_id: window.app.info.site.site_id 810 } 811 return await this.utilts.request({ 812 url: '/site/info', 813 method: 'get', 814 params 815 }).then(res => { 816 if (res.code == 0) { 817 if (window.app.info.page.page_type === 'landing_page') { 818 this.is_inquiry_captcha = res.data.ads_inquiry_captcha 819 } else { 820 this.is_inquiry_captcha = res.data.inquiry_captcha 821 } 822 } 823 return res 824 }) 825 } 826 827 // é®ä»¶è®¢é æäº¤ 828 async _subscriptionsRequest(config) { 829 const params = { 830 site_id: window.app.info.site.site_id, 831 terminal: window.app.info.client.terminal_type, 832 ip: window.app.info.user.visitor_ip, 833 ...config 834 } 835 // è ¾è®¯éªè¯ 836 let captcha_token = await this.utilts.checkTCaptcha('inquiry') 837 if (captcha_token) params.token = captcha_token 838 else { 839 this.utilts.setBtnLoadingStatus(this.$submit, false) 840 return 841 } 842 this.utilts.request({ 843 url: '/member/email-subscribe/subscribe', 844 method: 'POST', 845 params 846 }) 847 .then(res => { 848 window.dispatchEvent(new CustomEvent('email-subscribe:success', {})) 849 this.utilts.setBtnLoadingStatus(this.$submit, false) 850 new Message().success(this.utilts.$t('The subscription is successful, thank you for your participation')) 851 }) 852 .catch(() => { 853 this.utilts.setBtnLoadingStatus(this.$submit, false) 854 }) 855 } 856 857 /** è·å表åè¦æäº¤çåæ° */ 858 _getConfigParams(preset_config, custom_config, inquire_pro) { 859 let params = Object.assign({}, preset_config, { 860 custom_config: custom_config, 861 site_id: window.app.info.site.site_id, 862 visitor_code: window.app.info.user.visitor_code, 863 visitor_id: window.app.info.user.visitor_id,
864 ip: window.app.info.user.visitor_ip, 865 inquiry_record: this.utilts.getDevice(), 866 // member_id: window.app.info.user.user_id, 867 content_type: window.app.info.source.source_content_type, 868 page_url: window.app.info.tempValidPage.href, 869 page_type: window.app.info.page.page_type, 870 source: window.app.info.source.source_result, 871 referrer: window.app.info.source.referrer || '', 872 language_code: window.app.info.site.language_code 873 }) 874 // if ( 875 // window.app.info.checkProductDetail(window.app.info.page.page_type) || 876 // window.app.info.checkInquireForm(window.app.info.page.page_type) || 877 // window.app.info.checkProductLives(window.app.info.page.page_type) 878 // ) { 879 // params.product_list = inquire_pro 880 // } 881 params.product_list = inquire_pro 882 if (window.app.info.page.page_type == 'product_detail') { 883 let attrs = `` 884 let pattern_item = document.querySelectorAll('.unit-detail-pattern__items .unit-detail-pattern__item') 885 if (pattern_item && pattern_item.length) { 886 pattern_item.forEach(item => { 887 let pattern_lable = item.querySelector('.unit-detail-pattern__label') 888 let pattern_value = item.querySelector('.unit-detail-pattern__child.active span') 889 if (pattern_value) attrs += `${pattern_lable.innerHTML}: ${pattern_value.innerHTML}ï¼` 890 }) 891 attrs = attrs.slice(0, attrs.length - 1) 892 } 893 if (params.product_list && params.product_list.length) { 894 params.product_list.forEach(_val => { 895 if (_val.id == window.app.info.productDetail.product_id) { 896 _val.attr = attrs 897 } 898 }) 899 } 900 } 901 // 客æè¯¢çåæ° 902 if (this.formType === 'socialMedia') params.type = 4 903 return params 904 } 905 906 // ç»å®ä¸ä¼ æä»¶è¡¨åäºä»¶ 907 _uploadFileChange() { 908 if (!this.$file) { return } 909 this.$file.parentNode.parentNode.addEventListener('click', (e) => { 910 if (e.target.tagName.toLowerCase() !== 'input') e.preventDefault() 911 }) 912 this.$file.addEventListener('change', async () => { 913 if (!this._fileCheck()) return 914 this._promiseUpload() 915 .then(res => { 916 this._removeLoading() 917 }) 918 .catch(err => { 919 this._removeLoading() 920 console.log(err) 921 }) 922 }) 923 } 924 925 /** å¤ç弿¥ä¸ä¼ å¾ç */ 926 _promiseUpload() { 927 return new Promise(async (resolve, reject) => { 928 const formName = this.$file.getAttribute('name') 929 const files = this.$file.files 930 if (files.length > 0) { 931 //è ¾è®¯éªè¯å¿ é¡»éè¿ 932 // if (!await this.utilts.checkTCaptcha('attach')) { 933 // reject(new Error('verify is error')) 934 // this.clearUploadFile() 935 // return 936 // } 937 this.utilts.setBtnLoadingStatus(this.$submit, true) 938 this.$file.setAttribute('disabled', 'disabled') 939 this._showLoading() 940 // ä¸ä¼ æä»¶ 941 this.utilts.uploadFile([...files]) 942 .then(fileList => { 943 this.$file.removeAttribute('disabled') 944 let fileArray = [] 945 // å¤çè¦æäº¤çæ ¼å¼ 946 fileList.forEach((info, index) => { 947 const val = { name: info.name, url: `${info.host}/${info.cname}` } 948 fileArray.push(val) 949 this._setShowImg(info.size, info.name, index) 950 }) 951 const _file = { name: formName, title: fileList[0].name, value: JSON.stringify(fileArray) } 952 this.file_config.push(_file) 953 this.$file_box.setAttribute('validated', '') 954 fileArray = [] 955 resolve() 956 this.utilts.setBtnLoadingStatus(this.$submit, false) 957 }) 958 .catch(err => reject(err)) 959 } else { 960 resolve() 961 } 962 }) 963 } 964 965 /** æ¸ ç©ºæä»¶ */ 966 clearUploadFile() { 967 this.$file.value = '' 968 this.uploadCheck = false 969 } 970 971 /** æ£æ¥ä¸ä¼ å¾çåæ³æ§ */ 972 _fileCheck() { 973 //妿æå¾çå表ï¼ä¸ä¼ 以忷»å å°promiseAlléé¢å»ï¼å 为è¦å¤ç弿¥ 974 const _type_ = ['txt', 'doc', 'docx', 'ppt', 'pptx', 'xlsx', 'xls', 'pdf', 'jpg', 'png', 'bmp', 'gif', 'jpeg', 'rar', 'zip', 'mp4'] 975 let isTrue = true 976 if (this.$file.hasAttribute('required') && !this.$file.value) isTrue = false
977 Array.from(this.$file.files).forEach(item => { 978 // éå¶æ ¼å¼ 979 const selfFileType = item.name.split('.')[item.name.split('.').length - 1].toLowerCase() 980 if (isTrue) isTrue = _type_.includes(selfFileType) 981 // éå¶å¤§å° 982 if (isTrue) isTrue = item.size <= 1024 * 1024 * 20 983 // æä»¶åä¸è½å¤§äº100 984 if (isTrue) isTrue = item.name.length < 100 985 }) 986 if (!isTrue) { 987 this.$file.value = '' 988 this.$file_box.classList.add('show_error') 989 return false 990 } else this.$file_box.classList.remove('show_error') 991 return true 992 } 993 994 /** 设置æ¾ç¤ºå¾ç */ 995 _setShowImg(size, name, index) { 996 // æä»¶å¤§å° 997 if (size < 1024 * 1024) size = (size / 1024).toFixed(2) + 'KB' 998 else size = (size / 1024 / 1024).toFixed(2) + 'MB' 999 // 设置æ¾ç¤ºçhtml 1000 const divImg = document.createElement('div') 1001 divImg.className = 'unit-form__file-item' 1002 const formFileIndex = `form_file_${index}` 1003 divImg.id = formFileIndex 1004 let innerHTML = `<div><span class='iconfont icon-wenjian'></span> ${name}</div>` 1005 const span = document.createElement('span') 1006 span.className = 'icon iconfont' 1007 //å é¤å¾ç 1008 span.addEventListener('click', () => { 1009 this.$file_list.querySelector(`#${formFileIndex}`).remove() 1010 this.file_config.splice(index, 1) 1011 this.$file_box.removeAttribute('validated') 1012 if (this.file_config.length === 0) this.clearUploadFile() 1013 }) 1014 divImg.innerHTML = innerHTML 1015 divImg.append(span) 1016 this.$file_list.append(divImg) 1017 } 1018 1019 // æ·»å ä¸ä¼ å è½½çå¾ç 1020 _showLoading() { 1021 const node = this._getLoadingDiv() 1022 this.$file_list.appendChild(node) 1023 } 1024 1025 // å建ä¸ä¼ æç¤º 1026 _getLoadingDiv() { 1027 const $div = document.createElement('div') 1028 $div.innerHTML = this.utilts.$t('uploading') + '...' 1029 $div.style.cssText = ';color: #908d8d;' 1030 $div.classList.add('div_loading') 1031 $div.width = 30 1032 $div.height = 30 1033 return $div 1034 } 1035 1036 // å é¤ä¸ä¼ å è½½çå¾ç 1037 _removeLoading() { 1038 const imgLoading = this.$file_list.querySelector('.div_loading') 1039 if (imgLoading) imgLoading.remove() 1040 } 1041}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.