| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349 |
- <template>
- <div class="menu flex-column-center">
- <el-button
- v-for="button in buttons"
- size="large"
- :key="button.name"
- @click="button.action"
- >
- {{ button.name }}
- </el-button>
- <el-button size="large" @click="() => (hotkeysDialogVisible = true)"
- >快捷键</el-button
- >
- </div>
- <el-dialog
- v-model="hotkeysDialogVisible"
- :show-close="false"
- :before-close="stopRecordKeyDown"
- >
- <template #header="{ titleClass, titleId }">
- <div class="hotkeys-header flex-space-between">
- <div :id="titleId" :class="titleClass">
- 快捷键设置
- <span v-if="recordKeyDowning">
- <el-text> / 录入中 </el-text>
- </span>
- </div>
- <el-button
- :disabled="recordKeyDowning"
- @click="saveHotKeys"
- :icon="CircleCheckFilled"
- >保存</el-button
- >
- </div>
- </template>
- <div class="hotkeys-settings flex-column-center">
- <div
- v-for="(button, buttonIndex) in buttons"
- :key="button.name"
- class="hotkeys-item flex-space-between"
- >
- <span class="title"
- ><el-text>{{ button.name }}</el-text></span
- >
- <div class="hotkeys-item__content">
- <div v-for="(key, hotKeysIndex) in button.hotKeys" :key="key">
- <kbd>{{ key }}</kbd>
- <span v-if="hotKeysIndex + 1 < button.hotKeys.length">
- <el-text>+</el-text>
- </span>
- </div>
- <span v-if="button.hotKeys.length == 0">未设置</span>
- </div>
- <el-button
- :disabled="recordKeyDowning"
- text
- :icon="Edit"
- @click="recordKeyDown(buttonIndex)"
- >编辑</el-button
- >
- </div>
- </div>
- </el-dialog>
- </template>
- <script setup lang="ts">
- import API from '@api'
- import { CircleCheckFilled, Edit } from '@element-plus/icons-vue'
- import hotkeys from 'hotkeys-js'
- import { getSourceName, isInvaildSource } from '../utils/souce'
- const store = useSourceStore()
- const pull = () => {
- const loadingMsg = ElMessage({
- message: '加载中……',
- showClose: true,
- duration: 0,
- })
- API.getSources()
- .then(({ data }) => {
- if (data.isSuccess) {
- store.changeTabName('editList')
- store.saveSources(data.data)
- ElMessage({
- message: `成功拉取${data.data.length}条源`,
- type: 'success',
- })
- } else {
- ElMessage({
- message: data.errorMsg ?? '后端错误',
- type: 'error',
- })
- }
- })
- .finally(() => loadingMsg.close())
- }
- const push = () => {
- const sources = store.sources
- store.changeTabName('editList')
- if (sources.length === 0) {
- return ElMessage({
- message: '空空如也',
- type: 'info',
- })
- }
- ElMessage({
- message: '正在推送中',
- type: 'info',
- })
- API.saveSources(sources).then(({ data }) => {
- if (data.isSuccess) {
- const okData = data.data
- if (Array.isArray(okData)) {
- let failMsg = ``
- if (sources.length > okData.length) {
- failMsg = '\n推送失败的源将用红色字体标注!'
- store.setPushReturnSources(okData)
- }
- ElMessage({
- message: `批量推送源到「阅读3.0APP」\n共计: ${
- sources.length
- } 条\n成功: ${okData.length} 条\n失败: ${
- sources.length - okData.length
- } 条${failMsg}`,
- type: 'success',
- })
- }
- } else {
- ElMessage({
- message: `批量推送源失败!\nErrorMsg: ${data.errorMsg}`,
- type: 'error',
- })
- }
- })
- }
- const conver2Tab = () => {
- store.changeTabName('editTab')
- store.changeEditTabSource(store.currentSource)
- }
- const conver2Source = () => {
- store.changeCurrentSource(store.editTabSource)
- }
- const undo = () => {
- store.editHistoryUndo()
- }
- const clearEdit = () => {
- store.clearEdit()
- ElMessage({
- message: '已清除',
- type: 'success',
- })
- }
- const redo = () => {
- store.clearEdit()
- store.clearAllHistory()
- ElMessage({
- message: '已清除所有历史记录',
- type: 'success',
- })
- }
- const saveSource = () => {
- const source = store.currentSource
- if (isInvaildSource(source)) {
- API.saveSource(source).then(({ data }) => {
- const sourceName = getSourceName(source)
- if (data.isSuccess) {
- ElMessage({
- message: `源《${sourceName}》已成功保存到「阅读3.0APP」`,
- type: 'success',
- })
- //save to store
- store.saveCurrentSource()
- } else {
- ElMessage({
- message: `源《${sourceName}》保存失败!\nErrorMsg: ${data.errorMsg}`,
- type: 'error',
- })
- }
- })
- } else {
- ElMessage({
- message: `请检查<必填>项是否全部填写`,
- type: 'error',
- })
- }
- }
- const debug = () => {
- store.startDebug()
- }
- const buttons = ref<{ name: string; hotKeys: string[]; action: () => void }[]>(
- Array.of(
- { name: '⇈推送源', hotKeys: [], action: push },
- { name: '⇊拉取源', hotKeys: [], action: pull },
- { name: '⋙生成源', hotKeys: [], action: conver2Tab },
- { name: '⋘编辑源', hotKeys: [], action: conver2Source },
- { name: '✗清空表单', hotKeys: [], action: clearEdit },
- { name: '↶撤销操作', hotKeys: [], action: undo },
- { name: '↷重做操作', hotKeys: [], action: redo },
- { name: '⇏调试源', hotKeys: [], action: debug },
- { name: '✓保存源', hotKeys: [], action: saveSource },
- ),
- )
- const hotkeysDialogVisible = ref(true)
- const recordKeyDowning = ref(false)
- const recordKeyDownIndex = ref(-1)
- const stopRecordKeyDown = () => {
- if (!recordKeyDowning.value) {
- hotkeysDialogVisible.value = false
- }
- recordKeyDowning.value = false
- }
- watch(
- hotkeysDialogVisible,
- visibale => {
- if (!visibale) {
- hotkeys.unbind('*')
- readHotkeysConfig()
- bindHotKeys()
- return
- }
- readHotkeysConfig()
- hotkeys.unbind()
- /**监听按键 */
- hotkeys('*', event => {
- event.preventDefault()
- const pressedKeys = hotkeys.getPressedKeyString()
- if (pressedKeys.length == 1 && pressedKeys[0] == 'esc') {
- //单独按下esc 不录入
- return
- }
- if (recordKeyDowning.value && recordKeyDownIndex.value > -1)
- buttons.value[recordKeyDownIndex.value].hotKeys = pressedKeys
- })
- },
- { immediate: true },
- )
- const recordKeyDown = (index: number) => {
- recordKeyDowning.value = true
- ElMessage({
- message: '按ESC键或者点击空白处结束录入',
- type: 'info',
- })
- buttons.value[index].hotKeys = []
- recordKeyDownIndex.value = index
- }
- const saveHotKeys = () => {
- const hotKeysConfig: string[][] = []
- buttons.value.forEach(({ hotKeys }) => {
- hotKeysConfig.push(hotKeys)
- })
- saveHotkeysConfig(hotKeysConfig)
- hotkeysDialogVisible.value = false
- }
- const bindHotKeys = () => {
- // hotkeys默认过滤INPUT SELECT TEXTAREA
- hotkeys.filter = () => true
- buttons.value.forEach(({ hotKeys, action }) => {
- if (hotKeys.length == 0) return
- hotkeys(hotKeys.join('+'), event => {
- event.preventDefault()
- action.call(null)
- })
- })
- }
- const saveHotkeysConfig = (config: string[][]) => {
- localStorage.setItem('legado_web_hotkeys', JSON.stringify(config))
- }
- /**
- * 读取快捷键配置
- * @return 是否成功读取配置
- */
- function readHotkeysConfig() {
- try {
- const localStorageConfig = localStorage.getItem('legado_web_hotkeys')
- if (localStorageConfig === null) return false
- const config = JSON.parse(localStorageConfig)
- if (!Array.isArray(config) || config.length == 0) return false
- buttons.value.forEach((button, index) => (button.hotKeys = config[index]))
- return true
- } catch {
- ElMessage({ message: '快捷键配置错误', type: 'error' })
- localStorage.removeItem('legado_web_hotkeys')
- }
- return false
- }
- onMounted(() => {
- /**读取热键配置 */
- if (readHotkeysConfig()) {
- hotkeysDialogVisible.value = false
- }
- })
- </script>
- <style scoped>
- .flex-space-between {
- display: flex;
- justify-content: space-between;
- align-items: baseline;
- }
- .flex-column-center {
- display: flex;
- flex-direction: column;
- justify-content: center;
- }
- .menu > .el-button {
- margin: 4px;
- padding: 1em;
- width: 6em;
- }
- .hotkeys-item {
- .title {
- width: 5em;
- display: flex;
- justify-content: flex-end;
- margin-right: 1em;
- }
- .hotkeys-item__content {
- display: flex;
- flex-wrap: wrap;
- flex: 1;
- div {
- margin-bottom: 1em;
- }
- span {
- margin: 0.5em;
- }
- }
- }
- </style>
|