| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100 |
- <template>
- <div class="app-container">
- <el-card class="box-card">
- <!-- 顶部选项卡 -->
- <el-tabs v-model="activeTab" type="border-card" @tab-click="handleTabClick">
- <el-tab-pane label="招聘公告" name="recruitment">
- <div class="tab-content">
- <!-- 搜索区域 -->
- <transition :enter-active-class="animate.searchAnimate.enter" :leave-active-class="animate.searchAnimate.leave">
- <div v-show="showSearch" class="mb-[10px]">
- <el-card shadow="hover">
- <el-form ref="queryForm" :model="queryParams" label-width="100px">
- <el-row :gutter="20">
- <el-col :span="6">
- <el-form-item label="职位名称" prop="title">
- <el-input v-model="queryParams.title" placeholder="请输入职位名称" clearable @keyup.enter="handleQuery" />
- </el-form-item>
- </el-col>
- <el-col :span="6">
- <el-form-item label="部门" prop="department">
- <el-select v-model="queryParams.department" placeholder="请选择部门" clearable style="width: 100%">
- <el-option v-for="dict in departmentOptions" :key="dict.value" :label="dict.label" :value="dict.value" />
- </el-select>
- </el-form-item>
- </el-col>
- <el-col :span="6">
- <el-form-item label="状态" prop="isActive">
- <el-select v-model="queryParams.isActive" placeholder="请选择状态" clearable style="width: 100%">
- <el-option label="招聘中" value="0" />
- <el-option label="已停止" value="1" />
- </el-select>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row>
- <el-col :span="24" class="search-btn-container">
- <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-col>
- </el-row>
- </el-form>
- </el-card>
- </div>
- </transition>
- <!-- 操作按钮区域 -->
- <el-card shadow="never" class="button-card table-card">
- <template #header>
- <el-row :gutter="10" class="mb8">
- <el-col :span="1.5">
- <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['rs:job:add']">新增</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button icon="Edit" :disabled="single" @click="handleUpdate()">修改</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['rs:job:remove']">删除</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button icon="Download" @click="handleExport" v-hasPermi="['rs:job:export']" style="display: none">导出</el-button>
- </el-col>
- <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
- </el-row>
- </template>
- <!-- 表格区域 -->
- <el-table v-loading="loading" border :data="jobList" @selection-change="handleSelectionChange" @row-dblclick="handleView">
- <el-table-column type="selection" width="55" align="center" />
- <el-table-column label="职位名称" align="center" prop="title" :show-overflow-tooltip="true" />
- <el-table-column label="部门" align="center" prop="department">
- <template #default="scope">
- <el-tag type="info">{{ getDepartmentLabel(scope.row.department) }}</el-tag>
- </template>
- </el-table-column>
- <el-table-column label="工作地点" align="center" prop="location" />
- <el-table-column label="状态" align="center" prop="isActive" width="120">
- <template #default="scope">
- <el-tag :type="scope.row.isActive === '0' ? 'success' : 'info'">
- {{ scope.row.isActive === '0' ? '招聘中' : '已停止' }}
- </el-tag>
- </template>
- </el-table-column>
- <el-table-column label="申请人数" align="center" prop="applicantCount" width="100" />
- <el-table-column label="浏览次数" align="center" prop="viewCount" width="100" />
- <el-table-column label="创建时间" align="center" prop="createTime" width="180">
- <template #default="scope">
- <span>{{ parseTime(scope.row.createTime) }}</span>
- </template>
- </el-table-column>
- <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="280">
- <template #default="scope">
- <el-tooltip content="查看" placement="top">
- <el-button
- link
- type="primary"
- icon="View"
- size="default"
- style="font-size: 16px; margin-right: 8px; color: blue"
- @click="handleView(scope.row)"
- ></el-button>
- </el-tooltip>
- <el-tooltip content="修改" placement="top">
- <el-button
- link
- type="primary"
- icon="Edit"
- size="default"
- style="font-size: 16px; margin-right: 8px"
- @click="handleUpdate(scope.row)"
- ></el-button>
- </el-tooltip>
- <el-tooltip content="查看简历记录" placement="top">
- <el-button
- link
- type="info"
- icon="Document"
- size="default"
- style="font-size: 16px; margin-right: 8px"
- @click="handleApplications(scope.row)"
- v-if="scope.row.jobId"
- ></el-button>
- </el-tooltip>
- <el-tooltip content="删除" placement="top">
- <el-button
- link
- type="danger"
- icon="Delete"
- size="default"
- style="font-size: 16px; margin-right: 8px"
- @click="handleDelete(scope.row)"
- v-hasPermi="['rs:job:remove']"
- ></el-button>
- </el-tooltip>
- <el-tooltip :content="scope.row.isActive === '0' ? '停止招聘' : '开始招聘'" placement="top">
- <el-button
- link
- :type="scope.row.isActive === '0' ? 'warning' : 'success'"
- :icon="scope.row.isActive === '0' ? 'CircleClose' : 'VideoPlay'"
- size="default"
- style="font-size: 16px"
- @click="handleToggleStatus(scope.row)"
- ></el-button>
- </el-tooltip>
- </template>
- </el-table-column>
- </el-table>
- <div class="pagination-container">
- <pagination
- v-show="total > 0"
- :total="total"
- v-model:page="queryParams.pageNum"
- v-model:limit="queryParams.pageSize"
- @pagination="getList"
- />
- </div>
- </el-card>
- </div>
- </el-tab-pane>
- <el-tab-pane label="简历管理" name="application">
- <div class="tab-content">
- <!-- 搜索区域 -->
- <transition :enter-active-class="animate.searchAnimate.enter" :leave-active-class="animate.searchAnimate.leave">
- <div v-show="showApplicationSearch" class="mb-[10px]">
- <el-card shadow="hover">
- <el-form ref="applicationQueryForm" :model="applicationQueryParams" label-width="100px">
- <el-row :gutter="20">
- <el-col :span="6">
- <el-form-item label="职位名称" prop="jobTitle">
- <el-input
- v-model="applicationQueryParams.jobTitle"
- placeholder="请输入职位名称"
- clearable
- @keyup.enter="handleApplicationQuery"
- />
- </el-form-item>
- </el-col>
- <el-col :span="6">
- <el-form-item label="应聘者" prop="applicantName">
- <el-input
- v-model="applicationQueryParams.applicantName"
- placeholder="请输入应聘者姓名"
- clearable
- @keyup.enter="handleApplicationQuery"
- />
- </el-form-item>
- </el-col>
- <el-col :span="6">
- <el-form-item label="申请状态" prop="status">
- <el-select v-model="applicationQueryParams.status" placeholder="请选择申请状态" clearable style="width: 100%">
- <el-option v-for="dict in applicationStatusOptions" :key="dict.value" :label="dict.label" :value="dict.value" />
- </el-select>
- </el-form-item>
- </el-col>
- <el-col :span="6">
- <el-form-item label="联系电话" prop="contactPhone">
- <el-input
- v-model="applicationQueryParams.contactPhone"
- placeholder="请输入联系电话"
- clearable
- @keyup.enter="handleApplicationQuery"
- />
- </el-form-item>
- </el-col>
- </el-row>
- <el-row>
- <el-col :span="24" class="search-btn-container">
- <el-form-item>
- <el-button type="primary" icon="Search" @click="handleApplicationQuery">搜索</el-button>
- <el-button icon="Refresh" @click="resetApplicationQuery">重置</el-button>
- </el-form-item>
- </el-col>
- </el-row>
- </el-form>
- </el-card>
- </div>
- </transition>
- <!-- 操作按钮区域 -->
- <el-card shadow="never" class="table-card">
- <template #header>
- <el-row :gutter="10" class="mb8">
- <el-col :span="1.5">
- <el-button icon="Download" @click="handleExportApplications" v-hasPermi="['rs:application:export']" style="display: none"
- >导出</el-button
- >
- </el-col>
- <el-col :span="1.5">
- <el-button icon="Printer" @click="handlePrintApplications" style="display: none">打印</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button icon="Document" :disabled="applicationIds.length !== 1" @click="handleExportResume">导出简历</el-button>
- </el-col>
- <right-toolbar v-model:showSearch="showApplicationSearch" @queryTable="getApplicationList"></right-toolbar>
- </el-row>
- </template>
- <!-- 表格区域 -->
- <el-table
- v-loading="applicationLoading"
- border
- :data="applicationList"
- @selection-change="handleApplicationSelectionChange"
- @row-dblclick="handleViewApplicant"
- >
- <el-table-column type="selection" width="55" align="center" />
- <el-table-column label="职位名称" align="center" prop="jobTitle" :show-overflow-tooltip="true" />
- <el-table-column label="应聘者" align="center" prop="applicantName" />
- <el-table-column label="联系电话" align="center" prop="contactPhone" />
- <el-table-column label="联系邮箱" align="center" prop="contactEmail" width="200" :show-overflow-tooltip="true" />
- <el-table-column label="申请时间" align="center" prop="applyTime" width="180">
- <template #default="scope">
- <span>{{ parseTime(scope.row.applyTime) }}</span>
- </template>
- </el-table-column>
- <el-table-column label="申请状态" align="center" prop="status" width="120">
- <template #default="scope">
- <el-tag :type="getStatusType(scope.row.status)">
- {{ getStatusLabel(scope.row.status) }}
- </el-tag>
- </template>
- </el-table-column>
- <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="300">
- <template #default="scope">
- <div class="action-buttons">
- <el-tooltip content="查看详情" placement="top">
- <el-button link type="primary" icon="View" size="small" @click="handleViewApplicant(scope.row)"></el-button>
- </el-tooltip>
- <el-tooltip content="下载简历" placement="top" v-if="scope.row.resumePath">
- <el-button link type="primary" icon="Download" size="small" @click="downloadResume(scope.row.resumePath)"></el-button>
- </el-tooltip>
- <el-tooltip content="修改" placement="top">
- <el-button
- link
- type="warning"
- icon="Edit"
- size="small"
- @click="handleEditApplicant(scope.row)"
- v-hasPermi="['rs:application:edit']"
- ></el-button>
- </el-tooltip>
- </div>
- </template>
- </el-table-column>
- </el-table>
- <div class="pagination-container">
- <pagination
- v-show="applicationTotal > 0"
- :total="applicationTotal"
- v-model:page="applicationQueryParams.pageNum"
- v-model:limit="applicationQueryParams.pageSize"
- @pagination="getApplicationList"
- />
- </div>
- </el-card>
- </div>
- </el-tab-pane>
- </el-tabs>
- </el-card>
- <!-- 添加或修改职位对话框 -->
- <el-dialog :title="title" v-model="open" width="700px" append-to-body>
- <el-form ref="jobForm" :model="form" :rules="rules" label-width="100px">
- <el-form-item label="职位名称" prop="title">
- <el-input v-model="form.title" placeholder="请输入职位名称" />
- </el-form-item>
- <el-form-item label="部门" prop="department">
- <el-select v-model="form.department" placeholder="请选择部门" style="width: 100%">
- <el-option v-for="dict in departmentOptions" :key="dict.value" :label="dict.label" :value="dict.value" />
- </el-select>
- </el-form-item>
- <el-form-item label="工作地点" prop="location">
- <el-input v-model="form.location" placeholder="请输入工作地点" />
- </el-form-item>
- <el-form-item label="发布时间" prop="publishTime">
- <el-date-picker
- v-model="form.publishTime"
- type="datetime"
- placeholder="选择发布时间"
- style="width: 100%"
- value-format="YYYY-MM-DD HH:mm:ss"
- />
- </el-form-item>
- <el-form-item label="职位描述" prop="description">
- <el-input
- v-model="form.description"
- type="textarea"
- placeholder="请输入职位描述"
- resize="none"
- style="height: 150px"
- :autosize="false"
- :rows="6"
- />
- </el-form-item>
- <el-form-item label="任职要求" prop="requirements">
- <el-input
- v-model="form.requirements"
- type="textarea"
- placeholder="请输入任职要求"
- resize="none"
- style="height: 150px"
- :autosize="false"
- :rows="6"
- />
- </el-form-item>
- <el-form-item label="状态" prop="isActive">
- <el-radio-group v-model="form.isActive">
- <el-radio label="0">招聘中</el-radio>
- <el-radio label="1">已停止</el-radio>
- </el-radio-group>
- </el-form-item>
- <el-form-item label="备注" prop="remark">
- <el-input v-model="form.remark" type="textarea" placeholder="请输入备注" />
- </el-form-item>
- </el-form>
- <template #footer>
- <div class="dialog-footer">
- <el-button :loading="buttonLoading" plain type="primary" @click="submitForm">确 定</el-button>
- <el-button @click="cancel">取 消</el-button>
- </div>
- </template>
- </el-dialog>
- <!-- 查看职位详情对话框 -->
- <el-dialog title="职位详情" v-model="viewOpen" width="700px" append-to-body>
- <el-descriptions :column="2" border>
- <el-descriptions-item label="职位名称">{{ viewForm.title }}</el-descriptions-item>
- <el-descriptions-item label="部门">{{ getDepartmentLabel(viewForm.department) }}</el-descriptions-item>
- <el-descriptions-item label="工作地点">{{ viewForm.location }}</el-descriptions-item>
- <el-descriptions-item label="状态">
- <el-tag :type="viewForm.isActive === '0' ? 'success' : 'info'">
- {{ viewForm.isActive === '0' ? '招聘中' : '已停止' }}
- </el-tag>
- </el-descriptions-item>
- <el-descriptions-item label="申请人数">{{ viewForm.applicantCount }}</el-descriptions-item>
- <el-descriptions-item label="浏览次数">{{ viewForm.viewCount }}</el-descriptions-item>
- <el-descriptions-item label="应聘链接">
- <el-link
- :href="`/recruitment-apply?jobId=${viewForm.jobId}`"
- target="_blank"
- type="primary"
- :underline="false"
- style="font-size: 14px;"
- >
- 点击前往应聘页面
- <el-icon style="margin-left: 4px;"><Link /></el-icon>
- </el-link>
- </el-descriptions-item>
- <el-descriptions-item label="发布时间">
- {{ parseTime(viewForm.publishTime) || (viewForm.isActive === '0' ? parseTime(viewForm.createTime) || '长期有效' : '未发布') }}
- </el-descriptions-item>
- <el-descriptions-item label="创建时间">{{ parseTime(viewForm.createTime) }}</el-descriptions-item>
- <el-descriptions-item label="职位描述" :span="2">
- <div class="view-description">{{ viewForm.description || '暂无描述' }}</div>
- </el-descriptions-item>
- <el-descriptions-item label="任职要求" :span="2">
- <div class="view-description">{{ viewForm.requirements || '暂无要求' }}</div>
- </el-descriptions-item>
- <el-descriptions-item label="备注" :span="2">{{ viewForm.remark || '暂无备注' }}</el-descriptions-item>
- </el-descriptions>
- <template #footer>
- <div class="dialog-footer">
- <el-button @click="viewOpen = false">关 闭</el-button>
- </div>
- </template>
- </el-dialog>
- <!-- 简历记录对话框 -->
- <el-dialog title="简历记录" v-model="applicationOpen" width="1200px" append-to-body>
- <div v-if="currentJob">
- <div class="job-info-header">
- <div class="job-info-compact">
- <div class="info-item">
- <span class="info-label">职位名称:</span>
- <span class="info-value">{{ currentJob.title }}</span>
- </div>
- <div class="info-divider">|</div>
- <div class="info-item">
- <span class="info-label">部门:</span>
- <span class="info-value">{{ getDepartmentLabel(currentJob.department) }}</span>
- </div>
- <div class="info-divider">|</div>
- <div class="info-item">
- <span class="info-label">申请人数:</span>
- <span class="info-value highlight">{{ currentJob.applicantCount }}</span>
- </div>
- </div>
- </div>
- <div class="application-table mt-4">
- <el-table
- v-loading="applicationLoading"
- :data="applicationList"
- border
- size="small"
- class="compact-table"
- :row-style="{ height: '32px' }"
- :cell-style="{ padding: '2px 0' }"
- >
- <el-table-column label="应聘者" align="center" prop="applicantName" width="110" />
- <el-table-column label="申请状态" align="center" prop="status" width="110">
- <template #default="scope">
- <el-tag :type="getStatusType(scope.row.status)" size="small">
- {{ getStatusLabel(scope.row.status) }}
- </el-tag>
- </template>
- </el-table-column>
- <el-table-column label="联系电话" align="center" prop="contactPhone" width="130" />
- <el-table-column label="联系邮箱" align="center" prop="contactEmail" width="200" :show-overflow-tooltip="true" />
- <el-table-column label="自我介绍" align="center" prop="selfDescription" width="180" :show-overflow-tooltip="true" />
- <el-table-column label="申请时间" align="center" prop="applyTime" width="170">
- <template #default="scope">
- <span>{{ parseTime(scope.row.applyTime) }}</span>
- </template>
- </el-table-column>
- <el-table-column label="HR备注" align="center" prop="hrNotes" width="150" :show-overflow-tooltip="true" />
- <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="130" fixed="right">
- <template #default="scope">
- <div class="action-buttons">
- <el-tooltip content="查看详情" placement="top">
- <el-button link type="primary" icon="View" size="small" @click="handleViewApplicant(scope.row)"></el-button>
- </el-tooltip>
- <el-tooltip content="下载简历" placement="top" v-if="scope.row.resumePath">
- <el-button link type="primary" icon="Download" size="small" @click="downloadResume(scope.row.resumePath)"></el-button>
- </el-tooltip>
- <!-- 状态选择器已隐藏 -->
- <!-- <div class="status-selector" v-hasPermi="['rs:application:edit']">
- <el-select
- :model-value="scope.row.status"
- @change="(newStatus: string) => handleStatusChange(scope.row, newStatus)"
- size="small"
- style="width: 100px"
- >
- <el-option v-for="option in applicationStatusOptions" :key="option.value" :label="option.label" :value="option.value" />
- </el-select>
- </div> -->
- </div>
- </template>
- </el-table-column>
- </el-table>
- <div class="pagination-container">
- <pagination
- v-show="applicationTotal > 0"
- :total="applicationTotal"
- v-model:page="applicationQueryParams.pageNum"
- v-model:limit="applicationQueryParams.pageSize"
- @pagination="getApplicationList"
- :page-sizes="[5, 10, 15, 20]"
- layout="sizes, prev, pager, next, jumper"
- :small="true"
- />
- </div>
- </div>
- </div>
- </el-dialog>
- <!-- 应聘者详情对话框 -->
- <el-dialog v-model="applicationDetailOpen" title="应聘者详情" width="700px" append-to-body>
- <div class="applicant-detail">
- <el-descriptions :column="2" border>
- <el-descriptions-item label="职位名称">{{ applicationDetail.jobTitle }}</el-descriptions-item>
- <el-descriptions-item label="应聘者">{{ applicationDetail.applicantName }}</el-descriptions-item>
- <el-descriptions-item label="申请状态">
- <el-tag :type="applicationDetail.status === '0' ? 'warning' : applicationDetail.status === '1' ? 'success' : 'danger'">
- {{ getStatusLabel(applicationDetail.status) }}
- </el-tag>
- </el-descriptions-item>
- <el-descriptions-item label="申请时间">{{ parseTime(applicationDetail.applyTime) }}</el-descriptions-item>
- <el-descriptions-item label="联系电话">{{ applicationDetail.contactPhone }}</el-descriptions-item>
- <el-descriptions-item label="联系邮箱">
- <div style="display: flex; align-items: center; gap: 8px;">
- <span>{{ applicationDetail.contactEmail }}</span>
- <el-button
- v-if="applicationDetail.contactEmail"
- size="small"
- type="primary"
- :icon="Message"
- @click="sendEmail(applicationDetail.contactEmail, applicationDetail.applicantName)"
- style="margin-left: 8px;"
- >
- 发送邮件
- </el-button>
- </div>
- </el-descriptions-item>
- <el-descriptions-item label="学历">{{ applicationDetail.education || '暂无信息' }}</el-descriptions-item>
- <el-descriptions-item label="教育背景">{{ applicationDetail.educationBackground || '暂无信息' }}</el-descriptions-item>
- <el-descriptions-item label="工作经验" :span="2">{{ applicationDetail.experience || '暂无信息' }}</el-descriptions-item>
- <el-descriptions-item label="自我介绍" :span="2">
- <div class="view-description">{{ applicationDetail.selfDescription || '暂无自我介绍' }}</div>
- </el-descriptions-item>
- <el-descriptions-item label="HR备注" :span="2">
- <el-input
- v-model="applicationDetail.hrNotes"
- type="textarea"
- :rows="4"
- placeholder="请输入HR备注"
- :disabled="applicationDetail.status !== '0'"
- />
- </el-descriptions-item>
- </el-descriptions>
- </div>
- <template #footer>
- <div class="dialog-footer">
- <el-button type="primary" @click="saveHrNotes" v-if="applicationDetail.status === '0'">保存备注</el-button>
- <el-button type="success" @click="handleUpdateStatus(applicationDetail, '1')" v-if="applicationDetail.status === '0'">通过申请</el-button>
- <el-button type="danger" @click="handleUpdateStatus(applicationDetail, '2')" v-if="applicationDetail.status === '0'">拒绝申请</el-button>
- <el-button @click="applicationDetailOpen = false">关闭</el-button>
- </div>
- </template>
- </el-dialog>
- <!-- 应聘者详情对话框 -->
- <el-dialog v-model="applicantViewOpen" title="应聘者详情" width="700px" append-to-body>
- <el-descriptions :column="2" border>
- <el-descriptions-item label="姓名">{{ currentApplication?.applicantName }}</el-descriptions-item>
- <el-descriptions-item label="应聘职位">{{ currentApplication?.jobTitle }}</el-descriptions-item>
- <el-descriptions-item label="性别">{{ currentApplication?.gender || '未提供' }}</el-descriptions-item>
- <el-descriptions-item label="年龄">{{ currentApplication?.age || '未提供' }}</el-descriptions-item>
- <el-descriptions-item label="联系电话">{{ currentApplication?.contactPhone }}</el-descriptions-item>
- <el-descriptions-item label="邮箱地址">
- <div style="display: flex; align-items: center; gap: 8px;">
- <span>{{ currentApplication?.contactEmail }}</span>
- <el-button
- v-if="currentApplication?.contactEmail"
- size="small"
- type="primary"
- :icon="Message"
- @click="sendEmail(currentApplication?.contactEmail, currentApplication?.applicantName)"
- style="margin-left: 8px;"
- >
- 发送邮件
- </el-button>
- </div>
- </el-descriptions-item>
- <el-descriptions-item label="申请状态">
- <el-tag
- :type="
- currentApplication?.status === '0'
- ? 'warning'
- : currentApplication?.status === '1'
- ? 'success'
- : currentApplication?.status === '2'
- ? 'danger'
- : 'info'
- "
- >
- {{ getStatusLabel(currentApplication?.status) }}
- </el-tag>
- </el-descriptions-item>
- <el-descriptions-item label="申请时间">{{ parseTime(currentApplication?.applyTime) }}</el-descriptions-item>
- <el-descriptions-item label="学历">{{ currentApplication?.education || '未提供' }}</el-descriptions-item>
- <el-descriptions-item label="教育背景">{{ currentApplication?.educationBackground || '未提供' }}</el-descriptions-item>
- <el-descriptions-item label="工作经验" :span="2">{{ currentApplication?.experience || '未提供' }}</el-descriptions-item>
- <el-descriptions-item label="自我介绍" :span="2">
- <div class="view-description">{{ currentApplication?.selfDescription || '未提供自我介绍' }}</div>
- </el-descriptions-item>
- <el-descriptions-item label="HR备注" :span="2">
- <div class="view-description">{{ currentApplication?.hrNotes || '暂无备注' }}</div>
- </el-descriptions-item>
- </el-descriptions>
- <template #footer>
- <div class="dialog-footer">
- <el-button @click="applicantViewOpen = false">关 闭</el-button>
- </div>
- </template>
- </el-dialog>
- <!-- 编辑应聘者信息对话框 -->
- <el-dialog v-model="applicantEditOpen" title="编辑应聘者信息" width="700px" append-to-body>
- <el-form ref="applicantEditFormRef" :model="editForm" :rules="editRules" label-width="100px">
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item label="姓名">
- <el-input v-model="editForm.applicantName" readonly />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="应聘职位">
- <el-input v-model="editForm.jobTitle" readonly />
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item label="性别">
- <el-input :model-value="editForm.gender || '未提供'" readonly />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="年龄">
- <el-input :model-value="editForm.age || '未提供'" readonly />
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item label="联系电话">
- <el-input v-model="editForm.contactPhone" readonly />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="邮箱地址">
- <el-input v-model="editForm.contactEmail" readonly />
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item label="学历">
- <el-input :model-value="editForm.education || '未提供'" readonly />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="申请时间">
- <el-input :model-value="parseTime(editForm.applyTime)" readonly />
- </el-form-item>
- </el-col>
- </el-row>
- <el-form-item label="教育背景">
- <el-input :model-value="editForm.educationBackground || '未提供'" type="textarea" :rows="3" readonly placeholder="暂无教育背景" />
- </el-form-item>
- <el-form-item label="自我介绍">
- <el-input v-model="editForm.selfDescription" type="textarea" :rows="3" readonly placeholder="暂无自我介绍" />
- </el-form-item>
- <el-form-item label="工作经验">
- <el-input v-model="editForm.experience" type="textarea" :rows="3" readonly placeholder="暂无工作经验" />
- </el-form-item>
- <el-form-item label="申请状态" prop="status">
- <el-select v-model="editForm.status" placeholder="请选择申请状态" style="width: 100%">
- <el-option v-for="option in applicationStatusOptions" :key="option.value" :label="option.label" :value="option.value" />
- </el-select>
- </el-form-item>
- <el-form-item label="HR备注" prop="hrNotes">
- <el-input v-model="editForm.hrNotes" type="textarea" :rows="4" placeholder="请输入HR备注..." maxlength="500" show-word-limit />
- </el-form-item>
- </el-form>
- <template #footer>
- <div class="dialog-footer">
- <el-button :loading="buttonLoading" type="primary" @click="submitEdit">保 存</el-button>
- <el-button @click="applicantEditOpen = false">取 消</el-button>
- </div>
- </template>
- </el-dialog>
- </div>
- </template>
- <script setup lang="ts" name="PersonnelManagement">
- import { ref, reactive, onMounted, getCurrentInstance, ComponentInternalInstance } from 'vue';
- import { ElMessage, ElMessageBox } from 'element-plus';
- import {
- listJob,
- getJob,
- addJob,
- updateJob,
- delJob,
- toggleJobStatus,
- exportJob,
- listApplications,
- listAllApplications,
- updateApplicationStatus,
- updateApplicationInfo,
- getApplication,
- exportApplication,
- uploadAttachment,
- exportResumePdf
- } from '@/api/rs/job';
- import { parseTime } from '@/utils/ruoyi';
- import type { JobVO, JobForm, ApplicationVO } from '@/api/rs/job';
- import { listDept } from '@/api/system/dept';
- import type { DeptVO } from '@/api/system/dept/types';
- import { Document, Link, Message } from '@element-plus/icons-vue';
- import { getToken } from '@/utils/auth';
- import jsPDF from 'jspdf';
- import html2canvas from 'html2canvas';
- const { proxy } = getCurrentInstance() as ComponentInternalInstance;
- const animate = proxy?.animate || { searchAnimate: { enter: 'animate__fadeInUp', leave: 'animate__fadeOutDown' } };
- // 遮罩层
- const loading = ref(true);
- const buttonLoading = ref(false);
- // 选中数组
- const ids = ref<Array<string | number>>([]);
- // 非单个禁用
- const single = ref(true);
- // 非多个禁用
- const multiple = ref(true);
- // 显示搜索条件
- const showSearch = ref(true);
- // 总条数
- const total = ref(0);
- // 职位表格数据
- const jobList = ref<JobVO[]>([]);
- // 弹出层标题
- const title = ref('');
- // 是否显示弹出层
- const open = ref(false);
- // 是否显示详情弹出层
- const viewOpen = ref(false);
- // 是否显示申请记录弹出层
- const applicationOpen = ref(false);
- // 当前激活的选项卡
- const activeTab = ref('recruitment');
- // 部门选项 - 从数据库sys_dept表获取
- const departmentOptions = ref<Array<{ value: string; label: string }>>([]);
- // 申请状态选项
- const applicationStatusOptions = [
- { value: 'pending', label: '待处理', type: 'warning' },
- { value: 'interviewed', label: '已面试', type: 'primary' },
- { value: 'offered', label: '已通过', type: 'success' },
- { value: 'eliminated', label: '已淘汰', type: 'info' },
- { value: 'rejected', label: '已拒绝', type: 'danger' }
- ];
- // 查询参数
- const queryParams = reactive({
- pageNum: 1,
- pageSize: 10,
- title: '',
- department: '',
- isActive: '',
- params: {}
- });
- // 表单参数
- const form = reactive<JobForm>({
- jobId: undefined,
- title: '',
- department: '',
- salaryRange: '',
- location: '',
- description: '',
- requirements: '',
- isActive: '0',
- publishTime: '',
- remark: ''
- });
- // 查看表单
- const viewForm = reactive<JobVO>({
- jobId: undefined,
- title: '',
- department: '',
- salaryRange: '',
- location: '',
- description: '',
- requirements: '',
- isActive: '0',
- applicantCount: 0,
- viewCount: 0,
- publishTime: '',
- createTime: '',
- updateTime: '',
- createBy: '',
- updateBy: '',
- remark: ''
- });
- // 表单校验
- const rules = reactive<Record<string, any>>({
- title: [
- { required: true, message: '职位名称不能为空', trigger: 'blur' },
- { min: 2 as number, max: 50 as number, message: '长度在 2 到 50 个字符', trigger: 'blur' }
- ],
- department: [{ required: true, message: '部门不能为空', trigger: 'change' }],
- location: [{ required: true, message: '工作地点不能为空', trigger: 'blur' }]
- });
- // 培训申请表单校验规则
- const applicationRules = reactive({
- reason: [
- { required: true, message: '申请理由不能为空', trigger: 'blur' },
- { min: 10, max: 500, message: '长度在 10 到 500 个字符', trigger: 'blur' }
- ]
- });
- // 表单引用
- const jobForm = ref<any>(null);
- const queryForm = ref<any>(null);
- // 申请记录相关
- const applicationLoading = ref(false);
- const applicationList = ref<ApplicationVO[]>([]);
- const applicationTotal = ref(0);
- const currentJob = ref<JobVO | null>(null);
- const applicationQueryParams = reactive({
- pageNum: 1,
- pageSize: 10,
- jobId: undefined as string | number | undefined,
- jobTitle: '',
- applicantName: '',
- contactPhone: '',
- status: '',
- params: {}
- });
- // 申请管理页面相关
- const showApplicationSearch = ref(true);
- const applicationIds = ref<Array<string | number>>([]);
- const applicationSingle = ref(true);
- const applicationMultiple = ref(true);
- // 已有申请管理相关变量,不需要重复定义
- // 申请详情对话框
- const applicationDetailOpen = ref(false);
- const applicantViewOpen = ref(false); // 应聘者详情对话框
- const applicantEditOpen = ref(false); // 编辑应聘者信息对话框
- const currentApplication = ref<ApplicationVO | null>(null); // 当前查看的应聘者
- // 编辑表单
- const editForm = reactive<ApplicationVO>({
- applicationId: 0,
- jobId: 0,
- jobTitle: '',
- applicantId: 0,
- applicantName: '',
- gender: '', // 新增:性别
- age: '', // 新增:年龄
- status: '',
- applyTime: '',
- resumePath: '',
- selfDescription: '',
- hrNotes: '',
- contactPhone: '',
- contactEmail: '',
- education: '',
- educationBackground: '', // 新增:教育背景
- experience: '',
- remark: '',
- createBy: '',
- createTime: '',
- updateBy: '',
- updateTime: ''
- });
- // 编辑表单校验规则
- const editRules = reactive({
- status: [{ required: true, message: '请选择申请状态', trigger: 'change' }]
- });
- const applicationDetail = reactive<ApplicationVO>({
- applicationId: 0,
- jobId: 0,
- jobTitle: '',
- applicantId: 0,
- applicantName: '',
- gender: '', // 新增:性别
- age: '', // 新增:年龄
- status: '',
- applyTime: '',
- resumePath: '',
- selfDescription: '',
- hrNotes: '',
- contactPhone: '',
- contactEmail: '',
- education: '',
- educationBackground: '', // 新增:教育背景
- experience: '',
- remark: '',
- createBy: '',
- createTime: '',
- updateBy: '',
- updateTime: ''
- });
- /** 查询职位列表 */
- function getList() {
- loading.value = true;
- listJob(queryParams)
- .then((response) => {
- jobList.value = response.rows || [];
- total.value = response.total || 0;
- loading.value = false;
- })
- .catch((error) => {
- console.error('获取职位列表失败:', error);
- // 如果API调用失败,可以使用模拟数据
- mockJobData();
- loading.value = false;
- });
- }
- /** 获取部门列表 */
- function getDepartmentList() {
- listDept({
- pageNum: 1,
- pageSize: 1000, // 获取所有部门
- status: 0 // 修复:改为number类型
- })
- .then((response) => {
- const deptList = response.data || [];
- // 过滤出二级学院和行政单位下的部门,作为招聘部门选项
- const filteredDepts = deptList.filter((dept: DeptVO) => {
- // 包含二级学院(101)和行政单位(102)下的部门,排除顶级部门
- return dept.parentId === 101 || dept.parentId === 102;
- });
- departmentOptions.value = filteredDepts.map((dept: DeptVO) => ({
- value: dept.deptName,
- label: dept.deptName
- }));
- console.log('部门选项已更新:', departmentOptions.value);
- })
- .catch((error) => {
- console.error('获取部门列表失败:', error);
- // 使用备用部门数据
- departmentOptions.value = [
- { value: '人文学院', label: '人文学院' },
- { value: '智能控制学院', label: '智能控制学院' },
- { value: '智能制造学院', label: '智能制造学院' },
- { value: '医药健康学院', label: '医药健康学院' },
- { value: '餐饮休闲学院', label: '餐饮休闲学院' },
- { value: '数字信息学院', label: '数字信息学院' },
- { value: '生态园林学院', label: '生态园林学院' },
- { value: '人事处', label: '人事处' },
- { value: '教务处', label: '教务处' },
- { value: '学生处', label: '学生处' },
- { value: '总务处', label: '总务处' }
- ];
- });
- }
- /** 模拟职位数据 */
- function mockJobData() {
- // 创建基础模拟数据
- const mockData = [
- {
- jobId: 1,
- title: 'Java开发工程师',
- department: 'tech',
- salaryRange: '15k-25k',
- location: '杭州',
- description: '负责校园教学管理系统的开发和维护...',
- requirements: '计算机相关专业本科及以上学历,3年以上Java开发经验...',
- isActive: '0',
- viewCount: 356,
- applicantCount: 12,
- publishTime: '2025-06-01 10:00:00',
- createTime: '2025-06-01 10:00:00',
- updateTime: '2025-06-15 15:30:00',
- createBy: '1',
- updateBy: '1',
- remark: ''
- },
- {
- jobId: 2,
- title: '前端工程师',
- department: 'tech',
- salaryRange: '12k-18k',
- location: '杭州',
- description: '负责校园教学管理系统前端开发...',
- requirements: '计算机相关专业本科及以上学历,2年以上前端开发经验...',
- isActive: '0',
- viewCount: 245,
- applicantCount: 8,
- publishTime: '2025-06-05 14:30:00',
- createTime: '2025-06-05 14:30:00',
- updateTime: '2025-06-15 15:30:00',
- createBy: '1',
- updateBy: '1',
- remark: ''
- },
- {
- jobId: 3,
- title: '行政助理',
- department: 'admin',
- salaryRange: '6k-8k',
- location: '杭州',
- description: '负责日常行政工作...',
- requirements: '行政管理相关专业,1年以上相关工作经验...',
- isActive: '0',
- viewCount: 178,
- applicantCount: 15,
- publishTime: '2025-06-10 09:15:00',
- createTime: '2025-06-10 09:15:00',
- updateTime: '2025-06-15 15:30:00',
- createBy: '1',
- updateBy: '1',
- remark: ''
- }
- ];
- // 应用筛选
- let filteredData = [...mockData];
- // 按职位名称筛选
- if (queryParams.title) {
- filteredData = filteredData.filter((item) => item.title.includes(queryParams.title));
- }
- // 按部门筛选
- if (queryParams.department) {
- filteredData = filteredData.filter((item) => item.department === queryParams.department);
- }
- // 按状态筛选
- if (queryParams.isActive) {
- filteredData = filteredData.filter((item) => item.isActive === queryParams.isActive);
- }
- // 设置数据
- jobList.value = filteredData;
- total.value = filteredData.length;
- }
- /** 取消按钮 */
- function cancel() {
- open.value = false;
- reset();
- }
- /** 表单重置 */
- function reset() {
- form.jobId = undefined;
- form.title = '';
- form.department = '';
- form.salaryRange = '';
- form.location = '';
- form.description = '';
- form.requirements = '';
- form.isActive = '0';
- form.publishTime = '';
- form.remark = '';
- jobForm.value?.resetFields();
- }
- /** 搜索按钮操作 */
- function handleQuery() {
- queryParams.pageNum = 1;
- getList();
- }
- /** 重置按钮操作 */
- function resetQuery() {
- queryForm.value?.resetFields();
- handleQuery();
- }
- /** 多选框选中数据 */
- function handleSelectionChange(selection: JobVO[]) {
- ids.value = selection.map((item) => item.jobId);
- single.value = selection.length !== 1;
- multiple.value = !selection.length;
- }
- /** 新增按钮操作 */
- function handleAdd() {
- reset();
- open.value = true;
- title.value = '添加职位';
- }
- /** 修改按钮操作 */
- function handleUpdate(row?: JobVO) {
- reset();
- const jobId = row?.jobId || ids.value[0];
- getJob(jobId).then((response) => {
- Object.assign(form, response.data);
- open.value = true;
- title.value = '修改职位';
- });
- }
- /** 查看按钮操作 */
- function handleView(row: JobVO) {
- getJob(row.jobId)
- .then((response) => {
- Object.assign(viewForm, response.data);
- viewOpen.value = true;
- })
- .catch((error) => {
- console.error('获取职位详情失败:', error);
- // 如果API调用失败,使用行数据
- Object.assign(viewForm, row);
- viewOpen.value = true;
- });
- }
- /** 提交按钮 */
- function submitForm() {
- jobForm.value?.validate((valid: boolean) => {
- if (valid) {
- buttonLoading.value = true;
- if (form.jobId) {
- updateJob(form)
- .then(() => {
- proxy?.$modal.msgSuccess('修改成功');
- open.value = false;
- getList();
- })
- .finally(() => {
- buttonLoading.value = false;
- });
- } else {
- addJob(form)
- .then(() => {
- proxy?.$modal.msgSuccess('新增成功');
- open.value = false;
- getList();
- })
- .finally(() => {
- buttonLoading.value = false;
- });
- }
- }
- });
- }
- /** 删除按钮操作 */
- function handleDelete(row?: JobVO) {
- const jobIds = row?.jobId || ids.value;
- let confirmMessage = '';
- if (row) {
- // 单个删除
- confirmMessage = `是否确认删除职位"${row.title}"?`;
- } else {
- // 批量删除
- const selectedItems = jobList.value.filter((item) => ids.value.includes(item.jobId));
- if (selectedItems.length === 1) {
- confirmMessage = `是否确认删除职位"${selectedItems[0].title}"?`;
- } else {
- const names = selectedItems.map((item) => item.title).join('、');
- confirmMessage = `是否确认删除职位"${names}"?`;
- }
- }
- proxy?.$modal
- .confirm(confirmMessage)
- .then(() => {
- return delJob(jobIds);
- })
- .then(() => {
- getList();
- proxy?.$modal.msgSuccess('删除成功');
- });
- }
- /** 导出按钮操作 */
- function handleExport() {
- proxy?.download(
- 'rs/job/export',
- {
- ...queryParams
- },
- `job_${new Date().getTime()}.xlsx`
- );
- }
- /** 切换职位状态 */
- function handleToggleStatus(row: JobVO) {
- const text = row.isActive === '0' ? '停止招聘' : '开始招聘';
- proxy?.$modal
- .confirm(`确认要${text}该职位吗?`)
- .then(() => {
- return toggleJobStatus(row.jobId);
- })
- .then(() => {
- getList();
- proxy?.$modal.msgSuccess(`${text}成功`);
- });
- }
- /** 查询申请记录列表 */
- function getApplicationList() {
- applicationLoading.value = true;
- // 如果是从职位详情过来,使用当前职位ID
- if (currentJob.value?.jobId) {
- listApplications(currentJob.value.jobId, applicationQueryParams)
- .then((response) => {
- applicationList.value = response.rows || [];
- applicationTotal.value = response.total || 0;
- applicationLoading.value = false;
- })
- .catch(() => {
- // 加载失败时使用模拟数据
- mockApplicationData();
- });
- }
- // 如果是从申请管理选项卡过来,查询所有申请记录
- else {
- listAllApplications(applicationQueryParams)
- .then((response) => {
- applicationList.value = response.rows || [];
- applicationTotal.value = response.total || 0;
- applicationLoading.value = false;
- })
- .catch(() => {
- // 加载失败时使用模拟数据
- mockApplicationData();
- });
- }
- }
- /** 模拟申请数据 */
- function mockApplicationData() {
- const mockData: ApplicationVO[] = [
- {
- applicationId: 1,
- jobId: 1,
- jobTitle: 'Java开发工程师',
- applicantId: 1,
- applicantName: '张文明',
- gender: '男', // 新增:性别
- age: 25, // 新增:年龄
- status: '0',
- applyTime: '2025-07-25 10:30:00',
- resumePath: '/uploads/resume/zhangwm_resume.pdf',
- selfDescription: '本科计算机科学与技术专业毕业,熟悉Java开发技术栈,有2年相关工作经验,对Spring Boot、MyBatis等框架有深入了解。',
- hrNotes: '初步筛选通过,安排下周一进行技术面试',
- contactPhone: '13812345678',
- contactEmail: 'zhangwm@example.com',
- education: '2018-2022 浙江大学 计算机科学与技术 本科',
- educationBackground: '2018-2022 浙江大学 计算机科学与技术 本科', // 新增:教育背景
- experience: '2022-2025 杭州某科技公司 Java开发工程师',
- remark: '候选人技术基础扎实,沟通能力良好',
- createBy: 'admin',
- createTime: '2025-07-25 10:30:00',
- updateBy: 'hr001',
- updateTime: '2025-07-25 14:20:00'
- },
- {
- applicationId: 2,
- jobId: 1,
- jobTitle: 'Java开发工程师',
- applicantId: 2,
- applicantName: '李小红',
- gender: '女', // 新增:性别
- age: 23, // 新增:年龄
- status: '1',
- applyTime: '2025-07-24 16:45:00',
- resumePath: '/uploads/resume/lixh_resume.pdf',
- selfDescription: '计算机相关专业应届毕业生,在校期间参与过多个项目开发,熟悉Java、MySQL、Redis等技术。',
- hrNotes: '应届生,技术基础待考察',
- contactPhone: '13987654321',
- contactEmail: 'lixh@example.com',
- education: '2020-2024 杭州电子科技大学 软件工程 本科',
- educationBackground: '2020-2024 杭州电子科技大学 软件工程 本科', // 新增:教育背景
- experience: '在校期间参与学校实验室项目开发',
- remark: '应届毕业生,可培养',
- createBy: 'admin',
- createTime: '2025-07-24 16:45:00',
- updateBy: 'hr001',
- updateTime: '2025-07-24 17:30:00'
- },
- {
- applicationId: 3,
- jobId: 2,
- jobTitle: 'UI设计师',
- applicantId: 3,
- applicantName: '王设计',
- gender: '女', // 新增:性别
- age: 27, // 新增:年龄
- status: '2',
- applyTime: '2025-07-23 14:20:00',
- resumePath: '/uploads/resume/wangdesign_resume.pdf',
- selfDescription: '5年UI/UX设计经验,擅长移动端和Web端界面设计,熟练使用Figma、Sketch、Adobe系列软件。',
- hrNotes: '作品集质量很高,已通过初试',
- contactPhone: '13612345678',
- contactEmail: 'wangdesign@example.com',
- education: '2015-2019 中国美术学院 视觉传达设计 本科',
- educationBackground: '2015-2019 中国美术学院 视觉传达设计 本科', // 新增:教育背景
- experience: '2019-2024 某互联网公司 UI设计师',
- remark: '设计能力强,有良好的审美',
- createBy: 'admin',
- createTime: '2025-07-23 14:20:00',
- updateBy: 'hr002',
- updateTime: '2025-07-23 16:45:00'
- },
- {
- applicationId: 4,
- jobId: 3,
- jobTitle: '产品经理',
- applicantId: 4,
- applicantName: '陈产品',
- gender: '男', // 新增:性别
- age: 30, // 新增:年龄
- status: '3',
- applyTime: '2025-07-22 11:15:00',
- resumePath: '/uploads/resume/chenchanpin_resume.pdf',
- selfDescription: '8年产品经验,负责过多个从0到1的产品项目,具备完整的产品生命周期管理能力。',
- hrNotes: '面试表现优秀,待薪资谈判',
- contactPhone: '13512345678',
- contactEmail: 'chenchanpin@example.com',
- education: '2012-2016 浙江大学 工商管理 本科',
- educationBackground: '2012-2016 浙江大学 工商管理 本科', // 新增:教育背景
- experience: '2016-2024 多家互联网公司 产品经理',
- remark: '产品思维清晰,有丰富的实战经验',
- createBy: 'admin',
- createTime: '2025-07-22 11:15:00',
- updateBy: 'hr003',
- updateTime: '2025-07-22 15:30:00'
- },
- {
- applicationId: 5,
- jobId: 4,
- jobTitle: '市场专员',
- applicantId: 5,
- applicantName: '刘市场',
- gender: '女', // 新增:性别
- age: 24, // 新增:年龄
- status: '4',
- applyTime: '2025-07-21 09:30:00',
- resumePath: '/uploads/resume/liushichang_resume.pdf',
- selfDescription: '市场营销专业毕业,有2年市场推广经验,熟悉新媒体运营和活动策划。',
- hrNotes: '不符合岗位要求,建议拒绝',
- contactPhone: '13412345678',
- contactEmail: 'liushichang@example.com',
- education: '2018-2022 浙江工商大学 市场营销 本科',
- educationBackground: '2018-2022 浙江工商大学 市场营销 本科', // 新增:教育背景
- experience: '2022-2024 某传媒公司 市场专员',
- remark: '经验不足,与岗位需求不匹配',
- createBy: 'admin',
- createTime: '2025-07-21 09:30:00',
- updateBy: 'hr001',
- updateTime: '2025-07-21 11:45:00'
- }
- ];
- // 应用搜索过滤
- let filteredData = mockData;
- if (applicationQueryParams.applicantName) {
- filteredData = filteredData.filter((item) => item.applicantName.includes(applicationQueryParams.applicantName));
- }
- if (applicationQueryParams.contactPhone) {
- filteredData = filteredData.filter((item) => item.contactPhone.includes(applicationQueryParams.contactPhone));
- }
- if (applicationQueryParams.status) {
- filteredData = filteredData.filter((item) => item.status === applicationQueryParams.status);
- }
- // 分页处理
- const startIndex = (applicationQueryParams.pageNum - 1) * applicationQueryParams.pageSize;
- const endIndex = startIndex + applicationQueryParams.pageSize;
- const pageData = filteredData.slice(startIndex, endIndex);
- applicationList.value = pageData;
- applicationTotal.value = filteredData.length;
- applicationLoading.value = false;
- }
- /** 查看申请记录 */
- function handleApplications(row: JobVO) {
- currentJob.value = row;
- applicationQueryParams.pageNum = 1;
- applicationOpen.value = true;
- getApplicationList();
- }
- /** 查看应聘者详情 */
- function handleViewApplicant(row: ApplicationVO) {
- currentApplication.value = row;
- applicantViewOpen.value = true;
- }
- /** 编辑应聘者信息 */
- function handleEditApplicant(row: ApplicationVO) {
- // 复制数据到编辑表单
- Object.assign(editForm, row);
- applicantEditOpen.value = true;
- }
- /** 提交编辑 */
- function submitEdit() {
- console.log('提交编辑开始', {
- applicationId: editForm.applicationId,
- status: editForm.status,
- hrNotes: editForm.hrNotes
- });
- if (!editForm.applicationId) {
- proxy?.$modal.msgError('应聘记录ID不能为空');
- return;
- }
- if (!editForm.status) {
- proxy?.$modal.msgError('请选择申请状态');
- return;
- }
- buttonLoading.value = true;
- // 调用更新API,包含状态和HR备注
- updateApplicationInfo(editForm.applicationId, {
- status: editForm.status,
- hrNotes: editForm.hrNotes || ''
- })
- .then((response) => {
- console.log('API调用成功', response);
- proxy?.$modal.msgSuccess('修改成功');
- applicantEditOpen.value = false;
- // 更新列表中的数据
- const index = applicationList.value.findIndex((item) => item.applicationId === editForm.applicationId);
- if (index !== -1) {
- applicationList.value[index].status = editForm.status;
- applicationList.value[index].hrNotes = editForm.hrNotes;
- }
- buttonLoading.value = false;
- })
- .catch((error) => {
- console.error('API调用失败', error);
- proxy?.$modal.msgError('修改失败: ' + (error.message || '未知错误'));
- buttonLoading.value = false;
- });
- }
- /** 更新申请状态 */
- function handleUpdateStatus(row: ApplicationVO, status: string) {
- const statusText = status === '1' ? '通过' : '拒绝';
- proxy?.$modal
- .confirm(`确认要${statusText}该申请吗?`)
- .then(() => {
- return updateApplicationStatus(row.applicationId, status);
- })
- .then(() => {
- getApplicationList();
- proxy?.$modal.msgSuccess(`${statusText}成功`);
- });
- }
- /** 处理状态变更 */
- function handleStatusChange(row: ApplicationVO, newStatus: string) {
- if (newStatus === row.status) {
- return; // 状态未变更,无需处理
- }
- const statusOption = applicationStatusOptions.find((option) => option.value === newStatus);
- const statusText = statusOption ? statusOption.label : newStatus;
- proxy?.$modal
- .confirm(`确认要将申请状态修改为"${statusText}"吗?`)
- .then(() => {
- return updateApplicationStatus(row.applicationId, newStatus);
- })
- .then(() => {
- // 更新本地数据
- row.status = newStatus;
- proxy?.$modal.msgSuccess(`状态修改成功`);
- })
- .catch(() => {
- // 如果操作被取消或失败,刷新列表以恢复原状态
- getApplicationList();
- });
- }
- /** 获取部门标签 */
- function getDepartmentLabel(value: string): string {
- const option = departmentOptions.value.find((item) => item.value === value);
- return option ? option.label : value;
- }
- /** 获取申请状态标签 */
- function getStatusLabel(value: string): string {
- const option = applicationStatusOptions.find((item) => item.value === value);
- return option ? option.label : value;
- }
- /** 获取申请状态类型 */
- function getStatusType(value: string): 'primary' | 'success' | 'info' | 'warning' | 'danger' {
- const option = applicationStatusOptions.find((item) => item.value === value);
- return (option?.type as 'primary' | 'success' | 'info' | 'warning' | 'danger') || 'info';
- }
- /** 发送邮件 */
- function sendEmail(email: string, applicantName: string) {
- if (!email) {
- ElMessage.warning('邮箱地址为空');
- return;
- }
-
- const subject = encodeURIComponent(`关于您的求职申请 - ${applicantName}`);
- const body = encodeURIComponent(`亲爱的 ${applicantName}:\n\n感谢您对我们的关注和求职申请。\n\n我们将仔细审核您的申请材料,如有需要会及时与您联系。\n\n祝您工作顺利!\n\n此致\n敬礼\n\nHR部门`);
-
- const mailtoUrl = `mailto:${email}?subject=${subject}&body=${body}`;
-
- try {
- window.open(mailtoUrl);
- ElMessage.success('已打开邮件客户端');
- } catch (error) {
- ElMessage.error('打开邮件客户端失败,请检查系统设置');
- }
- }
- /** 选项卡切换 */
- function handleTabClick() {
- if (activeTab.value === 'application') {
- getApplicationList();
- } else if (activeTab.value === 'recruitment') {
- getList();
- }
- }
- /** 下载简历 */
- function downloadResume(resumePath: string) {
- if (!resumePath) {
- proxy?.$modal.msgError('简历文件不存在');
- return;
- }
- // 实际下载实现可能需要调用后端API
- ElMessage.success('简历下载功能开发中');
- }
- /** 导出申请记录 */
- function handleExportApplications() {
- proxy?.download(
- 'rs/application/export',
- {
- ...applicationQueryParams
- },
- `application_${new Date().getTime()}.xlsx`
- );
- }
- /** 打印简历记录 */
- function handlePrintApplications() {
- // 创建打印区域
- const printContainer = document.createElement('iframe');
- printContainer.style.position = 'fixed';
- printContainer.style.right = '-1000px';
- printContainer.style.top = '0';
- printContainer.style.width = '800px';
- printContainer.style.height = '100%';
- printContainer.style.border = 'none';
- document.body.appendChild(printContainer);
- // 创建打印内容
- const printDocument = printContainer.contentWindow.document;
- // 写入基本HTML结构
- printDocument.open();
- printDocument.write('<!DOCTYPE html><html><head><title>简历记录打印</title>');
- // 添加样式
- printDocument.write('<style>');
- printDocument.write('body { font-family: Arial, sans-serif; margin: 20px; }');
- printDocument.write('table { width: 100%; border-collapse: collapse; margin-bottom: 20px; }');
- printDocument.write('table, th, td { border: 1px solid #dcdfe6; }');
- printDocument.write('th, td { padding: 8px; text-align: center; }');
- printDocument.write('th { background-color: #f5f7fa; }');
- printDocument.write('.title { text-align: center; font-size: 20px; font-weight: bold; margin-bottom: 20px; }');
- printDocument.write('.info { margin-bottom: 15px; }');
- printDocument.write('.tag { padding: 2px 6px; border-radius: 4px; display: inline-block; }');
- printDocument.write('.tag-pending { background-color: #e6a23c; color: white; }');
- printDocument.write('.tag-success { background-color: #67c23a; color: white; }');
- printDocument.write('.tag-danger { background-color: #f56c6c; color: white; }');
- printDocument.write('</style></head><body>');
- // 添加标题和信息
- printDocument.write('<div class="title">简历管理列表</div>');
- printDocument.write('<div class="info">');
- printDocument.write('<p>打印时间: ' + parseTime(new Date()) + '</p>');
- if (currentJob.value) {
- printDocument.write('<p>职位: ' + currentJob.value.title + '</p>');
- }
- printDocument.write('<p>总记录数: ' + applicationTotal.value + '</p>');
- printDocument.write('</div>');
- // 添加表格
- printDocument.write('<table>');
- printDocument.write('<thead><tr>');
- printDocument.write('<th>职位名称</th>');
- printDocument.write('<th>应聘者</th>');
- printDocument.write('<th>申请状态</th>');
- printDocument.write('<th>联系电话</th>');
- printDocument.write('<th>联系邮箱</th>');
- printDocument.write('<th>申请时间</th>');
- printDocument.write('</tr></thead>');
- printDocument.write('<tbody>');
- // 添加数据行
- applicationList.value.forEach((item) => {
- let statusClass = '';
- if (item.status === '0') statusClass = 'tag-pending';
- else if (item.status === '1') statusClass = 'tag-success';
- else if (item.status === '2') statusClass = 'tag-danger';
- printDocument.write('<tr>');
- printDocument.write('<td>' + (item.jobTitle || '') + '</td>');
- printDocument.write('<td>' + (item.applicantName || '') + '</td>');
- printDocument.write('<td><span class="tag ' + statusClass + '">' + getStatusLabel(item.status) + '</span></td>');
- printDocument.write('<td>' + (item.contactPhone || '') + '</td>');
- printDocument.write('<td>' + (item.contactEmail || '') + '</td>');
- printDocument.write('<td>' + (parseTime(item.applyTime) || '') + '</td>');
- printDocument.write('</tr>');
- });
- printDocument.write('</tbody></table>');
- printDocument.write('</body></html>');
- printDocument.close();
- // 等待内容加载完成后打印
- printContainer.onload = () => {
- try {
- printContainer.contentWindow.print();
- // 打印完成后移除iframe
- setTimeout(() => {
- document.body.removeChild(printContainer);
- }, 1000);
- } catch (e) {
- console.error('打印出错:', e);
- document.body.removeChild(printContainer);
- proxy?.$modal.msgError('打印过程中出现错误');
- }
- };
- }
- /** 保存HR备注 */
- function saveHrNotes() {
- updateApplicationStatus(applicationDetail.applicationId, applicationDetail.status).then(() => {
- proxy?.$modal.msgSuccess('保存成功');
- applicationDetailOpen.value = false;
- getApplicationList();
- });
- }
- /** 搜索按钮操作 - 申请管理 */
- function handleApplicationQuery() {
- applicationQueryParams.pageNum = 1;
- getApplicationList();
- }
- /** 重置按钮操作 - 申请管理 */
- function resetApplicationQuery() {
- const applicationQueryFormRef = proxy?.$refs.applicationQueryForm as any;
- if (applicationQueryFormRef) {
- applicationQueryFormRef.resetFields();
- }
- applicationQueryParams.jobId = undefined;
- applicationQueryParams.jobTitle = '';
- applicationQueryParams.applicantName = '';
- applicationQueryParams.contactPhone = '';
- applicationQueryParams.status = '';
- handleApplicationQuery();
- }
- /** 多选框选中数据 - 申请管理 */
- function handleApplicationSelectionChange(selection: ApplicationVO[]) {
- applicationIds.value = selection.map((item) => item.applicationId);
- applicationSingle.value = selection.length !== 1;
- applicationMultiple.value = !selection.length;
- }
- /** 上传附件文件 */
- function uploadAttachmentFile(params: any, applicationId: string | number) {
- const file = params.file;
- uploadAttachment(applicationId, file)
- .then((response) => {
- if (response.code === 200) {
- ElMessage.success('附件上传成功');
- // 重新获取申请详情
- getApplication(applicationId as number).then((res) => {
- if (res.code === 200) {
- applicationDetail.attachmentPath = res.data.attachmentPath;
- applicationDetail.attachmentName = res.data.attachmentName;
- }
- });
- getApplicationList(); // 刷新申请列表
- } else {
- ElMessage.error(response.msg || '附件上传失败');
- }
- })
- .catch((error) => {
- console.error('上传附件失败:', error);
- ElMessage.error('附件上传失败');
- });
- }
- /** 预览附件 */
- function previewAttachment(row: ApplicationVO) {
- if (row.attachmentPath) {
- // 使用浏览器原生方法打开附件
- window.open(import.meta.env.VITE_APP_BASE_API + '/' + row.attachmentPath, '_blank');
- } else {
- ElMessage.warning('附件不存在');
- }
- }
- /** 导出简历为PDF */
- function handleExportResume() {
- if (applicationIds.value.length !== 1) {
- proxy?.$modal.msgWarning('请选择一条简历记录');
- return;
- }
- // 获取选中的申请记录
- const selectedId = applicationIds.value[0];
- const selectedRecord = applicationList.value.find((item) => item.applicationId === selectedId);
- if (!selectedRecord) {
- proxy?.$modal.msgError('未找到选中的记录');
- return;
- }
- // 显示加载提示
- proxy?.$modal.loading('正在生成PDF文件,请稍候...');
- try {
- // 创建一个临时的HTML元素来渲染简历内容
- const resumeContainer = document.createElement('div');
- resumeContainer.style.width = '800px';
- resumeContainer.style.padding = '40px';
- resumeContainer.style.position = 'absolute';
- resumeContainer.style.left = '-9999px';
- resumeContainer.style.fontFamily = 'Arial, "Microsoft YaHei", sans-serif'; // 使用系统字体
- // 添加简历内容
- resumeContainer.innerHTML = `
- <div style="text-align: center; margin-bottom: 30px;">
- <h1 style="font-size: 24px; margin-bottom: 10px;">简历详情</h1>
- <div style="border-bottom: 1px solid #ddd; margin-bottom: 20px;"></div>
- </div>
-
- <div style="margin-bottom: 30px;">
- <h2 style="font-size: 18px; margin-bottom: 15px; border-bottom: 1px solid #eee; padding-bottom: 5px;">基本信息</h2>
- <p><strong>姓名:</strong>${selectedRecord.applicantName || '未提供'}</p>
- <p><strong>应聘职位:</strong>${selectedRecord.jobTitle || '未提供'}</p>
- <p><strong>联系电话:</strong>${selectedRecord.contactPhone || '未提供'}</p>
- <p><strong>联系邮箱:</strong>${selectedRecord.contactEmail || '未提供'}</p>
- </div>
-
- <div style="margin-bottom: 30px;">
- <h2 style="font-size: 18px; margin-bottom: 15px; border-bottom: 1px solid #eee; padding-bottom: 5px;">教育背景</h2>
- <p><strong>最高学历:</strong>${selectedRecord.education || '未提供'}</p>
- </div>
-
- <div style="margin-bottom: 30px;">
- <h2 style="font-size: 18px; margin-bottom: 15px; border-bottom: 1px solid #eee; padding-bottom: 5px;">工作经验</h2>
- <p style="white-space: pre-wrap;">${selectedRecord.experience || '未提供工作经验'}</p>
- </div>
-
- <div style="margin-bottom: 30px;">
- <h2 style="font-size: 18px; margin-bottom: 15px; border-bottom: 1px solid #eee; padding-bottom: 5px;">自我介绍</h2>
- <p style="white-space: pre-wrap;">${selectedRecord.selfDescription || '未提供自我介绍'}</p>
- </div>
-
- <div style="margin-top: 50px; text-align: right; font-size: 12px; color: #999;">
- 生成日期:${parseTime(new Date())}
- </div>
- `;
- // 将元素添加到文档中
- document.body.appendChild(resumeContainer);
- // 使用html2canvas将HTML转换为canvas
- html2canvas(resumeContainer, {
- scale: 2, // 提高清晰度
- useCORS: true,
- logging: false
- })
- .then((canvas) => {
- // 从canvas创建PDF
- const imgData = canvas.toDataURL('image/png');
- const pdf = new jsPDF({
- orientation: 'portrait',
- unit: 'mm',
- format: 'a4'
- });
- // 计算PDF页面尺寸和图像比例
- const imgWidth = 210; // A4宽度,单位是mm
- const pageHeight = 297; // A4高度,单位是mm
- const imgHeight = (canvas.height * imgWidth) / canvas.width;
- let heightLeft = imgHeight;
- let position = 0;
- // 添加第一页
- pdf.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight);
- heightLeft -= pageHeight;
- // 如果内容超过一页,添加新页面
- while (heightLeft > 0) {
- position = heightLeft - imgHeight;
- pdf.addPage();
- pdf.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight);
- heightLeft -= pageHeight;
- }
- // 保存PDF
- pdf.save(`简历_${selectedRecord.applicantName}_${new Date().getTime()}.pdf`);
- // 移除临时元素
- document.body.removeChild(resumeContainer);
- proxy?.$modal.closeLoading();
- proxy?.$modal.msgSuccess('PDF导出成功');
- })
- .catch((error) => {
- console.error('PDF生成失败:', error);
- document.body.removeChild(resumeContainer);
- proxy?.$modal.closeLoading();
- proxy?.$modal.msgError('PDF导出失败,请重试');
- });
- } catch (error) {
- console.error('PDF导出失败:', error);
- proxy?.$modal.closeLoading();
- proxy?.$modal.msgError('PDF导出失败,请重试');
- }
- }
- onMounted(() => {
- // 加载招聘职位数据
- getList();
- // 加载简历管理数据,确保第一次进入时简历管理也有数据
- getApplicationList();
- // 加载部门数据,确保部门选项来自数据库
- getDepartmentList();
- });
- </script>
- <style scoped>
- .card-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- }
- .tab-content {
- padding: 20px 0;
- }
- .el-tag {
- margin-right: 5px;
- }
- /* 页面容器样式 */
- .app-container {
- padding: 8px;
- }
- /* 表格卡片布局 */
- .table-card {
- margin-top: 0;
- }
- .table-card :deep(.el-card__body) {
- padding: 0px 20px 20px 20px !important;
- }
- /* 移除按钮栏底部边框 */
- .button-card :deep(.el-card__header) {
- border-bottom: none !important;
- }
- .view-description {
- padding: 12px;
- border: 1px solid #e4e7ed;
- border-radius: 4px;
- width: 100%;
- height: 150px;
- font-size: 14px;
- color: #303133;
- line-height: 1.6;
- white-space: pre-wrap;
- word-break: break-word;
- overflow-y: auto;
- }
- /* 分页容器样式 */
- .pagination-container {
- display: flex;
- justify-content: flex-end;
- padding: 8px 20px 0 0 !important;
- background-color: #fff;
- margin-top: 0px !important;
- }
- .pagination-container :deep(.el-pagination) {
- font-size: 12px;
- }
- .pagination-container :deep(.el-pagination .btn-prev),
- .pagination-container :deep(.el-pagination .btn-next),
- .pagination-container :deep(.el-pagination .el-pager li) {
- min-width: 28px;
- height: 28px;
- line-height: 28px;
- font-size: 12px;
- }
- /* 搜索按钮容器样式 */
- .search-btn-container {
- display: flex;
- justify-content: flex-end;
- margin-top: 10px;
- }
- .search-btn-container :deep(.el-form-item) {
- margin-bottom: 0 !important;
- }
- /* 申请记录样式 */
- .job-info-header {
- margin-bottom: 8px;
- }
- /* 紧凑型职位信息样式 */
- .job-info-compact {
- display: flex;
- align-items: center;
- padding: 6px 10px;
- background: #f8f9fa;
- border: 1px solid #e1e8ed;
- border-radius: 4px;
- gap: 8px;
- flex-wrap: wrap;
- min-height: 36px;
- }
- .info-item {
- display: flex;
- align-items: center;
- gap: 3px;
- height: 24px;
- }
- .info-label {
- font-size: 13px;
- color: #606266;
- font-weight: 500;
- line-height: 1.3;
- }
- .info-value {
- font-size: 13px;
- color: #303133;
- font-weight: 600;
- line-height: 1.3;
- }
- .info-value.highlight {
- color: #409eff;
- font-size: 14px;
- font-weight: 700;
- line-height: 1.3;
- }
- .info-divider {
- color: #dcdfe6;
- font-size: 13px;
- margin: 0 4px;
- line-height: 1.3;
- }
- .application-table {
- margin-top: 8px;
- }
- .application-table .el-table {
- width: 100%;
- }
- .application-table .el-table__body-wrapper {
- overflow-x: hidden;
- }
- /* 弹窗内容区域优化 */
- .el-dialog__body {
- padding: 15px 20px 0 20px !important;
- }
- .el-dialog__footer {
- padding: 10px 20px 15px 20px !important;
- }
- .mt-4 {
- margin-top: 16px;
- }
- /* 操作列样式 */
- .action-buttons {
- display: flex;
- align-items: center;
- gap: 2px;
- flex-wrap: wrap;
- justify-content: center;
- .el-button {
- margin: 0;
- padding: 2px 6px;
- font-size: 11px;
- min-height: 20px;
- }
- .status-selector {
- .el-select {
- .el-input {
- font-size: 12px;
- }
- }
- }
- }
- /* 操作列表格样式优化 */
- .el-table {
- .small-padding {
- .cell {
- padding: 8px 4px;
- }
- }
- }
- /* 紧凑表格样式 */
- .compact-table {
- font-size: 13px;
- :deep(.el-table__header) {
- th {
- padding: 4px 0;
- font-size: 13px;
- height: 32px;
- }
- }
- :deep(.el-table__body) {
- td {
- padding: 4px 0;
- font-size: 13px;
- }
- }
- :deep(.cell) {
- padding: 0 4px;
- line-height: 1.3;
- word-break: keep-all;
- white-space: nowrap;
- }
- /* 固定列样式优化 */
- :deep(.el-table__fixed-right) {
- box-shadow: -2px 0 6px rgba(0, 0, 0, 0.1);
- }
- :deep(.el-table__fixed-right-patch) {
- background-color: #f5f7fa;
- }
- /* 确保固定列正常显示 */
- :deep(.el-table__fixed-right .el-table__fixed-body-wrapper) {
- background-color: #fff;
- }
- }
- </style>
|