Compare commits

...

20 次程式碼提交

共有 36 個文件被更改,包括 8127 次插入7227 次删除
分割檢視
  1. +4
    -2
      .env.development
  2. +1
    -1
      README.md
  3. +1
    -1
      index.html
  4. +1
    -0
      package.json
  5. +52
    -0
      src/api_mangage/business.js
  6. +39
    -0
      src/api_mangage/key.js
  7. +13
    -0
      src/apis/Permission.js
  8. +3
    -16
      src/apis/login.js
  9. +1
    -1
      src/apis/myAccount.js
  10. +13
    -0
      src/apis/system/userList.js
  11. +41
    -7
      src/lang/package/en.ts
  12. +40
    -6
      src/lang/package/zh-cn.ts
  13. +0
    -119
      src/layout/index copy 2.vue
  14. +0
    -131
      src/layout/index copy.vue
  15. +99
    -13
      src/layout/index.vue
  16. +25
    -24
      src/permission.ts
  17. +75
    -37
      src/router/index.ts
  18. +0
    -6
      src/types/auto-imports.d.ts
  19. +0
    -31
      src/types/components.d.ts
  20. +0
    -67
      src/utils/request copy.js
  21. +3
    -3
      src/utils/request.js
  22. +301
    -0
      src/views/business/businessCheck.vue
  23. +351
    -0
      src/views/business/businessList.vue
  24. +2
    -2
      src/views/createVideo/index.vue
  25. +325
    -0
      src/views/dict/components/dict-item.vue
  26. +322
    -0
      src/views/dict/index.vue
  27. +301
    -0
      src/views/keys/keyCheck.vue
  28. +149
    -0
      src/views/keys/keyList.vue
  29. +73
    -287
      src/views/login/index.vue
  30. +16
    -0
      src/views/mangage/model.vue
  31. +16
    -0
      src/views/mangage/ruleList.vue
  32. +16
    -0
      src/views/mangage/userList.vue
  33. +0
    -698
      src/views/myCreating/index copy.vue
  34. +7
    -2
      vite.config.ts
  35. +235
    -164
      yarn-error.log
  36. +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",


+ 52
- 0
src/api_mangage/business.js 查看文件

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


/**
* @description 获取合作商列表
* @param {*} (pageNum,pageSize)
* @returns data
*/
export function businessListApi(pageNum, pageSize) {
return request({
url: `/serviceInfo/page?pageNum=${pageNum}&pageSize=${pageSize}`,
method: 'get'
})
}

/**
* @description 通过id获取合作商
* @param {*} id
* @returns data
*/
export function getBusinessByIdApi(id) {
return request({
url: `/serviceInfo/get?id=${id}`,
method: 'get'
})
}

/**
* @description 新增合作商
* @param {*} data
* @returns data
*/
export function addBusinessApi(data) {
return request({
url: `/serviceInfo/save`,
method: 'post',
data
})
}

/**
* @description 修改合作商
* @param {*} data
* @returns data
*/
export function updateBusinessApi(data) {
return request({
url: `/serviceInfo/update`,
method: 'post',
data
})
}

+ 39
- 0
src/api_mangage/key.js 查看文件

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


/**
* @description 获取密钥列表
* @param {*} (pageNum,pageSize)
* @returns data
*/
export function keyListApi(pageNum, pageSize) {
return request({
url: `/thirdPartyApi/page?pageNum=${pageNum}&pageSize=${pageSize}`,
method: 'get'
})
}

/**
* @description 根据id获取密钥详情
* @param {*} (id)
* @returns data
*/
export function getKeyByIdApi(id) {
return request({
url: `/thirdPartyApi/get?id=${id}`,
method: 'get'
})
}

/**
* @description 更改密钥状态
* @param {*} (id,status)
* @returns data
*/
export function updateKeyStatusApi(id, status) {
return request({
url: `/thirdPartyApi/updateStatus`,
method: 'post',
data: { id, status }
})
}

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

+ 41
- 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,44 @@ export default {
},

modelMangage: {
title: "Model Set",
title: "Model",
},

businessMangage: {
title: "Business",
name: "Owner",
address: "Address",
status: "Status",
code: "Code",
addNew: "Add new business",
createTime: "CreateTime",
cancel: "Cancel",
confirm: "Confirm",
nameInputText: "Please type owner",
addressInputText: "Please type address",
codeInputText: "Please type code and make sure it's only",
accessMethod: "Access Method",
typeInputText: "Please select your access method",
},

keyMangage: {
title: "Key",
list: "Key List",
name: "Owner",
status: "Status",
operations: "Operations",
check: "Check",
},

priceMangage: {
title: "Price",
},

dataCount: {
title: "DataBoard",
},

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

+ 40
- 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,42 @@ export default {
modelMangage: {
title: "模板管理",
},

businessMangage: {
title: "商务管理",
name: "所属人",
address: "地址",
status: "状态",
code: "凭证",
addNew: "新增合作商",
createTime: "创建时间",
cancel: "取消",
confirm: "确认",
nameInputText: "请输入所属人名称",
addressInputText: "请输入地址",
codeInputText: "请输入凭证并确保此字段是唯一值",
accessMethod: "接入方式",
typeInputText: "请选择接入方式",
},

keyMangage: {
title: "密钥管理",
list: "密钥列表",
name: "所属人",
status: "密钥状态",
operations: "操作",
check: "查看",
},

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>

+ 99
- 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('/businessList')">
<div class="icon">
<el-icon><i-ep-edit /></el-icon>
{{ $t("businessMangage.title") }}
</div>
</div>

<div class="myRouter-item" @click="router.push('/keyList')">
<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,22 @@ const updateShowTalkUsDialog = (newValue: any) => {
vertical-align: sub;
}
}

.childrenRouter {
cursor: pointer;
transition: all 0.3s;
}
.childrenRouter:hover {
color: #ffffff;
background-color: #000000;
}
&: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(() => {


+ 75
- 37
src/router/index.ts 查看文件

@@ -5,87 +5,89 @@ 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: "/keyList",
children: [
{
path: "myCreating",
component: () => import("@/views/myCreating/index.vue"),
name: "myCreating",
path: "keyList",
component: () => import("@/views/keys/keyList.vue"),
name: "keyList",
meta: {
title: "myCreating",
title: "keyList",
icon: "homepage",
affix: true,
name: "myCreating.title",
name: "keyMangage.list",
},
},
],
}, {
},
{
path: "/",
component: Layout,
redirect: "/myStore",
redirect: "/keyCheck",
children: [
{
path: "myStore",
component: () => import("@/views/myStore/index.vue"),
name: "myStore",
path: "keyCheck",
component: () => import("@/views/keys/keyCheck.vue"),
name: "keyCheck",
meta: {
title: "myStore",
title: "keyCheck",
icon: "homepage",
affix: true,
name: "myStore.title",
name: "keyMangage.title",
},
},
],
}, {
},
{
path: "/",
component: Layout,
redirect: "/myAPI",
redirect: "/businessList",
children: [
{
path: "myAPI",
component: () => import("@/views/myAPI/index.vue"),
name: "myAPI",
path: "businessList",
component: () => import("@/views/business/businessList.vue"),
name: "businessList",
meta: {
title: "myAPI",
title: "businessList",
icon: "homepage",
affix: true,
name: "API.title",
name: "keyMangage.list",
},
},
],
@@ -93,22 +95,58 @@ export const constantRoutes: RouteRecordRaw[] = [
{
path: "/",
component: Layout,
redirect: "/moveImg",
redirect: "/businessCheck",
children: [
{
path: "moveImg",
component: () => import("@/views/moveImg/index.vue"),
name: "moveImg",
path: "businessCheck",
component: () => import("@/views/business/businessCheck.vue"),
name: "businessCheck",
meta: {
title: "moveImg",
title: "businessCheck",
icon: "homepage",
affix: true,
name: "moveImg.title",
name: "keyMangage.title",
},
},
],
},
// 系统设置路由
{
path: "/",
component: Layout,
redirect: "/userList",
children: [
{
path: "userList",
component: () => import("@/views/dict/index.vue"),
name: "userList",
meta: {
title: "userList",
icon: "homepage",
affix: true,
name: "userListMangage.title",
},
},
],
},
{
path: "/",
component: Layout,
redirect: "/ruleList",
children: [
{
path: "ruleList",
component: () => import("@/views/mangage/ruleList.vue"),
name: "ruleList",
meta: {
title: "ruleList",
icon: "homepage",
affix: true,
name: "ruleListMangage.title",
},
},
],
},

];

/**


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

@@ -2,9 +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']
const autoResetRef: typeof import('@vueuse/core')['autoResetRef']
const computed: typeof import('vue')['computed']
@@ -271,9 +268,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']>
readonly autoResetRef: UnwrapRef<typeof import('@vueuse/core')['autoResetRef']>
readonly computed: UnwrapRef<typeof import('vue')['computed']>


+ 0
- 31
src/types/components.d.ts 查看文件

@@ -13,38 +13,10 @@ declare module '@vue/runtime-core' {
CutImg1: typeof import('./../components/cutImg1.vue')['default']
EditPosition: typeof import('./../components/EditPosition.vue')['default']
'EditPosition copy': typeof import('./../components/EditPosition copy.vue')['default']
ElButton: typeof import('element-plus/es')['ElButton']
ElDialog: typeof import('element-plus/es')['ElDialog']
ElDropdown: typeof import('element-plus/es')['ElDropdown']
ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
ElForm: typeof import('element-plus/es')['ElForm']
ElFormItem: typeof import('element-plus/es')['ElFormItem']
ElIcon: typeof import('element-plus/es')['ElIcon']
ElInput: typeof import('element-plus/es')['ElInput']
ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
ElOption: typeof import('element-plus/es')['ElOption']
ElPagination: typeof import('element-plus/es')['ElPagination']
ElSelect: typeof import('element-plus/es')['ElSelect']
ElSwitch: typeof import('element-plus/es')['ElSwitch']
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']
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']
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']
@@ -58,7 +30,4 @@ declare module '@vue/runtime-core' {
TalkUs: typeof import('./../components/talkUs.vue')['default']
WangEditor: typeof import('./../components/WangEditor/index.vue')['default']
}
export interface ComponentCustomProperties {
vInfiniteScroll: typeof import('element-plus/es')['ElInfiniteScroll']
}
}

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


+ 301
- 0
src/views/business/businessCheck.vue 查看文件

@@ -0,0 +1,301 @@
<template>
<div class="page flex justify-around">
<div class="card">
<div class="title">密钥详情</div>
<div class="key">
<span class="text">{{ $t("keyMangage.name") }}:{{ name }}</span>
</div>
<!-- appId -->
<div class="key">
<span class="text">appId:{{ showCode }}</span>
<span class="showOrHide" @click="showHideCode">{{ showText }}</span>
<span v-if="showText == '隐藏'" class="copy" @click="copyKey(showCode)"
>复制</span
>
</div>
<!-- appKey -->
<div class="key">
<span class="text">appKey:{{ showCodeII }}</span>
<span class="showOrHide" @click="showHideCodeII">{{ showTextII }}</span>
<span
v-if="showTextII == '隐藏'"
class="copy"
@click="copyKey(showCodeII)"
>复制</span
>
</div>
<!-- signKey -->
<div class="key">
<span class="text">signKey:{{ showCodeIII }}</span>
<span class="showOrHide" @click="showHideCodeIII(showCodeIII)">{{
showTextIII
}}</span>
<span v-if="showTextIII == '隐藏'" class="copy" @click="copyKey"
>复制</span
>
</div>
<div class="keyStatus">
<span class="text"
>密钥状态:
<span v-if="!keyStatus" style="color: #36db43">正常</span>
<span v-else style="color: #ff0000">失效</span>
</span>
<span v-if="keyStatus" class="fail" @click="changeStatus(0)">恢复</span>
<span v-if="!keyStatus" class="success" @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";

import { getKeyByIdApi, updateKeyStatusApi } from "@/api_mangage/key";

const route = useRoute();
const router = useRouter();
const { locale } = useI18n();
const lanChange = ref(locale);
const AccessToken = localStorage.getItem("AccessToken"); // 判断有没有登录

const keyId = ref("");
const name = ref("");

const appId = ref("");
const hideCode = ref("");
const showCode = ref("");
const showText = ref("查看");

const showHideCode = () => {
if (showText.value == "查看") {
showText.value = "隐藏";
showCode.value = appId.value;
} else {
showText.value = "查看";
showCode.value = hideCode.value;
}
};

const appKey = ref("");
const hideCodeII = ref("");
const showCodeII = ref("");
const showTextII = ref("查看");

const showHideCodeII = () => {
if (showTextII.value == "查看") {
showTextII.value = "隐藏";
showCodeII.value = appKey.value;
} else {
showTextII.value = "查看";
showCodeII.value = hideCodeII.value;
}
};

const signKey = ref("");
const hideCodeIII = ref("");
const showCodeIII = ref("");
const showTextIII = ref("查看");

const showHideCodeIII = () => {
if (showTextIII.value == "查看") {
showTextIII.value = "隐藏";
showCodeIII.value = signKey.value;
} else {
showTextIII.value = "查看";
showCodeIII.value = hideCodeIII.value;
}
};

const getKeyFunc = async () => {
const id = keyId.value;
try {
const res = await getKeyByIdApi(id);
console.log(res, "res");
appId.value = res.data.appId;
appKey.value = res.data.appKey;
signKey.value = res.data.signKey;
keyStatus.value = res.data.status;
name.value = res.data.name;

const len = appId.value.length;
const lenII = appKey.value.length;
const lenIII = signKey.value.length;

let code = "";
let codeII = "";
let codeIII = "";
for (let index = 0; index < len; index++) {
code += "*";
}

for (let index = 0; index < lenII; index++) {
codeII += "*";
}

for (let index = 0; index < lenIII; index++) {
codeIII += "*";
}
hideCode.value = code;
showCode.value = code;

hideCodeII.value = codeII;
showCodeII.value = codeII;

hideCodeIII.value = codeIII;
showCodeIII.value = codeIII;
} catch (error) {
console.log(error, "err");
}
};

const copyKey = (text) => {
navigator.clipboard
.writeText(text)
.then(() => {
ElMessage.success("复制成功!");
})
.catch(() => {
ElMessage.error("复制失败!");
});
};

const keyStatus = ref("");

const changeStatus = async (status) => {
const id = keyId.value;
if (status) {
ElMessageBox.confirm("此操作将作废密钥,确定?", "Warning", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
.then(async () => {
try {
const res = await updateKeyStatusApi(id, status);
if (res.code == 200) {
ElMessage({
type: "success",
message: "作废成功!",
});
getKeyFunc();
}
} catch (error) {
console.log(error, "err");
}
})
.catch(() => {});
} else {
try {
const res = await updateKeyStatusApi(id, status);
if (res.code == 200) {
ElMessage({
type: "success",
message: "恢复成功!",
});
getKeyFunc();
}
} catch (error) {
console.log(error, "err");
}
}
};

onMounted(() => {
keyId.value = route.query.id;
getKeyFunc();
});
</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: 80%;
height: 70%;
background-color: #fafafa;
margin-top: 10vh;
border-radius: 5vh;
box-shadow: #0000002e 1px 1px 1px 1px;

.title {
text-align: center;
font-size: 3vh;
padding: 4vh;
}

.key {
text-align: center;
font-size: 2.5vh;
padding: 5vh;
padding-bottom: 0.5vh;
text-align: left;

.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: 2.9vh;
padding: 4vh;
margin-top: 1vh;

.success {
color: #ffffff;
background-color: #ff0000;
margin-left: 2vh;
padding: 0.7vh;
border-radius: 15px;
cursor: pointer;
transition: all 0.3s;
&:hover {
background-color: #36db43;
}
}
.fail {
color: #ffffff;
background-color: #36db43;
margin-left: 2vh;
padding: 0.7vh;
border-radius: 15px;
cursor: pointer;
transition: all 0.3s;
&:hover {
background-color: #ff0000;
}
}
}
}
}
</style>

+ 351
- 0
src/views/business/businessList.vue 查看文件

@@ -0,0 +1,351 @@
<template>
<div class="page justify-around">
<div class="addbtn">
<el-button type="primary" @click="dialogVisible = true">新增</el-button>
</div>

<el-table
:data="tableData"
style="width: 100%; height: 90%"
size="large"
align="center"
>
<el-table-column
prop="name"
:label="$t('businessMangage.name')"
width="200"
align="center"
/>

<el-table-column
prop="address"
:label="$t('businessMangage.address')"
width="200"
align="center"
/>

<el-table-column
prop="status"
:label="$t('businessMangage.status')"
width="200"
align="center"
>
<template #default="scope">
<span
:style="1 * scope.row.status ? 'color: #ff0000' : 'color: #36db43'"
>{{ getStatus(scope.row.status) }}</span
>
</template>
</el-table-column>

<el-table-column
prop="code"
:label="$t('businessMangage.code')"
width="200"
align="center"
/>

<el-table-column
prop="createTime"
:label="$t('businessMangage.createTime')"
width="200"
align="center"
>
<template #default="scope">
{{ getDate(scope.row.createTime) }}
</template>
</el-table-column>

<el-table-column
fixed="right"
:label="$t('keyMangage.operations')"
width="200"
align="center"
>
<template #default="scope">
<el-button
link
type="primary"
size="small"
@click="showDetail(scope.row.id)"
>{{ $t("keyMangage.check") }}</el-button
>
</template>
</el-table-column>
</el-table>

<el-dialog
v-model="dialogVisible"
:title="$t('businessMangage.addNew')"
width="35%"
:before-close="handleClose"
>
<div class="formData">
<el-form
ref="ruleForm"
label-position="left"
label-width="120px"
:model="formData"
:rules="rules"
>
<el-form-item :label="$t('businessMangage.name') + ':'" prop="name">
<el-input
v-model="formData.name"
:placeholder="$t('businessMangage.nameInputText')"
/>
</el-form-item>

<el-form-item
:label="$t('businessMangage.address') + ':'"
prop="address"
>
<el-input
v-model="formData.address"
:placeholder="$t('businessMangage.addressInputText')"
/>
</el-form-item>

<el-form-item :label="$t('businessMangage.code') + ':'" prop="code">
<el-input
v-model="formData.code"
:placeholder="$t('businessMangage.codeInputText')"
/>
</el-form-item>

<el-form-item
:label="$t('businessMangage.accessMethod') + ':'"
prop="type"
>
<el-select
v-model="formData.type"
:placeholder="$t('businessMangage.typeInputText')"
clearable
>
<el-option
v-for="(item, index) in accessMethods"
:key="index"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-form>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogVisible = false">{{
$t("businessMangage.cancel")
}}</el-button>
<el-button type="primary" @click="addNew(ruleForm)">
{{ $t("businessMangage.confirm") }}
</el-button>
</span>
</template>
</el-dialog>

<div class="pagination">
<el-pagination
v-model:current-page="pageNum"
v-model:page-size="pageSize"
:page-sizes="[10, 50, 100]"
:small="false"
:disabled="false"
:background="true"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
</div>
</template>

<!-- videoType==1为竖,==2为横 -->
<script setup>
//#region 导入
import { linkEmits } from "element-plus";
import { getCurrentInstance } from "vue";

import { businessListApi, addBusinessApi } from "@/api_mangage/business.js";

import { useI18n } from "vue-i18n";

import dayjs from "dayjs";

import { useRoute, useRouter } from "vue-router";

const route = useRoute();
const router = useRouter();
const { locale } = useI18n();
const lanChange = ref(locale);

const tableData = ref([]);

const dialogVisible = ref(false);

const showDetail = (id) => {
router.push({
path: "/businessCheck",
query: {
id,
},
});
};

const pageNum = ref(1);
const pageSize = ref(10);
const total = ref(0);

const getStatus = (val) => {
return val * 1 ? "锁定" : "正常";
};

const getDate = (val) => {
return dayjs(val).format("YYYY-MM-DD");
};

const handleSizeChange = (val) => {
pageSize.value = val;
getBusinessListFunc(pageNum.value, pageSize.value);
};

const handleCurrentChange = (val) => {
pageNum.value = val;
getBusinessListFunc(pageNum.value, pageSize.value);
};

const getBusinessListFunc = async (PageNum, PageSize) => {
try {
const res = await businessListApi(PageNum, PageSize);
console.log(res, "res");
tableData.value = res.data.list;
total.value = res.data.total * 1;
} catch (error) {
console.log(error, "err");
}
};

const formData = ref({
name: "",
address: "",
code: "",
type: "",
});

const rules = {
name: [
{
required: true,
message: "Please input name",
trigger: "blur",
},
],
address: [
{
required: true,
message: "Please input address",
trigger: "blur",
},
],
code: [
{
required: true,
message: "Please input code",
trigger: "blur",
},
],
type: [
{
required: true,
message: "Please select access methods",
trigger: "blur",
},
],
};

const accessMethods = ref([
{
label: "api接入",
value: 1,
},
{
label: "私有化接入",
value: 2,
},
]);

const handleClose = () => {
dialogVisible.value = false;
setTimeout(() => {
formData.value = {
name: "",
address: "",
code: "",
type: "",
};
}, 500);
};

const ruleForm = ref();

const addNew = async (refForm) => {
if (!refForm) return;
await refForm.validate(async (valid, fields) => {
if (valid) {
const data = formData.value;
try {
const res = await addBusinessApi(data);
console.log(res, "res");
if (res.code == 200) {
ElMessage.success("添加成功!");
dialogVisible.value = false;
}
getBusinessListFunc(1, 10);
pageNum.value = 1;
pageSize.value = 10;
} catch (error) {
console.log(error, "err");
ElMessage.error(error.message);
}
} else {
ElMessage.error("请完善信息!");
}
});
};

onMounted(() => {
getBusinessListFunc(1, 10);
});
</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;
padding: 10vh;
.addbtn {
margin-bottom: 2vh;
}
.formData {
padding: 5vh 3vh;
}

.pagination {
position: fixed;
left: 55%;
bottom: 8vh;
transform: translateX(-50%);
border-radius: 5px;
padding: 10px 20px;
z-index: 99;
transition: all 0.3s;
cursor: pointer;
&:hover {
background-color: #b8b8b873;
}
}
}
</style>

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

+ 301
- 0
src/views/keys/keyCheck.vue 查看文件

@@ -0,0 +1,301 @@
<template>
<div class="page flex justify-around">
<div class="card">
<div class="title">密钥详情</div>
<div class="key">
<span class="text">{{ $t("keyMangage.name") }}:{{ name }}</span>
</div>
<!-- appId -->
<div class="key">
<span class="text">appId:{{ showCode }}</span>
<span class="showOrHide" @click="showHideCode">{{ showText }}</span>
<span v-if="showText == '隐藏'" class="copy" @click="copyKey(showCode)"
>复制</span
>
</div>
<!-- appKey -->
<div class="key">
<span class="text">appKey:{{ showCodeII }}</span>
<span class="showOrHide" @click="showHideCodeII">{{ showTextII }}</span>
<span
v-if="showTextII == '隐藏'"
class="copy"
@click="copyKey(showCodeII)"
>复制</span
>
</div>
<!-- signKey -->
<div class="key">
<span class="text">signKey:{{ showCodeIII }}</span>
<span class="showOrHide" @click="showHideCodeIII(showCodeIII)">{{
showTextIII
}}</span>
<span v-if="showTextIII == '隐藏'" class="copy" @click="copyKey"
>复制</span
>
</div>
<div class="keyStatus">
<span class="text"
>密钥状态:
<span v-if="!keyStatus" style="color: #36db43">正常</span>
<span v-else style="color: #ff0000">失效</span>
</span>
<span v-if="keyStatus" class="fail" @click="changeStatus(0)">恢复</span>
<span v-if="!keyStatus" class="success" @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";

import { getKeyByIdApi, updateKeyStatusApi } from "@/api_mangage/key";

const route = useRoute();
const router = useRouter();
const { locale } = useI18n();
const lanChange = ref(locale);
const AccessToken = localStorage.getItem("AccessToken"); // 判断有没有登录

const keyId = ref("");
const name = ref("");

const appId = ref("");
const hideCode = ref("");
const showCode = ref("");
const showText = ref("查看");

const showHideCode = () => {
if (showText.value == "查看") {
showText.value = "隐藏";
showCode.value = appId.value;
} else {
showText.value = "查看";
showCode.value = hideCode.value;
}
};

const appKey = ref("");
const hideCodeII = ref("");
const showCodeII = ref("");
const showTextII = ref("查看");

const showHideCodeII = () => {
if (showTextII.value == "查看") {
showTextII.value = "隐藏";
showCodeII.value = appKey.value;
} else {
showTextII.value = "查看";
showCodeII.value = hideCodeII.value;
}
};

const signKey = ref("");
const hideCodeIII = ref("");
const showCodeIII = ref("");
const showTextIII = ref("查看");

const showHideCodeIII = () => {
if (showTextIII.value == "查看") {
showTextIII.value = "隐藏";
showCodeIII.value = signKey.value;
} else {
showTextIII.value = "查看";
showCodeIII.value = hideCodeIII.value;
}
};

const getKeyFunc = async () => {
const id = keyId.value;
try {
const res = await getKeyByIdApi(id);
console.log(res, "res");
appId.value = res.data.appId;
appKey.value = res.data.appKey;
signKey.value = res.data.signKey;
keyStatus.value = res.data.status;
name.value = res.data.name;

const len = appId.value.length;
const lenII = appKey.value.length;
const lenIII = signKey.value.length;

let code = "";
let codeII = "";
let codeIII = "";
for (let index = 0; index < len; index++) {
code += "*";
}

for (let index = 0; index < lenII; index++) {
codeII += "*";
}

for (let index = 0; index < lenIII; index++) {
codeIII += "*";
}
hideCode.value = code;
showCode.value = code;

hideCodeII.value = codeII;
showCodeII.value = codeII;

hideCodeIII.value = codeIII;
showCodeIII.value = codeIII;
} catch (error) {
console.log(error, "err");
}
};

const copyKey = (text) => {
navigator.clipboard
.writeText(text)
.then(() => {
ElMessage.success("复制成功!");
})
.catch(() => {
ElMessage.error("复制失败!");
});
};

const keyStatus = ref("");

const changeStatus = async (status) => {
const id = keyId.value;
if (status) {
ElMessageBox.confirm("此操作将作废密钥,确定?", "Warning", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
.then(async () => {
try {
const res = await updateKeyStatusApi(id, status);
if (res.code == 200) {
ElMessage({
type: "success",
message: "作废成功!",
});
getKeyFunc();
}
} catch (error) {
console.log(error, "err");
}
})
.catch(() => {});
} else {
try {
const res = await updateKeyStatusApi(id, status);
if (res.code == 200) {
ElMessage({
type: "success",
message: "恢复成功!",
});
getKeyFunc();
}
} catch (error) {
console.log(error, "err");
}
}
};

onMounted(() => {
keyId.value = route.query.id;
getKeyFunc();
});
</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: 80%;
height: 70%;
background-color: #fafafa;
margin-top: 10vh;
border-radius: 5vh;
box-shadow: #0000002e 1px 1px 1px 1px;

.title {
text-align: center;
font-size: 3vh;
padding: 4vh;
}

.key {
text-align: center;
font-size: 2.5vh;
padding: 5vh;
padding-bottom: 0.5vh;
text-align: left;

.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: 2.9vh;
padding: 4vh;
margin-top: 1vh;

.success {
color: #ffffff;
background-color: #ff0000;
margin-left: 2vh;
padding: 0.7vh;
border-radius: 15px;
cursor: pointer;
transition: all 0.3s;
&:hover {
background-color: #36db43;
}
}
.fail {
color: #ffffff;
background-color: #36db43;
margin-left: 2vh;
padding: 0.7vh;
border-radius: 15px;
cursor: pointer;
transition: all 0.3s;
&:hover {
background-color: #ff0000;
}
}
}
}
}
</style>

+ 149
- 0
src/views/keys/keyList.vue 查看文件

@@ -0,0 +1,149 @@
<template>
<div class="page flex justify-around">
<el-table
:data="tableData"
style="width: 100%; height: 90%"
size="large"
align="center"
>
<el-table-column
prop="name"
:label="$t('keyMangage.name')"
width="220"
align="center"
/>

<el-table-column
prop="status"
:label="$t('keyMangage.status')"
width="220"
align="center"
>
<template #default="scope">
<span
:style="1 * scope.row.status ? 'color: #ff0000' : 'color: #36db43'"
>{{ getStatus(scope.row.status) }}</span
>
</template>
</el-table-column>

<el-table-column
fixed="right"
:label="$t('keyMangage.operations')"
width="220"
align="center"
>
<template #default="scope">
<el-button
link
type="primary"
size="small"
@click="showDetail(scope.row.id)"
>{{ $t("keyMangage.check") }}</el-button
>
</template>
</el-table-column>
</el-table>
<div class="pagination">
<el-pagination
v-model:current-page="pageNum"
v-model:page-size="pageSize"
:page-sizes="[10, 50, 100]"
:small="false"
:disabled="false"
:background="true"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
</div>
</template>

<!-- videoType==1为竖,==2为横 -->
<script setup>
//#region 导入
import { linkEmits } from "element-plus";
import { getCurrentInstance } from "vue";

import { keyListApi } from "@/api_mangage/key";

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 tableData = ref([]);

const showDetail = (id) => {
router.push({
path: "/keyCheck",
query: {
id,
},
});
};

const pageNum = ref(1);
const pageSize = ref(10);
const total = ref(0);

const getStatus = (val) => {
return val * 1 ? "失效" : "正常";
};

const handleSizeChange = (val) => {
pageSize.value = val;
getKeyListFunc(pageNum.value, pageSize.value);
};

const handleCurrentChange = (val) => {
pageNum.value = val;
getKeyListFunc(pageNum.value, pageSize.value);
};

const getKeyListFunc = async (PageNum, PageSize) => {
try {
const res = await keyListApi(PageNum, PageSize);
console.log(res, "res");
tableData.value = res.data.list;
total.value = res.data.total * 1;
} catch (error) {
console.log(error, "err");
}
};

onMounted(() => {
getKeyListFunc(1, 10);
});
</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;
padding: 10vh;
.pagination {
position: fixed;
left: 55%;
bottom: 8vh;
transform: translateX(-50%);
border-radius: 5px;
padding: 10px 20px;
z-index: 99;
transition: all 0.3s;
cursor: pointer;
&:hover {
background-color: #b8b8b873;
}
}
}
</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();


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

+ 0
- 698
src/views/myCreating/index copy.vue 查看文件

@@ -1,698 +0,0 @@
<template>
<div class="page">
<!-- 搜索框 -->
<div class="top">
<div class="flex justify-between" style="width: 300px">
<el-input
v-model="title"
:placeholder="$t('myCreating.search')"
@keyup.enter="searchVideoList"
/>
<el-icon class="icon-edit" @click="searchVideoList"
><i-ep-search
/></el-icon>
</div>
</div>
<!-- 作品列表 -->
<div v-if="!isLoading">
<div v-if="videoList.length > 0" class="workList flex">
<div class="workItem" v-for="item in videoList" :key="item.id">
<div class="workImg">
<img
v-if="item.coverImg"
class="coverImg inmiddle"
:src="item.coverImg"
alt=""
/>
<img
v-else
class="takePlace inmiddle"
src="@/assets/img/left-top-logo.png"
alt=""
/>
</div>

<div :class="'statusName ' + item.statusName">
{{ $t("myCreating." + item.statusName) }}
</div>

<div class="workInfo flex">
<span>{{ item.title }}</span>
<span>{{ dayjs(item.createDate).format("YYYY-MM-DD") }}</span>
</div>
<!-- 更多遮罩层 -->
<div
class="more"
@mouseleave="mouseleave"
@click="clickVideoItem(item)"
>
<el-icon
v-if="[0].includes(item.videoStatus)"
class="icon-videoPlay"
><i-ep-edit
/></el-icon>
<el-icon
v-if="[1, 2, 4, 6].includes(item.videoStatus)"
class="icon-videoPlay"
><i-ep-loading
/></el-icon>
<el-icon
v-if="[3].includes(item.videoStatus)"
class="icon-videoPlay"
><i-ep-closeBold
/></el-icon>
<el-icon
v-if="[5].includes(item.videoStatus)"
class="icon-videoPlay"
><i-ep-videoPlay
/></el-icon>
<div class="showBtn" @click.stop="mouseenter(item)">...</div>
<div class="btns" v-show="showPopup">
<!-- 下载按钮 -->
<div
class="btns-item"
@click.stop="handleDownload(item.videoPlayUrl)"
>
<div class="btns-item-icon">
<el-icon class="icon-delete"><i-ep-download /></el-icon>
</div>
<div class="text">{{ $t("myCreating.download") }}</div>
</div>
<!-- 删除按钮 -->
<div
class="btns-item"
@click.stop="handelDelete(item.id, item.title)"
>
<div class="btns-item-icon">
<el-icon class="icon-delete"><i-ep-delete /></el-icon>
</div>
<div class="text">{{ $t("myCreating.delete") }}</div>
</div>
</div>
</div>
</div>
</div>
<div v-if="videoList.length == 0" class="noList">
<div class="title">
{{ $t("myCreating.noList") }}
</div>
<div class="goCreate" @click="goCreate">
{{ $t("myCreating.goCreate") }}
</div>
</div>
</div>
<div v-if="isLoading" class="loadingIcon">
<el-icon 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>
<span class="loadingText">{{ $t("myCreating.loading") }}</span>
</div>
<!-- 弹出框预览作品 -->
<el-dialog
destroy-on-close
class="elDialog"
v-model="showDialog"
:title="presentItem.title"
width="40%"
center
>
<div class="videoBox">
<video
v-if="presentItem.videoPlayUrl"
controls="true"
class=""
:src="presentItem.videoPlayUrl"
></video>
<div v-else class="insteadVideo">
{{ $t("myCreating." + presentItem.statusName + "Text") }}
<span v-if="presentItem.videoStatus == 3">{{
presentItem.videoMsg
}}</span>
</div>
<!-- 有视频路径的页脚 -->
<div class="footer" v-if="presentItem.videoPlayUrl">
<span class="dialog-footer">
<!-- dialog下载按钮 -->
<button
class="elBtn"
type="primary"
@click.stop="handleDownload(presentItem.videoPlayUrl)"
>
<el-icon class="icon-delete"><i-ep-download /></el-icon
>{{ $t("myCreating.download") }}
</button>
<!-- dialog删除按钮 -->
<button
class="elBtn"
@click.stop="handelDelete(presentItem.id, presentItem.title)"
>
<el-icon class="icon-delete"><i-ep-delete /></el-icon
>{{ $t("myCreating.delete") }}
</button>
</span>
</div>
<!-- 无视频路径的页脚 -->
<div class="footer" v-if="!presentItem.videoPlayUrl">
<span class="dialog-footer">
<!-- dialog编辑按钮 -->
<button
class="elBtn"
type="primary"
@click.stop="
router.push({
path: '/createVideo',
query: { id: presentItem.id },
})
"
v-if="[0, 3].includes(presentItem.videoStatus)"
>
{{ $t("myCreating.edit") }}
</button>
</span>
</div>
</div>
</el-dialog>
<!-- 分页 -->
<div v-if="!isLoading" class="pagination">
<el-pagination
v-model:current-page="pageNum"
v-model:page-size="pageSize"
:page-sizes="[10, 20, 50, 100, 200]"
:small="false"
:disabled="false"
:background="true"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
</div>
</template>

<script setup>
import {
userPhotoVideoListApi,
delUserPhotoVideoByIDApi,
} from "@/apis/myCreating";
import { timestampToTime } from "@/utils/tools";
import { useI18n } from "vue-i18n";
import { getStatus } from "./videoStatus";
import { useRouter } from "vue-router";
import dayjs from "dayjs";
const router = useRouter();
// 当前语言状态与国际化组件
const { locale } = useI18n();
const lanChange = ref(locale);

const title = ref("");
const pageNum = ref(1);
const pageSize = ref(10);
const total = ref(0);
// 弹窗显示隐藏
const showDialog = ref(false);
const isLoading = ref(true);
// 当前作品
const presentItem = ref("");
// 作品列表
const videoList = ref([]);

const handleSizeChange = (val) => {
pageSize.value = val;
getPhotoVideoList(pageNum.value, pageSize.value, title.value);
};

const handleCurrentChange = (val) => {
pageNum.value = val;
getPhotoVideoList(pageNum.value, pageSize.value, title.value);
};

// 点击作品
function clickVideoItem(item) {
showDialog.value = true;
presentItem.value = item;
}

// 删除框是否显示
let showPopup = ref(false);
function mouseleave() {
showPopup.value = false;
}

function mouseenter(item) {
presentItem.value = item;
showPopup.value = !showPopup.value;
}
// 下载
function handleDownload(itemVideoPlayUrl) {
if (itemVideoPlayUrl) {
const link = document.createElement("a");
link.href = itemVideoPlayUrl;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
} else {
ElMessage.error(
lanChange.value == "zh-cn" ? `无法下载` : `Unable to download`
);
}
}

function goCreate() {
router.push("/createVideo");
}

function searchVideoList() {
getPhotoVideoList(pageNum.value, pageSize.value, title.value, true);
}

function handelDelete(id, title) {
const msg =
lanChange.value == "zh-cn"
? `确定要删除这个作品吗? 作品标题:${title}`
: `Are you sure to delete this video ? Title:${title};`;
const notice = lanChange.value == "zh-cn" ? "提示" : "Notice";
const confirm = lanChange.value == "zh-cn" ? "确定" : "Confirm";
const cancel = lanChange.value == "zh-cn" ? "取消" : "Cancel";
ElMessageBox.confirm(msg, notice, {
confirmButtonText: confirm,
cancelButtonText: cancel,
}).then(() => {
delPhotoVideo(id);
});
}

/**
* @description:获取我的视频作品
* @return: data
*/
function getPhotoVideoList(pageNum, pageSize, title, searchFlag) {
userPhotoVideoList(pageNum, pageSize, title)
.then((res) => {
console.log(res, "res");
res.data.list.forEach((item) => {
// item.createDate = timestampToTime(item.createDate) || "";
// item.updateDate = timestampToTime(item.updateDate) || "";
// item.createVideoDate = timestampToTime(item.createVideoDate) || "";
item.statusName = getStatus(item.videoStatus);
});
videoList.value = res.data.list;
total.value = res.data.total * 1;
if (searchFlag) {
const total = res.data.total;
const msg1 =
lanChange.value == "zh-cn"
? `查询成功!找到${total}条符合条件的视频`
: `Found! Match ${total} videos`;
const msg2 =
lanChange.value == "zh-cn"
? `查询成功!没有符合条件的视频`
: `Found! No match videos`;
const msg3 =
lanChange.value == "zh-cn"
? `查询成功!已加载全部视频`
: `Found! Present all videos`;
return title
? ElMessage.success(total > 0 ? msg1 : msg2)
: ElMessage.success(msg3);
}
isLoading.value = false;
})
.catch((err) => {
console.log(err, "err");
});
}

/**
* @description:删除视频作品
* @param: videoID
* @return: data
*/
function delPhotoVideo(videoID) {
delUserPhotoVideoByID(videoID)
.then((res) => {
console.log(res, "res");
const msg = lanChange.value == "zh-cn" ? `删除成功!` : `Success !`;
ElMessage.success(msg);
showDialog.value = false;
getPhotoVideoList(pageNum.value, pageSize.value, title.value);
})
.catch((err) => {
console.log(err, "err");
ElMessage.error(err.message);
});
}

onMounted(() => {
isLoading.value = true;
getPhotoVideoList(pageNum.value, pageSize.value, title.value);
});
</script>

<style lang="scss" scoped>
.page {
min-height: calc(100vh - 80px);
padding: 15px 130px;
background-color: #fff;
border-radius: 25px 0 0;
.top {
margin-bottom: 35px;
}
.loadingIcon {
height: 100px;
line-height: 100px;
text-align: center;
transform: scale(2);
.loadingText {
position: relative;
top: -2px;
left: 4px;
}
}
.workList {
flex-wrap: wrap;
justify-content: flex-start;
width: 100%;
// height: 200px;
margin-top: 5px;
padding-bottom: 50px;
cursor: pointer;
.workItem {
position: relative;
width: 300px;
// height: 200px;
margin: 0 20px 20px 0;
border: 2px solid #c2c2c2;
border-radius: 15px;
cursor: pointer;
overflow: hidden;
.workImg {
position: relative;
width: 100%;
height: 170px;
cursor: pointer;
padding: 10px;
overflow: hidden;
.coverImg {
max-width: 90%;
max-height: 170px;
cursor: pointer;
}
.takePlace {
position: absolute;
top: 40%;
width: 80%;
}
}

.more {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 170px;
background-color: rgb(0 0 0 / 30%);
cursor: pointer;
opacity: 0;
transition: all 0.2s;
.icon-videoPlay {
position: absolute;
top: 50%;
left: 50%;
width: 50px;
height: 50px;
font-size: 50px;
color: #fff;
text-align: center;
transform: translate(-50%, -50%);
cursor: pointer;
}

.showBtn {
position: absolute;
top: 10px;
right: 10px;
width: 20px;
height: 20px;
font-size: 20px;
line-height: 10px;
color: #fff;
text-align: center;
transition: all 0.3s;
cursor: pointer;
border-radius: 2px;
&:hover {
background-color: #00000056;
}
}

.btns {
position: absolute;
top: 45px;
right: 10px;
// width: 70px;
// height: 60px;
overflow: hidden;
border-radius: 10px;
cursor: pointer;

&-item {
// width: 70px;
// height: 30px;
text-align: center;
background-color: #fff;
padding: 0 10px;
transition: all 0.3s;
cursor: pointer;
&-icon {
position: relative;
display: inline-block;
width: 20px;
height: 20px;
cursor: pointer;
.icon-delete {
position: absolute;
top: 4px;
left: 0;
width: 20px;
height: 20px;
font-size: 16px;
color: #000;
text-align: center;
cursor: pointer;
}
}

.text {
display: inline-block;
height: 30px;
padding-left: 5px;
margin-top: -5px;
line-height: 20px;
cursor: pointer;
}
&:hover {
color: #ffffff;
background-color: #0000001a;
}
}
}
}

.workInfo {
justify-content: space-between;
height: 40px;
padding: 0 10px;
line-height: 40px;
border-top: 1px solid #afafaf;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-size: 13px;
}
.statusName {
position: absolute;
top: 10%;
left: -10%;
width: 120px;
text-align: center;
color: #ffffff;
font-size: 14px;
transform: rotate(-45deg);

&.manuscript {
/* 草稿 */
background: linear-gradient(to right, #d7d2cc 0%, #304352 100%);
}
&.generating {
/* 生成中 */
background: linear-gradient(270deg, #4b61dc, #15d1b8);
}
&.generationFailed {
/* 生成失败 */
background: linear-gradient(120deg, #f093fb 0%, #f5576c 100%);
}
&.generationSucceed {
/* 生成成功 */
background: linear-gradient(120deg, #84fab0 0%, #8fd3f4 100%);
}
}
&:hover {
.more {
opacity: 1;
}
}
}
}
.noList {
.title {
font-size: 30px;
text-align: center;
margin-top: 100px;
background-image: -webkit-linear-gradient(
left,
#4b61dc,
#15d1b8 25%,
#4b61dc 50%,
#15d1b8 75%,
#4b61dc
) !important;
-webkit-text-fill-color: transparent !important;
-webkit-background-clip: text !important;
background-clip: text !important;
-webkit-background-size: 200% 100% !important;
background-size: 200% 100% !important;
}

.goCreate {
width: 200px;
height: 40px;
line-height: 40px;
text-align: center;
color: #ffffff;
border-radius: 6px;
background: linear-gradient(270deg, #4b61dc, #15d1b8);
margin: 30px auto;
cursor: pointer;
transition: all 0.3s;
&:hover {
transform: scale(1.1);
}
}
}
.pagination {
position: fixed;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
background-color: #ffffff;
padding: 10px 20px;
border-radius: 8px;
transition: all 0.3s;
cursor: pointer;
&:hover {
background-color: #b8b8b873;
}
}
}

:deep(.el-input__wrapper) {
border: none;
border-bottom: 2px solid #000;
border-radius: 0;
box-shadow: none;
}

.el-icon.icon-edit {
width: 30px;
height: 30px;
font-size: 30px;
color: #8c939d;
text-align: center;
cursor: pointer;
transition: all 0.3s;
&:hover {
color: #292929;
}
}

.elDialog {
.videoBox {
// display: flex;
// justify-content: space-between;
width: 100%;
padding: 20px;
video {
width: 100%;
max-height: 600px;
margin: auto;
}
.insteadVideo {
font-size: 20px;
font-weight: 600;
margin: 20px auto;
text-align: center;
}
}

.dialog-footer {
display: flex;
justify-content: space-between;
.elBtn {
color: #fff;
border-radius: 10px;
padding: 5px 10px;
cursor: pointer;
background-color: #000;
transition: all 0.3s;
&:hover {
background-color: #15d1b8;
}
}

:deep(.el-icon) {
margin-right: 5px;
font-weight: 700;
}
}
}

:deep(.el-dialog) {
overflow: hidden;
border-radius: 25px;
}
// :deep(.el-dialog__header) {
// }
:deep(.el-dialog__title) {
background-image: -webkit-linear-gradient(
left,
#4b61dc,
#15d1b8 25%,
#4b61dc 50%,
#15d1b8 75%,
#4b61dc
) !important;
-webkit-text-fill-color: transparent !important;
-webkit-background-clip: text !important;
background-clip: text !important;
-webkit-background-size: 200% 100% !important;
background-size: 200% 100% !important;
}

:deep(.el-dialog__body) {
padding: 0;
}

:deep(.dialog__footer) {
padding: 0;
}
</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…
取消
儲存