This commit is contained in:
阿梦 2026-05-28 16:32:43 +08:00
commit d13f75ddc0
9 changed files with 321 additions and 170 deletions

2
.npmrc Normal file
View File

@ -0,0 +1,2 @@
node-linker=hoisted
shamefully-hoist=true

19
project.config.json Normal file
View File

@ -0,0 +1,19 @@
{
"description": "uni-app 微信小程序工程配置,请用微信开发者工具打开本项目根目录",
"miniprogramRoot": "dist/dev/mp-weixin/",
"compileType": "miniprogram",
"appid": "wxa5522671f30c5891",
"projectname": "灵犀学",
"setting": {
"urlCheck": false,
"es6": true,
"postcss": false,
"minified": true,
"newFeature": true,
"bigPackageSizeSupport": true,
"ignoreUploadUnusedFiles": false,
"minifyWXML": true
},
"libVersion": "3.4.4",
"condition": {}
}

View File

@ -0,0 +1,18 @@
{
"description": "项目私有配置,仅本地生效",
"projectname": "灵犀学",
"setting": {
"compileHotReLoad": true
},
"condition": {
"miniprogram": {
"list": [
{
"name": "家长首页",
"pathName": "pages/parent/home/index",
"query": ""
}
]
}
}
}

View File

@ -57,15 +57,7 @@
"ignoreUploadUnusedFiles" : false "ignoreUploadUnusedFiles" : false
}, },
"usingComponents" : true, "usingComponents" : true,
"packOptions" : { "libVersion" : "3.4.4"
"ignore" : [],
"include" : [
{
"type" : "folder",
"value" : "uni_modules/qiun-data-charts"
}
]
}
}, },
"mp-alipay" : { "mp-alipay" : {
"usingComponents" : true "usingComponents" : true

View File

@ -94,6 +94,7 @@
}, },
"style": { "style": {
"navigationBarTitleText": "答题", "navigationBarTitleText": "答题",
"navigationStyle": "custom",
"disableScroll": true, "disableScroll": true,
"pageOrientation": "landscape", "pageOrientation": "landscape",
"app-plus": { "app-plus": {
@ -101,6 +102,7 @@
"allowsBounceVertical": "NO" "allowsBounceVertical": "NO"
}, },
"mp-weixin": { "mp-weixin": {
"navigationStyle": "custom",
"pageOrientation": "landscape" "pageOrientation": "landscape"
} }
} }

View File

@ -21,8 +21,8 @@
</view> </view>
<!-- 主题目 --> <!-- 主题目 -->
<view class="q-title"> <view v-if="stemText" class="q-title">
<rich-text :nodes="filterTitleWithoutImages(data?.titleMu || data?.title)" /> <rich-text :nodes="filterTitleWithoutImages(stemText)" />
</view> </view>
<!-- 题目图片 --> <!-- 题目图片 -->
@ -391,7 +391,7 @@ const toggleLeftExpand = () => {
/* ============== 题目图片提取 ============== */ /* ============== 题目图片提取 ============== */
const titleImages = computed(() => { const titleImages = computed(() => {
const title = props.data?.titleMu || props.data?.title || ''; const title = stemText.value || '';
const pidTitle = props.data?.pidTitle || ''; const pidTitle = props.data?.pidTitle || '';
const allTitle = pidTitle + title; const allTitle = pidTitle + title;
const imgRegex = /<img[^>]*\s*src=["']([^"']+)["'][^>]*\/?>/gi; const imgRegex = /<img[^>]*\s*src=["']([^"']+)["'][^>]*\/?>/gi;
@ -429,12 +429,32 @@ const filterTitleWithoutImages = (title?: string, cidx?: number | string) => {
return t; return t;
}; };
const parseJsonArray = (raw: any) => {
if (Array.isArray(raw)) return raw;
if (typeof raw !== 'string') return [];
try {
const parsed = JSON.parse(raw);
return Array.isArray(parsed) ? parsed : [];
} catch {
return [];
}
};
const stemText = computed(() => {
const data = props.data;
if (!data) return '';
if (data.stemType === 3) {
return data.stemHtml || data.titleMu || data.title || data.stem || '';
}
return data.stemHtml || data.titleMu || data.title || data.stem || '';
});
/* ============== 答案 ============== */ /* ============== 答案 ============== */
const submitAnswer = ref(''); const submitAnswer = ref('');
const submitAnswerPic = ref(''); const submitAnswerPic = ref('');
watch( watch(
() => props.data?.id, () => props.data?.id || props.data?.itemId,
() => { () => {
submitAnswer.value = props.data?.submitAnswer || ''; submitAnswer.value = props.data?.submitAnswer || '';
submitAnswerPic.value = props.data?.submitAnswerPic || ''; submitAnswerPic.value = props.data?.submitAnswerPic || '';
@ -726,17 +746,22 @@ watch(
/* ============== 选项 ============== */ /* ============== 选项 ============== */
const optionList = computed(() => { const optionList = computed(() => {
const data = props.data; const data = props.data;
let raw = const optionHtml = parseJsonArray(data?.optionHtml);
data?.optionsMu != null let raw = optionHtml.length
? optionHtml
: data?.optionsMu != null
? data.optionsMu ? data.optionsMu
: data?.options != null : data?.options != null
? data.options ? data.options
: data?.optionList != null
? data.optionList
: null; : null;
if (typeof raw === 'string') { if (typeof raw === 'string') {
try { raw = JSON.parse(raw); } catch { raw = null; } try { raw = JSON.parse(raw); } catch { raw = null; }
} }
const list = Array.isArray(raw) ? raw : raw ? [raw] : []; const normalized = Array.isArray(raw) ? (normalizeOptionsFromOptionList(raw) ?? raw) : raw ? [raw] : [];
const list = Array.isArray(normalized) ? normalized : [];
if (list.length === 0) return []; if (list.length === 0) return [];
return list.map((item: any, idx: number) => { return list.map((item: any, idx: number) => {
@ -744,7 +769,7 @@ const optionList = computed(() => {
if (typeof item === 'string') { if (typeof item === 'string') {
value = String(item || ''); value = String(item || '');
} else { } else {
const v = item?.value ?? item?.optionValue ?? item; const v = item?.html ?? item?.value ?? item?.optionValue ?? item?.content ?? '';
value = v != null && v !== '' ? String(v) : ''; value = v != null && v !== '' ? String(v) : '';
} }
value = fixMathSymbolsInHtml(value); value = fixMathSymbolsInHtml(value);
@ -764,10 +789,16 @@ const fillBlankNum = computed(() => props.data?.fillBlankNum || 0);
/* ============== 阅读 / 完形 ============== */ /* ============== 阅读 / 完形 ============== */
function toSimpleOptions(list: any[]) { function toSimpleOptions(list: any[]) {
return list.map((value: any, idx: number) => ({ return list.map((item: any, idx: number) => {
let value = item;
if (typeof item === 'object' && item !== null) {
value = item.html || item.value || item.optionValue || item.content || '';
}
return {
label: String.fromCharCode(65 + idx), label: String.fromCharCode(65 + idx),
value: value ?? '', value: value ?? '',
})); };
});
} }
function normalizeOptionsFromOptionList(optionList: any[]) { function normalizeOptionsFromOptionList(optionList: any[]) {
@ -790,8 +821,25 @@ function normalizeOptionsFromOptionList(optionList: any[]) {
const rawParsedOptions = computed(() => { const rawParsedOptions = computed(() => {
const data = props.data; const data = props.data;
if (data?.stemType === 3) {
const stems = parseJsonArray(data.stemSqs);
const opts = parseJsonArray(data.optionSqs);
const maxLen = Math.max(stems.length, opts.length);
if (maxLen === 0) return [];
return Array.from({ length: maxLen }, (_, idx) => ({
stem: stems[idx] || '',
options: Array.isArray(opts[idx]) ? toSimpleOptions(opts[idx]) : [],
}));
}
const optionHtml = parseJsonArray(data?.optionHtml);
if (optionHtml.length) {
return [optionHtml.map((item: any) => item?.html || item?.value || item?.optionValue || '')];
}
let raw = data?.optionsMu != null ? data.optionsMu let raw = data?.optionsMu != null ? data.optionsMu
: data?.options != null ? data.options : null; : data?.options != null ? data.options
: data?.optionList != null ? data.optionList : null;
if (typeof raw === 'string') { if (typeof raw === 'string') {
try { raw = JSON.parse(raw); } catch { raw = null; } try { raw = JSON.parse(raw); } catch { raw = null; }
} }
@ -819,7 +867,7 @@ const yueDuList = computed(() => {
return rawParsedOptions.value.map((item: any, idx: number) => { return rawParsedOptions.value.map((item: any, idx: number) => {
const rawSubOpts = Array.isArray(item.options) ? item.options : []; const rawSubOpts = Array.isArray(item.options) ? item.options : [];
const subOpts = rawSubOpts.map((opt: any, oIdx: number) => { const subOpts = rawSubOpts.map((opt: any, oIdx: number) => {
let v = typeof opt === 'string' ? opt : (opt?.value ?? opt?.optionValue ?? ''); let v = typeof opt === 'string' ? opt : (opt?.html ?? opt?.value ?? opt?.optionValue ?? opt?.content ?? '');
v = v != null ? String(v) : ''; v = v != null ? String(v) : '';
v = fixMathSymbolsInHtml(v); v = fixMathSymbolsInHtml(v);
v = processFormula(v, failedFormulaUrls.value); v = processFormula(v, failedFormulaUrls.value);
@ -908,15 +956,19 @@ const isMultiSelected = (key: string) => submitAnswer.value.includes(key);
const selectMultiOption = (key: string) => { const selectMultiOption = (key: string) => {
if (props.reportFlag) return; if (props.reportFlag) return;
let answer = submitAnswer.value; const answers = submitAnswer.value
if (answer.includes(key)) { .split(',')
answer = answer.replace(key, ''); .flatMap((item) => item.split(''))
.map((item) => item.trim())
.filter(Boolean);
const idx = answers.indexOf(key);
if (idx !== -1) {
answers.splice(idx, 1);
} else { } else {
answer += key; answers.push(key);
} }
answer = answer.split('').sort().join(''); submitAnswer.value = answers.sort().join(',');
submitAnswer.value = answer; emit('submit', { submitAnswer: submitAnswer.value });
emit('submit', { submitAnswer: answer });
}; };
/* ============== 判断 ============== */ /* ============== 判断 ============== */
@ -1090,7 +1142,7 @@ onUnmounted(() => {
display: flex; display: flex;
position: relative; position: relative;
background: #ffffff; background: #ffffff;
border-radius: 32rpx; border-radius: 18rpx;
overflow: hidden; overflow: hidden;
box-shadow: box-shadow:
0 12rpx 32rpx rgba(99, 102, 241, 0.12), 0 12rpx 32rpx rgba(99, 102, 241, 0.12),
@ -1100,10 +1152,10 @@ onUnmounted(() => {
/* 中间分隔条 */ /* 中间分隔条 */
.q-divider { .q-divider {
position: absolute; position: absolute;
left: 50%; left: 56%;
top: 0; top: 0;
bottom: 0; bottom: 0;
width: 60rpx; width: 48rpx;
transform: translateX(-50%); transform: translateX(-50%);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -1113,14 +1165,14 @@ onUnmounted(() => {
pointer-events: none; pointer-events: none;
&.at-right { &.at-right {
left: calc(100% - 30rpx); left: calc(100% - 24rpx);
} }
} }
.q-divider-line { .q-divider-line {
flex: 1; flex: 1;
width: 4rpx; width: 3rpx;
margin-top: 36rpx; margin-top: 24rpx;
background: repeating-linear-gradient( background: repeating-linear-gradient(
to bottom, to bottom,
#c7d2fe, #c7d2fe,
@ -1133,15 +1185,15 @@ onUnmounted(() => {
.q-fold-btn { .q-fold-btn {
pointer-events: auto; pointer-events: auto;
margin: 12rpx 0 24rpx; margin: 8rpx 0 16rpx;
padding: 10rpx 6rpx; padding: 7rpx 4rpx;
background: linear-gradient(180deg, #818cf8, #4f46e5); background: linear-gradient(180deg, #818cf8, #4f46e5);
border-radius: 14rpx; border-radius: 10rpx;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
gap: 6rpx; gap: 4rpx;
box-shadow: box-shadow:
0 6rpx 12rpx rgba(79, 70, 229, 0.35), 0 6rpx 12rpx rgba(79, 70, 229, 0.35),
inset 0 -3rpx 0 rgba(0, 0, 0, 0.12); inset 0 -3rpx 0 rgba(0, 0, 0, 0.12);
@ -1151,7 +1203,7 @@ onUnmounted(() => {
} }
text { text {
font-size: 16rpx; font-size: 13rpx;
color: #ffffff; color: #ffffff;
writing-mode: vertical-lr; writing-mode: vertical-lr;
letter-spacing: 2rpx; letter-spacing: 2rpx;
@ -1160,10 +1212,10 @@ onUnmounted(() => {
} }
.fold-arrow { .fold-arrow {
width: 14rpx; width: 11rpx;
height: 14rpx; height: 11rpx;
border-left: 3rpx solid #ffffff; border-left: 2rpx solid #ffffff;
border-bottom: 3rpx solid #ffffff; border-bottom: 2rpx solid #ffffff;
transform: rotate(45deg); transform: rotate(45deg);
transition: transform 200ms ease; transition: transform 200ms ease;
@ -1174,32 +1226,32 @@ onUnmounted(() => {
/* 左侧 */ /* 左侧 */
.q-left { .q-left {
width: 50%; width: 58%;
height: 100%; height: 100%;
box-sizing: border-box; box-sizing: border-box;
transition: width 300ms ease; transition: width 300ms ease;
&.expanded { &.expanded {
width: calc(100% - 60rpx); width: calc(100% - 48rpx);
} }
} }
.q-left-inner { .q-left-inner {
padding: 20rpx 50rpx 20rpx 20rpx; padding: 10rpx 34rpx 10rpx 12rpx;
} }
.q-meta { .q-meta {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 12rpx; gap: 6rpx;
margin-bottom: 16rpx; margin-bottom: 6rpx;
} }
.q-badge { .q-badge {
display: inline-flex; display: inline-flex;
align-items: baseline; align-items: baseline;
gap: 2rpx; gap: 2rpx;
padding: 6rpx 16rpx; padding: 3rpx 9rpx;
background: linear-gradient(180deg, #818cf8, #4f46e5); background: linear-gradient(180deg, #818cf8, #4f46e5);
color: #ffffff; color: #ffffff;
border-radius: 999rpx; border-radius: 999rpx;
@ -1208,28 +1260,28 @@ onUnmounted(() => {
inset 0 -3rpx 0 rgba(0, 0, 0, 0.12); inset 0 -3rpx 0 rgba(0, 0, 0, 0.12);
.q-badge-num { .q-badge-num {
font-size: 20rpx; font-size: 15rpx;
font-weight: 800; font-weight: 800;
} }
.q-badge-divider { .q-badge-divider {
font-size: 14rpx; font-size: 11rpx;
opacity: 0.6; opacity: 0.6;
} }
.q-badge-total { .q-badge-total {
font-size: 16rpx; font-size: 12rpx;
opacity: 0.85; opacity: 0.85;
} }
} }
.q-type { .q-type {
padding: 4rpx 12rpx; padding: 2rpx 8rpx;
background: #eef2ff; background: #eef2ff;
border-radius: 999rpx; border-radius: 999rpx;
text { text {
font-size: 18rpx; font-size: 13rpx;
color: #4f46e5; color: #4f46e5;
font-weight: 600; font-weight: 600;
} }
@ -1237,10 +1289,10 @@ onUnmounted(() => {
.q-pid, .q-pid,
.q-title { .q-title {
font-size: 26rpx; font-size: 18rpx;
color: #312e81; color: #312e81;
line-height: 1.7; line-height: 1.45;
margin-bottom: 12rpx; margin-bottom: 5rpx;
:deep(image) { :deep(image) {
max-width: 100%; max-width: 100%;
@ -1271,12 +1323,12 @@ onUnmounted(() => {
} }
.q-pid { .q-pid {
padding: 16rpx 20rpx; padding: 7rpx 10rpx;
background: #f5f7ff; background: #f5f7ff;
border-radius: 16rpx; border-radius: 12rpx;
border-left: 6rpx solid #818cf8; border-left: 4rpx solid #818cf8;
color: #4338ca; color: #4338ca;
font-size: 24rpx; font-size: 17rpx;
} }
.q-images { .q-images {
@ -1540,7 +1592,7 @@ onUnmounted(() => {
/* 右侧答题 */ /* 右侧答题 */
.q-right { .q-right {
width: 50%; width: 42%;
height: 100%; height: 100%;
box-sizing: border-box; box-sizing: border-box;
transition: width 300ms ease, opacity 200ms ease; transition: width 300ms ease, opacity 200ms ease;
@ -1555,7 +1607,7 @@ onUnmounted(() => {
} }
.q-right-inner { .q-right-inner {
padding: 20rpx 20rpx 20rpx 50rpx; padding: 10rpx 12rpx 10rpx 34rpx;
} }
/* 批改结果 */ /* 批改结果 */
@ -1607,23 +1659,23 @@ onUnmounted(() => {
/* 答题区 */ /* 答题区 */
.q-answer-area { .q-answer-area {
margin-bottom: 12rpx; margin-bottom: 8rpx;
} }
/* 选项 */ /* 选项 */
.opt-list { .opt-list {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 14rpx; gap: 7rpx;
} }
.opt { .opt {
display: flex; display: flex;
align-items: center; align-items: center;
padding: 16rpx 18rpx; padding: 7rpx 9rpx;
background: #ffffff; background: #ffffff;
border-radius: 20rpx; border-radius: 12rpx;
border: 4rpx solid #e0e7ff; border: 2rpx solid #e0e7ff;
transition: all 200ms ease; transition: all 200ms ease;
box-shadow: box-shadow:
0 4rpx 8rpx rgba(99, 102, 241, 0.08), 0 4rpx 8rpx rgba(99, 102, 241, 0.08),
@ -1634,26 +1686,26 @@ onUnmounted(() => {
} }
.opt-key { .opt-key {
width: 48rpx; width: 30rpx;
height: 48rpx; height: 30rpx;
background: #f5f7ff; background: #f5f7ff;
border-radius: 50%; border-radius: 50%;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
font-size: 24rpx; font-size: 16rpx;
font-weight: 800; font-weight: 800;
color: #6366f1; color: #6366f1;
margin-right: 16rpx; margin-right: 7rpx;
flex-shrink: 0; flex-shrink: 0;
transition: all 200ms ease; transition: all 200ms ease;
} }
.opt-value { .opt-value {
flex: 1; flex: 1;
font-size: 24rpx; font-size: 17rpx;
color: #312e81; color: #312e81;
line-height: 1.6; line-height: 1.45;
:deep(image) { max-width: 100%; height: auto; } :deep(image) { max-width: 100%; height: auto; }
:deep(.formula-text) { :deep(.formula-text) {
@ -1702,21 +1754,21 @@ onUnmounted(() => {
.judge-list { .judge-list {
display: flex; display: flex;
justify-content: center; justify-content: center;
gap: 28rpx; gap: 12rpx;
padding: 12rpx 0; padding: 5rpx 0;
} }
.judge { .judge {
flex: 1; flex: 1;
max-width: 240rpx; max-width: 150rpx;
padding: 28rpx 16rpx; padding: 12rpx 8rpx;
background: #ffffff; background: #ffffff;
border-radius: 28rpx; border-radius: 15rpx;
border: 4rpx solid #e0e7ff; border: 2rpx solid #e0e7ff;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
gap: 12rpx; gap: 8rpx;
transition: all 200ms ease; transition: all 200ms ease;
box-shadow: box-shadow:
0 6rpx 12rpx rgba(99, 102, 241, 0.1), 0 6rpx 12rpx rgba(99, 102, 241, 0.1),
@ -1727,14 +1779,14 @@ onUnmounted(() => {
} }
.judge-icon { .judge-icon {
width: 72rpx; width: 42rpx;
height: 72rpx; height: 42rpx;
border-radius: 50%; border-radius: 50%;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
svg { width: 56rpx; height: 56rpx; } svg { width: 32rpx; height: 32rpx; }
&.correct { &.correct {
background: linear-gradient(180deg, #4ade80, #16a34a); background: linear-gradient(180deg, #4ade80, #16a34a);
@ -1748,7 +1800,7 @@ onUnmounted(() => {
} }
text { text {
font-size: 26rpx; font-size: 18rpx;
font-weight: 700; font-weight: 700;
color: #312e81; color: #312e81;
} }
@ -1763,7 +1815,7 @@ onUnmounted(() => {
.fill-area { .fill-area {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 16rpx; gap: 10rpx;
} }
.fill-item { .fill-item {
@ -1774,22 +1826,22 @@ onUnmounted(() => {
.fill-label { .fill-label {
flex-shrink: 0; flex-shrink: 0;
padding: 4rpx 14rpx; padding: 3rpx 10rpx;
background: linear-gradient(135deg, #eef2ff, #e0e7ff); background: linear-gradient(135deg, #eef2ff, #e0e7ff);
border-radius: 999rpx; border-radius: 999rpx;
font-size: 22rpx; font-size: 17rpx;
font-weight: 700; font-weight: 700;
color: #4f46e5; color: #4f46e5;
} }
.fill-input { .fill-input {
flex: 1; flex: 1;
height: 64rpx; height: 46rpx;
padding: 0 20rpx; padding: 0 14rpx;
background: #f5f7ff; background: #f5f7ff;
border: 3rpx solid #e0e7ff; border: 3rpx solid #e0e7ff;
border-radius: 16rpx; border-radius: 12rpx;
font-size: 24rpx; font-size: 18rpx;
color: #312e81; color: #312e81;
&:focus { &:focus {
@ -1806,20 +1858,20 @@ onUnmounted(() => {
.upload-area { .upload-area {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 12rpx; gap: 8rpx;
} }
.upload-tip { .upload-tip {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 8rpx; gap: 8rpx;
padding: 12rpx 16rpx; padding: 6rpx 9rpx;
background: linear-gradient(135deg, #fef3c7, #fde68a); background: linear-gradient(135deg, #fef3c7, #fde68a);
border-radius: 16rpx; border-radius: 10rpx;
.tip-icon { .tip-icon {
width: 28rpx; width: 22rpx;
height: 28rpx; height: 22rpx;
flex-shrink: 0; flex-shrink: 0;
svg { width: 100%; height: 100%; } svg { width: 100%; height: 100%; }
@ -1827,7 +1879,7 @@ onUnmounted(() => {
text { text {
flex: 1; flex: 1;
font-size: 20rpx; font-size: 15rpx;
color: #92400e; color: #92400e;
line-height: 1.5; line-height: 1.5;
} }
@ -1836,14 +1888,14 @@ onUnmounted(() => {
.pic-list { .pic-list {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
gap: 16rpx; gap: 10rpx;
} }
.pic-item { .pic-item {
position: relative; position: relative;
width: 160rpx; width: 90rpx;
height: 160rpx; height: 90rpx;
border-radius: 16rpx; border-radius: 12rpx;
overflow: hidden; overflow: hidden;
background: #f5f7ff; background: #f5f7ff;
box-shadow: box-shadow:
@ -1872,9 +1924,9 @@ onUnmounted(() => {
} }
.add-btn { .add-btn {
width: 160rpx; width: 90rpx;
height: 160rpx; height: 90rpx;
border-radius: 16rpx; border-radius: 12rpx;
background: #f5f7ff; background: #f5f7ff;
border: 3rpx dashed #c7d2fe; border: 3rpx dashed #c7d2fe;
display: flex; display: flex;
@ -1924,9 +1976,9 @@ onUnmounted(() => {
} }
.upload-btn { .upload-btn {
height: 160rpx; height: 84rpx;
background: linear-gradient(180deg, #818cf8, #4f46e5); background: linear-gradient(180deg, #818cf8, #4f46e5);
border-radius: 24rpx; border-radius: 14rpx;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
@ -1938,14 +1990,14 @@ onUnmounted(() => {
inset 0 -4rpx 0 rgba(0, 0, 0, 0.15); inset 0 -4rpx 0 rgba(0, 0, 0, 0.15);
.upload-camera { .upload-camera {
width: 56rpx; width: 30rpx;
height: 56rpx; height: 30rpx;
svg { width: 100%; height: 100%; } svg { width: 100%; height: 100%; }
} }
text { text {
font-size: 22rpx; font-size: 16rpx;
font-weight: 700; font-weight: 700;
letter-spacing: 2rpx; letter-spacing: 2rpx;
} }

View File

@ -129,6 +129,60 @@ const initialIdx = ref(0);
const resourceType = computed(() => params.value.resourceType || RESOURCE_TYPE_HOMEWORK); const resourceType = computed(() => params.value.resourceType || RESOURCE_TYPE_HOMEWORK);
const normalizePaperList = (list: any, markUnLook = false) => {
if (!Array.isArray(list)) return [];
if (!markUnLook) return list;
return list.map((item: any, idx: number) => ({
...item,
unLook: idx > 0,
}));
};
const normalizeAnswerPic = (value: any) => String(value || '')
.split(',')
.map((url) => String(url || '').replace(/[`]/g, '').replace(/http:\/\//gi, 'https://').trim())
.filter(Boolean)
.join(',');
const isUploadImageQuestion = (item: any) => {
const typeText = [
item?.titleChannelTypeName,
item?.channelTypeName,
item?.typeName,
item?.titleTypeName,
].filter(Boolean).join(',');
return /上传|拍照/.test(typeText);
};
const extractPicLinksFromAnswer = (answer: any) => {
const raw = String(answer || '');
if (!raw) return '';
const links = raw.match(/https?:\/\/[^\s,]+/g) || [];
return normalizeAnswerPic(links.join(','));
};
const getSubmitAnswerPic = (item: any) => {
const answerPic = normalizeAnswerPic(item?.submitAnswerPic);
if (answerPic) return answerPic;
if (!isUploadImageQuestion(item)) return '';
return extractPicLinksFromAnswer(item?.submitAnswer);
};
const getQuestionKey = (item: any) => item?.id || item?.itemId || item?.jobStuTittleId || '';
const normalizeCurrentMultiAnswer = () => {
const cur = paperList.value[activeIdx.value];
if (!cur || cur.titleChannelTypeName !== '多选题') return;
const raw = String(cur.submitAnswer || '');
cur.submitAnswer = raw
.split(',')
.flatMap((item) => item.split(''))
.map((item) => item.trim())
.filter(Boolean)
.sort()
.join(',');
};
const title = computed(() => { const title = computed(() => {
const name = paperInfo.value.paperName; const name = paperInfo.value.paperName;
if (name) { if (name) {
@ -185,11 +239,13 @@ const switchQuestion = async (idx?: number) => {
} }
if (idx !== undefined) { if (idx !== undefined) {
if (!reportFlag.value && resourceType.value === RESOURCE_TYPE_HOMEWORK) { if (!reportFlag.value && resourceType.value === RESOURCE_TYPE_HOMEWORK) {
normalizeCurrentMultiAnswer();
await saveAnswer(); await saveAnswer();
} }
activeIdx.value = idx; activeIdx.value = idx;
} else if (activeIdx.value < paperList.value.length - 1) { } else if (activeIdx.value < paperList.value.length - 1) {
if (!reportFlag.value && resourceType.value === RESOURCE_TYPE_HOMEWORK) { if (!reportFlag.value && resourceType.value === RESOURCE_TYPE_HOMEWORK) {
normalizeCurrentMultiAnswer();
await saveAnswer(); await saveAnswer();
} }
activeIdx.value++; activeIdx.value++;
@ -227,7 +283,7 @@ const saveAnswer = async () => {
answer: cur.submitAnswer || '', answer: cur.submitAnswer || '',
answerPic: cur.submitAnswerPic || '', answerPic: cur.submitAnswerPic || '',
costTime: (paperInfo.value.costTime || 0) * 1000, costTime: (paperInfo.value.costTime || 0) * 1000,
itemId: cur.itemId || cur.id, itemId: getQuestionKey(cur),
recordId: params.value.recordId, recordId: params.value.recordId,
}); });
} catch (err) { } catch (err) {
@ -254,12 +310,13 @@ const submitTrain = async () => {
submitLoading.value = true; submitLoading.value = true;
uni.showLoading({ title: '提交中...', mask: true }); uni.showLoading({ title: '提交中...', mask: true });
try { try {
normalizeCurrentMultiAnswer();
await saveAnswer(); await saveAnswer();
await submitExam({ await submitExam({
answerDtoList: paperList.value.map((item) => ({ answerDtoList: paperList.value.map((item) => ({
itemId: item.itemId || item.id, itemId: getQuestionKey(item),
answer: item.submitAnswer || '', answer: item.submitAnswer || '',
answerPic: item.submitAnswerPic || '', answerPic: getSubmitAnswerPic(item),
})), })),
costTime: (paperInfo.value.costTime || 0) * 1000, costTime: (paperInfo.value.costTime || 0) * 1000,
recordId: params.value.recordId, recordId: params.value.recordId,
@ -303,7 +360,7 @@ const initReport = async () => {
reportFlag: 1, reportFlag: 1,
}); });
paperInfo.value = res.data; paperInfo.value = res.data;
paperList.value = res.data.subjectTitleVoList || []; paperList.value = normalizePaperList(res.data?.titleVoList || res.data?.subjectTitleVoList);
}; };
const initNewTrain = async () => { const initNewTrain = async () => {
@ -312,11 +369,9 @@ const initNewTrain = async () => {
if (paperInfo.value.costTime) { if (paperInfo.value.costTime) {
paperInfo.value.costTime = Math.floor(paperInfo.value.costTime / 1000); paperInfo.value.costTime = Math.floor(paperInfo.value.costTime / 1000);
} }
paperList.value = (res.data?.subjectTitleVoList || res.subjectTitleVoList || []).map( paperList.value = normalizePaperList(
(item: any, idx: number) => ({ paperInfo.value?.titleVoList || paperInfo.value?.subjectTitleVoList || [],
...item, true,
unLook: idx > 0,
}),
); );
}; };
@ -353,6 +408,9 @@ const init = async () => {
} }
const target = Math.min(initialIdx.value, paperList.value.length - 1); const target = Math.min(initialIdx.value, paperList.value.length - 1);
activeIdx.value = Math.max(0, target); activeIdx.value = Math.max(0, target);
if (!reportFlag.value && paperList.value[activeIdx.value]) {
paperList.value[activeIdx.value].unLook = false;
}
} catch (err: any) { } catch (err: any) {
console.error('[doWork] init err', err); console.error('[doWork] init err', err);
uni.showToast({ title: err?.message || '加载失败', icon: 'none' }); uni.showToast({ title: err?.message || '加载失败', icon: 'none' });
@ -417,16 +475,16 @@ onUnmounted(() => {
z-index: 10; z-index: 10;
display: flex; display: flex;
align-items: center; align-items: center;
padding: 12rpx 20rpx 8rpx; padding: 3rpx 12rpx 2rpx;
gap: 16rpx; gap: 8rpx;
} }
.top-back { .top-back {
width: 56rpx; width: 34rpx;
height: 56rpx; height: 34rpx;
flex-shrink: 0; flex-shrink: 0;
background: #ffffff; background: #ffffff;
border-radius: 18rpx; border-radius: 10rpx;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
@ -440,10 +498,10 @@ onUnmounted(() => {
} }
.back-arrow { .back-arrow {
width: 14rpx; width: 9rpx;
height: 14rpx; height: 9rpx;
border-left: 4rpx solid #4f46e5; border-left: 2rpx solid #4f46e5;
border-bottom: 4rpx solid #4f46e5; border-bottom: 2rpx solid #4f46e5;
transform: rotate(45deg); transform: rotate(45deg);
margin-left: 4rpx; margin-left: 4rpx;
} }
@ -451,7 +509,7 @@ onUnmounted(() => {
.top-title { .top-title {
flex: 1; flex: 1;
min-width: 0; min-width: 0;
font-size: 24rpx; font-size: 17rpx;
font-weight: 700; font-weight: 700;
color: #312e81; color: #312e81;
text-align: center; text-align: center;
@ -464,7 +522,7 @@ onUnmounted(() => {
.top-meta { .top-meta {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 12rpx; gap: 6rpx;
flex-shrink: 0; flex-shrink: 0;
} }
@ -472,7 +530,7 @@ onUnmounted(() => {
display: flex; display: flex;
align-items: baseline; align-items: baseline;
gap: 2rpx; gap: 2rpx;
padding: 6rpx 16rpx; padding: 3rpx 10rpx;
background: linear-gradient(180deg, #818cf8, #4f46e5); background: linear-gradient(180deg, #818cf8, #4f46e5);
border-radius: 999rpx; border-radius: 999rpx;
color: #ffffff; color: #ffffff;
@ -481,17 +539,17 @@ onUnmounted(() => {
inset 0 -3rpx 0 rgba(0, 0, 0, 0.12); inset 0 -3rpx 0 rgba(0, 0, 0, 0.12);
.cur { .cur {
font-size: 22rpx; font-size: 16rpx;
font-weight: 800; font-weight: 800;
} }
.divider { .divider {
font-size: 16rpx; font-size: 11rpx;
opacity: 0.6; opacity: 0.6;
} }
.total { .total {
font-size: 18rpx; font-size: 13rpx;
opacity: 0.8; opacity: 0.8;
} }
} }
@ -499,8 +557,8 @@ onUnmounted(() => {
.top-clock { .top-clock {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 6rpx; gap: 4rpx;
padding: 6rpx 14rpx; padding: 3rpx 10rpx;
background: #ffffff; background: #ffffff;
border-radius: 999rpx; border-radius: 999rpx;
box-shadow: box-shadow:
@ -508,8 +566,8 @@ onUnmounted(() => {
inset 0 -3rpx 0 rgba(199, 210, 254, 0.5); inset 0 -3rpx 0 rgba(199, 210, 254, 0.5);
.clock-icon { .clock-icon {
width: 24rpx; width: 15rpx;
height: 24rpx; height: 15rpx;
svg { svg {
width: 100%; width: 100%;
@ -518,7 +576,7 @@ onUnmounted(() => {
} }
text { text {
font-size: 20rpx; font-size: 15rpx;
font-weight: 700; font-weight: 700;
color: #4f46e5; color: #4f46e5;
font-variant-numeric: tabular-nums; font-variant-numeric: tabular-nums;
@ -531,7 +589,7 @@ onUnmounted(() => {
height: 0; height: 0;
position: relative; position: relative;
z-index: 1; z-index: 1;
padding: 0 20rpx 12rpx; padding: 0 10rpx 5rpx;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
@ -546,30 +604,34 @@ onUnmounted(() => {
flex-shrink: 0; flex-shrink: 0;
display: flex; display: flex;
align-items: center; align-items: center;
gap: 12rpx; gap: 6rpx;
padding-top: 10rpx; padding: 6rpx 0 calc(8rpx + constant(safe-area-inset-bottom));
padding: 6rpx 0 calc(8rpx + env(safe-area-inset-bottom));
box-sizing: border-box;
} }
.indicator { .indicator {
flex: 1; flex: 1;
width: 0; width: 0;
height: 56rpx; height: 42rpx;
white-space: nowrap; white-space: nowrap;
} }
.indicator-track { .indicator-track {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
gap: 10rpx; gap: 5rpx;
padding: 4rpx 0; padding: 3rpx 0 7rpx;
} }
.indicator-item { .indicator-item {
flex-shrink: 0; flex-shrink: 0;
width: 48rpx; width: 31rpx;
height: 48rpx; height: 31rpx;
background: #ffffff; background: #ffffff;
border-radius: 16rpx; border-radius: 9rpx;
border: 2rpx solid transparent;
box-sizing: border-box;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
@ -579,22 +641,11 @@ onUnmounted(() => {
transition: all 150ms ease; transition: all 150ms ease;
text { text {
font-size: 22rpx; font-size: 15rpx;
font-weight: 700; font-weight: 700;
color: #6366f1; color: #6366f1;
} }
&.active {
background: linear-gradient(180deg, #818cf8, #4f46e5);
box-shadow:
0 6rpx 14rpx rgba(79, 70, 229, 0.4),
inset 0 -3rpx 0 rgba(0, 0, 0, 0.15);
text {
color: #ffffff;
}
}
&.answered { &.answered {
background: linear-gradient(180deg, #c7d2fe, #818cf8); background: linear-gradient(180deg, #c7d2fe, #818cf8);
@ -633,12 +684,27 @@ onUnmounted(() => {
color: #ffffff; color: #ffffff;
} }
} }
&.active {
z-index: 1;
transform: translateY(-2rpx);
background: linear-gradient(180deg, #818cf8, #4f46e5);
border-color: rgba(255, 255, 255, 0.9);
box-shadow:
0 8rpx 16rpx rgba(79, 70, 229, 0.45),
0 0 0 3rpx rgba(129, 140, 248, 0.18),
inset 0 -3rpx 0 rgba(0, 0, 0, 0.15);
text {
color: #ffffff;
}
}
} }
.btn-next { .btn-next {
flex-shrink: 0; flex-shrink: 0;
height: 56rpx; height: 36rpx;
padding: 0 28rpx; padding: 0 18rpx;
border-radius: 999rpx; border-radius: 999rpx;
display: flex; display: flex;
align-items: center; align-items: center;
@ -652,14 +718,14 @@ onUnmounted(() => {
transition: all 150ms ease; transition: all 150ms ease;
text { text {
font-size: 22rpx; font-size: 15rpx;
font-weight: 700; font-weight: 700;
letter-spacing: 2rpx; letter-spacing: 2rpx;
} }
.btn-arrow { .btn-arrow {
width: 22rpx; width: 15rpx;
height: 22rpx; height: 15rpx;
svg { svg {
width: 100%; width: 100%;

View File

@ -394,7 +394,7 @@ const init = async () => {
recordId: recordId.value, recordId: recordId.value,
reportFlag: 1, reportFlag: 1,
}); });
paperList.value = detailRes.data?.subjectTitleVoList || []; paperList.value = detailRes.data?.titleVoList || detailRes.data?.subjectTitleVoList || [];
try { try {
const knowledgeRes = await getKnowledgeAnalyse({ recordId: recordId.value }); const knowledgeRes = await getKnowledgeAnalyse({ recordId: recordId.value });

View File

@ -365,7 +365,7 @@ const loadWrongQuestions = async () => {
}); });
return { return {
record, record,
questions: detailRes?.data?.subjectTitleVoList || [], questions: detailRes?.data?.titleVoList || detailRes?.data?.subjectTitleVoList || [],
}; };
} catch (err) { } catch (err) {
console.warn('[wrong] detail err', err); console.warn('[wrong] detail err', err);