表单拖拽
<template>
<div class="box">
<a-spin :spinning="loading" style="height: 100vh">
<div class="header">
<div class="w-300">
<a-button type="primary" @click="back">返回</a-button>
</div>
<div class="tab">
<!-- <a-tabs
v-model:activeKey="activeKey"
style="position: absolute; bottom: -16px"
class="tab-wrapper"
>
<a-tab-pane
:key="item.id"
:tab="item.name"
:disabled="custom_components_data.length <= 0"
v-for="item in tabList"
></a-tab-pane>
</a-tabs> -->
</div>
<div class="w-300 flex justify-center">
<a-button class="mr-5" v-if="activeKey == 1 && !is_disabled_first_second" @click="previewSurvey">
<template #icon>
<span class="pr-2">
<img :src="$utils.staticPath + 'images/workNotice/servey/preview.svg'
" class="img-icon" />
</span>
</template>
<span>预览</span>
</a-button>
<a-button type="primary" :loading="loading" class="ml-5"
v-if="!['release', 'close', 'expire'].includes(survey_status)" :disabled="custom_components_data.length <= 0"
@click="publishSurvey">
<template #icon>
<span class="pr-2">
<img :src="$utils.staticPath + 'images/workNotice/servey/publish.svg'
" class="img-icon" />
</span>
</template>
<span>发布</span>
</a-button>
</div>
</div>
<!--第一步-->
<div class="content" v-show="activeKey == 1">
<div class="left">
<div class="group-wrapper" @mousedown="isDown = true" @mouseup="isDown = false">
<div class="group-name">组件</div>
<draggable @start="mouseDown" @end="mouseUp" class="dragArea list-group" :list="components_data"
:group="{ name: 'people', pull: 'clone', put: false }" :clone="cloneDog" @change="log" item-key="id">
<template #item="{ element }">
<div class="list-group-item">
<img :src="imgObj[element.type]" class="w-16 h-16 object-contain" />
<span class="ml-5">{{ element.name }}</span>
</div>
</template>
</draggable>
</div>
</div>
<div class="right">
<!--固定字段 问卷调查标题和描述 -->
<div class="title-component mx-5">
<input v-model="fix_data.name" placeholder="请输入收集名称" style="margin-top: 20px"
class="input-component text-18 text-black" />
<div class="mt-20 w-full flex justify-center pb-20">
<textarea class="fixed_textarea-component" v-model="fix_data.remarks" placeholder="这里是可以输入收集的描述"></textarea>
</div>
</div>
<!--动态添加拖拽区自定义组件 -->
<div id="draggable-area" @mouseup="isDown = false">
<draggable :class="isDown ? 'hover-border' : ''" class="dragArea list-group" :list="custom_components_data"
group="people" @change="log" :boundary="'#draggable-area'" item-key="id">
<template #item="{ element, index }">
<div class="draggable-item" @mouseover.stop="element.isShowActionBtn = index"
@mouseleave.stop="element.isShowActionBtn = -1">
<div v-if="element.type == 'radio'" class="radio-component px-30 py-20 relative">
<div class="flex justify-end" v-show="element.isShowActionBtn == index">
<div class="flex">
<div class="copy-btn" @click.stop="copyComponent(index, element)">
<CopyOutlined />
</div>
<div class="del-btn" @click.stop="delComponent(index)">
<DeleteOutlined />
</div>
</div>
</div>
<div class="item-group-title">
<div class="item-group-title-index">{{ index + 1 }}.</div>
<input type="text" placeholder="这里是单选题的标题文字描述信息" v-model="element.title"
class="sub-component-input" />
</div>
<div style="margin-left: 5%; padding: 5px" class="mt-10 scroll-wrapper">
<a-radio-group v-model:value="element.value" name="radioGroup" style="width: 90%">
<div class="flex items-center justify-between" v-for="(o, inx) in element.options" :key="inx"
@mouseover.stop="o.isShow = true" @mouseleave.stop="o.isShow = false">
<div class="sub-radio-component">
<a-radio :value="o.value" name="radio-item">
<input type="text" v-model="o.label" />
</a-radio>
</div>
<div class="ml-10 cursor-pointer" v-show="o.isShow && element.options.length > 1"
@click="delRadioOption(index, inx)">
<DeleteOutlined style="color: red" />
</div>
</div>
</a-radio-group>
<input v-if="element.is_other" v-model="element.is_other_value" style="margin-left: 5%"
class="input-border" />
</div>
<div class="component-action h-32" style="margin-left: 4%">
<div v-show="element.isShowActionBtn == index">
<a-button type="link" @click="addRadioOption(element.id)">
<template #icon>
<PlusOutlined />
</template>
添加选项
</a-button>
<!-- <a-checkbox v-model:checked="element.is_other"
@change="radioOtherCheckedChange($event, element.id)">
<span style="color: #1890ff">显示其他</span>
</a-checkbox> -->
</div>
<div class="flex items-center" v-show="element.isShowActionBtn == index">
<span>必填</span>
<a-switch style="transform: scale(0.8)" v-model:checked="element.require" />
</div>
</div>
</div>
<div v-if="element.type == 'checkbox'" class="checkbox-component px-30 py-20 relative">
<div class="flex justify-end" v-show="element.isShowActionBtn == index">
<div class="flex">
<div class="copy-btn" @click.stop="copyComponent(index, element)">
<CopyOutlined />
</div>
<div class="del-btn" @click.stop="delComponent(index)">
<DeleteOutlined />
</div>
</div>
</div>
<div class="item-group-title">
<div class="item-group-title-index">{{ index + 1 }}.</div>
<input placeholder="这里是多选题的标题文字描述信息" type="text" v-model="element.title"
class="sub-component-input" />
</div>
<div style="margin-left: 5%; padding: 5px" class="mt-10 scroll-wrapper">
<a-checkbox-group v-model:value="element.value" name="radioGroup" style="width: 90%">
<div class="flex items-center justify-between" v-for="(o, inx) in element.options" :key="inx"
@mouseover.stop="o.isShow = true" @mouseleave.stop="o.isShow = false">
<div class="sub-radio-component">
<a-checkbox :value="o.value" name="radio-item">
<input type="text" v-model="o.label" />
</a-checkbox>
</div>
<div class="ml-10 cursor-pointer" v-show="o.isShow"
@click="delCheckOption(index, inx, o.value)">
<DeleteOutlined style="color: red" />
</div>
</div>
</a-checkbox-group>
<input v-if="element.is_other" v-model="element.is_other_value" style="margin-left: 5%"
class="input-border" />
</div>
<div class="component-action h-32" style="margin-left: 4%">
<div v-show="element.isShowActionBtn == index">
<a-button type="link" @click="addRadioOption(element.id)">
<template #icon>
<PlusOutlined />
</template>
添加选项
</a-button>
<!-- <a-checkbox v-model:checked="element.is_other" @change="
radioOtherCheckedChange($event, element.id, 'radio')
">
<span style="color: #1890ff">显示其他</span>
</a-checkbox> -->
</div>
<div class="flex items-center" v-show="element.isShowActionBtn == index">
<span>必填</span>
<a-switch style="transform: scale(0.8)" v-model:checked="element.require" />
</div>
</div>
</div>
<div v-if="element.type == 'textarea'" class="textarea-component px-30 py-20 relative">
<div class="flex justify-end" v-show="element.isShowActionBtn == index">
<div class="flex">
<div class="copy-btn" @click.stop="copyComponent(index, element)">
<CopyOutlined />
</div>
<div class="del-btn" @click.stop="delComponent(index)">
<DeleteOutlined />
</div>
</div>
</div>
<div class="item-group-title">
<div class="item-group-title-index">{{ index + 1 }}.</div>
<input placeholder="这里是问答题的标题文字描述信息" type="text" v-model="element.title"
class="sub-component-input" />
</div>
<textarea class="main_textarea-component" v-model="element.value"></textarea>
<div class="flex justify-end items-center pr-20 mt-10" v-show="element.isShowActionBtn == index">
<span>必填</span>
<a-switch style="transform: scale(0.8)" v-model:checked="element.require" />
</div>
</div>
<div v-if="element.type == 'image'" class="image-component-upload px-30 py-20 relative">
<div class="flex justify-end" v-show="element.isShowActionBtn == index">
<div class="flex">
<div class="copy-btn" @click.stop="copyComponent(index, element)">
<CopyOutlined />
</div>
<div class="del-btn" @click.stop="delComponent(index)">
<DeleteOutlined />
</div>
</div>
</div>
<div class="item-group-title">
<div class="item-group-title-index">{{ index + 1 }}.</div>
<input placeholder="这里是图片的标题文字描述信息" type="text" v-model="element.title"
class="sub-component-input" />
</div>
<div class="image-component-wrapper mt-5">
<img :src="$utils.staticPath +
'images/workNotice/servey/upload.svg'
" class="camera" />
<div>请选择上传图片</div>
</div>
<div class="flex justify-between items-center pr-20 mt-20" v-show="element.isShowActionBtn == index">
<div>
<span class="mr-5">最大上传数</span>
<a-input-number id="inputNumber" v-model:value="element.max_count" :min="1" :max="10" />
</div>
<div>
<span>必填</span>
<a-switch style="transform: scale(0.8)" v-model:checked="element.require" />
</div>
</div>
</div>
<div v-if="element.type == 'file'" class="image-component-upload px-30 py-20 relative">
<div class="flex justify-end" v-show="element.isShowActionBtn == index">
<div class="flex">
<div class="copy-btn" @click.stop="copyComponent(index, element)">
<CopyOutlined />
</div>
<div class="del-btn" @click.stop="delComponent(index)">
<DeleteOutlined />
</div>
</div>
</div>
<div class="item-group-title">
<div class="item-group-title-index">{{ index + 1 }}.</div>
<input placeholder="这里是附件的标题文字描述信息" type="text" v-model="element.title"
class="sub-component-input" />
</div>
<div class="image-component-wrapper mt-5">
<img :src="$utils.staticPath +
'images/workNotice/servey/upload.svg'
" class="camera" />
<div>请选择上传文件</div>
</div>
<div class="flex justify-between items-center pr-20 mt-20" v-show="element.isShowActionBtn == index">
<div>
<span class="mr-5">最大上传数</span>
<a-input-number id="inputNumber" v-model:value="element.max_count" :min="1" :max="10" />
</div>
<div class="flex items-center">
<span class="mr-5">允许格式</span>
<a-checkbox-group v-model:value="element.allow_format" :options="element.options">
</a-checkbox-group>
</div>
<div>
<span>必填</span>
<a-switch style="transform: scale(0.8)" v-model:checked="element.require" />
</div>
</div>
</div>
<div v-if="element.type == 'rate'" class="textarea-component px-30 py-20 relative">
<div class="flex justify-end" v-show="element.isShowActionBtn == index">
<div class="flex">
<div class="copy-btn" @click.stop="copyComponent(index, element)">
<CopyOutlined />
</div>
<div class="del-btn" @click.stop="delComponent(index)">
<DeleteOutlined />
</div>
</div>
</div>
<div class="item-group-title">
<div class="item-group-title-index">{{ index + 1 }}.</div>
<input placeholder="这里是评分的标题文字描述信息" type="text" v-model="element.title"
class="sub-component-input" />
</div>
<div class="flex justify-center">
<a-rate v-model:value="element.value" />
</div>
<div class="flex justify-end items-center pr-20 mt-10" v-show="element.isShowActionBtn == index">
<span>必填</span>
<a-switch style="transform: scale(0.8)" v-model:checked="element.require" />
</div>
</div>
</div>
</template>
</draggable>
</div>
</div>
</div>
</a-spin>
<a-drawer title="预览" :width="500" :visible="visible" :body-style="{ height: 'calc(100% - 90px)', overflowY: 'auto' }"
@close="onClose" :keyboard="false" :destroyOnClose="true">
<section class="beauty-scroller-bar">
<div class="border-bottom py-30 mx-10">
<div class="flex justify-center font-bold text-18">
{{ fix_data.name }}
</div>
<div>
<pre>{{ fix_data.remarks ? fix_data.remarks : "暂无描述消息" }}</pre>
</div>
</div>
<previewComponent :list="custom_components_data"></previewComponent>
</section>
<div class="drawer-footer">
<a-button style="width: 100%" type="primary">提交</a-button>
</div>
</a-drawer>
</div>
</template>
<script>
import {
defineComponent,
reactive,
ref,
toRaw,
onMounted,
watch,
computed,
} from "vue";
import draggable from "vuedraggable";
import { v4 as uuid } from "uuid";
import { message, Rate } from "ant-design-vue";
import { Form } from "ant-design-vue";
import { ChooseOrgMember } from "bl-common-vue3";
import moment from "moment";
const useForm = Form.useForm;
import _ from "lodash";
import store from "@/store";
import previewComponent from "./previewComponent.vue";
import {
PlusOutlined,
DeleteOutlined,
DoubleRightOutlined,
CopyOutlined,
PartitionOutlined,
UserOutlined,
ExclamationCircleOutlined
} from "@ant-design/icons-vue";
import request from "@/common/utils/request";
import { useRoute, useRouter } from "vue-router";
import QrcodeVue from "qrcode.vue";
import defaultSetting from "@/common/utils/defaultSetting";
import utils from "@/common/utils/utils";
export default defineComponent({
name: "addQuestionSurvey",
components: {
QrcodeVue,
previewComponent,
UserOutlined,
PartitionOutlined,
CopyOutlined,
ChooseOrgMember,
DoubleRightOutlined,
draggable,
PlusOutlined,
DeleteOutlined,
"a-rate": Rate,
ExclamationCircleOutlined
},
props: {
queryParams: {
typeof: Object,
}
},
setup(props, { emit }) {
let imgObj = reactive({
image: utils.staticPath + "images/workNotice/servey/img.svg",
radio: utils.staticPath + "images/workNotice/servey/radio.svg",
textarea: utils.staticPath + "images/workNotice/servey/txt.svg",
file: utils.staticPath + "images/workNotice/servey/file.svg",
rate: utils.staticPath + "images/workNotice/servey/rate.svg",
checkbox: utils.staticPath + "images/workNotice/servey/checkbox.svg",
});
let isDown = ref(false);
let is_disabled_first_second = ref(false);
let qrCodeUrl = ref("");
let visible = ref(false);
const route = useRoute();
let loading = ref(false);
const router = useRouter();
let is_collapse = ref(true);
const radioStyle = reactive({
display: "block",
height: "30px",
lineHeight: "30px",
});
let fix_data = reactive({
name: "",
remarks: "",
status: 1
});
let components_data = reactive([
{
title: "",
name: "单选",
type: "radio",
id: uuid(),
max_count: 1,
require: false,
options: [{ value: uuid(), label: "选项1" }],
placeholder: "",
value: "",
remarks: "",
is_other: false,
is_other_name: "其他",
is_other_value: "",
allow_format: [],
},
{
title: "",
name: "多选",
type: "checkbox",
id: uuid(),
max_count: 1,
require: false,
options: [{ value: uuid(), label: "选项1" }],
placeholder: "",
value: [],
remarks: "",
is_other: false,
is_other_name: "其他",
is_other_value: "",
allow_format: [],
},
{
title: "",
name: "文本",
type: "textarea",
id: uuid(),
max_count: 1,
require: false,
placeholder: "",
value: "",
remarks: "",
options: [],
is_other: false,
is_other_name: "其他",
is_other_value: "",
allow_format: [],
},
{
title: "",
name: "图片",
type: "image",
id: uuid(),
max_count: 1,
require: false,
placeholder: "",
value: [],
remarks: "",
options: [],
is_other: false,
is_other_name: "其他",
is_other_value: "",
allow_format: [],
},
{
title: "",
name: "附件",
type: "file",
id: uuid(),
max_count: 1,
require: false,
placeholder: "",
value: [],
remarks: "",
options: [
{ value: "zip", label: "压缩文件" },
{ value: "txt", label: "文档" },
{ value: "table", label: "表格" },
],
is_other: false,
is_other_name: "其他",
is_other_value: "",
allow_format: ["zip", "txt", "table"],
},
{
title: "",
name: "评分",
type: "rate",
id: uuid(),
max_count: 1,
require: false,
placeholder: "",
value: 1,
remarks: "",
options: [1, 2, 3, 4, 5],
is_other: false,
is_other_name: "其他",
is_other_value: "",
allow_format: [],
},
]);
let custom_components_data = ref([]);
let tabList = reactive([
{ id: 1, name: "设计问卷" },
{ id: 2, name: "问卷设置" },
{ id: 3, name: "数据统计" },
]);
let activeKey = ref(1);
const cloneDog = ({
id,
type,
name,
max_count,
require,
options,
placeholder,
value,
remarks,
title,
allow_format,
}) => {
return {
id: uuid(),
type,
name,
max_count,
require,
options: _.cloneDeep(options),
placeholder,
value: _.cloneDeep(value),
remarks,
title,
allow_format,
};
};
const log = () => { };
const addRadioOption = (id, arrLength) => {
let index = custom_components_data.value.findIndex(
(item) => item.id == id
);
let custom_components_data_item = custom_components_data.value[index];
let sub_index = custom_components_data_item.options.length;
if (custom_components_data_item.options[sub_index - 1].value == -1) {
custom_components_data_item.options.splice(sub_index - 1, 0, {
value: uuid(),
label: `选项${sub_index + 1}`,
});
} else {
custom_components_data_item.options.push({
value: uuid(),
label: `选项${sub_index + 1}`,
});
}
};
const delRadioOption = (fatherIndex, index) => {
if (
custom_components_data.value[fatherIndex].options[index].value == -1
) {
custom_components_data.value[fatherIndex].is_other = false;
custom_components_data.value[fatherIndex].is_other_value = "";
}
if (custom_components_data.value[fatherIndex].value == -1) {
custom_components_data.value[fatherIndex].value = "";
}
custom_components_data.value[fatherIndex].options.splice(index, 1);
};
const delCheckOption = (fatherIndex, index, value) => {
if (value == -1) {
custom_components_data.value[fatherIndex].is_other = false;
custom_components_data.value[fatherIndex].is_other_value = "";
if (custom_components_data.value[fatherIndex].value.includes(-1)) {
let ix = custom_components_data.value[fatherIndex].value.findIndex(
(item) => item == -1
);
if (ix != -1) {
custom_components_data.value[fatherIndex].value.splice(ix, 1);
}
}
}
custom_components_data.value[fatherIndex].options.splice(index, 1);
};
const radioOtherCheckedChange = (e, id, type = "radio") => {
let index = custom_components_data.value.findIndex(
(item) => item.id == id
);
let custom_components_data_item = custom_components_data.value[index];
if (e.target.checked) {
let length = custom_components_data_item.options.length;
custom_components_data_item.options.splice(length, 0, {
value: -1,
label: "其他",
});
} else {
let sub_index = custom_components_data_item.options.findIndex(
(item) => item.value == -1
);
custom_components_data_item.options.splice(sub_index, 1);
if (type == "radio") {
custom_components_data_item.value = "";
} else {
custom_components_data_item.value = [];
}
}
};
const copyComponent = (index, element) => {
let obj = _.cloneDeep(toRaw(element));
obj.id = uuid();
custom_components_data.value.splice(index + 1, 0, obj);
};
const delComponent = (index) => {
custom_components_data.value.splice(index, 1);
};
const addSurvey = async () => {
let params = {
...fix_data,
field_data: JSON.stringify(custom_components_data.value),
};
if (props.queryParams.id && props.queryParams.is_clone == 0) {
params.id = props.queryParams.id;
}
const res = props.queryParams.id ? await request.put("/org", "/collection/config", params) : await request.post("/org", "/collection/config", params);
};
const back = () => {
emit('closeModal')
};
const publishSurvey = async () => {
if (fix_data.name == '') {
return message.warn("请输入收集名称!");
}
if (custom_components_data.value.length == 0) {
return message.warn("请添加一个组件!");
}
loading.value = true;
await addSurvey();
message.success("发布成功");
emit('closeModal', true)
loading.value = false;
};
const getEditDetail = async (detail) => {
fix_data.name = detail.name
fix_data.remarks = detail.remarks
fix_data.status = detail.status
custom_components_data.value = JSON.parse(detail.field_data)
console.log(custom_components_data.value, ' custom_components_data')
if (props.queryParams.is_query) {
activeKey.value = 3
is_disabled_first_second.value = true
}
loading.value = false
}
const previewSurvey = () => {
visible.value = true;
};
const onClose = () => {
visible.value = false;
};
watch(
() => props.queryParams,
(newValue, oldValue) => {
console.log('props.queryParams', props.queryParams);
if (props.queryParams.id && props.queryParams.is_clone == 0) {
getEditDetail(props.queryParams);
}
},
{ deep: true, immediate: true }
);
const mouseDown = () => {
isDown.value = true;
};
const mouseUp = () => {
isDown.value = false;
};
return {
fileAction: request.BASE_URL + "/public/system/uploadFile",
tabList,
activeKey,
components_data,
custom_components_data,
fix_data,
radioStyle,
is_collapse,
loading,
visible,
qrCodeUrl,
is_disabled_first_second,
isDown,
imgObj,
cloneDog,
log,
addRadioOption,
delRadioOption,
radioOtherCheckedChange,
copyComponent,
delComponent,
back,
publishSurvey,
previewSurvey,
onClose,
mouseDown,
mouseUp,
delCheckOption,
};
},
});
</script>
<style>
.basic-layout {
padding: 0 !important;
}
</style>
<style scoped>
.box {
width: 100%;
height: 100%;
overflow: hidden;
background-color: #eaeaea;
}
.w-16 {
width: 16px;
}
.h-16 {
height: 16px;
}
.box /deep/ .ant-spin-nested-loading {
height: 100%;
}
/deep/ .ant-spin-container {
height: 100%;
}
.header {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
height: 60px;
box-sizing: border-box;
background-color: #fff;
padding: 0 40px;
}
.tab {
position: relative;
display: flex;
align-items: center;
height: 60px;
}
.content {
display: flex;
justify-content: center;
background-color: #eaeaea;
height: calc(100% - 60px);
}
.tab-wrapper {
left: 50%;
transform: translateX(-50%);
}
.left {
margin-right: 50px;
transform: translateY(20%);
}
.second {
width: 800px;
background-color: #fff;
margin-top: 10px;
}
.right {
margin-top: 10px;
width: 800px;
height: 96%;
overflow-y: auto;
padding-bottom: 10px;
}
.right::-webkit-scrollbar {
display: none;
}
.right::-webkit-scrollbar {
display: none;
}
.group-wrapper {
width: 120px;
height: 420px;
padding: 20px;
background-color: #fff;
text-align: center;
}
.group-name {
border-bottom: 1px dashed #eee;
margin-bottom: 20px;
padding: 10px;
font-weight: 600;
}
.list-group-item {
display: flex;
align-items: center;
background-color: #ebf3ff;
padding: 8px 10px;
margin: 10px 0;
border-radius: 3px;
border: 1px solid #7dc1ff;
cursor: pointer;
box-sizing: border-box;
}
.upload-image-component {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
min-height: 103px;
border-bottom: 1px dashed #eee;
background-color: #fff;
cursor: pointer;
}
.upload-image-component>span {
text-align: center;
}
.camera {
width: 50px;
height: 30px;
object-fit: contain;
}
.img-wrapper {
position: relative;
width: 780px;
height: 230px;
}
.preview-img {
width: 780px;
height: 230px;
object-fit: cover;
}
.img-mask {
display: flex;
align-items: center;
justify-content: center;
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
cursor: pointer;
}
.title-component {
display: flex;
flex-direction: column;
align-items: center;
min-height: 179px;
border-bottom: 1px dashed #eee;
background-color: #fff;
}
.input-component {
width: 60%;
height: 40px;
box-sizing: border-box;
flex-shrink: 0;
text-align: center;
box-sizing: border-box;
}
.input-component:hover {
border: 1px dashed #eaeaea;
}
.fixed_textarea-component {
width: 90%;
padding: 10px;
box-sizing: border-box;
}
.fixed_textarea-component:hover {
outline: 1px dashed #eaeaea;
}
input {
border: none;
outline: none;
background: none;
padding: 0;
margin: 0;
}
textarea {
border: none;
outline: none;
background: none;
padding: 0;
margin: 0;
}
.item-group-title {
display: flex;
align-items: center;
color: #666666;
}
.item-group-title-index {
width: 3%;
}
.sub-component-input {
width: 97%;
height: 30px;
box-sizing: border-box;
padding: 5px;
}
.sub-component-input:hover {
outline: 1px dashed #eaeaea;
}
.radio-component,
.textarea-component,
.checkbox-component {
box-sizing: border-box;
background-color: #fff;
}
.textarea-component {
height: 199px;
width: 100%;
}
.image-component-upload {
height: 215px;
width: 100%;
background-color: #fff;
}
.main_textarea-component {
height: 69px;
width: 90%;
margin-left: 6%;
box-sizing: border-box;
outline: 1px solid #eaeaea;
margin-top: 10px;
}
.sub-radio-component {
width: 100%;
padding: 5px;
}
.sub-radio-component:hover {
outline: 1px dashed #eaeaea;
}
.component-action {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 20px;
}
.input-border {
width: 80%;
outline: 1px solid #eaeaea;
padding: 5px;
height: 30px;
margin-top: 5px;
}
.draggable-item {
cursor: move;
margin: 1px 0px;
}
.draggable-item:hover {
outline: 1px dashed #1890ff;
}
.image-component-wrapper {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 90px;
box-sizing: border-box;
outline: 1px solid #eaeaea;
}
.ant-rate {
font-size: 35px;
}
.second-title {
border-bottom: 1px solid #eaeaea;
margin: 0 20px;
}
.second-content {
width: 800px;
margin: 0 auto;
overflow-y: auto;
overflow-x: hidden;
max-height: calc(100% - 70px);
}
.second-content::-webkit-scrollbar {
display: none;
}
.drop-wrapper::-webkit-scrollbar {
display: none;
}
.drop-wrapper::-webkit-scrollbar {
display: none;
}
.input-num-wrapper {
width: 60px;
}
.copy-btn {
position: absolute;
top: 0;
right: 20px;
display: flex;
justify-content: center;
align-items: center;
background-color: #1890ff;
width: 20px;
height: 20px;
color: #fff;
cursor: pointer;
}
.del-btn {
position: absolute;
top: 0;
right: 0;
display: flex;
justify-content: center;
align-items: center;
background-color: red;
width: 20px;
height: 20px;
color: #fff;
cursor: pointer;
}
.third-content {
height: calc(100% - 60px);
padding: 20px;
box-sizing: border-box;
}
.img-icon {
width: 18px;
height: 18px;
object-fit: contain;
}
.user-tag :deep(.ant-tag) {
border-radius: 20px !important;
padding: 0 12px 0 0 !important;
background: #f1f1f1;
border: none;
}
.border-bottom {
border-bottom: 1px dashed #eaeaea;
}
.preview-img1 {
width: 100%;
height: 120px;
object-fit: cover;
}
#draggable-area {
min-height: 50vh;
}
.dragArea,
.draggable-area {
min-height: 50vh;
}
.hover-border {
border: 1px dashed #1890ff;
}
.user-tip {
width: 800px;
margin: 10px auto;
display: flex;
justify-content: center;
align-items: center;
background-color: #fdf6ec;
color: #f5c563;
padding: 10px;
}
.relative {
position: relative;
}
.px-30 {
padding-left: 30px;
padding-right: 30px;
}
.py-20 {
padding-top: 20px;
padding-bottom: 20px;
}
.text-18 {
font-size: 18px;
}
.mt-20 {
margin-top: 20px;
}
.justify-center {
justify-content: center;
}
.w-full {
width: 100%;
}
.pb-20 {
padding-bottom: 20px;
}
.flex {
display: flex;
}
</style>
预览previewComponent
<template>
<div>
<template v-for="(item, index) in list" :key="index">
<div v-if="item.type == 'radio'" class="item">
<div class="item-title">
<span>{{ index + 1 }}.</span>
<span>{{ item.title }}</span>
</div>
<a-radio-group name="radioGroup" style="width: 90%">
<div class="flex items-center justify-between" v-for="(o, inx) in item.options" :key="inx">
<div class="sub-radio-component">
<a-radio :value="o.value" name="radio-item">
{{ o.label }}
</a-radio>
</div>
</div>
</a-radio-group>
</div>
<div v-if="item.type == 'checkbox'" class="item">
<div class="item-title">
<span>{{ index + 1 }}.</span>
<span>{{ item.title }}</span>
</div>
<a-checkbox-group name="radioGroup" style="width: 90%">
<div class="flex items-center justify-between" v-for="(o, inx) in item.options" :key="inx">
<div class="sub-radio-component">
<a-checkbox :value="o.value" name="radio-item">
{{ o.label }}
</a-checkbox>
</div>
</div>
</a-checkbox-group>
</div>
<div v-if="item.type == 'textarea'" class="item">
<div class="item-title">
<span>{{ index + 1 }}.</span>
<span>{{ item.title }}</span>
</div>
<a-textarea></a-textarea>
</div>
<div v-if="item.type == 'image'" class="item">
<div class="item-title">
<span>{{ index + 1 }}.</span>
<span>{{ item.title }}</span>
</div>
<div class="upload-img">
+
</div>
<div class="tipInfo">*上传图片</div>
</div>
<div v-if="item.type == 'file'" class="item">
<div class="item-title">
<span>{{ index + 1 }}.</span>
<span>{{ item.title }}</span>
</div>
<div class="upload-img">
+
</div>
<div class="tipInfo">*上传文件</div>
</div>
<div v-if="item.type == 'rate'" class="item">
<div class="item-title">
<span>{{ index + 1 }}.</span>
<span>{{ item.title }}</span>
</div>
<div class="flex justify-center">
<a-rate v-model:value="item.value" />
</div>
</div>
</template>
</div>
</template>
<script>
import { defineComponent, ref, watch } from "vue";
import { Rate } from 'ant-design-vue'
export default defineComponent({
name: "previewComponent",
components: { 'a-rate': Rate },
props: {
list: {
type: Array,
default: () => []
}
},
setup(props) {
let list_data = ref([])
watch(() => props.list, (newValue, oldValue) => {
console.log(newValue)
list_data.value = newValue
}, { immediate: true })
},
})
</script>
<style scoped>
.ant-rate {
font-size: 35px;
}
.item {
padding: 30px 0;
margin: 0 10px;
}
.item:not(:last-child) {
border-bottom: 1px dashed #eaeaea;
}
.item-title {
margin-bottom: 5px;
padding: 10px 0;
}
.upload-img {
display: flex;
justify-content: center;
align-items: center;
width: 100px;
height: 100px;
border: 1px solid #eaeaea;
font-size: 30px;
}
.tipInfo {
width: 100px;
text-align: center;
color: #999;
font-size: 12px;
margin-top: 6px;
}
</style>