|
@@ -8,18 +8,20 @@
|
|
|
<el-option label="活跃趋势" value="活跃趋势" />
|
|
|
<el-option label="活跃构成" value="活跃构成" />
|
|
|
<el-option label="活跃粘度" value="活跃粘度" />
|
|
|
- <el-option label="分时活跃用户" value="分时活跃用户" />
|
|
|
- <el-option label="周活跃度" value="周活跃度" />
|
|
|
- <el-option label="月活跃度" value="月活跃度" />
|
|
|
+ <el-option :disabled="isTrendDisabled" label="分时活跃用户" value="分时活跃用户" />
|
|
|
+ <el-option :disabled="isWeekRateDisabled" label="周活跃度" value="周活跃度" />
|
|
|
+ <el-option :disabled="isMonthRateDisabled" label="月活跃度" value="月活跃度" />
|
|
|
</el-select>
|
|
|
- <el-select v-model="industryCompare" class="!w-[120px] ml-2" clearable @change="handleCompareChange">
|
|
|
+ <el-select v-model="industryCompare" class="!w-[120px] ml-2" clearable
|
|
|
+ @change="handleCompareChange">
|
|
|
<el-option label="版本对比" value="version" />
|
|
|
<el-option label="渠道对比" value="channel" />
|
|
|
<el-option label="时段对比" value="time" />
|
|
|
</el-select>
|
|
|
|
|
|
<!-- 版本对比和渠道对比使用popover -->
|
|
|
- <el-popover v-if="industryCompare !== 'time' && industryCompare" placement="bottom" trigger="click" width="400">
|
|
|
+ <el-popover v-if="industryCompare !== 'time' && industryCompare" placement="bottom" trigger="click"
|
|
|
+ width="400">
|
|
|
<template #reference>
|
|
|
<el-button class="ml-2">{{ t('addUser.average') }}</el-button>
|
|
|
</template>
|
|
@@ -27,16 +29,12 @@
|
|
|
<div class="p-3">
|
|
|
<div class="mb-3">
|
|
|
<label class="text-sm font-medium mb-2 block">{{ getCompareTitle() }}</label>
|
|
|
- <el-input
|
|
|
- v-model="searchKeyword"
|
|
|
- :placeholder="`请搜索${getCompareTypeText()}`"
|
|
|
- clearable
|
|
|
- @input="filterCompareOptions"
|
|
|
- size="small"
|
|
|
- />
|
|
|
+ <el-input v-model="searchKeyword" :placeholder="`请搜索${getCompareTypeText()}`"
|
|
|
+ clearable @input="filterCompareOptions" size="small" />
|
|
|
</div>
|
|
|
<div class="max-h-60 overflow-y-auto">
|
|
|
- <el-checkbox-group v-model="selectedCompareItems" @change="handleCompareItemsChange">
|
|
|
+ <el-checkbox-group v-model="selectedCompareItems"
|
|
|
+ @change="handleCompareItemsChange">
|
|
|
<div v-for="item in filteredCompareOptions" :key="item" class="mb-2">
|
|
|
<el-checkbox :label="item" size="small">{{ item }}</el-checkbox>
|
|
|
</div>
|
|
@@ -47,32 +45,19 @@
|
|
|
</el-popover>
|
|
|
|
|
|
<!-- 时段对比使用日期选择 -->
|
|
|
- <el-popover
|
|
|
- v-if="industryCompare === 'time'"
|
|
|
- placement="bottom"
|
|
|
- trigger="click"
|
|
|
- width="300"
|
|
|
- :visible="timeCompareVisible"
|
|
|
- :hide-after="0"
|
|
|
- :persistent="true"
|
|
|
- >
|
|
|
+ <el-popover v-if="industryCompare === 'time'" placement="bottom" trigger="click" width="300"
|
|
|
+ :visible="timeCompareVisible" :hide-after="0" :persistent="true">
|
|
|
<template #reference>
|
|
|
- <el-button class="ml-2" @click="timeCompareVisible = !timeCompareVisible">{{ t('addUser.average') }}</el-button>
|
|
|
+ <el-button class="ml-2" @click="timeCompareVisible = !timeCompareVisible">{{
|
|
|
+ t('addUser.average') }}</el-button>
|
|
|
</template>
|
|
|
<template #default>
|
|
|
<div class="p-3">
|
|
|
<div class="mb-3">
|
|
|
<label class="text-sm font-medium mb-2 block">选择对比时段</label>
|
|
|
- <el-date-picker
|
|
|
- v-model="timeCompareRange"
|
|
|
- type="date"
|
|
|
- format="YYYY-MM-DD"
|
|
|
- value-format="YYYY-MM-DD"
|
|
|
- :disabled-date="disableAfterToday"
|
|
|
- @change="handleTimeCompareChange"
|
|
|
- style="width: 100%"
|
|
|
- :clearable="false"
|
|
|
- />
|
|
|
+ <el-date-picker v-model="timeCompareRange" type="date" format="YYYY-MM-DD"
|
|
|
+ value-format="YYYY-MM-DD" :disabled-date="disableAfterToday"
|
|
|
+ @change="handleTimeCompareChange" style="width: 100%" :clearable="false" />
|
|
|
</div>
|
|
|
</div>
|
|
|
<!-- <div class="flex justify-end">
|
|
@@ -84,7 +69,7 @@
|
|
|
|
|
|
<el-button link class="ml-2" @click="clearCompare(), getData('clearAll')">清除</el-button>
|
|
|
</div>
|
|
|
- <div class="flex items-center">
|
|
|
+ <div class="flex items-center" v-if="chartType !== '分时活跃用户'">
|
|
|
<el-radio-group v-model="formData.timeUnit" @change="getData(''), getBottomDetail()">
|
|
|
<el-radio-button label="day" :disabled="isDayDisabled">天</el-radio-button>
|
|
|
<el-radio-button label="week" :disabled="isWeekDisabled">周</el-radio-button>
|
|
@@ -101,7 +86,8 @@
|
|
|
<!-- 明细表格 -->
|
|
|
<div class="mt-3">
|
|
|
<div class="flex items-center justify-between mb-2">
|
|
|
- <div class="text-base font-medium cursor-pointer select-none ml-3 items-center flex text-[#167AF0]" @click="showDetail = !showDetail">
|
|
|
+ <div class="text-base font-medium cursor-pointer select-none ml-3 items-center flex text-[#167AF0]"
|
|
|
+ @click="showDetail = !showDetail">
|
|
|
{{ showDetail ? '收起明细数据' : '展开明细数据' }}
|
|
|
<el-icon class="ml-2">
|
|
|
<ArrowDown v-if="showDetail" />
|
|
@@ -117,33 +103,30 @@
|
|
|
<el-table-column prop="activeUser" label="活跃用户数" align="right" min-width="100" />
|
|
|
<el-table-column label="活跃构成(新用户占比)" align="right" min-width="140">
|
|
|
<template #default="{ row }">
|
|
|
- <div v-if="row.newUserRate" class="flex items-center justify-end w-full">{{ (row.newUserRate * 100).toFixed(2) }}%</div>
|
|
|
+ <div v-if="row.newUserRate" class="flex items-center justify-end w-full">{{ (row.newUserRate *
|
|
|
+ 100).toFixed(2) }}%</div>
|
|
|
<span v-else>--</span>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
<el-table-column label="DAU/过去7日活跃用户" align="right" min-width="140">
|
|
|
<template #default="{ row }">
|
|
|
- <div v-if="row.wauRate" class="flex items-center justify-end w-full">{{ (row.wauRate * 100).toFixed(2) }}%</div>
|
|
|
+ <div v-if="row.wauRate" class="flex items-center justify-end w-full">{{ (row.wauRate *
|
|
|
+ 100).toFixed(2) }}%</div>
|
|
|
<span v-else>--</span>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
<el-table-column label="DAU/过去30日活跃用户" align="right" min-width="140">
|
|
|
<template #default="{ row }">
|
|
|
- <div v-if="row.mauRate" class="flex items-center justify-end w-full">{{ (row.mauRate * 100).toFixed(2) }}%</div>
|
|
|
+ <div v-if="row.mauRate" class="flex items-center justify-end w-full">{{ (row.mauRate *
|
|
|
+ 100).toFixed(2) }}%</div>
|
|
|
<span v-else>--</span>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
</el-table>
|
|
|
<div v-if="showDetail" class="flex justify-end mt-3">
|
|
|
- <el-pagination
|
|
|
- v-model:current-page="pagination.current"
|
|
|
- v-model:page-size="pagination.size"
|
|
|
- @change="getBottomDetail"
|
|
|
- background
|
|
|
- layout="total, prev, pager, next, sizes"
|
|
|
- :total="pagination.total"
|
|
|
- :page-sizes="[5, 10, 20]"
|
|
|
- />
|
|
|
+ <el-pagination v-model:current-page="pagination.current" v-model:page-size="pagination.size"
|
|
|
+ @change="getBottomDetail" background layout="total, prev, pager, next, sizes"
|
|
|
+ :total="pagination.total" :page-sizes="[5, 10, 20]" />
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
@@ -182,6 +165,11 @@ const props = defineProps({
|
|
|
default: () => ({}),
|
|
|
},
|
|
|
});
|
|
|
+defineExpose({
|
|
|
+ chartType
|
|
|
+})
|
|
|
+
|
|
|
+const timeDiff = computed(() => dayjs(props.formData.time[1]).diff(props.formData.time[0], "day"));
|
|
|
|
|
|
interface FormDataType {
|
|
|
timeUnit: string;
|
|
@@ -216,11 +204,15 @@ const loading = ref(false);
|
|
|
|
|
|
const onChangeType = (value: string) => {
|
|
|
if (value !== '分时活跃用户') {
|
|
|
+ if (value === "活跃粘度") {
|
|
|
+ formData.value.timeUnit = "day";
|
|
|
+ }
|
|
|
getData('clearAll');
|
|
|
emit('query', '');
|
|
|
|
|
|
}
|
|
|
- if(value === '分时活跃用户' || value === '周活跃度' || value === '月活跃率'){
|
|
|
+ if (value === '分时活跃用户' || value === '周活跃度' || value === '月活跃率') {
|
|
|
+ getData('clearAll');
|
|
|
emit('query', 'disabled');
|
|
|
}
|
|
|
};
|
|
@@ -241,6 +233,7 @@ const getData = async (type: string) => {
|
|
|
}
|
|
|
let res;
|
|
|
let data;
|
|
|
+<<<<<<< Updated upstream
|
|
|
if (chartType.value == '活跃趋势') {
|
|
|
res = await getTrend(formData.value);
|
|
|
data = res.data || [];
|
|
@@ -258,6 +251,38 @@ const getData = async (type: string) => {
|
|
|
formData.value.timeUnit = 'month';
|
|
|
res = await getMonthrate(formData.value);
|
|
|
data = res.data || [];
|
|
|
+=======
|
|
|
+ try {
|
|
|
+
|
|
|
+ if (chartType.value == '活跃趋势') {
|
|
|
+ res = await getTrend(formData.value);
|
|
|
+ data = res.data || [];
|
|
|
+ } else if (chartType.value == '活跃构成') {
|
|
|
+ res = await getCompose(formData.value);
|
|
|
+ data = res.data || [];
|
|
|
+ } else if (chartType.value == '活跃粘度') {
|
|
|
+ res = await getViscosity(formData.value);
|
|
|
+ data = res.data || [];
|
|
|
+ } else if (chartType.value == '周活跃度') {
|
|
|
+ formData.value.timeUnit = 'week';
|
|
|
+ res = await getWeekrate(formData.value);
|
|
|
+ data = res.data || [];
|
|
|
+ } else if (chartType.value == '月活跃度') {
|
|
|
+ formData.value.timeUnit = 'month';
|
|
|
+ res = await getMonthrate(formData.value);
|
|
|
+ data = res.data || [];
|
|
|
+ } else if (chartType.value === '分时活跃用户') {
|
|
|
+ const params = {
|
|
|
+ ...formData.value
|
|
|
+ };
|
|
|
+ params.timeUnit = "hour";
|
|
|
+ res = await getTrend(params);
|
|
|
+ data = res.data || [];
|
|
|
+ }
|
|
|
+
|
|
|
+ } catch (error) {
|
|
|
+ console.log(error);
|
|
|
+>>>>>>> Stashed changes
|
|
|
}
|
|
|
|
|
|
// const res = await getTrend({ ...formData.value });
|
|
@@ -383,10 +408,58 @@ const rangeDays = computed(() => {
|
|
|
if (!start || !end) return 0;
|
|
|
return getDaysBetweenDates(start, end);
|
|
|
});
|
|
|
+const isTrendDisabled = computed(() => {
|
|
|
+ return timeDiff.value >= 7;
|
|
|
+})
|
|
|
+const isWeekRateDisabled = computed(() => {
|
|
|
+ return timeDiff.value < 7
|
|
|
+})
|
|
|
+const isMonthRateDisabled = computed(() => {
|
|
|
+ return timeDiff.value < 30
|
|
|
+})
|
|
|
+const isWeekDisabled = computed(() => {
|
|
|
+ if (chartType.value === "活跃粘度") {
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if (chartType.value === "月活跃度") {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if (!isTrendDisabled.value) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if (!isWeekRateDisabled.value && isMonthRateDisabled.value) {
|
|
|
+ if (chartType.value === "活跃粘度") {
|
|
|
|
|
|
-const isWeekDisabled = computed(() => rangeDays.value < 7);
|
|
|
-const isMonthDisabled = computed(() => rangeDays.value < 28);
|
|
|
-const isDayDisabled = computed(() => false);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+});
|
|
|
+const isMonthDisabled = computed(() => {
|
|
|
+ // rangeDays.value < 28
|
|
|
+ if (chartType.value === "活跃粘度") {
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if (chartType.value === "周活跃度") {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if (!isTrendDisabled.value) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if (!isWeekRateDisabled.value && isMonthRateDisabled.value) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+});
|
|
|
+const isDayDisabled = computed(() => {
|
|
|
+ if (chartType.value === "周活跃度") {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if (chartType.value === "月活跃度") {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+});
|
|
|
|
|
|
function ensureValidTimeUnit() {
|
|
|
// 不进行自动纠正,保持用户选择
|
|
@@ -458,6 +531,7 @@ function handleCompareItemsChange(items: string[]) {
|
|
|
.filter(({ item }) => !currentItems.has(item))
|
|
|
.map(({ index }) => index);
|
|
|
|
|
|
+<<<<<<< Updated upstream
|
|
|
// 输出结果用于调试或后续处理
|
|
|
console.log('新增的项:', addedItems);
|
|
|
console.log('减少的项:', removedItemIndices);
|
|
@@ -473,6 +547,30 @@ function handleCompareItemsChange(items: string[]) {
|
|
|
previousCompareItems.value = items;
|
|
|
|
|
|
const isVersion = industryCompare.value === 'version'; // 判断是否是版本对比
|
|
|
+=======
|
|
|
+ // 更新 previousCompareItems 为当前值,用于下次对比
|
|
|
+ previousCompareItems.value = items;
|
|
|
+
|
|
|
+ // 先处理主数据项的name
|
|
|
+ if (industryCompare.value === 'version') {
|
|
|
+ lineChartData.value.items[0].name = '全部版本';
|
|
|
+ } else if (industryCompare.value === 'channel') {
|
|
|
+ lineChartData.value.items[0].name = '全部渠道';
|
|
|
+ }
|
|
|
+
|
|
|
+ // 清理被取消的对比项
|
|
|
+ if (removedItemIndices.length > 0) {
|
|
|
+ // 从后往前删除,避免索引变化影响
|
|
|
+ removedItemIndices
|
|
|
+ .sort((a, b) => b - a)
|
|
|
+ .forEach(index => {
|
|
|
+ lineChartData.value.items.splice(index + 1, 1);
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新表单数据
|
|
|
+ const isVersion = industryCompare.value === 'version';
|
|
|
+>>>>>>> Stashed changes
|
|
|
if (isVersion) {
|
|
|
formData.value.version = addedItems;
|
|
|
formData.value.channel = props.formData?.channel ? [props.formData?.channel] : [];
|
|
@@ -480,9 +578,18 @@ function handleCompareItemsChange(items: string[]) {
|
|
|
formData.value.channel = addedItems;
|
|
|
formData.value.version = props.formData?.version ? [props.formData?.version] : [];
|
|
|
}
|
|
|
+<<<<<<< Updated upstream
|
|
|
if (addedItems.length > 0) {
|
|
|
getData('');
|
|
|
} else {
|
|
|
+=======
|
|
|
+
|
|
|
+ // 根据是否有新增项来决定是否重新获取数据
|
|
|
+ if (addedItems.length > 0) {
|
|
|
+ getData('');
|
|
|
+ } else if (removedItemIndices.length > 0) {
|
|
|
+ // 如果只是移除了项,则重新初始化图表
|
|
|
+>>>>>>> Stashed changes
|
|
|
initLineChart();
|
|
|
}
|
|
|
}
|