|
|
@@ -32,7 +32,7 @@
|
|
|
}}项</span>
|
|
|
</div>
|
|
|
|
|
|
- <!-- 日历事件 -->
|
|
|
+ <!-- 日历所属日期下的待办事项 -->
|
|
|
<div class="cal_cell_events" v-if="cell.inCurrentMonth">
|
|
|
<div class="cal_event_item"
|
|
|
v-for="(ev, ei) in cell.events" :key="ev.id"
|
|
|
@@ -40,7 +40,10 @@
|
|
|
>
|
|
|
<div class="event_main" :class="{ is_selected: selectedEventId === ev.id }">
|
|
|
<span class="cal_event_dot"></span>
|
|
|
- <span class="cal_event_text">{{ ev.title }}</span>
|
|
|
+ <div style="display: flex;flex-direction: column;">
|
|
|
+ <span class="cal_event_text">{{ ev.title }}</span>
|
|
|
+ <span class="cal_event_text">{{ ev.desc }}</span>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
@@ -51,18 +54,25 @@
|
|
|
class="event_popup"
|
|
|
:class="cell.weekday === 5 || cell.weekday === 6 ? 'popup_left' : 'popup_right'"
|
|
|
:style="{ top: `${10 + hoverState.eventIndex * 24}px` }">
|
|
|
- <div class="event_popup_title">{{ hoverState.event.title }}</div>
|
|
|
+ <div class="event_popup_title">{{ hoverState.event.isCustomToDo ? hoverState.event.desc : hoverState.event.customerName}}</div>
|
|
|
+ <div class="event_popup_middle_title" v-if="!(hoverState.event.isCustomToDo)">{{ hoverState.event.productName }}</div>
|
|
|
+ <div class="event_popup_desc" v-if="!(hoverState.event.isCustomToDo)">{{ hoverState.event.desc }}</div>
|
|
|
+
|
|
|
<div class="event_popup_actions">
|
|
|
- <span class="event_popup_date">{{ formatPopupDate(cell.date) }}</span>
|
|
|
+ <span class="event_popup_date">{{ formatPopupDate(cell.date) }} {{ hoverState.event.title.split(' ')[0] }}</span>
|
|
|
<span class="event_actions_right" v-if="hasSchoolManager">
|
|
|
- <span class="event_btn event_edit" @click.stop="editEvent(hoverState.event)">编辑</span>
|
|
|
- <span class="event_btn event_delete"
|
|
|
- @click.stop="deleteEvent(hoverState.event)">删除</span>
|
|
|
+ <template v-if="hoverState.event.isCustomToDo">
|
|
|
+ <span class="event_btn event_edit" @click.stop="editEvent(hoverState.event)">编辑</span>
|
|
|
+ <span class="event_btn event_delete" @click.stop="deleteEvent(hoverState.event)">删除</span>
|
|
|
+ </template>
|
|
|
+ <template v-else>
|
|
|
+ <span class="event_btn event_edit" @click.stop="detailEvent(hoverState.event)">详情</span>
|
|
|
+ </template>
|
|
|
</span>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
- <!-- 创建事件 日期格子悬浮窗:展示当天所有日程列表 + 新增日程按钮 -->
|
|
|
+ <!-- 创建日历事件弹窗 日期格子悬浮窗:展示当天所有日程列表 + 新增日程按钮 -->
|
|
|
<div v-if="cellHoverState.dateKey === formatDate(cell.date) && !hoverState.event"
|
|
|
class="cell_popup"
|
|
|
:class="[cell.weekday === 5 || cell.weekday === 6 ? 'popup_left' : 'popup_right', cell.isLastRow ? 'popup_top' : '']">
|
|
|
@@ -73,7 +83,10 @@
|
|
|
<div class="cell_popup_events">
|
|
|
<div class="cell_popup_event" v-for="(ev, ei) in cell.events" :key="ev.id">
|
|
|
<span class="cell_popup_dot"></span>
|
|
|
- <span class="cell_popup_text">{{ ev.title }}</span>
|
|
|
+ <div style="display: flex;flex-direction: column;">
|
|
|
+ <span class="cell_popup_title">{{ ev.title }}</span>
|
|
|
+ <span class="cell_popup_text">{{ ev.desc }}</span>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
<div v-if="cell.events.length === 0" class="cell_popup_empty">暂无日程安排</div>
|
|
|
</div>
|
|
|
@@ -90,16 +103,29 @@
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
import CalendarDateSelectHeader from './CalendarDateSelectHeader.vue'
|
|
|
-import { ref, computed, watch, onMounted, onUnmounted, reactive, nextTick } from 'vue'
|
|
|
+import { ref, computed, onMounted, onUnmounted} from 'vue'
|
|
|
import addIcon from '@/assets/icon/add.svg'
|
|
|
-import { ElMessage, ElMessageBox } from 'element-plus'
|
|
|
|
|
|
-const emit = defineEmits(['back','addOption'])
|
|
|
+interface ScheduleEventsItm {
|
|
|
+ [dateKey:string]:{
|
|
|
+ id:string,
|
|
|
+ title:string,
|
|
|
+ desc:string,
|
|
|
+ isCustomToDo:Boolean, //是否是自定义待办
|
|
|
+ productName?:string,
|
|
|
+ customerName?:string,
|
|
|
+ }[]
|
|
|
+}
|
|
|
+
|
|
|
+const emit = defineEmits(['back','addOrUpdateOption','deleteToDo','detailToDo'])
|
|
|
|
|
|
const props = defineProps({
|
|
|
showCalendarSelector:{
|
|
|
type:Boolean,
|
|
|
default:true
|
|
|
+ },
|
|
|
+ scheduleEvents:{
|
|
|
+ type:Object as ()=>ScheduleEventsItm
|
|
|
}
|
|
|
})
|
|
|
|
|
|
@@ -168,23 +194,11 @@ const handleEventClick = (date: Date, ev: { id: string; title: string }, index:
|
|
|
|
|
|
// 打开创建任务弹窗
|
|
|
const openAddSchedule = (date: Date) => {
|
|
|
- emit('addOption',date)
|
|
|
- const dateStr = formatDate(date)
|
|
|
+ emit('addOrUpdateOption')
|
|
|
}
|
|
|
|
|
|
-
|
|
|
const weekdays = ['周日', '周一', '周二', '周三', '周四', '周五', '周六']
|
|
|
|
|
|
-// 日程数据:以 YYYY-MM-DD 为 key
|
|
|
-// const scheduleEvents = ref<Record<string, { id: string; title: string }[]>>({})
|
|
|
-const scheduleEvents = ref({
|
|
|
- '2026-09-01':[
|
|
|
- {
|
|
|
- id: 'string', title: 'string'
|
|
|
- }
|
|
|
- ]
|
|
|
-})
|
|
|
-
|
|
|
const calendarRows = computed(() => {
|
|
|
const y = currentYear.value
|
|
|
const m = currentMonth.value - 1
|
|
|
@@ -202,30 +216,6 @@ const cellHeight = computed(() => {
|
|
|
})
|
|
|
|
|
|
|
|
|
-// 获取当前月所有日程
|
|
|
-const fetchMonthSchedule = async () => {
|
|
|
- const y = currentYear.value
|
|
|
- const m = currentMonth.value
|
|
|
- const startDate = `${y}-${pad(m)}-01`
|
|
|
- const lastDay = new Date(y, m, 0).getDate()
|
|
|
- const endDate = `${y}-${pad(m)}-${pad(lastDay)}`
|
|
|
- try {
|
|
|
- /*
|
|
|
- const res: any = await getTimePeriodSchedule({ startDate, endDate })
|
|
|
- if (res.code === 200 && res.data) {
|
|
|
- Object.keys(res.data).forEach(dateKey => {
|
|
|
- const list = res.data[dateKey] || []
|
|
|
- scheduleEvents.value[dateKey] = list.map((item: any) => ({
|
|
|
- id: String(item.id),
|
|
|
- title: item.content || ''
|
|
|
- }))
|
|
|
- })
|
|
|
- }
|
|
|
- */
|
|
|
- } catch (err) {
|
|
|
- console.error(err)
|
|
|
- }
|
|
|
-}
|
|
|
|
|
|
const handleGlobalClick = (event: MouseEvent) => {
|
|
|
const target = event.target as HTMLElement
|
|
|
@@ -235,7 +225,6 @@ const handleGlobalClick = (event: MouseEvent) => {
|
|
|
}
|
|
|
|
|
|
onMounted(() => {
|
|
|
- fetchMonthSchedule()
|
|
|
document.addEventListener('click', handleGlobalClick)
|
|
|
})
|
|
|
|
|
|
@@ -246,10 +235,6 @@ onUnmounted(() => {
|
|
|
// 当用户通过顶部下拉切换年月时,仅切换视图,不改变选中日期;
|
|
|
// 选中日期只有在点击日历格子时才会改变,保证"选中态"针对具体的年月日而非日号
|
|
|
|
|
|
-// 监听年月变化,重新获取日程数据
|
|
|
-watch([currentYear, currentMonth], () => {
|
|
|
- fetchMonthSchedule()
|
|
|
-})
|
|
|
|
|
|
// 生成当月日历格子(5 行 × 7 列 = 35 格,避免出现第 6 行)
|
|
|
const calendarCells = computed(() => {
|
|
|
@@ -269,7 +254,7 @@ const calendarCells = computed(() => {
|
|
|
const d = new Date(gridStart)
|
|
|
d.setDate(gridStart.getDate() + i)
|
|
|
const key = formatDate(d)
|
|
|
- const events = scheduleEvents.value[key] || []
|
|
|
+ const events = props.scheduleEvents?.[key] || []
|
|
|
cells.push({
|
|
|
num: d.getDate(),
|
|
|
weekday: d.getDay(),
|
|
|
@@ -292,43 +277,18 @@ const selectDate = (d: Date) => {
|
|
|
|
|
|
// 编辑事件
|
|
|
const editEvent = (ev: { id: string; title: string }) => {
|
|
|
- emit('addOption')
|
|
|
-
|
|
|
+ emit('addOrUpdateOption',ev)
|
|
|
}
|
|
|
|
|
|
// 删除事件
|
|
|
const deleteEvent = async (ev: { id: string; title: string }) => {
|
|
|
- try {
|
|
|
- await ElMessageBox.confirm(
|
|
|
- `是否删除:${ev.title}`,
|
|
|
- '提示',
|
|
|
- {
|
|
|
- confirmButtonText: '确定',
|
|
|
- cancelButtonText: '取消',
|
|
|
- type: 'warning'
|
|
|
- }
|
|
|
- )
|
|
|
- /*
|
|
|
- const res: any = await delSchedule(ev.id)
|
|
|
- if (res.code === 200) {
|
|
|
- ElMessage.success('日程删除成功')
|
|
|
- const key = hoverState.value.dateKey
|
|
|
- if (!scheduleEvents.value[key]) return
|
|
|
- const idx = scheduleEvents.value[key].findIndex(e => e.id === ev.id)
|
|
|
- if (idx >= 0) {
|
|
|
- scheduleEvents.value[key].splice(idx, 1)
|
|
|
- if (scheduleEvents.value[key].length === 0) delete scheduleEvents.value[key]
|
|
|
- }
|
|
|
- }
|
|
|
- */
|
|
|
- } catch (err) {
|
|
|
- if (err !== 'cancel') {
|
|
|
- console.error(err)
|
|
|
- }
|
|
|
- }
|
|
|
+ emit('deleteToDo',ev)
|
|
|
}
|
|
|
|
|
|
-
|
|
|
+// 跟进待办的 查看详情时间
|
|
|
+const detailEvent = async (ev: { id: string; title: string }) => {
|
|
|
+ emit('detailToDo',ev)
|
|
|
+}
|
|
|
|
|
|
</script>
|
|
|
|
|
|
@@ -486,14 +446,10 @@ const deleteEvent = async (ev: { id: string; title: string }) => {
|
|
|
overflow: visible;
|
|
|
z-index: 2;
|
|
|
max-width: 200px;
|
|
|
- // &:hover .event_main,
|
|
|
- // &.is-active .event_main {
|
|
|
- // background: #000;
|
|
|
- // }
|
|
|
|
|
|
.event_main {
|
|
|
display: flex;
|
|
|
- align-items: center;
|
|
|
+ align-items: flex-start;
|
|
|
gap: 6px;
|
|
|
width: 100%;
|
|
|
padding: 3px 6px;
|
|
|
@@ -513,6 +469,7 @@ const deleteEvent = async (ev: { id: string; title: string }) => {
|
|
|
border-radius: 50%;
|
|
|
background: #2E64FA;
|
|
|
flex-shrink: 0;
|
|
|
+ margin:6px 0;
|
|
|
}
|
|
|
.cal_event_text {
|
|
|
white-space: nowrap;
|
|
|
@@ -537,12 +494,17 @@ const deleteEvent = async (ev: { id: string; title: string }) => {
|
|
|
border: 1px solid #EBEEF5;
|
|
|
border-radius: 8px;
|
|
|
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.14), 0 2px 4px rgba(0, 0, 0, 0.06);
|
|
|
- padding: 6px 14px 8px 14px;
|
|
|
+ padding: 8px 0 8px;
|
|
|
z-index: 200;
|
|
|
opacity: 1;
|
|
|
visibility: visible;
|
|
|
pointer-events: auto;
|
|
|
- display: block;
|
|
|
+
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap:4px;
|
|
|
+
|
|
|
+
|
|
|
|
|
|
&.popup_right {
|
|
|
left: calc(100% + 8px);
|
|
|
@@ -584,14 +546,29 @@ const deleteEvent = async (ev: { id: string; title: string }) => {
|
|
|
bottom: 20px;
|
|
|
}
|
|
|
}
|
|
|
+ .event_popup_title,
|
|
|
+ .event_popup_middle_title,
|
|
|
+ .event_popup_desc {
|
|
|
+ padding:0 8px;
|
|
|
+
|
|
|
+ }
|
|
|
|
|
|
.event_popup_title {
|
|
|
font-size: 14px;
|
|
|
- font-weight: 500;
|
|
|
color: #333;
|
|
|
- line-height: 1.5;
|
|
|
- padding: 6px 0 4px 0;
|
|
|
word-break: break-all;
|
|
|
+ font-weight: 600;
|
|
|
+ line-height: 22px;
|
|
|
+ }
|
|
|
+ .event_popup_middle_title{
|
|
|
+ line-height: 17px;
|
|
|
+ font-size: 12px;
|
|
|
+ color: #333333;
|
|
|
+ }
|
|
|
+ .event_popup_desc{
|
|
|
+ line-height: 17px;
|
|
|
+ font-size: 12px;
|
|
|
+ color: #999999;
|
|
|
}
|
|
|
|
|
|
.event_popup_actions {
|
|
|
@@ -599,7 +576,8 @@ const deleteEvent = async (ev: { id: string; title: string }) => {
|
|
|
align-items: center;
|
|
|
justify-content: space-between;
|
|
|
border-top: 1px solid #EBEEF5;
|
|
|
- padding: 6px 0 2px 0;
|
|
|
+ padding: 8px 8px 0;
|
|
|
+ margin-top: 4px;
|
|
|
}
|
|
|
|
|
|
.event_popup_date {
|
|
|
@@ -616,7 +594,7 @@ const deleteEvent = async (ev: { id: string; title: string }) => {
|
|
|
padding: 2px 6px;
|
|
|
border-radius: 3px;
|
|
|
cursor: pointer;
|
|
|
- font-size: 13px;
|
|
|
+ font-size: 12px;
|
|
|
transition: background-color 0.15s;
|
|
|
|
|
|
&:hover {
|
|
|
@@ -704,17 +682,19 @@ const deleteEvent = async (ev: { id: string; title: string }) => {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: space-between;
|
|
|
- padding: 8px;
|
|
|
+ padding: 8px 8px 4px;
|
|
|
+
|
|
|
+ line-height: 20px;
|
|
|
+
|
|
|
.cell_popup_date {
|
|
|
font-size: 14px;
|
|
|
- font-weight: 500;
|
|
|
color: #000;
|
|
|
+ font-weight: 600;
|
|
|
}
|
|
|
-
|
|
|
.cell_popup_count {
|
|
|
- font-size: 12px;
|
|
|
- color: #999;
|
|
|
- line-height: 1.5;
|
|
|
+ font-weight: 400;
|
|
|
+ font-size: 10px;
|
|
|
+ color: #666666;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -736,8 +716,7 @@ const deleteEvent = async (ev: { id: string; title: string }) => {
|
|
|
display: flex;
|
|
|
align-items: flex-start;
|
|
|
gap: 8px;
|
|
|
- font-size: 14px;
|
|
|
- color: #666666;
|
|
|
+ font-size: 12px;
|
|
|
line-height: 1.5;
|
|
|
|
|
|
.cell_popup_dot {
|
|
|
@@ -746,10 +725,16 @@ const deleteEvent = async (ev: { id: string; title: string }) => {
|
|
|
border-radius: 50%;
|
|
|
background: #2E64FA;
|
|
|
flex-shrink: 0;
|
|
|
- margin-top: 6px;
|
|
|
+ margin:9px 0;
|
|
|
}
|
|
|
|
|
|
+ .cell_popup_title {
|
|
|
+ color:#333;
|
|
|
+ font-weight: 600;
|
|
|
+ word-break: break-all;
|
|
|
+ }
|
|
|
.cell_popup_text {
|
|
|
+ color: #999;
|
|
|
word-break: break-all;
|
|
|
}
|
|
|
}
|