Files
yunzerwebsiteallinone/uniapp/pages/tools/schedule/edit.vue
T

336 lines
7.5 KiB
Vue
Raw 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>
<view class="page">
<view v-if="isCompleted" class="completed-notice">
<FaIcon name="circle-check" color="#67c23a" :size="40" />
<text>该日程已完成,不可编辑</text>
</view>
<view class="form-card" :class="{ 'is-disabled': isCompleted }">
<view class="field">
<text class="field-label">标题 <text class="required">*</text></text>
<u-input
v-model="form.title"
placeholder="输入日程标题"
:maxlength="80"
border="none"
:disabled="isCompleted"
/>
</view>
<view class="field">
<text class="field-label">日期 <text class="required">*</text></text>
<picker mode="date" :value="form.date" @change="onDateChange" :disabled="isCompleted">
<view class="picker-value">
<text>{{ form.date || '选择日期' }}</text>
<FaIcon name="calendar-days" color="#909399" :size="16" />
</view>
</picker>
</view>
<view class="field switch-field">
<view class="switch-info">
<text class="field-label">全天</text>
<text class="form-tip">开启后无需填写起止时间</text>
</view>
<u-switch
v-model="form.allDay"
active-color="#2563eb"
size="22"
:disabled="isCompleted"
/>
</view>
<view v-if="!form.allDay" class="field">
<text class="field-label">开始时间 <text class="required">*</text></text>
<picker mode="time" :value="form.startTime" @change="onStartTimeChange" :disabled="isCompleted">
<view class="picker-value">
<text>{{ form.startTime || '选择开始时间' }}</text>
<FaIcon name="clock" color="#909399" :size="16" />
</view>
</picker>
</view>
<view v-if="!form.allDay" class="field">
<text class="field-label">结束时间</text>
<picker mode="time" :value="form.endTime" @change="onEndTimeChange" :disabled="isCompleted">
<view class="picker-value">
<text>{{ form.endTime || '选填,不填则只记开始时间' }}</text>
<FaIcon name="clock" color="#909399" :size="16" />
</view>
</picker>
</view>
<view class="field picker-field">
<text class="field-label">优先级</text>
<picker :range="priorityLabels" :value="priorityIndex" @change="onPriorityChange" :disabled="isCompleted">
<view class="picker-value">
<text>{{ priorityLabels[priorityIndex] }}</text>
<FaIcon name="flag" color="#909399" :size="16" />
</view>
</picker>
</view>
<view class="field">
<text class="field-label">内容</text>
<u-textarea
v-model="form.content"
placeholder="补充日程详细内容(选填)"
:maxlength="1000"
count
height="120"
border="none"
:disabled="isCompleted"
/>
</view>
</view>
<view v-if="!isCompleted" class="footer">
<u-button
type="primary"
color="#2563eb"
shape="circle"
:loading="saving"
loading-text="保存中..."
text="保存"
@click="onSave"
/>
</view>
</view>
</template>
<script setup>
import { ref, reactive, computed } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import {
getOaSchedule,
createOaSchedule,
updateOaSchedule,
OA_SCHEDULE_PRIORITY_OPTIONS
} from '@/api/oaSchedule.js'
import { formatDate } from '@/utils/date.js'
const scheduleId = ref('')
const saving = ref(false)
const isCompleted = ref(false)
const priorityOptions = OA_SCHEDULE_PRIORITY_OPTIONS
const priorityLabels = priorityOptions.map(item => item.label)
const form = reactive({
title: '',
content: '',
date: '',
allDay: true,
startTime: '09:00',
endTime: '',
priority: 0
})
const priorityIndex = computed(() => {
const index = priorityOptions.findIndex(item => item.value === Number(form.priority))
return index >= 0 ? index : 0
})
onLoad(async (query) => {
form.date = formatDate(new Date())
if (query?.id) {
scheduleId.value = query.id
uni.setNavigationBarTitle({ title: '编辑日程' })
await loadSchedule(query.id)
} else {
uni.setNavigationBarTitle({ title: '新建日程' })
}
})
async function loadSchedule(id) {
try {
const item = await getOaSchedule(id)
if (!item) {
uni.showToast({ title: '日程不存在', icon: 'none' })
setTimeout(() => uni.navigateBack(), 800)
return
}
form.title = item.title || ''
form.content = item.content || ''
form.date = item.schedule_date || formatDate(new Date())
form.allDay = !!item.allDay
form.startTime = item.start_time || '09:00'
form.endTime = item.end_time || ''
form.priority = Number(item.priority) || 0
isCompleted.value = !!item.completed
} catch (e) {
uni.showToast({ title: '加载失败', icon: 'none' })
}
}
function onDateChange(e) {
form.date = e.detail.value
}
function onStartTimeChange(e) {
form.startTime = e.detail.value
}
function onEndTimeChange(e) {
form.endTime = e.detail.value
}
function onPriorityChange(e) {
const index = Number(e.detail.value)
form.priority = priorityOptions[index].value
}
async function onSave() {
if (saving.value) return
if (!form.title.trim()) {
uni.showToast({ title: '请输入日程标题', icon: 'none' })
return
}
if (!form.date) {
uni.showToast({ title: '请选择日期', icon: 'none' })
return
}
if (!form.allDay) {
if (!form.startTime) {
uni.showToast({ title: '请选择开始时间', icon: 'none' })
return
}
if (form.endTime && form.endTime <= form.startTime) {
uni.showToast({ title: '结束时间需晚于开始时间', icon: 'none' })
return
}
}
await saveData()
}
async function saveData() {
saving.value = true
const payload = {
title: form.title.trim(),
content: form.content,
scheduleDate: form.date,
allDay: form.allDay,
startTime: form.startTime,
endTime: form.endTime,
priority: form.priority
}
try {
if (scheduleId.value) {
await updateOaSchedule(scheduleId.value, payload)
} else {
await createOaSchedule(payload)
}
uni.showToast({ title: '保存成功', icon: 'success' })
setTimeout(() => uni.navigateBack(), 400)
} catch (e) {
// request 封装已弹出服务端错误提示
} finally {
saving.value = false
}
}
</script>
<style lang="scss" scoped>
@import '@/src/styles/page-common.scss';
.page {
min-height: 100vh;
background: $color-bg-page;
padding: 24rpx $page-padding-x;
padding-bottom: calc(180rpx + env(safe-area-inset-bottom));
}
.completed-notice {
display: flex;
align-items: center;
justify-content: center;
gap: 12rpx;
padding: 20rpx 0;
margin-bottom: 16rpx;
font-size: 28rpx;
color: #67c23a;
background: #f0f9eb;
border-radius: $radius-md;
}
.is-disabled {
opacity: 0.7;
pointer-events: none;
}
.form-card {
@include card;
padding: 8rpx 0;
}
.field {
padding: 24rpx 28rpx;
& + & {
border-top: 1rpx solid $color-divider;
}
}
.field-label {
display: block;
font-size: 24rpx;
color: $color-text-muted;
margin-bottom: 12rpx;
}
.required {
color: #f56c6c;
}
.switch-field {
display: flex;
align-items: center;
justify-content: space-between;
.switch-info {
flex: 1;
}
.field-label {
margin-bottom: 4rpx;
}
.form-tip {
margin-top: 0;
}
}
.picker-value {
display: flex;
align-items: center;
justify-content: space-between;
height: 72rpx;
padding: 0 20rpx;
background: $color-bg-page;
border-radius: $radius-md;
font-size: 28rpx;
color: $color-text;
}
.form-tip {
display: block;
font-size: 22rpx;
color: $color-text-muted;
margin-top: 8rpx;
}
.footer {
position: fixed;
left: 0;
right: 0;
bottom: 0;
display: flex;
gap: 20rpx;
padding: 20rpx $page-padding-x;
padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
background: $color-card;
border-top: 1rpx solid $color-border;
box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.04);
}
</style>