Rap 原分销系统代码Web
Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

485 Zeilen
16KB

  1. <template>
  2. <div class="app-container">
  3. <el-row :gutter="20">
  4. <!--侧边部门数据-->
  5. <el-col :xs="9" :sm="6" :md="5" :lg="4" :xl="4">
  6. <div class="head-container">
  7. <el-input
  8. v-model="deptName"
  9. clearable
  10. size="small"
  11. placeholder="输入部门名称搜索"
  12. prefix-icon="el-icon-search"
  13. class="filter-item"
  14. @input="getDeptDatas"
  15. />
  16. </div>
  17. <el-tree
  18. :data="deptDatas"
  19. :load="getDeptDatas"
  20. :props="defaultProps"
  21. :expand-on-click-node="false"
  22. lazy
  23. @node-click="handleNodeClick"
  24. />
  25. </el-col>
  26. <!--用户数据-->
  27. <el-col :xs="15" :sm="18" :md="19" :lg="20" :xl="20">
  28. <!--工具栏-->
  29. <div class="head-container">
  30. <div v-if="crud.props.searchToggle">
  31. <!-- 搜索 -->
  32. <el-input
  33. v-model="query.blurry"
  34. clearable
  35. size="small"
  36. placeholder="输入名称或者邮箱搜索"
  37. style="width: 200px;"
  38. class="filter-item"
  39. @keyup.enter.native="crud.toQuery"
  40. />
  41. <date-range-picker v-model="query.createTime" class="date-item" />
  42. <el-select
  43. v-model="query.enabled"
  44. clearable
  45. size="small"
  46. placeholder="状态"
  47. class="filter-item"
  48. style="width: 90px"
  49. @change="crud.toQuery"
  50. >
  51. <el-option
  52. v-for="item in enabledTypeOptions"
  53. :key="item.key"
  54. :label="item.display_name"
  55. :value="item.key"
  56. />
  57. </el-select>
  58. <rrOperation />
  59. </div>
  60. <crudOperation show="" :permission="permission" />
  61. </div>
  62. <!--表单渲染-->
  63. <el-dialog append-to-body :close-on-click-modal="false" :before-close="crud.cancelCU" :visible.sync="crud.status.cu > 0" :title="crud.status.title" width="570px">
  64. <el-form ref="form" :inline="true" :model="form" :rules="rules" size="small" label-width="66px">
  65. <el-form-item label="用户名" prop="username">
  66. <el-input v-model="form.username" @keydown.native="keydown($event)" />
  67. </el-form-item>
  68. <el-form-item label="电话" prop="phone">
  69. <el-input v-model.number="form.phone" />
  70. </el-form-item>
  71. <el-form-item label="昵称" prop="nickName">
  72. <el-input v-model="form.nickName" @keydown.native="keydown($event)" />
  73. </el-form-item>
  74. <el-form-item label="邮箱" prop="email">
  75. <el-input v-model="form.email" />
  76. </el-form-item>
  77. <el-form-item label="部门" prop="dept.id">
  78. <treeselect
  79. v-model="form.dept.id"
  80. :options="depts"
  81. :load-options="loadDepts"
  82. style="width: 178px"
  83. placeholder="选择部门"
  84. />
  85. </el-form-item>
  86. <el-form-item label="岗位" prop="jobs">
  87. <el-select
  88. v-model="jobDatas"
  89. style="width: 178px"
  90. multiple
  91. placeholder="请选择"
  92. @remove-tag="deleteTag"
  93. @change="changeJob"
  94. >
  95. <el-option
  96. v-for="item in jobs"
  97. :key="item.name"
  98. :label="item.name"
  99. :value="item.id"
  100. />
  101. </el-select>
  102. </el-form-item>
  103. <el-form-item label="性别">
  104. <el-radio-group v-model="form.gender" style="width: 178px">
  105. <el-radio label="男">男</el-radio>
  106. <el-radio label="女">女</el-radio>
  107. </el-radio-group>
  108. </el-form-item>
  109. <el-form-item label="状态">
  110. <el-radio-group v-model="form.enabled" :disabled="form.id === user.id">
  111. <el-radio
  112. v-for="item in dict.user_status"
  113. :key="item.id"
  114. :label="item.value"
  115. >{{ item.label }}</el-radio>
  116. </el-radio-group>
  117. </el-form-item>
  118. <el-form-item style="margin-bottom: 0;" label="角色" prop="roles">
  119. <el-select
  120. v-model="roleDatas"
  121. style="width: 437px"
  122. multiple
  123. placeholder="请选择"
  124. @remove-tag="deleteTag"
  125. @change="changeRole"
  126. >
  127. <el-option
  128. v-for="item in roles"
  129. :key="item.name"
  130. :disabled="level !== 1 && item.level <= level"
  131. :label="item.name"
  132. :value="item.id"
  133. />
  134. </el-select>
  135. </el-form-item>
  136. </el-form>
  137. <div slot="footer" class="dialog-footer">
  138. <el-button type="text" @click="crud.cancelCU">取消</el-button>
  139. <el-button :loading="crud.status.cu === 2" type="primary" @click="crud.submitCU">确认</el-button>
  140. </div>
  141. </el-dialog>
  142. <!--表格渲染-->
  143. <el-table ref="table" v-loading="crud.loading" :data="crud.data" style="width: 100%;" @selection-change="crud.selectionChangeHandler">
  144. <el-table-column :selectable="checkboxT" type="selection" width="55" />
  145. <el-table-column :show-overflow-tooltip="true" prop="username" label="用户名" />
  146. <el-table-column :show-overflow-tooltip="true" prop="nickName" label="昵称" />
  147. <el-table-column prop="gender" label="性别" />
  148. <el-table-column :show-overflow-tooltip="true" prop="phone" width="100" label="电话" />
  149. <el-table-column :show-overflow-tooltip="true" width="135" prop="email" label="邮箱" />
  150. <el-table-column :show-overflow-tooltip="true" prop="dept" label="部门">
  151. <template slot-scope="scope">
  152. <div>{{ scope.row.dept.name }}</div>
  153. </template>
  154. </el-table-column>
  155. <el-table-column label="状态" align="center" prop="enabled">
  156. <template slot-scope="scope">
  157. <el-switch
  158. v-model="scope.row.enabled"
  159. :disabled="user.id === scope.row.id"
  160. active-color="#409EFF"
  161. inactive-color="#F56C6C"
  162. @change="changeEnabled(scope.row, scope.row.enabled)"
  163. />
  164. </template>
  165. </el-table-column>
  166. <el-table-column :show-overflow-tooltip="true" prop="createTime" width="135" label="创建日期" />
  167. <el-table-column
  168. v-if="checkPer(['admin','user:edit','user:del'])"
  169. label="操作"
  170. width="115"
  171. align="center"
  172. fixed="right"
  173. >
  174. <template slot-scope="scope">
  175. <udOperation
  176. :data="scope.row"
  177. :permission="permission"
  178. :disabled-dle="scope.row.id === user.id"
  179. />
  180. </template>
  181. </el-table-column>
  182. </el-table>
  183. <!--分页组件-->
  184. <pagination />
  185. </el-col>
  186. </el-row>
  187. </div>
  188. </template>
  189. <script>
  190. import crudUser from '@/api/system/user'
  191. import { isvalidPhone } from '@/utils/validate'
  192. import { getDepts, getDeptSuperior } from '@/api/system/dept'
  193. import { getAll, getLevel } from '@/api/system/role'
  194. import { getAllJob } from '@/api/system/job'
  195. import CRUD, { presenter, header, form, crud } from '@crud/crud'
  196. import rrOperation from '@crud/RR.operation'
  197. import crudOperation from '@crud/CRUD.operation'
  198. import udOperation from '@crud/UD.operation'
  199. import pagination from '@crud/Pagination'
  200. import DateRangePicker from '@/components/DateRangePicker'
  201. import Treeselect from '@riophae/vue-treeselect'
  202. import { mapGetters } from 'vuex'
  203. import '@riophae/vue-treeselect/dist/vue-treeselect.css'
  204. import { LOAD_CHILDREN_OPTIONS } from '@riophae/vue-treeselect'
  205. let userRoles = []
  206. let userJobs = []
  207. const defaultForm = { id: null, username: null, nickName: null, gender: '男', email: null, enabled: 'false', roles: [], jobs: [], dept: { id: null }, phone: null }
  208. export default {
  209. name: 'User',
  210. components: { Treeselect, crudOperation, rrOperation, udOperation, pagination, DateRangePicker },
  211. cruds() {
  212. return CRUD({ title: '用户', url: 'api/users', crudMethod: { ...crudUser }})
  213. },
  214. mixins: [presenter(), header(), form(defaultForm), crud()],
  215. // 数据字典
  216. dicts: ['user_status'],
  217. data() {
  218. // 自定义验证
  219. const validPhone = (rule, value, callback) => {
  220. if (!value) {
  221. callback(new Error('请输入电话号码'))
  222. } else if (!isvalidPhone(value)) {
  223. callback(new Error('请输入正确的11位手机号码'))
  224. } else {
  225. callback()
  226. }
  227. }
  228. return {
  229. height: document.documentElement.clientHeight - 180 + 'px;',
  230. deptName: '', depts: [], deptDatas: [], jobs: [], level: 3, roles: [],
  231. jobDatas: [], roleDatas: [], // 多选时使用
  232. defaultProps: { children: 'children', label: 'name', isLeaf: 'leaf' },
  233. permission: {
  234. add: ['admin', 'user:add'],
  235. edit: ['admin', 'user:edit'],
  236. del: ['admin', 'user:del']
  237. },
  238. enabledTypeOptions: [
  239. { key: 'true', display_name: '激活' },
  240. { key: 'false', display_name: '锁定' }
  241. ],
  242. rules: {
  243. username: [
  244. { required: true, message: '请输入用户名', trigger: 'blur' },
  245. { min: 2, max: 20, message: '长度在 2 到 20 个字符', trigger: 'blur' }
  246. ],
  247. nickName: [
  248. { required: true, message: '请输入用户昵称', trigger: 'blur' },
  249. { min: 2, max: 20, message: '长度在 2 到 20 个字符', trigger: 'blur' }
  250. ],
  251. email: [
  252. { required: true, message: '请输入邮箱地址', trigger: 'blur' },
  253. { type: 'email', message: '请输入正确的邮箱地址', trigger: 'blur' }
  254. ],
  255. phone: [
  256. { required: true, trigger: 'blur', validator: validPhone }
  257. ]
  258. }
  259. }
  260. },
  261. computed: {
  262. ...mapGetters([
  263. 'user'
  264. ])
  265. },
  266. created() {
  267. this.crud.msg.add = '新增成功,默认密码:123456'
  268. },
  269. mounted: function() {
  270. const that = this
  271. window.onresize = function temp() {
  272. that.height = document.documentElement.clientHeight - 180 + 'px;'
  273. }
  274. },
  275. methods: {
  276. // 禁止输入空格
  277. keydown(e) {
  278. if (e.keyCode === 32) {
  279. e.returnValue = false
  280. }
  281. },
  282. changeRole(value) {
  283. userRoles = []
  284. value.forEach(function(data, index) {
  285. const role = { id: data }
  286. userRoles.push(role)
  287. })
  288. },
  289. changeJob(value) {
  290. userJobs = []
  291. value.forEach(function(data, index) {
  292. const job = { id: data }
  293. userJobs.push(job)
  294. })
  295. },
  296. deleteTag(value) {
  297. userRoles.forEach(function(data, index) {
  298. if (data.id === value) {
  299. userRoles.splice(index, value)
  300. }
  301. })
  302. },
  303. // 新增与编辑前做的操作
  304. [CRUD.HOOK.afterToCU](crud, form) {
  305. this.getRoles()
  306. if (form.id == null) {
  307. this.getDepts()
  308. } else {
  309. this.getSupDepts(form.dept.id)
  310. }
  311. this.getRoleLevel()
  312. this.getJobs()
  313. form.enabled = form.enabled.toString()
  314. },
  315. // 新增前将多选的值设置为空
  316. [CRUD.HOOK.beforeToAdd]() {
  317. this.jobDatas = []
  318. this.roleDatas = []
  319. },
  320. // 初始化编辑时候的角色与岗位
  321. [CRUD.HOOK.beforeToEdit](crud, form) {
  322. this.getJobs(this.form.dept.id)
  323. this.jobDatas = []
  324. this.roleDatas = []
  325. userRoles = []
  326. userJobs = []
  327. const _this = this
  328. form.roles.forEach(function(role, index) {
  329. _this.roleDatas.push(role.id)
  330. const rol = { id: role.id }
  331. userRoles.push(rol)
  332. })
  333. form.jobs.forEach(function(job, index) {
  334. _this.jobDatas.push(job.id)
  335. const data = { id: job.id }
  336. userJobs.push(data)
  337. })
  338. },
  339. // 提交前做的操作
  340. [CRUD.HOOK.afterValidateCU](crud) {
  341. if (!crud.form.dept.id) {
  342. this.$message({
  343. message: '部门不能为空',
  344. type: 'warning'
  345. })
  346. return false
  347. } else if (this.jobDatas.length === 0) {
  348. this.$message({
  349. message: '岗位不能为空',
  350. type: 'warning'
  351. })
  352. return false
  353. } else if (this.roleDatas.length === 0) {
  354. this.$message({
  355. message: '角色不能为空',
  356. type: 'warning'
  357. })
  358. return false
  359. }
  360. crud.form.roles = userRoles
  361. crud.form.jobs = userJobs
  362. return true
  363. },
  364. // 获取左侧部门数据
  365. getDeptDatas(node, resolve) {
  366. const sort = 'id,desc'
  367. const params = { sort: sort }
  368. if (typeof node !== 'object') {
  369. if (node) {
  370. params['name'] = node
  371. }
  372. } else if (node.level !== 0) {
  373. params['pid'] = node.data.id
  374. }
  375. setTimeout(() => {
  376. getDepts(params).then(res => {
  377. if (resolve) {
  378. resolve(res.content)
  379. } else {
  380. this.deptDatas = res.content
  381. }
  382. })
  383. }, 100)
  384. },
  385. getDepts() {
  386. getDepts({ enabled: true }).then(res => {
  387. this.depts = res.content.map(function(obj) {
  388. if (obj.hasChildren) {
  389. obj.children = null
  390. }
  391. return obj
  392. })
  393. })
  394. },
  395. getSupDepts(deptId) {
  396. getDeptSuperior(deptId).then(res => {
  397. const date = res.content
  398. this.buildDepts(date)
  399. this.depts = date
  400. })
  401. },
  402. buildDepts(depts) {
  403. depts.forEach(data => {
  404. if (data.children) {
  405. this.buildDepts(data.children)
  406. }
  407. if (data.hasChildren && !data.children) {
  408. data.children = null
  409. }
  410. })
  411. },
  412. // 获取弹窗内部门数据
  413. loadDepts({ action, parentNode, callback }) {
  414. if (action === LOAD_CHILDREN_OPTIONS) {
  415. getDepts({ enabled: true, pid: parentNode.id }).then(res => {
  416. parentNode.children = res.content.map(function(obj) {
  417. if (obj.hasChildren) {
  418. obj.children = null
  419. }
  420. return obj
  421. })
  422. setTimeout(() => {
  423. callback()
  424. }, 200)
  425. })
  426. }
  427. },
  428. // 切换部门
  429. handleNodeClick(data) {
  430. if (data.pid === 0) {
  431. this.query.deptId = null
  432. } else {
  433. this.query.deptId = data.id
  434. }
  435. this.crud.toQuery()
  436. },
  437. // 改变状态
  438. changeEnabled(data, val) {
  439. this.$confirm('此操作将 "' + this.dict.label.user_status[val] + '" ' + data.username + ', 是否继续?', '提示', {
  440. confirmButtonText: '确定',
  441. cancelButtonText: '取消',
  442. type: 'warning'
  443. }).then(() => {
  444. crudUser.edit(data).then(res => {
  445. this.crud.notify(this.dict.label.user_status[val] + '成功', CRUD.NOTIFICATION_TYPE.SUCCESS)
  446. }).catch(() => {
  447. data.enabled = !data.enabled
  448. })
  449. }).catch(() => {
  450. data.enabled = !data.enabled
  451. })
  452. },
  453. // 获取弹窗内角色数据
  454. getRoles() {
  455. getAll().then(res => {
  456. this.roles = res
  457. }).catch(() => { })
  458. },
  459. // 获取弹窗内岗位数据
  460. getJobs() {
  461. getAllJob().then(res => {
  462. this.jobs = res.content
  463. }).catch(() => { })
  464. },
  465. // 获取权限级别
  466. getRoleLevel() {
  467. getLevel().then(res => {
  468. this.level = res.level
  469. }).catch(() => { })
  470. },
  471. checkboxT(row, rowIndex) {
  472. return row.id !== this.user.id
  473. }
  474. }
  475. }
  476. </script>
  477. <style rel="stylesheet/scss" lang="scss" scoped>
  478. ::v-deep .vue-treeselect__control,::v-deep .vue-treeselect__placeholder,::v-deep .vue-treeselect__single-value {
  479. height: 30px;
  480. line-height: 30px;
  481. }
  482. </style>