添加就餐相关页面
This commit is contained in:
parent
9ffab44ca4
commit
a27e4e8a40
92
src/api/base/jcApi.ts
Normal file
92
src/api/base/jcApi.ts
Normal file
@ -0,0 +1,92 @@
|
||||
import { get, post } from "@/utils/request";
|
||||
|
||||
/**
|
||||
* 获取就餐标准列表
|
||||
*/
|
||||
export const jcGetJcBzListApi = async (params: any) => {
|
||||
return await get("/mobile/jc/getJcBzList", params);
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取就餐标准详情
|
||||
*/
|
||||
export const jcGetJcBzDetailApi = async (params: any) => {
|
||||
return await get("/mobile/jc/getJcBzDetail", params);
|
||||
};
|
||||
|
||||
/**
|
||||
* 学生报名就餐标准
|
||||
*/
|
||||
export const jcBmJcBzApi = async (params: any) => {
|
||||
return await post("/mobile/jc/bmJcBz", params);
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取学生已报名的就餐标准列表
|
||||
*/
|
||||
export const jcGetXsBmJcBzListApi = async (params: any) => {
|
||||
return await get("/mobile/jc/getXsBmJcBzList", params);
|
||||
};
|
||||
|
||||
/**
|
||||
* 取消报名就餐标准
|
||||
*/
|
||||
export const jcCancelBmJcBzApi = async (params: any) => {
|
||||
return await post("/mobile/jc/cancelBmJcBz", params);
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取就餐标准报名倒计时
|
||||
*/
|
||||
export const jcGetBmExpiredTimeApi = async (params: any) => {
|
||||
return await get("/mobile/jc/getBmExpiredTime", params);
|
||||
};
|
||||
|
||||
/**
|
||||
* 发起就餐标准缴费
|
||||
*/
|
||||
export const jcFqJcBzJfjApi = async (params: any) => {
|
||||
return await post("/mobile/jc/fqJcBzJfj", params);
|
||||
};
|
||||
|
||||
/**
|
||||
* 查询就餐标准缴费状态
|
||||
*/
|
||||
export const jcJcBzJfCxjApi = async (params: any) => {
|
||||
return await post("/mobile/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");
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取学生就餐记录
|
||||
*/
|
||||
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);
|
||||
};
|
||||
265
src/pages/base/components/JcBzList/index.vue
Normal file
265
src/pages/base/components/JcBzList/index.vue
Normal file
@ -0,0 +1,265 @@
|
||||
<template>
|
||||
<view>
|
||||
<!-- 就餐标准网格列表 -->
|
||||
<view class="jc-bz-grid" v-if="jcBzList.length > 0">
|
||||
<view
|
||||
v-for="(jcBz, index) in jcBzList"
|
||||
:key="jcBz.id || index"
|
||||
class="jc-bz-item"
|
||||
:class="{ selected: jcBz.isSelected }"
|
||||
@click="toggleSelection(jcBz)"
|
||||
>
|
||||
<view class="jc-bz-header">
|
||||
<view class="jc-bz-name">{{ jcBz.bzmc }}</view>
|
||||
<view class="detail-btn" @click.stop="goToDetail(jcBz)">
|
||||
<image src="/static/base/home/details.svg" class="detail-icon" />
|
||||
</view>
|
||||
</view>
|
||||
<view class="jc-bz-info">
|
||||
<view class="jc-bz-price">
|
||||
<text>价格:</text>
|
||||
<text class="price-value">¥{{ jcBz.jfje }}</text>
|
||||
</view>
|
||||
<view class="jc-bz-desc">{{ jcBz.bzms || '暂无描述' }}</view>
|
||||
</view>
|
||||
<view v-if="jcBz.isSelected" class="selected-mark">
|
||||
<uni-icons
|
||||
type="checkbox-filled"
|
||||
color="#3FBF72"
|
||||
size="22"
|
||||
></uni-icons>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 暂无数据提示 -->
|
||||
<view v-else class="empty-jc-bz-list">
|
||||
<view class="empty-icon">
|
||||
<u-icon name="list" size="50" color="#C8C9CC"></u-icon>
|
||||
</view>
|
||||
<view class="empty-text">暂无就餐标准数据</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, watch, onMounted } from "vue";
|
||||
import { useDataStore } from "@/store/modules/data";
|
||||
import { jcGetJcBzListApi } from "@/api/base/jcApi";
|
||||
const { setJcBzData } = useDataStore();
|
||||
|
||||
// 接收外部传入属性并设置默认值
|
||||
const props = withDefaults(defineProps<{
|
||||
xsId: string,
|
||||
canSelected: boolean,
|
||||
multiple: boolean,
|
||||
}>(), {
|
||||
xsId: '',
|
||||
canSelected: false,
|
||||
multiple: false,
|
||||
});
|
||||
|
||||
// 定义一个上级传入的emit响应事件用于接收数据变更
|
||||
const emit = defineEmits(['change'])
|
||||
|
||||
// 就餐标准列表数据
|
||||
const jcBzList = ref<any>([]);
|
||||
|
||||
// 获取就餐标准列表
|
||||
const getJcBzList = async () => {
|
||||
try {
|
||||
const res = await jcGetJcBzListApi({
|
||||
xsId: props.xsId
|
||||
});
|
||||
if (res.resultCode === 1) {
|
||||
jcBzList.value = res.result || [];
|
||||
// 初始化选中状态
|
||||
initSelectedStatus();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取就餐标准列表失败:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 初始化选中状态
|
||||
const initSelectedStatus = () => {
|
||||
// 获取本地存储的已选就餐标准ID数组
|
||||
let selectedJcBzIds = uni.getStorageSync("selectedJcBzIds") || [];
|
||||
|
||||
jcBzList.value.forEach((jcBz: any) => {
|
||||
jcBz.isSelected = selectedJcBzIds.includes(jcBz.id);
|
||||
});
|
||||
};
|
||||
|
||||
// 切换选餐标准
|
||||
const toggleSelection = (jcBz: any) => {
|
||||
if (!props.canSelected) {
|
||||
return;
|
||||
}
|
||||
// 获取本地存储的已选就餐标准ID数组
|
||||
let selectedJcBzIds = uni.getStorageSync("selectedJcBzIds") || [];
|
||||
if (jcBz.isSelected) {
|
||||
jcBz.isSelected = false;
|
||||
if (props.multiple) {
|
||||
// 如果是多选,则从已选数组中移除
|
||||
selectedJcBzIds = selectedJcBzIds.filter(
|
||||
(id: string) => id !== jcBz.id
|
||||
);
|
||||
} else {
|
||||
// 如果是单选,则清空已选数组
|
||||
selectedJcBzIds = [];
|
||||
}
|
||||
} else {
|
||||
if (props.multiple) {
|
||||
// 如果是多选,则添加到已选数组
|
||||
if (!selectedJcBzIds.includes(jcBz.id)) {
|
||||
selectedJcBzIds.push(jcBz.id);
|
||||
}
|
||||
} else {
|
||||
// 如果是单选,则清空已选数组并添加当前标准
|
||||
selectedJcBzIds = [jcBz.id];
|
||||
// 清理选中状态
|
||||
jcBzList.value.forEach((jcBz: any) => {
|
||||
jcBz.isSelected = false;
|
||||
});
|
||||
}
|
||||
jcBz.isSelected = true;
|
||||
}
|
||||
// 更新本地存储
|
||||
uni.setStorageSync("selectedJcBzIds", selectedJcBzIds);
|
||||
emit("change", selectedJcBzIds);
|
||||
}
|
||||
|
||||
const goToDetail = (jcBz: any) => {
|
||||
setJcBzData(jcBz);
|
||||
uni.navigateTo({
|
||||
url: `/pages/base/jc/detail`,
|
||||
});
|
||||
};
|
||||
|
||||
// 监听学生ID变更
|
||||
watch(() => props.xsId, (newVal) => {
|
||||
if (newVal) {
|
||||
getJcBzList();
|
||||
}
|
||||
});
|
||||
|
||||
// 初始化
|
||||
onMounted(() => {
|
||||
if (props.xsId) {
|
||||
getJcBzList();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.jc-bz-grid {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
padding: 15px 15px 0 15px;
|
||||
|
||||
.jc-bz-item {
|
||||
position: relative;
|
||||
width: calc(50% - 10px);
|
||||
margin-bottom: 15px;
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
padding: 15px;
|
||||
box-sizing: border-box;
|
||||
border: 1px solid transparent;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:nth-child(odd) {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
&:nth-child(even) {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
&.selected {
|
||||
border: 1px solid #3fbf72;
|
||||
background-color: rgba(63, 191, 114, 0.05);
|
||||
box-shadow: 0 2px 8px rgba(63, 191, 114, 0.15);
|
||||
}
|
||||
|
||||
.jc-bz-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 10px;
|
||||
|
||||
.jc-bz-name {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
flex: 1;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.detail-btn {
|
||||
flex-shrink: 0;
|
||||
padding: 4px;
|
||||
|
||||
.detail-icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.jc-bz-info {
|
||||
.jc-bz-price {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
margin-bottom: 8px;
|
||||
|
||||
.price-value {
|
||||
color: #ff6b00;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.jc-bz-desc {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
line-height: 1.4;
|
||||
}
|
||||
}
|
||||
|
||||
.selected-mark {
|
||||
position: absolute;
|
||||
top: -6px;
|
||||
right: -6px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 暂无数据样式
|
||||
.empty-jc-bz-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 60px 20px;
|
||||
text-align: center;
|
||||
|
||||
.empty-icon {
|
||||
margin-bottom: 20px;
|
||||
background-color: #f5f6f7;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
color: #303133;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
221
src/pages/base/components/JcRecordList/index.vue
Normal file
221
src/pages/base/components/JcRecordList/index.vue
Normal file
@ -0,0 +1,221 @@
|
||||
<template>
|
||||
<view>
|
||||
<!-- 就餐记录列表 -->
|
||||
<view class="jc-record-list" v-if="jcRecordList.length > 0">
|
||||
<view
|
||||
v-for="(record, index) in jcRecordList"
|
||||
:key="record.id || index"
|
||||
class="record-item"
|
||||
>
|
||||
<view class="record-header">
|
||||
<view class="record-date">{{ formatDate(record.jcDate) }}</view>
|
||||
<view class="record-status" :class="getStatusClass(record.status)">
|
||||
{{ getStatusText(record.status) }}
|
||||
</view>
|
||||
</view>
|
||||
<view class="record-content">
|
||||
<view class="record-info">
|
||||
<view class="record-bz">{{ record.bzmc }}</view>
|
||||
<view class="record-time">{{ record.jcTime }}</view>
|
||||
</view>
|
||||
<view class="record-price">¥{{ record.jfje }}</view>
|
||||
</view>
|
||||
<view class="record-footer">
|
||||
<view class="record-location">{{ record.jcLocation || '暂无地点信息' }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 暂无数据提示 -->
|
||||
<view v-else class="empty-record-list">
|
||||
<view class="empty-icon">
|
||||
<u-icon name="list" size="50" color="#C8C9CC"></u-icon>
|
||||
</view>
|
||||
<view class="empty-text">暂无就餐记录</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, watch, onMounted } from "vue";
|
||||
import { jcGetXsJcJlApi } from "@/api/base/jcApi";
|
||||
|
||||
// 接收外部传入属性并设置默认值
|
||||
const props = withDefaults(defineProps<{
|
||||
xsId: string,
|
||||
}>(), {
|
||||
xsId: '',
|
||||
});
|
||||
|
||||
// 就餐记录列表数据
|
||||
const jcRecordList = ref<any>([]);
|
||||
|
||||
// 获取就餐记录列表
|
||||
const getJcRecordList = async () => {
|
||||
try {
|
||||
const res = await jcGetXsJcJlApi({
|
||||
xsId: props.xsId
|
||||
});
|
||||
if (res.resultCode === 1) {
|
||||
jcRecordList.value = res.result || [];
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取就餐记录失败:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 格式化日期
|
||||
const formatDate = (dateStr: string) => {
|
||||
if (!dateStr) return '';
|
||||
const date = new Date(dateStr);
|
||||
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
|
||||
};
|
||||
|
||||
// 获取状态样式类
|
||||
const getStatusClass = (status: string) => {
|
||||
switch (status) {
|
||||
case '1': return 'status-success';
|
||||
case '2': return 'status-pending';
|
||||
case '3': return 'status-cancelled';
|
||||
default: return 'status-default';
|
||||
}
|
||||
};
|
||||
|
||||
// 获取状态文本
|
||||
const getStatusText = (status: string) => {
|
||||
switch (status) {
|
||||
case '1': return '已完成';
|
||||
case '2': return '进行中';
|
||||
case '3': return '已取消';
|
||||
default: return '未知状态';
|
||||
}
|
||||
};
|
||||
|
||||
// 监听学生ID变更
|
||||
watch(() => props.xsId, (newVal) => {
|
||||
if (newVal) {
|
||||
getJcRecordList();
|
||||
}
|
||||
});
|
||||
|
||||
// 初始化
|
||||
onMounted(() => {
|
||||
if (props.xsId) {
|
||||
getJcRecordList();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.jc-record-list {
|
||||
padding: 15px;
|
||||
|
||||
.record-item {
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
padding: 15px;
|
||||
margin-bottom: 15px;
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05);
|
||||
|
||||
.record-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
|
||||
.record-date {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.record-status {
|
||||
font-size: 12px;
|
||||
padding: 2px 8px;
|
||||
border-radius: 10px;
|
||||
|
||||
&.status-success {
|
||||
background-color: #f0f9ff;
|
||||
color: #3fbf72;
|
||||
}
|
||||
|
||||
&.status-pending {
|
||||
background-color: #fff7e6;
|
||||
color: #ff8c00;
|
||||
}
|
||||
|
||||
&.status-cancelled {
|
||||
background-color: #fff2f0;
|
||||
color: #ff4d4f;
|
||||
}
|
||||
|
||||
&.status-default {
|
||||
background-color: #f5f5f5;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.record-content {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
|
||||
.record-info {
|
||||
.record-bz {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.record-time {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
|
||||
.record-price {
|
||||
font-size: 16px;
|
||||
color: #ff6b00;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.record-footer {
|
||||
.record-location {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 暂无数据样式
|
||||
.empty-record-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 60px 20px;
|
||||
text-align: center;
|
||||
|
||||
.empty-icon {
|
||||
margin-bottom: 20px;
|
||||
background-color: #f5f6f7;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
color: #303133;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
223
src/pages/base/jc/bm.vue
Normal file
223
src/pages/base/jc/bm.vue
Normal file
@ -0,0 +1,223 @@
|
||||
<template>
|
||||
<view class="jc-bm-page">
|
||||
<!-- 报名信息头部 - 固定部分 -->
|
||||
<view class="selection-header">
|
||||
<view class="header-content">
|
||||
<!-- 学生选择部分 -->
|
||||
<XsPicker :is-bar="true" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 可滚动的内容区域 -->
|
||||
<view class="scrollable-content">
|
||||
<JcBzList :xs-id="curXs.id" :can-selected="true" :multiple="true" @change="onJcBzChange" />
|
||||
</view>
|
||||
|
||||
<!-- 底部操作区域 -->
|
||||
<view class="bottom-action">
|
||||
<view class="selected-info">
|
||||
<text>已选择:{{ selectedCount }} 个就餐标准</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>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import XsPicker from "@/pages/base/components/XsPicker/index.vue"
|
||||
import JcBzList from "@/pages/base/components/JcBzList/index.vue"
|
||||
import { useUserStore } from "@/store/modules/user";
|
||||
import { useDataStore } from "@/store/modules/data";
|
||||
import { jcBmJcBzApi } 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[]>([]);
|
||||
|
||||
// 选中数量
|
||||
const selectedCount = computed(() => selectedJcBzIds.value.length);
|
||||
|
||||
// 总金额
|
||||
const totalPrice = computed(() => {
|
||||
let total = 0;
|
||||
selectedJcBzList.value.forEach(jcBz => {
|
||||
total += jcBz.jfje || 0;
|
||||
});
|
||||
return total;
|
||||
});
|
||||
|
||||
// 就餐标准选择变更
|
||||
const onJcBzChange = (ids: string[]) => {
|
||||
selectedJcBzIds.value = ids;
|
||||
// 这里需要根据选中的ID获取对应的就餐标准详情
|
||||
// 实际项目中可能需要从本地存储或重新请求数据
|
||||
updateSelectedJcBzList();
|
||||
};
|
||||
|
||||
// 更新选中的就餐标准列表
|
||||
const updateSelectedJcBzList = () => {
|
||||
// 这里需要根据selectedJcBzIds从本地存储或重新请求数据
|
||||
// 暂时使用空数组,实际项目中需要实现
|
||||
selectedJcBzList.value = [];
|
||||
};
|
||||
|
||||
// 返回上一页
|
||||
const goBack = () => {
|
||||
uni.navigateBack();
|
||||
};
|
||||
|
||||
// 确认报名
|
||||
const confirmBm = async () => {
|
||||
if (selectedCount.value === 0) {
|
||||
uni.showToast({
|
||||
title: "请选择就餐标准",
|
||||
icon: "none",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await jcBmJcBzApi({
|
||||
xsId: curXs.value.id,
|
||||
jcBzIds: selectedJcBzIds.value,
|
||||
jzId: getUser.jzId,
|
||||
userId: getUser.userId,
|
||||
});
|
||||
|
||||
if (res.resultCode === 1) {
|
||||
uni.showToast({
|
||||
title: "报名成功",
|
||||
icon: "success",
|
||||
});
|
||||
|
||||
// 保存报名数据到store
|
||||
setData({
|
||||
...getData,
|
||||
xsId: curXs.value.id,
|
||||
jcBzIds: selectedJcBzIds.value,
|
||||
jcBzList: selectedJcBzList.value,
|
||||
totalJe: totalPrice.value,
|
||||
});
|
||||
|
||||
// 跳转到支付页面
|
||||
uni.redirectTo({
|
||||
url: '/pages/base/jc/pay/index'
|
||||
});
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: res.result?.message || "报名失败",
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('报名失败:', error);
|
||||
uni.showToast({
|
||||
title: "报名失败,请重试",
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 页面卸载前清除定时器
|
||||
onBeforeUnmount(() => {
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.jc-bm-page {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// 可滚动内容区域样式
|
||||
.scrollable-content {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
-webkit-overflow-scrolling: touch; // 增强iOS滚动体验
|
||||
}
|
||||
|
||||
.bottom-action {
|
||||
background-color: #fff;
|
||||
padding: 15px;
|
||||
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.05);
|
||||
|
||||
.selected-info {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 15px;
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
|
||||
.total-price {
|
||||
color: #ff6b00;
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.cancel-btn,
|
||||
.confirm-btn {
|
||||
width: 48%;
|
||||
height: 44px;
|
||||
line-height: 44px;
|
||||
text-align: center;
|
||||
border-radius: 22px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.cancel-btn {
|
||||
background-color: #fff;
|
||||
color: #333;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.confirm-btn {
|
||||
background-color: #2879ff;
|
||||
color: #fff;
|
||||
|
||||
&.disabled {
|
||||
background-color: #ccc;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
285
src/pages/base/jc/detail.vue
Normal file
285
src/pages/base/jc/detail.vue
Normal file
@ -0,0 +1,285 @@
|
||||
<template>
|
||||
<BasicLayout>
|
||||
<view class="jc-detail">
|
||||
<!-- 就餐标准信息卡片 -->
|
||||
<view class="info-card">
|
||||
<view class="card-title">就餐标准信息</view>
|
||||
<view class="divider"></view>
|
||||
|
||||
<view class="jc-info">
|
||||
<image
|
||||
class="jc-image"
|
||||
:src="jcDetail.lxtp"
|
||||
mode="aspectFill"
|
||||
></image>
|
||||
|
||||
<view class="jc-content">
|
||||
<view class="jc-name">{{ jcDetail.bzmc }}</view>
|
||||
<view class="jc-price">
|
||||
价格:<text class="price-value">¥{{ jcDetail.jfje }}</text>
|
||||
</view>
|
||||
<view class="jc-desc">{{ jcDetail.bzms || '暂无描述' }}</view>
|
||||
<view class="jc-time">有效期:{{ jcDetail.yxq || '暂无有效期信息' }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 就餐标准详情 -->
|
||||
<view class="info-card">
|
||||
<view class="card-title">标准详情</view>
|
||||
<view class="divider"></view>
|
||||
|
||||
<view class="content-section">
|
||||
<text>{{ jcDetail.bzms || "暂无详细信息" }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 使用说明 -->
|
||||
<view class="info-card">
|
||||
<view class="card-title">使用说明</view>
|
||||
<view class="divider"></view>
|
||||
|
||||
<view class="content-section">
|
||||
<template v-if="usageInstructions && usageInstructions.length > 0">
|
||||
<view
|
||||
v-for="(instruction, index) in usageInstructions"
|
||||
:key="index"
|
||||
class="instruction-item"
|
||||
>
|
||||
<text>{{ instruction }}</text>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view class="empty-data">
|
||||
<u-icon name="info-circle" color="#C8C9CC" size="18"></u-icon>
|
||||
<text>暂无使用说明</text>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 注意事项 -->
|
||||
<view class="info-card">
|
||||
<view class="card-title">注意事项</view>
|
||||
<view class="divider"></view>
|
||||
|
||||
<view class="content-section">
|
||||
<template v-if="precautions && precautions.length > 0">
|
||||
<view
|
||||
v-for="(precaution, index) in precautions"
|
||||
:key="index"
|
||||
class="precaution-item"
|
||||
>
|
||||
<text>{{ precaution }}</text>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view class="empty-data">
|
||||
<u-icon name="info-circle" color="#C8C9CC" size="18"></u-icon>
|
||||
<text>暂无注意事项</text>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<template #bottom>
|
||||
<view class="white-bg-color py-5">
|
||||
<view class="flex-row items-center pb-10 pt-5">
|
||||
<u-button
|
||||
text="返回"
|
||||
class="ml-15 mr-7"
|
||||
:plain="true"
|
||||
@click="navigateBack"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</BasicLayout>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, computed } from "vue";
|
||||
import { navigateBack } from "@/utils/uniapp";
|
||||
import { useDataStore } from "@/store/modules/data";
|
||||
import { storeToRefs } from "pinia";
|
||||
import { imagUrl } from "@/utils";
|
||||
import { jcGetJcBzDetailApi } from "@/api/base/jcApi";
|
||||
|
||||
// 定义就餐标准数据类型
|
||||
interface JcBzData {
|
||||
id?: string;
|
||||
bzmc?: string;
|
||||
jfje?: number;
|
||||
bzms?: string;
|
||||
yxq?: string;
|
||||
lxtp?: string;
|
||||
[key: string]: any; // 允许其他字段
|
||||
}
|
||||
|
||||
const useData = useDataStore();
|
||||
const { jcBzData } = storeToRefs(useData);
|
||||
|
||||
// 使用说明 - 从备注中解析
|
||||
const usageInstructions = ref<string[]>([]);
|
||||
|
||||
// 注意事项 - 从备注中解析
|
||||
const precautions = ref<string[]>([]);
|
||||
|
||||
const jcBzDetail = jcBzData.value as JcBzData;
|
||||
if (jcBzDetail && jcBzDetail.id) {
|
||||
jcGetJcBzDetailApi({
|
||||
jcBzId: jcBzDetail.id,
|
||||
}).then((res) => {
|
||||
if (res.resultCode == 1) {
|
||||
// 这里可以根据实际数据结构处理详情信息
|
||||
console.log('就餐标准详情:', res.result);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 就餐标准详情数据
|
||||
const jcDetail = computed(() => {
|
||||
const data = (jcBzData.value as JcBzData) || {};
|
||||
return {
|
||||
id: data.id || "",
|
||||
bzmc: data.bzmc || "暂无标准名称",
|
||||
jfje: data.jfje || 0,
|
||||
bzms: data.bzms || "暂无描述",
|
||||
yxq: data.yxq || "暂无有效期信息",
|
||||
lxtp: imagUrl(data.lxtp || ''), // 使用imagUrl处理图片路径
|
||||
};
|
||||
});
|
||||
|
||||
// 解析使用说明和注意事项
|
||||
const parseInstructions = () => {
|
||||
const data = (jcBzData.value as JcBzData) || {};
|
||||
const bzms = data.bzms || '';
|
||||
|
||||
// 这里可以根据实际的数据格式来解析使用说明和注意事项
|
||||
// 示例:假设备注中包含使用说明和注意事项,用特定分隔符分隔
|
||||
if (bzms) {
|
||||
// 这里可以根据实际的数据格式来解析
|
||||
// 示例:假设使用说明和注意事项用"注意事项:"分隔
|
||||
const parts = bzms.split('注意事项:');
|
||||
if (parts.length > 1) {
|
||||
usageInstructions.value = parts[0].split('\n').filter(item => item.trim());
|
||||
precautions.value = parts[1].split('\n').filter(item => item.trim());
|
||||
} else {
|
||||
usageInstructions.value = bzms.split('\n').filter(item => item.trim());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
parseInstructions();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.jc-detail {
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
|
||||
.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: 10px;
|
||||
}
|
||||
|
||||
.divider {
|
||||
height: 1px;
|
||||
background-color: #eee;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.jc-info {
|
||||
display: flex;
|
||||
|
||||
.jc-image {
|
||||
width: 120px;
|
||||
height: 138px;
|
||||
border-radius: 8px;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.jc-content {
|
||||
flex: 1;
|
||||
|
||||
.jc-name {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.jc-price {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
margin-bottom: 8px;
|
||||
|
||||
.price-value {
|
||||
color: #ff6b00;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.jc-desc {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
margin-bottom: 8px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.jc-time {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.content-section {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
line-height: 1.6;
|
||||
|
||||
.instruction-item,
|
||||
.precaution-item {
|
||||
margin-bottom: 10px;
|
||||
padding-left: 15px;
|
||||
position: relative;
|
||||
|
||||
&:before {
|
||||
content: "•";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
color: #2879ff;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.empty-data {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 20px 0;
|
||||
color: #909399;
|
||||
font-size: 14px;
|
||||
|
||||
text {
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
67
src/pages/base/jc/index.vue
Normal file
67
src/pages/base/jc/index.vue
Normal file
@ -0,0 +1,67 @@
|
||||
<template>
|
||||
<view class="jc-page">
|
||||
<!-- 就餐信息头部 - 固定部分 -->
|
||||
<view class="selection-header">
|
||||
<view class="header-content">
|
||||
<!-- 学生选择部分 -->
|
||||
<XsPicker :is-bar="true" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 可滚动的内容区域 -->
|
||||
<view class="scrollable-content">
|
||||
<JcBzList :xs-id="curXs.id" />
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import XsPicker from "@/pages/base/components/XsPicker/index.vue"
|
||||
import JcBzList from "@/pages/base/components/JcBzList/index.vue"
|
||||
import { useUserStore } from "@/store/modules/user";
|
||||
|
||||
const { getCurXs } = useUserStore();
|
||||
|
||||
const curXs = computed(() => getCurXs);
|
||||
|
||||
// 页面卸载前清除定时器
|
||||
onBeforeUnmount(() => {
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.jc-page {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// 可滚动内容区域样式
|
||||
.scrollable-content {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
-webkit-overflow-scrolling: touch; // 增强iOS滚动体验
|
||||
}
|
||||
</style>
|
||||
117
src/pages/base/jc/pay/fail.vue
Normal file
117
src/pages/base/jc/pay/fail.vue
Normal file
@ -0,0 +1,117 @@
|
||||
<template>
|
||||
<view class="payment-fail">
|
||||
<!-- 失败提示卡片 -->
|
||||
<view class="fail-card">
|
||||
<view class="fail-icon-container">
|
||||
<image
|
||||
class="fail-icon"
|
||||
src="/static/base/2222.png"
|
||||
mode="aspectFit"
|
||||
></image>
|
||||
</view>
|
||||
|
||||
<view class="fail-text">抱歉,报名失败!</view>
|
||||
|
||||
<view class="divider"></view>
|
||||
|
||||
<view class="tip-text">请点击下方按钮</view>
|
||||
|
||||
<view class="finger-icon">
|
||||
<image
|
||||
src="/static/base/33333.png"
|
||||
mode="aspectFit"
|
||||
></image>
|
||||
</view>
|
||||
|
||||
<view class="action-btn" @click="reselect">
|
||||
重新报名
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue';
|
||||
|
||||
// 返回选课页面
|
||||
const reselect = () => {
|
||||
uni.redirectTo({
|
||||
url: '/pages/base/jc/bm'
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
// 实际应用中可能需要记录失败原因等信息
|
||||
console.log('支付失败页面加载');
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.payment-fail {
|
||||
min-height: 100%;
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
|
||||
.fail-card {
|
||||
margin: 15px;
|
||||
width: 90%;
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
padding: 30px 15px;
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
.fail-icon-container {
|
||||
margin-bottom: 20px;
|
||||
|
||||
.fail-icon {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
}
|
||||
}
|
||||
|
||||
.fail-text {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.divider {
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
background-color: #eee;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.tip-text {
|
||||
font-size: 16px;
|
||||
color: #999;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.finger-icon {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
margin-bottom: 15px;
|
||||
|
||||
image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.action-btn {
|
||||
width: 200px;
|
||||
height: 45px;
|
||||
line-height: 45px;
|
||||
text-align: center;
|
||||
border-radius: 22.5px;
|
||||
border: 1px solid #2879ff;
|
||||
color: #2879ff;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
345
src/pages/base/jc/pay/index.vue
Normal file
345
src/pages/base/jc/pay/index.vue
Normal file
@ -0,0 +1,345 @@
|
||||
<template>
|
||||
<view class="payment-page">
|
||||
<!-- 倒计时区域 -->
|
||||
<view class="countdown-section">
|
||||
<view class="countdown-icon">
|
||||
<u-icon name="clock" size="22" color="#fff"></u-icon>
|
||||
</view>
|
||||
<view class="countdown-text">待支付</view>
|
||||
<view class="countdown-timer">
|
||||
<text>剩余:</text>
|
||||
<text class="time-value">{{ countdownTime }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="scrollable-content">
|
||||
|
||||
<!-- 学生信息 -->
|
||||
<view class="student-info-card">
|
||||
<view class="card-title">学生信息</view>
|
||||
<view class="student-info">
|
||||
<view class="student-name">{{ curXs.xm }}</view>
|
||||
<view class="student-class">{{ curXs.bjmc }}</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 就餐标准信息 -->
|
||||
<view class="jc-bz-info-card">
|
||||
<view class="card-title">报名就餐标准</view>
|
||||
<view class="jc-bz-list">
|
||||
<view
|
||||
v-for="(jcBz, index) in jcBzList"
|
||||
:key="index"
|
||||
class="jc-bz-item"
|
||||
>
|
||||
<view class="jc-bz-name">{{ jcBz.bzmc }}</view>
|
||||
<view class="jc-bz-price">¥{{ jcBz.jfje }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
|
||||
<!-- 底部支付区域 -->
|
||||
<view class="payment-footer">
|
||||
<view class="total-amount">
|
||||
<text>总金额:</text>
|
||||
<text class="amount-value">¥{{ totalJe }}</text>
|
||||
</view>
|
||||
|
||||
<view class="action-buttons">
|
||||
<view class="cancel-btn" @click="cancelRegistration">取消报名</view>
|
||||
<view class="pay-btn" @click="payNow">立即支付</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useUserStore } from "@/store/modules/user";
|
||||
import { useDataStore } from "@/store/modules/data";
|
||||
import { jcCancelBmJcBzApi, jcFqJcBzJfjApi, jcGetJcBzPayExpiredTimeApi } from "@/api/base/jcApi";
|
||||
const { getCurXs, getUser } = useUserStore();
|
||||
const { getData, setData } = useDataStore();
|
||||
|
||||
// 学生信息
|
||||
const curXs = computed(() => getCurXs);
|
||||
// 就餐标准信息
|
||||
const jcBzList = computed(() => getData.jcBzList);
|
||||
// 总金额
|
||||
const totalJe = computed(() => {
|
||||
// 循环jcBzList.value 求和
|
||||
if (!jcBzList.value || !jcBzList.value.length) {
|
||||
return 0;
|
||||
}
|
||||
let total = 0;
|
||||
for (let i = 0; i < jcBzList.value.length; i++) {
|
||||
total += jcBzList.value[i].jfje;
|
||||
}
|
||||
return total;
|
||||
});
|
||||
|
||||
// 倒计时
|
||||
const countdownTime = ref("1分20秒");
|
||||
let timer: any = null;
|
||||
let seconds = 1 * 60 + 20; // 1分20秒
|
||||
|
||||
// 开始倒计时
|
||||
const startCountdown = () => {
|
||||
timer = setInterval(() => {
|
||||
seconds--;
|
||||
if (seconds <= 0) {
|
||||
clearInterval(timer);
|
||||
uni.showModal({
|
||||
title: "支付超时",
|
||||
content: "支付已超时,请重新选课",
|
||||
showCancel: false,
|
||||
success: () => {
|
||||
cancelRegistration();
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const minutes = Math.floor(seconds / 60);
|
||||
const remainSeconds = seconds % 60;
|
||||
countdownTime.value = `${minutes}分${remainSeconds}秒`;
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
// 返回上一页
|
||||
const goBack = () => {
|
||||
uni.reLaunch({
|
||||
url: '/pages/base/home/index'
|
||||
});
|
||||
};
|
||||
|
||||
// 取消报名
|
||||
const cancelRegistration = () => {
|
||||
uni.showModal({
|
||||
title: "取消报名",
|
||||
content: "确定要取消报名吗?",
|
||||
success: async (res) => {
|
||||
if (res.confirm) {
|
||||
try {
|
||||
await jcCancelBmJcBzApi({
|
||||
xsId: getData.xsId,
|
||||
jcBzIds: getData.jcBzIds
|
||||
});
|
||||
uni.showToast({
|
||||
title: "已取消报名",
|
||||
icon: "success",
|
||||
});
|
||||
goBack();
|
||||
} catch (error) {
|
||||
console.error('取消报名失败:', error);
|
||||
uni.showToast({
|
||||
title: "取消报名失败",
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
// 立即支付
|
||||
const payNow = async () => {
|
||||
try {
|
||||
const res = await jcFqJcBzJfjApi({
|
||||
xsId: getData.xsId,
|
||||
jcBzIds: getData.jcBzIds,
|
||||
jffs: "四川农信", // TODO: 目前只支持四川农信
|
||||
jzId: getUser.jzId,
|
||||
userId: getUser.userId,
|
||||
openId: getUser.openId,
|
||||
});
|
||||
if (res.resultCode === 1 && res.result) {
|
||||
setData({
|
||||
...getData,
|
||||
...res.result
|
||||
});
|
||||
uni.redirectTo({
|
||||
url: `/pages/base/jc/pay/wait?payUrl=${encodeURIComponent(res.result.cashierPayHtml)}`
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
uni.showToast({
|
||||
title: "发起支付失败",
|
||||
icon: "error",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(async() => {
|
||||
try {
|
||||
const res = await jcGetJcBzPayExpiredTimeApi({ xsId: getCurXs.id });
|
||||
console.log('获取支付倒计时', res);
|
||||
if (res.resultCode === 1) {
|
||||
seconds = res.result;
|
||||
startCountdown();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取支付倒计时失败:', error);
|
||||
}
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
if (timer) {
|
||||
clearInterval(timer);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.payment-page {
|
||||
min-height: 100%;
|
||||
background-color: #f5f7fa;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
// 可滚动内容区域样式
|
||||
.scrollable-content {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
-webkit-overflow-scrolling: touch; // 增强iOS滚动体验
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.student-info-card,
|
||||
.jc-bz-info-card {
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
padding: 15px;
|
||||
margin-bottom: 15px;
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05);
|
||||
|
||||
.card-title {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.student-info {
|
||||
.student-name {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.student-class {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
|
||||
.jc-bz-list {
|
||||
.jc-bz-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 10px 0;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.jc-bz-name {
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.jc-bz-price {
|
||||
font-size: 14px;
|
||||
color: #ff6b00;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.countdown-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 15px;
|
||||
background-color: #2879ff;
|
||||
|
||||
.countdown-icon {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.countdown-text {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: #fff;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.countdown-timer {
|
||||
font-size: 15px;
|
||||
color: #fff;
|
||||
|
||||
.time-value {
|
||||
color: #ff4d4f;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.payment-footer {
|
||||
position: sticky;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: #fff;
|
||||
padding: 15px;
|
||||
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.05);
|
||||
|
||||
.total-amount {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 15px;
|
||||
font-size: 15px;
|
||||
color: #333;
|
||||
|
||||
.amount-value {
|
||||
color: #ff6b00;
|
||||
font-size: 20px;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.cancel-btn,
|
||||
.pay-btn {
|
||||
width: 48%;
|
||||
height: 44px;
|
||||
line-height: 44px;
|
||||
text-align: center;
|
||||
border-radius: 22px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.cancel-btn {
|
||||
background-color: #fff;
|
||||
color: #333;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.pay-btn {
|
||||
background-color: #ff8c00;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
129
src/pages/base/jc/pay/success.vue
Normal file
129
src/pages/base/jc/pay/success.vue
Normal file
@ -0,0 +1,129 @@
|
||||
<template>
|
||||
<BasicLayout>
|
||||
<view class="payment-success">
|
||||
<!-- 成功提示卡片 -->
|
||||
<view class="success-card">
|
||||
<view class="success-icon-container">
|
||||
<image
|
||||
class="success-icon-bg"
|
||||
src="/static/base/11223.png"
|
||||
mode="aspectFit"
|
||||
></image>
|
||||
<view class="success-icon">
|
||||
<u-icon name="checkmark" size="40" color="#fff"></u-icon>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="success-text">恭喜你,报名成功!</view>
|
||||
</view>
|
||||
|
||||
<!-- 这里显示学生信息和报名的就餐标准信息 -->
|
||||
|
||||
</view>
|
||||
<template #bottom>
|
||||
<!-- <view class="white-bg-color py-5">
|
||||
<view class="flex-row items-center pb-10 pt-5">
|
||||
<u-button
|
||||
text="返回"
|
||||
class="ml-15 mr-7"
|
||||
:plain="true"
|
||||
@click=""
|
||||
/>
|
||||
</view>
|
||||
</view> -->
|
||||
</template>
|
||||
</BasicLayout>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
||||
// 返回上一页
|
||||
const goBack = () => {
|
||||
uni.navigateBack();
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
// 实际应用中,应从页面参数或缓存获取课程和学生信息
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.payment-success {
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
|
||||
.nav-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 15px;
|
||||
height: 44px;
|
||||
background-color: #2879ff;
|
||||
|
||||
.nav-left {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.nav-title {
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.nav-right {
|
||||
width: 40px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
|
||||
.success-card {
|
||||
margin: 15px;
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
padding: 30px 15px;
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
.success-icon-container {
|
||||
position: relative;
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.success-icon-bg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.success-icon {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
background-color: #2879ff;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
.success-text {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
412
src/pages/base/jc/pay/wait.vue
Normal file
412
src/pages/base/jc/pay/wait.vue
Normal file
@ -0,0 +1,412 @@
|
||||
<template>
|
||||
<view class="payment-page">
|
||||
<!-- 倒计时区域 -->
|
||||
<view class="countdown-section">
|
||||
<view class="countdown-icon">
|
||||
<u-icon name="clock" size="22" color="#fff"></u-icon>
|
||||
</view>
|
||||
<view class="countdown-text">待支付</view>
|
||||
<view class="countdown-timer">
|
||||
<text>剩余:</text>
|
||||
<text class="time-value">{{ countdownTime }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="scrollable-content">
|
||||
<!-- H5环境下的处理 -->
|
||||
<view v-if="isH5" class="h5-payment-container">
|
||||
<view class="payment-info">
|
||||
<view class="payment-title">支付信息</view>
|
||||
<view class="payment-url">{{ payUrl }}</view>
|
||||
</view>
|
||||
<view class="payment-actions">
|
||||
<button class="open-payment-btn" @click="openPaymentUrl">打开支付页面</button>
|
||||
<button class="copy-url-btn" @click="copyPaymentUrl">复制支付链接</button>
|
||||
</view>
|
||||
<view class="payment-tips">
|
||||
<text>提示:</text>
|
||||
<text>1. 点击"打开支付页面"按钮在新窗口打开支付</text>
|
||||
<text>2. 支付完成后请返回此页面</text>
|
||||
<text>3. 如无法打开,请复制链接到浏览器中打开</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 非H5环境使用web-view -->
|
||||
<web-view v-else :src="payUrl" @error="handleWebViewError" class="payment-webview"></web-view>
|
||||
</view>
|
||||
|
||||
<!-- 底部支付区域 -->
|
||||
<view class="payment-footer">
|
||||
<view class="action-buttons">
|
||||
<view class="cancel-btn" @click="cancelRegistration">取消报名</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onLoad } from "@dcloudio/uni-app";
|
||||
// import { jzGetQkExpiredTime, jzXkCancelApi, jzXkJfCxjApi } from "@/api/base/server";
|
||||
import { useUserStore } from "@/store/modules/user";
|
||||
import { useDataStore } from "@/store/modules/data";
|
||||
const { getCurXs, initWs, setWsCallback } = useUserStore();
|
||||
const { getData } = useDataStore();
|
||||
|
||||
const payUrl = ref("");
|
||||
const isH5 = ref(false);
|
||||
|
||||
// 检测是否为H5环境
|
||||
const checkPlatform = () => {
|
||||
// #ifdef H5
|
||||
isH5.value = true;
|
||||
// #endif
|
||||
};
|
||||
|
||||
// 打开支付URL
|
||||
const openPaymentUrl = () => {
|
||||
if (payUrl.value) {
|
||||
// 在新窗口打开支付页面
|
||||
window.open(payUrl.value, '_blank');
|
||||
}
|
||||
};
|
||||
|
||||
// 复制支付URL
|
||||
const copyPaymentUrl = () => {
|
||||
if (payUrl.value) {
|
||||
// #ifdef H5
|
||||
if (navigator.clipboard) {
|
||||
navigator.clipboard.writeText(payUrl.value).then(() => {
|
||||
uni.showToast({
|
||||
title: '链接已复制',
|
||||
icon: 'success'
|
||||
});
|
||||
}).catch(() => {
|
||||
// 降级处理
|
||||
const textArea = document.createElement('textarea');
|
||||
textArea.value = payUrl.value;
|
||||
document.body.appendChild(textArea);
|
||||
textArea.select();
|
||||
document.execCommand('copy');
|
||||
document.body.removeChild(textArea);
|
||||
uni.showToast({
|
||||
title: '链接已复制',
|
||||
icon: 'success'
|
||||
});
|
||||
});
|
||||
} else {
|
||||
// 降级处理
|
||||
const textArea = document.createElement('textarea');
|
||||
textArea.value = payUrl.value;
|
||||
document.body.appendChild(textArea);
|
||||
textArea.select();
|
||||
document.execCommand('copy');
|
||||
document.body.removeChild(textArea);
|
||||
uni.showToast({
|
||||
title: '链接已复制',
|
||||
icon: 'success'
|
||||
});
|
||||
}
|
||||
// #endif
|
||||
}
|
||||
};
|
||||
|
||||
// web-view错误处理
|
||||
const handleWebViewError = (e: any) => {
|
||||
console.error('web-view加载错误:', e);
|
||||
uni.showModal({
|
||||
title: '加载失败',
|
||||
content: '支付页面加载失败,请检查网络连接或联系客服',
|
||||
showCancel: false
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
setWsCallback((type: string, res: any) => {
|
||||
console.log('收到WebSocket消息:', type, res.data);
|
||||
// 将data从字符串转为对象
|
||||
const dataObj = JSON.parse(res.data);
|
||||
if (dataObj.action === 'pay') {
|
||||
uni.showToast({
|
||||
title: '支付成功',
|
||||
icon: 'success',
|
||||
});
|
||||
setWsCallback((type: string, res: any) => {})
|
||||
// 跳转到支付成功页面
|
||||
setTimeout(() => {
|
||||
uni.reLaunch({
|
||||
url: "/pages/base/xk/pay/success",
|
||||
});
|
||||
}, 1000)
|
||||
}
|
||||
});
|
||||
|
||||
// 倒计时
|
||||
const countdownTime = ref("1分20秒");
|
||||
let timer: any = null;
|
||||
let seconds = 1 * 60 + 20; // 1分20秒
|
||||
|
||||
// 开始倒计时
|
||||
const startCountdown = () => {
|
||||
timer = setInterval(() => {
|
||||
seconds--;
|
||||
if (seconds <= 0) {
|
||||
clearInterval(timer);
|
||||
uni.showModal({
|
||||
title: "支付超时",
|
||||
content: "支付已超时,请重新选课",
|
||||
showCancel: false,
|
||||
success: () => {
|
||||
cancelRegistration();
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
const minutes = Math.floor(seconds / 60);
|
||||
const remainSeconds = seconds % 60;
|
||||
countdownTime.value = `${minutes}分${remainSeconds}秒`;
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
// 返回上一页
|
||||
const goBack = () => {
|
||||
uni.reLaunch({
|
||||
url: getData.backUrl
|
||||
});
|
||||
};
|
||||
|
||||
// 取消报名
|
||||
const cancelRegistration = () => {
|
||||
// uni.showModal({
|
||||
// title: "取消报名",
|
||||
// content: "确定要取消报名吗?",
|
||||
// success: async (res) => {
|
||||
// if (res.confirm) {
|
||||
// await jzXkCancelApi({
|
||||
// xsId: getData.xsId,
|
||||
// xkId: getData.xkId
|
||||
// });
|
||||
// uni.showToast({
|
||||
// title: "已取消报名",
|
||||
// icon: "success",
|
||||
// });
|
||||
// goBack();
|
||||
// }
|
||||
// },
|
||||
// });
|
||||
};
|
||||
|
||||
onLoad(async (options: any) => {
|
||||
// 检测平台
|
||||
checkPlatform();
|
||||
|
||||
if (options.payUrl) {
|
||||
payUrl.value = decodeURIComponent(options.payUrl);
|
||||
console.log('支付URL:', payUrl.value);
|
||||
|
||||
// const res = await jzGetQkExpiredTime({ xsId: getCurXs.id} );
|
||||
// seconds = res.result;
|
||||
// initWs();
|
||||
// startCountdown();
|
||||
} else {
|
||||
uni.showToast({ title: '缺少支付地址', icon: 'none' })
|
||||
setTimeout(() => {
|
||||
goBack();
|
||||
}, 1000)
|
||||
}
|
||||
openPaymentUrl();
|
||||
// try {
|
||||
// const res = await jzXkJfCxjApi({
|
||||
// orderNumber: getData.orderNumber,
|
||||
// xsId: getData.xsId,
|
||||
// xkId: getData.xkId
|
||||
// });
|
||||
// // 订单状态,01-交易中,02-交易成功,03-交易失败,04-交易关闭
|
||||
// const { orderStat, respCode } = res.result;
|
||||
// if ("0000000000" === respCode) {
|
||||
// if ("02" === orderStat) {
|
||||
// uni.reLaunch({
|
||||
// url: "/pages/base/xk/pay/success",
|
||||
// });
|
||||
// } else if ("03" === orderStat) {
|
||||
// uni.reLaunch({
|
||||
// url: "/pages/base/xk/pay/fail",
|
||||
// });
|
||||
// }
|
||||
// } else {
|
||||
// uni.showToast({
|
||||
// title: "订单状态查询失败",
|
||||
// icon: "error",
|
||||
// });
|
||||
// }
|
||||
// } catch (error) {
|
||||
// console.log("订单查询失败", error);
|
||||
// }
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (timer) {
|
||||
clearInterval(timer);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.payment-page {
|
||||
min-height: 100vh;
|
||||
background-color: #f5f7fa;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.scrollable-content {
|
||||
flex: 1;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.payment-webview {
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
border: none !important;
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
// H5支付容器样式
|
||||
.h5-payment-container {
|
||||
padding: 20px;
|
||||
background-color: #fff;
|
||||
margin: 15px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.payment-info {
|
||||
margin-bottom: 20px;
|
||||
|
||||
.payment-title {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.payment-url {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
word-break: break-all;
|
||||
background-color: #f5f5f5;
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
}
|
||||
|
||||
.payment-actions {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-bottom: 20px;
|
||||
|
||||
button {
|
||||
flex: 1;
|
||||
height: 44px;
|
||||
border-radius: 22px;
|
||||
font-size: 16px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
|
||||
&.open-payment-btn {
|
||||
background-color: #2879ff;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
&.copy-url-btn {
|
||||
background-color: #fff;
|
||||
color: #333;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.payment-tips {
|
||||
background-color: #fff7e6;
|
||||
border: 1px solid #ffd591;
|
||||
border-radius: 4px;
|
||||
padding: 15px;
|
||||
|
||||
text {
|
||||
display: block;
|
||||
font-size: 14px;
|
||||
color: #d46b08;
|
||||
line-height: 1.5;
|
||||
margin-bottom: 5px;
|
||||
|
||||
&:first-child {
|
||||
font-weight: bold;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.countdown-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 15px;
|
||||
background-color: #2879ff;
|
||||
flex-shrink: 0;
|
||||
|
||||
.countdown-icon {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.countdown-text {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: #fff;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.countdown-timer {
|
||||
font-size: 15px;
|
||||
color: #fff;
|
||||
|
||||
.time-value {
|
||||
color: #ff4d4f;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.payment-footer {
|
||||
position: sticky;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: #fff;
|
||||
padding: 15px;
|
||||
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.05);
|
||||
flex-shrink: 0;
|
||||
|
||||
.action-buttons {
|
||||
.cancel-btn {
|
||||
height: 44px;
|
||||
line-height: 44px;
|
||||
text-align: center;
|
||||
border-radius: 22px;
|
||||
font-size: 16px;
|
||||
background-color: #fff;
|
||||
color: #333;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
67
src/pages/base/jc/record.vue
Normal file
67
src/pages/base/jc/record.vue
Normal file
@ -0,0 +1,67 @@
|
||||
<template>
|
||||
<view class="jc-record-page">
|
||||
<!-- 记录信息头部 - 固定部分 -->
|
||||
<view class="selection-header">
|
||||
<view class="header-content">
|
||||
<!-- 学生选择部分 -->
|
||||
<XsPicker :is-bar="true" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 可滚动的内容区域 -->
|
||||
<view class="scrollable-content">
|
||||
<JcRecordList :xs-id="curXs.id" />
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import XsPicker from "@/pages/base/components/XsPicker/index.vue"
|
||||
import JcRecordList from "@/pages/base/components/JcRecordList/index.vue"
|
||||
import { useUserStore } from "@/store/modules/user";
|
||||
|
||||
const { getCurXs } = useUserStore();
|
||||
|
||||
const curXs = computed(() => getCurXs);
|
||||
|
||||
// 页面卸载前清除定时器
|
||||
onBeforeUnmount(() => {
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.jc-record-page {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// 可滚动内容区域样式
|
||||
.scrollable-content {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
-webkit-overflow-scrolling: touch; // 增强iOS滚动体验
|
||||
}
|
||||
</style>
|
||||
@ -5,6 +5,7 @@ export const useDataStore = defineStore({
|
||||
state: () => ({
|
||||
data: {},
|
||||
kcData: {},
|
||||
jcBzData: {},
|
||||
global: {},
|
||||
file: {},
|
||||
appCode: "JZ"
|
||||
@ -22,6 +23,9 @@ export const useDataStore = defineStore({
|
||||
getKcData(): any {
|
||||
return this.kcData;
|
||||
},
|
||||
getJcBzData(): any {
|
||||
return this.jcBzData;
|
||||
},
|
||||
getAppCode(): string {
|
||||
return this.appCode;
|
||||
},
|
||||
@ -39,6 +43,9 @@ export const useDataStore = defineStore({
|
||||
setKcData(data: any) {
|
||||
this.kcData = data;
|
||||
},
|
||||
setJcBzData(data: any) {
|
||||
this.jcBzData = data;
|
||||
},
|
||||
},
|
||||
persist: {
|
||||
enabled: true,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user