调整选课页面跳转逻辑
This commit is contained in:
parent
a27e4e8a40
commit
55c62cc033
@ -4,89 +4,68 @@ import { get, post } from "@/utils/request";
|
||||
* 获取就餐标准列表
|
||||
*/
|
||||
export const jcGetJcBzListApi = async (params: any) => {
|
||||
return await get("/mobile/jc/getJcBzList", params);
|
||||
return await get("/mobile/jz/jc/getJcBzList", params);
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取就餐标准详情
|
||||
*/
|
||||
export const jcGetJcBzDetailApi = async (params: any) => {
|
||||
return await get("/mobile/jc/getJcBzDetail", params);
|
||||
return await get("/mobile/jz/jc/getJcBzDetail", params);
|
||||
};
|
||||
|
||||
/**
|
||||
* 学生报名就餐标准
|
||||
*/
|
||||
export const jcBmJcBzApi = async (params: any) => {
|
||||
return await post("/mobile/jc/bmJcBz", params);
|
||||
return await post("/mobile/jz/jc/bmJcBz", params);
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取学生已报名的就餐标准列表
|
||||
*/
|
||||
export const jcGetXsBmJcBzListApi = async (params: any) => {
|
||||
return await get("/mobile/jc/getXsBmJcBzList", params);
|
||||
return await get("/mobile/jz/jc/getXsBmJcBzList", params);
|
||||
};
|
||||
|
||||
/**
|
||||
* 取消报名就餐标准
|
||||
*/
|
||||
export const jcCancelBmJcBzApi = async (params: any) => {
|
||||
return await post("/mobile/jc/cancelBmJcBz", params);
|
||||
return await post("/mobile/jz/jc/cancelBmJcBz", params);
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取就餐标准报名倒计时
|
||||
*/
|
||||
export const jcGetBmExpiredTimeApi = async (params: any) => {
|
||||
return await get("/mobile/jc/getBmExpiredTime", params);
|
||||
return await get("/mobile/jz/jc/getBmExpiredTime", params);
|
||||
};
|
||||
|
||||
/**
|
||||
* 发起就餐标准缴费
|
||||
*/
|
||||
export const jcFqJcBzJfjApi = async (params: any) => {
|
||||
return await post("/mobile/jc/fqJcBzJfj", params);
|
||||
return await post("/mobile/jz/jc/fqJcBzJfj", params);
|
||||
};
|
||||
|
||||
/**
|
||||
* 查询就餐标准缴费状态
|
||||
*/
|
||||
export const jcJcBzJfCxjApi = async (params: any) => {
|
||||
return await post("/mobile/jc/jcBzJfcx", params);
|
||||
return await post("/mobile/jz/jc/jcBzJfcx", params);
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取就餐标准报名学生列表
|
||||
*/
|
||||
export const jcGetJcBzBmXsListApi = async (params: any) => {
|
||||
return await get("/mobile/jc/getJcBzBmXsList", params);
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取就餐标准统计信息
|
||||
*/
|
||||
export const jcGetJcBzTjInfoApi = async (params: any) => {
|
||||
return await get("/mobile/jc/getJcBzTjInfo", params);
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取当前学期就餐标准配置
|
||||
*/
|
||||
export const jcGetDqXqJcBzConfigApi = async () => {
|
||||
return await get("/mobile/jc/getDqXqJcBzConfig");
|
||||
return await get("/mobile/jz/jc/getJcBzBmXsList", params);
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取学生就餐记录
|
||||
*/
|
||||
export const jcGetXsJcJlApi = async (params: any) => {
|
||||
return await get("/mobile/jc/getXsJcJl", params);
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取就餐标准支付倒计时
|
||||
*/
|
||||
export const jcGetJcBzPayExpiredTimeApi = async (params: any) => {
|
||||
return await get("/mobile/jc/getJcBzPayExpiredTime", params);
|
||||
return await get("/mobile/jz/jc/getXsJcJl", params);
|
||||
};
|
||||
@ -11,28 +11,12 @@ export const glxsApi = async (params: any) => {
|
||||
return await post("/open/login/glxs", params);
|
||||
};
|
||||
|
||||
export const xkAddXkqdApi = async (params: any) => {
|
||||
return await post("/mobile/xk/addXkqd", params);
|
||||
};
|
||||
|
||||
export const xkListApi = async (params: any) => {
|
||||
return await get("/mobile/xk/list", params);
|
||||
};
|
||||
export const xkXkqdApi = async (params: any) => {
|
||||
return await get("/mobile/xk/xkqd", params);
|
||||
};
|
||||
export const kcjhFindKcjhByKcIdApi = async (params: any) => {
|
||||
return await get("/api/kcjh/findKcjhByKcId", params);
|
||||
};
|
||||
export const xkgzsApi = async (params: any) => {
|
||||
return await get("/api/gzs/findPage", params);
|
||||
};
|
||||
export const xkxkbmInfoApi = async (params: any) => {
|
||||
return await get("/mobile/xk/xkbmInfo", params);
|
||||
};
|
||||
export const xkqddeleteApi = async (params: any) => {
|
||||
return await post("/api/xkqd/delete?ids=" + params.ids);
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取当前学期和周次
|
||||
@ -67,20 +51,6 @@ export const drpkkbApi = async (params: any) => {
|
||||
return await get("/mobile/jz/pkkb/drpkkb", params);
|
||||
};
|
||||
|
||||
/**
|
||||
* 查询学生选课列表
|
||||
*/
|
||||
export const xsKxApi = async (params: any) => {
|
||||
return await get("/mobile/jz/xkkc/list", params);
|
||||
};
|
||||
|
||||
/**
|
||||
* 学生已选课程列表
|
||||
*/
|
||||
export const xsYxListApi = async (params: any) => {
|
||||
return await get("/mobile/jz/xsxk/list", params);
|
||||
};
|
||||
|
||||
/**
|
||||
* 查询学生考试场次
|
||||
*/
|
||||
@ -94,46 +64,6 @@ export const xsKsccApi = async (params: any) => {
|
||||
export const xsKscjApi = async (params: any) => {
|
||||
return await get("/mobile/jz/kscj", params);
|
||||
};
|
||||
|
||||
/**
|
||||
* 家长抢课
|
||||
*/
|
||||
export const jzXkQkjApi = async (params: any) => {
|
||||
return await post("/mobile/jz/xk/qk", params);
|
||||
};
|
||||
/**
|
||||
* 家长获取抢课到期时间
|
||||
*/
|
||||
export const jzGetQkExpiredTime = async (params: any) => {
|
||||
return await get("/mobile/jz/xk/getQkExpiredTime", params);
|
||||
};
|
||||
/**
|
||||
* 家长发起缴费
|
||||
*/
|
||||
export const jzXkFqJfjApi = async (params: any) => {
|
||||
return await post("/mobile/jz/xk/fqjf", params);
|
||||
};
|
||||
|
||||
/**
|
||||
* 家长取消选课,不支付
|
||||
*/
|
||||
export const jzXkCancelApi = async (params: any) => {
|
||||
return await post("/mobile/jz/xk/cancel", params);
|
||||
};
|
||||
|
||||
/**
|
||||
* 家长退课
|
||||
*/
|
||||
export const jzXkTkjApi = async (params: any) => {
|
||||
return await post("/mobile/jz/xk/tk", params);
|
||||
};
|
||||
|
||||
/**
|
||||
* 家长缴费查询
|
||||
*/
|
||||
export const jzXkJfCxjApi = async (params: any) => {
|
||||
return await post("/mobile/jz/xk/jfcx", params);
|
||||
};
|
||||
/**
|
||||
* 家长接龙查询
|
||||
*/
|
||||
|
||||
95
src/api/base/xkApi.ts
Normal file
95
src/api/base/xkApi.ts
Normal file
@ -0,0 +1,95 @@
|
||||
// 选课相关接口
|
||||
import { get, post } from "@/utils/request";
|
||||
|
||||
/**
|
||||
* 查询学生选课列表
|
||||
*/
|
||||
export const xsKxApi = async (params: any) => {
|
||||
return await get("/mobile/jz/xkkc/list", params);
|
||||
};
|
||||
|
||||
/**
|
||||
* 学生已选课程列表
|
||||
*/
|
||||
export const xsYxListApi = async (params: any) => {
|
||||
return await get("/mobile/jz/xsxk/list", params);
|
||||
};
|
||||
|
||||
/**
|
||||
* 家长抢课
|
||||
*/
|
||||
export const jzXkQkjApi = async (params: any) => {
|
||||
return await post("/mobile/jz/xk/qk", params);
|
||||
};
|
||||
|
||||
/**
|
||||
* 家长获取抢课到期时间
|
||||
*/
|
||||
export const jzGetQkExpiredTime = async (params: any) => {
|
||||
return await get("/mobile/jz/xk/getQkExpiredTime", params);
|
||||
};
|
||||
|
||||
/**
|
||||
* 家长发起缴费
|
||||
*/
|
||||
export const jzXkFqJfjApi = async (params: any) => {
|
||||
return await post("/mobile/jz/xk/fqjf", params);
|
||||
};
|
||||
|
||||
/**
|
||||
* 家长取消选课,不支付
|
||||
*/
|
||||
export const jzXkCancelApi = async (params: any) => {
|
||||
return await post("/mobile/jz/xk/cancel", params);
|
||||
};
|
||||
|
||||
/**
|
||||
* 家长退课
|
||||
*/
|
||||
export const jzXkTkjApi = async (params: any) => {
|
||||
return await post("/mobile/jz/xk/tk", params);
|
||||
};
|
||||
|
||||
/**
|
||||
* 家长缴费查询
|
||||
*/
|
||||
export const jzXkJfCxjApi = async (params: any) => {
|
||||
return await post("/mobile/jz/xk/jfcx", params);
|
||||
};
|
||||
|
||||
/**
|
||||
* 查询学生当前学期是否选择了对应类型的选课
|
||||
*/
|
||||
export const checkXsXkByTypeApi = async (params: any) => {
|
||||
return await get("/mobile/jz/xk/checkXsXkByType", params);
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取学生选课状态和限制信息
|
||||
*/
|
||||
export const getXsXkStatusApi = async (params: any) => {
|
||||
return await get("/mobile/jz/xkkc/list", params);
|
||||
};
|
||||
|
||||
/**
|
||||
* 选课相关其他接口
|
||||
*/
|
||||
export const xkAddXkqdApi = async (params: any) => {
|
||||
return await post("/mobile/xk/addXkqd", params);
|
||||
};
|
||||
|
||||
export const xkListApi = async (params: any) => {
|
||||
return await get("/mobile/xk/list", params);
|
||||
};
|
||||
|
||||
export const xkXkqdApi = async (params: any) => {
|
||||
return await get("/mobile/xk/xkqd", params);
|
||||
};
|
||||
|
||||
export const xkxkbmInfoApi = async (params: any) => {
|
||||
return await get("/mobile/xk/xkbmInfo", params);
|
||||
};
|
||||
|
||||
export const xkqddeleteApi = async (params: any) => {
|
||||
return await post("/api/xkqd/delete?ids=" + params.ids);
|
||||
};
|
||||
@ -1,5 +1,5 @@
|
||||
// const ip: string = "127.0.0.1:8897";
|
||||
const ip: string = "lzcxsx.cn";
|
||||
const ip: string = "127.0.0.1:8897";
|
||||
// const ip: string = "lzcxsx.cn";
|
||||
const fwqip: string = "lzcxsx.cn";
|
||||
//const ip: string = "zhxy.yufangzc.com";
|
||||
//const fwqip: string = "zhxy.yufangzc.com";
|
||||
|
||||
@ -192,6 +192,13 @@
|
||||
"enablePullDownRefresh": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/base/home/xsXz",
|
||||
"style": {
|
||||
"navigationBarTitleText": "学生选择",
|
||||
"enablePullDownRefresh": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/base/xk/qk/xqk",
|
||||
"style": {
|
||||
@ -271,6 +278,72 @@
|
||||
"navigationBarTitleText": "俱乐部告知书",
|
||||
"enablePullDownRefresh": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/base/jc/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "检查",
|
||||
"enablePullDownRefresh": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/base/jc/detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "检查详情",
|
||||
"enablePullDownRefresh": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/base/jc/bm",
|
||||
"style": {
|
||||
"navigationBarTitleText": "报名",
|
||||
"enablePullDownRefresh": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/base/jc/bm-detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "报名详情",
|
||||
"enablePullDownRefresh": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/base/jc/record",
|
||||
"style": {
|
||||
"navigationBarTitleText": "记录",
|
||||
"enablePullDownRefresh": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/base/jc/pay/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "支付",
|
||||
"enablePullDownRefresh": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/base/jc/pay/wait",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"enablePullDownRefresh": false,
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black",
|
||||
"backgroundColor": "#ffffff"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/base/jc/pay/success",
|
||||
"style": {
|
||||
"navigationBarTitleText": "支付成功",
|
||||
"enablePullDownRefresh": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/base/jc/pay/fail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "支付失败",
|
||||
"enablePullDownRefresh": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"globalStyle": {
|
||||
|
||||
229
src/pages/base/components/JcBzDetailCard/index.vue
Normal file
229
src/pages/base/components/JcBzDetailCard/index.vue
Normal file
@ -0,0 +1,229 @@
|
||||
<template>
|
||||
<view class="jc-bz-detail-card">
|
||||
<view class="card-header">
|
||||
<view class="card-title">{{ title || '就餐标准详情' }}</view>
|
||||
</view>
|
||||
|
||||
<view class="jc-bz-list">
|
||||
<view
|
||||
v-for="(jcBz, index) in jcBzList"
|
||||
:key="jcBz.id || index"
|
||||
class="jc-bz-item"
|
||||
>
|
||||
<view class="jc-bz-info">
|
||||
<image
|
||||
class="jc-bz-image"
|
||||
:src="getImageUrl(jcBz.lxtp)"
|
||||
mode="aspectFill"
|
||||
></image>
|
||||
|
||||
<view class="jc-bz-content">
|
||||
<view class="jc-bz-name">{{ jcBz.bzmc || '暂无标准名称' }}</view>
|
||||
<view class="jc-bz-price">
|
||||
价格:<text class="price-value">¥{{ jcBz.jfje || 0 }}</text>
|
||||
</view>
|
||||
<view class="jc-bz-desc">{{ jcBz.bzms || '暂无描述' }}</view>
|
||||
<view class="jc-bz-time">有效期:{{ jcBz.yxq || '暂无有效期信息' }}</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 可选的详情展开按钮 -->
|
||||
<view v-if="showDetailBtn" class="detail-btn" @click="goToDetail(jcBz)">
|
||||
<text>查看详情</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 汇总信息 -->
|
||||
<view v-if="showSummary" class="summary-info">
|
||||
<view class="summary-item">
|
||||
<text class="label">已选择:</text>
|
||||
<text class="value">{{ jcBzList.length }} 个就餐标准</text>
|
||||
</view>
|
||||
<view class="summary-item">
|
||||
<text class="label">总金额:</text>
|
||||
<text class="value total-price">¥{{ totalPrice }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from "vue";
|
||||
import { imagUrl } from "@/utils";
|
||||
|
||||
// 定义就餐标准数据类型
|
||||
interface JcBzData {
|
||||
id?: string;
|
||||
bzmc?: string;
|
||||
jfje?: number;
|
||||
bzms?: string;
|
||||
yxq?: string;
|
||||
lxtp?: string;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
jcBzList: JcBzData[];
|
||||
title?: string;
|
||||
showDetailBtn?: boolean;
|
||||
showSummary?: boolean;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
jcBzList: () => [],
|
||||
title: '就餐标准详情',
|
||||
showDetailBtn: false,
|
||||
showSummary: true
|
||||
});
|
||||
|
||||
const emit = defineEmits(['detail']);
|
||||
|
||||
// 计算总金额
|
||||
const totalPrice = computed(() => {
|
||||
let total = 0;
|
||||
props.jcBzList.forEach(jcBz => {
|
||||
total += jcBz.jfje || 0;
|
||||
});
|
||||
return total;
|
||||
});
|
||||
|
||||
// 处理图片URL
|
||||
const getImageUrl = (imagePath: string) => {
|
||||
return imagUrl(imagePath || '');
|
||||
};
|
||||
|
||||
// 跳转到详情页面
|
||||
const goToDetail = (jcBz: JcBzData) => {
|
||||
emit('detail', jcBz);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.jc-bz-detail-card {
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
margin: 15px;
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
padding: 15px 15px 10px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
|
||||
.card-title {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
|
||||
.jc-bz-list {
|
||||
.jc-bz-item {
|
||||
padding: 15px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.jc-bz-info {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
|
||||
.jc-bz-image {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border-radius: 6px;
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
.jc-bz-content {
|
||||
flex: 1;
|
||||
|
||||
.jc-bz-name {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 8px;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.jc-bz-price {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
margin-bottom: 6px;
|
||||
|
||||
.price-value {
|
||||
color: #ff6b00;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.jc-bz-desc {
|
||||
font-size: 13px;
|
||||
color: #999;
|
||||
margin-bottom: 6px;
|
||||
line-height: 1.4;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.jc-bz-time {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.detail-btn {
|
||||
margin-left: 10px;
|
||||
padding: 6px 12px;
|
||||
background-color: #2879ff;
|
||||
color: #fff;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.summary-info {
|
||||
padding: 15px;
|
||||
background-color: #f8f9fa;
|
||||
border-top: 1px solid #f0f0f0;
|
||||
|
||||
.summary-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 8px;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.label {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.value {
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
|
||||
&.total-price {
|
||||
color: #ff6b00;
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -60,7 +60,7 @@ const props = withDefaults(defineProps<{
|
||||
});
|
||||
|
||||
// 定义一个上级传入的emit响应事件用于接收数据变更
|
||||
const emit = defineEmits(['change'])
|
||||
const emit = defineEmits(['change', 'selectedData'])
|
||||
|
||||
// 就餐标准列表数据
|
||||
const jcBzList = ref<any>([]);
|
||||
@ -89,6 +89,12 @@ const initSelectedStatus = () => {
|
||||
jcBzList.value.forEach((jcBz: any) => {
|
||||
jcBz.isSelected = selectedJcBzIds.includes(jcBz.id);
|
||||
});
|
||||
|
||||
// 发送初始选中的数据
|
||||
const selectedData = jcBzList.value.filter((item: any) =>
|
||||
selectedJcBzIds.includes(item.id)
|
||||
);
|
||||
emit("selectedData", selectedData);
|
||||
};
|
||||
|
||||
// 切换选餐标准
|
||||
@ -128,6 +134,12 @@ const toggleSelection = (jcBz: any) => {
|
||||
// 更新本地存储
|
||||
uni.setStorageSync("selectedJcBzIds", selectedJcBzIds);
|
||||
emit("change", selectedJcBzIds);
|
||||
|
||||
// 发送选中的完整数据
|
||||
const selectedData = jcBzList.value.filter((item: any) =>
|
||||
selectedJcBzIds.includes(item.id)
|
||||
);
|
||||
emit("selectedData", selectedData);
|
||||
}
|
||||
|
||||
const goToDetail = (jcBz: any) => {
|
||||
|
||||
318
src/pages/base/components/JcBzPicker/index.vue
Normal file
318
src/pages/base/components/JcBzPicker/index.vue
Normal file
@ -0,0 +1,318 @@
|
||||
<template>
|
||||
<view class="jc-bz-picker">
|
||||
<view class="picker-header" @click="showPicker">
|
||||
<view class="picker-label">
|
||||
<text class="label-text">{{ label }}</text>
|
||||
<text class="required" v-if="required">*</text>
|
||||
</view>
|
||||
<view class="picker-value" :class="{ placeholder: !selectedText }">
|
||||
{{ selectedText || placeholder }}
|
||||
</view>
|
||||
<view class="picker-arrow">
|
||||
<uni-icons type="right" size="16" color="#999"></uni-icons>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 选择器弹窗 -->
|
||||
<uni-popup ref="popup" type="bottom" :mask-click="false">
|
||||
<view class="popup-content">
|
||||
<view class="popup-header">
|
||||
<view class="popup-title">{{ title }}</view>
|
||||
<view class="popup-actions">
|
||||
<view class="cancel-btn" @click="cancelPicker">取消</view>
|
||||
<view class="confirm-btn" @click="confirmPicker">确定</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="popup-body">
|
||||
<view class="jc-bz-list">
|
||||
<view
|
||||
v-for="(jcBz, index) in jcBzList"
|
||||
:key="jcBz.id || index"
|
||||
class="jc-bz-item"
|
||||
:class="{ selected: isSelected(jcBz) }"
|
||||
@click="toggleSelection(jcBz)"
|
||||
>
|
||||
<view class="jc-bz-info">
|
||||
<view class="jc-bz-name">{{ jcBz.bzmc }}</view>
|
||||
<view class="jc-bz-price">¥{{ jcBz.jfje }}</view>
|
||||
</view>
|
||||
<view v-if="isSelected(jcBz)" class="selected-icon">
|
||||
<uni-icons type="checkmarkempty" color="#2879ff" size="20"></uni-icons>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, watch, onMounted } from "vue";
|
||||
import { jcGetJcBzListApi } from "@/api/base/jcApi";
|
||||
|
||||
interface JcBzData {
|
||||
id: string;
|
||||
bzmc: string;
|
||||
jfje: number;
|
||||
bzms?: string;
|
||||
yxq?: string;
|
||||
lxtp?: string;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
xsId: string;
|
||||
label?: string;
|
||||
placeholder?: string;
|
||||
title?: string;
|
||||
required?: boolean;
|
||||
multiple?: boolean;
|
||||
value?: string | string[];
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
xsId: '',
|
||||
label: '就餐标准',
|
||||
placeholder: '请选择就餐标准',
|
||||
title: '选择就餐标准',
|
||||
required: false,
|
||||
multiple: false,
|
||||
value: ''
|
||||
});
|
||||
|
||||
const emit = defineEmits(['change', 'update:value']);
|
||||
|
||||
const popup = ref();
|
||||
const jcBzList = ref<JcBzData[]>([]);
|
||||
const selectedIds = ref<string[]>([]);
|
||||
|
||||
// 计算选中的文本
|
||||
const selectedText = computed(() => {
|
||||
if (!selectedIds.value.length) return '';
|
||||
|
||||
if (props.multiple) {
|
||||
const selectedItems = jcBzList.value.filter(item =>
|
||||
selectedIds.value.includes(item.id)
|
||||
);
|
||||
return selectedItems.map(item => item.bzmc).join('、');
|
||||
} else {
|
||||
const selectedItem = jcBzList.value.find(item =>
|
||||
selectedIds.value.includes(item.id)
|
||||
);
|
||||
return selectedItem?.bzmc || '';
|
||||
}
|
||||
});
|
||||
|
||||
// 检查是否选中
|
||||
const isSelected = (jcBz: JcBzData) => {
|
||||
return selectedIds.value.includes(jcBz.id);
|
||||
};
|
||||
|
||||
// 获取就餐标准列表
|
||||
const getJcBzList = async () => {
|
||||
try {
|
||||
const res = await jcGetJcBzListApi({
|
||||
xsId: props.xsId
|
||||
});
|
||||
if (res.resultCode === 1) {
|
||||
// 处理返回的数据结构
|
||||
const result = res.result;
|
||||
if (result && result.jcBzList) {
|
||||
jcBzList.value = result.jcBzList || [];
|
||||
} else {
|
||||
jcBzList.value = [];
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取就餐标准列表失败:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 显示选择器
|
||||
const showPicker = () => {
|
||||
popup.value.open();
|
||||
};
|
||||
|
||||
// 取消选择
|
||||
const cancelPicker = () => {
|
||||
popup.value.close();
|
||||
};
|
||||
|
||||
// 确认选择
|
||||
const confirmPicker = () => {
|
||||
const result = props.multiple ? selectedIds.value : selectedIds.value[0] || '';
|
||||
emit('change', result);
|
||||
emit('update:value', result);
|
||||
popup.value.close();
|
||||
};
|
||||
|
||||
// 切换选择
|
||||
const toggleSelection = (jcBz: JcBzData) => {
|
||||
if (props.multiple) {
|
||||
const index = selectedIds.value.indexOf(jcBz.id);
|
||||
if (index > -1) {
|
||||
selectedIds.value.splice(index, 1);
|
||||
} else {
|
||||
selectedIds.value.push(jcBz.id);
|
||||
}
|
||||
} else {
|
||||
selectedIds.value = [jcBz.id];
|
||||
}
|
||||
};
|
||||
|
||||
// 监听值变化
|
||||
watch(() => props.value, (newVal) => {
|
||||
if (newVal) {
|
||||
if (props.multiple && Array.isArray(newVal)) {
|
||||
selectedIds.value = [...newVal];
|
||||
} else if (!props.multiple && typeof newVal === 'string') {
|
||||
selectedIds.value = [newVal];
|
||||
}
|
||||
} else {
|
||||
selectedIds.value = [];
|
||||
}
|
||||
}, { immediate: true });
|
||||
|
||||
// 监听学生ID变化
|
||||
watch(() => props.xsId, (newVal) => {
|
||||
if (newVal) {
|
||||
getJcBzList();
|
||||
}
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
if (props.xsId) {
|
||||
getJcBzList();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.jc-bz-picker {
|
||||
.picker-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 15px;
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #e5e5e5;
|
||||
|
||||
.picker-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: 10px;
|
||||
|
||||
.label-text {
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.required {
|
||||
color: #ff4757;
|
||||
margin-left: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.picker-value {
|
||||
flex: 1;
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
|
||||
&.placeholder {
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
.picker-arrow {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.popup-content {
|
||||
background-color: #fff;
|
||||
border-radius: 12px 12px 0 0;
|
||||
max-height: 70vh;
|
||||
|
||||
.popup-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 15px 20px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
|
||||
.popup-title {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.popup-actions {
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
|
||||
.cancel-btn,
|
||||
.confirm-btn {
|
||||
font-size: 14px;
|
||||
padding: 5px 10px;
|
||||
}
|
||||
|
||||
.cancel-btn {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.confirm-btn {
|
||||
color: #2879ff;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.popup-body {
|
||||
max-height: 60vh;
|
||||
overflow-y: auto;
|
||||
|
||||
.jc-bz-list {
|
||||
padding: 0 20px;
|
||||
|
||||
.jc-bz-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 15px 0;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
&.selected {
|
||||
background-color: rgba(40, 121, 255, 0.05);
|
||||
}
|
||||
|
||||
.jc-bz-info {
|
||||
flex: 1;
|
||||
|
||||
.jc-bz-name {
|
||||
font-size: 16px;
|
||||
color: #333;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.jc-bz-price {
|
||||
font-size: 14px;
|
||||
color: #ff6b00;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.selected-icon {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -26,13 +26,11 @@
|
||||
class="xk-item"
|
||||
:class="{
|
||||
'xk-item-active': curXk.id === xk.id,
|
||||
'xk-item-selected': xk.selected,
|
||||
}"
|
||||
@click="switchXk(xk)"
|
||||
>
|
||||
<view class="xk-info">
|
||||
<text class="xk-name">{{ xk.xkmc }}</text>
|
||||
<text v-if="xk.selected" class="xk-selected-tip">已选择</text>
|
||||
</view>
|
||||
<u-icon
|
||||
v-if="curXk.id === xk.id"
|
||||
@ -49,7 +47,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, watch } from "vue";
|
||||
import { xsKxApi, xsYxListApi } from "@/api/base/server";
|
||||
import { xsKxApi, xsYxListApi } from "@/api/base/xkApi";
|
||||
import { useUserStore } from "@/store/modules/user";
|
||||
import { useDataStore } from "@/store/modules/data";
|
||||
|
||||
@ -223,11 +221,6 @@ if (props.xsId) {
|
||||
background-color: rgba(64, 158, 255, 0.05);
|
||||
}
|
||||
|
||||
&-selected {
|
||||
background-color: rgba(64, 158, 255, 0.1);
|
||||
border-left: 3px solid #409eff;
|
||||
}
|
||||
|
||||
.xk-info {
|
||||
flex: 1;
|
||||
margin-left: 12px;
|
||||
@ -239,14 +232,6 @@ if (props.xsId) {
|
||||
margin-bottom: 4px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.xk-selected-tip {
|
||||
font-size: 12px;
|
||||
color: #409eff;
|
||||
background-color: rgba(64, 158, 255, 0.1);
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,7 +50,7 @@ async function submit() {
|
||||
sign_file: sign_file.value,
|
||||
});
|
||||
uni.reLaunch({
|
||||
url: "/pages/base/xk/qk/jlb",
|
||||
url: "/pages/base/jc/bm",
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
62
src/pages/base/home/xsXz.vue
Normal file
62
src/pages/base/home/xsXz.vue
Normal file
@ -0,0 +1,62 @@
|
||||
<template>
|
||||
<view class="interest-course">
|
||||
<!-- 选课信息头部 - 固定部分 -->
|
||||
<view class="selection-header">
|
||||
<view class="header-content">
|
||||
<!-- 学生选择部分 -->
|
||||
<XsPicker :is-bar="true" @change="switchXs" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import XsPicker from "@/pages/base/components/XsPicker/index.vue"
|
||||
import { useDataStore } from "@/store/modules/data";
|
||||
import { useUserStore } from "@/store/modules/user";
|
||||
const { getGlobal } = useDataStore();
|
||||
const { checkXqk, checkJlb } = useUserStore();
|
||||
|
||||
const switchXs = (xs: any) => {
|
||||
if (getGlobal.type == 1) {
|
||||
checkXqk();
|
||||
} else if (getGlobal.type == 2) {
|
||||
checkJlb();
|
||||
} else {
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.interest-course {
|
||||
min-height: 100%;
|
||||
background-color: #f5f7fa;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.selection-header {
|
||||
background: linear-gradient(135deg, #4a90e2, #2879ff);
|
||||
padding: 20px 15px;
|
||||
color: #fff;
|
||||
border-radius: 0 0 15px 15px;
|
||||
box-shadow: 0 4px 12px rgba(40, 121, 255, 0.2);
|
||||
position: sticky;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 10;
|
||||
|
||||
.header-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
78
src/pages/base/jc/README.md
Normal file
78
src/pages/base/jc/README.md
Normal file
@ -0,0 +1,78 @@
|
||||
# JC模块 - 就餐标准管理
|
||||
|
||||
## 功能概述
|
||||
|
||||
JC模块是用于管理学生就餐标准的前端模块,包含以下主要功能:
|
||||
|
||||
### 1. 就餐标准列表 (`/pages/base/jc/index.vue`)
|
||||
- 显示当前学期可用的就餐标准
|
||||
- 支持学生选择器切换不同学生
|
||||
- 展示就餐标准的基本信息(名称、价格、描述)
|
||||
|
||||
### 2. 就餐标准详情 (`/pages/base/jc/detail.vue`)
|
||||
- 显示就餐标准的详细信息
|
||||
- 包含标准描述、使用说明、注意事项等
|
||||
- 支持图片展示
|
||||
|
||||
### 3. 就餐标准报名 (`/pages/base/jc/bm.vue`)
|
||||
- 支持多选就餐标准
|
||||
- 实时计算总金额
|
||||
- 确认报名后跳转到支付页面
|
||||
|
||||
### 4. 支付流程 (`/pages/base/jc/pay/`)
|
||||
- 支付页面 (`index.vue`):显示报名信息和支付倒计时
|
||||
- 支付等待页面 (`wait.vue`):处理支付回调
|
||||
- 支付成功页面 (`success.vue`):支付成功提示
|
||||
- 支付失败页面 (`fail.vue`):支付失败处理
|
||||
|
||||
### 5. 就餐记录 (`/pages/base/jc/record.vue`)
|
||||
- 显示学生的就餐记录历史
|
||||
- 包含就餐日期、状态、地点等信息
|
||||
|
||||
## 组件结构
|
||||
|
||||
### 核心组件
|
||||
- `JcBzList` (`/pages/base/components/JcBzList/index.vue`):就餐标准列表组件
|
||||
- `JcRecordList` (`/pages/base/components/JcRecordList/index.vue`):就餐记录列表组件
|
||||
|
||||
### API接口
|
||||
所有JC相关的API接口都集中在 `jcApi.ts` 文件中,包括:
|
||||
- 获取就餐标准列表
|
||||
- 获取就餐标准详情
|
||||
- 学生报名就餐标准
|
||||
- 取消报名
|
||||
- 发起支付
|
||||
- 查询支付状态
|
||||
- 获取就餐记录等
|
||||
|
||||
## 数据流
|
||||
|
||||
1. **报名流程**:
|
||||
- 学生选择就餐标准 → 确认报名 → 跳转支付页面 → 完成支付
|
||||
|
||||
2. **数据存储**:
|
||||
- 使用 Pinia store 管理状态
|
||||
- 本地存储保存选中状态
|
||||
- 支付数据通过 store 传递
|
||||
|
||||
## 技术特点
|
||||
|
||||
- 采用 Vue 3 Composition API
|
||||
- 使用 TypeScript 进行类型检查
|
||||
- 响应式设计,支持移动端
|
||||
- 模块化组件设计
|
||||
- 统一的错误处理机制
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. 支付倒计时功能需要后端提供倒计时接口
|
||||
2. 多选功能需要合理处理数据同步
|
||||
3. 支付状态查询需要定时轮询
|
||||
4. 图片资源需要正确的路径处理
|
||||
|
||||
## 扩展建议
|
||||
|
||||
1. 可以添加就餐标准筛选功能
|
||||
2. 支持按时间范围查询就餐记录
|
||||
3. 添加就餐统计功能
|
||||
4. 支持批量操作就餐标准
|
||||
295
src/pages/base/jc/bm-detail.vue
Normal file
295
src/pages/base/jc/bm-detail.vue
Normal file
@ -0,0 +1,295 @@
|
||||
<template>
|
||||
<view class="bm-detail-page">
|
||||
<!-- 页面头部 -->
|
||||
<view class="page-header">
|
||||
<view class="header-title">报名详情</view>
|
||||
</view>
|
||||
|
||||
<!-- 学生信息 -->
|
||||
<view class="info-card">
|
||||
<view class="card-title">学生信息</view>
|
||||
<view class="student-info">
|
||||
<view class="info-item">
|
||||
<text class="label">姓名:</text>
|
||||
<text class="value">{{ curXs.xm }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="label">班级:</text>
|
||||
<text class="value">{{ curXs.bjmc }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 报名信息 -->
|
||||
<view class="info-card">
|
||||
<view class="card-title">报名信息</view>
|
||||
<view class="bm-info">
|
||||
<view class="info-item">
|
||||
<text class="label">报名时间:</text>
|
||||
<text class="value">{{ bmInfo.bmTime || '暂无' }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="label">报名状态:</text>
|
||||
<text class="value status-success">已报名</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 就餐标准详情 -->
|
||||
<JcBzDetailCard
|
||||
v-if="bmJcBzList.length > 0"
|
||||
:jc-bz-list="bmJcBzList"
|
||||
title="已报名的就餐标准"
|
||||
:show-detail-btn="true"
|
||||
:show-summary="false"
|
||||
@detail="goToDetail"
|
||||
/>
|
||||
|
||||
<!-- 支付信息 -->
|
||||
<view class="info-card">
|
||||
<view class="card-title">支付信息</view>
|
||||
<view class="payment-info">
|
||||
<view class="info-item">
|
||||
<text class="label">缴费金额:</text>
|
||||
<text class="value total-price">¥{{ totalAmount }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="label">支付状态:</text>
|
||||
<text class="value" :class="paymentStatusClass">{{ paymentStatusText }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部操作 -->
|
||||
<view class="bottom-actions">
|
||||
<view class="action-btn primary" @click="goToPay" v-if="paymentStatus === 'unpaid'">
|
||||
立即支付
|
||||
</view>
|
||||
<view class="action-btn secondary" @click="goBack">
|
||||
返回
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted } from "vue";
|
||||
import { useUserStore } from "@/store/modules/user";
|
||||
import { useDataStore } from "@/store/modules/data";
|
||||
import JcBzDetailCard from "@/pages/base/components/JcBzDetailCard/index.vue";
|
||||
import { jcGetXsBmJcBzListApi } from "@/api/base/jcApi";
|
||||
|
||||
const { getCurXs } = useUserStore();
|
||||
const { getData, setData } = useDataStore();
|
||||
|
||||
const curXs = computed(() => getCurXs);
|
||||
|
||||
// 报名信息
|
||||
const bmInfo = ref<any>({});
|
||||
// 已报名的就餐标准列表
|
||||
const bmJcBzList = ref<any[]>([]);
|
||||
// 支付状态
|
||||
const paymentStatus = ref<string>('unpaid'); // unpaid, paid, expired
|
||||
|
||||
// 计算总金额
|
||||
const totalAmount = computed(() => {
|
||||
let total = 0;
|
||||
bmJcBzList.value.forEach(jcBz => {
|
||||
total += jcBz.jfje || 0;
|
||||
});
|
||||
return total;
|
||||
});
|
||||
|
||||
// 支付状态样式
|
||||
const paymentStatusClass = computed(() => {
|
||||
switch (paymentStatus.value) {
|
||||
case 'paid':
|
||||
return 'status-success';
|
||||
case 'expired':
|
||||
return 'status-error';
|
||||
default:
|
||||
return 'status-warning';
|
||||
}
|
||||
});
|
||||
|
||||
// 支付状态文本
|
||||
const paymentStatusText = computed(() => {
|
||||
switch (paymentStatus.value) {
|
||||
case 'paid':
|
||||
return '已支付';
|
||||
case 'expired':
|
||||
return '已过期';
|
||||
default:
|
||||
return '待支付';
|
||||
}
|
||||
});
|
||||
|
||||
// 获取报名信息
|
||||
const getBmInfo = async () => {
|
||||
try {
|
||||
const res = await jcGetXsBmJcBzListApi({
|
||||
xsId: curXs.value.id
|
||||
});
|
||||
|
||||
if (res.resultCode === 1) {
|
||||
bmJcBzList.value = res.result || [];
|
||||
// 这里可以根据实际数据结构设置其他信息
|
||||
bmInfo.value = {
|
||||
bmTime: new Date().toLocaleString(),
|
||||
// 其他报名信息
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取报名信息失败:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 跳转到详情页面
|
||||
const goToDetail = (jcBz: any) => {
|
||||
setData({
|
||||
...getData,
|
||||
jcBzData: jcBz
|
||||
});
|
||||
uni.navigateTo({
|
||||
url: '/pages/base/jc/detail'
|
||||
});
|
||||
};
|
||||
|
||||
// 跳转到支付页面
|
||||
const goToPay = () => {
|
||||
// 保存支付数据到store
|
||||
setData({
|
||||
...getData,
|
||||
xsId: curXs.value.id,
|
||||
jcBzIds: bmJcBzList.value.map(item => item.id),
|
||||
jcBzList: bmJcBzList.value,
|
||||
totalJe: totalAmount.value,
|
||||
});
|
||||
|
||||
uni.redirectTo({
|
||||
url: '/pages/base/jc/pay/index'
|
||||
});
|
||||
};
|
||||
|
||||
// 返回上一页
|
||||
const goBack = () => {
|
||||
uni.navigateBack();
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getBmInfo();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.bm-detail-page {
|
||||
min-height: 100vh;
|
||||
background-color: #f5f7fa;
|
||||
padding-bottom: 100px;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
background: linear-gradient(135deg, #4a90e2, #2879ff);
|
||||
padding: 20px 15px;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
|
||||
.header-title {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.info-card {
|
||||
margin: 15px;
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
padding: 15px;
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05);
|
||||
|
||||
.card-title {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 15px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.student-info,
|
||||
.bm-info,
|
||||
.payment-info {
|
||||
.info-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.label {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.value {
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
|
||||
&.total-price {
|
||||
color: #ff6b00;
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
&.status-success {
|
||||
color: #52c41a;
|
||||
}
|
||||
|
||||
&.status-warning {
|
||||
color: #faad14;
|
||||
}
|
||||
|
||||
&.status-error {
|
||||
color: #ff4d4f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bottom-actions {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: #fff;
|
||||
padding: 15px;
|
||||
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.05);
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
|
||||
.action-btn {
|
||||
flex: 1;
|
||||
height: 44px;
|
||||
line-height: 44px;
|
||||
text-align: center;
|
||||
border-radius: 22px;
|
||||
font-size: 16px;
|
||||
|
||||
&.primary {
|
||||
background-color: #2879ff;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
&.secondary {
|
||||
background-color: #fff;
|
||||
color: #333;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -10,18 +10,38 @@
|
||||
|
||||
<!-- 可滚动的内容区域 -->
|
||||
<view class="scrollable-content">
|
||||
<JcBzList :xs-id="curXs.id" :can-selected="true" :multiple="true" @change="onJcBzChange" />
|
||||
<!-- 就餐标准选择器 -->
|
||||
<view class="form-section">
|
||||
<JcBzPicker
|
||||
:xs-id="curXs.id"
|
||||
label="就餐标准"
|
||||
placeholder="请选择就餐标准"
|
||||
:multiple="false"
|
||||
:required="true"
|
||||
v-model="selectedJcBzId"
|
||||
@change="onJcBzChange"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<!-- 选中标准的详情展示 -->
|
||||
<JcBzDetailCard
|
||||
v-if="selectedJcBz"
|
||||
:jc-bz-list="[selectedJcBz]"
|
||||
title="已选择的就餐标准"
|
||||
:show-detail-btn="true"
|
||||
:show-summary="false"
|
||||
@detail="goToDetail"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<!-- 底部操作区域 -->
|
||||
<view class="bottom-action">
|
||||
<view class="selected-info">
|
||||
<text>已选择:{{ selectedCount }} 个就餐标准</text>
|
||||
<text class="total-price">总金额:¥{{ totalPrice }}</text>
|
||||
<text class="total-price">缴费金额:¥{{ totalPrice }}</text>
|
||||
</view>
|
||||
<view class="action-buttons">
|
||||
<view class="cancel-btn" @click="goBack">取消</view>
|
||||
<view class="confirm-btn" @click="confirmBm" :class="{ disabled: selectedCount === 0 }">确认报名</view>
|
||||
<view class="confirm-btn" @click="confirmBm" :class="{ disabled: !selectedJcBzId }">确认报名</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@ -29,46 +49,72 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import XsPicker from "@/pages/base/components/XsPicker/index.vue"
|
||||
import JcBzList from "@/pages/base/components/JcBzList/index.vue"
|
||||
import JcBzPicker from "@/pages/base/components/JcBzPicker/index.vue"
|
||||
import JcBzDetailCard from "@/pages/base/components/JcBzDetailCard/index.vue"
|
||||
import { useUserStore } from "@/store/modules/user";
|
||||
import { useDataStore } from "@/store/modules/data";
|
||||
import { jcBmJcBzApi } from "@/api/base/jcApi";
|
||||
import { jcBmJcBzApi, jcGetJcBzListApi } from "@/api/base/jcApi";
|
||||
|
||||
const { getCurXs, getUser } = useUserStore();
|
||||
const { getData, setData } = useDataStore();
|
||||
|
||||
const curXs = computed(() => getCurXs);
|
||||
|
||||
// 选中的就餐标准ID列表
|
||||
const selectedJcBzIds = ref<string[]>([]);
|
||||
// 选中的就餐标准列表
|
||||
const selectedJcBzList = ref<any[]>([]);
|
||||
// 选中的就餐标准ID
|
||||
const selectedJcBzId = ref<string>('');
|
||||
// 选中的就餐标准详情
|
||||
const selectedJcBz = ref<any>(null);
|
||||
|
||||
// 选中数量
|
||||
const selectedCount = computed(() => selectedJcBzIds.value.length);
|
||||
|
||||
// 总金额
|
||||
// 缴费金额
|
||||
const totalPrice = computed(() => {
|
||||
let total = 0;
|
||||
selectedJcBzList.value.forEach(jcBz => {
|
||||
total += jcBz.jfje || 0;
|
||||
});
|
||||
return total;
|
||||
return selectedJcBz.value?.jfje || 0;
|
||||
});
|
||||
|
||||
// 就餐标准选择变更
|
||||
const onJcBzChange = (ids: string[]) => {
|
||||
selectedJcBzIds.value = ids;
|
||||
// 这里需要根据选中的ID获取对应的就餐标准详情
|
||||
// 实际项目中可能需要从本地存储或重新请求数据
|
||||
updateSelectedJcBzList();
|
||||
const onJcBzChange = (id: string) => {
|
||||
selectedJcBzId.value = id;
|
||||
// 根据选中的ID获取对应的就餐标准详情
|
||||
updateSelectedJcBz(id);
|
||||
};
|
||||
|
||||
// 更新选中的就餐标准列表
|
||||
const updateSelectedJcBzList = () => {
|
||||
// 这里需要根据selectedJcBzIds从本地存储或重新请求数据
|
||||
// 暂时使用空数组,实际项目中需要实现
|
||||
selectedJcBzList.value = [];
|
||||
// 更新选中的就餐标准详情
|
||||
const updateSelectedJcBz = async (id: string) => {
|
||||
if (!id) {
|
||||
selectedJcBz.value = null;
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 获取所有就餐标准列表
|
||||
const res = await jcGetJcBzListApi({
|
||||
xsId: curXs.value.id
|
||||
});
|
||||
|
||||
if (res.resultCode === 1) {
|
||||
// 处理返回的数据结构
|
||||
const result = res.result;
|
||||
const allJcBzList = result && result.jcBzList ? result.jcBzList : [];
|
||||
// 找到选中的就餐标准
|
||||
selectedJcBz.value = allJcBzList.find((jcBz: any) =>
|
||||
jcBz.id === id
|
||||
) || null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取就餐标准详情失败:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 跳转到详情页面
|
||||
const goToDetail = (jcBz: any) => {
|
||||
// 保存就餐标准数据到store
|
||||
setData({
|
||||
...getData,
|
||||
jcBzData: jcBz
|
||||
});
|
||||
// 跳转到详情页面
|
||||
uni.navigateTo({
|
||||
url: '/pages/base/jc/detail'
|
||||
});
|
||||
};
|
||||
|
||||
// 返回上一页
|
||||
@ -78,7 +124,7 @@ const goBack = () => {
|
||||
|
||||
// 确认报名
|
||||
const confirmBm = async () => {
|
||||
if (selectedCount.value === 0) {
|
||||
if (!selectedJcBzId.value) {
|
||||
uni.showToast({
|
||||
title: "请选择就餐标准",
|
||||
icon: "none",
|
||||
@ -89,9 +135,13 @@ const confirmBm = async () => {
|
||||
try {
|
||||
const res = await jcBmJcBzApi({
|
||||
xsId: curXs.value.id,
|
||||
jcBzIds: selectedJcBzIds.value,
|
||||
bzId: selectedJcBzId.value,
|
||||
jzId: getUser.jzId,
|
||||
userId: getUser.userId,
|
||||
njId: curXs.value.njId,
|
||||
njmcId: curXs.value.njmcId,
|
||||
njmc: curXs.value.njmc,
|
||||
bc: curXs.value.bc,
|
||||
xm: curXs.value.xsxm,
|
||||
});
|
||||
|
||||
if (res.resultCode === 1) {
|
||||
@ -104,8 +154,8 @@ const confirmBm = async () => {
|
||||
setData({
|
||||
...getData,
|
||||
xsId: curXs.value.id,
|
||||
jcBzIds: selectedJcBzIds.value,
|
||||
jcBzList: selectedJcBzList.value,
|
||||
jcBzIds: [selectedJcBzId.value],
|
||||
jcBzList: [selectedJcBz.value],
|
||||
totalJe: totalPrice.value,
|
||||
});
|
||||
|
||||
@ -113,12 +163,31 @@ const confirmBm = async () => {
|
||||
uni.redirectTo({
|
||||
url: '/pages/base/jc/pay/index'
|
||||
});
|
||||
} else {
|
||||
// 检查是否已经报名
|
||||
if (res.result?.message && res.result.message.includes('已报名')) {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '您已经报名了该就餐标准,是否查看报名详情?',
|
||||
success: (modalRes) => {
|
||||
if (modalRes.confirm) {
|
||||
// 跳转到报名详情页面
|
||||
uni.redirectTo({
|
||||
url: '/pages/base/jc/bm-detail'
|
||||
});
|
||||
} else {
|
||||
// 返回上一页
|
||||
uni.navigateBack();
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: res.result?.message || "报名失败",
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('报名失败:', error);
|
||||
uni.showToast({
|
||||
@ -169,6 +238,14 @@ onBeforeUnmount(() => {
|
||||
-webkit-overflow-scrolling: touch; // 增强iOS滚动体验
|
||||
}
|
||||
|
||||
.form-section {
|
||||
padding: 15px;
|
||||
background-color: #fff;
|
||||
margin: 15px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.bottom-action {
|
||||
background-color: #fff;
|
||||
padding: 15px;
|
||||
@ -176,7 +253,7 @@ onBeforeUnmount(() => {
|
||||
|
||||
.selected-info {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-bottom: 15px;
|
||||
font-size: 14px;
|
||||
@ -185,7 +262,7 @@ onBeforeUnmount(() => {
|
||||
.total-price {
|
||||
color: #ff6b00;
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
<view class="success-text">恭喜你,报名成功!</view>
|
||||
</view>
|
||||
|
||||
<!-- 这里显示学生信息和报名的就餐标准信息 -->
|
||||
<!-- TODO: 这里显示学生信息和报名的就餐标准信息 -->
|
||||
|
||||
</view>
|
||||
<template #bottom>
|
||||
|
||||
@ -40,7 +40,7 @@
|
||||
<script setup lang="ts">
|
||||
import XkPayXs from "@/pages/base/components/XkPayXs/index.vue"
|
||||
import XkPayXkqd from "@/pages/base/components/XkPayXkqd/index.vue"
|
||||
import { jzGetQkExpiredTime, jzXkCancelApi, jzXkFqJfjApi } from "@/api/base/server";
|
||||
import { jzGetQkExpiredTime, jzXkCancelApi, jzXkFqJfjApi } from "@/api/base/xkApi";
|
||||
import { useUserStore } from "@/store/modules/user";
|
||||
import { useDataStore } from "@/store/modules/data";
|
||||
const { getCurXs, getUser } = useUserStore();
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onLoad } from "@dcloudio/uni-app";
|
||||
import { jzGetQkExpiredTime, jzXkCancelApi, jzXkJfCxjApi } from "@/api/base/server";
|
||||
import { jzGetQkExpiredTime, jzXkCancelApi, jzXkJfCxjApi } from "@/api/base/xkApi";
|
||||
import { useUserStore } from "@/store/modules/user";
|
||||
import { useDataStore } from "@/store/modules/data";
|
||||
const { getCurXs, initWs, setWsCallback } = useUserStore();
|
||||
|
||||
@ -17,19 +17,12 @@
|
||||
|
||||
<!-- 可滚动的内容区域 -->
|
||||
<view class="scrollable-content">
|
||||
<!-- 如果当前选课已被选择,显示提示信息 -->
|
||||
<view v-if="curXk && curXk.selected" class="selected-notice">
|
||||
<view class="notice-content">
|
||||
<u-icon name="info-circle" color="#409EFF" size="24"></u-icon>
|
||||
<text class="notice-text">{{ curXk.message || '您已经选择了该选课下的课程,如果需要重新选课,请联系教师进行处理' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 如果当前选课未被选择,显示课程列表 -->
|
||||
<XkkcList v-else :xk="curXk" :can-selected="true" :multiple="true" @change="changeXkkc" />
|
||||
<!-- 显示课程列表 -->
|
||||
<XkkcList :xk="curXk" :can-selected="true" :multiple="true" @change="changeXkkc" />
|
||||
</view>
|
||||
|
||||
<!-- 底部报名按钮 - 固定部分 -->
|
||||
<view class="register-btn-container" v-if="curXk && !curXk.selected">
|
||||
<view class="register-btn-container" v-if="curXk && curXk.id">
|
||||
<view class="selected-count-info" v-if="selectedXkkcIds && selectedXkkcIds.length > 0">
|
||||
已选 {{ selectedXkkcIds.length }} 门课程
|
||||
</view>
|
||||
@ -43,7 +36,7 @@ import XsPicker from "@/pages/base/components/XsPicker/index.vue"
|
||||
import XkPicker from "@/pages/base/components/XkPicker/index.vue"
|
||||
import XkCountdown from "@/pages/base/components/XkCountdown/index.vue"
|
||||
import XkkcList from "@/pages/base/components/XkkcList/index.vue"
|
||||
import { jzXkQkjApi } from "@/api/base/server";
|
||||
import { jzXkQkjApi } from "@/api/base/xkApi";
|
||||
import { useUserStore } from "@/store/modules/user";
|
||||
import { useDataStore } from "@/store/modules/data";
|
||||
import dayjs from "dayjs";
|
||||
@ -116,15 +109,6 @@ const submit = async () => {
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查当前选课是否已被选择
|
||||
if (curXk.value && curXk.value.selected) {
|
||||
uni.showToast({
|
||||
title: "您已经选择了该选课下的课程,如需重新选课,请联系教师进行处理",
|
||||
icon: "none",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查选课时间
|
||||
if (curXk.value && curXk.value.xkkstime) {
|
||||
const now = dayjs().valueOf();
|
||||
@ -281,28 +265,6 @@ const submit = async () => {
|
||||
-webkit-overflow-scrolling: touch; // 增强iOS滚动体验
|
||||
}
|
||||
|
||||
// 已选择提示信息样式
|
||||
.selected-notice {
|
||||
padding: 20px 15px;
|
||||
|
||||
.notice-content {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 12px;
|
||||
background: linear-gradient(135deg, #e3f2fd, #f3e5f5);
|
||||
padding: 16px;
|
||||
border-radius: 12px;
|
||||
border-left: 4px solid #409EFF;
|
||||
|
||||
.notice-text {
|
||||
flex: 1;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.register-btn-container {
|
||||
position: sticky;
|
||||
bottom: 0;
|
||||
|
||||
@ -3,40 +3,171 @@
|
||||
<!-- 选课信息头部 - 固定部分 -->
|
||||
<view class="selection-header">
|
||||
<view class="header-content">
|
||||
<!-- 选课类型选择部分 -->
|
||||
<XkPicker title="兴趣课信息" :is-qk="false" xklx-id="962488654" :xs-id="curXs.id" @change="switchXk" />
|
||||
<!-- 学生选择部分 -->
|
||||
<XsPicker :is-bar="true" />
|
||||
<!-- 第一行:选课类型选择 -->
|
||||
<view class="top-row" v-if="!xsFlag">
|
||||
<XkPicker title="兴趣课信息" :is-qk="true" xklx-id="962488654" :xs-id="curXs.id" @change="switchXk" />
|
||||
</view>
|
||||
<!-- 第二行:学生选择和倒计时 -->
|
||||
<view class="bottom-row">
|
||||
<XsPicker :is-bar="true" @change="switchXs" />
|
||||
<XkCountdown :xk="curXk" @over="xkTimeOver" v-if="curXk && curXk.id" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 可滚动的内容区域 -->
|
||||
<view class="scrollable-content">
|
||||
<XkkcList :xk="curXk" />
|
||||
<!-- 显示课程列表 -->
|
||||
<XkkcList :xk="curXk" :can-selected="true" :multiple="false" @change="changeXkkc" />
|
||||
</view>
|
||||
|
||||
<!-- 底部报名按钮 - 固定部分 -->
|
||||
<view class="register-btn-container" v-if="curXk && curXk.id">
|
||||
<view class="selected-count-info" v-if="selectedXkkcIds && selectedXkkcIds.length > 0">
|
||||
已选 {{ selectedXkkcIds.length }} 门课程
|
||||
</view>
|
||||
<view class="register-btn" @click="submit">点击报名</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import XsPicker from "@/pages/base/components/XsPicker/index.vue"
|
||||
import XkPicker from "@/pages/base/components/XkPicker/index.vue"
|
||||
import XkCountdown from "@/pages/base/components/XkCountdown/index.vue"
|
||||
import XkkcList from "@/pages/base/components/XkkcList/index.vue"
|
||||
import { jzXkQkjApi } from "@/api/base/xkApi";
|
||||
import { useUserStore } from "@/store/modules/user";
|
||||
import { useDataStore } from "@/store/modules/data";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
const { getCurXs } = useUserStore();
|
||||
const { getCurXs, getUser } = useUserStore();
|
||||
const { setData, getData } = useDataStore();
|
||||
const { sign_file } = getData;
|
||||
|
||||
const curXs = computed(() => getCurXs);
|
||||
|
||||
const curXk = ref<any>({});
|
||||
const selectedXkkcIds = ref<any>([]);
|
||||
|
||||
const xsFlag = ref(true);
|
||||
|
||||
// 检查选课是否已结束
|
||||
const checkEnrollmentStatus = (xk: any) => {
|
||||
if (!xk || !xk.xkjstime) return;
|
||||
|
||||
const now = new Date().getTime();
|
||||
const endTime = new Date(xk.xkjstime).getTime();
|
||||
|
||||
if (now > endTime) {
|
||||
// 选课已结束,跳转到结束页面
|
||||
const courseInfo = encodeURIComponent(JSON.stringify(xk));
|
||||
uni.navigateTo({
|
||||
url: `/pages/base/xk/qk/yjz?courseInfo=${courseInfo}`
|
||||
});
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
// 切换选课
|
||||
const switchXk = (xk: any) => {
|
||||
curXk.value = xk;
|
||||
// 清空之前的选择状态
|
||||
selectedXkkcIds.value = [];
|
||||
uni.setStorageSync("selectedXkkcIds", []);
|
||||
|
||||
// 检查选课状态
|
||||
if (checkEnrollmentStatus(xk)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const switchXs = (xs: any) => {
|
||||
xsFlag.value = false;
|
||||
}
|
||||
|
||||
// 选课时间结束
|
||||
const xkTimeOver = (val: any) => {
|
||||
console.log('选课时间结束:', val);
|
||||
// 选课开始时不再跳转,让用户继续选课
|
||||
// 只有在选课结束时才跳转到选课结束页面
|
||||
}
|
||||
|
||||
// 选中课程
|
||||
const changeXkkc = (ids: any) => {
|
||||
selectedXkkcIds.value = ids;
|
||||
}
|
||||
|
||||
// 提交选课
|
||||
const submit = async () => {
|
||||
// 判断是否已选课
|
||||
if (selectedXkkcIds.value.length === 0) {
|
||||
uni.showToast({
|
||||
title: "请选择课程!",
|
||||
icon: "none",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查选课时间
|
||||
if (curXk.value && curXk.value.xkkstime) {
|
||||
const now = dayjs().valueOf();
|
||||
const startTime = dayjs(curXk.value.xkkstime).valueOf();
|
||||
|
||||
if (now < startTime) {
|
||||
uni.showToast({
|
||||
title: "选课还未开始,请耐心等待!",
|
||||
icon: "none",
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
uni.showLoading({
|
||||
title: "抢课中...",
|
||||
});
|
||||
const params = {
|
||||
xsId: curXs.value.id,
|
||||
xm: curXs.value.xm,
|
||||
njmc: curXs.value.njmc,
|
||||
njmcId: curXs.value.njmcId,
|
||||
njId: curXs.value.njId,
|
||||
bc: (curXs.value.njbc || '') + (curXs.value.bjmc || ''),
|
||||
xkId: curXk.value.id,
|
||||
xkkcIds: selectedXkkcIds.value,
|
||||
jzId: getUser.jzId,
|
||||
qmFile: sign_file ? sign_file.value : "",
|
||||
};
|
||||
const res = await jzXkQkjApi(params);
|
||||
uni.hideLoading();
|
||||
if (res.resultCode === 1) {
|
||||
selectedXkkcIds.value = [];
|
||||
uni.setStorageSync("selectedXkkcIds", []);
|
||||
res.result.backUrl = "/pages/base/xk/qk/xqk";
|
||||
setData(res.result);
|
||||
xsFlag.value = true;
|
||||
setTimeout(() => {
|
||||
xsFlag.value = false;
|
||||
}, 1000);
|
||||
if (curXk.value.sfjf === 1) {
|
||||
// 跳转到支付页面
|
||||
uni.navigateTo({
|
||||
url: "/pages/base/xk/pay/index",
|
||||
});
|
||||
} else {
|
||||
// 不需要支付,直接跳转到支付成功页面
|
||||
uni.navigateTo({
|
||||
url: "/pages/base/xk/pay/success",
|
||||
});
|
||||
}
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: res.message,
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 页面卸载前清除定时器
|
||||
onBeforeUnmount(() => {
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@ -94,6 +225,36 @@ onBeforeUnmount(() => {
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
|
||||
.top-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
:deep(.title-section) {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.bottom-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 15px;
|
||||
|
||||
// 学生选择器样式
|
||||
:deep(.xs-bar) {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
// 倒计时组件样式
|
||||
:deep(.countdown-section) {
|
||||
flex-shrink: 0;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border-radius: 6px;
|
||||
padding: 6px 10px;
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -104,4 +265,32 @@ onBeforeUnmount(() => {
|
||||
-webkit-overflow-scrolling: touch; // 增强iOS滚动体验
|
||||
}
|
||||
|
||||
.register-btn-container {
|
||||
position: sticky;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
padding: 15px;
|
||||
background-color: #fff;
|
||||
z-index: 1;
|
||||
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.05);
|
||||
|
||||
.selected-count-info {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.register-btn {
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
text-align: center;
|
||||
background-color: #2879ff;
|
||||
color: #fff;
|
||||
border-radius: 25px;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@ -19,25 +19,9 @@ import { checkOpenId } from "@/api/system/login";
|
||||
import { refreshPermissionCache } from "@/utils/permission";
|
||||
|
||||
const { setGlobal } = useDataStore();
|
||||
const { afterLoginAction } = useUserStore();
|
||||
const userStore = useUserStore();
|
||||
const isShow = ref(true);
|
||||
|
||||
function toHome(data: any) {
|
||||
if (data.type == 1) {
|
||||
uni.reLaunch({
|
||||
url: "/pages/base/gzs/xkXqk",
|
||||
});
|
||||
} if (data.type == 2) {
|
||||
uni.reLaunch({
|
||||
url: "/pages/base/gzs/xkJlb",
|
||||
});
|
||||
} else {
|
||||
uni.reLaunch({
|
||||
url: "/pages/base/home/index",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onLoad(async (data: any) => {
|
||||
setGlobal(data);
|
||||
if (data && data.openId) {
|
||||
@ -46,20 +30,18 @@ onLoad(async (data: any) => {
|
||||
|
||||
if (res.resultCode == 1 && res.result) {
|
||||
// 执行登录操作
|
||||
afterLoginAction(res.result);
|
||||
userStore.afterLoginAction(res.result);
|
||||
|
||||
// 如果有changeTime参数,更新权限缓存
|
||||
if (data.changeTime) {
|
||||
const userStore = useUserStore();
|
||||
const currentPermissions = userStore.getAuth;
|
||||
|
||||
if (currentPermissions && currentPermissions.length > 0) {
|
||||
refreshPermissionCache(currentPermissions, data.changeTime);
|
||||
}
|
||||
}
|
||||
|
||||
// 直接跳转到首页,关注检查在首页进行
|
||||
toHome(data);
|
||||
userStore.toHome(data.type);
|
||||
} else {
|
||||
uni.reLaunch({
|
||||
url: "/pages/system/login/login",
|
||||
|
||||
@ -266,24 +266,8 @@ function removeStudent(index: number) {
|
||||
}
|
||||
}
|
||||
|
||||
function toHome() {
|
||||
if (getGlobal.type == 1) {
|
||||
uni.reLaunch({
|
||||
url: "/pages/base/gzs/xkXqk",
|
||||
});
|
||||
} else if (getGlobal.type == 2) {
|
||||
uni.reLaunch({
|
||||
url: "/pages/base/gzs/xkJlb",
|
||||
});
|
||||
} else {
|
||||
uni.reLaunch({
|
||||
url: "/pages/base/home/index",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const { getGlobal, getAppCode } = useDataStore();
|
||||
const { afterLoginAction } = useUserStore();
|
||||
const userStore = useUserStore();
|
||||
async function submit() {
|
||||
for (const student of students.value) {
|
||||
if (!student.xstx) {
|
||||
@ -313,19 +297,16 @@ async function submit() {
|
||||
});
|
||||
hideLoading();
|
||||
if (res.resultCode == 1) {
|
||||
afterLoginAction(res.result);
|
||||
|
||||
userStore.afterLoginAction(res.result);
|
||||
// 如果有changeTime参数,更新权限缓存
|
||||
if (res.result && res.result.changeTime) {
|
||||
const userStore = useUserStore();
|
||||
const currentPermissions = userStore.getAuth;
|
||||
|
||||
if (currentPermissions && currentPermissions.length > 0) {
|
||||
refreshPermissionCache(currentPermissions, res.result.changeTime);
|
||||
}
|
||||
}
|
||||
|
||||
toHome();
|
||||
userStore.toHome(getGlobal.type);
|
||||
} else {
|
||||
showToast({ title: res.message || "提交失败", icon: "none" });
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { defineStore } from "pinia";
|
||||
import { authenticationApi, loginCode, loginPass, weChatLogin, checkOpenId } from "@/api/system/login";
|
||||
import { checkXsXkByTypeApi, xsKxApi } from "@/api/base/xkApi";
|
||||
import { AUTH_KEY } from "@/config";
|
||||
import { imagUrl } from "@/utils";
|
||||
import { useWebSocket } from '@/utils/webSocket/webSocket'
|
||||
@ -194,6 +195,192 @@ export const useUserStore = defineStore({
|
||||
}
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 跳转逻辑
|
||||
* @param type 跳转类型
|
||||
*/
|
||||
async toHome(type: number) {
|
||||
if (type == 1) {
|
||||
// 兴趣课逻辑: 判断当前学生列表
|
||||
if (this.userdata.xsList && this.userdata.xsList.length === 1) {
|
||||
this.checkXqk();
|
||||
} else if (this.userdata.xsList && this.userdata.xsList.length > 1) {
|
||||
uni.reLaunch({
|
||||
url: "/pages/base/home/xsXz",
|
||||
});
|
||||
}
|
||||
} else if (type == 2) {
|
||||
// 俱乐部逻辑: 判断当前学生列表
|
||||
if (this.userdata.xsList && this.userdata.xsList.length == 1) {
|
||||
this.checkJlb();
|
||||
} else if (this.userdata.xsList && this.userdata.xsList.length > 1) {
|
||||
uni.reLaunch({
|
||||
url: "/pages/base/home/xsXz",
|
||||
});
|
||||
}
|
||||
} else {
|
||||
uni.reLaunch({
|
||||
url: "/pages/base/home/index",
|
||||
});
|
||||
}
|
||||
},
|
||||
// 校验兴趣课 - 优化版本
|
||||
async checkXqk() {
|
||||
try {
|
||||
// 使用getXsKx接口获取详细选课信息
|
||||
const res = await xsKxApi({
|
||||
xsId: this.curXs.id,
|
||||
njmcId: this.curXs.njmcId,
|
||||
xklxId: "962488654" // 兴趣课类型ID
|
||||
});
|
||||
|
||||
if (res.resultCode === 1) {
|
||||
const data = res.result;
|
||||
const type = data.type;
|
||||
|
||||
switch (type) {
|
||||
case 1: // 待支付
|
||||
uni.reLaunch({
|
||||
url: "/pages/base/xk/pay/index",
|
||||
});
|
||||
return;
|
||||
case 2: // 可选课列表 - 跳转到抢课页面
|
||||
uni.reLaunch({
|
||||
url: "/pages/base/xk/qk/xqk",
|
||||
});
|
||||
return;
|
||||
case 3: // 已支付 - 跳转到详情页
|
||||
uni.reLaunch({
|
||||
url: "/pages/base/xk/xqk",
|
||||
});
|
||||
return;
|
||||
default:
|
||||
// 默认跳转到告知书页面
|
||||
uni.reLaunch({
|
||||
url: "/pages/base/gzs/xqk",
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 接口调用失败,使用备用方案
|
||||
this.checkXqkFallback();
|
||||
} catch (error) {
|
||||
console.error("查询兴趣课状态失败:", error);
|
||||
// 异常情况,使用备用方案
|
||||
this.checkXqkFallback();
|
||||
}
|
||||
},
|
||||
// 兴趣课备用检查方案
|
||||
async checkXqkFallback() {
|
||||
try {
|
||||
const res = await checkXsXkByTypeApi({
|
||||
xsId: this.curXs.id,
|
||||
xklxId: "962488654" // 兴趣课类型ID
|
||||
});
|
||||
if (res.resultCode === 1) {
|
||||
const checkResult = res.result;
|
||||
if (checkResult === 1) {
|
||||
uni.reLaunch({
|
||||
url: "/pages/base/xk/pay/index",
|
||||
});
|
||||
return;
|
||||
} else if (checkResult === 2) {
|
||||
uni.reLaunch({
|
||||
url: "/pages/base/xk/xqk",
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
uni.reLaunch({
|
||||
url: "/pages/base/gzs/xqk",
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("备用方案也失败:", error);
|
||||
uni.reLaunch({
|
||||
url: "/pages/base/gzs/xqk",
|
||||
});
|
||||
}
|
||||
},
|
||||
// 校验俱乐部 - 优化版本
|
||||
async checkJlb() {
|
||||
try {
|
||||
// 使用getXsKx接口获取详细选课信息
|
||||
const res = await xsKxApi({
|
||||
xsId: this.curXs.id,
|
||||
njmcId: this.curXs.njmcId,
|
||||
xklxId: "816059832" // 俱乐部类型ID
|
||||
});
|
||||
|
||||
if (res.resultCode === 1) {
|
||||
const data = res.result;
|
||||
const type = data.type;
|
||||
|
||||
switch (type) {
|
||||
case 1: // 待支付
|
||||
uni.reLaunch({
|
||||
url: "/pages/base/xk/pay/index",
|
||||
});
|
||||
return;
|
||||
case 2: // 可选课列表 - 跳转到抢课页面
|
||||
uni.reLaunch({
|
||||
url: "/pages/base/xk/qk/jlb",
|
||||
});
|
||||
return;
|
||||
case 3: // 已支付 - 跳转到详情页
|
||||
uni.reLaunch({
|
||||
url: "/pages/base/xk/jlb",
|
||||
});
|
||||
return;
|
||||
default:
|
||||
// 默认跳转到告知书页面
|
||||
uni.reLaunch({
|
||||
url: "/pages/base/gzs/jlb",
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 接口调用失败,使用备用方案
|
||||
this.checkJlbFallback();
|
||||
} catch (error) {
|
||||
console.error("查询俱乐部状态失败:", error);
|
||||
// 异常情况,使用备用方案
|
||||
this.checkJlbFallback();
|
||||
}
|
||||
},
|
||||
// 俱乐部备用检查方案
|
||||
async checkJlbFallback() {
|
||||
try {
|
||||
const res = await checkXsXkByTypeApi({
|
||||
xsId: this.curXs.id,
|
||||
xklxId: "816059832" // 俱乐部类型ID
|
||||
});
|
||||
|
||||
if (res.resultCode === 1) {
|
||||
const checkResult = res.result;
|
||||
if (checkResult === 1) {
|
||||
uni.reLaunch({
|
||||
url: "/pages/base/xk/pay/index",
|
||||
});
|
||||
return;
|
||||
} else if (checkResult === 2) {
|
||||
uni.reLaunch({
|
||||
url: "/pages/base/xk/jlb",
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
uni.reLaunch({
|
||||
url: "/pages/base/gzs/jlb",
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("备用方案也失败:", error);
|
||||
uni.reLaunch({
|
||||
url: "/pages/base/gzs/jlb",
|
||||
});
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @description: 注销
|
||||
*/
|
||||
|
||||
95
src/utils/xkUtils.ts
Normal file
95
src/utils/xkUtils.ts
Normal file
@ -0,0 +1,95 @@
|
||||
import { getXsXkStatusApi } from "@/api/base/xkApi";
|
||||
import { useUserStore } from "@/store/modules/user";
|
||||
|
||||
/**
|
||||
* 抢课工具类
|
||||
*/
|
||||
export class XkUtils {
|
||||
/**
|
||||
* 检查学生选课状态
|
||||
* @param xklxId 选课类型ID
|
||||
* @returns 选课状态信息
|
||||
*/
|
||||
static async checkXkStatus(xklxId: string) {
|
||||
const userStore = useUserStore();
|
||||
const curXs = userStore.getCurXs;
|
||||
|
||||
try {
|
||||
const res = await getXsXkStatusApi({
|
||||
xsId: curXs.id,
|
||||
njmcId: curXs.njmcId,
|
||||
xklxId: xklxId
|
||||
});
|
||||
|
||||
if (res.resultCode === 1) {
|
||||
return res.result;
|
||||
}
|
||||
return null;
|
||||
} catch (error) {
|
||||
console.error("检查选课状态失败:", error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取选课状态描述
|
||||
* @param type 状态类型
|
||||
* @returns 状态描述
|
||||
*/
|
||||
static getStatusDescription(type: number): string {
|
||||
switch (type) {
|
||||
case 1:
|
||||
return "有待支付的选课,请先完成支付";
|
||||
case 2:
|
||||
return "可以选择的课程";
|
||||
case 3:
|
||||
return "已选择并完成支付的选课";
|
||||
default:
|
||||
return "暂无可选课程";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否可以抢课
|
||||
* @param xkList 选课列表
|
||||
* @returns 是否可以抢课
|
||||
*/
|
||||
static canQk(xkList: any[]): boolean {
|
||||
if (!xkList || xkList.length === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查是否有可选的课程
|
||||
return xkList.some((xk: any) => {
|
||||
return !xk.selected && xk.xkkcs && xk.xkkcs.length > 0;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取可抢课的选课列表
|
||||
* @param xkList 选课列表
|
||||
* @returns 可抢课的选课列表
|
||||
*/
|
||||
static getAvailableXkList(xkList: any[]): any[] {
|
||||
if (!xkList || xkList.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return xkList.filter((xk: any) => {
|
||||
return !xk.selected && xk.xkkcs && xk.xkkcs.length > 0;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取已选课的选课信息
|
||||
* @param xkList 选课列表
|
||||
* @returns 已选课的选课信息
|
||||
*/
|
||||
static getSelectedXk(xkList: any[]): any | null {
|
||||
if (!xkList || xkList.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return xkList.find((xk: any) => xk.selected) || null;
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user