|
@@ -15,13 +15,18 @@ import EditLabelDialog from '/@/views/product-manage/comment-detail/component/Ed
|
|
import { useResponse } from '/@/utils/useResponse';
|
|
import { useResponse } from '/@/utils/useResponse';
|
|
import { ElMessage } from 'element-plus';
|
|
import { ElMessage } from 'element-plus';
|
|
import { handleCopy } from '/@/utils/useCopyText';
|
|
import { handleCopy } from '/@/utils/useCopyText';
|
|
|
|
+import * as echarts from 'echarts';
|
|
|
|
+import 'echarts-wordcloud';
|
|
|
|
+
|
|
|
|
|
|
const isShowLabel = defineModel({ default: false });
|
|
const isShowLabel = defineModel({ default: false });
|
|
|
|
|
|
|
|
+
|
|
const props = defineProps({
|
|
const props = defineProps({
|
|
- rowData: <any>Object,
|
|
|
|
|
|
+ rowData: <any>Object,
|
|
});
|
|
});
|
|
|
|
|
|
|
|
+
|
|
const { rowData } = props;
|
|
const { rowData } = props;
|
|
const { tableOptions, handlePageChange } = usePagination(fetchList);
|
|
const { tableOptions, handlePageChange } = usePagination(fetchList);
|
|
|
|
|
|
@@ -32,317 +37,181 @@ const editData = ref<any>();
|
|
|
|
|
|
const gridRef = ref();
|
|
const gridRef = ref();
|
|
const gridOptions: any = reactive({
|
|
const gridOptions: any = reactive({
|
|
- // id: 'NegativeLabel-table',
|
|
|
|
- // keepSource: true,
|
|
|
|
- height: 620,
|
|
|
|
- size: 'mini',
|
|
|
|
- border: false,
|
|
|
|
- round: true,
|
|
|
|
- stripe: true,
|
|
|
|
- showHeader: true,
|
|
|
|
- showOverflow: true,
|
|
|
|
- currentRowHighLight: true,
|
|
|
|
- toolbarConfig: {
|
|
|
|
- size: 'large',
|
|
|
|
- slots: {
|
|
|
|
- buttons: 'toolbar_buttons',
|
|
|
|
- // tools: 'toolbar_tools',
|
|
|
|
- },
|
|
|
|
- },
|
|
|
|
- rowConfig: {
|
|
|
|
- isHover: true,
|
|
|
|
- },
|
|
|
|
- columnConfig: {
|
|
|
|
- resizable: true,
|
|
|
|
- },
|
|
|
|
- pagerConfig: {
|
|
|
|
- total: tableOptions.value.total,
|
|
|
|
- page: tableOptions.value.page,
|
|
|
|
- limit: tableOptions.value.limit,
|
|
|
|
- },
|
|
|
|
- loading: false,
|
|
|
|
- loadingConfig: {
|
|
|
|
- icon: 'vxe-icon-indicator roll',
|
|
|
|
- text: '正在拼命加载中...',
|
|
|
|
- },
|
|
|
|
- columns: '',
|
|
|
|
- data: '',
|
|
|
|
|
|
+ // id: 'NegativeLabel-table',
|
|
|
|
+ // keepSource: true,
|
|
|
|
+ height: 620,
|
|
|
|
+ size: 'mini',
|
|
|
|
+ border: false,
|
|
|
|
+ round: true,
|
|
|
|
+ stripe: true,
|
|
|
|
+ showHeader: true,
|
|
|
|
+ showOverflow: true,
|
|
|
|
+ currentRowHighLight: true,
|
|
|
|
+ toolbarConfig: {
|
|
|
|
+ size: 'large',
|
|
|
|
+ slots: {
|
|
|
|
+ buttons: 'toolbar_buttons'
|
|
|
|
+ // tools: 'toolbar_tools',
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ rowConfig: {
|
|
|
|
+ isHover: true
|
|
|
|
+ },
|
|
|
|
+ columnConfig: {
|
|
|
|
+ resizable: true
|
|
|
|
+ },
|
|
|
|
+ pagerConfig: {
|
|
|
|
+ total: tableOptions.value.total,
|
|
|
|
+ page: tableOptions.value.page,
|
|
|
|
+ limit: tableOptions.value.limit
|
|
|
|
+ },
|
|
|
|
+ loading: false,
|
|
|
|
+ loadingConfig: {
|
|
|
|
+ icon: 'vxe-icon-indicator roll',
|
|
|
|
+ text: '正在拼命加载中...'
|
|
|
|
+ },
|
|
|
|
+ columns: '',
|
|
|
|
+ data: ''
|
|
});
|
|
});
|
|
|
|
|
|
async function fetchList() {
|
|
async function fetchList() {
|
|
- gridOptions.data = [];
|
|
|
|
- gridOptions.columns = [];
|
|
|
|
-
|
|
|
|
- const query = {
|
|
|
|
- review: rowData.id,
|
|
|
|
- };
|
|
|
|
- await useTableData(api.getNegativeTags, query, gridOptions);
|
|
|
|
- await gridRef.value.loadColumn(NegativeLabelColumns);
|
|
|
|
- gridOptions.showHeader = Boolean(gridOptions.data?.length);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-function handleCreate() {
|
|
|
|
- createOpen.value = true;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-function handleEdit(row) {
|
|
|
|
- editOpen.value = true;
|
|
|
|
- editData.value = row;
|
|
|
|
-}
|
|
|
|
-import { onBeforeUnmount, ref } from 'vue';
|
|
|
|
-import * as api from '../api';
|
|
|
|
-import * as echarts from 'echarts';
|
|
|
|
-import 'echarts-wordcloud';
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-const props = defineProps({
|
|
|
|
- asin: String
|
|
|
|
-});
|
|
|
|
-const { asin } = props;
|
|
|
|
-
|
|
|
|
-const loading = ref(false);
|
|
|
|
-
|
|
|
|
-let responseData: any = null;
|
|
|
|
-const chartRef: any = useTemplateRef('chartRef');
|
|
|
|
-let chart: echarts.ECharts | null = null;
|
|
|
|
-let resizeObserver: ResizeObserver | null = null;
|
|
|
|
-const hasData = ref(true);
|
|
|
|
-
|
|
|
|
-onBeforeMount(() => {
|
|
|
|
- fetchWordCloudData();
|
|
|
|
-});
|
|
|
|
|
|
+ gridOptions.data = [];
|
|
|
|
+ gridOptions.columns = [];
|
|
|
|
|
|
-onBeforeUnmount(() => {
|
|
|
|
- // 清理 ResizeObserver
|
|
|
|
- if (resizeObserver) {
|
|
|
|
- resizeObserver.disconnect();
|
|
|
|
- }
|
|
|
|
- if (chart) {
|
|
|
|
- chart.dispose();
|
|
|
|
- chart = null;
|
|
|
|
- }
|
|
|
|
-});
|
|
|
|
-
|
|
|
|
-async function fetchWordCloudData() {
|
|
|
|
- loading.value = true;
|
|
|
|
const query = {
|
|
const query = {
|
|
- asin,
|
|
|
|
- agg_field: 'raw_label'
|
|
|
|
|
|
+ review: rowData.id
|
|
};
|
|
};
|
|
- try {
|
|
|
|
- responseData = await api.getWordCloudData(query);
|
|
|
|
- if (!responseData.data || responseData.data.length === 0) {
|
|
|
|
- // 处理空数据的情况
|
|
|
|
- hasData.value = false;
|
|
|
|
- if (chart) {
|
|
|
|
- chart.clear();
|
|
|
|
- }
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
- hasData.value = true;
|
|
|
|
- setOption();
|
|
|
|
- // initChart(option);
|
|
|
|
- } catch (error) {
|
|
|
|
- console.error('==Error==', error);
|
|
|
|
- } finally {
|
|
|
|
- loading.value = false;
|
|
|
|
- }
|
|
|
|
|
|
+ await useTableData(api.getNegativeTags, query, gridOptions);
|
|
|
|
+ await gridRef.value.loadColumn(NegativeLabelColumns);
|
|
|
|
+ gridOptions.showHeader = Boolean(gridOptions.data?.length);
|
|
}
|
|
}
|
|
|
|
|
|
-function setOption() {
|
|
|
|
- const option = {
|
|
|
|
- title: {
|
|
|
|
- text: '负面标签'
|
|
|
|
- },
|
|
|
|
- tooltip: {
|
|
|
|
- show: true
|
|
|
|
- },
|
|
|
|
- series: [
|
|
|
|
- {
|
|
|
|
- type: 'wordCloud',
|
|
|
|
- width: '90%',
|
|
|
|
- height: '85%',
|
|
|
|
- // 词云图的形状
|
|
|
|
- shape: 'star', // 可以是 'circle', 'cardioid', 'diamond', 'triangle-forward', 'triangle', 'pentagon', 'star'
|
|
|
|
- // 控制字体大小
|
|
|
|
- sizeRange: [12, 60],
|
|
|
|
- // 文本旋转角度
|
|
|
|
- rotationRange: [0, 0],
|
|
|
|
- rotationStep: 45,
|
|
|
|
- gridSize: 8,
|
|
|
|
- drawOutOfBound: false,
|
|
|
|
- shrinkToFit: false,
|
|
|
|
- layoutAnimation: true,
|
|
|
|
- // 全局的文字样式
|
|
|
|
- textStyle: {
|
|
|
|
- fontFamily: 'PingFang',
|
|
|
|
- fontWeight: 'bold',
|
|
|
|
- // Color can be a callback function or a color string
|
|
|
|
- color: function () {
|
|
|
|
- // Random color
|
|
|
|
- return 'rgb(' + [
|
|
|
|
- Math.round(Math.random() * 160),
|
|
|
|
- Math.round(Math.random() * 160),
|
|
|
|
- Math.round(Math.random() * 160)
|
|
|
|
- ].join(',') + ')'
|
|
|
|
- }
|
|
|
|
- },
|
|
|
|
- // 鼠标hover时的样式
|
|
|
|
- emphasis: {
|
|
|
|
- focus: 'self',
|
|
|
|
- textStyle: {
|
|
|
|
- textShadowBlur: 10,
|
|
|
|
- textShadowColor: '#333'
|
|
|
|
- }
|
|
|
|
- },
|
|
|
|
- // left: '10%',
|
|
|
|
- // top: '10%',
|
|
|
|
- // right: '10%',
|
|
|
|
- // bottom: '10%',
|
|
|
|
- data: responseData.data,
|
|
|
|
- }
|
|
|
|
- ],
|
|
|
|
- backgroundColor: '#fff'
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
- if (!chart) {
|
|
|
|
- chart = echarts.init(chartRef.value);
|
|
|
|
- }
|
|
|
|
- chart.setOption(option);
|
|
|
|
|
|
+function handleCreate() {
|
|
|
|
+ createOpen.value = true;
|
|
|
|
+}
|
|
|
|
|
|
- // 添加 ResizeObserver 以处理图表大小变化
|
|
|
|
- if (!resizeObserver) {
|
|
|
|
- resizeObserver = new ResizeObserver(() => {
|
|
|
|
- chart?.resize();
|
|
|
|
- });
|
|
|
|
- resizeObserver.observe(chartRef.value);
|
|
|
|
- }
|
|
|
|
|
|
+function handleEdit(row: any) {
|
|
|
|
+ editOpen.value = true;
|
|
|
|
+ editData.value = row;
|
|
}
|
|
}
|
|
|
|
|
|
async function singleDelete(row: any) {
|
|
async function singleDelete(row: any) {
|
|
- const res = await useResponse(api.deleteNegativeTags, row);
|
|
|
|
- if (res.code === 2000) {
|
|
|
|
- ElMessage.success({ message: '删除成功', plain: true });
|
|
|
|
- await fetchList();
|
|
|
|
- }
|
|
|
|
|
|
+ const res = await useResponse(api.deleteNegativeTags, row);
|
|
|
|
+ if (res.code === 2000) {
|
|
|
|
+ ElMessage.success({ message: '删除成功', plain: true });
|
|
|
|
+ await fetchList();
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
function cellStyle() {
|
|
function cellStyle() {
|
|
- return{
|
|
|
|
- fontWeight: 500,
|
|
|
|
- }
|
|
|
|
|
|
+ return {
|
|
|
|
+ fontWeight: 500
|
|
|
|
+ };
|
|
}
|
|
}
|
|
|
|
|
|
onMounted(() => {
|
|
onMounted(() => {
|
|
- fetchList();
|
|
|
|
|
|
+ fetchList();
|
|
});
|
|
});
|
|
</script>
|
|
</script>
|
|
|
|
|
|
<template>
|
|
<template>
|
|
- <div class="drawer-container">
|
|
|
|
- <el-drawer
|
|
|
|
- ref="editDrawer"
|
|
|
|
- v-model="isShowLabel"
|
|
|
|
- :show-close="false"
|
|
|
|
- direction="rtl"
|
|
|
|
- size="50%"
|
|
|
|
- style="background-color: #f3f4fb"
|
|
|
|
- title="负面标签"
|
|
|
|
- >
|
|
|
|
- <div class="sticky top-0" style="background-color: #f3f4fb; min-height: 20px; z-index: 2"></div>
|
|
|
|
- <div class="px-5">
|
|
|
|
- <el-card class="mb-3">
|
|
|
|
- <el-descriptions :column="1" direction="vertical">
|
|
|
|
- <el-descriptions-item>
|
|
|
|
- <template #label>
|
|
|
|
- <div class="title-item">标题</div>
|
|
|
|
- </template>
|
|
|
|
- <span class="cell-item">{{ rowData.title }}</span>
|
|
|
|
- </el-descriptions-item>
|
|
|
|
- <el-descriptions-item>
|
|
|
|
- <template #label>
|
|
|
|
- <div class="title-item">评论内容</div>
|
|
|
|
- </template>
|
|
|
|
- <span class="cell-item">{{ rowData.content }}</span>
|
|
|
|
- <el-icon class="ml-2 cursor-pointer" @click="handleCopy(rowData.content)">
|
|
|
|
- <DocumentCopy />
|
|
|
|
- </el-icon>
|
|
|
|
- </el-descriptions-item>
|
|
|
|
- </el-descriptions>
|
|
|
|
- </el-card>
|
|
|
|
- <el-card>
|
|
|
|
- <vxe-grid ref="gridRef" v-bind="gridOptions" :cell-style="cellStyle">
|
|
|
|
- <template #toolbar_buttons>
|
|
|
|
- <div class="flex gap-2">
|
|
|
|
- <PermissionButton :icon="Plus" plain round type="primary" @click="handleCreate"> 新 增 </PermissionButton>
|
|
|
|
- </div>
|
|
|
|
- </template>
|
|
|
|
- <template #operate="{ row }">
|
|
|
|
- <div class="flex justify-center gap-2">
|
|
|
|
- <el-button :icon="Edit" link type="primary" @click="handleEdit(row)"></el-button>
|
|
|
|
- <el-popconfirm
|
|
|
|
- :icon="InfoFilled"
|
|
|
|
- icon-color="#626AEF"
|
|
|
|
- title="你确定要删除此项吗?"
|
|
|
|
- width="220"
|
|
|
|
- @confirm="singleDelete(row)"
|
|
|
|
- >
|
|
|
|
- <template #reference>
|
|
|
|
- <PermissionButton link type="danger">
|
|
|
|
- <el-icon>
|
|
|
|
- <Delete />
|
|
|
|
- </el-icon>
|
|
|
|
- </PermissionButton>
|
|
|
|
- </template>
|
|
|
|
- <template #actions="{ confirm, cancel }">
|
|
|
|
- <el-button size="small" @click="cancel">No!</el-button>
|
|
|
|
- <el-button
|
|
|
|
- size="small"
|
|
|
|
- type="danger"
|
|
|
|
- @click="confirm"
|
|
|
|
- >
|
|
|
|
- Yes?
|
|
|
|
- </el-button>
|
|
|
|
- </template>
|
|
|
|
- </el-popconfirm>
|
|
|
|
- </div>
|
|
|
|
- </template>
|
|
|
|
- <template #pager>
|
|
|
|
- <vxe-pager
|
|
|
|
- v-model:currentPage="gridOptions.pagerConfig.page"
|
|
|
|
- v-model:pageSize="gridOptions.pagerConfig.limit"
|
|
|
|
- :total="gridOptions.pagerConfig.total"
|
|
|
|
- class="mt-1.5"
|
|
|
|
- @page-change="handlePageChange"
|
|
|
|
- />
|
|
|
|
- </template>
|
|
|
|
- </vxe-grid>
|
|
|
|
- </el-card>
|
|
|
|
- </div>
|
|
|
|
- </el-drawer>
|
|
|
|
- <CreateLabelDialog v-if="createOpen" v-model="createOpen" :rowData="rowData" @refresh="fetchList"></CreateLabelDialog>
|
|
|
|
- <EditLabelDialog v-if="editOpen" v-model="editOpen" :editData="editData" :rowData="rowData" @refresh="fetchList"></EditLabelDialog>
|
|
|
|
- </div>
|
|
|
|
- <el-card v-loading="loading" class="border-none" shadow="never">
|
|
|
|
- <!-- 空状态 和 词云图 -->
|
|
|
|
- <div class="w-full" style="min-height: 500px">
|
|
|
|
- <div v-show="!loading && !hasData" style="min-height: 500px">
|
|
|
|
- <el-empty :image-size="300" />
|
|
|
|
|
|
+ <div class="drawer-container">
|
|
|
|
+ <el-drawer
|
|
|
|
+ ref="editDrawer"
|
|
|
|
+ v-model="isShowLabel"
|
|
|
|
+ :show-close="false"
|
|
|
|
+ direction="rtl"
|
|
|
|
+ size="50%"
|
|
|
|
+ style="background-color: #f3f4fb"
|
|
|
|
+ title="负面标签"
|
|
|
|
+ >
|
|
|
|
+ <div class="sticky top-0" style="background-color: #f3f4fb; min-height: 20px; z-index: 2"></div>
|
|
|
|
+ <div class="px-5">
|
|
|
|
+ <el-card class="mb-3">
|
|
|
|
+ <el-descriptions :column="1" direction="vertical">
|
|
|
|
+ <el-descriptions-item>
|
|
|
|
+ <template #label>
|
|
|
|
+ <div class="title-item">标题</div>
|
|
|
|
+ </template>
|
|
|
|
+ <span class="cell-item">{{ rowData.title }}</span>
|
|
|
|
+ </el-descriptions-item>
|
|
|
|
+ <el-descriptions-item>
|
|
|
|
+ <template #label>
|
|
|
|
+ <div class="title-item">评论内容</div>
|
|
|
|
+ </template>
|
|
|
|
+ <span class="cell-item">{{ rowData.content }}</span>
|
|
|
|
+ <el-icon class="ml-2 cursor-pointer" @click="handleCopy(rowData.content)">
|
|
|
|
+ <DocumentCopy />
|
|
|
|
+ </el-icon>
|
|
|
|
+ </el-descriptions-item>
|
|
|
|
+ </el-descriptions>
|
|
|
|
+ </el-card>
|
|
|
|
+ <el-card>
|
|
|
|
+ <vxe-grid ref="gridRef" :cell-style="cellStyle" v-bind="gridOptions">
|
|
|
|
+ <template #toolbar_buttons>
|
|
|
|
+ <div class="flex gap-2">
|
|
|
|
+ <PermissionButton :icon="Plus" plain round type="primary" @click="handleCreate"> 新 增</PermissionButton>
|
|
|
|
+ </div>
|
|
|
|
+ </template>
|
|
|
|
+ <template #operate="{ row }">
|
|
|
|
+ <div class="flex justify-center gap-2">
|
|
|
|
+ <el-button :icon="Edit" link type="primary" @click="handleEdit(row)"></el-button>
|
|
|
|
+ <el-popconfirm
|
|
|
|
+ :icon="InfoFilled"
|
|
|
|
+ icon-color="#626AEF"
|
|
|
|
+ title="你确定要删除此项吗?"
|
|
|
|
+ width="220"
|
|
|
|
+ @confirm="singleDelete(row)"
|
|
|
|
+ >
|
|
|
|
+ <template #reference>
|
|
|
|
+ <PermissionButton link type="danger">
|
|
|
|
+ <el-icon>
|
|
|
|
+ <Delete />
|
|
|
|
+ </el-icon>
|
|
|
|
+ </PermissionButton>
|
|
|
|
+ </template>
|
|
|
|
+ <template #actions="{ confirm, cancel }">
|
|
|
|
+ <el-button size="small" @click="cancel">No!</el-button>
|
|
|
|
+ <el-button
|
|
|
|
+ size="small"
|
|
|
|
+ type="danger"
|
|
|
|
+ @click="confirm"
|
|
|
|
+ >
|
|
|
|
+ Yes?
|
|
|
|
+ </el-button>
|
|
|
|
+ </template>
|
|
|
|
+ </el-popconfirm>
|
|
|
|
+ </div>
|
|
|
|
+ </template>
|
|
|
|
+ <template #pager>
|
|
|
|
+ <vxe-pager
|
|
|
|
+ v-model:currentPage="gridOptions.pagerConfig.page"
|
|
|
|
+ v-model:pageSize="gridOptions.pagerConfig.limit"
|
|
|
|
+ :total="gridOptions.pagerConfig.total"
|
|
|
|
+ class="mt-1.5"
|
|
|
|
+ @page-change="handlePageChange"
|
|
|
|
+ />
|
|
|
|
+ </template>
|
|
|
|
+ </vxe-grid>
|
|
|
|
+ </el-card>
|
|
</div>
|
|
</div>
|
|
- <div v-show="hasData" ref="chartRef" style="width: 100%; height: 500px"></div>
|
|
|
|
- </div>
|
|
|
|
- </el-card>
|
|
|
|
|
|
+ </el-drawer>
|
|
|
|
+ <CreateLabelDialog v-if="createOpen" v-model="createOpen" :rowData="rowData" @refresh="fetchList"></CreateLabelDialog>
|
|
|
|
+ <EditLabelDialog v-if="editOpen" v-model="editOpen" :editData="editData" :rowData="rowData"
|
|
|
|
+ @refresh="fetchList"></EditLabelDialog>
|
|
|
|
+ </div>
|
|
|
|
+
|
|
</template>
|
|
</template>
|
|
|
|
|
|
<style scoped>
|
|
<style scoped>
|
|
.title-item {
|
|
.title-item {
|
|
- font-weight: bold;
|
|
|
|
- font-size: 16px;
|
|
|
|
|
|
+ font-weight: bold;
|
|
|
|
+ font-size: 16px;
|
|
}
|
|
}
|
|
|
|
|
|
.cell-item {
|
|
.cell-item {
|
|
- font-size: 14px;
|
|
|
|
- font-weight: 600;
|
|
|
|
- color: #666;
|
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
+ font-weight: 600;
|
|
|
|
+ color: #666;
|
|
}
|
|
}
|
|
</style>
|
|
</style>
|