Merge branch 'dev-0120' of http://25.13.9.101:9000/K17_AITS/tra-app into dev-0120

This commit is contained in:
杨航
2026-01-13 10:48:52 +08:00
16 changed files with 247 additions and 578 deletions
+1 -2
View File
@@ -7,8 +7,7 @@ ENV = '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 = 'https://aitstest.jlbank.com.cn:7002'
# VITE_APP_BASE_API_Url = 'https://aitstest.jlbank.com.cn:7002'
+1
View File
@@ -3,6 +3,7 @@
xiangyuanhua@126.com
Xiang@1987
你的 App 专用密码:wais-pyeh-cmww-zqvc
法人实体名称:BANK OF JILIN CO.LTD
田岩UDID:
00008101-001911401152001E
+5 -1
View File
@@ -66,6 +66,9 @@
.max_page {
min-height: 100vh;
}
.no-touch {
touch-action: none !important;
}
// #endif
.mr-10 {
@@ -176,4 +179,5 @@
margin-right: 8rpx;
margin-left: 2rpx;
}
</style>
</style>
+44 -37
View File
@@ -284,38 +284,38 @@ function isLogin() {
* @returns {string} 最终的额外高度值(带单位)
*/
export const getExtraHeight = () => {
// 所有常量移入函数内部定义,TARGET_DEVICE_MODEL 改为数组类型
const TARGET_DEVICE_MODEL = ['XT2321-2']; // 目标设备型号数组(摩托罗拉razr 40 Ultra
const EXTRA_HEIGHT_TARGET = '15rpx'; // 目标设备额外高度
const EXTRA_HEIGHT_DEFAULT = '2rpx'; // 默认额外高度
try {
// 1. 优先读取缓存
const cachedHeight = getValue('extra_height', '');
if (cachedHeight) {
console.log('缓存有值直接返回', cachedHeight);
return cachedHeight; // 缓存有值直接返回
}
// 2. 缓存无值时,获取设备信息
const deviceInfo = uni.getDeviceInfo();
// 校验设备信息有效性
if (!deviceInfo || !deviceInfo.deviceModel) {
throw new Error('设备信息获取失败');
}
// 3. 判断设备型号(数组包含判断,适配多型号)
const isTargetDevice = TARGET_DEVICE_MODEL.includes(deviceInfo.deviceModel);
const finalHeight = isTargetDevice ? EXTRA_HEIGHT_TARGET : EXTRA_HEIGHT_DEFAULT;
// 所有常量移入函数内部定义,TARGET_DEVICE_MODEL 改为数组类型
const TARGET_DEVICE_MODEL = ['XT2321-2']; // 目标设备型号数组(摩托罗拉razr 40 Ultra
const EXTRA_HEIGHT_TARGET = '15rpx'; // 目标设备额外高度
const EXTRA_HEIGHT_DEFAULT = '2rpx'; // 默认额外高度
try {
// 1. 优先读取缓存
const cachedHeight = getValue('extra_height', '');
if (cachedHeight) {
console.log('缓存有值直接返回', cachedHeight);
return cachedHeight; // 缓存有值直接返回
}
// 2. 缓存无值时,获取设备信息
const deviceInfo = uni.getDeviceInfo();
// 校验设备信息有效性
if (!deviceInfo || !deviceInfo.deviceModel) {
throw new Error('设备信息获取失败');
}
// 4. 缓存结果(后续复用
setValue('extra_height', finalHeight);
return finalHeight; // 返回计算后的高度
// 3. 判断设备型号(数组包含判断,适配多型号
const isTargetDevice = TARGET_DEVICE_MODEL.includes(deviceInfo.deviceModel);
const finalHeight = isTargetDevice ? EXTRA_HEIGHT_TARGET : EXTRA_HEIGHT_DEFAULT;
} catch (error) {
// 5. 异常兜底:返回默认值并缓存
console.warn('获取/设置额外高度失败:', error.message);
setValue('extra_height', EXTRA_HEIGHT_DEFAULT);
return EXTRA_HEIGHT_DEFAULT;
}
// 4. 缓存结果(后续复用)
setValue('extra_height', finalHeight);
return finalHeight; // 返回计算后的高度
} catch (error) {
// 5. 异常兜底:返回默认值并缓存
console.warn('获取/设置额外高度失败:', error.message);
setValue('extra_height', EXTRA_HEIGHT_DEFAULT);
return EXTRA_HEIGHT_DEFAULT;
}
};
@@ -327,20 +327,27 @@ export function setupKeyboardHeightListener(updateCallback) {
return () => {};
// #endif
// #ifdef APP-PLUS
// 获取系统信息
const systemInfo = uni.getSystemInfoSync();
// 计算安全区域底部高度
const safeAreaBottomHeight = systemInfo.screenHeight - systemInfo.safeArea.bottom;
// 校验回调函数类型,避免非函数传入导致报错
if (typeof updateCallback !== 'function') {
console.error('setupKeyboardHeightListener: updateCallback 必须是函数');
return () => {};
}
// 定义处理函数
const handleKeyboardHeightChange = (res) => {
// 获取系统信息
const systemInfo = uni.getSystemInfoSync();
console.log('systemInfo', systemInfo);
// 计算安全区域底部高度
const safeAreaBottomHeight = systemInfo.screenHeight - systemInfo.safeArea.bottom;
console.log('计算安全区域底部高度', safeAreaBottomHeight);
let keyboardHeight = res.height;
console.log('软键盘高度', keyboardHeight);
// 仅在iOS端补偿安全区域高度
if (systemInfo.platform === 'ios') {
keyboardHeight = Math.max(0, keyboardHeight - safeAreaBottomHeight); // 避免负数
keyboardHeight = Math.max(0, keyboardHeight); // 避免负数
}
console.log('keyboardHeight', keyboardHeight);
// 通过回调函数更新外部的响应式变量
updateCallback(keyboardHeight);
};
+62 -17
View File
@@ -11,7 +11,7 @@
<text class="tr">{{ item.gradeDimens }}</text>
<text class="td">{{ item.anlyGrade }}</text>
<view class="your_answer" v-if="item.dimensCode === '01'">
<rich-text :nodes="highlightedText" class="content" />
<rich-text v-if="missingKeywords.length !== keywordsLength" :nodes="highlightedText" class="content" />
<view class="mt-10" v-if="missingKeywords.length">
<text class="">未命中</text>
<text v-for="(keyword, index) in missingKeywords" :key="index" class="miss-keyword-item">
@@ -56,12 +56,15 @@
return optionErrorIcon();
}
});
const keywords = computed(() => {
if (!props.value.relKeyword) return [];
return props.value.relKeyword.split(/[,、/]/).map((key) => key.trim());
});
const keywordsLength = computed(() => {
if (!props.value.relKeyword) return 0;
return props.value.relKeyword.split(/[,、]/).map((key) => key.trim()).length;
});
const highlightedText = computed(() => {
// 如果没有关键词,直接返回原文本
if (!keywords.value.length) return '命中:' + props.anserResult;
@@ -120,6 +123,39 @@
return missing;
});
// 找出答案中存在的关键词
const hitKeywords = computed(() => {
const relKeyword = props.value.relKeyword;
if (!props.anserResult) {
return [];
}
// 步骤1:按顿号拆分关键词组
const keywordGroups = relKeyword.split('、');
const missing = [];
// 步骤2:遍历每个关键词组,检查是否存在任意一种说法
keywordGroups.forEach((group) => {
// 拆分同关键词的不同说法(/ 分隔)
const keywordVariants = group.split('/');
let isFound = false;
// 检查答案中是否包含任意一种说法
for (const variant of keywordVariants) {
// 可选:增加 trim() 忽略首尾空格,提升匹配容错
if (props.anserResult.trim().includes(variant.trim())) {
isFound = true;
break;
}
}
// 未找到则加入缺失列表
if (isFound) {
missing.push(group);
}
});
return missing;
});
const click_option = () => {
emit('click_option', props.analysisVo);
};
@@ -129,23 +165,22 @@
.mt-10 {
margin-top: 10rpx;
}
.analysis_div {
:deep(.highlight) {
color: #15b859;
}
}
.success {
background-color: #e7f8ed;
.td {
color: #15b859;
}
:deep(.highlight) {
color: #15b859;
}
}
.error {
background-color: #fce8e9;
.td {
color: #f5212d;
}
:deep(.highlight) {
color: #f5212d;
}
}
.your_answer {
@@ -153,10 +188,19 @@
text-decoration: underline;
}
}
.keyword-text {
color: #d70c18;
text-decoration: underline;
.hit-keyword-item{
.keyword-text {
color: #15b859;
text-decoration: underline;
}
}
.miss-keyword-item{
.keyword-text {
color: #d70c18;
text-decoration: underline;
}
}
.separator {
}
.analysis_div {
@@ -176,13 +220,14 @@
.dimension-line::before {
content: '';
position: absolute;
left: 0.5em; /* 对齐padding-left的起始位置 */
top: 1em; /* 垂直居中 */
transform: translateY(-50%);
width: 8px; /* 圆点大小(默认是4px左右,调大到8px) */
height: 8px; /* 和宽度一致,保证圆形 */
left: 0.5rem; /* 对齐padding-left的起始位置 */
top: 0.5rem;
// transform: translateY(-50%);
width: 16rpx; /* 圆点大小(默认是4px左右,调大到8px) */
height: 16rpx; /* 和宽度一致,保证圆形 */
border-radius: 50%; /* 圆形 */
background-color: #333; /* 圆点颜色,可自定义 */
}
.tr {
@@ -20,15 +20,16 @@
required: true
}
});
// 判断一下维度有没有关键词命中率这一项
const isKeywordsStatus = computed(() => props.value.evalSettingVos.some(res => res.dimensCode === '01'));
const keywords = computed(() => {
if (!props.value.relKeyword) return [];
return props.value.relKeyword.split(/[,、/]/).map((key) => key.trim());
});
const highlightedText = computed(() => {
// 如果没有关键词,直接返回原文本
if (!keywords.value.length) return props.anserResult;
if (!keywords.value.length || !isKeywordsStatus.value) return props.anserResult;
// 构建正则表达式,匹配所有关键词(不区分大小写)
// 对关键词进行转义,避免特殊字符影响正则
const escapedKeywords = keywords.value.map((keyword) => keyword.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'));
+8 -5
View File
@@ -1,5 +1,5 @@
<template>
<view class="item">
<view class="item" :class="{'no-touch':qnsTyp === 'ES' && !isDisabled && ['examination', 'practice', 'mistake'].includes(props.mode)}">
<view class="top">
<view class="type">{{ subject_type_text }}</view>
<view class="score" v-if="['settlement', 'examination', 'pk_in'].includes(props.mode)">
@@ -116,7 +116,7 @@
<referenceAnswer
v-if="qnsTyp === 'ES'"
:value="subject_data.itemVos[0]"
:anserResult="subject_data.anserResult"
:anserResult="subject_data.itemVos[0]?.itemAnswer"
></referenceAnswer>
<view class="analysis_note" v-if="props.mode !== 'pk_in'">
试题解析:{{ subject_data?.analyContent }}
@@ -190,7 +190,9 @@
const wrapperRef = ref(null);
const contentRef = ref(null);
const judgeResultStatus = computed(() => props.item.judgeResult === 'P');
const isDisabled = computed(() => {
return props.item?.es_status !== '' && props.item?.es_status !== undefined;
});
// 不是错题本就默认不折叠,错题本默认折叠
const animationState = ref(props.mode !== 'mistake' ? true : false);
const animationHeight = ref(props.mode !== 'mistake' ? '' : '0px');
@@ -380,7 +382,6 @@
left: 0;
/* 初始状态非激活文本透明且轻微下移 */
opacity: 0;
// transform: translateY(15rpx);
/* 添加过渡动画 */
transition: all 0.2s ease-out;
/* 确保文本占据空间一致 */
@@ -490,7 +491,9 @@
display: flex;
flex-direction: column;
padding-bottom: 40rpx;
user-select: none !important; /* 禁用文本选择 */
-webkit-user-select: none !important; /* iOS兼容 */
-webkit-touch-callout: none !important; /* 禁用iOS长按菜单 */
.top {
display: flex;
align-items: center;
@@ -1,412 +0,0 @@
<template>
<uni-popup ref="popup" mask-background-color="rgba(0,0,0,0.9)">
<view class="popup-content" @touchmove.stop catchmove="true" @touchmove.stop.prevent="handleTouchMove">
<view class="fl1"></view>
<view class="max-div">
<view class="festival-text-pic-div">
<image
class="festival-text-img"
mode="widthFix"
src="@/static/images/pointsAndRank/festival-text.png"
></image>
</view>
<image
class="festival-bg-up-div"
mode="widthFix"
src="@/static/images/pointsAndRank/festival-bg-up.png"
></image>
<view class="max-area-div">
<!-- 右上角百禄图标 -->
<view class="festival-special-mascot">
<image-preview
class="festival-special-mascot-img"
mode="widthFix"
:src="holidayInfo.ossAddr"
></image-preview>
</view>
<!-- 几个特殊节日的特殊背景 -->
<view class="festival-special-bg" v-if="holidayInfo.backgroundOssAddr">
<image-preview
class="festival-special-bg-img"
mode="widthFix"
:src="holidayInfo.backgroundOssAddr"
></image-preview>
</view>
<!-- 顶部的字随机还是大额 -->
<view class="festival-text-div">{{ holidayInfo.holidayDesc }}</view>
<view class="festival-main-div">
<image
class="festival-main-img"
mode="widthFix"
src="@/static/images/pointsAndRank/festival-main.png"
></image>
<view class="festival-main-text">
<view class="festival-main-title">
{{ done.tipText }}
</view>
<view class="festival-main-number-div">
<text class="festival-main-number">
{{ score }}
</text>
<text class="festival-main-number-text">积分</text>
</view>
</view>
</view>
<view class="festival-button-div" @click="startLottery()">{{ done.buttonText }}</view>
</view>
<view class="close-div" @click="close(false)"></view>
</view>
<view class="fl1"></view>
</view>
</uni-popup>
</template>
<script setup lang="ts">
import type { HolidayInfo, CompleteCallback, StartLotteryCallback } from './types/holiday';
import { RewardType, AnimationStatus } from './types/holiday';
import { ref, computed, reactive } from 'vue';
import { optionErrorIcon, optionSuccessIcon } from '@/common/imgSvg';
import { obtainRewardRandom } from '@/api/pointsAndRank';
import common from '@/common/common';
const countToRef = ref(null);
const popup = ref(null);
const animationLoading = ref<AnimationStatus>(AnimationStatus.UNSTARTED);
const done = computed(() =>
holidayInfo.rewardType === RewardType.RANDOM_POINT
? {
tipText: '最高可获',
buttonText: animationLoading.value === AnimationStatus.COMPLETED ? '开心收下' : '立即抽取'
}
: { tipText: '恭喜获得', buttonText: '开心收下' }
);
// 显示的分数
const score = ref(10);
let lotteryTimer: number | null = null;
const emits = defineEmits(['checkInFun']);
// 开始抽奖
const startLottery = async () => {
// 固定积分,或者随机积分但是已经抽全完毕,再次点击按钮就是关闭
if (holidayInfo.rewardType === RewardType.FIXED_POINT || animationLoading.value === AnimationStatus.COMPLETED) {
close(true);
return;
}
// 正在抽取中防止重复点击
if (animationLoading.value === AnimationStatus.LOADING) return;
animationLoading.value = AnimationStatus.LOADING;
// 访问接口获取结果
if (lotteryTimer) clearInterval(lotteryTimer);
startLotteryCallback({
holidayCode: holidayInfo.holidayCode,
successCb: (body) => {
// const { body } = await obtainRewardRandom({ holidayCode: holidayInfo.holidayCode });
const finalScore = body.val;
// 记录已完成的循环圈数
let completedLoops = 0;
// 1. 数值范围(可自定义)
const LOTTERY_MIN = body.start; // 最小值
const LOTTERY_MAX = body.end; // 最大值
// 2. 循环圈数
const LOOP_TIMES = finalScore - LOTTERY_MIN > 10 ? 1 : 2;
// 3. 跳动速度(ms/次,越大越慢)
const JUMP_SPEED = 80;
// 3. 核心:循环指定圈数后,最后一轮停在目标数字
lotteryTimer = setInterval(() => {
// 先判断:是否已完成指定圈数 + 当前轮次能精准到目标数字
if (completedLoops >= LOOP_TIMES) {
if (score.value === finalScore) {
clearInterval(lotteryTimer!);
lotteryTimer = null;
animationLoading.value = AnimationStatus.COMPLETED;
return;
}
// 最后一轮:继续递增(不重置)
score.value += 1;
} else {
// 未完成指定圈数:正常循环(到max重置,计数+1)
score.value += 1;
// 当数值到max时,代表完成1圈
if (score.value >= LOTTERY_MAX) {
completedLoops += 1;
score.value = LOTTERY_MIN; // 重置为最小值,开始下一圈
}
}
}, JUMP_SPEED);
},
failCb: (res) => {
console.log('报错');
}
});
};
const handleTouchMove = (e) => {
e.stopPropagation();
e.preventDefault();
};
// 节日奖励信息响应式对象
const holidayInfo = reactive<HolidayInfo>({
// 假日编码
holidayCode: '',
// 是否存在节日奖励(true:有奖励 false:无奖励)
rewardFlag: false,
// 奖励类型(枚举限定:1-固定积分 2-随机积分)
rewardType: RewardType.RANDOM_POINT,
// 文案
holidayDesc: '',
// 奖励分数(字符串类型,兼容不同格式的积分值)
rewardPoints: 0,
// 可以获得的最高分
rangeEnd: 0,
// 可以获得的最低分
rangeStart: 0,
// 奖励获取标识(true:已获取 false:未获取)
obtainFlag: false,
// 文案图片的OSS存储key(用于图片上传/读取标识)
ossKey: '',
// 文案图片的OSS访问地址(图片完整URL)
ossAddr: '',
// 背景图片的OSS存储key(用于图片上传/读取标识)
backgroundOssKey: '',
// 背景图片的OSS访问地址(图片完整URL)
backgroundOssAddr: ''
});
let completeCallback: CompleteCallback | undefined; // 关闭弹窗的回调
let startLotteryCallback: StartLotteryCallback | undefined; // 抽奖的回调
// 退出
const close = (status: boolean): void => {
uni.showTabBar({
success() {
popup.value.close();
console.log('点击退出,执行回调函数');
typeof completeCallback === 'function' &&
completeCallback({
status
});
}
});
};
const open = (
holidayBody: any,
lotteryCb: StartLotteryCallback = () => {},
completeCb: CompleteCallback = () => {}
): void => {
startLotteryCallback = lotteryCb; // 抽奖的回调
completeCallback = completeCb; // 关闭弹窗的回调
Object.assign(holidayInfo, holidayBody);
// if (!holidayInfo.rewardFlag || holidayInfo.obtainFlag) {
if (!holidayInfo.rewardFlag) {
// 如果当前没有节日窗口,立刻返回回调函数
completeCallback({ status: false });
return;
}
// 设置初始得分
if (holidayInfo.rewardType === RewardType.RANDOM_POINT) {
score.value = holidayInfo.rangeEnd;
} else {
score.value = holidayInfo.rewardPoints;
}
animationLoading.value = AnimationStatus.UNSTARTED;
uni.hideTabBar({
success() {
popup.value.open();
}
});
};
defineExpose({ open, close });
</script>
<style scoped lang="scss">
.max-area-div {
width: 520rpx;
height: 542rpx;
background-image: url('@/static/images/pointsAndRank/festival-bg.png');
background-size: 100%;
border-radius: 0 0 60rpx 60rpx;
position: relative;
// .festival-tip-div {
// z-index: 20;
// position: relative;
// margin-left: 16rpx;
// margin-bottom: -16rpx;
// .festival-tip-img {
// margin-top: 30rpx;
// height: 56rpx;
// }
// }
.festival-text-div {
position: relative;
margin-left: 25rpx;
z-index: 60;
margin-top: 28rpx;
color: #ffffff;
font-style: normal;
font-weight: 600;
font-size: 58rpx;
color: #fffae8;
letter-spacing: 0.05em;
line-height: 77rpx;
text-shadow: 0px 4px 8px #d6061b;
text-align: left;
font-style: italic;
transform: skewX(2deg);
}
.festival-main-div {
// margin-top: 8rpx;
z-index: 20;
position: relative;
width: 530rpx;
height: 270rpx;
.festival-main-img {
margin-left: 16rpx;
width: 530rpx;
position: absolute;
left: 0;
top: 0;
}
.festival-main-text {
position: absolute;
left: 40rpx;
top: 50rpx;
width: 150rpx;
// background-color:red;
.festival-main-title {
font-weight: 600;
font-size: 34rpx;
color: #b24325;
line-height: 46rpx;
text-align: right;
}
.festival-main-number-div {
margin-top: 10rpx;
font-family: DINAlternate, DINAlternate;
color: #b24325;
line-height: 64rpx;
margin-right: 8rpx;
text-align: right;
white-space: nowrap;
.festival-main-number {
font-size: 64rpx;
font-weight: bold;
}
.festival-main-number-text {
font-size: 26rpx;
white-space: nowrap;
}
}
}
}
.festival-button-div {
position: relative;
z-index: 20;
width: 392rpx;
height: 108rpx;
margin: 0 auto;
background-image: url('@/static/images/pointsAndRank/festival-button.png');
background-size: 100%;
background-repeat: no-repeat;
font-weight: 600;
font-size: 38rpx;
color: #b24325;
line-height: 108rpx;
text-align: center;
}
.festival-special-bg {
width: 520rpx;
height: 542rpx;
overflow: hidden;
position: absolute;
left: 0;
bottom: 0;
border-radius: 0 0 60rpx 60rpx;
z-index: 10;
.festival-special-bg-img {
position: absolute;
left: 0;
bottom: 0;
width: 100%;
}
}
.festival-special-mascot {
z-index: 50;
position: absolute;
right: -36rpx;
top: 70rpx;
transform-origin: left bottom;
transform: translateY(-100%);
.festival-special-mascot-img {
width: 180rpx;
}
}
}
.festival-text-pic-div {
width: 100%;
.festival-text-img {
width: 400rpx;
}
}
.festival-bg-up-div {
width: 580rpx;
margin-bottom: -14rpx;
z-index: 5;
}
.popup-content {
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
padding: calc(10rpx + 2%) 0;
padding: 20rpx 0;
}
.max-div {
width: 600rpx;
border-radius: 38rpx;
position: relative;
padding: 26rpx;
margin-top: var(--status-bar-height);
margin-bottom: calc(180rpx + 15%);
display: flex;
flex-direction: column;
align-items: center;
}
.close-div {
// 基础样式:设置按钮大小、圆形、边框等
margin-top: 50rpx;
position: relative; // 为伪类定位做准备
width: 62rpx; // 圆圈直径,可根据需求调整
height: 62rpx;
border: 4rpx solid #b9b9b9; // 圆圈边框
border-radius: 50%; // 变成正圆
box-sizing: border-box; // 保证边框不影响整体大小
// 伪类通用样式:十字的基础线条
&::before,
&::after {
content: ''; // 伪类必须有content
position: absolute; // 绝对定位居中
top: 50%;
left: 50%;
width: 24rpx; // 十字线条长度,可调整
height: 4rpx; // 十字线条粗细,可调整
background-color: #b9b9b9; // 十字颜色
transform: translate(-50%, -50%); // 居中对齐
}
// 第一条线旋转45度
&::before {
transform: translate(-50%, -50%) rotate(45deg);
}
// 第二条线旋转-45度,组合成×
&::after {
transform: translate(-50%, -50%) rotate(-45deg);
}
}
</style>
+63 -65
View File
@@ -16,14 +16,6 @@
src="@/static/images/pointsAndRank/festival-bg-up.png"
></image>
<view class="max-area-div">
<!-- 右上角百禄图标 -->
<view class="festival-special-mascot">
<image-preview
class="festival-special-mascot-img"
mode="widthFix"
:src="holidayInfo.ossAddr"
></image-preview>
</view>
<!-- 几个特殊节日的特殊背景 -->
<view class="festival-special-bg" v-if="holidayInfo.backgroundOssAddr">
<image-preview
@@ -32,26 +24,32 @@
:src="holidayInfo.backgroundOssAddr"
></image-preview>
</view>
<!-- 顶部的字随机还是大额 -->
<view class="festival-text-div">{{ holidayInfo.holidayDesc }}</view>
<!-- 顶部的字-->
<view class="festival-main-div">
<!-- 右上角百禄图标 -->
<view class="festival-special-mascot">
<image-preview
class="festival-special-mascot-img"
mode="widthFix"
:src="holidayInfo.ossAddr"
></image-preview>
</view>
<view class="festival-text-div">{{ holidayInfo.holidayDesc }}</view>
<image
class="festival-main-img"
mode="widthFix"
src="@/static/images/pointsAndRank/festival-main.png"
src="@/static/images/pointsAndRank/gift.png"
></image>
<view class="festival-main-text">
<view class="festival-main-title">
{{ done.tipText }}
</view>
<view class="festival-main-number-div">
<text class="festival-main-number">
{{ score }}
</text>
<text class="festival-main-number-text">积分</text>
{{ score }}积分
</view>
</view>
</view>
<view class="festival-button-div" @click="startLottery()">{{ done.buttonText }}</view>
</view>
<view class="close-div" @click="close(false)"></view>
@@ -75,7 +73,7 @@
const done = computed(() =>
holidayInfo.rewardType === RewardType.RANDOM_POINT
? {
tipText: '最高可获',
tipText: animationLoading.value === AnimationStatus.COMPLETED ? '恭喜获得' : '最高可获',
buttonText: animationLoading.value === AnimationStatus.COMPLETED ? '开心收下' : '立即抽取'
}
: { tipText: '恭喜获得', buttonText: '开心收下' }
@@ -197,8 +195,8 @@
completeCallback = completeCb; // 关闭弹窗的回调
Object.assign(holidayInfo, holidayBody);
// if (!holidayInfo.rewardFlag || holidayInfo.obtainFlag) {
if (!holidayInfo.rewardFlag) {
if (!holidayInfo.rewardFlag || holidayInfo.obtainFlag) {
// if (!holidayInfo.rewardFlag) {
// 如果当前没有节日窗口,立刻返回回调函数
completeCallback({ status: false });
return;
@@ -238,68 +236,67 @@
// height: 56rpx;
// }
// }
.festival-text-div {
position: relative;
margin-left: 25rpx;
z-index: 60;
margin-top: 28rpx;
color: #ffffff;
font-style: normal;
font-weight: 600;
font-size: 58rpx;
color: #fffae8;
letter-spacing: 0.05em;
line-height: 77rpx;
text-shadow: 0px 4px 8px #d6061b;
text-align: left;
font-style: italic;
transform: skewX(2deg);
}
.festival-main-div {
// margin-top: 8rpx;
z-index: 20;
position: relative;
width: 530rpx;
height: 270rpx;
width: 444rpx;
height: 292rpx;
background: linear-gradient(0deg, #fce87e 0%, #fff298 38.9%, #ffffd4 100%);
box-shadow: 0px 4 8px 0px #e13520;
border-radius: 18rpx;
background: linear-gradient(180deg, rgba(255, 255, 255, 0.38), rgba(255, 255, 255, 0.5)) 2 2;
margin: 36rpx auto 0 auto;
.festival-main-img {
margin-left: 16rpx;
width: 530rpx;
width: 328rpx;
position: absolute;
left: 0;
top: 0;
right: -54rpx;
bottom: -80rpx;
}
.festival-main-text {
position: absolute;
left: 40rpx;
top: 50rpx;
left: 38rpx;
bottom: 10rpx;
width: 150rpx;
// background-color:red;
.festival-main-title {
font-weight: 600;
font-size: 34rpx;
color: #b24325;
line-height: 46rpx;
text-align: right;
font-weight: normal;
font-size: 30rpx;
color: #B24325;
line-height: 40rpx;
text-align: center;
}
.festival-main-number-div {
margin-top: 10rpx;
font-family: DINAlternate, DINAlternate;
color: #b24325;
line-height: 64rpx;
margin-top: 16rpx;
margin-bottom: 42rpx;
margin-right: 8rpx;
text-align: right;
white-space: nowrap;
.festival-main-number {
font-size: 64rpx;
font-weight: bold;
}
.festival-main-number-text {
font-size: 26rpx;
white-space: nowrap;
}
font-weight: 600;
font-size: 30rpx;
color: #B24325;
line-height: 25rpx;
text-align: center;
}
}
.festival-text-div {
position: relative;
z-index: 60;
width: 358rpx;
height: 136rpx;
padding-top: 0;
margin: 0 auto;
font-weight: 600;
font-size: 42rpx;
color: #B24325;
line-height: 62rpx;
text-align: center;
overflow: hidden;
display: flex;
flex-direction: column;
justify-content: center;
}
}
.festival-button-div {
position: relative;
@@ -307,13 +304,14 @@
width: 360rpx;
height: 80rpx;
margin: 0 auto;
margin-top: 80rpx;
background-image: url('@/static/images/pointsAndRank/festival-button.png');
background-size: 100%;
background-repeat: no-repeat;
font-weight: 600;
text-align: center;
font-size: 32rpx;
color: #B24325;
color: #b24325;
line-height: 80rpx;
}
@@ -336,8 +334,8 @@
.festival-special-mascot {
z-index: 50;
position: absolute;
right: -36rpx;
top: 70rpx;
right: -66rpx;
top: 40rpx;
transform-origin: left bottom;
transform: translateY(-100%);
.festival-special-mascot-img {
+11 -7
View File
@@ -1,5 +1,5 @@
<template>
<view class="main_div max_page">
<view class="main_div max_page no-touch">
<nav-bar :is_seat="true"></nav-bar>
<view class="nav-div">
<view class="title ellipsis-text">PK中</view>
@@ -93,11 +93,14 @@
<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"
ref="touchBtnRef"
@uploadVoice="touchBtnSubmit('voice',$event)"
@submitAnswer="touchBtnSubmit('text',$event)"
:isLoading="touchIsDisabled"
loadingText="只能进行一条回答"
:adjustPosition="false"
:isDisabled="false"
/>
</view>
</view>
@@ -117,7 +120,8 @@
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 TouchBtn from '@/components/examination/touchBtn.vue';
import TouchBtn from '@/pages/course/components/touchBtn.vue';
import common from '@/common/common';
import { setPageCache, formatSeconds, getPageCache, setupKeyboardHeightListener, formatName } from '@/common/common';
import { commonUploadVoiceFile } from '@/api/common.js';
@@ -326,7 +330,7 @@
// 录音组件提交
const touchBtnSubmit = (type, submitObj) => {
const topic = topicList[questionNumber.value];
touchBtnRef.value?.clearinputText(); // 清除发送框数据
// touchBtnRef.value?.clearinputText(); // 清除发送框数据
if (type === 'voice') {
if (topic.es_status === '00') return;
topic.es_status = '00'; // 00转圈
+14 -7
View File
@@ -1,5 +1,5 @@
<template>
<view class="main_div max_page">
<view class="main_div max_page no-touch">
<nav-bar :is_seat="true"></nav-bar>
<view class="nav-div">
<view class="title ellipsis-text" @click="hand_in_paper_button_click()">
@@ -99,10 +99,13 @@
<TouchBtn
class="talk-btns"
ref="touchBtnRef"
@submit="touchBtnSubmit"
disabledText="只能进行一条回答"
:isLoading="!answerIsOver"
:isDisabled="touchIsDisabled"
@uploadVoice="touchBtnSubmit('voice',$event)"
@submitAnswer="touchBtnSubmit('text',$event)"
:isLoading="touchIsDisabled"
loadingText="只能进行一条回答"
:adjustPosition="false"
:isDisabled="false"
:answerMethod="answerMethod"
/>
</view>
</view>
@@ -157,7 +160,8 @@
import Feedback from './components/feedback.vue';
import Dialog from './components/dialog.vue';
import Subject from '@/components/examination/subject.vue';
import TouchBtn from '@/components/examination/touchBtn.vue';
// import TouchBtn from '@/components/examination/touchBtn.vue';
import TouchBtn from '@/pages/course/components/touchBtn.vue';
import { ref, reactive, computed, onMounted, nextTick } from 'vue';
import { onLoad, onBackPress } from '@dcloudio/uni-app';
import common from '@/common/common';
@@ -172,6 +176,7 @@
const popupRef = ref(null);
const touchBtnRef = ref(null);
const countDownRef = ref(null);
const answerMethod = ref('01');
let examinationStartTime = 0; // 考试开始时间
let examinationAnswerCacheKey;
const style_button_1 = {
@@ -306,7 +311,7 @@
// 录音按钮提交
const touchBtnSubmit = (type, submitObj) => {
const topic = topicList[questionNumber.value];
touchBtnRef.value?.clearinputText(); // 清除发送框数据
// touchBtnRef.value?.clearinputText(); // 清除发送框数据
if (type === 'voice') {
if (topic.es_status == '00') return;
topic.es_status = '00'; // 00转圈
@@ -389,6 +394,8 @@
paperData.flagQuery = examination.flagQuery || 'Y';
paperData.flagQueryDetail = examination.flagQueryDetail || 'Y';
mode = paperData.examId ? 'PAPERS' : 'CRS'; // 课程考试CRS,考试中心考试PAPERS
answerMethod.value = examination.answerMethod ?? '01'
console.log('answerMethod', answerMethod.value);
// 设置缓存的键的名称
examinationAnswerCacheKey = 'examinationAnswerCache' + paperData.execId;
+23 -6
View File
@@ -1,5 +1,5 @@
<template>
<view class="main_div max_page">
<view class="main_div max_page no-touch">
<nav-bar :is_seat="true"></nav-bar>
<view class="nav-div">
<view class="title ellipsis-text">
@@ -64,14 +64,26 @@
</swiper-item>
</swiper>
</view>
<view class="fixed-box font_pf" :style="{ marginBottom: popup_input_bottom }">
<view class="touch-btn-div" :class="{ show: showTouchBtn }">
<TouchBtn
<!-- <TouchBtn
ref="touchBtnRef"
class="talk-btns"
@submit="touchBtnSubmit"
disabledText="只能进行一条回答"
:isDisabled="touchIsDisabled"
/> -->
<TouchBtn
class="talk-btns"
ref="touchBtnRef"
@uploadVoice="touchBtnSubmit('voice',$event)"
@submitAnswer="touchBtnSubmit('text',$event)"
:isLoading="touchIsDisabled"
loadingText="只能进行一条回答"
:adjustPosition="false"
:isDisabled="false"
:answerMethod="answerMethod"
/>
</view>
</view>
@@ -90,7 +102,8 @@
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 TouchBtn from '@/components/examination/touchBtn.vue';
import TouchBtn from '@/pages/course/components/touchBtn.vue';
import common from '@/common/common';
import { setPageCache, formatSeconds, getPageCache, setupKeyboardHeightListener } from '@/common/common';
import { commonUploadVoiceFile } from '@/api/common.js';
@@ -103,12 +116,15 @@
const feedbackRef = ref(null);
const dialogRef = ref(null);
const touchBtnRef = ref(null);
const answerMethod = ref('01');
const practiceTime = ref(0); // 当前练习时间
let practiceStartTime = 0; // 练习开始时间
let practiceTimeTimer = null; // 练习计时器
let leaveDuration = 0; // 当前总计离开时间
let leaveStartTime = 0; // 离开开始时间
const mode = ref('practice'); // 考试 examination 练习practice
const systemInfo = uni.getSystemInfoSync();
const paperData = reactive({
exrId: '',
crsId: '',
@@ -301,7 +317,7 @@
// 录音组件提交
const touchBtnSubmit = (type, submitObj) => {
const topic = topicList[questionNumber.value];
touchBtnRef.value?.clearinputText(); // 清除发送框数据
// touchBtnRef.value?.clearinputText(); // 清除发送框数据
if (type === 'voice') {
if (topic.es_status === '00') return;
topic.es_status = '00'; // 00转圈
@@ -363,6 +379,8 @@
es_status: '', // 预设一下问答题的状态,'' 空为没有 00 转圈 01 播放,其他暂定
my_answer: []
}));
answerMethod.value = practice.answerMethod ?? '01'
console.log('answerMethod', answerMethod.value);
addProblem();
// 记录练习起始时间
practiceStartTime = new Date().getTime();
@@ -476,7 +494,6 @@
<style scoped lang="scss">
$bg-margin-left: 30rpx;
.popup_title_text {
color: red;
}
@@ -769,7 +786,7 @@
flex-direction: column;
background: linear-gradient(to top, #3480ff, #0066ff);
/* 确保背景占满整个视口高度 */
min-height: 100vh;
// min-height: 100vh;
margin: 0;
}
</style>
@@ -13,15 +13,6 @@
<subject :item="item" mode="mistake" :isPreview="true" :clearResult="false"></subject>
</view>
</view>
<!-- <view class="max_page detail-main">
<scroll-view :scroll-y="true" class="scroll-Y" :show-scrollbar="false" @scrolltolower="scrolltolower"> -->
<!-- <view class="content" v-for="(item, index) in data_list">
<subject :item="item" mode="mistake" :isPreview="true" :clearResult="false"></subject>
</view> -->
<!-- <list-no-data v-if="total === 0 && status == 'nomore'">暂无错题</list-no-data> -->
<!-- <uv-load-more v-if="total !== 0" :status="status" loadmore-text="轻轻上拉加载" :height="30"></uv-load-more> -->
<!-- </scroll-view>
</view> -->
<template #bottom>
<view class="fixed-box" v-if="show_fixed_button_statue"></view>
</template>
+11 -7
View File
@@ -1,5 +1,5 @@
<template>
<view class="main_div max_page">
<view class="main_div max_page no-touch">
<nav-bar :is_seat="true"></nav-bar>
<view class="nav-div">
<view class="title ellipsis-text">
@@ -64,11 +64,14 @@
<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"
ref="touchBtnRef"
@uploadVoice="touchBtnSubmit('voice',$event)"
@submitAnswer="touchBtnSubmit('text',$event)"
:isLoading="touchIsDisabled"
loadingText="只能进行一条回答"
:adjustPosition="false"
:isDisabled="false"
/>
</view>
</view>
@@ -85,7 +88,8 @@
import Feedback from '@/pages/examination/components/feedback.vue';
import Dialog from '@/pages/examination/components/dialog.vue';
import Subject from '@/components/examination/subject.vue';
import TouchBtn from '@/components/examination/touchBtn.vue';
// import TouchBtn from '@/components/examination/touchBtn.vue';
import TouchBtn from '@/pages/course/components/touchBtn.vue';
import common from '@/common/common';
import { getPageCache, setupKeyboardHeightListener } from '@/common/common';
import { commonUploadVoiceFile } from '@/api/common.js';
@@ -288,7 +292,7 @@
// 录音组件提交
const touchBtnSubmit = (type, submitObj) => {
const topic = topicList[questionNumber.value];
touchBtnRef.value?.clearinputText(); // 清除发送框数据
// touchBtnRef.value?.clearinputText(); // 清除发送框数据
console.log('录音组件提交');
if (type === 'voice') {
if (topic.es_status == '00') return;
Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB