UserList.vue 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588
  1. <template>
  2. <a-card :bordered="false">
  3. <!-- 查询区域 -->
  4. <div class="table-page-search-wrapper">
  5. <a-form layout="inline" @keyup.enter.native="searchQuery">
  6. <a-row :gutter="24">
  7. <a-col :md="6" :sm="12">
  8. <a-form-item label="真实名字">
  9. <a-input placeholder="请输入真实名字" v-model="queryParam.realname"></a-input>
  10. </a-form-item>
  11. </a-col>
  12. <a-col :md="6" :sm="8">
  13. <a-form-item label="工号">
  14. <a-input placeholder="请输入工号查询" v-model="queryParam.workNo"></a-input>
  15. </a-form-item>
  16. </a-col>
  17. <template v-if="toggleSearchStatus">
  18. <a-col :md="6" :sm="8">
  19. <a-form-item label="部门名称">
  20. <j-tree-select
  21. style="width: 200px"
  22. v-model="queryParam.orgCodeTxt"
  23. dict="sys_depart,depart_name,id"
  24. pid-field="parent_id">
  25. </j-tree-select>
  26. </a-form-item>
  27. </a-col>
  28. <a-col :md="6" :sm="8">
  29. <!-- <a-form-item label="性别">
  30. <a-select v-model="queryParam.sex" placeholder="请选择性别">
  31. <a-select-option value="">请选择</a-select-option>
  32. <a-select-option value="1">男</a-select-option>
  33. <a-select-option value="2">女</a-select-option>
  34. </a-select>
  35. </a-form-item> -->
  36. </a-col>
  37. <a-col :md="6" :sm="8">
  38. <a-form-item label="人员类别">
  39. <a-select v-model="queryParam.category" placeholder="请选择">
  40. <a-select-option value="101">正式工</a-select-option>
  41. <a-select-option value="102">顾问</a-select-option>
  42. <a-select-option value="103">实习生</a-select-option>
  43. <a-select-option value="104">劳务工</a-select-option>
  44. <a-select-option value="105">劳务外包5+2</a-select-option>
  45. <a-select-option value="106">劳务外包6+1</a-select-option>
  46. </a-select>
  47. </a-form-item>
  48. <!-- <a-form-item label="手机号码">
  49. <a-input placeholder="请输入手机号码查询" v-model="queryParam.phone"></a-input>
  50. </a-form-item> -->
  51. </a-col>
  52. <a-col :md="6" :sm="8">
  53. <a-form-item label="雇佣状态">
  54. <a-select v-model="queryParam.employmentStatus" placeholder="请选择">
  55. <a-select-option value="10">在职</a-select-option>
  56. <a-select-option value="20">离退</a-select-option>
  57. <a-select-option value="30">离职</a-select-option>
  58. <a-select-option value="40">待入职</a-select-option>
  59. </a-select>
  60. </a-form-item>
  61. </a-col>
  62. </template>
  63. <a-col :md="6" :sm="8">
  64. <span style="float: left;overflow: hidden;" class="table-page-search-submitButtons">
  65. <a-button type="primary" @click="searchQuery" icon="search">查询</a-button>
  66. <a-button type="primary" @click="searchReset" icon="reload" style="margin-left: 8px">重置</a-button>
  67. <a @click="handleToggleSearch" style="margin-left: 8px">
  68. {{ toggleSearchStatus ? '收起' : '展开' }}
  69. <a-icon :type="toggleSearchStatus ? 'up' : 'down'"/>
  70. </a>
  71. </span>
  72. </a-col>
  73. </a-row>
  74. </a-form>
  75. </div>
  76. <!-- 操作按钮区域 -->
  77. <div class="table-operator" style="border-top: 5px">
  78. <a-button @click="handleAdd()" type="primary" icon="plus" v-has="'user:add'" >添加员工</a-button>
  79. <a-button @click="handleExportXltx()"type="primary" icon="plus" v-has="'user:usermb'" >员工模板</a-button>
  80. <a-button @click="handleExportXls3('薪资模板')"type="primary" icon="plus" v-has="'user:changemb'" >薪资模板</a-button>
  81. <a-button type="primary" icon="download" @click="handleExportXls('用户信息')" v-has='"user:export"'>导出</a-button>
  82. <a-upload name="file" :showUploadList="false" :multiple="false" :headers="tokenHeader" :action="importExcelUrl" @change="handleImportExcel" v-has='"user:import"'>
  83. <a-button type="primary" icon="import">员工导入</a-button>
  84. </a-upload>
  85. <a-upload name="file" :showUploadList="false" :multiple="false" :headers="tokenHeader" :action="importExcelUrls" @change="handleImportExcels" v-has='"user:import"'>
  86. <a-button type="primary" icon="import">薪资导入</a-button>
  87. </a-upload>
  88. <a-button type="primary" icon="hdd" @click="recycleBinVisible=true" v-has='"user:recovery"'>回收站</a-button>
  89. <a-dropdown v-if="selectedRowKeys.length > 0">
  90. <a-menu slot="overlay" @click="handleMenuClick">
  91. <a-menu-item key="1" v-if="selectionRows[0].employmentStatus==40" >
  92. <a-icon type="delete" @click="batchDel" />
  93. 删除
  94. </a-menu-item>
  95. <a-menu-item key="4" v-if="selectionRows[0].employmentStatus==40" >
  96. <a-icon type="check-circle" @click="batchrz"/>
  97. 入职
  98. </a-menu-item>
  99. </a-menu>
  100. <a-button style="margin-left: 8px">
  101. 批量操作
  102. <a-icon type="down"/>
  103. </a-button>
  104. </a-dropdown>
  105. <!-- <j-super-query :fieldList="superQueryFieldList" @handleSuperQuery="handleSuperQuery" v-has='"user:query"'/> -->
  106. </div>
  107. <!-- table区域-begin -->
  108. <div>
  109. <div class="ant-alert ant-alert-info" style="margin-bottom: 16px;">
  110. <i class="anticon anticon-info-circle ant-alert-icon"></i>已选择&nbsp;<a style="font-weight: 600">{{ selectedRowKeys.length }}</a>项&nbsp;&nbsp;
  111. <a style="margin-left: 24px" @click="onClearSelected">清空</a>
  112. </div>
  113. <a-table
  114. ref="table"
  115. bordered
  116. size="middle"
  117. rowKey="id"
  118. :columns="columns"
  119. :dataSource="dataSource"
  120. :pagination="ipagination"
  121. :loading="loading"
  122. :rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}"
  123. @change="handleTableChange" :scroll="{ y: 700,x:1100 }">
  124. <template slot="avatarslot" slot-scope="text, record, index">
  125. <div class="anty-img-wrap">
  126. <a-avatar shape="square" :src="getAvatarView(record.avatar)" icon="user"/>
  127. </div>
  128. </template>
  129. <template slot="userRealname" slot-scope="text, record, index">
  130. <div class="anty-img-wrap">
  131. <a @click="handleDetails(record)" >{{text}}</a>
  132. </div>
  133. </template>
  134. <span slot="categorys" slot-scope="text, record, index">
  135. <a-tag color="#87d068" v-if="record.category=='101'||record.category==101 ">正式工</a-tag>
  136. <a-tag color="#87d068" v-else-if="record.category=='102'||record.category==102 ">顾问</a-tag>
  137. <a-tag color="#87d068" v-else-if="record.category=='103'||record.category==103 ">实习生</a-tag>
  138. <a-tag color="#87d068" v-else-if="record.category=='104'||record.category==104 ">劳务工</a-tag>
  139. <a-tag color="#87d068" v-else-if="record.category=='104'||record.category==105 ">劳务外包5+2</a-tag>
  140. <a-tag color="#87d068" v-else-if="record.category=='104'||record.category==106 ">劳务外包6+1</a-tag>
  141. </span>
  142. <span slot="employmentStatuss" slot-scope="text, record, index">
  143. <a-tag color="#87d068" v-if="record.employmentStatus=='10'||record.employmentStatus==10 ">在职</a-tag>
  144. <a-tag color="#cd201f" v-else-if="record.employmentStatus=='20'||record.employmentStatus==20 ">离退</a-tag>
  145. <a-tag color="#cd201f" v-else-if="record.employmentStatus=='30'||record.employmentStatus==30 ">离职</a-tag>
  146. <a-tag color="blue" v-else-if="record.employmentStatus=='40'||record.employmentStatus==40 ">待入职</a-tag>
  147. </span>
  148. <span slot="action" slot-scope="text, record">
  149. <a @click="handleEdit(record)" v-has='"user:edit"'>编辑</a>
  150. <a-divider type="vertical"/>
  151. <a @click="handleChangePassword(record.username)" v-has='"user:edit"'>修改密码</a>
  152. <!-- <a-dropdown v-has='"user:more"'>
  153. <a class="ant-dropdown-link">
  154. 更多 <a-icon type="down"/>
  155. </a>
  156. <a-menu slot="overlay">
  157. <a-menu-item v-has="'user:details'" v-if="record.employmentStatus==40||record.employmentStatus=='40'">
  158. <a href="javascript:;" @click="handleDetails(record)">入职</a>
  159. </a-menu-item>
  160. <a-menu-item v-has='"user:delete"'>
  161. <a-popconfirm title="确定删除吗?" @confirm="() => handleDelete(record.id)">
  162. <a>删除</a>
  163. </a-popconfirm>
  164. </a-menu-item>
  165. </a-menu>
  166. </a-dropdown> -->
  167. </span>
  168. </a-table>
  169. </div>
  170. <!-- table区域-end -->
  171. <user-modal ref="modalForm" @ok="modalFormOk"></user-modal>
  172. <user-detail-modal ref="userdetailmodal"></user-detail-modal>
  173. <password-modal ref="passwordmodal" @ok="passwordModalOk"></password-modal>
  174. <!-- 用户回收站 -->
  175. <user-recycle-bin-modal :visible.sync="recycleBinVisible" @ok="modalFormOk"/>
  176. </a-card>
  177. </template>
  178. <script>
  179. import UserModal from './modules/UserModal'
  180. import UserDetailModal from './modules/UserDetailModal'
  181. import PasswordModal from './modules/PasswordModal'
  182. import {putAction,getFileAccessHttpUrl,getAction,downFile} from '@/api/manage';
  183. import {frozenBatch} from '@/api/api'
  184. import {JeecgListMixin} from '@/mixins/JeecgListMixin'
  185. import JInput from '@/components/jeecg/JInput'
  186. import UserRecycleBinModal from './modules/UserRecycleBinModal'
  187. import JSuperQuery from '@/components/jeecg/JSuperQuery'
  188. import JSelectDepart from '@/components/jeecgbiz/JSelectDepart'
  189. import JTreeSelect from '@/components/jeecg/JTreeSelect'
  190. import { ACCESS_TOKEN, TENANT_ID } from "@/store/mutation-types"
  191. import store from '@/store'
  192. import { filterObj } from '@/utils/util';
  193. import {Modal} from 'ant-design-vue'
  194. import Vue from 'vue'
  195. export default {
  196. name: "UserList",
  197. mixins: [JeecgListMixin],
  198. components: {
  199. UserModal,
  200. PasswordModal,
  201. JInput,
  202. UserRecycleBinModal,
  203. UserDetailModal,
  204. JSuperQuery,
  205. JSelectDepart,
  206. JTreeSelect
  207. },
  208. data() {
  209. return {
  210. description: '这是用户管理页面',
  211. queryParam: {
  212. employmentStatus:"10",
  213. category:"101"
  214. },
  215. recycleBinVisible: false,
  216. selectedRowKeys:[],
  217. selectionRows:[],
  218. columns: [
  219. /*{
  220. title: '#',
  221. dataIndex: '',
  222. key:'rowIndex',
  223. width:60,
  224. align:"center",
  225. customRender:function (t,r,index) {
  226. return parseInt(index)+1;
  227. }
  228. },*/
  229. {
  230. title: '工号',
  231. align: "center",
  232. dataIndex: 'workNo',
  233. width: 100,
  234. },
  235. {
  236. title: '员工姓名',
  237. align: "center",
  238. width: 100,
  239. dataIndex: 'realname',
  240. scopedSlots: {customRender: "userRealname"}
  241. },
  242. // {
  243. // title: '头像',
  244. // align: "center",
  245. // width: 100,
  246. // dataIndex: 'avatar',
  247. // scopedSlots: {customRender: "avatarslot"}
  248. // },
  249. {
  250. title: '性别',
  251. align: "center",
  252. width: 80,
  253. dataIndex: 'sex_dictText',
  254. },
  255. // {
  256. // title: '生日',
  257. // align: "center",
  258. // width: 100,
  259. // dataIndex: 'birthday'
  260. // },
  261. // {
  262. // title: '手机号码',
  263. // align: "center",
  264. // width: 120,
  265. // dataIndex: 'phone',
  266. // customRender:function (t,r,index) {
  267. // if(t!=null&&t!=""){
  268. // var a=t.slice(0,3);
  269. // var b=t.slice(8,11);
  270. // return a+"****"+b;
  271. // }else{
  272. // return"";
  273. // }
  274. // }
  275. // },
  276. {
  277. title: '邮箱',
  278. align: "center",
  279. width: 120,
  280. dataIndex: 'email'
  281. },
  282. {
  283. title: '一级部门',
  284. align: "center",
  285. width: 120,
  286. dataIndex: 'del2'
  287. },
  288. {
  289. title: '二级部门',
  290. align: "center",
  291. width: 120,
  292. dataIndex: 'del3'
  293. },
  294. {
  295. title: '三级部门',
  296. align: "center",
  297. width: 120,
  298. dataIndex: 'del4'
  299. },
  300. {
  301. title: '职位',
  302. align: "center",
  303. width: 120,
  304. dataIndex: 'post_dictText'
  305. },
  306. {
  307. title: '入职时间',
  308. align: "center",
  309. width: 120,
  310. dataIndex: 'entryDate'
  311. },
  312. {
  313. title: '人员类别',
  314. align: "center",
  315. width: 100,
  316. dataIndex: 'category',
  317. scopedSlots: {customRender: "categorys"},
  318. },
  319. {
  320. title: '雇佣状态',
  321. align: "center",
  322. width: 100,
  323. dataIndex: 'employmentStatus',
  324. scopedSlots: {customRender: "employmentStatuss"},
  325. },
  326. // {
  327. // title: '状态',
  328. // align: "center",
  329. // width: 80,
  330. // dataIndex: 'status_dictText'
  331. // },
  332. {
  333. title: '操作',
  334. dataIndex: 'action',
  335. scopedSlots: {customRender: 'action'},
  336. align: "center",
  337. width: 170
  338. }
  339. ],
  340. superQueryFieldList: [
  341. { type: 'input', value: 'username', text: '用户账号', },
  342. { type: 'input', value: 'realname', text: '用户姓名', },
  343. { type: 'select', value: 'sex', text: '性别', dictCode: 'sex' },
  344. ],
  345. url: {
  346. syncUser: "/act/process/extActProcess/doSyncUser",
  347. list: "/sys/user/list",
  348. delete: "/sys/user/delete",
  349. deleteBatch: "/sys/user/deleteBatch",
  350. exportXlsUrl: "/sys/user/exportXls",
  351. importExcelUrl: "sys/user/importExcel",
  352. importExcelUrls:'sys/user/importExcels',
  353. pulldata:"/sys/weixin/pullData",
  354. editstate:"/sys/user/editState",
  355. userChangemb:'/userchange/userChage/exportXls'
  356. },
  357. }
  358. },
  359. computed: {
  360. importExcelUrl: function(){
  361. return `${window._CONFIG['domianURL']}/${this.url.importExcelUrl}`;
  362. },
  363. importExcelUrls(){
  364. return `${window._CONFIG['domianURL']}/${this.url.importExcelUrls}`;
  365. }
  366. },
  367. methods: {
  368. // onSelectChanges(selectedRowKeys, selectionRows) {
  369. // this.selectedRowKeys = selectedRowKeys;
  370. // this.selectionRows = selectionRows;
  371. // },
  372. handleExportXltx(){
  373. this.queryParam.orgCodeTxt="空白模板";
  374. this.$options.methods.handleExportXls.call(this)
  375. this.queryParam.orgCodeTxt="";
  376. },
  377. getAvatarView: function (avatar) {
  378. return getFileAccessHttpUrl(avatar)
  379. },
  380. batchrz(){
  381. if (this.selectedRowKeys.length<=0) {
  382. this.$message.warning('请选择一条记录!');
  383. return false;
  384. } else {
  385. var userids=this.selectedRowKeys.join(",");
  386. getAction(this.url.editstate, {
  387. userids:userids
  388. }).then(res => {
  389. if (res.success) {
  390. this.$message.success(res.message);
  391. this.loadData();
  392. }else{
  393. this.$message.warning(res.message);
  394. }
  395. })
  396. this.selectedRowKeys=[];
  397. this.selectionRows=[];
  398. }
  399. },
  400. batchFrozen: function (status) {
  401. if (this.selectedRowKeys.length <= 0) {
  402. this.$message.warning('请选择一条记录!');
  403. return false;
  404. } else {
  405. let ids = "";
  406. let that = this;
  407. let isAdmin = false;
  408. that.selectionRows.forEach(function (row) {
  409. if (row.username == 'admin') {
  410. isAdmin = true;
  411. }
  412. });
  413. if (isAdmin) {
  414. that.$message.warning('管理员账号不允许此操作,请重新选择!');
  415. return;
  416. }
  417. that.selectedRowKeys.forEach(function (val) {
  418. ids += val + ",";
  419. });
  420. that.$confirm({
  421. title: "确认操作",
  422. content: "是否" + (status == 1 ? "解冻" : "冻结") + "选中账号?",
  423. onOk: function () {
  424. frozenBatch({ids: ids, status: status}).then((res) => {
  425. if (res.success) {
  426. that.$message.success(res.message);
  427. that.loadData();
  428. that.onClearSelected();
  429. } else {
  430. that.$message.warning(res.message);
  431. }
  432. });
  433. }
  434. });
  435. }
  436. },
  437. handleMenuClick(e) {
  438. if (e.key == 1) {
  439. this.batchDel();
  440. } else if (e.key == 2) {
  441. this.batchFrozen(2);
  442. } else if (e.key == 3) {
  443. this.batchFrozen(1);
  444. }else if(e.key==4){
  445. this.batchrz();
  446. }
  447. },
  448. handleDetails(e){
  449. console.log(this.$refs)
  450. this.$refs.userdetailmodal.edit(e);
  451. },
  452. handleFrozen: function (id, status, username) {
  453. let that = this;
  454. //TODO 后台校验管理员角色
  455. if ('admin' == username) {
  456. that.$message.warning('管理员账号不允许此操作!');
  457. return;
  458. }
  459. frozenBatch({ids: id, status: status}).then((res) => {
  460. if (res.success) {
  461. that.$message.success(res.message);
  462. that.loadData();
  463. } else {
  464. that.$message.warning(res.message);
  465. }
  466. });
  467. },
  468. handleExportXls3(fileName){
  469. if(!fileName || typeof fileName != "string"){
  470. fileName = "导出文件"
  471. }
  472. downFile(this.url.userChangemb,{}).then((data)=>{
  473. if (!data) {
  474. this.$message.warning("文件下载失败")
  475. return
  476. }
  477. if (typeof window.navigator.msSaveBlob !== 'undefined') {
  478. window.navigator.msSaveBlob(new Blob([data],{type: 'application/vnd.ms-excel'}), fileName+'.xls')
  479. }else{
  480. let url = window.URL.createObjectURL(new Blob([data],{type: 'application/vnd.ms-excel'}))
  481. let link = document.createElement('a')
  482. link.style.display = 'none'
  483. link.href = url
  484. link.setAttribute('download', fileName+'.xls')
  485. document.body.appendChild(link)
  486. link.click()
  487. document.body.removeChild(link); //下载完成移除元素
  488. window.URL.revokeObjectURL(url); //释放掉blob对象
  489. }
  490. })
  491. },
  492. /* 导入 */
  493. handleImportExcels(info){
  494. if (info.file.status !== 'uploading') {
  495. console.log(info.file, info.fileList);
  496. }
  497. if (info.file.status === 'done') {
  498. if (info.file.response.success) {
  499. // this.$message.success(`${info.file.name} 文件上传成功`);
  500. if (info.file.response.code === 201) {
  501. let { message, result: { msg, fileUrl, fileName } } = info.file.response
  502. let href = window._CONFIG['domianURL'] + fileUrl
  503. this.$warning({
  504. title: message,
  505. content: (<div>
  506. <span>{msg}</span><br/>
  507. <span>具体详情请 <a href={href} target="_blank" download={fileName}>点击下载</a> </span>
  508. </div>
  509. )
  510. })
  511. } else {
  512. this.$message.success(info.file.response.message || `${info.file.name} 文件上传成功`)
  513. }
  514. this.loadData()
  515. } else {
  516. this.$message.error(`${info.file.name} ${info.file.response.message}.`);
  517. }
  518. } else if (info.file.status === 'error') {
  519. if (info.file.response.status === 500) {
  520. let data = info.file.response
  521. const token = Vue.ls.get(ACCESS_TOKEN)
  522. if (token && data.message.includes("Token失效")) {
  523. Modal.error({
  524. title: '登录已过期',
  525. content: '很抱歉,登录已过期,请重新登录',
  526. okText: '重新登录',
  527. mask: false,
  528. onOk: () => {
  529. store.dispatch('Logout').then(() => {
  530. Vue.ls.remove(ACCESS_TOKEN)
  531. window.location.reload();
  532. })
  533. }
  534. })
  535. }
  536. } else {
  537. this.$message.error(`文件上传失败: ${info.file.msg} `);
  538. }
  539. }
  540. },
  541. handleChangePassword(username) {
  542. this.$refs.passwordmodal.show(username);
  543. },
  544. passwordModalOk() {
  545. //TODO 密码修改完成 不需要刷新页面,可以把datasource中的数据更新一下
  546. }
  547. }
  548. }
  549. </script>
  550. <style scoped>
  551. @import '~@assets/less/common.less'
  552. </style>