mirror of
https://github.com/zclzone/vue-naive-admin.git
synced 2025-06-07 23:59:01 +08:00
feat: add tabs bar to CrudTable
This commit is contained in:
parent
72857b3862
commit
c64ed917ba
138
.history/mock/api/post_20230912152251.js
Normal file
138
.history/mock/api/post_20230912152251.js
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
const posts = [
|
||||||
|
{
|
||||||
|
title: '使用纯css优雅配置移动端rem布局',
|
||||||
|
author: '大脸怪',
|
||||||
|
category: 'Css',
|
||||||
|
description: '通常配置rem布局会使用js进行处理,比如750的设计稿会这样...',
|
||||||
|
content: '通常配置rem布局会使用js进行处理,比如750的设计稿会这样',
|
||||||
|
isRecommend: true,
|
||||||
|
isPublish: true,
|
||||||
|
createDate: '2021-11-04T04:03:36.000Z',
|
||||||
|
updateDate: '2021-11-04T04:03:36.000Z',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Vue2&Vue3项目风格指南',
|
||||||
|
author: 'Ronnie',
|
||||||
|
category: 'Vue',
|
||||||
|
description: '总结的Vue2和Vue3的项目风格',
|
||||||
|
content: '### 1. 命名风格\n\n> 文件夹如果是由多个单词组成,应该始终是横线连接 ',
|
||||||
|
isRecommend: true,
|
||||||
|
isPublish: true,
|
||||||
|
createDate: '2021-10-25T08:57:47.000Z',
|
||||||
|
updateDate: '2022-02-28T04:02:39.000Z',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '如何优雅的给图片添加水印',
|
||||||
|
author: '大脸怪',
|
||||||
|
category: 'JavaScript',
|
||||||
|
description: '优雅的给图片添加水印',
|
||||||
|
content: '我之前写过一篇文章记录了一次上传图片的优化史',
|
||||||
|
isRecommend: true,
|
||||||
|
isPublish: true,
|
||||||
|
createDate: '2021-06-24T18:46:19.000Z',
|
||||||
|
updateDate: '2021-09-23T07:51:22.000Z',
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
title: '前端缓存的理解',
|
||||||
|
author: '大脸怪',
|
||||||
|
category: 'Http',
|
||||||
|
description: '谈谈前端缓存的理解',
|
||||||
|
content:
|
||||||
|
'> 背景\n\n公司有个vue-cli3移动端web项目发版更新后发现部分用户手机在钉钉内置浏览器打开出现了缓存',
|
||||||
|
isRecommend: true,
|
||||||
|
isPublish: true,
|
||||||
|
createDate: '2021-06-10T18:51:19.000Z',
|
||||||
|
updateDate: '2021-09-17T09:33:24.000Z',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Promise的五个静态方法',
|
||||||
|
author: '大脸怪',
|
||||||
|
category: 'JavaScript',
|
||||||
|
description: '简单介绍下在 Promise 类中,有5 种静态方法及它们的使用场景',
|
||||||
|
content:
|
||||||
|
'## 1. Promise.all\n\n并行执行多个 promise,并等待所有 promise 都准备就绪。再对它们进行处理。',
|
||||||
|
isRecommend: true,
|
||||||
|
isPublish: true,
|
||||||
|
createDate: '2021-02-22T22:37:06.000Z',
|
||||||
|
updateDate: '2021-09-17T09:33:24.000Z',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
export default [
|
||||||
|
{
|
||||||
|
url: '/api/posts',
|
||||||
|
method: 'get',
|
||||||
|
response: (data = {}) => {
|
||||||
|
const { title, pageNo, pageSize } = data.query
|
||||||
|
let pageData = []
|
||||||
|
let total = 60
|
||||||
|
const filterData = posts.filter(
|
||||||
|
(item) => item.title.includes(title) || (!title && title !== 0)
|
||||||
|
)
|
||||||
|
if (filterData.length) {
|
||||||
|
if (pageSize) {
|
||||||
|
while (pageData.length < pageSize) {
|
||||||
|
pageData.push(filterData[Math.round(Math.random() * (filterData.length - 1))])
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pageData = filterData
|
||||||
|
}
|
||||||
|
pageData = pageData.map((item, index) => ({
|
||||||
|
id: pageSize * (pageNo - 1) + index + 1,
|
||||||
|
...item,
|
||||||
|
}))
|
||||||
|
} else {
|
||||||
|
total = 0
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
code: 0,
|
||||||
|
message: 'ok',
|
||||||
|
data: {
|
||||||
|
pageData,
|
||||||
|
total,
|
||||||
|
pageNo,
|
||||||
|
pageSize,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: '/api/post',
|
||||||
|
method: 'post',
|
||||||
|
response: ({ body }) => {
|
||||||
|
return {
|
||||||
|
code: 0,
|
||||||
|
message: 'ok',
|
||||||
|
data: body,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: '/api/post/:id',
|
||||||
|
method: 'put',
|
||||||
|
response: ({ query, body }) => {
|
||||||
|
return {
|
||||||
|
code: 0,
|
||||||
|
message: 'ok',
|
||||||
|
data: {
|
||||||
|
id: query.id,
|
||||||
|
body,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: '/api/post/:id',
|
||||||
|
method: 'delete',
|
||||||
|
response: ({ query }) => {
|
||||||
|
return {
|
||||||
|
code: 0,
|
||||||
|
message: 'ok',
|
||||||
|
data: {
|
||||||
|
id: query.id,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
144
.history/mock/api/post_20230912152547.js
Normal file
144
.history/mock/api/post_20230912152547.js
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
const posts = [
|
||||||
|
{
|
||||||
|
title: '使用纯css优雅配置移动端rem布局',
|
||||||
|
author: '大脸怪',
|
||||||
|
category: 'Css',
|
||||||
|
description: '通常配置rem布局会使用js进行处理,比如750的设计稿会这样...',
|
||||||
|
content: '通常配置rem布局会使用js进行处理,比如750的设计稿会这样',
|
||||||
|
isRecommend: true,
|
||||||
|
isPublish: true,
|
||||||
|
total_expanse: 100,
|
||||||
|
state: 'approve',
|
||||||
|
createDate: '2021-11-04T04:03:36.000Z',
|
||||||
|
updateDate: '2021-11-04T04:03:36.000Z',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Vue2&Vue3项目风格指南',
|
||||||
|
author: 'Ronnie',
|
||||||
|
category: 'Vue',
|
||||||
|
description: '总结的Vue2和Vue3的项目风格',
|
||||||
|
content: '### 1. 命名风格\n\n> 文件夹如果是由多个单词组成,应该始终是横线连接 ',
|
||||||
|
isRecommend: true,
|
||||||
|
total_expanse: 100,
|
||||||
|
isPublish: true,
|
||||||
|
createDate: '2021-10-25T08:57:47.000Z',
|
||||||
|
updateDate: '2022-02-28T04:02:39.000Z',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '如何优雅的给图片添加水印',
|
||||||
|
author: '大脸怪',
|
||||||
|
category: 'JavaScript',
|
||||||
|
description: '优雅的给图片添加水印',
|
||||||
|
content: '我之前写过一篇文章记录了一次上传图片的优化史',
|
||||||
|
isRecommend: true,
|
||||||
|
total_expanse: 100,
|
||||||
|
isPublish: true,
|
||||||
|
createDate: '2021-06-24T18:46:19.000Z',
|
||||||
|
updateDate: '2021-09-23T07:51:22.000Z',
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
title: '前端缓存的理解',
|
||||||
|
author: '大脸怪',
|
||||||
|
category: 'Http',
|
||||||
|
description: '谈谈前端缓存的理解',
|
||||||
|
content:
|
||||||
|
'> 背景\n\n公司有个vue-cli3移动端web项目发版更新后发现部分用户手机在钉钉内置浏览器打开出现了缓存',
|
||||||
|
isRecommend: true,
|
||||||
|
isPublish: true,
|
||||||
|
total_expanse: 100,
|
||||||
|
createDate: '2021-06-10T18:51:19.000Z',
|
||||||
|
updateDate: '2021-09-17T09:33:24.000Z',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Promise的五个静态方法',
|
||||||
|
author: '大脸怪',
|
||||||
|
category: 'JavaScript',
|
||||||
|
description: '简单介绍下在 Promise 类中,有5 种静态方法及它们的使用场景',
|
||||||
|
content:
|
||||||
|
'## 1. Promise.all\n\n并行执行多个 promise,并等待所有 promise 都准备就绪。再对它们进行处理。',
|
||||||
|
isRecommend: true,
|
||||||
|
isPublish: true,
|
||||||
|
total_expanse: 100,
|
||||||
|
createDate: '2021-02-22T22:37:06.000Z',
|
||||||
|
updateDate: '2021-09-17T09:33:24.000Z',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
export default [
|
||||||
|
{
|
||||||
|
url: '/api/posts',
|
||||||
|
method: 'get',
|
||||||
|
response: (data = {}) => {
|
||||||
|
const { title, pageNo, pageSize } = data.query
|
||||||
|
let pageData = []
|
||||||
|
let total = 60
|
||||||
|
const filterData = posts.filter(
|
||||||
|
(item) => item.title.includes(title) || (!title && title !== 0)
|
||||||
|
)
|
||||||
|
if (filterData.length) {
|
||||||
|
if (pageSize) {
|
||||||
|
while (pageData.length < pageSize) {
|
||||||
|
pageData.push(filterData[Math.round(Math.random() * (filterData.length - 1))])
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pageData = filterData
|
||||||
|
}
|
||||||
|
pageData = pageData.map((item, index) => ({
|
||||||
|
id: pageSize * (pageNo - 1) + index + 1,
|
||||||
|
...item,
|
||||||
|
}))
|
||||||
|
} else {
|
||||||
|
total = 0
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
code: 0,
|
||||||
|
message: 'ok',
|
||||||
|
data: {
|
||||||
|
pageData,
|
||||||
|
total,
|
||||||
|
pageNo,
|
||||||
|
pageSize,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: '/api/post',
|
||||||
|
method: 'post',
|
||||||
|
response: ({ body }) => {
|
||||||
|
return {
|
||||||
|
code: 0,
|
||||||
|
message: 'ok',
|
||||||
|
data: body,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: '/api/post/:id',
|
||||||
|
method: 'put',
|
||||||
|
response: ({ query, body }) => {
|
||||||
|
return {
|
||||||
|
code: 0,
|
||||||
|
message: 'ok',
|
||||||
|
data: {
|
||||||
|
id: query.id,
|
||||||
|
body,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: '/api/post/:id',
|
||||||
|
method: 'delete',
|
||||||
|
response: ({ query }) => {
|
||||||
|
return {
|
||||||
|
code: 0,
|
||||||
|
message: 'ok',
|
||||||
|
data: {
|
||||||
|
id: query.id,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
149
.history/src/components/table/CrudTable_20230912152251.vue
Normal file
149
.history/src/components/table/CrudTable_20230912152251.vue
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
<template>
|
||||||
|
<QueryBar v-if="$slots.queryBar" mb-30 @search="handleSearch" @reset="handleReset">
|
||||||
|
<slot name="queryBar" />
|
||||||
|
</QueryBar>
|
||||||
|
|
||||||
|
<n-data-table
|
||||||
|
:remote="remote"
|
||||||
|
:loading="loading"
|
||||||
|
:scroll-x="scrollX"
|
||||||
|
:columns="columns"
|
||||||
|
:data="tableData"
|
||||||
|
:row-key="(row) => row[rowKey]"
|
||||||
|
:pagination="isPagination ? pagination : false"
|
||||||
|
@update:checked-row-keys="onChecked"
|
||||||
|
@update:page="onPageChange"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { utils, writeFile } from 'xlsx'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
/**
|
||||||
|
* @remote true: 后端分页 false: 前端分页
|
||||||
|
*/
|
||||||
|
remote: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* @remote 是否分页
|
||||||
|
*/
|
||||||
|
isPagination: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
scrollX: {
|
||||||
|
type: Number,
|
||||||
|
default: 1200,
|
||||||
|
},
|
||||||
|
rowKey: {
|
||||||
|
type: String,
|
||||||
|
default: 'id',
|
||||||
|
},
|
||||||
|
columns: {
|
||||||
|
type: Array,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
/** queryBar中的参数 */
|
||||||
|
queryItems: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
/** 补充参数(可选) */
|
||||||
|
extraParams: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* ! 约定接口入参出参
|
||||||
|
* * 分页模式需约定分页接口入参
|
||||||
|
* @pageSize 分页参数:一页展示多少条,默认10
|
||||||
|
* @pageNo 分页参数:页码,默认1
|
||||||
|
* * 需约定接口出参
|
||||||
|
* @pageData 分页模式必须,非分页模式如果没有pageData则取上一层data
|
||||||
|
* @total 分页模式必须,非分页模式如果没有total则取上一层data.length
|
||||||
|
*/
|
||||||
|
getData: {
|
||||||
|
type: Function,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:queryItems', 'onChecked', 'onDataChange'])
|
||||||
|
const loading = ref(false)
|
||||||
|
const initQuery = { ...props.queryItems }
|
||||||
|
const tableData = ref([])
|
||||||
|
const pagination = reactive({ page: 1, pageSize: 10 })
|
||||||
|
|
||||||
|
async function handleQuery() {
|
||||||
|
try {
|
||||||
|
loading.value = true
|
||||||
|
let paginationParams = {}
|
||||||
|
// 如果非分页模式或者使用前端分页,则无需传分页参数
|
||||||
|
if (props.isPagination && props.remote) {
|
||||||
|
paginationParams = { pageNo: pagination.page, pageSize: pagination.pageSize }
|
||||||
|
}
|
||||||
|
const { data } = await props.getData({
|
||||||
|
...props.queryItems,
|
||||||
|
...props.extraParams,
|
||||||
|
...paginationParams,
|
||||||
|
})
|
||||||
|
tableData.value = data?.pageData || data
|
||||||
|
pagination.itemCount = data.total ?? data.length
|
||||||
|
} catch (error) {
|
||||||
|
tableData.value = []
|
||||||
|
pagination.itemCount = 0
|
||||||
|
} finally {
|
||||||
|
emit('onDataChange', tableData.value)
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function handleSearch() {
|
||||||
|
pagination.page = 1
|
||||||
|
handleQuery()
|
||||||
|
}
|
||||||
|
async function handleReset() {
|
||||||
|
const queryItems = { ...props.queryItems }
|
||||||
|
for (const key in queryItems) {
|
||||||
|
queryItems[key] = ''
|
||||||
|
}
|
||||||
|
emit('update:queryItems', { ...queryItems, ...initQuery })
|
||||||
|
await nextTick()
|
||||||
|
pagination.page = 1
|
||||||
|
handleQuery()
|
||||||
|
}
|
||||||
|
function onPageChange(currentPage) {
|
||||||
|
pagination.page = currentPage
|
||||||
|
if (props.remote) {
|
||||||
|
handleQuery()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function onChecked(rowKeys) {
|
||||||
|
if (props.columns.some((item) => item.type === 'selection')) {
|
||||||
|
emit('onChecked', rowKeys)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function handleExport(columns = props.columns, data = tableData.value) {
|
||||||
|
if (!data?.length) return $message.warning('没有数据')
|
||||||
|
const columnsData = columns.filter((item) => !!item.title && !item.hideInExcel)
|
||||||
|
const thKeys = columnsData.map((item) => item.key)
|
||||||
|
const thData = columnsData.map((item) => item.title)
|
||||||
|
const trData = data.map((item) => thKeys.map((key) => item[key]))
|
||||||
|
const sheet = utils.aoa_to_sheet([thData, ...trData])
|
||||||
|
const workBook = utils.book_new()
|
||||||
|
utils.book_append_sheet(workBook, sheet, '数据报表')
|
||||||
|
writeFile(workBook, '数据报表.xlsx')
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
handleSearch,
|
||||||
|
handleReset,
|
||||||
|
handleExport,
|
||||||
|
})
|
||||||
|
</script>
|
190
.history/src/components/table/CrudTable_20230912152508.vue
Normal file
190
.history/src/components/table/CrudTable_20230912152508.vue
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
<template>
|
||||||
|
<QueryBar v-if="$slots.queryBar" mb-30 @search="handleSearch" @reset="handleReset">
|
||||||
|
<slot name="queryBar" />
|
||||||
|
</QueryBar>
|
||||||
|
|
||||||
|
<n-data-table
|
||||||
|
:remote="remote"
|
||||||
|
:loading="loading"
|
||||||
|
:scroll-x="scrollX"
|
||||||
|
:columns="columns"
|
||||||
|
:data="tableData"
|
||||||
|
:summary="getSummary"
|
||||||
|
:row-key="(row) => row[rowKey]"
|
||||||
|
:pagination="isPagination ? pagination : false"
|
||||||
|
@update:checked-row-keys="onChecked"
|
||||||
|
@update:page="onPageChange"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { utils, writeFile } from 'xlsx'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
/**
|
||||||
|
* @remote true: 后端分页 false: 前端分页
|
||||||
|
*/
|
||||||
|
remote: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* @remote 是否分页
|
||||||
|
*/
|
||||||
|
isPagination: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
scrollX: {
|
||||||
|
type: Number,
|
||||||
|
default: 1200,
|
||||||
|
},
|
||||||
|
rowKey: {
|
||||||
|
type: String,
|
||||||
|
default: 'id',
|
||||||
|
},
|
||||||
|
columns: {
|
||||||
|
type: Array,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
//获取总结数据
|
||||||
|
getSummary: {
|
||||||
|
type: Function,
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
//总结栏所需列名
|
||||||
|
sumaryCol: {
|
||||||
|
type: String,
|
||||||
|
default: 'total_expanse',
|
||||||
|
},
|
||||||
|
//总结数据
|
||||||
|
summaryRef: {
|
||||||
|
type: Object,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
/** queryBar中的参数 */
|
||||||
|
queryItems: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
/** 补充参数(可选) */
|
||||||
|
extraParams: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* ! 约定接口入参出参
|
||||||
|
* * 分页模式需约定分页接口入参
|
||||||
|
* @pageSize 分页参数:一页展示多少条,默认10
|
||||||
|
* @pageNo 分页参数:页码,默认1
|
||||||
|
* * 需约定接口出参
|
||||||
|
* @pageData 分页模式必须,非分页模式如果没有pageData则取上一层data
|
||||||
|
* @total 分页模式必须,非分页模式如果没有total则取上一层data.length
|
||||||
|
*/
|
||||||
|
getData: {
|
||||||
|
type: Function,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:queryItems', 'onChecked', 'onDataChange', 'setSum'])
|
||||||
|
const loading = ref(false)
|
||||||
|
const initQuery = { ...props.queryItems }
|
||||||
|
const tableData = ref([])
|
||||||
|
const pagination = reactive({ page: 1, pageSize: 1 })
|
||||||
|
|
||||||
|
const getSummary = (pageData) => {
|
||||||
|
// console.log(props.summaryRef)
|
||||||
|
// // eslint-disable-next-line vue/no-mutating-props
|
||||||
|
const sum = pageData.reduce(
|
||||||
|
(prevValue, row) => Number(prevValue) + Number(row[props.sumaryCol]),
|
||||||
|
0
|
||||||
|
)
|
||||||
|
emit('setSum', sum)
|
||||||
|
console.log(props.sumaryCol)
|
||||||
|
return {
|
||||||
|
title: {
|
||||||
|
value: h(
|
||||||
|
'div',
|
||||||
|
{ style: 'top:10%' },
|
||||||
|
'Total: ' + Number(sum).toFixed(2)
|
||||||
|
// eslint-disable-next-line vue/no-mutating-props
|
||||||
|
// props.summaryRef.value = num
|
||||||
|
// return num
|
||||||
|
),
|
||||||
|
colSpan: 10,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleQuery() {
|
||||||
|
try {
|
||||||
|
loading.value = true
|
||||||
|
let paginationParams = {}
|
||||||
|
// 如果非分页模式或者使用前端分页,则无需传分页参数
|
||||||
|
if (props.isPagination && props.remote) {
|
||||||
|
paginationParams = { pageNo: pagination.page, pageSize: pagination.pageSize }
|
||||||
|
}
|
||||||
|
const { data } = await props.getData({
|
||||||
|
...props.queryItems,
|
||||||
|
...props.extraParams,
|
||||||
|
...paginationParams,
|
||||||
|
})
|
||||||
|
tableData.value = data?.pageData || data
|
||||||
|
pagination.itemCount = data.total ?? data.length
|
||||||
|
} catch (error) {
|
||||||
|
tableData.value = []
|
||||||
|
pagination.itemCount = 0
|
||||||
|
} finally {
|
||||||
|
emit('onDataChange', tableData.value)
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function handleSearch() {
|
||||||
|
pagination.page = 1
|
||||||
|
handleQuery()
|
||||||
|
}
|
||||||
|
async function handleReset() {
|
||||||
|
const queryItems = { ...props.queryItems }
|
||||||
|
for (const key in queryItems) {
|
||||||
|
queryItems[key] = ''
|
||||||
|
}
|
||||||
|
emit('update:queryItems', { ...queryItems, ...initQuery })
|
||||||
|
await nextTick()
|
||||||
|
pagination.page = 1
|
||||||
|
handleQuery()
|
||||||
|
}
|
||||||
|
function onPageChange(currentPage) {
|
||||||
|
pagination.page = currentPage
|
||||||
|
if (props.remote) {
|
||||||
|
handleQuery()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function onChecked(rowKeys) {
|
||||||
|
if (props.columns.some((item) => item.type === 'selection')) {
|
||||||
|
emit('onChecked', rowKeys)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function handleExport(columns = props.columns, data = tableData.value) {
|
||||||
|
if (!data?.length) return $message.warning('没有数据')
|
||||||
|
const columnsData = columns.filter((item) => !!item.title && !item.hideInExcel)
|
||||||
|
const thKeys = columnsData.map((item) => item.key)
|
||||||
|
const thData = columnsData.map((item) => item.title)
|
||||||
|
const trData = data.map((item) => thKeys.map((key) => item[key]))
|
||||||
|
const sheet = utils.aoa_to_sheet([thData, ...trData])
|
||||||
|
const workBook = utils.book_new()
|
||||||
|
utils.book_append_sheet(workBook, sheet, '数据报表')
|
||||||
|
writeFile(workBook, '数据报表.xlsx')
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
handleSearch,
|
||||||
|
handleReset,
|
||||||
|
handleExport,
|
||||||
|
})
|
||||||
|
</script>
|
233
.history/src/views/demo/table/index_20230912152251.vue
Normal file
233
.history/src/views/demo/table/index_20230912152251.vue
Normal file
@ -0,0 +1,233 @@
|
|||||||
|
<template>
|
||||||
|
<CommonPage show-footer title="文章">
|
||||||
|
<template #action>
|
||||||
|
<div>
|
||||||
|
<n-button type="primary" secondary @click="$table?.handleExport()">
|
||||||
|
<TheIcon icon="mdi:download" :size="18" class="mr-5" />
|
||||||
|
导出
|
||||||
|
</n-button>
|
||||||
|
<n-button type="primary" class="ml-16" @click="handleAdd">
|
||||||
|
<TheIcon icon="material-symbols:add" :size="18" class="mr-5" />
|
||||||
|
新建文章
|
||||||
|
</n-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<CrudTable
|
||||||
|
ref="$table"
|
||||||
|
v-model:query-items="queryItems"
|
||||||
|
:extra-params="extraParams"
|
||||||
|
:scroll-x="1200"
|
||||||
|
:columns="columns"
|
||||||
|
:get-data="api.getPosts"
|
||||||
|
@on-checked="onChecked"
|
||||||
|
@on-data-change="(data) => (tableData = data)"
|
||||||
|
>
|
||||||
|
<template #queryBar>
|
||||||
|
<QueryBarItem label="标题" :label-width="50">
|
||||||
|
<n-input
|
||||||
|
v-model:value="queryItems.title"
|
||||||
|
type="text"
|
||||||
|
placeholder="请输入标题"
|
||||||
|
@keypress.enter="$table?.handleSearch"
|
||||||
|
/>
|
||||||
|
</QueryBarItem>
|
||||||
|
</template>
|
||||||
|
</CrudTable>
|
||||||
|
<!-- 新增/编辑/查看 -->
|
||||||
|
<CrudModal
|
||||||
|
v-model:visible="modalVisible"
|
||||||
|
:title="modalTitle"
|
||||||
|
:loading="modalLoading"
|
||||||
|
:show-footer="modalAction !== 'view'"
|
||||||
|
@on-save="handleSave"
|
||||||
|
>
|
||||||
|
<n-form
|
||||||
|
ref="modalFormRef"
|
||||||
|
label-placement="left"
|
||||||
|
label-align="left"
|
||||||
|
:label-width="80"
|
||||||
|
:model="modalForm"
|
||||||
|
:disabled="modalAction === 'view'"
|
||||||
|
>
|
||||||
|
<n-form-item label="作者" path="author">
|
||||||
|
<n-input v-model:value="modalForm.author" disabled />
|
||||||
|
</n-form-item>
|
||||||
|
<n-form-item
|
||||||
|
label="文章标题"
|
||||||
|
path="title"
|
||||||
|
:rule="{
|
||||||
|
required: true,
|
||||||
|
message: '请输入文章标题',
|
||||||
|
trigger: ['input', 'blur'],
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<n-input v-model:value="modalForm.title" placeholder="请输入文章标题" />
|
||||||
|
</n-form-item>
|
||||||
|
<n-form-item
|
||||||
|
label="文章内容"
|
||||||
|
path="content"
|
||||||
|
:rule="{
|
||||||
|
required: true,
|
||||||
|
message: '请输入文章内容',
|
||||||
|
trigger: ['input', 'blur'],
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<n-input
|
||||||
|
v-model:value="modalForm.content"
|
||||||
|
placeholder="请输入文章内容"
|
||||||
|
type="textarea"
|
||||||
|
:autosize="{
|
||||||
|
minRows: 3,
|
||||||
|
maxRows: 5,
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
</n-form-item>
|
||||||
|
</n-form>
|
||||||
|
</CrudModal>
|
||||||
|
</CommonPage>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { NButton, NSwitch } from 'naive-ui'
|
||||||
|
import { formatDateTime, renderIcon, isNullOrUndef } from '@/utils'
|
||||||
|
import { useCRUD } from '@/composables'
|
||||||
|
import api from './api'
|
||||||
|
|
||||||
|
defineOptions({ name: 'Crud' })
|
||||||
|
|
||||||
|
const $table = ref(null)
|
||||||
|
/** 表格数据,触发搜索的时候会更新这个值 */
|
||||||
|
const tableData = ref([])
|
||||||
|
/** QueryBar筛选参数(可选) */
|
||||||
|
const queryItems = ref({})
|
||||||
|
/** 补充参数(可选) */
|
||||||
|
const extraParams = ref({})
|
||||||
|
|
||||||
|
onActivated(() => {
|
||||||
|
$table.value?.handleSearch()
|
||||||
|
})
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{ type: 'selection', fixed: 'left' },
|
||||||
|
{
|
||||||
|
title: '发布',
|
||||||
|
key: 'isPublish',
|
||||||
|
width: 60,
|
||||||
|
align: 'center',
|
||||||
|
fixed: 'left',
|
||||||
|
render(row) {
|
||||||
|
return h(NSwitch, {
|
||||||
|
size: 'small',
|
||||||
|
rubberBand: false,
|
||||||
|
value: row['isPublish'],
|
||||||
|
loading: !!row.publishing,
|
||||||
|
onUpdateValue: () => handlePublish(row),
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ title: '标题', key: 'title', width: 150, ellipsis: { tooltip: true } },
|
||||||
|
{ title: '分类', key: 'category', width: 80, ellipsis: { tooltip: true } },
|
||||||
|
{ title: '创建人', key: 'author', width: 80 },
|
||||||
|
{
|
||||||
|
title: '创建时间',
|
||||||
|
key: 'createDate',
|
||||||
|
width: 150,
|
||||||
|
render(row) {
|
||||||
|
return h('span', formatDateTime(row['createDate']))
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '最后更新时间',
|
||||||
|
key: 'updateDate',
|
||||||
|
width: 150,
|
||||||
|
render(row) {
|
||||||
|
return h('span', formatDateTime(row['updateDate']))
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '操作',
|
||||||
|
key: 'actions',
|
||||||
|
width: 240,
|
||||||
|
align: 'center',
|
||||||
|
fixed: 'right',
|
||||||
|
hideInExcel: true,
|
||||||
|
render(row) {
|
||||||
|
return [
|
||||||
|
h(
|
||||||
|
NButton,
|
||||||
|
{
|
||||||
|
size: 'small',
|
||||||
|
type: 'primary',
|
||||||
|
secondary: true,
|
||||||
|
onClick: () => handleView(row),
|
||||||
|
},
|
||||||
|
{ default: () => '查看', icon: renderIcon('majesticons:eye-line', { size: 14 }) }
|
||||||
|
),
|
||||||
|
h(
|
||||||
|
NButton,
|
||||||
|
{
|
||||||
|
size: 'small',
|
||||||
|
type: 'primary',
|
||||||
|
style: 'margin-left: 15px;',
|
||||||
|
onClick: () => handleEdit(row),
|
||||||
|
},
|
||||||
|
{ default: () => '编辑', icon: renderIcon('material-symbols:edit-outline', { size: 14 }) }
|
||||||
|
),
|
||||||
|
|
||||||
|
h(
|
||||||
|
NButton,
|
||||||
|
{
|
||||||
|
size: 'small',
|
||||||
|
type: 'error',
|
||||||
|
style: 'margin-left: 15px;',
|
||||||
|
onClick: () => handleDelete(row.id),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
default: () => '删除',
|
||||||
|
icon: renderIcon('material-symbols:delete-outline', { size: 14 }),
|
||||||
|
}
|
||||||
|
),
|
||||||
|
]
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
// 选中事件
|
||||||
|
function onChecked(rowKeys) {
|
||||||
|
if (rowKeys.length) $message.info(`选中${rowKeys.join(' ')}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发布
|
||||||
|
function handlePublish(row) {
|
||||||
|
if (isNullOrUndef(row.id)) return
|
||||||
|
|
||||||
|
row.publishing = true
|
||||||
|
setTimeout(() => {
|
||||||
|
row.isPublish = !row.isPublish
|
||||||
|
row.publishing = false
|
||||||
|
$message?.success(row.isPublish ? '已发布' : '已取消发布')
|
||||||
|
}, 1000)
|
||||||
|
}
|
||||||
|
|
||||||
|
const {
|
||||||
|
modalVisible,
|
||||||
|
modalAction,
|
||||||
|
modalTitle,
|
||||||
|
modalLoading,
|
||||||
|
handleAdd,
|
||||||
|
handleDelete,
|
||||||
|
handleEdit,
|
||||||
|
handleView,
|
||||||
|
handleSave,
|
||||||
|
modalForm,
|
||||||
|
modalFormRef,
|
||||||
|
} = useCRUD({
|
||||||
|
name: '文章',
|
||||||
|
initForm: { author: '大脸怪' },
|
||||||
|
doCreate: api.addPost,
|
||||||
|
doDelete: api.deletePost,
|
||||||
|
doUpdate: api.updatePost,
|
||||||
|
refresh: () => $table.value?.handleSearch(),
|
||||||
|
})
|
||||||
|
</script>
|
287
.history/src/views/demo/table/index_20230912152520.vue
Normal file
287
.history/src/views/demo/table/index_20230912152520.vue
Normal file
@ -0,0 +1,287 @@
|
|||||||
|
<template>
|
||||||
|
<CommonPage show-footer title="文章">
|
||||||
|
<template #action>
|
||||||
|
<div>
|
||||||
|
<n-button type="primary" secondary @click="$table?.handleExport()">
|
||||||
|
<TheIcon icon="mdi:download" :size="18" class="mr-5" />
|
||||||
|
导出
|
||||||
|
</n-button>
|
||||||
|
<n-button type="primary" class="ml-16" @click="handleAdd">
|
||||||
|
<TheIcon icon="material-symbols:add" :size="18" class="mr-5" />
|
||||||
|
新建文章
|
||||||
|
</n-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<n-tabs
|
||||||
|
v-model:value="queryItems.state"
|
||||||
|
type="card"
|
||||||
|
animated
|
||||||
|
tab-style="font-weight:600;background-color:rgb(222, 231, 232); margin-bottom:10px;"
|
||||||
|
:on-update:value="selecetChap"
|
||||||
|
>
|
||||||
|
<n-tab v-for="(i, index) in tabsOptions" :id="i.name" :key="index" :name="i.name" style="">
|
||||||
|
<template #default>
|
||||||
|
<div style="">{{ i.text }}</div>
|
||||||
|
</template>
|
||||||
|
</n-tab>
|
||||||
|
</n-tabs>
|
||||||
|
<CrudTable
|
||||||
|
ref="$table"
|
||||||
|
v-model:query-items="queryItems"
|
||||||
|
:extra-params="extraParams"
|
||||||
|
:scroll-x="1200"
|
||||||
|
:columns="columns"
|
||||||
|
:get-data="api.getPosts"
|
||||||
|
:summary-ref="sumRef"
|
||||||
|
:sumary-col="current_ms"
|
||||||
|
@setSum="setSum"
|
||||||
|
@on-checked="onChecked"
|
||||||
|
@on-data-change="(data) => (tableData = data)"
|
||||||
|
>
|
||||||
|
<template #queryBar>
|
||||||
|
<QueryBarItem label="标题" :label-width="50">
|
||||||
|
<n-input
|
||||||
|
v-model:value="queryItems.title"
|
||||||
|
type="text"
|
||||||
|
placeholder="请输入标题"
|
||||||
|
@keypress.enter="$table?.handleSearch"
|
||||||
|
/>
|
||||||
|
</QueryBarItem>
|
||||||
|
</template>
|
||||||
|
</CrudTable>
|
||||||
|
<!-- 新增/编辑/查看 -->
|
||||||
|
<CrudModal
|
||||||
|
v-model:visible="modalVisible"
|
||||||
|
:title="modalTitle"
|
||||||
|
:loading="modalLoading"
|
||||||
|
:show-footer="modalAction !== 'view'"
|
||||||
|
@on-save="handleSave"
|
||||||
|
>
|
||||||
|
<n-form
|
||||||
|
ref="modalFormRef"
|
||||||
|
label-placement="left"
|
||||||
|
label-align="left"
|
||||||
|
:label-width="80"
|
||||||
|
:model="modalForm"
|
||||||
|
:disabled="modalAction === 'view'"
|
||||||
|
>
|
||||||
|
<n-form-item label="作者" path="author">
|
||||||
|
<n-input v-model:value="modalForm.author" disabled />
|
||||||
|
</n-form-item>
|
||||||
|
<n-form-item
|
||||||
|
label="文章标题"
|
||||||
|
path="title"
|
||||||
|
:rule="{
|
||||||
|
required: true,
|
||||||
|
message: '请输入文章标题',
|
||||||
|
trigger: ['input', 'blur'],
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<n-input v-model:value="modalForm.title" placeholder="请输入文章标题" />
|
||||||
|
</n-form-item>
|
||||||
|
<n-form-item
|
||||||
|
label="文章内容"
|
||||||
|
path="content"
|
||||||
|
:rule="{
|
||||||
|
required: true,
|
||||||
|
message: '请输入文章内容',
|
||||||
|
trigger: ['input', 'blur'],
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<n-input
|
||||||
|
v-model:value="modalForm.content"
|
||||||
|
placeholder="请输入文章内容"
|
||||||
|
type="textarea"
|
||||||
|
:autosize="{
|
||||||
|
minRows: 3,
|
||||||
|
maxRows: 5,
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
</n-form-item>
|
||||||
|
</n-form>
|
||||||
|
</CrudModal>
|
||||||
|
</CommonPage>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { NButton, NSwitch } from 'naive-ui'
|
||||||
|
import { formatDateTime, renderIcon, isNullOrUndef } from '@/utils'
|
||||||
|
import { useCRUD } from '@/composables'
|
||||||
|
import api from './api'
|
||||||
|
|
||||||
|
defineOptions({ name: 'Crud' })
|
||||||
|
|
||||||
|
const $table = ref(null)
|
||||||
|
/** 表格数据,触发搜索的时候会更新这个值 */
|
||||||
|
const tableData = ref([])
|
||||||
|
/** QueryBar筛选参数(可选) */
|
||||||
|
const queryItems = ref({})
|
||||||
|
/** 补充参数(可选) */
|
||||||
|
const extraParams = ref({})
|
||||||
|
|
||||||
|
//总结数
|
||||||
|
const sumRef = ref(0)
|
||||||
|
const current_ms = ref('total_expanse')
|
||||||
|
|
||||||
|
onActivated(() => {
|
||||||
|
$table.value?.handleSearch()
|
||||||
|
})
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{ type: 'selection', fixed: 'left' },
|
||||||
|
{
|
||||||
|
title: '发布',
|
||||||
|
key: 'isPublish',
|
||||||
|
width: 60,
|
||||||
|
align: 'center',
|
||||||
|
fixed: 'left',
|
||||||
|
render(row) {
|
||||||
|
return h(NSwitch, {
|
||||||
|
size: 'small',
|
||||||
|
rubberBand: false,
|
||||||
|
value: row['isPublish'],
|
||||||
|
loading: !!row.publishing,
|
||||||
|
onUpdateValue: () => handlePublish(row),
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ title: '标题', key: 'title', width: 150, ellipsis: { tooltip: true } },
|
||||||
|
{ title: '分类', key: 'category', width: 80, ellipsis: { tooltip: true } },
|
||||||
|
{ title: '创建人', key: 'author', width: 80 },
|
||||||
|
{
|
||||||
|
title: '创建时间',
|
||||||
|
key: 'createDate',
|
||||||
|
width: 150,
|
||||||
|
render(row) {
|
||||||
|
return h('span', formatDateTime(row['createDate']))
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '最后更新时间',
|
||||||
|
key: 'updateDate',
|
||||||
|
width: 150,
|
||||||
|
render(row) {
|
||||||
|
return h('span', formatDateTime(row['updateDate']))
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '操作',
|
||||||
|
key: 'actions',
|
||||||
|
width: 240,
|
||||||
|
align: 'center',
|
||||||
|
fixed: 'right',
|
||||||
|
hideInExcel: true,
|
||||||
|
render(row) {
|
||||||
|
return [
|
||||||
|
h(
|
||||||
|
NButton,
|
||||||
|
{
|
||||||
|
size: 'small',
|
||||||
|
type: 'primary',
|
||||||
|
secondary: true,
|
||||||
|
onClick: () => handleView(row),
|
||||||
|
},
|
||||||
|
{ default: () => '查看', icon: renderIcon('majesticons:eye-line', { size: 14 }) }
|
||||||
|
),
|
||||||
|
h(
|
||||||
|
NButton,
|
||||||
|
{
|
||||||
|
size: 'small',
|
||||||
|
type: 'primary',
|
||||||
|
style: 'margin-left: 15px;',
|
||||||
|
onClick: () => handleEdit(row),
|
||||||
|
},
|
||||||
|
{ default: () => '编辑', icon: renderIcon('material-symbols:edit-outline', { size: 14 }) }
|
||||||
|
),
|
||||||
|
|
||||||
|
h(
|
||||||
|
NButton,
|
||||||
|
{
|
||||||
|
size: 'small',
|
||||||
|
type: 'error',
|
||||||
|
style: 'margin-left: 15px;',
|
||||||
|
onClick: () => handleDelete(row.id),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
default: () => '删除',
|
||||||
|
icon: renderIcon('material-symbols:delete-outline', { size: 14 }),
|
||||||
|
}
|
||||||
|
),
|
||||||
|
]
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
//tabs栏
|
||||||
|
const tabsOptions = ref([
|
||||||
|
{
|
||||||
|
name: 'tab1',
|
||||||
|
value: 'tab1',
|
||||||
|
text: 'tab1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'tab2',
|
||||||
|
value: 'tab2',
|
||||||
|
text: 'tab2',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'tab3',
|
||||||
|
value: 'tab3',
|
||||||
|
text: 'tab3',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'tab4',
|
||||||
|
value: 'tab4',
|
||||||
|
text: 'tab4',
|
||||||
|
},
|
||||||
|
])
|
||||||
|
//设置总结需要传的函数
|
||||||
|
function setSum(val) {
|
||||||
|
sumRef.value = val
|
||||||
|
console.log(sumRef.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
//根据tabs选择状态搜索
|
||||||
|
function selecetChap(val) {
|
||||||
|
queryItems.value.state = val
|
||||||
|
$table.value?.handleSearch()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 选中事件
|
||||||
|
function onChecked(rowKeys) {
|
||||||
|
if (rowKeys.length) $message.info(`选中${rowKeys.join(' ')}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发布
|
||||||
|
function handlePublish(row) {
|
||||||
|
if (isNullOrUndef(row.id)) return
|
||||||
|
|
||||||
|
row.publishing = true
|
||||||
|
setTimeout(() => {
|
||||||
|
row.isPublish = !row.isPublish
|
||||||
|
row.publishing = false
|
||||||
|
$message?.success(row.isPublish ? '已发布' : '已取消发布')
|
||||||
|
}, 1000)
|
||||||
|
}
|
||||||
|
|
||||||
|
const {
|
||||||
|
modalVisible,
|
||||||
|
modalAction,
|
||||||
|
modalTitle,
|
||||||
|
modalLoading,
|
||||||
|
handleAdd,
|
||||||
|
handleDelete,
|
||||||
|
handleEdit,
|
||||||
|
handleView,
|
||||||
|
handleSave,
|
||||||
|
modalForm,
|
||||||
|
modalFormRef,
|
||||||
|
} = useCRUD({
|
||||||
|
name: '文章',
|
||||||
|
initForm: { author: '大脸怪' },
|
||||||
|
doCreate: api.addPost,
|
||||||
|
doDelete: api.deletePost,
|
||||||
|
doUpdate: api.updatePost,
|
||||||
|
refresh: () => $table.value?.handleSearch(),
|
||||||
|
})
|
||||||
|
</script>
|
3
.vs/ProjectSettings.json
Normal file
3
.vs/ProjectSettings.json
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"CurrentProjectSetting": null
|
||||||
|
}
|
7
.vs/VSWorkspaceState.json
Normal file
7
.vs/VSWorkspaceState.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"ExpandedNodes": [
|
||||||
|
""
|
||||||
|
],
|
||||||
|
"SelectedNode": "\\C:\\Users\\P17 Gen1\\Source\\Repos\\vue-naive-admin",
|
||||||
|
"PreviewInSolutionExplorer": false
|
||||||
|
}
|
BIN
.vs/slnx.sqlite
Normal file
BIN
.vs/slnx.sqlite
Normal file
Binary file not shown.
BIN
.vs/vue-naive-admin/v16/.suo
Normal file
BIN
.vs/vue-naive-admin/v16/.suo
Normal file
Binary file not shown.
@ -7,6 +7,8 @@ const posts = [
|
|||||||
content: '通常配置rem布局会使用js进行处理,比如750的设计稿会这样',
|
content: '通常配置rem布局会使用js进行处理,比如750的设计稿会这样',
|
||||||
isRecommend: true,
|
isRecommend: true,
|
||||||
isPublish: true,
|
isPublish: true,
|
||||||
|
total_expanse: 100,
|
||||||
|
state: 'approve',
|
||||||
createDate: '2021-11-04T04:03:36.000Z',
|
createDate: '2021-11-04T04:03:36.000Z',
|
||||||
updateDate: '2021-11-04T04:03:36.000Z',
|
updateDate: '2021-11-04T04:03:36.000Z',
|
||||||
},
|
},
|
||||||
@ -17,6 +19,7 @@ const posts = [
|
|||||||
description: '总结的Vue2和Vue3的项目风格',
|
description: '总结的Vue2和Vue3的项目风格',
|
||||||
content: '### 1. 命名风格\n\n> 文件夹如果是由多个单词组成,应该始终是横线连接 ',
|
content: '### 1. 命名风格\n\n> 文件夹如果是由多个单词组成,应该始终是横线连接 ',
|
||||||
isRecommend: true,
|
isRecommend: true,
|
||||||
|
total_expanse: 100,
|
||||||
isPublish: true,
|
isPublish: true,
|
||||||
createDate: '2021-10-25T08:57:47.000Z',
|
createDate: '2021-10-25T08:57:47.000Z',
|
||||||
updateDate: '2022-02-28T04:02:39.000Z',
|
updateDate: '2022-02-28T04:02:39.000Z',
|
||||||
@ -28,6 +31,7 @@ const posts = [
|
|||||||
description: '优雅的给图片添加水印',
|
description: '优雅的给图片添加水印',
|
||||||
content: '我之前写过一篇文章记录了一次上传图片的优化史',
|
content: '我之前写过一篇文章记录了一次上传图片的优化史',
|
||||||
isRecommend: true,
|
isRecommend: true,
|
||||||
|
total_expanse: 100,
|
||||||
isPublish: true,
|
isPublish: true,
|
||||||
createDate: '2021-06-24T18:46:19.000Z',
|
createDate: '2021-06-24T18:46:19.000Z',
|
||||||
updateDate: '2021-09-23T07:51:22.000Z',
|
updateDate: '2021-09-23T07:51:22.000Z',
|
||||||
@ -42,6 +46,7 @@ const posts = [
|
|||||||
'> 背景\n\n公司有个vue-cli3移动端web项目发版更新后发现部分用户手机在钉钉内置浏览器打开出现了缓存',
|
'> 背景\n\n公司有个vue-cli3移动端web项目发版更新后发现部分用户手机在钉钉内置浏览器打开出现了缓存',
|
||||||
isRecommend: true,
|
isRecommend: true,
|
||||||
isPublish: true,
|
isPublish: true,
|
||||||
|
total_expanse: 100,
|
||||||
createDate: '2021-06-10T18:51:19.000Z',
|
createDate: '2021-06-10T18:51:19.000Z',
|
||||||
updateDate: '2021-09-17T09:33:24.000Z',
|
updateDate: '2021-09-17T09:33:24.000Z',
|
||||||
},
|
},
|
||||||
@ -54,6 +59,7 @@ const posts = [
|
|||||||
'## 1. Promise.all\n\n并行执行多个 promise,并等待所有 promise 都准备就绪。再对它们进行处理。',
|
'## 1. Promise.all\n\n并行执行多个 promise,并等待所有 promise 都准备就绪。再对它们进行处理。',
|
||||||
isRecommend: true,
|
isRecommend: true,
|
||||||
isPublish: true,
|
isPublish: true,
|
||||||
|
total_expanse: 100,
|
||||||
createDate: '2021-02-22T22:37:06.000Z',
|
createDate: '2021-02-22T22:37:06.000Z',
|
||||||
updateDate: '2021-09-17T09:33:24.000Z',
|
updateDate: '2021-09-17T09:33:24.000Z',
|
||||||
},
|
},
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
:scroll-x="scrollX"
|
:scroll-x="scrollX"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
:data="tableData"
|
:data="tableData"
|
||||||
|
:summary="getSummary"
|
||||||
:row-key="(row) => row[rowKey]"
|
:row-key="(row) => row[rowKey]"
|
||||||
:pagination="isPagination ? pagination : false"
|
:pagination="isPagination ? pagination : false"
|
||||||
@update:checked-row-keys="onChecked"
|
@update:checked-row-keys="onChecked"
|
||||||
@ -46,6 +47,21 @@ const props = defineProps({
|
|||||||
type: Array,
|
type: Array,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
|
//获取总结数据
|
||||||
|
getSummary: {
|
||||||
|
type: Function,
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
//总结栏所需列名
|
||||||
|
sumaryCol: {
|
||||||
|
type: String,
|
||||||
|
default: 'total_expanse',
|
||||||
|
},
|
||||||
|
//总结数据
|
||||||
|
summaryRef: {
|
||||||
|
type: Object,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
/** queryBar中的参数 */
|
/** queryBar中的参数 */
|
||||||
queryItems: {
|
queryItems: {
|
||||||
type: Object,
|
type: Object,
|
||||||
@ -53,6 +69,7 @@ const props = defineProps({
|
|||||||
return {}
|
return {}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
/** 补充参数(可选) */
|
/** 补充参数(可选) */
|
||||||
extraParams: {
|
extraParams: {
|
||||||
type: Object,
|
type: Object,
|
||||||
@ -75,11 +92,35 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const emit = defineEmits(['update:queryItems', 'onChecked', 'onDataChange'])
|
const emit = defineEmits(['update:queryItems', 'onChecked', 'onDataChange', 'setSum'])
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const initQuery = { ...props.queryItems }
|
const initQuery = { ...props.queryItems }
|
||||||
const tableData = ref([])
|
const tableData = ref([])
|
||||||
const pagination = reactive({ page: 1, pageSize: 10 })
|
const pagination = reactive({ page: 1, pageSize: 1 })
|
||||||
|
|
||||||
|
const getSummary = (pageData) => {
|
||||||
|
// console.log(props.summaryRef)
|
||||||
|
// // eslint-disable-next-line vue/no-mutating-props
|
||||||
|
const sum = pageData.reduce(
|
||||||
|
(prevValue, row) => Number(prevValue) + Number(row[props.sumaryCol]),
|
||||||
|
0
|
||||||
|
)
|
||||||
|
emit('setSum', sum)
|
||||||
|
console.log(props.sumaryCol)
|
||||||
|
return {
|
||||||
|
title: {
|
||||||
|
value: h(
|
||||||
|
'div',
|
||||||
|
{ style: 'top:10%' },
|
||||||
|
'Total: ' + Number(sum).toFixed(2)
|
||||||
|
// eslint-disable-next-line vue/no-mutating-props
|
||||||
|
// props.summaryRef.value = num
|
||||||
|
// return num
|
||||||
|
),
|
||||||
|
colSpan: 10,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function handleQuery() {
|
async function handleQuery() {
|
||||||
try {
|
try {
|
||||||
|
@ -12,7 +12,19 @@
|
|||||||
</n-button>
|
</n-button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
<n-tabs
|
||||||
|
v-model:value="queryItems.state"
|
||||||
|
type="card"
|
||||||
|
animated
|
||||||
|
tab-style="font-weight:600;background-color:rgb(222, 231, 232); margin-bottom:10px;"
|
||||||
|
:on-update:value="selecetChap"
|
||||||
|
>
|
||||||
|
<n-tab v-for="(i, index) in tabsOptions" :id="i.name" :key="index" :name="i.name" style="">
|
||||||
|
<template #default>
|
||||||
|
<div style="">{{ i.text }}</div>
|
||||||
|
</template>
|
||||||
|
</n-tab>
|
||||||
|
</n-tabs>
|
||||||
<CrudTable
|
<CrudTable
|
||||||
ref="$table"
|
ref="$table"
|
||||||
v-model:query-items="queryItems"
|
v-model:query-items="queryItems"
|
||||||
@ -20,6 +32,9 @@
|
|||||||
:scroll-x="1200"
|
:scroll-x="1200"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
:get-data="api.getPosts"
|
:get-data="api.getPosts"
|
||||||
|
:summary-ref="sumRef"
|
||||||
|
:sumary-col="current_ms"
|
||||||
|
@setSum="setSum"
|
||||||
@on-checked="onChecked"
|
@on-checked="onChecked"
|
||||||
@on-data-change="(data) => (tableData = data)"
|
@on-data-change="(data) => (tableData = data)"
|
||||||
>
|
>
|
||||||
@ -104,6 +119,10 @@ const queryItems = ref({})
|
|||||||
/** 补充参数(可选) */
|
/** 补充参数(可选) */
|
||||||
const extraParams = ref({})
|
const extraParams = ref({})
|
||||||
|
|
||||||
|
//总结数
|
||||||
|
const sumRef = ref(0)
|
||||||
|
const current_ms = ref('total_expanse')
|
||||||
|
|
||||||
onActivated(() => {
|
onActivated(() => {
|
||||||
$table.value?.handleSearch()
|
$table.value?.handleSearch()
|
||||||
})
|
})
|
||||||
@ -193,6 +212,41 @@ const columns = [
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
//tabs栏
|
||||||
|
const tabsOptions = ref([
|
||||||
|
{
|
||||||
|
name: 'tab1',
|
||||||
|
value: 'tab1',
|
||||||
|
text: 'tab1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'tab2',
|
||||||
|
value: 'tab2',
|
||||||
|
text: 'tab2',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'tab3',
|
||||||
|
value: 'tab3',
|
||||||
|
text: 'tab3',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'tab4',
|
||||||
|
value: 'tab4',
|
||||||
|
text: 'tab4',
|
||||||
|
},
|
||||||
|
])
|
||||||
|
//设置总结需要传的函数
|
||||||
|
function setSum(val) {
|
||||||
|
sumRef.value = val
|
||||||
|
console.log(sumRef.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
//根据tabs选择状态搜索
|
||||||
|
function selecetChap(val) {
|
||||||
|
queryItems.value.state = val
|
||||||
|
$table.value?.handleSearch()
|
||||||
|
}
|
||||||
|
|
||||||
// 选中事件
|
// 选中事件
|
||||||
function onChecked(rowKeys) {
|
function onChecked(rowKeys) {
|
||||||
if (rowKeys.length) $message.info(`选中${rowKeys.join(' ')}`)
|
if (rowKeys.length) $message.info(`选中${rowKeys.join(' ')}`)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user