mirror of
https://github.com/Kuingsmile/PicList.git
synced 2025-01-22 22:28:14 -05:00
🔨 Refactor: upgrade vue2 -> vue3
This commit is contained in:
parent
624e5738d1
commit
66d8d714db
@ -8,7 +8,7 @@ module.exports = {
|
||||
},
|
||||
parser: 'vue-eslint-parser',
|
||||
extends: [
|
||||
'plugin:vue/essential',
|
||||
'plugin:vue/vue3-recommended',
|
||||
'@vue/standard',
|
||||
'@vue/typescript'
|
||||
],
|
||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -19,3 +19,6 @@ dist_electron/
|
||||
test.js
|
||||
.env
|
||||
scripts/*.yml
|
||||
|
||||
#Electron-builder output
|
||||
/dist_electron
|
@ -30,7 +30,7 @@
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: '',
|
||||
name: 'HomePage',
|
||||
data () {
|
||||
return {
|
||||
version: '',
|
||||
|
154
package.json
154
package.json
@ -3,25 +3,87 @@
|
||||
"version": "2.4.0-beta.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vue-cli-service electron:serve",
|
||||
"build": "vue-cli-service electron:build",
|
||||
"lint": "vue-cli-service lint",
|
||||
"lint:fix": "eslint --fix --ext .js,.jsx,.ts,.tsx,.vue src/",
|
||||
"bump": "bump-version",
|
||||
"cz": "git-cz",
|
||||
"dev": "vue-cli-service electron:serve",
|
||||
"electron:build": "vue-cli-service electron:build",
|
||||
"electron:serve": "vue-cli-service electron:serve",
|
||||
"gen-i18n": "node ./scripts/gen-i18n-types.js",
|
||||
"lint:fix": "eslint --fix --ext .js,.jsx,.ts,.tsx,.vue src/",
|
||||
"postinstall": "electron-builder install-app-deps",
|
||||
"postuninstall": "electron-builder install-app-deps",
|
||||
"cz": "git-cz",
|
||||
"bump": "bump-version",
|
||||
"release": "vue-cli-service electron:build --publish always",
|
||||
"upload-dist": "node ./scripts/upload-dist-to-cos.js",
|
||||
"gen-i18n": "node ./scripts/gen-i18n-types.js"
|
||||
"upload-dist": "node ./scripts/upload-dist-to-cos.js"
|
||||
},
|
||||
"main": "background.js",
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
|
||||
}
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "^2.0.10",
|
||||
"@picgo/i18n": "^1.0.0",
|
||||
"@picgo/store": "^2.0.4",
|
||||
"axios": "^0.19.0",
|
||||
"compare-versions": "^4.1.3",
|
||||
"core-js": "^3.27.1",
|
||||
"element-plus": "^2.2.28",
|
||||
"fs-extra": "^10.0.0",
|
||||
"js-yaml": "^4.1.0",
|
||||
"keycode": "^2.2.0",
|
||||
"lodash-id": "^0.14.0",
|
||||
"lowdb": "^1.0.0",
|
||||
"mitt": "^3.0.0",
|
||||
"picgo": "^1.5.0",
|
||||
"qrcode.vue": "^3.3.3",
|
||||
"shell-path": "2.1.0",
|
||||
"uuidv4": "^6.2.11",
|
||||
"vue": "^3.2.45",
|
||||
"vue-router": "^4.1.6",
|
||||
"vue3-lazyload": "^0.3.6",
|
||||
"vue3-photo-preview": "^0.2.9",
|
||||
"write-file-atomic": "^4.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/plugin-proposal-optional-chaining": "^7.16.7",
|
||||
"@picgo/bump-version": "^1.1.2",
|
||||
"@types/electron-devtools-installer": "^2.2.0",
|
||||
"@types/fs-extra": "^9.0.13",
|
||||
"@types/inquirer": "^6.5.0",
|
||||
"@types/js-yaml": "^4.0.5",
|
||||
"@types/lowdb": "^1.0.9",
|
||||
"@types/node": "^16.10.2",
|
||||
"@types/request-promise-native": "^1.0.17",
|
||||
"@types/semver": "^7.3.8",
|
||||
"@types/write-file-atomic": "^4.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.48.0",
|
||||
"@typescript-eslint/parser": "^5.48.0",
|
||||
"@vue/cli-plugin-babel": "^5.0.8",
|
||||
"@vue/cli-plugin-eslint": "^5.0.8",
|
||||
"@vue/cli-plugin-router": "^5.0.8",
|
||||
"@vue/cli-plugin-typescript": "^5.0.8",
|
||||
"@vue/cli-service": "^5.0.8",
|
||||
"@vue/eslint-config-standard": "^8.0.1",
|
||||
"@vue/eslint-config-typescript": "^11.0.2",
|
||||
"@vue/runtime-dom": "^3.2.45",
|
||||
"conventional-changelog": "^3.1.18",
|
||||
"cz-customizable": "^6.2.0",
|
||||
"dotenv": "^16.0.1",
|
||||
"electron": "^16.0.6",
|
||||
"electron-devtools-installer": "^3.2.0",
|
||||
"eslint": "^8.31.0",
|
||||
"eslint-config-standard": ">=16.0.0",
|
||||
"eslint-plugin-import": "^2.24.2",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-promise": "^5.1.0",
|
||||
"eslint-plugin-vue": "^9.8.0",
|
||||
"husky": "^3.1.0",
|
||||
"stylus": "^0.54.7",
|
||||
"stylus-loader": "^3.0.2",
|
||||
"typescript": "^4.4.3",
|
||||
"vue-cli-plugin-electron-builder": "^3.0.0-alpha.4"
|
||||
},
|
||||
"commitlint": {
|
||||
"extends": [
|
||||
"./node_modules/@picgo/bump-version/commitlint-picgo"
|
||||
]
|
||||
},
|
||||
"config": {
|
||||
"commitizen": {
|
||||
@ -31,72 +93,10 @@
|
||||
"config": "./node_modules/@picgo/bump-version/.cz-config.js"
|
||||
}
|
||||
},
|
||||
"commitlint": {
|
||||
"extends": [
|
||||
"./node_modules/@picgo/bump-version/commitlint-picgo"
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@picgo/i18n": "^1.0.0",
|
||||
"@picgo/store": "^2.0.4",
|
||||
"axios": "^0.19.0",
|
||||
"compare-versions": "^4.1.3",
|
||||
"core-js": "^3.3.2",
|
||||
"element-ui": "^2.13.0",
|
||||
"fs-extra": "^10.0.0",
|
||||
"js-yaml": "^4.1.0",
|
||||
"keycode": "^2.2.0",
|
||||
"lodash-id": "^0.14.0",
|
||||
"lowdb": "^1.0.0",
|
||||
"picgo": "^1.5.0",
|
||||
"qrcode.vue": "^1.7.0",
|
||||
"shell-path": "2.1.0",
|
||||
"uuidv4": "^6.2.11",
|
||||
"vue": "^2.6.10",
|
||||
"vue-gallery": "^2.0.1",
|
||||
"vue-lazyload": "^1.2.6",
|
||||
"vue-router": "^3.1.3",
|
||||
"write-file-atomic": "^4.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/plugin-proposal-optional-chaining": "^7.16.7",
|
||||
"@picgo/bump-version": "^1.1.2",
|
||||
"@types/fs-extra": "^9.0.13",
|
||||
"@types/inquirer": "^6.5.0",
|
||||
"@types/js-yaml": "^4.0.5",
|
||||
"@types/lowdb": "^1.0.9",
|
||||
"@types/node": "^16.10.2",
|
||||
"@types/request-promise-native": "^1.0.17",
|
||||
"@types/semver": "^7.3.8",
|
||||
"@types/write-file-atomic": "^4.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^4.33.0",
|
||||
"@typescript-eslint/parser": "^4.33.0",
|
||||
"@vue/cli-plugin-babel": "^4.0.0",
|
||||
"@vue/cli-plugin-eslint": "^4.0.0",
|
||||
"@vue/cli-plugin-router": "^4.0.0",
|
||||
"@vue/cli-plugin-typescript": "^4.5.13",
|
||||
"@vue/cli-service": "^4.0.0",
|
||||
"@vue/eslint-config-standard": "^6.1.0",
|
||||
"@vue/eslint-config-typescript": "^7.0.0",
|
||||
"@vue/runtime-dom": "^3.2.45",
|
||||
"conventional-changelog": "^3.1.18",
|
||||
"cz-customizable": "^6.2.0",
|
||||
"dotenv": "^16.0.1",
|
||||
"electron": "^16.0.6",
|
||||
"electron-devtools-installer": "^3.2.0",
|
||||
"eslint": "^7.32.0",
|
||||
"eslint-config-standard": ">=16.0.0",
|
||||
"eslint-plugin-import": "^2.24.2",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-promise": "^5.1.0",
|
||||
"eslint-plugin-vue": "^7.0.0",
|
||||
"husky": "^3.1.0",
|
||||
"stylus": "^0.54.7",
|
||||
"stylus-loader": "^3.0.2",
|
||||
"typescript": "^4.4.3",
|
||||
"vue-cli-plugin-electron-builder": "^2.1.1",
|
||||
"vue-property-decorator": "^8.3.0",
|
||||
"vue-template-compiler": "^2.6.10"
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
|
||||
}
|
||||
},
|
||||
"resolutions": {
|
||||
"@types/node": "^16.10.2",
|
||||
|
53
src/main.ts
53
src/main.ts
@ -1,26 +1,29 @@
|
||||
import Vue from 'vue'
|
||||
import { createApp } from 'vue'
|
||||
import App from './renderer/App.vue'
|
||||
import router from './renderer/router'
|
||||
import ElementUI from 'element-ui'
|
||||
import ElementUI from 'element-plus'
|
||||
import 'element-plus/dist/index.css'
|
||||
import { webFrame } from 'electron'
|
||||
import 'element-ui/lib/theme-chalk/index.css'
|
||||
import VueLazyLoad from 'vue-lazyload'
|
||||
import VueLazyLoad from 'vue3-lazyload'
|
||||
import axios from 'axios'
|
||||
import mainMixin from './renderer/utils/mainMixin'
|
||||
import bus from '@/utils/bus'
|
||||
import { mainMixin } from './renderer/utils/mainMixin'
|
||||
import { dragMixin } from '@/utils/mixin'
|
||||
import { initTalkingData } from './renderer/utils/analytics'
|
||||
import db from './renderer/utils/db'
|
||||
// import { T, i18n } from '#/i18n/index'
|
||||
// import { handleURLParams } from '@/utils/beforeOpen'
|
||||
import { i18nManager, T } from './renderer/i18n/index'
|
||||
import { getConfig, saveConfig, sendToMain, triggerRPC } from '@/utils/dataSender'
|
||||
import { store } from '@/store'
|
||||
import vue3PhotoPreview from 'vue3-photo-preview'
|
||||
import 'vue3-photo-preview/dist/index.css'
|
||||
|
||||
webFrame.setVisualZoomLevelLimits(1, 1)
|
||||
|
||||
// do here before vue init
|
||||
// handleURLParams()
|
||||
|
||||
Vue.config.productionTip = false
|
||||
Vue.prototype.$builtInPicBed = [
|
||||
const app = createApp(App)
|
||||
|
||||
app.config.globalProperties.$builtInPicBed = [
|
||||
'smms',
|
||||
'imgur',
|
||||
'qiniu',
|
||||
@ -29,21 +32,27 @@ Vue.prototype.$builtInPicBed = [
|
||||
'aliyun',
|
||||
'github'
|
||||
]
|
||||
Vue.prototype.$$db = db
|
||||
Vue.prototype.$http = axios
|
||||
Vue.prototype.$bus = bus
|
||||
Vue.prototype.$T = T
|
||||
Vue.prototype.$i18n = i18nManager
|
||||
|
||||
Vue.use(ElementUI)
|
||||
Vue.use(VueLazyLoad, {
|
||||
app.config.globalProperties.$$db = db
|
||||
app.config.globalProperties.$http = axios
|
||||
app.config.globalProperties.$T = T
|
||||
app.config.globalProperties.$i18n = i18nManager
|
||||
app.config.globalProperties.getConfig = getConfig
|
||||
app.config.globalProperties.triggerRPC = triggerRPC
|
||||
app.config.globalProperties.saveConfig = saveConfig
|
||||
app.config.globalProperties.sendToMain = sendToMain
|
||||
|
||||
app.mixin(mainMixin)
|
||||
app.mixin(dragMixin)
|
||||
|
||||
app.use(VueLazyLoad, {
|
||||
error: `file://${__static.replace(/\\/g, '/')}/unknown-file-type.svg`
|
||||
})
|
||||
Vue.mixin(mainMixin)
|
||||
app.use(ElementUI)
|
||||
app.use(router)
|
||||
app.use(store)
|
||||
app.use(vue3PhotoPreview)
|
||||
|
||||
new Vue({
|
||||
router,
|
||||
render: h => h(App)
|
||||
}).$mount('#app')
|
||||
app.mount('#app')
|
||||
|
||||
initTalkingData()
|
||||
|
@ -23,6 +23,7 @@ const handleClipboardUploading = async (): Promise<false | ImgInfo[]> => {
|
||||
|
||||
export const uploadClipboardFiles = async (): Promise<string> => {
|
||||
const img = await handleClipboardUploading()
|
||||
console.log(img)
|
||||
if (img !== false) {
|
||||
if (img.length > 0) {
|
||||
const trayWindow = windowManager.get(IWindowList.TRAY_WINDOW)
|
||||
|
@ -21,6 +21,7 @@ import { T } from '~/main/i18n'
|
||||
|
||||
// Cross-process support may be required in the future
|
||||
class GuiApi implements IGuiApi {
|
||||
// eslint-disable-next-line no-use-before-define
|
||||
private static instance: GuiApi
|
||||
private windowId: number = -1
|
||||
private settingWindowId: number = -1
|
||||
|
@ -70,6 +70,7 @@ export default {
|
||||
})
|
||||
|
||||
ipcMain.on('uploadClipboardFilesFromUploadPage', () => {
|
||||
console.log('handle')
|
||||
uploadClipboardFiles()
|
||||
})
|
||||
|
||||
|
@ -9,7 +9,7 @@ import {
|
||||
import { privacyManager } from '~/main/utils/privacyManager'
|
||||
import pkg from 'root/package.json'
|
||||
import GuiApi from 'apis/gui'
|
||||
import { PICGO_CONFIG_PLUGIN, PICGO_HANDLE_PLUGIN_ING, PICGO_TOGGLE_PLUGIN, SHOW_MAIN_PAGE_DONATION, SHOW_MAIN_PAGE_QRCODE } from '~/universal/events/constants'
|
||||
import { PICGO_CONFIG_PLUGIN, PICGO_HANDLE_PLUGIN_DONE, PICGO_HANDLE_PLUGIN_ING, PICGO_TOGGLE_PLUGIN, SHOW_MAIN_PAGE_DONATION, SHOW_MAIN_PAGE_QRCODE } from '~/universal/events/constants'
|
||||
import picgoCoreIPC from '~/main/events/picgoCoreIPC'
|
||||
import { PicGo as PicGoCore } from 'picgo'
|
||||
import { T } from '~/main/i18n'
|
||||
@ -210,6 +210,7 @@ const buildPluginPageMenu = (plugin: IPicGoPlugin) => {
|
||||
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
|
||||
window.webContents.send(PICGO_HANDLE_PLUGIN_ING, plugin.fullName)
|
||||
window.webContents.send(PICGO_TOGGLE_PLUGIN, plugin.fullName, false)
|
||||
window.webContents.send(PICGO_HANDLE_PLUGIN_DONE, plugin.fullName)
|
||||
if (plugin.config.transformer.name) {
|
||||
handleRestoreState('transformer', plugin.config.transformer.name)
|
||||
}
|
||||
|
@ -105,11 +105,7 @@ class LifeCycle {
|
||||
await remoteNoticeHandler.init()
|
||||
remoteNoticeHandler.triggerHook(IRemoteNoticeTriggerHook.APP_START)
|
||||
}
|
||||
if (!app.isReady()) {
|
||||
app.on('ready', readyFunction)
|
||||
} else {
|
||||
readyFunction()
|
||||
}
|
||||
app.whenReady().then(readyFunction)
|
||||
}
|
||||
|
||||
private onRunning () {
|
||||
|
@ -1,12 +1,28 @@
|
||||
<template>
|
||||
<div id="app">
|
||||
<router-view></router-view>
|
||||
<router-view />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script lang="ts" setup>
|
||||
import { useStore } from '@/hooks/useStore'
|
||||
import { onBeforeMount } from 'vue'
|
||||
import { getConfig } from './utils/dataSender'
|
||||
import type { IConfig } from 'picgo'
|
||||
|
||||
const store = useStore()
|
||||
onBeforeMount(async () => {
|
||||
const config = await getConfig<IConfig>()
|
||||
if (config) {
|
||||
store?.setDefaultPicBed(config?.picBed?.uploader || config?.picBed?.current || 'smms')
|
||||
}
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'picgo'
|
||||
name: 'PicGoApp'
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -1,37 +0,0 @@
|
||||
<template>
|
||||
<div id="choose-pic-bed">
|
||||
<span>{{ $T('CHOOSE_YOUR_DEFAULT_PICBED', { d: label }) }}</span>
|
||||
<el-switch
|
||||
v-model="value"
|
||||
@change="choosePicBed"
|
||||
>
|
||||
</el-switch>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { Component, Vue, Prop } from 'vue-property-decorator'
|
||||
@Component({
|
||||
name: 'choose-pic-bed'
|
||||
})
|
||||
export default class extends Vue {
|
||||
value = false
|
||||
@Prop() type!: string
|
||||
@Prop() label!: string
|
||||
async created () {
|
||||
const current = await this.getConfig<string>('picBed.current')
|
||||
if (this.type === current) {
|
||||
this.value = true
|
||||
}
|
||||
}
|
||||
|
||||
choosePicBed () {
|
||||
this.saveConfig({
|
||||
'picBed.current': this.type,
|
||||
'picBed.uploader': this.type
|
||||
})
|
||||
this.$emit('update:choosed', this.type)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang='stylus'>
|
||||
</style>
|
@ -1,11 +1,14 @@
|
||||
<template>
|
||||
<div id="config-form">
|
||||
<div
|
||||
id="config-form"
|
||||
:class="props.colorMode === 'white' ? 'white' : ''"
|
||||
>
|
||||
<el-form
|
||||
label-position="right"
|
||||
label-width="120px"
|
||||
ref="$form"
|
||||
label-position="left"
|
||||
label-width="50%"
|
||||
:model="ruleForm"
|
||||
ref="form"
|
||||
size="mini"
|
||||
size="small"
|
||||
>
|
||||
<el-form-item
|
||||
:label="$T('UPLOADER_CONFIG_NAME')"
|
||||
@ -13,25 +16,25 @@
|
||||
prop="_configName"
|
||||
>
|
||||
<el-input
|
||||
type="input"
|
||||
v-model="ruleForm._configName"
|
||||
type="input"
|
||||
:placeholder="$T('UPLOADER_CONFIG_PLACEHOLDER')"
|
||||
></el-input>
|
||||
/>
|
||||
</el-form-item>
|
||||
<!-- dynamic config -->
|
||||
<el-form-item
|
||||
v-for="(item, index) in configList"
|
||||
:key="item.name + index"
|
||||
:label="item.alias || item.name"
|
||||
:required="item.required"
|
||||
:prop="item.name"
|
||||
:key="item.name + index"
|
||||
>
|
||||
<el-input
|
||||
v-if="item.type === 'input' || item.type === 'password'"
|
||||
:type="item.type === 'password' ? 'password' : 'input'"
|
||||
v-model="ruleForm[item.name]"
|
||||
:type="item.type === 'password' ? 'password' : 'input'"
|
||||
:placeholder="item.message || item.name"
|
||||
></el-input>
|
||||
/>
|
||||
<el-select
|
||||
v-else-if="item.type === 'list' && item.choices"
|
||||
v-model="ruleForm[item.name]"
|
||||
@ -39,10 +42,10 @@
|
||||
>
|
||||
<el-option
|
||||
v-for="choice in item.choices"
|
||||
:label="choice.name || choice.value || choice"
|
||||
:key="choice.name || choice.value || choice"
|
||||
:label="choice.name || choice.value || choice"
|
||||
:value="choice.value || choice"
|
||||
></el-option>
|
||||
/>
|
||||
</el-select>
|
||||
<el-select
|
||||
v-else-if="item.type === 'checkbox' && item.choices"
|
||||
@ -53,112 +56,120 @@
|
||||
>
|
||||
<el-option
|
||||
v-for="choice in item.choices"
|
||||
:label="choice.name || choice.value || choice"
|
||||
:key="choice.value || choice"
|
||||
:label="choice.name || choice.value || choice"
|
||||
:value="choice.value || choice"
|
||||
></el-option>
|
||||
/>
|
||||
</el-select>
|
||||
<el-switch
|
||||
v-else-if="item.type === 'confirm'"
|
||||
v-model="ruleForm[item.name]"
|
||||
active-text="yes"
|
||||
inactive-text="no"
|
||||
>
|
||||
</el-switch>
|
||||
/>
|
||||
</el-form-item>
|
||||
<slot></slot>
|
||||
<slot />
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import {
|
||||
Component,
|
||||
Vue,
|
||||
Prop,
|
||||
Watch
|
||||
} from 'vue-property-decorator'
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref, watch, defineExpose, toRefs } from 'vue'
|
||||
import { cloneDeep, union } from 'lodash'
|
||||
import { getConfig } from '@/utils/dataSender'
|
||||
import { useRoute } from 'vue-router'
|
||||
import type { FormInstance } from 'element-plus'
|
||||
|
||||
@Component({
|
||||
name: 'config-form'
|
||||
interface IProps {
|
||||
config: any[]
|
||||
type: 'uploader' | 'transformer' | 'plugin'
|
||||
id: string
|
||||
colorMode?: 'white' | 'dark'
|
||||
}
|
||||
|
||||
const props = defineProps<IProps>()
|
||||
const $route = useRoute()
|
||||
const $form = ref<FormInstance>()
|
||||
|
||||
const configList = ref<IPicGoPluginConfig[]>([])
|
||||
const ruleForm = reactive<IStringKeyMap>({})
|
||||
|
||||
watch(toRefs(props.config), (val: IPicGoPluginConfig[]) => {
|
||||
handleConfigChange(val)
|
||||
}, {
|
||||
deep: true,
|
||||
immediate: true
|
||||
})
|
||||
export default class extends Vue {
|
||||
@Prop() private config!: any[]
|
||||
@Prop() readonly type!: 'uploader' | 'transformer' | 'plugin'
|
||||
@Prop() readonly id!: string
|
||||
configList: IPicGoPluginConfig[] = []
|
||||
ruleForm: IStringKeyMap = {}
|
||||
@Watch('config', {
|
||||
deep: true,
|
||||
immediate: true
|
||||
})
|
||||
handleConfigChange (val: any) {
|
||||
this.handleConfig(val)
|
||||
}
|
||||
|
||||
async validate () {
|
||||
return new Promise((resolve) => {
|
||||
// @ts-ignore
|
||||
this.$refs.form.validate((valid: boolean) => {
|
||||
if (valid) {
|
||||
resolve(this.ruleForm)
|
||||
} else {
|
||||
resolve(false)
|
||||
return false
|
||||
}
|
||||
})
|
||||
function handleConfigChange (val: any) {
|
||||
handleConfig(val)
|
||||
}
|
||||
|
||||
async function validate (): Promise<IStringKeyMap | false> {
|
||||
return new Promise((resolve) => {
|
||||
$form.value?.validate((valid: boolean) => {
|
||||
if (valid) {
|
||||
resolve(ruleForm)
|
||||
} else {
|
||||
resolve(false)
|
||||
return false
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
getConfigType () {
|
||||
switch (this.type) {
|
||||
case 'plugin': {
|
||||
return this.id
|
||||
}
|
||||
case 'uploader': {
|
||||
return `picBed.${this.id}`
|
||||
}
|
||||
case 'transformer': {
|
||||
return `transformer.${this.id}`
|
||||
}
|
||||
default:
|
||||
return 'unknown'
|
||||
function getConfigType () {
|
||||
switch (props.type) {
|
||||
case 'plugin': {
|
||||
return props.id
|
||||
}
|
||||
}
|
||||
|
||||
async handleConfig (val: IPicGoPluginConfig[]) {
|
||||
const config = await this.getCurConfigFormData()
|
||||
const configId = this.$route.params.configId
|
||||
this.ruleForm = Object.assign({}, config)
|
||||
if (val.length > 0) {
|
||||
this.configList = cloneDeep(val).map((item) => {
|
||||
if (!configId) return item
|
||||
let defaultValue = item.default !== undefined
|
||||
? item.default
|
||||
: item.type === 'checkbox'
|
||||
? []
|
||||
: null
|
||||
if (item.type === 'checkbox') {
|
||||
const defaults = item.choices?.filter((i: any) => {
|
||||
return i.checked
|
||||
}).map((i: any) => i.value) || []
|
||||
defaultValue = union(defaultValue, defaults)
|
||||
}
|
||||
if (config && config[item.name] !== undefined) {
|
||||
defaultValue = config[item.name]
|
||||
}
|
||||
this.$set(this.ruleForm, item.name, defaultValue)
|
||||
return item
|
||||
})
|
||||
case 'uploader': {
|
||||
return `picBed.${props.id}`
|
||||
}
|
||||
}
|
||||
|
||||
async getCurConfigFormData () {
|
||||
const configId = this.$route.params.configId
|
||||
const curTypeConfigList = await this.getConfig<IStringKeyMap[]>(`uploader.${this.id}.configList`) || []
|
||||
return curTypeConfigList.find(i => i._id === configId) || {}
|
||||
case 'transformer': {
|
||||
return `transformer.${props.id}`
|
||||
}
|
||||
default:
|
||||
return 'unknown'
|
||||
}
|
||||
}
|
||||
|
||||
async function handleConfig (val: IPicGoPluginConfig[]) {
|
||||
const config = await getCurConfigFormData()
|
||||
const configId = $route.params.configId
|
||||
Object.assign(ruleForm, config)
|
||||
if (val.length > 0) {
|
||||
configList.value = cloneDeep(val).map((item) => {
|
||||
if (!configId) return item
|
||||
let defaultValue = item.default !== undefined
|
||||
? item.default
|
||||
: item.type === 'checkbox'
|
||||
? []
|
||||
: null
|
||||
if (item.type === 'checkbox') {
|
||||
const defaults = item.choices?.filter((i: any) => {
|
||||
return i.checked
|
||||
}).map((i: any) => i.value) || []
|
||||
defaultValue = union(defaultValue, defaults)
|
||||
}
|
||||
if (config && config[item.name] !== undefined) {
|
||||
defaultValue = config[item.name]
|
||||
}
|
||||
ruleForm[item.name] = defaultValue
|
||||
return item
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
async function getCurConfigFormData () {
|
||||
const configId = $route.params.configId
|
||||
const curTypeConfigList = await getConfig<IStringKeyMap[]>(`uploader.${props.id}.configList`) || []
|
||||
return curTypeConfigList.find(i => i._id === configId) || {}
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
validate,
|
||||
getConfigType
|
||||
})
|
||||
</script>
|
||||
<style lang='stylus'>
|
||||
#config-form
|
||||
@ -166,15 +177,25 @@ export default class extends Vue {
|
||||
label
|
||||
line-height 22px
|
||||
padding-bottom 0
|
||||
&-item
|
||||
display: flex
|
||||
justify-content space-between
|
||||
border-bottom 1px solid darken(#eee, 50%)
|
||||
padding-bottom 16px
|
||||
&:last-child
|
||||
border-bottom none
|
||||
&__content
|
||||
justify-content flex-end
|
||||
.el-button-group
|
||||
width 100%
|
||||
.el-button
|
||||
width 50%
|
||||
.el-input__inner
|
||||
border-radius 19px
|
||||
.el-radio-group
|
||||
margin-left 25px
|
||||
.el-switch__label
|
||||
&.is-active
|
||||
color #409EFF
|
||||
&.white
|
||||
.el-form-item
|
||||
border-bottom 1px solid #ddd
|
||||
</style>
|
||||
|
@ -1,69 +1,84 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="showInputBoxVisible"
|
||||
:title="inputBoxOptions.title || $T('INPUT')"
|
||||
:visible.sync="showInputBoxVisible"
|
||||
:modal-append-to-body="false"
|
||||
>
|
||||
<el-input
|
||||
v-model="inputBoxValue"
|
||||
:placeholder="inputBoxOptions.placeholder"></el-input>
|
||||
<span slot="footer">
|
||||
<el-button @click="handleInputBoxCancel" round>{{ $T('CANCEL') }}</el-button>
|
||||
<el-button type="primary" @click="handleInputBoxConfirm" round>{{ $T('CONFIRM') }}</el-button>
|
||||
</span>
|
||||
:placeholder="inputBoxOptions.placeholder"
|
||||
/>
|
||||
<template #footer>
|
||||
<el-button
|
||||
round
|
||||
@click="handleInputBoxCancel"
|
||||
>
|
||||
{{ $T('CANCEL') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
round
|
||||
@click="handleInputBoxConfirm"
|
||||
>
|
||||
{{ $T('CONFIRM') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from 'vue-property-decorator'
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive, onBeforeUnmount, onBeforeMount } from 'vue'
|
||||
import { ipcRenderer, IpcRendererEvent } from 'electron'
|
||||
import {
|
||||
SHOW_INPUT_BOX,
|
||||
SHOW_INPUT_BOX_RESPONSE
|
||||
} from '~/universal/events/constants'
|
||||
@Component({
|
||||
name: 'input-box-dialog'
|
||||
import $bus from '@/utils/bus'
|
||||
import { sendToMain } from '@/utils/dataSender'
|
||||
const inputBoxValue = ref('')
|
||||
const showInputBoxVisible = ref(false)
|
||||
const inputBoxOptions = reactive({
|
||||
title: '',
|
||||
placeholder: ''
|
||||
})
|
||||
export default class extends Vue {
|
||||
inputBoxValue = ''
|
||||
showInputBoxVisible = false
|
||||
inputBoxOptions = {
|
||||
title: '',
|
||||
placeholder: ''
|
||||
}
|
||||
|
||||
created () {
|
||||
ipcRenderer.on(SHOW_INPUT_BOX, this.ipcEventHandler)
|
||||
this.$bus.$on(SHOW_INPUT_BOX, this.initInputBoxValue)
|
||||
}
|
||||
onBeforeMount(() => {
|
||||
ipcRenderer.on(SHOW_INPUT_BOX, ipcEventHandler)
|
||||
$bus.on(SHOW_INPUT_BOX, initInputBoxValue)
|
||||
})
|
||||
|
||||
ipcEventHandler (evt: IpcRendererEvent, options: IShowInputBoxOption) {
|
||||
this.initInputBoxValue(options)
|
||||
}
|
||||
function ipcEventHandler (evt: IpcRendererEvent, options: IShowInputBoxOption) {
|
||||
initInputBoxValue(options)
|
||||
}
|
||||
|
||||
initInputBoxValue (options: IShowInputBoxOption) {
|
||||
this.inputBoxValue = options.value || ''
|
||||
this.inputBoxOptions.title = options.title || ''
|
||||
this.inputBoxOptions.placeholder = options.placeholder || ''
|
||||
this.showInputBoxVisible = true
|
||||
}
|
||||
function initInputBoxValue (options: IShowInputBoxOption) {
|
||||
inputBoxValue.value = options.value || ''
|
||||
inputBoxOptions.title = options.title || ''
|
||||
inputBoxOptions.placeholder = options.placeholder || ''
|
||||
showInputBoxVisible.value = true
|
||||
}
|
||||
|
||||
handleInputBoxCancel () {
|
||||
// TODO: RPCServer
|
||||
this.showInputBoxVisible = false
|
||||
ipcRenderer.send(SHOW_INPUT_BOX, '')
|
||||
this.$bus.$emit(SHOW_INPUT_BOX_RESPONSE, '')
|
||||
}
|
||||
function handleInputBoxCancel () {
|
||||
// TODO: RPCServer
|
||||
showInputBoxVisible.value = false
|
||||
sendToMain(SHOW_INPUT_BOX, '')
|
||||
$bus.emit(SHOW_INPUT_BOX_RESPONSE, '')
|
||||
}
|
||||
|
||||
handleInputBoxConfirm () {
|
||||
this.showInputBoxVisible = false
|
||||
ipcRenderer.send(SHOW_INPUT_BOX, this.inputBoxValue)
|
||||
this.$bus.$emit(SHOW_INPUT_BOX_RESPONSE, this.inputBoxValue)
|
||||
}
|
||||
function handleInputBoxConfirm () {
|
||||
showInputBoxVisible.value = false
|
||||
sendToMain(SHOW_INPUT_BOX, inputBoxValue.value)
|
||||
$bus.emit(SHOW_INPUT_BOX_RESPONSE, inputBoxValue.value)
|
||||
}
|
||||
|
||||
beforeDestroy () {
|
||||
ipcRenderer.removeListener(SHOW_INPUT_BOX, this.ipcEventHandler)
|
||||
this.$bus.$off(SHOW_INPUT_BOX)
|
||||
}
|
||||
onBeforeUnmount(() => {
|
||||
ipcRenderer.removeListener(SHOW_INPUT_BOX, ipcEventHandler)
|
||||
$bus.off(SHOW_INPUT_BOX)
|
||||
})
|
||||
|
||||
</script>
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'InputBoxDialog'
|
||||
}
|
||||
</script>
|
||||
<style lang='stylus'>
|
||||
|
6
src/renderer/hooks/useStore.ts
Normal file
6
src/renderer/hooks/useStore.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import { inject } from 'vue'
|
||||
import { storeKey } from '@/store'
|
||||
|
||||
export const useStore = () => {
|
||||
return inject(storeKey) ?? null
|
||||
}
|
@ -19,7 +19,7 @@ export class I18nManager {
|
||||
ipcRenderer.send(GET_CURRENT_LANGUAGE)
|
||||
ipcRenderer.once(GET_CURRENT_LANGUAGE, (event, lang: string, locales: ILocales) => {
|
||||
this.setLocales(lang, locales)
|
||||
bus.$emit(FORCE_UPDATE)
|
||||
bus.emit(FORCE_UPDATE)
|
||||
})
|
||||
}
|
||||
|
||||
@ -38,7 +38,7 @@ export class I18nManager {
|
||||
this.getLanguageList()
|
||||
ipcRenderer.on(SET_CURRENT_LANGUAGE, (event, lang: string, locales: ILocales) => {
|
||||
this.setLocales(lang, locales)
|
||||
bus.$emit(FORCE_UPDATE)
|
||||
bus.emit(FORCE_UPDATE)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -1,37 +1,69 @@
|
||||
<template>
|
||||
<div id="main-page">
|
||||
<div class="fake-title-bar" :class="{ 'darwin': os === 'darwin' }">
|
||||
<div
|
||||
class="fake-title-bar"
|
||||
:class="{ 'darwin': os === 'darwin' }"
|
||||
>
|
||||
<div class="fake-title-bar__title">
|
||||
PicGo - {{ version }}
|
||||
</div>
|
||||
<div class="handle-bar" v-if="os !== 'darwin'">
|
||||
<i class="el-icon-minus" @click="minimizeWindow"></i>
|
||||
<i class="el-icon-circle-plus-outline" @click="openMiniWindow"></i>
|
||||
<i class="el-icon-close" @click="closeWindow"></i>
|
||||
<div
|
||||
v-if="os !== 'darwin'"
|
||||
class="handle-bar"
|
||||
>
|
||||
<el-icon
|
||||
class="minus"
|
||||
@click="minimizeWindow"
|
||||
>
|
||||
<Minus />
|
||||
</el-icon>
|
||||
<el-icon
|
||||
class="plus"
|
||||
@click="openMiniWindow"
|
||||
>
|
||||
<CirclePlus />
|
||||
</el-icon>
|
||||
<el-icon
|
||||
class="close"
|
||||
@click="closeWindow"
|
||||
>
|
||||
<Close />
|
||||
</el-icon>
|
||||
</div>
|
||||
</div>
|
||||
<el-row style="padding-top: 22px;" class="main-content">
|
||||
<el-col :span="5" class="side-bar-menu">
|
||||
<el-row
|
||||
style="padding-top: 22px;"
|
||||
class="main-content"
|
||||
>
|
||||
<el-col
|
||||
class="side-bar-menu"
|
||||
>
|
||||
<el-menu
|
||||
class="picgo-sidebar"
|
||||
:default-active="defaultActive"
|
||||
@select="handleSelect"
|
||||
:unique-opened="true"
|
||||
@select="handleSelect"
|
||||
@open="handleGetPicPeds"
|
||||
>
|
||||
<el-menu-item index="upload">
|
||||
<i class="el-icon-upload"></i>
|
||||
<span slot="title">{{ $T('UPLOAD_AREA') }}</span>
|
||||
>
|
||||
<el-menu-item :index="routerConfig.UPLOAD_PAGE">
|
||||
<el-icon>
|
||||
<UploadFilled />
|
||||
</el-icon>
|
||||
<span>{{ $T('UPLOAD_AREA') }}</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="gallery">
|
||||
<i class="el-icon-picture"></i>
|
||||
<span slot="title">{{ $T('GALLERY') }}</span>
|
||||
<el-menu-item :index="routerConfig.GALLERY_PAGE">
|
||||
<el-icon>
|
||||
<PictureFilled />
|
||||
</el-icon>
|
||||
<span>{{ $T('GALLERY') }}</span>
|
||||
</el-menu-item>
|
||||
<el-submenu
|
||||
<el-sub-menu
|
||||
index="sub-menu"
|
||||
>
|
||||
<template slot="title">
|
||||
<i class="el-icon-menu"></i>
|
||||
<template #title>
|
||||
<el-icon>
|
||||
<Menu />
|
||||
</el-icon>
|
||||
<span>{{ $T('PICBEDS_SETTINGS') }}</span>
|
||||
</template>
|
||||
<template
|
||||
@ -39,72 +71,97 @@
|
||||
>
|
||||
<el-menu-item
|
||||
v-if="item.visible"
|
||||
:index="`uploader-config-page-${item.type}`"
|
||||
:key="item.type"
|
||||
:index="`${routerConfig.UPLOADER_CONFIG_PAGE}-${item.type}`"
|
||||
>
|
||||
<!-- <i :class="`el-icon-ui-${item.type}`"></i> -->
|
||||
<span slot="title">{{ item.name }}</span>
|
||||
<span>{{ item.name }}</span>
|
||||
</el-menu-item>
|
||||
</template>
|
||||
</el-submenu>
|
||||
<el-menu-item index="setting">
|
||||
<i class="el-icon-setting"></i>
|
||||
<span slot="title">{{ $T('PICGO_SETTINGS') }}</span>
|
||||
</el-sub-menu>
|
||||
<el-menu-item :index="routerConfig.SETTING_PAGE">
|
||||
<el-icon>
|
||||
<Setting />
|
||||
</el-icon>
|
||||
<span>{{ $T('PICGO_SETTINGS') }}</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="plugin">
|
||||
<i class="el-icon-share"></i>
|
||||
<span slot="title">{{ $T('PLUGIN_SETTINGS') }}</span>
|
||||
<el-menu-item :index="routerConfig.PLUGIN_PAGE">
|
||||
<el-icon>
|
||||
<Share />
|
||||
</el-icon>
|
||||
<span>{{ $T('PLUGIN_SETTINGS') }}</span>
|
||||
</el-menu-item>
|
||||
</el-menu>
|
||||
<i class="el-icon-info setting-window" @click="openDialog"></i>
|
||||
<el-icon
|
||||
class="info-window"
|
||||
@click="openMenu"
|
||||
>
|
||||
<InfoFilled />
|
||||
</el-icon>
|
||||
</el-col>
|
||||
<el-col
|
||||
:span="19"
|
||||
:offset="5"
|
||||
style="height: 428px"
|
||||
class="main-wrapper"
|
||||
:class="{ 'darwin': os === 'darwin' }">
|
||||
<transition name="picgo-fade" mode="out-in">
|
||||
<keep-alive>
|
||||
<router-view v-if="$route && $route.meta && $route.meta.keepAlive"></router-view>
|
||||
</keep-alive>
|
||||
</transition>
|
||||
<transition name="picgo-fade" mode="out-in">
|
||||
<router-view :key="$route.path" v-if="!($route && $route.meta && $route.meta.keepAlive)"></router-view>
|
||||
</transition>
|
||||
:class="{ 'darwin': os === 'darwin' }"
|
||||
>
|
||||
<router-view
|
||||
v-slot="{ Component }"
|
||||
>
|
||||
<transition
|
||||
name="picgo-fade"
|
||||
mode="out-in"
|
||||
>
|
||||
<keep-alive :include="keepAlivePages">
|
||||
<component
|
||||
:is="Component"
|
||||
/>
|
||||
</keep-alive>
|
||||
</transition>
|
||||
</router-view>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-dialog
|
||||
v-model="visible"
|
||||
:title="$T('SPONSOR_PICGO')"
|
||||
:visible.sync="visible"
|
||||
width="70%"
|
||||
top="10vh"
|
||||
>
|
||||
{{ $T('PICGO_SPONSOR_TEXT') }}
|
||||
<el-row class="support">
|
||||
<el-col :span="12">
|
||||
<img src="https://user-images.githubusercontent.com/12621342/34188165-e7cdf372-e56f-11e7-8732-1338c88b9bb7.jpg" :alt="$T('ALIPAY')">
|
||||
<div class="support-title">{{ $T('ALIPAY') }}</div>
|
||||
<img
|
||||
src="https://user-images.githubusercontent.com/12621342/34188165-e7cdf372-e56f-11e7-8732-1338c88b9bb7.jpg"
|
||||
:alt="$T('ALIPAY')"
|
||||
>
|
||||
<div class="support-title">
|
||||
{{ $T('ALIPAY') }}
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<img src="https://user-images.githubusercontent.com/12621342/34188201-212cda84-e570-11e7-9b7a-abb298699d85.jpg" :alt="$T('WECHATPAY')">
|
||||
<div class="support-title">{{ $T('WECHATPAY') }}</div>
|
||||
<img
|
||||
src="https://user-images.githubusercontent.com/12621342/34188201-212cda84-e570-11e7-9b7a-abb298699d85.jpg"
|
||||
:alt="$T('WECHATPAY')"
|
||||
>
|
||||
<div class="support-title">
|
||||
{{ $T('WECHATPAY') }}
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-dialog>
|
||||
<el-dialog
|
||||
v-model="qrcodeVisible"
|
||||
class="qrcode-dialog"
|
||||
top="3vh"
|
||||
width="60%"
|
||||
:title="$T('PICBED_QRCODE')"
|
||||
:visible.sync="qrcodeVisible"
|
||||
:modal-append-to-body="false"
|
||||
lock-scroll
|
||||
>
|
||||
<el-form
|
||||
label-position="left"
|
||||
label-width="70px"
|
||||
size="mini"
|
||||
size="small"
|
||||
>
|
||||
<el-form-item
|
||||
:label="$T('CHOOSE_PICBED')"
|
||||
@ -119,7 +176,7 @@
|
||||
:key="item.type"
|
||||
:label="item.name"
|
||||
:value="item.type"
|
||||
></el-option>
|
||||
/>
|
||||
</el-select>
|
||||
<el-button
|
||||
v-show="choosedPicBedForQRCode.length > 0"
|
||||
@ -143,17 +200,32 @@
|
||||
<input-box-dialog />
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { Component, Vue, Watch } from 'vue-property-decorator'
|
||||
<script lang="ts" setup>
|
||||
// import { Component, Vue, Watch } from 'vue-property-decorator'
|
||||
import {
|
||||
Setting,
|
||||
UploadFilled,
|
||||
PictureFilled,
|
||||
Menu,
|
||||
Share,
|
||||
InfoFilled,
|
||||
Minus,
|
||||
CirclePlus,
|
||||
Close
|
||||
} from '@element-plus/icons-vue'
|
||||
import { ElMessage as $message } from 'element-plus'
|
||||
import { T } from '@/i18n/index'
|
||||
import { ref, onBeforeUnmount, Ref, onBeforeMount, watch, nextTick, reactive } from 'vue'
|
||||
import { onBeforeRouteUpdate, useRouter } from 'vue-router'
|
||||
import QrcodeVue from 'qrcode.vue'
|
||||
import pick from 'lodash/pick'
|
||||
import pkg from 'root/package.json'
|
||||
import * as config from '@/router/config'
|
||||
import {
|
||||
ipcRenderer,
|
||||
IpcRendererEvent,
|
||||
clipboard
|
||||
} from 'electron'
|
||||
import mixin from '@/utils/mixin'
|
||||
import InputBoxDialog from '@/components/InputBoxDialog.vue'
|
||||
import {
|
||||
MINIMIZE_WINDOW,
|
||||
@ -163,116 +235,118 @@ import {
|
||||
SHOW_MAIN_PAGE_DONATION,
|
||||
GET_PICBEDS
|
||||
} from '~/universal/events/constants'
|
||||
@Component({
|
||||
name: 'main-page',
|
||||
mixins: [mixin],
|
||||
components: {
|
||||
InputBoxDialog,
|
||||
QrcodeVue
|
||||
import { getConfig, sendToMain } from '@/utils/dataSender'
|
||||
const version = ref(process.env.NODE_ENV === 'production' ? pkg.version : 'Dev')
|
||||
const routerConfig = reactive(config)
|
||||
const defaultActive = ref(routerConfig.UPLOAD_PAGE)
|
||||
const visible = ref(false)
|
||||
const os = ref('')
|
||||
const $router = useRouter()
|
||||
const picBed: Ref<IPicBedType[]> = ref([])
|
||||
const qrcodeVisible = ref(false)
|
||||
const picBedConfigString = ref('')
|
||||
const choosedPicBedForQRCode: Ref<string[]> = ref([])
|
||||
|
||||
const keepAlivePages = $router.getRoutes().filter(item => item.meta.keepAlive).map(item => item.name as string)
|
||||
|
||||
onBeforeMount(() => {
|
||||
os.value = process.platform
|
||||
sendToMain(GET_PICBEDS)
|
||||
ipcRenderer.on(GET_PICBEDS, getPicBeds)
|
||||
handleGetPicPeds()
|
||||
ipcRenderer.on(SHOW_MAIN_PAGE_QRCODE, () => {
|
||||
qrcodeVisible.value = true
|
||||
})
|
||||
ipcRenderer.on(SHOW_MAIN_PAGE_DONATION, () => {
|
||||
visible.value = true
|
||||
})
|
||||
})
|
||||
|
||||
watch(() => choosedPicBedForQRCode, (val) => {
|
||||
if (val.value.length > 0) {
|
||||
nextTick(async () => {
|
||||
const picBedConfig = await getConfig('picBed')
|
||||
const config = pick(picBedConfig, ...choosedPicBedForQRCode.value)
|
||||
picBedConfigString.value = JSON.stringify(config)
|
||||
})
|
||||
}
|
||||
}, { deep: true })
|
||||
|
||||
const handleGetPicPeds = () => {
|
||||
sendToMain(GET_PICBEDS)
|
||||
}
|
||||
|
||||
const handleSelect = (index: string) => {
|
||||
defaultActive.value = index
|
||||
const type = index.match(routerConfig.UPLOADER_CONFIG_PAGE)
|
||||
if (type === null) {
|
||||
$router.push({
|
||||
name: index
|
||||
})
|
||||
} else {
|
||||
const type = index.replace(`${routerConfig.UPLOADER_CONFIG_PAGE}-`, '')
|
||||
$router.push({
|
||||
name: routerConfig.UPLOADER_CONFIG_PAGE,
|
||||
params: {
|
||||
type
|
||||
}
|
||||
})
|
||||
// if (this.$builtInPicBed.includes(picBed)) {
|
||||
// this.$router.push({
|
||||
// name: picBed
|
||||
// })
|
||||
// } else {
|
||||
// this.$router.push({
|
||||
// name: 'others',
|
||||
// params: {
|
||||
// type: picBed
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
function minimizeWindow () {
|
||||
sendToMain(MINIMIZE_WINDOW)
|
||||
}
|
||||
|
||||
function closeWindow () {
|
||||
sendToMain(CLOSE_WINDOW)
|
||||
}
|
||||
|
||||
function openMenu () {
|
||||
sendToMain(SHOW_MAIN_PAGE_MENU)
|
||||
}
|
||||
|
||||
function openMiniWindow () {
|
||||
sendToMain('openMiniWindow')
|
||||
}
|
||||
|
||||
function handleCopyPicBedConfig () {
|
||||
clipboard.writeText(picBedConfigString.value)
|
||||
$message.success(T('COPY_PICBED_CONFIG_SUCCEED'))
|
||||
}
|
||||
|
||||
function getPicBeds (event: IpcRendererEvent, picBeds: IPicBedType[]) {
|
||||
picBed.value = picBeds
|
||||
}
|
||||
|
||||
onBeforeRouteUpdate(async (to) => {
|
||||
if (to.params.type) {
|
||||
defaultActive.value = `${routerConfig.UPLOADER_CONFIG_PAGE}-${to.params.type}`
|
||||
} else {
|
||||
defaultActive.value = to.name as string
|
||||
}
|
||||
})
|
||||
export default class extends Vue {
|
||||
version = process.env.NODE_ENV === 'production' ? pkg.version : 'Dev'
|
||||
defaultActive = 'upload'
|
||||
visible = false
|
||||
keyBindingVisible = false
|
||||
customLinkVisible = false
|
||||
os = ''
|
||||
picBed: IPicBedType[] = []
|
||||
qrcodeVisible = false
|
||||
picBedConfigString = ''
|
||||
choosedPicBedForQRCode: string[] = []
|
||||
created () {
|
||||
this.os = process.platform
|
||||
ipcRenderer.send(GET_PICBEDS)
|
||||
ipcRenderer.on(GET_PICBEDS, this.getPicBeds)
|
||||
this.handleGetPicPeds()
|
||||
ipcRenderer.on(SHOW_MAIN_PAGE_QRCODE, () => {
|
||||
this.qrcodeVisible = true
|
||||
})
|
||||
ipcRenderer.on(SHOW_MAIN_PAGE_DONATION, () => {
|
||||
this.visible = true
|
||||
})
|
||||
}
|
||||
|
||||
@Watch('choosedPicBedForQRCode')
|
||||
choosedPicBedForQRCodeChange (val: string[]) {
|
||||
if (val.length > 0) {
|
||||
this.$nextTick(async () => {
|
||||
const picBedConfig = await this.getConfig('picBed')
|
||||
const config = pick(picBedConfig, ...this.choosedPicBedForQRCode)
|
||||
this.picBedConfigString = JSON.stringify(config)
|
||||
})
|
||||
}
|
||||
}
|
||||
onBeforeUnmount(() => {
|
||||
ipcRenderer.removeListener(GET_PICBEDS, getPicBeds)
|
||||
})
|
||||
|
||||
handleGetPicPeds = () => {
|
||||
ipcRenderer.send(GET_PICBEDS)
|
||||
}
|
||||
|
||||
handleSelect (index: string) {
|
||||
const type = index.match(/uploader-config-page-/)
|
||||
if (type === null) {
|
||||
this.$router.push({
|
||||
name: index
|
||||
})
|
||||
} else {
|
||||
const type = index.replace(/uploader-config-page-/, '')
|
||||
this.$router.push({
|
||||
name: 'UploaderConfigPage',
|
||||
params: {
|
||||
type
|
||||
}
|
||||
})
|
||||
// if (this.$builtInPicBed.includes(picBed)) {
|
||||
// this.$router.push({
|
||||
// name: picBed
|
||||
// })
|
||||
// } else {
|
||||
// this.$router.push({
|
||||
// name: 'others',
|
||||
// params: {
|
||||
// type: picBed
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
minimizeWindow () {
|
||||
ipcRenderer.send(MINIMIZE_WINDOW)
|
||||
}
|
||||
|
||||
closeWindow () {
|
||||
ipcRenderer.send(CLOSE_WINDOW)
|
||||
}
|
||||
|
||||
openDialog () {
|
||||
ipcRenderer.send(SHOW_MAIN_PAGE_MENU)
|
||||
}
|
||||
|
||||
openMiniWindow () {
|
||||
ipcRenderer.send('openMiniWindow')
|
||||
}
|
||||
|
||||
handleCopyPicBedConfig () {
|
||||
clipboard.writeText(this.picBedConfigString)
|
||||
this.$message.success(this.$T('COPY_PICBED_CONFIG_SUCCEED'))
|
||||
}
|
||||
|
||||
getPicBeds (event: IpcRendererEvent, picBeds: IPicBedType[]) {
|
||||
this.picBed = picBeds
|
||||
}
|
||||
|
||||
beforeRouteEnter (to: any, next: any) {
|
||||
next((vm: this) => {
|
||||
vm.defaultActive = to.name
|
||||
})
|
||||
}
|
||||
|
||||
beforeDestroy () {
|
||||
ipcRenderer.removeListener(GET_PICBEDS, this.getPicBeds)
|
||||
}
|
||||
</script>
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'MainPage'
|
||||
}
|
||||
</script>
|
||||
<style lang='stylus'>
|
||||
@ -289,7 +363,7 @@ $darwinBg = transparentify(#172426, #000, 0.7)
|
||||
opacity 0
|
||||
&-enter-active,
|
||||
&-leave-active
|
||||
transition all 100ms linear
|
||||
transition all 150ms linear
|
||||
.view-title
|
||||
color #eee
|
||||
font-size 20px
|
||||
@ -304,8 +378,6 @@ $darwinBg = transparentify(#172426, #000, 0.7)
|
||||
padding-top 10px
|
||||
.copy-picbed-config
|
||||
margin-left 10px
|
||||
.el-input__inner
|
||||
border-radius 14px
|
||||
.fake-title-bar
|
||||
-webkit-app-region drag
|
||||
height h = 22px
|
||||
@ -333,17 +405,17 @@ $darwinBg = transparentify(#172426, #000, 0.7)
|
||||
right 4px
|
||||
z-index 10000
|
||||
-webkit-app-region no-drag
|
||||
i
|
||||
.el-icon
|
||||
cursor pointer
|
||||
font-size 16px
|
||||
margin-left 5px
|
||||
.el-icon-minus
|
||||
.el-icon.minus
|
||||
&:hover
|
||||
color #409EFF
|
||||
.el-icon-close
|
||||
.el-icon.close
|
||||
&:hover
|
||||
color #F15140
|
||||
.el-icon-circle-plus-outline
|
||||
.el-icon.plus
|
||||
&:hover
|
||||
color #69C282
|
||||
.main-wrapper
|
||||
@ -355,7 +427,8 @@ $darwinBg = transparentify(#172426, #000, 0.7)
|
||||
overflow-x hidden
|
||||
overflow-y auto
|
||||
width 170px
|
||||
.el-icon-info.setting-window
|
||||
.info-window
|
||||
cursor pointer
|
||||
position fixed
|
||||
bottom 4px
|
||||
left 4px
|
||||
@ -385,14 +458,13 @@ $darwinBg = transparentify(#172426, #000, 0.7)
|
||||
right 0
|
||||
top 18px
|
||||
background active-color
|
||||
.el-submenu__title
|
||||
span
|
||||
color #eee
|
||||
.el-sub-menu__title
|
||||
color #eee
|
||||
&:hover
|
||||
background transparent
|
||||
span
|
||||
color #fff
|
||||
.el-submenu
|
||||
.el-sub-menu
|
||||
.el-menu-item
|
||||
min-width 166px
|
||||
&.is-active
|
||||
|
@ -1,65 +1,105 @@
|
||||
<template>
|
||||
<div id="gallery-view">
|
||||
<div class="view-title">
|
||||
{{ $T('GALLERY') }} - {{ filterList.length }} <i class="el-icon-caret-bottom" @click="toggleHandleBar" :class="{'active': handleBarActive}"></i>
|
||||
{{ $T('GALLERY') }} - {{ filterList.length }}
|
||||
<el-icon
|
||||
style="margin-left: 4px"
|
||||
class="cursor-pointer"
|
||||
@click="toggleHandleBar"
|
||||
>
|
||||
<CaretBottom v-show="!handleBarActive" />
|
||||
<CaretTop v-show="handleBarActive" />
|
||||
</el-icon>
|
||||
</div>
|
||||
<transition name="el-zoom-in-top">
|
||||
<el-row v-show="handleBarActive">
|
||||
<el-col :span="20" :offset="2">
|
||||
<el-row class="handle-bar" :gutter="16">
|
||||
<el-col
|
||||
:span="20"
|
||||
:offset="2"
|
||||
>
|
||||
<el-row
|
||||
class="handle-bar"
|
||||
:gutter="16"
|
||||
>
|
||||
<el-col :span="12">
|
||||
<el-select
|
||||
v-model="choosedPicBed"
|
||||
multiple
|
||||
collapse-tags
|
||||
size="mini"
|
||||
size="small"
|
||||
style="width: 100%"
|
||||
:placeholder="$T('CHOOSE_SHOWED_PICBED')">
|
||||
:placeholder="$T('CHOOSE_SHOWED_PICBED')"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in picBed"
|
||||
:key="item.type"
|
||||
:label="item.name"
|
||||
:value="item.type">
|
||||
</el-option>
|
||||
:value="item.type"
|
||||
/>
|
||||
</el-select>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-select
|
||||
v-model="pasteStyle"
|
||||
size="mini"
|
||||
size="small"
|
||||
style="width: 100%"
|
||||
:placeholder="$T('CHOOSE_PASTE_FORMAT')"
|
||||
@change="handlePasteStyleChange"
|
||||
:placeholder="$T('CHOOSE_PASTE_FORMAT')">
|
||||
>
|
||||
<el-option
|
||||
v-for="(value, key) in pasteStyleMap"
|
||||
:key="key"
|
||||
:label="key"
|
||||
:value="value">
|
||||
</el-option>
|
||||
:value="value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row class="handle-bar" :gutter="16">
|
||||
<el-row
|
||||
class="handle-bar"
|
||||
:gutter="16"
|
||||
>
|
||||
<el-col :span="12">
|
||||
<el-input
|
||||
v-model="searchText"
|
||||
:placeholder="$T('SEARCH')"
|
||||
size="mini"
|
||||
v-model="searchText">
|
||||
<i slot="suffix" class="el-input__icon el-icon-close" v-if="searchText" @click="cleanSearch" style="cursor: pointer"></i>
|
||||
size="small"
|
||||
>
|
||||
<template #suffix>
|
||||
<el-icon
|
||||
class="el-input__icon"
|
||||
style="cursor: pointer;"
|
||||
@click="cleanSearch"
|
||||
>
|
||||
<close />
|
||||
</el-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<div class="item-base copy round" :class="{ active: isMultiple(choosedList)}" @click="multiCopy">
|
||||
<div
|
||||
class="item-base copy round"
|
||||
:class="{ active: isMultiple(choosedList)}"
|
||||
@click="multiCopy"
|
||||
>
|
||||
{{ $T('COPY') }}
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<div class="item-base delete round" :class="{ active: isMultiple(choosedList)}" @click="multiRemove">
|
||||
<div
|
||||
class="item-base delete round"
|
||||
:class="{ active: isMultiple(choosedList)}"
|
||||
@click="multiRemove"
|
||||
>
|
||||
{{ $T('DELETE') }}
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<div class="item-base all-pick round" :class="{ active: filterList.length > 0}" @click="toggleSelectAll">
|
||||
<div
|
||||
class="item-base all-pick round"
|
||||
:class="{ active: filterList.length > 0}"
|
||||
@click="toggleSelectAll"
|
||||
>
|
||||
{{ isAllSelected ? $T('CANCEL') : $T('SELECT_ALL') }}
|
||||
</div>
|
||||
</el-col>
|
||||
@ -67,398 +107,470 @@
|
||||
</el-col>
|
||||
</el-row>
|
||||
</transition>
|
||||
<el-row class="gallery-list" :class="{ small: handleBarActive }">
|
||||
<el-col :span="20" :offset="2">
|
||||
<el-row
|
||||
class="gallery-list"
|
||||
:class="{ small: handleBarActive }"
|
||||
>
|
||||
<el-col
|
||||
:span="20"
|
||||
:offset="2"
|
||||
>
|
||||
<el-row :gutter="16">
|
||||
<gallerys
|
||||
:images="filterList"
|
||||
:index="idx"
|
||||
@close="handleClose"
|
||||
:options="options"
|
||||
></gallerys>
|
||||
<el-col :span="6" v-for="(item, index) in filterList" :key="item.id" class="gallery-list__img">
|
||||
<photo-slider
|
||||
:items="filterList"
|
||||
:visible="gallerySliderControl.visible"
|
||||
:index="gallerySliderControl.index"
|
||||
:should-transition="true"
|
||||
@change-index="zoomImage"
|
||||
@click-mask="handleClose"
|
||||
@close-modal="handleClose"
|
||||
/>
|
||||
<el-col
|
||||
v-for="(item, index) in filterList"
|
||||
:key="item.id"
|
||||
:span="6"
|
||||
class="gallery-list__img"
|
||||
>
|
||||
<div
|
||||
class="gallery-list__item"
|
||||
@click="zoomImage(index)"
|
||||
>
|
||||
<img v-lazy="item.imgUrl" class="gallery-list__item-img">
|
||||
<img
|
||||
v-lazy="item.imgUrl"
|
||||
class="gallery-list__item-img"
|
||||
>
|
||||
</div>
|
||||
<div class="gallery-list__file-name" :title="item.fileName">
|
||||
<div
|
||||
class="gallery-list__file-name"
|
||||
:title="item.fileName"
|
||||
>
|
||||
{{ item.fileName }}
|
||||
</div>
|
||||
<div class="gallery-list__tool-panel">
|
||||
<i class="el-icon-document" @click="copy(item)"></i>
|
||||
<i class="el-icon-edit-outline" @click="openDialog(item)"></i>
|
||||
<i class="el-icon-delete" @click="remove(item.id)"></i>
|
||||
<el-checkbox v-model="choosedList[item.id ? item.id : '']" class="pull-right" @change="(val) => handleChooseImage(val, index)"></el-checkbox>
|
||||
</div>
|
||||
<el-row
|
||||
class="gallery-list__tool-panel"
|
||||
justify="space-between"
|
||||
align="middle"
|
||||
>
|
||||
<el-row>
|
||||
<el-icon
|
||||
class="cursor-pointer document"
|
||||
@click="copy(item)"
|
||||
>
|
||||
<Document />
|
||||
</el-icon>
|
||||
<el-icon
|
||||
class="cursor-pointer edit"
|
||||
@click="openDialog(item)"
|
||||
>
|
||||
<Edit />
|
||||
</el-icon>
|
||||
<el-icon
|
||||
class="cursor-pointer delete"
|
||||
@click="remove(item.id)"
|
||||
>
|
||||
<Delete />
|
||||
</el-icon>
|
||||
</el-row>
|
||||
<el-checkbox
|
||||
v-model="choosedList[item.id ? item.id : '']"
|
||||
@change="(val) => handleChooseImage(val, index)"
|
||||
/>
|
||||
</el-row>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-dialog
|
||||
:visible.sync="dialogVisible"
|
||||
v-model="dialogVisible"
|
||||
:title="$T('CHANGE_IMAGE_URL')"
|
||||
width="500px"
|
||||
:modal-append-to-body="false"
|
||||
>
|
||||
<el-input v-model="imgInfo.imgUrl"></el-input>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="dialogVisible = false">{{ $T('CANCEL') }}</el-button>
|
||||
<el-button type="primary" @click="confirmModify">{{ $T('CONFIRM') }}</el-button>
|
||||
</span>
|
||||
<el-input v-model="imgInfo.imgUrl" />
|
||||
<template
|
||||
#footer
|
||||
>
|
||||
<el-button @click="dialogVisible = false">
|
||||
{{ $T('CANCEL') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="confirmModify"
|
||||
>
|
||||
{{ $T('CONFIRM') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
// @ts-ignore
|
||||
import gallerys from 'vue-gallery'
|
||||
import { Component, Vue, Watch } from 'vue-property-decorator'
|
||||
import { IResult } from '@picgo/store/dist/types'
|
||||
<script lang="ts" setup>
|
||||
import type { IResult } from '@picgo/store/dist/types'
|
||||
import { PASTE_TEXT, GET_PICBEDS } from '#/events/constants'
|
||||
import { CheckboxValueType, ElMessageBox } from 'element-plus'
|
||||
import { Close, CaretBottom, Document, Edit, Delete, CaretTop } from '@element-plus/icons-vue'
|
||||
import {
|
||||
ipcRenderer,
|
||||
clipboard,
|
||||
IpcRendererEvent
|
||||
} from 'electron'
|
||||
@Component({
|
||||
name: 'gallery',
|
||||
components: {
|
||||
gallerys
|
||||
import { computed, nextTick, onActivated, onBeforeUnmount, onBeforeMount, reactive, ref, watch } from 'vue'
|
||||
import { getConfig, saveConfig, sendToMain } from '@/utils/dataSender'
|
||||
import { onBeforeRouteUpdate } from 'vue-router'
|
||||
import { T as $T } from '@/i18n/index'
|
||||
import $$db from '@/utils/db'
|
||||
const images = ref<ImgInfo[]>([])
|
||||
const dialogVisible = ref(false)
|
||||
const imgInfo = reactive({
|
||||
id: '',
|
||||
imgUrl: ''
|
||||
})
|
||||
const $confirm = ElMessageBox.confirm
|
||||
const choosedList: IObjT<boolean> = reactive({})
|
||||
const gallerySliderControl = reactive({
|
||||
visible: false,
|
||||
index: 0
|
||||
})
|
||||
const choosedPicBed = ref<string[]>([])
|
||||
const lastChoosed = ref<number>(-1)
|
||||
const isShiftKeyPress = ref<boolean>(false)
|
||||
const searchText = ref<string>('')
|
||||
const handleBarActive = ref<boolean>(false)
|
||||
const pasteStyle = ref<string>('')
|
||||
const pasteStyleMap = {
|
||||
Markdown: 'markdown',
|
||||
HTML: 'HTML',
|
||||
URL: 'URL',
|
||||
UBB: 'UBB',
|
||||
Custom: 'Custom'
|
||||
}
|
||||
const picBed = ref<IPicBedType[]>([])
|
||||
onBeforeRouteUpdate((to, from) => {
|
||||
if (from.name === 'gallery') {
|
||||
clearChoosedList()
|
||||
}
|
||||
if (to.name === 'gallery') {
|
||||
updateGallery()
|
||||
}
|
||||
})
|
||||
export default class extends Vue {
|
||||
images: ImgInfo[] = []
|
||||
idx: null | number = null
|
||||
options = {
|
||||
titleProperty: 'fileName',
|
||||
urlProperty: 'imgUrl',
|
||||
closeOnSlideClick: true
|
||||
}
|
||||
|
||||
dialogVisible = false
|
||||
imgInfo = {
|
||||
id: '',
|
||||
imgUrl: ''
|
||||
}
|
||||
|
||||
choosedList: IObjT<boolean> = {}
|
||||
choosedPicBed: string[] = []
|
||||
lastChoosed: number = -1
|
||||
isShiftKeyPress: boolean = false
|
||||
searchText = ''
|
||||
handleBarActive = false
|
||||
pasteStyle = ''
|
||||
pasteStyleMap = {
|
||||
Markdown: 'markdown',
|
||||
HTML: 'HTML',
|
||||
URL: 'URL',
|
||||
UBB: 'UBB',
|
||||
Custom: 'Custom'
|
||||
}
|
||||
|
||||
picBed: IPicBedType[] = []
|
||||
@Watch('$route')
|
||||
handleRouteUpdate (to: any, from: any) {
|
||||
if (from.name === 'gallery') {
|
||||
this.clearChoosedList()
|
||||
}
|
||||
if (to.name === 'gallery') {
|
||||
this.updateGallery()
|
||||
}
|
||||
}
|
||||
|
||||
async created () {
|
||||
ipcRenderer.on('updateGallery', () => {
|
||||
this.$nextTick(async () => {
|
||||
this.updateGallery()
|
||||
})
|
||||
onBeforeMount(async () => {
|
||||
ipcRenderer.on('updateGallery', () => {
|
||||
nextTick(async () => {
|
||||
updateGallery()
|
||||
})
|
||||
ipcRenderer.send(GET_PICBEDS)
|
||||
ipcRenderer.on(GET_PICBEDS, this.getPicBeds)
|
||||
this.updateGallery()
|
||||
}
|
||||
})
|
||||
sendToMain(GET_PICBEDS)
|
||||
ipcRenderer.on(GET_PICBEDS, getPicBeds)
|
||||
updateGallery()
|
||||
|
||||
mounted () {
|
||||
document.addEventListener('keydown', this.handleDetectShiftKey)
|
||||
document.addEventListener('keyup', this.handleDetectShiftKey)
|
||||
}
|
||||
document.addEventListener('keydown', handleDetectShiftKey)
|
||||
document.addEventListener('keyup', handleDetectShiftKey)
|
||||
})
|
||||
|
||||
handleDetectShiftKey (event: KeyboardEvent) {
|
||||
if (event.key === 'Shift') {
|
||||
if (event.type === 'keydown') {
|
||||
this.isShiftKeyPress = true
|
||||
} else if (event.type === 'keyup') {
|
||||
this.isShiftKeyPress = false
|
||||
function handleDetectShiftKey (event: KeyboardEvent) {
|
||||
if (event.key === 'Shift') {
|
||||
if (event.type === 'keydown') {
|
||||
isShiftKeyPress.value = true
|
||||
} else if (event.type === 'keyup') {
|
||||
isShiftKeyPress.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const filterList = computed(() => {
|
||||
return getGallery()
|
||||
})
|
||||
|
||||
const isAllSelected = computed(() => {
|
||||
const values = Object.values(choosedList)
|
||||
if (values.length === 0) {
|
||||
return false
|
||||
} else {
|
||||
return filterList.value.every(item => {
|
||||
return choosedList[item.id!]
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
function getPicBeds (event: IpcRendererEvent, picBeds: IPicBedType[]) {
|
||||
picBed.value = picBeds
|
||||
}
|
||||
|
||||
function getGallery (): IGalleryItem[] {
|
||||
if (searchText.value || choosedPicBed.value.length > 0) {
|
||||
return images.value
|
||||
.filter(item => {
|
||||
let isInChoosedPicBed = true
|
||||
let isIncludesSearchText = true
|
||||
if (choosedPicBed.value.length > 0) {
|
||||
isInChoosedPicBed = choosedPicBed.value.some(type => type === item.type)
|
||||
}
|
||||
if (searchText.value) {
|
||||
isIncludesSearchText = item.fileName?.includes(searchText.value) || false
|
||||
}
|
||||
return isIncludesSearchText && isInChoosedPicBed
|
||||
}).map(item => {
|
||||
return {
|
||||
...item,
|
||||
src: item.imgUrl || '',
|
||||
key: (item.id || `${Date.now()}`),
|
||||
intro: item.fileName || ''
|
||||
}
|
||||
})
|
||||
} else {
|
||||
return images.value.map(item => {
|
||||
return {
|
||||
...item,
|
||||
src: item.imgUrl || '',
|
||||
key: (item.id || `${Date.now()}`),
|
||||
intro: item.fileName || ''
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
async function updateGallery () {
|
||||
images.value = (await $$db.get({ orderBy: 'desc' })).data
|
||||
}
|
||||
|
||||
watch(() => filterList, () => {
|
||||
clearChoosedList()
|
||||
})
|
||||
|
||||
function handleChooseImage (val: CheckboxValueType, index: number) {
|
||||
if (val === true) {
|
||||
handleBarActive.value = true
|
||||
if (lastChoosed.value !== -1 && isShiftKeyPress.value) {
|
||||
const min = Math.min(lastChoosed.value, index)
|
||||
const max = Math.max(lastChoosed.value, index)
|
||||
for (let i = min + 1; i < max; i++) {
|
||||
const id = filterList.value[i].id!
|
||||
choosedList[id] = true
|
||||
}
|
||||
}
|
||||
lastChoosed.value = index
|
||||
}
|
||||
}
|
||||
|
||||
get filterList () {
|
||||
return this.getGallery()
|
||||
function clearChoosedList () {
|
||||
isShiftKeyPress.value = false
|
||||
Object.keys(choosedList).forEach(key => {
|
||||
choosedList[key] = false
|
||||
})
|
||||
lastChoosed.value = -1
|
||||
}
|
||||
|
||||
function zoomImage (index: number) {
|
||||
gallerySliderControl.index = index
|
||||
gallerySliderControl.visible = true
|
||||
changeZIndexForGallery(true)
|
||||
}
|
||||
|
||||
function changeZIndexForGallery (isOpen: boolean) {
|
||||
if (isOpen) {
|
||||
// @ts-ignore
|
||||
document.querySelector('.main-content.el-row').style.zIndex = 101
|
||||
} else {
|
||||
// @ts-ignore
|
||||
document.querySelector('.main-content.el-row').style.zIndex = 10
|
||||
}
|
||||
}
|
||||
|
||||
get isAllSelected () {
|
||||
const values = Object.values(this.choosedList)
|
||||
if (values.length === 0) {
|
||||
return false
|
||||
} else {
|
||||
return this.filterList.every(item => {
|
||||
return this.choosedList[item.id!]
|
||||
})
|
||||
}
|
||||
function handleClose () {
|
||||
gallerySliderControl.index = 0
|
||||
gallerySliderControl.visible = false
|
||||
changeZIndexForGallery(false)
|
||||
}
|
||||
|
||||
async function copy (item: ImgInfo) {
|
||||
const copyLink = await ipcRenderer.invoke(PASTE_TEXT, item)
|
||||
const obj = {
|
||||
title: $T('COPY_LINK_SUCCEED'),
|
||||
body: copyLink
|
||||
// sometimes will cause lagging
|
||||
// icon: item.url || item.imgUrl
|
||||
}
|
||||
|
||||
getPicBeds (event: IpcRendererEvent, picBeds: IPicBedType[]) {
|
||||
this.picBed = picBeds
|
||||
const myNotification = new Notification(obj.title, obj)
|
||||
myNotification.onclick = () => {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
getGallery (): ImgInfo[] {
|
||||
if (this.searchText || this.choosedPicBed.length > 0) {
|
||||
return this.images
|
||||
.filter(item => {
|
||||
let isInChoosedPicBed = true
|
||||
let isIncludesSearchText = true
|
||||
if (this.choosedPicBed.length > 0) {
|
||||
isInChoosedPicBed = this.choosedPicBed.some(type => type === item.type)
|
||||
}
|
||||
if (this.searchText) {
|
||||
isIncludesSearchText = item.fileName?.includes(this.searchText) || false
|
||||
}
|
||||
return isIncludesSearchText && isInChoosedPicBed
|
||||
})
|
||||
} else {
|
||||
return this.images
|
||||
}
|
||||
}
|
||||
|
||||
async updateGallery () {
|
||||
this.images = (await this.$$db.get({ orderBy: 'desc' })).data
|
||||
}
|
||||
|
||||
@Watch('filterList')
|
||||
handleFilterListChange () {
|
||||
this.clearChoosedList()
|
||||
}
|
||||
|
||||
handleChooseImage (val: boolean, index: number) {
|
||||
if (val === true) {
|
||||
this.handleBarActive = true
|
||||
if (this.lastChoosed !== -1 && this.isShiftKeyPress) {
|
||||
const min = Math.min(this.lastChoosed, index)
|
||||
const max = Math.max(this.lastChoosed, index)
|
||||
for (let i = min + 1; i < max; i++) {
|
||||
const id = this.filterList[i].id!
|
||||
this.$set(this.choosedList, id, true)
|
||||
}
|
||||
}
|
||||
this.lastChoosed = index
|
||||
}
|
||||
}
|
||||
|
||||
clearChoosedList () {
|
||||
this.isShiftKeyPress = false
|
||||
Object.keys(this.choosedList).forEach(key => {
|
||||
this.choosedList[key] = false
|
||||
})
|
||||
this.lastChoosed = -1
|
||||
}
|
||||
|
||||
zoomImage (index: number) {
|
||||
this.idx = index
|
||||
this.changeZIndexForGallery(true)
|
||||
}
|
||||
|
||||
changeZIndexForGallery (isOpen: boolean) {
|
||||
if (isOpen) {
|
||||
// @ts-ignore
|
||||
document.querySelector('.main-content.el-row').style.zIndex = 101
|
||||
} else {
|
||||
// @ts-ignore
|
||||
document.querySelector('.main-content.el-row').style.zIndex = 10
|
||||
}
|
||||
}
|
||||
|
||||
handleClose () {
|
||||
this.idx = null
|
||||
this.changeZIndexForGallery(false)
|
||||
}
|
||||
|
||||
async copy (item: ImgInfo) {
|
||||
const copyLink = await ipcRenderer.invoke(PASTE_TEXT, item)
|
||||
const obj = {
|
||||
title: this.$T('COPY_LINK_SUCCEED'),
|
||||
body: copyLink
|
||||
// sometimes will cause lagging
|
||||
// icon: item.url || item.imgUrl
|
||||
}
|
||||
const myNotification = new Notification(obj.title, obj)
|
||||
myNotification.onclick = () => {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
remove (id?: string) {
|
||||
if (id) {
|
||||
this.$confirm(this.$T('TIPS_REMOVE_LINK'), this.$T('TIPS_NOTICE'), {
|
||||
confirmButtonText: this.$T('CONFIRM'),
|
||||
cancelButtonText: this.$T('CANCEL'),
|
||||
type: 'warning'
|
||||
}).then(async () => {
|
||||
const file = await this.$$db.getById(id)
|
||||
await this.$$db.removeById(id)
|
||||
ipcRenderer.send('removeFiles', [file])
|
||||
const obj = {
|
||||
title: this.$T('OPERATION_SUCCEED'),
|
||||
body: ''
|
||||
}
|
||||
const myNotification = new Notification(obj.title, obj)
|
||||
myNotification.onclick = () => {
|
||||
return true
|
||||
}
|
||||
this.updateGallery()
|
||||
}).catch((e) => {
|
||||
console.log(e)
|
||||
return true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
openDialog (item: ImgInfo) {
|
||||
this.imgInfo.id = item.id!
|
||||
this.imgInfo.imgUrl = item.imgUrl as string
|
||||
this.dialogVisible = true
|
||||
}
|
||||
|
||||
async confirmModify () {
|
||||
await this.$$db.updateById(this.imgInfo.id, {
|
||||
imgUrl: this.imgInfo.imgUrl
|
||||
})
|
||||
const obj = {
|
||||
title: this.$T('CHANGE_IMAGE_URL_SUCCEED'),
|
||||
body: this.imgInfo.imgUrl
|
||||
// icon: this.imgInfo.imgUrl
|
||||
}
|
||||
const myNotification = new Notification(obj.title, obj)
|
||||
myNotification.onclick = () => {
|
||||
return true
|
||||
}
|
||||
this.dialogVisible = false
|
||||
this.updateGallery()
|
||||
}
|
||||
|
||||
choosePicBed (type: string) {
|
||||
const idx = this.choosedPicBed.indexOf(type)
|
||||
if (idx !== -1) {
|
||||
this.choosedPicBed.splice(idx, 1)
|
||||
} else {
|
||||
this.choosedPicBed.push(type)
|
||||
}
|
||||
}
|
||||
|
||||
cleanSearch () {
|
||||
this.searchText = ''
|
||||
}
|
||||
|
||||
isMultiple (obj: IObj) {
|
||||
return Object.values(obj).some(item => item)
|
||||
}
|
||||
|
||||
toggleSelectAll () {
|
||||
const result = !this.isAllSelected
|
||||
this.filterList.forEach(item => {
|
||||
this.$set(this.choosedList, item.id!, result)
|
||||
})
|
||||
}
|
||||
|
||||
multiRemove () {
|
||||
// choosedList -> { [id]: true or false }; true means choosed. false means not choosed.
|
||||
const multiRemoveNumber = Object.values(this.choosedList).filter(item => item).length
|
||||
if (multiRemoveNumber) {
|
||||
this.$confirm(this.$T('TIPS_WILL_REMOVE_CHOOSED_IMAGES', {
|
||||
m: multiRemoveNumber
|
||||
}), this.$T('TIPS_NOTICE'), {
|
||||
confirmButtonText: this.$T('CONFIRM'),
|
||||
cancelButtonText: this.$T('CANCEL'),
|
||||
type: 'warning'
|
||||
}).then(async () => {
|
||||
const files: IResult<ImgInfo>[] = []
|
||||
const imageIDList = Object.keys(this.choosedList)
|
||||
for (let i = 0; i < imageIDList.length; i++) {
|
||||
const key = imageIDList[i]
|
||||
if (this.choosedList[key]) {
|
||||
const file = await this.$$db.getById<ImgInfo>(key)
|
||||
if (file) {
|
||||
files.push(file)
|
||||
await this.$$db.removeById(key)
|
||||
}
|
||||
}
|
||||
}
|
||||
this.clearChoosedList()
|
||||
this.choosedList = {} // 只有删除才能将这个置空
|
||||
const obj = {
|
||||
title: this.$T('OPERATION_SUCCEED'),
|
||||
body: ''
|
||||
}
|
||||
ipcRenderer.send('removeFiles', files)
|
||||
const myNotification = new Notification(obj.title, obj)
|
||||
myNotification.onclick = () => {
|
||||
return true
|
||||
}
|
||||
this.updateGallery()
|
||||
}).catch(() => {
|
||||
return true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
async multiCopy () {
|
||||
if (Object.values(this.choosedList).some(item => item)) {
|
||||
const copyString: string[] = []
|
||||
// choosedList -> { [id]: true or false }; true means choosed. false means not choosed.
|
||||
const imageIDList = Object.keys(this.choosedList)
|
||||
for (let i = 0; i < imageIDList.length; i++) {
|
||||
const key = imageIDList[i]
|
||||
if (this.choosedList[key]) {
|
||||
const item = await this.$$db.getById<ImgInfo>(key)
|
||||
if (item) {
|
||||
const txt = await ipcRenderer.invoke(PASTE_TEXT, item)
|
||||
copyString.push(txt)
|
||||
this.choosedList[key] = false
|
||||
}
|
||||
}
|
||||
}
|
||||
function remove (id?: string) {
|
||||
if (id) {
|
||||
$confirm($T('TIPS_REMOVE_LINK'), $T('TIPS_NOTICE'), {
|
||||
confirmButtonText: $T('CONFIRM'),
|
||||
cancelButtonText: $T('CANCEL'),
|
||||
type: 'warning'
|
||||
}).then(async () => {
|
||||
const file = await $$db.getById(id)
|
||||
await $$db.removeById(id)
|
||||
sendToMain('removeFiles', [file])
|
||||
const obj = {
|
||||
title: this.$T('BATCH_COPY_LINK_SUCCEED'),
|
||||
body: copyString.join('\n')
|
||||
title: $T('OPERATION_SUCCEED'),
|
||||
body: ''
|
||||
}
|
||||
const myNotification = new Notification(obj.title, obj)
|
||||
clipboard.writeText(copyString.join('\n'))
|
||||
myNotification.onclick = () => {
|
||||
return true
|
||||
}
|
||||
updateGallery()
|
||||
}).catch((e) => {
|
||||
console.log(e)
|
||||
return true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function openDialog (item: ImgInfo) {
|
||||
imgInfo.id = item.id!
|
||||
imgInfo.imgUrl = item.imgUrl as string
|
||||
dialogVisible.value = true
|
||||
}
|
||||
|
||||
async function confirmModify () {
|
||||
await $$db.updateById(imgInfo.id, {
|
||||
imgUrl: imgInfo.imgUrl
|
||||
})
|
||||
const obj = {
|
||||
title: $T('CHANGE_IMAGE_URL_SUCCEED'),
|
||||
body: imgInfo.imgUrl
|
||||
// icon: this.imgInfo.imgUrl
|
||||
}
|
||||
const myNotification = new Notification(obj.title, obj)
|
||||
myNotification.onclick = () => {
|
||||
return true
|
||||
}
|
||||
dialogVisible.value = false
|
||||
updateGallery()
|
||||
}
|
||||
|
||||
// function choosePicBed (type: string) {
|
||||
// const idx = choosedPicBed.value.indexOf(type)
|
||||
// if (idx !== -1) {
|
||||
// choosedPicBed.value.splice(idx, 1)
|
||||
// } else {
|
||||
// choosedPicBed.value.push(type)
|
||||
// }
|
||||
// }
|
||||
|
||||
function cleanSearch () {
|
||||
searchText.value = ''
|
||||
}
|
||||
|
||||
function isMultiple (obj: IObj) {
|
||||
return Object.values(obj).some(item => item)
|
||||
}
|
||||
|
||||
function toggleSelectAll () {
|
||||
const result = !isAllSelected.value
|
||||
filterList.value.forEach(item => {
|
||||
choosedList[item.id!] = result
|
||||
})
|
||||
}
|
||||
|
||||
function multiRemove () {
|
||||
// choosedList -> { [id]: true or false }; true means choosed. false means not choosed.
|
||||
const multiRemoveNumber = Object.values(choosedList).filter(item => item).length
|
||||
if (multiRemoveNumber) {
|
||||
$confirm($T('TIPS_WILL_REMOVE_CHOOSED_IMAGES', {
|
||||
m: multiRemoveNumber
|
||||
}), $T('TIPS_NOTICE'), {
|
||||
confirmButtonText: $T('CONFIRM'),
|
||||
cancelButtonText: $T('CANCEL'),
|
||||
type: 'warning'
|
||||
}).then(async () => {
|
||||
const files: IResult<ImgInfo>[] = []
|
||||
const imageIDList = Object.keys(choosedList)
|
||||
for (let i = 0; i < imageIDList.length; i++) {
|
||||
const key = imageIDList[i]
|
||||
if (choosedList[key]) {
|
||||
const file = await $$db.getById<ImgInfo>(key)
|
||||
if (file) {
|
||||
files.push(file)
|
||||
await $$db.removeById(key)
|
||||
}
|
||||
}
|
||||
}
|
||||
clearChoosedList()
|
||||
// TODO: check this
|
||||
// choosedList = {} // 只有删除才能将这个置空
|
||||
const obj = {
|
||||
title: $T('OPERATION_SUCCEED'),
|
||||
body: ''
|
||||
}
|
||||
sendToMain('removeFiles', files)
|
||||
const myNotification = new Notification(obj.title, obj)
|
||||
myNotification.onclick = () => {
|
||||
return true
|
||||
}
|
||||
updateGallery()
|
||||
}).catch(() => {
|
||||
return true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
async function multiCopy () {
|
||||
if (Object.values(choosedList).some(item => item)) {
|
||||
const copyString: string[] = []
|
||||
// choosedList -> { [id]: true or false }; true means choosed. false means not choosed.
|
||||
const imageIDList = Object.keys(choosedList)
|
||||
for (let i = 0; i < imageIDList.length; i++) {
|
||||
const key = imageIDList[i]
|
||||
if (choosedList[key]) {
|
||||
const item = await $$db.getById<ImgInfo>(key)
|
||||
if (item) {
|
||||
const txt = await ipcRenderer.invoke(PASTE_TEXT, item)
|
||||
copyString.push(txt)
|
||||
choosedList[key] = false
|
||||
}
|
||||
}
|
||||
}
|
||||
const obj = {
|
||||
title: $T('BATCH_COPY_LINK_SUCCEED'),
|
||||
body: copyString.join('\n')
|
||||
}
|
||||
const myNotification = new Notification(obj.title, obj)
|
||||
clipboard.writeText(copyString.join('\n'))
|
||||
myNotification.onclick = () => {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
toggleHandleBar () {
|
||||
this.handleBarActive = !this.handleBarActive
|
||||
}
|
||||
function toggleHandleBar () {
|
||||
handleBarActive.value = !handleBarActive.value
|
||||
}
|
||||
|
||||
// getPasteStyle () {
|
||||
// this.pasteStyle = this.$db.get('settings.pasteStyle') || 'markdown'
|
||||
// }
|
||||
async handlePasteStyleChange (val: string) {
|
||||
this.saveConfig('settings.pasteStyle', val)
|
||||
this.pasteStyle = val
|
||||
}
|
||||
async function handlePasteStyleChange (val: string) {
|
||||
saveConfig('settings.pasteStyle', val)
|
||||
pasteStyle.value = val
|
||||
}
|
||||
|
||||
beforeDestroy () {
|
||||
ipcRenderer.removeAllListeners('updateGallery')
|
||||
ipcRenderer.removeListener(GET_PICBEDS, this.getPicBeds)
|
||||
}
|
||||
onBeforeUnmount(() => {
|
||||
console.log('unmounted')
|
||||
ipcRenderer.removeAllListeners('updateGallery')
|
||||
ipcRenderer.removeListener(GET_PICBEDS, getPicBeds)
|
||||
})
|
||||
|
||||
onActivated(async () => {
|
||||
pasteStyle.value = (await getConfig('settings.pasteStyle')) || 'markdown'
|
||||
})
|
||||
|
||||
</script>
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'GalleryPage'
|
||||
}
|
||||
</script>
|
||||
<style lang='stylus'>
|
||||
.PhotoSlider
|
||||
&__BannerIcon
|
||||
&:nth-child(1)
|
||||
display none
|
||||
&__Counter
|
||||
margin-top 20px
|
||||
.view-title
|
||||
color #eee
|
||||
font-size 20px
|
||||
@ -473,6 +585,8 @@ export default class extends Vue {
|
||||
transform: rotate(180deg)
|
||||
#gallery-view
|
||||
height 100%
|
||||
.cursor-pointer
|
||||
cursor pointer
|
||||
.item-base
|
||||
background #2E2E2E
|
||||
text-align center
|
||||
@ -523,9 +637,9 @@ export default class extends Vue {
|
||||
height: 287px
|
||||
top: 113px
|
||||
&__img
|
||||
height 150px
|
||||
// height 150px
|
||||
position relative
|
||||
margin-bottom 16px
|
||||
margin-bottom 8px
|
||||
&__item
|
||||
width 100%
|
||||
height 120px
|
||||
@ -534,6 +648,7 @@ export default class extends Vue {
|
||||
margin-bottom 4px
|
||||
overflow hidden
|
||||
display flex
|
||||
margin-bottom 6px
|
||||
&-fake
|
||||
position absolute
|
||||
top 0
|
||||
@ -549,16 +664,20 @@ export default class extends Vue {
|
||||
&__tool-panel
|
||||
color #ddd
|
||||
margin-bottom 4px
|
||||
display flex
|
||||
.el-checkbox
|
||||
height 16px
|
||||
i
|
||||
cursor pointer
|
||||
transition all .2s ease-in-out
|
||||
&.el-icon-document
|
||||
margin-right 4px
|
||||
&.document
|
||||
&:hover
|
||||
color #49B1F5
|
||||
&.el-icon-edit-outline
|
||||
&.edit
|
||||
&:hover
|
||||
color #69C282
|
||||
&.el-icon-delete
|
||||
&.delete
|
||||
&:hover
|
||||
color #F15140
|
||||
&__file-name
|
||||
@ -571,6 +690,4 @@ export default class extends Vue {
|
||||
.handle-bar
|
||||
color #ddd
|
||||
margin-bottom 10px
|
||||
.el-input__inner
|
||||
border-radius 14px
|
||||
</style>
|
||||
|
@ -1,187 +1,198 @@
|
||||
<template>
|
||||
<div id="mini-page"
|
||||
<div
|
||||
id="mini-page"
|
||||
:style="{ backgroundImage: 'url(' + logo + ')' }"
|
||||
:class="{ linux: os === 'linux' }"
|
||||
>
|
||||
<!-- <i class="el-icon-upload2"></i> -->
|
||||
<div
|
||||
id="upload-area"
|
||||
:class="{ 'is-dragover': dragover, uploading: showProgress, linux: os === 'linux' }" @drop.prevent="onDrop" @dragover.prevent="dragover = true" @dragleave.prevent="dragover = false"
|
||||
:style="{ backgroundPosition: '0 ' + progress + '%'}"
|
||||
>
|
||||
<div id="upload-dragger" @dblclick="openUploadWindow">
|
||||
<input type="file" id="file-uploader" @change="onChange" multiple>
|
||||
<div
|
||||
id="upload-area"
|
||||
:class="{ 'is-dragover': dragover, uploading: showProgress, linux: os === 'linux' }"
|
||||
:style="{ backgroundPosition: '0 ' + progress + '%'}"
|
||||
@drop.prevent="onDrop"
|
||||
@dragover.prevent="dragover = true"
|
||||
@dragleave.prevent="dragover = false"
|
||||
>
|
||||
<div
|
||||
id="upload-dragger"
|
||||
@dblclick="openUploadWindow"
|
||||
>
|
||||
<input
|
||||
id="file-uploader"
|
||||
type="file"
|
||||
multiple
|
||||
@change="onChange"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import mixin from '@/utils/mixin'
|
||||
import { Component, Vue, Watch } from 'vue-property-decorator'
|
||||
<script lang="ts" setup>
|
||||
// import mixin from '@/utils/mixin'
|
||||
// import { Component, Vue, Watch } from 'vue-property-decorator'
|
||||
import { T as $T } from '@/i18n/index'
|
||||
import { ElMessage as $message } from 'element-plus'
|
||||
import {
|
||||
ipcRenderer,
|
||||
IpcRendererEvent
|
||||
} from 'electron'
|
||||
import { onBeforeUnmount, onBeforeMount, ref, watch } from 'vue'
|
||||
import { SHOW_MINI_PAGE_MENU, SET_MINI_WINDOW_POS } from '~/universal/events/constants'
|
||||
import {
|
||||
isUrl
|
||||
} from '~/universal/utils/common'
|
||||
@Component({
|
||||
name: 'mini-page',
|
||||
mixins: [mixin]
|
||||
import { sendToMain } from '@/utils/dataSender'
|
||||
const logo = require('../assets/squareLogo.png')
|
||||
const dragover = ref(false)
|
||||
const progress = ref(0)
|
||||
const showProgress = ref(false)
|
||||
const showError = ref(false)
|
||||
const dragging = ref(false)
|
||||
const wX = ref(-1)
|
||||
const wY = ref(-1)
|
||||
const screenX = ref(-1)
|
||||
const screenY = ref(-1)
|
||||
const os = ref('')
|
||||
|
||||
onBeforeMount(() => {
|
||||
os.value = process.platform
|
||||
ipcRenderer.on('uploadProgress', (event: IpcRendererEvent, _progress: number) => {
|
||||
if (_progress !== -1) {
|
||||
showProgress.value = true
|
||||
progress.value = _progress
|
||||
} else {
|
||||
progress.value = 100
|
||||
showError.value = true
|
||||
}
|
||||
})
|
||||
window.addEventListener('mousedown', handleMouseDown, false)
|
||||
window.addEventListener('mousemove', handleMouseMove, false)
|
||||
window.addEventListener('mouseup', handleMouseUp, false)
|
||||
})
|
||||
export default class extends Vue {
|
||||
logo = require('../assets/squareLogo.png')
|
||||
dragover = false
|
||||
progress = 0
|
||||
showProgress = false
|
||||
showError = false
|
||||
dragging = false
|
||||
wX: number = -1
|
||||
wY: number = -1
|
||||
screenX: number = -1
|
||||
screenY: number = -1
|
||||
menu: Electron.Menu | null = null
|
||||
os = ''
|
||||
picBed: IPicBedType[] = []
|
||||
created () {
|
||||
this.os = process.platform
|
||||
ipcRenderer.on('uploadProgress', (event: IpcRendererEvent, progress: number) => {
|
||||
if (progress !== -1) {
|
||||
this.showProgress = true
|
||||
this.progress = progress
|
||||
} else {
|
||||
this.progress = 100
|
||||
this.showError = true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
mounted () {
|
||||
window.addEventListener('mousedown', this.handleMouseDown, false)
|
||||
window.addEventListener('mousemove', this.handleMouseMove, false)
|
||||
window.addEventListener('mouseup', this.handleMouseUp, false)
|
||||
watch(progress, (val) => {
|
||||
if (val === 100) {
|
||||
setTimeout(() => {
|
||||
showProgress.value = false
|
||||
showError.value = false
|
||||
}, 1000)
|
||||
setTimeout(() => {
|
||||
progress.value = 0
|
||||
}, 1200)
|
||||
}
|
||||
})
|
||||
|
||||
@Watch('progress')
|
||||
onProgressChange (val: number) {
|
||||
if (val === 100) {
|
||||
setTimeout(() => {
|
||||
this.showProgress = false
|
||||
this.showError = false
|
||||
}, 1000)
|
||||
setTimeout(() => {
|
||||
this.progress = 0
|
||||
}, 1200)
|
||||
}
|
||||
}
|
||||
|
||||
onDrop (e: DragEvent) {
|
||||
this.dragover = false
|
||||
const items = e.dataTransfer!.items
|
||||
if (items.length === 2 && items[0].type === 'text/uri-list') {
|
||||
this.handleURLDrag(items, e.dataTransfer!)
|
||||
} else if (items[0].type === 'text/plain') {
|
||||
const str = e.dataTransfer!.getData(items[0].type)
|
||||
if (isUrl(str)) {
|
||||
ipcRenderer.send('uploadChoosedFiles', [{ path: str }])
|
||||
} else {
|
||||
this.$message.error(this.$T('TIPS_DRAG_VALID_PICTURE_OR_URL'))
|
||||
}
|
||||
function onDrop (e: DragEvent) {
|
||||
dragover.value = false
|
||||
const items = e.dataTransfer!.items
|
||||
if (items.length === 2 && items[0].type === 'text/uri-list') {
|
||||
handleURLDrag(items, e.dataTransfer!)
|
||||
} else if (items[0].type === 'text/plain') {
|
||||
const str = e.dataTransfer!.getData(items[0].type)
|
||||
if (isUrl(str)) {
|
||||
sendToMain('uploadChoosedFiles', [{ path: str }])
|
||||
} else {
|
||||
this.ipcSendFiles(e.dataTransfer!.files)
|
||||
$message.error($T('TIPS_DRAG_VALID_PICTURE_OR_URL'))
|
||||
}
|
||||
} else {
|
||||
ipcSendFiles(e.dataTransfer!.files)
|
||||
}
|
||||
}
|
||||
|
||||
handleURLDrag (items: DataTransferItemList, dataTransfer: DataTransfer) {
|
||||
// text/html
|
||||
// Use this data to get a more precise URL
|
||||
const urlString = dataTransfer.getData(items[1].type)
|
||||
const urlMatch = urlString.match(/<img.*src="(.*?)"/)
|
||||
if (urlMatch) {
|
||||
ipcRenderer.send('uploadChoosedFiles', [
|
||||
{
|
||||
path: urlMatch[1]
|
||||
}
|
||||
])
|
||||
} else {
|
||||
this.$message.error(this.$T('TIPS_DRAG_VALID_PICTURE_OR_URL'))
|
||||
}
|
||||
}
|
||||
|
||||
openUploadWindow () {
|
||||
// @ts-ignore
|
||||
document.getElementById('file-uploader').click()
|
||||
}
|
||||
|
||||
onChange (e: any) {
|
||||
this.ipcSendFiles(e.target.files)
|
||||
// @ts-ignore
|
||||
document.getElementById('file-uploader').value = ''
|
||||
}
|
||||
|
||||
ipcSendFiles (files: FileList) {
|
||||
const sendFiles: IFileWithPath[] = []
|
||||
Array.from(files).forEach((item) => {
|
||||
const obj = {
|
||||
name: item.name,
|
||||
path: item.path
|
||||
function handleURLDrag (items: DataTransferItemList, dataTransfer: DataTransfer) {
|
||||
// text/html
|
||||
// Use this data to get a more precise URL
|
||||
const urlString = dataTransfer.getData(items[1].type)
|
||||
const urlMatch = urlString.match(/<img.*src="(.*?)"/)
|
||||
if (urlMatch) {
|
||||
sendToMain('uploadChoosedFiles', [
|
||||
{
|
||||
path: urlMatch[1]
|
||||
}
|
||||
sendFiles.push(obj)
|
||||
])
|
||||
} else {
|
||||
$message.error($T('TIPS_DRAG_VALID_PICTURE_OR_URL'))
|
||||
}
|
||||
}
|
||||
|
||||
function openUploadWindow () {
|
||||
// @ts-ignore
|
||||
document.getElementById('file-uploader').click()
|
||||
}
|
||||
|
||||
function onChange (e: any) {
|
||||
ipcSendFiles(e.target.files)
|
||||
// @ts-ignore
|
||||
document.getElementById('file-uploader').value = ''
|
||||
}
|
||||
|
||||
function ipcSendFiles (files: FileList) {
|
||||
const sendFiles: IFileWithPath[] = []
|
||||
Array.from(files).forEach((item) => {
|
||||
const obj = {
|
||||
name: item.name,
|
||||
path: item.path
|
||||
}
|
||||
sendFiles.push(obj)
|
||||
})
|
||||
sendToMain('uploadChoosedFiles', sendFiles)
|
||||
}
|
||||
|
||||
function handleMouseDown (e: MouseEvent) {
|
||||
dragging.value = true
|
||||
wX.value = e.pageX
|
||||
wY.value = e.pageY
|
||||
screenX.value = e.screenX
|
||||
screenY.value = e.screenY
|
||||
}
|
||||
|
||||
function handleMouseMove (e: MouseEvent) {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
if (dragging.value) {
|
||||
const xLoc = e.screenX - wX.value
|
||||
const yLoc = e.screenY - wY.value
|
||||
sendToMain(SET_MINI_WINDOW_POS, {
|
||||
x: xLoc,
|
||||
y: yLoc,
|
||||
width: 64,
|
||||
height: 64
|
||||
})
|
||||
ipcRenderer.send('uploadChoosedFiles', sendFiles)
|
||||
// remote.BrowserWindow.getFocusedWindow()!.setBounds({
|
||||
// x: xLoc,
|
||||
// y: yLoc,
|
||||
// width: 64,
|
||||
// height: 64
|
||||
// })
|
||||
}
|
||||
}
|
||||
|
||||
handleMouseDown (e: MouseEvent) {
|
||||
this.dragging = true
|
||||
this.wX = e.pageX
|
||||
this.wY = e.pageY
|
||||
this.screenX = e.screenX
|
||||
this.screenY = e.screenY
|
||||
}
|
||||
|
||||
handleMouseMove (e: MouseEvent) {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
if (this.dragging) {
|
||||
const xLoc = e.screenX - this.wX
|
||||
const yLoc = e.screenY - this.wY
|
||||
ipcRenderer.send(SET_MINI_WINDOW_POS, {
|
||||
x: xLoc,
|
||||
y: yLoc,
|
||||
width: 64,
|
||||
height: 64
|
||||
})
|
||||
// remote.BrowserWindow.getFocusedWindow()!.setBounds({
|
||||
// x: xLoc,
|
||||
// y: yLoc,
|
||||
// width: 64,
|
||||
// height: 64
|
||||
// })
|
||||
function handleMouseUp (e: MouseEvent) {
|
||||
dragging.value = false
|
||||
if (screenX.value === e.screenX && screenY.value === e.screenY) {
|
||||
if (e.button === 0) { // left mouse
|
||||
openUploadWindow()
|
||||
} else {
|
||||
openContextMenu()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
handleMouseUp (e: MouseEvent) {
|
||||
this.dragging = false
|
||||
if (this.screenX === e.screenX && this.screenY === e.screenY) {
|
||||
if (e.button === 0) { // left mouse
|
||||
this.openUploadWindow()
|
||||
} else {
|
||||
this.openContextMenu()
|
||||
}
|
||||
}
|
||||
}
|
||||
function openContextMenu () {
|
||||
sendToMain(SHOW_MINI_PAGE_MENU)
|
||||
}
|
||||
|
||||
openContextMenu () {
|
||||
ipcRenderer.send(SHOW_MINI_PAGE_MENU)
|
||||
}
|
||||
onBeforeUnmount(() => {
|
||||
ipcRenderer.removeAllListeners('uploadProgress')
|
||||
window.removeEventListener('mousedown', handleMouseDown, false)
|
||||
window.removeEventListener('mousemove', handleMouseMove, false)
|
||||
window.removeEventListener('mouseup', handleMouseUp, false)
|
||||
})
|
||||
|
||||
beforeDestroy () {
|
||||
ipcRenderer.removeAllListeners('uploadProgress')
|
||||
window.removeEventListener('mousedown', this.handleMouseDown, false)
|
||||
window.removeEventListener('mousemove', this.handleMouseMove, false)
|
||||
window.removeEventListener('mouseup', this.handleMouseUp, false)
|
||||
}
|
||||
</script>
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'MiniPage'
|
||||
}
|
||||
</script>
|
||||
<style lang='stylus'>
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -2,72 +2,142 @@
|
||||
<div id="plugin-view">
|
||||
<div class="view-title">
|
||||
{{ $T('PLUGIN_SETTINGS') }} -
|
||||
<el-tooltip :content="pluginListToolTip" placement="right">
|
||||
<i class="el-icon-goods" @click="goAwesomeList"></i>
|
||||
<el-tooltip
|
||||
:content="pluginListToolTip"
|
||||
placement="right"
|
||||
>
|
||||
<el-icon
|
||||
class="el-icon-goods"
|
||||
@click="goAwesomeList"
|
||||
>
|
||||
<Goods />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
<el-tooltip :content="importLocalPluginToolTip" placement="left">
|
||||
<i class="el-icon-download" @click="handleImportLocalPlugin"/>
|
||||
<el-tooltip
|
||||
:content="importLocalPluginToolTip"
|
||||
placement="left"
|
||||
>
|
||||
<el-icon
|
||||
class="el-icon-download"
|
||||
@click="handleImportLocalPlugin"
|
||||
>
|
||||
<Download />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<el-row class="handle-bar" :class="{ 'cut-width': pluginList.length > 6 }">
|
||||
<el-row
|
||||
class="handle-bar"
|
||||
:class="{ 'cut-width': pluginList.length > 6 }"
|
||||
>
|
||||
<el-input
|
||||
v-model="searchText"
|
||||
:placeholder="$T('PLUGIN_SEARCH_PLACEHOLDER')"
|
||||
size="small"
|
||||
>
|
||||
<i slot="suffix" class="el-input__icon el-icon-close" v-if="searchText" @click="cleanSearch" style="cursor: pointer"></i>
|
||||
<template #suffix>
|
||||
<el-icon
|
||||
class="el-input__icon"
|
||||
style="cursor: pointer;"
|
||||
@click="cleanSearch"
|
||||
>
|
||||
<close />
|
||||
</el-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-row>
|
||||
<el-row :gutter="10" class="plugin-list" v-loading="loading">
|
||||
<el-col :span="12" v-for="item in pluginList" :key="item.fullName">
|
||||
<div class="plugin-item" :class="{ 'darwin': os === 'darwin' }">
|
||||
<div class="cli-only-badge" v-if="!item.gui" title="CLI only">CLI</div>
|
||||
<img class="plugin-item__logo" :src="item.logo"
|
||||
<el-row
|
||||
v-loading="loading"
|
||||
:gutter="10"
|
||||
class="plugin-list"
|
||||
>
|
||||
<el-col
|
||||
v-for="item in pluginList"
|
||||
:key="item.fullName"
|
||||
class="plugin-item__container"
|
||||
:span="12"
|
||||
>
|
||||
<div
|
||||
class="plugin-item"
|
||||
:class="{ 'darwin': os === 'darwin' }"
|
||||
>
|
||||
<div
|
||||
v-if="!item.gui"
|
||||
class="cli-only-badge"
|
||||
title="CLI only"
|
||||
>
|
||||
CLI
|
||||
</div>
|
||||
<img
|
||||
class="plugin-item__logo"
|
||||
:src="item.logo"
|
||||
:onerror="defaultLogo"
|
||||
>
|
||||
<div
|
||||
class="plugin-item__content"
|
||||
:class="{ disabled: !item.enabled }"
|
||||
>
|
||||
<div class="plugin-item__name" @click="openHomepage(item.homepage)">
|
||||
<div
|
||||
class="plugin-item__name"
|
||||
@click="openHomepage(item.homepage)"
|
||||
>
|
||||
{{ item.name }} <small>{{ ' ' + item.version }}</small>
|
||||
</div>
|
||||
<div class="plugin-item__desc" :title="item.description">
|
||||
<div
|
||||
class="plugin-item__desc"
|
||||
:title="item.description"
|
||||
>
|
||||
{{ item.description }}
|
||||
</div>
|
||||
<div class="plugin-item__info-bar">
|
||||
<span class="plugin-item__author">
|
||||
{{ item.author }}
|
||||
</span>
|
||||
<span class="plugin-item__config" >
|
||||
<span class="plugin-item__config">
|
||||
<template v-if="searchText">
|
||||
<template v-if="!item.hasInstall">
|
||||
<span class="config-button install" v-if="!item.ing" @click="installPlugin(item)">
|
||||
<span
|
||||
v-if="!item.ing"
|
||||
class="config-button install"
|
||||
@click="installPlugin(item)"
|
||||
>
|
||||
{{ $T('PLUGIN_INSTALL') }}
|
||||
</span>
|
||||
<span v-else-if="item.ing" class="config-button ing">
|
||||
<span
|
||||
v-else-if="item.ing"
|
||||
class="config-button ing"
|
||||
>
|
||||
{{ $T('PLUGIN_INSTALLING') }}
|
||||
</span>
|
||||
</template>
|
||||
<span v-else class="config-button ing">
|
||||
<span
|
||||
v-else
|
||||
class="config-button ing"
|
||||
>
|
||||
{{ $T('PLUGIN_INSTALLED') }}
|
||||
</span>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span v-if="item.ing" class="config-button ing">
|
||||
<span
|
||||
v-if="item.ing"
|
||||
class="config-button ing"
|
||||
>
|
||||
{{ $T('PLUGIN_DOING_SOMETHING') }}
|
||||
</span>
|
||||
<template v-else>
|
||||
<i
|
||||
<el-icon
|
||||
v-if="item.enabled"
|
||||
class="el-icon-setting"
|
||||
@click="buildContextMenu(item)"
|
||||
></i>
|
||||
<i
|
||||
>
|
||||
<Setting />
|
||||
</el-icon>
|
||||
<el-icon
|
||||
v-else
|
||||
class="el-icon-remove-outline"
|
||||
@click="buildContextMenu(item)"
|
||||
></i>
|
||||
>
|
||||
<Remove />
|
||||
</el-icon>
|
||||
</template>
|
||||
</template>
|
||||
</span>
|
||||
@ -76,11 +146,23 @@
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row v-show="needReload" class="reload-mask" :class="{ 'cut-width': pluginList.length > 6 }">
|
||||
<el-button type="primary" @click="reloadApp" size="mini" round>{{ $T('TIPS_NEED_RELOAD') }}</el-button>
|
||||
<el-row
|
||||
v-show="needReload"
|
||||
class="reload-mask"
|
||||
:class="{ 'cut-width': pluginList.length > 6 }"
|
||||
justify="center"
|
||||
>
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
round
|
||||
@click="reloadApp"
|
||||
>
|
||||
{{ $T('TIPS_NEED_RELOAD') }}
|
||||
</el-button>
|
||||
</el-row>
|
||||
<el-dialog
|
||||
:visible.sync="dialogVisible"
|
||||
v-model="dialogVisible"
|
||||
:modal-append-to-body="false"
|
||||
:title="$T('CONFIG_THING', {
|
||||
c: configName
|
||||
@ -88,27 +170,35 @@
|
||||
width="70%"
|
||||
>
|
||||
<config-form
|
||||
:id="configName"
|
||||
ref="$configForm"
|
||||
:config="config"
|
||||
:type="currentType"
|
||||
:id="configName"
|
||||
ref="configForm"
|
||||
>
|
||||
</config-form>
|
||||
<span slot="footer">
|
||||
<el-button @click="dialogVisible = false" round>{{ $T('CANCEL') }}</el-button>
|
||||
<el-button type="primary" @click="handleConfirmConfig" round>{{ $T('CONFIRM') }}</el-button>
|
||||
</span>
|
||||
color-mode="white"
|
||||
/>
|
||||
<template #footer>
|
||||
<el-button
|
||||
round
|
||||
@click="dialogVisible = false"
|
||||
>
|
||||
{{ $T('CANCEL') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
round
|
||||
@click="handleConfirmConfig"
|
||||
>
|
||||
{{ $T('CONFIRM') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import {
|
||||
Component,
|
||||
Vue,
|
||||
Watch
|
||||
} from 'vue-property-decorator'
|
||||
<script lang="ts" setup>
|
||||
import { Close, Download, Goods, Remove, Setting } from '@element-plus/icons-vue'
|
||||
import { T as $T } from '@/i18n/index'
|
||||
import ConfigForm from '@/components/ConfigForm.vue'
|
||||
import { debounce } from 'lodash'
|
||||
import { debounce, DebouncedFunc } from 'lodash'
|
||||
import {
|
||||
ipcRenderer,
|
||||
IpcRendererEvent
|
||||
@ -121,326 +211,336 @@ import {
|
||||
PICGO_HANDLE_PLUGIN_ING,
|
||||
PICGO_TOGGLE_PLUGIN,
|
||||
SHOW_PLUGIN_PAGE_MENU,
|
||||
GET_PICBEDS
|
||||
GET_PICBEDS,
|
||||
PICGO_HANDLE_PLUGIN_DONE
|
||||
} from '#/events/constants'
|
||||
import { computed, ref, onBeforeMount, onBeforeUnmount, watch } from 'vue'
|
||||
import { getConfig, saveConfig, sendToMain } from '@/utils/dataSender'
|
||||
import { ElMessageBox } from 'element-plus'
|
||||
import axios from 'axios'
|
||||
const $confirm = ElMessageBox.confirm
|
||||
const searchText = ref('')
|
||||
const pluginList = ref<IPicGoPlugin[]>([])
|
||||
const config = ref<any[]>([])
|
||||
const currentType = ref<'plugin' | 'uploader' | 'transformer'>('plugin')
|
||||
const configName = ref('')
|
||||
const dialogVisible = ref(false)
|
||||
const pluginNameList = ref<string[]>([])
|
||||
const loading = ref(true)
|
||||
const needReload = ref(false)
|
||||
const pluginListToolTip = $T('PLUGIN_LIST')
|
||||
const importLocalPluginToolTip = $T('PLUGIN_IMPORT_LOCAL')
|
||||
// const id = ref('')
|
||||
const os = ref('')
|
||||
const defaultLogo = ref(`this.src="file://${__static.replace(/\\/g, '/')}/roundLogo.png"`)
|
||||
const $configForm = ref<InstanceType<typeof ConfigForm> | null>(null)
|
||||
const npmSearchText = computed(() => {
|
||||
return searchText.value.match('picgo-plugin-')
|
||||
? searchText.value
|
||||
: searchText.value !== ''
|
||||
? `picgo-plugin-${searchText.value}`
|
||||
: searchText.value
|
||||
})
|
||||
let getSearchResult: DebouncedFunc<(val: string) => void>
|
||||
|
||||
@Component({
|
||||
name: 'plugin',
|
||||
components: {
|
||||
ConfigForm
|
||||
watch(npmSearchText, (val: string) => {
|
||||
if (val) {
|
||||
loading.value = true
|
||||
pluginList.value = []
|
||||
getSearchResult(val)
|
||||
} else {
|
||||
getPluginList()
|
||||
}
|
||||
})
|
||||
export default class extends Vue {
|
||||
searchText = ''
|
||||
pluginList: IPicGoPlugin[] = []
|
||||
menu: Electron.Menu | null = null
|
||||
config: any[] = []
|
||||
currentType = ''
|
||||
configName = ''
|
||||
dialogVisible = false
|
||||
pluginNameList: string[] = []
|
||||
loading = true
|
||||
needReload = false
|
||||
pluginListToolTip = this.$T('PLUGIN_LIST')
|
||||
importLocalPluginToolTip = this.$T('PLUGIN_IMPORT_LOCAL')
|
||||
id = ''
|
||||
os = ''
|
||||
defaultLogo: string = `this.src="file://${__static.replace(/\\/g, '/')}/roundLogo.png"`
|
||||
get npmSearchText () {
|
||||
return this.searchText.match('picgo-plugin-')
|
||||
? this.searchText
|
||||
: this.searchText !== ''
|
||||
? `picgo-plugin-${this.searchText}`
|
||||
: this.searchText
|
||||
}
|
||||
|
||||
@Watch('npmSearchText')
|
||||
onNpmSearchTextChange (val: string) {
|
||||
if (val) {
|
||||
this.loading = true
|
||||
this.pluginList = []
|
||||
this.getSearchResult(val)
|
||||
} else {
|
||||
this.getPluginList()
|
||||
}
|
||||
watch(dialogVisible, (val: boolean) => {
|
||||
if (val) {
|
||||
// @ts-ignore
|
||||
document.querySelector('.main-content.el-row').style.zIndex = 101
|
||||
} else {
|
||||
// @ts-ignore
|
||||
document.querySelector('.main-content.el-row').style.zIndex = 10
|
||||
}
|
||||
})
|
||||
|
||||
@Watch('dialogVisible')
|
||||
onDialogVisible (val: boolean) {
|
||||
if (val) {
|
||||
// @ts-ignore
|
||||
document.querySelector('.main-content.el-row').style.zIndex = 101
|
||||
} else {
|
||||
// @ts-ignore
|
||||
document.querySelector('.main-content.el-row').style.zIndex = 10
|
||||
}
|
||||
}
|
||||
|
||||
async created () {
|
||||
this.os = process.platform
|
||||
ipcRenderer.on('hideLoading', () => {
|
||||
this.loading = false
|
||||
})
|
||||
ipcRenderer.on('pluginList', (evt: IpcRendererEvent, list: IPicGoPlugin[]) => {
|
||||
this.pluginList = list
|
||||
this.pluginNameList = list.map(item => item.fullName)
|
||||
this.loading = false
|
||||
})
|
||||
ipcRenderer.on('installPlugin', (evt: IpcRendererEvent, { success, body }: {
|
||||
success: boolean,
|
||||
body: string
|
||||
}) => {
|
||||
this.loading = false
|
||||
this.pluginList.forEach(item => {
|
||||
if (item.fullName === body) {
|
||||
item.ing = false
|
||||
item.hasInstall = success
|
||||
}
|
||||
})
|
||||
})
|
||||
ipcRenderer.on('updateSuccess', (evt: IpcRendererEvent, plugin: string) => {
|
||||
this.loading = false
|
||||
this.pluginList.forEach(item => {
|
||||
if (item.fullName === plugin) {
|
||||
item.ing = false
|
||||
item.hasInstall = true
|
||||
}
|
||||
this.getPicBeds()
|
||||
})
|
||||
this.handleReload()
|
||||
this.getPluginList()
|
||||
})
|
||||
ipcRenderer.on('uninstallSuccess', (evt: IpcRendererEvent, plugin: string) => {
|
||||
this.loading = false
|
||||
this.pluginList = this.pluginList.filter(item => {
|
||||
if (item.fullName === plugin) { // restore Uploader & Transformer after uninstalling
|
||||
if (item.config.transformer.name) {
|
||||
this.handleRestoreState('transformer', item.config.transformer.name)
|
||||
}
|
||||
if (item.config.uploader.name) {
|
||||
this.handleRestoreState('uploader', item.config.uploader.name)
|
||||
}
|
||||
this.getPicBeds()
|
||||
}
|
||||
return item.fullName !== plugin
|
||||
})
|
||||
this.pluginNameList = this.pluginNameList.filter(item => item !== plugin)
|
||||
})
|
||||
ipcRenderer.on(PICGO_CONFIG_PLUGIN, (evt: IpcRendererEvent, currentType: string, configName: string, config: any) => {
|
||||
this.currentType = currentType
|
||||
this.configName = configName
|
||||
this.dialogVisible = true
|
||||
this.config = config
|
||||
})
|
||||
ipcRenderer.on(PICGO_HANDLE_PLUGIN_ING, (evt: IpcRendererEvent, fullName: string) => {
|
||||
this.pluginList.forEach(item => {
|
||||
if (item.fullName === fullName || (item.name === fullName)) {
|
||||
item.ing = true
|
||||
}
|
||||
})
|
||||
this.loading = true
|
||||
})
|
||||
ipcRenderer.on(PICGO_TOGGLE_PLUGIN, (evt: IpcRendererEvent, fullName: string, enabled: boolean) => {
|
||||
const plugin = this.pluginList.find(item => item.fullName === fullName)
|
||||
if (plugin) {
|
||||
plugin.enabled = enabled
|
||||
this.getPicBeds()
|
||||
this.needReload = true
|
||||
onBeforeMount(async () => {
|
||||
os.value = process.platform
|
||||
ipcRenderer.on('hideLoading', () => {
|
||||
loading.value = false
|
||||
})
|
||||
ipcRenderer.on(PICGO_HANDLE_PLUGIN_DONE, (evt: IpcRendererEvent, fullName: string) => {
|
||||
pluginList.value.forEach(item => {
|
||||
if (item.fullName === fullName || (item.name === fullName)) {
|
||||
item.ing = false
|
||||
}
|
||||
})
|
||||
this.getPluginList()
|
||||
this.getSearchResult = debounce(this.getSearchResult, 50)
|
||||
this.needReload = await this.getConfig<boolean>('needReload') || false
|
||||
}
|
||||
|
||||
async buildContextMenu (plugin: IPicGoPlugin) {
|
||||
ipcRenderer.send(SHOW_PLUGIN_PAGE_MENU, plugin)
|
||||
}
|
||||
|
||||
getPluginList () {
|
||||
ipcRenderer.send('getPluginList')
|
||||
}
|
||||
|
||||
getPicBeds () {
|
||||
ipcRenderer.send(GET_PICBEDS)
|
||||
}
|
||||
|
||||
installPlugin (item: IPicGoPlugin) {
|
||||
if (!item.gui) {
|
||||
this.$confirm(this.$T('TIPS_PLUGIN_NOT_GUI_IMPLEMENT'), this.$T('TIPS_NOTICE'), {
|
||||
confirmButtonText: this.$T('CONFIRM'),
|
||||
cancelButtonText: this.$T('CANCEL'),
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
loading.value = false
|
||||
})
|
||||
ipcRenderer.on('pluginList', (evt: IpcRendererEvent, list: IPicGoPlugin[]) => {
|
||||
pluginList.value = list
|
||||
pluginNameList.value = list.map(item => item.fullName)
|
||||
loading.value = false
|
||||
})
|
||||
ipcRenderer.on('installPlugin', (evt: IpcRendererEvent, { success, body }: {
|
||||
success: boolean,
|
||||
body: string
|
||||
}) => {
|
||||
loading.value = false
|
||||
pluginList.value.forEach(item => {
|
||||
if (item.fullName === body) {
|
||||
item.ing = false
|
||||
item.hasInstall = success
|
||||
}
|
||||
})
|
||||
})
|
||||
ipcRenderer.on('updateSuccess', (evt: IpcRendererEvent, plugin: string) => {
|
||||
loading.value = false
|
||||
pluginList.value.forEach(item => {
|
||||
if (item.fullName === plugin) {
|
||||
item.ing = false
|
||||
item.hasInstall = true
|
||||
}
|
||||
getPicBeds()
|
||||
})
|
||||
handleReload()
|
||||
getPluginList()
|
||||
})
|
||||
ipcRenderer.on('uninstallSuccess', (evt: IpcRendererEvent, plugin: string) => {
|
||||
loading.value = false
|
||||
pluginList.value = pluginList.value.filter(item => {
|
||||
if (item.fullName === plugin) { // restore Uploader & Transformer after uninstalling
|
||||
if (item.config.transformer.name) {
|
||||
handleRestoreState('transformer', item.config.transformer.name)
|
||||
}
|
||||
if (item.config.uploader.name) {
|
||||
handleRestoreState('uploader', item.config.uploader.name)
|
||||
}
|
||||
getPicBeds()
|
||||
}
|
||||
return item.fullName !== plugin
|
||||
})
|
||||
pluginNameList.value = pluginNameList.value.filter(item => item !== plugin)
|
||||
})
|
||||
ipcRenderer.on(PICGO_CONFIG_PLUGIN, (evt: IpcRendererEvent, _currentType: 'plugin' | 'transformer' | 'uploader', _configName: string, _config: any) => {
|
||||
currentType.value = _currentType
|
||||
configName.value = _configName
|
||||
dialogVisible.value = true
|
||||
config.value = _config
|
||||
})
|
||||
ipcRenderer.on(PICGO_HANDLE_PLUGIN_ING, (evt: IpcRendererEvent, fullName: string) => {
|
||||
pluginList.value.forEach(item => {
|
||||
if (item.fullName === fullName || (item.name === fullName)) {
|
||||
item.ing = true
|
||||
ipcRenderer.send('installPlugin', item.fullName)
|
||||
}).catch(() => {
|
||||
console.log('Install canceled')
|
||||
})
|
||||
} else {
|
||||
}
|
||||
})
|
||||
loading.value = true
|
||||
})
|
||||
ipcRenderer.on(PICGO_TOGGLE_PLUGIN, (evt: IpcRendererEvent, fullName: string, enabled: boolean) => {
|
||||
const plugin = pluginList.value.find(item => item.fullName === fullName)
|
||||
if (plugin) {
|
||||
plugin.enabled = enabled
|
||||
getPicBeds()
|
||||
needReload.value = true
|
||||
}
|
||||
})
|
||||
getPluginList()
|
||||
getSearchResult = debounce(_getSearchResult, 50)
|
||||
needReload.value = await getConfig<boolean>('needReload') || false
|
||||
})
|
||||
|
||||
async function buildContextMenu (plugin: IPicGoPlugin) {
|
||||
sendToMain(SHOW_PLUGIN_PAGE_MENU, plugin)
|
||||
}
|
||||
|
||||
function getPluginList () {
|
||||
sendToMain('getPluginList')
|
||||
}
|
||||
|
||||
function getPicBeds () {
|
||||
sendToMain(GET_PICBEDS)
|
||||
}
|
||||
|
||||
function installPlugin (item: IPicGoPlugin) {
|
||||
if (!item.gui) {
|
||||
$confirm($T('TIPS_PLUGIN_NOT_GUI_IMPLEMENT'), $T('TIPS_NOTICE'), {
|
||||
confirmButtonText: $T('CONFIRM'),
|
||||
cancelButtonText: $T('CANCEL'),
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
item.ing = true
|
||||
ipcRenderer.send('installPlugin', item.fullName)
|
||||
sendToMain('installPlugin', item.fullName)
|
||||
}).catch(() => {
|
||||
console.log('Install canceled')
|
||||
})
|
||||
} else {
|
||||
item.ing = true
|
||||
sendToMain('installPlugin', item.fullName)
|
||||
}
|
||||
}
|
||||
|
||||
// function uninstallPlugin (val: string) {
|
||||
// pluginList.value.forEach(item => {
|
||||
// if (item.name === val) {
|
||||
// item.ing = true
|
||||
// }
|
||||
// })
|
||||
// loading.value = true
|
||||
// sendToMain('uninstallPlugin', val)
|
||||
// }
|
||||
|
||||
// function updatePlugin (val: string) {
|
||||
// pluginList.value.forEach(item => {
|
||||
// if (item.fullName === val) {
|
||||
// item.ing = true
|
||||
// }
|
||||
// })
|
||||
// loading.value = true
|
||||
// sendToMain('updatePlugin', val)
|
||||
// }
|
||||
|
||||
function reloadApp () {
|
||||
sendToMain(RELOAD_APP)
|
||||
}
|
||||
|
||||
async function handleReload () {
|
||||
saveConfig({
|
||||
needReload: true
|
||||
})
|
||||
needReload.value = true
|
||||
const successNotification = new Notification($T('PLUGIN_UPDATE_SUCCEED'), {
|
||||
body: $T('TIPS_NEED_RELOAD')
|
||||
})
|
||||
successNotification.onclick = () => {
|
||||
reloadApp()
|
||||
}
|
||||
}
|
||||
|
||||
function cleanSearch () {
|
||||
searchText.value = ''
|
||||
}
|
||||
|
||||
async function handleConfirmConfig () {
|
||||
const result = (await $configForm.value?.validate() || false)
|
||||
if (result !== false) {
|
||||
switch (currentType.value) {
|
||||
case 'plugin':
|
||||
saveConfig({
|
||||
[`${configName.value}`]: result
|
||||
})
|
||||
break
|
||||
case 'uploader':
|
||||
saveConfig({
|
||||
[`picBed.${configName.value}`]: result
|
||||
})
|
||||
break
|
||||
case 'transformer':
|
||||
saveConfig({
|
||||
[`transformer.${configName.value}`]: result
|
||||
})
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
uninstallPlugin (val: string) {
|
||||
this.pluginList.forEach(item => {
|
||||
if (item.name === val) {
|
||||
item.ing = true
|
||||
}
|
||||
})
|
||||
this.loading = true
|
||||
ipcRenderer.send('uninstallPlugin', val)
|
||||
}
|
||||
|
||||
updatePlugin (val: string) {
|
||||
this.pluginList.forEach(item => {
|
||||
if (item.fullName === val) {
|
||||
item.ing = true
|
||||
}
|
||||
})
|
||||
this.loading = true
|
||||
ipcRenderer.send('updatePlugin', val)
|
||||
}
|
||||
|
||||
reloadApp () {
|
||||
ipcRenderer.send(RELOAD_APP)
|
||||
}
|
||||
|
||||
async handleReload () {
|
||||
this.saveConfig({
|
||||
needReload: true
|
||||
})
|
||||
this.needReload = true
|
||||
const successNotification = new Notification(this.$T('PLUGIN_UPDATE_SUCCEED'), {
|
||||
body: this.$T('TIPS_NEED_RELOAD')
|
||||
const successNotification = new Notification($T('SETTINGS_RESULT'), {
|
||||
body: $T('TIPS_SET_SUCCEED')
|
||||
})
|
||||
successNotification.onclick = () => {
|
||||
this.reloadApp()
|
||||
return true
|
||||
}
|
||||
dialogVisible.value = false
|
||||
getPluginList()
|
||||
}
|
||||
}
|
||||
|
||||
cleanSearch () {
|
||||
this.searchText = ''
|
||||
}
|
||||
|
||||
async handleConfirmConfig () {
|
||||
// @ts-ignore
|
||||
const result = await this.$refs.configForm.validate()
|
||||
if (result !== false) {
|
||||
switch (this.currentType) {
|
||||
case 'plugin':
|
||||
this.saveConfig({
|
||||
[`${this.configName}`]: result
|
||||
})
|
||||
break
|
||||
case 'uploader':
|
||||
this.saveConfig({
|
||||
[`picBed.${this.configName}`]: result
|
||||
})
|
||||
break
|
||||
case 'transformer':
|
||||
this.saveConfig({
|
||||
[`transformer.${this.configName}`]: result
|
||||
})
|
||||
break
|
||||
}
|
||||
const successNotification = new Notification(this.$T('SETTINGS_RESULT'), {
|
||||
body: this.$T('TIPS_SET_SUCCEED')
|
||||
})
|
||||
successNotification.onclick = () => {
|
||||
return true
|
||||
}
|
||||
this.dialogVisible = false
|
||||
this.getPluginList()
|
||||
}
|
||||
}
|
||||
|
||||
getSearchResult (val: string) {
|
||||
// this.$http.get(`https://api.npms.io/v2/search?q=${val}`)
|
||||
this.$http.get(`https://registry.npmjs.com/-/v1/search?text=${val}`)
|
||||
.then((res: INPMSearchResult) => {
|
||||
this.pluginList = res.data.objects
|
||||
.filter((item:INPMSearchResultObject) => {
|
||||
return item.package.name.includes('picgo-plugin-')
|
||||
})
|
||||
.map((item: INPMSearchResultObject) => {
|
||||
return this.handleSearchResult(item)
|
||||
})
|
||||
this.loading = false
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
this.loading = false
|
||||
})
|
||||
}
|
||||
|
||||
handleSearchResult (item: INPMSearchResultObject) {
|
||||
const name = handleStreamlinePluginName(item.package.name)
|
||||
let gui = false
|
||||
if (item.package.keywords && item.package.keywords.length > 0) {
|
||||
if (item.package.keywords.includes('picgo-gui-plugin')) {
|
||||
gui = true
|
||||
}
|
||||
}
|
||||
return {
|
||||
name: name,
|
||||
fullName: item.package.name,
|
||||
author: item.package.author.name,
|
||||
description: item.package.description,
|
||||
logo: `https://cdn.jsdelivr.net/npm/${item.package.name}/logo.png`,
|
||||
config: {},
|
||||
homepage: item.package.links ? item.package.links.homepage : '',
|
||||
hasInstall: this.pluginNameList.some(plugin => plugin === item.package.name),
|
||||
version: item.package.version,
|
||||
gui,
|
||||
ing: false // installing or uninstalling
|
||||
}
|
||||
}
|
||||
|
||||
// restore Uploader & Transformer
|
||||
async handleRestoreState (item: string, name: string) {
|
||||
if (item === 'uploader') {
|
||||
const current = await this.getConfig('picBed.current')
|
||||
if (current === name) {
|
||||
this.saveConfig({
|
||||
'picBed.current': 'smms',
|
||||
'picBed.uploader': 'smms'
|
||||
function _getSearchResult (val: string) {
|
||||
// this.$http.get(`https://api.npms.io/v2/search?q=${val}`)
|
||||
axios.get(`https://registry.npmjs.com/-/v1/search?text=${val}`)
|
||||
.then((res: INPMSearchResult) => {
|
||||
pluginList.value = res.data.objects
|
||||
.filter((item:INPMSearchResultObject) => {
|
||||
return item.package.name.includes('picgo-plugin-')
|
||||
})
|
||||
}
|
||||
}
|
||||
if (item === 'transformer') {
|
||||
const current = await this.getConfig('picBed.transformer')
|
||||
if (current === name) {
|
||||
this.saveConfig({
|
||||
'picBed.transformer': 'path'
|
||||
.map((item: INPMSearchResultObject) => {
|
||||
return handleSearchResult(item)
|
||||
})
|
||||
}
|
||||
loading.value = false
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
function handleSearchResult (item: INPMSearchResultObject) {
|
||||
const name = handleStreamlinePluginName(item.package.name)
|
||||
let gui = false
|
||||
if (item.package.keywords && item.package.keywords.length > 0) {
|
||||
if (item.package.keywords.includes('picgo-gui-plugin')) {
|
||||
gui = true
|
||||
}
|
||||
}
|
||||
return {
|
||||
name,
|
||||
fullName: item.package.name,
|
||||
author: item.package.author.name,
|
||||
description: item.package.description,
|
||||
logo: `https://cdn.jsdelivr.net/npm/${item.package.name}/logo.png`,
|
||||
config: {},
|
||||
homepage: item.package.links ? item.package.links.homepage : '',
|
||||
hasInstall: pluginNameList.value.some(plugin => plugin === item.package.name),
|
||||
version: item.package.version,
|
||||
gui,
|
||||
ing: false // installing or uninstalling
|
||||
}
|
||||
}
|
||||
|
||||
openHomepage (url: string) {
|
||||
if (url) {
|
||||
ipcRenderer.send(OPEN_URL, url)
|
||||
// restore Uploader & Transformer
|
||||
async function handleRestoreState (item: string, name: string) {
|
||||
if (item === 'uploader') {
|
||||
const current = await getConfig('picBed.current')
|
||||
if (current === name) {
|
||||
saveConfig({
|
||||
'picBed.current': 'smms',
|
||||
'picBed.uploader': 'smms'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
goAwesomeList () {
|
||||
ipcRenderer.send(OPEN_URL, 'https://github.com/PicGo/Awesome-PicGo')
|
||||
if (item === 'transformer') {
|
||||
const current = await getConfig('picBed.transformer')
|
||||
if (current === name) {
|
||||
saveConfig({
|
||||
'picBed.transformer': 'path'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
handleImportLocalPlugin () {
|
||||
ipcRenderer.send('importLocalPlugin')
|
||||
this.loading = true
|
||||
function openHomepage (url: string) {
|
||||
if (url) {
|
||||
sendToMain(OPEN_URL, url)
|
||||
}
|
||||
}
|
||||
|
||||
beforeDestroy () {
|
||||
ipcRenderer.removeAllListeners('pluginList')
|
||||
ipcRenderer.removeAllListeners('installPlugin')
|
||||
ipcRenderer.removeAllListeners('uninstallSuccess')
|
||||
ipcRenderer.removeAllListeners('updateSuccess')
|
||||
ipcRenderer.removeAllListeners('hideLoading')
|
||||
}
|
||||
function goAwesomeList () {
|
||||
sendToMain(OPEN_URL, 'https://github.com/PicGo/Awesome-PicGo')
|
||||
}
|
||||
|
||||
function handleImportLocalPlugin () {
|
||||
sendToMain('importLocalPlugin')
|
||||
loading.value = true
|
||||
}
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
ipcRenderer.removeAllListeners('pluginList')
|
||||
ipcRenderer.removeAllListeners('installPlugin')
|
||||
ipcRenderer.removeAllListeners('uninstallSuccess')
|
||||
ipcRenderer.removeAllListeners('updateSuccess')
|
||||
ipcRenderer.removeAllListeners('hideLoading')
|
||||
ipcRenderer.removeAllListeners(PICGO_HANDLE_PLUGIN_DONE)
|
||||
})
|
||||
|
||||
</script>
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'PluginPage'
|
||||
}
|
||||
</script>
|
||||
<style lang='stylus'>
|
||||
@ -451,6 +551,7 @@ $darwinBg = #172426
|
||||
.el-loading-mask
|
||||
background-color rgba(0, 0, 0, 0.8)
|
||||
.plugin-list
|
||||
align-content flex-start
|
||||
height: 339px;
|
||||
box-sizing: border-box;
|
||||
padding: 8px 15px;
|
||||
@ -471,6 +572,7 @@ $darwinBg = #172426
|
||||
margin 10px auto
|
||||
position relative
|
||||
i.el-icon-goods
|
||||
margin-left 4px
|
||||
font-size 20px
|
||||
vertical-align middle
|
||||
cursor pointer
|
||||
@ -500,8 +602,10 @@ $darwinBg = #172426
|
||||
padding 8px
|
||||
user-select text
|
||||
transition all .2s ease-in-out
|
||||
margin-bottom 10px
|
||||
position relative
|
||||
&__container
|
||||
height 80px
|
||||
margin-bottom 10px
|
||||
.cli-only-badge
|
||||
position absolute
|
||||
right 0px
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div id="rename-page">
|
||||
<el-form
|
||||
@submit.native.prevent
|
||||
@submit.prevent
|
||||
>
|
||||
<el-form-item
|
||||
:label="$T('FILE_RENAME')"
|
||||
@ -9,54 +9,67 @@
|
||||
<el-input
|
||||
v-model="fileName"
|
||||
size="small"
|
||||
@keyup.enter.native="confirmName"
|
||||
></el-input>
|
||||
@keyup.enter="confirmName"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-row>
|
||||
<div class="pull-right">
|
||||
<el-button @click="cancel" round size="mini">{{ $T('CANCEL') }}</el-button>
|
||||
<el-button type="primary" @click="confirmName" round size="mini">{{ $T('CONFIRM') }}</el-button>
|
||||
<el-button
|
||||
round
|
||||
size="small"
|
||||
@click="cancel"
|
||||
>
|
||||
{{ $T('CANCEL') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
round
|
||||
size="small"
|
||||
@click="confirmName"
|
||||
>
|
||||
{{ $T('CONFIRM') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
<script lang="ts" setup>
|
||||
import { RENAME_FILE_NAME } from '#/events/constants'
|
||||
import { Component, Vue } from 'vue-property-decorator'
|
||||
import mixin from '@/utils/mixin'
|
||||
import { sendToMain } from '@/utils/dataSender'
|
||||
import {
|
||||
ipcRenderer,
|
||||
IpcRendererEvent
|
||||
} from 'electron'
|
||||
@Component({
|
||||
name: 'rename-page',
|
||||
mixins: [mixin]
|
||||
import { onBeforeUnmount, onBeforeMount, ref } from 'vue'
|
||||
const fileName = ref('')
|
||||
const originName = ref('')
|
||||
const id = ref<string | null>(null)
|
||||
onBeforeMount(() => {
|
||||
ipcRenderer.on(RENAME_FILE_NAME, (event: IpcRendererEvent, newName: string, _originName: string, _id: string) => {
|
||||
fileName.value = newName
|
||||
originName.value = _originName
|
||||
id.value = _id
|
||||
})
|
||||
})
|
||||
export default class extends Vue {
|
||||
fileName: string = ''
|
||||
originName: string = ''
|
||||
id: string | null = null
|
||||
created () {
|
||||
ipcRenderer.on(RENAME_FILE_NAME, (event: IpcRendererEvent, newName: string, originName: string, id: string) => {
|
||||
this.fileName = newName
|
||||
this.originName = originName
|
||||
this.id = id
|
||||
})
|
||||
}
|
||||
|
||||
confirmName () {
|
||||
ipcRenderer.send(`${RENAME_FILE_NAME}${this.id}`, this.fileName)
|
||||
}
|
||||
function confirmName () {
|
||||
sendToMain(`${RENAME_FILE_NAME}${id.value}`, fileName.value)
|
||||
}
|
||||
|
||||
cancel () {
|
||||
// if cancel, use origin file name
|
||||
ipcRenderer.send(`${RENAME_FILE_NAME}${this.id}`, this.originName)
|
||||
}
|
||||
function cancel () {
|
||||
// if cancel, use origin file name
|
||||
sendToMain(`${RENAME_FILE_NAME}${id.value}`, originName.value)
|
||||
}
|
||||
|
||||
beforeDestroy () {
|
||||
ipcRenderer.removeAllListeners('rename')
|
||||
}
|
||||
onBeforeUnmount(() => {
|
||||
ipcRenderer.removeAllListeners('rename')
|
||||
})
|
||||
|
||||
</script>
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'RenamePage'
|
||||
}
|
||||
</script>
|
||||
<style lang='stylus'>
|
||||
|
@ -4,18 +4,21 @@
|
||||
{{ $T('SETTINGS_SET_SHORTCUT') }}
|
||||
</div>
|
||||
<el-row>
|
||||
<el-col :span="20" :offset="2">
|
||||
<el-col
|
||||
:span="20"
|
||||
:offset="2"
|
||||
>
|
||||
<el-table
|
||||
class="shortcut-page-table-border"
|
||||
:data="list"
|
||||
size="mini"
|
||||
size="small"
|
||||
header-cell-class-name="shortcut-page-table-border"
|
||||
cell-class-name="shortcut-page-table-border"
|
||||
>
|
||||
<el-table-column
|
||||
:label="$T('SHORTCUT_NAME')"
|
||||
>
|
||||
<template slot-scope="scope">
|
||||
<template #default="scope">
|
||||
{{ scope.row.label ? scope.row.label : scope.row.name }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
@ -23,14 +26,13 @@
|
||||
width="160px"
|
||||
:label="$T('SHORTCUT_BIND')"
|
||||
prop="key"
|
||||
>
|
||||
</el-table-column>
|
||||
/>
|
||||
<el-table-column
|
||||
:label="$T('SHORTCUT_STATUS')"
|
||||
>
|
||||
<template slot-scope="scope">
|
||||
<template #default="scope">
|
||||
<el-tag
|
||||
size="mini"
|
||||
size="small"
|
||||
:type="scope.row.enable ? 'success' : 'danger'"
|
||||
>
|
||||
{{ scope.row.enable ? $T('SHORTCUT_ENABLED') : $T('SHORTCUT_DISABLED') }}
|
||||
@ -41,38 +43,43 @@
|
||||
:label="$T('SHORTCUT_SOURCE')"
|
||||
width="100px"
|
||||
>
|
||||
<template slot-scope="scope">
|
||||
<template #default="scope">
|
||||
{{ calcOriginShowName(scope.row.from) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
:label="$T('SHORTCUT_HANDLE')"
|
||||
width="100px"
|
||||
>
|
||||
<template slot-scope="scope">
|
||||
<el-button
|
||||
@click="toggleEnable(scope.row)"
|
||||
size="mini"
|
||||
:class="{
|
||||
disabled: scope.row.enable
|
||||
}"
|
||||
type="text">
|
||||
{{ scope.row.enable ? $T('SHORTCUT_DISABLE') : $T('SHORTCUT_ENABLE') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
class="edit"
|
||||
size="mini"
|
||||
@click="openKeyBindingDialog(scope.row, scope.$index)"
|
||||
type="text">
|
||||
{{ $T('SHORTCUT_EDIT') }}
|
||||
</el-button>
|
||||
<template #default="scope">
|
||||
<el-row>
|
||||
<el-button
|
||||
size="small"
|
||||
:class="{
|
||||
disabled: scope.row.enable
|
||||
}"
|
||||
type="text"
|
||||
@click="toggleEnable(scope.row)"
|
||||
>
|
||||
{{ scope.row.enable ? $T('SHORTCUT_DISABLE') : $T('SHORTCUT_ENABLE') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
class="edit"
|
||||
size="small"
|
||||
type="text"
|
||||
@click="openKeyBindingDialog(scope.row, scope.$index)"
|
||||
>
|
||||
{{ $T('SHORTCUT_EDIT') }}
|
||||
</el-button>
|
||||
</el-row>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-dialog
|
||||
v-model="keyBindingVisible"
|
||||
:title="$T('SHORTCUT_CHANGE_UPLOAD')"
|
||||
:visible.sync="keyBindingVisible"
|
||||
:modal-append-to-body="false"
|
||||
>
|
||||
<el-form
|
||||
@ -81,101 +88,109 @@
|
||||
>
|
||||
<el-form-item>
|
||||
<el-input
|
||||
class="align-center"
|
||||
@keydown.native.prevent="keyDetect($event)"
|
||||
v-model="shortKey"
|
||||
class="align-center"
|
||||
:autofocus="true"
|
||||
></el-input>
|
||||
@keydown.prevent="keyDetect($event as KeyboardEvent)"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer">
|
||||
<el-button @click="cancelKeyBinding" round>
|
||||
<template #footer>
|
||||
<el-button
|
||||
round
|
||||
@click="cancelKeyBinding"
|
||||
>
|
||||
{{ $T('CANCEL') }}
|
||||
</el-button>
|
||||
<el-button type="primary" @click="confirmKeyBinding" round>
|
||||
<el-button
|
||||
type="primary"
|
||||
round
|
||||
@click="confirmKeyBinding"
|
||||
>
|
||||
{{ $T('CONFIRM') }}
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { Component, Vue, Watch } from 'vue-property-decorator'
|
||||
import keyDetect from '@/utils/key-binding'
|
||||
<script lang="ts" setup>
|
||||
import keyBinding from '@/utils/key-binding'
|
||||
import { ipcRenderer, IpcRendererEvent } from 'electron'
|
||||
import { TOGGLE_SHORTKEY_MODIFIED_MODE } from '#/events/constants'
|
||||
import { onBeforeUnmount, onBeforeMount, ref, watch } from 'vue'
|
||||
import { getConfig, sendToMain } from '@/utils/dataSender'
|
||||
|
||||
@Component({
|
||||
name: 'shortkey-page'
|
||||
const list = ref<IShortKeyConfig[]>([])
|
||||
const keyBindingVisible = ref(false)
|
||||
const command = ref('')
|
||||
const shortKey = ref('')
|
||||
const currentIndex = ref(0)
|
||||
|
||||
onBeforeMount(async () => {
|
||||
const shortKeyConfig = (await getConfig<IShortKeyConfigs>('settings.shortKey'))!
|
||||
list.value = Object.keys(shortKeyConfig).map(item => {
|
||||
return {
|
||||
...shortKeyConfig[item],
|
||||
from: calcOrigin(item)
|
||||
}
|
||||
})
|
||||
})
|
||||
export default class extends Vue {
|
||||
list: IShortKeyConfig[] = []
|
||||
keyBindingVisible = false
|
||||
command = ''
|
||||
shortKey = ''
|
||||
currentIndex = 0
|
||||
async created () {
|
||||
const shortKeyConfig = (await this.getConfig<IShortKeyConfigs>('settings.shortKey'))!
|
||||
this.list = Object.keys(shortKeyConfig).map(item => {
|
||||
return {
|
||||
...shortKeyConfig[item],
|
||||
from: this.calcOrigin(item)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@Watch('keyBindingVisible')
|
||||
onKeyBindingVisibleChange (val: boolean) {
|
||||
ipcRenderer.send(TOGGLE_SHORTKEY_MODIFIED_MODE, val)
|
||||
}
|
||||
watch(keyBindingVisible, (val: boolean) => {
|
||||
sendToMain(TOGGLE_SHORTKEY_MODIFIED_MODE, val)
|
||||
})
|
||||
|
||||
calcOrigin (item: string) {
|
||||
const [origin] = item.split(':')
|
||||
return origin
|
||||
}
|
||||
function calcOrigin (item: string) {
|
||||
const [origin] = item.split(':')
|
||||
return origin
|
||||
}
|
||||
|
||||
calcOriginShowName (item: string) {
|
||||
return item.replace('picgo-plugin-', '')
|
||||
}
|
||||
function calcOriginShowName (item: string) {
|
||||
return item.replace('picgo-plugin-', '')
|
||||
}
|
||||
|
||||
toggleEnable (item: IShortKeyConfig) {
|
||||
const status = !item.enable
|
||||
item.enable = status
|
||||
ipcRenderer.send('bindOrUnbindShortKey', item, item.from)
|
||||
}
|
||||
function toggleEnable (item: IShortKeyConfig) {
|
||||
const status = !item.enable
|
||||
item.enable = status
|
||||
sendToMain('bindOrUnbindShortKey', item, item.from)
|
||||
}
|
||||
|
||||
keyDetect (event: KeyboardEvent) {
|
||||
this.shortKey = keyDetect(event).join('+')
|
||||
}
|
||||
function keyDetect (event: KeyboardEvent) {
|
||||
shortKey.value = keyBinding(event).join('+')
|
||||
}
|
||||
|
||||
async openKeyBindingDialog (config: IShortKeyConfig, index: number) {
|
||||
this.command = `${config.from}:${config.name}`
|
||||
this.shortKey = await this.getConfig(`settings.shortKey.${this.command}.key`) || ''
|
||||
this.currentIndex = index
|
||||
this.keyBindingVisible = true
|
||||
}
|
||||
async function openKeyBindingDialog (config: IShortKeyConfig, index: number) {
|
||||
command.value = `${config.from}:${config.name}`
|
||||
shortKey.value = await getConfig(`settings.shortKey.${command.value}.key`) || ''
|
||||
currentIndex.value = index
|
||||
keyBindingVisible.value = true
|
||||
}
|
||||
|
||||
async cancelKeyBinding () {
|
||||
this.keyBindingVisible = false
|
||||
this.shortKey = await this.getConfig<string>(`settings.shortKey.${this.command}.key`) || ''
|
||||
}
|
||||
async function cancelKeyBinding () {
|
||||
keyBindingVisible.value = false
|
||||
shortKey.value = await getConfig<string>(`settings.shortKey.${command.value}.key`) || ''
|
||||
}
|
||||
|
||||
async confirmKeyBinding () {
|
||||
const oldKey = await this.getConfig<string>(`settings.shortKey.${this.command}.key`)
|
||||
const config = Object.assign({}, this.list[this.currentIndex])
|
||||
config.key = this.shortKey
|
||||
ipcRenderer.send('updateShortKey', config, oldKey, config.from)
|
||||
ipcRenderer.once('updateShortKeyResponse', (evt: IpcRendererEvent, result) => {
|
||||
if (result) {
|
||||
this.keyBindingVisible = false
|
||||
this.list[this.currentIndex].key = this.shortKey
|
||||
}
|
||||
})
|
||||
}
|
||||
async function confirmKeyBinding () {
|
||||
const oldKey = await getConfig<string>(`settings.shortKey.${command.value}.key`)
|
||||
const config = Object.assign({}, list.value[currentIndex.value])
|
||||
config.key = shortKey.value
|
||||
sendToMain('updateShortKey', config, oldKey, config.from)
|
||||
ipcRenderer.once('updateShortKeyResponse', (evt: IpcRendererEvent, result) => {
|
||||
if (result) {
|
||||
keyBindingVisible.value = false
|
||||
list.value[currentIndex.value].key = shortKey.value
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
beforeDestroy () {
|
||||
ipcRenderer.send(TOGGLE_SHORTKEY_MODIFIED_MODE, false)
|
||||
}
|
||||
onBeforeUnmount(() => {
|
||||
sendToMain(TOGGLE_SHORTKEY_MODIFIED_MODE, false)
|
||||
})
|
||||
</script>
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'ShortkeyPage'
|
||||
}
|
||||
</script>
|
||||
<style lang='stylus'>
|
||||
@ -191,6 +206,9 @@ export default class extends Vue {
|
||||
color: #F56C6C
|
||||
&.edit
|
||||
color: #67C23A
|
||||
&--text
|
||||
padding-left 4px
|
||||
padding-right 4px
|
||||
.el-table
|
||||
background-color: transparent
|
||||
color #ddd
|
||||
@ -209,4 +227,6 @@ export default class extends Vue {
|
||||
tr:hover
|
||||
&>td
|
||||
background #333
|
||||
.el-button+.el-button
|
||||
margin-left 4px
|
||||
</style>
|
||||
|
@ -1,24 +1,59 @@
|
||||
<template>
|
||||
<div id="tray-page">
|
||||
<div class="open-main-window" @click="openSettingWindow">{{ $T('OPEN_MAIN_WINDOW') }}</div>
|
||||
<div
|
||||
class="open-main-window"
|
||||
@click="openSettingWindow"
|
||||
>
|
||||
{{ $T('OPEN_MAIN_WINDOW') }}
|
||||
</div>
|
||||
<div class="content">
|
||||
<div class="wait-upload-img" v-if="clipboardFiles.length > 0">
|
||||
<div class="list-title">{{ $T('WAIT_TO_UPLOAD') }}</div>
|
||||
<div v-for="(item, index) in clipboardFiles" :key="index" class="img-list">
|
||||
<div
|
||||
v-if="clipboardFiles.length > 0"
|
||||
class="wait-upload-img"
|
||||
>
|
||||
<div class="list-title">
|
||||
{{ $T('WAIT_TO_UPLOAD') }}
|
||||
</div>
|
||||
<div
|
||||
v-for="(item, index) in clipboardFiles"
|
||||
:key="index"
|
||||
class="img-list"
|
||||
>
|
||||
<div
|
||||
class="upload-img__container"
|
||||
:class="{ upload: uploadFlag }"
|
||||
@click="uploadClipboardFiles">
|
||||
<img :src="item.imgUrl" class="upload-img">
|
||||
@click="uploadClipboardFiles"
|
||||
>
|
||||
<img
|
||||
:src="item.imgUrl"
|
||||
class="upload-img"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="uploaded-img">
|
||||
<div class="list-title">{{ $T('ALREADY_UPLOAD') }}</div>
|
||||
<div v-for="item in files" :key="item.imgUrl" class="img-list">
|
||||
<div class="upload-img__container" @click="copyTheLink(item)">
|
||||
<img v-lazy="item.imgUrl" class="upload-img">
|
||||
<div class="upload-img__title" :title="item.fileName">{{ item.fileName }}</div>
|
||||
<div class="list-title">
|
||||
{{ $T('ALREADY_UPLOAD') }}
|
||||
</div>
|
||||
<div
|
||||
v-for="item in files"
|
||||
:key="item.imgUrl"
|
||||
class="img-list"
|
||||
>
|
||||
<div
|
||||
class="upload-img__container"
|
||||
@click="copyTheLink(item)"
|
||||
>
|
||||
<img
|
||||
v-lazy="item.imgUrl"
|
||||
class="upload-img"
|
||||
>
|
||||
<div
|
||||
class="upload-img__title"
|
||||
:title="item.fileName"
|
||||
>
|
||||
{{ item.fileName }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -26,99 +61,100 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from 'vue-property-decorator'
|
||||
import mixin from '@/utils/mixin'
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref, onBeforeUnmount, onBeforeMount } from 'vue'
|
||||
import { ipcRenderer } from 'electron'
|
||||
import $$db from '@/utils/db'
|
||||
import { T as $T } from '@/i18n/index'
|
||||
import { IResult } from '@picgo/store/dist/types'
|
||||
import { PASTE_TEXT, OPEN_WINDOW } from '#/events/constants'
|
||||
import { IWindowList } from '#/types/enum'
|
||||
import { sendToMain } from '@/utils/dataSender'
|
||||
|
||||
@Component({
|
||||
name: 'tray-page',
|
||||
mixins: [mixin]
|
||||
const files = ref<IResult<ImgInfo>[]>([])
|
||||
const notification = reactive({
|
||||
title: $T('COPY_LINK_SUCCEED'),
|
||||
body: ''
|
||||
})
|
||||
export default class extends Vue {
|
||||
files: IResult<ImgInfo>[] = []
|
||||
notification = {
|
||||
title: this.$T('COPY_LINK_SUCCEED'),
|
||||
body: ''
|
||||
}
|
||||
|
||||
clipboardFiles: ImgInfo[] = []
|
||||
uploadFlag = false
|
||||
get reverseList () {
|
||||
return this.files.slice().reverse()
|
||||
}
|
||||
const clipboardFiles = ref<ImgInfo[]>([])
|
||||
const uploadFlag = ref(false)
|
||||
|
||||
openSettingWindow () {
|
||||
this.sendToMain(OPEN_WINDOW, IWindowList.SETTING_WINDOW)
|
||||
}
|
||||
// const reverseList = computed(() => files.value.slice().reverse())
|
||||
|
||||
async getData () {
|
||||
this.files = (await this.$$db.get<ImgInfo>({ orderBy: 'desc', limit: 5 })).data
|
||||
}
|
||||
function openSettingWindow () {
|
||||
sendToMain(OPEN_WINDOW, IWindowList.SETTING_WINDOW)
|
||||
}
|
||||
|
||||
async copyTheLink (item: ImgInfo) {
|
||||
this.notification.body = item.imgUrl!
|
||||
const myNotification = new Notification(this.notification.title, this.notification)
|
||||
ipcRenderer.invoke(PASTE_TEXT, item)
|
||||
myNotification.onclick = () => {
|
||||
return true
|
||||
async function getData () {
|
||||
files.value = (await $$db.get<ImgInfo>({ orderBy: 'desc', limit: 5 })).data
|
||||
}
|
||||
|
||||
async function copyTheLink (item: ImgInfo) {
|
||||
notification.body = item.imgUrl!
|
||||
const myNotification = new Notification(notification.title, notification)
|
||||
ipcRenderer.invoke(PASTE_TEXT, item)
|
||||
myNotification.onclick = () => {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// function calcHeight (width: number, height: number): number {
|
||||
// return height * 160 / width
|
||||
// }
|
||||
|
||||
function disableDragFile () {
|
||||
window.addEventListener('dragover', (e) => {
|
||||
e = e || event
|
||||
e.preventDefault()
|
||||
}, false)
|
||||
window.addEventListener('drop', (e) => {
|
||||
e = e || event
|
||||
e.preventDefault()
|
||||
}, false)
|
||||
}
|
||||
|
||||
function uploadClipboardFiles () {
|
||||
if (uploadFlag.value) {
|
||||
return
|
||||
}
|
||||
uploadFlag.value = true
|
||||
sendToMain('uploadClipboardFiles')
|
||||
}
|
||||
|
||||
onBeforeMount(() => {
|
||||
disableDragFile()
|
||||
getData()
|
||||
ipcRenderer.on('dragFiles', async (event: Event, _files: string[]) => {
|
||||
for (let i = 0; i < _files.length; i++) {
|
||||
const item = _files[i]
|
||||
await $$db.insert(item)
|
||||
}
|
||||
}
|
||||
files.value = (await $$db.get<ImgInfo>({ orderBy: 'desc', limit: 5 })).data
|
||||
})
|
||||
ipcRenderer.on('clipboardFiles', (event: Event, files: ImgInfo[]) => {
|
||||
clipboardFiles.value = files
|
||||
})
|
||||
ipcRenderer.on('uploadFiles', async () => {
|
||||
files.value = (await $$db.get<ImgInfo>({ orderBy: 'desc', limit: 5 })).data
|
||||
uploadFlag.value = false
|
||||
})
|
||||
ipcRenderer.on('updateFiles', () => {
|
||||
getData()
|
||||
})
|
||||
})
|
||||
|
||||
calcHeight (width: number, height: number): number {
|
||||
return height * 160 / width
|
||||
}
|
||||
onBeforeUnmount(() => {
|
||||
ipcRenderer.removeAllListeners('dragFiles')
|
||||
ipcRenderer.removeAllListeners('clipboardFiles')
|
||||
ipcRenderer.removeAllListeners('uploadClipboardFiles')
|
||||
ipcRenderer.removeAllListeners('updateFiles')
|
||||
})
|
||||
</script>
|
||||
|
||||
disableDragFile () {
|
||||
window.addEventListener('dragover', (e) => {
|
||||
e = e || event
|
||||
e.preventDefault()
|
||||
}, false)
|
||||
window.addEventListener('drop', (e) => {
|
||||
e = e || event
|
||||
e.preventDefault()
|
||||
}, false)
|
||||
}
|
||||
|
||||
uploadClipboardFiles () {
|
||||
if (this.uploadFlag) {
|
||||
return
|
||||
}
|
||||
this.uploadFlag = true
|
||||
ipcRenderer.send('uploadClipboardFiles')
|
||||
}
|
||||
|
||||
mounted () {
|
||||
this.disableDragFile()
|
||||
this.getData()
|
||||
ipcRenderer.on('dragFiles', async (event: Event, files: string[]) => {
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const item = files[i]
|
||||
await this.$$db.insert(item)
|
||||
}
|
||||
this.files = (await this.$$db.get<ImgInfo>({ orderBy: 'desc', limit: 5 })).data
|
||||
})
|
||||
ipcRenderer.on('clipboardFiles', (event: Event, files: ImgInfo[]) => {
|
||||
this.clipboardFiles = files
|
||||
})
|
||||
ipcRenderer.on('uploadFiles', async () => {
|
||||
this.files = (await this.$$db.get<ImgInfo>({ orderBy: 'desc', limit: 5 })).data
|
||||
this.uploadFlag = false
|
||||
})
|
||||
ipcRenderer.on('updateFiles', () => {
|
||||
this.getData()
|
||||
})
|
||||
}
|
||||
|
||||
beforeDestroy () {
|
||||
ipcRenderer.removeAllListeners('dragFiles')
|
||||
ipcRenderer.removeAllListeners('clipboardFiles')
|
||||
ipcRenderer.removeAllListeners('uploadClipboardFiles')
|
||||
ipcRenderer.removeAllListeners('updateFiles')
|
||||
}
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'TrayPage'
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -179,11 +215,20 @@ body::-webkit-scrollbar
|
||||
background #49B1F5
|
||||
.upload-img__index
|
||||
color #fff
|
||||
.upload-img__container
|
||||
display flex
|
||||
flex-direction column
|
||||
justify-content center
|
||||
align-items center
|
||||
.upload-img
|
||||
width 100%
|
||||
max-width 100%
|
||||
object-fit scale-down
|
||||
margin 0 auto
|
||||
&__container
|
||||
display flex
|
||||
flex-direction column
|
||||
justify-content center
|
||||
align-items center
|
||||
width 100%
|
||||
padding 8px 8px 4px
|
||||
height 100%
|
||||
|
@ -1,9 +1,18 @@
|
||||
<template>
|
||||
<div id="upload-view">
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="20" :offset="2">
|
||||
<el-col
|
||||
:span="20"
|
||||
:offset="2"
|
||||
>
|
||||
<div class="view-title">
|
||||
{{ $T('PICTURE_UPLOAD') }} - {{ picBedName }} <i class="el-icon-caret-bottom" @click="handleChangePicBed"></i>
|
||||
{{ $T('PICTURE_UPLOAD') }} - {{ picBedName }}
|
||||
<el-icon
|
||||
style="cursor: pointer; margin-left: 4px;"
|
||||
@click="handleChangePicBed"
|
||||
>
|
||||
<CaretBottom />
|
||||
</el-icon>
|
||||
</div>
|
||||
<div
|
||||
id="upload-area"
|
||||
@ -12,12 +21,22 @@
|
||||
@dragover.prevent="dragover = true"
|
||||
@dragleave.prevent="dragover = false"
|
||||
>
|
||||
<div id="upload-dragger" @click="openUplodWindow">
|
||||
<i class="el-icon-upload"></i>
|
||||
<div
|
||||
id="upload-dragger"
|
||||
@click="openUplodWindow"
|
||||
>
|
||||
<el-icon>
|
||||
<UploadFilled />
|
||||
</el-icon>
|
||||
<div class="upload-dragger__text">
|
||||
{{ $T('DRAG_FILE_TO_HERE') }} <span>{{ $T('CLICK_TO_UPLOAD') }}</span>
|
||||
</div>
|
||||
<input type="file" id="file-uploader" @change="onChange" multiple>
|
||||
<input
|
||||
id="file-uploader"
|
||||
type="file"
|
||||
multiple
|
||||
@change="onChange"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<el-progress
|
||||
@ -26,42 +45,69 @@
|
||||
class="upload-progress"
|
||||
:class="{ 'show': showProgress }"
|
||||
:status="showError ? 'exception' : undefined"
|
||||
></el-progress>
|
||||
/>
|
||||
<div class="paste-style">
|
||||
<div class="el-col-16">
|
||||
<div class="paste-style__text">
|
||||
{{ $T('LINK_FORMAT') }}
|
||||
</div>
|
||||
<el-radio-group v-model="pasteStyle" size="mini"
|
||||
<el-radio-group
|
||||
v-model="pasteStyle"
|
||||
size="small"
|
||||
@change="handlePasteStyleChange"
|
||||
>
|
||||
<el-radio-button label="markdown">
|
||||
Markdown
|
||||
</el-radio-button>
|
||||
<el-radio-button label="HTML"></el-radio-button>
|
||||
<el-radio-button label="URL"></el-radio-button>
|
||||
<el-radio-button label="UBB"></el-radio-button>
|
||||
<el-radio-button label="Custom" :title="$T('CUSTOM')"></el-radio-button>
|
||||
<el-radio-button label="HTML" />
|
||||
<el-radio-button label="URL" />
|
||||
<el-radio-button label="UBB" />
|
||||
<el-radio-button
|
||||
label="Custom"
|
||||
:title="$T('CUSTOM')"
|
||||
/>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
<div class="el-col-8">
|
||||
<div class="paste-style__text">
|
||||
{{ $T('QUICK_UPLOAD') }}
|
||||
</div>
|
||||
<el-button type="primary" round size="mini" @click="uploadClipboardFiles" class="quick-upload" style="width: 50%">{{ $T('CLIPBOARD_PICTURE') }}</el-button>
|
||||
<el-button type="primary" round size="mini" @click="uploadURLFiles" class="quick-upload" style="width: 46%; margin-left: 6px">URL</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
round
|
||||
size="small"
|
||||
class="quick-upload"
|
||||
style="width: 50%"
|
||||
@click="uploadClipboardFiles"
|
||||
>
|
||||
{{ $T('CLIPBOARD_PICTURE') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
round
|
||||
size="small"
|
||||
class="quick-upload"
|
||||
style="width: 46%; margin-left: 6px"
|
||||
@click="uploadURLFiles"
|
||||
>
|
||||
URL
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { Component, Vue, Watch } from 'vue-property-decorator'
|
||||
<script lang="ts" setup>
|
||||
// import { Component, Vue, Watch } from 'vue-property-decorator'
|
||||
import { UploadFilled, CaretBottom } from '@element-plus/icons-vue'
|
||||
import {
|
||||
ipcRenderer,
|
||||
IpcRendererEvent
|
||||
} from 'electron'
|
||||
import { ref, onBeforeMount, onBeforeUnmount, watch } from 'vue'
|
||||
import { T as $T } from '@/i18n'
|
||||
import $bus from '@/utils/bus'
|
||||
import {
|
||||
SHOW_INPUT_BOX,
|
||||
SHOW_INPUT_BOX_RESPONSE,
|
||||
@ -71,170 +117,176 @@ import {
|
||||
import {
|
||||
isUrl
|
||||
} from '~/universal/utils/common'
|
||||
@Component({
|
||||
name: 'upload'
|
||||
import { ElMessage as $message } from 'element-plus'
|
||||
import { getConfig, saveConfig, sendToMain } from '@/utils/dataSender'
|
||||
const dragover = ref(false)
|
||||
const progress = ref(0)
|
||||
const showProgress = ref(false)
|
||||
const showError = ref(false)
|
||||
const pasteStyle = ref('')
|
||||
const picBed = ref<IPicBedType[]>([])
|
||||
const picBedName = ref('')
|
||||
onBeforeMount(() => {
|
||||
ipcRenderer.on('uploadProgress', (event: IpcRendererEvent, _progress: number) => {
|
||||
if (_progress !== -1) {
|
||||
showProgress.value = true
|
||||
progress.value = _progress
|
||||
} else {
|
||||
progress.value = 100
|
||||
showError.value = true
|
||||
}
|
||||
})
|
||||
getPasteStyle()
|
||||
getDefaultPicBed()
|
||||
ipcRenderer.on('syncPicBed', () => {
|
||||
getDefaultPicBed()
|
||||
})
|
||||
sendToMain(GET_PICBEDS)
|
||||
ipcRenderer.on(GET_PICBEDS, getPicBeds)
|
||||
$bus.on(SHOW_INPUT_BOX_RESPONSE, handleInputBoxValue)
|
||||
})
|
||||
export default class extends Vue {
|
||||
dragover = false
|
||||
progress = 0
|
||||
showProgress = false
|
||||
showError = false
|
||||
pasteStyle = ''
|
||||
picBed: IPicBedType[] = []
|
||||
picBedName = ''
|
||||
mounted () {
|
||||
ipcRenderer.on('uploadProgress', (event: IpcRendererEvent, progress: number) => {
|
||||
if (progress !== -1) {
|
||||
this.showProgress = true
|
||||
this.progress = progress
|
||||
} else {
|
||||
this.progress = 100
|
||||
this.showError = true
|
||||
}
|
||||
})
|
||||
this.getPasteStyle()
|
||||
this.getDefaultPicBed()
|
||||
ipcRenderer.on('syncPicBed', () => {
|
||||
this.getDefaultPicBed()
|
||||
})
|
||||
ipcRenderer.send(GET_PICBEDS)
|
||||
ipcRenderer.on(GET_PICBEDS, this.getPicBeds)
|
||||
this.$bus.$on(SHOW_INPUT_BOX_RESPONSE, this.handleInputBoxValue)
|
||||
}
|
||||
|
||||
@Watch('progress')
|
||||
onProgressChange (val: number) {
|
||||
if (val === 100) {
|
||||
setTimeout(() => {
|
||||
this.showProgress = false
|
||||
this.showError = false
|
||||
}, 1000)
|
||||
setTimeout(() => {
|
||||
this.progress = 0
|
||||
}, 1200)
|
||||
}
|
||||
}
|
||||
watch(progress, onProgressChange)
|
||||
|
||||
beforeDestroy () {
|
||||
this.$bus.$off(SHOW_INPUT_BOX_RESPONSE)
|
||||
ipcRenderer.removeAllListeners('uploadProgress')
|
||||
ipcRenderer.removeAllListeners('syncPicBed')
|
||||
ipcRenderer.removeListener(GET_PICBEDS, this.getPicBeds)
|
||||
function onProgressChange (val: number) {
|
||||
if (val === 100) {
|
||||
setTimeout(() => {
|
||||
showProgress.value = false
|
||||
showError.value = false
|
||||
}, 1000)
|
||||
setTimeout(() => {
|
||||
progress.value = 0
|
||||
}, 1200)
|
||||
}
|
||||
}
|
||||
|
||||
onDrop (e: DragEvent) {
|
||||
this.dragover = false
|
||||
const items = e.dataTransfer!.items
|
||||
if (items.length === 2 && items[0].type === 'text/uri-list') {
|
||||
this.handleURLDrag(items, e.dataTransfer!)
|
||||
} else if (items[0].type === 'text/plain') {
|
||||
const str = e.dataTransfer!.getData(items[0].type)
|
||||
if (isUrl(str)) {
|
||||
ipcRenderer.send('uploadChoosedFiles', [{ path: str }])
|
||||
} else {
|
||||
this.$message.error(this.$T('TIPS_DRAG_VALID_PICTURE_OR_URL'))
|
||||
}
|
||||
onBeforeUnmount(() => {
|
||||
$bus.off(SHOW_INPUT_BOX_RESPONSE)
|
||||
ipcRenderer.removeAllListeners('uploadProgress')
|
||||
ipcRenderer.removeAllListeners('syncPicBed')
|
||||
ipcRenderer.removeListener(GET_PICBEDS, getPicBeds)
|
||||
})
|
||||
|
||||
function onDrop (e: DragEvent) {
|
||||
dragover.value = false
|
||||
const items = e.dataTransfer!.items
|
||||
if (items.length === 2 && items[0].type === 'text/uri-list') {
|
||||
handleURLDrag(items, e.dataTransfer!)
|
||||
} else if (items[0].type === 'text/plain') {
|
||||
const str = e.dataTransfer!.getData(items[0].type)
|
||||
if (isUrl(str)) {
|
||||
sendToMain('uploadChoosedFiles', [{ path: str }])
|
||||
} else {
|
||||
this.ipcSendFiles(e.dataTransfer!.files)
|
||||
$message.error($T('TIPS_DRAG_VALID_PICTURE_OR_URL'))
|
||||
}
|
||||
} else {
|
||||
ipcSendFiles(e.dataTransfer!.files)
|
||||
}
|
||||
}
|
||||
|
||||
handleURLDrag (items: DataTransferItemList, dataTransfer: DataTransfer) {
|
||||
// text/html
|
||||
// Use this data to get a more precise URL
|
||||
const urlString = dataTransfer.getData(items[1].type)
|
||||
const urlMatch = urlString.match(/<img.*src="(.*?)"/)
|
||||
if (urlMatch) {
|
||||
ipcRenderer.send('uploadChoosedFiles', [
|
||||
{
|
||||
path: urlMatch[1]
|
||||
}
|
||||
])
|
||||
} else {
|
||||
this.$message.error(this.$T('TIPS_DRAG_VALID_PICTURE_OR_URL'))
|
||||
}
|
||||
}
|
||||
|
||||
openUplodWindow () {
|
||||
document.getElementById('file-uploader')!.click()
|
||||
}
|
||||
|
||||
onChange (e: any) {
|
||||
this.ipcSendFiles(e.target.files);
|
||||
(document.getElementById('file-uploader') as HTMLInputElement).value = ''
|
||||
}
|
||||
|
||||
ipcSendFiles (files: FileList) {
|
||||
const sendFiles: IFileWithPath[] = []
|
||||
Array.from(files).forEach((item) => {
|
||||
const obj = {
|
||||
name: item.name,
|
||||
path: item.path
|
||||
function handleURLDrag (items: DataTransferItemList, dataTransfer: DataTransfer) {
|
||||
// text/html
|
||||
// Use this data to get a more precise URL
|
||||
const urlString = dataTransfer.getData(items[1].type)
|
||||
const urlMatch = urlString.match(/<img.*src="(.*?)"/)
|
||||
if (urlMatch) {
|
||||
sendToMain('uploadChoosedFiles', [
|
||||
{
|
||||
path: urlMatch[1]
|
||||
}
|
||||
sendFiles.push(obj)
|
||||
})
|
||||
ipcRenderer.send('uploadChoosedFiles', sendFiles)
|
||||
])
|
||||
} else {
|
||||
$message.error($T('TIPS_DRAG_VALID_PICTURE_OR_URL'))
|
||||
}
|
||||
}
|
||||
|
||||
async getPasteStyle () {
|
||||
this.pasteStyle = await this.getConfig('settings.pasteStyle') || 'markdown'
|
||||
}
|
||||
function openUplodWindow () {
|
||||
document.getElementById('file-uploader')!.click()
|
||||
}
|
||||
|
||||
handlePasteStyleChange (val: string) {
|
||||
this.saveConfig({
|
||||
'settings.pasteStyle': val
|
||||
})
|
||||
}
|
||||
function onChange (e: any) {
|
||||
ipcSendFiles(e.target.files);
|
||||
(document.getElementById('file-uploader') as HTMLInputElement).value = ''
|
||||
}
|
||||
|
||||
uploadClipboardFiles () {
|
||||
ipcRenderer.send('uploadClipboardFilesFromUploadPage')
|
||||
}
|
||||
|
||||
async uploadURLFiles () {
|
||||
const str = await navigator.clipboard.readText()
|
||||
this.$bus.$emit(SHOW_INPUT_BOX, {
|
||||
value: isUrl(str) ? str : '',
|
||||
title: this.$T('TIPS_INPUT_URL'),
|
||||
placeholder: this.$T('TIPS_HTTP_PREFIX')
|
||||
})
|
||||
}
|
||||
|
||||
handleInputBoxValue (val: string) {
|
||||
if (val === '') return false
|
||||
if (isUrl(val)) {
|
||||
ipcRenderer.send('uploadChoosedFiles', [{
|
||||
path: val
|
||||
}])
|
||||
} else {
|
||||
this.$message.error(this.$T('TIPS_INPUT_VALID_URL'))
|
||||
function ipcSendFiles (files: FileList) {
|
||||
const sendFiles: IFileWithPath[] = []
|
||||
Array.from(files).forEach((item) => {
|
||||
const obj = {
|
||||
name: item.name,
|
||||
path: item.path
|
||||
}
|
||||
}
|
||||
sendFiles.push(obj)
|
||||
})
|
||||
sendToMain('uploadChoosedFiles', sendFiles)
|
||||
}
|
||||
|
||||
async getDefaultPicBed () {
|
||||
const currentPicBed = await this.getConfig<string>('picBed.current')
|
||||
this.picBed.forEach(item => {
|
||||
if (item.type === currentPicBed) {
|
||||
this.picBedName = item.name
|
||||
}
|
||||
})
|
||||
}
|
||||
async function getPasteStyle () {
|
||||
pasteStyle.value = await getConfig('settings.pasteStyle') || 'markdown'
|
||||
}
|
||||
|
||||
getPicBeds (event: Event, picBeds: IPicBedType[]) {
|
||||
this.picBed = picBeds
|
||||
this.getDefaultPicBed()
|
||||
}
|
||||
function handlePasteStyleChange (val: string | number | boolean) {
|
||||
saveConfig({
|
||||
'settings.pasteStyle': val
|
||||
})
|
||||
}
|
||||
|
||||
async handleChangePicBed () {
|
||||
ipcRenderer.send(SHOW_UPLOAD_PAGE_MENU)
|
||||
function uploadClipboardFiles () {
|
||||
sendToMain('uploadClipboardFilesFromUploadPage')
|
||||
}
|
||||
|
||||
async function uploadURLFiles () {
|
||||
const str = await navigator.clipboard.readText()
|
||||
$bus.emit(SHOW_INPUT_BOX, {
|
||||
value: isUrl(str) ? str : '',
|
||||
title: $T('TIPS_INPUT_URL'),
|
||||
placeholder: $T('TIPS_HTTP_PREFIX')
|
||||
})
|
||||
}
|
||||
|
||||
function handleInputBoxValue (val: string) {
|
||||
if (val === '') return
|
||||
if (isUrl(val)) {
|
||||
sendToMain('uploadChoosedFiles', [{
|
||||
path: val
|
||||
}])
|
||||
} else {
|
||||
$message.error($T('TIPS_INPUT_VALID_URL'))
|
||||
}
|
||||
}
|
||||
|
||||
async function getDefaultPicBed () {
|
||||
const currentPicBed = await getConfig<string>('picBed.current')
|
||||
picBed.value.forEach(item => {
|
||||
if (item.type === currentPicBed) {
|
||||
picBedName.value = item.name
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function getPicBeds (event: Event, picBeds: IPicBedType[]) {
|
||||
picBed.value = picBeds
|
||||
getDefaultPicBed()
|
||||
}
|
||||
|
||||
async function handleChangePicBed () {
|
||||
sendToMain(SHOW_UPLOAD_PAGE_MENU)
|
||||
}
|
||||
</script>
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'UploadPage'
|
||||
}
|
||||
</script>
|
||||
<style lang='stylus'>
|
||||
.view-title
|
||||
display flex
|
||||
color #eee
|
||||
font-size 20px
|
||||
text-align center
|
||||
margin 10px auto
|
||||
align-items center
|
||||
justify-content center
|
||||
#upload-view
|
||||
.view-title
|
||||
margin 20px auto
|
||||
@ -275,6 +327,8 @@ export default class extends Vue {
|
||||
.paste-style
|
||||
text-align center
|
||||
margin-top 16px
|
||||
display flex
|
||||
align-items flex-end
|
||||
&__text
|
||||
font-size 12px
|
||||
color #eeeeee
|
||||
|
@ -3,11 +3,17 @@
|
||||
<div class="view-title">
|
||||
{{ $T('SETTINGS') }}
|
||||
</div>
|
||||
<el-row :gutter="15" justify="space-between" align="center" type="flex" class="config-list">
|
||||
<el-row
|
||||
:gutter="15"
|
||||
justify="space-between"
|
||||
align="middle"
|
||||
type="flex"
|
||||
class="config-list"
|
||||
>
|
||||
<el-col
|
||||
class="config-item-col"
|
||||
v-for="item in curConfigList"
|
||||
:key="item._id"
|
||||
class="config-item-col"
|
||||
:span="11"
|
||||
:offset="1"
|
||||
>
|
||||
@ -15,12 +21,32 @@
|
||||
:class="`config-item ${defaultConfigId === item._id ? 'selected' : ''}`"
|
||||
@click="() => selectItem(item._id)"
|
||||
>
|
||||
<div class="config-name">{{item._configName}}</div>
|
||||
<div class="config-update-time">{{formatTime(item._updatedAt)}}</div>
|
||||
<div v-if="defaultConfigId === item._id" class="default-text">{{$T('SELECTED_SETTING_HINT')}}</div>
|
||||
<div class="config-name">
|
||||
{{ item._configName }}
|
||||
</div>
|
||||
<div class="config-update-time">
|
||||
{{ formatTime(item._updatedAt) }}
|
||||
</div>
|
||||
<div
|
||||
v-if="defaultConfigId === item._id"
|
||||
class="default-text"
|
||||
>
|
||||
{{ $T('SELECTED_SETTING_HINT') }}
|
||||
</div>
|
||||
<div class="operation-container">
|
||||
<i class="el-icon-edit" @click="openEditPage(item._id)"></i>
|
||||
<i :class="`el-icon-delete ${curConfigList.length <= 1 ? 'disabled' : ''}`" @click.stop="() => deleteConfig(item._id)"></i>
|
||||
<el-icon
|
||||
class="el-icon-edit"
|
||||
@click="openEditPage(item._id)"
|
||||
>
|
||||
<Edit />
|
||||
</el-icon>
|
||||
<el-icon
|
||||
class="el-icon-delete"
|
||||
:class="curConfigList.length <= 1 ? 'disabled' : ''"
|
||||
@click.stop="() => deleteConfig(item._id)"
|
||||
>
|
||||
<Delete />
|
||||
</el-icon>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
@ -33,96 +59,132 @@
|
||||
class="config-item config-item-add"
|
||||
@click="addNewConfig"
|
||||
>
|
||||
<i class="el-icon-plus"></i>
|
||||
<el-icon
|
||||
class="el-icon-plus"
|
||||
>
|
||||
<Plus />
|
||||
</el-icon>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row type="flex" justify="center" :span="24" class="set-default-container">
|
||||
<el-button class="set-default-btn" type="success" @click="setDefaultPicBed(type)" round :disabled="defaultPicBed === type">{{ $T('SETTINGS_SET_DEFAULT_PICBED') }}</el-button>
|
||||
<el-row
|
||||
type="flex"
|
||||
justify="center"
|
||||
:span="24"
|
||||
class="set-default-container"
|
||||
>
|
||||
<el-button
|
||||
class="set-default-btn"
|
||||
type="success"
|
||||
round
|
||||
:disabled="store?.state.defaultPicBed === type"
|
||||
@click="setDefaultPicBed(type)"
|
||||
>
|
||||
{{ $T('SETTINGS_SET_DEFAULT_PICBED') }}
|
||||
</el-button>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from 'vue-property-decorator'
|
||||
<script lang="ts" setup>
|
||||
import { Edit, Delete, Plus } from '@element-plus/icons-vue'
|
||||
import { saveConfig, triggerRPC } from '@/utils/dataSender'
|
||||
import dayjs from 'dayjs'
|
||||
import mixin from '@/utils/ConfirmButtonMixin'
|
||||
import { IRPCActionType } from '~/universal/types/enum'
|
||||
import { T as $T } from '@/i18n/index'
|
||||
import { useRouter, useRoute, onBeforeRouteUpdate } from 'vue-router'
|
||||
import { onBeforeMount, ref } from 'vue'
|
||||
import { PICBEDS_PAGE, UPLOADER_CONFIG_PAGE } from '@/router/config'
|
||||
import { useStore } from '@/hooks/useStore'
|
||||
const $router = useRouter()
|
||||
const $route = useRoute()
|
||||
|
||||
@Component({
|
||||
name: 'UploaderConfigPage',
|
||||
mixins: [mixin]
|
||||
const type = ref('')
|
||||
const curConfigList = ref<IStringKeyMap[]>([])
|
||||
const defaultConfigId = ref('')
|
||||
const store = useStore()
|
||||
|
||||
async function selectItem (id: string) {
|
||||
await triggerRPC<void>(IRPCActionType.SELECT_UPLOADER, type.value, id)
|
||||
defaultConfigId.value = id
|
||||
}
|
||||
|
||||
onBeforeRouteUpdate((to, from, next) => {
|
||||
if (to.params.type && (to.name === UPLOADER_CONFIG_PAGE)) {
|
||||
type.value = to.params.type as string
|
||||
getCurrentConfigList()
|
||||
console.log(type.value)
|
||||
}
|
||||
next()
|
||||
})
|
||||
export default class extends Vue {
|
||||
type!: string;
|
||||
curConfigList: IStringKeyMap[] = [];
|
||||
defaultConfigId = '';
|
||||
|
||||
async selectItem (id: string) {
|
||||
await this.triggerRPC<void>(IRPCActionType.SELECT_UPLOADER, this.type, id)
|
||||
this.defaultConfigId = id
|
||||
}
|
||||
onBeforeMount(() => {
|
||||
type.value = $route.params.type as string
|
||||
console.log(type.value)
|
||||
getCurrentConfigList()
|
||||
})
|
||||
|
||||
created () {
|
||||
this.type = this.$route.params.type
|
||||
this.getCurrentConfigList()
|
||||
}
|
||||
async function getCurrentConfigList () {
|
||||
const configList = await triggerRPC<IUploaderConfigItem>(IRPCActionType.GET_PICBED_CONFIG_LIST, type.value)
|
||||
console.log(configList)
|
||||
curConfigList.value = configList?.configList ?? []
|
||||
defaultConfigId.value = configList?.defaultId ?? ''
|
||||
}
|
||||
|
||||
async getCurrentConfigList () {
|
||||
const configList = await this.triggerRPC<IUploaderConfigItem>(IRPCActionType.GET_PICBED_CONFIG_LIST, this.type)
|
||||
this.curConfigList = configList?.configList ?? []
|
||||
this.defaultConfigId = configList?.defaultId ?? ''
|
||||
}
|
||||
|
||||
openEditPage (configId: string) {
|
||||
this.$router.push({
|
||||
name: 'picbeds',
|
||||
params: {
|
||||
type: this.type,
|
||||
configId
|
||||
},
|
||||
query: {
|
||||
defaultConfigId: this.defaultConfigId
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
formatTime (time: number):string {
|
||||
return dayjs(time).format('YYYY-MM-DD HH:mm:ss')
|
||||
}
|
||||
|
||||
async deleteConfig (id: string) {
|
||||
const res = await this.triggerRPC<IUploaderConfigItem | undefined>(IRPCActionType.DELETE_PICBED_CONFIG, this.type, id)
|
||||
if (!res) return
|
||||
this.curConfigList = res.configList
|
||||
this.defaultConfigId = res.defaultId
|
||||
}
|
||||
|
||||
addNewConfig () {
|
||||
this.$router.push({
|
||||
name: 'picbeds',
|
||||
params: {
|
||||
type: this.type,
|
||||
configId: ''
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
setDefaultPicBed (type: string) {
|
||||
this.saveConfig({
|
||||
'picBed.current': type,
|
||||
'picBed.uploader': type
|
||||
})
|
||||
// @ts-ignore 来自mixin的数据
|
||||
this.defaultPicBed = type
|
||||
const successNotification = new Notification(this.$T('SETTINGS_DEFAULT_PICBED'), {
|
||||
body: this.$T('TIPS_SET_SUCCEED')
|
||||
})
|
||||
successNotification.onclick = () => {
|
||||
return true
|
||||
function openEditPage (configId: string) {
|
||||
console.log(configId, type.value, defaultConfigId.value)
|
||||
$router.push({
|
||||
name: PICBEDS_PAGE,
|
||||
params: {
|
||||
type: type.value,
|
||||
configId
|
||||
},
|
||||
query: {
|
||||
defaultConfigId: defaultConfigId.value
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function formatTime (time: number): string {
|
||||
return dayjs(time).format('YYYY-MM-DD HH:mm:ss')
|
||||
}
|
||||
|
||||
async function deleteConfig (id: string) {
|
||||
const res = await triggerRPC<IUploaderConfigItem | undefined>(IRPCActionType.DELETE_PICBED_CONFIG, type.value, id)
|
||||
if (!res) return
|
||||
curConfigList.value = res.configList
|
||||
defaultConfigId.value = res.defaultId
|
||||
}
|
||||
|
||||
function addNewConfig () {
|
||||
$router.push({
|
||||
name: PICBEDS_PAGE,
|
||||
params: {
|
||||
type: type.value,
|
||||
configId: ''
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function setDefaultPicBed (type: string) {
|
||||
saveConfig({
|
||||
'picBed.current': type,
|
||||
'picBed.uploader': type
|
||||
})
|
||||
|
||||
store?.setDefaultPicBed(type)
|
||||
const successNotification = new Notification($T('SETTINGS_DEFAULT_PICBED'), {
|
||||
body: $T('TIPS_SET_SUCCEED')
|
||||
})
|
||||
successNotification.onclick = () => {
|
||||
return true
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'UploaderConfigPage'
|
||||
}
|
||||
</script>
|
||||
<style lang='stylus'>
|
||||
#config-list-view
|
||||
position relative
|
||||
|
@ -1,104 +1,104 @@
|
||||
<template>
|
||||
<div id="others-view">
|
||||
<el-row :gutter="20" class="setting-list">
|
||||
<el-col :span="20" :offset="2">
|
||||
<div id="picbeds-page">
|
||||
<el-row
|
||||
:gutter="20"
|
||||
class="setting-list"
|
||||
>
|
||||
<el-col
|
||||
:span="20"
|
||||
:offset="2"
|
||||
>
|
||||
<div class="view-title">
|
||||
{{ picBedName }} {{ $T('SETTINGS') }}
|
||||
</div>
|
||||
<config-form
|
||||
v-if="config.length > 0"
|
||||
:id="type"
|
||||
ref="$configForm"
|
||||
:config="config"
|
||||
type="uploader"
|
||||
ref="configForm"
|
||||
:id="type"
|
||||
>
|
||||
<el-form-item>
|
||||
<el-button class="confirm-btn" type="primary" @click="handleConfirm" round>{{ $T('CONFIRM') }}</el-button>
|
||||
<el-button
|
||||
class="confirm-btn"
|
||||
type="primary"
|
||||
round
|
||||
@click="handleConfirm"
|
||||
>
|
||||
{{ $T('CONFIRM') }}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</config-form>
|
||||
<div v-else class="single">
|
||||
<div class="notice">{{ $T('SETTINGS_NOT_CONFIG_OPTIONS') }}</div>
|
||||
<div
|
||||
v-else
|
||||
class="single"
|
||||
>
|
||||
<div class="notice">
|
||||
{{ $T('SETTINGS_NOT_CONFIG_OPTIONS') }}
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from 'vue-property-decorator'
|
||||
<script lang="ts" setup>
|
||||
import { IRPCActionType } from '~/universal/types/enum'
|
||||
import { ref, onBeforeUnmount, onBeforeMount } from 'vue'
|
||||
import { T as $T } from '@/i18n/index'
|
||||
import { sendToMain, triggerRPC } from '@/utils/dataSender'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import ConfigForm from '@/components/ConfigForm.vue'
|
||||
import mixin from '@/utils/ConfirmButtonMixin'
|
||||
// import mixin from '@/utils/ConfirmButtonMixin'
|
||||
import {
|
||||
ipcRenderer,
|
||||
IpcRendererEvent
|
||||
} from 'electron'
|
||||
import { IRPCActionType } from '~/universal/types/enum'
|
||||
const type = ref('')
|
||||
const config = ref<IPicGoPluginConfig[]>([])
|
||||
const picBedName = ref('')
|
||||
const $route = useRoute()
|
||||
const $router = useRouter()
|
||||
const $configForm = ref<InstanceType<typeof ConfigForm> | null>(null)
|
||||
type.value = $route.params.type as string
|
||||
console.log('picbed type', $route.params.type)
|
||||
|
||||
@Component({
|
||||
name: 'OtherPicBed',
|
||||
mixins: [mixin],
|
||||
components: {
|
||||
ConfigForm
|
||||
}
|
||||
onBeforeMount(() => {
|
||||
sendToMain('getPicBedConfig', $route.params.type)
|
||||
ipcRenderer.on('getPicBedConfig', getPicBeds)
|
||||
})
|
||||
export default class extends Vue {
|
||||
type: string = ''
|
||||
config: any[] = []
|
||||
picBedName: string = ''
|
||||
created () {
|
||||
this.type = this.$route.params.type
|
||||
ipcRenderer.send('getPicBedConfig', this.$route.params.type)
|
||||
ipcRenderer.on('getPicBedConfig', this.getPicBeds)
|
||||
}
|
||||
|
||||
async handleConfirm () {
|
||||
// @ts-ignore
|
||||
const result = await this.$refs.configForm.validate()
|
||||
if (result !== false) {
|
||||
await this.triggerRPC<void>(IRPCActionType.UPDATE_UPLOADER_CONFIG, this.type, result?._id, result)
|
||||
const successNotification = new Notification(this.$T('SETTINGS_RESULT'), {
|
||||
body: this.$T('TIPS_SET_SUCCEED')
|
||||
})
|
||||
successNotification.onclick = () => {
|
||||
return true
|
||||
}
|
||||
this.$router.back()
|
||||
}
|
||||
}
|
||||
|
||||
shouldUpdateDefaultConfig (item: IStringKeyMap) {
|
||||
const curDefaultConfigId = this.$route.query.defaultConfigId
|
||||
if (item._id === curDefaultConfigId) {
|
||||
this.saveConfig(`picBed.${this.type}`, item)
|
||||
}
|
||||
}
|
||||
|
||||
setDefaultPicBed (type: string) {
|
||||
this.saveConfig({
|
||||
'picBed.current': type,
|
||||
'picBed.uploader': type
|
||||
})
|
||||
// @ts-ignore 来自mixin的数据
|
||||
this.defaultPicBed = type
|
||||
const successNotification = new Notification(this.$T('SETTINGS_DEFAULT_PICBED'), {
|
||||
body: this.$T('TIPS_SET_SUCCEED')
|
||||
const handleConfirm = async () => {
|
||||
const result = (await $configForm.value?.validate()) || false
|
||||
console.log(result)
|
||||
if (result !== false) {
|
||||
await triggerRPC<void>(IRPCActionType.UPDATE_UPLOADER_CONFIG, type.value, result?._id, result)
|
||||
const successNotification = new Notification($T('SETTINGS_RESULT'), {
|
||||
body: $T('TIPS_SET_SUCCEED')
|
||||
})
|
||||
successNotification.onclick = () => {
|
||||
return true
|
||||
}
|
||||
$router.back()
|
||||
}
|
||||
}
|
||||
|
||||
getPicBeds (event: IpcRendererEvent, config: any[], name: string) {
|
||||
this.config = config
|
||||
this.picBedName = name
|
||||
}
|
||||
function getPicBeds (event: IpcRendererEvent, _config: IPicGoPluginConfig[], name: string) {
|
||||
config.value = _config
|
||||
picBedName.value = name
|
||||
}
|
||||
|
||||
beforeDestroy () {
|
||||
ipcRenderer.removeListener('getPicBedConfig', this.getPicBeds)
|
||||
}
|
||||
onBeforeUnmount(() => {
|
||||
ipcRenderer.removeListener('getPicBedConfig', getPicBeds)
|
||||
})
|
||||
|
||||
</script>
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'PicbedsPage'
|
||||
}
|
||||
</script>
|
||||
<style lang='stylus'>
|
||||
#others-view
|
||||
#picbeds-page
|
||||
.setting-list
|
||||
height 425px
|
||||
overflow-y auto
|
||||
@ -111,13 +111,11 @@ export default class extends Vue {
|
||||
padding-bottom 0
|
||||
color #eee
|
||||
&-item
|
||||
margin-bottom 11px
|
||||
margin-bottom 16px
|
||||
.el-button-group
|
||||
width 100%
|
||||
.el-button
|
||||
width 50%
|
||||
.el-input__inner
|
||||
border-radius 19px
|
||||
.el-radio-group
|
||||
margin-left 25px
|
||||
.el-switch__label
|
||||
|
11
src/renderer/router/config.ts
Normal file
11
src/renderer/router/config.ts
Normal file
@ -0,0 +1,11 @@
|
||||
export const GALLERY_PAGE = 'GalleryPage'
|
||||
export const TRAY_PAGE = 'TrayPage'
|
||||
export const RENAME_PAGE = 'RenamePage'
|
||||
export const MINI_PAGE = 'MiniPage'
|
||||
export const MAIN_PAGE = 'MainPage'
|
||||
export const UPLOAD_PAGE = 'UploadPage'
|
||||
export const PICBEDS_PAGE = 'PicbedsPage'
|
||||
export const SETTING_PAGE = 'SettingPage'
|
||||
export const PLUGIN_PAGE = 'PluginPage'
|
||||
export const SHORTKEY_PAGE = 'ShortkeyPage'
|
||||
export const UPLOADER_CONFIG_PAGE = 'UploaderConfigPage'
|
@ -1,45 +1,43 @@
|
||||
import Vue from 'vue'
|
||||
import Router from 'vue-router'
|
||||
import { createRouter, createWebHashHistory } from 'vue-router'
|
||||
import * as config from './config'
|
||||
|
||||
Vue.use(Router)
|
||||
|
||||
export default new Router({
|
||||
mode: 'hash',
|
||||
export default createRouter({
|
||||
history: createWebHashHistory(),
|
||||
routes: [
|
||||
{
|
||||
path: '/',
|
||||
name: 'tray-page',
|
||||
name: config.TRAY_PAGE,
|
||||
component: () => import(/* webpackChunkName: "tray" */ '@/pages/TrayPage.vue')
|
||||
},
|
||||
{
|
||||
path: '/rename-page',
|
||||
name: 'rename-page',
|
||||
name: config.RENAME_PAGE,
|
||||
component: () => import(/* webpackChunkName: "RenamePage" */ '@/pages/RenamePage.vue')
|
||||
},
|
||||
{
|
||||
path: '/mini-page',
|
||||
name: 'mini-page',
|
||||
name: config.MINI_PAGE,
|
||||
component: () => import(/* webpackChunkName: "MiniPage" */ '@/pages/MiniPage.vue')
|
||||
},
|
||||
{
|
||||
path: '/main-page',
|
||||
name: 'main-page',
|
||||
name: config.MAIN_PAGE,
|
||||
component: () => import(/* webpackChunkName: "SettingPage" */ '@/layouts/Main.vue'),
|
||||
children: [
|
||||
{
|
||||
path: 'upload',
|
||||
component: () => import(/* webpackChunkName: "Upload" */ '@/pages/Upload.vue'),
|
||||
name: 'upload'
|
||||
name: config.UPLOAD_PAGE
|
||||
},
|
||||
{
|
||||
path: 'picbeds/:type/:configId',
|
||||
path: 'picbeds/:type/:configId?',
|
||||
component: () => import(/* webpackChunkName: "Other" */ '@/pages/picbeds/index.vue'),
|
||||
name: 'picbeds'
|
||||
name: config.PICBEDS_PAGE
|
||||
},
|
||||
{
|
||||
path: 'gallery',
|
||||
component: () => import(/* webpackChunkName: "Gallery" */ '@/pages/Gallery.vue'),
|
||||
name: 'gallery',
|
||||
component: () => import(/* webpackChunkName: "GalleryView" */ '@/pages/Gallery.vue'),
|
||||
name: config.GALLERY_PAGE,
|
||||
meta: {
|
||||
keepAlive: true
|
||||
}
|
||||
@ -47,27 +45,27 @@ export default new Router({
|
||||
{
|
||||
path: 'setting',
|
||||
component: () => import(/* webpackChunkName: "setting" */ '@/pages/PicGoSetting.vue'),
|
||||
name: 'setting'
|
||||
name: config.SETTING_PAGE
|
||||
},
|
||||
{
|
||||
path: 'plugin',
|
||||
component: () => import(/* webpackChunkName: "Plugin" */ '@/pages/Plugin.vue'),
|
||||
name: 'plugin'
|
||||
name: config.PLUGIN_PAGE
|
||||
},
|
||||
{
|
||||
path: 'shortKey',
|
||||
component: () => import(/* webpackChunkName: "ShortkeyPage" */ '@/pages/ShortKey.vue'),
|
||||
name: 'shortKey'
|
||||
name: config.SHORTKEY_PAGE
|
||||
},
|
||||
{
|
||||
path: 'uploader-config-page/:type',
|
||||
component: () => import(/* webpackChunkName: "Other" */ '@/pages/UploaderConfigPage.vue'),
|
||||
name: 'UploaderConfigPage'
|
||||
name: config.UPLOADER_CONFIG_PAGE
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '*',
|
||||
path: '/:pathMatch(.*)*',
|
||||
redirect: '/'
|
||||
}
|
||||
]
|
||||
|
@ -1,11 +0,0 @@
|
||||
import Vue from 'vue'
|
||||
import Vuex from 'vuex'
|
||||
|
||||
import modules from './modules'
|
||||
|
||||
Vue.use(Vuex)
|
||||
|
||||
export default new Vuex.Store({
|
||||
modules,
|
||||
strict: process.env.NODE_ENV !== 'production'
|
||||
})
|
37
src/renderer/store/index.ts
Normal file
37
src/renderer/store/index.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import { reactive, InjectionKey, readonly, App, UnwrapRef } from 'vue'
|
||||
import { saveConfig } from '@/utils/dataSender'
|
||||
|
||||
export interface IState {
|
||||
defaultPicBed: string;
|
||||
}
|
||||
|
||||
export interface IStore {
|
||||
state: UnwrapRef<IState>
|
||||
setDefaultPicBed: (type: string) => void;
|
||||
}
|
||||
|
||||
export const storeKey: InjectionKey<IStore> = Symbol('store')
|
||||
|
||||
// state
|
||||
const state: IState = reactive({
|
||||
defaultPicBed: 'smms'
|
||||
})
|
||||
|
||||
// methods
|
||||
const setDefaultPicBed = (type: string) => {
|
||||
saveConfig({
|
||||
'picBed.current': type,
|
||||
'picBed.uploader': type
|
||||
})
|
||||
state.defaultPicBed = type
|
||||
console.log(state)
|
||||
}
|
||||
|
||||
export const store = {
|
||||
install (app: App) {
|
||||
app.provide(storeKey, {
|
||||
state: readonly(state),
|
||||
setDefaultPicBed
|
||||
})
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
const state = {
|
||||
main: 0
|
||||
}
|
||||
|
||||
const mutations = {
|
||||
DECREMENT_MAIN_COUNTER (state) {
|
||||
state.main--
|
||||
},
|
||||
INCREMENT_MAIN_COUNTER (state) {
|
||||
state.main++
|
||||
}
|
||||
}
|
||||
|
||||
const actions = {
|
||||
someAsyncTask ({ commit }) {
|
||||
// do something async
|
||||
commit('INCREMENT_MAIN_COUNTER')
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
state,
|
||||
mutations,
|
||||
actions
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
/**
|
||||
* The file enables `@/store/index.js` to import all vuex modules
|
||||
* in a one-shot manner. There should not be any reason to edit this file.
|
||||
*/
|
||||
|
||||
const files = require.context('.', false, /\.js$/)
|
||||
const modules = {}
|
||||
|
||||
files.keys().forEach(key => {
|
||||
if (key === './index.js') return
|
||||
modules[key.replace(/(\.\/|\.js)/g, '')] = files(key).default
|
||||
})
|
||||
|
||||
export default modules
|
@ -1,26 +0,0 @@
|
||||
import { Component, Vue } from 'vue-property-decorator'
|
||||
import { IConfig } from 'picgo'
|
||||
@Component
|
||||
export default class extends Vue {
|
||||
defaultPicBed = 'smms'
|
||||
async created () {
|
||||
const config = await this.getConfig<IConfig>()
|
||||
if (config) {
|
||||
this.defaultPicBed = config?.picBed?.uploader || config?.picBed?.current || 'smms'
|
||||
}
|
||||
}
|
||||
|
||||
setDefaultPicBed (type: string) {
|
||||
this.saveConfig({
|
||||
'picBed.current': type,
|
||||
'picBed.uploader': type
|
||||
})
|
||||
this.defaultPicBed = type
|
||||
const successNotification = new Notification(this.$T('SETTINGS_DEFAULT_PICBED'), {
|
||||
body: this.$T('TIPS_SET_SUCCEED')
|
||||
})
|
||||
successNotification.onclick = () => {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
@ -1,2 +1,20 @@
|
||||
import Vue from 'vue'
|
||||
export default new Vue()
|
||||
import mitt from 'mitt'
|
||||
import {
|
||||
SHOW_INPUT_BOX,
|
||||
SHOW_INPUT_BOX_RESPONSE,
|
||||
FORCE_UPDATE
|
||||
} from '~/universal/events/constants'
|
||||
|
||||
type IEvent ={
|
||||
[SHOW_INPUT_BOX_RESPONSE]: string
|
||||
[SHOW_INPUT_BOX]: {
|
||||
value: string
|
||||
title: string
|
||||
placeholder: string
|
||||
},
|
||||
[FORCE_UPDATE]: void
|
||||
}
|
||||
|
||||
const emitter = mitt<IEvent>()
|
||||
|
||||
export default emitter
|
||||
|
@ -1,3 +1,5 @@
|
||||
import { isReactive, isRef, toRaw, unref } from 'vue'
|
||||
|
||||
const isDevelopment = process.env.NODE_ENV !== 'production'
|
||||
/* eslint-disable camelcase */
|
||||
export const handleTalkingDataEvent = (data: ITalkingDataOptions) => {
|
||||
@ -16,3 +18,36 @@ export const trimValues = (obj: IStringKeyMap) => {
|
||||
})
|
||||
return newObj
|
||||
}
|
||||
|
||||
/**
|
||||
* get raw data from reactive or ref
|
||||
*/
|
||||
export const getRawData = (args: any) => {
|
||||
if (Array.isArray(args)) {
|
||||
const data = args.map((item: any) => {
|
||||
if (isRef(item)) {
|
||||
return unref(item)
|
||||
}
|
||||
if (isReactive(item)) {
|
||||
return toRaw(item)
|
||||
}
|
||||
return item
|
||||
})
|
||||
return data
|
||||
}
|
||||
if (typeof args === 'object') {
|
||||
const data = {} as IStringKeyMap
|
||||
Object.keys(args).forEach(key => {
|
||||
const item = args[key]
|
||||
if (isRef(item)) {
|
||||
data[key] = unref(item)
|
||||
} else if (isReactive(item)) {
|
||||
data[key] = toRaw(item)
|
||||
} else {
|
||||
data[key] = getRawData(item)
|
||||
}
|
||||
})
|
||||
return data
|
||||
}
|
||||
return args
|
||||
}
|
||||
|
55
src/renderer/utils/dataSender.ts
Normal file
55
src/renderer/utils/dataSender.ts
Normal file
@ -0,0 +1,55 @@
|
||||
import { ipcRenderer, IpcRendererEvent } from 'electron'
|
||||
import { PICGO_SAVE_CONFIG, PICGO_GET_CONFIG, RPC_ACTIONS } from '#/events/constants'
|
||||
import { uuid } from 'uuidv4'
|
||||
import { IRPCActionType } from '~/universal/types/enum'
|
||||
import { getRawData } from './common'
|
||||
|
||||
export function saveConfig (_config: IObj | string, value?: any) {
|
||||
let config
|
||||
if (typeof _config === 'string') {
|
||||
config = {
|
||||
[_config]: value
|
||||
}
|
||||
} else {
|
||||
config = getRawData(_config)
|
||||
}
|
||||
ipcRenderer.send(PICGO_SAVE_CONFIG, config)
|
||||
}
|
||||
|
||||
export function getConfig<T> (key?: string): Promise<T | undefined> {
|
||||
return new Promise((resolve) => {
|
||||
const callbackId = uuid()
|
||||
const callback = (event: IpcRendererEvent, config: T | undefined, returnCallbackId: string) => {
|
||||
if (returnCallbackId === callbackId) {
|
||||
resolve(config)
|
||||
ipcRenderer.removeListener(PICGO_GET_CONFIG, callback)
|
||||
}
|
||||
}
|
||||
ipcRenderer.on(PICGO_GET_CONFIG, callback)
|
||||
ipcRenderer.send(PICGO_GET_CONFIG, key, callbackId)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* trigger RPC action
|
||||
* TODO: create an isolate rpc handler
|
||||
*/
|
||||
export function triggerRPC<T> (action: IRPCActionType, ...args: any[]): Promise<T | null> {
|
||||
return new Promise((resolve) => {
|
||||
const callbackId = uuid()
|
||||
const callback = (event: IpcRendererEvent, data: T | null, returnActionType: IRPCActionType, returnCallbackId: string) => {
|
||||
if (returnCallbackId === callbackId && returnActionType === action) {
|
||||
resolve(data)
|
||||
ipcRenderer.removeListener(RPC_ACTIONS, callback)
|
||||
}
|
||||
}
|
||||
const data = getRawData(args)
|
||||
ipcRenderer.on(RPC_ACTIONS, callback)
|
||||
ipcRenderer.send(RPC_ACTIONS, action, data, callbackId)
|
||||
})
|
||||
}
|
||||
|
||||
export function sendToMain (channel: string, ...args: any[]) {
|
||||
const data = getRawData(args)
|
||||
ipcRenderer.send(channel, ...data)
|
||||
}
|
@ -10,6 +10,7 @@ import {
|
||||
PICGO_REMOVE_BY_ID_DB
|
||||
} from '#/events/constants'
|
||||
import { IGalleryDB } from '#/types/extra-vue'
|
||||
import { getRawData } from './common'
|
||||
export class GalleryDB implements IGalleryDB {
|
||||
async get<T> (filter?: IFilter): Promise<IGetResult<T>> {
|
||||
const res = await this.msgHandler<IGetResult<T>>(PICGO_GET_DB, filter)
|
||||
@ -50,8 +51,9 @@ export class GalleryDB implements IGalleryDB {
|
||||
ipcRenderer.removeListener(method, callback)
|
||||
}
|
||||
}
|
||||
const data = getRawData(args)
|
||||
ipcRenderer.on(method, callback)
|
||||
ipcRenderer.send(method, ...args, callbackId)
|
||||
ipcRenderer.send(method, ...data, callbackId)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1,63 +1,20 @@
|
||||
import { Component, Vue } from 'vue-property-decorator'
|
||||
import { ipcRenderer, IpcRendererEvent } from 'electron'
|
||||
import { PICGO_SAVE_CONFIG, PICGO_GET_CONFIG, FORCE_UPDATE, RPC_ACTIONS } from '#/events/constants'
|
||||
import { uuid } from 'uuidv4'
|
||||
import { IRPCActionType } from '~/universal/types/enum'
|
||||
@Component
|
||||
export default class extends Vue {
|
||||
import { ComponentOptions, getCurrentInstance } from 'vue'
|
||||
import { FORCE_UPDATE, GET_PICBEDS } from '~/universal/events/constants'
|
||||
import bus from '~/renderer/utils/bus'
|
||||
import { ipcRenderer } from 'electron'
|
||||
export const mainMixin: ComponentOptions = {
|
||||
created () {
|
||||
this.$bus.$on(FORCE_UPDATE, () => {
|
||||
this.$forceUpdate()
|
||||
bus.on(FORCE_UPDATE, () => {
|
||||
getCurrentInstance()?.proxy?.$forceUpdate()
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
// support string key + value or object config
|
||||
saveConfig (config: IObj | string, value?: any) {
|
||||
if (typeof config === 'string') {
|
||||
config = {
|
||||
[config]: value
|
||||
}
|
||||
methods: {
|
||||
forceUpdate () {
|
||||
bus.emit(FORCE_UPDATE)
|
||||
},
|
||||
getPicBeds () {
|
||||
ipcRenderer.send(GET_PICBEDS)
|
||||
}
|
||||
ipcRenderer.send(PICGO_SAVE_CONFIG, config)
|
||||
}
|
||||
|
||||
getConfig<T> (key?: string): Promise<T | undefined> {
|
||||
return new Promise((resolve) => {
|
||||
const callbackId = uuid()
|
||||
const callback = (event: IpcRendererEvent, config: T | undefined, returnCallbackId: string) => {
|
||||
if (returnCallbackId === callbackId) {
|
||||
resolve(config)
|
||||
ipcRenderer.removeListener(PICGO_GET_CONFIG, callback)
|
||||
}
|
||||
}
|
||||
ipcRenderer.on(PICGO_GET_CONFIG, callback)
|
||||
ipcRenderer.send(PICGO_GET_CONFIG, key, callbackId)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* trigger RPC action
|
||||
* TODO: create an isolate rpc handler
|
||||
*/
|
||||
triggerRPC<T> (action: IRPCActionType, ...args: any[]): Promise<T | null> {
|
||||
return new Promise((resolve) => {
|
||||
const callbackId = uuid()
|
||||
const callback = (event: IpcRendererEvent, data: T | null, returnActionType: IRPCActionType, returnCallbackId: string) => {
|
||||
if (returnCallbackId === callbackId && returnActionType === action) {
|
||||
resolve(data)
|
||||
ipcRenderer.removeListener(RPC_ACTIONS, callback)
|
||||
}
|
||||
}
|
||||
ipcRenderer.on(RPC_ACTIONS, callback)
|
||||
ipcRenderer.send(RPC_ACTIONS, action, args, callbackId)
|
||||
})
|
||||
}
|
||||
|
||||
forceUpdate () {
|
||||
this.$bus.$emit(FORCE_UPDATE)
|
||||
}
|
||||
|
||||
sendToMain (channel: string, ...args: any[]) {
|
||||
ipcRenderer.send(channel, ...args)
|
||||
}
|
||||
}
|
||||
|
@ -1,26 +1,27 @@
|
||||
import { Component, Vue } from 'vue-property-decorator'
|
||||
@Component
|
||||
export default class extends Vue {
|
||||
import { ComponentOptions } from 'vue'
|
||||
export const dragMixin: ComponentOptions = {
|
||||
mounted () {
|
||||
this.disableDragEvent()
|
||||
}
|
||||
},
|
||||
|
||||
disableDragEvent () {
|
||||
window.addEventListener('dragenter', this.disableDrag, false)
|
||||
window.addEventListener('dragover', this.disableDrag)
|
||||
window.addEventListener('drop', this.disableDrag)
|
||||
}
|
||||
methods: {
|
||||
disableDragEvent () {
|
||||
window.addEventListener('dragenter', this.disableDrag, false)
|
||||
window.addEventListener('dragover', this.disableDrag)
|
||||
window.addEventListener('drop', this.disableDrag)
|
||||
},
|
||||
|
||||
disableDrag (e: DragEvent) {
|
||||
const dropzone = document.getElementById('upload-area')
|
||||
if (dropzone === null || !dropzone.contains(<Node>e.target)) {
|
||||
e.preventDefault()
|
||||
e.dataTransfer!.effectAllowed = 'none'
|
||||
e.dataTransfer!.dropEffect = 'none'
|
||||
disableDrag (e: DragEvent) {
|
||||
const dropzone = document.getElementById('upload-area')
|
||||
if (dropzone === null || !dropzone.contains(<Node>e.target)) {
|
||||
e.preventDefault()
|
||||
e.dataTransfer!.effectAllowed = 'none'
|
||||
e.dataTransfer!.dropEffect = 'none'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
beforeDestroy () {
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('dragenter', this.disableDrag, false)
|
||||
window.removeEventListener('dragover', this.disableDrag)
|
||||
window.removeEventListener('drop', this.disableDrag)
|
||||
|
@ -25,6 +25,7 @@ export const OPEN_URL = 'OPEN_URL'
|
||||
export const RELOAD_APP = 'RELOAD_APP'
|
||||
export const PICGO_CONFIG_PLUGIN = 'PICGO_CONFIG_PLUGIN'
|
||||
export const PICGO_HANDLE_PLUGIN_ING = 'PICGO_HANDLE_PLUGIN_ING'
|
||||
export const PICGO_HANDLE_PLUGIN_DONE = 'PICGO_HANDLE_PLUGIN_DONE'
|
||||
export const PICGO_TOGGLE_PLUGIN = 'PICGO_TOGGLE_PLUGIN'
|
||||
export const PASTE_TEXT = 'PASTE_TEXT'
|
||||
export const SET_MINI_WINDOW_POS = 'SET_MINI_WINDOW_POS'
|
||||
|
14
src/universal/types/extra-vue.d.ts
vendored
14
src/universal/types/extra-vue.d.ts
vendored
@ -1,4 +1,3 @@
|
||||
import VueRouter, { Route } from 'vue-router'
|
||||
import axios from 'axios'
|
||||
import { IObject, IResult, IGetResult, IFilter } from '@picgo/store/dist/types'
|
||||
|
||||
@ -13,11 +12,13 @@ interface IGalleryDB {
|
||||
|
||||
declare module 'vue/types/vue' {
|
||||
interface Vue {
|
||||
$router: VueRouter,
|
||||
$route: Route,
|
||||
}
|
||||
}
|
||||
|
||||
declare module '@vue/runtime-core' {
|
||||
interface ComponentCustomProperties {
|
||||
$http: typeof axios
|
||||
$builtInPicBed: string[]
|
||||
$bus: Vue
|
||||
$$db: IGalleryDB
|
||||
$T: typeof import('~/renderer/i18n/index').T
|
||||
$i18n: import('~/renderer/i18n/index').I18nManager
|
||||
@ -29,4 +30,9 @@ declare module 'vue/types/vue' {
|
||||
forceUpdate(): void
|
||||
sendToMain(channel: string, ...args: any[]): void
|
||||
}
|
||||
interface GlobalComponents {
|
||||
PhotoProvider: typeof import('vue3-photo-preview').PhotoProvider
|
||||
PhotoConsumer: typeof import('vue3-photo-preview').PhotoConsumer
|
||||
PhotoSlider: typeof import('vue3-photo-preview').PhotoSlider
|
||||
}
|
||||
}
|
||||
|
5
src/universal/types/shims-module.d.ts
vendored
5
src/universal/types/shims-module.d.ts
vendored
@ -1,6 +1,7 @@
|
||||
declare module '*.vue' {
|
||||
import Vue from 'vue'
|
||||
export default Vue
|
||||
import { DefineComponent } from 'vue'
|
||||
const component: DefineComponent<{}, {}, any>
|
||||
export default component
|
||||
}
|
||||
// // third-party
|
||||
// declare module 'fix-path' {
|
||||
|
8
src/universal/types/types.d.ts
vendored
8
src/universal/types/types.d.ts
vendored
@ -49,6 +49,12 @@ interface ImgInfo {
|
||||
[propName: string]: any
|
||||
}
|
||||
|
||||
interface IGalleryItem extends ImgInfo {
|
||||
src: string
|
||||
key: string
|
||||
intro: string
|
||||
}
|
||||
|
||||
interface IPicBedType {
|
||||
type: string
|
||||
name: string
|
||||
@ -423,3 +429,5 @@ interface IUploaderConfigItem {
|
||||
}
|
||||
|
||||
type IUploaderConfigListItem = IStringKeyMap & IUploaderListItemMetaInfo
|
||||
|
||||
type ICheckBoxValueType = boolean | string | number
|
||||
|
@ -13,7 +13,9 @@
|
||||
"sourceMap": true,
|
||||
"baseUrl": ".",
|
||||
"types": [
|
||||
"webpack-env"
|
||||
"webpack-env",
|
||||
"element-plus/global",
|
||||
"vue3-photo-preview"
|
||||
],
|
||||
"typeRoots": [
|
||||
"./src/universal/types/*",
|
||||
@ -56,6 +58,6 @@
|
||||
"node_modules"
|
||||
],
|
||||
"vueCompilerOptions": {
|
||||
"target": 2,
|
||||
"target": 3,
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user