| @@ -1,22 +1,3 @@ | |||||
| <script setup lang="ts"> | |||||
| import { useI18n } from "vue-i18n"; | |||||
| import SvgIcon from "@/components/SvgIcon/index.vue"; | |||||
| import { useAppStore } from "@/store/modules/app"; | |||||
| const appStore = useAppStore(); | |||||
| const { locale } = useI18n(); | |||||
| function handleLanguageChange(lang: string) { | |||||
| locale.value = lang; | |||||
| appStore.changeLanguage(lang); | |||||
| if (lang == "en") { | |||||
| ElMessage.success("Switch Language Successful!"); | |||||
| } else { | |||||
| ElMessage.success("切换语言成功!"); | |||||
| } | |||||
| } | |||||
| </script> | |||||
| <template> | <template> | ||||
| <el-dropdown class="outSide" trigger="click" @command="handleLanguageChange"> | <el-dropdown class="outSide" trigger="click" @command="handleLanguageChange"> | ||||
| <div> | <div> | ||||
| @@ -38,6 +19,25 @@ function handleLanguageChange(lang: string) { | |||||
| </el-dropdown> | </el-dropdown> | ||||
| </template> | </template> | ||||
| <script setup lang="ts"> | |||||
| import { useI18n } from "vue-i18n"; | |||||
| import SvgIcon from "@/components/SvgIcon/index.vue"; | |||||
| import { useAppStore } from "@/store/modules/app"; | |||||
| const appStore = useAppStore(); | |||||
| const { locale } = useI18n(); | |||||
| function handleLanguageChange(lang: string) { | |||||
| locale.value = lang; | |||||
| appStore.changeLanguage(lang); | |||||
| if (lang == "en") { | |||||
| ElMessage.success("Switch Language Successful!"); | |||||
| } else { | |||||
| ElMessage.success("切换语言成功!"); | |||||
| } | |||||
| } | |||||
| </script> | |||||
| <style lang="scss" scoped> | <style lang="scss" scoped> | ||||
| .outSide { | .outSide { | ||||
| cursor: pointer; | cursor: pointer; | ||||
| @@ -7,11 +7,13 @@ export default { | |||||
| // 登录页面国际化 | // 登录页面国际化 | ||||
| login: { | login: { | ||||
| title: "Metavatar-PC", | |||||
| title: "Metavatar-PC Sign in", | |||||
| username: "Username", | username: "Username", | ||||
| password: "Password", | password: "Password", | ||||
| login: "Login", | |||||
| login: "Sign in", | |||||
| verifyCode: "Verify Code", | verifyCode: "Verify Code", | ||||
| signUp: "Don't have an account? Sign up here", | |||||
| forgetPwd: "I forgot my password", | |||||
| }, | }, | ||||
| // 导航栏国际化 | // 导航栏国际化 | ||||
| @@ -51,6 +53,7 @@ export default { | |||||
| account: { | account: { | ||||
| title: "My Account", | title: "My Account", | ||||
| reSetPwd: "Reset Password", | reSetPwd: "Reset Password", | ||||
| until: "until", | |||||
| getMore: "UPGRADE", | getMore: "UPGRADE", | ||||
| copyCode: "Copy invitation code", | copyCode: "Copy invitation code", | ||||
| saveCode: "Save QR code", | saveCode: "Save QR code", | ||||
| @@ -67,5 +70,13 @@ export default { | |||||
| // 商店 | // 商店 | ||||
| shop: { | shop: { | ||||
| title: "Shop", | title: "Shop", | ||||
| Trial: "Trial", | |||||
| Lite: "Lite", | |||||
| Pro: "Pro", | |||||
| Adv: "Advanced", | |||||
| Ent: "Enterprise", | |||||
| selectPlan: "SELECT PLAN", | |||||
| WeChatPay: "WeChatPay", | |||||
| Alipay: "Alipay", | |||||
| }, | }, | ||||
| }; | }; | ||||
| @@ -7,11 +7,13 @@ export default { | |||||
| // 登录页面国际化 | // 登录页面国际化 | ||||
| login: { | login: { | ||||
| title: "Metavatar-PC", | |||||
| title: "Metavatar-PC 登录", | |||||
| username: "用户名", | username: "用户名", | ||||
| password: "密码", | password: "密码", | ||||
| login: "登 录", | login: "登 录", | ||||
| verifyCode: "验证码", | verifyCode: "验证码", | ||||
| signUp: "没有账号?现在加入!", | |||||
| forgetPwd: "忘记密码", | |||||
| }, | }, | ||||
| // 导航栏国际化 | // 导航栏国际化 | ||||
| @@ -51,6 +53,7 @@ export default { | |||||
| account: { | account: { | ||||
| title: "个人账户", | title: "个人账户", | ||||
| reSetPwd: "修改密码", | reSetPwd: "修改密码", | ||||
| until: "有效期至", | |||||
| getMore: "升级套餐", | getMore: "升级套餐", | ||||
| copyCode: "复制邀请码", | copyCode: "复制邀请码", | ||||
| saveCode: "保存二维码", | saveCode: "保存二维码", | ||||
| @@ -67,5 +70,13 @@ export default { | |||||
| // 商店 | // 商店 | ||||
| shop: { | shop: { | ||||
| title: "商店", | title: "商店", | ||||
| Trial: "尝鲜版", | |||||
| Lite: "基础版", | |||||
| Pro: "专业版", | |||||
| Adv: "加强版", | |||||
| Ent: "企业版", | |||||
| selectPlan: "方案选择", | |||||
| WeChatPay: "微信支付", | |||||
| Alipay: "支付宝支付", | |||||
| }, | }, | ||||
| }; | }; | ||||
| @@ -79,6 +79,11 @@ import { RouteLocationRaw, useRoute, useRouter } from "vue-router"; | |||||
| import { useAppStore } from "@/store/modules/app"; | import { useAppStore } from "@/store/modules/app"; | ||||
| import { useTagsViewStore } from "@/store/modules/tagsView"; | import { useTagsViewStore } from "@/store/modules/tagsView"; | ||||
| import { useUserStore } from "@/store/modules/user"; | import { useUserStore } from "@/store/modules/user"; | ||||
| import { useI18n } from "vue-i18n"; | |||||
| const { locale } = useI18n(); | |||||
| // 当前语言状态与国际化组件 | |||||
| const lanChange = ref(locale); | |||||
| import LangSelect from "@/components/LangSelect/index.vue"; | import LangSelect from "@/components/LangSelect/index.vue"; | ||||
| const appStore = useAppStore(); | const appStore = useAppStore(); | ||||
| @@ -106,10 +111,16 @@ const { isFullscreen, toggle } = useFullscreen(); | |||||
| * 注销 | * 注销 | ||||
| */ | */ | ||||
| function logout() { | function logout() { | ||||
| ElMessageBox.confirm("确定注销并退出系统吗?", "提示", { | |||||
| confirmButtonText: "确定", | |||||
| cancelButtonText: "取消", | |||||
| type: "warning", | |||||
| const msg = | |||||
| (lanChange.value as string) == "zh-cn" | |||||
| ? "确定退出登录吗?" | |||||
| : "Are you sure to log out?"; | |||||
| const notice = (lanChange.value as string) == "zh-cn" ? "提示" : "Notice"; | |||||
| const confirm = (lanChange.value as string) == "zh-cn" ? "确定" : "Confirm"; | |||||
| const cancel = (lanChange.value as string) == "zh-cn" ? "取消" : "Cancel"; | |||||
| ElMessageBox.confirm(msg, notice, { | |||||
| confirmButtonText: confirm, | |||||
| cancelButtonText: cancel, | |||||
| }).then(() => { | }).then(() => { | ||||
| userStore | userStore | ||||
| .logout() | .logout() | ||||
| @@ -186,10 +197,9 @@ watch( | |||||
| height: 80px; | height: 80px; | ||||
| padding: 0 20px; | padding: 0 20px; | ||||
| color: #fff; | color: #fff; | ||||
| background-color: #fff; | |||||
| background-color: #000; | background-color: #000; | ||||
| box-shadow: 0 0 1px #0003; | box-shadow: 0 0 1px #0003; | ||||
| padding-right: 50px; | |||||
| .avatar { | .avatar { | ||||
| width: 30px; | width: 30px; | ||||
| height: 30px; | height: 30px; | ||||
| @@ -1,3 +1,60 @@ | |||||
| <template> | |||||
| <div v-if="false" class="tags-container"> | |||||
| <scroll-pane ref="scrollPaneRef" @scroll="handleScroll"> | |||||
| <router-link | |||||
| :class="'tags-item ' + (isActive(tag) ? 'active' : '')" | |||||
| v-for="tag in visitedViews" | |||||
| :key="tag.path" | |||||
| :data-path="tag.path" | |||||
| :to="{ path: tag.path, query: tag.query }" | |||||
| @click.middle="!isAffix(tag) ? closeSelectedTag(tag) : ''" | |||||
| @contextmenu.prevent="openTagMenu(tag, $event)" | |||||
| > | |||||
| {{ translateRouteTitleI18n(tag.meta?.title) }} | |||||
| <span | |||||
| v-if="!isAffix(tag)" | |||||
| class="tags-item-close" | |||||
| @click.prevent.stop="closeSelectedTag(tag)" | |||||
| > | |||||
| <i-ep-close class="text-[10px]" /> | |||||
| </span> | |||||
| </router-link> | |||||
| </scroll-pane> | |||||
| <!-- tag标签操作菜单 --> | |||||
| <ul | |||||
| v-show="tagMenuVisible" | |||||
| class="tag-menu" | |||||
| :style="{ left: left + 'px', top: top + 'px' }" | |||||
| > | |||||
| <li @click="refreshSelectedTag(selectedTag)"> | |||||
| <svg-icon icon-class="refresh" /> | |||||
| 刷新 | |||||
| </li> | |||||
| <li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)"> | |||||
| <svg-icon icon-class="close" /> | |||||
| 关闭 | |||||
| </li> | |||||
| <li @click="closeOtherTags"> | |||||
| <svg-icon icon-class="close_other" /> | |||||
| 关闭其它 | |||||
| </li> | |||||
| <li v-if="!isFirstView()" @click="closeLeftTags"> | |||||
| <svg-icon icon-class="close_left" /> | |||||
| 关闭左侧 | |||||
| </li> | |||||
| <li v-if="!isLastView()" @click="closeRightTags"> | |||||
| <svg-icon icon-class="close_right" /> | |||||
| 关闭右侧 | |||||
| </li> | |||||
| <li @click="closeAllTags(selectedTag)"> | |||||
| <svg-icon icon-class="close_all" /> | |||||
| 关闭所有 | |||||
| </li> | |||||
| </ul> | |||||
| </div> | |||||
| </template> | |||||
| <script setup lang="ts"> | <script setup lang="ts"> | ||||
| import { | import { | ||||
| getCurrentInstance, | getCurrentInstance, | ||||
| @@ -241,63 +298,6 @@ onMounted(() => { | |||||
| }); | }); | ||||
| </script> | </script> | ||||
| <template> | |||||
| <div v-if="false" class="tags-container"> | |||||
| <scroll-pane ref="scrollPaneRef" @scroll="handleScroll"> | |||||
| <router-link | |||||
| :class="'tags-item ' + (isActive(tag) ? 'active' : '')" | |||||
| v-for="tag in visitedViews" | |||||
| :key="tag.path" | |||||
| :data-path="tag.path" | |||||
| :to="{ path: tag.path, query: tag.query }" | |||||
| @click.middle="!isAffix(tag) ? closeSelectedTag(tag) : ''" | |||||
| @contextmenu.prevent="openTagMenu(tag, $event)" | |||||
| > | |||||
| {{ translateRouteTitleI18n(tag.meta?.title) }} | |||||
| <span | |||||
| v-if="!isAffix(tag)" | |||||
| class="tags-item-close" | |||||
| @click.prevent.stop="closeSelectedTag(tag)" | |||||
| > | |||||
| <i-ep-close class="text-[10px]" /> | |||||
| </span> | |||||
| </router-link> | |||||
| </scroll-pane> | |||||
| <!-- tag标签操作菜单 --> | |||||
| <ul | |||||
| v-show="tagMenuVisible" | |||||
| class="tag-menu" | |||||
| :style="{ left: left + 'px', top: top + 'px' }" | |||||
| > | |||||
| <li @click="refreshSelectedTag(selectedTag)"> | |||||
| <svg-icon icon-class="refresh" /> | |||||
| 刷新 | |||||
| </li> | |||||
| <li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)"> | |||||
| <svg-icon icon-class="close" /> | |||||
| 关闭 | |||||
| </li> | |||||
| <li @click="closeOtherTags"> | |||||
| <svg-icon icon-class="close_other" /> | |||||
| 关闭其它 | |||||
| </li> | |||||
| <li v-if="!isFirstView()" @click="closeLeftTags"> | |||||
| <svg-icon icon-class="close_left" /> | |||||
| 关闭左侧 | |||||
| </li> | |||||
| <li v-if="!isLastView()" @click="closeRightTags"> | |||||
| <svg-icon icon-class="close_right" /> | |||||
| 关闭右侧 | |||||
| </li> | |||||
| <li @click="closeAllTags(selectedTag)"> | |||||
| <svg-icon icon-class="close_all" /> | |||||
| 关闭所有 | |||||
| </li> | |||||
| </ul> | |||||
| </div> | |||||
| </template> | |||||
| <style lang="scss" scoped> | <style lang="scss" scoped> | ||||
| .tags-container { | .tags-container { | ||||
| width: 100%; | width: 100%; | ||||
| @@ -2,6 +2,7 @@ | |||||
| export {} | export {} | ||||
| declare global { | declare global { | ||||
| const EffectScope: typeof import('vue')['EffectScope'] | const EffectScope: typeof import('vue')['EffectScope'] | ||||
| const ElForm: typeof import('element-plus/es')['ElForm'] | |||||
| const ElMessage: typeof import('element-plus/es')['ElMessage'] | const ElMessage: typeof import('element-plus/es')['ElMessage'] | ||||
| const ElMessageBox: typeof import('element-plus/es')['ElMessageBox'] | const ElMessageBox: typeof import('element-plus/es')['ElMessageBox'] | ||||
| const asyncComputed: typeof import('@vueuse/core')['asyncComputed'] | const asyncComputed: typeof import('@vueuse/core')['asyncComputed'] | ||||
| @@ -270,6 +271,7 @@ import { UnwrapRef } from 'vue' | |||||
| declare module 'vue' { | declare module 'vue' { | ||||
| interface ComponentCustomProperties { | interface ComponentCustomProperties { | ||||
| readonly EffectScope: UnwrapRef<typeof import('vue')['EffectScope']> | readonly EffectScope: UnwrapRef<typeof import('vue')['EffectScope']> | ||||
| readonly ElForm: UnwrapRef<typeof import('element-plus/es')['ElForm']> | |||||
| readonly ElMessage: UnwrapRef<typeof import('element-plus/es')['ElMessage']> | readonly ElMessage: UnwrapRef<typeof import('element-plus/es')['ElMessage']> | ||||
| readonly ElMessageBox: UnwrapRef<typeof import('element-plus/es')['ElMessageBox']> | readonly ElMessageBox: UnwrapRef<typeof import('element-plus/es')['ElMessageBox']> | ||||
| readonly asyncComputed: UnwrapRef<typeof import('@vueuse/core')['asyncComputed']> | readonly asyncComputed: UnwrapRef<typeof import('@vueuse/core')['asyncComputed']> | ||||
| @@ -9,10 +9,9 @@ | |||||
| ></video> | ></video> | ||||
| </div> | </div> | ||||
| <el-form | <el-form | ||||
| v-if="true" | |||||
| v-if="isLogin" | |||||
| ref="loginFormRef" | ref="loginFormRef" | ||||
| :model="loginData" | :model="loginData" | ||||
| :rules="loginRules" | |||||
| class="login-form" | class="login-form" | ||||
| > | > | ||||
| <div class="flex text-white items-center py-4"> | <div class="flex text-white items-center py-4"> | ||||
| @@ -84,15 +83,108 @@ | |||||
| size="default" | size="default" | ||||
| :loading="loading" | :loading="loading" | ||||
| type="primary" | type="primary" | ||||
| class="w-full" | |||||
| class="loginBtn" | |||||
| @click.prevent="handleLogin" | @click.prevent="handleLogin" | ||||
| >{{ $t("login.login") }} | >{{ $t("login.login") }} | ||||
| </el-button> | </el-button> | ||||
| <!-- 账号密码提示 --> | |||||
| <div class="mt-4 text-white text-sm"> | |||||
| <span>{{ $t("login.username") }}: admin</span> | |||||
| <span class="ml-4"> {{ $t("login.password") }}: 123456</span> | |||||
| <div :class="currentLan == 'zh-cn' ? 'bottomBtnCN' : 'bottomBtnEN'"> | |||||
| <div style="margin-bottom: 5px"> | |||||
| <span class="join">{{ $t("login.signUp") }}</span> | |||||
| </div> | |||||
| <div> | |||||
| <span class="join">{{ $t("login.forgetPwd") }}</span> | |||||
| </div> | |||||
| </div> | |||||
| </el-form> | |||||
| <el-form | |||||
| v-if="!isLogin" | |||||
| ref="loginFormRef" | |||||
| :model="loginData" | |||||
| class="login-form" | |||||
| > | |||||
| <div class="flex text-white items-center py-4"> | |||||
| <span class="text-2xl flex-1 text-center">{{ $t("login.title") }}</span> | |||||
| <lang-select style="color: #fff" /> | |||||
| </div> | |||||
| <el-form-item prop="username"> | |||||
| <div class="p-2 text-white"> | |||||
| <svg-icon icon-class="user" /> | |||||
| </div> | |||||
| <el-input | |||||
| class="flex-1" | |||||
| ref="username" | |||||
| size="large" | |||||
| v-model="loginData.username" | |||||
| :placeholder="$t('login.username')" | |||||
| name="username" | |||||
| /> | |||||
| </el-form-item> | |||||
| <el-tooltip | |||||
| :disabled="isCapslock === false" | |||||
| content="Caps lock is On" | |||||
| placement="right" | |||||
| > | |||||
| <el-form-item prop="password"> | |||||
| <span class="p-2 text-white"> | |||||
| <svg-icon icon-class="password" /> | |||||
| </span> | |||||
| <el-input | |||||
| class="flex-1" | |||||
| v-model="loginData.password" | |||||
| placeholder="密码" | |||||
| :type="passwordVisible === false ? 'password' : 'input'" | |||||
| size="large" | |||||
| name="password" | |||||
| @keyup="checkCapslock" | |||||
| @keyup.enter="handleLogin" | |||||
| /> | |||||
| <span class="mr-2" @click="passwordVisible = !passwordVisible"> | |||||
| <svg-icon | |||||
| :icon-class="passwordVisible === false ? 'eye' : 'eye-open'" | |||||
| class="text-white cursor-pointer" | |||||
| /> | |||||
| </span> | |||||
| </el-form-item> | |||||
| </el-tooltip> | |||||
| <!-- 验证码 --> | |||||
| <el-form-item prop="verifyCode"> | |||||
| <span class="p-2 text-white"> | |||||
| <svg-icon icon-class="verify_code" /> | |||||
| </span> | |||||
| <el-input | |||||
| v-model="loginData.verifyCode" | |||||
| auto-complete="off" | |||||
| :placeholder="$t('login.verifyCode')" | |||||
| class="w-[60%]" | |||||
| @keyup.enter="handleLogin" | |||||
| /> | |||||
| <div class="captcha"> | |||||
| <img :src="captchaBase64" @click="getCaptcha" /> | |||||
| </div> | |||||
| </el-form-item> | |||||
| <el-button | |||||
| size="default" | |||||
| :loading="loading" | |||||
| type="primary" | |||||
| class="loginBtn" | |||||
| @click.prevent="handleLogin" | |||||
| >{{ $t("login.login") }} | |||||
| </el-button> | |||||
| <div :class="currentLan == 'zh-cn' ? 'bottomBtnCN' : 'bottomBtnEN'"> | |||||
| <div style="margin-bottom: 5px" @click="loginFlag"> | |||||
| <span class="join">{{ $t("login.signUp") }}</span> | |||||
| </div> | |||||
| <div> | |||||
| <span class="join">{{ $t("login.forgetPwd") }}</span> | |||||
| </div> | |||||
| </div> | </div> | ||||
| </el-form> | </el-form> | ||||
| </div> | </div> | ||||
| @@ -111,6 +203,11 @@ import { LocationQuery, LocationQueryValue, useRoute } from "vue-router"; | |||||
| import { getCaptchaApi } from "@/api/auth"; | import { getCaptchaApi } from "@/api/auth"; | ||||
| import { LoginData } from "@/api/auth/types"; | import { LoginData } from "@/api/auth/types"; | ||||
| import { useI18n } from "vue-i18n"; | |||||
| const { locale } = useI18n(); | |||||
| const currentLan = ref(locale); | |||||
| const userStore = useUserStore(); | const userStore = useUserStore(); | ||||
| const route = useRoute(); | const route = useRoute(); | ||||
| @@ -118,19 +215,27 @@ const route = useRoute(); | |||||
| * 按钮loading | * 按钮loading | ||||
| */ | */ | ||||
| const loading = ref(false); | const loading = ref(false); | ||||
| /** | /** | ||||
| * 是否大写锁定 | * 是否大写锁定 | ||||
| */ | */ | ||||
| const isCapslock = ref(false); | const isCapslock = ref(false); | ||||
| /** | /** | ||||
| * 密码是否可见 | * 密码是否可见 | ||||
| */ | */ | ||||
| const passwordVisible = ref(false); | const passwordVisible = ref(false); | ||||
| /** | /** | ||||
| * 验证码图片Base64字符串 | * 验证码图片Base64字符串 | ||||
| */ | */ | ||||
| const captchaBase64 = ref(); | const captchaBase64 = ref(); | ||||
| /** | |||||
| * 登录/注册 | |||||
| */ | |||||
| const isLogin = ref(true); | |||||
| /** | /** | ||||
| * 登录表单引用 | * 登录表单引用 | ||||
| */ | */ | ||||
| @@ -147,6 +252,14 @@ const loginRules = { | |||||
| verifyCode: [{ required: true, trigger: "blur" }], | verifyCode: [{ required: true, trigger: "blur" }], | ||||
| }; | }; | ||||
| /** | |||||
| * @description: 切换登录/注册状态 | |||||
| */ | |||||
| function loginFlag() { | |||||
| isLogin.value = !isLogin; | |||||
| console.log(isLogin.value, "isLogin.value"); | |||||
| } | |||||
| /** | /** | ||||
| * 密码校验器 | * 密码校验器 | ||||
| */ | */ | ||||
| @@ -235,13 +348,15 @@ onMounted(() => { | |||||
| max-width: 100%; | max-width: 100%; | ||||
| padding: 20px; | padding: 20px; | ||||
| overflow: hidden; | overflow: hidden; | ||||
| backdrop-filter: blur(5px); | |||||
| background: linear-gradient( | background: linear-gradient( | ||||
| 225deg, | |||||
| rgb(81 217 202 / 100%), | |||||
| rgb(114 100 245 / 100%) | |||||
| 123.64deg, | |||||
| rgba(188, 193, 196, 0.1) -22.71%, | |||||
| rgba(255, 255, 255, 0.039) 70.04% | |||||
| ); | ); | ||||
| border-radius: 20px; | border-radius: 20px; | ||||
| transform: translateY(-50%); | transform: translateY(-50%); | ||||
| border: 1px solid #cacaca; | |||||
| .captcha { | .captcha { | ||||
| position: absolute; | position: absolute; | ||||
| @@ -257,6 +372,54 @@ onMounted(() => { | |||||
| } | } | ||||
| } | } | ||||
| .loginBtn { | |||||
| width: 100%; | |||||
| height: 40px; | |||||
| background: linear-gradient(270deg, #4b61dc, #15d1b8); | |||||
| transition: all 0.3s; | |||||
| &:hover { | |||||
| transform: scale(1.02); | |||||
| } | |||||
| } | |||||
| .bottomBtnCN { | |||||
| display: flex; | |||||
| justify-content: space-between; | |||||
| align-items: center; | |||||
| padding: 0 10px; | |||||
| color: #fff; | |||||
| text-align: center; | |||||
| margin-top: 20px; | |||||
| .join { | |||||
| cursor: pointer; | |||||
| border-bottom: 2px solid #ffffff00; | |||||
| padding: 0 3px; | |||||
| padding-bottom: 2px; | |||||
| transition: all 0.3s; | |||||
| &:hover { | |||||
| border-bottom: 2px solid #ffffff; | |||||
| } | |||||
| } | |||||
| } | |||||
| .bottomBtnEN { | |||||
| padding: 0 10px; | |||||
| color: #fff; | |||||
| text-align: center; | |||||
| margin-top: 20px; | |||||
| .join { | |||||
| cursor: pointer; | |||||
| border-bottom: 2px solid #ffffff00; | |||||
| padding: 0 3px; | |||||
| padding-bottom: 2px; | |||||
| transition: all 0.3s; | |||||
| &:hover { | |||||
| border-bottom: 2px solid #ffffff; | |||||
| } | |||||
| } | |||||
| } | |||||
| .videoBox { | .videoBox { | ||||
| position: absolute; | position: absolute; | ||||
| top: 0; | top: 0; | ||||
| @@ -268,13 +431,12 @@ onMounted(() => { | |||||
| .el-form-item { | .el-form-item { | ||||
| background: rgb(0 0 0 / 10%); | background: rgb(0 0 0 / 10%); | ||||
| border: 1px solid rgb(255 255 255 / 10%); | |||||
| border: 1px solid #ffffff2d; | |||||
| border-radius: 5px; | border-radius: 5px; | ||||
| } | } | ||||
| .el-input { | .el-input { | ||||
| background: transparent; | background: transparent; | ||||
| // 子组件 scoped 无效,使用 :deep | // 子组件 scoped 无效,使用 :deep | ||||
| :deep(.el-input__wrapper) { | :deep(.el-input__wrapper) { | ||||
| padding: 0; | padding: 0; | ||||
| @@ -15,20 +15,32 @@ | |||||
| </div> | </div> | ||||
| <!-- 剩余次数 --> | <!-- 剩余次数 --> | ||||
| <div class="left-two border"> | <div class="left-two border"> | ||||
| <div class="number">3 Videos Generation Left</div> | |||||
| <div class="time">Until 2023/12/31</div> | |||||
| <div v-if="currentLan == 'en'" class="number"> | |||||
| 3 Videos Generation Left | |||||
| </div> | |||||
| <div v-if="currentLan == 'zh-cn'" class="number"> | |||||
| 剩余生成视频次数:3条 | |||||
| </div> | |||||
| <div class="time">{{ $t("account.until") }} 2023/12/31</div> | |||||
| <div class="getMore">{{ $t("account.getMore") }}</div> | <div class="getMore">{{ $t("account.getMore") }}</div> | ||||
| </div> | </div> | ||||
| <!-- 邀请码 --> | <!-- 邀请码 --> | ||||
| <div class="left-three border flex justify-between"> | <div class="left-three border flex justify-between"> | ||||
| <div class="codeImg"></div> | <div class="codeImg"></div> | ||||
| <div class="other"> | <div class="other"> | ||||
| <div> | |||||
| Invite friends to get | |||||
| <div v-if="currentLan == 'en'"> | |||||
| <span>Invite friends to get</span> | |||||
| <span class="bigWord">free</span> | <span class="bigWord">free</span> | ||||
| video | |||||
| <span class="bigWord">Generation</span> | |||||
| <span>video</span> | |||||
| <span class="bigWord">Generation!</span> | |||||
| </div> | |||||
| <div v-if="currentLan == 'zh-cn'"> | |||||
| <span>邀请更多好友</span> | |||||
| <span class="bigWord">免费</span> | |||||
| <span>生成视频!</span> | |||||
| </div> | </div> | ||||
| <div class="btns"> | <div class="btns"> | ||||
| <span class="myBtn">{{ $t("account.copyCode") }}</span> | <span class="myBtn">{{ $t("account.copyCode") }}</span> | ||||
| <span class="myBtn">{{ $t("account.saveCode") }}</span> | <span class="myBtn">{{ $t("account.saveCode") }}</span> | ||||
| @@ -76,7 +88,14 @@ | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| </template> | </template> | ||||
| <script setup></script> | |||||
| <script setup> | |||||
| import { useI18n } from "vue-i18n"; | |||||
| const { locale } = useI18n(); | |||||
| const currentLan = ref(locale); | |||||
| </script> | |||||
| <style lang="scss" scoped> | <style lang="scss" scoped> | ||||
| .page { | .page { | ||||
| height: 887px; | height: 887px; | ||||
| @@ -289,5 +308,6 @@ | |||||
| .bigWord { | .bigWord { | ||||
| font-size: 30px; | font-size: 30px; | ||||
| font-weight: 700; | font-weight: 700; | ||||
| margin: 0 10px; | |||||
| } | } | ||||
| </style> | </style> | ||||
| @@ -9,7 +9,7 @@ | |||||
| <div class="content"> | <div class="content"> | ||||
| <div class="title"> | <div class="title"> | ||||
| <el-icon><i-ep-edit /></el-icon> | <el-icon><i-ep-edit /></el-icon> | ||||
| {{ item.title }} | |||||
| {{ $t(item.title) }} | |||||
| </div> | </div> | ||||
| <div class="money"> | <div class="money"> | ||||
| <span class="price">{{ item.price }}元</span>/{{ | <span class="price">{{ item.price }}元</span>/{{ | ||||
| @@ -21,7 +21,7 @@ | |||||
| >分钟/月 | >分钟/月 | ||||
| </div> | </div> | ||||
| <div class="button" :style="`background-color:${item.color} ;`"> | <div class="button" :style="`background-color:${item.color} ;`"> | ||||
| 选择方案 | |||||
| {{ $t("shop.selectPlan") }} | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <!-- 商品权益 --> | <!-- 商品权益 --> | ||||
| @@ -43,7 +43,7 @@ | |||||
| <el-dialog v-model="showPayDialog" width="60%" center> | <el-dialog v-model="showPayDialog" width="60%" center> | ||||
| <div class="payDialog"> | <div class="payDialog"> | ||||
| <div class="left"> | <div class="left"> | ||||
| <div class="title">{{ presentItme.value.title }}</div> | |||||
| <div class="title">{{ $t(presentItme.value.title) }}</div> | |||||
| <div class="price"> | <div class="price"> | ||||
| <span>{{ presentItme.value.price }}</span> | <span>{{ presentItme.value.price }}</span> | ||||
| 元/{{ presentItme.value.priceTime }} | 元/{{ presentItme.value.priceTime }} | ||||
| @@ -57,8 +57,10 @@ | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <div class="right"> | <div class="right"> | ||||
| <div style="background-color: #07c160">微信支付</div> | |||||
| <div style="background-color: #1378fe">支付宝支付</div> | |||||
| <div style="background-color: #07c160"> | |||||
| {{ $t("shop.WeChatPay") }} | |||||
| </div> | |||||
| <div style="background-color: #1378fe">{{ $t("shop.Alipay") }}</div> | |||||
| <div style="background-color: #0070ba">Paypal</div> | <div style="background-color: #0070ba">Paypal</div> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| @@ -70,13 +72,13 @@ const title = ref(""); | |||||
| const list = reactive([ | const list = reactive([ | ||||
| { | { | ||||
| color: "#f3af00", | color: "#f3af00", | ||||
| title: "基础款", | |||||
| title: "shop.Lite", | |||||
| icon: "", | icon: "", | ||||
| price: "0", | price: "0", | ||||
| priceTime: "14天", | priceTime: "14天", | ||||
| time: "5", | time: "5", | ||||
| authority: [ | authority: [ | ||||
| "D-ID 水印", | |||||
| "Metavatar 水印", | |||||
| "高级和标准演示器", | "高级和标准演示器", | ||||
| "15 个 AI 演示提示", | "15 个 AI 演示提示", | ||||
| "AI 脚本世代", | "AI 脚本世代", | ||||
| @@ -84,13 +86,13 @@ const list = reactive([ | |||||
| }, | }, | ||||
| { | { | ||||
| color: "#c971ff", | color: "#c971ff", | ||||
| title: "升级款", | |||||
| title: "shop.Pro", | |||||
| icon: "", | icon: "", | ||||
| price: "10", | price: "10", | ||||
| priceTime: "30天", | priceTime: "30天", | ||||
| time: "10", | time: "10", | ||||
| authority: [ | authority: [ | ||||
| "D-ID 水印", | |||||
| "Metavatar 水印", | |||||
| "高级和标准演示器", | "高级和标准演示器", | ||||
| "15 个 AI 演示提示", | "15 个 AI 演示提示", | ||||
| "AI 脚本世代", | "AI 脚本世代", | ||||
| @@ -99,13 +101,13 @@ const list = reactive([ | |||||
| }, | }, | ||||
| { | { | ||||
| color: "#7b61ff", | color: "#7b61ff", | ||||
| title: "豪华款", | |||||
| title: "shop.Adv", | |||||
| icon: "", | icon: "", | ||||
| price: "20", | price: "20", | ||||
| priceTime: "30天", | priceTime: "30天", | ||||
| time: "15", | time: "15", | ||||
| authority: [ | authority: [ | ||||
| "D-ID 水印", | |||||
| "Metavatar 水印", | |||||
| "高级和标准演示器", | "高级和标准演示器", | ||||
| "15 个 AI 演示提示", | "15 个 AI 演示提示", | ||||
| "AI 脚本世代", | "AI 脚本世代", | ||||
| @@ -115,13 +117,13 @@ const list = reactive([ | |||||
| }, | }, | ||||
| { | { | ||||
| color: "#000", | color: "#000", | ||||
| title: "探索款", | |||||
| title: "shop.Ent", | |||||
| icon: "", | icon: "", | ||||
| price: "50", | price: "50", | ||||
| priceTime: "30天", | priceTime: "30天", | ||||
| time: "40", | time: "40", | ||||
| authority: [ | authority: [ | ||||
| "D-ID 水印", | |||||
| "Metavatar 水印", | |||||
| "高级和标准演示器", | "高级和标准演示器", | ||||
| "15 个 AI 演示提示", | "15 个 AI 演示提示", | ||||
| "AI 脚本世代", | "AI 脚本世代", | ||||