模板资源修改

This commit is contained in:
jingna 2025-06-27 18:29:43 +08:00
parent f283f3ad59
commit 1bd7d778d2
10 changed files with 1514 additions and 214 deletions

View File

@ -522,6 +522,9 @@ const initOpenHandler = newWindow => {
}
openHandler.value.invokeMethod(pm)
}
}
function saveas(){
}
</script>
@ -538,9 +541,9 @@ const initOpenHandler = newWindow => {
</template>
<template v-else>
<el-icon v-if="!batchOptStatus" class="custom-el-icon back-icon" @click="backToMain()">
<Icon name="icon_left_outlined"
><icon_left_outlined class="svg-icon toolbar-icon"
/></Icon>
<Icon name="icon_left_outlined">
<icon_left_outlined class="svg-icon toolbar-icon" />
</Icon>
</el-icon>
<div class="left-area" v-if="editMode === 'edit' && !batchOptStatus">
<span id="canvas-name" class="name-area" @dblclick="editCanvasName">
@ -548,25 +551,21 @@ const initOpenHandler = newWindow => {
</span>
<div class="opt-area">
<el-tooltip effect="dark" :content="$t('visualization.undo')" placement="bottom">
<el-icon
class="toolbar-hover-icon"
:class="{ 'toolbar-icon-disabled': snapshotIndex < 1 }"
:disabled="snapshotIndex < 1"
@click="undo()"
>
<Icon name="icon_undo_outlined"><icon_undo_outlined class="svg-icon" /></Icon>
<el-icon class="toolbar-hover-icon" :class="{ 'toolbar-icon-disabled': snapshotIndex < 1 }"
:disabled="snapshotIndex < 1" @click="undo()">
<Icon name="icon_undo_outlined">
<icon_undo_outlined class="svg-icon" />
</Icon>
</el-icon>
</el-tooltip>
<el-tooltip effect="dark" :content="$t('commons.reduction')" placement="bottom">
<el-icon
class="toolbar-hover-icon opt-icon-redo"
:class="{
<el-icon class="toolbar-hover-icon opt-icon-redo" :class="{
'toolbar-icon-disabled': snapshotIndex === snapshotStore.snapshotData.length - 1
}"
@click="redo()"
>
<Icon name="icon_redo_outlined"><icon_redo_outlined class="svg-icon" /></Icon>
}" @click="redo()">
<Icon name="icon_redo_outlined">
<icon_redo_outlined class="svg-icon" />
</Icon>
</el-icon>
</el-tooltip>
</div>
@ -577,127 +576,61 @@ const initOpenHandler = newWindow => {
</el-col>
</div>
<div class="middle-area" v-if="!batchOptStatus && !linkageSettingStatus">
<component-group
:base-width="410"
:show-split-line="true"
is-label
:icon-name="dvView"
themes="light"
:title="t('chart.datalist')"
>
<component-group :base-width="410" :show-split-line="true" is-label :icon-name="dvView" themes="light"
:title="t('chart.datalist')">
<user-view-group themes="light" :dv-model="dvModel"></user-view-group>
</component-group>
<component-group
:base-width="115"
:show-split-line="true"
is-label
themes="light"
:icon-name="dvFilter"
:title="t('visualization.filter_component')"
>
<component-group :base-width="115" :show-split-line="true" is-label themes="light" :icon-name="dvFilter"
:title="t('visualization.filter_component')">
<query-group themes="light" :dv-model="dvModel"></query-group>
</component-group>
<component-group
is-label
themes="light"
:base-width="115"
:icon-name="dvText"
:title="t('components.rich_text')"
>
<component-group is-label themes="light" :base-width="115" :icon-name="dvText"
:title="t('components.rich_text')">
<text-group themes="light" :dv-model="dvModel"></text-group>
</component-group>
<component-group
is-label
themes="light"
placement="bottom"
:base-width="328"
:icon-name="dvMedia"
:title="t('components.media')"
>
<component-group is-label themes="light" placement="bottom" :base-width="328" :icon-name="dvMedia"
:title="t('components.media')">
<media-group themes="light" :dv-model="dvModel"></media-group>
</component-group>
<component-group themes="light" is-label :base-width="115" :icon-name="dvTab" title="Tab">
<tabs-group themes="light" :dv-model="dvModel"></tabs-group>
</component-group>
<component-group
themes="light"
show-split-line
is-label
:base-width="115"
:icon-name="dvMoreCom"
:title="t('visualization.more')"
>
<component-group themes="light" show-split-line is-label :base-width="115" :icon-name="dvMoreCom"
:title="t('visualization.more')">
<db-more-com-group themes="light" :dv-model="dvModel"></db-more-com-group>
</component-group>
<component-button-label
:icon-name="icon_copy_filled"
:title="t('visualization.multiplexing')"
is-label
@customClick="multiplexingCanvasOpen"
></component-button-label>
<component-button-label :icon-name="icon_copy_filled" :title="t('visualization.multiplexing')" is-label
@customClick="multiplexingCanvasOpen"></component-button-label>
</div>
</template>
<div class="right-area" v-if="!batchOptStatus && !linkageSettingStatus">
<template v-if="editMode !== 'preview'">
<el-tooltip
effect="dark"
:content="t('visualization.outer_param_set')"
placement="bottom"
>
<component-button
:tips="t('visualization.outer_param_set')"
@custom-click="openOuterParamsSet"
:icon-name="icon_params_setting"
/>
<el-tooltip effect="dark" :content="t('visualization.outer_param_set')" placement="bottom">
<component-button :tips="t('visualization.outer_param_set')" @custom-click="openOuterParamsSet"
:icon-name="icon_params_setting" />
</el-tooltip>
<el-tooltip effect="dark" :content="t('visualization.batch_opt')" placement="bottom">
<component-button
:tips="t('visualization.batch_opt')"
@custom-click="batchOptStatusChange(true)"
:icon-name="dvBatch"
/>
<component-button :tips="t('visualization.batch_opt')" @custom-click="batchOptStatusChange(true)"
:icon-name="dvBatch" />
</el-tooltip>
<el-tooltip
effect="dark"
:content="t('components.dashboard_configuration')"
placement="bottom"
>
<component-button
:tips="t('components.dashboard_configuration')"
@custom-click="openDataBoardSetting"
:icon-name="dvDashboard"
/>
<el-tooltip effect="dark" :content="t('components.dashboard_configuration')" placement="bottom">
<component-button :tips="t('components.dashboard_configuration')" @custom-click="openDataBoardSetting"
:icon-name="dvDashboard" />
</el-tooltip>
<el-tooltip
effect="dark"
:content="t('visualization.hidden_components')"
placement="bottom"
>
<component-button
:tips="t('visualization.hidden_components')"
@custom-click="openHiddenList"
:icon-name="dvHidden"
/>
<el-tooltip effect="dark" :content="t('visualization.hidden_components')" placement="bottom">
<component-button :tips="t('visualization.hidden_components')" @custom-click="openHiddenList"
:icon-name="dvHidden" />
</el-tooltip>
<div class="divider"></div>
<template v-if="!desktop">
<el-tooltip
:offset="14"
effect="dark"
:content="t('components.to_mobile_layout')"
placement="bottom"
>
<component-button
:tips="t('components.to_mobile_layout')"
@custom-click="openMobileSetting"
:icon-name="icon_phone_outlined"
/>
<el-tooltip :offset="14" effect="dark" :content="t('components.to_mobile_layout')" placement="bottom">
<component-button :tips="t('components.to_mobile_layout')" @custom-click="openMobileSetting"
:icon-name="icon_phone_outlined" />
</el-tooltip>
</template>
</template>
<el-dropdown v-if="editMode === 'edit'" trigger="hover">
<el-button class="preview-button" style="float: right; margin-right: 12px">
{{ t('visualization.preview') }}
@ -706,13 +639,17 @@ const initOpenHandler = newWindow => {
<el-dropdown-menu class="drop-style">
<el-dropdown-item @click="previewInner" v-if="!isIframe">
<el-icon style="margin-right: 8px; font-size: 16px">
<Icon name="icon_pc_fullscreen"><icon_pc_fullscreen class="svg-icon" /></Icon>
<Icon name="icon_pc_fullscreen">
<icon_pc_fullscreen class="svg-icon" />
</Icon>
</el-icon>
{{ t('visualization.fullscreen_preview') }}
</el-dropdown-item>
<el-dropdown-item @click="previewOuter()">
<el-icon style="margin-right: 8px; font-size: 16px">
<Icon><dvPreviewOuter class="svg-icon" /></Icon>
<Icon>
<dvPreviewOuter class="svg-icon" />
</Icon>
</el-icon>
{{ t('work_branch.new_page_preview') }}
</el-dropdown-item>
@ -720,102 +657,51 @@ const initOpenHandler = newWindow => {
</template>
</el-dropdown>
<el-button
class="custom-normal-button"
v-if="editMode === 'preview'"
icon="EditPen"
@click="edit()"
type="primary"
>
<el-button class="custom-normal-button" v-if="editMode === 'preview'" icon="EditPen" @click="edit()"
type="primary">
{{ t('data_set.edit') }}
</el-button>
<el-button
v-if="editMode === 'edit' || editMode === 'preview'"
:disabled="styleChangeTimes < 1"
@click="saveCanvasWithCheck()"
style="float: right; margin-right: 12px"
type="primary"
class="savebtn"
>
<el-button class="savebtn" type="primary" @click="saveas">另存为</el-button>
<el-button v-if="editMode === 'edit' || editMode === 'preview'" :disabled="styleChangeTimes < 1"
@click="saveCanvasWithCheck()" style="float: right; margin-right: 12px" type="primary" class="savebtn">
{{ t('data_set.save') }}
</el-button>
</div>
<div class="right-area full-area" v-if="batchOptStatus">
<el-button
text
icon="CopyDocument"
class="custom-normal-button"
@click="batchCopy"
:disabled="curBatchOptComponents.length === 0"
style="float: right; margin-right: 12px"
>
{{ t('data_set.copy') }}</el-button
>
<el-button text icon="CopyDocument" class="custom-normal-button" @click="batchCopy"
:disabled="curBatchOptComponents.length === 0" style="float: right; margin-right: 12px">
{{ t('data_set.copy') }}</el-button>
<el-button
text
icon="Delete"
class="custom-normal-button"
@click="batchDelete"
:disabled="curBatchOptComponents.length === 0"
style="float: right; margin-right: 12px"
>
{{ t('data_set.delete') }}</el-button
>
<el-button text icon="Delete" class="custom-normal-button" @click="batchDelete"
:disabled="curBatchOptComponents.length === 0" style="float: right; margin-right: 12px">
{{ t('data_set.delete') }}</el-button>
<el-button
@click="saveBatchChange"
style="float: right; margin-right: 12px"
type="primary"
>{{ t('components.complete') }}</el-button
>
<el-button @click="saveBatchChange" style="float: right; margin-right: 12px" type="primary">{{
t('components.complete') }}</el-button>
</div>
<div class="right-area full-area" v-if="linkageSettingStatus">
<el-button
class="custom-normal-button"
@click="cancelLinkageSetting()"
style="float: right; margin-right: 12px"
>
{{ t('userimport.cancel') }}</el-button
>
<el-button
@click="saveLinkageSetting"
style="float: right; margin-right: 12px"
type="primary"
>{{ t('userimport.sure') }}</el-button
>
<el-button class="custom-normal-button" @click="cancelLinkageSetting()"
style="float: right; margin-right: 12px">
{{ t('userimport.cancel') }}</el-button>
<el-button @click="saveLinkageSetting" style="float: right; margin-right: 12px" type="primary">{{
t('userimport.sure')
}}</el-button>
</div>
</div>
<Teleport v-if="nameEdit" :to="'#canvas-name'">
<input
@change="onDvNameChange"
ref="nameInput"
v-model="inputName"
@blur="closeEditCanvasName"
/>
<input @change="onDvNameChange" ref="nameInput" v-model="inputName" @blur="closeEditCanvasName" />
</Teleport>
<multiplexing-canvas ref="multiplexingRef"></multiplexing-canvas>
<de-resource-group-opt
@finish="resourceOptFinish"
cur-canvas-type="dashboard"
ref="resourceGroupOpt"
/>
<de-resource-group-opt @finish="resourceOptFinish" cur-canvas-type="dashboard" ref="resourceGroupOpt" />
<outer-params-set ref="outerParamsSetRef"> </outer-params-set>
</div>
<de-fullscreen show-position="edit" ref="fullScreeRef"></de-fullscreen>
<XpackComponent ref="openHandler" jsname="L2NvbXBvbmVudC9lbWJlZGRlZC1pZnJhbWUvT3BlbkhhbmRsZXI=" />
<de-app-apply
ref="resourceAppOpt"
:component-data="componentData"
:dv-info="dvInfo"
:canvas-view-info="canvasViewInfo"
cur-canvas-type="dashboard"
@saveAppCanvas="saveCanvasWithCheck"
></de-app-apply>
<de-app-apply ref="resourceAppOpt" :component-data="componentData" :dv-info="dvInfo"
:canvas-view-info="canvasViewInfo" cur-canvas-type="dashboard" @saveAppCanvas="saveCanvasWithCheck"></de-app-apply>
</template>
<style lang="less" scoped>
@ -823,33 +709,40 @@ const initOpenHandler = newWindow => {
.group_icon+.ed-button {
margin-left: 10px;
}
.drop-style {
:deep(.ed-dropdown-menu__item) {
padding: 5px 12px !important;
}
:deep(.ed-dropdown-menu__item:not(.is_disabled):focus) {
color: inherit;
background-color: rgba(31, 35, 41, 0.1);
}
}
.full-area {
flex: 1;
}
.edit-button {
right: 10px;
top: 10px;
position: absolute;
z-index: 10;
}
.toolbar-main {
position: relative;
}
.preview-state-head {
height: 0px !important;
overflow: hidden;
padding: 0;
margin: 0;
}
.toolbar {
height: @top-bar-height;
white-space: nowrap;
@ -858,17 +751,20 @@ const initOpenHandler = newWindow => {
color: #ffffff;
display: flex;
transition: 0.5s;
.back-icon {
margin-left: 20px;
margin-top: 22px;
font-size: 20px;
}
.left-area {
margin-top: 8px;
margin-left: 14px;
width: 300px;
display: flex;
flex-direction: column;
.name-area {
position: relative;
line-height: 24px;
@ -877,6 +773,7 @@ const initOpenHandler = newWindow => {
width: 300px;
overflow: hidden;
cursor: pointer;
input {
position: absolute;
left: 0;
@ -890,6 +787,7 @@ const initOpenHandler = newWindow => {
height: 100%;
}
}
.opt-area {
width: 300px;
text-align: left;
@ -900,12 +798,14 @@ const initOpenHandler = newWindow => {
}
}
}
.middle-area {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
}
.right-area {
width: 400px;
display: flex;
@ -919,12 +819,14 @@ const initOpenHandler = newWindow => {
margin: 0 10px;
}
}
.custom-el-icon {
margin-left: 15px;
color: #ffffff;
cursor: pointer;
vertical-align: -0.2em;
}
.toolbar-icon {
width: 20px;
height: 20px;
@ -937,6 +839,7 @@ const initOpenHandler = newWindow => {
// background-color: #050e21;
background-color: transparent;
border-color: rgba(255, 255, 255, 0.3);
&:hover,
&:focus {
// background-color: #121a2c;
@ -948,18 +851,22 @@ const initOpenHandler = newWindow => {
// background-color: #1e2637;
}
}
.custom-normal-button {
background-color: transparent;
border-color: #a6a6a6 !important;
color: #ffffff !important;
&:hover {
color: #ffffff;
background-color: #ffffff1a !important;
}
&:active {
color: #ffffff;
background-color: #ffffff33 !important;
}
&.is-disabled {
color: var(--ed-button-disabled-text-color) !important;
}
@ -972,11 +879,15 @@ const initOpenHandler = newWindow => {
font-weight: 400;
padding-top: 14px;
}
.savebtn {
background: #0089ff;
border: 1px solid #0089ff;
}
.ed-button.is-disabled, .ed-button.is-disabled:focus, .ed-button.is-disabled:hover {
.ed-button.is-disabled,
.ed-button.is-disabled:focus,
.ed-button.is-disabled:hover {
color: #fff;
cursor: not-allowed;
background-image: none;

View File

@ -247,6 +247,29 @@ export const routes: AppRouteRecordRaw[] = [
hidden: true,
meta: {},
component: () => import('@/viewsnew/application/SystemLogin.vue')
},
{
path: '/TemplateResource',
name: 'TemplateResource',
redirect: '/TemplateResource/index',
component: () => import('@/viewsnew/layout/index.vue'),
hidden: true,
meta: {},
children: [
{
path: 'index',
name: 'TemplateResource',
hidden: true,
component: () => import('@/viewsnew/TemplateResource/index.vue'),
meta: { hidden: true }
},
]
},{
path: '/TemplatePreview',
name: 'TemplatePreview',
hidden: true,
meta: {},
component: () => import('@/viewsnew/TemplateResource/preview/index.vue')
}
]

View File

@ -175,7 +175,7 @@
</div>
</el-row>
<el-row v-show="!state.networkStatus" class="template-empty">
111 {{ t('visualization.market_network_tips', [state.baseUrl]) }}
{{ t('visualization.market_network_tips', [state.baseUrl]) }}
</el-row>
</el-row>
</el-row>
@ -461,6 +461,7 @@ const nextOne = () => {
}
const templateApply = template => {
debugger
state.curApplyTemplate = template
state.dvCreateForm.name = template.title
state.dvCreateForm.nodeType = template.templateType

View File

@ -0,0 +1,99 @@
<script lang="ts" setup>
import { ref, onMounted, reactive, computed } from 'vue'
import type { FormInstance } from 'element-plus'
import { ElMessage } from 'element-plus-secondary'
import { useI18n } from '@/hooks/web/useI18n'
import {save} from '@/api/template'
const emits = defineEmits(['closeClassDialog', 'classrefresh'])
const { t } = useI18n()
const classform = ref({ name: '', nodeType: 'folder', templateType: 'self', level: 0 })
const ruleFormRef = ref<FormInstance>()
const rules = ref({
name: [
{ required: true, message: '请输入分类名称', trigger: 'blur' },
]
})
const submitForm = async (formEl: FormInstance | undefined) => {
if (classform.value.name === t('work_branch.recently_used')) {
ElMessage({
message: t('template_manage.illegal_name_hint'),
type: 'error',
showClose: true
})
return
}
if (!formEl) return
await formEl.validate((valid, fields) => {
if (valid) {
save({ ...classform.value }).then(() => {
ElMessage({
message: '添加成功',
type: 'success',
showClose: true
})
emits('classrefresh')
emits('closeClassDialog')
})
} else {
ElMessage({
message: '添加失败',
type: 'error',
showClose: true
})
}
})
}
function cancel() {
emits('closeClassDialog')
}
</script>
<template>
<div class="template-import">
<el-form ref="ruleFormRef" :rules="rules" :model="classform" label-width="80px">
<el-form-item label="分类名称" prop="name">
<el-input v-model="classform.name" />
</el-form-item>
</el-form>
<div style="display: flex;justify-content: flex-end;">
<el-button @click="cancel">取消</el-button>
<el-button type="primary" @click="submitForm(ruleFormRef)">确定</el-button>
</div>
</div>
</template>
<style lang="less" scoped>
.preview {
margin-top: -8px;
border: 1px solid #e6e6e6;
height: 300px !important;
overflow: auto;
background-size: 100% 100% !important;
border-radius: 4px;
margin-bottom: 10px;
}
.flex-template {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
.el-input {
margin-right: 2px;
flex: 1;
}
}
.class-add {
width: 100%;
background-color: transparent;
padding: 10px;
font-size: 14px;
cursor: pointer;
}
.class-add:hover {
background-color: #434343;
;
}
</style>

View File

@ -0,0 +1,293 @@
<script lang="ts" setup>
import { ref, onMounted, reactive, computed } from 'vue'
import { save, nameCheck, findOne, categoryTemplateNameCheck } from '@/api/template'
import type { FormInstance } from 'element-plus'
import { ElMessage, ElMessageBox } from 'element-plus-secondary'
import { useI18n } from '@/hooks/web/useI18n'
import { imgUrlTrans } from '@/utils/imgUtils'
import { findCategories } from '@/api/template'
import AddTemplateClass from '@/viewsnew/TemplateResource/addclass.vue'
const props = defineProps({
classList: {
type: Array,
required: true
},
optType: {
type: String,
required: true,
default: 'insert'
},
})
const emits = defineEmits(['closeTemplateDialog', 'init'])
const { t } = useI18n()
const importform = ref({ name: '' })
const ruleFormRef = ref<FormInstance>()
const pid = ref('')
const filesRef = ref(null)
const maxImageSize = 35000000
const dialogVisible = ref(false)
const state = reactive({
categories: [],
nameList: [],
importTemplateInfo: {
snapshot: ''
},
templateInfoRules: {
name: [
{
required: true,
message: t('commons.input_content'),
trigger: 'change'
},
{
max: 50,
message: t('commons.char_can_not_more_50'),
trigger: 'change'
}
],
categories: [
{
required: true,
message: t('commons.input_content'),
trigger: 'change'
}
]
},
recover: false,
templateInfo: {
id: null,
level: '1',
pid: pid,
categories: [],
dvType: 'dashboard',
nodeType: 'template',
name: '',
templateStyle: null,
templateData: null,
dynamicData: null,
appData: null,
staticResource: null,
snapshot: '',
version: null
},
templateCategories: []
})
const handleFileChange = e => {
const file = e.target.files[0]
const reader = new FileReader()
if (file.size > maxImageSize) {
ElMessage.success(t('template_manage.template_size_hint'))
return
}
reader.onload = res => {
const result = res.target.result as string
state.importTemplateInfo = JSON.parse(result)
state.templateInfo.name = state.importTemplateInfo['name']
state.templateInfo.dvType = state.importTemplateInfo['dvType']
state.templateInfo.templateStyle = state.importTemplateInfo['canvasStyleData']
state.templateInfo.templateData = state.importTemplateInfo['componentData']
state.templateInfo.snapshot = state.importTemplateInfo.snapshot
state.templateInfo.dynamicData = state.importTemplateInfo['dynamicData']
state.templateInfo.appData = state.importTemplateInfo['appData']
state.templateInfo.staticResource = state.importTemplateInfo['staticResource']
state.templateInfo['nodeType'] = state.importTemplateInfo['nodeType'] || 'template'
state.templateInfo['version'] = state.importTemplateInfo['version']
}
importform.value.name = state.importTemplateInfo['name']
console.log(importform.value.name, 9999)
reader.readAsText(file)
}
const goFile = () => {
filesRef.value.click()
}
const classBackground = computed(() => {
if (state.templateInfo.snapshot) {
return {
background: `url(${imgUrlTrans(state.templateInfo.snapshot)}) no-repeat`
}
} else {
return {}
}
})
onMounted(() => {
queryclass()
})
function queryclass() {
const request = {
templateType: 'self',
level: '0'
}
findCategories(request).then(res => {
state.templateCategories = res.data
console.log(res.data)
})
}
function saveTemplate() {
if (!state.templateInfo.name) {
ElMessage.warning(t('chart.name_can_not_empty'))
return false
}
if (state.templateInfo.name.length > 50) {
ElMessage.warning(t('commons.char_can_not_more_50'))
return false
}
if (!state.templateInfo.templateData) {
ElMessage.warning(t('chart.template_can_not_empty'))
return false
}
if (!state.templateInfo.categories.length) {
ElMessage.warning(t('template_manage.please_select_catalog'))
return false
}
if (props.optType === 'insert') {
importTemplate()
} else {
editTemplate()
}
}
const editTemplate = () => {
const nameCheckRequest = {
pid: state.templateInfo.pid,
id: state.templateInfo.id,
name: state.templateInfo.name,
categories: state.templateInfo.categories,
optType: props.optType
}
//
nameCheck(nameCheckRequest).then(response => {
if (response.data.indexOf('exist') > -1) {
ElMessage.warning('当前分类存在相同模板名称,是否覆盖')
} else {
save(state.templateInfo).then(() => {
ElMessage.success('导入成功')
emits('init')
emits('closeTemplateDialog')
})
}
})
}
const importTemplate = () => {
const nameCheckRequest = {
pid: state.templateInfo.pid,
name: state.templateInfo.name,
categories: state.templateInfo.categories,
optType: props.optType
}
categoryTemplateNameCheck(nameCheckRequest).then(response => {
if (response.data.indexOf('exist') > -1) {
ElMessageBox.confirm('提示', {
tip: '当前分类存在相同模板名称,是否覆盖?',
confirmButtonType: 'danger',
type: 'warning',
autofocus: false,
showClose: false
}).then(() => {
save(state.templateInfo).then(() => {
ElMessage.success('导入成功')
emits('init')
emits('closeTemplateDialog')
})
})
} else {
//
nameCheck(nameCheckRequest).then(response => {
if (response.data.indexOf('exist') > -1) {
ElMessage.warning('当前名称已在模版管理中存在,请修改')
} else {
save(state.templateInfo).then(() => {
ElMessage.success(t('导入成功'))
emits('init')
emits('closeTemplateDialog')
})
}
})
}
})
}
function cancel() {
emits('closeTemplateDialog')
}
function addclassclick() {
dialogVisible.value = true
}
function closeClassDialog() {
dialogVisible.value = false
}
function classrefresh(){
queryclass()
}
</script>
<template>
<div class="template-import">
<el-form ref="ruleFormRef" :model="state.templateInfo" label-width="80px">
<el-form-item label="模板名称" prop="name">
<div class="flex-template">
<el-input v-model="state.templateInfo.name" />
<el-button style="margin-left: 10px" icon="Upload" @click="goFile">导入模板</el-button>
</div>
<input id="input" ref="filesRef" type="file" accept=".DET2,.DET2APP" hidden
@change="handleFileChange" />
</el-form-item>
<el-row v-show="!!state.templateInfo.snapshot" class="preview" :style="classBackground" />
<el-form-item label="分类" prop="name">
<el-select v-model="state.templateInfo.categories" multiple placeholder="请选择分类" style="width: 100%">
<el-option v-for="item in state.templateCategories" :key="item.id" :label="item.name"
:value="item.id" />
<template #footer>
<div class="class-add" @click="addclassclick">
添加分类
</div>
</template>
</el-select>
</el-form-item>
</el-form>
<div style="display: flex;justify-content: flex-end;">
<el-button @click="cancel">取消</el-button>
<el-button type="primary" @click="saveTemplate">确定</el-button>
</div>
<el-dialog v-model="dialogVisible" append-to-body title="添加分类" width="30%" :before-close="closeClassDialog">
<AddTemplateClass v-if="dialogVisible" @classrefresh="classrefresh" @closeClassDialog="closeClassDialog" />
</el-dialog>
</div>
</template>
<style lang="less" scoped>
.preview {
margin-top: -8px;
border: 1px solid #e6e6e6;
height: 300px !important;
overflow: auto;
background-size: 100% 100% !important;
border-radius: 4px;
margin-bottom: 10px;
}
.flex-template {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
.el-input {
margin-right: 2px;
flex: 1;
}
}
.class-add {
width: 100%;
background-color: transparent;
padding: 10px;
font-size: 14px;
cursor: pointer;
}
.class-add:hover {
background-color: #434343;
;
}
</style>

View File

@ -0,0 +1,663 @@
<script lang="ts" setup>
import { ref, onMounted, reactive, computed } from 'vue'
import { useRouter } from 'vue-router'
import { searchMarketPreview } from '@/api/templateMarket'
import { useI18n } from '@/hooks/web/useI18n'
import { useCache } from '@/hooks/web/useCache'
import { ElMessage } from 'element-plus-secondary'
import { Base64 } from 'js-base64'
import { useEmbedded } from '@/store/modules/embedded'
import { useAppStoreWithOut } from '@/store/modules/app'
import { useEmitt } from '@/hooks/web/useEmitt'
import type { FormInstance } from 'element-plus'
import AddTemplate from '@/viewsnew/TemplateResource/addtemplate.vue'
import AddTemplateClass from '@/viewsnew/TemplateResource/addclass.vue'
import { update } from 'lodash'
const basePath = import.meta.env.VITE_API_BASEPATH
const router = useRouter()
const { t } = useI18n()
const { wsCache } = useCache()
const keywords: any = ref("") //
const dataList: any = ref([])
const classList: any = ref([])
const mask = ref(-1) //
const activeIndex: any = ref(null)
const detailsList: any = ref([])
const loading: any = ref(false)
const embeddedStore = useEmbedded()
const appStore = useAppStoreWithOut()
const isEmbedded = computed(() => appStore.getIsDataEaseBi || appStore.getIsIframe)
const state = reactive({
initReady: true,
curPosition: 'branch',
pid: null,
treeProps: {
value: 'label',
label: 'label'
},
templateType: 'all', //
templateSourceType: 'all', //
templateClassifyType: 'all', //
treeShow: true,
templateClassifyOptions: [
{
value: 'all',
label: t('visualization.all_type')
},
{
value: 'app',
label: t('visualization.apply_template')
},
{
value: 'template',
label: t('visualization.style_template')
}
],
templateSourceOptions: [
{
value: 'all',
label: t('work_branch.all_source')
},
{
value: 'market',
label: t('visualization.template_market')
},
{
value: 'manage',
label: t('template_manage.name')
}
],
templateTypeOptions: [
{
value: 'all',
label: t('work_branch.all_types')
},
{
value: 'PANEL',
label: t('work_branch.dashboard')
},
{
value: 'SCREEN',
label: t('work_branch.big_data_screen')
}
],
loading: false,
hasResult: true,
templateMiniWidth: 250,
templateCurWidth: 310,
templateSpan: '25%',
previewVisible: false,
templatePreviewId: '',
marketTabs: [],
marketActiveTab: null,
searchText: null,
dvCreateForm: {
resourceName: null,
name: null,
pid: null,
nodeType: 'panel',
templateUrl: null,
newFrom: 'new_market_template',
templateId: null,
panelType: 'self',
panelStyle: {},
panelData: '[]'
},
panelGroupList: [],
curApplyTemplate: null,
folderSelectShow: false,
baseUrl: 'https://dataease.io/templates',
currentMarketTemplateShowList: [],
curTemplateShowFilter: [],
curTemplateIndex: 0,
curTemplate: null,
networkStatus: true,
rule: {
name: [
{
required: true,
message: t('visualization.template_name_tips'),
trigger: 'blur'
}
],
pid: [
{
required: true,
message: '',
trigger: 'blur'
}
]
}
})
const templateApply = (template: any) => {
state.curApplyTemplate = template
state.dvCreateForm.name = template.title
state.dvCreateForm.nodeType = template.templateType
if (template.source === 'market') {
state.dvCreateForm.newFrom = 'new_market_template'
state.dvCreateForm.templateUrl = template.metas.theme_repo
state.dvCreateForm.resourceName = template.id
} else {
state.dvCreateForm.newFrom = 'new_inner_template'
state.dvCreateForm.templateId = template.id
}
apply()
}
const apply = () => {
if (state.dvCreateForm.newFrom === 'new_market_template' && !state.dvCreateForm.templateUrl) {
ElMessage.warning(t('template_manage.get_download_link_hint'))
return false
}
const templateTemplate = {
newFrom: state.dvCreateForm.newFrom,
templateUrl: state.dvCreateForm.templateUrl,
resourceName: state.dvCreateForm.resourceName,
templateId: state.dvCreateForm.templateId
}
state.curApplyTemplate.recentUseTime = Date.now()
state.curApplyTemplate.categoryNames.push(t('work_branch.recent'))
const baseUrl =
(['dataV', 'SCREEN'].includes(state.dvCreateForm.nodeType)
? '#/dvCanvas?opt=create&createType=template'
: '#/dashboard?opt=create&createType=template') +
'&templateParams=' +
encodeURIComponent(Base64.encode(JSON.stringify(templateTemplate)))
let newWindow = null
if (isEmbedded.value) {
embeddedStore.clearState()
embeddedStore.setCreateType('template')
embeddedStore.setTemplateParams(
encodeURIComponent(Base64.encode(JSON.stringify(templateTemplate)))
)
embeddedStore.setOpt('create')
if (state.pid) {
embeddedStore.setPid(state.pid)
}
useEmitt().emitter.emit(
'changeCurrentComponent',
['dataV', 'SCREEN'].includes(state.dvCreateForm.nodeType)
? 'VisualizationEditor'
: 'DashboardEditor'
)
return
}
const openType = wsCache.get('open-backend') === '1' ? '_self' : '_blank'
if (state.pid) {
newWindow = window.open(baseUrl + `&pid=${state.pid}`, openType)
} else {
newWindow = window.open(baseUrl, openType)
}
initOpenHandler(newWindow)
}
const openHandler = ref(null)
const initOpenHandler = newWindow => {
if (openHandler?.value) {
const pm = {
methodName: 'initOpenHandler',
args: newWindow
}
openHandler.value.invokeMethod(pm)
}
}
const dialogVisible = ref(false)
const classform = ref({ name: '' })
const dialogVisibles = ref(false)
const optType = ref('insert')
onMounted(() => {
init()
})
function addClass() {
classform.value = { name: '' }
dialogVisible.value = true
}
function importTemplate() {
dialogVisibles.value = true
}
function preview(item, index) {
router.push({
path: '/TemplatePreview',
query: { title: classList.value[activeIndex.value].category.label, index: index }
})
}
function design(item, index) {
templateApply(dataList.value[index])
}
function init() {
searchMarketPreview().then(res => {
classList.value = res.data.contents
if (classList.value[0]) {
activeIndex.value = 0
dataList.value = classList.value[activeIndex.value].contents
}
})
}
function classclick(index) { //
activeIndex.value = index
dataList.value = classList.value[activeIndex.value].contents
}
function handleDatasetName() { //
console.log(dataList.value)
if (keywords.value == '') {
dataList.value = classList.value[activeIndex.value].contents
} else {
var arr = dataList.value
var resarr = []
arr.forEach((e) => {
if (e.title.indexOf(keywords.value) != -1) {
resarr.push(e)
}
})
dataList.value = resarr
}
}
function mouseover(index) { //
mask.value = index
}
function mouseleave() { //
mask.value = -1
}
function closeClassDialog() {
dialogVisible.value = false
}
function closeTemplateDialog() {
dialogVisibles.value = false
}
function classrefresh() {
init()
}
function editTemplate(item) {
optType.value = 'template'
console.log(item)
}
</script>
<template>
<div class="common-layout">
<div style="display: flex;align-items: center;">
<el-input placeholder="请输入模板名称" class="keywordsClass" maxlength="64" v-model="keywords" @blur="handleDatasetName">
<template #prepend>
<img src="@/assets/newimg/u62.png" alt="">
</template>
</el-input>
<div class="import-btn" @click="importTemplate">导入模板</div>
<div class="import-btn" @click="addClass">添加分类</div>
</div>
<div>
<div class="class_list_box">
<div v-for="(item, index) in classList" :key="index"
:class="activeIndex === index ? 'class_list_active' : 'class_list'" @click="classclick(index)">
<div class="class_list_text">{{ item.category.label }} ({{ item.contents.length }}) </div>
</div>
</div>
<div class="application_list_box">
<div v-for="(item, index) in dataList" :key="index" class="application_list" @mouseover="mouseover(index)"
@mouseleave="mouseleave">
<img v-if="item.thumbnail != null && item.thumbnail != ''" :src="basePath + item.thumbnail" alt=""
style="width: 267px;height: 155px;">
<img v-else src="@/assets/newimg/u110.png" alt="" style="width: 267px;height: 155px;">
<div style="display: flex;justify-content: space-between;">
<div class="application_list_text">{{ item.title }}</div>
</div>
<div class="mask_box" v-if="mask == index">
<div>
<img src="@/assets/newimg/icon/editpro.png" @click="editTemplate(item)" style="cursor: pointer;" title="编辑模板">
<img src="@/assets/newimg/icon/del.png" alt="" style="margin-left: 10px;cursor: pointer;" title="删除">
</div>
<div style="display: flex;justify-content: center;margin-top: 20px;">
<div class="yulan" @click="preview(item, index)">预览</div>
<div class="mokuaipeizhi" @click="design(item, index)">设计</div>
</div>
</div>
</div>
</div>
</div>
<el-dialog v-model="dialogVisible" title="添加分类" width="30%" :before-close="closeClassDialog">
<AddTemplateClass v-if="dialogVisible" @closeClassDialog="closeClassDialog" :classrefresh="classrefresh" />
</el-dialog>
<el-dialog v-model="dialogVisibles" title="导入模板" width="30%" :before-close="closeTemplateDialog">
<AddTemplate v-if="dialogVisibles" :optType="optType" :classList="classList" @init="init"
@closeTemplateDialog="closeTemplateDialog" />
</el-dialog>
</div>
</template>
<style lang="less" scoped>
.common-layout {
width: 100vw;
height: 100vh;
overflow: hidden;
display: flex;
flex-direction: column;
color: #1f2329;
min-width: 1000px;
overflow-x: auto;
box-sizing: border-box;
padding: 20px;
padding-left: 40px;
padding-right: 0px;
background-color: rgb(21, 21, 21);
}
.keywordsClass {
width: 403px;
height: 40px;
background: inherit;
background-color: rgba(37, 38, 38, 1);
box-sizing: border-box;
border-width: 1px;
border-style: solid;
border-color: rgba(51, 51, 51, 1);
border-radius: 4px;
:deep(.ed-input__wrapper) {
background-color: rgba(37, 38, 38, 1);
box-sizing: border-box;
border-width: 1px;
border-style: solid;
border-color: rgba(51, 51, 51, 0);
border-radius: 4px;
box-shadow: 0 0 0 1px transparent;
}
:deep(.ed-input__inner) {
background-color: rgba(37, 38, 38, 1);
box-sizing: border-box;
border-width: 1px;
border-style: solid;
border-color: rgba(51, 51, 51, 0);
border-radius: 4px;
color: #fff;
}
:deep(.ed-input-group__prepend) {
background-color: rgba(37, 38, 38, 1);
border: 0;
box-shadow: 0 0 0 1px transparent;
padding: 0 10px;
padding-right: 0;
}
}
.application_list_box {
display: flex;
flex-wrap: wrap;
height: calc(100vh - 200px);
overflow: auto;
align-content: flex-start;
}
.application_list {
position: relative;
margin-top: 20px;
width: 296px;
height: 210px;
background: inherit;
background-color: rgba(37, 38, 38, 1);
box-sizing: border-box;
padding: 10px;
border-width: 1px;
border-style: solid;
border-color: rgba(51, 51, 51, 1);
border-radius: 10px;
margin-right: 20px;
text-align: center;
}
.application_list_text {
font-family: 'Arial Normal', 'Arial';
font-weight: 400;
font-style: normal;
font-size: 12px;
color: #F2F4F5;
padding-top: 13px;
position: relative;
z-index: 11;
}
.mask_box {
position: absolute;
top: 0;
left: 0;
z-index: 10;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.8);
border-radius: 10px;
box-sizing: border-box;
padding-top: 60px;
border: 1px solid #0089ff;
}
.mask_box_img {
display: flex;
justify-content: center;
margin-bottom: 20px;
img {
margin: 0 8px;
cursor: pointer;
}
}
.yulan {
width: 50px;
height: 28px;
line-height: 28px;
text-align: center;
background-color: rgba(255, 255, 255, 0.3);
border: none;
border-radius: 4px;
box-shadow: none;
font-size: 14px;
font-family: 'Arial Normal', 'Arial';
font-weight: 400;
font-style: normal;
color: rgb(255, 255, 255);
margin-right: 10px;
cursor: pointer;
}
.mokuaipeizhi {
width: 50px;
height: 28px;
line-height: 28px;
text-align: center;
background-color: rgba(0, 137, 255, 1);
border: none;
border-radius: 4px;
box-shadow: none;
font-size: 14px;
font-family: 'Arial Normal', 'Arial';
font-weight: 400;
font-style: normal;
color: rgb(255, 255, 255);
cursor: pointer;
}
.import-btn {
width: 80px;
height: 35px;
line-height: 35px;
text-align: center;
background-color: rgba(0, 137, 255, 1);
border: none;
border-radius: 4px;
box-shadow: none;
font-size: 14px;
font-family: 'Arial Normal', 'Arial';
font-weight: 400;
font-style: normal;
color: rgb(255, 255, 255);
cursor: pointer;
margin-left: 10px;
}
.class_list_box {
display: flex;
align-items: center;
margin-top: 20px;
margin-bottom: 10px;
width: calc(100% - 270px);
flex-wrap: wrap;
gap: 15px;
}
.class_list {
padding: 0px 20px;
height: 40px;
line-height: 40px;
text-align: center;
background-color: rgba(36, 37, 38, 1);
border-radius: 4px;
font-size: 14px;
color: #C9C9C9;
cursor: pointer;
}
.class_list_active {
padding: 0px 20px;
height: 40px;
line-height: 40px;
text-align: center;
background-color: rgba(54, 55, 56, 1);
border-radius: 4px;
font-size: 14px;
color: #F2F4F5;
cursor: pointer;
}
.class-add {
width: 100%;
background-color: transparent;
padding: 10px;
font-size: 14px;
cursor: pointer;
}
.class-add:hover {
background-color: #434343;
;
}
</style>
<style>
.ed-message-box__headerbtn {
top: -15px;
right: -10px;
}
.ed-dialog {
background-color: #212121;
}
.ed-form-item__label {
color: #D2D2D2;
}
.ed-input__wrapper {
background-color: #252626;
box-sizing: border-box;
border-width: 1px;
border-style: solid;
border-color: rgba(67, 67, 67, 0);
border-radius: 4px;
box-shadow: none;
border: 1px solid #434343;
}
.ed-form-item.is-error .ed-input__wrapper {
box-shadow: none;
border: 1px solid #f54a45;
}
.ed-input__wrapper.is-focus {
box-shadow: none;
border: 1px solid #0089ff;
}
.ed-input__wrapper:hover {
box-shadow: none;
border: 1px solid #0089ff;
}
.ed-input__inner {
color: #fff;
}
.ed-button {
color: #ffffff;
background-color: rgb(54, 55, 56);
border: 1px solid #363636;
}
.ed-button:focus,
.ed-button:hover {
color: #ffffff;
background-color: rgb(54, 55, 56);
border: 1px solid #363636;
}
.ed-button--primary {
background-color: #0089ff;
border-color: #0089ff;
}
.ed-button--primary:focus,
.ed-button--primary:hover {
background-color: #0089ff;
border-color: #0089ff;
}
.ed-dialog__title {
color: #fff;
}
.ed-select__wrapper {
border: 1px solid #434343;
box-shadow: none !important;
height: 32px;
word-wrap: break-word;
text-align: left;
color: rgba(0, 0, 0, 0.65);
list-style: none;
user-select: none;
cursor: pointer;
line-height: 32px;
box-sizing: border-box;
max-width: 100%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
opacity: 1;
background-color: #252626;
}
.ed-select__popper.ed-popper {
background: rgb(41, 41, 41) !important;
color: #fff;
border: 1px solid #434343;
}
.ed-select-dropdown__item.is-hovering {
background: #434343 !important;
}
.ed-select-dropdown__item {
color: #fff;
}
.ed-select-dropdown__footer {
padding: 5px 0px;
border-top: 1px solid #434343;
}
.ed-tag {
background: #434343;
color: #fff;
}
</style>

View File

@ -0,0 +1,270 @@
<script lang="ts" setup>
import { ref, onMounted } from 'vue'
import { useRouter,useRoute } from 'vue-router'
import { searchMarketPreview } from '@/api/templateMarket'
import { template } from 'lodash';
const router = useRouter()
const route = useRoute();
const keywords: any = ref("") //
const classList: any = ref([])
const loading: any = ref(false)
const activeNames: any = ref('')
const activeIndex: any = ref(null)
const activeIndex1: any = ref(null)
const basePath = import.meta.env.VITE_API_BASEPATH
const currentthumbnail = ref(null)
onMounted(() => {
init()
})
function init() {
searchMarketPreview().then(res => {
classList.value = res.data.contents
if (route.query.title) {
for(var i = 0;i<res.data.contents.length;i++){
if (route.query.title == res.data.contents[i].category.label) {
activeNames.value = route.query.title
templateclick(i, Number(route.query.index))
break
}
}
}
})
}
function handleChange() {
}
function templateclick(index, index1) {
activeIndex.value = index
activeIndex1.value = index1
currentthumbnail.value = classList.value[activeIndex.value].contents[index1].thumbnail
}
</script>
<template>
<div>
<div class="template-header">
<div class="template-header-left">
<div class="return-box" @click="$router.go(-1)">
<img src="@/assets/newimg/u594.png" alt="">
</div>
<div class="header-title">模板资源</div>
</div>
<div class="template-header-right">
<div class="sj-btn">设计</div>
</div>
</div>
<div class="template-content">
<div class="template-content-left">
<div class="template-content-left-title">模板列表</div>
<el-input placeholder="请输入" class="keywordsClass" v-model="keywords">
<template #prepend>
<img src="@/assets/newimg/u62.png" alt="">
</template>
</el-input>
<div style="margin-top: 10px;width:100%;height: calc(100vh - 180px);overflow: auto;">
<el-collapse v-model="activeNames" @change="handleChange" accordion>
<el-collapse-item v-for="(item, index) in classList" :key="index" :title="item.category.label"
:name="item.category.label">
<div v-for="(item1, index1) in item.contents" :key="index1" @click="templateclick(index,index1)"
:class="activeIndex === index && activeIndex1 === index1? 'application_list_active' : 'application_list'">
<img v-if="item1.thumbnail != null && item1.thumbnail != ''" :src="basePath+item1.thumbnail" alt=""
style="width: 208px;height: 120px;">
<img v-else src="@/assets/newimg/u110.png" alt="" style="width: 224px;height: 126px;">
<div style="display: flex;justify-content: space-between;">
<div class="application_list_text">{{ item1.title }}</div>
</div>
</div>
</el-collapse-item>
</el-collapse>
</div>
</div>
<div class="template-content-right">
<img v-if="currentthumbnail !== null && currentthumbnail !== ''"
:src="basePath + currentthumbnail" style="width: 100%;height:100%;object-fit: contain;" alt="">
</div>
</div>
</div>
</template>
<style lang="less" scoped>
.template-header {
width: 100%;
height: 60px;
background-color: rgba(37, 38, 38, 1);
box-sizing: border-box;
border-bottom: 1px solid rgba(79, 80, 82, 1);
display: flex;
align-items: center;
justify-content: space-between;
box-sizing: border-box;
padding: 0 10px;
.template-header-left {
display: flex;
align-items: center;
.return-box {
display: flex;
justify-content: center;
align-items: center;
width: 36px;
height: 36px;
cursor: pointer;
}
.return-box:hover {
background-color: rgba(255, 255, 255, 0.1);
}
.header-title {
font-family: 'Arial Negreta', 'Arial Normal', 'Arial';
font-weight: 700;
font-style: normal;
font-size: 16px;
color: #F2F4F5;
padding-left: 14px;
}
}
}
.template-content {
background-color: #151515;
height: calc(100vh - 60px);
display: flex;
.template-content-left {
width: 260px;
height: calc(100vh - 60px);
background: inherit;
background-color: rgba(37, 38, 38, 1);
box-sizing: border-box;
border-right: 1px solid rgba(79, 80, 82, 1);
padding: 0px 10px;
padding: 20px 10px 0px;
.template-content-left-title {
font-family: 'Arial Negreta', 'Arial Normal', 'Arial', sans-serif;
font-weight: 700;
font-style: normal;
font-size: 16px;
color: #F2F4F5;
margin-bottom: 15px;
}
.application_list {
width: 239px;
height: 170px;
background: inherit;
background-color: rgba(37, 38, 38, 1);
box-sizing: border-box;
padding: 5px;
border-width: 1px;
border-style: solid;
border-color: rgba(51, 51, 51, 1);
border-radius: 10px;
text-align: center;
margin-bottom: 10px;
cursor: pointer;
}
.application_list_active {
width: 239px;
height: 170px;
background: inherit;
background-color: rgba(37, 38, 38, 1);
box-sizing: border-box;
padding: 5px;
border-width: 1px;
border-style: solid;
border-color: #0089ff;
border-radius: 10px;
text-align: center;
margin-bottom: 10px;
cursor: pointer;
}
.application_list:hover{
border: 1px solid #0089ff;
}
:deep(.ed-collapse-item--light .ed-collapse-item__header) {
background-color: transparent;
border-color: none;
color: #F2F4F5;
}
:deep(.ed-collapse-item__header) {
height: 40px;
padding: 0px;
}
:deep(.ed-collapse) {
border: none;
}
:deep(.ed-collapse-item__content) {
background-color: rgba(37, 38, 38, 1);
color: #fff;
padding: 0px;
}
:deep(.ed-collapse-item--light .ed-collapse-item__wrap) {
border: none;
background-color: rgba(37, 38, 38, 1);
}
::-webkit-scrollbar {
width: 0px !important;
height: 0px !important;
}
}
.template-content-right{
width: calc(100% - 260px);
padding: 20px;
}
}
.sj-btn {
width: 60px;
height: 30px;
line-height: 30px;
text-align: center;
background-color: rgba(0, 137, 255, 1);
border-radius: 4px;
font-size: 14px;
color: #F2F4F5;
}
.keywordsClass {
width: 100%;
height: 40px;
background: inherit;
background-color: rgba(37, 38, 38, 1);
box-sizing: border-box;
border-width: 1px;
border-style: solid;
border-color: #434343;
border-radius: 4px;
:deep(.ed-input__wrapper) {
background-color: rgba(37, 38, 38, 1);
box-sizing: border-box;
border-width: 1px;
border-style: solid;
border-color: rgba(51, 51, 51, 0);
border-radius: 4px;
box-shadow: 0 0 0 1px transparent;
}
:deep(.ed-input__inner) {
background-color: rgba(37, 38, 38, 1);
box-sizing: border-box;
border-width: 1px;
border-style: solid;
border-color: rgba(51, 51, 51, 0);
border-radius: 4px;
color: #fff;
}
:deep(.ed-input-group__prepend) {
background-color: rgba(37, 38, 38, 1);
border: 0;
box-shadow: 0 0 0 1px transparent;
padding: 0 10px;
padding-right: 0;
}
}
</style>

View File

@ -177,12 +177,14 @@ function userdetails(){
</div>
</div>
<div class="Navbar-box-right">
<div style="margin-right: 10px;cursor: pointer;"><img src="@/assets/img/nav1.png" alt=""></div>
<div style="margin-right: 10px;min-width: 45px;cursor: pointer;" @click="userdetails">{{ props.isExecuteEvent == false?userList.nickname:'admin' }}</div>
<div style="margin-right: 10px;cursor: pointer;" @click="userdetails"><img src="@/assets/img/nav3.png" alt=""></div>
<div style="margin-right: 10px;cursor: pointer;" @click="permissionClick"><img
src="@/assets/img/navpermission.png" alt=""></div>
<div style="margin-right: 10px;cursor: pointer;"><img src="@/assets/img/nav1.png" alt=""></div>
<div style="margin-right: 15px;min-width: 45px;cursor: pointer;" @click="userdetails">{{ props.isExecuteEvent == false?userList.nickname:'admin' }}</div>
<div style="margin-right: 15px;cursor: pointer;" @click="userdetails"><img src="@/assets/img/nav3.png" alt=""></div>
<div @click="logout" style="cursor: pointer;"><img src="@/assets/img/nav4.png" alt=""></div>
</div>
</div>
</div>
@ -204,7 +206,8 @@ function userdetails(){
.Navbar-box {
width: 100%;
height: 65px;
height: 85px;
padding-top:20px;
display: flex;
align-items: center;
color: #fff;
@ -246,6 +249,7 @@ function userdetails(){
.Navbar-menu-time {
width: 150px;
margin-top: -10px;
.Navbar-menu-time-text {
font-size: 16px;
@ -254,23 +258,25 @@ function userdetails(){
.Navbar-menu-time-text2 {
font-size: 13px;
font-weight: 700;
margin-top:5px;
}
}
.Navbar-menu-item {
font-size: 14px;
padding: 5px 15px;
padding: 8px 20px;
background: url(/images/navmenu.png) no-repeat;
background-size: 100% 100%;
margin-left: 15px;
cursor: pointer;
position: relative;
margin-top: -18px;
}
.Navbar-menu-items {
background: url(/images/navmenucheck.png) no-repeat;
background-size: 100% 100%;
}
}
@ -280,6 +286,7 @@ function userdetails(){
display: flex;
align-items: center;
font-size: 14px;
margin-top: -15px;
}
}
@ -292,20 +299,25 @@ function userdetails(){
</style>
<style>
.tsmenu-popover.el-popover.el-popper {
background: linear-gradient(to bottom, rgba(0, 52, 102, 1), rgba(0, 55, 110, 0.5));
;
background: linear-gradient(to bottom, rgba(0, 71, 142, 1), rgba(0, 71, 142, 0));
border: 1px solid;
border-image: linear-gradient(to bottom, rgba(0,255,255,0.5), rgba(0,255,255,0)) 1;
border-bottom:none;
color: #fff;
border: none;
border-radius: 0px;
padding: 5px 0px;
z-index: 9001 !important;
}
.tsmenu-popover.ed-popover.ed-popper {
background: linear-gradient(to bottom, rgba(0, 52, 102, 1), rgba(0, 55, 110, 0.5));
;
background: linear-gradient(to bottom, rgba(0, 71, 142, 1), rgba(0, 71, 142, 0));
border: 1px solid;
border-image: linear-gradient(to bottom, rgba(0,255,255,0.5), rgba(0,255,255,0)) 1;
border-bottom:none;
color: #fff;
border: none;
border-radius: 0px;
padding: 5px 0px;
z-index: 9001 !important;
@ -319,7 +331,7 @@ function userdetails(){
.tsmenu-popover .Navbar-menu-item-child-item:hover {
color: rgb(0, 255, 254);
background: rgb(2, 88, 161);
background: rgba(0,153,255,0.2);
font-weight: 700;
}
</style>

View File

@ -11,7 +11,10 @@ import icon_permission_more_white from '@/assets/svg/icon_more-vertical_outlined
import { ElTree,FormInstance } from 'element-plus'
import { ElMessage, ElMessageBox } from 'element-plus'
import { getMenuTree,addMenu,updateMenuById,deleteMenuById } from '@/api/permission/menu'
import type {
NodeDropType,
} from 'element-plus/es/components/tree/src/tree.type'
import type { DragEvents } from 'element-plus/es/components/tree/src/model/useDragNode'
const projectInfo:any =ref({})
const route = useRoute()
const router = useRouter()
@ -91,6 +94,22 @@ const resetForm = (formEl: FormInstance | undefined) => {
formEl.resetFields()
dialogVisible.value = false
}
const handleDrop = (
draggingNode: Node,
dropNode: Node,
dropType: NodeDropType,
ev: DragEvents
) => {
console.log('tree drop:', draggingNode,dropNode, dropType,ev)
}
const allowDrop = (draggingNode: Node, dropNode: Node, type: AllowDropType) => {
if (draggingNode.level === dropNode.level) {
return type === 'prev' || type === 'next'
} else {
//
return false
}
}
onMounted(() => {
if (route.query.id) {
applicationId.value = route.query.id
@ -229,8 +248,8 @@ function assocsubmit(){
</div>
<el-input v-model="filterText" placeholder="请输入" @blur="querytree" />
<el-tree v-loading="treeloading" ref="treeRef" :data="treeData" node-key="id" :props="defaultProps"
default-expand-all :expand-on-click-node="false" highlight-current
@node-click="nodeclick" style="height: calc(100vh - 210px);margin-top: 10px;overflow: auto;">
default-expand-all :expand-on-click-node="false" highlight-current draggable @node-drop="handleDrop"
:allow-drop="allowDrop" @node-click="nodeclick" style="height: calc(100vh - 210px);margin-top: 10px;overflow: auto;">
<template #default="{ node, data }">
<div class="custom-tree-node" @mouseenter="handleMouseEnter(node)"
@mouseleave="handleMouseLeave()">

View File

@ -3,10 +3,17 @@ import { usePermissionStore } from '@/store/modules/permission'
import { formatRoute } from '@/router/establish'
import { ref, onMounted } from 'vue'
import router from '@/router';
import { useRoute } from 'vue-router';
const permissionStore = usePermissionStore()
const routers: any[] = formatRoute(permissionStore.getRoutersNotHidden as AppCustomRouteRecordRaw[])
const activeIndex:any = ref(0)
const route = useRoute();
onMounted(async () => {
if(route.path == '/application/index'){
activeIndex.value = 0
}else if(route.path == '/TemplateResource/index'){
activeIndex.value = 1
}
})
function clickRoute(params:any) {
@ -19,6 +26,8 @@ function clickRoute(params:any) {
}else{
if(params == 0){
router.push('/application/index')
}else if(params == 1){
router.push('/TemplateResource/index')
}
}
}
@ -43,7 +52,7 @@ function clickRoute(params:any) {
<img src="@/assets/newimg/u17.png" alt="" >
<div class="logo-left-title">模板</div>
</div>
<div class="navmuen" :class="activeIndex === 1 && 'active'" @click="activeIndex = 1">
<div class="navmuen" :class="activeIndex === 1 && 'active'" @click="clickRoute(1)">
<img src="@/assets/newimg/u56.png" alt="" style="margin-left: 15px;margin-right: 10px;">
<div>模板资源</div>
</div>