create-m2m-bo-template-vue 1.0.7 → 1.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/template/src/pages/admin/AdminRolesPage.vue +1 -1
- package/template/src/pages/cartconversion/CartConversionPage.vue +0 -24
- package/template/src/pages/system/CommonCodesPage.vue +1 -1
- package/template/src/pages/system/IntegrationManagementPage.vue +1 -1
- package/template/src/pages/system/JobManagementPage.vue +1 -1
- package/template/src/pages/system/ServiceSettingsPage.vue +1 -1
- package/template/src/style.css +20 -1
package/package.json
CHANGED
|
@@ -520,7 +520,7 @@ function dlgBtnStyle(kind: DialogButton['kind']) {
|
|
|
520
520
|
v-for="[key, label] in TAB_OPTIONS"
|
|
521
521
|
:key="key"
|
|
522
522
|
type="button"
|
|
523
|
-
|
|
523
|
+
variant="secondary"
|
|
524
524
|
size="md"
|
|
525
525
|
:class-names="[common.button, tab === key ? common['button_primary-light'] : common.button_secondary, common.size_md, tabShared.qfBtn, tab === key ? tabShared.quickActive : '']"
|
|
526
526
|
@click="tab = key"
|
|
@@ -1,14 +1,9 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { computed, ref } from 'vue';
|
|
3
3
|
import { useRouter } from 'vue-router';
|
|
4
|
-
import { RotateCcw } from 'lucide-vue-next';
|
|
5
|
-
import { Button } from 'm2m-uiux-vue/Button';
|
|
6
|
-
import { Checkbox } from 'm2m-uiux-vue/Checkbox';
|
|
7
|
-
import { Segmented } from 'm2m-uiux-vue/Segmented';
|
|
8
4
|
import { ExcelDownloadButton } from '../../components/common';
|
|
9
5
|
import { StatisticsBarChart } from '../../components/charts';
|
|
10
6
|
import { downloadStatisticsReport } from '../../lib/statisticsReport';
|
|
11
|
-
import DatePicker from '../../components/forms/DatePicker.vue';
|
|
12
7
|
import shared from '../ops/opsShared.module.css';
|
|
13
8
|
import styles from '../stats/TransactionStatsPage.module.css';
|
|
14
9
|
import extra from './cartConversionExtra.module.css';
|
|
@@ -33,7 +28,6 @@ import {
|
|
|
33
28
|
type DropoffThreshold,
|
|
34
29
|
type Granularity,
|
|
35
30
|
type PeriodAggregate,
|
|
36
|
-
type QuickRange,
|
|
37
31
|
} from './cartConversionData';
|
|
38
32
|
|
|
39
33
|
type Tab = 'overview' | 'dropoff' | 'funnel';
|
|
@@ -42,7 +36,6 @@ const TABS: [Tab, string][] = [
|
|
|
42
36
|
['dropoff', '이탈 분석'],
|
|
43
37
|
['funnel', '구매 퍼널'],
|
|
44
38
|
];
|
|
45
|
-
const QUICK_RANGES: QuickRange[] = ['오늘', '어제', '최근 7일', '최근 30일', '이번 달', '지난 달'];
|
|
46
39
|
const METRICS = ['cartUsers', 'buyUsers', 'conversionRate'] as const;
|
|
47
40
|
type Metric = (typeof METRICS)[number];
|
|
48
41
|
const METRIC_LABEL: Record<Metric, string> = { cartUsers: '장바구니 사용자', buyUsers: '구매 사용자', conversionRate: '전환율' };
|
|
@@ -60,17 +53,6 @@ const granularity = ref<Granularity>('일별');
|
|
|
60
53
|
const metric = ref<Metric>('cartUsers');
|
|
61
54
|
const threshold = ref<DropoffThreshold>('24시간');
|
|
62
55
|
|
|
63
|
-
function applyQuick(range: QuickRange) {
|
|
64
|
-
const [s, e] = quickRangeDates(range);
|
|
65
|
-
start.value = s;
|
|
66
|
-
end.value = e;
|
|
67
|
-
}
|
|
68
|
-
function resetFilters() {
|
|
69
|
-
channel.value = '전체';
|
|
70
|
-
category.value = '전체';
|
|
71
|
-
applyQuick('최근 30일');
|
|
72
|
-
}
|
|
73
|
-
|
|
74
56
|
const agg = computed<PeriodAggregate>(() => aggregate(start.value, end.value, channel.value, category.value));
|
|
75
57
|
const prevRange = computed(() => previousPeriod(start.value, end.value));
|
|
76
58
|
const prevStart = computed(() => prevRange.value[0]);
|
|
@@ -97,12 +79,6 @@ const steps = computed(() => funnelSteps(agg.value));
|
|
|
97
79
|
const prevSteps = computed(() => funnelSteps(prevAgg.value));
|
|
98
80
|
const finalConv = computed(() => (steps.value[0].count ? (steps.value[steps.value.length - 1].count / steps.value[0].count) * 100 : 0));
|
|
99
81
|
const prevFinalConv = computed(() => (prevSteps.value[0].count ? (prevSteps.value[prevSteps.value.length - 1].count / prevSteps.value[0].count) * 100 : 0));
|
|
100
|
-
const activeQuickRange = computed(() =>
|
|
101
|
-
QUICK_RANGES.find((range) => {
|
|
102
|
-
const [rangeStart, rangeEnd] = quickRangeDates(range);
|
|
103
|
-
return rangeStart === start.value && rangeEnd === end.value;
|
|
104
|
-
})
|
|
105
|
-
);
|
|
106
82
|
|
|
107
83
|
function deltaClass(deltaValue: number | undefined, positiveIsBad?: boolean) {
|
|
108
84
|
if (deltaValue == null) return undefined;
|
|
@@ -87,7 +87,7 @@ function toggleStatus() {
|
|
|
87
87
|
v-for="status in QUICK_STATUSES"
|
|
88
88
|
:key="status"
|
|
89
89
|
type="button"
|
|
90
|
-
|
|
90
|
+
variant="secondary"
|
|
91
91
|
size="md"
|
|
92
92
|
:class-names="[common.button, quick === status ? common['button_primary-light'] : common.button_secondary, common.size_md, shared.qfBtn, quick === status ? shared.quickActive : '']"
|
|
93
93
|
@click="quick = status"
|
|
@@ -87,7 +87,7 @@ function toggleStatus() {
|
|
|
87
87
|
v-for="status in QUICK_STATUSES"
|
|
88
88
|
:key="status"
|
|
89
89
|
type="button"
|
|
90
|
-
|
|
90
|
+
variant="secondary"
|
|
91
91
|
size="md"
|
|
92
92
|
:class-names="[common.button, quick === status ? common['button_primary-light'] : common.button_secondary, common.size_md, shared.qfBtn, quick === status ? shared.quickActive : '']"
|
|
93
93
|
@click="quick = status"
|
|
@@ -87,7 +87,7 @@ function toggleStatus() {
|
|
|
87
87
|
v-for="status in QUICK_STATUSES"
|
|
88
88
|
:key="status"
|
|
89
89
|
type="button"
|
|
90
|
-
|
|
90
|
+
variant="secondary"
|
|
91
91
|
size="md"
|
|
92
92
|
:class-names="[common.button, quick === status ? common['button_primary-light'] : common.button_secondary, common.size_md, shared.qfBtn, quick === status ? shared.quickActive : '']"
|
|
93
93
|
@click="quick = status"
|
|
@@ -87,7 +87,7 @@ function toggleStatus() {
|
|
|
87
87
|
v-for="status in QUICK_STATUSES"
|
|
88
88
|
:key="status"
|
|
89
89
|
type="button"
|
|
90
|
-
|
|
90
|
+
variant="secondary"
|
|
91
91
|
size="md"
|
|
92
92
|
:class-names="[common.button, quick === status ? common['button_primary-light'] : common.button_secondary, common.size_md, shared.qfBtn, quick === status ? shared.quickActive : '']"
|
|
93
93
|
@click="quick = status"
|
package/template/src/style.css
CHANGED
|
@@ -386,6 +386,25 @@ html[data-theme='dark'] {
|
|
|
386
386
|
field-sizing: content;
|
|
387
387
|
}
|
|
388
388
|
|
|
389
|
+
/* SearchField 내부 input의 테두리/배경/반경을 리셋하여 외부 컨테이너 테두리와 겹쳐 두 줄로 보이는 현상 완벽 방지 */
|
|
390
|
+
:where(
|
|
391
|
+
[class*="SearchField"],
|
|
392
|
+
[class*="searchField"],
|
|
393
|
+
[class*="field"],
|
|
394
|
+
[class*="control"]
|
|
395
|
+
)
|
|
396
|
+
input {
|
|
397
|
+
border: 0 !important;
|
|
398
|
+
border-radius: 0 !important;
|
|
399
|
+
outline: none !important;
|
|
400
|
+
box-shadow: none !important;
|
|
401
|
+
background: transparent !important;
|
|
402
|
+
width: 100% !important;
|
|
403
|
+
max-width: none !important;
|
|
404
|
+
height: 100% !important;
|
|
405
|
+
padding: 0 62px 0 10px !important;
|
|
406
|
+
}
|
|
407
|
+
|
|
389
408
|
/* searchRow / filterRow1 내부의 form 태그도 flex 정렬 보장 */
|
|
390
409
|
:where(
|
|
391
410
|
[class*="filterBox"],
|
|
@@ -1133,7 +1152,7 @@ html[data-theme='dark'] {
|
|
|
1133
1152
|
|
|
1134
1153
|
html,
|
|
1135
1154
|
body,
|
|
1136
|
-
#
|
|
1155
|
+
#root {
|
|
1137
1156
|
height: 100%;
|
|
1138
1157
|
overflow: hidden;
|
|
1139
1158
|
}
|