committed by
GitHub
67 changed files with 5217 additions and 4647 deletions
@ -0,0 +1,4 @@ |
|||||
|
import { withInstall } from '/@/utils'; |
||||
|
import cardList from './src/CardList.vue'; |
||||
|
|
||||
|
export const CardList = withInstall(cardList); |
||||
@ -0,0 +1,178 @@ |
|||||
|
<template> |
||||
|
<div class="p-2"> |
||||
|
<div class="bg-white mb-2 p-4"> |
||||
|
<BasicForm @register="registerForm" /> |
||||
|
</div> |
||||
|
{{ sliderProp.width }} |
||||
|
<div class="bg-white p-2"> |
||||
|
<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> |
||||
|
<Button><TableOutlined /></Button> |
||||
|
</Tooltip> |
||||
|
<Tooltip @click="fetch"> |
||||
|
<template #title>刷新</template> |
||||
|
<Button><RedoOutlined /></Button> |
||||
|
</Tooltip> |
||||
|
</div> |
||||
|
</template> |
||||
|
<template #renderItem="{ item }"> |
||||
|
<ListItem> |
||||
|
<Card> |
||||
|
<template #title></template> |
||||
|
<template #cover> |
||||
|
<div :class="height"> |
||||
|
<Image :src="item.imgs[0]" /> |
||||
|
</div> |
||||
|
</template> |
||||
|
<template class="ant-card-actions" #actions> |
||||
|
<!-- <SettingOutlined key="setting" />--> |
||||
|
<EditOutlined key="edit" /> |
||||
|
<Dropdown |
||||
|
:trigger="['hover']" |
||||
|
:dropMenuList="[ |
||||
|
{ |
||||
|
text: '删除', |
||||
|
event: '1', |
||||
|
popConfirm: { |
||||
|
title: '是否确认删除', |
||||
|
confirm: handleDelete.bind(null, item.id), |
||||
|
}, |
||||
|
}, |
||||
|
]" |
||||
|
popconfirm |
||||
|
> |
||||
|
<EllipsisOutlined key="ellipsis" /> |
||||
|
</Dropdown> |
||||
|
</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 { |
||||
|
EditOutlined, |
||||
|
EllipsisOutlined, |
||||
|
RedoOutlined, |
||||
|
TableOutlined, |
||||
|
} from '@ant-design/icons-vue'; |
||||
|
import { List, Card, Image, Typography, Tooltip, Slider, Avatar } from 'ant-design-vue'; |
||||
|
import { Dropdown } from '/@/components/Dropdown'; |
||||
|
import { BasicForm, useForm } from '/@/components/Form'; |
||||
|
import { propTypes } from '/@/utils/propTypes'; |
||||
|
import { Button } from '/@/components/Button'; |
||||
|
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, |
||||
|
}); |
||||
|
//暴露内部方法 |
||||
|
const emit = defineEmits(['getMethod', 'delete']); |
||||
|
//数据 |
||||
|
const data = ref([]); |
||||
|
// 切换每行个数 |
||||
|
// cover图片自适应高度 |
||||
|
//修改pageSize并重新请求数据 |
||||
|
|
||||
|
const height = computed(() => { |
||||
|
return `h-${120 - grid.value * 6}`; |
||||
|
}); |
||||
|
//表单 |
||||
|
const [registerForm, { validate }] = useForm({ |
||||
|
schemas: [{ field: 'type', component: 'Input', label: '类型' }], |
||||
|
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) { |
||||
|
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.items; |
||||
|
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) => `总 ${total} 条`, |
||||
|
onChange: pageChange, |
||||
|
onShowSizeChange: pageSizeChange, |
||||
|
}); |
||||
|
|
||||
|
function pageChange(p, pz) { |
||||
|
page.value = p; |
||||
|
pageSize.value = pz; |
||||
|
fetch(); |
||||
|
} |
||||
|
function pageSizeChange(current, size) { |
||||
|
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, |
||||
|
}; |
||||
|
}; |
||||
@ -0,0 +1,5 @@ |
|||||
|
export enum MODE { |
||||
|
JSON = 'application/json', |
||||
|
HTML = 'htmlmixed', |
||||
|
JS = 'javascript', |
||||
|
} |
||||
@ -1,5 +1,7 @@ |
|||||
import { withInstall } from '/@/utils'; |
import { withInstall } from '/@/utils'; |
||||
import markDown from './src/Markdown.vue'; |
import markDown from './src/Markdown.vue'; |
||||
|
import markDownViewer from './src/MarkdownViewer.vue'; |
||||
|
|
||||
export const MarkDown = withInstall(markDown); |
export const MarkDown = withInstall(markDown); |
||||
|
export const MarkdownViewer = withInstall(markDownViewer); |
||||
export * from './src/typing'; |
export * from './src/typing'; |
||||
|
|||||
@ -0,0 +1,22 @@ |
|||||
|
<template> |
||||
|
<div v-html="getHtmlData" :class="$props.class" class="markdown-viewer"></div> |
||||
|
</template> |
||||
|
|
||||
|
<script lang="ts" setup> |
||||
|
import { computed } from 'vue'; |
||||
|
import showdown from 'showdown'; |
||||
|
|
||||
|
const converter = new showdown.Converter(); |
||||
|
converter.setOption('tables', true); |
||||
|
const props = defineProps({ |
||||
|
value: { type: String }, |
||||
|
class: { type: String }, |
||||
|
}); |
||||
|
const getHtmlData = computed(() => converter.makeHtml(props.value || '')); |
||||
|
</script> |
||||
|
|
||||
|
<style scoped> |
||||
|
.markdown-viewer { |
||||
|
width: 100%; |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,32 @@ |
|||||
|
<template> |
||||
|
<PageWrapper title="卡片列表示例" content="基础封装"> |
||||
|
<CardList :params="params" :api="demoListApi" @getMethod="getMethod" @delete="handleDel"> |
||||
|
<template #header> |
||||
|
<Button type="primary" color="error"> 按钮1 </Button> |
||||
|
<Button type="primary" color="success"> 按钮2 </Button> |
||||
|
</template> |
||||
|
</CardList> |
||||
|
</PageWrapper> |
||||
|
</template> |
||||
|
<script lang="ts" setup> |
||||
|
import { CardList } from '/@/components/CardList'; |
||||
|
import { Button } from '/@/components/Button'; |
||||
|
import { PageWrapper } from '/@/components/Page'; |
||||
|
import { demoListApi } from '/@/api/demo/table'; |
||||
|
import { useMessage } from '/@/hooks/web/useMessage'; |
||||
|
const { notification } = useMessage(); |
||||
|
// 请求api时附带参数 |
||||
|
const params = {}; |
||||
|
|
||||
|
let reload = () => {}; |
||||
|
// 获取内部fetch方法; |
||||
|
function getMethod(m: any) { |
||||
|
reload = m; |
||||
|
} |
||||
|
//删除按钮事件 |
||||
|
function handleDel(id) { |
||||
|
console.log(id); |
||||
|
notification.success({ message: `成功删除${id}` }); |
||||
|
reload(); |
||||
|
} |
||||
|
</script> |
||||
File diff suppressed because it is too large
Loading…
Reference in new issue