Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 
 
 
 

773 lignes
20 KiB

  1. <template>
  2. <view id="home" class="page">
  3. <!-- 顶部搜索栏 -->
  4. <view class="header text-white">
  5. <!-- #ifndef H5 -->
  6. <l-icon
  7. @click="scanClick"
  8. type="scan"
  9. color="white"
  10. class="header-left text-xxl margin-left-sm"
  11. />
  12. <!-- #endif -->
  13. <view @click="moreClick(1)" class="search header-mid margin-lr-sm">
  14. <l-icon type="search" color="white" class="margin-lr-sm" />
  15. 搜索更多应用
  16. </view>
  17. <!-- <l-icon
  18. @click="msgClick"
  19. type="mail"
  20. color="white"
  21. class="header-right text-xxl margin-right-sm"
  22. /> -->
  23. </view>
  24. <!-- 轮播图片 -->
  25. <swiper v-if="imgCount > 0" style="height: 120px">
  26. <swiper-item
  27. v-for="(item, index) of imgData"
  28. :key="index"
  29. style="height: 120px"
  30. >
  31. <image
  32. :src="item"
  33. mode="aspectFill"
  34. style="height: 100%; width: 100%"
  35. ></image>
  36. </swiper-item>
  37. </swiper>
  38. <!-- 功能宫格列表 -->
  39. <view class="col-4 function-list cu-list grid no-border">
  40. <view
  41. v-for="(item, index) in funcListDisplay"
  42. @click="funcListClick(item)"
  43. :key="index"
  44. class="cu-item text-center flex flex-wrap justify-center align-center"
  45. >
  46. <view
  47. class="app-item align-center flex flex-wrap justify-center align-center"
  48. style="position: relative;"
  49. >
  50. <l-icon :type="item.icon" color="white" class="text-sl" />
  51. <view v-if="item.F_Name == '我的审批'&&CornerMarker" class="CornerMarker">
  52. {{CornerMarker}}
  53. </view>
  54. </view>
  55. <text>{{ item.F_Name }}</text>
  56. </view>
  57. </view>
  58. <view class="text-center bg-white margin-bottom"
  59. ><text
  60. @click="moreClick(0)"
  61. class="function-more-btn margin-tb-sm text-gray"
  62. >更多应用</text
  63. ></view
  64. >
  65. <!-- 统计数据宫格 -->
  66. <l-title>统计数据</l-title>
  67. <view class="count-list cu-list grid col-3 margin-bottom">
  68. <view
  69. v-for="(item, index) in countData"
  70. :key="index"
  71. class="cu-item text-center"
  72. >
  73. <text class="margin-bottom-xs">{{ item.title || "(未命名)" }}</text>
  74. <text class="count-item-value">{{ item.value || "-" }}</text>
  75. </view>
  76. </view>
  77. <!-- 通知列表区块 -->
  78. <view
  79. v-for="(block, blockIndex) of noticeData"
  80. :key="blockIndex"
  81. class="margin-bottom"
  82. >
  83. <!-- <view class="margin-top"></view> -->
  84. <l-title @click="informClick(block.title)">{{ block.title }}</l-title>
  85. <l-list>
  86. <l-list-item
  87. v-for="(item, i) of block.content"
  88. @click="noticeClick(item)"
  89. :key="i"
  90. arrow
  91. >
  92. {{ item.f_title || "(无标题)" }}
  93. <l-tag slot="action" line="gray">{{
  94. postDateTime(item.f_time)
  95. }}</l-tag>
  96. </l-list-item>
  97. </l-list>
  98. </view>
  99. <!-- 图表区块 -->
  100. <view v-for="item of chartData" :key="item.id" class="margin-bottom">
  101. <l-title>{{ item.title }}</l-title>
  102. <view
  103. :style="{ width: cWidth + 'px', height: cHeight + 'px' }"
  104. class="chart-list"
  105. >
  106. <!--#ifndef MP-ALIPAY -->
  107. <canvas
  108. v-if="item.type === 1"
  109. @tap="chartTap(item, $event)"
  110. @touchstart="touchStart(item.id, $event)"
  111. @touchmove="touchMove(item.id, $event)"
  112. @touchend="touchEnd(item.id, $event)"
  113. :style="{ width: cWidth + 'px', height: cHeight + 'px' }"
  114. :canvas-id="item.id"
  115. :id="item.id"
  116. class="charts"
  117. ></canvas>
  118. <canvas
  119. v-else
  120. @tap="chartTap(item, $event)"
  121. :style="{ width: cWidth + 'px', height: cHeight + 'px' }"
  122. :canvas-id="item.id"
  123. :id="item.id"
  124. class="charts"
  125. ></canvas>
  126. <!--#endif -->
  127. <!-- 阿里小程序,需要以2倍尺寸显示,然后缩放为50% -->
  128. <!--#ifdef MP-ALIPAY -->
  129. <canvas
  130. v-if="item.type === 1"
  131. @tap="chartTap(item, $event)"
  132. @touchstart="touchStart(item.id, $event)"
  133. @touchmove="touchMove(item.id, $event)"
  134. @touchend="touchEnd(item.id, $event)"
  135. :style="{
  136. width: cWidth * pixelRatio + 'px',
  137. height: cHeight * pixelRatio + 'px',
  138. transform: 'scale(' + 1 / pixelRatio + ')',
  139. marginLeft: (-cWidth * (pixelRatio - 1)) / 2 + 'px',
  140. marginTop: (-cHeight * (pixelRatio - 1)) / 2 + 'px',
  141. }"
  142. :canvas-id="item.id"
  143. :id="item.id"
  144. class="charts"
  145. ></canvas>
  146. <canvas
  147. v-else
  148. @tap="chartTap(item, $event)"
  149. :style="{
  150. width: cWidth * pixelRatio + 'px',
  151. height: cHeight * pixelRatio + 'px',
  152. transform: 'scale(' + 1 / pixelRatio + ')',
  153. marginLeft: (-cWidth * (pixelRatio - 1)) / 2 + 'px',
  154. marginTop: (-cHeight * (pixelRatio - 1)) / 2 + 'px',
  155. }"
  156. :canvas-id="item.id"
  157. :id="item.id"
  158. class="charts"
  159. ></canvas>
  160. <!--#endif -->
  161. </view>
  162. </view>
  163. </view>
  164. </template>
  165. <script>
  166. import moment from "moment";
  167. import mapValues from "lodash/mapValues";
  168. import uCharts from "@/common/u-charts.js";
  169. // 用于保存图表操作对象
  170. let chartsObject = {};
  171. let chartsConfig = {};
  172. export default {
  173. data() {
  174. return {
  175. imgData: [],
  176. listData: [],
  177. myList: [],
  178. countData: [],
  179. noticeData: [],
  180. chartData: [],
  181. pixelRatio: 1,
  182. cWidth: "",
  183. cHeight: "",
  184. chartsFontSize: 10,
  185. ready:false,
  186. CornerMarker:''
  187. };
  188. },
  189. async onLoad(param) {
  190. await this.init(param);
  191. },
  192. async onShow() {
  193. if(this.ready){
  194. this.ready = false
  195. await this.refresh()
  196. this.ready = true
  197. }
  198. },
  199. // 本页面开启下拉刷新,用于刷新首页数据
  200. onPullDownRefresh() {
  201. this.refresh().then(() => {
  202. this.TOAST("已更新首页数据");
  203. uni.stopPullDownRefresh();
  204. });
  205. },
  206. methods: {
  207. // 页面初始化
  208. async init(param) {
  209. this.HIDE_LOADING();
  210. // 有参数表示可能是打开分享消息;将数据存入全局变量以备后续跳转
  211. if (param && param.learun && param.pagePath) {
  212. this.SET_GLOBAL("jumpParam", param);
  213. }
  214. // 登录状态无效,则跳转到登录页
  215. const stateValid = await this.checkLoginState();
  216. if (!stateValid) {
  217. this.RELAUNCH_TO("/pages/login");
  218. return;
  219. }
  220. // 图表相关参数初始化
  221. this.initCharts();
  222. // 加载页面数据和全局数据
  223. await this.FETCH_CLIENTDATA();
  224. await this.refresh();
  225. this.ready = true
  226. // 监听「我的应用」列表修改
  227. this.ON("home-list-change", () => {
  228. this.HTTP_GET("learun/adms/function/mylist").then((newList) => {
  229. this.myList = newList;
  230. });
  231. });
  232. this.SET_STORAGE("nextTime", null);
  233. // 处理小程序分享消息跳转
  234. // #ifdef MP
  235. const jumpParam = this.GET_GLOBAL("jumpParam");
  236. if (jumpParam) {
  237. this.SET_GLOBAL("jumpParam", null);
  238. this.MP_SHARE_DECODE(jumpParam);
  239. }
  240. // #endif
  241. //微信推送跳转
  242. if (!!param.page) {
  243. //通知公告
  244. if (param.page == "notice") {
  245. this.NAV_TO("/pages/LR_OAModule/list");
  246. }
  247. //邮件
  248. if (param.page == "mail") {
  249. this.NAV_TO("/pages/EducationalAdministration/SYS_ReceiveMessage/list");
  250. }
  251. //OA待办
  252. if (param.page == "oa") {
  253. this.NAV_TO("/pages/nworkflow/myflow/list");
  254. }
  255. //公文下发
  256. if (param.page == "file") {
  257. this.NAV_TO("/pages/EducationalAdministration/Sys_ReceiveFile/list");
  258. }
  259. return;
  260. }
  261. },
  262. // 验证登录状态
  263. async checkLoginState() {
  264. const token = this.GET_GLOBAL("token") || uni.getStorageSync("token");
  265. if (!token || token === "null" || token === "undefined") {
  266. this.RELAUNCH_TO("/pages/login");
  267. this.HIDE_LOADING();
  268. return false;
  269. }
  270. this.SET_GLOBAL("token", token);
  271. // 判断是否有 loginUser 对象
  272. if (this.GET_GLOBAL("loginUser")) {
  273. return true;
  274. }
  275. // 拉取用户信息验证登录态;如果失败则跳转至登录页
  276. const userInfo = await this.HTTP_GET("learun/adms/user/info");
  277. if (!userInfo) {
  278. this.SET_GLOBAL("token", null);
  279. this.SET_STORAGE("token", null);
  280. return false;
  281. }
  282. // 有登录态,则设置用户信息和全局数据
  283. const { baseinfo, mpinfo, post, role } = userInfo;
  284. const user = { ...baseinfo, post, role };
  285. if (mpinfo && Array.isArray(mpinfo) && mpinfo.includes(this.PLATFORM)) {
  286. user.miniProgram = true;
  287. }
  288. this.SET_GLOBAL("loginUser", user);
  289. return true;
  290. },
  291. // 刷新首页数据
  292. async refresh() {
  293. // 清空页面数据
  294. chartsObject = {};
  295. this.imgData = [];
  296. this.listData = [];
  297. this.myList = [];
  298. this.countData = [];
  299. this.noticeData = [];
  300. this.chartData = [];
  301. // 同时发出请求,获取轮播图、所有功能列表、我的功能列表、商机通知提醒图表数据
  302. // 商机、通知提醒图表数据,获取的是数据ID,所以还需要进一步请求
  303. const [imgData, listData, myList, settingData] = await Promise.all([
  304. this.HTTP_GET(
  305. "learun/adms/desktop/imgid" +
  306. (this.CONFIG("isDistributed") == true ? "?isDistributed=true" : "")
  307. ),
  308. this.HTTP_GET("learun/adms/function/list").then(
  309. (result) => result.data
  310. ),
  311. this.HTTP_GET("learun/adms/function/mylist"),
  312. this.HTTP_GET("learun/adms/desktop/setting").then(
  313. (result) => result.data
  314. ),
  315. ]);
  316. this.imgData = imgData;
  317. if (!this.CONFIG("isDistributed"))
  318. // 轮播图需要加上 url 前缀
  319. this.imgData = imgData.map((t) => this.API + `/desktop/img?data=${t}`);
  320. // 功能区按钮需要处理 icon
  321. this.listData = listData.map((item) => {
  322. const icon = item.F_Icon
  323. ? item.F_Icon.replace(`iconfont icon-`, ``)
  324. : "";
  325. const existsIcon = this.getUiIcons().some((t) => t === icon);
  326. return {
  327. ...item,
  328. icon: existsIcon ? icon : "roundright",
  329. };
  330. });
  331. // 我的应用列表需要过滤掉不存在的按钮
  332. this.myList = myList.filter((t) =>
  333. listData.find((item) => item.F_Id === t)
  334. );
  335. // 发出请求,获取商机信息、消息通知信息、图表信息;三类数据全部同时请求
  336. await Promise.all([
  337. ...settingData.target.map((item) =>
  338. this.HTTP_GET("learun/adms/desktop/data", {
  339. type: "Target",
  340. id: item.F_Id,
  341. }).then((data) => {
  342. if (data && data.value) {
  343. const { value } = data;
  344. this.countData.push({
  345. title: item.F_Name,
  346. value,
  347. });
  348. }
  349. })
  350. ),
  351. ...settingData.list.map((item) =>
  352. this.HTTP_GET("learun/adms/desktop/data", {
  353. type: "list",
  354. id: item.F_Id,
  355. }).then((data) => {
  356. if (data && data.value) {
  357. let { value } = data;
  358. if(value&&value.length){
  359. value = value.sort((a,b)=>{
  360. return new Date(b.f_time).valueOf() - new Date(a.f_time).valueOf()
  361. })
  362. }
  363. if(item.F_Name == "待办事项"){
  364. this.CornerMarker = value.length||'0'
  365. }
  366. this.noticeData.push({
  367. title: item.F_Name,
  368. content: value,
  369. });
  370. }
  371. })
  372. ),
  373. ...settingData.chart.map((item) =>
  374. this.HTTP_GET("learun/adms/desktop/data", {
  375. type: "chart",
  376. id: item.F_Id,
  377. }).then((data) => {
  378. if (data && data.value) {
  379. const { value } = data;
  380. this.chartData.push({
  381. title: item.F_Name,
  382. value,
  383. id: item.F_Id,
  384. type: item.F_Type,
  385. });
  386. }
  387. })
  388. ),
  389. ]);
  390. // 渲染图表
  391. this.chartData.forEach((item) => {
  392. // 根据 item.type 的值选用对应的图表初始化配置项
  393. // 0=环形图;1=折线图;2=柱状图
  394. const charts = new uCharts(
  395. [
  396. {
  397. ...chartsConfig,
  398. canvasId: item.id,
  399. type: "ring",
  400. series: item.value.map((t) => ({
  401. name: t.name,
  402. data: t.value,
  403. })),
  404. extra: {
  405. pie: {
  406. offsetAngle: -45,
  407. ringWidth: 20,
  408. labelWidth: 15,
  409. },
  410. },
  411. legend: {
  412. lineHeight: 20,
  413. },
  414. },
  415. {
  416. ...chartsConfig,
  417. canvasId: item.id,
  418. type: "line",
  419. series: [
  420. {
  421. name: item.title,
  422. data: item.value.map((t) => t.value),
  423. },
  424. ],
  425. categories: item.value.map((t) => t.name),
  426. extra: {
  427. line: {
  428. type: "straight",
  429. },
  430. },
  431. xAxis: {
  432. rotateLabel: true,
  433. fontSize: this.chartsFontSize,
  434. itemCount: 8,
  435. },
  436. enableScroll: true,
  437. },
  438. {
  439. ...chartsConfig,
  440. canvasId: item.id,
  441. type: "column",
  442. series: [
  443. {
  444. name: item.title,
  445. data: item.value.map((t) => t.value),
  446. },
  447. ],
  448. categories: item.value.map((t) => t.name),
  449. xAxis: {
  450. rotateLabel: true,
  451. fontSize: this.chartsFontSize,
  452. },
  453. },
  454. ][item.type]
  455. );
  456. chartsObject[item.id] = charts;
  457. });
  458. },
  459. // 初始化图表
  460. initCharts() {
  461. // (阿里小程序)设置图表尺寸为2倍
  462. // #ifdef MP-ALIPAY
  463. const pixelRatio = uni.getSystemInfoSync().pixelRatio;
  464. if (pixelRatio > 1) {
  465. this.pixelRatio = 2;
  466. this.chartsFontSize = 15;
  467. }
  468. // #endif
  469. this.cWidth = uni.upx2px(750);
  470. this.cHeight = uni.upx2px(500);
  471. chartsConfig = {
  472. $this: this,
  473. pixelRatio: this.pixelRatio,
  474. width: this.cWidth * this.pixelRatio,
  475. height: this.cHeight * this.pixelRatio,
  476. background: "#FFFFFF",
  477. dataLabel: true,
  478. padding: [20, 15, 5, 15],
  479. };
  480. },
  481. // 图表点击事件
  482. chartTap(chartItem, e) {
  483. const format = ({ name, data }, category) =>
  484. `${category || ""} ${name}: ${data}`;
  485. // #ifdef MP-DINGTALK
  486. const detail = e.detail;
  487. const item = detail;
  488. e.mp.changedTouches = [item];
  489. // #endif
  490. chartsObject[chartItem.id].showToolTip(e, {
  491. format,
  492. });
  493. },
  494. // 图表拖动事件(开始)
  495. touchStart(chartId, e) {
  496. chartsObject[chartId].scrollStart(e);
  497. },
  498. // 图表拖动事件(拖动)
  499. touchMove(chartId, e) {
  500. chartsObject[chartId].scroll(e);
  501. },
  502. // 图表拖动事件(结束)
  503. touchEnd(chartId, e) {
  504. chartsObject[chartId].scrollEnd(e);
  505. },
  506. // 格式化日期的显示(新闻列表、通知公告等)
  507. postDateTime(timeStr) {
  508. return moment(timeStr).fromNow();
  509. },
  510. // 点击功能按钮
  511. funcListClick(item) {
  512. if (item.F_IsSystem === 2) {
  513. this.NAV_TO(
  514. `/pages/customapp/list?formId=${item.F_FormId}`,
  515. item,
  516. true
  517. );
  518. return;
  519. }
  520. this.NAV_TO(`/pages/${item.F_Url}/list`);
  521. },
  522. // 点击通知公告的标题
  523. async noticeClick(item) {
  524. console.log(item);
  525. if(item.f_category!==undefined){
  526. this.NAV_TO("/pages/home/notice", item, true);
  527. }else{
  528. // const result = await this.HTTP_GET(
  529. // 'learun/adms/newwf/mytask',
  530. // {
  531. // pagination:{"rows":100,"page":1,"sidx":"F_CreateDate","sord":"DESC"},
  532. // queryJson: JSON.stringify({keyword:item.f_title})
  533. // },
  534. // '加载任务时出错'
  535. // )
  536. // if(!result){
  537. // return
  538. // }
  539. // this.processId = this.currentTask.F_Id
  540. // this.taskId = this.currentTask.F_TaskId
  541. let params = {
  542. F_Id:item.f_processid,
  543. F_TaskId:item.f_id,
  544. mark:"pre",
  545. F_Title:item.f_title,
  546. }
  547. this.NAV_TO('/pages/nworkflow/myflow/single', params, true)
  548. }
  549. },
  550. informClick(titleName) {
  551. if (titleName == "通知公告") {
  552. this.NAV_TO("/pages/LR_OAModule/list", "", true);
  553. }
  554. },
  555. // #ifndef H5
  556. // 点击左上角扫码图标,H5 无此功能
  557. scanClick() {
  558. uni.scanCode({
  559. scanType: ["qrCode", "barCode"],
  560. success: ({ result, charSet }) => {
  561. // 您可以在这里自行定制扫码后的功能
  562. },
  563. });
  564. },
  565. // #endif
  566. // 点击更多功能按钮
  567. moreClick(openSearch) {
  568. this.NAV_TO(`/pages/home/more${openSearch ? "?search=1" : ""}`);
  569. },
  570. // 点击右上角的消息按钮
  571. msgClick() {
  572. this.TAB_TO("/pages/msg");
  573. },
  574. },
  575. computed: {
  576. // 「我的功能」区域按钮列表
  577. funcListDisplay() {
  578. const { myList, listData } = this;
  579. const myFuncList = myList.reduce((list, id) => {
  580. if (listData.find((t) => t.F_Id === id)) {
  581. return [...list, listData.find((t) => t.F_Id === id)];
  582. }
  583. return list;
  584. }, []);
  585. return myFuncList;
  586. },
  587. // imgData 数组的长度
  588. imgCount() {
  589. return this.imgData.length;
  590. },
  591. },
  592. };
  593. </script>
  594. <style lang="less" scoped>
  595. .page {
  596. background-color: #f3f3f3;
  597. .header {
  598. height: 100rpx;
  599. background-color: #0c86d8;
  600. display: flex;
  601. align-items: center;
  602. .header-left {
  603. flex-grow: 0;
  604. }
  605. .header-mid {
  606. flex-grow: 1;
  607. background-color: #3d9ee0;
  608. line-height: 60rpx;
  609. height: 60rpx;
  610. font-size: 24rpx;
  611. color: #fff;
  612. border-radius: 6rpx;
  613. }
  614. .header-right {
  615. flex-grow: 0;
  616. }
  617. }
  618. .content {
  619. background-color: #fff;
  620. }
  621. .function-list {
  622. padding-bottom: 0;
  623. .cu-item {
  624. .app-item {
  625. border-radius: 50%;
  626. height: 45px;
  627. width: 45px;
  628. }
  629. &:nth-child(7n + 1) > .app-item {
  630. background-color: #62bbff;
  631. }
  632. &:nth-child(7n + 2) > .app-item {
  633. background-color: #7bd2ff;
  634. }
  635. &:nth-child(7n + 3) > .app-item {
  636. background-color: #ffd761;
  637. }
  638. &:nth-child(7n + 4) > .app-item {
  639. background-color: #fe955c;
  640. }
  641. &:nth-child(7n + 5) > .app-item {
  642. background-color: #ff6283;
  643. }
  644. &:nth-child(7n + 6) > .app-item {
  645. background-color: #60e3f3;
  646. }
  647. &:nth-child(7n) > .app-item {
  648. background-color: #acc8fe;
  649. }
  650. }
  651. }
  652. .function-more-btn {
  653. display: inline-block;
  654. border: currentColor 1px solid;
  655. border-radius: 2px;
  656. padding: 10rpx 50rpx;
  657. }
  658. .count-list {
  659. &:after {
  660. content: "";
  661. clear: both;
  662. display: table;
  663. }
  664. .count-item-value {
  665. color: #0188d2;
  666. font-size: 24px;
  667. }
  668. }
  669. .chart-list {
  670. background-color: #fff;
  671. overflow: hidden;
  672. }
  673. }
  674. </style>
  675. <style lang="less">
  676. #home {
  677. width: 750rpx;
  678. overflow-x: hidden;
  679. .function-list .cu-item text[class*="cuIcon"] {
  680. margin-top: 0 !important;
  681. }
  682. }
  683. .CornerMarker{
  684. padding: 1px 2px;
  685. position: absolute;
  686. right: 0px;
  687. top: 0px;
  688. background-color: red;
  689. min-width: 14px;
  690. border-radius: 7px;
  691. font-size: 12px;
  692. color: #fff;
  693. }
  694. </style>