Sfoglia il codice sorgente

fix not complete merged

tomoya 2 anni fa
parent
commit
0d7099de0a

+ 9 - 13
frontend/src/api.ts

@@ -1,6 +1,6 @@
 import axios from "axios";
 import { apiUrl } from "@/env";
-import type { IUserProfile, IUserProfileUpdate, IUserProfileCreate, Video, VideoCreate} from "@/interfaces";
+import type { IUserProfile, IUserProfileUpdate, IUserProfileCreate, Video, VideoCreate, ArticleCreate, ImageDownload } from "@/interfaces";
 
 function authHeaders(token: string) {
   return {
@@ -49,15 +49,15 @@ export const api = {
   async registerUser(data: IUserProfileCreate) {
     return axios.post(`${apiUrl}/api/v1/users/open`, data);
   },
-  async testCeleryMsg(token: string, data:{msg: string}){
-    return axios.post<{msg:string}>(`${apiUrl}/api/v1/utils/test-celery/msg`, data, authHeaders(token));
+  async testCeleryMsg(token: string, data: { msg: string }) {
+    return axios.post<{ msg: string }>(`${apiUrl}/api/v1/utils/test-celery/msg`, data, authHeaders(token));
   },
-  async testCeleryFile(token: string, file: File){
+  async testCeleryFile(token: string, file: File) {
     const formData = new FormData();
     formData.append("file", file)
-    return axios.post<{msg:string}>(`${apiUrl}/api/v1/utils/test-celery/file`, formData, authHeaders(token));
+    return axios.post<{ msg: string }>(`${apiUrl}/api/v1/utils/test-celery/file`, formData, authHeaders(token));
   },
-  async uploadPlot(token: string, video_data:VideoCreate, file: File){
+  async uploadPlot(token: string, video_data: VideoCreate, file: File) {
     const formData = new FormData();
     formData.append("title", video_data.title)
     formData.append("anchor_id", video_data.anchor_id.toString())
@@ -102,11 +102,7 @@ export const api = {
   async getVideos(token: string) {
     return axios.get<Video[]>(`${apiUrl}/api/v1/videos/`, authHeaders(token));
   },
-  async googleLogInGetToken(username: string, password: string){
-    const params = new URLSearchParams();
-    params.append("username", username);
-    params.append("password", password);
-
-    return axios.post(`${apiUrl}/api/v1/login/google/access-token`, params);
+  async googleLogin(access_token: string) {
+    return axios.post(`${apiUrl}/api/v1/login/google/access-token/${access_token}`,)
   },
-};
+};

+ 1 - 2
frontend/src/env.ts

@@ -16,5 +16,4 @@ if (env === "production") {
 export const apiUrl = envApiUrl;
 export const wsUrl = envWsUrl;
 export const appName = import.meta.env.VITE_APP_NAME;
-export const openRegisration = import.meta.env.VITE_APP_OPEN_REGISRATION;
-
+export const openRegisration = import.meta.env.VITE_APP_OPEN_REGISRATION;

+ 18 - 19
frontend/src/interfaces/index.ts

@@ -1,27 +1,25 @@
 export interface IUserProfile {
-    email: string;
-    is_active: boolean;
-    is_superuser: boolean;
-    full_name?: string;
-    id: number;
-    available_time: number;
-    membership_status: string;
+  email: string;
+  is_active: boolean;
+  is_superuser: boolean;
+  full_name?: string;
+  id: number;
 }
 
 export interface IUserProfileUpdate {
-    email?: string;
-    full_name?: string;
-    password?: string;
-    is_active?: boolean;
-    is_superuser?: boolean;
+  email?: string;
+  full_name?: string;
+  password?: string;
+  is_active?: boolean;
+  is_superuser?: boolean;
 }
 
 export interface IUserProfileCreate {
-    email: string;
-    full_name?: string;
-    password: string;
-    is_active?: boolean;
-    is_superuser?: boolean;
+  email: string;
+  full_name?: string;
+  password: string;
+  is_active?: boolean;
+  is_superuser?: boolean;
 }
 
 export interface AppNotification {
@@ -39,6 +37,7 @@ export interface MainState {
   dashboardShowDrawer: boolean;
   notifications: AppNotification[];
   videos: Video[];
+  images: Image[];
 };
 
 export interface Video {
@@ -48,7 +47,7 @@ export interface Video {
   progress_state: string;
 }
 
-export interface VideoCreate{
+export interface VideoCreate {
   title: string;
   anchor_id: number;
   lang_id: number;
@@ -70,4 +69,4 @@ export interface Image {
 export interface ImageDownload {
   file_name: string;
   stored_file_name: string;
-}
+}

+ 1 - 1
frontend/src/main.ts

@@ -18,4 +18,4 @@ app.use(vue3GoogleLogin, {
 
 app.mount("#app");
 
-export default app;
+export default app;

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

@@ -4,7 +4,7 @@ import { api } from "@/api"
 import router from "@/router"
 import { getLocalToken, removeLocalToken, saveLocalToken } from "@/utils";
 import type { AppNotification } from '@/interfaces';
-import type { IUserProfile, IUserProfileCreate, IUserProfileUpdate, MainState, Video, VideoCreate } from '@/interfaces';
+import type { IUserProfile, IUserProfileCreate, IUserProfileUpdate, MainState, Video, VideoCreate, ArticleCreate, Image, ImageDownload } from '@/interfaces';
 import i18n from '@/plugins/i18n'
 import WS from "@/stores/ws";
 
@@ -17,6 +17,7 @@ const defaultState: MainState = {
   dashboardShowDrawer: true,
   notifications: [],
   videos: [],
+  images: [],
 };
 
 export const useMainStore = defineStore("MainStoreId", {
@@ -63,7 +64,6 @@ export const useMainStore = defineStore("MainStoreId", {
           this.setLoggedIn(true);
           this.setLogInError(false);
           await this.getUserProfile();
-          console.log(this.userProfile);
           await this.routeLoggedIn();
           this.addNotification({ content: i18n.global.t("loggedIn"), color: "success" });
         } else {
@@ -358,27 +358,15 @@ export const useMainStore = defineStore("MainStoreId", {
         await mainStore.checkApiError(error);
       }
     },
-    async googleLogin(username:string, password: string) {
+    async googleLogin(access_token: string) {
       try {
-        const response = await api.googleLogInGetToken(username, password);
-        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();
+        const response = await api.googleLogin(access_token)
+        if (response) {
+          console.log(response)
         }
-      } catch (err) {
-        this.setLogInError(true);
-        await this.logOut();
+      } catch (error) {
+        await this.checkApiError(error)
       }
     }
   }
 });
-
-

+ 39 - 32
frontend/src/views/main/Image.vue

@@ -1,5 +1,5 @@
 <script setup lang="ts">
-import { ref, reactive } from "vue";
+import { ref, reactive, onMounted } from "vue";
 import { useMainStore } from "@/stores/main";
 import { required } from "@/utils";
 import { useI18n } from "vue-i18n";
@@ -10,29 +10,10 @@ import WS from "@/stores/ws";
 const mainStore = useMainStore();
 const { t } = useI18n();
 const valid = ref(true);
-const dialog = ref(false);
-const title = ref("");
 const Form = ref();
 let imgFiles = ref();
 let imgList: any[] = reactive([]);
 
-async function upload() {
-  for (let i = 0; i < imgFiles.value.files.length; i++) {
-    const item = imgFiles.value.files[i];
-    imgList.push(item);
-    console.log("element", item.name);
-  }
-}
-
-// async function Submit() {
-//   setTimeout(() => {
-//     dialog.value = true;
-//   }, 2000);
-//   await (Form as any).value.validate();
-//   if (valid.value) {
-//     valid.value = false;
-//   }
-// }
 // props
 let dialog = reactive({
   msg: "圖片處理需要幾秒鐘的時間,敬請耐心等候",
@@ -89,7 +70,7 @@ const headers = [
   {
     title: "檔名",
     sortable: true,
-    key: "name",
+    key: "file_name",
     align: "left",
   },
   {
@@ -99,8 +80,8 @@ const headers = [
     align: "left",
   },
   {
-    title: t("preview"),
-    key: "id",
+    title: t("download"),
+    key: "stored_file_name",
   },
 ];
 </script>
@@ -112,16 +93,29 @@ const headers = [
         <h3 class="card-title mb-3">圖片優化</h3>
       </v-card-title>
       <v-card-text>
-        <v-form v-model="valid" ref="Form" class="img-form">
-          <img src="@/assets/img/icon/add-image.png" alt="" class="mb-4" />
-          <input
+        <!-- <section class="d-flex flex-column form-title">
+        <img src="@/assets/img/icon/add-image.png" alt="" class="mb-4" />
+        <p>請點擊加入圖片並開始優化</p>
+       </section> -->
+
+        <v-form v-model="valid" ref="Form">
+          <!-- <img src="@/assets/img/icon/add-image.png" alt="" class="mb-4" /> -->
+          <!-- <input
             @change="upload()"
             ref="imgFiles"
             type="file"
             multiple
             class="file-input"
-          />
-          <p>請點擊加入圖片並開始優化</p>
+          /> -->
+
+          <v-file-input
+            v-model="imgFiles"
+            multiple
+            label="請選擇圖片"
+            prepend-icon="add_photo_alternate"
+          ></v-file-input>
+
+          <!-- <p>請點擊加入圖片並開始優化</p> -->
         </v-form>
       </v-card-text>
       <v-card-actions class="justify-center">
@@ -131,7 +125,8 @@ const headers = [
           color="primary"
           class="px-5"
           prepend-icon="file_upload"
-          >上傳圖片</v-btn
+          @click="Submit()"
+          >上傳</v-btn
         >
       </v-card-actions>
     </v-card>
@@ -156,11 +151,23 @@ const headers = [
             處理中
           </span>
         </template>
-        <template v-slot:item.id="{ item }">
-          <v-icon icon="crop_original" />
+        <template v-slot:item.stored_file_name="{ item }">
+          <v-btn
+            flat
+            @click="downloadImg(item.raw.file_name, item.raw.stored_file_name)"
+          >
+            <v-icon icon="crop_original" />
+          </v-btn>
         </template>
       </v-data-table>
     </v-card>
+
+    <Dialog
+      :msg="dialog.msg"
+      :state="dialog.state"
+      :dialog="dialog.show"
+      @close="dialog.show = false"
+    ></Dialog>
   </v-container>
 </template>
 
@@ -207,4 +214,4 @@ const headers = [
     margin-top: 20px;
   }
 }
-</style>
+</style>

+ 85 - 48
frontend/src/views/main/Upload.vue

@@ -3,28 +3,19 @@ import { ref, reactive, watch, computed } from "vue";
 import { useMainStore } from "@/stores/main";
 import { required } from "@/utils";
 import { useI18n } from "vue-i18n";
-import { useDisplay } from "vuetify";
 import type { VideoCreate } from "@/interfaces";
 import router from "@/router";
+import Dialog from "@/components/Dialog.vue";
 
-const { t } = useI18n();
-const { name } = useDisplay();
-const width = computed(() => {
-  switch (name.value) {
-    case "xs":
-      return 6;
-    case "sm":
-      return 4;
-    case "md":
-      return 3;
-    case "lg":
-      return 2;
-  }
-  return "auto";
+// props
+let dialog = reactive({
+  msg: "影片處理需要約 5-10 分鐘,敬請耐心等候",
+  state: "info",
+  show: false,
 });
 
+const { t } = useI18n();
 const valid = ref(true);
-const dialog = ref(false);
 const title = ref("");
 const zipFiles = ref();
 const Form = ref();
@@ -35,102 +26,102 @@ const anchorList = reactive([
   {
     anchor_id: 0,
     language_id: 1,
-    name: "Peggy",
+    name: "Angela",
   },
   {
     anchor_id: 1,
     language_id: 1,
-    name: "Jocelyn",
+    name: "半身主播-1",
   },
   {
     anchor_id: 2,
     language_id: 1,
-    name: "Summer",
+    name: "半身主播-2",
   },
   {
     anchor_id: 3,
     language_id: 1,
-    name: "Angela",
+    name: "半身主播-3",
   },
   {
     anchor_id: 4,
     language_id: 1,
-    name: "半身主播-1",
+    name: "半身主播-4",
   },
   {
     anchor_id: 5,
     language_id: 1,
-    name: "半身主播-2",
+    name: "半身主播-5",
   },
   {
     anchor_id: 6,
     language_id: 1,
-    name: "半身主播-3",
+    name: "半身主播-6",
   },
   {
     anchor_id: 7,
     language_id: 1,
-    name: "半身主播-4",
+    name: "半身主播-7",
   },
   {
     anchor_id: 8,
     language_id: 1,
-    name: "半身主播-5",
+    name: "半身主播-8",
   },
   {
     anchor_id: 9,
     language_id: 1,
-    name: "半身主播-6",
+    name: "半身主播-9",
   },
   {
     anchor_id: 10,
     language_id: 1,
-    name: "半身主播-7",
+    name: "半身主播-10",
   },
   {
     anchor_id: 11,
     language_id: 1,
-    name: "半身主播-8",
+    name: "半身主播-11",
   },
   {
     anchor_id: 12,
     language_id: 1,
-    name: "半身主播-9",
+    name: "半身主播-12",
   },
   {
     anchor_id: 13,
     language_id: 1,
-    name: "半身主播-10",
+    name: "半身主播-13",
   },
   {
     anchor_id: 14,
     language_id: 1,
-    name: "半身主播-11",
+    name: "半身主播-14",
   },
   {
     anchor_id: 15,
     language_id: 1,
-    name: "半身主播-12",
+    name: "半身主播-15",
   },
   {
     anchor_id: 16,
     language_id: 1,
-    name: "半身主播-13",
+    name: "半身主播-16",
   },
   {
     anchor_id: 17,
     language_id: 1,
-    name: "半身主播-14",
+    name: "Peggy",
   },
   {
     anchor_id: 18,
     language_id: 1,
-    name: "半身主播-15",
+    name: "Jocelyn",
   },
   {
     anchor_id: 19,
     language_id: 1,
-    name: "半身主播-16",
+    name: "Summer",
   },
 ]);
 
@@ -169,20 +160,23 @@ let items = reactive([
 
 // 取得圖片路徑
 const getImageUrl = (imgFolder: string, name: string) => {
-  return new URL(`../../assets/img/${imgFolder}/${name}.webp`, import.meta.url).href;
+  return new URL(`../../assets/img/${imgFolder}/${name}.webp`, import.meta.url)
+    .href;
 };
 
 const mainStore = useMainStore();
 
 watch(dialog, (newVal, oldVal) => {
-  if (!newVal) {
-    router.push("/main/progress");
+  if (!newVal.show) {
+    setTimeout(() => {
+      router.push("/main/progress");
+    }, 500);
   }
 });
 
 async function Submit() {
   setTimeout(() => {
-    dialog.value = true;
+    dialog.show = true;
   }, 2000);
   await (Form as any).value.validate();
   if (valid.value) {
@@ -247,9 +241,22 @@ async function Submit() {
                           dark
                           @click="toggle"
                           :title="n.name"
+                          :disabled="n.anchor_id !== 0"
                         >
                           <v-scroll-y-transition>
-                            <img :src="getImageUrl('anchor', n.name)" alt="" />
+                            <div v-if="n.anchor_id !== 0" class="img-disabled">
+                              <img
+                                :src="getImageUrl('anchor', n.name)"
+                                alt=""
+                              />
+                              <p>Coming Soon</p>
+                            </div>
+
+                            <img
+                              v-else
+                              :src="getImageUrl('anchor', n.name)"
+                              alt=""
+                            />
                           </v-scroll-y-transition>
                         </v-card>
                       </v-item>
@@ -287,7 +294,6 @@ async function Submit() {
                       >
                         <v-icon icon="done" color="white" />
                       </span>
-                      <img :src="getImageUrl('template', n.img)" alt="" />
                       <div :class="{ 'img-disabled': n.template_id !== 0 }">
                         <img :src="getImageUrl('template', n.img)" alt="" />
                         <p v-if="n.template_id !== 0">Coming Soon</p>
@@ -346,9 +352,8 @@ async function Submit() {
                 <br />
                 (建議 10 個字內,若超過請使用換行符號)
               </li>
-              <li>2. 字幕段落勿超過中文 25 字、英文 50 字</li>
-              <li>3. 大標字數勿超過中文 15 字、英文 30 字</li>
-              <li>4. 音檔請留空白</li>
+              <li>2. 大標字數勿超過中文 15 字、英文 30 字</li>
+              <li>3. 音檔請留空白</li>
             </ul>
             <p class="mt-5 excerpt">以下為顯示效果:</p>
             <img src="@/assets/img/step/step-04.png" alt="" />
@@ -372,7 +377,7 @@ async function Submit() {
 
     <template>
       <div class="text-center">
-        <v-dialog v-model="dialog" width="auto">
+        <!-- <v-dialog v-model="dialog" width="auto">
           <v-card>
             <v-card-text>
               <section class="d-flex flex-column align-center">
@@ -390,7 +395,14 @@ async function Submit() {
               }}</v-btn>
             </v-card-actions>
           </v-card>
-        </v-dialog>
+        </v-dialog> -->
+
+        <Dialog
+          :msg="dialog.msg"
+          :state="dialog.state"
+          :dialog="dialog.show"
+          @close="dialog.show = false"
+        ></Dialog>
       </div>
     </template>
   </v-container>
@@ -522,4 +534,29 @@ async function Submit() {
     margin-bottom: 2px;
   }
 }
-</style>
+
+.img-disabled {
+  position: relative;
+  z-index: 999;
+  background-color: #ccc;
+  margin-bottom: -5px;
+  img {
+    opacity: 0.7;
+  }
+  p {
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    color: #fff;
+    transform: translate(-50%, -50%);
+    font-size: 16px;
+    text-align: center;
+    letter-spacing: 1px;
+    text-shadow: 2px 2px 6px #000;
+  }
+}
+
+.v-card--disabled > :not(.v-card__loader) {
+  opacity: 1 !important;
+}
+</style>