# Conflicts:
#	src/config.ts
This commit is contained in:
ywyonui 2025-07-08 20:34:43 +08:00
commit a8a0edc5d4
7 changed files with 552 additions and 345 deletions

View File

@ -1,7 +1,7 @@
// 参数接口 // 参数接口
// 响应接口 // 响应接口
import {get, post} from "@/utils/request"; import { get, post } from "@/utils/request";
/** /**
* *
@ -32,7 +32,7 @@ export const jsdFindPageTaskApi = async (params: any) => {
}; };
export const rwflFindRwlxsByRwId = async (params: any) => { export const rwflFindRwlxsByRwId = async (params: any) => {
return await get("/api/rwlx/findRwlxsByRwId", params); return await get("/api/rwlx/findRwlxsByRwId", params);
} };
export const rwzxSaveApi = async (params: any) => { export const rwzxSaveApi = async (params: any) => {
return await post("/api/rwzx/save", params); return await post("/api/rwzx/save", params);
}; };
@ -40,10 +40,9 @@ export const rwzxExecutedInfoByRwIdAndJsApi = async (params: any) => {
return await get("/api/rwzx/executedInfoByRwIdAndJs", params); return await get("/api/rwzx/executedInfoByRwIdAndJs", params);
}; };
export const rwFindInfoByRwId = async (params: any) => { export const rwFindInfoByRwId = async (params: any) => {
return await get("/api/rw/findInfoByRwId", params); return await get("/api/rw/findInfoByRwId", params);
} };
export const fractionRuleApi = async () => { export const fractionRuleApi = async () => {
return await get( return await get(
@ -75,6 +74,14 @@ export const jsdXkkcSaveApi = async (params: any) => {
export const jsdXkXsListApi = async (params: any) => { export const jsdXkXsListApi = async (params: any) => {
return await get("/mobile/js/xkxs/list", params); return await get("/mobile/js/xkxs/list", params);
}; };
export const mobilejlstudentListApi = async (params: any) => {
return await get("/mobile/jl/studentList", params);
};
export const mobilejllistApi = async (params: any) => {
const res = await get("/mobile/jl/list", params);
return res.result;
};
// 提交点名信息 // 提交点名信息
export const jsdXkdmListApi = async (params: any) => { export const jsdXkdmListApi = async (params: any) => {

View File

@ -1,4 +1,5 @@
const ip: string = "127.0.0.1:8897"; // const ip: string = "192.168.239.1:8897";
const ip: string = "yufangzc.com";
// const ip: string = "yufangzc.com"; // const ip: string = "yufangzc.com";
const fwqip: string = "yufangzc.com"; const fwqip: string = "yufangzc.com";
//打包服务器接口代理标识 //打包服务器接口代理标识

View File

@ -359,21 +359,21 @@
{ {
"path": "pages/view/notice/index", "path": "pages/view/notice/index",
"style": { "style": {
"navigationBarTitleText": "通知公告", "navigationBarTitleText": "发布接龙",
"enablePullDownRefresh": false "enablePullDownRefresh": false
} }
}, },
{ {
"path": "pages/view/notice/detail", "path": "pages/view/notice/detail",
"style": { "style": {
"navigationBarTitleText": "通知详情", "navigationBarTitleText": "接龙详情",
"enablePullDownRefresh": false "enablePullDownRefresh": false
} }
}, },
{ {
"path": "pages/view/notice/publish", "path": "pages/view/notice/publish",
"style": { "style": {
"navigationBarTitleText": "发布通知", "navigationBarTitleText": "接龙推送",
"enablePullDownRefresh": false "enablePullDownRefresh": false
} }
}, },

View File

@ -206,7 +206,7 @@ const sections = reactive<Section[]>([
{ {
id: "r7", id: "r7",
icon: "file-text-fill-2", icon: "file-text-fill-2",
text: "选课详情", text: "课程介绍",
show: true, show: true,
path: "/pages/base/groupTeaching/xkList", path: "/pages/base/groupTeaching/xkList",
}, },
@ -218,6 +218,13 @@ const sections = reactive<Section[]>([
show: true, show: true,
path: "/pages/base/groupTeaching/dmXkList", path: "/pages/base/groupTeaching/dmXkList",
}, },
{
id: "r8",
icon: "draftfill",
text: "发布接龙",
show: true,
path: "/pages/view/notice/index",
},
], ],
}, },
{ {

View File

@ -226,29 +226,6 @@ if (getFile.rgqkList && getFile.rgqkList.length > 0) {
}); });
} }
//
const calculateAllPositionYears = () => {
education.xl.forEach((item: any, index: number) => {
if (item.value.gwrzkstime) {
const years = calculatePositionYears(
item.value.gwrzkstime,
item.value.gwrzjstime
);
item.value.gwrznx = years;
console.log(`表单项${index}计算结果:`, {
gwrzkstime: item.value.gwrzkstime,
gwrzjstime: item.value.gwrzjstime,
gwrznx: years,
是否为0: years === "0",
});
} else {
//
item.value.gwrznx = "";
}
});
forceUpdateKey.value++;
};
function addEducation() { function addEducation() {
education.xl.push({ value: {} }); education.xl.push({ value: {} });
// //

View File

@ -1,120 +1,81 @@
<!-- src/pages/view/notice/index.vue --> <!-- src/pages/view/notice/index.vue -->
<template> <template>
<view class="notice-list-page"> <view class="jl-list-page">
<!-- 列表内容 -->
<BasicListLayout @register="register"> <BasicListLayout @register="register">
<template #default="{ data }"> <template v-slot="{ data }">
<view class="notice-card" @click="goToDetail(data.id)"> <view class="jl-card" @click="goToDetail(data.id)">
<view class="card-header"> <view class="card-header">
<text class="notice-title">{{ data.title }}</text> <text class="jl-title">{{ data.jlmc }}</text>
<text class="notice-status" :class="getStatusClass(data.status)">{{ <text class="jl-status" :class="getStatusClass(data.jlStatus)">
data.statusText {{ getStatusText(data.jlStatus) }}
}}</text> </text>
</view> </view>
<view class="card-body"> <view class="card-body">
<!-- 可选显示封面缩略图 -->
<image <image
v-if="data.coverImage" v-if="data.jlfm"
:src="data.coverImage" :src="imagUrl(data.jlfm)"
mode="aspectFill" mode="aspectFill"
class="cover-thumbnail" class="cover-thumbnail"
></image> ></image>
<text class="notice-excerpt">{{ data.excerpt }}</text> <rich-text class="jl-excerpt" :nodes="data.jlms"></rich-text>
</view> </view>
<view class="card-footer"> <view class="card-footer">
<text class="footer-item">发布者: {{ data.publisher }}</text> <text class="footer-item">发布者: {{ data.jsxm }}</text>
<text class="footer-item">{{ data.publishTime }}</text> <text class="footer-item">{{ formatTime(data.jlFbtime) }}</text>
<text class="footer-item" v-if="data.target" <text class="footer-item" v-if="data.bjmc"
>范围: {{ data.target }}</text >范围: {{ data.njmc + data.bjmc }}</text
> >
</view> </view>
</view> </view>
</template> </template>
</BasicListLayout> <template #bottom>
<view class="white-bg-color py-5">
<!-- 新建通知按钮 --> <view class="flex-row items-center pb-10 pt-5">
<view class="fab-button" @click="goToPublish"> <u-button
<uni-icons type="plusempty" size="24" color="#fff"></uni-icons> text="新增接龙"
class="mx-15"
type="primary"
@click="goToPublish"
/>
</view> </view>
</view> </view>
</template>
</BasicListLayout>
</view>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref } from "vue";
import { useLayout } from "@/components/BasicListLayout/hooks/useLayout"; import { useLayout } from "@/components/BasicListLayout/hooks/useLayout";
import { mobilejllistApi } from "@/api/base/server";
import { imagUrl } from "@/utils";
import BasicDragButton from "@/components/BasicDragButton/DragButton.vue";
interface NoticeItem { interface JlItem {
id: string; id: string;
title: string; jlmc: string; //
excerpt: string; // jlms: string; //
status: "published" | "draft" | "ended"; // jlStatus: string; // AB
statusText: string; // jlFbr: string; //
publisher: string; jlFbtime: string; //
publishTime: string; jlfm: string; //
coverImage?: string; // URL () njmc: string;
target?: string; // () bjmc: string; //
jlkstime: string; //
jljstime: string; //
jsxm?: string;
} }
// API // 使 BasicListLayout
const fetchNoticeList = async (params: any): Promise<any> => {
// Promise<any>
console.log("Fetching notice list with params:", params);
return new Promise((resolve) => {
setTimeout(() => {
// params.pageNo params.pageSize
const pageNo = params.pageNo || 1;
const pageSize = params.pageSize || 10;
const total = 35; //
const mockData: NoticeItem[] = [];
const startIndex = (pageNo - 1) * pageSize;
for (let i = 0; i < pageSize; i++) {
const currentIndex = startIndex + i;
if (currentIndex >= total) break; //
const status =
currentIndex % 3 === 0
? "draft"
: currentIndex % 3 === 1
? "published"
: "ended";
mockData.push({
id: `notice_${currentIndex + 1}`,
title: `重要通知标题 ${currentIndex + 1}`,
excerpt: `这是通知 ${currentIndex + 1} 的内容摘要,只显示一部分...`,
status: status,
statusText:
status === "draft"
? "草稿"
: status === "published"
? "已发布"
: "已结束",
publisher: "教务处",
publishTime: `2024-06-${String(
18 - Math.floor(currentIndex / 5)
).padStart(2, "0")}`,
target: currentIndex % 2 === 0 ? "一年级3班" : "全体教师",
// coverImage: i % 3 === 0 ? '/static/mock/cover.png' : undefined
});
}
resolve({
message: "获取成功",
resultCode: 1,
rows: mockData,
total: total,
});
}, 800); //
});
};
const [register, { reload }] = useLayout({ const [register, { reload }] = useLayout({
api: fetchNoticeList, api: mobilejllistApi, // api使使 query
componentProps: {},
}); });
// //
const goToDetail = (noticeId: string) => { const goToDetail = (jlId: string) => {
uni.navigateTo({ uni.navigateTo({
url: `/pages/view/notice/detail?id=${noticeId}`, url: `/pages/view/notice/detail?id=${jlId}`,
}); });
}; };
@ -126,21 +87,37 @@ const goToPublish = () => {
}; };
// CSS // CSS
const getStatusClass = (status: "published" | "draft" | "ended") => { const getStatusClass = (status: string) => {
if (status === "published") return "status-published"; if (status === "A") return "status-published";
if (status === "draft") return "status-draft"; if (status === "B") return "status-draft";
if (status === "ended") return "status-ended"; return "status-ended";
return ""; };
//
const getStatusText = (status: string) => {
if (status === "A") return "已发布";
if (status === "B") return "暂存";
return "已结束";
};
//
const formatTime = (timeStr: string) => {
if (!timeStr) return "";
const date = new Date(timeStr);
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(
2,
"0"
)}-${String(date.getDate()).padStart(2, "0")}`;
}; };
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.notice-list-page { .jl-list-page {
position: relative; // FAB position: relative; // FAB
min-height: 100vh; // FAB min-height: 100vh; // FAB
} }
.notice-card { .jl-card {
background-color: #ffffff; background-color: #ffffff;
border-radius: 8px; border-radius: 8px;
padding: 15px; padding: 15px;
@ -155,7 +132,7 @@ const getStatusClass = (status: "published" | "draft" | "ended") => {
align-items: flex-start; align-items: flex-start;
margin-bottom: 8px; margin-bottom: 8px;
.notice-title { .jl-title {
font-size: 16px; font-size: 16px;
font-weight: bold; font-weight: bold;
color: #333; color: #333;
@ -169,7 +146,7 @@ const getStatusClass = (status: "published" | "draft" | "ended") => {
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
} }
.notice-status { .jl-status {
font-size: 12px; font-size: 12px;
padding: 2px 6px; padding: 2px 6px;
border-radius: 4px; border-radius: 4px;
@ -180,9 +157,11 @@ const getStatusClass = (status: "published" | "draft" | "ended") => {
&.status-published { &.status-published {
background-color: #19be6b; // 绿- background-color: #19be6b; // 绿-
} }
&.status-draft { &.status-draft {
background-color: #ff9f0a; // -稿 background-color: #ff9f0a; // -
} }
&.status-ended { &.status-ended {
background-color: #999999; // - background-color: #999999; // -
} }
@ -198,7 +177,8 @@ const getStatusClass = (status: "published" | "draft" | "ended") => {
margin-right: 10px; margin-right: 10px;
float: left; // float: left; //
} }
.notice-excerpt {
.jl-excerpt {
font-size: 14px; font-size: 14px;
color: #666; color: #666;
line-height: 1.5; line-height: 1.5;
@ -209,12 +189,6 @@ const getStatusClass = (status: "published" | "draft" | "ended") => {
-webkit-line-clamp: 3; -webkit-line-clamp: 3;
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
} }
// float
// &::after {
// content: "";
// display: table;
// clear: both;
// }
} }
.card-footer { .card-footer {
@ -232,11 +206,8 @@ const getStatusClass = (status: "published" | "draft" | "ended") => {
} }
} }
// FAB // FAB - DragButton
.fab-button { .fab-button {
position: fixed;
right: 20px;
bottom: 40px; //
width: 50px; width: 50px;
height: 50px; height: 50px;
background-color: #4477ee; background-color: #4477ee;
@ -245,6 +216,7 @@ const getStatusClass = (status: "published" | "draft" | "ended") => {
justify-content: center; justify-content: center;
align-items: center; align-items: center;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2); box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
z-index: 10;
} }
/* 空列表样式已由 BasicListLayout 组件处理,移除此样式 */
</style> </style>

View File

@ -15,7 +15,7 @@
<view class="cover-upload-wrapper"> <view class="cover-upload-wrapper">
<CustomUpload <CustomUpload
field="coverImage" field="coverImage"
:value="formData.coverImage" :value="formData.coverImage ? imagUrl(formData.coverImage) : ''"
@select="handleCoverSelected" @select="handleCoverSelected"
@close="handleCoverClosed" @close="handleCoverClosed"
> >
@ -80,21 +80,13 @@
<view class="add-icon" <view class="add-icon"
><uni-icons type="plusempty" size="20" color="#ccc"></uni-icons ><uni-icons type="plusempty" size="20" color="#ccc"></uni-icons
></view> ></view>
<text class="placeholder-text" <text class="placeholder-text">添加图文/视频/文件</text>
>添加图文/视频/文件/公众号/小程序等</text
>
</view> </view>
</view> </view>
</view> </view>
<view class="info-card"> <view class="info-card">
<picker <view class="card-header picker-header" @click="showClassTree">
mode="selector"
:range="combinedClassRange"
:value="selectedClassIndex"
@change="onClassPickerChange"
>
<view class="card-header picker-header">
<text class="section-title">按名单填写</text> <text class="section-title">按名单填写</text>
<view class="target-class"> <view class="target-class">
<text :class="{ placeholder: !formData.targetClass }">{{ <text :class="{ placeholder: !formData.targetClass }">{{
@ -103,22 +95,20 @@
<uni-icons type="right" size="16" color="#999"></uni-icons> <uni-icons type="right" size="16" color="#999"></uni-icons>
</view> </view>
</view> </view>
</picker>
<view class="name-tags"> <view class="name-tags">
<text <text
v-for="name in formData.targetNames" v-for="(name, index) in displayNames"
:key="name" :key="name + index"
class="name-tag" class="name-tag"
>{{ name }}</text >{{ name }}</text
> >
<button </view>
v-if="formData.targetNames.length > 0" <view
size="mini" v-if="formData.targetNames.length > maxDisplayCount"
type="default" class="more-btn-container"
class="modify-btn"
@click="handleModifyNames"
> >
修改 <button size="mini" class="more-btn-full" @click="showAllStudents">
更多({{ formData.targetNames.length - maxDisplayCount }})
</button> </button>
</view> </view>
</view> </view>
@ -166,7 +156,9 @@
<!-- Bottom slot --> <!-- Bottom slot -->
<template #bottom> <template #bottom>
<view class="bottom-actions"> <view class="bottom-actions">
<button class="action-btn draft-btn" @click="saveDraft">保存草稿</button> <button class="action-btn draft-btn" @click="saveDraft">
保存草稿
</button>
<button class="action-btn preview-btn" @click="previewNotice"> <button class="action-btn preview-btn" @click="previewNotice">
预览 预览
</button> </button>
@ -176,6 +168,51 @@
</view> </view>
</template> </template>
<!-- 班级选择树 -->
<BasicTree
ref="treeRef"
:range="treeData"
idKey="key"
rangeKey="title"
title="选择班级"
:multiple="true"
:selectParent="false"
@confirm="onTreeConfirm"
@cancel="onTreeCancel"
/>
<!-- 学生名单弹窗 -->
<view
v-if="showStudentModal"
class="student-modal-mask"
@click="closeStudentModal"
>
<view class="student-modal" @click.stop>
<view class="student-modal-header">
<text class="modal-title">全部学生名单</text>
<text class="student-count"
>{{ formData.targetNames.length }}</text
>
<uni-icons
type="closeempty"
size="20"
color="#999"
@click="closeStudentModal"
class="close-icon"
></uni-icons>
</view>
<scroll-view scroll-y class="student-modal-content">
<view class="all-student-tags">
<text
v-for="(name, index) in formData.targetNames"
:key="name + index"
class="student-tag"
>{{ name }}</text
>
</view>
</scroll-view>
</view>
</view>
</BasicLayout> </BasicLayout>
</template> </template>
@ -183,6 +220,10 @@
import { ref, reactive, computed } from "vue"; import { ref, reactive, computed } from "vue";
import { onLoad } from "@dcloudio/uni-app"; import { onLoad } from "@dcloudio/uni-app";
import CustomUpload from "/src/components/BasicUpload/CustomUpload.vue"; import CustomUpload from "/src/components/BasicUpload/CustomUpload.vue";
import BasicTree from "@/components/BasicTree/Tree.vue";
import { attachmentUpload } from "@/api/system/upload";
import { imagUrl } from "@/utils";
import { findAllNjBjTree, mobilejlstudentListApi } from "@/api/base/server";
interface Attachment { interface Attachment {
name: string; name: string;
@ -200,6 +241,8 @@ interface FormData {
targetClass: string; targetClass: string;
targetNames: string[]; targetNames: string[];
targetStudentIds: string[]; targetStudentIds: string[];
targetNjIds: string[]; // ID
targetBjIds: string[]; // ID
signatureRequired: boolean; signatureRequired: boolean;
startTime: string; startTime: string;
endTime: string; endTime: string;
@ -215,6 +258,8 @@ const formData = reactive<FormData>({
targetClass: "", targetClass: "",
targetNames: [], targetNames: [],
targetStudentIds: [], targetStudentIds: [],
targetNjIds: [],
targetBjIds: [],
signatureRequired: false, signatureRequired: false,
startTime: "", startTime: "",
endTime: "", endTime: "",
@ -225,38 +270,40 @@ const signatureStatusText = computed(() => {
return formData.signatureRequired ? "启用" : "不启用"; return formData.signatureRequired ? "启用" : "不启用";
}); });
const classList = ref([ //
{ id: "g1c1", name: "一年级1班" }, const treeData = ref([]);
{ id: "g1c2", name: "一年级2班" }, const treeRef = ref();
{ id: "g1c3", name: "一年级3班" },
{ id: "g1c4", name: "一年级4班" },
{ id: "g1c5", name: "一年级5班" },
{ id: "g2c1", name: "二年级1班" },
{ id: "g2c2", name: "二年级2班" },
{ id: "g2c3", name: "二年级3班" },
{ id: "g3c1", name: "三年级1班" },
{ id: "g3c2", name: "三年级2班" },
{ id: "g3c3", name: "三年级3班" },
{ id: "g3c4", name: "三年级4班" },
{ id: "g4c1", name: "四年级1班" },
{ id: "g4c2", name: "四年级2班" },
{ id: "g5c1", name: "五年级1班" },
{ id: "g5c2", name: "五年级2班" },
{ id: "g5c3", name: "五年级3班" },
{ id: "g6c1", name: "六年级1班" },
{ id: "g6c2", name: "六年级2班" },
]);
const combinedClassRange = computed(() => { //
return classList.value.map((cls) => cls.name); const maxDisplayCount = 24; // 244×6
const showStudentModal = ref(false);
// 24
const displayNames = computed(() => {
return formData.targetNames.slice(0, maxDisplayCount);
}); });
const selectedClassIndex = computed(() => { //
const index = classList.value.findIndex( const loadTreeData = async () => {
(cls) => cls.name === formData.targetClass try {
); const res = await findAllNjBjTree();
return index >= 0 ? index : 0; if (res.resultCode === 1 && res.result) {
}); // BasicTree
treeData.value = res.result.map((item: any) => ({
key: item.key,
title: item.title,
children: item.children || [],
}));
console.log("树形数据加载成功:", treeData.value);
}
} catch (error) {
console.error("加载树形数据失败:", error);
uni.showToast({ title: "加载班级数据失败", icon: "error" });
}
};
//
loadTreeData();
const fetchStudentsByClass = async (className: string): Promise<string[]> => { const fetchStudentsByClass = async (className: string): Promise<string[]> => {
console.log(`模拟获取班级 [${className}] 的学生列表...`); console.log(`模拟获取班级 [${className}] 的学生列表...`);
@ -281,40 +328,42 @@ const fetchStudentsByClass = async (className: string): Promise<string[]> => {
return mockStudents; return mockStudents;
}; };
onLoad((options) => { onLoad((options) => {});
if (options && options.id) {
noticeId.value = options.id;
uni.setNavigationBarTitle({ title: "编辑通知" });
formData.title = "关于五一放假的通知 (编辑)";
formData.content = "根据校历安排现将2024年五一劳动节放假安排通知如下...";
formData.targetClass = "二年级1班";
formData.targetNames = ["张三", "李四"];
formData.targetStudentIds = ["s201-mock", "s202-mock"];
formData.signatureRequired = true;
formData.startTime = "2024-04-30 18:00:00";
formData.endTime = "2024-05-05 23:59:59";
if (formData.targetClass && noticeId.value) {
fetchStudentsByClass(formData.targetClass).then((students) => {
formData.targetNames = students;
});
}
} else {
uni.setNavigationBarTitle({ title: "发布通知" });
}
});
const handleCoverSelected = (e: any) => { const handleCoverSelected = async (e: any) => {
console.log("选择封面 (CustomUpload):", e);
if (e.tempFilePaths && e.tempFilePaths.length > 0) { if (e.tempFilePaths && e.tempFilePaths.length > 0) {
formData.coverImage = e.tempFilePaths[0]; const tempFilePath = e.tempFilePaths[0];
console.log("封面临时路径:", formData.coverImage);
try {
uni.showLoading({ title: "上传中..." });
// 使 tempFilePath Blob
const uploadResult: any = await attachmentUpload(tempFilePath as any);
if (
uploadResult.resultCode === 1 &&
uploadResult.result &&
uploadResult.result.length > 0
) {
// filePath
const originalPath = uploadResult.result[0].filePath;
formData.coverImage = originalPath;
uni.showToast({ title: "封面上传成功", icon: "success" });
} else {
throw new Error("上传响应格式异常");
}
} catch (error) {
uni.showToast({ title: "封面上传失败", icon: "error" });
formData.coverImage = null;
} finally {
uni.hideLoading();
}
} else { } else {
console.error("无法从选择事件中获取封面路径:", e); console.error("无法从选择事件中获取封面路径:", e);
} }
}; };
const handleCoverClosed = (field: string) => { const handleCoverClosed = (field: string) => {
console.log(`删除封面 (CustomUpload): field=${field}`);
if (field === "coverImage") { if (field === "coverImage") {
formData.coverImage = null; formData.coverImage = null;
} }
@ -324,12 +373,16 @@ const addAttachment = () => {
uni.chooseFile({ uni.chooseFile({
count: 5, count: 5,
type: "all", type: "all",
success: (res) => { success: async (res) => {
const tempFiles = res.tempFiles; const tempFiles = res.tempFiles;
if (Array.isArray(tempFiles) && tempFiles.length > 0) { if (Array.isArray(tempFiles) && tempFiles.length > 0) {
tempFiles.forEach((file: any) => { uni.showLoading({ title: "上传中..." });
try {
for (const file of tempFiles) {
const fileInfo = file as any; //
let fileType = "file"; let fileType = "file";
const fileName = file.name || ""; const fileName = fileInfo.name || "";
const fileExtension = fileName.split(".").pop()?.toLowerCase(); const fileExtension = fileName.split(".").pop()?.toLowerCase();
if ( if (
@ -349,22 +402,45 @@ const addAttachment = () => {
} }
if ( if (
file.type && fileInfo.type &&
typeof file.type === "string" && typeof fileInfo.type === "string" &&
(file.type.startsWith("image/") || (fileInfo.type.startsWith("image/") ||
file.type.startsWith("video/") || fileInfo.type.startsWith("video/") ||
file.type.startsWith("audio/")) fileInfo.type.startsWith("audio/"))
) { ) {
fileType = file.type.split("/")[0]; fileType = fileInfo.type.split("/")[0];
} }
// 使 Blob
const uploadResult: any = await attachmentUpload(
fileInfo.path as any
);
if (
uploadResult.resultCode === 1 &&
uploadResult.result &&
uploadResult.result.length > 0
) {
// filePath
const originalPath = uploadResult.result[0].filePath;
formData.attachments.push({ formData.attachments.push({
name: fileName, name: fileName,
type: fileType, type: fileType,
url: file.path, url: originalPath, //
size: file.size, size: fileInfo.size,
});
}); });
} else {
uni.showToast({ title: `${fileName} 上传失败`, icon: "error" });
}
}
uni.showToast({ title: "附件上传完成", icon: "success" });
} catch (error) {
console.error("附件上传失败:", error);
uni.showToast({ title: "附件上传失败", icon: "error" });
} finally {
uni.hideLoading();
}
} else { } else {
console.log("未选择任何文件或返回结果异常,或 tempFiles 不是数组"); console.log("未选择任何文件或返回结果异常,或 tempFiles 不是数组");
} }
@ -391,38 +467,124 @@ const getAttachmentIcon = (type: string): string => {
const previewAttachment = (attachment: Attachment) => { const previewAttachment = (attachment: Attachment) => {
console.log("预览附件:", attachment); console.log("预览附件:", attachment);
uni.showToast({ title: `预览 ${attachment.name} 功能待实现`, icon: "none" }); //
if (attachment.type === "image") {
const fullUrl = imagUrl(attachment.url);
uni.previewImage({
urls: [fullUrl],
current: fullUrl,
});
} else {
uni.showToast({
title: `预览 ${attachment.name} 功能待实现`,
icon: "none",
});
}
}; };
const onClassPickerChange = async (e: any) => { //
const index = e.detail.value; const showClassTree = () => {
const selectedClass = classList.value[index]; if (treeRef.value) {
if (selectedClass && selectedClass.name !== formData.targetClass) { treeRef.value._show();
formData.targetClass = selectedClass.name; }
};
//
const onTreeConfirm = async (selectedItems: any[]) => {
console.log("选择的班级:", selectedItems);
if (selectedItems.length > 0) {
//
const classNames = selectedItems.map((item) => item.title);
formData.targetClass = classNames.join(", ");
formData.targetNames = []; formData.targetNames = [];
formData.targetStudentIds = []; formData.targetStudentIds = [];
formData.targetNjIds = [];
formData.targetBjIds = [];
try { try {
const students = await fetchStudentsByClass(formData.targetClass); uni.showLoading({ title: "获取学生列表中..." });
formData.targetNames = students;
// IDID
const njIds: string[] = [];
const bjIds: string[] = [];
selectedItems.forEach((item) => {
// parents
if (item.parents && item.parents.length > 0) {
const njId = item.parents[0].key; // IDparents[0].key
const bjId = item.key; // IDitem.key
njIds.push(njId);
bjIds.push(bjId);
console.log(
`选择班级: ${item.title}, 年级ID: ${njId}, 班级ID: ${bjId}`
);
}
});
if (njIds.length > 0 && bjIds.length > 0) {
// ID
const uniqueNjIds = [...new Set(njIds)];
// IDIDformData
formData.targetNjIds = uniqueNjIds;
formData.targetBjIds = bjIds;
//
const params = {
njId: uniqueNjIds.join(","),
bjId: bjIds.join(","),
};
const response = await mobilejlstudentListApi(params);
if (response && response.resultCode === 1 && response.result) {
//
const studentNames = response.result.map(
(student: any) =>
student.xsxm ||
student.name ||
student.studentName ||
student.xm ||
"未知姓名"
);
formData.targetNames = studentNames;
formData.targetStudentIds = response.result.map(
(student: any) =>
student.id || student.xsId || student.studentId || ""
);
} else {
throw new Error("获取学生列表失败");
}
}
uni.hideLoading();
uni.showToast({
title: `已选择 ${selectedItems.length} 个班级`,
icon: "success",
});
} catch (error) { } catch (error) {
console.error("获取学生列表失败:", error); console.error("获取学生列表失败:", error);
uni.showToast({ title: "获取学生列表失败", icon: "none" }); uni.hideLoading();
uni.showToast({ title: "获取学生列表失败", icon: "error" });
// 使
formData.targetNames = await fetchStudentsByClass(formData.targetClass);
} }
} }
}; };
const handleModifyNames = () => { //
const selectedClassObj = classList.value.find( const onTreeCancel = () => {
(cls) => cls.name === formData.targetClass console.log("取消选择班级");
); };
if (!selectedClassObj) {
uni.showToast({ title: "请先选择班级", icon: "none" }); //
return; const showAllStudents = () => {
} showStudentModal.value = true;
const classId = selectedClassObj.id; };
uni.navigateTo({
url: `/pages/view/notice/selectStudents?classId=${classId}`, //
}); const closeStudentModal = () => {
showStudentModal.value = false;
}; };
const handleSignatureChange = (e: any) => { const handleSignatureChange = (e: any) => {
@ -464,13 +626,25 @@ const previewNotice = () => {
const publishNotice = () => { const publishNotice = () => {
if (!validateForm()) return; if (!validateForm()) return;
console.log("发布通知", formData);
uni.showLoading({ title: "发布中..." }); // IDID
setTimeout(() => { const publishData = {
uni.hideLoading(); ...formData,
uni.showToast({ title: "发布成功 (模拟)", icon: "success" }); njIds: formData.targetNjIds.join(","), // ID
uni.navigateBack(); bjIds: formData.targetBjIds.join(","), // ID
}, 1000); };
console.log("发布通知数据:", publishData);
console.log("年级ID:", publishData.njIds);
console.log("班级ID:", publishData.bjIds);
// TODO:
// uni.showLoading({ title: "..." });
// setTimeout(() => {
// uni.hideLoading();
// uni.showToast({ title: " ()", icon: "success" });
// uni.navigateBack();
// }, 1000);
}; };
</script> </script>
@ -734,8 +908,7 @@ const publishNotice = () => {
position: relative; position: relative;
min-height: 30px; min-height: 30px;
.name-tag, .name-tag {
.modify-btn {
font-size: 13px; font-size: 13px;
padding: 5px 0; padding: 5px 0;
border-radius: 4px; border-radius: 4px;
@ -746,29 +919,10 @@ const publishNotice = () => {
flex-basis: calc((100% - 50px) / 6); flex-basis: calc((100% - 50px) / 6);
height: 28px; height: 28px;
line-height: 18px; line-height: 18px;
}
.name-tag {
background-color: #f4f4f5; background-color: #f4f4f5;
color: #909399; color: #909399;
} }
.modify-btn {
background-color: #ecf5ff;
color: #409eff;
border: 1px solid #d9ecff;
padding: 0;
margin-left: 0;
margin-top: 0;
margin-bottom: 0;
&::after {
border: none;
}
display: flex;
justify-content: center;
align-items: center;
}
.loading-spinner { .loading-spinner {
position: absolute; position: absolute;
top: 5px; top: 5px;
@ -778,6 +932,26 @@ const publishNotice = () => {
} }
} }
.more-btn-container {
width: 100%;
}
.more-btn-full {
width: 100%;
height: 35px;
background-color: #fff2e8;
color: #e6a23c;
border: 1px solid #f5dab1;
border-radius: 4px;
font-size: 14px;
&::after {
border: none;
}
&:active {
background-color: #ffecd1;
}
}
.list-item-card { .list-item-card {
padding: 0; padding: 0;
.uni-datetime-picker, .uni-datetime-picker,
@ -890,4 +1064,73 @@ const publishNotice = () => {
color: #909399; color: #909399;
} }
/* 学生名单弹窗样式 */
.student-modal-mask {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
z-index: 9999;
display: flex;
justify-content: center;
align-items: center;
}
.student-modal {
width: 90%;
max-height: 80%;
background-color: #ffffff;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
.student-modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px 20px;
border-bottom: 1px solid #f0f0f0;
background-color: #fafafa;
}
.modal-title {
font-size: 16px;
font-weight: 500;
color: #303133;
}
.student-count {
font-size: 14px;
color: #909399;
}
.close-icon {
cursor: pointer;
padding: 5px;
}
.student-modal-content {
max-height: 400px;
padding: 20px;
}
.all-student-tags {
display: flex;
flex-wrap: wrap;
gap: 8px 10px;
}
.student-tag {
font-size: 13px;
padding: 6px 12px;
border-radius: 4px;
text-align: center;
background-color: #f4f4f5;
color: #909399;
min-width: 60px;
box-sizing: border-box;
}
</style> </style>