| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424 |
- <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="bg-fff flex1 ov-hd d-flex flex-cln" style="height: 80vh">
- <div class="flex1 over-auto d-flex">
- <div class="w-300 ">
- <div class="info-title f-s-18 c-333 f-w-7">常用信息</div>
- <div class="pd-10 f-s-16">个人信息</div>
- <div>
- <el-button
- class="mb-18 ml-10 w-80"
- @click="addCustoms({
- name: `id-${generateSecureRandomString()}`,
- label: '身份证', type: '1', required: '1', 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-18 w-80"
- @click="addCustoms({
- name: `birth-${generateSecureRandomString()}`, readonly: '0', required: '1',
- label: '出生日期', type: '3'
- })"
- >
- 出生日期
- </el-button>
- <el-button
- class="mb-18 w-80"
- @click="addCustoms({
- name: `sex-${generateSecureRandomString()}`,
- label: '性别', type: '4', required: '1', readonly: '0',
- options: [
- { label: '男', value: '男' }, { label: '女', value: '女' }
- ]
- })"
- >
- 性别
- </el-button>
- <el-button
- class="mb-18 w-80"
- @click="addCustoms({
- name: `old-${generateSecureRandomString()}`, required: '1', readonly: '0',
- label: '年龄', type: '1',
- })"
- >
- 年龄
- </el-button>
- <el-button
- class="mb-18 w-80"
- @click="addCustoms({
- name: `edu-${generateSecureRandomString()}`, required: '1', readonly: '0',
- label: '学历', type: '1',
- })"
- >
- 学历
- </el-button>
- <el-button
- class="mb-18 w-80"
- @click="addCustoms({
- name: `uni-${generateSecureRandomString()}`, required: '1', readonly: '0',
- label: '大学', type: '1',
- })"
- >
- 大学
- </el-button>
- <el-button
- class="mb-18 w-80"
- @click="addCustoms({
- name: `pro-${generateSecureRandomString()}`, required: '1', readonly: '0',
- label: '专业', type: '1',
- })"
- >
- 专业
- </el-button>
- <el-button
- class="mb-18 w-80"
- @click="addCustoms({
- name: `ind-${generateSecureRandomString()}`, required: '1', readonly: '0',
- label: '行业', type: '1',
- })"
- >
- 行业
- </el-button>
- </div>
- <div class="pd-10 f-s-16">联系方式</div>
- <div>
- <el-button
- class="mb-18 ml-10 w-80"
- @click="addCustoms({
- name: `wx-${generateSecureRandomString()}`, required: '1', readonly: '0',
- label: '微信号', type: '1',
- })"
- >
- 微信号
- </el-button>
- <el-button
- class="mb-18 w-80"
- @click="addCustoms({
- name: `qq-${generateSecureRandomString()}`, required: '1', readonly: '0',
- label: 'QQ号', type: '1',
- })"
- >
- QQ号
- </el-button>
- <el-button
- class="mb-18 w-80"
- @click="addCustoms({
- name: `eml-${generateSecureRandomString()}`, required: '1', readonly: '0',
- label: '邮箱', type: '1',
- pattern: '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
- })"
- >
- 邮箱
- </el-button>
- <el-button
- class="mb-18 w-80"
- @click="addCustoms({
- name: `add-${generateSecureRandomString()}`, required: '1', readonly: '0',
- label: '地址', type: '1',
- })"
- >
- 地址
- </el-button>
- </div>
- <div class="info-title f-s-18 c-333 f-w-7">自定义信息</div>
- <div class="pd-10 f-s-16">选择</div>
- <div>
- <el-button
- class="mb-18 ml-10 w-80"
- @click="addCustoms({
- name: `rad-${generateSecureRandomString()}`, required: '1', readonly: '0',
- label: '请输入标题', type: '4', options: [
- { label: '选项一', value: '选项一' }, { label: '选项二', value: '选项二' }, { label: '选项三', value: '选项三' }
- ]
- })"
- >
- 单选
- </el-button>
- <el-button
- class="mb-18 w-80"
- @click="addCustoms({
- name: `che-${generateSecureRandomString()}`, required: '1', readonly: '0',
- label: '请输入标题', type: '5', options: [
- { label: '选项一', value: '选项一' }, { label: '选项二', value: '选项二' }, { label: '选项三', value: '选项三' }
- ]
- })"
- >
- 多选
- </el-button>
- </div>
- <div class="pd-10 f-s-16">文本输入</div>
- <div>
- <el-button
- class="mb-18 ml-10 w-80"
- @click="addCustoms({
- name: `text1-${generateSecureRandomString()}`, type: '1', required: '1', readonly: '0', label: '请输入标题',
- })"
- >
- 单行文本
- </el-button>
- <el-button
- class="mb-18 w-80"
- @click="addCustoms({
- name: `text2-${generateSecureRandomString()}`, type: '7', required: '1', readonly: '0', label: '请输入标题',
- })"
- >
- 多行文本
- </el-button>
- <el-button
- class="mb-18 w-80"
- @click="addCustoms({
- name: `desc1-${generateSecureRandomString()}`, type: '10', readonly: '1', required: '0', label: '文本描述', defValue: '请输入内容',
- })"
- >
- 文本描述
- </el-button>
- </div>
- <div class="pd-10 f-s-16">其他</div>
- <div>
- <el-button
- class="mb-18 ml-10 w-80"
- @click="addCustoms({
- name: `pic1-${generateSecureRandomString()}`, type: '8', required: '1', readonly: '0', label: '请输入标题'
- })"
- >
- 图片
- </el-button>
- <el-button
- class="mb-18 w-80"
- @click="addCustoms({
- name: `file1-${generateSecureRandomString()}`, type: '6', required: '1', readonly: '0', label: '请输入标题'
- })"
- >
- 文件
- </el-button>
- <el-button
- class="mb-18 w-80"
- @click="addCustoms({
- name: `pic2-${generateSecureRandomString()}`, type: '9', required: '0', readonly: '0', label: '请输入内容'
- })"
- >
- 图文描述
- </el-button>
- </div>
- </div>
- <div class="w-300"></div>
- <div class="w-400 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-red">此页面为意向人报名时所见页面:</div>
- </div>
- <template v-for="(item, index) in fixedField" :key="index">
- <div class="pd-15 border1 c-#D7D7D7 d-flex j-sb">
- <span class="c-#606266 f-s-16 f-w-6">{{ item.label }}</span>
- <span>(固定字段,不可编辑)</span>
- </div>
- </template>
- <VueDraggable ref="el" v-model="fields" handle=".drag-handle" :filter="'.no-drag'">
- <template v-for="(field, index) in fields" :key="index">
- <div class="meeting-custom-wrapper" :class="{ 'active-border': activeField === field }" @click="setActive(field)" :ref="el => setFieldRef(el, index)">
- <MeetingCustom :field="field" ref="childRef" v-if="field" />
- <img class="ml-10 delete-btn c-s-p" :src="shanchu" @click.stop="removeField(index)" />
- </div>
- </template>
- </VueDraggable>
- <div class="pd-15 border1 c-#D7D7D7 d-flex j-sb">
- <span class="c-#606266 f-s-16 f-w-6">备注</span>
- <span>(固定字段,不可编辑)</span>
- </div>
- </div>
- </div>
- </div>
- <template #footer>
- <div class="d-flex a-c j-c">
- <el-button @click="cancel">取消</el-button>
- <el-button @click="saveArray" type="primary">保存</el-button>
- </div>
- </template>
- </vxe-modal>
- </template>
- <script setup name="lmmeeting-meeting-add" lang="ts">
- import shanchu from '@/assets/images/shanchu.png';
- import { VueDraggable } from 'vue-draggable-plus';
- import { ref, reactive, onMounted, watch } from 'vue';
- import { useRouter } from 'vue-router';
- import { cloneDeep } from 'lodash';
- // 需要添加以下导入
- 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 } from './type';
- const props = defineProps({
- field: propTypes.any,
- show: propTypes.bool.def(false),
- info: propTypes.array.def([]),
- dict: propTypes.object.def({}),
- width: propTypes.number.def(1200),
- title: propTypes.string.def('编辑报名需收集信息')
- });
- 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 fieldRefs = ref([])
- // 设置字段引用
- const setFieldRef = (el, index) => {
- if (el) {
- fieldRefs.value[index] = el
- }
- }
- const addCustoms = async (value) => {
- const newField = new FieldDefinition(value)
- fields.value.push(newField)
- activeField.value = newField
- // 等待DOM更新
- await nextTick()
- // 获取新增字段的索引
- const newIndex = fields.value.length - 1
- // 滚动到新增字段位置
- if (fieldRefs.value[newIndex]) {
- fieldRefs.value[newIndex].scrollIntoView({
- behavior: 'smooth',
- block: 'nearest'
- })
- }
- }
- 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(() => {
- fields.value = cloneDeep(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: 15px;
- right: 5px;
- padding: 0 5px;
- font-size: 12px;
- }
- </style>
|