You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

741 lines
24 KiB
HTML

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!--
* @Description:
* @Autor: 飘泊客
* @Date: 2023-01-30 16:40:50
* @LastEditors: 飘泊客
* @LastEditTime: 2023-03-24 19:00:14
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title></title>
<link rel="shortcut icon" href="https://baiyee.vip/favicon.ico">
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js"></script>
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
<script src="https://cdn.jsdelivr.net/npm/js-cookie@2/src/js.cookie.min.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="./auth.js"></script>
</head>
<body>
<div id="app">
<!-- <header class="u-flex u-flex-between">
顶部信息
<at-button size="small" @click="showLoginProp">添加</at-button>
</header> -->
<!-- <at-button @click="showMessage1">get1</at-button> -->
<div class="account-wrap">
<div class="account-list-wrap">
<header>
<div class="p-10">
<el-popover
v-model="visible"
placement="bottom"
width="320"
trigger="manual">
<div>
<el-form ref="form" :model="form" label-width="0">
<el-form-item >
<el-input v-model="form.nickName" size="small" placeholder="搜索账号" style="width: 100%;"></el-input>
</el-form-item>
<el-form-item>
<el-select v-model="form.terrace" placeholder="平台" size="small" style="width: 100%;">
<el-option label="小红书" value="1"></el-option>
</el-select>
</el-form-item>
<!-- <el-form-item>
<el-select v-model="form.status" placeholder="状态" size="small" style="width: 100%;">
<el-option label="已登录" value="1"></el-option>
<el-option label="未登录" value="2"></el-option>
</el-select>
</el-form-item> -->
<el-form-item style="text-align: right;">
<el-button size="small" @click="initAccount" >重置</el-button>
<el-button type="primary" size="small" @click="toSearch" >搜索</el-button>
</el-form-item>
</el-form>
</div>
<el-input slot="reference" size="small" placeholder="搜索账号" readonly suffix-icon="el-icon-search" @focus="visible = !visible" />
</el-popover>
</div>
<div class="u-flex u-flex-between" style="padding: 0 10px 10px;">
<el-button size="small" type="primary" icon="el-icon-plus" @click="addGroupProp">分类组</el-button>
<el-button size="small" type="primary" icon="el-icon-plus" @click="openSelect">账号</el-button>
</div>
</header>
<div class="account-list-content mt-5 sim-cont">
<el-menu
v-if="accountList.length > 0"
:default-active="activeName"
class="el-menu-vertical-demo"
@select="changAccountSelect"
style="width: 202px;"
:unique-opened="true"
>
<el-submenu v-for="(item, index) in accountList" :index="index">
<template slot="title">
<span>{{ item.groupName }}</span>
</template>
<el-menu-item-group v-for="(it, idx) in item.childList" :key="idx" title="">
<el-menu-item :index="index + '-' + idx">
<div class="u-flex account-item">
<img :src="it.avater" class="u-avater" :class="{'u-filter': it.loginStatus == 2}">
<div class="ml-5 account-item-right" :class="{'u-filter': it.loginStatus == 2}">
<span class="account-list-name">{{ it.nickName }}</span>
<span class="line-span">{{ it.type == 1 ? '小红书' : '未知' }}</span>
</div>
</div>
</el-menu-item>
</el-menu-item-group>
</el-submenu>
</el-menu>
<div v-else>
<el-empty description="快去添加账号吧~"></el-empty>
</div>
</div>
</div>
<div class="account-tabs-wrap">
<div class="at-tabs">
<el-tabs v-model="activeTabName" closable @tab-click="handleTabClick" @tab-remove="handleTabRemove">
<el-tab-pane v-for="(item, index) in tabList" :key="item.characteristic" :name="item.characteristic" >
<div slot="label" class="u-flex">
<el-avatar size="small" shape="circle" :src="item.avater"></el-avatar>
<span class="ml-5">{{ item.type == 1 ? '小红书' : '未知' }}-{{ item.label }}</span>
</div>
<div class="tab-web-view">
<div class="ant-tabs-content">
<webview :id="item.characteristic" :src="item.url" :partition="item.partition" style="width: 100%; height: 100%; border: 0px;"/>
</div>
</div>
</el-tab-pane>
</el-tabs>
</div>
</div>
</div>
<el-dialog
title=""
:visible.sync="addAcount"
class="loginProp"
width="98vw"
>
<div id="login" ref="login" style="height: 820px;width: 100%;"></div>
<!-- <at-button @click="showMessage1">get1</at-button> -->
</el-dialog>
<el-dialog
title="新增账号"
:visible.sync="selectProp"
:close-on-click-modal="false"
:close-on-press-escape="false"
:show-close="false"
width="30%"
>
<el-select v-model="groupRegion" size="small" placeholder="选择分类组" style="width: 100%;">
<el-option v-for="(item, index) in accountList" :label="item.groupName" :value="item.groupId" />
</el-select>
<span slot="footer" class="dialog-footer">
<el-button size="small" @click="closeSelect">取 消</el-button>
<el-button size="small" type="primary" @click="showLoginProp">确 定</el-button>
</span>
</el-dialog>
</div>
</body>
<script>
// const request = require('request')
// var request = require('sync-request')
const session = require('express-session')
new Vue({
el: '#app',
data: {
addAcount: false,
selectProp: false,
addPartition: '',
seachName: '',
visible: false,
activeName: '', // 当前active
activeTabName: '', // 当前tab
groupRegion: '', // 新增的组
vwId: '', // 生成主键
tabList: [], // 账号列表
form: {
nickName: '',
terrace: '1',
status: ''
},
routerInterval: null,
accountList: [
// {
// groupName: '幽密蘑菇林',
// groupId: '10',
// childList: [
// {
// id: '1',
// nickName: '蘑菇',
// label: '蘑菇',
// characteristic: 'webview_F8As5EnDBf',
// partition: 'persist:F8As5EnDBf',
// url: 'https://creator.xiaohongshu.com/creator/home',
// avater: 'https://pic4.zhimg.com/80/v2-7e84978160b3dc2b2733000a01c408cb_720w.webp',
// personal_desc: '无',
// type: 1
// },
// {
// id: '2',
// nickName: '呀哈哈',
// label: '呀哈哈',
// characteristic: 'webview_P00MJiPZ1L',
// partition: 'persist:P00MJiPZ1L',
// url: 'https://creator.xiaohongshu.com/creator/home',
// avater: 'https://pic4.zhimg.com/80/v2-7e84978160b3dc2b2733000a01c408cb_720w.webp',
// personal_desc: '无',
// type: 1
// }
// ]
// }
]
},
mounted() {
// 取出cookie 暂不处理
// 解密拼接
// 传值iframe
this.accountList = JSON.parse(localStorage.getItem('accountList')) || []
this.tabList = JSON.parse(localStorage.getItem('tabList')) || []
console.log('accountList=', this.accountList)
this.$nextTick(() => {
if (this.accountList.length > 0 && this.tabList.length > 0) {
// this.activeName = this.accountList[0].childList[0].characteristic
this.activeTabName = this.tabList[0].characteristic
}
})
},
methods: {
closeSelect() {
this.groupRegion = ''
this.selectProp = false
},
addGroupProp() {
this.$prompt('请输入分类名', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消'
}).then(({ value }) => {
let obj = {
groupName: value,
groupId: getRandomAlphaNum(3),
childList: []
}
this.accountList.push(obj)
localStorage.setItem('accountList', JSON.stringify(this.accountList))
}).catch(() => {});
},
// tabclose
handleTabClick(e) {
// this.activeName = e.name
},
// 打开账号添加
openSelect() {
this.initAccount()
this.selectProp = true
},
// 重置搜索
initAccount() {
this.visible = false
this.form.nickName = ''
this.accountList = JSON.parse(localStorage.getItem('accountList')) || []
},
// 搜索
toSearch() {
const accList = JSON.parse(localStorage.getItem('accountList')) || []
let arr = []
accList.forEach(item => {
arr = [...arr, ...item.childList.filter(it => it.nickName.search(this.form.nickName) !== -1)]
})
let obj = {
groupName: '共搜索到' + arr.length + '条',
groupId: '01',
childList: arr
}
this.accountList = [obj]
this.visible = false
},
initTime() {
// setInterval(() => {
// this.tabList.forEach(item => {
// this.useGetCookie('https://creator.xiaohongshu.com/creator/home', document.getElementById(item.characteristic).getCookieStoreId()).then(res => {
// this.accountList.forEach(it => {
// it.childList.forEach(t => {
// if (t.characteristic === item.characteristic) return t.cookies = this.handleCookie(res)
// })
// })
// })
// })
// }, 60000 * 60)
},
handleTabRemove(e) {
let index = this.tabList.findIndex(item => item.characteristic === e)
if (this.activeTabName === e && this.tabList.length > 1) {
this.activeTabName = this.tabList[index = index == 0 ? index + 1 : index - 1].characteristic
}
this.tabList.splice(this.tabList.findIndex(item => item.characteristic === e), 1)
localStorage.setItem('tabList', JSON.stringify(this.tabList))
},
// 左侧选择
changAccountSelect(key) {
const headIndex = key.split('-')[0]
const afterIndex = key.split('-')[1]
const characteristic = this.accountList[headIndex].childList[afterIndex].characteristic
let tabIndex = this.tabList.findIndex(item => item.characteristic === characteristic)
if (tabIndex !== -1) {
this.activeTabName = this.tabList[tabIndex].characteristic
} else {
this.accountList.forEach(res => {
const obj = res.childList.filter(it => it.characteristic === characteristic)[0] || null
obj && this.tabList.push(obj)
})
tabIndex = this.tabList.length - 1
this.activeTabName = this.tabList[tabIndex].characteristic
}
//验证cookie
this.intendedEffect(headIndex, afterIndex, tabIndex)
},
// 定时器间隔拉取右侧有效cookie同步到左侧用户信息
// 点击时效验cookie 是否失效
showMessage1: function () {
this.tabList.forEach(item => {
this.useGetCookie('https://creator.xiaohongshu.com/creator/home', document.getElementById(item.characteristic).getCookieStoreId()).then(res => {
console.log('cookies=', res)
// if (res.findIndex(item => item.name === 'access-token') !== -1) {
// }
})
})
},
showLoginProp() {
if (!this.groupRegion) {
this.$message({
message: '请选择组',
type: 'warning'
})
return false
}
this.selectProp = false
this.addAcount = true
// this.vwId = 'webview_123456788'
// this.addPartition = 'persist:123456788'
const identification = getRandomAlphaNum(9)
this.addPartition = 'persist:' + identification
this.vwId = 'webview_' + identification
this.$nextTick(() => {
const viewWrap = `<webview id="${this.vwId}" partition="${this.addPartition}" src="https://creator.xiaohongshu.com/login" style="width: 100%; height: 100%; border: 0px;"/>`
document.getElementById('login').innerHTML = viewWrap
// 临时处理监听跳转关闭
const routerInterval = setInterval(() => {
this.useGetCookie('https://creator.xiaohongshu.com/creator/home', document.getElementById(this.vwId).getCookieStoreId()).then(res => {
if (res.length >= 10) {
// 获取个人信息
this.getUserInfo_personal(res)
clearInterval(routerInterval)
}
})
}, 3000)
})
},
// 效验cookie
async intendedEffect(headIndex, afterIndex, tabIndex) {
// 2 获取右侧cookie信息判断是否有效
// 3 匹配同步cookie信息
setTimeout( async() => {
let userInfo = this.tabList[tabIndex]
const cookies = await this.useGetCookie('https://creator.xiaohongshu.com/creator/home', document.getElementById(userInfo.characteristic).getCookieStoreId()).then(res => {
return this.handleCookie(res)
})
try {
const resultDaata = (await getUserinfo(cookies))
if (resultDaata.data) {
userInfo.nickName = resultDaata.data.name
userInfo.label = resultDaata.data.name
userInfo.avater = resultDaata.data.avatar
userInfo.personal_desc = resultDaata.data.personal_desc
userInfo.loginStatus = 1
userInfo.cookies = cookies
} else if(resultDaata.result === -100){
userInfo.loginStatus = 2
}
this.tabList[tabIndex] = userInfo
this.accountList[headIndex].childList[afterIndex] = userInfo
localStorage.setItem('accountList', JSON.stringify(this.accountList))
localStorage.setItem('tabList', JSON.stringify(this.tabList))
} catch (e) {
console.log('response', e)
if (e.data.code === 401) {
userInfo.loginStatus = 2
}
this.accountList[headIndex].childList[afterIndex] = userInfo
this.tabList[tabIndex] = userInfo
localStorage.setItem('accountList', JSON.stringify(this.accountList))
localStorage.setItem('tabList', JSON.stringify(this.tabList))
// return Promise.reject(e)
}
}, 1500)
},
async getUserInfo_personal(data) {
let notUplicate = true
// 用户信息
const userInfo = (await getUserinfo(this.handleCookie(data))).data
const groupIndex = this.accountList.findIndex(item => item.groupId === this.groupRegion)
// const groupInfo = this.accountList[groupIndex]
// 获取源数据
// 判断是否id已存在
// 根据组id差入数据、
this.accountList.forEach(item => {
// 小红书
// if (groupInfo.type === 1) {
if (item.childList.filter(it => it.id === userInfo.red_num).length > 0) {
this.$message({
message: '请勿重复添加用户',
type: 'error'
})
notUplicate = false
return false
}
// }
})
if (notUplicate) {
const obj = {
characteristic: this.vwId,
partition: this.addPartition,
type: 1,
url: 'https://creator.xiaohongshu.com/creator/home',
cookies: this.handleCookie(data),
loginStatus: 1
}
obj.nickName = userInfo.name
obj.label = userInfo.name
obj.avater = userInfo.avatar
obj.id = userInfo.red_num
obj.personal_desc = userInfo.personal_desc
this.accountList[groupIndex].childList.push(obj)
localStorage.setItem('accountList', JSON.stringify(this.accountList))
}
this.addAcount = false
},
handleCookie(data) {
let cookie = ''
data.forEach(item => { cookie += `${item.name} = ${item.value};`})
return cookie
},
useGetCookie(e, t) {
return new Promise(function(resolve, reject) {
chrome.cookies.getAll({
url: e,
storeId: t
}, function(e) {
resolve(e)
})
})
}
}
})
// var cookieArr = []
// var gui = require('nw.gui');
// var win = gui.Window.get();
// win.on('new-win-policy', newWinPolicyHandler);
// function newWinPolicyHandler(frame, url, policy) {
// policy.ignore(); //ignore policy first to prevent popup
// // $("#ifr2").attr("src",url); //load popup url into iFrame 后来$("#ifr2")获取不到了;改成下面的方式:
// // document.getElementById("#welIfr1").src = url;
// // document.getElementById("#welIfr1").contentDocument.getElementById("#ifr2").src = url; 这个是设置iframe内的iframe路径
// // document.getElementById("ifr4").contentWindow.document.getElementById("cctvIfr")
// $("#ifr4").attr("src", url)
// }
// nw.Window.get().on('new-win-policy', function(frame, url, policy) {
// console.log('neibu')
// // 不打开窗口
// policy.ignore();
// // 在系统默认浏览器打开
// nw.Shell.openExternal(url);
// });
// nw.Window.get().on('navigation', function(frame, url, policy){
// console.log('我是frame', frame)
// console.log('我是url', url)
// console.log('我是policy', policy)
// })
// function getCookie() {
// var win = nw.Window.get()
// win.title = 'cc'
// console.log('win2=', win)
// }
// function opentab(id) {
// $('#' + id).toggleClass('no')
// }
// function openWin() {
// // nw.window.open('https://creator.xiaohongshu.com/login?lastUrl=%252Fcreator%252Fhome', {}, function(new_win) {
// // // 监听新窗口焦点事件
// // new_win.on('focus', function() {
// // console.log('New window is focused');
// // });
// // })
// nw.Window.open('https://www.baidu.com', {
// id: 'login',
// title: '小红书',
// position: 'center',
// width: 1150,
// height: 750,
// new_instance: false,
// id: 'tab3',
// resizable: false // 是否可拖动
// }, function(new_win) {
// new_win.setAlwaysOnTop(false)
// new_win.setVisibleOnAllWorkspaces(false)
// new_win.on('loaded', () => {
// console.log('我是loaded')
// })
// new_win.on('blur', () => {
// console.log('我是blur')
// })
// new_win.on('onunload', () => {
// console.log('我是onunload')
// })
// new_win.on('closed', () => {
// console.log('我是closed')
// })
// new_win.on('onbeforeunload', () => {
// console.log('我是onbeforeunload')
// })
// new_win.on('navigation', function(frame, url, policy){
// console.log('我是frame', frame)
// console.log('我是url', url)
// console.log('我是policy', policy)
// })
// });
// }
</script>
<style>
body {
padding: 0;
margin: 0;
}
.loginProp .el-dialog{
margin-top: 1vh!important;
}
.loginProp .el-dialog__body {
padding: 0;
}
.el-tabs__nav {
display: flex;
}
.el-form-item {
margin-bottom: 0;
}
.el-menu-item.is-active:after{
content: "";
display: inline-block;
position: absolute;
top: 0;
left: 0;
width: 6px;
height: 100%;
background-color: #6190e8;
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
box-shadow: 1px 0 12px 0 #6190e8;
}
.el-tabs__content {
height: calc(100vh - 60px);
overflow-y: auto;
}
.el-tab-pane {
height: 99%;
}
.el-tabs__item {
display: flex;
align-items: center;
position: relative;
cursor: pointer;
font-size: 12px;
margin-top: 4px;
padding: 0 12px;
}
.el-menu-item-group__title {
display: none;
}
.el-submenu .el-menu-item {
padding: 0;
}
.account-list-content {
height: calc(100vh - 83px);
overflow-y: scroll;
overflow-x: hidden;
}
.account-list-name {
font-size: 14px;
font-family: PingFangSC-Regular,PingFang SC;
font-weight: 500;
color: rgba(0,0,0,.85);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
margin-bottom: 3px;
}
.account-item {
height: inherit;
}
.account-item-right {
width: 100%;
display: flex;
flex-direction: column;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.account-item-right span {
line-height: normal;
}
.u-filter {
filter: grayscale(1);
}
.u-avater {
width: 40px;
height: 40px;
border-radius: 50%;
margin-right: 10px;
}
.line-span {
font-size: 12px;
color: rgba(0,0,0,.45);
}
.mt-5 {
margin-top: 5px;
}
.ml-5 {
margin-left: 5px;
}
.p-10 {
padding: 10px;
}
.text-hide {
overflow: hidden;
text-overflow: ellipsis;
white-space:nowrap
}
.text-hide-2 {
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
word-break: break-all;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
}
.u-flex {
display: flex;
align-items: center;
}
.flex-start {
align-items: flex-start;
}
.u-flex-between {
justify-content: space-between;
}
.u-flex-center {
justify-content: center;
}
.u-flex-around {
justify-content: space-around;
}
.u-flex-end {
justify-content: flex-end;
}
.u-flex-wrap {
flex-wrap: wrap;
}
.flex-1 {
flex: 1;
}
#app {
display: flex;
flex-direction: column;
height: 100%;
}
header {
position: relative;
width: 100%;
height: 82px;
z-index: 11;
color: rgba(0,0,0,.85);
background: #fff;
box-shadow: 0 2px 9px 0 rgb(0 0 0 / 5%);
-webkit-app-region: no-drag;
}
.width-100 {
width: 100%;
}
.account-wrap {
display: flex;
justify-content: flex-start;
align-items: flex-start;
height: 100%;
overflow: hidden;
}
.account-list-wrap {
position: relative;
width: 202px;
display: flex;
flex-direction: column;
height: 100%;
background: #fff;
border-right: 1px solid #eee;
transition: all .2s ease-in-out;
}
.account-tabs-wrap {
flex: 1;
height: 100vh;
}
.at-tabs {
width: calc(100vw - 202px);
height: 100%;
background: #fff;
box-sizing: border-box;
margin: 0;
padding: 0;
color: rgba(0,0,0,.85);
font-size: 14px;
font-variant: tabular-nums;
line-height: 1.5715;
list-style: none;
display: flex;
flex-direction: column;
}
.tab-web-view {
height: 100%;
}
.ant-tabs-content {
flex: auto;
min-width: 0;
min-height: 0;
height: 100%;
}
.sim-cont{
max-height: 100%;
overflow: auto;
}
.sim-cont::-webkit-scrollbar { /*滚动条整体样式*/
width: 5px;
height: 3px;
}
.sim-cont::-webkit-scrollbar-thumb { /*滚动条里面小方块样式*/
border-radius: 100px;
-webkit-box-shadow: inset 0 0 5px rgba(151, 151, 151, 0.2);
background:rgba(0,0,0,0.1);;
}
.sim-cont::-webkit-scrollbar-track { /*滚动条里面轨道样式*/
-webkit-box-shadow: inset 0 0 5px rgba(223, 223, 223, 0.2);
border-radius: 100px;
background: rgba(0,0,0,0.1);
}
</style>
</html>