ykt-wxapp/pages/work/todo/todo-detail.vue

313 lines
11 KiB
Vue
Raw Normal View History

2026-02-02 17:49:17 +08:00
<template>
<full-page v-if="todo" pageClass="bg-white">
<view class="px-15 py-12 border-b">
<view class="flex items-center">
<view class="mr-5 text-lg text-dark font-semibold">{{ todo.eventTypeLabel }}</view>
<view class="bg-light-text-color px-10 py-3 leading-normal text-base rounded overflow-hidden"
:class="statusClassNames[todo.eventStatus] || 'text-gray'">
{{ todo.eventStatusLabel }}
</view>
</view>
<view v-if="!canEdit" class="mt-5 text-base text-gray break-all">
{{ todo.taskContent || "暂无任务内容" }}
</view>
</view>
<view class="px-15 py-12 border-b">
<view class="text-lg text-dark font-semibold">发送内容</view>
<view class="mt-5 text-base text-gray break-all">
{{ todo.sendContent }}
</view>
<view v-for="(file, idx) in todo.fileList" :key="idx" class="mt-5 text-base text-gray break-all">
附件{{ file.file.name }}
</view>
</view>
<template v-if="canEdit">
<picker mode="date" :value="formData.planDate" @change="changePlanDate($event)">
<view class="flex items-center py-10 px-15 border-b">
<view class="text-base text-gray">计划执行时间</view>
<view class="flex-grow"></view>
<view class="text-base text-dark">{{ formData.planDate }}</view>
<view class="flex-shrink-0">
<uni-icons type="right" size="16" color="#999999" />
</view>
</view>
</picker>
<picker mode="selector" :range="memberList" range-key="name" :value="formData.executorUserId"
@change="changeExecutorUserId($event)">
<view class="flex items-center py-10 px-15 border-b">
<view class="text-base text-gray">执行人</view>
<view class="flex-grow"></view>
<view class="text-base text-dark">{{ memberMap[formData.executorUserId] || '' }}</view>
<view class="flex-shrink-0">
<uni-icons type="right" size="16" color="#999999" />
</view>
</view>
</picker>
<picker mode="selector" :range="eventTypeList" range-key="label" :value="formData.eventType"
@change="changeEventType($event)">
<view class="flex items-center py-10 px-15 border-b">
<view class="text-base text-gray">回访类型</view>
<view class="flex-grow"></view>
<view class="text-base text-dark">{{ ToDoEventType[formData.eventType] || '' }}</view>
<view class="flex-shrink-0">
<uni-icons type="right" size="16" color="#999999" />
</view>
</view>
</picker>
<view class="px-15 py-12 border-b">
<view class="text-lg text-dark font-semibold">任务内容</view>
<view class="mt-5 p-10 border rounded">
<textarea :value="formData.taskContent" class="w-full h-120 text-base text-dark" @input="changeTaskContent($event)" />
</view>
</view>
</template>
<!-- v-else -->
<template v-else>
<view class="flex items-center justify-between py-10 px-15 border-b">
<view class="text-base text-gray">计划执行时间</view>
<view class="text-base text-dark">{{ todo.planDate }}</view>
</view>
<view class="flex items-center justify-between py-10 px-15 border-b">
<view class="text-base text-gray">执行人</view>
<view class="text-base text-dark">{{ memberMap[todo.executorUserId] || '' }}</view>
</view>
<view class="px-15 py-12 border-b">
<view class="text-lg text-dark font-semibold">回访结果</view>
<view class="mt-5 p-10 border rounded">
<textarea :value="formData.result" class="w-full h-120 text-base text-dark" @input="changeResult($event)" />
</view>
</view>
</template>
<view class="px-15 py-12 border-b">
<view class="text-base text-gray">创建人{{ todo.creatorUserId }}</view>
<view class="text-base text-gray">创建时间{{ todo.createTime }}</view>
<view v-if="todo.endTime" class="text-base text-gray">执行时间{{ todo.endTime }}</view>
</view>
<template #footer>
<button-footer v-if="canEdit" confirmText="保存" :showCancel="false" @confirm="save()" />
<button-footer v-else-if="editable" cancelText="取消任务" confirmText="设为完成" @cancel="cancelTask()"
@confirm="completeTask()" />
<button-footer v-else-if="canWriteResult" confirmText="保存" :showCancel="false" @confirm="saveResult()" />
</template>
</full-page>
</template>
<script setup>
import { computed, ref } from "vue";
import { storeToRefs } from "pinia";
import dayjs from "dayjs";
import { statusNames, ToDoEventType, statusClassNames } from '@/baseData';
import useGuard from "@/hooks/useGuard.js";
import useAccountStore from "@/store/account.js";
import api from "@/utils/api.js";
import { confirm, toast } from "@/utils/widget";
import buttonFooter from '@/components/button-footer.vue';
import fullPage from '@/components/full-page.vue';
const { useLoad } = useGuard();
const { doctorInfo, account } = storeToRefs(useAccountStore());
const todo = ref(null);
const team = ref(null);
const form = ref({});
const isEditTodo = ref(false);
const formData = computed(() => ({ ...(todo.value || {}), ...form.value }));
const teamManager = computed(() => {
const memberLeaderList = team.value && Array.isArray(team.value.memberLeaderList) ? team.value.memberLeaderList : [];
return doctorInfo.value && memberLeaderList.includes(doctorInfo.value.userid);
})
const hasPermission = computed(() => {
const userid = doctorInfo.value && doctorInfo.value.userid;
return userid && todo.value && (userid === todo.value.executorUserId || teamManager.value);
})
const memberList = computed(() => {
const memberList = team.value && Array.isArray(team.value.memberList) ? team.value.memberList : [];
return memberList.map(i => ({ name: i.anotherName, value: i.userid }))
})
const memberMap = computed(() => memberList.value.reduce((m, item) => {
m[item.value] = item.name;
return m
}, {}))
const canEdit = computed(() => isEditTodo.value && ['notStart', 'processing'].includes(todo.value?.eventStatus))
const canWriteResult = computed(() => {
return hasPermission.value && 'treated' === todo.value?.eventStatus;
})
const editable = computed(() => {
const statusRight = ['notStart', 'processing'].includes(todo.value?.eventStatus);
return hasPermission.value && statusRight;
})
const eventTypeList = computed(() => Object.keys(ToDoEventType).map((key) => ({ label: ToDoEventType[key], value: key })));
function getVisitPlanStatus(row) {
if (row.eventStatus === "untreated" && dayjs().isBefore(dayjs(row.plannedExecutionTime))) {
return "notStart";
} else if (row.eventStatus === "untreated" && dayjs().isAfter(dayjs(row.plannedExecutionTime)) && dayjs().isBefore(dayjs(row.expireTime))) {
return "processing";
} else if (row.eventStatus === "treated") {
return "treated";
} else if (row.eventStatus === "closed") {
return "cancelled";
} else if (row.eventStatus === "expired" || dayjs().isAfter(row.expireTime)) {
return "expired";
}
return "";
}
function changePlanDate(e) {
form.value.planDate = e.detail.value;
}
function changeExecutorUserId(e) {
const idx = e.detail.value;
const user = memberList[idx];
form.value.executorUserId = user.value;
}
function changeEventType(e) {
const idx = e.detail.value;
const type = eventTypeList[idx];
form.value.eventType = type.value;
}
function changeTaskContent(e) {
form.value.taskContent = e.detail.value;
}
function changeResult(e) {
form.value.result = e.detail.value;
}
async function save() {
if (!formData.value.eventType) {
return toast('请选择回访类型');
}
if (!formData.value.planDate) {
return toast("请选择执行时间");
}
if (!formData.value.executorUserId) {
return toast("请选择处理人");
}
const taskParams = {
eventType: formData.value.eventType,
planExecutionTime: dayjs(formData.value.planDate).valueOf(),
executorUserId: formData.value.executorUserId,
executorTeamId: formData.value.executorTeamId || undefined,
executeTeamName: formData.value.executeTeamName || undefined,
taskContent: formData.value.taskContent || undefined,
}
const params = {
id: todo.value._id,
task: taskParams,
corpId: account.value.corpId
}
const res = await api('updateTaskTodo', params);
if (res && res.success) {
await toast('保存成功');
uni.navigateBack();
} else {
toast(res?.message || '保存失败')
}
}
async function cancelTask() {
await confirm('确定取消该回访任务吗');
const res = await api('setTodoStatus', {
id: todo.value._id,
eventStatus: 'closed',
result: formData.value.result || '已取消',
userId: doctorInfo.value.userid,
})
if (res && res.success) {
await toast('取消成功');
uni.navigateBack();
} else {
toast(res?.message || '取消失败')
}
}
async function completeTask() {
await confirm('确定完成该回访任务吗');
const res = await api('setTodoStatus', {
id: todo.value._id,
eventStatus: 'treated',
result: formData.value.result || '已完成',
userId: doctorInfo.value.userid,
})
if (res && res.success) {
await toast('操作成功');
uni.navigateBack();
} else {
toast(res?.message || '操作失败')
}
}
async function saveResult() {
if (typeof formData.value.result !== 'string' || formData.value.result.trim() === '') {
return toast('请填写回访结果')
}
const res = await api('updateTaskTodoResult', {
id: todo.value._id,
result: formData.value.result.trim(),
})
if (res && res.success) {
await toast('操作成功');
uni.navigateBack();
} else {
toast(res?.message || '操作失败')
}
}
async function getDetail(id) {
const res = await api('getTodoById', { id, corpId: account.value.corpId });
if (res && res.success) {
const eventStatus = getVisitPlanStatus(res.data);
todo.value = {
...res.data,
eventTypeLabel: ToDoEventType[res.data.eventType],
planDate: res.data.plannedExecutionTime && dayjs(res.data.plannedExecutionTime).isValid() ? dayjs(res.data.plannedExecutionTime).format("YYYY-MM-DD") : "",
endTime: res.data.endTime && dayjs(res.data.endTime).isValid() ? dayjs(res.data.endTime).format("YYYY-MM-DD HH:mm") : "",
createTime: res.data.createTime && dayjs(res.data.createTime).isValid() ? dayjs(res.data.createTime).format("YYYY-MM-DD HH:mm") : "",
eventStatus,
eventStatusLabel: statusNames[eventStatus],
fileList: Array.isArray(res.data.fileList) ? res.data.fileList.filter(i => i && i.file && i.file.name) : []
};
if (todo.value.executeTeamId) {
getTeamDetail(todo.value.executeTeamId)
}
console.log(ToDoEventType, res.data.eventType, ToDoEventType[res.data.eventType])
} else {
toast(res?.message || '获取数据失败')
}
}
async function getTeamDetail(teamId) {
const res = await api('getTeamData', { teamId, corpId: account.value.corpId });
if (res && res.success) {
team.value = res.data;
} else {
await toast(res.message || '获取团队信息失败')
uni.navigateBack();
}
}
useLoad(opts => {
console.clear()
isEditTodo.value = opts.editMode === 'YES';
getDetail(opts.id);
})
</script>
<style>
.mt-5 {
margin-top: 10rpx;
}
.h-120 {
height: 240rpx;
}
</style>