SAAS模式调整

This commit is contained in:
hebo 2026-03-16 15:19:39 +08:00
parent 73515ab6a5
commit e7a726af56
19 changed files with 374 additions and 209 deletions

View File

@ -8,6 +8,13 @@ export const checkXsXkApi = async (params: any) => {
return await get("/mobile/jz/checkXsXk", params); return await get("/mobile/jz/checkXsXk", params);
}; };
/**
* KQK
*/
export const checkXsXkWithGzsApi = async (params: any) => {
return await get("/mobile/jz/checkXsXkWithGzs", params);
};
/** /**
* *
*/ */

View File

@ -1,22 +1,32 @@
const ip: string = "127.0.0.1:8897"; // 测试环境 / 正式环境:开发时用测试地址,打包时用正式地址
const fwqip: string = "127.0.0.1:8897"; const isDev = process.env.NODE_ENV === "development";
//const ip: string = "lzcxsx.cn"; const ip: string = isDev ? "127.0.0.1:8897" : "lzcxsx.cn";
//const fwqip: string = "lzcxsx.cn"; const fwqip: string = isDev ? "127.0.0.1:8897" : "lzcxsx.cn";
//const ip: string = "zhxy.yufangzc.com"; //const ip: string = "zhxy.yufangzc.com";
//const fwqip: string = "zhxy.yufangzc.com"; //const fwqip: string = "zhxy.yufangzc.com";
//const ip: string = "lzcxsx.cn";
//const fwqip: string = "lzcxsx.cn";
//打包服务器接口代理标识 //打包服务器接口代理标识
const SERVERAGENT: string = "/jzd-api"; const SERVERAGENT: string = "/jzd-api";
//本地代理url地址,配置了就启动代理,没配置就不启动代理 //本地代理url地址,配置了就启动代理,没配置就不启动代理
export const HOMEAGENT: string = ""; export const HOMEAGENT: string = "";
// 开发环境下,手机/平板访问时非localhost使用当前页面 host避免 127.0.0.1 指向设备自身导致请求失败
function getDevBaseUrl(): string {
if (typeof window !== "undefined" && window.location?.hostname && window.location.hostname !== "localhost" && window.location.hostname !== "127.0.0.1") {
return `http://${window.location.hostname}:8897/zhxy`;
}
return `http://${ip}/zhxy`;
}
// 接口地址 // 接口地址
export const BASE_URL: string = export const BASE_URL: string =
process.env.NODE_ENV == "development" ? `http://${ip}/zhxy` : SERVERAGENT; process.env.NODE_ENV == "development" ? getDevBaseUrl() : SERVERAGENT;
// WebSocket地址 // WebSocket地址开发环境用 ws无 SSL正式环境用 wss
export const BASE_WS_URL: string = export const BASE_WS_URL: string = isDev ? `ws://${ip}` : `wss://${ip}`;
process.env.NODE_ENV == "development" ? `ws://${ip}` : `wss://${fwqip}`;
//图片地址 //图片地址
// export const BASE_IMAGE_URL: string = process.env.NODE_ENV == "development" ? `https://${ip}` : `http://${fwqip}`; // export const BASE_IMAGE_URL: string = process.env.NODE_ENV == "development" ? `https://${ip}` : `https://${fwqip}`;
export const BASE_IMAGE_URL: string = `http://${fwqip}`; export const BASE_IMAGE_URL: string = `https://${fwqip}`;
// kkFileView预览服务地址 // kkFileView预览服务地址
export const KK_FILE_VIEW_URL: string = `https://${fwqip}/kkpro`; export const KK_FILE_VIEW_URL: string = `https://${fwqip}/kkpro`;
//存token的key //存token的key
@ -33,3 +43,6 @@ export const WHITELIST: WhiteList = [];
export const THEMECOLOR: string = "#35468C"; export const THEMECOLOR: string = "#35468C";
// 启动vconsole // 启动vconsole
export const ENABLE_VCONSOLE: boolean = false; // process.env.NODE_ENV != "development"; export const ENABLE_VCONSOLE: boolean = false; // process.env.NODE_ENV != "development";
/** 就餐报名成功后跳转的支付链接(后续可改为接口/动态配置) */
export const JC_PAY_REDIRECT_URL: string = "https://app.xiaoyuan.ccb.com/LHECRESM/V6/JFPAGENEW/index.html#/?schoolId=213245500";

View File

@ -25,13 +25,15 @@
<script lang="ts" setup> <script lang="ts" setup>
import { xkgzsApi } from "@/api/base/server"; import { xkgzsApi } from "@/api/base/server";
import { useDataStore } from "@/store/modules/data"; import { useDataStore } from "@/store/modules/data";
const dataStore = useDataStore();
import { showLoading } from "@/utils/uniapp"; import { showLoading } from "@/utils/uniapp";
import { onLoad } from "@dcloudio/uni-app"; import { onLoad } from "@dcloudio/uni-app";
import RichTextContent from "@/components/RichTextContent/RichTextContent.vue"; import RichTextContent from "@/components/RichTextContent/RichTextContent.vue";
const signCompRef = ref<any>(null); const signCompRef = ref<any>(null);
const sign_file = ref<any>(null); const sign_file = ref<any>(null);
const { setFile } = useDataStore(); const { setFile } = dataStore;
const notice = ref(""); const notice = ref("");
const lxId = ref(""); const lxId = ref("");
@ -54,6 +56,12 @@ onLoad(async (options: any) => {
return; return;
} }
} }
// 使
const cachedGzs = dataStore.getQk?.gzsContent;
if (cachedGzs && (lxId.value === "816059832" || lxId.value === "962488654")) {
notice.value = cachedGzs;
return;
}
showLoading({ title: "加载中..." }); showLoading({ title: "加载中..." });
const res = await xkgzsApi({ kcLx: kcLx }); const res = await xkgzsApi({ kcLx: kcLx });
notice.value = res.rows?.[0]?.content || ""; notice.value = res.rows?.[0]?.content || "";
@ -73,12 +81,12 @@ async function submit() {
}); });
switch (lxId.value) { switch (lxId.value) {
case "JC": { case "JC": {
uni.reLaunch({ uni.navigateTo({
url: "/pages/base/jc/pay/qrcode", url: "/pages/base/jc/pay/qrcode",
}); });
} break; } break;
default: { default: {
uni.reLaunch({ uni.navigateTo({
url: "/pages/base/xk/qk/index?xklxId=" + lxId.value, url: "/pages/base/xk/qk/index?xklxId=" + lxId.value,
}); });
} }

View File

@ -97,11 +97,11 @@ interface HomeMenuItem {
/** 家长端特殊菜单:选课/退费/缴费需 lxId + action后端 auth_code 映射 */ /** 家长端特殊菜单:选课/退费/缴费需 lxId + action后端 auth_code 映射 */
const JZD_SPECIAL_MENU: Record<string, { lxId: string; action: string }> = { const JZD_SPECIAL_MENU: Record<string, { lxId: string; action: string }> = {
"school-xqkxk": { lxId: "962488654", action: "jf" }, // "910010": { lxId: "962488654", action: "jf" }, //
"school-jlbxk": { lxId: "816059832", action: "jf" }, // "910011": { lxId: "816059832", action: "jf" }, //
"school-jcjf": { lxId: "JC", action: "jf" }, // "910012": { lxId: "JC", action: "jf" }, //
"school-xqk-tf": { lxId: "962488654", action: "tf" }, // 退 "910013": { lxId: "962488654", action: "tf" }, // 退
"school-jlb-tf": { lxId: "816059832", action: "tf" }, // 退 "910014": { lxId: "816059832", action: "tf" }, // 退
}; };
// //
@ -113,7 +113,7 @@ function flattenMenuToItems(nodes: MobileMenuTreeNode[]): HomeMenuItem[] {
const icon = (node.normalCss && /^[a-zA-Z0-9_-]+$/.test(node.normalCss)) const icon = (node.normalCss && /^[a-zA-Z0-9_-]+$/.test(node.normalCss))
? `/static/base/home/${node.normalCss}.png` ? `/static/base/home/${node.normalCss}.png`
: "/static/base/home/file-text-line.png"; : "/static/base/home/file-text-line.png";
const authCode = node.authCode || ""; const authCode = node.id + "";
const special = authCode ? JZD_SPECIAL_MENU[authCode] : undefined; const special = authCode ? JZD_SPECIAL_MENU[authCode] : undefined;
items.push({ items.push({
id: node.id, id: node.id,
@ -160,7 +160,13 @@ const handleMenuClick = debounce(async (item: any) => {
if (item.path) { if (item.path) {
if (item.lxId) { if (item.lxId) {
setGlobal({ lxId: item.lxId, action: item.action, from: 'home' }); setGlobal({ lxId: item.lxId, action: item.action, from: 'home' });
PageUtils.toHome(item.lxId, item.action); uni.showLoading({ title: "加载中...", mask: true });
try {
await PageUtils.toHome(item.lxId, item.action);
uni.hideLoading();
} catch (error) {
uni.hideLoading();
}
} else { } else {
uni.navigateTo({ uni.navigateTo({
url: item.path, url: item.path,

View File

@ -77,6 +77,7 @@ import BasicSign from "@/components/BasicSign/Sign.vue"
import { useUserStore } from "@/store/modules/user"; import { useUserStore } from "@/store/modules/user";
import { useDataStore } from "@/store/modules/data"; import { useDataStore } from "@/store/modules/data";
import { checkXsJcBmApi, jcXsBmJcApi } from "@/api/base/jcApi"; import { checkXsJcBmApi, jcXsBmJcApi } from "@/api/base/jcApi";
import { JC_PAY_REDIRECT_URL } from "@/config";
const signCompRef = ref<any>(null); const signCompRef = ref<any>(null);
@ -171,14 +172,19 @@ const handleJcBzClick = (jcBz: any) => {
} }
}; };
// //
const navigateToPayment = (jcBz: any) => { const navigateToPayment = (jcBz: any) => {
// store setJcBz(jcBz);
setJcBz(jcBz); const payUrl = JC_PAY_REDIRECT_URL;
// try {
uni.navigateTo({ if (typeof (window as any).plus !== 'undefined' && (window as any).plus.runtime?.openURL) {
url: "/pages/base/jc/pay/qrcode", (window as any).plus.runtime.openURL(payUrl);
}); } else {
window.location.href = payUrl;
}
} catch (_e) {
window.location.href = payUrl;
}
}; };
// //
@ -221,10 +227,17 @@ const goToQrCode = async (jcBz: any) => {
jcBz.paidStatus = 'unpaid'; jcBz.paidStatus = 'unpaid';
// store // store
setJcBz(jcBz); setJcBz(jcBz);
// //
uni.navigateTo({ const payUrl = JC_PAY_REDIRECT_URL;
url: '/pages/base/jc/pay/qrcode' try {
}); if (typeof (window as any).plus !== 'undefined' && (window as any).plus.runtime?.openURL) {
(window as any).plus.runtime.openURL(payUrl);
} else {
window.location.href = payUrl;
}
} catch (_e) {
window.location.href = payUrl;
}
} else { } else {
uni.hideLoading(); uni.hideLoading();
setTimeout(() => { setTimeout(() => {
@ -246,11 +259,14 @@ const goToQrCode = async (jcBz: any) => {
} }
}; };
// //
const goHome = () => { const goHome = () => {
uni.reLaunch({ const pages = getCurrentPages();
url: '/pages/base/home/index' if (pages.length > 1) {
}); uni.navigateBack();
} else {
uni.reLaunch({ url: '/pages/base/home/index' });
}
}; };
// //

View File

@ -47,7 +47,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, watch } from "vue"; import { ref, watch } from "vue";
import { checkXsXkApi, getXsXkListApi } from "@/api/base/xkApi"; import dayjs from "dayjs";
import { getXsXkListApi } from "@/api/base/xkApi";
import { useUserStore } from "@/store/modules/user"; import { useUserStore } from "@/store/modules/user";
import { useDataStore } from "@/store/modules/data"; import { useDataStore } from "@/store/modules/data";
@ -83,6 +84,23 @@ const goToWks = () => {
}); });
}; };
/**
* 从多个选课中优先选择处于选课时间段的xkkstime <= now < xkjstime
* @param list 选课列表
* @returns 优先选中的选课若无则返回第一个
*/
const pickPreferredXk = (list: any[]): any => {
if (!list || list.length === 0) return null;
if (list.length === 1) return list[0];
const now = dayjs().valueOf();
const inRange = list.find((xk: any) => {
const xkkstime = xk?.xkkstime ? dayjs(xk.xkkstime).valueOf() : 0;
const xkjstime = xk?.xkjstime ? dayjs(xk.xkjstime).valueOf() : Infinity;
return now >= xkkstime && now < xkjstime;
});
return inRange ?? list[0];
};
// //
const loadXkList = async () => { const loadXkList = async () => {
uni.showLoading({ uni.showLoading({
@ -97,7 +115,8 @@ const loadXkList = async () => {
const res = await getXsXkListApi(params); const res = await getXsXkListApi(params);
if (res.resultCode === 1 && res.result && res.result.length) { if (res.resultCode === 1 && res.result && res.result.length) {
xkList.value = res.result; xkList.value = res.result;
switchXk(res.result[0]); const preferred = pickPreferredXk(res.result);
switchXk(preferred ?? res.result[0]);
} else { } else {
xkList.value = []; xkList.value = [];
switchXk({}); switchXk({});
@ -113,10 +132,10 @@ const loadXkList = async () => {
if (res.resultCode === 1) { if (res.resultCode === 1) {
const result = res.result || {}; const result = res.result || {};
if (result.type === 1) { if (result.type === 1) {
// // navigateTo
setData(result); setData(result);
uni.reLaunch({ uni.navigateTo({
url: "/pages/base/xk/pay/index", url: "/pages/base/xk/pay/index?xklxId=" + props.xklxId,
}); });
return; return;
} else if (result.type === 2 || result.type === 3) { } else if (result.type === 2 || result.type === 3) {
@ -134,7 +153,8 @@ const loadXkList = async () => {
const initXkList = (list: any) => { const initXkList = (list: any) => {
xkList.value = list; xkList.value = list;
switchXk(xkList.value[0]); const preferred = pickPreferredXk(list);
switchXk(preferred ?? list[0] ?? {});
}; };

View File

@ -17,7 +17,7 @@
</view> </view>
<view class="register-info"> <view class="register-info">
<text>报名情况</text> <text>报名情况</text>
<text class="register-count">{{ xkkc.hasNum || 0 }}</text> <text class="register-count">{{ getDisplayHasNum(xkkc) }}</text>
<text> | {{ xkkc.maxNum || 0 }}</text> <text> | {{ xkkc.maxNum || 0 }}</text>
</view> </view>
<view class="study-time-info" v-if="xkkc.studyTime"> <view class="study-time-info" v-if="xkkc.studyTime">
@ -45,10 +45,19 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, watch } from "vue"; import { ref, watch, computed } from "vue";
import { useDataStore } from "@/store/modules/data"; import { useDataStore } from "@/store/modules/data";
const { setKcData, getQk } = useDataStore(); const { setKcData, getQk } = useDataStore();
// hasNum 0
const isXkStarted = computed(() => {
const xkkstime = props.xk?.xkkstime;
if (!xkkstime) return true;
return new Date().getTime() >= new Date(xkkstime).getTime();
});
const getDisplayHasNum = (xkkc: any) => (isXkStarted.value ? (xkkc?.hasNum ?? 0) : 0);
const getEffectiveHasNum = (xkkc: any) => (isXkStarted.value ? (xkkc?.hasNum ?? 0) : 0);
// //
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
xk: any, xk: any,
@ -80,9 +89,9 @@ const toggleSelection = (xkkc: any) => {
(id: string) => id !== xkkc.id (id: string) => id !== xkkc.id
); );
} else { } else {
// // hasNum 0
const maxNum = xkkc.maxNum || 0; const maxNum = xkkc.maxNum || 0;
const hasNum = xkkc.hasNum || 0; const hasNum = getEffectiveHasNum(xkkc);
if (maxNum <= hasNum) { if (maxNum <= hasNum) {
uni.showToast({ uni.showToast({

View File

@ -75,13 +75,14 @@
<view class="divider"></view> <view class="divider"></view>
<view class="content-section"> <view class="content-section">
<template v-if="teachingPlan && teachingPlan.length > 0"> <template v-if="teachingPlanList.length > 0">
<view <view
v-for="(phase, index) in teachingPlan" v-for="(phase, index) in teachingPlanList"
:key="index" :key="index"
class="teaching-phase" class="teaching-phase"
> >
<text>{{ phase }}</text> <text class="phase-title">{{ phase.jhjd }}</text>
<rich-text v-if="phase.jhnr" :nodes="phase.jhnr" class="phase-content"></rich-text>
</view> </view>
</template> </template>
<template v-else> <template v-else>
@ -92,6 +93,24 @@
</template> </template>
</view> </view>
</view> </view>
<!-- 相关教学附件 -->
<view class="info-card" v-if="attachmentList.length > 0">
<view class="card-title">相关教学附件</view>
<view class="divider"></view>
<view class="attachment-list">
<view
v-for="(att, index) in attachmentList"
:key="index"
class="attachment-item"
@click="openAttachment(att)"
>
<u-icon name="file-text" size="20" color="#2879ff"></u-icon>
<text class="attachment-name">{{ att.name }}</text>
<u-icon name="arrow-right" size="14" color="#c0c4cc"></u-icon>
</view>
</view>
</view>
</view> </view>
<template #bottom> <template #bottom>
<view class="white-bg-color py-5"> <view class="white-bg-color py-5">
@ -111,14 +130,14 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed } from "vue"; import { ref, computed, onMounted } from "vue";
import { navigateBack } from "@/utils/uniapp"; import { navigateBack } from "@/utils/uniapp";
import { useDataStore } from "@/store/modules/data"; import { useDataStore } from "@/store/modules/data";
import { storeToRefs } from "pinia"; import { storeToRefs } from "pinia";
import { imagUrl } from "@/utils"; import { imagUrl } from "@/utils";
import { kcjhFindKcjhByKcIdApi } from "@/api/base/server"; import { getXkkcDetailByIdApi } from "@/api/base/xkApi";
// // yfzc_xkkc
interface CourseData { interface CourseData {
id?: string; id?: string;
kcmc?: string; kcmc?: string;
@ -128,33 +147,76 @@ interface CourseData {
studyTime?: string; studyTime?: string;
kcjsms?: string; kcjsms?: string;
jxll?: string; jxll?: string;
jxjh?: string;
fileUrl?: string;
fileName?: string;
fileFormat?: string;
remark?: string; remark?: string;
lxtp?: string; lxtp?: string;
[key: string]: any; // [key: string]: any;
} }
const useData = useDataStore(); const useData = useDataStore();
const { kcData } = storeToRefs(useData); const { kcData } = storeToRefs(useData);
// - // getXkkcDetailById xkkc
const teachingPlan = ref<string[]>([]); const xkkcDetail = ref<CourseData>({});
const courseData = kcData.value as CourseData; // HTML img src URL rich-text
if (courseData && courseData.id) { const processHtmlForRichText = (html: string): string => {
kcjhFindKcjhByKcIdApi({ if (!html) return "";
xkkcId: courseData.id, return html.replace(/<img\s+([^>]*?)src=["']([^"']+)["']([^>]*)>/gi, (_, before, src, after) => {
}).then((res) => { const fullSrc = imagUrl(src);
if (res.resultCode == 1) { const style = 'style="max-width:100%;height:auto"';
teachingPlan.value = res.result.map( return `<img ${before}src="${fullSrc}" ${style}${after}>`;
(item: any) => item.jhjd + ":" + item.jhms
);
}
}); });
} };
// - xkkc.jxjh HTML rich-text
// : [{"value":{"jhjd":"1","jhnr":"<p><img src=\"...\"></p>"}}, ...]
const teachingPlanList = computed(() => {
const jxjh = xkkcDetail.value.jxjh;
if (!jxjh) return [];
try {
const parsed = JSON.parse(jxjh);
if (Array.isArray(parsed)) {
return parsed
.map((item: any) => {
const v = item?.value ?? item;
const jhjd = v.jhjd || "";
const rawJhnr = v.jhnr || v.jhms || "";
const jhnr = rawJhnr ? processHtmlForRichText(rawJhnr) : "";
return { jhjd, jhnr };
})
.filter((p: { jhjd: string; jhnr: string }) => p.jhjd || p.jhnr);
}
} catch {
// JSON
}
return [];
});
// - xkkc.fileUrlfileNamefileFormat
const attachmentList = computed(() => {
const fileUrl = xkkcDetail.value.fileUrl || "";
const fileName = xkkcDetail.value.fileName || "";
const urls = fileUrl.split(",").map((s) => s.trim()).filter(Boolean);
const names = fileName.split(";").map((s) => s.trim());
return urls.map((url, i) => ({ url, name: names[i] || `附件${i + 1}` }));
});
// webView
const openAttachment = (att: { url: string; name: string }) => {
const fullUrl = imagUrl(att.url);
if (!fullUrl) return;
uni.navigateTo({
url: "/pages/system/webView/webView?url=" + encodeURIComponent(fullUrl),
});
};
// //
const courseDetail = computed(() => { const courseDetail = computed(() => {
const data = (kcData.value as CourseData) || {}; const data = xkkcDetail.value || {};
return { return {
id: data.id || "", id: data.id || "",
title: data.kcmc || "暂无课程名称", title: data.kcmc || "暂无课程名称",
@ -162,28 +224,41 @@ const courseDetail = computed(() => {
location: data.kcdd || "暂无地点信息", location: data.kcdd || "暂无地点信息",
price: data.kcje || 0, price: data.kcje || 0,
studyTime: data.studyTime || "暂无上课时间", studyTime: data.studyTime || "暂无上课时间",
lxtp: imagUrl(data.lxtp || ''), // 使imagUrl lxtp: imagUrl(data.lxtp || ""),
}; };
}); });
// //
const teacherInfo = computed(() => { const teacherInfo = computed(() => {
const data = (kcData.value as CourseData) || {}; const data = xkkcDetail.value || {};
const teacherAvatars = data.jstx ? data.jstx.split(",").map((a: string) => a.trim()) : [];
//
const teacherAvatars = data.jstx ? data.jstx.split(',').map((avatar: string) => avatar.trim()) : [];
return { return {
name: data.jsName || "暂无教师信息", name: data.jsName || "暂无教师信息",
avatar: teacherAvatars.length > 0 ? imagUrl(teacherAvatars[0]) : '', // avatar: teacherAvatars.length > 0 ? imagUrl(teacherAvatars[0]) : "",
introduction: data.kcjsms || "暂无教师介绍", introduction: data.kcjsms || "暂无教师介绍",
}; };
}); });
// // - xkkc.jxll
const teachingPhilosophy = computed(() => { const teachingPhilosophy = computed(() => xkkcDetail.value.jxll || "暂无教学理念信息");
const data = (kcData.value as CourseData) || {};
return data.jxll || "暂无教学理念信息"; // getXkkcDetailById xkkc jxlljxjhfileUrl
onMounted(() => {
const data = kcData.value as CourseData;
const id = data?.id;
if (id) {
getXkkcDetailByIdApi(id).then((res) => {
if (res.resultCode === 1 && res.result) {
xkkcDetail.value = res.result;
} else {
xkkcDetail.value = { ...data };
}
}).catch(() => {
xkkcDetail.value = { ...data };
});
} else {
xkkcDetail.value = { ...data } || {};
}
}); });
</script> </script>
@ -351,12 +426,26 @@ const teachingPhilosophy = computed(() => {
line-height: 1.6; line-height: 1.6;
.teaching-phase { .teaching-phase {
margin-bottom: 10px; margin-bottom: 20px;
&:last-child { &:last-child {
margin-bottom: 0; margin-bottom: 0;
} }
} }
.phase-title {
display: block;
font-weight: 600;
color: #333;
margin-bottom: 8px;
}
.phase-content {
display: block;
font-size: 14px;
color: #666;
line-height: 1.6;
}
.empty-data { .empty-data {
display: flex; display: flex;
@ -372,6 +461,26 @@ const teachingPhilosophy = computed(() => {
} }
} }
.attachment-list {
.attachment-item {
display: flex;
align-items: center;
padding: 12px 0;
border-bottom: 1px solid #f0f0f0;
&:last-child {
border-bottom: none;
}
}
.attachment-name {
flex: 1;
margin-left: 10px;
font-size: 14px;
color: #333;
}
}
.bottom-action { .bottom-action {
padding: 15px; padding: 15px;
margin-top: 20px; margin-top: 20px;

View File

@ -30,8 +30,8 @@
</view> </view>
<view class="action-buttons"> <view class="action-buttons">
<view class="cancel-btn" @click="cancelRegistration"> <view class="cancel-btn" @click="goBack">
取消报名 返回
</view> </view>
<view class="pay-btn" :class="{ 'pay-btn--disabled': isPaySubmitting }" @click="payNow"> <view class="pay-btn" :class="{ 'pay-btn--disabled': isPaySubmitting }" @click="payNow">
{{ isPaySubmitting ? '支付中...' : '立即支付' }} {{ isPaySubmitting ? '支付中...' : '立即支付' }}
@ -54,9 +54,6 @@ const { getQk } = useDataStore();
// //
const { isProcessing: isPaySubmitting, debounce: payDebounce } = useDebounce(2000); const { isProcessing: isPaySubmitting, debounce: payDebounce } = useDebounce(2000);
//
const { isProcessing: isCancelSubmitting, debounce: cancelDebounce } = useDebounce(2000);
const qk = ref<any>({}); const qk = ref<any>({});
// //
const totalJe = ref(0); const totalJe = ref(0);
@ -168,40 +165,13 @@ const startCountdown = () => {
}, 1000); }, 1000);
}; };
// //
const goBack = () => { const goBack = () => {
uni.reLaunch({ uni.reLaunch({
url: '/pages/base/home/index' url: '/pages/base/home/index'
}); });
}; };
//
const cancelRegistration = () => {
uni.showModal({
title: "取消报名",
content: "确定要取消报名吗?",
success: cancelDebounce(async (res) => {
if (res.confirm) {
try {
const res = await jzXkCancelApi({
xsId: qk.value.xsId,
xkId: qk.value.xkId
});
if (res.resultCode === 1) {
uni.showLoading({ title: "取消报名中,请稍后..." });
} else {
uni.showToast({ title: res.message, icon: "none" });
goBack();
}
} catch (error) {
console.log(error);
goBack();
}
}
}),
});
};
// //
const payNow = payDebounce(async () => { const payNow = payDebounce(async () => {
try { try {

View File

@ -74,9 +74,12 @@ const checkEnrollmentStatus = (xk: any) => {
const endTime = new Date(xk.xkjstime).getTime(); const endTime = new Date(xk.xkjstime).getTime();
if (now > endTime) { if (now > endTime) {
// // redirectTo
console.log('[qk/index] 跳转 yjzxk 数据:', xk);
console.log('[qk/index] xk 字段:', { xkmc: xk?.xkmc, xkkstime: xk?.xkkstime, xkjstime: xk?.xkjstime });
const courseInfo = encodeURIComponent(JSON.stringify(xk)); const courseInfo = encodeURIComponent(JSON.stringify(xk));
uni.navigateTo({ console.log('[qk/index] courseInfo 长度:', courseInfo.length);
uni.redirectTo({
url: `/pages/base/xk/qk/yjz?courseInfo=${courseInfo}` url: `/pages/base/xk/qk/yjz?courseInfo=${courseInfo}`
}); });
return true; return true;
@ -119,11 +122,14 @@ const changeXkkc = (ids: any) => {
selectedXkkcIds.value = ids; selectedXkkcIds.value = ids;
} }
// //
const goBack = () => { const goBack = () => {
uni.reLaunch({ const pages = getCurrentPages();
url: '/pages/base/home/index' if (pages.length > 1) {
}); uni.navigateBack();
} else {
uni.reLaunch({ url: '/pages/base/home/index' });
}
} }
// //

View File

@ -59,9 +59,11 @@ const checkEnrollmentStatus = (xk: any) => {
const endTime = new Date(xk.xkjstime).getTime(); const endTime = new Date(xk.xkjstime).getTime();
if (now > endTime) { if (now > endTime) {
// // redirectTo
console.log('[qk/jlb] 跳转yjz传入的xk:', xk);
console.log('[qk/jlb] xk.xkmc:', xk?.xkmc, 'xk.xkkstime:', xk?.xkkstime, 'xk.xkjstime:', xk?.xkjstime);
const courseInfo = encodeURIComponent(JSON.stringify(xk)); const courseInfo = encodeURIComponent(JSON.stringify(xk));
uni.navigateTo({ uni.redirectTo({
url: `/pages/base/xk/qk/yjz?courseInfo=${courseInfo}` url: `/pages/base/xk/qk/yjz?courseInfo=${courseInfo}`
}); });
return true; return true;

View File

@ -53,11 +53,14 @@ const { getData } = useDataStore();
const title = ref(""); const title = ref("");
// //
const goHome = () => { const goHome = () => {
uni.reLaunch({ const pages = getCurrentPages();
url: "/pages/base/home/index" if (pages.length > 1) {
}); uni.navigateBack();
} else {
uni.reLaunch({ url: "/pages/base/home/index" });
}
}; };
onLoad((options:any) => { onLoad((options:any) => {

View File

@ -60,7 +60,10 @@ const checkEnrollmentStatus = (xk: any) => {
if (now > endTime) { if (now > endTime) {
// //
console.log('[qk/xqk] 跳转 yjzxk 数据:', xk);
console.log('[qk/xqk] xk 字段:', { xkmc: xk?.xkmc, xkkstime: xk?.xkkstime, xkjstime: xk?.xkjstime });
const courseInfo = encodeURIComponent(JSON.stringify(xk)); const courseInfo = encodeURIComponent(JSON.stringify(xk));
console.log('[qk/xqk] courseInfo 长度:', courseInfo.length);
uni.navigateTo({ uni.navigateTo({
url: `/pages/base/xk/qk/yjz?courseInfo=${courseInfo}` url: `/pages/base/xk/qk/yjz?courseInfo=${courseInfo}`
}); });

View File

@ -72,8 +72,8 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, onMounted } from 'vue'; import { ref, onMounted, onUnmounted } from 'vue';
import { onLoad } from '@dcloudio/uni-app'; import { onLoad, onBackPress } from '@dcloudio/uni-app';
// //
const courseInfo = ref<any>(null); const courseInfo = ref<any>(null);
@ -81,14 +81,46 @@ const courseInfo = ref<any>(null);
onLoad((options) => { onLoad((options) => {
// //
if (options?.courseInfo) { if (options?.courseInfo) {
const raw = options.courseInfo;
try { try {
courseInfo.value = JSON.parse(decodeURIComponent(options.courseInfo)); // URL decodeURIComponent URI malformed
} catch (error) { courseInfo.value = JSON.parse(raw);
console.error('解析选课信息失败:', error); } catch (_e1) {
try {
courseInfo.value = JSON.parse(decodeURIComponent(raw));
} catch (e2) {
console.error('解析选课信息失败:', e2);
}
} }
} }
}); });
//
const goBack = () => {
uni.reLaunch({ url: '/pages/base/home/index' });
};
// App
onBackPress(() => {
goBack();
return true; //
});
// H5onBackPress H5
let popstateHandler: (() => void) | null = null;
onMounted(() => {
if (typeof window !== 'undefined' && window.history?.pushState) {
popstateHandler = () => goBack();
window.history.pushState(null, '', document.URL);
window.addEventListener('popstate', popstateHandler);
}
});
onUnmounted(() => {
if (typeof window !== 'undefined' && popstateHandler) {
window.removeEventListener('popstate', popstateHandler);
}
});
// //
const formatTime = (time: string) => { const formatTime = (time: string) => {
if (!time) return '未设置'; if (!time) return '未设置';
@ -102,13 +134,6 @@ const formatTime = (time: string) => {
}); });
}; };
//
const goBack = () => {
uni.reLaunch({
url: '/pages/base/home/index'
});
};
// //
const refreshPage = () => { const refreshPage = () => {
uni.reLaunch({ uni.reLaunch({

View File

@ -32,11 +32,12 @@
</view> </view>
<!-- 附件预览 --> <!-- 附件预览 -->
<view v-if="taskInfo.fileUrl && taskInfo.fileName" class="file-preview mt-15"> <view v-if="taskInfo.fileUrl" class="file-preview mt-15">
<view class="file-preview-item"> <BasicFilePreview
<text class="file-label">附件</text> :file-url="taskInfo.fileUrl"
<text class="file-name" @click="previewFile(taskInfo.fileUrl)">{{ taskInfo.fileName }}</text> :file-name="taskInfo.fileName"
</view> :file-format="taskInfo.fileFormat"
/>
</view> </view>
</view> </view>
@ -77,7 +78,7 @@
import { ref, onMounted } from 'vue'; import { ref, onMounted } from 'vue';
import { onLoad } from '@dcloudio/uni-app'; import { onLoad } from '@dcloudio/uni-app';
import { zpFindDetailByIdApi } from "@/api/base/server"; import { zpFindDetailByIdApi } from "@/api/base/server";
import { imagUrl } from "@/utils"; import BasicFilePreview from "@/components/BasicFile/preview.vue";
interface TaskInfo { interface TaskInfo {
id?: string; id?: string;
@ -87,6 +88,7 @@ interface TaskInfo {
zpjstime?: string; zpjstime?: string;
fileUrl?: string; fileUrl?: string;
fileName?: string; fileName?: string;
fileFormat?: string;
[key: string]: any; [key: string]: any;
} }
@ -189,21 +191,6 @@ const getTaskTypeText = (type?: string) => {
}; };
return typeMap[type || ''] || '未知类型'; return typeMap[type || ''] || '未知类型';
}; };
//
const previewFile = (fileUrl: string) => {
if (!fileUrl) return;
const fullUrl = imagUrl(fileUrl);
const fileExt = fileUrl.split('.').pop()?.toLowerCase();
if (['jpg', 'jpeg', 'png', 'gif', 'webp'].includes(fileExt || '')) {
uni.previewImage({
urls: [fullUrl],
current: fullUrl
});
} else {
uni.showToast({ title: '请下载查看', icon: 'none' });
}
};
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
@ -391,36 +378,11 @@ const previewFile = (fileUrl: string) => {
} }
} }
// // BasicFilePreview
.file-preview { .file-preview {
padding: 12px; padding: 12px;
background: #f8f9fa; background: #f8f9fa;
border-radius: 6px; border-radius: 6px;
border: 1px solid #e9ecef; border: 1px solid #e9ecef;
.file-preview-item {
display: flex;
align-items: center;
.file-label {
color: #666;
font-size: 14px;
margin-right: 8px;
flex-shrink: 0;
}
.file-name {
color: #4e73df;
font-size: 14px;
text-decoration: underline;
cursor: pointer;
word-break: break-all;
flex: 1;
&:active {
color: #2e59d9;
}
}
}
} }
</style> </style>

View File

@ -354,7 +354,7 @@ const generateFormSchema = () => {
} }
}; };
} else if (zplx.zpfl === "scsp") { } else if (zplx.zpfl === "scsp") {
// // 50MB
componentConfig = { componentConfig = {
component: "ImageVideoUpload", component: "ImageVideoUpload",
componentProps: { componentProps: {
@ -363,7 +363,13 @@ const generateFormSchema = () => {
enableFile: false, enableFile: false,
maxVideoCount: 30, maxVideoCount: 30,
uploadApi: attachmentUpload, uploadApi: attachmentUpload,
compressConfig: COMPRESS_PRESETS.medium, compressConfig: {
...COMPRESS_PRESETS.medium,
video: {
...COMPRESS_PRESETS.medium.video,
maxSize: 50 * 1024 * 1024
}
},
videoList: formData.value[fieldName] || [], videoList: formData.value[fieldName] || [],
showSectionTitle: false showSectionTitle: false
} }

View File

@ -2,9 +2,9 @@ import { defineStore } from "pinia";
import type { MobileMenuTreeNode } from "@/api/system/menu"; import type { MobileMenuTreeNode } from "@/api/system/menu";
export const useMenuStore = defineStore({ export const useMenuStore = defineStore({
id: "app-Menu", id: "app-Menu-jzd",
state: () => ({ state: () => ({
/** 树形菜单数据,持久化到 localStorage key: app-Menu */ /** 树形菜单数据,持久化到 localStorage key: app-Menu-jzd家长端与教师端 app-Menu-jsd 区分,避免同域下菜单互相覆盖) */
mobileMenu: [] as MobileMenuTreeNode[], mobileMenu: [] as MobileMenuTreeNode[],
}), }),
getters: { getters: {

View File

@ -1,4 +1,4 @@
import { checkXsXkApi, checkXkTfApi } from "@/api/base/xkApi"; import { checkXsXkWithGzsApi, checkXkTfApi } from "@/api/base/xkApi";
import { useUserStore } from "@/store/modules/user"; import { useUserStore } from "@/store/modules/user";
import { useDataStore } from "@/store/modules/data"; import { useDataStore } from "@/store/modules/data";
const userStore = useUserStore(); const userStore = useUserStore();
@ -75,7 +75,7 @@ export const PageUtils = {
* @param xklxId * @param xklxId
*/ */
async checkQkLogic(xklxId: string) { async checkQkLogic(xklxId: string) {
const res: any = await checkXsXkApi({ const res: any = await checkXsXkWithGzsApi({
xsId: userStore.getCurXs.id, xsId: userStore.getCurXs.id,
njmcId: userStore.getCurXs.njmcId, njmcId: userStore.getCurXs.njmcId,
xklxId: xklxId, xklxId: xklxId,
@ -94,35 +94,35 @@ export const PageUtils = {
const result = res.result || {}; const result = res.result || {};
// 记录到缓存数据中 // 记录到缓存数据中
dataStore.setQk(result); dataStore.setQk(result);
// 状态判断 // 状态判断(使用 navigateTo 保留页面栈,支持浏览器返回)
switch (result.xsXkStatus) { switch (result.xsXkStatus) {
case 'WFB': { // KQK可抢课 case 'WFB': { // 未开放
uni.reLaunch({ uni.navigateTo({
url: "/pages/base/xk/qk/wks?xklxId=" + xklxId, url: "/pages/base/xk/qk/wks?xklxId=" + xklxId,
}); });
} break; } break;
case 'KQK': { // KQK可抢课 case 'KQK': { // 可抢课-告知书
uni.reLaunch({ uni.navigateTo({
url: "/pages/base/gzs/index?lxId=" + xklxId, url: "/pages/base/gzs/index?lxId=" + xklxId,
}); });
} break; } break;
case 'QKZ': { // QKZ抢课中 case 'QKZ': { // 抢课中
uni.reLaunch({ uni.navigateTo({
url: "/pages/base/xk/qk/index?xklxId=" + xklxId, url: "/pages/base/xk/qk/index?xklxId=" + xklxId,
}); });
} break; } break;
case 'YQK': { // YQK已选课 case 'YQK': { // 已选课
uni.reLaunch({ uni.navigateTo({
url: "/pages/base/xk/pay/index?xklxId=" + xklxId, url: "/pages/base/xk/pay/index?xklxId=" + xklxId,
}); });
} break; } break;
case 'DZF': { // DZF待支付 case 'DZF': { // 待支付
uni.reLaunch({ uni.navigateTo({
url: "/pages/base/xk/pay/index?xklxId=" + xklxId, url: "/pages/base/xk/pay/index?xklxId=" + xklxId,
}); });
} break; } break;
case 'YZF': { // YZF已支付 case 'YZF': { // 已支付
uni.reLaunch({ uni.navigateTo({
url: "/pages/base/xk/pay/success?xklxId=" + xklxId, url: "/pages/base/xk/pay/success?xklxId=" + xklxId,
}); });
} break; } break;
@ -166,9 +166,9 @@ export const PageUtils = {
} }
}, },
// 判断就餐逻辑 // 判断就餐逻辑(使用 navigateTo 保留页面栈,支持浏览器返回)
async checkJcLogic() { async checkJcLogic() {
uni.reLaunch({ uni.navigateTo({
url: "/pages/base/jc/bm", url: "/pages/base/jc/bm",
}); });
}, },

View File

@ -120,14 +120,14 @@ export function get<T = any>(
} else { } else {
if (res.resultCode) { if (res.resultCode) {
if (res.resultCode != RESULT_CODE_NOT_LOGIN) { if (res.resultCode != RESULT_CODE_NOT_LOGIN) {
showToast(res.message || "接口异常"); showToast(res.message || "接口异常1");
reject(res); reject(res);
} }
} else { } else {
if (res.rows) { if (res.rows) {
resolve(res); resolve(res);
} else { } else {
showToast(res.message || "接口异常"); showToast(res.message || "接口异常2");
reject(res); reject(res);
} }
} }
@ -169,14 +169,14 @@ export function post<T = any>(
} else { } else {
if (res.resultCode) { if (res.resultCode) {
if (res.resultCode != RESULT_CODE_NOT_LOGIN) { if (res.resultCode != RESULT_CODE_NOT_LOGIN) {
showToast(res.message || "接口异常"); showToast(res.message || "接口异常3");
reject(res); reject(res);
} }
} else { } else {
if (res.rows) { if (res.rows) {
resolve(res); resolve(res);
} else { } else {
showToast(res.message || "接口异常"); showToast(res.message || "接口异常4");
reject(res); reject(res);
} }
} }
@ -216,14 +216,14 @@ export function file(
} else { } else {
if (res.resultCode) { if (res.resultCode) {
if (res.resultCode != RESULT_CODE_NOT_LOGIN) { if (res.resultCode != RESULT_CODE_NOT_LOGIN) {
showToast(res.message || "接口异常"); showToast(res.message || "接口异常5");
reject(res); reject(res);
} }
} else { } else {
if (res.rows) { if (res.rows) {
resolve(res); resolve(res);
} else { } else {
showToast(res.message || "接口异常"); showToast(res.message || "接口异常6");
reject(res); reject(res);
} }
} }