d69b2fe1 by zhangmeng

Merge branch 'order' of https://code.itechtop.cn/yangyang/dance-pc into order

2 parents 848a4831 421304e8
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
30 "jszip": "^3.10.1", 30 "jszip": "^3.10.1",
31 "katex": "^0.16.6", 31 "katex": "^0.16.6",
32 "lodash": "^4.17.21", 32 "lodash": "^4.17.21",
33 "md5js": "^1.0.7",
33 "nprogress": "0.2.0", 34 "nprogress": "0.2.0",
34 "pinia": "2.0.35", 35 "pinia": "2.0.35",
35 "qrcode": "^1.5.3", 36 "qrcode": "^1.5.3",
......
This diff could not be displayed because it is too large.
No preview for this file type
...@@ -1078,7 +1078,8 @@ img{display: block;} ...@@ -1078,7 +1078,8 @@ img{display: block;}
1078 text-decoration: underline;} 1078 text-decoration: underline;}
1079 } 1079 }
1080 .panel-title{font-size: 16px;line-height: 50px;margin: 0; 1080 .panel-title{font-size: 16px;line-height: 50px;margin: 0;
1081 color: var(--el-color-primary)} 1081 color: var(--el-color-primary)
1082 }
1082 .panel-body{padding: 20px;} 1083 .panel-body{padding: 20px;}
1083 &.border{border: 1px solid #EEEEEE;} 1084 &.border{border: 1px solid #EEEEEE;}
1084 } 1085 }
......
...@@ -12,12 +12,13 @@ ...@@ -12,12 +12,13 @@
12 > 12 >
13 <el-menu-item index="/">{{ language==0?'首页':'HOME' }}</el-menu-item> 13 <el-menu-item index="/">{{ language==0?'首页':'HOME' }}</el-menu-item>
14 <el-menu-item index="/news">{{ language==0?'新闻资讯':'NEWS' }}</el-menu-item> 14 <el-menu-item index="/news">{{ language==0?'新闻资讯':'NEWS' }}</el-menu-item>
15 <el-menu-item index="/notice">{{ language==0?'通知公告':'NOTICEBOARD' }}</el-menu-item> 15 <el-menu-item index="/guide">{{ language==0?'参赛指南':'GUIDELINE' }}</el-menu-item>
16 <el-menu-item index="/match/list">{{ language==0?'大赛报名':'REGISTRATION' }}</el-menu-item> 16 <el-menu-item index="/match/list">{{ language==0?'大赛报名':'REGISTRATION' }}</el-menu-item>
17 <el-menu-item index="/saiC">{{ language==0?'赛程安排':'COMPETITIONS' }}</el-menu-item> 17 <el-menu-item index="/saiC">{{ language==0?'赛程安排':'COMPETITIONS' }}</el-menu-item>
18 <el-menu-item index="/meta">{{ language==0?'媒体中心':'MEDIA' }}</el-menu-item> 18 <el-menu-item index="/meta">{{ language==0?'媒体中心':'MEDIA' }}</el-menu-item>
19 <el-menu-item index="/guide">{{ language==0?'参赛指南':'GUIDELINE' }}</el-menu-item> 19 <el-menu-item index="/notice">{{ language==0?'通知公告':'NOTICEBOARD' }}</el-menu-item>
20 <!-- <el-sub-menu index="/about">--> 20
21 <!-- <el-sub-menu index="/about">-->
21 <!-- <template #title>{{ language==0?'关于我们':'CONTACT & MORE' }}</template>--> 22 <!-- <template #title>{{ language==0?'关于我们':'CONTACT & MORE' }}</template>-->
22 <!-- <el-menu-item index="/about/wuDao">{{ language==0?'舞蹈节':'About Us' }}</el-menu-item>--> 23 <!-- <el-menu-item index="/about/wuDao">{{ language==0?'舞蹈节':'About Us' }}</el-menu-item>-->
23 <!-- <el-menu-item index="/about/regulations" v-if="language==1">Rules & Regulations</el-menu-item>--> 24 <!-- <el-menu-item index="/about/regulations" v-if="language==1">Rules & Regulations</el-menu-item>-->
...@@ -30,12 +31,13 @@ ...@@ -30,12 +31,13 @@
30 > 31 >
31 <el-menu-item index="/">{{ language==0?'首页':'HOME' }}</el-menu-item> 32 <el-menu-item index="/">{{ language==0?'首页':'HOME' }}</el-menu-item>
32 <el-menu-item index="/news">{{ language==0?'新闻资讯':'NEWS' }}</el-menu-item> 33 <el-menu-item index="/news">{{ language==0?'新闻资讯':'NEWS' }}</el-menu-item>
33 <el-menu-item index="/notice">{{ language==0?'通知公告':'NOTICEBOARD' }}</el-menu-item> 34 <el-menu-item index="/guide">{{ language==0?'参赛指南':'GUIDELINE' }}</el-menu-item>
34 <el-menu-item index="/match/list">{{ language==0?'大赛报名':'REGISTRATION' }}</el-menu-item> 35 <el-menu-item index="/match/list">{{ language==0?'大赛报名':'REGISTRATION' }}</el-menu-item>
35 <el-menu-item index="/saiC">{{ language==0?'赛程安排':'COMPETITIONS' }}</el-menu-item> 36 <el-menu-item index="/saiC">{{ language==0?'赛程安排':'COMPETITIONS' }}</el-menu-item>
36 <el-menu-item index="/meta">{{ language==0?'媒体中心':'MEDIA' }}</el-menu-item> 37 <el-menu-item index="/meta">{{ language==0?'媒体中心':'MEDIA' }}</el-menu-item>
37 <el-menu-item index="/guide">{{ language==0?'参赛指南':'GUIDELINE' }}</el-menu-item> 38 <el-menu-item index="/notice">{{ language==0?'通知公告':'NOTICEBOARD' }}</el-menu-item>
38 <!-- <el-sub-menu index="/about">--> 39
40 <!-- <el-sub-menu index="/about">-->
39 <!-- <template #title>{{ language==0?'关于我们':'CONTACT & MORE' }}</template>--> 41 <!-- <template #title>{{ language==0?'关于我们':'CONTACT & MORE' }}</template>-->
40 <!-- <el-menu-item index="/about/wuDaoEn">{{ language==0?'舞蹈节':'About Us' }}</el-menu-item>--> 42 <!-- <el-menu-item index="/about/wuDaoEn">{{ language==0?'舞蹈节':'About Us' }}</el-menu-item>-->
41 <!-- <el-menu-item index="/about/regulations" v-if="language==1">Rules & Regulations</el-menu-item>--> 43 <!-- <el-menu-item index="/about/regulations" v-if="language==1">Rules & Regulations</el-menu-item>-->
......
...@@ -13,6 +13,7 @@ NProgress.configure({ showSpinner: false }) ...@@ -13,6 +13,7 @@ NProgress.configure({ showSpinner: false })
13 const whiteList = ['/login', '/register', '/regulations'] 13 const whiteList = ['/login', '/register', '/regulations']
14 14
15 router.beforeEach((to, from, next) => { 15 router.beforeEach((to, from, next) => {
16 console.log('to2', to)
16 NProgress.start() 17 NProgress.start()
17 if (getToken()) { 18 if (getToken()) {
18 // debugger 19 // debugger
......
...@@ -9,6 +9,7 @@ import useUserStore from '@/store/modules/user' ...@@ -9,6 +9,7 @@ import useUserStore from '@/store/modules/user'
9 NProgress.configure({ showSpinner: false }) 9 NProgress.configure({ showSpinner: false })
10 10
11 router.beforeEach((to, from, next) => { 11 router.beforeEach((to, from, next) => {
12 console.log('to', to)
12 NProgress.start() 13 NProgress.start()
13 if (getToken()) { 14 if (getToken()) {
14 // 判断当前用户是否已拉取完user_info信息 15 // 判断当前用户是否已拉取完user_info信息
......
...@@ -500,6 +500,71 @@ export const constantRoutes = [ ...@@ -500,6 +500,71 @@ export const constantRoutes = [
500 meta: { title: 'System messages' } 500 meta: { title: 'System messages' }
501 } 501 }
502 ] 502 ]
503 },
504 {
505 path: 'seat',
506 component: () => import('@/viewsPc/seat/seat'),
507 name: 'seat',
508 redirect: '/seat/detail',
509 children: [
510 {
511 path: 'detail',
512 name: 'seat_detail',
513 component: () => import('@/viewsPc/seat/ticket-detail'),
514 meta: { title: '购票详情' },
515 props: route => ({
516 activityId:route.query.id,
517 })
518 },
519 {
520 path: 'seat_picker',
521 name: 'seat_picker',
522 component: () => import('@/viewsPc/seat/seat-picker'),
523 meta: { title: '选座' },
524 props: route => ({
525 activityId:route.query.id,
526 })
527 },
528 {
529 path: 'order',
530 name: 'seat_order',
531 component: () => import('@/viewsPc/seat/order-list'),
532 meta: { title: '我的订单' },
533 props: route => ({
534 activityId:route.query.id,
535 })
536 },
537 {
538 path: 'order_detail',
539 name: 'order_detail',
540 component: () => import('@/viewsPc/seat/order-detail'),
541 meta: { title: '订单详情' },
542 props: route => ({
543 activityId: route.query.id,
544 })
545 },
546 {
547 path: 'confirm_order',
548 name: 'confirm_order',
549 component: () => import('@/viewsPc/seat/confirm-order'),
550 meta: { title: '确认订单' },
551 props: route => ({
552 activityId:route.query.id,
553 })
554 },
555 {
556 path: 'add_watch_people',
557 name: 'add_watch_people',
558 component: () => import('@/viewsPc/seat/add-watch-people'),
559 meta: { title: '新增观影人' }
560 },
561 {
562 path: 'people_manage',
563 name: 'people_manage',
564 component: () => import('@/viewsPc/seat/people-manage'),
565 meta: { title: '观影人管理' }
566 },
567 ]
503 } 568 }
504 ] 569 ]
505 }, 570 },
......
...@@ -108,6 +108,13 @@ const menus = ref([ ...@@ -108,6 +108,13 @@ const menus = ref([
108 isActive: false 108 isActive: false
109 }, 109 },
110 { 110 {
111 name: language.value==0?'票务预订':'Ticket Reservation',
112 routeName: 'seat_order',
113 picUrl1: '/img/nav_29.png',
114 picUrl2: '/img/nav_29_dwn.png',
115 isActive: false
116 },
117 {
111 name: language.value==0?'系统消息':'System messages', 118 name: language.value==0?'系统消息':'System messages',
112 routeName: 'mySms', 119 routeName: 'mySms',
113 picUrl1: '/img/nav_30.png', 120 picUrl1: '/img/nav_30.png',
......
...@@ -24,7 +24,8 @@ ...@@ -24,7 +24,8 @@
24 </el-form-item> 24 </el-form-item>
25 <el-form-item :label="language==0?'会员角色':'Role'"> 25 <el-form-item :label="language==0?'会员角色':'Role'">
26 <el-select v-model="labelArr" multiple style="width: 100px;"> 26 <el-select v-model="labelArr" multiple style="width: 100px;">
27 <el-option v-for="l in labels" :key="l.value" :value="l.value" :label="language==0?(l.label):(l.enlabel)"/> 27 <el-option v-if="group.type=='4'" v-for="l in labels" :key="l.value" :value="l.value" :label="language==0?(l.label):(l.enlabel)"/>
28 <el-option v-else v-for="l in labelsForType4" :key="l.value" :value="l.value" :label="language==0?(l.label):(l.enlabel)"/>
28 </el-select> 29 </el-select>
29 </el-form-item> 30 </el-form-item>
30 <el-form-item :label="language==0?'WDSF':'WDSF'"> 31 <el-form-item :label="language==0?'WDSF':'WDSF'">
...@@ -73,6 +74,8 @@ import useUserStore from "@/store/modules/user"; ...@@ -73,6 +74,8 @@ import useUserStore from "@/store/modules/user";
73 import {useStorage} from "@vueuse/core/index"; 74 import {useStorage} from "@vueuse/core/index";
74 import AddWdsf from "@/viewsPc/match/components/addWdsf"; 75 import AddWdsf from "@/viewsPc/match/components/addWdsf";
75 const language= useStorage('language',0) 76 const language= useStorage('language',0)
77 const group = useUserStore().group || {}
78
76 const tableData = ref([]) 79 const tableData = ref([])
77 const labelArr = ref([]) 80 const labelArr = ref([])
78 const labels = ref([ 81 const labels = ref([
...@@ -84,6 +87,15 @@ const labels = ref([ ...@@ -84,6 +87,15 @@ const labels = ref([
84 {value: '6', label: '官员', enlabel: 'Official'}, 87 {value: '6', label: '官员', enlabel: 'Official'},
85 {value: '3', label: '其他', enlabel: 'Other'} 88 {value: '3', label: '其他', enlabel: 'Other'}
86 ]) 89 ])
90 const labelsForType4 = ref([
91 {value: '0', label: '运动员', enlabel: 'Sportsman'},
92 {value: '1', label: '教练', enlabel: 'Coach'},
93 {value: '2', label: '领队', enlabel: 'Head of team'},
94 {value: '4', label: '管理', enlabel: 'Manager'},
95 {value: '5', label: '翻译', enlabel: 'Interpreter'},
96 {value: '6', label: '官员', enlabel: 'Official'},
97 {value: '3', label: '其他', enlabel: 'Other'}
98 ])
87 const certificates = ref([ 99 const certificates = ref([
88 { 100 {
89 value: '0', 101 value: '0',
...@@ -102,7 +114,6 @@ const query = ref({ ...@@ -102,7 +114,6 @@ const query = ref({
102 pageNum: 1, pageSize: 10 114 pageNum: 1, pageSize: 10
103 }) 115 })
104 const total = ref(0) 116 const total = ref(0)
105 const group = useUserStore().group || {}
106 const props = defineProps({ 117 const props = defineProps({
107 user: { 118 user: {
108 type: Object, 119 type: Object,
...@@ -193,6 +204,8 @@ function delperson(p) { ...@@ -193,6 +204,8 @@ function delperson(p) {
193 cancelButtonText: c, 204 cancelButtonText: c,
194 type: 'warning' 205 type: 'warning'
195 }).then(() => { 206 }).then(() => {
207
208 // This user has registered for the event and cannot be deleted.
196 match.delPerson(p.id).then(res => { 209 match.delPerson(p.id).then(res => {
197 ElMessage.success(msg) 210 ElMessage.success(msg)
198 getList(groupId.value) 211 getList(groupId.value)
......
...@@ -101,7 +101,8 @@ function popRemark(type){ ...@@ -101,7 +101,8 @@ function popRemark(type){
101 building() 101 building()
102 return 102 return
103 } 103 }
104 if((form.value.isJdView == 0&&type=='1') || (form.value.isCarView == 0&&type=='2') || (form.value.isFoodView == 0&&type=='3') || type=='0' || (form.value.isMealView == 0&&type=='4') || (type=='5'&&form.value.isPhotoView == 0)){ 104 if((form.value.isJdView == 0&&type=='1') || (form.value.isCarView == 0&&type=='2') || (form.value.isFoodView == 0&&type=='3') || (form.value.isMealView == 0&&type=='4') || (type=='5'&&form.value.isPhotoView == 0)){
105 //type == '0'
105 building() 106 building()
106 return 107 return
107 } 108 }
...@@ -116,8 +117,11 @@ function goBooking(n) { ...@@ -116,8 +117,11 @@ function goBooking(n) {
116 switch (n) { 117 switch (n) {
117 case 0: 118 case 0:
118 // 票务 119 // 票务
119 building() 120 router.push({
120 router.push({path: `/booking/ticket/${props.matchId}`}) 121 path: `/seat/detail`,
122 params: {id: 1},
123 query: {id: 1}
124 })
121 break; 125 break;
122 case 1: 126 case 1:
123 //酒店 127 //酒店
......
...@@ -96,8 +96,8 @@ ...@@ -96,8 +96,8 @@
96 96
97 <div class="content" v-if="activeName==8"> 97 <div class="content" v-if="activeName==8">
98 <label>点击下载:</label> 98 <label>点击下载:</label>
99 <!-- <a target="_blank" class="text-primary" href="/file/COMPETITION_GUIDE_0511V1.pdf">--> 99 <a target="_blank" class="text-primary" href="/file/COMPETITION%20GUIDE%200520V1.pdf">
100 <a @click="showBuilding" class="text-primary"> 100 <!-- <a @click="showBuilding" class="text-primary">-->
101 <el-icon style="position: relative;top: 2px"><download/></el-icon> 101 <el-icon style="position: relative;top: 2px"><download/></el-icon>
102 2024 WDSF亚洲体育舞蹈节参赛指南 102 2024 WDSF亚洲体育舞蹈节参赛指南
103 </a> 103 </a>
...@@ -200,8 +200,8 @@ ...@@ -200,8 +200,8 @@
200 <div class="content" v-if="activeName==71"><el-empty description="no data"></el-empty></div> 200 <div class="content" v-if="activeName==71"><el-empty description="no data"></el-empty></div>
201 <div class="content" v-if="activeName==8"> 201 <div class="content" v-if="activeName==8">
202 <label>Download:</label> 202 <label>Download:</label>
203 <!-- <a target="_blank" class="text-primary" href="/file/COMPETITION_GUIDE_0511V1.pdf">--> 203 <a target="_blank" class="text-primary" href="/file/COMPETITION%20GUIDE%200520V1.pdf">
204 <a @click="showBuilding" class="text-primary"> 204 <!-- <a @click="showBuilding" class="text-primary">-->
205 <el-icon style="position: relative;top: 2px"><download/></el-icon> 205 <el-icon style="position: relative;top: 2px"><download/></el-icon>
206 2024 WDSF ASIAN DANCESPORT FESTIVAL COMPETITION GUIDE 206 2024 WDSF ASIAN DANCESPORT FESTIVAL COMPETITION GUIDE
207 </a> 207 </a>
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
4 <div class="box ph-30"> 4 <div class="box ph-30">
5 <el-card v-if="user"> 5 <el-card v-if="user">
6 <single-sign-step v-if="user.utype=='1'" activeStep="1" :language="language"/> 6 <single-sign-step v-if="user.utype=='1'" activeStep="1" :language="language"/>
7 <team-sign-step v-if="user.utype=='2'" activeStep="2" :language="language"/> 7 <team-sign-step v-if="user.utype=='2'" :activeStep="1" :language="language"/>
8 </el-card> 8 </el-card>
9 9
10 <el-card class="mt20"> 10 <el-card class="mt20">
...@@ -73,10 +73,14 @@ ...@@ -73,10 +73,14 @@
73 <el-col :lg="12"> 73 <el-col :lg="12">
74 <el-card class="mt20" v-loading="loading"> 74 <el-card class="mt20" v-loading="loading">
75 <template #header> 75 <template #header>
76 <div class="card-header"> 76 <div class="card-header" v-if="isNational">
77 <img src="@/assets/sign/tag03.png"/> 77 <img src="@/assets/sign/tag03.png"/>
78 {{ language==0?'队医':'Team doctor' }} 78 {{ language==0?'队医':'Team doctor' }}
79 </div> 79 </div>
80 <div class="card-header" v-else>
81 <img src="@/assets/sign/gl.png"/>
82 管理
83 </div>
80 </template> 84 </template>
81 <div class="chooseForm"> 85 <div class="chooseForm">
82 <el-checkbox-group v-model="form.doctor"> 86 <el-checkbox-group v-model="form.doctor">
...@@ -198,7 +202,7 @@ import DialogAddCoach_En from './components/addCoach_en' ...@@ -198,7 +202,7 @@ import DialogAddCoach_En from './components/addCoach_en'
198 const {proxy} = getCurrentInstance() 202 const {proxy} = getCurrentInstance()
199 const router = useRouter() 203 const router = useRouter()
200 const route = useRoute() 204 const route = useRoute()
201 import {ElMessage} from 'element-plus' 205 import {ElMessage, ElMessageBox} from 'element-plus'
202 import {useRoute, useRouter} from 'vue-router' 206 import {useRoute, useRouter} from 'vue-router'
203 import useUserStore from "@/store/modules/user"; 207 import useUserStore from "@/store/modules/user";
204 import {useStorage} from "@vueuse/core/index"; 208 import {useStorage} from "@vueuse/core/index";
...@@ -242,7 +246,7 @@ onMounted(() => { ...@@ -242,7 +246,7 @@ onMounted(() => {
242 }) 246 })
243 247
244 function getList() { 248 function getList() {
245 console.log(user.utype) 249 // console.log(user.utype)
246 if (user.utype == '1') { 250 if (user.utype == '1') {
247 geren() 251 geren()
248 } 252 }
...@@ -252,7 +256,7 @@ function getList() { ...@@ -252,7 +256,7 @@ function getList() {
252 } 256 }
253 257
254 function changecoachs(e) { 258 function changecoachs(e) {
255 console.log(e) 259 // console.log(e)
256 } 260 }
257 261
258 // 获取报名时是否已选过 262 // 获取报名时是否已选过
...@@ -309,11 +313,31 @@ function geren() { ...@@ -309,11 +313,31 @@ function geren() {
309 } 313 }
310 314
311 function goNext() { 315 function goNext() {
312 console.log(form.value) 316 console.log(personAllList.value.teamDoctors,form.value)
313 // if ((form.value.coachs.length < 1) && (form.value.leader.length < 1)) { 317 // if ((form.value.coachs.length < 1) && (form.value.leader.length < 1)) {
314 // ElMessage.warning(language.value==0?'至少选一个教练或领队':'Coach/Team Leader, select at least one') 318 // ElMessage.warning(language.value==0?'至少选一个教练或领队':'Coach/Team Leader, select at least one')
315 // return 319 // return
316 // } 320 // }
321 if((personAllList.value.coaches.length>=0 && form.value.coachs?.toString().length == 0)&&
322 (personAllList.value.teamDoctors.length>=0 && form.value.doctor?.toString().length == 0)&&
323 (personAllList.value.translators.length>=0 && form.value.translator?.toString().length == 0)&&
324 (personAllList.value.others.length>=0 && form.value.other?.toString().length == 0)&&
325 (personAllList.value.officials.length>=0 && form.value.official?.toString().length == 0)&&
326 (personAllList.value.leaders.length>=0 && form.value.leader?.toString().length == 0)
327 ){
328 ElMessageBox.confirm(language.value==0?'您已添加随行人员,但尚未选中,是否进行下一步?':'You have added a follower, but have not selected, do you want to continue?', {
329 confirmButtonText: language.value==0?'下一步':'Next',
330 cancelButtonText: language.value==0?'取消':'Cancel',
331 type: 'warning'
332 }).then(()=>{
333 next()
334 })
335 return
336 }
337 next()
338 }
339
340 function next() {
317 var obj = { 341 var obj = {
318 cptId: matchId, 342 cptId: matchId,
319 coachIds: form.value.coachs?.toString() || '', 343 coachIds: form.value.coachs?.toString() || '',
...@@ -332,7 +356,6 @@ function goNext() { ...@@ -332,7 +356,6 @@ function goNext() {
332 if (user.utype == '1') { 356 if (user.utype == '1') {
333 // 个人报名 357 // 个人报名
334 match.singleSignSavePerson(obj).then(res => { 358 match.singleSignSavePerson(obj).then(res => {
335 console.log(res)
336 router.push({ 359 router.push({
337 name: 'chooseProject', 360 name: 'chooseProject',
338 query: { 361 query: {
...@@ -357,11 +380,8 @@ function goNext() { ...@@ -357,11 +380,8 @@ function goNext() {
357 }) 380 })
358 } 381 }
359 382
360 console.log(form.value)
361 } 383 }
362
363 function goPrev() { 384 function goPrev() {
364 console.log(languageSource.value)
365 if(languageSource.value=='100'){ 385 if(languageSource.value=='100'){
366 router.push({ 386 router.push({
367 name: `teamSignCn`, 387 name: `teamSignCn`,
......
...@@ -38,7 +38,10 @@ ...@@ -38,7 +38,10 @@
38 <div class="text-center mt20"> 38 <div class="text-center mt20">
39 <el-button type="primary" plain @click="switchPerson">{{language==0?'切换':'Switch'}}</el-button> 39 <el-button type="primary" plain @click="switchPerson">{{language==0?'切换':'Switch'}}</el-button>
40 </div> 40 </div>
41 41 <div class="tip">
42 <span v-if="language==0">*如果您参加个人项目,或给其他组合/选手进行报名,请点击切换按钮重新选择人员</span>
43 <span v-else>*If you would like to register individual competitions for yourself or other couples/athletes, please click "Switch" button to re-select persons concerned.</span>
44 </div>
42 </div> 45 </div>
43 </div> 46 </div>
44 </el-col> 47 </el-col>
...@@ -46,7 +49,7 @@ ...@@ -46,7 +49,7 @@
46 <el-col :lg="18"> 49 <el-col :lg="18">
47 <div class="panel border"> 50 <div class="panel border">
48 <div class="panel-header "> 51 <div class="panel-header ">
49 <h3 class="panel-title" v-if="language==0">可参与报名的项目</h3> 52 <h3 class="panel-title" v-if="language==0">可参与报名的项目 <span>已报项目在下方查看</span></h3>
50 <h3 class="panel-title" v-else>Search Events</h3> 53 <h3 class="panel-title" v-else>Search Events</h3>
51 <div class="fr"> 54 <div class="fr">
52 <el-input size="small" v-model="projectQuery.name" :prefix-icon="Search" @change="getProjectList" 55 <el-input size="small" v-model="projectQuery.name" :prefix-icon="Search" @change="getProjectList"
...@@ -59,7 +62,7 @@ ...@@ -59,7 +62,7 @@
59 <el-checkbox class="flexBetweenBox" v-for="c in projectList" :label="c.id" :key="c.id" :disabled="cantBao.flag"> 62 <el-checkbox class="flexBetweenBox" v-for="c in projectList" :label="c.id" :key="c.id" :disabled="cantBao.flag">
60 <div class="flexBetween w100"> 63 <div class="flexBetween w100">
61 <div class="l"> 64 <div class="l">
62 {{ c.code }}:{{ c.name }} 65 {{ c.code }}:{{ c.name }} {{c.danceType}}
63 <div>{{ c.danceTypeDetailStr }}</div> 66 <div>{{ c.danceTypeDetailStr }}</div>
64 </div> 67 </div>
65 <div class="text-primary">{{ language == 0 ? '¥' : '€' }}{{ c.serviceFee }}</div> 68 <div class="text-primary">{{ language == 0 ? '¥' : '€' }}{{ c.serviceFee }}</div>
...@@ -793,4 +796,8 @@ function switchTabletype() { ...@@ -793,4 +796,8 @@ function switchTabletype() {
793 } 796 }
794 .mName{color: #000;font-size: 15px;display: inline-block;max-width: 6.5em;text-overflow: ellipsis; 797 .mName{color: #000;font-size: 15px;display: inline-block;max-width: 6.5em;text-overflow: ellipsis;
795 overflow: hidden;} 798 overflow: hidden;}
799
800 .panel h3.panel-title{
801 span{ color: #999;font-size: 12px;}
802 }
796 </style> 803 </style>
......
...@@ -32,10 +32,10 @@ ...@@ -32,10 +32,10 @@
32 32
33 {{c.representing}} 33 {{c.representing}}
34 {{c.ageGroup}} 34 {{c.ageGroup}}
35 {{c.division}} 35 {{c.division}}<span v-if="c.age"> -{{ c.age }}{{language==0 ? '岁' : 'years'}}</span>
36 <!-- @click="editPerson(c.id)"--> 36 <!-- @click="editPerson(c.id)"-->
37 <span v-if="c.disabled" class="text-danger po-right">需补全信息</span> 37 <span v-if="c.disabled" class="text-danger po-right">需补全信息</span>
38 <!-- -{{ c.age }}--> 38
39 </div> 39 </div>
40 </el-option> 40 </el-option>
41 <!-- <template #tag>--> 41 <!-- <template #tag>-->
...@@ -78,7 +78,9 @@ ...@@ -78,7 +78,9 @@
78 <el-col :lg="14"> 78 <el-col :lg="14">
79 <div class="panel border"> 79 <div class="panel border">
80 <div class="panel-header "> 80 <div class="panel-header ">
81 <h3 class="panel-title" v-if="language==0">可参与报名的项目</h3> 81 <h3 class="panel-title" v-if="language==0">可参与报名的项目
82 <span>已报项目在下方查看</span>
83 </h3>
82 <h3 class="panel-title" v-else>Search Events</h3> 84 <h3 class="panel-title" v-else>Search Events</h3>
83 <div class="fr"> 85 <div class="fr">
84 <el-input size="small" v-model="projectQuery.name" :prefix-icon="Search" 86 <el-input size="small" v-model="projectQuery.name" :prefix-icon="Search"
...@@ -91,7 +93,7 @@ ...@@ -91,7 +93,7 @@
91 <el-checkbox class="flexBetweenBox" v-for="c in projectList" :value="c.id" :key="c.id"> 93 <el-checkbox class="flexBetweenBox" v-for="c in projectList" :value="c.id" :key="c.id">
92 <div class="flexBetween w100"> 94 <div class="flexBetween w100">
93 <div class="l"> 95 <div class="l">
94 {{ c.code }}:{{ c.name }} 96 {{ c.code }}:{{ c.name }}({{c.danceType}})
95 <div>{{ c.danceTypeDetailStr }}</div> 97 <div>{{ c.danceTypeDetailStr }}</div>
96 </div> 98 </div>
97 <div class="text-primary">{{ language == 0 ? '¥' : '€' }}{{ c.serviceFee }}</div> 99 <div class="text-primary">{{ language == 0 ? '¥' : '€' }}{{ c.serviceFee }}</div>
...@@ -868,4 +870,7 @@ watch(choosedchoosed, (newVal, oldVal) => { ...@@ -868,4 +870,7 @@ watch(choosedchoosed, (newVal, oldVal) => {
868 } 870 }
869 :deep(.el-select__tags-text){color: #000;font-size: 14px;} 871 :deep(.el-select__tags-text){color: #000;font-size: 14px;}
870 .po-right{position: absolute;right: 0;} 872 .po-right{position: absolute;right: 0;}
873 .panel h3.panel-title{
874 span{ color: #999;font-size: 13px;}
875 }
871 </style> 876 </style>
......
...@@ -164,7 +164,7 @@ const data = reactive({ ...@@ -164,7 +164,7 @@ const data = reactive({
164 {value: '0', label: '运动员', enlabel: 'Sportsman'}, 164 {value: '0', label: '运动员', enlabel: 'Sportsman'},
165 {value: '1', label: '教练', enlabel: 'Coach'}, 165 {value: '1', label: '教练', enlabel: 'Coach'},
166 {value: '2', label: '领队', enlabel: 'Head Of Team'}, 166 {value: '2', label: '领队', enlabel: 'Head Of Team'},
167 {value: '4', label: '队医', enlabel: 'Team doctor'}, 167 {value: '4', label: '管理', enlabel: 'Team doctor'},
168 {value: '5', label: '翻译', enlabel: 'Interpreter'}, 168 {value: '5', label: '翻译', enlabel: 'Interpreter'},
169 {value: '6', label: '官员', enlabel: 'Official'}, 169 {value: '6', label: '官员', enlabel: 'Official'},
170 {value: '3', label: '其他', enlabel: 'Other'} 170 {value: '3', label: '其他', enlabel: 'Other'}
......
...@@ -4,9 +4,9 @@ ...@@ -4,9 +4,9 @@
4 <el-button type="primary" @click="addMember"> 4 <el-button type="primary" @click="addMember">
5 {{ language == 0 ? '添加选手' : 'Add Player' }} 5 {{ language == 0 ? '添加选手' : 'Add Player' }}
6 </el-button> 6 </el-button>
7 <el-button type="primary" plain @click="importSportman" v-if="!isNational"> 7 <!-- <el-button type="primary" plain @click="importSportman" v-if="!isNational">-->
8 {{language == 0 ? '导入选手' : 'Import Player'}} 8 <!-- {{language == 0 ? '导入选手' : 'Import Player'}}-->
9 </el-button> 9 <!-- </el-button>-->
10 </div> 10 </div>
11 <div class="from-Card"> 11 <div class="from-Card">
12 <el-form :inline="true" :model="query" class="mt20" label-width="60" size="small"> 12 <el-form :inline="true" :model="query" class="mt20" label-width="60" size="small">
......
...@@ -25,7 +25,8 @@ ...@@ -25,7 +25,8 @@
25 </el-col> 25 </el-col>
26 <el-col :lg="8"> 26 <el-col :lg="8">
27 <div class="item"> 27 <div class="item">
28 <label>{{ language == 0 ? '队医' : 'TEAM DOCTOR' }}</label> 28 <label v-if="group.type=='4'">{{ language == 0 ? '队医' : 'TEAM DOCTOR' }}</label>
29 <label v-else>{{ language == 0 ? '管理' : 'MANAGER' }}</label>
29 <span class="mr5" v-for="c in names.teamDoctorList"> 30 <span class="mr5" v-for="c in names.teamDoctorList">
30 {{ c.realName }}, 31 {{ c.realName }},
31 </span> 32 </span>
......
...@@ -43,7 +43,11 @@ ...@@ -43,7 +43,11 @@
43 </div> 43 </div>
44 <div v-else> 44 <div v-else>
45 <div>{{ scope.row.birthPeriod.replace(',',language==0?' 至 ':' to ') }}</div> 45 <div>{{ scope.row.birthPeriod.replace(',',language==0?' 至 ':' to ') }}</div>
46 <div>{{scope.row.birthPeriodSecond?.replace(',',language==0?' 至 ':' to ')}}</div> 46 <div v-if="scope.row.birthPeriodSecond">{{scope.row.birthPeriodSecond?.replace(',',language==0?' 至 ':' to ')}}</div>
47 <div v-if="scope.row.birthPeriodThird">{{scope.row.birthPeriodThird?.replace(',',language==0?' 至 ':' to ')}}</div>
48 <div v-if="scope.row.birthPeriodFourth">{{scope.row.birthPeriodFourth?.replace(',',language==0?' 至 ':' to ')}}</div>
49 <div v-if="scope.row.birthPeriodFifth">{{scope.row.birthPeriodFifth?.replace(',',language==0?' 至 ':' to ')}}</div>
50 <div v-if="scope.row.birthPeriodSixth">{{scope.row.birthPeriodSixth?.replace(',',language==0?' 至 ':' to ')}}</div>
47 </div> 51 </div>
48 </template> 52 </template>
49 </el-table-column> 53 </el-table-column>
......
...@@ -27,7 +27,12 @@ ...@@ -27,7 +27,12 @@
27 <span v-if="item==='0'" class="ml5">{{ language == 0 ? '运动员' : 'Athletes' }}</span> 27 <span v-if="item==='0'" class="ml5">{{ language == 0 ? '运动员' : 'Athletes' }}</span>
28 <span v-if="item==='1'" class="ml5">{{ language == 0 ? '教练' : 'Coach' }}</span> 28 <span v-if="item==='1'" class="ml5">{{ language == 0 ? '教练' : 'Coach' }}</span>
29 <span v-if="item==='2'" class="ml5">{{ language == 0 ? '领队' : 'Head of team' }}</span> 29 <span v-if="item==='2'" class="ml5">{{ language == 0 ? '领队' : 'Head of team' }}</span>
30 <span v-if="item==='4'" class="ml5">{{ language == 0 ? '队医' : 'Team Doctor' }}</span> 30 <span v-if="item==='4'&&group.type!='4'" class="ml5">
31 {{ language == 0 ? '管理' : 'Manager' }}
32 </span>
33 <span v-if="item==='4'&&group.type=='4'" class="ml5">
34 {{ language == 0 ? '队医' : 'Team Doctor' }}
35 </span>
31 <span v-if="item==='5'" class="ml5">{{ language == 0 ? '翻译' : 'Interpreter' }}</span> 36 <span v-if="item==='5'" class="ml5">{{ language == 0 ? '翻译' : 'Interpreter' }}</span>
32 <span v-if="item==='6'" class="ml5">{{ language == 0 ? '官员' : 'Official' }}</span> 37 <span v-if="item==='6'" class="ml5">{{ language == 0 ? '官员' : 'Official' }}</span>
33 <span v-if="item==='3'" class="ml5">{{ language == 0 ? '其他' : 'Other' }}</span> 38 <span v-if="item==='3'" class="ml5">{{ language == 0 ? '其他' : 'Other' }}</span>
...@@ -61,7 +66,8 @@ ...@@ -61,7 +66,8 @@
61 <script setup> 66 <script setup>
62 import {ref} from "vue"; 67 import {ref} from "vue";
63 import {useStorage} from "@vueuse/core/index"; 68 import {useStorage} from "@vueuse/core/index";
64 69 import useUserStore from "@/store/modules/user";
70 const group = useUserStore().group || {}
65 const language = useStorage('language', 0) 71 const language = useStorage('language', 0)
66 const emit = defineEmits(['edit', 'delete']) 72 const emit = defineEmits(['edit', 'delete'])
67 let title = '' 73 let title = ''
......
...@@ -4,22 +4,22 @@ ...@@ -4,22 +4,22 @@
4 </div> 4 </div>
5 <el-table :data="list" :sum-text="sumText" border style="width: 100%" v-loading="loading"> 5 <el-table :data="list" :sum-text="sumText" border style="width: 100%" v-loading="loading">
6 <el-table-column :label="language==0?'序号':'Index'" type="index" width="70" align="center"/> 6 <el-table-column :label="language==0?'序号':'Index'" type="index" width="70" align="center"/>
7 <el-table-column v-if="!isNational" :label="language==0?'姓名':'Real Name'" prop="personInfo.realName" min-width="100"/> 7 <el-table-column v-if="!isNational" :label="language==0?'姓名':'Real Name'" prop="personInfo.realName" align="center" min-width="100"/>
8 <el-table-column v-if="isNational" :label="language==0?'姓氏':'Surname'" prop="personInfo.xing" min-width="100"/> 8 <el-table-column v-if="isNational" :label="language==0?'姓氏':'Surname'" prop="personInfo.xing" min-width="100"/>
9 <el-table-column v-if="isNational" :label="language==0?'名':'Name'" prop="personInfo.ming" min-width="100"/> 9 <el-table-column v-if="isNational" :label="language==0?'名':'Name'" prop="personInfo.ming" min-width="100"/>
10 <el-table-column :label="language==0?'所属国家/地区':'Country'" min-width="120"> 10 <el-table-column :label="language==0?'所属国家/地区':'Country'" min-width="120" header-align="center" align="center">
11 <template #default="scope"> 11 <template #default="scope">
12 <span v-if="scope.row.personInfo.countryName">{{scope.row.personInfo.countryName}}</span> 12 <span v-if="scope.row.personInfo.countryName">{{scope.row.personInfo.countryName}}</span>
13 <span v-if="scope.row.personInfo.representing">{{scope.row.personInfo.representing}}</span> 13 <span v-if="scope.row.personInfo.representing">{{scope.row.personInfo.representing}}</span>
14 </template> 14 </template>
15 </el-table-column> 15 </el-table-column>
16 <el-table-column :label="language==0?'性别':'Gender'" prop="personInfo.sexStr"/> 16 <el-table-column :label="language==0?'性别':'Gender'" prop="personInfo.sexStr" align="center"/>
17 <el-table-column v-if="!isNational" :label="language==0?'证件类型':'ID Type'" :width="language==0?'':'140'" prop="personInfo.idcTypeStr"/> 17 <el-table-column v-if="!isNational" :label="language==0?'证件类型':'ID Type'" align="center" :width="language==0?'':'140'" prop="personInfo.idcTypeStr" header-align="center"/>
18 <el-table-column v-if="!isNational" :label="language==0?'证件号码':'ID NO.'" prop="personInfo.idcCode" width="200"/> 18 <el-table-column v-if="!isNational" :label="language==0?'证件号码':'ID NO.'" prop="personInfo.idcCode" width="200" header-align="center"/>
19 <el-table-column v-if="isNational" :label="language==0?'WDSF 会员号':'WDSF MIN'" prop="personInfo.wdsfMin" width="200"/> 19 <el-table-column v-if="isNational" :label="language==0?'WDSF 会员号':'WDSF MIN'" prop="personInfo.wdsfMin" width="200" header-align="center"/>
20 <el-table-column v-if="!isNational" :label="language==0?'出生日期':'Date of Birth'" prop="personInfo.birth" width="130"/> 20 <el-table-column v-if="!isNational" :label="language==0?'出生日期':'Date of Birth'" align="center" prop="personInfo.birth" width="130" header-align="center"/>
21 <el-table-column v-if="isNational" :label="language==0?'年龄组':'Age group'" prop="personInfo.ageGroup" width="110"/> 21 <el-table-column v-if="isNational" :label="language==0?'年龄组':'Age group'" prop="personInfo.ageGroup" width="110" header-align="center"/>
22 <el-table-column v-if="isNational" :label="language==0?'舞种':'Division'" prop="personInfo.division" width="110"/> 22 <el-table-column v-if="isNational" :label="language==0?'舞种':'Division'" prop="personInfo.division" width="110" header-align="center"/>
23 <!-- <el-table-column :label="language==0?'会员角色':'Role'" width="150">--> 23 <!-- <el-table-column :label="language==0?'会员角色':'Role'" width="150">-->
24 <!-- <template #default="scope">--> 24 <!-- <template #default="scope">-->
25 <!-- <div class="esp">--> 25 <!-- <div class="esp">-->
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
36 <!-- </template>--> 36 <!-- </template>-->
37 <!-- </el-table-column>--> 37 <!-- </el-table-column>-->
38 <!-- <el-table-column :label="language==0?'详细地址':'Detailed Address'" prop="personInfo.address" min-width="140"/>--> 38 <!-- <el-table-column :label="language==0?'详细地址':'Detailed Address'" prop="personInfo.address" min-width="140"/>-->
39 <el-table-column :label="language==0?'报项':'REGISTERED COMPETITION'" min-width="300" :fixed="hasAction?false:'right'"> 39 <el-table-column :label="language==0?'报项':'REGISTERED COMPETITION'" min-width="300" header-align="center" :fixed="hasAction?false:'right'">
40 <template #default="props"> 40 <template #default="props">
41 <ol> 41 <ol>
42 <li v-for="s in props.row.signInfo"> 42 <li v-for="s in props.row.signInfo">
...@@ -51,7 +51,7 @@ ...@@ -51,7 +51,7 @@
51 </ol> 51 </ol>
52 </template> 52 </template>
53 </el-table-column> 53 </el-table-column>
54 <el-table-column :fixed="hasAction?false:'right'" min-width="100" :label="language==0?'保险费':'Premium'" prop="insuranceFee"> 54 <el-table-column :fixed="hasAction?false:'right'" min-width="100" align="center" :label="language==0?'保险费':'Premium'" prop="insuranceFee">
55 <template #default="scope"> 55 <template #default="scope">
56 <span class="text-primary">{{ language==0?'¥':'€' }}{{ scope.row.insuranceFee }}</span> 56 <span class="text-primary">{{ language==0?'¥':'€' }}{{ scope.row.insuranceFee }}</span>
57 </template> 57 </template>
...@@ -61,11 +61,11 @@ ...@@ -61,11 +61,11 @@
61 <template #default="scope"> 61 <template #default="scope">
62 <el-link v-if="scope.row.signInfo[0].extraPersonInfoMapList[index]?.type=='2'" 62 <el-link v-if="scope.row.signInfo[0].extraPersonInfoMapList[index]?.type=='2'"
63 target="_blank" 63 target="_blank"
64 :href="fillImgUrl(scope.row.signInfo[0].extraPersonInfoMapList[index].value.url)"> 64 :href="fillImgUrl(scope.row.signInfo[0].extraPersonInfoMapList[index]?.value?.url)">
65 <span class="text-primary">{{ scope.row.signInfo[0].extraPersonInfoMapList[index].value.name }}</span> 65 <span class="text-primary">{{ scope.row.signInfo[0].extraPersonInfoMapList[index]?.value?.name }}</span>
66 </el-link> 66 </el-link>
67 <img v-else-if="scope.row.signInfo[0].extraPersonInfoMapList[index]?.type=='3'" style="width: 50px;" 67 <img v-else-if="scope.row.signInfo[0].extraPersonInfoMapList[index]?.type=='3'" style="width: 50px;"
68 :src="fillImgUrl(scope.row.signInfo[0].extraPersonInfoMapList[index].value.url||scope.row.signInfo[0].extraPersonInfoMapList[index].value)"> 68 :src="fillImgUrl(scope.row.signInfo[0].extraPersonInfoMapList[index]?.value?.url||scope.row.signInfo[0]?.extraPersonInfoMapList[index]?.value)">
69 <span v-else>{{ scope.row.signInfo[0].extraPersonInfoMapList[index]?.value }}</span> 69 <span v-else>{{ scope.row.signInfo[0].extraPersonInfoMapList[index]?.value }}</span>
70 </template> 70 </template>
71 </el-table-column> 71 </el-table-column>
......
...@@ -2,22 +2,35 @@ ...@@ -2,22 +2,35 @@
2 <div class="mt20"></div> 2 <div class="mt20"></div>
3 <el-table :data="list" border style="width: 100%"> 3 <el-table :data="list" border style="width: 100%">
4 <el-table-column :label="language==0?'序号':'Index'" type="index" width="70" align="center"/> 4 <el-table-column :label="language==0?'序号':'Index'" type="index" width="70" align="center"/>
5 <el-table-column :label="language==0?'组别代码':'EVENT code'" width="120px" prop="project.code"/> 5 <el-table-column :label="language==0?'组别代码':'EVENT code'" width="120px" align="center" prop="project.code"/>
6 <el-table-column :label="language==0?'组别':'EVENT'" prop="project.name"/> 6 <el-table-column :label="language==0?'组别':'EVENT'" min-width="150px" header-align="center" prop="project.name">
7 <el-table-column :label="language==0?'舞种':'DISCIPLINE'" width="120px" prop="project.danceType"/>
8 <el-table-column :label="language==0?'参赛说明':'Participation Instructions'" min-width="160px">
9 <template #default="scope"> 7 <template #default="scope">
10 <div v-html="scope.row.project.remarks"></div> 8 <el-tooltip effect="dark" :content="scope.row.project.name">
9 <div class="esp">{{scope.row.project.name}}</div>
10 </el-tooltip>
11 </template> 11 </template>
12 </el-table-column> 12 </el-table-column>
13 <el-table-column :label="language==0?'参赛运动员':'PARTICIPATING ATHLETES'" min-width="140px"> 13 <el-table-column :label="language==0?'舞种':'DISCIPLINE'" align="center" width="120px" prop="project.danceType"/>
14 <el-table-column :label="language==0?'参赛说明':'Participation Instructions'" header-align="center" min-width="160px">
14 <template #default="scope"> 15 <template #default="scope">
15 <div> 16 <el-tooltip effect="dark" :content="scope.row.project.remarks">
17 <div class="esp" v-html="scope.row.project.remarks"></div>
18 </el-tooltip>
19 </template>
20 </el-table-column>
21 <el-table-column :label="language==0?'参赛运动员':'PARTICIPATING ATHLETES'" header-align="center" min-width="140px">
22 <template #default="scope">
23 <el-tooltip effect="dark">
24 <template #content>
25 <span v-for="s in scope.row.athletes">{{ s.name }},</span>
26 </template>
27 <div class="esp">
16 <span v-for="s in scope.row.athletes">{{ s.name }},</span> 28 <span v-for="s in scope.row.athletes">{{ s.name }},</span>
17 </div> 29 </div>
30 </el-tooltip>
18 </template> 31 </template>
19 </el-table-column> 32 </el-table-column>
20 <el-table-column :label="language==0?'参赛服务费':'REGISTRATION FEE'" width="150px" prop=""> 33 <el-table-column :label="language==0?'参赛服务费':'REGISTRATION FEE'" align="center" width="150px" prop="">
21 <template #default="scope"> 34 <template #default="scope">
22 <div class="text-primary"> 35 <div class="text-primary">
23 {{ language==0?'¥':'€' }}{{ scope.row.project.serviceFee }} 36 {{ language==0?'¥':'€' }}{{ scope.row.project.serviceFee }}
......
...@@ -116,8 +116,10 @@ ...@@ -116,8 +116,10 @@
116 </el-col> 116 </el-col>
117 <el-col :lg="12" v-if="Number(form.totalFee)>0"> 117 <el-col :lg="12" v-if="Number(form.totalFee)>0">
118 <div class="priceb" v-if="form.payStatus=='0'">{{ language==0?'待支付金额':'Amount Due' }}:<span class="price">{{ language==0?'¥':'€' }}{{ Number(totalFee).toFixed(2) }}</span></div> 118 <div class="priceb" v-if="form.payStatus=='0'">{{ language==0?'待支付金额':'Amount Due' }}:<span class="price">{{ language==0?'¥':'€' }}{{ Number(totalFee).toFixed(2) }}</span></div>
119 <div class="priceb" v-if="form.payStatus=='1'">{{ language==0?'已支付金额':'Amount Due' }}:<span class="price">{{ language==0?'¥':'€' }}{{ Number(totalFee).toFixed(2) }}</span></div> 119 <div class="priceb" v-else-if="form.payStatus=='1'">{{ language==0?'线下支付待核销':'Amount Due' }}:<span class="price">{{ language==0?'¥':'€' }}{{ Number(totalFee).toFixed(2) }}</span></div>
120 <div class="priceb" v-if="form.payStatus=='5'">{{ language==0?'已退款':'Refunded' }}:<span class="price">{{ language==0?'¥':'€' }}{{ Number(totalFee).toFixed(2) }}</span></div> 120 <div class="priceb" v-else-if="form.payStatus=='3'">{{ language==0?'已支付金额':'Amount Due' }}:<span class="price">{{ language==0?'¥':'€' }}{{ Number(totalFee).toFixed(2) }}</span></div>
121 <div class="priceb" v-else-if="form.payStatus=='5'">{{ language==0?'已退款':'Refunded' }}:<span class="price">{{ language==0?'¥':'€' }}{{ Number(totalFee).toFixed(2) }}</span></div>
122 <div class="priceb" v-else>{{ language==0?'费用总计':'Amount Due' }}:<span class="price">{{ language==0?'¥':'€' }}{{ Number(totalFee).toFixed(2) }}</span></div>
121 </el-col> 123 </el-col>
122 </el-row> 124 </el-row>
123 </el-card> 125 </el-card>
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
23 </el-form-item> 23 </el-form-item>
24 </el-col> 24 </el-col>
25 <el-col :lg="10"> 25 <el-col :lg="10">
26 <el-form-item :label="language==0?'代表国家/地区':'Representing'"> 26 <el-form-item :label="language==0?'代表国家/地区':'Representing'" required>
27 <el-select filterable v-model="form.countryId" @change="changeCountryId" 27 <el-select filterable v-model="form.countryId" @change="changeCountryId"
28 :disabled="form.type!='4'"> 28 :disabled="form.type!='4'">
29 <!-- <el-option v-for="item in countryList" :key="item.id" :label="language==0?item.name:item.enName" :value="item.id"/>--> 29 <!-- <el-option v-for="item in countryList" :key="item.id" :label="language==0?item.name:item.enName" :value="item.id"/>-->
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
26 <el-form-item :label="language==0?'参赛队名称':'Name of participating team'" required prop="abreviations"> 26 <el-form-item :label="language==0?'参赛队名称':'Name of participating team'" required prop="abreviations">
27 <el-input type="text" v-model="form.abreviations" :placeholder="language==0?'请输入内容':''"/> 27 <el-input type="text" v-model="form.abreviations" :placeholder="language==0?'请输入内容':''"/>
28 </el-form-item> 28 </el-form-item>
29 <el-form-item :label="language==0?'团体名称':'Team Name'" prop="name"> 29 <el-form-item :label="language==0?'团体名称':'Team Name'" prop="name" required>
30 <el-input v-model="form.name" :placeholder="language==0?'请输入团体名称':''" /> 30 <el-input v-model="form.name" :placeholder="language==0?'请输入团体名称':''" />
31 </el-form-item> 31 </el-form-item>
32 <el-form-item :label="language==0?'所属国家/地区':'Country'" required> 32 <el-form-item :label="language==0?'所属国家/地区':'Country'" required>
...@@ -43,12 +43,12 @@ ...@@ -43,12 +43,12 @@
43 <el-form-item :label="language==0?'邮箱':'Email'" required prop="contactEmail"> 43 <el-form-item :label="language==0?'邮箱':'Email'" required prop="contactEmail">
44 <el-input v-model="form.contactEmail" type="email" :placeholder="language==0?'请输入内容':''"/> 44 <el-input v-model="form.contactEmail" type="email" :placeholder="language==0?'请输入内容':''"/>
45 </el-form-item> 45 </el-form-item>
46 <!-- <el-form-item :label="language==0?'专业/业余':'Professional/Amateur'" required prop="majorFlag">--> 46 <el-form-item :label="language==0?'专业/业余':'Professional/Amateur'" required prop="majorFlag">
47 <!-- <el-select v-model="form.majorFlag">--> 47 <el-select v-model="form.majorFlag">
48 <!-- <el-option :label="language==0?'专业':'Professional'" value="1" />--> 48 <el-option :label="language==0?'专业':'Professional'" value="1" />
49 <!-- <el-option :label="language==0?'业余':'Amateur'" value="0" />--> 49 <el-option :label="language==0?'业余':'Amateur'" value="0" />
50 <!-- </el-select>--> 50 </el-select>
51 <!-- </el-form-item>--> 51 </el-form-item>
52 <el-form-item :label="language==0?'团体类型':'Group type'" prop="type"> 52 <el-form-item :label="language==0?'团体类型':'Group type'" prop="type">
53 <el-select :disabled="form.type=='4'" v-model="form.type" :placeholder="typeOptions[language].selectPlaceholder" style="width: 100%;"> 53 <el-select :disabled="form.type=='4'" v-model="form.type" :placeholder="typeOptions[language].selectPlaceholder" style="width: 100%;">
54 <el-option v-for="(o,index) in typeOptions[language].options" :label="o.text" 54 <el-option v-for="(o,index) in typeOptions[language].options" :label="o.text"
......
1 <script setup>
2 import { ElMessage } from "element-plus";
3 import { addViewPeople } from "./api/index.js";
4 import { languageFormat } from "./utils/language.js";
5 import { useStorage } from "@vueuse/core/index";
6 const language = useStorage("language", 0);
7
8 const router = useRouter();
9
10 const people = reactive({
11 form: {
12 name: "",
13 idCard: "",
14 },
15 type: language.value == 0 ? "身份证" : "Identity Card",
16 onConfirm() {
17 if (!people.form.name)
18 return ElMessage({
19 type: "warning",
20 message: languageFormat(language.value, "请输入姓名", "Name"),
21 });
22 if (!people.form.idCard)
23 return ElMessage({
24 type: "warning",
25 message: languageFormat(language.value, "请输入证件号", "ID Numbe"),
26 });
27
28 // 使用正则验证身份证号码格式
29 const idCardRegex =
30 /^[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]$/;
31 if (!idCardRegex.test(people.form.idCard) && language.value == 0)
32 return ElMessage({ type: "warning", message: "身份证号格式不正确" });
33
34 addViewPeople(people.form).then((res) => {
35 ElMessage({
36 type: "success",
37 message: languageFormat(language.value, "操作成功", "Operate successfully"),
38 });
39 router.go(-2);
40 });
41 },
42 });
43 </script>
44
45 <template>
46 <div class="container">
47 <div class="title">
48 {{ languageFormat(language, "新增观影人", "Companion") }}
49 </div>
50 <div class="content">
51 <div class="form-item">
52 <div>
53 <div class="label">
54 {{ languageFormat(language, "姓名", "Full Name") }}
55 </div>
56 <el-input
57 v-model="people.form.name"
58 style="width: 570px"
59 :placeholder="language == 0 ? '请输入姓名' : 'Nama'"
60 />
61 </div>
62 <div>
63 <div class="label">
64 {{ languageFormat(language, "证件类型", "Type of Document") }}
65 </div>
66 <el-input
67 v-model="people.type"
68 style="width: 570px"
69 placeholder="Please input"
70 readonly
71 />
72 </div>
73 </div>
74 <div class="form-item">
75 <div>
76 <div class="label">
77 {{ languageFormat(language, "身份证号", "Identity Card") }}
78 </div>
79 <el-input
80 v-model="people.form.idCard"
81 style="width: 570px"
82 :placeholder="language == 0 ? '请输入身份证号' : 'ID Numbe'"
83 />
84 </div>
85 </div>
86 </div>
87
88 <div class="footer">
89 <div class="can_pay">
90 {{ languageFormat(language, "取消", "Cancel") }}
91 </div>
92 <div class="pay" @click="people.onConfirm()">
93 {{ languageFormat(language, "确认", "Confirm") }}
94 </div>
95 </div>
96 </div>
97 </template>
98
99 <style scoped lang="scss">
100 div {
101 box-sizing: border-box;
102 }
103 .container {
104 padding: 20px 0;
105 width: 1200px;
106 margin: 0 auto;
107
108 .title {
109 padding: 11px;
110 text-align: center;
111 background: linear-gradient(270deg, #493ceb 0%, #8623fc 100%);
112 font-size: 18px;
113 color: #ffffff;
114 }
115
116 .content {
117 padding: 46px 20px 24px;
118 background-color: #fff;
119 :deep(.el-input) {
120 height: 48px;
121 border-radius: 24px !important;
122 }
123 .form-item {
124 display: flex;
125 gap: 20px;
126 margin-bottom: 36px;
127 &:last-child {
128 margin: 0;
129 }
130 .label {
131 font-size: 18px;
132 color: #333333;
133 margin-bottom: 16px;
134 }
135 }
136 }
137 .footer {
138 display: flex;
139 justify-content: center;
140 align-items: center;
141 gap: 20px;
142 height: 70px;
143 background-color: #fff;
144 margin-top: 12px;
145 .pay {
146 width: 200px;
147 height: 40px;
148 background: linear-gradient(270deg, #493ceb 0%, #8623fc 100%);
149 border-radius: 20px;
150 font-weight: 500;
151 font-size: 16px;
152 color: #ffffff;
153 line-height: 40px;
154 text-align: center;
155 cursor: pointer;
156 }
157 .can_pay {
158 width: 200px;
159 height: 40px;
160 background: #f6f6f6;
161 border-radius: 20px;
162 font-weight: 500;
163 font-size: 16px;
164 color: #999;
165 line-height: 40px;
166 text-align: center;
167 box-sizing: border-box;
168 cursor: pointer;
169 }
170 }
171 }
172 </style>
1 import request from "../utils/request";
2
3 export const loginFree = (data) => request("POST", "/login/loginFree", data);
4 /** 活动详情 */
5 export const activityDetail = (data) =>
6 request("GET", `/api/activity/detail/${data.actId}`, data);
7 /** 场次详情 */
8 export const sessionDetail = (data) =>
9 request("GET", `/api/activity/sessionDetail/${data.actId}`, data);
10 /** 获取场馆信息 */
11 export const getSitePlaceInfo = (data) =>
12 request("GET", `/api/activity/getSitePlaceInfo`, data);
13 /** 获取票档信息 */
14 export const getPriceLevelInfo = (data) =>
15 request("GET", `/api/activity/getPriceLevelInfo`, data);
16 /** 获取座位信息 */
17 export const getSiteConfig = (data) =>
18 request("GET", `/api/activity/getSiteConfig`, data);
19 /** 确认订单 */
20 export const confirmOrder = (data) =>
21 request("POST", `/api/order/confirmOrder`, data);
22 /** 订单支付 */
23 export const payOrder = (data) =>
24 request("POST", `/api/order/payment`, data);
25 /** 观众列表 */
26 export const viewPeopleList = (data) =>
27 request("GET", `/api/customer/list`, data);
28 /** 删除观众 */
29 export const deleteViewPeople = (data) =>
30 request("POST", `/api/customer/delete/${data.id}`, data);
31 /** 新增观众 */
32 export const addViewPeople = (data) =>
33 request("POST", `/api/customer/add`, data);
34 /** 订单列表 */
35 export const getOrderList = (data) =>
36 request("GET", `/api/order/list`, data);
37 /** 立即支付 */
38 export const immediatePay = (data) =>
39 request("POST", `/api/order/immediatePay`, data);
40 /** 取消支付 */
41 export const cancelPay = (data) =>
42 request("POST", `/api/order/cancelPay/${data.orderSn}`, data);
43 /** 退单 */
44 export const cancelOrder = (data) =>
45 request("POST", `/api/order/cancelOrder/${data.orderSn}`, data);
46 /** 订单详情 */
47 export const getOrderDetail = (data) =>
48 request("GET", `/api/order/detail/${data.orderSn}`, data);
49 /** 检查是否支付成功 */
50 export const checkPaySuccess = (data) =>
51 request("POST", `/api/order/checkOrderIsPay/${data.orderSn}`, data);
1 <script setup>
2 const props = defineProps({
3 showCodeDialog: {
4 type: Boolean,
5 default: false,
6 },
7 qrCode: {
8 type: String,
9 default: "",
10 },
11 });
12
13 const emit = defineEmits(["closeDialog"]);
14 const handleCloce = () => {
15 emit("closeDialog", false);
16 };
17 </script>
18
19 <template>
20 <div>
21 <el-dialog
22 v-model="props.showCodeDialog"
23 title="支付"
24 width="300"
25 :before-close="handleCloce()"
26 >
27 <div>
28 <img class="qrcode" :src="props.qrCode" />
29 </div>
30 </el-dialog>
31 </div>
32 </template>
33
34 <style scoped lang="scss">
35 .qrcode {
36 width: 150px;
37 height: 150px;
38 background-color: #8623fc;
39 margin: 0 auto;
40 }
41 </style>
1 <script setup>
2 import { confirmOrder } from "./api/index.js";
3 import { ElMessage } from "element-plus";
4 import { payOrder, viewPeopleList, checkPaySuccess } from "./api/index.js";
5 import qrCodeDialog from "./components/qrCodeDialog.vue";
6 import qrcode from "qrcode";
7 import { languageFormat } from "./utils/language.js";
8 import { useStorage } from "@vueuse/core/index";
9 const language = useStorage("language", 0);
10
11 const route = useRoute();
12 const router = useRouter();
13
14 const props = defineProps({
15 activityId: [String, Number],
16 });
17
18 let timer = null;
19 const startCheckSuccessListener = (orderSn, actId) => {
20 timer = setInterval(() => {
21 checkPaySuccess({ orderSn }).then((res) => {
22 if (res.data) {
23 clearInterval(timer);
24 timer = null;
25 // 支付成功
26 payment.showCodeDialog = false;
27 ElMessage({
28 type: "success",
29 message: anguageFormat(
30 language.value,
31 "支付成功",
32 "Payment succeeded"
33 ),
34 });
35 router.replace({
36 path: "/seat/order",
37 });
38 } else {
39 return false;
40 }
41 });
42 }, 3000);
43 };
44
45 const payment = reactive({
46 showCodeDialog: false,
47 btn_loading: false,
48 form: {
49 viewers: [],
50 phone: "",
51 },
52 qrInfo: {},
53 qrCodeData: "",
54 paymentHandle() {
55 if (payment.form.viewers.length != order.data?.seatInfo?.length)
56 return ElMessage({
57 type: "warning",
58 message: languageFormat(
59 language.value,
60 "观看人与购买票数不符",
61 "The number of viewers does not match the number of tickets purchased."
62 ),
63 });
64 if (!payment.form.phone)
65 return ElMessage({
66 type: "warning",
67 message: languageFormat(
68 language.value,
69 "请输入联系电话",
70 "Please enter the contact phone number."
71 ),
72 });
73 payOrder({
74 contactPhone: payment.form.phone,
75 customerIds: payment.form.viewers,
76 orderToken: order.data?.orderToken,
77 payType: 1,
78 paymentAmount: order.data?.paymentAmount,
79 }).then((res) => {
80 if (res.data.language == "zh-cn") {
81 payment.qrInfo = res.data;
82 qrcode.toDataURL(res.data.scanCodeUrl, (err, url) => {
83 if (url) {
84 payment.qrCodeData = url;
85 }
86 });
87 payment.showCodeDialog = true;
88 startCheckSuccessListener(res.data.orderSn, props.activityId);
89 } else {
90 // TODO: 这里是PayPal支付
91 }
92 });
93 },
94 handleCloce() {
95 payment.showCodeDialog = false;
96 payment.qrCodeData = "";
97 clearInterval(timer);
98 timer = null;
99 },
100 });
101
102 const order = reactive({
103 data: null,
104 fetchData() {
105 confirmOrder({
106 actId: props.activityId,
107 openType: route.query.openType,
108 sessionId: route.query.sessionId,
109 sitePlace: route.query.sitePlace,
110 ticketType: route.query.ticketType,
111 seatIds: route.query.seatIds.split(","),
112 }).then((res) => {
113 this.data = res.data;
114 });
115 },
116 });
117
118 const audience = reactive({
119 data: [],
120 fetchData() {
121 viewPeopleList().then((res) => {
122 audience.data = res.data;
123 });
124 },
125 });
126
127 onUnmounted(() => {
128 clearInterval(timer);
129 });
130
131 audience.fetchData();
132 order.fetchData();
133 </script>
134
135 <template>
136 <div class="container">
137 <div class="title">
138 {{ languageFormat(language, "订单确认", "Order confirmation") }}
139 </div>
140 <div class="content">
141 <div class="left">
142 <div class="info">
143 <div class="name">{{ order.data?.activityName }}</div>
144 <div class="address">{{ order.data?.placeName }}</div>
145 </div>
146
147 <div class="ticket_info">
148 <div class="tit_box">
149 <div class="line"></div>
150 <div class="txt">
151 {{ languageFormat(language, "订票信息", "Ticket Info") }}
152 </div>
153 </div>
154
155 <div class="form">
156 <el-form>
157 <el-form-item :label="language == 0 ? '联系人' : 'contacts'">
158 <el-input
159 v-model="payment.form.phone"
160 :placeholder="
161 language == 0
162 ? '请输入联系电话'
163 : 'Please enter the contact phone number'
164 "
165 style="width: 260px"
166 />
167 </el-form-item>
168 <el-form-item :label="language == 0 ? '观看人' : 'contacts'">
169 <div class="p_box">
170 <div class="people">
171 <el-checkbox-group
172 v-model="payment.form.viewers"
173 :max="order.data?.seatInfo?.length"
174 >
175 <div
176 v-for="(it, index) in audience.data"
177 :key="index"
178 class="prople_item"
179 >
180 <div>
181 <div class="name">{{ it.name }}</div>
182 <div class="idcard">{{ it.idCard }}</div>
183 </div>
184 <el-checkbox :value="it.id"> </el-checkbox>
185 </div>
186 </el-checkbox-group>
187 </div>
188 <!-- button -->
189 <div
190 class="btn"
191 @click="$router.push({ path: '/seat/people_manage' })"
192 >
193 {{ languageFormat(language, "新增", "Add") }}
194 </div>
195 </div>
196 </el-form-item>
197 </el-form>
198 </div>
199 </div>
200 </div>
201
202 <div class="right">
203 <div class="tit_box">
204 <div class="line"></div>
205 <div class="txt">
206 {{ languageFormat(language, "订单明细", "Order summary") }}
207 </div>
208 </div>
209
210 <div class="detail">
211 <div class="detail_top">
212 <div class="time">{{ order.data?.dateStr }}</div>
213 <div class="ticket">
214 {{ order.data?.singlePrice }}<span v-if="language == 0"></span
215 >{{ languageFormat(language, "票档", "Ticket file") }} x{{
216 order.data?.seatInfo?.length
217 }}{{ languageFormat(language, "张", "tickets") }}
218 </div>
219 </div>
220 <div class="detail_center">
221 <div
222 v-for="(it, index) in order.data?.seatInfo"
223 :key="index"
224 class="ticket"
225 >
226 <span v-if="it.venueId == 1"
227 >{{ it.area }}{{ languageFormat(language, "区", "Zones") }}
228 </span>
229 {{ it.pai }}{{ languageFormat(language, "排", "Row") }} {{ it.no
230 }}{{ languageFormat(language, "座", "Seat") }} ({{
231 it.venueId == 1 ? "B6" : "B4"
232 }}{{ languageFormat(language, "馆", "Venue") }})
233 </div>
234 </div>
235 <div class="detail_b">
236 <div class="sum_txt">
237 {{ languageFormat(language, "共计", "Total") }}
238 </div>
239 <div class="price_num">
240 <span v-if="language == 1">¥</span>{{ order.data?.paymentAmount }}
241 </div>
242 </div>
243 </div>
244 </div>
245 </div>
246 <div class="footer">
247 <div>
248 <span class="label"
249 >{{ languageFormat(language, "共计金额", "Subtotal") }}</span
250 ><span class="value">¥{{ order.data?.paymentAmount }}</span>
251 </div>
252 <div class="pay" @click="payment.paymentHandle()">
253 {{ languageFormat(language, "立即支付", "Pay Now") }}
254 </div>
255 </div>
256
257 <el-dialog
258 v-model="payment.showCodeDialog"
259 title="支付"
260 width="300"
261 @closed="payment.handleCloce()"
262 >
263 <div>
264 <img class="qrcode" :src="payment.qrCodeData" />
265 </div>
266 </el-dialog>
267 </div>
268 </template>
269
270 <style scoped lang="scss">
271 div {
272 box-sizing: border-box;
273 }
274 .qrcode {
275 width: 200px;
276 height: 200px;
277 margin: 0 auto;
278 }
279 .container {
280 padding: 20px 0;
281 width: 1200px;
282 margin: 0 auto;
283
284 .title {
285 padding: 11px;
286 text-align: center;
287 background: linear-gradient(270deg, #493ceb 0%, #8623fc 100%);
288 font-size: 18px;
289 color: #ffffff;
290 }
291
292 .content {
293 display: flex;
294 background-color: #fff;
295 padding: 20px 0;
296 }
297
298 .line {
299 width: 4px;
300 height: 18px;
301 background: linear-gradient(180deg, #493ceb 0%, #8623fc 100%);
302 border-radius: 4px;
303 }
304
305 .left {
306 padding-left: 20px;
307 .info {
308 width: 640px;
309 background: rgba(69, 61, 234, 0.04);
310 border-radius: 8px;
311 border: 1px solid #d3d1f6;
312 padding: 20px 0 28px 33px;
313 margin-bottom: 20px;
314 .name {
315 font-weight: 500;
316 font-size: 18px;
317 color: #000000;
318 margin-bottom: 20px;
319 }
320 .address {
321 font-weight: 400;
322 font-size: 14px;
323 color: #929aa0;
324 }
325 }
326
327 .ticket_info {
328 .tit_box {
329 display: flex;
330 align-items: center;
331 gap: 10px;
332 margin-bottom: 14px;
333 .txt {
334 font-weight: bold;
335 font-size: 16px;
336 color: #493ceb;
337 }
338 }
339 .form {
340 width: 640px;
341 min-height: 464px;
342 padding: 20px 60px;
343 border-radius: 5px;
344 border: 1px solid #dcdfe6;
345
346 .p_box {
347 display: flex;
348 gap: 10px;
349 .people {
350 width: 298px;
351 background: #fbfcfd;
352 border-radius: 2px;
353 border: 1px solid #dcdfe6;
354 padding: 0 14px;
355 .prople_item {
356 display: flex;
357 justify-content: space-between;
358 align-items: center;
359 padding: 14px 0;
360 border-bottom: 1px solid #dcdfe6;
361 &:last-child {
362 border: none;
363 }
364 .name {
365 font-size: 16px;
366 color: #929aa0;
367 margin-bottom: 20px;
368 }
369 .idcard {
370 font-size: 10px;
371 color: #929aa0;
372 }
373 }
374 }
375 .btn {
376 width: 90px;
377 height: 40px;
378 background: #fbfcfd;
379 border-radius: 20px;
380 border: 1px solid #493ceb;
381 margin-top: 10px;
382 font-size: 14px;
383 color: #493ceb;
384 line-height: 40px;
385 text-align: center;
386 cursor: pointer;
387 user-select: none;
388 }
389 }
390 }
391 }
392 }
393
394 .right {
395 width: 460px;
396 margin-left: 36px;
397 .tit_box {
398 display: flex;
399 align-items: center;
400 gap: 10px;
401 margin-bottom: 20px;
402 .txt {
403 font-weight: bold;
404 font-size: 16px;
405 color: #493ceb;
406 }
407 }
408
409 .detail {
410 padding: 15px 26px;
411 border-radius: 5px;
412 border: 1px solid #dcdfe6;
413 .detail_top {
414 padding-bottom: 13px;
415 border-bottom: 1px solid #dcdfe6;
416 .time {
417 font-weight: 500;
418 font-size: 18px;
419 color: #2d373f;
420 line-height: 25px;
421 margin-bottom: 8px;
422 }
423 .ticket {
424 font-size: 16px;
425 color: #2d373f;
426 }
427 }
428 .detail_center {
429 margin-top: 14px;
430 display: flex;
431 flex-direction: column;
432 padding-bottom: 13px;
433 border-bottom: 1px solid #dcdfe6;
434 gap: 8px;
435 .ticket {
436 font-size: 16px;
437 color: #2d373f;
438 }
439 }
440 .detail_b {
441 display: flex;
442 justify-content: space-between;
443 align-items: center;
444 margin-top: 16px;
445 .sum_txt {
446 font-weight: 600;
447 font-size: 18px;
448 color: #2d373f;
449 line-height: 25px;
450 }
451 .price_num {
452 font-weight: 600;
453 font-size: 36px;
454 color: #ff8124;
455 line-height: 50px;
456 }
457 }
458 }
459 }
460
461 .footer {
462 display: flex;
463 justify-content: space-between;
464 height: 70px;
465 align-items: center;
466 background: #ffffff;
467 box-shadow: 0px 0px 46px 0px rgba(1, 16, 64, 0.08);
468 margin-top: 9px;
469 padding: 0 30px;
470 .label {
471 font-size: 16px;
472 color: #7b7f83;
473 line-height: 22px;
474 }
475 .value {
476 font-size: 22px;
477 color: #ff8124;
478 line-height: 30px;
479 font-weight: 600;
480 }
481 .pay {
482 width: 200px;
483 height: 40px;
484 background: linear-gradient(270deg, #493ceb 0%, #8623fc 100%);
485 border-radius: 20px;
486 font-weight: 500;
487 font-size: 16px;
488 color: #ffffff;
489 line-height: 40px;
490 text-align: center;
491 cursor: pointer;
492 user-select: none;
493 }
494 }
495 }
496 </style>
1 <script setup>
2 import { onBeforeUnmount, reactive } from "vue";
3 import {
4 cancelOrder,
5 getOrderDetail,
6 immediatePay,
7 cancelPay,
8 checkPaySuccess,
9 } from "./api/index.js";
10 import qrCodeDialog from "./components/qrCodeDialog.vue";
11 import { ElMessageBox, ElMessage } from "element-plus";
12 import qrcode from "qrcode";
13 import { languageFormat } from "./utils/language.js";
14 import { useStorage } from "@vueuse/core/index";
15 const language = useStorage("language", 0);
16
17 const route = useRoute();
18 const router = useRouter();
19
20 const status = reactive({
21 0: {
22 txt: "待支付",
23 color: "#F740A6",
24 bgColor: "#FFE2F2",
25 },
26 1: {
27 txt: "购票成功",
28 color: "#FFCC00",
29 bgColor: "#FFF7D9",
30 },
31 2: {
32 txt: "交易关闭",
33 color: "#757575",
34 bgColor: "#DDDDDD",
35 },
36 3: {
37 txt: "已退款",
38 color: "#757575",
39 bgColor: "#DDDDDD",
40 },
41 4: {
42 color: "#F740A6",
43 bgColor: "#FFE2F2",
44 },
45 5: {
46 txt: "完成",
47 color: "#34C759",
48 bgColor: "#D2FFDD",
49 },
50 });
51
52 const props = defineProps({
53 activityId: [String, Number],
54 });
55
56 let timer = null;
57 const startCheckSuccessListener = (orderSn, actId) => {
58 timer = setInterval(() => {
59 checkPaySuccess({ orderSn }).then((res) => {
60 if (res.data) {
61 clearInterval(timer);
62 timer = null;
63 // 支付成功
64 detail.showCodeDialog = false;
65 detail.fetchData();
66 ElMessage({ type: "success", message: "支付成功" });
67 } else {
68 return false;
69 }
70 });
71 }, 3000);
72 };
73
74 const detail = reactive({
75 showCodeDialog: false,
76 qrCodeData: "",
77 pay_loading: false,
78 qrInfo: {},
79 data: null,
80 timer: null,
81
82 // 分钟
83 minutes: 0,
84 seconds: 0,
85 fetchData() {
86 getOrderDetail({ orderSn: route.query.orderSn }).then((res) => {
87 detail.data = res.data;
88 detail.countDown(detail.data?.payEndTime);
89 });
90 },
91 // 倒计时
92 countDown(time) {
93 // 当前时间
94 let nowTime = new Date();
95 let endTime = new Date(time);
96 // 两个日期相差的时间戳,以毫秒为单位(1000ms = 1s)
97 let totalTime = endTime - nowTime;
98 // 结束时间大于现在的时间
99 if (totalTime > 0) {
100 detail.timer = setInterval(() => {
101 if (totalTime >= 0) {
102 //获取分钟数
103 let minutes = Math.floor(
104 (((totalTime % (3600 * 24 * 1000)) / 1000) % 3600) / 60
105 );
106 //获取秒数
107 let seconds = Math.floor(
108 (((totalTime % (3600 * 24 * 1000)) / 1000) % 3600) % 60
109 )
110 .toString()
111 .padStart(2, "0");
112
113 detail.minutes = minutes;
114 detail.seconds = seconds;
115
116 totalTime -= 1000;
117 // console.log(totalTime)
118 } else {
119 clearInterval(detail.timer); // 停止调用函数
120 detail.fetchData();
121 }
122 }, 1000);
123 }
124 },
125 payment() {
126 if (detail.pay_loading) return;
127 detail.pay_loading = true;
128 immediatePay({ orderSn: detail.data.orderSn, payType: 1 })
129 .then((res) => {
130 if (res.data.language == "zh-cn") {
131 detail.qrInfo = res.data;
132 qrcode.toDataURL(res.data.scanCodeUrl, (err, url) => {
133 if (url) {
134 detail.qrCodeData = url;
135 }
136 });
137 startCheckSuccessListener(detail.data.orderSn);
138 detail.showCodeDialog = true;
139 } else {
140 // TODO: 这里是PayPal支付
141 }
142 })
143 .finally(() => (detail.pay_loading = false));
144 },
145 handleClose() {
146 detail.showCodeDialog = false;
147 detail.qrCodeData = "";
148 clearInterval(timer);
149 timer = null;
150 },
151 // 取消支付
152 cancelPay() {
153 ElMessageBox.confirm(
154 languageFormat(
155 language.value,
156 "确认取消支付吗?",
157 "Are you sure to cancel?"
158 ),
159 languageFormat(language.value, "提示", "tip"),
160 {
161 confirmButtonText: languageFormat(language.value, "确认", "confirm"),
162 cancelButtonText: languageFormat(language.value, "取消", "cancel"),
163 type: "warning",
164 draggable: true,
165 }
166 )
167 .then(() => {
168 cancelPay({ orderSn: detail.data.orderSn }).then(() => {
169 detail.fetchData();
170 ElMessage({
171 type: "success",
172 message: languageFormat(
173 language.value,
174 "操作成功",
175 "Operate successfully"
176 ),
177 });
178 });
179 })
180 .catch(() => {});
181 },
182 // 取消购票
183 cancelOrder() {
184 ElMessageBox.confirm(
185 languageFormat(
186 language.value,
187 "确认取消购票吗?",
188 "Are you sure to cancel?"
189 ),
190 languageFormat(language.value, "提示", "tip"),
191 {
192 confirmButtonText: languageFormat(language.value, "确认", "confirm"),
193 cancelButtonText: languageFormat(language.value, "取消", "cancel"),
194 type: "warning",
195 draggable: true,
196 }
197 )
198 .then(() => {
199 cancelOrder({ orderSn: detail.data.orderSn }).then((res) => {
200 detail.fetchData();
201 ElMessage({
202 type: "success",
203 message: languageFormat(
204 language.value,
205 "操作成功",
206 "Operate successfully"
207 ),
208 });
209 });
210 })
211 .catch(() => {});
212 },
213 comeBack() {
214 router.push({
215 path: "/seat/detail",
216 query: {
217 id: props.activityId,
218 },
219 });
220 },
221 });
222
223 onBeforeUnmount(() => {
224 clearInterval(detail.timer);
225 clearInterval(timer);
226 });
227
228 detail.fetchData();
229 </script>
230
231 <template>
232 <div class="container">
233 <div class="left">
234 <!-- 票务信息 -->
235 <div class="ticket">
236 <div class="th">
237 <div style="width: 33%" class="td">
238 {{ languageFormat(language, "票务信息", "Ticket Info") }}
239 </div>
240 <div style="width: 25%" class="td">
241 {{ languageFormat(language, "地点", "Venue") }}
242 </div>
243 <div style="width: 20%" class="td">
244 {{ languageFormat(language, "单价", "Price") }}
245 </div>
246 <div style="width: 10%" class="td">
247 {{ languageFormat(language, "数量", "Ticket Qty.") }}
248 </div>
249 <div style="width: 12%; text-align: right" class="td">
250 {{ languageFormat(language, "小计", "Subtotal") }}
251 </div>
252 </div>
253 <div class="line"></div>
254 <div class="tr">
255 <div style="width: 30%" class="td">{{ detail.data?.name }}</div>
256 <div style="width: 25%" class="td">{{ detail.data?.placeName }}</div>
257 <div style="width: 20%" class="td">
258 ¥{{ detail.data?.singlePrice }}
259 </div>
260 <div style="width: 12%" class="td">
261 x{{ detail.data?.seatList?.length }}
262 </div>
263 <div style="width: 13%; text-align: right" class="td">
264 ¥{{ detail.data?.payAmount }}
265 </div>
266 </div>
267 </div>
268 <!-- 座位 -->
269 <div class="seat_box">
270 <div class="th">
271 <div style="width: 30.33%" class="td">
272 {{ languageFormat(language, "时间座位", "Seat Info") }}
273 </div>
274 <div style="width: 30.33%" class="td">
275 {{ languageFormat(language, "订单信息", "Summary") }}
276 </div>
277 <div style="width: 30.33%" class="td">
278 {{ languageFormat(language, "联系方式", "Contact details") }}
279 </div>
280 </div>
281 <div class="tr">
282 <div style="width: 30.33%" class="td flex-col">
283 <div>{{ detail.data?.dateStr }}</div>
284 <div v-for="(it, index) in detail.data?.seatList" :key="index">
285 <span v-if="it.venueId == 1"
286 >{{ it.area
287 }}{{ languageFormat(language, "区", "Zones") }}</span
288 >{{ it.pai }}{{ languageFormat(language, "排", "Row") }}{{ it.no
289 }}{{ languageFormat(language, "座", "Seat") }} ({{
290 it.venueId == 1 ? "B6" : "B4"
291 }}{{ languageFormat(language, "馆", "Venue") }})
292 </div>
293 </div>
294 <div style="width: 30.33%" class="td flex-col">
295 <div>
296 {{ languageFormat(language, "订单编号", "Order No.") }}{{
297 detail.data?.orderSn
298 }}
299 </div>
300 <div>
301 {{ languageFormat(language, "创建时间", "Order Time") }}{{
302 detail.data?.orderTime
303 }}
304 </div>
305 </div>
306 <div style="width: 30.33%" class="td">
307 <div>
308 {{ languageFormat(language, "联系电话", "Telephone") }}{{
309 detail.data?.contactPhone
310 }}
311 </div>
312 </div>
313 </div>
314 </div>
315 <!-- 购票人 -->
316 <div class="pay_ticket">
317 <div class="title">
318 {{ languageFormat(language, "购票人", "Full Name") }}
319 </div>
320 <div class="people">
321 <div
322 v-for="(it, index) in detail.data?.customerList"
323 :key="index"
324 class="p_info"
325 >
326 <div>{{ it.name }}</div>
327 <div class="idcard">
328 {{ languageFormat(language, "身份证", "ID number") }}{{
329 it.idCard
330 }}
331 </div>
332 </div>
333 </div>
334 </div>
335 </div>
336
337 <div class="right">
338 <div class="balance">
339 <div class="title">
340 {{ languageFormat(language, "结算信息", "Payment details") }}
341 </div>
342 <div class="cell">
343 <div class="label">
344 {{ languageFormat(language, "订单状态", "Order Status") }}
345 </div>
346 <div
347 class="value"
348 :style="{ color: status[detail.data?.state]?.color }"
349 >
350 {{ status[detail.data?.state]?.txt }}
351 </div>
352 </div>
353 <div class="cell">
354 <div class="label">
355 {{ languageFormat(language, "订单金额", "Order amount") }}
356 </div>
357 <div
358 class="value"
359 :style="{ color: status[detail.data?.state]?.color }"
360 >
361 <span v-if="language == 0">¥</span>{{ detail.data?.payAmount }}
362 </div>
363 </div>
364 <!-- button -->
365 <div v-if="detail.data?.state == 0" class="btn_box">
366 <div class="can_pay" @click="detail.cancelPay()">
367 {{ languageFormat(language, "取消支付", "Cancel the payment") }}
368 </div>
369 <div class="pay" @click="detail.payment()">
370 {{ languageFormat(language, "立即支付", "Pay Now") }}
371 </div>
372 </div>
373 <div v-else>
374 <!-- v-if="detail.data?.state == 1 && detail.data?.isRefund" -->
375 <div
376 v-if="detail.data?.state == 1 && detail.data?.isRefund"
377 class="btn_box"
378 >
379 <div class="can_pay" @click="detail.cancelOrder()">
380 {{
381 languageFormat(
382 language,
383 "取消购票",
384 "Cancel the ticket purchase"
385 )
386 }}
387 </div>
388 <div class="pay" @click="detail.comeBack()">
389 {{ languageFormat(language, "再来一单", "Make another order") }}
390 </div>
391 </div>
392
393 <div v-else class="btn_box">
394 <div class="pay_dis">
395 {{
396 languageFormat(
397 language,
398 "请联系工作人员",
399 "Please contact the staff"
400 )
401 }}
402 </div>
403 </div>
404 </div>
405 </div>
406 <div v-if="detail.data?.state == 0" class="tip">
407 <span v-if="language == 0"
408 >请尽快完成支付,还剩{{ detail.minutes }}{{
409 detail.seconds
410 }}</span
411 >
412 <span v-if="language == 1"
413 >Time left {{ detail.minutes }}:{{ detail.seconds }}</span
414 >
415 </div>
416 </div>
417
418 <!-- <qrCodeDialog
419 :showCodeDialog="detail.showCodeDialog"
420 :qrCode="detail.qrCodeData"
421 /> -->
422
423 <el-dialog
424 v-model="detail.showCodeDialog"
425 title="支付"
426 width="300"
427 @closed="detail.handleClose()"
428 >
429 <div>
430 <img class="qrcode" :src="detail.qrCodeData" />
431 </div>
432 </el-dialog>
433 </div>
434 </template>
435
436 <style scoped lang="scss">
437 .qrcode {
438 width: 200px;
439 height: 200px;
440 margin: 0 auto;
441 }
442 .container {
443 width: 1200px;
444 margin: 0 auto;
445 padding: 20px 0;
446 display: flex;
447 gap: 20px;
448 .left {
449 width: 780px;
450 // 票务信息
451 .ticket {
452 background-color: #fff;
453 padding: 0 20px;
454 .th {
455 display: flex;
456 justify-content: space-between;
457 padding: 20px 0;
458 .td {
459 font-weight: bold;
460 font-size: 16px;
461 color: #333333;
462 line-height: 24px;
463 }
464 }
465 .line {
466 width: 740px;
467 height: 1px;
468 background: #eee;
469 }
470 .tr {
471 display: flex;
472 justify-content: space-between;
473 padding: 20px 0;
474 .td {
475 font-weight: 400;
476 font-size: 16px;
477 color: #333333;
478 line-height: 24px;
479 }
480 }
481 }
482 // 座位
483 .seat_box {
484 background-color: #fff;
485 padding: 0 20px;
486 margin-top: 20px;
487 .th {
488 display: flex;
489 justify-content: space-between;
490 padding: 20px 0;
491 .td {
492 font-weight: bold;
493 font-size: 16px;
494 color: #333333;
495 line-height: 24px;
496 }
497 }
498 .tr {
499 display: flex;
500 justify-content: space-between;
501 padding: 20px 0;
502 .td {
503 font-weight: 400;
504 font-size: 16px;
505 color: #333333;
506 line-height: 24px;
507 }
508 .flex-col {
509 display: flex;
510 flex-direction: column;
511 gap: 16px;
512 }
513 }
514 }
515 // 购票人
516 .pay_ticket {
517 background-color: #fff;
518 padding: 20px;
519 margin-top: 20px;
520 .title {
521 font-weight: bold;
522 font-size: 16px;
523 color: #333333;
524 margin-bottom: 28px;
525 }
526 .people {
527 display: flex;
528 justify-content: space-between;
529 flex-wrap: wrap;
530 gap: 15px 50px;
531 .p_info {
532 font-weight: 400;
533 font-size: 16px;
534 color: #333333;
535 line-height: 24px;
536 .idcard {
537 color: #999999;
538 }
539 }
540 }
541 }
542 }
543 .right {
544 width: 400px;
545 .balance {
546 background-color: #fff;
547 padding: 20px;
548 .title {
549 font-weight: bold;
550 font-size: 20px;
551 color: #333333;
552 line-height: 30px;
553 margin-bottom: 28px;
554 }
555 .cell {
556 display: flex;
557 justify-content: space-between;
558 align-items: center;
559 margin-bottom: 20px;
560 &:last-child {
561 margin: 0;
562 }
563 .label {
564 font-weight: 400;
565 font-size: 16px;
566 color: #333333;
567 }
568 .value {
569 font-weight: 400;
570 font-size: 16px;
571 color: #ff8124;
572 }
573 }
574 .btn_box {
575 border-top: 1px solid #eee;
576 padding-top: 20px;
577 display: flex;
578 gap: 20px;
579 user-select: none;
580 .pay_dis {
581 width: 360px;
582 height: 40px;
583 background: #a09dff;
584 border-radius: 20px;
585 font-weight: 500;
586 font-size: 16px;
587 color: #ffffff;
588 line-height: 40px;
589 text-align: center;
590 cursor: pointer;
591 }
592 .pay {
593 width: 170px;
594 height: 40px;
595 background: linear-gradient(270deg, #493ceb 0%, #8623fc 100%);
596 border-radius: 20px;
597 font-weight: 500;
598 font-size: 16px;
599 color: #ffffff;
600 line-height: 40px;
601 text-align: center;
602 cursor: pointer;
603 }
604 .can_pay {
605 width: 170px;
606 height: 40px;
607 background: #f6f6f6;
608 border-radius: 20px;
609 font-weight: 500;
610 font-size: 16px;
611 color: #999;
612 line-height: 40px;
613 text-align: center;
614 box-sizing: border-box;
615 cursor: pointer;
616 }
617 }
618 }
619 .tip {
620 font-weight: 400;
621 font-size: 16px;
622 color: #ea3d6b;
623 line-height: 24px;
624 margin-top: 20px;
625 text-align: center;
626 }
627 }
628 }
629 </style>
1 <script setup>
2 import { setToken, getToken } from "./utils/local-store.js";
3 import useUserStore from "@/store/modules/user";
4 import {
5 getOrderList,
6 immediatePay,
7 cancelPay,
8 loginFree,
9 } from "./api/index.js";
10 import qrCodeDialog from "./components/qrCodeDialog.vue";
11 import { ElMessageBox, ElMessage } from "element-plus";
12 import qrcode from "qrcode";
13 import { md5 } from "md5js";
14 import { languageFormat } from "./utils/language.js";
15 import { useStorage } from "@vueuse/core/index";
16 const language = useStorage("language", 0);
17
18 const userStore = useUserStore();
19
20 const status = reactive({
21 0: {
22 txt: "待支付",
23 text_en: "Pending Payment",
24 color: "#F740A6",
25 bgColor: "#FFE2F2",
26 },
27 1: {
28 txt: "购票成功",
29 text_en: "Transaction completed",
30 color: "#FFCC00",
31 bgColor: "#FFF7D9",
32 },
33 2: {
34 txt: "交易关闭",
35 text_en: "Transaction closed",
36 color: "#757575",
37 bgColor: "#DDDDDD",
38 },
39 3: {
40 txt: "已退款",
41 text_en: "Already refunded",
42 color: "#757575",
43 bgColor: "#DDDDDD",
44 },
45 4: {
46 txt: "退款中",
47 text_en: "In the process of refunding",
48 color: "#F740A6",
49 bgColor: "#FFE2F2",
50 },
51 5: {
52 txt: "完成",
53 text_en: "Finish",
54 color: "#34C759",
55 bgColor: "#D2FFDD",
56 },
57 });
58 const props = defineProps({
59 activityId: [String, Number],
60 });
61
62 const order = reactive({
63 showCodeDialog: false,
64 qrInfo: {},
65 pay_loading: false,
66 pageNo: 1,
67 pageSize: 10,
68 total: 0,
69
70 noPay: {},
71 minutes: 0,
72 seconds: 0,
73 data: [],
74 timer: null,
75 qrCodeData: "",
76 fetchData() {
77 getOrderList({ pageNo: order.pageNo, pageSize: order.pageSize }).then(
78 (res) => {
79 order.noPay = res.data.lists.find((it) => it.state == 0);
80 order.data = res.data.lists;
81 order.total = res.data.count;
82 }
83 );
84 },
85 payment(it) {
86 if (order.pay_loading) return;
87 order.pay_loading = true;
88 immediatePay({ orderSn: it.orderSn, payType: 1 })
89 .then((res) => {
90 order.qrInfo = res.data;
91 qrcode.toDataURL(res.data.scanCodeUrl, (err, url) => {
92 if (err) {
93 console.error(err);
94 } else {
95 order.qrCodeData = url;
96 }
97 });
98 order.showCodeDialog = true;
99 })
100 .finally(() => (order.pay_loading = false));
101 },
102 handleClose() {
103 order.showCodeDialog = false;
104 order.qrCodeData = "";
105 },
106 // 取消支付
107 cancelPayment(it) {
108 ElMessageBox.confirm(
109 languageFormat(
110 language.value,
111 "确认取消支付吗?",
112 "Are you sure to cancel the payment?"
113 ),
114 languageFormat(language.value, "提示", "tip"),
115 {
116 confirmButtonText: languageFormat(language.value, "确认", "confirm"),
117 cancelButtonText: languageFormat(language.value, "取消", "cancel"),
118 type: "warning",
119 draggable: true,
120 }
121 )
122 .then(() => {
123 cancelPay({ orderSn: it.orderSn }).then(() => {
124 order.fetchData();
125 ElMessage({
126 type: "success",
127 message: languageFormat(
128 language.value,
129 "操作成功",
130 "Operate successfully"
131 ),
132 });
133 });
134 })
135 .catch(() => {});
136 },
137 countDown(time) {
138 // 当前时间
139 let nowTime = new Date();
140 let endTime = new Date(time);
141 // 两个日期相差的时间戳,以毫秒为单位(1000ms = 1s)
142 let totalTime = endTime - nowTime;
143 // 结束时间大于现在的时间
144 if (totalTime > 0) {
145 order.timer = setInterval(() => {
146 if (totalTime >= 0) {
147 //获取分钟数
148 let minutes = Math.floor(
149 (((totalTime % (3600 * 24 * 1000)) / 1000) % 3600) / 60
150 );
151 //获取秒数
152 let seconds = Math.floor(
153 (((totalTime % (3600 * 24 * 1000)) / 1000) % 3600) % 60
154 )
155 .toString()
156 .padStart(2, "0");
157
158 order.minutes = minutes;
159 order.seconds = seconds;
160
161 totalTime -= 1000;
162 // console.log(totalTime)
163 } else {
164 clearInterval(order.timer); // 停止调用函数
165 }
166 }, 1000);
167 }
168 },
169 });
170
171 watch(
172 () => order.noPay,
173 (val) => {
174 if (val) {
175 order.countDown(val.payEndTime);
176 }
177 }
178 );
179
180 onUnmounted(() => {
181 clearInterval(order.timer);
182 });
183
184 // 用户免登录
185 const login = async () => {
186 const userId = userStore.user?.userId;
187 const sign = md5(`uid=${userId}lgo1acfkw51jfo`, 32);
188 return loginFree({
189 userId: userId,
190 sign,
191 }).then((res) => {
192 setToken(res.data.token);
193 order.fetchData();
194 });
195 };
196 onMounted(() => {
197 login();
198 });
199 </script>
200
201 <template>
202 <div class="container">
203 <div
204 v-for="(it, index) in order.data"
205 :key="index"
206 @click="
207 $router.push({
208 path: '/seat/order_detail',
209 query: { orderSn: it.orderSn, id: it.actId },
210 })
211 "
212 class="order-item"
213 >
214 <div class="info_box">
215 <img class="cover_img" :src="it.coverImg" />
216 <div class="info">
217 <div class="title">{{ it.name }}</div>
218 <div class="common">
219 {{ languageFormat(language, "时间", "Event Date & Time") }}{{
220 it.dateStr
221 }}
222 </div>
223 <div class="common">
224 {{ languageFormat(language, "地址", "Location") }}{{
225 it.placeName
226 }}
227 </div>
228 <div class="common">
229 {{ languageFormat(language, "订单编号", "Order No.") }}{{
230 it.orderSn
231 }}
232 </div>
233 <div class="common">
234 {{ languageFormat(language, "张数", "Location") }}{{ it.ticketNum
235 }}{{ languageFormat(language, "张", "tickets") }}
236 </div>
237 <div class="common">
238 {{ languageFormat(language, "金额", "Ticket Price") }}<span
239 v-if="language == 0"
240 ></span
241 >{{ it.payAmount }}
242 </div>
243 <div class="status">
244 <div class="label">
245 {{ languageFormat(language, "订单状态", "Order Status") }}
246 </div>
247 <div class="value">
248 <div
249 :style="{
250 borderColor: status[it.state].color,
251 background: status[it.state].bgColor,
252 color: status[it.state].color,
253 }"
254 class="tag"
255 >
256 {{
257 language == 0 ? status[it.state].txt : status[it.state].txt_en
258 }}
259 </div>
260 <div v-if="it.state == 0" class="tip">
261 <span v-if="language == 0"
262 >请尽快完成支付,还剩{{ order.minutes }}{{
263 order.seconds
264 }}</span
265 >
266 <span v-else
267 >Time left {{ order.minutes }}:{{ order.seconds }}</span
268 >
269 </div>
270 </div>
271 </div>
272 </div>
273 </div>
274 <div v-if="it.state == 0" class="btn_box">
275 <div class="pay">立即支付</div>
276 <div class="can_pay" @click.stop="order.cancelPayment(it)">
277 取消支付
278 </div>
279 </div>
280 </div>
281
282 <div class="pagination">
283 <el-pagination
284 v-show="order.total > 0"
285 v-model:current-page="order.pageNo"
286 v-model:page-size="order.pageSize"
287 background
288 layout="prev, pager, next"
289 :total="order.total"
290 @current-change="order.fetchData()"
291 />
292 </div>
293
294 <el-dialog
295 v-model="order.showCodeDialog"
296 title="支付"
297 width="300"
298 @closed="order.handleClose()"
299 >
300 <div>
301 <img class="qrcode" :src="order.qrCodeData" />
302 </div>
303 </el-dialog>
304 </div>
305 </template>
306
307 <style scoped lang="scss">
308 .qrcode {
309 width: 150px;
310 height: 150px;
311 margin: 0 auto;
312 }
313 .container {
314 width: 1200px;
315 margin: 0 auto;
316 padding: 26px 0;
317 font-family: SourceHanSansCN, SourceHanSansCN;
318 .order-item {
319 display: flex;
320 justify-content: space-between;
321 align-items: center;
322 padding: 36px;
323 background: #fff;
324 box-shadow: 0px 0px 46px 0px rgba(1, 16, 64, 0.08);
325 border-radius: 8px;
326 margin-bottom: 30px;
327 cursor: pointer;
328 .info_box {
329 display: flex;
330 gap: 20px;
331 .cover_img {
332 width: 155px;
333 height: 200px;
334 object-fit: fill;
335 }
336 .info {
337 .title {
338 font-weight: bold;
339 font-size: 22px;
340 color: #000000;
341 line-height: 33px;
342 margin-bottom: 25px;
343 margin-bottom: 10px;
344 }
345 .common {
346 font-weight: 500;
347 font-size: 16px;
348 color: #4e4e4e;
349 margin-bottom: 6px;
350 }
351 .status {
352 display: flex;
353
354 .label {
355 font-weight: 500;
356 font-size: 16px;
357 color: #4e4e4e;
358 line-height: 24px;
359 }
360 .value {
361 display: flex;
362 align-items: center;
363 gap: 20px;
364 .tag {
365 padding: 6px 14px;
366 border-radius: 6px;
367 border: 1px solid #34c759;
368 }
369 .tip {
370 font-size: 16px;
371 color: #f740a6;
372 line-height: 24px;
373 }
374 }
375 }
376 }
377 }
378 .btn_box {
379 display: flex;
380 flex-direction: column;
381 gap: 12px;
382 .pay {
383 width: 175px;
384 height: 40px;
385 background: linear-gradient(270deg, #493ceb 0%, #8623fc 100%);
386 border-radius: 20px;
387 font-weight: 500;
388 font-size: 16px;
389 color: #ffffff;
390 line-height: 40px;
391 text-align: center;
392 cursor: pointer;
393 }
394 .can_pay {
395 width: 175px;
396 height: 40px;
397 background: #fff;
398 border-radius: 20px;
399 font-weight: 500;
400 font-size: 16px;
401 color: #493ceb;
402 line-height: 40px;
403 border: 1px solid #493ceb;
404 text-align: center;
405 box-sizing: border-box;
406 cursor: pointer;
407 }
408 }
409 }
410 }
411
412 .pagination {
413 display: flex;
414 justify-content: center;
415 }
416 </style>
1 <script setup>
2 import { deleteViewPeople, viewPeopleList } from "./api/index.js";
3 import { ElMessageBox, ElMessage } from "element-plus";
4 import { languageFormat } from "./utils/language.js";
5 import { useStorage } from "@vueuse/core/index";
6 const language = useStorage("language", 0);
7
8 const audience = reactive({
9 data: [],
10 fetchData() {
11 viewPeopleList().then((res) => {
12 audience.data = res.data;
13 });
14 },
15
16 deletePeople(id) {
17 ElMessageBox.confirm(
18 languageFormat(
19 language.value,
20 "确认删除该观看人吗?",
21 "Are you sure to delete this viewer?"
22 ),
23 languageFormat(language.value, "提示", "Reminder"),
24 {
25 confirmButtonText: languageFormat(language.value, "确认", "confirm"),
26 cancelButtonText: languageFormat(language.value, "取消", "cancel"),
27 type: "warning",
28 draggable: true,
29 }
30 )
31 .then(() => {
32 deleteViewPeople({ id }).then(() => {
33 audience.fetchData();
34 ElMessage({
35 type: "success",
36 message: languageFormat(
37 language.value,
38 "操作成功",
39 "Operate successfully"
40 ),
41 });
42 });
43 })
44 .catch(() => {});
45 },
46 });
47
48 audience.fetchData();
49 </script>
50
51 <template>
52 <div class="container">
53 <div class="title">
54 <div
55 class="add_btn"
56 @click="$router.push({ path: '/seat/add_watch_people' })"
57 >
58 {{ languageFormat(language, "新增", "Add") }}
59 </div>
60 {{ languageFormat(language, "观影人管理", "Viewers") }}
61 </div>
62 <div class="content">
63 <div class="people_box">
64 <div
65 v-for="(it, index) in audience.data"
66 :key="index"
67 class="people_item"
68 >
69 <div class="name">{{ it.name }}</div>
70 <div class="idcard">
71 {{ languageFormat(language, "身份证", "Identity Card") }}{{
72 it.idCard
73 }}
74 </div>
75 <div class="btn" @click="audience.deletePeople(it.id)">
76 {{ languageFormat(language, "删除", "delete") }}
77 </div>
78 </div>
79 </div>
80 </div>
81 </div>
82 </template>
83
84 <style scoped lang="scss">
85 div {
86 box-sizing: border-box;
87 }
88 .container {
89 padding: 20px 0;
90 width: 1200px;
91 margin: 0 auto;
92
93 .title {
94 position: relative;
95 padding: 11px;
96 text-align: center;
97 background: linear-gradient(270deg, #493ceb 0%, #8623fc 100%);
98 font-size: 18px;
99 color: #ffffff;
100 .add_btn {
101 position: absolute;
102 left: 20px;
103 top: 50%;
104 transform: translateY(-50%);
105 width: 68px;
106 height: 24px;
107 border-radius: 12px;
108 border: 1px solid #ffffff;
109 font-weight: 400;
110 font-size: 12px;
111 color: #ffffff;
112 text-align: center;
113 line-height: 24px;
114 box-sizing: border-box;
115 user-select: none;
116 cursor: pointer;
117 }
118 }
119
120 .content {
121 min-height: 590px;
122 background-color: #fff;
123 box-shadow: 0px 0px 46px 0px rgba(1, 16, 64, 0.08);
124 padding: 20px;
125 .people_box {
126 display: flex;
127 flex-wrap: wrap;
128 gap: 20px;
129 .people_item {
130 width: 275px;
131 height: 137px;
132 background: #ffffff;
133 border: 1px solid #dcdfe6;
134 padding: 16px;
135 .name {
136 font-weight: 600;
137 font-size: 16px;
138 color: #2d373f;
139 line-height: 22px;
140 }
141 .idcard {
142 font-size: 16px;
143 color: #95a1a6;
144 line-height: 22px;
145 margin-top: 12px;
146 margin-bottom: 17px;
147 }
148 .btn {
149 width: 69px;
150 height: 32px;
151 background: #e7e6ff;
152 font-weight: 400;
153 font-size: 16px;
154 color: #493ceb;
155 line-height: 32px;
156 text-align: center;
157 cursor: pointer;
158 user-select: none;
159 }
160 }
161 }
162 }
163 }
164 </style>
1 <script setup>
2 import { ElMessage } from "element-plus";
3 import { getPriceLevelInfo, getSiteConfig, confirmOrder } from "./api/index.js";
4 import { languageFormat } from "./utils/language.js";
5 import { useStorage } from "@vueuse/core/index";
6 const language = useStorage("language", 0);
7
8 const route = useRoute();
9 const router = useRouter();
10
11 const iframeRef = ref();
12
13 const props = defineProps({
14 activityId: [String, Number],
15 });
16
17 // 获取票档
18 const price = reactive({
19 curPriceId: route.query.ticket_block,
20 data: [],
21
22 fetchData() {
23 getPriceLevelInfo({
24 actId: props.activityId ?? 1,
25 sessionId: route.query.sessionId,
26 openType: route.query.openType,
27 sitePlace: route.query.sitePlace,
28 ticketType: route.query.ticketType,
29 }).then((res) => {
30 this.data = res.data;
31 // price.curPriceId = route.query.ticket_block
32 });
33 },
34 onClickPrice(e) {
35 if (selectedSeats.value?.length) {
36 return ElMessage({ type: "warning", message: "请先取消已选座位" });
37 }
38 price.curPriceId = e.priceId;
39 },
40 });
41
42 // 座位禁用时图标地址
43 const disabledIconUrl =
44 "https://radv4.gitliuyi.top/images/20240511/unselect_default.png";
45
46 function onWindowMessage(e) {
47 const data = e.data;
48
49 if (data.type == "picker-ready") {
50 // apiPromise.then(() => {})
51
52 siteConfig.fetchData().then((res) => {
53 const seat_arr = res.map((it) => {
54 let result = {
55 ...it,
56 active: 0,
57 };
58 Object.assign(result, getSeatRenderState(result));
59 return result;
60 });
61 // 子页面加载完毕,这里iframeRef一定ok
62 sendMsg("load-seats", seat_arr);
63 setTimeout(() => {
64 moveToPriceArea(route.query.ticket_block);
65 }, 500);
66 });
67
68 // 绘制舞台矩形
69 sendMsg("draw-object-rectangle", {
70 x: 1800,
71 y: 960,
72 w: 4400,
73 h: 1300,
74 color: "#e0e0e0",
75 });
76 // 绘制舞台文字
77 sendMsg("draw-object-text", {
78 x: 3900,
79 y: 1500,
80 text: language.value == 0 ? "舞台" : "stage",
81 style: { fontSize: 160, fontWeight: "400", fill: "#6a6a6a" },
82 });
83 } else if (data.type == "seat-click") {
84 // 子页面点击了座位
85 const seatData = data.data;
86 console.log("座位点击", seatData);
87
88 // 如果座位处于不可点击状态,就return
89 if (seatData.state != 1) return;
90
91 // 如果当前筛选了某种座位,点击的不是这种座位,也返回
92 if (price.curPriceId && seatData.priceId != price.curPriceId) return;
93
94 if (
95 selectedSeats.value &&
96 selectedSeats.value?.length >= 5 &&
97 seatData.active == 0
98 )
99 return ElMessage({
100 type: "warning",
101 message: languageFormat(
102 language.value,
103 "最多选择5个座位",
104 "Selectt at most 5 seats"
105 ),
106 });
107
108 const newActive = seatData.active == 0 ? 1 : 0;
109 const siteConfigItem = siteConfig.data.find((it) => it.id == seatData.id);
110 if (siteConfigItem) {
111 siteConfigItem.active = newActive;
112 }
113 sendMsg("update-seat", {
114 id: seatData.id,
115 data: {
116 active: newActive,
117 ...getSeatRenderState(siteConfigItem),
118 },
119 });
120 }
121 }
122
123 const siteConfig = reactive({
124 loading: false,
125 data: [],
126 fetchData() {
127 return getSiteConfig({
128 actId: props.activityId ?? 1,
129 openType: route.query.openType,
130 sessionId: route.query.sessionId,
131 sitePlace: route.query.sitePlace,
132 ticketType: route.query.ticketType,
133 }).then((res) => {
134 const gridSize = 40;
135 const seat_arr = res.data.map((it, index) => {
136 return {
137 ...it,
138 // 这几个是iframe引擎渲染座位必须的属性,规定好的
139 x: gridSize * it.x,
140 y: gridSize * it.y,
141 w: gridSize,
142 h: gridSize,
143 icon: it.state == 1 ? it.unSelectIcon : disabledIconUrl, // 图片的url
144 active: 0, // 是否选中
145 priceId: route.query.openType == 0 ? it.dayPriceId : it.nightPriceId,
146 };
147 });
148 siteConfig.data = seat_arr;
149 return seat_arr;
150 });
151 },
152 });
153
154 watch(
155 () => price.curPriceId,
156 (priceId) => {
157 siteConfig.data.forEach((it) => {
158 sendMsg("update-seat", {
159 id: it.id,
160 data: {
161 ...getSeatRenderState(it),
162 },
163 });
164 });
165 moveToPriceArea(priceId);
166 console.log("update完成");
167 }
168 // { immediate: true }
169 );
170
171 const sendMsg = (type, data) =>
172 iframeRef.value?.contentWindow.postMessage({ type: type, data: data }, "*");
173
174 const getSeatRenderState = (seat) => {
175 const { state, selectIcon, unSelectIcon } = seat;
176 const opacity = state == 0 || price.curPriceId == seat.priceId ? 1 : 0.3;
177 if (state != 1) return { icon: disabledIconUrl, opacity };
178 return { icon: seat?.active ? selectIcon : unSelectIcon, opacity };
179 };
180
181 /** 平移到某个价格区域 */
182 const moveToPriceArea = (priceId) => {
183 const priceSeats = siteConfig.data.filter((it) => it.priceId == priceId);
184 // 计算出x和y最小的值
185 const minX = Math.min(...priceSeats.map((it) => it.x));
186 const minY = Math.min(...priceSeats.map((it) => it.y));
187
188 const offset = {
189 x: 40,
190 y: 200,
191 };
192
193 sendMsg("stage-scale-to", { scale: 1 });
194 setTimeout(() => {
195 sendMsg("stage-move-to", { x: offset.x - minX, y: offset.y - minY });
196 }, 500);
197 };
198
199 const deleteSiteConfigItem = (seatData) => {
200 const newActive = seatData.active == 0 ? 1 : 0;
201 const siteConfigItem = siteConfig.data.find((it) => it.id == seatData.id);
202 if (siteConfigItem) {
203 siteConfigItem.active = newActive;
204 }
205 sendMsg("update-seat", {
206 id: seatData.id,
207 data: {
208 active: newActive,
209 ...getSeatRenderState(siteConfigItem),
210 },
211 });
212 };
213
214 /** 所选座位 */
215 const selectedSeats =
216 computed(() => siteConfig.data.filter((it) => it.active == 1)) ?? [];
217
218 /** 所选座位价格 */
219 const sumPrice = computed(() => {
220 return selectedSeats.value.reduce((total, item) => {
221 const price =
222 route.query.openType == 0
223 ? Number(item.dayPrice)
224 : Number(item.nightPrice);
225 return total + price;
226 }, 0);
227 });
228
229 const toConfirmOrder = () => {
230 const seatIds = selectedSeats.value.map((it) => it.id);
231 if (!seatIds.length)
232 return ElMessage({
233 type: "warning",
234 message: languageFormat(
235 language,
236 "请先选择座位",
237 "Please select the seat first."
238 ),
239 });
240 confirmOrder({
241 actId: props.activityId,
242 openType: route.query.openType,
243 sessionId: route.query.sessionId,
244 sitePlace: route.query.sitePlace,
245 ticketType: route.query.ticketType,
246 seatIds: seatIds,
247 })
248 .then((res) => {
249 router.push({
250 path: "/seat/confirm_order",
251 query: {
252 id: props.activityId,
253 openType: route.query.openType,
254 sessionId: route.query.sessionId,
255 sitePlace: route.query.sitePlace,
256 ticketType: route.query.ticketType,
257 seatIds: seatIds.join(","),
258 },
259 });
260 })
261 .catch((e) => {
262 if (e.code == "B001") {
263 router.push({
264 path: "/seat/order",
265 query: {
266 id: props.activityId,
267 },
268 });
269 }
270 });
271 };
272
273 /**
274 * 1. 加載iframe 3. 请求API的数据
275 * 2. 等待iframe里面资源加载完毕并触发picker-ready事件
276 * 4. 传递数据给iframe,等待渲染
277 */
278
279 window.addEventListener("message", onWindowMessage);
280
281 onBeforeUnmount(() => {
282 window.removeEventListener("message", onWindowMessage);
283 });
284
285 price.fetchData();
286 </script>
287
288 <template>
289 <div class="container">
290 <div class="top">
291 <div class="time">
292 <span>{{ route.query?.time_txt }}</span>
293 <span class="place">{{ route.query.sitePlace }}</span>
294 </div>
295 <div class="price_tab">
296 <div
297 v-for="(it, index) in price.data"
298 class="tab_item"
299 :class="{ tabActive: it.priceId == price.curPriceId }"
300 @click="price.onClickPrice(it)"
301 >
302 <img class="seat" :src="it.unSelectIcon" />
303 <span class="price"
304 >{{ it.price }}<span v-if="language == 0">¥</span></span
305 >
306 </div>
307 </div>
308 </div>
309
310 <div v-if="selectedSeats?.length" class="bottom">
311 <div class="seat_box">
312 <!-- v-for="(it, index) in selectedSeats" -->
313 <div v-for="(it, index) in selectedSeats" class="seat_item">
314 <img class="seat_icon" :src="it.selectIcon" />
315 <span class="num"
316 >{{ it.area }}{{ languageFormat(language, "区", "Zones") }}
317 {{ it.pai }}{{ languageFormat(language, "排", "Row") }} {{ it.no }}
318 {{ languageFormat(language, "座", "Seat") }}</span
319 >
320 <el-icon
321 style="cursor: pointer"
322 color="#ccc"
323 @click="deleteSiteConfigItem(it)"
324 ><CircleCloseFilled
325 /></el-icon>
326 </div>
327 </div>
328 <div class="pay">
329 <div class="sum">¥{{ sumPrice?.toFixed(2) }}</div>
330 <div class="pay_btn" @click="toConfirmOrder()">
331 {{ languageFormat(language, "立即购买", "Continue") }}
332 </div>
333 </div>
334 </div>
335
336 <div class="iframeBox">
337 <iframe
338 ref="iframeRef"
339 class="iframe"
340 id="iframe"
341 src="https://seat-choose.parent4relax.com/#/seat-picker"
342 ></iframe>
343 </div>
344 </div>
345 </template>
346
347 <style scoped lang="scss">
348 .container {
349 width: 1200px;
350 margin: 0 auto;
351 padding: 20px;
352
353 .top {
354 width: 100%;
355 background-color: #fff;
356 padding: 20px;
357 margin-bottom: 10px;
358 border-radius: 6px;
359 .time {
360 font-size: 18px;
361 font-weight: 600;
362 margin-bottom: 10px;
363 .place {
364 color: #7e8489;
365 margin-left: 15px;
366 }
367 }
368
369 .price_tab {
370 display: flex;
371 align-items: center;
372 flex-wrap: wrap;
373 gap: 10px;
374 .tabActive {
375 background: #eeeeee !important;
376 border: 2px solid #7e8489 !important;
377 }
378 .tab_item {
379 display: flex;
380 align-items: center;
381 padding: 10px 14px;
382 background: #f5f7f8;
383 border-radius: 30px;
384 border: 2px solid #dcdedf;
385 font-size: 16px;
386 color: #646666;
387 cursor: pointer;
388 user-select: none;
389
390 .seat {
391 width: 14px;
392 height: 14px;
393 margin-right: 5px;
394 }
395 }
396 }
397 }
398
399 .iframeBox {
400 border-radius: 6px;
401 background-color: #fff;
402 padding: 20px;
403 margin-bottom: 20px;
404 }
405
406 .iframe {
407 width: 100%;
408 height: 500px;
409 border: none;
410 background-color: #f7f8fa;
411 }
412
413 .bottom {
414 border-radius: 6px;
415 background-color: #fff;
416 padding: 20px;
417 margin-bottom: 20px;
418 .seat_box {
419 display: flex;
420 flex-wrap: wrap;
421 gap: 10px;
422 width: 100%;
423 .seat_item {
424 display: flex;
425 align-items: center;
426 padding: 10px 14px;
427 font-size: 16px;
428 color: #29343c;
429 background: #eeeeee;
430 border-radius: 30px;
431 border: 2px solid #7e8489;
432 user-select: none;
433 .seat_icon {
434 width: 14px;
435 height: 14px;
436 margin-right: 5px;
437 }
438 .num {
439 margin-right: 5px;
440 }
441 }
442 }
443
444 .pay {
445 display: flex;
446 justify-content: space-between;
447 align-items: center;
448 margin-top: 10px;
449 .sum {
450 font-weight: 600;
451 font-size: 22px;
452 color: #493ceb;
453 }
454 .pay_btn {
455 width: 200px;
456 height: 40px;
457 background: #493ceb;
458 border-radius: 20px;
459 margin-top: 10px;
460 font-size: 14px;
461 color: #fff;
462 line-height: 40px;
463 text-align: center;
464 cursor: pointer;
465 font-weight: 600;
466 user-select: none;
467 }
468 }
469 }
470 }
471 </style>
1 <script setup></script>
2
3 <template>
4 <div class="view">
5 <router-view />
6 </div>
7 </template>
8
9 <style scoped lang="scss">
10 .view {
11 min-width: 1024px;
12 max-width: 1920px;
13 margin: 0 auto;
14 }
15 </style>
1 <script setup>
2 import dayjs from "dayjs";
3 import useUserStore from "@/store/modules/user";
4 import { setToken, getToken } from "./utils/local-store.js";
5 import { md5 } from "md5js";
6 import { ElMessageBox, ElMessage } from "element-plus";
7 import {
8 loginFree,
9 activityDetail,
10 sessionDetail,
11 getSitePlaceInfo,
12 getPriceLevelInfo,
13 } from "./api/index.js";
14 import { languageFormat } from "./utils/language.js";
15 import { useStorage } from "@vueuse/core/index";
16 const language = useStorage("language", 0);
17
18 const route = useRoute();
19 const router = useRouter();
20 const userStore = useUserStore();
21
22 const props = defineProps({
23 activityId: [String, Number],
24 });
25
26 // 用户免登录
27 const login = async (userId) => {
28 const sign = md5(`uid=${userId}lgo1acfkw51jfo`, 32);
29 return loginFree({
30 userId: userId,
31 sign,
32 }).then((res) => {
33 setToken(res.data.token);
34 });
35 };
36
37 const select_form = reactive({
38 venueItem: {
39 id: 0,
40 dateStr: "",
41 dayOpen: 1,
42 nightOpen: 1,
43 type: 0,
44 }, // 所选场次
45 session: -1, // 日/夜场 0:日场 1:夜场
46 place: "", // 场馆
47 ticket_block: 0, // 票档
48 onClickVenue(e, index) {
49 if (e.state == 1) return; // 表示
50 select_form.venueItem = e;
51 if (
52 (e.dayOpen == 0 && select_form.session == 0) ||
53 (e.nightOpen == 0 && select_form.session == 1)
54 ) {
55 select_form.session = -1;
56 select_form.place = "";
57 select_form.ticket_block = 0;
58 }
59 },
60 // 选择日/夜场
61 onClickSession(e) {
62 if (
63 (e == 0 && select_form.venueItem?.dayOpen == 1) ||
64 (e == 1 && select_form.venueItem?.nightOpen == 1)
65 ) {
66 select_form.session = e;
67 // select_form.place = "";
68 select_form.ticket_block = 0;
69 }
70 },
71 // 选择场馆
72 onClickPlace(e) {
73 if (e.state == 1) return;
74 select_form.place = e.placeName;
75 select_form.ticket_block = 0;
76 },
77 // 选择票档
78 onClickPrice(e) {
79 if (e.state == 1) return;
80 select_form.ticket_block = e.priceId;
81 },
82 // 去选座
83 async toSelectSeat() {
84 // 检查登录
85 // const ticketUserToken = getToken();
86 // if (!ticketUserToken) {
87 const userId = userStore.user?.userId; // userId
88 if (!userId) {
89 // 未登录,打开登录弹窗
90 return userStore.setVisitor();
91 }
92 // }
93 await login(userId);
94
95 if (!select_form.venueItem?.id)
96 return ElMessage({
97 type: "warning",
98 message: languageFormat(
99 language.value,
100 "请选择时间",
101 "Please select the time"
102 ),
103 });
104 if (select_form.session == -1)
105 return ElMessage({
106 type: "warning",
107 message: languageFormat(
108 language.value,
109 "请选择场次",
110 "Please select the session"
111 ),
112 });
113 if (!select_form.place)
114 return ElMessage({
115 type: "warning",
116 message: languageFormat(
117 language.value,
118 "请选择场馆",
119 "Please choose the venue"
120 ),
121 });
122 if (!select_form.ticket_block)
123 return ElMessage({
124 type: "warning",
125 message: languageFormat(
126 language.value,
127 "请选择票档",
128 "Please choose the ticket category"
129 ),
130 });
131
132 router.push({
133 path: "/seat/seat_picker",
134 query: {
135 id: props.activityId,
136 openType: select_form.session,
137 sessionId: select_form.venueItem?.id,
138 sitePlace: select_form.place,
139 ticketType: select_form.venueItem?.type,
140 ticket_block: select_form.ticket_block,
141 time_txt: select_form.venueItem?.dateStr,
142 },
143 });
144 },
145 });
146
147 // 活动详情
148 const detail = reactive({
149 loading: false,
150 data: null,
151 fetchData() {
152 this.loading = true;
153 activityDetail({ actId: props.activityId })
154 .then((res) => {
155 this.data = res.data;
156 })
157 .finally(() => (this.loding = false));
158 },
159 });
160
161 // 获取场次信息
162 const timeVenue = reactive({
163 loading: false,
164 data: [],
165 fetchData() {
166 this.loading = true;
167 sessionDetail({ actId: props.activityId })
168 .then((res) => {
169 this.data = res.data;
170 })
171 .finally(() => (this.loading = false));
172 },
173 });
174
175 // 获取场馆
176 const sitePlaceInfo = reactive({
177 data: [
178 { placeName: "B4", state: "0" },
179 { placeName: "B6", state: "0" },
180 ],
181 fetchData() {
182 console.log(select_form.venueItem?.id, select_form.session);
183 getSitePlaceInfo({
184 sessionId: select_form.venueItem?.id,
185 openType: select_form.session,
186 }).then((res) => {
187 this.data = res.data;
188 });
189 },
190 });
191
192 // 获取票档
193 const price = reactive({
194 data: [],
195 fetchData() {
196 getPriceLevelInfo({
197 actId: props.activityId,
198 sessionId: select_form.venueItem?.id,
199 openType: select_form.session,
200 sitePlace: select_form.place,
201 ticketType: select_form.venueItem?.type,
202 }).then((res) => {
203 this.data = res.data;
204 });
205 },
206 });
207
208 watchEffect(() => {
209 if (select_form.session != -1 && select_form.venueItem?.id) {
210 if (select_form.session == 1 && select_form.place == "B4") {
211 select_form.place = "";
212 }
213 sitePlaceInfo.fetchData();
214 }
215 });
216
217 watchEffect(() => {
218 if (
219 select_form.venueItem?.id &&
220 select_form.session != -1 &&
221 select_form.place
222 ) {
223 price.fetchData();
224 }
225 });
226
227 // 主流程开始
228 watch(
229 () => props.activityId,
230 async (activityId) => {
231 if (!activityId) {
232 // [TODO] dialog提示缺少活動ID讓然後返回
233 ElMessageBox.confirm("缺少活动id", "提示", {
234 confirmButtonText: "确认",
235 type: "warning",
236 showCancelButton: false,
237 draggable: true,
238 }).then((res) => {
239 router.push("/");
240 });
241 return;
242 }
243
244 detail.fetchData();
245 timeVenue.fetchData();
246 },
247 { immediate: true }
248 );
249 </script>
250
251 <template>
252 <div>
253 <!-- top -->
254 <div class="container top">
255 <img class="cover_img" :src="detail.data?.coverImg" />
256 <div class="info">
257 <div class="title">{{ detail.data?.name }}</div>
258 <div class="time">
259 {{ languageFormat(language, "时间", "Event Date & Time") }}{{
260 detail.data?.startTime
261 ? dayjs(detail.data?.startTime).format("YYYY.MM.DD ddd")
262 : ""
263 }}
264
265 {{
266 detail.data?.endTime
267 ? dayjs(detail.data?.endTime).format("YYYY.MM.DD ddd")
268 : ""
269 }}
270 </div>
271 <div class="address">
272 {{ languageFormat(language, "地址", "Location") }}{{
273 detail.data?.address
274 }}
275 </div>
276 <!-- 时间 -->
277 <div class="select_item_box">
278 <div class="label">
279 {{ languageFormat(language, "时间", "Event Date & Time") }}
280 </div>
281 <div class="select_item">
282 <div
283 v-for="(it, index) in timeVenue.data"
284 :key="index"
285 :class="[
286 it.id == select_form.venueItem?.id ? 'tagActive' : 'tag',
287 ]"
288 @click="select_form.onClickVenue(it)"
289 >
290 {{ it.dateStr }}
291 <div v-if="it.type == 1" class="tag_t">{{ languageFormat(language, "套票", "Package ticket") }}</div>
292 </div>
293 </div>
294 </div>
295 <!-- 场次 -->
296 <div class="select_item_box">
297 <div class="label">{{ languageFormat(language, "场次", "Session") }}</div>
298 <div class="select_item">
299 <div
300 :class="[
301 select_form.venueItem?.dayOpen == 1
302 ? select_form.session == 0
303 ? 'tagActive'
304 : 'tag'
305 : 'tagDisabled',
306 ]"
307 @click="select_form.onClickSession(0)"
308 >
309 {{ languageFormat(language, "日场", "Day session") }}
310 </div>
311 <div
312 :class="[
313 select_form.venueItem?.nightOpen == 1
314 ? select_form.session == 1
315 ? 'tagActive'
316 : 'tag'
317 : 'tagDisabled',
318 ]"
319 @click="select_form.onClickSession(1)"
320 >
321 {{ languageFormat(language, "夜场", "Night session") }}
322 </div>
323 </div>
324 </div>
325 <!-- 场馆 -->
326 <div class="select_item_box">
327 <div class="label">
328 {{ languageFormat(language, "场馆", "Venue") }}
329 </div>
330 <div class="select_item">
331 <div
332 v-for="(it, index) in sitePlaceInfo.data"
333 :key="index"
334 :class="[
335 it.state == 0
336 ? it.placeName == select_form.place
337 ? 'tagActive'
338 : 'tag'
339 : 'tagDisabled',
340 ]"
341 @click="select_form.onClickPlace(it)"
342 >
343 {{ it.placeName }}
344 </div>
345 </div>
346 </div>
347 <!-- 票档 -->
348 <div
349 v-if="price.data?.length && select_form.place"
350 class="select_item_box"
351 >
352 <div class="label">
353 {{ languageFormat(language, "票档", "Ticket Category") }}
354 </div>
355 <div class="select_item">
356 <div
357 v-for="(it, index) in price.data"
358 :key="index"
359 :class="[
360 it.state == 0
361 ? it.priceId == select_form.ticket_block
362 ? 'tagActive'
363 : 'tag'
364 : 'tagDisabled',
365 ]"
366 @click="select_form.onClickPrice(it)"
367 >
368 {{ it.price }}
369 </div>
370 </div>
371 </div>
372 <!-- button -->
373 <div class="btn" @click="select_form.toSelectSeat()">
374 {{ languageFormat(language, "选座购票", "Seat selection") }}
375 </div>
376 </div>
377 </div>
378
379 <!-- bottom -->
380 <div class="container bottom">
381 <div class="title">
382 {{ languageFormat(language, "活动介绍", "Event Details") }}
383 </div>
384 <div class="rich_content" v-html="detail.data?.introduceInfo"></div>
385
386 <div class="title" style="margin-top: 30px">
387 {{ languageFormat(language, "购票须知", "Ticketing Information") }}
388 </div>
389 <div class="rich_content" v-html="detail.data?.buyNotice"></div>
390 </div>
391 </div>
392 </template>
393
394 <style scoped lang="scss">
395 .container {
396 width: 1200px;
397 margin: 0 auto;
398 background-color: #fff;
399 box-shadow: 0px 0px 46px 0px rgba(1, 16, 64, 0.08);
400 border-radius: 8px;
401 box-sizing: border-box;
402 font-family: SourceHanSansCN, SourceHanSansCN;
403 padding-bottom: 20px;
404 }
405
406 .top {
407 display: flex;
408 padding: 19px;
409 margin-top: 26px;
410 .cover_img {
411 width: 390px;
412 height: 517px;
413 object-fit: fill;
414 margin-right: 36px;
415 }
416
417 .info {
418 padding-top: 12px;
419 .title {
420 font-weight: bold;
421 font-size: 28px;
422 color: #000000;
423 line-height: 42px;
424 margin-bottom: 34px;
425 }
426 .time {
427 font-weight: 500;
428 font-size: 16px;
429 color: #4a4a4a;
430 line-height: 24px;
431 margin-bottom: 16px;
432 }
433 .address {
434 font-weight: 500;
435 font-size: 16px;
436 color: #4a4a4a;
437 line-height: 24px;
438 margin-bottom: 33px;
439 }
440
441 .select_item_box {
442 display: flex;
443 margin-bottom: 30px;
444 &:last-child {
445 margin-bottom: 0;
446 }
447 .label {
448 font-weight: 600;
449 font-size: 16px;
450 color: #000;
451 line-height: 24px;
452 margin-right: 12px;
453 flex-shrink: 0;
454 }
455
456 .select_item {
457 display: flex;
458 flex-wrap: wrap;
459 gap: 10px;
460 user-select: none;
461 .tag_t {
462 padding: 1px 15px;
463 font-weight: 400;
464 font-size: 14px;
465 color: #493ceb;
466 border-radius: 6px;
467 border: 1px solid #453dea;
468 margin-left: 5px;
469 }
470 .tag {
471 display: flex;
472 padding: 12px 18px;
473 background: #eeeeee;
474 border-radius: 4px;
475 border: 1px solid #29343c;
476 font-size: 14px;
477 color: #4a4a4a;
478 cursor: pointer;
479 }
480
481 .tagActive {
482 display: flex;
483 padding: 12px 18px;
484 background: #fff;
485 border-radius: 4px;
486 border: 1px solid #493ceb;
487 font-size: 14px;
488 color: #493ceb;
489 cursor: pointer;
490 }
491 .tagDisabled {
492 padding: 12px 18px;
493 background: #878787;
494 border-radius: 4px;
495 border: 1px solid #29343c;
496 font-size: 14px;
497 color: #4a4a4a;
498 cursor: no-drop;
499 }
500 }
501 }
502 .btn {
503 width: 175px;
504 height: 40px;
505 background: linear-gradient(270deg, #493ceb 0%, #8623fc 100%);
506 border-radius: 20px;
507 line-height: 40px;
508 text-align: center;
509 font-weight: 500;
510 font-size: 16px;
511 color: #ffffff;
512 cursor: pointer;
513 }
514 }
515 }
516
517 .bottom {
518 padding: 50px;
519 margin-top: 30px;
520 margin-bottom: 30px;
521 .title {
522 padding: 20px 30px;
523 background: linear-gradient(270deg, #493ceb 0%, #8623fc 100%);
524 font-weight: bold;
525 font-size: 20px;
526 color: #ffffff;
527 line-height: 30px;
528 margin-bottom: 30px;
529 }
530 .rich_content {
531 margin-top: 30px;
532 }
533 }
534 </style>
1
2 export const languageFormat = (language = 0, zh, en) => {
3 return language == 1 ? en : zh;
4 };
1 /** 用户登录token储存的key */
2 export const TOKEN_KEY = "SEAT_TOKEN";
3
4 /** 设置token */
5 export const setToken = (token) => localStorage.setItem(TOKEN_KEY, token);
6
7 /**
8 * 获取登录token
9 * @param drop 是否清空
10 */
11 export const getToken = (drop = false) => {
12 let token = localStorage.getItem(TOKEN_KEY);
13 if (!token) return null;
14 if (drop) localStorage.removeItem(TOKEN_KEY);
15 return token;
16 };
1 // http.js
2
3 // import axios from "axios";
4 import axios from 'axios/dist/axios'
5 import { getToken } from "./local-store";
6 import { ElMessage } from "element-plus";
7
8 import { useStorage } from "@vueuse/core/index";
9 const language = useStorage("language", 0);
10
11 const baseURL = "https://radv4.gitliuyi.top/ticket"; //"http://book.xiaojinyu.games"; // 这里填入你的基础 API URL
12 const timeout = 15000; // 请求超时时间
13
14 const http = axios.create({
15 baseURL,
16 timeout,
17 headers: {
18 "Content-Type": "application/json",
19 },
20 });
21
22 // 请求拦截器
23 http.interceptors.request.use(
24 (config) => {
25 // 在发送请求之前做些什么
26 if (language.value == 1) config.headers.Language = "en-us";
27 const TOKEN = getToken();
28 if (TOKEN) config.headers.Authorization = TOKEN;
29 if (config.method == "get") config.params = config.data;
30 console.log("config", config);
31 return config;
32 },
33 (error) => {
34 return Promise.reject(error);
35 }
36 );
37
38 // 响应拦截器
39 http.interceptors.response.use(
40 (response) => {
41 // 判断是否有异常
42 let error = null; // 若无异常此值为null
43 if (response.status !== 200) {
44 error = Error(`Request failed with statuCode ${response.status}`);
45 }
46
47 if (response.data.code != 200) {
48 ElMessage({ type: "error", message: response.data.msg });
49 return Promise.reject(response.data);
50 }
51
52 return response.data;
53 },
54 (error) => {
55 // 对响应错误做点什么
56 return Promise.reject(error);
57 }
58 );
59
60 // 封装请求函数
61 const request = (method, url, data = null) => {
62 return http({
63 method,
64 url,
65 data,
66 });
67 };
68
69 export default request;
...@@ -65,25 +65,25 @@ export default defineConfig(({ mode, command }) => { ...@@ -65,25 +65,25 @@ export default defineConfig(({ mode, command }) => {
65 // https://cn.vitejs.dev/config/#server-proxy 65 // https://cn.vitejs.dev/config/#server-proxy
66 '/dev-api/ztx-train': { 66 '/dev-api/ztx-train': {
67 // target: 'http://123.60.96.243:1896/stage-api', 67 // target: 'http://123.60.96.243:1896/stage-api',
68 target: 'http://192.168.1.25:8686', 68 target: 'https://jijin.wtwuxicenter.com/stage-api',
69 changeOrigin: true, 69 changeOrigin: true,
70 rewrite: (p) => p.replace(/^\/dev-api\/ztx-train/, '') 70 rewrite: (p) => p.replace(/^\/dev-api\/ztx-train/, '')
71 }, 71 },
72 '/dev-api/ztx-match': { 72 '/dev-api/ztx-match': {
73 target: 'http://192.168.1.118:8083', 73 // target: 'http://192.168.1.118:8083',
74 // target: 'http://192.168.1.132:8081', 74 target: 'https://jijin.wtwuxicenter.com/stage-api',
75 changeOrigin: true, 75 changeOrigin: true,
76 rewrite: (p) => p.replace(/^\/dev-api\/ztx-match/, '') 76 rewrite: (p) => p.replace(/^\/dev-api\/ztx-match/, '')
77 }, 77 },
78 '/dev-api/ztx-webSite': { 78 '/dev-api/ztx-webSite': {
79 // target: 'https://dance.itechtop.cn/stage-api', 79 // target: 'https://dance.itechtop.cn/stage-api',
80 target: 'http://192.168.1.118:8081/', 80 target: 'https://jijin.wtwuxicenter.com/stage-api',
81 changeOrigin: true, 81 changeOrigin: true,
82 rewrite: (p) => p.replace(/^\/dev-api\/ztx-webSite/, '') 82 rewrite: (p) => p.replace(/^\/dev-api\/ztx-webSite/, '')
83 }, 83 },
84 '/dev-api': { 84 '/dev-api': {
85 target: 'http://192.168.1.131:8081/', 85 // target: 'http://192.168.1.118:8081/',
86 // target: 'https://dance.itechtop.cn/stage-api', 86 target: 'https://jijin.wtwuxicenter.com/stage-api',
87 // target: 'https://wdsfwuxicenter.com/stage-api', 87 // target: 'https://wdsfwuxicenter.com/stage-api',
88 changeOrigin: true, 88 changeOrigin: true,
89 rewrite: (p) => p.replace(/^\/dev-api/, '') 89 rewrite: (p) => p.replace(/^\/dev-api/, '')
......
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!