Files
2025-11-13 10:36:23 +08:00

324 lines
8.5 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<cl-page title="我的周报">
<!-- 筛选栏 -->
<view class="px-4 py-3 bg-white border-b">
<view class="flex gap-2">
<cl-button
:type="filterType === 'all' ? 'primary' : 'default'"
size="small"
@tap="changeFilter('all')"
>
全部
</cl-button>
<cl-button
:type="filterType === 'draft' ? 'primary' : 'default'"
size="small"
@tap="changeFilter('draft')"
>
草稿
</cl-button>
<cl-button
:type="filterType === 'submitted' ? 'primary' : 'default'"
size="small"
@tap="changeFilter('submitted')"
>
已提交
</cl-button>
</view>
</view>
<!-- 周报列表 -->
<scroll-view scroll-y class="flex-1">
<!-- 加载中 -->
<view v-if="loading && list.length === 0" class="flex items-center justify-center py-20">
<text class="text-gray-400">加载中...</text>
</view>
<!-- 列表内容 -->
<view v-else-if="list.length > 0">
<view
v-for="(item, index) in list"
:key="item.id || index"
class="mx-4 my-2 p-4 bg-white rounded-lg shadow-sm"
@tap="toDetail(item)"
>
<!-- 头部:周范围和状态 -->
<view class="flex justify-between items-center mb-3">
<view class="flex items-center gap-2">
<text class="text-lg font-bold">
{{ formatWeekRange(item.weekStartDate, item.weekEndDate) }}
</text>
</view>
<view
:class="[
'px-2 py-1 rounded text-xs',
item.status === 1 ? 'bg-green-100 text-green-700' : 'bg-yellow-100 text-yellow-700'
]"
>
{{ item.status === 1 ? "已提交" : "草稿" }}
</view>
</view>
<!-- 内容摘要 -->
<view class="mb-3">
<text class="text-sm text-gray-700">
{{ getContentPreview(item.userEditedContent) }}
</text>
</view>
<!-- 底部信息 -->
<view class="flex justify-between items-center text-xs text-gray-500">
<view class="flex items-center gap-2">
<text>{{ item.inputType === 1 ? "🎤 语音输入" : "⌨️ 文字输入" }}</text>
</view>
<text v-if="item.submitTime">
提交于 {{ formatTime(item.submitTime) }}
</text>
<text v-else-if="item.createTime">
创建于 {{ formatTime(item.createTime) }}
</text>
</view>
</view>
<!-- 加载更多提示 -->
<view v-if="loading" class="flex items-center justify-center py-4">
<text class="text-gray-400 text-sm">加载中...</text>
</view>
<view v-else-if="finished" class="flex items-center justify-center py-4">
<text class="text-gray-400 text-sm">没有更多了</text>
</view>
</view>
<!-- 空状态 -->
<view v-else class="flex flex-col items-center justify-center py-20">
<text class="text-6xl mb-4">📝</text>
<text class="text-gray-400 text-base">暂无周报</text>
<view
class="mt-4 px-4 py-2 bg-blue-500 text-white rounded"
@tap="toSubmit"
>
<text>去提交周报</text>
</view>
</view>
</scroll-view>
<!-- 悬浮提交按钮 -->
<view class="fixed bottom-20 right-4">
<cl-button
type="primary"
size="large"
round
@tap="toSubmit"
>
<text class="text-2xl">✏️</text>
</cl-button>
</view>
</cl-page>
</template>
<script setup lang="ts">
import { ref, onMounted } from "vue";
import { request, router, useStore } from "@/cool";
import { useUi } from "@/uni_modules/cool-ui";
const ui = useUi();
const { user } = useStore();
// 列表相关
const list = ref<any[]>([]);
const loading = ref(false);
const finished = ref(false);
const page = ref(1);
const pageSize = ref(20);
// 筛选类型
const filterType = ref<"all" | "draft" | "submitted">("all");
// 用户ID从登录状态获取
const userId = ref(0);
// 初始化
onMounted(async () => {
console.log("【周报列表】页面加载, user.info:", user.info.value);
// 先尝试获取最新用户信息
if (user.token) {
try {
await user.get();
} catch (e) {
console.error("【周报列表】获取用户信息失败:", e);
}
}
console.log("【周报列表】获取用户信息后, user.info:", user.info.value);
if (user.info.value && user.info.value.id) {
userId.value = user.info.value.id;
console.log("【周报列表】设置userId:", userId.value);
loadReports();
} else {
console.error("【周报列表】用户未登录或用户信息为空");
ui.showToast({
message: "请先登录",
type: "error"
});
setTimeout(() => {
router.to("/pages/user/login");
}, 1000);
}
});
// 加载周报列表
async function loadReports() {
if (loading.value || finished.value) return;
loading.value = true;
try {
console.log("【周报列表】开始加载, userId:", userId.value);
if (!userId.value || userId.value === 0) {
console.error("【周报列表】userId无效:", userId.value);
throw new Error("用户ID无效请重新登录");
}
const params: any = {
userId: userId.value,
page: page.value,
size: pageSize.value
};
// 添加状态筛选
if (filterType.value === "draft") {
params.status = 0;
} else if (filterType.value === "submitted") {
params.status = 1;
}
console.log("【周报列表】请求参数:", params);
const res = await request({
url: "/app/weeklyreport/report/myReports",
method: "GET",
params
});
console.log("【周报列表】响应数据:", res);
console.log("【周报列表】响应类型:", typeof res);
console.log("【周报列表】是否为数组:", Array.isArray(res));
console.log("【周报列表】数据长度:", res ? res.length : 0);
if (res && res.length > 0) {
console.log("【周报列表】开始填充列表数据");
if (page.value === 1) {
list.value = res;
} else {
list.value.push(...res);
}
page.value++;
console.log("【周报列表】列表已更新, 当前list长度:", list.value.length);
console.log("【周报列表】列表第一项数据:", list.value[0]);
// 如果返回数据少于每页大小,说明已经到底了
if (res.length < pageSize.value) {
finished.value = true;
}
} else {
console.log("【周报列表】无数据或数据为空");
// 即使没有数据也不应该标记为finished可能只是筛选条件没有匹配的数据
if (page.value === 1) {
list.value = [];
}
finished.value = true;
}
} catch (error: any) {
console.error("加载周报列表失败:", error);
ui.showToast({
message: "加载失败: " + (error.message || "未知错误"),
type: "error"
});
} finally {
loading.value = false;
}
}
// 下拉刷新
function onRefresh() {
console.log("【周报列表】下拉刷新");
page.value = 1;
finished.value = false;
list.value = [];
loadReports();
}
// 切换筛选条件
function changeFilter(type: "all" | "draft" | "submitted") {
console.log("【周报列表】切换筛选:", type);
filterType.value = type;
page.value = 1;
finished.value = false;
list.value = [];
loadReports();
}
// 跳转到详情
function toDetail(item: any) {
router.to(`/pages/weeklyreport/detail?id=${item.id}`);
}
// 跳转到提交页面
function toSubmit() {
router.to("/pages/weeklyreport/submit");
}
// 格式化周范围
function formatWeekRange(startDate: string, endDate: string) {
if (!startDate || !endDate) return "";
const start = new Date(startDate);
const end = new Date(endDate);
const startMonth = String(start.getMonth() + 1).padStart(2, "0");
const startDay = String(start.getDate()).padStart(2, "0");
const endMonth = String(end.getMonth() + 1).padStart(2, "0");
const endDay = String(end.getDate()).padStart(2, "0");
return `${startMonth}月${startDay}日 - ${endMonth}月${endDay}日`;
}
// 格式化时间
function formatTime(timeStr: string) {
if (!timeStr) return "";
const date = new Date(timeStr);
const month = String(date.getMonth() + 1).padStart(2, "0");
const day = String(date.getDate()).padStart(2, "0");
const hours = String(date.getHours()).padStart(2, "0");
const minutes = String(date.getMinutes()).padStart(2, "0");
return `${month}-${day} ${hours}:${minutes}`;
}
// 获取内容摘要
function getContentPreview(content: string) {
if (!content) return "(无内容)";
// 移除 Markdown 标记
const plain = content.replace(/[#*`\[\]()]/g, "").trim();
// 限制长度
return plain.length > 100 ? plain.substring(0, 100) + "..." : plain;
}
</script>
<style scoped>
.gap-2 {
gap: 0.5rem;
}
.line-clamp-3 {
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
}
</style>