| @@ -5,6 +5,8 @@ NODE_ENV='development' | |||
| VITE_APP_TITLE = 'Metavatar-PC' | |||
| VITE_APP_PORT = 3000 | |||
| ## VITE_APP_BASE_API = 'https://photo.metavatar.cc/C' | |||
| VITE_APP_BASE_API = 'https://test.metavatar.cc/C' | |||
| ## VITE_APP_BASE_API = 'https://photo.metavatar.cc/C' alitest 123456 | |||
| VITE_APP_BASE_API = 'https://mtest.metavatar.cc/A' | |||
| @@ -1,4 +1,4 @@ | |||
| <!-- 照片说话 慧影 --> | |||
| <!-- 邃芒A端--> | |||
| git commit -m "feat: " | |||
| git commit --no-verify -m "提交时的注释" 跳过检验 | |||
| git merge origin/dev_ | |||
| @@ -5,7 +5,7 @@ | |||
| <meta charset="UTF-8" /> | |||
| <link rel="icon" href="/favicon.ico" /> | |||
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |||
| <title>Metavatar-慧影</title> | |||
| <title>Metavatar-邃芒管理端</title> | |||
| </head> | |||
| <body> | |||
| @@ -24,6 +24,7 @@ | |||
| "echarts": "^5.2.2", | |||
| "element-plus": "^2.3.1", | |||
| "js-audio-recorder": "^1.0.7", | |||
| "js-cookie": "^3.0.5", | |||
| "nprogress": "^0.2.0", | |||
| "path-browserify": "^1.0.1", | |||
| "path-to-regexp": "^6.2.0", | |||
| @@ -0,0 +1,13 @@ | |||
| import request from "@/utils/request.js"; | |||
| /** | |||
| * @description:全查询导航菜单 | |||
| * @param | |||
| * @return: | |||
| */ | |||
| export function getMenuNavApi() { | |||
| return request({ | |||
| url: `/menu/nav`, | |||
| method: 'get', | |||
| }) | |||
| } | |||
| @@ -2,29 +2,16 @@ import request from "@/utils/request.js"; | |||
| const baseURL = import.meta.env.VITE_APP_BASE_API | |||
| /** | |||
| * @description 注册 | |||
| * @params email,password | |||
| * @returns data | |||
| */ | |||
| export function register(data) { | |||
| return request({ | |||
| // url: `/api/user/doRegisterByEmail`, | |||
| url: `/api/user/doRegisterByPhone`, | |||
| method: 'post', | |||
| data | |||
| }) | |||
| } | |||
| /** | |||
| * @description 登录 | |||
| * @params email,password,code | |||
| * @returns data | |||
| */ | |||
| export function login(data) { | |||
| export function loginApi(data) { | |||
| return request({ | |||
| // url: `/api/user/loginByEmail`, | |||
| url: `/api/user/login`, | |||
| url: `/doLogin`, | |||
| method: 'post', | |||
| data | |||
| }) | |||
| @@ -175,5 +162,5 @@ export function resetPwdFormApi(data) { | |||
| * @description:获取图形验证码 | |||
| * @return: 验证码地址 | |||
| */ | |||
| export const getCodeImgUrl = baseURL + '/api/user/captcha.jpg' | |||
| export const getCodeImgUrl = baseURL + '/captcha.jpg' | |||
| @@ -70,7 +70,7 @@ export function updUserInfoApi(data) { | |||
| */ | |||
| export function getUserInfoApi() { | |||
| return request({ | |||
| url: `api/user/getUserInfo`, | |||
| url: `getUserInfo`, | |||
| method: 'get', | |||
| }) | |||
| } | |||
| @@ -0,0 +1,13 @@ | |||
| import request from "@/utils/request.js"; | |||
| /** | |||
| * @description 获取用户列表 | |||
| * @param sex ,pageNum,pageSize | |||
| * @returns data | |||
| */ | |||
| export function modeListApi(sex, pageNum, pageSize, videoType) { | |||
| return request({ | |||
| url: `/api/personPatch/list?sex=${sex}&pageNum=${pageNum}&pageSize=${pageSize}&videoType=${videoType}`, | |||
| method: 'get' | |||
| }) | |||
| } | |||
| @@ -15,7 +15,7 @@ export default { | |||
| // 登录页面国际化 | |||
| login: { | |||
| // title: "Metavatar-MetaTalker", | |||
| title: "MetaTalker", | |||
| title: "MetaTalker-Admin", | |||
| username: "Username", | |||
| email: "Phone", | |||
| password: "Password", | |||
| @@ -24,7 +24,7 @@ export default { | |||
| register: "Sign up", | |||
| loginBtn: "Sign in", | |||
| registerBtn: "Sign up", | |||
| verifyCode: "Verify code", | |||
| captcha: "Verify code", | |||
| signIn: "Already got an account? Sign in here", | |||
| signUp: "Don't have an account? Sign up here", | |||
| forgetPwd: "I forgot my password", | |||
| @@ -203,10 +203,6 @@ export default { | |||
| comingSoon: "Coming Soon", | |||
| }, | |||
| apiMangage: { | |||
| title: "API Mangage", | |||
| }, | |||
| signSucceed: { | |||
| title: "Confirm your email", | |||
| succeed: "Sign Succeed !", | |||
| @@ -221,6 +217,26 @@ export default { | |||
| }, | |||
| modelMangage: { | |||
| title: "Model Set", | |||
| title: "Model", | |||
| }, | |||
| businessMangage: { | |||
| title: "Business", | |||
| }, | |||
| keyMangage: { | |||
| title: "Key", | |||
| }, | |||
| priceMangage: { | |||
| title: "Price", | |||
| }, | |||
| dataCount: { | |||
| title: "DataBoard", | |||
| }, | |||
| apiMangage: { | |||
| title: "API", | |||
| }, | |||
| }; | |||
| @@ -14,7 +14,7 @@ export default { | |||
| }, | |||
| // 登录页面国际化 | |||
| login: { | |||
| title: "慧影", | |||
| title: "邃芒管理端", | |||
| username: "用户名", | |||
| email: "手机号", | |||
| password: "密码", | |||
| @@ -23,7 +23,7 @@ export default { | |||
| register: "注册", | |||
| loginBtn: "登 录", | |||
| registerBtn: "注 册", | |||
| verifyCode: "验证码", | |||
| captcha: "验证码", | |||
| // signIn: "已有账号?现在登录!", | |||
| // signUp: "没有账号?现在加入!", | |||
| signIn: "立即登录", | |||
| @@ -203,10 +203,6 @@ export default { | |||
| comingSoon: "敬请期待", | |||
| }, | |||
| apiMangage: { | |||
| title: "API 管理", | |||
| }, | |||
| signSucceed: { | |||
| title: "确认邮箱", | |||
| succeed: "注册成功", | |||
| @@ -222,4 +218,24 @@ export default { | |||
| modelMangage: { | |||
| title: "模板管理", | |||
| }, | |||
| businessMangage: { | |||
| title: "商务管理", | |||
| }, | |||
| keyMangage: { | |||
| title: "密钥管理", | |||
| }, | |||
| priceMangage: { | |||
| title: "价格管理", | |||
| }, | |||
| dataCount: { | |||
| title: "数据统计", | |||
| }, | |||
| apiMangage: { | |||
| title: "API 管理", | |||
| }, | |||
| }; | |||
| @@ -1,119 +0,0 @@ | |||
| <template> | |||
| <div> | |||
| <!-- 侧边栏 --> | |||
| <div><Sidebar class="sidebar-container" /></div> | |||
| <!-- 页面主体 --> | |||
| <div> | |||
| <!-- nav --> | |||
| <div><navbar /></div> | |||
| <!-- 页面主体 --> | |||
| <div><app-main /></div> | |||
| </div> | |||
| </div> | |||
| </template> | |||
| <script setup lang="ts"> | |||
| import { computed, watchEffect } from "vue"; | |||
| import { useWindowSize } from "@vueuse/core"; | |||
| import { AppMain, Navbar } from "./components/index"; | |||
| import SignSucceed from "../views/signSucceed/index.vue"; | |||
| import Sidebar from "./components/Sidebar/index.vue"; | |||
| import { useAppStore } from "@/store/modules/app"; | |||
| import { useSettingsStore } from "@/store/modules/settings"; | |||
| import { useRoute, useRouter } from "vue-router"; | |||
| const route = useRoute(); | |||
| const { params } = route; | |||
| const { width } = useWindowSize(); | |||
| /** | |||
| * 响应式布局容器固定宽度 | |||
| * | |||
| * 大屏(>=1200px) | |||
| * 中屏(>=992px) | |||
| * 小屏(>=768px) | |||
| */ | |||
| const WIDTH = 992; | |||
| const appStore = useAppStore(); | |||
| const settingsStore = useSettingsStore(); | |||
| const fixedHeader = computed(() => settingsStore.fixedHeader); | |||
| const showTagsView = computed(() => settingsStore.tagsView); | |||
| const showSettings = computed(() => settingsStore.showSettings); | |||
| const classObj = computed(() => ({ | |||
| hideSidebar: !appStore.sidebar.opened, | |||
| openSidebar: appStore.sidebar.opened, | |||
| withoutAnimation: appStore.sidebar.withoutAnimation, | |||
| mobile: appStore.device === "mobile", | |||
| })); | |||
| watchEffect(() => { | |||
| if (width.value < WIDTH) { | |||
| appStore.toggleDevice("mobile"); | |||
| appStore.closeSideBar(true); | |||
| } else { | |||
| appStore.toggleDevice("desktop"); | |||
| if (width.value >= 1200) { | |||
| //大屏 | |||
| appStore.openSideBar(true); | |||
| } else { | |||
| appStore.closeSideBar(true); | |||
| } | |||
| } | |||
| }); | |||
| function handleOutsideClick() { | |||
| appStore.closeSideBar(false); | |||
| } | |||
| onMounted(() => {}); | |||
| </script> | |||
| <style lang="scss" scoped> | |||
| .app-wrapper { | |||
| &::after { | |||
| display: table; | |||
| clear: both; | |||
| content: ""; | |||
| } | |||
| position: relative; | |||
| width: 100%; | |||
| height: 100%; | |||
| e &.mobile.openSidebar { | |||
| position: fixed; | |||
| top: 0; | |||
| } | |||
| } | |||
| .fixed-header { | |||
| position: fixed; | |||
| top: 0; | |||
| right: 0; | |||
| z-index: 9; | |||
| width: calc(100% - #{$sideBarWidth}); | |||
| transition: width 0.28s; | |||
| } | |||
| .hideSidebar .fixed-header { | |||
| width: calc(100% - 54px); | |||
| } | |||
| .mobile .fixed-header { | |||
| width: 100%; | |||
| } | |||
| .drawer-bg { | |||
| position: absolute; | |||
| top: 0; | |||
| z-index: 999; | |||
| width: 100%; | |||
| height: 100%; | |||
| // background: #1b213a; | |||
| background: #000; | |||
| opacity: 0.3; | |||
| } | |||
| </style> | |||
| @@ -1,131 +0,0 @@ | |||
| <template> | |||
| <div :class="classObj" class="app-wrapper"> | |||
| <!-- 手机设备侧边栏打开遮罩层 --> | |||
| <div | |||
| v-if="classObj.mobile && classObj.openSidebar" | |||
| class="drawer-bg" | |||
| @click="handleOutsideClick" | |||
| ></div> | |||
| <Sidebar class="sidebar-container" /> | |||
| <div :class="{ hasTagsView: showTagsView }" class="main-container"> | |||
| <div | |||
| :class="{ 'fixed-header': fixedHeader }" | |||
| style="box-shadow: rgba(0, 0, 0, 0.05) 0px 4px 4px; height: 80px" | |||
| > | |||
| <navbar /> | |||
| <tags-view v-if="showTagsView" /> | |||
| </div> | |||
| <!-- 主页面 --> | |||
| <app-main /> | |||
| </div> | |||
| </div> | |||
| </template> | |||
| <script setup lang="ts"> | |||
| import { computed, watchEffect } from "vue"; | |||
| import { useWindowSize } from "@vueuse/core"; | |||
| import { AppMain, Navbar } from "./components/index"; | |||
| import SignSucceed from "../views/signSucceed/index.vue"; | |||
| import Sidebar from "./components/Sidebar/index.vue"; | |||
| import { useAppStore } from "@/store/modules/app"; | |||
| import { useSettingsStore } from "@/store/modules/settings"; | |||
| import { useRoute, useRouter } from "vue-router"; | |||
| const route = useRoute(); | |||
| const { params } = route; | |||
| const { width } = useWindowSize(); | |||
| /** | |||
| * 响应式布局容器固定宽度 | |||
| * | |||
| * 大屏(>=1200px) | |||
| * 中屏(>=992px) | |||
| * 小屏(>=768px) | |||
| */ | |||
| const WIDTH = 992; | |||
| const appStore = useAppStore(); | |||
| const settingsStore = useSettingsStore(); | |||
| const fixedHeader = computed(() => settingsStore.fixedHeader); | |||
| const showTagsView = computed(() => settingsStore.tagsView); | |||
| const showSettings = computed(() => settingsStore.showSettings); | |||
| const classObj = computed(() => ({ | |||
| hideSidebar: !appStore.sidebar.opened, | |||
| openSidebar: appStore.sidebar.opened, | |||
| withoutAnimation: appStore.sidebar.withoutAnimation, | |||
| mobile: appStore.device === "mobile", | |||
| })); | |||
| watchEffect(() => { | |||
| if (width.value < WIDTH) { | |||
| appStore.toggleDevice("mobile"); | |||
| appStore.closeSideBar(true); | |||
| } else { | |||
| appStore.toggleDevice("desktop"); | |||
| if (width.value >= 1200) { | |||
| //大屏 | |||
| appStore.openSideBar(true); | |||
| } else { | |||
| appStore.closeSideBar(true); | |||
| } | |||
| } | |||
| }); | |||
| function handleOutsideClick() { | |||
| appStore.closeSideBar(false); | |||
| } | |||
| onMounted(() => {}); | |||
| </script> | |||
| <style lang="scss" scoped> | |||
| .app-wrapper { | |||
| &::after { | |||
| display: table; | |||
| clear: both; | |||
| content: ""; | |||
| } | |||
| position: relative; | |||
| width: 100%; | |||
| height: 100%; | |||
| e &.mobile.openSidebar { | |||
| position: fixed; | |||
| top: 0; | |||
| } | |||
| } | |||
| .fixed-header { | |||
| position: fixed; | |||
| top: 0; | |||
| right: 0; | |||
| z-index: 9; | |||
| width: calc(100% - #{$sideBarWidth}); | |||
| transition: width 0.28s; | |||
| } | |||
| .hideSidebar .fixed-header { | |||
| width: calc(100% - 54px); | |||
| } | |||
| .mobile .fixed-header { | |||
| width: 100%; | |||
| } | |||
| .drawer-bg { | |||
| position: absolute; | |||
| top: 0; | |||
| z-index: 999; | |||
| width: 100%; | |||
| height: 100%; | |||
| // background: #1b213a; | |||
| background: #000; | |||
| opacity: 0.3; | |||
| } | |||
| </style> | |||
| @@ -11,19 +11,69 @@ | |||
| </div> | |||
| <!-- 侧边路由列表 --> | |||
| <div class="myRouter"> | |||
| <div class="myRouter-item" @click="router.push('/createVideo')"> | |||
| <!-- 动态路由 --> | |||
| <div | |||
| v-for="item in MenuList" | |||
| :key="item.id" | |||
| class="myRouter-item" | |||
| @click="showChildrenRouter = item.name" | |||
| > | |||
| <div class="icon"> | |||
| <el-icon><i-ep-edit /></el-icon> | |||
| <span>{{ item.name }}</span> | |||
| </div> | |||
| <div | |||
| v-show="showChildrenRouter == item.name" | |||
| v-for="childrens in item.children" | |||
| :key="childrens.id" | |||
| class="childrenRouter" | |||
| @click="router.push(`/${childrens.url}`)" | |||
| > | |||
| {{ childrens.name }} | |||
| </div> | |||
| </div> | |||
| <!-- 固定路由 --> | |||
| <div class="myRouter-item" @click="router.push('/model')"> | |||
| <div class="icon"> | |||
| <el-icon><i-ep-edit /></el-icon> | |||
| {{ $t("modelMangage.title") }} | |||
| </div> | |||
| </div> | |||
| <div class="myRouter-item" @click="router.push('/model')"> | |||
| <div class="icon"> | |||
| <el-icon><i-ep-edit /></el-icon> | |||
| {{ $t("businessMangage.title") }} | |||
| </div> | |||
| </div> | |||
| <div class="myRouter-item" @click="router.push('/keyCheck')"> | |||
| <div class="icon"> | |||
| <el-icon><i-ep-edit /></el-icon> | |||
| {{ $t("keyMangage.title") }} | |||
| </div> | |||
| </div> | |||
| <div class="myRouter-item" @click="router.push('/model')"> | |||
| <div class="icon"> | |||
| <el-icon><i-ep-edit /></el-icon> | |||
| {{ $t("priceMangage.title") }} | |||
| </div> | |||
| </div> | |||
| <div class="myRouter-item" @click="router.push('/model')"> | |||
| <div class="icon"> | |||
| <el-icon><i-ep-edit /></el-icon> | |||
| {{ $t("dataCount.title") }} | |||
| </div> | |||
| {{ $t("modelMangage.title") }} | |||
| </div> | |||
| <div class="bottomBtx"> | |||
| <div class="myRouter-item" @click="router.push('/myAPI')"> | |||
| <div class="myRouter-item" @click="router.push('/model')"> | |||
| <div class="icon"> | |||
| <el-icon><i-ep-DocumentAdd /></el-icon> | |||
| {{ $t("apiMangage.title") }} | |||
| </div> | |||
| {{ $t("apiMangage.title") }} | |||
| </div> | |||
| </div> | |||
| </div> | |||
| @@ -77,7 +127,7 @@ import { useAppStore } from "@/store/modules/app"; | |||
| // import { useSettingsStore } from "@/store/modules/settings"; | |||
| import { useRoute, useRouter } from "vue-router"; | |||
| import { useI18n } from "vue-i18n"; | |||
| import { getMenuNavApi } from "@/apis/Permission.js"; | |||
| import { userInfoModules } from "@/store/modules/userInfo"; | |||
| const userInfoPinia = userInfoModules(); | |||
| @@ -138,12 +188,31 @@ function handleOutsideClick() { | |||
| appStore.closeSideBar(false); | |||
| } | |||
| onMounted(() => {}); | |||
| onMounted(() => { | |||
| getMenuNavFunc(); | |||
| }); | |||
| //#region 联系我们弹窗 | |||
| const showTalkUsDialog = ref(false); | |||
| const updateShowTalkUsDialog = (newValue: any) => { | |||
| showTalkUsDialog.value = newValue; | |||
| }; | |||
| //#endregion ------------------------------------ | |||
| //#region 获取路由列表 | |||
| const MenuList = ref([{ id: "", name: "" }]); | |||
| async function getMenuNavFunc() { | |||
| try { | |||
| const res = await getMenuNavApi(); | |||
| MenuList.value = res.data.menuList; | |||
| } catch (error) { | |||
| console.log(error); | |||
| } | |||
| } | |||
| //#endregion ------------------------------------ | |||
| //#region 路由及子路由 | |||
| const showChildrenRouter = ref(""); | |||
| //#endregion ------------------------------------ | |||
| </script> | |||
| @@ -179,10 +248,10 @@ const updateShowTalkUsDialog = (newValue: any) => { | |||
| bottom: 30px; | |||
| } | |||
| &-item { | |||
| display: flex; | |||
| // display: flex; | |||
| width: 100%; | |||
| height: 50px; | |||
| padding-left: 10px; | |||
| // height: 50px; | |||
| // padding-left: 10px; | |||
| font-size: 20px; | |||
| font-weight: 500; | |||
| line-height: 50px; | |||
| @@ -193,14 +262,20 @@ const updateShowTalkUsDialog = (newValue: any) => { | |||
| border-radius: 5px; | |||
| margin-bottom: 20px; | |||
| margin-right: 20px; | |||
| overflow: hidden; | |||
| .icon { | |||
| width: 40px; | |||
| height: 40px; | |||
| display: flex; | |||
| color: #fff; | |||
| border-radius: 50%; | |||
| margin-right: 10px; | |||
| width: 100%; | |||
| height: 50px; | |||
| line-height: 50px; | |||
| .el-icon { | |||
| margin-left: 10px; | |||
| margin-top: 12px; | |||
| margin-right: 10px; | |||
| width: 25px; | |||
| height: 25px; | |||
| font-size: 25px; | |||
| @@ -210,11 +285,20 @@ const updateShowTalkUsDialog = (newValue: any) => { | |||
| vertical-align: sub; | |||
| } | |||
| } | |||
| .childrenRouter { | |||
| cursor: pointer; | |||
| } | |||
| .childrenRouter:hover { | |||
| background-color: #304156; | |||
| } | |||
| &:hover { | |||
| // background: rgba(255, 255, 255, 0.2); | |||
| color: #000; | |||
| background: #fff; | |||
| .icon { | |||
| color: #000; | |||
| } | |||
| .el-icon { | |||
| // color: #d4d0ff; | |||
| color: #000; | |||
| @@ -9,35 +9,36 @@ NProgress.configure({ showSpinner: false }); // 进度条 | |||
| const permissionStore = usePermissionStoreHook(); | |||
| // 白名单路由 | |||
| const whiteList = ["/login", "/signSucceed",'/createVideo','/moveImg']; | |||
| const whiteList = ["/login", "/signSucceed", "/createVideo", "/moveImg"]; | |||
| router.beforeEach(async (to, from, next) => { | |||
| NProgress.start(); | |||
| const AccessToken = localStorage.getItem("AccessToken"); | |||
| next(); | |||
| // 已登录 | |||
| if (AccessToken) { | |||
| // 重置密码时可以去往login页面 | |||
| if ((to.params.type as string) == "4") { | |||
| next(); | |||
| } | |||
| if (to.query.resetPwd) { | |||
| next(); | |||
| } | |||
| if (to.path === "/login") { | |||
| next({ path: "/createVideo" }); | |||
| } else { | |||
| next(); | |||
| } | |||
| // 未登录 | |||
| } else { | |||
| // 未登录可以访问白名单页面 | |||
| if (whiteList.indexOf(to.path) !== -1) { | |||
| next(); | |||
| } else { | |||
| // 不在白名单内,跳转登录页 | |||
| next({ path: "/login" }); | |||
| } | |||
| } | |||
| // if (AccessToken) { | |||
| // // 重置密码时可以去往login页面 | |||
| // if ((to.params.type as string) == "4") { | |||
| // next(); | |||
| // } | |||
| // if (to.query.resetPwd) { | |||
| // next(); | |||
| // } | |||
| // if (to.path === "/login") { | |||
| // next({ path: "/createVideo" }); | |||
| // } else { | |||
| // next(); | |||
| // } | |||
| // // 未登录 | |||
| // } else { | |||
| // // 未登录可以访问白名单页面 | |||
| // if (whiteList.indexOf(to.path) !== -1) { | |||
| // next(); | |||
| // } else { | |||
| // // 不在白名单内,跳转登录页 | |||
| // next({ path: "/login" }); | |||
| // } | |||
| // } | |||
| }); | |||
| router.afterEach(() => { | |||
| @@ -5,87 +5,72 @@ export const Layout = () => import("@/layout/index.vue"); | |||
| // 静态路由 | |||
| export const constantRoutes: RouteRecordRaw[] = [ | |||
| // 登录 | |||
| { | |||
| path: "/login", | |||
| component: () => import("@/views/login/index.vue"), | |||
| meta: { hidden: true }, | |||
| name:'login' | |||
| name: "login", | |||
| }, | |||
| { | |||
| path: "/signSucceed", | |||
| component: () => import("@/views/signSucceed/index.vue"), | |||
| meta: { hidden: true }, | |||
| }, | |||
| // 创建视频 | |||
| { | |||
| path: "/", | |||
| component: Layout, | |||
| redirect: "/createVideo", | |||
| redirect: "/model", | |||
| children: [ | |||
| { | |||
| path: "createVideo", | |||
| component: () => import("@/views/createVideo/index.vue"), | |||
| name: "createVideo", | |||
| path: "model", | |||
| component: () => import("@/views/mangage/model.vue"), | |||
| name: "model", | |||
| meta: { | |||
| title: "createVideo", | |||
| title: "model", | |||
| icon: "homepage", | |||
| affix: true, | |||
| name: "createVideo.title", | |||
| name: "modelMangage.title", | |||
| }, | |||
| }, | |||
| ], | |||
| }, | |||
| // 视频列表 | |||
| { | |||
| path: "/", | |||
| component: Layout, | |||
| redirect: "/myCreating", | |||
| redirect: "/keyCheck", | |||
| children: [ | |||
| { | |||
| path: "myCreating", | |||
| component: () => import("@/views/myCreating/index.vue"), | |||
| name: "myCreating", | |||
| path: "keyCheck", | |||
| component: () => import("@/views/mangage/keyCheck.vue"), | |||
| name: "keyCheck", | |||
| meta: { | |||
| title: "myCreating", | |||
| title: "keyCheck", | |||
| icon: "homepage", | |||
| affix: true, | |||
| name: "myCreating.title", | |||
| name: "keyMangage.title", | |||
| }, | |||
| }, | |||
| ], | |||
| }, { | |||
| path: "/", | |||
| component: Layout, | |||
| redirect: "/myStore", | |||
| children: [ | |||
| { | |||
| path: "myStore", | |||
| component: () => import("@/views/myStore/index.vue"), | |||
| name: "myStore", | |||
| meta: { | |||
| title: "myStore", | |||
| icon: "homepage", | |||
| affix: true, | |||
| name: "myStore.title", | |||
| }, | |||
| }, | |||
| ], | |||
| }, { | |||
| }, | |||
| // 系统设置路由 | |||
| { | |||
| path: "/", | |||
| component: Layout, | |||
| redirect: "/myAPI", | |||
| redirect: "/userList", | |||
| children: [ | |||
| { | |||
| path: "myAPI", | |||
| component: () => import("@/views/myAPI/index.vue"), | |||
| name: "myAPI", | |||
| path: "userList", | |||
| component: () => import("@/views/dict/index.vue"), | |||
| name: "userList", | |||
| meta: { | |||
| title: "myAPI", | |||
| title: "userList", | |||
| icon: "homepage", | |||
| affix: true, | |||
| name: "API.title", | |||
| name: "userListMangage.title", | |||
| }, | |||
| }, | |||
| ], | |||
| @@ -93,22 +78,21 @@ export const constantRoutes: RouteRecordRaw[] = [ | |||
| { | |||
| path: "/", | |||
| component: Layout, | |||
| redirect: "/moveImg", | |||
| redirect: "/ruleList", | |||
| children: [ | |||
| { | |||
| path: "moveImg", | |||
| component: () => import("@/views/moveImg/index.vue"), | |||
| name: "moveImg", | |||
| path: "ruleList", | |||
| component: () => import("@/views/mangage/ruleList.vue"), | |||
| name: "ruleList", | |||
| meta: { | |||
| title: "moveImg", | |||
| title: "ruleList", | |||
| icon: "homepage", | |||
| affix: true, | |||
| name: "moveImg.title", | |||
| name: "ruleListMangage.title", | |||
| }, | |||
| }, | |||
| ], | |||
| }, | |||
| ]; | |||
| /** | |||
| @@ -2,7 +2,6 @@ | |||
| export {} | |||
| declare global { | |||
| const EffectScope: typeof import('vue')['EffectScope'] | |||
| const ElForm: typeof import('element-plus/es')['ElForm'] | |||
| const ElMessage: typeof import('element-plus/es')['ElMessage'] | |||
| const ElMessageBox: typeof import('element-plus/es')['ElMessageBox'] | |||
| const asyncComputed: typeof import('@vueuse/core')['asyncComputed'] | |||
| @@ -271,7 +270,6 @@ import { UnwrapRef } from 'vue' | |||
| declare module 'vue' { | |||
| interface ComponentCustomProperties { | |||
| 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 ElMessageBox: UnwrapRef<typeof import('element-plus/es')['ElMessageBox']> | |||
| readonly asyncComputed: UnwrapRef<typeof import('@vueuse/core')['asyncComputed']> | |||
| @@ -14,6 +14,7 @@ declare module '@vue/runtime-core' { | |||
| EditPosition: typeof import('./../components/EditPosition.vue')['default'] | |||
| 'EditPosition copy': typeof import('./../components/EditPosition copy.vue')['default'] | |||
| ElButton: typeof import('element-plus/es')['ElButton'] | |||
| ElCard: typeof import('element-plus/es')['ElCard'] | |||
| ElDialog: typeof import('element-plus/es')['ElDialog'] | |||
| ElDropdown: typeof import('element-plus/es')['ElDropdown'] | |||
| ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem'] | |||
| @@ -25,26 +26,25 @@ declare module '@vue/runtime-core' { | |||
| ElInputNumber: typeof import('element-plus/es')['ElInputNumber'] | |||
| ElOption: typeof import('element-plus/es')['ElOption'] | |||
| ElPagination: typeof import('element-plus/es')['ElPagination'] | |||
| ElRadio: typeof import('element-plus/es')['ElRadio'] | |||
| ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup'] | |||
| ElSelect: typeof import('element-plus/es')['ElSelect'] | |||
| ElSwitch: typeof import('element-plus/es')['ElSwitch'] | |||
| ElTable: typeof import('element-plus/es')['ElTable'] | |||
| ElTableColumn: typeof import('element-plus/es')['ElTableColumn'] | |||
| ElTag: typeof import('element-plus/es')['ElTag'] | |||
| ElTooltip: typeof import('element-plus/es')['ElTooltip'] | |||
| ElUpload: typeof import('element-plus/es')['ElUpload'] | |||
| GithubCorner: typeof import('./../components/GithubCorner/index.vue')['default'] | |||
| Hamburger: typeof import('./../components/Hamburger/index.vue')['default'] | |||
| IconSelect: typeof import('./../components/IconSelect/index.vue')['default'] | |||
| IEpCloseBold: typeof import('~icons/ep/close-bold')['default'] | |||
| IEpCollection: typeof import('~icons/ep/collection')['default'] | |||
| IEpDelete: typeof import('~icons/ep/delete')['default'] | |||
| IEpDocumentAdd: typeof import('~icons/ep/document-add')['default'] | |||
| IEpDownload: typeof import('~icons/ep/download')['default'] | |||
| IEpEdit: typeof import('~icons/ep/edit')['default'] | |||
| IEpGoods: typeof import('~icons/ep/goods')['default'] | |||
| IEpLoading: typeof import('~icons/ep/loading')['default'] | |||
| IEpLock: typeof import('~icons/ep/lock')['default'] | |||
| IEpMenu: typeof import('~icons/ep/menu')['default'] | |||
| IEpPhone: typeof import('~icons/ep/phone')['default'] | |||
| IEpPlus: typeof import('~icons/ep/plus')['default'] | |||
| IEpRefresh: typeof import('~icons/ep/refresh')['default'] | |||
| IEpSearch: typeof import('~icons/ep/search')['default'] | |||
| IEpUser: typeof import('~icons/ep/user')['default'] | |||
| IEpVideoPlay: typeof import('~icons/ep/video-play')['default'] | |||
| LangSelect: typeof import('./../components/LangSelect/index.vue')['default'] | |||
| MultiUpload: typeof import('./../components/Upload/MultiUpload.vue')['default'] | |||
| MyLoading: typeof import('./../components/myLoading.vue')['default'] | |||
| @@ -60,5 +60,6 @@ declare module '@vue/runtime-core' { | |||
| } | |||
| export interface ComponentCustomProperties { | |||
| vInfiniteScroll: typeof import('element-plus/es')['ElInfiniteScroll'] | |||
| vLoading: typeof import('element-plus/es')['ElLoadingDirective'] | |||
| } | |||
| } | |||
| @@ -1,67 +0,0 @@ | |||
| import axios from 'axios' | |||
| import router from '@/router/index' | |||
| import { ElMessage } from 'element-plus' | |||
| // ElMessage | |||
| import { userInfoModules } from "@/store/modules/userInfo"; | |||
| // import stores from '@/store/index' | |||
| import { store } from '@/store/index'; // 因为不是在setup环境而是js中,必须重新初始化加载store | |||
| const userInfoPinia = userInfoModules(store); //pinia | |||
| // 开发环境需以 "/api" 拼接,其他环境需以 "/C" 拼接 | |||
| const env = process.env.NODE_ENV == 'development' ? "/api" : "/C" | |||
| // console.log(process.env.NODE_ENV, 'env') | |||
| /** | |||
| * @description:发送Axios请求 | |||
| */ | |||
| const request = axios.create({ | |||
| baseURL: env, | |||
| timeout: 15000 | |||
| }) | |||
| // 请求拦截器 | |||
| request.interceptors.request.use( | |||
| function (config) { | |||
| // 给所有授权的请求提供token | |||
| const AccessToken = localStorage.getItem("AccessToken") | |||
| if (AccessToken) { | |||
| config.headers.token = AccessToken | |||
| } | |||
| return config | |||
| }, | |||
| function (error) { | |||
| // 操作 | |||
| return Promise.reject(error) | |||
| } | |||
| ) | |||
| // 响应拦截器 | |||
| request.interceptors.response.use( | |||
| function (response) { | |||
| let code = response.data.code | |||
| // 当token无效(过期或损坏)时 1053为未登录 | |||
| if (code == 1052 || code == 1053) { | |||
| localStorage.removeItem("AccessToken"); | |||
| router.push("/login"); | |||
| ElMessage.error("登录过期,请重新登录!"); | |||
| return | |||
| // 弹出错误 | |||
| } else if (code != 200) { | |||
| if (code == 500) { | |||
| ElMessage.error("系统异常,请稍后再试"); | |||
| // 其他错误 | |||
| } else { | |||
| return Promise.reject(response.data) | |||
| } | |||
| } else { | |||
| // 正常返回 | |||
| return response.data | |||
| } | |||
| }, | |||
| function (error) { | |||
| } | |||
| ) | |||
| export default request | |||
| @@ -11,8 +11,8 @@ const appStore = useAppStore(store); //pinia | |||
| const userInfoPinia = userInfoModules(store); //pinia | |||
| // const userInfoPinia = userInfoModules(store); //pinia | |||
| // 开发环境需以 "/api" 拼接,其他环境需以 "/C" 拼接 | |||
| const env = process.env.NODE_ENV == 'development' ? "/api" : "/C" | |||
| // const env = process.env.NODE_ENV == 'development' ? "" : "" | |||
| // const env = process.env.NODE_ENV == 'development' ? "/api" : "/C" | |||
| const env = process.env.NODE_ENV == 'development' ? "/A" : "/A" | |||
| console.log(env) | |||
| /** | |||
| @@ -60,7 +60,7 @@ request.interceptors.response.use( | |||
| let code = response.data.code | |||
| // 当token无效(过期或损坏)时 1053为未登录 | |||
| if (code == 1052 || code == 1053) { | |||
| localStorage.removeItem("AccessToken"); | |||
| // localStorage.removeItem("AccessToken"); | |||
| router.push("/login"); | |||
| // ElMessage.error("登录过期,请重新登录!"); | |||
| // ElMessage.error($t('tips.tokenExpired')); | |||
| @@ -757,8 +757,8 @@ const soundStyle = ref(""); //选择的风格 | |||
| // 语言下拉框内容 | |||
| const languageOptions = ref([]); | |||
| async function voiceTotal() { | |||
| const res = await voiceTotalApi(); | |||
| languageOptions.value = res.data; | |||
| // const res = await voiceTotalApi(); | |||
| // languageOptions.value = res.data; | |||
| } | |||
| // 声音下拉框内容 | |||
| const soundOptions = ref([]); | |||
| @@ -0,0 +1,325 @@ | |||
| <!-- 字典数据 --> | |||
| <script setup lang="ts"> | |||
| import { | |||
| getDictPage, | |||
| getDictFormData, | |||
| addDict, | |||
| updateDict, | |||
| deleteDict, | |||
| } from "@/api/dict"; | |||
| import { DictPageVO, DictForm, DictQuery } from "@/api/dict/types"; | |||
| defineOptions({ | |||
| name: "DictData", | |||
| inheritAttrs: false, | |||
| }); | |||
| const props = defineProps({ | |||
| typeCode: { | |||
| type: String, | |||
| default: () => { | |||
| return ""; | |||
| }, | |||
| }, | |||
| typeName: { | |||
| type: String, | |||
| default: () => { | |||
| return ""; | |||
| }, | |||
| }, | |||
| }); | |||
| watch( | |||
| () => props.typeCode, | |||
| (newVal: string) => { | |||
| queryParams.typeCode = newVal; | |||
| formData.typeCode = newVal; | |||
| resetQuery(); | |||
| } | |||
| ); | |||
| const queryFormRef = ref(ElForm); | |||
| const dataFormRef = ref(ElForm); | |||
| const loading = ref(false); | |||
| const ids = ref<number[]>([]); | |||
| const total = ref(0); | |||
| const queryParams = reactive<DictQuery>({ | |||
| pageNum: 1, | |||
| pageSize: 10, | |||
| typeCode: props.typeCode, | |||
| }); | |||
| const dictList = ref<DictPageVO[]>(); | |||
| const dialog = reactive<DialogOption>({ | |||
| visible: false, | |||
| }); | |||
| const formData = reactive<DictForm>({ | |||
| status: 1, | |||
| typeCode: props.typeCode, | |||
| sort: 1, | |||
| }); | |||
| const rules = reactive({ | |||
| name: [{ required: true, message: "请输入字典名称", trigger: "blur" }], | |||
| value: [{ required: true, message: "请输入字典值", trigger: "blur" }], | |||
| }); | |||
| /** | |||
| * 查询 | |||
| */ | |||
| function handleQuery() { | |||
| if (queryParams.typeCode) { | |||
| loading.value = true; | |||
| getDictPage(queryParams) | |||
| .then(({ data }) => { | |||
| dictList.value = data.list; | |||
| total.value = data.total; | |||
| }) | |||
| .finally(() => (loading.value = false)); | |||
| } | |||
| } | |||
| /** | |||
| * 重置查询 | |||
| */ | |||
| function resetQuery() { | |||
| queryFormRef.value.resetFields(); | |||
| queryParams.pageNum = 1; | |||
| handleQuery(); | |||
| } | |||
| /** | |||
| * 行checkbox change事件 | |||
| * | |||
| * @param selection | |||
| */ | |||
| function handleSelectionChange(selection: any) { | |||
| ids.value = selection.map((item: any) => item.id); | |||
| } | |||
| /** | |||
| * 打开字典表单弹窗 | |||
| * | |||
| * @param dictId 字典ID | |||
| */ | |||
| function openDialog(dictId?: number) { | |||
| dialog.visible = true; | |||
| if (dictId) { | |||
| dialog.title = "修改字典"; | |||
| getDictFormData(dictId).then(({ data }) => { | |||
| Object.assign(formData, data); | |||
| }); | |||
| } else { | |||
| dialog.title = "新增字典"; | |||
| } | |||
| } | |||
| /** | |||
| * 字典表单提交 | |||
| */ | |||
| function handleSubmit() { | |||
| dataFormRef.value.validate((isValid: boolean) => { | |||
| if (isValid) { | |||
| loading.value = false; | |||
| const dictId = formData.id; | |||
| if (dictId) { | |||
| updateDict(dictId, formData) | |||
| .then(() => { | |||
| ElMessage.success("修改成功"); | |||
| closeDialog(); | |||
| resetQuery(); | |||
| }) | |||
| .finally(() => (loading.value = false)); | |||
| } else { | |||
| addDict(formData) | |||
| .then(() => { | |||
| ElMessage.success("新增成功"); | |||
| closeDialog(); | |||
| resetQuery(); | |||
| }) | |||
| .finally(() => (loading.value = false)); | |||
| } | |||
| } | |||
| }); | |||
| } | |||
| /** | |||
| * 关闭弹窗 | |||
| */ | |||
| function closeDialog() { | |||
| dialog.visible = false; | |||
| resetForm(); | |||
| } | |||
| /** | |||
| * 重置表单 | |||
| */ | |||
| function resetForm() { | |||
| dataFormRef.value.resetFields(); | |||
| dataFormRef.value.clearValidate(); | |||
| formData.id = undefined; | |||
| formData.status = 1; | |||
| formData.sort = 1; | |||
| formData.typeCode = props.typeCode; | |||
| } | |||
| /** | |||
| * 删除字典 | |||
| */ | |||
| function handleDelete(dictId?: number) { | |||
| const dictIds = [dictId || ids.value].join(","); | |||
| if (!dictIds) { | |||
| ElMessage.warning("请勾选删除项"); | |||
| return; | |||
| } | |||
| ElMessageBox.confirm("确认删除已选中的数据项?", "警告", { | |||
| confirmButtonText: "确定", | |||
| cancelButtonText: "取消", | |||
| type: "warning", | |||
| }).then(() => { | |||
| deleteDict(dictIds).then(() => { | |||
| ElMessage.success("删除成功"); | |||
| resetQuery(); | |||
| }); | |||
| }); | |||
| } | |||
| onMounted(() => { | |||
| handleQuery(); | |||
| }); | |||
| </script> | |||
| <template> | |||
| <div class="app-container"> | |||
| <div class="search-container"> | |||
| <!-- 搜索表单 --> | |||
| <el-form ref="queryFormRef" :model="queryParams" :inline="true"> | |||
| <el-form-item label="关键字" prop="name"> | |||
| <el-input | |||
| v-model="queryParams.name" | |||
| placeholder="字典名称" | |||
| clearable | |||
| /> | |||
| </el-form-item> | |||
| <el-form-item> | |||
| <el-button type="primary" @click="handleQuery" | |||
| ><i-ep-search />搜索</el-button | |||
| > | |||
| <el-button @click="resetQuery"> <i-ep-refresh />重置</el-button> | |||
| </el-form-item> | |||
| </el-form> | |||
| </div> | |||
| <el-card shadow="never"> | |||
| <template #header> | |||
| <el-button | |||
| v-hasPerm="['sys:dict:add']" | |||
| type="success" | |||
| @click="openDialog()" | |||
| ><i-ep-plus />新增</el-button | |||
| > | |||
| <el-button | |||
| v-hasPerm="['sys:dict:delete']" | |||
| type="danger" | |||
| :disabled="ids.length === 0" | |||
| @click="handleDelete()" | |||
| ><i-ep-delete />删除</el-button | |||
| > | |||
| </template> | |||
| <!-- 数据表格 --> | |||
| <el-table | |||
| v-loading="loading" | |||
| :data="dictList" | |||
| border | |||
| @selection-change="handleSelectionChange" | |||
| > | |||
| <el-table-column type="selection" width="50" /> | |||
| <el-table-column label="字典名称" prop="name" /> | |||
| <el-table-column label="字典值" prop="value" /> | |||
| <el-table-column label="状态" align="center"> | |||
| <template #default="scope"> | |||
| <el-tag v-if="scope.row.status === 1" type="success">启用</el-tag> | |||
| <el-tag v-else type="info">禁用</el-tag> | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column fixed="right" label="操作" align="center"> | |||
| <template #default="scope"> | |||
| <el-button | |||
| v-hasPerm="['sys:dict:edit']" | |||
| type="primary" | |||
| link | |||
| @click="openDialog(scope.row.id)" | |||
| ><i-ep-edit />编辑</el-button | |||
| > | |||
| <el-button | |||
| v-hasPerm="['sys:dict:delete']" | |||
| type="primary" | |||
| link | |||
| @click.stop="handleDelete(scope.row.id)" | |||
| ><i-ep-delete />删除</el-button | |||
| > | |||
| </template> | |||
| </el-table-column> | |||
| </el-table> | |||
| <pagination | |||
| v-if="total > 0" | |||
| v-model:total="total" | |||
| v-model:page="queryParams.pageNum" | |||
| v-model:limit="queryParams.pageSize" | |||
| @pagination="handleQuery" | |||
| /> | |||
| </el-card> | |||
| <!-- 表单弹窗 --> | |||
| <el-dialog | |||
| v-model="dialog.visible" | |||
| :title="dialog.title" | |||
| width="500px" | |||
| @close="closeDialog" | |||
| > | |||
| <el-form | |||
| ref="dataFormRef" | |||
| :model="formData" | |||
| :rules="rules" | |||
| label-width="100px" | |||
| > | |||
| <el-form-item label="字典名称">{{ typeName }}</el-form-item> | |||
| <el-form-item label="字典名称" prop="name"> | |||
| <el-input v-model="formData.name" placeholder="请输入字典名称" /> | |||
| </el-form-item> | |||
| <el-form-item label="字典值" prop="value"> | |||
| <el-input v-model="formData.value" placeholder="字典值" /> | |||
| </el-form-item> | |||
| <el-form-item label="排序" prop="sort"> | |||
| <el-input-number | |||
| v-model="formData.sort" | |||
| controls-position="right" | |||
| :min="0" | |||
| /> | |||
| </el-form-item> | |||
| <el-form-item label="状态" prop="status"> | |||
| <el-radio-group v-model="formData.status"> | |||
| <el-radio :label="1">正常</el-radio> | |||
| <el-radio :label="0">停用</el-radio> | |||
| </el-radio-group> | |||
| </el-form-item> | |||
| <el-form-item label="备注" prop="remark"> | |||
| <el-input v-model="formData.remark" type="textarea" /> | |||
| </el-form-item> | |||
| </el-form> | |||
| <template #footer> | |||
| <div class="dialog-footer"> | |||
| <el-button type="primary" @click="handleSubmit">确 定</el-button> | |||
| <el-button @click="closeDialog">取 消</el-button> | |||
| </div> | |||
| </template> | |||
| </el-dialog> | |||
| </div> | |||
| </template> | |||
| @@ -0,0 +1,322 @@ | |||
| <template> | |||
| <div class="app-container"> | |||
| <div class="search-container"> | |||
| <el-form ref="queryFormRef" :model="queryParams" :inline="true"> | |||
| <el-form-item label="关键字" prop="name"> | |||
| <el-input | |||
| v-model="queryParams.keywords" | |||
| placeholder="字典类型名称/编码" | |||
| clearable | |||
| @keyup.enter="handleQuery" | |||
| /> | |||
| </el-form-item> | |||
| <el-form-item> | |||
| <el-button type="primary" @click="handleQuery()" | |||
| ><i-ep-search />搜索</el-button | |||
| > | |||
| <el-button @click="resetQuery()"><i-ep-refresh />重置</el-button> | |||
| </el-form-item> | |||
| </el-form> | |||
| </div> | |||
| <el-card shadow="never" class="table-container"> | |||
| <template #header> | |||
| <el-button | |||
| v-hasPerm="['sys:dict_type:add']" | |||
| type="success" | |||
| @click="openDialog()" | |||
| ><i-ep-plus />新增</el-button | |||
| > | |||
| <el-button | |||
| type="danger" | |||
| :disabled="ids.length === 0" | |||
| @click="handleDelete()" | |||
| ><i-ep-delete />删除</el-button | |||
| > | |||
| </template> | |||
| <el-table | |||
| v-loading="loading" | |||
| highlight-current-row | |||
| :data="dictTypeList" | |||
| border | |||
| @selection-change="handleSelectionChange" | |||
| > | |||
| <el-table-column type="selection" width="55" align="center" /> | |||
| <el-table-column label="字典类型名称" prop="name" width="200" /> | |||
| <el-table-column label="字典类型编码" prop="code" width="200" /> | |||
| <el-table-column label="状态" align="center" width="100"> | |||
| <template #default="scope"> | |||
| <el-tag v-if="scope.row.status === 1" type="success">启用</el-tag> | |||
| <el-tag v-else type="info">禁用</el-tag> | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column label="备注" prop="remark" align="center" /> | |||
| <el-table-column fixed="right" label="操作" align="center" width="220"> | |||
| <template #default="scope"> | |||
| <el-button | |||
| type="primary" | |||
| link | |||
| size="small" | |||
| @click.stop="openDictDialog(scope.row)" | |||
| ><i-ep-Collection />字典数据</el-button | |||
| > | |||
| <el-button | |||
| v-hasPerm="['sys:dict_type:edit']" | |||
| type="primary" | |||
| link | |||
| size="small" | |||
| @click.stop="openDialog(scope.row.id)" | |||
| ><i-ep-edit />编辑</el-button | |||
| > | |||
| <el-button | |||
| v-hasPerm="['sys:dict_type:delete']" | |||
| type="primary" | |||
| link | |||
| size="small" | |||
| @click.stop="handleDelete(scope.row.id)" | |||
| ><i-ep-delete />删除</el-button | |||
| > | |||
| </template> | |||
| </el-table-column> | |||
| </el-table> | |||
| <pagination | |||
| v-if="total > 0" | |||
| v-model:total="total" | |||
| v-model:page="queryParams.pageNum" | |||
| v-model:limit="queryParams.pageSize" | |||
| @pagination="handleQuery" | |||
| /> | |||
| </el-card> | |||
| <el-dialog | |||
| v-model="dialog.visible" | |||
| :title="dialog.title" | |||
| width="500px" | |||
| @close="closeDialog" | |||
| > | |||
| <el-form | |||
| ref="dataFormRef" | |||
| :model="formData" | |||
| :rules="rules" | |||
| label-width="80px" | |||
| > | |||
| <el-form-item label="字典名称" prop="name"> | |||
| <el-input v-model="formData.name" placeholder="请输入字典名称" /> | |||
| </el-form-item> | |||
| <el-form-item label="字典编码" prop="code"> | |||
| <el-input v-model="formData.code" placeholder="请输入字典编码" /> | |||
| </el-form-item> | |||
| <el-form-item label="状态" prop="status"> | |||
| <el-radio-group v-model="formData.status"> | |||
| <el-radio :label="1">正常</el-radio> | |||
| <el-radio :label="0">停用</el-radio> | |||
| </el-radio-group> | |||
| </el-form-item> | |||
| <el-form-item label="备注" prop="remark"> | |||
| <el-input | |||
| v-model="formData.remark" | |||
| type="textarea" | |||
| placeholder="字典类型备注" | |||
| :autosize="{ minRows: 2, maxRows: 4 }" | |||
| /> | |||
| </el-form-item> | |||
| </el-form> | |||
| <template #footer> | |||
| <div class="dialog-footer"> | |||
| <el-button type="primary" @click="handleSubmit">确 定</el-button> | |||
| <el-button @click="closeDialog">取 消</el-button> | |||
| </div> | |||
| </template> | |||
| </el-dialog> | |||
| <!--字典数据弹窗--> | |||
| <el-dialog | |||
| v-model="dictDataDialog.visible" | |||
| :title="dictDataDialog.title" | |||
| width="1000px" | |||
| @close="closeDictDialog" | |||
| > | |||
| <dict-item | |||
| v-model:typeCode="selectedDictType.typeCode" | |||
| v-model:typeName="selectedDictType.typeName" | |||
| /> | |||
| </el-dialog> | |||
| </div> | |||
| </template> | |||
| <script setup> | |||
| import { | |||
| getDictTypePage, | |||
| getDictTypeForm, | |||
| addDictType, | |||
| updateDictType, | |||
| deleteDictTypes, | |||
| } from "@/api/dict"; | |||
| // import { DictTypePageVO, DictTypeQuery, DictTypeForm } from "@/api/dict/types"; | |||
| defineOptions({ | |||
| name: "DictType", | |||
| inheritAttrs: false, | |||
| }); | |||
| const queryFormRef = ref(""); | |||
| const dataFormRef = ref(""); | |||
| const loading = ref(false); | |||
| const ids = ref([]); | |||
| const total = ref(0); | |||
| const queryParams = reactive({ | |||
| pageNum: 1, | |||
| pageSize: 10, | |||
| }); | |||
| const dictTypeList = ref(); | |||
| const dialog = reactive({ | |||
| visible: false, | |||
| }); | |||
| const formData = reactive({ | |||
| status: 1, | |||
| }); | |||
| const rules = reactive({ | |||
| name: [{ required: true, message: "请输入字典类型名称", trigger: "blur" }], | |||
| code: [{ required: true, message: "请输入字典类型编码", trigger: "blur" }], | |||
| }); | |||
| /** 查询 */ | |||
| function handleQuery() { | |||
| loading.value = true; | |||
| getDictTypePage(queryParams) | |||
| .then(({ data }) => { | |||
| dictTypeList.value = data.list; | |||
| total.value = data.total; | |||
| }) | |||
| .finally(() => { | |||
| loading.value = false; | |||
| }); | |||
| } | |||
| /** | |||
| * 重置查询 | |||
| */ | |||
| function resetQuery() { | |||
| queryFormRef.value.resetFields(); | |||
| queryParams.pageNum = 1; | |||
| handleQuery(); | |||
| } | |||
| /** 行复选框选中 */ | |||
| function handleSelectionChange(selection) { | |||
| ids.value = selection.map((item) => item.id); | |||
| } | |||
| /** | |||
| * 打开字典类型表单弹窗 | |||
| * | |||
| * @param dicTypeId 字典类型ID | |||
| */ | |||
| function openDialog(dicTypeId) { | |||
| dialog.visible = true; | |||
| if (dicTypeId) { | |||
| dialog.title = "修改字典类型"; | |||
| getDictTypeForm(dicTypeId).then(({ data }) => { | |||
| Object.assign(formData, data); | |||
| }); | |||
| } else { | |||
| dialog.title = "新增字典类型"; | |||
| } | |||
| } | |||
| /** 字典类型表单提交 */ | |||
| function handleSubmit() { | |||
| dataFormRef.value.validate((isValid) => { | |||
| if (isValid) { | |||
| loading.value = false; | |||
| const dictTypeId = formData.id; | |||
| if (dictTypeId) { | |||
| updateDictType(dictTypeId, formData) | |||
| .then(() => { | |||
| ElMessage.success("修改成功"); | |||
| closeDialog(); | |||
| handleQuery(); | |||
| }) | |||
| .finally(() => (loading.value = false)); | |||
| } else { | |||
| addDictType(formData) | |||
| .then(() => { | |||
| ElMessage.success("新增成功"); | |||
| closeDialog(); | |||
| handleQuery(); | |||
| }) | |||
| .finally(() => (loading.value = false)); | |||
| } | |||
| } | |||
| }); | |||
| } | |||
| /** 关闭字典类型弹窗 */ | |||
| function closeDialog() { | |||
| dialog.visible = false; | |||
| resetForm(); | |||
| } | |||
| /** 重置字典类型表单 */ | |||
| function resetForm() { | |||
| dataFormRef.value.resetFields(); | |||
| dataFormRef.value.clearValidate(); | |||
| formData.id = undefined; | |||
| formData.status = 1; | |||
| } | |||
| /** 删除字典类型 */ | |||
| function handleDelete(dictTypeId) { | |||
| const dictTypeIds = [dictTypeId || ids.value].join(","); | |||
| if (!dictTypeIds) { | |||
| ElMessage.warning("请勾选删除项"); | |||
| return; | |||
| } | |||
| ElMessageBox.confirm("确认删除已选中的数据项?", "警告", { | |||
| confirmButtonText: "确定", | |||
| cancelButtonText: "取消", | |||
| type: "warning", | |||
| }).then(() => { | |||
| deleteDictTypes(dictTypeIds).then(() => { | |||
| ElMessage.success("删除成功"); | |||
| resetQuery(); | |||
| }); | |||
| }); | |||
| } | |||
| const dictDataDialog = reactive({ | |||
| visible: false, | |||
| }); | |||
| const selectedDictType = reactive({ typeCode: "", typeName: "" }); // 当前选中的字典类型 | |||
| /** 打开字典数据弹窗 */ | |||
| function openDictDialog(row) { | |||
| dictDataDialog.visible = true; | |||
| dictDataDialog.title = "【" + row.name + "】字典数据"; | |||
| selectedDictType.typeCode = row.code; | |||
| selectedDictType.typeName = row.name; | |||
| } | |||
| /** 关闭字典数据弹窗 */ | |||
| function closeDictDialog() { | |||
| dictDataDialog.visible = false; | |||
| } | |||
| onMounted(() => { | |||
| handleQuery(); | |||
| }); | |||
| </script> | |||
| <style lang="scss" scoped></style> | |||
| @@ -31,7 +31,7 @@ | |||
| </el-tooltip> | |||
| </div> | |||
| <el-form-item prop="email"> | |||
| <el-form-item prop="username"> | |||
| <div class="text-white"> | |||
| <svg-icon icon-class="user" /> | |||
| </div> | |||
| @@ -39,8 +39,8 @@ | |||
| class="flex-1" | |||
| ref="email" | |||
| size="large" | |||
| v-model="loginData.email" | |||
| :placeholder="$t('login.email')" | |||
| v-model="loginData.username" | |||
| :placeholder="$t('login.username')" | |||
| name="email" | |||
| /> | |||
| </el-form-item> | |||
| @@ -67,14 +67,14 @@ | |||
| </el-form-item> | |||
| <!-- 验证码 --> | |||
| <el-form-item prop="verifyCode"> | |||
| <el-form-item prop="captcha"> | |||
| <span class="text-white"> | |||
| <svg-icon icon-class="verify_code" /> | |||
| </span> | |||
| <el-input | |||
| v-model="loginData.verifyCode" | |||
| v-model="loginData.captcha" | |||
| auto-complete="off" | |||
| :placeholder="$t('login.verifyCode')" | |||
| :placeholder="$t('login.captcha')" | |||
| class="flex-1" | |||
| @keyup.enter="handleLogin" | |||
| /> | |||
| @@ -111,9 +111,6 @@ | |||
| </el-button> | |||
| <div :class="currentLan == 'zh-cn' ? 'bottomBtnCN' : 'bottomBtnEN'"> | |||
| <div style="margin-bottom: 5px" @click="loginFlag(2)"> | |||
| <span class="join">{{ $t("login.signUp") }}</span> | |||
| </div> | |||
| <div style="margin-bottom: 5px"> | |||
| <span class="join" @click="loginFlag(7)">{{ | |||
| $t("login.SMSLogin") | |||
| @@ -126,188 +123,8 @@ | |||
| </div> | |||
| </div> | |||
| </el-form> | |||
| <!-- 注册账户 isLogin == 2--> | |||
| <el-form | |||
| v-if="isLogin == 2" | |||
| ref="loginFormRef" | |||
| :model="loginData2" | |||
| :rules="loginRules" | |||
| class="login-form" | |||
| > | |||
| <div class="flex text-white items-center"> | |||
| <span class="flex-1 text-center">{{ | |||
| $t("login.title") + " " + $t("login.register") | |||
| }}</span> | |||
| <el-tooltip | |||
| class="box-item" | |||
| effect="dark" | |||
| :content="$t('navbar.LanguageChange')" | |||
| placement="top-start" | |||
| > | |||
| <lang-select class="navItem" style="color: #ffffff" /> | |||
| </el-tooltip> | |||
| </div> | |||
| <el-form-item prop="email"> | |||
| <div class="text-white"> | |||
| <svg-icon icon-class="user" /> | |||
| </div> | |||
| <el-input | |||
| class="flex-1" | |||
| ref="email" | |||
| size="large" | |||
| v-model="loginData2.email" | |||
| :placeholder="$t('login.email')" | |||
| name="email" | |||
| /> | |||
| </el-form-item> | |||
| <el-form-item prop="password"> | |||
| <span class="text-white"> | |||
| <svg-icon icon-class="password" /> | |||
| </span> | |||
| <el-input | |||
| class="flex-1" | |||
| v-model="loginData2.password" | |||
| :placeholder="$t('login.password')" | |||
| :type="passwordVisible === false ? 'password' : 'input'" | |||
| size="large" | |||
| name="password" | |||
| /> | |||
| <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-form-item prop="confirmPassword"> | |||
| <span class="text-white"> | |||
| <svg-icon icon-class="password" /> | |||
| </span> | |||
| <el-input | |||
| class="flex-1" | |||
| v-model="loginData2.confirmPassword" | |||
| :placeholder="$t('login.confirmPassword')" | |||
| :type="passwordVisible === false ? 'password' : 'input'" | |||
| size="large" | |||
| name="confirmPassword" | |||
| @keyup.enter="handleRegister" | |||
| /> | |||
| <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-button | |||
| size="default" | |||
| :loading="loading" | |||
| type="primary" | |||
| class="loginBtn" | |||
| @click.prevent="handleRegister" | |||
| > | |||
| <el-icon | |||
| v-if="isRegistering" | |||
| style="margin-right: 10px" | |||
| class="is-loading" | |||
| > | |||
| <svg | |||
| viewBox="0 0 1024 1024" | |||
| xmlns="http://www.w3.org/2000/svg" | |||
| data-v-ea893728="" | |||
| > | |||
| <path | |||
| fill="currentColor" | |||
| d="M512 64a32 32 0 0 1 32 32v192a32 32 0 0 1-64 0V96a32 32 0 0 1 32-32zm0 640a32 32 0 0 1 32 32v192a32 32 0 1 1-64 0V736a32 32 0 0 1 32-32zm448-192a32 32 0 0 1-32 32H736a32 32 0 1 1 0-64h192a32 32 0 0 1 32 32zm-640 0a32 32 0 0 1-32 32H96a32 32 0 0 1 0-64h192a32 32 0 0 1 32 32zM195.2 195.2a32 32 0 0 1 45.248 0L376.32 331.008a32 32 0 0 1-45.248 45.248L195.2 240.448a32 32 0 0 1 0-45.248zm452.544 452.544a32 32 0 0 1 45.248 0L828.8 783.552a32 32 0 0 1-45.248 45.248L647.744 692.992a32 32 0 0 1 0-45.248zM828.8 195.264a32 32 0 0 1 0 45.184L692.992 376.32a32 32 0 0 1-45.248-45.248l135.808-135.808a32 32 0 0 1 45.248 0zm-452.544 452.48a32 32 0 0 1 0 45.248L240.448 828.8a32 32 0 0 1-45.248-45.248l135.808-135.808a32 32 0 0 1 45.248 0z" | |||
| ></path> | |||
| </svg> | |||
| </el-icon> | |||
| {{ $t("login.registerBtn") }} | |||
| </el-button> | |||
| <div :class="currentLan == 'zh-cn' ? 'bottomBtnCN' : 'bottomBtnEN'"> | |||
| <div style="margin-bottom: 5px" @click="loginFlag(1)"> | |||
| <span class="join">{{ $t("login.signIn") }}</span> | |||
| </div> | |||
| <div> | |||
| <span class="join" @click="loginFlag(3)">{{ | |||
| $t("login.forgetPwd") | |||
| }}</span> | |||
| </div> | |||
| </div> | |||
| </el-form> | |||
| <!-- 注册账户之后输入短信验证码 isLogin == 6--> | |||
| <el-form | |||
| v-if="isLogin == 6" | |||
| ref="loginFormRef" | |||
| :model="loginData6" | |||
| :rules="loginRules" | |||
| class="login-form" | |||
| > | |||
| <div class="flex text-white items-center"> | |||
| <span class="flex-1 text-center">{{ | |||
| $t("login.title") + " " + $t("login.register") | |||
| }}</span> | |||
| <el-tooltip | |||
| class="box-item" | |||
| effect="dark" | |||
| :content="$t('navbar.LanguageChange')" | |||
| placement="top-start" | |||
| > | |||
| <lang-select class="navItem" style="color: #ffffff" /> | |||
| </el-tooltip> | |||
| </div> | |||
| <el-form-item prop="SMSCode"> | |||
| <div class="text-white"> | |||
| <svg-icon icon-class="user" /> | |||
| </div> | |||
| <el-input | |||
| class="flex-1" | |||
| ref="email" | |||
| size="large" | |||
| v-model="loginData6.SMSCode" | |||
| :placeholder="$t('login.SMSCode')" | |||
| name="email" | |||
| /> | |||
| </el-form-item> | |||
| <el-button | |||
| size="default" | |||
| :loading="loading" | |||
| type="primary" | |||
| class="loginBtn" | |||
| @click.prevent="handleRegister" | |||
| > | |||
| <el-icon | |||
| v-if="isRegistering" | |||
| style="margin-right: 10px" | |||
| class="is-loading" | |||
| > | |||
| <svg | |||
| viewBox="0 0 1024 1024" | |||
| xmlns="http://www.w3.org/2000/svg" | |||
| data-v-ea893728="" | |||
| > | |||
| <path | |||
| fill="currentColor" | |||
| d="M512 64a32 32 0 0 1 32 32v192a32 32 0 0 1-64 0V96a32 32 0 0 1 32-32zm0 640a32 32 0 0 1 32 32v192a32 32 0 1 1-64 0V736a32 32 0 0 1 32-32zm448-192a32 32 0 0 1-32 32H736a32 32 0 1 1 0-64h192a32 32 0 0 1 32 32zm-640 0a32 32 0 0 1-32 32H96a32 32 0 0 1 0-64h192a32 32 0 0 1 32 32zM195.2 195.2a32 32 0 0 1 45.248 0L376.32 331.008a32 32 0 0 1-45.248 45.248L195.2 240.448a32 32 0 0 1 0-45.248zm452.544 452.544a32 32 0 0 1 45.248 0L828.8 783.552a32 32 0 0 1-45.248 45.248L647.744 692.992a32 32 0 0 1 0-45.248zM828.8 195.264a32 32 0 0 1 0 45.184L692.992 376.32a32 32 0 0 1-45.248-45.248l135.808-135.808a32 32 0 0 1 45.248 0zm-452.544 452.48a32 32 0 0 1 0 45.248L240.448 828.8a32 32 0 0 1-45.248-45.248l135.808-135.808a32 32 0 0 1 45.248 0z" | |||
| ></path> | |||
| </svg> | |||
| </el-icon> | |||
| {{ $t("login.registerBtn") }} | |||
| </el-button> | |||
| <div :class="currentLan == 'zh-cn' ? 'bottomBtnCN' : 'bottomBtnEN'"> | |||
| <div style="margin-bottom: 5px" @click="loginFlag(1)"> | |||
| <span class="join">{{ $t("login.signIn") }}</span> | |||
| </div> | |||
| </div> | |||
| </el-form> | |||
| <!-- 忘记密码 isLogin == 3--> | |||
| <el-form | |||
| v-if="isLogin == 3" | |||
| @@ -691,9 +508,6 @@ | |||
| </el-button> | |||
| <div :class="currentLan == 'zh-cn' ? 'bottomBtnCN' : 'bottomBtnEN'"> | |||
| <div style="margin-bottom: 5px" @click="loginFlag(2)"> | |||
| <span class="join">{{ $t("login.signUp") }}</span> | |||
| </div> | |||
| <div style="margin-bottom: 5px"> | |||
| <span class="join" @click="loginFlag(1)">{{ | |||
| $t("login.pwsLogin") | |||
| @@ -786,8 +600,7 @@ | |||
| import LangSelect from "@/components/LangSelect/index.vue"; | |||
| import SvgIcon from "@/components/SvgIcon/index.vue"; | |||
| import { | |||
| register, | |||
| login, | |||
| loginApi, | |||
| sendRegisterEmail, | |||
| getCodeImgUrl, | |||
| sendUpdPwdEmailApi, | |||
| @@ -799,6 +612,7 @@ import { | |||
| doFindInviteCode, | |||
| doUpdateInviteCode, | |||
| } from "@/apis/login"; | |||
| import { getMenuNavApi } from "@/apis/Permission.js"; | |||
| import axios from "axios"; | |||
| // 状态管理依赖 | |||
| @@ -848,9 +662,9 @@ const isLogining = ref(false); | |||
| const isRegistering = ref(false); | |||
| const loginData = ref({ | |||
| email: "", | |||
| username: "", | |||
| password: "", | |||
| verifyCode: "", | |||
| captcha: "", | |||
| }); | |||
| const loginData2 = ref({ | |||
| @@ -882,6 +696,13 @@ const loginData8 = ref({ | |||
| invitatioCode: "", | |||
| }); | |||
| const loginRules = ref({ | |||
| username: [ | |||
| { | |||
| required: true, | |||
| trigger: "blur", | |||
| validator: passwordValidator, | |||
| }, | |||
| ], | |||
| email: [ | |||
| { | |||
| required: true, | |||
| @@ -894,13 +715,13 @@ const loginRules = ref({ | |||
| confirmPassword: [ | |||
| { required: true, trigger: "blur", validator: confirmPasswordValidator }, | |||
| ], | |||
| verifyCode: [ | |||
| captcha: [ | |||
| { | |||
| required: true, | |||
| trigger: "blur", | |||
| message: | |||
| currentLan.value == "zh-cn" | |||
| ? "请输入验证码" | |||
| ? "请输入验证码2" | |||
| : "Please input verifyCode", | |||
| }, | |||
| ], | |||
| @@ -928,8 +749,8 @@ const loginRules = ref({ | |||
| watch(currentLan, (newValue, oldValue) => { | |||
| const loginRule = loginRules.value; | |||
| loginRule.verifyCode[0].message = | |||
| newValue == "zh-cn" ? "请输入验证码" : "Please input verifyCode"; | |||
| loginRule.captcha[0].message = | |||
| newValue == "zh-cn" ? "请输入验证码1" : "Please input verifyCode"; | |||
| setTimeout(() => { | |||
| loginFormRef.value.resetFields(); | |||
| getInfo(); | |||
| @@ -973,7 +794,7 @@ function getInfo() { | |||
| const deCodeUserInfo = decodeURI(data as any); | |||
| const userInfo = JSON.parse(deCodeUserInfo); | |||
| if (userInfo) { | |||
| loginData.value.email = userInfo.email ? userInfo.email : ""; | |||
| loginData.value.username = userInfo.email ? userInfo.email : ""; | |||
| loginData.value.password = userInfo.password ? userInfo.password : ""; | |||
| } | |||
| } | |||
| @@ -1091,48 +912,7 @@ function confirmPasswordValidator5(rule: any, value: any, callback: any) { | |||
| } | |||
| //#endregion ---------------------------- | |||
| // 登录行为 | |||
| function handleLogin() { | |||
| loginFormRef.value.validate((val: any) => { | |||
| if (val) { | |||
| const data = { | |||
| phone: loginData.value.email, | |||
| password: loginData.value.password, | |||
| code: loginData.value.verifyCode, | |||
| }; | |||
| isLogining.value = true; | |||
| doLogin(data); | |||
| } else { | |||
| const msg = | |||
| currentLan.value == "zh-cn" | |||
| ? "请检查信息格式!" | |||
| : "Please check the format !"; | |||
| ElMessage.error(msg); | |||
| return; | |||
| } | |||
| }); | |||
| } | |||
| // 注册行为 | |||
| function handleRegister() { | |||
| loginFormRef.value.validate((val: any) => { | |||
| if (val) { | |||
| const data = { | |||
| phone: loginData2.value.email, | |||
| password: loginData2.value.password, | |||
| }; | |||
| isRegistering.value = true; | |||
| doRegister(data); | |||
| } else { | |||
| const msg = | |||
| currentLan.value == "zh-cn" | |||
| ? "请检查信息格式!" | |||
| : "Please check the format !"; | |||
| ElMessage.error(msg); | |||
| return; | |||
| } | |||
| }); | |||
| } | |||
| //#region 忘记密码 表单3 | |||
| function sendEmailforgetPwd() { | |||
| @@ -1329,7 +1109,7 @@ async function checkInviteCode() { | |||
| isLogin.value = 8; | |||
| // 有邀请码直接前往我的页面 | |||
| } else if (status == 1) { | |||
| userInfoPinia.getUserInfo(); //保存邮箱到pinia | |||
| // userInfoPinia.getUserInfo(); //保存邮箱到pinia | |||
| ElMessage.success( | |||
| 'currentLan.value == "zh-cn" ? "登录成功!" : "Welcome to Metavatar!"' | |||
| ); | |||
| @@ -1351,7 +1131,7 @@ async function handleInvitatioCode() { | |||
| }; | |||
| try { | |||
| const res = await doUpdateInviteCode(data); | |||
| userInfoPinia.getUserInfo(); //保存邮箱到pinia | |||
| // userInfoPinia.getUserInfo(); //保存邮箱到pinia | |||
| ElMessage.success( | |||
| 'currentLan.value == "zh-cn" ? "登录成功!" : "Welcome to Metavatar!"' | |||
| ); | |||
| @@ -1370,58 +1150,75 @@ function getCode() { | |||
| axios({ | |||
| url: getCodeImgUrl, | |||
| method: "get", | |||
| }).then(() => { | |||
| }).then((res) => { | |||
| verifyCodeUrl.value = getCodeImgUrl; | |||
| showCodeImg.value = true; | |||
| }); | |||
| } | |||
| /** | |||
| * @description:注册 | |||
| * @description:登录 | |||
| * @param {Object} data | |||
| * @return: data | |||
| */ | |||
| async function doRegister(data: object) { | |||
| /** | |||
| * @description:重新发送邮件 | |||
| * @param {string} email | |||
| * @return: data | |||
| */ | |||
| async function reSendEmail(email: string) { | |||
| const msg = | |||
| currentLan.value == "zh-cn" ? "注册成功!" : "Registered successfully"; | |||
| await register(data) | |||
| currentLan.value == "zh-cn" | |||
| ? "确认信息已发送至您的邮箱,请注意查收!" | |||
| : "An email has been send to you, Please pay attention to confirm !"; | |||
| await sendRegisterEmail(email) | |||
| .then((res) => { | |||
| console.log(res, "res"); | |||
| isRegistering.value = false; | |||
| ElMessage.success(msg); | |||
| isLogin.value = 1; | |||
| // 注册成功将账号密码保存到本地 | |||
| saveInfo(data); | |||
| router.go(0); | |||
| }) | |||
| .catch((err) => { | |||
| // 注册失败刷新验证码 | |||
| getCode(); | |||
| isRegistering.value = false; | |||
| console.log(err, "err"); | |||
| ElMessage.error(err.message); | |||
| }); | |||
| } | |||
| /** | |||
| * @description:登录 | |||
| * @param {Object} data | |||
| * @return: data | |||
| */ | |||
| //#region 新登录 | |||
| // 登录行为 | |||
| function handleLogin() { | |||
| loginFormRef.value.validate((val: any) => { | |||
| if (val) { | |||
| const data = { | |||
| username: loginData.value.username, | |||
| password: loginData.value.password, | |||
| captcha: loginData.value.captcha, | |||
| }; | |||
| isLogining.value = true; | |||
| doLogin(data); | |||
| } else { | |||
| const msg = | |||
| currentLan.value == "zh-cn" | |||
| ? "请检查信息格式!" | |||
| : "Please check the format !"; | |||
| ElMessage.error(msg); | |||
| return; | |||
| } | |||
| }); | |||
| } | |||
| async function doLogin(data: any) { | |||
| const msg = | |||
| currentLan.value == "zh-cn" ? "登录成功!" : "Welcome to Metavatar!"; | |||
| await login(data) | |||
| await loginApi(data) | |||
| .then(async (res) => { | |||
| console.log(res, "res"); | |||
| localStorage.setItem("AccessToken", res.data.token); | |||
| // localStorage.setItem("AccessToken", res.data.token); | |||
| // 注册成功将账号密码保存到本地 | |||
| saveInfo(data); | |||
| await getMenuNavFunc(); | |||
| isLogining.value = false; | |||
| // await checkInviteCode(); | |||
| userInfoPinia.getUserInfo(); //保存邮箱到pinia | |||
| // userInfoPinia.getUserInfo(); //保存邮箱到pinia | |||
| ElMessage.success(msg); | |||
| router.push("/createVideo"); | |||
| router.push("/model"); | |||
| }) | |||
| .catch((err) => { | |||
| console.log(err, "err"); | |||
| @@ -1434,28 +1231,17 @@ async function doLogin(data: any) { | |||
| } | |||
| }); | |||
| } | |||
| //#endregion | |||
| /** | |||
| * @description:重新发送邮件 | |||
| * @param {string} email | |||
| * @return: data | |||
| */ | |||
| async function reSendEmail(email: string) { | |||
| const msg = | |||
| currentLan.value == "zh-cn" | |||
| ? "确认信息已发送至您的邮箱,请注意查收!" | |||
| : "An email has been send to you, Please pay attention to confirm !"; | |||
| await sendRegisterEmail(email) | |||
| .then((res) => { | |||
| console.log(res, "res"); | |||
| ElMessage.success(msg); | |||
| }) | |||
| .catch((err) => { | |||
| console.log(err, "err"); | |||
| ElMessage.error(err.message); | |||
| }); | |||
| //#region 获取菜单导航路由 | |||
| async function getMenuNavFunc() { | |||
| try { | |||
| const res = await getMenuNavApi(); | |||
| } catch (error) { | |||
| console.log(error); | |||
| } | |||
| } | |||
| //#endregion -------------------------------- | |||
| onMounted(() => { | |||
| getCode(); | |||
| getInfo(); | |||
| @@ -0,0 +1,171 @@ | |||
| <template> | |||
| <div class="page flex justify-around"> | |||
| <div class="card"> | |||
| <div class="title">密钥管理</div> | |||
| <div class="key"> | |||
| <span class="text">密钥:{{ showCode }}</span> | |||
| <span class="showOrHide" @click="showHideCode">{{ showText }}</span> | |||
| <span v-if="showText == '隐藏'" class="copy" @click="copyKey" | |||
| >复制</span | |||
| > | |||
| </div> | |||
| <div class="keyStatus"> | |||
| <span class="text" | |||
| >密钥状态:{{ keyStatus == 1 ? "正常" : "作废" }}</span | |||
| > | |||
| <span v-if="keyStatus == 1" class="success" @click="changeStatus(2)" | |||
| >恢复</span | |||
| > | |||
| <span v-if="keyStatus == 2" class="fail" @click="changeStatus(1)" | |||
| >作废</span | |||
| > | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </template> | |||
| <!-- videoType==1为竖,==2为横 --> | |||
| <script setup> | |||
| //#region 导入 | |||
| import { linkEmits } from "element-plus"; | |||
| import { getCurrentInstance } from "vue"; | |||
| import { useI18n } from "vue-i18n"; | |||
| import { useRoute, useRouter } from "vue-router"; | |||
| const route = useRoute(); | |||
| const router = useRouter(); | |||
| const { locale } = useI18n(); | |||
| const lanChange = ref(locale); | |||
| const AccessToken = localStorage.getItem("AccessToken"); // 判断有没有登录 | |||
| const key = ref("AE0DVHDWMDOURSBCAP"); | |||
| const hideCode = ref(""); | |||
| const showCode = ref(""); | |||
| const showText = ref("查看"); | |||
| const getKey = () => { | |||
| const len = key.value.length; | |||
| let code = ""; | |||
| for (let index = 0; index < len; index++) { | |||
| code += "*"; | |||
| } | |||
| hideCode.value = code; | |||
| showCode.value = code; | |||
| }; | |||
| const showHideCode = () => { | |||
| if (showText.value == "查看") { | |||
| showText.value = "隐藏"; | |||
| showCode.value = key.value; | |||
| } else { | |||
| showText.value = "查看"; | |||
| showCode.value = hideCode.value; | |||
| } | |||
| }; | |||
| const copyKey = () => { | |||
| navigator.clipboard | |||
| .writeText(key.value) | |||
| .then(() => { | |||
| ElMessage.success("复制成功!"); | |||
| }) | |||
| .catch(() => { | |||
| ElMessage.error("复制失败!"); | |||
| }); | |||
| }; | |||
| const keyStatus = ref(""); | |||
| const getStatus = () => { | |||
| // 1:正常;2:作废 | |||
| const status = 1; | |||
| keyStatus.value = status; | |||
| }; | |||
| const changeStatus = (num) => { | |||
| keyStatus.value = num; | |||
| }; | |||
| onMounted(() => { | |||
| getKey(); | |||
| getStatus(); | |||
| }); | |||
| </script> | |||
| <style lang="scss" scoped> | |||
| .page { | |||
| height: calc(100vh - 80px); | |||
| // height: calc(100vh - 80px); | |||
| background-color: #ffffff; | |||
| border-radius: 30px 0 0 0; | |||
| overflow: hidden; | |||
| .card { | |||
| width: 70%; | |||
| height: 70%; | |||
| background-color: #f8f8f8; | |||
| margin-top: 10vh; | |||
| border-radius: 5vh; | |||
| box-shadow: #0000002e 1px 1px 1px 1px; | |||
| .title { | |||
| text-align: center; | |||
| font-size: 4vh; | |||
| padding: 5vh; | |||
| } | |||
| .key { | |||
| text-align: center; | |||
| font-size: 4vh; | |||
| padding: 5vh; | |||
| .copy { | |||
| color: #ffffff; | |||
| margin-left: 2vh; | |||
| cursor: pointer; | |||
| transition: all 0.3s; | |||
| background-color: #3a57b6; | |||
| padding: 0.7vh; | |||
| border-radius: 15px; | |||
| &:hover { | |||
| background-color: #1ceedc; | |||
| } | |||
| } | |||
| .showOrHide { | |||
| color: #20b4a8; | |||
| margin-left: 2vh; | |||
| cursor: pointer; | |||
| transition: all 0.3s; | |||
| &:hover { | |||
| color: #476ad9; | |||
| } | |||
| } | |||
| } | |||
| .keyStatus { | |||
| text-align: center; | |||
| font-size: 4vh; | |||
| padding: 5vh; | |||
| .success { | |||
| color: #ff0000; | |||
| margin-left: 2vh; | |||
| cursor: pointer; | |||
| transition: all 0.3s; | |||
| &:hover { | |||
| color: #36db43; | |||
| } | |||
| } | |||
| .fail { | |||
| color: #36db43; | |||
| margin-left: 2vh; | |||
| cursor: pointer; | |||
| transition: all 0.3s; | |||
| &:hover { | |||
| color: #ff0000; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| </style> | |||
| @@ -0,0 +1,16 @@ | |||
| <template> | |||
| <div class="page flex justify-around"></div> | |||
| </template> | |||
| <!-- videoType==1为竖,==2为横 --> | |||
| <script setup></script> | |||
| <style lang="scss" scoped> | |||
| .page { | |||
| height: calc(100vh - 80px); | |||
| // height: calc(100vh - 80px); | |||
| background-color: #fff; | |||
| border-radius: 30px 0 0 0; | |||
| overflow: hidden; | |||
| } | |||
| </style> | |||
| @@ -0,0 +1,16 @@ | |||
| <template> | |||
| <div class="page flex justify-around"></div> | |||
| </template> | |||
| <!-- videoType==1为竖,==2为横 --> | |||
| <script setup></script> | |||
| <style lang="scss" scoped> | |||
| .page { | |||
| height: calc(100vh - 80px); | |||
| // height: calc(100vh - 80px); | |||
| background-color: #fff; | |||
| border-radius: 30px 0 0 0; | |||
| overflow: hidden; | |||
| } | |||
| </style> | |||
| @@ -0,0 +1,16 @@ | |||
| <template> | |||
| <div class="page flex justify-around"></div> | |||
| </template> | |||
| <!-- videoType==1为竖,==2为横 --> | |||
| <script setup></script> | |||
| <style lang="scss" scoped> | |||
| .page { | |||
| height: calc(100vh - 80px); | |||
| // height: calc(100vh - 80px); | |||
| background-color: #fff; | |||
| border-radius: 30px 0 0 0; | |||
| overflow: hidden; | |||
| } | |||
| </style> | |||
| @@ -49,12 +49,17 @@ export default defineConfig(({ mode }: ConfigEnv): UserConfig => { | |||
| host: "0.0.0.0", | |||
| port: Number(env.VITE_APP_PORT), | |||
| open: true, // 运行是否自动打开浏览器 | |||
| // "/api": { | |||
| // target: env.VITE_APP_BASE_API, // 线上接口地址 | |||
| // changeOrigin: true, | |||
| // rewrite: (path) => path.replace(/^\/api/, ""), | |||
| // }, | |||
| proxy: { | |||
| // 反向代理解决跨域 | |||
| "/api": { | |||
| "/A": { | |||
| target: env.VITE_APP_BASE_API, // 线上接口地址 | |||
| changeOrigin: true, | |||
| rewrite: (path) => path.replace(/^\/api/, ""), | |||
| rewrite: (path) => path.replace(/^\/A/, ""), | |||
| }, | |||
| }, | |||
| }, | |||