619 lines
16 KiB
Vue
Raw Normal View History

2025-05-21 02:44:13 +08:00
<template>
<BasicLayout>
2025-06-20 18:38:22 +08:00
<!-- <template #top>
</template> -->
<view class="mb-5">
<view class="flex-row items-center white-bg-color p-15 r-md">
2025-08-11 21:11:19 +08:00
<!-- 左侧课程图片 -->
<view class="course-image-section" v-if="xkkc.lxtp">
<image
:src="getImageUrl(xkkc.lxtp)"
class="course-image"
mode="aspectFill"
@error="handleImageError"
/>
</view>
2025-06-20 18:38:22 +08:00
<view class="flex-col ml-10 flex-1 course-info">
<view class="course-name">{{ xkkc.kcmc }}</view>
<view class="course-info-item">
<view class="info-label">上课周期</view>
<view class="info-data">{{ xkkc.skzqmc }}</view>
</view>
<view class="course-info-item">
2025-08-11 21:11:19 +08:00
<view class="info-label">上课时间</view>
<view class="info-data">{{ formatClassTime(xkkc.skkstime, xkkc.skjstime) }}</view>
2025-06-20 18:38:22 +08:00
</view>
</view>
</view>
</view>
2025-08-11 21:11:19 +08:00
<!-- 四个主要部分 -->
<view class="p-15">
<!-- 第一部分教师信息 -->
<view class="section-card mb-15">
<view class="section-title">教师信息 <text class="required">*</text></view>
<view class="teacher-info-header">
<!-- 教师头像 -->
<view class="teacher-avatar-section" v-if="teacherHeadPic">
<image
:src="getImageUrl(teacherHeadPic)"
class="teacher-avatar"
mode="aspectFill"
@error="handleTeacherAvatarError"
/>
</view>
<!-- 右侧信息 -->
<view class="teacher-details">
<view class="detail-row">
<view class="detail-item">
<text class="detail-label">开课老师</text>
<text class="detail-value">{{ js.jsxm }}</text>
</view>
<view class="detail-item">
<text class="detail-label">上课地点</text>
<text class="detail-value">{{ xkkc.kcdd }}</text>
</view>
<view class="detail-item">
<text class="detail-label">上课人数</text>
<text class="detail-value">{{ xkkc.hasNum || 0 }} | {{ xkkc.maxNum || 0 }}</text>
</view>
</view>
</view>
</view>
<!-- 老师信息输入框单独一行 -->
<view class="teacher-input-row">
<textarea
v-model="xkkc.kcjsms"
placeholder="请输入教师信息(必填)"
class="form-textarea"
/>
</view>
</view>
<!-- 第二部分教学理念 -->
<view class="section-card mb-15">
<view class="section-title">教学理念 <text class="required">*</text></view>
<textarea
v-model="xkkc.jxll"
placeholder="请输入教学理念(必填)"
class="form-textarea"
/>
</view>
<!-- 第三部分教学计划 -->
<view class="section-card mb-15">
<view class="section-header">
<view class="section-title">教学计划 <text class="required">*</text></view>
<view @click="addEducation" class="add-icon">
<BasicIcon type="icon-tianjia" size="25" />
</view>
</view>
<view v-if="education.xl.length > 0">
<template v-for="(item, index) in education.xl" :key="index">
<view class="po-re mb-15">
<BasicForm v-model="item.value" :schema="schema" :formsProps="{ labelWidth: 100 }" />
<view @click="deleteMemberFamily(index as number, item.value)" class="delete-icon mt-5">
<BasicIcon type="clear" size="30" />
</view>
</view>
</template>
</view>
<view v-else class="p-15 flex-row-center color-9 font-13 white-bg-color">教学计划暂无数据</view>
</view>
</view>
2025-05-21 02:44:13 +08:00
<template #bottom>
<view class="white-bg-color py-5">
<view class="flex-row items-center pb-10 pt-5">
2025-06-20 09:51:43 +08:00
<u-button text="返回" class="ml-15 mr-7" :plain="true" @click="navigateBack" />
<u-button text="提交" class="mr-15 mr-7" type="primary" @click="submit" />
2025-05-21 02:44:13 +08:00
</view>
</view>
</template>
</BasicLayout>
</template>
<script lang="ts" setup>
2025-06-20 09:51:43 +08:00
import { navigateBack } from "@/utils/uniapp";
import { useForm } from "@/components/BasicForm/hooks/useForm";
import { cloneDeep, get } from "lodash";
import { useUserStore } from "@/store/modules/user";
import { useDataStore } from "@/store/modules/data";
import { jsdXkkcSaveApi } from "@/api/base/server";
2025-08-11 21:11:19 +08:00
import dayjs from "dayjs";
import { BASE_IMAGE_URL } from "@/config";
2025-06-20 09:51:43 +08:00
const { getJs } = useUserStore();
const { getData } = useDataStore();
2025-05-21 02:44:13 +08:00
2025-06-20 09:51:43 +08:00
const js = computed(() => getJs)
const xkkc = ref<any>({})
2025-05-21 02:44:13 +08:00
2025-08-11 21:11:19 +08:00
// 获取教师头像
const teacherHeadPic = ref<string>('')
// 从localStorage获取教师头像
const getTeacherHeadPic = () => {
try {
console.log('开始获取教师头像...');
const appUserStr = uni.getStorageSync('app-user')
console.log('app-user原始数据:', appUserStr);
// 解析JSON字符串为对象
let appUser;
try {
appUser = typeof appUserStr === 'string' ? JSON.parse(appUserStr) : appUserStr;
} catch (parseError) {
console.error('JSON解析失败:', parseError);
return;
}
console.log('解析后的appUser数据:', appUser);
// 详细检查数据结构
console.log('appUser存在:', !!appUser);
console.log('appUser类型:', typeof appUser);
console.log('appUser的所有键:', Object.keys(appUser));
if (appUser) {
console.log('appUser.userdata存在:', !!appUser.userdata);
console.log('appUser.userdata类型:', typeof appUser.userdata);
if (appUser.userdata) {
console.log('appUser.userdata的所有键:', Object.keys(appUser.userdata));
console.log('appUser.userdata.js存在:', !!appUser.userdata.js);
if (appUser.userdata.js) {
console.log('appUser.userdata.js的所有键:', Object.keys(appUser.userdata.js));
console.log('appUser.userdata.js.headPic存在:', !!appUser.userdata.js.headPic);
console.log('headPic值:', appUser.userdata.js.headPic);
}
}
}
// 直接从app-user获取userdata
if (appUser && appUser.userdata && appUser.userdata.js) {
console.log('userdata.js数据:', appUser.userdata.js);
if (appUser.userdata.js.headPic) {
console.log('找到headPic:', appUser.userdata.js.headPic);
teacherHeadPic.value = appUser.userdata.js.headPic
console.log('设置teacherHeadPic为:', teacherHeadPic.value);
} else {
console.log('userdata.js中没有headPic字段');
}
} else {
console.log('没有找到userdata或js');
}
} catch (error) {
console.error('获取教师头像失败:', error)
}
}
2025-06-20 09:51:43 +08:00
const [register, { getValue, setValue }] = useForm({
2025-05-21 02:44:13 +08:00
schema: [
2025-08-11 21:11:19 +08:00
// 不再需要kcjsms和jxll字段因为已经用原生textarea处理
2025-06-20 09:51:43 +08:00
{ colSlot: 'jxjh' },
2025-05-21 02:44:13 +08:00
],
});
const schema = reactive<FormsSchema[]>([
{
2025-06-20 09:51:43 +08:00
field: "jhjd",
2025-05-21 02:44:13 +08:00
label: "阶段",
component: "BasicInput",
componentProps: {},
},
{
2025-06-20 09:51:43 +08:00
field: "jhsj",
2025-05-21 02:44:13 +08:00
label: "计划时间",
component: "BasicDateTimes",
componentProps: {},
},
{
2025-06-20 09:51:43 +08:00
field: "jhdd",
2025-05-21 02:44:13 +08:00
label: "地址",
component: "BasicInput",
componentProps: {},
},
{
2025-06-20 09:51:43 +08:00
field: "jhnr",
2025-05-21 02:44:13 +08:00
label: "计划内容",
component: "BasicInput",
itemProps: {
labelPosition: "top",
},
componentProps: {
type: "textarea",
},
},
])
const education = reactive<any>(
2025-06-20 09:51:43 +08:00
{
xl: []
}
2025-05-21 02:44:13 +08:00
)
function addEducation() {
2025-06-20 09:51:43 +08:00
education.xl.push({ value: {
jhjd: '',
jhsj: '',
jhdd: '',
jhnr: ''
} })
2025-05-21 02:44:13 +08:00
}
function deleteMemberFamily(index: number, item: any) {
const list = cloneDeep(education.xl)
list.splice(index, 1)
education.xl = list
}
2025-06-20 09:51:43 +08:00
2025-08-11 21:11:19 +08:00
// 格式化上课时间
const formatClassTime = (startTime: string, endTime: string) => {
if (!startTime || !endTime) {
return '';
}
try {
// 尝试解析时间,支持多种格式
let start, end;
// 如果是时间格式HH:mm:ss 或 HH:mm
if (startTime.includes(':') && !startTime.includes('-') && !startTime.includes('/')) {
start = startTime;
end = endTime;
} else {
// 尝试用 dayjs 解析
const startDate = dayjs(startTime);
const endDate = dayjs(endTime);
if (startDate.isValid() && endDate.isValid()) {
start = startDate.format('HH:mm:ss');
end = endDate.format('HH:mm:ss');
} else {
// 如果解析失败,直接返回原始值
return `${startTime}~${endTime}`;
}
}
return `${start}~${end}`;
} catch (error) {
console.error('时间格式化错误:', error);
// 如果出错,返回原始值
return `${startTime}~${endTime}`;
}
};
// 获取完整的图片URL
const getImageUrl = (imagePath: string) => {
console.log('getImageUrl被调用参数:', imagePath);
console.log('BASE_IMAGE_URL:', BASE_IMAGE_URL);
if (!imagePath) {
console.log('图片路径为空,返回空字符串');
return '';
}
// 如果已经是完整URL直接返回
if (imagePath.startsWith('http://') || imagePath.startsWith('https://')) {
console.log('已经是完整URL直接返回:', imagePath);
return imagePath;
}
// 否则拼接BASE_IMAGE_URL
const fullUrl = `${BASE_IMAGE_URL}${imagePath}`;
console.log('拼接后的完整URL:', fullUrl);
return fullUrl;
};
// 处理图片加载错误
const handleImageError = () => {
console.log('课程图片加载失败');
};
// 处理教师头像加载错误
const handleTeacherAvatarError = () => {
console.log('教师头像加载失败');
};
2025-06-20 09:51:43 +08:00
const submit = async () => {
2025-08-11 21:11:19 +08:00
// 必填验证
if (!xkkc.value.kcjsms || xkkc.value.kcjsms.trim() === '') {
uni.showToast({
title: '请输入教师信息',
icon: 'none',
duration: 2000
});
return;
}
if (!xkkc.value.jxll || xkkc.value.jxll.trim() === '') {
uni.showToast({
title: '请输入教学理念',
icon: 'none',
duration: 2000
});
return;
}
if (!education.xl || education.xl.length === 0) {
uni.showToast({
title: '请添加教学计划',
icon: 'none',
duration: 2000
});
return;
}
// 验证教学计划是否完整
for (let i = 0; i < education.xl.length; i++) {
const item = education.xl[i];
if (!item.value.jhjd || item.value.jhjd.trim() === '' ||
!item.value.jhsj || item.value.jhsj.trim() === '' ||
!item.value.jhdd || item.value.jhdd.trim() === '' ||
!item.value.jhnr || item.value.jhnr.trim() === '') {
uni.showToast({
title: `教学计划第${i + 1}项信息不完整`,
icon: 'none',
duration: 2000
});
return;
}
}
// 直接使用v-model绑定的值不需要调用getValue()
// xkkc.value.kcjsms 和 xkkc.value.jxll 已经通过v-model绑定
2025-06-20 09:51:43 +08:00
xkkc.value.jxjh = JSON.stringify(education.xl)
2025-08-11 21:11:19 +08:00
2025-06-20 09:51:43 +08:00
await jsdXkkcSaveApi(xkkc.value).then(res => {
uni.showToast({
title: '提交成功',
icon: 'success',
duration: 2000
})
2025-08-11 21:11:19 +08:00
// 提交成功后延迟返回列表页
setTimeout(() => {
uni.navigateBack({
delta: 1
});
}, 1500); // 延迟1.5秒,让用户看到成功提示
2025-06-20 09:51:43 +08:00
}).catch(err => {
uni.showToast({
title: '提交失败',
icon: 'error',
duration: 2000
})
});
}
// 初始化
onMounted(() => {
2025-08-11 21:11:19 +08:00
console.log('页面初始化开始...');
2025-06-20 09:51:43 +08:00
xkkc.value = getData;
setValue(getData);
2025-08-11 21:11:19 +08:00
// 处理教学计划数据回显
if (xkkc.value.jxjh) {
try {
// 如果jxjh是字符串先解析
let jxjhData = xkkc.value.jxjh;
if (typeof jxjhData === 'string') {
jxjhData = JSON.parse(jxjhData);
}
// 检查数据结构并转换为正确的格式
if (Array.isArray(jxjhData)) {
education.xl = jxjhData.map(item => {
// 确保每个item都有value属性
if (item.value) {
return {
value: {
jhjd: item.value.jhjd || '',
jhsj: item.value.jhsj || '',
jhdd: item.value.jhdd || '',
jhnr: item.value.jhnr || ''
}
};
}
return item;
});
console.log('教学计划数据回显成功:', education.xl);
} else {
education.xl = [];
console.log('教学计划数据格式不正确,初始化为空数组');
}
} catch (error) {
console.error('解析教学计划数据失败:', error);
education.xl = [];
}
2025-06-20 09:51:43 +08:00
} else {
education.xl = [];
2025-08-11 21:11:19 +08:00
console.log('没有教学计划数据,初始化为空数组');
2025-06-20 09:51:43 +08:00
}
2025-08-11 21:11:19 +08:00
console.log('调用getTeacherHeadPic前teacherHeadPic值:', teacherHeadPic.value);
getTeacherHeadPic(); // 调用获取教师头像的函数
console.log('调用getTeacherHeadPic后teacherHeadPic值:', teacherHeadPic.value);
// 添加调试信息
setTimeout(() => {
console.log('延迟检查teacherHeadPic值:', teacherHeadPic.value);
console.log('teacherHeadPic是否存在:', !!teacherHeadPic.value);
console.log('当前教学计划数据:', education.xl);
}, 1000);
2025-06-20 09:51:43 +08:00
})
2025-05-21 02:44:13 +08:00
</script>
2025-06-23 11:29:16 +08:00
<style lang="scss">
2025-05-21 02:44:13 +08:00
.delete-icon {
position: absolute;
right: 0;
top: 0;
z-index: 1;
}
2025-08-11 21:11:19 +08:00
2025-06-20 09:51:43 +08:00
.course-info {
2025-08-11 21:11:19 +08:00
flex: 1;
2025-06-20 09:51:43 +08:00
.course-name {
font-size: 16px;
font-weight: 500;
color: #333;
margin-bottom: 10px;
}
.course-info-item {
display: flex;
margin-bottom: 12px;
font-size: 12px;
2025-08-11 21:11:19 +08:00
align-items: center;
2025-06-20 09:51:43 +08:00
.info-label {
color: #949AA4;
2025-08-11 21:11:19 +08:00
flex: 0 0 auto;
margin-right: 4px;
white-space: nowrap;
2025-06-20 09:51:43 +08:00
}
.info-data {
2025-08-11 21:11:19 +08:00
flex: 0 0 auto;
color: #333;
font-weight: 400;
2025-06-20 09:51:43 +08:00
}
}
}
2025-08-11 21:11:19 +08:00
.course-image-section {
flex: 0 0 100px;
margin-right: 15px;
display: flex;
align-items: center;
justify-content: center;
.course-image {
width: 80px;
height: 80px;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
border: 1px solid #f0f0f0;
}
}
.teacher-name {
vertical-align: middle;
}
.teacher-info-header {
display: flex;
align-items: center;
gap: 15px;
margin-bottom: 15px;
}
.teacher-details {
flex: 1;
display: flex;
flex-direction: column;
gap: 10px;
}
.detail-row {
display: flex;
gap: 20px;
flex-wrap: wrap;
}
.detail-item {
display: flex;
align-items: center;
gap: 5px;
white-space: nowrap;
}
.detail-label {
font-size: 12px;
color: #666;
font-weight: 500;
}
.detail-value {
font-size: 14px;
color: #333;
font-weight: 400;
}
.teacher-input-row {
margin-top: 15px;
}
.add-icon {
cursor: pointer;
color: #007aff;
}
.teacher-avatar-section {
flex: 0 0 60px;
display: flex;
align-items: center;
justify-content: center;
.teacher-avatar {
width: 50px;
height: 50px;
border-radius: 50%;
border: 2px solid #e0e0e0;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
}
.teacher-input-section {
flex: 1;
}
.section-card {
background: white;
border-radius: 8px;
padding: 15px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.section-title {
font-size: 16px;
font-weight: 600;
color: #333;
margin-bottom: 15px;
padding-left: 8px;
border-left: 3px solid #007aff;
.required {
color: #f56c6c;
font-weight: 700;
margin-left: 4px;
}
}
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
}
.form-textarea {
width: 100%; /* 恢复为100%宽度 */
min-height: 80px;
padding: 12px 15px; /* 左右padding保持15px */
border: 1px solid #e0e0e0;
border-radius: 6px;
font-size: 14px;
line-height: 1.5;
resize: vertical;
box-sizing: border-box; /* 确保padding和border包含在宽度内 */
&:focus {
outline: none;
border-color: #007aff;
box-shadow: 0 0 0 2px rgba(0, 122, 255, 0.1);
}
&::placeholder {
color: #999;
}
}
2025-05-21 02:44:13 +08:00
</style>