cankao-admin/src/views/pages/richedit/indexMobile.vue

645 lines
20 KiB
Vue
Raw Normal View History

2025-08-03 13:41:47 +08:00
<template>
<div class="all" ref="mescrollRef" v-infinite-scroll="getDataByScoll" style="overflow-y: auto">
<div style="display: flex; align-items: center">
<el-input v-model="form.keyword" placeholder="输入关键字进行搜索(以空格隔开)" class="input-with-select"
@keyup.enter="handleSearch" style="width: 80%">
<template #append>
<el-button icon="Search" @click="handleSearch" />
</template>
</el-input>
<el-button style="width: 20%" type="text" @click="restData">清空条件</el-button>
</div>
<el-date-picker style="margin-top: 20px; width: 100%; max-height: 40px" v-model="daterange" type="daterange"
range-separator="至" value-format="YYYY-MM-DD" start-placeholder="选择报道时间" end-placeholder="选择报道时间"
@change="handleSearch" />
<div class="filter">
<div class="r_tabs">
<div class="tabItem" v-for="(item, index) in tabsList" :key="index" @click="changeTab(index)">
<text :style="{
color: tabIndex == index ? '#409eff' : '#333',
fontWeight: tabIndex == index ? 'bold' : 'normal',
}">{{ item.name }}</text>
<div class="tab_line" v-if="tabIndex == index"></div>
</div>
</div>
<!-- <SortButton ref="sortRef" @changeSort="changeSort"></SortButton> -->
</div>
<div class="r_list" v-loading="loading" ref="listRef">
<el-card v-for="(item, index) in tableData.data" :key="index" class="card">
<template #header>
<div class="card_header" @click.stop="goDetail(1, item, true)">
<text class="card_title" v-html="item.title"></text>
<div class="r_point" :style="{ color: '#000' }">
<div class="point" :style="{ backgroundColor: item.status == 2 ? '#52C41A' : '#D9D9D9' }">
</div>
<text v-if="item.status == 0" style="color: rgba(0, 0, 0, 0.65)">草稿</text>
<text v-if="item.status == 1" style="color: rgba(0, 0, 0, 0.65)">
{{ item.deleted ? '已删除' : '未发布' }}
</text>
<text v-if="item.status == 2" style="color: rgba(0, 0, 0, 0.65)">已发布</text>
<text v-if="item.status == 3" style="color: rgba(0, 0, 0, 0.65)">审核中</text>
<text v-if="item.status == 4" style="color: rgba(0, 0, 0, 0.65)">已二审</text>
<text v-if="item.status == -1 && !item.deleted" style="color: red"> 退改中 </text>
<text v-if="item.status == -1 && item.deleted"> 已删除 </text>
</div>
</div>
</template>
<div style="display: flex; align-items: center" @click.stop="goDetail(1, item, true)">
<div style="display: flex; align-items: center; gap: 5px" v-if="item.submitter">
<el-icon>
<UserFilled />
</el-icon>
<text>{{ item.submitter }}</text>
</div>
<div style="margin-left: 20px" v-if="item.rating != 0 && item.rating != null">
<text>编辑评分</text>
<text>{{ item.rating }}</text>
</div>
</div>
<template #footer>
<div style="display: flex; justify-content: space-between; align-items: center; height: 10px">
<div>
<text>报道时间</text>
<text>{{ item.publishTime }}</text>
</div>
<div class="option">
<el-button v-if="item.deleted" type="text" style="margin-left: -10px"
@click="doRecoverFn(item)">
<text>恢复</text>
</el-button>
<div v-else
style="display: flex; gap: 3px; align-items: center; flex-wrap: nowrap; white-space: nowrap">
<!-- 新闻状态 0-草稿 | 1-未发布 | 2-已发布 | 3-送审 | 4-已二审 | -1-退改中 -->
<div v-if="Session.get('userInfoLocal').userType == '00'">
<!-- 普通账号 -->
<el-button v-if="item.status == 0 || item.status == 1 || item.status == -1"
type="text" @click="goDetail(1, item, false)">编辑</el-button>
<el-button v-if="item.status == 0 || item.status == 1 || item.status == -1"
type="text" @click="doApprovalFn(item, item.status)">送审</el-button>
<el-button v-else-if="item.status == 3" type="text"
@click="doApprovalFn(item, item.status)">撤审</el-button>
<el-button v-if="item.status == 0 || item.status == 1 || item.status == -1"
type="text" style="color: #ff1818" @click="doDeleteNewsFn(item)">删除</el-button>
</div>
<div v-if="Session.get('userInfoLocal').userType == '02'">
<el-button v-if="item.status == 4" type="text"
@click="doApprovalFn(item, item.status)">撤审</el-button>
<!-- 二审账号 -->
<el-button v-if="item.status == 3" type="text" style="color: #ff1818"
@click="doNewReturnFn(item)">退改</el-button>
<el-button v-if="item.status == 3" type="text"
@click="goDetail(1, item, false)">编辑</el-button>
<el-button v-if="item.status == 3" type="text"
@click="doNewCheckFn(item)">复审</el-button>
<el-button type="text" v-if="item.status == 4"
@click="doNewsPublishFn(item, 2)">发布</el-button>
</div>
<div v-if="Session.get('userInfoLocal').userType == '01'">
<!-- 终审账号 -->
<el-button v-if="item.status == 3 || item.status == 4" type="text"
@click="goDetail(1, item, false)">编辑</el-button>
<el-button v-if="item.status == 4" type="text" style="color: #ff1818"
@click="doNewReturnFn(item)">退改</el-button>
<el-button type="text" v-if="item.status == 2"
@click="doNewsPublishFn(item, 1)">撤稿</el-button>
<el-button type="text" v-else-if="item.status != -1 && item.status == 4"
@click="doNewsPublishFn(item, 2)">发布</el-button>
<el-button v-if="item.status == 3" type="text"
style="color: #ff1818; margin-left: 5px"
@click="doNewReturnFn(item)">退改</el-button>
</div>
<!-- <el-icon size="16" @click="goRecord(scope.row)">
<Tickets />
</el-icon> -->
</div>
</div>
</div>
</template>
</el-card>
<text class="bottom_load_text" v-if="tableData.data.length < tableData.total">--- 正在加载中 ---</text>
<text class="bottom_load_text" v-else>--- 已经到底了 ---</text>
</div>
<div v-if="isShowBackTop" class="back_top" @click="goTop">
<el-icon>
<CaretTop />
</el-icon>
</div>
<keep-alive>
<DetailDrawer v-model="drawer" :data="newsData" :readOnly="readOnly" :type="newstype"
@handleEditStatus="handleEditStatus" @doNewsPublishFn="doNewsPublishFn" @doDeleteNewsFn="doDeleteNewsFn"
@getData="getData" />
</keep-alive>
</div>
2025-08-03 13:41:47 +08:00
</template>
<script setup lang="ts" name="loginIndex">
import { onUnmounted, onMounted, reactive, ref } 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 SortButton from '/@/components/mobile/SortButton.vue';
import { Session } from '/@/utils/storage';
import { isMobileByWidth } from '/@/utils/Utils';
import { doNewRevoke, doNewSubmit, doNewLog, getNews, doNewsPublish, doNewCheck, doNewReturn } from '/@/api/api';
import preventBack from 'vue-prevent-browser-back'; //组件内单独引入
2025-08-03 13:41:47 +08:00
import router from '/@/router';
import { highlightTitle } from '/@/utils/highlight';
2025-08-03 13:41:47 +08:00
const loading = ref(false);
2025-08-03 13:41:47 +08:00
const tabsList = ref([
{
name: '审核中',
status: 3,
},
{
name: '已发布',
status: 2,
},
{
name: '全部',
status: null,
},
]);
const tabIndex = ref(0);
2025-08-03 13:41:47 +08:00
function changeTab(index) {
tabIndex.value = index;
form.value.status = tabsList.value[index].status;
getData();
2025-08-03 13:41:47 +08:00
}
function changeSort(sort) {
form.value.orderBy = 'publishTime$' + sort;
getData();
2025-08-03 13:41:47 +08:00
}
const form = ref({
// orderBy: 'updateTime$desc',
orderBy: null,
// direction: 'desc',
keyword: '',
minScore: '',
maxScore: '',
industry: [],
2025-08-03 13:41:47 +08:00
});
const tableData = reactive({
data: [],
total: 0,
page: 1,
size: 10,
2025-08-03 13:41:47 +08:00
});
function getDataByScoll() {
if (tableData.data.length < tableData.total) {
tableData.page++;
getData();
}
2025-08-03 13:41:47 +08:00
}
const tableLoading = ref(false);
const daterange = ref('');
// 获取列表
async function getData() {
// return
if (form.value.minScore && form.value.maxScore && Number(form.value.maxScore) < Number(form.value.minScore)) {
ElMessage.error('最高分不能小于最低分');
return;
}
let _sdate = '';
let _edate = '';
if (daterange.value) {
_sdate = daterange.value[0];
_edate = daterange.value[1];
}
console.log('🚀 ~ getData ~ _edate:', _edate);
const industry = form.value.industry?.length > 0 ? encodeURIComponent(JSON.stringify(form.value.industry)) : '';
try {
loading.value = true;
let { code, data, total } = await getNews({
...form.value,
industry,
// page: tableData.page,
current: tableData.page,
size: tableData.size,
dateline_from: _sdate || undefined,
dateline_to: _edate || undefined,
range: Session.get('userInfoLocal').userType == '01' ? 'review' : Session.get('userInfoLocal').userType == '02' ? 'secondReview' : 'all',
});
loading.value = false;
if (code == 200) {
tableData.total = total;
if (tableData.page == 1) {
tableData.data = data;
} else {
tableData.data.push(...data);
}
tableData.data.forEach((item, index) => {
item.columns.forEach((childItem, childIndex) => {
if (childIndex < 2) {
if (!item.columnsMin) {
item.columnsMin = [];
}
item.columnsMin.push(childItem);
}
});
item.title = highlightTitle(item.title, form.value.keyword);
});
}
} catch (error) {
loading.value = false;
}
2025-08-03 13:41:47 +08:00
}
function handleSearch() {
tableData.page = 1;
getData();
2025-08-03 13:41:47 +08:00
}
/**
* 上下架
* @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 } =
status == 1
? await doNewRevoke({
id: item.id,
status: status,
})
: await doNewsPublish({
id: item.id,
status: status,
});
if (code == 200) {
ElMessage.success('操作成功');
drawer.value = false;
getData();
}
})
.catch(() => { });
2025-08-03 13:41:47 +08:00
}
/** 管理后台需求文件0519V1.1 start */
const drawer = ref(false);
const newsData = ref<any>();
const readOnly = ref(false);
const newstype = ref(0);
/** 管理后台需求文件0519V1.1 end */
/**
* 进入详情页
* @param type 0创建 1编辑
*/
function goDetail(type, item, readonly) {
readOnly.value = readonly;
newsData.value = item;
newstype.value = type;
drawer.value = true;
// router.push({
// path: '/detailMobile',
// query: {
// type,
// item,
// readonly,
// }
// })
2025-08-03 13:41:47 +08:00
}
const sortRef = ref(null);
2025-08-03 13:41:47 +08:00
function restData() {
form.value.keyword = null;
form.value.industry = null;
form.value.tag = null;
daterange.value = null;
form.value.minScore = null;
form.value.maxScore = null;
form.value.mediaId = null;
form.value.deleted = null;
form.value.status = null;
form.value.rating = null;
form.value.orderBy = null;
sortRef.value.clearSort();
tableData.page = 1;
getData();
2025-08-03 13:41:47 +08:00
}
function handleEditStatus(val: boolean) {
readOnly.value = val;
}
const mescrollRef = ref();
function goTop() {
window.scrollTo({
top: 0,
behavior: 'smooth',
});
mescrollRef.value.scrollTo({
top: 0,
behavior: 'smooth',
});
}
const isShowBackTop = ref(false);
function handleScroll() {
if (mescrollRef.value.scrollTop > 300) {
isShowBackTop.value = true;
} else {
isShowBackTop.value = false;
}
}
// 复审
async function doNewCheckFn(item) {
let { code, data } = await doNewCheck({
id: item.id,
});
if (code == 200) {
ElMessage.success('操作成功');
getData();
}
}
// 退改
async function doNewReturnFn(item) {
let { code, data } = await doNewReturn({
id: item.id,
});
if (code == 200) {
ElMessage.success('操作成功');
getData();
}
}
async function doApprovalFn(item, status) {
let str = '确认初审完成并提交复核?送审后不支持再次编辑';
if (status == 3 || status == 4) {
str = '确认撤销该篇资讯审核?';
} else {
str = '确认初审完成并提交复核?送审后不支持再次编辑';
}
ElMessageBox.confirm(str, '提示', {
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning',
})
.then(async () => {
let { code } =
status == 3 || status == 4
? await doNewRevoke({
id: item.id,
})
: await doNewSubmit({
id: item.id,
});
if (code == 200) {
ElMessage.success('操作成功');
drawer.value = false;
getData();
}
})
.catch(() => { });
}
2025-08-03 13:41:47 +08:00
onMounted(() => {
if (Session.get('userInfoLocal').userType == '02') {
tabsList.value = [
{
name: '审核中',
status: 3,
},
{
name: '已二审',
status: 4,
},
{
name: '已发布',
status: 2,
},
{
name: '退改中',
status: -1,
},
{
name: '全部',
status: null,
},
]
} else if (Session.get('userInfoLocal').userType == '01') {
tabsList.value = [
{
name: '已二审',
status: 4,
},
{
name: '已发布',
status: 2,
},
{
name: '退改中',
status: -1,
},
{
name: '全部',
status: null,
},
]
}
changeTab(0);
mescrollRef.value.addEventListener('scroll', handleScroll);
// getData();
});
2025-08-03 13:41:47 +08:00
onUnmounted(() => {
mescrollRef.value.removeEventListener('scroll', handleScroll);
});
2025-08-03 13:41:47 +08:00
</script>
<style scoped lang="scss">
.all {
display: flex;
flex-direction: column;
max-width: 100vw;
height: 100vh;
scrollbar-width: none;
/* Firefox */
-ms-overflow-style: none;
/* IE and Edge 旧版本 */
2025-08-03 13:41:47 +08:00
}
/* 隐藏容器的滚动条 */
.all::-webkit-scrollbar {
display: none;
/* Chrome, Safari, Edge, Opera */
2025-08-03 13:41:47 +08:00
}
.filter {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 15px;
padding: 0 5px;
2025-08-03 13:41:47 +08:00
}
.r_tabs {
display: flex;
gap: 30px;
margin-top: 10px;
.tabItem {
font-size: 16px;
color: #333;
// font-weight: bold;
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
}
.tab_line {
width: 20px;
height: 5px;
background-color: #409eff;
border-radius: 20px;
margin-top: 5px;
}
2025-08-03 13:41:47 +08:00
}
.r_list {
display: flex;
flex-direction: column;
margin-top: 20px;
gap: 15px;
2025-08-03 13:41:47 +08:00
}
.card_header {
display: flex;
justify-content: space-between;
.card_title {
font-size: 15px;
font-weight: bold;
width: 73%;
// overflow: hidden;
// text-overflow: ellipsis;
// white-space: nowrap;
height: 43px;
overflow: hidden;
display: -webkit-box;
text-overflow: ellipsis; //属性规定当文本溢出包含元素时发生的事情 text-overflow: clip|ellipsis|string; (修剪/省略号/指定字符串)
-webkit-line-clamp: 2;
/*要显示的行数*/
/* autoprefixer: off */
-webkit-box-orient: vertical; //属性规定框的子元素应该被水平或垂直排列
}
.r_point {
display: flex;
align-items: center;
gap: 5px;
font-weight: 400;
}
.point {
width: 8px;
height: 8px;
border-radius: 100px;
}
2025-08-03 13:41:47 +08:00
}
.card {
box-shadow: 0 0 5px rgba($color: #474747, $alpha: 0.1);
border-radius: 5px;
2025-08-03 13:41:47 +08:00
}
.option {
display: flex;
2025-08-03 13:41:47 +08:00
button {
padding: 0 0px 0 0px;
}
2025-08-03 13:41:47 +08:00
}
:deep(.highlight) {
color: #ff0000;
font-weight: bold;
}
.bottom_load_text {
font-size: 14px;
color: #ccc;
width: 90vw;
height: 30px;
display: flex;
text-align: center;
justify-content: center;
align-items: center;
}
.back_top {
position: fixed;
bottom: 30px;
right: 30px;
width: 40px;
height: 40px;
background-color: white;
border-radius: 100px;
display: flex;
justify-content: center;
align-items: center;
box-shadow: 0 0 10px rgba($color: #363636, $alpha: 0.2);
}
2025-08-03 13:41:47 +08:00
</style>