first
This commit is contained in:
328
safekiso_admin/pages/admin/statistics/byterm/[hero].vue
Normal file
328
safekiso_admin/pages/admin/statistics/byterm/[hero].vue
Normal file
@@ -0,0 +1,328 @@
|
||||
<!-- This example requires Tailwind CSS v2.0+ -->
|
||||
<template>
|
||||
<div class="pb-8 px-4 sm:px-6 lg:px-8">
|
||||
<div class="sm:flex sm:items-center">
|
||||
<div class="sm:flex-auto">
|
||||
<h1 class="text-xl font-semibold text-gray-900">
|
||||
API 사용 통계 {{ hero == 'usage' ? '(사용량)' : '(단어)' }}
|
||||
</h1>
|
||||
<p class="mt-2 text-sm text-gray-700">
|
||||
사용량 통계를 보여 줍니다. 구분 항목으로 시간별, 날짜별,
|
||||
월별 구분이 가능합니다.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<select
|
||||
id="targetUnit"
|
||||
v-model="targetUnit"
|
||||
name="targetUnit"
|
||||
class="mt-0 block pl-3 pr-10 py-2 text-base border-gray-300 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm rounded-md"
|
||||
@change="onChange($event)"
|
||||
>
|
||||
<option
|
||||
v-for="unit in units"
|
||||
:key="unit.key"
|
||||
:selected="unit.current"
|
||||
:value="unit.key"
|
||||
>
|
||||
<span class="truncate">
|
||||
{{ unit.key }}
|
||||
</span>
|
||||
</option>
|
||||
</select>
|
||||
|
||||
<Datepicker
|
||||
v-model="date"
|
||||
class="w-64 mt-4 sm:mt-0 sm:ml-2 sm:flex-none"
|
||||
range
|
||||
multi-calendars
|
||||
multi-calendars-solo
|
||||
:format="inputFormat"
|
||||
:preview-format="previewFormat"
|
||||
@update:modelValue="handleDate"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<StatisticsTable1
|
||||
:headings="listHeadings"
|
||||
:actions="listActions"
|
||||
:keys="listKeys"
|
||||
:data="listData"
|
||||
:action-key="actionKey"
|
||||
:column-filter="columnFilter"
|
||||
:do-action="doAction"
|
||||
/>
|
||||
|
||||
<div class="p-0 rounded-bl-2xl rounded-br-2xl md:px-0">
|
||||
<button
|
||||
type="button"
|
||||
class="relative inline-flex items-center px-4 py-2 border border-gray-300 shadow-sm text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none"
|
||||
@click="doDownload()"
|
||||
>
|
||||
<span> 엑셀파일로 다운로드 </span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Datepicker from '@vuepic/vue-datepicker';
|
||||
import '@vuepic/vue-datepicker/dist/main.css';
|
||||
|
||||
definePageMeta({
|
||||
middleware: 'check-auth-admin',
|
||||
});
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
const route = useRoute();
|
||||
const hero = ref(route.params.hero);
|
||||
|
||||
const targetUID = ref(route.query.uid ? route.query.uid : 'all');
|
||||
const targetKey = ref(route.query.key ? route.query.key : 'all');
|
||||
const targetUnit = ref(route.query.unit ? route.query.unit : 'day');
|
||||
|
||||
const { $dayjs } = useNuxtApp();
|
||||
|
||||
const targetDate = ref($dayjs(new Date().toISOString()).format('YYYY'));
|
||||
const targetDateMonth = ref($dayjs(new Date().toISOString()).format('YYYY'));
|
||||
const targetDateDay = ref({
|
||||
month: new Date().getMonth(),
|
||||
year: new Date().getFullYear,
|
||||
});
|
||||
const targetDateHour = ref($dayjs(new Date().toISOString()));
|
||||
|
||||
const units = ref([
|
||||
{ current: targetUnit.value == 'year', key: 'year' },
|
||||
{ current: targetUnit.value == 'month', key: 'month' },
|
||||
{ current: targetUnit.value == 'day', key: 'day' },
|
||||
{ current: targetUnit.value == 'hour', key: 'hour' },
|
||||
]);
|
||||
|
||||
function onChange(e) {
|
||||
console.log('targetUnit.value=', targetUnit.value);
|
||||
|
||||
navigateTo(
|
||||
'/admin/statistics/byterm/' +
|
||||
hero.value +
|
||||
'?unit=' +
|
||||
targetUnit.value +
|
||||
'&uid=' +
|
||||
targetUID.value +
|
||||
'&key=' +
|
||||
targetKey.value
|
||||
);
|
||||
refresh();
|
||||
|
||||
units.value = [
|
||||
{ current: targetUnit.value == 'year', key: 'year' },
|
||||
{ current: targetUnit.value == 'month', key: 'month' },
|
||||
{ current: targetUnit.value == 'day', key: 'day' },
|
||||
{ current: targetUnit.value == 'hour', key: 'hour' },
|
||||
];
|
||||
|
||||
refresh();
|
||||
}
|
||||
|
||||
const date = ref([]);
|
||||
|
||||
const inputFormat = (date) => {
|
||||
// console.log('huk date=', date);
|
||||
if (date.length == 1) {
|
||||
const day = date[0].getDate();
|
||||
const month = date[0].getMonth() + 1;
|
||||
const year = date[0].getFullYear();
|
||||
|
||||
return `${day}/${month}/${year}`;
|
||||
} else if (date.length == 2) {
|
||||
const day1 = date[0].getDate();
|
||||
const month1 = date[0].getMonth() + 1;
|
||||
const year1 = date[0].getFullYear();
|
||||
const day2 = date[1].getDate();
|
||||
const month2 = date[1].getMonth() + 1;
|
||||
const year2 = date[1].getFullYear();
|
||||
|
||||
return `${year1}-${month1}-${day1} ~ ${year2}-${month2}-${day2}`;
|
||||
}
|
||||
};
|
||||
|
||||
const previewFormat = (date) => {
|
||||
// console.log('huk date=', date);
|
||||
if (date.length == 1) {
|
||||
const day = date[0].getDate();
|
||||
const month = date[0].getMonth() + 1;
|
||||
const year = date[0].getFullYear();
|
||||
|
||||
return `${day}/${month}/${year}`;
|
||||
} else if (date.length == 2) {
|
||||
const day1 = date[0].getDate();
|
||||
const month1 = date[0].getMonth() + 1;
|
||||
const year1 = date[0].getFullYear();
|
||||
const day2 = date[1].getDate();
|
||||
const month2 = date[1].getMonth() + 1;
|
||||
const year2 = date[1].getFullYear();
|
||||
|
||||
return `${year1}-${month1}-${day1} ~ ${year2}-${month2}-${day2}`;
|
||||
}
|
||||
};
|
||||
|
||||
const endDate = new Date();
|
||||
const startDate = new Date(new Date().setDate(endDate.getDate() - 7));
|
||||
|
||||
date.value = [startDate, endDate];
|
||||
|
||||
const startDateTag = ref($dayjs(startDate.toISOString()).format('YYYYMMDDHH'));
|
||||
const endDateTag = ref($dayjs(endDate.toISOString()).format('YYYYMMDDHH'));
|
||||
|
||||
function doDownload() {
|
||||
const anchor = document.createElement('a');
|
||||
|
||||
let urlBase = '';
|
||||
|
||||
const currentHost = window.location.host.toLowerCase();
|
||||
const currentProtocol = window.location.protocol;
|
||||
const currentDomain = _utils.getDomain(window.location.href);
|
||||
|
||||
const apiBaseUrl = _crossCtl.config['API_BASE_URL'];
|
||||
|
||||
console.log('currentHost=', currentHost);
|
||||
console.log('currentProtocol=', currentProtocol);
|
||||
console.log('currentDomain=', currentDomain);
|
||||
|
||||
console.log('apiBaseUrl=', apiBaseUrl);
|
||||
|
||||
if (apiBaseUrl.indexOf(currentHost) == -1) {
|
||||
urlBase = apiBaseUrl;
|
||||
} else {
|
||||
urlBase = '/api/';
|
||||
}
|
||||
|
||||
console.log('urlBase=', urlBase);
|
||||
|
||||
anchor.href =
|
||||
urlBase +
|
||||
'local/download/report_' +
|
||||
hero.value +
|
||||
'_' +
|
||||
startDateTag.value +
|
||||
'_' +
|
||||
endDateTag.value +
|
||||
'.xlsx?tag=' +
|
||||
hero.value +
|
||||
'&startDateTag=' +
|
||||
startDateTag.value +
|
||||
'&endDateTag=' +
|
||||
endDateTag.value +
|
||||
'&unit=' +
|
||||
targetUnit.value +
|
||||
'&uid=' +
|
||||
targetUID.value +
|
||||
'&key=' +
|
||||
targetKey.value;
|
||||
|
||||
anchor.target = '_blank';
|
||||
|
||||
anchor.click();
|
||||
}
|
||||
|
||||
const listHeadings =
|
||||
hero.value == 'usage'
|
||||
? [
|
||||
{
|
||||
title: 'date',
|
||||
key: 'date_tag',
|
||||
},
|
||||
{
|
||||
title: 'total',
|
||||
key: 'total',
|
||||
},
|
||||
{
|
||||
title: 'hit',
|
||||
key: 'hit',
|
||||
},
|
||||
{
|
||||
title: 'size',
|
||||
key: 'size',
|
||||
},
|
||||
]
|
||||
: [
|
||||
{
|
||||
title: 'word',
|
||||
key: 'word',
|
||||
widthRatio: '100',
|
||||
},
|
||||
{
|
||||
title: 'count',
|
||||
key: 'count_sum',
|
||||
},
|
||||
];
|
||||
const listActions = [];
|
||||
const actionKey = 'serial';
|
||||
const listKeys = [
|
||||
'serial',
|
||||
'date_tag',
|
||||
'total',
|
||||
'hit',
|
||||
'size',
|
||||
'uniq_ip',
|
||||
'uniq_referrer',
|
||||
'updated',
|
||||
];
|
||||
const listData = ref([]);
|
||||
|
||||
function columnFilter(key, val) {
|
||||
// console.log('columnFilter(), key = ', key, ', val = ', val);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
function doAction(tag, target) {
|
||||
console.log('on doAction(), tag=', tag, ', target=', target);
|
||||
router.push({
|
||||
name: 'key-edit',
|
||||
params: { target: target },
|
||||
});
|
||||
}
|
||||
|
||||
async function refresh() {
|
||||
const responseJson = await _crossCtl.doComm(
|
||||
'local/select',
|
||||
hero.value == 'usage'
|
||||
? 'admin:statistics:usage'
|
||||
: 'admin:statistics:word',
|
||||
{
|
||||
unit: targetUnit.value,
|
||||
uid: targetUID.value,
|
||||
key: targetKey.value,
|
||||
startDateTag: startDateTag.value,
|
||||
endDateTag: endDateTag.value,
|
||||
}
|
||||
);
|
||||
|
||||
for (let i = 0; i < responseJson['data'].length; i++) {
|
||||
responseJson['data'][i]['hit_ratio'] =
|
||||
(
|
||||
(responseJson['data'][i]['hit'] /
|
||||
responseJson['data'][i]['total']) *
|
||||
100
|
||||
).toFixed(2) + '%';
|
||||
responseJson['data'][i]['size_avg'] = _utils.formatBytes(
|
||||
responseJson['data'][i]['size'] / responseJson['data'][i]['total'],
|
||||
2
|
||||
);
|
||||
}
|
||||
|
||||
listData.value = responseJson['data'];
|
||||
|
||||
console.log('listData.value=', listData.value);
|
||||
}
|
||||
|
||||
function handleDate(date) {
|
||||
console.log('huk date = ', date);
|
||||
startDateTag.value = $dayjs(date[0].toISOString()).format('YYYYMMDDHH');
|
||||
endDateTag.value = $dayjs(date[1].toISOString()).format('YYYYMMDDHH');
|
||||
refresh();
|
||||
}
|
||||
|
||||
refresh();
|
||||
</script>
|
||||
194
safekiso_admin/pages/admin/statistics/index.vue
Normal file
194
safekiso_admin/pages/admin/statistics/index.vue
Normal file
@@ -0,0 +1,194 @@
|
||||
<template>
|
||||
<div class="m-8">
|
||||
<div class="space-y-8 divide-y divide-gray-200 sm:space-y-5">
|
||||
<div>
|
||||
<div class="sm:flex sm:items-center">
|
||||
<div class="sm:flex-auto">
|
||||
<h1 class="text-xl font-semibold text-gray-900">
|
||||
전체 사용량 통계
|
||||
</h1>
|
||||
<p class="mt-2 text-sm text-gray-700">
|
||||
전체 서버의 사용량 통계를 확인 합니다.
|
||||
</p>
|
||||
</div>
|
||||
<img
|
||||
v-if="inPregressFlag"
|
||||
width="32"
|
||||
src="/loading-load-2.gif"
|
||||
/>
|
||||
<div class="mt-4 sm:mt-0 sm:ml-16 sm:flex-none">
|
||||
<button
|
||||
type="button"
|
||||
class="ml-3 inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
|
||||
@click="
|
||||
navigateTo('/admin/statistics/byterm/usage')
|
||||
"
|
||||
>
|
||||
상세 사용량 통계
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="ml-3 inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
|
||||
@click="navigateTo('/admin/statistics/byterm/word')"
|
||||
>
|
||||
상세 단어 통계
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<section aria-labelledby="applicant-information-title">
|
||||
<div class="bg-white mt-3 shadow sm:rounded-lg">
|
||||
<div class="px-4 py-5 sm:px-6">
|
||||
<h2
|
||||
id="applicant-information-title"
|
||||
class="text-lg font-medium leading-6 text-gray-900"
|
||||
>
|
||||
최근 24시간 사용량
|
||||
</h2>
|
||||
</div>
|
||||
<div class="border-t border-gray-200 px-4 py-5 sm:px-6">
|
||||
<LineChart
|
||||
:chart-data="lineChartData"
|
||||
:chart-options="lineChartOptions"
|
||||
/>
|
||||
</div>
|
||||
<!--
|
||||
<div>
|
||||
<a
|
||||
href="javascript:void(0)"
|
||||
class="block bg-gray-50 px-4 py-4 text-center text-sm font-medium text-gray-500 hover:text-gray-700 sm:rounded-b-lg"
|
||||
@click="refresh()"
|
||||
>새로 고침</a
|
||||
>
|
||||
</div>
|
||||
-->
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section aria-labelledby="applicant-information-title">
|
||||
<div class="bg-white mt-3 shadow sm:rounded-lg">
|
||||
<div class="px-4 py-5 sm:px-6">
|
||||
<h2
|
||||
id="applicant-information-title"
|
||||
class="text-lg font-medium leading-6 text-gray-900"
|
||||
>
|
||||
최근 24시간 키별 점유율
|
||||
</h2>
|
||||
</div>
|
||||
<div class="border-t border-gray-200 px-4 py-5 sm:px-6">
|
||||
<PieChart
|
||||
:chart-data="pieChartData"
|
||||
:chart-options="pieChartOptions"
|
||||
/>
|
||||
</div>
|
||||
<!--
|
||||
<div>
|
||||
<a
|
||||
href="javascript:void(0)"
|
||||
class="block bg-gray-50 px-4 py-4 text-center text-sm font-medium text-gray-500 hover:text-gray-700 sm:rounded-b-lg"
|
||||
@click="refresh()"
|
||||
>새로 고침</a
|
||||
>
|
||||
</div>
|
||||
-->
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pt-5">
|
||||
<div class="flex justify-end"></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
definePageMeta({
|
||||
middleware: 'check-auth-op',
|
||||
});
|
||||
const inPregressFlag = ref(true);
|
||||
|
||||
const responseJson = await _crossCtl.doComm(
|
||||
'local/select',
|
||||
'admin:dashboard',
|
||||
{}
|
||||
);
|
||||
|
||||
let rawData1 = [];
|
||||
let rawData2 = [];
|
||||
|
||||
console.log('responseJson=', responseJson);
|
||||
inPregressFlag.value = false;
|
||||
|
||||
if (responseJson['responseMessage'] == 'ok') {
|
||||
rawData1 = responseJson['result']['adminDashData1'];
|
||||
rawData2 = responseJson['result']['adminDashData2'];
|
||||
} else {
|
||||
alert(responseJson['responseMessage']);
|
||||
}
|
||||
|
||||
const lineChartData = {
|
||||
labels: rawData1.map((item) => item['date_tag']),
|
||||
datasets: [
|
||||
{
|
||||
label: 'Total',
|
||||
backgroundColor: '#00D8FF',
|
||||
data: rawData1.map((item) => item['total']),
|
||||
},
|
||||
{
|
||||
label: 'Hit',
|
||||
backgroundColor: '#f87979',
|
||||
data: rawData1.map((item) => item['hit']),
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const lineChartOptions = {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
};
|
||||
|
||||
const pieChartData = {
|
||||
labels: rawData2.map((item) => item['key_name']),
|
||||
datasets: [
|
||||
{
|
||||
// backgroundColor: ['#41B883', '#E46651', '#00D8FF', '#DD1B16'],
|
||||
data: rawData2.map((item) => item['total']),
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const pieChartOptions = {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
};
|
||||
|
||||
const chartData = {
|
||||
labels: [
|
||||
'January',
|
||||
'February',
|
||||
'March',
|
||||
'April',
|
||||
'May',
|
||||
'June',
|
||||
'July',
|
||||
'August',
|
||||
'September',
|
||||
'October',
|
||||
'November',
|
||||
'December',
|
||||
],
|
||||
datasets: [
|
||||
{
|
||||
label: 'Data One',
|
||||
backgroundColor: '#f87979',
|
||||
data: [40, 20, 12, 39, 10, 40, 39, 80, 40, 20, 12, 11],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const chartOptions = {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
};
|
||||
</script>
|
||||
121
safekiso_admin/pages/admin/statistics/index_bak.vue
Normal file
121
safekiso_admin/pages/admin/statistics/index_bak.vue
Normal file
@@ -0,0 +1,121 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="mt-5 sm:px-3 lg:px-5">전체 통계 페이지 대시보드</div>
|
||||
|
||||
<LineChart
|
||||
:chart-data="lineChartData"
|
||||
:chart-options="lineChartOptions"
|
||||
/>
|
||||
|
||||
<PieChart :chart-data="pieChartData" :chart-options="pieChartOptions" />
|
||||
|
||||
<div class="mt-5 sm:px-3 lg:px-5">
|
||||
<a
|
||||
href="javascript:void(0)"
|
||||
class="text-base font-medium text-indigo-700 hover:text-indigo-600"
|
||||
@click="navigateTo('/admin/statistics/byterm/usage')"
|
||||
>기간별 사용량 통계 화면으로 →</a
|
||||
>
|
||||
</div>
|
||||
<div class="mt-5 sm:px-3 lg:px-5">
|
||||
<a
|
||||
href="javascript:void(0)"
|
||||
class="text-base font-medium text-indigo-700 hover:text-indigo-600"
|
||||
@click="navigateTo('/admin/statistics/byterm/word')"
|
||||
>기간별 단어 통계 화면으로 →</a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
definePageMeta({
|
||||
middleware: 'check-auth-admin',
|
||||
});
|
||||
|
||||
/*
|
||||
const route = useRoute();
|
||||
let hero: string | string[] = '';
|
||||
hero = route.params['hero'];
|
||||
*/
|
||||
|
||||
const responseJson = await _crossCtl.doComm(
|
||||
'local/select',
|
||||
'admin:dashboard',
|
||||
{}
|
||||
);
|
||||
|
||||
let rawData1 = [];
|
||||
let rawData2 = [];
|
||||
|
||||
console.log('responseJson=', responseJson);
|
||||
if (responseJson['responseMessage'] == 'ok') {
|
||||
rawData1 = responseJson['result']['adminDashData1'];
|
||||
rawData2 = responseJson['result']['adminDashData2'];
|
||||
}
|
||||
|
||||
const lineChartData = {
|
||||
labels: rawData1.map((item) => item['date_tag']),
|
||||
datasets: [
|
||||
{
|
||||
label: 'Total',
|
||||
backgroundColor: '#00D8FF',
|
||||
data: rawData1.map((item) => item['total']),
|
||||
},
|
||||
{
|
||||
label: 'Hit',
|
||||
backgroundColor: '#f87979',
|
||||
data: rawData1.map((item) => item['hit']),
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const lineChartOptions = {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
};
|
||||
|
||||
const pieChartData = {
|
||||
labels: rawData2.map((item) => item['key_name']),
|
||||
datasets: [
|
||||
{
|
||||
// backgroundColor: ['#41B883', '#E46651', '#00D8FF', '#DD1B16'],
|
||||
data: rawData2.map((item) => item['total']),
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const pieChartOptions = {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
};
|
||||
|
||||
const chartData = {
|
||||
labels: [
|
||||
'January',
|
||||
'February',
|
||||
'March',
|
||||
'April',
|
||||
'May',
|
||||
'June',
|
||||
'July',
|
||||
'August',
|
||||
'September',
|
||||
'October',
|
||||
'November',
|
||||
'December',
|
||||
],
|
||||
datasets: [
|
||||
{
|
||||
label: 'Data One',
|
||||
backgroundColor: '#f87979',
|
||||
data: [40, 20, 12, 39, 10, 40, 39, 80, 40, 20, 12, 11],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const chartOptions = {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
};
|
||||
</script>
|
||||
Reference in New Issue
Block a user