d69b2fe1 by zhangmeng

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

2 parents 848a4831 421304e8
......@@ -30,6 +30,7 @@
"jszip": "^3.10.1",
"katex": "^0.16.6",
"lodash": "^4.17.21",
"md5js": "^1.0.7",
"nprogress": "0.2.0",
"pinia": "2.0.35",
"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;}
text-decoration: underline;}
}
.panel-title{font-size: 16px;line-height: 50px;margin: 0;
color: var(--el-color-primary)}
color: var(--el-color-primary)
}
.panel-body{padding: 20px;}
&.border{border: 1px solid #EEEEEE;}
}
......
......@@ -12,12 +12,13 @@
>
<el-menu-item index="/">{{ language==0?'首页':'HOME' }}</el-menu-item>
<el-menu-item index="/news">{{ language==0?'新闻资讯':'NEWS' }}</el-menu-item>
<el-menu-item index="/notice">{{ language==0?'通知公告':'NOTICEBOARD' }}</el-menu-item>
<el-menu-item index="/guide">{{ language==0?'参赛指南':'GUIDELINE' }}</el-menu-item>
<el-menu-item index="/match/list">{{ language==0?'大赛报名':'REGISTRATION' }}</el-menu-item>
<el-menu-item index="/saiC">{{ language==0?'赛程安排':'COMPETITIONS' }}</el-menu-item>
<el-menu-item index="/meta">{{ language==0?'媒体中心':'MEDIA' }}</el-menu-item>
<el-menu-item index="/guide">{{ language==0?'参赛指南':'GUIDELINE' }}</el-menu-item>
<!-- <el-sub-menu index="/about">-->
<el-menu-item index="/notice">{{ language==0?'通知公告':'NOTICEBOARD' }}</el-menu-item>
<!-- <el-sub-menu index="/about">-->
<!-- <template #title>{{ language==0?'关于我们':'CONTACT & MORE' }}</template>-->
<!-- <el-menu-item index="/about/wuDao">{{ language==0?'舞蹈节':'About Us' }}</el-menu-item>-->
<!-- <el-menu-item index="/about/regulations" v-if="language==1">Rules & Regulations</el-menu-item>-->
......@@ -30,12 +31,13 @@
>
<el-menu-item index="/">{{ language==0?'首页':'HOME' }}</el-menu-item>
<el-menu-item index="/news">{{ language==0?'新闻资讯':'NEWS' }}</el-menu-item>
<el-menu-item index="/notice">{{ language==0?'通知公告':'NOTICEBOARD' }}</el-menu-item>
<el-menu-item index="/guide">{{ language==0?'参赛指南':'GUIDELINE' }}</el-menu-item>
<el-menu-item index="/match/list">{{ language==0?'大赛报名':'REGISTRATION' }}</el-menu-item>
<el-menu-item index="/saiC">{{ language==0?'赛程安排':'COMPETITIONS' }}</el-menu-item>
<el-menu-item index="/meta">{{ language==0?'媒体中心':'MEDIA' }}</el-menu-item>
<el-menu-item index="/guide">{{ language==0?'参赛指南':'GUIDELINE' }}</el-menu-item>
<!-- <el-sub-menu index="/about">-->
<el-menu-item index="/notice">{{ language==0?'通知公告':'NOTICEBOARD' }}</el-menu-item>
<!-- <el-sub-menu index="/about">-->
<!-- <template #title>{{ language==0?'关于我们':'CONTACT & MORE' }}</template>-->
<!-- <el-menu-item index="/about/wuDaoEn">{{ language==0?'舞蹈节':'About Us' }}</el-menu-item>-->
<!-- <el-menu-item index="/about/regulations" v-if="language==1">Rules & Regulations</el-menu-item>-->
......
......@@ -13,6 +13,7 @@ NProgress.configure({ showSpinner: false })
const whiteList = ['/login', '/register', '/regulations']
router.beforeEach((to, from, next) => {
console.log('to2', to)
NProgress.start()
if (getToken()) {
// debugger
......
......@@ -9,6 +9,7 @@ import useUserStore from '@/store/modules/user'
NProgress.configure({ showSpinner: false })
router.beforeEach((to, from, next) => {
console.log('to', to)
NProgress.start()
if (getToken()) {
// 判断当前用户是否已拉取完user_info信息
......
......@@ -500,6 +500,71 @@ export const constantRoutes = [
meta: { title: 'System messages' }
}
]
},
{
path: 'seat',
component: () => import('@/viewsPc/seat/seat'),
name: 'seat',
redirect: '/seat/detail',
children: [
{
path: 'detail',
name: 'seat_detail',
component: () => import('@/viewsPc/seat/ticket-detail'),
meta: { title: '购票详情' },
props: route => ({
activityId:route.query.id,
})
},
{
path: 'seat_picker',
name: 'seat_picker',
component: () => import('@/viewsPc/seat/seat-picker'),
meta: { title: '选座' },
props: route => ({
activityId:route.query.id,
})
},
{
path: 'order',
name: 'seat_order',
component: () => import('@/viewsPc/seat/order-list'),
meta: { title: '我的订单' },
props: route => ({
activityId:route.query.id,
})
},
{
path: 'order_detail',
name: 'order_detail',
component: () => import('@/viewsPc/seat/order-detail'),
meta: { title: '订单详情' },
props: route => ({
activityId: route.query.id,
})
},
{
path: 'confirm_order',
name: 'confirm_order',
component: () => import('@/viewsPc/seat/confirm-order'),
meta: { title: '确认订单' },
props: route => ({
activityId:route.query.id,
})
},
{
path: 'add_watch_people',
name: 'add_watch_people',
component: () => import('@/viewsPc/seat/add-watch-people'),
meta: { title: '新增观影人' }
},
{
path: 'people_manage',
name: 'people_manage',
component: () => import('@/viewsPc/seat/people-manage'),
meta: { title: '观影人管理' }
},
]
}
]
},
......
......@@ -108,6 +108,13 @@ const menus = ref([
isActive: false
},
{
name: language.value==0?'票务预订':'Ticket Reservation',
routeName: 'seat_order',
picUrl1: '/img/nav_29.png',
picUrl2: '/img/nav_29_dwn.png',
isActive: false
},
{
name: language.value==0?'系统消息':'System messages',
routeName: 'mySms',
picUrl1: '/img/nav_30.png',
......
......@@ -24,7 +24,8 @@
</el-form-item>
<el-form-item :label="language==0?'会员角色':'Role'">
<el-select v-model="labelArr" multiple style="width: 100px;">
<el-option v-for="l in labels" :key="l.value" :value="l.value" :label="language==0?(l.label):(l.enlabel)"/>
<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)"/>
<el-option v-else v-for="l in labelsForType4" :key="l.value" :value="l.value" :label="language==0?(l.label):(l.enlabel)"/>
</el-select>
</el-form-item>
<el-form-item :label="language==0?'WDSF':'WDSF'">
......@@ -73,6 +74,8 @@ import useUserStore from "@/store/modules/user";
import {useStorage} from "@vueuse/core/index";
import AddWdsf from "@/viewsPc/match/components/addWdsf";
const language= useStorage('language',0)
const group = useUserStore().group || {}
const tableData = ref([])
const labelArr = ref([])
const labels = ref([
......@@ -84,6 +87,15 @@ const labels = ref([
{value: '6', label: '官员', enlabel: 'Official'},
{value: '3', label: '其他', enlabel: 'Other'}
])
const labelsForType4 = ref([
{value: '0', label: '运动员', enlabel: 'Sportsman'},
{value: '1', label: '教练', enlabel: 'Coach'},
{value: '2', label: '领队', enlabel: 'Head of team'},
{value: '4', label: '管理', enlabel: 'Manager'},
{value: '5', label: '翻译', enlabel: 'Interpreter'},
{value: '6', label: '官员', enlabel: 'Official'},
{value: '3', label: '其他', enlabel: 'Other'}
])
const certificates = ref([
{
value: '0',
......@@ -102,7 +114,6 @@ const query = ref({
pageNum: 1, pageSize: 10
})
const total = ref(0)
const group = useUserStore().group || {}
const props = defineProps({
user: {
type: Object,
......@@ -193,6 +204,8 @@ function delperson(p) {
cancelButtonText: c,
type: 'warning'
}).then(() => {
// This user has registered for the event and cannot be deleted.
match.delPerson(p.id).then(res => {
ElMessage.success(msg)
getList(groupId.value)
......
......@@ -101,7 +101,8 @@ function popRemark(type){
building()
return
}
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)){
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)){
//type == '0'
building()
return
}
......@@ -116,8 +117,11 @@ function goBooking(n) {
switch (n) {
case 0:
// 票务
building()
router.push({path: `/booking/ticket/${props.matchId}`})
router.push({
path: `/seat/detail`,
params: {id: 1},
query: {id: 1}
})
break;
case 1:
//酒店
......
......@@ -96,8 +96,8 @@
<div class="content" v-if="activeName==8">
<label>点击下载:</label>
<!-- <a target="_blank" class="text-primary" href="/file/COMPETITION_GUIDE_0511V1.pdf">-->
<a @click="showBuilding" class="text-primary">
<a target="_blank" class="text-primary" href="/file/COMPETITION%20GUIDE%200520V1.pdf">
<!-- <a @click="showBuilding" class="text-primary">-->
<el-icon style="position: relative;top: 2px"><download/></el-icon>
2024 WDSF亚洲体育舞蹈节参赛指南
</a>
......@@ -200,8 +200,8 @@
<div class="content" v-if="activeName==71"><el-empty description="no data"></el-empty></div>
<div class="content" v-if="activeName==8">
<label>Download:</label>
<!-- <a target="_blank" class="text-primary" href="/file/COMPETITION_GUIDE_0511V1.pdf">-->
<a @click="showBuilding" class="text-primary">
<a target="_blank" class="text-primary" href="/file/COMPETITION%20GUIDE%200520V1.pdf">
<!-- <a @click="showBuilding" class="text-primary">-->
<el-icon style="position: relative;top: 2px"><download/></el-icon>
2024 WDSF ASIAN DANCESPORT FESTIVAL COMPETITION GUIDE
</a>
......
......@@ -4,7 +4,7 @@
<div class="box ph-30">
<el-card v-if="user">
<single-sign-step v-if="user.utype=='1'" activeStep="1" :language="language"/>
<team-sign-step v-if="user.utype=='2'" activeStep="2" :language="language"/>
<team-sign-step v-if="user.utype=='2'" :activeStep="1" :language="language"/>
</el-card>
<el-card class="mt20">
......@@ -73,10 +73,14 @@
<el-col :lg="12">
<el-card class="mt20" v-loading="loading">
<template #header>
<div class="card-header">
<div class="card-header" v-if="isNational">
<img src="@/assets/sign/tag03.png"/>
{{ language==0?'队医':'Team doctor' }}
</div>
<div class="card-header" v-else>
<img src="@/assets/sign/gl.png"/>
管理
</div>
</template>
<div class="chooseForm">
<el-checkbox-group v-model="form.doctor">
......@@ -198,7 +202,7 @@ import DialogAddCoach_En from './components/addCoach_en'
const {proxy} = getCurrentInstance()
const router = useRouter()
const route = useRoute()
import {ElMessage} from 'element-plus'
import {ElMessage, ElMessageBox} from 'element-plus'
import {useRoute, useRouter} from 'vue-router'
import useUserStore from "@/store/modules/user";
import {useStorage} from "@vueuse/core/index";
......@@ -242,7 +246,7 @@ onMounted(() => {
})
function getList() {
console.log(user.utype)
// console.log(user.utype)
if (user.utype == '1') {
geren()
}
......@@ -252,7 +256,7 @@ function getList() {
}
function changecoachs(e) {
console.log(e)
// console.log(e)
}
// 获取报名时是否已选过
......@@ -309,11 +313,31 @@ function geren() {
}
function goNext() {
console.log(form.value)
console.log(personAllList.value.teamDoctors,form.value)
// if ((form.value.coachs.length < 1) && (form.value.leader.length < 1)) {
// ElMessage.warning(language.value==0?'至少选一个教练或领队':'Coach/Team Leader, select at least one')
// return
// }
if((personAllList.value.coaches.length>=0 && form.value.coachs?.toString().length == 0)&&
(personAllList.value.teamDoctors.length>=0 && form.value.doctor?.toString().length == 0)&&
(personAllList.value.translators.length>=0 && form.value.translator?.toString().length == 0)&&
(personAllList.value.others.length>=0 && form.value.other?.toString().length == 0)&&
(personAllList.value.officials.length>=0 && form.value.official?.toString().length == 0)&&
(personAllList.value.leaders.length>=0 && form.value.leader?.toString().length == 0)
){
ElMessageBox.confirm(language.value==0?'您已添加随行人员,但尚未选中,是否进行下一步?':'You have added a follower, but have not selected, do you want to continue?', {
confirmButtonText: language.value==0?'下一步':'Next',
cancelButtonText: language.value==0?'取消':'Cancel',
type: 'warning'
}).then(()=>{
next()
})
return
}
next()
}
function next() {
var obj = {
cptId: matchId,
coachIds: form.value.coachs?.toString() || '',
......@@ -332,7 +356,6 @@ function goNext() {
if (user.utype == '1') {
// 个人报名
match.singleSignSavePerson(obj).then(res => {
console.log(res)
router.push({
name: 'chooseProject',
query: {
......@@ -357,11 +380,8 @@ function goNext() {
})
}
console.log(form.value)
}
function goPrev() {
console.log(languageSource.value)
if(languageSource.value=='100'){
router.push({
name: `teamSignCn`,
......
......@@ -38,7 +38,10 @@
<div class="text-center mt20">
<el-button type="primary" plain @click="switchPerson">{{language==0?'切换':'Switch'}}</el-button>
</div>
<div class="tip">
<span v-if="language==0">*如果您参加个人项目,或给其他组合/选手进行报名,请点击切换按钮重新选择人员</span>
<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>
</div>
</div>
</div>
</el-col>
......@@ -46,7 +49,7 @@
<el-col :lg="18">
<div class="panel border">
<div class="panel-header ">
<h3 class="panel-title" v-if="language==0">可参与报名的项目</h3>
<h3 class="panel-title" v-if="language==0">可参与报名的项目 <span>已报项目在下方查看</span></h3>
<h3 class="panel-title" v-else>Search Events</h3>
<div class="fr">
<el-input size="small" v-model="projectQuery.name" :prefix-icon="Search" @change="getProjectList"
......@@ -59,7 +62,7 @@
<el-checkbox class="flexBetweenBox" v-for="c in projectList" :label="c.id" :key="c.id" :disabled="cantBao.flag">
<div class="flexBetween w100">
<div class="l">
{{ c.code }}:{{ c.name }}
{{ c.code }}:{{ c.name }} {{c.danceType}}
<div>{{ c.danceTypeDetailStr }}</div>
</div>
<div class="text-primary">{{ language == 0 ? '¥' : '€' }}{{ c.serviceFee }}</div>
......@@ -793,4 +796,8 @@ function switchTabletype() {
}
.mName{color: #000;font-size: 15px;display: inline-block;max-width: 6.5em;text-overflow: ellipsis;
overflow: hidden;}
.panel h3.panel-title{
span{ color: #999;font-size: 12px;}
}
</style>
......
......@@ -32,10 +32,10 @@
{{c.representing}}
{{c.ageGroup}}
{{c.division}}
{{c.division}}<span v-if="c.age"> -{{ c.age }}{{language==0 ? '岁' : 'years'}}</span>
<!-- @click="editPerson(c.id)"-->
<span v-if="c.disabled" class="text-danger po-right">需补全信息</span>
<!-- -{{ c.age }}-->
</div>
</el-option>
<!-- <template #tag>-->
......@@ -78,7 +78,9 @@
<el-col :lg="14">
<div class="panel border">
<div class="panel-header ">
<h3 class="panel-title" v-if="language==0">可参与报名的项目</h3>
<h3 class="panel-title" v-if="language==0">可参与报名的项目
<span>已报项目在下方查看</span>
</h3>
<h3 class="panel-title" v-else>Search Events</h3>
<div class="fr">
<el-input size="small" v-model="projectQuery.name" :prefix-icon="Search"
......@@ -91,7 +93,7 @@
<el-checkbox class="flexBetweenBox" v-for="c in projectList" :value="c.id" :key="c.id">
<div class="flexBetween w100">
<div class="l">
{{ c.code }}:{{ c.name }}
{{ c.code }}:{{ c.name }}({{c.danceType}})
<div>{{ c.danceTypeDetailStr }}</div>
</div>
<div class="text-primary">{{ language == 0 ? '¥' : '€' }}{{ c.serviceFee }}</div>
......@@ -868,4 +870,7 @@ watch(choosedchoosed, (newVal, oldVal) => {
}
:deep(.el-select__tags-text){color: #000;font-size: 14px;}
.po-right{position: absolute;right: 0;}
.panel h3.panel-title{
span{ color: #999;font-size: 13px;}
}
</style>
......
......@@ -164,7 +164,7 @@ const data = reactive({
{value: '0', label: '运动员', enlabel: 'Sportsman'},
{value: '1', label: '教练', enlabel: 'Coach'},
{value: '2', label: '领队', enlabel: 'Head Of Team'},
{value: '4', label: '队医', enlabel: 'Team doctor'},
{value: '4', label: '管理', enlabel: 'Team doctor'},
{value: '5', label: '翻译', enlabel: 'Interpreter'},
{value: '6', label: '官员', enlabel: 'Official'},
{value: '3', label: '其他', enlabel: 'Other'}
......
......@@ -4,9 +4,9 @@
<el-button type="primary" @click="addMember">
{{ language == 0 ? '添加选手' : 'Add Player' }}
</el-button>
<el-button type="primary" plain @click="importSportman" v-if="!isNational">
{{language == 0 ? '导入选手' : 'Import Player'}}
</el-button>
<!-- <el-button type="primary" plain @click="importSportman" v-if="!isNational">-->
<!-- {{language == 0 ? '导入选手' : 'Import Player'}}-->
<!-- </el-button>-->
</div>
<div class="from-Card">
<el-form :inline="true" :model="query" class="mt20" label-width="60" size="small">
......
......@@ -25,7 +25,8 @@
</el-col>
<el-col :lg="8">
<div class="item">
<label>{{ language == 0 ? '队医' : 'TEAM DOCTOR' }}</label>
<label v-if="group.type=='4'">{{ language == 0 ? '队医' : 'TEAM DOCTOR' }}</label>
<label v-else>{{ language == 0 ? '管理' : 'MANAGER' }}</label>
<span class="mr5" v-for="c in names.teamDoctorList">
{{ c.realName }},
</span>
......
......@@ -43,7 +43,11 @@
</div>
<div v-else>
<div>{{ scope.row.birthPeriod.replace(',',language==0?' 至 ':' to ') }}</div>
<div>{{scope.row.birthPeriodSecond?.replace(',',language==0?' 至 ':' to ')}}</div>
<div v-if="scope.row.birthPeriodSecond">{{scope.row.birthPeriodSecond?.replace(',',language==0?' 至 ':' to ')}}</div>
<div v-if="scope.row.birthPeriodThird">{{scope.row.birthPeriodThird?.replace(',',language==0?' 至 ':' to ')}}</div>
<div v-if="scope.row.birthPeriodFourth">{{scope.row.birthPeriodFourth?.replace(',',language==0?' 至 ':' to ')}}</div>
<div v-if="scope.row.birthPeriodFifth">{{scope.row.birthPeriodFifth?.replace(',',language==0?' 至 ':' to ')}}</div>
<div v-if="scope.row.birthPeriodSixth">{{scope.row.birthPeriodSixth?.replace(',',language==0?' 至 ':' to ')}}</div>
</div>
</template>
</el-table-column>
......
......@@ -27,7 +27,12 @@
<span v-if="item==='0'" class="ml5">{{ language == 0 ? '运动员' : 'Athletes' }}</span>
<span v-if="item==='1'" class="ml5">{{ language == 0 ? '教练' : 'Coach' }}</span>
<span v-if="item==='2'" class="ml5">{{ language == 0 ? '领队' : 'Head of team' }}</span>
<span v-if="item==='4'" class="ml5">{{ language == 0 ? '队医' : 'Team Doctor' }}</span>
<span v-if="item==='4'&&group.type!='4'" class="ml5">
{{ language == 0 ? '管理' : 'Manager' }}
</span>
<span v-if="item==='4'&&group.type=='4'" class="ml5">
{{ language == 0 ? '队医' : 'Team Doctor' }}
</span>
<span v-if="item==='5'" class="ml5">{{ language == 0 ? '翻译' : 'Interpreter' }}</span>
<span v-if="item==='6'" class="ml5">{{ language == 0 ? '官员' : 'Official' }}</span>
<span v-if="item==='3'" class="ml5">{{ language == 0 ? '其他' : 'Other' }}</span>
......@@ -61,7 +66,8 @@
<script setup>
import {ref} from "vue";
import {useStorage} from "@vueuse/core/index";
import useUserStore from "@/store/modules/user";
const group = useUserStore().group || {}
const language = useStorage('language', 0)
const emit = defineEmits(['edit', 'delete'])
let title = ''
......
......@@ -4,22 +4,22 @@
</div>
<el-table :data="list" :sum-text="sumText" border style="width: 100%" v-loading="loading">
<el-table-column :label="language==0?'序号':'Index'" type="index" width="70" align="center"/>
<el-table-column v-if="!isNational" :label="language==0?'姓名':'Real Name'" prop="personInfo.realName" min-width="100"/>
<el-table-column v-if="!isNational" :label="language==0?'姓名':'Real Name'" prop="personInfo.realName" align="center" min-width="100"/>
<el-table-column v-if="isNational" :label="language==0?'姓氏':'Surname'" prop="personInfo.xing" min-width="100"/>
<el-table-column v-if="isNational" :label="language==0?'名':'Name'" prop="personInfo.ming" min-width="100"/>
<el-table-column :label="language==0?'所属国家/地区':'Country'" min-width="120">
<el-table-column :label="language==0?'所属国家/地区':'Country'" min-width="120" header-align="center" align="center">
<template #default="scope">
<span v-if="scope.row.personInfo.countryName">{{scope.row.personInfo.countryName}}</span>
<span v-if="scope.row.personInfo.representing">{{scope.row.personInfo.representing}}</span>
</template>
</el-table-column>
<el-table-column :label="language==0?'性别':'Gender'" prop="personInfo.sexStr"/>
<el-table-column v-if="!isNational" :label="language==0?'证件类型':'ID Type'" :width="language==0?'':'140'" prop="personInfo.idcTypeStr"/>
<el-table-column v-if="!isNational" :label="language==0?'证件号码':'ID NO.'" prop="personInfo.idcCode" width="200"/>
<el-table-column v-if="isNational" :label="language==0?'WDSF 会员号':'WDSF MIN'" prop="personInfo.wdsfMin" width="200"/>
<el-table-column v-if="!isNational" :label="language==0?'出生日期':'Date of Birth'" prop="personInfo.birth" width="130"/>
<el-table-column v-if="isNational" :label="language==0?'年龄组':'Age group'" prop="personInfo.ageGroup" width="110"/>
<el-table-column v-if="isNational" :label="language==0?'舞种':'Division'" prop="personInfo.division" width="110"/>
<el-table-column :label="language==0?'性别':'Gender'" prop="personInfo.sexStr" align="center"/>
<el-table-column v-if="!isNational" :label="language==0?'证件类型':'ID Type'" align="center" :width="language==0?'':'140'" prop="personInfo.idcTypeStr" header-align="center"/>
<el-table-column v-if="!isNational" :label="language==0?'证件号码':'ID NO.'" prop="personInfo.idcCode" width="200" header-align="center"/>
<el-table-column v-if="isNational" :label="language==0?'WDSF 会员号':'WDSF MIN'" prop="personInfo.wdsfMin" width="200" header-align="center"/>
<el-table-column v-if="!isNational" :label="language==0?'出生日期':'Date of Birth'" align="center" prop="personInfo.birth" width="130" header-align="center"/>
<el-table-column v-if="isNational" :label="language==0?'年龄组':'Age group'" prop="personInfo.ageGroup" width="110" header-align="center"/>
<el-table-column v-if="isNational" :label="language==0?'舞种':'Division'" prop="personInfo.division" width="110" header-align="center"/>
<!-- <el-table-column :label="language==0?'会员角色':'Role'" width="150">-->
<!-- <template #default="scope">-->
<!-- <div class="esp">-->
......@@ -36,7 +36,7 @@
<!-- </template>-->
<!-- </el-table-column>-->
<!-- <el-table-column :label="language==0?'详细地址':'Detailed Address'" prop="personInfo.address" min-width="140"/>-->
<el-table-column :label="language==0?'报项':'REGISTERED COMPETITION'" min-width="300" :fixed="hasAction?false:'right'">
<el-table-column :label="language==0?'报项':'REGISTERED COMPETITION'" min-width="300" header-align="center" :fixed="hasAction?false:'right'">
<template #default="props">
<ol>
<li v-for="s in props.row.signInfo">
......@@ -51,7 +51,7 @@
</ol>
</template>
</el-table-column>
<el-table-column :fixed="hasAction?false:'right'" min-width="100" :label="language==0?'保险费':'Premium'" prop="insuranceFee">
<el-table-column :fixed="hasAction?false:'right'" min-width="100" align="center" :label="language==0?'保险费':'Premium'" prop="insuranceFee">
<template #default="scope">
<span class="text-primary">{{ language==0?'¥':'€' }}{{ scope.row.insuranceFee }}</span>
</template>
......@@ -61,11 +61,11 @@
<template #default="scope">
<el-link v-if="scope.row.signInfo[0].extraPersonInfoMapList[index]?.type=='2'"
target="_blank"
:href="fillImgUrl(scope.row.signInfo[0].extraPersonInfoMapList[index].value.url)">
<span class="text-primary">{{ scope.row.signInfo[0].extraPersonInfoMapList[index].value.name }}</span>
:href="fillImgUrl(scope.row.signInfo[0].extraPersonInfoMapList[index]?.value?.url)">
<span class="text-primary">{{ scope.row.signInfo[0].extraPersonInfoMapList[index]?.value?.name }}</span>
</el-link>
<img v-else-if="scope.row.signInfo[0].extraPersonInfoMapList[index]?.type=='3'" style="width: 50px;"
:src="fillImgUrl(scope.row.signInfo[0].extraPersonInfoMapList[index].value.url||scope.row.signInfo[0].extraPersonInfoMapList[index].value)">
:src="fillImgUrl(scope.row.signInfo[0].extraPersonInfoMapList[index]?.value?.url||scope.row.signInfo[0]?.extraPersonInfoMapList[index]?.value)">
<span v-else>{{ scope.row.signInfo[0].extraPersonInfoMapList[index]?.value }}</span>
</template>
</el-table-column>
......
......@@ -2,22 +2,35 @@
<div class="mt20"></div>
<el-table :data="list" border style="width: 100%">
<el-table-column :label="language==0?'序号':'Index'" type="index" width="70" align="center"/>
<el-table-column :label="language==0?'组别代码':'EVENT code'" width="120px" prop="project.code"/>
<el-table-column :label="language==0?'组别':'EVENT'" prop="project.name"/>
<el-table-column :label="language==0?'舞种':'DISCIPLINE'" width="120px" prop="project.danceType"/>
<el-table-column :label="language==0?'参赛说明':'Participation Instructions'" min-width="160px">
<el-table-column :label="language==0?'组别代码':'EVENT code'" width="120px" align="center" prop="project.code"/>
<el-table-column :label="language==0?'组别':'EVENT'" min-width="150px" header-align="center" prop="project.name">
<template #default="scope">
<div v-html="scope.row.project.remarks"></div>
<el-tooltip effect="dark" :content="scope.row.project.name">
<div class="esp">{{scope.row.project.name}}</div>
</el-tooltip>
</template>
</el-table-column>
<el-table-column :label="language==0?'参赛运动员':'PARTICIPATING ATHLETES'" min-width="140px">
<el-table-column :label="language==0?'舞种':'DISCIPLINE'" align="center" width="120px" prop="project.danceType"/>
<el-table-column :label="language==0?'参赛说明':'Participation Instructions'" header-align="center" min-width="160px">
<template #default="scope">
<div>
<el-tooltip effect="dark" :content="scope.row.project.remarks">
<div class="esp" v-html="scope.row.project.remarks"></div>
</el-tooltip>
</template>
</el-table-column>
<el-table-column :label="language==0?'参赛运动员':'PARTICIPATING ATHLETES'" header-align="center" min-width="140px">
<template #default="scope">
<el-tooltip effect="dark">
<template #content>
<span v-for="s in scope.row.athletes">{{ s.name }},</span>
</template>
<div class="esp">
<span v-for="s in scope.row.athletes">{{ s.name }},</span>
</div>
</el-tooltip>
</template>
</el-table-column>
<el-table-column :label="language==0?'参赛服务费':'REGISTRATION FEE'" width="150px" prop="">
<el-table-column :label="language==0?'参赛服务费':'REGISTRATION FEE'" align="center" width="150px" prop="">
<template #default="scope">
<div class="text-primary">
{{ language==0?'¥':'€' }}{{ scope.row.project.serviceFee }}
......
......@@ -116,8 +116,10 @@
</el-col>
<el-col :lg="12" v-if="Number(form.totalFee)>0">
<div class="priceb" v-if="form.payStatus=='0'">{{ language==0?'待支付金额':'Amount Due' }}:<span class="price">{{ language==0?'¥':'€' }}{{ Number(totalFee).toFixed(2) }}</span></div>
<div class="priceb" v-if="form.payStatus=='1'">{{ language==0?'已支付金额':'Amount Due' }}:<span class="price">{{ language==0?'¥':'€' }}{{ Number(totalFee).toFixed(2) }}</span></div>
<div class="priceb" v-if="form.payStatus=='5'">{{ language==0?'已退款':'Refunded' }}:<span class="price">{{ language==0?'¥':'€' }}{{ Number(totalFee).toFixed(2) }}</span></div>
<div class="priceb" v-else-if="form.payStatus=='1'">{{ language==0?'线下支付待核销':'Amount Due' }}:<span class="price">{{ language==0?'¥':'€' }}{{ Number(totalFee).toFixed(2) }}</span></div>
<div class="priceb" v-else-if="form.payStatus=='3'">{{ language==0?'已支付金额':'Amount Due' }}:<span class="price">{{ language==0?'¥':'€' }}{{ Number(totalFee).toFixed(2) }}</span></div>
<div class="priceb" v-else-if="form.payStatus=='5'">{{ language==0?'已退款':'Refunded' }}:<span class="price">{{ language==0?'¥':'€' }}{{ Number(totalFee).toFixed(2) }}</span></div>
<div class="priceb" v-else>{{ language==0?'费用总计':'Amount Due' }}:<span class="price">{{ language==0?'¥':'€' }}{{ Number(totalFee).toFixed(2) }}</span></div>
</el-col>
</el-row>
</el-card>
......
......@@ -23,7 +23,7 @@
</el-form-item>
</el-col>
<el-col :lg="10">
<el-form-item :label="language==0?'代表国家/地区':'Representing'">
<el-form-item :label="language==0?'代表国家/地区':'Representing'" required>
<el-select filterable v-model="form.countryId" @change="changeCountryId"
:disabled="form.type!='4'">
<!-- <el-option v-for="item in countryList" :key="item.id" :label="language==0?item.name:item.enName" :value="item.id"/>-->
......
......@@ -26,7 +26,7 @@
<el-form-item :label="language==0?'参赛队名称':'Name of participating team'" required prop="abreviations">
<el-input type="text" v-model="form.abreviations" :placeholder="language==0?'请输入内容':''"/>
</el-form-item>
<el-form-item :label="language==0?'团体名称':'Team Name'" prop="name">
<el-form-item :label="language==0?'团体名称':'Team Name'" prop="name" required>
<el-input v-model="form.name" :placeholder="language==0?'请输入团体名称':''" />
</el-form-item>
<el-form-item :label="language==0?'所属国家/地区':'Country'" required>
......@@ -43,12 +43,12 @@
<el-form-item :label="language==0?'邮箱':'Email'" required prop="contactEmail">
<el-input v-model="form.contactEmail" type="email" :placeholder="language==0?'请输入内容':''"/>
</el-form-item>
<!-- <el-form-item :label="language==0?'专业/业余':'Professional/Amateur'" required prop="majorFlag">-->
<!-- <el-select v-model="form.majorFlag">-->
<!-- <el-option :label="language==0?'专业':'Professional'" value="1" />-->
<!-- <el-option :label="language==0?'业余':'Amateur'" value="0" />-->
<!-- </el-select>-->
<!-- </el-form-item>-->
<el-form-item :label="language==0?'专业/业余':'Professional/Amateur'" required prop="majorFlag">
<el-select v-model="form.majorFlag">
<el-option :label="language==0?'专业':'Professional'" value="1" />
<el-option :label="language==0?'业余':'Amateur'" value="0" />
</el-select>
</el-form-item>
<el-form-item :label="language==0?'团体类型':'Group type'" prop="type">
<el-select :disabled="form.type=='4'" v-model="form.type" :placeholder="typeOptions[language].selectPlaceholder" style="width: 100%;">
<el-option v-for="(o,index) in typeOptions[language].options" :label="o.text"
......
<script setup>
import { ElMessage } from "element-plus";
import { addViewPeople } from "./api/index.js";
import { languageFormat } from "./utils/language.js";
import { useStorage } from "@vueuse/core/index";
const language = useStorage("language", 0);
const router = useRouter();
const people = reactive({
form: {
name: "",
idCard: "",
},
type: language.value == 0 ? "身份证" : "Identity Card",
onConfirm() {
if (!people.form.name)
return ElMessage({
type: "warning",
message: languageFormat(language.value, "请输入姓名", "Name"),
});
if (!people.form.idCard)
return ElMessage({
type: "warning",
message: languageFormat(language.value, "请输入证件号", "ID Numbe"),
});
// 使用正则验证身份证号码格式
const idCardRegex =
/^[1-9]\d{5}(19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[\dXx]$/;
if (!idCardRegex.test(people.form.idCard) && language.value == 0)
return ElMessage({ type: "warning", message: "身份证号格式不正确" });
addViewPeople(people.form).then((res) => {
ElMessage({
type: "success",
message: languageFormat(language.value, "操作成功", "Operate successfully"),
});
router.go(-2);
});
},
});
</script>
<template>
<div class="container">
<div class="title">
{{ languageFormat(language, "新增观影人", "Companion") }}
</div>
<div class="content">
<div class="form-item">
<div>
<div class="label">
{{ languageFormat(language, "姓名", "Full Name") }}
</div>
<el-input
v-model="people.form.name"
style="width: 570px"
:placeholder="language == 0 ? '请输入姓名' : 'Nama'"
/>
</div>
<div>
<div class="label">
{{ languageFormat(language, "证件类型", "Type of Document") }}
</div>
<el-input
v-model="people.type"
style="width: 570px"
placeholder="Please input"
readonly
/>
</div>
</div>
<div class="form-item">
<div>
<div class="label">
{{ languageFormat(language, "身份证号", "Identity Card") }}
</div>
<el-input
v-model="people.form.idCard"
style="width: 570px"
:placeholder="language == 0 ? '请输入身份证号' : 'ID Numbe'"
/>
</div>
</div>
</div>
<div class="footer">
<div class="can_pay">
{{ languageFormat(language, "取消", "Cancel") }}
</div>
<div class="pay" @click="people.onConfirm()">
{{ languageFormat(language, "确认", "Confirm") }}
</div>
</div>
</div>
</template>
<style scoped lang="scss">
div {
box-sizing: border-box;
}
.container {
padding: 20px 0;
width: 1200px;
margin: 0 auto;
.title {
padding: 11px;
text-align: center;
background: linear-gradient(270deg, #493ceb 0%, #8623fc 100%);
font-size: 18px;
color: #ffffff;
}
.content {
padding: 46px 20px 24px;
background-color: #fff;
:deep(.el-input) {
height: 48px;
border-radius: 24px !important;
}
.form-item {
display: flex;
gap: 20px;
margin-bottom: 36px;
&:last-child {
margin: 0;
}
.label {
font-size: 18px;
color: #333333;
margin-bottom: 16px;
}
}
}
.footer {
display: flex;
justify-content: center;
align-items: center;
gap: 20px;
height: 70px;
background-color: #fff;
margin-top: 12px;
.pay {
width: 200px;
height: 40px;
background: linear-gradient(270deg, #493ceb 0%, #8623fc 100%);
border-radius: 20px;
font-weight: 500;
font-size: 16px;
color: #ffffff;
line-height: 40px;
text-align: center;
cursor: pointer;
}
.can_pay {
width: 200px;
height: 40px;
background: #f6f6f6;
border-radius: 20px;
font-weight: 500;
font-size: 16px;
color: #999;
line-height: 40px;
text-align: center;
box-sizing: border-box;
cursor: pointer;
}
}
}
</style>
import request from "../utils/request";
export const loginFree = (data) => request("POST", "/login/loginFree", data);
/** 活动详情 */
export const activityDetail = (data) =>
request("GET", `/api/activity/detail/${data.actId}`, data);
/** 场次详情 */
export const sessionDetail = (data) =>
request("GET", `/api/activity/sessionDetail/${data.actId}`, data);
/** 获取场馆信息 */
export const getSitePlaceInfo = (data) =>
request("GET", `/api/activity/getSitePlaceInfo`, data);
/** 获取票档信息 */
export const getPriceLevelInfo = (data) =>
request("GET", `/api/activity/getPriceLevelInfo`, data);
/** 获取座位信息 */
export const getSiteConfig = (data) =>
request("GET", `/api/activity/getSiteConfig`, data);
/** 确认订单 */
export const confirmOrder = (data) =>
request("POST", `/api/order/confirmOrder`, data);
/** 订单支付 */
export const payOrder = (data) =>
request("POST", `/api/order/payment`, data);
/** 观众列表 */
export const viewPeopleList = (data) =>
request("GET", `/api/customer/list`, data);
/** 删除观众 */
export const deleteViewPeople = (data) =>
request("POST", `/api/customer/delete/${data.id}`, data);
/** 新增观众 */
export const addViewPeople = (data) =>
request("POST", `/api/customer/add`, data);
/** 订单列表 */
export const getOrderList = (data) =>
request("GET", `/api/order/list`, data);
/** 立即支付 */
export const immediatePay = (data) =>
request("POST", `/api/order/immediatePay`, data);
/** 取消支付 */
export const cancelPay = (data) =>
request("POST", `/api/order/cancelPay/${data.orderSn}`, data);
/** 退单 */
export const cancelOrder = (data) =>
request("POST", `/api/order/cancelOrder/${data.orderSn}`, data);
/** 订单详情 */
export const getOrderDetail = (data) =>
request("GET", `/api/order/detail/${data.orderSn}`, data);
/** 检查是否支付成功 */
export const checkPaySuccess = (data) =>
request("POST", `/api/order/checkOrderIsPay/${data.orderSn}`, data);
<script setup>
const props = defineProps({
showCodeDialog: {
type: Boolean,
default: false,
},
qrCode: {
type: String,
default: "",
},
});
const emit = defineEmits(["closeDialog"]);
const handleCloce = () => {
emit("closeDialog", false);
};
</script>
<template>
<div>
<el-dialog
v-model="props.showCodeDialog"
title="支付"
width="300"
:before-close="handleCloce()"
>
<div>
<img class="qrcode" :src="props.qrCode" />
</div>
</el-dialog>
</div>
</template>
<style scoped lang="scss">
.qrcode {
width: 150px;
height: 150px;
background-color: #8623fc;
margin: 0 auto;
}
</style>
<script setup>
import { confirmOrder } from "./api/index.js";
import { ElMessage } from "element-plus";
import { payOrder, viewPeopleList, checkPaySuccess } from "./api/index.js";
import qrCodeDialog from "./components/qrCodeDialog.vue";
import qrcode from "qrcode";
import { languageFormat } from "./utils/language.js";
import { useStorage } from "@vueuse/core/index";
const language = useStorage("language", 0);
const route = useRoute();
const router = useRouter();
const props = defineProps({
activityId: [String, Number],
});
let timer = null;
const startCheckSuccessListener = (orderSn, actId) => {
timer = setInterval(() => {
checkPaySuccess({ orderSn }).then((res) => {
if (res.data) {
clearInterval(timer);
timer = null;
// 支付成功
payment.showCodeDialog = false;
ElMessage({
type: "success",
message: anguageFormat(
language.value,
"支付成功",
"Payment succeeded"
),
});
router.replace({
path: "/seat/order",
});
} else {
return false;
}
});
}, 3000);
};
const payment = reactive({
showCodeDialog: false,
btn_loading: false,
form: {
viewers: [],
phone: "",
},
qrInfo: {},
qrCodeData: "",
paymentHandle() {
if (payment.form.viewers.length != order.data?.seatInfo?.length)
return ElMessage({
type: "warning",
message: languageFormat(
language.value,
"观看人与购买票数不符",
"The number of viewers does not match the number of tickets purchased."
),
});
if (!payment.form.phone)
return ElMessage({
type: "warning",
message: languageFormat(
language.value,
"请输入联系电话",
"Please enter the contact phone number."
),
});
payOrder({
contactPhone: payment.form.phone,
customerIds: payment.form.viewers,
orderToken: order.data?.orderToken,
payType: 1,
paymentAmount: order.data?.paymentAmount,
}).then((res) => {
if (res.data.language == "zh-cn") {
payment.qrInfo = res.data;
qrcode.toDataURL(res.data.scanCodeUrl, (err, url) => {
if (url) {
payment.qrCodeData = url;
}
});
payment.showCodeDialog = true;
startCheckSuccessListener(res.data.orderSn, props.activityId);
} else {
// TODO: 这里是PayPal支付
}
});
},
handleCloce() {
payment.showCodeDialog = false;
payment.qrCodeData = "";
clearInterval(timer);
timer = null;
},
});
const order = reactive({
data: null,
fetchData() {
confirmOrder({
actId: props.activityId,
openType: route.query.openType,
sessionId: route.query.sessionId,
sitePlace: route.query.sitePlace,
ticketType: route.query.ticketType,
seatIds: route.query.seatIds.split(","),
}).then((res) => {
this.data = res.data;
});
},
});
const audience = reactive({
data: [],
fetchData() {
viewPeopleList().then((res) => {
audience.data = res.data;
});
},
});
onUnmounted(() => {
clearInterval(timer);
});
audience.fetchData();
order.fetchData();
</script>
<template>
<div class="container">
<div class="title">
{{ languageFormat(language, "订单确认", "Order confirmation") }}
</div>
<div class="content">
<div class="left">
<div class="info">
<div class="name">{{ order.data?.activityName }}</div>
<div class="address">{{ order.data?.placeName }}</div>
</div>
<div class="ticket_info">
<div class="tit_box">
<div class="line"></div>
<div class="txt">
{{ languageFormat(language, "订票信息", "Ticket Info") }}
</div>
</div>
<div class="form">
<el-form>
<el-form-item :label="language == 0 ? '联系人' : 'contacts'">
<el-input
v-model="payment.form.phone"
:placeholder="
language == 0
? '请输入联系电话'
: 'Please enter the contact phone number'
"
style="width: 260px"
/>
</el-form-item>
<el-form-item :label="language == 0 ? '观看人' : 'contacts'">
<div class="p_box">
<div class="people">
<el-checkbox-group
v-model="payment.form.viewers"
:max="order.data?.seatInfo?.length"
>
<div
v-for="(it, index) in audience.data"
:key="index"
class="prople_item"
>
<div>
<div class="name">{{ it.name }}</div>
<div class="idcard">{{ it.idCard }}</div>
</div>
<el-checkbox :value="it.id"> </el-checkbox>
</div>
</el-checkbox-group>
</div>
<!-- button -->
<div
class="btn"
@click="$router.push({ path: '/seat/people_manage' })"
>
{{ languageFormat(language, "新增", "Add") }}
</div>
</div>
</el-form-item>
</el-form>
</div>
</div>
</div>
<div class="right">
<div class="tit_box">
<div class="line"></div>
<div class="txt">
{{ languageFormat(language, "订单明细", "Order summary") }}
</div>
</div>
<div class="detail">
<div class="detail_top">
<div class="time">{{ order.data?.dateStr }}</div>
<div class="ticket">
{{ order.data?.singlePrice }}<span v-if="language == 0"></span
>{{ languageFormat(language, "票档", "Ticket file") }} x{{
order.data?.seatInfo?.length
}}{{ languageFormat(language, "张", "tickets") }}
</div>
</div>
<div class="detail_center">
<div
v-for="(it, index) in order.data?.seatInfo"
:key="index"
class="ticket"
>
<span v-if="it.venueId == 1"
>{{ it.area }}{{ languageFormat(language, "区", "Zones") }}
</span>
{{ it.pai }}{{ languageFormat(language, "排", "Row") }} {{ it.no
}}{{ languageFormat(language, "座", "Seat") }} ({{
it.venueId == 1 ? "B6" : "B4"
}}{{ languageFormat(language, "馆", "Venue") }})
</div>
</div>
<div class="detail_b">
<div class="sum_txt">
{{ languageFormat(language, "共计", "Total") }}
</div>
<div class="price_num">
<span v-if="language == 1">¥</span>{{ order.data?.paymentAmount }}
</div>
</div>
</div>
</div>
</div>
<div class="footer">
<div>
<span class="label"
>{{ languageFormat(language, "共计金额", "Subtotal") }}</span
><span class="value">¥{{ order.data?.paymentAmount }}</span>
</div>
<div class="pay" @click="payment.paymentHandle()">
{{ languageFormat(language, "立即支付", "Pay Now") }}
</div>
</div>
<el-dialog
v-model="payment.showCodeDialog"
title="支付"
width="300"
@closed="payment.handleCloce()"
>
<div>
<img class="qrcode" :src="payment.qrCodeData" />
</div>
</el-dialog>
</div>
</template>
<style scoped lang="scss">
div {
box-sizing: border-box;
}
.qrcode {
width: 200px;
height: 200px;
margin: 0 auto;
}
.container {
padding: 20px 0;
width: 1200px;
margin: 0 auto;
.title {
padding: 11px;
text-align: center;
background: linear-gradient(270deg, #493ceb 0%, #8623fc 100%);
font-size: 18px;
color: #ffffff;
}
.content {
display: flex;
background-color: #fff;
padding: 20px 0;
}
.line {
width: 4px;
height: 18px;
background: linear-gradient(180deg, #493ceb 0%, #8623fc 100%);
border-radius: 4px;
}
.left {
padding-left: 20px;
.info {
width: 640px;
background: rgba(69, 61, 234, 0.04);
border-radius: 8px;
border: 1px solid #d3d1f6;
padding: 20px 0 28px 33px;
margin-bottom: 20px;
.name {
font-weight: 500;
font-size: 18px;
color: #000000;
margin-bottom: 20px;
}
.address {
font-weight: 400;
font-size: 14px;
color: #929aa0;
}
}
.ticket_info {
.tit_box {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 14px;
.txt {
font-weight: bold;
font-size: 16px;
color: #493ceb;
}
}
.form {
width: 640px;
min-height: 464px;
padding: 20px 60px;
border-radius: 5px;
border: 1px solid #dcdfe6;
.p_box {
display: flex;
gap: 10px;
.people {
width: 298px;
background: #fbfcfd;
border-radius: 2px;
border: 1px solid #dcdfe6;
padding: 0 14px;
.prople_item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 14px 0;
border-bottom: 1px solid #dcdfe6;
&:last-child {
border: none;
}
.name {
font-size: 16px;
color: #929aa0;
margin-bottom: 20px;
}
.idcard {
font-size: 10px;
color: #929aa0;
}
}
}
.btn {
width: 90px;
height: 40px;
background: #fbfcfd;
border-radius: 20px;
border: 1px solid #493ceb;
margin-top: 10px;
font-size: 14px;
color: #493ceb;
line-height: 40px;
text-align: center;
cursor: pointer;
user-select: none;
}
}
}
}
}
.right {
width: 460px;
margin-left: 36px;
.tit_box {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 20px;
.txt {
font-weight: bold;
font-size: 16px;
color: #493ceb;
}
}
.detail {
padding: 15px 26px;
border-radius: 5px;
border: 1px solid #dcdfe6;
.detail_top {
padding-bottom: 13px;
border-bottom: 1px solid #dcdfe6;
.time {
font-weight: 500;
font-size: 18px;
color: #2d373f;
line-height: 25px;
margin-bottom: 8px;
}
.ticket {
font-size: 16px;
color: #2d373f;
}
}
.detail_center {
margin-top: 14px;
display: flex;
flex-direction: column;
padding-bottom: 13px;
border-bottom: 1px solid #dcdfe6;
gap: 8px;
.ticket {
font-size: 16px;
color: #2d373f;
}
}
.detail_b {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 16px;
.sum_txt {
font-weight: 600;
font-size: 18px;
color: #2d373f;
line-height: 25px;
}
.price_num {
font-weight: 600;
font-size: 36px;
color: #ff8124;
line-height: 50px;
}
}
}
}
.footer {
display: flex;
justify-content: space-between;
height: 70px;
align-items: center;
background: #ffffff;
box-shadow: 0px 0px 46px 0px rgba(1, 16, 64, 0.08);
margin-top: 9px;
padding: 0 30px;
.label {
font-size: 16px;
color: #7b7f83;
line-height: 22px;
}
.value {
font-size: 22px;
color: #ff8124;
line-height: 30px;
font-weight: 600;
}
.pay {
width: 200px;
height: 40px;
background: linear-gradient(270deg, #493ceb 0%, #8623fc 100%);
border-radius: 20px;
font-weight: 500;
font-size: 16px;
color: #ffffff;
line-height: 40px;
text-align: center;
cursor: pointer;
user-select: none;
}
}
}
</style>
<script setup>
import { onBeforeUnmount, reactive } from "vue";
import {
cancelOrder,
getOrderDetail,
immediatePay,
cancelPay,
checkPaySuccess,
} from "./api/index.js";
import qrCodeDialog from "./components/qrCodeDialog.vue";
import { ElMessageBox, ElMessage } from "element-plus";
import qrcode from "qrcode";
import { languageFormat } from "./utils/language.js";
import { useStorage } from "@vueuse/core/index";
const language = useStorage("language", 0);
const route = useRoute();
const router = useRouter();
const status = reactive({
0: {
txt: "待支付",
color: "#F740A6",
bgColor: "#FFE2F2",
},
1: {
txt: "购票成功",
color: "#FFCC00",
bgColor: "#FFF7D9",
},
2: {
txt: "交易关闭",
color: "#757575",
bgColor: "#DDDDDD",
},
3: {
txt: "已退款",
color: "#757575",
bgColor: "#DDDDDD",
},
4: {
color: "#F740A6",
bgColor: "#FFE2F2",
},
5: {
txt: "完成",
color: "#34C759",
bgColor: "#D2FFDD",
},
});
const props = defineProps({
activityId: [String, Number],
});
let timer = null;
const startCheckSuccessListener = (orderSn, actId) => {
timer = setInterval(() => {
checkPaySuccess({ orderSn }).then((res) => {
if (res.data) {
clearInterval(timer);
timer = null;
// 支付成功
detail.showCodeDialog = false;
detail.fetchData();
ElMessage({ type: "success", message: "支付成功" });
} else {
return false;
}
});
}, 3000);
};
const detail = reactive({
showCodeDialog: false,
qrCodeData: "",
pay_loading: false,
qrInfo: {},
data: null,
timer: null,
// 分钟
minutes: 0,
seconds: 0,
fetchData() {
getOrderDetail({ orderSn: route.query.orderSn }).then((res) => {
detail.data = res.data;
detail.countDown(detail.data?.payEndTime);
});
},
// 倒计时
countDown(time) {
// 当前时间
let nowTime = new Date();
let endTime = new Date(time);
// 两个日期相差的时间戳,以毫秒为单位(1000ms = 1s)
let totalTime = endTime - nowTime;
// 结束时间大于现在的时间
if (totalTime > 0) {
detail.timer = setInterval(() => {
if (totalTime >= 0) {
//获取分钟数
let minutes = Math.floor(
(((totalTime % (3600 * 24 * 1000)) / 1000) % 3600) / 60
);
//获取秒数
let seconds = Math.floor(
(((totalTime % (3600 * 24 * 1000)) / 1000) % 3600) % 60
)
.toString()
.padStart(2, "0");
detail.minutes = minutes;
detail.seconds = seconds;
totalTime -= 1000;
// console.log(totalTime)
} else {
clearInterval(detail.timer); // 停止调用函数
detail.fetchData();
}
}, 1000);
}
},
payment() {
if (detail.pay_loading) return;
detail.pay_loading = true;
immediatePay({ orderSn: detail.data.orderSn, payType: 1 })
.then((res) => {
if (res.data.language == "zh-cn") {
detail.qrInfo = res.data;
qrcode.toDataURL(res.data.scanCodeUrl, (err, url) => {
if (url) {
detail.qrCodeData = url;
}
});
startCheckSuccessListener(detail.data.orderSn);
detail.showCodeDialog = true;
} else {
// TODO: 这里是PayPal支付
}
})
.finally(() => (detail.pay_loading = false));
},
handleClose() {
detail.showCodeDialog = false;
detail.qrCodeData = "";
clearInterval(timer);
timer = null;
},
// 取消支付
cancelPay() {
ElMessageBox.confirm(
languageFormat(
language.value,
"确认取消支付吗?",
"Are you sure to cancel?"
),
languageFormat(language.value, "提示", "tip"),
{
confirmButtonText: languageFormat(language.value, "确认", "confirm"),
cancelButtonText: languageFormat(language.value, "取消", "cancel"),
type: "warning",
draggable: true,
}
)
.then(() => {
cancelPay({ orderSn: detail.data.orderSn }).then(() => {
detail.fetchData();
ElMessage({
type: "success",
message: languageFormat(
language.value,
"操作成功",
"Operate successfully"
),
});
});
})
.catch(() => {});
},
// 取消购票
cancelOrder() {
ElMessageBox.confirm(
languageFormat(
language.value,
"确认取消购票吗?",
"Are you sure to cancel?"
),
languageFormat(language.value, "提示", "tip"),
{
confirmButtonText: languageFormat(language.value, "确认", "confirm"),
cancelButtonText: languageFormat(language.value, "取消", "cancel"),
type: "warning",
draggable: true,
}
)
.then(() => {
cancelOrder({ orderSn: detail.data.orderSn }).then((res) => {
detail.fetchData();
ElMessage({
type: "success",
message: languageFormat(
language.value,
"操作成功",
"Operate successfully"
),
});
});
})
.catch(() => {});
},
comeBack() {
router.push({
path: "/seat/detail",
query: {
id: props.activityId,
},
});
},
});
onBeforeUnmount(() => {
clearInterval(detail.timer);
clearInterval(timer);
});
detail.fetchData();
</script>
<template>
<div class="container">
<div class="left">
<!-- 票务信息 -->
<div class="ticket">
<div class="th">
<div style="width: 33%" class="td">
{{ languageFormat(language, "票务信息", "Ticket Info") }}
</div>
<div style="width: 25%" class="td">
{{ languageFormat(language, "地点", "Venue") }}
</div>
<div style="width: 20%" class="td">
{{ languageFormat(language, "单价", "Price") }}
</div>
<div style="width: 10%" class="td">
{{ languageFormat(language, "数量", "Ticket Qty.") }}
</div>
<div style="width: 12%; text-align: right" class="td">
{{ languageFormat(language, "小计", "Subtotal") }}
</div>
</div>
<div class="line"></div>
<div class="tr">
<div style="width: 30%" class="td">{{ detail.data?.name }}</div>
<div style="width: 25%" class="td">{{ detail.data?.placeName }}</div>
<div style="width: 20%" class="td">
¥{{ detail.data?.singlePrice }}
</div>
<div style="width: 12%" class="td">
x{{ detail.data?.seatList?.length }}
</div>
<div style="width: 13%; text-align: right" class="td">
¥{{ detail.data?.payAmount }}
</div>
</div>
</div>
<!-- 座位 -->
<div class="seat_box">
<div class="th">
<div style="width: 30.33%" class="td">
{{ languageFormat(language, "时间座位", "Seat Info") }}
</div>
<div style="width: 30.33%" class="td">
{{ languageFormat(language, "订单信息", "Summary") }}
</div>
<div style="width: 30.33%" class="td">
{{ languageFormat(language, "联系方式", "Contact details") }}
</div>
</div>
<div class="tr">
<div style="width: 30.33%" class="td flex-col">
<div>{{ detail.data?.dateStr }}</div>
<div v-for="(it, index) in detail.data?.seatList" :key="index">
<span v-if="it.venueId == 1"
>{{ it.area
}}{{ languageFormat(language, "区", "Zones") }}</span
>{{ it.pai }}{{ languageFormat(language, "排", "Row") }}{{ it.no
}}{{ languageFormat(language, "座", "Seat") }} ({{
it.venueId == 1 ? "B6" : "B4"
}}{{ languageFormat(language, "馆", "Venue") }})
</div>
</div>
<div style="width: 30.33%" class="td flex-col">
<div>
{{ languageFormat(language, "订单编号", "Order No.") }}{{
detail.data?.orderSn
}}
</div>
<div>
{{ languageFormat(language, "创建时间", "Order Time") }}{{
detail.data?.orderTime
}}
</div>
</div>
<div style="width: 30.33%" class="td">
<div>
{{ languageFormat(language, "联系电话", "Telephone") }}{{
detail.data?.contactPhone
}}
</div>
</div>
</div>
</div>
<!-- 购票人 -->
<div class="pay_ticket">
<div class="title">
{{ languageFormat(language, "购票人", "Full Name") }}
</div>
<div class="people">
<div
v-for="(it, index) in detail.data?.customerList"
:key="index"
class="p_info"
>
<div>{{ it.name }}</div>
<div class="idcard">
{{ languageFormat(language, "身份证", "ID number") }}{{
it.idCard
}}
</div>
</div>
</div>
</div>
</div>
<div class="right">
<div class="balance">
<div class="title">
{{ languageFormat(language, "结算信息", "Payment details") }}
</div>
<div class="cell">
<div class="label">
{{ languageFormat(language, "订单状态", "Order Status") }}
</div>
<div
class="value"
:style="{ color: status[detail.data?.state]?.color }"
>
{{ status[detail.data?.state]?.txt }}
</div>
</div>
<div class="cell">
<div class="label">
{{ languageFormat(language, "订单金额", "Order amount") }}
</div>
<div
class="value"
:style="{ color: status[detail.data?.state]?.color }"
>
<span v-if="language == 0">¥</span>{{ detail.data?.payAmount }}
</div>
</div>
<!-- button -->
<div v-if="detail.data?.state == 0" class="btn_box">
<div class="can_pay" @click="detail.cancelPay()">
{{ languageFormat(language, "取消支付", "Cancel the payment") }}
</div>
<div class="pay" @click="detail.payment()">
{{ languageFormat(language, "立即支付", "Pay Now") }}
</div>
</div>
<div v-else>
<!-- v-if="detail.data?.state == 1 && detail.data?.isRefund" -->
<div
v-if="detail.data?.state == 1 && detail.data?.isRefund"
class="btn_box"
>
<div class="can_pay" @click="detail.cancelOrder()">
{{
languageFormat(
language,
"取消购票",
"Cancel the ticket purchase"
)
}}
</div>
<div class="pay" @click="detail.comeBack()">
{{ languageFormat(language, "再来一单", "Make another order") }}
</div>
</div>
<div v-else class="btn_box">
<div class="pay_dis">
{{
languageFormat(
language,
"请联系工作人员",
"Please contact the staff"
)
}}
</div>
</div>
</div>
</div>
<div v-if="detail.data?.state == 0" class="tip">
<span v-if="language == 0"
>请尽快完成支付,还剩{{ detail.minutes }}{{
detail.seconds
}}</span
>
<span v-if="language == 1"
>Time left {{ detail.minutes }}:{{ detail.seconds }}</span
>
</div>
</div>
<!-- <qrCodeDialog
:showCodeDialog="detail.showCodeDialog"
:qrCode="detail.qrCodeData"
/> -->
<el-dialog
v-model="detail.showCodeDialog"
title="支付"
width="300"
@closed="detail.handleClose()"
>
<div>
<img class="qrcode" :src="detail.qrCodeData" />
</div>
</el-dialog>
</div>
</template>
<style scoped lang="scss">
.qrcode {
width: 200px;
height: 200px;
margin: 0 auto;
}
.container {
width: 1200px;
margin: 0 auto;
padding: 20px 0;
display: flex;
gap: 20px;
.left {
width: 780px;
// 票务信息
.ticket {
background-color: #fff;
padding: 0 20px;
.th {
display: flex;
justify-content: space-between;
padding: 20px 0;
.td {
font-weight: bold;
font-size: 16px;
color: #333333;
line-height: 24px;
}
}
.line {
width: 740px;
height: 1px;
background: #eee;
}
.tr {
display: flex;
justify-content: space-between;
padding: 20px 0;
.td {
font-weight: 400;
font-size: 16px;
color: #333333;
line-height: 24px;
}
}
}
// 座位
.seat_box {
background-color: #fff;
padding: 0 20px;
margin-top: 20px;
.th {
display: flex;
justify-content: space-between;
padding: 20px 0;
.td {
font-weight: bold;
font-size: 16px;
color: #333333;
line-height: 24px;
}
}
.tr {
display: flex;
justify-content: space-between;
padding: 20px 0;
.td {
font-weight: 400;
font-size: 16px;
color: #333333;
line-height: 24px;
}
.flex-col {
display: flex;
flex-direction: column;
gap: 16px;
}
}
}
// 购票人
.pay_ticket {
background-color: #fff;
padding: 20px;
margin-top: 20px;
.title {
font-weight: bold;
font-size: 16px;
color: #333333;
margin-bottom: 28px;
}
.people {
display: flex;
justify-content: space-between;
flex-wrap: wrap;
gap: 15px 50px;
.p_info {
font-weight: 400;
font-size: 16px;
color: #333333;
line-height: 24px;
.idcard {
color: #999999;
}
}
}
}
}
.right {
width: 400px;
.balance {
background-color: #fff;
padding: 20px;
.title {
font-weight: bold;
font-size: 20px;
color: #333333;
line-height: 30px;
margin-bottom: 28px;
}
.cell {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
&:last-child {
margin: 0;
}
.label {
font-weight: 400;
font-size: 16px;
color: #333333;
}
.value {
font-weight: 400;
font-size: 16px;
color: #ff8124;
}
}
.btn_box {
border-top: 1px solid #eee;
padding-top: 20px;
display: flex;
gap: 20px;
user-select: none;
.pay_dis {
width: 360px;
height: 40px;
background: #a09dff;
border-radius: 20px;
font-weight: 500;
font-size: 16px;
color: #ffffff;
line-height: 40px;
text-align: center;
cursor: pointer;
}
.pay {
width: 170px;
height: 40px;
background: linear-gradient(270deg, #493ceb 0%, #8623fc 100%);
border-radius: 20px;
font-weight: 500;
font-size: 16px;
color: #ffffff;
line-height: 40px;
text-align: center;
cursor: pointer;
}
.can_pay {
width: 170px;
height: 40px;
background: #f6f6f6;
border-radius: 20px;
font-weight: 500;
font-size: 16px;
color: #999;
line-height: 40px;
text-align: center;
box-sizing: border-box;
cursor: pointer;
}
}
}
.tip {
font-weight: 400;
font-size: 16px;
color: #ea3d6b;
line-height: 24px;
margin-top: 20px;
text-align: center;
}
}
}
</style>
<script setup>
import { setToken, getToken } from "./utils/local-store.js";
import useUserStore from "@/store/modules/user";
import {
getOrderList,
immediatePay,
cancelPay,
loginFree,
} from "./api/index.js";
import qrCodeDialog from "./components/qrCodeDialog.vue";
import { ElMessageBox, ElMessage } from "element-plus";
import qrcode from "qrcode";
import { md5 } from "md5js";
import { languageFormat } from "./utils/language.js";
import { useStorage } from "@vueuse/core/index";
const language = useStorage("language", 0);
const userStore = useUserStore();
const status = reactive({
0: {
txt: "待支付",
text_en: "Pending Payment",
color: "#F740A6",
bgColor: "#FFE2F2",
},
1: {
txt: "购票成功",
text_en: "Transaction completed",
color: "#FFCC00",
bgColor: "#FFF7D9",
},
2: {
txt: "交易关闭",
text_en: "Transaction closed",
color: "#757575",
bgColor: "#DDDDDD",
},
3: {
txt: "已退款",
text_en: "Already refunded",
color: "#757575",
bgColor: "#DDDDDD",
},
4: {
txt: "退款中",
text_en: "In the process of refunding",
color: "#F740A6",
bgColor: "#FFE2F2",
},
5: {
txt: "完成",
text_en: "Finish",
color: "#34C759",
bgColor: "#D2FFDD",
},
});
const props = defineProps({
activityId: [String, Number],
});
const order = reactive({
showCodeDialog: false,
qrInfo: {},
pay_loading: false,
pageNo: 1,
pageSize: 10,
total: 0,
noPay: {},
minutes: 0,
seconds: 0,
data: [],
timer: null,
qrCodeData: "",
fetchData() {
getOrderList({ pageNo: order.pageNo, pageSize: order.pageSize }).then(
(res) => {
order.noPay = res.data.lists.find((it) => it.state == 0);
order.data = res.data.lists;
order.total = res.data.count;
}
);
},
payment(it) {
if (order.pay_loading) return;
order.pay_loading = true;
immediatePay({ orderSn: it.orderSn, payType: 1 })
.then((res) => {
order.qrInfo = res.data;
qrcode.toDataURL(res.data.scanCodeUrl, (err, url) => {
if (err) {
console.error(err);
} else {
order.qrCodeData = url;
}
});
order.showCodeDialog = true;
})
.finally(() => (order.pay_loading = false));
},
handleClose() {
order.showCodeDialog = false;
order.qrCodeData = "";
},
// 取消支付
cancelPayment(it) {
ElMessageBox.confirm(
languageFormat(
language.value,
"确认取消支付吗?",
"Are you sure to cancel the payment?"
),
languageFormat(language.value, "提示", "tip"),
{
confirmButtonText: languageFormat(language.value, "确认", "confirm"),
cancelButtonText: languageFormat(language.value, "取消", "cancel"),
type: "warning",
draggable: true,
}
)
.then(() => {
cancelPay({ orderSn: it.orderSn }).then(() => {
order.fetchData();
ElMessage({
type: "success",
message: languageFormat(
language.value,
"操作成功",
"Operate successfully"
),
});
});
})
.catch(() => {});
},
countDown(time) {
// 当前时间
let nowTime = new Date();
let endTime = new Date(time);
// 两个日期相差的时间戳,以毫秒为单位(1000ms = 1s)
let totalTime = endTime - nowTime;
// 结束时间大于现在的时间
if (totalTime > 0) {
order.timer = setInterval(() => {
if (totalTime >= 0) {
//获取分钟数
let minutes = Math.floor(
(((totalTime % (3600 * 24 * 1000)) / 1000) % 3600) / 60
);
//获取秒数
let seconds = Math.floor(
(((totalTime % (3600 * 24 * 1000)) / 1000) % 3600) % 60
)
.toString()
.padStart(2, "0");
order.minutes = minutes;
order.seconds = seconds;
totalTime -= 1000;
// console.log(totalTime)
} else {
clearInterval(order.timer); // 停止调用函数
}
}, 1000);
}
},
});
watch(
() => order.noPay,
(val) => {
if (val) {
order.countDown(val.payEndTime);
}
}
);
onUnmounted(() => {
clearInterval(order.timer);
});
// 用户免登录
const login = async () => {
const userId = userStore.user?.userId;
const sign = md5(`uid=${userId}lgo1acfkw51jfo`, 32);
return loginFree({
userId: userId,
sign,
}).then((res) => {
setToken(res.data.token);
order.fetchData();
});
};
onMounted(() => {
login();
});
</script>
<template>
<div class="container">
<div
v-for="(it, index) in order.data"
:key="index"
@click="
$router.push({
path: '/seat/order_detail',
query: { orderSn: it.orderSn, id: it.actId },
})
"
class="order-item"
>
<div class="info_box">
<img class="cover_img" :src="it.coverImg" />
<div class="info">
<div class="title">{{ it.name }}</div>
<div class="common">
{{ languageFormat(language, "时间", "Event Date & Time") }}{{
it.dateStr
}}
</div>
<div class="common">
{{ languageFormat(language, "地址", "Location") }}{{
it.placeName
}}
</div>
<div class="common">
{{ languageFormat(language, "订单编号", "Order No.") }}{{
it.orderSn
}}
</div>
<div class="common">
{{ languageFormat(language, "张数", "Location") }}{{ it.ticketNum
}}{{ languageFormat(language, "张", "tickets") }}
</div>
<div class="common">
{{ languageFormat(language, "金额", "Ticket Price") }}<span
v-if="language == 0"
></span
>{{ it.payAmount }}
</div>
<div class="status">
<div class="label">
{{ languageFormat(language, "订单状态", "Order Status") }}
</div>
<div class="value">
<div
:style="{
borderColor: status[it.state].color,
background: status[it.state].bgColor,
color: status[it.state].color,
}"
class="tag"
>
{{
language == 0 ? status[it.state].txt : status[it.state].txt_en
}}
</div>
<div v-if="it.state == 0" class="tip">
<span v-if="language == 0"
>请尽快完成支付,还剩{{ order.minutes }}{{
order.seconds
}}</span
>
<span v-else
>Time left {{ order.minutes }}:{{ order.seconds }}</span
>
</div>
</div>
</div>
</div>
</div>
<div v-if="it.state == 0" class="btn_box">
<div class="pay">立即支付</div>
<div class="can_pay" @click.stop="order.cancelPayment(it)">
取消支付
</div>
</div>
</div>
<div class="pagination">
<el-pagination
v-show="order.total > 0"
v-model:current-page="order.pageNo"
v-model:page-size="order.pageSize"
background
layout="prev, pager, next"
:total="order.total"
@current-change="order.fetchData()"
/>
</div>
<el-dialog
v-model="order.showCodeDialog"
title="支付"
width="300"
@closed="order.handleClose()"
>
<div>
<img class="qrcode" :src="order.qrCodeData" />
</div>
</el-dialog>
</div>
</template>
<style scoped lang="scss">
.qrcode {
width: 150px;
height: 150px;
margin: 0 auto;
}
.container {
width: 1200px;
margin: 0 auto;
padding: 26px 0;
font-family: SourceHanSansCN, SourceHanSansCN;
.order-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 36px;
background: #fff;
box-shadow: 0px 0px 46px 0px rgba(1, 16, 64, 0.08);
border-radius: 8px;
margin-bottom: 30px;
cursor: pointer;
.info_box {
display: flex;
gap: 20px;
.cover_img {
width: 155px;
height: 200px;
object-fit: fill;
}
.info {
.title {
font-weight: bold;
font-size: 22px;
color: #000000;
line-height: 33px;
margin-bottom: 25px;
margin-bottom: 10px;
}
.common {
font-weight: 500;
font-size: 16px;
color: #4e4e4e;
margin-bottom: 6px;
}
.status {
display: flex;
.label {
font-weight: 500;
font-size: 16px;
color: #4e4e4e;
line-height: 24px;
}
.value {
display: flex;
align-items: center;
gap: 20px;
.tag {
padding: 6px 14px;
border-radius: 6px;
border: 1px solid #34c759;
}
.tip {
font-size: 16px;
color: #f740a6;
line-height: 24px;
}
}
}
}
}
.btn_box {
display: flex;
flex-direction: column;
gap: 12px;
.pay {
width: 175px;
height: 40px;
background: linear-gradient(270deg, #493ceb 0%, #8623fc 100%);
border-radius: 20px;
font-weight: 500;
font-size: 16px;
color: #ffffff;
line-height: 40px;
text-align: center;
cursor: pointer;
}
.can_pay {
width: 175px;
height: 40px;
background: #fff;
border-radius: 20px;
font-weight: 500;
font-size: 16px;
color: #493ceb;
line-height: 40px;
border: 1px solid #493ceb;
text-align: center;
box-sizing: border-box;
cursor: pointer;
}
}
}
}
.pagination {
display: flex;
justify-content: center;
}
</style>
<script setup>
import { deleteViewPeople, viewPeopleList } from "./api/index.js";
import { ElMessageBox, ElMessage } from "element-plus";
import { languageFormat } from "./utils/language.js";
import { useStorage } from "@vueuse/core/index";
const language = useStorage("language", 0);
const audience = reactive({
data: [],
fetchData() {
viewPeopleList().then((res) => {
audience.data = res.data;
});
},
deletePeople(id) {
ElMessageBox.confirm(
languageFormat(
language.value,
"确认删除该观看人吗?",
"Are you sure to delete this viewer?"
),
languageFormat(language.value, "提示", "Reminder"),
{
confirmButtonText: languageFormat(language.value, "确认", "confirm"),
cancelButtonText: languageFormat(language.value, "取消", "cancel"),
type: "warning",
draggable: true,
}
)
.then(() => {
deleteViewPeople({ id }).then(() => {
audience.fetchData();
ElMessage({
type: "success",
message: languageFormat(
language.value,
"操作成功",
"Operate successfully"
),
});
});
})
.catch(() => {});
},
});
audience.fetchData();
</script>
<template>
<div class="container">
<div class="title">
<div
class="add_btn"
@click="$router.push({ path: '/seat/add_watch_people' })"
>
{{ languageFormat(language, "新增", "Add") }}
</div>
{{ languageFormat(language, "观影人管理", "Viewers") }}
</div>
<div class="content">
<div class="people_box">
<div
v-for="(it, index) in audience.data"
:key="index"
class="people_item"
>
<div class="name">{{ it.name }}</div>
<div class="idcard">
{{ languageFormat(language, "身份证", "Identity Card") }}{{
it.idCard
}}
</div>
<div class="btn" @click="audience.deletePeople(it.id)">
{{ languageFormat(language, "删除", "delete") }}
</div>
</div>
</div>
</div>
</div>
</template>
<style scoped lang="scss">
div {
box-sizing: border-box;
}
.container {
padding: 20px 0;
width: 1200px;
margin: 0 auto;
.title {
position: relative;
padding: 11px;
text-align: center;
background: linear-gradient(270deg, #493ceb 0%, #8623fc 100%);
font-size: 18px;
color: #ffffff;
.add_btn {
position: absolute;
left: 20px;
top: 50%;
transform: translateY(-50%);
width: 68px;
height: 24px;
border-radius: 12px;
border: 1px solid #ffffff;
font-weight: 400;
font-size: 12px;
color: #ffffff;
text-align: center;
line-height: 24px;
box-sizing: border-box;
user-select: none;
cursor: pointer;
}
}
.content {
min-height: 590px;
background-color: #fff;
box-shadow: 0px 0px 46px 0px rgba(1, 16, 64, 0.08);
padding: 20px;
.people_box {
display: flex;
flex-wrap: wrap;
gap: 20px;
.people_item {
width: 275px;
height: 137px;
background: #ffffff;
border: 1px solid #dcdfe6;
padding: 16px;
.name {
font-weight: 600;
font-size: 16px;
color: #2d373f;
line-height: 22px;
}
.idcard {
font-size: 16px;
color: #95a1a6;
line-height: 22px;
margin-top: 12px;
margin-bottom: 17px;
}
.btn {
width: 69px;
height: 32px;
background: #e7e6ff;
font-weight: 400;
font-size: 16px;
color: #493ceb;
line-height: 32px;
text-align: center;
cursor: pointer;
user-select: none;
}
}
}
}
}
</style>
<script setup>
import { ElMessage } from "element-plus";
import { getPriceLevelInfo, getSiteConfig, confirmOrder } from "./api/index.js";
import { languageFormat } from "./utils/language.js";
import { useStorage } from "@vueuse/core/index";
const language = useStorage("language", 0);
const route = useRoute();
const router = useRouter();
const iframeRef = ref();
const props = defineProps({
activityId: [String, Number],
});
// 获取票档
const price = reactive({
curPriceId: route.query.ticket_block,
data: [],
fetchData() {
getPriceLevelInfo({
actId: props.activityId ?? 1,
sessionId: route.query.sessionId,
openType: route.query.openType,
sitePlace: route.query.sitePlace,
ticketType: route.query.ticketType,
}).then((res) => {
this.data = res.data;
// price.curPriceId = route.query.ticket_block
});
},
onClickPrice(e) {
if (selectedSeats.value?.length) {
return ElMessage({ type: "warning", message: "请先取消已选座位" });
}
price.curPriceId = e.priceId;
},
});
// 座位禁用时图标地址
const disabledIconUrl =
"https://radv4.gitliuyi.top/images/20240511/unselect_default.png";
function onWindowMessage(e) {
const data = e.data;
if (data.type == "picker-ready") {
// apiPromise.then(() => {})
siteConfig.fetchData().then((res) => {
const seat_arr = res.map((it) => {
let result = {
...it,
active: 0,
};
Object.assign(result, getSeatRenderState(result));
return result;
});
// 子页面加载完毕,这里iframeRef一定ok
sendMsg("load-seats", seat_arr);
setTimeout(() => {
moveToPriceArea(route.query.ticket_block);
}, 500);
});
// 绘制舞台矩形
sendMsg("draw-object-rectangle", {
x: 1800,
y: 960,
w: 4400,
h: 1300,
color: "#e0e0e0",
});
// 绘制舞台文字
sendMsg("draw-object-text", {
x: 3900,
y: 1500,
text: language.value == 0 ? "舞台" : "stage",
style: { fontSize: 160, fontWeight: "400", fill: "#6a6a6a" },
});
} else if (data.type == "seat-click") {
// 子页面点击了座位
const seatData = data.data;
console.log("座位点击", seatData);
// 如果座位处于不可点击状态,就return
if (seatData.state != 1) return;
// 如果当前筛选了某种座位,点击的不是这种座位,也返回
if (price.curPriceId && seatData.priceId != price.curPriceId) return;
if (
selectedSeats.value &&
selectedSeats.value?.length >= 5 &&
seatData.active == 0
)
return ElMessage({
type: "warning",
message: languageFormat(
language.value,
"最多选择5个座位",
"Selectt at most 5 seats"
),
});
const newActive = seatData.active == 0 ? 1 : 0;
const siteConfigItem = siteConfig.data.find((it) => it.id == seatData.id);
if (siteConfigItem) {
siteConfigItem.active = newActive;
}
sendMsg("update-seat", {
id: seatData.id,
data: {
active: newActive,
...getSeatRenderState(siteConfigItem),
},
});
}
}
const siteConfig = reactive({
loading: false,
data: [],
fetchData() {
return getSiteConfig({
actId: props.activityId ?? 1,
openType: route.query.openType,
sessionId: route.query.sessionId,
sitePlace: route.query.sitePlace,
ticketType: route.query.ticketType,
}).then((res) => {
const gridSize = 40;
const seat_arr = res.data.map((it, index) => {
return {
...it,
// 这几个是iframe引擎渲染座位必须的属性,规定好的
x: gridSize * it.x,
y: gridSize * it.y,
w: gridSize,
h: gridSize,
icon: it.state == 1 ? it.unSelectIcon : disabledIconUrl, // 图片的url
active: 0, // 是否选中
priceId: route.query.openType == 0 ? it.dayPriceId : it.nightPriceId,
};
});
siteConfig.data = seat_arr;
return seat_arr;
});
},
});
watch(
() => price.curPriceId,
(priceId) => {
siteConfig.data.forEach((it) => {
sendMsg("update-seat", {
id: it.id,
data: {
...getSeatRenderState(it),
},
});
});
moveToPriceArea(priceId);
console.log("update完成");
}
// { immediate: true }
);
const sendMsg = (type, data) =>
iframeRef.value?.contentWindow.postMessage({ type: type, data: data }, "*");
const getSeatRenderState = (seat) => {
const { state, selectIcon, unSelectIcon } = seat;
const opacity = state == 0 || price.curPriceId == seat.priceId ? 1 : 0.3;
if (state != 1) return { icon: disabledIconUrl, opacity };
return { icon: seat?.active ? selectIcon : unSelectIcon, opacity };
};
/** 平移到某个价格区域 */
const moveToPriceArea = (priceId) => {
const priceSeats = siteConfig.data.filter((it) => it.priceId == priceId);
// 计算出x和y最小的值
const minX = Math.min(...priceSeats.map((it) => it.x));
const minY = Math.min(...priceSeats.map((it) => it.y));
const offset = {
x: 40,
y: 200,
};
sendMsg("stage-scale-to", { scale: 1 });
setTimeout(() => {
sendMsg("stage-move-to", { x: offset.x - minX, y: offset.y - minY });
}, 500);
};
const deleteSiteConfigItem = (seatData) => {
const newActive = seatData.active == 0 ? 1 : 0;
const siteConfigItem = siteConfig.data.find((it) => it.id == seatData.id);
if (siteConfigItem) {
siteConfigItem.active = newActive;
}
sendMsg("update-seat", {
id: seatData.id,
data: {
active: newActive,
...getSeatRenderState(siteConfigItem),
},
});
};
/** 所选座位 */
const selectedSeats =
computed(() => siteConfig.data.filter((it) => it.active == 1)) ?? [];
/** 所选座位价格 */
const sumPrice = computed(() => {
return selectedSeats.value.reduce((total, item) => {
const price =
route.query.openType == 0
? Number(item.dayPrice)
: Number(item.nightPrice);
return total + price;
}, 0);
});
const toConfirmOrder = () => {
const seatIds = selectedSeats.value.map((it) => it.id);
if (!seatIds.length)
return ElMessage({
type: "warning",
message: languageFormat(
language,
"请先选择座位",
"Please select the seat first."
),
});
confirmOrder({
actId: props.activityId,
openType: route.query.openType,
sessionId: route.query.sessionId,
sitePlace: route.query.sitePlace,
ticketType: route.query.ticketType,
seatIds: seatIds,
})
.then((res) => {
router.push({
path: "/seat/confirm_order",
query: {
id: props.activityId,
openType: route.query.openType,
sessionId: route.query.sessionId,
sitePlace: route.query.sitePlace,
ticketType: route.query.ticketType,
seatIds: seatIds.join(","),
},
});
})
.catch((e) => {
if (e.code == "B001") {
router.push({
path: "/seat/order",
query: {
id: props.activityId,
},
});
}
});
};
/**
* 1. 加載iframe 3. 请求API的数据
* 2. 等待iframe里面资源加载完毕并触发picker-ready事件
* 4. 传递数据给iframe,等待渲染
*/
window.addEventListener("message", onWindowMessage);
onBeforeUnmount(() => {
window.removeEventListener("message", onWindowMessage);
});
price.fetchData();
</script>
<template>
<div class="container">
<div class="top">
<div class="time">
<span>{{ route.query?.time_txt }}</span>
<span class="place">{{ route.query.sitePlace }}</span>
</div>
<div class="price_tab">
<div
v-for="(it, index) in price.data"
class="tab_item"
:class="{ tabActive: it.priceId == price.curPriceId }"
@click="price.onClickPrice(it)"
>
<img class="seat" :src="it.unSelectIcon" />
<span class="price"
>{{ it.price }}<span v-if="language == 0">¥</span></span
>
</div>
</div>
</div>
<div v-if="selectedSeats?.length" class="bottom">
<div class="seat_box">
<!-- v-for="(it, index) in selectedSeats" -->
<div v-for="(it, index) in selectedSeats" class="seat_item">
<img class="seat_icon" :src="it.selectIcon" />
<span class="num"
>{{ it.area }}{{ languageFormat(language, "区", "Zones") }}
{{ it.pai }}{{ languageFormat(language, "排", "Row") }} {{ it.no }}
{{ languageFormat(language, "座", "Seat") }}</span
>
<el-icon
style="cursor: pointer"
color="#ccc"
@click="deleteSiteConfigItem(it)"
><CircleCloseFilled
/></el-icon>
</div>
</div>
<div class="pay">
<div class="sum">¥{{ sumPrice?.toFixed(2) }}</div>
<div class="pay_btn" @click="toConfirmOrder()">
{{ languageFormat(language, "立即购买", "Continue") }}
</div>
</div>
</div>
<div class="iframeBox">
<iframe
ref="iframeRef"
class="iframe"
id="iframe"
src="https://seat-choose.parent4relax.com/#/seat-picker"
></iframe>
</div>
</div>
</template>
<style scoped lang="scss">
.container {
width: 1200px;
margin: 0 auto;
padding: 20px;
.top {
width: 100%;
background-color: #fff;
padding: 20px;
margin-bottom: 10px;
border-radius: 6px;
.time {
font-size: 18px;
font-weight: 600;
margin-bottom: 10px;
.place {
color: #7e8489;
margin-left: 15px;
}
}
.price_tab {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 10px;
.tabActive {
background: #eeeeee !important;
border: 2px solid #7e8489 !important;
}
.tab_item {
display: flex;
align-items: center;
padding: 10px 14px;
background: #f5f7f8;
border-radius: 30px;
border: 2px solid #dcdedf;
font-size: 16px;
color: #646666;
cursor: pointer;
user-select: none;
.seat {
width: 14px;
height: 14px;
margin-right: 5px;
}
}
}
}
.iframeBox {
border-radius: 6px;
background-color: #fff;
padding: 20px;
margin-bottom: 20px;
}
.iframe {
width: 100%;
height: 500px;
border: none;
background-color: #f7f8fa;
}
.bottom {
border-radius: 6px;
background-color: #fff;
padding: 20px;
margin-bottom: 20px;
.seat_box {
display: flex;
flex-wrap: wrap;
gap: 10px;
width: 100%;
.seat_item {
display: flex;
align-items: center;
padding: 10px 14px;
font-size: 16px;
color: #29343c;
background: #eeeeee;
border-radius: 30px;
border: 2px solid #7e8489;
user-select: none;
.seat_icon {
width: 14px;
height: 14px;
margin-right: 5px;
}
.num {
margin-right: 5px;
}
}
}
.pay {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 10px;
.sum {
font-weight: 600;
font-size: 22px;
color: #493ceb;
}
.pay_btn {
width: 200px;
height: 40px;
background: #493ceb;
border-radius: 20px;
margin-top: 10px;
font-size: 14px;
color: #fff;
line-height: 40px;
text-align: center;
cursor: pointer;
font-weight: 600;
user-select: none;
}
}
}
}
</style>
<script setup></script>
<template>
<div class="view">
<router-view />
</div>
</template>
<style scoped lang="scss">
.view {
min-width: 1024px;
max-width: 1920px;
margin: 0 auto;
}
</style>
<script setup>
import dayjs from "dayjs";
import useUserStore from "@/store/modules/user";
import { setToken, getToken } from "./utils/local-store.js";
import { md5 } from "md5js";
import { ElMessageBox, ElMessage } from "element-plus";
import {
loginFree,
activityDetail,
sessionDetail,
getSitePlaceInfo,
getPriceLevelInfo,
} from "./api/index.js";
import { languageFormat } from "./utils/language.js";
import { useStorage } from "@vueuse/core/index";
const language = useStorage("language", 0);
const route = useRoute();
const router = useRouter();
const userStore = useUserStore();
const props = defineProps({
activityId: [String, Number],
});
// 用户免登录
const login = async (userId) => {
const sign = md5(`uid=${userId}lgo1acfkw51jfo`, 32);
return loginFree({
userId: userId,
sign,
}).then((res) => {
setToken(res.data.token);
});
};
const select_form = reactive({
venueItem: {
id: 0,
dateStr: "",
dayOpen: 1,
nightOpen: 1,
type: 0,
}, // 所选场次
session: -1, // 日/夜场 0:日场 1:夜场
place: "", // 场馆
ticket_block: 0, // 票档
onClickVenue(e, index) {
if (e.state == 1) return; // 表示
select_form.venueItem = e;
if (
(e.dayOpen == 0 && select_form.session == 0) ||
(e.nightOpen == 0 && select_form.session == 1)
) {
select_form.session = -1;
select_form.place = "";
select_form.ticket_block = 0;
}
},
// 选择日/夜场
onClickSession(e) {
if (
(e == 0 && select_form.venueItem?.dayOpen == 1) ||
(e == 1 && select_form.venueItem?.nightOpen == 1)
) {
select_form.session = e;
// select_form.place = "";
select_form.ticket_block = 0;
}
},
// 选择场馆
onClickPlace(e) {
if (e.state == 1) return;
select_form.place = e.placeName;
select_form.ticket_block = 0;
},
// 选择票档
onClickPrice(e) {
if (e.state == 1) return;
select_form.ticket_block = e.priceId;
},
// 去选座
async toSelectSeat() {
// 检查登录
// const ticketUserToken = getToken();
// if (!ticketUserToken) {
const userId = userStore.user?.userId; // userId
if (!userId) {
// 未登录,打开登录弹窗
return userStore.setVisitor();
}
// }
await login(userId);
if (!select_form.venueItem?.id)
return ElMessage({
type: "warning",
message: languageFormat(
language.value,
"请选择时间",
"Please select the time"
),
});
if (select_form.session == -1)
return ElMessage({
type: "warning",
message: languageFormat(
language.value,
"请选择场次",
"Please select the session"
),
});
if (!select_form.place)
return ElMessage({
type: "warning",
message: languageFormat(
language.value,
"请选择场馆",
"Please choose the venue"
),
});
if (!select_form.ticket_block)
return ElMessage({
type: "warning",
message: languageFormat(
language.value,
"请选择票档",
"Please choose the ticket category"
),
});
router.push({
path: "/seat/seat_picker",
query: {
id: props.activityId,
openType: select_form.session,
sessionId: select_form.venueItem?.id,
sitePlace: select_form.place,
ticketType: select_form.venueItem?.type,
ticket_block: select_form.ticket_block,
time_txt: select_form.venueItem?.dateStr,
},
});
},
});
// 活动详情
const detail = reactive({
loading: false,
data: null,
fetchData() {
this.loading = true;
activityDetail({ actId: props.activityId })
.then((res) => {
this.data = res.data;
})
.finally(() => (this.loding = false));
},
});
// 获取场次信息
const timeVenue = reactive({
loading: false,
data: [],
fetchData() {
this.loading = true;
sessionDetail({ actId: props.activityId })
.then((res) => {
this.data = res.data;
})
.finally(() => (this.loading = false));
},
});
// 获取场馆
const sitePlaceInfo = reactive({
data: [
{ placeName: "B4", state: "0" },
{ placeName: "B6", state: "0" },
],
fetchData() {
console.log(select_form.venueItem?.id, select_form.session);
getSitePlaceInfo({
sessionId: select_form.venueItem?.id,
openType: select_form.session,
}).then((res) => {
this.data = res.data;
});
},
});
// 获取票档
const price = reactive({
data: [],
fetchData() {
getPriceLevelInfo({
actId: props.activityId,
sessionId: select_form.venueItem?.id,
openType: select_form.session,
sitePlace: select_form.place,
ticketType: select_form.venueItem?.type,
}).then((res) => {
this.data = res.data;
});
},
});
watchEffect(() => {
if (select_form.session != -1 && select_form.venueItem?.id) {
if (select_form.session == 1 && select_form.place == "B4") {
select_form.place = "";
}
sitePlaceInfo.fetchData();
}
});
watchEffect(() => {
if (
select_form.venueItem?.id &&
select_form.session != -1 &&
select_form.place
) {
price.fetchData();
}
});
// 主流程开始
watch(
() => props.activityId,
async (activityId) => {
if (!activityId) {
// [TODO] dialog提示缺少活動ID讓然後返回
ElMessageBox.confirm("缺少活动id", "提示", {
confirmButtonText: "确认",
type: "warning",
showCancelButton: false,
draggable: true,
}).then((res) => {
router.push("/");
});
return;
}
detail.fetchData();
timeVenue.fetchData();
},
{ immediate: true }
);
</script>
<template>
<div>
<!-- top -->
<div class="container top">
<img class="cover_img" :src="detail.data?.coverImg" />
<div class="info">
<div class="title">{{ detail.data?.name }}</div>
<div class="time">
{{ languageFormat(language, "时间", "Event Date & Time") }}{{
detail.data?.startTime
? dayjs(detail.data?.startTime).format("YYYY.MM.DD ddd")
: ""
}}
{{
detail.data?.endTime
? dayjs(detail.data?.endTime).format("YYYY.MM.DD ddd")
: ""
}}
</div>
<div class="address">
{{ languageFormat(language, "地址", "Location") }}{{
detail.data?.address
}}
</div>
<!-- 时间 -->
<div class="select_item_box">
<div class="label">
{{ languageFormat(language, "时间", "Event Date & Time") }}
</div>
<div class="select_item">
<div
v-for="(it, index) in timeVenue.data"
:key="index"
:class="[
it.id == select_form.venueItem?.id ? 'tagActive' : 'tag',
]"
@click="select_form.onClickVenue(it)"
>
{{ it.dateStr }}
<div v-if="it.type == 1" class="tag_t">{{ languageFormat(language, "套票", "Package ticket") }}</div>
</div>
</div>
</div>
<!-- 场次 -->
<div class="select_item_box">
<div class="label">{{ languageFormat(language, "场次", "Session") }}</div>
<div class="select_item">
<div
:class="[
select_form.venueItem?.dayOpen == 1
? select_form.session == 0
? 'tagActive'
: 'tag'
: 'tagDisabled',
]"
@click="select_form.onClickSession(0)"
>
{{ languageFormat(language, "日场", "Day session") }}
</div>
<div
:class="[
select_form.venueItem?.nightOpen == 1
? select_form.session == 1
? 'tagActive'
: 'tag'
: 'tagDisabled',
]"
@click="select_form.onClickSession(1)"
>
{{ languageFormat(language, "夜场", "Night session") }}
</div>
</div>
</div>
<!-- 场馆 -->
<div class="select_item_box">
<div class="label">
{{ languageFormat(language, "场馆", "Venue") }}
</div>
<div class="select_item">
<div
v-for="(it, index) in sitePlaceInfo.data"
:key="index"
:class="[
it.state == 0
? it.placeName == select_form.place
? 'tagActive'
: 'tag'
: 'tagDisabled',
]"
@click="select_form.onClickPlace(it)"
>
{{ it.placeName }}
</div>
</div>
</div>
<!-- 票档 -->
<div
v-if="price.data?.length && select_form.place"
class="select_item_box"
>
<div class="label">
{{ languageFormat(language, "票档", "Ticket Category") }}
</div>
<div class="select_item">
<div
v-for="(it, index) in price.data"
:key="index"
:class="[
it.state == 0
? it.priceId == select_form.ticket_block
? 'tagActive'
: 'tag'
: 'tagDisabled',
]"
@click="select_form.onClickPrice(it)"
>
{{ it.price }}
</div>
</div>
</div>
<!-- button -->
<div class="btn" @click="select_form.toSelectSeat()">
{{ languageFormat(language, "选座购票", "Seat selection") }}
</div>
</div>
</div>
<!-- bottom -->
<div class="container bottom">
<div class="title">
{{ languageFormat(language, "活动介绍", "Event Details") }}
</div>
<div class="rich_content" v-html="detail.data?.introduceInfo"></div>
<div class="title" style="margin-top: 30px">
{{ languageFormat(language, "购票须知", "Ticketing Information") }}
</div>
<div class="rich_content" v-html="detail.data?.buyNotice"></div>
</div>
</div>
</template>
<style scoped lang="scss">
.container {
width: 1200px;
margin: 0 auto;
background-color: #fff;
box-shadow: 0px 0px 46px 0px rgba(1, 16, 64, 0.08);
border-radius: 8px;
box-sizing: border-box;
font-family: SourceHanSansCN, SourceHanSansCN;
padding-bottom: 20px;
}
.top {
display: flex;
padding: 19px;
margin-top: 26px;
.cover_img {
width: 390px;
height: 517px;
object-fit: fill;
margin-right: 36px;
}
.info {
padding-top: 12px;
.title {
font-weight: bold;
font-size: 28px;
color: #000000;
line-height: 42px;
margin-bottom: 34px;
}
.time {
font-weight: 500;
font-size: 16px;
color: #4a4a4a;
line-height: 24px;
margin-bottom: 16px;
}
.address {
font-weight: 500;
font-size: 16px;
color: #4a4a4a;
line-height: 24px;
margin-bottom: 33px;
}
.select_item_box {
display: flex;
margin-bottom: 30px;
&:last-child {
margin-bottom: 0;
}
.label {
font-weight: 600;
font-size: 16px;
color: #000;
line-height: 24px;
margin-right: 12px;
flex-shrink: 0;
}
.select_item {
display: flex;
flex-wrap: wrap;
gap: 10px;
user-select: none;
.tag_t {
padding: 1px 15px;
font-weight: 400;
font-size: 14px;
color: #493ceb;
border-radius: 6px;
border: 1px solid #453dea;
margin-left: 5px;
}
.tag {
display: flex;
padding: 12px 18px;
background: #eeeeee;
border-radius: 4px;
border: 1px solid #29343c;
font-size: 14px;
color: #4a4a4a;
cursor: pointer;
}
.tagActive {
display: flex;
padding: 12px 18px;
background: #fff;
border-radius: 4px;
border: 1px solid #493ceb;
font-size: 14px;
color: #493ceb;
cursor: pointer;
}
.tagDisabled {
padding: 12px 18px;
background: #878787;
border-radius: 4px;
border: 1px solid #29343c;
font-size: 14px;
color: #4a4a4a;
cursor: no-drop;
}
}
}
.btn {
width: 175px;
height: 40px;
background: linear-gradient(270deg, #493ceb 0%, #8623fc 100%);
border-radius: 20px;
line-height: 40px;
text-align: center;
font-weight: 500;
font-size: 16px;
color: #ffffff;
cursor: pointer;
}
}
}
.bottom {
padding: 50px;
margin-top: 30px;
margin-bottom: 30px;
.title {
padding: 20px 30px;
background: linear-gradient(270deg, #493ceb 0%, #8623fc 100%);
font-weight: bold;
font-size: 20px;
color: #ffffff;
line-height: 30px;
margin-bottom: 30px;
}
.rich_content {
margin-top: 30px;
}
}
</style>
export const languageFormat = (language = 0, zh, en) => {
return language == 1 ? en : zh;
};
/** 用户登录token储存的key */
export const TOKEN_KEY = "SEAT_TOKEN";
/** 设置token */
export const setToken = (token) => localStorage.setItem(TOKEN_KEY, token);
/**
* 获取登录token
* @param drop 是否清空
*/
export const getToken = (drop = false) => {
let token = localStorage.getItem(TOKEN_KEY);
if (!token) return null;
if (drop) localStorage.removeItem(TOKEN_KEY);
return token;
};
// http.js
// import axios from "axios";
import axios from 'axios/dist/axios'
import { getToken } from "./local-store";
import { ElMessage } from "element-plus";
import { useStorage } from "@vueuse/core/index";
const language = useStorage("language", 0);
const baseURL = "https://radv4.gitliuyi.top/ticket"; //"http://book.xiaojinyu.games"; // 这里填入你的基础 API URL
const timeout = 15000; // 请求超时时间
const http = axios.create({
baseURL,
timeout,
headers: {
"Content-Type": "application/json",
},
});
// 请求拦截器
http.interceptors.request.use(
(config) => {
// 在发送请求之前做些什么
if (language.value == 1) config.headers.Language = "en-us";
const TOKEN = getToken();
if (TOKEN) config.headers.Authorization = TOKEN;
if (config.method == "get") config.params = config.data;
console.log("config", config);
return config;
},
(error) => {
return Promise.reject(error);
}
);
// 响应拦截器
http.interceptors.response.use(
(response) => {
// 判断是否有异常
let error = null; // 若无异常此值为null
if (response.status !== 200) {
error = Error(`Request failed with statuCode ${response.status}`);
}
if (response.data.code != 200) {
ElMessage({ type: "error", message: response.data.msg });
return Promise.reject(response.data);
}
return response.data;
},
(error) => {
// 对响应错误做点什么
return Promise.reject(error);
}
);
// 封装请求函数
const request = (method, url, data = null) => {
return http({
method,
url,
data,
});
};
export default request;
......@@ -65,25 +65,25 @@ export default defineConfig(({ mode, command }) => {
// https://cn.vitejs.dev/config/#server-proxy
'/dev-api/ztx-train': {
// target: 'http://123.60.96.243:1896/stage-api',
target: 'http://192.168.1.25:8686',
target: 'https://jijin.wtwuxicenter.com/stage-api',
changeOrigin: true,
rewrite: (p) => p.replace(/^\/dev-api\/ztx-train/, '')
},
'/dev-api/ztx-match': {
target: 'http://192.168.1.118:8083',
// target: 'http://192.168.1.132:8081',
// target: 'http://192.168.1.118:8083',
target: 'https://jijin.wtwuxicenter.com/stage-api',
changeOrigin: true,
rewrite: (p) => p.replace(/^\/dev-api\/ztx-match/, '')
},
'/dev-api/ztx-webSite': {
// target: 'https://dance.itechtop.cn/stage-api',
target: 'http://192.168.1.118:8081/',
target: 'https://jijin.wtwuxicenter.com/stage-api',
changeOrigin: true,
rewrite: (p) => p.replace(/^\/dev-api\/ztx-webSite/, '')
},
'/dev-api': {
target: 'http://192.168.1.131:8081/',
// target: 'https://dance.itechtop.cn/stage-api',
// target: 'http://192.168.1.118:8081/',
target: 'https://jijin.wtwuxicenter.com/stage-api',
// target: 'https://wdsfwuxicenter.com/stage-api',
changeOrigin: true,
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!