c60c7a3c by 杨炀

Merge commit '421304e8' into dev

2 parents 6c5989a6 421304e8
<script setup>
import { ElMessage } from "element-plus";
import { addViewPeople } from "./api/index.js";
import { languageFormat } from "./utils/language.js";
import { useStorage } from "@vueuse/core/index";
const language = useStorage("language", 0);
const router = useRouter();
......@@ -9,21 +12,30 @@ const people = reactive({
name: "",
idCard: "",
},
type: "身份证",
type: language.value == 0 ? "身份证" : "Identity Card",
onConfirm() {
if (!people.form.name)
return ElMessage({ type: "warning", message: "请输入姓名" });
return ElMessage({
type: "warning",
message: languageFormat(language.value, "请输入姓名", "Name"),
});
if (!people.form.idCard)
return ElMessage({ type: "warning", message: "请输入证件号" });
return ElMessage({
type: "warning",
message: languageFormat(language.value, "请输入证件号", "ID Numbe"),
});
// 使用正则验证身份证号码格式
const idCardRegex =
/^[1-9]\d{5}(19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[\dXx]$/;
if (!idCardRegex.test(people.form.idCard))
if (!idCardRegex.test(people.form.idCard) && language.value == 0)
return ElMessage({ type: "warning", message: "身份证号格式不正确" });
addViewPeople(people.form).then((res) => {
ElMessage({ type: "success", message: "操作成功" });
ElMessage({
type: "success",
message: languageFormat(language.value, "操作成功", "Operate successfully"),
});
router.go(-2);
});
},
......@@ -32,19 +44,25 @@ const people = reactive({
<template>
<div class="container">
<div class="title">新增观影人</div>
<div class="title">
{{ languageFormat(language, "新增观影人", "Companion") }}
</div>
<div class="content">
<div class="form-item">
<div>
<div class="label">姓名</div>
<div class="label">
{{ languageFormat(language, "姓名", "Full Name") }}
</div>
<el-input
v-model="people.form.name"
style="width: 570px"
placeholder="请输入姓名"
:placeholder="language == 0 ? '请输入姓名' : 'Nama'"
/>
</div>
<div>
<div class="label">证件类型</div>
<div class="label">
{{ languageFormat(language, "证件类型", "Type of Document") }}
</div>
<el-input
v-model="people.type"
style="width: 570px"
......@@ -55,19 +73,25 @@ const people = reactive({
</div>
<div class="form-item">
<div>
<div class="label">身份证号</div>
<div class="label">
{{ languageFormat(language, "身份证号", "Identity Card") }}
</div>
<el-input
v-model="people.form.idCard"
style="width: 570px"
placeholder="请输入身份证号"
:placeholder="language == 0 ? '请输入身份证号' : 'ID Numbe'"
/>
</div>
</div>
</div>
<div class="footer">
<div class="can_pay">取消</div>
<div class="pay" @click="people.onConfirm()">确认</div>
<div class="can_pay">
{{ languageFormat(language, "取消", "Cancel") }}
</div>
<div class="pay" @click="people.onConfirm()">
{{ languageFormat(language, "确认", "Confirm") }}
</div>
</div>
</div>
</template>
......
......@@ -4,7 +4,9 @@ import { ElMessage } from "element-plus";
import { payOrder, viewPeopleList, checkPaySuccess } from "./api/index.js";
import qrCodeDialog from "./components/qrCodeDialog.vue";
import qrcode from "qrcode";
import { onUnmounted } from "vue";
import { languageFormat } from "./utils/language.js";
import { useStorage } from "@vueuse/core/index";
const language = useStorage("language", 0);
const route = useRoute();
const router = useRouter();
......@@ -22,7 +24,14 @@ const startCheckSuccessListener = (orderSn, actId) => {
timer = null;
// 支付成功
payment.showCodeDialog = false;
ElMessage({ type: "success", message: "支付成功" });
ElMessage({
type: "success",
message: anguageFormat(
language.value,
"支付成功",
"Payment succeeded"
),
});
router.replace({
path: "/seat/order",
});
......@@ -44,9 +53,23 @@ const payment = reactive({
qrCodeData: "",
paymentHandle() {
if (payment.form.viewers.length != order.data?.seatInfo?.length)
return ElMessage({ type: "warning", message: "观看人与购买票数不符" });
return ElMessage({
type: "warning",
message: languageFormat(
language.value,
"观看人与购买票数不符",
"The number of viewers does not match the number of tickets purchased."
),
});
if (!payment.form.phone)
return ElMessage({ type: "warning", message: "请输入联系人电话" });
return ElMessage({
type: "warning",
message: languageFormat(
language.value,
"请输入联系电话",
"Please enter the contact phone number."
),
});
payOrder({
contactPhone: payment.form.phone,
customerIds: payment.form.viewers,
......@@ -54,14 +77,18 @@ const payment = reactive({
payType: 1,
paymentAmount: order.data?.paymentAmount,
}).then((res) => {
payment.qrInfo = res.data;
qrcode.toDataURL(res.data.scanCodeUrl, (err, url) => {
if (url) {
payment.qrCodeData = url;
}
});
payment.showCodeDialog = true;
startCheckSuccessListener(res.data.orderSn, props.activityId);
if (res.data.language == "zh-cn") {
payment.qrInfo = res.data;
qrcode.toDataURL(res.data.scanCodeUrl, (err, url) => {
if (url) {
payment.qrCodeData = url;
}
});
payment.showCodeDialog = true;
startCheckSuccessListener(res.data.orderSn, props.activityId);
} else {
// TODO: 这里是PayPal支付
}
});
},
handleCloce() {
......@@ -98,8 +125,8 @@ const audience = reactive({
});
onUnmounted(() => {
clearInterval(timer)
})
clearInterval(timer);
});
audience.fetchData();
order.fetchData();
......@@ -107,7 +134,9 @@ order.fetchData();
<template>
<div class="container">
<div class="title">订单确认</div>
<div class="title">
{{ languageFormat(language, "订单确认", "Order confirmation") }}
</div>
<div class="content">
<div class="left">
<div class="info">
......@@ -118,19 +147,25 @@ order.fetchData();
<div class="ticket_info">
<div class="tit_box">
<div class="line"></div>
<div class="txt">订票信息</div>
<div class="txt">
{{ languageFormat(language, "订票信息", "Ticket Info") }}
</div>
</div>
<div class="form">
<el-form>
<el-form-item label="联系人">
<el-form-item :label="language == 0 ? '联系人' : 'contacts'">
<el-input
v-model="payment.form.phone"
placeholder="请输入联系人电话"
:placeholder="
language == 0
? '请输入联系电话'
: 'Please enter the contact phone number'
"
style="width: 260px"
/>
</el-form-item>
<el-form-item label="观看人">
<el-form-item :label="language == 0 ? '观看人' : 'contacts'">
<div class="p_box">
<div class="people">
<el-checkbox-group
......@@ -155,7 +190,7 @@ order.fetchData();
class="btn"
@click="$router.push({ path: '/seat/people_manage' })"
>
新增
{{ languageFormat(language, "新增", "Add") }}
</div>
</div>
</el-form-item>
......@@ -167,16 +202,19 @@ order.fetchData();
<div class="right">
<div class="tit_box">
<div class="line"></div>
<div class="txt">订单明细</div>
<div class="txt">
{{ languageFormat(language, "订单明细", "Order summary") }}
</div>
</div>
<div class="detail">
<div class="detail_top">
<div class="time">{{ order.data?.dateStr }}</div>
<div class="ticket">
{{ order.data?.singlePrice }}元票档 x{{
{{ order.data?.singlePrice }}<span v-if="language == 0"></span
>{{ languageFormat(language, "票档", "Ticket file") }} x{{
order.data?.seatInfo?.length
}}
}}{{ languageFormat(language, "张", "tickets") }}
</div>
</div>
<div class="detail_center">
......@@ -185,25 +223,35 @@ order.fetchData();
:key="index"
class="ticket"
>
<span v-if="it.venueId == 1">{{ it.area }}</span>
{{ it.pai }}{{ it.no }}座 ({{
<span v-if="it.venueId == 1"
>{{ it.area }}{{ languageFormat(language, "区", "Zones") }}
</span>
{{ it.pai }}{{ languageFormat(language, "排", "Row") }} {{ it.no
}}{{ languageFormat(language, "座", "Seat") }} ({{
it.venueId == 1 ? "B6" : "B4"
}})
}}{{ languageFormat(language, "馆", "Venue") }})
</div>
</div>
<div class="detail_b">
<div class="sum_txt">共计</div>
<div class="price_num">¥{{ order.data?.paymentAmount }}</div>
<div class="sum_txt">
{{ languageFormat(language, "共计", "Total") }}
</div>
<div class="price_num">
<span v-if="language == 1">¥</span>{{ order.data?.paymentAmount }}
</div>
</div>
</div>
</div>
</div>
<div class="footer">
<div>
<span class="label">共计金额:</span
<span class="label"
>{{ languageFormat(language, "共计金额", "Subtotal") }}</span
><span class="value">¥{{ order.data?.paymentAmount }}</span>
</div>
<div class="pay" @click="payment.paymentHandle()">立即支付</div>
<div class="pay" @click="payment.paymentHandle()">
{{ languageFormat(language, "立即支付", "Pay Now") }}
</div>
</div>
<el-dialog
......
......@@ -11,37 +11,46 @@ import qrCodeDialog from "./components/qrCodeDialog.vue";
import { ElMessageBox, ElMessage } from "element-plus";
import qrcode from "qrcode";
import { md5 } from "md5js";
import { languageFormat } from "./utils/language.js";
import { useStorage } from "@vueuse/core/index";
const language = useStorage("language", 0);
const userStore = useUserStore();
const status = reactive({
0: {
txt: "待支付",
text_en: "Pending Payment",
color: "#F740A6",
bgColor: "#FFE2F2",
},
1: {
txt: "购票成功",
text_en: "Transaction completed",
color: "#FFCC00",
bgColor: "#FFF7D9",
},
2: {
txt: "交易关闭",
text_en: "Transaction closed",
color: "#757575",
bgColor: "#DDDDDD",
},
3: {
txt: "已退款",
text_en: "Already refunded",
color: "#757575",
bgColor: "#DDDDDD",
},
4: {
txt: '退款中',
txt: "退款中",
text_en: "In the process of refunding",
color: "#F740A6",
bgColor: "#FFE2F2",
},
5: {
txt: "完成",
text_en: "Finish",
color: "#34C759",
bgColor: "#D2FFDD",
},
......@@ -96,18 +105,30 @@ const order = reactive({
},
// 取消支付
cancelPayment(it) {
ElMessageBox.confirm("确定取消支付吗?", "提示", {
confirmButtonText: "确认",
cancelButtonText: "取消",
type: "warning",
draggable: true,
})
ElMessageBox.confirm(
languageFormat(
language.value,
"确认取消支付吗?",
"Are you sure to cancel the payment?"
),
languageFormat(language.value, "提示", "tip"),
{
confirmButtonText: languageFormat(language.value, "确认", "confirm"),
cancelButtonText: languageFormat(language.value, "取消", "cancel"),
type: "warning",
draggable: true,
}
)
.then(() => {
cancelPay({ orderSn: it.orderSn }).then(() => {
order.fetchData();
ElMessage({
type: "success",
message: "操作成功",
message: languageFormat(
language.value,
"操作成功",
"Operate successfully"
),
});
});
})
......@@ -162,7 +183,7 @@ onUnmounted(() => {
// 用户免登录
const login = async () => {
const userId = userStore.user?.userId
const userId = userStore.user?.userId;
const sign = md5(`uid=${userId}lgo1acfkw51jfo`, 32);
return loginFree({
userId: userId,
......@@ -173,9 +194,8 @@ const login = async () => {
});
};
onMounted(() => {
login()
login();
});
</script>
<template>
......@@ -195,13 +215,35 @@ onMounted(() => {
<img class="cover_img" :src="it.coverImg" />
<div class="info">
<div class="title">{{ it.name }}</div>
<div class="common">时间:{{ it.dateStr }}</div>
<div class="common">地址:{{ it.placeName }}</div>
<div class="common">订单编号:{{ it.orderSn }}</div>
<div class="common">张数:{{ it.ticketNum }}</div>
<div class="common">金额:¥{{ it.payAmount }}</div>
<div class="common">
{{ languageFormat(language, "时间", "Event Date & Time") }}{{
it.dateStr
}}
</div>
<div class="common">
{{ languageFormat(language, "地址", "Location") }}{{
it.placeName
}}
</div>
<div class="common">
{{ languageFormat(language, "订单编号", "Order No.") }}{{
it.orderSn
}}
</div>
<div class="common">
{{ languageFormat(language, "张数", "Location") }}{{ it.ticketNum
}}{{ languageFormat(language, "张", "tickets") }}
</div>
<div class="common">
{{ languageFormat(language, "金额", "Ticket Price") }}<span
v-if="language == 0"
></span
>{{ it.payAmount }}
</div>
<div class="status">
<div class="label">订单状态:</div>
<div class="label">
{{ languageFormat(language, "订单状态", "Order Status") }}
</div>
<div class="value">
<div
:style="{
......@@ -211,10 +253,19 @@ onMounted(() => {
}"
class="tag"
>
{{ status[it.state].txt }}
{{
language == 0 ? status[it.state].txt : status[it.state].txt_en
}}
</div>
<div v-if="it.state == 0" class="tip">
请尽快完成支付,还剩{{ order.minutes }}{{ order.seconds }}
<span v-if="language == 0"
>请尽快完成支付,还剩{{ order.minutes }}{{
order.seconds
}}</span
>
<span v-else
>Time left {{ order.minutes }}:{{ order.seconds }}</span
>
</div>
</div>
</div>
......
<script setup>
import { deleteViewPeople, viewPeopleList } from "./api/index.js";
import { ElMessageBox, ElMessage } from "element-plus";
import { languageFormat } from "./utils/language.js";
import { useStorage } from "@vueuse/core/index";
const language = useStorage("language", 0);
const audience = reactive({
data: [],
......@@ -12,18 +14,30 @@ const audience = reactive({
},
deletePeople(id) {
ElMessageBox.confirm("确定删除该观看人吗?", "提示", {
confirmButtonText: "确认",
cancelButtonText: "取消",
type: "warning",
draggable: true,
})
ElMessageBox.confirm(
languageFormat(
language.value,
"确认删除该观看人吗?",
"Are you sure to delete this viewer?"
),
languageFormat(language.value, "提示", "Reminder"),
{
confirmButtonText: languageFormat(language.value, "确认", "confirm"),
cancelButtonText: languageFormat(language.value, "取消", "cancel"),
type: "warning",
draggable: true,
}
)
.then(() => {
deleteViewPeople({ id }).then(() => {
audience.fetchData();
ElMessage({
type: "success",
message: "操作成功",
message: languageFormat(
language.value,
"操作成功",
"Operate successfully"
),
});
});
})
......@@ -41,9 +55,9 @@ audience.fetchData();
class="add_btn"
@click="$router.push({ path: '/seat/add_watch_people' })"
>
新增
{{ languageFormat(language, "新增", "Add") }}
</div>
观影人管理
{{ languageFormat(language, "观影人管理", "Viewers") }}
</div>
<div class="content">
<div class="people_box">
......@@ -53,8 +67,14 @@ audience.fetchData();
class="people_item"
>
<div class="name">{{ it.name }}</div>
<div class="idcard">身份证:{{ it.idCard }}</div>
<div class="btn" @click="audience.deletePeople(it.id)">删除</div>
<div class="idcard">
{{ languageFormat(language, "身份证", "Identity Card") }}{{
it.idCard
}}
</div>
<div class="btn" @click="audience.deletePeople(it.id)">
{{ languageFormat(language, "删除", "delete") }}
</div>
</div>
</div>
</div>
......
<script setup>
import { ElMessage } from "element-plus";
import { getPriceLevelInfo, getSiteConfig, confirmOrder } from "./api/index.js";
import { onBeforeUnmount } from "vue";
import { languageFormat } from "./utils/language.js";
import { useStorage } from "@vueuse/core/index";
const language = useStorage("language", 0);
const route = useRoute();
const router = useRouter();
......@@ -62,6 +64,22 @@ function onWindowMessage(e) {
moveToPriceArea(route.query.ticket_block);
}, 500);
});
// 绘制舞台矩形
sendMsg("draw-object-rectangle", {
x: 1800,
y: 960,
w: 4400,
h: 1300,
color: "#e0e0e0",
});
// 绘制舞台文字
sendMsg("draw-object-text", {
x: 3900,
y: 1500,
text: language.value == 0 ? "舞台" : "stage",
style: { fontSize: 160, fontWeight: "400", fill: "#6a6a6a" },
});
} else if (data.type == "seat-click") {
// 子页面点击了座位
const seatData = data.data;
......@@ -78,7 +96,14 @@ function onWindowMessage(e) {
selectedSeats.value?.length >= 5 &&
seatData.active == 0
)
return ElMessage({ type: "warning", message: "最多选择5个座位" });
return ElMessage({
type: "warning",
message: languageFormat(
language.value,
"最多选择5个座位",
"Selectt at most 5 seats"
),
});
const newActive = seatData.active == 0 ? 1 : 0;
const siteConfigItem = siteConfig.data.find((it) => it.id == seatData.id);
......@@ -204,7 +229,14 @@ const sumPrice = computed(() => {
const toConfirmOrder = () => {
const seatIds = selectedSeats.value.map((it) => it.id);
if (!seatIds.length)
return ElMessage({ type: "warning", message: "请先选择座位" });
return ElMessage({
type: "warning",
message: languageFormat(
language,
"请先选择座位",
"Please select the seat first."
),
});
confirmOrder({
actId: props.activityId,
openType: route.query.openType,
......@@ -268,7 +300,9 @@ price.fetchData();
@click="price.onClickPrice(it)"
>
<img class="seat" :src="it.unSelectIcon" />
<span class="price">{{ it.price }}¥</span>
<span class="price"
>{{ it.price }}<span v-if="language == 0">¥</span></span
>
</div>
</div>
</div>
......@@ -278,7 +312,11 @@ price.fetchData();
<!-- v-for="(it, index) in selectedSeats" -->
<div v-for="(it, index) in selectedSeats" class="seat_item">
<img class="seat_icon" :src="it.selectIcon" />
<span class="num">{{ it.area }}{{ it.pai }}{{ it.no }}</span>
<span class="num"
>{{ it.area }}{{ languageFormat(language, "区", "Zones") }}
{{ it.pai }}{{ languageFormat(language, "排", "Row") }} {{ it.no }}
{{ languageFormat(language, "座", "Seat") }}</span
>
<el-icon
style="cursor: pointer"
color="#ccc"
......@@ -289,7 +327,9 @@ price.fetchData();
</div>
<div class="pay">
<div class="sum">¥{{ sumPrice?.toFixed(2) }}</div>
<div class="pay_btn" @click="toConfirmOrder()">立即购买</div>
<div class="pay_btn" @click="toConfirmOrder()">
{{ languageFormat(language, "立即购买", "Continue") }}
</div>
</div>
</div>
......
......@@ -11,6 +11,9 @@ import {
getSitePlaceInfo,
getPriceLevelInfo,
} from "./api/index.js";
import { languageFormat } from "./utils/language.js";
import { useStorage } from "@vueuse/core/index";
const language = useStorage("language", 0);
const route = useRoute();
const router = useRouter();
......@@ -90,13 +93,41 @@ const select_form = reactive({
await login(userId);
if (!select_form.venueItem?.id)
return ElMessage({ type: "warning", message: "请选择时间" });
return ElMessage({
type: "warning",
message: languageFormat(
language.value,
"请选择时间",
"Please select the time"
),
});
if (select_form.session == -1)
return ElMessage({ type: "warning", message: "请选择场次" });
return ElMessage({
type: "warning",
message: languageFormat(
language.value,
"请选择场次",
"Please select the session"
),
});
if (!select_form.place)
return ElMessage({ type: "warning", message: "请选择场馆" });
return ElMessage({
type: "warning",
message: languageFormat(
language.value,
"请选择场馆",
"Please choose the venue"
),
});
if (!select_form.ticket_block)
return ElMessage({ type: "warning", message: "请选择票档" });
return ElMessage({
type: "warning",
message: languageFormat(
language.value,
"请选择票档",
"Please choose the ticket category"
),
});
router.push({
path: "/seat/seat_picker",
......@@ -225,7 +256,7 @@ watch(
<div class="info">
<div class="title">{{ detail.data?.name }}</div>
<div class="time">
时间{{
{{ languageFormat(language, "时间", "Event Date & Time") }}{{
detail.data?.startTime
? dayjs(detail.data?.startTime).format("YYYY.MM.DD ddd")
: ""
......@@ -237,10 +268,16 @@ watch(
: ""
}}
</div>
<div class="address">地址:{{ detail.data?.address }}</div>
<div class="address">
{{ languageFormat(language, "地址", "Location") }}{{
detail.data?.address
}}
</div>
<!-- 时间 -->
<div class="select_item_box">
<div class="label">时间</div>
<div class="label">
{{ languageFormat(language, "时间", "Event Date & Time") }}
</div>
<div class="select_item">
<div
v-for="(it, index) in timeVenue.data"
......@@ -251,13 +288,13 @@ watch(
@click="select_form.onClickVenue(it)"
>
{{ it.dateStr }}
<div v-if="it.type == 1" class="tag_t">套票</div>
<div v-if="it.type == 1" class="tag_t">{{ languageFormat(language, "套票", "Package ticket") }}</div>
</div>
</div>
</div>
<!-- 场次 -->
<div class="select_item_box">
<div class="label">场次</div>
<div class="label">{{ languageFormat(language, "场次", "Session") }}</div>
<div class="select_item">
<div
:class="[
......@@ -269,7 +306,7 @@ watch(
]"
@click="select_form.onClickSession(0)"
>
日场
{{ languageFormat(language, "日场", "Day session") }}
</div>
<div
:class="[
......@@ -281,13 +318,15 @@ watch(
]"
@click="select_form.onClickSession(1)"
>
夜场
{{ languageFormat(language, "夜场", "Night session") }}
</div>
</div>
</div>
<!-- 场馆 -->
<div class="select_item_box">
<div class="label">场馆</div>
<div class="label">
{{ languageFormat(language, "场馆", "Venue") }}
</div>
<div class="select_item">
<div
v-for="(it, index) in sitePlaceInfo.data"
......@@ -310,7 +349,9 @@ watch(
v-if="price.data?.length && select_form.place"
class="select_item_box"
>
<div class="label">票档</div>
<div class="label">
{{ languageFormat(language, "票档", "Ticket Category") }}
</div>
<div class="select_item">
<div
v-for="(it, index) in price.data"
......@@ -329,16 +370,22 @@ watch(
</div>
</div>
<!-- button -->
<div class="btn" @click="select_form.toSelectSeat()">选座购票</div>
<div class="btn" @click="select_form.toSelectSeat()">
{{ languageFormat(language, "选座购票", "Seat selection") }}
</div>
</div>
</div>
<!-- bottom -->
<div class="container bottom">
<div class="title">活动介绍</div>
<div class="title">
{{ languageFormat(language, "活动介绍", "Event Details") }}
</div>
<div class="rich_content" v-html="detail.data?.introduceInfo"></div>
<div class="title" style="margin-top: 30px">购票须知</div>
<div class="title" style="margin-top: 30px">
{{ languageFormat(language, "购票须知", "Ticketing Information") }}
</div>
<div class="rich_content" v-html="detail.data?.buyNotice"></div>
</div>
</div>
......
export const languageFormat = (language = 0, zh, en) => {
return language == 1 ? en : zh;
};
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!