JeecgBoot仪表盘版本发布,重磅新功能!支持在线拖拽设计大屏和门户
parent
9d61822479
commit
7f03885154
|
@ -34,6 +34,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@jeecg/online": "3.4.4-RC",
|
||||
"@qiaoqiaoyun/drag-free": "^1.0.2",
|
||||
"@iconify/iconify": "^2.2.1",
|
||||
"@ant-design/colors": "^6.0.0",
|
||||
"@ant-design/icons-vue": "^6.1.0",
|
||||
|
|
1403
pnpm-lock.yaml
1403
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
|
@ -2,6 +2,8 @@ import type { App } from 'vue';
|
|||
import { Icon } from './Icon';
|
||||
import AIcon from '/@/components/jeecg/AIcon.vue';
|
||||
import { Button, JUploadButton } from './Button';
|
||||
//敲敲云—仪表盘设计器(拖拽设计)
|
||||
import DragEngine from '@qiaoqiaoyun/drag-free';
|
||||
import {
|
||||
// Need
|
||||
Button as AntButton,
|
||||
|
@ -107,6 +109,7 @@ export function registerGlobComp(app: App) {
|
|||
.use(InputNumber)
|
||||
.use(Carousel)
|
||||
.use(Popconfirm)
|
||||
.use(DragEngine)
|
||||
.use(Skeleton)
|
||||
.use(Cascader)
|
||||
.use(Rate);
|
||||
|
|
|
@ -0,0 +1,473 @@
|
|||
<template>
|
||||
<div class="p-2">
|
||||
<div class="bg-white mb-2 p-4">
|
||||
<BasicForm @register="registerForm" />
|
||||
</div>
|
||||
<a-spin :spinning="spinning">
|
||||
<div class="bg-white p-2">
|
||||
<slot name="cardTitle"></slot>
|
||||
<List :grid="{ gutter: 5, xs: 1, sm: 2, md: 3, lg: 3, xl: 4, xxl: grid }" size="small" :data-source="data" :pagination="paginationProp">
|
||||
<template #header>
|
||||
<div class="flex justify-start space-x-2">
|
||||
<slot name="header"></slot>
|
||||
<Tooltip>
|
||||
<template #title>
|
||||
<div class="w-50">每行显示数量</div>
|
||||
<Slider id="slider" v-bind="sliderProp" v-model:value="grid" @change="sliderChange" />
|
||||
</template>
|
||||
<a-button type="primary" style="min-width: 80px">
|
||||
<TableOutlined />
|
||||
</a-button>
|
||||
</Tooltip>
|
||||
<Tooltip>
|
||||
<template #title>刷新</template>
|
||||
<a-button @click="fetch">
|
||||
<RedoOutlined />
|
||||
</a-button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</template>
|
||||
<template #renderItem="{ item, index }">
|
||||
<ListItem style="margin-top: 10px">
|
||||
<Card
|
||||
class="cardItem"
|
||||
size="small"
|
||||
:headStyle="{ textAlign: 'left', fontWeight: '500', background: '#efefef', minHeight: '20px' }"
|
||||
:bodyStyle="{ display: 'none' }"
|
||||
>
|
||||
<template #title>
|
||||
<em class="aui-tag"><div class="aui-tag-re"></div><div class="aui-tag-ye"></div><div class="aui-tag-bl"></div></em>
|
||||
<span class="lock-to-right" v-if="item.protectionCode">
|
||||
<Icon icon="ant-design:lock-filled" :size="15" style="margin: 5px;"/>
|
||||
</span>
|
||||
</template>
|
||||
<!--<template #extra>-->
|
||||
<!--<Dropdown :trigger="['hover']" :dropMenuList="getDropDownAction(item)" popconfirm>-->
|
||||
<!--<SettingOutlined />-->
|
||||
<!--</Dropdown>-->
|
||||
<!--</template>-->
|
||||
<template #cover>
|
||||
<div class="title-div ellipsis">{{ item.name }}</div>
|
||||
<div class="image-div" @click="handleDesign(item)">
|
||||
<img :src="getCover(item.coverUrl)" />
|
||||
<div class="image-mask">
|
||||
<Icon icon="ant-design:eye-outlined" v-if="params.izTemplate === '1' && !hasAuth()" :size="60" />
|
||||
<Icon icon="ri:drag-drop-fill" v-else :size="60" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template class="ant-card-actions" #actions>
|
||||
<Tooltip>
|
||||
<template #title>预览</template>
|
||||
<EyeOutlined key="view" style="font-size: 20px" @click="handleView(item.id)" />
|
||||
</Tooltip>
|
||||
<Dropdown :trigger="['hover']" :dropMenuList="getDropDownAction(item)" popconfirm>
|
||||
<SettingOutlined key="set" style="font-size: 20px" />
|
||||
</Dropdown>
|
||||
</template>
|
||||
</Card>
|
||||
</ListItem>
|
||||
</template>
|
||||
</List>
|
||||
</div>
|
||||
</a-spin>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { computed, onMounted, ref, unref } from 'vue';
|
||||
import { EyeOutlined, DeleteOutlined, EditOutlined, RedoOutlined, TableOutlined, EllipsisOutlined, SettingOutlined } from '@ant-design/icons-vue';
|
||||
import { Dropdown } from '/@/components/Dropdown';
|
||||
import { List, Card, Image, Tooltip, Slider, Popconfirm } from 'ant-design-vue';
|
||||
import { BasicForm, useForm } from '/@/components/Form';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
import { isFunction } from '/@/utils/is';
|
||||
import { useSlider } from '/@/components/CardList/src/data';
|
||||
import { useCopyToClipboard } from '/@/hooks/web/useCopyToClipboard';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import { getFileAccessHttpUrl } from '/@/utils/common/compUtils';
|
||||
import { usePermission } from '/@/hooks/web/usePermission';
|
||||
|
||||
const { hasPermission } = usePermission();
|
||||
const ListItem = List.Item;
|
||||
const defCover = 'https://jeecgdev.oss-cn-beijing.aliyuncs.com/temp/designCover_1655434422024.png';
|
||||
const { createMessage } = useMessage();
|
||||
const { clipboardRef, copiedRef } = useCopyToClipboard();
|
||||
const spinning = ref<boolean>(false);
|
||||
const grid = ref(5);
|
||||
// 获取slider属性
|
||||
const sliderProp = computed(() => useSlider(4, 7));
|
||||
// 组件接收参数
|
||||
const props = defineProps({
|
||||
// 请求API的参数
|
||||
params: propTypes.object.def({}),
|
||||
//api
|
||||
api: propTypes.func,
|
||||
searchFormSchema: propTypes.object.def([]),
|
||||
});
|
||||
//暴露内部方法
|
||||
const emit = defineEmits(['getMethod', 'delete', 'edit', 'view', 'design', 'add', 'copy']);
|
||||
//数据
|
||||
const data = ref([]);
|
||||
// 切换每行个数
|
||||
// cover图片自适应高度
|
||||
//修改pageSize并重新请求数据
|
||||
const height = computed(() => {
|
||||
return `${200 - grid.value * 8}px`;
|
||||
});
|
||||
const width = computed(() => {
|
||||
let rowNum = grid.value;
|
||||
let width = rowNum==4?"360px":rowNum==6?"230px":rowNum==7?"190px":"280px";
|
||||
return width;
|
||||
});
|
||||
//表单
|
||||
const [registerForm, { validate }] = useForm({
|
||||
schemas: props.searchFormSchema,
|
||||
labelWidth: 80,
|
||||
// 操作按钮配置
|
||||
baseColProps: { span: 6 },
|
||||
actionColOptions: {
|
||||
xs: 24,
|
||||
sm: 12,
|
||||
md: 12,
|
||||
lg: 8,
|
||||
xl: 8,
|
||||
xxl: 6,
|
||||
style: { textAlign: 'left' },
|
||||
},
|
||||
autoSubmitOnEnter: true,
|
||||
submitFunc: handleSubmit,
|
||||
resetFunc: handleReset,
|
||||
});
|
||||
|
||||
//表单提交
|
||||
async function handleSubmit() {
|
||||
const data = await validate();
|
||||
//查询时设置首页
|
||||
pageNo.value = 1;
|
||||
await fetch(data);
|
||||
}
|
||||
|
||||
//表单重置
|
||||
async function handleReset() {
|
||||
await fetch();
|
||||
}
|
||||
|
||||
async function sliderChange(n) {
|
||||
pageSize.value = n * 3;
|
||||
const data = await validate();
|
||||
fetch(data);
|
||||
}
|
||||
|
||||
// 自动请求并暴露内部方法
|
||||
onMounted(() => {
|
||||
fetch();
|
||||
emit('getMethod', fetch);
|
||||
});
|
||||
|
||||
async function fetch(p = {}) {
|
||||
spinning.value = true;
|
||||
const { api, params } = props;
|
||||
if (api && isFunction(api)) {
|
||||
const res = await api({ ...params, pageNo: pageNo.value, pageSize: pageSize.value, ...p });
|
||||
data.value = res.records;
|
||||
total.value = res.total;
|
||||
}
|
||||
spinning.value = false;
|
||||
}
|
||||
|
||||
//分页相关
|
||||
const pageNo = ref(1);
|
||||
const pageSize = ref(15);
|
||||
const total = ref(0);
|
||||
const paginationProp = ref({
|
||||
showSizeChanger: false,
|
||||
showQuickJumper: true,
|
||||
pageSize,
|
||||
pageNo,
|
||||
total,
|
||||
showTotal: (total) => `总 ${total} 条`,
|
||||
onChange: pageChange,
|
||||
onShowSizeChange: pageSizeChange,
|
||||
});
|
||||
|
||||
async function pageChange(p, pz) {
|
||||
pageNo.value = p;
|
||||
pageSize.value = pz;
|
||||
const data = await validate();
|
||||
fetch(data);
|
||||
}
|
||||
|
||||
async function pageSizeChange(current, size) {
|
||||
pageSize.value = size;
|
||||
const data = await validate();
|
||||
fetch(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取封面图
|
||||
*/
|
||||
function getCover(url) {
|
||||
return url ? getFileAccessHttpUrl(url) : defCover;
|
||||
}
|
||||
|
||||
/**
|
||||
* 下拉操作栏
|
||||
*/
|
||||
function getDropDownAction(record) {
|
||||
//1.如果是模板案例
|
||||
if(props.params.izTemplate === '1'){
|
||||
let commonAction = [];
|
||||
//1.1有权限的用户操作
|
||||
if(hasAuth()){
|
||||
commonAction = [
|
||||
{
|
||||
text: '编辑',
|
||||
event: '1',
|
||||
onClick: handleEdit.bind(null, record),
|
||||
},
|
||||
{
|
||||
text: '复制面板',
|
||||
event: '2',
|
||||
onClick: handleCopy.bind(null, record.id),
|
||||
},{
|
||||
text: '取消模板',
|
||||
event: '6',
|
||||
onClick: handleTemplate.bind(null, record,'0'),
|
||||
}
|
||||
];
|
||||
}else{
|
||||
///1.2没有权限的用户只能复制和预览
|
||||
commonAction = [
|
||||
{
|
||||
text: '复制面板',
|
||||
event: '2',
|
||||
onClick: handleCopy.bind(null, record.id),
|
||||
}
|
||||
];
|
||||
}
|
||||
return commonAction;
|
||||
}else{
|
||||
//非模板案例的tab下的按钮显示
|
||||
let commonAction = [
|
||||
{
|
||||
text: '编辑',
|
||||
event: '1',
|
||||
onClick: handleEdit.bind(null, record),
|
||||
},
|
||||
{
|
||||
text: '复制面板',
|
||||
event: '2',
|
||||
onClick: handleCopy.bind(null, record.id),
|
||||
},
|
||||
{
|
||||
text: '复制路由',
|
||||
event: '3',
|
||||
onClick: handleCopyUrl.bind(null, record.path),
|
||||
},
|
||||
];
|
||||
//模板按钮的显隐逻辑判断
|
||||
if(hasAuth()){
|
||||
if(record.izTemplate == '1'){
|
||||
commonAction.push({
|
||||
text: '取消模板',
|
||||
event: '6',
|
||||
onClick: handleTemplate.bind(null, record,'0'),
|
||||
})
|
||||
}else{
|
||||
commonAction.push({
|
||||
text: '收藏模板',
|
||||
event: '5',
|
||||
onClick: handleTemplate.bind(null, record,'1'),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
//删除按钮的逻辑判断
|
||||
if(!hasPassword(record)){
|
||||
commonAction.push({
|
||||
text: '删除',
|
||||
event: '4',
|
||||
popConfirm: {
|
||||
title: '是否确认删除',
|
||||
confirm: handleDelete.bind(null, record),
|
||||
}
|
||||
})
|
||||
}else {
|
||||
commonAction.push({
|
||||
text: '删除',
|
||||
event: '4',
|
||||
onClick: handleDelete.bind(null, record),
|
||||
})
|
||||
}
|
||||
return commonAction;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 判断是否有模板操作权限
|
||||
*/
|
||||
function hasAuth(){
|
||||
return hasPermission('drag:template:edit')
|
||||
}
|
||||
/**
|
||||
* 是否包含保护码
|
||||
**/
|
||||
function hasPassword(record){
|
||||
return record.protectionCode && record.protectionCode.length > 0;
|
||||
}
|
||||
/**
|
||||
* 复制面板
|
||||
* @param id
|
||||
*/
|
||||
function handleCopy(id) {
|
||||
emit('copy', id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制路由地址
|
||||
* @param value
|
||||
*/
|
||||
async function handleCopyUrl(value) {
|
||||
if (value) {
|
||||
clipboardRef.value = value;
|
||||
if (unref(copiedRef)) {
|
||||
createMessage.success('复制成功!');
|
||||
}
|
||||
} else {
|
||||
createMessage.warning('复制失败,请检查路径!');
|
||||
}
|
||||
}
|
||||
|
||||
async function handleCreate() {
|
||||
emit('add');
|
||||
}
|
||||
|
||||
async function handleEdit(record) {
|
||||
emit('edit', record);
|
||||
}
|
||||
|
||||
async function handleDelete(record) {
|
||||
emit('delete', record);
|
||||
}
|
||||
|
||||
async function handleView(id) {
|
||||
emit('view', id);
|
||||
}
|
||||
|
||||
async function handleDesign(record) {
|
||||
if(props.params.izTemplate === '1' && !hasAuth()){
|
||||
//模板案例tab下并且没有操作权限时,只能预览
|
||||
emit('view', record.id);
|
||||
}else{
|
||||
emit('design', record);
|
||||
}
|
||||
}
|
||||
|
||||
async function handleTemplate(record,izTemplate) {
|
||||
emit('template', record.id,izTemplate);
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="less">
|
||||
.addItem {
|
||||
height: 250px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.cardItem {
|
||||
width: v-bind('width');
|
||||
text-align: center;
|
||||
border-radius: 3px;
|
||||
box-shadow: 0 4px 5px rgb(0 0 0 / 20%);
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 0 20px 0 #616161;
|
||||
}
|
||||
|
||||
.title-div {
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
background: #fff;
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
border-bottom: 1px solid #efefef;
|
||||
}
|
||||
|
||||
.ellipsis {
|
||||
display:block;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.image-div {
|
||||
img {
|
||||
width: 100%;
|
||||
//object-fit: cover;
|
||||
height: v-bind('height');
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.image-mask {
|
||||
opacity: 1;
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
|
||||
.image-mask {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: v-bind('height');
|
||||
bottom: 50px;
|
||||
background: rgba(101, 101, 101, 0.6);
|
||||
color: #fff;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.aui-tag {
|
||||
display: flex;
|
||||
|
||||
div {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
background: #333;
|
||||
border-radius: 100px;
|
||||
margin: 0 2px;
|
||||
}
|
||||
|
||||
.aui-tag-re {
|
||||
background: #ff5a52;
|
||||
}
|
||||
|
||||
.aui-tag-ye {
|
||||
background: #e6c02a;
|
||||
}
|
||||
|
||||
.aui-tag-bl {
|
||||
background: #53c22c;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*右上角锁标记*/
|
||||
.lock-to-right{
|
||||
z-index: 0;
|
||||
color: #fff;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.lock-to-right::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
border-style: solid;
|
||||
border-width: 0 50px 40px 0;
|
||||
border-color: transparent #db2828 transparent transparent;
|
||||
z-index: -1
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,187 @@
|
|||
<template>
|
||||
<BasicModal
|
||||
v-bind="$attrs"
|
||||
:footer="null"
|
||||
wrapClassName="drag-design-process-modal"
|
||||
:style="{ top: '0', padding: '0' }"
|
||||
@register="registerModal"
|
||||
:bodyStyle="bodyStyle"
|
||||
:canFullscreen="false"
|
||||
:closable="false"
|
||||
defaultFullscreen
|
||||
destroyOnClose
|
||||
>
|
||||
<div id="dragEngineBox" style="height:100vh;overflow-y: auto">
|
||||
<DragEngine
|
||||
v-if="refresh"
|
||||
:dragData="dragData"
|
||||
:pageId="pageId"
|
||||
:token="getToken()"
|
||||
:tenantId="getTenantId()"
|
||||
:lowAppId="lowAppId"
|
||||
:isLowApp="isLowApp"
|
||||
@save="handleSave"
|
||||
@close="handleClose"
|
||||
@scroll="handleScroll"
|
||||
@openWindow="openWindow"
|
||||
>
|
||||
</DragEngine>
|
||||
</div>
|
||||
</BasicModal>
|
||||
<PasswordModal ref="passwordRef" @closed="closeModal"></PasswordModal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, unref, reactive, nextTick,computed } from 'vue';
|
||||
import { getToken,getTenantId } from '/@/utils/auth';
|
||||
import { queryById } from '../page.api';
|
||||
import { BasicModal, useModalInner } from '/src/components/Modal';
|
||||
import { getCacheByDynKey } from '/@/utils/auth';
|
||||
import { JDragConfigEnum } from '/@/enums/jeecgEnum';
|
||||
import PasswordModal from './PasswordModal.vue';
|
||||
// 声明Emits
|
||||
const emit = defineEmits(['success', 'register', 'close']);
|
||||
const bodyStyle = {
|
||||
padding: '0',
|
||||
height: window.innerHeight + 'px',
|
||||
};
|
||||
|
||||
//组件接受传参
|
||||
const props = defineProps({
|
||||
lowAppId: { type: String },
|
||||
// 是否低代码模式(简化使用难度)
|
||||
isLowApp: { type: Boolean, default: true }
|
||||
});
|
||||
|
||||
|
||||
//页面Id
|
||||
const pageId = ref('');
|
||||
const title = ref('');
|
||||
const refresh = ref(true);
|
||||
const passwordRef = ref();
|
||||
//拖拽信息
|
||||
const dragData = ref({
|
||||
componentData: [],
|
||||
name: '',
|
||||
coverUrl: '',
|
||||
backgroundColor: '',
|
||||
backgroundImage: '',
|
||||
designType: 100,
|
||||
theme: 'default',
|
||||
style: 'default',
|
||||
updateCount: null,
|
||||
});
|
||||
//表单赋值
|
||||
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
|
||||
setModalProps({ showCancelBtn: false, showOkBtn: false });
|
||||
refresh.value = false;
|
||||
pageId.value = data.record.id;
|
||||
//校验保护码
|
||||
checkCode(data.record);
|
||||
title.value = `页面设计 [${data.record.name}]`;
|
||||
const res = await queryById({ id: unref(pageId) });
|
||||
if (res.success) {
|
||||
dragData.value.name = res.result.name;
|
||||
dragData.value.coverUrl = res.result.coverUrl;
|
||||
let template = res.result.template ? JSON.parse(res.result.template) : [];
|
||||
dragData.value.componentData = template;
|
||||
dragData.value.backgroundColor = res.result.backgroundColor;
|
||||
dragData.value.backgroundImage = res.result.backgroundImage;
|
||||
dragData.value.designType = res.result.designType;
|
||||
dragData.value.style = res.result.style || 'default';
|
||||
dragData.value.theme = res.result.theme || 'default';
|
||||
//设置乐观锁字段
|
||||
dragData.value.updateCount = res.result.updateCount;
|
||||
}
|
||||
setTimeout(() => {
|
||||
nextTick(() => {
|
||||
refresh.value = true;
|
||||
});
|
||||
}, 300);
|
||||
});
|
||||
/**
|
||||
* 检验保护码
|
||||
*/
|
||||
function checkCode(result) {
|
||||
const password = result.protectionCode;
|
||||
let passIsExit = getCacheByDynKey(JDragConfigEnum.DRAG_CACHE_PREFIX + unref(pageId));
|
||||
let hasPassword = password && password.length > 0;
|
||||
if (hasPassword && !passIsExit) {
|
||||
passwordRef.value.showModal('design', result);
|
||||
passwordRef.value.extraMsg = '';
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 关闭事件
|
||||
*/
|
||||
function handleClose() {
|
||||
closeModal();
|
||||
emit('success');
|
||||
emit('close')
|
||||
}
|
||||
/**
|
||||
* 保存布局后的回调事件
|
||||
* @param data
|
||||
*/
|
||||
function handleSave(data) {
|
||||
//保存后不关闭modal
|
||||
//closeModal()
|
||||
emit('success');
|
||||
}
|
||||
/**
|
||||
* 新增组件后的滚动事件
|
||||
* @param data
|
||||
*/
|
||||
function handleScroll(scrollHeight) {
|
||||
let dom = document.getElementById("dragEngineBox");
|
||||
scrollIntoView(dom,scrollHeight)
|
||||
}
|
||||
|
||||
/**
|
||||
* 模拟滚动效果
|
||||
* @param element 滚动元素
|
||||
* @param scrollHeight 滚动高度
|
||||
*/
|
||||
function scrollIntoView(element,scrollHeight) {
|
||||
// 当前滚动高度
|
||||
let scrollTop = element.scrollTop;
|
||||
// 滚动step方法
|
||||
const step = () =>{
|
||||
// 距离目标滚动距离
|
||||
let distance = scrollHeight - scrollTop;
|
||||
// 目标需要滚动的距离,也就是只走全部距离的十分之一
|
||||
scrollTop = scrollTop + distance / 10;
|
||||
if (Math.abs(distance) < 1) {
|
||||
element.scrollTo(0, scrollHeight);
|
||||
} else {
|
||||
element.scrollTo(0, scrollTop);
|
||||
setTimeout(step, 20);
|
||||
}
|
||||
};
|
||||
step();
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开分享
|
||||
* @param url
|
||||
*/
|
||||
function openWindow(url){
|
||||
window.open(url, '_blank');
|
||||
}
|
||||
</script>
|
||||
<style lang="less">
|
||||
@import '@qiaoqiaoyun/drag-free/lib/index.css';
|
||||
|
||||
.drag-design-process-modal {
|
||||
.ant-modal-header {
|
||||
padding: 0 !important;
|
||||
}
|
||||
.ant-modal-body > .scrollbar {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.jeecg-modal-content > .scroll-container {
|
||||
padding: 0 !important;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,71 @@
|
|||
<template>
|
||||
<BasicModal v-bind="$attrs" @register="registerModal" okText="保存" :title="getTitle" @ok="handleSubmit" :width="700" destroyOnClose>
|
||||
<BasicForm @register="registerForm" />
|
||||
<template #appendFooter>
|
||||
<a-button type="primary" @click="handleSubmit(1)">保存并设计</a-button>
|
||||
</template>
|
||||
</BasicModal>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, unref } from 'vue';
|
||||
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||
import { BasicForm, useForm } from '/@/components/Form/index';
|
||||
import { formSchema } from '../page.data';
|
||||
import { saveOrUpdate } from '../page.api';
|
||||
import { removeCacheByDynKey } from '/@/utils/auth';
|
||||
import { JDragConfigEnum } from '/@/enums/jeecgEnum';
|
||||
import { encryptByBase64,decodeByBase64 } from '/@/utils/cipher.ts';
|
||||
// 声明Emits
|
||||
const emit = defineEmits(['success', 'register']);
|
||||
const isUpdate = ref(true);
|
||||
//表单配置
|
||||
const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({
|
||||
schemas: formSchema,
|
||||
showActionButtonGroup: false,
|
||||
});
|
||||
//表单赋值
|
||||
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
|
||||
//重置表单
|
||||
await resetFields();
|
||||
setModalProps({ confirmLoading: false });
|
||||
isUpdate.value = !!data?.isUpdate;
|
||||
if (unref(isUpdate)) {
|
||||
let obj = {...data.record}
|
||||
//解密
|
||||
if(obj.protectionCode && obj.protectionCode.length>0){
|
||||
obj.protectionCode = decodeByBase64( obj.protectionCode)
|
||||
}
|
||||
//表单赋值
|
||||
await setFieldsValue({
|
||||
...obj,
|
||||
});
|
||||
}
|
||||
});
|
||||
//设置标题
|
||||
const getTitle = computed(() => (!unref(isUpdate) ? '新增' : '编辑'));
|
||||
|
||||
/**
|
||||
* 表单提交事件
|
||||
* @param flag 标识0:保存/1:保存并设计
|
||||
*/
|
||||
async function handleSubmit(flag = 0) {
|
||||
try {
|
||||
const values = await validate();
|
||||
setModalProps({ confirmLoading: true });
|
||||
//加密
|
||||
if(values.protectionCode){
|
||||
values.protectionCode = encryptByBase64(values.protectionCode)
|
||||
}
|
||||
//提交表单
|
||||
const res = await saveOrUpdate(values, isUpdate.value);
|
||||
//编辑后,将缓存中的密码清除掉
|
||||
values.id && removeCacheByDynKey(JDragConfigEnum.DRAG_CACHE_PREFIX + values.id);
|
||||
//关闭弹窗
|
||||
closeModal();
|
||||
//刷新列表
|
||||
emit('success', flag === 1 ? res : null);
|
||||
} finally {
|
||||
setModalProps({ confirmLoading: false });
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,105 @@
|
|||
<!--面板保护密码弹窗-->
|
||||
<template>
|
||||
<a-modal
|
||||
v-model:visible="visible"
|
||||
okText="确认"
|
||||
:bodyStyle="{ padding: '24px 0 0 0' }"
|
||||
:closable="false"
|
||||
:maskClosable="false"
|
||||
v-bind="$attrs"
|
||||
centered
|
||||
destroyOnClose
|
||||
>
|
||||
<a-form ref="formRef" :model="formState" :rules="rules" :label-col="labelCol" :wrapper-col="wrapperCol">
|
||||
<a-form-item :extra="extraMsg" label="保护码" name="password">
|
||||
<a-input v-model:value="formState.password" type="password" />
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
<template #footer>
|
||||
<a-button @click="handleClosed">关闭</a-button>
|
||||
<a-button key="submit" type="primary" @click="handleOk">确认</a-button>
|
||||
</template>
|
||||
</a-modal>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, reactive, ref, toRaw, unref } from 'vue';
|
||||
import { RuleObject, ValidateErrorEntity } from 'ant-design-vue/es/form/interface';
|
||||
import { encryptByBase64 } from '/@/utils/cipher.ts';
|
||||
import { setCacheByDynKey } from '/@/utils/auth';
|
||||
import { JDragConfigEnum } from '/@/enums/jeecgEnum';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'PasswordModal',
|
||||
emits: ['success', 'closed'],
|
||||
setup(props, { emit }) {
|
||||
//表单modal实例
|
||||
const formRef = ref();
|
||||
//表单信息
|
||||
const formModal = ref();
|
||||
//保护码提示语
|
||||
const extraMsg = ref('面板被保护中,编辑前请先输入保护码');
|
||||
//操作类型
|
||||
const operatorType = ref('');
|
||||
//弹窗显隐标记
|
||||
const visible = ref(false);
|
||||
//表单信息
|
||||
const formState = reactive({ password: '' });
|
||||
//显示modal
|
||||
function showModal(type,record) {
|
||||
formModal.value = { ...record };
|
||||
formState.password = '';
|
||||
operatorType.value = type;
|
||||
visible.value = true;
|
||||
}
|
||||
//关闭后的回调
|
||||
function handleClosed() {
|
||||
visible.value = false;
|
||||
emit('closed');
|
||||
}
|
||||
//校验密码
|
||||
let validatePass = async (rule: RuleObject, value: string) => {
|
||||
if (value === '') {
|
||||
return Promise.reject('密码不能为空');
|
||||
} else {
|
||||
let password = formModal.value.protectionCode;
|
||||
if (password !== encryptByBase64(value)) {
|
||||
return Promise.reject('密码不正确');
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
};
|
||||
//校验规则
|
||||
const rules = { password: [{ validator: validatePass, trigger: 'change' }] };
|
||||
//确实
|
||||
const handleOk = () => {
|
||||
formRef.value
|
||||
.validate()
|
||||
.then(async () => {
|
||||
let values = toRaw(unref(formModal));
|
||||
//返回表单信息,编辑时候需要
|
||||
emit('success', unref(operatorType),values);
|
||||
//判断是设计页面的时候弹窗
|
||||
let isEdit = unref(extraMsg) && unref(extraMsg).length > 0;
|
||||
//设计页面密码正确后,保存到缓存中
|
||||
!isEdit && setCacheByDynKey(JDragConfigEnum.DRAG_CACHE_PREFIX+values.id, values.protectionCode);
|
||||
visible.value = false;
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log('error', error);
|
||||
});
|
||||
};
|
||||
return {
|
||||
visible,
|
||||
showModal,
|
||||
handleClosed,
|
||||
extraMsg,
|
||||
handleOk,
|
||||
formRef,
|
||||
formState,
|
||||
rules,
|
||||
labelCol: { span: 4 },
|
||||
wrapperCol: { span: 14 },
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,74 @@
|
|||
import { defHttp } from '/@/utils/http/axios';
|
||||
import { Modal } from 'ant-design-vue';
|
||||
|
||||
enum Api {
|
||||
list = '/drag/page/list',
|
||||
queryById = '/drag/page/queryById',
|
||||
queryPageById = '/drag/page/queryPageById',
|
||||
save = '/drag/page/add',
|
||||
edit = '/drag/page/edit',
|
||||
copyPage = '/drag/page/copyPage',
|
||||
deleteOne = '/drag/page/delete',
|
||||
deleteBatch = '/drag/page/deleteBatch',
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表
|
||||
* @param params
|
||||
*/
|
||||
export const list = (params) => defHttp.get({ url: Api.list, params });
|
||||
/**
|
||||
* 根据id查询
|
||||
* @param params
|
||||
*/
|
||||
export const queryById = (params) => defHttp.get({ url: Api.queryById, params }, { isTransformResponse: false });
|
||||
/**
|
||||
* 根据id查询(不租户隔离)
|
||||
* @param params
|
||||
*/
|
||||
export const queryPageById = (params) => defHttp.get({ url: Api.queryPageById, params }, { isTransformResponse: false });
|
||||
|
||||
/**
|
||||
* 保存或者更新
|
||||
* @param params
|
||||
*/
|
||||
export const saveOrUpdate = (params, isUpdate) => {
|
||||
let url = isUpdate ? Api.edit : Api.save;
|
||||
return defHttp.post({ url: url, params });
|
||||
};
|
||||
/**
|
||||
* 删除
|
||||
*/
|
||||
export const deleteOne = (params, handleSuccess) => {
|
||||
return defHttp.delete({ url: Api.deleteOne, params }, { joinParamsToUrl: true }).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 批量删除
|
||||
* @param params
|
||||
*/
|
||||
export const batchDelete = (params, handleSuccess) => {
|
||||
Modal.confirm({
|
||||
title: '确认删除',
|
||||
content: '是否删除选中数据',
|
||||
okText: '确认',
|
||||
cancelText: '取消',
|
||||
onOk: () => {
|
||||
return defHttp.delete({ url: Api.deleteBatch, data: params }, { joinParamsToUrl: true }).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 复制
|
||||
*/
|
||||
export const copyPage = (params, handleSuccess) => {
|
||||
return defHttp.get({ url: Api.copyPage, params }, { isTransformResponse: false }).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
};
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
import { BasicColumn, FormSchema } from '/@/components/Table';
|
||||
|
||||
export const columns: BasicColumn[] = [
|
||||
{
|
||||
title: '名称',
|
||||
align: 'center',
|
||||
dataIndex: 'name',
|
||||
},
|
||||
];
|
||||
export const searchFormSchema: FormSchema[] = [
|
||||
{
|
||||
label: '名称',
|
||||
field: 'name',
|
||||
component: 'Input',
|
||||
colProps: { span: 6 },
|
||||
},
|
||||
];
|
||||
|
||||
export const formSchema: FormSchema[] = [
|
||||
{
|
||||
label: '',
|
||||
field: 'id',
|
||||
component: 'Input',
|
||||
show: false,
|
||||
},
|
||||
{
|
||||
label: '名称',
|
||||
field: 'name',
|
||||
component: 'Input',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
label: '封面图',
|
||||
field: 'coverUrl',
|
||||
component: 'JImageUpload',
|
||||
componentProps: {
|
||||
fileMax: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '分类',
|
||||
field: 'type',
|
||||
component: 'Select',
|
||||
defaultValue: '1',
|
||||
required: true,
|
||||
componentProps: {
|
||||
options: [
|
||||
{
|
||||
label: '仪表盘设计',
|
||||
value: '1',
|
||||
key: '1',
|
||||
},
|
||||
{
|
||||
label: '门户设计器',
|
||||
value: '2',
|
||||
key: '2',
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '保护码',
|
||||
field: 'protectionCode',
|
||||
component: 'StrengthMeter'
|
||||
}
|
||||
];
|
|
@ -0,0 +1,176 @@
|
|||
<template>
|
||||
<CardList
|
||||
:searchFormSchema="searchFormSchema"
|
||||
:params="params"
|
||||
:api="list"
|
||||
@getMethod="getMethod"
|
||||
@delete="handleDelete"
|
||||
@view="handleView"
|
||||
@design="handleDesign"
|
||||
@edit="handleEdit"
|
||||
@copy="handleCopy"
|
||||
@template="handleTemplate"
|
||||
>
|
||||
<template #header>
|
||||
<a-button preIcon="ant-design:plus-outlined" type="primary" @click="handleCreate">新增</a-button>
|
||||
</template>
|
||||
<template #cardTitle>
|
||||
<a-tabs defaultActiveKey="1" @change="tabChange" size="small">
|
||||
<a-tab-pane key="1">
|
||||
<template #tab>
|
||||
<span>
|
||||
<Icon icon="ant-design:bar-chart-outlined" :size="20"></Icon>
|
||||
仪表盘设计
|
||||
</span>
|
||||
</template>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="3">
|
||||
<template #tab>
|
||||
<span>
|
||||
<Icon icon="ant-design:star-outlined" :size="20"></Icon>
|
||||
模板
|
||||
</span>
|
||||
</template>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</template>
|
||||
</CardList>
|
||||
<!--编辑弹窗-->
|
||||
<PageModal @register="registerModal" @success="handleOk" />
|
||||
<!--保护密码弹窗-->
|
||||
<PasswordModal ref="passwordRef" @success="checkPassOk"/>
|
||||
<!--页面配置弹窗-->
|
||||
<DragPageModal @register="registerDragModal" @success="success" :isLowApp="false"/>
|
||||
</template>
|
||||
<script lang="ts" setup name="drag-page">
|
||||
import CardList from './components/CardList.vue';
|
||||
import PageModal from './components/PageModal.vue';
|
||||
import PasswordModal from './components/PasswordModal.vue';
|
||||
import DragPageModal from './components/DragPageModal.vue';
|
||||
import { ref,reactive } from 'vue';
|
||||
import { useModal } from '/@/components/Modal';
|
||||
import { router } from '/@/router';
|
||||
import { list, deleteOne, copyPage ,saveOrUpdate} from './page.api';
|
||||
import { searchFormSchema } from './page.data';
|
||||
|
||||
const [registerModal, { openModal }] = useModal();
|
||||
const [registerDragModal, { openModal: openDragModal }] = useModal();
|
||||
const passwordRef = ref()
|
||||
let reload = (params?) => {};
|
||||
//额外的查询参数
|
||||
const params = reactive({type:"1",izTemplate:'0'});
|
||||
// 获取内部fetch方法;
|
||||
function getMethod(m: any) {
|
||||
reload = m;
|
||||
}
|
||||
/**
|
||||
* 提交后的回调
|
||||
*/
|
||||
function handleOk(record) {
|
||||
reload();
|
||||
record && handleDesign(record);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增事件
|
||||
*/
|
||||
function handleCreate() {
|
||||
openModal(true, {
|
||||
isUpdate: false,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑
|
||||
*/
|
||||
function handleEdit(record: Recordable) {
|
||||
//判断是否有保护密码
|
||||
let hasPassword = record.protectionCode && record.protectionCode.length > 0;
|
||||
if (hasPassword) {
|
||||
passwordRef.value.showModal('edit', record);
|
||||
//passwordRef.value.extraMsg = '面板被保护中,编辑前请先输入保护码';
|
||||
} else {
|
||||
openModal(true, {
|
||||
record,
|
||||
isUpdate: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 密码校验成功
|
||||
*/
|
||||
async function checkPassOk(type, record) {
|
||||
if (type == 'edit') {
|
||||
openModal(true, {
|
||||
record,
|
||||
isUpdate: true,
|
||||
});
|
||||
} else if (type == 'delete') {
|
||||
await deleteOne({ id: record.id }, reload);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除事件
|
||||
*/
|
||||
async function handleDelete(record) {
|
||||
//判断是否有保护密码
|
||||
let hasPassword = record.protectionCode && record.protectionCode.length > 0;
|
||||
if (hasPassword) {
|
||||
passwordRef.value.showModal('delete', record);
|
||||
passwordRef.value.extraMsg = '面板被保护中,删除前请先输入保护码';
|
||||
} else {
|
||||
await deleteOne({ id: record.id }, reload);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 页面配置
|
||||
*/
|
||||
function handleDesign(record) {
|
||||
openDragModal(true, {
|
||||
record,
|
||||
isUpdate: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 页面预览
|
||||
*/
|
||||
function handleView(id) {
|
||||
router.push({ name: 'drag-page-view-@id'!, params: { id } });
|
||||
}
|
||||
/**
|
||||
* 面板复制
|
||||
*/
|
||||
async function handleCopy(id) {
|
||||
await copyPage({ id }, reload);
|
||||
}
|
||||
/**
|
||||
* 收藏模板
|
||||
*/
|
||||
async function handleTemplate(id,template) {
|
||||
let params = {id, izTemplate:template};
|
||||
const res = await saveOrUpdate(params,true);
|
||||
console.log('handleTemplate-------------->res:',res)
|
||||
reload();
|
||||
}
|
||||
// 面板类型
|
||||
function tabChange(key) {
|
||||
if(key!=='3'){
|
||||
params.type = key;
|
||||
params.izTemplate = '0';
|
||||
}else{
|
||||
params.type = '';
|
||||
params.izTemplate = '1';
|
||||
}
|
||||
reload({pageNo:1});
|
||||
}
|
||||
|
||||
/**
|
||||
* 成功回调,刷新列表
|
||||
*/
|
||||
function success() {
|
||||
reload();
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,65 @@
|
|||
|
||||
import {ref} from 'vue'
|
||||
import html2canvas from 'html2canvas';
|
||||
|
||||
/**
|
||||
* 用于导出生成image
|
||||
*/
|
||||
export function useExportImage() {
|
||||
|
||||
const exportRef = ref();
|
||||
|
||||
/**
|
||||
* 导出图片触发事件
|
||||
* @param fileName
|
||||
*/
|
||||
function onExportImage(fileName) {
|
||||
let ele = exportRef.value;
|
||||
if(!ele){
|
||||
console.error('没有导出对象')
|
||||
return;
|
||||
}
|
||||
const size = {
|
||||
width: ele.offsetWidth,
|
||||
height: ele.offsetHeight
|
||||
}
|
||||
html2canvas(ele, { useCORS: true, logging: true }).then(async (canvas) => {
|
||||
const dataURL = canvas.toDataURL('image/png');
|
||||
await download(dataURL, size, fileName);
|
||||
});
|
||||
}
|
||||
|
||||
async function download(imgUrl, size, fileName) {
|
||||
const dataUrl = await getBase64(imgUrl, size);
|
||||
const link:any = document.createElement('a');
|
||||
link.href = dataUrl;
|
||||
link.download = `${fileName}.png`;
|
||||
link.click();
|
||||
}
|
||||
|
||||
function getBase64(url, size){
|
||||
return new Promise((resolve) => {
|
||||
let canvas:any = document.createElement('canvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
const img = new Image();
|
||||
// 允许跨域
|
||||
img.crossOrigin = 'Anonymous';
|
||||
img.src = url;
|
||||
img.onload = () => {
|
||||
// eslint-disable-next-line prefer-destructuring
|
||||
canvas.height = size.height;
|
||||
// eslint-disable-next-line prefer-destructuring
|
||||
canvas.width = size.width;
|
||||
ctx!.drawImage(img, 0, 0, size.width, size.height);
|
||||
const dataURL = canvas.toDataURL('image/png');
|
||||
canvas = null;
|
||||
resolve(dataURL);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
exportRef,
|
||||
onExportImage
|
||||
}
|
||||
}
|
|
@ -0,0 +1,163 @@
|
|||
<template>
|
||||
<div ref="exportRef">
|
||||
<ViewEngine :dragData="dragData" :token="getToken()" @go="compRouter" @btnClick="btnClick"></ViewEngine>
|
||||
</div>
|
||||
|
||||
<DemoModal @register="registerModal"/>
|
||||
<DesformViewModal @register="registerRecordModal" :showComment="false" :showFiles="false" :showDataLog="false"/>
|
||||
|
||||
</template>
|
||||
|
||||
<script lang="ts" name="drag-page-view" setup>
|
||||
import { ref, unref, reactive,computed, watch } from 'vue';
|
||||
import { useRouter, useRoute } from 'vue-router';
|
||||
import {queryById} from './page.api';
|
||||
import { useTabs } from '/@/hooks/web/useTabs';
|
||||
import { useModal } from '/@/components/Modal';
|
||||
import { openWindow } from '/@/utils';
|
||||
import { getToken } from '/@/utils/auth';
|
||||
import { useUserStore } from '/@/store/modules/user';
|
||||
import DemoModal from '/@/views/system/examples/demo/DemoModal.vue';
|
||||
import {router} from "/@/router";
|
||||
import {useExportImage} from './useExportImage'
|
||||
|
||||
const { setTitle } = useTabs();
|
||||
const userStore = useUserStore();
|
||||
//当前页面id
|
||||
const currentId: any = ref('');
|
||||
//当前路由信息
|
||||
const { currentRoute, push, resolve: pathResolve } = useRouter();
|
||||
//拖拽信息
|
||||
const dragData = ref({
|
||||
name: '',
|
||||
coverUrl: '',
|
||||
backgroundColor: '',
|
||||
theme: 'default',
|
||||
style: 'default',
|
||||
designType: 100,
|
||||
backgroundImage: '',
|
||||
componentData: [],
|
||||
});
|
||||
|
||||
//初始化数据
|
||||
async function initData() {
|
||||
const { params, path } = unref(currentRoute);
|
||||
let id = params.id ? params.id : path.substr(path.lastIndexOf('/') + 1);
|
||||
currentId.value = id;
|
||||
const res = await queryById({ id });
|
||||
if (res.success) {
|
||||
console.info(123, res);
|
||||
await setTitle(res.result.name);
|
||||
let template = res.result.template ? JSON.parse(res.result.template) : [];
|
||||
dragData.value.componentData = template;
|
||||
dragData.value.name = res.result.name;
|
||||
dragData.value.coverUrl = res.result.coverUrl;
|
||||
dragData.value.backgroundColor = res.result.backgroundColor;
|
||||
dragData.value.backgroundImage = res.result.backgroundImage;
|
||||
dragData.value.designType = res.result.designType;
|
||||
dragData.value.theme = res.result.theme || 'default';
|
||||
dragData.value.style = res.result.style || 'default';
|
||||
}
|
||||
}
|
||||
//界面跳转
|
||||
function compRouter(url: any, params: any) {
|
||||
if (url && url.indexOf('http') > -1) {
|
||||
openWindow(url);
|
||||
} else {
|
||||
push({ path: url, query: params });
|
||||
}
|
||||
}
|
||||
//********************按钮问点击回调后的逻辑begin*****************************************
|
||||
const [registerModal, { openModal }] = useModal();
|
||||
// 注册创建记录弹窗
|
||||
const [registerRecordModal, { openModal: openRecordModal }] = useModal();
|
||||
const route = useRoute();
|
||||
|
||||
/**
|
||||
* 跳转路由页面
|
||||
* @param path
|
||||
* @param openMode
|
||||
*/
|
||||
function goPage(nextRoute, params) {
|
||||
if(params.openMode==='2'){
|
||||
// 新页面打开视图
|
||||
let winUrl = pathResolve(nextRoute);
|
||||
window.open(winUrl.href, '_blank')
|
||||
}else{
|
||||
// 当前页面打开视图
|
||||
push(nextRoute)
|
||||
}
|
||||
}
|
||||
|
||||
function btnClick(params) {
|
||||
console.log("btnClick---->params",params);
|
||||
let operationType = params.operationType;
|
||||
if(operationType=='1'){
|
||||
let modalData = {
|
||||
mode: 'add',
|
||||
desformCode: params.worksheet.value,
|
||||
dataId: null,
|
||||
isOnline: false,
|
||||
viewId: '',
|
||||
lowAppId: route.params.appId
|
||||
}
|
||||
console.log('创建记录 打开modal的参数', modalData)
|
||||
openRecordModal(true, modalData);
|
||||
}else if(operationType=='2'){
|
||||
let appId = route.params.appId;
|
||||
let designFormCode = params.worksheet.value;
|
||||
let nextRoute = {
|
||||
path: `/myapp/${appId}/desform/${designFormCode}`,
|
||||
};
|
||||
if(params.view){
|
||||
nextRoute['query']={
|
||||
view: params.view
|
||||
}
|
||||
}
|
||||
console.log('打开视图 路由', nextRoute)
|
||||
goPage(nextRoute, params)
|
||||
//update-end-author:taoyan date:2023-2-23 for: QQYUN-3674【仪表盘】按钮配置,打开创建model和打开视图
|
||||
|
||||
}else if(operationType=='3'){
|
||||
|
||||
//update-begin-author:taoyan date:2023-3-1 for: QQYUN-4420【仪表盘】打开仪表盘 打不开或者跳转到后台了 应该在应用里边打开
|
||||
let appId = route.params.appId;
|
||||
let dragId = params.customPage.value;
|
||||
let nextRoute = {
|
||||
path: `/myapp/${appId}/drag/${dragId}`,
|
||||
};
|
||||
goPage(nextRoute, params);
|
||||
//update-end-author:taoyan date:2023-3-1 for: QQYUN-4420【仪表盘】打开仪表盘 打不开或者跳转到后台了 应该在应用里边打开
|
||||
|
||||
}else if(operationType=='4'){
|
||||
//打开链接
|
||||
|
||||
}
|
||||
}
|
||||
//********************按钮问点击回调后的逻辑end*****************************************
|
||||
|
||||
//update-begin-author:taoyan date:2023-2-24 for: QQYUN-3663【应用】仪表盘页面上,添加分享和导出图片功能
|
||||
const emit = defineEmits(['loadOk']);
|
||||
const props = defineProps({
|
||||
routeInfo: {
|
||||
type: Object,
|
||||
default: ()=>{}
|
||||
},
|
||||
});
|
||||
const { exportRef, onExportImage } = useExportImage();
|
||||
watch(()=>props.routeInfo, (info)=>{
|
||||
if(info){
|
||||
if(info.exportImage){
|
||||
console.log('导出图片》》》');
|
||||
let name = dragData.value.name;
|
||||
onExportImage(name);
|
||||
}
|
||||
}
|
||||
}, {deep: true, immediate: true});
|
||||
//update-end-author:taoyan date:2023-2-24 for: QQYUN-3663【应用】仪表盘页面上,添加分享和导出图片功能
|
||||
|
||||
initData();
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
@import '@qiaoqiaoyun/drag-free/lib/index.css';
|
||||
</style>
|
Loading…
Reference in New Issue