refactor(应用): 应用导出增加设置应用信息,并导出为zip文件

This commit is contained in:
wangjiahao 2022-10-28 17:40:40 +08:00
parent 19a6bd6058
commit 7fb148c7e8
8 changed files with 329 additions and 36 deletions

View File

@ -45,6 +45,7 @@
"js-cookie": "2.2.0",
"jsencrypt": "^3.0.0-rc.1",
"jspdf": "^2.3.1",
"jszip": "^3.10.1",
"lodash": "^4.17.21",
"lodash.isboolean": "^3.0.3",
"lodash.isempty": "^4.4.0",

View File

@ -2640,8 +2640,13 @@ export default {
dataset_group: 'Dataset group',
panel: 'Panel',
log_delete_tips: 'Are you sure to delete this application record?',
log_resource_delete_tips: 'Delete related resources (irrecoverable after deletion)'
log_resource_delete_tips: 'Delete related resources (irrecoverable after deletion)',
file_error_tips: 'The relevant data file is not found. The current file may not be a DataEase application file, or the file may be damaged ',
app_export: 'Application export',
app_version: 'Application version',
program_version: 'DataEase minimum version',
creator: 'Author',
export: 'Export'
},
logout: {

View File

@ -2630,7 +2630,6 @@ export default {
search_by_keyword: '通過關鍵字搜索',
apply_logs: '應用記錄',
app_group_delete_tips: '確定刪除該應用分類嗎?',
app_group_delete_content: '刪除後,該分類中所有的應用模板也將被刪除。',
panel_position: '儀表板位置',
panel_name: '儀表板名稱',
@ -2641,8 +2640,13 @@ export default {
dataset_group: '數據集分組',
panel: '儀表板',
log_delete_tips: '確定刪除該條應用記錄嗎?',
log_resource_delete_tips: '刪除相關資源(刪除後不可恢復)'
log_resource_delete_tips: '刪除相關資源(刪除後不可恢復)',
file_error_tips: '未找到相關數據文件當前文件可能不是DataEase應用文件或者文件已經損壞',
app_export: '应用导出',
app_version: '应用版本',
program_version: 'DataEase最低版本',
creator: '作者',
export: '导出'
},
logout: {

View File

@ -2630,7 +2630,6 @@ export default {
search_by_keyword: '通过关键字搜索',
apply_logs: '应用记录',
app_group_delete_tips: '确定删除该应用分类吗?',
app_group_delete_content: '删除后,该分类中所有的应用模板也将被删除。',
panel_position: '仪表板位置',
panel_name: '仪表板名称',
@ -2641,8 +2640,13 @@ export default {
dataset_group: '数据集分组',
panel: '仪表板',
log_delete_tips: '确定删除该条应用记录吗?',
log_resource_delete_tips: '删除相关资源(删除后不可恢复)'
log_resource_delete_tips: '删除相关资源(删除后不可恢复)',
file_error_tips: '未找到相关数据文件当前文件可能不是DataEase应用文件或者文件已经损坏',
app_export: '應用導出',
app_version: '應用版本',
program_version: 'DataEase最低版本',
creator: '作者',
export: '導出'
},
logout: {

View File

@ -259,7 +259,7 @@ const data = {
} else {
state.componentData.push(component)
}
this.commit('setCurComponent', { component: component, index: index ? index : state.componentData.length - 1 })
this.commit('setCurComponent', { component: component, index: index || state.componentData.length - 1 })
},
removeViewFilter(state, componentId) {
state.componentData = state.componentData.map(item => {

View File

@ -31,7 +31,7 @@
id="input"
ref="files"
type="file"
accept=".DEAPP"
accept=".zip"
hidden
@change="handleFileChange"
>
@ -47,14 +47,16 @@
secondary
@click="cancel()"
>{{
$t("commons.cancel")
}}</deBtn>
$t('commons.cancel')
}}
</deBtn>
<deBtn
type="primary"
@click="save()"
>{{
$t("commons.confirm")
}}</deBtn>
$t('commons.confirm')
}}
</deBtn>
</el-row>
</div>
</template>
@ -64,6 +66,7 @@ import { save, update, nameCheck } from '@/api/system/appTemplate'
import msgCfm from '@/components/msgCfm/index'
import { find } from '@/api/system/template'
import { imgUrlTrans } from '@/components/canvas/utils/utils'
import JSZip from 'jszip'
export default {
mixins: [msgCfm],
@ -186,22 +189,31 @@ export default {
})
},
handleFileChange(e) {
const jsZip = new JSZip()
const file = e.target.files[0]
const reader = new FileReader()
const _this = this
reader.onload = (res) => {
_this.appResultInfo = JSON.parse(res.target.result)
_this.importTemplateInfo = JSON.parse(this.appResultInfo.panelInfo)
_this.templateInfo.name = this.importTemplateInfo.name
_this.templateInfo.templateStyle = this.importTemplateInfo.panelStyle
_this.templateInfo.templateData = this.importTemplateInfo.panelData
_this.templateInfo.snapshot = this.importTemplateInfo.snapshot
_this.templateInfo.dynamicData = this.importTemplateInfo.dynamicData
_this.templateInfo.staticResource =
_this.importTemplateInfo.staticResource
_this.templateInfo.nodeType = 'template'
}
reader.readAsText(file)
jsZip.loadAsync(file).then(function(file) {
jsZip.file('DATA_RELATION.DE').async('string').then(function(content) {
_this.appResultInfo = { ...JSON.parse(content), ..._this.appResultInfo }
})
jsZip.file('APP.json').async('string').then(function(content) {
_this.appResultInfo['applicationInfo'] = content
const appInfo = JSON.parse(content)
_this.templateInfo.name = appInfo.appName
})
jsZip.file('TEMPLATE.DET').async('string').then(function(content) {
_this.appResultInfo['panelInfo'] = content
_this.importTemplateInfo = JSON.parse(content)
_this.templateInfo.templateStyle = _this.importTemplateInfo.panelStyle
_this.templateInfo.templateData = _this.importTemplateInfo.panelData
_this.templateInfo.snapshot = _this.importTemplateInfo.snapshot
_this.templateInfo.dynamicData = _this.importTemplateInfo.dynamicData
_this.templateInfo.staticResource = _this.importTemplateInfo.staticResource
_this.templateInfo.nodeType = 'template'
})
}).catch(() => {
_this.$warning(this.$t('app_template.file_error_tips'))
})
},
goFile() {
this.$refs.files.click()
@ -216,10 +228,12 @@ export default {
border: none;
padding: 0 0;
}
.my_table ::v-deep .el-table th.is-leaf {
/* 去除上边框 */
border: none;
}
.my_table ::v-deep .el-table::before {
/* 去除下边框 */
height: 0;
@ -229,6 +243,7 @@ export default {
margin-top: 24px;
text-align: right;
}
.preview {
margin-top: -12px;
border: 1px solid #e6e6e6;
@ -237,6 +252,7 @@ export default {
background-size: 100% 100% !important;
border-radius: 4px;
}
.preview-show {
border-left: 1px solid #e6e6e6;
height: 300px;
@ -250,6 +266,7 @@ export default {
display: flex;
align-items: center;
justify-content: space-between;
.el-input {
margin-right: 2px;
flex: 1;

View File

@ -0,0 +1,195 @@
<template>
<el-drawer
v-closePress
:title="$t('app_template.app_export')"
:visible.sync="applyDownloadDrawer"
custom-class="de-user-drawer"
size="600px"
direction="rtl"
>
<div class="app-export">
<el-form
ref="applyDownloadForm"
:model="form"
:rules="rule"
size="small"
class="de-form-item"
label-width="180px"
label-position="right"
>
<el-form-item
:label="$t('app_template.app_name')"
prop="appName"
>
<el-input
v-model="form.appName"
autocomplete="off"
:placeholder="$t('commons.input_name')"
/>
</el-form-item>
<el-form-item
:label="$t('app_template.app_version')"
prop="version"
>
<el-input
v-model="form.version"
autocomplete="off"
/>
</el-form-item>
<el-form-item
:label="$t('app_template.program_version')"
prop="required"
>
<el-input
v-model="form.required"
autocomplete="off"
/>
</el-form-item>
<el-form-item
:label="$t('app_template.creator')"
prop="creator"
>
<el-input
v-model="form.creator"
autocomplete="off"
/>
</el-form-item>
<el-form-item
:label="$t('commons.description')"
prop="description"
>
<deTextarea
v-model="form.description"
class="w100-textarea"
/>
</el-form-item>
</el-form>
</div>
<div
class="app-export-bottom"
>
<div
class="apply"
style="width: 100%"
>
<deBtn
secondary
@click="close"
>{{ $t('commons.cancel') }}
</deBtn>
<deBtn
type="primary"
@click="downloadApp"
>{{ $t('app_template.export') }}
</deBtn>
</div>
</div>
</el-drawer>
</template>
<script>
import i18n from '@/lang/index'
import deTextarea from '@/components/deCustomCm/deTextarea.vue'
import msgCfm from '@/components/msgCfm'
export default {
name: 'AppExportForm',
components: {
deTextarea
},
mixins: [msgCfm],
props: {},
data() {
return {
applyDownloadDrawer: false,
form: {
appName: null,
icon: null,
version: null,
creator: null,
required: '1.16.0',
description: null
},
rule: {
appName: [
{
required: true,
min: 2,
max: 25,
message: i18n.t('datasource.input_limit_2_25', [2, 25]),
trigger: 'blur'
}
],
creator: [
{
required: true,
min: 2,
max: 25,
message: i18n.t('datasource.input_limit_2_25', [2, 25]),
trigger: 'blur'
}
],
required: [
{
required: true,
min: 2,
max: 25,
message: i18n.t('datasource.input_limit_2_25', [2, 25]),
trigger: 'blur'
}
],
version: [
{
required: true,
min: 2,
max: 25,
message: i18n.t('datasource.input_limit_2_25', [2, 25]),
trigger: 'blur'
}
]
}
}
},
created() {
},
methods: {
init(params) {
this.applyDownloadDrawer = true
this.form = params
},
close() {
this.$emit('closeDraw')
this.applyDownloadDrawer = false
},
downloadApp() {
this.$refs.applyDownloadForm.validate(valid => {
if (valid) {
this.$emit('downLoadApp', this.form)
this.applyDownloadDrawer = false
} else {
return false
}
})
}
}
}
</script>
<style lang="scss" scoped>
.app-export{
width: 100%;
height: calc(100% - 56px);
}
.app-export-bottom{
width: 100%;
height: 56px;
text-align: right;
}
::v-deep .el-drawer__body{
padding-bottom: 0px!important;
}
</style>

View File

@ -120,7 +120,7 @@
>{{ $t('panel.export_to_img') }}</el-dropdown-item>
<el-dropdown-item
icon="el-icon-s-data"
@click.native="downLoadToApp"
@click.native="downLoadToAppPre"
>{{ $t('panel.export_to_app') }}</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
@ -278,6 +278,48 @@
@closePreExport="closePreExport"
/>
</el-dialog>
<el-dialog
v-if="appExportShow"
:title="'应用导出'"
:visible.sync="appExportShow"
width="80%"
:top="'8vh'"
:destroy-on-close="true"
class="dialog-css2"
>
<span style="position: absolute;right: 70px;top:15px">
<svg-icon
icon-class="PDF"
class="ds-icon-pdf"
/>
<el-select
v-model="pdfTemplateSelectedIndex"
:placeholder="'切换PDF模板'"
@change="changePdfTemplate()"
>
<el-option
v-for="(item, index) in pdfTemplateAll"
:key="index"
:label="item.name"
:value="index"
/>
</el-select>
</span>
<PDFPreExport
:snapshot="snapshotInfo"
:panel-name="panelInfo.name"
:template-content="pdfTemplateContent"
@closePreExport="closePreExport"
/>
</el-dialog>
<keep-alive>
<app-export-form
ref="appExportForm"
@downLoadApp="downLoadApp"
/>
</keep-alive>
</el-row>
</template>
<script>
@ -287,6 +329,7 @@ import SaveToTemplate from '@/views/panel/list/SaveToTemplate'
import { mapState } from 'vuex'
import html2canvas from 'html2canvasde'
import FileSaver from 'file-saver'
import JSZip from 'jszip'
import { starStatus, saveEnshrine, deleteEnshrine } from '@/api/panel/enshrine'
import bus from '@/utils/bus'
import { queryAll } from '@/api/panel/pdfTemplate'
@ -296,10 +339,11 @@ import { proxyInitPanelData } from '@/api/panel/shareProxy'
import { dataURLToBlob, getNowCanvasComponentData } from '@/components/canvas/utils/utils'
import { findResourceAsBase64 } from '@/api/staticResource/staticResource'
import PanelDetailInfo from '@/views/panel/list/common/PanelDetailInfo'
import AppExportForm from '@/views/panel/list/AppExportForm'
export default {
name: 'PanelViewShow',
components: { PanelDetailInfo, Preview, SaveToTemplate, PDFPreExport, ShareHead },
components: { AppExportForm, PanelDetailInfo, Preview, SaveToTemplate, PDFPreExport, ShareHead },
props: {
activeTab: {
type: String,
@ -320,6 +364,7 @@ export default {
hasStar: false,
fullscreen: false,
pdfExportShow: false,
appExportShow: false,
snapshotInfo: '',
showType: 0,
dataLoading: false,
@ -385,6 +430,9 @@ export default {
bus.$off('set-panel-share-user', this.setPanelShareUser)
},
methods: {
downLoadApp(appAttachInfo) {
this.downLoadToApp(appAttachInfo)
},
setPanelShowType(type) {
this.showType = type || 0
},
@ -458,10 +506,11 @@ export default {
_this.dataLoading = false
}
},
saveAppFile(appAttachInfo) {
saveAppFile(appRelationInfo, appAttachInfo) {
const _this = this
_this.dataLoading = true
try {
const jsZip = new JSZip()
_this.findStaticSource(function(staticResource) {
html2canvas(document.getElementById(_this.canvasInfoTemp)).then(canvas => {
_this.dataLoading = false
@ -473,11 +522,19 @@ export default {
snapshot: snapshot,
panelStyle: JSON.stringify(_this.canvasStyleData),
panelData: JSON.stringify(_this.componentData),
dynamicData: JSON.stringify(_this.panelViewDetailsInfo),
staticResource: JSON.stringify(staticResource || {})
}
appAttachInfo['panelInfo'] = JSON.stringify(panelInfo)
const blob = new Blob([JSON.stringify(appAttachInfo)], { type: '' })
FileSaver.saveAs(blob, _this.$store.state.panel.panelInfo.name + '-APP.DEAPP')
const blobTemplate = new Blob([JSON.stringify(panelInfo)], { type: '' })
const blobRelation = new Blob([JSON.stringify(appRelationInfo)], { type: '' })
const blobAppInfo = new Blob([JSON.stringify(appAttachInfo)], { type: '' })
jsZip.file('TEMPLATE.DET', blobTemplate, { binary: true })
jsZip.file('DATA_RELATION.DE', blobRelation, { binary: true })
jsZip.file('APP.json', blobAppInfo, { binary: true })
jsZip.generateAsync({ type: 'blob' }).then(content => {
//
FileSaver.saveAs(content, appAttachInfo.appName + '.zip') // file-saver
})
}
})
})
@ -486,11 +543,21 @@ export default {
_this.dataLoading = false
}
},
downLoadToApp() {
downLoadToAppPre() {
this.$refs.appExportForm.init({
appName: this.$store.state.panel.panelInfo.name,
icon: null,
version: '1.0',
creator: this.$store.getters.user.nickName,
required: '1.16.0',
description: null
})
},
downLoadToApp(appAttachInfo) {
this.dataLoading = true
export2AppCheck(this.$store.state.panel.panelInfo.id).then(rsp => {
if (rsp.data.checkStatus) {
this.saveAppFile(rsp.data)
this.saveAppFile(rsp.data, appAttachInfo)
} else {
this.dataLoading = false
this.$message({