Commits vergleichen

...

66 Commits
master ... dev

Autor SHA1 Nachricht Datum
  chutingting 1940c0b685 Merge branch 'ctt_dev_new' into dev vor 1 Jahr
  chutingting 73400e88e6 edit vor 1 Jahr
  chutingting c496128a43 Merge branch 'ctt_dev_new' into dev vor 1 Jahr
  chutingting 11c06b5258 edit img vor 1 Jahr
  chutingting d86470ba40 Merge branch 'ctt_dev_new' into dev vor 1 Jahr
  chutingting bb406fafdf edit all vor 1 Jahr
  chutingting ac9868188d Merge branch 'ctt_dev_new' into dev vor 1 Jahr
  chutingting 6cc4be4260 edit bug vor 1 Jahr
  chutingting 1ec8bf11af del <<< vor 1 Jahr
  chutingting 35a7d20216 lang vor 1 Jahr
  chutingting 17064ca715 Merge branch 'ctt_dev_new' into dev vor 1 Jahr
  chutingting f2086edbae 中英文 vor 1 Jahr
  chutingting cb7beed615 Merge branch 'ctt_dev_new' into dev vor 1 Jahr
  chutingting d322aad7fe 中英文 vor 1 Jahr
  chutingting 2a275bee1f Merge branch 'ctt_dev_new' into dev vor 1 Jahr
  chutingting ae4c2c001c edit bug vor 1 Jahr
  chutingting 9cba811432 Merge branch 'ctt_dev_new' into dev vor 1 Jahr
  chutingting 4af1793c35 edit bug vor 1 Jahr
  chutingting 80bbe4ad20 关联模版 vor 1 Jahr
  chutingting f66338a09b Merge branch 'ctt_dev_new' into dev vor 1 Jahr
  chutingting a54db920c9 新增用户列表 vor 1 Jahr
  chutingting 2a7e33c08b Merge branch 'ctt_dev_new' into dev vor 1 Jahr
  chutingting c9e452ec73 edit time vor 1 Jahr
  chutingting 049d29513b Merge branch 'ctt_dev_new' into dev vor 1 Jahr
  chutingting 1247c83be3 m模版 vor 1 Jahr
  chutingting e7b1b1dd67 Merge branch 'ctt_dev_new' into dev vor 1 Jahr
  chutingting 1ea2a703fc 查看密钥 vor 1 Jahr
  chutingting a7bbbbde67 Merge branch 'ctt_dev_new' into dev vor 1 Jahr
  chutingting 19d23fd81d 关联模版 vor 1 Jahr
  chutingting 118fe07754 Merge branch 'ctt_dev_new' into dev vor 1 Jahr
  chutingting 5ec876f0d0 edit bug vor 1 Jahr
  chutingting fbd76de8c5 Merge branch 'dev' of https://git.malls.iformall.com/suimang/Metavatar_Neuver_Admin into dev vor 1 Jahr
  chutingting 355081afc9 edit bug vor 1 Jahr
  chutingting c6a78b61bb Merge branch 'ctt_dev_new' of https://git.malls.iformall.com/suimang/Metavatar_Neuver_Admin into ctt_dev_new vor 1 Jahr
  chutingting 8ad90f7ff1 Merge branch 'ctt_dev_new' into dev vor 1 Jahr
  chutingting 0cf09fa32d edit id vor 1 Jahr
  chutingting 63dd0f17b1 私有化 vor 1 Jahr
  chutingting d8021b8534 edit vor 1 Jahr
  chutingting fcce2ac320 格式化数据 vor 1 Jahr
  chutingting 3a6cc2f7f6 视频 vor 1 Jahr
  chutingting 10c02576d9 区分权限 vor 1 Jahr
  chutingting 8f535ec278 个人信息 vor 1 Jahr
  chutingting cc4de57991 api管理 vor 1 Jahr
  HolyKnightIX 0729502903 upload vor 1 Jahr
  HolyKnightIX c5724c8f3a upload vor 1 Jahr
  HolyKnightIX c1c120f295 upload vor 1 Jahr
  HolyKnightIX 0fa58b0e29 1 vor 1 Jahr
  HolyKnightIX fa32adcc87 upload vor 1 Jahr
  HolyKnightIX c26b37a10d Merge branch 'dev_YWQ' into dev vor 1 Jahr
  HolyKnightIX 9aaf01c726 add vor 1 Jahr
  HolyKnightIX 5fde1e9028 Merge branch 'dev_YWQ' into dev vor 1 Jahr
  HolyKnightIX 9a7a2915fc upload vor 1 Jahr
  congzc fedcf416d9 1 vor 1 Jahr
  congzc a9617aecf0 1 vor 1 Jahr
  congzc 18fff628ca Merge branch 'dev' of https://git.malls.iformall.com/suimang/Metavatar_Neuver_Admin into dev vor 1 Jahr
  congzc caf94c1922 Merge remote-tracking branch 'origin/dev_czc' into dev vor 1 Jahr
  congzc 16a2b1a3fa 1 vor 1 Jahr
  HolyKnightIX a7ebf36f25 upload vor 1 Jahr
  HolyKnightIX aac111f7ff 1 vor 1 Jahr
  HolyKnightIX 2cc33377a5 upload vor 1 Jahr
  HolyKnightIX fe636bfa31 add vor 1 Jahr
  congzc 850a644381 Merge branch 'dev' of https://git.malls.iformall.com/suimang/Metavatar_Neuver_Admin into dev vor 1 Jahr
  congzc 57d44bc461 1 vor 1 Jahr
  HolyKnightIX 761197b8d2 upload vor 1 Jahr
  HolyKnightIX c07bcb67c9 upload vor 1 Jahr
  HolyKnightIX bdd6f53bfe upload vor 1 Jahr
65 geänderte Dateien mit 8560 neuen und 3239 gelöschten Zeilen
  1. +4
    -2
      .env.development
  2. +1
    -1
      .env.production
  3. +1
    -1
      .env.test
  4. +1
    -1
      README.md
  5. +1
    -1
      index.html
  6. +1
    -1
      package.json
  7. +52
    -0
      src/api_mangage/business.js
  8. +39
    -0
      src/api_mangage/key.js
  9. +13
    -0
      src/apis/Permission.js
  10. +113
    -0
      src/apis/apiManage.js
  11. +14
    -0
      src/apis/editPass.js
  12. +83
    -0
      src/apis/home.js
  13. +11
    -11
      src/apis/login.js
  14. +1
    -1
      src/apis/myAccount.js
  15. +13
    -0
      src/apis/secretKey.js
  16. +13
    -0
      src/apis/system/userList.js
  17. +14
    -0
      src/apis/template.js
  18. +159
    -0
      src/apis/userManage.js
  19. +198
    -7
      src/lang/package/en.ts
  20. +197
    -6
      src/lang/package/zh-cn.ts
  21. +8
    -0
      src/layout/components/AppMain.vue
  22. +0
    -119
      src/layout/index copy 2.vue
  23. +0
    -131
      src/layout/index copy.vue
  24. +126
    -30
      src/layout/index.vue
  25. +1
    -1
      src/main.ts
  26. +25
    -24
      src/permission.ts
  27. +207
    -36
      src/router/index.ts
  28. +7
    -0
      src/store/modules/userInfo.js
  29. +23
    -4
      src/types/components.d.ts
  30. +0
    -67
      src/utils/request copy.js
  31. +6
    -6
      src/utils/request.js
  32. +5
    -1
      src/utils/request.ts
  33. +304
    -0
      src/views/apiManage/businessCheck.vue
  34. +519
    -0
      src/views/apiManage/index.vue
  35. +88
    -0
      src/views/apiManage/model.vue
  36. +301
    -0
      src/views/business/businessCheck.vue
  37. +351
    -0
      src/views/business/businessList.vue
  38. +2
    -2
      src/views/createVideo/index.vue
  39. +325
    -0
      src/views/dict/components/dict-item.vue
  40. +322
    -0
      src/views/dict/index.vue
  41. +116
    -0
      src/views/editPass/index.vue
  42. +104
    -0
      src/views/home/index.vue
  43. +301
    -0
      src/views/keys/keyCheck.vue
  44. +149
    -0
      src/views/keys/keyList.vue
  45. +75
    -289
      src/views/login/index.vue
  46. +16
    -0
      src/views/mangage/model.vue
  47. +16
    -0
      src/views/mangage/ruleList.vue
  48. +16
    -0
      src/views/mangage/userList.vue
  49. +0
    -698
      src/views/myCreating/index copy.vue
  50. +378
    -0
      src/views/privatization/index.vue
  51. +43
    -0
      src/views/secretKey/index.vue
  52. +124
    -0
      src/views/template/index.vue
  53. +91
    -0
      src/views/userManage/personMould.vue
  54. +146
    -0
      src/views/userManage/personVoice.vue
  55. +207
    -0
      src/views/userManage/rechargeList.vue
  56. +264
    -0
      src/views/userManage/userList.vue
  57. +180
    -0
      src/views/userManage/userMouldList.vue
  58. +188
    -0
      src/views/userManage/userVoiceList.vue
  59. +342
    -0
      src/views/userManage/videoList.vue
  60. +87
    -0
      src/views/userManage/voiceMould.vue
  61. +175
    -0
      src/views/video/index.vue
  62. +16
    -11
      vite.config.ts
  63. +123
    -0
      vite.config.ts.timestamp-1698900171336-585e6054472a3.mjs
  64. +235
    -164
      yarn-error.log
  65. +1619
    -1624
      yarn.lock

+ 4
- 2
.env.development Datei anzeigen

@@ -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
.env.production Datei anzeigen

@@ -5,4 +5,4 @@ NODE_ENV='production'

VITE_APP_TITLE = 'Metavatar-PC'
VITE_APP_PORT = 3000
VITE_APP_BASE_API = 'https://neuver.metavatar.cc/C'
VITE_APP_BASE_API = 'https://neuver.metavatar.cc/A'

+ 1
- 1
.env.test Datei anzeigen

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

+ 1
- 1
README.md Datei anzeigen

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

+ 1
- 1
index.html Datei anzeigen

@@ -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
- 1
package.json Datei anzeigen

@@ -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",
@@ -67,7 +68,6 @@
"stylelint-config-recommended-vue": "^1.4.0",
"stylelint-config-standard": "^32.0.0",
"stylelint-config-standard-scss": "^8.0.0",
"typescript": "^4.9.3",
"unocss": "^0.50.1",
"unplugin-auto-import": "^0.13.0",
"unplugin-icons": "^0.15.1",


+ 52
- 0
src/api_mangage/business.js Datei anzeigen

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

@@ -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/getByServiceId?serviceId=${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 Datei anzeigen

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

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

+ 113
- 0
src/apis/apiManage.js Datei anzeigen

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

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

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

/**
* @description 获取api接入管理列表
* @param {*} (pageNum,pageSize)
* @returns data
*/
export function apiManageListApi(pageNum, pageSize) {
return request({
url: `/serviceInfo/page?type=1pageNum=${pageNum}&pageSize=${pageSize}`,
method: 'get'
})
}

/**
* @description 设置登录账号
* @param {*} data
* @returns data
*/
export function saveMallUserInfo(data) {
return request({
url: `/serviceInfo/saveMallUserInfo`,
method: 'post',
data
})
}

/**
* @description 修改登录账号 详情
* @param {*} data
* @returns data
*/
export function getMallUserInfo(id) {
return request({
url: `/serviceInfo/getMallUserInfo?serviceId=${id}`,
method: 'get'
})
}

/**
* @description 设置时长
* @param {*} data
* @returns data
*/
export function setRemainingTimes(data) {
return request({
url: `/serviceInfo/setRemainingTimes`,
method: 'post',
data
})
}

/**
* @description 所有模版
* @param {*} (pageNum,pageSize)
* @returns data
*/
export function modelAllList(pageNum, pageSize) {
return request({
url: `/personMould/alList?pageNum=${pageNum}&pageSize=${pageSize}`,
method: 'get'
})
}

/**
* @description 已关联模版
* @param {*}
* @returns data
*/
export function personMouldIdList(id) {
return request({
url: `/serviceInfo/personMouldIdList?serviceId=${id || ''}`,
method: 'get'
})
}

/**
* @description 保存关联模版
* @param {*}
* @returns data
*/
export function associatedMould(data) {
return request({
url: `/serviceInfo/associatedMould`,
method: 'post',
data
})
}

+ 14
- 0
src/apis/editPass.js Datei anzeigen

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

/**
* @description 修改密码
* @params userName, pwd
* @returns data
*/
export function updatepwd(data) {
return request({
url: `/user/updatepwd`,
method: 'post',
data
})
}

+ 83
- 0
src/apis/home.js Datei anzeigen

@@ -0,0 +1,83 @@
/*
* @Autor: Chutingting
* @Date: 2023-11-11 19:15:01
* @LastEditors: Chutingting
* @LastEditTime: 2023-11-13 10:28:20
* @Description:
*/
import request from "@/utils/request.js";
/**
* @description:用户角色
* @param
* @return:
*/
export function getUser() {
return request({
url: `/user/getUser`,
method: 'get',
})
}

/**
* @description:用户角色
* @param
* @return:
*/
export function localDeployApi() {
return request({
url: `/localDeploy`,
method: 'get',
})
}


/**
* @description: api 剩余时长
* @param
* @return:
*/
export function current() {
return request({
url: `/serviceInfo/current`,
method: 'get',
})
}

/**
* @description: 私有化 剩余时长
* @param
* @return:
*/
export function privateDeployAdminCurrent() {
return request({
url: `/serviceInfo/privateDeployAdminCurrent`,
method: 'get',
})
}

/**
* @description: 视频制作统计
* @param
* @return:
*/
export function videoListApi(pageNum, pageSize) {
let api = localStorage.getItem("isAdmin") === '0' ? '/serviceInfo/currentVideoRecords' : '/serviceInfo/privateDeployAdminCurrentVideoRecords'
return request({
url: `${api}?pageNum=${pageNum}&pageSize=${pageSize}`,
method: 'get',
})
}

/**
* @description: 已消耗总时长
* @param
* @return:
*/
export function currentVideoToalApi(pageNum) {
let api = localStorage.getItem("isAdmin") === '0' ? '/serviceInfo/currentVideoToal' : '/serviceInfo/privateDeployAdminCurrentVideoTotal'
return request({
url: `${api}`,
method: 'get',
})
}


+ 11
- 11
src/apis/login.js Datei anzeigen

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

const baseURL = import.meta.env.VITE_APP_BASE_API


/**
* @description 注册
* @params email,password
* @description 登录
* @params email,password,code
* @returns data
*/
export function register(data) {
export function loginApi(data) {
return request({
// url: `/api/user/doRegisterByEmail`,
url: `/api/user/doRegisterByPhone`,
// url: `/api/user/loginByEmail`,
url: `/doLogin`,
method: 'post',
data
})
}

/**
* @description 登录
* @description 退出登录
* @params email,password,code
* @returns data
*/
export function login(data) {
export function logoutApi(data) {
return request({
// url: `/api/user/loginByEmail`,
url: `/api/user/login`,
method: 'post',
data
url: `/logout`,
method: 'get'
})
}

@@ -175,5 +175,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 Datei anzeigen

@@ -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/secretKey.js Datei anzeigen

@@ -0,0 +1,13 @@

import request from "@/utils/request.js";
/**
* @description: 密钥查看
* @param
* @return:
*/
export function secretKeyApi() {
return request({
url: `/thirdPartyApi/current`,
method: 'get',
})
}

+ 13
- 0
src/apis/system/userList.js Datei anzeigen

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

+ 14
- 0
src/apis/template.js Datei anzeigen

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

/**
* @description 获取合作商列表
* @param {*} (pageNum,pageSize)
* @returns data
*/
export function templateListApi(pageNum, pageSize) {
let api = localStorage.getItem("isAdmin") === '1' && localStorage.getItem("localDeploy") === 'true' ? '/personMould/alList' : '/personMould/serviceMouldList'
return request({
url: `${api}?pageNum=${pageNum}&pageSize=${pageSize}`,
method: 'get'
})
}

+ 159
- 0
src/apis/userManage.js Datei anzeigen

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

/**
* @description 用户列表
* @param {*} (pageNum,pageSize)
* @returns data
*/
export function userListApi(params) {
return request({
url: `/wxCUserBasicInfo/list`,
method: 'get',
params
})
}
/**
* @description 用户列表-状态
* @param {*}
* @returns
*/
export function updateStatusApi(data) {
return request({
url: `/wxCUserBasicInfo/updateStatus`,
method: 'post',
data
})
}
// 绑定定制模板
export function personMouldListApi(pageNum, pageSize) {
return request({
url: `/personMould/alList?onlyCustomizedQuery=1&pageNum=${pageNum}&pageSize=${pageSize}`,
method: 'get'
})
}
// 绑定定制模板-已关联模版
export function userPersonMouldIdListApi(cUserId) {
return request({
url: `/personMould/userPersonMouldIdList?cUserId=${cUserId}`,
method: 'get'
})
}

// 绑定定制模板-关联模版
export function associatedUserMouldsApi(data) {
return request({
url: `/personMould/associatedUserMoulds`,
method: 'post',
data
})
}
// 绑定定制声纹
export function voiceMouldListApi(pageNum, pageSize) {
return request({
url: `/voiceMould/alList?onlyCustomizedQuery=1&pageNum=${pageNum}&pageSize=${pageSize}`,
method: 'get'
})
}
// 绑定定制声纹-已关联模版
export function userVoiceIdListApi(cUserId) {
return request({
url: `/voiceMould/userVoiceIdList?cUserId=${cUserId}`,
method: 'get'
})
}

// 绑定定制声纹-关联模版
export function associatedUserVoicesApi(data) {
return request({
url: `/voiceMould/associatedUserVoices`,
method: 'post',
data
})
}

/**
* @description 用户列表查看
* @param {*}
* @returns
*/
export function userListFindByIdApi(id) {
return request({
url: `/wxCUserBasicInfo/findById?id=${id}`,
method: 'get'
})
}

/**
* @description 私人定制模板列表
* @param {*} (pageNum,pageSize)
* @returns data
*/
export function userMouldListApi(params) {
return request({
url: `/personMould/userMouldList`,
method: 'get',
params
})
}
/**
* @description 私人定制声纹列表
* @param {*} (pageNum,pageSize)
* @returns data
*/
export function userVoiceListAPi(params) {
return request({
url: `/voiceMould/userVoiceList`,
method: 'get',
params
})
}

/**
* @description 充值列表
* @param {*} (pageNum,pageSize)
* @returns data
*/
export function rechargeListApi(params) {
return request({
url: `/productOrder/paiedOrders`,
method: 'get',
params
})
}

/**
* @description 视频列表
* @param {*} (pageNum,pageSize)
* @returns data
*/
export function videoListApi(params) {
return request({
url: `/userVideo/list`,
method: 'get',
params
})
}

/**
* @description 视频列表-查看
* @param {*}
* @returns
*/
export function videoListFindByIdApi(id) {
return request({
url: `/userVideo/findById?id=${id}`,
method: 'get'
})
}

/**
* @description 视频列表-删除
* @param {*}
* @returns
*/
export function videoListDelApi(id) {
return request({
url: `/userVideo/del?id=${id}`,
method: 'get'
})
}

+ 198
- 7
src/lang/package/en.ts Datei anzeigen

@@ -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",
@@ -51,6 +51,18 @@ export default {
logout: "Logout",
goLogin: "Go and log in",
LanguageChange: "Language switching",
home: 'Home',
apiManage: 'API Access Party Management',
privatization: 'Privatized customer management',
template: 'Template management',
secretKey: 'Key View',
video: 'Video production statistics',
userMange: 'User Management',
userList: 'User List',
userMouldList: 'Private Custom Template List',
userVoiceList: 'Private customized voiceprint list',
rechargeList: 'Recharge List',
videoList: 'Video List'
},

// 创作视频
@@ -203,10 +215,6 @@ export default {
comingSoon: "Coming Soon",
},

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

signSucceed: {
title: "Confirm your email",
succeed: "Sign Succeed !",
@@ -221,6 +229,189 @@ 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",
},
home: {
info: 'Personal Information',
welcome: 'Welcome',
loginAccount: 'Login account',
userName: 'User nickname',
phone: 'Phone',
time: 'Current account duration',
setting: 'security setting',
editPwd: 'Change password',
key: 'secret key',
view: 'View',
},
template: {
img: 'picture'
},
video: {
time: 'Total time consumed',
code: 'Access Party Code',
videoTime: 'Video duration(S)',
videoUrl: 'Video link',
createTime: 'CreateTime',
detail: 'View video details',
},
userList: {
phone: 'phone',
phonePlaceholder: 'Please enter your phone number',
search: 'search',
id: 'user id',
poins: 'Current currency value',
createDate: 'CreateTime',
view: 'View',
rechargeDetail: 'View recharge records',
videoDetail: 'View video list',
personMould: 'Bind custom templates',
personVoice: 'Bind custom voiceprints',
viewDetail: 'Detail',
close: 'Close'
},
personMould: {
cancel: 'Cancel',
confirm: 'Confirm association'
},
personVoice: {
lang: 'language',
country: 'country',
enName: 'English name',
chineseName: 'Chinese name',
cancel: 'Cancel',
confirm: 'Confirm association'
},
rechargeList: {
phone: 'phone',
phonePlaceholder: 'Please enter your phone number',
search: 'search',
productName: 'product name',
productNamePlaceholder: 'Please enter the product name',
time: 'Recharge time period',
orderNumber: 'Order No',
payVendor: 'Payment method',
orderPriceStr: 'Payment amount',
createDate: 'CreateTime'
},
userMouldList: {
phone: 'phone',
phonePlaceholder: 'Please enter your phone number',
search: 'search',
coverImg: 'Cover Image',
mouldSmId: 'Template number',
mouldSmIdPlaceholder: 'Please enter the template number',
bindPhone: 'Bind phone number',
createDate: 'CreateTime'
},
userVoiceList: {
phone: 'phone',
phonePlaceholder: 'Please enter your phone number',
mouldSmId: 'Template number',
mouldSmIdPlaceholder: 'Please enter the template number',
search: 'search',
lang: 'language',
country: 'country',
enName: 'English name',
chineseName: 'Chinese name',
bindPhone: 'Bind phone number',
createDate: 'CreateTime'
},
videoList: {
phone: 'phone',
phonePlaceholder: 'Please enter your phone number',
text: 'text',
textPlaceholder: 'Please enter text',
type: 'type',
typePlaceholder: 'Please select a type',
portrait: 'Portrait',
transversePlate: 'horizontal version',
status: 'status',
statusPlaceholder: 'Please select a status',
notDeleted: 'Not deleted',
deleted: 'Deleted',
time: 'Create time period',
search: 'search',
title: 'Video Title',
coverImg: 'Cover Image',
videoPlayUrl: 'Video address',
videoTime: 'Video duration(S)',
videoSize: 'Video size',
videoMsg: 'Video Generation Information',
costPoints: 'Consumption coins',
costPointsDetail: 'Consumption Gold Coin Details',
createDate: 'CreateTime',
view: 'view',
del: 'delete',
videoDetail: 'Video Details',
name: 'name',
videType: 'Video type',
close: 'Close',
all: 'All'
},
businessCheck: {
detail: 'Key details',
copy: 'copy',
status: 'Key Status',
normal: 'normal',
loseEfficacy: 'lose efficacy',
restore: 'restore',
cancel: 'cancel'
},
editPass: {
username: 'user name',
pass: 'password',
checkPass: 'Confirm Password'
},
apiManage: {
add: 'add',
time: 'Duration (s)',
viewKey: 'View Key',
editAccount: 'Modify login account',
eddAccount: 'Add login account',
setTime: 'Set duration',
associationTemp: 'Association template',
loginAccount: 'Login account',
username: 'user name',
name: 'name',
pass: 'password',
phone: 'phone',
}
};

+ 197
- 6
src/lang/package/zh-cn.ts Datei anzeigen

@@ -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: "立即登录",
@@ -52,6 +52,18 @@ export default {
logout: "注销",
goLogin: "登录",
LanguageChange: "语言切换",
home: '首页',
apiManage: 'API接入方管理',
privatization: '私有化客户管理',
template: '模版管理',
secretKey: '密钥查看',
video: '视频制作统计',
userMange: '用户管理',
userList: '用户列表',
userMouldList: '私人定制模板列表',
userVoiceList: '私人定制声纹列表',
rechargeList: '充值列表',
videoList: '视频列表'
},

// 创作视频
@@ -203,10 +215,6 @@ export default {
comingSoon: "敬请期待",
},

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

signSucceed: {
title: "确认邮箱",
succeed: "注册成功",
@@ -222,4 +230,187 @@ 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 管理",
},
home: {
info: '个人信息',
welcome: '欢迎您',
loginAccount: '登录账号',
userName: '用户昵称',
phone: '手机号',
time: '当前账户时长',
setting: '安全设置',
editPwd: '修改密码',
key: '密钥',
view: '查看',
},
template: {
img: '图片'
},
video: {
time: '已消耗总时长',
code: '接入方编码',
videoTime: '视频时长(秒)',
videoUrl: '视频链接',
createTime: '创建时间',
detail: '查看视频详情',
},
userList: {
phone: '手机号',
phonePlaceholder: '请输入手机号',
search: '查询',
id: '用户ID',
poins: '当前币值',
createDate: '创建时间',
view: '查看',
rechargeDetail: '查看充值记录',
videoDetail: '查看视频列表',
personMould: '绑定定制模版',
personVoice: '绑定定制声纹',
viewDetail: '查看详情',
close: '关闭'
},
personMould: {
cancel: '取消',
confirm: '确认关联'
},
personVoice: {
lang: '语言',
country: '国家',
enName: '英文名称',
chineseName: '中文名称',
cancel: '取消',
confirm: '确认关联'
},
rechargeList: {
phone: '手机号',
phonePlaceholder: '请输入手机号',
search: '查询',
productName: '商品名称',
productNamePlaceholder: '请输入商品名',
time: '充值时间段',
orderNumber: '订单号',
payVendor: '支付方式',
orderPriceStr: '支付金额',
createDate: '创建时间'
},
userMouldList: {
phone: '手机号',
phonePlaceholder: '请输入手机号',
search: '查询',
coverImg: '封面图',
mouldSmId: '模版号',
mouldSmIdPlaceholder: '请输入模版号',
bindPhone: '绑定手机号',
createDate: '创建时间'
},
userVoiceList: {
phone: '手机号',
phonePlaceholder: '请输入手机号',
mouldSmId: '模版号',
mouldSmIdPlaceholder: '请输入模版号',
search: '查询',
lang: '语言',
country: '国家',
enName: '英文名称',
chineseName: '中文名称',
bindPhone: '绑定手机号',
createDate: '创建时间'
},
videoList: {
phone: '手机号',
phonePlaceholder: '请输入手机号',
text: '文本',
textPlaceholder: '请输入文本',
type: '类型',
typePlaceholder: '请选择类型',
portrait: '竖版',
transversePlate: '横版',
status: '状态',
statusPlaceholder: '请选择状态',
notDeleted: '未删除',
deleted: '已删除',
time: '创建时间段',
search: '查询',
title: '视频标题',
coverImg: '封面图',
videoPlayUrl: '视频地址',
videoTime: '视频时长(秒)',
videoSize: '视频大小',
videoMsg: '视频生成信息',
costPoints: '消耗金币',
costPointsDetail: '消耗金币明细',
createDate: '创建时间',
view: '查看',
del: '删除',
videoDetail: '视频详情',
name: '名称',
videType: '视频类型',
close: '关闭',
all: '全部'
},
businessCheck: {
detail: '密钥详情',
copy: '复制',
status: '密钥状态',
normal: '正常',
loseEfficacy: '失效',
restore: '恢复',
cancel: '作废'
},
editPass: {
username: '用户名',
pass: '密码',
checkPass: '确认密码'
},
apiManage: {
add: '新增',
time: '时长(秒)',
viewKey: '查看密钥',
editAccount: '修改登录账号',
eddAccount: '新增登录账号',
setTime: '设置时长',
associationTemp: '关联模版',
loginAccount: '登录账号',
username: '用户名',
name: '名称',
pass: '密码',
phone: '手机号',
}
};

+ 8
- 0
src/layout/components/AppMain.vue Datei anzeigen

@@ -1,3 +1,10 @@
<!--
* @Autor: Chutingting
* @Date: 2023-11-02 11:32:51
* @LastEditors: Chutingting
* @LastEditTime: 2023-11-08 16:06:12
* @Description:
-->
<script setup lang="ts">
import { useTagsViewStore } from "@/store/modules/tagsView";

@@ -23,6 +30,7 @@ const tagsViewStore = useTagsViewStore();
width: 100%;
/* 50= navbar 50 */
min-height: calc(100vh - 80px);
background: #fff;
// overflow: hidden;
// background-color: var(--el-bg-color-page);
// background-color: #000;


+ 0
- 119
src/layout/index copy 2.vue Datei anzeigen

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

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

+ 126
- 30
src/layout/index.vue Datei anzeigen

@@ -11,21 +11,55 @@
</div>
<!-- 侧边路由列表 -->
<div class="myRouter">
<div class="myRouter-item" @click="router.push('/createVideo')">
<div class="icon">
<el-icon><i-ep-edit /></el-icon>
</div>
{{ $t("modelMangage.title") }}
</div>

<div class="bottomBtx">
<div class="myRouter-item" @click="router.push('/myAPI')">
<div class="icon">
<el-icon><i-ep-DocumentAdd /></el-icon>
</div>
{{ $t("apiMangage.title") }}
</div>
</div>
<el-menu
default-active="1"
active-text-color="#ffd04b"
background-color="#000"
text-color="#fff"
class="el-menu-vertical-demo">
<el-menu-item index="1" @click="router.push('/home')">
<el-icon><i-ep-House /></el-icon>
<span>{{ $t('navbar.home') }}</span>
</el-menu-item>
<!-- 邃芒后台 -->
<el-menu-item v-if="isAdmin === '1' && localDeploy !== 'true' " index="2" @click="router.push('/apiManage')">
<el-icon><i-ep-link /></el-icon>
<span>{{ $t('navbar.apiManage') }}</span>
</el-menu-item>
<el-menu-item v-if="isAdmin === '1' && localDeploy !== 'true'" index="3" @click="router.push('/privatization')">
<el-icon><i-ep-edit /></el-icon>
<span>{{ $t('navbar.privatization') }}</span>
</el-menu-item>
<!-- 私有化客户管理 API v-if="(isAdmin === '1' && localDeploy === 'true') || isAdmin === '0'" -->
<template v-else>
<el-menu-item index="4" @click="router.push('/template')">
<el-icon><i-ep-edit /></el-icon>
<span>{{ $t('navbar.template') }}</span>
</el-menu-item>
<el-menu-item index="5" @click="router.push('/secretKey')">
<el-icon><i-ep-edit /></el-icon>
<span>{{ $t('navbar.secretKey') }}</span>
</el-menu-item>
<el-menu-item index="6" @click="router.push('/video')">
<el-icon><i-ep-edit /></el-icon>
<span>{{ $t('navbar.video') }}</span>
</el-menu-item>
</template>
<!-- v-if="isAdmin === '1'" -->
<el-sub-menu index="7" v-if="isAdmin == '1'" >
<template #title>
<el-icon><i-ep-edit /></el-icon>
<span>{{ $t('navbar.userMange') }}</span>
</template>
<el-menu-item-group>
<el-menu-item index="7-1" @click="router.push('/userManage')">{{ $t('navbar.userList') }}</el-menu-item>
<el-menu-item index="7-2" @click="router.push('/userMouldList')">{{ $t('navbar.userMouldList') }}</el-menu-item>
<el-menu-item index="7-3" @click="router.push('/userVoiceList')">{{ $t('navbar.userVoiceList') }}</el-menu-item>
<el-menu-item index="7-4" @click="router.push('/rechargeList')">{{ $t('navbar.rechargeList') }}</el-menu-item>
<el-menu-item index="7-5" @click="router.push('/videoList')">{{ $t('navbar.videoList') }}</el-menu-item>
</el-menu-item-group>
</el-sub-menu>
</el-menu>
</div>
</div>
<!-- 右边显示部分 -->
@@ -43,13 +77,13 @@
<lang-select class="navItem" />
</el-tooltip>
<!-- 登录 -->
<div class="navItem" v-if="!AccessToken" @click="router.push('login')">
<div class="navItem" v-if="!isLogin" @click="router.push('login')">
{{ $t("navbar.goLogin") }}
</div>
<!-- 注销 -->
<div
v-if="isLogin"
class="navItem"
v-if="AccessToken"
@click="logout"
style="margin-left: 10px"
>
@@ -77,8 +111,9 @@ 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";
import { logoutApi } from '@/apis/login.js'

const userInfoPinia = userInfoModules();
const route = useRoute();
@@ -89,6 +124,10 @@ const AccessToken = localStorage.getItem("AccessToken");
// 当前语言状态与国际化组件
const { locale } = useI18n();
const lanChange = ref(locale);
const isLogin = ref(false);
const isAdmin = ref('')
const localDeploy = ref('')

function logout() {
const msg =
(lanChange.value as string) == "zh-cn"
@@ -101,8 +140,11 @@ function logout() {
confirmButtonText: confirm,
cancelButtonText: cancel,
}).then(() => {
userInfoPinia.loginOut();
router.push(`/login`);
logoutApi().then(res => {
userInfoPinia.loginOut();
localStorage.clear()
router.push(`/login`);
})
localStorage.removeItem("AccessToken");
});
}
@@ -138,19 +180,48 @@ function handleOutsideClick() {
appStore.closeSideBar(false);
}

onMounted(() => {});
onMounted(() => {
setTimeout(() => {
isAdmin.value = localStorage.getItem("isAdmin") || ''
localDeploy.value = localStorage.getItem("localDeploy") || ''
}, 500)
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;
if (res.code === 200) {
isLogin.value = true
}
} catch (error) {
console.log(error);
}
}
//#endregion ------------------------------------

//#region 路由及子路由
const showChildrenRouter = ref("");

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



</script>

<!-- 新样式 -->
<style lang="scss" scoped>
.app-wrapper {
width: 1920px;
// width: 1920px;
display: flex;
}
.Sidebar {
@@ -170,8 +241,9 @@ const updateShowTalkUsDialog = (newValue: any) => {
.myRouter {
position: relative;
height: calc(100% - 80px);
padding: 130px 20px 0;
padding: 50px 20px 0;
color: #fff;
width: 230px;
// color: #868593;

.bottomBtx {
@@ -179,10 +251,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 +265,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 +288,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;
@@ -256,4 +345,11 @@ const updateShowTalkUsDialog = (newValue: any) => {
}
}
}
.el-menu{
border: none;
:deep .el-sub-menu__title, :deep .el-menu-item{
font-size: 16px;
}

}
</style>

+ 1
- 1
src/main.ts Datei anzeigen

@@ -17,7 +17,7 @@ import "element-plus/theme-chalk/dark/css-vars.css";
import "@/styles/index.scss";
import "uno.css";
import "@/styles/my.scss"; // 引入自己定义的样式
import 'amfe-flexible';
// import 'amfe-flexible';
import ElementPlus from "element-plus";
// 引入组件
import myLoading from "@/components/myLoading.vue";


+ 25
- 24
src/permission.ts Datei anzeigen

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


+ 207
- 36
src/router/index.ts Datei anzeigen

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

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

{
path: "/",
redirect: "/login",
},
// 登录
{
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 +99,187 @@ 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/apiManage/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",
},
},
],
},
{
path: "/",
component: Layout,
redirect: "/home",
children: [
{
path: "/home",
component: () => import("@/views/home/index.vue"),
name: "home",
meta: {
title: "home",
icon: "home",
affix: true,
name: "ruleListMangage.title",
},
},
{
path: "/apiManage",
component: () => import("@/views/apiManage/index.vue"),
name: "apiManage",
meta: {
title: "apiManage",
icon: "homepage",
affix: true,
name: "ruleListMangage.title",
},
},
{
path: "/privatization",
component: () => import("@/views/privatization/index.vue"),
name: "privatization",
meta: {
title: "privatization",
icon: "homepage",
affix: true,
name: "ruleListMangage.title",
},
},
{
path: "/template",
component: () => import("@/views/template/index.vue"),
name: "template",
meta: {
title: "template",
icon: "homepage",
affix: true,
name: "ruleListMangage.title",
},
},
{
path: "/secretKey",
component: () => import("@/views/secretKey/index.vue"),
name: "secretKey",
meta: {
title: "secretKey",
icon: "homepage",
affix: true,
name: "ruleListMangage.title",
},
},
{
path: "/video",
component: () => import("@/views/video/index.vue"),
name: "video",
meta: {
title: "video",
icon: "homepage",
affix: true,
name: "ruleListMangage.title",
},
},
{
path: "/userManage",
component: () => import("@/views/userManage/userList.vue"),
name: "userManage",
meta: {
title: "userManage",
icon: "homepage",
affix: true,
name: "ruleListMangage.title",
},
},
{
path: "/userMouldList",
component: () => import("@/views/userManage/userMouldList.vue"),
name: "userMouldList",
meta: {
title: "userMouldList",
icon: "homepage",
affix: true,
name: "ruleListMangage.title",
},
},
{
path: "/userVoiceList",
component: () => import("@/views/userManage/userVoiceList.vue"),
name: "userVoiceList",
meta: {
title: "userVoiceList",
icon: "homepage",
affix: true,
name: "ruleListMangage.title",
},
},

{
path: "/rechargeList",
component: () => import("@/views/userManage/rechargeList.vue"),
name: "rechargeList",
meta: {
title: "rechargeList",
icon: "homepage",
affix: true,
name: "ruleListMangage.title",
},
},
{
path: "/videoList",
component: () => import("@/views/userManage/videoList.vue"),
name: "videoList",
meta: {
title: "videoList",
icon: "homepage",
affix: true,
name: "ruleListMangage.title",
},
},
],
}
];

/**


+ 7
- 0
src/store/modules/userInfo.js Datei anzeigen

@@ -1,3 +1,10 @@
/*
* @Autor: Chutingting
* @Date: 2023-11-02 11:32:51
* @LastEditors: Chutingting
* @LastEditTime: 2023-11-08 10:26:54
* @Description:
*/
import { defineStore } from "pinia";
import { store } from "@/store";
import {


+ 23
- 4
src/types/components.d.ts Datei anzeigen

@@ -13,7 +13,12 @@ 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']
ElCard: typeof import('element-plus/es')['ElCard']
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup']
ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
ElDialog: typeof import('element-plus/es')['ElDialog']
ElDropdown: typeof import('element-plus/es')['ElDropdown']
ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
@@ -23,27 +28,40 @@ 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']
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']
ElTag: typeof import('element-plus/es')['ElTag']
ElTooltip: typeof import('element-plus/es')['ElTooltip']
ElUpload: typeof import('element-plus/es')['ElUpload']
GithubCorner: typeof import('./../components/GithubCorner/index.vue')['default']
Hamburger: typeof import('./../components/Hamburger/index.vue')['default']
IconSelect: typeof import('./../components/IconSelect/index.vue')['default']
IEpAvatar: typeof import('~icons/ep/avatar')['default']
IEpCloseBold: typeof import('~icons/ep/close-bold')['default']
IEpCollection: typeof import('~icons/ep/collection')['default']
IEpDelete: typeof import('~icons/ep/delete')['default']
IEpDocumentAdd: typeof import('~icons/ep/document-add')['default']
IEpDownload: typeof import('~icons/ep/download')['default']
IEpEdit: typeof import('~icons/ep/edit')['default']
IEpGoods: typeof import('~icons/ep/goods')['default']
IEpHouse: typeof import('~icons/ep/house')['default']
IEpLink: typeof import('~icons/ep/link')['default']
IEpLoading: typeof import('~icons/ep/loading')['default']
IEpLock: typeof import('~icons/ep/lock')['default']
IEpMenu: typeof import('~icons/ep/menu')['default']
IEpPhone: typeof import('~icons/ep/phone')['default']
IEpPlus: typeof import('~icons/ep/plus')['default']
IEpPointer: typeof import('~icons/ep/pointer')['default']
IEpRefresh: typeof import('~icons/ep/refresh')['default']
IEpSearch: typeof import('~icons/ep/search')['default']
IEpUser: typeof import('~icons/ep/user')['default']
IEpUserFilled: typeof import('~icons/ep/user-filled')['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']
@@ -60,5 +78,6 @@ declare module '@vue/runtime-core' {
}
export interface ComponentCustomProperties {
vInfiniteScroll: typeof import('element-plus/es')['ElInfiniteScroll']
vLoading: typeof import('element-plus/es')['ElLoadingDirective']
}
}

+ 0
- 67
src/utils/request copy.js Datei anzeigen

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

+ 6
- 6
src/utils/request.js Datei anzeigen

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

/**
@@ -27,7 +27,7 @@ const request = axios.create({
request.interceptors.request.use(

function (config) {
// 给所有授权的请求提供token
// // 给所有授权的请求提供token
const AccessToken = localStorage.getItem("AccessToken")
if (AccessToken) {
config.headers.token = AccessToken
@@ -59,8 +59,8 @@ request.interceptors.response.use(
}
let code = response.data.code
// 当token无效(过期或损坏)时 1053为未登录
if (code == 1052 || code == 1053) {
localStorage.removeItem("AccessToken");
if (code == 1052 || code == 1053 || code === 701) {
// localStorage.removeItem("AccessToken");
router.push("/login");
// ElMessage.error("登录过期,请重新登录!");
// ElMessage.error($t('tips.tokenExpired'));
@@ -78,7 +78,7 @@ request.interceptors.response.use(
);
// 其他错误
} else {
return Promise.reject(response.data)
return Promise.reject(response.data.message)
}
} else {
// 正常返回


+ 5
- 1
src/utils/request.ts Datei anzeigen

@@ -21,7 +21,11 @@ service.interceptors.request.use(
return Promise.reject(error);
}
);

declare module 'axios' {
interface AxiosInstance {
(config: AxiosRequestConfig): Promise<any>
}
}
// 响应拦截器
service.interceptors.response.use(
(response: AxiosResponse) => {


+ 304
- 0
src/views/apiManage/businessCheck.vue Datei anzeigen

@@ -0,0 +1,304 @@
<template>
<div class="page flex justify-around">
<div class="card">
<div class="title">{{ $t("businessCheck.detail") }}</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)"
>{{ $t("businessCheck.copy") }}</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)"
>{{ $t("businessCheck.copy") }}</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"
>{{ $t("businessCheck.copy") }}</span
>
</div>
<div class="keyStatus">
<span class="text"
>{{ $t("businessCheck.status") }}:
<span v-if="!keyStatus" style="color: #36db43">{{ $t("businessCheck.normal") }}</span>
<span v-else style="color: #ff0000">{{ $t("businessCheck.loseEfficacy") }}</span>
</span>
<span v-if="keyStatus" class="fail" @click="changeStatus(0)">{{ $t("businessCheck.restore") }}</span>
<span v-if="!keyStatus" class="success" @click="changeStatus(1)"
>{{ $t("businessCheck.cancel") }}</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 detailId = 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");
detailId.value = res.data.id
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 = detailId.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>

+ 519
- 0
src/views/apiManage/index.vue Datei anzeigen

@@ -0,0 +1,519 @@
<template>
<div class="page justify-around">
<div class="addbtn">
<el-button type="primary" @click="dialogVisible = true"><el-icon><i-ep-plus /></el-icon> {{$t('apiManage.add')}}</el-button>
</div>

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

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

<el-table-column
prop="status"
:label="$t('businessMangage.status')"
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')"
align="center"
/>

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

<el-table-column
fixed="right"
:label="$t('keyMangage.operations')"
width="400"
align="center"
>
<template #default="scope">
<el-button
link
type="primary"
size="small"
@click="showDetail(scope.row.id)"
>{{$t('apiManage.viewKey')}}</el-button>
<el-button link type="primary" size="small" @click="loginAccount(scope.row)">{{ scope.row.mallUserInfo ? $t('apiManage.editAccount') : $t('apiManage.eddAccount')}}</el-button>
<el-button link type="primary" size="small" @click="setTime(scope.row.id)">{{$t('apiManage.setTime')}}</el-button>
<el-button link type="primary" size="small" @click="associationTemp(scope.row.id)">{{$t('apiManage.associationTemp')}}</el-button>
</template>
</el-table-column>
</el-table>

<el-dialog
v-model="dialogVisible"
v-if="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
disabled
>
<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>

<!-- 登录账号 -->
<el-dialog v-model="accountDialogVisible" v-if="accountDialogVisible" :title="$t('apiManage.loginAccount')" width="35%" :before-close="handleClose" >
<el-form ref="ruleForm2" label-position="left" label-width="120px" :model="formData2" :rules="rules2">
<el-form-item :label="$t('apiManage.username')" prop="username">
<el-input :disabled="mallUserInfoFlag" v-model="formData2.username" :placeholder="$t('businessMangage.nameInputText')" />
</el-form-item>

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

<el-form-item :label="$t('apiManage.pass')" prop="password">
<el-input v-model="formData2.password" :placeholder="$t('businessMangage.codeInputText')" />
</el-form-item>
<el-form-item :label="$t('apiManage.phone')" prop="phone">
<el-input v-model="formData2.phone" :placeholder="$t('businessMangage.codeInputText')" />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="accountDialogVisible = false">{{
$t("businessMangage.cancel")
}}</el-button>
<el-button type="primary" @click="addAccount(ruleForm2)">
{{ $t("businessMangage.confirm") }}
</el-button>
</span>
</template>
</el-dialog>
<el-dialog v-model="modelDialogVisible" v-if="modelDialogVisible" :title="$t('apiManage.associationTemp')" width="60%" :before-close="handleClose" >
<model :serviceId="serviceId" @close="handleClose"></model>
</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, setRemainingTimes, saveMallUserInfo, getMallUserInfo } from '@/apis/apiManage.js'

import { useI18n } from "vue-i18n";

import dayjs from "dayjs";

import { useRoute, useRouter } from "vue-router";
import model from './model.vue'

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;
getListData(pageNum.value, pageSize.value);
};

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

const getListData = async (PageNum, PageSize) => {
try {
const res = await businessListApi(PageNum, PageSize, 1, route.query.id || '');
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: 1,
});

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;
accountDialogVisible.value = false;
modelDialogVisible.value = false;
setTimeout(() => {
formData.value = {
name: "",
address: "",
code: "",
type: 1,
};
}, 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;
}
getListData(1, 10);
pageNum.value = 1;
pageSize.value = 10;
} catch (error) {
console.log(error, "err");
ElMessage.error(error.message);
}
} else {
ElMessage.error("请完善信息!");
}
});
};

// 设置时长
const setTime = (id) => {
ElMessageBox.prompt('请输入时长(秒)', '设置时长', {
confirmButtonText: 'OK',
cancelButtonText: 'Cancel',
inputPattern: /^[0-9]*$/,
inputErrorMessage: '请输入数字',
beforeClose: async (action, instance, done) => {
if (action == "confirm") {//点击确认请求接口
let res = await setRemainingTimes({ id: id, times: instance.inputValue })
if (res.code === 200) {
// 通过监测关闭
ElMessage.success('设置成功')
done();
} else {
ElMessage.error(res.message)
}
} else {
//点击取消关闭
done();
}
}
})
}


// 登录账号
const accountDialogVisible = ref(false);
const mallUserInfoFlag = ref(false);
const loginAccount = (item) => {
if (item.mallUserInfo) {
getMallUserInfo(item.id).then(res => {
if (res.code === 200) {
formData2.value = {
serviceId: item.id,
username: res.data.username,
name: res.data.name,
password: '',
phone: res.data.phone
};
}
})
} else {
formData2.value.serviceId = item.id
}
mallUserInfoFlag.value = item.mallUserInfo ? true : false
accountDialogVisible.value = true
}
// 登录账号
const formData2 = ref({
serviceId: "",
username: "",
name: "",
password: "",
phone: "",
});

const rules2 = {
name: [
{
required: true,
message: "Please input name",
trigger: "blur",
},
],
username: [
{
required: true,
message: "Please input username",
trigger: "blur",
},
],
password: [
{
required: true,
message: "Please input password",
trigger: "blur",
},
],
phone: [
{
required: true,
message: "Please input phone",
trigger: "blur",
},
],
};

const ruleForm2 = ref();

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

// 关联模版
const modelDialogVisible = ref(false);
const serviceId = ref('')
function associationTemp(id) {
modelDialogVisible.value = true
serviceId.value = id
}

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

+ 88
- 0
src/views/apiManage/model.vue Datei anzeigen

@@ -0,0 +1,88 @@
<template>
<div>
<el-checkbox-group v-model="checkboxGroup" size="small" class="checkbox">
<el-checkbox v-for="(item, index) in tableData" :key="index" :label="item.id" border>
<img :src="item.coverImg" width="50" />
<p>{{ item.title }}</p>
</el-checkbox>
</el-checkbox-group>
<div style="margin-top: 20px">
<el-button @click="handleClose"
>{{ $t('personMould.cancel') }}</el-button
>
<el-button type="primary" @click="addModel()">{{ $t('personMould.confirm') }}</el-button>
</div>
</div>
</template>

<script setup>
import { ref } from 'vue'
import { ElTable } from 'element-plus'
import { modelAllList, personMouldIdList, associatedMould } from '@/apis/apiManage.js'
import dayjs from "dayjs";

const emit = defineEmits(["close"]);
const props = defineProps({
serviceId: {
required: true,
}
});

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

const checkboxGroup = ref([])
const total = ref(0);
const tableData = ref([]);

const modelAllListFunc = async () => {
try {
const res = await modelAllList(1, 10000);
const modelIds = await personMouldIdList(props.serviceId);
tableData.value = res.data.list;
total.value = res.data.total * 1;
setTimeout(()=> {
if(modelIds.data && modelIds.data.length > 0) {
modelIds.data.forEach((item) => {
checkboxGroup.value.push(item)
})
}
}, 500)

} catch (error) {
console.log(error, "err");
}
};

const addModel = async () => {
const data = {
mouldIds: checkboxGroup.value,
serviceId: props.serviceId
}
const res = await associatedMould(data);
if(res.code === 200) {
ElMessage.success("关联成功!");
handleClose()
}
};

function handleClose() {
emit("close");
}
onMounted(() => {
modelAllListFunc(1, 10);
});
</script>

<style lang="scss" scoped>
.checkbox {
max-height: 500px;
overflow: auto;
:deep .el-checkbox.el-checkbox--small {
width: 110px;
height:110px;
margin-bottom: 10px;
}
}
</style>

+ 301
- 0
src/views/business/businessCheck.vue Datei anzeigen

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

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

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

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

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

+ 116
- 0
src/views/editPass/index.vue Datei anzeigen

@@ -0,0 +1,116 @@
<template>
<div class="page">
<el-form
ref="ruleFormRef"
:model="ruleForm"
status-icon
:rules="rules"
label-width="120px"
class="editPass"
>
<el-form-item :label="$t('editPass.username')" prop="pass">
<el-input v-model="ruleForm.userName" disabled autocomplete="off" />
</el-form-item>
<el-form-item :label="$t('editPass.pass')" prop="pass">
<el-input v-model="ruleForm.pass" type="password" autocomplete="off" />
</el-form-item>
<el-form-item :label="$t('editPass.checkPass')" prop="checkPass">
<el-input
v-model="ruleForm.checkPass"
type="password"
autocomplete="off"
/>
</el-form-item>
<el-form-item>
<el-button @click="handleClose(ruleFormRef)">Close</el-button>
<el-button type="primary" @click="submitForm(ruleFormRef)">Submit</el-button>
</el-form-item>
</el-form>
</div>
</template>

<script lang="ts" setup>
import { reactive, ref } from 'vue'
import type { FormInstance, FormRules } from 'element-plus'
import { updatepwd } from "@/apis/editPass.js";
import { logoutApi } from '@/apis/login.js'
import { userInfoModules } from "@/store/modules/userInfo";
import { useRoute, useRouter } from "vue-router";

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

const userInfoPinia = userInfoModules();
const router = useRouter();
const emit = defineEmits(["close"]);

const ruleFormRef = ref<FormInstance>()

const validatePass = (rule: any, value: any, callback: any) => {
if (value === '') {
callback(new Error(lanChange.value == "zh-cn" ? '请输入密码' : 'Please enter the password'))
} else {
if (ruleForm.checkPass !== '') {
if (!ruleFormRef.value) return
ruleFormRef.value.validateField('checkPass', () => null)
}
callback()
}
}
const validatePass2 = (rule: any, value: any, callback: any) => {
if (value === '') {
callback(new Error(lanChange.value == "zh-cn" ? '请重新输入密码' : 'Please re-enter the password'))
} else if (value !== ruleForm.pass) {
callback(new Error(lanChange.value == "zh-cn" ? "两次密码不一致" : 'The two passwords do not match'))
} else {
callback()
}
}

const ruleForm = reactive({
userName: localStorage.getItem("username"),
pass: '',
checkPass: ''
})

const rules = reactive({
pass: [{ validator: validatePass, trigger: 'blur' }],
checkPass: [{ validator: validatePass2, trigger: 'blur' }]
})

const submitForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.validate(async (valid) => {
if (valid) {
const data = {
userName: ruleForm.userName,
pwd: ruleForm.checkPass
};
try {
const res = await updatepwd(data);
if (res.code == 200) {
ElMessage.success( lanChange.value == "zh-cn" ? "修改成功!" : 'Modified successfully!');
logoutApi().then(d => {
userInfoPinia.loginOut();
router.push(`/login`);
})
localStorage.removeItem("AccessToken");
handleClose(ruleFormRef.value)
}
} catch (error) {
console.log(error, "err");
// ElMessage.error(error.message);
}
} else {
console.log('error submit!')
return false
}
})
}
const handleClose = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
emit("close");
}
</script>

+ 104
- 0
src/views/home/index.vue Datei anzeigen

@@ -0,0 +1,104 @@
<template>
<div class="page">
<el-card class="box-card">
<div slot="header" class="clearfix">
<span>{{ $t('home.info') }}</span>
</div>
<div>
<div style="text-align: center">
<div class="el-upload">
<img :src="Avatar" class="avatar">
<p>{{ userData.username }},{{ $t('home.welcome') }}</p>
</div>
</div>
<ul class="user-info">
<li><div style="height: 100%"><el-icon><i-ep-UserFilled /></el-icon> {{ $t('home.loginAccount') }}<div class="user-right">{{ userData.username }}</div></div></li>
<li><el-icon><i-ep-Avatar /></el-icon> {{ $t('home.userName') }} <div class="user-right">{{ userData.name }}</div></li>
<li><el-icon><i-ep-User /></el-icon> {{ $t('home.phone') }} <div class="user-right"> {{ userData.phone }}</div></li>
<li v-if="(userData.isAdmin === 1 && localDeploy) || userData.isAdmin === 0"><el-icon><i-ep-User /></el-icon> {{ $t('home.time') }} <div class="user-right"> {{ userData.remainingTimes }} (秒)</div></li>
<li>
<el-icon><i-ep-edit /></el-icon> {{ $t('home.setting') }}
<div class="user-right">
<a @click="editDialogVisible = true">{{ $t('home.editPwd') }}</a>
</div>
</li>
<!-- <li v-if="userData.isAdmin === '1' && userData.localDeploy">
<el-icon><i-ep-Pointer /></el-icon> 视频制作统计
<div class="user-right">
<a @click="videoDialogVisible = true">查看</a>
</div>
</li> -->
<li v-if="userData.isAdmin === 0">
<el-icon><i-ep-Pointer /></el-icon>{{ $t('home.key') }}
<div class="user-right">
<a @click="router.push('/secretKey')">{{ $t('home.view') }} </a>
</div>
</li>
</ul>
</div>
</el-card>
<el-dialog v-model="editDialogVisible" :title="$t('home.editPwd')" width="40%" :before-close="handleClose" >
<edit-pass @close="handleClose"></edit-pass>
</el-dialog>
</div>
</template>
<script setup>
import editPass from '../editPass/index.vue'
import { useRoute, useRouter } from "vue-router";
import { getUser, privateDeployAdminCurrent, current, localDeployApi } from "@/apis/home.js";
const route = useRoute();
const router = useRouter();
const Avatar = ref('https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png')
const editDialogVisible = ref(false)
const handleClose = () => {
editDialogVisible.value = false;
};

const userData = ref({
username: '',
name: '',
remainingTimes: '',
phone: '',
isAdmin: '',
localDeploy: ''
});
const localDeploy = ref('')
const getData = async () => {
let userRes = await getUser()
let localDeployRes = await localDeployApi()
userData.value = userRes.data
localStorage.setItem("username", userRes.data.username);
localStorage.setItem("isAdmin", userRes.data.isAdmin); // isAdmin=1,为管理人员(邃芒后台) , isAdmin=0,为API接入方登录后台 isAmin=1&&localDeploy=true,就是私有化部署的管理后台
userData.value.localDeploy = localDeployRes.data
localDeploy.value = localDeployRes.data
localStorage.setItem("localDeploy", localDeployRes.data);
// 当前账户时长
let res = userData.isAdmin === 1 && localDeploy ? await privateDeployAdminCurrent() : await current()
userData.value.remainingTimes = res.data.remainingTimes
}

onMounted(async () => {
getData()
});
</script>
<style lang="scss" scoped>
.page{
padding: 30px
}
.user-info {
padding-left: 0;
list-style: none;
li{
border-bottom: 1px solid #F0F3F4;
padding: 11px 0;
font-size: 13px;
}
.user-right {
float: right;
a{
color: #317EF3;
}
}
}
</style>

+ 301
- 0
src/views/keys/keyCheck.vue Datei anzeigen

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

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

+ 75
- 289
src/views/login/index.vue Datei anzeigen

@@ -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() {
@@ -1178,7 +958,7 @@ function resetPwdEmail() {
ticket: route.query.ticket,
});
localStorage.removeItem("AccessToken");
loginData.value.email = route.query.email + "";
// loginData.value.email = route.query.email + "";
loginData.value.password = "";
isLogin.value = 1;
router.push({ path: "login", query: {} });
@@ -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,92 +1150,98 @@ 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("/home");
})
.catch((err) => {
console.log(err, "err");
// 登录失败刷新验证码
getCode();
ElMessage.error(err.message);
ElMessage.error(err);
isLogining.value = false;
if (err.code == 2112) {
reSendEmail(data.email);
}
});
}
//#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 Datei anzeigen

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

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

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

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

+ 378
- 0
src/views/privatization/index.vue Datei anzeigen

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

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

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

<el-table-column
prop="status"
:label="$t('businessMangage.status')"
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')"
align="center"
/>

<el-table-column
prop="createTime"
:label="$t('businessMangage.createTime')"
align="center"
>
<template #default="scope">
{{ getDate(scope.row.createTime) }}
</template>
</el-table-column>
<el-table-column
prop="createTime"
label="时长(秒)"
align="center"
>
<template #default="scope">
{{ scope.row.remainingTimes }}
</template>
</el-table-column>
<el-table-column
fixed="right"
:label="$t('keyMangage.operations')"
width="400"
align="center"
>
<template #default="scope">
<el-button
link
type="primary"
size="small"
@click="showDetail(scope.row.id)"
>查看密钥</el-button>
<el-button link type="primary" size="small" @click="setTime(scope.row.id)">设置时长</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
disabled
>
<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 { businessListApi, addBusinessApi, setRemainingTimes, saveMallUserInfo } from '@/apis/apiManage.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 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;
getListData(pageNum.value, pageSize.value);
};

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

const getListData = async (PageNum, PageSize) => {
try {
const res = await businessListApi(PageNum, PageSize, 2);
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: 2,
});

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: 1,
};
}, 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;
}
getListData(1, 10);
pageNum.value = 1;
pageSize.value = 10;
} catch (error) {
console.log(error, "err");
ElMessage.error(error.message);
}
} else {
ElMessage.error("请完善信息!");
}
});
};

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

// 设置时长
const setTime = (id) => {
ElMessageBox.prompt('请输入时长(秒)', '设置时长', {
confirmButtonText: 'OK',
cancelButtonText: 'Cancel',
inputPattern: /^[0-9]*$/,
inputErrorMessage: '请输入数字',
beforeClose: async (action, instance, done) => {
if (action == "confirm") {//点击确认请求接口
let res = await setRemainingTimes({ id: id, times: instance.inputValue })
if (res.code === 200) {
// 通过监测关闭
ElMessage.success('设置成功')
done();
} else {
ElMessage.error(res.message)
}
} else {
//点击取消关闭
done();
}
}
})
}

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

+ 43
- 0
src/views/secretKey/index.vue Datei anzeigen

@@ -0,0 +1,43 @@
<template>
<el-form :model="form" label-width="120px" class="page">
<el-form-item label="name">
<el-input v-model="form.name" />
</el-form-item>
<el-form-item label="appId">
<el-input v-model="form.appId" />
</el-form-item>
<el-form-item label="appKey">
<el-input v-model="form.appKey" />
</el-form-item>
<el-form-item label="signKey">
<el-input v-model="form.signKey" />
</el-form-item>
</el-form>
</template>
<script lang="ts" setup>
import { reactive } from 'vue'
import { secretKeyApi } from '@/apis/secretKey.js'
const form = ref({
name: '',
appId: '',
appKey: '',
signKey: ''
})
function getSecretKey() {
secretKeyApi().then(res => {
form.value = res.data
})
}
onMounted(() => {
getSecretKey();
});
</script>
<style lang="scss" scoped>
.page{
height: calc(100vh - 80px);
background-color: #ffffff;
border-radius: 30px 0 0 0;
overflow: hidden;
padding: 10vh;
}
</style>

+ 124
- 0
src/views/template/index.vue Datei anzeigen

@@ -0,0 +1,124 @@
<template>
<div class="page justify-around">

<el-table
:data="tableData"
style="width: 100%; height: 90%"
size="large"
align="center"
border
>

<el-table-column :label="$t('template.img')" align="center">
<template #default="scope">
<img :src="scope.row.coverImg" width="50" />
</template>
</el-table-column>
<el-table-column
prop="createTime"
label="创建时间"
align="center"
>
<template #default="scope">
{{ getDate(scope.row.createTime) }}
</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 { templateListApi } from '@/apis/template.js'

import { useI18n } from "vue-i18n";

import dayjs from "dayjs";

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

const route = useRoute();
const router = useRouter();

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");
};

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 {
const res = await templateListApi(PageNum, PageSize);
console.log(res, "res");
tableData.value = res.data.list;
total.value = res.data.total * 1;
} catch (error) {
console.log(error, "err");
}
};
onMounted(() => {
getListData(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>

+ 91
- 0
src/views/userManage/personMould.vue Datei anzeigen

@@ -0,0 +1,91 @@
<template>
<div>
<el-checkbox-group v-model="checkboxGroup" size="small" class="checkbox">
<el-checkbox v-for="(item, index) in tableData" :key="index" :label="item.id" border>
<img :src="item.coverImg" width="50" />
<p>{{ item.title }}</p>
</el-checkbox>
</el-checkbox-group>
<div style="margin-top: 20px">
<el-button @click="handleClose"
>{{$t('personMould.cancel')}}</el-button
>
<el-button type="primary" @click="addModel()">{{$t('personMould.confirm')}}</el-button>
</div>
</div>
</template>

<script setup>
import { ref } from 'vue'
import { personMouldListApi, userPersonMouldIdListApi, associatedUserMouldsApi } from '@/apis/userManage.js'
import dayjs from "dayjs";
import { useI18n } from "vue-i18n";
const { locale } = useI18n();
const lanChange = ref(locale);

const emit = defineEmits(["close"]);
const props = defineProps({
cUserId: {
required: true,
}
});

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

const checkboxGroup = ref([])
const total = ref(0);
const tableData = ref([]);
const modelAllListFunc = async () => {
try {
const res = await personMouldListApi(1, 10000);
const modelIds = await userPersonMouldIdListApi(props.cUserId);
tableData.value = res.data.list;
total.value = res.data.total * 1;
setTimeout(()=> {
if(modelIds.data && modelIds.data.length > 0) {
modelIds.data.forEach((item) => {
checkboxGroup.value.push(item)
let set = new Set(checkboxGroup.value)
checkboxGroup.value = Array.from(set)
})
}
}, 500)

} catch (error) {
console.log(error, "err");
}
};

const addModel = async () => {
const data = {
mouldIds: checkboxGroup.value,
userId: props.cUserId
}
const res = await associatedUserMouldsApi(data);
if(res.code === 200) {
ElMessage.success((lanChange.value) == "zh-cn" ? "关联成功!" : 'Successfully associated!');
handleClose()
}
};

function handleClose() {
emit("close");
}
onMounted(() => {
modelAllListFunc(1, 10);
});
</script>

<style lang="scss" scoped>
.checkbox {
max-height: 500px;
overflow: auto;
:deep .el-checkbox.el-checkbox--small {
width: 110px;
height:110px;
margin-bottom: 10px;
}
}
</style>

+ 146
- 0
src/views/userManage/personVoice.vue Datei anzeigen

@@ -0,0 +1,146 @@
<template>
<el-table
ref="multipleTableRef"
:data="tableData"
style="width: 100%"
border
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" width="55" align="center"/>
<el-table-column property="language" :label="$t('personVoice.lang')" align="center"/>
<el-table-column property="country" :label="$t('personVoice.country')" align="center"/>
<el-table-column property="name" :label="$t('personVoice.enName')" align="center"/>
<el-table-column property="chineseName" :label="$t('personVoice.chineseName')" align="center"/>
<el-table-column
prop="createTime"
:label="$t('businessMangage.createTime')"
align="center">
<template #default="scope">
{{ getDate(scope.row.createDate) }}
</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"
:total="total"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
<div style="margin-top: 20px">
<el-button @click="handleClose"
>取消</el-button
>
<el-button type="primary" @click="addModel()">确认关联</el-button>
</div>
</template>

<script setup>
import { voiceMouldListApi, userVoiceIdListApi, associatedUserVoicesApi } from '@/apis/userManage.js'
import dayjs from "dayjs";
import { useI18n } from "vue-i18n";
const { locale } = useI18n();
const lanChange = ref(locale);
const emit = defineEmits(["close"]);
const props = defineProps({
cUserId: {
required: true,
}
});

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

const multipleTableRef = ref()
const multipleSelection = ref([])
const toggleSelection = (rows) => {
if (rows) {
rows.forEach((row) => {
// TODO: improvement typing when refactor table
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
multipleTableRef.value.toggleRowSelection(row, undefined)
})
} else {
multipleTableRef.value.clearSelection()
}
}
const handleSelectionChange = (val) => {
multipleSelection.value = val
}
const pageNum = ref(1);
const pageSize = ref(10);
const total = ref(0);
const tableData = ref([]);

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

const handleCurrentChange = (val) => {
pageNum.value = val;
modelAllListFunc(pageNum.value, pageSize.value);
};
const modelAllListFunc = async (PageNum, PageSize) => {
try {
const res = await voiceMouldListApi(PageNum, 10000);
const modelIds = await userVoiceIdListApi(props.cUserId);
let idIndx = []
if(modelIds.data && modelIds.data.length > 0) {
res.data.list.forEach((ele, idx) => {
modelIds.data.forEach((item) => {
if (ele.id === item) {
idIndx.push(idx)
}
})
})
}
tableData.value = res.data.list;
total.value = res.data.total * 1;
// 选中关联模版
if(idIndx.length) {
setTimeout(()=> {
let list = []
idIndx.forEach(d => {
list.push(tableData.value[d])
})
toggleSelection(list)
}, 500)
}
} catch (error) {
console.log(error, "err");
}
};

const addModel = async () => {
console.log(multipleSelection.value)
let mouldIds = []
multipleSelection.value.forEach(res => {
mouldIds.push(res.id)
})
const data = {
voiceLanguageIdList: mouldIds,
userId: props.cUserId
}
const res = await associatedUserVoicesApi(data);
if(res.code === 200) {
ElMessage.success((lanChange.value) == "zh-cn" ? "关联成功!" : 'Successfully associated!');
handleClose()
}
};
function handleClose() {
emit("close");
}
onMounted(() => {
modelAllListFunc(1, 10);
});
</script>

+ 207
- 0
src/views/userManage/rechargeList.vue Datei anzeigen

@@ -0,0 +1,207 @@
<template>
<div class="page justify-around">
<div class="addbtn">
<el-form :inline="true" :model="formInline" class="demo-form-inline">
<el-form-item :label="$t('rechargeList.phone')">
<el-input v-model="formInline.phone" :placeholder="$t('rechargeList.phonePlaceholder')" clearable />
</el-form-item>
<el-form-item :label="$t('rechargeList.productName')">
<el-input v-model="formInline.productTitle" :placeholder="$t('rechargeList.productNamePlaceholder')" clearable />
</el-form-item>
<el-form-item :label="$t('rechargeList.time')">
<el-date-picker
v-model="formInline.time"
type="datetimerange"
start-placeholder="Start Date"
end-placeholder="End Date"
value-format="YYYY-MM-DD HH:mm:ss"
:default-time="defaultTime"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="getListData()">{{ $t('rechargeList.search') }}</el-button>
</el-form-item>
</el-form>
</div>
<el-table
:data="tableData"
style="width: 100%; height: 90%"
size="large"
align="center"
border
>
<el-table-column
prop="orderNumber"
:label="$t('rechargeList.orderNumber')"
align="center"
/>
<el-table-column
prop="productTitle"
:label="$t('rechargeList.productName')"
align="center"
/>
<el-table-column
prop="payVendor"
:label="$t('rechargeList.payVendor')"
align="center"
>
<template #default="scope">
{{ getPayVendor(scope.row.payVendor) }}
</template>
</el-table-column>
<el-table-column
prop="orderPriceStr"
:label="$t('rechargeList.orderPriceStr')"
align="center"
/>
<el-table-column
prop="phone"
:label="$t('rechargeList.phone')"
align="center"
>
<template #default="scope">
{{ scope.row.cuserInfo ? scope.row.cuserInfo.phone : '' }}
</template>
</el-table-column>
<el-table-column
prop="createDate"
:label="$t('rechargeList.createDate')"
align="center"
>
<template #default="scope">
{{ getDate(scope.row.createDate) }}
</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 { rechargeListApi } from '@/apis/userManage.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 pageNum = ref(1);
const pageSize = ref(10);
const total = ref(0);

const defaultTime = [
new Date(2000, 1, 1, 0, 0, 0),
new Date(2000, 2, 1, 23, 59, 59),
] // '12:00:00', '08:00:00'
const getPayVendor = (val) => {
return val === 2 ? "微信" : "支付宝";
};

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 formInline = ref({
phone: route.query.phone || '',
productTitle: '',
time: ''
})
const getListData = async (PageNum, PageSize) => {
try {
let data = {
PageNum: PageNum || 1,
PageSize: PageSize || 10,
phone: formInline.value.phone,
projectType: 2,
productTitle: formInline.value.productTitle,
startDate: formInline.value.time ? formInline.value.time[0] : '',
endDate: formInline.value.time ? formInline.value.time[1] : '',
}
const res = await rechargeListApi(data);
tableData.value = res.data.list;
total.value = res.data.total * 1;
} catch (error) {
console.log(error, "err");
}
};
onMounted(() => {
getListData(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>

+ 264
- 0
src/views/userManage/userList.vue Datei anzeigen

@@ -0,0 +1,264 @@
<template>
<div class="page justify-around">
<div class="addbtn">
<el-form :inline="true" :model="formInline" class="demo-form-inline">
<el-form-item :label="$t('userList.phone')">
<el-input v-model="formInline.phone" :placeholder="$t('userList.phonePlaceholder')" clearable />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="getListData()">{{ $t('userList.search') }}</el-button>
</el-form-item>
</el-form>
</div>
<el-table
:data="tableData"
style="width: 100%; height: 90%"
size="large"
align="center"
border
>
<el-table-column
prop="id"
:label="$t('userList.id')"
align="center"
/>
<el-table-column
prop="phone"
:label="$t('userList.phone')"
align="center"
/>


<el-table-column
prop="poins"
:label="$t('userList.poins')"
align="center"
/>
<el-table-column
prop="createDate"
:label="$t('userList.createDate')"
align="center"
>
<template #default="scope">
{{ getDate(scope.row.createDate) }}
</template>
</el-table-column>
<el-table-column
fixed="right"
:label="$t('keyMangage.operations')"
align="center"
>
<template #default="scope">
<el-button link type="primary" size="small" @click="setStatus(scope.row)">{{ scope.row.status === 0 ? '封禁' : '恢复' }}</el-button>
<el-button link type="primary" size="small" @click="showDetail(scope.row.id)">{{$t('userList.view')}}</el-button>
<el-button link type="primary" size="small" @click="rechargeDetail(scope.row)">{{$t('userList.rechargeDetail')}}</el-button>
<el-button link type="primary" size="small" @click="videoDetail(scope.row)"> {{$t('userList.videoDetail')}}</el-button>
<el-button link type="primary" size="small" @click="personMould(scope.row.id)">{{$t('userList.personMould')}}</el-button>
<el-button link type="primary" size="small" @click="personVoice(scope.row.id)">{{$t('userList.personVoice')}}</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="detailDialogVisible" v-if="detailDialogVisible" :title="$t('userList.viewDetail')" width="60%" :before-close="handleClose" >
<el-form :model="form" label-width="120px">
<el-form-item :label="$t('userList.phone')">
<el-input v-model="form.phone" />
</el-form-item>
<el-form-item label="Level">
<el-input v-model="form.level" />
</el-form-item>
<el-form-item :label="$t('userList.poins')">
<el-input v-model="form.poins" />
</el-form-item>
<el-form-item :label="$t('userList.createDate')">
<el-input v-model="form.createDate" />
</el-form-item>
<!-- <el-form-item>
<el-button>{{$t('userList.close')}}</el-button>
</el-form-item> -->
</el-form>
</el-dialog>

<el-dialog v-model="modelDialogVisible" v-if="modelDialogVisible" :title="$t('userList.personMould')" width="60%" :before-close="handleClose" >
<model :cUserId="cUserId" @close="handleClose"></model>
</el-dialog>
<el-dialog v-model="voiceDialogVisible" v-if="voiceDialogVisible" :title="$t('userList.personVoice')" width="60%" :before-close="handleClose" >
<voice :cUserId="cUserId" @close="handleClose"></voice>
</el-dialog>
</div>
</template>
<!-- videoType==1为竖,==2为横 -->
<script setup>
//#region 导入

import { userListApi, userListFindByIdApi, updateStatusApi } from '@/apis/userManage.js'
import { useI18n } from "vue-i18n";
import dayjs from "dayjs";
import { useRoute, useRouter } from "vue-router";
import model from './personMould.vue'
import voice from './personVoice.vue'
const route = useRoute();
const router = useRouter();
const { locale } = useI18n();
const lanChange = ref(locale);
const tableData = ref([]);
const dialogVisible = ref(false);
const rechargeDetail = (item) => {
router.push({
path: "/rechargeList",
query: {
phone: item.phone
},
});
};
const videoDetail = (item) => {
router.push({
path: "/videoList",
query: {
phone: item.phone
},
});
};
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 formInline = ref({
phone: ''
})
const getListData = async (PageNum, PageSize) => {
try {
let data = {
PageNum: PageNum || 1,
PageSize: PageSize || 10,
phone: formInline.value.phone
}
const res = await userListApi(data);
console.log(res, "res");
tableData.value = res.data.list;
total.value = res.data.total * 1;
} catch (error) {
console.log(error, "err");
}
};

const form = ref({
name: '',
phone: ''
})
const detailDialogVisible = ref(false)
function showDetail(id) {
userListFindByIdApi(id).then(res => {
detailDialogVisible.value = true
res.data.createDate = getDate(res.data.createDate)
form.value = res.data
})
}
function handleClose() {
detailDialogVisible.value = false
modelDialogVisible.value = false
voiceDialogVisible.value = false
}
const modelDialogVisible = ref(false)
const cUserId = ref('')
function personMould(id) {
modelDialogVisible.value = true
cUserId.value = id
}

const voiceDialogVisible = ref(false)
function personVoice(id) {
voiceDialogVisible.value = true
cUserId.value = id
}

// 状态
function setStatus(item) {
updateStatusApi({id: item.id, status: item.status === 0 ? 1 : 0}).then(res => {
if (res.code === 200) {
ElMessage.success((lanChange.value) == "zh-cn" ? "操作成功!" : 'Operation successful!');
getListData(1, 10);
}
})
}
onMounted(() => {
getListData(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>

+ 180
- 0
src/views/userManage/userMouldList.vue Datei anzeigen

@@ -0,0 +1,180 @@
<template>
<div class="page justify-around">
<div class="addbtn">
<el-form :inline="true" :model="formInline" class="demo-form-inline">
<el-form-item :label="$t('userMouldList.phone')">
<el-input v-model="formInline.phone" :placeholder="$t('userMouldList.phonePlaceholder')" clearable />
</el-form-item>
<el-form-item :label="$t('userMouldList.mouldSmId')">
<el-input v-model="formInline.mouldSmIdLike" :placeholder="$t('userMouldList.mouldSmIdPlaceholder')" clearable />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="getListData()">{{$t('userMouldList.search')}}</el-button>
</el-form-item>
</el-form>
</div>
<el-table
:data="tableData"
style="width: 100%; height: 90%"
size="large"
align="center"
border
>
<el-table-column
prop="coverImg"
:label="$t('userMouldList.coverImg')"
align="center"
>
<template #default="scope">
<img :src="scope.row.coverImg" width="50" height="50" alt="" />
</template>
</el-table-column>
<el-table-column
prop="mouldSmId"
:label="$t('userMouldList.mouldSmId')"
align="center"
/>
<el-table-column
prop="wxCUserBasicInfoList"
:label="$t('userMouldList.bindPhone')"
align="center"
>
<template #default="scope">
{{ getListPhone(scope.row.wxCUserBasicInfoList) }}
</template>
</el-table-column>
<el-table-column
prop="createDate"
:label="$t('userMouldList.createDate')"
align="center"
>
<template #default="scope">
{{ getDate(scope.row.createDate) }}
</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 { userMouldListApi } from '@/apis/userManage.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 pageNum = ref(1);
const pageSize = ref(10);
const total = ref(0);
const getDate = (val) => {
return dayjs(val).format("YYYY-MM-DD");
};
const getListPhone = (list) => {
let phone = []
list && list.forEach(ele => {
phone.push(ele.phone)
});
return phone.join(',')
}

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

const formInline = ref({
phone: '',
mouldSmIdLike: ''
})
const getListData = async (PageNum, PageSize) => {
try {
let data = {
PageNum: PageNum || 1,
PageSize: PageSize || 10,
phone: formInline.value.phone,
mouldSmIdLike: formInline.value.mouldSmIdLike
}
const res = await userMouldListApi(data);
console.log(res, "res");
tableData.value = res.data.list;
total.value = res.data.total * 1;
} catch (error) {
console.log(error, "err");
}
};

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

+ 188
- 0
src/views/userManage/userVoiceList.vue Datei anzeigen

@@ -0,0 +1,188 @@
<template>
<div class="page justify-around">
<div class="addbtn">
<el-form :inline="true" :model="formInline" class="demo-form-inline">
<el-form-item :label="$t('userVoiceList.phone')">
<el-input v-model="formInline.phone" :placeholder="$t('userVoiceList.phonePlaceholder')" clearable />
</el-form-item>
<el-form-item :label="$t('userVoiceList.mouldSmId')">
<el-input v-model="formInline.mouldSmIdLike" :placeholder="$t('userVoiceList.mouldSmIdPlaceholder')" clearable />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="getListData()"> {{ $t('userVoiceList.search') }}</el-button>
</el-form-item>
</el-form>
</div>

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

<el-table-column
prop="chineseName"
:label="$t('userVoiceList.chineseName')"
align="center"
/>
<el-table-column
prop="country"
:label="$t('userVoiceList.country')"
align="center"
/>
<el-table-column
prop="language"
:label="$t('userVoiceList.lang')"
align="center"
/>

<el-table-column
prop="wxCUserBasicInfoList"
:label="$t('userVoiceList.bindPhone')"
align="center"
>
<template #default="scope">
{{ getListPhone(scope.row.wxCUserBasicInfoList) }}
</template>
</el-table-column>

<el-table-column
prop="createDate"
:label="$t('userVoiceList.createDate')"
align="center"
>
<template #default="scope">
{{ getDate(scope.row.createDate) }}
</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 { userVoiceListAPi } from '@/apis/userManage.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 pageNum = ref(1);
const pageSize = ref(10);
const total = ref(0);

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

const getListPhone = (list) => {
let phone = []
list && list.forEach(ele => {
phone.push(ele.phone)
});
return phone.join(',')
}


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

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

const formInline = ref({
phone: '',
mouldSmIdLike: ''
})

const getListData = async (PageNum, PageSize) => {
try {
let data = {
PageNum: PageNum || 1,
PageSize: PageSize || 10,
phone: formInline.value.phone,
mouldSmIdLike: formInline.value.mouldSmIdLike
}
const res = await userVoiceListAPi(data);
console.log(res, "res");
tableData.value = res.data.list;
total.value = res.data.total * 1;
} catch (error) {
console.log(error, "err");
}
};


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

+ 342
- 0
src/views/userManage/videoList.vue Datei anzeigen

@@ -0,0 +1,342 @@
<template>
<div class="page justify-around">
<div class="addbtn">
<el-form :inline="true" :model="formInline" class="demo-form-inline">
<el-form-item :label="$t('videoList.phone')">
<el-input v-model="formInline.phone" :placeholder="$t('videoList.phonePlaceholder')" clearable />
</el-form-item>
<el-form-item :label="$t('videoList.text')">
<el-input v-model="formInline.paperwork" :placeholder="$t('videoList.textPlaceholder')" clearable />
</el-form-item>
<el-form-item :label="$t('videoList.type')">
<el-select
v-model="formInline.videoType"
:placeholder="$t('videoList.typePlaceholder')"
clearable
>
<el-option :label="$t('videoList.all')" value="" />
<el-option :label="$t('videoList.portrait')" value="1" />
<el-option :label="$t('videoList.transversePlate')" value="2" />
</el-select>
</el-form-item>
<el-form-item :label="$t('videoList.status')">
<el-select
v-model="formInline.isDel"
:placeholder="$t('videoList.statusPlaceholder')"
clearable
>
<el-option :label="$t('videoList.all')" value="" />
<el-option :label="$t('videoList.notDeleted')" value="0" />
<el-option :label="$t('videoList.deleted')" value="1" />
</el-select>
</el-form-item>
<el-form-item :label="$t('videoList.time')">
<el-date-picker
v-model="formInline.time"
type="datetimerange"
start-placeholder="Start Date"
end-placeholder="End Date"
value-format="YYYY-MM-DD HH:mm:ss"
:default-time="defaultTime"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="getListData()">{{ $t('videoList.search') }}</el-button>
</el-form-item>
</el-form>
</div>
<el-table
:data="tableData"
style="width: 100%; height: 90%"
size="large"
align="center"
border
>
<el-table-column
prop="videoType"
:label="$t('videoList.type')"
align="center"
>
<template #default="scope">
{{ getVideoType(scope.row.videoType) }}
</template>
</el-table-column>
<el-table-column
prop="paperwork"
:label="$t('videoList.text')"
align="center"
>
<template #default="scope">
{{ scope.row.paperwork.substring(0, 10) + '...' }}
</template>
</el-table-column>
<el-table-column
prop="isDel"
:label="$t('videoList.status')"
align="center"
>
<template #default="scope">
{{ getIsDel(scope.row.isDel) }}
</template>
</el-table-column>
<el-table-column
prop="title"
:label="$t('videoList.title')"
align="center"
/>
<el-table-column
prop="coverImg"
:label="$t('videoList.coverImg')"
align="center"
>
<template #default="scope">
<img :src="scope.row.coverImg" width="50" height="50" alt="" />
</template>
</el-table-column>
<el-table-column
prop="videoPlayUrl"
:label="$t('videoList.videoPlayUrl')"
align="center"
/>
<el-table-column
prop="videoTime"
:label="$t('videoList.videoTime')"
align="center"
>
</el-table-column>
<el-table-column
prop="videoSize"
:label="$t('videoList.videoSize')"
align="center"
/>
<el-table-column
prop="videoMsg"
:label="$t('videoList.videoMsg')"
align="center"
/>
<el-table-column
prop="costPoints"
:label="$t('videoList.costPoints')"
align="center"
/>
<el-table-column
prop="costPointsDetail"
:label="$t('videoList.costPointsDetail')"
align="center"
/>
<el-table-column
prop="createDate"
:label="$t('videoList.createDate')"
align="center"
>
<template #default="scope">
{{ getDate(scope.row.createDate) }}
</template>
</el-table-column>

<el-table-column
fixed="right"
:label="$t('keyMangage.operations')"
align="center"
>
<template #default="scope">
<el-button link type="primary" size="small" @click="showDetail(scope.row.id)">{{$t('videoList.view')}}</el-button>
<el-button v-if="scope.row.isDel === 0" link type="primary" size="small" @click="confirmDel(scope.row.id)">{{$t('videoList.del')}}</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" v-if="dialogVisible" :title="`${$t('videoList.videoDetail')}:`" width="40%">
<el-form :model="form" label-width="120px">
<el-form-item :label="$t('videoList.name')">
<el-input v-model="form.title" />
</el-form-item>
<el-form-item :label="$t('videoList.videType')">
<el-radio-group v-model="form.videoType">
<el-radio :label="1">{{$t('videoList.portrait')}}</el-radio>
<el-radio :label="2">{{$t('videoList.transversePlate')}}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="$t('videoList.text')">
<el-input v-model="form.paperwork" type="textarea" />
</el-form-item>
<el-form-item :label="$t('videoList.coverImg')">
<img :src="form.coverImg" alt="" :style="{ width: form.videoType === 1 ? '50%' : '100%'}">
</el-form-item>
<el-form-item :label="$t('videoList.videoPlayUrl')">
<el-input v-model="form.videoPlayUrl" />
<video :src="form.videoPlayUrl" controls :style="{ width: form.videoType === 1 ? '50%' : '100%'}"></video>
</el-form-item>
<el-form-item :label="$t('videoList.videoTime')">
<el-input v-model="form.videoTime" />
</el-form-item>
<el-form-item :label="$t('videoList.createDate')">
<el-input v-model="form.createDate" />
</el-form-item>
<el-form-item :label="$t('videoList.costPoints')">
<el-input v-model="form.costPoints" />
</el-form-item>
<el-form-item :label="$t('videoList.costPointsDetail')">
<el-input v-model="form.costPointsDetail" />
</el-form-item>
<el-form-item>
<el-button @click="dialogVisible = false">{{ $t('videoList.close') }}</el-button>
</el-form-item>
</el-form>
</el-dialog>
</div>
</template>
<script setup>
//#region 导入
import { videoListApi, videoListFindByIdApi, videoListDelApi } from '@/apis/userManage.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 pageNum = ref(1);
const pageSize = ref(10);
const total = ref(0);

const defaultTime = [
new Date(2000, 1, 1, 0, 0, 0),
new Date(2000, 2, 1, 23, 59, 59),
] // '12:00:00', '08:00:00'
const getVideoType = (val) => {
return val === 1 ? "竖版" : "横版";
};
const getIsDel = (val) => {
return val === 1 ? "已删除" : "未删除";
};

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 formInline = ref({
phone: route.query.phone || '',
productTitle: '',
time: ''
})
const getListData = async (PageNum, PageSize) => {
try {
let data = {
PageNum: PageNum || 1,
PageSize: PageSize || 10,
phone: formInline.value.phone,
projectType: 2,
productTitle: formInline.value.productTitle,
startDate: formInline.value.time ? formInline.value.time[0] : '',
endDate: formInline.value.time ? formInline.value.time[1] : '',
id: route.query.id || '',
isDel: formInline.value.isDel,
videoType: formInline.value.videoType,
paperwork: formInline.value.paperwork
}
const res = await videoListApi(data);
tableData.value = res.data.list;
total.value = res.data.total * 1;
} catch (error) {
console.log(error, "err");
}
};
// 查看详情
const dialogVisible = ref(false)
const form = ref({})
function showDetail(id) {
videoListFindByIdApi(id).then(res => {
if(res.code === 200){
dialogVisible.value = true
form.value = res.data
}
})
}
function confirmDel(id) {
ElMessageBox.confirm('你确定要删除吗?').then(() => {
videoListDelApi(id).then(res => {
if (res.code == 200) {
ElMessage.success("删除成功!");
getListData(1, 10)
}
})
done()
}).catch(() => {
// catch error
})
}
onMounted(() => {
getListData(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>

+ 87
- 0
src/views/userManage/voiceMould.vue Datei anzeigen

@@ -0,0 +1,87 @@
<template>
<div>
<el-checkbox-group v-model="checkboxGroup" size="small" class="checkbox">
<el-checkbox v-for="(item, index) in tableData" :key="index" :label="item.id" border>
<img :src="item.coverImg" width="50" />
<p>{{ item.title }}</p>
</el-checkbox>
</el-checkbox-group>
<div style="margin-top: 20px">
<el-button @click="handleClose"
>{{ $t('personMould.cancel') }}</el-button
>
<el-button type="primary" @click="addModel()">{{ $t('personMould.confirm') }}</el-button>
</div>
</div>
</template>

<script setup>
import { ref } from 'vue'
import { voiceMouldListApi, userVoiceIdListApi, associatedUserVoicesApi } from '@/apis/userManage.js'
import dayjs from "dayjs";

const emit = defineEmits(["close"]);
const props = defineProps({
serviceId: {
required: true,
}
});

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

const checkboxGroup = ref([])
const total = ref(0);
const tableData = ref([]);

const modelAllListFunc = async () => {
try {
const res = await voiceMouldListApi(1, 10000);
const modelIds = await userVoiceIdListApi(props.serviceId);
tableData.value = res.data.list;
total.value = res.data.total * 1;
setTimeout(()=> {
if(modelIds.data && modelIds.data.length > 0) {
modelIds.data.forEach((item) => {
checkboxGroup.value.push(item)
})
}
}, 500)

} catch (error) {
console.log(error, "err");
}
};

const addModel = async () => {
const data = {
mouldIds: checkboxGroup.value,
cUserId: props.serviceId
}
const res = await associatedUserVoicesApi(data);
if(res.code === 200) {
ElMessage.success("关联成功!");
handleClose()
}
};

function handleClose() {
emit("close");
}
onMounted(() => {
modelAllListFunc(1, 10);
});
</script>

<style lang="scss" scoped>
.checkbox {
max-height: 500px;
overflow: auto;
:deep .el-checkbox.el-checkbox--small {
width: 110px;
height:110px;
margin-bottom: 10px;
}
}
</style>

+ 175
- 0
src/views/video/index.vue Datei anzeigen

@@ -0,0 +1,175 @@
<template>
<div class="page justify-around">
<el-alert :title="`${$t('video.time')}:${crrentVideoToal} 秒`" type="success" :closable="false" />
<el-table
:data="tableData"
style="width: 100%; height: 90%"
size="large"
align="center"
border
>
<el-table-column
prop="serviceId"
:label="$t('video.code')"
align="center">
<template #default="scope">
<el-button type="primary" text @click="getDetail(scope.row.serviceId)">{{ scope.row.serviceId }}</el-button>
</template>
</el-table-column>
<el-table-column
prop="videoTime"
:label="$t('video.videoTime')"
align="center"
/>
<el-table-column
prop="videoUrl"
:label="$t('video.videoUrl')"
align="center"
/>
<el-table-column
prop="createTime"
:label="$t('video.createTime')"
align="center"
>
<template #default="scope">
{{ getDate(scope.row.createTime) }}
</template>
</el-table-column>

<el-table-column
fixed="right"
:label="$t('keyMangage.operations')"
align="center"
>
<template #default="scope">
<el-button link type="primary" size="small" @click="showDetail(scope.row.userMouldVideoId)">{{ $t('keyMangage.detail') }}</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 { videoListApi,currentVideoToalApi } from '@/apis/home.js'
import { useI18n } from "vue-i18n";
import dayjs from "dayjs";
import { useRoute, useRouter } from "vue-router";
const route = useRoute();
const router = useRouter();
const tableData = ref([]);
const pageNum = ref(1);
const pageSize = ref(10);
const total = ref(0);
const getDate = (val) => {
return dayjs(Number(val)).format("YYYY-MM-DD HH:mm:ss");
};

// 跳转视频列表
const showDetail = (id) => {
router.push({
path: "/videoList",
query: {
id,
},
});
};
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 videoListApi(PageNum, PageSize);
console.log(res, "res");
tableData.value = res.data.list;
total.value = res.data.total * 1;
} catch (error) {
console.log(error, "err");
}
};

//查看详情
function getDetail(id) {
router.push({
path: "/apiManage",
query: {
id,
},
});
}
const crrentVideoToal = ref('')
function getCrrentVideoToal() {
currentVideoToalApi().then(res => {
crrentVideoToal.value = res.data
})
}
onMounted(() => {
getCrrentVideoToal()
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>

+ 16
- 11
vite.config.ts Datei anzeigen

@@ -35,26 +35,31 @@ export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
`,
},
},
postcss: {
plugins: [
postCssPxToRem({
rootValue: 192, // 1rem 的大小
propList: ['*'], // 需要转换的属性,*(全部转换)
unitPrecision: 6 // 转换精度,保留的小数位数
})
]
}
// postcss: {
// plugins: [
// postCssPxToRem({
// rootValue: 192, // 1rem 的大小
// propList: ['*'], // 需要转换的属性,*(全部转换)
// unitPrecision: 6 // 转换精度,保留的小数位数
// })
// ]
// }
},
server: {
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/, ""),
},
},
},


+ 123
- 0
vite.config.ts.timestamp-1698900171336-585e6054472a3.mjs
Datei-Diff unterdrückt, da er zu groß ist
Datei anzeigen


+ 235
- 164
yarn-error.log
Datei-Diff unterdrückt, da er zu groß ist
Datei anzeigen


+ 1619
- 1624
yarn.lock
Datei-Diff unterdrückt, da er zu groß ist
Datei anzeigen


Laden…
Abbrechen
Speichern