util.js 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985
  1. import { getData } from '@/api/platform/desktop/column'
  2. import { getFile } from '@/utils/avatar'
  3. import { mapState } from 'vuex'
  4. import {
  5. taskTypeOptions,
  6. dashboardStatus,
  7. genderOptions,
  8. favoritesOptions,
  9. noticeOptions,
  10. unreadMessageOptions,
  11. imgOptionsData
  12. } from '@/business/platform/bpmn/constants'
  13. import ActionUtils from '@/utils/action'
  14. import Utils from '@/utils/util'
  15. import {
  16. findAllByCurrUserId,
  17. saveCalendarInfos,
  18. removeCalendarInfos,
  19. delNavigation,
  20. addNavigation,
  21. getNavigation,
  22. sortNavigation
  23. } from '@/api/detection/newHomeApi'
  24. import { isEqual, now } from 'lodash'
  25. import Bus from '@/utils/EventBus'
  26. import newPng from '@/assets/images/homepage/new.png'
  27. import { BASE_URL } from '@/constant'
  28. import dayjs from 'dayjs'
  29. import { scheduleType } from '@/views/constants/schedule'
  30. import { attendanceDetailClockIn } from '@/api/business/attendance'
  31. import { lifeTimeData } from '@/views/business/deviceManagement/constants/simulated'
  32. /**
  33. * 创建组件
  34. */
  35. export function buildComponent(name, column, preview, vm) {
  36. try {
  37. return {
  38. name,
  39. components: {
  40. VueDraggable: () => import('vuedraggable')
  41. },
  42. props: {
  43. params: {
  44. type: Object,
  45. default: () => {}
  46. },
  47. height: {
  48. type: Number,
  49. default: column.height || 300
  50. },
  51. visible: {
  52. type: Boolean,
  53. default: false
  54. },
  55. fullScreen: {
  56. type: Boolean,
  57. default: false
  58. }
  59. },
  60. filters: {
  61. filterStatus(val, type) {
  62. if (Utils.isEmpty(val)) {
  63. return ''
  64. }
  65. const typeMap = {
  66. pending: taskTypeOptions,
  67. already: dashboardStatus,
  68. myRequest: dashboardStatus,
  69. gender: genderOptions,
  70. favorites: favoritesOptions,
  71. notice: noticeOptions,
  72. unreadMessage: unreadMessageOptions
  73. }
  74. if (!typeMap[type]) {
  75. return val
  76. }
  77. return typeMap[type].find((x) => x['value'] === val)
  78. ? typeMap[type].find((x) => x['value'] === val).label
  79. : val
  80. }
  81. },
  82. data() {
  83. const { first = '', second = '' } = this.$store.getters.level
  84. const {
  85. userId,
  86. userList = [],
  87. deptList = [],
  88. menus,
  89. userInfo
  90. } = this.$store.getters
  91. const t1 = deptList.find((i) => i.positionId === first) || {}
  92. const t2 = deptList.find((i) => i.positionId === second) || {}
  93. const locationName = second
  94. ? t1.positionName + t2.positionName
  95. : t1.positionName
  96. return {
  97. userId,
  98. userList,
  99. deptList,
  100. menus,
  101. locationName,
  102. newPng,
  103. imgOptionsData,
  104. positions: userInfo.positions,
  105. loading: false,
  106. title: `${column.name}`,
  107. alias: `${column.alias}`,
  108. attrs: this.getAttrs(),
  109. variables: {}, // 一些变量,比如分页信息
  110. data: null,
  111. totalCount: 0,
  112. quickNavigationData: [],
  113. navigationList: [],
  114. stautusOptions: [],
  115. bpmnFormrenderDialogVisible: false, // 表单
  116. editId: '',
  117. bodyShow: true,
  118. show: false,
  119. showHeight: '',
  120. cardHeight: '100%',
  121. activeName: 'innerMessage',
  122. unreadMessageOption: {},
  123. formName: 'quickNavform',
  124. dialogFormVisible: false,
  125. formLabelWidth: '120px',
  126. quickNavform: {
  127. urlName: '',
  128. urlAddr: '',
  129. display: '_blank',
  130. diDian: second || first
  131. },
  132. defaultForm: {},
  133. pendingTabActiveName: 'user-type',
  134. bodyParams: ActionUtils.formatParams({}, {}, {}),
  135. pendingBusinessOption: {},
  136. bpmn: [],
  137. rules: {
  138. urlName: [
  139. {
  140. required: true,
  141. message: this.$t('validate.required')
  142. }
  143. ],
  144. urlAddr: [
  145. {
  146. required: true,
  147. message: this.$t('validate.required')
  148. }
  149. ],
  150. display: [
  151. {
  152. required: true,
  153. message: this.$t('validate.required')
  154. }
  155. ]
  156. },
  157. calendarDialogForm: {
  158. id: '',
  159. biaoTi: '',
  160. neiRong: '',
  161. kaiShiShiJian: '',
  162. jieShuShiJian: '',
  163. formDate: []
  164. },
  165. colorStatus: ['#e7505a', '#f3c200', '#578ebe', '#1BBC9B'],
  166. // const status = ['急', '重', '轻','缓']
  167. isDragging: false,
  168. draggableOptions: {
  169. handle: '.draggable',
  170. ghostClass: 'sortable-ghost',
  171. distance: 1,
  172. disabled: false,
  173. animation: 200,
  174. axis: 'y'
  175. },
  176. calendarToolbar: this.fullScreen
  177. ? [{ key: 'refresh' }]
  178. : [{ key: 'refresh' }, { key: 'fullscreen' }, { key: 'collapse' }],
  179. isFirstAlert: true, // 是否首次日程提醒
  180. scheduleData: [],
  181. hasMounted: false,
  182. attendanceData: [],
  183. scheduleShift: [],
  184. todaySchedule: [],
  185. tempSelectedValue: ''
  186. }
  187. },
  188. computed: {
  189. ...mapState({
  190. userInfo: (state) => state.ibps.user.info
  191. })
  192. },
  193. mounted() {
  194. this.defaultForm = JSON.parse(JSON.stringify(this.quickNavform))
  195. this.$nextTick(async () => {
  196. this.fetchData()
  197. // this.attendanceData = await this.getAttendanceData()
  198. // this.scheduleData = await this.getScheduleData()
  199. this.todaySchedule = await this.getTodaySchedule()
  200. })
  201. },
  202. methods: {
  203. fetchData(columns, params = {}) {
  204. this.loading = true
  205. this.data = []
  206. this.showHeight = this.getHeight()
  207. const param =
  208. Utils.isNotEmpty(columns) &&
  209. (column.alias === 'unreadMessage' ||
  210. column.alias === 'pendingBusiness')
  211. ? { dataMode: column.dataMode, dataFrom: column.dataFrom }
  212. : column
  213. if (param.alias === 'myCalendar') {
  214. const { getFormatDate, getDate } = this.$common
  215. findAllByCurrUserId()
  216. .then((res) => {
  217. const { data = [] } = res || {}
  218. if (this.isFirstAlert) {
  219. this.isFirstAlert = false
  220. this.showAlert(data)
  221. }
  222. this.data = data.map((i) => ({
  223. id: i.id,
  224. title: i.title,
  225. content: i.content,
  226. start: i.startTime,
  227. // 日期组件日程显示里,end的时间需要多加一天,end:2024-01-02时,日程条只到2024-01-01的日期位置上
  228. end: getFormatDate(
  229. 'string',
  230. 10,
  231. getDate('day', 1, i.endTime)
  232. ),
  233. jieShuShiJian: i.endTime,
  234. zhuangTai: i.emergencyState,
  235. color: this.colorStatus[Number(i.emergencyState) - 1]
  236. }))
  237. })
  238. .catch(() => {
  239. this.$message.error('获取日历日程失败!')
  240. })
  241. } else if (param.alias === 'quickNavigation') {
  242. getNavigation().then((res) => {
  243. const { data = [] } = res || {}
  244. data.forEach((item) => {
  245. if (!item.userId) {
  246. item.urlAddr = `${BASE_URL}#${item.urlAddr}`
  247. }
  248. })
  249. this.quickNavigationData = data
  250. })
  251. } else {
  252. getData(param, params)
  253. .then((res) => {
  254. let { data } = res || {}
  255. if (Utils.isNotEmpty(data) && Utils.isString(data)) {
  256. data = Utils.parseData(res.data)
  257. }
  258. this.data = data && data.dataResult ? data.dataResult : data
  259. this.totalCount =
  260. data && data.pageResult ? data.pageResult.totalCount : 0
  261. // 更新小铃铛消息数量
  262. if (param.alias === 'unreadMessage') {
  263. Bus.$emit('getMessageCount', this.totalCount)
  264. }
  265. this.variables = res.variables
  266. this.loading = false
  267. })
  268. .catch((e) => {
  269. this.loading = false
  270. })
  271. }
  272. },
  273. // 过滤日程提醒数据
  274. filterAlertData(data, dayNumber = 3) {
  275. if (dayNumber <= 0) return
  276. const today = dayjs()
  277. const tempCalendarAlertData = data.filter((day) => {
  278. const startTime = dayjs(day.startTime)
  279. const endTime = dayjs(day.endTime)
  280. if (day.popUp) {
  281. if (
  282. (startTime.diff(today, 'day') <= 0 &&
  283. endTime.diff(today, 'day') >= 0) ||
  284. (startTime.diff(today, 'day') <= dayNumber - 2 &&
  285. startTime.diff(today, 'day') >= 0)
  286. ) {
  287. return true
  288. }
  289. }
  290. })
  291. tempCalendarAlertData.sort(
  292. (a, b) => new Date(a.startTime) - new Date(b.startTime)
  293. )
  294. const calendarIds = tempCalendarAlertData.map((item) => item.id)
  295. const calendarAlertData = {}
  296. tempCalendarAlertData.forEach((item) => {
  297. if (calendarAlertData[item.startTime]) {
  298. calendarAlertData[item.startTime].push(item)
  299. } else {
  300. calendarAlertData[item.startTime] = []
  301. calendarAlertData[item.startTime].push(item)
  302. }
  303. })
  304. return { calendarAlertData, calendarIds }
  305. },
  306. // 日程提醒
  307. showAlert(data) {
  308. const calendarAlertData = this.filterAlertData(data)
  309. this.$emit('action-event', 'calendarAlert', calendarAlertData)
  310. },
  311. getPhoto(photo) {
  312. return getFile(photo)
  313. },
  314. getTaskDesc(v) {
  315. if (!v.includes('#')) {
  316. return ''
  317. }
  318. return v.split('#')[1] || ''
  319. },
  320. getTaskInfo(val, arg) {
  321. const arr = val.split('#')
  322. if (!arr[2]) {
  323. return ''
  324. }
  325. // 中文冒号转英文冒号 防止流程定义时输入的冒号格式错误导致转换报错
  326. arr[2] = arr[2].replace(':', ':')
  327. const result = JSON.parse(`{${arr[2]}}`)
  328. if (!result.dept) {
  329. return ''
  330. }
  331. const depts = result.dept.split(',')
  332. const deptNames = []
  333. depts.forEach((item) => {
  334. const t = this.deptList.find((i) => i.positionId === item)
  335. deptNames.push(t ? t.positionName : result.dept)
  336. })
  337. result.deptName = deptNames.join(',')
  338. return result[arg]
  339. },
  340. transformData(val, dataset, from, to) {
  341. if (!val) {
  342. return ''
  343. }
  344. const temp = this[dataset].find((u) => u[from] === val)
  345. return temp ? temp[to] : ''
  346. },
  347. getHeightNoUnit() {
  348. // 高度 - header - 边框
  349. if (!this.visible) {
  350. return this.height ? this.height - 60 - 20 : 150
  351. } else {
  352. return 150
  353. }
  354. },
  355. getHeight(h = 20) {
  356. // 高度 - header - 边框
  357. if (!this.visible) {
  358. return this.height ? `${this.height - 60 - h}px` : '150px'
  359. } else {
  360. return '100%'
  361. }
  362. },
  363. getDashboardHeight() {
  364. return this.height ? `${this.height + 20}px` : '150px'
  365. },
  366. getAttrs() {
  367. const item = JSON.parse(JSON.stringify(column))
  368. item.templateHtml = null
  369. return item
  370. },
  371. /**
  372. * 构建首页日期组件的参数
  373. * @param {*} data
  374. * @returns
  375. */
  376. getFullCalendarConfig(data) {
  377. const events = data === null ? [] : Utils.parseJSON(data)
  378. const config = {
  379. height: preview ? '100%' : this.height ? this.height : 180,
  380. // editable: true, // 允许拖动缩放,不写默认就是false
  381. selectable: true,
  382. dayMaxEvents: 1, // 最多显示3个日程
  383. locale: this.$i18n.locale
  384. ? this.$i18n.locale.toLowerCase()
  385. : 'zh-cn',
  386. events: events,
  387. buttonText: {
  388. today: '今天',
  389. dayGridMonth: '月',
  390. listMonth: '日程'
  391. // week: '周视图',
  392. // day: '日视图',
  393. // prev: '<i class="icon-chevron-left">后退</i>',
  394. // next: '<i class="icon-chevron-right">前进</i>'
  395. },
  396. dateClick: this.handleDateClick, // 日期点击
  397. eventClick: this.handleEventClick,
  398. moreLinkClick: this.handleMoreLinkClick
  399. }
  400. if (preview) {
  401. config.headerToolbar = {
  402. start: '',
  403. center: 'title',
  404. end: 'prev,next,today'
  405. // end: 'prev,next,today,month,agendaWeek,agendaDay,listWeek'
  406. }
  407. delete config['dayMaxEvents']
  408. }
  409. return config
  410. },
  411. handleDateClick(param) {
  412. this.$emit(
  413. 'open',
  414. 'calendar',
  415. [param.dateStr, param.dateStr],
  416. this.data
  417. )
  418. },
  419. handleEventClick(param) {
  420. this.$emit(
  421. 'open',
  422. 'calendar',
  423. [
  424. param.event.startStr,
  425. param.event._def.extendedProps.jieShuShiJian
  426. ],
  427. this.data,
  428. param.event.id
  429. )
  430. },
  431. handleMoreLinkClick(date) {
  432. this.$emit(
  433. 'open',
  434. 'calendar',
  435. [
  436. date.allSegs[0].event.startStr,
  437. date.allSegs[0].event._def.extendedProps.jieShuShiJian
  438. ],
  439. this.data,
  440. date.allSegs[0].event.id
  441. )
  442. },
  443. refreshData() {
  444. this.fetchData()
  445. },
  446. /**
  447. * 处理按钮事件
  448. * @param {*} command
  449. * @param {*} position
  450. * @param {*} data
  451. * @param {*} actions
  452. */
  453. handleActionEvent(command, position, data, actions) {
  454. switch (command) {
  455. case 'refresh': // 刷新
  456. this.refreshData()
  457. break
  458. case 'fullscreen': // 全屏
  459. this.handleFullscreen()
  460. break
  461. case 'more': // 更多
  462. this.handleMore()
  463. break
  464. case 'collapse': // 收缩
  465. case 'expansion': // 展开
  466. this.handleCollapseExpand(command, data, actions)
  467. break
  468. case 'add': // 新增
  469. this.getFormData()
  470. break
  471. default:
  472. break
  473. }
  474. },
  475. emitActionEventHandler(command) {
  476. this.$emit('action-event', command, ...Array.from(arguments).slice(1))
  477. },
  478. // 公告栏目点击事件
  479. handleApprove(id, title) {
  480. this.$emit('action-event', 'approve', {
  481. id,
  482. title
  483. })
  484. },
  485. handleUnreadMessage(id, tableId, tableName) {
  486. this.$emit('action-event', 'unRead', { id, tableId, tableName })
  487. },
  488. // 处理全屏
  489. handleFullscreen() {
  490. this.emitActionEventHandler('fullscreen', { id: this.attrs.id })
  491. },
  492. openPlate(url) {
  493. const menuMap = {
  494. myTraining: 'rygl/rypx/wdpx',
  495. myTesting: 'rygl/kszx/wdks',
  496. myDevices: 'sbgls/mywh',
  497. notice: 'tygl/tzgg',
  498. myFacility: 'sshjgl/sshjjk/sshjkzzl',
  499. quickNavigation: 'xtgl/xtsjpz/tyglpz/kjdhpz'
  500. }
  501. if (menuMap[url]) {
  502. const alias = menuMap[url].split('/')[0]
  503. const resInfo = this.menus.find((i) => i.alias === alias)
  504. this.$store.dispatch('ibps/menu/activeHeaderSet', {
  505. activeHeader: resInfo.id,
  506. vm: this
  507. })
  508. }
  509. this.$router.push(`/${menuMap[url] || url}`)
  510. },
  511. /**
  512. * 处理更多
  513. */
  514. handleMore() {
  515. if (this.attrs.alias === 'quickNavigation') {
  516. return this.openPlate('quickNavigation')
  517. }
  518. if (!this.attrs.colUrl) {
  519. return this.$message.warning('未设置更多路径的url')
  520. }
  521. this.openPlate(this.attrs.colUrl)
  522. },
  523. // 未读消息
  524. handleClick(option) {
  525. this.unreadMessageOption = option
  526. option[this.activeName].dataMode = column.dataMode
  527. this.fetchData(option[this.activeName])
  528. },
  529. // 待办事务
  530. handleTabClick(option) {
  531. this.pendingBusinessOption = option
  532. option[this.pendingTabActiveName].dataMode = column.dataMode
  533. this.fetchData(option[this.pendingTabActiveName])
  534. },
  535. handleFlowClick(params) {
  536. params.$alias = this.alias
  537. this.emitActionEventHandler('flow', params)
  538. },
  539. handleCollapseExpand(command, data, actions) {
  540. this.bodyShow = !this.bodyShow
  541. const index = actions.findIndex((action) => action.key === data.key)
  542. actions[index].key = this.bodyShow ? 'collapse' : 'expansion'
  543. if (!this.visible) {
  544. this.emitActionEventHandler(command, {})
  545. return
  546. }
  547. this.showHeight = this.bodyShow ? this.getHeight() : 0
  548. this.$refs['toolbar'].callback(actions)
  549. },
  550. formValidate(formName) {
  551. this.$nextTick(() => {
  552. this.$refs[formName].validate(() => {})
  553. })
  554. },
  555. getFormData() {
  556. this.quickNavform = JSON.parse(JSON.stringify(this.defaultForm))
  557. this.formValidate('quickNavform')
  558. this.dialogFormVisible = true
  559. },
  560. handleNavRemove(navId, i) {
  561. this.$confirm('是否确认删除该快捷导航?', '提示', {
  562. confirmButtonText: '确认',
  563. cancelButtonText: '取消',
  564. type: 'warning',
  565. showClose: false,
  566. closeOnClickModal: false
  567. }).then(() => {
  568. delNavigation({ navigateIds: navId }).then(() => {
  569. this.$message.success('删除成功')
  570. this.quickNavigationData.splice(i, 1)
  571. })
  572. })
  573. },
  574. // 错误头像的照片
  575. errorAvatarHandler(data) {
  576. // data.photo = require('https://cube.elemecdn.com/e/fd/0fc7d20532fdaf769a25683617711png.png')
  577. return true
  578. },
  579. close() {
  580. this.$refs[this.formName].resetFields()
  581. this.dialogFormVisible = false
  582. },
  583. saveQuickNav() {
  584. this.$refs[this.formName].validate((valid) => {
  585. if (valid) {
  586. addNavigation({ id: '', ...this.quickNavform }).then((res) => {
  587. this.$message.success('添加成功!')
  588. const { id } = res.variables || {}
  589. this.quickNavigationData.unshift({
  590. id,
  591. ...this.quickNavform,
  592. userId: this.userId
  593. })
  594. this.dialogFormVisible = false
  595. })
  596. } else {
  597. ActionUtils.saveErrorMessage()
  598. }
  599. })
  600. },
  601. handleSortChange() {
  602. this.isDragging = false
  603. const newSort = this.quickNavigationData.map((i) => i.id)
  604. if (isEqual(this.navigationList, newSort)) {
  605. return
  606. }
  607. this.navigationList = newSort
  608. sortNavigation({ orders: this.navigationList.join(',') }).then(() => {
  609. this.$message.success('排序成功!')
  610. })
  611. },
  612. // 父组件调用该方法给日程添加数据
  613. async setCalendarEvents(param) {
  614. const { name = '' } = this.$store.getters
  615. const form = param.form
  616. const paramObject = {
  617. id: form.id ? form.id : '11111',
  618. // diDian: "string", // 地点
  619. userId: this.userId, // 用户id
  620. userName: name, // 用户名
  621. title: form.biaoTi, // 标题
  622. content: form.neiRong, // 内容
  623. startTime: form.formDate[0], // 开始时间
  624. endTime: form.formDate[1], // 结束时间
  625. emergencyState: form.zhuangTai // 紧急状态
  626. }
  627. await saveCalendarInfos(paramObject)
  628. this.refreshData()
  629. },
  630. async hanldeCalendardel(param) {
  631. if (param.form.id) {
  632. await removeCalendarInfos({
  633. calendarIds: param.form.id
  634. })
  635. }
  636. this.refreshData()
  637. },
  638. // 公告栏是否显示new图标
  639. showNewIcon(date, days) {
  640. const nowDate = new Date().getTime()
  641. const targetDate = new Date(date).getTime()
  642. return targetDate + days * 24 * 60 * 60 * 1000 > nowDate
  643. },
  644. handleOverflow(val, length) {
  645. if (val.length > length) {
  646. return val.slice(0, length - 2) + '...'
  647. }
  648. return val
  649. },
  650. getDays(start, end) {
  651. if (!start || !end) {
  652. return 0
  653. }
  654. return (
  655. Math.ceil(
  656. (new Date(end) - new Date(start)) / (1000 * 60 * 60 * 24)
  657. ) + 1
  658. )
  659. },
  660. getTodaySchedule() {
  661. // 获取今日班次
  662. const { first, second } = this.$store.getters.level || {}
  663. const today = this.$common.getDateNow()
  664. // const sql = `select a.*, b.title_,b.type_, b.start_date_, b.end_date_, b.config_, b.overview_, b.id_ as pai_ban_id_ from t_schedule_detail a, t_schedule b where a.parent_id_ = b.id_ and b.di_dian_ = '${second || first}' and a.user_id_ = '${this.userId}' and b.status_ = '已发布'`
  665. return new Promise((resolve, reject) => {
  666. this.$common
  667. .request('query', {
  668. key: 'getScheduleDataByUid',
  669. params: [second || first, this.userId]
  670. })
  671. .then((res) => {
  672. const { data = [] } = res.variables || {}
  673. let todaySchedule = []
  674. data.forEach((item) => {
  675. const days = this.getDays(item.start_date_, today)
  676. const shift = item[`d${days}_`]
  677. const config = item.config_ ? JSON.parse(item.config_) : {}
  678. const { scheduleShift } = config
  679. this.scheduleShift = scheduleShift
  680. if (shift) {
  681. const shiftList = shift.split(',')
  682. todaySchedule = todaySchedule.concat(shiftList) // 返回今日班次
  683. }
  684. })
  685. console.log(todaySchedule)
  686. resolve(todaySchedule)
  687. })
  688. .catch((error) => {
  689. reject(error)
  690. })
  691. })
  692. },
  693. getAttendanceData() {
  694. const { first, second } = this.$store.getters.level || {}
  695. const today = this.$common.getDateNow()
  696. // const sql = `select a.id_, a.kao_qin_zhuang_ta,a.ri_qi_, a.pai_ban_id_, a.pai_ban_ji_lu_id_, a.ban_ci_bie_ming_, a.ban_ci_kai_shi_, a.ban_ci_jie_shu_, a.ban_ci_ming_, a.da_ka_shi_jian_1_, a.zhuang_tai_1_, a.da_ka_shi_jian_2_, a.zhuang_tai_2_, a.chi_dao_shi_chang FROM t_attendance_detail a JOIN t_schedule b ON a.pai_ban_id_ = b.id_ AND b.status_ = '已发布' WHERE a.di_dian_ = '${second || first}' AND a.ri_qi_ <= '${today}' AND a.yong_hu_id_ = '${this.userId}'`
  697. return new Promise((resolve, reject) => {
  698. this.$common
  699. .request('query', {
  700. key: 'getAttendanceDataByUid',
  701. params: [second || first, today, this.userId]
  702. })
  703. .then((res) => {
  704. const { data = [] } = res.variables || {}
  705. const resultMap = new Map()
  706. data.forEach((item) => {
  707. const { ri_qi_, pai_ban_id_, ban_ci_bie_ming_, ...rest } =
  708. item
  709. // 第一级:按日期分组
  710. if (!resultMap.has(ri_qi_)) {
  711. resultMap.set(ri_qi_, new Map())
  712. }
  713. const dateMap = resultMap.get(ri_qi_)
  714. // 第二级:按排班ID分组
  715. if (!dateMap.has(pai_ban_id_)) {
  716. dateMap.set(pai_ban_id_, new Map())
  717. }
  718. const scheduleMap = dateMap.get(pai_ban_id_)
  719. // 第三级:按班次别名存储完整数据
  720. scheduleMap.set(ban_ci_bie_ming_, rest)
  721. })
  722. // return resultMap
  723. resolve(resultMap)
  724. })
  725. .catch((error) => {
  726. reject(error)
  727. })
  728. })
  729. },
  730. getScheduleData() {
  731. const { first, second } = this.$store.getters.level || {}
  732. // const sql = `select a.*, b.title_,b.type_, b.start_date_, b.end_date_, b.config_, b.overview_, b.id_ as pai_ban_id_ from t_schedule_detail a, t_schedule b where a.parent_id_ = b.id_ and b.di_dian_ = '${second || first}' and a.user_id_ = '${this.userId}' and b.status_ = '已发布'`
  733. return new Promise((resolve, reject) => {
  734. this.$common
  735. .request('query', {
  736. key: 'getScheduleDataByUid',
  737. params: [second || first, this.userId]
  738. })
  739. .then((res) => {
  740. const { data = [] } = res.variables || {}
  741. const eventList = []
  742. const self = this
  743. data.forEach((item) => {
  744. const days = this.getDays(item.start_date_, item.end_date_)
  745. const config = item.config_ ? JSON.parse(item.config_) : {}
  746. const scheduleTypeLabel =
  747. scheduleType.filter((obj) => obj.value === item.type_)[0]
  748. ?.label || ''
  749. const scheduleCreateBy =
  750. self.userList.filter(
  751. (obj) => obj.userId === item.create_by_
  752. )[0]?.userName || ''
  753. const { scheduleShift } = config
  754. this.scheduleShift = scheduleShift
  755. for (let i = 1; i <= days; i++) {
  756. const shift = item[`d${i}_`]
  757. if (shift) {
  758. const date = this.$common.getFormatDate(
  759. 'string',
  760. 10,
  761. this.$common.getDate('day', i - 1, item.start_date_)
  762. )
  763. const nextdate = this.$common.getFormatDate(
  764. 'string',
  765. 10,
  766. this.$common.getDate('day', i, item.start_date_)
  767. )
  768. const enddate = this.$common.getFormatDate(
  769. 'string',
  770. 10,
  771. this.$common.getDate('day', i+1, item.start_date_)
  772. )
  773. const shiftList = shift.split(',')
  774. shiftList.forEach((s) => {
  775. const t = scheduleShift.find((i) => i.alias === s)
  776. const attendance = self.attendanceData
  777. .get(date)
  778. ?.get(item.pai_ban_id_)
  779. ?.get(s)
  780. eventList.push({
  781. scheduleName: item.title_ ? item.title_ : '', // 排班表名字
  782. scheduleTypeLabel: scheduleTypeLabel || '', // 排班类型
  783. scheduleCreateBy: scheduleCreateBy || '', // 排班创建人
  784. content: t.dateRange
  785. .map((d) => {
  786. return d.type === 'allday'
  787. ? '全天'
  788. : `当天 ${d.startTime}` +
  789. ' 至 ' +
  790. `${d.isSecondDay === 'Y' ? '第二天' : '当天'} ${d.endTime}`
  791. })
  792. .join('\n'),
  793. title: s,
  794. start: date,
  795. end:t.dateRange[0].isSecondDay=='Y'? nextdate : date, //是否跨天班次,跨天班次要设置为结束日期的下一天,即开始日期的后天
  796. jieShuShiJian: t.dateRange[0].isSecondDay=='Y'? nextdate : date,
  797. kaishishijian: date,
  798. zhuangTai: '',
  799. // id: i,
  800. id:attendance?.id_ || i,
  801. bcolor: t.color,
  802. attendance: attendance || {}, // 考勤状态
  803. //allDay: true, // 标记为全天事件
  804. //display: "auto", // 自动跨天渲染(默认值)
  805. ...t
  806. })
  807. })
  808. }
  809. }
  810. })
  811. // const today = this.$common.getDateNow()
  812. // this.todaySchedule = eventList.filter(i => i.start === today).map(i => i.title)
  813. // console.log(this.todaySchedule)
  814. resolve(eventList)
  815. })
  816. .catch((error) => {
  817. reject(error)
  818. })
  819. })
  820. },
  821. handleScheduleEventClick(param) {
  822. // 排班点击事件
  823. this.$emit(
  824. 'open',
  825. 'banci',
  826. param.event._def.extendedProps,
  827. this.scheduleShift,
  828. param.event._def.title
  829. )
  830. },
  831. showDaKaBtn(targetDay1,targetDay2) { //班次开始或结束时间有一个是今天就显示打卡按钮
  832. // 判断是否展示打卡按钮,当前日期则展示
  833. const today = this.$common.getDateNow()
  834. if (targetDay1 === today || targetDay2 === today) {
  835. return true
  836. } else {
  837. return false
  838. }
  839. },
  840. // 打卡处理逻辑
  841. handleClock(attendance) {
  842. if (Object.keys(attendance).length === 0) {
  843. this.$message.warning('考勤数据异常!')
  844. return
  845. }
  846. // 更新打卡请求
  847. attendanceDetailClockIn({ id: attendance.id_ })
  848. .then(() => {
  849. this.$message.success('打卡成功!')
  850. })
  851. .catch(() => {
  852. // this.$message.warning('打卡失败')
  853. })
  854. },
  855. getTimeDifferenceInMinutes(startTimeStr, endTimeStr) {
  856. // 时间相减分钟数
  857. const startTime = new Date(startTimeStr)
  858. const endTime = new Date(endTimeStr)
  859. const timeDifference = endTime - startTime
  860. return timeDifference / (1000 * 60)
  861. },
  862. // 首页打卡处理逻辑
  863. handleClockFromTab(todaySchedule) {
  864. const today = this.$common.getDateNow()
  865. // 当天仅有一个班次
  866. if (todaySchedule.length === 1) {
  867. this.$emit('dakaSingle', todaySchedule[0])
  868. return
  869. } else {
  870. this.$emit('action-event', 'daka', todaySchedule)
  871. }
  872. },
  873. async showMySchedule() {
  874. this.attendanceData = await this.getAttendanceData()
  875. this.scheduleData = await this.getScheduleData()
  876. const scheduleConfig = {
  877. height: '100%',
  878. locale: 'zh-cn', // 语言
  879. selectable: true, // 是否可以选中日历格
  880. buttonText: {
  881. // 日历头部按钮中文转换
  882. today: '今天',
  883. dayGridMonth: '月',
  884. listMonth: '',
  885. month: '月',
  886. week: '周视图',
  887. day: '日视图',
  888. list: '表'
  889. // prev: '<i class="icon-chevron-left">后退</i>',
  890. // next: '<i class="icon-chevron-right">前进</i>'
  891. },
  892. headerToolbar: {
  893. // 日历头部按钮位置
  894. // left: 'prev,next today',
  895. // start: '',
  896. right: 'customButton prev,next today',
  897. left: '',
  898. center: 'title'
  899. // right: 'dayGridMonth,timeGridWeek,timeGridDay'
  900. // end: 'prev,next,today,month,agendaWeek,agendaDay,listWeek'
  901. },
  902. customButtons: {
  903. customButton: {
  904. // 定义自定义按钮
  905. text: '补卡',
  906. click: (param) => {
  907. // 打开补卡申请弹窗
  908. this.$emit('open', 'buka')
  909. }
  910. }
  911. },
  912. // events: this.scheduleData, // 排班数组
  913. eventClick: this.handleScheduleEventClick, // 排班点击信息展示
  914. scheduleShift: this.scheduleShift,
  915. eventColor: '#ffffff',
  916. events: this.scheduleData,
  917. // 添加自定义事件渲染
  918. eventContent: (arg) => {
  919. const event = arg.event
  920. const now = new Date()
  921. const dayStart = new Date(event.start)
  922. dayStart.setHours(0, 0, 0, 0)
  923. // 组合DOM内容
  924. const fragment = document.createDocumentFragment()
  925. const content = document.createElement('div')
  926. const titleStr =
  927. event.extendedProps.name + '/' + event.extendedProps.alias
  928. const timeStr =
  929. event.extendedProps.dateRange[0].startTime +
  930. '至' +
  931. event.extendedProps.dateRange[0].endTime
  932. // 考勤是否正常
  933. const status =
  934. event.extendedProps.attendance.kao_qin_zhuang_ta || ''
  935. content.innerHTML = `
  936. <div class="event-header">
  937. <div>
  938. <div style="background:${event.extendedProps.bcolor};height:10px;width:10px;display:inline-block;"> </div>
  939. ${titleStr}
  940. </div>
  941. <div class="button-placeholder">
  942. ${
  943. event.extendedProps.jieShuShiJian <=
  944. this.$common.getDateNow()
  945. ? status === '正常'
  946. ? '<i class="el-icon-check" style="color:#409EFF"></i>'
  947. : '<i class="el-icon-warning-outline" style="color:#F5222D"></i>'
  948. : ''
  949. }
  950. </div>
  951. </div>
  952. `
  953. // 打卡按钮显示
  954. if (this.showDaKaBtn(event.extendedProps.kaishishijian,event.extendedProps.jieShuShiJian)) {
  955. const button = document.createElement('button')
  956. button.className = 'clock-btn'
  957. // 根据打卡状态显示不同文本
  958. button.innerHTML = '打卡'
  959. // 绑定点击事件(通过闭包传递当前事件)
  960. button.onclick = (e) => {
  961. e.stopPropagation()
  962. this.handleClock(event.extendedProps.attendance)
  963. }
  964. const placeholder = content.querySelector('.button-placeholder')
  965. placeholder.replaceWith(button)
  966. }
  967. fragment.appendChild(content)
  968. return { domNodes: [fragment] }
  969. }
  970. }
  971. this.$emit('action-event', 'mySchedule', scheduleConfig)
  972. }
  973. },
  974. template:
  975. column.templateHtml !== '' ? `${column.templateHtml}` : `<div></div>`
  976. }
  977. } catch (error) {
  978. console.error(error)
  979. }
  980. }