PageSourceSearch

https://actwill.co.jp/wp/wp-content/themes/story_tcd041-child/bot_mail/form-main.js

js actwill.co.jp collected 2026-10-07 00:50:29 UTC 64,143 bytes, 1,626 lines download raw bytes

1class ChatbotForm {
2  constructor(config = {}) {
3    this.config = {
4      title: config.title || '法人向け融資 アクト・ウィル',
5      subtitle: config.subtitle || 'お申し込み・お問合せはこちら',
6      position: config.position || 'bottom-right',
7      primaryColor: config.primaryColor || '#1E88E5',
8      botIcon: config.botIcon || 'https://actwill.co.jp/wp/wp-content/themes/story_tcd041-child/bot_mail/img/women3_new.png',
9      defaultTrigger: config.defaultTrigger !== false,
10      ...config
11    };
12
13    this.questions = [
14
15      {
16        type: 'message',
17        message: '',
18        image: 'https://actwill.co.jp/wp/wp-content/themes/story_tcd041-child/bot_mail/img/5cefa38d3aaa2.png'
19      },
20      {
21        type: 'message',
22        message: '',
23        image: 'https://actwill.co.jp/wp/wp-content/themes/story_tcd041-child/bot_mail/img/5f0d28e42bd1b.png'
24      },
25      {
26        id: 'inquiry_type',
27        type: 'buttons',
28        message: 'まずはじめに、お問い合わせ項目を教えていただけますか?<br>注※「創業融資」は行っておりません。',
29        title: 'お問い合わせ項目',
30        options: [
31          { value: 'お申込み', label: 'お申込み', className: 'cta-chat-application' },
32          { value: 'お問い合わせ', label: 'お問い合わせ', className: 'cta-chat-contact' }
33        ]
34      },
35      {
36        type: 'message',
37        condition: {
38          inquiry_type: 'お申込み'
39        },
40        message: '「お申込み」ですね。<br>かしこまりました。'
41      },
42      {
43        type: 'message',
44        condition: {
45          inquiry_type: 'お問い合わせ'
46        },
47        message: '「お問い合わせ」ですね。<br>承知いたしました。'
48      },
49      {
50        id: 'annual_sales',
51        type: 'text',
52        message: '次に年商の金額を教えてください。',
53        title: '年商',
54        placeholder: '',
55        numberOnly: true,  // 数値のみ許可
56        unit: '万円'  // 単位を指定
57      },
58      {
59        id: 'annual_revenue',
60        type: 'text',
61        message: '次に融資のご希望金額を教えてください。',
62        title: '希望金額 ',
63        placeholder: '',
64        numberOnly: true,  // 数値のみ許可
65        unit: '万円'  // 単位を指定
66      },
67      {
68        id: 'company_name',
69        type: 'text',
70        message: '次に、会社名を教えてください',
71        title: '会社名',
72        placeholder: '例)アクト・ウィル株式会社'
73      },
74      {
75        type: 'message',
76        message: answer => `「${answer.company_name}」様ですね。<br>ありがとうございます。`
77      },
78      {
79        id: 'address_group',
80        type: 'form_group',
81        message: 'ご住所を教えてください。',
82        fields: [
83          {
84            id: 'postal_code',
85            type: 'text',
86            label: '郵便番号',
87            placeholder: '例)1234567',
88            maxLength: 7,
89            pattern: '^[0-9]{7}$'
90          },
91          {
92            id: 'prefecture',
93            type: 'select',
94            label: '都道府県',
95            placeholder: '例)北海道',
96            options: [
97              { value: '', label: '選択してください' },
98              { value: '北海道', label: '北海道' },
99              { value: '青森県', label: '青森県' },
100              { value: '岩手県', label: '岩手県' },
101              { value: '宮城県', label: '宮城県' },
102              { value: '秋田県', label: '秋田県' },
103              { value: '山形県', label: '山形県' },
104              { value: '福島県', label: '福島県' },
105              { value: '茨城県', label: '茨城県' },
106              { value: '栃木県', label: '栃木県' },
107              { value: '群馬県', label: '群馬県' },
108              { value: '埼玉県', label: '埼玉県' },
109              { value: '千葉県', label: '千葉県' },
110              { value: '東京都', label: '東京都' },
111              { value: '神奈川県', label: '神奈川県' },
112              { value: '新潟県', label: '新潟県' },
113              { value: '富山県', label: '富山県' },
114              { value: '石川県', label: '石川県' },
115              { value: '福井県', label: '福井県' },
116              { value: '山梨県', label: '山梨県' },
117              { value: '長野県', label: '長野県' },
118              { value: '岐阜県', label: '岐阜県' },
119              { value: '静岡県', label: '静岡県' },
120              { value: '愛知県', label: '愛知県' },
121              { value: '三重県', label: '三重県' },
122              { value: '滋賀県', label: '滋賀県' },
123              { value: '京都府', label: '京都府' },
124              { value: '大阪府', label: '大阪府' },
125              { value: '兵庫県', label: '兵庫県' },
126              { value: '奈良県', label: '奈良県' },
127              { value: '和歌山県', label: '和歌山県' },
128              { value: '鳥取県', label: '鳥取県' },
129              { value: '島根県', label: '島根県' },
130              { value: '岡山県', label: '岡山県' },
131              { value: '広島県', label: '広島県' },
132              { value: '山口県', label: '山口県' },
133              { value: '徳島県', label: '徳島県' },
134              { value: '香川県', label: '香川県' },
135              { value: '愛媛県', label: '愛媛県' },
136              { value: '高知県', label: '高知県' },
137              { value: '福岡県', label: '福岡県' },
138              { value: '佐賀県', label: '佐賀県' },
139              { value: '長崎県', label: '長崎県' },
140              { value: '熊本県', label: '熊本県' },
141              { value: '大分県', label: '大分県' },
142              { value: '宮崎県', label: '宮崎県' },
143              { value: '鹿児島県', label: '鹿児島県' },
144              { value: '沖縄県', label: '沖縄県' }
145
146
147            ]
148          },
149          {
150            id: 'city',
151            type: 'text',
152            label: '市区町村',
153            placeholder: '例)豊島区東池袋'
154          },
155          {
156            id: 'street',
157            type: 'text',
158            label: '番地',
159            placeholder: '例)3-11-9'
160          },
161          {
162            id: 'building',
163            type: 'text',
164            label: '建物名',
165            placeholder: '例)〇〇ビル2F',
166            required: false
167          }
168        ]
169      },
170      {
171        id: 'representative_name',
172        type: 'text',
173        message: '次に、代表者様のお名前をご記入ください。',
174        label: '代表者名',
175        placeholder: '例)山田 太郎'
176      },
177      {
178        id: 'contact_group',
179        type: 'form_group',
180        message: '続いて、ご連絡先情報をお伺いします。<br>お電話番号とメールアドレスをご入力ください。',
181        fields: [
182          {
183            id: 'office_telephone_number',
184            type: 'tel',
185            label: '会社電話番号',
186            placeholder: '例)0312345678',
187          },
188          {
189            id: 'mobile_telephone_number',
190            type: 'tel',
191            label: '携帯電話番号',
192            placeholder: '例)09012345678',
193          }
194        ]
195      },
196      {
197        id: 'email',
198        type: 'email',
199        skipBotMessage: true,
200        label: 'メールアドレス',
201        placeholder: '[email protected]'
202      },
203      {
204        id: 'remarks',
205        type: 'textarea',
206        message: 'その他ご意見・ご質問等がございましたら、ご記入ください。',
207        label: '備考欄 ※空欄でも可',
208        placeholder: 'ご自由にご記入ください'
209      },
210      {
211        type: 'message',
212        message: '最後に、入力していただいた内容をご確認ください。<br>また当社の「個人情報保護方針」をお読みになり、同意していただけましたら下記ボタンより情報を送信してください。'
213      },
214      {
215        id: 'confirmation',
216        type: 'confirmation',
217        message: '',
218        skipBotMessage: true
219      }
220    ];
221
222    this.currentQuestionIndex = -1;
223    this.answers = {};
224    this.isOpen = false;
225    this.triggerElements = new Set();
226
227    this.init();
228  }
229
230  init() {
231    this.createStyles();
232    this.createHTML();
233    this.attachEventListeners();
234    this.showNextQuestion();
235  }
236
237  // 条件チェックのメソッドを追加
238  checkCondition(condition) {
239    if (!condition) return true;
240
241    return Object.entries(condition).every(([key, value]) => {
242      // 配列の場合は、いずれかの値にマッチするか確認
243      if (Array.isArray(value)) {
244        return value.includes(this.answers[key]);
245      }
246      // 文字列または数値の場合は完全一致で確認
247      return this.answers[key] == value;
248    });
249  }
250
251  // 次の表示可能な質問/メッセージのインデックスを取得
252  getNextValidIndex() {
253    let index = this.currentQuestionIndex + 1;
254    while (index < this.questions.length) {
255      const question = this.questions[index];
256      if (!question.condition || this.checkCondition(question.condition)) {
257        return index;
258      }
259      index++;
260    }
261    return index;
262  }
263
264  createStyles() {
265    const styles = `
266        input[type=text], select, textarea {
267          font-family: 'Hiragino Sans', 'ヒラギノ角ゴ Pro W3', 'Hiragino Kaku Gothic Pro', メイリオ, Meiryo, 'MS Pゴシック', 'MS PGothic', sans-serif;
268          font-size: 13px;
269          font-weight: 400;
270          letter-spacing: normal;
271          padding: 8px;
272          height: 36px;
273        }
274
275        .chatbot-container {
276          position: fixed;
277          z-index: 9999;
278          font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
279        }
280
281        .chatbot-container.bottom-right {
282          right: 20px;
283          bottom: 20px;
284        }
285
286        .chatbot-trigger {
287          display: flex;
288          width: 360px;
289          height: 66px;
290          align-items: center;
291          background: linear-gradient(to right, ${this.config.primaryColor}, #2196F3);
292          border-radius: 60px;
293          cursor: pointer;
294          color: white;
295          box-shadow: 0 2px 12px rgba(0, 0, 0, 0.15);
296          transition: transform 0.2s;
297        }
298
299        .chatbot-trigger-head{
300          background-color: #fff;
301          color: #000;
302          font-size: 15px;
303          line-height: 44px;
304          width: 238px;
305          margin-left: 12px;
306          padding: 0 10px;
307          border-radius: 20px;
308        }
309
310        .trigger-icon-head {
311          position: absolute;
312          right: 8px;
313        }
314
315        .trigger-icon-head img {
316          width: 20px;
317          height: 20px;
318        }
319
320        .trigger-icon-head-2 {
321          position: absolute;
322          top: 30px;
323          right: 8px;
324        }
325
326        .trigger-icon-head-2 img {
327          transform: rotate(180deg);
328          width: 20px;
329          height: 20px;
330        }
331
332        .bot-icon-head {
333          width: 50px;
334          height: 50px;
335          margin: 0 4px;
336          border-radius: 50%;
337          overflow: hidden;
338          flex-shrink: 0;
339        }
340
341        .bot-icon-head img {
342          width: 100%;
343          height: 100%;
344          object-fit: cover;
345        }
346
347        .chatbot-window {
348          position: absolute;
349          bottom: calc(100% + 20px);
350          right: 0;
351          width: 370px;
352          background: white;
353          border-radius: 16px;
354          box-shadow: 0 5px 20px rgba(0, 0, 0, 0.15);
355          display: none;
356          overflow: hidden;
357          opacity: 0;
358          transform: translateY(20px);
359          transition: opacity 0.3s, transform 0.3s;
360        }
361
362        .chatbot-window.open {
363          display: block;
364          opacity: 1;
365          transform: translateY(0);
366        }
367
368        .chatbot-header {
369          padding: 10px;
370          background: linear-gradient(to right, ${this.config.primaryColor}, #2196F3);
371          color: white;
372        }
373
374        .chatbot-header-box {
375          display: flex;
376        }
377
378        .chatbot-header-title-box {
379          padding: 0 10px;
380          display: flex;
381          flex-direction: column;
382          justify-content: center;
383        }
384
385        .chatbot-title {
386          font-size: 16px;
387          font-weight: bold;
388          margin: 0;
389        }
390                
391        .chatbot-title-sub {
392          font-size: 16px;
393          margin: 0;
394        }
395
396        .chatbot-progress {
397          font-size: 14px;
398          margin-top: 4px;
399          opacity: 0.8;
400        }
401
402        .chatbot-close {
403          /* position: absolute;
404          right: 16px;
405          top: 16px;
406          color: white;
407          cursor: pointer;
408          font-size: 20px; */
409        }
410
411        .chatbot-content {
412          padding: 20px;
413          height: 400px;
414          overflow-y: auto;
415          background: #d6e0f0;
416        }
417
418        .chat-message {
419          margin-bottom: 20px;
420          display: flex;
421          flex-direction: column;
422          max-width: 100%;
423        }
424
425        .chat-message.bot {
426          align-items: flex-start;
427        }
428
429        .chat-message.user {
430          align-items: flex-end;
431          margin-left: auto;
432        }
433
434        .message-content-wrapper {
435          display: flex;
436          align-items: flex-start;
437          gap: 8px;
438        }
439
440        .bot-icon {
441          width: 36px;
442          height: 36px;
443          border-radius: 50%;
444          overflow: hidden;
445          flex-shrink: 0;
446        }
447
448        .bot-icon img {
449          width: 100%;
450          height: 100%;
451          object-fit: cover;
452        }
453
454        .message-label {
455          font-size: 12px;
456          color: #666;
457          margin-bottom: 4px;
458          margin-left: 44px;
459          /* アイコンの幅 + gap */
460        }
461
462        .chat-message-content {
463          background: white;
464          padding: 12px 16px;
465          border-radius: 12px;
466          box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
467          position: relative;
468          /* font-size: 13px; */
469          font-size: 16px;
470          font-weight: 400;
471        }
472
473        .chat-message.bot .chat-message-content {
474          border-top-left-radius: 4px;
475          background-color: #3bacef;
476          color: #fff;
477          padding: 10px;
478          line-height: initial;
479        }
480
481        /* スタイルを消すクラス */
482        .chat-message-content.no-style {
483          background: none;
484          box-shadow: none;
485          padding: 0;
486        }
487
488        .chat-message.bot .chat-message-content.no-style {
489          background: none;
490          color: inherit;
491        }
492
493        .message-image {
494          margin-top: 8px;
495          border-radius: 8px;
496          overflow: hidden;
497        }
498
499        .message-image img {
500          max-width: 100%;
501          height: auto;
502          display: block;
503        }
504
505        /* no-styleの場合、画像のマージンを調整 */
506        .chat-message-content.no-style .message-image {
507          margin-top: 0;
508        }
509
510        .chat-message.user .chat-message-content {
511          background: ${this.config.primaryColor};
512          color: white;
513          border-top-right-radius: 4px;
514          width: 90%;
515          max-width: 630px;
516        }
517
518        .chat-message.user .chat-message-content.form {
519          background: white;
520          color: #333;
521          padding: 10px;
522          margin-bottom: 30px;
523        }
524
525        .button-options {
526          display: grid;
527          gap: 8px;
528        }
529
530        .button-option {
531          padding: 10px;
532          background: none;
533          border: 1px solid ${this.config.primaryColor};
534          border-radius: 6px;
535          cursor: pointer;
536          color: ${this.config.primaryColor};
537          font-size: 14px;
538          transition: all 0.2s;
539          width: 100%;
540          text-align: center;
541        }
542
543        .button-option:hover {
544          background: ${this.config.primaryColor}10;
545        }
546
547        .button-option.selected {
548          background: ${this.config.primaryColor};
549          color: white;
550          pointer-events: none;
551        }
552
553        .text-input {
554          width: 100%;
555          padding: 8px 12px;
556          border: 1px solid #ddd !important;
557          border-radius: 6px;
558          font-size: 16px;
559          margin-bottom: 8px;
560        }
561
562        .text-input:focus {
563          outline: none;
564          border-color: ${this.config.primaryColor};
565        }
566
567        .submit-button {
568          background: ${this.config.primaryColor};
569          color: white;
570          border: none;
571          border-radius: 6px;
572          cursor: pointer;
573          font-size: 16px;
574          display: block;
575          margin: 0px auto;
576        }
577
578        .button-size-1{
579          width: 118px;
580          height: 42px;
581          padding: 8px;
582        }
583
584        .button-size-2{
585          width: 172px;
586          height: 42px;
587          padding: 8px 14px;
588        }
589
590        .input-preview {
591          color: #666;
592          font-size: 14px;
593          margin-top: 8px;
594        }
595
596        .input-preview.has-value {
597          color: #333;
598          font-weight: 500;
599        }
600
601        .form-group {
602          display: grid;
603          gap: 12px;
604        }
605
606        .form-field {
607          display: grid;
608          gap: 4px;
609        }
610
611        .form-field label {
612          font-size: 14px;
613          color: #666;
614        }
615
616        .form-field select {
617          width: 100%;
618          padding: 8px 12px;
619          border: 1px solid #ddd;
620          border-radius: 6px;
621          font-size: 14px;
622          background-color: white;
623        }
624
625        .form-field select:focus {
626          outline: none;
627          border-color: ${this.config.primaryColor};
628        }
629
630
631        /* チャットメッセージのアニメーション */
632        .chat-message {
633          opacity: 0;
634          transform: translateY(10px);
635          animation: messageAppear 0.3s ease forwards;
636        }
637
638        @keyframes messageAppear {
639          to {
640            opacity: 1;
641            transform: translateY(0);
642          }
643        }
644
645
646        .form-title {
647          font-size: 16px;
648          font-weight: 400;
649          color: #333;
650          margin-bottom: 12px;
651          padding-bottom: 8px;
652          border-bottom: 1px solid #eee;
653        }
654
655        .field-label {
656          font-size: 16px;
657          font-weight: 400;
658          color: #333;
659          margin-bottom: 12px;
660          padding-bottom: 8px;
661          border-bottom: 1px solid #eee;
662          padding-left: 0;
663        }
664
665        .form-field {
666          margin-bottom: 12px;
667        }
668
669        .text-input {
670          margin-top: 4px;
671        }
672
673        .input-container {
674          position: relative;
675          display: flex;
676          align-items: center;
677        }
678
679        .input-container.has-unit .text-input {
680          padding-right: 4em;
681        }
682
683        .input-unit {
684          position: absolute;
685          right: 12px;
686          color: #666;
687          font-size: 14px;
688        }
689
690        .validation-message {
691          color: #dc3545;
692          font-size: 12px;
693          margin-top: 4px;
694          display: none;
695        }
696
697        .text-input.invalid {
698          border-color: #dc3545;
699        }
700
701        .text-input.invalid:focus {
702          border-color: #dc3545;
703          box-shadow: 0 0 0 2px rgba(220, 53, 69, 0.25);
704        }
705
706        .text-input.textarea {
707          resize: vertical;
708          min-height: 100px;
709          max-height: 300px;
710          line-height: 1.5;
711          padding: 12px;
712          resize: none;
713        }
714
715        .confirmation-section,
716        .privacy-policy-section {
717          background: white;
718          // padding: 15px;
719          padding-bottom: 20px;
720          border-radius: 8px;
721          // margin-bottom: 15px;
722        }
723
724        .confirmation-summary {
725          max-height: 210px;
726          overflow-y: auto;
727          // white-space: pre-line;
728          line-height: 18px;
729          font-size: 16px;
730          border: 1px solid #ddd;
731          padding: 8px;
732        }
733
734        .privacy-policy-content {
735          max-height: 210px;
736          overflow-y: auto;
737          padding: 10px;
738          border: 1px solid #ddd;
739          border-radius: 4px;
740          margin: 10px 0;
741          font-size: 16px;
742          line-height: 1.6;
743        }
744
745        .agreement-section {
746          display: flex;
747          align-items: center;
748          gap: 8px;
749          // margin: 15px 0;
750          margin-bottom: 15px;
751        }
752
753        .agreement-section input[type="checkbox"] {
754          width: 18px;
755          height: 18px;
756        }
757
758        .agreement-section label {
759          font-size: 14px;
760          color: #333;
761          padding-left: 0;
762        }
763
764        /* 無効化された入力欄のスタイル */
765        .text-input:disabled {
766          cursor: pointer;
767          background-color: #f8f9fa;
768          opacity: 0.8;
769        }
770
771        .text-input:disabled:hover {
772          background-color: #e9ecef;
773        }
774
775        /* ボタンの無効化状態のスタイル */
776        .button-option:disabled {
777          cursor: pointer;
778        }
779
780        @media (max-width: 768px) {
781          .chatbot-container {
782            right: 10px !important;
783            bottom: 10px !important;
784          }
785
786          .chatbot-trigger {
787            width: 270px;
788            height: 44px;
789          }
790
791          .chatbot-trigger-head{
792            overflow: hidden;
793            white-space: nowrap;
794            text-overflow: ellipsis;
795            line-height: 30px;
796            width: 178px;
797            margin-left: 12px;
798            padding: 0 10px;
799            border-radius: 20px;
800          }
801          .bot-icon-head {
802            width: 38px;
803            height: 38px;
804          }
805
806          .bot-icon-head img {
807          }
808
809          .trigger-icon-head {
810            position: absolute;
811            right: 8px;
812          }
813
814          .trigger-icon-head img {
815            width: 20px;
816            height: 20px;
817          }
818
819          .chatbot-window {
820            position: fixed;
821            top: 0;
822            left: 0;
823            right: 0;
824            bottom: 0;
825            width: 100%;
826            height: 100%;
827            border-radius: 0;
828          }
829
830          .chatbot-content {
831            height: calc(100% - 60px);
832          }
833        }
834
835        /* 20260521 CSS追加 */
836        .titlebold {
837          font-weight: bold;
838        }
839      `;
840
841    const styleSheet = document.createElement('style');
842    styleSheet.textContent = styles;
843    document.head.appendChild(styleSheet);
844  }
845
846  createHTML() {
847    const container = document.createElement('div');
848    container.className = `chatbot-container ${this.config.position}`;
849
850    // デフォルトトリガーが有効な場合のみ追加
851    if (this.config.defaultTrigger) {
852      container.innerHTML = `
853            <div class="chatbot-trigger">
854                <div class="bot-icon-head">
855                    <img src="${this.config.botIcon}" alt="Bot Icon">
856                </div>
857                <div class="chatbot-trigger-head">
858                    ${this.config.subtitle}
859                </div>
860                <div class="trigger-icon-head">
861                    <img src="https://actwill.co.jp/wp/wp-content/themes/story_tcd041-child/bot_mail/img/header_arrow.png" alt="Bot Icon">
862                </div>
863            </div>
864        `;
865    }
866
867    container.innerHTML += `
868        <div class="chatbot-window">
869            <div class="chatbot-header">
870                <div class="chatbot-header-box">
871                    <div class="bot-icon-head">
872                        <img src="${this.config.botIcon}" alt="Bot Icon">
873                    </div>
874                    <div class="chatbot-header-title-box">
875                        <div class="chatbot-title-sub titlebold">${this.config.title}</div>
876                        <div class="chatbot-title">お申込み・お問い合わせはこちら</div>
877                    </div>
878                </div>
879                <div class="chatbot-progress"></div>
880                <span class="chatbot-close trigger-icon-head-2"><img src="https://actwill.co.jp/wp/wp-content/themes/story_tcd041-child/bot_mail/img/header_arrow.png" alt="Bot Icon"></span>
881            </div>
882          
883            <div class="chatbot-content"></div>
884        </div>
885      `;
886
887    document.body.appendChild(container);
888
889    this.elements = {
890      container,
891      trigger: container.querySelector('.chatbot-trigger'),
892      window: container.querySelector('.chatbot-window'),
893      content: container.querySelector('.chatbot-content'),
894      close: container.querySelector('.chatbot-close'),
895      progress: container.querySelector('.chatbot-progress')
896    };
897    if (this.config.defaultTrigger) {
898      this.elements.trigger = container.querySelector('.chatbot-trigger');
899      this.addTriggerElement(this.elements.trigger);
900    }
901  }
902  // 新規メソッド: トリガー要素を追加
903  addTrigger(element) {
904    if (element) {
905      this.addTriggerElement(element);
906    }
907    return this; // メソッドチェーン用
908  }
909
910  // 新規メソッド: 複数のトリガー要素を一度に追加
911  addTriggers(elements) {
912    if (Array.isArray(elements)) {
913      elements.forEach(element => this.addTriggerElement(element));
914    } else if (typeof elements === 'string') {
915      // セレクタ文字列の場合
916      document.querySelectorAll(elements).forEach(element => this.addTriggerElement(element));
917    }
918    return this; // メソッドチェーン用
919  }
920
921  // 新規メソッド: トリガー要素の処理
922  addTriggerElement(element) {
923    if (element && !this.triggerElements.has(element)) {
924      element.addEventListener('click', () => this.toggle());
925      this.triggerElements.add(element);
926    }
927  }
928
929  // 新規メソッド: トリガー要素を削除
930  removeTrigger(element) {
931    if (this.triggerElements.has(element)) {
932      element.removeEventListener('click', () => this.toggle());
933      this.triggerElements.delete(element);
934    }
935    return this; // メソッドチェーン用
936  }
937
938
939
940  attachEventListeners() {
941    this.elements.close.addEventListener('click', () => this.close());
942  }
943
944  toggle() {
945    this.isOpen = !this.isOpen;
946    this.elements.window.classList.toggle('open', this.isOpen);
947  }
948
949  close() {
950    this.isOpen = false;
951    this.elements.window.classList.remove('open');
952  }
953
954  addBotMessage(message, options = {}) {
955    return new Promise(resolve => {
956      const messageDiv = document.createElement('div');
957      messageDiv.className = 'chat-message bot';
958
959      // メッセージが関数の場合、answers を渡して実行
960      let messageContent = typeof message === 'function'
961        ? message(this.answers)
962        : message;
963      let messageContentClass = 'chat-message-content';
964
965      // 画像のみの場合、または明示的にスタイルを消す指定がある場合
966      if (options.removeStyle || (options.image && !message.trim())) {
967        messageContentClass += ' no-style';
968      }
969
970      if (options.image) {
971        messageContent += `
972                    <div class="message-image">
973                        <img src="${options.image}" alt="Message Image">
974                    </div>
975                `;
976      }
977
978      messageDiv.innerHTML = `
979                <div class="message-label"></div>
980                <div class="message-content-wrapper">
981                    <div class="bot-icon">
982                        <img src="${this.config.botIcon}" alt="Bot Icon">
983                    </div>
984                    <div class="${messageContentClass}">${messageContent}</div>
985                </div>
986            `;
987
988      this.elements.content.appendChild(messageDiv);
989      this.elements.content.scrollTop = this.elements.content.scrollHeight;
990
991      setTimeout(resolve, 500);
992    });
993  }
994
995  // 連続メッセージ送信メソッド
996  async sendSequentialMessages(messages) {
997    for (const message of messages) {
998      if (typeof message === 'string') {
999        await this.addBotMessage(message);
1000      } else {
1001        await this.addBotMessage(message.text, {
1002          image: message.image
1003        });
1004      }
1005      // メッセージ間に適度な間を設ける
1006      await new Promise(resolve => setTimeout(resolve, 800));
1007    }
1008  }
1009
1010  addUserForm(question) {
1011    const messageDiv = document.createElement('div');
1012    messageDiv.className = 'chat-message user';
1013
1014    const formContent = document.createElement('div');
1015    formContent.className = 'chat-message-content form';
1016
1017    if (question.title) {
1018      const titleDiv = document.createElement('div');
1019      titleDiv.className = 'form-title';
1020      titleDiv.textContent = question.title;
1021      formContent.appendChild(titleDiv);
1022    }
1023
1024    if (question.type === 'buttons') {
1025      const buttonsDiv = document.createElement('div');
1026      buttonsDiv.className = 'button-options';
1027
1028      question.options.forEach(option => {
1029        const button = document.createElement('button');
1030        button.className = 'button-option';
1031        if (option.className) button.classList.add(option.className);
1032        button.textContent = option.label;
1033        button.addEventListener('click', () => {
1034          button.classList.add('selected');
1035          buttonsDiv.querySelectorAll('.button-option').forEach(btn => {
1036            if (btn !== button) {
1037              btn.disabled = true;
1038              btn.style.opacity = '0.5';
1039            }
1040          });
1041          this.handleAnswer(question.id, option.value, option.label);
1042        });
1043        buttonsDiv.appendChild(button);
1044      });
1045
1046      formContent.appendChild(buttonsDiv);
1047    } else if (question.type === 'form_group') {
1048      const form = document.createElement('form');
1049      form.className = 'form-group';
1050
1051      const formFields = {};
1052
1053      question.fields.forEach(field => {
1054        const fieldContainer = document.createElement('div');
1055        fieldContainer.className = 'form-field';
1056
1057        const label = document.createElement('label');
1058        label.textContent = field.label;
1059        label.className = 'field-label';
1060        fieldContainer.appendChild(label);
1061
1062        let input;
1063        if (field.type === 'select') {
1064          input = document.createElement('select');
1065          field.options.forEach(option => {
1066            const optionElement = document.createElement('option');
1067            optionElement.value = option.value;
1068            optionElement.textContent = option.label;
1069            input.appendChild(optionElement);
1070          });
1071        } else {
1072          input = document.createElement('input');
1073          input.type = field.type;
1074          input.placeholder = field.placeholder;
1075        }
1076
1077        input.className = 'text-input';
1078        input.required = field.required !== false;
1079        if (field.maxLength) input.maxLength = field.maxLength;
1080        if (field.pattern) input.pattern = field.pattern;
1081
1082        fieldContainer.appendChild(input);
1083        form.appendChild(fieldContainer);
1084        formFields[field.id] = input;
1085
1086      });
1087
1088      // 郵便番号の自動入力機能
1089      if (formFields.postal_code) {
1090        formFields.postal_code.addEventListener('input', async (e) => {
1091          const value = e.target.value.replace(/[^0-9]/g, '');
1092          if (value.length === 7) {
1093            try {
1094              const response = await fetch(`https://zipcloud.ibsnet.co.jp/api/search?zipcode=${value}`);
1095              const data = await response.json();
1096              if (data.results) {
1097                const address = data.results[0];
1098                if (formFields.prefecture) {
1099                  formFields.prefecture.value = address.address1;
1100                }
1101                if (formFields.city) {
1102                  formFields.city.value = address.address2 + address.address3;
1103                }
1104              }
1105            } catch (error) {
1106              console.error('郵便番号検索エラー:', error);
1107            }
1108          }
1109        });
1110      }
1111
1112      const submitButton = document.createElement('button');
1113      submitButton.type = 'submit';
1114      submitButton.className = 'submit-button button-size-1';
1115      submitButton.textContent = '次へ';
1116      form.appendChild(submitButton);
1117
1118      form.addEventListener('submit', (e) => {
1119        e.preventDefault();
1120        // すべての入力フィールドを無効化
1121        Object.values(formFields).forEach(input => {
1122          input.disabled = true;
1123        });
1124        // 送信ボタンを無効化
1125        submitButton.disabled = true;
1126        submitButton.style.opacity = '0.5';
1127
1128        const formData = {};
1129        question.fields.forEach(field => {
1130          formData[field.id] = formFields[field.id].value;
1131
1132        });
1133        this.handleAnswer(question.id, formData, JSON.stringify(formData));
1134      });
1135
1136      formContent.appendChild(form);
1137    } else if (question.type === 'confirmation') {
1138      const form = document.createElement('form');
1139
1140      // 入力内容確認セクション
1141      const confirmationSection = document.createElement('div');
1142      confirmationSection.className = 'confirmation-section';
1143
1144      const confirmTitle = document.createElement('div');
1145      confirmTitle.className = 'form-title';
1146      confirmTitle.textContent = '内容確認';
1147      confirmationSection.appendChild(confirmTitle);
1148
1149      // 入力内容のサマリーを作成
1150      const summary = document.createElement('div');
1151      summary.className = 'confirmation-summary';
1152
1153      // 受付内容
1154      let summaryHTML = `
1155        ◇受付内容<br>
1156        【お問い合わせ項目】<br>
1157        ${this.answers.inquiry_type}<br>
1158        【希望金額】<br>
1159        ${this.answers.annual_revenue}万円<br><br>
1160        ◇お客様情報<br>
1161        【会社名】<br>
1162        ${this.answers.company_name}<br>
1163        【会社住所】<br>
1164        〒
1165        ${this.answers.address_group.postal_code}
1166        ${this.answers.address_group.prefecture}
1167        ${this.answers.address_group.city}
1168        ${this.answers.address_group.street}
1169        ${this.answers.address_group.building}<br>
1170        【代表者名】<br>
1171        ${this.answers.representative_name}<br>
1172        【会社電話番号】<br>
1173        ${this.answers.contact_group.office_telephone_number}<br>
1174        【携帯電話番号】<br>
1175        ${this.answers.contact_group.mobile_telephone_number}<br>
1176        【メールアドレス】<br>
1177        ${this.answers.email}<br>
1178        【年商】<br>
1179        ${this.answers.annual_sales}万円<br>
1180        【備考欄】<br>
1181        ${this.answers.remarks}
1182    `;
1183
1184      summary.innerHTML = summaryHTML;
1185      confirmationSection.appendChild(summary);
1186      form.appendChild(confirmationSection);
1187
1188      // プライバシーポリシー
1189      const policySection = document.createElement('div');
1190      policySection.className = 'privacy-policy-section';
1191
1192      const policyTitle = document.createElement('div');
1193      policyTitle.className = 'form-title';
1194      policyTitle.textContent = '個人情報保護方針';
1195      policySection.appendChild(policyTitle);
1196
1197      const policyContent = document.createElement('div');
1198      policyContent.className = 'privacy-policy-content';
1199      policyContent.innerHTML = `
1200■当社の個人情報保護に関する基本方針<br>
1201アクト・ウィル株式会社は、当社の「地域の中小企業活性化をし社会貢献をする」という経営理念に基づき、社会的責任の重要性を十分に認識して、社会に貢献してゆくことを目指しております。 当社は、以下の条項を遵守し、お客様から取得した個人情報の保護に万全を尽くしてまいります。 当社は、個人情報の保護に関する法律(平成15年5月30日法律第57号)その他関係法令を遵守いたします。
1202<br><br>
12031.当社は、個人情報の保護に関する法律(平成15年5月30日法律第57号)その他関係法令を遵守いたします。<br>
12042.当社は、個人情報保護に関するコンプライアンス・プログラム及び個人情報保護規程を定め、継続的に見直し、改善に努めてまいります。<br>
12053.当社は、取得した個人情報の取扱いに当たっては、その利用目的を明確にし、その目的の範囲内で利用いたします。<br>
12064.当社は、収集した個人情報の保護に関し、安全管理規程を定め、不正アクセス、個人情報の紛失、破壊、改ざん及び漏えいなどの予防に努めるとともに、規程の継続的な見直し及び改善に努めてまいります。<br>
12075.当社は、個人情報の取得、利用及び提供に関する監査を定期的に行い、この宣言内容の適切な実践に万全を尽くします。<br>
1208<br>
1209■個人情報の取り扱いに関する宣言<br>
1210当社は、個人情報の保護に関する法律(平成15年5月30日法律第57号。以下「個人情報保護法」といいます。)および当社の「個人情報の保護に関する当社の基本方針(プライバシーポリシー)」の理念に従い、お客様からの個人情報について、以下のとおり取得、管理などを行います。
1211<br><br>
1212お客様の個人情報の利用目的<br>
1213当社は、個人情報の取得にあたっては、取得した個人情報の利用目的を明確にし、<br>
1214利用目的の達成に必要な範囲内で、個人情報を利用いたします。<br>
1215<br>
1216利用目的の例<br>
1217当社の利用目的は、例えば、以下のとおりです。<br>
1218<br>
1219お客様が申し込まれた契約について契約締結の可否などを判断する 目的(与信判断のため)<br>
1220与信後の返済・融資や、お問い合わせに対する回 答などを適切に行う目的(取引に関する記録保存のため)<br>
1221当社がお客様と直接ご融資に係る契約などを締結する際の利用目的<br>
1222<br>
1223利用目的の例<br>
1224当社は、お客様の個人情報について次の利用目的の範囲内で適正に利用いたします。<br>
1225当社の与信判断のため<br>
1226(1)当社の与信ならびに与信後の権利の保存、管理、変更および権利行使のため<br>
1227(2)お客様の本籍地に関する情報については、お客様確認および所在確認のため<br>
1228当社の与信後の権利に関する債権譲渡などの処分および担保差入れその他の取引のため<br>
1229当社とお客様との取引および交渉経過その他の事実に関する記録保存のため<br>
1230当社の与信に係る商品およびサービスのご案内のため<br>
1231当社内部における市場調査および分析ならびに金融商品およびサービスの研究および開発のため<br>
1232<br>
1233■個人情報の共同利用について<br>
1234当社は、お客様の個人情報について、前記「個人情報の第三者への提供について」「金融商品などおよびサービスのご案内について」の内容にかかわらず、以下の範囲で共同利用することがあります。なお、法人情報(法人名、代表者名、所在地、電話番号等)についても同じ範囲で共同利用することがあります。
1235<br><br>
12361 共同利用者の利用目的<br>
1237①各共同利用者の事業者向け融資商品・保証の与信判断のため<br>
1238②各共同利用者の事業者向け融資商品・保証の与信ならびに与信後の権利の保存、管理、変更および権利行使のため<br>
1239③各共同利用者の事業者向け融資商品・保証の与信後の権利に関する債権譲渡等の処分および担保差入れその他の取引のため<br>
1240④各共同利用者と関係当事者との事業者向け融資商品・保証の取引および交渉経過その他の事実に関する記録保存のため<br>
1241⑤各共同利用者内部における事業者向け融資商品・保証の市場調査および分析ならびに金融商品やサービスの研究や開発のã
1241Ÿã‚<br>
1242<br>
1243<br>
12442 共同利用するデータ項目<br>
1245①本人特定に関する情報(氏名、生年月日、性別、住所、電話番号、メールアドレス、勤務先、勤務先電話番号、家族構成、居住状況および運転免許証等の記号番号等)<br>
1246②契約内容に関する情報(契約の種類、申込日、契約日、貸付日、契約金額および貸付金額・保証額等)<br>
1247③返済状況に関する情報(入金日、入金予定日、貸付残高、完済日および延滞等)<br>
1248④取引事実に関する情報(債権回収、債務整理、保証履行、強制解約、破産申立、債権譲渡等)<br>
1249⑤与信に関する情報(収支、資産・負債、職歴および各共同利用者の与信評価情報等)<br>
1250<br>
12513 データの管理について責任を有する者 情報を取得した各共同利用者<br>
1252取得する個人情報の例<br>
1253当社が取得するお客様の個人情報などは、例えば、以下のとおりです。(一部、個人情報保護法に定める個人情報に該当しない情報が含まれます。)<br>
1254<br>
1255■ 氏名、性別、生年月日、住所、電話番号、携帯電話番号、勤務先に関わる内容、家族構成、家族情報、住居状況、保険種類、eメールアドレス、その他ご本人の特定に関する情報<br>
1256■ お客様がご利用されている契約の種類、申込日、契約日、商品名、契約極度額、契約金額、利用残高、月々の返済状況、その他取引に関する情報<br>
1257※ お客様からのお問い合わせ内容などを正確に把握し、対応ã
1257•せていただくために、お客様との通話を記録させていただく場合がございます。なお、この記録は6ヶ月以内に消去いたします。<br>
1258※ お客様が、店舗にご来店された際に、防犯ビデオなどによりお客様の画像および映像を記録し、防犯および本人確認の目的で利用することがあります。なお、この記録は6ヶ月以内に消去いたします。<br>
1259<br>
12602 個人情報の適正な取得<br>
1261当社は、適正な方法で個人情報を取得いたします。<br>
1262適正な取得方法の例<br>
1263当社の個人情報の取得方法は、例えば、以下のとおりです。<br>
1264■ お客様が当社の申込書の書面に必要事項をご記入いただくことにより取得する方法<br>
1265■ お客様がインターネットなどにて、当社ホームページにアクセスした際に、ご提供いただくことにより取得する方法<br>
1266■ 当社が官報、NTT作成の電話帳など一般に公開されている情報媒体から取得する方法<br>
1267■ お客様から口頭により当社にお申し出いただくことにより取得する方法<br>
1268※契約の締結の意思確認時、保証契約の締結の意思確認時等、お客様と当社の会話内容は録音しております。<br>
1269<br>
12703 その他の保有個人データの利用目的<br>
1271当社に入社(採用)を希望される方および採用者の個人情報についての利用目的<br>
1272当社は、当社に採用を希望される方の個人情報について以下の利用目的で使用いたしますので公表いたします。<br>
1273■ 当社の採用の判断のため<br>
1274■ 当社での採用が決定した場合は、従業員管理のため<br>
1275<br>
12764 個人情報の第三者への提供および共同利用<br>
1277当社は、お客様の事前の同意に基づき、個人情報を提供することがあります。<br>
1278また、事業者向け融資商品・保証を取扱う会社において、個人情報を共同利用することがあります。<br>
1279なお、当社は、お客様の同意を得て提供する場合、法令などに基づく場合およびその他正当な事由に基づき提供する場合以外には、お客様の個人情報を第三者に提供いたしません。<br>
1280<br>
12815 個人情報の開示など<br>
1282■ ご相談窓口<br>
1283開示などの相談窓口は以下のとおりです。<br>
1284東京都豊島区東池袋3-11-9<br>
1285アクト・ウィル株式会社 お客様サービスセンター<br>
1286電話 :03-5944-9168(受付時間 平日9:00~17:00)<br>
1287<br>
1288≪開示等の請求ができる者(開示請求権者)≫<br>
1289・本人<br>
1290・代理人<br>
1291■ 開示等請求方法<br>
1292・口頭または当社が必要と認める場合は書面により請求いただきます。<br>
1293必要項目<br>
1294(1) 開示などを求める「お客様本人が識別される保有個人データ(個人情報)の項目」<br>
1295 (2) お客様の「氏名」・「住所」・「生年月日」・「電話番号(携帯電話可)」・「カード番号」<br>
1296 (3) 開示請求権者本人を確認できる書面として、運転免許証または旅券、開示請求者が外国籍の場合は外国人登録証明書の写しなど (4) 開示請求権者が代理人の場合は、上記に加え代理権を証する書面(委任状など)、印鑑証明書 ・その他、特に開示請求権者が求め、当社が承諾した方法<br>
1297<br>
1298■ 開示などに伴う条件<br>
1299・所定のご本人様確認により、本人または代理人であることの確認を行います。<br>
1300・代理人が正当な代理権を持っているか否かの確認を行います。<br>
1301■ 開示などに係る手数料<br>
1302・原則として無料とします。<br>
1303(但し、開示など請求内容により、実費相当額(郵送費用、調査費用など)を請求させていただく場合がございます。)<br>
1304■ 開示等の流れ<br>
1305開示などの基本的な流れは以下の通りです。<br>
1306<br>
1307(1) 開示請求<br>
1308  ↓<br>
1309(2) 開示担当部署にて受付<br>
1310  ↓<br>
1311(3) 当社にて調査<br>
1312  ↓<br>
1313(4) 開示など請求者への開示<br>
1314<br>
1315■ ご留意点<br>
1316※ お客様のご要望により、特に当社が承諾した場合は、上記以外の方法にて開示など対応することがあります。<br>
1317※ 開示など請求権者でないことが判明した場合、正当な代理人でないと当社が判断した場合、お客様本人が識別される保有個人データ(個人情報)の項目以外の開示なã
1317©è«‹æ±‚の場合など、当社の定める方法によらない請求の場合は開示請求などを受け付けしないこと、または、非開示とすることがありますので、あらかじめご了承ねがいます。<br>
1318なお、上記の場合は開示など請求者に対しその旨を通知いたします。<br>
1319※ 開示など請求項目、開示などの量などにより、対応までに相当の期間を要することがあります。<br>
1320<br>
13216 お問い合わせ窓口<br>
1322個人情報についての質問などのお問い合わせは、以下の窓口までお願いいたします。<br>
1323個人情報に関するご相談、個人情報の開示、訂正、利用停止等の手続きにつきましては、次の個人情報相談窓口にご相談ください。<br>
1324<br>
1325≪ご相談窓口≫<br>
1326開示等の相談窓口は以下のとおりです。<br>
1327東京都豊島区東池袋3-11-9<br>
1328アクト・ウィル株式会社 お客様サービスセンター<br>
1329電話 :03-5944-9168  (受付時間 平日9:00~17:00)<br>
1330<br>
13317 個人情報の取り扱いの委託<br>
1332個人情報保護法の規定に従い、当社の業務委託先に対して個人情報の取り扱いを委託する場合がございます。この場合には、業務委託先において個人情報の保護が十分に図られていることを確認した上で、個人情報の保護に関する契約を締結し、必要に応じた監査を実施するなどの適切な措置を講じます。<br>
1333<br>
13348 個人情報の管理<br>
1335当社は、個人情報の取り扱いに関して管理責任者を置き、個人情報保護法その他関係法令の遵守を徹底いたします。<br>
1336<br>
13379 ホームページのセキュリティー<br>
1338当社では、PCサイトにおいてcookie(クッキー)を利用しています。cookieとは、当社がWebブラウザーを通してお客様のコンピュータに一次的にデータを書込んで保存する仕組みです。当社では、cookieを当社ホームページのサービス向上、当社ホームページの利用状況の把握、ホームページの運用に関する統計情報および不正アクセスなどの原因調査のために使用しており、お客様個人を特定できる情報はcookieに含まれていません。また、調査に当っては、当社ホームページにアクセスされた方の情報をアクセスログという形で記録しています。アクセスログにはアクセスされた方のドメイン名やIPアドレス、アクセスされた日付・時刻などが含まれており当社のお客様においては、個人情報と照合することが可能です。 なお、当社ではアクセスログを閲覧・利用できる者を社内の特定人物に限定、また利用できる場所についても同様に限定しており適切に利用する環境を構築しております。なお、アクセスログを第三者に開示・譲渡または販売することはありません。 尚、当社PCサイトでのお客様の個人情報はグローバルサインのSSLにより保護しております。<br>
1339<br>
134010 ホームページのご利用上の注意点<br>
1341当社のホームページは、日本国の法律に準拠して適正に作成されておりますが、閲覧、利用に際しては、あらかじめ次の点をご承知おきください。<br>
1342■ 当社のホームページへのアクセスが海外から行われた場合にも日本国の法律が適用されること<br>
1343■ 当社のホームページ上の掲載物については、アクセスされた方の国の法律に照らして適切であるかどうかの表示や記述は行っておらず、当社のホームページの閲覧、利用に伴う責任は、アクセスされたお客様にあること<br>
1344当社のホームページの閲覧、利用に関する訴訟については、東京地方裁判所を第1審の専属管轄裁判所とします。<br>
1345当社は、【平成26年3月20日】から、「当社の個人情報保護に関する基本方針(プライバシーポリシー)」およびこの宣言を実施いたしております。<br>
1346当社は、個人情報保護法およびその他の法令などの変更に伴い、必要に応じて「当社の個人情報保護に関する基本方針(プライバシーポリシー)」およびこの宣言の一部または全部を改訂することがあります。また、当社の業務内容の変化ã
1346«ä¼´ã„合理的な必要が生じた場合には、当社が取得する個人情報についての利用目的を変更させていただくことがあります。<br>
1347これらの変更のうち特に重要な変更については、当社ホームページまたは最寄りの店舗においてお知らせいたしますので、定期的なご確認をお願いいたします。<br>
1348<br>
1349平成26年3月20日 <br>
1350アクト・ウィル株式会社<br>
1351        `;
1352      policySection.appendChild(policyContent);
1353
1354      // 同意チェックボックス
1355      const agreementDiv = document.createElement('div');
1356      agreementDiv.className = 'agreement-section';
1357
1358      const checkbox = document.createElement('input');
1359      checkbox.type = 'checkbox';
1360      checkbox.id = 'agreement';
1361      checkbox.required = true;
1362
1363      const label = document.createElement('label');
1364      label.htmlFor = 'agreement';
1365      label.textContent = '同意する';
1366
1367      agreementDiv.appendChild(checkbox);
1368      agreementDiv.appendChild(label);
1369      form.appendChild(policySection);
1370      form.appendChild(agreementDiv);
1371
1372      // 送信ボタン
1373      const submitButton = document.createElement('button');
1374      submitButton.type = 'submit';
1375      submitButton.className = 'submit-button button-size-2';
1376      submitButton.textContent = '入力内容を送信する';
1377      submitButton.disabled = true; // 初期状態は無効
1378      submitButton.style.opacity = '0.5'; // 初期状態は無効
1379
1380      // チェックボックスの状態により送信ボタンの有効/無効を切り替え
1381      checkbox.addEventListener('change', (e) => {
1382        submitButton.disabled = !e.target.checked;
1383        submitButton.style.opacity = e.target.checked ? '1' : '0.5';
1384      });
1385
1386      form.appendChild(submitButton);
1387      form.addEventListener('submit', (e) => {
1388        e.preventDefault();
1389        this.handleAnswer('confirmation', true, 'confirmed');
1390      });
1391
1392      formContent.appendChild(form);
1393    } else {
1394      const form = document.createElement('form');
1395
1396      if (question.label) {
1397        const label = document.createElement('label');
1398        label.className = 'field-label';
1399        label.textContent = question.label;
1400        form.appendChild(label);
1401      }
1402
1403      // 入力フィールドのコンテナを作成
1404      const inputContainer = document.createElement('div');
1405      inputContainer.className = 'input-container';
1406      if (question.unit) {
1407        inputContainer.classList.add('has-unit');
1408      }
1409
1410      // 入力要素の作成
1411      let input;
1412      if (question.type === 'textarea') {
1413        input = document.createElement('textarea');
1414        input.className = 'text-input textarea';
1415        input.rows = 4; // 行数を指定
1416      } else {
1417        input = document.createElement('input');
1418        input.type = question.type;
1419        input.className = 'text-input';
1420      }
1421
1422      input.placeholder = question.placeholder;
1423      if (question.id !== 'remarks') {
1424        input.required = true;
1425      }
1426
1427      // 金額入力の場合のカスタマイズ
1428      if (question.numberOnly) {
1429        input.pattern = '[0-9]*';
1430        input.inputMode = 'numeric';
1431
1432        // バリデーションメッセージ用のdiv
1433        const validationMessage = document.createElement('div');
1434        validationMessage.className = 'validation-message';
1435        validationMessage.style.display = 'none';
1436        validationMessage.textContent = '数字で入力してください';
1437
1438        input.addEventListener('input', (e) => {
1439          const value = e.target.value;
1440          const isValid = /^[0-9]*$/.test(value);
1441
1442          if (!isValid) {
1443            validationMessage.style.display = 'block';
1444            input.classList.add('invalid');
1445          } else {
1446            validationMessage.style.display = 'none';
1447            input.classList.remove('invalid');
1448          }
1449        });
1450
1451        inputContainer.appendChild(input);
1452
1453        // 単位表示
1454        if (question.unit) {
1455          const unitSpan = document.createElement('span');
1456          unitSpan.className = 'input-unit';
1457          unitSpan.textContent = question.unit;
1458          inputContainer.appendChild(unitSpan);
1459        }
1460        form.appendChild(inputContainer);
1461        form.appendChild(validationMessage);
1462      } else {
1463        inputContainer.appendChild(input);
1464        form.appendChild(inputContainer);
1465      }
1466
1467      const preview = document.createElement('div');
1468      preview.className = 'input-preview';
1469      form.appendChild(preview);
1470
1471      const button = document.createElement('button');
1472      button.type = 'submit';
1473      button.className = 'submit-button button-size-1';
1474      button.textContent = '次へ';
1475      form.appendChild(button);
1476
1477      form.addEventListener('submit', (e) => {
1478        e.preventDefault();
1479        const value = input.value.trim();
1480        if (question.id === 'remarks' || (value && (!question.numberOnly || /^[0-9,]+$/.test(value)))) {
1481          input.disabled = true;
1482          button.disabled = true;
1483          button.style.opacity = '0.5';
1484          const cleanValue = question.numberOnly ? value.replace(/,/g, '') : value;
1485          this.handleAnswer(question.id, cleanValue, value);
1486        }
1487      });
1488
1489      formContent.appendChild(form);
1490    }
1491
1492    messageDiv.appendChild(formContent);
1493    this.elements.content.appendChild(messageDiv);
1494    this.elements.content.scrollTop = this.elements.content.scrollHeight;
1495  }
1496
1497  async showNextQuestion() {
1498    const nextIndex = this.getNextValidIndex();
1499    if (nextIndex >= this.questions.length) {
1500      await this.handleFormCompletion();
1501      return;
1502    }
1503
1504    this.currentQuestionIndex = nextIndex;
1505    const question = this.questions[this.currentQuestionIndex];
1506
1507    // メッセージ専用タイプの場合
1508    if (question.type === 'message') {
1509      await this.addBotMessage(question.message, {
1510        image: question.image
1511      });
1512      // 少し間を置いて次のメッセージまたは質問を表示
1513      setTimeout(() => this.showNextQuestion(), 800);
1514      return;
1515    }
1516
1517    // 通常の質問の場合は残りの質問数を表示
1518    const remainingQuestions = this.getRemainingQuestions();
1519    if (remainingQuestions > 0) {
1520      this.elements.progress.textContent = `あと${remainingQuestions}問`;
1521    }
1522
1523    // 質問メッセージの表示
1524    // await this.addBotMessage(question.message, {
1525    //     image: question.image
1526    // });
1527
1528    // skipBotMessage が true でない場合のみボットメッセージを表示
1529    if (!question.skipBotMessage) {
1530      await this.addBotMessage(question.message, {
1531        image: question.image
1532      });
1533    }
1534
1535    // フォームの表示
1536    this.addUserForm(question);
1537  }
1538
1539  // 残りの質問数を計算(条件に合う質問のみカウント)
1540  getRemainingQuestions() {
1541    let count = 0;
1542    for (let i = this.currentQuestionIndex; i < this.questions.length; i++) {
1543      const question = this.questions[i];
1544      if (question.type !== 'message' && (!question.condition || this.checkCondition(question.condition))) {
1545        count++;
1546      }
1547    }
1548    return count;
1549  }
1550
1551  handleAnswer(questionId, value, displayValue) {
1552    this.answers[questionId] = value;
1553    setTimeout(() => this.showNextQuestion(), 500);
1554  }
1555
1556  // handleFormCompletion() {
1557  //     this.addBotMessage('ありがとうございます。担当者より連絡させていただきます。');
1558  //     console.log('Form completed with answers:', this.answers);
1559  // }
1560  async saveDataToJson() {
1561    const date = new Date();
1562    date.setMinutes(date.getMinutes() - date.getTimezoneOffset());
1563    const str_date = date.toJSON()?.replace('T', ' ').slice(0, -5);
1564    const mobile_telephone_hyphen = this.answers.contact_group.mobile_telephone_number.length === 11 ? this.answers.contact_group.mobile_telephone_number.replace(/(\d{3})(\d{4})(\d{4})/, "$1-$2-$3") : this.answers.contact_group.mobile_telephone_number.replace(/(\d{2})(\d{4})(\d{4})/, "$1-$2-$3");
1565    const office_telephone_hyphen = this.answers.contact_group.office_telephone_number.replace(/(\d{3})(\d{4})(\d{4})/, "$1-$2-$3")
1566    const postalCode1 = this.answers.address_group.postal_code.substring(0, 3);
1567    const postalCode2 = this.answers.address_group.postal_code.substring(3, 7);
1568    // const business_type1 = this.answers.business_type === 'corporation' ? '法人' : '個人事業主';
1569    const currentUrlParam = location.search;
1570
1571    const jsonData = {
1572      nensho: this.answers.annual_sales,
1573      kibokin: this.answers.annual_revenue,
1574      tel_ketai_hy: mobile_telephone_hyphen,
1575      tel_kaisya_hy: office_telephone_hyphen,
1576      address_zip01: postalCode1,
1577      address_zip02: postalCode2,
1578      address_prefectures: this.answers.address_group.prefecture,
1579      address_city: this.answers.address_group.city,
1580      address_tatemono: this.answers.address_group.building,
1581      address_banchi: this.answers.address_group.street,
1582      name_come: this.answers.company_name,
1583      name_daihyo: this.answers.representative_name,
1584      tel_kaisya: this.answers.contact_group.mobile_telephone_number,
1585      tel_ketai: this.answers.contact_group.office_telephone_number,
1586      biko: this.answers.remarks,
1587      email: this.answers.email,
1588      komoku: this.answers.inquiry_type,
1589      // kubun: business_type1,
1590      current_url: location.href,
1591      url: location.href,
1592      current_url_param: currentUrlParam,
1593      // current_url_title: { current_url_title }
1594      // user_id: { user_id }
1595      start_datatime: str_date,
1596    }
1597    console.log(jsonData);
1598
1599    // メール送信
1600    try {
1601      const response = await fetch('https://actwill.co.jp/wp/wp-content/themes/story_tcd041-child/bot_mail/mail.php', {
1602        method: 'POST',
1603        headers: {
1604          'Content-Type': 'application/json',
1605        },
1606        body: JSON.stringify(jsonData),
1607      });
1608      if (!response.ok) {
1609        throw new Error('メールの送信に失敗しました。');
1610      }
1611      console.log('メールを正常に送信しました。');
1612      // メール送信成功時の処理
1613      window.location.href = 'https://actwill.co.jp/wp/wp-content/themes/story_tcd041-child/bot_mail/thanks.html';
1614    } catch (error) {
1615      console.error('メールの送信中にエラーが発生しました:', error);
1616    }
1617  }
1618
1619  async handleFormCompletion() {
1620    await this.addBotMessage('ご入力ありがとうございました。<br>以上で融資のご相談・お問い合わせの受付は完了になります。');
1621    await this.addBotMessage('お申込み受付後、担当者より詳細についてご案内させていただきます');
1622    await this.addBotMessage('確認のメールを送信していますのでご確認ください。<br>この度はアクト・ウィルへお問い合わせいただき、誠にありがとうございました。');
1623    await this.addBotMessage('画面が切り替わるまでお待ちください。');
1624    await this.saveDataToJson();
1625  }
1626}

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.