You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1623 lines
50 KiB

  1. <template>
  2. <div class="app-container">
  3. <!-- 搜索部分 -->
  4. <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="90px">
  5. <el-form-item label="真实姓名" prop="realName">
  6. <el-input
  7. v-model="queryParams.realName"
  8. placeholder="请输入真实姓名"
  9. clearable
  10. @keyup.enter.native="handleQuery"
  11. />
  12. </el-form-item>
  13. <el-form-item label="性别" prop="gender">
  14. <el-input
  15. v-model="queryParams.gender"
  16. placeholder="请输入性别"
  17. clearable
  18. @keyup.enter.native="handleQuery"
  19. />
  20. </el-form-item>
  21. <el-form-item label="身份证号" prop="idCard">
  22. <el-input
  23. v-model="queryParams.idCard"
  24. placeholder="请输入身份证号"
  25. clearable
  26. @keyup.enter.native="handleQuery"
  27. />
  28. </el-form-item>
  29. <el-form-item label="工作经验" prop="workExperience">
  30. <el-input
  31. v-model="queryParams.workExperience"
  32. placeholder="请输入工作经验"
  33. clearable
  34. @keyup.enter.native="handleQuery"
  35. />
  36. </el-form-item>
  37. <el-form-item label="所属医院" prop="hospital">
  38. <el-input
  39. v-model="queryParams.hospital"
  40. placeholder="请输入所属医院"
  41. clearable
  42. @keyup.enter.native="handleQuery"
  43. />
  44. </el-form-item>
  45. <el-form-item>
  46. <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
  47. <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
  48. </el-form-item>
  49. </el-form>
  50. <el-row :gutter="10" class="mb8">
  51. <el-col :span="1.5">
  52. <el-button
  53. type="primary"
  54. plain
  55. icon="el-icon-plus"
  56. size="mini"
  57. @click="handleAdd"
  58. v-hasPermi="['vet:info:add']"
  59. >新增</el-button>
  60. </el-col>
  61. <el-col :span="1.5">
  62. <el-button
  63. type="success"
  64. plain
  65. icon="el-icon-edit"
  66. size="mini"
  67. :disabled="single"
  68. @click="handleUpdate"
  69. v-hasPermi="['vet:info:edit']"
  70. >修改</el-button>
  71. </el-col>
  72. <el-col :span="1.5">
  73. <el-button
  74. type="danger"
  75. plain
  76. icon="el-icon-delete"
  77. size="mini"
  78. :disabled="multiple"
  79. @click="handleDelete"
  80. v-hasPermi="['vet:info:remove']"
  81. >删除</el-button>
  82. </el-col>
  83. <el-col :span="1.5">
  84. <el-button
  85. type="warning"
  86. plain
  87. icon="el-icon-check"
  88. size="mini"
  89. :disabled="single"
  90. @click="handleAudit"
  91. v-hasPermi="['sys:vetAudit:audit']"
  92. >审核</el-button>
  93. </el-col>
  94. <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
  95. </el-row>
  96. <!-- 表格部分 -->
  97. <el-table v-loading="loading" :data="infoList" @selection-change="handleSelectionChange">
  98. <el-table-column type="selection" width="55" align="center" />
  99. <el-table-column label="用户昵称" align="center" prop="nickName" width="200px"/>
  100. <el-table-column label="真实姓名" align="center" prop="realName" width="200px"/>
  101. <el-table-column label="性别" align="center" prop="gender" width="100px"/>
  102. <el-table-column label="出生日期" align="center" prop="birthday" width="200px">
  103. <template slot-scope="scope">
  104. <span>{{ parseTime(scope.row.birthday, '{y}-{m}-{d}') }}</span>
  105. </template>
  106. </el-table-column>
  107. <el-table-column label="身份证号" align="center" prop="idCard" width="200px"/>
  108. <!-- <el-table-column label="擅长领域" align="center" prop="specialty" width="300px" :show-overflow-tooltip="true"/>-->
  109. <!-- <el-table-column label="工作经验" align="center" prop="workExperience" width="100px"/>-->
  110. <el-table-column label="职称" align="center" prop="title" width="200px"/>
  111. <el-table-column label="联系电话" align="center" prop="phone" width="200px"/>
  112. <!-- <el-table-column label="电子邮箱" align="center" prop="email"/>-->
  113. <el-table-column label="专家类型" align="center" prop="expertType" width="200px"/>
  114. <el-table-column label="所属医院" align="center" prop="hospital" width="300px" :show-overflow-tooltip="true"/>
  115. <!-- <el-table-column label="联系地址" align="center" prop="address" />-->
  116. <!-- <el-table-column label="个人简介" align="center" prop="introduction" />-->
  117. <el-table-column label="审核状态" align="center" prop="auditStatus" width="100" class-name="audit-status-column">
  118. <template slot-scope="scope">
  119. <el-tag :type="getAuditStatusTagType(scope.row.auditStatus)" size="small">
  120. {{ getAuditStatusText(scope.row.auditStatus) }}
  121. </el-tag>
  122. </template>
  123. </el-table-column>
  124. <el-table-column label="操作" align="center" class-name="small-padding fixed-width" fixed="right" width="220">
  125. <template slot-scope="scope">
  126. <el-button
  127. size="mini"
  128. type="text"
  129. icon="el-icon-view"
  130. class="info-btn view-btn"
  131. @click="handleView(scope.row)"
  132. v-hasPermi="['sys:vetAudit:view']"
  133. >详情</el-button>
  134. <el-button
  135. size="mini"
  136. type="text"
  137. icon="el-icon-check"
  138. style="color: #072eed"
  139. class="info-btn audit-btn"
  140. @click="handleAudit(scope.row)"
  141. v-hasPermi="['sys:vetAudit:auditVetPersonalInfo']"
  142. >审核</el-button>
  143. </template>
  144. </el-table-column>
  145. </el-table>
  146. <div class="pagestyle">
  147. <pagination
  148. v-show="total>0"
  149. :total="total"
  150. :page.sync="queryParams.pageNum"
  151. :limit.sync="queryParams.pageSize"
  152. @pagination="getList"
  153. />
  154. </div>
  155. <!-- 审核对话框 -->
  156. <el-dialog
  157. :title="auditTitle"
  158. :visible.sync="auditVisible"
  159. width="80%"
  160. append-to-body
  161. :close-on-click-modal="false"
  162. class="audit-dialog"
  163. >
  164. <el-tabs v-model="activeAuditTab" type="border-card" @tab-click="handleTabClick">
  165. <!-- 基本信息审核标签页 -->
  166. <el-tab-pane label="基本信息审核" name="basic">
  167. <div v-if="loadingBasicData" class="tab-loading">
  168. <i class="el-icon-loading"></i>
  169. <div>加载基本信息...</div>
  170. </div>
  171. <div v-else>
  172. <div class="info-section">
  173. <h3>兽医基本信息</h3>
  174. <el-descriptions :column="2" border>
  175. <el-descriptions-item label="真实姓名">{{ basicInfo.realName || '-' }}</el-descriptions-item>
  176. <el-descriptions-item label="性别">{{ basicInfo.gender || '-' }}</el-descriptions-item>
  177. <el-descriptions-item label="出生日期">{{ parseTime(basicInfo.birthday, '{y}-{m}-{d}') || '-' }}</el-descriptions-item>
  178. <el-descriptions-item label="身份证号">{{ basicInfo.idCard || '-' }}</el-descriptions-item>
  179. <el-descriptions-item label="职称">{{ basicInfo.title || '-' }}</el-descriptions-item>
  180. <el-descriptions-item label="联系电话">{{ basicInfo.phone || '-' }}</el-descriptions-item>
  181. <el-descriptions-item label="电子邮箱">{{ basicInfo.email || '-' }}</el-descriptions-item>
  182. <el-descriptions-item label="专家类型">
  183. <dict-tag :options="dict.type.expert_type" :value="basicInfo.expertType"/>
  184. </el-descriptions-item>
  185. <el-descriptions-item label="所属医院">{{ basicInfo.hospital || '-' }}</el-descriptions-item>
  186. <el-descriptions-item label="联系地址" :span="2">{{ basicInfo.address || '-' }}</el-descriptions-item>
  187. <el-descriptions-item label="个人简介" :span="2">{{ basicInfo.introduction || '-' }}</el-descriptions-item>
  188. <el-descriptions-item label="当前审核状态">
  189. <el-tag :type="getAuditStatusTagType(basicInfo.auditStatus)" size="small">
  190. {{ getAuditStatusText(basicInfo.auditStatus) }}
  191. </el-tag>
  192. </el-descriptions-item>
  193. <el-descriptions-item label="审核人">{{ basicInfo.auditor || '-' }}</el-descriptions-item>
  194. <el-descriptions-item label="审核时间">{{ parseTime(basicInfo.auditTime) || '-' }}</el-descriptions-item>
  195. <el-descriptions-item label="审核意见" :span="2">{{ basicInfo.auditDesc || '-' }}</el-descriptions-item>
  196. </el-descriptions>
  197. </div>
  198. <div class="audit-form-section">
  199. <h3>基本信息审核</h3>
  200. <el-form ref="basicAuditForm" :model="basicAuditForm" :rules="basicAuditRules" label-width="100px">
  201. <el-form-item label="审核结果" prop="auditStatus">
  202. <el-radio-group v-model="basicAuditForm.auditStatus">
  203. <el-radio label="1">审核通过</el-radio>
  204. <el-radio label="2">审核不通过</el-radio>
  205. </el-radio-group>
  206. <span v-if="basicInfo.auditStatus && basicInfo.auditStatus !== '0'" class="audit-status-tag">
  207. <el-tag :type="getAuditStatusTagType(basicInfo.auditStatus)" size="small">
  208. {{ getAuditStatusText(basicInfo.auditStatus) }}
  209. </el-tag>
  210. </span>
  211. </el-form-item>
  212. <el-form-item label="审核意见" prop="auditDesc">
  213. <el-input
  214. v-model="basicAuditForm.auditDesc"
  215. type="textarea"
  216. :rows="4"
  217. placeholder="请输入审核意见"
  218. :maxlength="500"
  219. show-word-limit
  220. />
  221. </el-form-item>
  222. </el-form>
  223. </div>
  224. </div>
  225. </el-tab-pane>
  226. <!-- 资质证书审核标签页 -->
  227. <el-tab-pane label="资质证书审核" name="certificate" v-if="showCertificateTab">
  228. <div v-if="loadingCertData" class="tab-loading">
  229. <i class="el-icon-loading"></i>
  230. <div>加载证书信息...</div>
  231. </div>
  232. <div v-else>
  233. <div v-if="!certificateList || certificateList.length === 0" class="no-data">
  234. <el-alert
  235. title="该兽医暂无资质证书"
  236. type="info"
  237. :closable="false"
  238. show-icon
  239. />
  240. </div>
  241. <div v-else>
  242. <div class="cert-summary" v-if="certificateList.length > 0">
  243. <el-alert
  244. :title="getCertSummaryText()"
  245. type="info"
  246. :closable="false"
  247. show-icon
  248. />
  249. </div>
  250. <el-tabs v-model="activeCertTab" type="card" class="cert-tabs">
  251. <el-tab-pane
  252. v-for="(cert, index) in certificateList"
  253. :key="cert.qualificationId"
  254. :label="cert.certName || cert.qualificationType || `证书${index + 1}`"
  255. :name="'cert' + cert.qualificationId"
  256. >
  257. <div class="certificate-item" :class="{'cert-audited': cert.auditStatus && cert.auditStatus !== '0'}">
  258. <div class="cert-header">
  259. <div class="cert-title">
  260. <span>{{ cert.certName || cert.qualificationType || '未命名证书' }}</span>
  261. <el-tag
  262. v-if="cert.auditStatus === '1'"
  263. type="success"
  264. size="small"
  265. class="cert-status-tag"
  266. effect="dark"
  267. >
  268. <i class="el-icon-success"></i> 已通过
  269. </el-tag>
  270. <el-tag
  271. v-if="cert.auditStatus === '2'"
  272. type="danger"
  273. size="small"
  274. class="cert-status-tag"
  275. effect="dark"
  276. >
  277. <i class="el-icon-error"></i> 未通过
  278. </el-tag>
  279. <el-tag
  280. v-if="!cert.auditStatus || cert.auditStatus === '0'"
  281. type="warning"
  282. size="small"
  283. class="cert-status-tag"
  284. effect="dark"
  285. >
  286. <i class="el-icon-time"></i> 待审核
  287. </el-tag>
  288. </div>
  289. <div class="cert-info">
  290. <span><strong>证书编号</strong>{{ cert.certificateNo || '-' }}</span>
  291. <span><strong>发证机构</strong>{{ cert.issueOrg || '-' }}</span>
  292. <span><strong>资质类型</strong>{{ cert.qualificationType || '-' }}</span>
  293. <span><strong>证书类型</strong>{{ cert.certType || '-' }}</span>
  294. <span><strong>颁发日期</strong>{{ parseTime(cert.issueDate, '{y}-{m}-{d}') || '-' }}</span>
  295. <span><strong>到期日期</strong>{{ parseTime(cert.expireDate, '{y}-{m}-{d}') || '-' }}</span>
  296. <span><strong>证书状态</strong>{{ cert.certStatus || '-' }}</span>
  297. </div>
  298. <div v-if="cert.certImage" class="cert-image-section">
  299. <div class="image-title">
  300. <strong>证书图片</strong>
  301. </div>
  302. <div class="image-preview">
  303. <el-image
  304. style="width: 200px; height: 150px;"
  305. :src="baseUrl + cert.certImage"
  306. :preview-src-list="[baseUrl + cert.certImage]"
  307. fit="contain"
  308. >
  309. <div slot="error" class="image-slot">
  310. <i class="el-icon-picture-outline"></i>
  311. <div>图片加载失败</div>
  312. </div>
  313. </el-image>
  314. </div>
  315. </div>
  316. <div v-if="cert.certificateFiles" class="cert-files-section">
  317. <div class="files-title">
  318. <strong>其他附件</strong>
  319. </div>
  320. <div class="files-list">
  321. <el-button
  322. type="text"
  323. icon="el-icon-download"
  324. @click="downloadFile(cert.certificateFiles)"
  325. class="download-btn"
  326. >
  327. {{ getFileName(cert.certificateFiles) }}
  328. </el-button>
  329. </div>
  330. </div>
  331. </div>
  332. <div class="cert-audit-form">
  333. <el-form :ref="'certForm' + cert.qualificationId"
  334. :model="certAuditForms[cert.qualificationId]"
  335. :rules="certAuditRules"
  336. label-width="100px">
  337. <el-form-item label="审核结果" prop="auditStatus">
  338. <el-radio-group v-model="certAuditForms[cert.qualificationId].auditStatus"
  339. @change="handleCertAuditChange(cert.qualificationId)">
  340. <el-radio label="1">审核通过</el-radio>
  341. <el-radio label="2">审核不通过</el-radio>
  342. </el-radio-group>
  343. <span v-if="certAuditForms[cert.qualificationId].submitted" class="audit-saved-tag">
  344. <el-tag type="success" size="small">已保存</el-tag>
  345. </span>
  346. </el-form-item>
  347. <el-form-item label="审核意见" prop="auditOpinion">
  348. <el-input
  349. v-model="certAuditForms[cert.qualificationId].auditOpinion"
  350. type="textarea"
  351. :rows="4"
  352. placeholder="请输入审核意见"
  353. :maxlength="200"
  354. show-word-limit
  355. @blur="saveCertificateAudit(cert.qualificationId)"
  356. />
  357. </el-form-item>
  358. <el-form-item>
  359. <el-button
  360. type="primary"
  361. @click="saveCertificateAudit(cert.qualificationId)"
  362. :loading="certAuditForms[cert.qualificationId] && certAuditForms[cert.qualificationId].saving"
  363. >
  364. 保存审核
  365. </el-button>
  366. <el-button @click="resetCertAudit(cert.qualificationId)">重置</el-button>
  367. </el-form-item>
  368. </el-form>
  369. </div>
  370. </div>
  371. </el-tab-pane>
  372. </el-tabs>
  373. </div>
  374. </div>
  375. </el-tab-pane>
  376. </el-tabs>
  377. <div slot="footer" class="dialog-footer">
  378. <el-button type="primary" @click="submitAllAudit" :loading="submittingAll">
  379. {{ submittingAll ? '提交中...' : '提交审核' }}
  380. </el-button>
  381. <el-button @click="auditVisible = false"> </el-button>
  382. </div>
  383. </el-dialog>
  384. <!-- 详情对话框 -->
  385. <el-dialog
  386. :title="detailTitle"
  387. :visible.sync="detailVisible"
  388. width="80%"
  389. append-to-body
  390. >
  391. <div v-if="loadingDetail" class="tab-loading">
  392. <i class="el-icon-loading"></i>
  393. <div>加载详情信息...</div>
  394. </div>
  395. <div v-else-if="detailData">
  396. <el-tabs v-model="detailActiveTab" type="border-card">
  397. <el-tab-pane label="基本信息" name="basicInfo">
  398. <div class="info-section">
  399. <h3>兽医详细信息</h3>
  400. <el-descriptions :column="2" border>
  401. <el-descriptions-item label="用户昵称">{{ detailData.nickName || '-' }}</el-descriptions-item>
  402. <el-descriptions-item label="真实姓名">{{ detailData.realName || '-' }}</el-descriptions-item>
  403. <el-descriptions-item label="性别">{{ detailData.gender || '-' }}</el-descriptions-item>
  404. <el-descriptions-item label="出生日期">{{ parseTime(detailData.birthday, '{y}-{m}-{d}') || '-' }}</el-descriptions-item>
  405. <el-descriptions-item label="身份证号">{{ detailData.idCard || '-' }}</el-descriptions-item>
  406. <el-descriptions-item label="职称">{{ detailData.title || '-' }}</el-descriptions-item>
  407. <el-descriptions-item label="联系电话">{{ detailData.phone || '-' }}</el-descriptions-item>
  408. <el-descriptions-item label="电子邮箱">{{ detailData.email || '-' }}</el-descriptions-item>
  409. <el-descriptions-item label="专家类型">
  410. <dict-tag :options="dict.type.expert_type" :value="detailData.expertType"/>
  411. </el-descriptions-item>
  412. <el-descriptions-item label="所属医院">{{ detailData.hospital || '-' }}</el-descriptions-item>
  413. <el-descriptions-item label="联系地址">{{ detailData.address || '-' }}</el-descriptions-item>
  414. <el-descriptions-item label="擅长领域">{{ detailData.specialty || '-' }}</el-descriptions-item>
  415. <el-descriptions-item label="工作经验">{{ detailData.workExperience || '-' }}</el-descriptions-item>
  416. <el-descriptions-item label="个人简介" :span="2">{{ detailData.introduction || '-' }}</el-descriptions-item>
  417. <el-descriptions-item label="当前审核状态">
  418. <el-tag :type="getAuditStatusTagType(detailData.auditStatus)" size="small">
  419. {{ getAuditStatusText(detailData.auditStatus) }}
  420. </el-tag>
  421. </el-descriptions-item>
  422. <el-descriptions-item label="审核人">{{ detailData.auditor || '-' }}</el-descriptions-item>
  423. <el-descriptions-item label="审核时间">{{ parseTime(detailData.auditTime) || '-' }}</el-descriptions-item>
  424. <el-descriptions-item label="审核意见" :span="2">{{ detailData.auditDesc || '-' }}</el-descriptions-item>
  425. </el-descriptions>
  426. </div>
  427. </el-tab-pane>
  428. <el-tab-pane label="资质证书" name="certificates" v-if="detailCertificates && detailCertificates.length > 0">
  429. <div class="certificate-section">
  430. <h3>资质证书列表 {{ detailCertificates.length }} 个证书</h3>
  431. <el-tabs v-model="detailCertActiveTab" type="card" class="cert-tabs">
  432. <el-tab-pane
  433. v-for="(cert, index) in detailCertificates"
  434. :key="cert.qualificationId"
  435. :label="cert.certName || cert.qualificationType || `证书${index + 1}`"
  436. :name="'detailCert' + cert.qualificationId"
  437. >
  438. <div class="certificate-item view-only">
  439. <div class="cert-header">
  440. <div class="cert-title">
  441. <span>{{ cert.certName || cert.qualificationType || '未命名证书' }}</span>
  442. <el-tag
  443. v-if="cert.auditStatus === '1'"
  444. type="success"
  445. size="small"
  446. class="cert-status-tag"
  447. effect="dark"
  448. >
  449. <i class="el-icon-success"></i> 已通过
  450. </el-tag>
  451. <el-tag
  452. v-if="cert.auditStatus === '2'"
  453. type="danger"
  454. size="small"
  455. class="cert-status-tag"
  456. effect="dark"
  457. >
  458. <i class="el-icon-error"></i> 未通过
  459. </el-tag>
  460. <el-tag
  461. v-if="!cert.auditStatus || cert.auditStatus === '0'"
  462. type="warning"
  463. size="small"
  464. class="cert-status-tag"
  465. effect="dark"
  466. >
  467. <i class="el-icon-time"></i> 待审核
  468. </el-tag>
  469. </div>
  470. <div class="cert-info">
  471. <span><strong>证书编号</strong>{{ cert.certificateNo || '-' }}</span>
  472. <span><strong>发证机构</strong>{{ cert.issueOrg || '-' }}</span>
  473. <span><strong>资质类型</strong>{{ cert.qualificationType || '-' }}</span>
  474. <span><strong>证书类型</strong>{{ cert.certType || '-' }}</span>
  475. <span><strong>颁发日期</strong>{{ parseTime(cert.issueDate, '{y}-{m}-{d}') || '-' }}</span>
  476. <span><strong>到期日期</strong>{{ parseTime(cert.expireDate, '{y}-{m}-{d}') || '-' }}</span>
  477. <span><strong>证书状态</strong>{{ cert.certStatus || '-' }}</span>
  478. <span><strong>审核状态</strong>
  479. <el-tag :type="getAuditStatusTagType(cert.auditStatus)" size="small">
  480. {{ getAuditStatusText(cert.auditStatus) }}
  481. </el-tag>
  482. </span>
  483. <span><strong>审核意见</strong>{{ cert.auditOpinion || '-' }}</span>
  484. <span><strong>审核时间</strong>{{ parseTime(cert.auditTime) || '-' }}</span>
  485. </div>
  486. <div v-if="cert.certImage" class="cert-image-section">
  487. <div class="image-title">
  488. <strong>证书图片</strong>
  489. </div>
  490. <div class="image-preview">
  491. <el-image
  492. style="width: 200px; height: 150px;"
  493. :src="baseUrl + cert.certImage"
  494. :preview-src-list="[baseUrl + cert.certImage]"
  495. fit="contain"
  496. >
  497. <div slot="error" class="image-slot">
  498. <i class="el-icon-picture-outline"></i>
  499. <div>图片加载失败</div>
  500. </div>
  501. </el-image>
  502. </div>
  503. </div>
  504. <div v-if="cert.certificateFiles" class="cert-files-section">
  505. <div class="files-title">
  506. <strong>其他附件</strong>
  507. </div>
  508. <div class="files-list">
  509. <el-button
  510. type="text"
  511. icon="el-icon-download"
  512. @click="downloadFile(cert.certificateFiles)"
  513. class="download-btn"
  514. >
  515. {{ getFileName(cert.certificateFiles) }}
  516. </el-button>
  517. </div>
  518. </div>
  519. </div>
  520. </div>
  521. </el-tab-pane>
  522. </el-tabs>
  523. </div>
  524. </el-tab-pane>
  525. </el-tabs>
  526. </div>
  527. <span slot="footer" class="dialog-footer">
  528. <el-button @click="detailVisible = false"> </el-button>
  529. </span>
  530. </el-dialog>
  531. </div>
  532. </template>
  533. <script>
  534. import { listInfo, getInfo, auditBasicInfo, auditCertificate, listQualification } from "@/api/system/vetAduit"
  535. import axios from 'axios'
  536. export default {
  537. name: "Info",
  538. dicts: ['expert_type'],
  539. data() {
  540. return {
  541. loading: true,
  542. ids: [],
  543. single: true,
  544. multiple: true,
  545. showSearch: true,
  546. total: 0,
  547. infoList: [],
  548. baseUrl: process.env.VUE_APP_BASE_API,
  549. detailTitle: "",
  550. detailVisible: false,
  551. detailData: null,
  552. loadingDetail: false,
  553. detailActiveTab: "basicInfo",
  554. detailCertificates: [],
  555. loadingCertDetail: false,
  556. detailCertActiveTab: null,
  557. auditTitle: "",
  558. auditVisible: false,
  559. activeAuditTab: "basic",
  560. activeCertTab: null,
  561. currentVetId: null,
  562. currentUserId: null,
  563. showCertificateTab: true,
  564. loadingBasicData: false,
  565. submittingAll: false,
  566. basicInfo: {},
  567. basicAuditForm: {
  568. auditStatus: "",
  569. auditDesc: ""
  570. },
  571. basicAuditRules: {
  572. auditStatus: [
  573. { required: true, message: "请选择审核结果", trigger: "change" }
  574. ]
  575. },
  576. loadingCertData: false,
  577. certificateList: [],
  578. certAuditForms: {},
  579. certAuditRules: {
  580. auditStatus: [
  581. { required: true, message: "请选择审核结果", trigger: "change" }
  582. ]
  583. },
  584. imagePreviewVisible: false,
  585. previewImageUrl: "",
  586. certAuditTimer: null,
  587. queryParams: {
  588. pageNum: 1,
  589. pageSize: 10,
  590. realName: null,
  591. gender: null,
  592. idCard: null,
  593. workExperience: null,
  594. hospital: null,
  595. },
  596. title: "",
  597. open: false,
  598. form: {},
  599. rules: {
  600. realName: [
  601. { required: true, message: "真实姓名不能为空", trigger: "blur" }
  602. ],
  603. gender: [
  604. { required: true, message: "性别不能为空", trigger: "change" }
  605. ],
  606. idCard: [
  607. { required: true, message: "身份证号不能为空", trigger: "blur" }
  608. ]
  609. }
  610. }
  611. },
  612. computed: {
  613. canCompleteAudit() {
  614. if (this.basicInfo.auditStatus && this.basicInfo.auditStatus !== '0') {
  615. return true
  616. }
  617. if (this.basicAuditForm.auditStatus) {
  618. return true
  619. }
  620. return false
  621. }
  622. },
  623. created() {
  624. this.getList()
  625. },
  626. methods: {
  627. getList() {
  628. this.loading = true
  629. listInfo(this.queryParams).then(response => {
  630. this.infoList = response.rows
  631. this.total = response.total
  632. this.loading = false
  633. }).catch(() => {
  634. this.loading = false
  635. })
  636. },
  637. handleAudit(row) {
  638. this.resetAuditData()
  639. const id = row.id || this.ids[0]
  640. const vetName = row.realName || ''
  641. this.currentVetId = id
  642. this.auditTitle = `兽医信息审核 - ${vetName}`
  643. this.auditVisible = true
  644. this.activeAuditTab = "basic"
  645. this.loadBasicData(id)
  646. },
  647. handleTabClick(tab) {
  648. if (tab.name === 'certificate' && (!this.certificateList || this.certificateList.length === 0)) {
  649. if (this.basicInfo && this.basicInfo.userId) {
  650. this.loadCertificateData(this.basicInfo.userId)
  651. } else {
  652. this.$message.warning('无法获取用户信息')
  653. }
  654. }
  655. },
  656. loadBasicData(id) {
  657. this.loadingBasicData = true
  658. getInfo(id).then(response => {
  659. if (response.code === 200) {
  660. this.basicInfo = response.data || {}
  661. this.currentUserId = this.basicInfo.userId
  662. this.basicAuditForm = {
  663. auditStatus: this.basicInfo.auditStatus || "",
  664. auditDesc: this.basicInfo.auditDesc || ""
  665. }
  666. } else {
  667. this.$message.error(response.msg || '加载失败')
  668. }
  669. }).catch(error => {
  670. console.error('加载失败:', error)
  671. this.$message.error('加载失败')
  672. }).finally(() => {
  673. this.loadingBasicData = false
  674. })
  675. },
  676. loadCertificateData(userId) {
  677. this.loadingCertData = true
  678. const queryParams = {
  679. userId: userId,
  680. pageNum: 1,
  681. pageSize: 1000
  682. }
  683. listQualification(queryParams).then(response => {
  684. if (response.code === 200) {
  685. this.certificateList = response.rows || []
  686. if (this.certificateList.length === 0) {
  687. this.$message.info('该兽医暂无资质证书')
  688. } else {
  689. if (this.certificateList.length > 0) {
  690. this.activeCertTab = 'cert' + this.certificateList[0].qualificationId
  691. }
  692. }
  693. const forms = {}
  694. this.certificateList.forEach(cert => {
  695. forms[cert.qualificationId] = {
  696. qualificationId: cert.qualificationId,
  697. auditStatus: cert.auditStatus || "",
  698. auditOpinion: cert.auditOpinion || "",
  699. submitted: !!cert.auditStatus && cert.auditStatus !== '0',
  700. saving: false
  701. }
  702. })
  703. this.certAuditForms = forms
  704. } else {
  705. this.$message.error(response.msg || '加载证书列表失败')
  706. }
  707. }).catch(error => {
  708. console.error('加载证书列表失败:', error)
  709. this.$message.error('加载证书列表失败')
  710. }).finally(() => {
  711. this.loadingCertData = false
  712. })
  713. },
  714. handleCertAuditChange(qualificationId) {
  715. if (this.certAuditForms[qualificationId]) {
  716. this.certAuditForms[qualificationId].submitted = false
  717. }
  718. },
  719. saveCertificateAudit(qualificationId) {
  720. const formRef = this.$refs['certForm' + qualificationId]
  721. if (!formRef || !formRef[0]) return
  722. formRef[0].validate(valid => {
  723. if (valid) {
  724. const form = this.certAuditForms[qualificationId]
  725. if (!form.auditStatus) {
  726. this.$message.warning('请选择审核结果')
  727. return
  728. }
  729. form.saving = true
  730. const auditData = {
  731. qualificationId: qualificationId,
  732. auditStatus: form.auditStatus,
  733. auditOpinion: form.auditOpinion || ''
  734. }
  735. auditCertificate(auditData).then(response => {
  736. if (response.code === 200) {
  737. form.submitted = true
  738. const certIndex = this.certificateList.findIndex(c => c.qualificationId === qualificationId)
  739. if (certIndex !== -1) {
  740. this.certificateList[certIndex].auditStatus = form.auditStatus
  741. this.certificateList[certIndex].auditOpinion = form.auditOpinion
  742. }
  743. this.$message.success('证书审核已保存')
  744. } else {
  745. this.$message.error(response.msg || '保存失败')
  746. }
  747. }).catch(error => {
  748. console.error('保存证书审核失败:', error)
  749. this.$message.error('保存失败')
  750. }).finally(() => {
  751. form.saving = false
  752. })
  753. }
  754. })
  755. },
  756. resetCertAudit(qualificationId) {
  757. const cert = this.certificateList.find(c => c.qualificationId === qualificationId)
  758. if (cert) {
  759. this.certAuditForms[qualificationId] = {
  760. qualificationId: cert.qualificationId,
  761. auditStatus: cert.auditStatus || "",
  762. auditOpinion: cert.auditOpinion || "",
  763. submitted: !!cert.auditStatus && cert.auditStatus !== '0',
  764. saving: false
  765. }
  766. this.$message.info('已重置审核表单')
  767. }
  768. },
  769. submitAllAudit() {
  770. this.$refs.basicAuditForm.validate(valid => {
  771. if (!valid) {
  772. this.$message.warning('请完成基本信息审核')
  773. this.activeAuditTab = 'basic'
  774. return
  775. }
  776. let allCertAudited = true
  777. if (this.certificateList.length > 0) {
  778. for (let i = 0; i < this.certificateList.length; i++) {
  779. const cert = this.certificateList[i]
  780. const form = this.certAuditForms[cert.qualificationId]
  781. if (!form || !form.submitted) {
  782. allCertAudited = false
  783. break
  784. }
  785. }
  786. if (!allCertAudited) {
  787. this.$message.warning('请完成所有证书的审核')
  788. this.activeAuditTab = 'certificate'
  789. return
  790. }
  791. }
  792. this.submittingAll = true
  793. const auditData = {
  794. id: this.currentVetId,
  795. auditStatus: this.basicAuditForm.auditStatus,
  796. auditDesc: this.basicAuditForm.auditDesc
  797. }
  798. auditBasicInfo(auditData).then(response => {
  799. if (response.code === 200) {
  800. this.$message.success('审核提交成功')
  801. this.auditVisible = false
  802. this.getList()
  803. } else {
  804. this.$message.error(response.msg || '提交失败')
  805. }
  806. }).catch(error => {
  807. console.error('提交失败:', error)
  808. this.$message.error('提交失败')
  809. }).finally(() => {
  810. this.submittingAll = false
  811. })
  812. })
  813. },
  814. getCertSummaryText() {
  815. if (this.certificateList.length === 0) {
  816. return '暂无资质证书'
  817. }
  818. const total = this.certificateList.length
  819. const audited = Object.values(this.certAuditForms).filter(f => f.submitted).length
  820. const passed = this.certificateList.filter(c => c.auditStatus === '1').length
  821. const failed = this.certificateList.filter(c => c.auditStatus === '2').length
  822. return `${total} 个证书,已审核 ${audited} 个,其中通过 ${passed} 个,不通过 ${failed}`
  823. },
  824. resetAuditData() {
  825. this.basicInfo = {}
  826. this.basicAuditForm = {
  827. auditStatus: "",
  828. auditDesc: ""
  829. }
  830. this.certificateList = []
  831. this.certAuditForms = {}
  832. this.currentVetId = null
  833. this.currentUserId = null
  834. this.activeCertTab = null
  835. if (this.certAuditTimer) {
  836. clearTimeout(this.certAuditTimer)
  837. this.certAuditTimer = null
  838. }
  839. },
  840. handleView(row) {
  841. this.detailVisible = true
  842. this.detailTitle = "兽医详情信息"
  843. this.loadingDetail = true
  844. this.detailActiveTab = "basicInfo"
  845. this.detailCertificates = []
  846. const id = row.id || this.ids[0]
  847. getInfo(id).then(response => {
  848. if (response.code === 200) {
  849. this.detailData = response.data
  850. if (response.data.userId) {
  851. const queryParams = {
  852. userId: response.data.userId,
  853. pageNum: 1,
  854. pageSize: 1000
  855. }
  856. listQualification(queryParams).then(certResponse => {
  857. if (certResponse.code === 200) {
  858. this.detailCertificates = certResponse.rows || []
  859. if (this.detailCertificates.length > 0) {
  860. this.detailCertActiveTab = 'detailCert' + this.detailCertificates[0].qualificationId
  861. }
  862. }
  863. }).catch(error => {
  864. console.error('加载证书详情失败:', error)
  865. }).finally(() => {
  866. this.loadingDetail = false
  867. })
  868. } else {
  869. this.loadingDetail = false
  870. }
  871. } else {
  872. this.$message.error(response.msg || '获取详情失败')
  873. this.loadingDetail = false
  874. }
  875. }).catch(error => {
  876. console.error('获取详情失败:', error)
  877. this.$message.error('获取详情失败')
  878. this.loadingDetail = false
  879. })
  880. },
  881. handleQuery() {
  882. this.queryParams.pageNum = 1
  883. this.getList()
  884. },
  885. resetQuery() {
  886. this.resetForm("queryForm")
  887. this.handleQuery()
  888. },
  889. handleSelectionChange(selection) {
  890. this.ids = selection.map(item => item.id)
  891. this.single = selection.length !== 1
  892. this.multiple = !selection.length
  893. },
  894. handleAdd() {
  895. this.reset()
  896. this.open = true
  897. this.title = "添加兽医个人信息"
  898. },
  899. handleUpdate(row) {
  900. this.reset()
  901. const id = row.id || this.ids[0]
  902. getInfo(id).then(response => {
  903. if (response.code === 200) {
  904. this.form = response.data
  905. this.open = true
  906. this.title = "修改兽医个人信息"
  907. }
  908. })
  909. },
  910. submitForm() {
  911. this.$refs["form"].validate(valid => {
  912. if (valid) {
  913. const api = this.form.id ?
  914. (data) => this.$axios.put('/system/vetInfo', data) :
  915. (data) => this.$axios.post('/system/vetInfo', data)
  916. api(this.form).then(response => {
  917. this.$modal.msgSuccess(this.form.id ? "修改成功" : "新增成功")
  918. this.open = false
  919. this.getList()
  920. }).catch(error => {
  921. this.$modal.msgError("操作失败")
  922. })
  923. }
  924. })
  925. },
  926. handleDelete(row) {
  927. const ids = row.id || this.ids
  928. this.$modal.confirm('是否确认删除兽医个人信息编号为"' + ids + '"的数据项?').then(() => {
  929. this.$axios.delete('/system/vetInfo/' + ids).then(response => {
  930. this.getList()
  931. this.$modal.msgSuccess("删除成功")
  932. })
  933. }).catch(() => {})
  934. },
  935. getAuditStatusText(status) {
  936. if (!status || status === 'null' || status === 'undefined') {
  937. return '未审核'
  938. }
  939. const statusMap = {
  940. '0': '待审核',
  941. '1': '审核通过',
  942. '2': '审核不通过'
  943. }
  944. return statusMap[status] || '未审核'
  945. },
  946. getAuditStatusTagType(status) {
  947. if (!status || status === 'null' || status === 'undefined') {
  948. return 'info'
  949. }
  950. const typeMap = {
  951. '0': 'warning',
  952. '1': 'success',
  953. '2': 'danger'
  954. }
  955. return typeMap[status] || 'info'
  956. },
  957. cancel() {
  958. this.open = false
  959. this.reset()
  960. },
  961. closeDetail() {
  962. this.detailVisible = false
  963. this.detailData = null
  964. this.detailCertificates = []
  965. },
  966. reset() {
  967. this.form = {
  968. id: null,
  969. userId: null,
  970. realName: null,
  971. gender: null,
  972. birthday: null,
  973. idCard: null,
  974. specialty: null,
  975. workExperience: null,
  976. hospital: null,
  977. address: null,
  978. introduction: null,
  979. title: null,
  980. phone: null,
  981. email: null,
  982. expertType: null,
  983. }
  984. this.resetForm("form")
  985. },
  986. // 文件下载方法
  987. downloadFile(filePath) {
  988. if (!filePath) {
  989. this.$message.warning('文件路径为空,无法下载')
  990. return
  991. }
  992. const loading = this.$loading({
  993. lock: true,
  994. text: '正在下载文件...',
  995. spinner: 'el-icon-loading',
  996. background: 'rgba(0, 0, 0, 0.7)'
  997. })
  998. const fullUrl = this.baseUrl + filePath
  999. axios({
  1000. method: 'get',
  1001. url: fullUrl,
  1002. responseType: 'blob', // 关键:设置响应类型为blob
  1003. headers: {
  1004. }
  1005. }).then(response => {
  1006. const blob = new Blob([response.data])
  1007. const downloadUrl = window.URL.createObjectURL(blob)
  1008. const a = document.createElement('a')
  1009. a.download = this.getFileName(filePath)
  1010. a.href = downloadUrl
  1011. document.body.appendChild(a)
  1012. a.click()
  1013. window.URL.revokeObjectURL(downloadUrl)
  1014. document.body.removeChild(a)
  1015. this.$message.success('文件下载成功')
  1016. }).catch(error => {
  1017. console.error('文件下载失败:', error)
  1018. this.$message.error('文件下载失败,请重试')
  1019. }).finally(() => {
  1020. loading.close()
  1021. })
  1022. },
  1023. getFileName(filePath) {
  1024. if (!filePath) return '未知文件'
  1025. const parts = filePath.split(/[\\/]/)
  1026. const fileName = parts.pop() || '未知文件'
  1027. return fileName
  1028. }
  1029. }
  1030. }
  1031. </script>
  1032. <style scoped>
  1033. ::v-deep .pagestyle .el-input{
  1034. width: auto !important;
  1035. }
  1036. </style>
  1037. <style scoped lang="scss">
  1038. .audit-dialog {
  1039. :deep(.el-dialog__body) {
  1040. max-height: 70vh;
  1041. overflow-y: auto;
  1042. padding: 20px;
  1043. }
  1044. }
  1045. .cert-tabs {
  1046. margin-top: 15px;
  1047. :deep(.el-tabs__header) {
  1048. margin-bottom: 10px;
  1049. }
  1050. :deep(.el-tabs__item) {
  1051. font-weight: 500;
  1052. padding: 0 15px;
  1053. height: 36px;
  1054. line-height: 36px;
  1055. &.is-active {
  1056. background-color: #ecf5ff;
  1057. border-bottom-color: #ecf5ff;
  1058. }
  1059. }
  1060. }
  1061. .tab-loading {
  1062. text-align: center;
  1063. padding: 60px 0;
  1064. .el-icon-loading {
  1065. font-size: 32px;
  1066. color: #409EFF;
  1067. margin-bottom: 15px;
  1068. }
  1069. div {
  1070. color: #606266;
  1071. font-size: 14px;
  1072. }
  1073. }
  1074. .info-section {
  1075. margin-bottom: 25px;
  1076. h3 {
  1077. margin-bottom: 15px;
  1078. color: #303133;
  1079. font-size: 16px;
  1080. font-weight: 600;
  1081. padding-bottom: 8px;
  1082. border-bottom: 2px solid #409EFF;
  1083. }
  1084. }
  1085. .audit-form-section {
  1086. margin-top: 20px;
  1087. h3 {
  1088. margin-bottom: 15px;
  1089. color: #303133;
  1090. font-size: 16px;
  1091. font-weight: 600;
  1092. }
  1093. }
  1094. .audit-status-tag {
  1095. margin-left: 15px;
  1096. .el-tag {
  1097. font-weight: 500;
  1098. }
  1099. }
  1100. .certificate-section {
  1101. h3 {
  1102. margin-bottom: 15px;
  1103. color: #303133;
  1104. font-size: 16px;
  1105. font-weight: 600;
  1106. padding-bottom: 8px;
  1107. border-bottom: 2px solid #67C23A;
  1108. }
  1109. }
  1110. .certificate-item {
  1111. border: 1px solid #ebeef5;
  1112. border-radius: 6px;
  1113. margin-bottom: 15px;
  1114. padding: 20px;
  1115. background-color: #fff;
  1116. transition: all 0.3s ease;
  1117. &:hover {
  1118. box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  1119. }
  1120. &.cert-audited {
  1121. background-color: #f8f9fa;
  1122. border-left: 4px solid #67C23A;
  1123. }
  1124. &.view-only {
  1125. background-color: #fafafa;
  1126. &:hover {
  1127. box-shadow: none;
  1128. }
  1129. }
  1130. }
  1131. .cert-header {
  1132. margin-bottom: 20px;
  1133. padding-bottom: 15px;
  1134. border-bottom: 1px dashed #ebeef5;
  1135. }
  1136. .cert-title {
  1137. display: flex;
  1138. align-items: center;
  1139. gap: 10px;
  1140. margin-bottom: 15px;
  1141. span {
  1142. font-size: 13px;
  1143. font-weight: 600;
  1144. color: #303133;
  1145. //flex: 1;
  1146. }
  1147. //.el-tag {
  1148. // font-weight: 500;
  1149. //
  1150. // &.el-tag--success {
  1151. // background-color: rgba(103, 194, 58, 0.1);
  1152. // border-color: rgba(103, 194, 58, 0.2);
  1153. // }
  1154. //
  1155. // &.el-tag--danger {
  1156. // background-color: rgba(245, 108, 108, 0.1);
  1157. // border-color: rgba(245, 108, 108, 0.2);
  1158. // }
  1159. //
  1160. // &.el-tag--warning {
  1161. // background-color: rgba(230, 162, 60, 0.1);
  1162. // border-color: rgba(230, 162, 60, 0.2);
  1163. // }
  1164. //}
  1165. }
  1166. .cert-info {
  1167. display: grid;
  1168. grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  1169. gap: 12px;
  1170. font-size: 14px;
  1171. color: #606266;
  1172. margin-bottom: 15px;
  1173. span {
  1174. display: flex;
  1175. align-items: center;
  1176. strong {
  1177. min-width: 80px;
  1178. color: #303133;
  1179. font-weight: 500;
  1180. margin-right: 8px;
  1181. }
  1182. .el-tag {
  1183. margin-left: 5px;
  1184. }
  1185. }
  1186. }
  1187. .cert-image-section {
  1188. margin-top: 15px;
  1189. padding: 12px;
  1190. background-color: #f8f9fa;
  1191. border-radius: 6px;
  1192. border: 1px solid #e4e7ed;
  1193. .image-title {
  1194. margin-bottom: 10px;
  1195. font-size: 14px;
  1196. color: #303133;
  1197. }
  1198. .image-preview {
  1199. .el-image {
  1200. border: 1px solid #dcdfe6;
  1201. border-radius: 4px;
  1202. overflow: hidden;
  1203. box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  1204. .image-slot {
  1205. display: flex;
  1206. flex-direction: column;
  1207. align-items: center;
  1208. justify-content: center;
  1209. width: 100%;
  1210. height: 100%;
  1211. background: #f5f7fa;
  1212. color: #909399;
  1213. i {
  1214. font-size: 30px;
  1215. margin-bottom: 5px;
  1216. }
  1217. div {
  1218. font-size: 12px;
  1219. }
  1220. }
  1221. }
  1222. }
  1223. }
  1224. .cert-files-section {
  1225. margin-top: 15px;
  1226. padding: 12px;
  1227. background-color: #f8f9fa;
  1228. border-radius: 6px;
  1229. border: 1px solid #e4e7ed;
  1230. .files-title {
  1231. margin-bottom: 10px;
  1232. font-size: 14px;
  1233. color: #303133;
  1234. }
  1235. .files-list {
  1236. color: #606266;
  1237. font-size: 13px;
  1238. // 新增:下载按钮样式
  1239. .download-btn {
  1240. color: #409EFF;
  1241. padding: 0;
  1242. height: auto;
  1243. line-height: 1;
  1244. &:hover {
  1245. color: #66b1ff;
  1246. text-decoration: underline;
  1247. }
  1248. i {
  1249. margin-right: 5px;
  1250. font-size: 12px;
  1251. }
  1252. }
  1253. }
  1254. }
  1255. .cert-audit-form {
  1256. margin-top: 20px;
  1257. padding-top: 20px;
  1258. border-top: 1px dashed #ebeef5;
  1259. }
  1260. .audit-saved-tag {
  1261. margin-left: 15px;
  1262. .el-tag {
  1263. font-weight: 500;
  1264. background-color: rgba(103, 194, 58, 0.1);
  1265. border-color: rgba(103, 194, 58, 0.2);
  1266. }
  1267. }
  1268. .cert-summary {
  1269. margin-bottom: 20px;
  1270. padding: 15px;
  1271. background-color: #f8f9fa;
  1272. border-radius: 6px;
  1273. border-left: 4px solid #409EFF;
  1274. }
  1275. .no-data {
  1276. text-align: center;
  1277. padding: 60px 0;
  1278. .el-alert {
  1279. max-width: 400px;
  1280. margin: 0 auto;
  1281. }
  1282. }
  1283. //.info-btn {
  1284. // padding: 6px 12px;
  1285. // border-radius: 4px;
  1286. // margin: 0 4px;
  1287. // transition: all 0.3s ease;
  1288. // font-weight: 500;
  1289. //
  1290. // &:hover {
  1291. // transform: translateY(-2px);
  1292. // box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
  1293. // }
  1294. //}
  1295. //
  1296. //.view-btn:hover {
  1297. // background-color: rgba(243, 239, 231, 0.9);
  1298. // border-color: #e6a23c;
  1299. // color: #e6a23c;
  1300. //}
  1301. //
  1302. //.audit-btn:hover {
  1303. // background-color: rgba(64, 158, 255, 0.15);
  1304. // border-color: #409eff;
  1305. // color: #409eff;
  1306. //}
  1307. :deep(.dialog-footer) {
  1308. .el-button {
  1309. min-width: 100px;
  1310. &:last-child {
  1311. margin-left: 10px;
  1312. }
  1313. }
  1314. }
  1315. :deep(.el-tabs__header) {
  1316. margin-bottom: 0;
  1317. }
  1318. :deep(.el-tabs__item) {
  1319. font-weight: 500;
  1320. &.is-active {
  1321. color: #409EFF;
  1322. font-weight: 600;
  1323. }
  1324. }
  1325. :deep(.el-tag) {
  1326. &.el-tag--success {
  1327. background-color: rgba(103, 194, 58, 0.1);
  1328. border-color: rgba(103, 194, 58, 0.2);
  1329. }
  1330. &.el-tag--danger {
  1331. background-color: rgba(245, 108, 108, 0.1);
  1332. border-color: rgba(245, 108, 108, 0.2);
  1333. }
  1334. &.el-tag--warning {
  1335. background-color: rgba(230, 162, 60, 0.1);
  1336. border-color: rgba(230, 162, 60, 0.2);
  1337. }
  1338. }
  1339. // 操作按钮样式
  1340. .info-btn {
  1341. padding: 6px 10px;
  1342. border-radius: 4px;
  1343. margin: 0 10px;
  1344. transition: all 0.3s ease;
  1345. }
  1346. .view-btn:hover {
  1347. background-color: rgb(216, 238, 248);
  1348. transform: translateY(-1px);
  1349. }
  1350. .audit-btn:hover {
  1351. background-color: rgb(215, 223, 246);
  1352. transform: translateY(-1px);
  1353. }
  1354. // 新增/修改的弹窗
  1355. ::v-deep .el-dialog {
  1356. border-radius: 12px;
  1357. overflow: hidden;
  1358. box-shadow: 0 10px 40px rgba(0, 0, 0, 0.12);
  1359. animation: dialogFadeIn 0.3s ease;
  1360. }
  1361. ::v-deep .el-dialog__header {
  1362. background: linear-gradient(135deg, #2c7a4d 0%, #42b983 100%);
  1363. padding: 18px 24px;
  1364. border-bottom: none;
  1365. position: relative;
  1366. }
  1367. ::v-deep .el-dialog__title {
  1368. font-size: 17px;
  1369. font-weight: 600;
  1370. color: white;
  1371. letter-spacing: 0.5px;
  1372. }
  1373. ::v-deep .el-dialog__headerbtn:hover .el-dialog__close {
  1374. color: #ffd04b;
  1375. transform: rotate(90deg);
  1376. }
  1377. ::v-deep .el-dialog__body {
  1378. padding: 28px 24px 20px;
  1379. background-color: #f8fafc;
  1380. max-height: 70vh;
  1381. overflow-y: auto;
  1382. }
  1383. ::v-deep .el-form-item {
  1384. margin-bottom: 20px;
  1385. transition: all 0.3s;
  1386. }
  1387. ::v-deep .el-form-item__label {
  1388. font-weight: 500;
  1389. color: #2d3748;
  1390. font-size: 14px;
  1391. transition: color 0.3s;
  1392. }
  1393. ::v-deep .el-input,
  1394. ::v-deep .el-textarea,
  1395. ::v-deep .el-select {
  1396. width: 100%;
  1397. }
  1398. ::v-deep .el-input__inner,
  1399. ::v-deep .el-textarea__inner {
  1400. border-radius: 8px;
  1401. border: 1px solid #dcdfe6;
  1402. font-size: 14px;
  1403. transition: all 0.3s;
  1404. background-color: #fcfdfe;
  1405. }
  1406. ::v-deep .el-input__inner:focus,
  1407. ::v-deep .el-textarea__inner:focus {
  1408. border-color: #42B983;
  1409. box-shadow: 0 0 0 3px rgb(230, 255, 238);
  1410. background-color: white;
  1411. }
  1412. ::v-deep .el-select .el-input__inner {
  1413. padding-right: 35px;
  1414. }
  1415. ::v-deep .el-dialog__footer {
  1416. padding: 20px 24px;
  1417. background-color: #f8fafc;
  1418. border-top: 1px solid #eef2f7;
  1419. border-radius: 0 0 12px 12px;
  1420. }
  1421. // 证书中的状态标签样式
  1422. .cert-status-tag {
  1423. min-width: 70px;
  1424. display: inline-flex;
  1425. align-items: center;
  1426. justify-content: center;
  1427. border-radius: 16px;
  1428. padding: 0 10px;
  1429. font-weight: 500;
  1430. letter-spacing: 0.3px;
  1431. transition: all 0.3s ease;
  1432. i {
  1433. margin-right: 4px;
  1434. font-size: 12px;
  1435. }
  1436. &:hover {
  1437. transform: translateY(-1px);
  1438. box-shadow: 0 3px 8px rgba(0, 0, 0, 0.15);
  1439. }
  1440. &.el-tag--success {
  1441. background: linear-gradient(135deg, #2c7a4d 0%, #42b983 100%);
  1442. border: none;
  1443. color: white;
  1444. }
  1445. &.el-tag--danger {
  1446. background: linear-gradient(135deg, #d9534f 0%, #f56c6c 100%);
  1447. border: none;
  1448. color: white;
  1449. }
  1450. &.el-tag--warning {
  1451. background: linear-gradient(135deg, #ff8c00 0%, #ffb347 100%);
  1452. border: none;
  1453. color: white;
  1454. }
  1455. }
  1456. </style>