Compare commits

...

12 次程式碼提交

共有 30 個文件被更改,包括 7033 次插入6513 次删除
分割檢視
  1. +4
    -2
      .env.development
  2. +1
    -1
      README.md
  3. +1
    -1
      index.html
  4. +1
    -0
      package.json
  5. +13
    -0
      src/apis/Permission.js
  6. +3
    -16
      src/apis/login.js
  7. +1
    -1
      src/apis/myAccount.js
  8. +13
    -0
      src/apis/system/userList.js
  9. +23
    -7
      src/lang/package/en.ts
  10. +22
    -6
      src/lang/package/zh-cn.ts
  11. +0
    -119
      src/layout/index copy 2.vue
  12. +0
    -131
      src/layout/index copy.vue
  13. +97
    -13
      src/layout/index.vue
  14. +25
    -24
      src/permission.ts
  15. +31
    -47
      src/router/index.ts
  16. +0
    -2
      src/types/auto-imports.d.ts
  17. +10
    -9
      src/types/components.d.ts
  18. +0
    -67
      src/utils/request copy.js
  19. +3
    -3
      src/utils/request.js
  20. +2
    -2
      src/views/createVideo/index.vue
  21. +325
    -0
      src/views/dict/components/dict-item.vue
  22. +322
    -0
      src/views/dict/index.vue
  23. +73
    -287
      src/views/login/index.vue
  24. +171
    -0
      src/views/mangage/keyCheck.vue
  25. +16
    -0
      src/views/mangage/model.vue
  26. +16
    -0
      src/views/mangage/ruleList.vue
  27. +16
    -0
      src/views/mangage/userList.vue
  28. +7
    -2
      vite.config.ts
  29. +235
    -164
      yarn-error.log
  30. +5602
    -5609
      yarn.lock

+ 4
- 2
.env.development 查看文件

@@ -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
- 1
README.md 查看文件

@@ -1,4 +1,4 @@
<!-- 照片说话 慧影 -->
<!-- 邃芒A端-->
git commit -m "feat: "
git commit --no-verify -m "提交时的注释" 跳过检验
git merge origin/dev_

+ 1
- 1
index.html 查看文件

@@ -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>


+ 1
- 0
package.json 查看文件

@@ -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",


+ 13
- 0
src/apis/Permission.js 查看文件

@@ -0,0 +1,13 @@
import request from "@/utils/request.js";

/**
* @description:全查询导航菜单
* @param
* @return:
*/
export function getMenuNavApi() {
return request({
url: `/menu/nav`,
method: 'get',
})
}

+ 3
- 16
src/apis/login.js 查看文件

@@ -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'


+ 1
- 1
src/apis/myAccount.js 查看文件

@@ -70,7 +70,7 @@ export function updUserInfoApi(data) {
*/
export function getUserInfoApi() {
return request({
url: `api/user/getUserInfo`,
url: `getUserInfo`,
method: 'get',
})
}

+ 13
- 0
src/apis/system/userList.js 查看文件

@@ -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'
})
}

+ 23
- 7
src/lang/package/en.ts 查看文件

@@ -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",
},
};

+ 22
- 6
src/lang/package/zh-cn.ts 查看文件

@@ -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 管理",
},
};

+ 0
- 119
src/layout/index copy 2.vue 查看文件

@@ -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>

+ 0
- 131
src/layout/index copy.vue 查看文件

@@ -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>

+ 97
- 13
src/layout/index.vue 查看文件

@@ -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;


+ 25
- 24
src/permission.ts 查看文件

@@ -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(() => {


+ 31
- 47
src/router/index.ts 查看文件

@@ -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",
},
},
],
},

];

/**


+ 0
- 2
src/types/auto-imports.d.ts 查看文件

@@ -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']>


+ 10
- 9
src/types/components.d.ts 查看文件

@@ -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']
}
}

+ 0
- 67
src/utils/request copy.js 查看文件

@@ -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

+ 3
- 3
src/utils/request.js 查看文件

@@ -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'));


+ 2
- 2
src/views/createVideo/index.vue 查看文件

@@ -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([]);


+ 325
- 0
src/views/dict/components/dict-item.vue 查看文件

@@ -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>

+ 322
- 0
src/views/dict/index.vue 查看文件

@@ -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>

+ 73
- 287
src/views/login/index.vue 查看文件

@@ -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();


+ 171
- 0
src/views/mangage/keyCheck.vue 查看文件

@@ -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>

+ 16
- 0
src/views/mangage/model.vue 查看文件

@@ -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>

+ 16
- 0
src/views/mangage/ruleList.vue 查看文件

@@ -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>

+ 16
- 0
src/views/mangage/userList.vue 查看文件

@@ -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>

+ 7
- 2
vite.config.ts 查看文件

@@ -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/, ""),
},
},
},


+ 235
- 164
yarn-error.log
文件差異過大導致無法顯示
查看文件


+ 5602
- 5609
yarn.lock
文件差異過大導致無法顯示
查看文件


Loading…
取消
儲存