综合办公系统
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

index.vue 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563
  1. <!--
  2. * @Author: ysh
  3. * @Date: 2024-01-03 09:23:11
  4. * @LastEditors: wrh
  5. * @LastEditTime: 2025-02-28 09:16:34
  6. -->
  7. <template>
  8. <div class="app-container home">
  9. <el-row :gutter="20">
  10. <el-col :span="6" :xs="24">
  11. <div class="header">个人信息</div>
  12. <div class="user-wrapper">
  13. <div class="avatar">
  14. <img :src="avatar" class="user-avatar" />
  15. </div>
  16. <div class="username">
  17. <div>{{ user.nickName }}</div>
  18. <div style="font-size: 14px;color:#bbb;font-weight:lighter;">
  19. <el-tag type="warning">{{ post.length == 0 ? '未设置职位' : post.join(' / ') }}</el-tag>
  20. </div>
  21. </div>
  22. <div class="user-info">
  23. <el-row :gutter="20" style="margin:10px">
  24. <el-col :span="10" style="text-align: right;">所属部门:</el-col>
  25. <el-col :span="14" style="text-align: left;">{{ user.dept.deptName }}</el-col>
  26. </el-row>
  27. <el-row :gutter="20">
  28. <el-col :span="10" style="text-align: right;">技术职称:</el-col>
  29. <el-col :span="14" style="text-align: left;">{{ user.titles }}</el-col>
  30. </el-row>
  31. </div>
  32. </div>
  33. </el-col>
  34. <el-col :span="18" :xs="24">
  35. <div class="header">快捷入口</div>
  36. <div class="nav-wrapper">
  37. <div class="nav-item" v-for="nav in navItem" @click="goToPath(nav.path)" v-hasPermi="nav.privilege">
  38. <el-badge :value="formartBadge(nav.id)" :max="99" class="item">
  39. <div class="nav-logo" :style="{ 'background-color': nav.bgColor, 'box-shadow': nav.boxShadow }">
  40. <div class="icon">
  41. <svg-icon slot="prefix" :icon-class="nav.icon" class="el-input__icon input-icon" />
  42. </div>
  43. </div>
  44. </el-badge>
  45. <div class="nav-text">{{ nav.name }}</div>
  46. </div>
  47. </div>
  48. </el-col>
  49. </el-row>
  50. <el-row :gutter="20">
  51. <el-col :span="10" :xs="24">
  52. <div class="header">通知公示</div>
  53. <div class="notice-content">
  54. <el-table v-loading="noticeLoading" :data="noticeList" height="320px">
  55. <!-- <el-table-column label="序号" align="center" prop="noticeId" width="100" /> -->
  56. <el-table-column label="类型" align="center" prop="noticeType" width="100">
  57. <template slot-scope="scope">
  58. <dict-tag :options="dict.type.sys_notice_type" :value="scope.row.noticeType" />
  59. </template>
  60. </el-table-column>
  61. <el-table-column label="标题" align="center" prop="noticeTitle" :show-overflow-tooltip="true" />
  62. <el-table-column label="创建者" align="center" prop="createBy" width="100" />
  63. <el-table-column label="创建时间" align="center" prop="createTime" width="100">
  64. <template slot-scope="scope">
  65. <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
  66. </template>
  67. </el-table-column>
  68. <el-table-column label="操作" width="90" align="center">
  69. <template slot-scope="scope">
  70. <el-button size="mini" type="text" icon="el-icon-view"
  71. @click="handleRowClick(scope.row)">查看详情</el-button>
  72. </template>
  73. </el-table-column>
  74. </el-table>
  75. <div style="text-align: right;margin-top: 20px;">
  76. <el-pagination @current-change="getNotice" :current-page.sync="noticeQueryParams.pageNum"
  77. :page-size="noticeQueryParams.pageSize" layout="total, prev, pager, next,jumper" :total="noticeTotal">
  78. </el-pagination>
  79. </div>
  80. </div>
  81. </el-col>
  82. <el-col :span="14" :xs="24">
  83. <div class="header">待办任务</div>
  84. <div class="calendar-warpper">
  85. <el-table v-loading="taskLoading" :data="todoList" height="400px">
  86. <el-table-column type="index" label="序号" width="55" align="center" />
  87. <el-table-column label="流程名称" align="center" prop="procDefName" />
  88. <el-table-column label="标题" align="center" prop="title" show-overflow-tooltip />
  89. <el-table-column label="当前节点" align="center" prop="taskName" />
  90. <el-table-column label="流程发起人" align="center">
  91. <template slot-scope="scope">
  92. <label>{{ scope.row.startUserName }} <el-tag type="info" size="mini">{{ scope.row.startDeptName
  93. }}</el-tag></label>
  94. </template>
  95. </el-table-column>
  96. <el-table-column label="接收时间" align="center" prop="createTime" width="180" />
  97. <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
  98. <template slot-scope="scope">
  99. <el-button size="mini" type="text" icon="el-icon-edit-outline" @click="handleProcess(scope.row)">处理
  100. </el-button>
  101. </template>
  102. </el-table-column>
  103. </el-table>
  104. </div>
  105. </el-col>
  106. </el-row>
  107. <el-dialog title="" :visible.sync="noticeOpen" width="750px" append-to-body>
  108. <h2 class="text-center">{{ clickNotice.noticeTitle }}</h2>
  109. <div class="pre-formatted" v-html="clickNotice.noticeContent"></div>
  110. </el-dialog>
  111. </div>
  112. </template>
  113. <script>
  114. import { mapGetters } from "vuex";
  115. import { getUserProfile, getUser } from "@/api/system/user";
  116. import { listProject } from "@/api/oa/project/project";
  117. import { todoList } from "@/api/flowable/todo";
  118. import { finishedList } from "@/api/flowable/finished";
  119. import Calendar from '@/components/Calendar';
  120. import { listNotice } from "@/api/system/notice";
  121. import { getProcessVariables } from "@/api/flowable/definition"
  122. export default {
  123. dicts: ['sys_notice_status', 'sys_notice_type'],
  124. components: {
  125. Calendar
  126. },
  127. computed: {
  128. ...mapGetters(["avatar", "userId"]),
  129. },
  130. created() {
  131. this.getUserbyId();
  132. this.getDetail();
  133. this.getProject();
  134. this.getNotice();
  135. },
  136. data() {
  137. return {
  138. noticeOpen: false,
  139. times: new Date(),
  140. user: {
  141. dept: {}
  142. },
  143. post: [],
  144. noticeData: [],
  145. projectData: [],
  146. noticeList: [],// 数据
  147. noticeTotal: 0,
  148. clickNotice: {},
  149. todoList: [],
  150. noticeLoading: true,
  151. taskLoading: true,
  152. noticeQueryParams: {
  153. pageNum: 1,
  154. pageSize: 10
  155. },
  156. projectQueryParams: {
  157. pageNum: 1,
  158. pageSize: 16
  159. },
  160. projectTotal: 0,
  161. detail: 0,
  162. finish: 0,
  163. engineerLevel: '',
  164. titles: '',
  165. navItem: [
  166. {
  167. id: 1,
  168. name: '发起流程',
  169. icon: 'cascader',
  170. bgColor: '#785aee',
  171. boxShadow: '0 5px 20px rgba(120,90,238,0.5)',
  172. path: '/task/process',
  173. privilege: ['system:deployment:add']
  174. }, {
  175. id: 2,
  176. name: '待办任务',
  177. icon: 'log',
  178. bgColor: '#e66794',
  179. boxShadow: '0 5px 20px rgba(230,103,148,0.5)',
  180. path: '/task/todo',
  181. privilege: ['system:deployment:add']
  182. }, {
  183. id: 3,
  184. name: '已办任务',
  185. icon: 'excel',
  186. bgColor: '#6389f4',
  187. boxShadow: '0 5px 20px rgba(99,137,244,0.5)',
  188. path: '/task/finished',
  189. privilege: ['system:deployment:add']
  190. }, {
  191. id: 4,
  192. name: '项目台账',
  193. icon: 'dict',
  194. bgColor: '#e64c56',
  195. boxShadow: '0 5px 20px rgba(230,76,86,0.5)',
  196. path: '/product/account/project',
  197. privilege: ['oa:project:query']
  198. }, {
  199. id: 5,
  200. name: '车辆管理',
  201. icon: 'car',
  202. bgColor: '#eeb62f',
  203. boxShadow: '0 5px 20px rgba(238,182,47,0.5)',
  204. path: '/oa/car/index',
  205. privilege: ['oa:car:list']
  206. }, {
  207. id: 6,
  208. name: '设备管理',
  209. icon: 'lock',
  210. bgColor: '#0be1bd',
  211. boxShadow: '0 5px 20px rgba(11,225,189,0.5)',
  212. path: '/oa/device/equipment',
  213. privilege: ['oa:device:list']
  214. }, {
  215. id: 7,
  216. name: '承接合同',
  217. icon: 'contractSign',
  218. bgColor: '#F7C59F',
  219. boxShadow: '0 5px 20px rgba(247,197,159,0.5)',
  220. path: '/business/contract/contract',
  221. privilege: ['oa:contract:list']
  222. }, {
  223. id: 8,
  224. name: '人事管理',
  225. icon: 'dept',
  226. bgColor: '#20B2AA',
  227. boxShadow: '0 5px 20px rgba(32,178,170,0.5)',
  228. path: '/oa/staff/people',
  229. privilege: ['oa:salary:list']
  230. },{
  231. id: 9,
  232. name: '项目结算',
  233. icon: 'settle',
  234. bgColor: '#ff6f61',
  235. boxShadow: '0 5px 20px rgba(255,111,97,0.5)',
  236. path: '/product/settle/project',
  237. privilege: ['oa:settle:list']
  238. },{
  239. id: 10,
  240. name: '借款管理',
  241. icon: 'borrow',
  242. bgColor: '#001a6e',
  243. boxShadow: '0 5px 20px rgba(0,26,110,0.5)',
  244. path: '/product/budget/borrow',
  245. privilege: ['oa:borrow:list']
  246. },
  247. // {
  248. // id: 9,
  249. // name: '预算管理',
  250. // icon: 'form',
  251. // bgColor: '#E64A19',
  252. // boxShadow: '0 5px 20px rgba(230,74,25,0.5)',
  253. // path: '/budget'
  254. // }
  255. ]
  256. }
  257. },
  258. methods: {
  259. goToPath(path) {
  260. this.$router.push({ path: path });
  261. },
  262. getUserbyId() {
  263. getUser(this.userId).then(response => {
  264. this.user = response.data;
  265. for (let p of response.posts) {
  266. for (let ids of response.postIds) {
  267. if (p.postId == ids) {
  268. this.post.push(p.postName)
  269. }
  270. }
  271. }
  272. this.getDicts("sys_user_titles").then(res => {
  273. if (this.user.titles != "" && this.user.titles != null && this.user.titles != undefined) {
  274. let titles = this.user.titles.split(',');
  275. let arr = []
  276. for (let t of titles) {
  277. arr.push(res.data[t].dictLabel)
  278. }
  279. this.user.titles = arr.join(' / ')
  280. }
  281. })
  282. });
  283. },
  284. // 获取项目列表
  285. getProject() {
  286. listProject(this.projectQueryParams).then(response => {
  287. this.projectData = response.rows;
  288. this.projectTotal = response.total;
  289. })
  290. },
  291. // 获取考核待办
  292. getDetail() {
  293. this.taskLoading = true;
  294. todoList({
  295. pageNum: 1,
  296. pageSize: 999,
  297. name: null
  298. }).then(response => {
  299. this.detail = response.data.total;
  300. this.todoList = response.data.records;
  301. this.taskLoading = false;
  302. });
  303. },
  304. getFinish() {
  305. finishedList({
  306. pageNum: 1,
  307. pageSize: 10,
  308. name: null,
  309. category: null,
  310. key: null,
  311. tenantId: null,
  312. deployTime: null,
  313. derivedFrom: null,
  314. derivedFromRoot: null,
  315. parentDeploymentId: null,
  316. engineVersion: null
  317. }).then(response => {
  318. this.finish = response.data.total;
  319. })
  320. },
  321. // 获取列表
  322. getNotice() {
  323. listNotice(this.noticeQueryParams).then(response => {
  324. this.noticeList = response.rows;
  325. this.noticeTotal = response.total;
  326. this.noticeLoading = false;
  327. });
  328. },
  329. formartBadge(id) {
  330. if (id == 2) {
  331. return this.detail
  332. } else {
  333. return null
  334. }
  335. },
  336. handleRowClick(row) {
  337. this.clickNotice = row;
  338. this.clickNotice.noticeContent = this.format(row.noticeContent);
  339. this.noticeOpen = true;
  340. },
  341. format(html) {
  342. var GRT = [
  343. // img 样式
  344. ['img', "max-width:100%;height:auto;"],
  345. ];
  346. for (let i = 0; i < GRT.length; i++) {
  347. html = html.replace(new RegExp('<' + GRT[i][0] + '>|<' + GRT[i][0] + ' (.*?)>', 'gi'), function (word) {
  348. // 分析 dom 上是否带有 style=""
  349. if (word.indexOf('style=') != -1) {
  350. var regIn = new RegExp('<' + GRT[i][0] + '(.*?)style="(.*?)"(.*?)(/?)>', 'gi');
  351. return word.replace(regIn, '<' + GRT[i][0] + '$1style="$2 ' + GRT[i][1] + '"$3$4>');
  352. } else {
  353. var regIn = new RegExp('<' + GRT[i][0] + '(.*?)(/?)>', 'gi');
  354. return word.replace(regIn, '<' + GRT[i][0] + '$1 style="' + GRT[i][1] + '$2">');
  355. }
  356. });
  357. }
  358. return html;
  359. },
  360. handleProcess(row) {
  361. let path = this.getRoutePath(row);
  362. getProcessVariables(row.taskId).then(res => {
  363. this.$router.push({
  364. path: path,
  365. query: {
  366. procInsId: row.procInsId,
  367. executionId: row.executionId,
  368. deployId: row.deployId,
  369. taskId: row.taskId,
  370. taskName: row.taskName,
  371. startUser: row.startUserName + '-' + row.startDeptName,
  372. formId: res.data.formId,
  373. procDefName: row.procDefName
  374. }
  375. })
  376. })
  377. },
  378. getRoutePath(row) {
  379. let path;
  380. for (let p of this.publicData.pathRoute) {
  381. if (p.name == row.procDefName) {
  382. path = p.path
  383. break
  384. } else {
  385. path = '/flowable/task/todo/detail/index'
  386. }
  387. }
  388. return path
  389. }
  390. }
  391. }
  392. </script>
  393. <style scoped lang="scss">
  394. .home {
  395. padding: 20px 40px;
  396. background-color: #f0f4f7;
  397. width: 100%;
  398. // height: calc(100vh - 100px);
  399. }
  400. .header {
  401. font-size: 20px;
  402. line-height: 60px;
  403. }
  404. .nav-wrapper {
  405. display: flex;
  406. flex-wrap: wrap;
  407. gap: 15px;
  408. .nav-item {
  409. background-color: #ffffff;
  410. // max-width: 240px;
  411. // width: 220px;
  412. flex-grow: 1;
  413. height: 120px;
  414. border-radius: 10px;
  415. display: flex;
  416. align-items: center;
  417. padding: 0 30px;
  418. margin-bottom: 10px;
  419. .nav-logo {
  420. width: 55px;
  421. height: 55px;
  422. border-radius: 10px;
  423. margin-right: 20px;
  424. text-align: center;
  425. line-height: 55px;
  426. .icon {
  427. font-size: 27px;
  428. color: #ffffff;
  429. }
  430. }
  431. .nav-text {
  432. font-size: 18px;
  433. }
  434. }
  435. .nav-item:hover {
  436. cursor: pointer;
  437. box-shadow: 0 0 15px rgba($color: #242d42, $alpha: 0.1);
  438. }
  439. }
  440. .user-wrapper {
  441. background-color: #ffffff;
  442. height: 267px;
  443. border-radius: 10px;
  444. .avatar {
  445. text-align: center;
  446. // padding: 10px 0;
  447. .user-avatar {
  448. width: 100px;
  449. height: 100px;
  450. border-radius: 50%;
  451. }
  452. }
  453. .username {
  454. text-align: center;
  455. font-size: 18px;
  456. font-weight: bold;
  457. font-family: '微软雅黑';
  458. }
  459. .user-info {
  460. text-align: center;
  461. table {
  462. margin: 0 auto;
  463. }
  464. }
  465. }
  466. .notice-content {
  467. width: 100%;
  468. height: 400px;
  469. background-color: #ffffff;
  470. border-radius: 15px;
  471. padding: 20px 15px 0;
  472. }
  473. .calendar-warpper {
  474. padding: 10px;
  475. width: 100%;
  476. height: 400px;
  477. background-color: #ffffff;
  478. border-radius: 15px;
  479. }
  480. .project-content {
  481. width: 100%;
  482. height: 400px;
  483. background-color: #ffffff;
  484. border-radius: 15px;
  485. }
  486. .pre-formatted {
  487. white-space: pre-wrap;
  488. /* css-2.1, curent FF, Opera, Safari */
  489. word-wrap: break-word;
  490. /* Internet Explorer 5.5+ */
  491. p {
  492. width: 100% !important;
  493. height: 100% !important;
  494. img {
  495. width: 100%;
  496. height: 100%;
  497. }
  498. }
  499. }
  500. ::v-deep .el-calendar-table .el-calendar-day {
  501. height: 39px;
  502. text-align: center;
  503. line-height: 26px;
  504. }
  505. ::v-deep .el-calendar-table .el-calendar-day:hover {
  506. color: #242d42;
  507. }
  508. ::v-deep .el-calendar__body {
  509. padding: 15px 31px 10px;
  510. }
  511. ::v-deep .el-calendar__header {
  512. padding: 20px;
  513. }
  514. ::v-deep .el-calendar-table td.is-today {
  515. background-color: #1890ff;
  516. border-radius: 10px;
  517. color: #ffffff;
  518. box-shadow: 0 0 10px rgba($color: #1890ff, $alpha: 0.2);
  519. }
  520. ::v-deep .el-calendar-table td.is-selected {
  521. // color: #242d42;
  522. }
  523. ::v-deep .el-calendar-table td {
  524. border-right: none;
  525. }
  526. ::v-deep .el-table .el-table__header-wrapper th,
  527. .el-table .el-table__fixed-header-wrapper th {
  528. background-color: #ffffff;
  529. }
  530. </style>