比较提交

...

59 次代码提交

作者 SHA1 备注 提交日期
  chutingting fd520ba2dc edit 1年前
  chutingting 8200692e68 edit 1年前
  chutingting 51d3cca8ad 生成文本 1年前
  chutingting 7b52f5489e edit title 1年前
  chutingting 32efebeb00 edit 1年前
  chutingting d398ae67b0 edit 1年前
  chutingting 59e1dc524b edit title 1年前
  chutingting 839d0187b5 edit api 1年前
  chutingting 160a196f97 edit time 1年前
  chutingting 6b83764334 0.2-2.0 1年前
  chutingting dfbf58c9cf edit zindex 1年前
  chutingting 7edfa614f0 选中 1年前
  chutingting 6069139fbc edit z 1年前
  chutingting e3819ec876 edit bug 1年前
  chutingting 033edd82c1 edit 1年前
  chutingting 58addd5730 scroll 1年前
  chutingting 3ad78b3403 edit store 1年前
  chutingting e7a19528a5 edit css 1年前
  chutingting 554da99452 edit brn 1年前
  chutingting 7e81f3d01f edit api 1年前
  chutingting 8141254955 edit 1年前
  chutingting 989b30db37 add api 1年前
  chutingting 7f22868ba4 edit 1年前
  chutingting f6c2c026e7 edit text 1年前
  chutingting 6ed3529c76 扣币 1年前
  chutingting f707fb32e8 gpt 1年前
  chutingting 7151d06fc5 url 1年前
  chutingting 211f69236b 图片检验 1年前
  chutingting 4ca7040149 lang 1年前
  chutingting 8e55ff3bad edit 1年前
  chutingting 952e2d5086 私人定制 1年前
  chutingting 8ef05dfe4c 校验视频 1年前
  chutingting 0a714db591 edit qrcode 1年前
  chutingting 4d35512fa0 rem 1年前
  chutingting 7958f5ab55 edit css 1年前
  chutingting 6709710325 edit font 1年前
  chutingting 46199d670d del rem 1年前
  chutingting 9c23f77397 订单详情 1年前
  chutingting b37aa42c96 订单 1年前
  chutingting 73063a7d6d 订单 1年前
  chutingting 37d6d4f994 username 1年前
  chutingting e5c1449d5f 支付 1年前
  chutingting 93903fef14 支付 1年前
  chutingting b72534ac83 支付 1年前
  chutingting 39f9567d79 商店 1年前
  chutingting 7357522f0d 增加我的 1年前
  chutingting d09946669c 增加我的列表 1年前
  chutingting ac2822f97d test 1年前
  congzc bf1dbdeef7 1 1年前
  congzc af8a52f71a 1 1年前
  congzc 3c02f7889b 1 1年前
  congzc e010b8687d 1 1年前
  congzc 3ea71a8495 1 1年前
  congzc ae78019597 1 1年前
  congzc 6f62765b56 1 1年前
  congzc 837db768cd 1 1年前
  congzc 63b20451f0 AI文案 1年前
  congzc b2d3b0ad3e Merge branch 'dev' of https://git.malls.iformall.com/suimang/Home_wap_pc into dev 1年前
  congzc a75a03d1b0 1 1年前
共有 42 个文件被更改,包括 4973 次插入1016 次删除
  1. +3
    -1
      .env.development
  2. +1
    -1
      .env.test
  3. 二进制
      dist.zip
  4. +1
    -1
      index.html
  5. +1
    -0
      package.json
  6. +39
    -0
      src/apis/api.js
  7. +65
    -4
      src/apis/createVideo.js
  8. +81
    -0
      src/apis/my.js
  9. +2
    -1
      src/apis/myCreating.js
  10. +40
    -1
      src/apis/myStore.js
  11. +39
    -0
      src/apis/pay.js
  12. 二进制
      src/assets/img/alipay.png
  13. 二进制
      src/assets/img/gpt.png
  14. 二进制
      src/assets/img/weChat.png
  15. +17
    -12
      src/components/EditPosition.vue
  16. +42
    -14
      src/components/cutImg.vue
  17. +51
    -0
      src/components/myLoadingIcon2.vue
  18. +59
    -0
      src/lang/package/en.ts
  19. +59
    -0
      src/lang/package/zh-cn.ts
  20. +80
    -13
      src/layout/index.vue
  21. +108
    -8
      src/router/index.ts
  22. +1
    -0
      src/store/modules/userInfo.js
  23. +4
    -0
      src/types/auto-imports.d.ts
  24. +12
    -0
      src/types/components.d.ts
  25. +2
    -2
      src/utils/request.js
  26. +141
    -0
      src/views/api/demo.html
  27. +125
    -0
      src/views/api/index.vue
  28. +755
    -148
      src/views/createVideo/index.vue
  29. +17
    -8
      src/views/login/index.vue
  30. +207
    -0
      src/views/my/coindeduc.vue
  31. +193
    -0
      src/views/my/recharge.vue
  32. +0
    -22
      src/views/myAPI/index.vue
  33. +2
    -1
      src/views/myCreating/index.vue
  34. +1152
    -0
      src/views/myStore/index copy.vue
  35. +303
    -445
      src/views/myStore/index.vue
  36. +7
    -0
      src/views/privatization/index.vue
  37. +6
    -0
      src/views/separation/index.vue
  38. +944
    -0
      src/views/userModel/index.vue
  39. +16
    -0
      src/views/userModel/videoStatus.js
  40. +7
    -0
      src/views/voiceModel/index.vue
  41. +6
    -0
      src/views/voiceprint/index.vue
  42. +385
    -334
      yarn.lock

+ 3
- 1
.env.development 查看文件

@@ -6,5 +6,7 @@ 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://test.metavatar.cc/C'
# VITE_APP_BASE_API = 'https://phototest.metavatar.cc/C'
VITE_APP_BASE_API = 'https://m.metavatar.cc/C'


+ 1
- 1
.env.test 查看文件

@@ -6,4 +6,4 @@ NODE_ENV='test'
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://mtest.metavatar.cc/C'

二进制
dist.zip 查看文件


+ 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 查看文件

@@ -34,6 +34,7 @@
"vue": "^3.2.45",
"vue-cropper": "^1.0.9",
"vue-i18n": "9",
"vue-qr": "^4.0.9",
"vue-router": "^4.0.13"
},
"devDependencies": {


+ 39
- 0
src/apis/api.js 查看文件

@@ -0,0 +1,39 @@

import request from "@/utils/request.js";


/**
* @description 服务端api签名指南
* @params
* @returns
*/
export function getAvailableApiGuideApi() {
return request({
url: `/api/apiGuide/getAvailableApiGuide`,
method: 'get'
})
}

/**
* @description 开放接口列表
* @params
* @returns
*/
export function apiMenuApi() {
return request({
url: `/api/apiMenu/list`,
method: 'get'
})
}

/**
* @description 获取接口详情
* @params
* @returns
*/
export function getContentApi(id) {
return request({
url: `/api/apiMenu/get?id=${id}`,
method: 'get'
})
}

+ 65
- 4
src/apis/createVideo.js 查看文件

@@ -7,8 +7,9 @@ import request from "@/utils/request.js";
* @returns data
*/
export function modeListApi(sex, pageNum, pageSize, videoType) {
let api = localStorage.getItem("AccessToken") ? '/api/personPatch/loginList' : '/api/personPatch/list'
return request({
url: `/api/personPatch/list?sex=${sex}&pageNum=${pageNum}&pageSize=${pageSize}&videoType=${videoType}`,
url: `${api}?sex=${sex}&pageNum=${pageNum}&pageSize=${pageSize}&videoType=${videoType}`,
method: 'get'
})
}
@@ -19,8 +20,9 @@ export function modeListApi(sex, pageNum, pageSize, videoType) {
* @returns data
*/
export function voiceTotalApi() {
let api = localStorage.getItem("AccessToken") ? '/api/voiceMould/loginVoiceTotal' : '/api/voiceMould/voiceTotal'
return request({
url: `api/voiceMould/voiceTotal`,
url: api,
method: 'GET',
})
}
@@ -88,12 +90,32 @@ export function personSCIListApi(pageNum, pageSize) {
* @returns data
*/
export function previewAudioApi(gen_txt, voice_id, voice_style) {
let api = localStorage.getItem("AccessToken") ? '/api/voiceMould/loginPreview' : '/api/voiceMould/hypreview'
return request({
url: `api/voiceMould/preview`,
url: api,
method: 'POST',
data: { gen_txt, voice_id, voice_style }
})
}
/**
* @description 图片检测接口
* @params id
* @returns data
*/
export function checkPhotoApi(data) {
const timestamp = Date.now();
const formData = new FormData();
formData.append('file', data, timestamp + ".png");
return request({
url: '/api/baidu/checkPhoto',
method: 'post',
data: formData,
headers: {
'Content-Type': 'application/form-data',
"Access-Control-Allow-Credentials": true,
}
});
}

/**
* @description 上传阿里云--裁剪后的个人背景图
@@ -173,7 +195,10 @@ export function createVideoApi(id) {
return request({
url: `/api/userVideo/createVideo`,
method: 'post',
data: { id }
data: {
id,
projectType: '2'
}
})
}

@@ -188,3 +213,39 @@ export function getModelDetailByIdApi(id) {
method: 'get'
})
}

/**
* @description:文字判断语种
* @param {number} id
* @return data
*/
export function getLanguageApi(data) {
return request({
url: `/api/VoiceLanguage/getLanguage`,
method: 'POST',
data
})
}

/**
* @description:视频校验
* @param {number} id
* @return data
*/
export function checkVideoApi(id) {
return request({
url: `/api/userVideo/checkVideo?id=${id}`,
method: 'get'
})
}

/**
* @description:扣币
* @return data
*/
export function reduceUserPoinsApi() {
return request({
url: `/api/user/reduceUserPoins`,
method: 'get'
})
}

+ 81
- 0
src/apis/my.js 查看文件

@@ -0,0 +1,81 @@
/*
* @Autor: Chutingting
* @Date: 2023-11-13 14:29:58
* @LastEditors: Chutingting
* @LastEditTime: 2023-11-14 10:48:23
* @Description:
*/
import request from "@/utils/request.js";


/**
* @description 充值订单
* @params
* @returns
*/
export function rechargeListApi(data) {
return request({
url: `/api/productOrder/myPaiedOrders?projectType=${data.projectType}&pageNum=${data.pageNum}&pageSize=${data.pageSize}`,
method: 'get'
})
}

/**
* @description 获取详情
* @params
* @returns
*/
export function getDetailApi(id) {
return request({
url: `/api/userVideo/findById?id=${id}`,
method: 'get'
})
}

/**
* @description 扣币详情
* @params
* @returns
*/
export function coindedApi(data) {
return request({
url: `/api/userVideo/list?videoStatus=5&pageNum=${data.pageNum}&pageSize=${data.pageSize}`,
method: 'get'
})
}

/**
* @description 当前币值
* @params
* @returns
*/
export function getUserPoinsApi() {
return request({
url: `/api/user/getUserPoins`,
method: 'get'
})
}

/**
* @description 充值订单详情
* @params
* @returns
*/
export function findByNumberApi(orderNumber) {
return request({
url: `/api/productOrder/findByNumber?orderNumber=${orderNumber}`,
method: 'get'
})
}

/**
* @description 扣币订单详情
* @params
* @returns
*/
export function findByIdApi(id) {
return request({
url: `/api/userVideo/findById?id=${id}`,
method: 'get'
})
}

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

@@ -1,3 +1,4 @@

import request from "@/utils/request.js";


@@ -52,7 +53,7 @@ export function videoHyApi(id) {
*/
export function checkVideoStatusApi(list) {
return request({
url: `/api/userPhotoVideo/checkVideoStatus?list=${list}`,
url: `/api/userVideo/checkVideoStatus?list=${list}`,
method: 'get'
})
}

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

@@ -8,9 +8,48 @@ import request from "@/utils/request.js";
*/
export function packageInfoApi() {
return request({
url: `/api/user/getPackageInfo`,
url: `/api/product/list_v1?type=2&projectType=2`, // /api/user/getPackageInfo
method: 'get'
})
}

/**
* @description 订单详情
* @params
* @returns
*/
export function orderDetailApi(id) {
return request({
url: `/api/productOrder/findByNumber?orderNumber=${id}`,
method: 'get'
})
}



/**
* @description 创建支付
* @params
* @returns
*/
export function createPayApi(data) {
return request({
url: `/api/productOrder/createPay`,
method: 'post',
data
})
}


/**
* @description 创建支付
* @params
* @returns
*/
export function findStatusApi(data) {
return request({
url: `/api/productOrder/findStatus?orderNumber=${data.orderNumber}&payVendor=${data.payVendor}`,
method: 'get'
})
}


+ 39
- 0
src/apis/pay.js 查看文件

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

/**
* @description:购买金币下单
* @param productId
* @return: data
*/
export function createOrderApi(data) {
return request({
url: `api/productOrder/createOrder`,
method: 'post',
data
})
}

/**
* @description:获取订单数据
* @param data
* @return: data
*/
export function createPayApi(data) {
return request({
url: `api/productOrder/createPay`,
method: 'post',
data
})
}

/**
* @description:获取订单支付状态
* @param orderNumber
* @return: data payStatus 查询支付状态 0:待支付,2:支付中,3:已支付
*/
export function getOrderStatusApi(orderNumber, payVendor) {
return request({
url: `api/productOrder/findStatus?orderNumber=${orderNumber}&payVendor=${payVendor}`,
method: 'get'
})
}

二进制
src/assets/img/alipay.png 查看文件

之前 之后
宽度: 200  |  高度: 200  |  大小: 3.7 KiB

二进制
src/assets/img/gpt.png 查看文件

之前 之后
宽度: 80  |  高度: 80  |  大小: 9.3 KiB

二进制
src/assets/img/weChat.png 查看文件

之前 之后
宽度: 200  |  高度: 200  |  大小: 4.0 KiB

+ 17
- 12
src/components/EditPosition.vue 查看文件

@@ -51,7 +51,7 @@
v-for="(item, index) in materialList.scList"
:key="item.id"
class="scListItem"
:class="showBorderActive == item.id ? 'border' : ''"
:class="scBorderActive == index ? 'border' : ''"
@mousedown.stop="handleDragSc(item, index, $event)"
:style="{
top: item.y / props.proportion + 'px',
@@ -64,7 +64,7 @@
<img id="scListItemImg" draggable="false" :src="item.material" alt="" />
<div ref="box1" class="stretchBox box1"></div>
<div
v-show="showBorderActive == item.id"
v-show="scBorderActive == index"
class="stretchBox box2"
@click="delScListItem(index)"
>
@@ -77,7 +77,7 @@
</div>
<div class="stretchBox box3"></div>
<div
v-show="showBorderActive == item.id"
v-show="scBorderActive == index"
ref="box4"
@mousedown.stop="changeScaleSc(index, $event)"
class="stretchBox box4"
@@ -161,6 +161,7 @@ const virtualStyle = computed(() => {
});
// 拖动盒子
const showBorderActive = ref(-1); //判断显示边框
const scBorderActive = ref('')
watch(
() => props.materialList.virtual.id,
(newValue, oldValue) => {
@@ -223,14 +224,14 @@ function changeScale(event) {
let deltaY = touchStart.pageY - y;
let boxDistance2 = Math.sqrt(deltaX ** 2 + deltaY ** 2);
if (deltaX < 0) {
if (props.materialList.virtual.w < 0.4) {
props.materialList.virtual.w = 0.4;
if (props.materialList.virtual.w < 0.2) {
props.materialList.virtual.w = 0.2;
return;
}
props.materialList.virtual.w = (baseLineScale + boxDistance2) / baseLine;
} else {
if (props.materialList.virtual.w > 1.3) {
props.materialList.virtual.w = 1.3;
if (props.materialList.virtual.w > 2.0) {
props.materialList.virtual.w = 2.0;
return;
}
props.materialList.virtual.w = (baseLineScale - boxDistance2) / baseLine;
@@ -253,8 +254,12 @@ function changeScale(event) {
//#region 素材图逻辑
const handleDragSc = (item, index, event) => {
realImgUrl.value = item.material;
scBorderActive.value= index
showBorderActive.value = item.id;
props.materialList.scList.forEach(res => {
res.activeIndex =''
})
item.activeIndex = item.id
event.preventDefault();
const imageElement = fatherBox.value;
const startX = event.clientX; //保存初始值,避免闪烁
@@ -293,15 +298,15 @@ function changeScaleSc(index, event) {
let deltaY = touchStart.pageY - y;
let boxDistance2 = Math.sqrt(deltaX ** 2 + deltaY ** 2);
if (deltaX < 0) {
if (props.materialList.scList[index].w < 0.4) {
props.materialList.scList[index].w = 0.4;
if (props.materialList.scList[index].w < 0.2) {
props.materialList.scList[index].w = 0.2;
return;
}
props.materialList.scList[index].w =
(baseLineScale + boxDistance2) / baseLine;
} else {
if (props.materialList.scList[index].w > 1.3) {
props.materialList.scList[index].w = 1.3;
if (props.materialList.scList[index].w > 2.0) {
props.materialList.scList[index].w = 2.0;
return;
}
props.materialList.scList[index].w =


+ 42
- 14
src/components/cutImg.vue 查看文件

@@ -63,7 +63,7 @@
// import { VueCropper } from "vue-cropper";
import { ElMessage } from "element-plus/es";
import { ref, reactive, watch } from "vue";
import { awsImgUpload, saveImgApi } from "../apis/createVideo";
import { awsImgUpload, saveImgApi, checkPhotoApi } from "../apis/createVideo";
import { useI18n } from "vue-i18n";

const { locale } = useI18n();
@@ -92,30 +92,58 @@ function myUpload(params) {}
const cropper = ref(null);
const option = reactive({
img: "",
canMove: true,
outputSize: 0.5, //图片质量
info: false, // 裁剪框的大小信息
// outputType: 'jpeg', // 裁剪生成图片的格式
outputType: "png", // 裁剪生成图片的格式
outputType: "png",
canScale: true, // 图片是否允许滚轮缩放
autoCrop: true, // 是否默认生成截图框
fixedBox: false,
original: false,
canMoveBox: true,
autoCrop: true,
// 只有自动截图开启 宽度高度才生效
autoCropWidth: window.innerWidth - 100 + "px", // 默认生成截图框宽度
autoCropHeight: window.innerWidth - 100 + "px", // 默认生成截图框高度
high: true, // 是否按照设备的dpr 输出等比例图片
fixedBox: false, // 固定截图框大小 不允许改变
fixed: false, // 是否开启截图框宽高固定比例
// fixedNumber: [1, 1], // 截图框的宽高比例
full: true, // 是否输出原图比例的截图
canMoveBox: true, // 截图框能否拖动
original: false, // 上传图片按照原始比例渲染
centerBox: true, // 截图框是否被限制在图片里面
centerBox: true,
high: true,
cropData: {},
enlarge: 1,
mode: 'contain',
maxImgSize: 3000,
// limitMinSize: [50, 50],
fixed: false,
// fixedNumber: [2, 1],
fillColor: '',
full: true,
infoTrue: false, // true 为展示真实输出图片宽高 false 展示看到的截图框宽高
mode: "100% auto", // 图片默认渲染方式
// outputSize: 0.5, //图片质量
// info: false, // 裁剪框的大小信息
// // outputType: 'jpeg', // 裁剪生成图片的格式
// outputType: "png", // 裁剪生成图片的格式
// canScale: true, // 图片是否允许滚轮缩放
// autoCrop: true, // 是否默认生成截图框
// autoCropWidth: window.innerWidth - 100 + "px", // 默认生成截图框宽度
// autoCropHeight: window.innerWidth - 100 + "px", // 默认生成截图框高度
// high: true, // 是否按照设备的dpr 输出等比例图片
// fixedBox: false, // 固定截图框大小 不允许改变
// fixed: false, // 是否开启截图框宽高固定比例
// // fixedNumber: [1, 1], // 截图框的宽高比例
// full: true, // 是否输出原图比例的截图
// canMoveBox: true, // 截图框能否拖动
// original: false, // 上传图片按照原始比例渲染
// centerBox: true, // 截图框是否被限制在图片里面
// infoTrue: false, // true 为展示真实输出图片宽高 false 展示看到的截图框宽高
// mode: "100% auto", // 图片默认渲染方式
});
//#region 裁剪图片
const cropperOverData = ref(null);
function sendImgData() {
cropper.value.getCropBlob(async (data) => {
try {
const checkPhotoRes = await checkPhotoApi(data)
if (checkPhotoRes.code !== 200) {
ElMessage.error(checkPhotoRes.message);
return
}
const res = await awsImgUpload(data);
const res2 = await saveImgApi({
type: props.type,


+ 51
- 0
src/components/myLoadingIcon2.vue 查看文件

@@ -0,0 +1,51 @@
<template>
<div class="loadingIcon">
<div>
<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>
</div>
</div>
</template>

<script setup>
import { useI18n } from "vue-i18n";
const { locale } = useI18n();
const lanChange = ref(locale);

const props = defineProps({
isLoading: {
required: false, //是否必传
},
});
</script>
<style lang="scss" scoped>
.loadingIcon {
position: relative;
width: 100%;
height: 60px;
line-height: 60px;
text-align: center;
transform: scale(2);
> div {
position: absolute;
top: 0;
left: 50%;
transform: translateX(-50%);
}
.loadingText {
position: relative;
top: -2px;
left: 4px;
}
}
</style>

+ 59
- 0
src/lang/package/en.ts 查看文件

@@ -51,6 +51,7 @@ export default {
logout: "Logout",
goLogin: "Go and log in",
LanguageChange: "Language switching",
currencyValue: 'Current currency value'
},

// 创作视频
@@ -85,6 +86,7 @@ export default {
comingSoon: "COMING SOON",
material: "Material",
subtitles: "Subtitles",
AItext:"AI Script",
sex: "Sex",
videoRatio: "Video Ratio",
all: "All",
@@ -104,6 +106,11 @@ export default {
tooltip2: "Add Pause",
SubtitlesTip: "Subtitles will be shown here",
subtitlesSwitch: "Subtitles Switch",
inputRequirement:'Please enter your requirements, for example: Please generate a beverage advertisement of 500 words or less',
GeneratedText:'Generated Text',
SmartText:'Smart Text',
copy:'Copy to text',
custom: 'VIP'
},

// 我的视频
@@ -202,6 +209,18 @@ export default {
title: "API Access",
comingSoon: "Coming Soon",
},
cooperate: {
title: 'Partner Access',
api: {
title: 'API Access'
},
privatization: {
title: 'Privatization deployment'
}
},
my: {
title: 'My',
},

signSucceed: {
title: "Confirm your email",
@@ -215,4 +234,44 @@ export default {
goLogin: "Login now",
reSend: "Resend",
},
recharge: {
title: 'Recharge order',
currencyValue: 'Current currency value',
productTitle: 'name',
orderNumber: 'Order No',
payment: 'amount of money',
createTime: 'Creation time',
operate: 'operate',
view: 'view',
detailTitle: 'Recharge Details',
payVendor: 'Payment method',
weChat: 'WeChat',
alipay: 'Alipay',
paymentStr: 'Payment amount',
orderStatus: 'Payment status',
paymentTime: 'Pay time',
close: 'close'
},
coindeduc: {
title: 'Creation Record',
currencyValue: 'Current currency value',
titleList: 'name',
videoPlayUrl: 'Video address',
videoTime: 'Video duration(S)',
costPoints: 'Deduction quantity',
createTime: 'Creation time',
operate: 'operate',
view: 'view',
detailTitle: 'Deduction Details',
second: 'S'
},
store: {
priceRmb: 'original price',
glod: 'currency value',
createOrder: 'BUY NOW',
payType:'Choose payment method',
cancel: 'Cancel',
confirm: 'Confirm',
pay: 'Payment in progress...',
}
};

+ 59
- 0
src/lang/package/zh-cn.ts 查看文件

@@ -52,6 +52,7 @@ export default {
logout: "注销",
goLogin: "登录",
LanguageChange: "语言切换",
currencyValue: '当前币值'
},

// 创作视频
@@ -86,6 +87,7 @@ export default {
BackgroundImage: "背景",
material: "素材",
subtitles: "字幕",
AItext:"AI生成文本",
sex: "性别",
videoRatio: "视频比例",
all: "全部",
@@ -105,6 +107,11 @@ export default {
tooltip2: "添加停顿",
SubtitlesTip: "字幕将在此处展示",
subtitlesSwitch: "字幕开关",
inputRequirement:'请输入您的需求,例如:请生成一个500字以内的饮料广告',
GeneratedText:'生成文本',
SmartText:'智能文本',
copy:'复制到文案',
custom: '私人订制'
},

// 我的视频
@@ -202,6 +209,18 @@ export default {
title: "API 接口",
comingSoon: "敬请期待",
},
cooperate: {
title: '合作商接入',
api: {
title: 'API 接口'
},
privatization: {
title: '私有化部署'
}
},
my: {
title: '我的',
},

signSucceed: {
title: "确认邮箱",
@@ -214,4 +233,44 @@ export default {
goLogin: "即将登录",
reSend: "重新发送",
},
recharge: {
title: '充值订单',
currencyValue: '当前币值',
productTitle: '名称',
orderNumber: '订单号',
payment: '金额',
createTime: '创建时间',
operate: '操作',
view: '查看',
detailTitle: '充值详情',
payVendor: '支付方式',
weChat: '微信',
alipay: '支付宝',
paymentStr: '支付金额',
orderStatus: '支付状态',
paymentTime: '支付时间',
close: '关闭'
},
coindeduc: {
title: '创作记录',
currencyValue: '当前币值',
titleList: '名称',
videoPlayUrl: '视频地址',
videoTime: '视频时长(秒)',
costPoints: '扣币数量',
createTime: '创建时间',
operate: '操作',
view: '查看',
detailTitle: '扣币详情',
second: '秒'
},
store: {
priceRmb: '原价',
glod: '币值',
createOrder: '立即购买',
payType:'选择支付方式',
cancel: '取消',
confirm: '确定',
pay: '支付中...',
}
};

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

@@ -23,39 +23,68 @@
</div>
{{ $t("myCreating.title") }}
</div>
<div class="myRouter-item" @click="showTalkUsDialog = true">
<div class="myRouter-item" @click="router.push('/separation')">
<div class="icon">
<el-icon><i-ep-user /></el-icon>
</div>
{{ $t("userModel.title") }}
</div>
<div class="myRouter-item" @click="showTalkUsDialog = true">
<div class="myRouter-item" @click="router.push('/voiceprint')">
<div class="icon">
<el-icon><i-ep-phone /></el-icon>
</div>
{{ $t("voiceModel.title") }}
</div>

<div class="bottomBtx">
<!-- <div class="bottomBtx"> -->
<div class="myRouter-item" @click="router.push('/myStore')">
<div class="icon">
<el-icon><i-ep-Goods /></el-icon>
</div>
{{ $t("shop.title") }}
</div>
<div class="myRouter-item" @click="router.push('/myAPI')">
<!-- <div class="myRouter-item" @click="router.push('/myAPI')">
<div class="icon">
<el-icon><i-ep-DocumentAdd /></el-icon>
</div>
{{ $t("API.title") }}
</div>
</div>
</div> -->
<el-menu
default-active=""
class="el-menu-vertical-demo"
active-text-color="#ffd04b"
background-color="#000"
text-color="#fff"
>
<el-sub-menu index="1">
<template #title>
<el-icon><location /></el-icon>
<span>{{ $t("cooperate.title") }}</span>
</template>
<el-menu-item-group>
<el-menu-item index="1-1" @click="router.push('/api')">{{ $t("cooperate.api.title") }}</el-menu-item>
<el-menu-item index="1-2" @click="router.push('/privatization')">{{ $t("cooperate.privatization.title") }} </el-menu-item>
</el-menu-item-group>
</el-sub-menu>
<el-sub-menu index="2">
<template #title>
<el-icon><location /></el-icon>
<span>{{ $t("my.title") }}</span>
</template>
<el-menu-item-group>
<el-menu-item index="2-1" @click="router.push('/myRecharge')">{{ $t("recharge.title") }} </el-menu-item>
<el-menu-item index="2-2" @click="router.push('/coindeduc')">{{ $t("coindeduc.title") }} </el-menu-item>
</el-menu-item-group>
</el-sub-menu>
</el-menu>
<!-- </div> -->
</div>
</div>
<!-- 右边显示部分 -->
<div class="rightBox">
<!-- nav栏 -->
<div class="nav">
<div class="navItem">{{ $t("navbar.currencyValue") }}:{{ currentValue }}</div>
<!-- 语言 -->
<el-tooltip
style="cursor: pointer; z-index: 999"
@@ -66,6 +95,7 @@
>
<lang-select class="navItem" />
</el-tooltip>
<div class="navItem" v-if="currentPhone">{{ currentPhone }}</div>
<!-- 登录 -->
<div class="navItem" v-if="!AccessToken" @click="router.push('login')">
{{ $t("navbar.goLogin") }}
@@ -103,6 +133,14 @@ import { useRoute, useRouter } from "vue-router";
import { useI18n } from "vue-i18n";

import { userInfoModules } from "@/store/modules/userInfo";
import { getUserPoinsApi } from '@/apis/my.js'

import {
Document,
Menu as IconMenu,
Location,
Setting,
} from '@element-plus/icons-vue'

const userInfoPinia = userInfoModules();
const route = useRoute();
@@ -162,20 +200,41 @@ function handleOutsideClick() {
appStore.closeSideBar(false);
}

onMounted(() => {});
// 当前币值
const currentValue = ref('')
const currentPhone = localStorage.getItem('phone')
function currentValFn() {
getUserPoinsApi().then(res => {
currentValue.value = res.data
localStorage.setItem('userPoinsVal', res.data)
})
}

onMounted(() => {
currentValFn()
});
//#region 联系我们弹窗
const showTalkUsDialog = ref(false);
const updateShowTalkUsDialog = (newValue: any) => {
showTalkUsDialog.value = newValue;
};
//#endregion -----------------------------------

//#region 页面跳转
function toUserModel() {
// router.push("/userModel");
window.location.href = '/priMakeHtml/dingzhifenshen/index.shtml'
showTalkUsDialog.value = true;
}
//#endregion ------------------------------------
</script>

<!-- 新样式 -->
<style lang="scss" scoped>
.app-wrapper {
width: 1920px;
width: 100%;
display: flex;
overflow: hidden;
}
.Sidebar {
width: 230px;
@@ -194,9 +253,12 @@ const updateShowTalkUsDialog = (newValue: any) => {
.myRouter {
position: relative;
height: calc(100% - 80px);
padding: 130px 20px 0;
padding: 40px 20px 0;
color: #fff;
user-select: none;
// color: #868593;
overflow: auto;
overflow-x: hidden;

.bottomBtx {
position: absolute;
@@ -207,8 +269,7 @@ const updateShowTalkUsDialog = (newValue: any) => {
width: 100%;
height: 50px;
padding-left: 10px;
font-size: 20px;
font-weight: 500;
font-size: 18px;
line-height: 50px;
text-align: center;
cursor: pointer;
@@ -234,7 +295,6 @@ const updateShowTalkUsDialog = (newValue: any) => {
vertical-align: sub;
}
}

&:hover {
// background: rgba(255, 255, 255, 0.2);
color: #000;
@@ -261,7 +321,7 @@ const updateShowTalkUsDialog = (newValue: any) => {
}
}
.rightBox {
width: 1690px;
width: calc(100% - 230px);
// background-color: #000;
.nav {
display: flex;
@@ -280,4 +340,11 @@ const updateShowTalkUsDialog = (newValue: any) => {
}
}
}
.el-menu{
border: none;
:deep .el-sub-menu__title, :deep .el-menu-item{
font-size: 18px;
}

}
</style>

+ 108
- 8
src/router/index.ts 查看文件

@@ -1,4 +1,4 @@
import { createRouter, createWebHashHistory, RouteRecordRaw } from "vue-router";
import { createRouter, createWebHashHistory, RouteRecordRaw, useRoute } from "vue-router";
import { getCurrentInstance } from "vue";

export const Layout = () => import("@/layout/index.vue");
@@ -55,6 +55,42 @@ export const constantRoutes: RouteRecordRaw[] = [
},
},
],
}, // 定制分身
{
path: "/",
component: Layout,
redirect: "/userModel",
children: [
{
path: "userModel",
component: () => import("@/views/userModel/index.vue"),
name: "userModel",
meta: {
title: "userModel",
icon: "homepage",
affix: true,
name: "userModel.title",
},
},
],
}, // 定制声纹
{
path: "/",
component: Layout,
redirect: "/voiceModel",
children: [
{
path: "voiceModel",
component: () => import("@/views/voiceModel/index.vue"),
name: "voiceModel",
meta: {
title: "voiceModel",
icon: "homepage",
affix: true,
name: "voiceModel.title",
},
},
],
}, {
path: "/",
component: Layout,
@@ -75,17 +111,28 @@ export const constantRoutes: RouteRecordRaw[] = [
}, {
path: "/",
component: Layout,
redirect: "/myAPI",
redirect: "/myRecharge",
children: [
{
path: "myAPI",
component: () => import("@/views/myAPI/index.vue"),
name: "myAPI",
path: "/myRecharge",
component: () => import("@/views/my/recharge.vue"),
name: "myRecharge",
meta: {
title: "myAPI",
title: "myRecharge",
icon: "homepage",
affix: true,
name: "API.title",
name: "my.title",
},
},
{
path: "/coindeduc",
component: () => import("@/views/my/coindeduc.vue"),
name: "coindeduc",
meta: {
title: "coindeduc",
icon: "homepage",
affix: true,
name: "my.title",
},
},
],
@@ -108,6 +155,57 @@ export const constantRoutes: RouteRecordRaw[] = [
},
],
},
{
path: "/",
component: Layout,
redirect: "/separation",
children: [
{
path: "/separation",
component: () => import("@/views/separation/index.vue"),
name: "separation",
meta: {
title: "separation",
icon: "homepage",
affix: true,
name: "separation.title",
},
},
{
path: "/voiceprint",
component: () => import("@/views/voiceprint/index.vue"),
name: "voiceprint",
meta: {
title: "voiceprint",
icon: "homepage",
affix: true,
name: "separation.title",
},
},
{
path: "/privatization",
component: () => import("@/views/privatization/index.vue"),
name: "privatization",
meta: {
title: "privatization",
icon: "homepage",
affix: true,
name: "separation.title",
},
},
{
path: "/api",
component: () => import("@/views/api/index.vue"),
name: "api",
meta: {
title: "api",
icon: "homepage",
affix: true,
name: "separation.title",
},
},
],
},

];

@@ -121,7 +219,9 @@ const router = createRouter({
// 2023-5-23 添加平滑滚动 YWQ
scrollBehavior: () => ({ behavior: "smooth", left: 0, top: 0 }),
});

router.beforeEach((to, from) => {
document.title = 'Metavatar-' + (to.query.p || from.query.p || localStorage.getItem("title") || '慧影')
})
/**
* 重置路由
*/


+ 1
- 0
src/store/modules/userInfo.js 查看文件

@@ -13,6 +13,7 @@ export const userInfoModules = defineStore("userInfo", () => {
async function getUserInfo() {
const res = await getUserInfoApi()
userInfo.value = res.data
localStorage.setItem('phone', res.data.phone)
}
// 退出清除用户信息
function loginOut(params) {


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

@@ -2,6 +2,8 @@
export {}
declare global {
const EffectScope: typeof import('vue')['EffectScope']
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']
@@ -268,6 +270,8 @@ import { UnwrapRef } from 'vue'
declare module 'vue' {
interface ComponentCustomProperties {
readonly EffectScope: UnwrapRef<typeof import('vue')['EffectScope']>
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']>


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

@@ -13,6 +13,7 @@ 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']
ElAlert: typeof import('element-plus/es')['ElAlert']
ElButton: typeof import('element-plus/es')['ElButton']
ElDialog: typeof import('element-plus/es')['ElDialog']
ElDropdown: typeof import('element-plus/es')['ElDropdown']
@@ -23,10 +24,19 @@ declare module '@vue/runtime-core' {
ElIcon: typeof import('element-plus/es')['ElIcon']
ElInput: typeof import('element-plus/es')['ElInput']
ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
ElMenu: typeof import('element-plus/es')['ElMenu']
ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
ElMenuItemGroup: typeof import('element-plus/es')['ElMenuItemGroup']
ElOption: typeof import('element-plus/es')['ElOption']
ElPagination: typeof import('element-plus/es')['ElPagination']
ElRadio: typeof import('element-plus/es')['ElRadio']
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
ElSelect: typeof import('element-plus/es')['ElSelect']
ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
ElSwitch: typeof import('element-plus/es')['ElSwitch']
ElTable: typeof import('element-plus/es')['ElTable']
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
ElTooltip: typeof import('element-plus/es')['ElTooltip']
ElUpload: typeof import('element-plus/es')['ElUpload']
GithubCorner: typeof import('./../components/GithubCorner/index.vue')['default']
@@ -49,6 +59,7 @@ declare module '@vue/runtime-core' {
MultiUpload: typeof import('./../components/Upload/MultiUpload.vue')['default']
MyLoading: typeof import('./../components/myLoading.vue')['default']
MyLoadingIcon: typeof import('./../components/myLoadingIcon.vue')['default']
MyLoadingIcon2: typeof import('./../components/myLoadingIcon2.vue')['default']
Pagination: typeof import('./../components/Pagination/index.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
@@ -60,5 +71,6 @@ declare module '@vue/runtime-core' {
}
export interface ComponentCustomProperties {
vInfiniteScroll: typeof import('element-plus/es')['ElInfiniteScroll']
vLoading: typeof import('element-plus/es')['ElLoadingDirective']
}
}

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

@@ -69,12 +69,12 @@ request.interceptors.response.use(
);
return
// 弹出错误
} else if (code != 200) {
} else if (code != 200 && code !== 64001) {
if (code == 500) {
// ElMessage.error("系统异常,请稍后再试");
// ElMessage.error($t('tips.systemException'));
ElMessage.error(
appStore.language == "zh-cn" ? `服务器繁忙,请重试!` : `The server is busy, please try again`
appStore.language == "zh-cn" ? (response.data.languageMessage && response.data.languageMessage['zh-cn']) || `服务器繁忙,请重试!` : (response.data.languageMessage && response.data.languageMessage[appStore.language]) || `The server is busy, please try again`
);
// 其他错误
} else {


+ 141
- 0
src/views/api/demo.html 查看文件

@@ -0,0 +1,141 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
padding: 0;
margin: 0;
}

.page {
padding: 50px
}

h1 {
font-size: 20px;
font-weight: 600;
margin-bottom: 0.8em;
}

p {
margin-bottom: 0.5em;
font-size: 14px;
line-height: 1.6;
}

.table {
margin-top: 50px;
}

.table .table-wrp {
margin: 1em 0 3em;
overflow-x: auto;
max-width: 100%;
}

.table table {
display: table;
width: 100%;
border-collapse: collapse;
border-spacing: 0;
overflow: auto;
font-size: 14px;
}

.table table th {
font-weight: 600;
text-align: left;
border-bottom: 1px solid #888;
padding: 10px 20px;
white-space: nowrap;
color: #888;
}

.table table td {
color: #353535;
text-align: left;
border-bottom: 1px solid #e5e5e5;
padding: 20px 20px;
height: 62px;
box-sizing: border-box;
word-break: normal;
}
.style .code{
background-color: #f9f9fa;
margin: 1em 0;
border-radius: 4px
}
</style>
</head>

<body>
<div class="page">
<!-- 文字 -->
<div class="text">
<h1>概述</h1>
<p>在小程序管理后台开启api加密后,开发者需要对原APl的请求内容 加密 与签名,同时AP的回包内容需要开发者验签 与 解密 。支持的api可参考接口调用。</p>
<p>目前支持以下几种算法,可在MP管理页配置。</p>
</div>
<!-- 表格 -->
<div class="table">
<h1>API请求处理</h1>
<div class="table-wrp">
<table>
<thead>
<tr>
<th>参数</th>
<th>类型</th>
<th>默认值</th>
<th>必填</th>
<th>备注</th>
</tr>
</thead>
<tbody>
<tr>
<td>iv</td>
<td>string</td>
<td></td>
<td>是</td>
<td>初始向量,为16字节base64字符串(解码后为12字节随机字符串)</td>
</tr>
<tr>
<td>data</td>
<td>string</td>
<td></td>
<td>是</td>
<td>加密后的密文,使用base64编码</td>
</tr>
<tr>
<td>authtag</td>
<td>string</td>
<td></td>
<td>是</td>
<td>GCM模式输出的认证信息,使用base64编码</td>
</tr>
</tbody>
</table>
</div>
</div>

<!-- 样式 -->
<div class="style">
<h1>样式</h1>
<div class="code">
<pre class="language-json">
<code>
<span>{</span>
<span>"Sn"</span><span>:</span> <span>"fa05fe1e5bcc79b81ad5ad4b58acf787"</span><span>,</span>
<span>"Key"</span><span>:</span> <span>"otUpngOjU+nVQaWJIC3D/yMLV17RKaP6t4Ot9tbnzLY="</span>
<span>}</span>
</code>
</pre>
</div>
</div>
</div>
</body>

</html>

+ 125
- 0
src/views/api/index.vue 查看文件

@@ -0,0 +1,125 @@
<template>
<div class="page">
<div class="">
<el-menu
default-active="1-1"
class="sidebar"
@open="handleOpen"
@close="handleClose"
>
<el-sub-menu index="1">
<template #title>
<span>开发前必读</span>
</template>
<el-menu-item index="1-1" @click="guide">服务端API签名指南</el-menu-item>
</el-sub-menu>
<el-sub-menu index="2">
<template #title>
<span>开发接口</span>
</template>
<el-menu-item v-for="item in apiMenuList" :key="item.id" :index="item.id" @click="getContent(item.id)">{{ item.name }}</el-menu-item>
</el-sub-menu>
</el-menu>
</div>
<div class="content">
<div v-html="content"></div>
</div>
</div>
</template>

<script setup>
import { getAvailableApiGuideApi, apiMenuApi, getContentApi } from '@/apis/api.js'

const handleOpen = (key, keyPath) => {
console.log(key, keyPath)
if (key === '2') {
getMenu()
}
}
const handleClose = (key, keyPath) => {
console.log(key, keyPath)
}
const content = ref('');
// 签名指南
const guide = () => {
getAvailableApiGuideApi().then(res => {
if(res.code === 200) {
content.value = res.data.content
}
})
}

// 开发接口
const apiMenuList = ref([])
const getMenu = () => {
apiMenuApi().then(res => {
if (res.code === 200) {
apiMenuList.value = res.data
}
})
}
// 详情
const getContent = (id) => {
getContentApi(id).then(res => {
if (res.code === 200) {
content.value = res.data.content || ''
}
})
}

onMounted(() => {
guide()
});
</script>
<style>
.sidebar.el-menu--vertical .el-sub-menu__title:hover {
background-color: #fff !important;
}
.sidebar.el-menu--vertical .el-menu-item:hover {
background-color: #fff !important;
}
</style>
<style lang="scss" scoped>
.page {
display: flex;
width: 100%;
overflow: hidden;
overflow-y: scroll;
background-color: #f5f5f5;
border-radius: 25px 0 0 0;
min-height: calc(100vh - 80px);
// text-align: center;
.title {
font-size: 50px;
}
.sidebar {
position: absolute;
width: 340px;
top: 0;
bottom: 0;
overflow: auto;
padding: 40px 30px;
box-sizing: border-box;
z-index: 1;
}
.content{
position: absolute;
left: 340px;
right: 0;
top: 0;
bottom:0;
background: #fff;
padding: 40px 30px;
overflow: auto;
}
}
:deep(.el-submenu .el-menu:hover) {

background: transparent;

color: #d75b5f;

}


</style>

+ 755
- 148
src/views/createVideo/index.vue
文件差异内容过多而无法显示
查看文件


+ 17
- 8
src/views/login/index.vue 查看文件

@@ -19,7 +19,7 @@
>
<div class="flex text-white items-center">
<span class="flex-1 text-center">{{
$t("login.title") + " " + $t("login.login")
title + " " + $t("login.login")
}}</span>
<el-tooltip
class="box-item"
@@ -136,7 +136,7 @@
>
<div class="flex text-white items-center">
<span class="flex-1 text-center">{{
$t("login.title") + " " + $t("login.register")
title + " " + $t("login.register")
}}</span>
<el-tooltip
class="box-item"
@@ -250,7 +250,7 @@
>
<div class="flex text-white items-center">
<span class="flex-1 text-center">{{
$t("login.title") + " " + $t("login.register")
title + " " + $t("login.register")
}}</span>
<el-tooltip
class="box-item"
@@ -318,7 +318,7 @@
>
<div class="flex text-white items-center">
<span class="flex-1 text-center">{{
$t("login.title") + " " + $t("login.forgetPwdTitle")
title + " " + $t("login.forgetPwdTitle")
}}</span>
<el-tooltip
class="box-item"
@@ -403,7 +403,7 @@
>
<div class="flex text-white items-center">
<span class="flex-1 text-center">{{
$t("login.title") + " " + $t("login.resetPassword")
title + " " + $t("login.resetPassword")
}}</span>
<el-tooltip
class="box-item"
@@ -524,7 +524,7 @@
>
<div class="flex text-white items-center">
<span class="flex-1 text-center">{{
$t("login.title") + " " + $t("login.setNewPwd")
title + " " + $t("login.setNewPwd")
}}</span>
<el-tooltip
class="box-item"
@@ -619,7 +619,7 @@
>
<div class="flex text-white items-center">
<span class="flex-1 text-center">{{
$t("login.title") + " " + $t("login.login")
title + " " + $t("login.login")
}}</span>
<el-tooltip
class="box-item"
@@ -716,7 +716,7 @@
>
<div class="flex text-white items-center">
<span class="flex-1 text-center">{{
$t("login.title") + " " + $t("login.setInvitatioCode")
title + " " + $t("login.setInvitatioCode")
}}</span>
<el-tooltip
class="box-item"
@@ -818,6 +818,15 @@ const currentLan = ref(locale);
const userInfoPinia = userInfoModules();
const route = useRoute();
const router = useRouter();

/**
* 获取页面标题
*/
const title = ref(<string>route.query.p || '慧影')
if (title) {
localStorage.setItem("title", title.value)
document.title = 'Metavatar-' + title.value
}
/**
* 按钮loading
*/


+ 207
- 0
src/views/my/coindeduc.vue 查看文件

@@ -0,0 +1,207 @@
<template>
<div class="page justify-around">
<el-alert :title="`${$t('coindeduc.currencyValue')}:${currentValue}`" type="success" :closable="false" />

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

<el-table-column
prop="videoPlayUrl"
:label="$t('coindeduc.videoPlayUrl')"
align="center"
/>
<el-table-column
prop="videoTime"
:label="$t('coindeduc.videoTime')"
align="center"
/>
<el-table-column
prop="costPoints"
:label="$t('coindeduc.costPoints')"
align="center"
/>
<el-table-column
prop="createTime"
:label="$t('coindeduc.createTime')"
align="center"
>
<template #default="scope">
{{ getDate(scope.row.createDate) }}
</template>
</el-table-column>
<el-table-column
fixed="right"
:label="$t('coindeduc.operate')"
align="center"
>
<template #default="scope">
<el-button link type="primary" size="small" @click="detailView(scope.row)">{{ $t('coindeduc.view') }}</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>
<el-dialog v-model="dialogVisible" :title="`${$t('coindeduc.detailTitle')}:`" width="40%" :before-close="handleClose" >
<el-form :model="form" label-width="120px">
<el-form-item label="名称">
<el-input v-model="form.title" />
</el-form-item>
<el-form-item label="视频类型">
<el-radio-group v-model="form.videoType">
<el-radio :label="1">竖版</el-radio>
<el-radio :label="2">横版</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="文案">
<el-input v-model="form.paperwork" type="textarea" />
</el-form-item>
<el-form-item label="封面图">
<img :src="form.coverImg" alt="" :style="{ width: form.videoType === 1 ? '50%' : '100%'}">
</el-form-item>
<el-form-item label="视频地址">
<el-input v-model="form.videoPlayUrl" />
<!-- <video :src="form.videoPlayUrl" style="width:100%;max-height: 300px;"></video> -->
</el-form-item>
<el-form-item label="视频时长">
<el-input v-model="form.videoTime" />
</el-form-item>
<el-form-item label="创建时间">
<el-input v-model="form.createDate" />
</el-form-item>
<el-form-item label="消耗金币">
<el-input v-model="form.costPoints" />
</el-form-item>
<el-form-item label="消耗金币明细">
<el-input v-model="form.costPointsDetail" />
</el-form-item>
<el-form-item>
<el-button @click="dialogVisible = false">关闭</el-button>
</el-form-item>
</el-form>
</el-dialog>
</div>
</template>

<!-- videoType==1为竖,==2为横 -->
<script setup>
//#region 导入
import { coindedApi, getDetailApi, getUserPoinsApi, findByIdApi } from '@/apis/my.js'
import dayjs from "dayjs";
import { useI18n } from "vue-i18n";
const { locale } = useI18n();
const lanChange = ref(locale);

const tableData = ref([]);

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

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

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

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

const getListData = async (PageNum, PageSize) => {
try {
let data = {
projectType: 2,
pageNum: 1,
pageSize: 10
}
const res = await coindedApi(data);
tableData.value = res.data.list;
total.value = res.data.total * 1;
} catch (error) {
console.log(error, "err");
}
};

// 当前币值
const currentValue = ref('')
function currentValFn() {
getUserPoinsApi().then(res => {
currentValue.value = res.data
})
}

// 查看详情
const dialogVisible = ref(false)
const form = ref({
title: '',
videoPlayUrl: ''

})

function detailView(item) {
findByIdApi(item.id).then(res => {
res.data.createDate = getDate(res.data.createDate)
res.data.videoTime = res.data.videoTime + (lanChange.value == "zh-cn" ? '(秒)' : '(S)')
form.value = res.data
dialogVisible.value = true
})
}

onMounted(() => {
getListData(1, 10);
currentValFn()
});
</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>

+ 193
- 0
src/views/my/recharge.vue 查看文件

@@ -0,0 +1,193 @@
<template>
<div class="page justify-around">
<el-alert :title="`${$t('recharge.currencyValue')}:${currentValue}`" type="success" :closable="false" />

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

<el-table-column
prop="orderNumber"
:label="$t('recharge.orderNumber')"
align="center"
/>
<el-table-column
prop="paymentStr"
:label="$t('recharge.payment')"
align="center"
/>
<el-table-column
prop="createTime"
:label="$t('recharge.createTime')"
align="center"
>
<template #default="scope">
{{ getDate(scope.row.createTime) }}
</template>
</el-table-column>
<el-table-column
fixed="right"
:label="$t('recharge.operate')"
align="center"
>
<template #default="scope">
<el-button link type="primary" size="small" @click="detailView(scope.row)">{{ $t('recharge.view') }}</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>
<el-dialog v-model="dialogVisible" :title="`${ $t('recharge.detailTitle')}:`" width="40%" >
<el-form :model="form" label-width="120px">
<el-form-item :label="$t('recharge.productTitle')">
<el-input v-model="form.productTitle" />
</el-form-item>
<el-form-item :label="$t('recharge.orderNumber')">
<el-input v-model="form.orderNumber" />
</el-form-item>
<el-form-item :label="$t('recharge.payVendor')">
<el-radio-group v-model="form.payVendor">
<el-radio :label="2">{{ $t('recharge.weChat') }}</el-radio>
<el-radio :label="4">{{$t('recharge.alipay')}}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="$t('recharge.paymentStr')">
<el-input v-model="form.paymentStr" />
</el-form-item>
<el-form-item :label="$t('recharge.orderStatus')">
<el-input v-model="form.orderStatus" />
</el-form-item>
<el-form-item :label="$t('recharge.paymentTime')">
<el-input v-model="form.paymentTime" />
</el-form-item>
<el-form-item>
<el-button @click="dialogVisible = false">{{ $t('recharge.close') }}</el-button>
</el-form-item>
</el-form>
</el-dialog>
</div>
</template>

<!-- videoType==1为竖,==2为横 -->
<script setup>
//#region 导入
import { rechargeListApi, getDetailApi, getUserPoinsApi, findByNumberApi } from '@/apis/my.js'
import dayjs from "dayjs";
import { useI18n } from "vue-i18n";
const { locale } = useI18n();
const lanChange = ref(locale);

const tableData = ref([]);

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

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

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

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

const getListData = async (PageNum, PageSize) => {
try {
let data = {
projectType: 2,
pageNum: 1,
pageSize: 10
}
const res = await rechargeListApi(data);
tableData.value = res.data.list;
total.value = res.data.total * 1;
} catch (error) {
console.log(error, "err");
}
};

// 当前币值
const currentValue = ref('')
function currentValFn() {
getUserPoinsApi().then(res => {
currentValue.value = res.data
})
}

// 查看详情
const dialogVisible = ref(false)
const form = ref({
productTitle: '',
orderStatus:'',
paymentTime: '',
})

function detailView(item) {
findByNumberApi(item.id).then(res => {
res.data.paymentTime = getDate(res.data.paymentTime)
res.data.orderStatus = res.data.orderStatus === 3 ? lanChange.value == "zh-cn" ? '支付成功' : 'Payment successful': lanChange.value == "zh-cn" ? '支付失败' : 'Payment failed'
form.value = res.data
dialogVisible.value = true
})
}

onMounted(() => {
getListData(1, 10);
currentValFn()
});
</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>

+ 0
- 22
src/views/myAPI/index.vue 查看文件

@@ -1,22 +0,0 @@
<template>
<div class="page">
<div class="title">{{ $t("API.comingSoon") }}</div>
</div>
</template>
<script setup>
// import { ref } from 'vue'
</script>
<style lang="scss" scoped>
.page {
padding: 30px;
width: 100%;
overflow: hidden;
overflow-y: scroll;
background-color: #fff;
min-height: calc(100vh - 80px);
text-align: center;
.title {
font-size: 50px;
}
}
</style>

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

@@ -481,6 +481,7 @@ const checkVideoStatus = async () => {
// 如果列表中没有生成中的视频,不发送请求
const intervalId = setInterval(async () => {
// && notGenerateList2.value.length == 0;
console.log("");
if (notGenerateList.value.length == 0) {
return;
}
@@ -509,7 +510,7 @@ onMounted(() => {
isLoading.value = true;
getPhotoVideoList(pageNum.value, pageSize.value, title.value);

// checkVideoStatus();
checkVideoStatus();
});
//#endregion ---------------------------
</script>


+ 1152
- 0
src/views/myStore/index copy.vue
文件差异内容过多而无法显示
查看文件


+ 303
- 445
src/views/myStore/index.vue 查看文件

@@ -1,141 +1,48 @@
<template>
<div class="page">
<div class="commoditylIst" ref="scrollContainerRef" @wheel="handleWheel">
<div class="item" v-for="item in packageList" :key="item.typeDesc">
<!-- 遮罩层 -->
<div class="mask" v-if="item.type != 1">
<el-icon><i-ep-Lock /></el-icon>
</div>
<div @click="clickPayDialog(item)" v-if="item.typeDesc">
<div class="line" :style="`background-color:${item.color} ;`"></div>
<div class="info">
<!-- 商品信息 -->
<div class="content">
<div class="titleBox">
<div class="title">
{{ lanChange == "zh-cn" ? item.typeDesc : item.englishName }}
<div class="commoditylIst">
<el-scrollbar :always="true">
<div class="scrollbar-flex-content">
<div class="item" v-for="item in packageList" :key="item.typeDesc" :class="item.sellPriceRmb <= 0 ? 'dashed' : ''">
<!-- @click="clickPayDialog(item)" -->
<div>
<div class="line" :style="`background-color:${ item.sellPriceRmb > 0 ? item.color : '#eee'} ;`"></div>
<div class="info">
<!-- 商品信息 -->
<div class="content">
<div class="titleBox">
<!-- <p class="iconText" v-if="item.sellPriceRmb <= 0" >会员权益</p> -->
<div class="title">
{{ item.title }}
</div>
</div>
<template v-if="item.sellPriceRmb > 0">
<div class="money">
<span class="price">{{
item.sellPriceRmb / 100
}} ¥</span
>/ <span style="text-decoration:line-through;"> {{ $t("store.priceRmb") }}{{ item.priceRmb / 100 }}</span>
</div>
<div class="time">
{{ $t("store.glod") }}<span> {{ item.glod }}</span
>
</div>
<div v-if="item.sellPriceRmb > 0" class="button" @click="clickPayDialog(item)" :style="`background-color: #f3af00 ;`">
{{ $t("store.createOrder") }}
</div>
</template>
</div>
<div class="money">
<span class="price">{{
lanChange == "zh-cn" ? item.rmb + "¥" : item.dollar + "$"
}}</span
>/{{ item.validityDuration }}{{ $t("shop.day") }}
</div>
<div class="time">
<span>{{ item.credit }}</span
>{{ $t("shop.score") }}
</div>
<div
v-if="item.type != 1"
class="button"
:style="`background-color:${item.color} ;`"
>
{{ $t("createVideo.comingSoon") }}
</div>
<div
v-else
class="button"
:style="`background-color:${item.color} ;`"
>
{{ $t("shop.selectPlan") }}
</div>
</div>
<!-- 商品权益 -->
<div class="authority">
<div class="authority-item">
{{ $t("shop.InviteGetscore") }}:

<span>
<i>{{ item.inviteUserCredit }}</i
>{{ $t("shop.score") }}</span
>
</div>
<div class="authority-item">
{{ $t("shop.createVideoPrice") }}:<span
><i>{{ item.videoPrice }}</i
>{{ $t("shop.score") }}</span
>
</div>
<div class="authority-item">
{{ $t("shop.AIGeneratesPhotoPrices") }}:<span
><i>{{ item.photoPrice }}</i
>{{ $t("shop.score") }}</span
>
</div>
<div class="authority-item">
{{ $t("shop.UnitChargeDuration") }}:<span
><i>{{ item.chargeTime }}</i
>{{ $t("shop.second") }}</span
>
</div>

<div class="authority-item">
{{ $t("shop.Language") }}:<span
><i>{{ item.userPackageDetails[0].languageDesc }}</i></span
>
</div>
<div class="authority-item">
{{ $t("shop.sound") }}:<span
><i>{{ item.userPackageDetails[0].soundDesc }}</i></span
>
</div>
<div class="authority-item">
{{ $t("shop.IndividualVideoDuration") }}:<span
><i>{{ item.userPackageDetails[0].videoTime }}</i
>{{ $t("shop.second") }}</span
>
</div>
<div class="authority-item">
{{ $t("shop.Watermark") }}:<span>{{
item.userPackageDetails[0].aiPortrait == 0
? $t("shop.yes")
: $t("shop.no")
}}</span>
</div>
<div class="authority-item">
{{ $t("shop.AIGeneratedPortrait") }}:<span>{{
item.userPackageDetails[0].aiPortrait == 0
? $t("shop.no")
: $t("shop.yes")
}}</span>
</div>
<div class="authority-item">
{{ $t("shop.PhotoSinging") }}:<span>{{
item.userPackageDetails[0].photoSing == 0
? $t("shop.no")
: $t("shop.yes")
}}</span>
</div>
<div class="authority-item">
{{ $t("shop.AIGeneratedText") }}:<span
><i>{{ item.userPackageDetails[0].aiCreateTime }}</i></span
>
</div>
<div class="authority-item">
{{ $t("shop.VideoResolution") }}:<span>{{
item.userPackageDetails[0].resolutionRatioDesc
}}</span>
<!-- 商品权益 -->
<div class="authority">
<div v-html="item.detail"></div>
</div>
<!-- <div class="authority-item">
{{ $t("shop.DigitalPersonTemplate") }}:{{
item.userPackageDetails[0].humanTemplateDesc
}}
</div> -->
<!-- <div
class="authority-item"
v-for="items in item.authority"
:key="items"
>
<span>✔</span>{{ items }}
</div> -->
</div>
</div>
</div>
</div>
</el-scrollbar>
<!-- 企业版 -->
<div class="item" @click="showTalkUsDialog = true">
<!-- 遮罩层 -->
<!-- <div class="item" @click="showTalkUsDialog = true">
<div class="mask" v-if="false">
<el-icon><i-ep-Lock /></el-icon>
</div>
@@ -147,7 +54,6 @@
{{ $t("shop.Ent") }}
</div>
</div>
<!-- 描述 -->
<div class="description">
<div>
{{ lanChange == "zh-cn" ? "所有权限" : "All Pro Benefits" }}
@@ -178,64 +84,68 @@
</div>
</div>
</div>
</div>
</div> -->
</div>
<!-- 对话框 -->
<el-dialog v-if="false" v-model="showPayDialog" width="60%" center>
<!-- 对话框 v-if="false"-->
<el-dialog v-model="showPayDialog" v-if="showPayDialog"
:title="$t('store.payType')" width="300px">
<div class="payDialog">
<div class="left">
<div class="title">{{ $t(presentItme.value.title) }}</div>
<div class="price">
<span>{{ presentItme.value.price }}</span>
元/{{ presentItme.value.priceTime }}
</div>
<div
class="authority"
v-for="item in presentItme.value.authority"
:key="item"
>
{{ item }}
</div>
</div>
<div class="right">
<div
style="background-color: #07c160; cursor: pointer"
@click="showOrderCode(1)"
>
{{ $t("shop.WeChatPay") }}
</div>
<div
style="background-color: #1378fe; cursor: pointer"
@click="showOrderCode(2)"
>
{{ $t("shop.Alipay") }}
</div>
<div
style="background-color: #0070ba; cursor: pointer"
@click="showOrderCode(3)"
>
Paypal
</div>
</div>
<el-radio-group v-model="payVendor">
<el-radio label="4" border>
<img src="../../assets/img/alipay.png" alt="" />{{ $t("recharge.alipay") }}
</el-radio>
<el-radio label="2" border>
<img src="../../assets/img/weChat.png" alt="" />{{ $t("recharge.weChat") }}
</el-radio>
</el-radio-group>
</div>
<!-- 二维码弹出框 -->
<el-dialog
v-model="orderCodeDialogShow"
width="30%"
width="500px"
append-to-body
destroy-on-close
@closed="clearCode"
:close-on-click-modal="false"
>
<div class="orderCodeDialog">
<div class="orderCodeDialog" v-loading="loading"
:element-loading-text="`${$t('store.pay')}`">
<div class="codeImg">
<my-Loading-Icon v-if="!orderCodeUrl"></my-Loading-Icon>
<img v-if="orderCodeUrl" src="../../assets/img/false1.png" alt="" />
<my-Loading-Icon2
v-if="!payCodeUrl && !iframeBody"
></my-Loading-Icon2>
<!-- :callback="qrcode" -->
<vue-qr v-if="payCodeUrl" :text="payCodeUrl" :size="280"></vue-qr>
<iframe
v-show="iframeBody"
id="myIframe"
width="210PX"
height="205PX"
frameborder="0"
></iframe>
</div>
<div class="tips">扫描二维码进行付款</div>
<div class="btnBox">
<div>刷新二维码</div>
<div class="tips">
{{
lanChange == "zh-cn"
? `扫描二维码进行付款`
: `Scan the QR code for payment`
}}
</div>
<!-- <div class="btnBox">
<div @click="RefreshQR">
{{ lanChange == "zh-cn" ? `刷新二维码` : `Refresh QR code` }}
</div>
</div> -->
</div>
</el-dialog>
<template #footer>
<span class="dialog-footer">
<el-button size="small" @click="showPayDialog = false">{{ $t("store.cancel") }}</el-button>
<el-button size="small" type="primary" @click="payConfirm">
{{$t("store.confirm")}}
</el-button>
</span>
</template>
</el-dialog>

<!-- 联系我们对话框 -->
@@ -249,10 +159,14 @@
<script setup>
//#region 导入
import { getCurrentInstance, ref, onMounted } from "vue";
// import { packageInfoApi } from "@/apis/myStore";
import { packageInfoApi } from "@/apis/myStore";
import { useI18n } from "vue-i18n";
import talkUs from "@/components/talkUs.vue";
import { useRoute, useRouter } from "vue-router";
import { createOrderApi, createPayApi, getOrderStatusApi } from "@/apis/pay";
import { orderDetailApi, findStatusApi } from '@/apis/myStore.js'
import vueQr from 'vue-qr/src/packages/vue-qr.vue';

const route = useRoute();
const router = useRouter();
const { locale } = useI18n();
@@ -261,236 +175,33 @@ const lanChange = ref(locale);
const AccessToken = localStorage.getItem("AccessToken"); // 判断有没有登录
//#endregion ------------------------------------

//#region 各个套餐的逻辑
const packageList = ref([
{
id: 1,
type: 1,
typeDesc: "基础版",
englishName: "Trial",
dollar: "0.00",
rmb: "0.00",
credit: 100,
validityDuration: 30,
inviteUserCredit: 10,
videoPrice: 10,
photoPrice: 10,
talkPrice: 20,
chargeTime: 60,
createDate: 1686814258000,
updateDate: 1686814258000,
isDel: 0,
color: "#f3af00",
userPackageDetails: [
{
id: 1,
detailType: 1,
detailTypeDesc: "照片说话",
packageId: 1,
watermark: 1,
watermarkDesc: "是",
language: 1,
languageDesc: "50+",
sound: 1,
soundDesc: "400+",
videoTime: 60,
aiPortrait: 0,
aiPortraitDesc: "否",
photoSing: 0,
photoSingDesc: "否",
aiCreateTime: 0,
resolutionRatio: 1,
resolutionRatioDesc: "720p",
createDate: 1686882177000,
updateDate: 1686882177000,
isDel: 0,
},
{
id: 4,
detailType: 2,
detailTypeDesc: "口播",
packageId: 1,
watermark: 1,
watermarkDesc: "是",
language: 1,
languageDesc: "50+",
sound: 1,
soundDesc: "400+",
videoTime: 60,
aiCreateTime: 0,
resolutionRatio: 1,
resolutionRatioDesc: "720p",
humanTemplate: 1,
humanTemplateDesc: "免费",
createDate: 1686882177000,
updateDate: 1686882177000,
isDel: 0,
},
],
},
{
id: 2,
type: 2,
typeDesc: "专业版",
englishName: "Pro",
dollar: "7.99",
rmb: "49.99",
credit: 200,
validityDuration: 30,
inviteUserCredit: 10,
videoPrice: 6,
photoPrice: 6,
talkPrice: 16,
chargeTime: 60,
createDate: 1686814258000,
updateDate: 1686814258000,
isDel: 0,
color: "#c971ff",
userPackageDetails: [
{
id: 2,
detailType: 1,
detailTypeDesc: "照片说话",
packageId: 2,
watermark: 0,
watermarkDesc: "否",
language: 1,
languageDesc: "50+",
sound: 1,
soundDesc: "400+",
videoTime: 300,
aiPortrait: 1,
aiPortraitDesc: "是",
photoSing: 1,
photoSingDesc: "是",
aiCreateTime: 30,
resolutionRatio: 2,
resolutionRatioDesc: "1080p",
createDate: 1686882177000,
updateDate: 1686882177000,
isDel: 0,
},
{
id: 5,
detailType: 2,
detailTypeDesc: "口播",
packageId: 2,
watermark: 0,
watermarkDesc: "否",
language: 1,
languageDesc: "50+",
sound: 1,
soundDesc: "400+",
videoTime: 300,
aiCreateTime: 100,
resolutionRatio: 2,
resolutionRatioDesc: "1080p",
humanTemplate: 2,
humanTemplateDesc: "VIP",
createDate: 1686882177000,
updateDate: 1686882177000,
isDel: 0,
},
],
},
{
id: 3,
type: 3,
typeDesc: "加强版",
englishName: "Advanced",
dollar: "39.99",
rmb: "279.99",
credit: 1200,
validityDuration: 30,
inviteUserCredit: 10,
videoPrice: 5,
photoPrice: 5,
talkPrice: 15,
chargeTime: 60,
createDate: 1686814258000,
updateDate: 1686814258000,
isDel: 0,
color: "#7b61ff",
userPackageDetails: [
{
id: 3,
detailType: 1,
detailTypeDesc: "照片说话",
packageId: 3,
watermark: 0,
watermarkDesc: "否",
language: 1,
languageDesc: "50+",
sound: 1,
soundDesc: "400+",
videoTime: 300,
aiPortrait: 1,
aiPortraitDesc: "是",
photoSing: 1,
photoSingDesc: "是",
aiCreateTime: 200,
resolutionRatio: 2,
resolutionRatioDesc: "1080p",
createDate: 1686882177000,
updateDate: 1686882177000,
isDel: 0,
},
{
id: 6,
detailType: 2,
detailTypeDesc: "口播",
packageId: 3,
watermark: 0,
watermarkDesc: "否",
language: 1,
languageDesc: "50+",
sound: 1,
soundDesc: "400+",
videoTime: 300,
aiCreateTime: 200,
resolutionRatio: 2,
resolutionRatioDesc: "1080p",
humanTemplate: 2,
humanTemplateDesc: "VIP",
createDate: 1686882177000,
updateDate: 1686882177000,
isDel: 0,
},
],
},
]);

const packageList = ref([]);
async function getPackageList() {
const res = await packageInfoApi();
packageList.value = res.data;
}

const showPayDialog = ref(false); //套餐信息dialog显示隐藏
const presentItme = reactive({}); //点击的套餐项
// const presentItme = ref({}); //点击的套餐项
function clickPayDialog(item) {
presentItme.value = item;
createOrder(item)
showPayDialog.value = true;
}
function showOrderCode(type) {
orderCodeDialogShow.value = true;
}

//#endregion ------------------------------------

//#region 点击套餐内的支付
function showOrderCode(type) {
orderCodeDialogShow.value = true;
myPayVendor.value = type;
createOrderFunc();
}
const orderCodeDialogShow = ref(false);
const orderCodeUrl = ref(null);
//#endregion ------------------------------------

//#region $t在script中的使用
// const {
// appContext: {
// config: { globalProperties },
// },
// } = getCurrentInstance();

// const string = "createVideo.typeScript";
// const t = globalProperties.$t(string);
//#endregion ------------------------------------

//#region 页面滚动
const scrollContainerRef = ref(null);
function handleWheel(event) {
@@ -517,20 +228,191 @@ const updateShowTalkUsDialog = (newValue) => {

//#region 页面初始化
onMounted(async () => {
// getPackageList();
getPackageList();
// createOrderFunc();
});
//#endregion ------------------------------------

//#region
//#region 支付
const myPayVendor = ref(null); // 2微信 4支付宝
const payCodeUrl = ref(null); //付款二维码地址
const payCodeImg = ref(null); //付款二维码图片
// 支付失败处理
function payErrorHandle() {
orderCodeDialogShow.value = false;
ElMessage.error(
lanChange.value == "zh-cn"
? `获取订单失败,请重试`
: `Failed to get the order, please try again`
);
}
// 获取订单
const myOrderNumber = ref(null); //订单号
async function createOrderFunc() {
const data = {
productId: 30,
};
try {
const res = await createOrderApi(data);
if (res.code == 200) {
myOrderNumber.value = res.data;
createPayFunc(res.data);
} else {
payErrorHandle();
}
} catch (error) {
payErrorHandle();
}
}
// 获取订单详情
let iframeBody = ref(null);
const iframeDom = ref(null);
const loading = ref(false)
async function createPayFunc(orderNumber) {
const data = {
orderNumber,
payVendor: payVendor.value,
};
try {
const res = await createPayApi(data);
if (res.code == 200) {
// 支付宝获取iframe内容
if (res.data.body) {
orderCodeDialogShow.value = true;
setTimeout(() => {
iframeBody.value = res.data.body;
iframeDom.value = document.getElementById("myIframe");
iframeDom.value.srcdoc = iframeBody.value;
}, 1000)
}
// 直接获取二维码
if (res.data.codeUrl) {
payCodeUrl.value = res.data.codeUrl;
// showOrderCode(payVendor.value)
orderCodeDialogShow.value = true;
}
// findStatus()
await getStatusOfOrderFunc(orderNumber);
} else {
payErrorHandle();
}
} catch (error) {
payErrorHandle();
}
}
// 获取订单支付状态 payStatus 查询支付状态 0:待支付,2:支付中,3:已支付
async function getStatusOfOrderFunc(orderNumber) {
// if (
// route.path != "/myStore" ||
// orderCodeDialogShow.value == false ||
// orderNumber != payVendor.value
// ) {
// return;
// }
try {
// let payVendor = payVendor.value;
let data = {
orderNumber,
payVendor: payVendor.value
}
const res = await findStatusApi(data);
if (res.code == 200) {
if (res.data.orderStatus == 1) { // 页面就不动,继续定时请求
setTimeout(() => {
getStatusOfOrderFunc(orderNumber);
}, 3000);
} else if (res.data.orderStatus == 2) { // 页面就不动, loading....的效果盖在二维码之前,继续定时请求
loading.value = true
setTimeout(() => {
getStatusOfOrderFunc(orderNumber);
}, 3000);
} else if (res.data.orderStatus == 3) { // 提示支付成功,关闭当前页
orderCodeDialogShow.value = false;
showPayDialog.value = false
ElMessage.success(
lanChange.value == "zh-cn" ? `支付成功!` : `Payment is successful!`
);
} else { // 提示支付失败,关闭当前页
ElMessage.success('支付失败');
}
} else {
setTimeout(() => {
getStatusOfOrderFunc(orderNumber);
}, 3000);
}
} catch (error) {
console.log(error, "error");
ElMessage.error(
lanChange.value == "zh-cn"
? `获取订单失败,请重试`
: `Failed to get the order, please try again`
);
}
}
// 生成二维码
// function qrcode() {
// return;
// }

// 关闭二维码弹窗
function clearCode() {
myPayVendor.value = null; // 2微信 4支付宝
payCodeUrl.value = null;
iframeBody.value = null;
showPayDialog.value = false;
}
// 刷新二维码
function RefreshQR() {
payCodeUrl.value = null;
iframeBody.value = null;
// createOrderFunc();
createPayFunc(myOrderNumber.value);
}
//#endregion ------------------------------------

//#region

//#endregion ------------------------------------
</script>
const payVendor = ref('4')
const orderNumber = ref('')
// 创建订单
function createOrder(item) {
createOrderApi({productId: item.id}).then(res => {
orderNumber.value = res.data
})
}
// 创建支付
function payConfirm() {
createPayFunc(orderNumber.value);
}
// 获取订单详情
function getOrderDetail(item) {
orderDetailApi(item.id).then(res => {
})
}
//每隔一分钟运行一次保存方法
// const timer = setInterval(()=>{
// findStatus()
// },1000)

function findStatus() {
let data = {
orderNumber: '',
payVendor: ''
}
findStatusApi(data).then(res => {
if (res.data !== 2) { // 如果是2就不停的调,直到返回1、3、4
clearInterval(timer);
}
})
}
</script>
<style>
.el-dialog {
border-radius: 5px !important;
}</style>
<style lang="scss" scoped>

.page {
// min-width: calc(100vw - 210px);
height: calc(100vh - 80px);
@@ -552,18 +434,14 @@ onMounted(async () => {
overflow-x: scroll;
padding: 30px 20px 20px 10px;
max-width: 100%;
// height: 75%;
// overflow: hidden;
// overflow-x: scroll;
// scrollbar-width: none; /* 隐藏滚动条(Chrome、Firefox) */
// -ms-overflow-style: none; /* 隐藏滚动条(IE、Edge) */
// &::-webkit-scrollbar {
// display: none; /* 隐藏滚动条(Safari、Chrome) */
// }
.scrollbar-flex-content{
display: flex;
padding-bottom: 30px;
}

.item {
position: relative;
width: 480px;
width: 450px;
// height: 680px;
margin-left: 45px;
background-color: #fffefd;
@@ -573,6 +451,9 @@ onMounted(async () => {
overflow: hidden;
transition: all 0.2s;
cursor: pointer;
&.dashed {
border: 1px dashed #c0bfbd;
}
&:hover {
.mask {
display: block;
@@ -606,10 +487,21 @@ onMounted(async () => {
padding: 20px;
border-bottom: 1px solid #c0bfbd;
cursor: pointer;
position: relative;
.titleBox {
display: flex;
justify-content: space-between;
}
.iconText{
font-size: 14px;
position: absolute;
left:-20px;
top:0;
transform: rotate(-45deg);
background: rgb(243, 175, 0);
padding: 3px 10px;
color: #fff;
}
.title {
font-size: 30px;
font-weight: 700;
@@ -636,7 +528,6 @@ onMounted(async () => {
text-align: end;
.price {
font-size: 30px;
font-weight: 700;
color: #242625;
cursor: pointer;
}
@@ -649,10 +540,10 @@ onMounted(async () => {
cursor: pointer;
margin-bottom: 20px;
span {
font-weight: 700;
color: #242625;
cursor: pointer;
margin-right: 5px;
padding-left: 10px;
}
}

@@ -729,62 +620,29 @@ onMounted(async () => {
}
}
// 支付弹窗
.payDialog {
display: flex;
position: relative;
min-height: 500px;
.left {
width: 35%;
border-right: 1px solid #7c7c7a;
.title {
color: #242625;
font-weight: 700;
font-size: 30px;
text-align: center;
}
.price {
span {
font-size: 30px;
font-weight: 700;
color: #242625;
}
}
.authority {
padding: 10px 20px;
}
}
.right {
width: 65%;
position: absolute;
top: 20%;
right: 0%;
padding-left: 20%;
> div {
width: 200px;
height: 40px;
// border: 1px solid #242625;
border-radius: 10px;
text-align: center;
line-height: 40px;
margin: 30px;
color: #fff;
}
.el-radio{
width: 100px;
img {
vertical-align: middle;
margin-right: 5px;
width: 16px;
}
}

// 二维码弹窗
.orderCodeDialog {
width: 100%;
.codeImg {
display: flex;
margin: auto;
justify-content: space-evenly;
// justify-content: space-evenly;
align-items: center;
width: 300px;
height: 300px;
width: 220PX;
height: 220PX;
border: 1px solid #ccc;
border-radius: 15px;
overflow: hidden;
padding: 10px;
padding: 13px;
img {
width: 100%;
height: 100%;


+ 7
- 0
src/views/privatization/index.vue 查看文件

@@ -0,0 +1,7 @@

<!--
* @Description: 定制分身
-->
<template>
<iframe src="/priMakeHtml/siyouhuabushu/index.shtml" style="width: 100%;height:86vh"></iframe>
</template>

+ 6
- 0
src/views/separation/index.vue 查看文件

@@ -0,0 +1,6 @@
<!--
* @Description: 定制声纹
-->
<template>
<iframe src="/priMakeHtml/dingzhifenshen/index.shtml" style="width: 100%;height:86vh"></iframe>
</template>

+ 944
- 0
src/views/userModel/index.vue 查看文件

@@ -0,0 +1,944 @@
<template>
<div class="page">
<!-- 搜索框 -->
<div class="top">
<div class="search">
<el-input
style="width: 300px"
v-model="title"
:placeholder="$t('myCreating.search')"
@keyup.enter="searchVideoList"
/>
<el-icon class="icon-edit" @click="searchVideoList"
><i-ep-search
/></el-icon>
<!-- 重置按钮 -->
<div v-show="title" class="resetSearch" @click="resetSearch">
{{ $t("myCreating.reset") }}
</div>
</div>
<!-- 更新视频提示 -->
<div class="hasNewVideoTips" :class="hasNewCreate ? '' : 'hasNew'">
{{ $t("myCreating.hasNewVideo") }}
</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, 7, 8, 9, 10, 11, 12].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, item.title)"
>
<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">
<!-- 免费用户1分钟 [5].includes(presentItem.videoStatus)-->
<div
v-if="presentItem.videoPlayUrl && presentItem.videoTime > 300"
class="overtimeTips"
>
<img src="../../assets/img/tips.png" alt="" />
{{ $t("myCreating.freeUserTip") }}
</div>
<video
v-if="presentItem.videoPlayUrl"
controls="true"
class=""
:src="presentItem.videoPlayUrl"
></video>
<div v-else class="insteadVideo">
{{ $t("myCreating." + presentItem.statusName + "Text") }}

<p v-if="lanChange == 'zh-cn' && presentItem.videoStatus == 3">
错误原因: {{ presentItem.videoMsg }}
</p>
<p v-if="lanChange == 'en' && presentItem.videoStatus == 3">
Error cause: {{ presentItem.videoMsg }}
</p>
<!-- <span v-if="presentItem.videoStatus == 3">{{
presentItem.videoMsg
}}</span> -->
</div>
<!-- 有视频路径的页脚 -->
<div class="footer" v-if="presentItem.videoPlayUrl">
<span class="dialog-footer">
<!-- dialog下载按钮 upGrades-->
<button
class="elBtn"
type="primary"
@click.stop="
handleDownload(presentItem.videoPlayUrl, presentItem.title)
"
>
<!-- <el-icon class="icon-delete"><i-ep-download /></el-icon> -->
{{ $t("myCreating.download") }}
</button>
<!-- 提升画质 v-if="presentItem.isHy == 0"-->
<el-tooltip
style="cursor: pointer"
v-if="false"
class="box-item"
effect="light"
:content="$t('myCreating.upSharpnessTips')"
placement="top"
>
<button
style="cursor: pointer"
v-if="presentItem.isHy == 0"
class="elBtn upSharpness"
@click.stop="upGrades(presentItem.id)"
>
<div v-if="!upGradesLoading" style="cursor: pointer">
<img src="../../assets/img/Upgrades.png" alt="" />
{{ $t("myCreating.upSharpness") }}
</div>
<div v-if="upGradesLoading">
<!-- <my-Loading-Icon
class="previewAudioLoadingBox"
v-if="!upGradesLoading"
></my-Loading-Icon> -->
<el-icon class="is-loading" style="font-size: 16px"
><i-ep-Loading
/></el-icon>
</div>
</button>
</el-tooltip>
<!-- 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="[12, 24, 36]"
: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>
//#region 导入
import {
userPhotoVideoListApi,
delUserPhotoVideoByIDApi,
videoHyApi,
checkVideoStatusApi,
} 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";
//#endregion ----------------------
const router = useRouter();
// 当前语言状态与国际化组件
const { locale } = useI18n();
const lanChange = ref(locale);

//#region 老页面逻辑
const title = ref("");
const pageNum = ref(1);
const pageSize = ref(12);
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, name) {
if (itemVideoPlayUrl) {
console.log(1);
let a = document.createElement("a");
a.download = `${name}.mp4`;
a.href = itemVideoPlayUrl;
// 设置下载文件名
a.style.display = "none";
document.body.appendChild(a);
a.click();
a.remove();
ElMessage.success(
lanChange.value == "zh-cn" ? `下载成功` : `Download Successfully`
);
} else {
ElMessage.error(
lanChange.value == "zh-cn" ? `无法下载` : `Unable to download`
);
}
}

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

function resetSearch(params) {
title.value = "";
searchVideoList();
}

// 搜索
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);
});
}
// 升级画质
const upGradesLoading = ref(false);
function upGrades(id) {
if (upGradesLoading.value == true) {
ElMessage.error(
lanChange.value == "zh-cn"
? `正在升级,请稍后~`
: `Upgrading, please wait ~`
);
return;
}
const msg =
lanChange.value == "zh-cn"
? `确定要升级该作品吗?`
: `Are you sure you want to upgrade this work?`;
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(async () => {
upGradesLoading.value = true;
try {
const res = await videoHyApi(id);
ElMessage.success(
lanChange.value == "zh-cn"
? `升级中!请稍等~`
: `Upgrading! Please wait a moment`
);
showDialog.value = false;
upGradesLoading.value = false;
getPhotoVideoList(pageNum.value, pageSize.value, title.value);
} catch (error) {
ElMessage.error(
lanChange.value == "zh-cn"
? `升级失败,请稍后重试`
: `Upgrade failed, please try again later`
);
upGradesLoading.value = false;
}
});
}

/**
* @description:获取我的视频作品
* @return: data
*/
function getPhotoVideoList(pageNum, pageSize, title, searchFlag) {
userPhotoVideoListApi(pageNum, pageSize, title)
.then((res) => {
console.log(res, "res");
notGenerateList.value = [];
// 找到数组中未生成的,放入列表,为了刷新
res.data.list.forEach((item) => {
if ([1, 2, 4, 6, 7, 8, 10, 12].includes(item.videoStatus)) {
notGenerateList.value.push(item.id);
}
});
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) {
delUserPhotoVideoByIDApi(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);
});
}
//#endregion ----------------------

//#region 定时刷新
const hasNewCreate = ref(false); //提示框显示隐藏
const notGenerateList = ref([]); //页面上未生成的视频的id 普通视频
const notGenerateList2 = ref([]); //页面上未生成的视频的id 升级视频
const checkVideoStatus = async () => {
// 如果列表中没有生成中的视频,不发送请求
const intervalId = setInterval(async () => {
// && notGenerateList2.value.length == 0;
console.log("");
if (notGenerateList.value.length == 0) {
return;
}
try {
const res = await checkVideoStatusApi(notGenerateList.value);
// 如果有新的,则提示且更新列表
if (res.code != 2115) {
hasNewCreate.value = true;
const changeHasNewCreate = setTimeout(() => {
hasNewCreate.value = false;
}, 5000);
notGenerateList.value = [];
// notGenerateList2.value = [];
getPhotoVideoList(pageNum.value, pageSize.value, title.value);
}
} catch (error) {}
}, 3000);
onUnmounted(() => {
clearInterval(intervalId);
});
};
//#endregion ---------------------------

//#region 页面初始化
onMounted(() => {
isLoading.value = true;
getPhotoVideoList(pageNum.value, pageSize.value, title.value);

// checkVideoStatus();
});
//#endregion ---------------------------
</script>

<style lang="scss" scoped>
.page {
position: relative;
height: calc(100vh - 80px);
padding: 15px 130px;
background-color: #fff;
border-radius: 25px 0 0;
width: 100%;
overflow: hidden;
overflow-y: auto;
.top {
position: relative;
margin-bottom: 35px;
.search {
display: flex;
justify-content: flex-start;
.resetSearch {
margin-left: 10px;
padding: 0 10px;
height: 30px;
width: 100px;
text-align: center;
line-height: 30px;
background-color: #000;
border: 1px solid #000;
border-radius: 15px;
cursor: pointer;
transition: all 0.3s;
color: #fff;
&:hover {
background-color: #fff;
color: #000;
}
}
}
.hasNewVideoTips {
position: absolute;
top: 0;
left: 50%;
transform: translateX(-50%);
width: 400px;
padding: 5px 30px;
color: #fff;
background-color: #000;
text-align: center;
font-size: 20px;
transition: all 0.5s;
opacity: 1;
border-radius: 15px;
}
.hasNew {
opacity: 0;
transition: all 0.5s;
}
}
.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;
.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;
font-size: 13px;
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%);
}
&.videoUping {
/* 升级中 */
background: linear-gradient(120deg, #4512c7 0%, #4fd334 100%);
}
&.videoUpFailed {
/* HD */
background: linear-gradient(120deg, #ff0019 0%, #ff00c3 100%);
}
&.videoUpSucceed {
/* HD */
background: linear-gradient(120deg, #fdeb71 0%, #d37e1a 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;
.overtimeTips {
// width: 60%;
// display: inline-block;
padding: 5px;
margin-bottom: 10px;
background-color: #ccc;
border-radius: 5px;
line-height: 20px;
color: #000;
text-align: center;
img {
width: 20px;
height: 20px;
vertical-align: middle;
margin-right: 5px;
}
}
video {
width: 100%;
max-height: 600px;
margin: auto;
}
.insteadVideo {
font-size: 20px;
font-weight: 400;
margin: 20px auto;
text-align: center;
}
p {
font-weight: 700;
}
}

.dialog-footer {
display: flex;
justify-content: space-between;
.elBtn {
color: #fff;
border-radius: 10px;
padding: 10px 15px;
cursor: pointer;
background-color: #000;
transition: all 0.3s;
&:hover {
background-color: #15d1b8;
}
}
.upSharpness {
img {
width: 14px;
height: 14px;
}
}
: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>

+ 16
- 0
src/views/userModel/videoStatus.js 查看文件

@@ -0,0 +1,16 @@
/**
* @description:根据状态返回状态名
* @param {number} status
* @return: statusName
*/
export const getStatus = status => {
if (status == 0) {
return "manuscript"
} else if (status == 1 || status == 2 || status == 4 || status == 6) {
return "generating"
} else if (status == 3) {
return "generationFailed"
} else if (status == 5) {
return "generationSucceed"
}
}

+ 7
- 0
src/views/voiceModel/index.vue 查看文件

@@ -0,0 +1,7 @@
<template>
<div></div>
</template>
<script setup>
// import { ref } from 'vue'
</script>
<style lang="scss" scoped></style>

+ 6
- 0
src/views/voiceprint/index.vue 查看文件

@@ -0,0 +1,6 @@
<!--
* @Description: 定制分身
-->
<template>
<iframe src="/priMakeHtml/dingzhishengwen/index.shtml" style="width: 100%;height:86vh"></iframe>
</template>

+ 385
- 334
yarn.lock
文件差异内容过多而无法显示
查看文件


正在加载...
取消
保存