313 lines
11 KiB
Vue
313 lines
11 KiB
Vue
|
|
<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>
|