index.vue 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790
  1. <template>
  2. <div class="user">
  3. <basic-container>
  4. <avue-crud
  5. ref="crud"
  6. :option="option"
  7. :search="searchForm"
  8. v-model="form"
  9. :page.sync="page"
  10. :table-loading="tableLoading"
  11. :before-open="handleOpenBefore"
  12. :before-close="handleCloseBefore"
  13. :data="list"
  14. @search-change="searchChange"
  15. @size-change="sizeChange"
  16. @current-change="currentChange"
  17. @search-reset="searchReset"
  18. @refresh-change="refreshChange"
  19. @row-save="saveFn"
  20. @row-update="updateFn"
  21. >
  22. <!-- 左侧添加按钮 -->
  23. <template slot="menuLeft">
  24. <el-button v-if="sys_user_add" class="filter-item" type="primary" size="small" icon="el-icon-edit" @click="$refs.crud.rowAdd()">添加 </el-button>
  25. <!-- 新增沟通专员 -->
  26. <el-button v-if="sys_user_add && hideCommunicationOfficer" class="filter-item" type="primary" size="small" icon="el-icon-user" @click="addCommunicationOfficerFn"
  27. >新增服务商人员
  28. </el-button>
  29. <!-- 批量导入 -->
  30. <el-button class="filter-item" type="primary" size="small" icon="el-icon-upload" @click="importUserOpen">导入用户 </el-button>
  31. </template>
  32. <!-- 右侧菜单 -->
  33. <template slot="menuRight">
  34. <!-- 角色说明隐藏 -->
  35. <el-button v-if="userInfo?.roles?.includes(50) && downShow" size="small" :disabled="exportUserInfoDisabled" type="primary" @click="downInfo">{{
  36. exportUserInfoText
  37. }}</el-button>
  38. <el-button v-if="userInfo?.roles?.includes(50)" size="small" type="primary" @click="exportUserInfo">导出人员数据</el-button>
  39. </template>
  40. <!-- 操作栏 -->
  41. <template slot="menu" slot-scope="scope">
  42. <el-button v-if="sys_user_edit" type="text" size="small" icon="el-icon-edit" @click="handleUpdate(scope.row, scope.index)">编辑 </el-button>
  43. <el-button v-if="sys_user_del" type="text" size="small" icon="el-icon-delete" @click="deleteFn(scope.row, scope.index)">删除 </el-button>
  44. <el-button v-if="scope.row.role.includes(5)" type="text" size="small" icon="el-icon-document" @click="fullTimeStaffRecordFn(scope.row)">备案 </el-button>
  45. <el-button v-if="showBoundMedicines(scope.row.role)" type="text" size="small" icon="el-icon-document" @click="boundMedicines(scope.row)">绑定药品 </el-button>
  46. <el-button v-if="false" type="text" size="small" icon="el-icon-document" @click="userInfoCardFn(scope.row)">个人名片 </el-button>
  47. </template>
  48. <!-- 人员名称 -->
  49. <template slot="realname" slot-scope="scope">
  50. <div class="info">
  51. <!-- <span class="lable"> {{ nameHide(scope.row.realname) }}</span> -->
  52. <span class="lable"> {{ scope.row.realname }}</span>
  53. <el-tooltip effect="dark" :content="scope.row.realname" placement="right">
  54. <i class="el-icon-unlock icon" />
  55. </el-tooltip>
  56. </div>
  57. </template>
  58. <!-- 手机号 -->
  59. <template slot="username" slot-scope="scope">
  60. <div class="info">
  61. <!-- <span class="lable"> {{ phoneHide(scope.row.username) }}</span> -->
  62. <span class="lable"> {{ scope.row.username }}</span>
  63. <el-tooltip effect="dark" :content="scope.row.username" placement="right">
  64. <i class="el-icon-unlock icon" />
  65. </el-tooltip>
  66. </div>
  67. </template>
  68. <!-- 角色 -->
  69. <template slot="role" slot-scope="scope">
  70. <span v-for="(role, index) in scope.row.roleList" :key="index">
  71. <el-tag>{{ role.roleName }} </el-tag>&nbsp;&nbsp;
  72. </span>
  73. </template>
  74. <!-- 状态 -->
  75. <template slot="lockFlag" slot-scope="scope">
  76. <el-tag>{{ scope.label }}</el-tag>
  77. </template>
  78. <!-- 评测结果 -->
  79. <template slot="quizResult" slot-scope="scope">
  80. <template v-if="scope.row.quizResult && scope.row.quizResult.length">
  81. <template v-for="(item, index) in scope.row.quizResult">
  82. <span :key="item.quizId">
  83. <span class="mark-text" @click="showQuizFn(item)">{{ item.finalMark || 0 }}</span>
  84. <span v-if="scope.row.quizResult.length - 1 !== index">/</span>
  85. </span>
  86. </template>
  87. </template>
  88. </template>
  89. <!-- 派工方搜索 -->
  90. <template slot="deptIdSearch">
  91. <el-select v-model="searchForm.deptId" clearable>
  92. <el-option v-for="item in deptLists" :key="item.deptId" :label="item.name" :value="item.deptId"> </el-option>
  93. </el-select>
  94. </template>
  95. <!-- 区域搜索 -->
  96. <template slot="areaCodesSearch">
  97. <el-cascader
  98. @change="searchFormAreaCodesChange"
  99. v-model="searchFormAreaCodes"
  100. :options="treeList"
  101. :key="cascaderKey"
  102. collapse-tags
  103. :props="searchCascaderProps"
  104. clearable
  105. ></el-cascader>
  106. </template>
  107. <!-- 表单-角色 -->
  108. <template slot="roleForm">
  109. <el-select v-model="form.role" :rules="[{ required: true, message: '请选择角色', trigger: 'blur' }]" multiple clearable>
  110. <el-option v-for="item in rolesList" :key="item.roleId" :label="item.roleName" :value="item.roleId" :disabled="item.disabled"> </el-option>
  111. </el-select>
  112. </template>
  113. <!-- 表单-派工方 -->
  114. <template slot="deptIdForm">
  115. <el-select v-model="form.deptId" clearable @change="deptIdChange">
  116. <el-option v-for="item in deptLists" :key="item.deptId" :label="item.name" :value="item.deptId"> </el-option>
  117. </el-select>
  118. </template>
  119. <!-- 表单-区域 -->
  120. <template slot="areaCodesDataForm">
  121. <el-cascader
  122. :disabled="areaCodesDisabled"
  123. :key="cascaderKey"
  124. v-model="form.areaCodesData"
  125. :options="treeListCopy"
  126. collapse-tags
  127. :props="cascaderProps"
  128. clearable
  129. ></el-cascader>
  130. </template>
  131. </avue-crud>
  132. </basic-container>
  133. <!-- 导入用户弹窗 -->
  134. <el-dialog title="导入用户" :visible.sync="importUserShow" :close-on-click-modal="false" width="35%" center :before-close="importUserClose">
  135. <div class="import-content" v-loading="importLoading">
  136. <el-upload
  137. class="upload-demo"
  138. :action="uploadUrl"
  139. :headers="headers"
  140. :before-upload="importUserBefore"
  141. :before-remove="beforeUserRemove"
  142. :limit="1"
  143. :on-exceed="handleUserExceed"
  144. :on-success="handleUserSuccess"
  145. :on-error="handleUserError"
  146. accept=".xls,.xlsx"
  147. :file-list="userFileList"
  148. :show-file-list="false"
  149. >
  150. <el-button size="small" type="primary">导入用户(*.xlsx,*.xls)</el-button>
  151. </el-upload>
  152. <br />
  153. <el-button type="text" @click="dowmTemplateFn">下载模板</el-button>
  154. </div>
  155. </el-dialog>
  156. <!-- 导入用户存在失败 -->
  157. <el-dialog title="上传失败!" width="35%" :close-on-click-modal="false" @close="importErrorDialogShow = fasle" :visible.sync="importErrorDialogShow" center>
  158. <avue-crud style="width: 100%" :data="importErrorTableData" :option="importErrorTableOption"> </avue-crud>
  159. <span slot="footer" class="dialog-footer">
  160. <el-button @click="importErrorDialogShow = fasle">关 闭</el-button>
  161. </span>
  162. </el-dialog>
  163. <!-- 角色描述弹窗 -->
  164. <RoleDescriptionDialog :roleDialogVisible.sync="roleDialogVisible" />
  165. <!-- 个人名片弹窗 -->
  166. <UserCard :userCardInfo="userCardInfo" :srcList="srcList" :userCardShow.sync="userCardShow" />
  167. <!-- 评测结果 -->
  168. <QuizDialog :showDialog.sync="showAddQuizDialog" :quizItem="quizItem" />
  169. <!-- 上传备案 -->
  170. <fullTimeStaffRecordDialog @success="refreshChange" ref="fullTimeStaffRecordRef" />
  171. <!-- 新增沟通专员 -->
  172. <communicationOfficerDialog @addSuccess="refreshChange" ref="communicationOfficerRef" />
  173. <!-- 生产企业绑定药品 -->
  174. <boundMedicinesDialog @success="refreshChange" ref="boundMedicinesDialogRef" />
  175. </div>
  176. </template>
  177. <script>
  178. import { mapGetters } from 'vuex';
  179. import { tableOption, importErrorTableOption } from '@/const/crud/admin/user';
  180. import { listDept } from '@/api/wmdaagent';
  181. import { getAreaTreeApi } from '@/api/areaTree';
  182. import { roleExcludeList, getListByDeptApi } from '@/api/admin/role';
  183. import { templateDownload } from '@/api/assignPoints/currency/manList';
  184. import RoleDescriptionDialog from './components/roleDescriptionDialog.vue';
  185. import QuizDialog from '@/views/admin/wmscorepackagestatus/components/quizDialog';
  186. import fullTimeStaffRecordDialog from './components/fullTimeStaffRecordDialog.vue';
  187. import communicationOfficerDialog from './components/communicationOfficerDialog.vue';
  188. import boundMedicinesDialog from './components/boundMedicinesDialog.vue';
  189. import UserCard from './components/UserCard.vue';
  190. import { addObj, delObj, fetchList, putObj, getUserDetails, batchChannelCert, getAuthInfo, getUserInfoApi, exportUserInfo, getExportResult } from '@/api/admin/user';
  191. import store from '@/store';
  192. import { getDictType } from '@/api/common';
  193. import { filterCodes, extractPaths } from '@/util/treeUtils.js';
  194. export default {
  195. components: {
  196. RoleDescriptionDialog,
  197. UserCard,
  198. QuizDialog,
  199. fullTimeStaffRecordDialog,
  200. communicationOfficerDialog,
  201. boundMedicinesDialog
  202. },
  203. data() {
  204. return {
  205. exportUserInfoText: '',
  206. exportUrl: '',
  207. downShow: false,
  208. exportUserInfoDisabled: false,
  209. hideCommunicationOfficer: true,
  210. dialogType: '',
  211. option: tableOption,
  212. searchFormAreaCodes: [],
  213. searchForm: {
  214. certType: '',
  215. areaCodes: []
  216. },
  217. searchCascaderProps: {
  218. multiple: true,
  219. label: 'name',
  220. value: 'id'
  221. },
  222. form: {
  223. role: [],
  224. deptId: '',
  225. areaCodesData: []
  226. },
  227. page: {
  228. total: 0, // 总页数
  229. currentPage: 1, // 当前页数
  230. pageSize: 20, // 每页显示多少条,
  231. isAsc: false // 是否倒序
  232. },
  233. list: [],
  234. tableLoading: false,
  235. deptIdList: [],
  236. rolesList: [], // 角色列表
  237. importUserShow: false,
  238. importLoading: false,
  239. uploadUrl: '/admin/wmtask/task-batch-import',
  240. headers: {
  241. Authorization: 'Bearer ' + store.getters.access_token
  242. },
  243. importErrorDialogShow: false,
  244. importErrorTableOption,
  245. importErrorTableData: [],
  246. userFileList: [],
  247. roleDialogVisible: false,
  248. cascaderKey: 0,
  249. treeList: [],
  250. treeListCopy: [],
  251. cascaderProps: {
  252. multiple: true,
  253. label: 'name',
  254. value: 'id'
  255. },
  256. genderList: [],
  257. userDegreeList: [],
  258. userCardInfo: {},
  259. userCardShow: false,
  260. srcList: [],
  261. quizItem: {},
  262. showAddQuizDialog: false,
  263. deptLists: [],
  264. areaCodesDisabled: true,
  265. noArea: false,
  266. isLevel2csoDept: {}
  267. };
  268. },
  269. watch: {
  270. 'form.role'(newVal) {
  271. if (!newVal) return;
  272. // 检查角色是否为全职、兼职或招商经理
  273. const deptId = this.findObject(this.option.column, 'deptId');
  274. // 角色为csm展示上级主管
  275. const parentIdList = this.findObject(this.option.column, 'parentIdList');
  276. // 选择区域
  277. const areaCodesData = this.findObject(this.option.column, 'areaCodesData');
  278. const isDeptRole = !newVal || newVal.length === 0 || [5, 6, 31].some((role) => newVal.includes(role));
  279. this.$set(deptId, 'editDisplay', !isDeptRole);
  280. this.$set(deptId, 'addDisplay', !isDeptRole);
  281. if ([5, 6, 37].some((role) => newVal.includes(role))) {
  282. this.form.areaCodesData = [];
  283. this.noArea = true;
  284. this.$set(areaCodesData, 'editDisplay', false);
  285. this.$set(areaCodesData, 'addDisplay', false);
  286. } else {
  287. this.noArea = false;
  288. this.$set(areaCodesData, 'editDisplay', true);
  289. this.$set(areaCodesData, 'addDisplay', true);
  290. }
  291. // 检查角色是否为CSM
  292. const isCsm = newVal && newVal.includes(19);
  293. this.$set(parentIdList, 'editDisplay', isCsm);
  294. this.$set(parentIdList, 'addDisplay', isCsm);
  295. },
  296. 'form.deptId'(newval) {
  297. this.isLevel2csoDept = {};
  298. // this.form.areaCodesData = [];
  299. if (!newval) {
  300. this.form.areaCodesData = [];
  301. this.areaCodesDisabled = true;
  302. }
  303. if (newval) {
  304. const curr = this.deptLists.find((item) => item.deptId === newval);
  305. if (this.noArea) {
  306. this.isLevel2csoDept = curr;
  307. }
  308. if (curr.areaCodes && curr.areaCodes.length) {
  309. const treeList = JSON.parse(JSON.stringify(this.treeList));
  310. const currTree = filterCodes(curr.areaCodes, treeList);
  311. this.treeListCopy = currTree;
  312. } else {
  313. this.treeListCopy = this.treeList;
  314. }
  315. this.areaCodesDisabled = false;
  316. }
  317. }
  318. },
  319. computed: {
  320. ...mapGetters(['permissions', 'userInfo'])
  321. },
  322. created() {
  323. this.sys_user_add = this.permissions['sys_user_add'];
  324. this.sys_user_edit = this.permissions['sys_user_edit'];
  325. this.sys_user_del = this.permissions['sys_user_del'];
  326. this.user_record_check = this.permissions['user_record_check'];
  327. this.getList(this.page);
  328. this.getAreaTree();
  329. this.getRoleList();
  330. this.getListByDept();
  331. this.getDict();
  332. // 获取上次导出的数据信息
  333. this.getExportInfoStatus();
  334. },
  335. mounted() {
  336. // 50 隐藏沟通专员
  337. const roles = this.userInfo.roles;
  338. },
  339. methods: {
  340. async exportUserInfo() {
  341. const res = await exportUserInfo({});
  342. console.log(res);
  343. if (res.data.code === 0 && res.data.data) {
  344. this.getExportInfoStatus();
  345. }
  346. },
  347. // 获取导出状态
  348. async getExportInfoStatus() {
  349. const timer = setInterval(async () => {
  350. const res = await getExportResult({
  351. type: 'USER'
  352. });
  353. if (res.data.code === 0) {
  354. this.downShow = true;
  355. const status = res.data.data.status;
  356. if (status === 'GENERATING') {
  357. this.exportUserInfoText = '数据生成中';
  358. this.exportUserInfoDisabled = true;
  359. } else if (status === 'GENERATED') {
  360. this.exportUrl = res.data.data.latestUrl;
  361. this.exportUserInfoText = '下载数据';
  362. this.exportUserInfoDisabled = false;
  363. clearInterval(timer);
  364. } else if (status === 'ERROR') {
  365. // 可选:处理其他状态
  366. this.exportUserInfoText = res.data.data.errorMsg;
  367. this.exportUserInfoDisabled = false;
  368. clearInterval(timer);
  369. }else {
  370. this.downShow = fasle;
  371. }
  372. } else {
  373. // 接口报错处理
  374. this.exportUserInfoText = '获取状态失败';
  375. this.exportUserInfoDisabled = false;
  376. clearInterval(timer);
  377. }
  378. }, 5000);
  379. },
  380. downInfo() {
  381. let link = document.createElement('a');
  382. link.style.display = 'none';
  383. link.href = process.env.VUE_APP_URL + this.exportUrl;
  384. link.setAttribute('download', '用户信息.xlsx');
  385. document.body.appendChild(link);
  386. link.click();
  387. document.body.removeChild(link);
  388. },
  389. // 判断可以绑定药品的角色id
  390. showBoundMedicines(role) {
  391. const flag = role.some((item) => item >= 49 || item == 39 || item == 41);
  392. return flag;
  393. },
  394. // 生产企业监督员绑定药品
  395. boundMedicines(row) {
  396. const info = JSON.parse(JSON.stringify(row));
  397. this.$refs.boundMedicinesDialogRef.addFn(info);
  398. },
  399. deptIdChange() {
  400. this.form.areaCodesData = [];
  401. },
  402. addCommunicationOfficerFn() {
  403. this.$refs.communicationOfficerRef.show();
  404. },
  405. fullTimeStaffRecordFn(row) {
  406. this.$refs.fullTimeStaffRecordRef.showInfo(row);
  407. },
  408. // 名字脱敏
  409. nameHide(name) {
  410. let userName;
  411. if (name.length == 2) {
  412. userName = name.substring(0, 1) + '*'; //截取name 字符串截取第一个字符,
  413. } else if (name.length == 3) {
  414. userName = name.substring(0, 1) + '*' + name.substring(2, 3); //截取第一个和第三个字符
  415. } else if (name.length > 3) {
  416. userName = name.substring(0, 1) + '*' + '*' + name.substring(3, name.length); //截取第一个和大于第4个字符
  417. }
  418. return userName;
  419. },
  420. phoneHide(phone) {
  421. let reg = /^(1[3-9][0-9])\d{4}(\d{4}$)/; // 定义手机号正则表达式
  422. phone = phone.replace(reg, '$1****$2');
  423. return phone; // 185****6696
  424. },
  425. // 获取列表
  426. async getList(page, params) {
  427. this.tableLoading = true;
  428. const obj = Object.assign(
  429. {
  430. current: page.currentPage,
  431. size: page.pageSize
  432. },
  433. params,
  434. this.searchForm
  435. );
  436. if (obj.role) {
  437. obj.role = [obj.role];
  438. }
  439. const res = await fetchList(obj);
  440. res.data.data.records.forEach((item) => {
  441. item.role = item.roleList.map((iten) => iten.roleId);
  442. });
  443. const records = res.data.data.records;
  444. this.list = records;
  445. this.page.total = res.data.data.total;
  446. this.tableLoading = false;
  447. },
  448. // 获取派工方列表
  449. // async getDeptIdList() {
  450. // const res = await listDept();
  451. // console.log("res", res);
  452. // this.deptIdList = res.data.data;
  453. // },
  454. // 获取区域树列表
  455. async getAreaTree() {
  456. const res = await getAreaTreeApi();
  457. this.treeList = res.data.data;
  458. },
  459. // 获取字典
  460. getDict() {
  461. getDictType({ type: 'gender' }).then((res) => {
  462. this.genderList = res.data.data;
  463. });
  464. getDictType({ type: 'user_degree' }).then((res) => {
  465. this.userDegreeList = res.data.data;
  466. });
  467. },
  468. searchFormAreaCodesChange(e) {
  469. console.log('e', e);
  470. },
  471. // 获取角色列表
  472. async getRoleList() {
  473. const res = await roleExcludeList();
  474. // 当前角色:BC总负责人,筛选出角色19: csm
  475. if (this.userInfo.roles.includes(35)) {
  476. res.data.data = response.data.data.filter((item) => item.roleId === 19);
  477. }
  478. let data = res.data.data;
  479. const roleList = [5, 6, 37];
  480. data = data.filter((item) => !roleList.includes(item.roleId));
  481. this.rolesList = data;
  482. this.rolesList.forEach((ele, idx) => {
  483. this.$set(this.rolesList[idx], 'disabled', false);
  484. });
  485. },
  486. async getListByDept() {
  487. const res = await getListByDeptApi();
  488. this.deptLists = res.data.data;
  489. },
  490. // 新增编辑前操作
  491. handleOpenBefore(show, type) {
  492. ++this.cascaderKey;
  493. // 请求角色列表
  494. show();
  495. },
  496. // 关闭前
  497. handleCloseBefore(done, type) {
  498. let self = this;
  499. for (let key in self.form) {
  500. self.form[key] = '';
  501. }
  502. ++this.cascaderKey;
  503. this.form = {};
  504. this.form.areaCodesData = [];
  505. done();
  506. },
  507. // 编辑
  508. async handleUpdate(row, index) {
  509. if (row.role.includes(5) || row.role.includes(37)) {
  510. return this.$refs.communicationOfficerRef.editFn(row);
  511. }
  512. const role = row.roleList.map((item) => item.roleId);
  513. row.role = role;
  514. const areaCodes = row.areaCodes;
  515. const treeList = JSON.parse(JSON.stringify(this.treeList));
  516. const currTree = filterCodes(areaCodes, treeList);
  517. if (currTree) {
  518. const ids = extractPaths(currTree);
  519. row.areaCodesData = ids;
  520. }
  521. this.$forceUpdate();
  522. this.$refs.crud.rowEdit(row, index);
  523. this.form.password = undefined;
  524. },
  525. // 删除
  526. deleteFn(row, index) {
  527. this.$confirm('此操作将永久删除该用户(用户名:' + row.username + '), 是否继续?', '提示', {
  528. confirmButtonText: '确定',
  529. cancelButtonText: '取消',
  530. type: 'warning'
  531. }).then(() => {
  532. delObj(row.userId)
  533. .then(() => {
  534. this.list.splice(index, 1);
  535. this.$notify.success('删除成功');
  536. })
  537. .catch(() => {
  538. this.$notify.error('删除失败');
  539. });
  540. });
  541. },
  542. // 个人名片
  543. async userInfoCardFn(row) {
  544. this.srcList = [];
  545. const res = await getUserInfoApi(row.userId);
  546. this.userCardInfo = res.data.data;
  547. // 性别回显
  548. const curr = this.genderList.find((item) => item.value === this.userCardInfo.gender);
  549. if (curr) {
  550. this.userCardInfo.genderLabel = curr.label;
  551. }
  552. // 学历回显
  553. const curr2 = this.userDegreeList.find((item) => item.value === this.userCardInfo.degree);
  554. if (curr2) {
  555. this.userCardInfo.degreeLabel = curr2.label;
  556. }
  557. if (this.userCardInfo.qualificationsUrl && this.userCardInfo.qualificationsUrl.length) {
  558. const arr = this.userCardInfo.qualificationsUrl.map((item) => process.env.VUE_APP_URL + item);
  559. this.userCardInfo.qualificationsUrl = arr;
  560. this.srcList = arr;
  561. }
  562. this.userCardShow = true;
  563. },
  564. // 导入用户
  565. importUserOpen() {
  566. this.uploadUrl = 'admin/user/batch';
  567. this.importUserShow = true;
  568. },
  569. // 导入用户弹窗关闭
  570. importUserClose() {
  571. this.importUserShow = false;
  572. this.userFileList = [];
  573. },
  574. // 导入模板前
  575. importUserBefore() {
  576. this.importLoading = true;
  577. },
  578. beforeUserRemove(file, fileList) {
  579. return this.$confirm(`确定移除 ${file.name}?`);
  580. },
  581. handleUserExceed(files, fileList) {
  582. this.$message.warning('最多上传一个文件');
  583. },
  584. // 用户导入成功
  585. handleUserSuccess(res, file) {
  586. this.importLoading = false;
  587. // 上传成功
  588. if (res.code === 0) {
  589. this.$message.success('上传成功!');
  590. this.importUserClose();
  591. this.getList(this.page);
  592. return;
  593. }
  594. // 初始化用户文件列表
  595. this.userFileList = [];
  596. // 检查上传失败的情况
  597. if (res.data && res.data.code === 'FAILURE') {
  598. // 上传有错误
  599. const errorData = res.data.data;
  600. this.importErrorTableData = Object.keys(errorData).map((key) => ({
  601. reason: key,
  602. index: errorData[key]
  603. }));
  604. this.importErrorDialogShow = true;
  605. } else {
  606. // 其他上传失败情况
  607. this.$message.error(res.msg);
  608. }
  609. },
  610. // 导入失败
  611. handleUserError(err) {
  612. this.$message.error('上传失败!');
  613. this.importLoading = false;
  614. },
  615. // 下载模板
  616. dowmTemplateFn() {
  617. this.importLoading = true;
  618. templateDownload({
  619. fileName: 'batch_create_user_template.xlsx'
  620. })
  621. .then((response) => {
  622. this.importLoading = false;
  623. let url = window.URL.createObjectURL(new Blob([response.data]));
  624. let link = document.createElement('a');
  625. link.style.display = 'none';
  626. link.href = url;
  627. link.setAttribute('download', '批量创建用户模板.xlsx');
  628. document.body.appendChild(link);
  629. link.click();
  630. document.body.removeChild(link);
  631. })
  632. .catch(() => {
  633. this.importLoading = false;
  634. });
  635. },
  636. updateDepartmentInfo() {
  637. if (!this.form.deptId) {
  638. this.form.deptId = this.userInfo.deptId;
  639. const curr = this.deptLists.find((item) => item.deptId === this.form.deptId);
  640. this.isLevel2csoDept = curr;
  641. }
  642. this.form.areaCodes = this.isLevel2csoDept.areaCodes;
  643. },
  644. async saveFn(row, done, loading) {
  645. if (this.noArea) {
  646. this.updateDepartmentInfo();
  647. } else {
  648. const flattenedArray = this.form.areaCodesData.flat();
  649. const areaCodes = Array.from(new Set(flattenedArray));
  650. this.form.areaCodes = areaCodes;
  651. }
  652. this.form.phone = this.form.username;
  653. if (this.form.phone.indexOf('*') > 0) {
  654. this.form.phone = undefined;
  655. }
  656. if (!this.form.deptId) {
  657. this.form.deptId = this.userInfo.deptId;
  658. }
  659. if (!this.form.parentIdList) {
  660. this.form.parentIdList = [];
  661. }
  662. addObj(this.form)
  663. .then(() => {
  664. this.getList(this.page);
  665. if (this.validateField) {
  666. }
  667. const obj = {
  668. role: [],
  669. deptId: '',
  670. areaCodesData: []
  671. };
  672. this.$set(this, 'form', obj);
  673. this.$notify.success('创建成功');
  674. done();
  675. })
  676. .catch(() => {
  677. loading();
  678. });
  679. },
  680. async updateFn(row, done, loading) {
  681. if (this.noArea) {
  682. this.updateDepartmentInfo();
  683. } else {
  684. const flattenedArray = this.form.areaCodesData.flat();
  685. const areaCodes = Array.from(new Set(flattenedArray));
  686. this.form.areaCodes = areaCodes;
  687. }
  688. this.form.phone = this.form.username;
  689. if (this.form.phone.indexOf('*') > 0) {
  690. this.form.phone = undefined;
  691. }
  692. putObj(this.form)
  693. .then(() => {
  694. this.form = {
  695. role: [],
  696. deptId: '',
  697. areaCodesData: []
  698. };
  699. this.getList(this.page);
  700. done();
  701. this.$notify.success('创建成功');
  702. })
  703. .catch(() => {
  704. loading();
  705. });
  706. },
  707. extractLastElements(array) {
  708. // 创建一个新的空数组来存储结果
  709. let result = [];
  710. // 遍历输入的二维数组
  711. for (let i = 0; i < array.length; i++) {
  712. // 检查内部数组是否非空
  713. if (array[i].length > 0) {
  714. // 将内部数组的最后一个元素添加到结果数组中
  715. result.push(array[i][array[i].length - 1]);
  716. }
  717. }
  718. // 返回结果数组
  719. return result;
  720. },
  721. // 搜索
  722. searchChange(param, done) {
  723. this.searchForm = param;
  724. if (this.searchFormAreaCodes.length) {
  725. const codes = this.extractLastElements(this.searchFormAreaCodes);
  726. this.searchForm.areaCodes = codes;
  727. }
  728. this.page.currentPage = 1;
  729. this.getList(this.page, param);
  730. done();
  731. },
  732. // page修改
  733. sizeChange(pageSize) {
  734. this.page.pageSize = pageSize;
  735. this.getList(this.page);
  736. },
  737. currentChange(current) {
  738. this.page.currentPage = current;
  739. this.getList(this.page);
  740. },
  741. refreshChange() {
  742. this.getList(this.page);
  743. },
  744. searchReset() {
  745. // this.searchForm = {};
  746. ++this.cascaderKey;
  747. this.searchFormAreaCodes = [];
  748. },
  749. // 合规测评
  750. showQuizFn(quizItem) {
  751. this.quizItem = quizItem;
  752. this.showAddQuizDialog = true;
  753. }
  754. }
  755. };
  756. </script>
  757. <style lang="scss" scoped>
  758. .import-content {
  759. text-align: center;
  760. }
  761. .info {
  762. .lable {
  763. margin-right: 5px;
  764. }
  765. .icon {
  766. cursor: pointer;
  767. }
  768. }
  769. </style>