4 changed files with 210 additions and 130 deletions
@ -0,0 +1,150 @@
|
||||
<template> |
||||
<div class="p-2"> |
||||
<div class="p-4 mb-2 bg-white"> |
||||
<BasicForm @register="registerForm" /> |
||||
</div> |
||||
<div class="p-2 bg-white"> |
||||
<List :grid="{ gutter: 5, xs: 1, sm: 2, md: 4, lg: 4, xl: 6, xxl: grid }" :data-source="data" :pagination="paginationProp"> |
||||
<template #header> |
||||
<div class="flex justify-end space-x-2"> |
||||
<slot name="header"></slot> |
||||
<Tooltip> |
||||
<template #title> |
||||
<div class="w-50">每行显示数量</div> |
||||
<Slider id="slider" v-bind="sliderProp" v-model:value="grid" @change="sliderChange" /> |
||||
</template> |
||||
<a-button><TableOutlined /></a-button> |
||||
</Tooltip> |
||||
<Tooltip @click="fetch"> |
||||
<template #title>刷新</template> |
||||
<a-button><RedoOutlined /></a-button> |
||||
</Tooltip> |
||||
</div> |
||||
</template> |
||||
<template #renderItem="{ item }"> |
||||
<ListItem> |
||||
<Card> |
||||
<template #title>{{ item.content.newsItem[0].title }}</template> |
||||
<template #cover> |
||||
<div :class="height"> |
||||
<Image :src="item.content.newsItem[0].thumbUrl" /> |
||||
</div> |
||||
</template> |
||||
<template #actions> |
||||
<Icon icon="ant-design:delete-outlined" @click="handleDelete.bind(null, item.id)" /> |
||||
</template> |
||||
|
||||
<CardMeta> |
||||
<template #title> |
||||
<TypographyText :content="item.name" :ellipsis="{ tooltip: item.address }" /> |
||||
</template> |
||||
<template #avatar> |
||||
<Avatar :src="item.avatar" /> |
||||
</template> |
||||
<template #description>{{ item.time }}</template> |
||||
</CardMeta> |
||||
</Card> |
||||
</ListItem> |
||||
</template> |
||||
</List> |
||||
</div> |
||||
</div> |
||||
</template> |
||||
<script lang="ts" setup> |
||||
import { computed, onMounted, ref } from 'vue' |
||||
import { RedoOutlined, TableOutlined } from '@ant-design/icons-vue' |
||||
import { List, Card, Image, Typography, Tooltip, Slider, Avatar } from 'ant-design-vue' |
||||
import { Icon } from '@/components/Icon' |
||||
import { BasicForm, useForm, FormSchema } from '@/components/Form' |
||||
import { propTypes } from '@/utils/propTypes' |
||||
import { isFunction } from '@/utils/is' |
||||
import { useSlider, grid } from './data' |
||||
|
||||
const ListItem = List.Item |
||||
const CardMeta = Card.Meta |
||||
const TypographyText = Typography.Text |
||||
// 获取slider属性 |
||||
const sliderProp = computed(() => useSlider(4)) |
||||
// 组件接收参数 |
||||
const props = defineProps({ |
||||
// 请求API的参数 |
||||
params: propTypes.object.def({}), |
||||
//api |
||||
api: propTypes.func, |
||||
searchSchema: { |
||||
type: Array |
||||
} |
||||
}) |
||||
//暴露内部方法 |
||||
const emit = defineEmits(['getMethod', 'delete']) |
||||
//数据 |
||||
const data = ref([]) |
||||
// 切换每行个数 |
||||
// cover图片自适应高度 |
||||
//修改pageSize并重新请求数据 |
||||
|
||||
const height = computed(() => { |
||||
return `h-${120 - grid.value * 6}` |
||||
}) |
||||
//表单 |
||||
const [registerForm, { validate }] = useForm({ |
||||
schemas: props.searchSchema as FormSchema[], |
||||
labelWidth: 80, |
||||
baseColProps: { span: 6 }, |
||||
actionColOptions: { span: 24 }, |
||||
autoSubmitOnEnter: true, |
||||
submitFunc: handleSubmit |
||||
}) |
||||
//表单提交 |
||||
async function handleSubmit() { |
||||
const data = await validate() |
||||
await fetch(data) |
||||
} |
||||
function sliderChange(n: number) { |
||||
pageSize.value = n * 4 |
||||
fetch() |
||||
} |
||||
|
||||
// 自动请求并暴露内部方法 |
||||
onMounted(() => { |
||||
fetch() |
||||
emit('getMethod', fetch) |
||||
}) |
||||
|
||||
async function fetch(p = {}) { |
||||
const { api, params } = props |
||||
if (api && isFunction(api)) { |
||||
const res = await api({ ...params, page: page.value, pageSize: pageSize.value, ...p }) |
||||
data.value = res.list |
||||
total.value = res.total |
||||
} |
||||
} |
||||
//分页相关 |
||||
const page = ref(1) |
||||
const pageSize = ref(36) |
||||
const total = ref(0) |
||||
const paginationProp = ref({ |
||||
showSizeChanger: false, |
||||
showQuickJumper: true, |
||||
pageSize, |
||||
current: page, |
||||
total, |
||||
showTotal: (total: number) => `总 ${total} 条`, |
||||
onChange: pageChange, |
||||
onShowSizeChange: pageSizeChange |
||||
}) |
||||
|
||||
function pageChange(p: number, pz: number) { |
||||
page.value = p |
||||
pageSize.value = pz |
||||
fetch() |
||||
} |
||||
function pageSizeChange(_current, size: number) { |
||||
pageSize.value = size |
||||
fetch() |
||||
} |
||||
|
||||
async function handleDelete(id) { |
||||
emit('delete', id) |
||||
} |
||||
</script> |
@ -0,0 +1,25 @@
|
||||
import { ref } from 'vue' |
||||
// 每行个数
|
||||
export const grid = ref(12) |
||||
// slider属性
|
||||
export const useSlider = (min = 6, max = 12) => { |
||||
// 每行显示个数滑动条
|
||||
const getMarks = () => { |
||||
const l = {} |
||||
for (let i = min; i < max + 1; i++) { |
||||
l[i] = { |
||||
style: { |
||||
color: '#fff' |
||||
}, |
||||
label: i |
||||
} |
||||
} |
||||
return l |
||||
} |
||||
return { |
||||
min, |
||||
max, |
||||
marks: getMarks(), |
||||
step: 1 |
||||
} |
||||
} |
@ -1,138 +1,39 @@
|
||||
<template> |
||||
<PageWrapper :class="prefixCls" title="公众号图文"> |
||||
<template #headerContent> |
||||
请选择公众号 |
||||
<div :class="`${prefixCls}__link`"> |
||||
<Select :value="queryParams.accountId as any" style="width: 200px" @change="getList"> |
||||
<SelectOption v-for="item in accounts" :label="item.name" :value="parseInt(item.id)" :key="parseInt(item.id)" /> |
||||
</Select> |
||||
<!-- <a><Icon icon="bx:bx-paper-plane" color="#1890ff" /><span>开始</span></a> |
||||
<a><Icon icon="carbon:warning" color="#1890ff" /><span>简介</span></a> |
||||
<a><Icon icon="ion:document-text-outline" color="#1890ff" /><span>文档</span></a> --> |
||||
</div> |
||||
</template> |
||||
|
||||
<div :class="`${prefixCls}__content`"> |
||||
<List :grid="{ gutter: 16, xs: 1, sm: 2, md: 4, lg: 4, xl: 6, xxl: 3, xxxl: 2 }" :data-source="cardList"> |
||||
<template v-for="item in cardList" :key="item.title"> |
||||
<ListItem> |
||||
<Card :hoverable="true" :class="`${prefixCls}__card`"> |
||||
<List> |
||||
<template v-for="(article, index) in item.content.newsItem" :key="index"> |
||||
<ListItem> |
||||
<Image :src="article.picUrl" :key="index" /> |
||||
<div :class="`${prefixCls}__card-title`"> |
||||
{{ article.title }} |
||||
</div> |
||||
<div :class="`${prefixCls}__card-detail`"></div> |
||||
</ListItem> |
||||
</template> |
||||
</List> |
||||
<!-- <div :class="`${prefixCls}__card-title`"> |
||||
<Icon class="icon" v-if="item.icon" :icon="item.icon" :color="item.color" /> |
||||
{{ item.title }} |
||||
</div> |
||||
<div :class="`${prefixCls}__card-detail`"> 基于Vue Next, TypeScript, Ant Design Vue实现的一套完整的企业级后台管理系统 </div> --> |
||||
</Card> |
||||
</ListItem> |
||||
</template> |
||||
</List> |
||||
<Pagination showLessItems size="small" :pageSize="queryParams.queryParamsSize" :total="queryParams.total" @change="getList" /> |
||||
</div> |
||||
<PageWrapper title="公众号图文"> |
||||
<NewsList :search-schema="searchSchema" :api="getFreePublishPage" @get-method="getMethod" @delete="handleDelete" /> |
||||
</PageWrapper> |
||||
</template> |
||||
<script lang="ts" setup> |
||||
// import { Icon } from '@/components/Icon' |
||||
import { PageWrapper } from '@/components/Page' |
||||
import { Card, List, Image, Select, Pagination } from 'ant-design-vue' |
||||
import { useDesign } from '@/hooks/web/useDesign' |
||||
import { ref, reactive, onMounted } from 'vue' |
||||
import NewsList from './NewsList.vue' |
||||
import { getSimpleAccounts } from '@/api/mp/account' |
||||
import { useMessage } from '@/hooks/web/useMessage' |
||||
import { getFreePublishPage } from '@/api/mp/freePublish' |
||||
|
||||
const ListItem = List.Item |
||||
const SelectOption = Select.Option |
||||
|
||||
const { prefixCls } = useDesign('list-card') |
||||
const { createMessage } = useMessage() |
||||
|
||||
const cardList = ref<any[]>([]) |
||||
|
||||
const accounts = ref() |
||||
|
||||
const queryParams = reactive({ |
||||
accountId: null, |
||||
total: 0, |
||||
currentPage: 1, |
||||
queryParamsSize: 20 |
||||
}) |
||||
|
||||
async function init() { |
||||
const res = await getSimpleAccounts() |
||||
accounts.value = res |
||||
if (accounts.value.length > 0) { |
||||
queryParams.accountId = accounts.value[0].id |
||||
import { deleteFreePublish, getFreePublishPage } from '@/api/mp/freePublish' |
||||
import { FormSchema } from '@/components/Form' |
||||
|
||||
const searchSchema: FormSchema[] = [ |
||||
{ |
||||
label: '公众号', |
||||
field: 'accountId', |
||||
component: 'ApiSelect', |
||||
componentProps: { |
||||
api: () => getSimpleAccounts(), |
||||
labelField: 'name', |
||||
valueField: 'id' |
||||
}, |
||||
colProps: { span: 8 } |
||||
} |
||||
await getList() |
||||
} |
||||
] |
||||
|
||||
async function getList() { |
||||
if (!queryParams.accountId) { |
||||
createMessage.error('未选中公众号,无法查询已发表图文!') |
||||
return false |
||||
} |
||||
const res = await getFreePublishPage(queryParams) |
||||
cardList.value = res.list |
||||
queryParams.total = res.total |
||||
let reload = () => {} |
||||
// 获取内部fetch方法; |
||||
function getMethod(m: any) { |
||||
reload = m |
||||
} |
||||
|
||||
onMounted(async () => { |
||||
await init() |
||||
}) |
||||
</script> |
||||
<style lang="less" scoped> |
||||
.list-card { |
||||
&__link { |
||||
margin-top: 10px; |
||||
font-size: 14px; |
||||
|
||||
a { |
||||
margin-right: 30px; |
||||
} |
||||
|
||||
span { |
||||
margin-left: 5px; |
||||
} |
||||
} |
||||
|
||||
&__card { |
||||
width: 100%; |
||||
margin-bottom: -8px; |
||||
|
||||
.ant-card-body { |
||||
padding: 16px; |
||||
} |
||||
|
||||
&-title { |
||||
margin-bottom: 5px; |
||||
font-size: 16px; |
||||
font-weight: 500; |
||||
color: @text-color; |
||||
|
||||
.icon { |
||||
margin-top: -5px; |
||||
margin-right: 10px; |
||||
font-size: 38px !important; |
||||
} |
||||
} |
||||
|
||||
&-detail { |
||||
padding-top: 10px; |
||||
padding-left: 30px; |
||||
font-size: 14px; |
||||
color: @text-color-secondary; |
||||
} |
||||
} |
||||
//删除按钮事件 |
||||
function handleDelete(id) { |
||||
deleteFreePublish(id, id) |
||||
reload() |
||||
} |
||||
</style> |
||||
</script> |
||||
|
Reference in new issue