|
|
@@ -0,0 +1,153 @@
|
|
|
+<template>
|
|
|
+ <el-dialog
|
|
|
+ v-model="show"
|
|
|
+ :title="$t('createComponent')"
|
|
|
+ width="600px"
|
|
|
+ :modal="false"
|
|
|
+ :close-on-click-modal="false"
|
|
|
+ align-center
|
|
|
+ >
|
|
|
+ <el-form label-position="top" ref="form" :model="formData" :rules="rules">
|
|
|
+ <el-form-item :label="$t('name')" prop="name">
|
|
|
+ <el-input v-model="formData.name" :placeholder="$t('name')" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item :label="$t('desc')" prop="description">
|
|
|
+ <el-input
|
|
|
+ v-model="formData.description"
|
|
|
+ :rows="3"
|
|
|
+ type="textarea"
|
|
|
+ :placeholder="$t('desc')"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item :label="$t('icon')" prop="iconFile">
|
|
|
+ <el-upload
|
|
|
+ drap
|
|
|
+ action="#"
|
|
|
+ class="avatar-uploader"
|
|
|
+ accept=".jpg, .png, .svg"
|
|
|
+ :http-request="handleUpload"
|
|
|
+ :show-file-list="false"
|
|
|
+ :on-success="handleAvatarSuccess"
|
|
|
+ >
|
|
|
+ <img v-if="imageUrl" :src="imageUrl" class="avatar" />
|
|
|
+ <LuPlus v-if="!imageUrl" size="18px" class="avatar-uploader-icon" />
|
|
|
+ </el-upload>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ <template #footer>
|
|
|
+ <el-button type="primary" @click="onSubmit">{{ $t('confirm') }}</el-button>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup lang="ts">
|
|
|
+import { ref, onBeforeUnmount } from 'vue'
|
|
|
+import { useEventBus } from '@vueuse/core'
|
|
|
+import { snapdom } from '@zumer/snapdom'
|
|
|
+import { addIDBData } from '@/utils/database'
|
|
|
+import { useProjectStore } from '@/store/modules/project'
|
|
|
+import { ElMessage } from 'element-plus'
|
|
|
+import { v4 } from 'uuid'
|
|
|
+
|
|
|
+import { LuPlus } from 'vue-icons-plus/lu'
|
|
|
+
|
|
|
+import { type UploadProps, type UploadRequestOptions, type FormInstance, dayjs } from 'element-plus'
|
|
|
+import { ICustomWidget } from '@/types'
|
|
|
+import { klona } from 'klona'
|
|
|
+
|
|
|
+const show = ref(false)
|
|
|
+const imageUrl = ref('')
|
|
|
+const form = ref<FormInstance>()
|
|
|
+const createCustomCompBus = useEventBus('create-custom-comp')
|
|
|
+const addedCustomCompBus = useEventBus('created-custom-comp')
|
|
|
+const projectStore = useProjectStore()
|
|
|
+
|
|
|
+const formData = ref<{
|
|
|
+ id: string
|
|
|
+ name: string
|
|
|
+ description?: string
|
|
|
+ iconFile: File | Blob | null
|
|
|
+}>({
|
|
|
+ id: '',
|
|
|
+ name: '',
|
|
|
+ description: '',
|
|
|
+ iconFile: null
|
|
|
+})
|
|
|
+
|
|
|
+const rules = {
|
|
|
+ name: [{ required: true, message: '请输入组件名称', trigger: 'blur' }],
|
|
|
+ iconFile: [{ required: true, message: '请选择图标文件', trigger: 'change' }]
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 创建自定义组件
|
|
|
+ */
|
|
|
+const unsubscribe = createCustomCompBus.on(async (_e, id) => {
|
|
|
+ show.value = true
|
|
|
+ formData.value.id = id
|
|
|
+
|
|
|
+ // 获取元素图片
|
|
|
+ const el = document.querySelector('[widget-id="' + id + '"]')
|
|
|
+ if (el) {
|
|
|
+ const blob = await snapdom.toBlob(el, {
|
|
|
+ exclude: ['.moveable-control-box'],
|
|
|
+ outerTransforms: false
|
|
|
+ })
|
|
|
+ imageUrl.value = URL.createObjectURL(blob)
|
|
|
+ formData.value.iconFile = blob
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
+const handleAvatarSuccess: UploadProps['onSuccess'] = (_, uploadFile) => {
|
|
|
+ imageUrl.value = URL.createObjectURL(uploadFile.raw!)
|
|
|
+}
|
|
|
+
|
|
|
+const handleUpload = async (options: UploadRequestOptions) => {
|
|
|
+ const { file, onSuccess } = options
|
|
|
+ formData.value.iconFile = file
|
|
|
+ onSuccess({ code: 200, message: '上传成功' } as any)
|
|
|
+}
|
|
|
+
|
|
|
+onBeforeUnmount(() => {
|
|
|
+ unsubscribe()
|
|
|
+})
|
|
|
+
|
|
|
+const onSubmit = () => {
|
|
|
+ form.value?.validate().then(() => {
|
|
|
+ const widget = projectStore.getWidgetById(formData.value.id)
|
|
|
+ if (widget) {
|
|
|
+ // todo:处理widget数据
|
|
|
+ const newComponent: ICustomWidget = {
|
|
|
+ name: formData.value.name,
|
|
|
+ description: formData.value.description,
|
|
|
+ iconFile: formData.value.iconFile,
|
|
|
+ widget: widget,
|
|
|
+ createBy: dayjs().format('YYYY-MM-DD HH:mm:ss'),
|
|
|
+ order: 0
|
|
|
+ }
|
|
|
+ addIDBData(v4(), klona(newComponent))
|
|
|
+ form.value?.resetFields()
|
|
|
+ ElMessage.success('添加成功')
|
|
|
+ show.value = false
|
|
|
+ addedCustomCompBus.emit()
|
|
|
+ }
|
|
|
+ })
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="less" scoped>
|
|
|
+.avatar-uploader .el-upload {
|
|
|
+ width: 178px;
|
|
|
+ height: 178px;
|
|
|
+ border: 1px dashed #eee;
|
|
|
+ border-radius: 6px;
|
|
|
+ cursor: pointer;
|
|
|
+ position: relative;
|
|
|
+ overflow: hidden;
|
|
|
+ transition: var(--el-transition-duration-fast);
|
|
|
+}
|
|
|
+.avatar {
|
|
|
+ width: 178px;
|
|
|
+ height: 178px;
|
|
|
+}
|
|
|
+</style>
|