Vue3表单拖拽

表单拖拽

<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')
      // router.push({ name: "configList" });
    };
    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)
      // router.push({ name: "configList" });
      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;
  /*margin: 0 auto;*/
  /*width: 30%;*/
  height: 60px;
}

.content {
  display: flex;
  justify-content: center;
  background-color: #eaeaea;
  height: calc(100% - 60px);
}

.tab-wrapper {
  left: 50%;
  transform: translateX(-50%);
}

.left {
  /* position: absolute;
  top: 50%;
  transform: translateY(-50%);
  left: 50px; */
  margin-right: 50px;
  transform: translateY(20%);
}

.second {
  width: 800px;
  /*height: 96%;*/
  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 {
  /*height: 289px;*/
  /*overflow-y: auto;*/
  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;
}

/*.scroll-wrapper::-webkit-scrollbar{*/
/*    display: none;*/
/*}*/
.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>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值