| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259 |
- <template>
- <div>
- <el-container style="height: 100vh;">
- <el-header height="45px" style="background-color: #fafafa; padding: 0 10px;">
- <soft-header ref="headerRef" @update-soft="updateSoft()" @login-url="loginUrl" @clear-cache="clearCache"></soft-header>
- </el-header>
-
- <el-main ref="el-main" style="background-color: #fafafa;">
- <template>
- <div style="padding: 10px 20px 0 20px; height: 100%;">
-
- <el-row type="flex" align="middle" justify="space-between">
- <div>
- <span>链接平台:</span>
- <el-radio-group v-model="menuIndex" size="mini" style="margin-right: 20px;">
- <!-- <el-radio-button label="3" size="mini">天猫</el-radio-button> -->
- <el-radio-button label="4" size="mini">淘宝/天猫</el-radio-button>
- <el-radio-button label="1" size="mini">1688</el-radio-button>
- <el-radio-button label="2" size="mini">京东</el-radio-button>
- <el-radio-button label="5" size="mini">小红书</el-radio-button>
- <el-radio-button label="10" size="mini">其他</el-radio-button>
- </el-radio-group>
- </div>
-
-
- <!-- 阿里巴巴账号 -->
- <template v-if="menuIndex == '1'">
- <div>
- <el-tag type="info" size="mini" v-if="alibabaStatus == 1">未检测</el-tag>
- <el-tag type="success" size="mini" v-if="alibabaStatus == 2">阿里巴巴账号已登录</el-tag>
- <el-link type="danger" style="text-decoration: underline;" v-if="alibabaStatus == 3" :underline="false" @click="loginUrl('https://www.1688.com')">未登录,点击登录阿里巴巴账号</el-link>
- <el-button size="mini" type="warning" :loading="checkLoading" style="margin-left: 10px;" :disabled='alibabaStatus == 2' @click="checkAlibabaLogin">检测登录状态</el-button>
- </div>
- </template>
-
- <!-- 天猫/淘宝 -->
- <template v-if="menuIndex == '3' || menuIndex == '4'">
- <div>
- <el-tag type="info" size="mini" v-if="tbStatus == 1">未检测</el-tag>
- <el-tag type="success" size="mini" v-if="tbStatus == 2">{{menuIndex == '3' ? '天猫' : '淘宝'}}账号已登录</el-tag>
- <el-link type="danger" style="text-decoration: underline;" v-if="tbStatus == 3" :underline="false" @click="loginUrl('https://login.taobao.com')">未登录,点击登录<span>{{menuIndex == '3' ? '天猫' : '淘宝'}}</span>账号</el-link>
- <el-button size="mini" type="warning" :loading="checkLoading" style="margin-left: 10px;" :disabled='tbStatus == 2' @click="checkLogin">检测登录状态</el-button>
- </div>
- </template>
-
- <!-- 京东账号 -->
- <template v-if="menuIndex == '2'">
- <div>
- <el-tag type="info" size="mini" v-if="jdStatus == 1">未检测</el-tag>
- <el-tag type="success" size="mini" v-if="jdStatus == 2">京东账号已登录</el-tag>
- <el-link type="danger" style="text-decoration: underline;" v-if="jdStatus == 3" :underline="false" @click="loginUrl('https://passport.jd.com/new/login.aspx')">未登录,点击登录京东账号</el-link>
- <el-button size="mini" type="warning" :loading="checkLoading" style="margin-left: 10px;" :disabled='jdStatus == 2' @click="checkJdLogin">检测登录状态</el-button>
- </div>
- </template>
-
- <!-- 小红书 -->
- <template v-if="menuIndex == '5'">
- <div>
- <el-tag type="info" size="mini" v-if="redStatus == 1">未检测</el-tag>
- <el-tag type="success" size="mini" v-if="redStatus == 2">小红书账号已登录</el-tag>
- <el-link type="danger" style="text-decoration: underline;" v-if="redStatus == 3" :underline="false" @click="loginUrl('https://www.xiaohongshu.com')">未登录,点击登录小红书账号</el-link>
- <el-button size="mini" type="warning" :loading="checkLoading" style="margin-left: 10px;" :disabled='redStatus == 2' @click="checkRedLogin">检测登录状态</el-button>
- </div>
- </template>
-
- <!-- 其他 -->
- <template v-if="menuIndex == '10'">
- <el-link type="danger" :underline="false" style="font-size: 12px;font-weight: 600;">其他平台仅提供试用,非会员功能</el-link>
- </template>
- </el-row>
-
- <el-row style="margin: 10px 0;">
- 提取模式:
- <el-radio-group v-model="exeType">
- <el-radio :label="1">后台运行</el-radio>
- <el-radio :label="2">前台显示</el-radio>
- </el-radio-group>
- </el-row>
-
- <el-row>
- <span class="set-title">保存目录:</span>
- <el-input :title="downloadDir" ref="upload-input" size="mini" @focus="pickPath" placeholder="请选择输出目录" v-model="downloadDir" readonly style="width:300px;" prefix-icon="el-icon-folder"></el-input>
- <el-popover placement="bottom" popper-class="popper-open" trigger="hover" content="打开保存目录">
- <i class="el-icon-folder-opened" slot="reference" style="padding-left: 5px; cursor: pointer; font-size: 22px; vertical-align: middle;" @click="openFolder()"></i>
- </el-popover>
- </el-row>
-
- <div style="margin-top: 10px;">
- <el-input id="aaa" type="textarea" :rows="3" placeholder="请输入需要提取的网址" v-model="formatUrl"></el-input>
-
- <div class="content-top" style="padding: 10px 0; text-align: center; display: inherit;">
- <el-button size="small" type="danger" @click="addLinks()" :loading="addLoading">开始提取</el-button>
- <el-button size="small" type="danger" @click="pauseLinks()">停止提取</el-button>
- <el-button size="small" type="danger" @click="clearList()">清除结果</el-button>
- <el-button size="small" type="danger" @click="exportLinks()">合并导出全部</el-button>
- </div>
- </div>
-
- <div class="table-scroll" style="height: calc(100% - 290px); overflow: hidden;">
- <el-row type="flex" justify="space-between">
- <div>
- <h4 style="display: inline-block;">
- 提取结果:
- </h4>
- </div>
- </el-row>
- <div style="display: flex; flex-wrap: nowrap;justify-content: space-between;height: calc(100% - 60px);">
- <vxe-table style="width: 100%;" ref="xTable" show-overflow class="img-table" max-height="100%" empty-text="没有更多数据了!" :loading="tabLoading" :row-config="{isHover: true}"
- :loading-config="{icon: 'vxe-icon-indicator roll', text: '加载中...'}" :data="this[listStr+'List']" :scroll-y="{enabled: true}">
- <vxe-column field="title" title="名称"></vxe-column>
- <vxe-column field="page" title="页数">
- <template #default="{ row }">
- 第{{row.currentPage}}页,共{{row.totalPage}}页
- </template>
- </vxe-column>
- <vxe-column field="filesize" title="条数" width="100">
- <template #default="{ row }">
- <span v-if="row.urls">{{row.urls.length}}</span>
- </template>
- </vxe-column>
- <vxe-column field="status" title="状态" width="150">
- <template #default="{ row }">
- <template v-if="row.status == '1'">
- <i class="el-icon-info" style="font-size: 16px; color: #999;"></i>
- <span>待操作</span>
- </template>
- <template v-if="row.status == '2'">
- <i class="el-icon-success" style="font-size: 16px; color: #19be6b;"></i>
- <span>导出成功</span>
- </template>
- </template>
- </vxe-column>
- <vxe-column title="操作" width="150">
- <template #default="{ row, rowIndex }">
- <el-button :loading="row.loading" type="danger" size="mini" plain @click="exportPageLinks(row)">导出</el-button>
- </template>
- </vxe-column>
- </vxe-table>
-
- </div>
- </div>
- </div>
- </template>
-
- </el-main>
-
- <el-footer height="48px">
- <!-- 更新 -->
- <soft-update ref="updateRef" :showDowload="dowloadModel" :dowloadFinish="finishModel"></soft-update>
- </el-footer>
- </el-container>
- </div>
- </template>
- <script>
- import os from 'os'
- import fs from 'fs'
- import request from 'request'
- import path from 'path';
- import xlsx from 'node-xlsx';
- import softUpdate from './update.vue';
- import softHeader from './header.vue';
- import electronApi from '@/utils/electronApi';
- import pjson from '/package.json'
- // import puppeteer from 'puppeteer'
- import puppeteer from 'puppeteer-extra'
- const axios = require('axios');
- const StealthPlugin = require('puppeteer-extra-plugin-stealth');
- const { ipcRenderer } = require('electron');
- const listNameArr = ['alibaba','jd','tmall','tb','red','aliguoji','acaigou','amazon', 'pdd' ,'common','goofish','dy'];
- let separator = '';
- if (os.platform == 'linux') {
- separator = '/'
- } else {
- separator = '\\'
- }
- export default {
- name: 'landing-page',
- components: {
- softUpdate,
- softHeader
- },
- data() {
- return {
- menuIndex: '4',
- exeType: 1,
-
- usageTimes: 3,
- tipsModal: false,
- tipsDesc: "暂无下载权限,请开通VIP会员使用",
-
- formatUrl: '',
- tabLoading: false,
- productName: pjson.softInfo.softName,
- imgUrl: this.$api.imgUrl,
- downloadDir: os.userInfo().homedir + separator + "Downloads",
- dowloadModel: false,
- finishModel: false,
- loading: false,
-
- tbList: [], //淘宝数据
- tmallList: [],
- alibabaList: [],
- jdList: [],
- redList: [],
- commonList: [],
-
- execNum: 100, //限制
- checkLoading: false, //点击检测登录状态
- tbStatus: 1, // 1、未检测 2、已经登录 3、未登录
- jdStatus: 1, // 1、未检测 2、已经登录 3、未登录
- redStatus: 1, //同上
- alibabaStatus: 1, //同上上
-
- /** 浏览器名称 **/
- alibabaBrowser: null,
- tbBrowser: null,
- jdBrowser: null,
- commonBrowser: null,
- redBrowser: null,
- loginBrowser: null, // 登录用的浏览器实例
- pauseFlag: true, //暂停中止标志
- addLoading: false,
-
- videoBrowser: null,
- parseLoading: false,
- mergeLoading: false
- };
- },
- computed: {
- listStr: function(){
- let index = Number(this.menuIndex) - 1;
- return listNameArr[index];
- }
- },
- async mounted() {
- this.$refs.updateRef.updateSoft(true);
- let homedir = os.userInfo().homedir;
- if (fs.existsSync(homedir + separator + "Desktop")) {
- this.downloadDir = homedir + separator + "Desktop"
- } else {
- this.downloadDir = homedir + separator + "Downloads"
- }
-
- let dir = this.$utils.getStorage('downloadDir');
- if(dir && fs.existsSync(dir)){
- this.downloadDir = dir;
- }
- if (!fs.existsSync(this.downloadDir + separator + pjson.softInfo.softName)) {
- fs.mkdirSync(this.downloadDir + separator + pjson.softInfo.softName);
- }
- if (!fs.existsSync(os.tmpdir() + separator + 'chrome-data-capture')) {
- fs.mkdirSync(os.tmpdir() + separator + 'chrome-data-capture');
- }
-
- if (!fs.existsSync(os.tmpdir() + separator + 'chrome-data-capture-jd')) {
- fs.mkdirSync(os.tmpdir() + separator + 'chrome-data-capture-jd');
- }
-
- if (!fs.existsSync(os.tmpdir() + separator + 'chrome-data-capture-local')) {
- fs.mkdirSync(os.tmpdir() + separator + 'chrome-data-capture-local');
- }
- // 打开浏览器
- const {
- shell
- } = require('electron');
- const links = document.querySelectorAll('a[href]');
- links.forEach(link => {
- link.addEventListener('click', e => {
- const url = link.getAttribute('href');
- e.preventDefault();
- shell.openExternal(url);
- });
- });
-
- // 判断系统版本 低于10使用兼容模式
- if(os.release() && os.release().indexOf('.') > -1){
- let systemVersion = Number(os.release().split('.')[0]);
- if(systemVersion < 10){ // 低于win10,软件打开时候浏览器设置为兼容版
- this.$utils.setStorage('versionType', 1);
- }else{
- this.$utils.setStorage('versionType', 2);
- }
- }
-
- // 初始化开发者设置
- this.$utils.setStorage('waitUntil', 'networkidle2');
-
- document.getElementById('aaa').addEventListener('contextmenu', e => {
- e.preventDefault();
- // 发送事件到主进程,附带元素类型信息
- ipcRenderer.send('show-context-menu', 'input');
- });
-
- },
- methods: {
- // 实时获取页面滚动加载时间
- initMs(){
- let pageMs = this.$utils.getStorage('pageMs');
- if(pageMs){
- return Number(pageMs);
- }else{
- return 600;
- }
- },
- // 实时获取开发者设置
- initDevelop(){
- let develop = {
- headless: true,
- waitUntil: 'networkidle2'
- };
- let n1 = this.exeType;
- let n2 = this.$utils.getStorage('waitUntil');
- if(n1){
- if(n1 == 1){
- develop.headless = true;
- }else if(n1 == 2){
- develop.headless = false;
- }
- }
- if(n2){
- develop.waitUntil = n2;
- }
-
- return develop;
- },
- // 实时获取浏览器路径
- initPath(){
- let chromeType = this.$utils.getStorage('chromeType');
- let chromePath = puppeteer.executablePath().replace('win32-1', 'win64-1');
- if(chromeType == 1){ // 电脑自带浏览器
- chromePath = this.$utils.getStorage('chromePath');
- }else{
- chromePath = puppeteer.executablePath().replace('win32-1', 'win64-1');
- let versionType = this.$utils.getStorage('versionType');
- if(versionType && versionType == 1){
- chromePath = chromePath.replace('chrome-win', 'chrome7');
- }
- }
- return chromePath;
- },
- // 实时获取浏览器数据缓存
- initDataDir(tag){
- let chromeType = this.$utils.getStorage('chromeType');
- let userDataDir = os.tmpdir() + separator + 'chrome-data-capture';
- if(chromeType == 1){ // 电脑自带浏览器
- userDataDir = os.tmpdir() + separator + 'chrome-data-capture-local';
- }else{
- userDataDir = os.tmpdir() + separator + 'chrome-data-capture';
- if(tag == 'jd'){
- userDataDir = os.tmpdir() + separator + 'chrome-data-capture-jd';
- }
- }
- return userDataDir;
- },
- // 任务下载间隔时间
- initGap(){
- let gap = this.$utils.getStorage('gap');
- if(gap){
- return Number(gap);
- }else{
- return 1;
- }
- },
- // 通用的延迟函数
- async delay(t) {
- let s = this.initGap();
- if(t){
- s = t;
- }
- if(s > 0){
- return new Promise(resolve => setTimeout(resolve, Number(s)*1000));
- }else{
- return null;
- }
- },
- checkAuthority(){
- let authority = this.$refs.headerRef.authority;
- this.$refs.imgRef.authority = authority;
- },
- // 选择目录
- pickPath() {
- this.$refs['upload-input'].blur();
- electronApi.call('pickDir', []).then((path) => {
- if (path) {
- this.downloadDir = path;
- this.$utils.setStorage('downloadDir', path);
- }
- });
- },
- // 打开自定义下载目录
- openFolder() {
- let path = this.downloadDir;
- if (fs.existsSync(this.downloadDir + separator + pjson.softInfo.softName)) {
- path = this.downloadDir + separator + pjson.softInfo.softName;
- } else {
- fs.mkdirSync(this.downloadDir + separator + pjson.softInfo.softName);
- path = this.downloadDir + separator + pjson.softInfo.softName;
- }
- electronApi.call('showItemInfolder', [path + '\\tty.tty'])
- },
- openVip() {
- this.tipsModal = false;
- this.$refs.headerRef.openVip();
- },
- updateSoft() {
- this.$refs.updateRef.updateSoft();
- },
- // 清除缓存的后续操作
- async clearCache(){
- if(this.loginBrowser){
- await this.loginBrowser.close();
- this.loginBrowser = null;
- }
-
- if(this.videoBrowser){
- await this.videoBrowser.close();
- this.videoBrowser = null;
- }
- },
- // 清除结果
- clearList(){
- let index = Number(this.menuIndex) - 1;
- this[listNameArr[index]+'List'] = [];
- },
- //停止提取
- async pauseLinks(){
- this.addLoading = false;
- let index = Number(this.menuIndex) - 1;
- let browserName = listNameArr[index] + 'Browser';
- if(index == '2'){ // 天猫和淘宝共用一个
- browserName = 'tbBrowser';
- }
- if(this[browserName]){ //关闭浏览器
- await this[browserName].close();
- this[browserName] = null;
- }
- },
- //导出全部链接
- exportLinks(){
- let allRows = {
- title: '淘宝商品链接汇总',
- urls: [],
- loading: false,
- status: '1'
- };
- switch(this.menuIndex){
- case '1': // 阿里巴巴
- allRows.title = '阿里巴巴商品链接汇总';
- break;
- case '2': // 京东
- allRows.title = '京东商品链接汇总';
- break;
- case '3': // 天猫
- case '4': // 淘宝
- let allUrls = [];
- for(let i = 0; i < this.tbList.length; i++){
- allUrls = allUrls.concat(this.tbList[i].urls);
- }
- allRows.urls = allUrls;
- break;
- case '5': // 小红书
- allRows.title = '小红书笔记链接汇总';
- break;
- case '10': // 普通网址
- allRows.title = '网页链接汇总';
- break;
- }
-
- this.exportPageLinks(allRows);
- },
- // 导出单页链接
- exportPageLinks(row){
- row.loading = true;
- let filename = row.title + '-' + this.$utils.formatFileTime() +'.xlsx';
- let sheet1 = [['序号','商品ID','商品标题','商品链接','价格','销量','店铺名称','店铺地址','首图地址']];
- if(this.menuIndex == '4'){
- sheet1 = [['序号','商品ID','商品标题','商品链接','价格','销量','店铺名称','店铺地址','首图地址','商品短链接']];
- }else if(this.menuIndex == '5'){
- sheet1 = [['序号','笔记标题','笔记链接','用户名','点赞量','发布时间','首图地址']];
- }else if(this.menuIndex == '10'){
- sheet1 = [['序号','标题','链接']];
- }
- for(let i = 0; i < row.urls.length; i++){
- let item = row.urls[i];
- let info = [i+1, item.id, item.title, item.href, item.price, item.realSales, item.shopNameText, item.shopUrl, item.mainPic];
- if(this.menuIndex == '4'){
- info = [i+1, item.id, item.title, item.href, item.price, item.realSales, item.shopNameText, item.shopUrl, item.mainPic, 'https://detail.tmall.com/item.htm?id='+item.id];
- }else if(this.menuIndex == '5'){
- info = [i+1, item.title, item.href, item.name, item.realSales, item.time, item.mainPic];
- }else if(this.menuIndex == '10'){
- info = [i+1, item.title, item.href];
- }
-
- sheet1.push(info);
- }
-
- let buffer = xlsx.build([
- {
- name: 'sheet1',
- data: sheet1
- }
- ]);
-
- if (!fs.existsSync(this.downloadDir + separator + pjson.softInfo.softName)) {
- fs.mkdirSync(this.downloadDir + separator + pjson.softInfo.softName);
- }
- fs.writeFileSync(this.downloadDir + separator + pjson.softInfo.softName + separator + filename, buffer, {'flag':'w'});
- row.loading = false;
- row.status = '2';
- this.$message({message: '文件导出成功!', type: 'success'});
- electronApi.call('showItemInfolder',[this.downloadDir + separator + pjson.softInfo.softName + separator + filename]);
- },
- //提取链接
- async addLinks(){
- this.addLoading = true;
- setTimeout(() => {
- this.addLoading = false;
- }, 30000);
- if(this.loginBrowser){
- await this.loginBrowser.close();
- this.loginBrowser = null;
- }
-
- let index = Number(this.menuIndex) - 1;
-
- if(this.menuIndex == '1'){ // 阿里巴巴
- if(this.alibabaStatus == 1 || this.alibabaStatus == 3){ // 未检测登录状态/或提示未登录状态,开始检测
- await this.checkAlibabaLogin().then((data) => {
- if(data != 2){ // 未登录
- this.alibabaStatus = 3;
- this.loginVisible = true;
- }
- }).catch(err => {
- this.alibabaStatus = 3;
- });
- if(this.alibabaStatus == 3){
- this.loading = false;
- return false;
- }
- }
- }
-
- if(this.menuIndex == '2'){ // 京东
- if(this.jdStatus == 1 || this.jdStatus == 3){ // 未检测登录状态/或提示未登录状态,开始检测
- await this.checkJdLogin().then((data) => {
- if(data != 2){ // 未登录
- this.jdStatus = 3;
- this.loginVisible = true;
- }
- }).catch(err => {
- this.jdStatus = 3;
- });
- if(this.jdStatus == 3){
- this.loading = false;
- return false;
- }
- }
- }
-
- if(this.menuIndex == '3' || this.menuIndex == '4'){ // 天猫/淘宝
- if(this.tbStatus == 1 || this.tbStatus == 3){ // 未检测登录状态/或提示未登录状态,开始检测
- await this.checkLogin().then((data) => {
- if(data != 2){ // 未登录
- this.tbStatus = 3;
- this.loginVisible = true;
- }
- }).catch(err => {
- this.tbStatus = 3;
- });
- }
- if(this.tbStatus == 3){
- this.loading = false;
- return false;
- }
- }
-
- if(this.menuIndex == '5'){ // 小红书
- if(this.redStatus == 1 || this.redStatus == 3){ // 未检测登录状态/或提示未登录状态,开始检测
- await this.checkRedLogin().then((data) => {
- if(data != 2){ // 未登录
- this.redStatus = 3;
- this.loginVisible = true;
- }
- }).catch(err => {
- this.redStatus = 3;
- });
- if(this.redStatus == 3){
- this.loading = false;
- return false;
- }
- }
- }
-
- let userDataDir = this.initDataDir();
- if(this.menuIndex == '2'){
- userDataDir = this.initDataDir('jd');
- }
- // 运行不同平台的浏览器
- puppeteer.use(StealthPlugin());
- let browserName = listNameArr[index] + 'Browser';
- if(index == '2'){ // 天猫和淘宝共用一个
- browserName = 'tbBrowser';
- }
-
- let headless = true;
- headless = this.initDevelop().headless;
- let redSize = '';
- if(['3','4','5'].indexOf(this.menuIndex) > -1){
- redSize = '--window-size=1920,800'; //给浏览器一个初始大小,在无头模式下,页面会自适用缩放
- }
-
- try{
- this[browserName] = await puppeteer.launch({
- headless: headless,
- executablePath: this.initPath(),
- userDataDir: userDataDir,
- args: [
- '--start-maximized',
- '--no-sandbox',
- '--disable-setuid-sandbox',
- '--disable-blink-features=AutomationControlled',
- redSize
- ]
- });
-
- switch(this.menuIndex){
- case '1': // 阿里巴巴
- this.alibabaScanUrl(this.formatUrl);
- break;
- case '2': // 京东
- this.jdScanUrl(this.formatUrl);
- break;
- case '3': // 天猫
- case '4': // 淘宝
- this.tbScanUrl(this.formatUrl);
- break;
- case '5': // 小红书
- this.redScanUrl(this.formatUrl);
- break;
- case '10': // 普通网址
- this.commonScanUrl(this.formatUrl);
- break;
- }
- }catch(e){
- console.log(e, '测试');
- }
-
-
- },
-
- // 天猫/淘宝扫描网址
- tbScanUrl(url){
- (async () => {
- try{
- let authority = this.$refs.headerRef.authority.isAuthority;
- let page = await this.tbBrowser.newPage();
-
- let responseVideo = [];
- let waitUntil = 'networkidle2';
- waitUntil = this.initDevelop().waitUntil;
- await page.goto(url, {waitUntil : waitUntil});
-
- let searchTitle = await page.title() || '淘宝商品搜索';
- if(searchTitle){
- searchTitle = searchTitle.substring(0, 50);
- if(this.containsAnyChar(searchTitle)){ //判断是否含有特殊字符
- searchTitle = searchTitle.replace(/[\\/:*?"<>|#%&\s]/g, "");
- }
- }
- let outObj = {};
- let pageHandle = await page.$$('[class^=next-pagination-display]');
- let currentPage = 1;
- let totalPage = 1;
- if(pageHandle && pageHandle.length > 0){
- let pageValue = await page.$eval('[class^=next-pagination-display]', el => el.innerText);
- currentPage = pageValue.replace('\n', '').split('/')[0] || 1;
- totalPage = pageValue.replace('\n', '').split('/')[1] || 1;
- }
-
- for(let i = Number(currentPage); i < Number(totalPage)+1; i++){
- let pValue = i + 1;
- let pageHandle = await page.$$('.next-pagination-jump-input input');
- if(pageHandle && pageHandle.length > 0){ // 页码多,可以点击跳转制定页码
- await page.type('.next-pagination-jump-input input', pValue.toString());
- }
-
- let itemTitle = searchTitle + '-' + i;
- const imgInfo = await page.evaluate((authority, execNum, itemTitle) => {
- let outObj = {
- title: itemTitle,
- currentPage: 1,
- totalPage: 1,
- urls: [],
- status: '1',
- loading: false
- };
- let total = document.querySelector('[class^=next-pagination-display]');
- if(total){
- outObj.currentPage = total.innerText.replace('\n', '').split('/')[0];
- outObj.totalPage = total.innerText.replace('\n', '').split('/')[1];
- }
-
- //主图
- let arr1 = document.querySelectorAll('a[id*=item_id]');
- for(let i=0; i< arr1.length; i++){
- let href = arr1[i].href;
- let id = arr1[i].id.replace('item_id_', '');
- let title = arr1[i].querySelector('[class^=title]') ? arr1[i].querySelector('[class^=title]').innerText : '淘宝商品'+new Date().getTime();
- let priceInt = arr1[i].querySelector('[class^=priceInt]') ? arr1[i].querySelector('[class^=priceInt]').innerText : 0;
- let priceFloat = arr1[i].querySelector('[class^=priceFloat]') ? arr1[i].querySelector('[class^=priceFloat]').innerText : '';
- let price = priceInt + priceFloat;
- let realSales = arr1[i].querySelector('[class^=realSales]') ? arr1[i].querySelector('[class^=realSales]').innerText : '';
- let shopNameText = arr1[i].querySelector('[class^=shopNameText]') ? arr1[i].querySelector('[class^=shopNameText]').innerText : '';
- let shopUrl = arr1[i].querySelector('a[class^=shopName]') ? arr1[i].querySelector('a[class^=shopName]').href : '';
- let mainPic = arr1[i].querySelector('img[class^=mainImg]') ? arr1[i].querySelector('img[class^=mainImg]').src : '';
-
- let info = {
- id: id,
- title: title,
- href: href,
- price: price,
- realSales: realSales,
- shopNameText: shopNameText,
- shopUrl: shopUrl,
- mainPic: mainPic
- }
- outObj.urls.push(info);
- }
-
- //page.$$('.next-pagination-jump-input input');
- // let skuHandle = document.querySelector('.next-pagination-jump-go');
- // if(skuHandle){
- // skuHandle.click({force: true});
- // }
-
- let nextHandle = document.querySelector('button[class*=next-next]');
- if(nextHandle){
- nextHandle.click({force: true});
- }
- return outObj;
- }, authority, this.execNum, itemTitle);
-
- this.tbList.push(imgInfo);
- await this.delay(5);
- }
-
- await this.tbBrowser.close();
- this.addLoading = false;
-
- }catch(e){
- this.addLoading = false;
- this.showError(e);
- }
- })();
- },
-
- // 阿里巴巴扫描网址
- alibabaScanUrl(url){
- (async () => {
- try{
- let authority = this.$refs.headerRef.authority.isAuthority;
- let page = await this.alibabaBrowser.newPage();
-
- let responseVideo = [];
- let waitUntil = 'networkidle2';
- waitUntil = this.initDevelop().waitUntil;
- await page.goto(url, {waitUntil : waitUntil});
-
- let searchTitle = await page.title() || '阿里巴巴商品搜索';
- if(searchTitle){
- searchTitle = searchTitle.substring(0, 50);
- if(this.containsAnyChar(searchTitle)){ //判断是否含有特殊字符
- searchTitle = searchTitle.replace(/[\\/:*?"<>|#%&\s]/g, "");
- }
- }
-
- //找页码信息
- let outObj = {};
- let pageHandle = await page.$$('[class^=pagination-container] span');
- let currentPage = 1;
- let totalPage = 1;
- if(pageHandle && pageHandle.length > 0){
- totalPage = await page.$eval('[class^=pagination-container] span', el => el.innerText);
- currentPage = await page.$eval('[class^=pagination-container] .fui-current', el => el.innerText);
- }
-
- for(let i = Number(currentPage); i < Number(totalPage)+1; i++){
- await new Promise(resolve => setTimeout(resolve, 1500)).then(async() => {
- await page.evaluate(() => {
- window.scrollTo({
- top: 10000,
- behavior: "smooth"
- });
- });
- });
-
- await new Promise(resolve => setTimeout(resolve, 5000)).then(async() => {
- let itemTitle = searchTitle + '-' + i;
- const imgInfo = await page.evaluate((authority, execNum, itemTitle) => {
- let outObj = {
- title: itemTitle,
- currentPage: 1,
- totalPage: 1,
- urls: [],
- status: '1',
- loading: false
- };
- let total = document.querySelector('[class^=pagination-container] span');
- if(total){
- outObj.currentPage = document.querySelector('[class^=pagination-container] .fui-current').innerText || 1;
- outObj.totalPage = total.innerText || 1;
- }
- // 广告链接
- // document.querySelectorAll('[class*=space-common-offerlist] a[class*=pc-ad]');
- // 正常
- let arr1 = document.querySelectorAll('[class*=space-common-offerlist] a[class*=search-offer-item]');
- for(let i=0; i< arr1.length; i++){
- let href = arr1[i].href;
- let idData = arr1[i].dataset.renderkey || '';
- let length = idData.split('_').length - 1;
- let id = idData.split('_')[length];
- let title = arr1[i].querySelector('[class^=title-text]') ? arr1[i].querySelector('[class^=title-text]').innerText : '阿里巴巴商品'+new Date().getTime();
- let priceText = arr1[i].querySelector('[class^=price-item]') ? arr1[i].querySelector('[class^=price-item]').innerText : '';
- let price = priceText.replace('¥', '').replaceAll('\n', '');
- let realDom = arr1[i].querySelector('.offer-price-row .offer-desc-item');
- let realSales = realDom ? realDom.innerText : '';
- let shopNameText = arr1[i].querySelector('[class^=offer-shop-row]') ? arr1[i].querySelector('[class^=offer-shop-row]').innerText : '';
- let shopUrl = arr1[i].querySelector('[class^=offer-shop-row] a') ? arr1[i].querySelector('[class^=offer-shop-row] a').href : '';
- let mainPic = arr1[i].querySelector('img[class^=main-img]') ? arr1[i].querySelector('img[class^=main-img]').src : '';
-
- let info = {
- id: id,
- title: title,
- href: href,
- price: price,
- realSales: realSales,
- shopNameText: shopNameText,
- shopUrl: shopUrl,
- mainPic: mainPic
- }
- outObj.urls.push(info);
- }
- let nextHandle = document.querySelector('.pagination-container .fui-next');
- if(nextHandle){
- nextHandle.click({force: true});
- }
- return outObj;
- }, authority, this.execNum, itemTitle);
- this.alibabaList.push(imgInfo);
- });
-
- }
-
- await this.alibabaBrowser.close();
- this.addLoading = false;
-
-
- }catch(e){
- this.addLoading = false;
- this.showError(e);
- }
- })();
- },
-
- // 京东扫描网址
- jdScanUrl(url){
- (async () => {
- try{
- let authority = this.$refs.headerRef.authority.isAuthority;
- let page = await this.jdBrowser.newPage();
-
- let responseVideo = [];
- let waitUntil = 'networkidle2';
- waitUntil = this.initDevelop().waitUntil;
- await page.goto(url, {waitUntil : waitUntil});
-
- let searchTitle = await page.title() || '京东商品搜索';
- if(searchTitle){
- searchTitle = searchTitle.substring(0, 50);
- if(this.containsAnyChar(searchTitle)){ //判断是否含有特殊字符
- searchTitle = searchTitle.replace(/[\\/:*?"<>|#%&\s]/g, "");
- }
- }
-
- //找页码信息
- let outObj = {};
- let pageHandle = await page.$$('[class*=quick-result]');
- let currentPage = 1;
- let totalPage = 1;
- if(pageHandle && pageHandle.length > 0){
- let pageContent = await page.$eval('[class*=quick-result]', el => el.innerText);
- pageContent = pageContent.replace('\n', '').replace('\n', '');
- currentPage =pageContent.split('/')[0];
- totalPage = pageContent.split('/')[1];
- }else{
- let pageHandle = await page.$$('[class*=pagination_center]');
- if(pageHandle && pageHandle.length > 0){
- currentPage = await page.$eval('[class*=pagination_center] [class*=active]', el => el.innerText);
- let totalInfo = await page.$eval('[class*=pagination_total]', el => el.innerText);
- totalPage = totalInfo.replace('共', '').replace('页', '');
- }
- }
-
- for(let i = Number(currentPage); i < Number(totalPage)+1; i++){
- await new Promise(resolve => setTimeout(resolve, 1500)).then(async() => {
- await page.evaluate(() => {
- window.scrollTo({
- top: 8000,
- behavior: "smooth"
- });
- });
- });
-
- await new Promise(resolve => setTimeout(resolve, 5000)).then(async() => {
- let itemTitle = searchTitle + '-' + i;
- const imgInfo = await page.evaluate((authority, execNum, itemTitle) => {
- let outObj = {
- title: itemTitle,
- currentPage: 1,
- totalPage: 1,
- urls: [],
- status: '1',
- loading: false
- };
-
- let total = document.querySelector('[class*=quick-result]');
- if(total){
- let pageContent = total.innerText.replace('\n', '').replace('\n', '');
- outObj.currentPage =pageContent.split('/')[0] || 1;
- outObj.totalPage = pageContent.split('/')[1] || 1;
- }else{
- let currentDom = document.querySelector('[class*=pagination_center] [class*=active]');
- if(currentDom){
- outObj.currentPage = currentDom.innerText;
- }
- let totalInfo = document.querySelector('[class*=pagination_total]');
- if(totalInfo){
- utObj.totalPage = totalInfo.innerText.replace('共', '').replace('页', '');
- }
- }
- // 正常
- let arr1 = document.querySelectorAll('[class*=goodsContainer]>div');
- for(let i=0; i< arr1.length; i++){
- let sku = arr1[i].dataset.sku || '';
- let title = arr1[i].querySelector('[class*=goods_title]') ? arr1[i].querySelector('[class*=goods_title]').innerText : '京东商品'+new Date().getTime();
- let priceText = arr1[i].querySelector('[class*=price]') ? arr1[i].querySelector('[class*=price]').innerText : '';
- let price = priceText.replace('¥', '').replaceAll('\n', '');
- let realDom = arr1[i].querySelector('[class*=goods_volume]');
- let realSales = realDom ? realDom.innerText : '';
- let shopNameText = arr1[i].querySelector('[class*=shopFloor]') ? arr1[i].querySelector('[class*=shopFloor]').innerText : '';
- let shopUrl = arr1[i].querySelector('[class*=shopFloor] a') ? arr1[i].querySelector('[class*=shopFloor] a').href : '';
- let mainPic = arr1[i].querySelector('img') ? arr1[i].querySelector('img').src : '';
-
- let info = {
- title: title,
- id: sku,
- href: "https://item.jd.com/" + sku + ".html",
- price: price,
- realSales: realSales,
- shopNameText: shopNameText,
- shopUrl: shopUrl,
- mainPic: mainPic
- }
- outObj.urls.push(info);
- }
- let nextHandle = document.querySelectorAll('[class*=quick-result] [class*=quick-num]');
- if(nextHandle && nextHandle.length > 0){
- nextHandle[1].click({force: true});
- }else{
- nextHandle = document.querySelector('[class*=pagination_center] [class*=pagination_next]');
- if(nextHandle && nextHandle.length > 0){
- nextHandle.click({force: true});
- }
- }
- return outObj;
- }, authority, this.execNum, itemTitle);
- this.jdList.push(imgInfo);
- });
-
- }
-
- await this.jdBrowser.close();
- this.addLoading = false;
-
-
- }catch(e){
- this.addLoading = false;
- this.showError(e);
- }
- })();
- },
-
- // 小红书扫描网址
- redScanUrl(url){
- (async () => {
- try{
- let authority = this.$refs.headerRef.authority.isAuthority;
- let page = await this.redBrowser.newPage();
-
- let responseVideo = [];
- let waitUntil = 'networkidle2';
- waitUntil = this.initDevelop().waitUntil;
- await page.goto(url, {waitUntil : waitUntil});
-
- let searchTitle = await page.title() || '小红书笔记';
- if(searchTitle){
- searchTitle = searchTitle.substring(0, 50);
- if(this.containsAnyChar(searchTitle)){ //判断是否含有特殊字符
- searchTitle = searchTitle.replace(/[\\/:*?"<>|#%&\s]/g, "");
- }
- }
-
- let pageInfo = await page.evaluate(() => {
- let cHeight = document.documentElement.clientHeight;
- let scrollHeight = document.body.scrollHeight;
- return {'scrollHeight': scrollHeight, 'cHeight': cHeight}
- });
-
- let scrollHeight = pageInfo.scrollHeight;
- let cHeight = pageInfo.cHeight;
- let num = Math.ceil(scrollHeight / cHeight);
- let start = -1;
- let scrollTime = this.initMs();
- let scrollInt = setInterval(async() => {
- if(this.redBrowser && !this.redBrowser.isConnected()){
- clearInterval(scrollInt);
- await this.redBrowser.close();
- this.redBrowser = null;
- }
- start ++;
- let outInfo = await page.evaluate((start, searchTitle, url) => {
- let scrollHeight = document.body.scrollHeight;
- let cHeight = document.documentElement.clientHeight;
-
- let outObj = {
- url: url,
- title: searchTitle,
- currentPage: 1,
- totalPage: 1,
- urls: [],
- status: '1',
- loading: false,
- scrollHeight: scrollHeight
- };
- let arr1 = document.querySelectorAll('[class=feeds-container]>section');
- for(let i=0; i< arr1.length; i++){
- let index = arr1[i].dataset.index || '';
- let href = arr1[i].querySelector('a[class*=cover]') ? arr1[i].querySelector('a[class*=cover]').href : '';
- let title = arr1[i].querySelector('[class*=title]') ? arr1[i].querySelector('[class*=title]').innerText : "";
- let realSales = arr1[i].querySelector('[class*=count]') ? arr1[i].querySelector('[class*=count]').innerText : 0;
- let mainPic = arr1[i].querySelector('img') ? arr1[i].querySelector('img').src : '';
- let name = arr1[i].querySelector('[class^=name]') ? arr1[i].querySelector('[class^=name]').innerText : "";
- let time = arr1[i].querySelector('[class^=time]') ? arr1[i].querySelector('[class^=time]').innerText : "";
-
- let info = {
- title: title,
- id: index,
- href: href,
- realSales: realSales,
- mainPic: mainPic,
- name: name,
- time: time
- }
- if(href || title || name){
- outObj.urls.push(info);
- }
- }
-
- window.scrollTo({
- top: cHeight * start,
- behavior: "smooth"
- });
- return outObj;
- }, start, searchTitle, url);
-
- if(this.redList.length == 0){
- this.redList.push(outInfo);
- }else{
- let flag = true;
- for(let i = 0; i < this.redList.length; i++){
- if(outInfo.url == this.redList[i].url){
- flag = false;
- let temp = this.redList[i].urls;
- temp = temp.concat(outInfo.urls);
- let list = temp.filter((item, index) => temp.findIndex(i => i.id === item.id) === index)
- this.redList[i].urls = list;
- }
- }
-
- if(flag){
- this.redList.push(outInfo);
- }
- }
-
- if(outInfo.scrollHeight > 0){
- num = Math.ceil(outInfo.scrollHeight / cHeight);
- }else{
- num = 0;
- }
-
- if(start > num || start > 500){ // 防止页面过长,滚动200次自动停止
- clearInterval(scrollInt);
- await this.redBrowser.close();
- this.redBrowser = null;
- this.addLoading = false;
- }
- }, scrollTime);
- }catch(e){
- this.addLoading = false;
- this.showError(e);
- }
- })();
- },
-
-
- // 普通扫描网址
- commonScanUrl(url){
- (async () => {
- try{
- let authority = this.$refs.headerRef.authority.isAuthority;
- let page = await this.commonBrowser.newPage();
-
- let responseVideo = [];
- let waitUntil = 'networkidle2';
- waitUntil = this.initDevelop().waitUntil;
- await page.goto(url, {waitUntil : waitUntil});
-
- let searchTitle = await page.title() || '网址链接';
- if(searchTitle){
- searchTitle = searchTitle.substring(0, 50);
- if(this.containsAnyChar(searchTitle)){ //判断是否含有特殊字符
- searchTitle = searchTitle.replace(/[\\/:*?"<>|#%&\s]/g, "");
- }
- }
-
- let pageInfo = await page.evaluate(() => {
- let cHeight = document.documentElement.clientHeight;
- let scrollHeight = document.body.scrollHeight;
- return {'scrollHeight': scrollHeight, 'cHeight': cHeight}
- });
-
- let scrollHeight = pageInfo.scrollHeight;
- let cHeight = pageInfo.cHeight;
- let num = Math.ceil(scrollHeight / cHeight);
- let start = -1;
- let scrollTime = this.initMs();
- let scrollInt = setInterval(async() => {
- if(this.commonBrowser && !this.commonBrowser.isConnected()){
- clearInterval(scrollInt);
- await this.commonBrowser.close();
- this.commonBrowser = null;
- }
- start ++;
- let scrollHeight2 = await page.evaluate((start) => {
- let scrollHeight = document.body.scrollHeight;
- let cHeight = document.documentElement.clientHeight;
-
- window.scrollTo({
- top: cHeight * start,
- behavior: "smooth"
- });
- return scrollHeight;
- }, start);
- if(scrollHeight2 > 0){
- num = Math.ceil(scrollHeight2 / cHeight);
- }else{
- num = 0;
- }
-
- if(start > num || start > 200){ // 防止页面过长,滚动200次自动停止
- clearInterval(scrollInt);
-
- let outInfo2 = await page.evaluate((searchTitle, url) => {
- let outObj = {
- url: url,
- title: searchTitle,
- currentPage: 1,
- totalPage: 1,
- urls: [],
- status: '1',
- loading: false
- };
- let arr1 = document.querySelectorAll('a[href^=http]');
- let arr2 = document.querySelectorAll('a[href^="/"]');
- for(let i=0; i< arr1.length; i++){
- let href = arr1[i].href;
- let title = arr1[i].innerText;
-
- let info = {
- title: title,
- href: href
- }
- outObj.urls.push(info);
- }
- for(let j=0; j< arr2.length; j++){
- let href = arr2[j].href;
- let title = arr2[j].innerText;
-
- let info = {
- title: title,
- href: href
- }
- outObj.urls.push(info);
- }
-
- return outObj;
- }, searchTitle, url);
-
- this.commonList.push(outInfo2);
- await this.commonBrowser.close();
- this.addLoading = false;
- }
- }, scrollTime);
- }catch(e){
- this.addLoading = false;
- this.showError(e);
- }
- })();
- },
-
- // 检查天猫淘宝登录状态
- checkLogin(){
- this.checkLoading = true;
- this.tbStatus = 1;
- return new Promise((resolve, reject) => {
- (async () => {
- try{
- if(this.loginBrowser){
- await this.loginBrowser.close();
- this.loginBrowser = null;
- }
- this.loginBrowser = await puppeteer.launch({
- executablePath: this.initPath(),
- args: ['--window-size=1280,800'],
- userDataDir: this.initDataDir()
- });
- const page = await this.loginBrowser.newPage();
- await page.setViewport({ width: 1280, height: 800 });
- let testUrl = 'https://www.taobao.com';
- await page.goto(testUrl, {waitUntil : 'networkidle2'});
-
- let loginInfo = await page.evaluate(() => {
- let navTags = document.querySelector('.site-nav-sign a');
- let userTags = document.querySelector('.site-nav-user a');
-
- if(navTags && navTags.innerHTML.indexOf('登录') > -1){
- return false;
- }else if(userTags){
- return true;
- }else{
- return false;
- }
- });
-
- if(loginInfo){
- this.tbStatus = 2;
- }else{
- this.tbStatus = 3;
- }
-
- resolve(this.tbStatus);
- this.checkLoading = false;
- await this.loginBrowser.close();
- this.loginBrowser = null;
- }catch(e){
- this.checkLoading = false;
- reject(3);
- this.showError(e);
- }
- })();
- });
-
- },
- // 检查阿里巴巴登录状态
- checkAlibabaLogin(){
- this.checkLoading = true;
- this.alibabaStatus = 1;
- return new Promise((resolve, reject) => {
- (async () => {
- try{
- if(this.loginBrowser){
- await this.loginBrowser.close();
- this.loginBrowser = null;
- }
- this.loginBrowser = await puppeteer.launch({
- executablePath: this.initPath(),
- args: ['--window-size=1280,800'],
- userDataDir: this.initDataDir()
- });
- const page = await this.loginBrowser.newPage();
- await page.setViewport({ width: 1280, height: 800 });
- let testUrl = 'https://www.1688.com';
- await page.goto(testUrl, {waitUntil : 'networkidle2'});
-
- const cookies = await page.cookies();
- let loginDiv = await page.$('div[class^=userNotLogin-]');
- const loginEle = await page.$('div[class^=loginAvatar-]');
- let loginText = '';
- if (loginEle) {
- loginText = await page.evaluate(el => el.innerText, loginEle);
- }
- const loginCookie = cookies.find(cookie =>
- cookie.name === '__cn_logon__'
- );
- let logonValue = '';
- if(loginCookie){
- logonValue = loginCookie.value;
- }
- if(loginDiv || loginText == '登录' || logonValue == 'false' || logonValue == false){
- this.alibabaStatus = 3; //未登录
- }else{
- this.alibabaStatus = 2;
- }
-
- resolve(this.alibabaStatus);
- this.checkLoading = false;
- await this.loginBrowser.close();
- this.loginBrowser = null;
- }catch(e){
- this.checkLoading = false;
- reject(3);
- this.showError(e);
- }
- })();
- });
- },
- // 检查京东登录状态
- checkJdLogin(){
- this.checkLoading = true;
- this.jdStatus = 1;
- return new Promise((resolve, reject) => {
- (async () => {
- try{
- if(this.loginBrowser){
- await this.loginBrowser.close();
- this.loginBrowser = null;
- }
- this.loginBrowser = await puppeteer.launch({
- executablePath: this.initPath(),
- userDataDir: this.initDataDir('jd'),
- args: [
- '--start-maximized',
- '--no-sandbox',
- '--disable-setuid-sandbox',
- '--disable-blink-features=AutomationControlled',
- '--window-size=1280,800'
- ]
- });
- const page = await this.loginBrowser.newPage();
- await page.setViewport({ width: 1280, height: 800 });
- let testUrl = 'https://www.jd.com';
- await page.goto(testUrl, {waitUntil : 'networkidle2'});
-
- let loginInfo = await page.evaluate(() => {
- let navTags = document.querySelector('.link-login');
- let userTags = document.querySelector('.nickname');
- let userTags2 = document.querySelector('.nick'); //企业账号
-
- let userInfo2 = document.querySelector('.login_info'); //页面右侧的登录信息
- let userTags3 = false;
- if(userInfo2 && userInfo2.innerText.indexOf('退出') > -1){
- userTags3 = true;
- }
-
- if(navTags && navTags.innerHTML.indexOf('请登录') > -1 && !userTags3){
- return false;
- }else if(userTags || userTags2 || userTags3){
- return true;
- }else{
- return false;
- }
- });
-
- if(loginInfo){
- this.jdStatus = 2;
- }else{
- this.jdStatus = 3;
- }
-
- resolve(this.jdStatus);
- this.checkLoading = false;
- await this.loginBrowser.close();
- this.loginBrowser = null;
- }catch(e){
- this.checkLoading = false;
- reject(3);
- this.showError(e);
- }
- })();
- });
- },
- // 检查小红书登录状态
- checkRedLogin(){
- this.checkLoading = true;
- this.redStatus = 1;
- return new Promise((resolve, reject) => {
- (async () => {
- try{
- if(this.loginBrowser){
- await this.loginBrowser.close();
- this.loginBrowser = null;
- }
- puppeteer.use(StealthPlugin());
- this.loginBrowser = await puppeteer.launch({
- executablePath: this.initPath(),
- userDataDir: this.initDataDir(),
- args: [
- '--start-maximized',
- '--no-sandbox',
- '--disable-setuid-sandbox',
- '--disable-blink-features=AutomationControlled',
- '--window-size=1280,800'
- ],
- });
- const page = await this.loginBrowser.newPage();
- await page.setViewport({ width: 1280, height: 800 });
- let testUrl = "https://www.xiaohongshu.com";
- await page.goto(testUrl, {waitUntil : 'networkidle2'});
-
- let loginBtn = await page.$$('#login-btn');
- let loginContainer = await page.$$('.login-container');
- if(loginContainer.length > 0 || loginBtn.length > 0){
- this.redStatus = 3; //未登录
- }else{
- this.redStatus = 2;
- }
-
- resolve(this.redStatus);
- this.checkLoading = false;
- await this.loginBrowser.close();
- this.loginBrowser = null;
- }catch(e){
- this.checkLoading = false;
- reject(3);
- this.showError(e);
- }
- })();
- });
- },
-
-
- // 去登录
- loginUrl(url){
- (async () => {
- if(this.loginBrowser){
- await this.loginBrowser.close();
- this.loginBrowser = null;
- }
- try{
- if (!fs.existsSync(os.tmpdir() + separator + 'chrome-data-capture')) {
- fs.mkdirSync(os.tmpdir() + separator + 'chrome-data-capture');
- }
- if (!fs.existsSync(os.tmpdir() + separator + 'chrome-data-capture-jd')) {
- fs.mkdirSync(os.tmpdir() + separator + 'chrome-data-capture-jd');
- }
- if (!fs.existsSync(os.tmpdir() + separator + 'chrome-data-capture-local')) {
- fs.mkdirSync(os.tmpdir() + separator + 'chrome-data-capture-local');
- }
-
- let userDataDir = this.initDataDir();
- if(url.indexOf('.jd.com/') > -1){
- userDataDir = this.initDataDir('jd');
- }
-
- puppeteer.use(StealthPlugin());
- this.loginBrowser = await puppeteer.launch({
- headless: false,
- executablePath: this.initPath(),
- args: ['--window-size=1280,800'],
- userDataDir: userDataDir,
- });
- const page = await this.loginBrowser.newPage();
- await page.setViewport({ width: 1280, height: 800 });
-
- await page.evaluateOnNewDocument(() => {
- const newProto = navigator.__proto__;
- delete newProto.webdriver;
- navigator.__proto__ = newProto;
-
- window.navigator.chrome = {
- runtime: {}
- };
- });
- await page.goto(url, {waitUntil : 'networkidle2'});
- }catch(e){
- this.showError(e);
- }
- })();
- },
-
- // 开始解析
- async startParsing(){
- if(this.formatUrl.trim()){
- let formatUrl = this.formatUrl.trim();
- if(formatUrl.indexOf('http://') > -1){
- formatUrl = formatUrl.replace('http://', 'https://');
- }
-
- if(formatUrl.indexOf('https://') == -1){
- this.$message.error('错了哦,请输入正确的视频地址(https://开头)');
- return false;
- }
- let arr = formatUrl.split('https://');
- formatUrl = 'https://' + arr[1];
- this.downloadUrl = formatUrl;
-
- const regex = /https:\/\/.*?.douyin.com/;
- const res = regex.exec(formatUrl);
- this.bUrl = true;
- if(res && res.length > 0){ //抖音视频解析,使用puputter
- this.selectIndex = -1;
- this.videoList = [];
- let reg2 = /[?&]modal_id=(\w+)/;
- let res2 = reg2.exec(formatUrl);
- if(res2){
- let modal_id = res2[1];
- formatUrl = res[0] + '/video/'+modal_id;
- this.downloadUrl = formatUrl;
- }
- this.douyinParsing(formatUrl);
- return false;
- }
-
- this.parseLoading = true;
- this.tabLoading = true;
- this.selectIndex = -1;
- this.videoList = [];
- let userAgent = [];
- let setingAgent = '';
- if(formatUrl.indexOf('weibo.com/') > -1 && setingAgent){
- userAgent = [
- '--add-header',
- 'User-Agent:'+setingAgent,
- '--add-header',
- "Referer:https://weibo.com/"
- ];
- }
- let params = [
- '--no-playlist',
- '--dump-json',
- ...userAgent,
- formatUrl
- ];
- electronApi.spawnExec(['dlp.exe', ...params]).then(res => {
- this.parseLoading = false;
- this.tabLoading = false;
- let info = res.stdout ? res.stdout.toString() : '{formats: []}';
- this.videoInfo = JSON.parse(info);
- this.videoList = this.videoInfo.formats || [];
- const bregex = /https:\/\/.*?.bilibili.com/;
- const bres = bregex.exec(formatUrl);
- if(bres && bres.length > 0){ //b站的视频
- this.bUrl = false;
- }else{
- this.bUrl = true;
- }
- this.biliAudioList = [];
- this.biliAudioIndex = -1;
- this.biliVideoList = [];
- this.biliVideoIndex = -1;
- this.videoList.map(item => {
- item.title = this.videoInfo.title,
- item.status = '1';
- if(!this.bUrl){ // b站的视频
- if(item.resolution.indexOf('audio') > -1 || item.audio_ext != 'none'){
- this.biliAudioList.push(item);
- }else{
- this.biliVideoList.push(item);
- }
- }
- })
- }).catch(err =>{
- this.parseLoading = false;
- this.tabLoading = false;
- // console.log('err1',err.stderr.toString());
- let errStr = err.stderr.toString();
- this.bUrl = true;
- if(errStr.indexOf('Unsupported URL') > -1){
- this.videoParsing(formatUrl);
- return false;
- }else if(formatUrl.indexOf('xiaohongshu.com/') > -1 && errStr.indexOf('No video formats') > -1){
- this.$notify.error({
- title: '设置中登录小红书账号下载!',
- message: errStr
- });
- this.videoParsing(formatUrl);
- return false;
- }else{
- this.$notify.error({
- title: '网址解析失败!',
- message: errStr
- });
- }
- })
- }
- },
- // 复制链接地址
- copyText(text){
- navigator.clipboard.writeText(text).then(() => {
- this.$message({message: '视频下载链接已成功复制到剪贴板', type: 'success'});
- }).catch(err => {
- this.$message.error('无法复制文本', err.toString());
- });
- },
- // 点击复制
- copy(index){
- this.commonUrl = '';
- this.thunderUrl = [];
- let tag = this.videoList[index].tag;
- let urlList = this.videoList[index].urlList;
- let title = this.videoList[index].title;
- let text = urlList[0];
- if(urlList.length <= 0){
- this.$message.error('无法复制下载地址');
- return false;
- }
- if(tag == 'douyin'){
- this.dyModal = true;
- this.dyIndex = index;
-
- urlList.map(uitem => {
- if(uitem.startsWith('https://www.douyin.com/')){
- this.commonUrl = uitem;
- }
- if(!title){
- title = '抖音视频';
- }
- // console.log(`AA`+uitem +`&filename=`+title+`.mp4ZZ`);
- let urlBuffer = Buffer.from(`AA`+uitem +`&filename=`+title+`.mp4ZZ`).toString('base64');
- this.thunderUrl.push('thunder://'+urlBuffer);
- })
- }else{
- this.copyText(text);
- }
- },
-
- // 解析抖音视频
- async douyinParsing(url){
- if(this.loginBrowser){
- await this.loginBrowser.close();
- this.loginBrowser = null;
- }
- if(this.videoBrowser){
- await this.videoBrowser.close();
- this.videoBrowser = null;
- }
- if (!fs.existsSync(os.tmpdir() + separator + 'chrome-data-capture-video')) {
- fs.mkdirSync(os.tmpdir() + separator + 'chrome-data-capture-video');
- }
-
- this.parseLoading = true;
- this.tabLoading = true;
-
- setTimeout(()=> {
- this.parseLoading = false;
- this.tabLoading = false;
- }, 20000)
-
- let userDataDir = os.tmpdir() + separator + 'chrome-data-capture-video';
- // 运行不同平台的浏览器
- puppeteer.use(StealthPlugin());
- let headless = true;
- headless = this.initDevelop().headless;
- this.videoBrowser = await puppeteer.launch({
- headless: headless,
- executablePath: this.initPath(),
- userDataDir: userDataDir,
- args: [
- '--start-maximized',
- '--no-sandbox',
- '--disable-setuid-sandbox',
- '--disable-blink-features=AutomationControlled',
- ]
- });
-
- await new Promise((resolve,reject) =>{
- (async () => {
- try{
- let authority = this.$refs.headerRef.authority.isAuthority;
- const page = await this.videoBrowser.newPage();
-
- let responseVideo = [];
- let responseUrl = [];
- let responseObj = {};
- let vtitle = '视频';
- page.on('response', async(response) => {
- // 检查响应的 MIME 类型是否以 'video/' 开头
- if (response.headers()['content-type'] && response.headers()['content-type'].startsWith('video/')) {
- if(responseVideo.indexOf(response.url()) < 0 && !response.url().startsWith('blob:https://')){
- responseVideo.push(response.url());
- vtitle = await page.title();
- if(vtitle){
- vtitle = vtitle.substring(0, 50);
- if(this.containsAnyChar(vtitle)){ //判断是否含有特殊字符
- vtitle = vtitle.replace(/[\\/:*?"<>|#%&\s]/g, "");
- }
- }
- }
- }
- if (response.headers()['content-type'] && response.headers()['content-type'].startsWith('application/json')) {
- if(response.url().indexOf('/aweme/detail/') > -1){
- if(responseUrl.indexOf(response.url()) < 0){
- responseUrl.push(response.url());
- }else{
- return false;
- }
-
- let jsonText = await response.text();
- if(jsonText && typeof jsonText == 'string'){
- responseObj = JSON.parse(jsonText);
- }
- }
- }
-
- });
- let waitUntil = 'networkidle2';
- waitUntil = this.initDevelop().waitUntil;
- await page.goto(url, {waitUntil : waitUntil});
- await page.waitForTimeout(1000);
- await this.videoBrowser.close();
-
- if(responseObj['aweme_detail']){ // 返回的接口数据中有aweme_detail参数 才会解析接口数据
- let arr = ['aweme_detail']; //'video' ,'play_addr', 'url_list', '2'];
- for(let i = 0; i < arr.length; i++){
- responseObj = responseObj[arr[i]];
- }
-
- if(responseObj && responseObj.preview_title){
- responseObj.preview_title = responseObj.preview_title.substring(0, 50);
- if(this.containsAnyChar(responseObj.preview_title)){ //判断是否含有特殊字符
- responseObj.preview_title = responseObj.preview_title.replace(/[\\/:*?"<>|#%&\s]/g, "");
- }
- }
- if(responseObj && responseObj.video && responseObj.video.play_addr){
- let vinfo = {
- title: responseObj.preview_title,
- tag: 'douyin',
- format_id: 'default',
- ext: 'mp4',
- resolution: responseObj.video.play_addr.width + 'x' + responseObj.video.play_addr.height,
- fps: '-',
- filesize: responseObj.video.play_addr.data_size,
- vcodec: '-',
- acodec: '-',
- urlList: responseObj.video.play_addr.url_list,
- status: '1',
- loading: false
- }
- this.videoList.push(vinfo);
- }
- if(responseObj && responseObj.video && responseObj.video.play_addr_265){
- let vinfo = {
- title: responseObj.preview_title,
- tag: 'douyin',
- format_id: 'play_addr_265',
- ext: 'mp4',
- resolution: responseObj.video.play_addr_265.width + 'x' + responseObj.video.play_addr_265.height,
- fps: '-',
- filesize: responseObj.video.play_addr_265.data_size,
- vcodec: '-',
- acodec: '-',
- urlList: responseObj.video.play_addr_265.url_list,
- status: '1',
- loading: false
- }
- this.videoList.push(vinfo);
- }
- if(responseObj && responseObj.video && responseObj.video.play_addr_h264){
- let vinfo = {
- title: responseObj.preview_title,
- tag: 'douyin',
- format_id: 'play_addr_h264',
- ext: 'mp4',
- resolution: responseObj.video.play_addr_h264.width + 'x' + responseObj.video.play_addr_h264.height,
- fps: '-',
- filesize: responseObj.video.play_addr_h264.data_size,
- vcodec: '-',
- acodec: '-',
- urlList: responseObj.video.play_addr_h264.url_list,
- status: '1',
- loading: false
- }
- this.videoList.push(vinfo);
- }
- }else if(responseVideo.length > 0){ //网页解析到视频地址
- let vinfo = {
- title: vtitle,
- tag: 'douyin',
- format_id: 'video',
- ext: 'mp4',
- resolution: '-',
- fps: '-',
- filesize: '',
- vcodec: '-',
- acodec: '-',
- urlList: responseVideo,
- status: '1',
- loading: false
- }
- this.videoList.push(vinfo);
- }
-
-
-
- this.parseLoading = false;
- this.tabLoading = false;
- }catch(e){
- this.parseLoading = false;
- this.tabLoading = false;
- reject(e);
- this.showError(e);
- }
- })();
- });
-
- },
-
- // 下载网址链接的图片
- async downloadImage(imageUrl, outputPath, urlInfo) {
- let _this = this;
- let received_bytes = 0;
- let total_bytes = 0;
- try {
- let req = request({
- method: 'GET', uri: imageUrl, strictSSL: false
- });
- let out = fs.createWriteStream(outputPath);
- req.pipe(out);
-
- return new Promise((resolve, reject) => {
- req.on('response', (data) => {
- total_bytes = parseInt(data.headers['content-length']);
- const status = data.statusCode;
- if(this.menuIndex != '1'){
- if (status < 200 || status >= 300) {
- this.$notify.error({
- title: '网络资源访问异常!- 1',
- message: imageUrl.slice(0,50)
- });
- }else if(isNaN(total_bytes)){
- this.$notify.error({
- title: '网络资源访问异常!- 2',
- message: imageUrl.slice(0,50)
- });
- }else{
- // console.log('下载中...')
- }
- }
-
- if(status == 403 || isNaN(total_bytes)){
- fs.unlinkSync(outputPath);
- urlInfo.status = '4';
- }
-
- });
- req.on('data', (chunk) => {
- received_bytes += chunk.length;
- if(urlInfo.filesize){
- let size = Number(urlInfo.filesize);
- let percent = Number(received_bytes / size * 100);
- urlInfo.percent = percent.toFixed(2);
- if(percent > 100){
- urlInfo.percent = 100;
- }
- this.$forceUpdate();
- }
- });
-
- req.on('end', ()=> {
- urlInfo.status = '3';
- //console.log('下载完成', outputPath)
- resolve(true);
- });
- });
- } catch (error) {
- urlInfo.status = '4';
- console.error(imageUrl, `Failed to download image: ${error.message}`);
- throw error;
- }
- },
-
- // 获取页面标题 - 生成对应的文件夹
- async getTitle(page, urlInfo){
- // 已页面标题作为新建文件夹,保留前50个字
- let title = await page.title();
- if(title){
- title = title.substring(0, 50);
- if(this.containsAnyChar(title)){ //判断是否含有特殊字符
- title = title.replace(/[\\/:*?"<>|#%&\s]/g, "");
- }
- if (fs.existsSync(this.downloadDir + separator + pjson.softInfo.softName + separator + title)) {
- urlInfo.newPath = this.downloadDir + separator + pjson.softInfo.softName + separator + title;
- } else {
- fs.mkdirSync(this.downloadDir + separator + pjson.softInfo.softName + separator + title);
- urlInfo.newPath = this.downloadDir + separator + pjson.softInfo.softName + separator + title;
- }
- }
- },
-
- // 下载base64位的图片
- async downloadBaseImage(base64String, outputPath, urlInfo) {
- const buffer = Buffer.from(base64String, 'base64');
- const writeStream = fs.createWriteStream(outputPath);
- writeStream.write(buffer);
- writeStream.end();
- writeStream.on('finish', () => {
- urlInfo.num += 1;
- });
- // 监听错误事件
- writeStream.on('error', (err) => {
- console.error('base64位写入文件时出错:', err);
- });
- },
-
- // 错误提示
- showError(e){
- let str = '';
- if(e.toString().indexOf('ERR_NAME_NOT_RESOLVE') > -1){
- str = '无法解析该网址,请查看网址是否正确!-1';
- }else if(e.toString().indexOf('Cannot navigate to invalid URL') > -1){
- str = '无效的网址,请查看网址格式是否正确!-2';
- }else if(e.toString().indexOf('ERR_CONNECTION_TIMED_OUT') > -1){
- str = '链接请求超时,请查看网络状态!-3';
- }else if(e.toString().indexOf('TimeoutError') > -1){
- str = '链接请求超时,请查看网络状态!-4';
- }else if(e.toString().indexOf('operation not permitted') > -1){
- str = '权限受限,请以管理员权限运行软件!-5';
- }else if(e.toString().indexOf('browser has disconnected') > -1){
- str = '内置浏览器已关闭!-6';
- }else if(e.toString().indexOf('Failed to launch the browser') > -1){
- str = '请先关闭内置浏览器!-7';
- }else{
- str = e.toString();
- //console.log(e);
- }
- this.loading = false;
- this.$notify.error({
- title: '提示',
- message: str
- });
- },
-
- // 是否包含特殊字符
- containsAnyChar(str) {
- let charsArray = ['\\', '/', ':', '*', '?', '"', '<', '>', '|', '#', '%' ,'&', ' ', '\t', '\n'];
- for (let i = 0; i < charsArray.length; i++) {
- if (str.includes(charsArray[i])) {
- return true;
- }
- }
- return false;
- },
-
- // 随机生成字符
- randomString(length) {
- let result = '';
- const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
- const charactersLength = characters.length;
- for (let i = 0; i < length; i++ ) {
- result += characters.charAt(Math.floor(Math.random() * charactersLength));
- }
- return result;
- },
-
- //
- formatSeconds(value) {
- var secondTime = parseInt(value); // 秒
- var minuteTime = 0; // 分
- var hourTime = 0; // 小时
- if (secondTime >= 60) {
- minuteTime = parseInt(secondTime / 60);
- secondTime = parseInt(secondTime % 60);
- if (minuteTime >= 60) {
- hourTime = parseInt(minuteTime / 60);
- minuteTime = parseInt(minuteTime % 60);
- }
- }
-
- var result ="" +(parseInt(secondTime) < 10? "0" + parseInt(secondTime): parseInt(secondTime));
- result ="" + (parseInt(minuteTime) < 10? "0" + parseInt(minuteTime) : parseInt(minuteTime)) + ":" + result;
- result ="" + (parseInt(hourTime) < 10 ? "0" + parseInt(hourTime): parseInt(hourTime)) +":" + result;
- return result;
- },
-
- // 视频时间转为秒
- getSs(rawDuration){
- const $ar = rawDuration.split(":");
- let $duration = parseFloat($ar[2]);
- if ($ar[1]) $duration += parseInt($ar[1]) * 60;
- if ($ar[0]) $duration += parseInt($ar[0]) * 60 * 60;
-
- return $duration;
- },
-
- }
- };
- </script>
- <style lang="scss">
- @import "../assets/css/fontx/iconfont.css";
- @import "../assets/css/home.scss";
- .ivu-input-number-controls-outside-btn i {
- font-weight: 800;
- }
- .update-point {
- display: inline-block;
- width: 8px;
- height: 8px;
- border-radius: 8px;
- background: #ff0000;
- top: 14px;
- position: absolute;
- left: -13px;
- }
- .menu-item {
- padding: 8px 0;
- font-size: 14px;
- .iconfont {
- font-size: 32px;
- }
- &:hover,
- &.active {
- color: #ed4014;
- }
- }
- .ivu-progress-show-info .ivu-progress-outer {
- padding-right: 40px !important;
- margin-right: -40px !important;
- }
- .tips {
- text-align: center;
- padding: 10px 0;
- color: #ed4014;
- font-size: 12px;
- }
- .handle-desc {
- display: inline-block;
- width: calc(100% - 100px);
- overflow: hidden;
- }
- .ivu-menu-submenu-title {
- font-weight: 600;
- }
- .ivu-menu .ivu-menu-item {
- line-height: 1;
- }
- // new-el
- .el-menu {
- border-right: none !important;
- }
- .cmenu-item {
- padding: 0 20px 20px;
- margin-bottom: 15px;
- .cmenu-title {
- font-size: 18px;
- font-weight: 600;
- padding-bottom: 20px;
- }
- .citem-nav {
- text-align: center;
- border-radius: 10px;
- min-height: 110px;
- padding: 15px 0;
- background-color: #fff;
- font-size: 15px;
- cursor: pointer;
- &.bg-linear1 {
- color: #fff;
- font-size: 20px;
- background: linear-gradient(to right bottom, #2A56CA, #5795F4);
- }
- &.bg-linear2 {
- color: #fff;
- font-size: 20px;
- background: linear-gradient(to right top, #147FBB, #5EB3E3);
- }
- &.bg-linear3 {
- color: #fff;
- font-size: 20px;
- background: linear-gradient(to right bottom, #2F9E8A, #56CDB1);
- }
- &:hover {
- margin-top: -5px;
- box-shadow: 3px 3px 6px #ccc, -3px -3px 6px #ccc;
- }
- .citem-img {
- width: 50px;
- margin-bottom: 10px;
- }
- }
- }
-
- .popper-open{
- text-align: center !important;
- padding: 10px !important;
- background: #303133 !important;
- color: #fff !important;
- min-width: 120px !important;
- opacity: 0.8;
- }
-
- .popper-open[x-placement^=bottom] .popper__arrow::after{
- border-bottom-color: #303133 !important;
- }
-
- textarea.el-textarea__inner{
- height: 100% !important;
- font-family: "Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","微软雅黑",Arial,sans-serif;
- }
-
- .set-item{
- margin-right: 15px;
-
- .set-title{
- font-size: 13px;
- }
- }
-
- .outarea{
- height: 100%;
- border: 1px solid #DCDFE6;
- background-color: #4851a415;
- padding: 15px;
- font-size: 20px;
- overflow: hidden auto;
- }
-
- .outtext{
- height: 100%;
- font-size: 20px;
- overflow: hidden auto;
-
- textarea{
- background-color: #4851a415;
- }
- }
-
- .pin-tips{
- font-size: 14px;
- position: absolute;
- bottom: 10px;
- color: #ff0000;
- left: 0;
- right: 0;
- margin: auto;
- text-align: center;
- }
-
- .outarea.red-border{
- border: 1px solid #F56C6C;
- }
-
- .outtext.red-border textarea{
- border: 1px solid #F56C6C;
- }
-
- h3{
- margin: 0;
- }
-
- .m-image{
- width: 20px;
- margin-right: 5px;
- }
-
- .dialog-footer-center{
- text-align: center;
- }
-
- .visible-tips-style{
- font-size: 18px;
- color: #f73131;
- font-weight: 600;
- padding: 30px 40px 0;
- }
-
- .no-select{
- user-select: none;
- }
-
- .tips-flex{
- display: flex;
- flex-wrap: nowrap;
- justify-content: space-around;
- align-items: center;
-
- .el-icon-s-opportunity{
- font-size: 50px;
- color: #f73131;
- margin-right: 10px;
- }
-
- .m-title{
- flex: 1;
- color: #f73131;
- }
- }
-
- .c-titles{
- background: -webkit-linear-gradient(left, #FF993F, #FFCE7C 25%, #FF9682 50%, #8e430d 75%, #FF993F);
- color: transparent;
- -webkit-background-clip: text;
- background-size: 200% 100%;
- animation: mask-ani 6s infinite linear;
- font-size: 30px;
- font-weight: 600;
- line-height: 1.5;
- }
-
- @-webkit-keyframes mask-ani {
- 0% {
- background-position: 0 0;
- }
-
- 50% {
- background-position: 100% 0;
- }
-
- 100% {
- background-position: 200% 0;
- }
- }
-
- .soft-icon{
- margin: 0 3px;
- }
-
- .el-upload-list{
- display: none;
- }
-
- </style>
|