删除前端仪表盘
parent
d4f134b2b5
commit
21e5143937
|
@ -2,7 +2,7 @@ import type { App } from 'vue';
|
||||||
import { Icon } from './Icon';
|
import { Icon } from './Icon';
|
||||||
import AIcon from '/@/components/jeecg/AIcon.vue';
|
import AIcon from '/@/components/jeecg/AIcon.vue';
|
||||||
//Tinymce富文本
|
//Tinymce富文本
|
||||||
import Editor from '/@/components/Tinymce/src/Editor.vue';
|
import Editor from '/@/components/Tinymce/src/Editor.vue'
|
||||||
|
|
||||||
import { Button, JUploadButton } from './Button';
|
import { Button, JUploadButton } from './Button';
|
||||||
|
|
||||||
|
@ -60,20 +60,16 @@ import {
|
||||||
} from 'ant-design-vue';
|
} from 'ant-design-vue';
|
||||||
const compList = [AntButton.Group, Icon, AIcon, JUploadButton];
|
const compList = [AntButton.Group, Icon, AIcon, JUploadButton];
|
||||||
|
|
||||||
//敲敲云—仪表盘设计器(拖拽设计)
|
|
||||||
import DragEngine from '@qiaoqiaoyun/drag-free';
|
|
||||||
import('@qiaoqiaoyun/drag-free/lib/index.css');
|
|
||||||
console.log('---初始化---, 全局注册仪表盘--------------');
|
|
||||||
|
|
||||||
export function registerGlobComp(app: App) {
|
export function registerGlobComp(app: App) {
|
||||||
compList.forEach((comp) => {
|
compList.forEach((comp) => {
|
||||||
app.component(comp.name || comp.displayName, comp);
|
app.component(comp.name || comp.displayName, comp);
|
||||||
});
|
});
|
||||||
|
|
||||||
//仪表盘依赖Tinymce,需要提前加载(没办法按需加载了)
|
//仪表盘依赖Tinymce,需要提前加载(没办法按需加载了)
|
||||||
app.component(Editor.name, Editor);
|
app.component(Editor.name, Editor);
|
||||||
|
|
||||||
app
|
app.use(Select)
|
||||||
.use(Select)
|
|
||||||
.use(Alert)
|
.use(Alert)
|
||||||
.use(Button)
|
.use(Button)
|
||||||
.use(Breadcrumb)
|
.use(Breadcrumb)
|
||||||
|
@ -118,9 +114,7 @@ export function registerGlobComp(app: App) {
|
||||||
.use(InputNumber)
|
.use(InputNumber)
|
||||||
.use(Carousel)
|
.use(Carousel)
|
||||||
.use(Popconfirm)
|
.use(Popconfirm)
|
||||||
.use(DragEngine)
|
|
||||||
.use(Skeleton)
|
.use(Skeleton)
|
||||||
.use(Cascader)
|
.use(Cascader)
|
||||||
.use(Rate);
|
.use(Rate);
|
||||||
console.log("注册antd组件完成!");
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,473 +0,0 @@
|
||||||
<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>
|
|
|
@ -1,187 +0,0 @@
|
||||||
<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="false"
|
|
||||||
@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>
|
|
|
@ -1,71 +0,0 @@
|
||||||
<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>
|
|
|
@ -1,105 +0,0 @@
|
||||||
<!--面板保护密码弹窗-->
|
|
||||||
<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>
|
|
|
@ -1,74 +0,0 @@
|
||||||
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();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
|
@ -1,66 +0,0 @@
|
||||||
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'
|
|
||||||
}
|
|
||||||
];
|
|
|
@ -1,176 +0,0 @@
|
||||||
<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>
|
|
|
@ -1,65 +0,0 @@
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,158 +0,0 @@
|
||||||
<template>
|
|
||||||
<div ref="exportRef">
|
|
||||||
<ViewEngine :dragData="dragData" :token="getToken()" @go="compRouter" @btnClick="btnClick"></ViewEngine>
|
|
||||||
</div>
|
|
||||||
</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 {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