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

513 lines
13 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="p-4">
<!-- 周范围选择 -->
<view class="mb-4">
<text class="text-base font-bold mb-2">周报周期</text>
<view class="flex gap-2 items-center">
<cl-input
v-model="form.weekStartDate"
type="date"
placeholder="周开始日期"
:max="todayDate"
/>
<text>至</text>
<cl-input
v-model="form.weekEndDate"
type="date"
placeholder="周结束日期"
:max="todayDate"
/>
</view>
<view class="mt-2">
<cl-button
type="primary"
size="small"
@tap="setCurrentWeek"
>
设置为本周
</cl-button>
</view>
</view>
<!-- 输入方式选择 -->
<view class="mb-4">
<text class="text-base font-bold mb-2">输入方式</text>
<view class="flex gap-2">
<cl-button
:type="inputType === 0 ? 'primary' : 'default'"
size="small"
@tap="inputType = 0"
>
文字输入
</cl-button>
<cl-button
:type="inputType === 1 ? 'primary' : 'default'"
size="small"
@tap="inputType = 1"
>
语音输入
</cl-button>
</view>
</view>
<!-- 语音输入区域 -->
<view v-if="inputType === 1" class="mb-4">
<text class="text-base font-bold mb-2">语音录制</text>
<view class="flex flex-col items-center p-6 bg-gray-50 rounded-lg">
<text class="text-gray-500 mb-4">语音录制功能暂未在H5环境实现</text>
<text class="text-gray-500 mb-4">请切换到文字输入</text>
</view>
</view>
<!-- 文字输入区域 -->
<view v-if="inputType === 0" class="mb-4">
<view class="p-4 bg-white rounded-2xl">
<cl-form>
<cl-form-item label="工作内容" required>
<cl-input
v-model="originalText"
placeholder="请输入本周的工作内容"
:maxlength="2000"
/>
</cl-form-item>
</cl-form>
</view>
</view>
<!-- AI格式化按钮 -->
<view v-if="originalText" class="mb-4">
<cl-button
type="success"
size="large"
block
@tap="formatWithAI"
:loading="isFormatting"
>
{{ isFormatting ? 'AI生成中...' : '🤖 AI生成周报' }}
</cl-button>
</view>
<!-- AI生成的周报内容 -->
<view v-if="aiFormattedContent" class="mb-4">
<text class="text-base font-bold mb-2">AI生成的周报</text>
<view class="p-3 bg-green-50 rounded-lg mb-2">
<cl-markdown :content="aiFormattedContent" />
</view>
<text class="text-sm text-gray-500">您可以在下方编辑最终内容</text>
</view>
<!-- 最终编辑区域 -->
<view v-if="aiFormattedContent" class="mb-4">
<view class="p-4 bg-white rounded-2xl">
<cl-form>
<cl-form-item label="最终周报内容" required>
<cl-input
v-model="userEditedContent"
placeholder="请编辑最终的周报内容"
:maxlength="3000"
/>
</cl-form-item>
</cl-form>
</view>
</view>
<!-- 从日报自动生成 -->
<view class="mb-4">
<cl-button
type="primary"
size="large"
block
@tap="generateFromDaily"
:loading="isGenerating"
>
{{ isGenerating ? '生成中..' : '📝 从我的日报生成' }}
</cl-button>
</view>
<!-- 操作按钮 -->
<view v-if="userEditedContent" class="flex gap-2 mt-6">
<cl-button
type="default"
size="large"
:flex="1"
@tap="saveDraft"
:loading="isSavingDraft"
>
{{ isSavingDraft ? '保存中...' : '保存草稿' }}
</cl-button>
<cl-button
type="primary"
size="large"
:flex="1"
@tap="submitReport"
:loading="isSubmitting"
>
{{ isSubmitting ? '提交中...' : '提交周报' }}
</cl-button>
</view>
</view>
</cl-page>
</template>
<script setup lang="ts">
import { ref, computed, onMounted } from "vue";
import { request, router, useStore } from "@/cool";
import { useUi } from "@/uni_modules/cool-ui";
const ui = useUi();
const { user } = useStore();
// 表单数据
const form = ref({
weekStartDate: "",
weekEndDate: "",
userId: 0
});
// 输入方式0-文字1-语音
const inputType = ref<number>(0);
// 文字输入
const originalText = ref("");
// AI格式化相关
const isFormatting = ref(false);
const aiFormattedContent = ref("");
const userEditedContent = ref("");
// 按日报生成相关
const isGenerating = ref(false);
// 提交相关
const isSavingDraft = ref(false);
const isSubmitting = ref(false);
// 今天的日期
const todayDate = computed(() => {
const today = new Date();
return `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, "0")}-${String(today.getDate()).padStart(2, "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);
// 获取当前登录用户ID
if (user.info.value && user.info.value.id) {
form.value.userId = user.info.value.id;
console.log("【周报提交】设置userId:", form.value.userId);
} else {
console.error("【周报提交】用户未登录或用户信息为空");
ui.showToast({
message: "请先登录",
type: "error"
});
setTimeout(() => {
router.to("/pages/user/login");
}, 1000);
return;
}
// 设置默认为本周
setCurrentWeek();
// 检查本周是否已有周报
checkCurrentWeekReport();
});
// 设置为本周
function setCurrentWeek() {
const today = new Date();
const dayOfWeek = today.getDay();
// 计算周一如果今天是周日dayOfWeek=0需要特殊处理
const diff = dayOfWeek === 0 ? -6 : 1 - dayOfWeek;
const monday = new Date(today);
monday.setDate(today.getDate() + diff);
// 计算周日
const sunday = new Date(monday);
sunday.setDate(monday.getDate() + 6);
form.value.weekStartDate = formatDateToString(monday);
form.value.weekEndDate = formatDateToString(sunday);
console.log("【周报提交】设置本周范围:", form.value.weekStartDate, "-", form.value.weekEndDate);
}
// 格式化日期为字符串
function formatDateToString(date: Date) {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, "0");
const day = String(date.getDate()).padStart(2, "0");
return `${year}-${month}-${day}`;
}
// 检查本周是否已有周报
async function checkCurrentWeekReport() {
try {
const res = await request({
url: "/app/weeklyreport/report/currentWeekReport",
method: "GET",
params: { userId: form.value.userId }
});
if (res && res.id) {
// 本周已有周报,询问是否继续编辑
uni.showModal({
title: "提示",
content: `本周已经${res.status === 1 ? "提交" : "保存"}了周报,是否继续编辑?`,
success: (modalRes) => {
if (modalRes.confirm) {
// 加载已有周报
loadExistingReport(res);
} else {
// 跳转到列表页
router.back();
}
}
});
}
} catch (error) {
console.log("本周还没有周报,可以新建");
}
}
// 加载已有周报
function loadExistingReport(report: any) {
originalText.value = report.originalText || "";
aiFormattedContent.value = report.aiFormattedContent || "";
userEditedContent.value = report.userEditedContent || "";
inputType.value = report.inputType || 0;
}
// AI格式化
async function formatWithAI() {
const text = originalText.value;
if (!text) {
return ui.showToast({
message: "请先输入内容",
type: "error"
});
}
isFormatting.value = true;
try {
const res = await request({
url: "/app/weeklyreport/report/aiFormat",
method: "POST",
data: {
originalText: text,
weekStartDate: form.value.weekStartDate,
weekEndDate: form.value.weekEndDate
}
});
// 后端返回的是对象 {formattedContent: "内容", length: 数字}
const formattedContent = res.formattedContent || res;
aiFormattedContent.value = formattedContent;
userEditedContent.value = formattedContent;
ui.showToast({
message: "AI生成成功",
type: "success"
});
} catch (error: any) {
console.error("AI格式化失败:", error);
ui.showToast({
message: "AI格式化失败: " + (error.message || "未知错误"),
type: "error"
});
} finally {
isFormatting.value = false;
}
}
// 从日报自动生成周报
async function generateFromDaily() {
if (!form.value.weekStartDate || !form.value.weekEndDate) {
return ui.showToast({ message: "请先选择周范围", type: "error" });
}
isGenerating.value = true;
try {
// 优先调用后端聚合接口
try {
const res = await request({
url: "/app/weeklyreport/report/generateFromDaily",
method: "POST",
data: {
userId: form.value.userId,
weekStartDate: form.value.weekStartDate,
weekEndDate: form.value.weekEndDate
}
});
const formatted = res.formattedContent || res;
aiFormattedContent.value = formatted || "";
userEditedContent.value = formatted || "";
ui.showToast({ message: "已从日报生成", type: "success" });
return;
} catch (e1: any) {
console.warn("后端聚合接口不可用,回退到前端聚合:", e1?.message || e1);
}
// 回退前端聚合本周已提交日报再调用现有AI格式化
const dailyList = await request({
url: "/app/dailyreport/report/myReports",
method: "GET",
params: {
userId: form.value.userId,
startDate: form.value.weekStartDate,
endDate: form.value.weekEndDate,
status: 1
}
});
if (!Array.isArray(dailyList) || dailyList.length === 0) {
throw new Error("本周没有已提交的日报");
}
// 按日期升序拼接内容
dailyList.sort((a: any, b: any) => new Date(a.reportDate).getTime() - new Date(b.reportDate).getTime());
const source = dailyList.map((r: any) => {
const content = r.userEditedContent || r.aiFormattedContent || r.originalText || "";
if (!content) return "";
return `# ${r.reportDate}\n${content}`;
}).filter(Boolean).join("\n\n");
if (!source) {
throw new Error("本周日报内容为空,无法生成周报");
}
const res2 = await request({
url: "/app/weeklyreport/report/aiFormat",
method: "POST",
data: {
originalText: source,
weekStartDate: form.value.weekStartDate,
weekEndDate: form.value.weekEndDate
}
});
const formatted2 = res2.formattedContent || res2;
aiFormattedContent.value = formatted2 || "";
userEditedContent.value = formatted2 || "";
ui.showToast({ message: "已从日报生成", type: "success" });
} catch (error: any) {
console.error("按日报生成失败:", error);
ui.showToast({ message: "生成失败: " + (error.message || "未知错误"), type: "error" });
} finally {
isGenerating.value = false;
}
}
// 保存草稿
async function saveDraft() {
if (!userEditedContent.value) {
return ui.showToast({
message: "请先生成周报内容",
type: "error"
});
}
isSavingDraft.value = true;
try {
await request({
url: "/app/weeklyreport/report/saveDraft",
method: "POST",
data: {
userId: form.value.userId,
weekStartDate: form.value.weekStartDate,
weekEndDate: form.value.weekEndDate,
originalText: originalText.value,
aiFormattedContent: aiFormattedContent.value,
userEditedContent: userEditedContent.value,
inputType: inputType.value
}
});
ui.showToast({
message: "草稿保存成功",
type: "success"
});
// 延迟跳转
setTimeout(() => {
router.back();
}, 1000);
} catch (error: any) {
console.error("保存草稿失败:", error);
ui.showToast({
message: "保存草稿失败: " + (error.message || "未知错误"),
type: "error"
});
} finally {
isSavingDraft.value = false;
}
}
// 提交周报
async function submitReport() {
if (!userEditedContent.value) {
return ui.showToast({
message: "请先生成周报内容",
type: "error"
});
}
isSubmitting.value = true;
try {
await request({
url: "/app/weeklyreport/report/submit",
method: "POST",
data: {
userId: form.value.userId,
weekStartDate: form.value.weekStartDate,
weekEndDate: form.value.weekEndDate,
originalText: originalText.value,
aiFormattedContent: aiFormattedContent.value,
userEditedContent: userEditedContent.value,
inputType: inputType.value
}
});
ui.showToast({
message: "周报提交成功",
type: "success"
});
// 延迟跳转
setTimeout(() => {
router.back();
}, 1000);
} catch (error: any) {
console.error("提交周报失败:", error);
ui.showToast({
message: "提交周报失败: " + (error.message || "未知错误"),
type: "error"
});
} finally {
isSubmitting.value = false;
}
}
</script>
<style scoped>
.gap-2 {
gap: 0.5rem;
}
</style>