|
@@ -3,390 +3,153 @@
|
|
|
<BackBtn />
|
|
|
|
|
|
<div class="venue-reservation-container">
|
|
|
- <div class="venue-reservation__title">场馆预约</div>
|
|
|
-
|
|
|
- <el-form
|
|
|
- ref="formRef"
|
|
|
- :rules="rules"
|
|
|
- :model="form"
|
|
|
- class="venue-reservation-form"
|
|
|
- >
|
|
|
- <el-form-item label="参观展馆">
|
|
|
- <div class="vr-ex-flex">
|
|
|
- <div
|
|
|
- v-for="item in MUSEUM_LIST"
|
|
|
- :key="item.id"
|
|
|
- :class="[
|
|
|
- 'vr-ex-flex__item',
|
|
|
- form.exhibitionName === item.name && 'active',
|
|
|
- ]"
|
|
|
- :style="{ backgroundImage: `url(${item.bg})` }"
|
|
|
- @click="handleExhibition(item)"
|
|
|
- >
|
|
|
- <span>{{ item.name }}</span>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item v-if="venues.length" label="选择场馆">
|
|
|
- <div class="vr-flex exhibition">
|
|
|
- <div
|
|
|
- v-for="str in venues"
|
|
|
- :key="str"
|
|
|
- :class="['vr-flex__item', str === form.venues && 'active']"
|
|
|
- @click="form.venues = str"
|
|
|
- >
|
|
|
- {{ str }}
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="所在单位" prop="organ">
|
|
|
- <div class="vr-input">
|
|
|
- <el-input v-model="form.organ" readonly placeholder="请输入内容" />
|
|
|
- </div>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="参观人员">
|
|
|
- <div class="vr-visitor">
|
|
|
- <div
|
|
|
- v-for="(item, index) in visitorList"
|
|
|
- :key="item.id"
|
|
|
- class="vr-visitor__item"
|
|
|
- >
|
|
|
- <div class="vr-input">
|
|
|
- <el-input
|
|
|
- v-model="item.name"
|
|
|
- placeholder="请输入姓名"
|
|
|
- @click="handleFocus"
|
|
|
- />
|
|
|
- </div>
|
|
|
- <div class="vr-input">
|
|
|
- <el-input
|
|
|
- v-model="item.phone"
|
|
|
- placeholder="请输入手机号"
|
|
|
- type="number"
|
|
|
- @click="handleFocus"
|
|
|
- />
|
|
|
- </div>
|
|
|
- <div class="vr-input">
|
|
|
- <el-input
|
|
|
- v-model="item.idcard"
|
|
|
- placeholder="请输入身份证号"
|
|
|
- @click="handleFocus"
|
|
|
- />
|
|
|
- </div>
|
|
|
-
|
|
|
- <div
|
|
|
- v-if="item.id !== 0"
|
|
|
- class="vr-visitor__del"
|
|
|
- @click="() => visitorList.splice(index, 1)"
|
|
|
- />
|
|
|
- </div>
|
|
|
-
|
|
|
- <div
|
|
|
- v-if="visitorList.length < 5"
|
|
|
- class="vr-visitor__add"
|
|
|
- @click="addVisitor"
|
|
|
- />
|
|
|
- </div>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="预约时间">
|
|
|
- <div class="vr-flex">
|
|
|
- <div
|
|
|
- v-for="item in dateList"
|
|
|
- :key="item.value"
|
|
|
- :class="[
|
|
|
- 'vr-flex__item',
|
|
|
- item.value === form.bookDay && 'active',
|
|
|
- item.disabled && 'disabled',
|
|
|
- ]"
|
|
|
- @click="!item.disabled && (form.bookDay = item.value)"
|
|
|
- >
|
|
|
- {{ item.label }}
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- <div
|
|
|
- :class="['vr-flex__item', bookDay === form.bookDay && 'active']"
|
|
|
- >
|
|
|
- <SvgIcon name="icon_date" />
|
|
|
- <el-date-picker
|
|
|
- v-model="bookDay"
|
|
|
- format="MM月DD日"
|
|
|
- placeholder="其他日期"
|
|
|
- value-format="YYYY-MM-DD"
|
|
|
- :clearable="false"
|
|
|
- :disabled-date="disabledDate"
|
|
|
- @focus="bookDay && (form.bookDay = bookDay)"
|
|
|
- @change="form.bookDay = bookDay"
|
|
|
- />
|
|
|
- </div> -->
|
|
|
+ <div class="venue-reservation__title">
|
|
|
+ {{ step === 0 ? "身份核验" : "场馆预约" }}
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div v-if="step === 1 && form1" class="ticket">
|
|
|
+ <p>{{ form1.organ }} - {{ form1.division }}</p>
|
|
|
+ <p>{{ form1.leader.name }} - {{ form1.leader.phone }}</p>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <Form1 v-if="step === 0" ref="form1Ref" :form-data="form1" />
|
|
|
+ <Form2 v-else-if="step === 1" ref="form2Ref" :form1-data="form1" />
|
|
|
+
|
|
|
+ <div class="venue-reservation__btns">
|
|
|
+ <div
|
|
|
+ v-if="step === 0"
|
|
|
+ class="venue-reservation__btns__next"
|
|
|
+ @click="next"
|
|
|
+ >
|
|
|
+ 下一步
|
|
|
+ </div>
|
|
|
+ <template v-else>
|
|
|
+ <div class="venue-reservation__btns__pre" @click="previous">
|
|
|
+ 上一步
|
|
|
</div>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="预约时段">
|
|
|
- <div class="vr-flex">
|
|
|
- <div
|
|
|
- v-for="str in timeAreaList"
|
|
|
- :key="str"
|
|
|
- :class="['vr-flex__item', str === form.bootTimeScope && 'active']"
|
|
|
- @click="form.bootTimeScope = str"
|
|
|
- >
|
|
|
- {{ str }}
|
|
|
- </div>
|
|
|
+ <div
|
|
|
+ :class="[
|
|
|
+ 'venue-reservation__btns__next',
|
|
|
+ form2Ref?.maxVisitorNum === 0 && 'disabled',
|
|
|
+ ]"
|
|
|
+ @click="next"
|
|
|
+ style="color: #fff3c9"
|
|
|
+ >
|
|
|
+ 提交
|
|
|
</div>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="备注">
|
|
|
- <div class="vr-input textarea">
|
|
|
- <el-input
|
|
|
- v-model="form.description"
|
|
|
- resize="none"
|
|
|
- :rows="3"
|
|
|
- :maxlength="200"
|
|
|
- type="textarea"
|
|
|
- placeholder="请输入备注"
|
|
|
- @click="handleFocus"
|
|
|
- />
|
|
|
- </div>
|
|
|
- </el-form-item>
|
|
|
- </el-form>
|
|
|
-
|
|
|
- <div class="vr-submit" @click="submit" />
|
|
|
+ </template>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
|
|
|
<Dialog v-model:visible="dialogVisible">
|
|
|
<p v-if="dialogErrType">请准确填写</p>
|
|
|
- <p>{{ dialogText }}</p>
|
|
|
+ <p v-html="dialogText"></p>
|
|
|
+ </Dialog>
|
|
|
+
|
|
|
+ <Dialog v-if="form1" v-model:visible="checkVisible" class="check-dialog">
|
|
|
+ <p class="title">请确认预约信息</p>
|
|
|
+ <div class="check-dialog__info">
|
|
|
+ <p>{{ form1.organ }} - {{ form1.division }}</p>
|
|
|
+ <p v-for="(item, index) in visitList" :key="index">
|
|
|
+ {{ item.name }} - {{ item.phone }} - {{ item.idcard }}
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="venue-reservation__btns">
|
|
|
+ <div class="venue-reservation__btns__pre" @click="checkVisible = false">
|
|
|
+ 取消
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ class="venue-reservation__btns__next"
|
|
|
+ style="color: #fff3c9"
|
|
|
+ @click="submit2"
|
|
|
+ >
|
|
|
+ 确认
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</Dialog>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script lang="ts" setup>
|
|
|
-import { getVenueNumApi, reservationVenueApi } from "@/api";
|
|
|
import { BackBtn } from "@/components";
|
|
|
-import { formatDate } from "@/utils";
|
|
|
import Dialog from "./components/dialog.vue";
|
|
|
-import { FormInstance, FormRules } from "element-plus";
|
|
|
-import { computed, onActivated, onMounted, reactive, ref, watch } from "vue";
|
|
|
-import NJImg from "./imgs/img_nanjing.jpg";
|
|
|
-import DYHImg from "./imgs/img_yangzhou.jpg";
|
|
|
-// import SZImg from "./imgs/img_suzhou.jpg";
|
|
|
-import limitJson from "/public/limit.json";
|
|
|
+import { onActivated, ref } from "vue";
|
|
|
import "./index.scss";
|
|
|
-import { OpenVirtualKeyBoard } from "@/utils/open-keyboard";
|
|
|
-
|
|
|
-type DateType = {
|
|
|
- label: string;
|
|
|
- value: string;
|
|
|
- week: number;
|
|
|
- disabled: boolean;
|
|
|
-};
|
|
|
-
|
|
|
-let visitorId = 0;
|
|
|
-const curExhibitionId = ref(0);
|
|
|
+import Form1 from "./form-1.vue";
|
|
|
+import Form2 from "./form-2.vue";
|
|
|
+import { reservationVenueApi } from "@/api";
|
|
|
+import { DEFAULT_FORM1 } from "./constants";
|
|
|
+import encodeStr from "@/utils/pass";
|
|
|
+import { cloneDeep } from "lodash";
|
|
|
+
|
|
|
+let saveParams: any = null;
|
|
|
+const step = ref(0);
|
|
|
+const checkVisible = ref(false);
|
|
|
const dialogVisible = ref(false);
|
|
|
const dialogText = ref("");
|
|
|
const dialogErrType = ref(false);
|
|
|
-const venues = computed(() => {
|
|
|
- const str = window.museum[curExhibitionId.value];
|
|
|
- return str ? str.split(",") : [];
|
|
|
-});
|
|
|
-const timeAreaList = computed(
|
|
|
- () => window.MUSEUM_LIST_TIME[curExhibitionId.value]
|
|
|
-);
|
|
|
-const DEFAULT_FORM = {
|
|
|
- bookDay: "",
|
|
|
- bootTimeScope: window.MUSEUM_LIST_TIME[1][0],
|
|
|
- description: "",
|
|
|
- organ: window.company,
|
|
|
- venues: "",
|
|
|
- exhibitionName: "",
|
|
|
-};
|
|
|
-const DEFAULT_VISITOR = {
|
|
|
- id: visitorId,
|
|
|
- name: "",
|
|
|
- idcard: "",
|
|
|
- phone: "",
|
|
|
-};
|
|
|
-const MUSEUM_LIST = [
|
|
|
- {
|
|
|
- id: 1,
|
|
|
- name: "南京博物院",
|
|
|
- bg: NJImg,
|
|
|
- },
|
|
|
- {
|
|
|
- id: 2,
|
|
|
- name: "扬州中国大运河博物馆",
|
|
|
- bg: DYHImg,
|
|
|
- },
|
|
|
- // {
|
|
|
- // id: 3,
|
|
|
- // name: "苏州博物馆",
|
|
|
- // bg: SZImg,
|
|
|
- // },
|
|
|
-];
|
|
|
-const visitorList = reactive<
|
|
|
- {
|
|
|
- id: number;
|
|
|
- name: string;
|
|
|
- idcard: string;
|
|
|
- phone: string;
|
|
|
- }[]
|
|
|
->([
|
|
|
- {
|
|
|
- ...DEFAULT_VISITOR,
|
|
|
- },
|
|
|
-]);
|
|
|
-const dateList = ref<DateType[]>([]);
|
|
|
-const bookDay = ref("");
|
|
|
-const form = reactive({ ...DEFAULT_FORM });
|
|
|
-const rules = reactive<FormRules>({
|
|
|
- organ: [{ required: true, message: "请填写单位", trigger: "blur" }],
|
|
|
-});
|
|
|
const loading = ref(false);
|
|
|
-const formRef = ref<FormInstance>();
|
|
|
-
|
|
|
-onMounted(() => {
|
|
|
- initDate();
|
|
|
-});
|
|
|
+const form1 = ref<typeof DEFAULT_FORM1 | null>(null);
|
|
|
+const visitList = ref<(typeof DEFAULT_FORM1)["leader"][]>([]);
|
|
|
+const form1Ref = ref();
|
|
|
+const form2Ref = ref();
|
|
|
|
|
|
onActivated(() => {
|
|
|
clear();
|
|
|
});
|
|
|
|
|
|
-watch(venues, (list) => {
|
|
|
- form.venues = list[0];
|
|
|
-});
|
|
|
-
|
|
|
-const handleFocus = () => {
|
|
|
- OpenVirtualKeyBoard();
|
|
|
-};
|
|
|
-
|
|
|
-const clear = () => {
|
|
|
- Object.assign(form, {
|
|
|
- ...DEFAULT_FORM,
|
|
|
- bookDay:
|
|
|
- dateList.value[0].week !== 1
|
|
|
- ? dateList.value[0].value
|
|
|
- : dateList.value[1].value,
|
|
|
- venues: venues.value[0],
|
|
|
- exhibitionName: MUSEUM_LIST[0].name,
|
|
|
- });
|
|
|
- bookDay.value = "";
|
|
|
- visitorList.length = 0;
|
|
|
- visitorList.push({ ...DEFAULT_VISITOR });
|
|
|
- curExhibitionId.value = MUSEUM_LIST[0].id;
|
|
|
-};
|
|
|
-
|
|
|
-// const disabledDate = (time: Date) => {
|
|
|
-// const today = new Date();
|
|
|
-// today.setDate(today.getDate() + 4);
|
|
|
-// return time.getTime() < today.getTime();
|
|
|
-// };
|
|
|
-
|
|
|
-const addVisitor = () => {
|
|
|
- visitorList.push({
|
|
|
- id: ++visitorId,
|
|
|
- name: "",
|
|
|
- idcard: "",
|
|
|
- phone: "",
|
|
|
- });
|
|
|
-};
|
|
|
-
|
|
|
-const initDate = () => {
|
|
|
- const stack: DateType[] = [];
|
|
|
- const today = new Date();
|
|
|
- const endDay = new Date();
|
|
|
- let isTomorro = true;
|
|
|
- endDay.setDate(today.getDate() + 6);
|
|
|
-
|
|
|
- if (!endDay) return;
|
|
|
-
|
|
|
- while (today.getTime() < endDay.getTime()) {
|
|
|
- today.setDate(today.getDate() + 1);
|
|
|
- const day = formatDate(today);
|
|
|
- const week = today.getDay();
|
|
|
- stack.push({
|
|
|
- value: day,
|
|
|
- label: `${isTomorro ? "明天" : ""}${formatDate(today, "MM月DD日")}`,
|
|
|
- disabled: week === 1,
|
|
|
- week,
|
|
|
- });
|
|
|
- isTomorro = false;
|
|
|
- }
|
|
|
- dateList.value = stack;
|
|
|
-};
|
|
|
-
|
|
|
-function checkTelephone(telephone: string) {
|
|
|
- var reg = /^[1][3,4,5,6,7,8,9][0-9]{9}$/;
|
|
|
- return reg.test(telephone);
|
|
|
-}
|
|
|
-
|
|
|
-function checkIdCard(idCard: string) {
|
|
|
- var reg = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/;
|
|
|
- return reg.test(idCard);
|
|
|
-}
|
|
|
-
|
|
|
-const submit = async () => {
|
|
|
- if (!form.bookDay && !bookDay.value) {
|
|
|
- dialogErrType.value = false;
|
|
|
- dialogText.value = "请选择预约时间";
|
|
|
- dialogVisible.value = true;
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if (!formRef.value || !(await formRef.value.validate())) return;
|
|
|
-
|
|
|
- for (let i = 0; i < visitorList.length; i++) {
|
|
|
- let errMsg = "";
|
|
|
- const item = visitorList[i];
|
|
|
-
|
|
|
- if (!item.name) {
|
|
|
- errMsg = `第${i + 1}个参观人员姓名`;
|
|
|
- } else if (!checkTelephone(item.phone)) {
|
|
|
- errMsg = `第${i + 1}个参观人员手机号`;
|
|
|
- } else if (!checkIdCard(item.idcard)) {
|
|
|
- errMsg = `第${i + 1}个参观人员身份证号`;
|
|
|
+const next = async () => {
|
|
|
+ try {
|
|
|
+ if (step.value === 0) {
|
|
|
+ const params = await form1Ref.value.next();
|
|
|
+ form1.value = params;
|
|
|
+ step.value += 1;
|
|
|
+ } else if (form2Ref.value?.maxVisitorNum > 0) {
|
|
|
+ const { visitorList, ...form2Rest } = await form2Ref.value.submit();
|
|
|
+ const { leader, ...form1Rest } = form1.value || {};
|
|
|
+ const list = [leader, ...visitorList];
|
|
|
+ visitList.value = visitorList;
|
|
|
+
|
|
|
+ saveParams = {
|
|
|
+ ...form1Rest,
|
|
|
+ ...form2Rest,
|
|
|
+ contact: list
|
|
|
+ .map(
|
|
|
+ (item: any) =>
|
|
|
+ `${item.name}-${item.phone}${
|
|
|
+ item.idcard ? "-" + encodeStr(item.idcard) : ""
|
|
|
+ }`
|
|
|
+ )
|
|
|
+ .join(","),
|
|
|
+ pcs: visitorList.length,
|
|
|
+ };
|
|
|
+
|
|
|
+ checkVisible.value = true;
|
|
|
}
|
|
|
-
|
|
|
- if (errMsg) {
|
|
|
+ } catch (err: any) {
|
|
|
+ if (typeof err === "object" && err.msg) {
|
|
|
dialogErrType.value = true;
|
|
|
- dialogText.value = errMsg;
|
|
|
+ dialogText.value = err.msg;
|
|
|
dialogVisible.value = true;
|
|
|
- return;
|
|
|
- } else {
|
|
|
- dialogErrType.value = false;
|
|
|
}
|
|
|
}
|
|
|
+};
|
|
|
|
|
|
- const params = {
|
|
|
- ...form,
|
|
|
- exhibitionName: `${form.exhibitionName}${
|
|
|
- form.venues ? "-" + form.venues : ""
|
|
|
- }`,
|
|
|
- contact: visitorList
|
|
|
- .map((item) => `${item.name}-${item.phone}-${item.idcard}`)
|
|
|
- .join(","),
|
|
|
- pcs: visitorList.length,
|
|
|
- };
|
|
|
+const clear = () => {
|
|
|
+ step.value = 0;
|
|
|
+ saveParams = null;
|
|
|
+ form1.value = cloneDeep(DEFAULT_FORM1);
|
|
|
+ visitList.value = [];
|
|
|
+};
|
|
|
|
|
|
- loading.value = true;
|
|
|
+const submit2 = async () => {
|
|
|
try {
|
|
|
- const { data } = await getVenueNumApi(params);
|
|
|
-
|
|
|
- console.log(
|
|
|
- (data ? data.pcs : 0) + visitorList.length,
|
|
|
- limitJson[params.organ][params.exhibitionName][params.bookDay]
|
|
|
- );
|
|
|
-
|
|
|
- if (
|
|
|
- (data ? data.pcs : 0) + visitorList.length >
|
|
|
- limitJson[params.organ][params.exhibitionName][params.bookDay]
|
|
|
- ) {
|
|
|
- dialogText.value = "已超出可预约人数上限";
|
|
|
- dialogVisible.value = true;
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- await reservationVenueApi(params);
|
|
|
-
|
|
|
- dialogText.value = "团队预约已接收!";
|
|
|
+ loading.value = true;
|
|
|
+ checkVisible.value = false;
|
|
|
+ await reservationVenueApi(saveParams);
|
|
|
+ dialogErrType.value = false;
|
|
|
+ dialogText.value = "预约已被接受<br/>请按照预约时间刷身份证原件入馆";
|
|
|
dialogVisible.value = true;
|
|
|
|
|
|
clear();
|
|
@@ -398,9 +161,7 @@ const submit = async () => {
|
|
|
}
|
|
|
};
|
|
|
|
|
|
-const handleExhibition = (item: (typeof MUSEUM_LIST)[0]) => {
|
|
|
- form.exhibitionName = item.name;
|
|
|
- curExhibitionId.value = item.id;
|
|
|
- form.bootTimeScope = timeAreaList.value[0];
|
|
|
+const previous = () => {
|
|
|
+ step.value -= 1;
|
|
|
};
|
|
|
</script>
|