index.vue 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642
  1. <template>
  2. <div>
  3. <el-card class="box-card">
  4. <template #header>
  5. <div class="card-header">
  6. <div class="system-menu-search">
  7. <el-input size="default" v-model="state.param2.keyword" placeholder="请输入关键词" style="max-width: 180px"> </el-input>
  8. <el-button size="default" type="primary" class="ml10" @click="getTableData()">
  9. <el-icon>
  10. <ele-Search />
  11. </el-icon>
  12. 查询
  13. </el-button>
  14. </div>
  15. <div>
  16. <el-button type="primary" @click="onOpenAddEmployee('add')">新增员工</el-button>
  17. <el-button type="primary" @click="pass()">审核</el-button>
  18. <el-button type="danger" @click="repass()">反审核</el-button>
  19. <el-button type="success" @click="importExcel()">导入</el-button>
  20. <el-button type="success" @click="exportExcel()">
  21. 导出
  22. <!-- <a :href="state.download_file_url" target="target" download>导出</a> -->
  23. </el-button>
  24. <el-button type="danger" @click="del()">删除</el-button>
  25. </div>
  26. </div>
  27. </template>
  28. <el-row>
  29. <el-col :span="6">
  30. <div class="card-header ml5 mr5 mt5 mb5">
  31. <span class="dept-all" @click="deptAll()">全部部门</span>
  32. <el-button link type="primary" @click="onOpenAddDept('add')">添加</el-button>
  33. </div>
  34. <el-tree :data="state.data" :props="defaultProps" @node-click="handleNodeClick" :draggable="false">
  35. <template #default="{ node, data }">
  36. <span class="custom-tree-node">
  37. <span>{{ node.label }}</span>
  38. <span>
  39. <a class="a1" @click="onOpenEditDept('edit',data)"> 编辑 </a>
  40. <a class="a2" @click="remove(node, data)"> 删除 </a>
  41. </span>
  42. </span>
  43. </template>
  44. </el-tree>
  45. </el-col>
  46. <el-col :span="18">
  47. <el-table
  48. ref="multipleTableRef"
  49. :data="state.tableData"
  50. style="width: 100%"
  51. @selection-change="handleSelectionChange"
  52. >
  53. <el-table-column type="selection" width="55" />
  54. <el-table-column type="index" label="序号" width="60" />
  55. <el-table-column property="name" label="员工姓名" />
  56. <el-table-column property="id_card" label="证件号码" />
  57. <el-table-column property="department.name" label="部门" />
  58. <el-table-column property="phone" label="电话" width="120" />
  59. <el-table-column property="valid" label="状态" width="90">
  60. <template #default="scope">
  61. <el-button link type="danger" size="default" v-if="scope.row.valid == 0">禁用</el-button>
  62. <el-button link type="primary" size="default" v-if="scope.row.valid == 1">启用</el-button>
  63. </template>
  64. </el-table-column>
  65. <el-table-column label="审核状态" width="120">
  66. <template #default="scope">
  67. <el-button link type="danger" v-if="scope.row.is_pass==-1">审核不通过</el-button>
  68. <el-button link type="info" v-if="scope.row.is_pass==0">待审核</el-button>
  69. <el-button link type="success" v-if="scope.row.is_pass==1">审核通过</el-button>
  70. </template>
  71. </el-table-column>
  72. <el-table-column fixed="right" label="操作" width="160">
  73. <template #default="scope">
  74. <div class="disflex">
  75. <!-- :disabled="scope.row.is_pass==1" -->
  76. <el-button link type="primary" size="small" @click="onOpenEditEmployee('edit',scope.row)" :disabled="scope.row.is_pass==1">编辑</el-button>
  77. <el-button link type="primary" size="small" @click="onOpenDetail(scope.row.id)">详情</el-button>
  78. <el-button link type="primary" size="small">
  79. <el-dropdown @command="handleCommand">
  80. <span class="el-dropdown-link">
  81. <span class="dropdown-text">更多</span>
  82. <el-icon class="el-icon--right">
  83. <arrow-down />
  84. </el-icon>
  85. </span>
  86. <template #dropdown>
  87. <el-dropdown-menu>
  88. <el-dropdown-item command="取消审核" @click="rePassOne(scope.row)">取消审核</el-dropdown-item>
  89. <!-- <el-dropdown-item command="工资设置">工资设置</el-dropdown-item> -->
  90. <el-dropdown-item command="重置登录密码" @click="onOpenResetPassword(scope.row)">重置登录密码</el-dropdown-item>
  91. <!-- <el-dropdown-item command="查看计件">查看计件</el-dropdown-item> -->
  92. <el-dropdown-item command="查看员工" @click="onOpenDetail(scope.row.id)">查看员工</el-dropdown-item>
  93. </el-dropdown-menu>
  94. </template>
  95. </el-dropdown>
  96. </el-button>
  97. </div>
  98. </template>
  99. </el-table-column>
  100. </el-table>
  101. <el-pagination
  102. @size-change="onHandleSizeChange"
  103. @current-change="onHandleCurrentChange"
  104. class="mt15"
  105. :pager-count="5"
  106. :page-sizes="[10, 20, 30]"
  107. v-model:current-page="state.param2.page"
  108. background
  109. v-model:page-size="state.param2.list_rows"
  110. layout="total, sizes, prev, pager, next, jumper"
  111. :total="state.total"
  112. >
  113. </el-pagination>
  114. </el-col>
  115. </el-row>
  116. </el-card>
  117. <DeptEditDialog ref="deptEditDialogRef" @refresh="getTableData()" />
  118. <DeptDialog ref="deptDialogRef" @refresh="getTableData()" />
  119. <ResetPasswordDialog ref="resetPasswordDialogRef" @refresh="getTableData()" />
  120. <DetailDialog ref="detailDialogRef" @refresh="getTableData()" />
  121. <ImportExcelDialog ref="importExcelDialogRef" @refresh="getTableData()" />
  122. <ExportExcelDialog ref="exportExcelDialogRef" @refresh="getTableData()" />
  123. </div>
  124. </template>
  125. <script lang="ts" setup name="underlyingDepartment">
  126. import { ref, reactive, onMounted, defineAsyncComponent } from 'vue';
  127. import { ElTable, ElMessage, ElMessageBox } from 'element-plus';
  128. import { ArrowDown, Download } from '@element-plus/icons-vue';
  129. import type Node from 'element-plus/es/components/tree/src/model/node';
  130. import Department from '/@/api/department/department.ts';
  131. import config from '/@/config.ts';
  132. const DeptEditDialog = defineAsyncComponent(() => import('/@/views/underlying/department/departEdit.vue'));
  133. const deptEditDialogRef = ref();
  134. // 打开新增部门弹窗
  135. const onOpenAddDept = (type: string) => {
  136. deptEditDialogRef.value.openDialog(type);
  137. };
  138. const onOpenEditDept = (type: string, data: Tree) => {
  139. deptEditDialogRef.value.openDialog(type, data);
  140. }
  141. const DeptDialog = defineAsyncComponent(() => import('/@/views/underlying/department/edit.vue'));
  142. const deptDialogRef = ref();
  143. // 打开新增员工弹窗
  144. const onOpenAddEmployee = (type: string) => {
  145. deptDialogRef.value.openDialog(type);
  146. };
  147. // 打开编辑员工弹窗
  148. const onOpenEditEmployee = (type: string, row: any) => {
  149. row = JSON.parse(JSON.stringify(row));
  150. console.log('row',row);
  151. deptDialogRef.value.openDialog(type, row);
  152. };
  153. const DetailDialog = defineAsyncComponent(() => import('/@/views/underlying/department/detail.vue'));
  154. const detailDialogRef = ref();
  155. // 打开详情弹窗
  156. const onOpenDetail = (id: number) => {
  157. detailDialogRef.value.openDialog(id);
  158. };
  159. interface Tree {
  160. label: string
  161. name: string
  162. children?: Tree[]
  163. department_id: number
  164. leader_id: number
  165. valid: number
  166. }
  167. const handleNodeClick = (data: Tree) => {
  168. console.log(data);
  169. state.param2.department_id = JSON.parse(JSON.stringify(data)).id;
  170. console.log('state.param2.department_id',state.param2.department_id);
  171. getAdminList();
  172. }
  173. const data: Tree[] = [
  174. {
  175. label: '研发部 1',
  176. name: '研发部 1',
  177. department_id: 1,
  178. leader_id: 1,
  179. valid: 1,
  180. children: [
  181. {
  182. label: '研发部 1-1',
  183. name: '研发部 1-1',
  184. department_id: 1,
  185. leader_id: 1,
  186. valid: 1,
  187. children: [
  188. {
  189. label: '研发部 1-1-1',
  190. name: '研发部 1-1-1',
  191. department_id: 1,
  192. leader_id: 1,
  193. valid: 1,
  194. },
  195. ],
  196. },
  197. ],
  198. },
  199. {
  200. label: '运营部 2',
  201. name: '运营部 2',
  202. department_id: 1,
  203. leader_id: 1,
  204. valid: 1,
  205. children: [
  206. {
  207. label: '运营部 2-1',
  208. name: '运营部 2-1',
  209. department_id: 1,
  210. leader_id: 1,
  211. valid: 1,
  212. children: [
  213. {
  214. label: '运营部 2-1-1',
  215. name: '运营部 2-1-1',
  216. department_id: 1,
  217. leader_id: 1,
  218. valid: 1,
  219. },
  220. ],
  221. },
  222. {
  223. label: '运营部 2-2',
  224. name: '运营部 2-2',
  225. department_id: 1,
  226. leader_id: 1,
  227. valid: 1,
  228. children: [
  229. {
  230. label: '运营部 2-2-1',
  231. name: '运营部 2-2-1',
  232. department_id: 1,
  233. leader_id: 1,
  234. valid: 1,
  235. },
  236. ],
  237. },
  238. ],
  239. },
  240. {
  241. label: '生产部 3',
  242. name: '生产部 3',
  243. department_id: 1,
  244. leader_id: 1,
  245. valid: 1,
  246. children: [
  247. {
  248. label: '生产部 3-1',
  249. name: '生产部 3-1',
  250. department_id: 1,
  251. leader_id: 1,
  252. valid: 1,
  253. children: [
  254. {
  255. label: '生产部 3-1-1',
  256. name: '生产部 3-1-1',
  257. department_id: 1,
  258. leader_id: 1,
  259. valid: 1,
  260. },
  261. ],
  262. },
  263. {
  264. label: '生产部 3-2',
  265. name: '生产部 3-2',
  266. department_id: 1,
  267. leader_id: 1,
  268. valid: 1,
  269. children: [
  270. {
  271. label: '生产部 3-2-1',
  272. name: '生产部 3-2-1',
  273. department_id: 1,
  274. leader_id: 1,
  275. valid: 1,
  276. },
  277. ],
  278. },
  279. ],
  280. },
  281. ]
  282. const defaultProps = {
  283. children: 'children',
  284. label: 'label',
  285. }
  286. interface User {
  287. id: number
  288. head_img: string
  289. gender: number
  290. name: string
  291. department_id: number
  292. id_card: string
  293. age: number
  294. phone: string
  295. valid: number
  296. role_id: number
  297. create_time: string
  298. update_time: string
  299. is_pass: number
  300. pass_time: string
  301. }
  302. const multipleTableRef = ref<InstanceType<typeof ElTable>>()
  303. const multipleSelection = ref<User[]>([])
  304. const toggleSelection = (rows?: User[]) => {
  305. if (rows) {
  306. rows.forEach((row) => {
  307. // TODO: improvement typing when refactor table
  308. // eslint-disable-next-line @typescript-eslint/ban-ts-comment
  309. // @ts-expect-error
  310. multipleTableRef.value!.toggleRowSelection(row, undefined)
  311. })
  312. } else {
  313. multipleTableRef.value!.clearSelection()
  314. }
  315. }
  316. const handleSelectionChange = (val: User[]) => {
  317. multipleSelection.value = val
  318. console.log('multipleSelection',multipleSelection.value);
  319. }
  320. const ResetPasswordDialog = defineAsyncComponent(() => import('/@/views/underlying/department/resetPassword.vue'));
  321. const resetPasswordDialogRef = ref();
  322. const onOpenResetPassword = (row:any) => {
  323. resetPasswordDialogRef.value.openDialog(row);
  324. }
  325. const handleCommand = (command: string) => {
  326. console.log('command',command);
  327. }
  328. const del = () => {
  329. console.log('multipleSelection.value',multipleSelection.value);
  330. if(multipleSelection.value.length==0){
  331. return ElMessage.warning("请选择要操作的列表");
  332. }
  333. let name = [];
  334. let noName = [];
  335. state.ids = [];
  336. for(let i=0;i<multipleSelection.value.length;i++){
  337. if(multipleSelection.value[i].is_pass==1){
  338. noName.push(multipleSelection.value[i].name);
  339. }else{
  340. name.push(multipleSelection.value[i].name);
  341. state.ids.push(multipleSelection.value[i].id);
  342. }
  343. }
  344. if(noName.length>0){
  345. return ElMessage.warning(`员工名称:“${noName}”不允许删除,请先反审核再操作`);
  346. }
  347. ElMessageBox.confirm(`此操作将永久删除员工名称:“${name}”,是否继续?`, '提示', {
  348. confirmButtonText: '确认',
  349. cancelButtonText: '取消',
  350. type: 'warning',
  351. })
  352. .then(() => {
  353. console.log('ids',JSON.stringify(state.ids).split('[')[1].split(']')[0]);
  354. delOnce('del',JSON.stringify(state.ids).split('[')[1].split(']')[0]);
  355. // getTableData();
  356. // ElMessage.success('删除成功');
  357. })
  358. .catch(() => {});
  359. }
  360. const remove = (node: Node, data: Tree) => {
  361. console.log('node', node);
  362. console.log('data', data);
  363. ElMessageBox.confirm(`此操作将永久删除部门名称:“${data.name}”,是否继续?`, '提示', {
  364. confirmButtonText: '确认',
  365. cancelButtonText: '取消',
  366. type: 'warning',
  367. })
  368. .then(() => {
  369. delOnce('remove',data.id);
  370. // getTableData();
  371. // ElMessage.success('删除成功');
  372. })
  373. .catch(() => {});
  374. // ElMessage(`click on 删除 ${data.name}`);
  375. }
  376. const delOnce = async(type: string, ids: number | string) => {
  377. let res: any = null;
  378. if(type=='del'){
  379. res = await Department.delAdmin(ids);
  380. if(res.code != 0){
  381. return ElMessage.error(res.msg);
  382. }
  383. }else if(type=='remove'){
  384. res = await Department.del(ids);
  385. if(res.code != 0){
  386. return ElMessage.error(res.msg);
  387. }
  388. }else{
  389. return ElMessage.warning("操作有误");
  390. }
  391. getTableData();
  392. ElMessage.success(res.msg);
  393. }
  394. const pass = () => {
  395. console.log('multipleSelection.value',multipleSelection.value.length);
  396. if(multipleSelection.value.length==0){
  397. return ElMessage.warning("请选择要操作的列表");
  398. }
  399. let name = [];
  400. let noName= [];
  401. state.ids = [];
  402. for(let i=0;i<multipleSelection.value.length;i++){
  403. if(multipleSelection.value[i].is_pass==1){
  404. noName.push(multipleSelection.value[i].name);
  405. }else{
  406. name.push(multipleSelection.value[i].name);
  407. state.ids.push(multipleSelection.value[i].id);
  408. }
  409. }
  410. if(noName.length>0){
  411. return ElMessage.warning(`员工名称:“${noName}”已审核通过,无需重复操作`);
  412. }
  413. ElMessageBox.confirm(`此操作将审核:“${name}”,是否继续?`, '提示', {
  414. confirmButtonText: '确认',
  415. cancelButtonText: '取消',
  416. type: 'warning',
  417. })
  418. .then(() => {
  419. console.log('ids',JSON.stringify(state.ids).split('[')[1].split(']')[0]);
  420. requestPass('pass',JSON.stringify(state.ids).split('[')[1].split(']')[0]);
  421. // getTableData();
  422. // ElMessage.success('删除成功');
  423. })
  424. .catch(() => {});
  425. }
  426. const repass = () => {
  427. console.log('multipleSelection.value',multipleSelection.value.length);
  428. if(multipleSelection.value.length==0){
  429. return ElMessage.warning("请选择要操作的列表");
  430. }
  431. let name = [];
  432. let noName= [];
  433. state.ids = [];
  434. for(let i=0;i<multipleSelection.value.length;i++){
  435. if(multipleSelection.value[i].is_pass==0){
  436. noName.push(multipleSelection.value[i].name);
  437. }else{
  438. name.push(multipleSelection.value[i].name);
  439. state.ids.push(multipleSelection.value[i].id);
  440. }
  441. }
  442. if(noName.length>0){
  443. return ElMessage.warning(`员工名称:“${noName}”已处于反审核状态,无需重复操作`);
  444. }
  445. ElMessageBox.confirm(`此操作将反审核:“${name}”,是否继续?`, '提示', {
  446. confirmButtonText: '确认',
  447. cancelButtonText: '取消',
  448. type: 'warning',
  449. })
  450. .then(() => {
  451. console.log('ids',JSON.stringify(state.ids).split('[')[1].split(']')[0]);
  452. requestPass('rePass',JSON.stringify(state.ids).split('[')[1].split(']')[0]);
  453. // getTableData();
  454. // ElMessage.success('删除成功');
  455. })
  456. .catch(() => {});
  457. }
  458. const requestPass = async(type: string, ids: number | string) => {
  459. let res: any = null;
  460. if(type=='pass'){
  461. res = await Department.passAdmin(ids);
  462. if(res.code != 0){
  463. return ElMessage.error(res.msg);
  464. }
  465. }else if(type=='rePass'){
  466. res = await Department.rePassAdmin(ids);
  467. if(res.code != 0){
  468. return ElMessage.error(res.msg);
  469. }
  470. }else{
  471. return ElMessage.warning("操作有误");
  472. }
  473. getTableData();
  474. ElMessage.success(res.msg);
  475. }
  476. const rePassOne = (row:any) => {
  477. if(row.is_pass==0){
  478. return ElMessage.warning("该记录已处于反审核状态,无需重复操作");
  479. }
  480. ElMessageBox.confirm(`此操作将反审核:“${row.name}”,是否继续?`, '提示', {
  481. confirmButtonText: '确认',
  482. cancelButtonText: '取消',
  483. type: 'warning',
  484. })
  485. .then(() => {
  486. requestPass('rePass',row.id);
  487. })
  488. .catch(() => {});
  489. }
  490. const ImportExcelDialog = defineAsyncComponent(() => import('/@/views/underlying/department/import.vue'));
  491. const importExcelDialogRef = ref();
  492. const importExcel = () => {
  493. importExcelDialogRef.value.openDialog();
  494. }
  495. const ExportExcelDialog = defineAsyncComponent(() => import('/@/views/underlying/department/export.vue'));
  496. const exportExcelDialogRef = ref();
  497. const exportExcel = async() => {
  498. let res = await Department.export();
  499. if(res.code != 0){
  500. return ElMessage.error(res.msg);
  501. }
  502. state.download_file_url = config.file +'/'+ res.data.path;
  503. console.log('state.download_file_url',state.download_file_url);
  504. exportExcelDialogRef.value.openDialog(state.download_file_url);
  505. }
  506. const deptAll = () => {
  507. state.param2 = {
  508. keyword: '',
  509. page: 1,
  510. list_rows: 10,
  511. department_id: 0,
  512. };
  513. getTableData();
  514. }
  515. const state = reactive({
  516. tableData: [],
  517. total: 0,
  518. loading: false,
  519. param1: {
  520. keyword: '',
  521. },
  522. param2: {
  523. keyword: '',
  524. page: 1,
  525. list_rows: 10,
  526. department_id: 0,
  527. },
  528. ids:<any> [],
  529. data: [],
  530. download_file_url: '',
  531. });
  532. const initDept = async() => {
  533. let res = await Department.init();
  534. if(res.code != 0){
  535. return ElMessage.error(res.msg);
  536. }
  537. }
  538. const getDeptList = async() => {
  539. let res = await Department.list(state.param1);
  540. if(res.code != 0){
  541. return ElMessage.error(res.msg);
  542. }
  543. state.data = res.data;
  544. getAdminList();
  545. }
  546. const getAdminList = async() => {
  547. console.log("getAdminList");
  548. let res = await Department.listAdmin(state.param2);
  549. if(res.code != 0){
  550. return ElMessage.error(res.msg);
  551. }
  552. state.tableData = res.data.data;
  553. state.total = res.data.total;
  554. }
  555. // 初始化表格数据
  556. const getTableData = () => {
  557. getDeptList();
  558. state.loading = true;
  559. setTimeout(() => {
  560. state.loading = false;
  561. }, 500);
  562. };
  563. // 分页改变
  564. const onHandleSizeChange = (val: number) => {
  565. state.param2.list_rows = val;
  566. getTableData();
  567. };
  568. // 分页改变
  569. const onHandleCurrentChange = (val: number) => {
  570. state.param2.page = val;
  571. getTableData();
  572. };
  573. // 页面加载时
  574. onMounted(() => {
  575. initDept();
  576. getTableData();
  577. });
  578. </script>
  579. <style lang="scss" scoped>
  580. .card-header {
  581. display: flex;
  582. justify-content: space-between;
  583. align-items: center;
  584. .dept-all{
  585. cursor: pointer;
  586. }
  587. .dept-all:hover{
  588. cursor: pointer;
  589. color: #409EFF;
  590. }
  591. }
  592. .box-card {
  593. margin: 10px;
  594. }
  595. .disflex{
  596. display: flex;
  597. }
  598. .example-showcase .el-dropdown-link {
  599. cursor: pointer;
  600. color: var(--el-color-primary);
  601. display: flex;
  602. align-items: center;
  603. }
  604. .dropdown-text{
  605. color: #409EFF;
  606. font-size: 12px;
  607. }
  608. .custom-tree-node {
  609. flex: 1;
  610. display: flex;
  611. align-items: center;
  612. justify-content: space-between;
  613. font-size: 14px;
  614. padding-right: 8px;
  615. .a1{
  616. color: #409EFF;
  617. }
  618. .a2{
  619. color: #F56C6C;
  620. margin-left: 8px
  621. }
  622. }
  623. </style>