first
This commit is contained in:
334
src/views/novel/index.vue
Normal file
334
src/views/novel/index.vue
Normal file
@@ -0,0 +1,334 @@
|
||||
<template>
|
||||
<div class="table-box">
|
||||
<ProTable
|
||||
ref="proTable"
|
||||
highlight-current-row
|
||||
:columns="columns"
|
||||
:request-api="getTableList"
|
||||
:data-callback="dataCallback"
|
||||
>
|
||||
<!-- 表格 header 按钮 -->
|
||||
<template #tableHeader="scope">
|
||||
<el-button type="primary" :icon="CirclePlus" @click="openSetDrawerRef(true)">批量设置</el-button>
|
||||
<el-button type="primary" style="display: none" :icon="CirclePlus" @click="openDrawer(true)">新增</el-button>
|
||||
<el-button
|
||||
style="display: none"
|
||||
type="danger"
|
||||
:icon="Delete"
|
||||
plain
|
||||
:disabled="!scope.isSelected"
|
||||
@click="batchDelete(scope.selectedList)"
|
||||
>
|
||||
批量删除小说
|
||||
</el-button>
|
||||
</template>
|
||||
<!-- 表格操作 -->
|
||||
<template #operation="scope">
|
||||
<el-button type="success" link :icon="ChatLineSquare" @click="openChapterDrawer(scope.row)">章节</el-button>
|
||||
<el-button type="primary" style="display: none" link :icon="EditPen" @click="openDrawer(false, scope.row)">
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button type="danger" style="display: none" link :icon="Delete" @click="deleteAccount(scope.row)">
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</ProTable>
|
||||
<Drawer ref="drawerRef" />
|
||||
<SetDrawer ref="setDrawerRef" />
|
||||
<ChapterDrawer ref="chapterDrawerRef" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="tsx" name="complexProTable">
|
||||
import { defineComponent, onMounted, h } from "vue";
|
||||
import { reactive, ref } from "vue";
|
||||
import { NovelList } from "@/api/interface/novel/list";
|
||||
import { useHandleData } from "@/hooks/useHandleData";
|
||||
import ProTable from "@/components/ProTable/index.vue";
|
||||
import { Delete, EditPen, CirclePlus, ChatLineSquare } from "@element-plus/icons-vue";
|
||||
import { ProTableInstance, ColumnProps } from "@/components/ProTable/interface";
|
||||
import { getList, saveData, deleteItem,levelSet } from "@/api/modules/novel/list";
|
||||
import Drawer from "./drawer.vue";
|
||||
import SetDrawer from "./setDrawer.vue";
|
||||
import ChapterDrawer from "./components/chapter.vue";
|
||||
import { getAllList } from "@/api/modules/novel/fenlei";
|
||||
// import { LOSE_STR_KEY, LOGIN_URL } from "@/config";
|
||||
import router from "@/routers";
|
||||
import { getEndpointAllApi } from "@/api/modules/system/endpoint";
|
||||
|
||||
//端点列表
|
||||
const Endpoints = ref([] as any);
|
||||
// ProTable 实例
|
||||
const proTable = ref<ProTableInstance>();
|
||||
|
||||
//小说分类
|
||||
// const getFenLeiList = ref([] as any);
|
||||
// getAllList().then(res => {
|
||||
// if (res.code === LOSE_STR_KEY) {
|
||||
// router.replace(LOGIN_URL);
|
||||
// return;
|
||||
// }
|
||||
// getFenLeiList.value = res.data.items;
|
||||
// });
|
||||
|
||||
const initParam = reactive({
|
||||
limit: 15,
|
||||
page: 1
|
||||
});
|
||||
|
||||
const dataCallback = (data: any) => {
|
||||
console.log(data)
|
||||
// data.items.forEach((item: any) => {
|
||||
// const DataString = JSON.parse(item.xsxq_feng_mian);
|
||||
// const found = Endpoints.value.find(item2 => item2.zydd_code === DataString.code);
|
||||
// if (found && found.zydd_domain) {
|
||||
// item["https_cover_url"] = found.zydd_domain + DataString.uri;
|
||||
// } else {
|
||||
// item["https_cover_url"] = import.meta.env.VITE_API_URL + DataString.uri;
|
||||
// }
|
||||
// });
|
||||
return {
|
||||
items: data.data,
|
||||
total: data.total,
|
||||
total_page: data.pages,
|
||||
page: initParam.page,
|
||||
limit: initParam.limit
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
const getTableList = async (params: any) => {
|
||||
// 获取 getEndpointAllApi 的返回值
|
||||
// const Configs = await getEndpointAllApi();
|
||||
// Endpoints.value = Configs.data.items;
|
||||
let newParams = JSON.parse(JSON.stringify(params));
|
||||
initParam.page = newParams.page;
|
||||
initParam.limit = newParams.limit;
|
||||
return getList(newParams);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
created_at
|
||||
:
|
||||
{$date: {…}}
|
||||
|
||||
*/
|
||||
|
||||
// 表格配置项
|
||||
const columns = reactive<ColumnProps<NovelList.ResList>[]>([
|
||||
{ type: "selection", fixed: "left", width: 50 },
|
||||
{
|
||||
prop: "key",
|
||||
label: "搜索内容",
|
||||
isShow: false,
|
||||
search: {
|
||||
el: "input"
|
||||
}
|
||||
},
|
||||
// {
|
||||
// prop: "n_id",
|
||||
// label: "id",
|
||||
// width: 100
|
||||
// },
|
||||
// {
|
||||
// prop: "n_source_id",
|
||||
// label: "源id",
|
||||
// width: 100
|
||||
// },
|
||||
{
|
||||
prop: "og_novel_book_name",
|
||||
label: "名称",
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
prop: "n_level",
|
||||
label: "推荐等级",
|
||||
width: 120
|
||||
},
|
||||
|
||||
{
|
||||
prop: "og_novel_pin_yin",
|
||||
label: "拼音",
|
||||
width: 120
|
||||
},
|
||||
|
||||
{
|
||||
prop: "n_cover_path",
|
||||
label: "封面",
|
||||
width: 120,
|
||||
|
||||
render(scope) {
|
||||
return <img src={'http://tp2.novel2.com'+scope.row.n_cover_path } alt="封面" style="width: 100%; height: auto;" />;
|
||||
}
|
||||
|
||||
},
|
||||
{
|
||||
prop: "og_novel_status",
|
||||
label: "状态"
|
||||
},
|
||||
{
|
||||
prop: "og_novel_author",
|
||||
label: "作者"
|
||||
},
|
||||
|
||||
{
|
||||
prop: "og_novel_category",
|
||||
label: "分类",
|
||||
width: 120,
|
||||
//fieldNames: { label: "xsfl_name", value: "xsfl_id" },
|
||||
//enum: getFenLeiList
|
||||
},
|
||||
|
||||
{
|
||||
prop: "n_page_description",
|
||||
label: "描述"
|
||||
},
|
||||
// {
|
||||
// prop: "n_site_name",
|
||||
// label: "源站"
|
||||
// },
|
||||
{
|
||||
prop: "og_novel_latest_chapter_name",
|
||||
label: "最新章节"
|
||||
},
|
||||
|
||||
// { prop: "xsxq_source_code", label: "源码", width: 200 },
|
||||
// { prop: "xsxq_zi_shu", label: "字数", width: 150 },
|
||||
// { prop: "xsxq_jie_shao", label: "描述", width: 200 },
|
||||
// { prop: "xsxq_geng_xin_shi_jian", label: "最后更新时间", width: 170 },
|
||||
// { prop: "created_at", label: "添加时间", width: 170 },
|
||||
{ prop: "og_novel_update_time", label: "更新时间", width: 170 },
|
||||
// { prop: "operation", label: "操作", fixed: "right", width: 100 }
|
||||
]);
|
||||
|
||||
// 删除小说信息
|
||||
const deleteAccount = async (params: NovelList.ResList) => {
|
||||
await useHandleData(deleteItem, { xsxq_id: params.xsxq_id }, "删除所选信息");
|
||||
proTable.value?.getTableList();
|
||||
};
|
||||
|
||||
// 批量删除小说信息
|
||||
const batchDelete = async (id: any[]) => {
|
||||
const ids = id.map((item: NovelList.ResList) => item.xsxq_id);
|
||||
await useHandleData(deleteItem, { xsxq_id: ids.join(",") }, "删除所选信息");
|
||||
proTable.value?.clearSelection();
|
||||
proTable.value?.getTableList();
|
||||
};
|
||||
// 打开 drawer(新增、编辑)
|
||||
const drawerRef = ref<InstanceType<typeof Drawer> | null>(null);
|
||||
const openDrawer = (isEdit: boolean, row: Partial<NovelList.ResList> = {}) => {
|
||||
const params = {
|
||||
title: isEdit ? "新增小说" : "编辑小说",
|
||||
row: { ...row },
|
||||
api: saveData,
|
||||
getTableList: proTable.value?.getTableList
|
||||
};
|
||||
drawerRef.value?.acceptParams(params as any);
|
||||
};
|
||||
|
||||
// 批量设置推荐等级
|
||||
const setDrawerRef = ref<InstanceType<typeof SetDrawer> | null>(null);
|
||||
const openSetDrawerRef = (isEdit: boolean, row: Partial<NovelList.ResList> = {}) => {
|
||||
const params = {
|
||||
title: "批量设置",
|
||||
row: { ...row },
|
||||
api: levelSet,
|
||||
getTableList: proTable.value?.getTableList
|
||||
};
|
||||
setDrawerRef.value?.acceptParams(params as any);
|
||||
};
|
||||
|
||||
// 章节
|
||||
const chapterDrawerRef = ref<InstanceType<typeof ChapterDrawer> | null>(null);
|
||||
const openChapterDrawer = (row: Partial<NovelList.ResList> = {}) => {
|
||||
chapterDrawerRef.value?.acceptParams(row.xsxq_id!);
|
||||
};
|
||||
|
||||
// 异步加载图片组件
|
||||
const AsyncImageComponent = defineComponent({
|
||||
props: {
|
||||
url: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
setup(props) {
|
||||
const imageUrl = ref("");
|
||||
const isLoading = ref(true);
|
||||
const error = ref(null);
|
||||
|
||||
onMounted(async () => {
|
||||
try {
|
||||
const data = await fetchImageData(props.url);
|
||||
const decodedImage = decode(data);
|
||||
imageUrl.value = decodedImage;
|
||||
isLoading.value = false;
|
||||
} catch (err) {
|
||||
console.error("Error converting image to base64:", err);
|
||||
error.value = err;
|
||||
isLoading.value = false;
|
||||
}
|
||||
});
|
||||
|
||||
return () => {
|
||||
if (isLoading.value) {
|
||||
return h("el-image", { src: "Loading..." });
|
||||
}
|
||||
|
||||
if (error.value) {
|
||||
return h("el-image", { src: "无法加载" });
|
||||
}
|
||||
return (
|
||||
<el-image
|
||||
style="width: 98%; height: 30px;display: flex;align-items: center;"
|
||||
src={imageUrl.value}
|
||||
preview-src-list={[imageUrl.value]}
|
||||
hide-on-click-modal={true}
|
||||
z-index={999999999}
|
||||
preview-teleported={true}
|
||||
// fit="contain"
|
||||
fit="cover"
|
||||
/>
|
||||
);
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
// 获取图片数据
|
||||
async function fetchImageData(url) {
|
||||
const response = await fetch(url);
|
||||
const data = await response.arrayBuffer();
|
||||
return data;
|
||||
}
|
||||
|
||||
// 解码图片函数
|
||||
function decode(data, key = 0x88) {
|
||||
let binary = "";
|
||||
let bytes = new Uint8Array(data);
|
||||
let len = bytes.byteLength;
|
||||
for (let i = 0; i < len; i++) {
|
||||
binary += String.fromCharCode(bytes[i] ^ key);
|
||||
}
|
||||
let src = window.btoa(binary);
|
||||
let image = "data:image/jpeg;base64," + src;
|
||||
return image;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.el-table .warning-row,
|
||||
.el-table .warning-row .el-table-fixed-column--right,
|
||||
.el-table .warning-row .el-table-fixed-column--left {
|
||||
background-color: var(--el-color-warning-light-9);
|
||||
}
|
||||
.el-table .success-row,
|
||||
.el-table .success-row .el-table-fixed-column--right,
|
||||
.el-table .success-row .el-table-fixed-column--left {
|
||||
background-color: var(--el-color-success-light-9);
|
||||
}
|
||||
.tag {
|
||||
margin-right: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user