UserModal.vue 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633
  1. <template>
  2. <a-drawer
  3. :title="title"
  4. :maskClosable="true"
  5. :width="drawerWidth"
  6. placement="right"
  7. :closable="true"
  8. @close="handleCancel"
  9. :visible="visible"
  10. >
  11. <template slot="title">
  12. <div style="width: 100%">
  13. <span>{{ title }}</span>
  14. <span style="display: inline-block; width: calc(100% - 51px); padding-right: 10px; text-align: right">
  15. <a-button @click="toggleScreen" icon="appstore" style="height: 20px; width: 20px; border: 0px"></a-button>
  16. </span>
  17. </div>
  18. </template>
  19. <a-spin :spinning="confirmLoading">
  20. <a-form :form="form">
  21. <a-form-item label="用户账号" :labelCol="labelCol" :wrapperCol="wrapperCol">
  22. <!-- :readOnly="!!model.id" -->
  23. <a-input placeholder="请输入用户账号" v-decorator="['username', validatorRules.username]" :disabled="disableSubmit"/>
  24. </a-form-item>
  25. <template v-if="!model.id">
  26. <a-form-item label="登陆密码" :labelCol="labelCol" :wrapperCol="wrapperCol">
  27. <a-input type="password" placeholder="请输入登陆密码" v-decorator="['password', validatorRules.password]" :disabled="disableSubmit"/>
  28. </a-form-item>
  29. <a-form-item label="确认密码" :labelCol="labelCol" :wrapperCol="wrapperCol">
  30. <a-input
  31. type="password"
  32. @blur="handleConfirmBlur"
  33. placeholder="请重新输入登陆密码"
  34. v-decorator="['confirmpassword', validatorRules.confirmpassword]"
  35. :disabled="disableSubmit"
  36. />
  37. </a-form-item>
  38. </template>
  39. <a-form-item label="用户名字" :labelCol="labelCol" :wrapperCol="wrapperCol">
  40. <a-input placeholder="请输入用户名称" v-decorator="['realname', validatorRules.realname]" :disabled="disableSubmit"/>
  41. </a-form-item>
  42. <a-form-item label="邮箱" :labelCol="labelCol" :wrapperCol="wrapperCol">
  43. <a-input placeholder="请输入邮箱" v-decorator="['email', validatorRules.email]" :disabled="disableSubmit"/>
  44. </a-form-item>
  45. <a-form-item label="角色分配" :labelCol="labelCol" :wrapperCol="wrapperCol" v-show="!roleDisabled">
  46. <a-select style="width: 100%" placeholder="请选择用户角色" v-model="selectedRole" :disabled="disableSubmit">
  47. <a-select-option v-for="(role, roleindex) in roleList" :key="roleindex.toString()" :value="role.id">
  48. {{ role.roleName }}
  49. </a-select-option>
  50. </a-select>
  51. </a-form-item>
  52. <!--部门分配-->
  53. <a-form-item label="部门分配" :labelCol="labelCol" :wrapperCol="wrapperCol" v-show="!departDisabled">
  54. <a-input placeholder="点击右侧按钮选择部门" v-model="checkedDepartNameString" disabled @search="onSearch">
  55. <span slot="addonAfter" icon="search" @click="onSearch" style="cursor: pointer">选择</span>
  56. </a-input>
  57. </a-form-item>
  58. <a-form-item label="头像" :labelCol="labelCol" :wrapperCol="wrapperCol">
  59. <a-upload
  60. listType="picture-card"
  61. class="avatar-uploader"
  62. :showUploadList="false"
  63. :action="uploadAction"
  64. :data="{ isup: 1 }"
  65. :headers="headers"
  66. :beforeUpload="beforeUpload"
  67. @change="handleChange"
  68. :disabled="disableSubmit"
  69. >
  70. <img v-if="picUrl" :src="getAvatarView()" alt="头像" style="height: 104px; max-width: 300px" />
  71. <div v-else>
  72. <a-icon :type="uploadLoading ? 'loading' : 'plus'" />
  73. <div class="ant-upload-text">上传</div>
  74. </div>
  75. </a-upload>
  76. </a-form-item>
  77. <a-form-item label="汇报上级" :labelCol="labelCol" :wrapperCol="wrapperCol">
  78. <a-select
  79. :disabled="disableSubmit"
  80. showSearch
  81. :filterOption="filterOption"
  82. style="width: 100%"
  83. placeholder="请选择汇报上级"
  84. v-decorator="['leader', { rules: [{ required: true, message: '汇报上级必选' }] }]"
  85. labelInValue
  86. >
  87. <a-select-option v-for="(people, peopleindex) in peopleList" :key="peopleindex" :value="people.key">
  88. {{ people.label }}
  89. </a-select-option>
  90. </a-select>
  91. </a-form-item>
  92. <!-- <a-form-item label="生日" :labelCol="labelCol" :wrapperCol="wrapperCol">
  93. <a-date-picker
  94. style="width: 100%"
  95. placeholder="请选择生日"
  96. v-decorator="['birthday', {initialValue:!model.birthday?null:moment(model.birthday,dateFormat)}]"/>
  97. </a-form-item> -->
  98. <a-form-item label="性别" :labelCol="labelCol" :wrapperCol="wrapperCol">
  99. <a-select v-decorator="['sex', {}]" placeholder="请选择性别" :disabled="disableSubmit">
  100. <a-select-option :value="1">男</a-select-option>
  101. <a-select-option :value="2">女</a-select-option>
  102. </a-select>
  103. </a-form-item>
  104. <a-form-item label="手机号码" :labelCol="labelCol" :wrapperCol="wrapperCol">
  105. <a-input
  106. placeholder="请输入手机号码"
  107. :disabled="disableSubmit"
  108. v-decorator="['phone', validatorRules.phone]"
  109. />
  110. </a-form-item>
  111. <a-form-item label="工作流引擎" :labelCol="labelCol" :wrapperCol="wrapperCol">
  112. <j-dict-select-tag
  113. :disabled="disableSubmit"
  114. v-decorator="['activitiSync', {}]"
  115. placeholder="请选择是否同步工作流引擎"
  116. :type="'radio'"
  117. :triggerChange="true"
  118. dictCode="activiti_sync"
  119. />
  120. </a-form-item>
  121. </a-form>
  122. </a-spin>
  123. <depart-window ref="departWindow" @ok="modalFormOk"></depart-window>
  124. <div class="drawer-bootom-button" v-show="!disableSubmit">
  125. <a-popconfirm title="确定放弃编辑?" @confirm="handleCancel" okText="确定" cancelText="取消">
  126. <a-button style="margin-right: 0.8rem">取消</a-button>
  127. </a-popconfirm>
  128. <a-button @click="handleSubmit" type="primary" :loading="confirmLoading">提交</a-button>
  129. </div>
  130. </a-drawer>
  131. </template>
  132. <script>
  133. import pick from 'lodash.pick'
  134. import moment from 'moment'
  135. import Vue from 'vue'
  136. // 引入搜索部门弹出框的组件
  137. import departWindow from './DepartWindow'
  138. import { ACCESS_TOKEN } from '@/store/mutation-types'
  139. import { getAction } from '@/api/manage'
  140. import { addUser, editUser, queryUserRole, queryall } from '@/api/api'
  141. import { disabledAuthFilter } from '@/utils/authFilter'
  142. import { duplicateCheck } from '@/api/api'
  143. export default {
  144. name: 'RoleModal',
  145. components: {
  146. departWindow,
  147. },
  148. data() {
  149. return {
  150. departDisabled: false, //是否是我的部门调用该页面
  151. roleDisabled: false, //是否是角色维护调用该页面
  152. modalWidth: 800,
  153. drawerWidth: 700,
  154. modaltoggleFlag: true,
  155. confirmDirty: false,
  156. selectedDepartKeys: [], //保存用户选择部门id
  157. checkedDepartKeys: [],
  158. checkedDepartNames: [], // 保存部门的名称 =>title
  159. checkedDepartNameString: '', // 保存部门的名称 =>title
  160. userId: '', //保存用户id
  161. disableSubmit: false,
  162. userDepartModel: { userId: '', departIdList: [] }, // 保存SysUserDepart的用户部门中间表数据需要的对象
  163. dateFormat: 'YYYY-MM-DD',
  164. validatorRules: {
  165. username: {
  166. rules: [
  167. {
  168. required: true,
  169. message: '请输入用户账号!',
  170. },
  171. {
  172. validator: this.validateUsername,
  173. },
  174. ],
  175. },
  176. password: {
  177. rules: [
  178. {
  179. required: true,
  180. pattern: /^(?=.*[a-zA-Z])(?=.*\d)(?=.*[~!@#$%^&*()_+`\-={}:";'<>?,./]).{8,}$/,
  181. message: '密码由8位数字、大小写字母和特殊符号组成!',
  182. },
  183. {
  184. validator: this.validateToNextPassword,
  185. },
  186. ],
  187. },
  188. confirmpassword: {
  189. rules: [
  190. {
  191. required: true,
  192. message: '请重新输入登陆密码!',
  193. },
  194. {
  195. validator: this.compareToFirstPassword,
  196. },
  197. ],
  198. },
  199. realname: { rules: [{ required: true, message: '请输入用户名称!' }] },
  200. phone: { rules: [{ validator: this.validatePhone }] },
  201. email: {
  202. rules: [
  203. {
  204. required: true,
  205. validator: this.validateEmail,
  206. },
  207. ],
  208. },
  209. roles: {},
  210. // sex:{initialValue:((!this.model.sex)?"": (this.model.sex+""))}
  211. },
  212. title: '操作',
  213. visible: false,
  214. model: {},
  215. roleList: [],
  216. peopleList: [],
  217. selectedRole: '',
  218. labelCol: {
  219. xs: { span: 24 },
  220. sm: { span: 5 },
  221. },
  222. wrapperCol: {
  223. xs: { span: 24 },
  224. sm: { span: 16 },
  225. },
  226. uploadLoading: false,
  227. confirmLoading: false,
  228. headers: {},
  229. form: this.$form.createForm(this),
  230. picUrl: '',
  231. url: {
  232. fileUpload: window._CONFIG['domianURL'] + '/sys/common/upload',
  233. imgerver: window._CONFIG['domianURL'] + '/sys/common/view',
  234. userWithDepart: '/sys/user/userDepartList', // 引入为指定用户查看部门信息需要的url
  235. userId: '/sys/user/generateUserId', // 引入生成添加用户情况下的url
  236. syncUserByUserName: '/process/extActProcess/doSyncUserByUserName', //同步用户到工作流
  237. },
  238. }
  239. },
  240. created() {
  241. const token = Vue.ls.get(ACCESS_TOKEN)
  242. this.headers = { 'X-Access-Token': token }
  243. },
  244. computed: {
  245. uploadAction: function () {
  246. return this.url.fileUpload
  247. },
  248. },
  249. methods: {
  250. filterOption(input, option) {
  251. return option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
  252. },
  253. isDisabledAuth(code) {
  254. return disabledAuthFilter(code)
  255. },
  256. //窗口最大化切换
  257. toggleScreen() {
  258. if (this.modaltoggleFlag) {
  259. this.modalWidth = window.innerWidth
  260. } else {
  261. this.modalWidth = 800
  262. }
  263. this.modaltoggleFlag = !this.modaltoggleFlag
  264. },
  265. initialRoleList() {
  266. queryall().then((res) => {
  267. if (res.success) {
  268. this.roleList = res.result
  269. } else {
  270. console.log(res.message)
  271. }
  272. })
  273. },
  274. getAllPeople() {
  275. this.getAction('/sys/user/getAllUser',{status:1}).then((res) => {
  276. if (res.success) {
  277. console.log(res)
  278. this.peopleList = res.result.map((item) => {
  279. return { key: item.userId, label: item.realName }
  280. })
  281. }
  282. })
  283. },
  284. loadUserRoles(userid) {
  285. queryUserRole({ userid: userid }).then((res) => {
  286. if (res.success) {
  287. console.log(res.result)
  288. this.selectedRole = res.result[0]
  289. } else {
  290. console.log(res.message)
  291. }
  292. })
  293. },
  294. refresh() {
  295. this.selectedDepartKeys = []
  296. this.checkedDepartKeys = []
  297. this.checkedDepartNames = []
  298. this.checkedDepartNameString = ''
  299. this.userId = ''
  300. },
  301. add() {
  302. this.disableSubmit = false
  303. this.selectedRole = ''
  304. this.userDepartModel = { userId: '', departIdList: [] }
  305. this.checkedDepartNames = []
  306. this.checkedDepartNameString = ''
  307. this.checkedDepartKeys = []
  308. this.selectedDepartKeys = []
  309. this.picUrl = ''
  310. this.refresh()
  311. this.edit({ activitiSync: '1' })
  312. },
  313. edit(record) {
  314. this.resetScreenSize() // 调用此方法,根据屏幕宽度自适应调整抽屉的宽度
  315. let that = this
  316. console.log(record)
  317. that.initialRoleList()
  318. that.getAllPeople()
  319. // that.checkedDepartNameString = "";
  320. that.form.resetFields()
  321. if (record.hasOwnProperty('id')) {
  322. that.loadUserRoles(record.id)
  323. this.picUrl = 'Has no pic url yet'
  324. }
  325. if (record.leaderId) {
  326. record.leader = {key:record.leaderId,label:record.leaderName}
  327. }else{
  328. record.leader = undefined
  329. }
  330. that.userId = record.id
  331. that.visible = true
  332. that.model = Object.assign({}, record)
  333. that.$nextTick(() => {
  334. that.form.setFieldsValue(pick(this.model, 'username', 'sex', 'realname', 'email', 'phone', 'activitiSync','leader'))
  335. })
  336. // 调用查询用户对应的部门信息的方法
  337. that.checkedDepartKeys = []
  338. that.loadCheckedDeparts()
  339. },
  340. //
  341. loadCheckedDeparts() {
  342. let that = this
  343. if (!that.userId) {
  344. return
  345. }
  346. getAction(that.url.userWithDepart, { userId: that.userId }).then((res) => {
  347. that.checkedDepartNames = []
  348. if (res.success) {
  349. for (let i = 0; i < res.result.length; i++) {
  350. that.checkedDepartNames.push(res.result[i].title)
  351. this.checkedDepartNameString = this.checkedDepartNames.join(',')
  352. that.checkedDepartKeys.push(res.result[i].key)
  353. }
  354. that.userDepartModel.departIdList = that.checkedDepartKeys
  355. } else {
  356. console.log(res.message)
  357. }
  358. })
  359. },
  360. close() {
  361. this.$emit('close')
  362. this.visible = false
  363. this.disableSubmit = false
  364. this.selectedRole = ''
  365. this.userDepartModel = { userId: '', departIdList: [] }
  366. this.checkedDepartNames = []
  367. this.checkedDepartNameString = ''
  368. this.checkedDepartKeys = []
  369. this.selectedDepartKeys = []
  370. },
  371. moment,
  372. handleSubmit() {
  373. const that = this
  374. that.confirmLoading = true
  375. // 触发表单验证
  376. this.form.validateFields((err, values) => {
  377. if (!err) {
  378. console.log(this.model, 'this.model-this.model');
  379. console.log(values, 'values-values');
  380. let avatar = that.model.avatar
  381. if (!values.birthday) {
  382. values.birthday = ''
  383. } else {
  384. values.birthday = values.birthday.format(this.dateFormat)
  385. }
  386. let formData = Object.assign(this.model, values)
  387. formData.avatar = avatar
  388. formData.selectedroles = this.selectedRole ? this.selectedRole : ''
  389. formData.roleName = this.selectedRole ? this.roleList.filter(item => item.id === this.selectedRole)[0].roleName : '';
  390. formData.departName = this.checkedDepartNameString;
  391. formData.selecteddeparts =
  392. this.userDepartModel.departIdList.length > 0 ? this.userDepartModel.departIdList.join(',') : ''
  393. formData.leaderId = values.leader.key
  394. formData.leaderName = values.leader.label.replace(/[\r\n]/g, "");
  395. // that.addDepartsToUser(that,formData); // 调用根据当前用户添加部门信息的方法
  396. let obj
  397. if (!this.model.id) {
  398. formData.id = this.userId
  399. obj = addUser(formData)
  400. } else {
  401. obj = editUser(formData)
  402. }
  403. console.log(formData)
  404. obj
  405. .then((res) => {
  406. if (res.success) {
  407. that.$message.success(res.message)
  408. that.$emit('ok')
  409. // that.close()
  410. that.visible = false
  411. that.confirmLoading = false
  412. } else {
  413. that.$message.warning(res.message)
  414. }
  415. })
  416. .finally(() => {
  417. })
  418. }else{
  419. that.confirmLoading = false
  420. }
  421. })
  422. },
  423. handleCancel() {
  424. this.close()
  425. },
  426. validateToNextPassword(rule, value, callback) {
  427. const form = this.form
  428. const confirmpassword = form.getFieldValue('confirmpassword')
  429. if (value && confirmpassword && value !== confirmpassword) {
  430. callback('两次输入的密码不一样!')
  431. }
  432. if (value && this.confirmDirty) {
  433. form.validateFields(['confirm'], { force: true })
  434. }
  435. callback()
  436. },
  437. compareToFirstPassword(rule, value, callback) {
  438. const form = this.form
  439. if (value && value !== form.getFieldValue('password')) {
  440. callback('两次输入的密码不一样!')
  441. } else {
  442. callback()
  443. }
  444. },
  445. validatePhone(rule, value, callback) {
  446. if (!value) {
  447. callback()
  448. } else {
  449. if (new RegExp(/^1[3|4|5|7|8][0-9]\d{8}$/).test(value)) {
  450. var params = {
  451. tableName: 'sys_user',
  452. fieldName: 'phone',
  453. fieldVal: value,
  454. dataId: this.userId,
  455. }
  456. duplicateCheck(params).then((res) => {
  457. if (res.success) {
  458. callback()
  459. } else {
  460. callback('手机号已存在!')
  461. }
  462. })
  463. } else {
  464. callback('请输入正确格式的手机号码!')
  465. }
  466. }
  467. },
  468. validateEmail(rule, value, callback) {
  469. if (!value) {
  470. callback()
  471. } else {
  472. if (new RegExp(/^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/).test(value)) {
  473. var params = {
  474. tableName: 'sys_user',
  475. fieldName: 'email',
  476. fieldVal: value,
  477. dataId: this.userId,
  478. }
  479. duplicateCheck(params).then((res) => {
  480. console.log(res)
  481. if (res.success) {
  482. callback()
  483. } else {
  484. callback('邮箱已存在!')
  485. }
  486. })
  487. } else {
  488. callback('请输入正确格式的邮箱!')
  489. }
  490. }
  491. },
  492. validateUsername(rule, value, callback) {
  493. var params = {
  494. tableName: 'sys_user',
  495. fieldName: 'username',
  496. fieldVal: value,
  497. dataId: this.userId,
  498. }
  499. duplicateCheck(params).then((res) => {
  500. if (res.success) {
  501. callback()
  502. } else {
  503. callback('用户名已存在!')
  504. }
  505. })
  506. },
  507. handleConfirmBlur(e) {
  508. const value = e.target.value
  509. this.confirmDirty = this.confirmDirty || !!value
  510. },
  511. normFile(e) {
  512. console.log('Upload event:', e)
  513. if (Array.isArray(e)) {
  514. return e
  515. }
  516. return e && e.fileList
  517. },
  518. beforeUpload: function (file) {
  519. var fileType = file.type
  520. if (fileType.indexOf('image') < 0) {
  521. this.$message.warning('请上传图片')
  522. return false
  523. }
  524. //TODO 验证文件大小
  525. },
  526. handleChange(info) {
  527. this.picUrl = ''
  528. if (info.file.status === 'uploading') {
  529. this.uploadLoading = true
  530. return
  531. }
  532. if (info.file.status === 'done') {
  533. var response = info.file.response
  534. this.uploadLoading = false
  535. console.log(response)
  536. if (response.success) {
  537. this.model.avatar = response.message
  538. this.picUrl = 'Has no pic url yet'
  539. } else {
  540. this.$message.warning(response.message)
  541. }
  542. }
  543. },
  544. getAvatarView() {
  545. return this.url.imgerver + '/' + this.model.avatar
  546. },
  547. // 搜索用户对应的部门API
  548. onSearch(value) {
  549. this.$refs.departWindow.add(this.checkedDepartKeys, this.userId)
  550. },
  551. // 获取用户对应部门弹出框提交给返回的数据
  552. modalFormOk(formData) {
  553. console.log(formData)
  554. this.checkedDepartNames = []
  555. this.selectedDepartKeys = []
  556. this.checkedDepartNameString = ''
  557. this.userId = formData.userId
  558. this.userDepartModel.userId = formData.userId
  559. for (let i = 0; i < formData.departIdList.length; i++) {
  560. this.selectedDepartKeys.push(formData.departIdList[i].key)
  561. this.checkedDepartNames.push(formData.departIdList[i].title)
  562. this.checkedDepartNameString = this.checkedDepartNames.join(',')
  563. }
  564. this.userDepartModel.departIdList = this.selectedDepartKeys
  565. this.checkedDepartKeys = this.selectedDepartKeys //更新当前的选择keys
  566. },
  567. // 根据屏幕变化,设置抽屉尺寸
  568. resetScreenSize() {
  569. let screenWidth = document.body.clientWidth
  570. if (screenWidth < 500) {
  571. this.drawerWidth = screenWidth
  572. } else {
  573. this.drawerWidth = 700
  574. }
  575. },
  576. getData(className) {
  577. return this.form.getFieldValue(className)
  578. },
  579. },
  580. }
  581. </script>
  582. <style scoped>
  583. .avatar-uploader > .ant-upload {
  584. width: 104px;
  585. height: 104px;
  586. }
  587. .ant-upload-select-picture-card i {
  588. font-size: 49px;
  589. color: #999;
  590. }
  591. .ant-upload-select-picture-card .ant-upload-text {
  592. margin-top: 8px;
  593. color: #666;
  594. }
  595. .ant-table-tbody .ant-table-row td {
  596. padding-top: 10px;
  597. padding-bottom: 10px;
  598. }
  599. .drawer-bootom-button {
  600. position: absolute;
  601. bottom: -8px;
  602. width: 100%;
  603. border-top: 1px solid #e8e8e8;
  604. padding: 10px 16px;
  605. text-align: right;
  606. left: 0;
  607. background: #fff;
  608. border-radius: 0 0 2px 2px;
  609. }
  610. </style>