ソースを参照

be 完成最后的修改

master
Chunxian Zhang 1年前
コミット
287c8f2d7b
17個のファイルの変更741行の追加185行の削除
  1. +58
    -13
      lazy-timer-be/app.py
  2. +5
    -12
      lazy-timer-fe/package-lock.json
  3. +1
    -0
      lazy-timer-fe/package.json
  4. +1
    -0
      lazy-timer-fe/public/index.html
  5. +5
    -2
      lazy-timer-fe/src/App.js
  6. +4
    -4
      lazy-timer-fe/src/components/UserProfile.jsx
  7. +48
    -133
      lazy-timer-fe/src/data/dummy.js
  8. +1
    -1
      lazy-timer-fe/src/pages/Charts/Bar.jsx
  9. +239
    -0
      lazy-timer-fe/src/pages/Charts/Line2.jsx
  10. +13
    -2
      lazy-timer-fe/src/pages/Customers.jsx
  11. +24
    -17
      lazy-timer-fe/src/pages/Ecommerce.jsx
  12. +199
    -0
      lazy-timer-fe/src/pages/Gannt.jsx
  13. +120
    -0
      lazy-timer-fe/src/service/colorGenerator.js
  14. +8
    -0
      lazy-timer-fe/src/service/getAppId.js
  15. +1
    -1
      lazy-timer-fe/src/service/getDayActivity/index.js
  16. +7
    -0
      lazy-timer-fe/src/service/getDayScreenUse/index.js
  17. +7
    -0
      lazy-timer-fe/src/service/getSeconds.js

+ 58
- 13
lazy-timer-be/app.py ファイルの表示

@ -2,7 +2,7 @@
import os
import sys
import json
from datetime import datetime # 处理时间
from datetime import datetime, timedelta # 处理时间
from flask import Flask, request
from flask_cors import CORS, cross_origin
from flask_sqlalchemy import SQLAlchemy
@ -21,6 +21,7 @@ db = SQLAlchemy(app)
# 数据库模型
class App(db.Model):
__tablename__ = 'app'
id = db.Column(db.Integer, primary_key=True) # App id
process = db.Column(db.Text) # appName
text = db.Column(db.Text) # app窗口名称
@ -28,17 +29,20 @@ class App(db.Model):
class Period(db.Model):
__tablename__ = 'period'
timeStart = db.Column(db.DateTime, primary_key=True) # 开始时间
timeEnd = db.Column(db.DateTime) # 结束时间
winId = db.Column(db.Integer) # 活动id
class Tag(db.Model):
__tablename__ = 'tag'
id = db.Column(db.Integer, primary_key=True) # 标签id
text = db.Column(db.Text) # 标签文本
class Win(db.Model):
__tablename__ = 'win'
id = db.Column(db.Integer, primary_key=True) # 活动id
appId = db.Column(db.Integer) # App id
text = db.Column(db.Text, nullable=True) # 活动窗口名称
@ -52,15 +56,17 @@ class Win(db.Model):
def getDayScreenUseTime():
datetimeStr1 = json.loads(request.data)
datetimeStr = datetimeStr1['datetimeStr']
struct_time = datetime.strptime(datetimeStr, "%Y-%m-%d").date() # 获取请求日期, struct_time数据类型为dateTime
struct_time = datetime.strptime(datetimeStr, "%Y-%m-%d").date() # 获取请求日期, struct_time数据类型为dateTime
activityTimeList = Period.query.all()
selectedTimeList = [] # 选中的对应今天日期的时间
selectedTimeList = [] # 选中的对应今天日期的时间
for time in activityTimeList:
if time.timeStart.date() == struct_time and time.timeEnd.date() == struct_time:
selectedTimeList.append(time)
if (len(selectedTimeList) == 0):
sendJson = {'getDayScreenUseTimeH': 0, 'getDayScreenUseTimeM': 0, 'getDayScreenUseTimeS': 0, 'firstScreenTime': '', 'lastScreenTime': '', 'getScreenTimeSpanH': 0, 'getScreenTimeSpanM':0, 'getScreenTimeSpanS': 0 }
sendJson = {'getDayScreenUseTimeH': 0, 'getDayScreenUseTimeM': 0, 'getDayScreenUseTimeS': 0,
'firstScreenTime': '', 'lastScreenTime': '', 'getScreenTimeSpanH': 0, 'getScreenTimeSpanM': 0,
'getScreenTimeSpanS': 0}
else:
timeAmount = 0
for time in selectedTimeList:
@ -69,20 +75,59 @@ def getDayScreenUseTime():
timeAmount = timeAmount + time_diff.total_seconds()
timeAmount = int(timeAmount)
getDayScreenUseTimeM, getDayScreenUseTimeS = divmod(timeAmount, 60) # 每日屏幕使用时长, 分时秒
getDayScreenUseTimeM, getDayScreenUseTimeS = divmod(timeAmount, 60) # 每日屏幕使用时长, 分时秒
getDayScreenUseTimeH, getDayScreenUseTimeM = divmod(getDayScreenUseTimeM, 60)
firstScreenTime = selectedTimeList[0].timeStart.strftime('%H时%M分%S秒') # 第一次屏幕使用时刻,
lastScreenTime = selectedTimeList[-1].timeEnd.strftime('%H时%M分%S秒') # 最后一次屏幕使用时刻
screenTimeSpan = int((selectedTimeList[-1].timeEnd - selectedTimeList[0].timeStart).total_seconds()) # 持续时间
firstScreenTime = selectedTimeList[0].timeStart.strftime('%H时%M分%S秒') # 第一次屏幕使用时刻,
lastScreenTime = selectedTimeList[-1].timeEnd.strftime('%H时%M分%S秒') # 最后一次屏幕使用时刻
screenTimeSpan = int((selectedTimeList[-1].timeEnd - selectedTimeList[0].timeStart).total_seconds()) # 持续时间
getScreenTimeSpanM, getScreenTimeSpanS = divmod(screenTimeSpan, 60) # 每日屏幕使用时长, 分时秒
getScreenTimeSpanH, getScreenTimeSpanM = divmod(getScreenTimeSpanM, 60)
sendJson = {'getDayScreenUseTimeH': getDayScreenUseTimeH, 'getDayScreenUseTimeM': getDayScreenUseTimeM, 'getDayScreenUseTimeS': getDayScreenUseTimeS, 'firstScreenTime': firstScreenTime, 'lastScreenTime': lastScreenTime, 'getScreenTimeSpanH': getScreenTimeSpanH, 'getScreenTimeSpanM': getScreenTimeSpanM, 'getScreenTimeSpanS': getScreenTimeSpanS }
sendJson = {'getDayScreenUseTimeH': getDayScreenUseTimeH, 'getDayScreenUseTimeM': getDayScreenUseTimeM,
'getDayScreenUseTimeS': getDayScreenUseTimeS, 'firstScreenTime': firstScreenTime,
'lastScreenTime': lastScreenTime, 'getScreenTimeSpanH': getScreenTimeSpanH,
'getScreenTimeSpanM': getScreenTimeSpanM, 'getScreenTimeSpanS': getScreenTimeSpanS}
return json.dumps(sendJson, indent=4)
@app.route('/getDayScreenUseTime', methods=['POST'])
@app.route('/getDayScreenUse', methods=['POST'])
@cross_origin()
def getDayScreenUseTime():
def getDayScreenUse():
datetimeStr1 = json.loads(request.data)
datetimeStr = datetimeStr1['datetimeStr']
struct_time = datetime.strptime(datetimeStr, "%Y-%m-%d").date() # 获取请求日期, struct_time数据类型为dateTime
return "1"
struct_time = datetime.strptime(datetimeStr, "%Y-%m-%d").date() # dateTime数据类型
struct_time_tomorrow = struct_time + timedelta(days=1)
# 连接多张表
joinTables = Period.query.filter(Period.timeStart > struct_time).filter(
Period.timeStart < struct_time_tomorrow).filter(Period.timeEnd > struct_time).filter(
Period.timeEnd < struct_time_tomorrow).all()
resultTables = []
for i in joinTables:
sampleDict = {}
sampleDict['timeStart'] = i.timeStart.strftime('%H:%M:%S')
sampleDict['timeEnd'] = i.timeEnd.strftime('%H:%M:%S')
sampleDict['totolSeconds'] = (i.timeEnd - i.timeStart).seconds
queryWin = Win.query.filter(Win.id == i.winId).first()
sampleDict['activity'] = queryWin.text
sampleDict['appId'] = queryWin.appId
queryApp = App.query.filter(queryWin.appId == App.id).first()
sampleDict['appName'] = queryApp.text
queryTag = Tag.query.filter(queryApp.tagId == Tag.id).first()
sampleDict['tag'] = queryTag.text
resultTables.append(sampleDict)
returnJson = json.dumps(resultTables)
return returnJson
@app.route('/getAppId', methods=['POST'])
@cross_origin()
def getAppId():
queryAppId = App.query.all()
resultTables = []
for i in queryAppId:
sampleDict = {}
sampleDict['id'] = i.id
sampleDict['text'] = i.text
resultTables.append(sampleDict)
return json.dumps(resultTables)

+ 5
- 12
lazy-timer-fe/package-lock.json ファイルの表示

@ -19,6 +19,7 @@
"@syncfusion/ej2-react-richtexteditor": "^19.4.50",
"@syncfusion/ej2-react-schedule": "^19.4.50",
"axios": "^0.27.2",
"echarts": "^5.3.3",
"echarts-for-react": "^3.0.2",
"moment": "^2.29.4",
"react": "^17.0.2",
@ -6497,7 +6498,6 @@
"version": "5.3.3",
"resolved": "https://registry.npmmirror.com/echarts/-/echarts-5.3.3.tgz",
"integrity": "sha512-BRw2serInRwO5SIwRviZ6Xgm5Lb7irgz+sLiFMmy/HOaf4SQ+7oYqxKzRHAKp4xHQ05AuHw1xvoQWJjDQq/FGw==",
"peer": true,
"dependencies": {
"tslib": "2.3.0",
"zrender": "5.3.2"
@ -6519,8 +6519,7 @@
"node_modules/echarts/node_modules/tslib": {
"version": "2.3.0",
"resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.3.0.tgz",
"integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==",
"peer": true
"integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="
},
"node_modules/ee-first": {
"version": "1.1.1",
@ -16038,7 +16037,6 @@
"version": "5.3.2",
"resolved": "https://registry.npmmirror.com/zrender/-/zrender-5.3.2.tgz",
"integrity": "sha512-8IiYdfwHj2rx0UeIGZGGU4WEVSDEdeVCaIg/fomejg1Xu6OifAL1GVzIPHg2D+MyUkbNgPWji90t0a8IDk+39w==",
"peer": true,
"dependencies": {
"tslib": "2.3.0"
}
@ -16046,8 +16044,7 @@
"node_modules/zrender/node_modules/tslib": {
"version": "2.3.0",
"resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.3.0.tgz",
"integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==",
"peer": true
"integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="
}
},
"dependencies": {
@ -21038,7 +21035,6 @@
"version": "5.3.3",
"resolved": "https://registry.npmmirror.com/echarts/-/echarts-5.3.3.tgz",
"integrity": "sha512-BRw2serInRwO5SIwRviZ6Xgm5Lb7irgz+sLiFMmy/HOaf4SQ+7oYqxKzRHAKp4xHQ05AuHw1xvoQWJjDQq/FGw==",
"peer": true,
"requires": {
"tslib": "2.3.0",
"zrender": "5.3.2"
@ -21047,8 +21043,7 @@
"tslib": {
"version": "2.3.0",
"resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.3.0.tgz",
"integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==",
"peer": true
"integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="
}
}
},
@ -28330,7 +28325,6 @@
"version": "5.3.2",
"resolved": "https://registry.npmmirror.com/zrender/-/zrender-5.3.2.tgz",
"integrity": "sha512-8IiYdfwHj2rx0UeIGZGGU4WEVSDEdeVCaIg/fomejg1Xu6OifAL1GVzIPHg2D+MyUkbNgPWji90t0a8IDk+39w==",
"peer": true,
"requires": {
"tslib": "2.3.0"
},
@ -28338,8 +28332,7 @@
"tslib": {
"version": "2.3.0",
"resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.3.0.tgz",
"integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==",
"peer": true
"integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="
}
}
}

+ 1
- 0
lazy-timer-fe/package.json ファイルの表示

@ -14,6 +14,7 @@
"@syncfusion/ej2-react-richtexteditor": "^19.4.50",
"@syncfusion/ej2-react-schedule": "^19.4.50",
"axios": "^0.27.2",
"echarts": "^5.3.3",
"echarts-for-react": "^3.0.2",
"moment": "^2.29.4",
"react": "^17.0.2",

+ 1
- 0
lazy-timer-fe/public/index.html ファイルの表示

@ -27,6 +27,7 @@
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>懒人记时</title>
<script src="https://cdn.bootcdn.net/ajax/libs/echarts/5.3.3/echarts.common.js"></script>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>

+ 5
- 2
lazy-timer-fe/src/App.js ファイルの表示

@ -5,6 +5,7 @@ import { TooltipComponent } from '@syncfusion/ej2-react-popups';
import { Navbar, Footer, Sidebar, ThemeSettings } from './components';
import { Ecommerce, Orders, Calendar, Employees, Stacked, Pyramid, Customers, Kanban, Line, Area, Bar, Pie, Financial, ColorPicker, ColorMapping, Editor } from './pages';
import Line2 from './pages/Charts/Line2'
import './App.css';
import { useStateContext } from './contexts/ContextProvider';
@ -70,8 +71,10 @@ const App = () => {
{/* pages */}
<Route path="/orders" element={<Bar/>} />
<Route path="/employees" element={<Employees />} />
<Route path="/customers" element={<Customers />} />
<Route path="/firstscreen" element={<Employees />} />
<Route path="/sheets" element={<Customers />} />
<Route path="/firstscreen" element={<Line />} />
<Route path="/lastscreen" element={<Line2 />} />
{/* apps */}
<Route path="/kanban" element={<Kanban />} />

+ 4
- 4
lazy-timer-fe/src/components/UserProfile.jsx ファイルの表示

@ -12,7 +12,7 @@ const UserProfile = () => {
return (
<div className="nav-item absolute right-1 top-16 bg-white dark:bg-[#42464D] p-8 rounded-lg w-96">
<div className="flex justify-between items-center">
<p className="font-semibold text-lg dark:text-gray-200">User Profile</p>
<p className="font-semibold text-lg dark:text-gray-200">用户信息</p>
<Button
icon={<MdOutlineCancel />}
color="rgb(153, 171, 180)"
@ -28,9 +28,9 @@ const UserProfile = () => {
alt="user-profile"
/>
<div>
<p className="font-semibold text-xl dark:text-gray-200"> Michael Roberts </p>
<p className="text-gray-500 text-sm dark:text-gray-400"> Administrator </p>
<p className="text-gray-500 text-sm font-semibold dark:text-gray-400"> info@shop.com </p>
<p className="font-semibold text-xl dark:text-gray-200"> 在隐身 </p>
<p className="text-gray-500 text-sm dark:text-gray-400"> 管理员 </p>
<p className="text-gray-500 text-sm font-semibold dark:text-gray-400"> 1836891291@qq.com </p>
</div>
</div>
<div>

+ 48
- 133
lazy-timer-fe/src/data/dummy.js ファイルの表示

@ -1,12 +1,13 @@
import React from 'react'
import { AiOutlineCalendar, AiOutlineShoppingCart, AiOutlineAreaChart, AiOutlineBarChart, AiOutlineStock } from 'react-icons/ai'
import { FiShoppingBag, FiEdit, FiPieChart, FiBarChart, FiCreditCard, FiStar, FiShoppingCart } from 'react-icons/fi'
import { BsKanban, BsBarChart, BsCurrencyDollar, BsShield, BsChatLeft, BsFillLaptopFill } from 'react-icons/bs'
import { BsKanban, BsBarChart, BsCurrencyDollar, BsShield, BsChatLeft, BsFillLaptopFill, BsFileSpreadsheet, BsFillMoonFill, BsPhone } from 'react-icons/bs'
import { FaSortAmountDown } from 'react-icons/fa'
import { BiColorFill } from 'react-icons/bi'
import { IoMdContacts } from 'react-icons/io'
import { RiContactsLine, RiStockLine } from 'react-icons/ri'
import { MdWbSunny, MdBedtime } from 'react-icons/md'
import { GrOverview } from 'react-icons/gr'
import { HiOutlineRefresh } from 'react-icons/hi'
import { TiTick } from 'react-icons/ti'
import { GiLouvrePyramid } from 'react-icons/gi'
@ -23,6 +24,7 @@ import product5 from './product5.jpg'
import product6 from './product6.jpg'
import product7 from './product7.jpg'
import product8 from './product8.jpg'
import { getDayScreenUse } from '../service/getDayScreenUse'
export const gridOrderImage = props => (
<div>
@ -87,7 +89,7 @@ const customerGridImage = props => (
const customerAppImage = props => {
return (
<div className="image flex gap-4">
<img className="rounded-full w-10 h-10" src={props.AppImage} alt="App" />
{/* <img className="rounded-full w-10 h-10" src={props.AppImage} alt="App" /> */}
<div>
<p>{props.AppName}</p>
</div>
@ -400,98 +402,27 @@ export const links = [
{
name: '总览',
englishName: 'overview',
icon: <FiShoppingBag />
icon: <GrOverview />
},
{
name: '表格',
englishName: 'customers',
icon: <RiContactsLine />
englishName: 'sheets',
icon: <BsFileSpreadsheet />
},
{
name: '屏幕使用时间',
englishName: 'orders',
icon: <AiOutlineShoppingCart />
icon: <BsPhone/>
},
{
name: '第一次屏幕使用',
englishName: 'employees',
icon: <IoMdContacts />
englishName: 'firstscreen',
icon: <MdWbSunny />
},
{
name: '最后一次屏幕使用',
englishName: 'customers',
icon: <RiContactsLine />
}
]
},
{
title: '标签',
links: [
{
name: '学习',
englishName: 'calendar',
icon: <AiOutlineCalendar />
},
{
name: '工作',
englishName: 'kanban',
icon: <BsKanban />
},
{
name: '娱乐',
englishName: 'editor',
icon: <FiEdit />
},
{
name: '生活',
englishName: 'color-picker',
icon: <BiColorFill />
}
]
},
{
title: '单项',
links: [
{
name: 'line',
englishName: 'line',
icon: <AiOutlineStock />
},
{
name: 'area',
englishName: 'area',
icon: <AiOutlineAreaChart />
},
{
name: 'bar',
englishName: 'bar',
icon: <AiOutlineBarChart />
},
{
name: 'pie',
englishName: 'pie',
icon: <FiPieChart />
},
{
name: 'financial',
englishName: 'financial',
icon: <RiStockLine />
},
{
name: 'color-mapping',
englishName: 'color-mapping',
icon: <BsBarChart />
},
{
name: 'pyramid',
englishName: 'pyramid',
icon: <GiLouvrePyramid />
},
{
name: 'stacked',
englishName: 'stacked',
icon: <AiOutlineBarChart />
englishName: 'lastscreen',
icon: <BsFillMoonFill />
}
]
}
@ -772,22 +703,22 @@ export const themeColors = [
export const userProfileData = [
{
icon: <BsCurrencyDollar />,
title: 'My Profile',
desc: 'Account Settings',
title: '我的信息',
desc: '账户设置',
iconColor: '#03C9D7',
iconBg: '#E5FAFB'
},
{
icon: <BsShield />,
title: 'My Inbox',
desc: 'Messages & Emails',
title: '我的消息',
desc: '接收到的消息或来信',
iconColor: 'rgb(0, 194, 146)',
iconBg: 'rgb(235, 250, 242)'
},
{
icon: <FiCreditCard />,
title: 'My Tasks',
desc: 'To-do and Daily Tasks',
title: '我的任务',
desc: 'Todo和每日',
iconColor: 'rgb(255, 244, 229)',
iconBg: 'rgb(254, 201, 15)'
}
@ -838,53 +769,37 @@ export const ordersGrid = [
}
]
export const customersData = [
{
StartTime: '05:36:45',
EndTime: '05:37:51',
Duration: '00:01:06',
AppName: 'GoogleChrome',
AppImage: require('../images/icons/5l.png'),
Text: 'How to Convert Python Datetime to String',
Tag: '工作'
},
{
StartTime: '05:37:51',
EndTime: '05:38:57',
Duration: '00:01:06',
AppName: 'PyCharm',
AppImage: require('../images/icons/5l.png'),
Text: '500 Internal Server Error',
Tag: '工作'
},
{
StartTime: '05:38:57',
EndTime: '05:40:03',
Duration: '00:01:06',
AppName: 'GoogleChrome',
AppImage: require('../images/icons/5l.png'),
Text: 'Python- Fetch a value of SQLalchemy instrumentedattribute',
Tag: '工作'
},
{
StartTime: '05:40:03',
EndTime: '05:41:28',
Duration: '00:01:25',
AppName: 'GoogleChrome',
AppImage: require('../images/icons/5l.png'),
Text: 'How to Convert Python Datetime to String',
Tag: '工作'
},
{
StartTime: '05:36:45',
EndTime: '05:37:51',
Duration: '00:01:06',
AppName: 'GoogleChrome',
AppImage: require('../images/icons/79l.png'),
Text: 'How to Convert Python Datetime to String',
Tag: '工作'
const getSecondstoHH = (seconds) => {
let calculatedTime = new Date(null);
calculatedTime.setSeconds( seconds );
let newTime = calculatedTime.toISOString().substr(11, 8);
return newTime
}
const getcustomersGriData = async () => {
let DayScreenUse = await getDayScreenUse('2022-09-07')
DayScreenUse = DayScreenUse.data
let customersData = new Array(DayScreenUse.length)
for(let i = 0; i < customersData.length; i++) {
customersData[i] = {
StartTime: DayScreenUse[i]['timeStart'],
EndTime: DayScreenUse[i]['timeEnd'],
Duration: getSecondstoHH(DayScreenUse[i]['totolSeconds']),
AppName: DayScreenUse[i]['appName'],
Appimage: '',
Text: DayScreenUse[i]['activity'],
Tag: DayScreenUse[i]['tag']
}
}
]
return customersData
}
export const customersData = getcustomersGriData()
export const employeesData = [
{

+ 1
- 1
lazy-timer-fe/src/pages/Charts/Bar.jsx ファイルの表示

@ -210,4 +210,4 @@ const Bar = () => {
)
}
export default Bar
export default Bar

+ 239
- 0
lazy-timer-fe/src/pages/Charts/Line2.jsx ファイルの表示

@ -0,0 +1,239 @@
import React, { useEffect, useState } from 'react'
import ReactECharts from 'echarts-for-react'
import { ChartsHeader } from '../../components'
import { useStateContext } from '../../contexts/ContextProvider'
import { getDayScreenUseTime } from '../../service/getDayScreenUseTime/index'
const Line2 = () => {
const { currentColor, currentMode } = useStateContext()
let [option, setOption] = useState({})
/* 生成本周日期, 格式为 MM-DD */
function convertDate(date) {
//
var yyyy = date.getFullYear().toString()
var mm = (date.getMonth() + 1).toString()
var dd = (date.getDate() + 1).toString()
var mmChars = mm.split('')
var ddChars = dd.split('')
return (mmChars[1] ? mm : '0' + mmChars[0]) + '-' + (ddChars[1] ? dd : '0' + ddChars[0])
}
let currentWeekDates = new Array(7)
for (let i = 0; i < 7; i++) {
const curr = new Date()
currentWeekDates[i] = convertDate(new Date(curr.setDate(curr.getDate() - curr.getDay() + i)))
}
let currentWeekFirstScreenTime = new Array(7)
let bgColor = '#fff'
let color = ['#0090FF', '#36CE9E', '#FFC005', '#FF515A', '#8B5CFF', '#00CA69']
let echartData = [
{
name: '周一',
value1: 100
},
{
name: '周二',
value1: 138
},
{
name: '周三',
value1: 350
},
{
name: '周四',
value1: 173
},
{
name: '周五',
value1: 180
},
{
name: '周六',
value1: 150
},
{
name: '周日',
value1: 180
}
]
let xAxisData = echartData.map(v => v.name)
for (let i = 0; i < 7; i++) {
xAxisData[i] = xAxisData[i] + ' ' + currentWeekDates[i]
}
const hexToRgba = (hex, opacity) => {
let rgbaColor = ''
let reg = /^#[\da-f]{6}$/i
if (reg.test(hex)) {
rgbaColor = `rgba(${parseInt('0x' + hex.slice(1, 3))},${parseInt('0x' + hex.slice(3, 5))},${parseInt('0x' + hex.slice(5, 7))},${opacity})`
}
return rgbaColor
}
useEffect(async () => {
for (let i = 0; i < 7; i++) {
let receivedJson = await getDayScreenUseTime('2022-' + currentWeekDates[i])
let firstScreenTimeH = parseInt(receivedJson.data.lastScreenTime.substring(0, 2))
let firstScreenTimeM = parseInt(receivedJson.data.lastScreenTime.substring(3, 5))
let firstScreenTimeS = parseInt(receivedJson.data.lastScreenTime.substring(6, 8))
if (firstScreenTimeH !== NaN && firstScreenTimeM !== NaN && firstScreenTimeS !== NaN) {
currentWeekFirstScreenTime[i] = 3600 * firstScreenTimeH + 60 * firstScreenTimeM + firstScreenTimeS
} else {
currentWeekFirstScreenTime[i] = NaN
}
}
setOption({
backgroundColor: bgColor,
color: color,
legend: {
right: 10,
top: 10
},
tooltip: {
trigger: 'axis',
formatter: function (params) {
let html = ''
params.forEach(v => {
if (!isNaN(v.value)) {
html += `<div style="color: #666;font-size: 14px;line-height: 24px">
<span style="display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:${color[v.componentIndex]};"></span>
${v.seriesName}
<span style="color:${color[v.componentIndex]};font-weight:700;font-size: 18px">${Math.floor(v.value / 3600) + '时' + Math.floor((v.value % 3600) / 60) + '分钟' + Math.floor(v.value % 60) + '秒'}</span>
`
} else {
html = `<div style="color: #666;font-size: 14px;line-height: 24px">
<span style="display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:${color[v.componentIndex]};"></span>
${v.seriesName}
<span style="color:${color[v.componentIndex]};font-weight:700;font-size: 18px">该天还尚未开始</span>
`
}
})
return html
},
extraCssText: 'background: #fff; border-radius: 0;box-shadow: 0 0 3px rgba(0, 0, 0, 0.2);color: #333;',
axisPointer: {
type: 'shadow',
shadowStyle: {
color: '#ffffff',
shadowColor: 'rgba(225,225,225,1)',
shadowBlur: 5
}
}
},
grid: {
top: 100,
containLabel: true
},
xAxis: [
{
type: 'category',
boundaryGap: false,
axisLabel: {
formatter: '{value}',
textStyle: {
color: '#333'
}
},
axisLine: {
lineStyle: {
color: '#D9D9D9'
}
},
data: xAxisData.map(function (str) {
return str.replace(' ', '\n')
})
}
],
yAxis: [
{
type: 'value',
// name: '',
axisLabel: {
textStyle: {
color: '#666'
},
formatter: (value, index, format) => {
return Math.floor(value / 3600) + '时'
}
},
max: 86400,
nameTextStyle: {
color: '#666',
fontSize: 12,
lineHeight: 40
},
splitLine: {
lineStyle: {
type: 'dashed',
color: '#E9E9E9'
}
},
axisLine: {
show: false
},
axisTick: {
show: false
}
}
],
series: [
{
name: '最后一次屏幕使用时刻',
type: 'line',
smooth: true,
// showSymbol: false,/
symbolSize: 8,
zlevel: 3,
lineStyle: {
normal: {
color: color[0],
shadowBlur: 3,
shadowColor: hexToRgba(color[0], 0.5),
shadowOffsetY: 8
}
},
areaStyle: {
// normal: {
// color: new echarts.graphic.LinearGradient(
// 0,
// 0,
// 0,
// 1,
// [
// {
// offset: 0,
// color: hexToRgba(color[0], 0.3)
// },
// {
// offset: 1,
// color: hexToRgba(color[0], 0.1)
// }
// ],
// false
// ),
shadowColor: hexToRgba(color[0], 0.1),
shadowBlur: 10
},
data: currentWeekFirstScreenTime
}
]
})
}, [])
return (
<div className="m-4 md:m-10 mt-24 p-10 bg-white dark:bg-secondary-dark-bg rounded-3xl">
<ChartsHeader category="Line" title="最后屏幕使用时刻" />
<div className="w-full">
<ReactECharts option={option} style={{ height: '600px' }}></ReactECharts>
</div>
</div>
)
}
export default Line2

+ 13
- 2
lazy-timer-fe/src/pages/Customers.jsx ファイルの表示

@ -1,4 +1,4 @@
import React from 'react';
import React, { useEffect, useState } from 'react';
import { GridComponent, ColumnsDirective, ColumnDirective, Page, Selection, Inject, Edit, Toolbar, Sort, Filter } from '@syncfusion/ej2-react-grids';
import { customersData, customersGrid } from '../data/dummy';
@ -9,11 +9,22 @@ const Customers = () => {
const toolbarOptions = ['Delete'];
const editing = { allowDeleting: true, allowEditing: true };
let [temp, setTemp] = useState([])
customersData.then(
(result) => {
setTemp(result);
}
)
return (
<div className="m-2 md:m-10 mt-24 p-2 md:p-10 bg-white rounded-3xl">
<Header category="Page" title="屏幕使用记录" />
<GridComponent
dataSource={customersData}
dataSource={temp}
enableHover={false}
allowPaging
pageSettings={{ pageCount: 5 }}

+ 24
- 17
lazy-timer-fe/src/pages/Ecommerce.jsx ファイルの表示

@ -12,6 +12,7 @@ import { earningData, medicalproBranding, recentTransactions, weeklyStats, dropd
import { useStateContext } from '../contexts/ContextProvider';
import product9 from '../data/product9.jpg';
import { getDayScreenUseTime } from '../service/getDayScreenUseTime/index'
import Gannt from './Gannt'
const DropDown = ({ currentMode }) => (
<div className="w-28 border-1 border-color px-2 py-1 rounded-md">
@ -29,6 +30,7 @@ const Ecommerce = () => {
var mm = String(today.getMonth() + 1).padStart(2, '0');
var yyyy = today.getFullYear();
const receivedJson = await getDayScreenUseTime(yyyy + '-' + mm + '-' + dd);
setEarningData2([
{
icon: <BsFillLaptopFill />,
@ -70,6 +72,8 @@ const Ecommerce = () => {
])
}, [])
return (
<div className="mt-24">
{/* 第一行四个盒子 */}
@ -78,7 +82,7 @@ const Ecommerce = () => {
<div className="flex justify-between items-center">
<div>
<p className="font-bold text-gray-400">日期</p>
<p className="text-2xl">2022年9月5</p>
<p className="text-2xl">2022年9月7</p>
</div>
@ -128,10 +132,11 @@ const Ecommerce = () => {
<div className="flex gap-10 flex-wrap justify-center">
{/* 实际的盒子 */}
<div className="bg-white dark:text-gray-200 dark:bg-secondary-dark-bg m-3 p-4 rounded-2xl" >
<div className="flex justify-between">
<p className="font-semibold text-xl">Revenue Updates</p>
<p className="font-semibold text-xl">屏幕使用记录甘特图</p>
<div className="flex items-center gap-4">
<p className="flex items-center gap-2 text-gray-600 hover:drop-shadow-xl">
{/* <p className="flex items-center gap-2 text-gray-600 hover:drop-shadow-xl">
<span>
<GoPrimitiveDot />
</span>
@ -142,12 +147,12 @@ const Ecommerce = () => {
<GoPrimitiveDot />
</span>
<span>Budget</span>
</p>
</p> */}
</div>
</div>
<div className="mt-10 flex gap-10 flex-wrap justify-center">
<div className=" border-r-1 border-color m-4 pr-10">
<div>
{/* <div>
<p>
<span className="text-3xl font-semibold">$93,438</span>
<span className="p-1.5 hover:drop-shadow-xl cursor-pointer rounded-full text-white bg-green-400 ml-3 text-xs">
@ -155,17 +160,19 @@ const Ecommerce = () => {
</span>
</p>
<p className="text-gray-500 mt-1">Budget</p>
</div>
<div className="mt-8">
</div> */}
{/* <div className="mt-8">
<p className="text-3xl font-semibold">$48,487</p>
<p className="text-gray-500 mt-1">Expense</p>
</div>
</div> */}
<div className="mt-5">
<SparkLine currentColor={currentColor} id="line-sparkLine" type="Line" height="80px" width="800px" data={SparklineAreaData} color={currentColor} />
{/* 这里弄甘特图 */}
<div>
{/* <SparkLine currentColor={currentColor} id="line-sparkLine" type="Line" height="80px" width="800px" data={SparklineAreaData} color={currentColor} /> */}
<Gannt></Gannt>
</div>
<div className="mt-10">
<div className="mt-8">
<Button
color="white"
bgColor={currentColor}
@ -174,10 +181,10 @@ const Ecommerce = () => {
/>
</div>
</div>
class="p">{ class="err">/ class="err">* class="err"> class="err"> class="err"> class="err"> class="err">
<div>
<Stacked currentMode={currentMode} width="320px" height="360px" />
</div>
</div> */}
</div>
</div>
{/* <div>
@ -212,7 +219,7 @@ const Ecommerce = () => {
</div> */}
</div>
<div className="flex gap-10 m-4 flex-wrap justify-center">
{/* <div className="flex gap-10 m-4 flex-wrap justify-center">
<div className="bg-white dark:text-gray-200 dark:bg-secondary-dark-bg p-6 rounded-2xl">
<div className="flex justify-between items-center gap-2">
<p className="text-xl font-semibold">Recent Transactions</p>
@ -263,9 +270,9 @@ const Ecommerce = () => {
<LineChart />
</div>
</div>
</div>
</div> */}
<div className="flex flex-wrap justify-center">
{/* <div className="flex flex-wrap justify-center">
<div className="md:w-400 bg-white dark:text-gray-200 dark:bg-secondary-dark-bg rounded-2xl p-6 m-3">
<div className="flex justify-between">
<p className="text-xl font-semibold">Weekly Stats</p>
@ -386,7 +393,7 @@ const Ecommerce = () => {
</div>
</div>
</div>
</div>
</div> */}
</div>
);
};

+ 199
- 0
lazy-timer-fe/src/pages/Gannt.jsx ファイルの表示

@ -0,0 +1,199 @@
import React, { useState, useEffect } from 'react'
import ReactECharts from 'echarts-for-react'
import ColorMaker from '../service/colorGenerator'
import { getSeconds } from '../service/getSeconds'
import { getAppId } from '../service/getAppId'
import { getDayScreenUse } from '../service/getDayScreenUse'
const Gannt = () => {
let [option, setOption] = useState({})
useEffect(async () => {
let categories = ['使用记录']
var startTime = +new Date()
function renderItem(params, api) {
var categoryIndex = api.value(0)
var start = api.coord([api.value(1), categoryIndex])
var end = api.coord([api.value(2), categoryIndex])
var height = api.size([0, 1])[1] * 0.6
var rectShape = echarts.graphic.clipRectByRect(
{
x: start[0],
y: start[1] - height / 2,
width: end[0] - start[0],
height: height
},
{
x: params.coordSys.x,
y: params.coordSys.y,
width: params.coordSys.width,
height: params.coordSys.height
}
)
return (
rectShape && {
type: 'rect',
shape: rectShape,
style: api.style()
}
)
}
let appIdArray = await getAppId('1')
let types = new Array(appIdArray.data.length)
for (let i = 0; i < appIdArray.data.length; i++) {
types[i] = {
appId: i + 1,
name: appIdArray.data[i].text,
color: '#' + ColorMaker.GetColor(i).Color
}
}
for (let i = 0; i < appIdArray.length; i++) {
types.push({
appId: i + 1,
name: appIdArray[i].text,
color: '#' + ColorMaker.GetColor(i).Color
})
}
let dateStr = '2022-09-07'
let useRecord = await getDayScreenUse(dateStr)
const date = new Date(dateStr)
const timestampInMs = date.getTime()
// 👇 timestamp in seconds (Unix timestamp)
const timestampInSeconds = Math.floor(date.getTime())
let data = new Array(useRecord.data.length)
for (let i = 0; i < useRecord.data.length; i++) {
data[i] = {
name: useRecord.data[i]['activity'],
value: new Array(getSeconds(useRecord.data[i]['timeStart']) * 1000, timestampInSeconds + getSeconds(useRecord.data[i]['timeStart']) * 1000, getSeconds(useRecord.data[i]['timeEnd']) * 1000 + timestampInSeconds, getSeconds(useRecord.data[i]['timeEnd']) * 1000),
itemStyle: {
normal: {
color: types[useRecord.data[i]['appId'] - 1]['color']
}
}
}
}
setOption({
tooltip: {
formatter: function (params) {
let seconds = params.value[3] / 1000
let duration = (params.value[3] - params.value[0]) / 1000
return (
params.marker +
params.name +
': ' +
Math.floor(seconds / 3600) +
'时' +
Math.floor((seconds % 3600) / 60) +
'分' +
Math.floor(seconds % 60) +
'秒' +
'<br/>' +
'持续时间: ' +
Math.floor(duration / 3600) +
'时' +
Math.floor((duration % 3600) / 60) +
'分' +
Math.floor(duration % 60) +
'秒'
)
}
},
dataZoom: [
{
type: 'slider',
filterMode: 'weakFilter',
showDataShadow: false,
top: 550,
height: 10,
borderColor: 'transparent',
backgroundColor: '#e2e2e2',
handleIcon: 'M10.7,11.9H9.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4h1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7v-1.2h6.6z M13.3,22H6.7v-1.2h6.6z M13.3,19.6H6.7v-1.2h6.6z', // jshint ignore:line
handleSize: 20,
handleStyle: {
shadowBlur: 6,
shadowOffsetX: 1,
shadowOffsetY: 2,
shadowColor: '#aaa'
},
labelFormatter: ''
},
{
type: 'inside',
filterMode: 'weakFilter'
}
],
grid: {
height: 450
},
xAxis: {
min: startTime,
scale: true,
axisLabel: {
formatter: function (val) {
let seconds = (val - startTime) / 1000 + 10620
return Math.floor(seconds / 3600) + '时' + Math.floor(seconds % 3600 / 60) + '分' + Math.floor(seconds % 60) + '秒'
}
}
},
yAxis: {
data: categories
},
series: [
{
type: 'custom',
renderItem: function (params, api) {
var categoryIndex = api.value(0)
var start = api.coord([api.value(1), categoryIndex])
var end = api.coord([api.value(2), categoryIndex])
var height = api.size([0, 1])[1] * 0.6
var rectShape = echarts.graphic.clipRectByRect(
{
x: start[0],
y: start[1] - height / 2,
width: end[0] - start[0],
height: height
},
{
x: params.coordSys.x,
y: params.coordSys.y,
width: params.coordSys.width,
height: params.coordSys.height
}
)
return (
rectShape && {
type: 'rect',
shape: rectShape,
style: api.style()
}
)
},
itemStyle: {
normal: {
opacity: 0.8
}
},
encode: {
x: [1, 2],
y: 0
},
data: data
}
]
})
}, [])
return <ReactECharts option={option} style={{ height: '800px', width: '1200px' }}></ReactECharts>
}
export default Gannt

+ 120
- 0
lazy-timer-fe/src/service/colorGenerator.js ファイルの表示

@ -0,0 +1,120 @@
function MyColor() {
this.TextColor = 'FFFFFF';
this.Color = 'FF0000';
}
var ColorMaker = {
// 最大支持颜色种类数
TotalColors: 300,
// 获取颜色 seed:颜色种子(任意int)
GetColor: (seed = 0) => {
var ret = new MyColor();
// 计算对应下标
var idx = seed % ColorMaker.TotalColors;
// 计算颜色
var colorVal = ColorMaker._CalColor(idx);
// 转成RGB 16进制字符串
ret.Color = colorVal.toString(16).padStart(6, '0');
// 计算互补色
ret.TextColor = ColorMaker._CalTextColor(ret.Color);
return ret;
},
_CalColor: (idx = 0) => {
// 默认返回红色
var ret = 0xFF0000;
// RGB的最大值
var full = 0xFFFFFF;
// 总共需要支持多少种颜色,若传0则取255
var total = ColorMaker.TotalColors > 0 ? ColorMaker.TotalColors : 0xFF;
// 将所有颜色平均分成x份
var perVal = full / total;
if (idx >= 0 && idx <= total) {
ret = perVal * idx;
}
ret = Math.round(ret);
return ret;
},
// 计算传入颜色的互补色
_CalTextColor: (input = '') => {
var R = input.substr(0, 2);
var G = input.substr(2, 2);
var B = input.substr(4, 2);
var rVal = parseInt(R, 16);
var gVal = parseInt(G, 16);
var bVal = parseInt(B, 16);
var hsl = rgbToHsl(rVal, gVal, bVal);
hsl.L = (hsl.L + 0.5) % 1.0;
var rgb = hslToRgb(hsl.H, hsl.S, hsl.L);
var ret = (rgb.R << 16) + (rgb.G << 8) + rgb.B;
return ret.toString(16).padStart(6, '0');
}
};
/**
* RGB 颜色值转换为 HSL.
* 转换公式参考自 http://en.wikipedia.org/wiki/HSL_color_space.
* r, g, b 需要在 [0, 255] 范围内
* 返回的 h, s, l [0, 1] 之间
*
* @param Number r 红色色值
* @param Number g 绿色色值
* @param Number b 蓝色色值
* @return Array HSL各值数组
*/
function rgbToHsl(r, g, b) {
r /= 255, g /= 255, b /= 255;
var max = Math.max(r, g, b), min = Math.min(r, g, b);
var h, s, l = (max + min) / 2;
if (max == min) {
h = s = 0; // achromatic
} else {
var d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch (max) {
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
case g: h = (b - r) / d + 2; break;
case b: h = (r - g) / d + 4; break;
}
h /= 6;
}
return { H: h, S: s, L: l };
}
/**
* HSL颜色值转换为RGB.
* 换算公式改编自 http://en.wikipedia.org/wiki/HSL_color_space.
* h, s, l 设定在 [0, 1] 之间
* 返回的 r, g, b [0, 255]之间
*
* @param Number h 色相
* @param Number s 饱和度
* @param Number l 亮度
* @return Array RGB色值数值
*/
function hslToRgb(h, s, l) {
var r, g, b;
if (s == 0) {
r = g = b = l; // achromatic
} else {
var hue2rgb = function hue2rgb(p, q, t) {
if (t < 0) t += 1;
if (t > 1) t -= 1;
if (t < 1 / 6) return p + (q - p) * 6 * t;
if (t < 1 / 2) return q;
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
return p;
}
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
var p = 2 * l - q;
r = hue2rgb(p, q, h + 1 / 3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1 / 3);
}
return { R: Math.round(r * 255), G: Math.round(g * 255), B: Math.round(b * 255) };
}
export default ColorMaker;

+ 8
- 0
lazy-timer-fe/src/service/getAppId.js ファイルの表示

@ -0,0 +1,8 @@
import { post } from './index'
export const getAppId = (appId) => {
return post('/getAppId', {
appId
})
}

+ 1
- 1
lazy-timer-fe/src/service/getDayActivity/index.js ファイルの表示

@ -2,6 +2,6 @@ import { post } from '../index'
export const getDayScreenUseTime = (datetimeStr) => {
return post('/getDayActivity', {
dateTimeStr
datetimeStr
})
}

+ 7
- 0
lazy-timer-fe/src/service/getDayScreenUse/index.js ファイルの表示

@ -0,0 +1,7 @@
import { post } from '../index'
export const getDayScreenUse = (datetimeStr) => {
return post('/getDayScreenUse', {
datetimeStr
})
}

+ 7
- 0
lazy-timer-fe/src/service/getSeconds.js ファイルの表示

@ -0,0 +1,7 @@
export const getSeconds = (str) => {
let hours = parseInt(str.substring(0, 2))
let minutes = parseInt(str.substring(3, 5))
let seconds = parseInt(str.substring(6, 8))
return hours * 3600 + minutes * 60 + seconds
}

読み込み中…
キャンセル
保存