mirror of
https://github.com/linux-do/new-api.git
synced 2025-09-17 16:06:38 +08:00
perf: 数据看板支持选择时间粒度
This commit is contained in:
parent
d30b9321b2
commit
00306aa142
@ -26,7 +26,8 @@ var DisplayInCurrencyEnabled = true
|
|||||||
var DisplayTokenStatEnabled = true
|
var DisplayTokenStatEnabled = true
|
||||||
var DrawingEnabled = true
|
var DrawingEnabled = true
|
||||||
var DataExportEnabled = true
|
var DataExportEnabled = true
|
||||||
var DataExportInterval = 5 // unit: minute
|
var DataExportInterval = 5 // unit: minute
|
||||||
|
var DataExportDefaultTime = "hour" // unit: minute
|
||||||
|
|
||||||
// Any options with "Secret", "Token" in its key won't be return by GetOptions
|
// Any options with "Secret", "Token" in its key won't be return by GetOptions
|
||||||
|
|
||||||
|
@ -16,26 +16,27 @@ func GetStatus(c *gin.Context) {
|
|||||||
"success": true,
|
"success": true,
|
||||||
"message": "",
|
"message": "",
|
||||||
"data": gin.H{
|
"data": gin.H{
|
||||||
"start_time": common.StartTime,
|
"start_time": common.StartTime,
|
||||||
"email_verification": common.EmailVerificationEnabled,
|
"email_verification": common.EmailVerificationEnabled,
|
||||||
"github_oauth": common.GitHubOAuthEnabled,
|
"github_oauth": common.GitHubOAuthEnabled,
|
||||||
"github_client_id": common.GitHubClientId,
|
"github_client_id": common.GitHubClientId,
|
||||||
"system_name": common.SystemName,
|
"system_name": common.SystemName,
|
||||||
"logo": common.Logo,
|
"logo": common.Logo,
|
||||||
"footer_html": common.Footer,
|
"footer_html": common.Footer,
|
||||||
"wechat_qrcode": common.WeChatAccountQRCodeImageURL,
|
"wechat_qrcode": common.WeChatAccountQRCodeImageURL,
|
||||||
"wechat_login": common.WeChatAuthEnabled,
|
"wechat_login": common.WeChatAuthEnabled,
|
||||||
"server_address": common.ServerAddress,
|
"server_address": common.ServerAddress,
|
||||||
"price": common.Price,
|
"price": common.Price,
|
||||||
"turnstile_check": common.TurnstileCheckEnabled,
|
"turnstile_check": common.TurnstileCheckEnabled,
|
||||||
"turnstile_site_key": common.TurnstileSiteKey,
|
"turnstile_site_key": common.TurnstileSiteKey,
|
||||||
"top_up_link": common.TopUpLink,
|
"top_up_link": common.TopUpLink,
|
||||||
"chat_link": common.ChatLink,
|
"chat_link": common.ChatLink,
|
||||||
"quota_per_unit": common.QuotaPerUnit,
|
"quota_per_unit": common.QuotaPerUnit,
|
||||||
"display_in_currency": common.DisplayInCurrencyEnabled,
|
"display_in_currency": common.DisplayInCurrencyEnabled,
|
||||||
"enable_batch_update": common.BatchUpdateEnabled,
|
"enable_batch_update": common.BatchUpdateEnabled,
|
||||||
"enable_drawing": common.DrawingEnabled,
|
"enable_drawing": common.DrawingEnabled,
|
||||||
"enable_data_export": common.DataExportEnabled,
|
"enable_data_export": common.DataExportEnabled,
|
||||||
|
"data_export_default_time": common.DataExportDefaultTime,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
|
@ -79,6 +79,7 @@ func InitOptionMap() {
|
|||||||
common.OptionMap["QuotaPerUnit"] = strconv.FormatFloat(common.QuotaPerUnit, 'f', -1, 64)
|
common.OptionMap["QuotaPerUnit"] = strconv.FormatFloat(common.QuotaPerUnit, 'f', -1, 64)
|
||||||
common.OptionMap["RetryTimes"] = strconv.Itoa(common.RetryTimes)
|
common.OptionMap["RetryTimes"] = strconv.Itoa(common.RetryTimes)
|
||||||
common.OptionMap["DataExportInterval"] = strconv.Itoa(common.DataExportInterval)
|
common.OptionMap["DataExportInterval"] = strconv.Itoa(common.DataExportInterval)
|
||||||
|
common.OptionMap["DataExportDefaultTime"] = common.DataExportDefaultTime
|
||||||
|
|
||||||
common.OptionMapRWMutex.Unlock()
|
common.OptionMapRWMutex.Unlock()
|
||||||
loadOptionsFromDatabase()
|
loadOptionsFromDatabase()
|
||||||
@ -228,6 +229,8 @@ func updateOptionMap(key string, value string) (err error) {
|
|||||||
common.RetryTimes, _ = strconv.Atoi(value)
|
common.RetryTimes, _ = strconv.Atoi(value)
|
||||||
case "DataExportInterval":
|
case "DataExportInterval":
|
||||||
common.DataExportInterval, _ = strconv.Atoi(value)
|
common.DataExportInterval, _ = strconv.Atoi(value)
|
||||||
|
case "DataExportDefaultTime":
|
||||||
|
common.DataExportDefaultTime = value
|
||||||
case "ModelRatio":
|
case "ModelRatio":
|
||||||
err = common.UpdateModelRatioByJSONString(value)
|
err = common.UpdateModelRatioByJSONString(value)
|
||||||
case "GroupRatio":
|
case "GroupRatio":
|
||||||
|
@ -51,6 +51,7 @@ function App() {
|
|||||||
localStorage.setItem('display_in_currency', data.display_in_currency);
|
localStorage.setItem('display_in_currency', data.display_in_currency);
|
||||||
localStorage.setItem('enable_drawing', data.enable_drawing);
|
localStorage.setItem('enable_drawing', data.enable_drawing);
|
||||||
localStorage.setItem('enable_data_export', data.enable_data_export);
|
localStorage.setItem('enable_data_export', data.enable_data_export);
|
||||||
|
localStorage.setItem('data_export_default_time', data.data_export_default_time);
|
||||||
if (data.chat_link) {
|
if (data.chat_link) {
|
||||||
localStorage.setItem('chat_link', data.chat_link);
|
localStorage.setItem('chat_link', data.chat_link);
|
||||||
} else {
|
} else {
|
||||||
|
@ -23,13 +23,19 @@ const OperationSetting = () => {
|
|||||||
DisplayTokenStatEnabled: '',
|
DisplayTokenStatEnabled: '',
|
||||||
DrawingEnabled: '',
|
DrawingEnabled: '',
|
||||||
DataExportEnabled: '',
|
DataExportEnabled: '',
|
||||||
|
DataExportDefaultTime: 'hour',
|
||||||
DataExportInterval: 5,
|
DataExportInterval: 5,
|
||||||
RetryTimes: 0
|
RetryTimes: 0
|
||||||
});
|
});
|
||||||
const [originInputs, setOriginInputs] = useState({});
|
const [originInputs, setOriginInputs] = useState({});
|
||||||
let [loading, setLoading] = useState(false);
|
let [loading, setLoading] = useState(false);
|
||||||
let [historyTimestamp, setHistoryTimestamp] = useState(timestamp2string(now.getTime() / 1000 - 30 * 24 * 3600)); // a month ago
|
let [historyTimestamp, setHistoryTimestamp] = useState(timestamp2string(now.getTime() / 1000 - 30 * 24 * 3600)); // a month ago
|
||||||
|
// 精确时间选项(小时,天,周)
|
||||||
|
const timeOptions = [
|
||||||
|
{key: 'hour', text: '小时', value: 'hour'},
|
||||||
|
{key: 'day', text: '天', value: 'day'},
|
||||||
|
{key: 'week', text: '周', value: 'week'}
|
||||||
|
];
|
||||||
const getOptions = async () => {
|
const getOptions = async () => {
|
||||||
const res = await API.get('/api/option/');
|
const res = await API.get('/api/option/');
|
||||||
const {success, message, data} = res.data;
|
const {success, message, data} = res.data;
|
||||||
@ -71,7 +77,10 @@ const OperationSetting = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleInputChange = async (e, {name, value}) => {
|
const handleInputChange = async (e, {name, value}) => {
|
||||||
if (name.endsWith('Enabled') || name === 'DataExportInterval') {
|
if (name.endsWith('Enabled') || name === 'DataExportInterval' || name === 'DataExportDefaultTime') {
|
||||||
|
if (name === 'DataExportDefaultTime') {
|
||||||
|
localStorage.setItem('data_export_default_time', value);
|
||||||
|
}
|
||||||
await updateOption(name, value);
|
await updateOption(name, value);
|
||||||
} else {
|
} else {
|
||||||
setInputs((inputs) => ({...inputs, [name]: value}));
|
setInputs((inputs) => ({...inputs, [name]: value}));
|
||||||
@ -234,15 +243,28 @@ const OperationSetting = () => {
|
|||||||
name='LogConsumeEnabled'
|
name='LogConsumeEnabled'
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</Form.Group>
|
</Form.Group>
|
||||||
<Form.Group inline>
|
<Form.Group widths={4}>
|
||||||
<Form.Checkbox
|
<Form.Input label='目标时间' value={historyTimestamp} type='datetime-local'
|
||||||
checked={inputs.DataExportEnabled === 'true'}
|
name='history_timestamp'
|
||||||
label='启用数据看板(实验性)'
|
onChange={(e, {name, value}) => {
|
||||||
name='DataExportEnabled'
|
setHistoryTimestamp(value);
|
||||||
onChange={handleInputChange}
|
}}/>
|
||||||
/>
|
</Form.Group>
|
||||||
|
<Form.Button onClick={() => {
|
||||||
|
deleteHistoryLogs().then();
|
||||||
|
}}>清理历史日志</Form.Button>
|
||||||
|
<Divider/>
|
||||||
|
<Header as='h3'>
|
||||||
|
数据看板
|
||||||
|
</Header>
|
||||||
|
<Form.Checkbox
|
||||||
|
checked={inputs.DataExportEnabled === 'true'}
|
||||||
|
label='启用数据看板(实验性)'
|
||||||
|
name='DataExportEnabled'
|
||||||
|
onChange={handleInputChange}
|
||||||
|
/>
|
||||||
|
<Form.Group>
|
||||||
<Form.Input
|
<Form.Input
|
||||||
label='数据看板更新间隔(分钟,设置过短会影响数据库性能)'
|
label='数据看板更新间隔(分钟,设置过短会影响数据库性能)'
|
||||||
name='DataExportInterval'
|
name='DataExportInterval'
|
||||||
@ -254,19 +276,17 @@ const OperationSetting = () => {
|
|||||||
value={inputs.DataExportInterval}
|
value={inputs.DataExportInterval}
|
||||||
placeholder='数据看板更新间隔(分钟,设置过短会影响数据库性能)'
|
placeholder='数据看板更新间隔(分钟,设置过短会影响数据库性能)'
|
||||||
/>
|
/>
|
||||||
|
<Form.Select
|
||||||
|
label='数据看板默认时间粒度(仅修改展示粒度,统计精确到小时)'
|
||||||
|
options={timeOptions}
|
||||||
|
name='DataExportDefaultTime'
|
||||||
|
onChange={handleInputChange}
|
||||||
|
autoComplete='new-password'
|
||||||
|
value={inputs.DataExportDefaultTime}
|
||||||
|
placeholder='数据看板默认时间粒度'
|
||||||
|
/>
|
||||||
</Form.Group>
|
</Form.Group>
|
||||||
<Divider/>
|
<Divider/>
|
||||||
<Form.Group widths={4}>
|
|
||||||
<Form.Input label='目标时间' value={historyTimestamp} type='datetime-local'
|
|
||||||
name='history_timestamp'
|
|
||||||
onChange={(e, {name, value}) => {
|
|
||||||
setHistoryTimestamp(value);
|
|
||||||
}}/>
|
|
||||||
</Form.Group>
|
|
||||||
<Form.Button onClick={() => {
|
|
||||||
deleteHistoryLogs().then();
|
|
||||||
}}>清理历史日志</Form.Button>
|
|
||||||
<Divider/>
|
|
||||||
<Header as='h3'>
|
<Header as='h3'>
|
||||||
监控设置
|
监控设置
|
||||||
</Header>
|
</Header>
|
||||||
|
@ -171,7 +171,7 @@ export function timestamp2string(timestamp) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function timestamp2string1(timestamp) {
|
export function timestamp2string1(timestamp, dataExportDefaultTime = 'hour') {
|
||||||
let date = new Date(timestamp * 1000);
|
let date = new Date(timestamp * 1000);
|
||||||
// let year = date.getFullYear().toString();
|
// let year = date.getFullYear().toString();
|
||||||
let month = (date.getMonth() + 1).toString();
|
let month = (date.getMonth() + 1).toString();
|
||||||
@ -186,15 +186,22 @@ export function timestamp2string1(timestamp) {
|
|||||||
if (hour.length === 1) {
|
if (hour.length === 1) {
|
||||||
hour = '0' + hour;
|
hour = '0' + hour;
|
||||||
}
|
}
|
||||||
return (
|
let str = month + '-' + day
|
||||||
// year +
|
if (dataExportDefaultTime === 'hour') {
|
||||||
// '-' +
|
str += ' ' + hour + ":00"
|
||||||
month +
|
} else if (dataExportDefaultTime === 'week') {
|
||||||
'-' +
|
let nextWeek = new Date(timestamp * 1000 + 6 * 24 * 60 * 60 * 1000);
|
||||||
day +
|
let nextMonth = (nextWeek.getMonth() + 1).toString();
|
||||||
' ' +
|
let nextDay = nextWeek.getDate().toString();
|
||||||
hour + ":00"
|
if (nextMonth.length === 1) {
|
||||||
);
|
nextMonth = '0' + nextMonth;
|
||||||
|
}
|
||||||
|
if (nextDay.length === 1) {
|
||||||
|
nextDay = '0' + nextDay;
|
||||||
|
}
|
||||||
|
str += ' - ' + nextMonth + '-' + nextDay
|
||||||
|
}
|
||||||
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function downloadTextAsFile(text, filename) {
|
export function downloadTextAsFile(text, filename) {
|
||||||
|
@ -12,17 +12,18 @@ import {
|
|||||||
} from "../../helpers/render";
|
} from "../../helpers/render";
|
||||||
|
|
||||||
const Detail = (props) => {
|
const Detail = (props) => {
|
||||||
|
const formRef = useRef();
|
||||||
let now = new Date();
|
let now = new Date();
|
||||||
const [inputs, setInputs] = useState({
|
const [inputs, setInputs] = useState({
|
||||||
username: '',
|
username: '',
|
||||||
token_name: '',
|
token_name: '',
|
||||||
model_name: '',
|
model_name: '',
|
||||||
start_timestamp: timestamp2string(now.getTime() / 1000 - 86400),
|
start_timestamp: localStorage.getItem('data_export_default_time') === 'hour' ? timestamp2string(now.getTime() / 1000 - 86400) : (localStorage.getItem('data_export_default_time') === 'week' ? timestamp2string(now.getTime() / 1000 - 86400 * 30) : timestamp2string(now.getTime() / 1000 - 86400 * 7)),
|
||||||
end_timestamp: timestamp2string(now.getTime() / 1000 + 3600),
|
end_timestamp: timestamp2string(now.getTime() / 1000 + 3600),
|
||||||
channel: ''
|
channel: '',
|
||||||
|
data_export_default_time: ''
|
||||||
});
|
});
|
||||||
const {username, token_name, model_name, start_timestamp, end_timestamp, channel} = inputs;
|
const {username, model_name, start_timestamp, end_timestamp, channel} = inputs;
|
||||||
const isAdminUser = isAdmin();
|
const isAdminUser = isAdmin();
|
||||||
const initialized = useRef(false)
|
const initialized = useRef(false)
|
||||||
const [modelDataChart, setModelDataChart] = useState(null);
|
const [modelDataChart, setModelDataChart] = useState(null);
|
||||||
@ -31,8 +32,13 @@ const Detail = (props) => {
|
|||||||
const [quotaData, setQuotaData] = useState([]);
|
const [quotaData, setQuotaData] = useState([]);
|
||||||
const [consumeQuota, setConsumeQuota] = useState(0);
|
const [consumeQuota, setConsumeQuota] = useState(0);
|
||||||
const [times, setTimes] = useState(0);
|
const [times, setTimes] = useState(0);
|
||||||
|
const [dataExportDefaultTime, setDataExportDefaultTime] = useState(localStorage.getItem('data_export_default_time') || 'hour');
|
||||||
|
|
||||||
const handleInputChange = (value, name) => {
|
const handleInputChange = (value, name) => {
|
||||||
|
if (name === 'data_export_default_time') {
|
||||||
|
setDataExportDefaultTime(value);
|
||||||
|
return
|
||||||
|
}
|
||||||
setInputs((inputs) => ({...inputs, [name]: value}));
|
setInputs((inputs) => ({...inputs, [name]: value}));
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -41,8 +47,7 @@ const Detail = (props) => {
|
|||||||
data: [
|
data: [
|
||||||
{
|
{
|
||||||
id: 'barData',
|
id: 'barData',
|
||||||
values: [
|
values: []
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
xField: 'Time',
|
xField: 'Time',
|
||||||
@ -54,7 +59,7 @@ const Detail = (props) => {
|
|||||||
},
|
},
|
||||||
title: {
|
title: {
|
||||||
visible: true,
|
visible: true,
|
||||||
text: '模型消耗分布(小时)',
|
text: '模型消耗分布',
|
||||||
subtext: '0'
|
subtext: '0'
|
||||||
},
|
},
|
||||||
bar: {
|
bar: {
|
||||||
@ -104,7 +109,7 @@ const Detail = (props) => {
|
|||||||
{
|
{
|
||||||
id: 'id0',
|
id: 'id0',
|
||||||
values: [
|
values: [
|
||||||
{ type: 'null', value: '0' },
|
{type: 'null', value: '0'},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@ -163,9 +168,9 @@ const Detail = (props) => {
|
|||||||
let localStartTimestamp = Date.parse(start_timestamp) / 1000;
|
let localStartTimestamp = Date.parse(start_timestamp) / 1000;
|
||||||
let localEndTimestamp = Date.parse(end_timestamp) / 1000;
|
let localEndTimestamp = Date.parse(end_timestamp) / 1000;
|
||||||
if (isAdminUser) {
|
if (isAdminUser) {
|
||||||
url = `/api/data/?username=${username}&start_timestamp=${localStartTimestamp}&end_timestamp=${localEndTimestamp}`;
|
url = `/api/data/?username=${username}&start_timestamp=${localStartTimestamp}&end_timestamp=${localEndTimestamp}&default_time=${dataExportDefaultTime}`;
|
||||||
} else {
|
} else {
|
||||||
url = `/api/data/self/?start_timestamp=${localStartTimestamp}&end_timestamp=${localEndTimestamp}`;
|
url = `/api/data/self/?start_timestamp=${localStartTimestamp}&end_timestamp=${localEndTimestamp}&default_time=${dataExportDefaultTime}`;
|
||||||
}
|
}
|
||||||
const res = await API.get(url);
|
const res = await API.get(url);
|
||||||
const {success, message, data} = res.data;
|
const {success, message, data} = res.data;
|
||||||
@ -179,6 +184,16 @@ const Detail = (props) => {
|
|||||||
'created_at': now.getTime() / 1000
|
'created_at': now.getTime() / 1000
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
// 根据dataExportDefaultTime重制时间粒度
|
||||||
|
let timeGranularity = 3600;
|
||||||
|
if (dataExportDefaultTime === 'day') {
|
||||||
|
timeGranularity = 86400;
|
||||||
|
} else if (dataExportDefaultTime === 'week') {
|
||||||
|
timeGranularity = 604800;
|
||||||
|
}
|
||||||
|
data.forEach(item => {
|
||||||
|
item['created_at'] = Math.floor(item['created_at'] / timeGranularity) * timeGranularity;
|
||||||
|
});
|
||||||
updateChart(lineChart, pieChart, data);
|
updateChart(lineChart, pieChart, data);
|
||||||
} else {
|
} else {
|
||||||
showError(message);
|
showError(message);
|
||||||
@ -190,7 +205,7 @@ const Detail = (props) => {
|
|||||||
await loadQuotaData(modelDataChart, modelDataPieChart);
|
await loadQuotaData(modelDataChart, modelDataPieChart);
|
||||||
};
|
};
|
||||||
|
|
||||||
const initChart = async () => {
|
const initChart = async () => {
|
||||||
let lineChart = modelDataChart
|
let lineChart = modelDataChart
|
||||||
if (!modelDataChart) {
|
if (!modelDataChart) {
|
||||||
lineChart = new VChart(spec_line, {dom: 'model_data'});
|
lineChart = new VChart(spec_line, {dom: 'model_data'});
|
||||||
@ -231,7 +246,7 @@ const Detail = (props) => {
|
|||||||
}
|
}
|
||||||
// 合并created_at和model_name 为 lineData, created_at 数据类型是小时的时间戳
|
// 合并created_at和model_name 为 lineData, created_at 数据类型是小时的时间戳
|
||||||
// 转换日期格式
|
// 转换日期格式
|
||||||
let createTime = timestamp2string1(item.created_at);
|
let createTime = timestamp2string1(item.created_at, dataExportDefaultTime);
|
||||||
let lineItem = lineData.find(it => it.Time === createTime && it.Model === item.model_name);
|
let lineItem = lineData.find(it => it.Time === createTime && it.Model === item.model_name);
|
||||||
if (lineItem) {
|
if (lineItem) {
|
||||||
lineItem.Usage += parseFloat(getQuotaWithUnit(item.quota));
|
lineItem.Usage += parseFloat(getQuotaWithUnit(item.quota));
|
||||||
@ -263,6 +278,13 @@ const Detail = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
// setDataExportDefaultTime(localStorage.getItem('data_export_default_time'));
|
||||||
|
// if (dataExportDefaultTime === 'day') {
|
||||||
|
// // 设置开始时间为7天前
|
||||||
|
// let st = timestamp2string(now.getTime() / 1000 - 86400 * 7)
|
||||||
|
// inputs.start_timestamp = st;
|
||||||
|
// formRef.current.formApi.setValue('start_timestamp', st);
|
||||||
|
// }
|
||||||
if (!initialized.current) {
|
if (!initialized.current) {
|
||||||
initialized.current = true;
|
initialized.current = true;
|
||||||
initChart();
|
initChart();
|
||||||
@ -276,7 +298,7 @@ const Detail = (props) => {
|
|||||||
<h3>数据看板</h3>
|
<h3>数据看板</h3>
|
||||||
</Layout.Header>
|
</Layout.Header>
|
||||||
<Layout.Content>
|
<Layout.Content>
|
||||||
<Form layout='horizontal' style={{marginTop: 10}}>
|
<Form ref={formRef} layout='horizontal' style={{marginTop: 10}}>
|
||||||
<>
|
<>
|
||||||
<Form.DatePicker field="start_timestamp" label='起始时间' style={{width: 272}}
|
<Form.DatePicker field="start_timestamp" label='起始时间' style={{width: 272}}
|
||||||
initValue={start_timestamp}
|
initValue={start_timestamp}
|
||||||
@ -288,6 +310,18 @@ const Detail = (props) => {
|
|||||||
value={end_timestamp} type='dateTime'
|
value={end_timestamp} type='dateTime'
|
||||||
name='end_timestamp'
|
name='end_timestamp'
|
||||||
onChange={value => handleInputChange(value, 'end_timestamp')}/>
|
onChange={value => handleInputChange(value, 'end_timestamp')}/>
|
||||||
|
<Form.Select field="data_export_default_time" label='时间粒度' style={{width: 176}}
|
||||||
|
initValue={dataExportDefaultTime}
|
||||||
|
placeholder={'时间粒度'} name='data_export_default_time'
|
||||||
|
optionList={
|
||||||
|
[
|
||||||
|
{label: '小时', value: 'hour'},
|
||||||
|
{label: '天', value: 'day'},
|
||||||
|
{label: '周', value: 'week'}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
onChange={value => handleInputChange(value, 'data_export_default_time')}>
|
||||||
|
</Form.Select>
|
||||||
{
|
{
|
||||||
isAdminUser && <>
|
isAdminUser && <>
|
||||||
<Form.Input field="username" label='用户名称' style={{width: 176}} value={username}
|
<Form.Input field="username" label='用户名称' style={{width: 176}} value={username}
|
||||||
|
Loading…
Reference in New Issue
Block a user