|  | @@ -2,27 +2,6 @@
 | 
	
		
			
				|  |  |    <div class="mod-demo__schedule">
 | 
	
		
			
				|  |  |      <div class="form-container">
 | 
	
		
			
				|  |  |      <el-form :inline="true" :model="state.dataForm" @keyup.enter="state.getDataList()">
 | 
	
		
			
				|  |  | -      <el-form-item>
 | 
	
		
			
				|  |  | -        <el-input v-model="state.dataForm.schedule_name" placeholder="排班表名称" clearable></el-input>
 | 
	
		
			
				|  |  | -      </el-form-item>
 | 
	
		
			
				|  |  | -      <el-form-item >
 | 
	
		
			
				|  |  | -        <el-date-picker
 | 
	
		
			
				|  |  | -          v-model="state.dataForm.period_start"
 | 
	
		
			
				|  |  | -          type="date"        
 | 
	
		
			
				|  |  | -          placeholder="开始日期"
 | 
	
		
			
				|  |  | -          value-format="YYYY-MM-DD" 
 | 
	
		
			
				|  |  | -          clearable
 | 
	
		
			
				|  |  | -        ></el-date-picker>
 | 
	
		
			
				|  |  | -      </el-form-item>
 | 
	
		
			
				|  |  | -      <el-form-item >
 | 
	
		
			
				|  |  | -        <el-date-picker
 | 
	
		
			
				|  |  | -          v-model="state.dataForm.period_end"
 | 
	
		
			
				|  |  | -          type="date"        
 | 
	
		
			
				|  |  | -          placeholder="结束日期"
 | 
	
		
			
				|  |  | -          value-format="YYYY-MM-DD" 
 | 
	
		
			
				|  |  | -          clearable
 | 
	
		
			
				|  |  | -        ></el-date-picker>
 | 
	
		
			
				|  |  | -      </el-form-item>
 | 
	
		
			
				|  |  |        <el-form-item>
 | 
	
		
			
				|  |  |          <el-select v-model="state.dataForm.status" placeholder="排班确认状态"  clearable>
 | 
	
		
			
				|  |  |            <el-option :label="item.dictLabel" :value="item.dictValue" v-for="item in state.getDictByKey('scheduleStatus')"></el-option>
 | 
	
	
		
			
				|  | @@ -32,8 +11,7 @@
 | 
	
		
			
				|  |  |          <el-button @click="state.getDataList()">查询</el-button>
 | 
	
		
			
				|  |  |        </el-form-item>
 | 
	
		
			
				|  |  |        <el-form-item>
 | 
	
		
			
				|  |  | -      <el-form-item>
 | 
	
		
			
				|  |  | -        <el-button v-if="state.hasPermission('emergency:schedule:save')" type="primary" @click="addOrUpdateHandle()">新增</el-button>
 | 
	
		
			
				|  |  | +        <el-button v-if="state.hasPermission('emergency:schedule:save')" type="primary" @click="addHandle()">新增</el-button>
 | 
	
		
			
				|  |  |        </el-form-item>
 | 
	
		
			
				|  |  |        <el-form-item>
 | 
	
		
			
				|  |  |          <el-button v-if="state.hasPermission('emergency:schedule:delete')" type="danger" @click="state.deleteHandle()">删除</el-button>
 | 
	
	
		
			
				|  | @@ -44,40 +22,33 @@
 | 
	
		
			
				|  |  |        <el-form-item>
 | 
	
		
			
				|  |  |          <el-button v-if="state.hasPermission('emergency:inspection:export')" type="info" @click="state.exportHandle()">导出</el-button>
 | 
	
		
			
				|  |  |        </el-form-item>
 | 
	
		
			
				|  |  | -    </el-form-item>
 | 
	
		
			
				|  |  |      </el-form>
 | 
	
		
			
				|  |  |    </div>
 | 
	
		
			
				|  |  | -    <el-table v-loading="state.dataListLoading" :data="state.dataList" border @selection-change="state.dataListSelectionChangeHandle" style="width: 100%">
 | 
	
		
			
				|  |  | -      <el-table-column type="selection" header-align="center" align="center" width="50"></el-table-column>
 | 
	
		
			
				|  |  | -              <!-- <el-table-column prop="id" label="排班ID" header-align="center" align="center"></el-table-column> -->
 | 
	
		
			
				|  |  | -              <el-table-column prop="id" label="序号" header-align="center" align="center" width="70">
 | 
	
		
			
				|  |  | -                <template v-slot="scope">{{ scope.$index+1 }}</template>
 | 
	
		
			
				|  |  | -              </el-table-column>
 | 
	
		
			
				|  |  | -              <el-table-column prop="scheduleName" label="排班表名称" header-align="center" align="center"></el-table-column>
 | 
	
		
			
				|  |  | -              <el-table-column prop="periodStart" label="排班周期开始日期" header-align="center" align="center"></el-table-column>
 | 
	
		
			
				|  |  | -              <el-table-column prop="periodEnd" label="排班周期结束日期" header-align="center" align="center"></el-table-column>
 | 
	
		
			
				|  |  | -              <!-- <el-table-column prop="filePath" label="用户上传文件路径" header-align="center" align="center"></el-table-column> -->
 | 
	
		
			
				|  |  | -              <el-table-column prop="status" label="是否确认" header-align="center" align="center">
 | 
	
		
			
				|  |  | -                <template v-slot="scope">
 | 
	
		
			
				|  |  | -                  {{ state.getDictLabel("scheduleStatus", scope.row.status) }}
 | 
	
		
			
				|  |  | -                </template>
 | 
	
		
			
				|  |  | -              </el-table-column>
 | 
	
		
			
				|  |  | -              <el-table-column prop="creatorName" label="创建人" header-align="center" align="center"></el-table-column>
 | 
	
		
			
				|  |  | -              <el-table-column prop="createDate" label="创建时间" header-align="center" align="center"></el-table-column>
 | 
	
		
			
				|  |  | -              <el-table-column prop="updaterName" label="更新人" header-align="center" align="center"></el-table-column>
 | 
	
		
			
				|  |  | -              <el-table-column prop="updateDate" label="更新时间" header-align="center" align="center"></el-table-column>
 | 
	
		
			
				|  |  | -              <el-table-column prop="remark" label="备注" header-align="center" align="center"></el-table-column>
 | 
	
		
			
				|  |  | -            <el-table-column label="操作" fixed="right" header-align="center" align="center" width="180">
 | 
	
		
			
				|  |  | -        <template v-slot="scope">
 | 
	
		
			
				|  |  | -          <el-button v-if="state.hasPermission('emergency:schedule:update')" type="primary" link @click="addOrUpdateHandle(scope.row.id)">修改</el-button>
 | 
	
		
			
				|  |  | -          <el-button v-if="state.hasPermission('emergency:schedule:delete')" type="primary" link @click="state.deleteHandle(scope.row.id)">删除</el-button>
 | 
	
		
			
				|  |  | -           <el-button v-if="state.hasPermission('emergency:schedule:review')" type="primary" link @click="reviewHandle(scope.row.id)">审阅</el-button>
 | 
	
		
			
				|  |  | -        </template>
 | 
	
		
			
				|  |  | -      </el-table-column>
 | 
	
		
			
				|  |  | -    </el-table>
 | 
	
		
			
				|  |  | +    <!-- <el-calendar v-model="calendarValue" /> -->
 | 
	
		
			
				|  |  | +    <el-calendar v-model="calendarValue">
 | 
	
		
			
				|  |  | +      <template #date-cell="{ data }">
 | 
	
		
			
				|  |  | +        <div
 | 
	
		
			
				|  |  | +          class="calendar-cell"
 | 
	
		
			
				|  |  | +          @dblclick="handleDayDblClick(data.day)"
 | 
	
		
			
				|  |  | +        >
 | 
	
		
			
				|  |  | +        <el-checkbox
 | 
	
		
			
				|  |  | +          :label="formatMonthDay(data.day)"
 | 
	
		
			
				|  |  | +          :value="data.day"
 | 
	
		
			
				|  |  | +          v-model="selectedDates"
 | 
	
		
			
				|  |  | +          @click.stop 
 | 
	
		
			
				|  |  | +        />
 | 
	
		
			
				|  |  | +        <div class="employee-names">
 | 
	
		
			
				|  |  | +          <div v-for="(name, index) in (scheduleMap[data.day]?.names || [])" :key="index" class="employee-name" @dblclick.stop>
 | 
	
		
			
				|  |  | +            {{ name }}
 | 
	
		
			
				|  |  | +          </div>
 | 
	
		
			
				|  |  | +        </div>
 | 
	
		
			
				|  |  | +        </div>
 | 
	
		
			
				|  |  | +      </template>
 | 
	
		
			
				|  |  | +    </el-calendar>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      <el-pagination :current-page="state.page" :page-sizes="[10, 20, 50, 100]" :page-size="state.limit" :total="state.total" layout="total, sizes, prev, pager, next, jumper" @size-change="state.pageSizeChangeHandle" @current-change="state.pageCurrentChangeHandle"> </el-pagination>
 | 
	
		
			
				|  |  |      <!-- 弹窗, 新增 / 修改 -->
 | 
	
		
			
				|  |  | -    <add-or-update ref="addOrUpdateRef" @refreshDataList="state.getDataList">确定</add-or-update>
 | 
	
		
			
				|  |  | +    <add-or-update ref="addOrUpdateRef" @refreshDataList="refreshAfterAdd">确定</add-or-update>
 | 
	
		
			
				|  |  |    </div>
 | 
	
		
			
				|  |  |  </template>
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -99,9 +70,85 @@ const view = reactive({
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  const state = reactive({ ...useView(view), ...toRefs(view) });
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +//日历
 | 
	
		
			
				|  |  | +const calendarValue = ref(new Date())
 | 
	
		
			
				|  |  | +const selectedDates = ref<string[]>([]);
 | 
	
		
			
				|  |  | +const formatMonthDay = (fullDate: string): string => {
 | 
	
		
			
				|  |  | +  const parts = fullDate.split("-");
 | 
	
		
			
				|  |  | +  return `${parts[1]}-${parts[2]}`;
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +const employeeOptions = ref<{ id: string; name: string }[]>([]);
 | 
	
		
			
				|  |  | +// id->姓名
 | 
	
		
			
				|  |  | +const employeeIdMap = ref<Record<string, string>>({});
 | 
	
		
			
				|  |  | +// 日期->员工姓名数组
 | 
	
		
			
				|  |  | +const scheduleMap = ref<Record<string, { id: number; names: string[] }>>({});
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// 构建id->姓名映射
 | 
	
		
			
				|  |  | +const fetchEmployeeOptions = async () => {
 | 
	
		
			
				|  |  | +  const res = await baseService.get("/emergency/employee/page");
 | 
	
		
			
				|  |  | +  employeeOptions.value = res.data.list || [];
 | 
	
		
			
				|  |  | +  
 | 
	
		
			
				|  |  | +  employeeIdMap.value = {};
 | 
	
		
			
				|  |  | +  for (const item of employeeOptions.value) {
 | 
	
		
			
				|  |  | +    employeeIdMap.value[item.id] = item.name;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  | +const buildScheduleMap = (list: any[]) => {
 | 
	
		
			
				|  |  | +  scheduleMap.value = {};
 | 
	
		
			
				|  |  | +  for (const item of list) {
 | 
	
		
			
				|  |  | +    const day = item.scheduleDate; 
 | 
	
		
			
				|  |  | +    //保存的ids
 | 
	
		
			
				|  |  | +    const ids = item.employeeIds || [];
 | 
	
		
			
				|  |  | +    const names = ids.map((id: string) => employeeIdMap.value[id] || `员工姓名未知,id为${id}`);
 | 
	
		
			
				|  |  | +    scheduleMap.value[day] = { id: item.id, names};
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  | +import { onMounted } from 'vue'
 | 
	
		
			
				|  |  | +onMounted(async () => {
 | 
	
		
			
				|  |  | +  await fetchEmployeeOptions();
 | 
	
		
			
				|  |  | +  await state.getDataList();
 | 
	
		
			
				|  |  | +  buildScheduleMap(state.dataList || []);
 | 
	
		
			
				|  |  | +});
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// 新增按钮
 | 
	
		
			
				|  |  | +const addHandle = () => {
 | 
	
		
			
				|  |  | +  if (!selectedDates.value || selectedDates.value.length === 0) {
 | 
	
		
			
				|  |  | +    ElMessage({
 | 
	
		
			
				|  |  | +      message: '请先选择一个或多个日期再新增排班',
 | 
	
		
			
				|  |  | +      type: 'warning',
 | 
	
		
			
				|  |  | +      duration: 500,
 | 
	
		
			
				|  |  | +    });
 | 
	
		
			
				|  |  | +    return;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  // 批量添加
 | 
	
		
			
				|  |  | +  addOrUpdateHandle(undefined, undefined, selectedDates.value);
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  | +//新增后清除已选中
 | 
	
		
			
				|  |  | +const refreshAfterAdd = async () => {
 | 
	
		
			
				|  |  | +  await fetchEmployeeOptions();
 | 
	
		
			
				|  |  | +  await state.getDataList(); 
 | 
	
		
			
				|  |  | +  buildScheduleMap(state.dataList || []);       
 | 
	
		
			
				|  |  | +  selectedDates.value = [];  
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  const addOrUpdateRef = ref();
 | 
	
		
			
				|  |  | -const addOrUpdateHandle = (id?: number) => {
 | 
	
		
			
				|  |  | -  addOrUpdateRef.value.init(id);
 | 
	
		
			
				|  |  | +const addOrUpdateHandle = (id?: number, date?: string, dates?: string[]) => {
 | 
	
		
			
				|  |  | +  addOrUpdateRef.value.init(id, date, dates);
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +const handleDayDblClick = (day: string) => {
 | 
	
		
			
				|  |  | +  const schedule = scheduleMap.value[day];
 | 
	
		
			
				|  |  | +  if (schedule && schedule.id) {
 | 
	
		
			
				|  |  | +    // 已有排班记录,修改
 | 
	
		
			
				|  |  | +    addOrUpdateHandle(schedule.id);
 | 
	
		
			
				|  |  | +  } else {
 | 
	
		
			
				|  |  | +    // 不存在,调用“新增”
 | 
	
		
			
				|  |  | +    addOrUpdateHandle(undefined, day);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  |  };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  // 审阅
 | 
	
	
		
			
				|  | @@ -138,3 +185,29 @@ const reviewHandle = (id?: string) => {
 | 
	
		
			
				|  |  |      });
 | 
	
		
			
				|  |  |  };
 | 
	
		
			
				|  |  |  </script>
 | 
	
		
			
				|  |  | +<style>
 | 
	
		
			
				|  |  | +.calendar-cell {
 | 
	
		
			
				|  |  | +  width: 100%;
 | 
	
		
			
				|  |  | +  height: 100%;
 | 
	
		
			
				|  |  | +  display: flex;
 | 
	
		
			
				|  |  | +  flex-direction: column;
 | 
	
		
			
				|  |  | +  align-items: center; 
 | 
	
		
			
				|  |  | +  justify-content: flex-start; 
 | 
	
		
			
				|  |  | +  padding-top: 6px;    
 | 
	
		
			
				|  |  | +  box-sizing: border-box;
 | 
	
		
			
				|  |  | +  padding: 4px;
 | 
	
		
			
				|  |  | +  cursor: pointer;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +::v-deep(.el-calendar-day) {
 | 
	
		
			
				|  |  | +  display: flex !important;
 | 
	
		
			
				|  |  | +  flex-direction: column;
 | 
	
		
			
				|  |  | +  align-items: flex-start;
 | 
	
		
			
				|  |  | +  justify-content: flex-start;
 | 
	
		
			
				|  |  | +  padding: 4px;
 | 
	
		
			
				|  |  | +  box-sizing: border-box;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +</style>
 |