|
|
@@ -0,0 +1,304 @@
|
|
|
+<template>
|
|
|
+ <vxe-modal v-model="dialogVisible" :title="title" show-zoom resize show-footer destroy-on-close transfer
|
|
|
+ @hide="close" :width="1200" :z-index="1002">
|
|
|
+ <div class="p-3">
|
|
|
+ <div class="bg-fff flex1 ov-hd d-flex flex-cln">
|
|
|
+ <div class="d-flex a-c pd-16 border-bottom">
|
|
|
+ <div class="f-s-20 c-333 f-w-7 mr-10">编辑报名需收集信息</div>
|
|
|
+ </div>
|
|
|
+ <div class="flex1 over-auto d-flex">
|
|
|
+ <div class="w-300 ">
|
|
|
+ <div class="pd-10 f-s-18 c-333 f-w-7 mr-10"><span class="c-primary pd-10">|</span>常用信息</div>
|
|
|
+ <div class="pd-10 f-s-16">个人信息</div>
|
|
|
+ <div class="pl-10 d-flex f-w-w">
|
|
|
+ <div class="pl-10 d-flex f-w-w">
|
|
|
+ <el-button class="mb-25 ml-10 w-80" @click="addCustoms({
|
|
|
+ name: `id-${generateSecureRandomString()}`,
|
|
|
+ label: '身份证', type: '1', required: '0', readonly: '0',
|
|
|
+ pattern: '^[1-9]\d{5}(18|19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dXx]$'
|
|
|
+ })">身份证</el-button>
|
|
|
+ <el-button class="mb-25 w-80" @click="addCustoms({
|
|
|
+ name: `birth-${generateSecureRandomString()}`, readonly: '0', required: '0',
|
|
|
+ label: '出生日期', type: '3'
|
|
|
+ })">出生日期</el-button>
|
|
|
+ <el-button class="mb-25 w-80" @click="addCustoms({
|
|
|
+ name: `sex-${generateSecureRandomString()}`,
|
|
|
+ label: '性别', type: '4', required: '0', readonly: '0',
|
|
|
+ options: [
|
|
|
+ { label: '男', value: '' }, { label: '女', value: '' }
|
|
|
+ ]
|
|
|
+ })">性别</el-button>
|
|
|
+ <el-button class="mb-25 w-80" @click="addCustoms({
|
|
|
+ name: `old-${generateSecureRandomString()}`, required: '0', readonly: '0',
|
|
|
+ label: '年龄', type: '1',
|
|
|
+ })">年龄</el-button>
|
|
|
+ <el-button class="mb-25 w-80" @click="addCustoms({
|
|
|
+ name: `edu-${generateSecureRandomString()}`, required: '0', readonly: '0',
|
|
|
+ label: '学历', type: '1',
|
|
|
+ })">学历</el-button>
|
|
|
+ <el-button class="mb-25 w-80" @click="addCustoms({
|
|
|
+ name: `uni-${generateSecureRandomString()}`, required: '0', readonly: '0',
|
|
|
+ label: '大学', type: '1',
|
|
|
+ })">大学</el-button>
|
|
|
+ <el-button class="mb-25 w-80" @click="addCustoms({
|
|
|
+ name: `pro-${generateSecureRandomString()}`, required: '0', readonly: '0',
|
|
|
+ label: '专业', type: '1',
|
|
|
+ })">专业</el-button>
|
|
|
+ <el-button class="mb-25 w-80" @click="addCustoms({
|
|
|
+ name: `ind-${generateSecureRandomString()}`, required: '0', readonly: '0',
|
|
|
+ label: '行业', type: '1',
|
|
|
+ })">行业</el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="pd-10 f-s-16">联系方式</div>
|
|
|
+ <div class="pl-10 d-flex f-w-w">
|
|
|
+ <el-button class="mb-25 ml-10 w-80" @click="addCustoms({
|
|
|
+ name: `wx-${generateSecureRandomString()}`, required: '0', readonly: '0',
|
|
|
+ label: '微信号', type: '1',
|
|
|
+ })">微信号</el-button>
|
|
|
+ <el-button class="mb-25 w-80" @click="addCustoms({
|
|
|
+ name: `qq-${generateSecureRandomString()}`, required: '0', readonly: '0',
|
|
|
+ label: 'QQ号', type: '1',
|
|
|
+ })">QQ号</el-button>
|
|
|
+ <el-button class="mb-25 w-80" @click="addCustoms({
|
|
|
+ name: `eml-${generateSecureRandomString()}`, required: '0', readonly: '0',
|
|
|
+ label: '邮箱', type: '1',
|
|
|
+ pattern: '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
|
|
|
+ })">邮箱</el-button>
|
|
|
+ <el-button class="mb-25 w-80" @click="addCustoms({
|
|
|
+ name: `add-${generateSecureRandomString()}`, required: '0', readonly: '0',
|
|
|
+ label: '地址', type: '1',
|
|
|
+ })">地址</el-button>
|
|
|
+ </div>
|
|
|
+ <div class="pd-10 f-s-16 c-333 f-w-7 mr-10"><span class="c-primary pd-10">|</span>自定义信息</div>
|
|
|
+ <div class="pd-10 f-s-16">选择</div>
|
|
|
+ <div class="pl-10 d-flex f-w-w">
|
|
|
+ <el-button class="mb-25 ml-10 w-80" @click="addCustoms({
|
|
|
+ name: `rad-${generateSecureRandomString()}`, required: '0', readonly: '0',
|
|
|
+ label: '', type: '4', options: [
|
|
|
+ { label: '', value: '' }, { label: '', value: '' }, { label: '', value: '' }
|
|
|
+ ]
|
|
|
+ })">单选</el-button>
|
|
|
+ <el-button class="mb-25 w-80" @click="addCustoms({
|
|
|
+ name: `che-${generateSecureRandomString()}`, required: '0', readonly: '0',
|
|
|
+ label: '', type: '5', options: [
|
|
|
+ { label: '', value: '' }, { label: '', value: '' }, { label: '', value: '' }
|
|
|
+ ]
|
|
|
+ })">多选</el-button>
|
|
|
+ </div>
|
|
|
+ <div class="pd-10 f-s-16">文本输入</div>
|
|
|
+ <div class="pl-10 d-flex f-w-w">
|
|
|
+ <el-button class="mb-25 ml-10 w-80" @click="addCustoms({
|
|
|
+ name: `text1-${generateSecureRandomString()}`, type: '1', required: '0', readonly: '0',
|
|
|
+ })">单行文本</el-button>
|
|
|
+ <el-button class="mb-25 w-80" @click="addCustoms({
|
|
|
+ name: `text2-${generateSecureRandomString()}`, type: '7', required: '0', readonly: '0',
|
|
|
+ })">多行文本</el-button>
|
|
|
+ <el-button class="mb-25 w-80" @click="addCustoms({
|
|
|
+ name: `desc1-${generateSecureRandomString()}`, type: '10', readonly: '1', required: '0', label: '文本描述'
|
|
|
+ })">文本描述</el-button>
|
|
|
+ </div>
|
|
|
+ <div class="pd-10 f-s-16">其他</div>
|
|
|
+ <div class="pl-10 d-flex f-w-w">
|
|
|
+ <el-button class="mb-25 ml-10 w-80" @click="addCustoms({
|
|
|
+ name: `pic1-${generateSecureRandomString()}`, type: '8', required: '0', readonly: '0',
|
|
|
+ })">图片</el-button>
|
|
|
+ <el-button class="mb-25 w-80" @click="addCustoms({
|
|
|
+ name: `file1-${generateSecureRandomString()}`, type: '6', required: '0', readonly: '0',
|
|
|
+ })">文件</el-button>
|
|
|
+ <el-button class="mb-25 w-80" @click="addCustoms({
|
|
|
+ name: `pic2-${generateSecureRandomString()}`, type: '9', required: '0', readonly: '0',
|
|
|
+ })">图文描述</el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="w-300"></div>
|
|
|
+ <div class="w-400 h-700 border mt-100 over-auto">
|
|
|
+ <div class="pd-10 border bg-#fafafa">
|
|
|
+ <div class="pt-10 f-s-20 f-w-6 d-flex j-c a-c flex-cln ">
|
|
|
+ 报名信息
|
|
|
+ </div>
|
|
|
+ <div class="f-s-12 f-w-4 d-flex j-start c-#BBBBBB">此页面为意向人报名时所见页面:</div>
|
|
|
+ </div>
|
|
|
+ <template v-for="(item, index) in fixedField" :key="index">
|
|
|
+ <div class="pd-15 border1 c-#D7D7D7 d-flex j-sb">
|
|
|
+ <span>{{ item.label }}</span>
|
|
|
+ <span>(不可编辑)</span>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ <VueDraggable ref="el" v-model="fields">
|
|
|
+ <template v-for="(field, index) in fields" :key="index">
|
|
|
+ <div class="meeting-custom-wrapper" :class="{ 'active-border': activeField === field }"
|
|
|
+ @click="setActive(field)">
|
|
|
+ <MeetingCustom :field="field" ref="childRef" v-if="field" />
|
|
|
+ <el-button class="delete-btn" type="danger" text @click.stop="removeField(index)">
|
|
|
+ 删除
|
|
|
+ </el-button>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </VueDraggable>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="d-flex a-c j-c pd-16">
|
|
|
+ <el-button @click="cancel">取消</el-button>
|
|
|
+ <el-button @click="saveArray" type="primary">保存</el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </vxe-modal>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup name="lmmeeting-meeting-add" lang="ts">
|
|
|
+import { VueDraggable } from 'vue-draggable-plus'
|
|
|
+import { ref, reactive, onMounted, watch } from 'vue';
|
|
|
+import { debounce } from 'lodash';
|
|
|
+import { useRouter } from 'vue-router';
|
|
|
+// 需要添加以下导入
|
|
|
+import MeetingCustom from './meeting-custom.vue'
|
|
|
+import { propTypes } from '@/utils/propTypes';
|
|
|
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
|
|
+const { dm_training_join_type, yes_no, lm_training_cert, vip_level } = toRefs<any>(proxy?.useDict('dm_training_join_type', 'yes_no', 'lm_training_cert', 'vip_level'));
|
|
|
+import { FieldDefinition, FieldType } from './type'
|
|
|
+const props = defineProps<{
|
|
|
+ field?: any; // 使用 any 简化类型(实际应替换为具体类型,如 FieldDefinition)
|
|
|
+ show?: boolean; // 可选参数,默认 false
|
|
|
+ title?: string; // 可选参数,默认 ' '
|
|
|
+ width?: number; // 可选参数,默认 500
|
|
|
+ info?: any[]; // 可选参数,默认 []
|
|
|
+ dict?: Record<string, any>; // 可选参数,默认 {}
|
|
|
+}>();
|
|
|
+const dialogVisible = ref(false);
|
|
|
+const fields = ref<FieldDefinition[]>([])
|
|
|
+const activeField = ref<any>(null)
|
|
|
+const childRef = ref()
|
|
|
+const emit = defineEmits(['update:show', 'close', 'success', 'update:info']);
|
|
|
+const close = () => {
|
|
|
+ emit('update:show', false);
|
|
|
+ emit('close', false);
|
|
|
+};
|
|
|
+const setActive = (field: any) => {
|
|
|
+ activeField.value = field
|
|
|
+}
|
|
|
+const addCustoms = (value) => {
|
|
|
+ const newField = new FieldDefinition(value);
|
|
|
+ fields.value.push(newField);
|
|
|
+ activeField.value = newField; // 自动选中新增字段
|
|
|
+};
|
|
|
+function generateSecureRandomString(length = 8) {
|
|
|
+ const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
|
|
|
+ const randomValues = new Uint32Array(length);
|
|
|
+ window.crypto.getRandomValues(randomValues);
|
|
|
+ let result = '';
|
|
|
+ randomValues.forEach((value) => {
|
|
|
+ result += chars[value % chars.length];
|
|
|
+ });
|
|
|
+ return result;
|
|
|
+}
|
|
|
+
|
|
|
+const removeField = (index: number) => {
|
|
|
+ fields.value.splice(index, 1)
|
|
|
+ if (activeField.value === fields[index]) {
|
|
|
+ activeField.value = null
|
|
|
+ }
|
|
|
+}
|
|
|
+const router = useRouter();
|
|
|
+const route = useRoute();
|
|
|
+
|
|
|
+const rules = reactive({
|
|
|
+ // 自动生成全部
|
|
|
+ trainingName: [{ required: true, message: '请输入会议名称', trigger: 'blur' }],
|
|
|
+ trainingTime: [{ required: true, message: '请选择培训时间', trigger: 'blur' }],
|
|
|
+ joinType: [{ required: true, message: '请选择培训方式', trigger: 'change' }],
|
|
|
+ trainingLocation: [{ required: true, message: '请输入培训地点', trigger: 'blur' }],
|
|
|
+ certFlag: [{ required: true, message: '请选择是否颁发证书', trigger: 'change' }],
|
|
|
+ certificateInfo: [{ required: true, message: '请选择证书名称', trigger: 'change' }],
|
|
|
+ description: [{ required: true, message: '请输入培训详情', trigger: 'blur' }],
|
|
|
+ // coverImg: [{ required: true, message: '请上传封面图', trigger: 'change' }],
|
|
|
+ // trainingImg: [{ required: true, message: '请上传会议图', trigger: 'change' }],
|
|
|
+ contactName: [{ required: true, message: '请输入会议联系人', trigger: 'blur' }],
|
|
|
+ tel: [{ required: true, message: '请输入联系电话', trigger: 'blur' }],
|
|
|
+});
|
|
|
+const formRef = ref();
|
|
|
+const cancel = () => {
|
|
|
+ emit('update:show', false);
|
|
|
+ emit('close', false);
|
|
|
+}
|
|
|
+const saveArray = async () => {
|
|
|
+ try {
|
|
|
+ // 使用 Promise.all 等待所有验证完成
|
|
|
+ await Promise.all(
|
|
|
+ childRef.value.map((i) => i.validate())
|
|
|
+ );
|
|
|
+ // 所有验证完成后,存储数据并关闭
|
|
|
+ // localStorage.setItem('RegistrationInformation', JSON.stringify(fields.value));
|
|
|
+ // props.info = fields.value
|
|
|
+ emit('update:info', fields.value);
|
|
|
+ emit('update:show', false);
|
|
|
+ emit('close', false);
|
|
|
+ } catch (error) {
|
|
|
+ console.error('验证或保存失败:', error);
|
|
|
+
|
|
|
+ }
|
|
|
+};
|
|
|
+const fixedField = ref<FieldDefinition[]>([{
|
|
|
+ name: `ent-${generateSecureRandomString()}`,
|
|
|
+ label: '企业名称', type: '1',
|
|
|
+ required: '1', readonly: '0',
|
|
|
+}, {
|
|
|
+ name: `name-${generateSecureRandomString()}`,
|
|
|
+ label: '姓名', type: '1', readonly: '0',
|
|
|
+ required: '1'
|
|
|
+}, {
|
|
|
+ name: `pos-${generateSecureRandomString()}`,
|
|
|
+ label: '职务', type: '1', readonly: '0',
|
|
|
+ required: '1'
|
|
|
+}, {
|
|
|
+ name: `Con-${generateSecureRandomString()}`,
|
|
|
+ label: '联系方式', type: '1', readonly: '0',
|
|
|
+ required: '1'
|
|
|
+}])
|
|
|
+onMounted(() => {
|
|
|
+ // if (localStorage.getItem('RegistrationInformation')) {
|
|
|
+ // fields.value = JSON.parse(localStorage.getItem('RegistrationInformation'))
|
|
|
+ // } else { console.log(props, '00000');
|
|
|
+ // fields.value = props.info
|
|
|
+ // }
|
|
|
+ fields.value = props.info
|
|
|
+});
|
|
|
+watch(
|
|
|
+ () => props.show,
|
|
|
+ (val) => {
|
|
|
+ dialogVisible.value = val;
|
|
|
+ },
|
|
|
+ { immediate: true }
|
|
|
+);
|
|
|
+
|
|
|
+</script>
|
|
|
+<style scoped>
|
|
|
+.border {
|
|
|
+ border: 1px solid #f2f2f2;
|
|
|
+ border-radius: 6px;
|
|
|
+}
|
|
|
+
|
|
|
+.border1 {
|
|
|
+ border: 1px solid #f2f2f2;
|
|
|
+}
|
|
|
+
|
|
|
+.active-border {
|
|
|
+ border: 1px solid #b6e7d9;
|
|
|
+ border-radius: 4px;
|
|
|
+ box-shadow: 0px 0px 3px 0px #009932;
|
|
|
+}
|
|
|
+
|
|
|
+.meeting-custom-wrapper {
|
|
|
+ position: relative;
|
|
|
+ /* padding: 10px; */
|
|
|
+}
|
|
|
+
|
|
|
+.delete-btn {
|
|
|
+ position: absolute;
|
|
|
+ top: 5px;
|
|
|
+ right: 5px;
|
|
|
+ padding: 0 5px;
|
|
|
+ font-size: 12px;
|
|
|
+}
|
|
|
+</style>
|