查询列表功能

This commit is contained in:
2025-04-03 16:41:54 +08:00
parent cd884686ce
commit 32cbc6404a
15 changed files with 951 additions and 226 deletions

View File

@@ -1,32 +1,5 @@
<template>
<div>
<nav>
<!-- <router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link> -->
</nav>
<router-view />
</div>
</template>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
nav {
padding: 30px;
}
nav a {
font-weight: bold;
color: #2c3e50;
}
nav a.router-link-exact-active {
color: #42b983;
}
</style>

17
src/api/account.js Normal file
View File

@@ -0,0 +1,17 @@
import { getAxios, postAxios } from '@/utils/axios.js'
export function apiGetCart() {
return getAxios({ url: '/cgi-bin/cart/latest' })
}
export function login(data) {
return postAxios({ url: 'account/login', data })
}
export function cheekalive(data) {
return postAxios({ url: 'account/cheekalive', data })
}
export function tkhostdata(data) {
return postAxios({ url: 'tkinfo/tkhostdata', data })
}
export function dicts(data) {
return postAxios({ url: 'param/dicts', data })
}

View File

@@ -1,14 +0,0 @@
import { getAxios, postAxios } from '@/utils/axios.js'
export function apiGetListXX(data) {
return postAxios({ url: '/cgi-bin/draft/batchget', data })
}
export function apiAddXX(data) {
return postAxios({ url: '/cgi-bin/draft/add', data })
}
export function apiGetCart() {
return getAxios({ url: '/cgi-bin/cart/latest' })
}
export function test() {
return getAxios({ url: 'https://share.gdaiyy.com/zhihui_config.json' })
}

View File

@@ -8,9 +8,12 @@
</p>
<h3>Installed CLI Plugins</h3>
<ul>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" target="_blank" rel="noopener">babel</a></li>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-router" target="_blank" rel="noopener">router</a></li>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-vuex" target="_blank" rel="noopener">vuex</a></li>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" target="_blank"
rel="noopener">babel</a></li>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-router" target="_blank"
rel="noopener">router</a></li>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-vuex" target="_blank"
rel="noopener">vuex</a></li>
</ul>
<h3>Essential Links</h3>
<ul>
@@ -24,7 +27,8 @@
<ul>
<li><a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a></li>
<li><a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a></li>
<li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a></li>
<li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a>
</li>
<li><a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a></li>
<li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li>
</ul>
@@ -45,14 +49,17 @@ export default {
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}

View File

@@ -3,11 +3,14 @@ import App from './App.vue'
import router from './router'
import store from './store'
import { createPinia } from 'pinia';
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
// createApp(App).use(store).use(router).mount('#app')
const app = createApp(App);
app.use(ElementPlus) // 注册 ElementPlus
app.use(createPinia()); // 注册 Pinia
app.use(store); // 注册 store
app.use(router); // 注册 router

View File

@@ -8,12 +8,9 @@ const routes = [
component: HomeView
},
{
path: '/about',
name: 'about',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue')
path: '/hostsList',
name: 'hostsList',
component: () => import(/* webpackChunkName: "hostsList" */ '../views/hostsList.vue')
}
]

View File

@@ -3,12 +3,18 @@
* https://rudon.blog.csdn.net/
*/
import axios from 'axios'
import { getToken, setToken, removeToken } from '@/utils/storage'
import { getToken, getUser } from '@/utils/storage'
import { useRouter } from 'vue-router';
import { ElMessage } from 'element-plus';
const router = useRouter();
// 请求地址前缀
let baseURL = ''
if (process.env.NODE_ENV === 'production') {
console.log(process.env.NODE_ENV)
if (process.env.NODE_ENV === 'development') {
// 生产环境
baseURL = ""
baseURL = "http://192.168.0.119:8080/api/"
} else {
// 开发环境
baseURL = ""
@@ -16,14 +22,15 @@ if (process.env.NODE_ENV === 'production') {
// 请求拦截器
axios.interceptors.request.use((config) => {
if (getToken()) {
config.headers['token'] = getToken();
}
// if (getToken()) {
// config.headers['token'] = getToken();
// }
// 请求超时时间 - 毫秒
config.timeout = 10000
config.timeout = 60000
config.baseURL = baseURL
// 自定义Content-type
// config.headers['Content-type'] = 'application/json'
config.headers['Content-type'] = 'application/json'
return config;
}, (error) => {
return Promise.reject(error)
@@ -65,6 +72,34 @@ export function getAxios({ url, params }) {
// axios的post请求
export function postAxios({ url, data }) {
if (url != 'account/login') {
axios.post('account/cheekalive', {
userId: getUser().userId,
currcode: getToken(),
},
{
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}
).then(res => {
console.log(res)
}).catch(err => {
if (err.message == "Network Error") {
// alert("网络错误,请检查网络连接")
ElMessage.error('网络连接错误');
} else {
ElMessage.error(err.message);
}
// console.log(err)
// reject(err)
})
}
return new Promise((resolve, reject) => {
axios.post(
url,
@@ -77,7 +112,14 @@ export function postAxios({ url, data }) {
).then(res => {
resolve(res.data)
}).catch(err => {
reject(err)
if (err.message == "Network Error") {
// alert("网络错误,请检查网络连接")
ElMessage.error('网络连接错误');
} else {
ElMessage.error(err.message);
}
// console.log(err)
// reject(err)
})
})
}

37
src/utils/pythonBridge.js Normal file
View File

@@ -0,0 +1,37 @@
// pythonBridge.js
import { ref, onMounted } from 'vue';
export function usePythonBridge() {
const bridge = ref(null);
// 初始化 QWebChannel
const initBridge = () => {
new QWebChannel(qt.webChannelTransport, (channel) => {
bridge.value = channel.objects.bridge;
});
};
// 调用 Python 方法
const callPython = (data) => {
if (bridge.value) {
bridge.value.stringFromJs(data);
}
};
// 从 Python 获取数据
const getPythonData = () => {
if (bridge.value) {
bridge.value.stringToJs(function (result) {
alert(result);
});
}
};
// 在组件挂载时初始化桥接
onMounted(initBridge);
return {
callPython,
getPythonData
};
}

View File

@@ -1,11 +1,20 @@
export default {
getToken() {
return localStorage.getItem('token');
},
setToken(token) {
localStorage.setItem('token', token);
},
removeToken() {
localStorage.removeItem('token');
}
export function setToken(token) {
localStorage.setItem('token', token);
}
export function getToken() {
return localStorage.getItem('token');
}
export function removeToken() {
localStorage.removeItem('token');
}
export function setUser(user) {
localStorage.setItem('user', JSON.stringify(user));
}
export function getUser() {
return JSON.parse(localStorage.getItem('user'));
}

View File

@@ -1,5 +0,0 @@
<template>
<div class="about">
<h1>This is an about page</h1>
</div>
</template>

View File

@@ -1,152 +1,219 @@
<template>
<div>
<button @click="callPython">设置数据"123" Python</button>
<button @click="getPythonData"> Python 获取数据</button>
<button @click="clickChildButton">从tk模拟点击按钮 </button>
<input type="text" id="input" v-model="inputValue"></input>
<div id="output">{{ output }}</div>
<h1>嵌入tk页面</h1>
<iframe id="myIframe" src="https://live-backstage.tiktok.com/portal/overview" width="100%" height="600px"
frameborder="0" ref="myIframe"></iframe>
</div>
<div class="main">
<!-- <button @click="callPython">设置数据"123" Python</button>
<button @click="getPythonData"> Python 获取数据</button> -->
<!-- <input type="text" id="input" v-model="inputValue"></input>
<div id="output">{{ output }}</div> -->
<div class="container">
<div class="left">
</div>
<div class="right">
<!-- 设置 -->
<div class="center-align">
<div></div>
<div class="setup">
<div class="setup-item center-justify">
<div></div>
<span>
网络设置
</span>
</div>
<div class="setup-item center-justify">
<div></div>
<span>
简体中文
</span>
</div>
</div>
</div>
<!-- logo -->
<div class="logo">
<div style="height: 80px; width: 300px; background-color: aqua;">
</div>
</div>
<!-- From -->
<div class="from">
<div class="from-title">
<div>账号登陆</div>
</div>
<div class="from-input">
<el-form label-position="left" label-width="100px" :model="formData">
<div class="from-input-item">
<div class="from-input-item-title center-justify">
账号
</div>
<el-input style="height: 50px;" v-model="formData.userId" placeholder="请输入登录账号"
clearable />
</div>
<div class="from-input-item">
<div class="from-input-item-title center-justify">
密码
</div>
<el-input style="height: 50px;" v-model="formData.password" type="password"
placeholder="请输入登录密码" show-password />
</div>
<div class="from-input-item">
<el-button style="width: 100%; height: 40px;" type="primary"
@click="onSubmit">登录</el-button>
</div>
</el-form>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import { ref, reactive, onMounted } from 'vue';
import { useRouter } from 'vue-router';
import { login } from '@/api/account';
import { getToken, setToken, setUser } from '@/utils/storage'
const myIframe = ref(null);
let inputValue = ref('999');
// 确保 DOM 渲染完成后再访问 iframe
onMounted(() => {
if (myIframe.value) {
// console.log('Iframe mounted:', myIframe.value);
onIframeLoad();
}
});
const router = useRouter();
const onIframeLoad = () => {
if (myIframe.value) {
const iframeDoc = myIframe.value.contentDocument;
// import { usePythonBridge } from '@/utils/pythonBridge';
// const button = iframeDoc.querySelector('button[data-id="add-host-btn"]')[0];
// if (button) {
// button.click(); // 触发点击事件
// }
// let inputValue = ref('999');
// const output = ref('');
// const { callPython, getPythonData } = usePythonBridge();
const formData = ref({
userId: '',
password: '',
})
const onSubmit = () => {
console.log('submit!')
login({
userId: formData.value.userId,
password: formData.value.password,
}).then(res => {
console.log(res)
setToken(res.currcode)
setUser(res)
router.push('/hostsList');
})
console.log('Iframe loaded:', iframeDoc);
if (iframeDoc) {
// console.log('Iframe loaded:', iframeDoc);
}
// 注入脚本
const script = iframeDoc.createElement('script');
// console.log('script:', script);
script.textContent = `
(function() {
// 拦截 XMLHttpRequest
const originalOpen = XMLHttpRequest.prototype.open;
const originalSend = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.open = function(method, url, async, user, password) {
this._method = method; // 保存请求方法
this._url = url; // 保存请求的URL
return originalOpen.apply(this, arguments);
};
XMLHttpRequest.prototype.send = function(body) {
if (this._url && this._url.includes('batch_check_anchor')) {
this.addEventListener('load', function() {
console.log('[XHR] 拦截到 batch_check_anchor 请求:');
console.log('URL:', this._url);
console.log('方法:', this._method);
console.log('请求体:', body);
console.log('响应:', this.responseText);
console.log('------------------------');
});
}
return originalSend.apply(this, arguments);
};
// 拦截 fetch
const originalFetch = window.fetch;
window.fetch = async function(...args) {
const [input, init] = args;
const url = typeof input === 'string' ? input : input.url;
if (url && url.includes('batch_check_anchor')) {
console.log('[Fetch] 拦截到 batch_check_anchor 请求:');
console.log('URL:', url);
console.log('方法:', (init && init.method) || 'GET');
console.log('请求体:', (init && init.body) || null);
const response = await originalFetch.apply(this, args);
const clonedResponse = response.clone();
try {
const data = await clonedResponse.json();
console.log('响应:', data);
} catch (e) {
const text = await clonedResponse.text();
console.log('响应:', text);
}
console.log('------------------------');
return response;
}
return originalFetch.apply(this, args);
};
console.log('batch_check_anchor 拦截器已成功注入');
console.log("123123123123132",document.querySelectorAll('button[data-id="view-more"]'))
})();
`;
iframeDoc.body.appendChild(script);
} else {
console.error('无法访问 iframe 的 contentDocument');
}
console.log(123)
} else {
console.error('无法获取 iframe 引用');
}
};
const output = ref('');
const bridge = ref(null);
onMounted(() => {
new QWebChannel(qt.webChannelTransport, function (channel) {
bridge.value = channel.objects.bridge;
});
});
const callPython = () => {
if (bridge.value) {
bridge.value.stringFromJs("123")
}
};
const getPythonData = () => {
if (bridge.value) {
bridge.value.stringToJs(function (result) {
alert(result); // 这里才会显示返回值
});
}
};
const clickChildButton = () => {
const iframeDoc = myIframe.value.contentDocument;
console.log(iframeDoc)
// 查找子页面中的按钮(假设按钮 id 为 child-button
};
</script>
<style lang="less">
.main {
height: 100vh;
width: 100vw;
// background-color: #ffffff;
.container {
display: flex;
.left {
width: 40%;
height: 100vh;
background-color: #1db97d;
padding: 20px 40px;
}
.right {
width: 60%;
height: 100vh;
background-color: #ffffff;
padding: 20px 40px 20px 50px;
.setup {
display: flex;
.setup-item {
padding: 10px 6px;
display: flex;
div {
width: 20px;
height: 20px;
border-radius: 50%;
background-color: red;
margin-right: 5px;
}
}
}
.logo {
padding: 20px 0;
}
.from {
.from-title {
display: flex;
padding: 10px 0 0 0;
div {
font-size: 20px;
font-weight: 600;
border-bottom: 4px solid #1db97d;
}
}
.from-input {
width: 100%;
padding: 15px 0;
.from-input-item {
display: flex;
padding: 20px 0;
.from-input-item-title {
width: 80px;
height: 50px;
}
}
}
}
}
}
}
.center-line {
display: flex;
flex-direction: column;
align-items: center;
// justify-content: center;
}
.center-justify {
display: flex;
justify-content: space-around;
align-items: center;
}
.center-align {
display: flex;
justify-content: space-between;
}
.center-flex {
display: flex;
justify-content: center;
align-items: center;
}
</style>

156
src/views/hostsList.vue Normal file
View File

@@ -0,0 +1,156 @@
<template>
<div class="main">
<div>
<div>
<el-select v-model="searchForm.country" placeholder="选择国家" size="large" style="width: 240px">
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
<el-date-picker v-model="searchForm.time" type="date" value-format="YYYYMMDD" placeholder="选择查询时间" size="large"
style="margin-left: 50px;" />
<el-button style="margin-left: 50px;" type="primary" @click="serch">查询</el-button>
</div>
<!-- <el-button type="primary" @click="getlist">查询列表</el-button>
<el-button type="primary" @click="getdictionary">查询字典</el-button> -->
</div>
<div style="width: 100%;" class="center-justify">
<el-table :data="tableData" stripe style="width: 100%">
<el-table-column prop="hostId" label="主播id" width="180" />
<el-table-column prop="hostName" label="主播名字" min-width="200" />
<el-table-column v-for="label in labelList" :prop="label.paramCode" :label="label.paramCodeMeaning"
width="150" />
</el-table>
</div>
<div class="center-justify" style="margin-top: 30px;">
<el-pagination :default-current-page="4" v-model:current-page="page" background layout="prev, pager, next"
:total="total" @change="serch" />
</div>
</div>
</template>
<script setup>
import { getToken, setToken, removeToken } from '@/utils/storage'
import { tkhostdata, dicts } from '@/api/account';
import { ref, reactive, onMounted } from 'vue';
let labelList = ref([])
const tableData = ref([])
//选择国家
const searchForm = ref({
country: '',
time: ''
})
//分页
let pageSize = ref(10)
let page = ref(1)
let total = ref(0)
const options = [
{
value: '日本',
label: '日本',
},
{
value: '美国',
label: '美国',
},
{
value: '荷兰',
label: '荷兰',
},
{
value: '澳大利亚',
label: '澳大利亚',
}
]
onMounted(() => {
getdictionary()
})
function serch() {
console.log("pageSize.value", pageSize.value)
console.log("page.value", page.value)
console.log("searchForm.value.country", searchForm.value.country)
console.log("time.value", searchForm.value.time)
getdictionary();
getlist();
}
const getlist = () => {
tkhostdata({
searchTime: searchForm.value.time,
region: searchForm.value.country,
pageSize: pageSize.value,
page: page.value
}).then(res => {
total.value = res.total
tableData.value = []
res.records.forEach(item => {
item = { ...item, ...item.infoMap }
console.log(item)
tableData.value.push(item)
})
console.log(tableData.value)
})
}
const getdictionary = () => {
dicts({
paramType: "hostsdata",
// page: 1,
offset: 1,
pageSize: 100
}).then(res => {
// labelList.value = res.records
labelList.value = res
console.log(labelList.value)
})
}
</script>
<style lang="less">
.main {
height: 100vh;
width: 100vw;
}
.center-line {
display: flex;
flex-direction: column;
align-items: center;
// justify-content: center;
}
.center-justify {
display: flex;
justify-content: space-around;
align-items: center;
}
.center-align {
display: flex;
justify-content: space-between;
}
.center-flex {
display: flex;
justify-content: center;
align-items: center;
}
</style>