workbench.vue 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865
  1. <template>
  2. <div class="app-container">
  3. <el-tabs v-model="activeTab" class="tabs" :before-leave="handleChange" @tab-click="changeTab">
  4. <el-tab-pane v-for="item in tabList" :key="item.key" :name="item.key">
  5. <span slot="label"><i :class="item.icon" /> {{ item.label }}</span>
  6. <div v-if="activeTab === item.key" class="tab-container">
  7. <div class="table-container">
  8. <ibps-crud
  9. :ref="item.key"
  10. :data="dataList"
  11. :toolbars="item.key === 'save' ? listConfig.darftTool : listConfig.toolbars"
  12. :search-form="listConfig.searchForm[item.key]"
  13. :pk-key="pkKey"
  14. :columns="listConfig.columns[item.key]"
  15. :pagination="pagination"
  16. :loading="loading"
  17. :index-row="false"
  18. :selection-row="item.key === 'save'"
  19. @row-click="handleRowClick"
  20. @action-event="handleAction"
  21. @sort-change="handleSortChange"
  22. @pagination-change="handlePaginationChange"
  23. >
  24. <template slot="name" slot-scope="scope">{{ scope.row.subject | getWorkInfo('name') }}</template>
  25. <template slot="desc" slot-scope="scope">{{ scope.row.subject | getWorkInfo('desc') }}</template>
  26. <!-- 待办字段处理 -->
  27. <template slot="waitStatus" slot-scope="scope">{{ '待' + scope.row.name }}</template>
  28. <template slot="stateLabel" slot-scope="scope">
  29. <span>{{ scope.column.label }}</span>
  30. <el-tooltip effect="dark" placement="top">
  31. <div slot="content">
  32. 普通事务:接收三天之内为待办理,三天之后为已超时
  33. <br>
  34. 计划事务:月底前七天内为即将超时,超过接收当月月底为已超时,其余为待办理
  35. </div>
  36. <i class="el-icon-info" />
  37. </el-tooltip>
  38. </template>
  39. <template slot="state" slot-scope="scope">
  40. <el-tag :type="scope.row.state ? stateOption[scope.row.state].type : ''">{{ scope.row.state ? stateOption[scope.row.state].label : '待办理' }}</el-tag>
  41. </template>
  42. <template slot="submitBy" slot-scope="scope">
  43. <span>{{ scope.column.label }}</span>
  44. <el-tooltip effect="dark" placement="top">
  45. <div slot="content">
  46. 该事务对应流程的发起人
  47. </div>
  48. <i class="el-icon-info" />
  49. </el-tooltip>
  50. </template>
  51. <template slot="forwardBy" slot-scope="scope">
  52. <span>上节点</span><br>
  53. <span>提交人</span>
  54. <el-tooltip effect="dark" placement="top">
  55. <div slot="content">
  56. 该事务对应流程上一节点的提交人
  57. </div>
  58. <i class="el-icon-info" />
  59. </el-tooltip>
  60. </template>
  61. <!-- 已办、办结字段处理 -->
  62. <template slot="overStatus" slot-scope="scope">{{ getStatus(scope.row.status) }}</template>
  63. <template slot="overDept" slot-scope="scope">{{ getAttr(scope.row.subject, 'deptName') }}</template>
  64. <template slot="creator" slot-scope="scope">{{ scope.row.createBy | getUserName(userList) }}</template>
  65. <template slot="updateBy" slot-scope="scope">{{ getName(scope.row) }}</template>
  66. <template slot="time" slot-scope="scope">{{ scope.row.endTime || scope.row.updateTime || scope.row.createTime }}</template>
  67. </ibps-crud>
  68. </div>
  69. </div>
  70. </el-tab-pane>
  71. </el-tabs>
  72. <bpmn-formrender
  73. :visible="dialogFormVisible"
  74. :task-id="activeTab === 'wait' ? taskId : null"
  75. :wai-jian="activeTab === 'wait' ? waiJian : null"
  76. :instance-id="['over', 'finish'].includes(activeTab) ? instanceId : null"
  77. :def-id="activeTab === 'save' ? defId : null"
  78. :pro-inst-id="activeTab === 'save' ? proInstId : null"
  79. :title="['wait', 'save'].includes(activeTab) ? FlowName : null"
  80. @callback="updateList"
  81. @close="visible => (dialogFormVisible = visible)"
  82. />
  83. <news-detail
  84. :id="newsId"
  85. :title="newsTitle"
  86. :visible="newsDialogVisible"
  87. readonly
  88. @close="visible => newsDialogVisible = visible"
  89. />
  90. </div>
  91. </template>
  92. <script>
  93. import { pending, handledTask } from '@/api/platform/office/bpmReceived'
  94. import { myDraft, removeDraft } from '@/api/platform/office/bpmInitiated'
  95. import { queryPageList as newsList } from '@/api/platform/system/news'
  96. import { queryOrgManager } from '@/api/platform/org/employee'
  97. import { save } from '@/api/platform/message/innerMessage'
  98. import BpmnFormrender from '@/business/platform/bpmn/form/dialog'
  99. import ActionUtils from '@/utils/action'
  100. import { typeOptions } from '@/views/platform/system/news/constants'
  101. import NewsDetail from '@/views/platform/system/news/detail'
  102. import { tabList, taskState, stateOption, taskTypeOptions } from './workbench'
  103. const paramsType = {
  104. wait: 'temp.',
  105. over: '',
  106. finish: 'inst.',
  107. save: '',
  108. news: '',
  109. guide: ''
  110. }
  111. const operate = {
  112. wait: pending,
  113. over: handledTask,
  114. finish: handledTask,
  115. save: myDraft,
  116. news: newsList,
  117. guide: ''
  118. }
  119. export default {
  120. name: 'calendar',
  121. components: { BpmnFormrender, NewsDetail },
  122. filters: {
  123. getWorkInfo (v, type) {
  124. const res = {
  125. name: v.split('#')[0],
  126. // 无#返回空,有#返回(左边的字符串,
  127. desc: v.split('#')[1] ? v.split('#')[1] : ''
  128. }
  129. return res[type]
  130. },
  131. getUserName (v, list) {
  132. const user = list.find(i => i.userId === v)
  133. return user ? user.userName : ''
  134. }
  135. },
  136. props: {
  137. plan: {
  138. type: Array,
  139. default: () => []
  140. }
  141. },
  142. data () {
  143. const fieldWidth = window.innerWidth > 1600 ? 150 : 120
  144. const { first = '', second = '' } = this.$store.getters.level || {}
  145. const level = second || first
  146. const { userList = [], deptList = [] } = this.$store.getters || {}
  147. const getGuide = ({ parameters, requestPage, sorts }) => {
  148. // 获取查询字段
  149. const params = parameters.reduce((acc, curr) => {
  150. return `${acc} and ${curr.key} like '%${curr.value}%'`
  151. }, '')
  152. const sql = `select sn_ as sn, suo_shu_xi_tong_ as sysName, gong_neng_mo_kuai as module, biao_dan_ming_che as tableName, biao_dan_bian_hao as tableNo, tian_xie_shi_ji_ as timing, shi_wu_lei_xing_ as taskType, cheng_xu_wen_jian as fileName, bian_zhi_ren_ as creator, shen_he_ren_ as reviewer, shen_pi_ren_ as approver from t_bdbhpzb where sn_ + 0 > 0 and di_dian_ = '${level}' ${params} order by sn_ + 0 asc`
  153. const { pageNo = 1, limit = 15 } = requestPage || {}
  154. return new Promise((resolve, reject) => {
  155. this.$common.request('sql', sql).then(res => {
  156. const { data = [] } = res.variables || {}
  157. const page = {
  158. limit,
  159. page: pageNo,
  160. totalCount: data.length,
  161. totalPages: Math.ceil(data.length / limit)
  162. }
  163. const result = {
  164. data: {
  165. dataResult: data.slice((pageNo - 1) * limit, pageNo * limit),
  166. pageResult: page
  167. }
  168. }
  169. resolve(result)
  170. }).catch(error => {
  171. reject(error)
  172. })
  173. })
  174. }
  175. operate.guide = getGuide
  176. return {
  177. level,
  178. tabList,
  179. stateOption,
  180. userList,
  181. deptList,
  182. pkKey: 'id',
  183. taskId: '', // 编辑dialog需要使用
  184. waiJian: '', // 编辑dialog需要使用
  185. instanceId: '',
  186. defId: '',
  187. proInstId: '',
  188. newsId: '',
  189. loading: false,
  190. dialogFormVisible: false,
  191. newsDialogVisible: false,
  192. newsTitle: '公告明细',
  193. orgName: '',
  194. roleName: '',
  195. FlowName: '',
  196. posName: '',
  197. timer: null,
  198. orgInfo: {},
  199. activeTab: tabList[0].key,
  200. height: document.body.clientHeight,
  201. selection: [],
  202. defaultPagination: { page: 1, limit: 15 },
  203. sorts: { },
  204. dataList: [],
  205. pagination: {},
  206. searchParams: {
  207. typeId: '',
  208. subject: '',
  209. createTime: ''
  210. },
  211. listConfig: {
  212. searchForm: {
  213. wait: {
  214. forms: [
  215. { prop: 'Q^subject_^SL', name: 'Q^temp.subject_^SL', label: '事务名称', fieldType: 'input' },
  216. { prop: ['Q^temp.create_time_^DL', 'Q^temp.create_time_^DG'], label: '提交时间', fieldType: 'daterange' }
  217. ]
  218. },
  219. over: {
  220. forms: [
  221. { prop: 'Q^subject_^SL', label: '事务名称', fieldType: 'input' },
  222. { prop: ['Q^create_time_^DL', 'Q^create_time_^DG'], label: '创建时间', fieldType: 'daterange' }
  223. ]
  224. },
  225. finish: {
  226. forms: [
  227. { prop: 'Q^subject_^SL', name: 'Q^inst.subject_^SL', label: '事务名称', fieldType: 'input' },
  228. { prop: ['Q^create_time_^DL', 'Q^create_time_^DG'], name: ['Q^inst.create_time_^DL', 'Q^inst.create_time_^DG'], label: '结束时间', fieldType: 'daterange' }
  229. ]
  230. },
  231. save: {
  232. forms: [
  233. { prop: 'Q^subject_^SL', label: '事务名称', fieldType: 'input' },
  234. { prop: ['Q^create_time_^DL', 'Q^create_time_^DG'], label: '提交时间', fieldType: 'daterange' }
  235. ]
  236. },
  237. news: {
  238. forms: [
  239. { prop: 'Q^title_^SL', label: '标题', fieldType: 'input' },
  240. { prop: 'Q^dep_name_^SL', label: '发布部门', fieldType: 'input' },
  241. { prop: 'Q^user_name_^SL', label: '发布人', fieldType: 'input' },
  242. { prop: ['Q^public_date_^DL', 'Q^public_date_^DG'], label: '发布时间', fieldType: 'daterange' }
  243. ]
  244. },
  245. guide: {
  246. forms: [
  247. { prop: 'suo_shu_xi_tong_', label: '所属子系统', labelWidth: 100, fieldType: 'input' },
  248. { prop: 'gong_neng_mo_kuai', label: '所属功能模块', labelWidth: 100, fieldType: 'input' },
  249. { prop: 'biao_dan_ming_che', label: '记录表单', fieldType: 'input' },
  250. { prop: 'shi_wu_lei_xing_', label: '事务类型', fieldType: 'select', options: taskTypeOptions }
  251. ]
  252. }
  253. },
  254. toolbars: [
  255. {
  256. key: 'search'
  257. }
  258. ],
  259. darftTool: [
  260. {
  261. key: 'search'
  262. },
  263. {
  264. key: 'remove'
  265. }
  266. ],
  267. // 表格字段配置
  268. columns: {
  269. wait: [
  270. { prop: 'scope', label: '事务名称', slotName: 'name', width: 250 },
  271. { prop: 'scope', label: '事务说明', slotName: 'desc', minWidth: 250 },
  272. { prop: 'scope', label: '事务状态', slotName: 'waitStatus', width: 120 },
  273. { prop: 'scope', label: '办理进度', headerName: 'stateLabel', slotName: 'state', width: 120 },
  274. // { prop: 'startDept', label: '发起部门', width: 120 },
  275. { prop: 'scope', label: '发起部门', slotName: 'overDept', width: 120 },
  276. { prop: 'submitBy', label: '发起人', headerName: 'submitBy', width: 100 },
  277. { prop: 'forwardBy', label: `上节点提交人`, headerName: 'forwardBy', width: 100 },
  278. { prop: 'createTime', label: '上节点提交时间', width: 150 }
  279. ],
  280. over: [
  281. { prop: 'scope', label: '事务名称', slotName: 'name', width: 250 },
  282. { prop: 'scope', label: '事务说明', slotName: 'desc', minWidth: 250 },
  283. { prop: 'scope', label: '事务状态', slotName: 'overStatus', width: 120 },
  284. { prop: 'scope', label: '发起部门', slotName: 'overDept', width: 120 },
  285. { prop: 'scope', label: '发起人', headerName: 'submitBy', slotName: 'creator', width: 100 },
  286. { prop: 'scope', label: `提交人`, slotName: 'updateBy', width: 100 },
  287. { prop: 'scope', label: '办理时间', slotName: 'time', width: 150 }
  288. ],
  289. finish: [
  290. { prop: 'scope', label: '事务名称', slotName: 'name', width: 250 },
  291. { prop: 'scope', label: '事务说明', slotName: 'desc', minWidth: 250 },
  292. { prop: 'scope', label: '事务状态', slotName: 'overStatus', width: 120 },
  293. { prop: 'scope', label: '发起部门', slotName: 'overDept', width: 120 },
  294. { prop: 'scope', label: '发起人', headerName: 'submitBy', slotName: 'creator', width: 100 },
  295. { prop: 'scope', label: `提交人`, slotName: 'updateBy', width: 100 },
  296. { prop: 'scope', label: '结束时间', slotName: 'time', width: 150 }
  297. ],
  298. save: [
  299. { prop: 'scope', label: '事务名称', slotName: 'name', width: 250 },
  300. { prop: 'scope', label: '事务说明', slotName: 'desc', minWidth: 250 },
  301. { prop: 'createTime', label: '暂存时间', width: 150 }
  302. ],
  303. news: [
  304. { prop: 'title', label: '标题', minWidth: 250 },
  305. { prop: 'depName', label: '发布部门', sortable: 'custom', width: 120 },
  306. { prop: 'userName', label: '发布人', width: 120 },
  307. { prop: 'publicDate', label: '发布日期', sortable: 'custom', dateFormat: 'yyyy-MM-dd', width: 120 },
  308. { prop: 'loseDate', label: '有效截至日期', sortable: 'custom', dateFormat: 'yyyy-MM-dd', width: 120 },
  309. { prop: 'status', label: '发布状态', tags: typeOptions, width: 100 }
  310. ],
  311. guide: [
  312. { prop: 'sn', label: '序号', width: 60 },
  313. { prop: 'sysName', label: '所属子系统', width: 100 },
  314. { prop: 'module', label: '所属功能模块', width: fieldWidth },
  315. { prop: 'tableName', label: '记录表单', width: 200 },
  316. // { prop: 'tableNo', label: '表单编号', width: 100 },
  317. { prop: 'timing', label: '填写时机/记录频次', minWidth: fieldWidth },
  318. { prop: 'taskType', label: '事务类型', tags: taskTypeOptions, width: 100 },
  319. { prop: 'fileName', label: '程序文件', width: 160 },
  320. { prop: 'creator', label: '编制人', width: fieldWidth },
  321. { prop: 'reviewer', label: '审核人', width: fieldWidth },
  322. { prop: 'approver', label: '审批人', width: fieldWidth }
  323. ]
  324. }
  325. }
  326. }
  327. },
  328. mounted () {
  329. this.getData(this.activeTab)
  330. this.getOrgInfo()
  331. if (this.timer) {
  332. clearInterval(this.timer)
  333. }
  334. // 轮询刷新公告数据和任务数据
  335. this.timer = setInterval(() => {
  336. // this.getMessage()
  337. this.getData(this.activeTab)
  338. }, 30 * 1000)
  339. },
  340. beforeDestroy () {
  341. clearInterval(this.timer)
  342. },
  343. // 路由离开时
  344. beforeRouteLeave (to, from, next) {
  345. clearInterval(this.timer)
  346. },
  347. methods: {
  348. // 获取用户部门信息
  349. getOrgInfo () {
  350. const { org = {}} = this.$store.getters
  351. if (!org || !org.id) {
  352. return
  353. }
  354. const params = {
  355. parameters: [{ key: 'Q^MANAGER_ORG_ID_^S', value: org.id }]
  356. }
  357. queryOrgManager(params).then(res => {
  358. this.orgInfo = {}
  359. const data = res.data.dataResult
  360. if (data && data.length) {
  361. const { id, name, mobile, account, gender, groupID } = data[0]
  362. this.orgInfo = { id, name, mobile, account, gender, groupID, orgName: org.name }
  363. }
  364. })
  365. },
  366. getName ({ createBy, updateBy }) {
  367. const id = updateBy || createBy
  368. const { name = '' } = this.$store.getters || {}
  369. if (this.activeTab === 'finish') {
  370. const t = this.userList.find(i => i.userId === id)
  371. return t ? t.userName : ''
  372. }
  373. return name
  374. },
  375. getStatus (val) {
  376. const s = taskState[val]
  377. return s || '暂停'
  378. },
  379. getAttr (val, arg) {
  380. const arr = val.split('#')
  381. if (!arr[2]) {
  382. return ''
  383. }
  384. const result = JSON.parse(`{${arr[2]}}`)
  385. if (!result.dept) {
  386. return ''
  387. }
  388. const depts = result.dept.split(',')
  389. const deptNames = []
  390. depts.forEach(item => {
  391. const t = this.deptList.find(i => i.positionId === item)
  392. deptNames.push(t ? t.positionName : result.dept)
  393. })
  394. result.deptName = deptNames.join(',')
  395. return result[arg]
  396. },
  397. getDept (v, arg = 'positionName') {
  398. if (!v) {
  399. return ''
  400. }
  401. const t = this.deptList.find(i => i.positionId === v)
  402. return t ? t[arg] : ''
  403. },
  404. tableRowClassName ({ row, rowIndex }) {
  405. if (rowIndex % 2 === 1) return 'warning-row'
  406. return 'success-row'
  407. },
  408. // 获取表格数据
  409. getData (type) {
  410. this.loading = true
  411. const pageParams = this.pagination.page ? this.pagination : this.defaultPagination
  412. operate[this.activeTab](this.getFormatParams(null, pageParams)).then(response => {
  413. const { dataResult, pageResult } = response.data
  414. if (dataResult && dataResult.length) {
  415. // 待办事宜对任务发起人做额外处理
  416. if (type === 'wait') {
  417. const instList = []
  418. dataResult.forEach(item => {
  419. instList.push(item.bpmnInstId)
  420. })
  421. const sql = `select b.bpmn_inst_id_, b.create_by_, a.name_ from ibps_bpm_inst b left join ibps_party_employee a on a.id_ = b.create_by_ where b.bpmn_inst_id_ in (${instList.join(',')}) order by find_in_set(b.bpmn_inst_id_,'${instList.join(',')}')`
  422. const currentTime = Date.now()
  423. this.$common.request('sql', sql).then(res => {
  424. const data = res.variables && res.variables.data
  425. data.forEach((item, index) => {
  426. dataResult[index].submitBy = item.name_
  427. dataResult[index].workName = dataResult[index].subject.includes('#') ? dataResult[index].subject.split('#')[0] : dataResult[index].subject.split('(')[0]
  428. dataResult[index].workType = this.plan.includes(dataResult[index].procDefKey) ? 'plan' : 'normal'
  429. const limit = this.getAttr(dataResult[index].subject, 'loseDate') || this.getAttr(dataResult[index].subject, 'timeLimit') || 3
  430. dataResult[index].state = this.judgeExpire(dataResult[index].createTime, currentTime, dataResult[index].workType, limit, '1')
  431. })
  432. this.dataList = dataResult.sort((a, b) => b.createTime.localeCompare(a.createTime))
  433. this.pagination = pageResult
  434. })
  435. this.urgeToManager()
  436. } else {
  437. this.dataList = dataResult
  438. this.pagination = pageResult
  439. }
  440. }
  441. this.loading = false
  442. }).catch(() => {
  443. this.loading = false
  444. })
  445. },
  446. // 延迟更新列表数据
  447. updateList () {
  448. setTimeout(() => {
  449. this.getData(this.activeTab)
  450. }, 1000)
  451. },
  452. // 查询
  453. search () {
  454. this.dataList = []
  455. this.pagination = {}
  456. this.getData(this.activeTab)
  457. },
  458. handleChange (activeName, oldActiveName) {
  459. // this.$refs[oldActiveName][0].handleReset()
  460. },
  461. // 切换tab
  462. changeTab () {
  463. // 数据、筛选条件初始化
  464. this.dataList = []
  465. this.selection = []
  466. this.pagination = { }
  467. this.getData(this.activeTab)
  468. },
  469. handleSortChange (sort) {
  470. console.log(sort)
  471. ActionUtils.setSorts(this.sorts, sort)
  472. this.getData(this.activeTab)
  473. },
  474. handlePaginationChange (page) {
  475. ActionUtils.setPagination(this.pagination, page)
  476. this.getData(this.activeTab)
  477. },
  478. getFormatParams (v, page) {
  479. const params = this.$refs[this.activeTab] && this.$refs[this.activeTab].length ? this.$refs[this.activeTab][0].getSearcFormData() : {}
  480. if (this.activeTab === 'finish') {
  481. params.end = '1'
  482. }
  483. if (this.activeTab === 'news') {
  484. // 公告限制显示当前医院且状态为已发布的数据,过滤草稿及失效公告
  485. params['Q^type_^SL'] = this.level
  486. params['Q^status_^SL'] = 'publish'
  487. }
  488. let pageParams
  489. if (this.activeTab === 'guide') {
  490. pageParams = { ...page, limit: 100 }
  491. } else {
  492. pageParams = page
  493. }
  494. // const s = this.activeTab === 'news' ? this.sorts { 'PUBLIC_DATE_': 'DESC' } : this.sorts
  495. return ActionUtils.formatParams(params, pageParams, this.sorts)
  496. },
  497. // 处理表格点击事件
  498. handleRowClick (data) {
  499. if (this.activeTab === 'guide') {
  500. return
  501. }
  502. if (this.activeTab === 'news') {
  503. this.newsId = data.id
  504. this.newsDialogVisible = true
  505. this.newsTitle = data.title
  506. return
  507. }
  508. this.taskId = data.id || ''
  509. this.waiJian = data.waiJian || ''
  510. this.instanceId = data.id || ''
  511. this.defId = data.procDefId || ''
  512. this.proInstId = data.id || ''
  513. this.FlowName = data.name
  514. this.dialogFormVisible = true
  515. },
  516. handleAction (command, position, selection, data) {
  517. switch (command) {
  518. case 'search':// 查询
  519. ActionUtils.setFirstPagination(this.pagination)
  520. this.search()
  521. break
  522. case 'remove':// 删除
  523. ActionUtils.removeRecord(selection).then((ids) => {
  524. console.log(ids)
  525. this.handleRemove(ids)
  526. }).catch(() => { })
  527. break
  528. default:
  529. break
  530. }
  531. },
  532. // 删除暂存数据
  533. handleRemove (ids) {
  534. removeDraft({ ids }).then(() => {
  535. ActionUtils.removeSuccessMessage()
  536. this.selection = []
  537. this.search()
  538. })
  539. },
  540. // 数组去重
  541. unique (arr) {
  542. const res = new Map()
  543. return arr.filter(arr => !res.has(arr.id) && res.set(arr.id, 1))
  544. },
  545. /**
  546. * 主管提醒
  547. * 数据处理,将所有待办数据根据是否过期处理为两个数组
  548. * 过期判断依据:普通事务-创建时间到当前时间超过三天即为过期;计划事务【事务名称中含计划】-创建当月月末前七天
  549. * 逻辑说明:过期数组中不存于在主管提醒表中的数据插入主管提醒表,并发送内部通知,主管提醒表删除不存在于未过期数组中的数据
  550. */
  551. urgeToManager () {
  552. const { userId } = this.$store.getters
  553. const params = {
  554. parameters: [],
  555. sorts: []
  556. }
  557. const sql = `select id_, shi_wu_id_ as taskId from t_gqswb where position('${userId}' in chu_li_ren_id_)`
  558. // Promise.all([pending(params), this.$common.request('sql', sql)]).then(([res1, res2]) => {
  559. // let workData = res1.data && res1.data.dataResult
  560. // let noticeData = res2.variables && res2.variables.data
  561. // if (!workData || !workData.length) {
  562. // return
  563. // }
  564. // this.dealData(workData, noticeData)
  565. // })
  566. pending(params).then(res1 => {
  567. const workData = res1.data && res1.data.dataResult
  568. this.$common.request('sql', sql).then(res2 => {
  569. const noticeData = res2.variables && res2.variables.data
  570. if (!workData || !workData.length) {
  571. return
  572. }
  573. this.dealData(workData, noticeData)
  574. })
  575. })
  576. },
  577. // 处理数据
  578. dealData (workList, noticeList) {
  579. const result = {
  580. expire: [],
  581. unexpire: [],
  582. all: []
  583. }
  584. const currentTime = Date.now()
  585. // 筛选已过期数据
  586. workList.forEach(item => {
  587. // 截取流程名
  588. item.workName = item.subject.includes('#') ? item.subject.split('#')[0] : item.subject.split('(')[0]
  589. item.workType = this.plan.includes(item.procDefKey) ? 'plan' : 'normal'
  590. item.deptId = this.getAttr(item.subject, 'dept')
  591. const limit = this.getAttr(item.subject, 'loseDate') || this.getAttr(item.subject, 'timeLimit')
  592. const isExpire = this.judgeExpire(item.createTime, currentTime, item.workType, limit)
  593. if (isExpire) {
  594. result.expire.push(item)
  595. } else {
  596. result.unexpire.push(item)
  597. }
  598. result.all.push(item)
  599. })
  600. // console.log('处理后数据:', result)
  601. // 有过期数据才执行过期数据处理
  602. if (result.expire.length) {
  603. this.dealExpile(result.expire, noticeList)
  604. }
  605. // 主管提醒表中有数据才执行数据删除
  606. if (noticeList && noticeList.length) {
  607. this.dealUnexpile(result.all, noticeList)
  608. }
  609. },
  610. /**
  611. * 判断是否过期、获取办理状态
  612. * @param {string} time 比较时间
  613. * @param {number} current 当前时间戳
  614. * @param {string} type 事务类型
  615. * @param {string} limit 限时,值分为两种类型,传值为字符串格式的时间时,判定逻辑为当前时间小于该时间,传值为字符串类型数字时,判定逻辑为创建limit天后,大于当前时间
  616. * @param {string} isState 调用类型
  617. */
  618. judgeExpire (time, current, type, limit, isState) {
  619. const D = new Date(time)
  620. const a = new Date(time).getTime()
  621. const b = new Date(current).getTime()
  622. const l = limit || 3
  623. // 创建时间当月最后一天的时间戳
  624. const c = new Date(D.getFullYear(), D.getMonth() + 1, 0).getTime() + 86400000
  625. const isDate = l.toString().includes('-')
  626. // 返回办理状态
  627. if (isState) {
  628. let state = ''
  629. if (type === 'plan') {
  630. const M = isDate ? new Date(l).getTime() : c
  631. state = b >= M ? 'overtime' : b + (86400000 * 7) > M ? 'soon' : 'wait'
  632. } else {
  633. if (isDate) {
  634. const L = new Date(l).getTime()
  635. state = b >= L ? 'overtime' : 'wait'
  636. } else {
  637. state = a + (86400000 * parseInt(l)) < b ? 'overtime' : 'wait'
  638. }
  639. }
  640. return state
  641. }
  642. // 返回是否过期
  643. if (isDate) {
  644. return b + (86400000 * 7) > new Date(l).getTime()
  645. }
  646. if (type === 'plan') {
  647. return b + (86400000 * 7) > c
  648. } else {
  649. return a + (86400000 * parseInt(l)) < b
  650. }
  651. },
  652. // 处理已过期数据
  653. dealExpile (data, noticeList) {
  654. // console.log('已过期流程数据:', data)
  655. // console.log('过期事务表数据:', noticeList)
  656. const { userId } = this.$store.getters
  657. const addList = []
  658. const sendList = []
  659. const msgContent = {
  660. plan: '距离超时还剩七天,请及时处理!',
  661. normal: '至今三天未处理,已超时,请及时处理!'
  662. }
  663. const msgTitle = {
  664. plan: '计划事务即将到期提醒',
  665. normal: '事务超时提醒'
  666. }
  667. const nowTime = new Date(new Date().getTime() + 28800000).toJSON().slice(0, 16).replace('T', ' ')
  668. data.forEach(item => {
  669. const isExist = !!noticeList.find(i => i.taskId === item.taskId)
  670. // 筛选出不存在于主管提醒表的过期数据
  671. if (!isExist) {
  672. const obj = {
  673. // 事务ID
  674. shi_wu_id_: item.taskId,
  675. // 完整名称
  676. wan_zheng_ming_ch: item.subject,
  677. // 事务说明
  678. shi_wu_shuo_ming_: item.subject.includes('#') ? item.subject.split('#')[1] : '',
  679. // 事务名称
  680. shi_wu_ming_cheng: item.workName,
  681. // 事务状态
  682. shi_wu_zhuang_tai: `待${item.name}`,
  683. // 事务类型
  684. shi_wu_lei_xing_: item.workType,
  685. chu_li_ren_ming_: item.ownerName,
  686. chu_li_ren_id_: this.getInfoByName(item.ownerName, 'id'),
  687. chu_li_ren_dian_h: this.getInfoByName(item.ownerName, 'phone'),
  688. bu_men_: this.getDept(item.deptId),
  689. bu_men_id_: item.deptId,
  690. zhu_guan_id_: this.getDept(item.deptId, 'managerId'),
  691. zhu_guan_dian_hua: this.getInfoByName(this.getDept(item.deptId, 'manager'), 'phone'),
  692. bian_zhi_shi_jian: item.createTime,
  693. ti_xing_ci_shu_: 1,
  694. duan_xin_ci_shu_: 0,
  695. ti_xing_shi_jian_: nowTime
  696. }
  697. addList.push(obj)
  698. const msg = {
  699. subject: msgTitle[item.workType],
  700. content: `事务【${item.workName}】${msgContent[item.workType]}`,
  701. receiverId: userId,
  702. canreply: '0',
  703. taskId: item.taskId
  704. }
  705. sendList.push(msg)
  706. }
  707. })
  708. const addParams = {
  709. tableName: 't_gqswb',
  710. paramWhere: addList
  711. }
  712. // console.log('新增过期事务表数据:', addList, '发送消息数据', sendList)
  713. if (addList.length) {
  714. this.$common.request('add', addParams)
  715. }
  716. if (sendList.length) {
  717. this.sendMsg(sendList)
  718. }
  719. },
  720. // 删除已办的提醒表数据
  721. dealUnexpile (data, noticeList) {
  722. // 清除存在于主管提醒表中【处理人含我】,但是不存在于待办中的数据
  723. const deleteList = []
  724. noticeList.forEach(item => {
  725. const isExist = !!data.find(i => i.taskId === item.taskId)
  726. if (!isExist) {
  727. deleteList.push(item.id_)
  728. }
  729. })
  730. // console.log('过期事务表中需删除的数据:', deleteList)
  731. if (!deleteList.length) {
  732. return
  733. }
  734. const params = {
  735. tableName: 't_gqswb',
  736. paramWhere: {
  737. id_: deleteList.join(',')
  738. }
  739. }
  740. this.$common.request('delete', params).then(() => {}).catch(err => {
  741. console.log(err)
  742. })
  743. },
  744. // 发送站内消息
  745. sendMsg (data) {
  746. data.forEach(item => {
  747. save(item).then(() => {}).catch(err => {
  748. console.log(err)
  749. })
  750. })
  751. },
  752. // 通过名字获取id/电话
  753. getInfoByName (names, type) {
  754. const res = {
  755. id: [],
  756. phone: []
  757. }
  758. const temp = names.split(',')
  759. temp.forEach(item => {
  760. const t = this.userList.find(i => i.userName === item)
  761. if (t) {
  762. res.id.push(t.userId)
  763. res.phone.push(t.phone)
  764. }
  765. })
  766. return res[type].filter(i => i).join(',')
  767. }
  768. }
  769. }
  770. </script>
  771. <style lang="scss" scoped>
  772. ::v-deep .el-table__row {
  773. cursor: pointer;
  774. }
  775. ::v-deep .el-tabs__header {
  776. margin-bottom: 0;
  777. }
  778. .el-completing {
  779. background: #409eff !important;
  780. }
  781. .el-col {
  782. min-height: 1px;
  783. }
  784. .firstcol {
  785. padding-right: 10px;
  786. }
  787. .el-nothing {
  788. font-size: 13px;
  789. }
  790. .calendar-day {
  791. text-align: center;
  792. color: #202535;
  793. line-height: 30px;
  794. font-size: 12px;
  795. }
  796. .is-selected {
  797. color: #f8a535;
  798. font-size: 10px;
  799. margin-top: 5px;
  800. }
  801. #calendar .el-button-group > .el-button:not(:first-child):not(:last-child):after {
  802. content: '当月';
  803. }
  804. #calendar .item {
  805. position: relative;
  806. margin: 0;
  807. padding: 0;
  808. height: auto;
  809. border-radius: 4px;
  810. -webkit-box-sizing: border-box;
  811. box-sizing: border-box;
  812. overflow: hidden;
  813. color: #f8a535;
  814. }
  815. .ibps-list-split .ibps-list-item {
  816. border-bottom: 1px solid #dcdfe6;
  817. padding: 6px 0;
  818. }
  819. .jbd-font-style {
  820. font-weight: bold;
  821. }
  822. .home-text-border {
  823. color: #999999;
  824. box-shadow: 0 0 0 0 rgba(0, 0, 0, 0.1), 0 0 0 0 rgba(0, 0, 0, 0.1), 0 0 0 0 rgba(0, 0, 0, 0.1), 0 1px 0px 0 rgba(0, 0, 0, 0.1);
  825. min-height: 20px;
  826. font-size: 14px;
  827. margin-left: 60px;
  828. margin-bottom: 5px;
  829. }
  830. .jbd-home-card {
  831. overflow: auto;
  832. }
  833. .jbd-home-task {
  834. width: 100%;
  835. padding: 10px;
  836. cursor: pointer;
  837. font-size: 12px;
  838. margin-bottom: 35px;
  839. }
  840. .jbd-home-card::-webkit-scrollbar {
  841. display: none;
  842. }
  843. .jbd-control-cont {
  844. text-align: center;
  845. position: absolute;
  846. z-index: 10;
  847. right: 0px;
  848. top: 50%;
  849. }
  850. .tab-container {
  851. height: calc(100vh - 160px);
  852. min-height: 600px;
  853. >div {
  854. display: inline-block;
  855. }
  856. .table-container {
  857. width: 100%;
  858. vertical-align: top;
  859. }
  860. }
  861. </style>