checkIn.vue 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. <template>
  2. <view class="attendance-page">
  3. <view class="header">
  4. <text class="title">我的考勤记录</text>
  5. <picker mode="selector" :range="timeRanges" @change="onTimeRangeChange">
  6. <view class="picker">
  7. {{ selectedTimeRange }}
  8. </view>
  9. </picker>
  10. </view>
  11. <view class="statistics" :class="{'show': chartShow}">
  12. <view class="statistic-card">
  13. <view class="statistic-title">考勤统计</view>
  14. <view class="statistic-item">
  15. <text class="label">出勤:</text>
  16. <text class="value">{{ attendanceCount }}</text>
  17. </view>
  18. <view class="statistic-item">
  19. <text class="label">请假:</text>
  20. <text class="value">{{ leaveCount }}</text>
  21. </view>
  22. <view class="statistic-item">
  23. <text class="label">出差:</text>
  24. <text class="value">{{ businessTripCount }}</text>
  25. </view>
  26. <view class="statistic-item">
  27. <text class="label">打卡:</text>
  28. <text class="value">{{ clockInCount }}</text>
  29. </view>
  30. <view class="statistic-item">
  31. <text class="label">补卡:</text>
  32. <text class="value">{{ makeUpCount }}</text>
  33. </view>
  34. </view>
  35. </view>
  36. <view class="todayCheckIn" :class="{'show': shouldShow}">
  37. <view class="check-in-container">
  38. <text class="title2">今日签到信息</text>
  39. <view class="info-row">
  40. <text class="value">日期:</text>
  41. <text class="label">{{todayData.day}}</text>
  42. </view>
  43. <view class="info-row">
  44. <text class="value">晨签时间:</text>
  45. <text class="label">{{todayData.startTime || '未打卡'}} </text>
  46. </view>
  47. <view class="info-row">
  48. <text class="value">晚签时间:</text>
  49. <text class="label">{{todayData.endTime || '未打卡'}} </text>
  50. </view>
  51. <view class="info-row">
  52. <text class="value">状态:</text>
  53. <text class="label">{{todayData.status}}</text>
  54. </view>
  55. </view>
  56. </view>
  57. <view class="chart-container" :class="{'show': chartShow}">
  58. <view class="">
  59. <text class="chart-title">考勤趋势图</text>
  60. <view class="charts-box">
  61. <qiun-data-charts :type="chartsType" :opts="opts" :chartData="chartData" />
  62. </view>
  63. </view>
  64. </view>
  65. </view>
  66. </template>
  67. <script setup>
  68. import {
  69. ref,
  70. onMounted,
  71. reactive
  72. } from 'vue';
  73. const todayData = reactive({
  74. day: '2024-11-11',
  75. startTime: '08:59:59',
  76. endTime: '',
  77. status: '待补卡'
  78. })
  79. const shouldShow = ref(true)
  80. const chartShow = ref(false)
  81. //图表类型
  82. const chartsType = ref('pie')
  83. //图表要填充的数据
  84. const chartData = ref({})
  85. const opts = ref({
  86. color: ["#1890FF", "#91CB74", "#FAC858", "#EE6666", "#73C0DE", "#3CA272", "#FC8452", "#9A60B4", "#ea7ccc"],
  87. padding: [15, 15, 0, 5],
  88. enableScroll: false,
  89. legend: {},
  90. xAxis: {
  91. disableGrid: true
  92. },
  93. yAxis: {
  94. data: [{
  95. min: 0
  96. }]
  97. },
  98. extra: {
  99. column: {
  100. type: "group",
  101. width: 30,
  102. activeBgColor: "#000000",
  103. activeBgOpacity: 0.08
  104. }
  105. }
  106. });
  107. const timeRanges = ref(['日', '周', '月']);
  108. const selectedTimeRange = ref('日');
  109. //出勤...补卡统计
  110. const attendanceCount = ref(0);
  111. const leaveCount = ref(0);
  112. const businessTripCount = ref(0);
  113. const clockInCount = ref(0);
  114. const makeUpCount = ref(0);
  115. const arr=ref([])
  116. const currentData = ref({
  117. attendance: 0,
  118. leave: 0,
  119. businessTrip: 0,
  120. clockIn: 0,
  121. makeUp: 0,
  122. res: {},
  123. });
  124. onMounted(() => {
  125. //初始化数据
  126. fetchAttendanceData();
  127. });
  128. //日周月切换
  129. function onTimeRangeChange(event) {
  130. const selectedIndex = event.detail.value;
  131. console.log('selectedIndex', selectedIndex)
  132. selectedTimeRange.value = timeRanges.value[selectedIndex];
  133. fetchAttendanceData();
  134. switch (selectedTimeRange.value) {
  135. case '日':
  136. showDay();
  137. break;
  138. case '周':
  139. chartsType.value = 'pie';
  140. showWeekAndMonth();
  141. break;
  142. case '月':
  143. chartsType.value = 'column';
  144. showWeekAndMonth();
  145. break;
  146. }
  147. };
  148. function showDay() {
  149. shouldShow.value = true;
  150. chartShow.value = false;
  151. }
  152. function showWeekAndMonth() {
  153. shouldShow.value = false;
  154. chartShow.value = true;
  155. getData();
  156. }
  157. function fetchAttendanceData() {
  158. const mockData = {
  159. 日: {
  160. attendance: 5,
  161. leave: 0,
  162. businessTrip: 1,
  163. clockIn: 5,
  164. makeUp: 0,
  165. res: {}
  166. },
  167. 周: {
  168. attendance: 30,
  169. leave: 2,
  170. businessTrip: 1,
  171. clockIn: 32,
  172. makeUp: 1,
  173. res: {
  174. series: [{
  175. data: [{
  176. "name": "出勤",
  177. "value": 50,
  178. "labelText": "出勤:50次"
  179. }, {
  180. "name": "请假",
  181. "value": 30
  182. }, {
  183. "name": "出差",
  184. "value": 20
  185. }, {
  186. "name": "打卡",
  187. "value": 18,
  188. "labelText": "打卡:18次"
  189. }, {
  190. "name": "补卡",
  191. "value": 8
  192. }]
  193. }],
  194. }
  195. },
  196. 月: {
  197. attendance: 100,
  198. leave: 5,
  199. businessTrip: 2,
  200. clockIn: 105,
  201. makeUp: 3,
  202. res: {
  203. categories: ["第1周", "第2周", "第3周", "第4周"],
  204. series: [{
  205. name: "出勤",
  206. data: [35, 8, 25, 37]
  207. },
  208. {
  209. name: "出差",
  210. data: [70, 40, 65, 100]
  211. },
  212. {
  213. name: "请假",
  214. data: [100, 80, 95, 10]
  215. }
  216. ]
  217. },
  218. }
  219. };
  220. const currentData1 = mockData[selectedTimeRange.value];
  221. currentData.value = currentData1;
  222. if (currentData1) {
  223. attendanceCount.value = currentData1.attendance;
  224. leaveCount.value = currentData1.leave;
  225. businessTripCount.value = currentData1.businessTrip;
  226. clockInCount.value = currentData1.clockIn;
  227. makeUpCount.value = currentData1.makeUp;
  228. } else {
  229. console.error('没有找到相关的考勤数据:', selectedTimeRange.value);
  230. }
  231. }
  232. function getData() {
  233. let res = currentData.value.res;
  234. chartData.value = JSON.parse(JSON.stringify(res));
  235. }
  236. //计算数组和
  237. function countArr(arr){
  238. const sum=0;
  239. for (var i = 0; i < arr.length; i++) {
  240. sum+=arr[i];
  241. }
  242. return sum;
  243. }
  244. </script>
  245. <style scoped>
  246. .attendance-page {
  247. padding: 20px;
  248. background-color: #f9f9f9;
  249. }
  250. .header {
  251. display: flex;
  252. justify-content: space-between;
  253. align-items: center;
  254. margin-bottom: 20px;
  255. }
  256. .title {
  257. font-size: 24px;
  258. font-weight: bold;
  259. color: #333;
  260. }
  261. .picker {
  262. border: 1px solid #3498db;
  263. border-radius: 5px;
  264. padding: 10px;
  265. background-color: #ecf6fc;
  266. color: #3498db;
  267. }
  268. .statistics {
  269. display: flex;
  270. justify-content: center;
  271. }
  272. .statistic-card {
  273. background: white;
  274. border-radius: 10px;
  275. padding: 20px;
  276. box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
  277. /* width: 100%; */
  278. max-width: 600px;
  279. }
  280. .statistic-title {
  281. text-align: center;
  282. font-size: 20px;
  283. font-weight: bold;
  284. color: #333;
  285. }
  286. .statistic-item {
  287. display: flex;
  288. justify-content: space-between;
  289. margin-bottom: 10px;
  290. border-bottom: 1px solid #eee;
  291. padding-bottom: 10px;
  292. }
  293. .label {
  294. font-size: 18px;
  295. color: #666;
  296. }
  297. .value {
  298. font-size: 16px;
  299. font-weight: bold;
  300. color: #333;
  301. }
  302. .chart-container {
  303. margin-top: 20px;
  304. }
  305. .chart-title {
  306. font-size: 20px;
  307. font-weight: bold;
  308. text-align: center;
  309. margin-bottom: 10px;
  310. color: #333;
  311. }
  312. .charts-box {
  313. width: 100%;
  314. height: 300px;
  315. }
  316. .todayCheckIn {
  317. background-color: #ffffff;
  318. padding: 20px;
  319. box-sizing: border-box;
  320. }
  321. .check-in-container {
  322. width: 100%;
  323. height: 100%;
  324. display: flex;
  325. flex-direction: column;
  326. align-items: center;
  327. justify-content: center;
  328. }
  329. .title2 {
  330. font-size: 22px;
  331. font-weight: bold;
  332. margin-bottom: 20px;
  333. }
  334. .info-row {
  335. width: 100%;
  336. display: flex;
  337. justify-content: space-between;
  338. margin-bottom: 10px;
  339. }
  340. .todayCheckIn,
  341. .chart-container,
  342. .statistics {
  343. /* 默认隐藏 */
  344. display: none;
  345. }
  346. /* 当需要显示时,可以添加一个额外的类 */
  347. .todayCheckIn.show,
  348. .chart-container.show,
  349. .statistics.show {
  350. display: block;
  351. }
  352. </style>