| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709 |
- <template>
- <div class="app-container">
- <!-- 顶部切换 -->
- <div class="tab-container">
- <el-radio-group v-model="currentTab" size="large">
- <el-radio-button value="non-cadre">非干部</el-radio-button>
- <el-radio-button value="cadre">干部</el-radio-button>
- </el-radio-group>
- </div>
- <!-- 查询条件 -->
- <div class="filter-container">
- <el-form :model="queryParams" ref="queryFormRef" :inline="true" class="search-form">
- <el-form-item label="姓名" prop="userName">
- <el-input v-model="queryParams.userName" placeholder="请输入姓名" clearable style="width: 200px" />
- </el-form-item>
- <el-form-item label="考核月份" prop="assessmentMonth">
- <el-date-picker v-model="queryParams.assessmentMonth" type="month" placeholder="请选择考核月份"
- value-format="YYYY-MM" style="width: 200px" />
- </el-form-item>
- <template v-if="currentTab === 'non-cadre'">
- <el-form-item label="岗位" prop="post">
- <el-select v-model="queryParams.post" placeholder="请选择岗位" clearable style="width: 200px">
- <el-option v-for="item in post" :key="item.value" :label="item.label" :value="item.value" />
- </el-select>
- </el-form-item>
- <el-form-item label="考核组" prop="assessmentTeam">
- <el-select v-model="queryParams.assessmentTeam" placeholder="请选择考核组" clearable style="width: 200px">
- <el-option v-for="item in assessment_team" :key="item.value" :label="item.label" :value="item.value" />
- </el-select>
- </el-form-item>
- <el-form-item label="考核结果" prop="assessmentResult">
- <el-input v-model="queryParams.assessmentResult" placeholder="请输入考核结果" clearable style="width: 200px" />
- </el-form-item>
- <el-form-item label="豁免" prop="exemption">
- <el-input v-model="queryParams.exemption" placeholder="请输入豁免" clearable style="width: 200px" />
- </el-form-item>
- </template>
- <el-form-item>
- <el-button type="primary" icon="Search" @click="handleQuery">查询</el-button>
- <el-button icon="Refresh" @click="resetQuery">重置</el-button>
- </el-form-item>
- </el-form>
- </div>
- <!-- 操作按钮 -->
- <div class="operation-container">
- <!-- 非干部操作按钮 -->
- <div v-if="currentTab === 'non-cadre'" class="left-buttons">
- <el-button type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
- <el-button type="danger" plain icon="Delete" :disabled="selectedIds.length === 0"
- @click="handleBatchDelete">删除</el-button>
- <el-button type="warning" plain icon="Download" @click="handleExport">导出</el-button>
- </div>
- <!-- 干部模式时显示空白占位 -->
- <div v-else class="left-buttons"></div>
- <div class="right-buttons">
- <el-button type="primary" :disabled="!queryParams.assessmentMonth"
- @click="generateMonthlyAssessment">生成本月考核表</el-button>
- </div>
- </div>
- <!-- 非干部数据表格 -->
- <div v-if="currentTab === 'non-cadre'">
- <el-table v-loading="loading" :data="nonCadreList" border fit highlight-current-row
- style="width: 100%; margin-top: 20px;" @selection-change="handleSelectionChange">
- <el-table-column type="selection" width="55" align="center" />
- <el-table-column label="用工形式" prop="employmentType" align="center" min-width="100">
- <template #default="scope">
- <dict-tag :options="employment_type" :value="scope.row.employmentType" />
- </template>
- </el-table-column>
- <el-table-column label="岗位" prop="post" align="center" min-width="120">
- <template #default="scope">
- <dict-tag :options="post" :value="scope.row.post" />
- </template>
- </el-table-column>
- <el-table-column label="员工姓名" prop="userName" align="center" min-width="120" />
- <el-table-column label="考核组" prop="assessmentTeam" align="center" min-width="100">
- <template #default="scope">
- <dict-tag :options="assessment_team" :value="scope.row.assessmentTeam" />
- </template>
- </el-table-column>
- <el-table-column label="分管班组长" prop="deputyTeamLeaderName" align="center" min-width="120" />
- <el-table-column label="分管主管" prop="deputySupervisorName" align="center" min-width="120" />
- <el-table-column label="分管经理" prop="deputyManagerName" align="center" min-width="120" />
- <el-table-column label="红线指标触发次数" prop="redLineIndexTriggerCount" align="center" min-width="140" />
- <el-table-column label="红线指标依据" prop="redLineIndexAccordList" align="center" min-width="120"
- show-overflow-tooltip />
- <el-table-column label="核心指标分值" prop="coreIndexScore" align="center" min-width="120" />
- <el-table-column label="核心指标依据" prop="coreIndexAccordList" align="center" min-width="120"
- show-overflow-tooltip />
- <el-table-column label="其他指标分值" prop="otherIndexScore" align="center" min-width="120" />
- <el-table-column label="其他指标依据" prop="otherIndexAccordList" align="center" min-width="120"
- show-overflow-tooltip />
- <el-table-column label="其他指标中的安全(仅含SOC/站品控检查扣分)分值" prop="otherIndexSafetyScoreWithSocStationQcDeduction"
- align="center" min-width="200" show-overflow-tooltip />
- <el-table-column label="其他指标中的安全(仅含SOC/站品控检查扣分)依据" prop="otherIndexSafetyScoreWithSocStationQcAccordList"
- align="center" min-width="200" show-overflow-tooltip />
- <el-table-column label="其他指标中的安全(不含SOC/站品控检查扣分)分值" prop="otherIndexSafetyScoreWithoutSocStationQcDeduction"
- align="center" min-width="200" show-overflow-tooltip />
- <el-table-column label="其他指标中的安全(不含SOC/站品控检查扣分)依据" prop="otherIndexSafetyScoreWithoutSocStationQcAccordList"
- align="center" min-width="200" show-overflow-tooltip />
- <el-table-column label="其他指标中的非安全指标扣分" prop="otherIndexNonSafetyDeduction" align="center" min-width="160"
- show-overflow-tooltip />
- <el-table-column label="其他指标中的非安全指标扣分依据" prop="otherIndexNonSafetyAccordList" align="center" min-width="160"
- show-overflow-tooltip />
- <el-table-column label="非核心安全+核心扣分" prop="nonCoreSafetyPlusCoreDeduction" align="center" min-width="140" />
- <el-table-column label="SOC/站品控检查的涉及核心、安全指标扣分" prop="socStationQcInvolvedCoreSafetyDeduction" align="center"
- min-width="200" show-overflow-tooltip />
- <el-table-column label="SOC/站品控检查的涉及核心、安全指标扣分依据" prop="socStationQcInvolvedCoreSafetyAccordList" align="center"
- min-width="200" show-overflow-tooltip />
- <el-table-column label="分管员工数量" prop="inChargeEmployeeCount" align="center" min-width="120" />
- <el-table-column label="扣分平均值" prop="deductionAverage" align="center" min-width="100" />
- <el-table-column label="总分" prop="totalScore" align="center" min-width="100" sortable />
- <el-table-column label="奖励明细" prop="rewardAccordList" align="center" min-width="120" show-overflow-tooltip />
- <el-table-column label="惩罚明细" prop="punishmentAccordList" align="center" min-width="120"
- show-overflow-tooltip />
- <el-table-column label="奖励(元)" prop="rewardAmount" align="center" min-width="100" />
- <el-table-column label="扣罚(元)" prop="punishmentAmount" align="center" min-width="100" />
- <el-table-column label="考核结果" prop="assessmentResult" align="center" min-width="100" />
- <el-table-column label="考核结果备注" prop="assessmentResultRemark" align="center" min-width="140"
- show-overflow-tooltip />
- <el-table-column label="应用方式" prop="applicationMethod" align="center" min-width="100" />
- <el-table-column label="应用方式备注" prop="applicationMethodRemark" align="center" min-width="140"
- show-overflow-tooltip />
- <el-table-column label="是否豁免" prop="exemption" align="center" min-width="100">
- <template #default="scope">
- {{ scope.row.exemption }}
- </template>
- </el-table-column>
- <el-table-column label="是否豁免备注" prop="exemptionReasonRemark" align="center" min-width="140"
- show-overflow-tooltip />
- <el-table-column label="考核月份" prop="assessmentMonth" align="center" min-width="120" />
- <el-table-column label="操作" align="center" width="150" fixed="right">
- <template #default="scope">
- <el-button link type="primary" icon="Edit" @click="handleEdit(scope.row, 'non-cadre')">修改</el-button>
- <el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)">删除</el-button>
- </template>
- </el-table-column>
- </el-table>
- </div>
- <!-- 干部数据表格 -->
- <div v-else>
- <el-table v-loading="loading" :data="cadreList" border fit highlight-current-row
- style="width: 100%; margin-top: 20px;" @selection-change="handleSelectionChange">
- <el-table-column type="selection" width="55" align="center" />
- <el-table-column label="姓名" prop="name" align="center" min-width="120" />
- <el-table-column label="部门" prop="deptName" align="center" min-width="120" />
- <el-table-column label="岗位" prop="post" align="center" min-width="120">
- <template #default="scope">
- <dict-tag :options="post" :value="scope.row.post" />
- </template>
- </el-table-column>
- <el-table-column label="区域" prop="area" align="center" min-width="100">
- <template #default="scope">
- <dict-tag :options="work_area" :value="scope.row.area" />
- </template>
- </el-table-column>
- <el-table-column label="红线扣分" prop="redLineDeduction" align="center" min-width="100" />
- <el-table-column label="违规排名扣分" prop="violationRankingDeduction" align="center" min-width="140" />
- <el-table-column label="技能排名扣分" prop="skillRankingDeduction" align="center" min-width="140" />
- <el-table-column label="技能排名扣分豁免情况" prop="skillExemptionStatus" align="center" min-width="180"
- show-overflow-tooltip />
- <el-table-column label="总分" prop="totalScore" align="center" min-width="100" sortable />
- <el-table-column label="考核结果" prop="assessmentResult" align="center" min-width="120" />
- <el-table-column label="考核结果备注" prop="assessmentRemark" align="center" min-width="140" show-overflow-tooltip />
- <el-table-column label="考核月份" align="center" min-width="120">
- <template #default="scope">
- {{ scope.row.year }}-{{ String(scope.row.month).padStart(2, '0') }}
- </template>
- </el-table-column>
- <el-table-column label="应用方式" prop="applicationMethod" align="center" min-width="120" />
- <el-table-column label="应用方式备注" prop="applicationRemark" align="center" min-width="160" show-overflow-tooltip />
- </el-table>
- </div>
- <!-- 分页 -->
- <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
- v-model:limit="queryParams.pageSize" @pagination="getList" />
- <!-- 编辑/新增弹窗 -->
- <el-dialog :title="dialog.title" v-model="dialog.visible" width="80%" :close-on-click-modal="false"
- destroy-on-close>
- <!-- 非干部表单 -->
- <el-form v-loading="dialog.loading" v-if="dialog.type === 'non-cadre'" :model="nonCadreForm" ref="formRef"
- :rules="nonCadreRules" label-width="380px" class="form-container">
- <!-- 第一部分:基础信息 -->
- <el-row :gutter="20">
- <el-col :span="8">
- <el-form-item label="姓名" prop="userId" label-width="100px">
- <el-select v-model="nonCadreForm.userId" placeholder="请选择姓名" style="width: 100%" clearable filterable
- @change="handleUserChange">
- <el-option v-for="user in userList" :key="user.userId" :label="user.nickName" :value="user.userId" />
- </el-select>
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item label="考核月份" prop="assessmentMonth" label-width="100px">
- <el-date-picker v-model="nonCadreForm.assessmentMonth" type="month" placeholder="请选择考核月份"
- value-format="YYYY-MM" style="width: 100%" @change="handleAssessmentMonthChange" />
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <div class="score-display">
- <span class="score-label">总分:</span>
- <span class="score-value">{{ nonCadreForm.totalScore }}</span>
- </div>
- </el-col>
- </el-row>
- <el-row :gutter="20">
- <el-col :span="8">
- <el-form-item label="用工形式" prop="employmentType" label-width="100px">
- <el-select v-model="nonCadreForm.employmentType" placeholder="请选择用工形式" style="width: 100%" disabled>
- <el-option v-for="item in employment_type" :key="item.value" :label="item.label" :value="item.value" />
- </el-select>
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item label="角色" prop="roleName" label-width="100px">
- <el-input v-model="nonCadreForm.roleName" disabled placeholder="角色" />
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item label="分管班组长" prop="deputyTeamLeaderId" label-width="100px">
- <el-select v-model="nonCadreForm.deputyTeamLeaderId" placeholder="请选择分管班组长" style="width: 100%" clearable>
- <el-option v-for="leader in teamLeaderOptions" :key="leader.userId" :label="leader.nickName"
- :value="leader.userId" />
- </el-select>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="20">
- <el-col :span="8">
- <el-form-item label="分管主管" prop="deputySupervisorId" label-width="100px">
- <el-select v-model="nonCadreForm.deputySupervisorId" placeholder="请选择分管主管" style="width: 100%" clearable>
- <el-option v-for="supervisor in supervisorOptions" :key="supervisor.userId" :label="supervisor.nickName"
- :value="supervisor.userId" />
- </el-select>
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item label="分管经理" prop="deputyManagerId" label-width="100px">
- <el-select v-model="nonCadreForm.deputyManagerId" placeholder="请选择分管经理" style="width: 100%" clearable>
- <el-option v-for="manager in managerOptions" :key="manager.userId" :label="manager.nickName"
- :value="manager.userId" />
- </el-select>
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item label="考核组" prop="assessmentTeam" label-width="100px">
- <el-select v-model="nonCadreForm.assessmentTeam" placeholder="请选择考核组" style="width: 100%">
- <el-option v-for="item in assessment_team" :key="item.value" :label="item.label" :value="item.value" />
- </el-select>
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item label="岗位" prop="post" label-width="100px">
- <el-select v-model="nonCadreForm.post" placeholder="请选择岗位" style="width: 100%">
- <el-option v-for="item in post" :key="item.value" :label="item.label" :value="item.value" />
- </el-select>
- </el-form-item>
- </el-col>
- </el-row>
- <!-- 考核指标区域 -->
- <div class="section-title blue" style="cursor: pointer;" @click="addIndicator">考核指标+</div>
- <div class="indicators-box" v-if="nonCadreForm.indicatorGroups.length > 0">
- <div v-for="(group, groupIndex) in nonCadreForm.indicatorGroups" :key="groupIndex" class="indicator-group">
- <div class="indicator-group-title">{{ group.title }}</div>
- <div v-for="(item, itemIndex) in group.items" :key="itemIndex" class="indicator-item">
- <div class="indicator-name">{{ item.indicatorName }}</div>
- <div class="indicator-value" v-if="item.categoryNameOne != '红线指标'">{{ item.score > 0 ? '+' : '' }}{{ item.score
- }}/次
- </div>
- <div class="indicator-count">{{ item.occurCount }}次</div>
- <div class="indicator-total">{{ item.scoreResult > 0 ? '+' : '' }}{{ item.scoreResult }}</div>
- <div class="indicator-actions">
- <el-button type="primary" link icon="Edit" @click="editIndicator(groupIndex, itemIndex)"></el-button>
- <el-button type="danger" link icon="Delete" @click="deleteIndicator(groupIndex, itemIndex)"></el-button>
- </div>
- </div>
- <!-- <el-button type="primary" plain icon="Plus" @click="addIndicator" style="margin-top: 10px;">添加指标</el-button> -->
- </div>
- </div>
- <!-- 第二部分:详细信息 -->
- <div style="margin-top: 30px;">
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item label="红线指标触发次数">
- <el-input v-model="nonCadreForm.redLineIndexTriggerCount" disabled placeholder="不可编辑,红线明细的次数之和" />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="红线指标依据">
- <span class="detail-link"
- @click="showDetailModal('红线指标依据', formatAccordList(nonCadreForm.redLineIndexAccordList))">
- 查看详情
- </span>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item label="核心指标分值">
- <el-input v-model="nonCadreForm.coreIndexScore" disabled placeholder="不可编辑,各个明细的集合" />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="核心指标依据">
- <span class="detail-link"
- @click="showDetailModal('核心指标依据', formatAccordList(nonCadreForm.coreIndexAccordList))">
- 查看详情
- </span>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item label="其他指标中的安全指标(仅含SOC/站品控检查扣分)分值">
- <el-input v-model="nonCadreForm.otherIndexSafetyScoreWithSocStationQcDeduction" disabled
- placeholder="不可编辑,各个明细的集合" />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="其他指标中的安全指标(仅含SOC/站品控检查扣分)依据">
- <span class="detail-link"
- @click="showDetailModal('其他指标中的安全指标依据', formatAccordList(nonCadreForm.otherIndexSafetyScoreWithSocStationQcAccordList))">
- 查看详情
- </span>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item label="其他指标中的非安全指标分值">
- <el-input v-model="nonCadreForm.otherIndexNonSafetyDeduction" disabled placeholder="不可编辑,各个明细的集合" />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="其他指标中的非安全指标依据">
- <span class="detail-link"
- @click="showDetailModal('其他指标中的非安全指标依据', formatAccordList(nonCadreForm.otherIndexNonSafetyAccordList))">
- 查看详情
- </span>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item label="SOC/站品控检查的涉及核心、安全指标扣分">
- <el-input v-model="nonCadreForm.socStationQcInvolvedCoreSafetyDeduction" disabled
- placeholder="不可编辑,各个明细的集合" />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="SOC/站品控检查的涉及核心、安全指标扣分依据">
- <span class="detail-link"
- @click="showDetailModal('SOC/站品控检查的涉及核心、安全指标扣分依据', formatAccordList(nonCadreForm.socStationQcInvolvedCoreSafetyAccordList))">
- 查看详情
- </span>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item label="非核心安全+核心扣分">
- <el-input v-model="nonCadreForm.nonCoreSafetyPlusCoreDeduction" disabled placeholder="不可编辑,各个明细的集合" />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="分管员工数量" prop="inChargeEmployeeCount">
- <el-input-number v-model="nonCadreForm.inChargeEmployeeCount" :min="0" style="width: 100%" />
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item label="扣分平均值">
- <el-input v-model="nonCadreForm.deductionAverage" disabled placeholder="不可编辑,计算" />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="总分">
- <el-input v-model="nonCadreForm.totalScore" disabled placeholder="不可编辑" />
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item label="奖励明细">
- <span class="detail-link"
- @click="showDetailModal('奖励明细', formatAccordList(nonCadreForm.rewardAccordList))">
- 查看详情
- </span>
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="惩罚明细">
- <span class="detail-link"
- @click="showDetailModal('惩罚明细', formatAccordList(nonCadreForm.punishmentAccordList))">
- 查看详情
- </span>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item label="奖励汇总" prop="rewardAmount">
- <div class="input-with-unit">
- <el-input-number v-model="nonCadreForm.rewardAmount" :min="0" :precision="2" disabled
- style="width: calc(100% - 40px)" />
- <span class="unit">元</span>
- </div>
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="扣罚汇总" prop="penaltyAmount">
- <div class="input-with-unit">
- <el-input-number v-model="nonCadreForm.penaltyAmount" :min="0" :precision="2" disabled
- style="width: calc(100% - 40px)" />
- <span class="unit">元</span>
- </div>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item label="是否豁免" prop="exemption">
- <el-input v-model="nonCadreForm.exemption" placeholder="请输入是否豁免" disabled />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="豁免备注" prop="exemptionReasonRemark">
- <el-input v-model="nonCadreForm.exemptionReasonRemark" type="textarea" :rows="1" placeholder="请输入豁免备注"
- disabled />
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item label="考核结果" prop="assessmentResult" disabled>
- <el-input v-model="nonCadreForm.assessmentResult" placeholder="请输入考核结果" disabled />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="考核结果备注" prop="assessmentResultRemark">
- <el-input v-model="nonCadreForm.assessmentResultRemark" type="textarea" :rows="1"
- placeholder="请输入考核结果备注" disabled />
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item label="应用方式" prop="applicationMethod">
- <el-input v-model="nonCadreForm.applicationMethod" placeholder="请输入应用方式" disabled />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="应用备注" prop="applicationMethodRemark">
- <el-input v-model="nonCadreForm.applicationMethodRemark" type="textarea" :rows="1" disabled
- placeholder="请输入应用备注" />
- </el-form-item>
- </el-col>
- </el-row>
- </div>
- </el-form>
- <template #footer>
- <div class="dialog-footer">
- <el-button @click="dialog.visible = false">取消</el-button>
- <el-button type="primary" @click="submitForm">确定</el-button>
- </div>
- </template>
- </el-dialog>
- <!-- 第二个模态框:添加/编辑扣分指标 -->
- <el-dialog :title="indicatorDialog.title" v-model="indicatorDialog.visible" width="60%">
- <el-form label-width="150px" class="indicator-form" :model="indicatorDialog.form" :rules="indicatorDialog.rules">
- <el-form-item label="指标名称" prop="indicatorId" required>
- <el-cascader v-model="indicatorDialog.form.indicatorId" placeholder="搜索指标名称" filterable clearable
- :options="indicatorDialog.cascaderOptions" :props="indicatorDialog.cascaderProps" style="flex: 1;"
- @change="onIndicatorCascaderChange">
- </el-cascader>
- </el-form-item>
- <el-form-item label="分值/单位" v-if="indicatorDialog.form.categoryNameOne != '红线指标'">
- <div style="display: flex; align-items: center; gap: 10px;">
- <span style="font-size: 24px; font-weight: bold;">{{ indicatorDialog.form.score > 0 ? '+' : '' }}{{
- indicatorDialog.form.score }}/次</span>
- </div>
- </el-form-item>
- <el-form-item label="发生次数">
- <div style="display: flex; align-items: center; gap: 10px;">
- <el-input-number v-model="indicatorDialog.form.occurCount" :min="1" style="width: 200px;"
- @change="updateTotal" />
- </div>
- </el-form-item>
- <template
- v-for="(detail, index) in (indicatorDialog.form.personnelMonthlyAssessmentIndicatorRewardPunishmentDetailList || [])"
- :key="index">
- <div style="display: flex; align-items: center; gap: 10px; margin-bottom: 10px;">
- <h4 style="margin-left: 80px;">明细{{ index + 1 }}</h4>
- <el-button type="danger" size="small" @click="removeRewardPunishmentDetail(index)">删除</el-button>
- </div>
- <el-form-item label="检查部门">
- <div style="display: flex; align-items: center; gap: 10px; width: 100%;">
- <el-select v-model="detail.qcDeptType" placeholder="请选择" style="width: 200px;">
- <el-option v-for="item in base_performance_indicator_qc_dept_type" :key="item.value" :label="item.label"
- :value="item.value" />
- </el-select>
- </div>
- </el-form-item>
- <el-form-item v-if="indicatorDialog.form.score > 0" label="奖励明细">
- <el-input v-model="detail.rewardPunishmentDetail" type="textarea" :rows="2" />
- </el-form-item>
- <el-form-item v-if="indicatorDialog.form.score > 0" label="奖励">
- <div style="display: flex; align-items: center; gap: 10px;">
- <el-input-number v-model="detail.amount" :min="0" :precision="2" style="width: 200px;"
- @change="updateTotal" />
- <span>元</span>
- </div>
- </el-form-item>
- <el-form-item v-if="indicatorDialog.form.score < 0" label="惩罚明细">
- <el-input v-model="detail.rewardPunishmentDetail" type="textarea" :rows="2" />
- </el-form-item>
- <el-form-item v-if="indicatorDialog.form.score < 0" label="扣罚">
- <div style="display: flex; align-items: center; gap: 10px;">
- <el-input-number v-model="detail.amount" :min="0" :precision="2" style="width: 200px;"
- @change="updateTotal" />
- <span>元</span>
- </div>
- </el-form-item>
- </template>
- </el-form>
- <template #footer>
- <div class="dialog-footer">
- <el-button @click="indicatorDialog.visible = false">取消</el-button>
- <el-button type="primary" @click="saveIndicator">确定</el-button>
- </div>
- </template>
- </el-dialog>
- <!-- 详情模态框 -->
- <el-dialog :title="detailModal.title" v-model="detailModal.visible" width="60%">
- <div class="detail-content">
- {{ detailModal?.content || '暂无内容' }}
- </div>
- <template #footer>
- <div class="dialog-footer">
- <el-button @click="detailModal.visible = false">关闭</el-button>
- </div>
- </template>
- </el-dialog>
- </div>
- </template>
- <script setup>
- import { ref, reactive, onMounted, getCurrentInstance, watch, nextTick } from 'vue'
- import { ElMessage, ElMessageBox } from 'element-plus'
- // API导入(需要根据实际API路径调整)
- import { listCadreAssessment, generateCadreAssessment, listNonCadreAssessment, addNonCadreAssessment, updateNonCadreAssessment, deleteNonCadreAssessment, exportNonCadreAssessment, generateNonCadreAssessment, getNonCadreAssessment, deleteCadreAssessment } from '@/api/performance/monthlyAssess.js'
- import { selectUserLeaderListByCondition, listUserPerformance } from '@/api/system/user.js'
- import { listIndicator } from '@/api/system/classificationAssess.js'
- import { queryAssessCategoryTreeAndIndicator } from '@/api/system/classificationAssessIndicator.js'
- const { proxy } = getCurrentInstance()
- const { post, work_area, employment_type, assessment_team, base_performance_indicator_qc_dept_type } = proxy.useDict('post', 'work_area', 'employment_type', 'assessment_team', 'base_performance_indicator_qc_dept_type')
- // 响应式数据
- const loading = ref(false)
- const total = ref(0)
- const queryFormRef = ref()
- const formRef = ref()
- const currentTab = ref('non-cadre')
- const selectedIds = ref([])
- // 监听tab切换
- watch(() => currentTab.value, () => {
- getList()
- })
- // 查询参数
- const queryParams = reactive({
- pageNum: 1,
- pageSize: 10,
- userName: '',
- assessmentMonth: '',
- post: '',
- assessmentTeam: '',
- assessmentResult: '',
- exemption: ''
- })
- const currentMonthDefault = `${new Date().getFullYear()}-${String(new Date().getMonth() + 1).padStart(2, '0')}`
- const getEmptyNonCadreForm = () => ({
- id: '',
- userId: '',
- userName: '',
- roleKey: '',
- roleId: '',
- roleName: '',
- employmentType: '',
- post: '',
- assessmentMonth: currentMonthDefault,
- assessmentTeam: '',
- deputyTeamLeaderId: '',
- deputyTeamLeaderName: '',
- deputySupervisorId: '',
- deputySupervisorName: '',
- deputyManagerId: '',
- deputyManagerName: '',
- inChargeEmployeeCount: 0,
- totalScore: 0,
- assessmentResult: '',
- applicationMethod: '',
- exemption: '',
- exemptionReasonRemark: '',
- rewardAmount: 0,
- penaltyAmount: 0,
- punishmentAmount: 0,
- assessmentRemark: '',
- applicationMethodRemark: '',
- indicatorGroups: [],
- redLineTriggerCount: '',
- coreIndicatorScore: '',
- safetyWithSocScore: '',
- nonSafetyIndicatorScore: '',
- socSafetyCoreDeduction: '',
- nonCoreSafetyCoreDeduction: '',
- deductionAverage: '',
- rewardDetailsSummary: '',
- penaltyDetailsSummary: '',
- redLineIndexAccordList: [],
- coreIndexAccordList: [],
- otherIndexSafetyScoreWithSocStationQcAccordList: [],
- otherIndexNonSafetyAccordList: [],
- socStationQcInvolvedCoreSafetyAccordList: [],
- rewardAccordList: [],
- punishmentAccordList: []
- })
- const nonCadreForm = reactive(getEmptyNonCadreForm())
- watch(() => nonCadreForm.assessmentMonth, (newVal) => {
- if (newVal) {
- const month = newVal.replace('-', '')
- loadUserList(month)
- }
- })
- watch(() => nonCadreForm.deputyTeamLeaderId, (newVal) => {
- if (newVal) {
- const leader = teamLeaderOptions.value.find(u => u.userId === newVal)
- nonCadreForm.deputyTeamLeaderName = leader?.nickName || ''
- } else {
- nonCadreForm.deputyTeamLeaderName = ''
- }
- })
- watch(() => nonCadreForm.deputySupervisorId, (newVal) => {
- if (newVal) {
- const supervisor = supervisorOptions.value.find(u => u.userId === newVal)
- nonCadreForm.deputySupervisorName = supervisor?.nickName || ''
- } else {
- nonCadreForm.deputySupervisorName = ''
- }
- })
- watch(() => nonCadreForm.deputyManagerId, (newVal) => {
- if (newVal) {
- const manager = managerOptions.value.find(u => u.userId === newVal)
- nonCadreForm.deputyManagerName = manager?.nickName || ''
- } else {
- nonCadreForm.deputyManagerName = ''
- }
- })
- function addIndicatorToGroup(item) {
- const categoryName = item.categoryNameOne || '未分类'
- let group = nonCadreForm.indicatorGroups.length == 0 ? null : nonCadreForm.indicatorGroups.find(g => g.title === categoryName);
- if (!group) {
- group = {
- title: categoryName,
- items: []
- }
- nonCadreForm.indicatorGroups.push(group)
- }
- group.items.push(item)
- }
- // 第二个模态框状态
- const indicatorDialog = reactive({
- visible: false,
- title: '',
- mode: 'add',
- groupIndex: null,
- itemIndex: null,
- loading: false,
- indicatorOptions: [],
- cascaderOptions: [],
- cascaderProps: {
- value: 'id',
- label: 'name',
- children: 'indicatorList',
- checkStrictly: false,
- emitPath: false
- },
- rules: {
- indicatorId: [
- { required: true, message: '请选择指标名称', trigger: 'change' }
- ]
- },
- form: {
- indicatorId: '',
- name: '',
- score: 0,
- occurCount: 1,
- qcDeptType: '',
- scoreResult: 0,
- amountResult: 0,
- rewardDetails: '',
- reward: 0,
- penaltyDetails: '',
- penalty: 0,
- rewardPunishmentType: '',
- personnelMonthlyAssessmentIndicatorRewardPunishmentDetailList: []
- }
- })
- async function searchIndicators(query) {
- if (!query) {
- indicatorDialog.indicatorOptions = []
- return
- }
- indicatorDialog.loading = true
- try {
- const res = await listIndicator({ name: query })
- indicatorDialog.indicatorOptions = res.rows || []
- } catch (error) {
- console.error('搜索指标失败:', error)
- indicatorDialog.indicatorOptions = []
- } finally {
- indicatorDialog.loading = false
- }
- }
- async function loadIndicatorCascaderOptions() {
- try {
- const res = await queryAssessCategoryTreeAndIndicator({})
- const treeData = res.data || []
- indicatorDialog.cascaderOptions = transformIndicatorTree(treeData)
- } catch (error) {
- console.error('加载指标树失败:', error)
- indicatorDialog.cascaderOptions = []
- }
- }
- function transformIndicatorTree(treeData) {
- return treeData.map(node => {
- const transformed = {
- id: node.id,
- name: node.name,
- indicatorList: []
- }
- if (node.children && node.children.length > 0) {
- transformed.indicatorList = node.children.map(child => {
- const transformedChild = {
- id: child.id,
- name: child.name,
- indicatorList: []
- }
- if (child.indicatorList && child.indicatorList.length > 0) {
- transformedChild.indicatorList = child.indicatorList.map(indicator => ({
- ...indicator, name: indicator.name, id: indicator.id, indicatorId: indicator.id, indicatorName: indicator.name, occurCount: 1, personnelMonthlyAssessmentIndicatorRewardPunishmentDetailList: []
- }))
- }
- return transformedChild
- })
- }
- if (node.indicatorList && node.indicatorList.length > 0) {
- transformed.indicatorList = node.indicatorList.map(indicator => ({
- ...indicator, name: indicator.name, id: indicator.id, indicatorId: indicator.id, indicatorName: indicator.name, occurCount: 1, personnelMonthlyAssessmentIndicatorRewardPunishmentDetailList: []
- }))
- }
- return transformed
- })
- }
- function onIndicatorCascaderChange(value) {
- const selected = findIndicatorById(indicatorDialog.cascaderOptions, value)
- if (selected) {
- indicatorDialog.form = {
- ...selected,
- name: selected.name,
- id: selected.id,
- indicatorId: selected.id,
- indicatorName: selected.name,
- occurCount: 1,
- personnelMonthlyAssessmentIndicatorRewardPunishmentDetailList: []
- }
- updateTotal()
- }
- }
- function findIndicatorById(tree, targetId) {
- for (const node of tree) {
- if (node.id === targetId) {
- return node
- }
- if (node.indicatorList && node.indicatorList.length > 0) {
- const found = findIndicatorById(node.indicatorList, targetId)
- if (found) return found
- }
- }
- return null
- }
- // 弹窗配置
- const dialog = reactive({
- visible: false,
- title: '',
- type: 'non-cadre',
- loading: false
- })
- // 详情模态框
- const detailModal = reactive({
- visible: false,
- title: '',
- content: ''
- })
- // 显示详情模态框
- const showDetailModal = (title, content) => {
- detailModal.title = title
- detailModal.content = content
- detailModal.visible = true
- }
- const formatAccordList = (list) => {
- if (!list || !Array.isArray(list) || list.length === 0) return ''
- return list.map(item => {
- const name = item.indicatorName || item.name || ''
- const score = item.score !== undefined ? item.score : ''
- const count = item.occurCount !== undefined ? item.occurCount : ''
- return `${name} ${score}分 x ${count}次`
- }).join('\n')
- }
- // 数据列表
- const nonCadreList = ref([])
- const cadreList = ref([])
- const userList = ref([])
- const teamLeaderOptions = ref([])
- const supervisorOptions = ref([])
- const managerOptions = ref([])
- // 非干部表单验证规则
- const nonCadreRules = {
- userId: [{ required: true, message: '姓名不能为空', trigger: 'change' }]
- }
- async function loadUserList(month) {
- dialog.loading = true
- try {
- const res = await listUserPerformance({ month })
- userList.value = res.data || []
- } catch (error) {
- console.error('获取员工列表失败:', error)
- } finally {
- dialog.loading = false
- }
- }
- async function loadTeamLeaderOptions(userId) {
- try {
- const res = await selectUserLeaderListByCondition({ roleKeyList: ['banzuzhang'], userId })
- teamLeaderOptions.value = res.data || []
- } catch (error) {
- console.error('获取班组长列表失败:', error)
- }
- }
- async function loadSupervisorOptions(userId) {
- try {
- const res = await selectUserLeaderListByCondition({ roleKeyList: ['kezhang'], userId })
- supervisorOptions.value = res.data || []
- } catch (error) {
- console.error('获取主管列表失败:', error)
- }
- }
- async function loadManagerOptions(userId) {
- try {
- const res = await selectUserLeaderListByCondition({ roleKeyList: ['jingli'], userId })
- managerOptions.value = res.data || []
- } catch (error) {
- console.error('获取经理列表失败:', error)
- }
- }
- async function handleUserChange(userId) {
- if (!userId) {
- teamLeaderOptions.value = []
- supervisorOptions.value = []
- managerOptions.value = []
- nonCadreForm.deputyTeamLeaderId = ''
- nonCadreForm.deputyTeamLeaderName = ''
- nonCadreForm.deputySupervisorId = ''
- nonCadreForm.deputySupervisorName = ''
- nonCadreForm.deputyManagerId = ''
- nonCadreForm.deputyManagerName = ''
- checkAndLoadExistingAssessment()
- return
- }
- const user = userList.value.find(u => u.userId === userId)
- if (user && user.nickName) {
- await Promise.all([
- loadTeamLeaderOptions(user.userId),
- loadSupervisorOptions(user.userId),
- loadManagerOptions(user.userId)
- ])
- const role = user.roles && user.roles[0] || {}
- nonCadreForm.userName = user.nickName
- nonCadreForm.roleName = role?.roleName
- nonCadreForm.roleKey = role?.roleKey
- nonCadreForm.roleId = role?.roleId
- nonCadreForm.employmentType = user.employmentType
- nonCadreForm.post = user.post
- nonCadreForm.assessmentTeam = user.assessmentTeam
- nonCadreForm.assessmentTeamDesc = user.assessmentTeamDesc
- nonCadreForm.deputyTeamLeaderId = ''
- nonCadreForm.deputyTeamLeaderName = ''
- nonCadreForm.deputySupervisorId = ''
- nonCadreForm.deputySupervisorName = ''
- nonCadreForm.deputyManagerId = ''
- nonCadreForm.deputyManagerName = ''
- }
- checkAndLoadExistingAssessment()
- }
- async function handleAssessmentMonthChange() {
- checkAndLoadExistingAssessment()
- }
- async function checkAndLoadExistingAssessment() {
- if (!nonCadreForm.userId || !nonCadreForm.assessmentMonth) {
- return
- }
- try {
- const assessmentMonth = nonCadreForm.assessmentMonth.replace('-', '')
- const res = await listNonCadreAssessment({
- userId: nonCadreForm.userId,
- assessmentMonth: assessmentMonth
- })
- const rows = res.rows || []
- if (rows.length > 0) {
- const assessmentId = rows[0].id
- await loadAssessmentDetail(assessmentId)
- }
- } catch (error) {
- console.error('检查已有考核数据失败:', error)
- }
- }
- async function loadAssessmentDetail(id) {
- try {
- const res = await getNonCadreAssessment(id)
- const detailList = res.data.personnelMonthlyAssessmentIndicatorDetailList || []
- const indicatorGroupsMap = {}
- detailList.forEach(item => {
- const categoryKey = item.categoryCodeOne || item.categoryNameOne || '未分类'
- if (!indicatorGroupsMap[categoryKey]) {
- indicatorGroupsMap[categoryKey] = {
- title: item.categoryNameOne || '未分类',
- items: []
- }
- }
- indicatorGroupsMap[categoryKey].items.push({
- ...item
- })
- })
- const indicatorGroups = Object.values(indicatorGroupsMap)
- Object.keys(res.data).forEach(key => {
- if (key === 'assessmentMonth' && res.data[key]) {
- const val = res.data[key]
- if (typeof val === 'string' && val.length === 6 && /^\d+$/.test(val)) {
- nonCadreForm[key] = val.substring(0, 4) + '-' + val.substring(4, 6)
- } else {
- nonCadreForm[key] = val
- }
- } else if (key !== 'personnelMonthlyAssessmentIndicatorDetailList') {
- nonCadreForm[key] = res.data[key]
- }
- })
- nonCadreForm.indicatorGroups = indicatorGroups
- calculateRewardPenaltyTotal()
- } catch (error) {
- console.error('获取考核详情失败:', error)
- ElMessage.error('获取考核详情失败')
- }
- }
- // 获取数据列表
- const getList = async () => {
- loading.value = true
- try {
- // 将 assessmentMonth 拆分为 year 和 month
- let params = { ...queryParams }
- let params1 = { ...queryParams }
- if (params.assessmentMonth) {
- const [year, month] = params.assessmentMonth.split('-')
- params.year = parseInt(year)
- params.month = parseInt(month)
- delete params.assessmentMonth
- }
- if (params1.assessmentMonth) {
- const [year, month] = params1.assessmentMonth.split('-')
- params1.assessmentMonth = `${year}${month}`
- }
- if (currentTab.value === 'non-cadre') {
- const res = await listNonCadreAssessment(params1)
- nonCadreList.value = res.rows || []
- total.value = res.total || 0
- } else {
- // 干部数据API
- const res = await listCadreAssessment(params)
- cadreList.value = res.rows || []
- total.value = res.total || 0
- }
- } catch (error) {
- console.error('获取数据失败:', error)
- ElMessage.error('获取数据失败')
- } finally {
- loading.value = false
- }
- }
- // 查询
- const handleQuery = () => {
- queryParams.pageNum = 1
- getList()
- }
- // 重置查询
- const resetQuery = () => {
- queryFormRef.value?.resetFields()
- queryParams.pageNum = 1
- getList()
- }
- // 批量选择
- const handleSelectionChange = (selection) => {
- selectedIds.value = selection.map(item => item.id)
- }
- // 批量删除
- const handleBatchDelete = () => {
- if (selectedIds.value.length === 0) {
- return
- }
- proxy.$modal.confirm(`是否确认删除选中的 ${selectedIds.value.length} 条数据?`).then(async () => {
- try {
- if (currentTab.value === 'non-cadre') {
- await deleteNonCadreAssessment(selectedIds.value.join(','))
- } else {
- await deleteCadreAssessment(selectedIds.value.join(','))
- }
- ElMessage.success('删除成功')
- selectedIds.value = []
- getList()
- } catch (error) {
- console.error('删除失败:', error)
- }
- }).catch(() => { })
- }
- // 新增
- const handleAdd = () => {
- dialog.visible = true
- dialog.type = currentTab.value
- dialog.title = currentTab.value === 'non-cadre' ? '新增非干部月度考核' : '新增干部月度考核'
- if (currentTab.value === 'non-cadre') {
- const emptyForm = getEmptyNonCadreForm()
- Object.keys(emptyForm).forEach(key => {
- nonCadreForm[key] = emptyForm[key]
- })
- const month = nonCadreForm.assessmentMonth.replace('-', '')
- loadUserList(month)
- teamLeaderOptions.value = []
- supervisorOptions.value = []
- managerOptions.value = []
- }
- }
- // 编辑
- const handleEdit = async (row, type) => {
- dialog.visible = true
- dialog.type = type
- dialog.title = '编辑非干部月度考核'
- if (type === 'non-cadre') {
- const month = nonCadreForm.assessmentMonth.replace('-', '')
- loadUserList(month)
- loadTeamLeaderOptions(row.userId)
- loadSupervisorOptions(row.userId)
- loadManagerOptions(row.userId)
- try {
- const res = await getNonCadreAssessment(row.id)
- const detailList = res.data.personnelMonthlyAssessmentIndicatorDetailList || []
- const indicatorGroupsMap = {}
- detailList.forEach(item => {
- const categoryKey = item.categoryCodeOne || item.categoryNameOne || '未分类'
- if (!indicatorGroupsMap[categoryKey]) {
- indicatorGroupsMap[categoryKey] = {
- title: item.categoryNameOne || '未分类',
- items: []
- }
- }
- indicatorGroupsMap[categoryKey].items.push({
- ...item
- })
- })
- const indicatorGroups = Object.values(indicatorGroupsMap)
- Object.keys(res.data).forEach(key => {
- if (key === 'assessmentMonth' && res.data[key]) {
- const val = res.data[key]
- if (typeof val === 'string' && val.length === 6 && /^\d+$/.test(val)) {
- nonCadreForm[key] = val.substring(0, 4) + '-' + val.substring(4, 6)
- } else {
- nonCadreForm[key] = val
- }
- } else if (key !== 'personnelMonthlyAssessmentIndicatorDetailList') {
- nonCadreForm[key] = res.data[key]
- }
- })
- nonCadreForm.indicatorGroups = indicatorGroups
- } catch (error) {
- console.error('获取详情失败:', error)
- ElMessage.error('获取详情失败')
- }
- }
- }
- // 删除
- const handleDelete = async (row) => {
- try {
- await ElMessageBox.confirm('确认删除该考核记录吗?', '提示', {
- confirmButtonText: '确定',
- cancelButtonText: '取消',
- type: 'warning'
- })
- await deleteNonCadreAssessment(row.id)
- ElMessage.success('删除成功')
- getList()
- } catch (error) {
- if (error !== 'cancel') {
- ElMessage.error('删除失败')
- }
- }
- }
- // 提交表单
- const submitForm = async () => {
- const valid = await formRef.value?.validate()
- if (!valid) return
- try {
- if (dialog.type === 'non-cadre') {
- const submitData = { ...nonCadreForm }
- if (submitData.assessmentMonth) {
- submitData.assessmentMonth = submitData.assessmentMonth.replace('-', '')
- }
- if (submitData.indicatorGroups && submitData.indicatorGroups.length > 0) {
- submitData.personnelMonthlyAssessmentIndicatorDetailList = submitData.indicatorGroups.flatMap(group =>
- group.items.map(item => ({
- ...item,
- indicatorName: item.name || item.indicatorName,
- indicatorId: item.id || item.indicatorId,
- indicatorCode: item.code || item.indicatorCode,
- }))
- )
- delete submitData.indicatorGroups
- }
- if (dialog.title === '新增非干部月度考核') {
- await addNonCadreAssessment(submitData)
- ElMessage.success('新增成功')
- } else {
- await updateNonCadreAssessment(submitData)
- ElMessage.success('更新成功')
- }
- } else {
- ElMessage.success('操作成功')
- }
- dialog.visible = false
- getList()
- } catch (error) {
- ElMessage.error('操作失败')
- }
- }
- // 导出
- const handleExport = async () => {
- try {
- let params = { ...queryParams }
- if (params.assessmentMonth) {
- const [year, month] = params.assessmentMonth.split('-')
- params.year = parseInt(year)
- params.month = parseInt(month)
- delete params.assessmentMonth
- }
- Object.keys(params).forEach(key => {
- if (params[key] === null || params[key] === undefined || params[key] === '') {
- delete params[key]
- }
- })
- proxy.download('personnel/assessment/export', params, `非干部月度考核_${new Date().getTime()}.xlsx`)
- } catch (error) {
- ElMessage.error('导出失败')
- }
- }
- // 生成本月考核表
- const generateMonthlyAssessment = async () => {
- try {
- const tabText = currentTab.value === 'non-cadre' ? '非干部' : '干部'
- ElMessageBox.confirm(`是否生成${queryParams.assessmentMonth}考核数据?`, '提示', {
- confirmButtonText: '确定',
- cancelButtonText: '取消',
- type: 'warning'
- }).then(async () => {
- loading.value = true
- const queryMonth = queryParams.assessmentMonth.replace('-', '')
- const queryYear = parseInt(queryMonth.substring(0, 4))
- const queryMonthNum = parseInt(queryMonth.substring(4, 6))
- if (currentTab.value === 'non-cadre') {
- const res = await generateNonCadreAssessment({ month: queryMonth })
- ElMessage.success('生成成功')
- } else {
- const params = {
- year: queryYear,
- month: queryMonthNum
- }
- const res = await generateCadreAssessment(params)
- ElMessage.success('生成成功')
- }
- getList()
- }).catch(() => { })
- } catch (error) {
- console.error('生成失败:', error)
- ElMessage.error('生成失败')
- } finally {
- loading.value = false
- }
- }
- // 获取考核结果文本
- const getResultText = (value) => {
- const map = {
- 'excellent': '优秀',
- 'good': '良好',
- 'qualified': '合格',
- 'unqualified': '不称职'
- }
- return map[value] || ''
- }
- // 添加指标 - 打开新增模态框
- const addIndicator = () => {
- indicatorDialog.visible = true
- indicatorDialog.title = '添加扣分指标'
- indicatorDialog.mode = 'add'
- indicatorDialog.groupIndex = null
- indicatorDialog.itemIndex = null
- indicatorDialog.form = {
- name: '',
- score: 0,
- occurCount: 1,
- qcDeptType: '',
- scoreResult: 0,
- amountResult: 0,
- rewardPunishmentDetail: '',
- amount: 0,
- personnelMonthlyAssessmentIndicatorRewardPunishmentDetailList: []
- }
- loadIndicatorCascaderOptions()
- }
- // 编辑指标 - 打开编辑模态框
- const editIndicator = async (groupIndex, itemIndex) => {
- const item = nonCadreForm.indicatorGroups[groupIndex].items[itemIndex]
- indicatorDialog.visible = true
- indicatorDialog.title = '编辑扣分指标'
- indicatorDialog.mode = 'edit'
- indicatorDialog.groupIndex = groupIndex
- indicatorDialog.itemIndex = itemIndex
- await loadIndicatorCascaderOptions()
- await nextTick()
- indicatorDialog.form = { ...item }
- if (!indicatorDialog.form.personnelMonthlyAssessmentIndicatorRewardPunishmentDetailList) {
- indicatorDialog.form.personnelMonthlyAssessmentIndicatorRewardPunishmentDetailList = []
- }
- }
- // 删除指标
- const deleteIndicator = (groupIndex, itemIndex) => {
- ElMessageBox.confirm('确认删除该指标吗?', '提示', {
- confirmButtonText: '确定',
- cancelButtonText: '取消',
- type: 'warning'
- }).then(() => {
- nonCadreForm.indicatorGroups[groupIndex].items.splice(itemIndex, 1)
- calculateRewardPenaltyTotal()
- ElMessage.success('删除成功')
- }).catch(() => { })
- }
- // 指标名称变化时更新分值
- const onIndicatorNameChange = (value) => {
- console.log(value, indicatorDialog.indicatorOptions, "indicatorDialog.indicatorOptions")
- const selected = indicatorDialog.indicatorOptions.find(item => item.id === value)
- if (selected) {
- indicatorDialog.form = { ...selected, indicatorId: selected.id, indicatorName: selected.name, occurCount: 1, personnelMonthlyAssessmentIndicatorRewardPunishmentDetailList: [] }
- updateTotal()
- }
- }
- // 更新总分
- const updateTotal = () => {
- indicatorDialog.form.scoreResult = indicatorDialog.form.score * indicatorDialog.form.occurCount
- const list = indicatorDialog.form.personnelMonthlyAssessmentIndicatorRewardPunishmentDetailList
- if (!list) {
- indicatorDialog.form.personnelMonthlyAssessmentIndicatorRewardPunishmentDetailList = []
- indicatorDialog.form.amountResult = 0
- return
- }
- const targetCount = indicatorDialog.form.occurCount
- if (list.length < targetCount) {
- for (let i = list.length; i < targetCount; i++) {
- list.push({
- qcDeptType: '',
- rewardPunishmentDetail: '',
- amount: 0
- })
- }
- }
- indicatorDialog.form.amountResult = list.reduce((sum, item) => sum + (Number(item.amount) || 0), 0)
- }
- // 保存指标
- const saveIndicator = () => {
- if (!indicatorDialog.form.indicatorId) {
- ElMessage.error('请选择指标名称')
- return
- }
- const list = indicatorDialog.form.personnelMonthlyAssessmentIndicatorRewardPunishmentDetailList || []
- if (list.length !== indicatorDialog.form.occurCount) {
- ElMessage.error(`发生次数为 ${indicatorDialog.form.occurCount},但明细数量为 ${list.length},请删除多余的明细`)
- return
- }
- list.forEach(detail => {
- detail.rewardPunishmentType = indicatorDialog.form.rewardPunishmentType;
- detail.score = indicatorDialog.form.score
- })
- if (indicatorDialog.mode === 'add') {
- addIndicatorToGroup({ ...indicatorDialog.form })
- ElMessage.success('添加成功')
- } else {
- if (indicatorDialog.groupIndex !== null && indicatorDialog.itemIndex !== null) {
- Object.assign(nonCadreForm.indicatorGroups[indicatorDialog.groupIndex].items[indicatorDialog.itemIndex], indicatorDialog.form)
- ElMessage.success('修改成功')
- }
- }
- indicatorDialog.visible = false
- calculateRewardPenaltyTotal()
- }
- // 计算奖励和扣罚汇总
- const calculateRewardPenaltyTotal = () => {
- let rewardTotal = 0
- let penaltyTotal = 0
- if (!nonCadreForm.indicatorGroups) {
- nonCadreForm.rewardAmount = 0
- nonCadreForm.penaltyAmount = 0
- return
- }
- nonCadreForm.indicatorGroups.forEach(group => {
- if (group.items && Array.isArray(group.items)) {
- group.items.forEach(item => {
- const detailList = item.personnelMonthlyAssessmentIndicatorRewardPunishmentDetailList || []
- detailList.forEach(detail => {
- if (detail.rewardPunishmentType === 'PUNISHMENT') {
- penaltyTotal += Number(detail.amount) || 0
- } else {
- rewardTotal += Number(detail.amount) || 0
- }
- })
- })
- }
- })
- nonCadreForm.rewardAmount = rewardTotal
- nonCadreForm.penaltyAmount = penaltyTotal
- }
- // 删除奖励/惩罚明细
- const removeRewardPunishmentDetail = (index) => {
- indicatorDialog.form.personnelMonthlyAssessmentIndicatorRewardPunishmentDetailList.splice(index, 1)
- updateTotal()
- }
- // 监听Tab切换
- const handleTabChange = () => {
- queryParams.pageNum = 1
- getList()
- }
- onMounted(() => {
- getList()
- })
- </script>
- <style lang="less" scoped>
- .app-container {
- padding: 20px;
- }
- .tab-container {
- margin-bottom: 20px;
- text-align: left;
- }
- .filter-container {
- // margin-bottom: 20px;
- }
- .search-form {
- display: flex;
- flex-wrap: wrap;
- gap: 10px;
- }
- .operation-container {
- margin-bottom: 20px;
- display: flex;
- justify-content: space-between;
- align-items: center;
- }
- .left-buttons {
- display: flex;
- gap: 10px;
- }
- .right-buttons {
- display: flex;
- gap: 10px;
- }
- .form-container {
- max-height: 70vh;
- overflow-y: auto;
- padding-right: 10px;
- }
- .el-divider {
- margin: 20px 0;
- }
- :deep(.el-form-item__label) {
- font-weight: 500;
- }
- /* 新增样式 */
- .score-display {
- display: flex;
- align-items: center;
- gap: 10px;
- height: 32px;
- line-height: 32px;
- padding: 0 10px;
- justify-content: center;
- }
- .score-label,
- .result-label {
- font-weight: bold;
- font-size: 16px;
- }
- .score-value {
- font-size: 20px;
- font-weight: bold;
- }
- .result-value {
- font-size: 20px;
- font-weight: bold;
- }
- .text-danger {
- color: #f56c6c;
- }
- .section-title {
- font-size: 22px;
- font-weight: bold;
- margin: 25px 0 15px 0;
- padding-left: 5px;
- }
- .section-title.blue {
- color: #409eff;
- // border-left: 4px solid #409eff;
- }
- .indicators-box {
- border: 1px solid #dcdfe6;
- border-radius: 4px;
- padding: 15px;
- }
- .indicator-group {
- padding: 10px 0;
- }
- .indicator-group-title {
- font-size: 18px;
- font-weight: bold;
- color: #303133;
- margin-bottom: 15px;
- }
- .indicator-item {
- display: flex;
- align-items: center;
- gap: 10px;
- margin-bottom: 10px;
- padding: 10px;
- background: #f5f7fa;
- border-radius: 4px;
- }
- .indicator-name {
- flex: 2;
- font-size: 16px;
- }
- .indicator-value,
- .indicator-count,
- .indicator-qcDeptType,
- .indicator-total {
- flex: 1;
- font-size: 16px;
- text-align: center;
- }
- .indicator-actions {
- display: flex;
- gap: 5px;
- }
- .input-with-unit {
- display: flex;
- align-items: center;
- gap: 10px;
- }
- .unit {
- font-size: 14px;
- color: #606266;
- }
- .exemption-container {
- display: flex;
- align-items: center;
- gap: 15px;
- }
- .exemption-hint {
- font-size: 12px;
- }
- .indicator-form {
- padding: 20px 0;
- }
- .indicator-form :deep(.el-form-item__label) {
- font-weight: 500;
- color: #303133;
- }
- .detail-link {
- color: #409eff;
- cursor: pointer;
- text-decoration: underline;
- display: inline-block;
- width: 100%;
- padding: 5px 0;
- }
- .detail-link:hover {
- color: #66b1ff;
- }
- .detail-content {
- padding: 20px;
- line-height: 1.8;
- font-size: 14px;
- color: #303133;
- min-height: 100px;
- max-height: 500px;
- overflow-y: auto;
- white-space: pre-wrap;
- word-break: break-all;
- }
- </style>
|