index.vue 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. <template>
  2. <home-container>
  3. <div class="title">
  4. <user-info :name="checkerName" :sub-title="userInfo" />
  5. <div>
  6. <span class="btn">
  7. <img alt="" src="@/static/images/clock.png">{{ todayCheckInTime }}
  8. </span>
  9. <span class="btn">
  10. <img alt="" src="@/static/images/status.png">执勤中
  11. </span>
  12. </div>
  13. </div>
  14. <div class="tab">
  15. <div v-for="tab in tabs" :key="tab.id" :class="{ 'unread': tab.hasUnread, 'item': true }"
  16. @click="goToPage(tab.appUrl)">
  17. <img alt="" :src="tab.workbenchIcon">
  18. <view class="text">{{ tab.appName }}</view>
  19. </div>
  20. </div>
  21. <div class="work">
  22. <!-- <div class="item">
  23. <div class="text">
  24. 一键报警
  25. <span>紧急情况</span>
  26. </div>
  27. <div class="icon"><img alt="" src="@/static/images/done.png"></div>
  28. </div> -->
  29. <div class="item" @click="goworkDocu">
  30. <div class="text">
  31. 工作手册
  32. <span>查询规则制度</span>
  33. </div>
  34. <div class="icon"><img alt="" src="@/static/images/pending.png"></div>
  35. </div>
  36. </div>
  37. <Notice ref="notice" />
  38. <!-- 今日待办 -->
  39. <!-- <myToDo /> -->
  40. <!-- 最新公告 -->
  41. <announcement ref="announcement" />
  42. <!--
  43. <img alt="" class="banner" src="@/static/images/banner.png"> -->
  44. <!-- 今日待办 -->
  45. <!-- <task /> -->
  46. </home-container>
  47. </template>
  48. <script>
  49. import HomeContainer from "@/components/HomeContainer.vue";
  50. import UserInfo from "@/components/UserInfo.vue";
  51. import HeadTitle from "@/components/HeadTitle.vue";
  52. import Announcement from "@/pages/home/components/announcement.vue";
  53. import myToDo from "@/pages/home/components/myToDo.vue";
  54. import Task from "@/pages/home/components/task.vue";
  55. import Notice from "@/pages/home/components/notice.vue";
  56. import { getUserProfile,getAppListByRoleId,getAppList } from "@/api/system/user";
  57. import { getAttendanceList } from "@/api/attendance/attendance"
  58. import { getUnreadCount } from "@/api/check/checkTask"
  59. import { checkRolePermission } from "@/utils/common.js";
  60. export default {
  61. components: { Task, Announcement, myToDo, HeadTitle, UserInfo, HomeContainer, Notice },
  62. data() {
  63. return {
  64. checkerId: this.$store.state.user.id,
  65. userInfo: '',
  66. todayCheckInTime: '未打卡',
  67. unreadCount: 0,
  68. appList: [] // 存储接口返回的应用列表
  69. }
  70. },
  71. computed: {
  72. checkerName() {
  73. if (this.$store.state.user) {
  74. if (this.$store.state.user.userInfo && this.$store.state.user.userInfo.nickName) {
  75. return this.$store.state.user.userInfo.nickName
  76. }
  77. }
  78. return this.$store.state.user.name
  79. },
  80. role() {
  81. return this.$store?.state?.user?.roles[0]
  82. },
  83. tabs() {
  84. // 如果接口返回了应用列表,则使用接口数据
  85. if (this.appList && this.appList.length > 0) {
  86. return this.appList.map((app, index) => {
  87. // 根据应用名称映射到对应的路径和图标
  88. return {
  89. ...app,
  90. showUnread: app.appName === '巡视检查' ? this.unreadCount > 0 : false
  91. };
  92. });
  93. }
  94. }
  95. },
  96. onShow() {
  97. this.updateCurrentDate();
  98. this.getUnreadCount()
  99. // 页面显示时,刷新子组件的数据 - 使用$nextTick确保DOM已渲染完成
  100. this.$nextTick(() => {
  101. console.log("notice====", this.$refs.notice)
  102. this.$refs.notice?.refreshData();
  103. this.$refs.announcement?.refreshData();
  104. });
  105. },
  106. onLoad() {
  107. this.getUser()
  108. this.loadTodayRecord();
  109. },
  110. methods: {
  111. goworkDocu() {
  112. uni.navigateTo({
  113. url: '/pages/workDocu/index'
  114. });
  115. },
  116. async getUnreadCount() {
  117. const res = await getUnreadCount();
  118. this.unreadCount = res.data
  119. },
  120. async getUser() {
  121. const data = await getUserProfile();
  122. console.log("data====", data)
  123. //data.postGroup + " " +
  124. this.userInfo = data.data.dept.deptName
  125. await this.loadAppList(data.data);
  126. // this.formData.securityLocationText = data.data.dept.deptName
  127. // this.formData.positionText = data.postGroup
  128. },
  129. formatDate(date) {
  130. const year = date.getFullYear();
  131. const month = (date.getMonth() + 1).toString().padStart(2, '0');
  132. const day = date.getDate().toString().padStart(2, '0');
  133. const week = ['日', '一', '二', '三', '四', '五', '六'][date.getDay()];
  134. return `${year}年${month}月${day}日 星期${week}`;
  135. },
  136. updateCurrentDate() {
  137. this.currentDate = this.formatDate(new Date());
  138. },
  139. handleGridClick(item) {
  140. console.log('点击了宫格:', item);
  141. if (item.path) {
  142. uni.navigateTo({
  143. url: item.path
  144. });
  145. } else {
  146. this.$modal.showToast('功能开发中,敬请期待');
  147. }
  148. },
  149. goToAttendance() {
  150. uni.navigateTo({
  151. url: '/pages/attendance/index'
  152. });
  153. },
  154. changeGrid(e) {
  155. const index = e.detail.index;
  156. const item = this.items[index];
  157. this.handleGridClick(item);
  158. },
  159. goToPage(path) {
  160. // if (checkRolePermission(this.role, path)) {
  161. uni.navigateTo({ url: path });
  162. // } else {
  163. // this.$modal.showToast('此角色不需要查看该功能,无需操作~');
  164. // }
  165. },
  166. async loadAppList(userInfo) {
  167. // const roleId = userInfo.roles && userInfo.roles.length ? userInfo.roles[0].roleId : null;
  168. try {
  169. // if (roleId) {
  170. const res = await getAppList({homePage:1});
  171. if (res.code === 200) {
  172. this.appList = res.data;
  173. }
  174. // }
  175. } catch (error) {
  176. console.error('获取应用列表失败:', error);
  177. this.appList = [];
  178. }
  179. },
  180. async loadTodayRecord() {
  181. if (this.yesterday) {
  182. return;
  183. }
  184. const today = this.formatDate(new Date());
  185. const { data } = await getAttendanceList({
  186. type: 1,
  187. checkInDate: today,
  188. userId: this.$store.state.user.id
  189. });
  190. // 接口 data 可能是多条(按天),我们取第一条里的 items
  191. const todayData = data && data.length ? data[0] : null;
  192. const items = todayData ? todayData.items : [];
  193. const lastMorning = items.find(r => r.checkInType == 'CLOCK_IN');
  194. if (lastMorning) {
  195. console.log(lastMorning);
  196. this.todayCheckInTime = '已打卡 ' + lastMorning.checkInTime
  197. } else {
  198. }
  199. },
  200. // 日期格式化(昨天、今天查询用)
  201. formatDate(date) {
  202. const y = date.getFullYear();
  203. const m = String(date.getMonth() + 1).padStart(2, '0');
  204. const d = String(date.getDate()).padStart(2, '0');
  205. return `${y}-${m}-${d}`;
  206. },
  207. }
  208. }
  209. </script>
  210. <style lang="scss" scoped>
  211. img {
  212. display: inline-flex;
  213. }
  214. .title {
  215. padding: 40rpx 20rpx 20rpx;
  216. }
  217. .btn {
  218. display: inline-flex;
  219. align-items: center;
  220. padding: 10rpx 16rpx;
  221. font-weight: 400;
  222. font-size: 24rpx;
  223. color: #FFFFFF;
  224. line-height: 28rpx;
  225. background: rgba(255, 255, 255, 0.18);
  226. border-radius: 8rpx;
  227. img {
  228. display: inline-block;
  229. width: 32rpx;
  230. height: 32rpx;
  231. }
  232. &:not(:last-child) {
  233. margin-right: 48rpx;
  234. }
  235. }
  236. .tab {
  237. display: flex;
  238. align-items: center;
  239. justify-content: space-between;
  240. padding: 40rpx 70rpx;
  241. background: #FFFFFF;
  242. box-shadow: 0 8rpx 32rpx 0 rgba(0, 0, 0, 0.06);
  243. border-radius: 32rpx;
  244. .item {
  245. display: flex;
  246. align-items: center;
  247. justify-content: center;
  248. flex-flow: column;
  249. font-weight: 600;
  250. font-size: 20rpx;
  251. color: #3D3D3D;
  252. img {
  253. display: inline-block;
  254. width: 88rpx;
  255. height: 88rpx;
  256. }
  257. .text {
  258. margin-top: 10rpx;
  259. }
  260. }
  261. .unread {
  262. position: relative;
  263. }
  264. .unread::after {
  265. content: '';
  266. position: absolute;
  267. top: 0;
  268. right: 0;
  269. width: 24rpx;
  270. height: 24rpx;
  271. background: #FF4D4F;
  272. border-radius: 50%;
  273. }
  274. }
  275. .work {
  276. display: flex;
  277. flex-shrink: 2;
  278. margin: 32rpx 0;
  279. gap: 26rpx;
  280. .item {
  281. justify-content: space-between;
  282. flex-grow: 1;
  283. display: flex;
  284. padding: 20rpx 30rpx 20rpx 40rpx;
  285. background: #FFFFFF;
  286. box-shadow: 0 8rpx 20rpx 0 rgba(0, 0, 0, 0.06);
  287. border-radius: 28rpx;
  288. }
  289. .text {
  290. display: flex;
  291. flex-flow: column;
  292. font-weight: bold;
  293. font-size: 32rpx;
  294. color: #3D3D3D;
  295. line-height: 44rpx;
  296. justify-content: center;
  297. span {
  298. margin-top: 12rpx;
  299. font-weight: 400;
  300. font-size: 24rpx;
  301. color: #999999;
  302. line-height: 28rpx;
  303. }
  304. }
  305. .icon {
  306. display: inline-flex;
  307. width: 112rpx;
  308. height: 112rpx;
  309. }
  310. }
  311. .tips {
  312. display: flex;
  313. align-items: center;
  314. padding: 16rpx 28rpx;
  315. background: #FFF4F4;
  316. border-radius: 32rpx;
  317. font-size: 24rpx;
  318. color: #222222;
  319. line-height: 28rpx;
  320. margin-bottom: 32rpx;
  321. img {
  322. width: 66rpx;
  323. padding-right: 28rpx;
  324. border-right: 1px solid rgba(0, 0, 0, 0.1);
  325. margin-right: 28rpx;
  326. }
  327. }
  328. .banner {
  329. width: 100%;
  330. margin-bottom: 32rpx;
  331. }
  332. </style>