Преглед на файлове

Merge branch 'dev-ly' into dev-cmn

cmy преди 6 дни
родител
ревизия
a5fa64bb37

+ 4 - 0
src/assets/icons/wenhao.svg

@@ -0,0 +1,4 @@
+<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M7 14C8.93298 14 10.683 13.2165 11.9497 11.9497C13.2165 10.683 14 8.93298 14 7C14 5.06702 13.2165 3.31702 11.9497 2.05025C10.683 0.783503 8.93298 0 7 0C5.06702 0 3.31702 0.783503 2.05025 2.05025C0.783503 3.31702 0 5.06702 0 7C0 8.93298 0.783503 10.683 2.05025 11.9497C3.31702 13.2165 5.06702 14 7 14Z" fill="#1B4D88" fill-opacity="0.4"/>
+<path d="M4 4.702C4 4.40333 4.02333 4.09533 4.07 3.778C4.126 3.46067 4.21933 3.17133 4.35 2.91C4.49 2.64867 4.67667 2.434 4.91 2.266C5.14333 2.08867 5.45133 2 5.834 2H7.794C8.102 2 8.37267 2.06533 8.606 2.196C8.84867 2.31733 9.04467 2.476 9.194 2.672C9.35267 2.868 9.474 3.092 9.558 3.344C9.65133 3.596 9.70733 3.848 9.726 4.1C9.754 4.352 9.74467 4.59467 9.698 4.828C9.66067 5.06133 9.59533 5.26667 9.502 5.444L7.934 8.314V9.574H6.324V8.146L7.808 5.556C7.892 5.416 7.948 5.234 7.976 5.01C8.01333 4.786 8.01333 4.57133 7.976 4.366C7.948 4.15133 7.878 3.96933 7.766 3.82C7.66333 3.67067 7.514 3.596 7.318 3.596H6.408C6.24933 3.596 6.11867 3.624 6.016 3.68C5.91333 3.72667 5.82933 3.80133 5.764 3.904C5.708 3.99733 5.67067 4.114 5.652 4.254C5.63333 4.38467 5.624 4.534 5.624 4.702H4ZM7.976 12.15H6.324V10.512H7.976V12.15Z" fill="white"/>
+</svg>

+ 41 - 0
src/components/LYcom/Lcard/index.vue

@@ -0,0 +1,41 @@
+<!-- src/components/LYcom/Lcard/index.vue -->
+<template>
+  <div class="l-card" :style="{ height: cardHeight }">
+    <slot></slot>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import { computed } from 'vue'
+
+// 定义组件props
+interface Props {
+  height?: string | number
+}
+
+const props = withDefaults(defineProps<Props>(), {
+  height: 'auto'
+})
+
+// 计算卡片高度
+const cardHeight = computed(() => {
+  if (typeof props.height === 'number') {
+    return props.height + 'px'
+  }
+  return props.height
+})
+</script>
+
+<style scoped>
+.l-card {
+  width: 100%;
+  min-height: 100px;
+  border-radius: 8px;
+  border: 1px solid #DDE4ED;
+  background-color: #fff;
+  /* box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); */
+  padding: 30px;
+  box-sizing: border-box;
+  margin-bottom: 10px;
+}
+</style>

+ 19 - 1
src/components/Title/index.vue

@@ -1,5 +1,6 @@
 <template>
-	<div class=" font-medium " style="font-size: 16px;">
+	<div class="font-medium" style="font-size: 16px;">
+		<div v-if="props.leftLine" class="left-line mr-2"></div>
 		{{ props.title }}
 		<slot></slot>
 	</div>
@@ -11,5 +12,22 @@ const props = defineProps({
 		type: String,
         default: '标题',
 	},
+	leftLine:{
+		type: Boolean,
+        default: false,
+
+	}
 });
 </script>
+<style lang="scss" scoped>
+.font-medium {
+	font-weight: 500;
+	display: flex;
+	align-items: center;
+}
+.left-line{
+	width: 4px;
+	height: 14px;
+	background: #167AF0;
+}
+</style>

+ 1 - 0
src/layout/footer/index.vue

@@ -22,6 +22,7 @@ const footerAuthor = computed(() => {
 .layout-footer {
 	width: 100%;
 	display: flex;
+	display: none;
 
 	&-warp {
 		margin: auto;

+ 3 - 1
src/layout/routerView/parent.vue

@@ -1,5 +1,5 @@
 <template>
-	<div class="layout-parent" style="display: flex;flex-direction: row">
+	<div class="layout-parent">
 		<Vertical v-if="isShowLeftMenu" :menuList="menuLeftList" />
 		<router-view v-slot="{ Component }">
 			<transition :name="setTransitionName" mode="out-in">
@@ -119,6 +119,7 @@ watch(
 	.w100vh-210 {
 		width: calc(100vw - 210px);
 		left: 210px !important;
+		overflow-y: scroll;
 	}
 	.el-menu--vertical {
 		width: 210px !important;
@@ -126,6 +127,7 @@ watch(
 		border: 1px solid #DDE4ED !important;
 		// margin-top: -30px;
 		margin: 5px 0;
+		position: fixed;
 		background-color: #fff;
 		:deep(.el-menu-item), :deep(.el-sub-menu__title) {
 			color: #646464 !important;

+ 1 - 1
src/router/backEnd.ts

@@ -136,7 +136,7 @@ export function backEndComponent(routes: any) {
 			item.component = dynamicImport(dynamicViewsModules, item.path.split('/:')[0]);
 		}
 		item.children && backEndComponent(item.children);
-		if (item.children && !['/count/index'].includes(item.path)) {
+		if (item.children) {
 			item.redirect = item.children[0].path;
 		}
 		return item;

+ 3 - 0
src/views/count/main/trend/icons/icon1.svg

@@ -0,0 +1,3 @@
+<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect width="48" height="48" rx="14" fill="#167AF0" fill-opacity="0.1"/>
+</svg>

+ 3 - 0
src/views/count/main/trend/icons/icon2.svg

@@ -0,0 +1,3 @@
+<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect width="48" height="48" rx="14" fill="#167AF0" fill-opacity="0.1"/>
+</svg>

+ 9 - 0
src/views/count/main/trend/icons/icon3.svg

@@ -0,0 +1,9 @@
+<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect width="48" height="48" rx="14" fill="#167AF0" fill-opacity="0.1"/>
+<rect x="13" y="13" width="5.7895" height="5.7895" fill="#167AF0"/>
+<rect x="21.1053" y="13" width="5.7895" height="5.7895" fill="#167AF0"/>
+<rect x="29.2106" y="13" width="5.7895" height="5.7895" fill="#167AF0"/>
+<rect x="13" y="21.1055" width="5.7895" height="5.7895" fill="#167AF0"/>
+<rect x="21.1053" y="21.1055" width="5.7895" height="5.7895" fill="#167AF0"/>
+<rect x="13" y="29.2104" width="5.7895" height="5.7895" fill="#167AF0"/>
+</svg>

+ 5 - 0
src/views/count/main/trend/icons/icon4.svg

@@ -0,0 +1,5 @@
+<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect width="48" height="48" rx="14" fill="#167AF0" fill-opacity="0.1"/>
+<path d="M23.9571 12C17.354 12 12 17.354 12 23.9571C12 30.5601 17.354 35.9145 23.9571 35.9145C30.5601 35.9145 35.9142 30.5604 35.9142 23.9571C35.9142 17.3537 30.5628 12 23.9571 12ZM31.2071 31.2091C29.4085 33.0045 27.0059 34.0658 24.4675 34.1863C21.9292 34.3069 19.4368 33.4779 17.4763 31.8611C15.5157 30.2442 14.2274 27.9553 13.8625 25.4404C13.4975 22.9255 14.082 20.3648 15.5021 18.2573C16.9221 16.1499 19.076 14.6466 21.544 14.0406C24.0119 13.4346 26.6171 13.7692 28.8517 14.9793C31.0864 16.1893 32.7905 18.188 33.6319 20.5859C34.4733 22.9839 34.3917 25.6092 33.403 27.9502C32.889 29.1685 32.1432 30.2753 31.2071 31.2091Z" fill="#167AF0"/>
+<path d="M23.9571 15.1494C19.0904 15.1494 15.1495 19.0915 15.1495 23.9571C15.1495 28.8226 19.0915 32.7647 23.9571 32.7647C28.8227 32.7647 32.7648 28.822 32.7648 23.9574C32.7648 19.0927 28.8227 15.1494 23.9571 15.1494ZM28.3876 24.1707H23.1218C22.8882 24.1705 22.6643 24.0776 22.4992 23.9125C22.3341 23.7474 22.2412 23.5235 22.241 23.29V18.0267C22.241 17.7931 22.3338 17.5691 22.499 17.4039C22.6641 17.2388 22.8882 17.146 23.1218 17.146C23.3553 17.146 23.5794 17.2388 23.7445 17.4039C23.9097 17.5691 24.0025 17.7931 24.0025 18.0267V22.4092H28.3879C28.6215 22.4092 28.8456 22.502 29.0107 22.6672C29.1759 22.8323 29.2687 23.0564 29.2687 23.29C29.2687 23.5235 29.1759 23.7476 29.0107 23.9127C28.8456 24.0779 28.6215 24.1707 28.3879 24.1707H28.3876Z" fill="#167AF0"/>
+</svg>

+ 4 - 0
src/views/count/main/trend/icons/icon5.svg

@@ -0,0 +1,4 @@
+<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect width="48" height="48" rx="14" fill="#167AF0" fill-opacity="0.1"/>
+<path d="M20.3407 23.8579C20.3735 23.8367 20.4215 23.7987 20.4359 23.7893C20.4588 23.7802 20.4651 23.7668 20.5132 23.7314C20.7243 23.5845 20.9395 23.4438 21.1618 23.3155C19.794 22.2226 18.9643 20.6033 18.9643 18.8329C18.9647 18.2144 19.0691 17.6001 19.2737 17.0136C19.1694 17.0052 19.0652 16.9985 18.9583 16.9985C16.8793 16.9985 15.1938 18.5772 15.1938 20.5238C15.1938 22.0874 16.281 23.411 17.7849 23.873C15.0488 24.5812 13 27.4363 13 30.6917C13 30.7544 14.2973 30.7328 16.1629 30.7121C16.6786 27.8906 18.21 25.4137 20.3407 23.8579ZM26.1968 30.8148C26.1968 28.163 28.2591 25.9707 30.9221 25.6283C29.8211 24.5086 28.4685 23.7062 26.9726 23.3754C28.9635 22.7052 30.3902 20.927 30.3902 18.8328C30.3901 16.1641 28.0775 14 25.2259 14C22.3734 14 20.0612 16.1641 20.0612 18.8328C20.0612 20.9846 21.5656 22.8064 23.6428 23.4316C19.8829 24.3963 17.0662 28.3292 17.0662 32.8097C17.0662 32.8529 17.5074 32.8671 18.2665 32.8671C19.784 32.8671 22.5741 32.8097 25.6517 32.8097C25.9768 32.8097 26.2961 32.81 26.6094 32.8106C26.3366 32.1778 26.1964 31.4996 26.1968 30.8148ZM31.6466 26.6305C29.2465 26.6305 27.2937 28.5081 27.2937 30.8153C27.2937 33.1224 29.2465 35 31.6466 35C34.0468 35 36 33.1224 36 30.8153C36 28.5081 34.0468 26.6305 31.6466 26.6305ZM33.6578 31.5182H31.8295C31.6839 31.5181 31.5444 31.4625 31.4415 31.3637C31.3387 31.2648 31.2809 31.1308 31.2809 30.991C31.2812 30.9594 31.2846 30.9279 31.2912 30.8969C31.2845 30.826 31.2809 30.7418 31.2809 30.6396V28.1795C31.2809 28.0398 31.3387 27.9058 31.4416 27.807C31.5444 27.7083 31.684 27.6528 31.8294 27.6528C31.9749 27.6528 32.1144 27.7083 32.2173 27.807C32.3201 27.9058 32.3779 28.0398 32.3779 28.1795V30.4638H33.6577C33.8027 30.4648 33.9414 30.5207 34.0436 30.6195C34.1458 30.7183 34.2031 30.8518 34.2031 30.991C34.2031 31.1302 34.1458 31.2638 34.0436 31.3626C33.9414 31.4613 33.8027 31.5173 33.6577 31.5183" fill="#167AF0"/>
+</svg>

+ 4 - 0
src/views/count/main/trend/icons/icon6.svg

@@ -0,0 +1,4 @@
+<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect width="48" height="48" rx="14" fill="#167AF0" fill-opacity="0.1"/>
+<path d="M20.3407 23.8579C20.3735 23.8367 20.4215 23.7987 20.4359 23.7893C20.4588 23.7802 20.4651 23.7668 20.5132 23.7314C20.7243 23.5845 20.9395 23.4438 21.1618 23.3155C19.794 22.2226 18.9643 20.6033 18.9643 18.8329C18.9647 18.2144 19.0691 17.6001 19.2737 17.0136C19.1694 17.0052 19.0652 16.9985 18.9583 16.9985C16.8793 16.9985 15.1938 18.5772 15.1938 20.5238C15.1938 22.0874 16.281 23.411 17.7849 23.873C15.0488 24.5812 13 27.4363 13 30.6917C13 30.7544 14.2973 30.7328 16.1629 30.7121C16.6786 27.8906 18.21 25.4137 20.3407 23.8579ZM26.1968 30.8148C26.1968 28.163 28.2591 25.9707 30.9221 25.6283C29.8211 24.5086 28.4685 23.7062 26.9726 23.3754C28.9635 22.7052 30.3902 20.927 30.3902 18.8328C30.3901 16.1641 28.0775 14 25.2259 14C22.3734 14 20.0612 16.1641 20.0612 18.8328C20.0612 20.9846 21.5656 22.8064 23.6428 23.4316C19.8829 24.3963 17.0662 28.3292 17.0662 32.8097C17.0662 32.8529 17.5074 32.8671 18.2665 32.8671C19.784 32.8671 22.5741 32.8097 25.6517 32.8097C25.9768 32.8097 26.2961 32.81 26.6094 32.8106C26.3366 32.1778 26.1964 31.4996 26.1968 30.8148ZM31.6466 26.6305C29.2465 26.6305 27.2937 28.5081 27.2937 30.8153C27.2937 33.1224 29.2465 35 31.6466 35C34.0468 35 36 33.1224 36 30.8153C36 28.5081 34.0468 26.6305 31.6466 26.6305ZM33.6578 31.5182H31.8295C31.6839 31.5181 31.5444 31.4625 31.4415 31.3637C31.3387 31.2648 31.2809 31.1308 31.2809 30.991C31.2812 30.9594 31.2846 30.9279 31.2912 30.8969C31.2845 30.826 31.2809 30.7418 31.2809 30.6396V28.1795C31.2809 28.0398 31.3387 27.9058 31.4416 27.807C31.5444 27.7083 31.684 27.6528 31.8294 27.6528C31.9749 27.6528 32.1144 27.7083 32.2173 27.807C32.3201 27.9058 32.3779 28.0398 32.3779 28.1795V30.4638H33.6577C33.8027 30.4648 33.9414 30.5207 34.0436 30.6195C34.1458 30.7183 34.2031 30.8518 34.2031 30.991C34.2031 31.1302 34.1458 31.2638 34.0436 31.3626C33.9414 31.4613 33.8027 31.5173 33.6577 31.5183" fill="#167AF0"/>
+</svg>

+ 13 - 0
src/views/count/main/trend/icons/icon7.svg

@@ -0,0 +1,13 @@
+<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect width="48" height="48" rx="14" fill="#167AF0" fill-opacity="0.1"/>
+<g clip-path="url(#clip0_561_3826)">
+<path d="M32.8016 14.1146H30.6014V13.0107H28.4012V14.1146H19.6006V13.0107H17.4002V14.1146H15.2002C14.6167 14.1146 14.057 14.3464 13.6444 14.759C13.2318 15.1716 13 15.7313 13 16.3148V32.7893C13.0001 33.3728 13.2319 33.9324 13.6445 34.3449C14.0571 34.7575 14.6167 34.9893 15.2002 34.9893H32.8016C33.3851 34.9892 33.9446 34.7574 34.3571 34.3449C34.7697 33.9323 35.0015 33.3728 35.0016 32.7893V16.3148C35.0016 15.7313 34.7698 15.1717 34.3572 14.7591C33.9447 14.3465 33.3851 14.1147 32.8016 14.1146ZM32.1442 32.9902H15.8574C15.6055 32.9902 15.3639 32.8901 15.1857 32.712C15.0076 32.5338 14.9075 32.2922 14.9075 32.0403V20.5146H33.0943V32.04C33.0944 32.1648 33.0698 32.2884 33.0221 32.4037C32.9743 32.519 32.9044 32.6237 32.8161 32.712C32.7279 32.8002 32.6231 32.8702 32.5078 32.9179C32.3925 32.9657 32.269 32.9902 32.1442 32.9902Z" fill="#167AF0"/>
+<path d="M24.0579 29.0869C24.1373 28.6748 24.3302 28.2931 24.6149 27.9847C25.0035 27.565 25.5211 27.3339 26.0722 27.3339C26.6234 27.3339 27.1407 27.5648 27.5296 27.9847C27.6696 28.1373 27.7879 28.3085 27.8812 28.4935L28.0046 28.7345H27.2232L27.1777 28.67C27.1383 28.6135 27.0952 28.5599 27.0486 28.5093C26.9266 28.3728 26.7771 28.2635 26.61 28.1887C26.4428 28.114 26.2618 28.0753 26.0787 28.0753C25.8955 28.0753 25.7145 28.114 25.5473 28.1887C25.3802 28.2635 25.2307 28.3728 25.1087 28.5093C24.9554 28.6737 24.8415 28.8709 24.7758 29.0858L25.7667 29.2465L24.0584 29.4677L24.0579 29.0869ZM28.1305 29.6249C28.0511 30.037 27.8582 30.4188 27.5735 30.7272C27.1849 31.1468 26.6673 31.3779 26.1161 31.3779C25.565 31.3779 25.0476 31.1471 24.6588 30.7272C24.5188 30.5745 24.4005 30.4033 24.3072 30.2184L24.1837 29.9773H24.9665L25.012 30.0419C25.0514 30.0983 25.0945 30.152 25.1411 30.2026C25.2631 30.3391 25.4126 30.4483 25.5798 30.5231C25.7469 30.5979 25.9279 30.6365 26.1111 30.6365C26.2942 30.6365 26.4752 30.5979 26.6424 30.5231C26.8095 30.4483 26.959 30.3391 27.081 30.2026C27.234 30.0381 27.3476 29.8411 27.4131 29.6263L26.4222 29.4656L28.1305 29.2428V29.6249ZM23.3249 25.416C24.3235 25.416 25.1446 24.5952 25.1446 23.5883C25.1419 23.1091 24.9503 22.6503 24.6114 22.3116C24.2726 21.9728 23.8137 21.7814 23.3346 21.7788C22.8554 21.7763 22.3946 21.9629 22.0521 22.298C21.7097 22.6332 21.5133 23.0899 21.5055 23.569V23.5883C21.5037 24.0708 21.6935 24.5343 22.0333 24.877C22.373 25.2197 22.8349 25.4136 23.3174 25.416H23.3249Z" fill="#167AF0"/>
+<path d="M22.0767 25.8545H22.085C22.1011 25.8706 23.0675 26.4383 24.3556 25.8545H24.3594C24.9729 26.0505 25.3912 26.4562 25.6716 26.93C25.2292 26.9692 24.8068 27.132 24.4525 27.3998C24.0982 27.6676 23.8263 28.0295 23.6678 28.4444C23.5092 28.8592 23.4705 29.3102 23.5559 29.7461C23.6414 30.1819 23.8476 30.5849 24.151 30.9091C21.7837 31.5979 20.2088 29.6714 20.2088 29.6714C19.9108 26.5344 22.0767 25.8545 22.0767 25.8545Z" fill="#167AF0"/>
+</g>
+<defs>
+<clipPath id="clip0_561_3826">
+<rect width="22" height="22" fill="white" transform="translate(13 13)"/>
+</clipPath>
+</defs>
+</svg>

+ 4 - 0
src/views/count/main/trend/icons/icon8.svg

@@ -0,0 +1,4 @@
+<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect width="48" height="48" rx="14" fill="#167AF0" fill-opacity="0.1"/>
+<path d="M20.3407 23.8579C20.3735 23.8367 20.4215 23.7987 20.4359 23.7893C20.4588 23.7802 20.4651 23.7668 20.5132 23.7314C20.7243 23.5845 20.9395 23.4438 21.1618 23.3155C19.794 22.2226 18.9643 20.6033 18.9643 18.8329C18.9647 18.2144 19.0691 17.6001 19.2737 17.0136C19.1694 17.0052 19.0652 16.9985 18.9583 16.9985C16.8793 16.9985 15.1938 18.5772 15.1938 20.5238C15.1938 22.0874 16.281 23.411 17.7849 23.873C15.0488 24.5812 13 27.4363 13 30.6917C13 30.7544 14.2973 30.7328 16.1629 30.7121C16.6786 27.8906 18.21 25.4137 20.3407 23.8579ZM26.1968 30.8148C26.1968 28.163 28.2591 25.9707 30.9221 25.6283C29.8211 24.5086 28.4685 23.7062 26.9726 23.3754C28.9635 22.7052 30.3902 20.927 30.3902 18.8328C30.3901 16.1641 28.0775 14 25.2259 14C22.3734 14 20.0612 16.1641 20.0612 18.8328C20.0612 20.9846 21.5656 22.8064 23.6428 23.4316C19.8829 24.3963 17.0662 28.3292 17.0662 32.8097C17.0662 32.8529 17.5074 32.8671 18.2665 32.8671C19.784 32.8671 22.5741 32.8097 25.6517 32.8097C25.9768 32.8097 26.2961 32.81 26.6094 32.8106C26.3366 32.1778 26.1964 31.4996 26.1968 30.8148ZM31.6466 26.6305C29.2465 26.6305 27.2937 28.5081 27.2937 30.8153C27.2937 33.1224 29.2465 35 31.6466 35C34.0468 35 36 33.1224 36 30.8153C36 28.5081 34.0468 26.6305 31.6466 26.6305ZM33.6578 31.5182H31.8295C31.6839 31.5181 31.5444 31.4625 31.4415 31.3637C31.3387 31.2648 31.2809 31.1308 31.2809 30.991C31.2812 30.9594 31.2846 30.9279 31.2912 30.8969C31.2845 30.826 31.2809 30.7418 31.2809 30.6396V28.1795C31.2809 28.0398 31.3387 27.9058 31.4416 27.807C31.5444 27.7083 31.684 27.6528 31.8294 27.6528C31.9749 27.6528 32.1144 27.7083 32.2173 27.807C32.3201 27.9058 32.3779 28.0398 32.3779 28.1795V30.4638H33.6577C33.8027 30.4648 33.9414 30.5207 34.0436 30.6195C34.1458 30.7183 34.2031 30.8518 34.2031 30.991C34.2031 31.1302 34.1458 31.2638 34.0436 31.3626C33.9414 31.4613 33.8027 31.5173 33.6577 31.5183" fill="#167AF0"/>
+</svg>

+ 4 - 0
src/views/count/main/trend/icons/icon9.svg

@@ -0,0 +1,4 @@
+<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect width="48" height="48" rx="14" fill="#167AF0" fill-opacity="0.1"/>
+<path d="M15 33.8333V14.6667C15 14.2246 15.1724 13.8007 15.4793 13.4882C15.7862 13.1756 16.2024 13 16.6364 13H26.5953C27.0292 13.0001 27.4454 13.1758 27.7522 13.4883L32.5205 18.345C32.8274 18.6575 32.9999 19.0813 33 19.5233V33.8333C33 34.2754 32.8276 34.6993 32.5207 35.0118C32.2138 35.3244 31.7976 35.5 31.3636 35.5H16.6364C16.2024 35.5 15.7862 35.3244 15.4793 35.0118C15.1724 34.6993 15 34.2754 15 33.8333ZM32.1818 18.8333L27.2727 13.8333V18.8333H32.1818ZM24.8182 19.6667H23.1818V28H24.8182V19.6667ZM24.8182 29.6667H23.1818V31.3333H24.8182V29.6667Z" fill="#167AF0"/>
+</svg>

+ 239 - 3
src/views/count/main/trend/index.vue

@@ -1,7 +1,243 @@
 <template>
-   <div>trend</div>
+   <div class="layout-padding">
+      <div class="!overflow-auto px-1">
+         <Lcard :height="440">
+            <template #default>
+               <Title style="margin-bottom: 10px;" title="整体趋势">
+                  <el-popover class="box-item" placement="right" trigger="hover" width="250">
+                     <template #reference>
+                        <el-icon class="ml-1" style="color: #a4b8cf">
+                           <InfoFilled />
+                        </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>
+                           </div>
+                        </div>
+                     </template>
+                  </el-popover>
+               </Title>
+               <div class="msg">
+                  <el-icon class="ml-1" style="color: #a4b8cf; vertical-align: middle;">
+                     <InfoFilled />
+                  </el-icon>
+                  前往
+                  <span class="link">U-DOP数据开放平台</span>
+                  ,获取用户访问明细日志,点击查看
+                  <span class="link">支持返还的字段</span>
+               </div>
+               <div class="box1">
+                  <Lcard :height="280" style="margin-right: 20px;">
+                     <div class="card-box1">
+                        <InfoCard title="订单数量" value="1,234" description="较昨日减少 1.2%">
+                           <template #icon>
+                              <img src="./icons/icon1.svg" alt="icon">
+                           </template>
+                        </InfoCard>
+                        <InfoCard title="订单数量" value="1,234" description="较昨日减少 1.2%">
+                           <template #icon>
+                              <img src="./icons/icon2.svg" alt="icon">
+                           </template>
+                        </InfoCard>
+                        <InfoCard title="订单数量" value="1,234" description="较昨日减少 1.2%">
+                           <template #icon>
+                              <img src="./icons/icon3.svg" alt="icon">
+                           </template>
+                        </InfoCard>
+                        <InfoCard title="订单数量" value="1,234" description="较昨日减少 1.2%">
+                           <template #icon>
+                              <img src="./icons/icon4.svg" alt="icon">
+                           </template>
+                        </InfoCard>
+                     </div>
+                  </Lcard>
+                  <Lcard :height="280">
+                     <div class="card-box2">
+                        <InfoCard title="订单数量" value="1,234" description="较昨日减少 1.2%">
+                           <template #icon>
+                              <img src="./icons/icon5.svg" alt="icon">
+                           </template>
+                        </InfoCard>
+                        <InfoCard title="订单数量" value="1,234" description="较昨日减少 1.2%">
+                           <template #icon>
+                              <img src="./icons/icon6.svg" alt="icon">
+                           </template>
+                        </InfoCard>
+                        <InfoCard title="订单数量" value="1,234" description="较昨日减少 1.2%">
+                           <template #icon>
+                              <img src="./icons/icon7.svg" alt="icon">
+                           </template>
+                        </InfoCard>
+                        <InfoCard title="订单数量" value="1,234" description="较昨日减少 1.2%">
+                           <template #icon>
+                              <img src="./icons/icon8.svg" alt="icon">
+                           </template>
+                        </InfoCard>
+                        <InfoCard title="订单数量" value="1,234" description="较昨日减少 1.2%">
+                           <template #icon>
+                              <img src="./icons/icon9.svg" alt="icon">
+                           </template>
+                        </InfoCard>
+                     </div>
+                  </Lcard>
+               </div>
+            </template>
+         </Lcard>
+         <Lcard :height="975">          
+            <el-date-picker
+               style="float: left;"
+               v-model="timeRange"
+               type="datetimerange"
+               range-separator="To"
+               start-placeholder="Start date"
+               end-placeholder="End date"
+            />
+            <div class="link" style="float: right;">订阅</div>
+            <div class="link" style="float: right;">编辑指标</div>
+            <div class="link" style="float: right;">生成AI简报</div>
+            <div class="line"></div>
+            <div class="flex items-center justify-between mb-2 mt-3">
+               <el-form>
+                  <el-form-item>
+                     <el-select style="width: 140px" placeholder="渠道对比">
+                        <!-- <el-option v-for="item in channelCompareOptions" :key="item.value" :label="item.label" :value="item.value" /> -->
+                     </el-select>
+                     <el-button class="ml-2">对比时间</el-button>
+                  </el-form-item>
+               </el-form>
+               <div class="flex items-center">
+                  <el-radio-group size="small">
+                     <el-radio-button label="hour">新增用户</el-radio-button>
+                     <el-radio-button label="day">活跃用户</el-radio-button>
+                     <el-radio-button label="week">启动次数</el-radio-button>
+                     <el-radio-button label="month">累计用户</el-radio-button>
+                  </el-radio-group>
+               </div>
+				</div>
+            <div class="relative">
+               <div ref="qChartRef" style="width: 100%; height: 320px"></div>
+            </div>
+         </Lcard>
+      <Lcard :height="440" />
+      <Lcard :height="440" />
+      <Lcard :height="440" />
+   </div>
+   </div>
 </template>
 
-<script lang="ts" setup>
+<script lang="ts" name="countMainTrend" setup>
+import { ref, onMounted, watch, computed, defineAsyncComponent } from 'vue';
+import { useI18n } from 'vue-i18n';
+import * as echarts from 'echarts';
+// 引入组件
+const Lcard = defineAsyncComponent(() => import('/@/components/LYcom/Lcard/index.vue'));
+const Title = defineAsyncComponent(() => import('/@/components/Title/index.vue'));
+const InfoCard = defineAsyncComponent(() => import('./infoCard.vue'));
+const { t } = useI18n();
+const timeRange = ref(null);
+let qualityChart: echarts.ECharts | null = null;
+const qChartRef = ref(null);
+onMounted(() => {
+	// initLineChart();
+	initQualityChart();
+   console.log(qualityChart);
+	// initBehaviorChart();
+});
+const qualityXAxis = ref<string[]>([
+	'2025-07-01',
+	'2025-07-08',
+	'2025-07-15',
+	'2025-07-22',
+	'2025-07-29',
+	'2025-08-05',
+	'2025-08-12',
+	'2025-08-19',
+	'2025-08-26',
+	'2025-09-02',
+	'2025-09-09',
+	'2025-09-16',
+]);
+const retentionSeries = ref<number[]>([20, 23, 27, 24, 22, 15, 5, 4, 16, 26, 25, 2]);
+const industryAvgSeries = ref<number[]>([16, 18, 20, 24, 25, 24, 16, 10, 15, 22, 21, 12]);
+const peerSameScaleSeries = ref<number[]>([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
+function initQualityChart(): void {
+   console.log(qChartRef.value);
+	if (!qChartRef.value) return;
+	if (qualityChart) qualityChart.dispose();
+	qualityChart = echarts.init( qChartRef.value);
+   debugger
+	const option: echarts.EChartsOption = {
+		tooltip: { trigger: 'axis', valueFormatter: (v) => `${v}%` },
+		legend: { data: ['留存率', '同行业App', '同行业同规模App'] },
+		grid: { left: 40, right: 20, top: 30, bottom: 30 },
+		xAxis: { type: 'category', data: qualityXAxis.value },
+		yAxis: {
+			type: 'value',
+			min: 0,
+			max: 30,
+			axisLabel: { formatter: '{value}%' },
+			splitLine: { lineStyle: { color: '#f3f4f6' } },
+		},
+		series: [
+			{ name: '留存率', type: 'line', smooth: true, data: retentionSeries.value },
+			{ name: '同行业App', type: 'line', smooth: true, data: industryAvgSeries.value, color: '#f59e0b' },
+			{ name: '同行业同规模App', type: 'line', smooth: true, data: peerSameScaleSeries.value, color: '#60a5fa' },
+		],
+	};
+	qualityChart.setOption(option);
+}
 
-</script>
+
+
+</script>
+<style lang="scss" scoped>
+.msg {
+   height: 30px;
+   background-color: #f4f5fa;
+   line-height: 30px;
+   font-size: 12px;
+}
+
+.link {
+   color: #167af0;
+   cursor: pointer;
+}
+
+.box1 {
+   display: flex;
+   margin-top: 30px;
+
+   .card-box1,
+   .card-box2 {
+      display: flex;
+      flex-wrap: wrap;
+      justify-content: start;
+   }
+
+   .card-box1 {
+      .info-card {
+         width: 48%;
+      }
+   }
+
+   .card-box2 {
+      .info-card {
+         width: 33%;
+      }
+   }
+}
+.line {
+   margin: 90px -30px 30px;
+   height: 1px;
+   background-color: #E6E6E6;
+}
+</style>

+ 89 - 0
src/views/count/main/trend/infoCard.vue

@@ -0,0 +1,89 @@
+<!-- src/components/LYcom/InfoCard/index.vue -->
+<template>
+  <div class="info-card">
+    <div class="info-card-icon">
+      <slot name="icon">
+        <i :class="iconClass" v-if="iconClass"></i>
+        <svg v-else-if="iconSvg" v-html="iconSvg" class="icon-svg"></svg>
+      </slot>
+    </div>
+    <div class="info-card-content">
+      <div class="content-title">{{ title }}</div>
+      <div class="content-value">{{ value }}</div>
+      <div class="content-desc">{{ description }}</div>
+    </div>
+  </div>
+</template>
+
+<script lang="ts" setup>
+interface Props {
+  iconClass?: string
+  iconSvg?: string
+  title?: string
+  value?: string | number
+  description?: string
+}
+
+withDefaults(defineProps<Props>(), {
+  title: '',
+  value: '',
+  description: ''
+})
+</script>
+
+<style scoped>
+.info-card {
+  display: flex;
+  align-items: center;
+  padding: 16px;
+  background-color: #ffffff;
+  border-radius: 8px;
+  /* box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); */
+}
+
+.info-card-icon {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  width: 50px;
+  height: 50px;
+  border-radius: 8px;
+  background-color: #f0f2f5;
+  margin-right: 16px;
+  flex-shrink: 0;
+}
+
+.info-card-icon i {
+  font-size: 24px;
+  color: #409eff;
+}
+
+.info-card-icon .icon-svg {
+  width: 24px;
+  height: 24px;
+}
+
+.info-card-content {
+  flex: 1;
+  display: flex;
+  flex-direction: column;
+}
+
+.content-title {
+  font-size: 14px;
+  color: #909399;
+  margin-bottom: 4px;
+}
+
+.content-value {
+  font-size: 20px;
+  font-weight: bold;
+  color: #303133;
+  margin-bottom: 4px;
+}
+
+.content-desc {
+  font-size: 12px;
+  color: #c0c4cc;
+}
+</style>

+ 11 - 0
src/views/count/user/activations/i18n/en.ts

@@ -0,0 +1,11 @@
+export default {
+	addUser: {
+		analytics:'Added user analysis',
+		growth:'Go to U-Growth to text/push',
+		ai:'Generative AI intelligence',
+		addtrend:'New trends',
+		channel:'Select a channel',
+		userQuality:'User quality',
+		average:'Industry average'
+	},
+};

+ 12 - 0
src/views/count/user/activations/i18n/zh-cn.ts

@@ -0,0 +1,12 @@
+export default {
+	activations: {
+		analytics:'启动次数',
+		growth:'前往U-Growth发短信/Push',
+		ai:'生成ai智能',
+		addtrend:'新增趋势',
+		version:'选择版本',
+		userQuality:'用户质量',
+		average:'行业平均值',
+		selectTime:'选择时间'
+	},
+};

+ 284 - 0
src/views/count/user/activations/index.vue

@@ -0,0 +1,284 @@
+<template>
+	<div class="layout-padding">
+		<div class="!overflow-auto px-1">
+			<div class="el-card p-2">
+				<div class="flex justify-between">
+					<Title :title="t('activations.analytics')">
+						<template #default>
+							<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>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>
+								</template>
+							</el-popover>
+						</template>
+					</Title>
+				</div>
+				<div>
+					<el-row shadow="hover" class="ml10 mt-2">
+						<el-form :inline="true" :model="formData" @keyup.enter="query" ref="queryRef">
+							<el-form-item>
+								<el-date-picker v-model="formData.time" type="daterange" start-placeholder="开始时间" end-placeholder="结束时间" />
+							</el-form-item>
+							<el-form-item>
+								<el-select v-model="selectedChannelCompare" class="w-[140px]" placeholder="全部渠道">
+									<el-option v-for="item in channelCompareOptions" :key="item.value" :label="item.label" :value="item.value" />
+								</el-select>
+							</el-form-item>
+							<el-form-item>
+								<el-select v-model="selectedChannelCompare" class="w-[140px]" placeholder="全部版本">
+									<el-option v-for="item in channelCompareOptions" :key="item.value" :label="item.label" :value="item.value" />
+								</el-select>
+							</el-form-item>
+						</el-form>
+					</el-row>
+				</div>
+			</div>
+			<div class="mt-2 el-card p-2">
+				<div class="">
+					<div class="flex items-center justify-between mb-2 mt-3">
+						<div>
+							<el-select v-model="selectedChannelCompare" class="w-[140px] ml-2" style="width: 140px" placeholder="版本对比">
+								<el-option v-for="item in channelCompareOptions" :key="item.value" :label="item.label" :value="item.value" />
+							</el-select>
+							<el-button type="primary" class="ml-2">{{ t('activations.version') }}</el-button>
+						</div>
+
+						<div class="flex items-center">
+							<el-radio-group v-model="timeGranularity" size="small">
+								<el-radio-button label="hour">小时</el-radio-button>
+
+								<el-radio-button label="day">天</el-radio-button>
+								<el-radio-button label="week">周</el-radio-button>
+								<el-radio-button label="month">月</el-radio-button>
+							</el-radio-group>
+						</div>
+					</div>
+
+					<div class="relative">
+						<div ref="lineChartRef" style="width: 100%; height: 320px"></div>
+					</div>
+				</div>
+
+				<!-- 明细表格 -->
+				<div class="mt-3">
+					<div class="flex items-center justify-between mb-2">
+						<div class="text-base font-medium cursor-pointer select-none" @click="showDetail1 = !showDetail1">
+							{{ showDetail1 ? '收起明细数据' : '展开明细数据' }}
+						</div>
+						<div>
+							<el-button>导出</el-button>
+						</div>
+					</div>
+					<el-table v-if="showDetail1" :data="pagedTableRows" border>
+						<el-table-column prop="date" label="日期" align="center" min-width="140" />
+						<el-table-column prop="hyyh" label="启动次数" align="center" min-width="140" />
+						<el-table-column prop="ratio" label="启动次数(占比)" align="center" min-width="220">
+							
+						</el-table-column>
+					</el-table>
+					<div v-if="showDetail1" class="flex justify-end mt-2">
+						<el-pagination
+							v-model:current-page="currentPage"
+							v-model:page-size="pageSize"
+							background
+							layout="total, prev, pager, next, sizes"
+							:total="tableRows.length"
+							:page-sizes="[5, 10, 20]"
+						/>
+					</div>
+				</div>
+			</div>
+		</div>
+	</div>
+</template>
+
+<script setup lang="ts">
+import { ref, onMounted, watch, computed, defineAsyncComponent } from 'vue';
+import * as echarts from 'echarts';
+import { useI18n } from 'vue-i18n';
+
+const { t } = useI18n();
+
+interface TableRow {
+	date: string;
+	newUsers: number;
+	ratio: string;
+}
+
+const formData = ref<Record<string, any>>({});
+const query = () => {
+	console.log(formData.value);
+};
+
+const selectedChannelCompare = ref('');
+const channelCompareOptions = [
+	{ label: '渠道对比', value: 'compare' },
+	{ label: '渠道A', value: 'a' },
+	{ label: '渠道B', value: 'b' },
+];
+
+// 图表相关
+const timeGranularity = ref<'hour' | 'day' | 'week' | 'month'>('week');
+const lineChartRef = ref<HTMLDivElement | null>(null);
+let chartInstance: echarts.ECharts | null = null;
+
+const lineChartData = ref<Array<{ x: string; value: number }>>([
+	{ x: '2025-07-01', value: 900 },
+	{ x: '2025-07-08', value: 1000 },
+	{ x: '2025-07-15', value: 1100 },
+	{ x: '2025-07-22', value: 1000 },
+	{ x: '2025-07-29', value: 600 },
+	{ x: '2025-08-05', value: 300 },
+	{ x: '2025-08-12', value: 250 },
+	{ x: '2025-08-19', value: 200 },
+	{ x: '2025-08-26', value: 650 },
+	{ x: '2025-09-02', value: 950 },
+	{ x: '2025-09-09', value: 900 },
+	{ x: '2025-09-16', value: 120 },
+]);
+
+function initLineChart(): void {
+	if (!lineChartRef.value) return;
+	if (chartInstance) chartInstance.dispose();
+	chartInstance = echarts.init(lineChartRef.value);
+	const option: echarts.EChartsOption = {
+		tooltip: { trigger: 'axis' },
+		grid: { left: 40, right: 20, top: 20, bottom: 30 },
+		xAxis: {
+			type: 'category',
+			data: lineChartData.value.map((d) => d.x),
+			axisLine: { lineStyle: { color: '#e5e7eb' } },
+			axisLabel: { color: '#6b7280' },
+			axisTick: { alignWithLabel: true },
+		},
+		yAxis: {
+			type: 'value',
+			axisLine: { show: false },
+			splitLine: { lineStyle: { color: '#f3f4f6' } },
+			axisLabel: { color: '#6b7280' },
+		},
+		series: [
+			{
+				name: '新增人数',
+				type: 'line',
+				smooth: true,
+				showSymbol: true,
+				symbolSize: 6,
+				itemStyle: { color: '#409EFF' },
+				lineStyle: { color: '#409EFF' },
+				data: lineChartData.value.map((d) => d.value),
+			},
+		],
+	};
+	chartInstance.setOption(option);
+}
+
+onMounted(() => {
+	initLineChart();
+	initQualityChart();
+});
+
+watch(timeGranularity, () => {
+	// 静态页面:仅重新渲染
+	initLineChart();
+});
+
+// 表格相关(静态数据)
+const tableRows = ref<TableRow[]>(
+	Array.from({ length: 42 }).map((_, idx) => ({
+		date: `2025-08-${String(11).padStart(2, '0')}`,
+		newUsers: 727,
+		hyyh: '115',
+		ratio: '97.45%',
+	}))
+);
+
+const currentPage = ref(1);
+const pageSize = ref(5);
+const pagedTableRows = computed(() => {
+	const startIndex = (currentPage.value - 1) * pageSize.value;
+
+	return tableRows.value.slice(startIndex, startIndex + pageSize.value);
+});
+
+const Title = defineAsyncComponent(() => import('/@/components/Title/index.vue'));
+
+// 展开/收起明细
+const showDetail1 = ref(true);
+
+// 用户质量(留存率)
+const qualityChartRef = ref<HTMLDivElement | null>(null);
+let qualityChart: echarts.ECharts | null = null;
+
+const qualityXAxis = ref<string[]>([
+	'2025-07-01',
+	'2025-07-08',
+	'2025-07-15',
+	'2025-07-22',
+	'2025-07-29',
+	'2025-08-05',
+	'2025-08-12',
+	'2025-08-19',
+	'2025-08-26',
+	'2025-09-02',
+	'2025-09-09',
+	'2025-09-16',
+]);
+
+const retentionSeries = ref<number[]>([20, 23, 27, 24, 22, 15, 5, 4, 16, 26, 25, 2]);
+const industryAvgSeries = ref<number[]>([16, 18, 20, 24, 25, 24, 16, 10, 15, 22, 21, 12]);
+const peerSameScaleSeries = ref<number[]>([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
+
+function initQualityChart(): void {
+	if (!qualityChartRef.value) return;
+	if (qualityChart) qualityChart.dispose();
+	qualityChart = echarts.init(qualityChartRef.value);
+	const option: echarts.EChartsOption = {
+		tooltip: { trigger: 'axis', valueFormatter: (v) => `${v}%` },
+		legend: { data: ['留存率', '同行业App', '同行业同规模App'] },
+		grid: { left: 40, right: 20, top: 30, bottom: 30 },
+		xAxis: { type: 'category', data: qualityXAxis.value },
+		yAxis: {
+			type: 'value',
+			min: 0,
+			max: 30,
+			axisLabel: { formatter: '{value}%' },
+			splitLine: { lineStyle: { color: '#f3f4f6' } },
+		},
+		series: [
+			{ name: '留存率', type: 'line', smooth: true, data: retentionSeries.value },
+			{ name: '同行业App', type: 'line', smooth: true, data: industryAvgSeries.value, color: '#f59e0b' },
+			{ name: '同行业同规模App', type: 'line', smooth: true, data: peerSameScaleSeries.value, color: '#60a5fa' },
+		],
+	};
+	qualityChart.setOption(option);
+}
+</script>
+
+<style lang="scss" scoped>
+.highlight {
+	color: #2196f3;
+}
+</style>

+ 11 - 0
src/views/count/user/activeUser/i18n/en.ts

@@ -0,0 +1,11 @@
+export default {
+	addUser: {
+		analytics:'Added user analysis',
+		growth:'Go to U-Growth to text/push',
+		ai:'Generative AI intelligence',
+		addtrend:'New trends',
+		channel:'Select a channel',
+		userQuality:'User quality',
+		average:'Industry average'
+	},
+};

+ 12 - 0
src/views/count/user/activeUser/i18n/zh-cn.ts

@@ -0,0 +1,12 @@
+export default {
+	activeUser: {
+		analytics:'活跃用户分析',
+		growth:'前往U-Growth发短信/Push',
+		ai:'生成ai智能',
+		addtrend:'新增趋势',
+		channel:'选择渠道',
+		userQuality:'用户质量',
+		average:'行业平均值',
+		selectTime:'选择时间'
+	},
+};

+ 350 - 0
src/views/count/user/activeUser/index.vue

@@ -0,0 +1,350 @@
+<template>
+	<div class="layout-padding">
+		<div class="!overflow-auto px-1">
+			<div class="el-card p-2">
+				<div class="flex justify-between">
+					<Title :title="t('activeUser.analytics')" />
+					<div class="">
+						<el-button type="primary">{{ t('activeUser.growth') }}</el-button>
+						<el-button type="primary">{{ t('activeUser.ai') }}</el-button>
+					</div>
+				</div>
+				<div>
+					<el-row shadow="hover" class="ml10">
+						<el-form :inline="true" :model="formData" @keyup.enter="query" ref="queryRef">
+							<el-form-item>
+								<el-date-picker v-model="formData.time" type="daterange" start-placeholder="开始时间" end-placeholder="结束时间" />
+							</el-form-item>
+							<el-form-item>
+								<el-select v-model="selectedChannelCompare" class="w-[140px]" placeholder="全部渠道">
+									<el-option v-for="item in channelCompareOptions" :key="item.value" :label="item.label" :value="item.value" />
+								</el-select>
+							</el-form-item>
+							<el-form-item>
+								<el-select v-model="selectedChannelCompare" class="w-[140px]" placeholder="全部版本">
+									<el-option v-for="item in channelCompareOptions" :key="item.value" :label="item.label" :value="item.value" />
+								</el-select>
+							</el-form-item>
+						</el-form>
+					</el-row>
+				</div>
+			</div>
+			<div class="mt-2 el-card p-2">
+				<!-- 新增趋势 -->
+				<div class="">
+					<Title left-line :title="t('activeUser.addtrend')">
+						<template #default>
+							<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>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>
+								</template>
+							</el-popover>
+						</template>
+					</Title>
+					<div class="flex items-center justify-between mb-2 mt-3">
+						<div>
+							<el-select v-model="selectedChannelCompare" class="!w-[140px]" placeholder="渠道对比">
+								<el-option v-for="item in channelCompareOptions" :key="item.value" :label="item.label" :value="item.value" />
+							</el-select>
+
+							<el-select v-model="selectedChannelCompare" class="w-[140px] ml-2" style="width: 140px" placeholder="时间段对比">
+								<el-option v-for="item in channelCompareOptions" :key="item.value" :label="item.label" :value="item.value" />
+							</el-select>
+							<el-button type="primary" class="ml-2">{{ t('activeUser.selectTime') }}</el-button>
+						</div>
+
+						<div class="flex items-center">
+							<el-radio-group v-model="timeGranularity" size="small">
+								<el-radio-button label="day">天</el-radio-button>
+								<el-radio-button label="week">周</el-radio-button>
+								<el-radio-button label="month">月</el-radio-button>
+							</el-radio-group>
+						</div>
+					</div>
+
+					<div class="relative">
+						<div ref="lineChartRef" style="width: 100%; height: 320px"></div>
+					</div>
+				</div>
+
+				<!-- 明细表格 -->
+				<div class="mt-3">
+					<div class="flex items-center justify-between mb-2">
+						<div class="text-base font-medium cursor-pointer select-none" @click="showDetail1 = !showDetail1">
+							{{ showDetail1 ? '收起明细数据' : '展开明细数据' }}
+						</div>
+						<div>
+							<el-button>导出</el-button>
+						</div>
+					</div>
+					<el-table v-if="showDetail1" :data="pagedTableRows" border>
+						<el-table-column prop="date" label="日期" min-width="140" />
+						<el-table-column prop="hyyh" label="活跃用户数" min-width="140" />
+						<el-table-column prop="xyhzb" label="活跃构成(新用户占比)" min-width="140" />
+						<el-table-column prop="gqqr" label="DAU/过去7日活跃用户" min-width="140" />
+						<el-table-column label="新增用户(占比)" min-width="220">
+							<template #default="scope">
+								<div class="flex items-center justify-between w-full">
+									<span>{{ scope.row.newUsers }}</span>
+									<span class="text-gray-500 text-xs">{{ scope.row.ratio }}</span>
+								</div>
+							</template>
+						</el-table-column>
+					</el-table>
+					<div v-if="showDetail1" class="flex justify-end mt-2">
+						<el-pagination
+							v-model:current-page="currentPage"
+							v-model:page-size="pageSize"
+							background
+							layout="total, prev, pager, next, sizes"
+							:total="tableRows.length"
+							:page-sizes="[5, 10, 20]"
+						/>
+					</div>
+				</div>
+			</div>
+		</div>
+	</div>
+</template>
+
+<script setup lang="ts">
+import { ref, onMounted, watch, computed, defineAsyncComponent } from 'vue';
+import * as echarts from 'echarts';
+import { useI18n } from 'vue-i18n';
+
+const { t } = useI18n();
+
+interface TableRow {
+	date: string;
+	newUsers: number;
+	ratio: string;
+}
+
+const formData = ref<Record<string, any>>({});
+const query = () => {
+	console.log(formData.value);
+};
+
+const selectedChannelCompare = ref('');
+const channelCompareOptions = [
+	{ label: '渠道对比', value: 'compare' },
+	{ label: '渠道A', value: 'a' },
+	{ label: '渠道B', value: 'b' },
+];
+
+// 图表相关
+const timeGranularity = ref<'hour' | 'day' | 'week' | 'month'>('week');
+const lineChartRef = ref<HTMLDivElement | null>(null);
+let chartInstance: echarts.ECharts | null = null;
+
+const lineChartData = ref<Array<{ x: string; value: number }>>([
+	{ x: '2025-07-01', value: 900 },
+	{ x: '2025-07-08', value: 1000 },
+	{ x: '2025-07-15', value: 1100 },
+	{ x: '2025-07-22', value: 1000 },
+	{ x: '2025-07-29', value: 600 },
+	{ x: '2025-08-05', value: 300 },
+	{ x: '2025-08-12', value: 250 },
+	{ x: '2025-08-19', value: 200 },
+	{ x: '2025-08-26', value: 650 },
+	{ x: '2025-09-02', value: 950 },
+	{ x: '2025-09-09', value: 900 },
+	{ x: '2025-09-16', value: 120 },
+]);
+
+function initLineChart(): void {
+	if (!lineChartRef.value) return;
+	if (chartInstance) chartInstance.dispose();
+	chartInstance = echarts.init(lineChartRef.value);
+	const option: echarts.EChartsOption = {
+		tooltip: { trigger: 'axis' },
+		grid: { left: 40, right: 20, top: 20, bottom: 30 },
+		xAxis: {
+			type: 'category',
+			data: lineChartData.value.map((d) => d.x),
+			axisLine: { lineStyle: { color: '#e5e7eb' } },
+			axisLabel: { color: '#6b7280' },
+			axisTick: { alignWithLabel: true },
+		},
+		yAxis: {
+			type: 'value',
+			axisLine: { show: false },
+			splitLine: { lineStyle: { color: '#f3f4f6' } },
+			axisLabel: { color: '#6b7280' },
+		},
+		series: [
+			{
+				name: '新增人数',
+				type: 'line',
+				smooth: true,
+				showSymbol: true,
+				symbolSize: 6,
+				itemStyle: { color: '#409EFF' },
+				lineStyle: { color: '#409EFF' },
+				data: lineChartData.value.map((d) => d.value),
+			},
+		],
+	};
+	chartInstance.setOption(option);
+}
+
+onMounted(() => {
+	initLineChart();
+	initQualityChart();
+	initBehaviorChart();
+});
+
+watch(timeGranularity, () => {
+	// 静态页面:仅重新渲染
+	initLineChart();
+});
+
+// 表格相关(静态数据)
+const tableRows = ref<TableRow[]>(
+	Array.from({ length: 42 }).map((_, idx) => ({
+		date: `2025-08-${String(11).padStart(2, '0')}`,
+		newUsers: 727,
+        hyyh:'115',
+        xyhzb:'111',
+        gqqr:'112',
+		ratio: '97.45%',
+	}))
+);
+
+const currentPage = ref(1);
+const pageSize = ref(5);
+const pagedTableRows = computed(() => {
+	const startIndex = (currentPage.value - 1) * pageSize.value;
+    
+	return tableRows.value.slice(startIndex, startIndex + pageSize.value);
+});
+
+const Title = defineAsyncComponent(() => import('/@/components/Title/index.vue'));
+
+// 展开/收起明细
+const showDetail1 = ref(true);
+
+// 用户质量(留存率)
+const qualityChartRef = ref<HTMLDivElement | null>(null);
+let qualityChart: echarts.ECharts | null = null;
+
+const qualityXAxis = ref<string[]>([
+	'2025-07-01',
+	'2025-07-08',
+	'2025-07-15',
+	'2025-07-22',
+	'2025-07-29',
+	'2025-08-05',
+	'2025-08-12',
+	'2025-08-19',
+	'2025-08-26',
+	'2025-09-02',
+	'2025-09-09',
+	'2025-09-16',
+]);
+
+const retentionSeries = ref<number[]>([20, 23, 27, 24, 22, 15, 5, 4, 16, 26, 25, 2]);
+const industryAvgSeries = ref<number[]>([16, 18, 20, 24, 25, 24, 16, 10, 15, 22, 21, 12]);
+const peerSameScaleSeries = ref<number[]>([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
+
+function initQualityChart(): void {
+	if (!qualityChartRef.value) return;
+	if (qualityChart) qualityChart.dispose();
+	qualityChart = echarts.init(qualityChartRef.value);
+	const option: echarts.EChartsOption = {
+		tooltip: { trigger: 'axis', valueFormatter: (v) => `${v}%` },
+		legend: { data: ['留存率', '同行业App', '同行业同规模App'] },
+		grid: { left: 40, right: 20, top: 30, bottom: 30 },
+		xAxis: { type: 'category', data: qualityXAxis.value },
+		yAxis: {
+			type: 'value',
+			min: 0,
+			max: 30,
+			axisLabel: { formatter: '{value}%' },
+			splitLine: { lineStyle: { color: '#f3f4f6' } },
+		},
+		series: [
+			{ name: '留存率', type: 'line', smooth: true, data: retentionSeries.value },
+			{ name: '同行业App', type: 'line', smooth: true, data: industryAvgSeries.value, color: '#f59e0b' },
+			{ name: '同行业同规模App', type: 'line', smooth: true, data: peerSameScaleSeries.value, color: '#60a5fa' },
+		],
+	};
+	qualityChart.setOption(option);
+}
+
+// 用户行为分析(静态)
+const behaviorChartRef = ref<HTMLDivElement | null>(null);
+let behaviorChart: echarts.ECharts | null = null;
+
+const behaviorXAxis = ref<string[]>([
+	'2025-07-01',
+	'2025-07-08',
+	'2025-07-15',
+	'2025-07-22',
+	'2025-07-29',
+	'2025-08-05',
+	'2025-08-12',
+	'2025-08-19',
+	'2025-08-26',
+	'2025-09-02',
+	'2025-09-09',
+	'2025-09-16',
+]);
+
+const activeUsersSeries = ref<number[]>([100, 120, 130, 110, 105, 90, 80, 70, 95, 110, 100, 85]);
+const avgSessionSeries = ref<number[]>([120, 130, 140, 125, 120, 110, 100, 95, 115, 125, 120, 110]);
+const behaviorAvgSeries = ref<number[]>([110, 115, 120, 115, 110, 105, 100, 95, 110, 115, 110, 105]);
+
+function initBehaviorChart(): void {
+	if (!behaviorChartRef.value) return;
+	if (behaviorChart) behaviorChart.dispose();
+	behaviorChart = echarts.init(behaviorChartRef.value);
+	const option: echarts.EChartsOption = {
+		tooltip: { trigger: 'axis', valueFormatter: (v) => `${v}s` },
+		legend: { data: ['活跃用户数', '平均会话时长', '行为均值'] },
+		grid: { left: 40, right: 20, top: 30, bottom: 30 },
+		xAxis: { type: 'category', data: behaviorXAxis.value },
+		yAxis: {
+			type: 'value',
+			min: 0,
+			max: 150,
+			axisLabel: { formatter: '{value}s' },
+			splitLine: { lineStyle: { color: '#f3f4f6' } },
+		},
+		series: [
+			{ name: '活跃用户数', type: 'line', smooth: true, data: activeUsersSeries.value },
+			{ name: '平均会话时长', type: 'line', smooth: true, data: avgSessionSeries.value, color: '#f59e0b' },
+			{ name: '行为均值', type: 'line', smooth: true, data: behaviorAvgSeries.value, color: '#60a5fa' },
+		],
+	};
+	behaviorChart.setOption(option);
+}
+</script>
+
+<style lang="scss" scoped>
+.highlight {
+	color: #2196f3;
+}
+</style>

+ 11 - 0
src/views/count/user/adduser/i18n/en.ts

@@ -0,0 +1,11 @@
+export default {
+	addUser: {
+		analytics:'Added user analysis',
+		growth:'Go to U-Growth to text/push',
+		ai:'Generative AI intelligence',
+		addtrend:'New trends',
+		channel:'Select a channel',
+		userQuality:'User quality',
+		average:'Industry average'
+	},
+};

+ 11 - 0
src/views/count/user/adduser/i18n/zh-cn.ts

@@ -0,0 +1,11 @@
+export default {
+	addUser: {
+		analytics:'新增用户分析',
+		growth:'前往U-Growth发短信/Push',
+		ai:'生成ai智能',
+		addtrend:'新增趋势',
+		channel:'选择渠道',
+		userQuality:'用户质量',
+		average:'行业平均值'
+	},
+};

+ 397 - 3
src/views/count/user/adduser/index.vue

@@ -1,7 +1,401 @@
 <template>
-   <div>adduser</div>
+	<div class="layout-padding">
+		<div class="!overflow-auto px-1">
+			<div class="el-card p-2">
+				<div class="flex justify-between">
+					<Title :title="t('addUser.analytics')" />
+					<div class="">
+						<el-button type="primary">{{ t('addUser.growth') }}</el-button>
+						<el-button type="primary">{{ t('addUser.ai') }}</el-button>
+					</div>
+				</div>
+				<div>
+					<el-row shadow="hover" class="ml10">
+						<el-form :inline="true" :model="formData" @keyup.enter="query" ref="queryRef">
+							<el-form-item>
+								<el-date-picker v-model="formData.time" type="daterange" start-placeholder="开始时间" end-placeholder="结束时间" />
+							</el-form-item>
+							<el-form-item prop="appId">
+								<el-input :placeholder="'请输入应用ID'" clearable v-model="formData.appId" />
+							</el-form-item>
+						</el-form>
+					</el-row>
+				</div>
+			</div>
+			<div class="mt-3 el-card p-2">
+				<!-- 新增趋势 -->
+				<div class="">
+					<Title left-line :title="t('addUser.addtrend')">
+						<template #default>
+							<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>
+											</div>
+										</div>
+									</template>
+								</el-popover>
+						</template>
+					</Title>
+					<div class="flex items-center justify-between mb-2 mt-3">
+						<el-form>
+							<el-form-item>
+								<el-select v-model="selectedChannelCompare" style="width: 140px" placeholder="渠道对比">
+									<el-option v-for="item in channelCompareOptions" :key="item.value" :label="item.label" :value="item.value" />
+								</el-select>
+								<el-button class="ml-2">{{ t('addUser.channel') }}</el-button>
+							</el-form-item>
+						</el-form>
+						<div class="flex items-center">
+							<el-radio-group v-model="timeGranularity" size="small">
+								<el-radio-button label="hour">小时</el-radio-button>
+								<el-radio-button label="day">天</el-radio-button>
+								<el-radio-button label="week">周</el-radio-button>
+								<el-radio-button label="month">月</el-radio-button>
+							</el-radio-group>
+						</div>
+					</div>
+
+					<div class="relative">
+						<div ref="lineChartRef" style="width: 100%; height: 320px"></div>
+					</div>
+				</div>
+
+				<!-- 明细表格 -->
+				<div class="mt-3">
+					<div class="flex items-center justify-between mb-2">
+						<div class="text-base font-medium cursor-pointer select-none" @click="showDetail1 = !showDetail1">
+							{{ showDetail1 ? '收起明细数据' : '展开明细数据' }}
+						</div>
+						<div>
+							<el-button>导出</el-button>
+						</div>
+					</div>
+					<el-table v-if="showDetail1" :data="pagedTableRows" border>
+						<el-table-column prop="date" label="日期" min-width="140" />
+						<el-table-column label="新增用户(占比)" min-width="220">
+							<template #default="scope">
+								<div class="flex items-center justify-between w-full">
+									<span>{{ scope.row.newUsers }}</span>
+									<span class="text-gray-500 text-xs">{{ scope.row.ratio }}</span>
+								</div>
+							</template>
+						</el-table-column>
+					</el-table>
+					<div v-if="showDetail1" class="flex justify-end mt-3">
+						<el-pagination
+							v-model:current-page="currentPage"
+							v-model:page-size="pageSize"
+							background
+							layout="total, prev, pager, next, sizes"
+							:total="tableRows.length"
+							:page-sizes="[5, 10, 20]"
+						/>
+					</div>
+				</div>
+			</div>
+			<div class="mt-3 el-card p-2">
+				<!-- 新增用户质量 -->
+				<div class="">
+					<div class="flex items-center justify-between mb-2">
+						<Title left-line :title="t('addUser.userQuality')">
+							<template #default>
+								<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>
+											</div>
+										</div>
+									</template>
+								</el-popover>
+							</template>
+						</Title>
+						
+					</div>
+					<div class="flex items-center ">
+							<el-select v-model="industryCompare" style="width: 120px">
+								<el-option label="行业对比" value="industry" />
+							</el-select>
+							<el-button class="ml-2">{{ t('addUser.average') }}</el-button>
+							<el-button link class="ml-2">清除</el-button>
+						</div>
+					<div class="relative">
+						<div ref="qualityChartRef" style="width: 100%; height: 320px"></div>
+					</div>
+				</div>
+				<!-- 明细表格 -->
+				<div class="mt-3">
+					<div class="flex items-center justify-between mb-2">
+						<div class="text-base font-medium cursor-pointer select-none" @click="showDetail1 = !showDetail1">
+							{{ showDetail1 ? '收起明细数据' : '展开明细数据' }}
+						</div>
+						<div>
+							<el-button>导出</el-button>
+						</div>
+					</div>
+					<el-table v-if="showDetail1" :data="pagedTableRows" border>
+						<el-table-column prop="date" label="日期" min-width="140" />
+						<el-table-column label="新增用户(占比)" min-width="220">
+							<template #default="scope">
+								<div class="flex items-center justify-between w-full">
+									<span>{{ scope.row.newUsers }}</span>
+									<span class="text-gray-500 text-xs">{{ scope.row.ratio }}</span>
+								</div>
+							</template>
+						</el-table-column>
+					</el-table>
+					<div v-if="showDetail1" class="flex justify-end mt-3">
+						<el-pagination
+							v-model:current-page="currentPage"
+							v-model:page-size="pageSize"
+							background
+							layout="total, prev, pager, next, sizes"
+							:total="tableRows.length"
+							:page-sizes="[5, 10, 20]"
+						/>
+					</div>
+				</div>
+			</div>
+		</div>
+	</div>
 </template>
 
-<script lang="ts" setup>
+<script setup lang="ts">
+import { ref, onMounted, watch, computed, defineAsyncComponent } from 'vue';
+import * as echarts from 'echarts';
+import { useI18n } from 'vue-i18n';
+
+const { t } = useI18n();
+
+interface TableRow {
+	date: string;
+	newUsers: number;
+	ratio: string;
+}
+
+const formData = ref<Record<string, any>>({});
+const query = () => {
+	console.log(formData.value);
+};
+
+const selectedChannelCompare = ref('');
+const channelCompareOptions = [
+	{ label: '渠道对比', value: 'compare' },
+	{ label: '渠道A', value: 'a' },
+	{ label: '渠道B', value: 'b' },
+];
+
+// 图表相关
+const timeGranularity = ref<'hour' | 'day' | 'week' | 'month'>('week');
+const lineChartRef = ref<HTMLDivElement | null>(null);
+let chartInstance: echarts.ECharts | null = null;
+
+const lineChartData = ref<Array<{ x: string; value: number }>>([
+	{ x: '2025-07-01', value: 900 },
+	{ x: '2025-07-08', value: 1000 },
+	{ x: '2025-07-15', value: 1100 },
+	{ x: '2025-07-22', value: 1000 },
+	{ x: '2025-07-29', value: 600 },
+	{ x: '2025-08-05', value: 300 },
+	{ x: '2025-08-12', value: 250 },
+	{ x: '2025-08-19', value: 200 },
+	{ x: '2025-08-26', value: 650 },
+	{ x: '2025-09-02', value: 950 },
+	{ x: '2025-09-09', value: 900 },
+	{ x: '2025-09-16', value: 120 },
+]);
+
+function initLineChart(): void {
+	if (!lineChartRef.value) return;
+	if (chartInstance) chartInstance.dispose();
+	chartInstance = echarts.init(lineChartRef.value);
+	const option: echarts.EChartsOption = {
+		tooltip: { trigger: 'axis' },
+		grid: { left: 40, right: 20, top: 20, bottom: 30 },
+		xAxis: {
+			type: 'category',
+			data: lineChartData.value.map((d) => d.x),
+			axisLine: { lineStyle: { color: '#e5e7eb' } },
+			axisLabel: { color: '#6b7280' },
+			axisTick: { alignWithLabel: true },
+		},
+		yAxis: {
+			type: 'value',
+			axisLine: { show: false },
+			splitLine: { lineStyle: { color: '#f3f4f6' } },
+			axisLabel: { color: '#6b7280' },
+		},
+		series: [
+			{
+				name: '新增人数',
+				type: 'line',
+				smooth: true,
+				showSymbol: true,
+				symbolSize: 6,
+				itemStyle: { color: '#409EFF' },
+				lineStyle: { color: '#409EFF' },
+				data: lineChartData.value.map((d) => d.value),
+			},
+		],
+	};
+	chartInstance.setOption(option);
+}
+
+onMounted(() => {
+	initLineChart();
+	initQualityChart();
+	console.log(qualityChart);
+	initBehaviorChart();
+});
+
+watch(timeGranularity, () => {
+	// 静态页面:仅重新渲染
+	initLineChart();
+});
+
+// 表格相关(静态数据)
+const tableRows = ref<TableRow[]>(
+	Array.from({ length: 42 }).map((_, idx) => ({
+		date: `2025-08-${String(11).padStart(2, '0')}`,
+		newUsers: 727,
+		ratio: '97.45%',
+	}))
+);
+
+const currentPage = ref(1);
+const pageSize = ref(5);
+const pagedTableRows = computed(() => {
+	const startIndex = (currentPage.value - 1) * pageSize.value;
+	return tableRows.value.slice(startIndex, startIndex + pageSize.value);
+});
+
+const Title = defineAsyncComponent(() => import('/@/components/Title/index.vue'));
+
+// 展开/收起明细
+const showDetail1 = ref(true);
+
+// 用户质量(留存率)
+const industryCompare = ref('industry');
+const qualityChartRef = ref<HTMLDivElement | null>(null);
+let qualityChart: echarts.ECharts | null = null;
+
+const qualityXAxis = ref<string[]>([
+	'2025-07-01',
+	'2025-07-08',
+	'2025-07-15',
+	'2025-07-22',
+	'2025-07-29',
+	'2025-08-05',
+	'2025-08-12',
+	'2025-08-19',
+	'2025-08-26',
+	'2025-09-02',
+	'2025-09-09',
+	'2025-09-16',
+]);
+
+const retentionSeries = ref<number[]>([20, 23, 27, 24, 22, 15, 5, 4, 16, 26, 25, 2]);
+const industryAvgSeries = ref<number[]>([16, 18, 20, 24, 25, 24, 16, 10, 15, 22, 21, 12]);
+const peerSameScaleSeries = ref<number[]>([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
+
+function initQualityChart(): void {
+	if (!qualityChartRef.value) return;
+	if (qualityChart) qualityChart.dispose();
+	qualityChart = echarts.init(qualityChartRef.value);
+	const option: echarts.EChartsOption = {
+		tooltip: { trigger: 'axis', valueFormatter: (v) => `${v}%` },
+		legend: { data: ['留存率', '同行业App', '同行业同规模App'] },
+		grid: { left: 40, right: 20, top: 30, bottom: 30 },
+		xAxis: { type: 'category', data: qualityXAxis.value },
+		yAxis: {
+			type: 'value',
+			min: 0,
+			max: 30,
+			axisLabel: { formatter: '{value}%' },
+			splitLine: { lineStyle: { color: '#f3f4f6' } },
+		},
+		series: [
+			{ name: '留存率', type: 'line', smooth: true, data: retentionSeries.value },
+			{ name: '同行业App', type: 'line', smooth: true, data: industryAvgSeries.value, color: '#f59e0b' },
+			{ name: '同行业同规模App', type: 'line', smooth: true, data: peerSameScaleSeries.value, color: '#60a5fa' },
+		],
+	};
+	qualityChart.setOption(option);
+}
+
+
+
+
+
+// 用户行为分析(静态)
+const behaviorChartRef = ref<HTMLDivElement | null>(null);
+let behaviorChart: echarts.ECharts | null = null;
+
+const behaviorXAxis = ref<string[]>([
+	'2025-07-01',
+	'2025-07-08',
+	'2025-07-15',
+	'2025-07-22',
+	'2025-07-29',
+	'2025-08-05',
+	'2025-08-12',
+	'2025-08-19',
+	'2025-08-26',
+	'2025-09-02',
+	'2025-09-09',
+	'2025-09-16',
+]);
+
+const activeUsersSeries = ref<number[]>([100, 120, 130, 110, 105, 90, 80, 70, 95, 110, 100, 85]);
+const avgSessionSeries = ref<number[]>([120, 130, 140, 125, 120, 110, 100, 95, 115, 125, 120, 110]);
+const behaviorAvgSeries = ref<number[]>([110, 115, 120, 115, 110, 105, 100, 95, 110, 115, 110, 105]);
+
+function initBehaviorChart(): void {
+	if (!behaviorChartRef.value) return;
+	if (behaviorChart) behaviorChart.dispose();
+	behaviorChart = echarts.init(behaviorChartRef.value);
+	const option: echarts.EChartsOption = {
+		tooltip: { trigger: 'axis', valueFormatter: (v) => `${v}s` },
+		legend: { data: ['活跃用户数', '平均会话时长', '行为均值'] },
+		grid: { left: 40, right: 20, top: 30, bottom: 30 },
+		xAxis: { type: 'category', data: behaviorXAxis.value },
+		yAxis: {
+			type: 'value',
+			min: 0,
+			max: 150,
+			axisLabel: { formatter: '{value}s' },
+			splitLine: { lineStyle: { color: '#f3f4f6' } },
+		},
+		series: [
+			{ name: '活跃用户数', type: 'line', smooth: true, data: activeUsersSeries.value },
+			{ name: '平均会话时长', type: 'line', smooth: true, data: avgSessionSeries.value, color: '#f59e0b' },
+			{ name: '行为均值', type: 'line', smooth: true, data: behaviorAvgSeries.value, color: '#60a5fa' },
+		],
+	};
+	behaviorChart.setOption(option);
+}
+
+
+
+</script>
 
-</script>
+<style lang="scss" scoped>
+.highlight{
+	color: #2196f3;
+}
+</style>