huangxw 4 månader sedan
förälder
incheckning
d4be281da6

+ 7 - 9
src/components/DragResizeRotate/DragResizeRotate.vue

@@ -30,11 +30,8 @@ const emit = defineEmits([
     'delete'
 ]);
 const drapJson = ref({
-    x: 0,
-    y: 0,
-    w: 100,
-    h: 100,
-    r: 0,
+     x: 0, y: 0, w: 100, h: 100,
+     r:0,
     ...prop.modelValue
 });
 const onActivated = () => {
@@ -46,18 +43,19 @@ const onDeactivated = () => {
 const onDrag = (left: number, top: number) => {
     emit('dragging', left, top);
 };
-const onDragStop = (left: number, top: number) => {
-    emit('update:modelValue', { ...drapJson.value, x: left, y: top });
-    emit('dragstop', left, top);
+const onDragStop = (x: number, y: number) => {
+    emit('update:modelValue', { ...drapJson.value, x, y });
+    emit('dragstop', x, y);
 };
 const onResize = (x: number, y: number, width: number, height: number) => {
     emit('resizing', x, y, width, height);
 };
 const onResizeStop = (x: number, y: number, width: number, height: number) => {
-    emit('update:modelValue', { ...drapJson.value, x, y, w: width, h: height });
+    emit('update:modelValue', { ...drapJson.value, x, y, w: width, h: height  });
     emit('resizestop', x, y, width, height);
 };
 const deleteItem = () => {
+    emit('deactivated');
     emit('delete')
 };
 watch(() => prop.modelValue, (newVal) => {

+ 3 - 1
src/views/training/models/index.ts

@@ -6,4 +6,6 @@ export { default as MeetingCustom } from './meeting-custom.vue'; // 查看签到
 export { default as registrationInfo } from './registration-info.vue'; 
 export { default as meetingCustomPreview } from './meeting-custom-preview.vue';
 export { default as MeetingTplH5 } from './meeting-tpl-h5.vue';
-export { default as MeetingTplList } from './meeting-tpl-list.vue';
+export { default as MeetingTplList } from './meeting-tpl-list.vue';
+export { default as MeetingTplEvents } from './meeting-tpl-events.vue';
+export { default as SelectMeetingTplPage } from './select-meeting-tpl-page.vue';

+ 107 - 0
src/views/training/models/meeting-tpl-events.vue

@@ -0,0 +1,107 @@
+<template>
+    <div class="pd-16">
+        <div class="f-s-16 c-333 f-w-6 mb-16">设置事件</div>
+        <el-form ref="enentFormRef" :model="form" label-position="left" :rules="rules" label-width="auto">
+            <el-form-item label="触发事件" prop="eventName">
+                <el-select v-model="form.eventName" @change="changeEventName" placeholder="请选择事件类型">
+                    <el-option v-for="item in page_event" :key="item.value" :label="item.label" :value="item.value"></el-option>
+                </el-select>
+            </el-form-item>
+            <template v-if="form.eventName === 'callEvent'">
+                <el-form-item label="电话号码" prop="params.phone">
+                    <el-input v-model="form.params.phone" placeholder="请输入电话号码"></el-input>
+                </el-form-item>
+            </template>
+            <template v-if="form.eventName === 'viewEvent'">
+                <el-form-item label="文件上传" prop="params.file" label-position="top">
+                    <FileUpload v-model="form.params.file" format="object" :fileSize="100"></FileUpload>
+                </el-form-item>
+            </template>
+            <template v-if="form.eventName === 'gotoEvent'">
+                <el-form-item label="页面" prop="params.pageId" label-position="top">
+                    <el-button v-if="!form.params.pageId" type="primary" @click="showSelectMeeting = true">选择页面</el-button>
+                    <div v-if="form.params.pageId" class="pt-10">
+                        <div class="w-160 p-rtv">
+                            <div class="delete-icon-tpl c-s-p c-danger f-s-20" @click="form.params.pageId = null; selectPageInfo = null;">
+                                <el-icon><CircleCloseFilled /></el-icon>
+                            </div>
+                            <div class="h-180 bg-#ccc bg-img-item_view" :style="{ backgroundImage: 'url('+ selectPageInfo?.img +')' }"></div>
+                            <div class="f-s-14 pd2-10-0 btm-text">{{ selectPageInfo?.label }}</div>
+                        </div>
+                    </div>
+                </el-form-item>
+            </template>
+            <el-form-item>
+                <div class="flex1 d-flex j-ed pt-40">
+                    <el-button>清除</el-button>
+                    <el-button @click="save" type="primary">保存</el-button>
+                </div>
+            </el-form-item>
+        </el-form>
+    </div>
+    <SelectMeetingTplPage v-model:show="showSelectMeeting" :list="list" :pageId="form.params.pageId" @success="selectSuccess"></SelectMeetingTplPage>
+</template>
+<script setup lang="ts">
+import { SelectMeetingTplPage } from '.';
+
+const props = defineProps<{
+    modelValue: any,
+    dict: any,
+    list: any[]
+}>();
+const { page_event } = toRefs<any>(props.dict)
+const enentFormRef = ref<any>(null);
+const showSelectMeeting = ref(false);
+const emit = defineEmits<{
+    (e: 'update:modelValue', value: any): void
+    (e: 'save', value: any): void
+}>();
+const rules = ref<any>({
+    eventName: [
+        { required: true, message: '请选择触发事件', trigger: 'change' },
+    ],
+    'params.phone': [
+        { required: true, message: '请输入电话号码', trigger: 'blur' },
+        { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的电话号码', trigger: 'blur' }
+    ],
+    'params.url': [
+        { required: true, message: '请输入跳转链接', trigger: 'blur' },
+        { type: 'url', message: '请输入正确的链接地址', trigger: 'blur' }
+    ]
+})
+const form = ref<any>(props.modelValue || {});
+const save = () => {
+    emit('update:modelValue', form.value);
+    emit('save', form.value);
+};
+const selectPageInfo = ref<any>(null);
+const selectSuccess = (pageId: string) => {
+    form.value.params.pageId = pageId;
+    // 找到对应的页面信息
+    const page = props.list.find(item => item.id === pageId);
+    selectPageInfo.value = page || null;
+};
+const changeEventName = (val: string) => {
+    form.value.params = {};
+};
+watch(() => props.modelValue, (val) => {
+    form.value = val || {};
+}, { deep: true });
+</script>
+<style lang="scss" scoped>
+.bg-img-item_view {
+    background-size: cover;
+    background-position: center;
+    border: 1px solid transparent;
+}
+.delete-icon-tpl {
+    position: absolute;
+    top: -10px;
+    right: -10px;
+    width: 24px;
+    height: 24px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+}
+</style>

+ 36 - 17
src/views/training/models/meeting-tpl-h5.vue

@@ -3,7 +3,7 @@
         <div class="flex1" style="overflow: auto;">
             <TelViewTem @selectArea="selectArea" :enableDraw="enableDraw" bgColor="#f7f7f7" :bgSrc="form.img">
                 <template v-for="(item, index) in form?.events" :key="index">
-                    <DragResizeRotate v-model="form.events[index]" @delete="deleteItemEvents($event, index)" @activated="activated" @deactivated="deactivated"></DragResizeRotate>
+                    <DragResizeRotate v-model="form.events[index]" @delete="deleteItemEvents($event, index, item)" @activated="activated($event, index)" @deactivated="deactivated"></DragResizeRotate>
                 </template>
             </TelViewTem>
         </div>
@@ -16,42 +16,61 @@
 </template>
 <script setup lang="ts">
 import { importFileGetUrls } from '@/utils/models';
-
+const emit = defineEmits<{
+    (e: 'update:modelValue', value: any): void,
+    (e: 'activated', value: any): void
+    (e: 'deactivated'): void
+    (e: 'deleteItemEvents', value: any): void
+}>();
 const props = defineProps<{
     modelValue: any
 }>();
-const form = ref<any>(props.modelValue || { img: '', events: []});
+const eventDefault = {
+    id: '',
+    eventName: '',
+    params: {
+        phone: '',
+        url: '',
+    },
+    x: 0,
+    y: 0,
+    w: 100,
+    h: 100,
+};
+const form = ref<any>(props.modelValue || { img: '', events: [] });
 const enableDraw = ref(true);
-const addInfo = () => {
-    form.value.events.push({ id: new Date().getTime() + '_btn_drap' });
-}
+
 const selectArea = (area: any) => {
     if (area.rect.w < 20 || area.rect.h < 20) {
         return;
     }
-    form.value.events.push({ id: new Date().getTime() + '_btn_drap', ...area.rect });
+    form.value.events.push({ ...eventDefault, id: new Date().getTime() + '_btn_drap', ...area.rect });
 }
-const activated = () => {
+const activated = (event, index) => {
     enableDraw.value = false;
+    emit('activated', form.value.events[index] || { id: '' });
 }
 const deactivated = () => {
     enableDraw.value = true;
+    emit('deactivated');
 }
-const deleteItemEvents = (item: any, index: number) => {
+const deleteItemEvents = (event: any, index: number, item: any) => {
     form.value.events.splice(index, 1);
+    emit('deleteItemEvents', item);
+    emit('update:modelValue', form.value);
 }
 const clickInfo = () => {
     console.log(form.value);
 }
 const addImgBg = async () => {
-  const res: any[] = await importFileGetUrls(['png', 'jpg', 'jpeg'], false);
-  if (res.length) {
-     res.forEach(element => {
-        if (element.data?.url) {
-            form.value.img = element.data.url;
-        }
-     });
-  }
+    const res: any[] = await importFileGetUrls(['png', 'jpg', 'jpeg'], false);
+    if (res.length) {
+        res.forEach(element => {
+            if (element.data?.url) {
+                form.value.img = element.data.url;
+            }
+        });
+    }
 }
 </script>
 <style scoped lang="scss"></style>

+ 7 - 32
src/views/training/models/meeting-tpl-list.vue

@@ -13,7 +13,7 @@
             </div>
         </template>
         <div class="pd-16 d-flex a-c j-c">
-            <el-button @click.stop="addMeetingTpl" plain type="primary">
+            <el-button @click.stop="addMeetingTpls" plain type="primary">
                 <el-icon><Plus /></el-icon>
                 添加页面
             </el-button>
@@ -23,48 +23,23 @@
 <script setup lang="ts">
 import { httpRequests } from '@/utils/httpRequests';
 const emit = defineEmits<{
-    (e: 'selectItem', value: any): void
+    (e: 'selectItem', value: any): void,
+    (e: 'addMeetingTpls'): void
 }>();
 const props = defineProps<{
-    meetid: string
+    meetid: string,
+    list: any[]
 }>()
 const queryParams = ref<any>({
     pageNum: 1,
     pageSize: 10,
 });
-const loading = ref(false);
-const total = ref(0);
-const list = ref<any>([]);
-const itemsData = ref<any>([]);
-const getList = async () => {
-    loading.value = true;
-    const res: any = await httpRequests.get(`/dgtmedicine/trainpage/listByTrainId/${props.meetid}`,);
-    if (!res || res.code !== 200) return;
-    list.value = res.data;
-    total.value = res.total;
-    loading.value = false;
-    if (list.value.length) {
-        emit('selectItem', list.value[0] || { img: '', events: [] });
-        return;
-    }
+const addMeetingTpls = async () => {
+   emit('addMeetingTpls');
 };
-const handleQuery = () => {
-    queryParams.value.pageNum = 1;
-    getList();
-};
-const addMeetingTpl = async () => {
-    const res: any = await httpRequests.post(`/dgtmedicine/trainpage/add`, {
-        trainId: props.meetid,
-        label: '页面名称',
-    });
-    if (!res || res.code !== 200) return;
-}
 const clickItem = (item: any) => {
     emit('selectItem', item);
 };
-onMounted(() => {
-    handleQuery();
-});
 </script>
 <style scoped lang="scss">
 .item-hover:hover {

+ 102 - 0
src/views/training/models/select-meeting-tpl-page.vue

@@ -0,0 +1,102 @@
+<template>
+    <vxe-modal v-model="dialogVisible" :title="title" show-zoom resize show-footer destroy-on-close transfer @hide="close" :width="width" :z-index="1002">
+        <div class="ov-hd">
+            <el-row :gutter="30">
+                <template v-for="(item, index) in list" :key="index">
+                    <el-col :span="4">
+                        <div class="pd-10 w-160 c-s-p item-hover mb-30" @click="clickItem(item)" :class="{ checked: checkedid === item.id }">
+                            <div class="h-180 bg-#ccc bg-img-item_view" :style="{ backgroundImage: 'url('+ item?.img +')' }"></div>
+                            <div class="f-s-14 pd2-10-0 btm-text">{{ item?.label }}</div>
+                        </div>
+                    </el-col>
+                </template>
+            </el-row>
+        </div>
+        <template #footer>
+            <div class="d-flex a-c j-ed">
+                <el-button @click="cancel">取消</el-button>
+                <el-button @click="save" type="primary">保存</el-button>
+            </div>
+        </template>
+    </vxe-modal>
+</template>
+
+<script setup name="lmmeeting-meeting-add" lang="ts">
+import { cloneDeep } from 'lodash';
+import { onMounted, reactive, ref, watch } from 'vue';
+import { useRouter } from 'vue-router';
+// 需要添加以下导入
+import { propTypes } from '@/utils/propTypes';
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const props = defineProps({
+    show: propTypes.bool.def(false),
+    info: propTypes.array.def([]),
+    dict: propTypes.object.def({}),
+    width: propTypes.number.def(1100),
+    title: propTypes.string.def('选择跳转页面'),
+    list: propTypes.any.def([]),
+    pageId: propTypes.string.def('')
+});
+const dialogVisible = ref(false);
+const emit = defineEmits(['update:show', 'close', 'success', 'update:info']);
+const close = () => {
+    emit('update:show', false);
+    emit('close', false);
+};
+const checkedid = ref(props.pageId || '');
+const formRef = ref();
+const cancel = () => {
+    emit('update:show', false);
+    emit('close', false);
+};
+const save = () => {
+    console.log('----');
+    emit('success', checkedid.value);
+    emit('update:show', false);
+};
+const clickItem = (item: any) => {
+    checkedid.value = item.id || '';
+};
+onMounted(() => {});
+watch(
+    () => props.show,
+    (val) => {
+        dialogVisible.value = val;
+    },
+    { immediate: true }
+);
+watch(
+    () => props.pageId,
+    (val) => {
+        checkedid.value = val || '';
+    },
+    { immediate: true }
+);
+</script>
+<style scoped lang="scss">
+.bg-img-item_view {
+    background-size: cover;
+    background-position: center;
+    border: 1px solid transparent;
+}
+.item-hover {
+    cursor: pointer;
+    &:hover {
+        .bg-img-item_view {
+            border-color: var(--el-color-primary);
+        }
+        .btm-text {
+            color: var(--el-color-primary);
+        }
+    }
+    &.checked {
+        .bg-img-item_view {
+            border-color: var(--el-color-primary);
+        }
+        .btm-text {
+            font-weight: 600;
+            color: var(--el-color-primary);
+        }
+    }
+}
+</style>

+ 34 - 4
src/views/training/ptpl/edit/index.vue

@@ -17,26 +17,30 @@
             </div>
             <div class="flex1 ov-hd d-flex">
                 <div class="bg-#f8f8f8 w-200 box-sizing-border over-auto">
-                    <MeetingTplList v-if="meetid" :meetid="meetid" @selectItem="selectItem"></MeetingTplList>
+                    <MeetingTplList v-if="meetid" :meetid="meetid" @selectItem="selectItem" :list="list"></MeetingTplList>
                 </div>
                 <div class="flex1 ov-hd d-flex flex-cln a-c">
                     <div v-if="form.id" class="w-750 pd2-10-0 f-w-5">
                         页面名称
                         <el-icon><EditPen /></el-icon>
                     </div>
-                    <MeetingTplH5 v-if="form.id" v-model="form"></MeetingTplH5>
+                    <MeetingTplH5 v-if="form.id" v-model="form" @activated="activated" @deleteItemEvents="deleteItemEvents"></MeetingTplH5>
+                </div>
+                <div class="bg-#f8f8f8 w-240">
+                    <MeetingTplEvents v-if="curEvent" v-model="curEvent" :dict="dict" @save="saveEevent" :list="list"></MeetingTplEvents>
                 </div>
-                <div class="bg-#f8f8f8 w-240"></div>
             </div>
         </div>
     </div>
 </template>
 <script setup lang="ts" name="ptpl-edit-index">
 import router from '@/router';
-import { MeetingTplH5, MeetingTplList } from '../../models';
+import { MeetingTplH5, MeetingTplList, MeetingTplEvents } from '../../models';
 import { useRoute } from 'vue-router';
 import { httpRequests } from '@/utils/httpRequests';
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const dict = proxy?.useDict('page_event')
+const { page_event } = toRefs<any>(dict);
 // 获取地址栏参数
 const meetid = ref<string>('');
 const form = ref<any>({});
@@ -44,13 +48,39 @@ onMounted(() => {
     const route = useRoute();
     meetid.value = (route.query.meetid as string) || '';
 });
+const curEvent = ref<any>(null);
+const activated = (item: any) => {
+    curEvent.value = item;
+};
 const selectItem = (item: any) => {
     form.value = item;
 };
+const saveEevent = (item: any) => {
+    console.log(item);
+    if (!form.value?.events || !form.value?.events.length) return;
+    const index = form.value.events.findIndex((it: any) => it.id === item.id);
+    if (index === -1) return;
+    form.value.events[index] = item;
+};
+const deleteItemEvents = (item: any) => {
+    if (curEvent.value?.id === item.id) {
+        curEvent.value = null;
+    }
+};
 // 预览
 const previewTpl = async () => {
     const res: any = await httpRequests.post(`/dgtmedicine/trainpage/edit`, form.value);
     if (!res || res.code !== 200) return;
     console.log(res);
 };
+const list = ref<any>([]);
+const itemsData = ref<any>([]);
+const getList = async () => {
+    const res: any = await httpRequests.get(`/dgtmedicine/trainpage/listByTrainId/${meetid.value}`,);
+    if (!res || res.code !== 200) return;
+    list.value = res.data;
+};
+onMounted(() => {
+    getList();
+});
 </script>