接龙调整

This commit is contained in:
hebo 2025-11-10 16:42:11 +08:00
parent 88a8c6f3de
commit 01fad2bfe7
3 changed files with 502 additions and 4 deletions

View File

@ -31,6 +31,31 @@
<u-button type="text" size="mini" class="more-btn" @click="descExpanded = false">收起</u-button>
</view>
</view>
<!-- 选择题选项区域 -->
<view v-if="noticeDetail.jlType === 'select' && optionsList.length > 0" class="options-section">
<view class="options-title">
<text>请选择一项</text>
<text v-if="isAlreadyRelayed" class="already-relayed-hint">您已选择</text>
</view>
<view class="options-list">
<view
v-for="(option, index) in optionsList"
:key="index"
class="option-item"
:class="{ 'option-selected': selectedOption === option.key, 'option-disabled': isAlreadyRelayed && selectedOption !== option.key }"
@click="isAlreadyRelayed ? null : selectOption(option.key)"
>
<view class="option-radio">
<view v-if="selectedOption === option.key" class="radio-checked"></view>
</view>
<view class="option-content">
<text class="option-key">{{ option.key }}.</text>
<text class="option-value">{{ option.value }}</text>
</view>
</view>
</view>
</view>
</view>
<!-- 2. 附件卡片 -->
<view v-if="noticeDetail.jlfj" class="info-card attachment-card">
@ -69,7 +94,20 @@
<BasicSign v-if="showSignature" ref="signCompRef" :title="signTitle"></BasicSign>
<template #bottom>
<view class="bottom-actions">
<button class="action-btn publish-btn" @click="onRelayClick">接龙</button>
<button
v-if="!relaySuccess"
class="action-btn publish-btn"
@click="onRelayClick"
>
接龙
</button>
<button
v-else
class="action-btn return-btn"
@click="handleReturn"
>
返回
</button>
</view>
</template>
</BasicLayout>
@ -95,6 +133,13 @@ const njId = ref<string>("");
const njmcId = ref<string>("");
const bjId = ref<string>("");
//
const optionsList = ref<any[]>([]);
const selectedOption = ref<string>("");
//
const relaySuccess = ref<boolean>(false);
//
const signCompRef = ref<any>(null);
const signTitle = ref<string>("签名");
@ -125,6 +170,34 @@ const receivedCount = computed(() => {
});
const totalStudents = computed(() => studentList.value.length);
//
const isAlreadyRelayed = computed(() => {
const curStu = studentList.value.find(stu => stu.xsId === currentStudent.value?.id);
return curStu && curStu.jlts === '1';
});
//
function selectOption(key: string) {
//
if (isAlreadyRelayed.value) {
uni.showToast({ title: '您已接龙,无法修改选择', icon: 'none' });
return;
}
selectedOption.value = key;
}
//
function handleReturn() {
// 线
// 1: 使 uni.$emit
uni.$emit('jlListRefresh');
// 2: index.vue onShow
uni.navigateBack({
delta: 1
});
}
//
async function onRelayClick() {
try {
@ -136,6 +209,15 @@ async function onRelayClick() {
uni.showToast({ title: '您已参与接龙,无须重复提交', icon: 'none' });
return;
}
//
if (noticeDetail.value.jlType === 'select') {
if (!selectedOption.value) {
uni.showToast({ title: '请选择一项后再提交', icon: 'none' });
return;
}
}
if (noticeDetail.value && noticeDetail.value.mdqz == 1) {
//
showSignature.value = true;
@ -164,12 +246,24 @@ async function submitRelay() {
if (sign_file.value) {
params.qmFile = sign_file.value;
}
//
if (noticeDetail.value.jlType === 'select' && selectedOption.value) {
params.selectedOption = selectedOption.value;
//
const selectedOpt = optionsList.value.find(opt => opt.key === selectedOption.value);
if (selectedOpt) {
params.selectedValue = selectedOpt.value;
}
}
showLoading('提交中...');
try {
const res:any = await relayFinishApi(params);
hideLoading();
if (res && res.resultCode === 1 ) {
uni.showToast({title: '接龙成功', icon: 'success'});
relaySuccess.value = true; //
await refreshStudentList();
} else {
uni.showToast({title: res?.msg || '接龙失败', icon: 'none'});
@ -192,6 +286,15 @@ async function refreshStudentList() {
const stuRes = await jlzxFindByJlParamsApi(params);
studentList.value = stuRes?.rows || stuRes?.result || [];
//
const curStu = studentList.value.find(stu => stu.xsId === currentStudent.value?.id);
if (curStu && curStu.jlts === '1') {
relaySuccess.value = true; //
if (curStu.selectedOption) {
selectedOption.value = curStu.selectedOption;
}
}
} catch (e) {
uni.showToast({ title: "刷新学生状态失败", icon: "none" });
}
@ -218,6 +321,18 @@ onLoad(async (options) => {
try {
const detailRes = await getByJlIdApi({ jlId: noticeId.value });
noticeDetail.value = Array.isArray(detailRes) ? detailRes[0] : {};
//
if (noticeDetail.value.jlType === 'select' && noticeDetail.value.jlOptions) {
try {
optionsList.value = JSON.parse(noticeDetail.value.jlOptions);
// sort
optionsList.value.sort((a, b) => (a.sort || 0) - (b.sort || 0));
} catch (e) {
console.error('解析选项配置失败:', e);
optionsList.value = [];
}
}
} catch (e) {
uni.showToast({ title: "加载接龙详情失败", icon: "none" });
}
@ -232,6 +347,16 @@ onLoad(async (options) => {
const stuRes = await jlzxFindByJlParamsApi(params);
studentList.value = stuRes?.rows || stuRes?.result || [];
//
const curStu = studentList.value.find(stu => stu.xsId === currentStudent.value?.id);
if (curStu && curStu.jlts === '1') {
//
relaySuccess.value = true;
if (curStu.selectedOption) {
selectedOption.value = curStu.selectedOption;
}
}
} catch (e) {
uni.showToast({ title: "加载学生状态失败", icon: "none" });
}
@ -375,6 +500,16 @@ watch(studentList, (list) => {
&.publish-btn:active {
background-color: #3a8ee6;
}
&.return-btn {
background-color: #67c23a;
color: #ffffff;
border: none;
}
&.return-btn:active {
background-color: #5daf34;
}
}
}
@ -638,6 +773,97 @@ watch(studentList, (list) => {
}
}
/* 选择题选项区域 */
.options-section {
margin-top: 20px;
padding-top: 15px;
border-top: 1px solid #f0f0f0;
.options-title {
display: flex;
align-items: center;
gap: 8px;
font-size: 15px;
font-weight: bold;
color: #333;
margin-bottom: 12px;
.already-relayed-hint {
font-size: 13px;
font-weight: normal;
color: #67c23a;
}
}
.options-list {
.option-item {
display: flex;
align-items: flex-start;
padding: 12px;
margin-bottom: 10px;
background-color: #f8f9fa;
border: 2px solid #e9ecef;
border-radius: 8px;
transition: all 0.3s ease;
&.option-selected {
background-color: #e6f7ff;
border-color: #409eff;
}
&.option-disabled {
opacity: 0.5;
cursor: not-allowed;
}
.option-radio {
width: 20px;
height: 20px;
border: 2px solid #d9d9d9;
border-radius: 50%;
margin-right: 10px;
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
margin-top: 2px;
transition: all 0.3s ease;
.radio-checked {
width: 10px;
height: 10px;
background-color: #409eff;
border-radius: 50%;
}
}
&.option-selected .option-radio {
border-color: #409eff;
}
.option-content {
flex: 1;
display: flex;
flex-wrap: wrap;
line-height: 1.6;
.option-key {
font-size: 15px;
font-weight: bold;
color: #333;
margin-right: 6px;
}
.option-value {
flex: 1;
font-size: 15px;
color: #333;
}
}
}
}
}
/* 更多按钮样式 */
.more-btn {
font-size: 16px !important;

View File

@ -31,6 +31,31 @@
<u-button type="text" size="mini" class="more-btn" @click="descExpanded = false">收起</u-button>
</view>
</view>
<!-- 选择题选项区域 -->
<view v-if="noticeDetail.jlType === 'select' && optionsList.length > 0" class="options-section">
<view class="options-title">
<text>请选择一项</text>
<text v-if="isAlreadyRelayed" class="already-relayed-hint">您已选择</text>
</view>
<view class="options-list">
<view
v-for="(option, index) in optionsList"
:key="index"
class="option-item"
:class="{ 'option-selected': selectedOption === option.key, 'option-disabled': isAlreadyRelayed && selectedOption !== option.key }"
@click="isAlreadyRelayed ? null : selectOption(option.key)"
>
<view class="option-radio">
<view v-if="selectedOption === option.key" class="radio-checked"></view>
</view>
<view class="option-content">
<text class="option-key">{{ option.key }}.</text>
<text class="option-value">{{ option.value }}</text>
</view>
</view>
</view>
</view>
</view>
<!-- 2. 附件卡片 -->
<view v-if="noticeDetail.jlfj" class="info-card attachment-card">
@ -69,7 +94,20 @@
<BasicSign v-if="showSignature" ref="signCompRef" :title="signTitle"></BasicSign>
<template #bottom>
<view class="bottom-actions">
<button class="action-btn publish-btn" @click="onRelayClick">接龙</button>
<button
v-if="!relaySuccess"
class="action-btn publish-btn"
@click="onRelayClick"
>
接龙
</button>
<button
v-else
class="action-btn return-btn"
@click="handleReturn"
>
返回
</button>
</view>
</template>
</BasicLayout>
@ -96,6 +134,13 @@ const njmcId = ref<string>("");
const bjId = ref<string>("");
const xsId = ref<string>("");
//
const optionsList = ref<any[]>([]);
const selectedOption = ref<string>("");
//
const relaySuccess = ref<boolean>(false);
//
const signCompRef = ref<any>(null);
const signTitle = ref<string>("签名");
@ -126,6 +171,70 @@ const receivedCount = computed(() => {
});
const totalStudents = computed(() => studentList.value.length);
//
const isAlreadyRelayed = computed(() => {
const curStu = studentList.value.find(stu => stu.xsId === xsId.value);
return curStu && curStu.jlts === '1';
});
//
function selectOption(key: string) {
//
if (isAlreadyRelayed.value) {
uni.showToast({ title: '您已接龙,无法修改选择', icon: 'none' });
return;
}
selectedOption.value = key;
}
//
function handleReturn() {
//
const pages = getCurrentPages();
//
if (pages.length === 1) {
// #ifdef H5
// H5
if (window.opener) {
window.close();
} else {
//
uni.showModal({
title: '提示',
content: '请点击右上角关闭按钮退出',
showCancel: false,
confirmText: '知道了'
});
}
// #endif
// #ifdef MP-WEIXIN
//
// @ts-ignore
wx.closeWindow();
// #endif
// #ifndef H5 || MP-WEIXIN
//
uni.navigateBack({
delta: 1,
fail: () => {
uni.showToast({
title: '无法返回,请手动关闭',
icon: 'none'
});
}
});
// #endif
} else {
//
uni.navigateBack({
delta: 1
});
}
}
//
async function onRelayClick() {
try {
@ -137,6 +246,15 @@ async function onRelayClick() {
uni.showToast({ title: '您已参与接龙,无须重复提交', icon: 'none' });
return;
}
//
if (noticeDetail.value.jlType === 'select') {
if (!selectedOption.value) {
uni.showToast({ title: '请选择一项后再提交', icon: 'none' });
return;
}
}
if (noticeDetail.value && noticeDetail.value.mdqz == 1) {
//
showSignature.value = true;
@ -165,12 +283,24 @@ async function submitRelay() {
if (sign_file.value) {
params.qmFile = sign_file.value;
}
//
if (noticeDetail.value.jlType === 'select' && selectedOption.value) {
params.selectedOption = selectedOption.value;
//
const selectedOpt = optionsList.value.find(opt => opt.key === selectedOption.value);
if (selectedOpt) {
params.selectedValue = selectedOpt.value;
}
}
showLoading('提交中...');
try {
const res:any = await relayFinishApi(params);
hideLoading();
if (res && res.resultCode === 1 ) {
uni.showToast({title: '接龙成功', icon: 'success'});
relaySuccess.value = true; //
await refreshStudentList();
} else {
uni.showToast({title: res?.msg || '接龙失败', icon: 'none'});
@ -193,6 +323,15 @@ async function refreshStudentList() {
const stuRes = await jlzxFindByJlParamsApi(params);
studentList.value = stuRes?.rows || stuRes?.result || [];
//
const curStu = studentList.value.find(stu => stu.xsId === xsId.value);
if (curStu && curStu.jlts === '1') {
relaySuccess.value = true; //
if (curStu.selectedOption) {
selectedOption.value = curStu.selectedOption;
}
}
} catch (e) {
uni.showToast({ title: "刷新学生状态失败", icon: "none" });
}
@ -220,6 +359,18 @@ onLoad(async (options) => {
try {
const detailRes = await getByJlIdApi({ jlId: noticeId.value });
noticeDetail.value = Array.isArray(detailRes) ? detailRes[0] : {};
//
if (noticeDetail.value.jlType === 'select' && noticeDetail.value.jlOptions) {
try {
optionsList.value = JSON.parse(noticeDetail.value.jlOptions);
// sort
optionsList.value.sort((a, b) => (a.sort || 0) - (b.sort || 0));
} catch (e) {
console.error('解析选项配置失败:', e);
optionsList.value = [];
}
}
} catch (e) {
uni.showToast({ title: "加载接龙详情失败", icon: "none" });
}
@ -235,6 +386,16 @@ onLoad(async (options) => {
const stuRes = await jlzxFindByJlParamsApi(params);
studentList.value = stuRes?.rows || stuRes?.result || [];
//
const curStu = studentList.value.find(stu => stu.xsId === xsId.value);
if (curStu && curStu.jlts === '1') {
//
relaySuccess.value = true;
if (curStu.selectedOption) {
selectedOption.value = curStu.selectedOption;
}
}
} catch (e) {
uni.showToast({ title: "加载学生状态失败", icon: "none" });
}
@ -378,6 +539,16 @@ watch(studentList, (list) => {
&.publish-btn:active {
background-color: #3a8ee6;
}
&.return-btn {
background-color: #67c23a;
color: #ffffff;
border: none;
}
&.return-btn:active {
background-color: #5daf34;
}
}
}
@ -641,6 +812,97 @@ watch(studentList, (list) => {
}
}
/* 选择题选项区域 */
.options-section {
margin-top: 20px;
padding-top: 15px;
border-top: 1px solid #f0f0f0;
.options-title {
display: flex;
align-items: center;
gap: 8px;
font-size: 15px;
font-weight: bold;
color: #333;
margin-bottom: 12px;
.already-relayed-hint {
font-size: 13px;
font-weight: normal;
color: #67c23a;
}
}
.options-list {
.option-item {
display: flex;
align-items: flex-start;
padding: 12px;
margin-bottom: 10px;
background-color: #f8f9fa;
border: 2px solid #e9ecef;
border-radius: 8px;
transition: all 0.3s ease;
&.option-selected {
background-color: #e6f7ff;
border-color: #409eff;
}
&.option-disabled {
opacity: 0.5;
cursor: not-allowed;
}
.option-radio {
width: 20px;
height: 20px;
border: 2px solid #d9d9d9;
border-radius: 50%;
margin-right: 10px;
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
margin-top: 2px;
transition: all 0.3s ease;
.radio-checked {
width: 10px;
height: 10px;
background-color: #409eff;
border-radius: 50%;
}
}
&.option-selected .option-radio {
border-color: #409eff;
}
.option-content {
flex: 1;
display: flex;
flex-wrap: wrap;
line-height: 1.6;
.option-key {
font-size: 15px;
font-weight: bold;
color: #333;
margin-right: 6px;
}
.option-value {
flex: 1;
font-size: 15px;
color: #333;
}
}
}
}
}
/* 更多按钮样式 */
.more-btn {
font-size: 16px !important;

View File

@ -60,7 +60,7 @@
import {useLayout} from "@/components/BasicListLayout/hooks/useLayout";
import {mobilejzjllistApi} from "@/api/base/server";
import {imagUrl} from "@/utils";
import {computed, watch, ref} from "vue";
import {computed, watch, ref, onBeforeUnmount} from "vue";
import {onShow} from "@dcloudio/uni-app";
import { useUserStore } from "@/store/modules/user";
@ -193,12 +193,22 @@ const formatTime = (timeStr: string) => {
)}-${String(date.getDate()).padStart(2, "0")}`;
};
//
uni.$on('jlListRefresh', () => {
reload();
});
//
onBeforeUnmount(() => {
uni.$off('jlListRefresh');
});
onShow(() => {
//
const studentInfo = getStudentInfo();
if (studentInfo.id && studentInfo.njId && studentInfo.njmcId) {
reload();
reload(); //
} else {
setTimeout(() => {
const retryStudentInfo = getStudentInfo();