cankao-admin/src/views/pages/comprehensive/index.vue

612 lines
16 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="index inside_pd">
<div class="colHeader" style="align-items: start">
<div class="page_title">全量资讯库</div>
<div style="width: 100%; display: flex; align-items: flex-end">
<div style="display: flex; align-items: center; margin-bottom: 10px">
<el-button type="primary" @click="restData">清空条件</el-button>
<el-button type="primary" icon="Plus" @click="goDetail(0, null, false)">创建新资讯</el-button>
</div>
<div class="colHeader-right">
<el-space :size="12" class="colHeader-right-1">
<el-input v-model="form.title" placeholder="输入标题关键字进行搜索" class="input-with-select" @keyup.enter="handleSearch">
<template #append>
<el-button icon="Search" @click="handleSearch" />
</template>
</el-input>
<el-input v-model="form.content" placeholder="输入内容关键字进行搜索" class="input-with-select" @keyup.enter="handleSearch">
<template #append>
<el-button icon="Search" @click="handleSearch" />
</template>
</el-input>
<el-select-v2
v-model="form.sourcename"
:options="tagSourceList"
clearable
placeholder="媒体来源"
size="large"
style="width: 240px"
filterable
@change="handleSearch"
/>
</el-space>
<el-space :size="12" class="colHeader-right-1" style="margin-top: 10px">
<el-date-picker
v-model="daterange"
type="daterange"
range-separator="至"
value-format="YYYY-MM-DD"
start-placeholder="选择报道时间"
end-placeholder="选择报道时间"
style="margin-right: 12px"
@change="handleSearch"
/>
<div style="display: flex; flex-wrap: nowrap; align-items: center">
<span>评分范围:</span>
<el-input
type="number"
v-model="form.minScore"
style="width: 80px"
placeholder="最低"
:min="0"
:max="100"
@keyup.enter="handleSearch"
/>
<i style="color: #ccc"> - </i>
<el-input type="number" v-model="form.maxScore" style="width: 140px" placeholder="最高" :min="0" :max="100" @keyup.enter="handleSearch">
<template #append>
<el-button icon="Search" @click="handleSearch" />
</template>
</el-input>
</div>
</el-space>
<!-- <el-button type="primary" icon="Plus" @click="toDetail({}, false)">创建新资讯</el-button> -->
</div>
</div>
</div>
<tableComponents
ref="tableRef"
:tableData="tableData"
style="margin-top: 20px"
@sortChange="sortChange"
:tableLoading="tableLoading"
@currentChange="currentChange"
@sizeChange="sizeChange"
>
<el-table-column prop="title" label="标题" align="left" width="300">
<template v-slot="scope">
<span class="cursor-pointer" @click="goDetail(1, scope.row, true)" v-html="scope.row.title"></span>
</template>
</el-table-column>
<el-table-column label="资讯评分" sortable="custom" align="center">
<template v-slot="scope">
<!-- {{ scope.row.score != 0 && scope.row.score != null ? scope.row.score : '-' }} -->
<div @click="getScoreDetail(scope.row.id)" :class="[{ 'score-active': isAdmin && curScore === scope.row.id }, { 'score-hover': isAdmin }]">
{{ scope.row.score }}
</div>
</template>
</el-table-column>
<el-table-column prop="inputDate" label="报道时间" sortable="custom" align="center">
<template v-slot="scope">
<span>{{ formatDate(new Date(scope.row.inputDate), 'YYYY-mm-dd HH:MM:SS') }}</span>
</template>
</el-table-column>
<el-table-column prop="updateTime" label="编辑时间" sortable="custom" align="center" />
<el-table-column prop="sourcename" label="媒体来源" align="center" />
<el-table-column label="操作" align="center" width="250">
<template v-slot="scope">
<div class="option">
<el-button type="text" @click="goDetail(1, scope.row, false)">编辑</el-button>
<!-- <el-button type="text" @click="toDetail(scope.row, false)">编辑</el-button> -->
<el-button type="text" v-if="scope.row.status == 2" @click="doNewsPublishFn(scope.row, 1)">撤稿</el-button>
<el-button type="text" v-else @click="doNewsPublishFn(scope.row, 2)">发布</el-button>
<el-button type="text" style="color: #ff1818" @click="doDeleteNewsFn(scope.row)">删除</el-button>
</div>
</template>
</el-table-column>
</tableComponents>
<DetailDrawer
v-if="drawer"
v-model="drawer"
:data="newsData"
:readOnly="readOnly"
:type="newstype"
@handleEditStatus="handleEditStatus"
@doNewsPublishFn="doNewsPublishFn"
@doDeleteNewsFn="doDeleteNewsFn"
@getData="getData"
/>
<el-dialog v-model="isScoreShow" title="资讯评分详情" width="680" center>
<div class="score-detail">
<el-row class="score-detail-row">
<el-col :span="6" class="score-detail-label">行业分类标注</el-col>
<el-col :span="18">
<el-row>[{{ scoreDetail?.industryLabel.join(',') }}]</el-row>
<el-row justify="space-between">
<el-col :span="12">置信度:[{{ scoreDetail?.industryConfidence.join(',') }}]</el-col>
<el-col :span="12" style="text-align: right"
>分类评分:<span style="color: #36a4f8">[{{ scoreDetail?.industryScore.join(',') }}]</span></el-col
>
</el-row>
</el-col>
</el-row>
<el-row class="score-detail-row">
<el-col :span="6" class="score-detail-label">概念标签标注</el-col>
<el-col :span="18">
<el-row>[{{ scoreDetail?.conceptLabel.join(',') }}]</el-row>
<el-row justify="space-between">
<el-col :span="12">置信度:[{{ scoreDetail?.conceptConfidence.join(',') }}]</el-col>
<el-col :span="12" style="text-align: right"
>概念评分:<span style="color: #36a4f8">[{{ scoreDetail?.conceptScore.join(',') }}]</span></el-col
>
</el-row>
</el-col>
</el-row>
<el-row class="score-detail-row rule" style="border-bottom: 1px solid #ccc; padding-bottom: 12px">
<el-col :span="24">*计算规则</el-col>
<el-col :span="24">资讯行业or概念指标得分=资讯评分*行业or概念中的置信度</el-col>
</el-row>
<el-row class="score-detail-row">
<el-col :span="12">媒体影响力</el-col>
<el-col :span="12" style="text-align: right"
>评分:<span style="color: #36a4f8">{{ scoreDetail?.sourceImpact }}</span></el-col
>
</el-row>
<el-row class="score-detail-row">
<el-col :span="12">中国股市相关性</el-col>
<el-col :span="12" style="text-align: right"
>置信度:<span style="color: #36a4f8">{{ scoreDetail?.chinaFactor }}</span></el-col
>
</el-row>
<el-row class="score-detail-row">
<el-col :span="12">资讯质量</el-col>
<el-col :span="12" style="text-align: right"
>评分:<span style="color: #36a4f8">{{ scoreDetail?.publicOpinionScore }}</span></el-col
>
</el-row>
<el-row class="score-detail-row rule">
<el-col :span="24">*计算规则</el-col>
<el-col :span="24">资讯评分=媒体影响力分*0.04+资讯质量分*0.25+中国股市相关分*35</el-col>
</el-row>
<el-row class="score-detail-row" justify="space-between">
<el-col :span="12">资讯评分</el-col>
<el-col :span="12" style="color: #36a4f8; text-align: right; font-weight: 700">{{ scoreDetail?.newsScore }}</el-col>
</el-row>
</div>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="isScoreShow = false">关闭</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup lang="ts" name="loginIndex">
import { onMounted, reactive, ref, computed } from 'vue';
import { NextLoading } from '/@/utils/loading';
import { ElMessage, ElMessageBox } from 'element-plus';
import tableComponents from '/@/components/tableComponents/index.vue';
import { useRoute, useRouter } from 'vue-router';
import icon_table_filter from '/@/assets/icon_table_filter.png';
import DetailDrawer from './DetailDrawer/index.vue';
import { getNewsInfoScore, getNewsInfo, getNewsInfoPublish, delNewsInfo, getColumn, getNewsInfoSave, getTagSource } from '/@/api/api';
import { highlightTitle } from '/@/utils/highlight';
import clipboard from 'clipboard';
import { encode, decode } from 'js-base64';
import { formatDate } from '/@/utils/formatTime';
/** 管理后台需求文件0519V1.1 start */
const drawer = ref(false);
const newsData = ref<any>();
const readOnly = ref(false);
const newstype = ref(0);
const daterange = ref();
/** 管理后台需求文件0519V1.1 end */
// 多选的栏目
const checkList = ref([]);
const route = useRoute();
const router = useRouter();
const form = ref({
orderBy: 'inputDate',
direction: 'desc',
});
const tableData = reactive({
data: [],
total: 0,
page: 1,
size: 10,
});
const tableLoading = ref(false);
/**
* 进入详情页
* @param type 0创建 1编辑
*/
function goDetail(type, item, readonly) {
readOnly.value = readonly;
newsData.value = item;
newstype.value = type;
drawer.value = true;
}
async function doDeleteNewsFn(item) {
ElMessageBox.confirm('是否确认要删除本篇文章?删除后无法找回', '提示', {
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning',
})
.then(async () => {
let { code, data } = await delNewsInfo({
id: item.id,
});
if (code == 200) {
ElMessage.success('操作成功');
drawer.value = false;
getData();
}
})
.catch(() => {});
}
function handleSearch() {
tableData.page = 1;
getData();
}
// 新的分页入参
const cursorPage = ref<any>(null);
// 获取列表
async function getData() {
tableLoading.value = true;
let header: any = {};
if (cursorPage.value && cursorPage.value.pitId !== '') {
header = {
'X-Pagination-Cursor': encode(cursorPage.value.pitId + '|' + cursorPage.value.searchAfter),
};
}
try {
let _sdate = '';
let _edate = '';
if (daterange.value) {
_sdate = daterange.value[0];
_edate = daterange.value[1];
}
let { code, data, total, cursor } = await getNewsInfo(
{
...form.value,
// page: tableData.page,
current: tableData.page,
size: tableData.size,
inputDateFrom: _sdate || undefined,
inputDateTo: _edate || undefined,
},
header
);
console.log('🚀 ~ getData ~ data:', data);
tableLoading.value = false;
if (code == 200) {
tableData.data = data;
console.log('🚀 ~ getData ~ tableData.data:', tableData.data);
tableData.total = total;
tableData.data.forEach((item, index) => {
item.title = highlightTitle(item.title, form.value.title);
});
cursorPage.value = cursor;
}
} catch (error) {
tableLoading.value = false;
}
}
/**
* 上下架
* @param item
* @param status 1下架 2上架
*/
async function doNewsPublishFn(item, status) {
let str = '请确认要下架该篇资讯?撤稿后前台将不可见本文章';
if (status == 1) {
str = '请确认要下架该篇资讯?撤稿后前台将不可见本文章';
} else {
str = '已同步至【资讯精选】,请确认审核无误后可发布。';
}
ElMessageBox.confirm(str, '提示', {
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning',
})
.then(async () => {
let { code } = await getNewsInfoPublish({
id: item.id,
});
if (code == 200) {
ElMessage.success('操作成功');
drawer.value = false;
getData();
}
})
.catch(() => {});
}
/**
* 表格排序改变
* @param row
*/
function sortChange(row) {
if (row.order == 'ascending') {
form.value.direction = 'asc';
} else if (row.order == 'descending') {
form.value.direction = 'desc';
}
form.value.orderBy = row.prop;
getData();
}
async function copyUrl(res) {
console.log('🚀 ~ copyUrl ~ res:', res);
let clipboardBean = new clipboard('.copyBtn', {
text: function (trigger) {
//返回的就是复制的内容,可以在返回前面对数据进行增强等...
// http://192.168.31.5:8881/#/pages/detail/index?id=0&needPay=0&type=article
ElMessage.success('复制成功');
return import.meta.env.VITE_API_URL_H5 + '/#/pages/realtimeInfo/pc/indexPC?id=' + res.id + '&type=2';
},
});
clipboardBean.on('success', function (e) {
console.log('成功复制...');
//复制完成后销毁clipboard对象预防下一次调用会多次提示
clipboardBean.destroy();
});
clipboardBean.on('error', function (e) {
console.log('失败...');
//复制完成后销毁clipboard对象预防下一次调用会多次提示
clipboardBean.destroy();
});
}
const columnList = ref([]);
// 获取栏目
async function getColumnFn(parent) {
let { code, data } = await getColumn({
page: 1,
size: 100000,
parent,
});
if (code == 200) {
return data;
} else {
return [];
}
}
function checkChange(val) {
let str = '';
val.forEach((item, index) => {
if (index < val.length - 1) {
str = str + item + ',';
} else {
str = str + item;
}
});
if (val.length > 0) {
form.value.column = str;
} else {
delete form.value.column;
}
getData();
}
function currentChange(val) {
console.log('🚀 ~ currentChange ~ val:', val);
tableData.page = val;
getData();
}
function sizeChange(val) {
console.log('🚀 ~ sizeChange ~ val:', val);
tableData.size = val;
getData();
}
function toDetail(data: any, val: boolean) {
readOnly.value = val;
newsData.value = data;
drawer.value = true;
}
function handleEditStatus(val: boolean) {
readOnly.value = val;
}
// 来源标签列表
const tagSourceList = ref([]);
async function getTagSourceFn() {
let { code, data } = await getTagSource({
page: 1,
size: 100000,
});
if (code == 200) {
tagSourceList.value = data.map((item: any) => {
return {
label: item.name,
value: item.id,
};
});
}
}
// 资讯评分详情
const isScoreShow = ref(false);
const curScore = ref(0);
const scoreDetail = ref<any>({});
const isAdmin = computed(() => {
return route.query.admin == 'superman' ? true : false;
});
async function getScoreDetail(id: any) {
if (!isAdmin.value) return;
curScore.value = id;
const result = await getNewsInfoScore({ id });
console.log('🚀 ~ getScoreDetail123 ~ result:', result);
if (result.code == 200) {
scoreDetail.value = result.data;
isScoreShow.value = true;
}
}
const tableRef = ref();
function restData() {
form.value.title = null;
form.value.content = null;
form.value.sourcename = null;
form.value.minScore = null;
form.value.maxScore = null;
daterange.value = null;
form.value.orderBy = 'inputDate';
form.value.direction = 'desc';
tableRef.value.clearSort();
tableData.page = 1;
getData();
}
// 页面加载时
onMounted(async () => {
NextLoading.done();
getTagSourceFn();
getData();
let arr = [];
arr = await getColumnFn(1);
if (arr) {
arr.forEach((item) => {
columnList.value.push(item);
});
}
let arr1 = [];
arr1 = await getColumnFn(null);
if (arr1) {
arr1.forEach((item) => {
if (item.name == '天下事' || item.name == '早知道') {
columnList.value.push(item);
}
});
}
});
</script>
<style scoped lang="scss">
.index {
background-color: white;
padding: 20px;
border-radius: 10px;
}
.option {
:deep(.el-button--large) {
padding: 0;
}
:deep(.is-disabled) {
color: rgba(24, 144, 255, 0.4);
}
}
.r_point {
display: flex;
align-items: center;
gap: 5px;
font-weight: 400;
}
.point {
width: 8px;
height: 8px;
border-radius: 100px;
}
.columns {
display: flex;
gap: 5px;
.column_item {
border: 1px solid #d9d9d9;
background-color: #fafafa;
padding: 2px 5px;
height: 30px;
text-wrap: nowrap;
}
}
:deep(.highlight) {
color: #ff0000;
font-weight: bold;
}
.colHeader-right {
flex: 1;
display: flex;
flex-direction: column;
text-align: start;
justify-content: flex-start;
align-items: flex-end;
min-width: 700px;
margin-right: 20px;
.colHeader-right-1,
.colHeader-right-2 {
display: flex;
justify-self: flex-end;
// align-items: center;
margin-bottom: 10px;
}
}
.colHeader {
//align-items: flex-start;
display: flex;
flex-direction: column;
}
.score-active {
cursor: pointer;
font-weight: 700;
color: #36a4f8;
}
.score-hover {
&:hover {
cursor: pointer;
font-weight: 700;
color: #36a4f8;
}
}
.score-detail {
font-size: 14px;
color: #333333;
.score-detail-row {
margin-top: 24px;
}
.rule {
font-size: 12px;
color: #8e8e8e;
}
}
</style>