Pārlūkot izejas kodu

fix: 页面接口联调更新

jcq 4 dienas atpakaļ
vecāks
revīzija
3625293d43

+ 2 - 2
.env

@@ -5,9 +5,9 @@ VITE_IS_MICRO= true
 VITE_PUBLIC_PATH = /
 
 # 后端请求前缀
-VITE_API_URL = http://192.168.10.101:9999
+# VITE_API_URL = http://192.168.10.101:9999
 # VITE_API_URL = http://192.168.3.118:9999
-# VITE_API_URL = http://192.168.3.17:9999
+VITE_API_URL = http://192.168.3.17:9999
 
 # OAUTH2 密码模式客户端信息
 VITE_OAUTH2_PASSWORD_CLIENT='pig:pig'

+ 52 - 0
src/api/count/activeUser.ts

@@ -0,0 +1,52 @@
+import request from '/@/utils/request';
+import { appID } from '/@/api/common/common';
+
+
+export const getTrendDetail = (data?: Object) => {
+	return request({
+		url: '/stats/user/active/detail',
+		method: 'post',
+		data:{appId: appID, ...data},
+	});
+};
+//活跃趋势
+export const getTrend = (data?: Object) => {
+	return request({
+		url: '/stats/user/active/trend',
+		method: 'post',
+		data:{appId: appID, ...data},
+	});
+};
+
+//活跃构成
+export const getCompose = (data?: Object) => {
+	return request({
+		url: '/stats/user/active/compose',
+		method: 'post',
+		data:{appId: appID, ...data},
+	});
+};
+//活跃粘度
+export const getViscosity = (data?: Object) => {
+	return request({
+		url: '/stats/user/active/viscosity',
+		method: 'post',
+		data:{appId: appID, ...data},
+	});
+};
+//周活跃率
+export const getWeekrate = (data?: Object) => {
+	return request({
+		url: '/stats/user/active/weekrate',
+		method: 'post',
+		data:{appId: appID, ...data},
+	});
+};
+//月活跃率
+export const getMonthrate = (data?: Object) => {
+	return request({
+		url: '/stats/user/active/monthrate',
+		method: 'post',
+		data:{appId: appID, ...data},
+	});
+};

+ 116 - 41
src/views/count/user/activeUser/components/AddTrend.vue

@@ -4,15 +4,22 @@
 		<div class="">
 			<div class="flex items-center justify-between mb-2 mt-3">
 				<div class="flex items-center">
-					<el-select v-model="industryCompare" class="!w-[120px]" clearable @change="handleCompareChange">
+					<el-select v-model="chartType" class="!w-[140px]" @change="onChangeType">
+						<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-select>
+					<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>
@@ -20,12 +27,16 @@
 							<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>
@@ -33,22 +44,35 @@
 								</div>
 							</div>
 						</template>
-					</el-popover> 
+					</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">
@@ -61,7 +85,7 @@
 					<el-button link class="ml-2" @click="clearCompare(), getData('clearAll')">清除</el-button>
 				</div>
 				<div class="flex items-center">
-					<el-radio-group v-model="formData.timeUnit" @change="getData">
+					<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>
 						<el-radio-button label="month" :disabled="isMonthDisabled">月</el-radio-button>
@@ -77,9 +101,9 @@
 		<!-- 明细表格 -->
 		<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">
-					{{ showDetail ? '收起明细数据' : '展开明细数据' }} <el-icon class="ml-2">
+				<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" />
 						<ArrowUp v-else />
 					</el-icon>
@@ -88,26 +112,38 @@
 					<el-button type="primary" text>导出</el-button>
 				</div>
 			</div>
-			<el-table v-if="showDetail" :data="tableData" border>
-				<el-table-column prop="date" label="日期" min-width="140" />
-				<el-table-column prop="date" label="活跃用户数" min-width="140" />
-				<el-table-column prop="date" label="活跃构成(新用户占比)" min-width="140" />
-				<el-table-column prop="date" label="DAU/过去7日活跃用户" min-width="140" />
-				<el-table-column prop="date" label="DAU/过去30日活跃用户" min-width="140" />
-				<el-table-column label="新增用户(占比)" align="right" min-width="220">
-					<template #default="scope">
-						<div class="flex items-center justify-end w-full">
-							<span>{{ scope.row.newUser }}</span>
-							<span class="text-gray-500 text-xs ml-2">({{ (scope.row.newUserRate * 100).toFixed(2)
-							}}%)</span>
-						</div>
+			<el-table v-if="showDetail" :data="tableData" border v-loading.fullscreen.lock="loading">
+				<el-table-column prop="date" label="日期" min-width="100" />
+				<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>
+						<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>
+						<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>
+						<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>
@@ -120,18 +156,18 @@ import { useI18n } from 'vue-i18n';
 import dayjs from 'dayjs';
 import { getDaysBetweenDates } from '/@/utils/formatTime';
 import { getAppVersion, getAppChannel } from '/@/api/common/common';
-import { getTrend, getTrendDetail } from '/@/api/count/addUser';
+import { getTrend, getTrendDetail, getCompose, getViscosity, getWeekrate, getMonthrate } from '/@/api/count/activeUser';
 
 const { t } = useI18n();
-const Title = defineAsyncComponent(() => import('/@/components/Title/index.vue'));
 
-const industryCompare = ref('');	
+const industryCompare = ref('');
 const selectedCompareItems = ref<string[]>([]);
 const searchKeyword = ref('');
 const compareOptions = ref<string[]>([]);
 const filteredCompareOptions = ref<string[]>([]);
 const timeCompareRange = ref<string>('');
 const timeCompareVisible = ref(false);
+const chartType = ref('活跃趋势');
 
 const masterData = ref(<any>{
 	//图表主数据
@@ -176,8 +212,21 @@ const pagination = ref({
 });
 const previousCompareItems = ref<string[]>([]);
 const chartTimes = ref<string[]>([]);
+const loading = ref(false);
+
+const onChangeType = (value: string) => {
+	if (value !== '分时活跃用户') {
+		getData('clearAll');
+		emit('query', '');
+
+	}
+	if(value === '分时活跃用户' || value === '周活跃度' || value === '月活跃率'){
+		emit('query', 'disabled');
+	}
+};
 
 const getData = async (type: string) => {
+	loading.value = true;
 	//上方图表
 	if (type === 'clearAll') {
 		lineChartData.value = { dates: [], items: [] };
@@ -190,9 +239,32 @@ const getData = async (type: string) => {
 			return;
 		}
 	}
-	const res = await getTrend({ ...formData.value });
-	const data = res?.data || [];
+	let res;
+	let data;
+	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 == '周活跃度') {
+		res = await getWeekrate(formData.value);
+		data = res.data || [];
+	} else if (chartType.value == '月活跃度') {
+		res = await getMonthrate(formData.value);
+		data = res.data || [];
+	}
 
+	// const res = await getTrend({ ...formData.value });
+	// const data = res?.data || [];
+	initChartData(data);
+	loading.value = false;
+};
+
+const initChartData = async (data: any) => {
 	if (!industryCompare.value) {
 		masterData.value = data;
 		lineChartData.value.items = data.items.map((item: any, index: number) => {
@@ -241,6 +313,7 @@ const getData = async (type: string) => {
 	lineChartData.value.dates = masterData.value.dates;
 	initLineChart();
 };
+
 const getBottomDetail = async () => {
 	// 下方明细表
 	const resDetail = await getTrendDetail({ ...formData.value, ...pagination.value });
@@ -432,7 +505,9 @@ async function initCompareOptions() {
 function handleTimeCompareChange(value: string) {
 	timeCompareRange.value = value;
 	formData.value.toDate = timeCompareRange.value;
-	formData.value.fromDate = dayjs(timeCompareRange.value).subtract(getDaysBetweenDates(props.formData?.time[0], props.formData?.time[1]), 'day').format('YYYY-MM-DD');
+	formData.value.fromDate = dayjs(timeCompareRange.value)
+		.subtract(getDaysBetweenDates(props.formData?.time[0], props.formData?.time[1]), 'day')
+		.format('YYYY-MM-DD');
 	formData.value.channel = props.formData?.channel ? [props.formData?.channel] : [];
 	formData.value.version = props.formData?.version ? [props.formData?.version] : [];
 

+ 58 - 39
src/views/count/user/activeUser/index.vue

@@ -4,30 +4,36 @@
 			<!-- 头部筛选区域 -->
 			<div class="el-card p-9">
 				<div class="flex justify-between">
-					<Title :title="t('activeUser.analytics')" >
-						<el-popover class="box-item" placement="right" trigger="hover" width="250">
-						<template #reference>
-							<el-icon class="ml-1" style="color: #a4b8cf">
-								<QuestionFilled />
-							</el-icon>
-						</template>
-						<template #default>
-							<div class="ant-popover-inner-content">
-								<div class="um-page-tips-content" style="line-height: 24px">
-									<p><span class="highlight">新增用户:</span><span>第一次启动应用的用户(以设备为判断标准)</span></p>
-									<p><span class="highlight">新增账号:</span><span>第一次启动应用的账号</span></p>
-									<p><span class="highlight">新增用户占比:</span><span>某时段内新增用户占该时段活跃用户的比例</span></p>
-									<p>
-										<span>
-											按天、周或月查看数据可进行版本、渠道的交叉筛选,小时数据最多展示7天并且不支持筛选。周区间定义为周日至次周周六。按周(按月)显示时,界面上用每周的周日(每个月的第一日)来代表该周(该月)
-										</span>
-									</p>
+					<Title :title="t('activeUser.analytics')">
+						<el-popover class="box-item" placement="right" trigger="hover" width="400">
+							<template #reference>
+								<el-icon class="ml-1" style="color: #a4b8cf">
+									<QuestionFilled />
+								</el-icon>
+							</template>
+							<template #default>
+								<div class="ant-popover-inner-content">
+									<div class="um-page-tips-content" style="line-height: 24px">
+										<p>
+											<span class="highlight">活跃用户:</span
+											><span>启动过应用的用户(去重),启动过一次的用户即视为活跃用户,包括新用户与老用户</span>
+										</p>
+										<p><span class="highlight">活跃构成:</span><span>活跃用户中新增用户的占比比例</span></p>
+										<p><span class="highlight">活跃粘度:</span><span>DAU/过去7日活跃用户,DAU/过去30日活跃用户</span></p>
+										<p><span class="highlight">过去7日活跃用户:</span><span>过去7日(不含今日)的活跃用户数(去重)</span></p>
+										<p><span class="highlight">过去30日活跃用户:</span><span>过去30日(不含今日)的活跃用户数(去重)</span></p>
+										<p><span class="highlight">分时活跃用户:</span><span>活跃用户在24小时中的分布情况(每小时间去重)&ZeroWidthSpace;</span></p>
+										<p><span class="highlight">周活跃率:</span><span>周活跃用户占截止本周累计用户的比例</span></p>
+										<p><span class="highlight">月活跃率:</span><span>月活跃用户占截止本月累计用户的比例</span></p>
+										<p>
+											<span
+												>按天、周或月查看数据可进行版本、渠道的交叉筛选。周区间定义为周日至次周周六。按周(按月)显示时,界面上用每周的周日(每个月的第一日)来代表该周(该月)</span
+											>
+										</p>
+									</div>
 								</div>
-							</div>
-						</template>
-					</el-popover>	
-					
-					
+							</template>
+						</el-popover>
 					</Title>
 					<!-- <div class="">
 						<el-button type="primary">{{ t('addUser.growth') }}</el-button>
@@ -38,18 +44,23 @@
 					<el-row shadow="hover" class="ml10">
 						<el-form :inline="true" :model="formData" ref="queryRef">
 							<el-form-item>
-								<el-date-picker v-model="formData.time" type="daterange" value-format="YYYY-MM-DD"
-									:disabled-date="disableFuture" @change="handleRangeChange" class="!w-[250px]"
-									start-placeholder="开始时间" end-placeholder="结束时间" />
+								<el-date-picker
+									v-model="formData.time"
+									type="daterange"
+									value-format="YYYY-MM-DD"
+									:disabled-date="disableFuture"
+									@change="handleRangeChange"
+									class="!w-[250px]"
+									start-placeholder="开始时间"
+									end-placeholder="结束时间"
+								/>
 							</el-form-item>
 
 							<el-form-item>
-								<FilterSelect v-model="formData.channel" type="channel" @change="query"
-									class="!w-[180px] ml-2" />
+								<FilterSelect v-model="formData.channel" :disabled="channelDisabled" type="channel" class="!w-[180px] ml-2" />
 							</el-form-item>
 							<el-form-item>
-								<FilterSelect v-model="formData.version" type="version" @change="query"
-									class="!w-[180px] ml-2" />
+								<FilterSelect v-model="formData.version" :disabled="versionDisabled" type="version" class="!w-[180px] ml-2" />
 							</el-form-item>
 						</el-form>
 					</el-row>
@@ -58,9 +69,8 @@
 
 			<!-- 新增趋势模块 -->
 			<div class="mt-3">
-				<AddTrend :form-data="formData" @query="query" />
+				<AddTrend :form-data="formData" @query="isDisabled" />
 			</div>
-
 		</div>
 	</div>
 </template>
@@ -76,15 +86,23 @@ const FilterSelect = defineAsyncComponent(() => import('/@/components/common/fil
 const AddTrend = defineAsyncComponent(() => import('./components/AddTrend.vue'));
 // 计算默认时间范围(半个月前到今天)
 const getDefaultDateRange = () => {
-  const endDate = dayjs();
-  const startDate = endDate.subtract(15, 'day');
-  return [startDate.format('YYYY-MM-DD'), endDate.format('YYYY-MM-DD')];
+	const endDate = dayjs();
+	const startDate = endDate.subtract(15, 'day');
+	return [startDate.format('YYYY-MM-DD'), endDate.format('YYYY-MM-DD')];
 };
 const formData = ref<Record<string, any>>({
 	time: getDefaultDateRange(), // 时间范围
 });
-const query = () => {
-	console.log(formData.value);
+const channelDisabled = ref(false);
+const versionDisabled = ref(false);
+const isDisabled = (type: string) => {
+	if (type == 'disabled') {
+		versionDisabled.value = true;
+		channelDisabled.value = true;
+	}else{
+		versionDisabled.value = false;
+		channelDisabled.value = false;
+	}
 };
 
 function disableFuture(date: Date) {
@@ -95,7 +113,6 @@ function disableFuture(date: Date) {
 
 function handleRangeChange(val: [string, string] | null) {
 	if (!val) {
-		query();
 		return;
 	}
 	const [startStr, endStr] = val;
@@ -106,11 +123,13 @@ function handleRangeChange(val: [string, string] | null) {
 		end = start.add(2, 'year').subtract(1, 'day');
 		formData.value.time = [start.format('YYYY-MM-DD'), end.format('YYYY-MM-DD')];
 	}
-	query();
 }
 </script>
 
 <style lang="scss" scoped>
+.highlight {
+	color: #409eff;
+}
 .el-form-item--default {
 	margin-bottom: 0;
 }

+ 1 - 1
src/views/count/user/adduser/components/AddTrend.vue

@@ -86,7 +86,7 @@
 					<el-button link class="ml-2" @click="clearCompare(), getData('clearAll')">清除</el-button>
 				</div>
 				<div class="flex items-center">
-					<el-radio-group v-model="formData.timeUnit" @change="getData">
+					<el-radio-group v-model="formData.timeUnit" @change="getData(''),getBottomDetail()">
 						<el-radio-button label="hour" :disabled="isHourDisabled">小时</el-radio-button>
 						<el-radio-button label="day" :disabled="isDayDisabled">天</el-radio-button>
 						<el-radio-button label="week" :disabled="isWeekDisabled">周</el-radio-button>