优化代码

This commit is contained in:
pengxiaolong
2025-09-25 19:40:54 +08:00
parent 8cabf98bd9
commit ea50c14175
17 changed files with 1462 additions and 271 deletions

View File

@@ -26,7 +26,6 @@ export function tkhostdata(data) {
export function apiGetCart() {
return getAxios({ url: '/cgi-bin/cart/latest' })
}

BIN
src/assets/MiniProgram.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

BIN
src/assets/ai.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

BIN
src/assets/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
src/assets/plus.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

BIN
src/assets/plus2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@@ -25,14 +25,14 @@ if (process.env.NODE_ENV === 'development') {
// baseURL = "https://api.tkpage.yolozs.com"
baseURL = "http://47.79.98.113:8101"
// baseURL = "http://192.168.0.103:8085/"
// baseURL = "http://192.168.1.174:8101"
// baseURL = "http://192.168.1.144:8101"
} else {
// 测试环境
// baseURL = "http://120.26.251.180:8085/"
// 开发环境
// baseURL = "https://api.tkpage.yolozs.com"
baseURL = "http://47.79.98.113:8101"
// baseURL = "http://192.168.1.174:8101"
// baseURL = "http://192.168.1.144:8101"
// baseURL = "http://api.tkpage.vvtiktok.cn"
}

View File

@@ -10,34 +10,6 @@ const initBridge = () => {
});
};
export function usePythonBridge() {
// // 调用 Python 方法
// const fetchDataConfig = (data) => {
// return new Promise((resolve, reject) => {
// if (bridge.value) {
// bridge.value.fetchDataConfig(data, function (result) {
// resolve(result);
// });
// }
// });
// };
// // 查询获取主播的数据
// const fetchDataCount = () => {
// return new Promise((resolve, reject) => {
// if (bridge.value) {
// bridge.value.fetchDataCount(function (result) {
// resolve(result);
// });
// }
// });
// };
//删除前端储存数据
const deleteStorageData = (data) => {
return new Promise((resolve, reject) => {
@@ -112,18 +84,42 @@ export function usePythonBridge() {
}
};
// // 登录tk后台
// const loginBackStage = (data) => {
// if (bridge.value) {
// if (data.index == 0) {
// bridge.value.loginBackStage(JSON.stringify(data));
// } else if (data.index == 1) {
// bridge.value.loginBackStageCopy(JSON.stringify(data));
// }
// }
// };
//指定直播间
const Specifystreaming = (data) => {
return new Promise((resolve, reject) => {
if (pyBridge.value) {
pyBridge.value.find_big_brother_in_rooms(data,function (result) {
resolve(result);
});
}else{
console.log("pyBridge is null未连接上")
}
});
};
//储存直播间id
const setStorageStreamId = (data) => {
return new Promise((resolve, reject) => {
if (pyBridge.value) {
pyBridge.value.saveFrontString(JSON.stringify(data),function (result) {
resolve(result);
});
}else{
console.log("pyBridge is null未连接上")
}
});
};
//获取直播间id
const getStorageStreamId = (data) => {
return new Promise((resolve, reject) => {
if (pyBridge.value) {
pyBridge.value.loadFrontStringRaw(JSON.stringify(data),function (result) {
resolve(result);
});
}else{
console.log("pyBridge is null未连接上")
}
});
};
//跳转到主播页面
const givePyAnchorId = (id) => {
console.log("id",id);
@@ -133,29 +129,6 @@ export function usePythonBridge() {
}
};
// //查询登录状态
// const backStageloginStatus = () => {
// return new Promise((resolve, reject) => {
// if (bridge.value) {
// bridge.value.backStageloginStatus(function (result) {
// resolve(result);
// });
// }
// });
// };
// //查询登录状态
// const backStageloginStatusCopy = () => {
// return new Promise((resolve, reject) => {
// if (bridge.value) {
// bridge.value.backStageloginStatusCopy(function (result) {
// resolve(result);
// });
// }
// });
// };
//导出表格
const exportToExcel = (data) => {
if (pyBridge .value) {
@@ -194,5 +167,8 @@ export function usePythonBridge() {
getStorageData,
setStorageData,
deleteStorageData,
Specifystreaming,
setStorageStreamId,
getStorageStreamId
};
}

View File

@@ -28,6 +28,13 @@ export async function getUser() {
return JSON.parse(res);
}
export function setuserprmisson() {
return new Promise((resolve, reject) => {
const res = getStorageData({ key: 'user' });
resolve(res);
});
}
export async function setNumData(numData) {
const res = await setStorageData({key: 'num',data: numData})
}

View File

@@ -141,7 +141,7 @@ const onSubmit = () => {
})
.then((res) => {
loading.close();
console.log(res);
console.log("123123123123",res);
setToken(res.tokenValue);
tokenCache.setToken(res.tokenValue)
userCache.setUser(res)

77
src/views/hosts/Home.vue Normal file
View File

@@ -0,0 +1,77 @@
<template>
<div class="home">
<!-- <div id="main" class="main"></div> -->
<div class="noData">
暂无数据
</div>
</div>
</template>
// <script setup>
// import { ref, watch, onMounted, onUpdated, onUnmounted } from "vue";
// const refname = ref('');
// const echarts = require('echarts/lib/echarts');
// require('echarts/lib/component/grid');
// require('echarts/lib/chart/bar');
// const initChart = () => {
// var chartDom = document.getElementById('main');
// var myChart = echarts.init(chartDom);
// var option = {
// xAxis: {
// type: 'category',
// data: ['用户量', '123', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
// },
// yAxis: {
// type: 'value'
// },
// series: [
// {
// data: [120, 200, 150, 80, 70, 110, 130],
// type: 'bar'
// }
// ]
// };
// myChart.setOption(option);
// };
// watch(refname, (newQuestion) => {
// // 变化后执行
// // 如果 refname 的变化影响图表数据,可以在这里更新 option 并调用 myChart.setOption(option)
// });
// onMounted(() => {
// initChart();
// });
// onUpdated(() => {
// // 组件更新后执行
// // 如果需要根据更新重新初始化图表或更新数据,可以在这里添加逻辑
// });
// onUnmounted(() => {
// // 组件销毁前执行
// // 如果需要销毁图表实例以释放资源,可以在这里添加逻辑
// });
</script>
<style scoped>
.home {
width: 100%;
height: 100%;
background-color: #ffffff;
border-radius: 10px;
display: flex;
justify-content: center;
align-items: center;
}
.noData{
font-size: 20px;
color: #999999;
}
.main{
width: 40%;
height: 40%;
}
</style>

View File

@@ -0,0 +1,288 @@
<template>
<div class="language-management">
<div class="content">
<div class="languagetitle">
<div class="title">语言管理</div>
<div class="add" @click="dialogVisible = true">
<img class="add-img" src="@/assets/plus2.png" alt="" />
</div>
</div>
<!-- 语言列表 -->
<div class="languagelist">
<el-table
:data="tableData"
stripe
style="width: 100%; margin-top: 10px"
max-height="700"
>
<el-table-column prop="language" label="语言名称" />
<el-table-column prop="" label="" />
<el-table-column prop="" label="" />
<el-table-column prop="" label="" />
<el-table-column label="操作">
<template #default="scope">
<el-button size="small" @click="handleEdit(scope.$index, scope.row)">
修改
</el-button>
<el-button
size="small"
type="danger"
@click="handleDelete(scope.$index, scope.row)"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
</div>
<!-- 编辑弹窗 -->
<el-drawer v-model="dialogVisible" :with-header="false" @close="dialogVisible = false, languageNamedeta = {}">
<div class="dialog-content">
<div class="dialog-title">语言{{languageNamedeta.id? '编辑' : '新增'}}</div>
<el-input
v-model="languageNamedeta.language"
style="width: 100%; margin-top: 20px"
:rows="3"
type="textarea"
placeholder="请输入语言内容"
/>
<div class="dialog-btn">
<div class="dialogSave" @click="languageSave">保存</div>
<div class="dialogCancel" @click="dialogVisible = false">取消</div>
</div>
</div>
</el-drawer>
</template>
<script setup>
import { ElMessage, ElMessageBox } from "element-plus";
import { getLanguageList,deleteLanguage,editLanguage,addLanguage} from "@/api/account";
import {
ref, // 响应式基础
watch, // 侦听器
onMounted, // 组件挂载完成后执行
onUpdated, // 组件更新后执行
onUnmounted, // 组件销毁前执行
} from "vue";
const refname = ref("");
const tableData = ref([]);
const dialogVisible = ref(false);
let languageNamedeta = ref({});// 编辑添加弹窗数据
// 编辑弹窗
function handleEdit(index, row) {
dialogVisible.value = true;
languageNamedeta.value = row;
}
// 保存语言
function languageSave() {
if (languageNamedeta.value.language == null) {
ElMessage({
type: "error",
message: "请输入语言内容",
});
return;
}
if (languageNamedeta.value.id) {
// 修改语言
editLanguage(languageNamedeta.value)
.then(() => {
ElMessage({
type: "success",
message: "修改成功",
});
getLanguageListData();
})
.catch(() => {
ElMessage({
type: "error",
message: "修改失败",
});
});
dialogVisible.value = false;
}else{
// 新增语言
addLanguage(languageNamedeta.value)
.then(() => {
ElMessage({
type: "success",
message: "添加成功",
});
getLanguageListData();
})
.catch(() => {
ElMessage({
type: "error",
message: "添加失败",
});
});
dialogVisible.value = false;
}
}
// 删除语言
function handleDelete(index, row) {
ElMessageBox.confirm("您确认要删除这个语言吗?")
.then(() => {
deleteLanguage({ id: row.id })
.then(() => {
ElMessage({
type: "success",
message: "删除成功",
});
getLanguageListData();
})
.catch(() => {
ElMessage({
type: "error",
message: "删除失败",
});
});
})
.catch(() => {});
}
function getLanguageListData() {
// 获取语言列表
getLanguageList()
.then((res) => {
console.log(res);
tableData.value = res;
}).catch(() => {
ElMessage({
type: "error",
message: "获取语言列表失败",
});
});
}
watch(refname, async (newQuestion, oldQuestion) => {
// 变化后执行
});
onMounted(() => {
getLanguageListData();
// 组件挂载完成后执行
});
onUpdated(() => {
// 组件更新后执行
});
onUnmounted(() => {
// 组件销毁前执行
});
</script>
<style scoped>
.language-management {
width: 100%;
height: 100%;
background-color: #ffffff;
border-radius: 10px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.content {
width: 95%;
height: 95%;
background-color: #f5f5f5;
border-radius: 10px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
box-shadow: 2px 4px 8px rgba(0, 0, 0, 0.3);
}
.languagetitle {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
height: 50px;
background-color: #e2e2e2;
border-radius: 10px;
}
.title {
font-size: 24px;
font-weight: bold;
color: #999999;
margin-left: 40px;
}
.add {
width: 150px;
height: 50px;
background-color: #cccccc;
border-radius: 10px;
display: flex;
justify-content: center;
align-items: center;
}
.add:hover {
background-color: #999999;
}
.add-img {
width: 40px;
height: 40px;
}
.languagelist {
width: 97%;
height: 85%;
background-color: #ffffff;
margin-bottom: 20px;
border-radius: 10px;
overflow: auto;
scrollbar-width: none;
}
.dialog-content {
width: 100%;
height: 100%;
}
.dialog-title {
width: 100%;
height: 50px;
font-size: 25px;
color: #b4b4b4;
font-weight: bold;
margin-top: 20px;
margin-bottom: 20px;
text-align: center;
}
.dialog-btn {
margin-top: 20px;
display: flex;
justify-content: space-between;
}
.dialogSave {
width: 45%;
height: 50px;
background-color: #d6d6d6;
line-height: 50px;
text-align: center;
font-weight: bold;
border-radius: 5px;
font-size: 16px;
color: #ffffff;
}
.dialogSave:hover {
background-color: #b4b4b4;
}
.dialogCancel {
width: 45%;
height: 50px;
line-height: 50px;
text-align: center;
font-weight: bold;
border-radius: 5px;
font-size: 16px;
color: #d6d6d6;
border: 1px solid #d6d6d6;
}
.dialogCancel:hover {
background-color: #e7e6e6;
color: #ffffff;
}
</style>

View File

@@ -0,0 +1,416 @@
<template>
<div class="scriptManagement">
<div class="wordslist">
<!-- 话术列表 -->
<div class="wordscontent" ref="containerRef">
<div
class="words"
v-for="(item, index) in LanguageData"
:key="index"
:id="item.language"
>
<div class="wordsname">{{ item.language }}</div>
<div class="wordscontents">
<div
class="wordscontentstext"
v-for="(items, indexs) in item.content"
:key="index"
>
<div>{{ indexs + 1 + ".&nbsp;" + items.content }}</div>
<div class="wordscontentstextbtn">
<div style="margin-right: 10px" @click="handleEditor(items.id)">编辑</div>
<div @click="handleDelete(items.id)">删除</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="Languagelist">
<div class="Languagecontent">
<!-- 话术添加 -->
<div class="addwords" @click="wordsAddStatus = true">
<img class="addwordsimg" src="@/assets/plus.png" />
</div>
<!-- 语言选择 -->
<el-anchor
class="Languageanchor"
:container="containerRef"
direction="vertical"
type="default"
:offset="30"
@click="handleClick"
>
<el-anchor-link
class="anchorLink"
v-for="(item, index) in getLanguageListData"
:href="'#' + item.language"
:title="item.language"
:key="index"
/>
</el-anchor>
</div>
</div>
</div>
<!-- 话术编辑 -->
<el-drawer v-model="dialogVisible" :with-header="false">
<div class="dialog-content">
<div class="dialog-title">话术编辑</div>
<el-input
v-model="handletextareadeta.content"
style="width: 100%; margin-top: 20px"
:rows="25"
type="textarea"
placeholder="请输入话术内容"
/>
<div class="dialog-btn">
<div class="dialogSave" @click="handleSave">保存</div>
<div class="dialogCancel" @click="dialogVisible = false">取消</div>
</div>
</div>
</el-drawer>
<!-- 话术添加 -->
<el-drawer v-model="wordsAddStatus" :with-header="false">
<div class="dialog-content">
<div class="dialog-title">话术编辑</div>
<el-select v-model="wordsAddData.language" placeholder="请选择语言">
<el-option
v-for="item in LanguageData"
:key="item.language"
:label="item.language"
:value="item.language"
/>
</el-select>
<el-input
v-model="wordsAddData.content"
style="width: 100%; margin-top: 20px"
:rows="25"
type="textarea"
placeholder="请输入话术内容"
/>
<div class="dialog-btn">
<div class="dialogSave" @click="handleSaveWordsAdd">保存</div>
<div class="dialogCancel" @click="wordsAddStatus = false">取消</div>
</div>
</div>
</el-drawer>
</template>
<script setup>
import {
getDialogList,
getLanguageList,
editDialog,
deleteDialog,
addDialog,
} from "@/api/account";
import { ElMessage, ElMessageBox } from "element-plus";
import {
ref, // 响应式基础
watch, // 侦听器
onMounted, // 组件挂载完成后执行
onUpdated, // 组件更新后执行
onUnmounted, // 组件销毁前执行
} from "vue";
const refname = ref("");
const containerRef = ref(null);
const getDialogListData = ref([]);
const getLanguageListData = ref([]);
const LanguageData = ref([]);
const wordsAddStatus = ref(false);
const wordsAddData = ref({
language: "",
content: "",
});
const handleClick = (e) => {
e.preventDefault();
};
//数据处理
function mergeArrays(arr1, arr2) {
const result = [];
const languages = new Set([...arr1.map(i => i.language), ...arr2.map(i => i.language)]);
for (const lang of languages) {
const contents = arr1.filter(item => item.language === lang)
.map(item => ({ id: item.id, content: item.content }));
result.push({
language: lang,
content: contents
});
}
return result;
}
const dialogVisible = ref(false);
const handletextareadeta = ref({});
//添加话术
function handleSaveWordsAdd() {
console.log("handleSaveWordsAdd",wordsAddData.value);
if (wordsAddData.value.language === "" || wordsAddData.value.content === "") {
ElMessage({
type: "error",
message: "请填写完整信息",
});
return;
}
wordsAddStatus.value = false;
addDialog(wordsAddData.value)
.then(() => {
ElMessage({
type: "success",
message: "添加成功",
});
getLanguageListDataFn();
})
.catch(() => {
ElMessage({
type: "error",
message: "添加失败",
});
});
}
// 编辑
function handleEditor(id) {
dialogVisible.value = true;
handletextareadeta.value = getDialogListData.value.find((item) => item.id === id);
}
// 保存
function handleSave() {
editDialog({
id: handletextareadeta.value.id,
content: handletextareadeta.value.content,
})
.then(() => {
ElMessage({
type: "success",
message: "保存成功",
});
getLanguageListDataFn();
dialogVisible.value = false;
})
.catch(() => {
ElMessage({
type: "error",
message: "保存失败",
});
});
}
// 删除
function handleDelete(id) {
ElMessageBox.confirm("您确认要删除这条话术吗?")
.then(() => {
deleteDialog({ id })
.then(() => {
ElMessage({
type: "success",
message: "删除成功",
});
getLanguageListDataFn();
})
.catch(() => {
ElMessage({
type: "error",
message: "删除失败",
});
});
})
.catch(() => {});
}
function getLanguageListDataFn() {
getDialogList().then((res) => {
getDialogListData.value = res;
getLanguageList().then((res) => {
getLanguageListData.value = res;
LanguageData.value = mergeArrays(
getDialogListData.value,
getLanguageListData.value
);
console.log("LanguageData", LanguageData.value);
});
});
}
watch(refname, async (newQuestion, oldQuestion) => {
// 变化后执行
});
onMounted(() => {
getLanguageListDataFn();
});
onUpdated(() => {
// 组件更新后执行
});
onUnmounted(() => {
// 组件销毁前执行
});
</script>
<style scoped>
.scriptManagement {
width: 100%;
height: 100%;
background-color: #ffffff;
border-radius: 10px;
display: flex;
}
.wordslist {
width: 87%;
height: 97%;
padding: 1% 1%;
/* background-color: #00ff40; */
}
.Languagelist {
height: 97%;
width: 10%;
padding: 1% 1% 1% 0%;
/* background-color: #8d0000; */
}
.wordscontent {
height: 100%;
width: 100%;
border-radius: 10px;
background-color: rgb(243, 243, 243);
overflow-y: auto;
display: flex;
flex-direction: column;
align-items: center;
scrollbar-width: none;
}
.Languagecontent {
height: 100%;
width: 100%;
border-radius: 10px;
background-color: rgb(243, 243, 243);
display: flex;
flex-direction: column;
overflow-y: auto;
scrollbar-width: none; /* 隐藏滚动条 */
}
.addwords {
width: 100%;
height: 50px;
background-color: rgb(226, 226, 226);
display: flex;
justify-content: center;
align-items: center;
}
.addwords:hover {
background-color: rgb(214, 214, 214);
}
.addwordsimg {
width: 30px;
height: 30px;
}
.Language {
height: 50px;
width: 100%;
background-color: rgb(226, 226, 226);
margin-top: 20px;
}
.words {
width: 95%;
margin-top: 20px;
margin-bottom: 20px;
}
.Languageanchor {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
background-color: rgb(243, 243, 243);
}
.anchorLink {
width: 100px;
height: 30px;
margin-top: 20px;
margin-bottom: 20px;
text-align: center;
font-size: 16px;
line-height: 30px;
border-radius: 5px;
margin-left: -0.875vw;
}
.wordsname {
font-size: 18px;
color: #c9c9c9;
font-weight: bold;
margin-top: 20px;
margin-bottom: 20px;
}
.wordscontents {
width: 95%;
/* min-height: 200px; */
/* background-color: #ffffff; */
border-radius: 10px;
margin-left: 30px;
}
.wordscontentstext {
font-size: 16px;
color: #7a7a7a;
line-height: 24px;
margin-top: 10px;
margin-bottom: 10px;
text-align: left;
word-wrap: break-word;
word-break: break-all;
display: flex;
justify-content: space-between;
align-items: center;
}
.wordscontentstextbtn {
display: flex;
}
.dialog-content {
width: 100%;
height: 100%;
}
.dialog-title {
width: 100%;
height: 50px;
font-size: 25px;
color: #b4b4b4;
font-weight: bold;
margin-top: 20px;
margin-bottom: 20px;
text-align: center;
}
.dialog-btn {
margin-top: 20px;
display: flex;
justify-content: space-between;
}
.dialogSave {
width: 45%;
height: 50px;
background-color: #d6d6d6;
line-height: 50px;
text-align: center;
font-weight: bold;
border-radius: 5px;
font-size: 16px;
color: #ffffff;
}
.dialogSave:hover {
background-color: #b4b4b4;
}
.dialogCancel {
width: 45%;
height: 50px;
line-height: 50px;
text-align: center;
font-weight: bold;
border-radius: 5px;
font-size: 16px;
color: #d6d6d6;
border: 1px solid #d6d6d6;
}
.dialogCancel:hover {
background-color: #e7e6e6;
color: #ffffff;
}
/* 样式定义 */
</style>

View File

@@ -3,66 +3,78 @@
<div>
<!-- -->
<div style="display: flex">
<div></div>
<el-checkbox
class="isFilter"
v-model="queryFormData.isFilter"
label="过滤隐私用户"
size="large"
border
/>
<el-input
v-model="queryFormData.coinMin"
placeholder="最小金币"
size="large"
style="width: 180px"
type="number"
:disabled = "streamdialogVisibletext || isRunnings"
/>
<el-input
v-model="queryFormData.coinMax"
placeholder="最大金币"
size="large"
style="width: 180px;"
style="width: 180px"
class="right-input"
type="number"
:disabled = "streamdialogVisibletext || isRunnings"
/>
<el-input
v-model="queryFormData.levelMin"
placeholder="最小等级"
size="large"
style="width: 180px;"
style="width: 180px"
class="right-input"
type="number"
:disabled = "streamdialogVisibletext || isRunnings"
/>
<el-input
v-model="queryFormData.levelMax"
placeholder="最大等级"
size="large"
style="width: 180px;"
style="width: 180px"
class="right-input"
type="number"
:disabled = "streamdialogVisibletext || isRunnings"
/>
<div class="right-input right-text" style="width: 250px; height: 50px; line-height: 50px">
当前网络{{ countryData }}
</div>
<div class="right-input right-text" style="width: 160px; height: 50px; line-height: 50px">
<el-button
@click="streamdialogVisible = true"
:disabled="isRunnings"
class="put-button buttoMore-filters Specify"
type="primary"
>
<div>{{ streamdialogVisibletext ? '已指定直播间' : '指定直播间' }}</div></el-button
>
<div
class="right-input right-text"
style="width: 160px; height: 50px; line-height: 50px"
>
总数{{ getBrotherInfodata.total }}
</div>
<div class="right-input right-text" style="width: 160px;height: 50px; line-height: 50px">
<div
class="right-input right-text"
style="width: 160px; height: 50px; line-height: 50px"
>
有效数{{ getBrotherInfodata.valid }}
</div>
<el-button
class="serch-button right-input"
type="primary"
@click="Resetss"
<el-button class="serch-button right-input" type="primary" @click="Resetss"
>重置</el-button
>
<el-button
class="serch-button right-input"
style="width: 150px"
type="primary"
@click="openTikTok"
>打开 TikTok 登录</el-button
>
<el-button
v-show="queryFormData.isRunning"
class="serch-button right-input"
@@ -101,15 +113,12 @@
v-model="searchForm.displayId"
placeholder="大哥id"
size="large"
style="width: 160px;"
style="width: 160px"
class="right-input"
clearable
/>
<el-button
class="serch-button right-input"
type="primary"
@click="serch"
<el-button class="serch-button right-input" type="primary" @click="serch"
>查询</el-button
>
@@ -126,12 +135,26 @@
@click="filterdialogVisible = true"
class="put-button buttoMore-filters"
type="primary"
><img class="filters-img" src="@/assets/filter.png"
/><div style="margin-left: 10px">
更多筛选
</div></el-button>
<!-- <el-button @click="filterdialogVisible = true" style="width: 50px;" class="put-button" type="primary"><img
style="height: 30px;" src="@/assets/filter.png"></el-button> -->
><img class="filters-img" src="@/assets/filter.png" />
<div style="margin-left: 10px">更多筛选</div></el-button
>
<el-button
class="serch-button right-input"
style="width: 150px"
type="primary"
@click="openTikTok"
>打开 TikTok 登录</el-button
>
<div
class="right-input right-text"
style="width: auto; height: 50px; line-height: 50px"
>
当前网络{{ countryData }}
</div>
<div class="right-input right-text" style="width: auto; height: 50px; line-height: 50px">
运行时间{{ String(hourstuo).padStart(2, '0') }}:{{ String(minutestuo).padStart(2, '0') }}:{{ String(secondstuo).padStart(2, '0') }}
</div>
</div>
<!-- ····················································································································· -->
<div class="hostTable center-justify">
@@ -145,7 +168,7 @@
>
<!-- <el-table-column type="selection" width="35" /> -->
<el-table-column fixed prop="displayId" label="Id" width="170">
<el-table-column fixed prop="displayId" label="Id" :width="screenWidth">
<template #default="scope">
<div class="hostIdText" @click="openHTML(scope.row.displayId)">
{{ scope.row.displayId }}
@@ -158,7 +181,7 @@
:key="label.paramCode"
:prop="label.paramCode"
:label="label.paramCodeMeaning"
width="170"
:width="screenWidth"
>
<template v-if="label.paramCode != 'createDt'" #default="scope"> </template>
</el-table-column>
@@ -283,6 +306,24 @@
</span>
</template>
</el-dialog>
<el-dialog v-model="streamdialogVisible" width="800px" :before-close="handleClose">
<div class="specify-dialog">
<el-input
v-model="textarea"
style="width: 100%"
:rows="15"
type="textarea"
placeholder="请输入直播间id多个id用回车键隔开"
@input="handleInput"
/>
<div class="specify-footer">
<el-button class="specify-button" @click="specifyCancel">取消指定直播间</el-button>
<el-button class="specify-button" type="primary" @click="specifyreset"> 重置 </el-button>
<el-button class="specify-button" type="primary" @click="specifyClick"> 确认 </el-button>
</div>
</div>
</el-dialog>
</div>
</div>
</template>
@@ -302,7 +343,10 @@ import {
} from "@/api/account";
import { usePythonBridge } from "@/utils/pythonBridge";
import { getUser, setSerch, getSerch } from "@/utils/storage";
import { ref, reactive, onMounted } from "vue";
import { ref, reactive, onMounted, onBeforeUnmount } from "vue";
const hourstuo = ref(0);
const minutestuo = ref(0);
const secondstuo = ref(0);
import EChartsComponent from "@/components/EChartsComponent.vue";
import { ElMessage, ElMessageBox } from "element-plus";
import { color } from "echarts";
@@ -310,6 +354,8 @@ import { getCountryName } from "@/utils/countryUtil";
import { ElLoading } from "element-plus";
//ip国家
let countryData = ref("");
//获取屏幕宽度
const screenWidth = ref(window.innerWidth / 11);
//获取国家
const getIpInfo = async () => {
try {
@@ -354,7 +400,9 @@ const queryFormData = ref({
coinMax: "",
levelMin: "",
levelMax: "",
isFilter: false,
isRunning: true,
anchor_ids: [],
});
//时间
const timerId = ref(null);
@@ -363,15 +411,64 @@ const getBrotherInfodata = ref({
valid: 0,
});
//结束爬取
function BigBrotherstop() {
const loading = ElLoading.service({
lock: true,
text: "正在停止...",
background: "rgba(0, 0, 0, 0.7)",
});
stopTimerfun();
isRunnings.value = false;
queryFormData.value.tenantId = userInfo.value.tenantId;
queryFormData.value.region = countryData.value;
controlTask(JSON.stringify(queryFormData.value)).then((res) => {
queryFormData.value.isRunning = true;
clearInterval(timerId.value);
timerId.value = null;
loading.close();
});
Specifystreaming(JSON.stringify(queryFormData.value)).then((res) => {
queryFormData.value.isRunning = true;
clearInterval(timerId.value);
timerId.value = null;
loading.close();
});
}
//指定直播间
function specifyClick() {
if (textarea.value == "") {
ElMessage({
type: "error",
message: "请输入直播间id",
});
return;
}
setStorageStreamId(textarea.value).then((res) => {
});
queryFormData.value.anchor_ids = textarea.value.split("\n");
streamdialogVisible.value = false;
streamdialogVisibletext.value = true;
}
//指定直播间重置
function specifyreset() {
textarea.value = "";
streamdialogVisibletext.value = false;
queryFormData.value.anchor_ids = []
}
//指定直播间取消
function specifyCancel() {
streamdialogVisible.value = false;
streamdialogVisibletext.value = false;
queryFormData.value.anchor_ids = []
}
//输入框input
function handleInput() {
streamdialogVisibletext.value = false;
}
//获取主播列表
//开始爬取
function getBigBrother() {
const loading = ElLoading.service({
lock: true,
@@ -380,15 +477,29 @@ function getBigBrother() {
});
queryFormData.value.tenantId = userInfo.value.tenantId;
queryFormData.value.region = countryData.value;
controlTask(JSON.stringify(queryFormData.value)).then((res) => {
queryFormData.value.isRunning = false;
timerId.value = setInterval(() => {
getBrotherInfo().then((res) => {
loading.close();
getBrotherInfodata.value = res;
});
}, 1000);
});
startTimerfun();
isRunnings.value = true;
if (queryFormData.value.anchor_ids == [] || queryFormData.value.anchor_ids == null || queryFormData.value.anchor_ids == undefined || queryFormData.value.anchor_ids.length == "") {
controlTask(JSON.stringify(queryFormData.value)).then((res) => {
queryFormData.value.isRunning = false;
timerId.value = setInterval(() => {
getBrotherInfo().then((res) => {
loading.close();
getBrotherInfodata.value = res;
});
}, 1000);
});
} else {
Specifystreaming(JSON.stringify(queryFormData.value)).then((res) => {
queryFormData.value.isRunning = false;
timerId.value = setInterval(() => {
getBrotherInfo().then((res) => {
loading.close();
getBrotherInfodata.value = res;
});
}, 1000);
});
}
}
const loading = ref(false);
@@ -399,6 +510,9 @@ const {
loginTikTok,
controlTask,
getBrotherInfo,
Specifystreaming,
setStorageStreamId,
getStorageStreamId
} = usePythonBridge();
let num = ref(0);
@@ -409,8 +523,8 @@ const multipleTableRef = ref(null);
let labelList = ref([
{ paramCode: "userIdStr", paramCodeMeaning: "用户id" },
{ paramCode: "level", paramCodeMeaning: "等级" },
{ paramCode: "fansLevel", paramCodeMeaning: "粉丝团等级" },
{ paramCode: "hostcoins", paramCodeMeaning: "打赏的金币" },
{ paramCode: "totalGiftCoins", paramCodeMeaning: "最低打赏金币数" },
{ paramCode: "hostDisplayId", paramCodeMeaning: "所在直播间主播id" },
{ paramCode: "region", paramCodeMeaning: "地区" },
{ paramCode: "followerCount", paramCodeMeaning: "粉丝数" },
@@ -426,8 +540,7 @@ const createTimes = ref([]);
const page = ref(1);
const pageSize = ref(10);
const fields = [
{ label: "打赏的金币", minModel: "hostcoinsMin", maxModel: "hostcoinsMax" },
{ label: "打赏金币总和", minModel: "totalGiftCoinsMin", maxModel: "totalGiftCoinsMax" },
// { label: "打赏的金币", minModel: "hostcoinsMin", maxModel: "hostcoinsMax" },
{ label: "等级", minModel: "levelMin", maxModel: "levelMax" },
];
//排序
@@ -440,23 +553,14 @@ let sortNameOptions = ref([
{ label: "打赏金币总和", type: "totalGiftCoins" },
{ label: "等级", type: "level" },
]);
//员工选择列表
let staffOptions = ref([]);
//筛选条件选择列表
//选择的员工
let staffValue = ref("");
//选择的主播列表
let selectHostList = ref([]);
//分配弹窗是否弹出
let dialogFormVisible = ref(false);
//分配情况弹窗是否弹出
let hostNameVisible = ref(false);
//备注弹窗是否弹出
let commentVisible = ref(false);
//筛选弹窗是否弹出
let filterdialogVisible = ref(false);
//是否在运行
let isRunnings = ref(false);
//是否指定直播间
let streamdialogVisibletext = ref(false);
//指定直播间弹窗
let streamdialogVisible = ref(false);
//指定直播间id
let textarea = ref("");
//分配的员工
let staffId = ref({});
//备注信息
@@ -473,10 +577,38 @@ let options = ref([]);
let version = ref("0.0.0");
onMounted(() => {
window.addEventListener("resize", handleResize);
setTimeout(() => {
getUserdata();
getStorageStreamId(1).then((res) => {
textarea.value = res == "" ? "" : JSON.parse(res);
});
}, 500);
});
// 启动计时器
function startTimerfun() {
startTime.value = setInterval(() => {
secondstuo.value++;
if (secondstuo.value >= 60) {
secondstuo.value = 0;
minutestuo.value++;
if (minutestuo.value >= 60) {
minutestuo.value = 0;
hourstuo.value++;
}
}
}, 1000);
}
// 停止计时器
function stopTimerfun() {
clearInterval(startTime.value);
}
//表格单元格长度判断
function handleResize() {
screenWidth.value = window.innerWidth / 11;
}
async function getUserdata() {
const User = await getUser();
@@ -492,21 +624,7 @@ function serch() {
}
function exportList() {
// if (searchForm.value.dataType == "InvitationType") {
// searchForm.value.dataEnd = searchForm.value.dataStart;
// }
exportToExcel(requestParams.value);
// //浏览器导出方法
// downList('export/hostsinfo',
// {
// searchTime: searchForm.value.time,
// region: searchForm.value.country,
// pageSize: pageSize.value,
// page: page.value,
// userId: userInfo.value.userId,
// }
// );
}
//分页每页条数
function handleSizeChange(val) {
@@ -562,6 +680,7 @@ const getlist = () => {
total.value = Number(res.total);
tableData.value = res.records.map((item) => ({
level: item.level, // 等级
fansLevel: item.fansLevel, // 粉丝团等级
createTime: formatDate(new Date(item.createTime)), // 创建时间
followerCount: item.followerCount, // 粉丝数
followingCount: item.followingCount, // 关注数
@@ -578,45 +697,18 @@ const getlist = () => {
function handelClick() {
filterdialogVisible.value = false;
}
function reset() {
searchForm.value = {};
sortData.value = { sortName: "createTime", sort: "desc" };
createTimes.value = [];
}
function handleClose(done) {
console.log("关闭");
done();
}
//修改主播维护状态
// function handleSelectChange(event, data) {
// upholdinfo({
// "hostId": data.hostId,
// "userId": userInfo.value.userId,
// "tenantId": userInfo.value.tenantId,
// // "comment": "我已经尽力维护,但是失败了",
// "useable": event.target.value
// }).then(res => {
// console.log(res)
// })
// }
//更改主播维护备注
// function uphostcomment() {
// upholdinfo({
// "hostId": commentHost.value,
// "userId": userInfo.value.userId,
// "tenantId": userInfo.value.tenantId,
// "comment": commentInfo.value,
// }).then(res => {
// console.log(res)
// serch()
// commentVisible.value = false
// })
// }
function filterTag(value, row) {
console.log(row.useable, value);
return row.useable === value;
@@ -626,7 +718,6 @@ function filterTag(value, row) {
function getCountry() {
getCountryinfo({})
.then((res) => {
console.log("````````国家`````````", res);
res.forEach((item) => {
if (item.countryGroupName) {
options.value.push({
@@ -635,60 +726,12 @@ function getCountry() {
});
}
});
console.log("````````国家2`````````", options.value);
})
.catch((err) => {
console.log("getCountry", err);
});
}
//获取下级员工
// const getStaff = () => {
// getStaffList({
// userId: userInfo.value.userId,
// activeYn: userInfo.value.activeYn,
// tenantId: userInfo.value.tenantId,
// }).then(res => {
// console.log(res)
// res.forEach(item => {
// staffOptions.value.push({
// value: item.userId,
// label: item.userName
// })
// })
// })
// }
// //分配主播给员工
// function allocation() {
// managerhosts({
// "manaId": userInfo.value.userId,
// "userId": staffValue.value,
// "tenantId": userInfo.value.tenantId,
// "hostIds": selectHostList.value
// }).then(res => {
// if (res) {
// dialogFormVisible.value = false
// }
// })
// }
//获取主播信息
// const getTkhostdetail = (id) => {
// tkhostdetail({
// hostId: id,
// // page: 1,
// searchTimeStart: '20250401',
// searchTimeEnd: '20250403'
// }).then(res => {
// console.log(labelList.value)
// })
// }
function openPopover(hostId, paramCode) {
isPopoverVisible[`${hostId}-${paramCode}`] = true;
}
@@ -701,30 +744,7 @@ function openHTML(id) {
console.log(id);
givePyAnchorId(id);
// upholdinfo({
// "hostId": id,
// "userId": userInfo.value.userId,
// "tenantId": userInfo.value.tenantId,
// // "comment": "我已经尽力维护,但是失败了",
// "useable": "Y"
// }).then(res => {
// getlist();
// })
}
// function openAccountName(idStr) {
// if (idStr) {
// hostNameVisible.value = true
// accountName(idStr).then(res => {
// staffId.value = JSON.stringify(res).replace(/[{}"]/g, '') // 移除所有 {} 和 "
// .split(',') // 按逗号分割成数组
// console.log(res)
// })
// }
// }
</script>
<style lang="less">
@@ -734,10 +754,10 @@ function openHTML(id) {
padding: 40px;
/* 页面无法选中 */
// -webkit-user-select: none;
// -moz-user-select: none;
// -ms-user-select: none;
// user-select: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
.hostTable {
width: 100%;
@@ -764,11 +784,14 @@ function openHTML(id) {
border-radius: 10px;
border: none;
}
.Specify {
margin-left: 20px;
}
}
.buttoMore-filters{
.buttoMore-filters {
width: 150px;
}
.filters-img{
.filters-img {
width: 30px;
}
.el-dialog {
@@ -823,8 +846,25 @@ function openHTML(id) {
.right-input {
margin-left: 20px;
}
.right-text{
.isFilter {
margin-right: 20px;
height: 47px;
}
.right-text {
color: #666;
font-size: 16px;
}
.specify-dialog {
height: 400px;
}
.specify-footer{
width: 100%;
display: flex;
justify-content:space-around;
margin-top: 20px;
}
.specify-button{
width: 200px;
height: 50px;
}
</style>

View File

@@ -0,0 +1,47 @@
<template>
<div class="miniAM">
<div class="noData">
暂无数据
</div>
</div>
</template>
<script setup>
import {
ref, // 响应式基础
watch, // 侦听器
onMounted, // 组件挂载完成后执行
onUpdated, // 组件更新后执行
onUnmounted, // 组件销毁前执行
} from "vue";
const refname = ref('');
watch(refname, async (newQuestion, oldQuestion) => {
// 变化后执行
});
onMounted(() => {
// 组件挂载完成后执行
});
onUpdated(() => {
// 组件更新后执行
});
onUnmounted(() => {
// 组件销毁前执行
});
</script>
<style scoped>
.miniAM {
width: 100%;
height: 100%;
background-color: #ffffff;
border-radius: 10px;
display: flex;
justify-content: center;
align-items: center;
}
.noData{
font-size: 20px;
color: #999999;
}
/* 样式定义 */
</style>

View File

@@ -0,0 +1,315 @@
<template>
<div class="mini-integral">
<div class="content">
<!-- 积分配置列表 -->
<div class="integral-list">
<el-table
:data="tableData"
stripe
style="width: 100%; margin-top: 10px"
max-height="700"
>
<el-table-column prop="functionName" label="事件" />
<el-table-column prop="" label="" />
<el-table-column prop="functionValue" label="积分" />
<el-table-column prop="" label="" />
<el-table-column label="操作">
<template #default="scope">
<el-button size="small" @click="miniIntegralEdit(scope.$index, scope.row)">
修改
</el-button>
<el-button
size="small"
type="danger"
@click="miniIntegralDelete(scope.$index, scope.row)"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
<!-- 积分配置 -->
<div class="integral-title">
<div class="add" @click="dialogVisible = true">
<img class="add-img" src="@/assets/plus2.png" alt="">
</div>
<div class="integral-text">
<div class="h1"></div>
<div class="h1"></div>
<div class="h1"></div>
<div class="h1"></div>
<div class="h1"></div>
<div class="h1"></div>
<div class="h1"></div>
</div>
</div>
</div>
</div>
<!-- 新增修改积分配置弹窗 -->
<el-drawer v-model="dialogVisible" :with-header="false" @close="dialogVisible = false, miniIntegraldeta = {}">
<div class="dialog-content">
<div class="dialog-title">事件{{miniIntegraldeta.id? '编辑' : '新增'}}</div>
<el-input
v-if="!miniIntegraldeta.id"
v-model="miniIntegraldeta.functionName"
style="width: 100%; margin-top: 20px"
:rows="3"
type="textarea"
placeholder="请输入事件名称"
/>
<el-input
v-model="miniIntegraldeta.functionValue"
style="width: 100%;height: 50px; margin-top: 20px"
type="number"
placeholder="请输入积分值"
/>
<div class="dialog-btn">
<div class="dialogSave" @click="miniIntegralAddSave">保存</div>
<div class="dialogCancel" @click="dialogVisible = false">取消</div>
</div>
</div>
</el-drawer>
</template>
<script setup>
import { ElMessage, ElMessageBox } from "element-plus";
import {
getWxConfigList,
addWxConfig,
editWxConfig,
deleteWxConfig,
} from "@/api/account";
import {
ref, // 响应式基础
watch, // 侦听器
onMounted, // 组件挂载完成后执行
onUpdated, // 组件更新后执行
onUnmounted, // 组件销毁前执行
} from "vue";
const refname = ref("");
const tableData = ref([]);
const dialogVisible = ref(false);
const miniIntegraldeta = ref({});
//保存积分配置
function miniIntegralAddSave() {
if (!miniIntegraldeta.value.functionName) {
ElMessage({
type: "error",
message: "事件名称不能为空",
});
return;
}
if (!miniIntegraldeta.value.functionValue) {
ElMessage({
type: "error",
message: "积分值不能为空",
});
return;
}
if (miniIntegraldeta.value.id) {
// 修改积分配置
editWxConfig(miniIntegraldeta.value)
.then(() => {
ElMessage({
type: "success",
message: "修改成功",
});
dialogVisible.value = false;
miniIntegraldeta.value = {};
getIntegralList()
})
.catch(() => {
ElMessage({
type: "error",
message: "修改失败",
});
});
} else {
// 新增积分配置
addWxConfig(miniIntegraldeta.value)
.then(() => {
ElMessage({
type: "success",
message: "新增成功",
});
dialogVisible.value = false;
miniIntegraldeta.value = {};
getIntegralList()
})
.catch(() => {
ElMessage({
type: "error",
message: "新增失败",
});
});
}
}
// 新增积分配置弹窗
function miniIntegralEdit(index, row) {
dialogVisible.value = true;
miniIntegraldeta.value = row;
}
//删除积分配置
function miniIntegralDelete(index, row) {
ElMessageBox.confirm("您确认要删除这个积分配置吗?")
.then(() => {
deleteWxConfig({ id: row.id })
.then(() => {
ElMessage({
type: "success",
message: "删除成功",
});
getIntegralList()
})
.catch(() => {
ElMessage({
type: "error",
message: "删除失败",
});
});
})
.catch(() => {});
}
// 获取积分配置列表
function getIntegralList() {
getWxConfigList()
.then((res) => {
tableData.value = res;
})
.catch(() => {
ElMessage({
type: "error",
message: "获取积分配置列表失败",
});
});
}
watch(refname, async (newQuestion, oldQuestion) => {
// 变化后执行
});
onMounted(() => {
getIntegralList();
});
onUpdated(() => {
// 组件更新后执行
});
onUnmounted(() => {
// 组件销毁前执行
});
</script>
<style scoped>
.mini-integral {
width: 100%;
height: 100%;
background-color: #ffffff;
border-radius: 10px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.content {
width: 80%;
height: 80%;
background-color: #f5f5f5;
border-radius: 10px;
display: flex;
justify-content: space-between;
align-items: center;
padding: 20px;
box-shadow: 2px 4px 8px rgba(0, 0, 0, 0.3);
padding: 40px;
}
.integral-list{
width: 87%;
height: 100%;
background-color: #ffffff;
border-radius: 10px;
}
.integral-title{
width: 10%;
height: 100%;
background-color: #ffffff;
border-radius: 10px;
}
.add{
width: 100%;
height: 50px;
display: flex;
justify-content: center;
align-items: center;
background-color: #c4c4c4;
border-radius: 10px 10px 0 0;
}
.add:hover{
background-color: #a9a9a9;
}
.add-img{
width: 40px;
height: 40px;
}
.integral-text{
width: 100%;
height: 520px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: 20px;
color: #c4c4c4;
font-size: 25px;
font-family: "SimSun", "Microsoft YaHei", sans-serif;
}
.h1{
margin-top: 10px;
margin-bottom: 10px;
}
.dialog-title {
width: 100%;
height: 50px;
font-size: 25px;
color: #b4b4b4;
font-weight: bold;
margin-top: 20px;
margin-bottom: 20px;
text-align: center;
}
.dialog-btn {
margin-top: 20px;
display: flex;
justify-content: space-between;
}
.dialogSave {
width: 45%;
height: 50px;
background-color: #d6d6d6;
line-height: 50px;
text-align: center;
font-weight: bold;
border-radius: 5px;
font-size: 16px;
color: #ffffff;
}
.dialogSave:hover {
background-color: #b4b4b4;
}
.dialogCancel {
width: 45%;
height: 50px;
line-height: 50px;
text-align: center;
font-weight: bold;
border-radius: 5px;
font-size: 16px;
color: #d6d6d6;
border: 1px solid #d6d6d6;
}
.dialogCancel:hover {
background-color: #e7e6e6;
color: #ffffff;
}
/* 样式定义 */
</style>

View File

@@ -9,32 +9,46 @@
<hostsList />
</div>
<!-- <div style="position: absolute; bottom: 0; right: 0;">{{ version }}</div> -->
</div>
<div class="footer">
到期时间{{ time }}
</div>
</div>
</template>
<script setup>
import { ref, reactive, onMounted } from "vue";
// import Sidebar from '../components/Sidebar.vue';
import { RouterLink, RouterView } from 'vue-router'
import hostsList from '@/views/hosts/hostsList.vue'
import { ElMessage } from 'element-plus';
import { getUser } from "@/utils/storage";
// import workbenches from '@/views/hosts/workbenches.vue'
import { ref } from 'vue'
import { getUser } from '@/utils/storage'
// import { usePythonBridge } from '@/utils/pythonBridge'
// let activeIndexA = ref(1)
// function activeIndexFn(data) {
// activeIndexA.value = data
// console.log(data)
// }
import { tokenStore,UserStore } from '@/stores/notice'
const userCache = UserStore()
const time = ref(formatTimestamp(userCache.user.brotherExpireTime))
// 时间格式化方法 - 将12位时间戳转为YYYY-MM-DD HH:mm:ss格式
function formatTimestamp(timestamp) {
try {
// 转换为数字
const ts = Number(timestamp);
if (isNaN(ts)) {
return '--';
}
// 处理13位时间戳毫秒级
const date = new Date(ts > 999999999999 ? ts : ts * 1000);
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
const seconds = String(date.getSeconds()).padStart(2, '0');
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
} catch (e) {
console.error('时间格式化错误:', e);
return '--';
}
}
</script>
@@ -45,6 +59,11 @@ html {
margin: 0;
padding: 0;
height: 100%;
/* 页面无法选中 */
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.app-container {
@@ -77,7 +96,7 @@ html {
margin-left: 25px;
margin-right: 25px;
width: 1540px;
height: 868px;
height: 848px;
background: #FFFFFF;
border-radius: 36px;
margin-top: 16px;
@@ -88,4 +107,11 @@ html {
justify-content: space-around;
align-items: center;
}
.footer{
position: absolute;
bottom: 10px;
left: calc(50% - 150px);
color: aqua;
font-size: 16px;
}
</style>