فهرست منبع

add qrcode page

SyuanYu 1 سال پیش
والد
کامیت
3a47a1c287

+ 21 - 8
frontend/src/api.ts

@@ -18,6 +18,26 @@ export const api = {
 
 
     return axios.post(`${apiUrl}/api/v1/login/access-token`, params);
     return axios.post(`${apiUrl}/api/v1/login/access-token`, params);
   },
   },
+  async qrLogInGetToken(username: string, password: string,ser_no: string) {
+    const params = new URLSearchParams();
+    params.append("username", username);
+    params.append("password", password);
+
+    return axios.post(`${apiUrl}/api/v1/login/access-token?add-time-code=${ser_no}`, params);
+  },
+  async googleLogin(username: string) {
+    const params = new URLSearchParams();
+    params.append("username", username);
+    params.append("password", "google");
+
+    return axios.post(`${apiUrl}/api/v1/login/google/access-token`, params);
+  },
+  async qrGoogleLogin(username: string,ser_no: string) {
+    const params = new URLSearchParams();
+    params.append("username", username);
+    params.append("password", "google");
+    return axios.post(`${apiUrl}/api/v1/login/google/access-token?add-time-code=${ser_no}`, params);
+  },
   async getMe(token: string) {
   async getMe(token: string) {
     return axios.get<IUserProfile>(`${apiUrl}/api/v1/users/me`, authHeaders(token));
     return axios.get<IUserProfile>(`${apiUrl}/api/v1/users/me`, authHeaders(token));
   },
   },
@@ -113,12 +133,5 @@ export const api = {
   },
   },
   async getVideos(token: string) {
   async getVideos(token: string) {
     return axios.get<Video[]>(`${apiUrl}/api/v1/videos/`, authHeaders(token));
     return axios.get<Video[]>(`${apiUrl}/api/v1/videos/`, authHeaders(token));
-  },
-  async googleLogin(username: string) {
-    const params = new URLSearchParams();
-    params.append("username", username);
-    params.append("password", "google");
-
-    return axios.post(`${apiUrl}/api/v1/login/google/access-token`, params);
-  },
+  }
 };
 };

BIN
frontend/src/assets/img/qrcode/Angela.png


BIN
frontend/src/assets/img/qrcode/aianchor3-title.png


BIN
frontend/src/assets/img/qrcode/aianchor3bg.png


BIN
frontend/src/assets/img/qrcode/angela.webp


BIN
frontend/src/assets/img/qrcode/button1.png


BIN
frontend/src/assets/img/qrcode/button2.png


BIN
frontend/src/assets/img/qrcode/button3.png


BIN
frontend/src/assets/img/qrcode/choozmologo.png


BIN
frontend/src/assets/img/qrcode/icon-19.png


BIN
frontend/src/assets/img/qrcode/icon-20.png


BIN
frontend/src/assets/img/qrcode/line1.png


BIN
frontend/src/assets/img/qrcode/line2.png


BIN
frontend/src/assets/img/qrcode/moichiu.png


BIN
frontend/src/assets/img/qrcode/moichiu.webp


BIN
frontend/src/assets/img/qrcode/startline.png


BIN
frontend/src/assets/img/qrcode/startline1.png


BIN
frontend/src/assets/img/qrcode/儲值卷-06.png


BIN
frontend/src/assets/img/qrcode/儲值卷-07.png


BIN
frontend/src/assets/img/qrcode/儲值卷-13.png


+ 7 - 2
frontend/src/components/Dialog.vue

@@ -17,6 +17,10 @@ const props = defineProps({
   state: {
   state: {
     type: String,
     type: String,
   },
   },
+  icon: {
+    type: String,
+    default: "info"
+  },
 });
 });
 
 
 const emit = defineEmits(["close"]);
 const emit = defineEmits(["close"]);
@@ -35,8 +39,9 @@ function close() {
     <v-card>
     <v-card>
       <v-card-text>
       <v-card-text>
         <section class="d-flex flex-column align-center">
         <section class="d-flex flex-column align-center">
-          <v-icon style="font-size: 70px" icon="info" :color="state" />
-          <p class="mt-3">{{ msg }}</p>
+          <v-icon style="font-size: 70px" :icon="icon" :color="state" />
+          <!-- <p class="mt-3">{{ msg }}</p> -->
+          <p  v-html="msg" class="mt-3 text-center"></p>
         </section>
         </section>
       </v-card-text>
       </v-card-text>
       <v-card-actions>
       <v-card-actions>

+ 1 - 0
frontend/src/components/Navbar.vue

@@ -12,6 +12,7 @@ let lang = reactive([
 let menu = reactive([
 let menu = reactive([
   { title: "login", link: "/login" },
   { title: "login", link: "/login" },
   { title: "register", link: "/signup" },
   { title: "register", link: "/signup" },
+  // { title: "實體卡儲值", link: "/qrcode" },
 ]);
 ]);
 
 
 function setLang(lang: String) {
 function setLang(lang: String) {

+ 5 - 0
frontend/src/router/index.ts

@@ -33,6 +33,11 @@ const router = createRouter({
           name: 'reset-password',
           name: 'reset-password',
           component: () => import(/* webpackChunkName: "reset-password" */ '@/views/ResetPassword.vue'),
           component: () => import(/* webpackChunkName: "reset-password" */ '@/views/ResetPassword.vue'),
         },
         },
+        {
+          path: 'qrcode/:ser_no',
+          name: 'qrcode',
+          component: () => import(/* webpackChunkName: "reset-password" */ '@/views/Qrcode.vue'),
+        },
         {
         {
           path: 'main',
           path: 'main',
           name: 'main',
           name: 'main',

+ 71 - 20
frontend/src/stores/main.ts

@@ -75,6 +75,77 @@ export const useMainStore = defineStore("MainStoreId", {
         await this.logOut();
         await this.logOut();
       }
       }
     },
     },
+    async qrLogIn(username: string, password: string,ser_no: string) {
+      console.log('qrLogIn');
+      
+      try {
+        const response = await api.qrLogInGetToken(username, password,ser_no);
+        // const token: string = response.data.access_token;
+        console.log('response',response);
+        return response;
+        // console.log('token',token);
+        // if (token) {
+        //   saveLocalToken(token);
+        //   this.setToken(token);
+        //   this.setLoggedIn(true);
+        //   this.setLogInError(false);
+        //   await this.getUserProfile();
+        //   await this.routeLoggedIn();
+        //   this.addNotification({ content: i18n.global.t("loggedIn"), color: "success" });
+        // } else {
+        //   await this.logOut();
+        // }
+      } catch (err) {
+        console.log('qrLogIn err',err);
+        
+        // this.addNotification({ content: i18n.global.t("loggedError"), color: "error" });
+        // this.setLogInError(true);
+        // await this.logOut();
+      }
+    },
+    async googleLogin(username: string) {
+      try {
+        const response = await api.googleLogin(username);
+        const token: string = response.data.access_token;
+        if (token) {
+          saveLocalToken(token);
+          this.setToken(token);
+          this.setLoggedIn(true);
+          this.setLogInError(false);
+          await this.getUserProfile();
+          await this.routeLoggedIn();
+          this.addNotification({ content: i18n.global.t("loggedIn"), color: "success" });
+        } else {
+          await this.logOut();
+        }
+      } catch (err) {
+        this.setLogInError(true);
+        await this.logOut();
+      }
+    },
+    async qrGoogleLogin(username: string,ser_no: string) {
+      console.log('qrGoogleLogin');
+      
+      try {
+        const response = await api.qrGoogleLogin(username,ser_no);
+        return response;
+        // const token: string = response.data.access_token;
+        // if (token) {
+        //   saveLocalToken(token);
+        //   this.setToken(token);
+        //   this.setLoggedIn(true);
+        //   this.setLogInError(false);
+        //   await this.getUserProfile();
+        //   await this.routeLoggedIn();
+        //   this.addNotification({ content: i18n.global.t("loggedIn"), color: "success" });
+        // } else {
+        //   await this.logOut();
+        // }
+      } catch (err) {
+        this.setLogInError(true);
+        // await this.logOut();
+      }
+    },
     async getUserProfile() {
     async getUserProfile() {
       try {
       try {
         const response = await api.getMe(this.token);
         const response = await api.getMe(this.token);
@@ -368,26 +439,6 @@ export const useMainStore = defineStore("MainStoreId", {
       } catch (error) {
       } catch (error) {
         await mainStore.checkApiError(error);
         await mainStore.checkApiError(error);
       }
       }
-    },
-    async googleLogin(username: string) {
-      try {
-        const response = await api.googleLogin(username);
-        const token: string = response.data.access_token;
-        if (token) {
-          saveLocalToken(token);
-          this.setToken(token);
-          this.setLoggedIn(true);
-          this.setLogInError(false);
-          await this.getUserProfile();
-          await this.routeLoggedIn();
-          this.addNotification({ content: i18n.global.t("loggedIn"), color: "success" });
-        } else {
-          await this.logOut();
-        }
-      } catch (err) {
-        this.setLogInError(true);
-        await this.logOut();
-      }
     }
     }
   }
   }
 });
 });

+ 682 - 0
frontend/src/views/Qrcode.vue

@@ -0,0 +1,682 @@
+<script setup lang="ts">
+// import { appName, openRegisration } from "@/env";
+import { ref, reactive, computed, onMounted } from "vue";
+import { useMainStore } from "@/stores/main";
+import { useDisplay } from "vuetify";
+import { useRoute } from "vue-router";
+import { storeToRefs } from "pinia";
+import { useI18n } from "vue-i18n";
+// import router from "@/router";
+// import { saveLocalToken } from "@/utils";
+import { googleTokenLogin, decodeCredential } from "vue3-google-login";
+import type { CallbackTypes } from "vue3-google-login";
+import Navbar from "@/components/Navbar.vue";
+import Dialog from "@/components/Dialog.vue";
+
+const mainStore = useMainStore();
+const mainStoreRef = storeToRefs(mainStore);
+
+// variable
+const { t } = useI18n();
+const route = useRoute();
+const { name } = useDisplay();
+const email = ref("");
+const password = ref("");
+let ser_no: any = ref("");
+let showPassword = ref(false);
+let dialog = reactive({
+  msg: "",
+  state: "",
+  show: false,
+  icon: "check_circle",
+});
+
+// getter
+const loginError = mainStoreRef.readLoginError;
+const width = computed(() => {
+  switch (name.value) {
+    case "xs":
+      return 12;
+    case "sm":
+      return 8;
+  }
+});
+
+// action
+async function submit() {
+  console.log("submit ser_no.value", ser_no.value);
+  let response = await mainStore.qrLogIn(
+    email.value,
+    password.value,
+    ser_no.value
+  );
+  console.log("response", response);
+  if (response?.status === 200) {
+    console.log("加值成功");
+    setTimeout(() => {
+      dialog.show = true;
+      dialog.state = "success";
+      dialog.msg =
+        "儲值成功!<br/>已獲得價值 1000 元的 2 分鐘影片製作時間<br/>(加值成功後即可登入電腦版進行影片製作)";
+      dialog.icon = "check_circle";
+    }, 500);
+  } else {
+    dialog.show = true;
+    dialog.state = "error";
+    dialog.msg = "查無此帳號/序號有誤";
+    dialog.icon = "highlight_off";
+  }
+}
+
+// lifecycle
+onMounted(() => {
+  console.log("onMounted");
+  if (route.params.ser_no) {
+    ser_no.value = route.params.ser_no;
+    console.log("ser_no.value", ser_no.value);
+  }
+});
+
+const callback: CallbackTypes.CredentialCallback = (response: any) => {
+  console.log("Handle the response", response);
+  const userData: any = decodeCredential(response.credential);
+  console.log("Handle the userData", userData);
+  mainStore.qrGoogleLogin(userData.email, ser_no.value);
+};
+</script>
+
+<template>
+  <Navbar />
+  <v-container fluid class="pa-0 overflow-hidden">
+    <div class="ai_anchor3_content">
+      <div class="ai_anchor3_content_box">
+        <img
+          class="ai_anchor3_content_title img-fluid"
+          src="../assets/img/qrcode/aianchor3-title.png"
+          alt=""
+        />
+        <h1>集仕多股份有限公司</h1>
+        <h1>AI 主播&ensp;儲值禮物卡</h1>
+      </div>
+      <div class="ai_anchor3_content_start">
+        <!-- <h1>開放倒數</h1> -->
+        <img
+          class="img-fluid"
+          src="../assets/img/qrcode/startline.png"
+          alt=""
+        />
+      </div>
+
+      <!-- <v-row
+        align="center"
+        no-gutters
+        class="overflow-hidden mx-auto login-form"
+      >
+        <v-col :cols="width" class="px-6 my-8 my-md-0">
+          <div class="form-title">
+            <h3>{{ t("login") }}</h3>
+            <span></span>
+          </div>
+          <v-form ref="form" lazy-validation>
+            <v-text-field
+              v-model="email"
+              name="email"
+              prepend-icon="person"
+              :rules="[(v) => !!v || '請輸入您的帳號']"
+              :label="$t('emailAddress')"
+              required
+            >
+            </v-text-field>
+
+            <v-text-field
+              v-model="password"
+              name="password"
+              id="password"
+              prepend-icon="key"
+              :append-icon="showPassword ? 'visibility' : 'visibility_off'"
+              :rules="[(v) => !!v || '請輸入您的密碼']"
+              :type="showPassword ? 'text' : 'password'"
+              :label="$t('password')"
+              hint="4-12 位數密碼"
+              @click:append="showPassword = !showPassword"
+              @keyup.enter="submit"
+              required
+            >
+            </v-text-field>
+
+            <p class="text-center">
+              {{ t("haventAccount") }}
+              <router-link to="/signup">{{ t("register") }}</router-link> /
+              <router-link to="/recover-password">{{
+                t("forgotPsd")
+              }}</router-link>
+            </p>
+
+            <div class="d-flex flex-column">
+              <v-btn rounded="pill" @click.prevent="submit" class="login-btn">
+                {{ t("loginLink") }}
+              </v-btn>
+
+              <section class="line">
+                <p>&ensp;沒有帳號嗎?使用 Google 快速註冊 &ensp;</p>
+                <span></span>
+              </section>
+
+              <div class="mx-auto mt-5" style="max-width: 235px">
+                <GoogleLogin
+                  :callback="callback"
+                  prompt
+                  popup-type="TOKEN"
+                  class="w-100"
+                />
+              </div>
+            </div>
+          </v-form>
+        </v-col>
+      </v-row> -->
+
+      <div class="ai_anchor_moichiu left-70" style="background: #67b5b5">
+        <v-row align="center" no-gutters class="px-0 mx-0">
+          <v-col cols="12" sm="4">
+            <div class="line1">
+              <img
+                class="img-fluid anchor_moichiu"
+                src="../assets/img/qrcode/moichiu.webp"
+                alt=""
+              />
+              <img
+                class="ai_anchor_line1"
+                src="../assets/img/qrcode/line1.png"
+                alt=""
+              />
+            </div>
+            <div class="anchor_name">
+              <img
+                class="img-fluid"
+                src="../assets/img/qrcode/moichiu.png"
+                alt=""
+              />
+            </div>
+          </v-col>
+          <v-col :cols="width">
+            <div class="ai_anchor_moichiu_text">
+              <p>To. 親愛的 VIP</p>
+              <p>我知道您們已經準備好,開始使用 AI 主播的系統了</p>
+              <p>儲值金還在來的路上</p>
+              <!-- <p>在此之前,系統目前測試中</p> -->
+              <p>預計 2023/04/06 後開始正式上線!</p>
+            </div>
+          </v-col>
+        </v-row>
+      </div>
+      <!-- <div class="mt-100">
+        <div class="ai_anchor_moichiu" style="background: #ce96c1">
+          <v-row align="center" no-gutters class="px-0 mx-0">
+            <v-col :cols="width">
+              <div class="ai_anchor_moichiu_text">
+                <p>如果有任何不清楚的,歡迎與我們聯繫</p>
+                <p>AI 主播系統裡會有使用教學</p>
+                <p>現在即可開始使用</p>
+                <p>先登入系統,看看製作影片還需要哪些東西吧!</p>
+                <p>感謝您的耐心等候</p>
+              </div>
+            </v-col>
+            <v-col cols="4">
+              <div class="line2">
+                <img
+                  class="img-fluid anchor_angela"
+                  src="../assets/img/qrcode/angela.webp"
+                  alt=""
+                />
+                <img
+                  class="ai_anchor_line2"
+                  src="../assets/img/qrcode/line2.png"
+                  alt=""
+                />
+              </div>
+
+              <div class="anchor_name2">
+                <img
+                  class="img-fluid"
+                  src="../assets/img/qrcode/Angela.png"
+                  alt=""
+                />
+              </div>
+            </v-col>
+          </v-row>
+        </div>
+      </div> -->
+      
+      <div class="CTA_Button_div text-center">
+        <button type="button" class="CTA_Button">
+          <!-- 點我開始製作 AI 主播!<br />Log In -->
+          AI 三代主播系統 <br> 於 2023/04/06 正式上線!
+        </button>
+      </div>
+
+      <div class="CTA_box">
+        <a href="https://ai.choozmo.com/ai-presenter/info/" target="_blank">
+          <div class="cta-content">看更多<br />官網介紹</div>
+        </a>
+
+        <a href="https://ai.choozmo.com/contact/service/" target="_blank">
+          <div class="cta-content">
+            聯絡我們
+            <img class="icon20" src="../assets/img/qrcode/icon-19.png" alt="" />
+          </div>
+        </a>
+
+        <a href="https://line.me/R/ti/p/@choozmo?from=page" target="_blank">
+          <div class="cta-content">
+            關注我們
+            <img class="icon20" src="../assets/img/qrcode/icon-20.png" alt="" />
+          </div>
+        </a>
+      </div>
+
+      <div class="logo_box">
+        <img
+          class="choozmologo"
+          src="../assets/img/qrcode/choozmologo.png"
+          alt=""
+        />
+      </div>
+    </div>
+    <Dialog
+      :msg="dialog.msg"
+      :state="dialog.state"
+      :dialog="dialog.show"
+      :icon="dialog.icon"
+      @close="dialog.show = false"
+    ></Dialog>
+  </v-container>
+</template>
+
+<style lang="scss" scoped>
+.ai_anchor3_content {
+  background-image: url("../assets/img/qrcode/aianchor3bg.png");
+  width: 100%;
+  background-size: cover;
+  background-repeat: no-repeat;
+}
+.login-form {
+  color: #fff;
+  margin-bottom: 100px;
+  .line {
+    margin-top: 50px;
+    display: flex;
+    justify-content: center;
+    position: relative;
+    p {
+      position: relative;
+      z-index: 1;
+      color: #fff;
+      background-color: #140720;
+      letter-spacing: 1px;
+    }
+    span {
+      display: block;
+      border-top: 1px solid #fff;
+      width: 400px;
+      position: absolute;
+      bottom: 12px;
+    }
+  }
+  .login-btn {
+    color: #fff;
+    background: #4f4fa0;
+  }
+
+  .form-title span {
+    background: #fff !important;
+  }
+}
+.logo_box {
+  text-align: end;
+  overflow: hidden;
+}
+.choozmologo {
+  width: 500px;
+  margin-right: -50px;
+  margin-bottom: -80px;
+  @media (max-width: 767px) {
+    width: 80vw;
+  }
+  @media (max-width: 376px) {
+    width: 85vw;
+  }
+}
+.cta-content {
+  width: 200px;
+  height: 130px;
+  margin: 0 20px;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+  border: 3px solid #fff;
+  padding: 30px 20px;
+  color: #fff;
+  border-radius: 10px;
+  text-align: center;
+  font-size: 24px;
+  @media (max-width: 767px) {
+    width: 100%;
+    margin: 5vh auto 0;
+  }
+  @media (max-width: 376px) {
+    width: 187px;
+  }
+}
+.icon20 {
+  width: 50px;
+}
+.CTA_box {
+  width: 50%;
+  margin: 100px auto;
+  display: flex;
+  justify-content: space-evenly;
+  @media (max-width: 1200px) {
+    width: 70%;
+  }
+  @media (max-width: 767px) {
+    flex-direction: column;
+  }
+}
+.CTA_Button_div {
+  margin-top: 100px;
+}
+.CTA_Button {
+  width: 400px;
+  height: 120px;
+  border-radius: 50px;
+  background: #4f4fa0;
+  transition: all 300ms ease-in-out;
+  box-shadow: 1px 15px #2e3287;
+  color: #fff;
+  border: none;
+  padding: 0px 30px;
+  font-size: 24px;
+  position: relative;
+  bottom: 0px;
+  left: 0px;
+  transition: all 300ms ease-in-out;
+  font-weight: 600;
+  letter-spacing: 2px;
+  &:hover {
+    bottom: -10px;
+    box-shadow: none;
+  }
+  @media (max-width: 991px) {
+    width: 80%;
+  }
+
+  @media (max-width: 767px) {
+    width: 80%;
+    margin-top: 20vh;
+  }
+  @media (max-width: 575px) {
+    margin-top: 25vh;
+    font-size: 20px;
+  }
+}
+.ai_anchor3_content_box {
+  width: 50vw;
+  margin: 0 auto;
+  padding-top: 150px;
+  text-align: center;
+  color: #fff;
+
+  h1 {
+    font-size: 2rem;
+  }
+  @media (max-width: 991px) {
+    width: 80vw;
+  }
+  @media (max-width: 767px) {
+    width: 90vw;
+  }
+}
+.ai_anchor_moichiu_text {
+  @media (max-width: 767px) {
+    height: 300px;
+    padding: 0;
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+  }
+}
+
+.ai_anchor3_content_start {
+  padding-top: 50px;
+  width: 93%;
+  margin: 0 auto;
+  text-align: center;
+  color: #fff;
+  margin-bottom: 80px;
+  h1 {
+    margin-bottom: -60px;
+  }
+}
+.left-70 {
+  left: 70px;
+  @media (max-width: 991px) {
+    left: 0px;
+  }
+}
+.mt-100 {
+  margin-top: 100px;
+
+  @media (max-width: 767px) {
+    margin-top: 25vh;
+  }
+  @media (max-width: 400px) {
+    margin-top: 35vh;
+  }
+}
+.ai_anchor_moichiu {
+  width: 75%;
+  margin: auto;
+  border-radius: 1rem;
+  padding: 50px 10px;
+  position: relative;
+  @media (max-width: 991px) {
+    width: 80%;
+    padding: 40px 10px;
+  }
+  @media (max-width: 767px) {
+    padding: 20px 10px;
+  }
+  @media (max-width: 767px) {
+    width: 90%;
+  }
+  .anchor_moichiu {
+    margin-left: -60px;
+
+    @media (max-width: 767px) {
+      margin-bottom: 0px;
+      margin-top: 0;
+      position: absolute;
+      width: 50vw;
+      left: 53px;
+      bottom: -134px;
+    }
+  }
+
+  .anchor_moichiu,
+  .anchor_angela {
+    width: 350px;
+    max-width: unset;
+    @media (max-width: 1200px) {
+      width: 300px;
+    }
+    @media (max-width: 991px) {
+      width: 275px;
+    }
+  }
+  .anchor_angela {
+    @media (max-width: 767px) {
+      margin-bottom: 0px;
+      margin-top: 0;
+      position: absolute;
+      right: -60vw;
+      bottom: -103px;
+    }
+  }
+  .anchor_name {
+    position: absolute;
+    bottom: -20px;
+    left: -8px;
+    width: 80px;
+
+    @media (max-width: 991px) {
+      width: 50px;
+      left: -8px;
+      bottom: -20px;
+    }
+    @media (max-width: 767px) {
+      left: 250px;
+      bottom: -170px;
+    }
+
+    img {
+      @media (max-width: 1200px) {
+        max-width: unset;
+        width: 70px;
+      }
+      @media (max-width: 991px) {
+        max-width: unset;
+        width: 65px;
+      }
+    }
+  }
+
+  .anchor_name2 {
+    position: absolute;
+    bottom: -5px;
+    right: 0;
+    width: 100px;
+    @media (max-width: 991px) {
+      bottom: -8px;
+      right: -3px;
+      width: 80px;
+    }
+    @media (max-width: 767px) {
+      bottom: -27vw;
+      right: 280px;
+      width: 100px;
+    }
+    @media (max-width: 575px) {
+      bottom: -32vw;
+      right: 270px;
+      width: 70px;
+    }
+    @media (max-width: 414px) {
+      bottom: -40vw;
+      right: 285px;
+    }
+    p {
+      color: #fff !important;
+      font-size: 14px;
+      margin-bottom: 0rem;
+    }
+    img {
+      width: 100px;
+      @media (max-width: 991px) {
+        width: 80px;
+      }
+      @media (max-width: 767px) {
+        width: 100px;
+      }
+    }
+  }
+  .line1,
+  .line2 {
+    position: relative;
+  }
+
+  .line1 {
+    @media (max-width: 767px) {
+      bottom: -360px;
+    }
+  }
+
+  .line2 {
+    @media (max-width: 991px) {
+      margin-left: 30px;
+    }
+    @media (max-width: 767px) {
+      bottom: -120px;
+    }
+  }
+  .ai_anchor_line1 {
+    max-width: 1500px;
+    position: absolute;
+    bottom: 0px;
+    left: 165px;
+    object-fit: cover;
+    @media (max-width: 1200px) {
+      max-width: 1000px;
+      left: 140px;
+    }
+    @media (max-width: 991px) {
+      width: 85vw;
+      left: 123px;
+    }
+    @media (max-width: 767px) {
+      left: 175px;
+      bottom: -138px;
+    }
+    @media (max-width: 575px) {
+      left: 168px;
+    }
+  }
+  .ai_anchor_line2 {
+    width: 1300px;
+    height: 290px;
+    position: absolute;
+    bottom: 6px;
+    left: -1238px;
+
+    @media (max-width: 1200px) {
+      width: 830px;
+      height: auto;
+      bottom: -5px;
+      left: -775px;
+    }
+
+    @media (max-width: 991px) {
+      width: 700px;
+      height: auto;
+      bottom: -5px;
+      left: -665px;
+    }
+    @media (max-width: 767px) {
+      width: 100vw;
+      bottom: -15vw;
+      left: -345px;
+    }
+    @media (max-width: 575px) {
+      left: -333px;
+    }
+  }
+  p {
+    font-weight: 900;
+    letter-spacing: 3px;
+    text-align: center;
+    margin-bottom: 0.3rem;
+    font-size: 22px;
+
+    @media (max-width: 991px) {
+      font-size: 20px;
+    }
+    @media (max-width: 767px) {
+      font-size: 16px;
+    }
+  }
+}
+.img-fluid {
+  max-width: 100%;
+  height: auto;
+}
+</style>