forked from github/dataease
refactor(应用): 应用导出增加设置应用信息,并导出为zip文件
This commit is contained in:
parent
19a6bd6058
commit
7fb148c7e8
@ -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",
|
||||
|
@ -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: {
|
||||
|
@ -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: {
|
||||
|
@ -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: {
|
||||
|
@ -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 => {
|
||||
|
@ -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;
|
||||
|
195
frontend/src/views/panel/list/AppExportForm.vue
Normal file
195
frontend/src/views/panel/list/AppExportForm.vue
Normal 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>
|
@ -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({
|
||||
|
Loading…
Reference in New Issue
Block a user