新增数据同步服务端模式已认证设备列表管理
This commit is contained in:
@@ -1,130 +0,0 @@
|
||||
<template lang="pug">
|
||||
dt#sync
|
||||
| {{ $t('setting__sync') }}
|
||||
button(class="help-btn" :aria-label="$t('setting__sync_tip')" @click="openUrl('https://lyswhut.github.io/lx-music-doc/desktop/faq/sync')")
|
||||
svg-icon(name="help-circle-outline")
|
||||
dd
|
||||
base-checkbox(id="setting_sync_enable" :model-value="appSetting['sync.enable']" :label="$t('setting__sync_enable')" @update:model-value="updateSetting({ 'sync.enable': $event })")
|
||||
|
||||
dd
|
||||
h3#sync_mode {{ $t('setting__sync_mode') }}
|
||||
div
|
||||
base-checkbox.gap-left(id="setting_sync_mode_server" :disabled="sync.enable" :model-value="appSetting['sync.mode']" need value="server" :label="$t('setting__sync_mode_server')" @update:model-value="updateSetting({ 'sync.mode': $event })")
|
||||
base-checkbox.gap-left(id="setting_sync_mode_client" :disabled="sync.enable" :model-value="appSetting['sync.mode']" need value="client" :label="$t('setting__sync_mode_client')" @update:model-value="updateSetting({ 'sync.mode': $event })")
|
||||
|
||||
|
||||
dd(v-if="sync.mode == 'client'")
|
||||
h3 {{ $t('setting__sync_client_mode') }}
|
||||
div
|
||||
.p.small {{ $t('setting__sync_client_status', { status: clientStatus }) }}
|
||||
.p.small {{ $t('setting__sync_client_address', { address: sync.client.status.address.join(', ') || '' }) }}
|
||||
.p
|
||||
.p.small {{ $t('setting__sync_client_host') }}
|
||||
div
|
||||
base-input.gap-left(:class="$style.hostInput" :model-value="appSetting['sync.client.host']" :disabled="sync.enable" :placeholder="$t('setting__sync_client_host_tip')" @update:model-value="setSyncClientHost")
|
||||
dd(v-else)
|
||||
h3 {{ syncEnableServerTitle }}
|
||||
div
|
||||
.p.small {{ $t('setting__sync_server_auth_code', { code: sync.server.status.code || '' }) }}
|
||||
.p.small {{ $t('setting__sync_server_address', { address: sync.server.status.address.join(', ') || '' }) }}
|
||||
.p.small {{ $t('setting__sync_server_device', { devices: syncDevices }) }}
|
||||
.p
|
||||
base-btn.btn(min :disabled="!sync.server.status.status" @click="refreshSyncCode") {{ $t('setting__sync_server_refresh_code') }}
|
||||
.p
|
||||
.p.small {{ $t('setting__sync_server_port') }}
|
||||
div
|
||||
base-input.gap-left(:class="$style.portInput" :model-value="appSetting['sync.server.port']" :disabled="sync.enable" type="number" :placeholder="$t('setting__sync_server_port_tip')" @update:model-value="setSyncServerPort")
|
||||
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { computed } from '@common/utils/vueTools'
|
||||
import { sync } from '@renderer/store'
|
||||
import { sendSyncAction } from '@renderer/utils/ipc'
|
||||
import { openUrl } from '@common/utils/electron'
|
||||
import { useI18n } from '@renderer/plugins/i18n'
|
||||
import { appSetting, updateSetting } from '@renderer/store/setting'
|
||||
import { debounce } from '@common/utils/common'
|
||||
import { SYNC_CODE } from '@common/constants_sync'
|
||||
|
||||
export default {
|
||||
name: 'SettingSync',
|
||||
setup() {
|
||||
const t = useI18n()
|
||||
|
||||
|
||||
const syncEnableServerTitle = computed(() => {
|
||||
let title = t('setting__sync_server_mode')
|
||||
if (sync.server.status.message) {
|
||||
title += ` [${sync.server.status.message}]`
|
||||
}
|
||||
// else if (this.sync.server.status.address.length) {
|
||||
// // title += ` [${this.sync.server.status.address.join(', ')}]`
|
||||
// }
|
||||
return title
|
||||
})
|
||||
|
||||
const clientStatus = computed(() => {
|
||||
let status
|
||||
switch (sync.client.status.message) {
|
||||
case SYNC_CODE.msgBlockedIp:
|
||||
status = t('setting__sync_code_blocked_ip')
|
||||
break
|
||||
case SYNC_CODE.authFailed:
|
||||
status = t('setting__sync_code_fail')
|
||||
break
|
||||
default:
|
||||
status = sync.client.status.message
|
||||
? sync.client.status.message
|
||||
: sync.client.status.status
|
||||
? t('setting_sync_status_enabled')
|
||||
: t('sync_status_disabled')
|
||||
break
|
||||
}
|
||||
return status
|
||||
})
|
||||
const syncDevices = computed(() => {
|
||||
return sync.server.status.devices.length
|
||||
? sync.server.status.devices.map(d => `${d.deviceName} (${d.clientId.substring(0, 5)})`).join(', ')
|
||||
: ''
|
||||
})
|
||||
|
||||
const refreshSyncCode = () => {
|
||||
void sendSyncAction({ action: 'generate_code' })
|
||||
}
|
||||
|
||||
const setSyncServerPort = debounce(port => {
|
||||
updateSetting({ 'sync.server.port': port.trim() })
|
||||
}, 500)
|
||||
|
||||
const setSyncClientHost = debounce(host => {
|
||||
updateSetting({ 'sync.client.host': host.trim() })
|
||||
}, 500)
|
||||
|
||||
|
||||
return {
|
||||
appSetting,
|
||||
updateSetting,
|
||||
sync,
|
||||
syncEnableServerTitle,
|
||||
setSyncServerPort,
|
||||
setSyncClientHost,
|
||||
syncDevices,
|
||||
refreshSyncCode,
|
||||
clientStatus,
|
||||
openUrl,
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" module>
|
||||
.portInput[disabled], .hostInput[disabled] {
|
||||
opacity: .8 !important;
|
||||
}
|
||||
|
||||
.hostInput {
|
||||
min-width: 380px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,163 @@
|
||||
<template lang="pug">
|
||||
material-modal(:show="modelValue" bg-close teleport="#view" @close="$emit('update:modelValue', false)")
|
||||
main(:class="$style.main")
|
||||
h2 {{ $t('setting__sync_server_device_list_title') }}
|
||||
ul.scroll(v-if="historyDeviceList.length" :class="$style.content")
|
||||
li(v-for="(device, index) in historyDeviceList" :key="device.id" :class="$style.listItem")
|
||||
div(:class="$style.listLeft")
|
||||
span(:class="$style.name")
|
||||
svg-icon(v-if="device.isMobile" name="phone" style="margin-right: 0.2rem; vertical-align: -0.2em;")
|
||||
| {{ device.name }}
|
||||
span(:class="$style.desc") {{ $t('setting__sync_server_device_list_time', { time: device.lastConnectDate }) }}
|
||||
base-btn(:class="$style.listBtn" outline :aria-label="$t('setting__sync_server_device_list_btn_remove')" @click.stop="handleRemove(index)")
|
||||
svg(v-once version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" viewBox="0 0 212.982 212.982" space="preserve")
|
||||
use(xlink:href="#icon-delete")
|
||||
div(v-else :class="$style.content")
|
||||
div(:class="$style.noitem") {{ $t('setting__sync_server_device_list_noitem') }}
|
||||
div(:class="$style.footer")
|
||||
div(:class="$style.tips") {{ $t('setting__sync_server_device_list_tips') }}
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { watch, ref } from '@common/utils/vueTools'
|
||||
import { sync } from '@renderer/store'
|
||||
import { getSyncServerDevices, removeSyncServerDevice } from '@renderer/utils/ipc'
|
||||
import { dateFormat } from '@common/utils/common'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
modelValue: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
emits: ['update:modelValue'],
|
||||
setup(props) {
|
||||
const historyDeviceList = ref([])
|
||||
|
||||
const getList = () => {
|
||||
void getSyncServerDevices().then((list) => {
|
||||
historyDeviceList.value = list.map(d => {
|
||||
return {
|
||||
id: d.clientId,
|
||||
name: d.deviceName,
|
||||
lastConnectDate: d.lastConnectDate ? dateFormat(d.lastConnectDate) : '-',
|
||||
isMobile: d.isMobile,
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
watch(() => sync.server.status.devices.length, () => {
|
||||
if (!props.modelValue) return
|
||||
getList()
|
||||
})
|
||||
watch(() => props.modelValue, (val) => {
|
||||
if (!val) return
|
||||
getList()
|
||||
})
|
||||
|
||||
const handleRemove = (index) => {
|
||||
void removeSyncServerDevice(historyDeviceList.value[index].id).then(getList)
|
||||
}
|
||||
|
||||
return {
|
||||
historyDeviceList,
|
||||
handleRemove,
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" module>
|
||||
@import '@renderer/assets/styles/layout.less';
|
||||
|
||||
.main {
|
||||
// padding: 15px;
|
||||
// max-width: 400px;
|
||||
min-width: 460px;
|
||||
min-height: 200px;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
justify-content: center;
|
||||
// min-height: 0;
|
||||
// max-height: 100%;
|
||||
// overflow: hidden;
|
||||
h2 {
|
||||
margin: 15px;
|
||||
font-size: 16px;
|
||||
color: var(--color-font);
|
||||
line-height: 1.3;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.name {
|
||||
color: var(--color-font);
|
||||
font-size: 14px;
|
||||
word-break: break-all;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.desc {
|
||||
color: var(--color-font-label);
|
||||
margin-top: 8px;
|
||||
font-size: 12px;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.content {
|
||||
flex: auto;
|
||||
min-height: 100px;
|
||||
max-height: 100%;
|
||||
}
|
||||
.listItem {
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
align-items: center;
|
||||
transition: background-color 0.2s ease;
|
||||
padding: 10px;
|
||||
// border-radius: @radius-border;
|
||||
&:hover {
|
||||
background-color: var(--color-primary-background-hover);
|
||||
}
|
||||
}
|
||||
.noitem {
|
||||
height: 100px;
|
||||
font-size: 18px;
|
||||
color: var(--color-font-label);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.listLeft {
|
||||
flex: auto;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
justify-content: center;
|
||||
}
|
||||
.listBtn {
|
||||
flex: none;
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
svg {
|
||||
width: 60%;
|
||||
}
|
||||
}
|
||||
|
||||
// .footer {
|
||||
// width: @width;
|
||||
// }
|
||||
.tips {
|
||||
padding: 8px 15px;
|
||||
font-size: 13px;
|
||||
line-height: 1.25;
|
||||
color: var(--color-font);
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,69 @@
|
||||
<template lang="pug">
|
||||
dd
|
||||
h3 {{ $t('setting__sync_client_mode') }}
|
||||
div
|
||||
.p.small {{ $t('setting__sync_client_status', { status: clientStatus }) }}
|
||||
.p.small {{ $t('setting__sync_client_address', { address: sync.client.status.address.join(', ') || '' }) }}
|
||||
.p
|
||||
.p.small {{ $t('setting__sync_client_host') }}
|
||||
div
|
||||
base-input.gap-left(:class="$style.hostInput" :model-value="appSetting['sync.client.host']" :disabled="sync.enable" :placeholder="$t('setting__sync_client_host_tip')" @update:model-value="setSyncClientHost")
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { computed } from '@common/utils/vueTools'
|
||||
import { sync } from '@renderer/store'
|
||||
import { useI18n } from '@renderer/plugins/i18n'
|
||||
import { appSetting, updateSetting } from '@renderer/store/setting'
|
||||
import { debounce } from '@common/utils/common'
|
||||
import { SYNC_CODE } from '@common/constants_sync'
|
||||
|
||||
export default {
|
||||
name: 'SettingSyncClient',
|
||||
setup() {
|
||||
const t = useI18n()
|
||||
|
||||
const clientStatus = computed(() => {
|
||||
let status
|
||||
switch (sync.client.status.message) {
|
||||
case SYNC_CODE.msgBlockedIp:
|
||||
status = t('setting__sync_code_blocked_ip')
|
||||
break
|
||||
case SYNC_CODE.authFailed:
|
||||
status = t('setting__sync_code_fail')
|
||||
break
|
||||
default:
|
||||
status = sync.client.status.message
|
||||
? sync.client.status.message
|
||||
: sync.client.status.status
|
||||
? t('setting_sync_status_enabled')
|
||||
: t('sync_status_disabled')
|
||||
break
|
||||
}
|
||||
return status
|
||||
})
|
||||
|
||||
const setSyncClientHost = debounce(host => {
|
||||
updateSetting({ 'sync.client.host': host.trim() })
|
||||
}, 500)
|
||||
|
||||
|
||||
return {
|
||||
appSetting,
|
||||
sync,
|
||||
setSyncClientHost,
|
||||
clientStatus,
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" module>
|
||||
.hostInput[disabled] {
|
||||
opacity: .8 !important;
|
||||
}
|
||||
|
||||
.hostInput {
|
||||
min-width: 380px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,175 @@
|
||||
<template lang="pug">
|
||||
dd
|
||||
h3 {{ syncEnableServerTitle }}
|
||||
div
|
||||
.p.small {{ $t('setting__sync_server_auth_code', { code: sync.server.status.code || '' }) }}
|
||||
.p.small {{ $t('setting__sync_server_address', { address: sync.server.status.address.join(', ') || '' }) }}
|
||||
.p.small {{ $t('setting__sync_server_device', { devices: syncDevices }) }}
|
||||
.p.gap-top
|
||||
.p.small {{ $t('setting__sync_server_port') }}
|
||||
div
|
||||
base-input.gap-left(:class="$style.portInput" :model-value="appSetting['sync.server.port']" :disabled="sync.enable" type="number" :placeholder="$t('setting__sync_server_port_tip')" @update:model-value="setSyncServerPort")
|
||||
|
||||
.p.gap-top
|
||||
base-btn.btn(min :disabled="!sync.server.status.status" @click="refreshSyncCode") {{ $t('setting__sync_server_refresh_code') }}
|
||||
base-btn.btn(min @click="isShowDeviceListModal = true") {{ $t('setting__sync_server_show_device_list') }}
|
||||
ServerDeviceListModal(v-model="isShowDeviceListModal")
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { computed, ref } from '@common/utils/vueTools'
|
||||
import { sync } from '@renderer/store'
|
||||
import { sendSyncAction } from '@renderer/utils/ipc'
|
||||
import { useI18n } from '@renderer/plugins/i18n'
|
||||
import { appSetting, updateSetting } from '@renderer/store/setting'
|
||||
import { debounce } from '@common/utils/common'
|
||||
import ServerDeviceListModal from './ServerDeviceListModal.vue'
|
||||
|
||||
export default {
|
||||
name: 'SettingSyncServer',
|
||||
components: {
|
||||
ServerDeviceListModal,
|
||||
},
|
||||
setup() {
|
||||
const t = useI18n()
|
||||
const isShowDeviceListModal = ref(false)
|
||||
|
||||
const syncEnableServerTitle = computed(() => {
|
||||
let title = t('setting__sync_server_mode')
|
||||
if (sync.server.status.message) {
|
||||
title += ` [${sync.server.status.message}]`
|
||||
}
|
||||
// else if (this.sync.server.status.address.length) {
|
||||
// // title += ` [${this.sync.server.status.address.join(', ')}]`
|
||||
// }
|
||||
return title
|
||||
})
|
||||
|
||||
const syncDevices = computed(() => {
|
||||
return sync.server.status.devices.length
|
||||
? sync.server.status.devices.map(d => `${d.deviceName} (${d.clientId.substring(0, 5)})`).join(', ')
|
||||
: ''
|
||||
})
|
||||
|
||||
const refreshSyncCode = () => {
|
||||
void sendSyncAction({ action: 'generate_code' })
|
||||
}
|
||||
|
||||
const setSyncServerPort = debounce(port => {
|
||||
updateSetting({ 'sync.server.port': port.trim() })
|
||||
}, 500)
|
||||
|
||||
return {
|
||||
appSetting,
|
||||
sync,
|
||||
syncEnableServerTitle,
|
||||
setSyncServerPort,
|
||||
syncDevices,
|
||||
refreshSyncCode,
|
||||
isShowDeviceListModal,
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" module>
|
||||
@import '@renderer/assets/styles/layout.less';
|
||||
.portInput[disabled], .hostInput[disabled] {
|
||||
opacity: .8 !important;
|
||||
}
|
||||
|
||||
.hostInput {
|
||||
min-width: 380px;
|
||||
}
|
||||
|
||||
|
||||
.list {
|
||||
// background-color: @color-search-form-background;
|
||||
font-size: 13px;
|
||||
transition-property: height;
|
||||
position: relative;
|
||||
.listItem {
|
||||
position: relative;
|
||||
padding: 15px 10px 15px 15px;
|
||||
transition: .3s ease;
|
||||
transition-property: background-color, opacity;
|
||||
line-height: 1.3;
|
||||
// overflow: hidden;
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
align-items: center;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--color-primary-background-hover);
|
||||
}
|
||||
// border-radius: 4px;
|
||||
// &:last-child {
|
||||
// border-bottom-left-radius: 4px;
|
||||
// border-bottom-right-radius: 4px;
|
||||
// }
|
||||
&.fetching {
|
||||
opacity: .5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.listLeft {
|
||||
flex: auto;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.text {
|
||||
flex: auto;
|
||||
margin-bottom: 2px;
|
||||
.mixin-ellipsis-1;
|
||||
}
|
||||
|
||||
.label {
|
||||
flex: none;
|
||||
font-size: 12px;
|
||||
opacity: 0.5;
|
||||
// padding: 0 10px;
|
||||
// display: flex;
|
||||
// align-items: center;
|
||||
// transform: rotate(45deg);
|
||||
// background-color:
|
||||
}
|
||||
.btns {
|
||||
flex: none;
|
||||
font-size: 12px;
|
||||
padding: 0 5px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.btn {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
border-radius: @form-radius;
|
||||
margin-right: 5px;
|
||||
cursor: pointer;
|
||||
padding: 4px 7px;
|
||||
color: var(--color-button-font);
|
||||
outline: none;
|
||||
transition: background-color 0.2s ease;
|
||||
line-height: 0;
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
svg {
|
||||
height: 22px;
|
||||
width: 22px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: var(--color-primary-background-hover);
|
||||
}
|
||||
&:active {
|
||||
background-color: var(--color-primary-font-active);
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,44 @@
|
||||
<template lang="pug">
|
||||
dt#sync
|
||||
| {{ $t('setting__sync') }}
|
||||
button(class="help-btn" :aria-label="$t('setting__sync_tip')" @click="openUrl('https://lyswhut.github.io/lx-music-doc/desktop/faq/sync')")
|
||||
svg-icon(name="help-circle-outline")
|
||||
dd
|
||||
base-checkbox(id="setting_sync_enable" :model-value="appSetting['sync.enable']" :label="$t('setting__sync_enable')" @update:model-value="updateSetting({ 'sync.enable': $event })")
|
||||
|
||||
dd
|
||||
h3#sync_mode {{ $t('setting__sync_mode') }}
|
||||
div
|
||||
base-checkbox.gap-left(id="setting_sync_mode_server" :disabled="sync.enable" :model-value="appSetting['sync.mode']" need value="server" :label="$t('setting__sync_mode_server')" @update:model-value="updateSetting({ 'sync.mode': $event })")
|
||||
base-checkbox.gap-left(id="setting_sync_mode_client" :disabled="sync.enable" :model-value="appSetting['sync.mode']" need value="client" :label="$t('setting__sync_mode_client')" @update:model-value="updateSetting({ 'sync.mode': $event })")
|
||||
|
||||
|
||||
SyncClient(v-if="sync.mode == 'client'")
|
||||
SyncServer(v-else)
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// import { computed } from '@common/utils/vueTools'
|
||||
import { sync } from '@renderer/store'
|
||||
import { openUrl } from '@common/utils/electron'
|
||||
import { appSetting, updateSetting } from '@renderer/store/setting'
|
||||
import SyncServer from './SyncServer.vue'
|
||||
import SyncClient from './SyncClient.vue'
|
||||
|
||||
export default {
|
||||
name: 'SettingSync',
|
||||
components: {
|
||||
SyncServer,
|
||||
SyncClient,
|
||||
},
|
||||
setup() {
|
||||
return {
|
||||
appSetting,
|
||||
updateSetting,
|
||||
sync,
|
||||
openUrl,
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -59,7 +59,7 @@ import SettingDesktopLyric from './components/SettingDesktopLyric.vue'
|
||||
import SettingSearch from './components/SettingSearch.vue'
|
||||
import SettingList from './components/SettingList.vue'
|
||||
import SettingDownload from './components/SettingDownload.vue'
|
||||
import SettingSync from './components/SettingSync.vue'
|
||||
import SettingSync from './components/SettingSync/index.vue'
|
||||
import SettingHotKey from './components/SettingHotKey.vue'
|
||||
import SettingNetwork from './components/SettingNetwork.vue'
|
||||
import SettingOdc from './components/SettingOdc.vue'
|
||||
|
||||
Reference in New Issue
Block a user