阅行客电子档案
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

405 lines
12 KiB

3 weeks ago
3 weeks ago
3 weeks ago
3 weeks ago
3 weeks ago
3 weeks ago
3 weeks ago
  1. <template>
  2. <!-- 选择发送对象 -->
  3. <el-dialog append-to-body :close-on-click-modal="false" :visible.sync="sendObjVisible" title="发布通知" @close="handleClose">
  4. <span class="dialog-right-top" />
  5. <span class="dialog-left-bottom" />
  6. <div class="setting-dialog">
  7. <el-form ref="selectObjForm" :rules="rulesObj" :model="selectObjForm" size="small" label-width="100px">
  8. <el-form-item label="发送对象" prop="sendObj" class="down-select">
  9. <el-radio-group v-model="selectObjForm.sendObj" size="mini" style="width: 178px">
  10. <el-radio-button label="0">用户</el-radio-button>
  11. <el-radio-button label="1">设备</el-radio-button>
  12. </el-radio-group>
  13. </el-form-item>
  14. </el-form>
  15. <div class="obj-tree-select">
  16. <div class="obj-tree">
  17. <el-tree ref="tree" :data="fondsDatas" :props="defaultProps" :expand-on-click-node="false" :default-expanded-keys="defaultExpandedKeys" node-key="id" highlight-current @node-click="handleNodeClick">
  18. <template slot-scope="{ node, data }">
  19. <div :class="{'top-level': data.id === 0}">
  20. <span v-if="data.label.length <= 8 " class="tree-text"> {{ data.label }}</span>
  21. <el-tooltip
  22. v-else
  23. effect="dark"
  24. :content="data.label"
  25. :enterable="false"
  26. placement="left"
  27. >
  28. <span class="tree-text">
  29. {{ data.label }}
  30. </span>
  31. </el-tooltip>
  32. </div>
  33. </template>
  34. </el-tree>
  35. </div>
  36. <div class="obj-list">
  37. <!-- <i class="el-icon-circle-plus-outline" /> -->
  38. <p class="obj-title">用户列表</p>
  39. <div v-if="userListWithCheck.length !== 0">
  40. <el-checkbox
  41. v-model="checkAll"
  42. class="checkbox-all"
  43. :indeterminate="indeterminate"
  44. @change="checkedAll"
  45. >用户</el-checkbox>
  46. <div v-for="user in userListWithCheck" :key="user.userId">
  47. <el-checkbox v-model="user.checked" @change="handleChange(user)">{{ user.username }}</el-checkbox>
  48. </div>
  49. </div>
  50. <div v-else style="font-size:12px; text-align: center; line-height: 80px; color: #999;">暂无数据</div>
  51. </div>
  52. <div class="obj-selected">
  53. <p class="obj-title">已选中<i class="iconfont icon-shanchu" @click="clearSelectAll" /></p>
  54. <div class="selected-list">
  55. <el-tag
  56. v-for="tag in selectedItems"
  57. :key="tag.userId"
  58. closable
  59. :disable-transitions="false"
  60. @close="handleDelt(tag)"
  61. >
  62. {{ tag.username }}
  63. </el-tag>
  64. </div>
  65. </div>
  66. </div>
  67. <div slot="footer" class="dialog-footer">
  68. <el-button type="primary" @click="handleSaveSelectObj">保存</el-button>
  69. </div>
  70. </div>
  71. </el-dialog>
  72. </template>
  73. <script>
  74. import { FetchFondsAll } from '@/api/system/fonds'
  75. import { FetchInitUserList } from '@/api/system/user'
  76. import Vue from 'vue'
  77. export default {
  78. props: {
  79. selectedCategory: {
  80. type: Object,
  81. default: function() {
  82. return {}
  83. }
  84. }
  85. },
  86. data() {
  87. return {
  88. fondsDatas: [],
  89. defaultExpandedKeys: [],
  90. defaultProps: { children: 'children', label: 'label' },
  91. sendObjVisible: false,
  92. selectObjForm: {
  93. sendObj: 0
  94. },
  95. checkAll: false,
  96. indeterminate: false,
  97. userList: [],
  98. selectedItems: [],
  99. userListWithCheck: [], // 中间用户列表数据带有选中状态的数组
  100. rulesObj: {
  101. sendObj: [
  102. { required: true, message: '请选择发送对象', trigger: 'change' }
  103. ]
  104. }
  105. }
  106. },
  107. watch: {
  108. selectedItems: {
  109. handler(val) {
  110. this.updateCheckedState()
  111. },
  112. deep: true
  113. },
  114. userListWithCheck: {
  115. handler(val) {
  116. this.updateCheckedState()
  117. },
  118. deep: true
  119. }
  120. },
  121. created() {
  122. },
  123. mounted() {
  124. },
  125. methods: {
  126. getFondsDatas() {
  127. const parent = {}
  128. this.fondsDatas = []
  129. parent.id = 0
  130. parent.fondsName = '全宗选择'
  131. FetchFondsAll().then(res => {
  132. res.forEach(item => {
  133. // 1. 全宗节点:将fondsName赋值给label
  134. item.label = item.fondsName
  135. // 2. 部门节点(depts -> children):将deptsName赋值给label
  136. if (item.depts && item.depts.length) {
  137. item.children = this.formatDeptNodes(item.depts)
  138. } else {
  139. item.children = []
  140. }
  141. })
  142. // 根节点添加label
  143. parent.label = parent.fondsName
  144. parent.children = res
  145. this.fondsDatas.push(parent)
  146. console.log('this.fondsDatas', this.fondsDatas)
  147. this.$nextTick(() => {
  148. Vue.set(this.defaultExpandedKeys, 0, this.fondsDatas[0].children[0].id)
  149. this.$refs.tree.setCurrentKey(this.fondsDatas[0].children[0].id)
  150. this.handleNodeClick(this.fondsDatas[0].children[0])
  151. })
  152. })
  153. },
  154. // 格式化部门节点:添加label字段
  155. formatDeptNodes(depts) {
  156. return depts.map(dept => {
  157. const node = { ...dept }
  158. node.label = dept.deptsName // 部门节点用deptsName作为label
  159. // 如果有子部门(childDepts),递归处理
  160. if (dept.childDepts && dept.childDepts.length) {
  161. node.children = this.formatDeptNodes(dept.childDepts)
  162. }
  163. return node
  164. })
  165. },
  166. // 可选:格式化分类节点(如果需要展示categorys)
  167. formatCategoryNodes(categorys) {
  168. return categorys.map(cate => {
  169. const node = { ...cate }
  170. node.label = cate.cnName // 分类节点用cnName作为label
  171. return node
  172. })
  173. },
  174. // 切换部门
  175. handleNodeClick(data) {
  176. let params = {}
  177. if (data.pid === 0) {
  178. params = {
  179. 'deptsId': null,
  180. 'deptsName': null
  181. }
  182. } else {
  183. if (data.fondsNo) {
  184. params = {
  185. 'fondsId': data.id,
  186. 'deptsId': null,
  187. 'deptsName': null
  188. }
  189. } else {
  190. params = {
  191. 'deptsId': data.id,
  192. 'deptsName': data.deptsName
  193. }
  194. }
  195. }
  196. this.getUserList(params)
  197. },
  198. checkedAll(checked) {
  199. if (this.selectedItems.length !== 0) {
  200. const missingUsers = this.userListWithCheck.filter(user => !this.isSelected(user))
  201. console.log('missingUsers', missingUsers)
  202. if (missingUsers.length !== 0) {
  203. if (this.checkAll) {
  204. missingUsers.forEach(user => {
  205. this.selectedItems.push(user)
  206. })
  207. } else {
  208. this.selectedItems = []
  209. }
  210. } else {
  211. this.userListWithCheck.forEach(user => {
  212. const index = this.selectedItems.findIndex(selectedUser => selectedUser.userId === user.userId)
  213. if (index > -1) {
  214. this.selectedItems.splice(index, 1)
  215. this.checkAll = false
  216. }
  217. })
  218. }
  219. } else {
  220. if (checked) {
  221. this.selectedItems = this.userListWithCheck.map(item => item)
  222. this.checkAll = true
  223. } else {
  224. this.selectedItems = []
  225. this.checkAll = false
  226. }
  227. }
  228. },
  229. isSelected(user) {
  230. return this.selectedItems.some(selectedUser => selectedUser.userId === user.userId)
  231. },
  232. resetCheckedState() {
  233. // 重置中间用户列表的选中状态
  234. this.userListWithCheck = this.userList.map(user => {
  235. return { ...user, checked: false }
  236. })
  237. if (this.selectedItems.length !== 0) {
  238. const isAllSelected = this.userListWithCheck.every(user => this.isSelected(user))
  239. if (isAllSelected) {
  240. this.checkAll = true
  241. } else {
  242. this.checkAll = false
  243. }
  244. }
  245. },
  246. updateCheckedState() {
  247. this.userListWithCheck.forEach(user => {
  248. user.checked = this.selectedItems.some(selectedUser => selectedUser.userId === user.userId)
  249. })
  250. },
  251. getUserList(params) {
  252. FetchInitUserList(params).then(res => {
  253. const newArr = res.content.map(item => {
  254. const json = {}
  255. json.userId = item.userId
  256. json.username = item.username
  257. return json
  258. })
  259. this.userList = newArr
  260. this.resetCheckedState()
  261. })
  262. },
  263. handleChange(user) {
  264. if (user.checked) {
  265. this.selectedItems.push(user)
  266. if (this.selectedItems.length !== 0) {
  267. const allUsersSelected = this.userListWithCheck.every(user => this.isSelected(user))
  268. if (allUsersSelected) {
  269. console.log('所有左边的用户都已加入到右边已选中的列表中')
  270. this.checkAll = true
  271. } else {
  272. this.checkAll = false
  273. console.log('左边的用户列表还有未加入到右边已选中的列表中的用户')
  274. }
  275. } else {
  276. this.checkAll = this.selectedItems.length === this.userListWithCheck.length
  277. }
  278. } else {
  279. const index = this.selectedItems.findIndex(selectedUser => selectedUser.userId === user.userId)
  280. if (index > -1) {
  281. this.selectedItems.splice(index, 1)
  282. this.checkAll = false
  283. }
  284. }
  285. },
  286. handleClose() {
  287. this.sendObjVisible = false
  288. },
  289. handleDelt(tag) {
  290. this.selectedItems.splice(this.selectedItems.indexOf(tag), 1)
  291. if (this.selectedItems.length !== 0) {
  292. const allUsersSelected = this.userListWithCheck.every(user => this.isSelected(user))
  293. if (allUsersSelected) {
  294. console.log('所有左边的用户都已加入到右边已选中的列表中')
  295. this.checkAll = true
  296. } else {
  297. this.checkAll = false
  298. console.log('左边的用户列表还有未加入到右边已选中的列表中的用户')
  299. }
  300. } else {
  301. this.checkAll = this.selectedItems.length === this.userListWithCheck.length
  302. }
  303. },
  304. clearSelectAll() {
  305. this.checkAll = false
  306. this.selectedItems = []
  307. },
  308. handleSaveSelectObj() {
  309. this.$emit('selectObjItem', this.selectObjForm.sendObj, this.selectedItems)
  310. this.sendObjVisible = false
  311. }
  312. }
  313. }
  314. </script>
  315. <style lang='scss' scoped>
  316. .obj-tree-select{
  317. display: flex;
  318. justify-content: space-between;
  319. height: 367px;
  320. border: 1px solid #E6E8ED;
  321. .obj-tree{
  322. width: 194px;
  323. overflow: hidden;
  324. overflow-y: scroll;
  325. border-right: 1px solid #E6E8ED;
  326. }
  327. .obj-list{
  328. width: 184px;
  329. overflow: hidden;
  330. overflow-y: scroll;
  331. border-right: 1px solid #E6E8ED;
  332. .obj-title{
  333. padding: 0 12px;
  334. i{
  335. font-weight: bold;
  336. font-size: 18px;
  337. right: 12px;
  338. }
  339. }
  340. ::v-deep .el-checkbox{
  341. width: 100%;
  342. height: 40px;
  343. line-height: 40px;
  344. padding-left: 16px;
  345. &:hover{
  346. background-color: #F5F9FC;
  347. }
  348. }
  349. }
  350. .obj-selected{
  351. flex: 1;
  352. .obj-title{
  353. padding: 0 15px;
  354. border-bottom: 1px solid #E6E8ED;
  355. i{
  356. right: 15px;
  357. }
  358. }
  359. ::v-deep .el-tag{
  360. margin: 14px 0 0 10px;
  361. height: 24px;
  362. line-height: 24px;
  363. padding: 0 8px;
  364. font-size: 12px;
  365. color: #0348F3;
  366. background: #E8F2FF;
  367. border: none;
  368. border-radius: 3px;
  369. .el-icon-close{
  370. color: #0348F3;
  371. &:hover{
  372. color: #fff;
  373. background-color: #0348F3;
  374. }
  375. }
  376. }
  377. }
  378. .obj-title{
  379. position: relative;
  380. font-size: 16px;
  381. color: #0C0E1E;
  382. height: 48px;
  383. line-height: 48px;
  384. i{
  385. position: absolute;
  386. top: 50%;
  387. transform: translateY(-50%);
  388. color: #0348F3;
  389. cursor: pointer;
  390. }
  391. }
  392. }
  393. .checkbox-all{
  394. font-weight: bold;
  395. background-color: #f5f9fc;
  396. color: #0c0e1e;
  397. }
  398. .el-tree .el-tooltip{
  399. width: 140px !important;
  400. }
  401. </style>