feat: 添加图片选择组件

master
绝弹 2023-10-10 22:48:11 +08:00
parent 2bc4ac1d34
commit 2076a87f19
22 changed files with 444 additions and 128 deletions

View File

@ -7,9 +7,7 @@
<a-tooltip content="固定水平方向"> <a-tooltip content="固定水平方向">
<i <i
class="cursor-pointer text-gray-400 hover:text-gray-700" class="cursor-pointer text-gray-400 hover:text-gray-700"
:class=" :class="data.xFixed ? 'icon-park-outline-lock text-gray-900' : 'icon-park-outline-unlock text-gray-400'"
data.xFixed ? 'icon-park-outline-lock text-gray-900' : 'icon-park-outline-unlock text-gray-400'
"
@click="data.xFixed = !data.xFixed" @click="data.xFixed = !data.xFixed"
></i> ></i>
</a-tooltip> </a-tooltip>
@ -22,9 +20,7 @@
<a-tooltip content="固定垂直方向"> <a-tooltip content="固定垂直方向">
<i <i
class="cursor-pointer text-gray-400 hover:text-gray-700" class="cursor-pointer text-gray-400 hover:text-gray-700"
:class=" :class="data.yFixed ? 'icon-park-outline-lock text-gray-900' : 'icon-park-outline-unlock text-gray-400'"
data.yFixed ? 'icon-park-outline-lock text-gray-900' : 'icon-park-outline-unlock text-gray-400'
"
@click="data.yFixed = !data.yFixed" @click="data.yFixed = !data.yFixed"
></i> ></i>
</a-tooltip> </a-tooltip>
@ -43,11 +39,7 @@
</div> </div>
<a-form-item label="背景图片"> <a-form-item label="背景图片">
<a-input v-model="data.bgImage" class="group w-full" allow-clear placeholder="暂无"> <input-image v-model="data.bgImage"></input-image>
<template #prefix>
<a-link class="!text-xs">选择</a-link>
</template>
</a-input>
</a-form-item> </a-form-item>
<a-form-item label="背景颜色"> <a-form-item label="背景颜色">
@ -62,6 +54,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { PropType } from "vue"; import { PropType } from "vue";
import InputImage from "../../components/InputImage.vue";
defineProps({ defineProps({
data: { data: {
@ -70,5 +63,3 @@ defineProps({
}, },
}); });
</script> </script>
<style scoped></style>

View File

@ -1,16 +1,189 @@
<template> <template>
<a-modal title="选择图片" v-model:visible="visible" title-align="start" :closable="false"> <a-modal
<div class="flex flex-wrap gap-4"> v-model:visible="innerVisible"
<div v-for="item in images" :key="item" class="w-24 h-24 bg-gray-200 flex items-center justify-center"> title="选择图片"
<img :src="item" class="w-full h-full object-cover" /> title-align="start"
:width="1080"
:closable="false"
:mask-closable="false"
:ok-button-props="{ disabled: !seleted.length }"
>
<div class="w-full flex items-center justify-between gap-4">
<div>
<a-button type="outline" class="!text-gray-700 !border-gray-300">
<template #icon>
<i class="icon-park-outline-upload"></i>
</template>
上传
</a-button>
</div>
<div>
<a-input-search
:disabled="loading"
class="!w-48 mr-2"
placeholder="请输入素材名称"
@search="loadData"
></a-input-search>
</div> </div>
</div> </div>
<a-spin :loading="loading" :dot="true" tip="正在加载中,请稍等..." class="h-[450px] w-full">
<div class="h-[450px] grid grid-cols-5 grid-rows-2 items-start justify-between gap-4 mt-2">
<div
v-for="item in images"
:key="item.title"
:class="{
selected: selectedKeys.includes(item.id),
}"
class="p-2 border border-transparent rounded"
@click="onSelectedImage(item)"
>
<div class="w-full bg-gray-50 flex items-center justify-center">
<img :src="item.url" class="w-full aspect-video object-cover rounded hover:opacity-80" />
</div>
<div class="mt-2 flex items-center gap-2">
<div class="flex-1 truncate">
{{ item.title }}
</div>
<div class="text-xs text-gray-400">1280 * 800</div>
</div>
</div>
</div>
<div class="mt-2 flex justify-end">
<a-pagination
v-model:current="pagination.page"
v-model:page-size="pagination.size"
:total="pagination.total"
:disabled="loading"
@change="loadData"
@page-size-change="loadData"
></a-pagination>
</div>
</a-spin>
<template #footer>
<div class="flex items-center justify-between gap-4">
<div>已选: {{ seleted.length }} </div>
<div>
<a-button class="mr-2" @click="onClose"></a-button>
<a-button type="primary" @click="onBeforeOk" :disabled="!seleted.length">确定</a-button>
</div>
</div>
</template>
</a-modal> </a-modal>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
const visible = ref(false); import { mockLoad } from "./mock";
const images = ref([]);
const props = defineProps({
modelValue: {
type: String,
default: "",
},
visible: {
type: Boolean,
default: false,
},
multiple: {
type: Boolean,
default: false,
},
load: {
type: Function,
default: mockLoad,
},
});
const loadData = async () => {
const { page, size } = pagination.value;
const params = { ...search.value, page, size };
try {
loading.value = true;
const { data, total } = await props.load(params);
images.value = data;
pagination.value.total = total;
} finally {
loading.value = false;
}
};
const pagination = ref({ page: 1, size: 15, total: 0 });
const search = ref({ name: "" });
const loading = ref(false);
const images = ref<any[]>([]);
const seleted = ref<any[]>([]);
const selectedKeys = computed(() => seleted.value.map((item) => item.id));
const onBeforeOk = () => {
emit("update:modelValue", seleted.value[0]?.url);
onClose();
};
const onClose = () => {
seleted.value = [];
images.value = [];
pagination.value.page = 1;
pagination.value.total = 0;
search.value.name = "";
innerVisible.value = false;
};
const onSelectedImage = (image: any) => {
if (selectedKeys.value.includes(image.id)) {
seleted.value = seleted.value.filter((item) => item.id !== image.id);
} else {
if (!props.multiple) {
seleted.value = [image];
return;
}
seleted.value.push(image);
}
};
watch(
() => props.visible,
async (value) => {
if (!value) return;
loadData();
}
);
const emit = defineEmits(["update:modelValue", "update:visible"]);
const innerVisible = computed({
get: () => props.visible,
set: (value) => emit("update:visible", value),
});
</script> </script>
<style scoped></style> <style scoped>
.selected {
position: relative;
border-color: rgb(var(--primary-6));
background-color: rgb(var(--primary-1));
cursor: pointer;
}
.selected:after {
content: "";
position: absolute;
bottom: 0px;
right: 0px;
width: 0;
height: 0;
border-bottom: 20px solid #09f;
border-left: 20px solid transparent;
}
.selected:before {
content: "";
position: absolute;
bottom: 5px;
right: 1px;
width: 10px;
height: 5px;
border: 2px solid white;
border-top: none;
border-right: none;
transform: rotate(-55deg);
z-index: 2;
}
</style>

View File

@ -0,0 +1,26 @@
<template>
<a-input v-model="model">
<template #prefix>
<color-picker v-model="model"></color-picker>
</template>
</a-input>
</template>
<script setup lang="ts">
const props = defineProps({
modelValue: {
type: String,
default: "",
},
});
const emit = defineEmits(["update:modelValue"]);
const model = computed({
get: () => props.modelValue,
set: (value) => emit("update:modelValue", value),
});
</script>
<style scoped></style>

View File

@ -0,0 +1,29 @@
<template>
<a-input v-model="model" class="group w-full" allow-clear placeholder="暂无">
<template #prefix>
<a-link @click="visible = true">选择</a-link>
</template>
</a-input>
<image-picker v-model="model" v-model:visible="visible"></image-picker>
</template>
<script setup lang="ts">
import ImagePicker from './ImagePicker.vue';
const props = defineProps({
modelValue: {
type: String,
default: "",
},
});
const emit = defineEmits(["update:modelValue"]);
const visible = ref(false);
const model = computed({
get: () => props.modelValue,
set: (value) => emit("update:modelValue", value),
});
</script>
<style scoped></style>

View File

@ -0,0 +1,29 @@
const sleep = (time: number) => {
return new Promise<void>((resolve) => {
setTimeout(() => {
resolve();
}, time);
});
};
interface MockParams {
page: number;
size: number;
}
export const mockLoad = async (params: MockParams) => {
const { page, size } = params;
await sleep(1000);
const counts = Array(15).fill(9);
const data = counts.map((v, i) => {
return {
id: (page - 1) * size + i,
title: "图片1",
url: `https://source.unsplash.com/random?sig=${(page - 1) * size + i}`,
};
});
return {
data,
total: 100,
};
};

View File

@ -11,7 +11,7 @@ export interface Block<T = any> {
bgColor?: string; bgColor?: string;
data: T; data: T;
meta: Record<string, any>; meta: Record<string, any>;
actived: false, actived: boolean,
resizable: boolean, resizable: boolean,
draggable: boolean, draggable: boolean,
} }

View File

@ -1,11 +1,13 @@
export interface Container { export interface Container {
id: number | string; id: number | string;
x: number;
y: number;
zoom: number;
title: string; title: string;
description?: string; description: string;
width: number; width: number;
height: number; height: number;
bgImage?: string; bgImage: string;
bgColor?: string; bgColor: string;
zoom: number;
} }

View File

@ -3,12 +3,13 @@ import { Block } from "./block";
import { Container } from "./container"; import { Container } from "./container";
export interface Context { export interface Context {
current: { current: Ref<{
block: Block; block: Block | null;
}; }>;
blocks: Ref<Block[]>; blocks: Ref<Block[]>;
container: Ref<Container>; container: Ref<Container>;
setCurrentBlock: (block: Block) => void; setCurrentBlock: (block: Block) => void;
setContainerOrigin: () => void;
} }
export const ContextKey = Symbol('ContextKey') as InjectionKey<Context>; export const ContextKey = Symbol('ContextKey') as InjectionKey<Context>;

View File

@ -20,13 +20,13 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ContextKey } from "./config"; import { Block, Container, ContextKey } from "./config";
import PanelHeader from "./panel-header/index.vue"; import PanelHeader from "./panel-header/index.vue";
import PanelLeft from "./panel-left/index.vue"; import PanelLeft from "./panel-left/index.vue";
import PanelMain from "./panel-main/index.vue"; import PanelMain from "./panel-main/index.vue";
import PanelRight from "./panel-right/index.vue"; import PanelRight from "./panel-right/index.vue";
const blocks = ref<Block>([]); const blocks = ref<Block[]>([]);
const current = ref({ const current = ref({
block: null as Block | null, block: null as Block | null,
@ -36,30 +36,40 @@ const container = ref<Container>({
id: 11, id: 11,
title: "国庆节喜庆版式设计", title: "国庆节喜庆版式设计",
description: "适用于国庆节1日-7日间上午9:00-10:00播出的版式设计", description: "适用于国庆节1日-7日间上午9:00-10:00播出的版式设计",
x: 0,
y: 0,
zoom: 0.7,
width: 1920, width: 1920,
height: 1080, height: 1080,
bgImage: "", bgImage: "",
bgColor: "#ffffff", bgColor: "#ffffff",
zoom: 1,
}); });
const setCurrentBlock = (block: Block | null) => { const setCurrentBlock = (block: Block | null) => {
for (const block of blocks.value) { for (const block of blocks.value) {
block.active = false; block.actived = false;
} }
if (!block) { if (!block) {
current.value.block = null; current.value.block = null;
return; return;
} }
block.active = true; block.actived = true;
current.value.block = block; current.value.block = block;
}; };
//
const setContainerOrigin = () => {
container.value.x = 0;
container.value.y = 0;
container.value.zoom = 0.7;
};
provide(ContextKey, { provide(ContextKey, {
current, current,
container, container,
blocks, blocks,
setCurrentBlock, setCurrentBlock,
setContainerOrigin,
}); });
</script> </script>

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="h-full grid grid-cols-[auto_1fr]" :style="{ width: !collapsed ? '248px' : undefined }"> <div class="h-full grid grid-cols-[auto_1fr]" :style="{ width: !collapsed ? '248px' : undefined }">
<div class="h-full grid grid-rows-[1fr_auto] border-r border-slate-200"> <div class="h-full grid grid-rows-[1fr_auto] border-r border-slate-200">
<a-menu :collapsed="true"> <a-menu :collapsed="true" :default-selected-keys="['0_0']">
<a-menu-item key="0_0"> <a-menu-item key="0_0">
<template #icon> <template #icon>
<i class="icon-park-outline-all-application"></i> <i class="icon-park-outline-all-application"></i>
@ -57,7 +57,7 @@
<script setup lang="ts"> <script setup lang="ts">
const collapsed = ref(false); const collapsed = ref(false);
const onDragStart = (e: Event) => { const onDragStart = (e: DragEvent) => {
console.log('start'); console.log('start');
e.dataTransfer?.setData("type", (e.target as HTMLElement).dataset.type!); e.dataTransfer?.setData("type", (e.target as HTMLElement).dataset.type!);
} }

View File

@ -6,11 +6,11 @@
:h="data.h" :h="data.h"
:parentW="container.width" :parentW="container.width"
:parentH="container.height" :parentH="container.height"
:parentScaleX="container.zoom / 100" :parentScaleX="container.zoom"
:parentScaleY="container.zoom / 100" :parentScaleY="container.zoom"
:parentLimitation="true" :parentLimitation="true"
:preventActiveBehavior="!data.draggable" :preventActiveBehavior="!data.draggable"
:isActive="data.active" :isActive="data.actived"
:isResizable="data.resizable" :isResizable="data.resizable"
:style="blockStyle" :style="blockStyle"
@dragging="onItemDragOrResize" @dragging="onItemDragOrResize"
@ -23,9 +23,9 @@
<script setup lang="ts"> <script setup lang="ts">
import { PropType } from "vue"; import { PropType } from "vue";
import { Block, Container, ContextKey } from "../../config"; import { BlockerMap } from "../../blocks";
import { BlockerMap } from "../../items";
import DragResizer from "../../components/DragResizer.vue"; import DragResizer from "../../components/DragResizer.vue";
import { Block, Container, ContextKey } from "../../config";
const props = defineProps({ const props = defineProps({
data: { data: {
@ -38,7 +38,7 @@ const props = defineProps({
}, },
}); });
const { setCurrentBlock } = inject(ContextKey); const { setCurrentBlock } = inject(ContextKey)!;
const blockStyle = computed(() => { const blockStyle = computed(() => {
const { bgColor, bgImage } = props.data; const { bgColor, bgImage } = props.data;

View File

@ -3,43 +3,33 @@
<div class="flex-1"> <div class="flex-1">
<div class="group"> <div class="group">
<span class="text-gray-400">描述: </span> <span class="text-gray-400">描述: </span>
<span v-if="!descEditing"> <ani-texter v-model="container.description"></ani-texter>
{{ container.description }}
<i
class="!hidden !group-hover:inline-block icon-park-outline-edit text-gray-400 hover:text-gray-700 ml-1 cursor-pointer"
@click="onDescEdit"
></i>
</span>
<span v-else class="inline-flex items-center">
<a-input size="small" v-model="descContent" class="!w-96"></a-input>
<a-button type="text" size="small" @click="onDescEdited" class="ml-2">
<template #icon>
<i class="icon-park-outline-check"></i>
</template>
</a-button>
<a-button type="text" size="small" class="!text-gray-500" @click="descEditing = false">
<template #icon>
<i class="icon-park-outline-close"></i>
</template>
</a-button>
</span>
</div> </div>
</div> </div>
<div class="flex items-center"> <div class="flex items-center">
<span class="text-gray-400 text-xs mr-2"> <span class="text-gray-400 text-xs mr-3">
坐标
<span class="text-gray-700">{{ Math.floor(container.x) }} , {{ Math.floor(container.y) }} </span>
</span>
<span class="text-gray-400 text-xs mr-3">
尺寸 尺寸
<span class="text-gray-700">{{ container.width }} * {{ container.height }} </span> <span class="text-gray-700">{{ container.width }} * {{ container.height }} </span>
</span> </span>
<span class="text-gray-400 text-xs mr-2"> <span class="text-gray-400 text-xs mr-2">
比例 比例
<span class="text-gray-700"> <span class="inline-block w-8 text-gray-700">{{ Math.floor(container.zoom * 100) }}% </span>
{{ parseInt(container.zoom * 100) }}%
</span>
</span> </span>
<span class="text-gray-400 text-xs mr-2"> <span class="text-gray-400 text-xs mr-2">
组件 组件
<span class="text-gray-700">{{ 2 }} </span> <span class="inline-block w-6 text-gray-700">{{ blocks.length }} </span>
</span> </span>
<a-tooltip content="自适应比例" position="bottom">
<a-button type="text" @click="setContainerOrigin">
<template #icon>
<i class="icon-park-outline-equal-ratio text-base !text-gray-600"></i>
</template>
</a-button>
</a-tooltip>
<a-tooltip content="预览" position="bottom"> <a-tooltip content="预览" position="bottom">
<a-button type="text"> <a-button type="text">
<template #icon> <template #icon>
@ -48,20 +38,24 @@
</a-button> </a-button>
</a-tooltip> </a-tooltip>
<a-popover position="br" trigger="click"> <a-popover position="br" trigger="click">
<a-tooltip content="设置" position="bottom">
<a-button type="text"> <a-button type="text">
<template #icon> <template #icon>
<i class="icon-park-outline-config text-base !text-gray-600"></i> <i class="icon-park-outline-config text-base !text-gray-600"></i>
</template> </template>
</a-button> </a-button>
</a-tooltip>
<template #content> <template #content>
<span> <a-form :model="{}" layout="vertical">
背景图片: <div class="muti-form-item">
<a-link>选择</a-link> <a-form-item label="背景图片">
</span> <input-image v-model="container.bgImage"></input-image>
<span class="inline-flex items-center"> </a-form-item>
背景颜色 <a-form-item label="背景颜色">
<color-picker></color-picker> <input-color v-model="container.bgColor"></input-color>
</span> </a-form-item>
</div>
</a-form>
</template> </template>
</a-popover> </a-popover>
</div> </div>
@ -69,25 +63,12 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
const props = defineProps({ import InputColor from "../../components/InputColor.vue";
container: { import InputImage from "../../components/InputImage.vue";
type: Object as PropType<any>, import { ContextKey } from "../../config";
required: true, import AniTexter from "./texter.vue";
},
});
const descEditing = ref(false); const { container, blocks, setContainerOrigin } = inject(ContextKey)!;
const descContent = ref("");
const onDescEdited = () => {
props.container.description = descContent.value;
descEditing.value = false;
};
const onDescEdit = () => {
descContent.value = props.container.description;
descEditing.value = true;
};
</script> </script>
<style scoped></style> <style scoped></style>

View File

@ -0,0 +1,47 @@
<template>
<span v-if="!descEditing">
{{ modelValue }}
<i
class="!hidden !group-hover:inline-block icon-park-outline-edit text-gray-400 hover:text-gray-700 ml-1 cursor-pointer"
@click="onDescEdit"
></i>
</span>
<span v-else class="inline-flex items-center">
<a-input size="small" v-model="descContent" class="!w-96"></a-input>
<a-button type="text" size="small" @click="onDescEdited" class="ml-2">
<template #icon>
<i class="icon-park-outline-check"></i>
</template>
</a-button>
<a-button type="text" size="small" class="!text-gray-500" @click="descEditing = false">
<template #icon>
<i class="icon-park-outline-close"></i>
</template>
</a-button>
</span>
</template>
<script setup lang="ts">
const props = defineProps({
modelValue: {
type: String,
default: "",
},
});
const emit = defineEmits(["update:modelValue"]);
const descEditing = ref(false);
const descContent = ref("");
const onDescEdited = () => {
emit("update:modelValue", descContent.value);
descEditing.value = false;
};
const onDescEdit = () => {
descContent.value = props.modelValue;
descEditing.value = true;
};
</script>
<style scoped></style>

View File

@ -22,10 +22,11 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import ColorPicker from "../components/ColorPicker.vue"; import { ContextKey } from "../config";
import AniBlock from "./components/block.vue"; import AniBlock from "./components/block.vue";
import AniHeader from "./components/header.vue"; import AniHeader from "./components/header.vue";
import { Block, ContextKey, Container } from "../config";
const { blocks, container } = inject(ContextKey)!;
const isStart = ref(false); const isStart = ref(false);
const position = ref({ const position = ref({
@ -37,19 +38,19 @@ const position = ref({
mouseY: 0, mouseY: 0,
}); });
const onMouseDown = (e: Event) => { const onMouseDown = (e: MouseEvent) => {
isStart.value = true; isStart.value = true;
position.value.startX = e.offsetX; position.value.startX = e.offsetX;
position.value.startY = e.offsetY; position.value.startY = e.offsetY;
}; };
const onMouseMove = (e: Event) => { const onMouseMove = (e: MouseEvent) => {
if (!isStart.value) { if (!isStart.value) {
return; return;
} }
const scale = container.value.zoom; const scale = container.value.zoom;
position.value.x += (e.offsetX - position.value.startX) * scale; container.value.x += (e.offsetX - position.value.startX) * scale;
position.value.y += (e.offsetY - position.value.startY) * scale; container.value.y += (e.offsetY - position.value.startY) * scale;
}; };
const onMouseUp = () => { const onMouseUp = () => {
@ -64,11 +65,8 @@ onUnmounted(() => {
window.removeEventListener("mouseup", onMouseUp); window.removeEventListener("mouseup", onMouseUp);
}); });
const { blocks, container } = inject(ContextKey);
const containerStyle = computed(() => { const containerStyle = computed(() => {
const { width, height, bgColor, bgImage, zoom } = container.value; const { width, height, bgColor, bgImage, zoom, x, y } = container.value;
const { x, y } = position.value;
return { return {
position: "absolute", position: "absolute",
width: `${width}px`, width: `${width}px`,
@ -76,13 +74,13 @@ const containerStyle = computed(() => {
backgroundColor: bgColor, backgroundColor: bgColor,
backgroundImage: bgImage ? `url(${bgImage})` : undefined, backgroundImage: bgImage ? `url(${bgImage})` : undefined,
backgroundSize: "100% 100%", backgroundSize: "100% 100%",
// transform: `translate3d(${x}px, ${y}px, 0) scale(${zoom})`, transform: `translate3d(${x}px, ${y}px, 0) scale(${zoom})`,
transform: `matrix(${zoom}, 0, 0, ${zoom}, ${x}, ${y})`, // transform: `matrix(${zoom}, 0, 0, ${zoom}, ${x}, ${y})`,
// transformOrigin: "0 0", // transformOrigin: "0 0",
}; } as any;
}); });
const onDragDrop = (e: Event) => { const onDragDrop = (e: DragEvent) => {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
@ -92,8 +90,7 @@ const onDragDrop = (e: Event) => {
} }
blocks.value.push({ blocks.value.push({
x: 0, id: "0",
y: 0,
w: 200, w: 200,
h: 100, h: 100,
bgColor: "#0099ff", bgColor: "#0099ff",
@ -104,6 +101,9 @@ const onDragDrop = (e: Event) => {
type, type,
x: e.offsetX, x: e.offsetX,
y: e.offsetY, y: e.offsetY,
data: {},
meta: {},
actived: false,
}); });
}; };
@ -111,14 +111,12 @@ const onMouseWheel = (e: WheelEvent) => {
e.preventDefault(); e.preventDefault();
const prezoom = container.value.zoom; const prezoom = container.value.zoom;
let zoom = prezoom; let zoom = prezoom;
if (e.wheelDelta > 0) { if (e.deltaY > 0) {
console.log("放大");
zoom += 0.1; zoom += 0.1;
if (zoom > 10) { if (zoom > 10) {
return; return;
} }
} else { } else {
console.log("缩小");
zoom -= 0.1; zoom -= 0.1;
if (zoom < 0.1) { if (zoom < 0.1) {
return; return;

View File

@ -17,12 +17,11 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import BlockAttr from "./block-attr.vue"; import { BlockerMap } from "../blocks";
import TextAttr from "./text-attr.vue";
import { ContextKey } from "../config"; import { ContextKey } from "../config";
import BlockerMap from "../items"; import TextAttr from "./text-attr.vue";
const { current } = inject(ContextKey); const { current } = inject(ContextKey)!;
const item = ref<any>({ const item = ref<any>({
x: 0, x: 0,

View File

@ -0,0 +1,13 @@
<template>
<div>
</div>
</template>
<script setup lang="ts">
</script>
<style scoped>
</style>

View File

@ -7,25 +7,34 @@ export {}
declare module '@vue/runtime-core' { declare module '@vue/runtime-core' {
export interface GlobalComponents { export interface GlobalComponents {
AAvatar: typeof import('@arco-design/web-vue')['Avatar']
AButton: typeof import('@arco-design/web-vue')['Button'] AButton: typeof import('@arco-design/web-vue')['Button']
ACheckbox: typeof import('@arco-design/web-vue')['Checkbox']
ADivider: typeof import('@arco-design/web-vue')['Divider'] ADivider: typeof import('@arco-design/web-vue')['Divider']
ADoption: typeof import('@arco-design/web-vue')['Doption'] ADoption: typeof import('@arco-design/web-vue')['Doption']
ADrawer: typeof import('@arco-design/web-vue')['Drawer']
ADropdown: typeof import('@arco-design/web-vue')['Dropdown']
ADropdownButton: typeof import('@arco-design/web-vue')['DropdownButton'] ADropdownButton: typeof import('@arco-design/web-vue')['DropdownButton']
AForm: typeof import('@arco-design/web-vue')['Form'] AForm: typeof import('@arco-design/web-vue')['Form']
AFormItem: typeof import('@arco-design/web-vue')['FormItem'] AFormItem: typeof import('@arco-design/web-vue')['FormItem']
AInput: typeof import('@arco-design/web-vue')['Input'] AInput: typeof import('@arco-design/web-vue')['Input']
AInputNumber: typeof import('@arco-design/web-vue')['InputNumber'] AInputNumber: typeof import('@arco-design/web-vue')['InputNumber']
AInputPassword: typeof import('@arco-design/web-vue')['InputPassword'] AInputSearch: typeof import('@arco-design/web-vue')['InputSearch']
ALayout: typeof import('@arco-design/web-vue')['Layout']
ALayoutContent: typeof import('@arco-design/web-vue')['LayoutContent']
ALayoutHeader: typeof import('@arco-design/web-vue')['LayoutHeader']
ALayoutSider: typeof import('@arco-design/web-vue')['LayoutSider']
ALink: typeof import('@arco-design/web-vue')['Link'] ALink: typeof import('@arco-design/web-vue')['Link']
AMenu: typeof import('@arco-design/web-vue')['Menu'] AMenu: typeof import('@arco-design/web-vue')['Menu']
AMenuItem: typeof import('@arco-design/web-vue')['MenuItem'] AMenuItem: typeof import('@arco-design/web-vue')['MenuItem']
AMenuItemGroup: typeof import('@arco-design/web-vue')['MenuItemGroup']
AModal: typeof import('@arco-design/web-vue')['Modal'] AModal: typeof import('@arco-design/web-vue')['Modal']
APagination: typeof import('@arco-design/web-vue')['Pagination']
APopover: typeof import('@arco-design/web-vue')['Popover'] APopover: typeof import('@arco-design/web-vue')['Popover']
ARadio: typeof import('@arco-design/web-vue')['Radio'] ARadio: typeof import('@arco-design/web-vue')['Radio']
ARadioGroup: typeof import('@arco-design/web-vue')['RadioGroup'] ARadioGroup: typeof import('@arco-design/web-vue')['RadioGroup']
AScrollbar: typeof import('@arco-design/web-vue')['Scrollbar']
ASelect: typeof import('@arco-design/web-vue')['Select'] ASelect: typeof import('@arco-design/web-vue')['Select']
ASpace: typeof import('@arco-design/web-vue')['Space'] ASpin: typeof import('@arco-design/web-vue')['Spin']
ATag: typeof import('@arco-design/web-vue')['Tag'] ATag: typeof import('@arco-design/web-vue')['Tag']
ATextarea: typeof import('@arco-design/web-vue')['Textarea'] ATextarea: typeof import('@arco-design/web-vue')['Textarea']
ATooltip: typeof import('@arco-design/web-vue')['Tooltip'] ATooltip: typeof import('@arco-design/web-vue')['Tooltip']
@ -38,16 +47,20 @@ declare module '@vue/runtime-core' {
Editor: typeof import('./../components/editor/index.vue')['default'] Editor: typeof import('./../components/editor/index.vue')['default']
Header: typeof import('./../components/editor/panel-main/components/header.vue')['default'] Header: typeof import('./../components/editor/panel-main/components/header.vue')['default']
ImagePicker: typeof import('./../components/editor/components/ImagePicker.vue')['default'] ImagePicker: typeof import('./../components/editor/components/ImagePicker.vue')['default']
Option: typeof import('./../components/editor/items/text/option.vue')['default'] InputColor: typeof import('./../components/editor/components/InputColor.vue')['default']
InputImage: typeof import('./../components/editor/components/InputImage.vue')['default']
Option: typeof import('./../components/editor/blocks/text/option.vue')['default']
Page403: typeof import('./../components/error/page-403.vue')['default'] Page403: typeof import('./../components/error/page-403.vue')['default']
PanelHeader: typeof import('./../components/editor/panel-header/index.vue')['default'] PanelHeader: typeof import('./../components/editor/panel-header/index.vue')['default']
PanelLeft: typeof import('./../components/editor/panel-left/index.vue')['default'] PanelLeft: typeof import('./../components/editor/panel-left/index.vue')['default']
PanelMain: typeof import('./../components/editor/panel-main/index.vue')['default'] PanelMain: typeof import('./../components/editor/panel-main/index.vue')['default']
PanelRight: typeof import('./../components/editor/panel-right/index.vue')['default'] PanelRight: typeof import('./../components/editor/panel-right/index.vue')['default']
Render: typeof import('./../components/editor/items/text/render.vue')['default'] Preview: typeof import('./../components/editor/preview/index.vue')['default']
Render: typeof import('./../components/editor/blocks/text/render.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink'] RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView'] RouterView: typeof import('vue-router')['RouterView']
TextAttr: typeof import('./../components/editor/panel-right/text-attr.vue')['default'] TextAttr: typeof import('./../components/editor/panel-right/text-attr.vue')['default']
Texter: typeof import('./../components/editor/panel-main/components/texter.vue')['default']
Toast: typeof import('./../components/toast/toast.vue')['default'] Toast: typeof import('./../components/toast/toast.vue')['default']
} }
} }

View File

@ -8,9 +8,9 @@ import { ArcoResolver } from "unplugin-vue-components/resolvers";
import AutoComponent from "unplugin-vue-components/vite"; import AutoComponent from "unplugin-vue-components/vite";
import { defineConfig, loadEnv } from "vite"; import { defineConfig, loadEnv } from "vite";
import Page from "vite-plugin-pages"; import Page from "vite-plugin-pages";
import plugin from "./scripts/vite/plugin";
import { arcoToUnoColor } from "./scripts/vite/color"; import { arcoToUnoColor } from "./scripts/vite/color";
import fileIcon from "./scripts/vite/icon-file.json"; import fileIcon from "./scripts/vite/icon-file.json";
import plugin from "./scripts/vite/plugin";
/** /**
* vite * vite
@ -51,7 +51,11 @@ export default defineConfig(({ mode }) => {
* Vue 3 * Vue 3
* @see https://github.com/vitejs/vite-plugin-vue/tree/main/packages/plugin-vue * @see https://github.com/vitejs/vite-plugin-vue/tree/main/packages/plugin-vue
*/ */
Vue({}), Vue({
script: {
defineModel: true
}
}),
/** /**
* Vue 3 JSX * Vue 3 JSX