三期pk功能开发以及积分两个页
@@ -2,32 +2,32 @@
|
||||
ENV = 'development'
|
||||
# 'development'
|
||||
|
||||
#VITE_APP_BASE_API_Url = 'https://aits.jlbank.com.cn:7001'
|
||||
VITE_APP_BASE_API_Url = 'https://aitstest.jlbank.com.cn:7001'
|
||||
# VITE_APP_BASE_API_Url = ' http://25.18.122.66:9786'
|
||||
#sit
|
||||
# VITE_APP_BASE_API_Url = 'https://aits.jlbank.com.cn:7001'
|
||||
VITE_APP_BASE_API_Url = 'https://aitstest.jlbank.com.cn:7002'
|
||||
# VITE_APP_BASE_API_Url = 'http://192.168.247.200'
|
||||
# VITE_APP_BASE_API_Url = 'http://aitscdn.jlbank.com.cn:7001'
|
||||
# VITE_APP_BASE_API_Url = 'http://192.168.108.129'
|
||||
# dev
|
||||
#VITE_APP_BASE_API_Url = 'http://25.18.122.65:7001'
|
||||
# sit
|
||||
# VITE_APP_BASE_API_Url = 'http://25.18.122.91:9786'
|
||||
# UAT
|
||||
# VITE_APP_BASE_API_Url = 'http://25.18.122.78:9786'
|
||||
|
||||
# DEV
|
||||
|
||||
# app入口
|
||||
|
||||
# VITE_APP_BASE_API_Url = 'http://25.18.122.65:7001'
|
||||
|
||||
# VITE_APP_BASE_API_Url = 'http://25.16.122.91:9786'
|
||||
# VITE_APP_BASE_API_Url = 'http://25.18.122.66:9786'
|
||||
|
||||
# h5专用地址x2
|
||||
|
||||
|
||||
VITE_APP_BASE_H5_API_Url = 'http://25.18.122.65:7001'
|
||||
# VITE_APP_BASE_H5_API_Url = 'http://25.18.122.65:7001'
|
||||
# VITE_APP_BASE_H5_API_Url = 'http://25.18.122.91:9786'
|
||||
# VITE_APP_BASE_H5_API_Url = 'http://25.18.122.78:9786'
|
||||
|
||||
# VITE_APP_BASE_H5_API_Url_TRAAPP = 'http://25.64.32.154:9601'
|
||||
# VITE_APP_BASE_H5_API_Url_TRAAPP = 'http://192.168.247.200'
|
||||
# VITE_APP_BASE_H5_API_Url_TRASTUDY = 'http://25.64.32.154:9602'
|
||||
VITE_APP_BASE_H5_API_Url_TRAEXAM = 'http://25.64.32.154:9604'
|
||||
# VITE_APP_BASE_H5_API_Url_TRAEXAM = 'http://192.168.247.200'
|
||||
# VITE_APP_BASE_H5_API_Url_TRAASK = 'http://25.64.32.154:9605'
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
# 任东专用开发环境
|
||||
ENV = 'development.rd'
|
||||
# 'development.rd'
|
||||
|
||||
VITE_APP_BASE_API_Url = 'http://25.18.122.65:7001'
|
||||
|
||||
VITE_APP_BASE_H5_API_Url_TRAEXAM = 'http://25.64.32.154:9604'
|
||||
@@ -0,0 +1,9 @@
|
||||
# 田岩开发环境
|
||||
ENV = 'development.ty'
|
||||
# 'development.ty'
|
||||
|
||||
VITE_APP_BASE_API_Url = 'https://aitstest.jlbank.com.cn:7001'
|
||||
|
||||
VITE_APP_BASE_H5_API_Url_TRAEXAM = 'http://192.168.108.129'
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
# 杨航开发环境
|
||||
ENV = 'development.yh'
|
||||
# 'development.yh'
|
||||
|
||||
VITE_APP_BASE_API_Url = 'http://25.18.122.65:7001'
|
||||
|
||||
VITE_APP_BASE_H5_API_Url_TRAEXAM = 'http://25.64.32.154:9604'
|
||||
|
||||
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
"description": "",
|
||||
"scripts": {
|
||||
"dev:h5": "uni",
|
||||
"dev:rd": "uni -p h5 --mode development.rd",
|
||||
"dev:yh": "uni -p h5 --mode development.yh",
|
||||
"dev:ty": "uni -p h5 --mode development.ty",
|
||||
"dev:h5:sit": "uni -p h5 --mode sit",
|
||||
"dev:h5:uat": "uni -p h5 --mode uat",
|
||||
"dev:h5:production": "uni -p h5 --mode production",
|
||||
|
||||
@@ -9,23 +9,7 @@
|
||||
});
|
||||
},
|
||||
onShow: function () {
|
||||
// function getBrowserInfo() {
|
||||
// const userAgent = navigator.userAgent;
|
||||
// let browserName = '未知浏览器';
|
||||
// let version = '未知版本';
|
||||
|
||||
// // 检测 Chrome
|
||||
// if (userAgent.indexOf('Chrome') > -1 && userAgent.indexOf('Edg') === -1) {
|
||||
// browserName = 'Chrome';
|
||||
// version = userAgent.match(/Chrome\/(\d+\.\d+)/)[1];
|
||||
// }
|
||||
|
||||
// return {
|
||||
// browser: browserName,
|
||||
// version: version,
|
||||
// userAgent: userAgent
|
||||
// };
|
||||
// }
|
||||
},
|
||||
onHide: function () {
|
||||
}
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
import request from '@/api/request'
|
||||
|
||||
const module_url = '/traexam'
|
||||
|
||||
// 查询竞赛列表
|
||||
export const queryTraCompetitionInfoPaging = (data) => {
|
||||
return request({
|
||||
url: module_url + '/traCompetitionInfo/queryTraCompetitionInfoPaging',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
};
|
||||
|
||||
// 查询试卷
|
||||
export const queryTestPapers = (data) => {
|
||||
return request({
|
||||
url: module_url + '/traCompetitionInfo/queryTestPapers',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
};
|
||||
|
||||
// 查询PK人员+试题
|
||||
export const queryTraCompetitionInfoByPkUser = (data) => {
|
||||
return request({
|
||||
url: module_url + '/traCompetitionInfo/queryTraCompetitionInfoByPkUser',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
};
|
||||
|
||||
// 循环获取简答题结果
|
||||
export const queryCompetitionPracticeAnswerResult = (data) => {
|
||||
return request({
|
||||
url: module_url + '/traCompetitionInfo/queryCompetitionPracticeAnswerResult',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
};
|
||||
|
||||
// 答题结束
|
||||
export const competitionAnswerEnd = (data) => {
|
||||
return request({
|
||||
url: module_url + '/traCompetitionInfo/competitionAnswerEnd',
|
||||
method: 'post',
|
||||
data,
|
||||
suppressErrors: true // 屏蔽报错信息
|
||||
});
|
||||
};
|
||||
|
||||
// 竞赛答题
|
||||
export const competitionAnswer = (data) => {
|
||||
return request({
|
||||
url: module_url + '/traCompetitionInfo/competitionAnswer',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
};
|
||||
|
||||
// 查询答题结果
|
||||
export const queryCompetitionAnswerResult = (data) => {
|
||||
return request({
|
||||
url: module_url + '/traCompetitionInfo/queryCompetitionAnswerResult',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
};
|
||||
|
||||
// 竞赛排行榜
|
||||
export const queryTraCompetitionRankingList = (data) => {
|
||||
return request({
|
||||
url: module_url + '/traCompetitionInfo/queryTraCompetitionRankingList',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
};
|
||||
|
||||
// 全行的机构数据
|
||||
export const queryOrgTree = (data) => {
|
||||
return request({
|
||||
url: module_url + '/traCompetitionInfo/queryOrgTree',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,111 @@
|
||||
import request from '@/api/request'
|
||||
const base_url = '/traapp'
|
||||
|
||||
/**
|
||||
* 查询签到
|
||||
* userId 学员ID String
|
||||
* checkInToday 今日是否签到 String
|
||||
* days 连续签到天数 int
|
||||
*/
|
||||
export const queryCheckIn = (data) => {
|
||||
return request({
|
||||
url: base_url + '/traPointsInfo/queryCheckIn',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 点击签到
|
||||
*/
|
||||
export const addPointsByCheckIn = (data) => {
|
||||
return request({
|
||||
url: base_url + '/traPointsInfo/addPointsByCheckIn',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 每次完成任务获得弹窗奖励
|
||||
* 入参:
|
||||
taskId 必输项:true 类型:String
|
||||
type 必输项:true 类型:String
|
||||
出参:
|
||||
userId 学员ID String
|
||||
badgeName 徽章名称 String
|
||||
badgeImg 徽章图片 String
|
||||
num 次数 int
|
||||
name 描述 String
|
||||
pointsBadgeName 积分徽章名称 String
|
||||
pointsBadgeImg 徽章图片 String
|
||||
currentPoints 当前积分 int
|
||||
changePoints 本次获得积分 int
|
||||
*/
|
||||
export const addPointsByTask = (data) => {
|
||||
return request({
|
||||
url: base_url + '/traPointsInfo/addPointsByTask',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 查询积分明细
|
||||
* 出参:
|
||||
detailId 明细ID String
|
||||
userId 学员ID String
|
||||
mattr 积分来源事项 String
|
||||
mattrDesc 积分来源描述 String
|
||||
changeValue 积分变化值 String
|
||||
currentPoints 当前积分 int
|
||||
countPoints 累计积分 int
|
||||
ctTime 创建时间 String
|
||||
*/
|
||||
export const queryPointsDetail = (data) => {
|
||||
return request({
|
||||
url: base_url + '/traPointsInfo/queryPointsDetail',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 查询段位明细
|
||||
* 出参:
|
||||
rankId 段位ID String
|
||||
rankName 段位名称 String
|
||||
currentRankName 当前段位名称 String
|
||||
ossAddr 段位图片 String
|
||||
pointsStart 段位开始区间 int
|
||||
pointsEnd 段位结束区间 int
|
||||
countPoints 累计积分 int
|
||||
*/
|
||||
export const queryRankDetail = (data) => {
|
||||
return request({
|
||||
url: base_url + '/traPointsInfo/queryRankDetail',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 查询当前状态
|
||||
* 出参:
|
||||
userId 学员ID String
|
||||
orgId 机构ID String
|
||||
countPoints 累计积分 int
|
||||
currentPoints 当前积分 int
|
||||
currentRankName 当前段位 String
|
||||
badgeNum 徽章数 int
|
||||
*/
|
||||
export const queryCurrentStatus = (data) => {
|
||||
return request({
|
||||
url: base_url + '/traPointsInfo/queryCurrentStatus',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
};
|
||||
@@ -4,9 +4,27 @@ import {
|
||||
import common from '@/common/common.js'
|
||||
|
||||
const ENV = import.meta.env
|
||||
// function getBrowserInfo() {
|
||||
// const userAgent = navigator.userAgent;
|
||||
// let browserName = '未知浏览器';
|
||||
// let version = '未知版本';
|
||||
|
||||
// // 检测 Chrome
|
||||
// if (userAgent.indexOf('Chrome') > -1 && userAgent.indexOf('Edg') === -1) {
|
||||
// browserName = 'Chrome';
|
||||
// version = userAgent.match(/Chrome\/(\d+\.\d+)/)[1];
|
||||
// }
|
||||
|
||||
// return {
|
||||
// browser: browserName,
|
||||
// version: version,
|
||||
// userAgent: userAgent
|
||||
// };
|
||||
// }
|
||||
|
||||
|
||||
export const get_base_url = (url = '') => {
|
||||
if (ENV.MODE === 'development') { // 开发环境
|
||||
if (['development', 'development.rd', 'development.yh', 'development.ty'].includes(ENV.MODE)) { // 开发环境
|
||||
// #ifdef H5
|
||||
if (url) {
|
||||
let _str = (url.split('/')[0] || url.split('/')[1])?.toUpperCase()
|
||||
@@ -20,7 +38,7 @@ export const get_base_url = (url = '') => {
|
||||
return ENV.VITE_APP_BASE_API_Url
|
||||
// #endif
|
||||
} else { // 其他环境,包括生产环境,sit环境,uat环境
|
||||
|
||||
|
||||
return ENV.VITE_APP_BASE_API_Url
|
||||
// return ENV.VITE_APP_BASE_API_Url
|
||||
|
||||
|
||||
@@ -36,4 +36,22 @@ export const updateDfSysUserExtandInfoGender = (data) => {
|
||||
data
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// 设置匿名 是Y 否N
|
||||
export const updateTraUserAnony = (data) => {
|
||||
return request({
|
||||
url: '/traapp/traUserAnony/updateTraUserAnony',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
};
|
||||
|
||||
// 查询是否匿名 是Y 否N
|
||||
export const queryTraUserAnonyByUserId = (data) => {
|
||||
return request({
|
||||
url: '/traapp/traUserAnony/queryTraUserAnonyByUserId',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ export const optionSuccessIcon = (color : string) : string => {
|
||||
|
||||
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgXml)}`;
|
||||
};
|
||||
export const optionErrorIcon = (color: string='#F5212D') : string => {
|
||||
export const optionErrorIcon = (color : string = '#F5212D') : string => {
|
||||
const svgXml = `
|
||||
<svg t="1754619171929" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6505" width="64" height="64"><path d="M910.336 186.368l-72.704-72.704L512 439.808 186.368 113.664 113.664 186.368 439.808 512l-326.144 325.632 72.704 72.704L512 584.192l325.632 326.144 72.704-72.704L584.192 512l326.144-325.632z" fill="${color}" p-id="6506"></path></svg>
|
||||
`.trim();
|
||||
@@ -19,7 +19,7 @@ export const examinationSheetIcon = () : string => {
|
||||
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgXml)}`;
|
||||
};
|
||||
|
||||
export const markIcon = (color: string='#ABABAB') : string => {
|
||||
export const markIcon = (color : string = '#ABABAB') : string => {
|
||||
const svgXml = `
|
||||
<svg t="1754987745092" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="13983" width="64" height="64"><path d="M693.01933598 59.45166004c-24.99339629-24.99339629-65.5162717-24.99339629-90.50966799 0-24.99339629 24.99339629-24.99339629 65.5162717 0 90.50966799l22.627417 22.627417-181.19328425 181.19328425c-78.50370195-71.13564929-199.8637317-68.83684515-275.5976964 6.89711955l-33.94112549 33.94112549a8 8 0 0 0 0 11.3137085l208.59650045 208.59650045-175.36248174 175.36248174a8 8 0 0 0 0 11.3137085l56.5685425 56.56854249a8 8 0 0 0 11.3137085 0L410.88373029 682.41273427l208.59650045 208.59650045a8 8 0 0 0 11.3137085 0l33.9411255-33.9411255c76.21055466-76.21055466 78.05893179-198.62346641 5.54583848-277.07484246L851.41125497 398.86291501l22.627417 22.627417c24.99339629 24.99339629 65.5162717 24.99339629 90.50966799 0 24.99339629-24.99339629 24.99339629-65.5162717 0-90.50966799L693.01933598 59.45166004z" fill="${color}" p-id="13984"></path></svg>
|
||||
`.trim();
|
||||
@@ -34,7 +34,7 @@ export const feedbackIcon = () : string => {
|
||||
};
|
||||
|
||||
// 通过考试
|
||||
export const passTheExamIcon = (color: string) : string => {
|
||||
export const passTheExamIcon = (color : string) : string => {
|
||||
const svgXml = `
|
||||
<svg t="1755670289043" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6974" width="64" height="64"><path d="M97.878 483.853c0-117.062-0.108-160.999-0.108-278.062 0-101.472 56.328-108.082 110.483-108.082h441.933c85.128 0 111.453 28.968 111.453 110.481v55.241c0 43.562-55.419 38.57-55.419 0V208.19c0-40.918-13.309-55.24-56.035-55.24H208.252c-45.746 0-55.241 6.203-55.241 55.24v552.407c0 30.278 16.572 55.241 55.241 55.241 67.004 0 43.482 0.026 110.484 0 33.77 0 36.252 55.241 0 55.241s-63.711 0.44-131.306 0.17c-39.867-0.163-72.883-23.774-84.643-60.322-3.292-10.223-4.694-21.525-4.694-32.34-0.323-116.658-0.215-178.076-0.215-294.734" fill="${color}" p-id="6975"></path><path d="M649.644 926.291c-152.344-0.027-275.666-123.537-275.666-276.122 0-152.586 123.915-276.259 276.529-276.042 152.616 0.215 275.884 124.022 275.722 276.878-0.16 152.236-123.807 275.314-276.585 275.286m0.756-496.868c-121.109-0.271-220.641 98.828-220.91 220.045-0.27 121.541 98.345 220.934 219.561 221.287 121.704 0.324 221.505-98.208 221.775-219.047 0.324-122.594-98.236-221.99-220.426-222.285m-55.455-166.362c44.02 0.027 37.978 55.979 0 55.979h-331.45c-41.431 0-39.704-55.979 0-55.979 108.756-0.027 289.155-0.027 331.45 0zM318.736 428.782c44.021 0.028 37.979 55.98 0 55.98h-55.242c-41.431 0-39.704-55.98 0-55.98 108.757-0.027 12.948-0.027 55.242 0z" fill="${color}" p-id="6976"></path><path d="M785.502 547.22c-12.496-12.498-32.758-12.498-45.254 0L602.151 685.316l-42.191-42.191c-12.498-12.496-32.758-12.496-45.256 0-12.496 12.497-12.496 32.759 0 45.256l64.818 64.818c6.249 6.248 14.438 9.372 22.628 9.372s16.379-3.124 22.628-9.372a32.424 32.424 0 0 0 2.402-2.695 32.304 32.304 0 0 0 2.689-2.397l155.633-155.633c12.497-12.496 12.497-32.758 0-45.254z" fill="${color}" p-id="6977"></path></svg>
|
||||
`.trim();
|
||||
@@ -42,7 +42,7 @@ export const passTheExamIcon = (color: string) : string => {
|
||||
};
|
||||
|
||||
// 完成练习
|
||||
export const completeTheExercisesIcon = (color: string) : string => {
|
||||
export const completeTheExercisesIcon = (color : string) : string => {
|
||||
const svgXml = `
|
||||
<svg t="1755670357132" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7127" width="64" height="64"><path d="M832 704a42.666667 42.666667 0 0 0-42.666667 42.666667v106.666666H170.666667V170.666667h618.666666v226.133333a42.666667 42.666667 0 0 0 85.333334 0V166.4A83.2 83.2 0 0 0 789.333333 85.333333H170.666667a83.2 83.2 0 0 0-85.333334 81.066667v691.2A83.413333 83.413333 0 0 0 170.666667 938.666667h618.666666a83.413333 83.413333 0 0 0 85.333334-81.066667V746.666667a42.666667 42.666667 0 0 0-42.666667-42.666667z" fill="${color}" p-id="7128"></path><path d="M682.666667 341.333333a42.666667 42.666667 0 0 0-42.666667-42.666666H298.666667a42.666667 42.666667 0 0 0 0 85.333333h341.333333a42.666667 42.666667 0 0 0 42.666667-42.666667zM298.666667 512a42.666667 42.666667 0 0 0 0 85.333333h213.333333a42.666667 42.666667 0 0 0 0-85.333333zM921.386667 491.733333a42.666667 42.666667 0 0 0-60.373334 0L649.813333 704l-60.16-60.373333A42.666667 42.666667 0 0 0 529.28 704l90.453333 90.453333a42.666667 42.666667 0 0 0 60.373334 0l241.28-242.346666a42.666667 42.666667 0 0 0 0-60.373334z" fill="${color}" p-id="7129"></path></svg>
|
||||
`.trim();
|
||||
@@ -50,7 +50,7 @@ export const completeTheExercisesIcon = (color: string) : string => {
|
||||
};
|
||||
|
||||
// 锁定
|
||||
export const lockIcon = (color: string) : string => {
|
||||
export const lockIcon = (color : string) : string => {
|
||||
const svgXml = `
|
||||
<svg t="1755683025230" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6630" width="64" height="64"><path d="M787.136 395.466H373.113c0.036-0.579 0.173-1.128 0.173-1.716V267.63c0-81.153 72.891-147.174 162.483-147.174 86.561 0 162.488 64.414 162.488 137.851 0 15.446 12.523 27.969 27.969 27.969 15.446 0 27.969-12.523 27.969-27.969 0-105.043-100.027-193.789-218.426-193.789-120.439 0-218.422 91.118-218.422 203.112v126.12c0 0.588 0.137 1.138 0.173 1.716h-14.467c-82.25 0-149.168 66.918-149.168 149.168v284.402c0 71.971 58.551 130.522 130.522 130.522h502.728c71.971 0 130.522-58.551 130.522-130.522V525.988c0.001-71.971-58.55-130.522-130.521-130.522z m74.584 433.57c0 41.125-33.459 74.584-74.584 74.584H284.408c-41.125 0-74.584-33.459-74.584-74.584V544.634c0-51.409 41.822-93.23 93.23-93.23h484.082c41.125 0 74.584 33.459 74.584 74.584v303.048z" fill="${color}" p-id="6631"></path><path d="M613.108 649.541H458.436c-15.446 0-27.969 12.523-27.969 27.969 0 15.446 12.523 27.969 27.969 27.969h154.672c15.446 0 27.969-12.523 27.969-27.969 0-15.446-12.523-27.969-27.969-27.969z" fill="${color}" p-id="6632"></path></svg>
|
||||
`.trim();
|
||||
@@ -66,3 +66,53 @@ export const practiceExitIcon = () : string => {
|
||||
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgXml)}`;
|
||||
};
|
||||
|
||||
|
||||
// Pk页规则图标
|
||||
export const pkRules = () : string => {
|
||||
const svgXml = `
|
||||
<svg t="1760676829470" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7500" width="64" height="64"><path d="M512 69.963c248.05 0 445.217 197.167 445.217 445.217S760.05 960.398 512 960.398 66.783 763.23 66.783 515.18 263.95 69.963 512 69.963m0-63.603C232.15 6.36 3.18 235.33 3.18 515.18 3.18 795.031 232.15 1024 512 1024s508.82-228.969 508.82-508.82C1020.82 235.33 791.85 6.36 512 6.36z" fill="#ffffff" p-id="7501"></path><path d="M512 432.497c-38.161 0-63.602 25.44-63.602 57.242v273.49c0 31.802 25.44 57.243 63.602 57.243 38.161 0 63.602-25.44 63.602-57.242V489.74c0-31.802-25.44-57.243-63.602-57.243z m0-95.404c38.161 0 63.602-25.44 63.602-63.602 0-38.162-25.44-63.603-63.602-63.603-38.161 0-63.602 25.441-63.602 63.603 0 38.161 25.44 63.602 63.602 63.602z" fill="#ffffff" p-id="7502"></path></svg>
|
||||
`.trim();
|
||||
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgXml)}`;
|
||||
};
|
||||
|
||||
// Pk页排行榜图标
|
||||
export const pkRankingList = () : string => {
|
||||
const svgXml = `
|
||||
<svg t="1760676897154" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7659" width="64" height="64"><path d="M323.9 326.9H215.8c-14.9 0-27 12.1-27 27v459.2c0 14.9 12.1 27 27 27h108.1c14.9 0 27-12.1 27-27V353.9c0-14.9-12.1-27-27-27zM567 488.9H459c-14.9 0-27 12.1-27 27v297.2c0 14.9 12.1 27 27 27h108c14.9 0 27-12.1 27-27V515.9c0-14.9-12-27-27-27zM810.2 191.8H702.1c-14.9 0-27 12.1-27 27v594.3c0 14.9 12.1 27 27 27h108.1c14.9 0 27-12.1 27-27V218.8c0-14.9-12.1-27-27-27z" p-id="7660" fill="#ffffff"></path></svg>
|
||||
`.trim();
|
||||
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgXml)}`;
|
||||
};
|
||||
|
||||
// Pk页匿名关
|
||||
export const pkAnonymousClose = () : string => {
|
||||
const svgXml = `
|
||||
<svg t="1760677024029" class="icon" viewBox="0 0 1292 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8345" width="64" height="64"><path d="M1188.53945615 539.42278643a46.73094873 46.73094873 0 0 0 0-55.20152813C979.91575068 197.74436416 724.94179737 84.96193203 470.63406904 166.33659834a486.48725859 486.48725859 0 0 0-86.32376894 35.69064258L256.91849844 75.92030263a48.25374961 48.25374961 0 0 0-67.81222178 0 47.06406123 47.06406123 0 0 0 0 67.09840841L300.03279541 252.47001641c-17.22668379 12.37275615-34.31060508 24.7455123-51.15658887 39.02177021A1053.25466924 1053.25466924 0 0 0 71.1843919 484.2212583a46.68336123 46.68336123 0 0 0 0 55.20152813c163.55832011 224.61311338 356.90643018 343.58192315 558.67753212 343.58192402a542.49777422 542.49777422 0 0 0 245.64679893-60.91203076l127.10627666 125.63106328a47.68269873 47.68269873 0 0 0 67.81222177-67.09840928l-110.40305536-108.97542949a992.43781348 992.43781348 0 0 0 228.51529013-232.22711777z m-558.48718212 248.40687568c-161.79758174 0-320.21644922-95.17504834-460.07618204-276.00763974a952.03600576 952.03600576 0 0 1 140.66872119-147.99719971 675.74284102 675.74284102 0 0 1 58.58024239-42.8287711l87.46586894 86.60929307a197.8213377 197.8213377 0 0 0-30.31325332 104.21667774 202.86561533 202.86561533 0 0 0 203.67460284 201.77110195 200.20071357 200.20071357 0 0 0 105.5491286-30.45601495l68.00257179 67.57428428a440.51770987 440.51770987 0 0 1-173.55170039 37.11826846z m101.69453935-242.22049717l-135.67203106-134.19681767a100.74278847 100.74278847 0 0 1 33.97749171-6.18637852 105.35877862 105.35877862 0 0 1 101.55177685 140.38319619z m-67.76463427 67.0984084a114.210058 114.210058 0 0 1-33.97749258 5.71050351 107.119517 107.119517 0 0 1-107.690567-106.59605448 101.69453848 101.69453848 0 0 1 5.99602852-33.3112667z m226.61178925 89.9404207l-87.27551894-86.60929394a196.53647432 196.53647432 0 0 0 30.31325243-104.21667773 202.96079033 202.96079033 0 0 0-309.31890556-171.31508614L456.31022451 272.93265195c2.47455088-0.95175088 4.75875263-2.37937588 7.37606602-3.33112676 12.08723115-4.75875263 24.26963731-9.5175044 36.40445595-13.32450615 203.34149033-65.19490752 411.9176083 25.69726318 589.75218545 255.54500333a847.91450303 847.91450303 0 0 1-199.43931357 190.82597167z" fill="#ffffff" p-id="8346"></path></svg>
|
||||
`.trim();
|
||||
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgXml)}`;
|
||||
};
|
||||
|
||||
// Pk页匿名开
|
||||
export const pkAnonymousOpen = () : string => {
|
||||
const svgXml = `
|
||||
<svg t="1760676973291" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7945" width="64" height="64"><path d="M900.4 424.87c19.47 0 37.03-11.73 44.49-29.73 7.46-17.98 3.33-38.7-10.43-52.48L713.97 122.19c-7.3-7.3-19.12-7.3-26.42 0l-41.69 41.69c-7.3 7.3-7.3 19.13 0 26.42l138.28 138.27H86.32c-10.19 0-18.46 8.26-18.46 18.46v59.39c0 10.19 8.26 18.46 18.46 18.46H900.4zM937.65 598.72H123.8c-19.47 0-37.03 11.73-44.49 29.73-7.46 17.98-3.33 38.7 10.43 52.48l220.49 220.48c7.3 7.3 19.12 7.3 26.42 0l41.69-41.69c7.3-7.3 7.3-19.13 0-26.42L240.06 695.02h697.59c10.32 0 18.68-8.37 18.68-18.68v-58.93c0-10.32-8.36-18.69-18.68-18.69z" p-id="7946" fill="#ffffff"></path></svg>
|
||||
`.trim();
|
||||
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgXml)}`;
|
||||
};
|
||||
|
||||
|
||||
// 重置页图标
|
||||
export const resetIcon = () : string => {
|
||||
const svgXml = `
|
||||
<svg t="1760952234942" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7688" width="64" height="64"><path d="M931.07 384.75a368 368 0 0 0-704 95.25H64l192 192 192-192H288.91C312 333.51 439.12 221.13 592 221.13c169.21 0 306.87 137.66 306.87 306.87S761.21 834.87 592 834.87a307.37 307.37 0 0 1-194.56-69.55 30.57 30.57 0 0 0-38.79 47.25 368.1 368.1 0 0 0 572.42-427.82z" fill="#333333" p-id="7689"></path></svg>
|
||||
`.trim();
|
||||
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgXml)}`;
|
||||
};
|
||||
|
||||
|
||||
// pk页切换图标
|
||||
export const switchIcon = () : string => {
|
||||
const svgXml = `
|
||||
<svg t="1761037923256" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7561" width="32" height="32"><path d="M900.4 424.87c19.47 0 37.03-11.73 44.49-29.73 7.46-17.98 3.33-38.7-10.43-52.48L713.97 122.19c-7.3-7.3-19.12-7.3-26.42 0l-41.69 41.69c-7.3 7.3-7.3 19.13 0 26.42l138.28 138.27H86.32c-10.19 0-18.46 8.26-18.46 18.46v59.39c0 10.19 8.26 18.46 18.46 18.46H900.4zM937.65 598.72H123.8c-19.47 0-37.03 11.73-44.49 29.73-7.46 17.98-3.33 38.7 10.43 52.48l220.49 220.48c7.3 7.3 19.12 7.3 26.42 0l41.69-41.69c7.3-7.3 7.3-19.13 0-26.42L240.06 695.02h697.59c10.32 0 18.68-8.37 18.68-18.68v-58.93c0-10.32-8.36-18.69-18.68-18.69z" p-id="7562" fill="#e6e6e6"></path></svg>
|
||||
`.trim();
|
||||
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgXml)}`;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
<template>
|
||||
<image class="img_100" v-if="showLocalImage" :src="imagePath"></image>
|
||||
<image-preview v-else-if="showNetworkImage" class="img_100" :src="imageAddr"></image-preview>
|
||||
<image class="img_100" v-else :src="defaultAvatar"></image>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, watch, onMounted } from 'vue';
|
||||
import { defaultAvatar } from '@/enum.js';
|
||||
import { getUserInfo } from '@/common/common';
|
||||
|
||||
const imagePath = ref('');
|
||||
const imageAddr = ref('');
|
||||
|
||||
// 状态标识
|
||||
const showLocalImage = ref(false);
|
||||
const showNetworkImage = ref(false);
|
||||
|
||||
// 初始化用户信息
|
||||
const initUserInfo = () => {
|
||||
const info = getUserInfo();
|
||||
imagePath.value = info.imagePath || '';
|
||||
imageAddr.value = info.imageAddr || '';
|
||||
validateAvatarSources();
|
||||
};
|
||||
|
||||
// 验证头像来源
|
||||
const validateAvatarSources = () => {
|
||||
if (imagePath.value) {
|
||||
showLocalImage.value = true;
|
||||
showNetworkImage.value = false;
|
||||
} else if (imageAddr.value) {
|
||||
showLocalImage.value = false;
|
||||
showNetworkImage.value = true;
|
||||
} else {
|
||||
showLocalImage.value = false;
|
||||
showNetworkImage.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 强制刷新方法 - 重新获取用户信息并刷新头像
|
||||
const forceRefreshAvatar = () => {
|
||||
// 清空当前图片信息
|
||||
imagePath.value = '';
|
||||
imageAddr.value = '';
|
||||
// 重新获取用户信息
|
||||
initUserInfo();
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
initUserInfo();
|
||||
});
|
||||
|
||||
// 暴露方法给父组件
|
||||
defineExpose({
|
||||
forceRefreshAvatar
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
@@ -2,10 +2,11 @@
|
||||
<view class="item">
|
||||
<view class="top">
|
||||
<view class="type">{{ subject_type_text }}</view>
|
||||
<view class="score" v-if="['settlement', 'examination'].includes(props.mode)">{{ item.tgtGrade }}分</view>
|
||||
<view class="score" v-if="['settlement', 'examination', 'pk_in'].includes(props.mode)">{{ item.tgtGrade }}分</view>
|
||||
<view class="fl1"></view>
|
||||
<view class="right">
|
||||
<!-- 反馈中心 -->
|
||||
<slot name="title-right"></slot>
|
||||
<view class="mark_and_feedback_div" v-if="['examination', 'practice'].includes(props.mode)">
|
||||
<image
|
||||
v-if="props.mode === 'examination'"
|
||||
@@ -23,12 +24,10 @@
|
||||
<template v-if="['mistake'].includes(props.mode)">
|
||||
<view class="expand_button_div" @click="toggleExpand()">
|
||||
<!-- <view class="right_text">{{animationState?'收起':'展开'}}</view> -->
|
||||
|
||||
<view class="toggle-container">
|
||||
<view class="toggle-text" :class="{ active: !animationState }">展开</view>
|
||||
<view class="toggle-text" :class="{ active: animationState }">收起</view>
|
||||
</view>
|
||||
|
||||
<uv-icon
|
||||
class="click_text_icon"
|
||||
name="arrow-right"
|
||||
@@ -52,7 +51,7 @@
|
||||
:isPreview="props.isPreview"
|
||||
:activeVoiceId="subject_data.qnsId"
|
||||
@buutton_click="questionButtonClick"
|
||||
:button_complete_show="props.mode === 'practice'"
|
||||
:button_complete_show="['practice', 'pk_in'].includes(props.mode)"
|
||||
></questionVue>
|
||||
</template>
|
||||
<template v-else>
|
||||
@@ -67,7 +66,7 @@
|
||||
</view>
|
||||
<view
|
||||
class="option_div_button"
|
||||
v-if="qnsTyp === 'MU' && ['practice', 'study'].includes(props.mode) && !props.isPreview && clearResult"
|
||||
v-if="qnsTyp === 'MU' && ['practice', 'study', 'pk_in'].includes(props.mode) && !props.isPreview && clearResult"
|
||||
>
|
||||
<uv-button
|
||||
type="primary"
|
||||
@@ -85,7 +84,7 @@
|
||||
class="analysis_div"
|
||||
v-if="
|
||||
!clearResult &&
|
||||
['study', 'mistake', 'settlement', 'practice', 'practice_record'].includes(props.mode)
|
||||
['study', 'mistake', 'settlement', 'practice', 'practice_record', 'pk_in'].includes(props.mode)
|
||||
"
|
||||
>
|
||||
<view class="analysis_title" v-if="qnsTyp !== 'ES'">
|
||||
@@ -153,8 +152,8 @@
|
||||
// 错题本: mistake
|
||||
// 学习: study
|
||||
// 考试结算页 settlement
|
||||
// 练习记录页 practice_record
|
||||
return ['examination', 'practice', 'mistake', 'study', 'settlement', 'practice_record'].includes(value);
|
||||
// 练习记录页 practice_record, 'practice_record'
|
||||
return ['examination', 'practice', 'mistake', 'study', 'settlement', 'practice_record', 'pk_in'].includes(value);
|
||||
}
|
||||
},
|
||||
// 是否预览模式
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<view>
|
||||
<view style="line-height: 0;">
|
||||
<image :src="imgUrlShow" :mode="mode" @click="showDetail" style="width: 100%; height: 100%"></image>
|
||||
<uni-popup ref="PopupRef" class="popup" mask-background-color="rgba(0,0,0,.2)" background-color="rgba(0,0,0,.2)" @change="changeShow">
|
||||
<view class="overlay-box" @click="closePopup" @touchmove.stop>
|
||||
@@ -167,6 +167,7 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
.overlay-box {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
@@ -182,6 +183,7 @@
|
||||
width: 100vw;
|
||||
max-height: 100%;
|
||||
transform: translate(-50%, -50%);
|
||||
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,197 @@
|
||||
<template>
|
||||
<uni-popup ref="popupRef" class="popup">
|
||||
<view class="tree-selector-div">
|
||||
<view class="title">
|
||||
<view class="title-text">机构选择</view>
|
||||
<view class="back_div" @click="openDialog(false)">
|
||||
<image :src="optionErrorIcon('#000000')" class="img"></image>
|
||||
</view>
|
||||
<uv-tabs
|
||||
class="uvTabs"
|
||||
:list="selectedPaths"
|
||||
:lineWidth="40"
|
||||
lineColor="#0066FF"
|
||||
:activeStyle="{ color: '#0066FF', fontSize: '30rpx' }"
|
||||
keyName="orgName"
|
||||
:current="selectedPaths.length - 1"
|
||||
@click="tabsClick"
|
||||
></uv-tabs>
|
||||
</view>
|
||||
|
||||
<scroll-view
|
||||
ref="scrollRef"
|
||||
scroll-with-animation
|
||||
:scroll-into-view="scrollIntoId"
|
||||
class="tree-selector-scroll"
|
||||
scroll-x="true"
|
||||
:show-scrollbar="false"
|
||||
>
|
||||
<treeSelector :node="orgTree"></treeSelector>
|
||||
</scroll-view>
|
||||
<view class="button-div">
|
||||
<view class="button">
|
||||
<image class="img" :src="resetIcon()"></image>
|
||||
<view class="" @click="click_button('reset')">重置</view>
|
||||
</view>
|
||||
|
||||
<view class="button" @click="click_button('all')">全部</view>
|
||||
<view class="button" @click="click_button('confirm')">确定</view>
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, provide, nextTick } from 'vue';
|
||||
import common, { getUserInfo } from '@/common/common';
|
||||
import { resetIcon, optionErrorIcon } from '@/common/imgSvg';
|
||||
import treeSelector from './treeSelector';
|
||||
const popupRef = ref(null);
|
||||
// 滚动容器的 ref
|
||||
const scrollRef = ref(null);
|
||||
// 控制滚动位置的属性(scroll-top)
|
||||
const scrollIntoId = ref('');
|
||||
const openDialog = (status) => {
|
||||
if (status) {
|
||||
popupRef.value.open('bottom');
|
||||
} else {
|
||||
popupRef.value.close();
|
||||
}
|
||||
};
|
||||
const tabsClick = (item) => {
|
||||
if (item.index === selectedPaths.value.length - 1) {
|
||||
return;
|
||||
}
|
||||
updateSelectedPaths(
|
||||
{
|
||||
orgName: item.orgName,
|
||||
orgId: item.orgId,
|
||||
parentId: item.parentId
|
||||
},
|
||||
item.index
|
||||
);
|
||||
};
|
||||
const orgTreeInit = common.getValue('orgTree');
|
||||
// 初始选中的
|
||||
const initSelect = {
|
||||
orgName: orgTreeInit[0].orgName,
|
||||
orgId: orgTreeInit[0].orgId,
|
||||
parentId: orgTreeInit[0].parentId
|
||||
};
|
||||
const orgTree = ref(orgTreeInit);
|
||||
|
||||
// 把全行信息插入
|
||||
const selectedPaths = ref([initSelect]);
|
||||
|
||||
const updateSelectedPaths = (node, level) => {
|
||||
console.log('node', node);
|
||||
const newPaths = [...selectedPaths.value];
|
||||
newPaths.splice(level);
|
||||
newPaths.push(
|
||||
reactive({
|
||||
orgName: node['orgName'],
|
||||
orgId: node['orgId'],
|
||||
parentId: node['parentId']
|
||||
})
|
||||
);
|
||||
selectedPaths.value = newPaths;
|
||||
nextTick(() => {
|
||||
scrollIntoId.value = `item-${selectedPaths.value.length}`;
|
||||
});
|
||||
};
|
||||
const click_button = (type) => {
|
||||
if (type === 'reset') {
|
||||
updateSelectedPaths(initSelect, 0);
|
||||
} else if (type === 'confirm') {
|
||||
emit('submit', JSON.parse(JSON.stringify(selectedPaths.value)));
|
||||
} else if (type === 'all') {
|
||||
emit('submit', [{ orgName: '全部', orgId: 'A', parentId: '' }]);
|
||||
}
|
||||
};
|
||||
provide('treeContextKey', {
|
||||
selectedPaths,
|
||||
updateSelectedPaths
|
||||
});
|
||||
|
||||
const emit = defineEmits(['submit']);
|
||||
defineExpose({
|
||||
open: () => openDialog(true),
|
||||
close: () => openDialog(false)
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.tree-selector-div {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
background-color: #fff;
|
||||
border-radius: 16rpx;
|
||||
.title {
|
||||
font-weight: 600;
|
||||
font-size: 34rpx;
|
||||
color: #333333;
|
||||
text-align: center;
|
||||
padding: 40rpx 0 0 0;
|
||||
border-bottom: 4rpx solid #efefef;
|
||||
.back_div {
|
||||
width: 70rpx;
|
||||
height: 70rpx;
|
||||
position: absolute;
|
||||
top: 20rpx;
|
||||
right: 20rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.img {
|
||||
width: 30rpx;
|
||||
height: 30rpx;
|
||||
}
|
||||
}
|
||||
.uvTabs {
|
||||
margin-bottom: -6rpx;
|
||||
:deep(.uv-tabs__wrapper__nav__item) {
|
||||
padding: 0 44rpx 0 1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
.button-div {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
background: #ffffff;
|
||||
// box-shadow: 0px -6 15px 0px rgba(0,0,0,0.05);
|
||||
.button {
|
||||
flex: 1;
|
||||
border: none;
|
||||
display: flex;
|
||||
height: 124rpx;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-weight: 600;
|
||||
font-size: 30rpx;
|
||||
.img {
|
||||
width: 38rpx;
|
||||
height: 38rpx;
|
||||
}
|
||||
&:first-child {
|
||||
color: #333333;
|
||||
}
|
||||
&:last-child {
|
||||
color: #0066ff;
|
||||
}
|
||||
&:active {
|
||||
background: #eaeaea;
|
||||
// transform: scale(0.98); /* 按下时轻微缩小,增强反馈 */
|
||||
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.2); /* 内阴影模拟按下凹陷感 */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.tree-selector-scroll {
|
||||
white-space: nowrap;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
background: #f0f0f0;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,134 @@
|
||||
<template>
|
||||
<view class="tree-selector" :id="`item-${props.level}`">
|
||||
<view class="tree-child-selector" :class="{ fl1: props.level === 0}">
|
||||
<view class="level" v-for="item in props.node" @click="click_node(item)">
|
||||
<view class="node" :class="classList(item.orgId)">
|
||||
{{ item.orgName }}
|
||||
</view>
|
||||
<view class="fl1"></view>
|
||||
</view>
|
||||
</view>
|
||||
<treeSelector v-if="childNode && childNode.length" :node="childNode" :level="props.level + 1"></treeSelector>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { defineOptions, ref, inject, reactive } from 'vue';
|
||||
import { computed } from 'vue';
|
||||
const treeContextKey = 'treeContextKey';
|
||||
const { selectedPaths, updateSelectedPaths } = inject(treeContextKey);
|
||||
const props = defineProps({
|
||||
// 当前节点数据
|
||||
node: {
|
||||
type: Array, // 改为数组类型
|
||||
required: true,
|
||||
// 验证数组中的每个元素是否符合结构要求
|
||||
validator: (value) => {
|
||||
// 先判断是否为数组
|
||||
if (!Array.isArray(value)) return false;
|
||||
// 验证数组中的每个对象
|
||||
return value.every((item) => {
|
||||
// 每个元素必须是对象
|
||||
if (typeof item !== 'object' || item === null) return false;
|
||||
// 必须包含 orgId(字符串类型)
|
||||
if (typeof item.orgId !== 'string') return false;
|
||||
// 必须包含 orgName(字符串类型)
|
||||
if (typeof item.orgName !== 'string') return false;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
},
|
||||
level: {
|
||||
type: Number,
|
||||
default: 0
|
||||
}
|
||||
});
|
||||
// 把选择的层级树处理成id列表
|
||||
const selectedPathsOrgCodeList = computed(() => selectedPaths.value.map((res) => res.orgId));
|
||||
// 设置子列表的数据
|
||||
const childNode = computed(() => {
|
||||
const lastItem = selectedPaths.value.at(-1);
|
||||
const selectItem = props.node.find((res) => selectedPathsOrgCodeList.value.includes(res.orgId));
|
||||
if (selectItem) return selectItem['children'] || [];
|
||||
return [];
|
||||
});
|
||||
|
||||
// 判断需要的样式class
|
||||
const classList = (orgId) => {
|
||||
let a = [];
|
||||
if (selectedPathsOrgCodeList.value.includes(orgId) || props.level === selectedPathsOrgCodeList.value.length) {
|
||||
a.push('select-bg');
|
||||
}
|
||||
if (selectedPathsOrgCodeList.value.at(-1) === orgId) {
|
||||
a.push('select-text');
|
||||
}
|
||||
return a;
|
||||
};
|
||||
const emit = defineEmits(['update:selectedKeys']);
|
||||
|
||||
// 处理当前节点被点击
|
||||
const click_node = (node) => {
|
||||
updateSelectedPaths(node, props.level);
|
||||
};
|
||||
|
||||
defineOptions({
|
||||
name: 'treeSelector'
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.tree-selector {
|
||||
border-left: 1rpx solid #eaeaea;
|
||||
border-right: 1rpx solid #eaeaea;
|
||||
display: flex;
|
||||
min-height: 600rpx;
|
||||
max-height: 800rpx;
|
||||
display: flex;
|
||||
transition: all 0.3s ease 2s; /* 关键配置 */
|
||||
}
|
||||
|
||||
.tree-child-selector {
|
||||
|
||||
display: inline-block;
|
||||
// 每一级树形容器
|
||||
min-width: 6rem;
|
||||
overflow-y: scroll;
|
||||
scrollbar-width: none; /* Firefox 特有:直接隐藏滚动条 */
|
||||
-ms-overflow-style: none; /* IE 和 Edge 特有:隐藏滚动条 */
|
||||
&::-webkit-scrollbar {
|
||||
display: none; /* 隐藏滚动条 */
|
||||
}
|
||||
.level {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
|
||||
}
|
||||
|
||||
.node {
|
||||
padding: 0 1rem;
|
||||
background: #f7f7f7;
|
||||
font-weight: 700;
|
||||
font-size: 30rpx;
|
||||
color: #333333;
|
||||
text-align: left;
|
||||
height: 80rpx;
|
||||
line-height: 80rpx;
|
||||
|
||||
white-space: nowrap;
|
||||
/* 强制不换行 */
|
||||
overflow: hidden;
|
||||
/* 超出部分隐藏 */
|
||||
text-overflow: ellipsis;
|
||||
/* 超出部分显示省略号 */
|
||||
|
||||
&.select-bg {
|
||||
background: #fff;
|
||||
|
||||
}
|
||||
&.select-text {
|
||||
color: #0066ff;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -43,7 +43,8 @@ export default function useZpaging({
|
||||
}
|
||||
|
||||
// 搜索
|
||||
const search = (value, state) => {
|
||||
const search = (value, state=true) => {
|
||||
console.log('搜索', value, state);
|
||||
searchText.value = value;
|
||||
if (state) {
|
||||
reload()
|
||||
|
||||
@@ -13,7 +13,7 @@ export const GENDER = [{
|
||||
value: "f",
|
||||
label: "女性",
|
||||
}
|
||||
]
|
||||
]
|
||||
// 试题题型
|
||||
export const SUBJECT_TYPE = [{
|
||||
value: "SN",
|
||||
@@ -32,4 +32,19 @@ export const SUBJECT_TYPE = [{
|
||||
label: "问答题",
|
||||
}
|
||||
]
|
||||
export const defaultAvatar = '/static/images/me/default_user_avatar.png'
|
||||
export const defaultAvatar = '/static/images/me/default_user_avatar.png'
|
||||
export const defaultAnonymousAvatar = '/static/images/me/default_user_avatar.png'
|
||||
export const styleButton = {
|
||||
style_button_1: {
|
||||
color: '#FFFFFF',
|
||||
fontSize: '30rpx',
|
||||
backgroundColor: '#0066FF',
|
||||
borderRadius: '8rpx'
|
||||
},
|
||||
style_button_2: {
|
||||
color: '#0066FF',
|
||||
fontSize: '30rpx',
|
||||
backgroundColor: '#E2EDFF',
|
||||
borderRadius: '8rpx'
|
||||
}
|
||||
}
|
||||
@@ -48,11 +48,13 @@
|
||||
]
|
||||
},
|
||||
/* ios打包配置 */
|
||||
"ios" : {},
|
||||
"ios" : {
|
||||
"dSYMs" : false
|
||||
},
|
||||
/* SDK配置 */
|
||||
"sdkConfigs" : {},
|
||||
"splashscreen" : {
|
||||
"androidStyle" : "default",
|
||||
"androidStyle" : "common",
|
||||
"android" : {
|
||||
"hdpi" : "src/static/images/login/open.9.png",
|
||||
"xhdpi" : "src/static/images/login/open.9.png",
|
||||
|
||||
@@ -311,6 +311,70 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/competition/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "竞赛列表页",
|
||||
"app-plus": {
|
||||
"titleNView": false
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/competition/matching",
|
||||
"style": {
|
||||
"navigationBarTitleText": "匹配页面",
|
||||
"app-plus": {
|
||||
"titleNView": false
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/competition/pk",
|
||||
"style": {
|
||||
"navigationBarTitleText": "pk页面",
|
||||
"disableSwipeBack": true,
|
||||
"app-plus": {
|
||||
"titleNView": false
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/competition/result",
|
||||
"style": {
|
||||
"navigationBarTitleText": "pk结果页面",
|
||||
"app-plus": {
|
||||
"titleNView": false
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/competition/ranking",
|
||||
"style": {
|
||||
"navigationBarTitleText": "pk排行榜",
|
||||
"app-plus": {
|
||||
"titleNView": false
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/pointsAndRank/points",
|
||||
"style": {
|
||||
"navigationBarTitleText": "积分变动明细",
|
||||
"app-plus": {
|
||||
"titleNView": false
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/pointsAndRank/rank",
|
||||
"style": {
|
||||
"navigationBarTitleText": "段位列表",
|
||||
"app-plus": {
|
||||
"titleNView": false
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/course/index",
|
||||
"style": {
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
<template>
|
||||
<z-paging
|
||||
ref="pagingRef"
|
||||
v-model="data_list"
|
||||
@query="queryList"
|
||||
class="scroll_div"
|
||||
bg-color="#F1F5FA"
|
||||
empty-view-img="/static/images/competition/list_empty.png"
|
||||
empty-view-text="竞赛正在筹备中,敬请期待~"
|
||||
:empty-view-super-style="{ paddingTop: '10%' }"
|
||||
:empty-view-img-style="{ height: '520rpx', width: '494rpx', marginBottom: '40rpx' }"
|
||||
>
|
||||
<template #top>
|
||||
<view class="main_div">
|
||||
<view class="body-title">
|
||||
<view class="back_div" @click="common.navigateBack()">
|
||||
<view class="back-icon"></view>
|
||||
</view>
|
||||
<view>竞赛练习</view>
|
||||
</view>
|
||||
<view class="input-view">
|
||||
<search-input placeholder="请输入竞赛名" @search="search"></search-input>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<view class="scroll-Y">
|
||||
<view class="item" v-for="(item, index) in data_list" @click="goto_competition(item)">
|
||||
<view class="cover">
|
||||
<image-preview class="img" :src="item.ossAddr" mode="aspectFill"></image-preview>
|
||||
</view>
|
||||
<view class="title ellipsis-text">
|
||||
{{ item.comName }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</z-paging>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
// 竞赛列表
|
||||
import { ref, reactive, watch, onMounted } from 'vue';
|
||||
import { onLoad, onUnload } from '@dcloudio/uni-app';
|
||||
import useZpaging from '@/composables/useZpaging.js';
|
||||
import common from '@/common/common';
|
||||
import { queryTraUserAnonyByUserId } from '@/api/user.js';
|
||||
import { queryTraCompetitionInfoPaging, queryTestPapers, queryOrgTree } from '@/api/competition.js';
|
||||
|
||||
const { pagingRef, queryList, data_list, search } = useZpaging({
|
||||
searchKey: 'comName',
|
||||
fetchFunction: queryTraCompetitionInfoPaging
|
||||
});
|
||||
const goto_competition = (item) => {
|
||||
common.loading();
|
||||
const result = Promise.all([queryTestPapers({ comId: item.comId }), queryTraUserAnonyByUserId(), queryOrgTree()]);
|
||||
result
|
||||
.then((res) => {
|
||||
const papersId = res[0].body;
|
||||
const comId = item.comId;
|
||||
common.setPageCache('competition_list', {
|
||||
papersId: papersId, // 试卷id
|
||||
isAnony: res[1].body.isAnony, // 是否匿名 Y是N否
|
||||
ruleDesc: item.ruleDesc, // 规则说明
|
||||
comName: item.comName, // 标题
|
||||
comId: comId
|
||||
});
|
||||
common.setValue('orgTree', res[2].body ?? []);
|
||||
common.hideLoading();
|
||||
common.navigateTo(`/pages/competition/matching?papersId=${papersId}&comId=${comId}`);
|
||||
})
|
||||
.catch(() => {
|
||||
common.msg('网络繁忙,请稍后再试!');
|
||||
});
|
||||
};
|
||||
onLoad(() => {});
|
||||
onUnload(() => {});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.item {
|
||||
margin: 28rpx;
|
||||
padding: 22rpx;
|
||||
border-radius: 16rpx;
|
||||
overflow: hidden;
|
||||
background-color: #fff;
|
||||
.cover {
|
||||
overflow: hidden;
|
||||
border-radius: 16rpx;
|
||||
width: calc(100vw - 100rpx);
|
||||
padding-top: calc(9 / 16 * 100%);
|
||||
position: relative;
|
||||
.img {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
font-weight: 700;
|
||||
font-size: 30rpx;
|
||||
color: #333333;
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.scroll-Y {
|
||||
overflow: hidden;
|
||||
background-color: #f1f5fa;
|
||||
}
|
||||
|
||||
.main_div {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding-top: var(--status-bar-height);
|
||||
overflow: hidden;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.body-title {
|
||||
width: 100%;
|
||||
height: 70rpx;
|
||||
font-size: 33rpx;
|
||||
padding-top: 10rpx;
|
||||
font-weight: 500;
|
||||
color: #000;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
|
||||
.delete_div {
|
||||
position: absolute;
|
||||
right: 20rpx;
|
||||
top: 17rpx;
|
||||
width: 50rpx;
|
||||
height: 50rpx;
|
||||
|
||||
.img {
|
||||
width: 34rpx;
|
||||
height: 34rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.back_div {
|
||||
position: absolute;
|
||||
left: 26rpx;
|
||||
height: 34rpx;
|
||||
top: 17rpx;
|
||||
|
||||
.back-icon {
|
||||
position: relative;
|
||||
width: 50rpx;
|
||||
height: 50rpx;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.back-icon::before,
|
||||
.back-icon::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.back-icon::after {
|
||||
top: 25%;
|
||||
left: 25%;
|
||||
width: 40%;
|
||||
height: 40%;
|
||||
border-top: 4rpx solid #2b2c2e;
|
||||
border-left: 4rpx solid #2b2c2e;
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.input-view {
|
||||
width: 90%;
|
||||
margin: 20rpx auto;
|
||||
height: 78rpx;
|
||||
position: relative;
|
||||
|
||||
.search_div {
|
||||
position: absolute;
|
||||
top: 0%;
|
||||
right: 0;
|
||||
height: 100%;
|
||||
width: 70rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* 生成随机匹配时间
|
||||
* 特点:同一时间段生成的时间会比较接近,时间范围可配置
|
||||
*/
|
||||
export const MatchTimeGenerator = (() => {
|
||||
// 可配置的时间范围(毫秒)
|
||||
const MIN_TIME = 2000; // 最小时间
|
||||
const MAX_TIME = 6000; // 最大时间
|
||||
|
||||
// 时间窗口:100秒内生成的时间会基于同一基准(可根据需要调整)
|
||||
const TIME_WINDOW = 100000;
|
||||
// 同一窗口内的最大偏差(±1.5秒,可根据需要调整)
|
||||
const MAX_DEVIATION = 1500;
|
||||
|
||||
// 记录上一次生成的基准时间和时间戳
|
||||
let lastBaseTime = 0;
|
||||
let lastTimestamp = 0;
|
||||
|
||||
return {
|
||||
/**
|
||||
* 生成匹配时间(毫秒)
|
||||
* @returns {number} 介于MIN_TIME和MAX_TIME之间的随机数(毫秒)
|
||||
*/
|
||||
generate() : number {
|
||||
const now = Date.now();
|
||||
let baseTime : number;
|
||||
|
||||
// 如果超过时间窗口或首次生成,重新计算基准时间
|
||||
if (now - lastTimestamp > TIME_WINDOW || lastBaseTime === 0) {
|
||||
// 生成MIN_TIME到MAX_TIME之间的基准时间(毫秒)
|
||||
const timeRange = MAX_TIME - MIN_TIME;
|
||||
baseTime = MIN_TIME + Math.floor(Math.random() * timeRange);
|
||||
lastBaseTime = baseTime;
|
||||
lastTimestamp = now;
|
||||
} else {
|
||||
// 在同一时间窗口内,基于上次基准时间生成偏差
|
||||
baseTime = lastBaseTime;
|
||||
}
|
||||
|
||||
// 生成偏差值(-MAX_DEVIATION 到 MAX_DEVIATION)
|
||||
const deviation = Math.floor(Math.random() * (MAX_DEVIATION * 2 + 1)) - MAX_DEVIATION;
|
||||
let matchTime = baseTime + deviation;
|
||||
|
||||
// 确保结果在配置的范围内
|
||||
matchTime = Math.max(MIN_TIME, Math.min(MAX_TIME, matchTime));
|
||||
|
||||
return matchTime;
|
||||
},
|
||||
|
||||
/**
|
||||
* 生成匹配时间(秒)
|
||||
* @returns {number} 介于MIN_TIME/1000和MAX_TIME/1000之间的随机数(秒,保留一位小数)
|
||||
*/
|
||||
generateInSeconds() : number {
|
||||
return Math.round(this.generate() / 100) / 10;
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
export const formatTime = (seconds : number) => {
|
||||
const m = Math.floor(seconds / 60);
|
||||
const s = seconds % 60;
|
||||
return [m.toString().padStart(2, '0'), s.toString().padStart(2, '0')].join(':');
|
||||
};
|
||||
@@ -0,0 +1,69 @@
|
||||
import AvatarW1 from '@/static/images/competition/avatar/f_1.jpg'
|
||||
import AvatarW2 from '@/static/images/competition/avatar/f_2.jpg'
|
||||
import AvatarW3 from '@/static/images/competition/avatar/f_3.jpg'
|
||||
import AvatarW4 from '@/static/images/competition/avatar/f_4.jpg'
|
||||
import AvatarM1 from '@/static/images/competition/avatar/m_1.jpg'
|
||||
import AvatarM2 from '@/static/images/competition/avatar/m_2.jpg'
|
||||
import AvatarM3 from '@/static/images/competition/avatar/m_3.jpg'
|
||||
import AvatarM4 from '@/static/images/competition/avatar/m_4.jpg'
|
||||
import AvatarS1 from '@/static/images/competition/avatar/s_1.jpg'
|
||||
import AvatarS2 from '@/static/images/competition/avatar/s_2.jpg'
|
||||
import AvatarS3 from '@/static/images/competition/avatar/s_3.jpg'
|
||||
import AvatarS4 from '@/static/images/competition/avatar/s_4.jpg'
|
||||
|
||||
// 定义头像类型
|
||||
type AvatarType = 'f' | 'm' | 's';
|
||||
|
||||
// 按类型分组
|
||||
const avatarsByType = {
|
||||
f: [AvatarW1, AvatarW2, AvatarW3, AvatarW4],
|
||||
m: [AvatarM1, AvatarM2, AvatarM3, AvatarM4],
|
||||
s: [AvatarS1, AvatarS2, AvatarS3, AvatarS4]
|
||||
};
|
||||
|
||||
/**
|
||||
* 随机获取头像
|
||||
* @param type1 第一个头像类型(可选)
|
||||
* @param type2 第二个头像类型(可选,传入则返回2个头像)
|
||||
* @returns 单个头像路径(当只传type1或都不传时)或两个头像路径的数组(当传入type2时)
|
||||
*/
|
||||
export default function getRandomAvatars(
|
||||
type1 ?: AvatarType,
|
||||
type2 ?: AvatarType
|
||||
) {
|
||||
// 随机获取指定类型的头像
|
||||
const getRandomAvatar = (type ?: AvatarType) => {
|
||||
// 如果指定了类型且有效,则从该类型中选择
|
||||
if (type && avatarsByType[type]) {
|
||||
const avatars = avatarsByType[type];
|
||||
return avatars[Math.floor(Math.random() * avatars.length)];
|
||||
}
|
||||
|
||||
// 否则从所有头像中随机选择
|
||||
const allAvatars = [
|
||||
...avatarsByType.f,
|
||||
...avatarsByType.m,
|
||||
...avatarsByType.s
|
||||
];
|
||||
return allAvatars[Math.floor(Math.random() * allAvatars.length)];
|
||||
};
|
||||
|
||||
// 只传type1或都不传时,返回1个头像
|
||||
if (type2 === undefined) {
|
||||
return getRandomAvatar(type1);
|
||||
}
|
||||
|
||||
// 传入type2时,返回2个头像
|
||||
const avatar1 = getRandomAvatar(type1);
|
||||
let avatar2;
|
||||
|
||||
// 当两个类型相同时,确保头像不重复
|
||||
if (type1 && type1 === type2) {
|
||||
const sameTypeAvatars = avatarsByType[type1].filter(avatar => avatar !== avatar1);
|
||||
avatar2 = sameTypeAvatars[Math.floor(Math.random() * sameTypeAvatars.length)];
|
||||
} else {
|
||||
avatar2 = getRandomAvatar(type2);
|
||||
}
|
||||
|
||||
return [avatar1, avatar2];
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
export function formatSecondsToMS(seconds) {
|
||||
|
||||
// 尝试将输入转换为数字(处理字符串类型的数字)
|
||||
const num = Number(seconds);
|
||||
|
||||
// 处理无效输入(转换失败、非数字、负数)
|
||||
if (isNaN(num) || num < 0) {
|
||||
return '0-秒';
|
||||
}
|
||||
|
||||
// 计算分钟(不进位,直接取整)
|
||||
const minutes = Math.floor(num / 60);
|
||||
// 计算剩余秒数(取整)
|
||||
const remainingSeconds = Math.floor(num % 60);
|
||||
if (minutes === 0) {
|
||||
return `${remainingSeconds}秒`;
|
||||
}
|
||||
// 拼接结果
|
||||
return `${minutes}分${remainingSeconds}秒`;
|
||||
}
|
||||
@@ -0,0 +1,337 @@
|
||||
<template>
|
||||
<view class="main_div max_page">
|
||||
<template v-if="!isMatchingSuccess">
|
||||
<!-- 顶部一些按钮 -->
|
||||
<view class="top-button-div">
|
||||
<view class="back_div" @click="common.navigateBack()">
|
||||
<view class="back-icon"></view>
|
||||
</view>
|
||||
<view class="fl1"></view>
|
||||
<view class="top-icon-div" @click="click_top_icon(1)">
|
||||
<image class="img1" :src="data_info.isAnony === 'N' ? pkAnonymousClose() : pkAnonymousOpen()"></image>
|
||||
<view class="text">{{ data_info.isAnony === 'N' ? '不匿名' : '匿名' }}</view>
|
||||
</view>
|
||||
<view class="top-icon-div" @click="click_top_icon(2)">
|
||||
<image class="img2" :src="pkRules()"></image>
|
||||
<view class="text">规则说明</view>
|
||||
</view>
|
||||
<view class="top-icon-div" @click="click_top_icon(3)">
|
||||
<image class="img3" :src="pkRankingList()"></image>
|
||||
<view class="text">排行榜</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="title-div" :class="{ hidden: challengeLoading }">
|
||||
{{ data_info.comName }}
|
||||
</view>
|
||||
<view class="match-msg-div" :class="{ hidden: !challengeLoading }">匹配中...</view>
|
||||
<view class="avatar-div">
|
||||
<view class="avatar-surround-div">
|
||||
<view class="avatar-img-div" :class="{ hidden: challengeLoading }">
|
||||
<cached-avatar v-show="data_info.isAnony === 'N'" class="img"></cached-avatar>
|
||||
<image v-show="data_info.isAnony === 'Y'" class="img" :src="defaultAnonymousAvatar"></image>
|
||||
</view>
|
||||
</view>
|
||||
<view class="avatar-name-div">{{ data_info.isAnony === 'N' ? data_info.userName : '匿名' }}</view>
|
||||
</view>
|
||||
<view class="select-div" :class="{ hidden: challengeLoading }" @click="selectionInstitutionsRef.open(true)">
|
||||
<view class="select-institution-div">
|
||||
{{ data_info.orgName }}
|
||||
<image class="img" :src="switchIcon()"></image>
|
||||
</view>
|
||||
<view class="select-institution-msg-div">*选择机构后,会根据机构进行人员随机匹配挑战</view>
|
||||
</view>
|
||||
<view class="fl1"></view>
|
||||
<!-- 匹配时间 -->
|
||||
<view class="match-time-div" :class="{ hidden: !challengeLoading }">
|
||||
{{ formatTime(practiceTime) }}
|
||||
</view>
|
||||
<view class="button-div" v-show="challengeButtonStatus">
|
||||
<view
|
||||
:class="{ start_button: !challengeLoading, cancel_button: challengeLoading, 'button-transition': true }"
|
||||
@click="start_challenge"
|
||||
>
|
||||
{{ challengeLoading ? '取消匹配' : '开始挑战' }}
|
||||
</view>
|
||||
</view>
|
||||
<view class="fl1"></view>
|
||||
<view class="fl1"></view>
|
||||
<view class="fl1"></view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view class="matching-success-msg">匹配成功</view>
|
||||
<view class="matching-success-animation">
|
||||
<view class="left animate-left">
|
||||
<image class="img" src="@/static/images/competition/matching-success-left.png" mode="widthFix"></image>
|
||||
<view class="information-div-left">
|
||||
<view class="avatar-img-div">
|
||||
<cached-avatar v-show="data_info.isAnony === 'N'" class="img"></cached-avatar>
|
||||
<image v-show="data_info.isAnony === 'Y'" class="img" :src="defaultAnonymousAvatar"></image>
|
||||
</view>
|
||||
<view class="name">
|
||||
{{ data_info.isAnony === 'N' ? data_info.userName : '匿名' }}
|
||||
</view>
|
||||
<view class="org">
|
||||
{{ data_info.isAnony === 'N' ? data_info.orgIdName : '机构不显示' }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="right animate-right">
|
||||
<image class="img" src="@/static/images/competition/matching-success-right.png" mode="widthFix"></image>
|
||||
<view class="information-div-right">
|
||||
<view class="avatar-img-div">
|
||||
<image-preview
|
||||
v-if="data_info.pkIsAnony === 'N'"
|
||||
class="img"
|
||||
:src="data_info.pkimgAddr"
|
||||
></image-preview>
|
||||
<image v-else class="img" :src="defaultAnonymousAvatar" mode="aspectFill"></image>
|
||||
</view>
|
||||
<view class="name">
|
||||
{{ data_info.pkIsAnony === 'N' ? data_info.pkUserName : '匿名' }}
|
||||
</view>
|
||||
<view class="org">
|
||||
{{ data_info.pkIsAnony === 'N' ? data_info.pkOrgIdName : '机构不显示' }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="matching-success-text">准备!</view>
|
||||
</template>
|
||||
<uni-popup ref="popupRef" class="popup">
|
||||
<view class="sheet_popup_div">
|
||||
<view class="title_div">双人对战规则说明</view>
|
||||
<view class="note_div">
|
||||
{{ data_info.ruleDesc }}
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
<selectionInstitutions ref="selectionInstitutionsRef" @submit="selectionInstitutionsSubmit"></selectionInstitutions>
|
||||
<uv-picker ref="anonyPickerRef" :columns="[anonyOptions]" keyName="label" @confirm="anonyConfirm"></uv-picker>
|
||||
</view>
|
||||
|
||||
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {ref, onMounted, reactive} from 'vue';
|
||||
import common, {getUserInfo} from '@/common/common';
|
||||
import {MatchTimeGenerator, formatTime} from './js/matching';
|
||||
import {queryTraCompetitionInfoByPkUser} from '@/api/competition';
|
||||
import {onLoad} from '@dcloudio/uni-app';
|
||||
import {defaultAnonymousAvatar} from '@/enum';
|
||||
import {pkAnonymousClose, pkAnonymousOpen, pkRankingList, pkRules, switchIcon} from '@/common/imgSvg';
|
||||
import {queryTraUserAnonyByUserId, updateTraUserAnony} from '@/api/user';
|
||||
import selectionInstitutions from '@/components/selection-institutions/index.vue';
|
||||
|
||||
const data_info = reactive({
|
||||
userId: '',
|
||||
userName: '',
|
||||
orgName: '全部', // 机构名称
|
||||
orgId: 'A', // 机构的ID,全行是A
|
||||
papersId: '', // 试卷id
|
||||
isAnony: '', // 是否匿名 Y是N否
|
||||
ruleDesc: '', // 规则说明
|
||||
comName: '', // 标题
|
||||
comId: '',
|
||||
orgIdName: '',
|
||||
pkIsAnony: '',
|
||||
pkimgAddr: '',
|
||||
pkUserName: '',
|
||||
pkOrgIdName: ''
|
||||
});
|
||||
|
||||
const popupRef = ref(null);
|
||||
const anonyPickerRef = ref(null);
|
||||
const selectionInstitutionsRef = ref(null);
|
||||
const challengeLoading = ref(false);
|
||||
const isMatchingSuccess = ref(false); // 匹配成功状态
|
||||
const challengeButtonStatus = ref(true); // 匹配按钮显示
|
||||
const practiceTime = ref(0); // 匹配时间
|
||||
let practiceTimeTimer: number | null = null; // 匹配时间计时器
|
||||
let matchTimer: number | null = null; // 匹配成功定时器
|
||||
const anonyOptions = [
|
||||
{
|
||||
value: 'Y',
|
||||
label: '匿名'
|
||||
},
|
||||
{
|
||||
value: 'N',
|
||||
label: '不匿名'
|
||||
}
|
||||
];
|
||||
// 开始挑战
|
||||
const start_challenge = () => {
|
||||
if (!challengeLoading.value) {
|
||||
challengeLoading.value = true;
|
||||
// 清除旧计时器
|
||||
if (practiceTimeTimer) {
|
||||
clearInterval(practiceTimeTimer);
|
||||
}
|
||||
// 开始计时
|
||||
const practiceStartTime = new Date().getTime();
|
||||
practiceTimeTimer = setInterval(() => {
|
||||
const currentTime = Date.now();
|
||||
practiceTime.value = Math.floor((currentTime - practiceStartTime) / 1000);
|
||||
}, 1000);
|
||||
|
||||
// 生成匹配延迟时间
|
||||
// const delayTime = 0;
|
||||
const delayTime = MatchTimeGenerator.generateInSeconds();
|
||||
|
||||
// 匹配定时器
|
||||
matchTimer = setTimeout(async () => {
|
||||
try {
|
||||
challengeButtonStatus.value = false;
|
||||
const orgId = data_info.orgId
|
||||
const papersId = data_info.papersId
|
||||
const comId = data_info.comId
|
||||
const pkDataBody = await queryTraCompetitionInfoByPkUser({
|
||||
// orgId:510121,
|
||||
// papersId:'COMPETITION_PAPERS0250640321542025101615442400000003107',
|
||||
// comId:'TRA_COMPETITION_INFO0250640321542025101615442400000003099'
|
||||
orgId, papersId, comId
|
||||
});
|
||||
const pkData = pkDataBody.body;
|
||||
// 下面两行是给后端擦屁股,后端传回的数值为空
|
||||
pkData.orgId = orgId
|
||||
pkData.papersId = papersId
|
||||
common.setPageCache('competition_pk', pkData);
|
||||
// 1. 显示匹配成功状态
|
||||
isMatchingSuccess.value = true;
|
||||
uni.vibrateLong({
|
||||
success: function () {
|
||||
}
|
||||
});
|
||||
// 2. 执行匹配成功动画(等待1.5秒)
|
||||
await new Promise((resolve) => setTimeout(resolve, 600));
|
||||
// 3. 清除计时器
|
||||
if (practiceTimeTimer) {
|
||||
clearInterval(practiceTimeTimer);
|
||||
practiceTimeTimer = null;
|
||||
}
|
||||
// 5. 跳转页面
|
||||
common.navigateTo('/pages/competition/pk');
|
||||
challengeLoading.value = true;
|
||||
} catch (error) {
|
||||
common.msg('队列繁忙,请稍后再试!');
|
||||
// 出错处理
|
||||
} finally {
|
||||
resetChallengeState();
|
||||
}
|
||||
}, delayTime * 1000);
|
||||
} else {
|
||||
// 取消挑战
|
||||
resetChallengeState();
|
||||
}
|
||||
};
|
||||
|
||||
interface InstitutionItem {
|
||||
orgName: string; // 机构名称,类型为字符串
|
||||
orgId: string; // 机构ID,类型为字符串
|
||||
parentId: string; // 父级ID,类型为字符串
|
||||
children?: InstitutionItem[];
|
||||
}
|
||||
|
||||
const selectionInstitutionsSubmit = (options: [InstitutionItem, ...InstitutionItem[]]) => {
|
||||
// 缓存起来
|
||||
common.setValue('cache_selection_institutions' + data_info.userId, options);
|
||||
const lastItem = options.at(-1);
|
||||
data_info.orgName = lastItem.orgName;
|
||||
data_info.orgId = lastItem.orgId;
|
||||
|
||||
selectionInstitutionsRef.value.close();
|
||||
};
|
||||
const anonyConfirm = (e) => {
|
||||
const originalIsAnony = data_info.isAnony;
|
||||
const isAnony = e.value[0].value;
|
||||
if (isAnony === data_info.isAnony) return;
|
||||
data_info.isAnony = isAnony;
|
||||
common.loading('修改中');
|
||||
updateTraUserAnony({isAnony})
|
||||
.then(() => {
|
||||
setTimeout(() => common.msg('切换成功'), 400);
|
||||
})
|
||||
.catch(() => {
|
||||
// 4. 请求失败:用初始值回滚
|
||||
data_info.isAnony = originalIsAnony;
|
||||
common.msg('切换失败,请重试'); // 可选:提示失败
|
||||
})
|
||||
.finally(() => {
|
||||
common.hideLoading();
|
||||
});
|
||||
};
|
||||
const click_top_icon = (type: number) => {
|
||||
// 匿名切换
|
||||
if (type === 1) {
|
||||
anonyPickerRef.value.setIndexs([data_info.isAnony === 'Y' ? 0 : 1], true);
|
||||
anonyPickerRef.value.open();
|
||||
} else if (type === 2) {
|
||||
// 打开规则说明
|
||||
popupRef.value.open('bottom');
|
||||
} else if (type === 3) {
|
||||
// 去排行榜
|
||||
common.navigateTo(`/pages/competition/ranking?papersId=${data_info.papersId}&orgId=${data_info.orgId}`)
|
||||
}
|
||||
};
|
||||
// 统一重置状态的函数
|
||||
const resetChallengeState = () => {
|
||||
if (matchTimer) {
|
||||
clearTimeout(matchTimer);
|
||||
matchTimer = null;
|
||||
}
|
||||
if (practiceTimeTimer) {
|
||||
clearInterval(practiceTimeTimer);
|
||||
practiceTimeTimer = null;
|
||||
}
|
||||
challengeButtonStatus.value = true;
|
||||
challengeLoading.value = false;
|
||||
isMatchingSuccess.value = false;
|
||||
practiceTime.value = 0;
|
||||
};
|
||||
|
||||
onLoad((e) => {
|
||||
const lastData = common.getPageCache('competition_list');
|
||||
console.log('lastData', lastData);
|
||||
const userInfo = getUserInfo();
|
||||
Object.assign(data_info, {
|
||||
...lastData,
|
||||
userId: userInfo.userId,
|
||||
userName: userInfo.userName,
|
||||
gender: userInfo.gender,
|
||||
papersId: e.papersId,
|
||||
comId: e.comId
|
||||
});
|
||||
const selectOptions = common.getValue('cache_selection_institutions' + data_info.userId);
|
||||
if (Array.isArray(selectOptions) && selectOptions.length > 0) {
|
||||
const lastItem = selectOptions.at(-1);
|
||||
data_info.orgName = lastItem.orgName;
|
||||
data_info.orgId = lastItem.orgId;
|
||||
// const orgTreeInit = common.getValue('orgTree');
|
||||
// if (Array.isArray(orgTreeInit) && orgTreeInit.length > 0) {
|
||||
// console.log('selectOptions', selectOptions);
|
||||
// }
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
// 匹配成功样式动画
|
||||
@import './style/matching-success.scss';
|
||||
@import './style/matching-loading.scss';
|
||||
@import './style/matching-prelude.scss';
|
||||
|
||||
/* 容器样式 */
|
||||
.max_page {
|
||||
width: 100%;
|
||||
min-height: 100vh;
|
||||
background-image: url('@/static/images/competition/bg.png');
|
||||
background-color: #000; /* 图片高度不足时的背景色 */
|
||||
background-size: 100% auto; /* 宽度填满,高度自适应 */
|
||||
background-position: center top; /* 图片顶部居中显示 */
|
||||
background-repeat: no-repeat; /* 不重复平铺 */
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,803 @@
|
||||
<template>
|
||||
<view class="main_div max_page">
|
||||
<nav-bar :is_seat="true"></nav-bar>
|
||||
<view class="nav-div">
|
||||
<view class="title ellipsis-text">PK中</view>
|
||||
<view class="back_div" @click="exit_practice">
|
||||
<view class="back-icon"></view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 对决信息框 -->
|
||||
<view class="duel-msg-div">
|
||||
<view class="personnel-div">
|
||||
<view class="avatar-div">
|
||||
<cached-avatar v-if="pkData.isAnony === 'N'" class="img"></cached-avatar>
|
||||
<image v-else class="img" :src="defaultAnonymousAvatar" mode="aspectFill"></image>
|
||||
</view>
|
||||
<view class="name-div ellipsis-text">{{ pkData.isAnony === 'N' ? pkData.userName : '匿名' }}</view>
|
||||
</view>
|
||||
<view class="fraction-div left">
|
||||
<view class="fraction-title">分数</view>
|
||||
<view class="fraction-value">{{ ourScore }}</view>
|
||||
</view>
|
||||
<view class="fraction-div right">
|
||||
<view class="fraction-title">分数</view>
|
||||
<view class="fraction-value">{{ opponentScore }}</view>
|
||||
</view>
|
||||
<view class="personnel-div">
|
||||
<view class="avatar-div">
|
||||
<image-preview v-if="pkData.pkIsAnony === 'N'" class="img" :src="pkData.pkImgAddr"></image-preview>
|
||||
<image v-else class="img" :src="defaultAnonymousAvatar" mode="aspectFill"></image>
|
||||
</view>
|
||||
<view class="name-div">{{ pkData.pkIsAnony === 'N' ? pkData.pkUserName : '匿名' }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="body-area-div">
|
||||
<view class="countdown-and-question-number-div">
|
||||
<view class="top">
|
||||
<view class="countdown">
|
||||
<text class="bold">{{ questionNumber + 1 }}</text>
|
||||
<text class="grey">/{{ topicList.length }}</text>
|
||||
</view>
|
||||
<view class="question">
|
||||
<view class="countdown_time">
|
||||
{{ formatSeconds(practiceRemainingTime) }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="progress">
|
||||
<uv-line-progress
|
||||
:percentage="progress"
|
||||
:showText="false"
|
||||
activeColor="#0066FF"
|
||||
inactiveColor="#D9DEE8"
|
||||
:height="8"
|
||||
></uv-line-progress>
|
||||
</view>
|
||||
</view>
|
||||
<view class="scroll_div">
|
||||
<swiper
|
||||
class="swiper"
|
||||
:indicator-dots="false"
|
||||
:current="questionNumber"
|
||||
:disable-touch="true"
|
||||
easing-function="linear"
|
||||
>
|
||||
<swiper-item v-for="(item, index) in topicList">
|
||||
<view class="content">
|
||||
<view class="expose_shadow"></view>
|
||||
<scroll-view :scroll-y="true" class="scroll-Y" :show-scrollbar="false" :refresher-threshold="0">
|
||||
<Subject
|
||||
:item="item"
|
||||
:mode="mode"
|
||||
:isPreview="item.isPreview"
|
||||
:clearResult="item.clearResult"
|
||||
@subject_click="subject_click"
|
||||
v-model="item.my_answer"
|
||||
>
|
||||
<template #title-right>
|
||||
<text class="success-sun-div">
|
||||
已答对
|
||||
<text class="number">{{ correctQuestions.length }}</text>
|
||||
题
|
||||
</text>
|
||||
</template>
|
||||
</Subject>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
</view>
|
||||
<view class="fixed-box font_pf" :style="{ marginBottom: popup_input_bottom }">
|
||||
<view class="touch-btn-div" :class="{ show: showTouchBtn }">
|
||||
<TouchBtn
|
||||
ref="touchBtnRef"
|
||||
class="talk-btns"
|
||||
@submit="touchBtnSubmit"
|
||||
disabledText="只能进行一条回答"
|
||||
:isDisabled="touchIsDisabled"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 反馈组件 -->
|
||||
<Feedback ref="feedbackRef"></Feedback>
|
||||
<!-- 结尾弹出层 -->
|
||||
<Dialog ref="dialogRef" @button_click="result_click"></Dialog>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, computed, onMounted, nextTick, onUnmounted } from 'vue';
|
||||
import { onLoad, onHide, onShow, onUnload, onBackPress, onReady } from '@dcloudio/uni-app';
|
||||
import { defaultAnonymousAvatar, styleButton } from '@/enum';
|
||||
import Feedback from '@/pages/examination/components/feedback.vue';
|
||||
import Dialog from '@/pages/examination/components/dialog.vue';
|
||||
import Subject from '@/components/examination/subject.vue';
|
||||
import CharactersSubject from '@/components/examination/characters-subject.vue';
|
||||
import TouchBtn from '@/components/examination/touchBtn.vue';
|
||||
import common from '@/common/common';
|
||||
import { setPageCache, formatSeconds, getPageCache, setupKeyboardHeightListener } from '@/common/common';
|
||||
import { commonUploadVoiceFile } from '@/api/common.js';
|
||||
import { optionErrorIcon, examinationSheetIcon, practiceExitIcon } from '@/common/imgSvg';
|
||||
import { practiceCommit, queryCrsPracticeAnswerResult } from '@/api/practice.js';
|
||||
import { competitionAnswer, queryCompetitionPracticeAnswerResult, competitionAnswerEnd } from '@/api/competition.js';
|
||||
import { startExamByCrs } from '@/api/examination.js';
|
||||
import { startPracticeByCrs } from '@/api/practice.js';
|
||||
|
||||
const feedbackRef = ref(null);
|
||||
const dialogRef = ref(null);
|
||||
const touchBtnRef = ref(null);
|
||||
const countDownRef = ref(null);
|
||||
const practiceTime = ref(0); // 当前Pk时长
|
||||
const practiceRemainingTime = ref(0); // 当前Pk剩余时长
|
||||
let practiceStartTime = 0; // Pk开始时间
|
||||
let practiceTimeTimer = null; // Pk计时器
|
||||
let leaveStartTime = 0; // 离开开始时间
|
||||
const mode = ref('pk_in'); // PK中 pk_in
|
||||
|
||||
// 计算对方分数
|
||||
const opponentScore = computed(() => {
|
||||
|
||||
// 筛选出所有 asrTm <= 当前时长的项
|
||||
const validItems = pkData.traCompetitionPkTimeRecordVos.filter((item) => item.asrTm <= practiceTime.value);
|
||||
if (validItems.length > 0) {
|
||||
return validItems[validItems.length - 1].singleGrade;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
const pkData = reactive({
|
||||
comLimit: 0,
|
||||
crsId: '',
|
||||
name: '', // 名称
|
||||
orgId: '',
|
||||
papersId: '',
|
||||
pkImgAddr: '',
|
||||
traCompetitionPkTimeRecordVos:[]
|
||||
}); // 试卷信息
|
||||
const topicList = reactive([]); // 问题列表
|
||||
const popup_input_bottom = ref('0px');
|
||||
const questionNumber = ref(0); // 题号
|
||||
// 答对的题目数组
|
||||
const correctQuestions = computed(() => topicList.filter((res) => res.judgeResult === 'P'));
|
||||
// 我方分数
|
||||
const ourScore = computed(() => correctQuestions.value.reduce((sum, item) => sum + item.tgtGrade, 0));
|
||||
|
||||
const topic = computed({
|
||||
get: () => topicList[questionNumber.value],
|
||||
set: (val) => (topicList[questionNumber.value] = val)
|
||||
});
|
||||
|
||||
const showTouchBtn = computed(() => {
|
||||
return topic.value?.qnsTyp === 'ES' && !topic.value?.my_answer.anserResult;
|
||||
});
|
||||
|
||||
// 下面语音组件的禁用状态判断
|
||||
const touchIsDisabled = computed(() => {
|
||||
return topic.value?.es_status !== '' && topic.value?.es_status !== undefined;
|
||||
});
|
||||
|
||||
const progress = computed(() => {
|
||||
// 计算进度百分比(保留两位小数)
|
||||
const total = topicList.length;
|
||||
if (total === 0) return 0;
|
||||
const completed = questionNumber.value + 1;
|
||||
return Math.min(Math.round((completed / total) * 10000) / 100, 100);
|
||||
});
|
||||
|
||||
const subject_click = (type, params) => {
|
||||
if (type === 'answer') {
|
||||
//多选点击按钮答题
|
||||
if (params.qnsTyp === 'MU') {
|
||||
submitProblem({
|
||||
anserResult: params.answer.join(',')
|
||||
});
|
||||
}
|
||||
} else if (type === 'choose') {
|
||||
//单选判断点击选项答题
|
||||
if (['JD', 'SN'].includes(params.qnsTyp)) {
|
||||
submitProblem({ anserResult: params.answer.join(',') });
|
||||
}
|
||||
} else if (type === 'complete') {
|
||||
// 问答题点击完成
|
||||
submitProblem(params.answer);
|
||||
} else if (type === 'again') {
|
||||
// 问答题点击重答
|
||||
topic.value.my_answer = {};
|
||||
topic.value.isPreview = false;
|
||||
topic.value.es_status = ''; // 取消转圈
|
||||
}
|
||||
};
|
||||
|
||||
// 单题回答
|
||||
const submitProblem = (answer) => {
|
||||
common.loading('答题中');
|
||||
// execId 执行ID 必输项:true 类型:String
|
||||
// papersId 竞赛试卷ID 必输项:true 类型:String
|
||||
// comId 竞赛ID 必输项:true 类型:String
|
||||
// qnsId 试题ID 必输项:true 类型:String
|
||||
// ossKey 对象存储 必输项:false 类型:String
|
||||
// ossAddr 对象存储 必输项:false 类型:String
|
||||
// showOrder 顺序号 必输项:false 类型:int
|
||||
// anserResult 作答结果 必输项:false 类型:String
|
||||
// asrStartTm 答题开始时间 必输项:false 类型:String
|
||||
|
||||
competitionAnswer({
|
||||
execId: pkData.execId,
|
||||
papersId: pkData.papersId,
|
||||
comId: pkData.comId,
|
||||
qnsId: topic.value.qnsId,
|
||||
ossKey: '',
|
||||
showOrder: questionNumber.value + 1,
|
||||
limit: practiceTime.value, // 当前答题的秒
|
||||
...answer
|
||||
})
|
||||
.then(async (res) => {
|
||||
let traQnsInfoVo;
|
||||
// 是问答题
|
||||
if (topic.value.qnsTyp === 'ES') {
|
||||
try {
|
||||
const result = await queryWithRetry(res.body.execLogId);
|
||||
traQnsInfoVo = result.body.traQnsInfoVo;
|
||||
} catch (e) {
|
||||
common.msg('当前服务器繁忙,请重新作答');
|
||||
common.hideLoading();
|
||||
topic.value.isPreview = false;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
traQnsInfoVo = res.body.traQnsInfoVo;
|
||||
}
|
||||
topic.value.isPreview = true; // 不能在点击了,打开预览模式
|
||||
console.log('给出来的traQnsInfoVo', traQnsInfoVo);
|
||||
common.hideLoading();
|
||||
topic.value.clearResult = false; // 不清除正确答案
|
||||
topic.value.analyContent = traQnsInfoVo.analyContent; // 答案解析
|
||||
// 更新选项正确项目
|
||||
topic.value.itemVos = traQnsInfoVo.itemVos; // 答案选项(todo应该不这样替换)
|
||||
topic.value.anserResult = traQnsInfoVo.anserResult; // 正确答案字符串分割
|
||||
topic.value.judgeResult = traQnsInfoVo.judgeResult; // 正确答案字符串分割
|
||||
|
||||
if (questionNumber.value >= topicList.length - 1) {
|
||||
console.log('pk页答完了,带走的数据', pkData);
|
||||
common.setPageCache('competition_pk_to_resulf', pkData);
|
||||
nextTick(() => {
|
||||
common.redirectTo(
|
||||
`/pages/competition/result?&execId=${pkData.execId}&orgId=${pkData.orgId}&papersId=${pkData.papersId}`
|
||||
);
|
||||
});
|
||||
} else {
|
||||
nextTick(() => {
|
||||
setTimeout(() => {
|
||||
questionNumber.value++;
|
||||
}, 400);
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
// 单选和判断需要清除已点击的按钮
|
||||
if (['JD', 'SN'].includes(topic.value.qnsTyp)) {
|
||||
topic.value.my_answer = [];
|
||||
}
|
||||
common.hideLoading();
|
||||
});
|
||||
};
|
||||
|
||||
// 问答题轮询结果方法
|
||||
const queryWithRetry = (execLogId, maxRetries = 20) => {
|
||||
// 递归终止条件:达到最大重试次数
|
||||
console.log('递归终止条件:达到最大重试次数', maxRetries);
|
||||
if (maxRetries <= 0) {
|
||||
console.log('超过最大重试次数,查询失败');
|
||||
const error = new Error('超过最大重试次数,查询失败');
|
||||
error.isMaxRetry = true; // 标记为"超过最大重试次数"错误
|
||||
return Promise.reject(error);
|
||||
}
|
||||
return queryCompetitionPracticeAnswerResult({ execLogId })
|
||||
.then((res) => {
|
||||
console.log('queryCompetitionPracticeAnswerResult', maxRetries, res.body);
|
||||
const isWait = res.body.isWait;
|
||||
if (isWait === 'Y') {
|
||||
// 如果是Y,延迟2秒后重试,重试次数减1
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve(queryWithRetry(execLogId, maxRetries - 1));
|
||||
}, 2000);
|
||||
});
|
||||
} else {
|
||||
// 不是Y,直接返回结果
|
||||
return res;
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log('error', error);
|
||||
// 对接口调用错误进行重试
|
||||
if (error.isMaxRetry) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve(queryWithRetry(execLogId, maxRetries - 1));
|
||||
}, 2000);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// 录音组件提交
|
||||
const touchBtnSubmit = (type, submitObj) => {
|
||||
const topic = topicList[questionNumber.value];
|
||||
touchBtnRef.value?.clearinputText(); // 清除发送框数据
|
||||
if (type === 'voice') {
|
||||
if (topic.es_status === '00') return;
|
||||
topic.es_status = '00'; // 00转圈
|
||||
const voicePath = submitObj;
|
||||
commonUploadVoiceFile(voicePath, '/traask/traAskchat/voiceTrans', {})
|
||||
.then((_res) => {
|
||||
const _content = _res.body.transContent.trim();
|
||||
if (_content === '') {
|
||||
topic.es_status = ''; // 取消转圈
|
||||
return common.msg('未识别到文字');
|
||||
} else {
|
||||
topic.es_status = '02';
|
||||
topic.my_answer = {
|
||||
anserResult: _res.body.transContent,
|
||||
ossKey: _res.body.fileId,
|
||||
ossAddr: _res.body.ossFileAddr,
|
||||
voicePath: voicePath
|
||||
};
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
topic.es_status = ''; // 取消转圈
|
||||
if (error === 'Other') {
|
||||
common.msg('系统异常,请联系管理员');
|
||||
}
|
||||
});
|
||||
} else if (type === 'text') {
|
||||
topic.es_status = '01';
|
||||
topic.my_answer = {
|
||||
anserResult: submitObj // 正确答案文字内容
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const examStat = ref('');
|
||||
|
||||
const result_click = async ({ key }) => {
|
||||
if (key === 'exit') {
|
||||
// 中途退出
|
||||
dialogRef.value.close();
|
||||
try {
|
||||
// 考试结束
|
||||
await competitionAnswerEnd({ execId: pkData.execId, comGrade: ourScore.value });
|
||||
} catch (e) {}
|
||||
common.navigateBack();
|
||||
} else if (key === 'revert') {
|
||||
// 返回
|
||||
dialogRef.value.close();
|
||||
}
|
||||
};
|
||||
|
||||
// 弹出框配置
|
||||
const dialogConfiguration = reactive({});
|
||||
|
||||
// 中途退出
|
||||
const exit_practice = () => {
|
||||
dialogRef.value.open({
|
||||
title: '提示',
|
||||
msg: '中途退出视为结束竞赛,确定要退出吗?',
|
||||
buttonList: [
|
||||
{
|
||||
key: 'exit',
|
||||
name: '确定退出',
|
||||
style: styleButton.style_button_2
|
||||
},
|
||||
{
|
||||
key: 'revert',
|
||||
name: '继续竞赛',
|
||||
style: styleButton.style_button_1
|
||||
}
|
||||
]
|
||||
});
|
||||
};
|
||||
// 启动练习时长定时器
|
||||
const startTimer = () => {
|
||||
if (practiceTimeTimer) {
|
||||
clearInterval(practiceTimeTimer);
|
||||
}
|
||||
practiceTimeTimer = setInterval(() => {
|
||||
const currentTime = Date.now();
|
||||
const elapsedSeconds = Math.floor((currentTime - practiceStartTime) / 1000);
|
||||
practiceTime.value = elapsedSeconds;
|
||||
practiceRemainingTime.value = pkData.comLimit - practiceTime.value;
|
||||
// console.log('倒计时时间', practiceRemainingTime.value);
|
||||
// Pk时间到
|
||||
if (practiceRemainingTime.value <= 0) {
|
||||
}
|
||||
}, 1000);
|
||||
};
|
||||
// 初始化时检查
|
||||
onLoad((e) => {
|
||||
const pkDataParams = getPageCache('competition_pk');
|
||||
if (!pkData) {
|
||||
common.navigateBack();
|
||||
return;
|
||||
}
|
||||
Object.assign(pkData, pkDataParams);
|
||||
console.log('pkData', pkData);
|
||||
pkDataParams.qnsInfoVos.forEach((res) => {
|
||||
topicList.push({
|
||||
...res,
|
||||
isPreview: false,
|
||||
clearResult: true,
|
||||
es_status: '', // 预设一下问答题的状态,'' 空为没有 00 转圈 01 播放,其他暂定
|
||||
my_answer: []
|
||||
});
|
||||
});
|
||||
// 记录练习起始时间
|
||||
practiceStartTime = new Date().getTime();
|
||||
practiceRemainingTime.value = pkData.comLimit; // 设置倒计时初始值
|
||||
setupKeyboardHeightListener((height) => {
|
||||
popup_input_bottom.value = `${height}px`;
|
||||
console.log('需要卸载吗');
|
||||
});
|
||||
});
|
||||
onMounted(() => {
|
||||
startTimer(); // 启动/恢复定时器
|
||||
});
|
||||
onBackPress((res) => res.from === 'backbutton');
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
$bg-margin-left: 30rpx;
|
||||
|
||||
.popup_title_text {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.popup {
|
||||
//答题卡
|
||||
z-index: 1800;
|
||||
padding: 0 38rpx;
|
||||
|
||||
.sheet_popup_div {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #ffffff;
|
||||
padding: 10rpx 34rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
border-radius: 16rpx 16rpx 0px 0px;
|
||||
position: relative;
|
||||
|
||||
.title_div {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
padding: 30rpx 0;
|
||||
font-family: PingFangSC;
|
||||
font-weight: 600;
|
||||
font-size: 34rpx;
|
||||
color: #000000;
|
||||
text-align: center;
|
||||
font-style: normal;
|
||||
border-bottom: 2rpx solid #efefef;
|
||||
}
|
||||
|
||||
.popup_back_div {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
position: absolute;
|
||||
top: 30rpx;
|
||||
right: 30rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.img {
|
||||
width: 30rpx;
|
||||
height: 30rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.sheet_table {
|
||||
margin-top: 48rpx;
|
||||
margin-bottom: 48rpx;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
width: calc(100vw - 108rpx);
|
||||
align-content: space-between;
|
||||
|
||||
.sheet_table_item {
|
||||
width: calc((100vw - 108rpx) / 5 - 16rpx);
|
||||
height: calc((100vw - 108rpx) / 5 - 16rpx);
|
||||
margin: 8rpx;
|
||||
border: 2rpx solid #e5e5e5;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 32rpx;
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
.current {
|
||||
background-color: rgba(0, 102, 255, 0.6);
|
||||
border-color: #0066ff;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.completed {
|
||||
// 已完成
|
||||
background-color: rgba(0, 102, 255, 0.1);
|
||||
border-color: #0066ff;
|
||||
color: #0066ff;
|
||||
}
|
||||
|
||||
.mark,
|
||||
.completed.mark {
|
||||
background-color: rgba(232, 181, 49, 0.1);
|
||||
color: #e8b531;
|
||||
border-color: #e8b531;
|
||||
}
|
||||
|
||||
.current.mark {
|
||||
// 已完成
|
||||
background-color: rgba(0, 102, 255, 0.6);
|
||||
color: #ffffff;
|
||||
border-color: #e8b531;
|
||||
}
|
||||
}
|
||||
|
||||
.sheet_button {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.fixed-box {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
border-radius: 16rpx 16rpx 0px 0px;
|
||||
border: 2rpx solid #e5e5e5;
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.touch-btn-div {
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
transition: height 0.2s ease-out;
|
||||
}
|
||||
.touch-btn-div.show {
|
||||
height: 150rpx;
|
||||
}
|
||||
|
||||
.scroll-Y {
|
||||
max-height: calc(100vh - var(--status-bar-height) - 70rpx - 210rpx - 70rpx - 40rpx - 160rpx);
|
||||
min-height: calc(100vh - var(--status-bar-height) - 70rpx - 210rpx - 70rpx - 40rpx - 380rpx);
|
||||
}
|
||||
|
||||
.swiper {
|
||||
// 状态栏 var(--status-bar-height)
|
||||
// 标题栏目 70rpx
|
||||
// PK栏 170rpx + 上间距 40rpx
|
||||
// 进度时间栏 70rpx
|
||||
// 进度时间栏上下间距 40rpx = 20rpx + 20rpx
|
||||
// height: calc(100vh - var(--status-bar-height) - 70rpx - 70rpx - 40rpx - 64rpx);
|
||||
height: calc(100vh - var(--status-bar-height) - 70rpx - 210rpx - 70rpx - 40rpx);
|
||||
.no_questions {
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
position: relative;
|
||||
margin: 32rpx $bg-margin-left;
|
||||
border-radius: 16rpx;
|
||||
padding: 34rpx 30rpx 34rpx 36rpx;
|
||||
background-color: #fff;
|
||||
|
||||
.expose_shadow {
|
||||
margin-left: 36rpx;
|
||||
position: absolute;
|
||||
bottom: -26rpx;
|
||||
left: 0%;
|
||||
width: calc(100% - 66rpx);
|
||||
height: 28rpx;
|
||||
background-color: #ffffff;
|
||||
border-radius: 0 0 14rpx 14rpx;
|
||||
opacity: 0.4;
|
||||
z-index: 0;
|
||||
// background-color: red;
|
||||
}
|
||||
}
|
||||
|
||||
// 正确总数
|
||||
.success-sun-div {
|
||||
font-weight: 500;
|
||||
font-size: 30rpx;
|
||||
color: #333333;
|
||||
.number {
|
||||
font-weight: 600;
|
||||
color: #0066ff;
|
||||
}
|
||||
}
|
||||
.body-area-div {
|
||||
margin-top: -2rpx;
|
||||
background: linear-gradient(185deg, #eff4ff 0%, #e9ebf9 100%);
|
||||
}
|
||||
|
||||
.countdown-and-question-number-div {
|
||||
margin: 20rpx $bg-margin-left;
|
||||
height: 70rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
z-index: 10;
|
||||
|
||||
.top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-size: 30rpx;
|
||||
color: #0066ff;
|
||||
text-align: left;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.question {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 216rpx;
|
||||
flex-wrap: nowrap;
|
||||
height: 42rpx;
|
||||
background-color: #b2d1ff;
|
||||
border-radius: 20px;
|
||||
color: #044ebb;
|
||||
font-weight: bold;
|
||||
font-size: 30rpx;
|
||||
.countdown_time {
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
.grey {
|
||||
color: #8cabeb;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.bold {
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
.duel-msg-div {
|
||||
width: 100%;
|
||||
height: 172rpx;
|
||||
background-image: url('@/static/images/competition/pk_bg_icon.png');
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100% 100%; /* 让背景图填满盒子,与宽高比匹配 */
|
||||
margin-top: 40rpx;
|
||||
border-radius: 22rpx 22rpx 0 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
.personnel-div {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
.name-div {
|
||||
font-weight: 500;
|
||||
font-size: 30rpx;
|
||||
color: #ffffff;
|
||||
text-align: center;
|
||||
margin-top: 10rpx;
|
||||
max-width: 5rem;
|
||||
}
|
||||
.avatar-div {
|
||||
width: 78rpx;
|
||||
height: 78rpx;
|
||||
border: 2px solid #ffffff;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
.img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
.fraction-div {
|
||||
&.left {
|
||||
margin: 0 74rpx 0 30rpx;
|
||||
}
|
||||
&.right {
|
||||
margin: 0 30rpx 0 74rpx;
|
||||
}
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
.fraction-title {
|
||||
font-weight: 400;
|
||||
font-size: 24rpx;
|
||||
color: #fbe7d9;
|
||||
line-height: 34rpx;
|
||||
text-align: center;
|
||||
font-style: normal;
|
||||
}
|
||||
.fraction-value {
|
||||
margin-top: 10rpx;
|
||||
font-family: Arial, Arial;
|
||||
font-weight: 700;
|
||||
font-size: 50rpx;
|
||||
color: #ffffff;
|
||||
line-height: 60rpx;
|
||||
text-align: center;
|
||||
font-style: italic;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.nav-div {
|
||||
position: relative;
|
||||
|
||||
.title {
|
||||
margin: 0 calc($bg-margin-left + 70rpx);
|
||||
height: 70rpx;
|
||||
font-family: PingFangSC;
|
||||
font-weight: 600;
|
||||
font-size: 34rpx;
|
||||
color: #ffffff;
|
||||
text-align: center;
|
||||
font-style: normal;
|
||||
line-height: 70rpx;
|
||||
}
|
||||
|
||||
.back_div {
|
||||
position: absolute;
|
||||
left: $bg-margin-left;
|
||||
top: 0;
|
||||
width: 40rpx;
|
||||
height: 70rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
|
||||
.img {
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
}
|
||||
.back-icon {
|
||||
position: relative;
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.back-icon::before,
|
||||
.back-icon::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.back-icon::after {
|
||||
top: 25%;
|
||||
left: 25%;
|
||||
width: 40%;
|
||||
height: 40%;
|
||||
border-top: 4rpx solid #ffffff;
|
||||
border-left: 4rpx solid #ffffff;
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.main_div {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: #000;
|
||||
/* 确保背景占满整个视口高度 */
|
||||
min-height: 100vh;
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,399 @@
|
||||
<template>
|
||||
<view class="exam-ranking">
|
||||
<image src="@/static/images/competition/ranking/ranking_bg.png" mode="widthFix" class="bg-box"></image>
|
||||
<view class="ranking-box">
|
||||
<view class="nav-div">
|
||||
<view class="back_div" @click="common.navigateBack()">
|
||||
<view class="back-icon"></view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="title-view">
|
||||
<!-- <view class="title-info">考试排行榜</view> -->
|
||||
<image
|
||||
class="title-image"
|
||||
src="@/static/images/competition/ranking/ranking_title.png"
|
||||
mode="aspectFit"
|
||||
></image>
|
||||
<view class="title-desc">欲穷千里目,更上一层楼</view>
|
||||
<image class="cup-image" src="@/static/images/examRanking/cup.png" mode="aspectFit"></image>
|
||||
</view>
|
||||
<view class="ranking-body">
|
||||
<view class="list-header list-item">
|
||||
<view class="rank-column">排名</view>
|
||||
<view class="user-column">用户名/所属机构</view>
|
||||
<view class="score-column">最高分</view>
|
||||
<view class="time-column">用时</view>
|
||||
</view>
|
||||
<scroll-view :scroll-y="true" class="scroll-items-view">
|
||||
<view v-for="(item, index) in userList" :class="['list-item', 'item-' + (index + 1)]">
|
||||
<view class="rank-column">
|
||||
{{ item.ranking }}
|
||||
</view>
|
||||
<view class="user-column">
|
||||
<view class="avatar-box">
|
||||
<image-preview
|
||||
v-if="item.ossAddr"
|
||||
class="avatar-image"
|
||||
:src="item.ossAddr"
|
||||
mode="aspectFit"
|
||||
></image-preview>
|
||||
<image v-else class="avatar-image" :src="defaultAvatarSrc"></image>
|
||||
</view>
|
||||
<view class="user-name">{{ item.userName }}</view>
|
||||
<view class="user-org">{{ item.orgName }}</view>
|
||||
</view>
|
||||
<view class="score-column">{{ item.examGrade }}</view>
|
||||
<view class="time-column">{{ item.time ?? 0 }}s</view>
|
||||
</view>
|
||||
<list-no-data v-if="userList.length == 0">暂无数据</list-no-data>
|
||||
</scroll-view>
|
||||
</view>
|
||||
<view class="ranking-self">
|
||||
<view class="list-header list-item">
|
||||
<view class="rank-column">我的排名</view>
|
||||
</view>
|
||||
<view class="list-item item-me">
|
||||
<view class="rank-column">
|
||||
{{ userRankObj.ranking }}
|
||||
</view>
|
||||
<view class="user-column">
|
||||
<view class="avatar-box">
|
||||
<image-preview
|
||||
v-if="userRankObj.ossAddr"
|
||||
class="avatar-image"
|
||||
:src="userRankObj.ossAddr"
|
||||
mode="aspectFit"
|
||||
></image-preview>
|
||||
<image class="avatar-image" v-else :src="defaultAvatarSrc"></image>
|
||||
</view>
|
||||
<view class="user-name">{{ userRankObj.userName }}</view>
|
||||
<view class="user-org">{{ userRankObj.orgName }}</view>
|
||||
</view>
|
||||
<view class="score-column">{{ userRankObj.examGrade }}</view>
|
||||
<view class="time-column">{{ userRankObj.time }}s</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {queryTraCompetitionRankingList} from '@/api/competition.js';
|
||||
import {defaultAvatar} from '@/enum.js';
|
||||
import common from '@/common/common';
|
||||
import {onLoad} from '@dcloudio/uni-app';
|
||||
import {formatSecondsToMS} from './js/tool';
|
||||
import {ref} from 'vue';
|
||||
|
||||
const papersId = ref('');
|
||||
const orgId = ref('');
|
||||
const userList = ref([]);
|
||||
const userRankObj = ref({});
|
||||
onLoad((e) => {
|
||||
papersId.value = e.papersId;
|
||||
orgId.value = e.orgId;
|
||||
getList();
|
||||
});
|
||||
const getList = () => {
|
||||
queryTraCompetitionRankingList({
|
||||
papersId: papersId.value,
|
||||
orgId: orgId.value
|
||||
}).then((res) => {
|
||||
userList.value = res.body.rankingListVos || [];
|
||||
userRankObj.value = res.body;
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
$top-height: var(--status-bar-height);
|
||||
|
||||
.exam-ranking {
|
||||
position: relative;
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
padding-top: $top-height;
|
||||
|
||||
// background:url(@/static/images/examRanking/bg.png) no-repeat top center;
|
||||
.bg-box {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 412rpx;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.ranking-box {
|
||||
height: calc(100% - $top-height);
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
top: $top-height;
|
||||
width: 100%;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.nav-div {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
height: 70rpx;
|
||||
|
||||
.back_div {
|
||||
margin-right: 10rpx;
|
||||
position: absolute;
|
||||
left: 25rpx;
|
||||
top: 0;
|
||||
padding: 15rpx;
|
||||
|
||||
.back-icon {
|
||||
position: relative;
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.back-icon::before,
|
||||
.back-icon::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.back-icon::after {
|
||||
top: 25%;
|
||||
left: 25%;
|
||||
width: 40%;
|
||||
height: 40%;
|
||||
border-top: 4rpx solid #000;
|
||||
border-left: 4rpx solid #000;
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.title-view {
|
||||
height: 180rpx;
|
||||
position: relative;
|
||||
padding-left: 79rpx;
|
||||
padding-top: 20rpx;
|
||||
|
||||
.cup-image {
|
||||
position: absolute;
|
||||
right: 90rpx;
|
||||
bottom: -5rpx;
|
||||
width: 178rpx;
|
||||
height: 159rpx;
|
||||
}
|
||||
|
||||
.title-desc {
|
||||
line-height: 34rpx;
|
||||
font-size: 25rpx;
|
||||
color: #ffffff;
|
||||
margin-top: -6rpx;
|
||||
}
|
||||
|
||||
.title-image {
|
||||
width: 354rpx;
|
||||
height: 88rpx;
|
||||
margin-left: -20rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.ranking-body {
|
||||
height: calc(100% - 170rpx - 180rpx - 70rpx);
|
||||
overflow: hidden;
|
||||
background-color: #fff;
|
||||
border-radius: 31rpx 31rpx 0 0;
|
||||
padding-top: 20rpx;
|
||||
box-sizing: border-box;
|
||||
z-index: 100;
|
||||
|
||||
.scroll-items-view {
|
||||
height: calc(100% - 54rpx);
|
||||
}
|
||||
}
|
||||
|
||||
.list-item {
|
||||
height: 108rpx;
|
||||
border-bottom: 2rpx solid #efefef;
|
||||
overflow: hidden;
|
||||
|
||||
&.list-header {
|
||||
height: 54rpx;
|
||||
line-height: 54rpx;
|
||||
color: #999;
|
||||
font-size: 25rpx;
|
||||
border-bottom: 0;
|
||||
|
||||
.rank-column {
|
||||
height: 54rpx;
|
||||
line-height: 54rpx;
|
||||
color: #999;
|
||||
font-weight: normal;
|
||||
font-size: 25rpx;
|
||||
font-style: initial;
|
||||
text-indent: 0;
|
||||
}
|
||||
|
||||
.user-column {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.score-column {
|
||||
line-height: 54rpx;
|
||||
color: #999;
|
||||
font-weight: normal;
|
||||
font-size: 25rpx;
|
||||
}
|
||||
|
||||
.time-column {
|
||||
line-height: 54rpx;
|
||||
color: #999;
|
||||
font-weight: normal;
|
||||
font-size: 25rpx;
|
||||
}
|
||||
}
|
||||
|
||||
&.item-1 {
|
||||
border-bottom: 0;
|
||||
margin-bottom: 8rpx;
|
||||
background: linear-gradient(90deg, #fbf9f5 0%, #fffffd 100%);
|
||||
|
||||
.rank-column {
|
||||
color: #ffffff00;
|
||||
background: url(@/static/images/examRanking/no-1.png) no-repeat;
|
||||
background-position: 40rpx center;
|
||||
background-size: 44rpx 66rpx;
|
||||
text-indent: 8rpx;
|
||||
}
|
||||
}
|
||||
|
||||
&.item-2 {
|
||||
border-bottom: 0;
|
||||
margin-bottom: 8rpx;
|
||||
background: linear-gradient(90deg, #f4f8f9 0%, #f7fbfe 100%);
|
||||
|
||||
.rank-column {
|
||||
color: #ffffff00;
|
||||
background: url(@/static/images/examRanking/no-2.png) no-repeat;
|
||||
background-position: 40rpx center;
|
||||
background-size: 44rpx 66rpx;
|
||||
text-indent: 8rpx;
|
||||
}
|
||||
}
|
||||
|
||||
&.item-3 {
|
||||
border-bottom: 0;
|
||||
margin-bottom: 8rpx;
|
||||
background: linear-gradient(90deg, #faf6f5 0%, #fcfbfc 100%);
|
||||
|
||||
.rank-column {
|
||||
color: #ffffff00;
|
||||
background: url(@/static/images/examRanking/no-3.png) no-repeat;
|
||||
background-position: 40rpx center;
|
||||
background-size: 44rpx 66rpx;
|
||||
text-indent: 8rpx;
|
||||
}
|
||||
}
|
||||
|
||||
&.item-me {
|
||||
border-bottom: 0;
|
||||
|
||||
.rank-column {
|
||||
color: #06f;
|
||||
}
|
||||
}
|
||||
|
||||
.rank-column {
|
||||
width: 170rpx;
|
||||
padding-left: 40rpx;
|
||||
float: left;
|
||||
font-weight: 600;
|
||||
line-height: 92rpx;
|
||||
height: 108rpx;
|
||||
color: #333;
|
||||
font-size: 38rpx;
|
||||
font-style: italic;
|
||||
text-indent: 8rpx;
|
||||
}
|
||||
|
||||
.user-column {
|
||||
width: 300rpx;
|
||||
float: left;
|
||||
padding: 15rpx 0;
|
||||
|
||||
.avatar-box {
|
||||
width: 77rpx;
|
||||
height: 77rpx;
|
||||
overflow: hidden;
|
||||
float: left;
|
||||
background-color: #eee;
|
||||
border-radius: 50%;
|
||||
|
||||
.avatar-image {
|
||||
width: 77rpx;
|
||||
height: 77rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.user-name {
|
||||
float: left;
|
||||
width: calc(100% - 77rpx);
|
||||
padding-left: 18rpx;
|
||||
padding-right: 18rpx;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
height: 40rpx;
|
||||
line-height: 40rpx;
|
||||
font-size: 29rpx;
|
||||
color: #000;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.user-org {
|
||||
float: left;
|
||||
width: calc(100% - 77rpx);
|
||||
padding-left: 18rpx;
|
||||
padding-right: 18rpx;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
height: 34rpx;
|
||||
line-height: 34rpx;
|
||||
font-size: 25rpx;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
.score-column {
|
||||
width: 126rpx;
|
||||
text-align: right;
|
||||
float: left;
|
||||
font-weight: 600;
|
||||
line-height: 108rpx;
|
||||
color: #333;
|
||||
font-size: 31rpx;
|
||||
}
|
||||
|
||||
.time-column {
|
||||
width: 100rpx;
|
||||
text-align: right;
|
||||
float: left;
|
||||
font-weight: 600;
|
||||
line-height: 108rpx;
|
||||
color: #333;
|
||||
font-size: 31rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.ranking-self {
|
||||
height: 170rpx;
|
||||
overflow: hidden;
|
||||
background-color: #f5f9ff;
|
||||
padding-top: 4rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,586 @@
|
||||
<template>
|
||||
<view class="main_div max_page">
|
||||
<!-- 顶部一些按钮 -->
|
||||
<view class="top-button-div">
|
||||
<view class="back_div" @click="common.navigateBack()">
|
||||
<view class="back-icon"></view>
|
||||
</view>
|
||||
<view class="fl1"></view>
|
||||
</view>
|
||||
<view class="fl1"></view>
|
||||
<view class="show-main-div" :class="action">
|
||||
<!-- 伸展出的吉祥物 -->
|
||||
<view class="result-container-div" :class="{ victory: jieguo === 'Y' }">
|
||||
<image class="img" src="@/static/images/competition/result_shengli.png"></image>
|
||||
</view>
|
||||
<view class="result-container-div" :class="{ defeat: jieguo === 'N' }">
|
||||
<image class="img defeat" src="@/static/images/competition/result_shibai.png"></image>
|
||||
</view>
|
||||
|
||||
<view class="mascot-div">
|
||||
<image class="img" src="@/static/images/competition/result_loading_mascot.png"></image>
|
||||
</view>
|
||||
|
||||
<view class="mascot-msg-div">
|
||||
<image class="img" src="@/static/images/competition/result_loading_msg.png"></image>
|
||||
</view>
|
||||
|
||||
<view class="bg-div">
|
||||
<!-- 下方的pk结算信息 -->
|
||||
<view class="pk-msg-div">
|
||||
<view class="win-icon" :class="jieguo">
|
||||
<image class="img_100" src="@/static/images/competition/result_huosheng.png"></image>
|
||||
</view>
|
||||
<view class="pk-msg-left-div">
|
||||
<view class="avatar-div">
|
||||
<cached-avatar v-if="pkData.isAnony === 'N'" class="img"></cached-avatar>
|
||||
<image v-else class="img" :src="defaultAnonymousAvatar" mode="aspectFill"></image>
|
||||
</view>
|
||||
|
||||
<view class="name-div">{{ pkData.userName }}</view>
|
||||
<view class="title">正确/总题数</view>
|
||||
<view class="topic-div number">
|
||||
<text class="loadingNoText font-size-54">{{ pkData.correctNub }}</text>
|
||||
<text class="loadingNoText">/{{ pkData.qnsNub }}</text>
|
||||
<text class="loadingText">结算中</text>
|
||||
</view>
|
||||
<view class="title">总分</view>
|
||||
<view class="score-div number">
|
||||
<text class="font-size-54 loadingNoText">{{ pkData.totalScore }}</text>
|
||||
<text class="loadingText">结算中</text>
|
||||
</view>
|
||||
<view class="title">用时</view>
|
||||
<view class="time-div number">
|
||||
<text class="loadingNoText">{{ formatSecondsToMS(pkData.timeTaken) }}</text>
|
||||
<text class="loadingText">结算中</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="pk-msg-right-div">
|
||||
<view class="avatar-div">
|
||||
<image-preview v-if="pkData.isAnonyPk === 'N'" class="img" :src="pkData.imgPk"></image-preview>
|
||||
<image v-else class="img" :src="defaultAnonymousAvatar" mode="aspectFill"></image>
|
||||
</view>
|
||||
<view class="name-div">{{ pkData.userNamePk }}</view>
|
||||
<view class="title">正确/总题数</view>
|
||||
<view class="topic-div number">
|
||||
<text class="loadingNoText font-size-54">{{ pkData.correctNubPk }}</text>
|
||||
<text class="loadingNoText">/{{ pkData.qnsNubPk }}</text>
|
||||
<text class="loadingText">结算中</text>
|
||||
</view>
|
||||
<view class="title">总分</view>
|
||||
<view class="score-div number">
|
||||
<text class="font-size-54 loadingNoText">{{ pkData.totalScorePk }}</text>
|
||||
<text class="loadingText">结算中</text>
|
||||
</view>
|
||||
<view class="title">用时</view>
|
||||
<view class="time-div number">
|
||||
<text class="loadingNoText">{{ formatSecondsToMS(pkData.timeTakenPk) }}</text>
|
||||
<text class="loadingText">结算中</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 查看排行榜按钮 -->
|
||||
<view class="ranking-list-div" @click="buttonClick('toRanking')">查看排行榜</view>
|
||||
<!-- 下方的两个按钮 -->
|
||||
<view class="fl1"></view>
|
||||
<view class="bottom-button-div">
|
||||
<uv-button class="button-1" text="退出挑战" shape="circle" @click="buttonClick('exit')"></uv-button>
|
||||
<uv-button class="button-2" text="继续挑战" shape="circle" @click="buttonClick('continue')"></uv-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, reactive, computed, nextTick } from 'vue';
|
||||
import common, { getUserInfo } from '@/common/common';
|
||||
import { MatchTimeGenerator, formatTime } from './js/matching';
|
||||
import { queryCompetitionAnswerResult } from '@/api/competition';
|
||||
import { onLoad } from '@dcloudio/uni-app';
|
||||
import { defaultAnonymousAvatar } from '@/enum';
|
||||
import { pkAnonymousClose, pkAnonymousOpen, pkRankingList, pkRules } from '@/common/imgSvg';
|
||||
import { queryTraUserAnonyByUserId, updateTraUserAnony } from '@/api/user';
|
||||
import { formatSecondsToMS } from './js/tool';
|
||||
|
||||
const action = ref('');
|
||||
const pkData = reactive({
|
||||
// 公共的
|
||||
execId: '',
|
||||
papersId: '',
|
||||
orgId: '',
|
||||
answerResult: '', // 答题结果 Y代表我赢,N代表我输
|
||||
timeDifference: 30, // 时差 int 单位 s
|
||||
|
||||
// 自己的
|
||||
userName: '',
|
||||
isAnony: 'Y', // 匿名 String
|
||||
correctNub: 0, // 正确数 int
|
||||
qnsNub: 0, // 总数 int
|
||||
timeTaken: 0, // 用时 int
|
||||
totalScore: 0, // 我方总分 int
|
||||
|
||||
// 对方的
|
||||
userIdPk: '', // 用户Id String
|
||||
userNamePk: '', // 用户姓名 String
|
||||
imgPk: '', // 对方头像 String
|
||||
isAnonyPk: 'Y', // 匿名 String
|
||||
correctNubPk: 0, // 正确数 int
|
||||
qnsNubPk: 0, // 总数 int
|
||||
timeTakenPk: 0, // 用时 int
|
||||
totalScorePk: 0 // 对方总分 int
|
||||
});
|
||||
const jieguo = computed(() => pkData.answerResult);
|
||||
const buttonClick = (type: String) => {
|
||||
if (type === 'exit') {
|
||||
common.navigateBack(2);
|
||||
} else if (type === 'continue') {
|
||||
common.navigateBack();
|
||||
} else if (type === 'toRanking') {
|
||||
common.navigateTo(`/pages/competition/ranking?papersId=${pkData.papersId}&orgId=${pkData.orgId}`);
|
||||
}
|
||||
};
|
||||
|
||||
onLoad((e) => {
|
||||
pkData.execId = e.execId || '';
|
||||
pkData.papersId = e.papersId || '';
|
||||
pkData.orgId = e.orgId || '';
|
||||
const pkDataInit = common.getPageCache('competition_pk_to_resulf');
|
||||
Object.assign(pkData, {
|
||||
userName: pkDataInit.userName,
|
||||
isAnony: pkDataInit.isAnony
|
||||
});
|
||||
});
|
||||
onMounted(() => {
|
||||
action.value = 'loading';
|
||||
setTimeout(() => {
|
||||
queryCompetitionAnswerResult({ execId: pkData.execId }).then(({ body }) => {
|
||||
const userResult = body.userResult;
|
||||
pkData.answerResult = body.answerResult; // 答题结果 Y代表我赢,N代表我输
|
||||
pkData.timeDifference = body.timeDifference; // 时差 int 单位 s
|
||||
Object.assign(pkData, {
|
||||
// 自己的
|
||||
isAnony: userResult.isAnony, // 匿名 String
|
||||
correctNub: userResult.correctNub, // 正确数 int
|
||||
qnsNub: userResult.qnsNub, // 总数 int
|
||||
timeTaken: userResult.timeTaken, // 用时 int
|
||||
totalScore: userResult.totalScore || 0, // 我方总分
|
||||
// 对方的
|
||||
userIdPk: userResult.userIdPk, // 用户Id String
|
||||
userNamePk: userResult.userNamePk, // 用户姓名 String
|
||||
imgPk: userResult.imgPk, // 用户姓名 String
|
||||
pkIsAnony: userResult.pkIsAnony, // 匿名 String
|
||||
correctNubPk: userResult.correctNubPk, // 正确数 int
|
||||
qnsNubPk: userResult.qnsNubPk || 0, // 总数 int
|
||||
timeTakenPk: userResult.timeTakenPk || 0, // 用时 int
|
||||
totalScorePk: userResult.totalScorePk || 0 // 对方总分
|
||||
});
|
||||
nextTick(() => {
|
||||
action.value = 'result';
|
||||
});
|
||||
});
|
||||
}, 2000);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.pk-msg-div {
|
||||
width: 570rpx;
|
||||
height: 480rpx;
|
||||
background-image: url('@/static/images/competition/result_pk_bg.png');
|
||||
background-size: 100% auto; /* 宽度填满,高度自适应 */
|
||||
background-position: center top; /* 图片顶部居中显示 */
|
||||
background-repeat: no-repeat; /* 不重复平铺 */
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
font-size: 26rpx;
|
||||
.pk-msg-left-div > .avatar-div {
|
||||
border: 3rpx solid #2b7af1;
|
||||
}
|
||||
.pk-msg-right-div > .avatar-div {
|
||||
border: 3rpx solid #f63c13;
|
||||
}
|
||||
.avatar-div {
|
||||
width: 78rpx;
|
||||
height: 78rpx;
|
||||
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
margin-top: 30rpx;
|
||||
flex-shrink: 0;
|
||||
.img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
.name-div {
|
||||
margin-top: 10rpx;
|
||||
font-weight: 700;
|
||||
font-size: 30rpx;
|
||||
color: #000000;
|
||||
height: 42rpx;
|
||||
}
|
||||
.topic-div {
|
||||
font-family: Arial, Arial;
|
||||
font-style: italic;
|
||||
height: 62rpx;
|
||||
line-height: 62rpx;
|
||||
}
|
||||
.score-div {
|
||||
font-family: Arial, Arial;
|
||||
height: 62rpx;
|
||||
line-height: 62rpx;
|
||||
}
|
||||
.win-icon {
|
||||
width: 140rpx;
|
||||
height: 130rpx;
|
||||
position: absolute;
|
||||
display: none;
|
||||
&.Y {
|
||||
display: block;
|
||||
left: -20rpx;
|
||||
top: -46rpx;
|
||||
}
|
||||
&.N {
|
||||
display: block;
|
||||
right: -30rpx;
|
||||
top: -46rpx;
|
||||
}
|
||||
}
|
||||
.pk-msg-left-div,
|
||||
.pk-msg-right-div {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
.title {
|
||||
font-weight: 400;
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
}
|
||||
.pk-msg-left-div {
|
||||
.title {
|
||||
color: #6a8db1;
|
||||
}
|
||||
.number {
|
||||
color: #2b7af1;
|
||||
}
|
||||
}
|
||||
.pk-msg-right-div {
|
||||
.title {
|
||||
color: #b16f6a;
|
||||
}
|
||||
.number {
|
||||
color: #f63c13;
|
||||
}
|
||||
}
|
||||
.font-size-54 {
|
||||
font-size: 54rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
}
|
||||
|
||||
.show-main-div {
|
||||
width: 100%;
|
||||
min-height: 500rpx;
|
||||
background-color: #fff; /* 关键:背景图未覆盖的区域填充白色 */
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
border-radius: 31px 31px 0px 0px;
|
||||
@keyframes victoryEnter {
|
||||
0% {
|
||||
transform: translateY(50rpx) scale(0.8);
|
||||
opacity: 0;
|
||||
}
|
||||
30% {
|
||||
transform: translateY(-10rpx) scale(1.05);
|
||||
}
|
||||
100% {
|
||||
transform: translateY(0) scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes defeatEnter {
|
||||
0% {
|
||||
transform: translateY(-50rpx) scale(1.2);
|
||||
opacity: 0;
|
||||
}
|
||||
70% {
|
||||
transform: translateY(10rpx) scale(0.95);
|
||||
}
|
||||
100% {
|
||||
transform: translateY(0) scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
@keyframes defeatRotateSway {
|
||||
0% {
|
||||
transform: rotate(0deg); // 初始角度
|
||||
}
|
||||
25% {
|
||||
transform: rotate(-2deg); // 向左微转2度
|
||||
}
|
||||
75% {
|
||||
transform: rotate(2deg); // 向右微转2度
|
||||
}
|
||||
100% {
|
||||
transform: rotate(0deg); // 回到初始角度
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes victoryFloat {
|
||||
0%,
|
||||
100% {
|
||||
transform: translateY(0);
|
||||
// transform: translateY(0);
|
||||
}
|
||||
50% {
|
||||
transform: translateY(-10rpx);
|
||||
// transform: translateY(-10rpx);
|
||||
}
|
||||
}
|
||||
.loadingText {
|
||||
display: none;
|
||||
}
|
||||
// loading 状态样式(保持不变)
|
||||
&.loading {
|
||||
.mascot-div {
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
.mascot-msg-div {
|
||||
opacity: 1;
|
||||
pointer-events: auto;
|
||||
}
|
||||
.topic-div,
|
||||
.score-div,
|
||||
.time-div {
|
||||
position: relative;
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 4rpx;
|
||||
left: calc(100% + 3rpx);
|
||||
animation: loading 2.5s infinite;
|
||||
}
|
||||
@keyframes loading {
|
||||
0% {
|
||||
content: '';
|
||||
}
|
||||
25% {
|
||||
content: '.';
|
||||
}
|
||||
50% {
|
||||
content: '..';
|
||||
}
|
||||
75% {
|
||||
content: '...';
|
||||
}
|
||||
100% {
|
||||
content: '';
|
||||
}
|
||||
}
|
||||
}
|
||||
.loadingText {
|
||||
display: inline;
|
||||
}
|
||||
.loadingNoText {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
// 当 action=result 时,触发结果动画
|
||||
&.result {
|
||||
// 胜利状态:入场 + 浮动 + 闪光
|
||||
.result-container-div.victory {
|
||||
animation: victoryEnter 0.8s cubic-bezier(0.22, 1, 0.36, 1) forwards,
|
||||
victoryFloat 2s ease-in-out infinite 0.8s;
|
||||
}
|
||||
// 失败状态:入场 + 抖动
|
||||
.result-container-div.defeat {
|
||||
// defeatShake 1s ease-in-out infinite 0.6s
|
||||
animation: defeatEnter 0.6s ease-out forwards, defeatRotateSway 1s ease-in-out 0.6s 1; // 入场后开始晃动,2秒结束,仅1次
|
||||
}
|
||||
}
|
||||
|
||||
// 结果容器基础样式
|
||||
.result-container-div {
|
||||
position: absolute;
|
||||
top: -300rpx; // 初始位置(可根据需求调整)
|
||||
z-index: 20;
|
||||
opacity: 0; // 初始隐藏,动画中变为1
|
||||
.img {
|
||||
width: 512rpx;
|
||||
height: 408rpx;
|
||||
display: block; // 避免图片底部间隙
|
||||
}
|
||||
}
|
||||
.mascot-div {
|
||||
position: absolute;
|
||||
top: -300rpx;
|
||||
margin-left: 50rpx;
|
||||
transition: top 0.6s ease-out;
|
||||
z-index: 5;
|
||||
left: 100%;
|
||||
transform: translateX(0);
|
||||
transition: left 0.5s ease-out, transform 0.5s ease-out;
|
||||
.img {
|
||||
width: 284rpx;
|
||||
height: 400rpx;
|
||||
}
|
||||
}
|
||||
.mascot-msg-div {
|
||||
position: absolute;
|
||||
top: -300rpx;
|
||||
transition: top 0.6s ease-out;
|
||||
z-index: 20;
|
||||
margin-top: 240rpx;
|
||||
transition: top 0.6s ease-out, opacity 0.5s ease-out; /* 新增透明度过渡 */
|
||||
z-index: 20;
|
||||
opacity: 0; /* 初始隐藏 */
|
||||
pointer-events: none; /* 隐藏时不响应交互 */
|
||||
.img {
|
||||
width: 326rpx;
|
||||
height: 198rpx;
|
||||
}
|
||||
}
|
||||
.bg-div {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
border-radius: 20rpx 20rpx 0 0;
|
||||
padding-top: 140rpx;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.img {
|
||||
// width: 100%;
|
||||
// height: 100%;
|
||||
}
|
||||
z-index: 10;
|
||||
background: linear-gradient(to bottom, transparent 0%, #ffffff 200rpx, #ffffff 100%),
|
||||
linear-gradient(to right, #bfebff 0%, #fef1de 100%);
|
||||
}
|
||||
|
||||
.ranking-list-div {
|
||||
margin-top: 48rpx;
|
||||
margin-bottom: 24rpx;
|
||||
font-weight: 400;
|
||||
font-size: 30rpx;
|
||||
color: #0066ff;
|
||||
text-align: center;
|
||||
font-style: normal;
|
||||
}
|
||||
.bottom-button-div {
|
||||
display: flex;
|
||||
margin-top: 50rpx;
|
||||
margin-bottom: 60rpx;
|
||||
:deep(.uv-button) {
|
||||
/* 以下是所有 .uv-button 共用的公共样式 */
|
||||
margin: 16rpx;
|
||||
width: 246rpx;
|
||||
height: 92rpx;
|
||||
border-radius: 58px;
|
||||
font-weight: 500;
|
||||
text-align: center;
|
||||
.uv-button__text {
|
||||
font-size: 30rpx !important;
|
||||
}
|
||||
}
|
||||
|
||||
.button-1 :deep(.uv-button) {
|
||||
background-color: #fff;
|
||||
}
|
||||
.button-2 :deep(.uv-button) {
|
||||
background: linear-gradient(0deg, #009fff 0%, #0066ff 100%) !important;
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.top-button-div {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
height: 70rpx;
|
||||
padding-top: 10rpx;
|
||||
font-weight: 500;
|
||||
position: relative;
|
||||
margin-right: 10rpx;
|
||||
.top-icon-div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: 30rpx;
|
||||
font-weight: 400;
|
||||
font-size: 26rpx;
|
||||
color: #ffffff;
|
||||
text-align: left;
|
||||
|
||||
.img1,
|
||||
.img2,
|
||||
.img3 {
|
||||
margin-right: 6rpx;
|
||||
}
|
||||
.img1,
|
||||
.img3 {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
}
|
||||
.img2 {
|
||||
width: 30rpx;
|
||||
height: 30rpx;
|
||||
}
|
||||
}
|
||||
.back_div {
|
||||
position: absolute;
|
||||
left: 26rpx;
|
||||
height: 34rpx;
|
||||
top: 17rpx;
|
||||
|
||||
.back-icon {
|
||||
position: relative;
|
||||
width: 50rpx;
|
||||
height: 50rpx;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.back-icon::before,
|
||||
.back-icon::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.back-icon::after {
|
||||
top: 25%;
|
||||
left: 25%;
|
||||
width: 40%;
|
||||
height: 40%;
|
||||
border-top: 4rpx solid #ffffff;
|
||||
border-left: 4rpx solid #ffffff;
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 容器样式 */
|
||||
.max_page {
|
||||
width: 100%;
|
||||
min-height: 100vh;
|
||||
background-image: url('@/static/images/competition/bg.png');
|
||||
background-color: #000; /* 图片高度不足时的背景色 */
|
||||
background-size: 100% auto; /* 宽度填满,高度自适应 */
|
||||
background-position: center top; /* 图片顶部居中显示 */
|
||||
background-repeat: no-repeat; /* 不重复平铺 */
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,37 @@
|
||||
.match-time-div {
|
||||
font-weight: 400;
|
||||
font-size: 34rpx;
|
||||
color: #ffffff;
|
||||
line-height: 34rpx;
|
||||
font-style: normal;
|
||||
margin-bottom: 20rpx;
|
||||
transition: opacity 0.3s cubic-bezier(0.34, 1.56, 0.64, 1), transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||
opacity: 1; /* 初始显示状态 */
|
||||
transform: translateY(0); /* 初始位置 */
|
||||
&.hidden {
|
||||
opacity: 0; /* 完全透明 */
|
||||
transform: translateY(40rpx); /* 轻微上移增强淡出效果 */
|
||||
pointer-events: none; /* 隐藏后不响应事件 */
|
||||
height: 0; /* 可选:完全隐藏高度 */
|
||||
overflow: hidden; /* 可选:隐藏溢出内容 */
|
||||
}
|
||||
}
|
||||
.match-msg-div {
|
||||
width: 100%;
|
||||
height: 8vh;
|
||||
font-weight: normal;
|
||||
font-size: 72rpx;
|
||||
color: #ffffff;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: flex-end;
|
||||
transition: opacity 0.3s cubic-bezier(0.34, 1.56, 0.64, 1), transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||
opacity: 1; /* 初始显示状态 */
|
||||
transform: translateY(0); /* 初始位置 */
|
||||
&.hidden {
|
||||
opacity: 0; /* 完全透明 */
|
||||
transform: translateY(-40rpx); /* 轻微上移增强淡出效果 */
|
||||
pointer-events: none; /* 隐藏后不响应事件 */
|
||||
overflow: hidden; /* 可选:隐藏溢出内容 */
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,334 @@
|
||||
.select-div {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
transition: opacity 0.3s ease-out;
|
||||
opacity: 1; /* 初始显示状态 */
|
||||
&.hidden {
|
||||
opacity: 0; /* 完全透明 */
|
||||
pointer-events: none; /* 隐藏后不响应事件 */
|
||||
height: 0; /* 可选:完全隐藏高度 */
|
||||
overflow: hidden; /* 可选:隐藏溢出内容 */
|
||||
}
|
||||
}
|
||||
.select-institution-msg-div {
|
||||
width: calc(100% - 228rpx);
|
||||
font-weight: 400;
|
||||
font-size: 22rpx;
|
||||
color: #ffffff;
|
||||
line-height: 32rpx;
|
||||
text-align: left;
|
||||
font-style: normal;
|
||||
opacity: 0.8;
|
||||
padding-top: 18rpx;
|
||||
padding-bottom: 18rpx;
|
||||
}
|
||||
|
||||
.select-institution-div {
|
||||
width: calc(100% - 228rpx);
|
||||
height: 86rpx;
|
||||
border: 1rpx solid transparent;
|
||||
position: relative;
|
||||
font-weight: 400;
|
||||
font-size: 32rpx;
|
||||
line-height: 86rpx;
|
||||
text-align: center;
|
||||
color: #ffffff;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
z-index: 1;
|
||||
overflow: hidden;
|
||||
padding: 0 60rpx 0 20rpx;
|
||||
white-space: nowrap;
|
||||
/* 强制不换行 */
|
||||
overflow: hidden;
|
||||
/* 超出部分隐藏 */
|
||||
text-overflow: ellipsis;
|
||||
.img {
|
||||
// background-color: red;
|
||||
padding: 16rpx;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
right: 10rpx;
|
||||
width: 30rpx;
|
||||
height: 30rpx;
|
||||
}
|
||||
}
|
||||
|
||||
/* 边框高光效果 */
|
||||
.select-institution-div::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
border: 4rpx solid transparent;
|
||||
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.8), transparent) border-box;
|
||||
-webkit-mask: linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0);
|
||||
-webkit-mask-composite: xor;
|
||||
mask-composite: exclude;
|
||||
|
||||
/* 初始位置在左侧外部 */
|
||||
background-size: 200% 100%;
|
||||
|
||||
/* 动画:高光从左到右流动 */
|
||||
animation: highlightFlow 4s linear infinite;
|
||||
}
|
||||
|
||||
/* 定义高光流动动画 */
|
||||
@keyframes highlightFlow {
|
||||
0% {
|
||||
background-position: -100% 0;
|
||||
}
|
||||
100% {
|
||||
background-position: 100% 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* 环绕版本带呼吸效果 */
|
||||
.select-institution-div.full-flow::before {
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
transparent,
|
||||
rgba(255, 255, 255, 0.8),
|
||||
transparent,
|
||||
transparent,
|
||||
transparent,
|
||||
transparent,
|
||||
transparent,
|
||||
transparent
|
||||
);
|
||||
background-size: 300% 300%;
|
||||
animation: fullBorderFlow 2s linear infinite, breathing 1s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes fullBorderFlow {
|
||||
0% {
|
||||
background-position: 0 0;
|
||||
}
|
||||
25% {
|
||||
background-position: 100% 0;
|
||||
}
|
||||
50% {
|
||||
background-position: 100% 100%;
|
||||
}
|
||||
75% {
|
||||
background-position: 0 100%;
|
||||
}
|
||||
100% {
|
||||
background-position: 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
.title-div {
|
||||
width: calc(100% - 80rpx);
|
||||
margin: 40rpx;
|
||||
font-size: 32rpx;
|
||||
font-weight: 500;
|
||||
color: #ffffff;
|
||||
line-height: 44rpx;
|
||||
text-shadow: 0px 0px 19px rgba(0, 0, 0, 0.11);
|
||||
text-align: center;
|
||||
font-family: none;
|
||||
min-height: 88rpx;
|
||||
margin: calc(var(--status-bar-height) + 40rpx);
|
||||
|
||||
/* 添加过渡动画 */
|
||||
transition: opacity 0.3s ease-out, transform 0.3s ease-out;
|
||||
opacity: 1; /* 初始显示状态 */
|
||||
transform: translateY(0); /* 初始位置 */
|
||||
&.hidden {
|
||||
opacity: 0; /* 完全透明 */
|
||||
transform: translateY(-10rpx); /* 轻微上移增强淡出效果 */
|
||||
pointer-events: none; /* 隐藏后不响应事件 */
|
||||
height: 0; /* 可选:完全隐藏高度 */
|
||||
overflow: hidden; /* 可选:隐藏溢出内容 */
|
||||
}
|
||||
}
|
||||
|
||||
.avatar-div {
|
||||
margin-top: 20rpx;
|
||||
.avatar-img-div {
|
||||
width: 204rpx;
|
||||
height: 204rpx;
|
||||
border: 4rpx solid #ffffff;
|
||||
border-radius: 50%;
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
/* 修复伪元素显示问题 */
|
||||
&.hidden::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
/* 使用固定尺寸确保计算正确 */
|
||||
width: 230rpx;
|
||||
height: 230rpx;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
/* 确保在z轴上处于正确层级 */
|
||||
z-index: 1;
|
||||
/* 背景图设置 */
|
||||
background-image: url('@/static/images/competition/avatar_surround.png');
|
||||
background-size: contain; /* 改用contain确保完整显示 */
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
/* 旋转动画 */
|
||||
animation: variableRotate 2s linear infinite;
|
||||
}
|
||||
.img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 50%;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes variableRotate {
|
||||
0% {
|
||||
transform: translate(-50%, -50%) rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: translate(-50%, -50%) rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.avatar-name-div {
|
||||
font-weight: 600;
|
||||
font-size: 46rpx;
|
||||
color: #ffffff;
|
||||
line-height: 64rpx;
|
||||
text-align: center;
|
||||
font-style: normal;
|
||||
padding-top: 16rpx;
|
||||
padding-bottom: 16rpx;
|
||||
}
|
||||
}
|
||||
.button-div {
|
||||
.start_button {
|
||||
width: 569rpx;
|
||||
height: 92rpx;
|
||||
background: linear-gradient(#009fff 0%, #0066ff 100%);
|
||||
border-radius: 58rpx;
|
||||
font-weight: 500;
|
||||
font-size: 30rpx;
|
||||
color: #ffffff;
|
||||
line-height: 92rpx;
|
||||
text-align: center;
|
||||
margin-top: 250rpx;
|
||||
}
|
||||
.cancel_button {
|
||||
width: 246rpx;
|
||||
height: 92rpx;
|
||||
border-radius: 58rpx;
|
||||
font-weight: 500;
|
||||
font-size: 30rpx;
|
||||
color: #ffffff;
|
||||
line-height: 92rpx;
|
||||
text-align: center;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
background: linear-gradient(rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.5) 100%);
|
||||
border-radius: 58rpx;
|
||||
border: 2rpx solid #dbdbdb;
|
||||
margin-bottom: 250rpx; /* 向上移动50rpx,可根据需要调整 */
|
||||
}
|
||||
.button-transition {
|
||||
/* 添加过渡动画属性 */
|
||||
transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||
/* 确保边框变化也有过渡效果 */
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
|
||||
.top-button-div {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
height: 70rpx;
|
||||
padding-top: calc(16rpx + var(--status-bar-height));
|
||||
font-weight: 500;
|
||||
position: relative;
|
||||
margin-right: 10rpx;
|
||||
.top-icon-div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: 30rpx;
|
||||
font-weight: 400;
|
||||
font-size: 26rpx;
|
||||
color: #ffffff;
|
||||
text-align: left;
|
||||
.img1,
|
||||
.img3 {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
margin-right: 6rpx;
|
||||
}
|
||||
.img2 {
|
||||
width: 30rpx;
|
||||
height: 30rpx;
|
||||
margin-right: 6rpx;
|
||||
}
|
||||
}
|
||||
.back_div {
|
||||
position: absolute;
|
||||
left: 26rpx;
|
||||
height: 34rpx;
|
||||
top: calc(10rpx + var(--status-bar-height));
|
||||
.back-icon {
|
||||
position: relative;
|
||||
width: 50rpx;
|
||||
height: 50rpx;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.back-icon::before,
|
||||
.back-icon::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.back-icon::after {
|
||||
top: 25%;
|
||||
left: 25%;
|
||||
width: 40%;
|
||||
height: 40%;
|
||||
border-top: 4rpx solid #ffffff;
|
||||
border-left: 4rpx solid #ffffff;
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.popup {
|
||||
z-index: 1800;
|
||||
padding: 0 38rpx;
|
||||
|
||||
.sheet_popup_div {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #ffffff;
|
||||
padding: 10rpx 34rpx;
|
||||
border-radius: 34rpx 34rpx 0px 0px;
|
||||
position: relative;
|
||||
|
||||
.title_div {
|
||||
width: 100%;
|
||||
padding: 30rpx 0;
|
||||
font-family: PingFangSC;
|
||||
font-weight: 600;
|
||||
font-size: 30rpx;
|
||||
color: #000000;
|
||||
font-style: normal;
|
||||
border-bottom: 2rpx solid #efefef;
|
||||
}
|
||||
.note_div {
|
||||
padding: 20rpx 0 80rpx 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
// 坠落动画配置变量 - 方便调整效果
|
||||
$fall-duration: 0.26s; // 动画总时长
|
||||
$initial-scale: 2.8; // 初始大小倍数
|
||||
$impact-scale: 0.9; // 撞击瞬间的压缩倍数
|
||||
$final-scale: 1; // 最终稳定大小
|
||||
$primary-color: #ffe271; // 文字颜色
|
||||
|
||||
.matching-success-text {
|
||||
margin-top: 10%;
|
||||
padding-left: 1rem;
|
||||
// 基础样式
|
||||
font-size: 74rpx;
|
||||
font-weight: bold;
|
||||
color: #ffe271;
|
||||
text-align: center;
|
||||
// 动画属性
|
||||
animation: fallDown $fall-duration ease-out forwards;
|
||||
|
||||
// 坠落动画关键帧
|
||||
@keyframes fallDown {
|
||||
0% {
|
||||
// 初始状态:高处坠落的起点
|
||||
transform: scale($initial-scale);
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
80% {
|
||||
// 撞击瞬间:略微压缩,增强冲击力
|
||||
transform: scale($impact-scale);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
100% {
|
||||
// 稳定状态:恢复正常大小
|
||||
transform: scale($final-scale);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
// 增强版:带震动效果的撞击(可选)
|
||||
&.with-vibration {
|
||||
animation: fallWithVibration $fall-duration cubic-bezier(0.21, 0.98, 0.6, 0.99) forwards;
|
||||
|
||||
@keyframes fallWithVibration {
|
||||
0% {
|
||||
transform: scale($initial-scale) rotate(0deg);
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
70% {
|
||||
transform: scale($impact-scale) rotate(2deg);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
85% {
|
||||
transform: scale($final-scale * 1.05) rotate(-1deg);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: scale($final-scale) rotate(0deg);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 可通过修改变量快速调整效果
|
||||
// 示例:更重的坠落效果
|
||||
.heavy-impact {
|
||||
$fall-duration: 0.3s;
|
||||
$initial-scale: 2.5;
|
||||
$impact-scale: 0.8;
|
||||
|
||||
animation: fallDown $fall-duration ease-out forwards;
|
||||
}
|
||||
|
||||
.matching-success-msg {
|
||||
margin-top: 20%;
|
||||
font-family: Alibaba-PuHuiTi, Alibaba-PuHuiTi;
|
||||
font-weight: normal;
|
||||
font-size: 74rpx;
|
||||
color: #ffffff;
|
||||
font-weight: 700;
|
||||
margin-bottom: 10%;
|
||||
}
|
||||
|
||||
/**匹配成功样式*/
|
||||
.matching-success-animation {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
height: 540rpx;
|
||||
position: relative;
|
||||
// overflow: hidden;
|
||||
.left {
|
||||
position: absolute;
|
||||
width: calc(59vw);
|
||||
left: -10rpx;
|
||||
top: 0%;
|
||||
z-index: 3;
|
||||
}
|
||||
.right {
|
||||
position: absolute;
|
||||
right: -10rpx;
|
||||
top: 18vw;
|
||||
width: calc(59vw);
|
||||
z-index: 2;
|
||||
}
|
||||
.img {
|
||||
width: 100%;
|
||||
}
|
||||
// 左侧元素回弹动画
|
||||
.animate-left {
|
||||
animation: leftCollision 0.24s ease-out forwards;
|
||||
}
|
||||
@keyframes leftCollision {
|
||||
0% {
|
||||
transform: translateX(-100%);
|
||||
} // 初始位置
|
||||
90% {
|
||||
transform: translateX(10rpx);
|
||||
} // 超过目标位置10rpx(冲刺)
|
||||
100% {
|
||||
transform: translateX(0);
|
||||
} // 回到目标位置(回弹)
|
||||
}
|
||||
|
||||
// 右侧元素回弹动画
|
||||
.animate-right {
|
||||
animation: rightCollision 0.24s ease-out forwards;
|
||||
}
|
||||
@keyframes rightCollision {
|
||||
0% {
|
||||
transform: translateX(100%);
|
||||
} // 初始位置
|
||||
90% {
|
||||
transform: translateX(-10rpx);
|
||||
} // 超过目标位置10rpx(冲刺)
|
||||
100% {
|
||||
transform: translateX(0);
|
||||
} // 回到目标位置(回弹)
|
||||
}
|
||||
|
||||
// 上面的双方头像
|
||||
.information-div-left,
|
||||
.information-div-right {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
.avatar-img-div {
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
border: 4rpx solid #ffffff;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
.img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
.name {
|
||||
font-size: 30rpx;
|
||||
margin-top: 20rpx;
|
||||
margin-bottom: 100rpx;
|
||||
font-weight: 600;
|
||||
font-size: 36rpx;
|
||||
color: #ffffff;
|
||||
}
|
||||
.org {
|
||||
font-weight: 400;
|
||||
font-size: 30rpx;
|
||||
color: #ffffff;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
width: 160rpx;
|
||||
}
|
||||
}
|
||||
.information-div-left {
|
||||
position: absolute;
|
||||
top: 0%;
|
||||
left: 0%;
|
||||
transform: translate(24%, -20%);
|
||||
}
|
||||
.information-div-right {
|
||||
position: absolute;
|
||||
right: 0%;
|
||||
top: 0%;
|
||||
transform: translate(-24%, -20%);
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,9 @@
|
||||
<!-- 3. 最后显示默认标题 -->
|
||||
<template v-else>{{ title }}</template>
|
||||
</view>
|
||||
<view v-if="msg" class="msg_div">
|
||||
{{ msg }}
|
||||
</view>
|
||||
<view class="button_div">
|
||||
<view class="button_item" v-for="item in buttonList" :style="item?.style" @click="click_button(item)">
|
||||
{{ item?.name || '' }}
|
||||
@@ -25,12 +28,14 @@
|
||||
dialogConfiguration: {
|
||||
type: Object,
|
||||
required: false
|
||||
}
|
||||
},
|
||||
|
||||
});
|
||||
const emit = defineEmits(['button_click']);
|
||||
|
||||
const title = ref('');
|
||||
const html = ref('');
|
||||
const msg = ref('');
|
||||
const buttonList = ref([]);
|
||||
const PopupRef = ref(null);
|
||||
// 点击按钮
|
||||
@@ -41,9 +46,10 @@
|
||||
const close = () => PopupRef.value?.close();
|
||||
const open = (dialogConfiguration) => {
|
||||
// 解构赋值更清晰
|
||||
const { title: t, html: h, buttonList: bl = [] } = dialogConfiguration || props.dialogConfiguration || {};
|
||||
const { title: t, html: h, msg: m, buttonList: bl = [] } = dialogConfiguration || props.dialogConfiguration || {};
|
||||
title.value = t || '';
|
||||
html.value = h || '';
|
||||
msg.value = m || '';
|
||||
buttonList.value = Array.isArray(bl) ? bl : [];
|
||||
|
||||
// 确保PopupRef存在再调用open
|
||||
@@ -62,7 +68,7 @@
|
||||
z-index: 1810;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.9);
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.popup_div {
|
||||
|
||||
@@ -143,7 +143,7 @@
|
||||
onUnmounted(() => {
|
||||
removeListener();
|
||||
});
|
||||
|
||||
|
||||
const open = (qnsId) => {
|
||||
feedbackInfo.qnsId = qnsId;
|
||||
openFeedback(true);
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<view class="talking-cont">
|
||||
<MarkdownPreview :mdString="mdText" />
|
||||
</view>
|
||||
<view class="talking-link" v-show="dataInfo.asrTime > 0">
|
||||
<view class="talking-link">
|
||||
<view class="link-cont-desc">语音转文字的耗时:{{ dataInfo.asrTime }}ms</view>
|
||||
<!-- <view class="link-cont-desc">请求的文字:{{ dataInfo.reqContent }}</view> -->
|
||||
<view class="link-cont-desc">请求内容的字符长度:{{ dataInfo.reqContSize }}</view>
|
||||
|
||||
@@ -138,7 +138,8 @@
|
||||
<image class="icon" src="@/static/images/index/navigation_examination.png"></image>
|
||||
<view class="title">考试中心</view>
|
||||
</view>
|
||||
<view class="item">
|
||||
|
||||
<view class="item" @click="common.navigateTo('/pages/competition/index')">
|
||||
<image class="icon" src="@/static/images/index/navigation_practice.png"></image>
|
||||
<view class="title">竞赛练习</view>
|
||||
</view>
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
<view class="fl1"></view>
|
||||
</view>
|
||||
<!-- 显示当前选中的徽章 -->
|
||||
<!-- <view class="dan" @click="changeBadge">
|
||||
<view class="dan" @click="changeBadge">
|
||||
<view class="dan_img">
|
||||
<image
|
||||
class="img_100"
|
||||
@@ -48,18 +48,18 @@
|
||||
></image>
|
||||
</view>
|
||||
<view class="dan_text">{{ badgeList[currentIndex].name }}</view>
|
||||
</view> -->
|
||||
</view>
|
||||
</view>
|
||||
<!-- 用户学习时间信息 -->
|
||||
<view class="study_information">
|
||||
<view class="item">
|
||||
<view class="item" @click="common.navigateTo('/pages/pointsAndRank/points')">
|
||||
<view class="top">我的积分</view>
|
||||
<view class="bottom">
|
||||
<uv-count-to :startVal="0" :endVal="0" :useEasing="true" ref="accmTaskCntRef"></uv-count-to>
|
||||
</view>
|
||||
</view>
|
||||
<view class="item-interval"></view>
|
||||
<view class="item">
|
||||
<view class="item" @click="common.navigateTo('/pages/pointsAndRank/rank')">
|
||||
<view class="top">徽章墙</view>
|
||||
<view class="bottom">
|
||||
<uv-count-to :startVal="0" :endVal="0" :useEasing="true" ref="accmTaskCntRef"></uv-count-to>
|
||||
@@ -101,7 +101,12 @@
|
||||
</view>
|
||||
<view class="cell_div">
|
||||
<uv-cell-group :border="false">
|
||||
<uv-cell title="问答演示" v-if="user_info.loginName === 'ADMIN'" :isLink="true" @click="common.navigateTo('/pages/example/dialog')"></uv-cell>
|
||||
<uv-cell
|
||||
title="问答演示"
|
||||
v-if="user_info.loginName === 'ADMIN'"
|
||||
:isLink="true"
|
||||
@click="common.navigateTo('/pages/example/dialog')"
|
||||
></uv-cell>
|
||||
<uv-cell
|
||||
title="消息通知"
|
||||
:isLink="true"
|
||||
|
||||
@@ -0,0 +1,265 @@
|
||||
<template>
|
||||
<z-paging
|
||||
ref="pagingRef"
|
||||
v-model="data_list"
|
||||
@query="queryList"
|
||||
class="scroll_div"
|
||||
empty-view-text="暂无积分记录"
|
||||
paging-class="z-paging-class"
|
||||
>
|
||||
<template #top>
|
||||
<view class="top-main-div">
|
||||
<view class="content">
|
||||
<view class="body-title">
|
||||
<view class="back_div" @click="common.navigateBack()">
|
||||
<view class="back-icon"></view>
|
||||
</view>
|
||||
<view>积分明细</view>
|
||||
</view>
|
||||
<view class="fl1"></view>
|
||||
<view class="my-points">
|
||||
<view class="msg">我的积分</view>
|
||||
<view class="score">
|
||||
<uv-count-to
|
||||
:startVal="startVal"
|
||||
:endVal="endVal"
|
||||
:useEasing="true"
|
||||
ref="countToRef"
|
||||
></uv-count-to>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<view class="scroll-Y">
|
||||
<view class="item_th">
|
||||
<view class="title">事项明细</view>
|
||||
<view class="time">时间</view>
|
||||
<view class="value">积分变化</view>
|
||||
</view>
|
||||
<view class="item" v-for="(item, index) in data_list">
|
||||
<view class="title ellipsis-text">
|
||||
{{ item.mattrDesc }}
|
||||
</view>
|
||||
<view class="time">
|
||||
{{ item.ctTime.substr(0, 16) }}
|
||||
</view>
|
||||
<view class="value" :class="Number(item.changeValue) >= 0 ? 'up' : 'down'">
|
||||
{{ item.changeValue }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</z-paging>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
// 竞赛列表
|
||||
import { ref, reactive, watch, onMounted } from 'vue';
|
||||
import { onLoad, onUnload } from '@dcloudio/uni-app';
|
||||
import useZpaging from '@/composables/useZpaging.js';
|
||||
import common from '@/common/common';
|
||||
import { queryPointsDetail, queryCurrentStatus } from '@/api/pointsAndRank.js';
|
||||
const startVal = ref(0);
|
||||
const endVal = ref(0);
|
||||
const countToRef = ref(null);
|
||||
const fetchFunction = (params) => {
|
||||
queryCurrentStatus().then(({ body }) => {
|
||||
const { currentPoints } = body;
|
||||
console.log('recurrentPointss', currentPoints);
|
||||
startVal.value = 9999;
|
||||
endVal.value = 99999;
|
||||
stdtTmLenRef.value.start();
|
||||
});
|
||||
return queryPointsDetail({ ...params });
|
||||
};
|
||||
const { pagingRef, queryList, data_list, search } = useZpaging({
|
||||
fetchFunction
|
||||
});
|
||||
|
||||
onLoad(() => {});
|
||||
onUnload(() => {});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
|
||||
.z-paging-class {
|
||||
background-color: #e0e3ef;
|
||||
::v-deep .zp-view-super {
|
||||
background-color: #ffffff;
|
||||
margin: 0 24rpx;
|
||||
height: 100%;
|
||||
border-radius: 30rpx 30rpx 0 0;
|
||||
}
|
||||
}
|
||||
.top-main-div {
|
||||
/* 宽度占满父容器 */
|
||||
width: 100%;
|
||||
/* 隐藏超出容器的背景图部分 */
|
||||
overflow: hidden;
|
||||
/* 使用 padding-top 实现 78:35 的宽高比(计算公式:35/78*100% ≈ 44.87%) */
|
||||
padding-top: 44.87%;
|
||||
/* 背景图设置,确保图片覆盖且不重复 */
|
||||
background-image: url('@/static/images/pointsAndRank/bg.png');
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
/* 若盒子内有内容,需用相对定位让内容脱离文档流 */
|
||||
position: relative;
|
||||
margin-bottom: -44rpx;
|
||||
.content {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.my-points {
|
||||
padding-bottom: 84rpx;
|
||||
padding-left: 46rpx;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
.msg {
|
||||
font-weight: 400;
|
||||
font-size: 26rpx;
|
||||
color: #ffffff;
|
||||
text-align: center;
|
||||
padding-bottom: 4rpx;
|
||||
}
|
||||
|
||||
.score {
|
||||
margin-left: 16rpx;
|
||||
width: 112px;
|
||||
::v-deep .uv-count-num {
|
||||
font-family: DINAlternate, DINAlternate !important;
|
||||
font-weight: bold !important;
|
||||
font-size: 77rpx !important;
|
||||
color: #ffffff !important;
|
||||
line-height: 77rpx !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.item_th {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
border-bottom: 4rpx solid #efefef;
|
||||
font-family: PingFangSC, PingFang SC;
|
||||
font-weight: 400;
|
||||
font-size: 26rpx;
|
||||
color: #999999;
|
||||
text-align: left;
|
||||
padding: 32rpx 38rpx 32rpx 26rpx;
|
||||
.title {
|
||||
flex: 1;
|
||||
}
|
||||
.time {
|
||||
min-width: max(150rpx, 42%);
|
||||
}
|
||||
.value {
|
||||
text-align: right;
|
||||
min-width: max(80rpx, 20%);
|
||||
}
|
||||
}
|
||||
.item {
|
||||
background: #ffffff;
|
||||
border-bottom: 2rpx solid #efefef;
|
||||
overflow: hidden;
|
||||
background-color: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 40rpx 38rpx 40rpx 26rpx;
|
||||
.title {
|
||||
font-weight: 700;
|
||||
font-size: 30rpx;
|
||||
color: #333333;
|
||||
flex: 1;
|
||||
text-align: left;
|
||||
}
|
||||
.time {
|
||||
font-family: ArialMT;
|
||||
font-size: 30rpx;
|
||||
color: #000000;
|
||||
text-align: left;
|
||||
min-width: max(150rpx, 42%);
|
||||
}
|
||||
.value {
|
||||
font-family: Arial, Arial;
|
||||
font-weight: normal;
|
||||
font-size: 30rpx;
|
||||
|
||||
text-align: right;
|
||||
font-weight: 600;
|
||||
min-width: max(80rpx, 20%);
|
||||
}
|
||||
.up {
|
||||
color: #ff8a2d;
|
||||
}
|
||||
.down {
|
||||
color: #48ae80;
|
||||
}
|
||||
}
|
||||
|
||||
.scroll-Y {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.body-title {
|
||||
width: 100%;
|
||||
height: 70rpx;
|
||||
font-size: 33rpx;
|
||||
font-weight: 500;
|
||||
color: #ffffff;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
margin-top: var(--status-bar-height);
|
||||
.delete_div {
|
||||
position: absolute;
|
||||
right: 20rpx;
|
||||
top: 17rpx;
|
||||
width: 50rpx;
|
||||
height: 50rpx;
|
||||
|
||||
.img {
|
||||
width: 34rpx;
|
||||
height: 34rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.back_div {
|
||||
position: absolute;
|
||||
left: 26rpx;
|
||||
top: 17rpx;
|
||||
.back-icon {
|
||||
position: relative;
|
||||
width: 50rpx;
|
||||
height: 50rpx;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.back-icon::before,
|
||||
.back-icon::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.back-icon::after {
|
||||
top: 25%;
|
||||
left: 25%;
|
||||
width: 40%;
|
||||
height: 40%;
|
||||
border-top: 4rpx solid #ffffff;
|
||||
border-left: 4rpx solid #ffffff;
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,257 @@
|
||||
<template>
|
||||
<z-paging
|
||||
ref="pagingRef"
|
||||
v-model="data_list"
|
||||
@query="queryList"
|
||||
class="scroll_div"
|
||||
:layout-only="true"
|
||||
empty-view-text="暂无积分记录"
|
||||
paging-class="z-paging-class"
|
||||
>
|
||||
<template #top>
|
||||
<view class="top-main-div">
|
||||
<view class="content">
|
||||
<view class="body-title">
|
||||
<view class="back_div" @click="common.navigateBack()">
|
||||
<view class="back-icon"></view>
|
||||
</view>
|
||||
<view>积分段位说明</view>
|
||||
</view>
|
||||
<view class="fl1"></view>
|
||||
<view class="my-rank">
|
||||
<view class="left">
|
||||
<view class="fl1"></view>
|
||||
<view class="note">当前段位:{{dataInfo.currentRankName}}</view>
|
||||
<view class="note">
|
||||
我的累计积分:
|
||||
<text class="score">{{dataInfo.currentPoints}}/{{dataInfo.countPoints}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="fl1"></view>
|
||||
<view class="right">
|
||||
<image-preview class="img_100" :src="dataInfo.ossAddr" mode="widthFix"></image-preview>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<view class="scroll-Y">
|
||||
<view class="item_th">
|
||||
<view class="title">段位</view>
|
||||
<view class="score">积分范围</view>
|
||||
<view class="value">标识</view>
|
||||
</view>
|
||||
<view class="item" v-for="(item, index) in data_list">
|
||||
<view class="title ellipsis-text">
|
||||
{{ item.rankName }}
|
||||
</view>
|
||||
<view class="score">{{ item.pointsStart }}~{{ item.pointsEnd }}</view>
|
||||
<view class="icon" :class="Number(item.changeValue) >= 0 ? 'up' : 'down'">
|
||||
<image-preview class="img_100" :src="item.ossAddr" mode="heightFix"></image-preview>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</z-paging>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
// 竞赛列表
|
||||
import { ref, reactive, watch, onMounted } from 'vue';
|
||||
import { onLoad, onUnload } from '@dcloudio/uni-app';
|
||||
import useZpaging from '@/composables/useZpaging.js';
|
||||
import common from '@/common/common';
|
||||
import { queryRankDetail, queryCurrentStatus } from '@/api/pointsAndRank.js';
|
||||
const dataInfo = reactive({
|
||||
countPoints: 0, // 累计积分 int
|
||||
currentPoints: 0, // 当前积分 int
|
||||
currentRankName: '', // 当前段位 String
|
||||
ossAddr: '', // 当前段位图片
|
||||
badgeNum: 0 // 徽章数 int
|
||||
});
|
||||
const fetchFunction = (params) => {
|
||||
queryCurrentStatus().then(({ body }) => {
|
||||
const { countPoints, currentPoints, currentRankName, badgeNum, ossAddr } = body;
|
||||
Object.assign(dataInfo, {
|
||||
countPoints,
|
||||
currentPoints,
|
||||
currentRankName,
|
||||
badgeNum,
|
||||
ossAddr,
|
||||
});
|
||||
});
|
||||
return queryRankDetail({ ...params });
|
||||
};
|
||||
const { pagingRef, queryList, data_list, search } = useZpaging({
|
||||
fetchFunction
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
pagingRef.value.reload();
|
||||
});
|
||||
onUnload(() => {});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.z-paging-class {
|
||||
background-color: #e0e3ef;
|
||||
::v-deep .zp-view-super {
|
||||
background-color: #ffffff;
|
||||
// margin: 0 24rpx;
|
||||
height: 100%;
|
||||
border-radius: 30rpx 30rpx 0 0;
|
||||
}
|
||||
}
|
||||
.top-main-div {
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
padding-top: calc(44.87% + var(--status-bar-height));
|
||||
background: linear-gradient(to right, #78238d, #5b25a0, #3b28b6);
|
||||
position: relative;
|
||||
margin-bottom: -44rpx;
|
||||
.content {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.my-rank {
|
||||
padding-bottom: 84rpx;
|
||||
padding-left: 46rpx;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
.left {
|
||||
.score {
|
||||
font-family: DINAlternate, DINAlternate;
|
||||
font-weight: bold;
|
||||
font-size: 33rpx;
|
||||
color: #ffffff;
|
||||
line-height: 38rpx;
|
||||
text-align: left;
|
||||
}
|
||||
.note {
|
||||
font-family: PingFangSC, PingFang SC;
|
||||
font-weight: 400;
|
||||
font-size: 25rpx;
|
||||
color: #ffffff;
|
||||
line-height: 35rpx;
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
.right {
|
||||
width: 124rpx;
|
||||
margin-right: 60rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
.item_th {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
border-bottom: 4rpx solid #efefef;
|
||||
font-family: PingFangSC, PingFang SC;
|
||||
font-weight: 400;
|
||||
font-size: 26rpx;
|
||||
color: #999999;
|
||||
text-align: left;
|
||||
padding: 30rpx 38rpx 30rpx 26rpx;
|
||||
.title {
|
||||
text-align: left;
|
||||
min-width: max(150rpx, 42%);
|
||||
}
|
||||
.score {
|
||||
flex: 1;
|
||||
// min-width: max(150rpx, 42%);/
|
||||
}
|
||||
.icon {
|
||||
// min-width: max(80rpx, 20%);
|
||||
}
|
||||
}
|
||||
.item {
|
||||
background: #ffffff;
|
||||
border-bottom: 2rpx solid #efefef;
|
||||
overflow: hidden;
|
||||
background-color: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 26rpx 38rpx 26rpx 26rpx;
|
||||
.title {
|
||||
font-weight: 700;
|
||||
font-size: 30rpx;
|
||||
color: #333333;
|
||||
text-align: left;
|
||||
min-width: max(150rpx, 42%);
|
||||
}
|
||||
.score {
|
||||
flex: 1;
|
||||
font-family: ArialMT;
|
||||
font-size: 30rpx;
|
||||
color: #000000;
|
||||
}
|
||||
.icon {
|
||||
height: 44rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.scroll-Y {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.body-title {
|
||||
width: 100%;
|
||||
height: 70rpx;
|
||||
font-size: 33rpx;
|
||||
font-weight: 500;
|
||||
color: #ffffff;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
margin-top: var(--status-bar-height);
|
||||
.delete_div {
|
||||
position: absolute;
|
||||
right: 20rpx;
|
||||
top: 17rpx;
|
||||
width: 50rpx;
|
||||
height: 50rpx;
|
||||
|
||||
.img {
|
||||
width: 34rpx;
|
||||
height: 34rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.back_div {
|
||||
position: absolute;
|
||||
left: 26rpx;
|
||||
top: 17rpx;
|
||||
.back-icon {
|
||||
position: relative;
|
||||
width: 50rpx;
|
||||
height: 50rpx;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.back-icon::before,
|
||||
.back-icon::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.back-icon::after {
|
||||
top: 25%;
|
||||
left: 25%;
|
||||
width: 40%;
|
||||
height: 40%;
|
||||
border-top: 4rpx solid #ffffff;
|
||||
border-left: 4rpx solid #ffffff;
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -114,7 +114,7 @@
|
||||
const storageTopicList = ref([]); // 所有题列表
|
||||
const popup_input_bottom = ref('0px');
|
||||
const questionNumber = ref(0); // 题号
|
||||
const systemInfo = uni.getSystemInfoSync();
|
||||
|
||||
|
||||
const topic = computed({
|
||||
get: () => topicList[questionNumber.value],
|
||||
@@ -747,7 +747,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.main_div {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@@ -67,16 +67,7 @@
|
||||
|
||||
const mascotName = computed(() => userInfo.value.mascotInfo?.mascotName || '');
|
||||
const sexOptions = GENDER;
|
||||
const anonymousOptions = [
|
||||
{
|
||||
value: 'y',
|
||||
label: '是'
|
||||
},
|
||||
{
|
||||
value: 'n',
|
||||
label: '否'
|
||||
}
|
||||
]; // 性别
|
||||
|
||||
|
||||
// 去选择百禄
|
||||
const gotoMascot = () => {
|
||||
|
||||
@@ -123,7 +123,7 @@
|
||||
"style": {
|
||||
"navigationBarTitleText": "错题本",
|
||||
"app-plus": {
|
||||
"titleNView": false
|
||||
"titleNView": false
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -246,7 +246,70 @@
|
||||
"titleNView": false
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/competition/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "竞赛列表页",
|
||||
"app-plus": {
|
||||
"titleNView": false
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/competition/matching",
|
||||
"style": {
|
||||
"navigationBarTitleText": "匹配页面",
|
||||
"app-plus": {
|
||||
"titleNView": false
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/competition/pk",
|
||||
"style": {
|
||||
"navigationBarTitleText": "pk页面",
|
||||
"disableSwipeBack": true,
|
||||
"app-plus": {
|
||||
"titleNView": false
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/competition/result",
|
||||
"style": {
|
||||
"navigationBarTitleText": "pk结果页面",
|
||||
"app-plus": {
|
||||
"titleNView": false
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/competition/ranking",
|
||||
"style": {
|
||||
"navigationBarTitleText": "pk排行榜",
|
||||
"app-plus": {
|
||||
"titleNView": false
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/pointsAndRank/points",
|
||||
"style": {
|
||||
"navigationBarTitleText": "积分变动明细",
|
||||
"app-plus": {
|
||||
"titleNView": false
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/pointsAndRank/rank",
|
||||
"style": {
|
||||
"navigationBarTitleText": "段位列表",
|
||||
"app-plus": {
|
||||
"titleNView": false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
]
|
||||
}
|
||||
@@ -3,11 +3,11 @@
|
||||
{
|
||||
"path": "pages/index/dialog",
|
||||
"style": {
|
||||
"navigationBarTitleText": "AI问答",
|
||||
"app-plus": {
|
||||
"titleNView": false,
|
||||
"animationType": "fade-in"
|
||||
}
|
||||
"navigationBarTitleText": "AI问答",
|
||||
"app-plus": {
|
||||
"titleNView": false,
|
||||
"animationType": "fade-in"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 830 KiB |
|
After Width: | Height: | Size: 312 KiB |
|
After Width: | Height: | Size: 262 KiB |
|
After Width: | Height: | Size: 230 KiB |
|
After Width: | Height: | Size: 212 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 75 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 174 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 146 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 136 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 114 KiB |
|
After Width: | Height: | Size: 172 KiB |
|
After Width: | Height: | Size: 112 KiB |
|
After Width: | Height: | Size: 66 KiB |
@@ -0,0 +1,20 @@
|
||||
// 声明图片文件模块
|
||||
declare module '*.jpg' {
|
||||
const src: string;
|
||||
export default src;
|
||||
}
|
||||
|
||||
declare module '*.jpeg' {
|
||||
const src: string;
|
||||
export default src;
|
||||
}
|
||||
|
||||
declare module '*.png' {
|
||||
const src: string;
|
||||
export default src;
|
||||
}
|
||||
|
||||
declare module '*.gif' {
|
||||
const src: string;
|
||||
export default src;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
// Vue 项目常用配置(根据实际版本调整)
|
||||
"moduleResolution": "NodeNext", // 或 "Node"
|
||||
"module": "NodeNext", // 与 moduleResolution 保持一致
|
||||
"target": "ES2022",
|
||||
"jsx": "preserve",
|
||||
"lib": ["ES2022", "DOM"],
|
||||
"baseUrl": ".", // 表示以 tsconfig.json 所在目录为基准
|
||||
"types": ["vue"], // 确保包含 vue 类型定义
|
||||
"paths": {
|
||||
"@/*": ["src/*"]
|
||||
}
|
||||
},
|
||||
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"]
|
||||
}
|
||||
@@ -1,8 +1,14 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import {
|
||||
defineConfig
|
||||
} from 'vite'
|
||||
import uni from '@dcloudio/vite-plugin-uni'
|
||||
// https://vitejs.dev/config/
|
||||
import path from 'path'
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
uni(),
|
||||
],
|
||||
})
|
||||
plugins: [uni()],
|
||||
// 新增服务器配置,指定启动端口
|
||||
server: {
|
||||
port: 5174,
|
||||
strictPort: true, // 可选:端口被占用时直接报错(避免自动切换端口)
|
||||
open: false // 可选:启动后自动打开浏览器(按需开启)
|
||||
}
|
||||
})
|
||||