소스 검색

add orders&contact views

SyuanYu 1 년 전
부모
커밋
ca00d908a2
5개의 변경된 파일254개의 추가작업 그리고 12개의 파일을 삭제
  1. 5 3
      frontend/src/App.vue
  2. 10 0
      frontend/src/router/index.ts
  3. 146 0
      frontend/src/views/Orders.vue
  4. 81 0
      frontend/src/views/main/Contact.vue
  5. 12 9
      frontend/src/views/main/Main.vue

+ 5 - 3
frontend/src/App.vue

@@ -15,7 +15,7 @@ const loggedIn = mainStoreRef.readIsLoggedIn;
 //lifecycle
 onMounted(() => {
   let path = location.pathname;
-  if (path !== "/qrcode" && path !== "/yt-views") {
+  if (path !== "/qrcode" && path !== "/yt-views" && path !== "/orders") {
     mainStore.checkLoggedIn();
   }
 });
@@ -43,14 +43,16 @@ a {
   }
 }
 
+.v-input__details {
+  padding: 3px 16px;
+}
+
 .login-form {
   margin: auto;
   max-width: 500px;
   position: relative;
 
   .v-input__details {
-    padding: 3px;
-
     .v-messages {
       color: #b00020 !important;
       text-align: end;

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

@@ -43,6 +43,11 @@ const router = createRouter({
           name: 'yt-views',
           component: () => import('@/views/YTViews.vue'),
         },
+        {
+          path: 'orders',
+          name: 'orders',
+          component: () => import('@/views/Orders.vue'),
+        },
         {
           path: 'test-yt-views',
           name: 'test-yt-views',
@@ -83,6 +88,11 @@ const router = createRouter({
             //   name: 'yt-views',
             //   component: () => import('@/views/main/YTViews.vue'),
             // },
+            {
+              path: 'contact',
+              name: 'contact',
+              component: () => import('@/views/main/Contact.vue'),
+            },
             {
               path: 'profile',
               name: 'profile',

+ 146 - 0
frontend/src/views/Orders.vue

@@ -0,0 +1,146 @@
+<script setup lang="ts">
+import { useMainStore } from "@/stores/main";
+import { reactive } from "vue";
+import { useI18n } from "vue-i18n";
+
+const { t } = useI18n();
+const mainStore = useMainStore();
+let orders: any[] = reactive([]);
+
+mainStore
+  .getYTViewsList()
+  .then((result) => {
+    console.log(result);
+    if (result) {
+      orders.push(result);
+    }
+  })
+  .catch((error) => {
+    console.error(error);
+  });
+
+console.log("orders", orders);
+
+const headers = [
+  {
+    title: "付款狀態",
+    sortable: true,
+    key: "payment_state",
+    align: "left",
+  },
+  {
+    title: "ID",
+    sortable: true,
+    key: "id",
+    align: "left",
+  },
+  {
+    title: "商品金額",
+    sortable: true,
+    key: "amount",
+    align: "left",
+  },
+  {
+    title: "姓名",
+    sortable: true,
+    key: "name",
+    align: "left",
+  },
+  {
+    title: "電子郵件",
+    sortable: true,
+    key: "email",
+    align: "left",
+  },
+  {
+    title: "公司 / 所屬產業",
+    sortable: true,
+    key: "company",
+    align: "left",
+  },
+  {
+    title: "YouTube 影片網址",
+    sortable: true,
+    key: "url",
+    align: "left",
+  },
+  {
+    title: "影片放送地區",
+    sortable: true,
+    key: "area",
+    align: "left",
+  },
+  {
+    title: "受眾語言",
+    sortable: true,
+    key: "language",
+    align: "left",
+  },
+  {
+    title: "客層",
+    sortable: true,
+    key: "ages",
+    align: "left",
+  },
+  {
+    title: "目標對象區隔",
+    sortable: true,
+    key: "target",
+    align: "left",
+  },
+  {
+    title: "影片主題",
+    sortable: true,
+    key: "theme",
+    align: "left",
+  },
+  {
+    title: "統編號碼",
+    sortable: true,
+    key: "taxID",
+    align: "left",
+  },
+];
+</script>
+
+<template>
+  <div>
+    <v-toolbar light>
+      <v-toolbar-title>
+        <h3>訂單明細</h3>
+      </v-toolbar-title>
+    </v-toolbar>
+    <v-data-table
+      :headers="headers"
+      :items="orders[0]"
+      :sort-by="[{ key: 'id', order: 'desc' }]"
+    >
+      <template v-slot:item.payment_state="{ item }">
+        <span v-if="item.raw.payment_state === 'succeeded'">
+          <v-icon icon="check_circle" color="success" />
+          完成
+        </span>
+        <span v-else-if="item.raw.payment_state === 'waiting'">
+          <v-icon icon="pending" color="warning" />
+          處理中
+        </span>
+        <span v-else>
+          <v-icon icon="warning" color="error" />
+          失敗
+        </span>
+      </template>
+    </v-data-table>
+  </div>
+</template>
+
+<style lang="scss">
+.v-data-table-footer {
+  margin-top: 10px;
+}
+.v-table {
+  td,
+  th {
+    white-space: nowrap;
+  }
+}
+</style>

+ 81 - 0
frontend/src/views/main/Contact.vue

@@ -0,0 +1,81 @@
+<script setup lang="ts">
+import { ref } from "vue";
+import { useMainStore } from "@/stores/main";
+import { storeToRefs } from "pinia";
+import { required, emailRules } from "@/utils";
+import { useI18n } from "vue-i18n";
+
+const { t } = useI18n();
+const valid = ref(true);
+const fullName = ref("");
+const email = ref("");
+const phone = ref("");
+const feedback = ref("");
+const form = ref(null);
+
+const phoneRules = [(v: any) => /^(09\d{8})?$/i.test(v) || "請輸入有效的號碼"];
+
+const mainStore = useMainStore();
+const mainStoreRef = storeToRefs(mainStore);
+const userProfile = mainStoreRef.readUserProfile;
+
+if (userProfile) {
+  if (typeof userProfile.value?.full_name === "string") {
+    fullName.value = userProfile.value.full_name;
+  } else {
+    fullName.value = "";
+  }
+  email.value = userProfile.value!.email;
+}
+
+async function submit() {
+  await (form as any).value.validate();
+  //   if (valid.value) {
+  //     await mainStore.updateUserProfile(updateProfile);
+  //   }
+}
+</script>
+
+<template>
+  <v-container fluid>
+    <v-card class="ma-3 pa-3">
+      <v-card-title>
+        <h3 class="card-title">{{ t("contactUs") }}</h3>
+      </v-card-title>
+      <v-card-text class="pt-3">
+        <v-form ref="form" v-model="valid">
+          <v-text-field
+            :label="$t('userName')"
+            v-model="fullName"
+            :rules="required()"
+            required
+          ></v-text-field>
+          <v-text-field
+            :label="$t('emailAddress')"
+            type="email"
+            v-model="email"
+            :rules="emailRules()"
+            required
+          ></v-text-field>
+          <v-text-field
+            :label="$t('phoneNumber')"
+            type="tel"
+            v-model="phone"
+            :rules="phoneRules"
+          ></v-text-field>
+          <v-textarea
+            :label="$t('feedback')"
+            v-model="feedback"
+            :rules="required()"
+            placeholder="請告訴我們您的使用體驗,您可以在此回報問題、提出功能建議,我們廣納接受各式建議與想法,請從填寫簡短描述開始"
+            required
+          ></v-textarea>
+        </v-form>
+      </v-card-text>
+      <v-card-actions>
+        <v-spacer></v-spacer>
+        <v-btn @click="submit" :disabled="!valid">{{ t("send") }}</v-btn>
+      </v-card-actions>
+    </v-card>
+  </v-container>
+</template>

+ 12 - 9
frontend/src/views/main/Main.vue

@@ -111,27 +111,30 @@ const routeGuardAdmin = async (
             <v-list-item to="/main/progress" prepend-icon="list">
               <v-list-item-title>{{ t("progress") }}</v-list-item-title>
             </v-list-item>
-            <!-- <v-list-item to="/main/make-article" prepend-icon="article">
-              <v-list-item-title>{{ t("article") }}</v-list-item-title>
-            </v-list-item> -->
             <!-- <v-list-item to="/main/make-image" prepend-icon="image">
               <v-list-item-title>圖片優化</v-list-item-title>
             </v-list-item> -->
+            <!-- <v-list-item to="/main/make-article" prepend-icon="article">
+              <v-list-item-title>{{ t("article") }}</v-list-item-title>
+            </v-list-item> -->
             <!-- <v-list-item to="/main/profile/view" prepend-icon="person">
               <v-list-item-title>{{ t("userProfile") }}</v-list-item-title>
             </v-list-item> -->
             <!-- <v-list-item to="/main/yt-views" prepend-icon="ondemand_video">
-              <v-list-item-title>網紅加速器</v-list-item-title>
+              <v-list-item-title>{{ t("ytViews") }}</v-list-item-title>
             </v-list-item> -->
+            <v-list-item to="/main/contact" prepend-icon="email">
+              <v-list-item-title>{{ t("contactUs") }}</v-list-item-title>
+            </v-list-item>
             <v-list-item to="/main/profile/edit" prepend-icon="edit">
               <v-list-item-title>{{ t("editProfile") }}</v-list-item-title>
             </v-list-item>
-            <v-list-item to="/main/profile/password" prepend-icon="key">
+            <!-- <v-list-item to="/main/profile/password" prepend-icon="key">
               <v-list-item-title>{{ t("changePassword") }}</v-list-item-title>
-            </v-list-item>
+            </v-list-item> -->
           </v-list>
         </v-sheet>
-        <v-divider></v-divider>
+        <!-- <v-divider></v-divider> -->
         <v-sheet class="">
           <v-list subheader v-show="hasAdminAccess">
             <v-list-subheader
@@ -238,7 +241,7 @@ const routeGuardAdmin = async (
     <v-footer class="pa-3" app>
       <v-spacer></v-spacer>
       <div class="contact-icon">
-        <a href="https://discord.gg/kHAEcu8T">
+        <a href="https://discord.gg/C6Yk83ZA" target="_blank">
           <img src="@/assets/img/icon/discord.png" alt="discord" />
         </a>
         <a href="mailto:service@choozmo.com">
@@ -281,7 +284,7 @@ const routeGuardAdmin = async (
 .contact-icon {
   margin-top: 10px;
   img {
-    width: 35px;
+    width: 30px;
     margin: 0 5px;
   }
 }