org-user-list.vue 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797
  1. <template>
  2. <div>
  3. <!-- 数据表格 -->
  4. <org-user-search @search="reload" ref="searchRef"></org-user-search>
  5. <!-- 员工状态 tab:选项来自「员工状态」字典(缺项不渲染、不编造状态码),末尾固定「全部」。
  6. 对照 hr 员工档案页样式,位于搜索区下方、表格工具栏之外 -->
  7. <div v-if="statusTabs.length" class="status-tab-bar">
  8. <button
  9. v-for="tab in statusTabs"
  10. :key="tab.key"
  11. type="button"
  12. class="status-tab"
  13. :class="{ active: String(statusTab) === String(tab.value) }"
  14. @click="switchStatusTab(tab.value)"
  15. >
  16. {{ tab.label }}
  17. </button>
  18. </div>
  19. <ele-pro-table
  20. ref="table"
  21. :columns="columns"
  22. :datasource="datasource"
  23. height="calc(100vh - 315px)"
  24. full-height="calc(100vh - 160px)"
  25. tool-class="ele-toolbar-form"
  26. :page-size="pageSize"
  27. row-key="id"
  28. :selection.sync="selection"
  29. @columns-change="handleColumnChange"
  30. :cache-key="cacheKeyUrl"
  31. @update:selection="handleSelectionChange"
  32. >
  33. <!-- 表头工具栏 -->
  34. <template v-slot:toolbar>
  35. <el-button
  36. size="small"
  37. type="primary"
  38. icon="el-icon-plus"
  39. class="ele-btn-icon"
  40. @click="openEdit()"
  41. v-if="$hasPermission('main:user:save')"
  42. >
  43. 添加
  44. </el-button>
  45. <el-button
  46. type="primary"
  47. size="mini"
  48. icon="el-icon-upload2"
  49. plain
  50. @click="uploadFile"
  51. v-if="$hasPermission('main:user:save')"
  52. >导入</el-button
  53. >
  54. <el-button
  55. type="primary"
  56. size="mini"
  57. icon="el-icon-download"
  58. plain
  59. @click="exportUsers"
  60. >导出</el-button
  61. >
  62. <el-button
  63. type="success"
  64. size="mini"
  65. icon="el-icon-guide"
  66. plain
  67. @click="bindingProcess"
  68. >绑定关键工序</el-button
  69. >
  70. <el-button
  71. v-if="$hasPermission('main:user:push')"
  72. :disabled="selection?.length === 0"
  73. type="primary"
  74. size="mini"
  75. plain
  76. @click="allPushBtn"
  77. >批量推送</el-button
  78. >
  79. </template>
  80. <!-- 角色列 -->
  81. <template v-slot:roles="{ row }">
  82. <el-tag
  83. v-for="item in row.roles"
  84. :key="item.roleId"
  85. type="primary"
  86. size="mini"
  87. :disable-transitions="true"
  88. >
  89. {{ item.roleName }}
  90. </el-tag>
  91. </template>
  92. <template v-slot:name="{ row }">
  93. <el-link type="primary" :underline="false" @click="openEdit(row, true)">
  94. {{ row.name }}</el-link
  95. >
  96. </template>
  97. <!-- 状态列 -->
  98. <!-- <template v-slot:status="{ row }">
  99. <el-switch
  100. :active-value="0"
  101. :inactive-value="1"
  102. v-model="row.status"
  103. @change="editStatus(row)"
  104. />
  105. </template> -->
  106. <!-- 操作列 -->
  107. <template v-slot:action="{ row }">
  108. <el-link
  109. type="primary"
  110. :underline="false"
  111. icon="el-icon-edit"
  112. @click="openEdit(row)"
  113. v-if="$hasPermission('main:user:save')"
  114. >
  115. 修改
  116. </el-link>
  117. <el-link
  118. v-if="row.loginName && $hasPermission('main:user:save')"
  119. type="primary"
  120. :underline="false"
  121. icon="el-icon-unlock"
  122. @click="toUnBind(row)"
  123. >
  124. 解绑
  125. </el-link>
  126. <el-link
  127. v-if="!row.loginName && $hasPermission('main:user:save')"
  128. type="primary"
  129. :underline="false"
  130. icon="el-icon-add"
  131. @click="addUsers(row)"
  132. >
  133. 新建账号
  134. </el-link>
  135. <!-- <el-link
  136. type="primary"
  137. :underline="false"
  138. icon="el-icon-key"
  139. @click="openDoor(row)"
  140. >
  141. 门禁
  142. </el-link> -->
  143. <el-popconfirm
  144. class="ele-action"
  145. title="确定要删除此用户吗?"
  146. @confirm="remove(row)"
  147. v-if="!row.loginName && $hasPermission('main:user:delete')"
  148. >
  149. <template v-slot:reference>
  150. <el-link type="danger" :underline="false" icon="el-icon-delete">
  151. 删除
  152. </el-link>
  153. </template>
  154. </el-popconfirm>
  155. </template>
  156. </ele-pro-table>
  157. <!-- 编辑弹窗 -->
  158. <org-user-edit
  159. :data="current"
  160. :visible.sync="showEdit"
  161. :organization-list="organizationList"
  162. :institutionList="institutionList"
  163. :organization-id="organizationId"
  164. @done="reload"
  165. ref="userEditRef"
  166. />
  167. <addUsers
  168. :visible.sync="showEdit1"
  169. @done="reload"
  170. :data="null"
  171. ref="userEdit"
  172. :organizationList="organizationList"
  173. />
  174. <importDialog
  175. :defModule="moudleName"
  176. ref="importDialogRef"
  177. @success="reload"
  178. />
  179. <el-dialog
  180. title="提示"
  181. :visible.sync="dialogVisible"
  182. @close="dialogVisible = false"
  183. width="400px"
  184. >
  185. <span>是否绑定已有用户?</span>
  186. <el-radio v-model="radio" label="1">是</el-radio>
  187. <el-radio v-model="radio" label="2">否</el-radio>
  188. <span slot="footer" class="dialog-footer">
  189. <el-button @click="dialogVisible = false">取 消</el-button>
  190. <el-button type="primary" @click="setUser">确 定</el-button>
  191. </span>
  192. </el-dialog>
  193. <ele-modal
  194. width="1000px"
  195. :visible.async="userShow"
  196. :close-on-click-modal="false"
  197. custom-class="ele-dialog-form"
  198. :maxable="true"
  199. @close="userShow = false"
  200. >
  201. <UserSearch @search="reload1"></UserSearch>
  202. <!-- 数据表格 -->
  203. <ele-pro-table
  204. ref="table1"
  205. :columns="columns1"
  206. :datasource="datasource1"
  207. :current.sync="userRow"
  208. highlight-current-row
  209. row-key="id"
  210. >
  211. </ele-pro-table>
  212. <template v-slot:footer>
  213. <el-button @click="userShow = false">取消</el-button>
  214. <el-button type="primary" @click="getUser"> 确认 </el-button>
  215. </template>
  216. </ele-modal>
  217. <critical-process
  218. ref="criticalProcessRef"
  219. @chooseProcess="chooseProcess"
  220. ></critical-process>
  221. <DoorModal ref="doorModalRef" :visible.sync="showDoor" :current="current" />
  222. </div>
  223. </template>
  224. <script>
  225. import tabMixins from '@/mixins/tableColumnsMixin';
  226. import OrgUserSearch from './org-user-search.vue';
  227. import OrgUserEdit from './org-user-edit.vue';
  228. import importDialog from '@/components/upload/import-dialog.vue';
  229. import addUsers from '@/views/system/user/components/user-edit.vue';
  230. import UserSearch from '@/views/system/user/components/user-search.vue';
  231. import {
  232. getUserPage,
  233. removePersonnel,
  234. unbindLoginName,
  235. employeePush
  236. } from '@/api/system/organization';
  237. import { pageUsers, exportUsers } from '@/api/system/user';
  238. import dictMixins from '@/mixins/dictMixins';
  239. import { getFactoryarea } from '@/api/factoryModel';
  240. import criticalProcess from './criticalProcess.vue';
  241. import DoorModal from './door-modal.vue';
  242. export default {
  243. mixins: [tabMixins, dictMixins],
  244. components: {
  245. importDialog,
  246. OrgUserSearch,
  247. OrgUserEdit,
  248. addUsers,
  249. UserSearch,
  250. criticalProcess,
  251. DoorModal
  252. },
  253. props: {
  254. // 机构id
  255. organizationId: [Number, String],
  256. // 全部机构
  257. organizationList: Array,
  258. institutionList: Array
  259. },
  260. created() {
  261. this.requestDict('岗位');
  262. this.requestDict('员工状态');
  263. getFactoryarea({
  264. pageNum: 1,
  265. size: 999,
  266. type: 1
  267. }).then((res) => {
  268. this.factoryList = res.list || [];
  269. });
  270. },
  271. computed: {
  272. // 表格列配置
  273. columns() {
  274. let columnsVersion = this.columnsVersion;
  275. return [
  276. {
  277. width: 45,
  278. type: 'selection',
  279. columnKey: 'selection',
  280. align: 'center'
  281. },
  282. {
  283. columnKey: 'index',
  284. label: '序号',
  285. type: 'index',
  286. width: 55,
  287. align: 'center',
  288. showOverflowTooltip: true,
  289. fixed: 'left'
  290. },
  291. {
  292. prop: 'name',
  293. label: '姓名',
  294. slot: 'name',
  295. sortable: 'custom',
  296. showOverflowTooltip: true,
  297. minWidth: 110
  298. },
  299. {
  300. // 所属机构(groupName)
  301. prop: 'groupName',
  302. label: '所属机构',
  303. showOverflowTooltip: true,
  304. minWidth: 110
  305. },
  306. {
  307. // 详情/列表口径一致:groupName 是机构,主所属部门名称在 deptName
  308. prop: 'deptName',
  309. label: '主所属部门',
  310. showOverflowTooltip: true,
  311. minWidth: 110
  312. },
  313. {
  314. prop: 'deptNames',
  315. label: '隶属部门',
  316. showOverflowTooltip: true,
  317. minWidth: 110
  318. },
  319. {
  320. prop: 'jobNumber',
  321. label: '工号',
  322. sortable: 'custom',
  323. showOverflowTooltip: true,
  324. minWidth: 110
  325. },
  326. {
  327. prop: 'phone',
  328. label: '手机号',
  329. sortable: 'custom',
  330. showOverflowTooltip: true,
  331. minWidth: 110
  332. },
  333. {
  334. prop: 'postName',
  335. label: '岗位',
  336. showOverflowTooltip: true,
  337. minWidth: 110
  338. },
  339. {
  340. prop: 'factoryId',
  341. label: '所属工厂',
  342. sortable: 'custom',
  343. showOverflowTooltip: true,
  344. minWidth: 110,
  345. formatter: (_row, _column, cellValue) => {
  346. return this.factoryList.find((item) => item.id == cellValue)
  347. ?.name;
  348. }
  349. },
  350. {
  351. prop: 'loginName',
  352. label: '用户账号',
  353. sortable: 'custom',
  354. showOverflowTooltip: true,
  355. minWidth: 110
  356. },
  357. {
  358. prop: 'sex',
  359. label: '性别',
  360. sortable: 'custom',
  361. showOverflowTooltip: true,
  362. minWidth: 80,
  363. formatter: (_row, _column, cellValue) => {
  364. return cellValue == 1 ? '男' : cellValue == 2 ? '女' : '';
  365. }
  366. },
  367. {
  368. prop: 'status',
  369. label: '状态',
  370. align: 'center',
  371. sortable: 'custom',
  372. width: 80,
  373. formatter: (_row, _column, cellValue) => {
  374. const dom = this.statusList.find((item) => {
  375. return item.value == cellValue;
  376. });
  377. return dom ? dom.label : _row.statusName || '';
  378. }
  379. },
  380. {
  381. prop: 'code',
  382. label: '是否推送',
  383. align: 'center',
  384. showOverflowTooltip: true,
  385. minWidth: 120,
  386. formatter: (_row, _column, cellValue) => {
  387. return _row.code ? '已推送' : '未推送';
  388. }
  389. },
  390. {
  391. prop: 'isEnabled',
  392. align: 'center',
  393. label: '是否启用',
  394. showOverflowTooltip: true,
  395. formatter: (row, column) => {
  396. return row.isEnabled === 0
  397. ? '停用'
  398. : row.isEnabled === 1
  399. ? '启用'
  400. : '';
  401. }
  402. },
  403. {
  404. prop: 'createTime',
  405. label: '创建时间',
  406. sortable: 'custom',
  407. showOverflowTooltip: true,
  408. minWidth: 110,
  409. formatter: (_row, _column, cellValue) => {
  410. return this.$util.toDateString(cellValue);
  411. }
  412. },
  413. {
  414. columnKey: 'action',
  415. label: '操作',
  416. width: 260,
  417. align: 'left',
  418. resizable: false,
  419. fixed: 'right',
  420. slot: 'action',
  421. showOverflowTooltip: true
  422. }
  423. ];
  424. },
  425. // 员工状态字典(hr_user_status)
  426. statusList() {
  427. const list = this.getDictListByName('员工状态');
  428. return Array.isArray(list) ? list : [];
  429. },
  430. /**
  431. * 员工状态 tab:顺序 在职 → 试用期 → 已离职 → 待岗 → 退休 → 全部(对照 hr 员工档案页)。
  432. * 前几项来自「员工状态」字典(value 就是接口 status 参数),字典里没有的状态不渲染,
  433. * 例如「退休」需要后端在字典里加项后才会出现(前端不编状态码)。
  434. * 「全部」为前端固定项(value 空串 → 不传 status 查全量)。
  435. */
  436. statusTabs() {
  437. const defs = [
  438. {
  439. key: 'active',
  440. test: (label) => label.includes('在职') && !label.includes('离职')
  441. },
  442. { key: 'probation', test: (label) => label.includes('试用') },
  443. { key: 'resigned', test: (label) => label.includes('离职') },
  444. { key: 'idle', test: (label) => label.includes('待岗') },
  445. { key: 'retired', test: (label) => label.includes('退休') }
  446. ];
  447. const options = this.statusList || [];
  448. const tabs = [];
  449. defs.forEach((def) => {
  450. const hit = options.find((item) => def.test(String(item.label || '')));
  451. if (hit) {
  452. tabs.push({ key: def.key, label: hit.label, value: String(hit.value) });
  453. }
  454. });
  455. tabs.push({ key: 'all', label: '全部', value: '' });
  456. return tabs;
  457. }
  458. },
  459. data() {
  460. return {
  461. showDoor: false,
  462. moudleName: 'mainUser',
  463. showEdit1: false,
  464. userShow: false,
  465. userRow: null,
  466. currentRow: null,
  467. dialogVisible: false,
  468. radio: '2',
  469. columnsVersion: 0,
  470. factoryList: [],
  471. // 表格列配置
  472. columns1: [
  473. {
  474. columnKey: 'index',
  475. type: 'index',
  476. width: 55,
  477. align: 'center',
  478. showOverflowTooltip: true,
  479. fixed: 'left',
  480. label: '序号'
  481. },
  482. {
  483. prop: 'loginName',
  484. label: '用户账号',
  485. showOverflowTooltip: true,
  486. minWidth: 110
  487. },
  488. {
  489. prop: 'jobNumber',
  490. label: '工号',
  491. showOverflowTooltip: true,
  492. minWidth: 110
  493. },
  494. {
  495. prop: 'name',
  496. label: '姓名',
  497. showOverflowTooltip: true,
  498. minWidth: 110
  499. },
  500. {
  501. prop: 'phone',
  502. label: '手机号',
  503. showOverflowTooltip: true,
  504. minWidth: 110
  505. },
  506. {
  507. columnKey: 'groupRoleList',
  508. label: '角色',
  509. showOverflowTooltip: true,
  510. minWidth: 110,
  511. formatter: (_row, _column, cellValue) => {
  512. let names = [];
  513. _row.groupRoleList.forEach((item) => {
  514. names.push(...item.roleVOList.map((val) => val.name));
  515. });
  516. return names.toString();
  517. }
  518. },
  519. {
  520. prop: 'createTime',
  521. label: '创建时间',
  522. // sortable: 'custom',
  523. showOverflowTooltip: true,
  524. minWidth: 110,
  525. formatter: (_row, _column, cellValue) => {
  526. return this.$util.toDateString(cellValue);
  527. }
  528. }
  529. ],
  530. // 当前编辑数据
  531. current: null,
  532. // 是否显示编辑弹窗
  533. showEdit: false,
  534. pageSize: this.$store.state.tablePageSize,
  535. cacheKeyUrl: 'ef00833a-system-organization',
  536. selection: [],
  537. // 员工状态 tab 当前选中的状态码('' = 全部);
  538. // 初始即「正式在职」的字典码 1(2026-10-14 抓包确认),字典异常时由 watch 纠正
  539. statusTab: '1'
  540. };
  541. },
  542. methods: {
  543. openDoor(row) {
  544. console.log(row);
  545. this.current = row;
  546. this.showDoor = true;
  547. },
  548. allPushBtn() {
  549. const dataId = this.selection.map((v) => v.id);
  550. employeePush(dataId)
  551. .then((res) => {
  552. this.$message.success('推送成功!');
  553. this.reload();
  554. })
  555. .catch(() => {
  556. console.log('推送失败!');
  557. });
  558. },
  559. async addUsers(row) {
  560. // this.userRow = null;
  561. this.currentRow = row;
  562. this.dialogVisible = true;
  563. },
  564. setUser() {
  565. this.dialogVisible = false;
  566. if (this.radio == 1) {
  567. this.userShow = true;
  568. } else {
  569. this.showEdit1 = true;
  570. this.$refs.userEdit.userBk(this.currentRow);
  571. }
  572. },
  573. getUser() {
  574. if (!this.userRow) {
  575. this.$message.warning('请选择一条数据!');
  576. return;
  577. }
  578. this.userShow = false;
  579. this.showEdit1 = true;
  580. this.$refs.userEdit.getByData(this.userRow, this.currentRow);
  581. },
  582. /* 表格数据源 */
  583. datasource({ page, limit, where, order }) {
  584. const params = {
  585. ...where,
  586. pageNum: page,
  587. orderName: order.order || '',
  588. sortBy: order.sort || '',
  589. size: limit,
  590. groupId: this.organizationId,
  591. isQueryLZ: 1,
  592. affiDeptId: 1
  593. };
  594. // 员工状态 tab:「全部」(空串)时不传 status,查全量
  595. if (this.statusTab !== '') {
  596. params.status = this.statusTab;
  597. }
  598. return getUserPage(params);
  599. },
  600. /* 表格数据源 */
  601. datasource1({ page, limit, where, order }) {
  602. return pageUsers({
  603. ...where,
  604. ...order,
  605. pageNum: page,
  606. size: limit
  607. });
  608. },
  609. /* 刷新表格 */
  610. reload(where) {
  611. this.$refs.table.reload({ pageNum: 1, where: where });
  612. },
  613. reload1(where) {
  614. this.$refs.table1.reload({ pageNum: 1, where: where });
  615. },
  616. exportUsers() {
  617. let where = this.$refs.searchRef.geValue();
  618. this.reload(where);
  619. exportUsers({
  620. ...where,
  621. pageNum: 1,
  622. size: 10000,
  623. groupId: this.organizationId,
  624. // 导出同样跟随状态 tab(「全部」时不带 status)
  625. ...(this.statusTab !== '' ? { status: this.statusTab } : {})
  626. });
  627. },
  628. /* 状态 tab 切换:立即生效并回到第一页 */
  629. switchStatusTab(value) {
  630. const next = value == null ? '' : String(value);
  631. if (String(this.statusTab) === next) return;
  632. this.statusTab = next;
  633. this.reload();
  634. },
  635. /* 显示编辑 */
  636. openEdit(row, disabled) {
  637. this.current = row;
  638. this.showEdit = true;
  639. this.$refs.userEditRef.setDisabled(disabled);
  640. },
  641. bindingProcess() {
  642. if (this.selection.length == 0) {
  643. return this.$message.warning('请至少选择一名需要绑定的人员');
  644. }
  645. this.$refs.criticalProcessRef.open(this.selection, 'batch');
  646. },
  647. chooseProcess() {
  648. this.reload();
  649. },
  650. handleSelectionChange(data) {
  651. this.selection = data;
  652. },
  653. // 解除绑定
  654. toUnBind(row) {
  655. const loading = this.$loading({ lock: true });
  656. unbindLoginName(row.id)
  657. .then((res) => {
  658. loading.close();
  659. this.$message.success('解绑成功');
  660. this.reload();
  661. })
  662. .catch((e) => {
  663. loading.close();
  664. // this.$message.error(e.message);
  665. });
  666. },
  667. /* 删除 */
  668. remove(row) {
  669. const loading = this.$loading({ lock: true });
  670. removePersonnel([row.id])
  671. .then((msg) => {
  672. loading.close();
  673. this.$message.success(msg);
  674. this.reload();
  675. })
  676. .catch((e) => {
  677. loading.close();
  678. // this.$message.error(e.message);
  679. });
  680. },
  681. /* 更改状态 */
  682. editStatus(row) {
  683. const loading = this.$loading({ lock: true });
  684. updateUserStatus(row.userId, row.status)
  685. .then((msg) => {
  686. loading.close();
  687. this.$message.success(msg);
  688. })
  689. .catch((e) => {
  690. loading.close();
  691. row.status = !row.status ? 1 : 0;
  692. // this.$message.error(e.message);
  693. });
  694. },
  695. uploadFile() {
  696. this.$refs.importDialogRef.open();
  697. }
  698. },
  699. watch: {
  700. // 监听机构id变化
  701. organizationId() {
  702. this.reload();
  703. },
  704. // 字典异步到位后检查默认 tab:当前选中值不在字典 tab 里时回到第一项(在职)并补一次查询
  705. statusTabs(tabs) {
  706. // 字典未加载时只有「全部」,不动默认值
  707. if (tabs.length <= 1) return;
  708. if (!tabs.some((tab) => tab.value === this.statusTab)) {
  709. this.statusTab = tabs[0].value;
  710. this.$nextTick(() => {
  711. this.$refs.table && this.reload();
  712. });
  713. }
  714. }
  715. }
  716. };
  717. </script>
  718. <style scoped lang="scss">
  719. /* 员工状态 tab(对照 hr 员工档案页样式):整体高约 40px、字号 14px、每段左右留白约 18px,
  720. 位于搜索区下方、表格工具栏之外 */
  721. .status-tab-bar {
  722. display: inline-flex;
  723. align-items: stretch;
  724. max-width: 100%;
  725. margin: 2px 0 0;
  726. overflow: hidden;
  727. border: 1px solid #dcdfe6;
  728. border-radius: 4px;
  729. background: #fff;
  730. }
  731. .status-tab {
  732. height: 40px;
  733. padding: 0 18px;
  734. border: 0;
  735. border-right: 1px solid #e5e5e5;
  736. background: #fff;
  737. color: #606266;
  738. font-size: 14px;
  739. font-weight: 400;
  740. line-height: 40px;
  741. white-space: nowrap;
  742. cursor: pointer;
  743. transition: color 0.18s ease, background-color 0.18s ease;
  744. }
  745. .status-tab:last-child {
  746. border-right: 0;
  747. }
  748. .status-tab:hover {
  749. color: #1890ff;
  750. background: #f7fbff;
  751. }
  752. .status-tab:focus {
  753. outline: none;
  754. }
  755. .status-tab.active {
  756. color: #1890ff;
  757. font-weight: 400;
  758. background: #fff;
  759. }
  760. /* 窄屏:状态 tab 横向滚动,不换行挤压表头 */
  761. @media (max-width: 768px) {
  762. .status-tab-bar {
  763. display: flex;
  764. width: 100%;
  765. overflow-x: auto;
  766. }
  767. .status-tab {
  768. padding: 0 14px;
  769. }
  770. }
  771. </style>