feat: 同步master
This commit is contained in:
parent
6a83d08309
commit
9eb1356c4e
|
@ -2,7 +2,7 @@
|
||||||
"typescript.tsdk": "node_modules/typescript/lib",
|
"typescript.tsdk": "node_modules/typescript/lib",
|
||||||
"prettier.enable": false,
|
"prettier.enable": false,
|
||||||
"editor.codeActionsOnSave": {
|
"editor.codeActionsOnSave": {
|
||||||
"source.fixAll.eslint": true
|
"source.fixAll.eslint": "explicit"
|
||||||
},
|
},
|
||||||
"[vue]": {
|
"[vue]": {
|
||||||
"editor.defaultFormatter": "rvest.vs-code-prettier-eslint"
|
"editor.defaultFormatter": "rvest.vs-code-prettier-eslint"
|
||||||
|
|
69
package.json
69
package.json
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "vue-element-plus-admin",
|
"name": "vue-element-plus-admin",
|
||||||
"version": "2.0.0",
|
"version": "2.5.5",
|
||||||
"description": "一套基于vue3、element-plus、typesScript、vite4的后台集成方案。",
|
"description": "一套基于vue3、element-plus、typesScript、vite4的后台集成方案。",
|
||||||
"author": "Archer <502431556@qq.com>",
|
"author": "Archer <502431556@qq.com>",
|
||||||
"private": false,
|
"private": false,
|
||||||
|
@ -29,59 +29,60 @@
|
||||||
"@faker-js/faker": "^8.3.1",
|
"@faker-js/faker": "^8.3.1",
|
||||||
"@iconify/iconify": "^3.1.1",
|
"@iconify/iconify": "^3.1.1",
|
||||||
"@iconify/vue": "^4.1.1",
|
"@iconify/vue": "^4.1.1",
|
||||||
"@vueuse/core": "^10.7.0",
|
"@vueuse/core": "^10.7.1",
|
||||||
"@wangeditor/editor": "^5.1.23",
|
"@wangeditor/editor": "^5.1.23",
|
||||||
"@wangeditor/editor-for-vue": "^5.1.10",
|
"@wangeditor/editor-for-vue": "^5.1.10",
|
||||||
"@zxcvbn-ts/core": "^3.0.4",
|
"@zxcvbn-ts/core": "^3.0.4",
|
||||||
"animate.css": "^4.1.1",
|
"animate.css": "^4.1.1",
|
||||||
"axios": "^1.6.2",
|
"axios": "^1.6.5",
|
||||||
"cropperjs": "^1.6.1",
|
"cropperjs": "^1.6.1",
|
||||||
"dayjs": "^1.11.10",
|
"dayjs": "^1.11.10",
|
||||||
"driver.js": "^1.3.1",
|
"driver.js": "^1.3.1",
|
||||||
"echarts": "^5.4.3",
|
"echarts": "^5.4.3",
|
||||||
"echarts-wordcloud": "^2.1.0",
|
"echarts-wordcloud": "^2.1.0",
|
||||||
"element-plus": "^2.4.3",
|
"element-plus": "^2.4.4",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"mitt": "^3.0.1",
|
"mitt": "^3.0.1",
|
||||||
"nprogress": "^0.2.0",
|
"nprogress": "^0.2.0",
|
||||||
"pinia": "^2.1.7",
|
"pinia": "^2.1.7",
|
||||||
"pinia-plugin-persistedstate": "^3.2.0",
|
"pinia-plugin-persistedstate": "^3.2.1",
|
||||||
"qrcode": "^1.5.3",
|
"qrcode": "^1.5.3",
|
||||||
"qs": "^6.11.2",
|
"qs": "^6.11.2",
|
||||||
"url": "^0.11.3",
|
"url": "^0.11.3",
|
||||||
"vue": "3.3.10",
|
"vue": "3.4.6",
|
||||||
"vue-i18n": "9.8.0",
|
"vue-draggable-plus": "^0.3.4",
|
||||||
"vue-json-pretty": "^2.2.4",
|
"vue-i18n": "9.9.0",
|
||||||
|
"vue-json-pretty": "^2.3.0",
|
||||||
"vue-router": "^4.2.5",
|
"vue-router": "^4.2.5",
|
||||||
"vue-types": "^5.1.1",
|
"vue-types": "^5.1.1",
|
||||||
"xgplayer": "^3.0.10"
|
"xgplayer": "^3.0.11"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@commitlint/cli": "^18.4.3",
|
"@commitlint/cli": "^18.4.4",
|
||||||
"@commitlint/config-conventional": "^18.4.3",
|
"@commitlint/config-conventional": "^18.4.4",
|
||||||
"@iconify/json": "^2.2.153",
|
"@iconify/json": "^2.2.166",
|
||||||
"@intlify/unplugin-vue-i18n": "^1.5.0",
|
"@intlify/unplugin-vue-i18n": "^2.0.0",
|
||||||
"@types/fs-extra": "^11.0.4",
|
"@types/fs-extra": "^11.0.4",
|
||||||
"@types/inquirer": "^9.0.7",
|
"@types/inquirer": "^9.0.7",
|
||||||
"@types/lodash-es": "^4.17.12",
|
"@types/lodash-es": "^4.17.12",
|
||||||
"@types/node": "^20.10.3",
|
"@types/node": "^20.10.7",
|
||||||
"@types/nprogress": "^0.2.3",
|
"@types/nprogress": "^0.2.3",
|
||||||
"@types/qrcode": "^1.5.5",
|
"@types/qrcode": "^1.5.5",
|
||||||
"@types/qs": "^6.9.10",
|
"@types/qs": "^6.9.11",
|
||||||
"@types/sortablejs": "^1.15.7",
|
"@types/sortablejs": "^1.15.7",
|
||||||
"@typescript-eslint/eslint-plugin": "^6.13.2",
|
"@typescript-eslint/eslint-plugin": "^6.18.1",
|
||||||
"@typescript-eslint/parser": "^6.13.2",
|
"@typescript-eslint/parser": "^6.18.1",
|
||||||
"@unocss/transformer-variant-group": "^0.58.0",
|
"@unocss/transformer-variant-group": "^0.58.3",
|
||||||
"@vitejs/plugin-legacy": "^5.2.0",
|
"@vitejs/plugin-legacy": "^5.2.0",
|
||||||
"@vitejs/plugin-vue": "^4.5.1",
|
"@vitejs/plugin-vue": "^5.0.2",
|
||||||
"@vitejs/plugin-vue-jsx": "^3.1.0",
|
"@vitejs/plugin-vue-jsx": "^3.1.0",
|
||||||
"autoprefixer": "^10.4.16",
|
"autoprefixer": "^10.4.16",
|
||||||
"chalk": "^5.3.0",
|
"chalk": "^5.3.0",
|
||||||
"consola": "^3.2.3",
|
"consola": "^3.2.3",
|
||||||
"eslint": "^8.55.0",
|
"eslint": "^8.56.0",
|
||||||
"eslint-config-prettier": "^9.1.0",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
"eslint-define-config": "^2.0.0",
|
"eslint-define-config": "^2.1.0",
|
||||||
"eslint-plugin-prettier": "^5.0.1",
|
"eslint-plugin-prettier": "^5.1.2",
|
||||||
"eslint-plugin-vue": "^9.19.2",
|
"eslint-plugin-vue": "^9.19.2",
|
||||||
"esno": "^4.0.0",
|
"esno": "^4.0.0",
|
||||||
"fs-extra": "^11.2.0",
|
"fs-extra": "^11.2.0",
|
||||||
|
@ -89,23 +90,23 @@
|
||||||
"inquirer": "^9.2.12",
|
"inquirer": "^9.2.12",
|
||||||
"less": "^4.2.0",
|
"less": "^4.2.0",
|
||||||
"lint-staged": "^15.2.0",
|
"lint-staged": "^15.2.0",
|
||||||
"plop": "^4.0.0",
|
"plop": "^4.0.1",
|
||||||
"postcss": "^8.4.32",
|
"postcss": "^8.4.33",
|
||||||
"postcss-html": "^1.5.0",
|
"postcss-html": "^1.5.0",
|
||||||
"postcss-less": "^6.0.0",
|
"postcss-less": "^6.0.0",
|
||||||
"prettier": "^3.1.0",
|
"prettier": "^3.1.1",
|
||||||
"rimraf": "^5.0.5",
|
"rimraf": "^5.0.5",
|
||||||
"rollup": "^4.6.1",
|
"rollup": "^4.9.4",
|
||||||
"rollup-plugin-visualizer": "^5.12.0",
|
"rollup-plugin-visualizer": "^5.12.0",
|
||||||
"stylelint": "^15.11.0",
|
"stylelint": "^16.1.0",
|
||||||
"stylelint-config-html": "^1.1.0",
|
"stylelint-config-html": "^1.1.0",
|
||||||
"stylelint-config-recommended": "^13.0.0",
|
"stylelint-config-recommended": "^14.0.0",
|
||||||
"stylelint-config-standard": "^34.0.0",
|
"stylelint-config-standard": "^36.0.0",
|
||||||
"stylelint-order": "^6.0.3",
|
"stylelint-order": "^6.0.4",
|
||||||
"terser": "^5.25.0",
|
"terser": "^5.26.0",
|
||||||
"typescript": "5.3.3",
|
"typescript": "5.3.3",
|
||||||
"unocss": "^0.58.0",
|
"unocss": "^0.58.3",
|
||||||
"vite": "5.0.6",
|
"vite": "5.0.11",
|
||||||
"vite-plugin-ejs": "^1.7.0",
|
"vite-plugin-ejs": "^1.7.0",
|
||||||
"vite-plugin-eslint": "^1.8.1",
|
"vite-plugin-eslint": "^1.8.1",
|
||||||
"vite-plugin-mock": "^2.9.6",
|
"vite-plugin-mock": "^2.9.6",
|
||||||
|
@ -113,7 +114,7 @@
|
||||||
"vite-plugin-purge-icons": "^0.10.0",
|
"vite-plugin-purge-icons": "^0.10.0",
|
||||||
"vite-plugin-style-import": "2.0.0",
|
"vite-plugin-style-import": "2.0.0",
|
||||||
"vite-plugin-svg-icons": "^2.0.1",
|
"vite-plugin-svg-icons": "^2.0.1",
|
||||||
"vue-tsc": "^1.8.25"
|
"vue-tsc": "^1.8.27"
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@8.1.0",
|
"packageManager": "pnpm@8.1.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|
|
@ -10,10 +10,14 @@ export const useRenderMenuTitle = () => {
|
||||||
return icon ? (
|
return icon ? (
|
||||||
<>
|
<>
|
||||||
<Icon icon={meta.icon}></Icon>
|
<Icon icon={meta.icon}></Icon>
|
||||||
<span class="v-menu__title">{t(title as string)}</span>
|
<span class="v-menu__title overflow-hidden overflow-ellipsis whitespace-nowrap">
|
||||||
|
{t(title as string)}
|
||||||
|
</span>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<span class="v-menu__title">{t(title as string)}</span>
|
<span class="v-menu__title overflow-hidden overflow-ellipsis whitespace-nowrap">
|
||||||
|
{t(title as string)}
|
||||||
|
</span>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,6 @@ import { set, get } from 'lodash-es'
|
||||||
import { CSSProperties } from 'vue'
|
import { CSSProperties } from 'vue'
|
||||||
import { getSlot } from '@/utils/tsxHelper'
|
import { getSlot } from '@/utils/tsxHelper'
|
||||||
import TableActions from './components/TableActions.vue'
|
import TableActions from './components/TableActions.vue'
|
||||||
import { isImgPath } from '@/utils/is'
|
|
||||||
import { createVideoViewer } from '@/components/VideoPlayer'
|
import { createVideoViewer } from '@/components/VideoPlayer'
|
||||||
import { Icon } from '@/components/Icon'
|
import { Icon } from '@/components/Icon'
|
||||||
import { BaseButton } from '@/components/Button'
|
import { BaseButton } from '@/components/Button'
|
||||||
|
@ -59,8 +58,13 @@ export default defineComponent({
|
||||||
type: Array as PropType<Recordable[]>,
|
type: Array as PropType<Recordable[]>,
|
||||||
default: () => []
|
default: () => []
|
||||||
},
|
},
|
||||||
// 是否自动预览
|
// 图片自动预览字段数组
|
||||||
preview: {
|
imagePreview: {
|
||||||
|
type: Array as PropType<string[]>,
|
||||||
|
default: () => []
|
||||||
|
},
|
||||||
|
// 视频自动预览字段数组
|
||||||
|
videoPreview: {
|
||||||
type: Array as PropType<string[]>,
|
type: Array as PropType<string[]>,
|
||||||
default: () => []
|
default: () => []
|
||||||
},
|
},
|
||||||
|
@ -275,6 +279,10 @@ export default defineComponent({
|
||||||
setProps({ size })
|
setProps({ size })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const confirmSetColumn = (columns: TableColumn[]) => {
|
||||||
|
setProps({ columns })
|
||||||
|
}
|
||||||
|
|
||||||
expose({
|
expose({
|
||||||
setProps,
|
setProps,
|
||||||
setColumn,
|
setColumn,
|
||||||
|
@ -335,7 +343,8 @@ export default defineComponent({
|
||||||
})
|
})
|
||||||
|
|
||||||
const renderTreeTableColumn = (columnsChildren: TableColumn[]) => {
|
const renderTreeTableColumn = (columnsChildren: TableColumn[]) => {
|
||||||
const { align, headerAlign, showOverflowTooltip, preview } = unref(getProps)
|
const { align, headerAlign, showOverflowTooltip, imagePreview, videoPreview } =
|
||||||
|
unref(getProps)
|
||||||
return columnsChildren.map((v) => {
|
return columnsChildren.map((v) => {
|
||||||
if (v.hidden) return null
|
if (v.hidden) return null
|
||||||
const props = { ...v } as any
|
const props = { ...v } as any
|
||||||
|
@ -346,10 +355,10 @@ export default defineComponent({
|
||||||
const slots = {
|
const slots = {
|
||||||
default: (...args: any[]) => {
|
default: (...args: any[]) => {
|
||||||
const data = args[0]
|
const data = args[0]
|
||||||
let isImageUrl = false
|
let isPreview = false
|
||||||
if (preview.length) {
|
isPreview =
|
||||||
isImageUrl = preview.some((item) => (item as string) === v.field)
|
imagePreview.some((item) => (item as string) === v.field) ||
|
||||||
}
|
videoPreview.some((item) => (item as string) === v.field)
|
||||||
|
|
||||||
return children && children.length
|
return children && children.length
|
||||||
? renderTreeTableColumn(children)
|
? renderTreeTableColumn(children)
|
||||||
|
@ -357,8 +366,8 @@ export default defineComponent({
|
||||||
? props.slots.default(...args)
|
? props.slots.default(...args)
|
||||||
: v?.formatter
|
: v?.formatter
|
||||||
? v?.formatter?.(data.row, data.column, get(data.row, v.field), data.$index)
|
? v?.formatter?.(data.row, data.column, get(data.row, v.field), data.$index)
|
||||||
: isImageUrl
|
: isPreview
|
||||||
? renderPreview(get(data.row, v.field))
|
? renderPreview(get(data.row, v.field), v.field)
|
||||||
: get(data.row, v.field)
|
: get(data.row, v.field)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -380,10 +389,11 @@ export default defineComponent({
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const renderPreview = (url: string) => {
|
const renderPreview = (url: string, field: string) => {
|
||||||
|
const { imagePreview, videoPreview } = unref(getProps)
|
||||||
return (
|
return (
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
{isImgPath(url) ? (
|
{imagePreview.includes(field) ? (
|
||||||
<ElImage
|
<ElImage
|
||||||
src={url}
|
src={url}
|
||||||
fit="cover"
|
fit="cover"
|
||||||
|
@ -392,7 +402,7 @@ export default defineComponent({
|
||||||
preview-src-list={[url]}
|
preview-src-list={[url]}
|
||||||
preview-teleported
|
preview-teleported
|
||||||
/>
|
/>
|
||||||
) : (
|
) : videoPreview.includes(field) ? (
|
||||||
<BaseButton
|
<BaseButton
|
||||||
type="primary"
|
type="primary"
|
||||||
icon={<Icon icon="ep:video-play" />}
|
icon={<Icon icon="ep:video-play" />}
|
||||||
|
@ -404,7 +414,7 @@ export default defineComponent({
|
||||||
>
|
>
|
||||||
预览
|
预览
|
||||||
</BaseButton>
|
</BaseButton>
|
||||||
)}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -419,7 +429,8 @@ export default defineComponent({
|
||||||
headerAlign,
|
headerAlign,
|
||||||
showOverflowTooltip,
|
showOverflowTooltip,
|
||||||
reserveSelection,
|
reserveSelection,
|
||||||
preview
|
imagePreview,
|
||||||
|
videoPreview
|
||||||
} = unref(getProps)
|
} = unref(getProps)
|
||||||
|
|
||||||
return (columnsChildren || columns).map((v) => {
|
return (columnsChildren || columns).map((v) => {
|
||||||
|
@ -434,6 +445,7 @@ export default defineComponent({
|
||||||
align={v.align || align}
|
align={v.align || align}
|
||||||
headerAlign={v.headerAlign || headerAlign}
|
headerAlign={v.headerAlign || headerAlign}
|
||||||
label={v.label}
|
label={v.label}
|
||||||
|
fixed={v.fixed}
|
||||||
width="65px"
|
width="65px"
|
||||||
></ElTableColumn>
|
></ElTableColumn>
|
||||||
)
|
)
|
||||||
|
@ -458,10 +470,10 @@ export default defineComponent({
|
||||||
default: (...args: any[]) => {
|
default: (...args: any[]) => {
|
||||||
const data = args[0]
|
const data = args[0]
|
||||||
|
|
||||||
let isImageUrl = false
|
let isPreview = false
|
||||||
if (preview.length) {
|
isPreview =
|
||||||
isImageUrl = preview.some((item) => (item as string) === v.field)
|
imagePreview.some((item) => (item as string) === v.field) ||
|
||||||
}
|
videoPreview.some((item) => (item as string) === v.field)
|
||||||
|
|
||||||
return children && children.length
|
return children && children.length
|
||||||
? renderTreeTableColumn(children)
|
? renderTreeTableColumn(children)
|
||||||
|
@ -469,8 +481,8 @@ export default defineComponent({
|
||||||
? props.slots.default(...args)
|
? props.slots.default(...args)
|
||||||
: v?.formatter
|
: v?.formatter
|
||||||
? v?.formatter?.(data.row, data.column, get(data.row, v.field), data.$index)
|
? v?.formatter?.(data.row, data.column, get(data.row, v.field), data.$index)
|
||||||
: isImageUrl
|
: isPreview
|
||||||
? renderPreview(get(data.row, v.field))
|
? renderPreview(get(data.row, v.field), v.field)
|
||||||
: get(data.row, v.field)
|
: get(data.row, v.field)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -543,11 +555,12 @@ export default defineComponent({
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
{unref(getProps).showAction ? (
|
{unref(getProps).showAction && !unref(getProps).customContent ? (
|
||||||
<TableActions
|
<TableActions
|
||||||
columns={unref(getProps).columns}
|
columns={unref(getProps).columns}
|
||||||
onChangSize={changSize}
|
onChangSize={changSize}
|
||||||
onRefresh={refresh}
|
onRefresh={refresh}
|
||||||
|
onConfirm={confirmSetColumn}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
<ElTable ref={elTableRef} data={unref(getProps).data} {...unref(getBindValue)}>
|
<ElTable ref={elTableRef} data={unref(getProps).data} {...unref(getBindValue)}>
|
||||||
|
|
|
@ -0,0 +1,165 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {
|
||||||
|
ElDrawer,
|
||||||
|
ElCheckbox,
|
||||||
|
ElCheckboxGroup,
|
||||||
|
ElText,
|
||||||
|
ElRadioButton,
|
||||||
|
ElRadioGroup
|
||||||
|
} from 'element-plus'
|
||||||
|
import { TableColumn } from '../types'
|
||||||
|
import { PropType, ref, watch, unref } from 'vue'
|
||||||
|
import { cloneDeep } from 'lodash-es'
|
||||||
|
import { DEFAULT_FILTER_COLUMN } from '@/constants'
|
||||||
|
import { VueDraggable } from 'vue-draggable-plus'
|
||||||
|
|
||||||
|
const modelValue = defineModel<boolean>()
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
columns: {
|
||||||
|
type: Array as PropType<TableColumn[]>,
|
||||||
|
default: () => []
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['confirm'])
|
||||||
|
|
||||||
|
const oldColumns = ref<TableColumn[]>()
|
||||||
|
|
||||||
|
const settingColumns = ref<TableColumn[]>()
|
||||||
|
|
||||||
|
// 存储不要的列
|
||||||
|
const hiddenColumns = ref<TableColumn[]>([])
|
||||||
|
|
||||||
|
const defaultCheckColumns = ref<string[]>([])
|
||||||
|
const checkColumns = ref<string[]>([])
|
||||||
|
|
||||||
|
const checkAll = ref(false)
|
||||||
|
const isIndeterminate = ref(true)
|
||||||
|
const handleCheckAllChange = (val: boolean) => {
|
||||||
|
checkColumns.value = val ? unref(defaultCheckColumns) : []
|
||||||
|
isIndeterminate.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleCheckedColumnsChange = (value: string[]) => {
|
||||||
|
const checkedCount = value.length
|
||||||
|
checkAll.value = checkedCount === unref(defaultCheckColumns)?.length
|
||||||
|
isIndeterminate.value = checkedCount > 0 && checkedCount < unref(defaultCheckColumns)?.length
|
||||||
|
}
|
||||||
|
|
||||||
|
const confirm = () => {
|
||||||
|
const newColumns = cloneDeep(unref(settingColumns))?.map((item) => {
|
||||||
|
const fixed = unref(settingColumns)?.find((col) => col.field === item.field)?.fixed
|
||||||
|
item.hidden = !!!unref(checkColumns)?.includes(item.field)
|
||||||
|
item.fixed = fixed ? fixed : undefined
|
||||||
|
return item
|
||||||
|
})
|
||||||
|
emit('confirm', [...unref(hiddenColumns), ...(newColumns || [])])
|
||||||
|
modelValue.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
const restore = () => {
|
||||||
|
initColumns([...unref(hiddenColumns), ...(unref(oldColumns) || [])], true)
|
||||||
|
}
|
||||||
|
|
||||||
|
const initColumns = (columns: TableColumn[], isReStore = false) => {
|
||||||
|
const newColumns = columns?.filter((item) => {
|
||||||
|
if (!isReStore) {
|
||||||
|
item.fixed = item.fixed !== void 0 ? item.fixed : undefined
|
||||||
|
}
|
||||||
|
return (item.type && !DEFAULT_FILTER_COLUMN.includes(item.type)) || !item.type
|
||||||
|
})
|
||||||
|
if (!unref(oldColumns)) {
|
||||||
|
oldColumns.value = cloneDeep(newColumns)
|
||||||
|
}
|
||||||
|
settingColumns.value = cloneDeep(newColumns)
|
||||||
|
|
||||||
|
hiddenColumns.value = cloneDeep(
|
||||||
|
columns?.filter((item) => item.type && DEFAULT_FILTER_COLUMN.includes(item.type))
|
||||||
|
)
|
||||||
|
|
||||||
|
defaultCheckColumns.value = unref(settingColumns)?.map((item) => item.field) || []
|
||||||
|
checkColumns.value =
|
||||||
|
unref(settingColumns)
|
||||||
|
?.filter((item) => !item.hidden)
|
||||||
|
?.map((item) => item.field) || []
|
||||||
|
|
||||||
|
if (unref(checkColumns)?.length === unref(defaultCheckColumns)?.length) {
|
||||||
|
checkAll.value = true
|
||||||
|
isIndeterminate.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.columns,
|
||||||
|
(columns) => {
|
||||||
|
initColumns(columns)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
immediate: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<ElDrawer v-model="modelValue" title="列设置" size="350px">
|
||||||
|
<div>
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<ElCheckbox
|
||||||
|
v-model="checkAll"
|
||||||
|
:indeterminate="isIndeterminate"
|
||||||
|
@change="handleCheckAllChange"
|
||||||
|
/>
|
||||||
|
<ElText class="ml-8px!">{{ checkColumns.length }} / {{ settingColumns?.length }}</ElText>
|
||||||
|
</div>
|
||||||
|
<ElText>固定 / 排序</ElText>
|
||||||
|
</div>
|
||||||
|
<div v-if="settingColumns?.length">
|
||||||
|
<VueDraggable
|
||||||
|
v-model="settingColumns"
|
||||||
|
target=".el-checkbox-group"
|
||||||
|
handle=".handle"
|
||||||
|
:animation="150"
|
||||||
|
>
|
||||||
|
<ElCheckboxGroup
|
||||||
|
ref="draggableWrap"
|
||||||
|
v-model="checkColumns"
|
||||||
|
@change="handleCheckedColumnsChange"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-for="item in settingColumns"
|
||||||
|
:key="item.field"
|
||||||
|
class="flex items-center justify-between mt-12px"
|
||||||
|
>
|
||||||
|
<ElCheckbox :label="item.field">
|
||||||
|
{{ item.label }}
|
||||||
|
</ElCheckbox>
|
||||||
|
<div class="flex items-center">
|
||||||
|
<ElRadioGroup size="small" v-model="item.fixed">
|
||||||
|
<ElRadioButton label="left">
|
||||||
|
<Icon icon="ep:arrow-left" />
|
||||||
|
</ElRadioButton>
|
||||||
|
<ElRadioButton :label="undefined">
|
||||||
|
<Icon icon="ep:close" />
|
||||||
|
</ElRadioButton>
|
||||||
|
<ElRadioButton label="right">
|
||||||
|
<Icon icon="ep:arrow-right" />
|
||||||
|
</ElRadioButton>
|
||||||
|
</ElRadioGroup>
|
||||||
|
|
||||||
|
<div class="ml-12px cursor-move handle"><Icon icon="ep:rank" /></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ElCheckboxGroup>
|
||||||
|
</VueDraggable>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<template #footer>
|
||||||
|
<div>
|
||||||
|
<BaseButton @click="restore">还原</BaseButton>
|
||||||
|
<BaseButton type="primary" @click="confirm">确定</BaseButton>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</ElDrawer>
|
||||||
|
</template>
|
|
@ -1,20 +1,11 @@
|
||||||
<script lang="tsx">
|
<script lang="tsx">
|
||||||
import { defineComponent, unref, computed, PropType, watch } from 'vue'
|
import { defineComponent, unref, computed, PropType, ref } from 'vue'
|
||||||
import {
|
import { ElDropdown, ElDropdownMenu, ElDropdownItem, ComponentSize } from 'element-plus'
|
||||||
ElTooltip,
|
|
||||||
ElDropdown,
|
|
||||||
ElDropdownMenu,
|
|
||||||
ElDropdownItem,
|
|
||||||
ComponentSize
|
|
||||||
// ElPopover,
|
|
||||||
// ElTree
|
|
||||||
} from 'element-plus'
|
|
||||||
import { Icon } from '@/components/Icon'
|
import { Icon } from '@/components/Icon'
|
||||||
import { useI18n } from '@/hooks/web/useI18n'
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
import { useAppStore } from '@/store/modules/app'
|
import { useAppStore } from '@/store/modules/app'
|
||||||
import { TableColumn } from '../types'
|
import { TableColumn } from '../types'
|
||||||
import { cloneDeep } from 'lodash-es'
|
import ColumnSetting from './ColumnSetting.vue'
|
||||||
// import { eachTree } from '@/utils/tree'
|
|
||||||
|
|
||||||
const appStore = useAppStore()
|
const appStore = useAppStore()
|
||||||
const sizeMap = computed(() => appStore.sizeMap)
|
const sizeMap = computed(() => appStore.sizeMap)
|
||||||
|
@ -23,14 +14,19 @@ const { t } = useI18n()
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'TableActions',
|
name: 'TableActions',
|
||||||
|
components: {
|
||||||
|
ColumnSetting
|
||||||
|
},
|
||||||
props: {
|
props: {
|
||||||
columns: {
|
columns: {
|
||||||
type: Array as PropType<TableColumn[]>,
|
type: Array as PropType<TableColumn[]>,
|
||||||
default: () => []
|
default: () => []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
emits: ['refresh', 'changSize'],
|
emits: ['refresh', 'changSize', 'confirm'],
|
||||||
setup(props, { emit }) {
|
setup(props, { emit }) {
|
||||||
|
const showSetting = ref(false)
|
||||||
|
|
||||||
const refresh = () => {
|
const refresh = () => {
|
||||||
emit('refresh')
|
emit('refresh')
|
||||||
}
|
}
|
||||||
|
@ -39,111 +35,71 @@ export default defineComponent({
|
||||||
emit('changSize', size)
|
emit('changSize', size)
|
||||||
}
|
}
|
||||||
|
|
||||||
const columns = computed(() => {
|
const confirm = (columns: TableColumn[]) => {
|
||||||
return cloneDeep(props.columns).filter((v) => {
|
emit('confirm', columns)
|
||||||
// 去掉type为selection的列和expand的列
|
}
|
||||||
if (v.type !== 'selection' && v.type !== 'expand') {
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
watch(
|
const showColumnSetting = () => {
|
||||||
() => columns.value,
|
showSetting.value = true
|
||||||
(newColumns) => {
|
}
|
||||||
console.log('columns change:', newColumns)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
deep: true
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
return () => (
|
return () => (
|
||||||
<>
|
<>
|
||||||
<div class="text-right h-28px flex items-center justify-end">
|
<div class="text-right h-28px flex items-center justify-end">
|
||||||
<ElTooltip content={t('common.refresh')} placement="top">
|
<div title="刷新" class="w-30px h-20px flex items-center justify-end" onClick={refresh}>
|
||||||
<span onClick={refresh}>
|
<Icon
|
||||||
<Icon
|
icon="ant-design:sync-outlined"
|
||||||
icon="ant-design:sync-outlined"
|
class="cursor-pointer"
|
||||||
class="cursor-pointer"
|
hover-color="var(--el-color-primary)"
|
||||||
hover-color="var(--el-color-primary)"
|
/>
|
||||||
/>
|
</div>
|
||||||
</span>
|
|
||||||
</ElTooltip>
|
|
||||||
|
|
||||||
<ElTooltip content={t('common.size')} placement="top">
|
<ElDropdown trigger="click" onCommand={changSize}>
|
||||||
<ElDropdown trigger="click" onCommand={changSize}>
|
|
||||||
{{
|
|
||||||
default: () => {
|
|
||||||
return (
|
|
||||||
<span>
|
|
||||||
<Icon
|
|
||||||
icon="ant-design:column-height-outlined"
|
|
||||||
class="cursor-pointer mr-8px ml-8px"
|
|
||||||
hover-color="var(--el-color-primary)"
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
dropdown: () => {
|
|
||||||
return (
|
|
||||||
<ElDropdownMenu>
|
|
||||||
{{
|
|
||||||
default: () => {
|
|
||||||
return unref(sizeMap).map((v) => {
|
|
||||||
return (
|
|
||||||
<ElDropdownItem key={v} command={v}>
|
|
||||||
{t(`size.${v}`)}
|
|
||||||
</ElDropdownItem>
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
</ElDropdownMenu>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
</ElDropdown>
|
|
||||||
</ElTooltip>
|
|
||||||
|
|
||||||
{/* <ElTooltip content={t('common.columnSetting')} placement="top"> */}
|
|
||||||
{/* <ElPopover trigger="click" placement="left">
|
|
||||||
{{
|
{{
|
||||||
default: () => {
|
default: () => {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div title="尺寸" class="w-30px h-20px flex items-center justify-end">
|
||||||
<ElTree
|
<Icon
|
||||||
data={unref(columns)}
|
icon="ant-design:column-height-outlined"
|
||||||
show-checkbox
|
class="cursor-pointer"
|
||||||
default-checked-keys={unref(defaultCheckeds)}
|
hover-color="var(--el-color-primary)"
|
||||||
draggable
|
|
||||||
node-key="field"
|
|
||||||
allow-drop={(_draggingNode: any, _dropNode: any, type: string) => {
|
|
||||||
if (type === 'inner') {
|
|
||||||
return false
|
|
||||||
} else {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
onNode-drag-end={onNodeDragEnd}
|
|
||||||
onCheck-change={onCheckChange}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
reference: () => {
|
dropdown: () => {
|
||||||
return (
|
return (
|
||||||
<Icon
|
<ElDropdownMenu>
|
||||||
icon="ant-design:setting-outlined"
|
{{
|
||||||
class="cursor-pointer"
|
default: () => {
|
||||||
hoverColor="var(--el-color-primary)"
|
return unref(sizeMap).map((v) => {
|
||||||
/>
|
return (
|
||||||
|
<ElDropdownItem key={v} command={v}>
|
||||||
|
{t(`size.${v}`)}
|
||||||
|
</ElDropdownItem>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
</ElDropdownMenu>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
</ElPopover> */}
|
</ElDropdown>
|
||||||
{/* </ElTooltip> */}
|
|
||||||
|
<div
|
||||||
|
title="列设置"
|
||||||
|
class="w-30px h-20px flex items-center justify-end"
|
||||||
|
onClick={showColumnSetting}
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
icon="ant-design:setting-outlined"
|
||||||
|
class="cursor-pointer"
|
||||||
|
hover-color="var(--el-color-primary)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<ColumnSetting v-model={showSetting.value} columns={props.columns} onConfirm={confirm} />
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,3 +22,8 @@ export const NO_REDIRECT_WHITE_LIST = ['/login']
|
||||||
* 不重置路由白名单
|
* 不重置路由白名单
|
||||||
*/
|
*/
|
||||||
export const NO_RESET_WHITE_LIST = ['Redirect', 'Login', 'NoFind', 'Root']
|
export const NO_RESET_WHITE_LIST = ['Redirect', 'Login', 'NoFind', 'Root']
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表格默认过滤列设置字段
|
||||||
|
*/
|
||||||
|
export const DEFAULT_FILTER_COLUMN = ['expand', 'selection']
|
||||||
|
|
|
@ -79,7 +79,7 @@ const filterSearchSchema = (crudSchema: CrudSchema[]): FormSchema[] => {
|
||||||
for (let i = 0; i < length; i++) {
|
for (let i = 0; i < length; i++) {
|
||||||
const schemaItem = crudSchema[i]
|
const schemaItem = crudSchema[i]
|
||||||
// 判断是否隐藏
|
// 判断是否隐藏
|
||||||
if (!schemaItem?.search?.hidden) {
|
if (!schemaItem?.search?.remove) {
|
||||||
const searchSchemaItem = {
|
const searchSchemaItem = {
|
||||||
component: schemaItem?.search?.component || 'Input',
|
component: schemaItem?.search?.component || 'Input',
|
||||||
...schemaItem.search,
|
...schemaItem.search,
|
||||||
|
@ -87,9 +87,6 @@ const filterSearchSchema = (crudSchema: CrudSchema[]): FormSchema[] => {
|
||||||
label: schemaItem.label
|
label: schemaItem.label
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除不必要的字段
|
|
||||||
delete searchSchemaItem.hidden
|
|
||||||
|
|
||||||
searchSchema.push(searchSchemaItem)
|
searchSchema.push(searchSchemaItem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -127,7 +124,7 @@ const filterFormSchema = (crudSchema: CrudSchema[]): FormSchema[] => {
|
||||||
for (let i = 0; i < length; i++) {
|
for (let i = 0; i < length; i++) {
|
||||||
const formItem = crudSchema[i]
|
const formItem = crudSchema[i]
|
||||||
// 判断是否隐藏
|
// 判断是否隐藏
|
||||||
if (!formItem?.form?.hidden) {
|
if (!formItem?.form?.remove) {
|
||||||
const formSchemaItem = {
|
const formSchemaItem = {
|
||||||
component: formItem?.form?.component || 'Input',
|
component: formItem?.form?.component || 'Input',
|
||||||
...formItem.form,
|
...formItem.form,
|
||||||
|
@ -135,9 +132,6 @@ const filterFormSchema = (crudSchema: CrudSchema[]): FormSchema[] => {
|
||||||
label: formItem.label
|
label: formItem.label
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除不必要的字段
|
|
||||||
delete formSchemaItem.hidden
|
|
||||||
|
|
||||||
formSchema.push(formSchemaItem)
|
formSchema.push(formSchemaItem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
// 引入windi css
|
import 'vue/jsx'
|
||||||
|
|
||||||
|
// 引入unocss
|
||||||
import '@/plugins/unocss'
|
import '@/plugins/unocss'
|
||||||
|
|
||||||
// 导入全局的svg图标
|
// 导入全局的svg图标
|
||||||
|
|
|
@ -5,7 +5,7 @@ import en from 'element-plus/es/locale/lang/en'
|
||||||
import { useStorage } from '@/hooks/web/useStorage'
|
import { useStorage } from '@/hooks/web/useStorage'
|
||||||
import { LocaleDropdownType } from '@/components/LocaleDropdown'
|
import { LocaleDropdownType } from '@/components/LocaleDropdown'
|
||||||
|
|
||||||
const { getStorage, setStorage } = useStorage()
|
const { getStorage, setStorage } = useStorage('localStorage')
|
||||||
|
|
||||||
const elLocaleMap = {
|
const elLocaleMap = {
|
||||||
'zh-CN': zhCn,
|
'zh-CN': zhCn,
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
|
"jsxImportSource": "vue",
|
||||||
"lib": ["esnext", "dom"],
|
"lib": ["esnext", "dom"],
|
||||||
"baseUrl": "./",
|
"baseUrl": "./",
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
|
|
Loading…
Reference in New Issue