xiongzhu 1 year ago
parent
commit
e4ab0ed085

+ 0 - 1
.env

@@ -1 +0,0 @@
-VITE_API_BASE_URL=/api

+ 4 - 0
.env.app

@@ -0,0 +1,4 @@
+VITE_BASE_URL=/
+VITE_API_BASE_URL=https://shorts.izouma.com/api/
+VITE_APP=true
+VITE_STORAGE_TYPE=oss

+ 1 - 0
.env.development

@@ -1 +1,2 @@
+VITE_BASE_URL=/
 VITE_API_BASE_URL=http://localhost:3333/api

+ 2 - 0
.env.production

@@ -0,0 +1,2 @@
+VITE_BASE_URL=/app/
+VITE_API_BASE_URL=/api/

+ 107 - 0
VitePluginUploadPackage.js

@@ -0,0 +1,107 @@
+/* eslint-disable */
+import { loadEnv } from 'vite'
+import archiver from 'archiver'
+import fs from 'fs'
+import OSS from 'ali-oss'
+import { format } from 'date-fns'
+import { Buffer } from 'node:buffer'
+import COS from 'cos-nodejs-sdk-v5'
+
+async function ossUpload(filePath, version) {
+    let client = new OSS({
+        accessKeyId: 'PXzJyah5rZfWHIIH',
+        accessKeySecret: 'e1MS6j0wypXJrw8CM0hObZu8qKbfah',
+        region: 'oss-cn-hangzhou',
+        bucket: 'zm-shorts'
+    })
+    let { url } = await client.put(`packages/${format(new Date(), 'yyyyMMddHHmmss')}.zip`, filePath, {
+        headers: {
+            'x-oss-object-acl': 'public-read'
+        }
+    })
+    url = url.replace('http://', 'https://')
+    console.log('package uploaded: %s', url.replace('http://', 'https://'))
+    await client.put('packages/freeshort/meta.json', Buffer.from(JSON.stringify({ url, version: version })), {
+        headers: { 'x-oss-object-acl': 'public-read' }
+    })
+}
+
+async function cosUpload(filePath, version) {
+    var cos = new COS({
+        SecretId: 'IKIDhOGOYkw59GUh0FMONLJKPLGfzJ5oeaWO',
+        SecretKey: 'sfSC9ACC9zjVK7BMUew8SmEdtBgDi6dI'
+    })
+    const url = await new Promise((resolve, reject) => {
+        cos.putObject(
+            {
+                Bucket: 'duanju2-1321229830',
+                Region: 'ap-jakarta',
+                Key: `packages/${format(new Date(), 'yyyyMMddHHmmss')}.zip`,
+                StorageClass: 'STANDARD',
+                Body: fs.createReadStream(filePath),
+                ACL: 'public-read'
+            },
+            function (err, data) {
+                if (err) reject(err)
+                else resolve('https://' + data.Location)
+            }
+        )
+    })
+    console.log('package uploaded: %s', url)
+    await new Promise((resolve, reject) => {
+        cos.putObject(
+            {
+                Bucket: 'duanju2-1321229830',
+                Region: 'ap-jakarta',
+                Key: 'packages/freeshort/meta.json',
+                StorageClass: 'STANDARD',
+                Body: Buffer.from(JSON.stringify({ url, version: version })),
+                ACL: 'public-read'
+            },
+            function (err, data) {
+                if (err) reject(err)
+                else resolve(data)
+            }
+        )
+    })
+}
+
+export default function VitePluginUploadPackage() {
+    let mode = ''
+    let env = {}
+    return {
+        name: 'upload-package',
+        config(config, { command }) {
+            mode = config.mode
+            env = loadEnv(mode, process.cwd())
+        },
+        async closeBundle(options) {
+            if (env['VITE_APP'] !== 'true') return
+            const meta = JSON.parse(fs.readFileSync('./src/assets/meta.json'))
+
+            const sourceDir = 'dist'
+            const outputFilePath = 'dist.zip'
+
+            await new Promise((resolve, reject) => {
+                const output = fs.createWriteStream(outputFilePath)
+                output.on('close', function () {
+                    resolve()
+                })
+                const archive = archiver('zip')
+                archive.pipe(output)
+                archive.directory(sourceDir, false)
+                archive.finalize()
+            }).catch(e => {
+                console.log(e)
+            })
+            switch (env['VITE_STORAGE_TYPE']) {
+                case 'oss':
+                    await ossUpload(outputFilePath, meta.version)
+                    break
+                case 'cos':
+                    await cosUpload(outputFilePath, meta.version)
+                    break
+            }
+        }
+    }
+}

+ 8 - 0
android/app/capacitor.build.gradle

@@ -9,10 +9,18 @@ android {
 
 apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle"
 dependencies {
+    implementation project(':capacitor-community-media')
     implementation project(':capacitor-app')
+    implementation project(':capacitor-app-launcher')
+    implementation project(':capacitor-browser')
+    implementation project(':capacitor-camera')
+    implementation project(':capacitor-device')
+    implementation project(':capacitor-filesystem')
     implementation project(':capacitor-haptics')
     implementation project(':capacitor-keyboard')
+    implementation project(':capacitor-share')
     implementation project(':capacitor-status-bar')
+    implementation project(':capgo-capacitor-updater')
     implementation project(':capacitor-plugin-safe-area')
 
 }

+ 5 - 2
android/app/src/main/AndroidManifest.xml

@@ -1,5 +1,10 @@
 <?xml version="1.0" encoding="utf-8" ?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android">
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
+    <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
     <application
         android:allowBackup="true"
         android:icon="@mipmap/ic_launcher"
@@ -29,7 +34,5 @@
         </provider>
     </application>
 
-    <!-- Permissions -->
 
-    <uses-permission android:name="android.permission.INTERNET" />
 </manifest>

+ 24 - 0
android/capacitor.settings.gradle

@@ -2,17 +2,41 @@
 include ':capacitor-android'
 project(':capacitor-android').projectDir = new File('../node_modules/@capacitor/android/capacitor')
 
+include ':capacitor-community-media'
+project(':capacitor-community-media').projectDir = new File('../node_modules/@capacitor-community/media/android')
+
 include ':capacitor-app'
 project(':capacitor-app').projectDir = new File('../node_modules/@capacitor/app/android')
 
+include ':capacitor-app-launcher'
+project(':capacitor-app-launcher').projectDir = new File('../node_modules/@capacitor/app-launcher/android')
+
+include ':capacitor-browser'
+project(':capacitor-browser').projectDir = new File('../node_modules/@capacitor/browser/android')
+
+include ':capacitor-camera'
+project(':capacitor-camera').projectDir = new File('../node_modules/@capacitor/camera/android')
+
+include ':capacitor-device'
+project(':capacitor-device').projectDir = new File('../node_modules/@capacitor/device/android')
+
+include ':capacitor-filesystem'
+project(':capacitor-filesystem').projectDir = new File('../node_modules/@capacitor/filesystem/android')
+
 include ':capacitor-haptics'
 project(':capacitor-haptics').projectDir = new File('../node_modules/@capacitor/haptics/android')
 
 include ':capacitor-keyboard'
 project(':capacitor-keyboard').projectDir = new File('../node_modules/@capacitor/keyboard/android')
 
+include ':capacitor-share'
+project(':capacitor-share').projectDir = new File('../node_modules/@capacitor/share/android')
+
 include ':capacitor-status-bar'
 project(':capacitor-status-bar').projectDir = new File('../node_modules/@capacitor/status-bar/android')
 
+include ':capgo-capacitor-updater'
+project(':capgo-capacitor-updater').projectDir = new File('../node_modules/@capgo/capacitor-updater/android')
+
 include ':capacitor-plugin-safe-area'
 project(':capacitor-plugin-safe-area').projectDir = new File('../node_modules/capacitor-plugin-safe-area/android')

+ 0 - 1
capacitor.config.ts

@@ -6,7 +6,6 @@ const config: CapacitorConfig = {
     webDir: "dist",
     server: {
         androidScheme: "https",
-        url: "http://192.168.50.202:4173",
         cleartext: true,
     },
     android: {},

BIN
dist.zip


+ 14 - 0
package.json

@@ -12,14 +12,22 @@
     "lint": "eslint ."
   },
   "dependencies": {
+    "@capacitor-community/media": "^5.4.0",
     "@capacitor/android": "^5.7.2",
     "@capacitor/app": "5.0.7",
+    "@capacitor/app-launcher": "^5.0.7",
     "@capacitor/assets": "^3.0.4",
+    "@capacitor/browser": "^5.2.0",
+    "@capacitor/camera": "^5.0.9",
     "@capacitor/core": "5.7.2",
+    "@capacitor/device": "^5.0.7",
+    "@capacitor/filesystem": "^5.2.1",
     "@capacitor/haptics": "5.0.7",
     "@capacitor/ios": "^5.7.2",
     "@capacitor/keyboard": "5.0.8",
+    "@capacitor/share": "^5.0.7",
     "@capacitor/status-bar": "5.0.7",
+    "@capgo/capacitor-updater": "^5.6.13",
     "@ionic/vue": "^7.0.0",
     "@ionic/vue-router": "^7.0.0",
     "@tailwindcss/aspect-ratio": "^0.4.2",
@@ -28,7 +36,9 @@
     "@vueuse/integrations": "^10.9.0",
     "axios": "^1.6.7",
     "capacitor-plugin-safe-area": "^2.0.6",
+    "date-fns": "^3.5.0",
     "eruda": "^3.0.1",
+    "file-saver": "^2.0.5",
     "ionicons": "^7.0.0",
     "less": "^4.2.0",
     "mitt": "^3.0.1",
@@ -42,13 +52,17 @@
   },
   "devDependencies": {
     "@capacitor/cli": "5.7.2",
+    "@types/file-saver": "^2.0.7",
     "@types/qs": "^6.9.12",
     "@types/validator": "^13.11.9",
     "@vitejs/plugin-legacy": "^5.0.0",
     "@vitejs/plugin-vue": "^4.0.0",
     "@vue/eslint-config-typescript": "^12.0.0",
     "@vue/test-utils": "^2.3.0",
+    "ali-oss": "^6.20.0",
+    "archiver": "^7.0.1",
     "autoprefixer": "^10.4.18",
+    "cos-nodejs-sdk-v5": "^2.13.3",
     "cypress": "^13.5.0",
     "eslint": "^8.35.0",
     "eslint-plugin-vue": "^9.9.0",

+ 4 - 0
src/assets/meta.json

@@ -0,0 +1,4 @@
+{
+    "version": 1,
+    "versionName": "1.0.0"
+}

+ 6 - 2
src/components/PlayView.vue

@@ -44,7 +44,10 @@
                     />
                 </template>
                 <div class="tool-bar flex">
-                    <div class="px-2 flex items-center" @click.stop="router.back()">
+                    <div
+                        class="px-2 flex items-center"
+                        @click.stop="router.back()"
+                    >
                         <IonIcon
                             :icon="chevronBack"
                             class="text-2xl opacity-80 h-10"
@@ -117,6 +120,7 @@
                     </div>
                     <div
                         class="btn flex flex-col items-center justify-center mt-4"
+                        @click.stop="emit('share')"
                     >
                         <IonIcon
                             :icon="arrowRedo"
@@ -240,7 +244,7 @@ const props = defineProps({
     episodes: Array<any>,
     saved: Boolean,
 });
-const emit = defineEmits(["chooseEpisode", "save", "ended", "pay"]);
+const emit = defineEmits(["chooseEpisode", "save", "ended", "pay", "share"]);
 const router = useIonRouter();
 const video: Ref<HTMLVideoElement | null> = ref(null);
 const { playing, currentTime, duration, volume } = useMediaControls(video);

+ 159 - 0
src/components/ShareModal.vue

@@ -0,0 +1,159 @@
+<template>
+    <ion-modal
+        class="invite-modal"
+        :isOpen="showInviteModal"
+        @didDismiss="showInviteModal = false"
+    >
+        <div class="content-wrapper text-base font-bold">
+            <div class="code-wrapper flex flex-col items-center justify-center">
+                <div class="font-bold">INVITE 3 FRIENDS</div>
+                <div class="">GET 7 DAYS FREE WATCHING</div>
+                <img class="mt-2" :src="qrcode" alt="QR Code" />
+                <div class="mt-2 font-bold">INVITED: 0</div>
+            </div>
+            <div class="flex mt-4 text-center text-sm">
+                <div
+                    class="flex-grow border-2 border-white rounded-full box-border h-10 flex items-center justify-center"
+                    @click="save"
+                >
+                    Save QR Code
+                </div>
+                <div
+                    class="ml-6 flex-grow bg-prim rounded-full h-10 flex items-center justify-center"
+                    @click="share"
+                >
+                    Share
+                </div>
+            </div>
+        </div>
+    </ion-modal>
+</template>
+<script setup lang="ts">
+import { computed, ref, watch } from "vue";
+import { IonModal } from "@ionic/vue";
+import { useUserStore } from "@/store/user";
+import { storeToRefs } from "pinia";
+import { useQRCode } from "@vueuse/integrations/useQRCode";
+import { Capacitor } from "@capacitor/core";
+import { Filesystem, Directory, Encoding } from "@capacitor/filesystem";
+import { Media } from "@capacitor-community/media";
+import { Share } from "@capacitor/share";
+import toast from "@/plugins/toast";
+import { saveAs } from "file-saver";
+import { useClipboard } from "@vueuse/core";
+import http from "@/plugins/http";
+
+const userStore = useUserStore();
+const { user } = storeToRefs(userStore);
+
+const showInviteModal = ref(false);
+
+const shareUrl = computed(() => {
+    return http.resolve("/static/share2.html?referrer=" + user.value?.id);
+});
+
+const qrcode = useQRCode(shareUrl, { margin: 2, width: 512 });
+
+const props = defineProps({
+    modelValue: Boolean,
+});
+const emit = defineEmits(["update:modelValue"]);
+showInviteModal.value = props.modelValue || false;
+watch(showInviteModal, (val) => {
+    emit("update:modelValue", val);
+});
+watch(
+    () => props.modelValue,
+    (val) => {
+        showInviteModal.value = val;
+    }
+);
+
+const b64toBlob = (b64Data: string, contentType = "", sliceSize = 512) => {
+    b64Data = b64Data.replace(/data:.+base64,/, "");
+    console.log(b64Data);
+    const byteCharacters = atob(b64Data);
+    const byteArrays = [];
+
+    for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
+        const slice = byteCharacters.slice(offset, offset + sliceSize);
+
+        const byteNumbers = new Array(slice.length);
+        for (let i = 0; i < slice.length; i++) {
+            byteNumbers[i] = slice.charCodeAt(i);
+        }
+
+        const byteArray = new Uint8Array(byteNumbers);
+        byteArrays.push(byteArray);
+    }
+
+    const blob = new Blob(byteArrays, { type: contentType });
+    return blob;
+};
+
+async function save() {
+    if (Capacitor.isNativePlatform()) {
+        //
+        try {
+            const savedFile = await Filesystem.writeFile({
+                path: "share.png",
+                data: qrcode.value,
+                directory: Directory.Cache,
+            });
+            const albums = (await Media.getAlbums()).albums;
+            console.log(albums);
+            const album = albums?.length
+                ? albums.find((a) => a.name === "Camera") || albums[0]
+                : null;
+            await Media.savePhoto({
+                path: savedFile.uri,
+                albumIdentifier: album?.identifier,
+                fileName: "share",
+            });
+            toast("Saved", { type: "success" });
+        } catch (e) {
+            console.log(e);
+        }
+    } else {
+        saveAs(b64toBlob(qrcode.value), "share.png");
+    }
+}
+
+async function share() {
+    //
+    if (Capacitor.isNativePlatform()) {
+        await Share.share({
+            title: "Invite Friends",
+            url: shareUrl.value,
+            dialogTitle: "Invite Friends",
+        });
+    } else {
+        const clipboard = useClipboard();
+        clipboard.copy(shareUrl.value);
+        toast("Share Link Copied", { type: "success" });
+    }
+}
+</script>
+<style lang="less" scoped>
+.invite-modal {
+    --width: fit-content;
+    --min-width: 290px;
+    --height: fit-content;
+    --border-radius: 0;
+    --background: transparent;
+    .content-wrapper {
+        .code-wrapper {
+            width: 290px;
+            height: 350px;
+            background-image: url(@/assets/bg_invite_modal.png);
+            background-size: cover;
+            background-position: center;
+            img {
+                width: 215px;
+                height: 215px;
+                border-radius: 8px;
+            }
+        }
+    }
+}
+</style>

+ 3 - 1
src/main.ts

@@ -8,7 +8,7 @@ import { GesturePlugin } from "@vueuse/gesture";
 import { Capacitor } from "@capacitor/core";
 import { StatusBar, Style } from "@capacitor/status-bar";
 import { SafeArea } from "capacitor-plugin-safe-area";
-
+import { checkUpdate } from "./plugins/updater";
 import "./theme/tailwind.css";
 
 /* Core CSS required for Ionic components to work properly */
@@ -47,7 +47,9 @@ if (Capacitor.isNativePlatform()) {
             // style.setProperty('--ion-safe-area-bottom', insets.bottom + 'px')
         });
     }
+    
 }
+checkUpdate();
 
 const app = createApp(App)
     .use(createPinia())

+ 33 - 0
src/plugins/updater.ts

@@ -0,0 +1,33 @@
+import meta from '@/assets/meta.json'
+import { CapacitorUpdater } from '@capgo/capacitor-updater'
+import { Capacitor } from '@capacitor/core'
+import axios from 'axios'
+if (Capacitor.isNativePlatform()) {
+    CapacitorUpdater.notifyAppReady()
+}
+window.meta = meta
+console.log('meta', meta)
+
+CapacitorUpdater.addListener('download', ({ percent }) => {
+    console.log('download progress:', percent)
+})
+CapacitorUpdater.addListener('downloadFailed', e => {
+    console.log('downloadFailed', e)
+})
+
+const checkUpdate = async (showPrompt = false) => {
+    const { data: remoteMeta } = await axios.get('https://zm-shorts.oss-cn-hangzhou.aliyuncs.com/packages/freeshort/meta.json', {
+        withCredentials: false
+    })
+    console.log('remoteMeta', remoteMeta)
+    if (remoteMeta.version > meta.version) {
+        const version = await CapacitorUpdater.download({
+            url: remoteMeta.url,
+            version: remoteMeta.version + ''
+        })
+        console.log('version', version)
+        CapacitorUpdater.set(version)
+    }
+}
+
+export { checkUpdate }

+ 1 - 0
src/type.d.ts

@@ -1,3 +1,4 @@
 declare interface Window {
     swiper: any;
+    meta: any;
 }

+ 7 - 7
src/views/LoginView.vue

@@ -183,31 +183,31 @@ async function login() {
             router.replace("/");
         }
     } catch (error: any) {
-        presentToast(error.errors[0]?.message, { type: "error" });
+        toast(error.errors[0]?.message, { type: "error" });
     }
     loginForm.loading = false;
 }
 async function register() {
     if (!registerForm.email) {
-        presentToast("Email is required", { type: "error" });
+        toast("Email is required", { type: "error" });
         return;
     }
     if (!isEmail(registerForm.email)) {
-        presentToast("Invalid email", { type: "error" });
+        toast("Invalid email", { type: "error" });
         return;
     }
     if (!registerForm.password) {
-        presentToast("Password is required", { type: "error" });
+        toast("Password is required", { type: "error" });
         return;
     }
     if (registerForm.password.length < 6) {
-        presentToast("Password must be at least 6 characters", {
+        toast("Password must be at least 6 characters", {
             type: "error",
         });
         return;
     }
     if (registerForm.password !== registerForm.confirmPassword) {
-        presentToast("Passwords do not match", { type: "error" });
+        toast("Passwords do not match", { type: "error" });
         return;
     }
     try {
@@ -225,7 +225,7 @@ async function register() {
             router.replace("/");
         }
     } catch (error: any) {
-        presentToast(error.errors[0]?.message, { type: "error" });
+        toast(error.errors[0]?.message, { type: "error" });
     }
     registerForm.loading = false;
 }

+ 3 - 54
src/views/MeTab.vue

@@ -90,34 +90,7 @@
                     </div>
                 </div>
             </div>
-            <ion-modal
-                id="invite-modal"
-                :isOpen="showInviteModal"
-                @didDismiss="showInviteModal = false"
-            >
-                <div class="content-wrapper text-base font-bold">
-                    <div
-                        class="code-wrapper flex flex-col items-center justify-center"
-                    >
-                        <div class="font-bold">INVITE 3 FRIENDS</div>
-                        <div class="">GET 7 DAYS FREE WATCHING</div>
-                        <img class="mt-2" :src="qrcode" alt="QR Code" />
-                        <div class="mt-2 font-bold">INVITED: 0</div>
-                    </div>
-                    <div class="flex mt-4 text-center text-sm">
-                        <div
-                            class="flex-grow border-2 border-white rounded-full box-border h-10 flex items-center justify-center"
-                        >
-                            Save QR Code
-                        </div>
-                        <div
-                            class="ml-6 flex-grow bg-prim rounded-full h-10 flex items-center justify-center"
-                        >
-                            Share
-                        </div>
-                    </div>
-                </div>
-            </ion-modal>
+            <ShareModal v-model="showInviteModal" />
         </ion-content>
     </ion-page>
 </template>
@@ -146,9 +119,9 @@ import { useUserStore } from "@/store/user";
 import http from "@/plugins/http";
 import bgInviteCell from "@/assets/bg_invite_cell.png";
 import bgInviteModal from "@/assets/bg_invite_modal.png";
-import { useQRCode } from "@vueuse/integrations/useQRCode";
 import SeriesItem from "@/components/SeriesItem.vue";
 import IconAvatar from "@/assets/icon_avatar.png";
+import ShareModal from "@/components/ShareModal.vue";
 
 const router = useIonRouter();
 const { user } = storeToRefs(useUserStore());
@@ -163,10 +136,6 @@ onIonViewDidEnter(() => {
 });
 
 const showInviteModal = ref(false);
-const qrcode = useQRCode("text-to-encode", {
-    margin: 2,
-    width: 500,
-});
 </script>
 <style lang="less" scoped>
 .top {
@@ -177,27 +146,7 @@ const qrcode = useQRCode("text-to-encode", {
         rgba(51, 5, 14, 0) 100%
     );
 }
-#invite-modal {
-    --width: fit-content;
-    --min-width: 290px;
-    --height: fit-content;
-    --border-radius: 0;
-    --background: transparent;
-    .content-wrapper {
-        .code-wrapper {
-            width: 290px;
-            height: 350px;
-            background-image: url(@/assets/bg_invite_modal.png);
-            background-size: cover;
-            background-position: center;
-            img {
-                width: 215px;
-                height: 215px;
-                border-radius: 8px;
-            }
-        }
-    }
-}
+
 ion-item {
     --min-height: 54px;
 }

+ 8 - 3
src/views/SeriesView.vue

@@ -39,6 +39,7 @@
                             @choose-episode="onChooseEpisode"
                             @ended="next"
                             @pay="showPayModal = true"
+                            @share="showShareModal = true"
                         />
                     </swiper-slide>
                 </VueSwiper>
@@ -134,6 +135,7 @@
                     ></iframe>
                 </IonContent>
             </IonModal>
+            <ShareModal v-model="showShareModal" />
         </ion-content>
     </ion-page>
 </template>
@@ -171,6 +173,7 @@ import toast from "@/plugins/toast";
 import { useUserStore } from "@/store/user";
 import { storeToRefs } from "pinia";
 import emitter from "@/events";
+import ShareModal from "@/components/ShareModal.vue";
 
 const { user } = storeToRefs(useUserStore());
 const el = ref<HTMLElement | null>(null);
@@ -275,7 +278,7 @@ window.addEventListener("message", async (event) => {
             type: "success",
         });
         showCheckoutModal.value = false;
-        emitter.emit('payment-success')
+        emitter.emit("payment-success");
     } else if (event.data === "fail") {
         toast("Payment failed", {
             type: "error",
@@ -284,14 +287,16 @@ window.addEventListener("message", async (event) => {
     }
 });
 
-const payUrl = ref("http://192.168.50.202:5174/stripe-checkout/");
+const payUrl = ref(http.resolve("/stripe-checkout/"));
 function onClickPay() {
     showPayModal.value = false;
     setTimeout(() => {
-        payUrl.value = "http://192.168.50.202:5174/stripe-checkout/";
+        payUrl.value = http.resolve("/stripe-checkout/");
         showCheckoutModal.value = true;
     }, 200);
 }
+
+const showShareModal = ref(false);
 </script>
 <style lang="less" scoped>
 .pay-modal {

+ 16 - 11
vite.config.ts

@@ -1,18 +1,23 @@
 import legacy from "@vitejs/plugin-legacy";
 import vue from "@vitejs/plugin-vue";
 import path from "path";
-import { defineConfig } from "vite";
+import { defineConfig, loadEnv } from "vite";
+import VitePluginUploadPackage from "./VitePluginUploadPackage";
 
 // https://vitejs.dev/config/
-export default defineConfig({
-    plugins: [vue(), legacy()],
-    resolve: {
-        alias: {
-            "@": path.resolve(__dirname, "./src"),
+export default defineConfig(({ command, mode }) => {
+    process.env = { ...process.env, ...loadEnv(mode, process.cwd()) };
+    return {
+        base: process.env.VITE_BASE_URL,
+        plugins: [vue(), legacy(), VitePluginUploadPackage()],
+        resolve: {
+            alias: {
+                "@": path.resolve(__dirname, "./src"),
+            },
         },
-    },
-    server: {
-        host: "0.0.0.0",
-        port: 4173
-    },
+        server: {
+            host: "0.0.0.0",
+            port: 4173,
+        },
+    };
 });

File diff suppressed because it is too large
+ 503 - 12
yarn.lock


Some files were not shown because too many files changed in this diff