Skip to content

Commit

Permalink
feat(web): support data import
Browse files Browse the repository at this point in the history
  • Loading branch information
Red-Asuka committed May 14, 2024
1 parent e430617 commit 95adbff
Show file tree
Hide file tree
Showing 6 changed files with 280 additions and 3 deletions.
195 changes: 195 additions & 0 deletions web/src/components/ImportData.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
<template>
<my-dialog
:title="$t('connections.importData')"
:visible.sync="showDialog"
class="import-data"
width="350px"
:confirmLoading="confirmLoading"
@confirm="importData"
@close="resetData"
>
<el-alert
class="import-data-tip"
:title="$t('connections.importDataTip')"
type="warning"
show-icon
:closable="false"
>
</el-alert>
<el-form ref="form" label-position="left" label-width="130px" :model="record">
<el-row :gutter="20">
<el-col :span="24">
<el-form-item :label="$t('connections.importFormat')">
<el-select size="small" v-model="record.importFormat">
<el-option v-for="(format, index) in ['JSON']" :key="index" :value="format"> </el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="22">
<el-form-item :label="$t('connections.importFile')">
<el-tooltip placement="top" :effect="theme !== 'light' ? 'light' : 'dark'" :open-delay="500">
<div slot="content" v-html="$t('connections.importConnectionsTip')">
{{ $t('connections.importConnectionsTip') }}
</div>
<a href="javascript:;" class="icon-tip">
<i class="el-icon-question"></i>
</a>
</el-tooltip>
<el-input size="small" v-model="record.fileName" readonly></el-input>
</el-form-item>
</el-col>
<el-col :span="2">
<div>
<input type="file" ref="fileInput" accept=".json" @change="getFileData" style="display: none" />
<a href="javascript:;" class="icon-upload" @click="triggerFileInput">
<i class="el-icon-folder-opened"></i>
</a>
</div>
</el-col>
</el-row>
</el-form>
</my-dialog>
</template>

<script lang="ts">
import { Component, Vue, Prop, Watch } from 'vue-property-decorator'
import { Getter } from 'vuex-class'
import { importAllData } from '@/utils/api/setting'
import MyDialog from './MyDialog.vue'
import { ElLoadingComponent } from 'element-ui/types/loading'
type ImportFormat = 'JSON'
interface ImportForm {
importFormat: ImportFormat
fileName: string
fileContent?: string
}
@Component({
components: {
MyDialog,
},
})
export default class ImportData extends Vue {
@Getter('currentTheme') private theme!: Theme
@Prop({ default: false }) public visible!: boolean
private showDialog: boolean = this.visible
private confirmLoading: boolean = false
private record: ImportForm = {
importFormat: 'JSON',
fileName: '',
}
@Watch('visible')
private onVisibleChanged(val: boolean) {
this.showDialog = val
}
private triggerFileInput() {
;(this.$refs.fileInput as HTMLInputElement).click()
}
private getFileData(e: Event) {
const file = (e.target as HTMLInputElement).files?.[0]
if (!file) return
this.getFileContentByFileReader(file)
}
private getFileContentByFileReader(file: File) {
let loading: ElLoadingComponent | undefined = undefined
let reader = new FileReader()
reader.readAsText(file)
reader.onloadstart = () => {
loading = this.$loading({
target: '.import-data .el-dialog',
spinner: 'el-icon-loading',
})
}
reader.onloadend = () => {
loading?.close()
}
reader.onerror = () => {
this.$message.error(`${this.$t('connections.readFileErr')}${reader.error?.message}`)
}
reader.onload = () => {
this.record.fileName = file.name
this.record.fileContent = this.getDiffFormatData(reader.result as string)
}
}
private getDiffFormatData(content: string): string | undefined {
switch (this.record.importFormat) {
case 'JSON':
return this.getJSONData(content)
break
default:
break
}
}
private getJSONData(data: string): string {
return data
}
private async importData() {
this.confirmLoading = true
if (!this.record.fileContent) {
this.$message.error(this.$tc('connections.uploadFileTip'))
return
}
importAllData(this.record.fileContent)
this.confirmLoading = false
this.$message.success(this.$tc('common.importSuccess'))
this.resetData()
setTimeout(() => {
location.reload()
}, 1000)
}
private resetData() {
this.showDialog = false
this.$emit('update:visible', false)
this.record = {
importFormat: 'JSON',
fileName: '',
}
}
}
</script>

<style lang="scss">
.import-data {
.el-dialog__body {
padding-bottom: 0px;
.el-tooltip.icon-tip {
position: absolute;
right: 195px;
font-size: 16px;
color: var(--color-text-tips);
}
}
.icon-upload {
display: inline-block;
margin-top: 9px;
}
.icon-file-name {
cursor: default;
}
.el-col-2 {
padding-left: 5px !important;
}
.el-dialog {
overflow: hidden;
.el-loading-mask {
opacity: 0.5;
}
}
.import-data-tip {
margin-bottom: 12px;
word-break: break-word;
}
}
</style>
5 changes: 5 additions & 0 deletions web/src/lang/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,11 @@ export default {
en: 'Copy Failed',
ja: 'コピーが失敗しました',
},
importSuccess: {
zh: '导入成功',
en: 'Imported successfully',
ja: 'インポートが成功しました',
},
exportSuccess: {
zh: '导出成功',
en: 'exported successfully',
Expand Down
48 changes: 48 additions & 0 deletions web/src/lang/connections.ts
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,54 @@ export default {
en: 'When this switch is turned on, all Connections data can be exported',
ja: 'このスイッチをオンにすると、全ての接続のデータをエクスポートすることができます',
},
importData: {
zh: '导入数据',
en: 'Import Data',
ja: 'インポート',
},
importDataTip: {
zh: '导入完成后会断开所有连接,请手动点击连接进行恢复。',
en: 'After import, all connections will be disconnected, please click the connect button manually to restore.',
ja: 'インポート後、すべての接続が切断されます。復元するには、接続ボタンを手動でクリックしてください。',
},
importFormat: {
zh: '导入数据格式',
en: 'Import format',
ja: 'フォーマット',
},
importConnectionsTip: {
zh: '导入文件内容请参考导出数据生成的文件内容。<br>若 id 重复原数据将会被覆盖。',
en: `For the content of the imported file, please refer to<br>the
content of the file generated by the exported data.<br>
If id duplicates the original data will be overwritten.`,
ja: `インポートしたファイルの内容については、エクスポートされたデータで生成されたファイルの内容を参照してください。<br>
idが重複している場合は、元のデータが上書きされます。`,
},
importFile: {
zh: '导入文件',
en: 'Import File',
ja: 'ファイル',
},
readFileErr: {
zh: '文件读取失败:',
en: 'An error ocurred reading the file:',
ja: '読み込み中にエラーが発生したファイル:',
},
fileContentRequired: {
zh: '文件内容中必填项为空',
en: 'Required fields in the file content are empty',
ja: '必須フィールドに値を入力してください',
},
flieName: {
zh: '文件名',
en: 'File Name',
ja: 'ファイル名',
},
uploadFileTip: {
zh: '文件内容格式错误或为空',
en: 'The file content is malformed or empty',
ja: 'ファイルの内容が不正な形式または空です',
},
exportData: {
zh: '导出数据',
en: 'Export Data',
Expand Down
4 changes: 4 additions & 0 deletions web/src/utils/api/setting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ export const setSettings = (key: string, value: string | boolean | number): stri
return db.set<string | boolean | number>(key, value)
}

export const importAllData = (data: string): void => {
localStorage.setItem('db', data)
}

export const getAllData = (): $TSFixed => {
return db.read().value()
}
Expand Down
6 changes: 3 additions & 3 deletions web/src/utils/element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ import {
// TabPane,
// Tag,
// Tree,
// Alert,
Alert,
// Slider,
// Icon,
Row,
Expand Down Expand Up @@ -113,7 +113,7 @@ export default (Vue: any) => {
// Vue.use(TabPane)
// Vue.use(Tag)
// Vue.use(Tree)
// Vue.use(Alert)
Vue.use(Alert)
// Vue.use(Slider)
// Vue.use(Icon)
Vue.use(Row)
Expand Down Expand Up @@ -141,7 +141,7 @@ export default (Vue: any) => {

Vue.use(Loading.directive)

// Vue.prototype.$loading = Loading.service
Vue.prototype.$loading = Loading.service
// Vue.prototype.$msgbox = MessageBox
// Vue.prototype.$alert = MessageBox.alert
Vue.prototype.$confirm = MessageBox.confirm
Expand Down
25 changes: 25 additions & 0 deletions web/src/views/settings/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,23 @@
<div class="settings-title">{{ $t('settings.advanced') }}</div>
<el-divider></el-divider>

<el-row class="settings-item" type="flex" justify="space-between" align="middle">
<el-col :span="20">
<label>{{ $t('settings.dataRecovery') }}</label>
</el-col>
<el-col :span="4">
<el-button
class="data-manager-btn"
type="primary"
size="mini"
icon="el-icon-upload2"
@click="handleImportData"
>
</el-button>
</el-col>
</el-row>
<el-divider></el-divider>

<el-row class="settings-item" type="flex" justify="space-between" align="middle">
<el-col :span="20">
<label>{{ $t('settings.dataBackup') }}</label>
Expand Down Expand Up @@ -196,6 +213,7 @@
</el-row>
<el-divider></el-divider>

<ImportData :visible.sync="showImportData" />
<ExportData :visible.sync="showExportData" />
<ClearUpHistoryData :visible.sync="showHistoryData" />
</div>
Expand All @@ -205,11 +223,13 @@
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
import { Getter, Action } from 'vuex-class'
import ImportData from '@/components/ImportData.vue'
import ExportData from '@/components/ExportData.vue'
import ClearUpHistoryData from '@/components/ClearUpHistoryData.vue'
@Component({
components: {
ImportData,
ExportData,
ClearUpHistoryData,
},
Expand Down Expand Up @@ -243,6 +263,7 @@ export default class Settings extends Vue {
{ label: 'Night', value: 'night' },
]
private showImportData = false
private showExportData = false
private showHistoryData = false
Expand Down Expand Up @@ -277,6 +298,10 @@ export default class Settings extends Vue {
this.actionAutoScrollInterval({ autoScrollInterval: value })
}
private handleImportData() {
this.showImportData = true
}
private handleExportData() {
this.showExportData = true
}
Expand Down

0 comments on commit 95adbff

Please sign in to comment.