workboard.vue 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. <template>
  2. <div>
  3. <div>
  4. <div>
  5. <el-row>
  6. <el-col :span="12"
  7. ><el-button @click="handleUser">选择用户</el-button></el-col
  8. >
  9. <el-col :span="12">
  10. <!-- <span>当前时间:</span><span>2025-05-12</span> -->
  11. </el-col>
  12. <el-button @click="fullScreen" class="full-screen-btn"
  13. >全屏</el-button
  14. >
  15. </el-row>
  16. </div>
  17. <div id="customer-content" ref="tableContainer" class="scroll-container" :style="{ height: tableHeight + 'px' }">
  18. <!-- 固定表头(4列) -->
  19. <div class="header-row">
  20. <div class="header-cell">姓名</div>
  21. <div class="header-cell">待审批工单</div>
  22. <div class="header-cell">待处理工单</div>
  23. <div class="header-cell">等待工单</div>
  24. <div class="header-cell">预警工单</div>
  25. </div>
  26. <seamless-scroll
  27. :data="list"
  28. class="seamless-scroll"
  29. :class-option="{ step: 0.5 }"
  30. >
  31. <ul>
  32. <li v-for="(item, index) in list" :key="index" class="content-row">
  33. <div class="content-cell">{{ item.userName }}</div>
  34. <div class="content-cell">{{ item.pendingApprovalNum }}</div>
  35. <div class="content-cell">{{ item.pendingTaskNum }}</div>
  36. <div class="content-cell">{{ item.toBeginTaskNum }}</div>
  37. <div class="content-cell">{{ item.warningTaskNum }}</div>
  38. </li>
  39. </ul>
  40. </seamless-scroll>
  41. </div>
  42. </div>
  43. <!-- 选择用户弹框 -->
  44. <el-dialog
  45. title="选择用户"
  46. :visible.sync="chooseUserVisible"
  47. :close-on-click-modal="false"
  48. >
  49. <div class="dialog">
  50. <el-form>
  51. <el-form-item label="选择用户" prop="">
  52. <el-select
  53. v-model="selectedUsers"
  54. v-loadmore="loadMore"
  55. placeholder="请选择"
  56. multiple
  57. style="width: 100%"
  58. >
  59. <el-option
  60. v-for="item in userOptions"
  61. :key="item.value"
  62. :label="item.label"
  63. :value="item.value"
  64. >
  65. </el-option>
  66. </el-select>
  67. </el-form-item>
  68. </el-form>
  69. <span slot="footer" class="dialog-footer2">
  70. <el-button type="primary" @click="userSubmit()">提交</el-button>
  71. </span>
  72. </div>
  73. </el-dialog>
  74. </div>
  75. </template>
  76. <script>
  77. import SeamlessScroll from 'vue-seamless-scroll' // 引入组件
  78. export default {
  79. components: { SeamlessScroll }, // 注册组件
  80. name: 'workboard',
  81. data () {
  82. return {
  83. tableHeight: 0, // 动态高度
  84. chooseUserVisible: false,
  85. userOptions: [],
  86. oldSelectedUsers: [],
  87. selectedUsers: [],
  88. list: [],
  89. current: 1,
  90. size: 50,
  91. total: 0,
  92. loading: false // 防止重复请求
  93. }
  94. },
  95. created () {
  96. this.getList()
  97. },
  98. mounted () {
  99. this.calcHeight()
  100. window.addEventListener('resize', this.calcHeight)
  101. this.startScroll()
  102. },
  103. beforeDestroy () {
  104. window.removeEventListener('resize', this.calcHeight) // 避免内存泄漏
  105. },
  106. methods: {
  107. calcHeight () {
  108. this.$nextTick(() => {
  109. setTimeout(() => {
  110. const container = this.$refs.tableContainer
  111. const top = container.getBoundingClientRect().top
  112. this.tableHeight = window.innerHeight - top - 50 // 50px 为预留边距
  113. }, 300) // 预留资源加载时间
  114. })
  115. },
  116. // 选择用户
  117. handleUser () {
  118. this.getSelectedUsers()
  119. this.chooseUserVisible = true
  120. this.getUsers()
  121. },
  122. async getUsers () {
  123. this.$http({
  124. url: this.$http.adornUrl(`/user-service/user/queryWithSelectedItems`),
  125. method: 'get',
  126. params: this.$http.adornParams({
  127. current: this.current,
  128. size: this.size
  129. })
  130. }).then(({ data }) => {
  131. if (data && data.code === '200') {
  132. this.total = data.data.pageUsers.total
  133. let users = data.data.pageUsers.records
  134. if (users != null && users.length > 0) {
  135. users.map((t) => {
  136. this.userOptions.push({ label: t.name, value: t.userId })
  137. })
  138. }
  139. }
  140. })
  141. },
  142. // 滚动到底部时触发
  143. async loadMore () {
  144. if (this.loading || this.userOptions.length >= this.total) return
  145. this.loading = true
  146. this.current++
  147. await this.getUsers() // 请求下一页数据
  148. this.loading = false
  149. },
  150. // 提交用户
  151. userSubmit () {
  152. // let addUserIds = []
  153. // let delUserIds = []
  154. // // 计算新增用户
  155. // for (let id of this.selectedUsers) {
  156. // if (this.oldSelectedUsers.indexOf(id) === -1) {
  157. // addUserIds.push(id)
  158. // }
  159. // }
  160. // // 计算删除用户
  161. // for (let id2 of this.oldSelectedUsers) {
  162. // if (this.selectedUsers.indexOf(id2) === -1) {
  163. // delUserIds.push(id2)
  164. // }
  165. // }
  166. this.$http({
  167. url: this.$http.adornUrl(`/biz-service/workBoard/selected/user/save`),
  168. method: 'post',
  169. data: { addUserIds: this.selectedUsers }
  170. }).then(({ data }) => {
  171. if (data && data.code === '200') {
  172. this.$message({
  173. type: 'success',
  174. message: '提交成功!'
  175. })
  176. this.chooseUserVisible = false
  177. this.getList()
  178. }
  179. })
  180. },
  181. getList () {
  182. this.$http({
  183. url: this.$http.adornUrl(`/biz-service/workBoard/list`),
  184. method: 'get',
  185. params: this.$http.adornParams({
  186. current: 1,
  187. size: 500
  188. })
  189. }).then(({ data }) => {
  190. if (data && data.code === '200') {
  191. this.list = data.data.records
  192. }
  193. })
  194. },
  195. getSelectedUsers () {
  196. this.$http({
  197. url: this.$http.adornUrl(`/biz-service/workBoard/selected/user/list`),
  198. method: 'get',
  199. data: {}
  200. }).then(({ data }) => {
  201. if (data && data.code === '200') {
  202. this.selectedUsers = this.oldSelectedUsers = data.data
  203. }
  204. })
  205. },
  206. // 全屏显示
  207. fullScreen () {
  208. const element = document.getElementById('customer-content')
  209. element.requestFullscreen()
  210. },
  211. startScroll () {
  212. const scrollContainer = this.$el.querySelector('.seamless-scroll')
  213. let top = 0 // 初始位置
  214. setInterval(() => {
  215. top -= 1 // 每次减少1px,可以根据需要调整速度和方向
  216. scrollContainer.scrollTop = top
  217. }, 200)
  218. // 调整这个值来改变速度,数值越小速度越快
  219. }
  220. }
  221. }
  222. </script>
  223. <style scoped>
  224. .mod-home {
  225. /* line-height: 1.5; */
  226. height: 100%;
  227. position: relative;
  228. }
  229. .full-screen-btn {
  230. position: absolute;
  231. top: 0;
  232. right: 0;
  233. z-index: 9;
  234. padding: 0 0;
  235. border-radius: 0;
  236. }
  237. .dialog {
  238. height: 330px;
  239. display: flex;
  240. flex-direction: column;
  241. justify-content: space-between;
  242. }
  243. .dialog-footer2 {
  244. display: flex;
  245. justify-content: end;
  246. }
  247. /* 容器设置 */
  248. .scroll-container {
  249. /* height: 100%; */
  250. border: 1px solid #eee;
  251. overflow: hidden;
  252. background: white; /* 全屏背景 */
  253. }
  254. /* 表头样式(固定定位) */
  255. .header-row {
  256. display: flex;
  257. background: #f5f7fa;
  258. position: sticky;
  259. top: 0;
  260. z-index: 10;
  261. }
  262. .header-cell {
  263. flex: 1;
  264. padding: 12px;
  265. text-align: center;
  266. font-weight: bold;
  267. border-bottom: 1px solid #ddd;
  268. font-size:30px;
  269. }
  270. /* 内容滚动区域 */
  271. .content-scroll {
  272. height: calc(100% - 46px); /* 减去表头高度 */
  273. overflow: hidden;
  274. }
  275. /* 内容行与列 */
  276. .content-row {
  277. display: flex;
  278. border-bottom: 1px solid #f0f0f0;
  279. }
  280. .content-cell {
  281. flex: 1;
  282. padding: 10px;
  283. text-align: center;
  284. font-size: 24px;
  285. }
  286. .content-row:hover {
  287. background: #f9f9f9; /* 悬停高亮 */
  288. }
  289. ul, ol {
  290. margin: 0; /* 消除外部边距 */
  291. padding: 0; /* 消除内部边距 */
  292. list-style: none; /* 可选:移除列表标记 */
  293. }
  294. ul li, ol li {
  295. padding-top: 0; /* 关键:消除首行上边距 */
  296. }
  297. </style>