mirror of
https://github.com/viarotel-org/escrcpy.git
synced 2025-01-18 17:14:10 +01:00
perf: 🚀 支持通过操作栏安装应用并提供相应安装反馈
This commit is contained in:
parent
763d6c56a2
commit
3bd2075324
@ -6,7 +6,7 @@ import dayjs from 'dayjs'
|
||||
import { Adb } from '@devicefarmer/adbkit'
|
||||
import { adbPath } from '@electron/configs/index.js'
|
||||
|
||||
console.log('adbPath', adbPath)
|
||||
// console.log('adbPath', adbPath)
|
||||
|
||||
const exec = util.promisify(child_process.exec)
|
||||
|
||||
@ -19,12 +19,11 @@ window.addEventListener('beforeunload', () => {
|
||||
})
|
||||
|
||||
const shell = async command => exec(`${adbPath} ${command}`)
|
||||
const getDevices = async () => await client.listDevicesWithPaths()
|
||||
const deviceShell = async (id, command) =>
|
||||
await client.getDevice(id).shell(command)
|
||||
const kill = async (...params) => await client.kill(...params)
|
||||
const connect = async (...params) => await client.connect(...params)
|
||||
const disconnect = async (...params) => await client.disconnect(...params)
|
||||
const getDevices = async () => client.listDevicesWithPaths()
|
||||
const deviceShell = async (id, command) => client.getDevice(id).shell(command)
|
||||
const kill = async (...params) => client.kill(...params)
|
||||
const connect = async (...params) => client.connect(...params)
|
||||
const disconnect = async (...params) => client.disconnect(...params)
|
||||
|
||||
const getDeviceIP = async (id) => {
|
||||
try {
|
||||
@ -40,7 +39,7 @@ const getDeviceIP = async (id) => {
|
||||
}
|
||||
}
|
||||
|
||||
const tcpip = async (id, port = 5555) => await client.getDevice(id).tcpip(port)
|
||||
const tcpip = async (id, port = 5555) => client.getDevice(id).tcpip(port)
|
||||
|
||||
const screencap = async (deviceId, options = {}) => {
|
||||
let fileStream = null
|
||||
@ -74,6 +73,8 @@ const screencap = async (deviceId, options = {}) => {
|
||||
})
|
||||
}
|
||||
|
||||
const install = async (id, path) => client.getDevice(id).install(path)
|
||||
|
||||
const watch = async (callback) => {
|
||||
const tracker = await client.trackDevices()
|
||||
tracker.on('add', async (ret) => {
|
||||
@ -112,6 +113,7 @@ export default () => {
|
||||
getDeviceIP,
|
||||
tcpip,
|
||||
screencap,
|
||||
install,
|
||||
watch,
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,48 @@
|
||||
import util from 'node:util'
|
||||
import child_process from 'node:child_process'
|
||||
import { spawn } from 'node:child_process'
|
||||
import { adbPath, scrcpyPath } from '@electron/configs/index.js'
|
||||
|
||||
const exec = util.promisify(child_process.exec)
|
||||
const shell = async (command, { stdout, stderr } = {}) => {
|
||||
const args = command.split(' ')
|
||||
const scrcpyProcess = spawn(scrcpyPath, args, {
|
||||
env: { ...process.env, ADB: adbPath },
|
||||
shell: true,
|
||||
})
|
||||
|
||||
const shell = command =>
|
||||
exec(`${scrcpyPath} ${command}`, { env: { ...process.env, ADB: adbPath } })
|
||||
scrcpyProcess.stdout.on('data', (data) => {
|
||||
const stringData = data.toString()
|
||||
|
||||
console.log('scrcpyProcess.stdout.data:', stringData)
|
||||
|
||||
if (stdout) {
|
||||
stdout(stringData)
|
||||
}
|
||||
})
|
||||
|
||||
scrcpyProcess.stderr.on('data', (data) => {
|
||||
const stringData = data.toString()
|
||||
|
||||
console.error('scrcpyProcess.stderr.data:', stringData)
|
||||
|
||||
if (stderr) {
|
||||
stderr(stringData)
|
||||
}
|
||||
})
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
scrcpyProcess.on('close', (code) => {
|
||||
if (code === 0) {
|
||||
resolve()
|
||||
}
|
||||
else {
|
||||
reject(new Error(`Command failed with code ${code}`))
|
||||
}
|
||||
})
|
||||
|
||||
scrcpyProcess.on('error', (err) => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export default () => ({
|
||||
shell,
|
||||
|
@ -14,6 +14,7 @@
|
||||
"build:linux": "vite build && electron-builder --linux",
|
||||
"preview": "vite preview",
|
||||
"lint": "eslint . --ext .md,.vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --ignore-path .eslintignore --fix",
|
||||
"svgo": "svgo -f src/icons/svg --config=src/icons/svgo.config.js",
|
||||
"postinstall": "electron-builder install-app-deps"
|
||||
},
|
||||
"dependencies": {
|
||||
@ -40,6 +41,7 @@
|
||||
"vite-plugin-electron": "^0.14.0",
|
||||
"vite-plugin-electron-renderer": "^0.14.5",
|
||||
"vite-plugin-eslint": "^1.8.1",
|
||||
"vite-svg-loader": "^4.0.0",
|
||||
"vue-tsc": "^1.8.8"
|
||||
}
|
||||
}
|
||||
|
67
pnpm-lock.yaml
generated
67
pnpm-lock.yaml
generated
@ -70,6 +70,9 @@ devDependencies:
|
||||
vite-plugin-eslint:
|
||||
specifier: ^1.8.1
|
||||
version: 1.8.1(eslint@8.51.0)(vite@4.4.11)
|
||||
vite-svg-loader:
|
||||
specifier: ^4.0.0
|
||||
version: 4.0.0
|
||||
vue-tsc:
|
||||
specifier: ^1.8.8
|
||||
version: 1.8.19(typescript@5.2.2)
|
||||
@ -781,6 +784,11 @@ packages:
|
||||
engines: {node: '>= 10'}
|
||||
dev: true
|
||||
|
||||
/@trysound/sax@0.2.0:
|
||||
resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==}
|
||||
engines: {node: '>=10.13.0'}
|
||||
dev: true
|
||||
|
||||
/@types/cacheable-request@6.0.3:
|
||||
resolution: {integrity: sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==}
|
||||
dependencies:
|
||||
@ -2035,6 +2043,11 @@ packages:
|
||||
engines: {node: '>= 6'}
|
||||
dev: true
|
||||
|
||||
/commander@7.2.0:
|
||||
resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==}
|
||||
engines: {node: '>= 10'}
|
||||
dev: true
|
||||
|
||||
/commander@9.5.0:
|
||||
resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==}
|
||||
engines: {node: ^12.20.0 || >=14}
|
||||
@ -2084,6 +2097,16 @@ packages:
|
||||
which: 2.0.2
|
||||
dev: true
|
||||
|
||||
/css-select@5.1.0:
|
||||
resolution: {integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==}
|
||||
dependencies:
|
||||
boolbase: 1.0.0
|
||||
css-what: 6.1.0
|
||||
domhandler: 5.0.3
|
||||
domutils: 3.1.0
|
||||
nth-check: 2.1.1
|
||||
dev: true
|
||||
|
||||
/css-selector-tokenizer@0.8.0:
|
||||
resolution: {integrity: sha512-Jd6Ig3/pe62/qe5SBPTN8h8LeUg/pT4lLgtavPf7updwwHpvFzxvOQBHYj2LZDMjUnBzgvIUSjRcf6oT5HzHFg==}
|
||||
dependencies:
|
||||
@ -2091,6 +2114,14 @@ packages:
|
||||
fastparse: 1.1.2
|
||||
dev: true
|
||||
|
||||
/css-tree@2.2.1:
|
||||
resolution: {integrity: sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==}
|
||||
engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'}
|
||||
dependencies:
|
||||
mdn-data: 2.0.28
|
||||
source-map-js: 1.0.2
|
||||
dev: true
|
||||
|
||||
/css-tree@2.3.1:
|
||||
resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==}
|
||||
engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0}
|
||||
@ -2099,12 +2130,24 @@ packages:
|
||||
source-map-js: 1.0.2
|
||||
dev: true
|
||||
|
||||
/css-what@6.1.0:
|
||||
resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==}
|
||||
engines: {node: '>= 6'}
|
||||
dev: true
|
||||
|
||||
/cssesc@3.0.0:
|
||||
resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
|
||||
engines: {node: '>=4'}
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/csso@5.0.5:
|
||||
resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==}
|
||||
engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'}
|
||||
dependencies:
|
||||
css-tree: 2.2.1
|
||||
dev: true
|
||||
|
||||
/csstype@3.1.2:
|
||||
resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==}
|
||||
|
||||
@ -3696,6 +3739,10 @@ packages:
|
||||
resolution: {integrity: sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w==}
|
||||
dev: true
|
||||
|
||||
/mdn-data@2.0.28:
|
||||
resolution: {integrity: sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==}
|
||||
dev: true
|
||||
|
||||
/mdn-data@2.0.30:
|
||||
resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==}
|
||||
dev: true
|
||||
@ -4644,6 +4691,19 @@ packages:
|
||||
engines: {node: '>= 0.4'}
|
||||
dev: true
|
||||
|
||||
/svgo@3.0.2:
|
||||
resolution: {integrity: sha512-Z706C1U2pb1+JGP48fbazf3KxHrWOsLme6Rv7imFBn5EnuanDW1GPaA/P1/dvObE670JDePC3mnj0k0B7P0jjQ==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
'@trysound/sax': 0.2.0
|
||||
commander: 7.2.0
|
||||
css-select: 5.1.0
|
||||
css-tree: 2.3.1
|
||||
csso: 5.0.5
|
||||
picocolors: 1.0.0
|
||||
dev: true
|
||||
|
||||
/tailwindcss@3.3.3:
|
||||
resolution: {integrity: sha512-A0KgSkef7eE4Mf+nKJ83i75TMyq8HqY3qmFIJSWy8bNt0v1lG7jUcpGpoTFxAwYcWOphcTBLPPJg+bDfhDf52w==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
@ -4991,6 +5051,13 @@ packages:
|
||||
vite: 4.4.11
|
||||
dev: true
|
||||
|
||||
/vite-svg-loader@4.0.0:
|
||||
resolution: {integrity: sha512-0MMf1yzzSYlV4MGePsLVAOqXsbF5IVxbn4EEzqRnWxTQl8BJg/cfwIzfQNmNQxZp5XXwd4kyRKF1LytuHZTnqA==}
|
||||
dependencies:
|
||||
'@vue/compiler-sfc': 3.3.4
|
||||
svgo: 3.0.2
|
||||
dev: true
|
||||
|
||||
/vite@4.4.11:
|
||||
resolution: {integrity: sha512-ksNZJlkcU9b0lBwAGZGGaZHCMqHsc8OpgtoYhsQ4/I2v5cnpmmmqe5pM4nv/4Hn6G/2GhTdj0DhZh2e+Er1q5A==}
|
||||
engines: {node: ^14.18.0 || >=16.0.0}
|
||||
|
@ -6,11 +6,16 @@
|
||||
type="primary"
|
||||
plain
|
||||
class="!border-none !mx-0 bg-transparent !rounded-0"
|
||||
:icon="item.icon"
|
||||
:disabled="device.$unauthorized"
|
||||
:title="item.tips"
|
||||
@click="handleClick(item)"
|
||||
>
|
||||
<template #icon>
|
||||
<svg-icon v-if="item.svgIcon" :name="item.svgIcon"></svg-icon>
|
||||
<el-icon v-else-if="item.elIcon" class="">
|
||||
<component :is="item.elIcon" />
|
||||
</el-icon>
|
||||
</template>
|
||||
{{ item.label }}
|
||||
</el-button>
|
||||
</div>
|
||||
@ -32,37 +37,43 @@ export default {
|
||||
controlModel: [
|
||||
{
|
||||
label: '切换键',
|
||||
icon: 'Switch',
|
||||
elIcon: 'Switch',
|
||||
command: 'input keyevent KEYCODE_APP_SWITCH',
|
||||
},
|
||||
{
|
||||
label: '主屏幕键',
|
||||
icon: 'HomeFilled',
|
||||
elIcon: 'HomeFilled',
|
||||
command: 'input keyevent KEYCODE_HOME',
|
||||
},
|
||||
{
|
||||
label: '返回键',
|
||||
icon: 'Back',
|
||||
elIcon: 'Back',
|
||||
command: 'input keyevent KEYCODE_BACK',
|
||||
},
|
||||
{
|
||||
label: '菜单键',
|
||||
icon: 'Menu',
|
||||
elIcon: 'Menu',
|
||||
command: 'input keyevent KEYCODE_MENU',
|
||||
tips: '不要和切换键搞错啦',
|
||||
},
|
||||
{
|
||||
label: '电源键',
|
||||
icon: 'SwitchButton',
|
||||
elIcon: 'SwitchButton',
|
||||
command: 'input keyevent KEYCODE_POWER',
|
||||
tips: '可以用来开启或关闭屏幕',
|
||||
},
|
||||
{
|
||||
label: '截取屏幕',
|
||||
icon: 'Crop',
|
||||
elIcon: 'Crop',
|
||||
handle: this.handleScreenCap,
|
||||
tips: '',
|
||||
},
|
||||
{
|
||||
label: '安装应用',
|
||||
svgIcon: 'install',
|
||||
handle: this.handleInstall,
|
||||
tips: '',
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
@ -72,6 +83,54 @@ export default {
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async handleInstall(device) {
|
||||
const files = await this.$electron.ipcRenderer.invoke(
|
||||
'show-open-dialog',
|
||||
{
|
||||
properties: ['openFile', 'multiSelections'],
|
||||
filters: [{ name: '请选择要安装的应用', extensions: ['apk'] }],
|
||||
},
|
||||
)
|
||||
|
||||
if (!files) {
|
||||
return false
|
||||
}
|
||||
|
||||
const messageEl = this.$message({
|
||||
message: ` 正在为 ${device.name} 安装应用中...`,
|
||||
icon: LoadingIcon,
|
||||
duration: 0,
|
||||
})
|
||||
|
||||
let failCount = 0
|
||||
|
||||
for (let index = 0; index < files.length; index++) {
|
||||
const item = files[index]
|
||||
await this.$adb.install(device.id, item).catch((e) => {
|
||||
console.warn(e)
|
||||
++failCount
|
||||
})
|
||||
}
|
||||
|
||||
messageEl.close()
|
||||
|
||||
const totalCount = files.length
|
||||
const successCount = totalCount - failCount
|
||||
|
||||
if (successCount) {
|
||||
if (totalCount > 1) {
|
||||
this.$message.success(
|
||||
`已成功将应用安装到 ${device.name} 中,共 ${totalCount}个,成功 ${successCount}个,失败 ${failCount}个`,
|
||||
)
|
||||
}
|
||||
else {
|
||||
this.$message.success(`已成功将应用安装到 ${device.name} 中`)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
this.$message.warning('安装应用失败,请检查安装包后重试')
|
||||
},
|
||||
handleClick(row) {
|
||||
if (row.command) {
|
||||
this.$adb.deviceShell(this.device.id, row.command)
|
||||
@ -84,16 +143,19 @@ export default {
|
||||
}
|
||||
},
|
||||
async handleScreenCap(device) {
|
||||
const deviceName = device.name || device.id
|
||||
|
||||
const messageEl = this.$message({
|
||||
message: ` 正在截取 ${deviceName} 的屏幕快照...`,
|
||||
message: ` 正在截取 ${device.name} 的屏幕快照...`,
|
||||
icon: LoadingIcon,
|
||||
duration: 0,
|
||||
})
|
||||
|
||||
const fileName = `${deviceName}-screencap-${dayjs().format('YYYY-MM-DD-HH-mm-ss')}.png`
|
||||
const savePath = this.$path.resolve(this.scrcpyConfig['--record'], fileName)
|
||||
const fileName = `${device.name}-screencap-${dayjs().format(
|
||||
'YYYY-MM-DD-HH-mm-ss',
|
||||
)}.png`
|
||||
const savePath = this.$path.resolve(
|
||||
this.scrcpyConfig['--record'],
|
||||
fileName,
|
||||
)
|
||||
|
||||
try {
|
||||
await this.$adb.screencap(device.id, { savePath })
|
||||
|
@ -1,7 +1,12 @@
|
||||
<template>
|
||||
<div class="h-full flex flex-col">
|
||||
<div class="flex items-center flex-none space-x-2">
|
||||
<el-input v-model="formData.host" placeholder="192.168.0.1" class="!w-86 flex-none" clearable>
|
||||
<el-input
|
||||
v-model="formData.host"
|
||||
placeholder="192.168.0.1"
|
||||
class="!w-86 flex-none"
|
||||
clearable
|
||||
>
|
||||
<template #prepend>
|
||||
无线连接
|
||||
</template>
|
||||
@ -53,8 +58,18 @@
|
||||
<template #empty>
|
||||
<el-empty description="设备列表为空" />
|
||||
</template>
|
||||
<el-table-column prop="id" label="设备 ID" show-overflow-tooltip align="left" />
|
||||
<el-table-column prop="name" label="设备名称" show-overflow-tooltip align="left">
|
||||
<el-table-column
|
||||
prop="id"
|
||||
label="设备 ID"
|
||||
show-overflow-tooltip
|
||||
align="left"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="name"
|
||||
label="设备名称"
|
||||
show-overflow-tooltip
|
||||
align="left"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<div class="flex items-center">
|
||||
<el-tooltip
|
||||
@ -85,7 +100,7 @@
|
||||
:icon="row.$loading ? '' : 'Monitor'"
|
||||
@click="handleMirror(row)"
|
||||
>
|
||||
{{ row.$loading ? '正在镜像' : '开始镜像' }}
|
||||
{{ row.$loading ? "正在镜像" : "开始镜像" }}
|
||||
</el-button>
|
||||
|
||||
<el-button
|
||||
@ -96,17 +111,21 @@
|
||||
:icon="row.$recordLoading ? '' : 'VideoCamera'"
|
||||
@click="handleRecord(row)"
|
||||
>
|
||||
{{ row.$recordLoading ? '正在录制' : '开始录制' }}
|
||||
{{ row.$recordLoading ? "正在录制" : "开始录制" }}
|
||||
</el-button>
|
||||
|
||||
<el-button
|
||||
v-if="!row.$wireless"
|
||||
type="primary"
|
||||
text
|
||||
:disabled="row.$unauthorized || row.$loading || row.$recordLoading"
|
||||
:icon="row.$recordLoading ? '' : 'Switch'"
|
||||
:disabled="
|
||||
row.$unauthorized || row.$loading || row.$recordLoading
|
||||
"
|
||||
@click="handleWifi(row)"
|
||||
>
|
||||
<template #icon>
|
||||
<svg-icon name="wifi"></svg-icon>
|
||||
</template>
|
||||
无线模式
|
||||
</el-button>
|
||||
|
||||
@ -119,7 +138,7 @@
|
||||
:icon="row.$stopLoading ? '' : 'CircleClose'"
|
||||
@click="handleStop(row)"
|
||||
>
|
||||
{{ row.$stopLoading ? '正在断开' : '断开连接' }}
|
||||
{{ row.$stopLoading ? "正在断开" : "断开连接" }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@ -189,6 +208,7 @@ export default {
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
onStdout() {},
|
||||
toggleRowExpansion(...params) {
|
||||
this.$refs.elTable.toggleRowExpansion(...params)
|
||||
},
|
||||
@ -213,7 +233,7 @@ export default {
|
||||
|
||||
console.log('handleRecord.command', command)
|
||||
|
||||
await this.$scrcpy.shell(command)
|
||||
await this.$scrcpy.shell(command, { stdout: this.onStdout })
|
||||
|
||||
await this.$confirm('是否前往录制位置进行查看?', '录制成功', {
|
||||
confirmButtonText: '确定',
|
||||
@ -239,6 +259,7 @@ export default {
|
||||
try {
|
||||
await this.$scrcpy.shell(
|
||||
`--serial=${row.id} --window-title=${row.name}-${row.id} ${this.stringScrcpyConfig}`,
|
||||
{ stdout: this.onStdout },
|
||||
)
|
||||
}
|
||||
catch (error) {
|
||||
|
75
src/icons/components/SvgIcon.vue
Normal file
75
src/icons/components/SvgIcon.vue
Normal file
@ -0,0 +1,75 @@
|
||||
<script lang="jsx">
|
||||
export default {
|
||||
name: 'SvgIcon',
|
||||
inheritAttrs: false,
|
||||
props: {
|
||||
name: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
SvgComponent: null,
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getSvgComponent()
|
||||
},
|
||||
methods: {
|
||||
async getSvgComponent() {
|
||||
if (!this.name) {
|
||||
return
|
||||
}
|
||||
|
||||
const module = await import(`../svg/${this.name}.svg?component`)
|
||||
this.SvgComponent = module.default.render()
|
||||
// console.log('this.SvgComponent', this.SvgComponent)
|
||||
},
|
||||
},
|
||||
render() {
|
||||
console.log('this', this)
|
||||
if (this.SvgComponent) {
|
||||
const props = this.SvgComponent.props
|
||||
return {
|
||||
...this.SvgComponent,
|
||||
props: {
|
||||
...props,
|
||||
...this.$attrs,
|
||||
class: ['svg-icon', props.class || '', this.$attrs.class || ''].join(
|
||||
' ',
|
||||
),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.name && this.$slots.default) {
|
||||
const SlotComponent = this.$slots.default()[0]
|
||||
const props = SlotComponent.props || {}
|
||||
return {
|
||||
...SlotComponent,
|
||||
props: {
|
||||
...props,
|
||||
...this.$attrs,
|
||||
class: ['svg-icon', props.class || '', this.$attrs.class || ''].join(
|
||||
' ',
|
||||
),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return ''
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.svg-icon {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
display: inline-block;
|
||||
vertical-align: -0.1em;
|
||||
fill: currentColor;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
7
src/icons/index.js
Normal file
7
src/icons/index.js
Normal file
@ -0,0 +1,7 @@
|
||||
import SvgIcon from './components/SvgIcon.vue'
|
||||
|
||||
export default {
|
||||
install(app) {
|
||||
app.component('SvgIcon', SvgIcon)
|
||||
},
|
||||
}
|
1
src/icons/svg/install.svg
Normal file
1
src/icons/svg/install.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1697530402297" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1513" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M56.888889 284.444444h853.333333v682.666667H56.888889V284.444444z m56.888889 56.888889v568.888889h739.555555V341.333333H113.777778zM199.111111 170.666667L125.155556 284.444444H56.888889l113.777778-170.666666h625.777777l113.777778 170.666666h-68.266666l-73.955556-113.777777h-568.888889zM125.155556 284.444444H56.888889l113.777778-170.666666h625.777777l113.777778 170.666666h-68.266666l-73.955556-113.777777h-568.888889L125.155556 284.444444z" p-id="1514"/><path d="M227.555556 603.022222l39.822222-34.133333 221.866666 193.422222 216.177778-193.422222 39.822222 34.133333-256 227.555556z" p-id="1515"/><path d="M455.111111 398.222222h56.888889v369.777778H455.111111z" p-id="1516"/></svg>
|
After Width: | Height: | Size: 1020 B |
1
src/icons/svg/wifi.svg
Normal file
1
src/icons/svg/wifi.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1697531019281" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5297" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M723 620.5C666.8 571.6 593.4 542 513 542s-153.8 29.6-210.1 78.6c-3.2 2.8-3.6 7.8-0.8 11.2l36 42.9c2.9 3.4 8 3.8 11.4 0.9C393.1 637.2 450.3 614 513 614s119.9 23.2 163.5 61.5c3.4 2.9 8.5 2.5 11.4-0.9l36-42.9c2.8-3.3 2.4-8.3-0.9-11.2zM840.4 480.4C751.7 406.5 637.6 362 513 362s-238.7 44.5-327.5 118.4c-3.4 2.8-3.8 7.9-1 11.3l36 42.9c2.8 3.4 7.9 3.8 11.2 1C308 472.2 406.1 434 513 434s205 38.2 281.2 101.6c3.4 2.8 8.4 2.4 11.2-1l36-42.9c2.8-3.4 2.4-8.5-1-11.3z" p-id="5298"/><path d="M957.1 341.4C835.7 241.8 680.3 182 511 182c-168.2 0-322.6 59-443.7 157.4-3.5 2.8-4 7.9-1.1 11.4l36 42.9c2.8 3.3 7.8 3.8 11.1 1.1C222 306.7 360.3 254 511 254c151.8 0 291 53.5 400 142.7 3.4 2.8 8.4 2.3 11.2-1.1l36-42.9c2.9-3.4 2.4-8.5-1.1-11.3z" p-id="5299"/><path d="M512 778m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0Z" p-id="5300"/></svg>
|
After Width: | Height: | Size: 1.1 KiB |
10
src/icons/svgo.config.js
Normal file
10
src/icons/svgo.config.js
Normal file
@ -0,0 +1,10 @@
|
||||
module.exports = {
|
||||
plugins: [
|
||||
{
|
||||
name: 'removeAttrs',
|
||||
params: {
|
||||
attrs: '(fill|fill-rule)',
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
@ -4,6 +4,7 @@ import App from './App.vue'
|
||||
import store from './store/index.js'
|
||||
|
||||
import plugins from './plugins/index.js'
|
||||
import icons from './icons/index.js'
|
||||
|
||||
import 'virtual:uno.css'
|
||||
import './styles/index.js'
|
||||
@ -13,6 +14,7 @@ const app = createApp(App)
|
||||
app.use(store)
|
||||
|
||||
app.use(plugins)
|
||||
app.use(icons)
|
||||
|
||||
app.config.globalProperties.$electron = window.electron
|
||||
app.config.globalProperties.$adb = window.adbkit
|
||||
|
@ -6,6 +6,7 @@ import useRenderer from 'vite-plugin-electron-renderer'
|
||||
import useVue from '@vitejs/plugin-vue'
|
||||
import useEslint from 'vite-plugin-eslint'
|
||||
import useUnoCSS from 'unocss/vite'
|
||||
import useSvg from 'vite-svg-loader'
|
||||
|
||||
const merge = config =>
|
||||
mergeConfig(
|
||||
@ -32,6 +33,7 @@ export default merge(
|
||||
plugins: [
|
||||
useEslint(),
|
||||
useUnoCSS(),
|
||||
useSvg(),
|
||||
useVue(),
|
||||
useElectron([
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user