mirror of
https://github.com/viarotel-org/escrcpy.git
synced 2024-11-23 23:21:02 +01:00
perf: 🍻 Update base copilot
This commit is contained in:
parent
3dab0cc833
commit
5ac5ee6e97
63
copilot/App.vue
Normal file
63
copilot/App.vue
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
<template>
|
||||||
|
<div class="flex flex-col absolute inset-fix-0 h-full overflow-hidden">
|
||||||
|
<div class="py-4 px-4 flex items-center flex-none">
|
||||||
|
<a class="block" :href="escrcpyURL" target="_blank">
|
||||||
|
<img src="@electron/resources/build/logo.png" class="h-9" alt="" />
|
||||||
|
</a>
|
||||||
|
<div class="pl-2 text-sm">
|
||||||
|
Escrcpy Copilot
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex-1 h-0 overflow-hidden bg-gray-100">
|
||||||
|
<el-tabs v-model="tabValue" class="el-tabs-flex" @tab-click="onTabClick">
|
||||||
|
<el-tab-pane
|
||||||
|
v-for="(item, index) of tabModel"
|
||||||
|
:key="index"
|
||||||
|
:label="item.label"
|
||||||
|
:name="item.value"
|
||||||
|
lazy
|
||||||
|
class=""
|
||||||
|
>
|
||||||
|
<component :is="item.value" />
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Transmission from './components/Transmission/index.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
Transmission,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
escrcpyURL: 'https://github.com/viarotel-org/escrcpy',
|
||||||
|
tabValue: 'Transmission',
|
||||||
|
tabModel: [
|
||||||
|
{
|
||||||
|
label: '传输助手',
|
||||||
|
value: 'Transmission',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onTabClick() {},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="postcss" scoped>
|
||||||
|
:deep() {
|
||||||
|
.el-tabs__header {
|
||||||
|
@apply bg-white px-4;
|
||||||
|
}
|
||||||
|
.el-tabs__nav-wrap::after {
|
||||||
|
@apply bg-transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
55
copilot/components/Transmission/Message/Preset.vue
Normal file
55
copilot/components/Transmission/Message/Preset.vue
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
<template>
|
||||||
|
<Message v-bind="messageProps">
|
||||||
|
<slot></slot>
|
||||||
|
</Message>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Message from './index.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
Message,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
content: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
messageProps() {
|
||||||
|
let value = {}
|
||||||
|
switch (this.type) {
|
||||||
|
case 'server':
|
||||||
|
value = {
|
||||||
|
name: 'PC',
|
||||||
|
content: this.content,
|
||||||
|
avatar: 'computer',
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'client':
|
||||||
|
value = {
|
||||||
|
name: this.$attrs.name || '我的手机',
|
||||||
|
content: this.content,
|
||||||
|
avatar: 'mobile',
|
||||||
|
reversed: true,
|
||||||
|
}
|
||||||
|
break
|
||||||
|
|
||||||
|
default:
|
||||||
|
value = this.$attrs
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return value
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style></style>
|
81
copilot/components/Transmission/Message/index.vue
Normal file
81
copilot/components/Transmission/Message/index.vue
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
<template>
|
||||||
|
<div :class="reversed ? 'flex-row-reverse' : ''" class="flex items-start">
|
||||||
|
<img :src="avatarURL" alt="" class="w-12 h-12 flex-none" />
|
||||||
|
<div
|
||||||
|
class="flex flex-col"
|
||||||
|
:class="reversed ? 'mr-4 pl-16 items-end' : 'ml-4 pr-16'"
|
||||||
|
>
|
||||||
|
<div v-if="!reversed" class="mt-1 text-base">
|
||||||
|
{{ name }}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="mt-2 shadow-el-light px-4 py-2 rounded-lg break-all overflow-hidden relative"
|
||||||
|
>
|
||||||
|
<slot>
|
||||||
|
<span class="pr-1">
|
||||||
|
{{ content }}
|
||||||
|
</span>
|
||||||
|
<el-icon v-if="loading" class="is-loading relative top-[2px]">
|
||||||
|
<Loading />
|
||||||
|
</el-icon>
|
||||||
|
</slot>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import logoURL from '@electron/resources/build/logo.png'
|
||||||
|
import userURL from '@/assets/user.png'
|
||||||
|
import mobileURL from '@/assets/mobile.png'
|
||||||
|
import computerURL from '@/assets/computer.png'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
reversed: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
avatar: {
|
||||||
|
type: String,
|
||||||
|
default: 'logo',
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
content: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
loading: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
avatarURL() {
|
||||||
|
let value = ''
|
||||||
|
|
||||||
|
switch (this.avatar) {
|
||||||
|
case 'logo':
|
||||||
|
value = logoURL
|
||||||
|
break
|
||||||
|
case 'user':
|
||||||
|
value = userURL
|
||||||
|
break
|
||||||
|
case 'mobile':
|
||||||
|
value = mobileURL
|
||||||
|
break
|
||||||
|
case 'computer':
|
||||||
|
value = computerURL
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return value
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style></style>
|
177
copilot/components/Transmission/index.vue
Normal file
177
copilot/components/Transmission/index.vue
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
<template>
|
||||||
|
<div class="h-full flex flex-col">
|
||||||
|
<div
|
||||||
|
ref="chats"
|
||||||
|
class="flex-1 h-0 space-y-4 pb-4 px-4 overflow-auto scroll-smooth"
|
||||||
|
>
|
||||||
|
<Message
|
||||||
|
v-for="(item, index) of messageList"
|
||||||
|
v-bind="{
|
||||||
|
type: item.type,
|
||||||
|
content: item.content,
|
||||||
|
}"
|
||||||
|
:key="index"
|
||||||
|
:loading="item.$loading"
|
||||||
|
>
|
||||||
|
</Message>
|
||||||
|
</div>
|
||||||
|
<div class="flex-none px-4 py-2 bg-white">
|
||||||
|
<el-input
|
||||||
|
v-model="inputValue"
|
||||||
|
placeholder="请输入想要发送的消息"
|
||||||
|
@keyup.enter="handleSubmit"
|
||||||
|
>
|
||||||
|
<template #append>
|
||||||
|
<el-button
|
||||||
|
icon="Promotion"
|
||||||
|
:loading="loading"
|
||||||
|
@click="handleSubmit"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Message from './Message/Preset.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
Message,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
messageList: [],
|
||||||
|
inputValue: '',
|
||||||
|
loading: false,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async created() {
|
||||||
|
await this.getMessageData()
|
||||||
|
await this.$nextTick()
|
||||||
|
this.handleScroll()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleScroll() {
|
||||||
|
const chatsEl = this.$refs.chats
|
||||||
|
chatsEl.scrollTop = chatsEl.scrollHeight
|
||||||
|
},
|
||||||
|
async handleSubmit() {
|
||||||
|
if (!this.inputValue) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
this.loading = true
|
||||||
|
|
||||||
|
const newMessage = {
|
||||||
|
type: 'client',
|
||||||
|
content: this.inputValue,
|
||||||
|
$loading: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
this.messageList.push(newMessage)
|
||||||
|
|
||||||
|
const params = {}
|
||||||
|
const res = await this.$mockAPI(params)
|
||||||
|
|
||||||
|
this.loading = false
|
||||||
|
|
||||||
|
if (res.success) {
|
||||||
|
this.inputValue = ''
|
||||||
|
newMessage.$loading = false
|
||||||
|
await this.$nextTick()
|
||||||
|
this.handleScroll()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async getMessageData() {
|
||||||
|
const params = {
|
||||||
|
imitate: [
|
||||||
|
{
|
||||||
|
type: 'server',
|
||||||
|
content: '你好啊',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'client',
|
||||||
|
content: '你也好啊',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'server',
|
||||||
|
content: '你好啊',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'client',
|
||||||
|
content: '你也好啊',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'server',
|
||||||
|
content: '你好啊',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'client',
|
||||||
|
content: '你也好啊',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'server',
|
||||||
|
content: '你好啊',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'client',
|
||||||
|
content: '你也好啊',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'server',
|
||||||
|
content: '你好啊',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'client',
|
||||||
|
content: '你也好啊',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'server',
|
||||||
|
content: '你好啊',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'client',
|
||||||
|
content: '你也好啊',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'server',
|
||||||
|
content: '你好啊',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'client',
|
||||||
|
content: '你也好啊',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'server',
|
||||||
|
content: '你好啊',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'client',
|
||||||
|
content: '你也好啊',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'server',
|
||||||
|
content: '你好啊',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'client',
|
||||||
|
content: '你也好啊',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
const res = await this.$mockAPI(params)
|
||||||
|
|
||||||
|
if (res.success) {
|
||||||
|
this.messageList = res.data.map(item => ({
|
||||||
|
...item,
|
||||||
|
$loading: false,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style></style>
|
@ -1,10 +1,10 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en" class="dark">
|
<html lang="en" class="">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" href="/logo.ico" />
|
<link rel="icon" href="/logo.ico" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Escrcpy-Server</title>
|
<title>Escrcpy Copilot</title>
|
||||||
</head>
|
</head>
|
||||||
<body class="">
|
<body class="">
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
37
copilot/main.js
Normal file
37
copilot/main.js
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import { createApp, toRaw } from 'vue'
|
||||||
|
import App from './App.vue'
|
||||||
|
import { i18n, t } from '@/locales/index.js'
|
||||||
|
import plugins from '@/plugins/index.js'
|
||||||
|
import icons from '@/icons/index.js'
|
||||||
|
|
||||||
|
import { replaceIP, restoreIP } from '@/utils/index.js'
|
||||||
|
|
||||||
|
import 'virtual:uno.css'
|
||||||
|
import '@/styles/index.js'
|
||||||
|
|
||||||
|
const app = createApp(App)
|
||||||
|
|
||||||
|
app.use(plugins)
|
||||||
|
|
||||||
|
app.use(icons)
|
||||||
|
|
||||||
|
app.use(i18n)
|
||||||
|
window.t = t
|
||||||
|
|
||||||
|
app.config.globalProperties.$replaceIP = replaceIP
|
||||||
|
app.config.globalProperties.$restoreIP = restoreIP
|
||||||
|
|
||||||
|
app.config.globalProperties.$toRaw = toRaw
|
||||||
|
|
||||||
|
app.config.globalProperties.$mockAPI = ({ imitate = {}, delay = 500 } = {}) =>
|
||||||
|
new Promise((resolve) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
resolve({
|
||||||
|
code: '0000',
|
||||||
|
data: imitate,
|
||||||
|
success: true,
|
||||||
|
})
|
||||||
|
}, delay)
|
||||||
|
})
|
||||||
|
|
||||||
|
app.mount('#app')
|
@ -7,14 +7,14 @@ export default async (mainWindow) => {
|
|||||||
const app = new Hono()
|
const app = new Hono()
|
||||||
|
|
||||||
app.notFound((c) => {
|
app.notFound((c) => {
|
||||||
return c.text('Escrcpy server 404', 404)
|
return c.text('Escrcpy copilot 404', 404)
|
||||||
})
|
})
|
||||||
|
|
||||||
const VITE_DEV_SERVER_URL = process.env.VITE_DEV_SERVER_URL
|
const VITE_DEV_SERVER_URL = process.env.VITE_DEV_SERVER_URL
|
||||||
|
|
||||||
if (VITE_DEV_SERVER_URL) {
|
if (VITE_DEV_SERVER_URL) {
|
||||||
app.get('/', ctx =>
|
app.get('/', ctx =>
|
||||||
ctx.redirect(`${VITE_DEV_SERVER_URL}server/index.html`),
|
ctx.redirect(`${VITE_DEV_SERVER_URL}copilot/index.html`),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -23,7 +23,7 @@ export default async (mainWindow) => {
|
|||||||
serveStatic({
|
serveStatic({
|
||||||
root: relative('./', process.env.DIST),
|
root: relative('./', process.env.DIST),
|
||||||
rewriteRequestPath: (path) => {
|
rewriteRequestPath: (path) => {
|
||||||
return path.replace(/^\//, '/server')
|
return path.replace(/^\//, '/copilot')
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
)
|
)
|
@ -14,7 +14,7 @@ import { icnsLogoPath, icoLogoPath, logoPath } from './configs/index.js'
|
|||||||
|
|
||||||
import events from './events/index.js'
|
import events from './events/index.js'
|
||||||
|
|
||||||
import server from './server/index.js'
|
import copilot from './copilot/index.js'
|
||||||
|
|
||||||
log.initialize({ preload: true })
|
log.initialize({ preload: true })
|
||||||
|
|
||||||
@ -104,7 +104,7 @@ function createWindow() {
|
|||||||
|
|
||||||
events(mainWindow)
|
events(mainWindow)
|
||||||
|
|
||||||
server(mainWindow)
|
copilot(mainWindow)
|
||||||
}
|
}
|
||||||
|
|
||||||
app.whenReady().then(() => {
|
app.whenReady().then(() => {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en" class="dark">
|
<html lang="en" class="">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" href="/logo.ico" />
|
<link rel="icon" href="/logo.ico" />
|
||||||
|
@ -3,11 +3,12 @@
|
|||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": ["src/*"],
|
"@/*": ["src/*"],
|
||||||
|
"@copilot/*": ["copilot/*"],
|
||||||
"@root/*": ["*"],
|
"@root/*": ["*"],
|
||||||
"@electron/*": ["electron/*"],
|
"@electron/*": ["electron/*"],
|
||||||
"@renderer/*": ["src/*"]
|
"@renderer/*": ["src/*"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"exclude": ["node_modules", "dist", "dist-electron", "dist-release"],
|
"exclude": ["node_modules", "dist", "dist-electron", "dist-release"],
|
||||||
"include": ["src/**/*.js", "src/**/*.jsx", "src/**/*.vue", "electron"]
|
"include": ["src", "electron", "copilot"]
|
||||||
}
|
}
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
import { createApp } from 'vue'
|
|
||||||
|
|
||||||
console.log('createApp', createApp)
|
|
BIN
src/assets/computer.png
Normal file
BIN
src/assets/computer.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.5 KiB |
BIN
src/assets/mobile.png
Normal file
BIN
src/assets/mobile.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.7 KiB |
BIN
src/assets/user.png
Normal file
BIN
src/assets/user.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 26 KiB |
@ -2,7 +2,7 @@ import { createI18n } from 'vue-i18n'
|
|||||||
import messages from '@intlify/unplugin-vue-i18n/messages'
|
import messages from '@intlify/unplugin-vue-i18n/messages'
|
||||||
|
|
||||||
const locale
|
const locale
|
||||||
= window.appStore.get('common.language')
|
= window.appStore?.get('common.language')
|
||||||
|| window.electron?.process?.env?.LOCALE
|
|| window.electron?.process?.env?.LOCALE
|
||||||
|
|
||||||
// const locale = 'en_US'
|
// const locale = 'en_US'
|
||||||
|
@ -3,12 +3,14 @@ html {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* 自定义滚动条的外观 */
|
/* 自定义滚动条的外观 */
|
||||||
|
|
||||||
|
@screen sm {
|
||||||
::-webkit-scrollbar {
|
::-webkit-scrollbar {
|
||||||
width: 8px;
|
width: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
::-webkit-scrollbar-track {
|
::-webkit-scrollbar-track {
|
||||||
background-color: theme("colors.gray.100");
|
background-color: theme('colors.gray.100');
|
||||||
@apply bg-gray-100 dark:bg-gray-800;
|
@apply bg-gray-100 dark:bg-gray-800;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -20,3 +22,4 @@ html {
|
|||||||
::-webkit-scrollbar-thumb:hover {
|
::-webkit-scrollbar-thumb:hover {
|
||||||
@apply bg-gray-500 dark:bg-gray-300;
|
@apply bg-gray-500 dark:bg-gray-300;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
@ -35,13 +35,14 @@ export default params =>
|
|||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
input: {
|
input: {
|
||||||
main: resolve(__dirname, 'index.html'),
|
main: resolve(__dirname, 'index.html'),
|
||||||
server: resolve(__dirname, 'server/index.html'),
|
copilot: resolve(__dirname, 'copilot/index.html'),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
'@': resolve('src'),
|
'@': resolve('src'),
|
||||||
|
'@copilot': resolve('copilot'),
|
||||||
'@electron': resolve('electron'),
|
'@electron': resolve('electron'),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user