diff --git a/controller/usedata.go b/controller/usedata.go index fc0a326..b936532 100644 --- a/controller/usedata.go +++ b/controller/usedata.go @@ -4,10 +4,33 @@ import ( "github.com/gin-gonic/gin" "net/http" "one-api/model" + "strconv" ) func GetAllQuotaDates(c *gin.Context) { - dates, err := model.GetAllQuotaDates() + startTimestamp, _ := strconv.ParseInt(c.Query("start_timestamp"), 10, 64) + endTimestamp, _ := strconv.ParseInt(c.Query("end_timestamp"), 10, 64) + dates, err := model.GetAllQuotaDates(startTimestamp, endTimestamp) + if err != nil { + c.JSON(http.StatusOK, gin.H{ + "success": false, + "message": err.Error(), + }) + return + } + c.JSON(http.StatusOK, gin.H{ + "success": true, + "message": "", + "data": dates, + }) + return +} + +func GetUserQuotaDates(c *gin.Context) { + userId := c.GetInt("id") + startTimestamp, _ := strconv.ParseInt(c.Query("start_timestamp"), 10, 64) + endTimestamp, _ := strconv.ParseInt(c.Query("end_timestamp"), 10, 64) + dates, err := model.GetQuotaDataByUserId(userId, startTimestamp, endTimestamp) if err != nil { c.JSON(http.StatusOK, gin.H{ "success": false, diff --git a/model/usedata.go b/model/usedata.go index ce3c86c..e00c3ce 100644 --- a/model/usedata.go +++ b/model/usedata.go @@ -74,16 +74,23 @@ func SaveQuotaDataCache() { CacheQuotaData = make(map[string]*QuotaData) } -func GetQuotaDataByUsername(username string) (quotaData []*QuotaData, err error) { +func GetQuotaDataByUsername(username string, startTime int64, endTime int64) (quotaData []*QuotaData, err error) { var quotaDatas []*QuotaData // 从quota_data表中查询数据 err = DB.Table("quota_data").Where("username = ?", username).Find("aDatas).Error return quotaDatas, err } -func GetAllQuotaDates() (quotaData []*QuotaData, err error) { +func GetQuotaDataByUserId(userId int, startTime int64, endTime int64) (quotaData []*QuotaData, err error) { var quotaDatas []*QuotaData // 从quota_data表中查询数据 - err = DB.Table("quota_data").Find("aDatas).Error + err = DB.Table("quota_data").Where("user_id = ? and created_at >= ? and created_at <= ?", userId, startTime, endTime).Find("aDatas).Error + return quotaDatas, err +} + +func GetAllQuotaDates(startTime int64, endTime int64) (quotaData []*QuotaData, err error) { + var quotaDatas []*QuotaData + // 从quota_data表中查询数据 + err = DB.Table("quota_data").Where("created_at >= ? and created_at <= ?", startTime, endTime).Find("aDatas).Error return quotaDatas, err } diff --git a/router/api-router.go b/router/api-router.go index f39a5af..3c3b999 100644 --- a/router/api-router.go +++ b/router/api-router.go @@ -116,6 +116,7 @@ func SetApiRouter(router *gin.Engine) { dataRoute := apiRouter.Group("/data") dataRoute.GET("/", middleware.AdminAuth(), controller.GetAllQuotaDates) + dataRoute.GET("/self", middleware.UserAuth(), controller.GetUserQuotaDates) logRoute.Use(middleware.CORS()) { diff --git a/web/src/components/LogsTable.js b/web/src/components/LogsTable.js index 8556493..347a681 100644 --- a/web/src/components/LogsTable.js +++ b/web/src/components/LogsTable.js @@ -422,7 +422,6 @@ const LogsTable = () => { value={end_timestamp} type='dateTime' name='end_timestamp' onChange={value => handleInputChange(value, 'end_timestamp')}/> - {/*查询*/} { isAdminUser && <> { @@ -19,8 +18,9 @@ const Detail = (props) => { }); const {username, token_name, model_name, start_timestamp, end_timestamp, channel} = inputs; const isAdminUser = isAdmin(); - let modelDataChart = null; - let modelDataPieChart = null; + const initialized = useRef(false) + const [modelDataChart, setModelDataChart] = useState(null); + const [modelDataPieChart, setModelDataPieChart] = useState(null); const [loading, setLoading] = useState(true); const [quotaData, setQuotaData] = useState([]); const [quotaDataPie, setQuotaDataPie] = useState([]); @@ -116,22 +116,22 @@ const Detail = (props) => { } }; - const loadQuotaData = async () => { + const loadQuotaData = async (lineChart, pieChart) => { setLoading(true); let url = ''; let localStartTimestamp = Date.parse(start_timestamp) / 1000; let localEndTimestamp = Date.parse(end_timestamp) / 1000; if (isAdminUser) { - url = `/api/data`; + url = `/api/data/?username=${username}&start_timestamp=${localStartTimestamp}&end_timestamp=${localEndTimestamp}`; } else { - url = `/api/data/self`; + url = `/api/data/self/?start_timestamp=${localStartTimestamp}&end_timestamp=${localEndTimestamp}`; } const res = await API.get(url); const {success, message, data} = res.data; if (success) { setQuotaData(data); - updateChart(data); + updateChart(lineChart, pieChart, data); } else { showError(message); } @@ -139,74 +139,73 @@ const Detail = (props) => { }; const refresh = async () => { - await loadQuotaData(); + await loadQuotaData(modelDataChart, modelDataPieChart); }; - const updateChart = (data) => { - if (isAdminUser) { - // 将所有用户的数据累加 - let pieData = []; - let lineData = []; - for (let i = 0; i < data.length; i++) { - const item = data[i]; - const {count, id, model_name, quota, user_id, username} = item; - // 合并model_name - let pieItem = pieData.find(item => item.model_name === model_name); - if (pieItem) { - pieItem.count += count; - } else { - pieData.push({ - "type": model_name, - "value": count - }); - } - // 合并created_at和model_name 为 lineData, created_at 数据类型是小时的时间戳 - // 转换日期格式 - let createTime = timestamp2string1(item.created_at); - let lineItem = lineData.find(item => item.Time === item.createTime && item.Model === model_name); - if (lineItem) { - lineItem.Usage += getQuotaWithUnit(quota); - } else { - lineData.push({ - "Time": createTime, - "Model": model_name, - "Usage": getQuotaWithUnit(quota) - }); - } - - } - // sort by count - pieData.sort((a, b) => b.value - a.value); - spec_line.data[0].values = lineData; - spec_pie.data[0].values = pieData; - // console.log('spec_line', spec_line); - console.log('spec_pie', spec_pie); - // modelDataChart.renderAsync(); - modelDataPieChart.updateSpec(spec_pie); - modelDataChart.updateSpec(spec_line); + const initChart = async () => { + let lineChart = modelDataChart + if (!modelDataChart) { + lineChart = new VChart(spec_line, {dom: 'model_data'}); + setModelDataChart(lineChart); + await lineChart.renderAsync(); } + let pieChart = modelDataPieChart + if (!modelDataPieChart) { + pieChart = new VChart(spec_pie, {dom: 'model_pie'}); + setModelDataPieChart(pieChart); + await pieChart.renderAsync(); + } + console.log('init vchart'); + await loadQuotaData(lineChart, pieChart) } - useEffect(() => { - refresh(); - }, []); + const updateChart = (lineChart, pieChart, data) => { + if (isAdminUser) { + // 将所有用户合并 + } + let pieData = []; + let lineData = []; + for (let i = 0; i < data.length; i++) { + const item = data[i]; + const {count, id, model_name, quota, user_id, username} = item; + // 合并model_name + let pieItem = pieData.find(item => item.type === model_name); + if (pieItem) { + pieItem.count += count; + } else { + pieData.push({ + "type": model_name, + "value": count + }); + } + // 合并created_at和model_name 为 lineData, created_at 数据类型是小时的时间戳 + // 转换日期格式 + let createTime = timestamp2string1(item.created_at); + let lineItem = lineData.find(item => item.Time === item.createTime && item.Model === model_name); + if (lineItem) { + lineItem.Usage += getQuotaWithUnit(quota); + } else { + lineData.push({ + "Time": createTime, + "Model": model_name, + "Usage": getQuotaWithUnit(quota) + }); + } + + } + // sort by count + pieData.sort((a, b) => b.value - a.value); + pieChart.updateData('id0', pieData); + lineChart.updateData('barData', lineData); + + } useEffectOnce(() => { - // 创建 vchart 实例 - if (!modelDataChart) { - modelDataChart = new VChart(spec_line, {dom: 'model_data'}); - // 绘制 - modelDataChart.renderAsync(); + if (!initialized.current) { + initialized.current = true; + initChart(); } - - if (!modelDataPieChart) { - modelDataPieChart = new VChart(spec_pie, {dom: 'model_pie'}); - // 绘制 - modelDataPieChart.renderAsync(); - } - - console.log('render vchart'); - }) + }); return ( <> @@ -227,7 +226,6 @@ const Detail = (props) => { value={end_timestamp} type='dateTime' name='end_timestamp' onChange={value => handleInputChange(value, 'end_timestamp')}/> - {/*查询*/} {/*{*/} {/* isAdminUser && <>*/} {/* { {/* onChange={value => handleInputChange(value, 'username')}/>*/} {/* */} {/*}*/} - {/**/} - {/* */} - {/**/} + + +