| ¶Ô±ÈÐÂÎļþ | 
 |  |  | 
 |  |  | <template> | 
 |  |  |   <div class="app-container"> | 
 |  |  |     <el-tabs v-model="activeTab" type="border-card"> | 
 |  |  |       <!-- åæè®¾ç½® --> | 
 |  |  |       <el-tab-pane label="åæè®¾ç½®" name="holiday"> | 
 |  |  |         <div class="tab-content"> | 
 |  |  |           <el-button type="primary" @click="openDialog('holiday', 'add')">æ°å¢åæ</el-button> | 
 |  |  |            | 
 |  |  |           <el-table :data="holidayData" border style="width: 100%; margin-top: 20px;"> | 
 |  |  |             <el-table-column prop="name" label="åæåç§°" /> | 
 |  |  |             <el-table-column prop="type" label="åæç±»å"> | 
 |  |  |               <template #default="scope"> | 
 |  |  |                 <el-tag :type="getTagType(scope.row.type)">{{ getTypeLabel(scope.row.type) }}</el-tag> | 
 |  |  |               </template> | 
 |  |  |             </el-table-column> | 
 |  |  |             <el-table-column prop="startDate" label="å¼å§æ¥æ"  /> | 
 |  |  |             <el-table-column prop="endDate" label="ç»ææ¥æ"  /> | 
 |  |  |             <el-table-column prop="days" label="天æ°"  align="center" /> | 
 |  |  |             <el-table-column prop="status" label="ç¶æ" > | 
 |  |  |               <template #default="scope"> | 
 |  |  |                 <el-tag :type="scope.row.status === 'active' ? 'success' : 'info'"> | 
 |  |  |                   {{ scope.row.status === 'active' ? 'å¯ç¨' : 'åç¨' }} | 
 |  |  |                 </el-tag> | 
 |  |  |               </template> | 
 |  |  |             </el-table-column> | 
 |  |  |             <el-table-column label="æä½" fixed="right"> | 
 |  |  |               <template #default="scope"> | 
 |  |  |                 <el-button type="primary" size="small" @click="openDialog('holiday', 'edit', scope.row)">ç¼è¾</el-button> | 
 |  |  |                 <el-button type="danger" size="small" @click="deleteItem('holiday', scope.row)">å é¤</el-button> | 
 |  |  |               </template> | 
 |  |  |             </el-table-column> | 
 |  |  |           </el-table> | 
 |  |  |         </div> | 
 |  |  |       </el-tab-pane> | 
 |  |  |  | 
 |  |  |       <!-- å¹´å设置 --> | 
 |  |  |       <el-tab-pane label="å¹´å设置" name="annual"> | 
 |  |  |         <div class="tab-content"> | 
 |  |  |           <el-button type="primary" @click="openDialog('annual', 'add')">æ°å¢å¹´åè§å</el-button> | 
 |  |  |            | 
 |  |  |           <el-table :data="annualData" border style="width: 100%; margin-top: 20px;"> | 
 |  |  |             <el-table-column prop="employeeType" label="å工类å"/> | 
 |  |  |             <el-table-column prop="workYears" label="å·¥ä½å¹´é" /> | 
 |  |  |             <el-table-column prop="annualDays" label="å¹´å天æ°" align="center" /> | 
 |  |  |             <el-table-column prop="maxCarryOver" label="æå¤§ç»è½¬å¤©æ°" align="center" /> | 
 |  |  |             <el-table-column prop="status" label="ç¶æ"> | 
 |  |  |               <template #default="scope"> | 
 |  |  |                 <el-tag :type="scope.row.status === 'active' ? 'success' : 'info'"> | 
 |  |  |                   {{ scope.row.status === 'active' ? 'å¯ç¨' : 'åç¨' }} | 
 |  |  |                 </el-tag> | 
 |  |  |               </template> | 
 |  |  |             </el-table-column> | 
 |  |  |             <el-table-column label="æä½" fixed="right"> | 
 |  |  |               <template #default="scope"> | 
 |  |  |                 <el-button type="primary" size="small" @click="openDialog('annual', 'edit', scope.row)">ç¼è¾</el-button> | 
 |  |  |                 <el-button type="danger" size="small" @click="deleteItem('annual', scope.row)">å é¤</el-button> | 
 |  |  |               </template> | 
 |  |  |             </el-table-column> | 
 |  |  |           </el-table> | 
 |  |  |         </div> | 
 |  |  |       </el-tab-pane> | 
 |  |  |  | 
 |  |  |       <!-- å ç设置 --> | 
 |  |  |       <el-tab-pane label="å ç设置" name="overtime"> | 
 |  |  |         <div class="tab-content"> | 
 |  |  |           <el-button type="primary" @click="openDialog('overtime', 'add')">æ°å¢å çè§å</el-button> | 
 |  |  |            | 
 |  |  |           <el-table :data="overtimeData" border style="width: 100%; margin-top: 20px;"> | 
 |  |  |             <el-table-column prop="name" label="è§ååç§°" /> | 
 |  |  |             <el-table-column prop="type" label="å çç±»å" > | 
 |  |  |               <template #default="scope"> | 
 |  |  |                 <el-tag :type="getTagType(scope.row.type)">{{ getTypeLabel(scope.row.type) }}</el-tag> | 
 |  |  |               </template> | 
 |  |  |             </el-table-column> | 
 |  |  |             <el-table-column prop="startTime" label="å¼å§æ¶é´"  /> | 
 |  |  |             <el-table-column prop="endTime" label="ç»ææ¶é´"  /> | 
 |  |  |             <el-table-column prop="rate" label="åç" align="center" /> | 
 |  |  |             <el-table-column prop="status" label="ç¶æ" > | 
 |  |  |               <template #default="scope"> | 
 |  |  |                 <el-tag :type="scope.row.status === 'active' ? 'success' : 'info'"> | 
 |  |  |                   {{ scope.row.status === 'active' ? 'å¯ç¨' : 'åç¨' }} | 
 |  |  |                 </el-tag> | 
 |  |  |               </template> | 
 |  |  |             </el-table-column> | 
 |  |  |             <el-table-column label="æä½" fixed="right"> | 
 |  |  |               <template #default="scope"> | 
 |  |  |                 <el-button type="primary" size="small" @click="openDialog('overtime', 'edit', scope.row)">ç¼è¾</el-button> | 
 |  |  |                 <el-button type="danger" size="small" @click="deleteItem('overtime', scope.row)">å é¤</el-button> | 
 |  |  |               </template> | 
 |  |  |             </el-table-column> | 
 |  |  |           </el-table> | 
 |  |  |         </div> | 
 |  |  |       </el-tab-pane> | 
 |  |  |  | 
 |  |  |       <!-- ä¸çæ¶é´è®¾ç½® --> | 
 |  |  |       <el-tab-pane label="ä¸çæ¶é´è®¾ç½®" name="worktime"> | 
 |  |  |         <div class="tab-content"> | 
 |  |  |           <el-button type="primary" @click="openDialog('worktime', 'add')">æ°å¢æ¶é´æ®µ</el-button> | 
 |  |  |            | 
 |  |  |           <el-table :data="worktimeData" border style="width: 100%; margin-top: 20px;"> | 
 |  |  |             <el-table-column prop="name" label="æ¶é´æ®µåç§°"  /> | 
 |  |  |             <el-table-column prop="startTime" label="ä¸çæ¶é´"/> | 
 |  |  |             <el-table-column prop="endTime" label="ä¸çæ¶é´" /> | 
 |  |  |             <el-table-column prop="flexibleStart" label="å¼¹æ§ä¸ç"> | 
 |  |  |               <template #default="scope"> | 
 |  |  |                 <el-tag :type="scope.row.flexibleStart ? 'success' : 'info'"> | 
 |  |  |                   {{ scope.row.flexibleStart ? 'æ¯' : 'å¦' }} | 
 |  |  |                 </el-tag> | 
 |  |  |               </template> | 
 |  |  |             </el-table-column> | 
 |  |  |             <el-table-column prop="flexibleMinutes" label="å¼¹æ§æ¶é´(åé)" width="120" align="center" /> | 
 |  |  |             <el-table-column prop="status" label="ç¶æ" > | 
 |  |  |               <template #default="scope"> | 
 |  |  |                 <el-tag :type="scope.row.status === 'active' ? 'success' : 'info'"> | 
 |  |  |                   {{ scope.row.status === 'active' ? 'å¯ç¨' : 'åç¨' }} | 
 |  |  |                 </el-tag> | 
 |  |  |               </template> | 
 |  |  |             </el-table-column> | 
 |  |  |             <el-table-column label="æä½" fixed="right"> | 
 |  |  |               <template #default="scope"> | 
 |  |  |                 <el-button type="primary" size="small" @click="openDialog('worktime', 'edit', scope.row)">ç¼è¾</el-button> | 
 |  |  |                 <el-button type="danger" size="small" @click="deleteItem('worktime', scope.row)">å é¤</el-button> | 
 |  |  |               </template> | 
 |  |  |             </el-table-column> | 
 |  |  |           </el-table> | 
 |  |  |         </div> | 
 |  |  |       </el-tab-pane> | 
 |  |  |     </el-tabs> | 
 |  |  |  | 
 |  |  |     <!-- éç¨å¼¹çª --> | 
 |  |  |     <el-dialog v-model="dialogVisible" :title="dialogTitle" width="600px"> | 
 |  |  |       <el-form ref="formRef" :model="form" :rules="rules" label-width="100px"> | 
 |  |  |         <el-form-item label="åç§°" prop="name" v-if="currentType !== 'annual'"> | 
 |  |  |           <el-input v-model="form.name" placeholder="请è¾å
¥åç§°" /> | 
 |  |  |         </el-form-item> | 
 |  |  |          | 
 |  |  |         <el-form-item label="ç±»å" prop="type" v-if="currentType === 'holiday' || currentType === 'overtime'"> | 
 |  |  |           <el-select v-model="form.type" placeholder="è¯·éæ©ç±»å" style="width: 100%"> | 
 |  |  |             <el-option  | 
 |  |  |               v-for="option in getTypeOptions()"  | 
 |  |  |               :key="option.value"  | 
 |  |  |               :label="option.label"  | 
 |  |  |               :value="option.value"  | 
 |  |  |             /> | 
 |  |  |           </el-select> | 
 |  |  |         </el-form-item> | 
 |  |  |  | 
 |  |  |         <el-form-item label="å工类å" prop="employeeType" v-if="currentType === 'annual'"> | 
 |  |  |           <el-select v-model="form.employeeType" placeholder="è¯·éæ©å工类å" style="width: 100%"> | 
 |  |  |             <el-option label="æ£å¼åå·¥" value="regular" /> | 
 |  |  |             <el-option label="è¯ç¨æåå·¥" value="probation" /> | 
 |  |  |             <el-option label="å®ä¹ ç" value="intern" /> | 
 |  |  |           </el-select> | 
 |  |  |         </el-form-item> | 
 |  |  |  | 
 |  |  |         <el-form-item label="å·¥ä½å¹´é" prop="workYears" v-if="currentType === 'annual'"> | 
 |  |  |           <el-input v-model="form.workYears" placeholder="å¦ï¼1-3å¹´ã3-5å¹´ç" /> | 
 |  |  |         </el-form-item> | 
 |  |  |  | 
 |  |  |         <el-form-item label="å¹´å天æ°" prop="annualDays" v-if="currentType === 'annual'"> | 
 |  |  |           <el-input-number v-model="form.annualDays" :min="0" :max="365" style="width: 100%" /> | 
 |  |  |         </el-form-item> | 
 |  |  |  | 
 |  |  |         <el-form-item label="æå¤§ç»è½¬å¤©æ°" prop="maxCarryOver" v-if="currentType === 'annual'"> | 
 |  |  |           <el-input-number v-model="form.maxCarryOver" :min="0" :max="30" style="width: 100%" /> | 
 |  |  |         </el-form-item> | 
 |  |  |  | 
 |  |  |                           <el-form-item label="æ¥æèå´" prop="dateRange" v-if="currentType === 'holiday'"> | 
 |  |  |            <el-date-picker | 
 |  |  |              v-model="form.dateRange" | 
 |  |  |              type="daterange" | 
 |  |  |              range-separator="è³" | 
 |  |  |              start-placeholder="å¼å§æ¥æ" | 
 |  |  |              end-placeholder="ç»ææ¥æ" | 
 |  |  |              style="width: 100%" | 
 |  |  |              @change="calculateDays" | 
 |  |  |            /> | 
 |  |  |          </el-form-item> | 
 |  |  |  | 
 |  |  |         <el-form-item label="天æ°" prop="days" v-if="currentType === 'holiday'"> | 
 |  |  |           <el-input-number v-model="form.days" :min="0" style="width: 100%" /> | 
 |  |  |         </el-form-item> | 
 |  |  |  | 
 |  |  |                  <el-form-item label="å¼å§æ¶é´" prop="startTime" v-if="currentType === 'overtime'"> | 
 |  |  |            <el-time-picker | 
 |  |  |              v-model="form.startTime" | 
 |  |  |              placeholder="å¼å§æ¶é´" | 
 |  |  |              format="HH:mm" | 
 |  |  |              value-format="HH:mm" | 
 |  |  |              style="width: 100%" | 
 |  |  |              @change="validateTimeField('startTime')" | 
 |  |  |            /> | 
 |  |  |          </el-form-item> | 
 |  |  |           | 
 |  |  |          <el-form-item label="ç»ææ¶é´" prop="endTime" v-if="currentType === 'overtime'"> | 
 |  |  |            <el-time-picker | 
 |  |  |              v-model="form.endTime" | 
 |  |  |              placeholder="ç»ææ¶é´" | 
 |  |  |              format="HH:mm" | 
 |  |  |              value-format="HH:mm" | 
 |  |  |              style="width: 100%" | 
 |  |  |              @change="validateTimeField('endTime')" | 
 |  |  |            /> | 
 |  |  |          </el-form-item> | 
 |  |  |  | 
 |  |  |         <el-form-item label="åç" prop="rate" v-if="currentType === 'overtime'"> | 
 |  |  |           <el-input-number v-model="form.rate" :min="1" :max="3" :step="0.5" style="width: 100%" /> | 
 |  |  |         </el-form-item> | 
 |  |  |  | 
 |  |  |                  <el-form-item label="ä¸çæ¶é´" prop="workStartTime" v-if="currentType === 'worktime'"> | 
 |  |  |            <el-time-picker | 
 |  |  |              v-model="form.workStartTime" | 
 |  |  |              placeholder="ä¸çæ¶é´" | 
 |  |  |              format="HH:mm" | 
 |  |  |              value-format="HH:mm" | 
 |  |  |              style="width: 100%" | 
 |  |  |              @change="validateTimeField('workStartTime')" | 
 |  |  |            /> | 
 |  |  |          </el-form-item> | 
 |  |  |  | 
 |  |  |          <el-form-item label="ä¸çæ¶é´" prop="workEndTime" v-if="currentType === 'worktime'"> | 
 |  |  |            <el-time-picker | 
 |  |  |              v-model="form.workEndTime" | 
 |  |  |              placeholder="ä¸çæ¶é´" | 
 |  |  |              format="HH:mm" | 
 |  |  |              value-format="HH:mm" | 
 |  |  |              style="width: 100%" | 
 |  |  |              @change="validateTimeField('workEndTime')" | 
 |  |  |            /> | 
 |  |  |          </el-form-item> | 
 |  |  |  | 
 |  |  |         <el-form-item label="å¼¹æ§ä¸ç" prop="flexibleStart" v-if="currentType === 'worktime'"> | 
 |  |  |           <el-switch v-model="form.flexibleStart" /> | 
 |  |  |         </el-form-item> | 
 |  |  |  | 
 |  |  |         <el-form-item label="å¼¹æ§æ¶é´(åé)" prop="flexibleMinutes" v-if="currentType === 'worktime' && form.flexibleStart"> | 
 |  |  |           <el-input-number v-model="form.flexibleMinutes" :min="0" :max="120" style="width: 100%" /> | 
 |  |  |         </el-form-item> | 
 |  |  |  | 
 |  |  |                  <el-form-item label="ç¶æ" prop="status"> | 
 |  |  |            <el-radio-group v-model="form.status"> | 
 |  |  |              <el-radio value="active">å¯ç¨</el-radio> | 
 |  |  |              <el-radio value="inactive">åç¨</el-radio> | 
 |  |  |            </el-radio-group> | 
 |  |  |          </el-form-item> | 
 |  |  |       </el-form> | 
 |  |  |        | 
 |  |  |       <template #footer> | 
 |  |  |         <span class="dialog-footer"> | 
 |  |  |           <el-button @click="dialogVisible = false">åæ¶</el-button> | 
 |  |  |           <el-button type="primary" @click="submitForm">ç¡®å®</el-button> | 
 |  |  |         </span> | 
 |  |  |       </template> | 
 |  |  |     </el-dialog> | 
 |  |  |   </div> | 
 |  |  | </template> | 
 |  |  |  | 
 |  |  | <script setup> | 
 |  |  | import { ref, reactive, onMounted, onUnmounted } from 'vue' | 
 |  |  | import { ElMessage, ElMessageBox } from 'element-plus' | 
 |  |  |  | 
 |  |  | // å½åæ¿æ´»çæ ç¾é¡µ | 
 |  |  | const activeTab = ref('holiday') | 
 |  |  |  | 
 |  |  | // å¼¹çªç¸å
³ | 
 |  |  | const dialogVisible = ref(false) | 
 |  |  | const dialogTitle = ref('') | 
 |  |  | const currentType = ref('') | 
 |  |  | const currentAction = ref('') | 
 |  |  | const currentEditId = ref('') | 
 |  |  | const formRef = ref() | 
 |  |  |  | 
 |  |  | // è¡¨åæ°æ® | 
 |  |  | const form = reactive({ | 
 |  |  |   name: '', | 
 |  |  |   type: '', | 
 |  |  |   dateRange: [], | 
 |  |  |   days: 0, | 
 |  |  |   employeeType: '', | 
 |  |  |   workYears: '', | 
 |  |  |   annualDays: 0, | 
 |  |  |   maxCarryOver: 0, | 
 |  |  |   startTime: '', // å çå¼å§æ¶é´ | 
 |  |  |   endTime: '',   // å çç»ææ¶é´ | 
 |  |  |   workStartTime: '', // ä¸çæ¶é´ | 
 |  |  |   workEndTime: '',   // ä¸çæ¶é´ | 
 |  |  |   rate: 1.5, | 
 |  |  |   flexibleStart: false, | 
 |  |  |   flexibleMinutes: 30, | 
 |  |  |   status: 'active' | 
 |  |  | }) | 
 |  |  |  | 
 |  |  | // è¡¨åéªè¯è§å | 
 |  |  | const rules = { | 
 |  |  |   name: [{ required: true, message: '请è¾å
¥åç§°', trigger: 'blur' }], | 
 |  |  |   type: [{ required: true, message: 'è¯·éæ©ç±»å', trigger: 'change' }], | 
 |  |  |   dateRange: [{ required: true, message: 'è¯·éæ©æ¥æèå´', trigger: 'change' }], | 
 |  |  |   days: [{ required: true, message: '请è¾å
¥å¤©æ°', trigger: 'blur' }], | 
 |  |  |   employeeType: [{ required: true, message: 'è¯·éæ©å工类å', trigger: 'change' }], | 
 |  |  |   workYears: [{ required: true, message: '请è¾å
¥å·¥ä½å¹´é', trigger: 'blur' }], | 
 |  |  |   annualDays: [{ required: true, message: '请è¾å
¥å¹´å天æ°', trigger: 'blur' }], | 
 |  |  |   maxCarryOver: [{ required: true, message: '请è¾å
¥æå¤§ç»è½¬å¤©æ°', trigger: 'blur' }], | 
 |  |  |   startTime: [{  | 
 |  |  |     required: true,  | 
 |  |  |     message: 'è¯·éæ©å¼å§æ¶é´',  | 
 |  |  |     trigger: 'change', | 
 |  |  |     validator: (rule, value, callback) => { | 
 |  |  |       if (!value) { | 
 |  |  |         callback(new Error('è¯·éæ©å¼å§æ¶é´')) | 
 |  |  |       } else { | 
 |  |  |         callback() | 
 |  |  |       } | 
 |  |  |     } | 
 |  |  |   }], | 
 |  |  |   endTime: [{  | 
 |  |  |     required: true,  | 
 |  |  |     message: 'è¯·éæ©ç»ææ¶é´',  | 
 |  |  |     trigger: 'change', | 
 |  |  |     validator: (rule, value, callback) => { | 
 |  |  |       if (!value) { | 
 |  |  |         callback(new Error('è¯·éæ©ç»ææ¶é´')) | 
 |  |  |       } else { | 
 |  |  |         callback() | 
 |  |  |       } | 
 |  |  |     } | 
 |  |  |   }], | 
 |  |  |   workStartTime: [{  | 
 |  |  |     required: true,  | 
 |  |  |     message: 'è¯·éæ©ä¸çæ¶é´',  | 
 |  |  |     trigger: 'change', | 
 |  |  |     validator: (rule, value, callback) => { | 
 |  |  |       if (!value) { | 
 |  |  |         callback(new Error('è¯·éæ©ä¸çæ¶é´')) | 
 |  |  |       } else { | 
 |  |  |         callback() | 
 |  |  |       } | 
 |  |  |     } | 
 |  |  |   }], | 
 |  |  |   workEndTime: [{  | 
 |  |  |     required: true,  | 
 |  |  |     message: 'è¯·éæ©ä¸çæ¶é´',  | 
 |  |  |     trigger: 'change', | 
 |  |  |     validator: (rule, value, callback) => { | 
 |  |  |       if (!value) { | 
 |  |  |         callback(new Error('è¯·éæ©ä¸çæ¶é´')) | 
 |  |  |       } else { | 
 |  |  |         callback() | 
 |  |  |       } | 
 |  |  |     } | 
 |  |  |   }], | 
 |  |  |   rate: [{ required: true, message: '请è¾å
¥åç', trigger: 'blur' }] | 
 |  |  | } | 
 |  |  |  | 
 |  |  | // æ¨¡ææ°æ® | 
 |  |  | const holidayData = ref([ | 
 |  |  |   { id: '1', name: 'æ¥è', type: 'legal', startDate: '2024-02-10', endDate: '2024-02-17', days: 8, status: 'active' }, | 
 |  |  |   { id: '2', name: 'æ¸
æè', type: 'legal', startDate: '2024-04-05', endDate: '2024-04-05', days: 1, status: 'active' }, | 
 |  |  |   { id: '3', name: 'å³å¨è', type: 'legal', startDate: '2024-05-01', endDate: '2024-05-05', days: 5, status: 'active' } | 
 |  |  | ]) | 
 |  |  |  | 
 |  |  | const annualData = ref([ | 
 |  |  |   { id: '1', employeeType: 'regular', workYears: '1-3å¹´', annualDays: 5, maxCarryOver: 2, status: 'active' }, | 
 |  |  |   { id: '2', employeeType: 'regular', workYears: '3-5å¹´', annualDays: 10, maxCarryOver: 5, status: 'active' }, | 
 |  |  |   { id: '3', employeeType: 'regular', workYears: '5年以ä¸', annualDays: 15, maxCarryOver: 10, status: 'active' } | 
 |  |  | ]) | 
 |  |  |  | 
 |  |  | const overtimeData = ref([ | 
 |  |  |   { id: '1', name: '工使¥å ç', type: 'weekday', startTime: '18:00', endTime: '22:00', rate: 1.5, status: 'active' }, | 
 |  |  |   { id: '2', name: '卿«å ç', type: 'weekend', startTime: '09:00', endTime: '18:00', rate: 2.0, status: 'active' }, | 
 |  |  |   { id: '3', name: 'æ·±å¤å ç', type: 'night', startTime: '22:00', endTime: '06:00', rate: 2.5, status: 'active' } | 
 |  |  | ]) | 
 |  |  |  | 
 |  |  | const worktimeData = ref([ | 
 |  |  |   { id: '1', name: 'æ å工使¶é´', startTime: '09:00', endTime: '18:00', flexibleStart: true, flexibleMinutes: 30, status: 'active' }, | 
 |  |  |   { id: '2', name: 'æ©çæ¶é´', startTime: '08:00', endTime: '17:00', flexibleStart: false, flexibleMinutes: 0, status: 'active' }, | 
 |  |  |   { id: '3', name: 'æçæ¶é´', startTime: '14:00', endTime: '23:00', flexibleStart: false, flexibleMinutes: 0, status: 'active' } | 
 |  |  | ]) | 
 |  |  |  | 
 |  |  | //ʌᴌ
·å½æ° | 
 |  |  | const getTagType = (type) => { | 
 |  |  |   const tagMap = { | 
 |  |  |     legal: 'success', adjustment: 'warning', special: 'info', company: 'primary', | 
 |  |  |     weekday: 'primary', weekend: 'warning', holiday: 'danger', night: 'info' | 
 |  |  |   } | 
 |  |  |   return tagMap[type] || 'info' | 
 |  |  | } | 
 |  |  |  | 
 |  |  | const getTypeLabel = (type) => { | 
 |  |  |   const labelMap = { | 
 |  |  |     legal: 'æ³å®è忥', adjustment: 'è°ä¼æ¥', special: 'ç¹æ®åæ', company: 'å
¬å¸åæ', | 
 |  |  |     weekday: '工使¥å ç', weekend: '卿«å ç', holiday: 'è忥å ç', night: 'æ·±å¤å ç' | 
 |  |  |   } | 
 |  |  |   return labelMap[type] || type | 
 |  |  | } | 
 |  |  |  | 
 |  |  | const getTypeOptions = () => { | 
 |  |  |   if (currentType.value === 'holiday') { | 
 |  |  |     return [ | 
 |  |  |       { label: 'æ³å®è忥', value: 'legal' }, | 
 |  |  |       { label: 'è°ä¼æ¥', value: 'adjustment' }, | 
 |  |  |       { label: 'ç¹æ®åæ', value: 'special' }, | 
 |  |  |       { label: 'å
¬å¸åæ', value: 'company' } | 
 |  |  |     ] | 
 |  |  |   } else if (currentType.value === 'overtime') { | 
 |  |  |     return [ | 
 |  |  |       { label: '工使¥å ç', value: 'weekday' }, | 
 |  |  |       { label: '卿«å ç', value: 'weekend' }, | 
 |  |  |       { label: 'è忥å ç', value: 'holiday' }, | 
 |  |  |       { label: 'æ·±å¤å ç', value: 'night' } | 
 |  |  |     ] | 
 |  |  |   } | 
 |  |  |   return [] | 
 |  |  | } | 
 |  |  |  | 
 |  |  | // è®¡ç®åæå¤©æ° | 
 |  |  | const calculateDays = () => { | 
 |  |  |   try { | 
 |  |  |     if (form.dateRange && form.dateRange.length === 2 && form.dateRange[0] && form.dateRange[1]) { | 
 |  |  |       const start = new Date(form.dateRange[0]) | 
 |  |  |       const end = new Date(form.dateRange[1]) | 
 |  |  |        | 
 |  |  |       if (isNaN(start.getTime()) || isNaN(end.getTime())) { | 
 |  |  |         console.warn('æ æçæ¥ææ ¼å¼') | 
 |  |  |         return | 
 |  |  |       } | 
 |  |  |        | 
 |  |  |       const diffTime = Math.abs(end - start) | 
 |  |  |       const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)) + 1 | 
 |  |  |       form.days = diffDays | 
 |  |  |     } | 
 |  |  |   } catch (error) { | 
 |  |  |     console.error('计ç®å¤©æ°å¤±è´¥:', error) | 
 |  |  |   } | 
 |  |  | } | 
 |  |  |  | 
 |  |  | // éªè¯æ¶é´æ ¼å¼ | 
 |  |  | const validateTime = (time) => { | 
 |  |  |   if (!time) return '' | 
 |  |  |   if (typeof time === 'string') return time | 
 |  |  |   if (time instanceof Date) { | 
 |  |  |     return time.toTimeString().slice(0, 5) | 
 |  |  |   } | 
 |  |  |   return '' | 
 |  |  | } | 
 |  |  |  | 
 |  |  | // éªè¯æ¶é´å段 | 
 |  |  | const validateTimeField = (fieldName) => { | 
 |  |  |   try { | 
 |  |  |     const value = form[fieldName] | 
 |  |  |     if (value && typeof value === 'object' && value.hour !== undefined) { | 
 |  |  |       // å¦ææ¯æ¶é´å¯¹è±¡ï¼è½¬æ¢ä¸ºåç¬¦ä¸²æ ¼å¼ | 
 |  |  |       const hours = value.hour.toString().padStart(2, '0') | 
 |  |  |       const minutes = value.minute.toString().padStart(2, '0') | 
 |  |  |       form[fieldName] = `${hours}:${minutes}` | 
 |  |  |     } | 
 |  |  |   } catch (error) { | 
 |  |  |     console.error(`éªè¯æ¶é´å段 ${fieldName} å¤±è´¥:`, error) | 
 |  |  |     form[fieldName] = '' | 
 |  |  |   } | 
 |  |  | } | 
 |  |  |  | 
 |  |  | // æå¼å¼¹çª | 
 |  |  | const openDialog = (type, action, row = null) => { | 
 |  |  |   try { | 
 |  |  |     currentType.value = type | 
 |  |  |     currentAction.value = action | 
 |  |  |      | 
 |  |  |     if (action === 'add') { | 
 |  |  |       dialogTitle.value = `æ°å¢${getTypeName(type)}` | 
 |  |  |       currentEditId.value = '' | 
 |  |  |       resetForm() | 
 |  |  |     } else if (action === 'edit' && row) { | 
 |  |  |       dialogTitle.value = `ç¼è¾${getTypeName(type)}` | 
 |  |  |       currentEditId.value = row.id | 
 |  |  |       fillForm(row) | 
 |  |  |     } | 
 |  |  |      | 
 |  |  |     dialogVisible.value = true | 
 |  |  |   } catch (error) { | 
 |  |  |     console.error('æå¼å¼¹çªå¤±è´¥:', error) | 
 |  |  |     ElMessage.error('æå¼å¼¹çªå¤±è´¥ï¼è¯·éè¯') | 
 |  |  |   } | 
 |  |  | } | 
 |  |  |  | 
 |  |  | const getTypeName = (type) => { | 
 |  |  |   const nameMap = { | 
 |  |  |     holiday: 'åæ', | 
 |  |  |     annual: 'å¹´åè§å', | 
 |  |  |     overtime: 'å çè§å', | 
 |  |  |     worktime: 'æ¶é´æ®µ' | 
 |  |  |   } | 
 |  |  |   return nameMap[type] || '' | 
 |  |  | } | 
 |  |  |  | 
 |  |  | const resetForm = () => { | 
 |  |  |   Object.assign(form, { | 
 |  |  |     name: '', | 
 |  |  |     type: '', | 
 |  |  |     dateRange: [], | 
 |  |  |     days: 0, | 
 |  |  |     employeeType: '', | 
 |  |  |     workYears: '', | 
 |  |  |     annualDays: 0, | 
 |  |  |     maxCarryOver: 0, | 
 |  |  |     startTime: '', | 
 |  |  |     endTime: '', | 
 |  |  |     workStartTime: '', | 
 |  |  |     workEndTime: '', | 
 |  |  |     rate: 1.5, | 
 |  |  |     flexibleStart: false, | 
 |  |  |     flexibleMinutes: 30, | 
 |  |  |     status: 'active' | 
 |  |  |   }) | 
 |  |  | } | 
 |  |  |  | 
 |  |  | const fillForm = (row) => { | 
 |  |  |   if (currentType.value === 'holiday') { | 
 |  |  |     Object.assign(form, { | 
 |  |  |       name: row.name, | 
 |  |  |       type: row.type, | 
 |  |  |       dateRange: [new Date(row.startDate), new Date(row.endDate)], | 
 |  |  |       days: row.days, | 
 |  |  |       status: row.status | 
 |  |  |     }) | 
 |  |  |   } else if (currentType.value === 'annual') { | 
 |  |  |     Object.assign(form, { | 
 |  |  |       employeeType: row.employeeType, | 
 |  |  |       workYears: row.workYears, | 
 |  |  |       annualDays: row.annualDays, | 
 |  |  |       maxCarryOver: row.maxCarryOver, | 
 |  |  |       status: row.status | 
 |  |  |     }) | 
 |  |  |   } else if (currentType.value === 'overtime') { | 
 |  |  |     Object.assign(form, { | 
 |  |  |       name: row.name, | 
 |  |  |       type: row.type, | 
 |  |  |       startTime: row.startTime || '', | 
 |  |  |       endTime: row.endTime || '', | 
 |  |  |       rate: row.rate, | 
 |  |  |       status: row.status | 
 |  |  |     }) | 
 |  |  |   } else if (currentType.value === 'worktime') { | 
 |  |  |     Object.assign(form, { | 
 |  |  |       name: row.name, | 
 |  |  |       workStartTime: row.startTime || '', | 
 |  |  |       workEndTime: row.endTime || '', | 
 |  |  |       flexibleStart: row.flexibleStart, | 
 |  |  |       flexibleMinutes: row.flexibleMinutes, | 
 |  |  |       status: row.status | 
 |  |  |     }) | 
 |  |  |   } | 
 |  |  | } | 
 |  |  |  | 
 |  |  | // æäº¤è¡¨å | 
 |  |  | const submitForm = async () => { | 
 |  |  |   try { | 
 |  |  |     if (!formRef.value) { | 
 |  |  |       ElMessage.error('表åå¼ç¨ä¸åå¨') | 
 |  |  |       return | 
 |  |  |     } | 
 |  |  |      | 
 |  |  |     await formRef.value.validate() | 
 |  |  |      | 
 |  |  |     if (currentAction.value === 'add') { | 
 |  |  |       addItem() | 
 |  |  |     } else if (currentAction.value === 'edit') { | 
 |  |  |       editItem() | 
 |  |  |     } | 
 |  |  |      | 
 |  |  |     dialogVisible.value = false | 
 |  |  |     ElMessage.success('æä½æå') | 
 |  |  |   } catch (error) { | 
 |  |  |     console.error('表åéªè¯å¤±è´¥:', error) | 
 |  |  |     ElMessage.error('表åéªè¯å¤±è´¥ï¼è¯·æ£æ¥è¾å
¥') | 
 |  |  |   } | 
 |  |  | } | 
 |  |  |  | 
 |  |  | const addItem = () => { | 
 |  |  |   const newItem = { ...form, id: Date.now().toString() } | 
 |  |  |    | 
 |  |  |   if (currentType.value === 'holiday') { | 
 |  |  |     newItem.startDate = form.dateRange[0].toISOString().split('T')[0] | 
 |  |  |     newItem.endDate = form.dateRange[1].toISOString().split('T')[0] | 
 |  |  |     holidayData.value.push(newItem) | 
 |  |  |   } else if (currentType.value === 'annual') { | 
 |  |  |     annualData.value.push(newItem) | 
 |  |  |   } else if (currentType.value === 'overtime') { | 
 |  |  |     newItem.startTime = form.startTime || '' | 
 |  |  |     newItem.endTime = form.endTime || '' | 
 |  |  |     overtimeData.value.push(newItem) | 
 |  |  |   } else if (currentType.value === 'worktime') { | 
 |  |  |     newItem.startTime = form.workStartTime || '' | 
 |  |  |     newItem.endTime = form.workEndTime || '' | 
 |  |  |     worktimeData.value.push(newItem) | 
 |  |  |   } | 
 |  |  | } | 
 |  |  |  | 
 |  |  | const editItem = () => { | 
 |  |  |   let dataArray | 
 |  |  |   let index | 
 |  |  |    | 
 |  |  |   if (currentType.value === 'holiday') { | 
 |  |  |     dataArray = holidayData.value | 
 |  |  |     index = dataArray.findIndex(item => item.id === currentEditId.value) | 
 |  |  |     if (index > -1) { | 
 |  |  |       dataArray[index] = {  | 
 |  |  |         ...dataArray[index], | 
 |  |  |         name: form.name, | 
 |  |  |         type: form.type, | 
 |  |  |         startDate: form.dateRange[0].toISOString().split('T')[0], | 
 |  |  |         endDate: form.dateRange[1].toISOString().split('T')[0], | 
 |  |  |         days: form.days, | 
 |  |  |         status: form.status | 
 |  |  |       } | 
 |  |  |     } | 
 |  |  |   } else if (currentType.value === 'annual') { | 
 |  |  |     dataArray = annualData.value | 
 |  |  |     index = dataArray.findIndex(item => item.id === currentEditId.value) | 
 |  |  |     if (index > -1) { | 
 |  |  |       dataArray[index] = {  | 
 |  |  |         ...dataArray[index], | 
 |  |  |         employeeType: form.employeeType, | 
 |  |  |         workYears: form.workYears, | 
 |  |  |         annualDays: form.annualDays, | 
 |  |  |         maxCarryOver: form.maxCarryOver, | 
 |  |  |         status: form.status | 
 |  |  |       } | 
 |  |  |     } | 
 |  |  |   } else if (currentType.value === 'overtime') { | 
 |  |  |     dataArray = overtimeData.value | 
 |  |  |     index = dataArray.findIndex(item => item.id === currentEditId.value) | 
 |  |  |     if (index > -1) { | 
 |  |  |       dataArray[index] = {  | 
 |  |  |         ...dataArray[index], | 
 |  |  |         name: form.name, | 
 |  |  |         type: form.type, | 
 |  |  |         startTime: form.startTime || '', | 
 |  |  |         endTime: form.endTime || '', | 
 |  |  |         rate: form.rate, | 
 |  |  |         status: form.status | 
 |  |  |       } | 
 |  |  |     } | 
 |  |  |   } else if (currentType.value === 'worktime') { | 
 |  |  |     dataArray = worktimeData.value | 
 |  |  |     index = dataArray.findIndex(item => item.id === currentEditId.value) | 
 |  |  |     if (index > -1) { | 
 |  |  |       dataArray[index] = {  | 
 |  |  |         ...dataArray[index], | 
 |  |  |         name: form.name, | 
 |  |  |         startTime: form.workStartTime || '', | 
 |  |  |         endTime: form.workEndTime || '', | 
 |  |  |         flexibleStart: form.flexibleStart, | 
 |  |  |         flexibleMinutes: form.flexibleMinutes, | 
 |  |  |         status: form.status | 
 |  |  |       } | 
 |  |  |     } | 
 |  |  |   } | 
 |  |  | } | 
 |  |  |  | 
 |  |  | // å é¤é¡¹ç® | 
 |  |  | const deleteItem = (type, row) => { | 
 |  |  |   ElMessageBox.confirm('ç¡®å®è¦å é¤è¿ä¸ªé¡¹ç®åï¼', 'æç¤º', { | 
 |  |  |     confirmButtonText: 'ç¡®å®', | 
 |  |  |     cancelButtonText: 'åæ¶', | 
 |  |  |     type: 'warning' | 
 |  |  |   }).then(() => { | 
 |  |  |     let dataArray | 
 |  |  |     if (type === 'holiday') dataArray = holidayData.value | 
 |  |  |     else if (type === 'annual') dataArray = annualData.value | 
 |  |  |     else if (type === 'overtime') dataArray = overtimeData.value | 
 |  |  |     else if (type === 'worktime') dataArray = worktimeData.value | 
 |  |  |      | 
 |  |  |     const index = dataArray.findIndex(item => item.id === row.id) | 
 |  |  |     if (index > -1) { | 
 |  |  |       dataArray.splice(index, 1) | 
 |  |  |       ElMessage.success('å é¤æå') | 
 |  |  |     } | 
 |  |  |   }) | 
 |  |  | } | 
 |  |  |  | 
 |  |  | onMounted(() => { | 
 |  |  |   console.log('èå¤ç®¡ç页é¢å è½½å®æ') | 
 |  |  | }) | 
 |  |  |  | 
 |  |  | onUnmounted(() => { | 
 |  |  |   // æ¸
çå·¥ä½ | 
 |  |  |   dialogVisible.value = false | 
 |  |  |   currentType.value = '' | 
 |  |  |   currentAction.value = '' | 
 |  |  |   currentEditId.value = '' | 
 |  |  | }) | 
 |  |  | </script> | 
 |  |  |  | 
 |  |  | <style scoped> | 
 |  |  | .app-container { | 
 |  |  |   padding: 20px; | 
 |  |  | } | 
 |  |  |  | 
 |  |  | .tab-content { | 
 |  |  |   padding: 20px 0; | 
 |  |  | } | 
 |  |  |  | 
 |  |  | .dialog-footer { | 
 |  |  |   text-align: right; | 
 |  |  | } | 
 |  |  |  | 
 |  |  | :deep(.el-tabs__content) { | 
 |  |  |   padding: 20px; | 
 |  |  | } | 
 |  |  |  | 
 |  |  | :deep(.el-form-item) { | 
 |  |  |   margin-bottom: 20px; | 
 |  |  | } | 
 |  |  | </style> |