Przeglądaj źródła

feat(customers-voice):用户之声模块-详情页添加
--标题卡片
--折线图图表
--表格

xinyan 5 miesięcy temu
rodzic
commit
bdf29239fd

+ 118 - 88
src/views/customers-voice/components/show-detail/components/DataDisplay.vue

@@ -6,12 +6,14 @@
  */
 import * as api from '/@/views/customers-voice/api';
 import { useResponse } from '/@/utils/useResponse';
-import { onMounted, ref } from 'vue';
+import { onMounted, reactive } from 'vue';
 
+// 定义 Props
 const props: any = defineProps({
 	rowData: Object,
 	queryParameter: Object,
 });
+
 const { rowData, queryParameter } = props;
 const start_time = dayjs(queryParameter?.date[0]).format('YYYY-MM-DD');
 const end_time = dayjs(queryParameter?.date[1]).format('YYYY-MM-DD');
@@ -23,128 +25,156 @@ interface Comment {
 	date: string;
 }
 
-const negativeCommentList = ref<Comment[]>([]); // 评论列表
-const page = ref(1); // 当前页
-const loading = ref(false); // 加载状态
-const noMore = ref(false); // 是否没有更多数据
-const disabled = computed(() => loading.value || noMore.value);
+function createGridOptions() {
+	return reactive({
+		size: 'mini',
+		border: true,
+		// stripe: true,
+		showHeader: false,
+		height: 500,
+		// showOverflow: 'tooltip',
+		loading: false,
+		rowConfig: {
+			isCurrent: true,
+			isHover: true,
+			height: 50,
+		},
+		loadingConfig: {
+			icon: 'vxe-icon-indicator roll',
+			text: '加载中...',
+		},
+		// tooltipConfig: {
+		// 	zIndex: 9999,
+		// },
+		pagerConfig: {
+			total: 0,
+			page: 1,
+			limit: 10, // 每页条数
+		},
+		columns: [{ field: 'comment', title: '评论内容', align: 'center', width: 500 }],
+		data: [] as Comment[],
+	});
+}
 
-// 获取评论数据
-async function fetchList() {
-	if (loading.value || noMore.value) return; // 防止重复请求或没有更多数据时请求
+// 每个表格的配置
+const returnGridOptions = createGridOptions(); // 退货评论
+const feedbackGridOptions = createGridOptions(); // 反馈评论
+const reviewGridOptions = createGridOptions(); // 评价评论
 
-	loading.value = true;
+// 获取数据
+async function handlePageChange(option: string, gridOptions: any) {
+	gridOptions.loading = true;
 
-	// 请求参数
+	// 请求参数,动态更新分页信息
 	const query = {
-		asin: 'B0D21RMR85', // 请根据实际情况替换
+		asin: rowData.asin,
 		start_time: start_time,
 		end_time: end_time,
-		option: 'return_negative_comment',
-		page: page.value,
-		limit: 5,
+		option,
+		page: gridOptions.pagerConfig.page,
+		limit: gridOptions.pagerConfig.limit,
 	};
 
 	try {
 		const resp = await useResponse(api.getCommentData, query);
-		const newData = resp.data;
-
-		// 如果返回数据少于 5 条,说明没有更多数据
-		if (newData.length < 5) {
-			noMore.value = true;
-		}
-
-		// 合并数据
-		negativeCommentList.value = [...negativeCommentList.value, ...newData];
-		console.log('=>(DataDisplay.vue:58) negativeCommentList.value', negativeCommentList.value);
-
-		// 页数加 1
-		page.value += 1;
+		gridOptions.data = resp.data;
+		gridOptions.pagerConfig.total = resp.total || 0; // 更新总数
 	} catch (error) {
-		console.error('加载评论数据失败:', error);
+		console.error(`加载 ${option} 数据失败:`, error);
 	} finally {
-		loading.value = false;
+		gridOptions.loading = false;
 	}
 }
 
-// 在组件加载时获取数据
+function cellStyle(){
+	return {
+		fontSize: '14px',
+		color:'#666',
+		fontWeight: 600,
+	};
+}
+
+// 组件加载时获取数据
 onMounted(() => {
-	fetchList();
+	handlePageChange('return_negative_comment', returnGridOptions);
+	handlePageChange('feedback_negative_comment', feedbackGridOptions);
+	handlePageChange('review_negative_comment', reviewGridOptions);
 });
 </script>
 
 <template>
-	<el-card style="height: 600px">
+	<div class="mt-5" style="height: 600px">
 		<el-row>
+			<!-- 退货评论 -->
 			<el-col :span="8">
-				<div class="infinite-list-wrapper" style="overflow: auto">
-					<ul v-infinite-scroll="fetchList" :infinite-scroll-disabled="disabled" class="list">
-						<li v-for="item in negativeCommentList" :key="item.order_id" class="list-item">
-							<div class="comment-text">{{ item.comment }}</div>
-						</li>
-					</ul>
-					<p v-if="loading">Loading...</p>
-					<p v-if="noMore">No more</p>
+				<div class="title">
+					<div class="font-semibold italic mb-2">退货评论</div>
+					<vxe-grid v-bind="returnGridOptions" :cell-style="cellStyle">
+						<template #empty>
+							<el-empty description="暂无数据" />
+						</template>
+						<template #pager>
+							<vxe-pager
+								v-model:currentPage="returnGridOptions.pagerConfig.page"
+								v-model:pageSize="returnGridOptions.pagerConfig.limit"
+								:total="returnGridOptions.pagerConfig.total"
+								class="mt-1.5"
+								@page-change="() => handlePageChange('return_negative_comment', returnGridOptions)"
+							/>
+						</template>
+					</vxe-grid>
 				</div>
 			</el-col>
+
+			<!-- 反馈评论 -->
 			<el-col :span="8">
-				<div class="infinite-list-wrapper" style="overflow: auto">
-					<ul v-infinite-scroll="fetchList" :infinite-scroll-disabled="disabled" class="list">
-						<li v-for="item in negativeCommentList" :key="item.order_id" class="list-item">
-							<div class="comment-text">{{ item.comment }}</div>
-						</li>
-					</ul>
-					<p v-if="loading">Loading...</p>
-					<p v-if="noMore">No more</p>
+				<div class="title">
+					<div class="font-semibold italic mb-2">反馈评论</div>
+					<vxe-grid v-bind="feedbackGridOptions">
+						<template #empty>
+							<el-empty description="暂无数据" />
+						</template>
+						<template #pager>
+							<vxe-pager
+								v-model:currentPage="feedbackGridOptions.pagerConfig.page"
+								v-model:pageSize="feedbackGridOptions.pagerConfig.limit"
+								:total="feedbackGridOptions.pagerConfig.total"
+								class="mt-1.5"
+								@page-change="() => handlePageChange('feedback_negative_comment', feedbackGridOptions)"
+							/>
+						</template>
+					</vxe-grid>
 				</div>
 			</el-col>
+
+			<!-- 评价评论 -->
 			<el-col :span="8">
-				<div class="infinite-list-wrapper" style="overflow: auto">
-					<ul v-infinite-scroll="fetchList" :infinite-scroll-disabled="disabled" class="list">
-						<li v-for="item in negativeCommentList" :key="item.order_id" class="list-item">
-							<div class="comment-text">{{ item.comment }}</div>
-						</li>
-					</ul>
-					<p v-if="loading">Loading...</p>
-					<p v-if="noMore">No more</p>
+				<div class="title">
+					<div class="font-semibold italic mb-2">评价评论</div>
+					<vxe-grid v-bind="reviewGridOptions">
+						<template #empty>
+							<el-empty description="暂无数据" />
+						</template>
+						<template #pager>
+							<vxe-pager
+								v-model:currentPage="reviewGridOptions.pagerConfig.page"
+								v-model:pageSize="reviewGridOptions.pagerConfig.limit"
+								:total="reviewGridOptions.pagerConfig.total"
+								class="mt-1.5"
+								@page-change="() => handlePageChange('review_negative_comment', reviewGridOptions)"
+							/>
+						</template>
+					</vxe-grid>
 				</div>
 			</el-col>
 		</el-row>
-	</el-card>
+	</div>
 </template>
 
 <style scoped>
-.infinite-list-wrapper {
-	height: 300px;
-	text-align: center;
-}
-.infinite-list-wrapper .list {
-	padding: 0;
-	margin: 0;
-	list-style: none;
-}
-
-.infinite-list-wrapper .list-item {
+.title {
 	display: flex;
+	flex-direction: column;
 	align-items: center;
-	justify-content: center;
-	height: 50px;
-	background: var(--el-color-primary-light-9);
-	margin: 10px;
-	color: var(--el-color-primary);
-}
-.infinite-list-wrapper .list-item + .list-item {
-	margin-top: 10px;
-}
-
-.comment-text {
-	display: -webkit-box;
-	-webkit-box-orient: vertical;
-	-webkit-line-clamp: 1; /* 显示的行数 */
-	overflow: hidden;
-	text-overflow: ellipsis;
-	max-height: 4.5em; /* 根据字号和行高设置最大高度 */
-	line-height: 1.5em; /* 控制行高,与你的内容相匹配 */
-	font-size: 14px;
 }
 </style>

+ 23 - 16
src/views/customers-voice/components/show-detail/components/LineChart.vue

@@ -51,11 +51,19 @@ const option: any = {
 	// },
 	tooltip: {
 		trigger: 'axis',
+		formatter: (params) => {
+			// console.log(params);
+			let relVal =  params[0].name;
+			for (let i = 0, l = params.length; i < l; i++) {
+				relVal += '<br/>' + params[i].marker + ' ' + params[i].seriesName + ' ' + (params[i].value * 100).toFixed(2) + ' %'; // 修正为 toFixed
+			}
+			return relVal;
+		},
 	},
-	legend: {
-		top: '10%',
-		align: 'right',
-	},
+	// legend: {
+	// 	top: '10%',
+	// 	align: 'right',
+	// },
 	grid: {
 		top: '30%',
 		left: '5%',
@@ -71,9 +79,6 @@ const option: any = {
 		{
 			type: 'value',
 			name: 'NCX Rate',
-			min: 2,
-			max: 5,
-			interval: 0.5,
 			position: 'left',
 			axisLine: {
 				show: true,
@@ -82,14 +87,16 @@ const option: any = {
 				},
 			},
 			axisLabel: {
-				formatter: '{value} 分',
+				formatter: function (value) {
+					return (value * 100).toFixed(2)+  ' %'; // 将值乘以100并保留两位小数
+				},
 			},
 		},
 	],
 	series: [
 		{
 			id: 0,
-			name: 'NCX Rate',
+			name: '28 天平均值',
 			type: 'line',
 			yAxisIndex: 0,
 			itemStyle: {
@@ -122,8 +129,8 @@ async function loadData() {
 		};
 		const res = await getChartData(query);
 		if (res.code === 2000 && res.data) {
-			option.xAxis.data = res.data.date;
-			option.series[0].data = res.data.ncx_rate;
+			option.xAxis.data = res.data.map((item) => item.date);
+			option.series[0].data = res.data.map((item) => item.ncx_rate);
 		}
 	} catch (e) {
 		ElMessage.error('加载数据失败,请稍后再试');
@@ -149,10 +156,10 @@ function removeResize() {
 </script>
 
 <template>
-	<div v-loading="loading" class="mt-10">
-		<div class="mb-3 flex items-center">
+	<el-card v-loading="loading" class="border-none mt-5">
+		<div class=" flex items-center">
 			<span class="font-semibold italic mr-2">时间范围:</span>
-			<el-select v-model="week" style="width: 100px">
+			<el-select v-model="week" style="width: 100px" @change="loadData">
 				<el-option label="一周" value="1"></el-option>
 				<el-option label="两周" value="2"></el-option>
 				<el-option label="四周" value="4"></el-option>
@@ -162,8 +169,8 @@ function removeResize() {
 			</el-select>
 		</div>
 		<!-- 图表区域 -->
-		<div ref="chartRef" style="width: 100%; height: 520px; background: #fff"></div>
-	</div>
+		<div ref="chartRef" style="width: 100%; height: 500px; background: #fff"></div>
+	</el-card>
 </template>
 
 <style scoped></style>

+ 70 - 66
src/views/customers-voice/components/show-detail/components/TitleCard.vue

@@ -29,74 +29,78 @@ const ncx_rate = computed(() => {
 
 <template>
 	<el-card body-class="flex justify-between items-center gap-5" class="border-none top-5 z-10 mt-5">
-		<div class="flex">
-			<el-image :src="`https://d1ge0kk1l5kms0.cloudfront.net/images/I/${rowData.img}.jpg`" class="mr-5"
-								fit="fill"
-								lazy style="min-width: 135px; height: 135px;">
-				<template #error>
-					<div class="flex justify-center items-center h-full w-full text-2xl"
-							 style="background:var(--el-fill-color-light)">
-						<el-icon>
-							<icon-picture />
-						</el-icon>
-					</div>
-				</template>
-			</el-image>
-			<div class="flex flex-col justify-between">
-				<el-link :href="url"
-								 :underline="false"
-								 target="_blank"
-								 style="font-size: 18px;justify-content: left !important;"
-								 :disabled="!rowData.product_name"
-								 type="primary">
-					<span class="line-clamp-2 text-ellipsis whitespace-normal" >{{ rowData.product_name || '--' }}</span>
-				</el-link>
-				<div class="mt-2">
-					<el-row>
-						<el-col :span="6">
-							<div class="font-semibold italic">ASIN : {{ rowData.asin || '-'}}</div>
-						</el-col>
-						<el-col :span="6">
-							<div class="font-semibold italic">SKU : {{ rowData.sku || '-'}}</div>
-						</el-col>
-					</el-row>
-					<el-divider style="margin-top: 10px;margin-bottom: 10px;"/>
-					<el-row>
-						<el-col :span="3">
-							<div class="font-semibold italic">总订单数 : {{ rowData.order_count || '-'}}</div>
-						</el-col>
-						<el-col :span="3">
-							<div class="font-semibold italic">NCX订单 : {{ rowData.ncx_count || '-'}}</div>
-						</el-col>
-						<el-col :span="3">
-							<div class="font-semibold italic">NCX率 : {{ ncx_rate || '-'}}</div>
-						</el-col>
-						<el-col :span="3">
-							<div class="font-semibold italic">退货率 : {{ rowData.return_record_rate || '-'}}</div>
-						</el-col>
-						<el-col :span="6">
-							<div class="font-semibold italic">最近更新 : {{ rowData.last_updated_date || '-'}}</div>
-						</el-col>
-						<el-col :span="4">
-							<div>
-								<template v-if="rowData.all_score !== null && rowData.all_score !== undefined && rowData.all_score !== ''">
-									<el-tooltip v-if="rowData.all_score > 0" :content="rowData.all_score" effect="dark" placement="top" show-after="350">
-										<div class="flex items-center">
-											<div class="font-semibold italic">星级 :</div>
-											<el-rate v-if="rowData.all_score > 0" v-model="rowData.all_score" :colors="['#FF0000', '#FF9900', '#67C23A']" disabled text-color="#1e293b" />
-										</div>
-									</el-tooltip>
-									<span v-else>{{ rowData.all_score }}</span>
-								</template>
-								<template v-else>
-									<span>-</span>
-								</template>
+				<div class="flex">
+					<el-image :src="`https://d1ge0kk1l5kms0.cloudfront.net/images/I/${rowData.img}.jpg`" class="mr-5"
+										fit="fill"
+										lazy style="min-width: 135px; height: 135px;">
+						<template #error>
+							<div class="flex justify-center items-center h-full w-full text-2xl"
+									 style="background:var(--el-fill-color-light)">
+								<el-icon>
+									<icon-picture />
+								</el-icon>
 							</div>
-						</el-col>
-					</el-row>
+						</template>
+					</el-image>
+					<div class="flex flex-col justify-between">
+						<el-row>
+							<el-col :span="24">
+								<el-link :href="url"
+												 :underline="false"
+												 target="_blank"
+												 style="font-size: 18px;justify-content: left !important;"
+												 :disabled="!rowData.product_name"
+												 type="primary">
+									<span class="line-clamp-2 text-ellipsis whitespace-normal" >{{ rowData.product_name || '--' }}</span>
+								</el-link>
+							</el-col>
+						</el-row>
+						<div class="mt-2">
+							<el-row>
+								<el-col :span="6">
+									<div class="font-semibold italic">ASIN : {{ rowData.asin || '-'}}</div>
+								</el-col>
+								<el-col :span="6">
+									<div class="font-semibold italic">SKU : {{ rowData.sku || '-'}}</div>
+								</el-col>
+							</el-row>
+							<el-divider style="margin-top: 10px;margin-bottom: 10px;"/>
+							<el-row>
+								<el-col :span="3">
+									<div class="font-semibold italic">总订单数 : {{ rowData.order_count || '-'}}</div>
+								</el-col>
+								<el-col :span="3">
+									<div class="font-semibold italic">NCX订单 : {{ rowData.ncx_count || '-'}}</div>
+								</el-col>
+								<el-col :span="3">
+									<div class="font-semibold italic">NCX率 : {{ ncx_rate || '-'}}</div>
+								</el-col>
+								<el-col :span="3">
+									<div class="font-semibold italic">退货率 : {{ rowData.return_record_rate || '-'}}</div>
+								</el-col>
+								<el-col :span="6">
+									<div class="font-semibold italic">最近更新 : {{ rowData.last_updated_date || '-'}}</div>
+								</el-col>
+								<el-col :span="6">
+									<div>
+										<template v-if="rowData.all_score !== null && rowData.all_score !== undefined && rowData.all_score !== ''">
+											<el-tooltip v-if="rowData.all_score > 0" :content="rowData.all_score" effect="dark" placement="top" show-after="350">
+												<div class="flex items-center">
+													<div class="font-semibold italic">星级 :</div>
+													<el-rate v-if="rowData.all_score > 0" v-model="rowData.all_score" :colors="['#FF0000', '#FF9900', '#67C23A']" disabled text-color="#1e293b" />
+												</div>
+											</el-tooltip>
+											<span v-else>{{ rowData.all_score }}</span>
+										</template>
+										<template v-else>
+											<span>-</span>
+										</template>
+									</div>
+								</el-col>
+							</el-row>
+						</div>
+					</div>
 				</div>
-			</div>
-		</div>
 		<!--<el-button :icon="Back" plain round type="info" @click="handleBack">返 回</el-button>-->
 	</el-card>
 </template>

+ 4 - 2
src/views/customers-voice/components/show-detail/index.vue

@@ -36,12 +36,14 @@ const emit = defineEmits(['refresh']);
 			:close-on-click-modal="false"
 			:close-on-press-escape="false"
 			direction="btt"
-			size="80%"
+			size="90%"
 		>
 			<div class="px-5">
 				<TitleCard :rowData="rowData"></TitleCard>
 				<LineChart :queryParameter="queryParameter" :rowData="rowData"></LineChart>
-				<DataDisplay :queryParameter="queryParameter" :rowData="rowData"></DataDisplay>
+				<el-card class="border-none mt-5">
+					<DataDisplay :queryParameter="queryParameter" :rowData="rowData"></DataDisplay>
+				</el-card>
 			</div>
 		</el-drawer>
 	</div>