Compare commits

...

12 Commits

30 changed files with 7033 additions and 6513 deletions
Unified View
  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 View File

@@ -5,6 +5,8 @@ NODE_ENV='development'


VITE_APP_TITLE = 'Metavatar-PC' VITE_APP_TITLE = 'Metavatar-PC'
VITE_APP_PORT = 3000 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 View File

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

+ 1
- 1
index.html View File

@@ -5,7 +5,7 @@
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" /> <link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Metavatar-慧影</title>
<title>Metavatar-邃芒管理端</title>
</head> </head>


<body> <body>


+ 1
- 0
package.json View File

@@ -24,6 +24,7 @@
"echarts": "^5.2.2", "echarts": "^5.2.2",
"element-plus": "^2.3.1", "element-plus": "^2.3.1",
"js-audio-recorder": "^1.0.7", "js-audio-recorder": "^1.0.7",
"js-cookie": "^3.0.5",
"nprogress": "^0.2.0", "nprogress": "^0.2.0",
"path-browserify": "^1.0.1", "path-browserify": "^1.0.1",
"path-to-regexp": "^6.2.0", "path-to-regexp": "^6.2.0",


+ 13
- 0
src/apis/Permission.js View File

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

@@ -2,29 +2,16 @@ import request from "@/utils/request.js";


const baseURL = import.meta.env.VITE_APP_BASE_API 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 登录 * @description 登录
* @params email,password,code * @params email,password,code
* @returns data * @returns data
*/ */
export function login(data) {
export function loginApi(data) {
return request({ return request({
// url: `/api/user/loginByEmail`, // url: `/api/user/loginByEmail`,
url: `/api/user/login`,
url: `/doLogin`,
method: 'post', method: 'post',
data data
}) })
@@ -175,5 +162,5 @@ export function resetPwdFormApi(data) {
* @description:获取图形验证码 * @description:获取图形验证码
* @return: 验证码地址 * @return: 验证码地址
*/ */
export const getCodeImgUrl = baseURL + '/api/user/captcha.jpg'
export const getCodeImgUrl = baseURL + '/captcha.jpg'



+ 1
- 1
src/apis/myAccount.js View File

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

+ 13
- 0
src/apis/system/userList.js View File

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

@@ -15,7 +15,7 @@ export default {
// 登录页面国际化 // 登录页面国际化
login: { login: {
// title: "Metavatar-MetaTalker", // title: "Metavatar-MetaTalker",
title: "MetaTalker",
title: "MetaTalker-Admin",
username: "Username", username: "Username",
email: "Phone", email: "Phone",
password: "Password", password: "Password",
@@ -24,7 +24,7 @@ export default {
register: "Sign up", register: "Sign up",
loginBtn: "Sign in", loginBtn: "Sign in",
registerBtn: "Sign up", registerBtn: "Sign up",
verifyCode: "Verify code",
captcha: "Verify code",
signIn: "Already got an account? Sign in here", signIn: "Already got an account? Sign in here",
signUp: "Don't have an account? Sign up here", signUp: "Don't have an account? Sign up here",
forgetPwd: "I forgot my password", forgetPwd: "I forgot my password",
@@ -203,10 +203,6 @@ export default {
comingSoon: "Coming Soon", comingSoon: "Coming Soon",
}, },


apiMangage: {
title: "API Mangage",
},

signSucceed: { signSucceed: {
title: "Confirm your email", title: "Confirm your email",
succeed: "Sign Succeed !", succeed: "Sign Succeed !",
@@ -221,6 +217,26 @@ export default {
}, },


modelMangage: { 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 View File

@@ -14,7 +14,7 @@ export default {
}, },
// 登录页面国际化 // 登录页面国际化
login: { login: {
title: "慧影",
title: "邃芒管理端",
username: "用户名", username: "用户名",
email: "手机号", email: "手机号",
password: "密码", password: "密码",
@@ -23,7 +23,7 @@ export default {
register: "注册", register: "注册",
loginBtn: "登 录", loginBtn: "登 录",
registerBtn: "注 册", registerBtn: "注 册",
verifyCode: "验证码",
captcha: "验证码",
// signIn: "已有账号?现在登录!", // signIn: "已有账号?现在登录!",
// signUp: "没有账号?现在加入!", // signUp: "没有账号?现在加入!",
signIn: "立即登录", signIn: "立即登录",
@@ -203,10 +203,6 @@ export default {
comingSoon: "敬请期待", comingSoon: "敬请期待",
}, },


apiMangage: {
title: "API 管理",
},

signSucceed: { signSucceed: {
title: "确认邮箱", title: "确认邮箱",
succeed: "注册成功", succeed: "注册成功",
@@ -222,4 +218,24 @@ export default {
modelMangage: { modelMangage: {
title: "模板管理", title: "模板管理",
}, },

businessMangage: {
title: "商务管理",
},

keyMangage: {
title: "密钥管理",
},

priceMangage: {
title: "价格管理",
},

dataCount: {
title: "数据统计",
},

apiMangage: {
title: "API 管理",
},
}; };

+ 0
- 119
src/layout/index copy 2.vue View File

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

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

@@ -11,19 +11,69 @@
</div> </div>
<!-- 侧边路由列表 --> <!-- 侧边路由列表 -->
<div class="myRouter"> <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"> <div class="icon">
<el-icon><i-ep-edit /></el-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> </div>
{{ $t("modelMangage.title") }}
</div> </div>


<div class="bottomBtx"> <div class="bottomBtx">
<div class="myRouter-item" @click="router.push('/myAPI')">
<div class="myRouter-item" @click="router.push('/model')">
<div class="icon"> <div class="icon">
<el-icon><i-ep-DocumentAdd /></el-icon> <el-icon><i-ep-DocumentAdd /></el-icon>
{{ $t("apiMangage.title") }}
</div> </div>
{{ $t("apiMangage.title") }}
</div> </div>
</div> </div>
</div> </div>
@@ -77,7 +127,7 @@ import { useAppStore } from "@/store/modules/app";
// import { useSettingsStore } from "@/store/modules/settings"; // import { useSettingsStore } from "@/store/modules/settings";
import { useRoute, useRouter } from "vue-router"; import { useRoute, useRouter } from "vue-router";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { getMenuNavApi } from "@/apis/Permission.js";
import { userInfoModules } from "@/store/modules/userInfo"; import { userInfoModules } from "@/store/modules/userInfo";


const userInfoPinia = userInfoModules(); const userInfoPinia = userInfoModules();
@@ -138,12 +188,31 @@ function handleOutsideClick() {
appStore.closeSideBar(false); appStore.closeSideBar(false);
} }


onMounted(() => {});
onMounted(() => {
getMenuNavFunc();
});
//#region 联系我们弹窗 //#region 联系我们弹窗
const showTalkUsDialog = ref(false); const showTalkUsDialog = ref(false);
const updateShowTalkUsDialog = (newValue: any) => { const updateShowTalkUsDialog = (newValue: any) => {
showTalkUsDialog.value = newValue; 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 ------------------------------------ //#endregion ------------------------------------
</script> </script>


@@ -179,10 +248,10 @@ const updateShowTalkUsDialog = (newValue: any) => {
bottom: 30px; bottom: 30px;
} }
&-item { &-item {
display: flex;
// display: flex;
width: 100%; width: 100%;
height: 50px;
padding-left: 10px;
// height: 50px;
// padding-left: 10px;
font-size: 20px; font-size: 20px;
font-weight: 500; font-weight: 500;
line-height: 50px; line-height: 50px;
@@ -193,14 +262,20 @@ const updateShowTalkUsDialog = (newValue: any) => {
border-radius: 5px; border-radius: 5px;
margin-bottom: 20px; margin-bottom: 20px;
margin-right: 20px; margin-right: 20px;
overflow: hidden;
.icon { .icon {
width: 40px;
height: 40px;
display: flex;
color: #fff; color: #fff;
border-radius: 50%; border-radius: 50%;
margin-right: 10px;
width: 100%;
height: 50px;
line-height: 50px;


.el-icon { .el-icon {
margin-left: 10px;
margin-top: 12px;
margin-right: 10px;
width: 25px; width: 25px;
height: 25px; height: 25px;
font-size: 25px; font-size: 25px;
@@ -210,11 +285,20 @@ const updateShowTalkUsDialog = (newValue: any) => {
vertical-align: sub; vertical-align: sub;
} }
} }

.childrenRouter {
cursor: pointer;
}
.childrenRouter:hover {
background-color: #304156;
}
&:hover { &:hover {
// background: rgba(255, 255, 255, 0.2); // background: rgba(255, 255, 255, 0.2);

color: #000; color: #000;
background: #fff; background: #fff;
.icon {
color: #000;
}
.el-icon { .el-icon {
// color: #d4d0ff; // color: #d4d0ff;
color: #000; color: #000;


+ 25
- 24
src/permission.ts View File

@@ -9,35 +9,36 @@ NProgress.configure({ showSpinner: false }); // 进度条
const permissionStore = usePermissionStoreHook(); const permissionStore = usePermissionStoreHook();


// 白名单路由 // 白名单路由
const whiteList = ["/login", "/signSucceed",'/createVideo','/moveImg'];
const whiteList = ["/login", "/signSucceed", "/createVideo", "/moveImg"];


router.beforeEach(async (to, from, next) => { router.beforeEach(async (to, from, next) => {
NProgress.start(); NProgress.start();
const AccessToken = localStorage.getItem("AccessToken"); 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(() => { router.afterEach(() => {


+ 31
- 47
src/router/index.ts View File

@@ -5,87 +5,72 @@ export const Layout = () => import("@/layout/index.vue");


// 静态路由 // 静态路由
export const constantRoutes: RouteRecordRaw[] = [ export const constantRoutes: RouteRecordRaw[] = [

// 登录 // 登录
{ {
path: "/login", path: "/login",
component: () => import("@/views/login/index.vue"), component: () => import("@/views/login/index.vue"),
meta: { hidden: true }, meta: { hidden: true },
name:'login'
name: "login",
}, },

{ {
path: "/signSucceed", path: "/signSucceed",
component: () => import("@/views/signSucceed/index.vue"), component: () => import("@/views/signSucceed/index.vue"),
meta: { hidden: true }, meta: { hidden: true },
}, },
// 创建视频
{ {
path: "/", path: "/",
component: Layout, component: Layout,
redirect: "/createVideo",
redirect: "/model",
children: [ children: [
{ {
path: "createVideo",
component: () => import("@/views/createVideo/index.vue"),
name: "createVideo",
path: "model",
component: () => import("@/views/mangage/model.vue"),
name: "model",
meta: { meta: {
title: "createVideo",
title: "model",
icon: "homepage", icon: "homepage",
affix: true, affix: true,
name: "createVideo.title",
name: "modelMangage.title",
}, },
}, },
], ],
}, },
// 视频列表
{ {
path: "/", path: "/",
component: Layout, component: Layout,
redirect: "/myCreating",
redirect: "/keyCheck",
children: [ children: [
{ {
path: "myCreating",
component: () => import("@/views/myCreating/index.vue"),
name: "myCreating",
path: "keyCheck",
component: () => import("@/views/mangage/keyCheck.vue"),
name: "keyCheck",
meta: { meta: {
title: "myCreating",
title: "keyCheck",
icon: "homepage", icon: "homepage",
affix: true, 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: "/", path: "/",
component: Layout, component: Layout,
redirect: "/myAPI",
redirect: "/userList",
children: [ children: [
{ {
path: "myAPI",
component: () => import("@/views/myAPI/index.vue"),
name: "myAPI",
path: "userList",
component: () => import("@/views/dict/index.vue"),
name: "userList",
meta: { meta: {
title: "myAPI",
title: "userList",
icon: "homepage", icon: "homepage",
affix: true, affix: true,
name: "API.title",
name: "userListMangage.title",
}, },
}, },
], ],
@@ -93,22 +78,21 @@ export const constantRoutes: RouteRecordRaw[] = [
{ {
path: "/", path: "/",
component: Layout, component: Layout,
redirect: "/moveImg",
redirect: "/ruleList",
children: [ children: [
{ {
path: "moveImg",
component: () => import("@/views/moveImg/index.vue"),
name: "moveImg",
path: "ruleList",
component: () => import("@/views/mangage/ruleList.vue"),
name: "ruleList",
meta: { meta: {
title: "moveImg",
title: "ruleList",
icon: "homepage", icon: "homepage",
affix: true, affix: true,
name: "moveImg.title",
name: "ruleListMangage.title",
}, },
}, },
], ],
}, },

]; ];


/** /**


+ 0
- 2
src/types/auto-imports.d.ts View File

@@ -2,7 +2,6 @@
export {} export {}
declare global { declare global {
const EffectScope: typeof import('vue')['EffectScope'] const EffectScope: typeof import('vue')['EffectScope']
const ElForm: typeof import('element-plus/es')['ElForm']
const ElMessage: typeof import('element-plus/es')['ElMessage'] const ElMessage: typeof import('element-plus/es')['ElMessage']
const ElMessageBox: typeof import('element-plus/es')['ElMessageBox'] const ElMessageBox: typeof import('element-plus/es')['ElMessageBox']
const asyncComputed: typeof import('@vueuse/core')['asyncComputed'] const asyncComputed: typeof import('@vueuse/core')['asyncComputed']
@@ -271,7 +270,6 @@ import { UnwrapRef } from 'vue'
declare module 'vue' { declare module 'vue' {
interface ComponentCustomProperties { interface ComponentCustomProperties {
readonly EffectScope: UnwrapRef<typeof import('vue')['EffectScope']> readonly EffectScope: UnwrapRef<typeof import('vue')['EffectScope']>
readonly ElForm: UnwrapRef<typeof import('element-plus/es')['ElForm']>
readonly ElMessage: UnwrapRef<typeof import('element-plus/es')['ElMessage']> readonly ElMessage: UnwrapRef<typeof import('element-plus/es')['ElMessage']>
readonly ElMessageBox: UnwrapRef<typeof import('element-plus/es')['ElMessageBox']> readonly ElMessageBox: UnwrapRef<typeof import('element-plus/es')['ElMessageBox']>
readonly asyncComputed: UnwrapRef<typeof import('@vueuse/core')['asyncComputed']> readonly asyncComputed: UnwrapRef<typeof import('@vueuse/core')['asyncComputed']>


+ 10
- 9
src/types/components.d.ts View File

@@ -14,6 +14,7 @@ declare module '@vue/runtime-core' {
EditPosition: typeof import('./../components/EditPosition.vue')['default'] EditPosition: typeof import('./../components/EditPosition.vue')['default']
'EditPosition copy': typeof import('./../components/EditPosition copy.vue')['default'] 'EditPosition copy': typeof import('./../components/EditPosition copy.vue')['default']
ElButton: typeof import('element-plus/es')['ElButton'] ElButton: typeof import('element-plus/es')['ElButton']
ElCard: typeof import('element-plus/es')['ElCard']
ElDialog: typeof import('element-plus/es')['ElDialog'] ElDialog: typeof import('element-plus/es')['ElDialog']
ElDropdown: typeof import('element-plus/es')['ElDropdown'] ElDropdown: typeof import('element-plus/es')['ElDropdown']
ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem'] ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
@@ -25,26 +26,25 @@ declare module '@vue/runtime-core' {
ElInputNumber: typeof import('element-plus/es')['ElInputNumber'] ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
ElOption: typeof import('element-plus/es')['ElOption'] ElOption: typeof import('element-plus/es')['ElOption']
ElPagination: typeof import('element-plus/es')['ElPagination'] 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'] ElSelect: typeof import('element-plus/es')['ElSelect']
ElSwitch: typeof import('element-plus/es')['ElSwitch'] 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'] ElTooltip: typeof import('element-plus/es')['ElTooltip']
ElUpload: typeof import('element-plus/es')['ElUpload'] ElUpload: typeof import('element-plus/es')['ElUpload']
GithubCorner: typeof import('./../components/GithubCorner/index.vue')['default'] GithubCorner: typeof import('./../components/GithubCorner/index.vue')['default']
Hamburger: typeof import('./../components/Hamburger/index.vue')['default'] Hamburger: typeof import('./../components/Hamburger/index.vue')['default']
IconSelect: typeof import('./../components/IconSelect/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'] IEpDelete: typeof import('~icons/ep/delete')['default']
IEpDocumentAdd: typeof import('~icons/ep/document-add')['default'] IEpDocumentAdd: typeof import('~icons/ep/document-add')['default']
IEpDownload: typeof import('~icons/ep/download')['default']
IEpEdit: typeof import('~icons/ep/edit')['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'] 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'] LangSelect: typeof import('./../components/LangSelect/index.vue')['default']
MultiUpload: typeof import('./../components/Upload/MultiUpload.vue')['default'] MultiUpload: typeof import('./../components/Upload/MultiUpload.vue')['default']
MyLoading: typeof import('./../components/myLoading.vue')['default'] MyLoading: typeof import('./../components/myLoading.vue')['default']
@@ -60,5 +60,6 @@ declare module '@vue/runtime-core' {
} }
export interface ComponentCustomProperties { export interface ComponentCustomProperties {
vInfiniteScroll: typeof import('element-plus/es')['ElInfiniteScroll'] vInfiniteScroll: typeof import('element-plus/es')['ElInfiniteScroll']
vLoading: typeof import('element-plus/es')['ElLoadingDirective']
} }
} }

+ 0
- 67
src/utils/request copy.js View File

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

@@ -11,8 +11,8 @@ const appStore = useAppStore(store); //pinia
const userInfoPinia = userInfoModules(store); //pinia const userInfoPinia = userInfoModules(store); //pinia
// const userInfoPinia = userInfoModules(store); //pinia // const userInfoPinia = userInfoModules(store); //pinia
// 开发环境需以 "/api" 拼接,其他环境需以 "/C" 拼接 // 开发环境需以 "/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) console.log(env)


/** /**
@@ -60,7 +60,7 @@ request.interceptors.response.use(
let code = response.data.code let code = response.data.code
// 当token无效(过期或损坏)时 1053为未登录 // 当token无效(过期或损坏)时 1053为未登录
if (code == 1052 || code == 1053) { if (code == 1052 || code == 1053) {
localStorage.removeItem("AccessToken");
// localStorage.removeItem("AccessToken");
router.push("/login"); router.push("/login");
// ElMessage.error("登录过期,请重新登录!"); // ElMessage.error("登录过期,请重新登录!");
// ElMessage.error($t('tips.tokenExpired')); // ElMessage.error($t('tips.tokenExpired'));


+ 2
- 2
src/views/createVideo/index.vue View File

@@ -757,8 +757,8 @@ const soundStyle = ref(""); //选择的风格
// 语言下拉框内容 // 语言下拉框内容
const languageOptions = ref([]); const languageOptions = ref([]);
async function voiceTotal() { async function voiceTotal() {
const res = await voiceTotalApi();
languageOptions.value = res.data;
// const res = await voiceTotalApi();
// languageOptions.value = res.data;
} }
// 声音下拉框内容 // 声音下拉框内容
const soundOptions = ref([]); const soundOptions = ref([]);


+ 325
- 0
src/views/dict/components/dict-item.vue View File

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

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

@@ -31,7 +31,7 @@
</el-tooltip> </el-tooltip>
</div> </div>


<el-form-item prop="email">
<el-form-item prop="username">
<div class="text-white"> <div class="text-white">
<svg-icon icon-class="user" /> <svg-icon icon-class="user" />
</div> </div>
@@ -39,8 +39,8 @@
class="flex-1" class="flex-1"
ref="email" ref="email"
size="large" size="large"
v-model="loginData.email"
:placeholder="$t('login.email')"
v-model="loginData.username"
:placeholder="$t('login.username')"
name="email" name="email"
/> />
</el-form-item> </el-form-item>
@@ -67,14 +67,14 @@
</el-form-item> </el-form-item>


<!-- 验证码 --> <!-- 验证码 -->
<el-form-item prop="verifyCode">
<el-form-item prop="captcha">
<span class="text-white"> <span class="text-white">
<svg-icon icon-class="verify_code" /> <svg-icon icon-class="verify_code" />
</span> </span>
<el-input <el-input
v-model="loginData.verifyCode"
v-model="loginData.captcha"
auto-complete="off" auto-complete="off"
:placeholder="$t('login.verifyCode')"
:placeholder="$t('login.captcha')"
class="flex-1" class="flex-1"
@keyup.enter="handleLogin" @keyup.enter="handleLogin"
/> />
@@ -111,9 +111,6 @@
</el-button> </el-button>


<div :class="currentLan == 'zh-cn' ? 'bottomBtnCN' : 'bottomBtnEN'"> <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"> <div style="margin-bottom: 5px">
<span class="join" @click="loginFlag(7)">{{ <span class="join" @click="loginFlag(7)">{{
$t("login.SMSLogin") $t("login.SMSLogin")
@@ -126,188 +123,8 @@
</div> </div>
</div> </div>
</el-form> </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--> <!-- 注册账户之后输入短信验证码 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--> <!-- 忘记密码 isLogin == 3-->
<el-form <el-form
v-if="isLogin == 3" v-if="isLogin == 3"
@@ -691,9 +508,6 @@
</el-button> </el-button>


<div :class="currentLan == 'zh-cn' ? 'bottomBtnCN' : 'bottomBtnEN'"> <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"> <div style="margin-bottom: 5px">
<span class="join" @click="loginFlag(1)">{{ <span class="join" @click="loginFlag(1)">{{
$t("login.pwsLogin") $t("login.pwsLogin")
@@ -786,8 +600,7 @@
import LangSelect from "@/components/LangSelect/index.vue"; import LangSelect from "@/components/LangSelect/index.vue";
import SvgIcon from "@/components/SvgIcon/index.vue"; import SvgIcon from "@/components/SvgIcon/index.vue";
import { import {
register,
login,
loginApi,
sendRegisterEmail, sendRegisterEmail,
getCodeImgUrl, getCodeImgUrl,
sendUpdPwdEmailApi, sendUpdPwdEmailApi,
@@ -799,6 +612,7 @@ import {
doFindInviteCode, doFindInviteCode,
doUpdateInviteCode, doUpdateInviteCode,
} from "@/apis/login"; } from "@/apis/login";
import { getMenuNavApi } from "@/apis/Permission.js";
import axios from "axios"; import axios from "axios";
// 状态管理依赖 // 状态管理依赖


@@ -848,9 +662,9 @@ const isLogining = ref(false);
const isRegistering = ref(false); const isRegistering = ref(false);


const loginData = ref({ const loginData = ref({
email: "",
username: "",
password: "", password: "",
verifyCode: "",
captcha: "",
}); });


const loginData2 = ref({ const loginData2 = ref({
@@ -882,6 +696,13 @@ const loginData8 = ref({
invitatioCode: "", invitatioCode: "",
}); });
const loginRules = ref({ const loginRules = ref({
username: [
{
required: true,
trigger: "blur",
validator: passwordValidator,
},
],
email: [ email: [
{ {
required: true, required: true,
@@ -894,13 +715,13 @@ const loginRules = ref({
confirmPassword: [ confirmPassword: [
{ required: true, trigger: "blur", validator: confirmPasswordValidator }, { required: true, trigger: "blur", validator: confirmPasswordValidator },
], ],
verifyCode: [
captcha: [
{ {
required: true, required: true,
trigger: "blur", trigger: "blur",
message: message:
currentLan.value == "zh-cn" currentLan.value == "zh-cn"
? "请输入验证码"
? "请输入验证码2"
: "Please input verifyCode", : "Please input verifyCode",
}, },
], ],
@@ -928,8 +749,8 @@ const loginRules = ref({


watch(currentLan, (newValue, oldValue) => { watch(currentLan, (newValue, oldValue) => {
const loginRule = loginRules.value; 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(() => { setTimeout(() => {
loginFormRef.value.resetFields(); loginFormRef.value.resetFields();
getInfo(); getInfo();
@@ -973,7 +794,7 @@ function getInfo() {
const deCodeUserInfo = decodeURI(data as any); const deCodeUserInfo = decodeURI(data as any);
const userInfo = JSON.parse(deCodeUserInfo); const userInfo = JSON.parse(deCodeUserInfo);
if (userInfo) { if (userInfo) {
loginData.value.email = userInfo.email ? userInfo.email : "";
loginData.value.username = userInfo.email ? userInfo.email : "";
loginData.value.password = userInfo.password ? userInfo.password : ""; loginData.value.password = userInfo.password ? userInfo.password : "";
} }
} }
@@ -1091,48 +912,7 @@ function confirmPasswordValidator5(rule: any, value: any, callback: any) {
} }
//#endregion ---------------------------- //#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 //#region 忘记密码 表单3
function sendEmailforgetPwd() { function sendEmailforgetPwd() {
@@ -1329,7 +1109,7 @@ async function checkInviteCode() {
isLogin.value = 8; isLogin.value = 8;
// 有邀请码直接前往我的页面 // 有邀请码直接前往我的页面
} else if (status == 1) { } else if (status == 1) {
userInfoPinia.getUserInfo(); //保存邮箱到pinia
// userInfoPinia.getUserInfo(); //保存邮箱到pinia
ElMessage.success( ElMessage.success(
'currentLan.value == "zh-cn" ? "登录成功!" : "Welcome to Metavatar!"' 'currentLan.value == "zh-cn" ? "登录成功!" : "Welcome to Metavatar!"'
); );
@@ -1351,7 +1131,7 @@ async function handleInvitatioCode() {
}; };
try { try {
const res = await doUpdateInviteCode(data); const res = await doUpdateInviteCode(data);
userInfoPinia.getUserInfo(); //保存邮箱到pinia
// userInfoPinia.getUserInfo(); //保存邮箱到pinia
ElMessage.success( ElMessage.success(
'currentLan.value == "zh-cn" ? "登录成功!" : "Welcome to Metavatar!"' 'currentLan.value == "zh-cn" ? "登录成功!" : "Welcome to Metavatar!"'
); );
@@ -1370,58 +1150,75 @@ function getCode() {
axios({ axios({
url: getCodeImgUrl, url: getCodeImgUrl,
method: "get", method: "get",
}).then(() => {
}).then((res) => {
verifyCodeUrl.value = getCodeImgUrl; verifyCodeUrl.value = getCodeImgUrl;
showCodeImg.value = true; showCodeImg.value = true;
}); });
} }


/** /**
* @description:注册
* @description:登录
* @param {Object} data * @param {Object} data
* @return: data * @return: data
*/ */
async function doRegister(data: object) {

/**
* @description:重新发送邮件
* @param {string} email
* @return: data
*/
async function reSendEmail(email: string) {
const msg = 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) => { .then((res) => {
console.log(res, "res"); console.log(res, "res");
isRegistering.value = false;
ElMessage.success(msg); ElMessage.success(msg);
isLogin.value = 1;
// 注册成功将账号密码保存到本地
saveInfo(data);
router.go(0);
}) })
.catch((err) => { .catch((err) => {
// 注册失败刷新验证码
getCode();
isRegistering.value = false;
console.log(err, "err"); console.log(err, "err");
ElMessage.error(err.message); 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) { async function doLogin(data: any) {
const msg = const msg =
currentLan.value == "zh-cn" ? "登录成功!" : "Welcome to Metavatar!"; currentLan.value == "zh-cn" ? "登录成功!" : "Welcome to Metavatar!";
await login(data)
await loginApi(data)
.then(async (res) => { .then(async (res) => {
console.log(res, "res"); console.log(res, "res");
localStorage.setItem("AccessToken", res.data.token);
// localStorage.setItem("AccessToken", res.data.token);
// 注册成功将账号密码保存到本地 // 注册成功将账号密码保存到本地
saveInfo(data); saveInfo(data);
await getMenuNavFunc();
isLogining.value = false; isLogining.value = false;
// await checkInviteCode(); // await checkInviteCode();
userInfoPinia.getUserInfo(); //保存邮箱到pinia
// userInfoPinia.getUserInfo(); //保存邮箱到pinia
ElMessage.success(msg); ElMessage.success(msg);
router.push("/createVideo");
router.push("/model");
}) })
.catch((err) => { .catch((err) => {
console.log(err, "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(() => { onMounted(() => {
getCode(); getCode();
getInfo(); getInfo();


+ 171
- 0
src/views/mangage/keyCheck.vue View File

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

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

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

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

@@ -49,12 +49,17 @@ export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
host: "0.0.0.0", host: "0.0.0.0",
port: Number(env.VITE_APP_PORT), port: Number(env.VITE_APP_PORT),
open: true, // 运行是否自动打开浏览器 open: true, // 运行是否自动打开浏览器
// "/api": {
// target: env.VITE_APP_BASE_API, // 线上接口地址
// changeOrigin: true,
// rewrite: (path) => path.replace(/^\/api/, ""),
// },
proxy: { proxy: {
// 反向代理解决跨域 // 反向代理解决跨域
"/api": {
"/A": {
target: env.VITE_APP_BASE_API, // 线上接口地址 target: env.VITE_APP_BASE_API, // 线上接口地址
changeOrigin: true, changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ""),
rewrite: (path) => path.replace(/^\/A/, ""),
}, },
}, },
}, },


+ 235
- 164
yarn-error.log
File diff suppressed because it is too large
View File


+ 5602
- 5609
yarn.lock
File diff suppressed because it is too large
View File


Loading…
Cancel
Save