修改访问客制站点功能技术架构前的存档

main
cysamurai 4 months ago
parent ddfba0ae1f
commit c76aa923d4

@ -2,6 +2,9 @@ import { resolve } from 'path'
import { defineConfig, externalizeDepsPlugin } from 'electron-vite'
import vue from '@vitejs/plugin-vue'
// const publicDir = resolve('resources')
// const envDir = resolve('build')
export default defineConfig({
main: {
plugins: [externalizeDepsPlugin()]
@ -10,6 +13,8 @@ export default defineConfig({
plugins: [externalizeDepsPlugin()]
},
renderer: {
// publicDir,
// envDir,
resolve: {
alias: {
'@renderer': resolve('src/renderer/src'),

@ -26,6 +26,7 @@
"@electron-toolkit/utils": "^3.0.0",
"@vicons/ionicons5": "^0.13.0",
"axios": "^1.11.0",
"mitt": "^3.0.1",
"naive-ui": "^2.42.0",
"pinia": "^3.0.3",
"vue-router": "^4.5.1"

@ -4,6 +4,7 @@ import { electronApp, optimizer, is } from '@electron-toolkit/utils'
import icon from '../../resources/icon.png?asset'
function createWindow(): void {
// Create the browser window.
const mainWindow = new BrowserWindow({
width: 1280,
@ -14,14 +15,17 @@ function createWindow(): void {
autoHideMenuBar: true,
...(process.platform === 'linux' ? { icon } : {}),
webPreferences: {
preload: join(__dirname, '../preload/index.js'),
sandbox: false
webviewTag: true,
sandbox: true,
// preload: join(__dirname, '../preload/index.js')
}
})
// if (is.dev) {
mainWindow.webContents.openDevTools() //打开调试工具
// }
mainWindow.webContents.setUserAgent('Mozilla/5.0 (Windows NT 10.0...) Chrome/91.0...')
mainWindow.on('ready-to-show', () => {
mainWindow.show()

@ -4,10 +4,10 @@
<meta charset="UTF-8" />
<title>Electron</title>
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
<meta
<!-- <meta
http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:"
/>
content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: http://192.168.0.117:8092 https://zjjcmspublic.oss-cn-hangzhou-zwynet-d01-a.internet.cloud.zj.gov.cn https:; frame-src 'self' https://etax.zhejiang.chinatax.gov.cn:8443 https://portal.zjzwfw.gov.cn https://www.zjzwfw.gov.cn https://etax.chinatax.gov.cn https://www.baidu.com https://chat.deepseek.com https://login.gjzwfw.gov.cn; form-action 'self' https://portal.zjzwfw.gov.cn https://login.gjzwfw.gov.cn"
/> -->
</head>
<body>

@ -7,3 +7,10 @@ export function loginByJson(data) {
data
})
}
export function getMenus() {
return request({
url: '/platforms',
method: 'get'
})
}

@ -1,13 +1,41 @@
<script setup lang="ts">
import { NGrid, NGridItem, NButton, NIcon } from 'naive-ui'
import { HomeOutline } from '@vicons/ionicons5'
import { NGrid, NGridItem, NButton, NIcon, NModal } from 'naive-ui'
import { HomeOutline, ExitOutline, AlertCircleOutline } from '@vicons/ionicons5'
import router from '@renderer/router'
import { ref } from 'vue'
import eventBus from '@renderer/utils/eventBus'
const bodyStyle = {
width: '600px'
}
const segmented = {
content: 'soft',
footer: 'soft'
} as const
let isShowNaviList = ref(false)
const goBackToMenu = () => {
router.push('/home/menu')
}
const showNaviList = () => {
isShowNaviList.value = !isShowNaviList.value
}
const handleLogout = async () => {
console.log('logout btn clicked')
eventBus.emit('logout-sent')
// router.push('/')
}
</script>
<template>
<div class="header-bg">
<n-grid x-gap="15" :cols="6">
<n-grid x-gap="24" :cols="8">
<n-grid-item class="col-center" >
<NButton color="#fff" ghost size="tiny" :strong="true">
<NButton color="#fff" ghost size="tiny" :strong="true" @click="goBackToMenu">
<template #icon>
<n-icon>
<HomeOutline />
@ -15,10 +43,19 @@ import { HomeOutline } from '@vicons/ionicons5'
</template>返回菜单
</NButton>
</n-grid-item>
<n-grid-item :span="2">
<n-button class="navi-div" @click="showNaviList">
<div>
<n-icon :component="AlertCircleOutline" size="12" color="#0e7a0d"/>
</div>
<span class="navi-span">请选择需要办理的业务</span>
<a class="navi-a">请点击这里进行选择</a>
</n-button>
</n-grid-item>
<n-grid-item></n-grid-item>
<n-grid-item></n-grid-item>
<n-grid-item></n-grid-item>
<n-grid-item class="col-center">
<n-grid-item class="col-right">
<NButton color="#fff" ghost size="tiny" :strong="true">
<template #icon>
<n-icon>
@ -28,22 +65,47 @@ import { HomeOutline } from '@vicons/ionicons5'
</NButton>
</n-grid-item>
<n-grid-item class="col-center">
<NButton color="#fff" ghost size="tiny" :strong="true">
<NButton color="#fff" ghost size="tiny" :strong="true" @click="handleLogout">
<template #icon>
<n-icon>
<HomeOutline />
<ExitOutline />
</n-icon>
</template>退出登录
</NButton>
</n-grid-item>
</n-grid>
</div>
<n-modal
v-model:show="isShowNaviList"
class="custom-card"
preset="card"
:style="bodyStyle"
title="请选择您要办理的业务"
size="huge"
:bordered="false"
:segmented="segmented"
>
<template #header-extra></template>
<!-- <n-data-table
:bordered="false"
:columns="columns"
:data="data"
:pagination="pagination"
/> -->
</n-modal>
</template>
<style lang="scss">
.col-center{
display: flex;
justify-content: center;
align-items: center;
}
.col-right{
display: flex;
justify-content: right;
align-items: center;
}
.header-bg{
@ -51,6 +113,23 @@ import { HomeOutline } from '@vicons/ionicons5'
align-items: center;
height: 8vh;
width: 100vw;
background-color: #FFD39B;
padding: 0 20px;
background-color: #EEAD0E;
.navi-div{
background-color: #fff;
border-radius: 5px;
.navi-span{
margin-left: 6px;
font-size: 12px;
color: #000;
}
.navi-a{
font-size: 12px;
color: #000fff;
}
}
}
</style>
</style>

@ -8,9 +8,23 @@ export default createRouter({
history: createWebHashHistory(),
routes: [
{ path: '/', component: Login },
{ path: '/home', component: Home, children:[
{ path: 'menu', component: Menu },
{ path:'webContainer', component: WebContainer}
] }
{
path: '/home', component: Home, children: [
{
path: 'menu',
component: Menu,
meta: {
KeepAlive: true
}
},
{
path: 'webContainer',
component: WebContainer,
meta: {
KeepAlive: true
}
}
]
}
]
})

@ -0,0 +1,23 @@
import { defineStore } from 'pinia'
import { getMenus } from '@renderer/api/api'
export const useMenusStore = defineStore('Menus', {
state: () => {
return {
menus: []
}
},
getters: {},
actions: {
async getMenusAction() {
let res = await getMenus()
// console.log(res.data)
this.menus = res.data.data.slice(0, res.data.data.length)
},
getMenusDebug(items) {
// let res = getMenus()
// console.log(res.data)
this.menus = items.slice(0, items.length)
}
}
})

@ -0,0 +1,52 @@
import { defineStore } from 'pinia'
interface Tab {
id: string
url: string
title: string
active: boolean
}
export const useTabsStore = defineStore('tabs', {
state: () => ({
tabs: [] as Tab[],
currentTabId: null as string | null
}),
actions: {
addTab(item: { platformUrl: string; platformName: string }) {
const existingTab = this.tabs.find(tab => tab.url === item.platformUrl)
if (existingTab) {
this.currentTabId = existingTab.id
return existingTab.id
}
const newTab = {
id: Date.now().toString(),
url: item.platformUrl,
title: item.platformName,
active: true
}
this.tabs.forEach(tab => tab.active = false)
this.tabs.push(newTab)
this.currentTabId = newTab.id
return newTab.id
},
setActiveTab(tabId: string) {
this.tabs.forEach(tab => {
tab.active = tab.id === tabId
})
this.currentTabId = tabId
},
closeTab(tabId: string) {
this.tabs = this.tabs.filter(tab => tab.id !== tabId)
if (this.currentTabId === tabId) {
this.currentTabId = this.tabs[0]?.id || null
}
}
},
getters: {
activeTab: (state) => state.tabs.find(tab => tab.id === state.currentTabId)
}
})

@ -0,0 +1,6 @@
// event-bus.js
import mitt from 'mitt'
const emitter = mitt()
export default emitter

@ -6,12 +6,16 @@ import HomeHeader from '@renderer/components/HomeHeader.vue';
<template>
<div class="home-bg">
<HomeHeader />
<router-view />
<router-view v-slot="{ Component }">
<keep-alive>
<component :is="Component" />
</keep-alive>
</router-view>
</div>
</template>
<style lang="css">
.home-bg{
.home-bg {
height: 100vh;
width: 100vw;
background-color: #66ccff;

@ -13,7 +13,7 @@ const login = async () => {
})
console.log('Login response:', res)
if (res.data.code == 200) {
router.push('/home')
router.push('/home/menu')
} else {
console.error('Login failed:', res.data)
dialog.error({

@ -1,153 +1,181 @@
<script setup lang="ts">
interface Item {
platformUrl: string
platformId: number
platformName: string
platformIcon: string
platformUrl: string
platformId: number
platformName: string
platformIcon: string
}
const items: Item[] = [
{
"platformUrl": "https://etax.zhejiang.chinatax.gov.cn:8443/",
"platformId": 1,
"platformName": "浙江电子税务局",
"platformIcon": "http://192.168.0.117:8092/images/zj-tax.png"
},
{
"platformUrl": "https://portal.zjzwfw.gov.cn/pc/portal/hall/#/MainLobby",
"platformId": 2,
"platformName": "浙江政务服务网",
"platformIcon": "https://zjjcmspublic.oss-cn-hangzhou-zwynet-d01-a.internet.cloud.zj.gov.cn/jcms_files/jcms1/web1/site/script/zjservice/resources/index1/newImg/zjzwLogo.png"
},
{
"platformUrl": "https://www.zjzwfw.gov.cn/zjzwfw/",
"platformId": 3,
"platformName": "浙里办",
"platformIcon": "https://zjjcmspublic.oss-cn-hangzhou-zwynet-d01-a.internet.cloud.zj.gov.cn/jcms_files/jcms1/web1/site/script/zjservice/resources/index1/newImg/zjzwLogo.png"
},
{
"platformUrl": "https://etax.chinatax.gov.cn",
"platformId": 4,
"platformName": "自然人电子税务局",
"platformIcon": "http://192.168.0.117:8092/images/personal-tax.png"
},
{
"platformUrl": "https://www.baidu.com/",
"platformId": 5,
"platformName": "百度",
"platformIcon": "http://192.168.0.117:8092/images/personal-tax.png"
},
{
"platformUrl": "https://https://chat.deepseek.com/",
"platformId": 6,
"platformName": "Deepseek",
"platformIcon": "http://192.168.0.117:8092/images/personal-tax.png"
}
{
"platformUrl": "https://etax.zhejiang.chinatax.gov.cn:8443/",
"platformId": 1,
"platformName": "浙江电子税务局",
"platformIcon": "http://192.168.0.117:8092/images/zj-tax.png"
},
{
"platformUrl": "https://www.zjzwfw.gov.cn/zjservice-fe/#/home",
"platformId": 2,
"platformName": "浙江政务服务网",
"platformIcon": "https://zjjcmspublic.oss-cn-hangzhou-zwynet-d01-a.internet.cloud.zj.gov.cn/jcms_files/jcms1/web1/site/script/zjservice/resources/index1/newImg/zjzwLogo.png"
},
{
"platformUrl": "https://www.zjzwfw.gov.cn/zjzwfw/",
"platformId": 3,
"platformName": "浙里办",
"platformIcon": "https://zjjcmspublic.oss-cn-hangzhou-zwynet-d01-a.internet.cloud.zj.gov.cn/jcms_files/jcms1/web1/site/script/zjservice/resources/index1/newImg/zjzwLogo.png"
},
{
"platformUrl": "https://etax.chinatax.gov.cn",
"platformId": 4,
"platformName": "自然人电子税务局",
"platformIcon": "http://192.168.0.117:8092/images/personal-tax.png"
},
{
"platformUrl": "https://www.baidu.com/",
"platformId": 5,
"platformName": "百度",
"platformIcon": "http://192.168.0.117:8092/images/personal-tax.png"
},
{
"platformUrl": "https://https://chat.deepseek.com/",
"platformId": 6,
"platformName": "Deepseek",
"platformIcon": "http://192.168.0.117:8092/images/personal-tax.png"
}
]
import { NButton } from 'naive-ui';
import router from '@renderer/router'
import { NIcon } from 'naive-ui';
import { ArrowBackCircleOutline, ArrowForwardCircleOutline } from '@vicons/ionicons5'
import { onMounted, ref } from 'vue';
import { useMenusStore } from '@renderer/store/menus'
const menusStore = useMenusStore()
const currentIndex = ref(0)
const visibleCount = ref(4)
let currentButtonList: Item[] = []
const currentButtonList = ref<Item[]>([])
onMounted(() => {
initButtonList()
// initButtonList()
initButtonDebug()
})
const initButtonList = () => {
currentButtonList = items.slice(0, 3)
console.log(currentButtonList)
const initButtonList = async () => {
await menusStore.getMenusAction()
if (menusStore.menus.length > 0) {
currentButtonList.value = menusStore.menus.slice(0, 4)
visibleCount.value = menusStore.menus.length
}
// currentButtonList.value = items.slice(0, 4)
console.log(currentButtonList.value)
}
const initButtonDebug = () => {
menusStore.getMenusDebug(items)
if (menusStore.menus.length > 0) {
currentButtonList.value = menusStore.menus.slice(0, 4)
visibleCount.value = menusStore.menus.length
}
}
const handleClick = (item) => {
console.log(item.platformUrl)
router.push({
path: '/home/webContainer',
query: item
})
}
const goLeft = () => {
currentIndex.value--
currentButtonList = items.slice(currentIndex.value, currentIndex.value + 3)
console.log(currentIndex.value)
currentIndex.value--
currentButtonList.value = menusStore.menus.slice(currentIndex.value, currentIndex.value + 4)
}
const goRight = () => {
currentIndex.value++
currentButtonList = items.slice(currentIndex.value, currentIndex.value + 3)
console.log(currentIndex.value)
currentIndex.value++
currentButtonList.value = menusStore.menus.slice(currentIndex.value, currentIndex.value + 4)
}
</script>
<template>
<div class="menu-bg">
<div class="side-div">
<NButton @click="goLeft" :disabled="currentIndex <= 0">{{ '<' }}</NButton>
</div>
<div class="center-div">
<div v-for="(item, index) in currentButtonList" :key="index" class="custom-button" @click="handleClick(item)">
<img :src="item.platformIcon" alt="" class="button-image">
<span class="button-text">{{ item.platformName }}</span>
</div>
</div>
<div class="side-div">
<NButton @click="goRight" :disabled="currentIndex >= 6">{{ '>' }}</NButton>
</div>
<div class="menu-bg">
<div class="side-div">
<a @click="goLeft" v-show="!(currentIndex <= 0)">
<n-icon size="50">
<ArrowBackCircleOutline />
</n-icon>
</a>
</div>
<div class="center-div">
<div v-for="(item, index) in currentButtonList" :key="index" class="custom-button" @click="handleClick(item)">
<img :src="item.platformIcon" alt="" class="button-image">
<span class="button-text">{{ item.platformName }}</span>
</div>
</div>
<div class="side-div">
<a @click="goRight" v-show="!(currentIndex >= visibleCount - 4)">
<n-icon size="50">
<ArrowForwardCircleOutline />
</n-icon>
</a>
</div>
</div>
</template>
<style lang="scss">
.menu-bg {
display: flex;
justify-content: center;
align-items: center;
height: 92vh;
width: 100vw;
.center-div {
display: flex;
justify-content: center;
align-items: center;
height: 92vh;
width: 100vw;
.center-div {
display: flex;
justify-content: center;
align-items: center;
height: 550px;
width: 1100px;
background-color: rgba($color: #fff, $alpha: 0.5);
flex-direction: row;
transition: transform 0.3s ease;
.custom-button {
display: flex;
flex: 0 0 20%;
flex-direction: column;
justify-content: center;
align-items: center;
height: 50%;
padding: 10px;
margin: 20px;
cursor: pointer;
transition: all 0.2s;
background-color: #6699ff;
.button-image {
width: 100px;
height: 100px;
object-fit: contain;
margin: 15px 0;
}
.button-text {
font-size: 20px;
font-weight: 600;
text-align: center;
margin-top: 20px;
}
}
.custom-button:hover {
transform: scale(1.05);
}
height: 550px;
width: 1100px;
background-color: rgba($color: #fff, $alpha: 0.5);
flex-direction: row;
transition: transform 0.3s ease;
.custom-button {
display: flex;
flex: 0 0 20%;
flex-direction: column;
justify-content: center;
align-items: center;
height: 50%;
padding: 10px;
margin: 20px;
cursor: pointer;
transition: all 0.2s;
background-color: #6699ff;
.button-image {
width: 100px;
height: 100px;
object-fit: contain;
margin: 15px 0;
}
.button-text {
font-size: 20px;
font-weight: 600;
text-align: center;
margin-top: 20px;
}
}
.side-div {
margin: 40px;
.custom-button:hover {
transform: scale(1.05);
}
}
.side-div {
margin: 40px;
width: 60px;
}
}
</style>

@ -1,7 +1,168 @@
<script setup lang="ts">
defineOptions({
name: 'WebContainer'
})
import { onBeforeUnmount, onMounted, watch, ref } from 'vue'
import { useRoute } from 'vue-router'
import { useTabsStore } from '@renderer/store/tabs'
import { NIcon } from 'naive-ui'
import { CloseCircleOutline } from '@vicons/ionicons5'
import eventBus from '@renderer/utils/eventBus'
const route = useRoute()
const tabsStore = useTabsStore()
// const webviewRefs = ref<webview[]>([])
// const tabs = ref([...]) //
// Initialize with current route item
watch(() => route.query, (newQuery) => {
if (newQuery.platformUrl) {
tabsStore.addTab({
platformUrl: newQuery.platformUrl as string,
platformName: newQuery.platformName as string
})
}
}, { immediate: true })
onMounted(() => {
eventBus.on('logout-sent', navigateToLogout)
})
onBeforeUnmount(() => {
eventBus.off('logout-sent', navigateToLogout)
})
// ref
// const setWebviewRef = (el) => {
// if (el) {
// webviewRefs.value.push(el)
// }
// }
const navigateToLogout = async () => {
//
const logoutScript = `
//
const logoutSelectors = [
'#logout',
'[href*="logout"]',
'button[onclick*="logout"]',
'.logout-btn'
]
let foundLogout = false
for (const selector of logoutSelectors) {
const btn = document.querySelector(selector)
if (btn) {
btn.click()
foundLogout = true
break
}
}
//
localStorage.clear()
sessionStorage.clear()
// cookies
document.cookie.split(";").forEach(c => {
document.cookie = c.replace(/^ +/, "")
.replace(/=.*/, "=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/")
})
foundLogout
`
const webviews = document.querySelectorAll('webview')
console.log(webviews)
// webview
webviews.forEach(webview => {
webview.addEventListener('close', () => {
console.log('webview被关闭')
// webview.src = 'about:blank'
// webview.executeJavaScript(logoutScript)
})
// Electron webview API
// webview.executeJavaScript(logoutScript)
// .then(success => {
// if (success) {
// console.log('')
// webview.reload(); //
// }
// })
// .catch(err => console.error(':', err))
})
}
</script>
<template>
<div>WebContainer</div>
</template>
<div class="web-container">
<div class="tabs">
<div v-for="tab in tabsStore.tabs" :key="tab.id" :class="['tab', { active: tab.id === tabsStore.currentTabId }]"
@click="tabsStore.setActiveTab(tab.id)">
<span class="title-tab">{{ tab.title }}</span>
<span class="title-tab close-tab" @click.stop="tabsStore.closeTab(tab.id)">
<n-icon :component="CloseCircleOutline" size="10" :depth="3" />
</span>
</div>
</div>
<div class="web-content">
<webview v-for="tab in tabsStore.tabs" v-show="tab.id === tabsStore.currentTabId" :key="tab.id" :src="tab.url"
sandbox="allow-same-origin allow-scripts" frameborder="0" class="webview" :data-tab-id="tab.id"></webview>
</div>
</div>
</template>
<style lang="scss" scoped>
.web-container {
display: flex;
flex-direction: column;
height: 92vh;
width: 100vw;
}
.tabs {
display: flex;
background: #f0f0f0;
// padding: 8px 8px 0;
}
.tab {
padding: 0 6px 0 10px;
margin-left: 4px;
background: #ddd;
color: #000;
border-radius: 4px 4px 0 0;
cursor: pointer;
.title-tab {
font-size: 12px;
}
.close-tab {
margin-left: 10px;
cursor: pointer;
}
.close-tab:hover {
color: red;
}
}
.tab.active {
background: #fff;
color: #000;
font-weight: bold;
}
.web-content {
flex: 1;
}
.webview {
width: 100%;
height: 100%;
}
</style>

@ -2822,7 +2822,7 @@ minizlib@^2.1.1:
mitt@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/mitt/-/mitt-3.0.1.tgz#ea36cf0cc30403601ae074c8f77b7092cdab36d1"
resolved "https://registry.npmmirror.com/mitt/-/mitt-3.0.1.tgz#ea36cf0cc30403601ae074c8f77b7092cdab36d1"
integrity sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==
mkdirp@^1.0.3:
@ -3358,16 +3358,7 @@ stat-mode@^1.0.0:
resolved "https://registry.yarnpkg.com/stat-mode/-/stat-mode-1.0.0.tgz#68b55cb61ea639ff57136f36b216a291800d1465"
integrity sha512-jH9EhtKIjuXZ2cWxmXS8ZP80XyC3iasQxMDV8jzhNJpfDb7VbQLVW4Wvsxz9QZvzV+G4YoSfBUVKDOyxLzi/sg==
"string-width-cjs@npm:string-width@^4.2.0":
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
dependencies:
emoji-regex "^8.0.0"
is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.1"
string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
@ -3385,14 +3376,7 @@ string-width@^5.0.1, string-width@^5.1.2:
emoji-regex "^9.2.2"
strip-ansi "^7.0.1"
"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
dependencies:
ansi-regex "^5.0.1"
strip-ansi@^6.0.0, strip-ansi@^6.0.1:
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
@ -3670,16 +3654,7 @@ word-wrap@^1.2.5:
resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34"
integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
dependencies:
ansi-styles "^4.0.0"
string-width "^4.1.0"
strip-ansi "^6.0.0"
wrap-ansi@^7.0.0:
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==

Loading…
Cancel
Save